; 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.
;
.dseg
-
+z_regs:
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
-
+
;Init z80
z80_init:
ldi z_pcl,low (IPLADDR)
printnewline
printstring "PC="
movw temp,z_pcl
- rcall printhexw
+ lcall printhexw
printstring " "
noprintpc:
.endif
;
; instr fetch, op, store
;
-.macro instr
+.macro instr
.ifndef opcjmp_table_pos_
.set todo_table_pos_ = PC
; Place the opcode jump table on the next available location.
.equ opcjmp = (PC+255) & 0xff00
.set opcjmp_table_pos_ = opcjmp
.endif
-
+
.if todo_table_pos_ < opcjmp + 256 + 128
.if todo_table_pos_ + 3 >= opcjmp
.set todo_table_pos_ = opcjmp + 256 + 128
.endif
.if cnt_ == 1 ; jump direct to action
- .if fetch_ ;
- rjmp @0 ;
- .endif
+ .if fetch_ ;
+ rjmp @0 ;
+ .endif
.if op_
rjmp do_@1 ; do op and return to main
- .endif
- .if store_ ;
- rjmp @2 ;
- .endif
+ .endif
+ .if store_ ;
+ rjmp @2 ;
+ .endif
.endif
; two or tree actions
.if fetch_ ; must fetch
.if op_ || store_
rcall @0 ; fetch and come back here
- .else ;
+ .else ;
rjmp @0 ; fetch and return to main
.endif
.endif
.endif
.if store_ ; must store
rjmp @2 ; store is allways last
- .endif
-
+ .endif
+
.set todo_table_pos_ = PC
.endif
.endm
-
+
; ------------ Fetch phase stuff -----------------
;.org (PC+255) & 0xff00
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
;|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:
do_op_da:
#if EM_Z80
- sbrc z_flags,ZFL_N ;if add-op
+ sbrc z_flags,ZFL_N ;if add-op
rjmp op_da_sub ;then
#endif
brlo op_da_a10 ; |
op_da_a01: ; then
ldi oph,0x06 ; add 6 to lower nibble
- add opl,oph ;
- brhc op_da_02 ; if
+ 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
sbrc z_flags,ZFL_C ; |
rjmp op_da_a12 ; if (C flag ...
cpi opl,0xA0 ; |... or upper nibble >= 0xA0)
- brlo op_da_a13 ;
+ brlo op_da_a13 ;
op_da_a12: ;
ldi oph,0x60 ; add 6 to lower nibble
add opl,oph ;
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:
;|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
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_L, op_nop, do_store_MHL ;75 ;LD (HL),L
instr do_fetch_nop, op_INV, do_store_nop ;76 ;HALT
instr do_fetch_A, op_nop, do_store_MHL ;77 ;LD (HL),A
-instr do_fetch_b, op_nop, do_store_A ;78 ;LD A,B
+instr do_fetch_B, op_nop, do_store_A ;78 ;LD A,B
instr do_fetch_C, op_nop, do_store_A ;79 ;LD A,C
instr do_fetch_D, op_nop, do_store_A ;7A ;LD A,D
instr do_fetch_E, op_nop, do_store_A ;7B ;LD A,E
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
.org opcjmp + 256
.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