diff --git a/src/zvm_m65/,aliases_zvm.s b/src/zvm_m65/,aliases_zvm.s index 4a46ba74..cc497eb9 100644 --- a/src/zvm_m65/,aliases_zvm.s +++ b/src/zvm_m65/,aliases_zvm.s @@ -1,73 +1,116 @@ -!addr REG_AF = $02 ; 16-bit combined register -!addr REG_F = REG_AF+0 ; 8-bit flag register -!addr REG_A = REG_AF+1 ; 8-bit accumulator -!addr REG_BC = $04 -!addr REG_C = REG_BC+0 -!addr REG_B = REG_BC+1 -!addr REG_DE = $06 -!addr REG_E = REG_DE+0 -!addr REG_D = REG_DE+1 -!addr REG_HL = $08 -!addr REG_L = REG_HL+0 -!addr REG_H = REG_HL+1 +; +; Z80 CPU state/emulation data +; -!addr REG_F_SH = $0A ; shadow registers -!addr REG_A_SH = $0B -!addr REG_C_SH = $0C -!addr REG_B_SH = $0D -!addr REG_E_SH = $0E -!addr REG_D_SH = $0F -!addr REG_L_SH = $10 -!addr REG_H_SH = $11 +!addr z80_cpustate__start = $02 -!addr REG_IX = $12 ; 16-bit index register -!addr REG_IXL = $12 -!addr REG_IXH = $13 -!addr REG_IY = $14 ; 16-bit index register -!addr REG_IYL = $14 -!addr REG_IYH = $15 -!addr REG_SP = $16 ; 16-bit stack pointer -!addr REG_PC = $18 ; 16-bit program counter +!addr REG_AF = $02 ; 2 bytes - combined register +!addr REG_F = REG_AF+0 ; - flag register +!addr REG_A = REG_AF+1 ; - accumulator -!addr REG_I = $1A ; 8-bit interrupt vector base -!addr REG_R06 = $1B ; refresh counter, bits 0-6 (bit 7 is garbage) -!addr REG_R7 = $1C ; refresh counter, bit 7 (bits 0-6 are garbage) +!addr REG_BC = $04 ; 2 bytes - combined register +!addr REG_C = REG_BC+0 +!addr REG_B = REG_BC+1 +!addr REG_BC_EXT1 = $06 ; 2 bytes - helper for faster access via BC in bank 1 -!addr PTR_IXY_d = $1D ; 16-bit calculated address IX+d / IY+d XXX - important!!! -!addr PTR_DATA = $1F ; data source address XXX - important!!! +!addr REG_DE = $08 ; 2 bytes - combined register +!addr REG_E = REG_DE+0 +!addr REG_D = REG_DE+1 +!addr REG_DE_EXT1 = $0A ; 2 bytes - helper for faster access via DE in bank 1 -!addr REG_IFF1 = $23 ; interrupt flip-flop flag 1 -!addr REG_IFF2 = $24 ; interrupt flip-flop flag 2 +!addr REG_HL = $0C ; 2 bytes - combined register +!addr REG_L = REG_HL+0 +!addr REG_H = REG_HL+1 +!addr REG_HL_EXT1 = $0E ; 2 bytes - helper for faster access via HL in bank 1 -!addr REG_TMP1 = $25 ; emulation-specific temporary storage -!addr REG_TMP2 = $26 -!addr ADDR_IO = $27 ; 16-bit address for fetching/storing the IO +!addr REG_SHADOW = $10 ; 8 bytes - shadow registers +!addr REG_F_SH = REG_SHADOW+0 +!addr REG_A_SH = REG_SHADOW+1 +!addr REG_C_SH = REG_SHADOW+2 +!addr REG_B_SH = REG_SHADOW+3 +!addr REG_E_SH = REG_SHADOW+4 +!addr REG_D_SH = REG_SHADOW+5 +!addr REG_L_SH = REG_SHADOW+6 +!addr REG_H_SH = REG_SHADOW+7 +!addr REG_SP = $18 ; 2 bytes - stack pointer +!addr REG_SP_EXT1 = $1A ; 2 bytes - helper for faster access via SP in bank 1 +!addr REG_PC = $1C ; 2 bytes - sprogram counter +!addr REG_PC_EXT1 = $1E ; 2 bytes - helper for faster access via PC in bank 1 -!addr VEC_MOVE_fetch = $30 ; vector to byte fetch routine, for BIOS routine MOVE -!addr VEC_MOVE_store = $32 ; vector to byte store routine, for BIOS routine MOVE -!addr VEC_DISKIO_store = $34 ; vector to byte store routine, for BIOS disk I/O operations +!addr REG_IX = $20 ; 2 bytes - index register +!addr REG_IXL = REG_IX+0 +!addr REG_IXH = REG_IX+1 +!addr REG_IY = $22 ; 2 bytes - index register +!addr REG_IYL = REG_IY+0 +!addr REG_IYH = REG_IY+1 -!addr VEC_fetch_value = $50 -!addr VEC_fetch_stack = $52 -!addr VEC_store_stack = $54 -!addr VEC_fetch_via_BC = $56 ; XXX add routines -!addr VEC_store_via_BC = $58 ; XXX add routines -!addr VEC_fetch_via_DE = $5A ; XXX add routines -!addr VEC_store_via_DE = $5C ; XXX add routines -!addr VEC_fetch_via_HL = $5E -!addr VEC_store_via_HL = $60 -!addr VEC_fetch_via_IX_d = $62 -!addr VEC_fetch_via_IY_d = $64 -!addr VEC_store_via_IX_d = $66 -!addr VEC_store_via_IY_d = $68 -!addr VEC_fetch_via_nn = $6A -!addr VEC_store_via_nn = $6C -!addr VEC_fetch_via_plus1 = $6E ; XXX add routines -!addr VEC_store_via_plus1 = $70 ; XXX add routines XXX jump to next directly? -!addr VEC_xchng_stack_lo = $72 ; XXX add routines -!addr VEC_xchng_stack_hi = $74 ; XXX add routines +!addr REG_IFF1 = $24 ; 1 byte - interrupt flip-flop flag 1 +!addr REG_IFF2 = $25 ; 1 byte - interrupt flip-flop flag 2 +!addr REG_R06 = $26 ; 1 byte - refresh counter, bits 0-6 (bit 7 is garbage) +!addr REG_R7 = $27 ; 1 byte - refresh counter, bit 7 (bits 0-6 are garbage) +!addr REG_I = $28 ; 1 byte - interrupt vector base + +!addr z80_cpustate__end = $28 + +!addr BANK_ID = $29 ; 1 byte - currently selected bank + +; +; BIOS vectors +; + +!addr VEC_MOVE_fetch = $2A ; 2 bytes - vector to byte fetch routine, for BIOS routine MOVE +!addr VEC_MOVE_store = $2C ; 2 bytes - vector to byte store routine, for BIOS routine MOVE +!addr VEC_DISKIO_store = $2E ; 2 bytes - vector to byte store routine, for BIOS disk I/O operations + +; +; Z80 emulation temporary area +; + +!addr PTR_IXY_d = $30 ; 4 bytes - calculated address IX+d / IY+d XXX - review usage !!! +!addr PTR_IXY_d_EXT1 = PTR_IXY_d+2 +!addr PTR_DATA = $34 ; 4 bytes - calculated data source address XXX - review usage !!! also check functions using ZVM_store_next +!addr PTR_DATA_EXT1 = PTR_DATA+2 +!addr ADDR_IO = $38 ; 4 bytes - address for fetching/storing the IO + +!addr REG_TMP1 = $3C ; 1 byte - emulation-specific temporary storage +!addr REG_TMP2 = $3D ; 1 byte - emulation-specific temporary storage + +; $3E ; 2 bytes - reserved + +; +; Memory banking vectors +; + +!addr zvm_bankvectors__start = $40 + +!addr VEC_fetch_via_PC_inc = $40 ; fetch to .A from (PC), increment PC afterwards XXX consider providing dual-byte retrieval + +; XXX implement routines for vectors below + +!addr VEC_fetch_stack = $42 +!addr VEC_store_stack = $44 +!addr VEC_fetch_via_BC = $46 +!addr VEC_store_via_BC = $48 +!addr VEC_fetch_via_DE = $4A +!addr VEC_store_via_DE = $4C +!addr VEC_fetch_via_HL = $4E +!addr VEC_store_via_HL = $50 +!addr VEC_fetch_via_IX_d = $52 +!addr VEC_fetch_via_IY_d = $54 +!addr VEC_store_via_IX_d = $56 +!addr VEC_store_via_IY_d = $58 +!addr VEC_fetch_via_nn = $5A +!addr VEC_store_via_nn = $5C +!addr VEC_fetch_via_plus1 = $5E +!addr VEC_store_via_plus1 = $60 ; XXX jump to next directly? +!addr VEC_xchng_stack_lo = $62 +!addr VEC_xchng_stack_hi = $64 + +; +; Constant/macros definitions +; ; Masks for Z80 flag (F) register @@ -101,3 +144,10 @@ !macro Z80_PUT_0_NF { rmb1 REG_F } !macro Z80_PUT_1_CF { smb0 REG_F } !macro Z80_PUT_0_CF { rmb0 REG_F } + +; +; Helper tables for CPU emulation, downwards from $2000 +; + +!addr z80_atable_mi_bank0 = $1FF0 ; table for bank 0 memory address conversion +!addr z80_atable_hi_bank0 = $1FE0 ; table for bank 0 memory address conversion diff --git a/src/zvm_m65/z80_instr_bit.s b/src/zvm_m65/z80_instr_bit.s index 050acc05..bec34ddd 100644 --- a/src/zvm_m65/z80_instr_bit.s +++ b/src/zvm_m65/z80_instr_bit.s @@ -3,7 +3,6 @@ ; Z80 bit set/reset/test instructions ; - ; bits 0, 1, 4, 6 Z80_instr_CB_40: ; BIT 0,B diff --git a/src/zvm_m65/z80_instr_call_return.s b/src/zvm_m65/z80_instr_call_return.s index 15ef8033..63f3c836 100644 --- a/src/zvm_m65/z80_instr_call_return.s +++ b/src/zvm_m65/z80_instr_call_return.s @@ -6,9 +6,9 @@ Z80_instr_CD: ; CALL nn - jsr (VEC_fetch_value) + jsr (VEC_fetch_via_PC_inc) pha - jsr (VEC_fetch_value) + jsr (VEC_fetch_via_PC_inc) pha lda REG_PC+1 diff --git a/src/zvm_m65/z80_instr_io.s b/src/zvm_m65/z80_instr_io.s index 95ba655d..b587659a 100644 --- a/src/zvm_m65/z80_instr_io.s +++ b/src/zvm_m65/z80_instr_io.s @@ -6,7 +6,7 @@ Z80_instr_DB: ; IN A,(n) - jsr (VEC_fetch_value) + jsr (VEC_fetch_via_PC_inc) sta ADDR_IO+0 lda REG_A sta ADDR_IO+1 @@ -39,7 +39,7 @@ Z80_instr_ED_78: +Z80_IN_REGn REG_A ; Z80_instr_D3: ; OUT (n),A - jsr (VEC_fetch_value) + jsr (VEC_fetch_via_PC_inc) sta ADDR_IO+0 lda REG_A sta ADDR_IO+1 diff --git a/src/zvm_m65/z80_instr_jump.s b/src/zvm_m65/z80_instr_jump.s index 9d3b611d..f6e6f009 100644 --- a/src/zvm_m65/z80_instr_jump.s +++ b/src/zvm_m65/z80_instr_jump.s @@ -6,9 +6,9 @@ Z80_instr_C3: ; JP nn - jsr (VEC_fetch_value) + jsr (VEC_fetch_via_PC_inc) sta REG_PC+0 - jsr (VEC_fetch_value) + jsr (VEC_fetch_via_PC_inc) sta REG_PC+1 jmp ZVM_next @@ -102,7 +102,7 @@ Z80_instr_18: ; JR e @1: rmb7 REG_PC+0 @2: - jsr (VEC_fetch_value) + jsr (VEC_fetch_via_PC_inc) tax lda z80_otable_displacement,x clc diff --git a/src/zvm_m65/z80_instr_load_16bit.s b/src/zvm_m65/z80_instr_load_16bit.s index c01e673f..d4560f11 100644 --- a/src/zvm_m65/z80_instr_load_16bit.s +++ b/src/zvm_m65/z80_instr_load_16bit.s @@ -5,9 +5,9 @@ !macro Z80_LD_REGnn_nn .REGnn { - jsr (VEC_fetch_value) + jsr (VEC_fetch_via_PC_inc) sta .REGnn+0 - jsr (VEC_fetch_value) + jsr (VEC_fetch_via_PC_inc) sta .REGnn+1 jmp ZVM_next } diff --git a/src/zvm_m65/z80_instr_load_8bit.s b/src/zvm_m65/z80_instr_load_8bit.s index 1258b049..90e640d4 100644 --- a/src/zvm_m65/z80_instr_load_8bit.s +++ b/src/zvm_m65/z80_instr_load_8bit.s @@ -110,7 +110,7 @@ Z80_illeg_FD_6C: +Z80_LD_REGn_REGn REG_IYL, REG_IYH ; Z80_illeg_FD_6F: +Z80_LD_REGn_REGn REG_IYL, REG_A ; LD IYL,A !macro Z80_LD_REGn_n .REGn { - jsr (VEC_fetch_value) + jsr (VEC_fetch_via_PC_inc) sta .REGn jmp ZVM_next } @@ -250,7 +250,7 @@ Z80_instr_FD_77: +Z80_LD_VIA_IY_d_REG_n REG_A ; Z80_instr_36: ; LD (HL),n - jsr (VEC_fetch_value) + jsr (VEC_fetch_via_PC_inc) jsr (VEC_store_via_HL) jmp ZVM_next diff --git a/src/zvm_m65/z80_instr_math_16bit.s b/src/zvm_m65/z80_instr_math_16bit.s index 337f6167..ea28c8eb 100644 --- a/src/zvm_m65/z80_instr_math_16bit.s +++ b/src/zvm_m65/z80_instr_math_16bit.s @@ -4,62 +4,243 @@ ; -Z80_instr_03: ; INC BC - - inw REG_BC +!macro Z80_INC_REGnn .REGnn { + inw .REGnn jmp ZVM_next +} -Z80_instr_13: ; INC DE - - inw REG_DE +!macro Z80_DEC_REGnn .REGnn { + dew .REGnn jmp ZVM_next +} -Z80_instr_23: ; INC HL +Z80_instr_03: +Z80_INC_REGnn REG_BC ; INC BC +Z80_instr_13: +Z80_INC_REGnn REG_DE ; INC DE +Z80_instr_23: +Z80_INC_REGnn REG_HL ; INC HL +Z80_instr_33: +Z80_INC_REGnn REG_SP ; INC SP +Z80_instr_DD_23: +Z80_INC_REGnn REG_IX ; INC IX +Z80_instr_FD_23: +Z80_INC_REGnn REG_IY ; INC IY - inw REG_HL +Z80_instr_0B: +Z80_DEC_REGnn REG_BC ; DEC BC +Z80_instr_1B: +Z80_DEC_REGnn REG_DE ; DEC DE +Z80_instr_2B: +Z80_DEC_REGnn REG_HL ; DEC HL +Z80_instr_3B: +Z80_DEC_REGnn REG_SP ; DEC SP +Z80_instr_DD_2B: +Z80_DEC_REGnn REG_IX ; DEC IX +Z80_instr_FD_2B: +Z80_DEC_REGnn REG_IY ; DEC IY + +!macro Z80_ADD_REGnn_REGnn .REGnn1, .REGnn2 { ; XXX size-optimize this - extract common parts + + lda REG_F + and #($FF - Z80_HF - Z80_YF - Z80_XF - Z80_NF - Z80_CF) + sta REG_F + + ; Handle low bytes + + clc + lda .REGnn1+0 + adc .REGnn2+0 + sta .REGnn1+0 + + ; Handle HF flag + + php + clc + lda .REGnn1+1 + and #$0F + sta REG_TMP1 + lda .REGnn2+1 + and #$0F + adc REG_TMP1 + and #$F0 + beq @1 + +Z80_PUT_1_HF +@1: + plp + + ; Handle high bytes + + lda .REGnn1+1 + adc .REGnn2+1 + sta .REGnn1+1 + + ; Handle XF/YF flags + + and #%00101000 + ora REG_F + sta REG_F + + ; Handle CF flag + + +bcc ZVM_next + +Z80_PUT_1_CF jmp ZVM_next +} -Z80_instr_33: ; INC SP +Z80_instr_09: +Z80_ADD_REGnn_REGnn REG_HL, REG_BC ; ADD HL,BC +Z80_instr_19: +Z80_ADD_REGnn_REGnn REG_HL, REG_DE ; ADD HL,DE +Z80_instr_29: +Z80_ADD_REGnn_REGnn REG_HL, REG_HL ; ADD HL,HL +Z80_instr_39: +Z80_ADD_REGnn_REGnn REG_HL, REG_SP ; ADD HL,SP - inw REG_SP +Z80_instr_DD_09: +Z80_ADD_REGnn_REGnn REG_IX, REG_BC ; ADD IX,BC +Z80_instr_DD_19: +Z80_ADD_REGnn_REGnn REG_IX, REG_DE ; ADD IX,DE +Z80_instr_DD_29: +Z80_ADD_REGnn_REGnn REG_IX, REG_IX ; ADD IX,IX +Z80_instr_DD_39: +Z80_ADD_REGnn_REGnn REG_IX, REG_SP ; ADD IX,SP + +Z80_instr_FD_09: +Z80_ADD_REGnn_REGnn REG_IY, REG_BC ; ADD IY,BC +Z80_instr_FD_19: +Z80_ADD_REGnn_REGnn REG_IY, REG_DE ; ADD IY,DE +Z80_instr_FD_29: +Z80_ADD_REGnn_REGnn REG_IY, REG_IY ; ADD IY,IY +Z80_instr_FD_39: +Z80_ADD_REGnn_REGnn REG_IY, REG_SP ; ADD IY,SP + +!macro Z80_ADC_HL_REGnn .REGnn { ; XXX size-optimize this - extract common parts + + ; Clear flags + + stz REG_F + + ; Handle low bytes + + clc + bbr0 REG_F, @1 + sec +@1: + lda REG_HL+0 + adc .REGnn+0 + sta REG_HL+0 + + ; Handle HF flag + + php + clc + bbr0 REG_F, @2 + sec +@2: + lda REG_HL+1 + and #$0F + sta REG_TMP1 + lda .REGnn+1 + and #$0F + adc REG_TMP1 + and #$F0 + beq @3 + +Z80_PUT_1_HF +@3: + plp + + ; Handle high bytes + + lda REG_HL+1 + adc .REGnn+1 + sta REG_HL+1 + + ; Handle SF flag + + bne @4 + +Z80_PUT_1_SF +@4: + ; Handle XF/YF flags + + and #%00101000 + ora REG_F + sta REG_F + + ; Handle CF flag + + bcc @5 + +Z80_PUT_1_CF +@5: + ; Handle VF flag + + bvc @6 + +Z80_PUT_1_VF +@6 + ; Handle ZF flag + + lda REG_HL+0 + ora REG_HL+1 + +beq ZVM_next + +Z80_PUT_1_ZF jmp ZVM_next +} -Z80_instr_DD_23: ; INC IX +Z80_instr_ED_4A: +Z80_ADC_HL_REGnn REG_BC ; ADC HL,BC +Z80_instr_ED_5A: +Z80_ADC_HL_REGnn REG_DE ; ADC HL,DE +Z80_instr_ED_6A: +Z80_ADC_HL_REGnn REG_HL ; ADC HL,HL +Z80_instr_ED_7A: +Z80_ADC_HL_REGnn REG_SP ; ADC HL,SP - inw REG_IX +!macro Z80_SBC_HL_REGnn .REGnn { ; XXX size-optimize this - extract common parts + + ; Clear flags, set NF + + lda #Z80_NF + sta REG_F + + ; Handle low bytes + + clc + bbs0 REG_F, @1 + sec +@1: + lda REG_HL+0 + adc .REGnn+0 + sta REG_HL+0 + + ; Handle HF flag + + php + clc + bbs0 REG_F, @2 + sec +@2: + lda REG_HL+1 + and #$0F + sta REG_TMP1 + lda .REGnn+1 + and #$0F + sbc REG_TMP1 + and #$F0 + beq @3 + +Z80_PUT_1_HF +@3: + plp + + ; Handle high bytes + + lda REG_HL+1 + sbc .REGnn+1 + sta REG_HL+1 + + ; Handle SF flag + + bne @4 + +Z80_PUT_1_SF +@4: + ; Handle XF/YF flags + + and #%00101000 + ora REG_F + sta REG_F + + ; Handle CF flag + + bcs @5 + +Z80_PUT_1_CF +@5: + + ; Handle VF flag + + bvc @6 + +Z80_PUT_1_VF +@6 + ; Handle ZF flag + + lda REG_HL+0 + ora REG_HL+1 + +beq ZVM_next + +Z80_PUT_1_ZF jmp ZVM_next +} -Z80_instr_FD_23: ; INC IY - - inw REG_IY - jmp ZVM_next - -Z80_instr_0B: ; DEC BC - - dew REG_BC - jmp ZVM_next - -Z80_instr_1B: ; DEC DE - - dew REG_DE - jmp ZVM_next - -Z80_instr_2B: ; DEC HL - - dew REG_HL - jmp ZVM_next - -Z80_instr_3B: ; DEC SP - - dew REG_SP - jmp ZVM_next - -Z80_instr_DD_2B: ; DEC IX - - dew REG_IX - jmp ZVM_next - -Z80_instr_FD_2B: ; DEC IY - - dew REG_IY - jmp ZVM_next +Z80_instr_ED_42: +Z80_SBC_HL_REGnn REG_BC; SBC HL,BC +Z80_instr_ED_52: +Z80_SBC_HL_REGnn REG_DE; SBC HL,DE +Z80_instr_ED_62: +Z80_SBC_HL_REGnn REG_HL; SBC HL,HL +Z80_instr_ED_72: +Z80_SBC_HL_REGnn REG_SP; SBC HL,SP diff --git a/src/zvm_m65/z80_instr_math_8bit.s b/src/zvm_m65/z80_instr_math_8bit.s index 112a79d8..66b3cd4c 100644 --- a/src/zvm_m65/z80_instr_math_8bit.s +++ b/src/zvm_m65/z80_instr_math_8bit.s @@ -8,12 +8,12 @@ !macro Z80_ADD_n { - jsr (VEC_fetch_value) + jsr (VEC_fetch_via_PC_inc) bra Z80_common_add } !macro Z80_ADC_n { - jsr (VEC_fetch_value) + jsr (VEC_fetch_via_PC_inc) bbs0 REG_F,Z80_common_adc jmp Z80_common_add } @@ -167,12 +167,12 @@ Z80_common_adc: jmp ZVM_next !macro Z80_SUB_n { - jsr (VEC_fetch_value) + jsr (VEC_fetch_via_PC_inc) bra Z80_common_sub } !macro Z80_SBC_n { - jsr (VEC_fetch_value) + jsr (VEC_fetch_via_PC_inc) bbs0 REG_F,Z80_common_sbc jmp Z80_common_sub } @@ -326,7 +326,7 @@ Z80_common_sbc: jmp ZVM_next !macro Z80_CP_n { - jsr (VEC_fetch_value) + jsr (VEC_fetch_via_PC_inc) bra Z80_common_cp } @@ -431,7 +431,7 @@ Z80_common_cp: } !macro Z80_AND_n { - jsr (VEC_fetch_value) + jsr (VEC_fetch_via_PC_inc) +Z80_AND_common } @@ -491,7 +491,7 @@ Z80_instr_FD_A6: +Z80_AND_VIA_IY_d ; } !macro Z80_OR_n { - jsr (VEC_fetch_value) + jsr (VEC_fetch_via_PC_inc) +Z80_OR_common } @@ -548,7 +548,7 @@ Z80_instr_FD_B6: +Z80_OR_VIA_IY_d ; } !macro Z80_XOR_n { - jsr (VEC_fetch_value) + jsr (VEC_fetch_via_PC_inc) +Z80_XOR_common } diff --git a/src/zvm_m65/z80_instr_rotate_shift.s b/src/zvm_m65/z80_instr_rotate_shift.s index e75efea2..bd5f5843 100644 --- a/src/zvm_m65/z80_instr_rotate_shift.s +++ b/src/zvm_m65/z80_instr_rotate_shift.s @@ -3,6 +3,85 @@ ; Z80 rotate/shift instructions ; +; XXX for RRD/RLD generate tables in extended RAM + + +Z80_instr_ED_67: ; RRD + + jsr (VEC_fetch_via_HL) + sta REG_TMP1 + + lda REG_A + tax + and #$F0 + sta REG_A + txa + + ror + ror REG_TMP1 + ror + ror REG_TMP1 + ror + ror REG_TMP1 + ror + ror REG_TMP1 + ror + + clc + ror + asr + asr + asr + + ora REG_A + sta REG_A + + tax + lda REG_F + and #Z80_CF + ora z80_ftable_RRD_RLD,x + sta REG_F + + lda REG_TMP1 + jmp ZVM_store_next + +Z80_instr_ED_6F: ; RLD + + jsr (VEC_fetch_via_HL) + sta REG_TMP1 + + lda REG_A + tax + and #$F0 + sta REG_A + txa + + asl + asl + asl + asl + + asl + rol REG_TMP1 + rol + rol REG_TMP1 + rol + rol REG_TMP1 + rol + rol REG_TMP1 + rol + + ora REG_A + sta REG_A + + tax + lda REG_F + and #Z80_CF + ora z80_ftable_RRD_RLD,x + sta REG_F + + lda REG_TMP1 + jmp ZVM_store_next Z80_instr_07: ; RLCA @@ -92,6 +171,25 @@ Z80_instr_1F: ; RRA jmp ZVM_next } +!macro Z80_RLC_VIA_HL { + + jsr (VEC_fetch_via_HL) + + tax + rol + txa + + rol + sta [PTR_DATA],z + + tax + lda z80_ftable_IN_OR_XOR, x + sta REG_F + +bcc ZVM_next + +Z80_PUT_1_CF + jmp ZVM_next +} + Z80_instr_CB_00: +Z80_RLC_REGn REG_B ; RLC B Z80_instr_CB_01: +Z80_RLC_REGn REG_C ; RLC C Z80_instr_CB_02: +Z80_RLC_REGn REG_D ; RLC D @@ -99,6 +197,7 @@ Z80_instr_CB_03: +Z80_RLC_REGn REG_E ; Z80_instr_CB_04: +Z80_RLC_REGn REG_H ; RLC H Z80_instr_CB_05: +Z80_RLC_REGn REG_L ; RLC L Z80_instr_CB_07: +Z80_RLC_REGn REG_A ; RLC A +Z80_instr_CB_06: +Z80_RLC_VIA_HL ; RLC (HL) !macro Z80_RRC_REGn .REGn { @@ -116,6 +215,25 @@ Z80_instr_CB_07: +Z80_RLC_REGn REG_A ; jmp ZVM_next } +!macro Z80_RRC_VIA_HL { + + jsr (VEC_fetch_via_HL) + + tax + ror + txa + + ror + sta [PTR_DATA],z + + tax + lda z80_ftable_IN_OR_XOR, x + sta REG_F + +bcc ZVM_next + +Z80_PUT_1_CF + jmp ZVM_next +} + Z80_instr_CB_08: +Z80_RRC_REGn REG_B ; RRC B Z80_instr_CB_09: +Z80_RRC_REGn REG_C ; RRC C Z80_instr_CB_0A: +Z80_RRC_REGn REG_D ; RRC D @@ -123,6 +241,7 @@ Z80_instr_CB_0B: +Z80_RRC_REGn REG_E ; Z80_instr_CB_0C: +Z80_RRC_REGn REG_H ; RRC H Z80_instr_CB_0D: +Z80_RRC_REGn REG_L ; RRC L Z80_instr_CB_0F: +Z80_RRC_REGn REG_A ; RRC A +Z80_instr_CB_0E: +Z80_RRC_VIA_HL ; RRC (HL) !macro Z80_RL_REGn .REGn { @@ -140,6 +259,25 @@ Z80_instr_CB_0F: +Z80_RRC_REGn REG_A ; jmp ZVM_next } +!macro Z80_RL_VIA_HL { + + jsr (VEC_fetch_via_HL) + + clc + bbr0 REG_F, @1 + sec +@1: + rol + sta [PTR_DATA],z + + tax + lda z80_ftable_IN_OR_XOR, x + sta REG_F + +bcc ZVM_next + +Z80_PUT_1_CF + jmp ZVM_next +} + Z80_instr_CB_10: +Z80_RL_REGn REG_B ; RL B Z80_instr_CB_11: +Z80_RL_REGn REG_C ; RL C Z80_instr_CB_12: +Z80_RL_REGn REG_D ; RL D @@ -147,6 +285,7 @@ Z80_instr_CB_13: +Z80_RL_REGn REG_E ; Z80_instr_CB_14: +Z80_RL_REGn REG_H ; RL H Z80_instr_CB_15: +Z80_RL_REGn REG_L ; RL L Z80_instr_CB_17: +Z80_RL_REGn REG_A ; RL A +Z80_instr_CB_16: +Z80_RL_VIA_HL ; RL (HL) !macro Z80_RR_REGn .REGn { @@ -164,6 +303,25 @@ Z80_instr_CB_17: +Z80_RL_REGn REG_A ; jmp ZVM_next } +!macro Z80_RR_VIA_HL { + + jsr (VEC_fetch_via_HL) + + clc + bbr0 REG_F, @1 + sec +@1: + ror + sta [PTR_DATA],z + + tax + lda z80_ftable_IN_OR_XOR, x + sta REG_F + +bcc ZVM_next + +Z80_PUT_1_CF + jmp ZVM_next +} + Z80_instr_CB_18: +Z80_RR_REGn REG_B ; RR B Z80_instr_CB_19: +Z80_RR_REGn REG_C ; RR C Z80_instr_CB_1A: +Z80_RR_REGn REG_D ; RR D @@ -171,6 +329,7 @@ Z80_instr_CB_1B: +Z80_RR_REGn REG_E ; Z80_instr_CB_1C: +Z80_RR_REGn REG_H ; RR H Z80_instr_CB_1D: +Z80_RR_REGn REG_L ; RR L Z80_instr_CB_1F: +Z80_RR_REGn REG_A ; RR A +Z80_instr_CB_1E: +Z80_RR_VIA_HL ; RR (HL) ; XXX SLA/SLL (and possibly rotations) can be made slightly faster with dedicated tables (omit carry flag calculation) @@ -186,6 +345,20 @@ Z80_instr_CB_1F: +Z80_RR_REGn REG_A ; jmp ZVM_next } +!macro Z80_SLA_VIA { + + jsr (VEC_fetch_via_HL) + asl + sta [PTR_DATA],z + + tax + lda z80_ftable_IN_OR_XOR, x + sta REG_F + +bcc ZVM_next + +Z80_PUT_1_CF + jmp ZVM_next +} + Z80_instr_CB_20: +Z80_SLA_REGn REG_B ; SLA B Z80_instr_CB_21: +Z80_SLA_REGn REG_C ; SLA C Z80_instr_CB_22: +Z80_SLA_REGn REG_D ; SLA D @@ -193,6 +366,7 @@ Z80_instr_CB_23: +Z80_SLA_REGn REG_E ; Z80_instr_CB_24: +Z80_SLA_REGn REG_H ; SLA H Z80_instr_CB_25: +Z80_SLA_REGn REG_L ; SLA L Z80_instr_CB_27: +Z80_SLA_REGn REG_A ; SLA A +Z80_instr_CB_26: +Z80_SLA_VIA ; SLA (HL) !macro Z80_SLL_REGn .REGn { @@ -228,6 +402,21 @@ Z80_illeg_CB_37: +Z80_SLL_REGn REG_A ; jmp ZVM_next } +!macro Z80_SRL_VIA_HL { + + jsr (VEC_fetch_via_HL) + clc + ror + sta [PTR_DATA],z + + tax + lda z80_ftable_IN_OR_XOR, x + sta REG_F + +bcc ZVM_next + +Z80_PUT_1_CF + jmp ZVM_next +} + Z80_instr_CB_38: +Z80_SRL_REGn REG_B ; SRL B Z80_instr_CB_39: +Z80_SRL_REGn REG_C ; SRL C Z80_instr_CB_3A: +Z80_SRL_REGn REG_D ; SRL D @@ -235,6 +424,7 @@ Z80_instr_CB_3B: +Z80_SRL_REGn REG_E ; Z80_instr_CB_3C: +Z80_SRL_REGn REG_H ; SRL H Z80_instr_CB_3D: +Z80_SRL_REGn REG_L ; SRL L Z80_instr_CB_3F: +Z80_SRL_REGn REG_A ; SRL A +Z80_instr_CB_3E: +Z80_SRL_VIA_HL ; SRL (HL) !macro Z80_SRA_REGn .REGn { @@ -252,12 +442,30 @@ Z80_instr_CB_3F: +Z80_SRL_REGn REG_A ; jmp ZVM_next } -Z80_instr_CB_28: +Z80_SRA_REGn REG_B; SRA B -Z80_instr_CB_29: +Z80_SRA_REGn REG_C; SRA C -Z80_instr_CB_2A: +Z80_SRA_REGn REG_D; SRA D -Z80_instr_CB_2B: +Z80_SRA_REGn REG_E; SRA E -Z80_instr_CB_2C: +Z80_SRA_REGn REG_H; SRA H -Z80_instr_CB_2D: +Z80_SRA_REGn REG_L; SRA L -Z80_instr_CB_2F: +Z80_SRA_REGn REG_A; SRA A +!macro Z80_SRA_VIA_HL { + jsr (VEC_fetch_via_HL) + + tax + ror + txa + + ror + sta [PTR_DATA],z + + tax + lda z80_ftable_IN_OR_XOR, x + sta REG_F + +bcc ZVM_next + +Z80_PUT_1_CF + jmp ZVM_next +} +Z80_instr_CB_28: +Z80_SRA_REGn REG_B ; SRA B +Z80_instr_CB_29: +Z80_SRA_REGn REG_C ; SRA C +Z80_instr_CB_2A: +Z80_SRA_REGn REG_D ; SRA D +Z80_instr_CB_2B: +Z80_SRA_REGn REG_E ; SRA E +Z80_instr_CB_2C: +Z80_SRA_REGn REG_H ; SRA H +Z80_instr_CB_2D: +Z80_SRA_REGn REG_L ; SRA L +Z80_instr_CB_2F: +Z80_SRA_REGn REG_A ; SRA A +Z80_instr_CB_2E: +Z80_SRA_VIA_HL ; SRA (HL) diff --git a/src/zvm_m65/z80_table_gen.s b/src/zvm_m65/z80_table_gen.s index deecff15..c807372c 100644 --- a/src/zvm_m65/z80_table_gen.s +++ b/src/zvm_m65/z80_table_gen.s @@ -1,2 +1,55 @@ -; XXX: move ALL table generation here, for some tables (DAA) use floor/ceiling RAM +; +; Z80 emulator - precalculated data generator +; + +z80_table_gen: + + jsr PRIMM + !pet $0D, "Generating CPU tables... " + !byte 0 + + ; + ; Generating: z80_atable_mi_bank0, z80_atable_hi_bank0 + ; Dependencies: NONE + ; + + ldx #$00 + +@loop_atable_bank0: + + cpx #$E0 + bcs @common_addr + + ; Memory area $0000-$DFFF - maps to $02000-$0FFFF - 56KB + + lda #$04 + sta z80_atable_hi_bank0, x + txa + clc + adc #$20 + sta z80_atable_mi_bank0, x + +@common_addr: + + ; Memory area $E000-$FFFF - maps to $4E000-$4FFFF - 8KB + + lda #$04 + sta z80_atable_hi_bank0, x + txa + sta z80_atable_mi_bank0, x + + inx + bne @loop_atable_bank0 + + ; XXX add more tables here + + ; + ; The END + ; + + jsr PRIMM + !pet "done", $0D, $0D + !byte 0 + + rts diff --git a/src/zvm_m65/z80_tables.s b/src/zvm_m65/z80_tables.s index 76b6127b..b0169eba 100644 --- a/src/zvm_m65/z80_tables.s +++ b/src/zvm_m65/z80_tables.s @@ -34,6 +34,9 @@ z80_ftable_SUB_SBC: z80_ftable_CP: +PUT_Z80_FTABLE_CP +z80_ftable_RRD_RLD: + +PUT_Z80_FTABLE_RRD_RLD + ; ; That horrific DAA instruction ; diff --git a/src/zvm_m65/zvm_banking.s b/src/zvm_m65/zvm_banking.s index 3403d769..4d8bfcab 100644 --- a/src/zvm_m65/zvm_banking.s +++ b/src/zvm_m65/zvm_banking.s @@ -4,18 +4,79 @@ ; +ZVM_bank0_vectab: + + !word ZVM_bank0_fetch_via_PC_inc + ; XXX add remaining routines here + +ZVM_bank1_vectab: + + !word ZVM_bank1_fetch_via_PC_inc + ; XXX add remaining routines here + +; +; Bank switching routines +; + ZVM_set_bank_0: + lda #$00 + sta BANK_ID + ; XXX use DMAgic to switch banks (vectors on zeropage) rts ZVM_set_bank_1: + lda #$01 + sta BANK_ID + ; XXX use DMAgic to switch banks (vectors on zeropage) + lda #$04 ; all the Z80 bank 1 memory is located in $0004:$xxxx + sta PTR_DATA+2 + sta PTR_IXY_d+2 + rts +; +; Memory access routines +; + +ZVM_bank0_fetch_via_PC_inc: + + lda REG_PC+0 + sta PTR_DATA+0 + ldy REG_PC+1 + lda z80_atable_mi_bank0,y + sta PTR_DATA+1 + lda z80_atable_hi_bank0,y + sta PTR_DATA+1 + + lda [PTR_DATA], z + + inw REG_PC + rts + +ZVM_bank1_fetch_via_PC_inc: + + lda [REG_PC], z + + inw REG_PC + rts + + + + + + + + +; XXX cleanup code below + + + ZVM_fetch_IO: ; XXX fetch addresses via ADDR_IO - but which ones are safe? Should we have a whitelist? @@ -27,39 +88,3 @@ ZVM_store_IO: ; XXX again, we should have a whitelist of addresses rts - - - -ZVM_fetch_opcode_bank_0: - - ; XXX implement, should return byte in .A - -ZVM_fetch_opcode_bank_1: - - ; XXX implement, should return byte in .A - -ZVM_fetch_value_bank_0: -ZVM_fetch_value_bank_1: -ZVM_fetch_stack_bank_0: -ZVM_fetch_stack_bank_1: -ZVM_fetch_via_HL_bank_0: -ZVM_fetch_via_HL_bank_1: -ZVM_fetch_via_IX_d_bank_0: -ZVM_fetch_via_IX_d_bank_1: -ZVM_fetch_via_IY_d_bank_0: -ZVM_fetch_via_IY_d_bank_1: -ZVM_fetch_via_nn_bank_0: -ZVM_fetch_via_nn_bank_1: -ZVM_store_stack_bank_0: -ZVM_store_stack_bank_1: -ZVM_store_via_HL_bank_0: -ZVM_store_via_HL_bank_1: -ZVM_store_via_IX_d_bank_0: -ZVM_store_via_IX_d_bank_1: -ZVM_store_via_IY_d_bank_0: -ZVM_store_via_IY_d_bank_1: -ZVM_store_via_nn_bank_0: -ZVM_store_via_nn_bank_1: - - ; XXX - rts \ No newline at end of file diff --git a/src/zvm_m65/zvm_bios.s b/src/zvm_m65/zvm_bios.s index c8d73d83..b11d375b 100644 --- a/src/zvm_m65/zvm_bios.s +++ b/src/zvm_m65/zvm_bios.s @@ -74,6 +74,8 @@ zvm_BIOS_00_BOOT: ; Cold start lda TIME+2 ; give a little initial randomness to register R sta REG_R06 + ; XXX restore all *_EXT1 values + ; XXX load CPM3.SYS ; FALLTROUGH diff --git a/src/zvm_m65/zvm_core.s b/src/zvm_m65/zvm_core.s index e6712f6c..784c1ab9 100644 --- a/src/zvm_m65/zvm_core.s +++ b/src/zvm_m65/zvm_core.s @@ -48,6 +48,19 @@ ZVM_entry: !byte $0D,$0D !byte 0 + ; Initialize constants XXX consider moving this to a dedicated reset CPU routine + + lda #$00 ; all the Z80 memory is located below $0100:$0000 + sta PTR_DATA+3 + sta PTR_IXY_d+3 + + ; Generate CPU tables + + jsr z80_table_gen + + + + ; XXX code is not ready to progress further jsr PRIMM @@ -55,7 +68,7 @@ ZVM_entry: !pet "* Implementation not finished yet - system HALTED *" !byte 0 @1 - bra @1 + bra @1 jmp zvm_BIOS_00_BOOT @@ -69,7 +82,7 @@ ZVM_store_next: ; Fetch and execute next opcode - jsr (VEC_fetch_value) + jsr (VEC_fetch_via_PC_inc) asl tax bcs @1 @@ -130,6 +143,43 @@ Z80_instr_FD: +ZVM_DISPATCH Z80_vectab_FD_0, Z80_vectab_FD_1 ; ; XXX addition and subtraction are slow; pre-calculate data/flag tables in the extended 8MB RAM ; XXX use TRB/TSB instead of LDA + AND/ORA + STA when applicable +; XXX all dispatch routines shall have separate versions for bank 0/1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -150,39 +200,10 @@ Z80_instr_FD: +ZVM_DISPATCH Z80_vectab_FD_0, Z80_vectab_FD_1 ; Z80_instr_DD_CB: ; #DDCB Z80_instr_FD_CB: ; #FDCB -Z80_instr_09: ; ADD HL,BC -Z80_instr_19: ; ADD HL,DE -Z80_instr_29: ; ADD HL,HL -Z80_instr_39: ; ADD HL,SP -Z80_instr_CB_06: ; RLC (HL) -Z80_instr_CB_0E: ; RRC (HL) -Z80_instr_CB_16: ; RL (HL) -Z80_instr_CB_1E: ; RR (HL) -Z80_instr_CB_26: ; SLA (HL) -Z80_instr_CB_2E: ; SRA (HL) -Z80_instr_CB_3E: ; SRL (HL) -Z80_instr_DD_09: ; ADD IX,BC -Z80_instr_DD_19: ; ADD IX,DE -Z80_instr_DD_29: ; ADD IX,IX -Z80_instr_DD_39: ; ADD IX,SP -Z80_instr_ED_42: ; SBC HL,BC -Z80_instr_ED_4A: ; ADC HL,BC -Z80_instr_ED_52: ; SBC HL,DE -Z80_instr_ED_5A: ; ADC HL,DE -Z80_instr_ED_62: ; SBC HL,HL -Z80_instr_ED_67: ; RRD -Z80_instr_ED_6A: ; ADC HL,HL -Z80_instr_ED_6F: ; RLD -Z80_instr_ED_72: ; SBC HL,SP -Z80_instr_ED_7A: ; ADC HL,SP Z80_instr_ED_A1: ; CPI Z80_instr_ED_A9: ; CPD Z80_instr_ED_B1: ; CPIR Z80_instr_ED_B9: ; CPDR -Z80_instr_FD_09: ; ADD IY,BC -Z80_instr_FD_19: ; ADD IY,DE -Z80_instr_FD_29: ; ADD IY,IY -Z80_instr_FD_39: ; ADD IY,SP Z80_instr_xDCB_06: ; RLC (IXY+d) Z80_instr_xDCB_0E: ; RRC (IXY+d) Z80_instr_xDCB_16: ; RL (IXY+d) diff --git a/tools/generate_z80_tables.cc b/tools/generate_z80_tables.cc index 34e4fd8f..b84a53c9 100644 --- a/tools/generate_z80_tables.cc +++ b/tools/generate_z80_tables.cc @@ -257,11 +257,30 @@ std::string generateCpTable(void) std::stringstream outStr; outStr << "!macro PUT_Z80_FTABLE_CP {\n"; + for (uint16_t idx = 0; idx < 0x100; idx++) + { + uint8_t flags = GLOBAL_Parity[idx]; + if (idx >= 0x80) flags |= Z80_SF; // for negative result + if (idx == 0) flags |= Z80_ZF; // for result equal 0 + + outStr << "\t!byte $" << std::hex << std::setw(2) << std::setfill('0') << int(flags) << "\n"; + } + + return outStr.str() + "}\n\n\n"; +} + +std::string generateRrdRldTable(void) +{ + std::stringstream outStr; + outStr << "!macro PUT_Z80_FTABLE_RRD_RLD {\n"; + for (uint16_t idx = 0; idx < 0x100; idx++) { uint8_t flags = Z80_NF; if (idx >= 0x80) flags |= Z80_SF; // for negative result if (idx == 0) flags |= Z80_ZF; // for result equal 0 + if (idx & 0x08) flags |= Z80_XF; // 3rd bit of the result + if (idx & 0x20) flags |= Z80_YF; // 5th bit of the result outStr << "\t!byte $" << std::hex << std::setw(2) << std::setfill('0') << int(flags) << "\n"; } @@ -415,6 +434,7 @@ void writeTables() outFile << generateAddAdcTable(); outFile << generateSubSbcTable(); outFile << generateCpTable(); + outFile << generateRrdRldTable(); outFile << generateNegTable(); outFile << generateDaaTables();