⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 emu65816.asm

📁 SNES game emulator. C and asm files.
💻 ASM
📖 第 1 页 / 共 5 页
字号:
.model flat, C
.486P

.data
;_DATA SEGMENT DWORD PUBLIC USE32 'DATA'
align 4

regpack struct
	PC  dd ?
	Y   dd ?
	X   dd ?
	DBR_2less db ?
		db ?
	DBR db ?
		db ?
	D   dd ?
	A   dd ?
	P   db 4 dup (?)
	S   dd ?
	E   db 4 dup (?)
regpack ends

FCARRY     equ  1
FZERO      equ  2
FINTERRUPT equ  4
FDECIMAL   equ  8
FINDEX     equ  16
FMEMORY    equ  32
FOVERFLOW  equ  64
FNEGATIVE  equ  128

extrn _registers:dword near
extrn _scan_cycles:dword near
extrn _startaddr:dword near
extrn _debug_instr:dword near
extrn _rom:dword near          ; pointer
extrn _state:byte near         ; first two elements: end_wai, within_wai
extrn _returntogui:byte near

_reg regpack <>
PUBLIC _reg

NZ_8bit db  02h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h   ; /* 00-0F */
        db  00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h   ; /* 10-1F */
        db  00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h   ; /* 20-2F */
        db  00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h   ; /* 30-3F */
        db  00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h   ; /* 40-4F */
        db  00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h   ; /* 50-5F */
        db  00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h   ; /* 60-6F */
        db  00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h   ; /* 70-7F */
        db  80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h   ; /* 80-8F */
        db  80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h   ; /* 90-9F */
        db  80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h   ; /* A0-AF */
        db  80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h   ; /* B0-BF */
        db  80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h   ; /* C0-CF */
        db  80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h   ; /* D0-DF */
        db  80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h   ; /* E0-EF */
        db  80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h,80h   ; /* F0-FF */

;****************************************************************************
;                        SNES MEMORY ACCESS MACROS
;****************************************************************************

	; EAX USED AS TEMPORARY; don't hold an arg in EAX.

convert_snesptr macro snesaddr
	; Takes snes address and converts it to a PC pointer.  reg is 32-bit.
	; EAX destroyed.
	mov eax, snesaddr
	shr eax, 11
	and snesaddr, 01FFFh     ; offset
	and al, 0FCh
	mov eax, [_startaddr+eax] ; base pointer
	add snesaddr, eax        ; add 'em
endm convert_snesptr

trapandwrite8 macro pcptr, reg
	; Takes data from reg and puts it in "snesaddr" and traps the write
	local notrom, notrap, isrom
	cmp pcptr, [_rom]
	jb notrom
	cmp pcptr, [_rom] + 300000h
	jb isrom
notrom:
	mov [pcptr], reg
	cmp pcptr, offset _registers
	jb notrap
	cmp pcptr, offset _registers + 4000h
	jae notrap
	mov byte  [_reg.P], cl
	mov dword [_reg.PC], edx
	mov dword [_scan_cycles], esi
	push eax
	push edx
	push ecx
	push dword 0
	push pcptr
	call _trapregwrite
	pop eax
	pop edx
	pop ecx
	pop edx
	pop eax
notrap:
isrom:
endm writesnesmem

trapandwrite16 macro pcptr, lo, hi
	; Takes data from reg and puts it in "snesaddr" and traps the write
	local notrom, notrap, isrom
	cmp pcptr, [_rom]
	jb notrom
	cmp pcptr, [_rom] + 300000h
	jb isrom
notrom:
	mov byte [pcptr], lo
	mov byte [pcptr+1], hi
	cmp pcptr, offset [_registers]
	jb notrap
	cmp pcptr, offset [_registers] + 4000h
	jae notrap
	mov byte  [_reg.P], cl
	mov dword [_reg.PC], edx
	mov dword [_scan_cycles], esi
	push eax
	push edx
	push ecx
	push dword 1
	push pcptr
	call _trapregwrite
	pop eax  ; arg 1
	pop edx  ; arg 2
	pop ecx
	pop edx
	pop eax
notrap:
isrom:
endm writesnesmem

trapandread8 macro pcptr
	; Traps the read of a PC pointer pointing to a part of SNES address space
	local notrap
	cmp pcptr, offset _registers
	jb notrap
	cmp pcptr, offset _registers + 4000h
	jae notrap
	mov byte  [_reg.P], cl
	mov dword [_reg.PC], edx
	mov dword [_scan_cycles], esi
	push eax
	push edx
	push ecx
	push dword 0
	push pcptr
	call _trapregread
	pop eax  ; arg 1
	pop edx  ; arg 2
	pop ecx
	pop edx
	pop eax
	mov esi, dword [_scan_cycles]
notrap:
	mov pcptr, [pcptr]
endm trapandread

trapandread16 macro pcptr
	; Traps the read of a PC pointer pointing to a part of SNES address space
	local notrap
	cmp pcptr, offset _registers
	jb notrap
	cmp pcptr, offset _registers + 4000h
	jae notrap
	mov byte  [_reg.P], cl
	mov dword [_reg.PC], edx
	mov dword [_scan_cycles], esi
	push eax
	push edx
	push ecx
	push dword 1
	push pcptr
	call _trapregread
	pop eax  ; arg 1
	pop edx  ; arg 2
	pop ecx
	pop edx
	pop eax
	mov esi, dword [_scan_cycles]
notrap:
	mov pcptr, [pcptr]
endm trapandread

;****************************************************************************
;                          ADDRESSING MODE MACROS
;****************************************************************************

	; ADDRESSING MODE MACROS: These load EBX with the pointer to value; EAX 
	; used as temporary.  Indirections are not read trapped.  Assumes EBX
	; contains OPDATA.

convert_abs_code macro
	shr ebx, 8
	mov eax, edx
	and ebx, 0000FFFFh
	and eax, 00FF0000h
	or  ebx, eax
endm load_absdataaddress

convert_abs_data macro        ; Converts OPDATA (EBX) to SNES 24bit address
	; value returned in EBX   ; For absolute addressing modes
	shr ebx, 8
	and ebx, 0FFFFh
	or  ebx, dword [_reg.DBR_2less]
endm load_absdataaddress

convert_dir macro             ; Converts OPDATA (EBX) to SNES 24bit address
	; value returned in EBX   ; For direct addressing modes
	shr ebx, 8
	and ebx, 0FFh
	add ebx, dword [_reg.D]
	; and ebx, 0FFFFh generally useless, but adds extra cycle!
endm load_absdataaddress

get_imm macro
	shr ebx, 8
endm get_imm

load_abs macro      ; (SNESMEM ((DBR << 16) + OPWORD))
	convert_abs_data
	convert_snesptr ebx
endm load_abs

load_abs_long macro ; (SNESMEM (OPLONG))
	shr ebx, 8      ; now have 24bit address
	convert_snesptr ebx
endm load_abs_long

load_dir macro      ; (SNESMEM ((D + OPBYTE) & 0xFFFF))
	convert_dir
	convert_snesptr ebx
endm load_dir

load_dir_indir_index_y8 macro ; ( _tmp = *(word*)SNESMEM(D + OPBYTE) + (DBR << 16) + INDEX_Y, SNESMEM(_tmp) )
	convert_dir
	convert_snesptr ebx
	mov ebx, [ebx]
	and ebx, 0FFFFh
	movzx eax, byte [_reg.Y]
	or  ebx, dword [_reg.DBR_2less]
	add ebx, eax              ; Indexes DO NOT wrap around on word boundaries, thank heaven
	convert_snesptr ebx
endm load_dir_indir_index_y

load_dir_indir_index_y16 macro ; ( _tmp = *(word*)SNESMEM(D + OPBYTE) + (DBR << 16) + INDEX_Y, SNESMEM(_tmp) )
	convert_dir
	convert_snesptr ebx
	mov ebx, [ebx]
	and ebx, 0FFFFh
	or  ebx, dword [_reg.DBR_2less]
	add ebx, dword [_reg.Y]
	convert_snesptr ebx
endm load_dir_indir_index_y

load_dir_indir_long macro ; ( _tmp = (*(dword*)SNESMEM( (D + OPBYTE)&0xFFFF )) & 0xFFFFFF, SNESMEM (_tmp) )
	convert_dir
	convert_snesptr ebx
	mov ebx, [ebx]
	and ebx, 00FFFFFFh
	convert_snesptr ebx
endm load_dir_indir_long

load_dir_indir_long_index_y8 macro ; ( _tmp = ((*(dword*)SNESMEM( (D+OPBYTE)&0xFFFF )) & 0xFFFFFF) + INDEX_Y, SNESMEM (_tmp) )
	convert_dir
	convert_snesptr ebx
	mov ebx, [ebx]
	and ebx, 00FFFFFFh
	movzx eax, byte [_reg.Y]
	add ebx, eax
	convert_snesptr ebx
endm load_dir_indir_long_index_y8

load_dir_indir_long_index_y16 macro ; ( _tmp = ((*(dword*)SNESMEM( (D+OPBYTE)&0xFFFF )) & 0xFFFFFF) + INDEX_Y, SNESMEM (_tmp) )
	convert_dir
	convert_snesptr ebx
	mov ebx, [ebx]
	and ebx, 00FFFFFFh
	add ebx, dword [_reg.Y]
	convert_snesptr ebx
endm load_dir_indir_long_index_y16

load_dir_index_indir_x8 macro ; ( _tmp = *(word *)SNESMEM( (((D+OPBYTE)&0xFFFF) + INDEX_X) & 0xFFFF ) + (DBR << 16), SNESMEM (_tmp) )
	convert_dir
	movzx eax, byte [_reg.X]
	add ebx, eax
	convert_snesptr ebx
	mov ebx, [ebx]
	and ebx, 0FFFFh
	or  ebx, dword [_reg.DBR_2less]
	convert_snesptr ebx
endm load_dir_index_indir_x8

load_dir_index_indir_x16 macro ; ( _tmp = *(word *)SNESMEM( (((D+OPBYTE)&0xFFFF) + INDEX_X) & 0xFFFF ) + (DBR << 16), SNESMEM (_tmp) )
	convert_dir
	add ebx, dword [_reg.X]
	convert_snesptr ebx
	mov ebx, [ebx]
	and ebx, 0FFFFh
	or  ebx, dword [_reg.DBR_2less]
	convert_snesptr ebx
endm load_dir_index_indir_x16

load_dir_index_x8 macro ; ( SNESMEM(D + OPBYTE + INDEX_X) )
	convert_dir
	xor eax, eax
	mov al, byte [_reg.X]
	add ebx, eax
	convert_snesptr ebx
endm load_dir_index_x8

load_dir_index_x16 macro ; ( SNESMEM(D + OPBYTE + INDEX_X) )
	convert_dir
	add ebx, dword [_reg.X]
	convert_snesptr ebx
endm load_dir_index_x16

load_dir_index_y8 macro ; ( SNESMEM(D + OPBYTE + INDEX_Y) )
	convert_dir
	xor eax, eax
	mov al, byte [_reg.Y]
	add ebx, eax
	convert_snesptr ebx
endm load_dir_index_y8

load_dir_index_y16 macro ; ( SNESMEM(D + OPBYTE + INDEX_Y) )
	convert_dir
	add ebx, dword [_reg.Y]
	convert_snesptr ebx
endm load_dir_index_y16

load_abs_index_x8 macro ; ( _tmp = (DBR << 16) + OPWORD + INDEX_X, SNESMEM(_tmp) )
	convert_abs_data
	xor eax, eax
	mov al, byte [_reg.X]
	add ebx, eax
	convert_snesptr ebx
endm load_abs_index_x8

load_abs_index_x16 macro ; ( _tmp = (DBR << 16) + OPWORD + INDEX_X, SNESMEM(_tmp) )
	convert_abs_data
	add ebx, dword [_reg.X]
	convert_snesptr ebx
endm load_abs_index_x16

load_abs_index_y8 macro ; ( _tmp = (DBR << 16) + OPWORD + INDEX_Y, SNESMEM(_tmp) )
	convert_abs_data
	xor eax, eax
	mov al, byte [_reg.Y]
	add ebx, eax
	convert_snesptr ebx
endm load_abs_index_y8

load_abs_index_y16 macro ; ( _tmp = (DBR << 16) + OPWORD + INDEX_Y, SNESMEM(_tmp) )
	convert_abs_data
	add ebx, dword [_reg.Y]
	convert_snesptr ebx
endm load_abs_index_y16

load_abs_long_index_x8 macro ; ( SNESMEM(OPLONG + INDEX_X) )
	shr ebx, 8
	xor eax, eax
	mov al, byte [_reg.X]
	add ebx, eax
	convert_snesptr ebx
endm load_abs_long_index_x8

load_abs_long_index_x16 macro ; ( SNESMEM(OPLONG + INDEX_X) )
	shr ebx, 8
	add ebx, dword [_reg.X]
	convert_snesptr ebx
endm load_abs_long_index_x16

load_abs_indir macro ; ( SNESMEM (OPWORD) ) Apparently you set PC=*ABS_INDIR
	shr ebx, 8
	and ebx, 0FFFFh
	convert_snesptr ebx
endm load_abs_indir

load_dir_indir macro ; ( _tmp = *(word*)SNESMEM((D + OPBYTE) & 0xFFFF) + (DBR << 16), SNESMEM (_tmp) )
	convert_dir
	convert_snesptr ebx
	mov ebx, [ebx]
	and ebx, 0FFFFh
	or  ebx, dword [_reg.DBR_2less]
	convert_snesptr ebx
endm load_dir_indir

load_abs_index_indir_x8_code macro ; ( _tmp = OPWORD + INDEX_X + (PC & 0xFF0000), *(word*)SNESMEM(_tmp) | (PC & 0xFF0000) )
	shr ebx, 8
	and ebx, 0FFFFh
	mov eax, edx
	and eax, 00FF0000h
	mov al, byte [_reg.X]
	add ebx, eax
	convert_snesptr ebx ; EAX destroyed
	mov ebx, [ebx]
	mov eax, edx
	and ebx, 0FFFFh
	and eax, 00FF0000h ; PBR
	or  ebx, eax
	; SET PC to this final value
endm load_abs_index_indir_x8

load_abs_index_indir_x16_code macro ; ( _tmp = OPWORD + INDEX_X + (PC & 0xFF0000), *(word*)SNESMEM(_tmp) | (PC & 0xFF0000) )
	shr ebx, 8
	and ebx, 0FFFFh
	mov eax, edx
	and eax, 00FF0000h
	or  eax, dword [_reg.X]
	add ebx, eax
	convert_snesptr ebx ; EAX destroyed
	mov ebx, [ebx]
	and ebx, 0FFFFh
	mov eax, edx
	and eax, 00FF0000h
	or  ebx, eax
	; SET PC to this final value
endm load_abs_index_indir_x16

load_s_rel macro ; (SNESMEM (S + OPBYTE))
	shr ebx, 8
	and ebx, 0FFh
	add ebx, dword [_reg.S]
	convert_snesptr ebx
endm load_s_rel

load_s_rel_indir_index_y8 macro ; ( _tmp = *(word*)SNESMEM (S + OPBYTE) + (DBR << 16) + INDEX_Y, SNESMEM (_tmp) )
	shr ebx, 8
	and ebx, 0FFh
	add ebx, dword [_reg.S]
	convert_snesptr ebx
	mov ebx, [ebx]
	and ebx, 0FFFFh
	or  ebx, dword [_reg.DBR_2less]
	xor eax, eax
	mov al, byte [_reg.Y]
	add ebx, eax
	convert_snesptr ebx
endm load_s_rel_indir_index_y8

load_s_rel_indir_index_y16 macro ; ( _tmp = *(word*)SNESMEM (S + OPBYTE) + (DBR << 16) + INDEX_Y, SNESMEM (_tmp) )
	shr ebx, 8
	and ebx, 0FFh
	add ebx, dword [_reg.S]
	convert_snesptr ebx
	mov ebx, [ebx]
	and ebx, 0FFFFh
	or  ebx, dword [_reg.DBR_2less]
	add ebx, dword [_reg.Y]
	convert_snesptr ebx
endm load_s_rel_indir_index_y16

;****************************************************************************
;                          STACK PUSH/PULL MACROS
;****************************************************************************

	; There don't seem to be any instances where edi and pushbyte are used in the same place...
pushbyte macro bytereg  ; DESTROYS EDI and EAX!!! But not EBP, good since longcall uses EBP _and_ pushbyte
	mov edi, dword [_reg.S]
	convert_snesptr edi
	mov byte [edi], bytereg
	;dec word [_reg.S]
	mov edi, dword [_reg.S]
	dec edi
	and edi, 0000FFFFh
	mov dword [_reg.S], edi
endm pushbyte

pullbyte macro bytereg  ; DESTROYS EDI and EAX and EBP!!!
	inc_word [_reg.S]
	mov edi, dword [_reg.S]
	convert_snesptr edi
	mov bytereg, byte [edi]
endm pushbyte

;****************************************************************************
;                               MISC. MACROS
;****************************************************************************

docount macro addtopc, subfromcycles
	add edx, addtopc
	sub esi, subfromcycles
endm docount

dobreak macro
	ret
endm dobreak

dobreak_mxchange macro
	pop eax ; Pop return address
	jmp looptop_check
endm dobreak_mxchange

mainloop macro vectortable
@@:
	mov ebx, edx        ; Memory at PC
	mov eax, ebx
	shr eax, 11
	and ebx, 01FFFh     ; offset
	and al, 0FCh
	mov eax, [_startaddr+eax] ; base pointer
	add ebx, eax        ; add 'em
	inc dword [_debug_instr]
	mov ebx, [ebx]
	movzx eax, bl
	call [vectortable+eax*4]
	test esi, esi
	jns @B
	jmp exitroutine
endm mainloop

; Workarounds for error in word handling in the assembler -- MODIFIES EBP!

dec_word macro what
	mov ebp, dword what
	dec ebp
	and ebp, 0000FFFFh
	mov dword what, ebp
endm dec_word

inc_word macro what
	mov ebp, dword what
	inc ebp
	and ebp, 0000FFFFh
	mov dword what, ebp
endm inc_word

;****************************************************************************
;                             INSTRUCTION MACROS
;****************************************************************************

vectorcall macro e_vector, not_e_vector
	; Pushes PC and P, then changes PC to vector
	mov ebx, edx
	shr ebx, 8
	pushbyte bh
	pushbyte bl
	pushbyte dl
	pushbyte cl
	mov edx, not_e_vector
	or byte [_reg.E], 0
	jz @F ; not emulation mode
	mov edx, e_vector
@@: convert_snesptr edx
	mov edx, [edx]
	and edx, 0FFFFh
endm vectorcall

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -