📄 spc700.asm
字号:
.set_write_loop:
mov [ebx],eax
mov [ebx+1*4],edx
mov [ebx+2*4],esi
mov [ebx+3*4],edi
add ebx,byte 4*4
dec cl
jnz .set_write_loop
popa
ret
ALIGNC
EXPORT_C Reset_SPC
pusha
; Get ROM reset vector and setup Program Counter
movzx eax,word [C_LABEL(SPC_ROM_CODE)+(0xFFFE-0xFFC0)]
mov [_PC],eax
mov eax,0 ;[C_LABEL(SNES_Cycles)]
mov [SPC_last_cycles],eax
; Reset the sound DSP registers
mov [C_LABEL(SPC_Cycles)],eax ; Clear Cycle Count
mov [C_LABEL(TotalCycles)],eax
mov [SPC_PAGE],eax ; Used to save looking up P flag for Direct page stuff!
mov dword [_SP],0x01EF ; Reset registers
mov [_YA],eax
mov [_X],al
mov [_PSW],al ; Clear Flags Register
mov [_N_flag],al ; Clear Flags Register
mov byte [_Z_flag],1
mov [_H_flag],al
mov [_V_flag],al
mov [_I_flag],al
mov [_P_flag],al
mov [_B_flag],al
mov [_C_flag],al
mov byte [C_LABEL(SPCRAM)+SPC_CTRL],0x80
mov dword [SPC_FFC0_Address],C_LABEL(SPC_ROM_CODE)-0xFFC0
mov dword [SPC_Code_Base],C_LABEL(SPC_ROM_CODE)-0xFFC0
; Reset timers
mov [C_LABEL(SPC_T0_counter)],al
mov [C_LABEL(SPC_T1_counter)],al
mov [C_LABEL(SPC_T2_counter)],al
mov word [C_LABEL(SPC_T0_target)],256
mov word [C_LABEL(SPC_T1_target)],256
mov word [C_LABEL(SPC_T2_target)],256
mov [C_LABEL(SPC_T0_position)],ax
mov [C_LABEL(SPC_T1_position)],ax
mov [C_LABEL(SPC_T2_position)],ax
mov [C_LABEL(SPC_T0_cycle_latch)],eax
mov [C_LABEL(SPC_T1_cycle_latch)],eax
mov [C_LABEL(SPC_T2_cycle_latch)],eax
mov [C_LABEL(sound_cycle_latch)],eax
; Reset SPC700 output ports
mov [C_LABEL(SPC_PORT0W)],al
mov [C_LABEL(SPC_PORT1W)],al
mov [C_LABEL(SPC_PORT2W)],al
mov [C_LABEL(SPC_PORT3W)],al
; Reset SPC700 input ports
mov [C_LABEL(SPC_PORT0R)],al
mov [C_LABEL(SPC_PORT1R)],al
mov [C_LABEL(SPC_PORT2R)],al
mov [C_LABEL(SPC_PORT3R)],al
; Reset sound DSP port address
mov [C_LABEL(SPC_DSP)+SPC_DSP_ADDR],al
mov [C_LABEL(SPC_DSP_DATA)],eax
popa
ret
SPC_SHOW_REGISTERS:
pusha
call C_LABEL(DisplaySPC)
popa
ret
ALIGNC
EXPORT_C get_SPC_PSW
push dword R_Base
LOAD_BASE
SETUPFLAGS_SPC
pop dword R_Base
ret
ALIGNC
SPC_GET_WORD:
GET_BYTE_SPC
mov ah,al
inc bx
GET_BYTE_SPC
ror ax,8
ret
ALIGNC
EXPORT_C SPC_START
%ifdef WATCH_SPC_BREAKS
EXTERN_C BreaksLast
inc dword [C_LABEL(BreaksLast)]
%endif
mov al,[In_CPU]
push eax
mov byte [In_CPU],0
LOAD_CYCLES
LOAD_PC
LOAD_BASE
xor eax,eax
jmp SPC_START_NEXT
ALIGNC
SPC_RETURN:
;cmp R_Base,SPC_Register_Base
;jne 0b
%ifdef DEBUG
;mov ebx,[SPC_TEMP_ADD]
;mov [_OLD_SPC_ADDRESS],ebx
%endif
test R_Cycles,R_Cycles
jg SPC_OUT ; Do another instruction if cycles left
SPC_START_NEXT:
; This code is for a SPC-tracker dump... #define TRACKERS to make a dump
; of the CPU state before each instruction - uncomment the calls to
; _Wangle__Fv and _exit to force the emulator to exit when the buffer
; fills. TRACKERS must be defined to the size of the buffer to be used -
; which must be a power of two, and the variables required by this and the
; write in Wangle() (romload.cc) exist only if DEBUG and SPCTRACKERS are
; also defined in romload.cc.
%ifdef TRACKERS
EXTERN_C SPC_LastIns
EXTERN_C SPC_InsAddress
EXTERN_C Wangle__Fv
EXTERN_C exit
mov edx,[_SPC_LastIns] ;
add edx,[_SPC_InsAddress] ;
SAVE_PC eax ;
mov [edx],ah ;
mov [1+edx],al ;
mov al,[_A] ;
mov [2+edx],al ;
mov al,[_X] ;
mov [3+edx],al ;
mov al,[_Y] ;
mov [4+edx],al ;
mov al,[_SP] ;
mov [5+edx],al ;
SETUPFLAGS_SPC ;
mov [6+edx],al ;
mov al,[esi] ;
mov [7+edx],al ;
mov eax,[1+esi] ;
mov [8+edx],eax ;
mov eax,[5+esi] ;
mov [12+edx],eax ;
mov edx,[_SPC_LastIns] ;
add edx,byte 16 ;
and edx,(TRACKERS-1) ;
mov [_SPC_LastIns],edx ;
test edx,edx ;
jnz .buffer_not_full ;
call _Wangle__Fv ;
jmp C_LABEL(exit) ;
;
.buffer_not_full: ;
xor eax,eax ;
%endif
;mov ebx,[_PC] ; PC now setup
;mov R_NativePC,[SPC_Code_Base]
;add R_NativePC,ebx
%ifdef DEBUG
;mov [SPC_TEMP_ADD],ebx
%endif
xor eax,eax
mov al,[R_NativePC] ; Fetch opcode
xor ebx,ebx
mov bl,[SPCCycleTable+eax]
add R_Cycles,ebx ; Update cycle counter
jmp dword [SPCOpTable+eax*4] ; jmp to opcode handler
ALIGNC
SPC_OUT:
SAVE_PC R_NativePC
SAVE_CYCLES ; Set cycle counter
%ifdef INDEPENDENT_SPC
; Update SPC timers to prevent overflow
Update_SPC_Timer 0
Update_SPC_Timer 1
Update_SPC_Timer 2
%endif
pop eax
mov [In_CPU],al
ret ; Return to CPU emulation
%include "apu/spcaddr.inc" ; Include addressing mode macros
%include "apu/spcmacro.inc" ; Include instruction macros
EXPORT_C spc_ops_start
ALIGNC
EXPORT_C SPC_INVALID
mov [C_LABEL(Map_Byte)],al ; al contains opcode!
SAVE_PC R_NativePC
SAVE_CYCLES ; Set cycle counter
mov eax,[_PC] ; Adjust address to correct for pre-increment
mov [C_LABEL(Map_Address)],eax ; this just sets the error output up correctly!
EXTERN_C InvalidSPCOpcode
jmp C_LABEL(InvalidSPCOpcode) ; This exits.. avoids conflict with other things!
ALIGNC
EXPORT_C SPC_SET1
shr eax,5
mov ebx,B_SPC_PAGE
mov bl,[1+R_NativePC]
add R_NativePC,byte 2
mov ah,[offset_to_bit+eax]
GET_BYTE_SPC
or al,ah
SET_BYTE_SPC
OPCODE_EPILOG
ALIGNC
EXPORT_C SPC_CLR1
shr eax,5
mov ebx,B_SPC_PAGE
mov bl,[1+R_NativePC]
add R_NativePC,byte 2
mov ah,[offset_to_not+eax]
GET_BYTE_SPC
and al,ah
SET_BYTE_SPC
OPCODE_EPILOG
ALIGNC
EXPORT_C SPC_BBS
shr eax,5
mov ebx,B_SPC_PAGE
mov bl,[1+R_NativePC]
add R_NativePC,byte 3
mov ah,[offset_to_bit+eax]
GET_BYTE_SPC
test al,ah
jz SPC_RETURN
movsx eax,byte [-1+R_NativePC]
short_branch
OPCODE_EPILOG
ALIGNC
EXPORT_C SPC_BBC
shr eax,5
mov ebx,B_SPC_PAGE
mov bl,[1+R_NativePC]
add R_NativePC,byte 3
mov ah,[offset_to_bit+eax]
GET_BYTE_SPC
test al,ah
jnz SPC_RETURN
movsx eax,byte [-1+R_NativePC]
short_branch
OPCODE_EPILOG
%include "apu/spcops.inc" ; Include opcodes
EXPORT_C SPC_READ_CTRL
EXPORT_C SPC_READ_DSP_ADDR
mov al,[C_LABEL(SPCRAM)+ebx]
ret
EXPORT_C SPC_READ_DSP_DATA
push ecx
;push edx
push eax
call C_LABEL(SPC_READ_DSP)
xor ecx,ecx
mov cl,[C_LABEL(SPCRAM)+SPC_DSP_ADDR]
pop eax
;pop edx
mov al,[C_LABEL(SPC_DSP)+ecx] ; read from DSP register
pop ecx
ret
EXPORT_C SPC_READ_PORT0R
mov al,[C_LABEL(SPC_PORT0R)]
ret
EXPORT_C SPC_READ_PORT1R
mov al,[C_LABEL(SPC_PORT1R)]
ret
EXPORT_C SPC_READ_PORT2R
mov al,[C_LABEL(SPC_PORT2R)]
ret
EXPORT_C SPC_READ_PORT3R
mov al,[C_LABEL(SPC_PORT3R)]
ret
; WOOPS... TIMER registers are write only, the actual timer clock is internal not accessible!
; COUNTERS ARE 4 BIT, upon read they reset to 0 status
EXPORT_C SPC_READ_COUNTER_0
push ecx
;push edx
push eax
Update_SPC_Timer 0
;call C_LABEL(Update_SPC_Timer_0)
pop eax
;pop edx
pop ecx
mov al,[C_LABEL(SPC_T0_counter)]
mov [C_LABEL(SPC_T0_counter)],bh
ret
EXPORT_C SPC_READ_COUNTER_1
push ecx
;push edx
push eax
Update_SPC_Timer 1
;call C_LABEL(Update_SPC_Timer_1)
pop eax
;pop edx
pop ecx
mov al,[C_LABEL(SPC_T1_counter)]
mov byte [C_LABEL(SPC_T1_counter)],bh
ret
EXPORT_C SPC_READ_COUNTER_2
push ecx
;push edx
push eax
Update_SPC_Timer 2
;call C_LABEL(Update_SPC_Timer_2)
pop eax
;pop edx
pop ecx
mov al,[C_LABEL(SPC_T2_counter)]
mov byte [C_LABEL(SPC_T2_counter)],bh
ret
; | ROMEN | TURBO | PC32 | PC10 | ----- | ST2 | ST1 | ST0 |
;
; ROMEN - enable mask ROM in top 64-bytes of address space for CPU read
; TURBO - enable turbo CPU clock ???
; PC32 - clear SPC read ports 2 & 3
; PC10 - clear SPC read ports 0 & 1
; ST2 - start timer 2 (64kHz)
; ST1 - start timer 1 (8kHz)
; ST0 - start timer 0 (8kHz)
EXPORT_C SPC_WRITE_CTRL
push eax
mov ah,0
test al,al ; New for 0.25 - read hidden RAM
mov edx,C_LABEL(SPCRAM)
jns .rom_disabled
mov edx,C_LABEL(SPC_ROM_CODE)-0xFFC0
.rom_disabled:
mov [SPC_FFC0_Address],edx
test al,0x10 ; Reset ports 0/1 to 00 if set
jz .no_clear_01
mov [C_LABEL(SPC_PORT0R)],ah ; Ports read by SPC should be reset!
mov [C_LABEL(SPC_PORT1R)],ah ; Thanks to Butcha for fix!
.no_clear_01:
test al,0x20 ; Reset ports 2/3 to 00 if set
jz .no_clear_23
mov [C_LABEL(SPC_PORT2R)],ah
mov [C_LABEL(SPC_PORT3R)],ah
.no_clear_23:
mov edx,[C_LABEL(TotalCycles)]
test byte [C_LABEL(SPCRAM)+ebx],4
jnz .no_enable_timer_2
test al,4
jz .no_enable_timer_2
mov byte [C_LABEL(SPC_T2_counter)],0
%ifdef FAST_SPC
and edx,~31
%else
and edx,~15
%endif
mov word [C_LABEL(SPC_T2_position)],0
mov [C_LABEL(SPC_T2_cycle_latch)],edx
.no_enable_timer_2:
%ifdef FAST_SPC
mov dl,0
%else
and edx,~127
%endif
test byte [C_LABEL(SPCRAM)+ebx],2
jnz .no_enable_timer_1
test al,2
jz .no_enable_timer_1
mov byte [C_LABEL(SPC_T1_counter)],0
mov word [C_LABEL(SPC_T1_position)],0
mov [C_LABEL(SPC_T1_cycle_latch)],edx
.no_enable_timer_1:
test byte [C_LABEL(SPCRAM)+ebx],1
jnz .no_enable_timer_0
test al,1
jz .no_enable_timer_0
mov byte [C_LABEL(SPC_T0_counter)],0
mov word [C_LABEL(SPC_T0_position)],0
mov [C_LABEL(SPC_T0_cycle_latch)],edx
.no_enable_timer_0:
pop eax
mov [C_LABEL(SPCRAM)+ebx],al
ret
EXPORT_C SPC_WRITE_DSP_ADDR
mov [C_LABEL(SPCRAM)+ebx],al
ret
EXPORT_C SPC_WRITE_DSP_DATA
mov [C_LABEL(SPC_DSP_DATA)],al
push ecx
;push edx
push eax
call C_LABEL(SPC_WRITE_DSP)
pop eax
;pop edx
pop ecx
ret
EXPORT_C SPC_WRITE_PORT0W
mov [C_LABEL(SPC_PORT0W)],al
ret
EXPORT_C SPC_WRITE_PORT1W
mov [C_LABEL(SPC_PORT1W)],al
ret
EXPORT_C SPC_WRITE_PORT2W
mov [C_LABEL(SPC_PORT2W)],al
ret
EXPORT_C SPC_WRITE_PORT3W
mov [C_LABEL(SPC_PORT3W)],al
ret
EXPORT_C SPC_WRITE_TIMER_0
cmp [C_LABEL(SPC_T0_target)],al
je .no_change
push ecx
;push edx
push eax
Update_SPC_Timer 0
;call C_LABEL(Update_SPC_Timer_0) ; Timer must catch up before changing target
pop eax
;pop edx
pop ecx
test al,al
mov [C_LABEL(SPC_T0_target)],al ; (0.32) Butcha - timer targets are writable
setz [C_LABEL(SPC_T0_target)+1] ; 0 = 256
.no_change:
ret
EXPORT_C SPC_WRITE_TIMER_1
cmp [C_LABEL(SPC_T1_target)],al
je .no_change
push ecx
;push edx
push eax
Update_SPC_Timer 1
;call C_LABEL(Update_SPC_Timer_1) ; Timer must catch up before changing target
pop eax
;pop edx
pop ecx
test al,al
mov [C_LABEL(SPC_T1_target)],al ; (0.32) Butcha - timer targets are writable
setz [C_LABEL(SPC_T1_target)+1] ; 0 = 256
.no_change:
ret
EXPORT_C SPC_WRITE_TIMER_2
cmp [C_LABEL(SPC_T2_target)],al
je .no_change
push ecx
;push edx
push eax
Update_SPC_Timer 2
;call C_LABEL(Update_SPC_Timer_2) ; Timer must catch up before changing target
pop eax
;pop edx
pop ecx
test al,al
mov [C_LABEL(SPC_T2_target)],al ; (0.32) Butcha - timer targets are writable
setz [C_LABEL(SPC_T2_target)+1] ; 0 = 256
.no_change:
ret
section .text
ALIGNC
section .data
ALIGND
section .bss
ALIGNB
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -