📄 drz80.asm
字号:
;@ Reesy's Z80 Emulator Version 0.001
;@ (c) Copyright 2004 Reesy, All rights reserved
;@ DrZ80 is free for non-commercial use.
;@ For commercial use, separate licencing terms must be obtained.
AREA |.bss|, NOINIT
EXPORT DrZ80Ver
EXPORT DrZ80Run
AREA |.text|, CODE, ARM
INTERRUPT_MODE EQU 1 ;@0 = Use internal int handler, 1 = Use Mames int handler
FAST_Z80SP EQU 1 ;@0 = Use mem functions for stack pointer, 1 = Use direct mem pointer
UPDATE_CONTEXT EQU 1
IF INTERRUPT_MODE
IMPORT Interrupt
ENDIF
DrZ80Ver
DCD 0x0001
;@---------------------------------------
MACRO
fetch $cycs
subs z80_icount,z80_icount,#$cycs
IF UPDATE_CONTEXT
str z80pc,[cpucontext,#z80pc_pointer]
str z80_icount,[cpucontext,#cycles_pointer]
ldr r1,[cpucontext,#z80pc_base]
sub r2,z80pc,r1
str r2,[cpucontext,#previouspc]
ENDIF
ldrplb r0,[z80pc],#1
ldrpl pc,[opcodes,r0, lsl #2]
bmi z80_execute_end
MEND
MACRO
eatcycles $cycs
sub z80_icount,z80_icount,#$cycs
IF UPDATE_CONTEXT
str z80_icount,[cpucontext,#cycles_pointer]
ENDIF
MEND
MACRO
readmem8
IF UPDATE_CONTEXT
str z80pc,[cpucontext,#z80pc_pointer]
ENDIF
stmfd sp!,{r3,r12}
mov lr,pc
ldr pc,[cpucontext,#z80_read8] ;@ r0 = addr - data returned in r0
ldmfd sp!,{r3,r12}
MEND
MACRO
readmem8HL
mov r0,z80hl, lsr #16
readmem8
MEND
MACRO
readmem16
IF UPDATE_CONTEXT
str z80pc,[cpucontext,#z80pc_pointer]
ENDIF
stmfd sp!,{r3,r12}
mov lr,pc
ldr pc,[cpucontext,#z80_read16]
ldmfd sp!,{r3,r12}
MEND
MACRO
writemem8
IF UPDATE_CONTEXT
str z80pc,[cpucontext,#z80pc_pointer]
ENDIF
stmfd sp!,{r3,r12}
mov lr,pc
ldr pc,[cpucontext,#z80_write8] ;@ r0=data r1=addr
ldmfd sp!,{r3,r12}
MEND
MACRO
writemem8DE
mov r1,z80de, lsr #16
writemem8
MEND
MACRO
writemem8HL
mov r1,z80hl, lsr #16
writemem8
MEND
MACRO
writemem16
IF UPDATE_CONTEXT
str z80pc,[cpucontext,#z80pc_pointer]
ENDIF
stmfd sp!,{r3,r12}
mov lr,pc
ldr pc,[cpucontext,#z80_write16] ;@ r0=data r1=addr
ldmfd sp!,{r3,r12}
MEND
MACRO
copymem8HL_DE
IF UPDATE_CONTEXT
str z80pc,[cpucontext,#z80pc_pointer]
ENDIF
mov r0,z80hl, lsr #16
stmfd sp!,{r3,r12}
mov lr,pc
ldr pc,[cpucontext,#z80_read8] ;@ r0 = addr - data returned in r0
IF UPDATE_CONTEXT
str z80pc,[cpucontext,#z80pc_pointer]
ENDIF
mov r1,z80de, lsr #16
mov lr,pc
ldr pc,[cpucontext,#z80_write8] ;@ r0=data r1=addr
ldmfd sp!,{r3,r12}
MEND
;@---------------------------------------
MACRO
rebasepc
IF UPDATE_CONTEXT
str z80pc,[cpucontext,#z80pc_pointer]
ENDIF
stmfd sp!,{r3,r12}
mov lr,pc
ldr pc,[cpucontext,#z80_rebasePC] ;@ r0=new pc - external function sets z80pc_base and returns new z80pc in r0
ldmfd sp!,{r3,r12}
mov z80pc,r0
MEND
MACRO
rebasesp
IF UPDATE_CONTEXT
str z80pc,[cpucontext,#z80pc_pointer]
ENDIF
stmfd sp!,{r3,r12}
mov lr,pc
ldr pc,[cpucontext,#z80_rebaseSP] ;@ external function must rebase sp
ldmfd sp!,{r3,r12}
MEND
;@----------------------------------------------------------------------------
MACRO
opADC
movs z80f,z80f,lsr #2 ;@ get C
subcs r0,r0,#0x100
eor z80f,r0,z80a,lsr #24 ;@ prepare for check of half carry
adcs z80a,z80a,r0,ror #8
mrs r0,cpsr ;@ S,Z,V&C
eor z80f,z80f,z80a,lsr #24
and z80f,z80f,#1<<HFlag ;@ H, correct
orr z80f,z80f,r0,lsr #28
MEND
MACRO
opADCA
movs z80f,z80f,lsr #2 ;@ get C
orrcs z80a,z80a,#0x00800000
adds z80a,z80a,z80a
mrs z80f,cpsr ;@ S,Z,V&C
mov z80f,z80f,lsr #28
tst z80a,#0x10000000 ;@ H, correct
orrne z80f,z80f,#1<<HFlag
fetch 4
MEND
MACRO
opADCH $reg
mov r0,$reg,lsr #24
opADC
fetch 4
MEND
MACRO
opADCL $reg
movs z80f,z80f,lsr #2 ;@ get C
adc r0,$reg,$reg,lsr #15
orrcs z80a,z80a,#0x00800000
mov r1,z80a,lsl #4 ;@ Prepare for check of half carry
adds z80a,z80a,r0,lsl #23
mrs z80f,cpsr ;@ S,Z,V&C
mov z80f,z80f,lsr #28
cmn r1,r0,lsl #27
orrcs z80f,z80f,#1<<HFlag ;@ H, correct
fetch 4
MEND
MACRO
opADCb
opADC
MEND
;@---------------------------------------
MACRO
opADD $reg, $shift
mov r1,z80a,lsl #4 ;@ Prepare for check of half carry
adds z80a,z80a,$reg,lsl #$shift
mrs z80f,cpsr ;@ S,Z,V&C
mov z80f,z80f,lsr #28
cmn r1,$reg,lsl #$shift+4
orrcs z80f,z80f,#1<<HFlag
MEND
MACRO
opADDA
adds z80a,z80a,z80a
mrs z80f,cpsr ;@ S,Z,V&C
mov z80f,z80f,lsr #28
tst z80a,#0x10000000 ;@ H, correct
orrne z80f,z80f,#1<<HFlag
fetch 4
MEND
MACRO
opADDH $reg
and r0,$reg,#0xFF000000
opADD r0, 0
fetch 4
MEND
MACRO
opADDL $reg
opADD $reg, 8
fetch 4
MEND
MACRO
opADDb
opADD r0, 24
MEND
;@---------------------------------------
MACRO
opADC16 $reg
movs z80f,z80f,lsr #2 ;@ get C
adc r0,z80a,$reg,lsr #15
orrcs z80hl,z80hl,#0x00008000
mov r1,z80hl,lsl #4
adds z80hl,z80hl,r0,lsl #15
mrs z80f,cpsr ;@ S, Z, V & C
mov z80f,z80f,lsr #28
cmn r1,r0,lsl #19
orrcs z80f,z80f,#1<<HFlag
fetch 15
MEND
MACRO
opADC16HL
movs z80f,z80f,lsr #2 ;@ get C
orrcs z80hl,z80hl,#0x00008000
adds z80hl,z80hl,z80hl
mrs z80f,cpsr ;@ S, Z, V & C
mov z80f,z80f,lsr #28
tst z80hl,#0x10000000 ;@ H, correct.
orrne z80f,z80f,#1<<HFlag
fetch 15
MEND
MACRO
opADD16 $reg1, $reg2
mov r1,$reg1,lsl #4 ;@ Prepare for check of half carry
adds $reg1,$reg1,$reg2
bic z80f,z80f,#50
orrcs z80f,z80f,#1<<CFlag
cmn r1,$reg2,lsl #4
orrcs z80f,z80f,#1<<HFlag
MEND
MACRO
opADD16s $reg1, $reg2, $shift
mov r1,$reg1,lsl #4 ;@ Prepare for check of half carry
adds $reg1,$reg1,$reg2,lsl #$shift
bic z80f,z80f,#50
orrcs z80f,z80f,#1<<CFlag
cmn r1,$reg2,lsl #4+$shift
orrcs z80f,z80f,#1<<HFlag
MEND
MACRO
opADD16_2 $reg
adds $reg,$reg,$reg
bic z80f,z80f,#50
orrcs z80f,z80f,#1<<CFlag
tst $reg,#0x10000000 ;@ H, correct.
orrne z80f,z80f,#1<<HFlag
MEND
;@---------------------------------------
MACRO
opAND $reg, $shift
and z80a,z80a,$reg,lsl #$shift
sub r0,opcodes,#0x100
ldrb z80f,[r0,z80a, lsr #24]
orr z80f,z80f,#1<<HFlag
MEND
MACRO
opANDA
sub r0,opcodes,#0x100
ldrb z80f,[r0,z80a, lsr #24]
orr z80f,z80f,#1<<HFlag
fetch 4
MEND
MACRO
opANDH $reg
opAND $reg, 0
fetch 4
MEND
MACRO
opANDL $reg
opAND $reg, 8
fetch 4
MEND
MACRO
opANDb
opAND r0, 24
MEND
;@---------------------------------------
MACRO
opBITH $reg, $bit
and z80f,z80f,#1<<CFlag
tst $reg,#1<<(24+$bit)
orreq z80f,z80f,#21
orrne z80f,z80f,#(1<<HFlag)
fetch 8
MEND
MACRO
opBIT7H $reg
and z80f,z80f,#1<<CFlag
tst $reg,#1<<(24+7)
orreq z80f,z80f,#21
orrne z80f,z80f,#(1<<HFlag)|(1<<SFlag)
fetch 8
MEND
MACRO
opBITL $reg, $bit
and z80f,z80f,#1<<CFlag
tst $reg,#1<<(16+$bit)
orreq z80f,z80f,#21
orrne z80f,z80f,#(1<<HFlag)
fetch 8
MEND
MACRO
opBIT7L $reg
and z80f,z80f,#1<<CFlag
tst $reg,#1<<(16+7)
orreq z80f,z80f,#21
orrne z80f,z80f,#(1<<HFlag)|(1<<SFlag)
fetch 8
MEND
MACRO
opBITb $bit
and z80f,z80f,#1<<CFlag
tst r0,#1<<$bit
orreq z80f,z80f,#21
orrne z80f,z80f,#(1<<HFlag)
MEND
MACRO
opBIT7b
and z80f,z80f,#1<<CFlag
tst r0,#1<<7
orreq z80f,z80f,#21
orrne z80f,z80f,#(1<<HFlag)|(1<<SFlag)
MEND
;@---------------------------------------
MACRO
opCP $reg, $shift
mov r1,z80a,lsl #4 ;@ prepare for check of half carry
cmp z80a,$reg,lsl #$shift
mrs z80f,cpsr
mov z80f,z80f,lsr #28 ;@ S,Z,V&C
eor z80f,z80f,#(1<<CFlag)|(1<<NFlag) ;@ invert C and set n
cmp r1,$reg,lsl #$shift+4
orrcc z80f,z80f,#1<<HFlag
MEND
MACRO
opCPA
mov z80f,#(1<<ZFlag)|(1<<NFlag) ;@ set Z & n
fetch 4
MEND
MACRO
opCPH $reg
and r0,$reg,#0xFF000000
opCP r0, 0
fetch 4
MEND
MACRO
opCPL $reg
opCP $reg, 8
fetch 4
MEND
MACRO
opCPb
opCP r0, 24
MEND
;@---------------------------------------
MACRO
opDEC8 $reg ;@for A and memory
and z80f,z80f,#1<<CFlag ;@save carry
orr z80f,z80f,#1<<NFlag ;@set n
tst $reg,#0x0f000000
orreq z80f,z80f,#1<<HFlag
subs $reg,$reg,#0x01000000
orrmi z80f,z80f,#1<<SFlag
orrvs z80f,z80f,#1<<VFlag
orreq z80f,z80f,#1<<ZFlag
MEND
MACRO
opDEC8H $reg ;@for B, D & H
and z80f,z80f,#1<<CFlag ;@save carry
orr z80f,z80f,#1<<NFlag ;@set n
tst $reg,#0x0f000000
orreq z80f,z80f,#1<<HFlag
subs $reg,$reg,#0x01000000
orrmi z80f,z80f,#1<<SFlag
orrvs z80f,z80f,#1<<VFlag
tst $reg,#0xff000000 ;@Z
orreq z80f,z80f,#1<<ZFlag
MEND
MACRO
opDEC8L $reg ;@for C, E & L
mov $reg,$reg,ror #24
opDEC8H $reg
mov $reg,$reg,ror #8
MEND
MACRO
opDEC8b ;@for memory
mov r0,r0,lsl #24
opDEC8 r0
mov r0,r0,lsr #24
MEND
;@---------------------------------------
MACRO
opIN
stmfd sp!,{r3,r12}
mov lr,pc
ldr pc,[cpucontext,#z80_in] ;@ r0=port - data returned in r0
ldmfd sp!,{r3,r12}
MEND
MACRO
opIN_C
mov r0,z80bc, lsr #16
opIN
MEND
;@---------------------------------------
MACRO
opINC8 $reg ;@for A and memory
and z80f,z80f,#1<<CFlag ;@save carry, clear n
adds $reg,$reg,#0x01000000
orrmi z80f,z80f,#1<<SFlag
orrvs z80f,z80f,#1<<VFlag
orrcs z80f,z80f,#1<<ZFlag ;@cs when going from 0xFF to 0x00
tst $reg,#0x0f000000
orreq z80f,z80f,#1<<HFlag
MEND
MACRO
opINC8H $reg ;@for B, D & H
opINC8 $reg
MEND
MACRO
opINC8L $reg ;@for C, E & L
mov $reg,$reg,ror #24
opINC8 $reg
mov $reg,$reg,ror #8
MEND
MACRO
opINC8b ;@for memory
mov r0,r0,lsl #24
opINC8 r0
mov r0,r0,lsr #24
MEND
;@---------------------------------------
MACRO
opOR $reg, $shift
orr z80a,z80a,$reg,lsl #$shift
sub r0,opcodes,#0x100
ldrb z80f,[r0,z80a, lsr #24]
MEND
MACRO
opORA
sub r0,opcodes,#0x100
ldrb z80f,[r0,z80a, lsr #24]
fetch 4
MEND
MACRO
opORH $reg
and r0,$reg,#0xFF000000
opOR r0, 0
fetch 4
MEND
MACRO
opORL $reg
opOR $reg, 8
fetch 4
MEND
MACRO
opORb
opOR r0, 24
MEND
;@---------------------------------------
MACRO
opOUT
stmfd sp!,{r3,r12}
mov lr,pc
ldr pc,[cpucontext,#z80_out] ;@ r0=port r1=data
ldmfd sp!,{r3,r12}
MEND
MACRO
opOUT_C
mov r0,z80bc, lsr #16
opOUT
MEND
;@---------------------------------------
MACRO
opPOP
IF FAST_Z80SP
ldrb r0,[z80sp],#1
ldrb r1,[z80sp],#1
orr r0,r0,r1, lsl #8
ELSE
mov r0,z80sp
readmem16
add z80sp,z80sp,#2
ENDIF
MEND
MACRO
opPOPreg $reg
opPOP
mov $reg,r0, lsl #16
fetch 10
MEND
;@---------------------------------------
MACRO
opPUSHreg $reg
IF FAST_Z80SP
mov r1,$reg, lsr #24
strb r1,[z80sp,#-1]!
mov r1,$reg, lsr #16
strb r1,[z80sp,#-1]!
ELSE
mov r0,$reg,lsr #16
sub z80sp,z80sp,#2
mov r1,z80sp
writemem16
ENDIF
MEND
;@---------------------------------------
MACRO
opRESmemHL $bit
mov r0,z80hl, lsr #16
stmfd sp!,{r3,r12}
mov lr,pc
ldr pc,[cpucontext,#z80_read8] ;@ r0 = addr - data returned in r0
bic r0,r0,#1<<$bit
mov r1,z80hl, lsr #16
mov lr,pc
ldr pc,[cpucontext,#z80_write8] ;@ r0=data r1=addr
ldmfd sp!,{r3,r12}
fetch 15
MEND
;@---------------------------------------
MACRO
opRESmem $bit
stmfd sp!,{r3,r12}
stmfd sp!,{r0} ;@ save addr as well
mov lr,pc
ldr pc,[cpucontext,#z80_read8] ;@ r0=addr - data returned in r0
bic r0,r0,#1<<$bit
ldmfd sp!,{r1} ;@ restore addr into r1
mov lr,pc
ldr pc,[cpucontext,#z80_write8] ;@ r0=data r1=addr
ldmfd sp!,{r3,r12}
fetch 23
MEND
;@---------------------------------------
MACRO
opRL $reg1, $reg2, $shift
movs $reg1,$reg2,lsl #$shift
tst z80f,#1<<CFlag ;@doesn't affect ARM carry, as long as the imidiate value is < 0x100. Watch out!
orrne $reg1,$reg1,#0x01000000
;@ and r2,z80f,#1<<CFlag
;@ orr $x,$x,r2,lsl #23
sub r1,opcodes,#0x100
ldrb z80f,[r1,$reg1,lsr #24] ;@get PZS
orrcs z80f,z80f,#1<<CFlag
MEND
MACRO
opRLA
opRL z80a, z80a, 1
fetch 8
MEND
MACRO
opRLH $reg
and r0,$reg,#0xFF000000 ;@mask high to r0
adds $reg,$reg,r0
tst z80f,#1<<CFlag ;@doesn't affect ARM carry, as long as the imidiate value is < 0x100. Watch out!
orrne $reg,$reg,#0x01000000
sub r1,opcodes,#0x100
ldrb z80f,[r1,$reg,lsr #24] ;@get PZS
orrcs z80f,z80f,#1<<CFlag
fetch 8
MEND
MACRO
opRLL $reg
opRL r0, $reg, 9
and $reg,$reg,#0xFF000000 ;@mask out high
orr $reg,$reg,r0,lsr #8
fetch 8
MEND
MACRO
opRLb
opRL r0, r0, 25
mov r0,r0,lsr #24
MEND
;@---------------------------------------
MACRO
opRLC $reg1, $reg2, $shift
movs $reg1,$reg2,lsl #$shift
orrcs $reg1,$reg1,#0x01000000
sub r1,opcodes,#0x100
ldrb z80f,[r1,$reg1,lsr #24]
orrcs z80f,z80f,#1<<CFlag
MEND
MACRO
opRLCA
opRLC z80a, z80a, 1
fetch 8
MEND
MACRO
opRLCH $reg
and r0,$reg,#0xFF000000 ;@mask high to r0
adds $reg,$reg,r0
orrcs $reg,$reg,#0x01000000
sub r1,opcodes,#0x100
ldrb z80f,[r1,$reg,lsr #24]
orrcs z80f,z80f,#1<<CFlag
fetch 8
MEND
MACRO
opRLCL $reg
opRLC r0, $reg, 9
and $reg,$reg,#0xFF000000 ;@mask out high
orr $reg,$reg,r0,lsr #8
fetch 8
MEND
MACRO
opRLCb
opRLC r0, r0, 25
mov r0,r0,lsr #24
MEND
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -