more work on Z80 support

This commit is contained in:
FeralChild64 committed 2020-12-30 18:08:31 +01:00
1 parent 3054a44e7c
commit 76f25a36e2
16 files changed
+763 -201

No files matched your search

+110 -60
View File
@@ -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
-1
View File
@@ -3,7 +3,6 @@
; Z80 bit set/reset/test instructions
;
; bits 0, 1, 4, 6
Z80_instr_CB_40: ; BIT 0,B
+2 -2
View File
@@ -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
+2 -2
View File
@@ -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
+3 -3
View File
@@ -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
+2 -2
View File
@@ -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
}
+2 -2
View File
@@ -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
+227 -46
View File
@@ -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
+8 -8
View File
@@ -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
}
+215 -7
View File
@@ -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)
+54 -1
View File
@@ -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
+3
View File
@@ -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
;
+61 -36
View File
@@ -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
+2
View File
@@ -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
+52 -31
View File
@@ -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)
+20
View File
@@ -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();