|
|
0.33
;----------------------------------------------------------------------------;
; RAZE-x86 Z80 emulator.
; version 1.06
;
; Copyright (c) 1999 Richard Mitton
;
; This may only be distributed as part of the complete RAZE package.
; See RAZE.TXT for license information.
;----------------------------------------------------------------------------;
; this is needed for compiling with allegro in coff mode
%macro cglobal 1
global %1
%endmacro
;%macro cglobal 1
; global _%1
; %define %1 _%1
;%endmacro
; You are not expected to understand this.
;----------------------------------------------------------------------------;
; Comment these in/out for faster speed (less accurate):
%define EMULATE_UNDOC_FLAGS ; a couple of undocumented flags
%define EMULATE_BITS_3_5 ; bits 3/5 of the flags (undocumented)
%define EMULATE_WEIRD_STUFF ; misc *very obscure* undocumented behaviour
%define EMULATE_R_REGISTER ; precise R register (not usually needed)
;;;;%define USE_FETCH_CALLBACK ; call a callback for every fetch (slow!)
;----------------------------------------------------------------------------;
; Registers:
; AF = ax (flags in AH)
; HL = bx
; BC = cx
; PC = si
; R = ebp
;
; GCC wants EBX, ESI, EDI, ESP, and EBP to be preserved at all times
; DH should always be clear between macros
; The high 16-bits of all registers should be clear at all times (except EBP)
; This assumes LAHF will set bit 1 of AH. (supposed to be undefined...)
BITS 32
SECTION .bss USE32
; Maximum number of memory handlers
%define MAX_MEM_HANDLERS 64
; The current context
align 16
context_start:
z80_AF resd 1
z80_BC resd 1
z80_DE resd 1
z80_HL resd 1
z80_IX resd 1
z80_IY resd 1
z80_PC resd 1
z80_SP resd 1
z80_AF2 resd 1
z80_BC2 resd 1
z80_DE2 resd 1
z80_HL2 resd 1
z80_IFF1 resb 1
z80_IFF2 resb 1
z80_R resd 1
z80_R2 resd 1
z80_I resb 1
z80_flag35 resb 1
z80_IM resb 1
z80_IRQVector resb 1
z80_IRQLine resb 1
z80_halted resb 1
z80_Extra_Cycles resd 1
registers_end:
z80_Fetch resd 256
z80_Read resd (256*2)
z80_Write resd (256*2)
z80_In resd 1
z80_Out resd 1
z80_RetI resd 1
z80_Fetch_Callback resd 1
_read_handlers resd 4*MAX_MEM_HANDLERS
_write_handlers resd 4*MAX_MEM_HANDLERS
context_end:
resd 1 ; safety gap, so z80_reset can use 32-bit transfers
; Variables
z80_ICount resd 1
z80_Initial_ICount resd 1
z80_TempICount resd 1
z80_afterEI resb 1
SECTION .text USE32
;----------------------------------------------------------------------------;
; Prepare to call a GCC function
%macro CALLGCC_START 0
mov [z80_AF], ezAF ; eax
mov [z80_BC], ezBC ; ecx
mov [z80_PC], ezPC ; esi
mov [z80_R], zR ; ebp
%endmacro
; Return from a GCC function
%macro CALLGCC_END 0
mov ezAF, [z80_AF] ; eax
mov ezBC, [z80_BC] ; ecx
mov ezPC, [z80_PC] ; esi
mov zR, [z80_R] ; ebp
%endmacro
; Read a byte from the PC, into DL
; GETBYTE
%macro GETBYTE 0
%ifdef USE_FETCH_CALLBACK
CALLGCC_START
push ezPC
call [z80_Fetch_Callback]
add esp, 4
CALLGCC_END
%endif
mov edx, ezPC
shr edx, 8
mov edi, [z80_Fetch+edx*4]
mov dl, [edi+ezPC]
inc zPC
xor edi, edi
%endmacro
; Read a byte from the PC, sign-extended into DI
; GETDISP
%macro GETDISP 0
%ifdef USE_FETCH_CALLBACK
CALLGCC_START
push ezPC
call [z80_Fetch_Callback]
add esp, 4
CALLGCC_END
%endif
mov edx, ezPC
shr edx, 8
mov edx, [z80_Fetch+edx*4]
movsx di, [edx+ezPC]
inc zPC
xor edx, edx
%endmacro
; Read a word from the PC, into DI
; GETWORD
%macro GETWORD 0
%ifdef USE_FETCH_CALLBACK
CALLGCC_START
push ezPC
call [z80_Fetch_Callback]
add esp, 4
CALLGCC_END
%endif
mov [z80_BC], ezBC
mov edx, ezPC ; low byte
shr edx, 8
mov edi, [z80_Fetch+edx*4]
mov dl, [edi+ezPC]
inc zPC
%ifdef USE_FETCH_CALLBACK
push edx
CALLGCC_START
push ezPC
call [z80_Fetch_Callback]
add esp, 4
CALLGCC_END
pop edx
%endif
mov ecx, ezPC ; high byte
shr ecx, 8
mov edi, [z80_Fetch+ecx*4]
mov dh, [edi+ezPC]
inc zPC
mov edi, edx
mov ezBC, [z80_BC]
xor edx, edx
%endmacro
; Read a byte from memory (DI) into DL
; MEMREAD
%macro MEMREAD 0
CALLGCC_START
mov edx, edi
shr edx, 8
mov ecx, [z80_Read+edx*8]
test ecx, ecx ; if handler exists, call it
jnz %%handler
; no handler, so go direct
mov ecx, [z80_Read+edx*8+4]
mov dl, [ecx+edi]
jmp %%finish
%%handler:
push edi
call ecx
xor edx, edx
add esp, 4
mov dl, al
%%finish:
CALLGCC_END
%endmacro
; Write a byte in DL to memory (DI)
%macro MEMWRITE 0
CALLGCC_START
xor eax, eax
mov al, dl
mov edx, edi
shr edx, 8
mov ecx, [z80_Write+edx*8]
test ecx, ecx ; if handler exists, call it
jnz %%handler
; no handler, so go direct
mov ecx, [z80_Write+edx*8+4]
mov [ecx+edi], al
jmp %%finish
%%handler:
push eax
push edi
call ecx
add esp, 8
%%finish:
CALLGCC_END
xor edx, edx
%endmacro
; Read a byte from port (DI) into DL
; IOREAD
%macro IOREAD 0
push edi
CALLGCC_START
call [z80_In]
xor edx, edx
add esp, 4
mov dl, al
CALLGCC_END
%endmacro
; Write a byte in DL to port (DI)
%macro IOWRITE 0
CALLGCC_START
xor dh, dh
push edx
push edi
call [z80_Out]
add esp, 8
CALLGCC_END
xor edx, edx
%endmacro
; Align code to the default boundary
%macro ALIGN 0
align 4
%endmacro
; Define an instruction
; DEF prefix, opcode, std_cycles, extra_cycles
%macro DEF 4
ALIGN
%define std_cycles %3
%define extra_cycles %4
%{1}_%2:
%endmacro
; Subtract the clock cycles for this instruction from the ICount
%macro DO_CYCLES 0
sub dword [z80_ICount], std_cycles
jbe near z80_finish
%endmacro
; Subtract the extra clock cycles for this instruction from the ICount
%macro DO_EXTRA_CYCLES 0
sub dword [z80_ICount], extra_cycles
jbe near z80_finish
%endmacro
; Finish straight away
%macro EXIT 0
jmp z80_finish
%endmacro
; Jump to the next instruction
%macro NEXT 0
%ifdef EMULATE_R_REGISTER
inc zR
%endif
GETBYTE
jmp [OpTable+edx*4]
%endmacro
; Check the IRQ line, cause an interrupt if needed
%macro CHECK_IRQ 0
cmp [z80_IRQLine], byte 0 ; check the IRQ line
je near %%finish
cmp [z80_IFF1], byte 0 ; check ints are enabled
je near %%finish
; disable interrupts
mov [z80_IFF1], byte 0
mov [z80_IFF2], byte 0
%ifdef EMULATE_R_REGISTER
inc zR
%endif
mov [z80_halted], byte 0 ; Un-HALT the Z80
mov edx, ezPC ; write the PC
dec zSP
xchg dl, dh
mov edi, ezSP
MEMWRITE
dec zSP
mov edx, ezPC
mov edi, ezSP
MEMWRITE
cmp [z80_IM], byte 0
jne %%not_im0
; IM 0, 13 T-states
add [z80_Extra_Cycles], dword 13
mov dl, [z80_IRQVector]
sub dl, 0c7h
movzx ezPC, dl
jmp %%finish
%%not_im0:
cmp [z80_IM], byte 1
jne %%not_im1
; IM 1, 13 T-states
add [z80_Extra_Cycles], dword 13
mov ezPC, 38h
jmp %%finish
%%not_im1:
; IM 2, 19 T-states
add [z80_Extra_Cycles], dword 19
mov dl, [z80_IRQVector]
mov dh, zI
mov edi, edx
MEMREAD
inc di
mov ezPC, edx
MEMREAD
xchg dl, dh
or ezPC, edx
xor dh, dh
%%finish:
%endmacro
;----------------------------------------------------------------------------;
; Helper functions
; Add A, %1
%macro DO_ADD 1
add zA, %1
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], zA
%endif
lahf
jo %%set_overflow
and zF, FLAG_S|FLAG_Z|FLAG_H|FLAG_C
jmp %%finish
%%set_overflow:
and zF, FLAG_S|FLAG_Z|FLAG_H|FLAG_C
or zF, FLAG_P
%%finish:
%endmacro
; Sub A, %1
%macro DO_SUB 1
sub zA, %1
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], zA
%endif
lahf
jo %%set_overflow
and zF, FLAG_S|FLAG_Z|FLAG_H|FLAG_C|FLAG_N
jmp %%finish
%%set_overflow:
or zF, FLAG_P
%%finish:
%endmacro
; Adc A, %1
%macro DO_ADC 1
ror zF, 1
adc zA, %1
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], zA
%endif
lahf
jo %%set_overflow
and zF, FLAG_S|FLAG_Z|FLAG_H|FLAG_C
jmp %%finish
%%set_overflow:
and zF, FLAG_S|FLAG_Z|FLAG_H|FLAG_C
or zF, FLAG_P
%%finish:
%endmacro
; Sbc A, %1
%macro DO_SBC 1
ror zF, 1
sbb zA, %1
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], zA
%endif
lahf
jo %%set_overflow
and zF, FLAG_S|FLAG_Z|FLAG_H|FLAG_C|FLAG_N
jmp %%finish
%%set_overflow:
or zF, FLAG_P
%%finish:
%endmacro
; And A, %1
%macro DO_AND 1
and zA, %1
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], zA
%endif
lahf
and zF, ~(FLAG_N|FLAG_C) ; clear N and carry
or zF, FLAG_H ; set half-carry
%endmacro
; Or A, %1
%macro DO_OR 1
or zA, %1
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], zA
%endif
lahf
and zF, ~(FLAG_N|FLAG_C|FLAG_H) ; clear N, carry and half-carry
%endmacro
; Xor A, %1
%macro DO_XOR 1
xor zA, %1
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], zA
%endif
lahf
and zF, ~(FLAG_N|FLAG_C|FLAG_H) ; clear N, carry and half-carry
%endmacro
; Cp A, %1
%macro DO_CP 1
%ifdef EMULATE_BITS_3_5
mov ah, %1
mov [z80_flag35], ah
%endif
cmp zA, %1
lahf
jo %%overflow
and zF, ~FLAG_P ; clear the overflow
or zF, FLAG_N ; set the N flag
jmp %%finish
%%overflow:
or zF, FLAG_P|FLAG_N ; set the overflow and N flag
%%finish:
%endmacro
; Inc %1
%macro DO_INC 1
and zF, FLAG_C ; leave carry alone
%ifnidn %1, dl
mov dl, %1
%endif
or zF, [INC_Table+edx]
inc %1
%ifdef EMULATE_BITS_3_5
%ifnidn %1, dl
inc dl
%endif
mov [z80_flag35], dl
%endif
%endmacro
; Dec %1
%macro DO_DEC 1
and zF, FLAG_C ; leave carry alone
%ifnidn %1, dl
mov dl, %1
%endif
or zF, [DEC_Table+edx]
dec %1
%ifdef EMULATE_BITS_3_5
%ifnidn %1, dl
dec dl
%endif
mov [z80_flag35], dl
%endif
%endmacro
; Add16 %1, %2
%macro DO_ADD16 2
%ifidn %2, dx
%error "DX used as parameter for DO_ADD16!"
%endif
mov edi, e%2
%ifdef EMULATE_UNDOC_FLAGS
mov edx, e%1
%endif
and zF, FLAG_S|FLAG_Z|FLAG_P
add %1, di ; do it
adc zF, 0 ; merge the new carry in
%ifdef EMULATE_UNDOC_FLAGS
xor edx, e%1 ; work out our new half-carry
xor edx, edi
and dh, FLAG_H
or zF, dh
%endif
%ifdef EMULATE_BITS_3_5
mov dl, h%1
mov [z80_flag35], dl
%endif
%ifdef EMULATE_UNDOC_FLAGS
xor dh, dh
%endif
%endmacro
; Adc16 %1, %2
%macro DO_ADC16 2
%ifidn %2, dx
%error "DX used as parameter for DO_ADC16!"
%endif
mov edi, e%2
%ifdef EMULATE_UNDOC_FLAGS
mov edx, e%1
%endif
ror zF, 1 ; load the carry
adc %1, %2
lahf
jo %%overflow
and zF, ~(FLAG_N|FLAG_H|FLAG_P) ; clear N,H and overflow
jmp %%finish
%%overflow:
and zF, ~(FLAG_N|FLAG_H) ; clear N and H
or zF, FLAG_P ; set overflow
%%finish:
%ifdef EMULATE_UNDOC_FLAGS
xor edx, e%1 ; work out our new half-carry
xor edx, edi
and dh, FLAG_H
or zF, dh
%endif
%ifdef EMULATE_BITS_3_5
mov dl, h%1
mov [z80_flag35], dl
%endif
%ifdef EMULATE_UNDOC_FLAGS
xor dh, dh
%endif
%endmacro
; Sbc16 %1, %2
%macro DO_SBC16 2
%ifidn %2, dx
%error "DX used as parameter for DO_SBC16!"
%endif
%ifdef EMULATE_UNDOC_FLAGS
mov edi, e%2
%endif
mov edx, e%1
ror zF, 1 ; load the carry
sbb %1, %2
lahf
jo %%overflow
and zF, ~(FLAG_P|FLAG_H) ; clear H and overflow
or zF, FLAG_N ; set N
jmp %%finish
%%overflow:
or zF, FLAG_N|FLAG_P ; set overflow and N
and zF, ~FLAG_H ; clear H
%%finish:
%ifdef EMULATE_UNDOC_FLAGS
xor edx, e%1 ; work out our new half-carry
xor edx, edi
and dh, FLAG_H
or zF, dh
%endif
%ifdef EMULATE_BITS_3_5
mov dl, h%1
mov [z80_flag35], dl
%endif
%ifdef EMULATE_UNDOC_FLAGS
xor dh, dh
%endif
%endmacro
; Rotate method, reg8
%macro DO_ROT 2
%ifidn %1, RLA
mov dl, zF
and dl, FLAG_S|FLAG_Z|FLAG_P
sahf
rcl zA, 1
adc dl, 0
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], zA
%endif
mov zF, dl
%elifidn %1, RRA
mov dl, zF
and dl, FLAG_S|FLAG_Z|FLAG_P
sahf
rcr zA, 1
adc dl, 0
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], zA
%endif
mov zF, dl
%elifidn %1, RLCA
and zF, FLAG_S|FLAG_Z|FLAG_P
rol zA, 1
adc zF, 0
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], zA
%endif
%elifidn %1, RRCA
and zF, FLAG_S|FLAG_Z|FLAG_P
ror zA, 1
adc zF, 0
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], zA
%endif
%else
%ifnidn %2, dl
mov dl, %2
%endif
%ifidn %1, RLC
rol dl, 1
%elifidn %1, RRC
ror dl, 1
%elifidn %1, RL
sahf
rcl dl, 1
%elifidn %1, RR
sahf
rcr dl, 1
%endif
adc dh, dh
test dl, dl
lahf
and zF, FLAG_S|FLAG_Z|FLAG_P
or zF, dh
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], dl
%endif
%ifnidn %2, dl
mov %2, dl
%endif
xor dh, dh
%endif
%endmacro
; Shift method, reg8
%macro DO_SHF 2
%ifnidn %2, dl
mov dl, %2
%endif
%ifidn %1, SLA
add dl, dl
adc dh, dh
%elifidn %1, SLL
add dl, dl
adc dh, dh
inc dl
%elifidn %1, SRA
sar dl, 1
adc dh, dh
%elifidn %1, SRL
shr dl, 1
adc dh, dh
%endif
test dl, dl
lahf
and zF, FLAG_S|FLAG_Z|FLAG_P
or zF, dh
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], dl
%endif
%ifnidn %2, dl
mov %2, dl
%endif
xor dh, dh
%endmacro
; BIT r,n n = bit (0-7)
; r = 8-bit register
%macro DO_BIT 2
and zF, FLAG_C
test %1, (1 << %2)
%ifdef EMULATE_BITS_3_5
; bit 3 and 5 are set from the register
; (actually they are bizarrely set, but
; there's no point emulating that, it's just
; plain silly...)
%ifnidn %1, dl
mov dl, %1 ; put in DL if not there already
%endif
mov [z80_flag35], dl
%endif
jz %%bit_is_clear
%ifidn %2, 7
or zF, FLAG_H|FLAG_S ; set sign bit, if testing bit 7
%else
or zF, FLAG_H ; set half-carry, and parity
%endif
jmp %%finish
%%bit_is_clear:
or zF, FLAG_H|FLAG_Z|FLAG_P ; set half-carry, parity, and zero
%%finish:
%endmacro
; SET r,n n = bit (0-7)
; r = 8-bit register
%macro DO_SET 2
or %1, (1 << %2)
%endmacro
; RES r,n n = bit (0-7)
; r = 8-bit register
%macro DO_RES 2
and %1, ~(1 << %2)
%endmacro
;----------------------------------------------------------------------------;
; Here are the interface functions:
; Move a register to another
; LD_R_R d8, s8 s8 = src reg, d8 = dest reg
%macro LD_R_R 2
%ifnidn %1, %2
%ifidn %2, D
mov dl, zD
mov z%1, dl
%elifidn %2, E
mov dl, zE
mov z%1, dl
%else
mov z%1, z%2
%endif
%endif
DO_CYCLES
NEXT
%endmacro
; Move a register to another (IXh/IXl)
; LD_XYr_XYr d8, s8 s8 = src reg, d8 = dest reg
%macro LD_XYr_XYr 2
%ifnidn %1, %2
mov dl, z%2
mov z%1, dl
%endif
DO_CYCLES
NEXT
%endmacro
; Move an immediate byte into a register
; LD_R_N d8 d8 = dest reg
%macro LD_R_N 1
GETBYTE
mov z%1, dl
DO_CYCLES
NEXT
%endmacro
; Move from (RR) into a register
; LD_R_mRR d8, s16 d8 = dest reg, s16 = src reg
%macro LD_R_mRR 2
mov edi, ez%2
MEMREAD
mov z%1, dl
DO_CYCLES
NEXT
%endmacro
; Move from (XY+dd) into a register
; LD_R_mXY d8, s16 d8 = dest reg, s16 = src reg
%macro LD_R_mXY 2
GETDISP
add di, z%2
MEMREAD
mov z%1, dl
DO_CYCLES
NEXT
%endmacro
; Move from a register into (RR)
; LD_mRR_R d16, s8 d16 = destreg, s8 = src reg
%macro LD_mRR_R 2
mov edi, ez%1
mov dl, z%2
MEMWRITE
DO_CYCLES
NEXT
%endmacro
; Move from a register into (XY+dd)
; LD_mXY_R d16, s8 d16 = dest reg, s8 = src reg
%macro LD_mXY_R 2
GETDISP
add di, z%1
mov dl, z%2
MEMWRITE
DO_CYCLES
NEXT
%endmacro
; Move an immediate into (RR)
; LD_mRR_N d16 d16 = dest reg
%macro LD_mRR_N 1
GETBYTE
mov edi, ez%1
MEMWRITE
DO_CYCLES
NEXT
%endmacro
; Move an immediate into (XY+dd)
; LD_mXY_N d16 d16 = dest reg
%macro LD_mXY_N 1
GETDISP
add di, z%1
push edi
GETBYTE
pop edi
MEMWRITE
DO_CYCLES
NEXT
%endmacro
; Move from (NN) into a register
; LD_R_mNN d8 d8 = dest reg
%macro LD_R_mNN 1
GETWORD
MEMREAD
mov z%1, dl
DO_CYCLES
NEXT
%endmacro
; Move from a register into (NN)
; LD_mNN_R s8 s8 = src reg
%macro LD_mNN_R 1
GETWORD
mov dl, z%1
MEMWRITE
DO_CYCLES
NEXT
%endmacro
; Move the Interrupt register into a register
; LD_R_I d8 d8 = dest reg
%macro LD_R_I 1
mov z%1, zI
and zF, FLAG_C ; keep old carry
mov dl, zF
test z%1, z%1
lahf
and zF, FLAG_S|FLAG_Z ; set S/Z from the I register
or zF, dl
or zF, [z80_IFF2]
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], z%1
%endif
DO_CYCLES
NEXT
%endmacro
; Move a register into the Interrupt register
; LD_I_R s8 s8 = src reg
%macro LD_I_R 1
mov zI, z%1
DO_CYCLES
NEXT
%endmacro
; Move the Refresh register into a register
; LD_R_Rf d8 d8 = dest reg
%macro LD_R_Rf 1
mov edx, [z80_R2]
and edx, 80h ; take bits 0-6 from R, bit 7 from R2
%ifndef EMULATE_R_REGISTER
; attempt to fake the R-register
; take the ICount, invert it, divide by 4
; this produces an increasing counter, roughly proportional to
; the number of instructions done
mov zR, [z80_ICount]
not zR
shr zR, 2
%endif
and zR, 7fh
or edx, zR
mov z%1, dl
mov dl, zF
and dl, FLAG_C ; keep the old carry
test z%1, z%1
lahf
and zF, FLAG_S|FLAG_Z
or zF, dl
or zF, [z80_IFF2]
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], z%1
%endif
DO_CYCLES
NEXT
%endmacro
; Move a register into the Refresh register
; LD_Rf_R s8 s8 = src reg
%macro LD_Rf_R 1
mov dl, z%1
mov zR, edx
mov [z80_R2], edx
DO_CYCLES
NEXT
%endmacro
; Move a 16-bit immediate into a register
; LD_RR_NN d16 d16 = dest reg
%macro LD_RR_NN 1
GETWORD
mov ez%1, edi
DO_CYCLES
NEXT
%endmacro
; Move from (NN) into a 16-bit register
; LD_RR_mNN d16 d16 = dest reg
%macro LD_RR_mNN 1
GETWORD
MEMREAD
mov lz%1, dl
inc di
MEMREAD
mov hz%1, dl
DO_CYCLES
NEXT
%endmacro
; Move from a 16-bit register into (NN)
; LD_mNN_RR s16 s16 = src reg
%macro LD_mNN_RR 1
GETWORD
mov dl, lz%1
MEMWRITE
inc di
mov dl, hz%1
MEMWRITE
DO_CYCLES
NEXT
%endmacro
; Move from a 16-bit register into another
; LD_RR_RR d16, s16 s16 = src reg, d16 = dest reg
%macro LD_RR_RR 2
mov ez%1, ez%2
DO_CYCLES
NEXT
%endmacro
; Move from a 16-bit register into another
; LD_RR_XY d16, s16 s16 = src reg, d16 = dest reg
%macro LD_RR_XY 2
mov edi, ez%2
mov ez%1, edi
DO_CYCLES
NEXT
%endmacro
; Push a word on the stack
; PUSH_RR s16 s16 = src reg
%macro PUSH_RR 1
mov dl, hz%1
dec zSP
mov edi, ezSP
MEMWRITE
dec zSP
mov edi, ezSP
%ifidn %1, AF
; merge bits 3 and 5 in
and zF, ~(FLAG_3|FLAG_5)
mov dl, [z80_flag35]
and dl, FLAG_3|FLAG_5
or zF, dl
%endif
mov dl, lz%1
MEMWRITE
DO_CYCLES
NEXT
%endmacro
; Pop a word from the stack
; POP_RR s16 s16 = src reg
%macro POP_RR 1
mov edi, ezSP
MEMREAD
%ifidn %1, AF
mov [z80_flag35], dl ; take out bits 3/5
%endif
mov lz%1, dl
inc zSP
mov edi, ezSP
MEMREAD
mov hz%1, dl
inc zSP
DO_CYCLES
NEXT
%endmacro
; Exchange 2 16-bit registers
; EX_RR_RR s16, d16 s16 = src reg, d16 = dest reg
%macro EX_RR_RR 2
xchg ez%1, ez%2
DO_CYCLES
NEXT
%endmacro
; Exchange AF with AF'
; EX_AF_AF2
%macro EX_AF_AF2 0
; Merge bits 3+5 of the flags in first
and zF, ~(FLAG_3|FLAG_5)
mov dl, [z80_flag35]
and dl, FLAG_3|FLAG_5
or zF, dl
xchg ezAF, ezAF2
; Un-merge the flags again
mov [z80_flag35], zF
DO_CYCLES
NEXT
%endmacro
; Exchange the 16-bit registers with their primes
; EXX
%macro EXX 0
mov edi, ezDE
xchg ezBC, ezBC2
xchg ezHL, ezHL2
xchg edi, ezDE2
mov ezDE, edi
DO_CYCLES
NEXT
%endmacro
; Exchange a 16-bit register with (RR)
; EX_RR_mRR d16, m16 d16 = dest reg, m16 = memory reg
%macro EX_RR_mRR 2
mov edi, ez%2 ; swap low byte
MEMREAD
xchg dl, lz%1
MEMWRITE
inc di ; swap high byte
MEMREAD
xchg dl, hz%1
MEMWRITE
DO_CYCLES
NEXT
%endmacro
; Move from (HL) to (DE), post-increment
; LDI
%macro LDI 0
mov edi, ezHL
MEMREAD
%ifdef EMULATE_BITS_3_5
push edx
%endif
mov edi, ezDE
MEMWRITE
%ifdef EMULATE_BITS_3_5
pop edx
add dl, zA
mov dh, dl
shl dl, 4
and edx, FLAG_5 | (FLAG_3 << 8)
or dl, dh
mov [z80_flag35], dl
xor dh, dh
%endif
and zF, FLAG_S|FLAG_Z|FLAG_C
inc zHL
inc zDE
dec zBC
jz %%ldi_zero
or zF, FLAG_P
%%ldi_zero:
DO_CYCLES
NEXT
%endmacro
; Move from (HL) to (DE), post-decrement
; LDD
%macro LDD 0
mov edi, ezHL
MEMREAD
%ifdef EMULATE_BITS_3_5
push edx
%endif
mov edi, ezDE
MEMWRITE
%ifdef EMULATE_BITS_3_5
pop edx
add dl, zA
mov dh, dl
shl dl, 4
and edx, FLAG_5 | (FLAG_3 << 8)
or dl, dh
mov [z80_flag35], dl
xor dh, dh
%endif
and zF, FLAG_S|FLAG_Z|FLAG_C
dec zHL
dec zDE
dec zBC
jz %%ldd_zero
or zF, FLAG_P
%%ldd_zero:
DO_CYCLES
NEXT
%endmacro
; Move from (HL) to (DE), post-increment, repeat
; LDIR
%macro LDIR 0
%ifdef EMULATE_WEIRD_STUFF
; Code marked with CG is from Charles Gallagher, to fix the
; Spectrum game 'Quazatron'
push ezPC ; CG
sub zPC, 2 ; CG
mov edi, ezPC ; CG
shr edi, 8 ; CG
add ezPC, [z80_Fetch+edi*4] ; CG
%endif
%%ldir_loop:
%ifdef EMULATE_WEIRD_STUFF
cmp [ezPC], word 0b0edh ; CG - check for self modifiying code!
jne near %%ldir_modified
%endif
mov edi, ezHL
MEMREAD
%ifdef EMULATE_BITS_3_5
push edx
%endif
mov edi, ezDE
MEMWRITE
%ifdef EMULATE_BITS_3_5
pop edx
%endif
inc zHL
inc zDE
dec zBC
jz %%ldir_zero
%ifdef EMULATE_R_REGISTER
inc zR
%endif
sub [z80_ICount], dword extra_cycles
ja near %%ldir_loop
%ifdef EMULATE_WEIRD_STUFF
pop ezPC ; CG
%endif
and zF, FLAG_S|FLAG_Z|FLAG_C
%ifdef EMULATE_BITS_3_5
add dl, zA
mov dh, dl
shl dl, 4
and edx, FLAG_5 | (FLAG_3 << 8)
or dl, dh
mov [z80_flag35], dl
xor dh, dh
%endif
or zF, FLAG_P
sub zPC, 2 ; rewind to instruction start
EXIT
%ifdef EMULATE_WEIRD_STUFF
%%ldir_modified:
sub [esp], word 2 ; CG
%endif
%%ldir_zero:
%ifdef EMULATE_WEIRD_STUFF
pop ezPC ; CG
%endif
and zF, FLAG_S|FLAG_Z|FLAG_C
%ifdef EMULATE_BITS_3_5
add dl, zA
mov dh, dl
shl dl, 4
and edx, FLAG_5 | (FLAG_3 << 8)
or dl, dh
mov [z80_flag35], dl
xor dh, dh
%endif
DO_CYCLES
NEXT
%endmacro
; Move from (HL) to (DE), post-decrement, repeat
; LDDR
%macro LDDR 0
%%lddr_loop:
mov edi, ezHL
MEMREAD
%ifdef EMULATE_BITS_3_5
push edx
%endif
mov edi, ezDE
MEMWRITE
%ifdef EMULATE_BITS_3_5
pop edx
%endif
dec zHL
dec zDE
dec zBC
jz %%lddr_zero
%ifdef EMULATE_R_REGISTER
inc zR
%endif
sub [z80_ICount], dword extra_cycles
ja near %%lddr_loop
and zF, FLAG_S|FLAG_Z|FLAG_C
%ifdef EMULATE_BITS_3_5
add dl, zA
mov dh, dl
shl dl, 4
and edx, FLAG_5 | (FLAG_3 << 8)
or dl, dh
mov [z80_flag35], dl
xor dh, dh
%endif
or zF, FLAG_P
sub zPC, 2 ; rewind to instruction start
EXIT
%%lddr_zero:
and zF, FLAG_S|FLAG_Z|FLAG_C
%ifdef EMULATE_BITS_3_5
add dl, zA
mov dh, dl
shl dl, 4
and edx, FLAG_5 | (FLAG_3 << 8)
or dl, dh
mov [z80_flag35], dl
xor dh, dh
%endif
DO_CYCLES
NEXT
%endmacro
; Compare A against (HL), post-increment
; CPI
%macro CPI 0
mov edi, ezHL
MEMREAD
and zF, FLAG_C ; keep the old carry
mov dh, zF
cmp zA, dl
lahf
and zF, FLAG_S|FLAG_Z|FLAG_H|FLAG_N
or zF, dh ; SZHN from compare, C unchanged, rest are zero
inc zHL
dec zBC
jz %%cpi_zero
or zF, FLAG_P ; set P if BC != 0
%%cpi_zero:
%ifdef EMULATE_BITS_3_5
mov dh, zA
sub dh, dl
test zF, FLAG_H
jz %%cpi_hzero
dec dh
%%cpi_hzero:
mov dl, dh
shl dl, 4
and edx, FLAG_5 | (FLAG_3 << 8)
or dl, dh
mov [z80_flag35], dl
%endif
xor dh, dh
DO_CYCLES
NEXT
%endmacro
; Compare A against (HL), post-decrement
; CPD
%macro CPD 0
mov edi, ezHL
MEMREAD
and zF, FLAG_C ; keep the old carry
mov dh, zF
cmp zA, dl
lahf
and zF, FLAG_S|FLAG_Z|FLAG_H|FLAG_N
or zF, dh ; SZHN from compare, C unchanged, rest are zero
dec zHL
dec zBC
jz %%cpd_zero
or zF, FLAG_P ; set P if BC != 0
%%cpd_zero:
%ifdef EMULATE_BITS_3_5
mov dh, zA
sub dh, dl
test zF, FLAG_H
jz %%cpd_hzero
dec dh
%%cpd_hzero:
mov dl, dh
shl dl, 4
and edx, FLAG_5 | (FLAG_3 << 8)
or dl, dh
mov [z80_flag35], dl
%endif
xor dh, dh
DO_CYCLES
NEXT
%endmacro
; Compare A against (HL), post-increment, repeat
; CPIR
%macro CPIR 0
and zF, FLAG_C ; keep the old carry
%%cpir_loop:
mov edi, ezHL
MEMREAD
inc zHL
dec zBC
jz %%cpir_end_bc ; end due to BC=0
%ifdef EMULATE_R_REGISTER
inc zR
%endif
cmp zA, dl
je %%cpir_end_equal ; end due to A=(HL)
sub [z80_ICount], dword extra_cycles
ja %%cpir_loop
; out of cycles, but not finished
mov dh, zF
cmp zA, dl
lahf
and zF, FLAG_S|FLAG_Z|FLAG_H|FLAG_N
or zF, dh ; SZHN from compare, C unchanged, rest are zero
%ifdef EMULATE_BITS_3_5
mov dh, zA
sub dh, dl
test zF, FLAG_H
jz %%cpir_hzero
dec dh
%%cpir_hzero:
mov dl, dh
shl dl, 4
and edx, FLAG_5 | (FLAG_3 << 8)
or dl, dh
mov [z80_flag35], dl
%endif
or zF, FLAG_P ; set P to indicate not finished
sub zPC, 2 ; rewind to instruction start
xor dh, dh
EXIT
%%cpir_end_equal:
or zF, FLAG_P ; set P to indicate not finished
%%cpir_end_bc:
mov dh, zF
cmp zA, dl
lahf
and zF, FLAG_S|FLAG_Z|FLAG_H|FLAG_N
or zF, dh ; SZHN from compare, C unchanged, rest are zero
%ifdef EMULATE_BITS_3_5
mov dh, zA
sub dh, dl
test zF, FLAG_H
jz %%cpir_hzero2
dec dh
%%cpir_hzero2:
mov dl, dh
shl dl, 4
and edx, FLAG_5 | (FLAG_3 << 8)
or dl, dh
mov [z80_flag35], dl
%endif
xor dh, dh
DO_CYCLES
NEXT
%endmacro
; Compare A against (HL), post-decrement, repeat
; CPDR
%macro CPDR 0
and zF, FLAG_C ; keep the old carry
%%cpdr_loop:
mov edi, ezHL
MEMREAD
dec zHL
dec zBC
jz %%cpdr_end_bc ; end due to BC=0
%ifdef EMULATE_R_REGISTER
inc zR
%endif
cmp zA, dl
je %%cpdr_end_equal ; end due to A=(HL)
sub [z80_ICount], dword extra_cycles
ja %%cpdr_loop
; out of cycles, but not finished
mov dh, zF
cmp zA, dl
lahf
and zF, FLAG_S|FLAG_Z|FLAG_H|FLAG_N
or zF, dh ; SZHN from compare, C unchanged, rest are zero
%ifdef EMULATE_BITS_3_5
mov dh, zA
sub dh, dl
test zF, FLAG_H
jz %%cpdr_hzero
dec dh
%%cpdr_hzero:
mov dl, dh
shl dl, 4
and edx, FLAG_5 | (FLAG_3 << 8)
or dl, dh
mov [z80_flag35], dl
%endif
or zF, FLAG_P ; set P to indicate not finished
sub zPC, 2 ; rewind to instruction start
xor dh, dh
EXIT
%%cpdr_end_equal:
or zF, FLAG_P ; set P to indicate not finished
%%cpdr_end_bc:
mov dh, zF
cmp zA, dl
lahf
and zF, FLAG_S|FLAG_Z|FLAG_H|FLAG_N
or zF, dh ; SZHN from compare, C unchanged, rest are zero
%ifdef EMULATE_BITS_3_5
mov dh, zA
sub dh, dl
test zF, FLAG_H
jz %%cpdr_hzero2
dec dh
%%cpdr_hzero2:
mov dl, dh
shl dl, 4
and edx, FLAG_5 | (FLAG_3 << 8)
or dl, dh
mov [z80_flag35], dl
%endif
xor dh, dh
DO_CYCLES
NEXT
%endmacro
; Perform arithmetic on the A register
; ART_R method, src8
%macro ART_R 2
%ifidn %1, ADD
DO_ADD z%2
%elifidn %1, ADC
DO_ADC z%2
%elifidn %1, SUB
DO_SUB z%2
%elifidn %1, SBC
DO_SBC z%2
%endif
DO_CYCLES
NEXT
%endmacro
; Perform arithmetic on the A register (using an immediate)
; ART_N method
%macro ART_N 1
GETBYTE
%ifidn %1, ADD
DO_ADD dl
%elifidn %1, ADC
DO_ADC dl
%elifidn %1, SUB
DO_SUB dl
%elifidn %1, SBC
DO_SBC dl
%endif
DO_CYCLES
NEXT
%endmacro
; Perform arithmetic on the A register, using (XY)
; ART_mXY method, src16
%macro ART_mXY 2
GETDISP
add di, z%2
MEMREAD
%ifidn %1, ADD
DO_ADD dl
%elifidn %1, ADC
DO_ADC dl
%elifidn %1, SUB
DO_SUB dl
%elifidn %1, SBC
DO_SBC dl
%endif
DO_CYCLES
NEXT
%endmacro
; Perform arithmetic on the A register using (RR)
; ART_mRR method, src16
%macro ART_mRR 2
mov edi, ez%2
MEMREAD
%ifidn %1, ADD
DO_ADD dl
%elifidn %1, ADC
DO_ADC dl
%elifidn %1, SUB
DO_SUB dl
%elifidn %1, SBC
DO_SBC dl
%endif
DO_CYCLES
NEXT
%endmacro
; Perform logic on the A register
; LOG_R method, src8
%macro LOG_R 2
%ifidn %1, AND
DO_AND z%2
%elifidn %1, OR
DO_OR z%2
%elifidn %1, XOR
DO_XOR z%2
%endif
DO_CYCLES
NEXT
%endmacro
; Perform logic on the A register (using an immediate)
; LOG_N method
%macro LOG_N 1
GETBYTE
%ifidn %1, AND
DO_AND dl
%elifidn %1, OR
DO_OR dl
%elifidn %1, XOR
DO_XOR dl
%endif
DO_CYCLES
NEXT
%endmacro
; Perform logic on the A register, using (RR)
; LOG_mRR method, src16
%macro LOG_mRR 2
mov edi, ez%2
MEMREAD
%ifidn %1, AND
DO_AND dl
%elifidn %1, OR
DO_OR dl
%elifidn %1, XOR
DO_XOR dl
%endif
DO_CYCLES
NEXT
%endmacro
; Perform logic on the A register, using (XY+dd)
; LOG_mXY method, src16
%macro LOG_mXY 2
GETDISP
add di, z%2
MEMREAD
%ifidn %1, AND
DO_AND dl
%elifidn %1, OR
DO_OR dl
%elifidn %1, XOR
DO_XOR dl
%endif
DO_CYCLES
NEXT
%endmacro
; Compare against the A register
; CP_R src8
%macro CP_R 1
DO_CP z%1
DO_CYCLES
NEXT
%endmacro
; Compare against the A register, using an immediate
; CP_N
%macro CP_N 0
GETBYTE
DO_CP dl
DO_CYCLES
NEXT
%endmacro
; Compare against the A register, using (RR)
; CP_mRR src16
%macro CP_mRR 1
mov edi, ez%1
MEMREAD
DO_CP dl
DO_CYCLES
NEXT
%endmacro
; Compare against the A register, using (XY+dd)
; CP_mXY src16
%macro CP_mXY 1
GETDISP
add di, z%1
MEMREAD
DO_CP dl
DO_CYCLES
NEXT
%endmacro
; Inc/dec a register
; DECINC_R method, reg8
%macro DECINC_R 2
%ifidn %1, INC
DO_INC z%2
%elifidn %1, DEC
DO_DEC z%2
%endif
DO_CYCLES
NEXT
%endmacro
; Inc/dec (RR)
; DECINC_mRR method
%macro DECINC_mRR 2
mov edi, ez%2
MEMREAD
%ifidn %1, INC
DO_INC dl
%elifidn %1, DEC
DO_DEC dl
%endif
MEMWRITE
DO_CYCLES
NEXT
%endmacro
; Inc/dec (XY+dd)
; DECINC_mXY method
%macro DECINC_mXY 2
GETDISP
add di, z%2
MEMREAD
%ifidn %1, INC
DO_INC dl
%elifidn %1, DEC
DO_DEC dl
%endif
MEMWRITE
DO_CYCLES
NEXT
%endmacro
; Add two 16-bit registers
; ADD_RR_RR dest16, src16
%macro ADD_RR_RR 2
DO_ADD16 z%1, z%2
DO_CYCLES
NEXT
%endmacro
; Add two 16-bit registers, with carry
; ADC_RR_RR dest16, src16
%macro ADC_RR_RR 2
DO_ADC16 z%1, z%2
DO_CYCLES
NEXT
%endmacro
; Subtract two 16-bit registers, with carry
; SBC_RR_RR dest16, src16
%macro SBC_RR_RR 2
DO_SBC16 z%1, z%2
DO_CYCLES
NEXT
%endmacro
; Inc/dec a 16-bit register
; DECINC_RR method, reg16
%macro DECINC_RR 2
%ifidn %1, INC
inc z%2
%elifidn %1, DEC
dec z%2
%endif
DO_CYCLES
NEXT
%endmacro
; Rotate a register
; ROT_R method, reg8
%macro ROT_R 2
DO_ROT %1, z%2
DO_CYCLES
NEXT
%endmacro
; Rotate (RR)
; ROT_mRR method, src16
%macro ROT_mRR 2
mov edi, ez%2
MEMREAD
DO_ROT %1, dl
MEMWRITE
DO_CYCLES
NEXT
%endmacro
; Rotate (XY+dd)
; ROT_mXY method
%macro ROT_mXY 1
MEMREAD
DO_ROT %1, dl
MEMWRITE
DO_CYCLES
NEXT
%endmacro
; Rotate (XY+dd), and store into a register
; ROT_mXY_R method, dest8
%macro ROT_mXY_R 2
MEMREAD
DO_ROT %1, dl
mov z%2, dl
MEMWRITE
DO_CYCLES
NEXT
%endmacro
; Shift a register
; SHF_R method, reg8
%macro SHF_R 2
DO_SHF %1, z%2
DO_CYCLES
NEXT
%endmacro
; Shift (RR)
; SHF_mRR method, src16
%macro SHF_mRR 2
mov edi, ez%2
MEMREAD
DO_SHF %1, dl
MEMWRITE
DO_CYCLES
NEXT
%endmacro
; Shift (XY+dd)
; SHF_mXY method
%macro SHF_mXY 1
MEMREAD
DO_SHF %1, dl
MEMWRITE
DO_CYCLES
NEXT
%endmacro
; Shift (XY+dd), and store into a register
; SHF_mXY_R method, dest8
%macro SHF_mXY_R 2
MEMREAD
DO_SHF %1, dl
mov z%2, dl
MEMWRITE
DO_CYCLES
NEXT
%endmacro
; Rotate A/(HL) left, via nibbles
; RLD
%macro RLD 0
mov edi, ezHL
MEMREAD
mov dh, zA
and zF, FLAG_C
shl dh, 4
rol dx, 4
and zA, 0f0h
or zA, dh
mov dh, zF
lahf
and zF, FLAG_S|FLAG_Z|FLAG_P
or zF, dh
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], zA
%endif
MEMWRITE
DO_CYCLES
NEXT
%endmacro
; Rotate A/(HL) right, via nibbles
; RRD
%macro RRD 0
mov edi, ezHL
MEMREAD
mov dh, zA
and zF, FLAG_C
ror dx, 4
shr dh, 4
and zA, 0f0h
or zA, dh
mov dh, zF
lahf
and zF, FLAG_S|FLAG_Z|FLAG_P
or zF, dh
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], zA
%endif
MEMWRITE
DO_CYCLES
NEXT
%endmacro
; Bit-test a register
; BIT_R src8, bit
%macro BIT_R_b 2
DO_BIT z%1, %2
DO_CYCLES
NEXT
%endmacro
; Bit-test (RR)
; BIT_mRR_b src16, bit
%macro BIT_mRR_b 2
and zF, FLAG_C
mov edi, ez%1
MEMREAD
test dl, (1 << %2)
; bit 3 and 5 are always cleared
; (actually they are bizarrely set, but
; there's no point emulating that, it's just
; plain silly...)
jz %%bit_is_clear
%ifidn %2, 7
or zF, FLAG_H|FLAG_S ; set sign bit, if testing bit 7
%else
or zF, FLAG_H ; set half-carry, and parity
%endif
jmp %%finish
%%bit_is_clear:
or zF, FLAG_H|FLAG_Z|FLAG_P ; set half-carry, parity, and zero
%%finish:
DO_CYCLES
NEXT
%endmacro
; Bit-test (XY+dd)
; BIT_mXY_b bit
%macro BIT_mXY_b 1
%ifdef EMULATE_BITS_3_5
mov edx, edi
mov [z80_flag35], dh
%endif
MEMREAD
and zF, FLAG_C
test dl, (1 << %1)
jz %%bit_is_clear
%ifidn %1, 7
or zF, FLAG_H|FLAG_S ; set sign bit, if testing bit 7
%else
or zF, FLAG_H ; set half-carry, and parity
%endif
jmp %%finish
%%bit_is_clear:
or zF, FLAG_H|FLAG_Z|FLAG_P ; set half-carry, parity, and zero
%%finish:
DO_CYCLES
NEXT
%endmacro
; Bit-clear a register
; RES_R_b src8, bit
%macro RES_R_b 2
DO_RES z%1, %2
DO_CYCLES
NEXT
%endmacro
; Bit-clear (RR)
; RES_mRR_b src16, bit
%macro RES_mRR_b 2
mov edi, ez%1
MEMREAD
DO_RES dl, %2
MEMWRITE
DO_CYCLES
NEXT
%endmacro
; Bit-clear (XY+dd)
; RES_mXY_b bit
%macro RES_mXY_b 1
MEMREAD
DO_RES dl, %1
MEMWRITE
DO_CYCLES
NEXT
%endmacro
; Bit-clear (XY+dd), with extra store
; RES_mXY_b_R bit, dest8
%macro RES_mXY_b_R 2
MEMREAD
DO_RES dl, %1
mov z%2, dl
MEMWRITE
DO_CYCLES
NEXT
%endmacro
; Bit-set a register
; SET_R_b src8, bit
%macro SET_R_b 2
DO_SET z%1, %2
DO_CYCLES
NEXT
%endmacro
; Bit-set (RR)
; SET_mRR_b src16, bit
%macro SET_mRR_b 2
mov edi, ez%1
MEMREAD
DO_SET dl, %2
MEMWRITE
DO_CYCLES
NEXT
%endmacro
; Bit-set (XY+dd)
; SET_mXY_b bit
%macro SET_mXY_b 1
MEMREAD
DO_SET dl, %1
MEMWRITE
DO_CYCLES
NEXT
%endmacro
; Bit-set (XY+dd), with extra store
; SET_mXY_b_R bit, dest8
%macro SET_mXY_b_R 2
MEMREAD
DO_SET dl, %1
mov z%2, dl
MEMWRITE
DO_CYCLES
NEXT
%endmacro
; Jump to an absolute address
; JP_NN
%macro JP_NN 0
GETWORD
mov ezPC, edi
DO_CYCLES
NEXT
%endmacro
; Jump to an absolute address, conditionally
; JP_cc_NN nz,cc
%macro JP_cc_NN 2
test zF, FLAG_%2
j%1 near %%dont_take_jump
GETWORD
mov ezPC, edi
DO_CYCLES
NEXT
ALIGN
%%dont_take_jump:
add zPC, 2 ; skip address
DO_CYCLES
NEXT
%endmacro
; Jump to an relative address
; JR_N
%macro JR_N 0
GETDISP
add zPC, di
DO_CYCLES
NEXT
%endmacro
; Jump to an relative address, conditionally
; JR_cc_N nz,cc
%macro JR_cc_N 2
test zF, FLAG_%2
j%1 near %%dont_take_jump
GETDISP
add zPC, di
DO_EXTRA_CYCLES
NEXT
ALIGN
%%dont_take_jump:
inc zPC ; skip over the displacement
DO_CYCLES
NEXT
%endmacro
; Jump to an absolute address (in a register)
; JP_RR addr16
%macro JP_RR 1
mov ezPC, ez%1
DO_CYCLES
NEXT
%endmacro
; Decrease B, if non-zero, jump to a relative address
; DJNZ_N
%macro DJNZ_N 0
dec zB
jz near %%dont_take_jump
GETDISP
add zPC, di
DO_EXTRA_CYCLES
NEXT
ALIGN
%%dont_take_jump:
inc zPC ; skip over the displacement
DO_CYCLES
NEXT
%endmacro
; Call an absolute address
; CALL_NN
%macro CALL_NN 0
GETWORD
mov edx, ezPC ; write the PC
dec zSP
push edi
xchg dl, dh
mov edi, ezSP
MEMWRITE
dec zSP
mov edx, ezPC
mov edi, ezSP
MEMWRITE
pop ezPC ; get the new PC
DO_CYCLES
NEXT
%endmacro
; Call an absolute address, conditionally
; CALL_cc_NN
%macro CALL_cc_NN 2
test zF, FLAG_%2
j%1 near %%dont_take_jump
GETWORD
mov edx, ezPC ; write the PC
push edi
dec zSP
xchg dl, dh
mov edi, ezSP
MEMWRITE
dec zSP
mov edx, ezPC
mov edi, ezSP
MEMWRITE
pop ezPC ; get the new PC
DO_CYCLES
NEXT
ALIGN
%%dont_take_jump:
add zPC, 2 ; skip address
DO_CYCLES
NEXT
%endmacro
; Pop the PC
; RET
%macro RET 0
mov edi, ezSP
MEMREAD
inc zSP
mov ezPC, edx
mov edi, ezSP
MEMREAD
xchg dl, dh
or ezPC, edx
inc zSP
xor dh, dh
DO_CYCLES
NEXT
%endmacro
; Pop the PC, conditionally
; RET_cc
%macro RET_cc 2
test zF, FLAG_%2
j%1 near %%dont_take_jump
mov edi, ezSP
MEMREAD
inc zSP
mov ezPC, edx
mov edi, ezSP
MEMREAD
xchg dl, dh
or ezPC, edx
inc zSP
xor dh, dh
DO_CYCLES
NEXT
ALIGN
%%dont_take_jump:
DO_CYCLES
NEXT
%endmacro
; Pop the PC, restore IFF1, signal the BUS
; RETI
%macro RETI 0
mov edi, ezSP
MEMREAD
mov ezPC, edx
inc zSP
mov edi, ezSP
MEMREAD
xchg dl, dh
or ezPC, edx
inc zSP
mov dl, [z80_IFF2]
mov [z80_IFF1], dl
call [z80_RetI] ; signal the user handler
DO_CYCLES
NEXT
%endmacro
; Pop the PC, restore IFF1
; RETN
%macro RETN 0
mov edi, ezSP
MEMREAD
mov ezPC, edx
inc zSP
mov edi, ezSP
MEMREAD
xchg dl, dh
or ezPC, edx
inc zSP
mov dl, [z80_IFF2]
mov [z80_IFF1], dl
DO_CYCLES
NEXT
%endmacro
; Call an absolute address
; RST addr8
%macro RST 1
dec zSP
mov edx, ezPC ; write the PC
xchg dl, dh
mov edi, ezSP
MEMWRITE
dec zSP
mov edx, ezPC
mov edi, ezSP
MEMWRITE
mov ezPC, %1 ; get the new PC
DO_CYCLES
NEXT
%endmacro
; Out R to R*256+N
; OUT_N_R src8
%macro OUT_N_R 1
GETBYTE
mov dh, z%1
mov edi, edx
mov dl, z%1
IOWRITE
DO_CYCLES
NEXT
%endmacro
; In from R*256+N, into R
; IN_R_N dest8
%macro IN_R_N 1
GETBYTE
mov dh, z%1
mov edi, edx
IOREAD
mov z%1, dl
DO_CYCLES
NEXT
%endmacro
; In from BC
; IN_R dest8
%macro IN_R 1
mov edi, ezBC
IOREAD
mov dh, zF
and dh, FLAG_C ; keep the old carry
mov z%1, dl
test dl, dl ; other flags come from the result
lahf
and zF, FLAG_S|FLAG_Z|FLAG_P
or zF, dh
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], dl
%endif
xor dh, dh
DO_CYCLES
NEXT
%endmacro
; In from BC, ignore result
; IN_F
%macro IN_F 0
mov edi, ezBC
IOREAD
mov dh, zF
and dh, FLAG_C ; keep the old carry
test dl, dl ; other flags come from the result
lahf
and zF, FLAG_S|FLAG_Z|FLAG_P
or zF, dh
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], dl
%endif
xor dh, dh
DO_CYCLES
NEXT
%endmacro
; Out to BC
; OUT_R src8
%macro OUT_R 1
mov edi, ezBC
mov dl, z%1
IOWRITE
DO_CYCLES
NEXT
%endmacro
; Out zero to BC
; OUT_0
%macro OUT_0 0
mov edi, ezBC
xor dl, dl
IOWRITE
DO_CYCLES
NEXT
%endmacro
; In from BC into (HL), increase HL, decrease B
%macro INI 0
; FIXME - Parity flag is not emulated
movzx edi, zC ; high byte clear? (documentation is fuzzy)
IOREAD ; read from the port
mov edi, ezHL
%ifdef EMULATE_WEIRD_STUFF
push edx ; preserve the value
%endif
MEMWRITE ; write to (HL)
%ifdef EMULATE_WEIRD_STUFF
pop edx
%endif
inc zHL ; increase HL
dec zB ; decrease B
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], zB
%endif
lahf
and zF, FLAG_S|FLAG_Z|FLAG_P
; This is a prime example of the weirdness of the Z80...
%ifdef EMULATE_WEIRD_STUFF
mov dh, zC
inc dh
add dh, dl
jnc %%no_carry
or zF, FLAG_H|FLAG_C
%%no_carry:
shr dl, 6
and edx, FLAG_N
or zF, dl
%endif
DO_CYCLES
NEXT
%endmacro
; In from BC into (HL), decrease HL, decrease B
%macro IND 0
; FIXME - Parity flag is not emulated
movzx edi, zC ; high byte clear? (documentation is fuzzy)
IOREAD ; read from the port
mov edi, ezHL
%ifdef EMULATE_WEIRD_STUFF
push edx ; preserve the value
%endif
MEMWRITE ; write to (HL)
%ifdef EMULATE_WEIRD_STUFF
pop edx
%endif
dec zHL ; increase HL
dec zB ; decrease B
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], zB
%endif
lahf
and zF, FLAG_S|FLAG_Z|FLAG_P
; This is a prime example of the weirdness of the Z80...
%ifdef EMULATE_WEIRD_STUFF
mov dh, zC
dec dh
add dh, dl
jnc %%no_carry
or zF, FLAG_H|FLAG_C
%%no_carry:
shr dl, 6
and edx, FLAG_N
or zF, dl
%endif
DO_CYCLES
NEXT
%endmacro
; In from BC into (HL), increase HL, decrease B, repeat
%macro INIR 0
; FIXME - Parity flag is not emulated
%%inir_loop:
movzx edi, zC ; high byte clear? (documentation is fuzzy)
IOREAD ; read from the port
mov edi, ezHL
%ifdef EMULATE_WEIRD_STUFF
push edx ; preserve the value
%endif
MEMWRITE ; write to (HL)
%ifdef EMULATE_WEIRD_STUFF
pop edx
%endif
inc zHL ; increase HL
dec zB ; decrease B
jz %%inir_zero
sub [z80_ICount], dword extra_cycles
ja near %%inir_loop ; repeat while cycles left and B>0
; out of cycles, but operation not finished
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], zB
%endif
mov zF, zB
and zF, FLAG_S
; This is a prime example of the weirdness of the Z80...
%ifdef EMULATE_WEIRD_STUFF
mov dh, zC
inc dh
add dh, dl
jnc %%no_carry
or zF, FLAG_H|FLAG_C
%%no_carry:
shr dl, 6
and edx, FLAG_N
or zF, dl
%endif
sub zPC, 2 ; rewind to instruction start
EXIT
; B=0
%%inir_zero:
mov zF, FLAG_Z|FLAG_P
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], zF
%endif
; This is a prime example of the weirdness of the Z80...
%ifdef EMULATE_WEIRD_STUFF
mov dh, zC
inc dh
add dh, dl
jnc %%no_carry2
or zF, FLAG_H|FLAG_C
%%no_carry2:
shr dl, 6
and edx, FLAG_N
or zF, dl
%endif
DO_CYCLES
NEXT
%endmacro
; In from BC into (HL), decrease HL, decrease B, repeat
%macro INDR 0
; FIXME - Parity flag is not emulated
%%indr_loop:
movzx edi, zC ; high byte clear? (documentation is fuzzy)
IOREAD ; read from the port
mov edi, ezHL
%ifdef EMULATE_WEIRD_STUFF
push edx ; preserve the value
%endif
MEMWRITE ; write to (HL)
%ifdef EMULATE_WEIRD_STUFF
pop edx
%endif
dec zHL ; decrease HL
dec zB ; decrease B
jz %%indr_zero
sub [z80_ICount], dword extra_cycles
ja near %%indr_loop ; repeat while cycles left and B>0
; out of cycles, but operation not finished
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], zB
%endif
mov zF, zB
and zF, FLAG_S
; This is a prime example of the weirdness of the Z80...
%ifdef EMULATE_WEIRD_STUFF
mov dh, zC
inc dh
add dh, dl
jnc %%no_carry
or zF, FLAG_H|FLAG_C
%%no_carry:
shr dl, 6
and edx, FLAG_N
or zF, dl
%endif
sub zPC, 2 ; rewind to instruction start
EXIT
; B=0
%%indr_zero:
mov zF, FLAG_Z|FLAG_P
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], zF
%endif
; This is a prime example of the weirdness of the Z80...
%ifdef EMULATE_WEIRD_STUFF
mov dh, zC
inc dh
add dh, dl
jnc %%no_carry2
or zF, FLAG_H|FLAG_C
%%no_carry2:
shr dl, 6
and edx, FLAG_N
or zF, dl
%endif
DO_CYCLES
NEXT
%endmacro
; Out from (HL) into BC, increase HL, decrease B
%macro OUTI 0
; FIXME - Parity flag is not emulated
mov edi, ezHL
MEMREAD ; read from (HL)
movzx edi, zC ; high byte clear? (documentation is fuzzy)
%ifdef EMULATE_WEIRD_STUFF
push edx ; preserve the value
%endif
IOWRITE ; write to the port
%ifdef EMULATE_WEIRD_STUFF
pop edx
%endif
inc zHL ; increase HL
dec zB ; decrease B
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], zB
%endif
lahf
and zF, FLAG_S|FLAG_Z|FLAG_P
; This is a prime example of the weirdness of the Z80...
%ifdef EMULATE_WEIRD_STUFF
mov dh, zC
inc dh
add dh, dl
jnc %%no_carry
or zF, FLAG_H|FLAG_C
%%no_carry:
shr dl, 6
and edx, FLAG_N
or zF, dl
%endif
DO_CYCLES
NEXT
%endmacro
; Out from (HL) into BC, decrease HL, decrease B
%macro OUTD 0
; FIXME - Parity flag is not emulated
mov edi, ezHL
MEMREAD ; read from (HL)
movzx edi, zC ; high byte clear? (documentation is fuzzy)
%ifdef EMULATE_WEIRD_STUFF
push edx ; preserve the value
%endif
IOWRITE ; write to the port
%ifdef EMULATE_WEIRD_STUFF
pop edx
%endif
dec zHL ; decrease HL
dec zB ; decrease B
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], zB
%endif
lahf
and zF, FLAG_S|FLAG_Z|FLAG_P
; This is a prime example of the weirdness of the Z80...
%ifdef EMULATE_WEIRD_STUFF
mov dh, zC
inc dh
add dh, dl
jnc %%no_carry
or zF, FLAG_H|FLAG_C
%%no_carry:
shr dl, 6
and edx, FLAG_N
or zF, dl
%endif
DO_CYCLES
NEXT
%endmacro
; Out from (HL) into BC, increase HL, decrease B, repeat
%macro OTIR 0
%%otir_loop:
mov edi, ezHL
MEMREAD
movzx edi, zC ; high byte clear? (documentation is fuzzy)
%ifdef EMULATE_WEIRD_STUFF
push edx ; preserve the value
%endif
IOWRITE
%ifdef EMULATE_WEIRD_STUFF
pop edx
%endif
inc zHL
dec zB
jz %%otir_zero
%ifdef EMULATE_R_REGISTER
inc zR
%endif
sub [z80_ICount], dword extra_cycles
ja near %%otir_loop
; out of cycles, but not finished
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], zB
%endif
mov zF, zB
and zF, FLAG_S
%ifdef EMULATE_WEIRD_STUFF
mov dh, zC
inc dh
add dh, dl
jnc %%otir_nocarry
or zF, FLAG_H|FLAG_C
%%otir_nocarry:
shr dl, 6
and edx, FLAG_N
or zF, dl
%endif
sub zPC, 2 ; rewind to instruction start
EXIT
%%otir_zero:
mov zF, FLAG_Z|FLAG_P
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], zF
%endif
%ifdef EMULATE_WEIRD_STUFF
mov dh, zC
inc dh
add dh, dl
jnc %%otir_nocarry2
or zF, FLAG_H|FLAG_C
%%otir_nocarry2:
shr dl, 6
and edx, FLAG_N
or zF, dl
%endif
DO_CYCLES
NEXT
%endmacro
; Out from (HL) into BC, decrease HL, decrease B, repeat
%macro OTDR 0
%%otdr_loop:
mov edi, ezHL
MEMREAD
movzx edi, zC ; high byte clear? (documentation is fuzzy)
%ifdef EMULATE_WEIRD_STUFF
push edx ; preserve the value
%endif
IOWRITE
%ifdef EMULATE_WEIRD_STUFF
pop edx
%endif
dec zHL
dec zB
jz %%otdr_zero
%ifdef EMULATE_R_REGISTER
inc zR
%endif
sub [z80_ICount], dword extra_cycles
ja near %%otdr_loop
; out of cycles, but not finished
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], zB
%endif
mov zF, zB
and zF, FLAG_S
%ifdef EMULATE_WEIRD_STUFF
mov dh, zC
inc dh
add dh, dl
jnc %%otdr_nocarry
or zF, FLAG_H|FLAG_C
%%otdr_nocarry:
shr dl, 6
and edx, FLAG_N
or zF, dl
%endif
sub zPC, 2 ; rewind to instruction start
EXIT
%%otdr_zero:
mov zF, FLAG_Z|FLAG_P
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], zF
%endif
%ifdef EMULATE_WEIRD_STUFF
mov dh, zC
inc dh
add dh, dl
jnc %%otdr_nocarry2
or zF, FLAG_H|FLAG_C
%%otdr_nocarry2:
shr dl, 6
and edx, FLAG_N
or zF, dl
%endif
DO_CYCLES
NEXT
%endmacro
; BCD adjust
%macro DAA 0
test zF, FLAG_H
jnz %%daa_h_set
and eax, 03ffh
mov ax, [DAA_Table + eax*2]
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], zF
%endif
DO_CYCLES
NEXT
%%daa_h_set:
and eax, 03ffh
mov ax, [DAA_Table + eax*2 + 4*512]
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], zF
%endif
DO_CYCLES
NEXT
%endmacro
; Complement A
%macro CPL 0
not zA
or zF, FLAG_H|FLAG_N
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], zA
%endif
DO_CYCLES
NEXT
%endmacro
; Negate A
%macro NEG 0
neg zA
lahf
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], zA
%endif
jo %%neg_overflow
and zF, ~FLAG_P
DO_CYCLES
NEXT
%%neg_overflow:
or zF, FLAG_P
DO_CYCLES
NEXT
%endmacro
; Set carry flag
%macro SCF 0
and zF, FLAG_S|FLAG_Z|FLAG_P
or zF, FLAG_C
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], zA
%endif
DO_CYCLES
NEXT
%endmacro
; Complement carry flag
%macro CCF 0
test zF, FLAG_C
jz %%set_carry
and zF, FLAG_S|FLAG_Z|FLAG_P
or zF, FLAG_H
%ifdef EMULATE_BITS_3_5
mov [z80_flag35], zA
%endif
DO_CYCLES
NEXT
%%set_carry:
SCF
%endmacro
; No operation
%macro NOP 0
DO_CYCLES
NEXT
%endmacro
; Halt the processor
%macro HALT 0
and [z80_ICount], dword 3
sub [z80_ICount], dword 4
mov [z80_halted], byte 1
EXIT
%endmacro
; Enable interrupts
%macro EI 0
mov dl, FLAG_P ; set the P/V bit, for use in "LD I,A" etc
mov [z80_IFF1], dl
mov [z80_IFF2], dl
; force the next instruction to be executed, regardless of ICount
; then force an IRQ check after it.
mov [z80_afterEI], byte 1
push eax
mov eax, [z80_ICount] ; set ICount to zero, so it will terminate
mov [z80_TempICount], eax ; after the next instruction.
mov [z80_ICount], dword 1 ; we can then pick it up again and carry on.
pop eax
NEXT
%endmacro
; Disable interrupts
%macro DI 0
xor edx, edx
mov [z80_IFF1], dl
mov [z80_IFF2], dl
DO_CYCLES
NEXT
%endmacro
; Set interrupt mode
%macro IM 1
mov [z80_IM], byte %1
DO_CYCLES
NEXT
%endmacro
;----------------------------------------------------------------------------;
; Bring in the opcodes...
%include 'raze.inc'
;----------------------------------------------------------------------------;
;----------------------------------------------------------------------------;
; Support functions:
DEF op, cb, 0, 0
%ifdef EMULATE_R_REGISTER
inc zR
%endif
GETBYTE
jmp [CBTable+edx*4]
DEF op, ed, 0, 0
%ifdef EMULATE_R_REGISTER
inc zR
%endif
GETBYTE
jmp [EDTable+edx*4]
DEF op, dd, 0, 0
%ifdef EMULATE_R_REGISTER
inc zR
%endif
GETBYTE
jmp [DDTable+edx*4]
DEF op, fd, 0, 0
%ifdef EMULATE_R_REGISTER
inc zR
%endif
GETBYTE
jmp [FDTable+edx*4]
DEF dd, cb, 0, 0
%ifdef EMULATE_R_REGISTER
inc zR
%endif
GETDISP
add di, zIX
push edi
GETBYTE
pop edi
jmp [DDCBTable+edx*4]
DEF fd, cb, 0, 0
%ifdef EMULATE_R_REGISTER
inc zR
%endif
GETDISP
add di, zIY
push edi
GETBYTE
pop edi
jmp [DDCBTable+edx*4]
DEF ed, xx, 8, 0
%ifdef EMULATE_R_REGISTER
inc zR
%endif
DO_CYCLES
NEXT
DEF dd, xx, 4, 0
dec zPC
DO_CYCLES
NEXT
DEF fd, xx, 0, 0
dec zPC
DO_CYCLES
NEXT
; called when out-of-cycles
z80_finish:
cmp [z80_afterEI], byte 1 ; test for the post-EI behaviour
jne near really_finish
push eax
mov eax, [z80_TempICount]
mov [z80_ICount], eax
mov [z80_afterEI], byte 0
pop eax
CHECK_IRQ
sub dword [z80_ICount], 4 ; subtract EI's cycles
jbe near z80_finish
NEXT
really_finish:
; merge bits 3 and 5 of the flags into the regs
and zF, ~(FLAG_3|FLAG_5)
mov dl, [z80_flag35]
and dl, FLAG_3|FLAG_5
or zF, dl
mov [z80_AF], ezAF
mov [z80_HL], ezHL
mov [z80_BC], ezBC
mov [z80_PC], ezPC
mov [z80_R], zR
pop ebp
pop edi
pop esi
pop ebx
mov eax, [z80_Initial_ICount]
sub eax, [z80_ICount]
ret
z80_default_in:
z80_default_read:
mov eax, 0ffh
ret
z80_default_out:
z80_default_write:
z80_default_reti:
z80_default_fetch_callback:
ret
; called to look up a read handler
; address is on the stack
read_dispatcher:
mov eax, [esp+4]
mov edx, _read_handlers
rd_find:
add edx, 16
cmp [edx-16], eax
ja rd_find
cmp [edx-12], eax
jb rd_find
cmp [edx-8], dword 1
je rd_handler
add eax, [edx-4]
movzx eax, byte [eax]
ret
rd_handler:
jmp [edx-4] ; call the GCC function
; called to look up a write handler
; address+value are on the stack
write_dispatcher:
mov eax, [esp+4]
mov edx, _write_handlers
wd_find:
add edx, 16
cmp [edx-16], eax
ja wd_find
cmp [edx-12], eax
jb wd_find
cmp [edx-8], dword 1
je wd_handler
add eax, [edx-4]
mov ecx, [esp+8]
mov [eax], cl
ret
wd_handler:
jmp [edx-4] ; call the GCC function
; int z80_emulate(int cycles)
; Emulate for 'cycles' T-states,
; Returns the number of cycles actually emulated.
cglobal z80_emulate
z80_emulate:
mov eax, [esp+4]
push ebx
push esi
push edi
push ebp
add eax, [z80_Extra_Cycles]
mov [z80_ICount], eax
mov [z80_Initial_ICount], eax
xor edx, edx
xor edi, edi
mov [z80_Extra_Cycles], edx
mov [z80_afterEI], dl
mov ezAF, [z80_AF]
mov ezHL, [z80_HL]
mov ezBC, [z80_BC]
mov ezPC, [z80_PC]
mov zR, [z80_R]
mov [z80_flag35], zF ; take out bits 3/5
cmp [z80_halted], byte 0
je not_halted
and [z80_ICount], dword 3 ; If we're halted, just skip it all.
sub [z80_ICount], dword 4
EXIT
not_halted:
NEXT
; void z80_reset(void)
; Resets the Z80.
cglobal z80_reset
z80_reset:
push edi
xor eax, eax ; just zero it all
mov edi, context_start
mov ecx, (registers_end - context_start)
rep stosb
pop edi
mov [z80_IX], word 0ffffh
mov [z80_IY], word 0ffffh
mov [z80_AF], word 04000h
ret
; void z80_raise_IRQ(UBYTE vector)
; Causes an interrupt with the given vector.
; In IM 0, the vector has to be an RST opcode.
; If interrupts are disabled, the interrupt will still happen as long as
; the IRQ line stays raised.
cglobal z80_raise_IRQ
z80_raise_IRQ:
mov [z80_IRQLine], byte 1
mov eax, [esp+4]
mov [z80_IRQVector], al
xor edx, edx
push ebx
push esi
push edi
push ebp
CALLGCC_END ; grab our Z80 regs
CHECK_IRQ
CALLGCC_START
pop ebp
pop edi
pop esi
pop ebx
ret
; void z80_lower_IRQ(void)
; Lowers the IRQ line.
cglobal z80_lower_IRQ
z80_lower_IRQ:
mov [z80_IRQLine], byte 0
ret
; void z80_cause_NMI(void)
; Causes a non-maskable interrupt.
; This will always be accepted.
; There is no raise/lower functions, as the NMI is edge-triggered.
cglobal z80_cause_NMI
z80_cause_NMI:
xor edx, edx
push ebx
push esi
push edi
push ebp
CALLGCC_END ; grab our Z80 regs
; disable interrupts
mov [z80_IFF1], byte 0
; take up 11 T-states
add [z80_Extra_Cycles], dword 11
%ifdef EMULATE_R_REGISTER
inc zR
%endif
mov [z80_halted], byte 0 ; Un-HALT us.
mov edx, ezPC ; write the PC
dec zSP
xchg dl, dh
mov edi, ezSP
MEMWRITE
dec zSP
mov edx, ezPC
mov edi, ezSP
MEMWRITE
mov ezPC, 66h ; set the new PC
CALLGCC_START
pop ebp
pop edi
pop esi
pop ebx
ret
; int z80_get_context_size(void)
; Returns the size of the context, in bytes
cglobal z80_get_context_size
z80_get_context_size:
mov eax, (context_end - context_start) + 4 ; +4 for a safety buffer
ret
; void z80_set_context(void *context)
; Copy the given context to the current Z80.
cglobal z80_set_context
z80_set_context:
push esi
push edi
mov ecx, (context_end - context_start) / 4
mov esi, [esp+12]
mov edi, context_start
rep movsd
pop edi
pop esi
ret
; void z80_get_context(void *context)
; Copy the current Z80 to the given context.
cglobal z80_get_context
z80_get_context:
push esi
push edi
mov ecx, (context_end - context_start) / 4
mov edi, [esp+12]
mov esi, context_start
rep movsd
pop edi
pop esi
ret
; int z80_get_cycles_elapsed(void)
; Returns the number of cycles emulated since z80_emulate was called.
cglobal z80_get_cycles_elapsed
z80_get_cycles_elapsed:
mov eax, [z80_Initial_ICount]
sub eax, [z80_ICount]
cmp [z80_afterEI], byte 0
je z80_gcd_fin
sub eax, [z80_TempICount]
z80_gcd_fin:
ret
; void z80_stop_emulating(void)
; Stops the emulation dead. (waits for the current instruction to finish
; first though).
; The return value from z80_execute will obviously be lower than expected.
cglobal z80_stop_emulating
z80_stop_emulating:
mov eax, [z80_ICount]
sub [z80_Initial_ICount], eax
cmp [z80_afterEI], byte 0
je z80_se_fin
mov ecx, [z80_TempICount]
sub [z80_Initial_ICount], ecx
z80_se_fin:
mov [z80_ICount], dword 0
mov [z80_TempICount], dword 0
ret
; void z80_skip_idle(void)
; Stops the emulation dead. (waits for the current instruction to finish
; first though).
; The return value from z80_execute will appear as though it had executed
; all the instructions like normal.
cglobal z80_skip_idle
z80_skip_idle:
mov [z80_ICount], dword 0
mov [z80_TempICount], dword 0
ret
; void z80_do_wait_states(int n)
; Halts the CPU temporarily, to execute 'n' memory wait states.
cglobal z80_do_wait_states
z80_do_wait_states:
add [z80_Initial_ICount], eax
ret
; UWORD z80_get_reg(z80_register reg)
; Return the value of the specified register.
cglobal z80_get_reg
z80_get_reg:
mov ecx, [esp+4]
cmp ecx, Z80_REG_HL2
mov eax, [context_start + ecx*4]
jbe getreg_simple
cmp ecx, Z80_REG_IFF1
mov al, [z80_IFF1]
je getreg_boolean
cmp ecx, Z80_REG_IFF2
mov al, [z80_IFF2]
je getreg_boolean
cmp ecx, Z80_REG_IRQLine
mov al, [z80_IRQLine]
je getreg_boolean
cmp ecx, Z80_REG_Halted
mov al, [z80_halted]
je getreg_boolean
cmp ecx, Z80_REG_IM
movzx eax, byte [z80_IM]
je getreg_finish
cmp ecx, Z80_REG_IRQVector
movzx eax, byte [z80_IRQVector]
je getreg_finish
; construct IR
mov eax, [z80_R]
and eax, 7fh
mov edx, [z80_R2]
and edx, 80h
or eax, edx
mov ah, byte [z80_I]
ret
getreg_simple:
cmp ecx, Z80_REG_AF
je getreg_swap
cmp ecx, Z80_REG_AF2
je getreg_swap
getreg_finish:
ret
getreg_swap:
xchg al, ah ; swap A and F
ret
getreg_boolean:
and eax, 0ffh
jz getreg_finish
mov al, 1
ret
; void z80_set_reg(z80_register reg, UWORD value)
; Set the specified register to a new value.
cglobal z80_set_reg
z80_set_reg:
mov ecx, [esp+4]
mov eax, [esp+8]
and eax, 0ffffh
cmp ecx, Z80_REG_HL2
jbe setreg_simple
cmp ecx, Z80_REG_IFF1
lea edx, [z80_IFF1]
jbe setreg_boolean
cmp ecx, Z80_REG_IFF2
lea edx, [z80_IFF2]
jbe setreg_boolean
cmp ecx, Z80_REG_IRQLine
lea edx, [z80_IRQLine]
je setreg_boolean
cmp ecx, Z80_REG_Halted
lea edx, [z80_halted]
je setreg_boolean
cmp ecx, Z80_REG_IM
lea edx, [z80_IM]
je setreg_value
cmp ecx, Z80_REG_IRQVector
lea edx, [z80_IRQVector]
je setreg_value
; deconstruct IR
mov [z80_I], ah
mov [z80_R2], eax
mov [z80_R], eax
ret
setreg_simple:
cmp ecx, Z80_REG_AF
je setreg_swap
cmp ecx, Z80_REG_AF2
je setreg_swap
setreg_finish:
mov [context_start + ecx*4], eax
ret
setreg_swap:
xchg al, ah ; swap A and F
mov [context_start + ecx*4], eax
ret
setreg_boolean:
test eax, eax
jz setreg_value
mov al, FLAG_P
setreg_value:
mov [edx], al
ret
; void z80_init_memmap(void)
; Reset the current memory map
cglobal z80_init_memmap
z80_init_memmap:
mov [z80_In], dword z80_default_in
mov [z80_Out], dword z80_default_out
mov [z80_RetI], dword z80_default_reti
mov [z80_Fetch_Callback], dword z80_default_fetch_callback
push edi ; clear the memory handlers
mov eax, -1
mov ecx, MAX_MEM_HANDLERS*4
mov edi, _read_handlers
rep stosd
mov ecx, MAX_MEM_HANDLERS*4
mov edi, _write_handlers
rep stosd
; reset the read table
mov edi, z80_Read
mov ecx, 100h
clear_read:
mov [edi], dword z80_default_read
add edi, 8
loop clear_read
; reset the write table
mov edi, z80_Write
mov ecx, 100h
clear_write:
mov [edi], dword z80_default_write
add edi, 8
loop clear_write
pop edi
ret
; void z80_end_memmap(void)
; Finishes the current memory map
cglobal z80_end_memmap
z80_end_memmap:
; put the entry at the end of the read table
mov edx, _read_handlers
er_find:
add edx, 16
cmp [edx-16], dword (-1)
jne er_find
sub edx, 16
; put it in there
mov [edx], dword 0
mov [edx+4], dword 0ffffh
mov [edx+8], dword 0
mov [edx+12], dword z80_default_read
; put the entry at the end of the write table
mov edx, _write_handlers
ew_find:
add edx, 16
cmp [edx-16], dword (-1)
jne ew_find
sub edx, 16
; put it in there
mov [edx], dword 0
mov [edx+4], dword 0ffffh
mov [edx+8], dword 0
mov [edx+12], dword z80_default_write
ret
; void z80_map_fetch(UWORD start, UWORD end, UBYTE *memory)
; Set the given area for op-code fetching
; start/end = the area it covers
; memory = the ROM/RAM to read from
cglobal z80_map_fetch
z80_map_fetch:
push ebx
mov eax, [esp+8]
mov ebx, [esp+12]
mov ecx, [esp+16]
and eax, 0ffffh
and ebx, 0ffffh
sub ecx, eax
mf_loop:
; if there's no area left inbetween, stop now.
mov edx, eax
shr edx, 8
cmp eax, ebx
ja mf_finish
mov [z80_Fetch+edx*4], ecx
add eax, 0100h
jmp mf_loop
mf_finish:
pop ebx
ret
; void z80_map_read(UWORD start, UWORD end, UBYTE *memory)
; Moves a Z80_MAP_MAPPED area to use a different region of memory
; start/end = the area it covers (must be page-aligned)
; memory = the ROM/RAM to read from
cglobal z80_map_read
z80_map_read:
push ebx
mov eax, [esp+8]
mov ebx, [esp+12]
mov ecx, [esp+16]
and eax, 0ffffh
and ebx, 0ffffh
sub ecx, eax
mr_loop:
; if there's no area left inbetween, stop now.
mov edx, eax
shr edx, 8
cmp eax, ebx
ja mr_finish
mov [z80_Read+edx*8], dword 0
mov [z80_Read+edx*8+4], ecx
add eax, 0100h
jmp mr_loop
mr_finish:
pop ebx
ret
; void z80_map_write(UWORD start, UWORD end, UBYTE *memory)
; Moves a Z80_MAP_MAPPED area to use a different region of memory
; start/end = the area it covers (must be page-aligned)
; memory = the ROM/RAM to read from
cglobal z80_map_write
z80_map_write:
push ebx
mov eax, [esp+8]
mov ebx, [esp+12]
mov ecx, [esp+16]
and eax, 0ffffh
and ebx, 0ffffh
sub ecx, eax
mw_loop:
; if there's no area left inbetween, stop now.
mov edx, eax
shr edx, 8
cmp eax, ebx
ja mw_finish
mov [z80_Write+edx*8], dword 0
mov [z80_Write+edx*8+4], ecx
add eax, 0100h
jmp mw_loop
mw_finish:
pop ebx
ret
; void z80_add_read(UWORD start, UWORD end, int method, void *data)
; Add a READ memory handler to the memory map
; start/end = the area it covers
; method = 0 for direct, 1 for handled
; data = RAM for direct, handler for handled
cglobal z80_add_read
z80_add_read:
push ebx
mov eax, [esp+8]
mov ebx, [esp+12]
mov ecx, [esp+20]
and eax, 0ffffh
and ebx, 0ffffh
; put the entry in the read table first
mov edx, _read_handlers
ar_find:
add edx, 16
cmp [edx-16], dword (-1)
jne ar_find
sub edx, 16
; put it in there
mov [edx], eax
mov [edx+4], ebx
mov eax, [esp+16]
mov [edx+8], eax
mov eax, ecx ; if direct, subtract the start from the memory area
push ebx
mov ebx, [esp+12]
and ebx, 0ffffh
cmp [esp+20], dword 1
je ar_dont_adjust
sub eax, ebx
ar_dont_adjust:
mov [edx+12], eax
mov eax, ebx
pop ebx
; process the start, so it's page aligned
test al, al
jz ar_start_done
; put the start handler to go to the dispatcher
mov edx, eax
shr edx, 8
mov [z80_Read+edx*8], dword read_dispatcher
xor al, al
add eax, 0100h
ar_start_done:
; process the end, so it's page aligned
cmp bl, 0ffh
je ar_end_done
; put the end handler to go to the dispatcher
mov edx, ebx
shr edx, 8
mov [z80_Read+edx*8], dword read_dispatcher
mov bl, 0ffh
sub ebx, 0100h
ar_end_done:
sub ecx, eax
ar_loop:
; if there's no area left inbetween, stop now.
mov edx, eax
shr edx, 8
cmp eax, ebx
jg ar_finish
cmp [esp+16], dword 0
je ar_put_direct
push ecx
mov ecx, [esp+24]
mov [z80_Read+edx*8], ecx
pop ecx
add eax, 0100h
jmp ar_loop
ar_put_direct:
mov [z80_Read+edx*8], dword 0
mov [z80_Read+edx*8+4], ecx
add eax, 0100h
jmp ar_loop
ar_finish:
pop ebx
ret
; void z80_add_write(UWORD start, UWORD end, int method, void *data)
; Add a WRITE memory handler to the memory map
; start/end = the area it covers
; method = 0 for direct, 1 for handled
; data = RAM for direct, handler for handled
cglobal z80_add_write
z80_add_write:
push ebx
mov eax, [esp+8]
mov ebx, [esp+12]
mov ecx, [esp+20]
and eax, 0ffffh
and ebx, 0ffffh
; put the entry in the read table first
mov edx, _write_handlers
aw_find:
add edx, 16
cmp [edx-16], dword (-1)
jne aw_find
sub edx, 16
; put it in there
mov [edx], eax
mov [edx+4], ebx
mov eax, [esp+16]
mov [edx+8], eax
mov eax, ecx ; if direct, subtract the start from the memory area
push ebx
mov ebx, [esp+12]
and ebx, 0ffffh
cmp [esp+20], dword 1
je aw_dont_adjust
sub eax, ebx
aw_dont_adjust:
mov [edx+12], eax
mov eax, ebx
pop ebx
; process the start, so it's page aligned
test al, al
jz aw_start_done
; put the start handler to go to the dispatcher
mov edx, eax
shr edx, 8
mov [z80_Write+edx*8], dword write_dispatcher
xor al, al
add eax, 0100h
aw_start_done:
; process the end, so it's page aligned
cmp bl, 0ffh
je aw_end_done
; put the end handler to go to the dispatcher
mov edx, ebx
shr edx, 8
mov [z80_Write+edx*8], dword write_dispatcher
mov bl, 0ffh
sub ebx, 0100h
aw_end_done:
sub ecx, eax
aw_loop:
; if there's no area left inbetween, stop now.
mov edx, eax
shr edx, 8
cmp eax, ebx
jg aw_finish
cmp [esp+16], dword 0
je aw_put_direct
push ecx
mov ecx, [esp+24]
mov [z80_Write+edx*8], ecx
pop ecx
add eax, 0100h
jmp aw_loop
aw_put_direct:
mov [z80_Write+edx*8], dword 0
mov [z80_Write+edx*8+4], ecx
add eax, 0100h
jmp aw_loop
aw_finish:
pop ebx
ret
; void z80_set_in(UBYTE (*handler)(UWORD port))
; Set the IN port handler to the given function
cglobal z80_set_in
z80_set_in:
mov eax, [esp+4]
mov [z80_In], eax
ret
; void z80_set_out(void (*handler)(UWORD port, UBYTE value))
; Set the OUT port handler to the given function
cglobal z80_set_out
z80_set_out:
mov eax, [esp+4]
mov [z80_Out], eax
ret
; void z80_set_reti(void (*handler)(void))
; Set the RETI handler to the given function
cglobal z80_set_reti
z80_set_reti:
mov eax, [esp+4]
mov [z80_RetI], eax
ret
; void z80_set_fetch_callback(void (*handler)(UWORD pc))
; Set the fetch callback to the given function
cglobal z80_set_fetch_callback
z80_set_fetch_callback:
mov eax, [esp+4]
mov [z80_Fetch_Callback], eax
ret
;----------------------------------------------------------------------------;
; the jump tables
OpTable:
dd op_00, op_01, op_02, op_03, op_04, op_05, op_06, op_07
dd op_08, op_09, op_0a, op_0b, op_0c, op_0d, op_0e, op_0f
dd op_10, op_11, op_12, op_13, op_14, op_15, op_16, op_17
dd op_18, op_19, op_1a, op_1b, op_1c, op_1d, op_1e, op_1f
dd op_20, op_21, op_22, op_23, op_24, op_25, op_26, op_27
dd op_28, op_29, op_2a, op_2b, op_2c, op_2d, op_2e, op_2f
dd op_30, op_31, op_32, op_33, op_34, op_35, op_36, op_37
dd op_38, op_39, op_3a, op_3b, op_3c, op_3d, op_3e, op_3f
dd op_40, op_41, op_42, op_43, op_44, op_45, op_46, op_47
dd op_48, op_49, op_4a, op_4b, op_4c, op_4d, op_4e, op_4f
dd op_50, op_51, op_52, op_53, op_54, op_55, op_56, op_57
dd op_58, op_59, op_5a, op_5b, op_5c, op_5d, op_5e, op_5f
dd op_60, op_61, op_62, op_63, op_64, op_65, op_66, op_67
dd op_68, op_69, op_6a, op_6b, op_6c, op_6d, op_6e, op_6f
dd op_70, op_71, op_72, op_73, op_74, op_75, op_76, op_77
dd op_78, op_79, op_7a, op_7b, op_7c, op_7d, op_7e, op_7f
dd op_80, op_81, op_82, op_83, op_84, op_85, op_86, op_87
dd op_88, op_89, op_8a, op_8b, op_8c, op_8d, op_8e, op_8f
dd op_90, op_91, op_92, op_93, op_94, op_95, op_96, op_97
dd op_98, op_99, op_9a, op_9b, op_9c, op_9d, op_9e, op_9f
dd op_a0, op_a1, op_a2, op_a3, op_a4, op_a5, op_a6, op_a7
dd op_a8, op_a9, op_aa, op_ab, op_ac, op_ad, op_ae, op_af
dd op_b0, op_b1, op_b2, op_b3, op_b4, op_b5, op_b6, op_b7
dd op_b8, op_b9, op_ba, op_bb, op_bc, op_bd, op_be, op_bf
dd op_c0, op_c1, op_c2, op_c3, op_c4, op_c5, op_c6, op_c7
dd op_c8, op_c9, op_ca, op_cb, op_cc, op_cd, op_ce, op_cf
dd op_d0, op_d1, op_d2, op_d3, op_d4, op_d5, op_d6, op_d7
dd op_d8, op_d9, op_da, op_db, op_dc, op_dd, op_de, op_df
dd op_e0, op_e1, op_e2, op_e3, op_e4, op_e5, op_e6, op_e7
dd op_e8, op_e9, op_ea, op_eb, op_ec, op_ed, op_ee, op_ef
dd op_f0, op_f1, op_f2, op_f3, op_f4, op_f5, op_f6, op_f7
dd op_f8, op_f9, op_fa, op_fb, op_fc, op_fd, op_fe, op_ff
CBTable:
dd cb_00, cb_01, cb_02, cb_03, cb_04, cb_05, cb_06, cb_07
dd cb_08, cb_09, cb_0a, cb_0b, cb_0c, cb_0d, cb_0e, cb_0f
dd cb_10, cb_11, cb_12, cb_13, cb_14, cb_15, cb_16, cb_17
dd cb_18, cb_19, cb_1a, cb_1b, cb_1c, cb_1d, cb_1e, cb_1f
dd cb_20, cb_21, cb_22, cb_23, cb_24, cb_25, cb_26, cb_27
dd cb_28, cb_29, cb_2a, cb_2b, cb_2c, cb_2d, cb_2e, cb_2f
dd cb_30, cb_31, cb_32, cb_33, cb_34, cb_35, cb_36, cb_37
dd cb_38, cb_39, cb_3a, cb_3b, cb_3c, cb_3d, cb_3e, cb_3f
dd cb_40, cb_41, cb_42, cb_43, cb_44, cb_45, cb_46, cb_47
dd cb_48, cb_49, cb_4a, cb_4b, cb_4c, cb_4d, cb_4e, cb_4f
dd cb_50, cb_51, cb_52, cb_53, cb_54, cb_55, cb_56, cb_57
dd cb_58, cb_59, cb_5a, cb_5b, cb_5c, cb_5d, cb_5e, cb_5f
dd cb_60, cb_61, cb_62, cb_63, cb_64, cb_65, cb_66, cb_67
dd cb_68, cb_69, cb_6a, cb_6b, cb_6c, cb_6d, cb_6e, cb_6f
dd cb_70, cb_71, cb_72, cb_73, cb_74, cb_75, cb_76, cb_77
dd cb_78, cb_79, cb_7a, cb_7b, cb_7c, cb_7d, cb_7e, cb_7f
dd cb_80, cb_81, cb_82, cb_83, cb_84, cb_85, cb_86, cb_87
dd cb_88, cb_89, cb_8a, cb_8b, cb_8c, cb_8d, cb_8e, cb_8f
dd cb_90, cb_91, cb_92, cb_93, cb_94, cb_95, cb_96, cb_97
dd cb_98, cb_99, cb_9a, cb_9b, cb_9c, cb_9d, cb_9e, cb_9f
dd cb_a0, cb_a1, cb_a2, cb_a3, cb_a4, cb_a5, cb_a6, cb_a7
dd cb_a8, cb_a9, cb_aa, cb_ab, cb_ac, cb_ad, cb_ae, cb_af
dd cb_b0, cb_b1, cb_b2, cb_b3, cb_b4, cb_b5, cb_b6, cb_b7
dd cb_b8, cb_b9, cb_ba, cb_bb, cb_bc, cb_bd, cb_be, cb_bf
dd cb_c0, cb_c1, cb_c2, cb_c3, cb_c4, cb_c5, cb_c6, cb_c7
dd cb_c8, cb_c9, cb_ca, cb_cb, cb_cc, cb_cd, cb_ce, cb_cf
dd cb_d0, cb_d1, cb_d2, cb_d3, cb_d4, cb_d5, cb_d6, cb_d7
dd cb_d8, cb_d9, cb_da, cb_db, cb_dc, cb_dd, cb_de, cb_df
dd cb_e0, cb_e1, cb_e2, cb_e3, cb_e4, cb_e5, cb_e6, cb_e7
dd cb_e8, cb_e9, cb_ea, cb_eb, cb_ec, cb_ed, cb_ee, cb_ef
dd cb_f0, cb_f1, cb_f2, cb_f3, cb_f4, cb_f5, cb_f6, cb_f7
dd cb_f8, cb_f9, cb_fa, cb_fb, cb_fc, cb_fd, cb_fe, cb_ff
EDTable:
dd ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx
dd ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx
dd ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx
dd ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx
dd ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx
dd ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx
dd ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx
dd ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx
dd ed_40, ed_41, ed_42, ed_43, ed_44, ed_45, ed_46, ed_47
dd ed_48, ed_49, ed_4a, ed_4b, ed_4c, ed_4d, ed_4e, ed_4f
dd ed_50, ed_51, ed_52, ed_53, ed_54, ed_55, ed_56, ed_57
dd ed_58, ed_59, ed_5a, ed_5b, ed_5c, ed_5d, ed_5e, ed_5f
dd ed_60, ed_61, ed_62, ed_63, ed_64, ed_65, ed_66, ed_67
dd ed_68, ed_69, ed_6a, ed_6b, ed_6c, ed_6d, ed_6e, ed_6f
dd ed_70, ed_71, ed_72, ed_73, ed_74, ed_75, ed_76, ed_xx
dd ed_78, ed_79, ed_7a, ed_7b, ed_7c, ed_7d, ed_7e, ed_xx
dd ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx
dd ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx
dd ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx
dd ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx
dd ed_a0, ed_a1, ed_a2, ed_a3, ed_xx, ed_xx, ed_xx, ed_xx
dd ed_a8, ed_a9, ed_aa, ed_ab, ed_xx, ed_xx, ed_xx, ed_xx
dd ed_b0, ed_b1, ed_b2, ed_b3, ed_xx, ed_xx, ed_xx, ed_xx
dd ed_b8, ed_b9, ed_ba, ed_bb, ed_xx, ed_xx, ed_xx, ed_xx
dd ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx
dd ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx
dd ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx
dd ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx
dd ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx
dd ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx
dd ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx
dd ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx, ed_xx
DDTable:
dd dd_xx, dd_xx, dd_xx, dd_xx, dd_xx, dd_xx, dd_xx, dd_xx
dd dd_xx, dd_09, dd_xx, dd_xx, dd_xx, dd_xx, dd_xx, dd_xx
dd dd_xx, dd_xx, dd_xx, dd_xx, dd_xx, dd_xx, dd_xx, dd_xx
dd dd_xx, dd_19, dd_xx, dd_xx, dd_xx, dd_xx, dd_xx, dd_xx
dd dd_xx, dd_21, dd_22, dd_23, dd_24, dd_25, dd_26, dd_xx
dd dd_xx, dd_29, dd_2a, dd_2b, dd_2c, dd_2d, dd_2e, dd_xx
dd dd_xx, dd_xx, dd_xx, dd_xx, dd_34, dd_35, dd_36, dd_xx
dd dd_xx, dd_39, dd_xx, dd_xx, dd_xx, dd_xx, dd_xx, dd_xx
dd dd_xx, dd_xx, dd_xx, dd_xx, dd_44, dd_45, dd_46, dd_xx
dd dd_xx, dd_xx, dd_xx, dd_xx, dd_4c, dd_4d, dd_4e, dd_xx
dd dd_xx, dd_xx, dd_xx, dd_xx, dd_54, dd_55, dd_56, dd_xx
dd dd_xx, dd_xx, dd_xx, dd_xx, dd_5c, dd_5d, dd_5e, dd_xx
dd dd_60, dd_61, dd_62, dd_63, dd_xx, dd_65, dd_66, dd_67
dd dd_68, dd_69, dd_6a, dd_6b, dd_6c, dd_xx, dd_6e, dd_6f
dd dd_70, dd_71, dd_72, dd_73, dd_74, dd_75, dd_xx, dd_77
dd dd_xx, dd_xx, dd_xx, dd_xx, dd_7c, dd_7d, dd_7e, dd_xx
dd dd_xx, dd_xx, dd_xx, dd_xx, dd_84, dd_85, dd_86, dd_xx
dd dd_xx, dd_xx, dd_xx, dd_xx, dd_8c, dd_8d, dd_8e, dd_xx
dd dd_xx, dd_xx, dd_xx, dd_xx, dd_94, dd_95, dd_96, dd_xx
dd dd_xx, dd_xx, dd_xx, dd_xx, dd_9c, dd_9d, dd_9e, dd_xx
dd dd_xx, dd_xx, dd_xx, dd_xx, dd_a4, dd_a5, dd_a6, dd_xx
dd dd_xx, dd_xx, dd_xx, dd_xx, dd_ac, dd_ad, dd_ae, dd_xx
dd dd_xx, dd_xx, dd_xx, dd_xx, dd_b4, dd_b5, dd_b6, dd_xx
dd dd_xx, dd_xx, dd_xx, dd_xx, dd_bc, dd_bd, dd_be, dd_xx
dd dd_xx, dd_xx, dd_xx, dd_xx, dd_xx, dd_xx, dd_xx, dd_xx
dd dd_xx, dd_xx, dd_xx, dd_cb, dd_xx, dd_xx, dd_xx, dd_xx
dd dd_xx, dd_xx, dd_xx, dd_xx, dd_xx, dd_xx, dd_xx, dd_xx
dd dd_xx, dd_xx, dd_xx, dd_xx, dd_xx, dd_xx, dd_xx, dd_xx
dd dd_xx, dd_e1, dd_xx, dd_e3, dd_xx, dd_e5, dd_xx, dd_xx
dd dd_xx, dd_e9, dd_xx, dd_xx, dd_xx, dd_xx, dd_xx, dd_xx
dd dd_xx, dd_xx, dd_xx, dd_xx, dd_xx, dd_xx, dd_xx, dd_xx
dd dd_xx, dd_f9, dd_xx, dd_xx, dd_xx, dd_xx, dd_xx, dd_xx
FDTable:
dd fd_xx, fd_xx, fd_xx, fd_xx, fd_xx, fd_xx, fd_xx, fd_xx
dd fd_xx, fd_09, fd_xx, fd_xx, fd_xx, fd_xx, fd_xx, fd_xx
dd fd_xx, fd_xx, fd_xx, fd_xx, fd_xx, fd_xx, fd_xx, fd_xx
dd fd_xx, fd_19, fd_xx, fd_xx, fd_xx, fd_xx, fd_xx, fd_xx
dd fd_xx, fd_21, fd_22, fd_23, fd_24, fd_25, fd_26, fd_xx
dd fd_xx, fd_29, fd_2a, fd_2b, fd_2c, fd_2d, fd_2e, fd_xx
dd fd_xx, fd_xx, fd_xx, fd_xx, fd_34, fd_35, fd_36, fd_xx
dd fd_xx, fd_39, fd_xx, fd_xx, fd_xx, fd_xx, fd_xx, fd_xx
dd fd_xx, fd_xx, fd_xx, fd_xx, fd_44, fd_45, fd_46, fd_xx
dd fd_xx, fd_xx, fd_xx, fd_xx, fd_4c, fd_4d, fd_4e, fd_xx
dd fd_xx, fd_xx, fd_xx, fd_xx, fd_54, fd_55, fd_56, fd_xx
dd fd_xx, fd_xx, fd_xx, fd_xx, fd_5c, fd_5d, fd_5e, fd_xx
dd fd_60, fd_61, fd_62, fd_63, fd_xx, fd_65, fd_66, fd_67
dd fd_68, fd_69, fd_6a, fd_6b, fd_6c, fd_xx, fd_6e, fd_6f
dd fd_70, fd_71, fd_72, fd_73, fd_74, fd_75, fd_xx, fd_77
dd fd_xx, fd_xx, fd_xx, fd_xx, fd_7c, fd_7d, fd_7e, fd_xx
dd fd_xx, fd_xx, fd_xx, fd_xx, fd_84, fd_85, fd_86, fd_xx
dd fd_xx, fd_xx, fd_xx, fd_xx, fd_8c, fd_8d, fd_8e, fd_xx
dd fd_xx, fd_xx, fd_xx, fd_xx, fd_94, fd_95, fd_96, fd_xx
dd fd_xx, fd_xx, fd_xx, fd_xx, fd_9c, fd_9d, fd_9e, fd_xx
dd fd_xx, fd_xx, fd_xx, fd_xx, fd_a4, fd_a5, fd_a6, fd_xx
dd fd_xx, fd_xx, fd_xx, fd_xx, fd_ac, fd_ad, fd_ae, fd_xx
dd fd_xx, fd_xx, fd_xx, fd_xx, fd_b4, fd_b5, fd_b6, fd_xx
dd fd_xx, fd_xx, fd_xx, fd_xx, fd_bc, fd_bd, fd_be, fd_xx
dd fd_xx, fd_xx, fd_xx, fd_xx, fd_xx, fd_xx, fd_xx, fd_xx
dd fd_xx, fd_xx, fd_xx, fd_cb, fd_xx, fd_xx, fd_xx, fd_xx
dd fd_xx, fd_xx, fd_xx, fd_xx, fd_xx, fd_xx, fd_xx, fd_xx
dd fd_xx, fd_xx, fd_xx, fd_xx, fd_xx, fd_xx, fd_xx, fd_xx
dd fd_xx, fd_e1, fd_xx, fd_e3, fd_xx, fd_e5, fd_xx, fd_xx
dd fd_xx, fd_e9, fd_xx, fd_xx, fd_xx, fd_xx, fd_xx, fd_xx
dd fd_xx, fd_xx, fd_xx, fd_xx, fd_xx, fd_xx, fd_xx, fd_xx
dd fd_xx, fd_f9, fd_xx, fd_xx, fd_xx, fd_xx, fd_xx, fd_xx
DDCBTable:
dd ddcb_00, ddcb_01, ddcb_02, ddcb_03, ddcb_04, ddcb_05, ddcb_06, ddcb_07
dd ddcb_08, ddcb_09, ddcb_0a, ddcb_0b, ddcb_0c, ddcb_0d, ddcb_0e, ddcb_0f
dd ddcb_10, ddcb_11, ddcb_12, ddcb_13, ddcb_14, ddcb_15, ddcb_16, ddcb_17
dd ddcb_18, ddcb_19, ddcb_1a, ddcb_1b, ddcb_1c, ddcb_1d, ddcb_1e, ddcb_1f
dd ddcb_20, ddcb_21, ddcb_22, ddcb_23, ddcb_24, ddcb_25, ddcb_26, ddcb_27
dd ddcb_28, ddcb_29, ddcb_2a, ddcb_2b, ddcb_2c, ddcb_2d, ddcb_2e, ddcb_2f
dd ddcb_30, ddcb_31, ddcb_32, ddcb_33, ddcb_34, ddcb_35, ddcb_36, ddcb_37
dd ddcb_38, ddcb_39, ddcb_3a, ddcb_3b, ddcb_3c, ddcb_3d, ddcb_3e, ddcb_3f
dd ddcb_40, ddcb_41, ddcb_42, ddcb_43, ddcb_44, ddcb_45, ddcb_46, ddcb_47
dd ddcb_48, ddcb_49, ddcb_4a, ddcb_4b, ddcb_4c, ddcb_4d, ddcb_4e, ddcb_4f
dd ddcb_50, ddcb_51, ddcb_52, ddcb_53, ddcb_54, ddcb_55, ddcb_56, ddcb_57
dd ddcb_58, ddcb_59, ddcb_5a, ddcb_5b, ddcb_5c, ddcb_5d, ddcb_5e, ddcb_5f
dd ddcb_60, ddcb_61, ddcb_62, ddcb_63, ddcb_64, ddcb_65, ddcb_66, ddcb_67
dd ddcb_68, ddcb_69, ddcb_6a, ddcb_6b, ddcb_6c, ddcb_6d, ddcb_6e, ddcb_6f
dd ddcb_70, ddcb_71, ddcb_72, ddcb_73, ddcb_74, ddcb_75, ddcb_76, ddcb_77
dd ddcb_78, ddcb_79, ddcb_7a, ddcb_7b, ddcb_7c, ddcb_7d, ddcb_7e, ddcb_7f
dd ddcb_80, ddcb_81, ddcb_82, ddcb_83, ddcb_84, ddcb_85, ddcb_86, ddcb_87
dd ddcb_88, ddcb_89, ddcb_8a, ddcb_8b, ddcb_8c, ddcb_8d, ddcb_8e, ddcb_8f
dd ddcb_90, ddcb_91, ddcb_92, ddcb_93, ddcb_94, ddcb_95, ddcb_96, ddcb_97
dd ddcb_98, ddcb_99, ddcb_9a, ddcb_9b, ddcb_9c, ddcb_9d, ddcb_9e, ddcb_9f
dd ddcb_a0, ddcb_a1, ddcb_a2, ddcb_a3, ddcb_a4, ddcb_a5, ddcb_a6, ddcb_a7
dd ddcb_a8, ddcb_a9, ddcb_aa, ddcb_ab, ddcb_ac, ddcb_ad, ddcb_ae, ddcb_af
dd ddcb_b0, ddcb_b1, ddcb_b2, ddcb_b3, ddcb_b4, ddcb_b5, ddcb_b6, ddcb_b7
dd ddcb_b8, ddcb_b9, ddcb_ba, ddcb_bb, ddcb_bc, ddcb_bd, ddcb_be, ddcb_bf
dd ddcb_c0, ddcb_c1, ddcb_c2, ddcb_c3, ddcb_c4, ddcb_c5, ddcb_c6, ddcb_c7
dd ddcb_c8, ddcb_c9, ddcb_ca, ddcb_cb, ddcb_cc, ddcb_cd, ddcb_ce, ddcb_cf
dd ddcb_d0, ddcb_d1, ddcb_d2, ddcb_d3, ddcb_d4, ddcb_d5, ddcb_d6, ddcb_d7
dd ddcb_d8, ddcb_d9, ddcb_da, ddcb_db, ddcb_dc, ddcb_dd, ddcb_de, ddcb_df
dd ddcb_e0, ddcb_e1, ddcb_e2, ddcb_e3, ddcb_e4, ddcb_e5, ddcb_e6, ddcb_e7
dd ddcb_e8, ddcb_e9, ddcb_ea, ddcb_eb, ddcb_ec, ddcb_ed, ddcb_ee, ddcb_ef
dd ddcb_f0, ddcb_f1, ddcb_f2, ddcb_f3, ddcb_f4, ddcb_f5, ddcb_f6, ddcb_f7
dd ddcb_f8, ddcb_f9, ddcb_fa, ddcb_fb, ddcb_fc, ddcb_fd, ddcb_fe, ddcb_ff
;----------------------------------------------------------------------------;
; flag tables ('borrowed' from MAZE, by Ishmair)
INC_Table:
DB 0,0,0,0,0,0,0,8,8,8,8,8,8,8,8,16,0,0,0,0
DB 0,0,0,8,8,8,8,8,8,8,8,48,32,32,32,32,32,32,32,40
DB 40,40,40,40,40,40,40,48,32,32,32,32,32,32,32,40,40,40,40,40
DB 40,40,40,16,0,0,0,0,0,0,0,8,8,8,8,8,8,8,8,16
DB 0,0,0,0,0,0,0,8,8,8,8,8,8,8,8,48,32,32,32,32
DB 32,32,32,40,40,40,40,40,40,40,40,48,32,32,32,32,32,32,32,40
DB 40,40,40,40,40,40,40,148,128,128,128,128,128,128,128,136,136,136,136,136
DB 136,136,136,144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136,176
DB 160,160,160,160,160,160,160,168,168,168,168,168,168,168,168,176,160,160,160,160
DB 160,160,160,168,168,168,168,168,168,168,168,144,128,128,128,128,128,128,128,136
DB 136,136,136,136,136,136,136,144,128,128,128,128,128,128,128,136,136,136,136,136
DB 136,136,136,176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168,176
DB 160,160,160,160,160,160,160,168,168,168,168,168,168,168,168,80
DEC_Table:
DB 186,66,2,2,2,2,2,2,2,10,10,10,10,10,10,10,26,2,2,2
DB 2,2,2,2,2,10,10,10,10,10,10,10,26,34,34,34,34,34,34,34
DB 34,42,42,42,42,42,42,42,58,34,34,34,34,34,34,34,34,42,42,42
DB 42,42,42,42,58,2,2,2,2,2,2,2,2,10,10,10,10,10,10,10
DB 26,2,2,2,2,2,2,2,2,10,10,10,10,10,10,10,26,34,34,34
DB 34,34,34,34,34,42,42,42,42,42,42,42,58,34,34,34,34,34,34,34
DB 34,42,42,42,42,42,42,42,62,130,130,130,130,130,130,130,130,138,138,138
DB 138,138,138,138,154,130,130,130,130,130,130,130,130,138,138,138,138,138,138,138
DB 154,162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186,162,162,162
DB 162,162,162,162,162,170,170,170,170,170,170,170,186,130,130,130,130,130,130,130
DB 130,138,138,138,138,138,138,138,154,130,130,130,130,130,130,130,130,138,138,138
DB 138,138,138,138,154,162,162,162,162,162,162,162,162,170,170,170,170,170,170,170
DB 186,162,162,162,162,162,162,162,162,170,170,170,170,170,170,170
; DAA table ('borrowed' from Z80Emul, by unknown)
DAA_Table:
DW 04400h, 00001h, 00002h, 00403h, 00004h, 00405h, 00406h, 00007h
DW 00808h, 00C09h, 01010h, 01411h, 01412h, 01013h, 01414h, 01015h
DW 00010h, 00411h, 00412h, 00013h, 00414h, 00015h, 00016h, 00417h
DW 00C18h, 00819h, 03020h, 03421h, 03422h, 03023h, 03424h, 03025h
DW 02020h, 02421h, 02422h, 02023h, 02424h, 02025h, 02026h, 02427h
DW 02C28h, 02829h, 03430h, 03031h, 03032h, 03433h, 03034h, 03435h
DW 02430h, 02031h, 02032h, 02433h, 02034h, 02435h, 02436h, 02037h
DW 02838h, 02C39h, 01040h, 01441h, 01442h, 01043h, 01444h, 01045h
DW 00040h, 00441h, 00442h, 00043h, 00444h, 00045h, 00046h, 00447h
DW 00C48h, 00849h, 01450h, 01051h, 01052h, 01453h, 01054h, 01455h
DW 00450h, 00051h, 00052h, 00453h, 00054h, 00455h, 00456h, 00057h
DW 00858h, 00C59h, 03460h, 03061h, 03062h, 03463h, 03064h, 03465h
DW 02460h, 02061h, 02062h, 02463h, 02064h, 02465h, 02466h, 02067h
DW 02868h, 02C69h, 03070h, 03471h, 03472h, 03073h, 03474h, 03075h
DW 02070h, 02471h, 02472h, 02073h, 02474h, 02075h, 02076h, 02477h
DW 02C78h, 02879h, 09080h, 09481h, 09482h, 09083h, 09484h, 09085h
DW 08080h, 08481h, 08482h, 08083h, 08484h, 08085h, 08086h, 08487h
DW 08C88h, 08889h, 09490h, 09091h, 09092h, 09493h, 09094h, 09495h
DW 08490h, 08091h, 08092h, 08493h, 08094h, 08495h, 08496h, 08097h
DW 08898h, 08C99h, 05500h, 01101h, 01102h, 01503h, 01104h, 01505h
DW 04500h, 00101h, 00102h, 00503h, 00104h, 00505h, 00506h, 00107h
DW 00908h, 00D09h, 01110h, 01511h, 01512h, 01113h, 01514h, 01115h
DW 00110h, 00511h, 00512h, 00113h, 00514h, 00115h, 00116h, 00517h
DW 00D18h, 00919h, 03120h, 03521h, 03522h, 03123h, 03524h, 03125h
DW 02120h, 02521h, 02522h, 02123h, 02524h, 02125h, 02126h, 02527h
DW 02D28h, 02929h, 03530h, 03131h, 03132h, 03533h, 03134h, 03535h
DW 02530h, 02131h, 02132h, 02533h, 02134h, 02535h, 02536h, 02137h
DW 02938h, 02D39h, 01140h, 01541h, 01542h, 01143h, 01544h, 01145h
DW 00140h, 00541h, 00542h, 00143h, 00544h, 00145h, 00146h, 00547h
DW 00D48h, 00949h, 01550h, 01151h, 01152h, 01553h, 01154h, 01555h
DW 00550h, 00151h, 00152h, 00553h, 00154h, 00555h, 00556h, 00157h
DW 00958h, 00D59h, 03560h, 03161h, 03162h, 03563h, 03164h, 03565h
DW 02560h, 02161h, 02162h, 02563h, 02164h, 02565h, 02566h, 02167h
DW 02968h, 02D69h, 03170h, 03571h, 03572h, 03173h, 03574h, 03175h
DW 02170h, 02571h, 02572h, 02173h, 02574h, 02175h, 02176h, 02577h
DW 02D78h, 02979h, 09180h, 09581h, 09582h, 09183h, 09584h, 09185h
DW 08180h, 08581h, 08582h, 08183h, 08584h, 08185h, 08186h, 08587h
DW 08D88h, 08989h, 09590h, 09191h, 09192h, 09593h, 09194h, 09595h
DW 08590h, 08191h, 08192h, 08593h, 08194h, 08595h, 08596h, 08197h
DW 08998h, 08D99h, 0B5A0h, 0B1A1h, 0B1A2h, 0B5A3h, 0B1A4h, 0B5A5h
DW 0A5A0h, 0A1A1h, 0A1A2h, 0A5A3h, 0A1A4h, 0A5A5h, 0A5A6h, 0A1A7h
DW 0A9A8h, 0ADA9h, 0B1B0h, 0B5B1h, 0B5B2h, 0B1B3h, 0B5B4h, 0B1B5h
DW 0A1B0h, 0A5B1h, 0A5B2h, 0A1B3h, 0A5B4h, 0A1B5h, 0A1B6h, 0A5B7h
DW 0ADB8h, 0A9B9h, 095C0h, 091C1h, 091C2h, 095C3h, 091C4h, 095C5h
DW 085C0h, 081C1h, 081C2h, 085C3h, 081C4h, 085C5h, 085C6h, 081C7h
DW 089C8h, 08DC9h, 091D0h, 095D1h, 095D2h, 091D3h, 095D4h, 091D5h
DW 081D0h, 085D1h, 085D2h, 081D3h, 085D4h, 081D5h, 081D6h, 085D7h
DW 08DD8h, 089D9h, 0B1E0h, 0B5E1h, 0B5E2h, 0B1E3h, 0B5E4h, 0B1E5h
DW 0A1E0h, 0A5E1h, 0A5E2h, 0A1E3h, 0A5E4h, 0A1E5h, 0A1E6h, 0A5E7h
DW 0ADE8h, 0A9E9h, 0B5F0h, 0B1F1h, 0B1F2h, 0B5F3h, 0B1F4h, 0B5F5h
DW 0A5F0h, 0A1F1h, 0A1F2h, 0A5F3h, 0A1F4h, 0A5F5h, 0A5F6h, 0A1F7h
DW 0A9F8h, 0ADF9h, 05500h, 01101h, 01102h, 01503h, 01104h, 01505h
DW 04500h, 00101h, 00102h, 00503h, 00104h, 00505h, 00506h, 00107h
DW 00908h, 00D09h, 01110h, 01511h, 01512h, 01113h, 01514h, 01115h
DW 00110h, 00511h, 00512h, 00113h, 00514h, 00115h, 00116h, 00517h
DW 00D18h, 00919h, 03120h, 03521h, 03522h, 03123h, 03524h, 03125h
DW 02120h, 02521h, 02522h, 02123h, 02524h, 02125h, 02126h, 02527h
DW 02D28h, 02929h, 03530h, 03131h, 03132h, 03533h, 03134h, 03535h
DW 02530h, 02131h, 02132h, 02533h, 02134h, 02535h, 02536h, 02137h
DW 02938h, 02D39h, 01140h, 01541h, 01542h, 01143h, 01544h, 01145h
DW 00140h, 00541h, 00542h, 00143h, 00544h, 00145h, 00146h, 00547h
DW 00D48h, 00949h, 01550h, 01151h, 01152h, 01553h, 01154h, 01555h
DW 00550h, 00151h, 00152h, 00553h, 00154h, 00555h, 00556h, 00157h
DW 00958h, 00D59h, 03560h, 03161h, 03162h, 03563h, 03164h, 03565h
DW 04600h, 00201h, 00202h, 00603h, 00204h, 00605h, 00606h, 00207h
DW 00A08h, 00E09h, 00204h, 00605h, 00606h, 00207h, 00A08h, 00E09h
DW 00210h, 00611h, 00612h, 00213h, 00614h, 00215h, 00216h, 00617h
DW 00E18h, 00A19h, 00614h, 00215h, 00216h, 00617h, 00E18h, 00A19h
DW 02220h, 02621h, 02622h, 02223h, 02624h, 02225h, 02226h, 02627h
DW 02E28h, 02A29h, 02624h, 02225h, 02226h, 02627h, 02E28h, 02A29h
DW 02630h, 02231h, 02232h, 02633h, 02234h, 02635h, 02636h, 02237h
DW 02A38h, 02E39h, 02234h, 02635h, 02636h, 02237h, 02A38h, 02E39h
DW 00240h, 00641h, 00642h, 00243h, 00644h, 00245h, 00246h, 00647h
DW 00E48h, 00A49h, 00644h, 00245h, 00246h, 00647h, 00E48h, 00A49h
DW 00650h, 00251h, 00252h, 00653h, 00254h, 00655h, 00656h, 00257h
DW 00A58h, 00E59h, 00254h, 00655h, 00656h, 00257h, 00A58h, 00E59h
DW 02660h, 02261h, 02262h, 02663h, 02264h, 02665h, 02666h, 02267h
DW 02A68h, 02E69h, 02264h, 02665h, 02666h, 02267h, 02A68h, 02E69h
DW 02270h, 02671h, 02672h, 02273h, 02674h, 02275h, 02276h, 02677h
DW 02E78h, 02A79h, 02674h, 02275h, 02276h, 02677h, 02E78h, 02A79h
DW 08280h, 08681h, 08682h, 08283h, 08684h, 08285h, 08286h, 08687h
DW 08E88h, 08A89h, 08684h, 08285h, 08286h, 08687h, 08E88h, 08A89h
DW 08690h, 08291h, 08292h, 08693h, 08294h, 08695h, 08696h, 08297h
DW 08A98h, 08E99h, 02334h, 02735h, 02736h, 02337h, 02B38h, 02F39h
DW 00340h, 00741h, 00742h, 00343h, 00744h, 00345h, 00346h, 00747h
DW 00F48h, 00B49h, 00744h, 00345h, 00346h, 00747h, 00F48h, 00B49h
DW 00750h, 00351h, 00352h, 00753h, 00354h, 00755h, 00756h, 00357h
DW 00B58h, 00F59h, 00354h, 00755h, 00756h, 00357h, 00B58h, 00F59h
DW 02760h, 02361h, 02362h, 02763h, 02364h, 02765h, 02766h, 02367h
DW 02B68h, 02F69h, 02364h, 02765h, 02766h, 02367h, 02B68h, 02F69h
DW 02370h, 02771h, 02772h, 02373h, 02774h, 02375h, 02376h, 02777h
DW 02F78h, 02B79h, 02774h, 02375h, 02376h, 02777h, 02F78h, 02B79h
DW 08380h, 08781h, 08782h, 08383h, 08784h, 08385h, 08386h, 08787h
DW 08F88h, 08B89h, 08784h, 08385h, 08386h, 08787h, 08F88h, 08B89h
DW 08790h, 08391h, 08392h, 08793h, 08394h, 08795h, 08796h, 08397h
DW 08B98h, 08F99h, 08394h, 08795h, 08796h, 08397h, 08B98h, 08F99h
DW 0A7A0h, 0A3A1h, 0A3A2h, 0A7A3h, 0A3A4h, 0A7A5h, 0A7A6h, 0A3A7h
DW 0ABA8h, 0AFA9h, 0A3A4h, 0A7A5h, 0A7A6h, 0A3A7h, 0ABA8h, 0AFA9h
DW 0A3B0h, 0A7B1h, 0A7B2h, 0A3B3h, 0A7B4h, 0A3B5h, 0A3B6h, 0A7B7h
DW 0AFB8h, 0ABB9h, 0A7B4h, 0A3B5h, 0A3B6h, 0A7B7h, 0AFB8h, 0ABB9h
DW 087C0h, 083C1h, 083C2h, 087C3h, 083C4h, 087C5h, 087C6h, 083C7h
DW 08BC8h, 08FC9h, 083C4h, 087C5h, 087C6h, 083C7h, 08BC8h, 08FC9h
DW 083D0h, 087D1h, 087D2h, 083D3h, 087D4h, 083D5h, 083D6h, 087D7h
DW 08FD8h, 08BD9h, 087D4h, 083D5h, 083D6h, 087D7h, 08FD8h, 08BD9h
DW 0A3E0h, 0A7E1h, 0A7E2h, 0A3E3h, 0A7E4h, 0A3E5h, 0A3E6h, 0A7E7h
DW 0AFE8h, 0ABE9h, 0A7E4h, 0A3E5h, 0A3E6h, 0A7E7h, 0AFE8h, 0ABE9h
DW 0A7F0h, 0A3F1h, 0A3F2h, 0A7F3h, 0A3F4h, 0A7F5h, 0A7F6h, 0A3F7h
DW 0ABF8h, 0AFF9h, 0A3F4h, 0A7F5h, 0A7F6h, 0A3F7h, 0ABF8h, 0AFF9h
DW 04700h, 00301h, 00302h, 00703h, 00304h, 00705h, 00706h, 00307h
DW 00B08h, 00F09h, 00304h, 00705h, 00706h, 00307h, 00B08h, 00F09h
DW 00310h, 00711h, 00712h, 00313h, 00714h, 00315h, 00316h, 00717h
DW 00F18h, 00B19h, 00714h, 00315h, 00316h, 00717h, 00F18h, 00B19h
DW 02320h, 02721h, 02722h, 02323h, 02724h, 02325h, 02326h, 02727h
DW 02F28h, 02B29h, 02724h, 02325h, 02326h, 02727h, 02F28h, 02B29h
DW 02730h, 02331h, 02332h, 02733h, 02334h, 02735h, 02736h, 02337h
DW 02B38h, 02F39h, 02334h, 02735h, 02736h, 02337h, 02B38h, 02F39h
DW 00340h, 00741h, 00742h, 00343h, 00744h, 00345h, 00346h, 00747h
DW 00F48h, 00B49h, 00744h, 00345h, 00346h, 00747h, 00F48h, 00B49h
DW 00750h, 00351h, 00352h, 00753h, 00354h, 00755h, 00756h, 00357h
DW 00B58h, 00F59h, 00354h, 00755h, 00756h, 00357h, 00B58h, 00F59h
DW 02760h, 02361h, 02362h, 02763h, 02364h, 02765h, 02766h, 02367h
DW 02B68h, 02F69h, 02364h, 02765h, 02766h, 02367h, 02B68h, 02F69h
DW 02370h, 02771h, 02772h, 02373h, 02774h, 02375h, 02376h, 02777h
DW 02F78h, 02B79h, 02774h, 02375h, 02376h, 02777h, 02F78h, 02B79h
DW 08380h, 08781h, 08782h, 08383h, 08784h, 08385h, 08386h, 08787h
DW 08F88h, 08B89h, 08784h, 08385h, 08386h, 08787h, 08F88h, 08B89h
DW 08790h, 08391h, 08392h, 08793h, 08394h, 08795h, 08796h, 08397h
DW 08B98h, 08F99h, 08394h, 08795h, 08796h, 08397h, 08B98h, 08F99h
DW 00406h, 00007h, 00808h, 00C09h, 00C0Ah, 0080Bh, 00C0Ch, 0080Dh
DW 0080Eh, 00C0Fh, 01010h, 01411h, 01412h, 01013h, 01414h, 01015h
DW 00016h, 00417h, 00C18h, 00819h, 0081Ah, 00C1Bh, 0081Ch, 00C1Dh
DW 00C1Eh, 0081Fh, 03020h, 03421h, 03422h, 03023h, 03424h, 03025h
DW 02026h, 02427h, 02C28h, 02829h, 0282Ah, 02C2Bh, 0282Ch, 02C2Dh
DW 02C2Eh, 0282Fh, 03430h, 03031h, 03032h, 03433h, 03034h, 03435h
DW 02436h, 02037h, 02838h, 02C39h, 02C3Ah, 0283Bh, 02C3Ch, 0283Dh
DW 0283Eh, 02C3Fh, 01040h, 01441h, 01442h, 01043h, 01444h, 01045h
DW 00046h, 00447h, 00C48h, 00849h, 0084Ah, 00C4Bh, 0084Ch, 00C4Dh
DW 00C4Eh, 0084Fh, 01450h, 01051h, 01052h, 01453h, 01054h, 01455h
DW 00456h, 00057h, 00858h, 00C59h, 00C5Ah, 0085Bh, 00C5Ch, 0085Dh
DW 0085Eh, 00C5Fh, 03460h, 03061h, 03062h, 03463h, 03064h, 03465h
DW 02466h, 02067h, 02868h, 02C69h, 02C6Ah, 0286Bh, 02C6Ch, 0286Dh
DW 0286Eh, 02C6Fh, 03070h, 03471h, 03472h, 03073h, 03474h, 03075h
DW 02076h, 02477h, 02C78h, 02879h, 0287Ah, 02C7Bh, 0287Ch, 02C7Dh
DW 02C7Eh, 0287Fh, 09080h, 09481h, 09482h, 09083h, 09484h, 09085h
DW 08086h, 08487h, 08C88h, 08889h, 0888Ah, 08C8Bh, 0888Ch, 08C8Dh
DW 08C8Eh, 0888Fh, 09490h, 09091h, 09092h, 09493h, 09094h, 09495h
DW 08496h, 08097h, 08898h, 08C99h, 08C9Ah, 0889Bh, 08C9Ch, 0889Dh
DW 0889Eh, 08C9Fh, 05500h, 01101h, 01102h, 01503h, 01104h, 01505h
DW 00506h, 00107h, 00908h, 00D09h, 00D0Ah, 0090Bh, 00D0Ch, 0090Dh
DW 0090Eh, 00D0Fh, 01110h, 01511h, 01512h, 01113h, 01514h, 01115h
DW 00116h, 00517h, 00D18h, 00919h, 0091Ah, 00D1Bh, 0091Ch, 00D1Dh
DW 00D1Eh, 0091Fh, 03120h, 03521h, 03522h, 03123h, 03524h, 03125h
DW 02126h, 02527h, 02D28h, 02929h, 0292Ah, 02D2Bh, 0292Ch, 02D2Dh
DW 02D2Eh, 0292Fh, 03530h, 03131h, 03132h, 03533h, 03134h, 03535h
DW 02536h, 02137h, 02938h, 02D39h, 02D3Ah, 0293Bh, 02D3Ch, 0293Dh
DW 0293Eh, 02D3Fh, 01140h, 01541h, 01542h, 01143h, 01544h, 01145h
DW 00146h, 00547h, 00D48h, 00949h, 0094Ah, 00D4Bh, 0094Ch, 00D4Dh
DW 00D4Eh, 0094Fh, 01550h, 01151h, 01152h, 01553h, 01154h, 01555h
DW 00556h, 00157h, 00958h, 00D59h, 00D5Ah, 0095Bh, 00D5Ch, 0095Dh
DW 0095Eh, 00D5Fh, 03560h, 03161h, 03162h, 03563h, 03164h, 03565h
DW 02566h, 02167h, 02968h, 02D69h, 02D6Ah, 0296Bh, 02D6Ch, 0296Dh
DW 0296Eh, 02D6Fh, 03170h, 03571h, 03572h, 03173h, 03574h, 03175h
DW 02176h, 02577h, 02D78h, 02979h, 0297Ah, 02D7Bh, 0297Ch, 02D7Dh
DW 02D7Eh, 0297Fh, 09180h, 09581h, 09582h, 09183h, 09584h, 09185h
DW 08186h, 08587h, 08D88h, 08989h, 0898Ah, 08D8Bh, 0898Ch, 08D8Dh
DW 08D8Eh, 0898Fh, 09590h, 09191h, 09192h, 09593h, 09194h, 09595h
DW 08596h, 08197h, 08998h, 08D99h, 08D9Ah, 0899Bh, 08D9Ch, 0899Dh
DW 0899Eh, 08D9Fh, 0B5A0h, 0B1A1h, 0B1A2h, 0B5A3h, 0B1A4h, 0B5A5h
DW 0A5A6h, 0A1A7h, 0A9A8h, 0ADA9h, 0ADAAh, 0A9ABh, 0ADACh, 0A9ADh
DW 0A9AEh, 0ADAFh, 0B1B0h, 0B5B1h, 0B5B2h, 0B1B3h, 0B5B4h, 0B1B5h
DW 0A1B6h, 0A5B7h, 0ADB8h, 0A9B9h, 0A9BAh, 0ADBBh, 0A9BCh, 0ADBDh
DW 0ADBEh, 0A9BFh, 095C0h, 091C1h, 091C2h, 095C3h, 091C4h, 095C5h
DW 085C6h, 081C7h, 089C8h, 08DC9h, 08DCAh, 089CBh, 08DCCh, 089CDh
DW 089CEh, 08DCFh, 091D0h, 095D1h, 095D2h, 091D3h, 095D4h, 091D5h
DW 081D6h, 085D7h, 08DD8h, 089D9h, 089DAh, 08DDBh, 089DCh, 08DDDh
DW 08DDEh, 089DFh, 0B1E0h, 0B5E1h, 0B5E2h, 0B1E3h, 0B5E4h, 0B1E5h
DW 0A1E6h, 0A5E7h, 0ADE8h, 0A9E9h, 0A9EAh, 0ADEBh, 0A9ECh, 0ADEDh
DW 0ADEEh, 0A9EFh, 0B5F0h, 0B1F1h, 0B1F2h, 0B5F3h, 0B1F4h, 0B5F5h
DW 0A5F6h, 0A1F7h, 0A9F8h, 0ADF9h, 0ADFAh, 0A9FBh, 0ADFCh, 0A9FDh
DW 0A9FEh, 0ADFFh, 05500h, 01101h, 01102h, 01503h, 01104h, 01505h
DW 00506h, 00107h, 00908h, 00D09h, 00D0Ah, 0090Bh, 00D0Ch, 0090Dh
DW 0090Eh, 00D0Fh, 01110h, 01511h, 01512h, 01113h, 01514h, 01115h
DW 00116h, 00517h, 00D18h, 00919h, 0091Ah, 00D1Bh, 0091Ch, 00D1Dh
DW 00D1Eh, 0091Fh, 03120h, 03521h, 03522h, 03123h, 03524h, 03125h
DW 02126h, 02527h, 02D28h, 02929h, 0292Ah, 02D2Bh, 0292Ch, 02D2Dh
DW 02D2Eh, 0292Fh, 03530h, 03131h, 03132h, 03533h, 03134h, 03535h
DW 02536h, 02137h, 02938h, 02D39h, 02D3Ah, 0293Bh, 02D3Ch, 0293Dh
DW 0293Eh, 02D3Fh, 01140h, 01541h, 01542h, 01143h, 01544h, 01145h
DW 00146h, 00547h, 00D48h, 00949h, 0094Ah, 00D4Bh, 0094Ch, 00D4Dh
DW 00D4Eh, 0094Fh, 01550h, 01151h, 01152h, 01553h, 01154h, 01555h
DW 00556h, 00157h, 00958h, 00D59h, 00D5Ah, 0095Bh, 00D5Ch, 0095Dh
DW 0095Eh, 00D5Fh, 03560h, 03161h, 03162h, 03563h, 03164h, 03565h
DW 0BEFAh, 0BAFBh, 0BEFCh, 0BAFDh, 0BAFEh, 0BEFFh, 04600h, 00201h
DW 00202h, 00603h, 00204h, 00605h, 00606h, 00207h, 00A08h, 00E09h
DW 01E0Ah, 01A0Bh, 01E0Ch, 01A0Dh, 01A0Eh, 01E0Fh, 00210h, 00611h
DW 00612h, 00213h, 00614h, 00215h, 00216h, 00617h, 00E18h, 00A19h
DW 01A1Ah, 01E1Bh, 01A1Ch, 01E1Dh, 01E1Eh, 01A1Fh, 02220h, 02621h
DW 02622h, 02223h, 02624h, 02225h, 02226h, 02627h, 02E28h, 02A29h
DW 03A2Ah, 03E2Bh, 03A2Ch, 03E2Dh, 03E2Eh, 03A2Fh, 02630h, 02231h
DW 02232h, 02633h, 02234h, 02635h, 02636h, 02237h, 02A38h, 02E39h
DW 03E3Ah, 03A3Bh, 03E3Ch, 03A3Dh, 03A3Eh, 03E3Fh, 00240h, 00641h
DW 00642h, 00243h, 00644h, 00245h, 00246h, 00647h, 00E48h, 00A49h
DW 01A4Ah, 01E4Bh, 01A4Ch, 01E4Dh, 01E4Eh, 01A4Fh, 00650h, 00251h
DW 00252h, 00653h, 00254h, 00655h, 00656h, 00257h, 00A58h, 00E59h
DW 01E5Ah, 01A5Bh, 01E5Ch, 01A5Dh, 01A5Eh, 01E5Fh, 02660h, 02261h
DW 02262h, 02663h, 02264h, 02665h, 02666h, 02267h, 02A68h, 02E69h
DW 03E6Ah, 03A6Bh, 03E6Ch, 03A6Dh, 03A6Eh, 03E6Fh, 02270h, 02671h
DW 02672h, 02273h, 02674h, 02275h, 02276h, 02677h, 02E78h, 02A79h
DW 03A7Ah, 03E7Bh, 03A7Ch, 03E7Dh, 03E7Eh, 03A7Fh, 08280h, 08681h
DW 08682h, 08283h, 08684h, 08285h, 08286h, 08687h, 08E88h, 08A89h
DW 09A8Ah, 09E8Bh, 09A8Ch, 09E8Dh, 09E8Eh, 09A8Fh, 08690h, 08291h
DW 08292h, 08693h, 02334h, 02735h, 02736h, 02337h, 02B38h, 02F39h
DW 03F3Ah, 03B3Bh, 03F3Ch, 03B3Dh, 03B3Eh, 03F3Fh, 00340h, 00741h
DW 00742h, 00343h, 00744h, 00345h, 00346h, 00747h, 00F48h, 00B49h
DW 01B4Ah, 01F4Bh, 01B4Ch, 01F4Dh, 01F4Eh, 01B4Fh, 00750h, 00351h
DW 00352h, 00753h, 00354h, 00755h, 00756h, 00357h, 00B58h, 00F59h
DW 01F5Ah, 01B5Bh, 01F5Ch, 01B5Dh, 01B5Eh, 01F5Fh, 02760h, 02361h
DW 02362h, 02763h, 02364h, 02765h, 02766h, 02367h, 02B68h, 02F69h
DW 03F6Ah, 03B6Bh, 03F6Ch, 03B6Dh, 03B6Eh, 03F6Fh, 02370h, 02771h
DW 02772h, 02373h, 02774h, 02375h, 02376h, 02777h, 02F78h, 02B79h
DW 03B7Ah, 03F7Bh, 03B7Ch, 03F7Dh, 03F7Eh, 03B7Fh, 08380h, 08781h
DW 08782h, 08383h, 08784h, 08385h, 08386h, 08787h, 08F88h, 08B89h
DW 09B8Ah, 09F8Bh, 09B8Ch, 09F8Dh, 09F8Eh, 09B8Fh, 08790h, 08391h
DW 08392h, 08793h, 08394h, 08795h, 08796h, 08397h, 08B98h, 08F99h
DW 09F9Ah, 09B9Bh, 09F9Ch, 09B9Dh, 09B9Eh, 09F9Fh, 0A7A0h, 0A3A1h
DW 0A3A2h, 0A7A3h, 0A3A4h, 0A7A5h, 0A7A6h, 0A3A7h, 0ABA8h, 0AFA9h
DW 0BFAAh, 0BBABh, 0BFACh, 0BBADh, 0BBAEh, 0BFAFh, 0A3B0h, 0A7B1h
DW 0A7B2h, 0A3B3h, 0A7B4h, 0A3B5h, 0A3B6h, 0A7B7h, 0AFB8h, 0ABB9h
DW 0BBBAh, 0BFBBh, 0BBBCh, 0BFBDh, 0BFBEh, 0BBBFh, 087C0h, 083C1h
DW 083C2h, 087C3h, 083C4h, 087C5h, 087C6h, 083C7h, 08BC8h, 08FC9h
DW 09FCAh, 09BCBh, 09FCCh, 09BCDh, 09BCEh, 09FCFh, 083D0h, 087D1h
DW 087D2h, 083D3h, 087D4h, 083D5h, 083D6h, 087D7h, 08FD8h, 08BD9h
DW 09BDAh, 09FDBh, 09BDCh, 09FDDh, 09FDEh, 09BDFh, 0A3E0h, 0A7E1h
DW 0A7E2h, 0A3E3h, 0A7E4h, 0A3E5h, 0A3E6h, 0A7E7h, 0AFE8h, 0ABE9h
DW 0BBEAh, 0BFEBh, 0BBECh, 0BFEDh, 0BFEEh, 0BBEFh, 0A7F0h, 0A3F1h
DW 0A3F2h, 0A7F3h, 0A3F4h, 0A7F5h, 0A7F6h, 0A3F7h, 0ABF8h, 0AFF9h
DW 0BFFAh, 0BBFBh, 0BFFCh, 0BBFDh, 0BBFEh, 0BFFFh, 04700h, 00301h
DW 00302h, 00703h, 00304h, 00705h, 00706h, 00307h, 00B08h, 00F09h
DW 01F0Ah, 01B0Bh, 01F0Ch, 01B0Dh, 01B0Eh, 01F0Fh, 00310h, 00711h
DW 00712h, 00313h, 00714h, 00315h, 00316h, 00717h, 00F18h, 00B19h
DW 01B1Ah, 01F1Bh, 01B1Ch, 01F1Dh, 01F1Eh, 01B1Fh, 02320h, 02721h
DW 02722h, 02323h, 02724h, 02325h, 02326h, 02727h, 02F28h, 02B29h
DW 03B2Ah, 03F2Bh, 03B2Ch, 03F2Dh, 03F2Eh, 03B2Fh, 02730h, 02331h
DW 02332h, 02733h, 02334h, 02735h, 02736h, 02337h, 02B38h, 02F39h
DW 03F3Ah, 03B3Bh, 03F3Ch, 03B3Dh, 03B3Eh, 03F3Fh, 00340h, 00741h
DW 00742h, 00343h, 00744h, 00345h, 00346h, 00747h, 00F48h, 00B49h
DW 01B4Ah, 01F4Bh, 01B4Ch, 01F4Dh, 01F4Eh, 01B4Fh, 00750h, 00351h
DW 00352h, 00753h, 00354h, 00755h, 00756h, 00357h, 00B58h, 00F59h
DW 01F5Ah, 01B5Bh, 01F5Ch, 01B5Dh, 01B5Eh, 01F5Fh, 02760h, 02361h
DW 02362h, 02763h, 02364h, 02765h, 02766h, 02367h, 02B68h, 02F69h
DW 03F6Ah, 03B6Bh, 03F6Ch, 03B6Dh, 03B6Eh, 03F6Fh, 02370h, 02771h
DW 02772h, 02373h, 02774h, 02375h, 02376h, 02777h, 02F78h, 02B79h
DW 03B7Ah, 03F7Bh, 03B7Ch, 03F7Dh, 03F7Eh, 03B7Fh, 08380h, 08781h
DW 08782h, 08383h, 08784h, 08385h, 08386h, 08787h, 08F88h, 08B89h
DW 09B8Ah, 09F8Bh, 09B8Ch, 09F8Dh, 09F8Eh, 09B8Fh, 08790h, 08391h
DW 08392h, 08793h, 08394h, 08795h, 08796h, 08397h, 08B98h, 08F99h
NEG_Table:
DB 0,66,255,187,254,187,253,187,252,187,251,187,250,187,249,187,248,187,247,179
DB 246,179,245,179,244,179,243,179,242,179,241,179,240,163,239,187,238,187,237,187
DB 236,187,235,187,234,187,233,187,232,187,231,179,230,179,229,179,228,179,227,179
DB 226,179,225,179,224,163,223,155,222,155,221,155,220,155,219,155,218,155,217,155
DB 216,155,215,147,214,147,213,147,212,147,211,147,210,147,209,147,208,131,207,155
DB 206,155,205,155,204,155,203,155,202,155,201,155,200,155,199,147,198,147,197,147
DB 196,147,195,147,194,147,193,147,192,131,191,187,190,187,189,187,188,187,187,187
DB 186,187,185,187,184,187,183,179,182,179,181,179,180,179,179,179,178,179,177,179
DB 176,163,175,187,174,187,173,187,172,187,171,187,170,187,169,187,168,187,167,179
DB 166,179,165,179,164,179,163,179,162,179,161,179,160,163,159,155,158,155,157,155
DB 156,155,155,155,154,155,153,155,152,155,151,147,150,147,149,147,148,147,147,147
DB 146,147,145,147,144,131,143,155,142,155,141,155,140,155,139,155,138,155,137,155
DB 136,155,135,147,134,147,133,147,132,147,131,147,130,147,129,147,128,135,127,59
DB 126,59,125,59,124,59,123,59,122,59,121,59,120,59,119,51,118,51,117,51
DB 116,51,115,51,114,51,113,51,112,35,111,59,110,59,109,59,108,59,107,59
DB 106,59,105,59,104,59,103,51,102,51,101,51,100,51,99,51,98,51,97,51
DB 96,35,95,27,94,27,93,27,92,27,91,27,90,27,89,27,88,27,87,19
DB 86,19,85,19,84,19,83,19,82,19,81,19,80,3,79,27,78,27,77,27
DB 76,27,75,27,74,27,73,27,72,27,71,19,70,19,69,19,68,19,67,19
DB 66,19,65,19,64,3,63,59,62,59,61,59,60,59,59,59,58,59,57,59
DB 56,59,55,51,54,51,53,51,52,51,51,51,50,51,49,51,48,35,47,59
DB 46,59,45,59,44,59,43,59,42,59,41,59,40,59,39,51,38,51,37,51
DB 36,51,35,51,34,51,33,51,32,35,31,27,30,27,29,27,28,27,27,27
DB 26,27,25,27,24,27,23,19,22,19,21,19,20,19,19,19,18,19,17,19
DB 16,3,15,27,14,27,13,27,12,27,11,27,10,27,9,27,8,27,7,19
DB 6,19,5,19,4,19,3,19,2,19,1,19
;- the end ------ (blimey) --------------------------------------------------;
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.