; 8080 Interpreter.
; This is part of the Z80-CP/M emulator written by Sprite_tm.
-;
+;
; Copyright (C) 2010 Sprite_tm
; Copyright (C) 2010 Leo C.
;
; instr fetch, op, store
;
-.macro instr
+.macro instr
.db low(@2), low(do_@1), high(do_@1), low(@0)
.endm
.dseg
-
+
z_b: .byte 1
z_c: .byte 1
z_d: .byte 1
z_h: .byte 1
z_l: .byte 1
+ .equ oz_b = 0
+ .equ oz_c = 1
+ .equ oz_d = 2
+ .equ oz_e = 3
+ .equ oz_h = 4
+ .equ oz_l = 5
+
+
+#if EM_Z80
+z_b2: .byte 1
+z_c2: .byte 1
+z_d2: .byte 1
+z_e2: .byte 1
+z_h2: .byte 1
+z_l2: .byte 1
+z_f2: .byte 1
+z_a2: .byte 1
+ .equ r2ofs = z_b2-z_b
+ .equ oz_b2 = 6
+ .equ oz_c2 = 7
+ .equ oz_d2 = 8
+ .equ oz_e2 = 9
+ .equ oz_h2 = 10
+ .equ oz_l2 = 11
+ .equ oz_f2 = 12
+ .equ oz_a2 = 13
+
+z_xh: .byte 1
+z_xl: .byte 1
+z_yh: .byte 1
+z_yl: .byte 1
+
+z_i: .byte 1
+z_r: .byte 1
+ .equ oz_xh = 14
+ .equ oz_xl = 15
+ .equ oz_yh = 16
+ .equ oz_yl = 17
+ .equ oz_i = 18
+ .equ oz_r = 19
+
+z_istat: .byte 1
+ .equ oz_istat = 20
+
+ .equ IM_MASK = 0x03 ;Mask IM 0..2
+ .equ IM0 = 0
+ .equ IM1 = 1
+ .equ IM2 = 2
+
+ .equ IFF1 = 2 ;IFF1 Flag
+ .equ IFF2 = 3 ;IFF2 Flag
+
+#endif
.cseg
notraceon:
.endif
-
.if PRINT_PC
cpi z_pch,DBG_TRACE_BOTTOM
brlo noprintpc
printnewline
printstring "PC="
movw temp,z_pcl
- rcall printhexw
+ lcall printhexw
printstring " "
noprintpc:
.endif
.endif
;hier kommt die Interruptbehandlung rein
-
+
ldi zl,low(main) ;da will ich wieder hin.
ldi zh,high(main) ;
push zl ;
add zl,r0 ;1
adc zh,r1 ;1
ldi temp2,high(store_ops) ;
- lpm temp,Z+ ;do_store
+ lpm temp,Z+ ;do_store
push temp ; low
push temp2 ; high
- lpm temp,Z+ ;do_op
+ lpm temp,Z+ ;do_op
push temp ; low
lpm temp,Z+ ; high
push temp ;
lpm zl,Z ;do_fetch
-
+
;mov zh,temp2 ;
ldi zh,high(fetch_ops)
ijmp ;direkt
.org (PC+255) & 0xff00 ; wichtig !!!fetch und store muessen in einer page liegen
fetch_ops:
-do_fetch_nop:
+do_fetch_nop:
ret
do_fetch_a:
store_ops:
do_store_nop:
ret
-
+
do_store_a:
mov z_a,opl
ret
ret
-
; ------------ Operation phase stuff -----------------
;----------------------------------------------------------------
;|ADC A,s |***V0*|Add with Carry |A=A+s+CY |
;|ADC HL,ss |**?V0*|Add with Carry |HL=HL+ss+CY |
;|ADD A,s |***V0*|Add |A=A+s |
-;|ADD HL,ss |--?-0*|Add |HL=HL+ss |
-;|ADD IX,pp |--?-0*|Add |IX=IX+pp |
-;|ADD IY,rr |--?-0*|Add |IY=IY+rr |
+;|ADD HL,ss |--*-0*|Add |HL=HL+ss |
+;|ADD IX,pp |--*-0*|Add |IX=IX+pp |
+;|ADD IY,rr |--*-0*|Add |IY=IY+rr |
;|AND s |**1P00|Logical AND |A=A&s |
;|BIT b,m |?*1?0-|Test Bit |m&{2^b} |
;|CALL cc,nn|------|Conditional Call |If cc CALL |
;|DEC s |***V1-|Decrement |s=s-1 |
;|DEC xx |------|Decrement |xx=xx-1 |
;|DEC ss |------|Decrement |ss=ss-1 |
-;|DI |------|Disable Interrupts | |
+;|DI |------|Disable Interrupts |IFF1 = IFF2 = 0 |
;|DJNZ e |------|Dec., Jump Non-Zero |B=B-1 till B=0 |
-;|EI |------|Enable Interrupts | |
+;|EI |------|Enable Interrupts |IFF1 = IFF2 = 1 |
;|EX [SP],HL|------|Exchange |[SP]<->HL |
;|EX [SP],xx|------|Exchange |[SP]<->xx |
;|EX AF,AF' |------|Exchange |AF<->AF' |
;|RRD |**0P0-|Rotate Right 4 bits |{A,[HL]}=->{A,[HL]} ##|
;|RST p |------|Restart | (p=0H,8H,10H,...,38H)|
;|SBC A,s |***V1*|Subtract with Carry |A=A-s-CY |
-;|SBC HL,ss |**?V1*|Subtract with Carry |HL=HL-ss-CY |
+;|SBC HL,ss |***V1*|Subtract with Carry |HL=HL-ss-CY |
;|SCF |--0-01|Set Carry Flag |CY=1 |
;|SET b,m |------|Set bit |m=mv{2^b} |
;|SLA m |**0P0*|Shift Left Arithmetic|m=m*2 |
.equ ZFL_N = 1
.equ ZFL_C = 0
-
.equ AVR_T = SREG_T
.equ AVR_H = SREG_H
.equ AVR_S = SREG_S
.macro ldpmx
ldi zh,high(@1*2) ; table must be page aligned
- mov zl,@2
- lpm @0,z
+ mov zl,@2
+ lpm @0,z
.endm
.macro do_z80_flags_V
#endif
.endm
+.macro do_z80_flags_H
+#if EM_Z80
+ bmov z_flags, ZFL_H, temp, AVR_H
+#endif
+.endm
+
.macro do_z80_flags_set_N
#if EM_Z80
ori z_flags, (1<<ZFL_N) ; Negation auf 1
#endif
.endm
-
+
.macro do_z80_flags_copy_HC
#if EM_Z80
bmov z_flags, ZFL_H, z_flags, ZFL_H
do_op_nop:
ret
-
+
;----------------------------------------------------------------
;|Mnemonic |SZHPNC|Description |Notes |
;----------------------------------------------------------------
printnewline
printstring "Port write: "
mov temp,z_a
- rcall printhex
+ lcall printhex
printstring " -> ("
mov temp,opl
- rcall printhex
+ lcall printhex
printstring ") "
.endif
mov temp,z_a
;|IN A,[n] |------|Input |A=[n] |
;
;
-do_op_in: ; in a,(opl)
+do_op_ina: ; in a,(opl)
.if PORT_DEBUG
printnewline
printstring "Port read: ("
mov temp,opl
- rcall printhex
+ lcall printhex
printstring ") -> "
.endif
mov temp2,opl
lcall portRead
- mov opl,temp
+ mov z_a,temp
.if PORT_DEBUG
- rcall printhex
+ lcall printhex
printstring " "
.endif
ret
;|INC r |**-P0-|Increment |r=r+1 |
;|INC [HL] |**-P0-|Increment |[HL]=[HL]+1 |
;
-;
+;
do_op_inc:
ldi temp,1
add opl,temp
;|INC xx |------|Increment |xx=xx+1 |
;|INC ss |------|Increment |ss=ss+1 |
;
-;
+;
do_op_inc16:
subi opl,low(-1)
sbci oph,high(-1)
;|DEC xx |------|Decrement |xx=xx-1 |
;|DEC ss |------|Decrement |ss=ss-1 |
;
-;
+;
do_op_dec16:
subi opl, 1
sbci oph, 0
;
;
do_op_rlca:
- ;Rotate Left Cyclical. All bits move 1 to the
+ ;Rotate Left Cyclical. All bits move 1 to the
;left, the msb becomes c and lsb.
do_z80_flags_op_rotate
lsl z_a
;|RRCA |---- *|Rotate Right Circular|A=->A |
;
;
-do_op_rrca:
- ;Rotate Right Cyclical. All bits move 1 to the
+do_op_rrca:
+ ;Rotate Right Cyclical. All bits move 1 to the
;right, the lsb becomes c and msb.
do_z80_flags_op_rotate
lsr z_a
;|----------|SZHP C|---------- 8080 ----------------------------|
;|RRA |---- *|Rotate Right Acc. |A=->{CY,A} |
;
-;
-do_op_rra:
- ;Rotate Right. All bits move 1 to the right, the lsb
+;
+do_op_rra:
+ ;Rotate Right. All bits move 1 to the right, the lsb
;becomes c, c becomes msb.
clc ; get z80 carry to avr carry
sbrc z_flags,ZFL_C
;|----------|SZHP C|---------- 8080 ----------------------------|
;|RLA |---- *|Rotate Left Acc. |A={CY,A}<- |
;
-;
+;
do_op_rla:
- ;Rotate Left. All bits move 1 to the left, the msb
+ ;Rotate Left. All bits move 1 to the left, the msb
;becomes c, c becomes lsb.
clc
sbrc z_flags,ZFL_C
lds temp2,z_h
add opl,temp
adc oph,temp2
+ sts z_l,opl
+ sts z_h,oph
in temp,sreg
- bmov z_flags,ZFL_H, temp,AVR_H
bmov z_flags,ZFL_C, temp,AVR_C
+ do_z80_flags_H
do_z80_flags_clear_N
ret
;----------------------------------------------------------------
;|LD dst,src|------|Load |dst=src |
;
-;
+;
do_op_rmem16:
movw xl,opl
mem_read_d opl
;
; ---------------------
; | N | H | low |H' |
-; | | |nibble | |
+; | | |nibble | |
; |---+---+-------+---|
-; | 0 | * | 0-9 | 0 |
-; | 0 | * | a-f | 1 |
-; | 1 | 0 | * | 0 |
-; | 1 | 1 | 6-f | 0 |
-; | 1 | 1 | 0-5 | 1 |
+; | 0 | * | 0-9 | 0 |
+; | 0 | * | a-f | 1 |
+; | 1 | 0 | * | 0 |
+; | 1 | 1 | 6-f | 0 |
+; | 1 | 1 | 0-5 | 1 |
; ---------------------
;
; Ohter flags:
; Z: Set if Acc. is Zero after operation, reset otherwise.
; S: Set if most significant bit of Acc. is 1 after operation, reset otherwise.
+#if 1
+
+do_op_da:
+
+#if EM_Z80
+ sbrc z_flags,ZFL_N ;if add-op
+ rjmp op_da_sub ;then
+#endif
+
+op_da_add:
+ ldi temp2,0 ; new C and H flag
+ sbrc z_flags,ZFL_H ; |
+ rjmp op_da_a01 ; if (H flag ...
+ mov temp,opl ; |
+ andi temp,0x0f ; |
+ cpi temp,0x0a ; or (lower nibble >= 0x0A))
+ brlo op_da_a10 ; |
+op_da_a01: ; then
+ ldi oph,0x06 ; add 6 to lower nibble
+ add opl,oph ;
+ brhc op_da_02 ; if
+ ori temp2,(1<<ZFL_H) ; set new H flag
+op_da_02: ;
+ brcc op_da_a10 ; if
+ ori temp2,(1<<ZFL_C) ; set new H flag
+op_da_a10: ; endif
+ sbrc z_flags,ZFL_C ; |
+ rjmp op_da_a12 ; if (C flag ...
+ cpi opl,0xA0 ; |... or upper nibble >= 0xA0)
+ brlo op_da_a13 ;
+op_da_a12: ;
+ ldi oph,0x60 ; add 6 to lower nibble
+ add opl,oph ;
+ ori temp2,(1<<ZFL_C) ; set new C flag
+op_da_a13: ;
+ ldpmx z_flags, sz53p_tab, opl ; get S,Z,P flag
+ or z_flags,temp2 ; merge new C and H flag
+ ret
+
+#if EM_Z80
+
+op_da_sub: ;else (sub-op)
+ rcall do_op_inv ; TODO: !
+ ret ;endif
+#endif
+
+#else
do_op_da:
ldi temp2,0 ;new C and H flag
ldi oph,0 ;oph: what to add
- sbrc z_flags,ZFL_N ;if add-op
+ sbrc z_flags,ZFL_N ;if add-op
rjmp op_da_sub ;then
op_da_add:
mov temp,opl ; |
rjmp op_da_a02 ; if (C flag ...
cpi opl,0x90 ; |... or upper nibble >= 0x90)
brlo op_da_a03 ; |
-op_da_a02:
+op_da_a02:
ori oph,0x60 ; add 0x60
ori temp2,(1<<ZFL_C) ; set new C flag
op_da_a03: ; endif
sbrc z_flags,ZFL_C ; |
rjmp op_da_a12 ; if (C flag ...
cpi opl,0xA0 ; |... or upper nibble >= 0xA0)
- brlo op_da_a13 ;
-op_da_a12:
+ brlo op_da_a13 ;
+op_da_a12:
ori oph,0x60 ; add 0x60
ori temp2,(1<<ZFL_C) ; set new C flag
op_da_a13:
ldpmx z_flags, sz53p_tab, opl ; get S,Z,P flag
or z_flags,temp2 ; merge new C and H flag
ret
-
+
op_da_sub: ;else (sub-op)
rcall do_op_inv ; TODO: !
ret ;endif
-
+#endif
;----------------------------------------------------------------
;|EX [SP],HL|------|Exchange |[SP]<->HL |
;|EX DE,HL |------|Exchange |DE<->HL |
;-----------------------------Z80--------------------------------
-;
+;
do_op_exhl:
lds temp,z_l
lds temp2,z_h
sbrs z_flags, ZFL_Z
ret
pop temp ; nix tun
- pop temp ; direkt zuruech zu main
+ pop temp ; direkt zurueck zu main
ret
;----------------------------------------------------------------
sbrc z_flags, ZFL_Z
ret
pop temp ; nix tun
- pop temp ; direkt zuruech zu main
+ pop temp ; direkt zurueck zu main
ret
;----------------------------------------------------------------
sbrs z_flags, ZFL_C
ret
pop temp ; nix tun
- pop temp ; direkt zuruech zu main
+ pop temp ; direkt zuruech zu main
ret
;----------------------------------------------------------------
sbrc z_flags, ZFL_C
ret
pop temp ; nix tun
- pop temp ; direkt zuruech zu main
+ pop temp ; direkt zuruech zu main
ret
;----------------------------------------------------------------
sbrs z_flags, ZFL_P
ret
pop temp ; nix tun
- pop temp ; direkt zuruech zu main
+ pop temp ; direkt zuruech zu main
ret
;----------------------------------------------------------------
sbrc z_flags, ZFL_P
ret
pop temp ; nix tun
- pop temp ; direkt zuruech zu main
+ pop temp ; direkt zuruech zu main
ret
;----------------------------------------------------------------
sbrs z_flags, ZFL_S
ret
pop temp ; nix tun
- pop temp ; direkt zuruech zu main
+ pop temp ; direkt zuruech zu main
ret
;----------------------------------------------------------------
sbrc z_flags, ZFL_S
ret
pop temp ; nix tun
- pop temp ; direkt zuruech zu main
+ pop temp ; direkt zuruech zu main
ret
-
+
; ----------------------- Opcode decoding -------------------------
; Lookup table for Z80 opcodes. Translates the first byte of the instruction word into three
; operations: fetch, do something, store.
-; The table is made of 256 words.
+; The table is made of 256 words.
;.org (PC+255) & 0xff00
todo_table:
instr do_fetch_DIR8, op_nop, do_store_B ;06 ;LD B,n
instr do_fetch_nop, op_RLCA, do_store_nop ;07 ;RLCA
instr do_fetch_nop, op_INV, do_store_nop ;08 ;EX AF,AF'
-instr do_fetch_BC, op_ADDHL, do_store_HL ;09 ;ADD HL,BC
+instr do_fetch_BC, op_ADDHL, do_store_nop ;09 ;ADD HL,BC
instr do_fetch_MBC, op_nop, do_store_nop ;0A ;LD A,(BC)
instr do_fetch_BC, op_DEC16, do_store_BC ;0B ;DEC BC
instr do_fetch_C, op_INC, do_store_C ;0C ;INC C
instr do_fetch_DIR8, op_nop, do_store_D ;16 nn ;LD D,n
instr do_fetch_nop, op_RLA, do_store_nop ;17 ;RLA
instr do_fetch_nop, op_INV, do_store_nop ;18 oo ;JR o
-instr do_fetch_DE, op_ADDHL, do_store_HL ;19 ;ADD HL,DE
+instr do_fetch_DE, op_ADDHL, do_store_nop ;19 ;ADD HL,DE
instr do_fetch_MDE, op_nop, do_store_nop ;1A ;LD A,(DE)
instr do_fetch_DE, op_DEC16, do_store_DE ;1B ;DEC DE
instr do_fetch_E, op_INC, do_store_E ;1C ;INC E
instr do_fetch_DIR8, op_nop, do_store_H ;26 nn ;LD H,n
instr do_fetch_A, op_DA, do_store_A ;27 ;DAA
instr do_fetch_nop, op_INV, do_store_nop ;28 oo ;JR Z,o
-instr do_fetch_HL, op_ADDHL, do_store_HL ;29 ;ADD HL,HL
+instr do_fetch_HL, op_ADDHL, do_store_nop ;29 ;ADD HL,HL
instr do_fetch_DIR16, op_RMEM16, do_store_HL ;2A nn nn ;LD HL,(nn)
instr do_fetch_HL, op_DEC16, do_store_HL ;2B ;DEC HL
instr do_fetch_L, op_INC, do_store_L ;2C ;INC L
instr do_fetch_DIR8, op_nop, do_store_MHL ;36 nn ;LD (HL),n
instr do_fetch_nop, op_SCF, do_store_nop ;37 ;SCF
instr do_fetch_nop, op_INV, do_store_nop ;38 oo ;JR C,o
-instr do_fetch_SP, op_ADDHL, do_store_HL ;39 ;ADD HL,SP
+instr do_fetch_SP, op_ADDHL, do_store_nop ;39 ;ADD HL,SP
instr do_fetch_DIR16, op_RMEM8, do_store_A ;3A nn nn ;LD A,(nn)
instr do_fetch_SP, op_DEC16, do_store_SP ;3B ;DEC SP
instr do_fetch_nop, op_INCA, do_store_nop ;3C ;INC A
instr do_fetch_nop, op_IFC, do_store_RET ;D8 ;RET C
instr do_fetch_nop, op_nop, do_store_nop ;D9 ;EXX
instr do_fetch_DIR16, op_IFC, do_store_PC ;DA nn nn ;JP C,nn
-instr do_fetch_DIR8, op_IN, do_store_A ;DB nn ;IN A,(n)
+instr do_fetch_DIR8, op_INA, do_store_nop ;DB nn ;IN A,(n)
instr do_fetch_DIR16, op_IFC, do_store_CALL ;DC nn nn ;CALL C,nn
instr do_fetch_nop, op_INV, do_store_nop ;DD ;(Z80 specific)
instr do_fetch_DIR8, op_SBCFA, do_store_nop ;DE nn ;SBC A,n
; Lookup table, stolen from z80ex, Z80 emulation library.
; http://z80ex.sourceforge.net/
-; The S, Z, 5 and 3 bits and the parity of the lookup value
+; The S, Z, 5 and 3 bits and the parity of the lookup value
.org (PC+255) & 0xff00
sz53p_tab:
.db 0xac,0xa8,0xa8,0xac,0xa8,0xac,0xac,0xa8
.db 0xa4,0xa0,0xa0,0xa4,0xa0,0xa4,0xa4,0xa0
.db 0xa8,0xac,0xac,0xa8,0xac,0xa8,0xa8,0xac
-
-; vim:set ts=8 noet nowrap
+; vim:set ts=8 noet nowrap