;@ 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. .data .align 4 .global DrZ80Run .global DrZ80Ver .equiv INTERRUPT_MODE, 0 ;@0 = Use internal int handler, 1 = Use Mames int handler .equiv FAST_Z80SP, 1 ;@0 = Use mem functions for stack pointer, 1 = Use direct mem pointer .equiv UPDATE_CONTEXT, 0 .equiv DRZ80_FOR_PICODRIVE, 1 .if INTERRUPT_MODE .extern Interrupt .endif .if DRZ80_FOR_PICODRIVE .extern PicoRead8 .extern Pico .extern z80_write .extern ym2612_st .endif DrZ80Ver: .long 0x0001 ;@ --------------------------- Defines ---------------------------- ;@ Make sure that regs/pointers for z80pc to z80sp match up! opcodes .req r3 z80_icount .req r4 cpucontext .req r5 z80pc .req r6 z80a .req r7 z80f .req r8 z80bc .req r9 z80de .req r10 z80hl .req r11 z80sp .req r12 z80xx .req lr .equ z80pc_pointer, 0 ;@ 0 .equ z80a_pointer, z80pc_pointer+4 ;@ 4 .equ z80f_pointer, z80a_pointer+4 ;@ 8 .equ z80bc_pointer, z80f_pointer+4 ;@ .equ z80de_pointer, z80bc_pointer+4 .equ z80hl_pointer, z80de_pointer+4 .equ z80sp_pointer, z80hl_pointer+4 .equ z80pc_base, z80sp_pointer+4 .equ z80sp_base, z80pc_base+4 .equ z80ix, z80sp_base+4 .equ z80iy, z80ix+4 .equ z80i, z80iy+4 .equ z80a2, z80i+4 .equ z80f2, z80a2+4 .equ z80bc2, z80f2+4 .equ z80de2, z80bc2+4 .equ z80hl2, z80de2+4 .equ cycles_pointer, z80hl2+4 .equ previouspc, cycles_pointer+4 .equ z80irq, previouspc+4 .equ z80if, z80irq+1 .equ z80im, z80if+1 .equ z80r, z80im+1 .equ z80irqvector, z80r+1 .equ z80irqcallback, z80irqvector+4 .equ z80_write8, z80irqcallback+4 .equ z80_write16, z80_write8+4 .equ z80_in, z80_write16+4 .equ z80_out, z80_in+4 .equ z80_read8, z80_out+4 .equ z80_read16, z80_read8+4 .equ z80_rebaseSP, z80_read16+4 .equ z80_rebasePC, z80_rebaseSP+4 .equ VFlag, 0 .equ CFlag, 1 .equ ZFlag, 2 .equ SFlag, 3 .equ HFlag, 4 .equ NFlag, 5 .equ Flag3, 6 .equ Flag5, 7 .equ Z80_CFlag, 0 .equ Z80_NFlag, 1 .equ Z80_VFlag, 2 .equ Z80_Flag3, 3 .equ Z80_HFlag, 4 .equ Z80_Flag5, 5 .equ Z80_ZFlag, 6 .equ Z80_SFlag, 7 .equ Z80_IF1, 1<<0 .equ Z80_IF2, 1<<1 .equ Z80_HALT, 1<<2 ;@--------------------------------------- .text .if DRZ80_FOR_PICODRIVE .macro YM2612Read_and_ret8 ldr r0, =ym2612_st ldr r0, [r0] ldrb r0, [r0, #0x11] ;@ ym2612_st->status bx lr .endm .macro YM2612Read_and_ret16 ldr r0, =ym2612_st ldr r0, [r0] ldrb r0, [r0, #0x11] ;@ ym2612_st->status orr r0,r0,r0,lsl #8 bx lr .endm pico_z80_read8: @ addr cmp r0,#0x2000 @ Z80 RAM ldrlt r1,[cpucontext,#z80sp_base] ldrltb r0,[r1,r0] bxlt lr cmp r0,#0x8000 @ 68k bank blt 1f ldr r2,=(Pico+0x22212) ldrh r1,[r2] bic r0,r0,#0x3f8000 orr r0,r0,r1,lsl #15 ldr r1,[r2,#-0xe] @ ROM size cmp r0,r1 ldrlt r1,[r2,#-0x12] @ ROM eorlt r0,r0,#1 @ our ROM is byteswapped ldrltb r0,[r1,r0] bxlt lr stmfd sp!,{r3,r12,lr} bl PicoRead8 ldmfd sp!,{r3,r12,pc} 1: mov r1,r0,lsr #13 cmp r1,#2 @ YM2612 (0x4000-0x5fff) bne 0f and r0,r0,#3 YM2612Read_and_ret8 0: cmp r0,#0x4000 movge r0,#0xff bxge lr ldr r1,[cpucontext,#z80sp_base] bic r0,r0,#0x0fe000 @ Z80 RAM (mirror) ldrb r0,[r1,r0] bx lr pico_z80_read16: @ addr cmp r0,#0x2000 @ Z80 RAM bge 2f ldr r1,[cpucontext,#z80sp_base] ldrb r0,[r1,r0]! ldrb r1,[r1,#1] orr r0,r0,r1,lsl #8 bx lr 2: cmp r0,#0x8000 @ 68k bank blt 1f ldr r2,=(Pico+0x22212) ldrh r1,[r2] bic r0,r0,#0x1f8000 orr r0,r0,r1,lsl #15 ldr r1,[r2,#-0xe] @ ROM size cmp r0,r1 ldr r1,[r2,#-0x12] @ ROM tst r0,#1 eor r0,r0,#1 ldrb r0,[r1,r0]! ldreqb r1,[r1,#-1] ldrneb r1,[r1,#3] @ this is due to byteswapped ROM orr r0,r0,r1,lsl #8 bx lr 3: stmfd sp!,{r3-r5,r12,lr} mov r4,r0 bl PicoRead8 mov r5,r0 add r0,r4,#1 bl PicoRead8 orr r0,r5,r0,lsl #8 ldmfd sp!,{r3-r5,r12,pc} 1: mov r1,r0,lsr #13 cmp r1,#2 @ YM2612 (0x4000-0x5fff) bne 0f and r0,r0,#3 YM2612Read_and_ret16 0: cmp r0,#0x4000 movge r0,#0xff bxge lr ldr r1,[cpucontext,#z80sp_base] bic r0,r0,#0x0fe000 @ Z80 RAM (mirror) ldrb r0,[r1,r0]! ldrb r1,[r1,#1] orr r0,r0,r1,lsl #8 bx lr pico_z80_write8: @ data, addr cmp r1,#0x4000 bge 1f ldr r2,[cpucontext,#z80sp_base] bic r1,r1,#0x0fe000 @ Z80 RAM strb r0,[r2,r1] bx lr 1: stmfd sp!,{r3,r12,lr} bl z80_write ldmfd sp!,{r3,r12,pc} pico_z80_write16: @ data, addr cmp r1,#0x4000 bge 1f ldr r2,[cpucontext,#z80sp_base] bic r1,r1,#0x0fe000 @ Z80 RAM strb r0,[r2,r1]! mov r0,r0,lsr #8 strb r0,[r2,#1] bx lr 1: stmfd sp!,{r3-r5,r12,lr} mov r4,r0 mov r5,r1 bl z80_write mov r0,r4,lsr #8 add r1,r5,#1 bl z80_write ldmfd sp!,{r3-r5,r12,pc} .pool .endif .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 .endm .macro eatcycles cycs sub z80_icount,z80_icount,#\cycs .if UPDATE_CONTEXT str z80_icount,[cpucontext,#cycles_pointer] .endif .endm .macro readmem8 .if UPDATE_CONTEXT str z80pc,[cpucontext,#z80pc_pointer] .endif .if DRZ80_FOR_PICODRIVE bl pico_z80_read8 .else stmfd sp!,{r3,r12} mov lr,pc ldr pc,[cpucontext,#z80_read8] ;@ r0 = addr - data returned in r0 ldmfd sp!,{r3,r12} .endif .endm .macro readmem8HL mov r0,z80hl, lsr #16 readmem8 .endm .macro readmem16 .if UPDATE_CONTEXT str z80pc,[cpucontext,#z80pc_pointer] .endif .if DRZ80_FOR_PICODRIVE bl pico_z80_read16 .else stmfd sp!,{r3,r12} mov lr,pc ldr pc,[cpucontext,#z80_read16] ldmfd sp!,{r3,r12} .endif .endm .macro writemem8 .if UPDATE_CONTEXT str z80pc,[cpucontext,#z80pc_pointer] .endif .if DRZ80_FOR_PICODRIVE bl pico_z80_write8 .else stmfd sp!,{r3,r12} mov lr,pc ldr pc,[cpucontext,#z80_write8] ;@ r0=data r1=addr ldmfd sp!,{r3,r12} .endif .endm .macro writemem8DE mov r1,z80de, lsr #16 writemem8 .endm .macro writemem8HL mov r1,z80hl, lsr #16 writemem8 .endm .macro writemem16 .if UPDATE_CONTEXT str z80pc,[cpucontext,#z80pc_pointer] .endif .if DRZ80_FOR_PICODRIVE bl pico_z80_write16 .else stmfd sp!,{r3,r12} mov lr,pc ldr pc,[cpucontext,#z80_write16] ;@ r0=data r1=addr ldmfd sp!,{r3,r12} .endif .endm .macro copymem8HL_DE .if UPDATE_CONTEXT str z80pc,[cpucontext,#z80pc_pointer] .endif mov r0,z80hl, lsr #16 .if DRZ80_FOR_PICODRIVE bl pico_z80_read8 .else stmfd sp!,{r3,r12} mov lr,pc ldr pc,[cpucontext,#z80_read8] ;@ r0 = addr - data returned in r0 .endif .if UPDATE_CONTEXT str z80pc,[cpucontext,#z80pc_pointer] .endif mov r1,z80de, lsr #16 .if DRZ80_FOR_PICODRIVE bl pico_z80_write8 .else mov lr,pc ldr pc,[cpucontext,#z80_write8] ;@ r0=data r1=addr ldmfd sp!,{r3,r12} .endif .endm ;@--------------------------------------- .macro rebasepc .if UPDATE_CONTEXT str z80pc,[cpucontext,#z80pc_pointer] .endif .if DRZ80_FOR_PICODRIVE bic r0,r0,#0xfe000 ldr r1,[cpucontext,#z80pc_base] add z80pc,r1,r0 .else 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 .endif .endm .macro rebasesp .if UPDATE_CONTEXT str z80pc,[cpucontext,#z80pc_pointer] .endif .if DRZ80_FOR_PICODRIVE bic r0,r0,#0xfe000 ldr r1,[cpucontext,#z80sp_base] add r0,r1,r0 .else stmfd sp!,{r3,r12} mov lr,pc ldr pc,[cpucontext,#z80_rebaseSP] ;@ external function must rebase sp ldmfd sp!,{r3,r12} .endif .endm ;@---------------------------------------------------------------------------- .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< r1 .if FAST_Z80SP .if DRZ80_FOR_PICODRIVE @ notaz: try to protect against stack overflows, which tend to happen in Picodrive because of poor timing ldr r0,[cpucontext,#z80sp_base] cmp z80sp,r0 addle z80sp,z80sp,#0x2000 mov r1,\reg, lsr #8 strb r1,[z80sp,#-1]! cmp z80sp,r0 addle z80sp,z80sp,#0x2000 strb \reg,[z80sp,#-1]! .else mov r1,\reg, lsr #8 strb r1,[z80sp,#-1]! strb \reg,[z80sp,#-1]! .endif .else mov r0,\reg sub z80sp,z80sp,#2 mov r1,z80sp writemem16 .endif .endm .macro opPUSHreg reg .if FAST_Z80SP .if DRZ80_FOR_PICODRIVE ldr r0,[cpucontext,#z80sp_base] cmp z80sp,r0 addle z80sp,z80sp,#0x2000 mov r1,\reg, lsr #24 strb r1,[z80sp,#-1]! cmp z80sp,r0 addle z80sp,z80sp,#0x2000 mov r1,\reg, lsr #16 strb r1,[z80sp,#-1]! .else mov r1,\reg, lsr #24 strb r1,[z80sp,#-1]! mov r1,\reg, lsr #16 strb r1,[z80sp,#-1]! .endif .else mov r0,\reg,lsr #16 sub z80sp,z80sp,#2 mov r1,z80sp writemem16 .endif .endm ;@--------------------------------------- .macro opRESmemHL bit .if DRZ80_FOR_PICODRIVE mov r0,z80hl, lsr #16 bl pico_z80_read8 bic r0,r0,#1<<\bit mov r1,z80hl, lsr #16 bl pico_z80_write8 .else 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} .endif fetch 15 .endm ;@--------------------------------------- .macro opRESmem bit .if DRZ80_FOR_PICODRIVE stmfd sp!,{r0} ;@ save addr as well bl pico_z80_read8 bic r0,r0,#1<<\bit ldmfd sp!,{r1} ;@ restore addr into r1 bl pico_z80_write8 .else 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} .endif fetch 23 .endm ;@--------------------------------------- .macro opRL reg1 reg2 shift movs \reg1,\reg2,lsl \shift tst z80f,#1< 0xFF writemem8HL add z80hl,z80hl,#1<<16 sub z80bc,z80bc,#1<<24 tst z80bc,#0xFF<<24 orrmi z80f,z80f,#1< 0xFF sub z80bc,z80bc,#1<<24 tst z80bc,#0xFF<<24 orrmi z80f,z80f,#1< 0xFF writemem8HL sub z80hl,z80hl,#1<<16 sub z80bc,z80bc,#1<<24 tst z80bc,#0xFF<<24 orrmi z80f,z80f,#1< 0xFF sub z80bc,z80bc,#1<<24 tst z80bc,#0xFF<<24 orrmi z80f,z80f,#1< 0xFF writemem8HL add z80hl,z80hl,#1<<16 sub z80bc,z80bc,#1<<24 tst z80bc,#0xFF<<24 orrmi z80f,z80f,#1< 0xFF sub z80bc,z80bc,#1<<24 tst z80bc,#0xFF<<24 orrmi z80f,z80f,#1< 0xFF writemem8HL sub z80hl,z80hl,#1<<16 sub z80bc,z80bc,#1<<24 tst z80bc,#0xFF<<24 orrmi z80f,z80f,#1< 0xFF sub z80bc,z80bc,#1<<24 tst z80bc,#0xFF<<24 orrmi z80f,z80f,#1<