--- /dev/null
+; 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.
+; Copyright (C) 2010 Horst S.
+
+; This file is part of avrcpm.
+;
+; avrcpm is free software: you can redistribute it and/or modify it
+; under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; avrcpm is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with avrcpm. If not, see <http://www.gnu.org/licenses/>.
+;
+; $Id$
+;
+
+ .dseg
+
+z_b: .byte 1
+z_c: .byte 1
+z_d: .byte 1
+z_e: .byte 1
+z_h: .byte 1
+z_l: .byte 1
+
+
+ .cseg
+
+;Init z80
+z80_init:
+ ldi z_pcl,low (IPLADDR)
+ ldi z_pch,high(IPLADDR)
+
+ cbi flags,trace
+ printnewline
+ printstring "Ok, CPU is live!"
+ printnewline
+
+main:
+.if INS_DEBUG
+ cbi flags,trace
+ cpi z_pch,DBG_TRACE_BOTTOM
+ brlo notraceon
+ cpi z_pch,DBG_TRACE_TOP
+ brsh notraceon
+ sbi flags,trace
+notraceon:
+.endif
+
+
+.if PRINT_PC
+ cpi z_pch,DBG_TRACE_BOTTOM
+ brlo noprintpc
+ cpi z_pch,DBG_TRACE_TOP
+ brsh noprintpc
+
+ printnewline
+ printstring "PC="
+ movw temp,z_pcl
+ rcall printhexw
+ printstring " "
+noprintpc:
+.endif
+
+.if INS_DEBUG
+ sbic flags,trace
+ rcall printregs
+.endif
+ ;hier kommt die Interruptbehandlung rein
+
+
+ mem_read_ds zl,z_pc ;zl = memReadByte(z_pc)
+ adiw z_pcl,1 ;++z_pc
+ ldi zh,high(opcjmp) ;
+ icall
+ rjmp main ;
+
+
+
+; .listmac
+
+;--------------------------------------------------
+; Generate a table entry for one instruction
+;
+; instr fetch, op, store
+;
+.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
+ .endif
+ .set do_@0_@1_@2 = todo_table_pos_ ; make a label
+
+ .org opcjmp_table_pos_
+ rjmp do_@0_@1_@2 ; generate a jump to the label
+ .set opcjmp_table_pos_ = PC
+
+ .org do_@0_@1_@2
+
+ .set fetch_ = (@0 != do_fetch_nop) ; must call or jump to fetch phase
+ .set op_ = (do_@1 != do_op_nop) ; must call or jump to op phase
+ .set store_ = (@2 != do_store_nop) ; must jump to store phase
+
+ .if fetch_ || op_ || store_ ; something to do
+ .if fetch_ ; must fetch
+ .if op_ || store_
+ rcall @0 ; fetch and come back here
+ .else ;
+ rjmp @0 ; fetch and return to main
+ .endif
+ .endif
+ .if op_ ; must exec op
+ .if store_
+ rcall do_@1 ; do op and come back here
+ .else
+ rjmp do_@1 ; do op and return to main
+ .endif
+ .endif
+ .if store_ ; must store
+ rjmp @2 ; store is allways last
+ .endif
+ .else
+ ret ; nop, go back to main
+ .endif
+
+ .set todo_table_pos_ = PC
+.endm
+
+
+; ------------ Fetch phase stuff -----------------
+
+;.org (PC+255) & 0xff00
+fetch_ops:
+do_fetch_nop:
+ ret
+
+do_fetch_a:
+ mov opl,z_a
+ ret
+
+do_fetch_b:
+ lds opl,z_b
+ ret
+
+do_fetch_c:
+ lds opl,z_c
+ ret
+
+do_fetch_d:
+ lds opl,z_d
+ ret
+
+do_fetch_e:
+ lds opl,z_e
+ ret
+
+do_fetch_h:
+ lds opl,z_h
+ ret
+
+do_fetch_l:
+ lds opl,z_l
+ ret
+
+do_fetch_af:
+ mov opl,z_flags
+ mov oph,z_a
+ ret
+
+do_fetch_bc:
+ lds opl,z_c
+ lds oph,z_b
+ ret
+
+do_fetch_de:
+ lds opl,z_e
+ lds oph,z_d
+ ret
+
+do_fetch_hl:
+ lds opl,z_l
+ lds oph,z_h
+ ret
+
+do_fetch_sp:
+ movw opl,z_spl
+ ret
+
+do_fetch_mbc:
+ lds xh,z_b
+ lds xl,z_c
+ mem_read_d opl
+ ret
+
+do_fetch_mde:
+ lds xh,z_d
+ lds xl,z_e
+ mem_read_d opl
+ ret
+
+do_fetch_mhl:
+ lds xh,z_h
+ lds xl,z_l
+ mem_read_d opl
+ ret
+
+do_fetch_msp:
+ movw x,z_spl
+ mem_read_d opl
+ adiw x,1
+ mem_read_d oph
+ ret
+
+do_fetch_dir8:
+ mem_read_ds opl, z_pc
+ adiw z_pcl,1
+ ret
+
+do_fetch_dir16:
+ mem_read_ds opl, z_pc
+ adiw z_pcl,1
+ mem_read_ds oph, z_pc
+ adiw z_pcl,1
+ ret
+
+do_fetch_rst:
+ movw x,z_pcl
+ sbiw x,1
+ mem_read_d opl
+ andi opl,0x38
+ ldi oph,0
+ ret
+
+; ------------ Store phase stuff -----------------
+
+;.org (PC+255) & 0xff00
+store_ops:
+do_store_nop:
+ ret
+
+do_store_a:
+ mov z_a,opl
+ ret
+
+do_store_b:
+ sts z_b,opl
+ ret
+
+do_store_c:
+ sts z_c,opl
+ ret
+
+do_store_d:
+ sts z_d,opl
+ ret
+
+do_store_e:
+ sts z_e,opl
+ ret
+
+do_store_h:
+ sts z_h,opl
+ ret
+
+do_store_l:
+ sts z_l,opl
+ ret
+
+do_store_af:
+ mov z_a,oph
+ mov z_flags,opl
+ ret
+
+do_store_bc:
+ sts z_b,oph
+ sts z_c,opl
+ ret
+
+do_store_de:
+ sts z_d,oph
+ sts z_e,opl
+ ret
+
+do_store_hl:
+ sts z_h,oph
+ sts z_l,opl
+ ret
+
+do_store_mbc:
+ lds xh,z_b
+ lds xl,z_c
+ mem_write_s opl
+ ret
+
+do_store_mde:
+ lds xh,z_d
+ lds xl,z_e
+ mem_write_s opl
+ ret
+
+do_store_mhl:
+ lds xh,z_h
+ lds xl,z_l
+ mem_write_s opl
+ ret
+
+do_store_msp:
+ movw xl,z_spl
+ mem_write_s opl
+ adiw xl,1
+ mem_write_s oph
+ ret
+
+do_store_sp:
+ movw z_spl,opl
+ ret
+
+do_store_pc:
+ movw z_pcl,opl
+ ret
+
+do_store_ret:
+ movw x,z_spl
+ mem_read_d z_pcl
+ adiw x,1
+ mem_read_d z_pch
+ adiw x,1
+ movw z_spl,x
+
+.if STACK_DBG
+ printnewline
+ printstring "Stack pop "
+ movw temp,z_pcl
+ rcall printhexw
+ printstring ", SP is now "
+ movw temp,z_spl
+ rcall printhexw
+ printstring ". "
+.endif
+ ret
+
+do_store_call:
+ movw xl,z_spl
+ sbiw x,1
+ mem_write_s z_pch
+ sbiw x,1
+ mem_write_s z_pcl
+ movw z_spl,xl
+
+.if STACK_DBG
+ printnewline
+ printstring "Stack push "
+ movw temp,z_pcl
+ rcall printhexw
+ printstring ", SP is now "
+ movw temp,z_spl
+ rcall printhexw
+ printstring ". "
+.endif
+ movw z_pcl,opl
+ ret
+
+
+do_store_am:
+ mem_write_ds op, z_a
+ ret
+
+
+
+
+; ------------ Operation phase stuff -----------------
+
+;----------------------------------------------------------------
+;| |
+;| Zilog |
+;| |
+;| ZZZZZZZ 88888 000 |
+;| Z 8 8 0 0 |
+;| Z 8 8 0 0 0 |
+;| Z 88888 0 0 0 |
+;| Z 8 8 0 0 0 |
+;| Z 8 8 0 0 |
+;| ZZZZZZZ 88888 000 |
+;| |
+;| Z80 MICROPROCESSOR Instruction Set Summary |
+;| |
+;----------------------------------------------------------------
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;|----------+------+---------------------+----------------------|
+;|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 |
+;|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 |
+;|CALL nn |------|Unconditional Call |-[SP]=PC,PC=nn |
+;|CCF |--?-0*|Complement Carry Flag|CY=~CY |
+;|CP s |***V1*|Compare |A-s |
+;|CPD |****1-|Compare and Decrement|A-[HL],HL=HL-1,BC=BC-1|
+;|CPDR |****1-|Compare, Dec., Repeat|CPD till A=[HL]or BC=0|
+;|CPI |****1-|Compare and Increment|A-[HL],HL=HL+1,BC=BC-1|
+;|CPIR |****1-|Compare, Inc., Repeat|CPI till A=[HL]or BC=0|
+;|CPL |--1-1-|Complement |A=~A |
+;|DAA |***P-*|Decimal Adjust Acc. |A=BCD format |
+;|DEC s |***V1-|Decrement |s=s-1 |
+;|DEC xx |------|Decrement |xx=xx-1 |
+;|DEC ss |------|Decrement |ss=ss-1 |
+;|DI |------|Disable Interrupts | |
+;|DJNZ e |------|Dec., Jump Non-Zero |B=B-1 till B=0 |
+;|EI |------|Enable Interrupts | |
+;|EX [SP],HL|------|Exchange |[SP]<->HL |
+;|EX [SP],xx|------|Exchange |[SP]<->xx |
+;|EX AF,AF' |------|Exchange |AF<->AF' |
+;|EX DE,HL |------|Exchange |DE<->HL |
+;|EXX |------|Exchange |qq<->qq' (except AF)|
+;|HALT |------|Halt | |
+;|IM n |------|Interrupt Mode | (n=0,1,2)|
+;|IN A,[n] |------|Input |A=[n] |
+;|IN r,[C] |***P0-|Input |r=[C] |
+;|INC r |***V0-|Increment |r=r+1 |
+;|INC [HL] |***V0-|Increment |[HL]=[HL]+1 |
+;|INC xx |------|Increment |xx=xx+1 |
+;|INC [xx+d]|***V0-|Increment |[xx+d]=[xx+d]+1 |
+;|INC ss |------|Increment |ss=ss+1 |
+;|IND |?*??1-|Input and Decrement |[HL]=[C],HL=HL-1,B=B-1|
+;|INDR |?1??1-|Input, Dec., Repeat |IND till B=0 |
+;|INI |?*??1-|Input and Increment |[HL]=[C],HL=HL+1,B=B-1|
+;|INIR |?1??1-|Input, Inc., Repeat |INI till B=0 |
+;|JP [HL] |------|Unconditional Jump |PC=[HL] |
+;|JP [xx] |------|Unconditional Jump |PC=[xx] |
+;|JP nn |------|Unconditional Jump |PC=nn |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|JR e |------|Unconditional Jump |PC=PC+e |
+;|JR cc,e |------|Conditional Jump |If cc JR(cc=C,NC,NZ,Z)|
+;|LD dst,src|------|Load |dst=src |
+;|LD A,i |**0*0-|Load |A=i (i=I,R)|
+;|LDD |--0*0-|Load and Decrement |[DE]=[HL],HL=HL-1,# |
+;|LDDR |--000-|Load, Dec., Repeat |LDD till BC=0 |
+;|LDI |--0*0-|Load and Increment |[DE]=[HL],HL=HL+1,# |
+;|LDIR |--000-|Load, Inc., Repeat |LDI till BC=0 |
+;|NEG |***V1*|Negate |A=-A |
+;|NOP |------|No Operation | |
+;|OR s |**0P00|Logical inclusive OR |A=Avs |
+;|OTDR |?1??1-|Output, Dec., Repeat |OUTD till B=0 |
+;|OTIR |?1??1-|Output, Inc., Repeat |OUTI till B=0 |
+;|OUT [C],r |------|Output |[C]=r |
+;|OUT [n],A |------|Output |[n]=A |
+;|OUTD |?*??1-|Output and Decrement |[C]=[HL],HL=HL-1,B=B-1|
+;|OUTI |?*??1-|Output and Increment |[C]=[HL],HL=HL+1,B=B-1|
+;|POP xx |------|Pop |xx=[SP]+ |
+;|POP qq |------|Pop |qq=[SP]+ |
+;|PUSH xx |------|Push |-[SP]=xx |
+;|PUSH qq |------|Push |-[SP]=qq |
+;|RES b,m |------|Reset bit |m=m&{~2^b} |
+;|RET |------|Return |PC=[SP]+ |
+;|RET cc |------|Conditional Return |If cc RET |
+;|RETI |------|Return from Interrupt|PC=[SP]+ |
+;|RETN |------|Return from NMI |PC=[SP]+ |
+;|RL m |**0P0*|Rotate Left |m={CY,m}<- |
+;|RLA |--0-0*|Rotate Left Acc. |A={CY,A}<- |
+;|RLC m |**0P0*|Rotate Left Circular |m=m<- |
+;|RLCA |--0-0*|Rotate Left Circular |A=A<- |
+;|RLD |**0P0-|Rotate Left 4 bits |{A,[HL]}={A,[HL]}<- ##|
+;|RR m |**0P0*|Rotate Right |m=->{CY,m} |
+;|RRA |--0-0*|Rotate Right Acc. |A=->{CY,A} |
+;|RRC m |**0P0*|Rotate Right Circular|m=->m |
+;|RRCA |--0-0*|Rotate Right Circular|A=->A |
+;|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 |
+;|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 |
+;|SRA m |**0P0*|Shift Right Arith. |m=m/2 |
+;|SRL m |**0P0*|Shift Right Logical |m=->{0,m,CY} |
+;|SUB s |***V1*|Subtract |A=A-s |
+;|XOR s |**0P00|Logical Exclusive OR |A=Axs |
+;|----------+------+--------------------------------------------|
+;| F |-*01? |Flag unaffected/affected/reset/set/unknown |
+;| S |S |Sign flag (Bit 7) |
+;| Z | Z |Zero flag (Bit 6) |
+;| HC | H |Half Carry flag (Bit 4) |
+;| P/V | P |Parity/Overflow flag (Bit 2, V=overflow) |
+;| N | N |Add/Subtract flag (Bit 1) |
+;| CY | C|Carry flag (Bit 0) |
+;|-----------------+--------------------------------------------|
+;| n |Immediate addressing |
+;| nn |Immediate extended addressing |
+;| e |Relative addressing (PC=PC+2+offset) |
+;| [nn] |Extended addressing |
+;| [xx+d] |Indexed addressing |
+;| r |Register addressing |
+;| [rr] |Register indirect addressing |
+;| |Implied addressing |
+;| b |Bit addressing |
+;| p |Modified page zero addressing (see RST) |
+;|-----------------+--------------------------------------------|
+;|DEFB n(,...) |Define Byte(s) |
+;|DEFB 'str'(,...) |Define Byte ASCII string(s) |
+;|DEFS nn |Define Storage Block |
+;|DEFW nn(,...) |Define Word(s) |
+;|-----------------+--------------------------------------------|
+;| A B C D E |Registers (8-bit) |
+;| AF BC DE HL |Register pairs (16-bit) |
+;| F |Flag register (8-bit) |
+;| I |Interrupt page address register (8-bit) |
+;| IX IY |Index registers (16-bit) |
+;| PC |Program Counter register (16-bit) |
+;| R |Memory Refresh register |
+;| SP |Stack Pointer register (16-bit) |
+;|-----------------+--------------------------------------------|
+;| b |One bit (0 to 7) |
+;| cc |Condition (C,M,NC,NZ,P,PE,PO,Z) |
+;| d |One-byte expression (-128 to +127) |
+;| dst |Destination s, ss, [BC], [DE], [HL], [nn] |
+;| e |One-byte expression (-126 to +129) |
+;| m |Any register r, [HL] or [xx+d] |
+;| n |One-byte expression (0 to 255) |
+;| nn |Two-byte expression (0 to 65535) |
+;| pp |Register pair BC, DE, IX or SP |
+;| qq |Register pair AF, BC, DE or HL |
+;| qq' |Alternative register pair AF, BC, DE or HL |
+;| r |Register A, B, C, D, E, H or L |
+;| rr |Register pair BC, DE, IY or SP |
+;| s |Any register r, value n, [HL] or [xx+d] |
+;| src |Source s, ss, [BC], [DE], [HL], nn, [nn] |
+;| ss |Register pair BC, DE, HL or SP |
+;| xx |Index register IX or IY |
+;|-----------------+--------------------------------------------|
+;| + - * / ^ |Add/subtract/multiply/divide/exponent |
+;| & ~ v x |Logical AND/NOT/inclusive OR/exclusive OR |
+;| <- -> |Rotate left/right |
+;| [ ] |Indirect addressing |
+;| [ ]+ -[ ] |Indirect addressing auto-increment/decrement|
+;| { } |Combination of operands |
+;| # |Also BC=BC-1,DE=DE-1 |
+;| ## |Only lower 4 bits of accumulator A used |
+;----------------------------------------------------------------
+
+;How the flags are supposed to work:
+;7 ZFL_S - Sign flag (=MSBit of result)
+;6 ZFL_Z - Zero flag. Is 1 when the result is 0
+;4 ZFL_H - Half-carry (carry from bit 3 to 4)
+;2 ZFL_P - Parity/2-complement Overflow
+;1 ZFL_N - Subtract - set if last op was a subtract
+;0 ZFL_C - Carry
+;
+;I sure hope I got the mapping between flags and instructions correct...
+
+.equ ZFL_S = 7
+.equ ZFL_Z = 6
+.equ ZFL_H = 4
+.equ ZFL_P = 2
+.equ ZFL_N = 1
+.equ ZFL_C = 0
+
+
+.equ AVR_T = SREG_T
+.equ AVR_H = SREG_H
+.equ AVR_S = SREG_S
+.equ AVR_V = SREG_V
+.equ AVR_N = SREG_N
+.equ AVR_Z = SREG_Z
+.equ AVR_C = SREG_C
+
+;------------------------------------------------;
+; Load table value from flash indexed by source reg.
+;
+; ldpmx dstreg,tablebase,indexreg
+;
+; (6 words, 8 cycles)
+
+.macro ldpmx
+ ldi zh,high(@1*2) ; table must be page aligned
+ mov zl,@2
+ lpm @0,z
+.endm
+
+.macro do_z80_flags_HP
+#if EM_Z80
+ bmov z_flags, ZFL_P, temp, AVR_V
+ 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_set_HN
+#if EM_Z80
+ ori z_flags,(1<<ZFL_N)|(1<<ZFL_H)
+#endif
+.endm
+
+.macro do_z80_flags_clear_N
+#if EM_Z80
+ andi z_flags,~(1<<ZFL_N)
+#endif
+.endm
+
+.macro do_z80_flags_op_rotate
+ ; must not change avr carry flag!
+#if EM_Z80
+ andi z_flags, ~( (1<<ZFL_H) | (1<<ZFL_N) | (1<<ZFL_C) )
+#else
+ andi z_flags, ~( (1<<ZFL_C) )
+#endif
+.endm
+
+.macro do_z80_flags_op_and
+#if EM_Z80
+ ori z_flags,(1<<ZFL_H)
+#else
+ ori z_flags,(1<<ZFL_H)
+#endif
+.endm
+
+.macro do_z80_flags_op_or
+#if EM_Z80
+#endif
+.endm
+
+
+;----------------------------------------------------------------
+
+do_op_inv:
+ sbiw z_pcl,1
+ rcall printregs
+ printstring "Invalid opcode! "
+
+haltinv:
+ rjmp haltinv
+
+do_op_nop:
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|OUT [n],A |------|Output |[n]=A |
+;
+;
+;Interface with peripherials goes here :)
+do_op_outa: ; out (opl),a
+.if PORT_DEBUG
+ printnewline
+ printstring "Port write: "
+ mov temp,z_a
+ rcall printhex
+ printstring " -> ("
+ mov temp,opl
+ rcall printhex
+ printstring ") "
+.endif
+ mov temp,z_a
+ mov temp2,opl
+ rcall portWrite
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|IN A,[n] |------|Input |A=[n] |
+;
+;
+do_op_in: ; in a,(opl)
+.if PORT_DEBUG
+ printnewline
+ printstring "Port read: ("
+ mov temp,opl
+ rcall printhex
+ printstring ") -> "
+.endif
+
+ mov temp2,opl
+ rcall portRead
+ mov opl,temp
+
+.if PORT_DEBUG
+ rcall printhex
+ printstring " "
+.endif
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|INC r |***V0-|Increment |r=r+1 |
+;|INC [HL] |***V0-|Increment |[HL]=[HL]+1 |
+;|INC [xx+d]|***V0-|Increment |[xx+d]=[xx+d]+1 |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|INC r |**-P0-|Increment |r=r+1 |
+;|INC [HL] |**-P0-|Increment |[HL]=[HL]+1 |
+;
+;
+do_op_inc:
+ inc opl
+#if EM_Z80
+ in temp, sreg
+#endif
+ andi z_flags,(1<<ZFL_H)|(1<<ZFL_C) ; preserve C-, and H-flag
+ ldpmx temp2, sz53p_tab, opl
+ or z_flags,temp2 ;
+ do_z80_flags_HP
+ ret
+
+do_op_inca:
+ inc z_a
+#if EM_Z80
+ in temp, sreg
+#endif
+ andi z_flags,(1<<ZFL_H)|(1<<ZFL_C) ; preserve C-, and H-flag
+ ldpmx temp2, sz53p_tab, z_a
+ or z_flags,temp2 ;
+ do_z80_flags_HP
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|DEC r |***V1-|Decrement |s=s-1 |
+;|INC [HL] |***V0-|Increment |[HL]=[HL]+1 |
+;|INC [xx+d]|***V0-|Increment |[xx+d]=[xx+d]+1 |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|DEC r |**-P -|Increment |r=r+1 |
+;|DEC [HL] |**-P -|Increment |[HL]=[HL]+1 |
+;
+;
+do_op_dec:
+ dec opl
+#if EM_Z80
+ in temp, sreg
+#endif
+ andi z_flags,(1<<ZFL_H)|(1<<ZFL_C) ; preserve C-, and H-flag
+ ldpmx temp2, sz53p_tab, opl
+ or z_flags,temp2 ;
+ do_z80_flags_HP
+ do_z80_flags_set_N
+ ret
+
+do_op_deca:
+ dec z_a
+#if EM_Z80
+ in temp, sreg
+#endif
+ andi z_flags,(1<<ZFL_H)|(1<<ZFL_C) ; preserve C-, and H-flag
+ ldpmx temp2, sz53p_tab, z_a
+ or z_flags,temp2 ;
+ do_z80_flags_HP
+ do_z80_flags_set_N
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|INC xx |------|Increment |xx=xx+1 |
+;|INC ss |------|Increment |ss=ss+1 |
+;
+;
+do_op_inc16:
+ subi opl,low(-1)
+ sbci oph,high(-1)
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|DEC xx |------|Decrement |xx=xx-1 |
+;|DEC ss |------|Decrement |ss=ss-1 |
+;
+;
+do_op_dec16:
+ subi opl, 1
+ sbci oph, 0
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|RLCA |--0-0*|Rotate Left Circular |A=A<- |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|RLCA |---- *|Rotate Left Circular |A=A<- |
+;
+;
+do_op_rlc:
+ ;Rotate Left Cyclical. All bits move 1 to the
+ ;left, the msb becomes c and lsb.
+ do_z80_flags_op_rotate
+ lsl opl
+ brcc do_op_rlc_noc
+ ori opl, 1
+ ori z_flags, (1<<ZFL_C)
+do_op_rlc_noc:
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|RRCA |--0-0*|Rotate Right Circular|A=->A |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|RRCA |---- *|Rotate Right Circular|A=->A |
+;
+;
+do_op_rrc:
+ ;Rotate Right Cyclical. All bits move 1 to the
+ ;right, the lsb becomes c and msb.
+ do_z80_flags_op_rotate
+ lsr opl
+ brcc do_op_rrc_noc
+ ori opl, 0x80
+ ori z_flags, (1<<ZFL_C)
+do_op_rrc_noc:
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|RRA |--0-0*|Rotate Right Acc. |A=->{CY,A} |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|RRA |---- *|Rotate Right Acc. |A=->{CY,A} |
+;
+;
+do_op_rr:
+ ;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
+ sec
+ do_z80_flags_op_rotate ; (clear ZFL_C, doesn't change AVR_C)
+ bmov z_flags,ZFL_C, opl,0 ; Bit 0 --> CY
+ ror opl
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|RLA |--0-0*|Rotate Left Acc. |A={CY,A}<- |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|RLA |---- *|Rotate Left Acc. |A={CY,A}<- |
+;
+;
+do_op_rl:
+ ;Rotate Left. All bits move 1 to the left, the msb
+ ;becomes c, c becomes lsb.
+ clc
+ sbrc z_flags,ZFL_C
+ sec
+ do_z80_flags_op_rotate ; (clear ZFL_C, doesn't change AVR_C)
+ bmov z_flags,ZFL_C, opl,7 ; Bit 7 --> CY
+ rol opl
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|ADD A,s |***V0*|Add |A=A+s |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|ADD A,s |***P *|Add |A=A+s |
+;
+;
+do_op_adda:
+ add z_a,opl
+ in temp,sreg
+ ldpmx z_flags,sz53p_tab,z_a ;S,Z,P flag
+ bmov z_flags,ZFL_C, temp,AVR_C
+ do_z80_flags_HP
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|ADC A,s |***V0*|Add with Carry |A=A+s+CY |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|ADC A,s |***P *|Add with Carry |A=A+s+CY |
+;
+;
+do_op_adca:
+ clc
+ sbrc z_flags,ZFL_C
+ sec
+ adc z_a,opl
+ in temp,sreg
+ ldpmx z_flags,sz53p_tab,z_a ;S,Z,P
+ bmov z_flags,ZFL_C, temp,AVR_C
+ do_z80_flags_HP
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|SUB s |***V1*|Subtract |A=A-s |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|SUB s |***P *|Subtract |A=A-s |
+
+;
+do_op_subfa:
+ sub z_a,opl
+ in temp,sreg
+ ldpmx z_flags,sz53p_tab,z_a ;S,Z,P
+ bmov z_flags,ZFL_C, temp,AVR_C
+ do_z80_flags_HP
+ do_z80_flags_set_N
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CP s |***V1*|Compare |A-s |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|CP s |***P *|Compare |A-s |
+
+;
+do_op_cpfa:
+ mov temp,z_a
+ sub temp,opl
+ mov opl,temp
+ in temp,sreg
+ ldpmx z_flags,sz53p_tab,opl ;S,Z,P
+ bmov z_flags,ZFL_C, temp,AVR_C
+ do_z80_flags_HP
+ do_z80_flags_set_N
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|SBC A,s |***V1*|Subtract with Carry |A=A-s-CY |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|SBC A,s |***P *|Subtract with Carry |A=A-s-CY |
+;
+;
+do_op_sbcfa:
+ clc
+ sbrc z_flags,ZFL_C
+ sec
+ sbc z_a,opl
+ in temp,sreg
+ ldpmx z_flags,sz53p_tab,z_a ;S,Z,P
+ bmov z_flags,ZFL_C, temp,AVR_C
+ do_z80_flags_HP
+ do_z80_flags_set_N
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|AND s |**1P00|Logical AND |A=A&s |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|AND s |**-P 0|Logical AND |A=A&s |
+;
+; TODO H-Flag
+do_op_anda:
+ and z_a,opl ;
+ ldpmx z_flags,sz53p_tab,z_a ;S,Z,P,N,C
+ do_z80_flags_op_and
+ ret
+
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|OR s |**0P00|Logical inclusive OR |A=Avs |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|OR s |**-P00|Logical inclusive OR |A=Avs |
+;
+; TODO: H-Flag
+do_op_ora:
+ or z_a,opl
+ ldpmx z_flags,sz53p_tab,z_a ;S,Z,H,P,N,C
+ do_z80_flags_op_or
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|XOR s |**0P00|Logical Exclusive OR |A=Axs |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|XOR s |**-P 0|Logical Exclusive OR |A=Axs |
+;
+; TODO: H-Flag
+do_op_xora:
+ eor z_a,opl
+ ldpmx z_flags,sz53p_tab,z_a ;S,Z,H,P,N,C
+ do_z80_flags_op_or
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|ADD HL,ss |--?-0*|Add |HL=HL+ss |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|ADD HL,ss |---- *|Add |HL=HL+ss |
+;
+;
+do_op_addhl:
+ lds temp,z_l
+ lds temp2,z_h
+ add opl,temp
+ adc oph,temp2
+ in temp,sreg
+ bmov z_flags,ZFL_H, temp,AVR_H
+ bmov z_flags,ZFL_C, temp,AVR_C
+ do_z80_flags_clear_N
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|LD dst,src|------|Load |dst=src |
+;
+;
+do_op_sthl: ;store hl to mem loc in opl:h
+ movw xl,opl
+ lds temp,z_l
+ mem_write
+ adiw xl,1
+ lds temp,z_h
+ mem_write
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|LD dst,src|------|Load |dst=src |
+;
+;
+do_op_rmem16:
+ movw xl,opl
+ mem_read_d opl
+ adiw x,1
+ mem_read_d oph
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|LD dst,src|------|Load |dst=src |
+;
+;
+do_op_rmem8:
+ mem_read_ds opl, op
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|DAA |***P-*|Decimal Adjust Acc. | |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;
+; Not yet checked
+
+; Description (http://www.z80.info/z80syntx.htm#DAA):
+; This instruction conditionally adjusts the accumulator for BCD addition
+; and subtraction operations. For addition (ADD, ADC, INC) or subtraction
+; (SUB, SBC, DEC, NEC), the following table indicates the operation performed:
+;
+; -------------------------------------------------------------------------------
+; | | C Flag | HEX value in | H Flag | HEX value in | Number | C flag|
+; | Operation| Before | upper digit | Before | lower digit | added | After |
+; | | DAA | (bit 7-4) | DAA | (bit 3-0) | to byte | DAA |
+; |-----------------------------------------------------------------------------|
+; | | 0 | 0-9 | 0 | 0-9 | 00 | 0 |
+; | ADD | 0 | 0-8 | 0 | A-F | 06 | 0 |
+; | | 0 | 0-9 | 1 | 0-3 | 06 | 0 |
+; | ADC | 0 | A-F | 0 | 0-9 | 60 | 1 |
+; | | 0 | 9-F | 0 | A-F | 66 | 1 |
+; | INC | 0 | A-F | 1 | 0-3 | 66 | 1 |
+; | | 1 | 0-2 | 0 | 0-9 | 60 | 1 |
+; | | 1 | 0-2 | 0 | A-F | 66 | 1 |
+; | | 1 | 0-3 | 1 | 0-3 | 66 | 1 |
+; |-----------------------------------------------------------------------------|
+; | SUB | 0 | 0-9 | 0 | 0-9 | 00 | 0 |
+; | SBC | 0 | 0-8 | 1 | 6-F | FA | 0 |
+; | DEC | 1 | 7-F | 0 | 0-9 | A0 | 1 |
+; | NEG | 1 | 6-F | 1 | 6-F | 9A | 1 |
+; |-----------------------------------------------------------------------------|
+;
+; Flags:
+; C: See instruction.
+; N: Unaffected.
+; P/V: Set if Acc. is even parity after operation, reset otherwise.
+; H: See instruction.
+; 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:
+ ldi oph,0 ; what to add
+ sbrc z_flags,ZFL_H ; if H-Flag
+ rjmp op_da_06
+ mov temp,opl
+ andi temp,0x0f ; ... or lower digit > 9
+ cpi temp,0x0a
+ brlo op_da_06n
+op_da_06:
+ ori oph,0x06
+op_da_06n:
+ sbrc z_flags,(1<<ZFL_C)
+ rjmp op_da_60
+ cpi opl,0xa0
+ brlo op_da_60n
+op_da_60:
+ ori oph,0x60
+op_da_60n:
+ cpi opl,0x9a
+ brlo op_da_99n
+ ori z_flags,(1<<ZFL_C); set C
+op_da_99n:
+ sbrs z_flags,ZFL_N ; if sub-op
+ rjmp op_da_add ; then
+ sub opl,oph
+ rjmp op_da_ex
+op_da_add: ; else add-op
+ cpi opl,0x91
+ brlo op_da_60n2
+ mov temp,opl
+ andi temp,0x0f
+ cpi temp,0x0a
+ brlo op_da_60n2
+ ori oph,0x60
+op_da_60n2:
+ add opl,oph
+op_da_ex:
+ in temp,SREG
+ sbrc temp,AVR_H
+ ori z_flags,(1<<ZFL_C)
+ andi z_flags,(1<<ZFL_N)|(1<<ZFL_C) ; preserve C,N
+ ldpmx temp2, sz53p_tab, opl ; get S,Z,P
+ or z_flags,temp2
+ bmov z_flags,ZFL_H, temp,AVR_H ; H (?)
+ ret
+#else
+
+do_op_da:
+ sbrc z_flags,ZFL_N ; if add-op
+ rjmp do_op_da_sub ; then
+ ldi temp2,0 ;
+ mov temp,opl ;
+ andi temp,0x0f ;
+ cpi temp,0x0a ; if lower digit > 9
+ brlo do_op_da_h ;
+ ori temp2,0x06 ; add 6 to lower digit
+do_op_da_h: ;
+ sbrc z_flags,ZFL_H ; ... or H-Flag
+ ori temp2,0x06 ;
+ add opl,temp2 ;
+
+ ldi temp2,0 ;
+ mov temp,opl ;
+ andi temp,0xf0 ;
+ cpi temp,0xa0 ;
+ brlo do_op_da_c ;
+ ori temp2,0x60 ;
+do_op_da_c: ; else sub-op
+ sbrc z_flags,ZFL_C ;
+ ori temp2,0x60 ;
+ andi z_flags, ~( (1<<ZFL_S) | (1<<ZFL_Z) | (1<<ZFL_H) )
+ add opl,temp2 ;
+ in temp,SREG ;
+ bst temp,AVR_Z ;Z-Flag
+ bld z_flags,ZFL_Z ;
+ bst temp,AVR_N ;S-Flag
+ bst z_flags,ZFL_S ;
+ sbrc temp2,5 ;C-Flag, set if 0x06 added
+ ori z_flags,(1<<ZFL_C) ;
+ ;H-Flag?
+ ret
+
+do_op_da_sub: ;TODO:
+ rcall do_op_inv
+ ret
+#endif
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|SCF |--0-01|Set Carry Flag |CY=1 |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;
+;
+do_op_scf:
+ andi z_flags,~((1<<ZFL_H)|(1<<ZFL_N))
+ ori z_flags,(1<<ZFL_C)
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CCF |--?-0*|Complement Carry Flag|CY=~CY |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|SCF |---- 1|Set Carry Flag |CY=1 |
+;
+;TODO: H-Flag
+do_op_ccf:
+ do_z80_flags_clear_N
+ ldi temp,(1<<ZFL_C)
+ eor z_flags,temp
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CPL |--1-1-|Complement |A=~A |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|CPL |---- -|Complement |A=~A |
+;
+;
+do_op_cpl:
+ com z_a
+ do_z80_flags_set_HN
+ ret
+
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|PUSH xx |------|Push |-[SP]=xx |
+;|PUSH qq |------|Push |-[SP]=qq |
+;
+;
+do_op_push16:
+ movw xl,z_spl
+ sbiw x,1
+ mem_write_s oph
+ sbiw x,1
+ mem_write_s opl
+ movw z_spl,xl
+
+.if STACK_DBG
+ printnewline
+ printstring "Stack push "
+ movw temp,opl
+ rcall printhexw
+ printstring ", SP is now "
+ movw temp,z_spl
+ rcall printhexw
+ printstring ". "
+.endif
+
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|POP xx |------|Pop |xx=[SP]+ |
+;|POP qq |------|Pop |qq=[SP]+ |
+;
+;
+do_op_pop16:
+ movw x,z_spl
+ mem_read_d opl
+ adiw x,1
+ mem_read_d oph
+ adiw x,1
+ movw z_spl,x
+
+.if STACK_DBG
+ printnewline
+ printstring "Stack pop "
+ movw temp,opl
+ rcall printhexw
+ printstring ", SP is now "
+ movw temp,z_spl
+ rcall printhexw
+ printstring ". "
+.endif
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|EX [SP],HL|------|Exchange |[SP]<->HL |
+;|EX DE,HL |------|Exchange |DE<->HL |
+;-----------------------------Z80--------------------------------
+;
+do_op_exhl:
+ lds temp,z_l
+ lds temp2,z_h
+ sts z_l,opl
+ sts z_h,oph
+ movw opl,temp
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;
+; TODO: Implement IFF1, IFF2
+do_op_di:
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;
+; TODO: Implement IFF1, IFF2
+do_op_ei:
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CALL cc,nn|------|Conditional Call |If cc CALL |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|RET cc |------|Conditional Return |If cc RET |
+;
+;
+do_op_ifnz:
+ sbrs z_flags, ZFL_Z
+ ret
+ pop temp ; nix tun
+ pop temp ; direkt zuruech zu main
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CALL cc,nn|------|Conditional Call |If cc CALL |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|RET cc |------|Conditional Return |If cc RET |
+;
+;
+do_op_ifz:
+ sbrc z_flags, ZFL_Z
+ ret
+ pop temp ; nix tun
+ pop temp ; direkt zuruech zu main
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CALL cc,nn|------|Conditional Call |If cc CALL |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|RET cc |------|Conditional Return |If cc RET |
+;
+;
+do_op_ifnc:
+ sbrs z_flags, ZFL_C
+ ret
+ pop temp ; nix tun
+ pop temp ; direkt zuruech zu main
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CALL cc,nn|------|Conditional Call |If cc CALL |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|RET cc |------|Conditional Return |If cc RET |
+;
+;
+do_op_ifc:
+ sbrc z_flags, ZFL_C
+ ret
+ pop temp ; nix tun
+ pop temp ; direkt zuruech zu main
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CALL cc,nn|------|Conditional Call |If cc CALL |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|RET cc |------|Conditional Return |If cc RET |
+;
+;
+do_op_ifpo:
+ sbrs z_flags, ZFL_P
+ ret
+ pop temp ; nix tun
+ pop temp ; direkt zuruech zu main
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CALL cc,nn|------|Conditional Call |If cc CALL |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|RET cc |------|Conditional Return |If cc RET |
+;
+;
+do_op_ifpe:
+ sbrc z_flags, ZFL_P
+ ret
+ pop temp ; nix tun
+ pop temp ; direkt zuruech zu main
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CALL cc,nn|------|Conditional Call |If cc CALL |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|RET cc |------|Conditional Return |If cc RET |
+;
+;
+do_op_ifp: ;sign positive, aka s=0
+ sbrs z_flags, ZFL_S
+ ret
+ pop temp ; nix tun
+ pop temp ; direkt zuruech zu main
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CALL cc,nn|------|Conditional Call |If cc CALL |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|RET cc |------|Conditional Return |If cc RET |
+;
+;
+do_op_ifm: ;sign negative, aka s=1
+ sbrc z_flags, ZFL_S
+ ret
+ pop temp ; nix tun
+ 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.
+
+; .org (PC+255) & 0xff00
+
+;todo_table:
+;opcjmp:
+instr do_fetch_nop, op_nop, do_store_nop ;00 ;NOP
+instr do_fetch_DIR16, op_nop, do_store_BC ;01 nn nn ;LD BC,nn
+instr do_fetch_A, op_nop, do_store_MBC ;02 ;LD (BC),A
+instr do_fetch_BC, op_INC16, do_store_BC ;03 ;INC BC
+instr do_fetch_B, op_INC, do_store_B ;04 ;INC B
+instr do_fetch_B, op_DEC, do_store_B ;05 ;DEC B
+instr do_fetch_DIR8, op_nop, do_store_B ;06 ;LD B,n
+instr do_fetch_A, op_RLC, do_store_A ;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_MBC, op_nop, do_store_A ;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_C, op_DEC, do_store_C ;0D ;DEC C
+instr do_fetch_DIR8, op_nop, do_store_C ;0E nn ;LD C,n
+instr do_fetch_A, op_RRC, do_store_A ;0F ;RRCA
+instr do_fetch_nop, op_INV, do_store_nop ;10 oo ;DJNZ o
+instr do_fetch_DIR16, op_nop, do_store_DE ;11 nn nn ;LD DE,nn
+instr do_fetch_A, op_nop, do_store_MDE ;12 ;LD (DE),A
+instr do_fetch_DE, op_INC16, do_store_DE ;13 ;INC DE
+instr do_fetch_D, op_INC, do_store_D ;14 ;INC D
+instr do_fetch_D, op_DEC, do_store_D ;15 ;DEC D
+instr do_fetch_DIR8, op_nop, do_store_D ;16 nn ;LD D,n
+instr do_fetch_A, op_RL, do_store_A ;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_MDE, op_nop, do_store_A ;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_E, op_DEC, do_store_E ;1D ;DEC E
+instr do_fetch_DIR8, op_nop, do_store_E ;1E nn ;LD E,n
+instr do_fetch_A, op_RR, do_store_A ;1F ;RRA
+instr do_fetch_nop, op_INV, do_store_nop ;20 oo ;JR NZ,o
+instr do_fetch_DIR16, op_nop, do_store_HL ;21 nn nn ;LD HL,nn
+instr do_fetch_DIR16, op_STHL, do_store_nop ;22 nn nn ;LD (nn),HL
+instr do_fetch_HL, op_INC16, do_store_HL ;23 ;INC HL
+instr do_fetch_H, op_INC, do_store_H ;24 ;INC H
+instr do_fetch_H, op_DEC, do_store_H ;25 ;DEC H
+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_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_L, op_DEC, do_store_L ;2D ;DEC L
+instr do_fetch_DIR8, op_nop, do_store_L ;2E nn ;LD L,n
+instr do_fetch_nop, op_CPL, do_store_nop ;2F ;CPL
+instr do_fetch_nop, op_INV, do_store_nop ;30 oo ;JR NC,o
+instr do_fetch_DIR16, op_nop, do_store_SP ;31 nn nn ;LD SP,nn
+instr do_fetch_DIR16, op_nop, do_store_AM ;32 nn nn ;LD (nn),A
+instr do_fetch_SP, op_INC16, do_store_SP ;33 ;INC SP
+instr do_fetch_MHL, op_INC, do_store_MHL ;34 ;INC (HL)
+instr do_fetch_MHL, op_DEC, do_store_MHL ;35 ;DEC (HL)
+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_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_DECA, do_store_nop ;3D ;DEC A
+instr do_fetch_DIR8, op_nop, do_store_A ;3E nn ;LD A,n
+instr do_fetch_nop, op_CCF, do_store_nop ;3F ;CCF (Complement Carry Flag, gvd)
+instr do_fetch_B, op_nop, do_store_B ;40 ;LD B,B
+instr do_fetch_C, op_nop, do_store_B ;41 ;LD B,C
+instr do_fetch_D, op_nop, do_store_B ;42 ;LD B,D
+instr do_fetch_E, op_nop, do_store_B ;43 ;LD B,E
+instr do_fetch_H, op_nop, do_store_B ;44 ;LD B,H
+instr do_fetch_L, op_nop, do_store_B ;45 ;LD B,L
+instr do_fetch_MHL, op_nop, do_store_B ;46 ;LD B,(HL)
+instr do_fetch_A, op_nop, do_store_B ;47 ;LD B,A
+instr do_fetch_B, op_nop, do_store_C ;48 ;LD C,B
+instr do_fetch_C, op_nop, do_store_C ;49 ;LD C,C
+instr do_fetch_D, op_nop, do_store_C ;4A ;LD C,D
+instr do_fetch_E, op_nop, do_store_C ;4B ;LD C,E
+instr do_fetch_H, op_nop, do_store_C ;4C ;LD C,H
+instr do_fetch_L, op_nop, do_store_C ;4D ;LD C,L
+instr do_fetch_MHL, op_nop, do_store_C ;4E ;LD C,(HL)
+instr do_fetch_A, op_nop, do_store_C ;4F ;LD C,A
+instr do_fetch_B, op_nop, do_store_D ;50 ;LD D,B
+instr do_fetch_C, op_nop, do_store_D ;51 ;LD D,C
+instr do_fetch_D, op_nop, do_store_D ;52 ;LD D,D
+instr do_fetch_E, op_nop, do_store_D ;53 ;LD D,E
+instr do_fetch_H, op_nop, do_store_D ;54 ;LD D,H
+instr do_fetch_L, op_nop, do_store_D ;55 ;LD D,L
+instr do_fetch_MHL, op_nop, do_store_D ;56 ;LD D,(HL)
+instr do_fetch_A, op_nop, do_store_D ;57 ;LD D,A
+instr do_fetch_B, op_nop, do_store_E ;58 ;LD E,B
+instr do_fetch_C, op_nop, do_store_E ;59 ;LD E,C
+instr do_fetch_D, op_nop, do_store_E ;5A ;LD E,D
+instr do_fetch_E, op_nop, do_store_E ;5B ;LD E,E
+instr do_fetch_H, op_nop, do_store_E ;5C ;LD E,H
+instr do_fetch_L, op_nop, do_store_E ;5D ;LD E,L
+instr do_fetch_MHL, op_nop, do_store_E ;5E ;LD E,(HL)
+instr do_fetch_A, op_nop, do_store_E ;5F ;LD E,A
+instr do_fetch_B, op_nop, do_store_H ;60 ;LD H,B
+instr do_fetch_C, op_nop, do_store_H ;61 ;LD H,C
+instr do_fetch_D, op_nop, do_store_H ;62 ;LD H,D
+instr do_fetch_E, op_nop, do_store_H ;63 ;LD H,E
+instr do_fetch_H, op_nop, do_store_H ;64 ;LD H,H
+instr do_fetch_L, op_nop, do_store_H ;65 ;LD H,L
+instr do_fetch_MHL, op_nop, do_store_H ;66 ;LD H,(HL)
+instr do_fetch_A, op_nop, do_store_H ;67 ;LD H,A
+instr do_fetch_B, op_nop, do_store_L ;68 ;LD L,B
+instr do_fetch_C, op_nop, do_store_L ;69 ;LD L,C
+instr do_fetch_D, op_nop, do_store_L ;6A ;LD L,D
+instr do_fetch_E, op_nop, do_store_L ;6B ;LD L,E
+instr do_fetch_H, op_nop, do_store_L ;6C ;LD L,H
+instr do_fetch_L, op_nop, do_store_L ;6D ;LD L,L
+instr do_fetch_MHL, op_nop, do_store_L ;6E ;LD L,(HL)
+instr do_fetch_A, op_nop, do_store_L ;6F ;LD L,A
+instr do_fetch_B, op_nop, do_store_MHL ;70 ;LD (HL),B
+instr do_fetch_C, op_nop, do_store_MHL ;71 ;LD (HL),C
+instr do_fetch_D, op_nop, do_store_MHL ;72 ;LD (HL),D
+instr do_fetch_E, op_nop, do_store_MHL ;73 ;LD (HL),E
+instr do_fetch_H, op_nop, do_store_MHL ;74 ;LD (HL),H
+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_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_H, op_nop, do_store_A ;7C ;LD A,H
+instr do_fetch_L, op_nop, do_store_A ;7D ;LD A,L
+instr do_fetch_MHL, op_nop, do_store_A ;7E ;LD A,(HL)
+instr do_fetch_A, op_nop, do_store_A ;7F ;LD A,A
+instr do_fetch_B, op_ADDA, do_store_nop ;80 ;ADD A,B
+instr do_fetch_C, op_ADDA, do_store_nop ;81 ;ADD A,C
+instr do_fetch_D, op_ADDA, do_store_nop ;82 ;ADD A,D
+instr do_fetch_E, op_ADDA, do_store_nop ;83 ;ADD A,E
+instr do_fetch_H, op_ADDA, do_store_nop ;84 ;ADD A,H
+instr do_fetch_L, op_ADDA, do_store_nop ;85 ;ADD A,L
+instr do_fetch_MHL, op_ADDA, do_store_nop ;86 ;ADD A,(HL)
+instr do_fetch_A, op_ADDA, do_store_nop ;87 ;ADD A,A
+instr do_fetch_B, op_ADCA, do_store_nop ;88 ;ADC A,B
+instr do_fetch_C, op_ADCA, do_store_nop ;89 ;ADC A,C
+instr do_fetch_D, op_ADCA, do_store_nop ;8A ;ADC A,D
+instr do_fetch_E, op_ADCA, do_store_nop ;8B ;ADC A,E
+instr do_fetch_H, op_ADCA, do_store_nop ;8C ;ADC A,H
+instr do_fetch_L, op_ADCA, do_store_nop ;8D ;ADC A,L
+instr do_fetch_MHL, op_ADCA, do_store_nop ;8E ;ADC A,(HL)
+instr do_fetch_A, op_ADCA, do_store_nop ;8F ;ADC A,A
+instr do_fetch_B, op_SUBFA, do_store_nop ;90 ;SUB A,B
+instr do_fetch_C, op_SUBFA, do_store_nop ;91 ;SUB A,C
+instr do_fetch_D, op_SUBFA, do_store_nop ;92 ;SUB A,D
+instr do_fetch_E, op_SUBFA, do_store_nop ;93 ;SUB A,E
+instr do_fetch_H, op_SUBFA, do_store_nop ;94 ;SUB A,H
+instr do_fetch_L, op_SUBFA, do_store_nop ;95 ;SUB A,L
+instr do_fetch_MHL, op_SUBFA, do_store_nop ;96 ;SUB A,(HL)
+instr do_fetch_A, op_SUBFA, do_store_nop ;97 ;SUB A,A
+instr do_fetch_B, op_SBCFA, do_store_nop ;98 ;SBC A,B
+instr do_fetch_C, op_SBCFA, do_store_nop ;99 ;SBC A,C
+instr do_fetch_D, op_SBCFA, do_store_nop ;9A ;SBC A,D
+instr do_fetch_E, op_SBCFA, do_store_nop ;9B ;SBC A,E
+instr do_fetch_H, op_SBCFA, do_store_nop ;9C ;SBC A,H
+instr do_fetch_L, op_SBCFA, do_store_nop ;9D ;SBC A,L
+instr do_fetch_MHL, op_SBCFA, do_store_nop ;9E ;SBC A,(HL)
+instr do_fetch_A, op_SBCFA, do_store_nop ;9F ;SBC A,A
+instr do_fetch_B, op_ANDA, do_store_nop ;A0 ;AND A,B
+instr do_fetch_C, op_ANDA, do_store_nop ;A1 ;AND A,C
+instr do_fetch_D, op_ANDA, do_store_nop ;A2 ;AND A,D
+instr do_fetch_E, op_ANDA, do_store_nop ;A3 ;AND A,E
+instr do_fetch_H, op_ANDA, do_store_nop ;A4 ;AND A,H
+instr do_fetch_L, op_ANDA, do_store_nop ;A5 ;AND A,L
+instr do_fetch_MHL, op_ANDA, do_store_nop ;A6 ;AND A,(HL)
+instr do_fetch_A, op_ANDA, do_store_nop ;A7 ;AND A,A
+instr do_fetch_B, op_XORA, do_store_nop ;A8 ;XOR A,B
+instr do_fetch_C, op_XORA, do_store_nop ;A9 ;XOR A,C
+instr do_fetch_D, op_XORA, do_store_nop ;AA ;XOR A,D
+instr do_fetch_E, op_XORA, do_store_nop ;AB ;XOR A,E
+instr do_fetch_H, op_XORA, do_store_nop ;AC ;XOR A,H
+instr do_fetch_L, op_XORA, do_store_nop ;AD ;XOR A,L
+instr do_fetch_MHL, op_XORA, do_store_nop ;AE ;XOR A,(HL)
+instr do_fetch_A, op_XORA, do_store_nop ;AF ;XOR A,A
+instr do_fetch_B, op_ORA, do_store_nop ;B0 ;OR A,B
+instr do_fetch_C, op_ORA, do_store_nop ;B1 ;OR A,C
+instr do_fetch_D, op_ORA, do_store_nop ;B2 ;OR A,D
+instr do_fetch_E, op_ORA, do_store_nop ;B3 ;OR A,E
+instr do_fetch_H, op_ORA, do_store_nop ;B4 ;OR A,H
+instr do_fetch_L, op_ORA, do_store_nop ;B5 ;OR A,L
+instr do_fetch_MHL, op_ORA, do_store_nop ;B6 ;OR A,(HL)
+instr do_fetch_A, op_ORA, do_store_nop ;B7 ;OR A,A
+instr do_fetch_B, op_CPFA, do_store_nop ;B8 ;CP A,B
+instr do_fetch_C, op_CPFA, do_store_nop ;B9 ;CP A,C
+instr do_fetch_D, op_CPFA, do_store_nop ;BA ;CP A,D
+instr do_fetch_E, op_CPFA, do_store_nop ;BB ;CP A,E
+instr do_fetch_H, op_CPFA, do_store_nop ;BC ;CP A,H
+instr do_fetch_L, op_CPFA, do_store_nop ;BD ;CP A,L
+instr do_fetch_MHL, op_CPFA, do_store_nop ;BE ;CP A,(HL)
+instr do_fetch_A, op_CPFA, do_store_nop ;BF ;CP A,A
+instr do_fetch_nop, op_IFNZ, do_store_RET ;C0 ;RET NZ
+instr do_fetch_nop, op_POP16, do_store_BC ;C1 ;POP BC
+instr do_fetch_DIR16, op_IFNZ, do_store_PC ;C2 nn nn ;JP NZ,nn
+instr do_fetch_DIR16, op_nop, do_store_PC ;C3 nn nn ;JP nn
+instr do_fetch_DIR16, op_IFNZ, do_store_CALL ;C4 nn nn ;CALL NZ,nn
+instr do_fetch_BC, op_PUSH16, do_store_nop ;C5 ;PUSH BC
+instr do_fetch_DIR8, op_ADDA, do_store_nop ;C6 nn ;ADD A,n
+instr do_fetch_RST, op_nop, do_store_CALL ;C7 ;RST 0
+instr do_fetch_nop, op_IFZ, do_store_RET ;C8 ;RET Z
+instr do_fetch_nop, op_nop, do_store_RET ;C9 ;RET
+instr do_fetch_DIR16, op_IFZ, do_store_PC ;CA nn nn ;JP Z,nn
+instr do_fetch_nop, op_INV, do_store_nop ;CB ;(Z80 specific)
+instr do_fetch_DIR16, op_IFZ, do_store_CALL ;CC nn nn ;CALL Z,nn
+instr do_fetch_DIR16, op_nop, do_store_CALL ;CD nn nn ;CALL nn
+instr do_fetch_DIR8, op_ADCA, do_store_nop ;CE nn ;ADC A,n
+instr do_fetch_RST, op_nop, do_store_CALL ;CF ;RST 8H
+instr do_fetch_nop, op_IFNC, do_store_RET ;D0 ;RET NC
+instr do_fetch_nop, op_POP16, do_store_DE ;D1 ;POP DE
+instr do_fetch_DIR16, op_IFNC, do_store_PC ;D2 nn nn ;JP NC,nn
+instr do_fetch_DIR8, op_OUTA, do_store_nop ;D3 nn ;OUT (n),A
+instr do_fetch_DIR16, op_IFNC, do_store_CALL ;D4 nn nn ;CALL NC,nn
+instr do_fetch_DE, op_PUSH16, do_store_nop ;D5 ;PUSH DE
+instr do_fetch_DIR8, op_SUBFA, do_store_nop ;D6 nn ;SUB n
+instr do_fetch_RST, op_nop, do_store_CALL ;D7 ;RST 10H
+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_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
+instr do_fetch_RST, op_nop, do_store_CALL ;DF ;RST 18H
+instr do_fetch_nop, op_IFPO, do_store_RET ;E0 ;RET PO
+instr do_fetch_nop, op_POP16, do_store_HL ;E1 ;POP HL
+instr do_fetch_DIR16, op_IFPO, do_store_PC ;E2 nn nn ;JP PO,nn
+instr do_fetch_MSP, op_EXHL, do_store_MSP ;E3 ;EX (SP),HL
+instr do_fetch_DIR16, op_IFPO, do_store_CALL ;E4 nn nn ;CALL PO,nn
+instr do_fetch_HL, op_PUSH16, do_store_nop ;E5 ;PUSH HL
+instr do_fetch_DIR8, op_ANDA, do_store_nop ;E6 nn ;AND n
+instr do_fetch_RST, op_nop, do_store_CALL ;E7 ;RST 20H
+instr do_fetch_nop, op_IFPE, do_store_RET ;E8 ;RET PE
+instr do_fetch_HL, op_nop, do_store_PC ;E9 ;JP HL
+instr do_fetch_DIR16, op_IFPE, do_store_PC ;EA nn nn ;JP PE,nn
+instr do_fetch_DE, op_EXHL, do_store_DE ;EB ;EX DE,HL
+instr do_fetch_DIR16, op_IFPE, do_store_CALL ;EC nn nn ;CALL PE,nn
+instr do_fetch_nop, op_INV, do_store_nop ;ED ;(Z80 specific)
+instr do_fetch_DIR8, op_XORA, do_store_nop ;EE nn ;XOR n
+instr do_fetch_RST, op_nop, do_store_CALL ;EF ;RST 28H
+instr do_fetch_nop, op_IFP, do_store_RET ;F0 ;RET P
+instr do_fetch_nop, op_POP16, do_store_AF ;F1 ;POP AF
+instr do_fetch_DIR16, op_IFP, do_store_PC ;F2 nn nn ;JP P,nn
+instr do_fetch_nop, op_DI, do_store_nop ;F3 ;DI
+instr do_fetch_DIR16, op_IFP, do_store_CALL ;F4 nn nn ;CALL P,nn
+instr do_fetch_AF, op_PUSH16, do_store_nop ;F5 ;PUSH AF
+instr do_fetch_DIR8, op_ORA, do_store_nop ;F6 nn ;OR n
+instr do_fetch_RST, op_nop, do_store_CALL ;F7 ;RST 30H
+instr do_fetch_nop, op_IFM, do_store_RET ;F8 ;RET M
+instr do_fetch_HL, op_nop, do_store_SP ;F9 ;LD SP,HL
+instr do_fetch_DIR16, op_IFM, do_store_PC ;FA nn nn ;JP M,nn
+instr do_fetch_nop, op_EI, do_store_nop ;FB ;EI
+instr do_fetch_DIR16, op_IFM, do_store_CALL ;FC nn nn ;CALL M,nn
+instr do_fetch_nop, op_INV, do_store_nop ;FD ;(Z80 specific)
+instr do_fetch_DIR8, op_CPFA, do_store_nop ;FE nn ;CP n
+instr do_fetch_RST, op_nop, do_store_CALL ;FF ;RST 38H
+
+
+;----------------------------------------------------------------
+; 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
+
+; .org (PC+255) & 0xff00
+ .org opcjmp + 256
+sz53p_tab:
+ .db 0x44,0x00,0x00,0x04,0x00,0x04,0x04,0x00
+ .db 0x08,0x0c,0x0c,0x08,0x0c,0x08,0x08,0x0c
+ .db 0x00,0x04,0x04,0x00,0x04,0x00,0x00,0x04
+ .db 0x0c,0x08,0x08,0x0c,0x08,0x0c,0x0c,0x08
+ .db 0x20,0x24,0x24,0x20,0x24,0x20,0x20,0x24
+ .db 0x2c,0x28,0x28,0x2c,0x28,0x2c,0x2c,0x28
+ .db 0x24,0x20,0x20,0x24,0x20,0x24,0x24,0x20
+ .db 0x28,0x2c,0x2c,0x28,0x2c,0x28,0x28,0x2c
+ .db 0x00,0x04,0x04,0x00,0x04,0x00,0x00,0x04
+ .db 0x0c,0x08,0x08,0x0c,0x08,0x0c,0x0c,0x08
+ .db 0x04,0x00,0x00,0x04,0x00,0x04,0x04,0x00
+ .db 0x08,0x0c,0x0c,0x08,0x0c,0x08,0x08,0x0c
+ .db 0x24,0x20,0x20,0x24,0x20,0x24,0x24,0x20
+ .db 0x28,0x2c,0x2c,0x28,0x2c,0x28,0x28,0x2c
+ .db 0x20,0x24,0x24,0x20,0x24,0x20,0x20,0x24
+ .db 0x2c,0x28,0x28,0x2c,0x28,0x2c,0x2c,0x28
+ .db 0x80,0x84,0x84,0x80,0x84,0x80,0x80,0x84
+ .db 0x8c,0x88,0x88,0x8c,0x88,0x8c,0x8c,0x88
+ .db 0x84,0x80,0x80,0x84,0x80,0x84,0x84,0x80
+ .db 0x88,0x8c,0x8c,0x88,0x8c,0x88,0x88,0x8c
+ .db 0xa4,0xa0,0xa0,0xa4,0xa0,0xa4,0xa4,0xa0
+ .db 0xa8,0xac,0xac,0xa8,0xac,0xa8,0xa8,0xac
+ .db 0xa0,0xa4,0xa4,0xa0,0xa4,0xa0,0xa0,0xa4
+ .db 0xac,0xa8,0xa8,0xac,0xa8,0xac,0xac,0xa8
+ .db 0x84,0x80,0x80,0x84,0x80,0x84,0x84,0x80
+ .db 0x88,0x8c,0x8c,0x88,0x8c,0x88,0x88,0x8c
+ .db 0x80,0x84,0x84,0x80,0x84,0x80,0x80,0x84
+ .db 0x8c,0x88,0x88,0x8c,0x88,0x8c,0x8c,0x88
+ .db 0xa0,0xa4,0xa4,0xa0,0xa4,0xa0,0xa0,0xa4
+ .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
+
--- /dev/null
+; 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.
+; Copyright (C) 2010 Horst S.
+
+; This file is part of avrcpm.
+;
+; avrcpm is free software: you can redistribute it and/or modify it
+; under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; avrcpm is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with avrcpm. If not, see <http://www.gnu.org/licenses/>.
+;
+; $Id$
+;
+
+ .dseg
+
+z_b: .byte 1
+z_c: .byte 1
+z_d: .byte 1
+z_e: .byte 1
+z_h: .byte 1
+z_l: .byte 1
+
+
+ .cseg
+
+;Init z80
+z80_init:
+ ldi z_pcl,low (IPLADDR)
+ ldi z_pch,high(IPLADDR)
+
+ cbi flags,trace
+ printnewline
+ printstring "Ok, CPU is live!"
+ printnewline
+
+
+main:
+.if INS_DEBUG
+ cbi flags,trace
+ cpi z_pch,DBG_TRACE_BOTTOM
+ brlo notraceon
+ cpi z_pch,DBG_TRACE_TOP
+ brsh notraceon
+ sbi flags,trace
+notraceon:
+.endif
+
+
+.if PRINT_PC
+ cpi z_pch,DBG_TRACE_BOTTOM
+ brlo noprintpc
+ cpi z_pch,DBG_TRACE_TOP
+ brsh noprintpc
+
+ printnewline
+ printstring "PC="
+ movw temp,z_pcl
+ rcall printhexw
+ printstring " "
+noprintpc:
+.endif
+
+.if INS_DEBUG
+ sbic flags,trace
+ rcall printregs
+.endif
+
+ ;hier kommt die Interruptbehandlung rein
+
+ mem_read_s z_pc ;temp=memReadByte(z_pc)
+ adiw z_pcl,1 ;++z_pc
+ ldi zl,low(todo_table*2) ;zhl=todo_table
+ ldi zh,high(todo_table*2) ;
+ ldi temp2,3 ;1
+ mul temp,temp2 ;2
+ add zl,r0 ;1
+ adc zh,r1 ;1
+ lpm insdecl,Z+ ;do_store
+ lpm insdech,Z+ ;do_op
+ lpm zl,Z ;do_fetch
+ ldi zh,high(fetch_ops)
+ ijmp ;direkt
+
+
+; .listmac
+;-----------------------------------------------------
+; Generate jump to target and position in table
+; gen_opjmp target
+;
+.macro gen_opjmp
+ .ifndef opjmp_table_pos_
+ .set opjmp_table_page_ = high(PC)
+ .set opjmp_table_pos_ = PC
+ .endif
+ .equ @0 = low(opjmp_table_pos_)
+ .set opjmp_table_pos_ = opjmp_table_pos_ + 1
+ .if high(opjmp_table_pos_) != opjmp_table_page_
+ .warning "Table 'opjump' crosses page boarder."
+ .message "Program will not work, unless the opjump table is relocated."
+ .endif
+ rjmp do_@0
+ .endm
+
+;--------------------------------------------------
+; Generate a table entry for one instruction
+;
+; instr fetch, op, store
+;
+.macro instr
+ .ifndef inst_table_odd_
+ .set inst_table_odd_ = 0
+ .endif
+
+ .if inst_table_odd_
+ .db inst_table_next_, low(@2), @1, low(@0)
+ .set inst_table_odd_ = 0
+ .else
+ .set inst_table_next_ = low(@0)
+ .db low(@2), @1
+ .set inst_table_odd_ = 1
+ .endif
+.endm
+
+;-----------------------------------
+; go to op.
+;
+.macro fetch_end
+ ldi zh,high(opjumps)
+ mov zl,insdech
+ ijmp
+.endm
+
+;-----------------------------------
+; go to store.
+;
+.macro op_end
+ ldi zh,high(store_ops) ;
+ mov zl,insdecl
+ ijmp
+.endm
+
+;-----------------------------------
+; go back to main
+;
+.macro store_end
+ rjmp main
+.endm
+
+;-----------------------------------
+; go back to main directly
+;
+.macro op_end_nojmp
+ rjmp main
+.endm
+
+
+; ------------ Fetch phase stuff -----------------
+
+.org (PC+255) & 0xff00
+fetch_ops:
+do_fetch_nop:
+ fetch_end
+
+do_fetch_a:
+ mov opl,z_a
+ fetch_end
+
+do_fetch_b:
+ lds opl,z_b
+ fetch_end
+
+do_fetch_c:
+ lds opl,z_c
+ fetch_end
+
+do_fetch_d:
+ lds opl,z_d
+ fetch_end
+
+do_fetch_e:
+ lds opl,z_e
+ fetch_end
+
+do_fetch_h:
+ lds opl,z_h
+ fetch_end
+
+do_fetch_l:
+ lds opl,z_l
+ fetch_end
+
+do_fetch_af:
+ mov opl,z_flags
+ mov oph,z_a
+ fetch_end
+
+do_fetch_bc:
+ lds opl,z_c
+ lds oph,z_b
+ fetch_end
+
+do_fetch_de:
+ lds opl,z_e
+ lds oph,z_d
+ fetch_end
+
+do_fetch_hl:
+ lds opl,z_l
+ lds oph,z_h
+ fetch_end
+
+do_fetch_sp:
+ movw opl,z_spl
+ fetch_end
+
+do_fetch_mbc:
+ lds xh,z_b
+ lds xl,z_c
+ mem_read_d opl
+ fetch_end
+
+do_fetch_mde:
+ lds xh,z_d
+ lds xl,z_e
+ mem_read_d opl
+ fetch_end
+
+do_fetch_mhl:
+ lds xh,z_h
+ lds xl,z_l
+ mem_read_d opl
+ fetch_end
+
+do_fetch_msp:
+ movw x,z_spl
+ mem_read_d opl
+ adiw x,1
+ mem_read_d oph
+ fetch_end
+
+do_fetch_dir8:
+ mem_read_ds opl, z_pc
+ adiw z_pcl,1
+ fetch_end
+
+do_fetch_dir16:
+ mem_read_ds opl, z_pc
+ adiw z_pcl,1
+ mem_read_ds oph, z_pc
+ adiw z_pcl,1
+ fetch_end
+
+do_fetch_rst:
+ movw x,z_pcl
+ sbiw x,1
+ mem_read_d opl
+ andi opl,0x38
+ ldi oph,0
+ fetch_end
+
+; ------------ Store phase stuff -----------------
+
+.org (PC+255) & 0xff00
+store_ops:
+do_store_nop:
+ store_end
+
+do_store_a:
+ mov z_a,opl
+ store_end
+
+do_store_b:
+ sts z_b,opl
+ store_end
+
+do_store_c:
+ sts z_c,opl
+ store_end
+
+do_store_d:
+ sts z_d,opl
+ store_end
+
+do_store_e:
+ sts z_e,opl
+ store_end
+
+do_store_h:
+ sts z_h,opl
+ store_end
+
+do_store_l:
+ sts z_l,opl
+ store_end
+
+do_store_af:
+ mov z_a,oph
+ mov z_flags,opl
+ store_end
+
+do_store_bc:
+ sts z_b,oph
+ sts z_c,opl
+ store_end
+
+do_store_de:
+ sts z_d,oph
+ sts z_e,opl
+ store_end
+
+do_store_hl:
+ sts z_h,oph
+ sts z_l,opl
+ store_end
+
+do_store_mbc:
+ lds xh,z_b
+ lds xl,z_c
+ mem_write_s opl
+ store_end
+
+do_store_mde:
+ lds xh,z_d
+ lds xl,z_e
+ mem_write_s opl
+ store_end
+
+do_store_mhl:
+ lds xh,z_h
+ lds xl,z_l
+ mem_write_s opl
+ store_end
+
+do_store_msp:
+ movw xl,z_spl
+ mem_write_s opl
+ adiw xl,1
+ mem_write_s oph
+ store_end
+
+do_store_sp:
+ movw z_spl,opl
+ store_end
+
+do_store_pc:
+ movw z_pcl,opl
+ store_end
+
+do_store_ret:
+ movw x,z_spl
+ mem_read_d z_pcl
+ adiw x,1
+ mem_read_d z_pch
+ adiw x,1
+ movw z_spl,x
+
+.if STACK_DBG
+ printnewline
+ printstring "Stack pop "
+ movw temp,z_pcl
+ rcall printhexw
+ printstring ", SP is now "
+ movw temp,z_spl
+ rcall printhexw
+ printstring ". "
+.endif
+ store_end
+
+do_store_call:
+ movw xl,z_spl
+ sbiw x,1
+ mem_write_s z_pch
+ sbiw x,1
+ mem_write_s z_pcl
+ movw z_spl,xl
+
+.if STACK_DBG
+ printnewline
+ printstring "Stack push "
+ movw temp,z_pcl
+ rcall printhexw
+ printstring ", SP is now "
+ movw temp,z_spl
+ rcall printhexw
+ printstring ". "
+.endif
+ movw z_pcl,opl
+ store_end
+
+
+do_store_am:
+ mem_write_ds op, z_a
+ store_end
+
+
+
+; ------------ Operation phase stuff -----------------
+
+;.org (PC+255) & 0xff00
+
+opjumps:
+ gen_opjmp op_nop
+ gen_opjmp op_inc
+ gen_opjmp op_dec
+ gen_opjmp op_inc16
+ gen_opjmp op_dec16
+ gen_opjmp op_rlc
+ gen_opjmp op_rrc
+ gen_opjmp op_rr
+ gen_opjmp op_rl
+ gen_opjmp op_adda
+ gen_opjmp op_adca
+ gen_opjmp op_subfa
+ gen_opjmp op_sbcfa
+ gen_opjmp op_anda
+ gen_opjmp op_ora
+ gen_opjmp op_xora
+ gen_opjmp op_addhl
+ gen_opjmp op_sthl
+ gen_opjmp op_rmem16
+ gen_opjmp op_rmem8
+ gen_opjmp op_da
+ gen_opjmp op_scf
+ gen_opjmp op_cpl
+ gen_opjmp op_ccf
+ gen_opjmp op_pop16
+ gen_opjmp op_push16
+ gen_opjmp op_ifnz
+ gen_opjmp op_ifz
+ gen_opjmp op_ifnc
+ gen_opjmp op_ifc
+ gen_opjmp op_ifpo
+ gen_opjmp op_ifpe
+ gen_opjmp op_ifp
+ gen_opjmp op_ifm
+ gen_opjmp op_outa
+ gen_opjmp op_in
+ gen_opjmp op_exhl
+ gen_opjmp op_di
+ gen_opjmp op_ei
+ gen_opjmp op_inv
+ gen_opjmp op_cpfa
+ gen_opjmp op_inca
+ gen_opjmp op_deca
+
+
+
+;----------------------------------------------------------------
+;| |
+;| Zilog |
+;| |
+;| ZZZZZZZ 88888 000 |
+;| Z 8 8 0 0 |
+;| Z 8 8 0 0 0 |
+;| Z 88888 0 0 0 |
+;| Z 8 8 0 0 0 |
+;| Z 8 8 0 0 |
+;| ZZZZZZZ 88888 000 |
+;| |
+;| Z80 MICROPROCESSOR Instruction Set Summary |
+;| |
+;----------------------------------------------------------------
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;|----------+------+---------------------+----------------------|
+;|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 |
+;|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 |
+;|CALL nn |------|Unconditional Call |-[SP]=PC,PC=nn |
+;|CCF |--?-0*|Complement Carry Flag|CY=~CY |
+;|CP s |***V1*|Compare |A-s |
+;|CPD |****1-|Compare and Decrement|A-[HL],HL=HL-1,BC=BC-1|
+;|CPDR |****1-|Compare, Dec., Repeat|CPD till A=[HL]or BC=0|
+;|CPI |****1-|Compare and Increment|A-[HL],HL=HL+1,BC=BC-1|
+;|CPIR |****1-|Compare, Inc., Repeat|CPI till A=[HL]or BC=0|
+;|CPL |--1-1-|Complement |A=~A |
+;|DAA |***P-*|Decimal Adjust Acc. |A=BCD format |
+;|DEC s |***V1-|Decrement |s=s-1 |
+;|DEC xx |------|Decrement |xx=xx-1 |
+;|DEC ss |------|Decrement |ss=ss-1 |
+;|DI |------|Disable Interrupts | |
+;|DJNZ e |------|Dec., Jump Non-Zero |B=B-1 till B=0 |
+;|EI |------|Enable Interrupts | |
+;|EX [SP],HL|------|Exchange |[SP]<->HL |
+;|EX [SP],xx|------|Exchange |[SP]<->xx |
+;|EX AF,AF' |------|Exchange |AF<->AF' |
+;|EX DE,HL |------|Exchange |DE<->HL |
+;|EXX |------|Exchange |qq<->qq' (except AF)|
+;|HALT |------|Halt | |
+;|IM n |------|Interrupt Mode | (n=0,1,2)|
+;|IN A,[n] |------|Input |A=[n] |
+;|IN r,[C] |***P0-|Input |r=[C] |
+;|INC r |***V0-|Increment |r=r+1 |
+;|INC [HL] |***V0-|Increment |[HL]=[HL]+1 |
+;|INC xx |------|Increment |xx=xx+1 |
+;|INC [xx+d]|***V0-|Increment |[xx+d]=[xx+d]+1 |
+;|INC ss |------|Increment |ss=ss+1 |
+;|IND |?*??1-|Input and Decrement |[HL]=[C],HL=HL-1,B=B-1|
+;|INDR |?1??1-|Input, Dec., Repeat |IND till B=0 |
+;|INI |?*??1-|Input and Increment |[HL]=[C],HL=HL+1,B=B-1|
+;|INIR |?1??1-|Input, Inc., Repeat |INI till B=0 |
+;|JP [HL] |------|Unconditional Jump |PC=[HL] |
+;|JP [xx] |------|Unconditional Jump |PC=[xx] |
+;|JP nn |------|Unconditional Jump |PC=nn |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|JR e |------|Unconditional Jump |PC=PC+e |
+;|JR cc,e |------|Conditional Jump |If cc JR(cc=C,NC,NZ,Z)|
+;|LD dst,src|------|Load |dst=src |
+;|LD A,i |**0*0-|Load |A=i (i=I,R)|
+;|LDD |--0*0-|Load and Decrement |[DE]=[HL],HL=HL-1,# |
+;|LDDR |--000-|Load, Dec., Repeat |LDD till BC=0 |
+;|LDI |--0*0-|Load and Increment |[DE]=[HL],HL=HL+1,# |
+;|LDIR |--000-|Load, Inc., Repeat |LDI till BC=0 |
+;|NEG |***V1*|Negate |A=-A |
+;|NOP |------|No Operation | |
+;|OR s |**0P00|Logical inclusive OR |A=Avs |
+;|OTDR |?1??1-|Output, Dec., Repeat |OUTD till B=0 |
+;|OTIR |?1??1-|Output, Inc., Repeat |OUTI till B=0 |
+;|OUT [C],r |------|Output |[C]=r |
+;|OUT [n],A |------|Output |[n]=A |
+;|OUTD |?*??1-|Output and Decrement |[C]=[HL],HL=HL-1,B=B-1|
+;|OUTI |?*??1-|Output and Increment |[C]=[HL],HL=HL+1,B=B-1|
+;|POP xx |------|Pop |xx=[SP]+ |
+;|POP qq |------|Pop |qq=[SP]+ |
+;|PUSH xx |------|Push |-[SP]=xx |
+;|PUSH qq |------|Push |-[SP]=qq |
+;|RES b,m |------|Reset bit |m=m&{~2^b} |
+;|RET |------|Return |PC=[SP]+ |
+;|RET cc |------|Conditional Return |If cc RET |
+;|RETI |------|Return from Interrupt|PC=[SP]+ |
+;|RETN |------|Return from NMI |PC=[SP]+ |
+;|RL m |**0P0*|Rotate Left |m={CY,m}<- |
+;|RLA |--0-0*|Rotate Left Acc. |A={CY,A}<- |
+;|RLC m |**0P0*|Rotate Left Circular |m=m<- |
+;|RLCA |--0-0*|Rotate Left Circular |A=A<- |
+;|RLD |**0P0-|Rotate Left 4 bits |{A,[HL]}={A,[HL]}<- ##|
+;|RR m |**0P0*|Rotate Right |m=->{CY,m} |
+;|RRA |--0-0*|Rotate Right Acc. |A=->{CY,A} |
+;|RRC m |**0P0*|Rotate Right Circular|m=->m |
+;|RRCA |--0-0*|Rotate Right Circular|A=->A |
+;|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 |
+;|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 |
+;|SRA m |**0P0*|Shift Right Arith. |m=m/2 |
+;|SRL m |**0P0*|Shift Right Logical |m=->{0,m,CY} |
+;|SUB s |***V1*|Subtract |A=A-s |
+;|XOR s |**0P00|Logical Exclusive OR |A=Axs |
+;|----------+------+--------------------------------------------|
+;| F |-*01? |Flag unaffected/affected/reset/set/unknown |
+;| S |S |Sign flag (Bit 7) |
+;| Z | Z |Zero flag (Bit 6) |
+;| HC | H |Half Carry flag (Bit 4) |
+;| P/V | P |Parity/Overflow flag (Bit 2, V=overflow) |
+;| N | N |Add/Subtract flag (Bit 1) |
+;| CY | C|Carry flag (Bit 0) |
+;|-----------------+--------------------------------------------|
+;| n |Immediate addressing |
+;| nn |Immediate extended addressing |
+;| e |Relative addressing (PC=PC+2+offset) |
+;| [nn] |Extended addressing |
+;| [xx+d] |Indexed addressing |
+;| r |Register addressing |
+;| [rr] |Register indirect addressing |
+;| |Implied addressing |
+;| b |Bit addressing |
+;| p |Modified page zero addressing (see RST) |
+;|-----------------+--------------------------------------------|
+;|DEFB n(,...) |Define Byte(s) |
+;|DEFB 'str'(,...) |Define Byte ASCII string(s) |
+;|DEFS nn |Define Storage Block |
+;|DEFW nn(,...) |Define Word(s) |
+;|-----------------+--------------------------------------------|
+;| A B C D E |Registers (8-bit) |
+;| AF BC DE HL |Register pairs (16-bit) |
+;| F |Flag register (8-bit) |
+;| I |Interrupt page address register (8-bit) |
+;| IX IY |Index registers (16-bit) |
+;| PC |Program Counter register (16-bit) |
+;| R |Memory Refresh register |
+;| SP |Stack Pointer register (16-bit) |
+;|-----------------+--------------------------------------------|
+;| b |One bit (0 to 7) |
+;| cc |Condition (C,M,NC,NZ,P,PE,PO,Z) |
+;| d |One-byte expression (-128 to +127) |
+;| dst |Destination s, ss, [BC], [DE], [HL], [nn] |
+;| e |One-byte expression (-126 to +129) |
+;| m |Any register r, [HL] or [xx+d] |
+;| n |One-byte expression (0 to 255) |
+;| nn |Two-byte expression (0 to 65535) |
+;| pp |Register pair BC, DE, IX or SP |
+;| qq |Register pair AF, BC, DE or HL |
+;| qq' |Alternative register pair AF, BC, DE or HL |
+;| r |Register A, B, C, D, E, H or L |
+;| rr |Register pair BC, DE, IY or SP |
+;| s |Any register r, value n, [HL] or [xx+d] |
+;| src |Source s, ss, [BC], [DE], [HL], nn, [nn] |
+;| ss |Register pair BC, DE, HL or SP |
+;| xx |Index register IX or IY |
+;|-----------------+--------------------------------------------|
+;| + - * / ^ |Add/subtract/multiply/divide/exponent |
+;| & ~ v x |Logical AND/NOT/inclusive OR/exclusive OR |
+;| <- -> |Rotate left/right |
+;| [ ] |Indirect addressing |
+;| [ ]+ -[ ] |Indirect addressing auto-increment/decrement|
+;| { } |Combination of operands |
+;| # |Also BC=BC-1,DE=DE-1 |
+;| ## |Only lower 4 bits of accumulator A used |
+;----------------------------------------------------------------
+
+;How the flags are supposed to work:
+;7 ZFL_S - Sign flag (=MSBit of result)
+;6 ZFL_Z - Zero flag. Is 1 when the result is 0
+;4 ZFL_H - Half-carry (carry from bit 3 to 4)
+;2 ZFL_P - Parity/2-complement Overflow
+;1 ZFL_N - Subtract - set if last op was a subtract
+;0 ZFL_C - Carry
+;
+;I sure hope I got the mapping between flags and instructions correct...
+
+.equ ZFL_S = 7
+.equ ZFL_Z = 6
+.equ ZFL_H = 4
+.equ ZFL_P = 2
+.equ ZFL_N = 1
+.equ ZFL_C = 0
+
+
+.equ AVR_T = SREG_T
+.equ AVR_H = SREG_H
+.equ AVR_S = SREG_S
+.equ AVR_V = SREG_V
+.equ AVR_N = SREG_N
+.equ AVR_Z = SREG_Z
+.equ AVR_C = SREG_C
+
+;------------------------------------------------;
+; Load table value from flash indexed by source reg.
+;
+; ldpmx dstreg,tablebase,indexreg
+;
+; (6 words, 8 cycles)
+
+.macro ldpmx
+ ldi zh,high(@1*2) ; table must be page aligned
+ mov zl,@2
+ lpm @0,z
+.endm
+
+.macro do_z80_flags_HP
+#if EM_Z80
+ bmov z_flags, ZFL_P, temp, AVR_V
+ 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_set_HN
+#if EM_Z80
+ ori z_flags,(1<<ZFL_N)|(1<<ZFL_H)
+#endif
+.endm
+
+.macro do_z80_flags_clear_N
+#if EM_Z80
+ andi z_flags,~(1<<ZFL_N)
+#endif
+.endm
+
+.macro do_z80_flags_op_rotate
+ ; must not change avr carry flag!
+#if EM_Z80
+ andi z_flags, ~( (1<<ZFL_H) | (1<<ZFL_N) | (1<<ZFL_C) )
+#else
+ andi z_flags, ~( (1<<ZFL_C) )
+#endif
+.endm
+
+.macro do_z80_flags_op_and
+#if EM_Z80
+ ori z_flags,(1<<ZFL_H)
+#else
+ ori z_flags,(1<<ZFL_H)
+#endif
+.endm
+
+.macro do_z80_flags_op_or
+#if EM_Z80
+#endif
+.endm
+
+
+;----------------------------------------------------------------
+
+do_op_inv:
+ printstring "Invalid opcode @ PC="
+ movw temp,z_pcl
+ rcall printhexw
+
+haltinv:
+ rjmp haltinv
+
+do_op_nop:
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|OUT [n],A |------|Output |[n]=A |
+;
+;
+;Interface with peripherials goes here :)
+do_op_outa: ; out (opl),a
+.if PORT_DEBUG
+ printnewline
+ printstring "Port write: "
+ mov temp,z_a
+ rcall printhex
+ printstring " -> ("
+ mov temp,opl
+ rcall printhex
+ printstring ") "
+.endif
+ mov temp,z_a
+ mov temp2,opl
+ rcall portWrite
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|IN A,[n] |------|Input |A=[n] |
+;
+;
+do_op_in: ; in a,(opl)
+.if PORT_DEBUG
+ printnewline
+ printstring "Port read: ("
+ mov temp,opl
+ rcall printhex
+ printstring ") -> "
+.endif
+
+ mov temp2,opl
+ rcall portRead
+ mov opl,temp
+
+.if PORT_DEBUG
+ rcall printhex
+ printstring " "
+.endif
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|INC r |***V0-|Increment |r=r+1 |
+;|INC [HL] |***V0-|Increment |[HL]=[HL]+1 |
+;|INC [xx+d]|***V0-|Increment |[xx+d]=[xx+d]+1 |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|INC r |**-P0-|Increment |r=r+1 |
+;|INC [HL] |**-P0-|Increment |[HL]=[HL]+1 |
+;
+;
+do_op_inc:
+ inc opl
+#if EM_Z80
+ in temp, sreg
+#endif
+ andi z_flags,(1<<ZFL_H)|(1<<ZFL_C) ; preserve C-, and H-flag
+ ldpmx temp2, sz53p_tab, opl
+ or z_flags,temp2 ;
+ do_z80_flags_HP
+ op_end
+
+do_op_inca:
+ inc z_a
+#if EM_Z80
+ in temp, sreg
+#endif
+ andi z_flags,(1<<ZFL_H)|(1<<ZFL_C) ; preserve C-, and H-flag
+ ldpmx temp2, sz53p_tab, z_a
+ or z_flags,temp2 ;
+ do_z80_flags_HP
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|DEC r |***V1-|Decrement |s=s-1 |
+;|INC [HL] |***V0-|Increment |[HL]=[HL]+1 |
+;|INC [xx+d]|***V0-|Increment |[xx+d]=[xx+d]+1 |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|DEC r |**-P -|Increment |r=r+1 |
+;|DEC [HL] |**-P -|Increment |[HL]=[HL]+1 |
+;
+;
+do_op_dec:
+ dec opl
+#if EM_Z80
+ in temp, sreg
+#endif
+ andi z_flags,(1<<ZFL_H)|(1<<ZFL_C) ; preserve C-, and H-flag
+ ldpmx temp2, sz53p_tab, opl
+ or z_flags,temp2 ;
+ do_z80_flags_HP
+ do_z80_flags_set_N
+ op_end
+
+do_op_deca:
+ dec z_a
+#if EM_Z80
+ in temp, sreg
+#endif
+ andi z_flags,(1<<ZFL_H)|(1<<ZFL_C) ; preserve C-, and H-flag
+ ldpmx temp2, sz53p_tab, z_a
+ or z_flags,temp2 ;
+ do_z80_flags_HP
+ do_z80_flags_set_N
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|INC xx |------|Increment |xx=xx+1 |
+;|INC ss |------|Increment |ss=ss+1 |
+;
+;
+do_op_inc16:
+ subi opl,low(-1)
+ sbci oph,high(-1)
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|DEC xx |------|Decrement |xx=xx-1 |
+;|DEC ss |------|Decrement |ss=ss-1 |
+;
+;
+do_op_dec16:
+ subi opl, 1
+ sbci oph, 0
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|RLCA |--0-0*|Rotate Left Circular |A=A<- |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|RLCA |---- *|Rotate Left Circular |A=A<- |
+;
+;
+do_op_rlc:
+ ;Rotate Left Cyclical. All bits move 1 to the
+ ;left, the msb becomes c and lsb.
+ do_z80_flags_op_rotate
+ lsl opl
+ brcc do_op_rlc_noc
+ ori opl, 1
+ ori z_flags, (1<<ZFL_C)
+do_op_rlc_noc:
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|RRCA |--0-0*|Rotate Right Circular|A=->A |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|RRCA |---- *|Rotate Right Circular|A=->A |
+;
+;
+do_op_rrc:
+ ;Rotate Right Cyclical. All bits move 1 to the
+ ;right, the lsb becomes c and msb.
+ do_z80_flags_op_rotate
+ lsr opl
+ brcc do_op_rrc_noc
+ ori opl, 0x80
+ ori z_flags, (1<<ZFL_C)
+do_op_rrc_noc:
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|RRA |--0-0*|Rotate Right Acc. |A=->{CY,A} |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|RRA |---- *|Rotate Right Acc. |A=->{CY,A} |
+;
+;
+do_op_rr:
+ ;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
+ sec
+ do_z80_flags_op_rotate ; (clear ZFL_C, doesn't change AVR_C)
+ bmov z_flags,ZFL_C, opl,0 ; Bit 0 --> CY
+ ror opl
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|RLA |--0-0*|Rotate Left Acc. |A={CY,A}<- |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|RLA |---- *|Rotate Left Acc. |A={CY,A}<- |
+;
+;
+do_op_rl:
+ ;Rotate Left. All bits move 1 to the left, the msb
+ ;becomes c, c becomes lsb.
+ clc
+ sbrc z_flags,ZFL_C
+ sec
+ do_z80_flags_op_rotate ; (clear ZFL_C, doesn't change AVR_C)
+ bmov z_flags,ZFL_C, opl,7 ; Bit 7 --> CY
+ rol opl
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|ADD A,s |***V0*|Add |A=A+s |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|ADD A,s |***P *|Add |A=A+s |
+;
+;
+do_op_adda:
+ add z_a,opl
+ in temp,sreg
+ ldpmx z_flags,sz53p_tab,z_a ;S,Z,P flag
+ bmov z_flags,ZFL_C, temp,AVR_C
+ do_z80_flags_HP
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|ADC A,s |***V0*|Add with Carry |A=A+s+CY |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|ADC A,s |***P *|Add with Carry |A=A+s+CY |
+;
+;
+do_op_adca:
+ clc
+ sbrc z_flags,ZFL_C
+ sec
+ adc z_a,opl
+ in temp,sreg
+ ldpmx z_flags,sz53p_tab,z_a ;S,Z,P
+ bmov z_flags,ZFL_C, temp,AVR_C
+ do_z80_flags_HP
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|SUB s |***V1*|Subtract |A=A-s |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|SUB s |***P *|Subtract |A=A-s |
+
+;
+do_op_subfa:
+ sub z_a,opl
+ in temp,sreg
+ ldpmx z_flags,sz53p_tab,z_a ;S,Z,P
+ bmov z_flags,ZFL_C, temp,AVR_C
+ do_z80_flags_HP
+ do_z80_flags_set_N
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CP s |***V1*|Compare |A-s |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|CP s |***P *|Compare |A-s |
+
+;
+do_op_cpfa:
+ mov temp,z_a
+ sub temp,opl
+ mov opl,temp
+ in temp,sreg
+ ldpmx z_flags,sz53p_tab,opl ;S,Z,P
+ bmov z_flags,ZFL_C, temp,AVR_C
+ do_z80_flags_HP
+ do_z80_flags_set_N
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|SBC A,s |***V1*|Subtract with Carry |A=A-s-CY |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|SBC A,s |***P *|Subtract with Carry |A=A-s-CY |
+;
+;
+do_op_sbcfa:
+ clc
+ sbrc z_flags,ZFL_C
+ sec
+ sbc z_a,opl
+ in temp,sreg
+ ldpmx z_flags,sz53p_tab,z_a ;S,Z,P
+ bmov z_flags,ZFL_C, temp,AVR_C
+ do_z80_flags_HP
+ do_z80_flags_set_N
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|AND s |**1P00|Logical AND |A=A&s |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|AND s |**-P 0|Logical AND |A=A&s |
+;
+; TODO H-Flag
+do_op_anda:
+ and z_a,opl ;
+ ldpmx z_flags,sz53p_tab,z_a ;S,Z,P,N,C
+ do_z80_flags_op_and
+ op_end
+
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|OR s |**0P00|Logical inclusive OR |A=Avs |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|OR s |**-P00|Logical inclusive OR |A=Avs |
+;
+; TODO: H-Flag
+do_op_ora:
+ or z_a,opl
+ ldpmx z_flags,sz53p_tab,z_a ;S,Z,H,P,N,C
+ do_z80_flags_op_or
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|XOR s |**0P00|Logical Exclusive OR |A=Axs |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|XOR s |**-P 0|Logical Exclusive OR |A=Axs |
+;
+; TODO: H-Flag
+do_op_xora:
+ eor z_a,opl
+ ldpmx z_flags,sz53p_tab,z_a ;S,Z,H,P,N,C
+ do_z80_flags_op_or
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|ADD HL,ss |--?-0*|Add |HL=HL+ss |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|ADD HL,ss |---- *|Add |HL=HL+ss |
+;
+;
+do_op_addhl:
+ lds temp,z_l
+ lds temp2,z_h
+ add opl,temp
+ adc oph,temp2
+ in temp,sreg
+ bmov z_flags,ZFL_H, temp,AVR_H
+ bmov z_flags,ZFL_C, temp,AVR_C
+ do_z80_flags_clear_N
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|LD dst,src|------|Load |dst=src |
+;
+;
+do_op_sthl: ;store hl to mem loc in opl:h
+ movw xl,opl
+ lds temp,z_l
+ mem_write
+ adiw xl,1
+ lds temp,z_h
+ mem_write
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|LD dst,src|------|Load |dst=src |
+;
+;
+do_op_rmem16:
+ movw xl,opl
+ mem_read_d opl
+ adiw x,1
+ mem_read_d oph
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|LD dst,src|------|Load |dst=src |
+;
+;
+do_op_rmem8:
+ mem_read_ds opl, op
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|DAA |***P-*|Decimal Adjust Acc. | |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;
+; Not yet checked
+
+; Description (http://www.z80.info/z80syntx.htm#DAA):
+; This instruction conditionally adjusts the accumulator for BCD addition
+; and subtraction operations. For addition (ADD, ADC, INC) or subtraction
+; (SUB, SBC, DEC, NEC), the following table indicates the operation performed:
+;
+; -------------------------------------------------------------------------------
+; | | C Flag | HEX value in | H Flag | HEX value in | Number | C flag|
+; | Operation| Before | upper digit | Before | lower digit | added | After |
+; | | DAA | (bit 7-4) | DAA | (bit 3-0) | to byte | DAA |
+; |-----------------------------------------------------------------------------|
+; | | 0 | 0-9 | 0 | 0-9 | 00 | 0 |
+; | ADD | 0 | 0-8 | 0 | A-F | 06 | 0 |
+; | | 0 | 0-9 | 1 | 0-3 | 06 | 0 |
+; | ADC | 0 | A-F | 0 | 0-9 | 60 | 1 |
+; | | 0 | 9-F | 0 | A-F | 66 | 1 |
+; | INC | 0 | A-F | 1 | 0-3 | 66 | 1 |
+; | | 1 | 0-2 | 0 | 0-9 | 60 | 1 |
+; | | 1 | 0-2 | 0 | A-F | 66 | 1 |
+; | | 1 | 0-3 | 1 | 0-3 | 66 | 1 |
+; |-----------------------------------------------------------------------------|
+; | SUB | 0 | 0-9 | 0 | 0-9 | 00 | 0 |
+; | SBC | 0 | 0-8 | 1 | 6-F | FA | 0 |
+; | DEC | 1 | 7-F | 0 | 0-9 | A0 | 1 |
+; | NEG | 1 | 6-F | 1 | 6-F | 9A | 1 |
+; |-----------------------------------------------------------------------------|
+;
+; Flags:
+; C: See instruction.
+; N: Unaffected.
+; P/V: Set if Acc. is even parity after operation, reset otherwise.
+; H: See instruction.
+; 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:
+ ldi oph,0 ; what to add
+ sbrc z_flags,ZFL_H ; if H-Flag
+ rjmp op_da_06
+ mov temp,opl
+ andi temp,0x0f ; ... or lower digit > 9
+ cpi temp,0x0a
+ brlo op_da_06n
+op_da_06:
+ ori oph,0x06
+op_da_06n:
+ sbrc z_flags,(1<<ZFL_C)
+ rjmp op_da_60
+ cpi opl,0xa0
+ brlo op_da_60n
+op_da_60:
+ ori oph,0x60
+op_da_60n:
+ cpi opl,0x9a
+ brlo op_da_99n
+ ori z_flags,(1<<ZFL_C); set C
+op_da_99n:
+ sbrs z_flags,ZFL_N ; if sub-op
+ rjmp op_da_add ; then
+ sub opl,oph
+ rjmp op_da_ex
+op_da_add: ; else add-op
+ cpi opl,0x91
+ brlo op_da_60n2
+ mov temp,opl
+ andi temp,0x0f
+ cpi temp,0x0a
+ brlo op_da_60n2
+ ori oph,0x60
+op_da_60n2:
+ add opl,oph
+op_da_ex:
+ in temp,SREG
+ sbrc temp,AVR_H
+ ori z_flags,(1<<ZFL_C)
+ andi z_flags,(1<<ZFL_N)|(1<<ZFL_C) ; preserve C,N
+ ldpmx temp2, sz53p_tab, opl ; get S,Z,P
+ or z_flags,temp2
+ bmov z_flags,ZFL_H, temp,AVR_H ; H (?)
+ op_end
+#else
+
+do_op_da:
+ sbrc z_flags,ZFL_N ; if add-op
+ rjmp do_op_da_sub ; then
+ ldi temp2,0 ;
+ mov temp,opl ;
+ andi temp,0x0f ;
+ cpi temp,0x0a ; if lower digit > 9
+ brlo do_op_da_h ;
+ ori temp2,0x06 ; add 6 to lower digit
+do_op_da_h: ;
+ sbrc z_flags,ZFL_H ; ... or H-Flag
+ ori temp2,0x06 ;
+ add opl,temp2 ;
+
+ ldi temp2,0 ;
+ mov temp,opl ;
+ andi temp,0xf0 ;
+ cpi temp,0xa0 ;
+ brlo do_op_da_c ;
+ ori temp2,0x60 ;
+do_op_da_c: ; else sub-op
+ sbrc z_flags,ZFL_C ;
+ ori temp2,0x60 ;
+ andi z_flags, ~( (1<<ZFL_S) | (1<<ZFL_Z) | (1<<ZFL_H) )
+ add opl,temp2 ;
+ in temp,SREG ;
+ bst temp,AVR_Z ;Z-Flag
+ bld z_flags,ZFL_Z ;
+ bst temp,AVR_N ;S-Flag
+ bst z_flags,ZFL_S ;
+ sbrc temp2,5 ;C-Flag, set if 0x06 added
+ ori z_flags,(1<<ZFL_C) ;
+ ;H-Flag?
+ op_end
+
+do_op_da_sub: ;TODO:
+ rcall do_op_inv
+ op_end
+#endif
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|SCF |--0-01|Set Carry Flag |CY=1 |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;
+;
+do_op_scf:
+ andi z_flags,~((1<<ZFL_H)|(1<<ZFL_N))
+ ori z_flags,(1<<ZFL_C)
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CCF |--?-0*|Complement Carry Flag|CY=~CY |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|SCF |---- 1|Set Carry Flag |CY=1 |
+;
+;TODO: H-Flag
+do_op_ccf:
+ do_z80_flags_clear_N
+ ldi temp,(1<<ZFL_C)
+ eor z_flags,temp
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CPL |--1-1-|Complement |A=~A |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|CPL |---- -|Complement |A=~A |
+;
+;
+do_op_cpl:
+ com z_a
+ do_z80_flags_set_HN
+ op_end
+
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|PUSH xx |------|Push |-[SP]=xx |
+;|PUSH qq |------|Push |-[SP]=qq |
+;
+;
+do_op_push16:
+ movw xl,z_spl
+ sbiw x,1
+ mem_write_s oph
+ sbiw x,1
+ mem_write_s opl
+ movw z_spl,xl
+
+.if STACK_DBG
+ printnewline
+ printstring "Stack push "
+ movw temp,opl
+ rcall printhexw
+ printstring ", SP is now "
+ movw temp,z_spl
+ rcall printhexw
+ printstring ". "
+.endif
+
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|POP xx |------|Pop |xx=[SP]+ |
+;|POP qq |------|Pop |qq=[SP]+ |
+;
+;
+do_op_pop16:
+ movw x,z_spl
+ mem_read_d opl
+ adiw x,1
+ mem_read_d oph
+ adiw x,1
+ movw z_spl,x
+
+.if STACK_DBG
+ printnewline
+ printstring "Stack pop "
+ movw temp,opl
+ rcall printhexw
+ printstring ", SP is now "
+ movw temp,z_spl
+ rcall printhexw
+ printstring ". "
+.endif
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|EX [SP],HL|------|Exchange |[SP]<->HL |
+;|EX DE,HL |------|Exchange |DE<->HL |
+;-----------------------------Z80--------------------------------
+;
+do_op_exhl:
+ lds temp,z_l
+ lds temp2,z_h
+ sts z_l,opl
+ sts z_h,oph
+ movw opl,temp
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;
+; TODO: Implement IFF1, IFF2
+do_op_di:
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;
+; TODO: Implement IFF1, IFF2
+do_op_ei:
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CALL cc,nn|------|Conditional Call |If cc CALL |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|RET cc |------|Conditional Return |If cc RET |
+;
+;
+do_op_ifnz:
+ sbrc z_flags, ZFL_Z
+ op_end_nojmp
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CALL cc,nn|------|Conditional Call |If cc CALL |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|RET cc |------|Conditional Return |If cc RET |
+;
+;
+do_op_ifz:
+ sbrs z_flags, ZFL_Z
+ op_end_nojmp
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CALL cc,nn|------|Conditional Call |If cc CALL |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|RET cc |------|Conditional Return |If cc RET |
+;
+;
+do_op_ifnc:
+ sbrc z_flags, ZFL_C
+ op_end_nojmp
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CALL cc,nn|------|Conditional Call |If cc CALL |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|RET cc |------|Conditional Return |If cc RET |
+;
+;
+do_op_ifc:
+ sbrs z_flags, ZFL_C
+ op_end_nojmp
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CALL cc,nn|------|Conditional Call |If cc CALL |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|RET cc |------|Conditional Return |If cc RET |
+;
+;
+do_op_ifpo:
+ sbrc z_flags, ZFL_P
+ op_end_nojmp
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CALL cc,nn|------|Conditional Call |If cc CALL |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|RET cc |------|Conditional Return |If cc RET |
+;
+;
+do_op_ifpe:
+ sbrs z_flags, ZFL_P
+ op_end_nojmp
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CALL cc,nn|------|Conditional Call |If cc CALL |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|RET cc |------|Conditional Return |If cc RET |
+;
+;
+do_op_ifp: ;sign positive, aka s=0
+ sbrc z_flags, ZFL_S
+ op_end_nojmp
+ op_end
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CALL cc,nn|------|Conditional Call |If cc CALL |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|RET cc |------|Conditional Return |If cc RET |
+;
+;
+do_op_ifm: ;sign negative, aka s=1
+ sbrs z_flags, ZFL_S
+ op_end_nojmp
+ op_end
+
+
+; ----------------------- 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.
+
+;.org (PC+255) & 0xff00
+todo_table:
+instr do_fetch_nop, op_nop, do_store_nop ;00 ;NOP
+instr do_fetch_DIR16, op_nop, do_store_BC ;01 nn nn ;LD BC,nn
+instr do_fetch_A, op_nop, do_store_MBC ;02 ;LD (BC),A
+instr do_fetch_BC, op_INC16, do_store_BC ;03 ;INC BC
+instr do_fetch_B, op_INC, do_store_B ;04 ;INC B
+instr do_fetch_B, op_DEC, do_store_B ;05 ;DEC B
+instr do_fetch_DIR8, op_nop, do_store_B ;06 ;LD B,n
+instr do_fetch_A, op_RLC, do_store_A ;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_MBC, op_nop, do_store_A ;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_C, op_DEC, do_store_C ;0D ;DEC C
+instr do_fetch_DIR8, op_nop, do_store_C ;0E nn ;LD C,n
+instr do_fetch_A, op_RRC, do_store_A ;0F ;RRCA
+instr do_fetch_nop, op_INV, do_store_nop ;10 oo ;DJNZ o
+instr do_fetch_DIR16, op_nop, do_store_DE ;11 nn nn ;LD DE,nn
+instr do_fetch_A, op_nop, do_store_MDE ;12 ;LD (DE),A
+instr do_fetch_DE, op_INC16, do_store_DE ;13 ;INC DE
+instr do_fetch_D, op_INC, do_store_D ;14 ;INC D
+instr do_fetch_D, op_DEC, do_store_D ;15 ;DEC D
+instr do_fetch_DIR8, op_nop, do_store_D ;16 nn ;LD D,n
+instr do_fetch_A, op_RL, do_store_A ;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_MDE, op_nop, do_store_A ;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_E, op_DEC, do_store_E ;1D ;DEC E
+instr do_fetch_DIR8, op_nop, do_store_E ;1E nn ;LD E,n
+instr do_fetch_A, op_RR, do_store_A ;1F ;RRA
+instr do_fetch_nop, op_INV, do_store_nop ;20 oo ;JR NZ,o
+instr do_fetch_DIR16, op_nop, do_store_HL ;21 nn nn ;LD HL,nn
+instr do_fetch_DIR16, op_STHL, do_store_nop ;22 nn nn ;LD (nn),HL
+instr do_fetch_HL, op_INC16, do_store_HL ;23 ;INC HL
+instr do_fetch_H, op_INC, do_store_H ;24 ;INC H
+instr do_fetch_H, op_DEC, do_store_H ;25 ;DEC H
+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_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_L, op_DEC, do_store_L ;2D ;DEC L
+instr do_fetch_DIR8, op_nop, do_store_L ;2E nn ;LD L,n
+instr do_fetch_nop, op_CPL, do_store_nop ;2F ;CPL
+instr do_fetch_nop, op_INV, do_store_nop ;30 oo ;JR NC,o
+instr do_fetch_DIR16, op_nop, do_store_SP ;31 nn nn ;LD SP,nn
+instr do_fetch_DIR16, op_nop, do_store_AM ;32 nn nn ;LD (nn),A
+instr do_fetch_SP, op_INC16, do_store_SP ;33 ;INC SP
+instr do_fetch_MHL, op_INC, do_store_MHL ;34 ;INC (HL)
+instr do_fetch_MHL, op_DEC, do_store_MHL ;35 ;DEC (HL)
+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_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_DECA, do_store_nop ;3D ;DEC A
+instr do_fetch_DIR8, op_nop, do_store_A ;3E nn ;LD A,n
+instr do_fetch_nop, op_CCF, do_store_nop ;3F ;CCF (Complement Carry Flag, gvd)
+instr do_fetch_B, op_nop, do_store_B ;40 ;LD B,B
+instr do_fetch_C, op_nop, do_store_B ;41 ;LD B,C
+instr do_fetch_D, op_nop, do_store_B ;42 ;LD B,D
+instr do_fetch_E, op_nop, do_store_B ;43 ;LD B,E
+instr do_fetch_H, op_nop, do_store_B ;44 ;LD B,H
+instr do_fetch_L, op_nop, do_store_B ;45 ;LD B,L
+instr do_fetch_MHL, op_nop, do_store_B ;46 ;LD B,(HL)
+instr do_fetch_A, op_nop, do_store_B ;47 ;LD B,A
+instr do_fetch_B, op_nop, do_store_C ;48 ;LD C,B
+instr do_fetch_C, op_nop, do_store_C ;49 ;LD C,C
+instr do_fetch_D, op_nop, do_store_C ;4A ;LD C,D
+instr do_fetch_E, op_nop, do_store_C ;4B ;LD C,E
+instr do_fetch_H, op_nop, do_store_C ;4C ;LD C,H
+instr do_fetch_L, op_nop, do_store_C ;4D ;LD C,L
+instr do_fetch_MHL, op_nop, do_store_C ;4E ;LD C,(HL)
+instr do_fetch_A, op_nop, do_store_C ;4F ;LD C,A
+instr do_fetch_B, op_nop, do_store_D ;50 ;LD D,B
+instr do_fetch_C, op_nop, do_store_D ;51 ;LD D,C
+instr do_fetch_D, op_nop, do_store_D ;52 ;LD D,D
+instr do_fetch_E, op_nop, do_store_D ;53 ;LD D,E
+instr do_fetch_H, op_nop, do_store_D ;54 ;LD D,H
+instr do_fetch_L, op_nop, do_store_D ;55 ;LD D,L
+instr do_fetch_MHL, op_nop, do_store_D ;56 ;LD D,(HL)
+instr do_fetch_A, op_nop, do_store_D ;57 ;LD D,A
+instr do_fetch_B, op_nop, do_store_E ;58 ;LD E,B
+instr do_fetch_C, op_nop, do_store_E ;59 ;LD E,C
+instr do_fetch_D, op_nop, do_store_E ;5A ;LD E,D
+instr do_fetch_E, op_nop, do_store_E ;5B ;LD E,E
+instr do_fetch_H, op_nop, do_store_E ;5C ;LD E,H
+instr do_fetch_L, op_nop, do_store_E ;5D ;LD E,L
+instr do_fetch_MHL, op_nop, do_store_E ;5E ;LD E,(HL)
+instr do_fetch_A, op_nop, do_store_E ;5F ;LD E,A
+instr do_fetch_B, op_nop, do_store_H ;60 ;LD H,B
+instr do_fetch_C, op_nop, do_store_H ;61 ;LD H,C
+instr do_fetch_D, op_nop, do_store_H ;62 ;LD H,D
+instr do_fetch_E, op_nop, do_store_H ;63 ;LD H,E
+instr do_fetch_H, op_nop, do_store_H ;64 ;LD H,H
+instr do_fetch_L, op_nop, do_store_H ;65 ;LD H,L
+instr do_fetch_MHL, op_nop, do_store_H ;66 ;LD H,(HL)
+instr do_fetch_A, op_nop, do_store_H ;67 ;LD H,A
+instr do_fetch_B, op_nop, do_store_L ;68 ;LD L,B
+instr do_fetch_C, op_nop, do_store_L ;69 ;LD L,C
+instr do_fetch_D, op_nop, do_store_L ;6A ;LD L,D
+instr do_fetch_E, op_nop, do_store_L ;6B ;LD L,E
+instr do_fetch_H, op_nop, do_store_L ;6C ;LD L,H
+instr do_fetch_L, op_nop, do_store_L ;6D ;LD L,L
+instr do_fetch_MHL, op_nop, do_store_L ;6E ;LD L,(HL)
+instr do_fetch_A, op_nop, do_store_L ;6F ;LD L,A
+instr do_fetch_B, op_nop, do_store_MHL ;70 ;LD (HL),B
+instr do_fetch_C, op_nop, do_store_MHL ;71 ;LD (HL),C
+instr do_fetch_D, op_nop, do_store_MHL ;72 ;LD (HL),D
+instr do_fetch_E, op_nop, do_store_MHL ;73 ;LD (HL),E
+instr do_fetch_H, op_nop, do_store_MHL ;74 ;LD (HL),H
+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_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_H, op_nop, do_store_A ;7C ;LD A,H
+instr do_fetch_L, op_nop, do_store_A ;7D ;LD A,L
+instr do_fetch_MHL, op_nop, do_store_A ;7E ;LD A,(HL)
+instr do_fetch_A, op_nop, do_store_A ;7F ;LD A,A
+instr do_fetch_B, op_ADDA, do_store_nop ;80 ;ADD A,B
+instr do_fetch_C, op_ADDA, do_store_nop ;81 ;ADD A,C
+instr do_fetch_D, op_ADDA, do_store_nop ;82 ;ADD A,D
+instr do_fetch_E, op_ADDA, do_store_nop ;83 ;ADD A,E
+instr do_fetch_H, op_ADDA, do_store_nop ;84 ;ADD A,H
+instr do_fetch_L, op_ADDA, do_store_nop ;85 ;ADD A,L
+instr do_fetch_MHL, op_ADDA, do_store_nop ;86 ;ADD A,(HL)
+instr do_fetch_A, op_ADDA, do_store_nop ;87 ;ADD A,A
+instr do_fetch_B, op_ADCA, do_store_nop ;88 ;ADC A,B
+instr do_fetch_C, op_ADCA, do_store_nop ;89 ;ADC A,C
+instr do_fetch_D, op_ADCA, do_store_nop ;8A ;ADC A,D
+instr do_fetch_E, op_ADCA, do_store_nop ;8B ;ADC A,E
+instr do_fetch_H, op_ADCA, do_store_nop ;8C ;ADC A,H
+instr do_fetch_L, op_ADCA, do_store_nop ;8D ;ADC A,L
+instr do_fetch_MHL, op_ADCA, do_store_nop ;8E ;ADC A,(HL)
+instr do_fetch_A, op_ADCA, do_store_nop ;8F ;ADC A,A
+instr do_fetch_B, op_SUBFA, do_store_nop ;90 ;SUB A,B
+instr do_fetch_C, op_SUBFA, do_store_nop ;91 ;SUB A,C
+instr do_fetch_D, op_SUBFA, do_store_nop ;92 ;SUB A,D
+instr do_fetch_E, op_SUBFA, do_store_nop ;93 ;SUB A,E
+instr do_fetch_H, op_SUBFA, do_store_nop ;94 ;SUB A,H
+instr do_fetch_L, op_SUBFA, do_store_nop ;95 ;SUB A,L
+instr do_fetch_MHL, op_SUBFA, do_store_nop ;96 ;SUB A,(HL)
+instr do_fetch_A, op_SUBFA, do_store_nop ;97 ;SUB A,A
+instr do_fetch_B, op_SBCFA, do_store_nop ;98 ;SBC A,B
+instr do_fetch_C, op_SBCFA, do_store_nop ;99 ;SBC A,C
+instr do_fetch_D, op_SBCFA, do_store_nop ;9A ;SBC A,D
+instr do_fetch_E, op_SBCFA, do_store_nop ;9B ;SBC A,E
+instr do_fetch_H, op_SBCFA, do_store_nop ;9C ;SBC A,H
+instr do_fetch_L, op_SBCFA, do_store_nop ;9D ;SBC A,L
+instr do_fetch_MHL, op_SBCFA, do_store_nop ;9E ;SBC A,(HL)
+instr do_fetch_A, op_SBCFA, do_store_nop ;9F ;SBC A,A
+instr do_fetch_B, op_ANDA, do_store_nop ;A0 ;AND A,B
+instr do_fetch_C, op_ANDA, do_store_nop ;A1 ;AND A,C
+instr do_fetch_D, op_ANDA, do_store_nop ;A2 ;AND A,D
+instr do_fetch_E, op_ANDA, do_store_nop ;A3 ;AND A,E
+instr do_fetch_H, op_ANDA, do_store_nop ;A4 ;AND A,H
+instr do_fetch_L, op_ANDA, do_store_nop ;A5 ;AND A,L
+instr do_fetch_MHL, op_ANDA, do_store_nop ;A6 ;AND A,(HL)
+instr do_fetch_A, op_ANDA, do_store_nop ;A7 ;AND A,A
+instr do_fetch_B, op_XORA, do_store_nop ;A8 ;XOR A,B
+instr do_fetch_C, op_XORA, do_store_nop ;A9 ;XOR A,C
+instr do_fetch_D, op_XORA, do_store_nop ;AA ;XOR A,D
+instr do_fetch_E, op_XORA, do_store_nop ;AB ;XOR A,E
+instr do_fetch_H, op_XORA, do_store_nop ;AC ;XOR A,H
+instr do_fetch_L, op_XORA, do_store_nop ;AD ;XOR A,L
+instr do_fetch_MHL, op_XORA, do_store_nop ;AE ;XOR A,(HL)
+instr do_fetch_A, op_XORA, do_store_nop ;AF ;XOR A,A
+instr do_fetch_B, op_ORA, do_store_nop ;B0 ;OR A,B
+instr do_fetch_C, op_ORA, do_store_nop ;B1 ;OR A,C
+instr do_fetch_D, op_ORA, do_store_nop ;B2 ;OR A,D
+instr do_fetch_E, op_ORA, do_store_nop ;B3 ;OR A,E
+instr do_fetch_H, op_ORA, do_store_nop ;B4 ;OR A,H
+instr do_fetch_L, op_ORA, do_store_nop ;B5 ;OR A,L
+instr do_fetch_MHL, op_ORA, do_store_nop ;B6 ;OR A,(HL)
+instr do_fetch_A, op_ORA, do_store_nop ;B7 ;OR A,A
+instr do_fetch_B, op_CPFA, do_store_nop ;B8 ;CP A,B
+instr do_fetch_C, op_CPFA, do_store_nop ;B9 ;CP A,C
+instr do_fetch_D, op_CPFA, do_store_nop ;BA ;CP A,D
+instr do_fetch_E, op_CPFA, do_store_nop ;BB ;CP A,E
+instr do_fetch_H, op_CPFA, do_store_nop ;BC ;CP A,H
+instr do_fetch_L, op_CPFA, do_store_nop ;BD ;CP A,L
+instr do_fetch_MHL, op_CPFA, do_store_nop ;BE ;CP A,(HL)
+instr do_fetch_A, op_CPFA, do_store_nop ;BF ;CP A,A
+instr do_fetch_nop, op_IFNZ, do_store_RET ;C0 ;RET NZ
+instr do_fetch_nop, op_POP16, do_store_BC ;C1 ;POP BC
+instr do_fetch_DIR16, op_IFNZ, do_store_PC ;C2 nn nn ;JP NZ,nn
+instr do_fetch_DIR16, op_nop, do_store_PC ;C3 nn nn ;JP nn
+instr do_fetch_DIR16, op_IFNZ, do_store_CALL ;C4 nn nn ;CALL NZ,nn
+instr do_fetch_BC, op_PUSH16, do_store_nop ;C5 ;PUSH BC
+instr do_fetch_DIR8, op_ADDA, do_store_nop ;C6 nn ;ADD A,n
+instr do_fetch_RST, op_nop, do_store_CALL ;C7 ;RST 0
+instr do_fetch_nop, op_IFZ, do_store_RET ;C8 ;RET Z
+instr do_fetch_nop, op_nop, do_store_RET ;C9 ;RET
+instr do_fetch_DIR16, op_IFZ, do_store_PC ;CA nn nn ;JP Z,nn
+instr do_fetch_nop, op_INV, do_store_nop ;CB ;(Z80 specific)
+instr do_fetch_DIR16, op_IFZ, do_store_CALL ;CC nn nn ;CALL Z,nn
+instr do_fetch_DIR16, op_nop, do_store_CALL ;CD nn nn ;CALL nn
+instr do_fetch_DIR8, op_ADCA, do_store_nop ;CE nn ;ADC A,n
+instr do_fetch_RST, op_nop, do_store_CALL ;CF ;RST 8H
+instr do_fetch_nop, op_IFNC, do_store_RET ;D0 ;RET NC
+instr do_fetch_nop, op_POP16, do_store_DE ;D1 ;POP DE
+instr do_fetch_DIR16, op_IFNC, do_store_PC ;D2 nn nn ;JP NC,nn
+instr do_fetch_DIR8, op_OUTA, do_store_nop ;D3 nn ;OUT (n),A
+instr do_fetch_DIR16, op_IFNC, do_store_CALL ;D4 nn nn ;CALL NC,nn
+instr do_fetch_DE, op_PUSH16, do_store_nop ;D5 ;PUSH DE
+instr do_fetch_DIR8, op_SUBFA, do_store_nop ;D6 nn ;SUB n
+instr do_fetch_RST, op_nop, do_store_CALL ;D7 ;RST 10H
+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_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
+instr do_fetch_RST, op_nop, do_store_CALL ;DF ;RST 18H
+instr do_fetch_nop, op_IFPO, do_store_RET ;E0 ;RET PO
+instr do_fetch_nop, op_POP16, do_store_HL ;E1 ;POP HL
+instr do_fetch_DIR16, op_IFPO, do_store_PC ;E2 nn nn ;JP PO,nn
+instr do_fetch_MSP, op_EXHL, do_store_MSP ;E3 ;EX (SP),HL
+instr do_fetch_DIR16, op_IFPO, do_store_CALL ;E4 nn nn ;CALL PO,nn
+instr do_fetch_HL, op_PUSH16, do_store_nop ;E5 ;PUSH HL
+instr do_fetch_DIR8, op_ANDA, do_store_nop ;E6 nn ;AND n
+instr do_fetch_RST, op_nop, do_store_CALL ;E7 ;RST 20H
+instr do_fetch_nop, op_IFPE, do_store_RET ;E8 ;RET PE
+instr do_fetch_HL, op_nop, do_store_PC ;E9 ;JP HL
+instr do_fetch_DIR16, op_IFPE, do_store_PC ;EA nn nn ;JP PE,nn
+instr do_fetch_DE, op_EXHL, do_store_DE ;EB ;EX DE,HL
+instr do_fetch_DIR16, op_IFPE, do_store_CALL ;EC nn nn ;CALL PE,nn
+instr do_fetch_nop, op_INV, do_store_nop ;ED ;(Z80 specific)
+instr do_fetch_DIR8, op_XORA, do_store_nop ;EE nn ;XOR n
+instr do_fetch_RST, op_nop, do_store_CALL ;EF ;RST 28H
+instr do_fetch_nop, op_IFP, do_store_RET ;F0 ;RET P
+instr do_fetch_nop, op_POP16, do_store_AF ;F1 ;POP AF
+instr do_fetch_DIR16, op_IFP, do_store_PC ;F2 nn nn ;JP P,nn
+instr do_fetch_nop, op_DI, do_store_nop ;F3 ;DI
+instr do_fetch_DIR16, op_IFP, do_store_CALL ;F4 nn nn ;CALL P,nn
+instr do_fetch_AF, op_PUSH16, do_store_nop ;F5 ;PUSH AF
+instr do_fetch_DIR8, op_ORA, do_store_nop ;F6 nn ;OR n
+instr do_fetch_RST, op_nop, do_store_CALL ;F7 ;RST 30H
+instr do_fetch_nop, op_IFM, do_store_RET ;F8 ;RET M
+instr do_fetch_HL, op_nop, do_store_SP ;F9 ;LD SP,HL
+instr do_fetch_DIR16, op_IFM, do_store_PC ;FA nn nn ;JP M,nn
+instr do_fetch_nop, op_EI, do_store_nop ;FB ;EI
+instr do_fetch_DIR16, op_IFM, do_store_CALL ;FC nn nn ;CALL M,nn
+instr do_fetch_nop, op_INV, do_store_nop ;FD ;(Z80 specific)
+instr do_fetch_DIR8, op_CPFA, do_store_nop ;FE nn ;CP n
+instr do_fetch_RST, op_nop, do_store_CALL ;FF ;RST 38H
+
+;----------------------------------------------------------------
+; 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
+
+ .org (PC+255) & 0xff00
+sz53p_tab:
+ .db 0x44,0x00,0x00,0x04,0x00,0x04,0x04,0x00
+ .db 0x08,0x0c,0x0c,0x08,0x0c,0x08,0x08,0x0c
+ .db 0x00,0x04,0x04,0x00,0x04,0x00,0x00,0x04
+ .db 0x0c,0x08,0x08,0x0c,0x08,0x0c,0x0c,0x08
+ .db 0x20,0x24,0x24,0x20,0x24,0x20,0x20,0x24
+ .db 0x2c,0x28,0x28,0x2c,0x28,0x2c,0x2c,0x28
+ .db 0x24,0x20,0x20,0x24,0x20,0x24,0x24,0x20
+ .db 0x28,0x2c,0x2c,0x28,0x2c,0x28,0x28,0x2c
+ .db 0x00,0x04,0x04,0x00,0x04,0x00,0x00,0x04
+ .db 0x0c,0x08,0x08,0x0c,0x08,0x0c,0x0c,0x08
+ .db 0x04,0x00,0x00,0x04,0x00,0x04,0x04,0x00
+ .db 0x08,0x0c,0x0c,0x08,0x0c,0x08,0x08,0x0c
+ .db 0x24,0x20,0x20,0x24,0x20,0x24,0x24,0x20
+ .db 0x28,0x2c,0x2c,0x28,0x2c,0x28,0x28,0x2c
+ .db 0x20,0x24,0x24,0x20,0x24,0x20,0x20,0x24
+ .db 0x2c,0x28,0x28,0x2c,0x28,0x2c,0x2c,0x28
+ .db 0x80,0x84,0x84,0x80,0x84,0x80,0x80,0x84
+ .db 0x8c,0x88,0x88,0x8c,0x88,0x8c,0x8c,0x88
+ .db 0x84,0x80,0x80,0x84,0x80,0x84,0x84,0x80
+ .db 0x88,0x8c,0x8c,0x88,0x8c,0x88,0x88,0x8c
+ .db 0xa4,0xa0,0xa0,0xa4,0xa0,0xa4,0xa4,0xa0
+ .db 0xa8,0xac,0xac,0xa8,0xac,0xa8,0xa8,0xac
+ .db 0xa0,0xa4,0xa4,0xa0,0xa4,0xa0,0xa0,0xa4
+ .db 0xac,0xa8,0xa8,0xac,0xa8,0xac,0xac,0xa8
+ .db 0x84,0x80,0x80,0x84,0x80,0x84,0x84,0x80
+ .db 0x88,0x8c,0x8c,0x88,0x8c,0x88,0x88,0x8c
+ .db 0x80,0x84,0x84,0x80,0x84,0x80,0x80,0x84
+ .db 0x8c,0x88,0x88,0x8c,0x88,0x8c,0x8c,0x88
+ .db 0xa0,0xa4,0xa4,0xa0,0xa4,0xa0,0xa0,0xa4
+ .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
+
--- /dev/null
+; 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.
+; Copyright (C) 2010 Horst S.
+
+; This file is part of avrcpm.
+;
+; avrcpm is free software: you can redistribute it and/or modify it
+; under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; avrcpm is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with avrcpm. If not, see <http://www.gnu.org/licenses/>.
+;
+; $Id$
+;
+
+
+ .dseg
+
+z_b: .byte 1
+z_c: .byte 1
+z_d: .byte 1
+z_e: .byte 1
+z_h: .byte 1
+z_l: .byte 1
+
+
+ .cseg
+
+;Init z80
+z80_init:
+ ldi z_pcl,low (IPLADDR)
+ ldi z_pch,high(IPLADDR)
+
+ cbi flags,trace
+ printnewline
+ printstring "Ok, CPU is live!"
+ printnewline
+
+;----------------------------------------------------------
+; 1 2 3 4
+;.db (low)do_store (low)do_op (hihg)do_op (low)do_fetch
+;
+;das kommt auf den stapel
+; main da solls zum schluss weitergehen
+;do_store wohin damit beenden mit RET
+;do_op was tun beenden mit RET
+;
+;das wird direkt angesprungen
+;do_fetch woher beenden mit RET
+;
+;
+main:
+.if INS_DEBUG
+ cbi flags,trace
+ cpi z_pch,DBG_TRACE_BOTTOM
+ brlo notraceon
+ cpi z_pch,DBG_TRACE_TOP
+ brsh notraceon
+ sbi flags,trace
+notraceon:
+.endif
+
+
+.if PRINT_PC
+ cpi z_pch,DBG_TRACE_BOTTOM
+ brlo noprintpc
+ cpi z_pch,DBG_TRACE_TOP
+ brsh noprintpc
+
+ printnewline
+ printstring "PC="
+ movw temp,z_pcl
+ rcall printhexw
+ printstring " "
+noprintpc:
+.endif
+
+.if INS_DEBUG
+ sbic flags,trace
+ rcall printregs
+.endif
+
+ ;hier kommt die Interruptbehandlung rein
+
+ ldi zl,low(main) ;da will ich wieder hin.
+ ldi zh,high(main) ;
+ push zl ;
+ push zh ;
+ mem_read_s z_pc ;temp=memReadByte(z_pc)
+ adiw z_pcl,1 ;++z_pc
+ ldi zl,low(todo_table*2) ;zhl=todo_table
+ ldi zh,high(todo_table*2) ;
+ ldi temp2,3 ;1
+ mul temp,temp2 ;2
+ add zl,r0 ;1
+ adc zh,r1 ;1
+
+ ldi temp2,high(store_ops) ;
+ lpm temp,Z+ ;do_store
+ push temp ; low
+ push temp2 ; high
+
+.if high(opjumps) != high(opjumps)
+ ldi temp2,high(opjumps)
+.endif
+ lpm temp,Z+ ;do_op
+ push temp ; low
+ push temp2 ; high
+
+ lpm zl,Z ;do_fetch
+ ldi zh,high(fetch_ops)
+ ijmp ;direkt
+
+
+; .listmac
+;-----------------------------------------------------
+; Generate jump to target and position in table
+; gen_opjmp target
+;
+.macro gen_opjmp
+ .ifndef opjmp_table_pos_
+ .set opjmp_table_page_ = high(PC)
+ .set opjmp_table_pos_ = PC
+ .endif
+ .equ @0 = low(opjmp_table_pos_)
+ .set opjmp_table_pos_ = opjmp_table_pos_ + 1
+ .if high(opjmp_table_pos_) != opjmp_table_page_
+ .warning "Table 'opjump' crosses page boarder."
+ .message "Program will not work, unless the opjump table is relocated."
+ .endif
+ rjmp do_@0
+ .endm
+
+;--------------------------------------------------
+; Generate a table entry for one instruction
+;
+; instr fetch, op, store
+;
+.macro instr
+ .ifndef inst_table_odd_
+ .set inst_table_odd_ = 0
+ .endif
+
+ .if inst_table_odd_
+ .db inst_table_next_, low(@2), @1, low(@0)
+ .set inst_table_odd_ = 0
+ .else
+ .set inst_table_next_ = low(@0)
+ .db low(@2), @1
+ .set inst_table_odd_ = 1
+ .endif
+.endm
+
+;-----------------------------------
+; go to op.
+;
+.macro fetch_end
+ ldi zh,high(opjumps)
+ mov zl,insdech
+ ijmp
+.endm
+
+;-----------------------------------
+; go to store.
+;
+.macro op_end
+ ldi zh,high(store_ops) ;
+ mov zl,insdecl
+ ijmp
+.endm
+
+;-----------------------------------
+; go back to main
+;
+.macro store_end
+ rjmp main
+.endm
+
+;-----------------------------------
+; go back to main
+;
+.macro op_end_nojmp
+ rjmp main
+.endm
+
+
+; ------------ Fetch phase stuff -----------------
+
+.org (PC+255) & 0xff00 ; wichtig !!!fetch und store muessen in einer page liegen
+fetch_ops:
+do_fetch_nop:
+ ret
+
+do_fetch_a:
+ mov opl,z_a
+ ret
+
+do_fetch_b:
+ lds opl,z_b
+ ret
+
+do_fetch_c:
+ lds opl,z_c
+ ret
+
+do_fetch_d:
+ lds opl,z_d
+ ret
+
+do_fetch_e:
+ lds opl,z_e
+ ret
+
+do_fetch_h:
+ lds opl,z_h
+ ret
+
+do_fetch_l:
+ lds opl,z_l
+ ret
+
+do_fetch_af:
+ mov opl,z_flags
+ mov oph,z_a
+ ret
+
+do_fetch_bc:
+ lds opl,z_c
+ lds oph,z_b
+ ret
+
+do_fetch_de:
+ lds opl,z_e
+ lds oph,z_d
+ ret
+
+do_fetch_hl:
+ lds opl,z_l
+ lds oph,z_h
+ ret
+
+do_fetch_sp:
+ movw opl,z_spl
+ ret
+
+do_fetch_mbc:
+ lds xh,z_b
+ lds xl,z_c
+ mem_read_d opl
+ ret
+
+do_fetch_mde:
+ lds xh,z_d
+ lds xl,z_e
+ mem_read_d opl
+ ret
+
+do_fetch_mhl:
+ lds xh,z_h
+ lds xl,z_l
+ mem_read_d opl
+ ret
+
+do_fetch_msp:
+ movw x,z_spl
+ mem_read_d opl
+ adiw x,1
+ mem_read_d oph
+ ret
+
+do_fetch_dir8:
+ mem_read_ds opl, z_pc
+ adiw z_pcl,1
+ ret
+
+do_fetch_dir16:
+ mem_read_ds opl, z_pc
+ adiw z_pcl,1
+ mem_read_ds oph, z_pc
+ adiw z_pcl,1
+ ret
+
+do_fetch_rst:
+ movw x,z_pcl
+ sbiw x,1
+ mem_read_d opl
+ andi opl,0x38
+ ldi oph,0
+ ret
+
+; ------------ Store phase stuff -----------------
+
+.org (PC+255) & 0xff00 ; wichtig !!!fetch und store muessen in einer page liegen
+store_ops:
+do_store_nop:
+ ret
+
+do_store_a:
+ mov z_a,opl
+ ret
+
+do_store_b:
+ sts z_b,opl
+ ret
+
+do_store_c:
+ sts z_c,opl
+ ret
+
+do_store_d:
+ sts z_d,opl
+ ret
+
+do_store_e:
+ sts z_e,opl
+ ret
+
+do_store_h:
+ sts z_h,opl
+ ret
+
+do_store_l:
+ sts z_l,opl
+ ret
+
+do_store_af:
+ mov z_a,oph
+ mov z_flags,opl
+ ret
+
+do_store_bc:
+ sts z_b,oph
+ sts z_c,opl
+ ret
+
+do_store_de:
+ sts z_d,oph
+ sts z_e,opl
+ ret
+
+do_store_hl:
+ sts z_h,oph
+ sts z_l,opl
+ ret
+
+do_store_mbc:
+ lds xh,z_b
+ lds xl,z_c
+ mem_write_s opl
+ ret
+
+do_store_mde:
+ lds xh,z_d
+ lds xl,z_e
+ mem_write_s opl
+ ret
+
+do_store_mhl:
+ lds xh,z_h
+ lds xl,z_l
+ mem_write_s opl
+ ret
+
+do_store_msp:
+ movw xl,z_spl
+ mem_write_s opl
+ adiw xl,1
+ mem_write_s oph
+ ret
+
+do_store_sp:
+ movw z_spl,opl
+ ret
+
+do_store_pc:
+ movw z_pcl,opl
+ ret
+
+do_store_ret:
+ movw x,z_spl
+ mem_read_d z_pcl
+ adiw x,1
+ mem_read_d z_pch
+ adiw x,1
+ movw z_spl,x
+
+.if STACK_DBG
+ printnewline
+ printstring "Stack pop "
+ movw temp,z_pcl
+ rcall printhexw
+ printstring ", SP is now "
+ movw temp,z_spl
+ rcall printhexw
+ printstring ". "
+.endif
+ ret
+
+do_store_call:
+ movw xl,z_spl
+ sbiw x,1
+ mem_write_s z_pch
+ sbiw x,1
+ mem_write_s z_pcl
+ movw z_spl,xl
+
+.if STACK_DBG
+ printnewline
+ printstring "Stack push "
+ movw temp,z_pcl
+ rcall printhexw
+ printstring ", SP is now "
+ movw temp,z_spl
+ rcall printhexw
+ printstring ". "
+.endif
+ movw z_pcl,opl
+ ret
+
+
+do_store_am:
+ mem_write_ds op, z_a
+ ret
+
+; ------------ Operation phase stuff -----------------
+
+;.org (PC+255) & 0xff00
+
+opjumps:
+ gen_opjmp op_nop
+ gen_opjmp op_inc
+ gen_opjmp op_dec
+ gen_opjmp op_inc16
+ gen_opjmp op_dec16
+ gen_opjmp op_rlc
+ gen_opjmp op_rrc
+ gen_opjmp op_rr
+ gen_opjmp op_rl
+ gen_opjmp op_adda
+ gen_opjmp op_adca
+ gen_opjmp op_subfa
+ gen_opjmp op_sbcfa
+ gen_opjmp op_anda
+ gen_opjmp op_ora
+ gen_opjmp op_xora
+ gen_opjmp op_addhl
+ gen_opjmp op_sthl
+ gen_opjmp op_rmem16
+ gen_opjmp op_rmem8
+ gen_opjmp op_da
+ gen_opjmp op_scf
+ gen_opjmp op_cpl
+ gen_opjmp op_ccf
+ gen_opjmp op_pop16
+ gen_opjmp op_push16
+ gen_opjmp op_ifnz
+ gen_opjmp op_ifz
+ gen_opjmp op_ifnc
+ gen_opjmp op_ifc
+ gen_opjmp op_ifpo
+ gen_opjmp op_ifpe
+ gen_opjmp op_ifp
+ gen_opjmp op_ifm
+ gen_opjmp op_outa
+ gen_opjmp op_in
+ gen_opjmp op_exhl
+ gen_opjmp op_di
+ gen_opjmp op_ei
+ gen_opjmp op_inv
+ gen_opjmp op_cpfa
+ gen_opjmp op_inca
+ gen_opjmp op_deca
+
+
+;----------------------------------------------------------------
+;| |
+;| Zilog |
+;| |
+;| ZZZZZZZ 88888 000 |
+;| Z 8 8 0 0 |
+;| Z 8 8 0 0 0 |
+;| Z 88888 0 0 0 |
+;| Z 8 8 0 0 0 |
+;| Z 8 8 0 0 |
+;| ZZZZZZZ 88888 000 |
+;| |
+;| Z80 MICROPROCESSOR Instruction Set Summary |
+;| |
+;----------------------------------------------------------------
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;|----------+------+---------------------+----------------------|
+;|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 |
+;|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 |
+;|CALL nn |------|Unconditional Call |-[SP]=PC,PC=nn |
+;|CCF |--?-0*|Complement Carry Flag|CY=~CY |
+;|CP s |***V1*|Compare |A-s |
+;|CPD |****1-|Compare and Decrement|A-[HL],HL=HL-1,BC=BC-1|
+;|CPDR |****1-|Compare, Dec., Repeat|CPD till A=[HL]or BC=0|
+;|CPI |****1-|Compare and Increment|A-[HL],HL=HL+1,BC=BC-1|
+;|CPIR |****1-|Compare, Inc., Repeat|CPI till A=[HL]or BC=0|
+;|CPL |--1-1-|Complement |A=~A |
+;|DAA |***P-*|Decimal Adjust Acc. |A=BCD format |
+;|DEC s |***V1-|Decrement |s=s-1 |
+;|DEC xx |------|Decrement |xx=xx-1 |
+;|DEC ss |------|Decrement |ss=ss-1 |
+;|DI |------|Disable Interrupts | |
+;|DJNZ e |------|Dec., Jump Non-Zero |B=B-1 till B=0 |
+;|EI |------|Enable Interrupts | |
+;|EX [SP],HL|------|Exchange |[SP]<->HL |
+;|EX [SP],xx|------|Exchange |[SP]<->xx |
+;|EX AF,AF' |------|Exchange |AF<->AF' |
+;|EX DE,HL |------|Exchange |DE<->HL |
+;|EXX |------|Exchange |qq<->qq' (except AF)|
+;|HALT |------|Halt | |
+;|IM n |------|Interrupt Mode | (n=0,1,2)|
+;|IN A,[n] |------|Input |A=[n] |
+;|IN r,[C] |***P0-|Input |r=[C] |
+;|INC r |***V0-|Increment |r=r+1 |
+;|INC [HL] |***V0-|Increment |[HL]=[HL]+1 |
+;|INC xx |------|Increment |xx=xx+1 |
+;|INC [xx+d]|***V0-|Increment |[xx+d]=[xx+d]+1 |
+;|INC ss |------|Increment |ss=ss+1 |
+;|IND |?*??1-|Input and Decrement |[HL]=[C],HL=HL-1,B=B-1|
+;|INDR |?1??1-|Input, Dec., Repeat |IND till B=0 |
+;|INI |?*??1-|Input and Increment |[HL]=[C],HL=HL+1,B=B-1|
+;|INIR |?1??1-|Input, Inc., Repeat |INI till B=0 |
+;|JP [HL] |------|Unconditional Jump |PC=[HL] |
+;|JP [xx] |------|Unconditional Jump |PC=[xx] |
+;|JP nn |------|Unconditional Jump |PC=nn |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|JR e |------|Unconditional Jump |PC=PC+e |
+;|JR cc,e |------|Conditional Jump |If cc JR(cc=C,NC,NZ,Z)|
+;|LD dst,src|------|Load |dst=src |
+;|LD A,i |**0*0-|Load |A=i (i=I,R)|
+;|LDD |--0*0-|Load and Decrement |[DE]=[HL],HL=HL-1,# |
+;|LDDR |--000-|Load, Dec., Repeat |LDD till BC=0 |
+;|LDI |--0*0-|Load and Increment |[DE]=[HL],HL=HL+1,# |
+;|LDIR |--000-|Load, Inc., Repeat |LDI till BC=0 |
+;|NEG |***V1*|Negate |A=-A |
+;|NOP |------|No Operation | |
+;|OR s |**0P00|Logical inclusive OR |A=Avs |
+;|OTDR |?1??1-|Output, Dec., Repeat |OUTD till B=0 |
+;|OTIR |?1??1-|Output, Inc., Repeat |OUTI till B=0 |
+;|OUT [C],r |------|Output |[C]=r |
+;|OUT [n],A |------|Output |[n]=A |
+;|OUTD |?*??1-|Output and Decrement |[C]=[HL],HL=HL-1,B=B-1|
+;|OUTI |?*??1-|Output and Increment |[C]=[HL],HL=HL+1,B=B-1|
+;|POP xx |------|Pop |xx=[SP]+ |
+;|POP qq |------|Pop |qq=[SP]+ |
+;|PUSH xx |------|Push |-[SP]=xx |
+;|PUSH qq |------|Push |-[SP]=qq |
+;|RES b,m |------|Reset bit |m=m&{~2^b} |
+;|RET |------|Return |PC=[SP]+ |
+;|RET cc |------|Conditional Return |If cc RET |
+;|RETI |------|Return from Interrupt|PC=[SP]+ |
+;|RETN |------|Return from NMI |PC=[SP]+ |
+;|RL m |**0P0*|Rotate Left |m={CY,m}<- |
+;|RLA |--0-0*|Rotate Left Acc. |A={CY,A}<- |
+;|RLC m |**0P0*|Rotate Left Circular |m=m<- |
+;|RLCA |--0-0*|Rotate Left Circular |A=A<- |
+;|RLD |**0P0-|Rotate Left 4 bits |{A,[HL]}={A,[HL]}<- ##|
+;|RR m |**0P0*|Rotate Right |m=->{CY,m} |
+;|RRA |--0-0*|Rotate Right Acc. |A=->{CY,A} |
+;|RRC m |**0P0*|Rotate Right Circular|m=->m |
+;|RRCA |--0-0*|Rotate Right Circular|A=->A |
+;|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 |
+;|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 |
+;|SRA m |**0P0*|Shift Right Arith. |m=m/2 |
+;|SRL m |**0P0*|Shift Right Logical |m=->{0,m,CY} |
+;|SUB s |***V1*|Subtract |A=A-s |
+;|XOR s |**0P00|Logical Exclusive OR |A=Axs |
+;|----------+------+--------------------------------------------|
+;| F |-*01? |Flag unaffected/affected/reset/set/unknown |
+;| S |S |Sign flag (Bit 7) |
+;| Z | Z |Zero flag (Bit 6) |
+;| HC | H |Half Carry flag (Bit 4) |
+;| P/V | P |Parity/Overflow flag (Bit 2, V=overflow) |
+;| N | N |Add/Subtract flag (Bit 1) |
+;| CY | C|Carry flag (Bit 0) |
+;|-----------------+--------------------------------------------|
+;| n |Immediate addressing |
+;| nn |Immediate extended addressing |
+;| e |Relative addressing (PC=PC+2+offset) |
+;| [nn] |Extended addressing |
+;| [xx+d] |Indexed addressing |
+;| r |Register addressing |
+;| [rr] |Register indirect addressing |
+;| |Implied addressing |
+;| b |Bit addressing |
+;| p |Modified page zero addressing (see RST) |
+;|-----------------+--------------------------------------------|
+;|DEFB n(,...) |Define Byte(s) |
+;|DEFB 'str'(,...) |Define Byte ASCII string(s) |
+;|DEFS nn |Define Storage Block |
+;|DEFW nn(,...) |Define Word(s) |
+;|-----------------+--------------------------------------------|
+;| A B C D E |Registers (8-bit) |
+;| AF BC DE HL |Register pairs (16-bit) |
+;| F |Flag register (8-bit) |
+;| I |Interrupt page address register (8-bit) |
+;| IX IY |Index registers (16-bit) |
+;| PC |Program Counter register (16-bit) |
+;| R |Memory Refresh register |
+;| SP |Stack Pointer register (16-bit) |
+;|-----------------+--------------------------------------------|
+;| b |One bit (0 to 7) |
+;| cc |Condition (C,M,NC,NZ,P,PE,PO,Z) |
+;| d |One-byte expression (-128 to +127) |
+;| dst |Destination s, ss, [BC], [DE], [HL], [nn] |
+;| e |One-byte expression (-126 to +129) |
+;| m |Any register r, [HL] or [xx+d] |
+;| n |One-byte expression (0 to 255) |
+;| nn |Two-byte expression (0 to 65535) |
+;| pp |Register pair BC, DE, IX or SP |
+;| qq |Register pair AF, BC, DE or HL |
+;| qq' |Alternative register pair AF, BC, DE or HL |
+;| r |Register A, B, C, D, E, H or L |
+;| rr |Register pair BC, DE, IY or SP |
+;| s |Any register r, value n, [HL] or [xx+d] |
+;| src |Source s, ss, [BC], [DE], [HL], nn, [nn] |
+;| ss |Register pair BC, DE, HL or SP |
+;| xx |Index register IX or IY |
+;|-----------------+--------------------------------------------|
+;| + - * / ^ |Add/subtract/multiply/divide/exponent |
+;| & ~ v x |Logical AND/NOT/inclusive OR/exclusive OR |
+;| <- -> |Rotate left/right |
+;| [ ] |Indirect addressing |
+;| [ ]+ -[ ] |Indirect addressing auto-increment/decrement|
+;| { } |Combination of operands |
+;| # |Also BC=BC-1,DE=DE-1 |
+;| ## |Only lower 4 bits of accumulator A used |
+;----------------------------------------------------------------
+
+;How the flags are supposed to work:
+;7 ZFL_S - Sign flag (=MSBit of result)
+;6 ZFL_Z - Zero flag. Is 1 when the result is 0
+;4 ZFL_H - Half-carry (carry from bit 3 to 4)
+;2 ZFL_P - Parity/2-complement Overflow
+;1 ZFL_N - Subtract - set if last op was a subtract
+;0 ZFL_C - Carry
+;
+;I sure hope I got the mapping between flags and instructions correct...
+
+.equ ZFL_S = 7
+.equ ZFL_Z = 6
+.equ ZFL_H = 4
+.equ ZFL_P = 2
+.equ ZFL_N = 1
+.equ ZFL_C = 0
+
+.equ AVR_T = SREG_T
+.equ AVR_H = SREG_H
+.equ AVR_S = SREG_S
+.equ AVR_V = SREG_V
+.equ AVR_N = SREG_N
+.equ AVR_Z = SREG_Z
+.equ AVR_C = SREG_C
+
+;------------------------------------------------;
+; Load table value from flash indexed by source reg.
+;
+;ldpmx dstreg,tablebase,indexreg
+;
+; (6 words, 8 cycles)
+
+.macro ldpmx
+ ldi zh,high(@1*2) ; table must be page aligned
+ mov zl,@2
+ lpm @0,z
+.endm
+
+.macro do_z80_flags_HP
+#if EM_Z80
+ bmov z_flags, ZFL_P, temp, AVR_V
+ 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_set_HN
+#if EM_Z80
+ ori z_flags,(1<<ZFL_N)|(1<<ZFL_H)
+#endif
+.endm
+
+.macro do_z80_flags_clear_N
+#if EM_Z80
+ andi z_flags,~(1<<ZFL_N)
+#endif
+.endm
+
+.macro do_z80_flags_op_rotate
+ ; must not change avr carry flag!
+#if EM_Z80
+ andi z_flags, ~( (1<<ZFL_H) | (1<<ZFL_N) | (1<<ZFL_C) )
+#else
+ andi z_flags, ~( (1<<ZFL_C) )
+#endif
+.endm
+
+.macro do_z80_flags_op_and
+#if EM_Z80
+ ori z_flags,(1<<ZFL_H)
+#else
+ ori z_flags,(1<<ZFL_H)
+#endif
+.endm
+
+.macro do_z80_flags_op_or
+#if EM_Z80
+#endif
+.endm
+
+
+;----------------------------------------------------------------
+
+do_op_inv:
+ printstring "Invalid opcode @ PC="
+ movw temp,z_pcl
+ rcall printhexw
+
+haltinv:
+ rjmp haltinv
+
+do_op_nop:
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|OUT [n],A |------|Output |[n]=A |
+;
+;
+;Interface with peripherials goes here :)
+do_op_outa: ; out (opl),a
+.if PORT_DEBUG
+ printnewline
+ printstring "Port write: "
+ mov temp,z_a
+ rcall printhex
+ printstring " -> ("
+ mov temp,opl
+ rcall printhex
+ printstring ") "
+.endif
+ mov temp,z_a
+ mov temp2,opl
+ rcall portWrite
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|IN A,[n] |------|Input |A=[n] |
+;
+;
+do_op_in: ; in a,(opl)
+.if PORT_DEBUG
+ printnewline
+ printstring "Port read: ("
+ mov temp,opl
+ rcall printhex
+ printstring ") -> "
+.endif
+
+ mov temp2,opl
+ rcall portRead
+ mov opl,temp
+
+.if PORT_DEBUG
+ rcall printhex
+ printstring " "
+.endif
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|INC r |***V0-|Increment |r=r+1 |
+;|INC [HL] |***V0-|Increment |[HL]=[HL]+1 |
+;|INC [xx+d]|***V0-|Increment |[xx+d]=[xx+d]+1 |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|INC r |**-P0-|Increment |r=r+1 |
+;|INC [HL] |**-P0-|Increment |[HL]=[HL]+1 |
+;
+;
+do_op_inc:
+ inc opl
+#if EM_Z80
+ in temp, sreg
+#endif
+ andi z_flags,(1<<ZFL_H)|(1<<ZFL_C) ; preserve C-, and H-flag
+ ldpmx temp2, sz53p_tab, opl
+ or z_flags,temp2 ;
+ do_z80_flags_HP
+ ret
+
+do_op_inca:
+ inc z_a
+#if EM_Z80
+ in temp, sreg
+#endif
+ andi z_flags,(1<<ZFL_H)|(1<<ZFL_C) ; preserve C-, and H-flag
+ ldpmx temp2, sz53p_tab, z_a
+ or z_flags,temp2 ;
+ do_z80_flags_HP
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|DEC r |***V1-|Decrement |s=s-1 |
+;|INC [HL] |***V0-|Increment |[HL]=[HL]+1 |
+;|INC [xx+d]|***V0-|Increment |[xx+d]=[xx+d]+1 |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|DEC r |**-P -|Increment |r=r+1 |
+;|DEC [HL] |**-P -|Increment |[HL]=[HL]+1 |
+;
+;
+do_op_dec:
+ dec opl
+#if EM_Z80
+ in temp, sreg
+#endif
+ andi z_flags,(1<<ZFL_H)|(1<<ZFL_C) ; preserve C-, and H-flag
+ ldpmx temp2, sz53p_tab, opl
+ or z_flags,temp2 ;
+ do_z80_flags_HP
+ do_z80_flags_set_N
+ ret
+
+do_op_deca:
+ dec z_a
+#if EM_Z80
+ in temp, sreg
+#endif
+ andi z_flags,(1<<ZFL_H)|(1<<ZFL_C) ; preserve C-, and H-flag
+ ldpmx temp2, sz53p_tab, z_a
+ or z_flags,temp2 ;
+ do_z80_flags_HP
+ do_z80_flags_set_N
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|INC xx |------|Increment |xx=xx+1 |
+;|INC ss |------|Increment |ss=ss+1 |
+;
+;
+do_op_inc16:
+ subi opl,low(-1)
+ sbci oph,high(-1)
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|DEC xx |------|Decrement |xx=xx-1 |
+;|DEC ss |------|Decrement |ss=ss-1 |
+;
+;
+do_op_dec16:
+ subi opl, 1
+ sbci oph, 0
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|RLCA |--0-0*|Rotate Left Circular |A=A<- |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|RLCA |---- *|Rotate Left Circular |A=A<- |
+;
+;
+do_op_rlc:
+ ;Rotate Left Cyclical. All bits move 1 to the
+ ;left, the msb becomes c and lsb.
+ do_z80_flags_op_rotate
+ lsl opl
+ brcc do_op_rlc_noc
+ ori opl, 1
+ ori z_flags, (1<<ZFL_C)
+do_op_rlc_noc:
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|RRCA |--0-0*|Rotate Right Circular|A=->A |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|RRCA |---- *|Rotate Right Circular|A=->A |
+;
+;
+do_op_rrc:
+ ;Rotate Right Cyclical. All bits move 1 to the
+ ;right, the lsb becomes c and msb.
+ do_z80_flags_op_rotate
+ lsr opl
+ brcc do_op_rrc_noc
+ ori opl, 0x80
+ ori z_flags, (1<<ZFL_C)
+do_op_rrc_noc:
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|RRA |--0-0*|Rotate Right Acc. |A=->{CY,A} |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|RRA |---- *|Rotate Right Acc. |A=->{CY,A} |
+;
+;
+do_op_rr:
+ ;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
+ sec
+ do_z80_flags_op_rotate ; (clear ZFL_C, doesn't change AVR_C)
+ bmov z_flags,ZFL_C, opl,0 ; Bit 0 --> CY
+ ror opl
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|RLA |--0-0*|Rotate Left Acc. |A={CY,A}<- |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|RLA |---- *|Rotate Left Acc. |A={CY,A}<- |
+;
+;
+do_op_rl:
+ ;Rotate Left. All bits move 1 to the left, the msb
+ ;becomes c, c becomes lsb.
+ clc
+ sbrc z_flags,ZFL_C
+ sec
+ do_z80_flags_op_rotate ; (clear ZFL_C, doesn't change AVR_C)
+ bmov z_flags,ZFL_C, opl,7 ; Bit 7 --> CY
+ rol opl
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|ADD A,s |***V0*|Add |A=A+s |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|ADD A,s |***P *|Add |A=A+s |
+;
+;
+do_op_adda:
+ add z_a,opl
+ in temp,sreg
+ ldpmx z_flags,sz53p_tab,z_a ;S,Z,P flag
+ bmov z_flags,ZFL_C, temp,AVR_C
+ do_z80_flags_HP
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|ADC A,s |***V0*|Add with Carry |A=A+s+CY |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|ADC A,s |***P *|Add with Carry |A=A+s+CY |
+;
+;
+do_op_adca:
+ clc
+ sbrc z_flags,ZFL_C
+ sec
+ adc z_a,opl
+ in temp,sreg
+ ldpmx z_flags,sz53p_tab,z_a ;S,Z,P
+ bmov z_flags,ZFL_C, temp,AVR_C
+ do_z80_flags_HP
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|SUB s |***V1*|Subtract |A=A-s |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|SUB s |***P *|Subtract |A=A-s |
+
+;
+do_op_subfa:
+ sub z_a,opl
+ in temp,sreg
+ ldpmx z_flags,sz53p_tab,z_a ;S,Z,P
+ bmov z_flags,ZFL_C, temp,AVR_C
+ do_z80_flags_HP
+ do_z80_flags_set_N
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CP s |***V1*|Compare |A-s |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|CP s |***P *|Compare |A-s |
+
+;
+do_op_cpfa:
+ mov temp,z_a
+ sub temp,opl
+ mov opl,temp
+ in temp,sreg
+ ldpmx z_flags,sz53p_tab,opl ;S,Z,P
+ bmov z_flags,ZFL_C, temp,AVR_C
+ do_z80_flags_HP
+ do_z80_flags_set_N
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|SBC A,s |***V1*|Subtract with Carry |A=A-s-CY |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|SBC A,s |***P *|Subtract with Carry |A=A-s-CY |
+;
+;
+do_op_sbcfa:
+ clc
+ sbrc z_flags,ZFL_C
+ sec
+ sbc z_a,opl
+ in temp,sreg
+ ldpmx z_flags,sz53p_tab,z_a ;S,Z,P
+ bmov z_flags,ZFL_C, temp,AVR_C
+ do_z80_flags_HP
+ do_z80_flags_set_N
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|AND s |**1P00|Logical AND |A=A&s |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|AND s |**-P 0|Logical AND |A=A&s |
+;
+; TODO H-Flag
+do_op_anda:
+ and z_a,opl ;
+ ldpmx z_flags,sz53p_tab,z_a ;S,Z,P,N,C
+ do_z80_flags_op_and
+ ret
+
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|OR s |**0P00|Logical inclusive OR |A=Avs |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|OR s |**-P00|Logical inclusive OR |A=Avs |
+;
+; TODO: H-Flag
+do_op_ora:
+ or z_a,opl
+ ldpmx z_flags,sz53p_tab,z_a ;S,Z,H,P,N,C
+ do_z80_flags_op_or
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|XOR s |**0P00|Logical Exclusive OR |A=Axs |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|XOR s |**-P 0|Logical Exclusive OR |A=Axs |
+;
+; TODO: H-Flag
+do_op_xora:
+ eor z_a,opl
+ ldpmx z_flags,sz53p_tab,z_a ;S,Z,H,P,N,C
+ do_z80_flags_op_or
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|ADD HL,ss |--?-0*|Add |HL=HL+ss |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|ADD HL,ss |---- *|Add |HL=HL+ss |
+;
+;
+do_op_addhl:
+ lds temp,z_l
+ lds temp2,z_h
+ add opl,temp
+ adc oph,temp2
+ in temp,sreg
+ bmov z_flags,ZFL_H, temp,AVR_H
+ bmov z_flags,ZFL_C, temp,AVR_C
+ do_z80_flags_clear_N
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|LD dst,src|------|Load |dst=src |
+;
+;
+do_op_sthl: ;store hl to mem loc in opl:h
+ movw xl,opl
+ lds temp,z_l
+ mem_write
+ adiw xl,1
+ lds temp,z_h
+ mem_write
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|LD dst,src|------|Load |dst=src |
+;
+;
+do_op_rmem16:
+ movw xl,opl
+ mem_read_d opl
+ adiw x,1
+ mem_read_d oph
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|LD dst,src|------|Load |dst=src |
+;
+;
+do_op_rmem8:
+ mem_read_ds opl, op
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|DAA |***P-*|Decimal Adjust Acc. | |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;
+; Not yet checked
+
+; Description (http://www.z80.info/z80syntx.htm#DAA):
+; This instruction conditionally adjusts the accumulator for BCD addition
+; and subtraction operations. For addition (ADD, ADC, INC) or subtraction
+; (SUB, SBC, DEC, NEC), the following table indicates the operation performed:
+;
+; -------------------------------------------------------------------------------
+; | | C Flag | HEX value in | H Flag | HEX value in | Number | C flag|
+; | Operation| Before | upper digit | Before | lower digit | added | After |
+; | | DAA | (bit 7-4) | DAA | (bit 3-0) | to byte | DAA |
+; |-----------------------------------------------------------------------------|
+; | | 0 | 0-9 | 0 | 0-9 | 00 | 0 |
+; | ADD | 0 | 0-8 | 0 | A-F | 06 | 0 |
+; | | 0 | 0-9 | 1 | 0-3 | 06 | 0 |
+; | ADC | 0 | A-F | 0 | 0-9 | 60 | 1 |
+; | | 0 | 9-F | 0 | A-F | 66 | 1 |
+; | INC | 0 | A-F | 1 | 0-3 | 66 | 1 |
+; | | 1 | 0-2 | 0 | 0-9 | 60 | 1 |
+; | | 1 | 0-2 | 0 | A-F | 66 | 1 |
+; | | 1 | 0-3 | 1 | 0-3 | 66 | 1 |
+; |-----------------------------------------------------------------------------|
+; | SUB | 0 | 0-9 | 0 | 0-9 | 00 | 0 |
+; | SBC | 0 | 0-8 | 1 | 6-F | FA | 0 |
+; | DEC | 1 | 7-F | 0 | 0-9 | A0 | 1 |
+; | NEG | 1 | 6-F | 1 | 6-F | 9A | 1 |
+; |-----------------------------------------------------------------------------|
+;
+; Flags:
+; C: See instruction.
+; N: Unaffected.
+; P/V: Set if Acc. is even parity after operation, reset otherwise.
+; H: See instruction.
+; 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:
+ ldi oph,0 ; what to add
+ sbrc z_flags,ZFL_H ; if H-Flag
+ rjmp op_da_06
+ mov temp,opl
+ andi temp,0x0f ; ... or lower digit > 9
+ cpi temp,0x0a
+ brlo op_da_06n
+op_da_06:
+ ori oph,0x06
+op_da_06n:
+ sbrc z_flags,(1<<ZFL_C)
+ rjmp op_da_60
+ cpi opl,0xa0
+ brlo op_da_60n
+op_da_60:
+ ori oph,0x60
+op_da_60n:
+ cpi opl,0x9a
+ brlo op_da_99n
+ ori z_flags,(1<<ZFL_C); set C
+op_da_99n:
+ sbrs z_flags,ZFL_N ; if sub-op
+ rjmp op_da_add ; then
+ sub opl,oph
+ rjmp op_da_ex
+op_da_add: ; else add-op
+ cpi opl,0x91
+ brlo op_da_60n2
+ mov temp,opl
+ andi temp,0x0f
+ cpi temp,0x0a
+ brlo op_da_60n2
+ ori oph,0x60
+op_da_60n2:
+ add opl,oph
+op_da_ex:
+ in temp,SREG
+ sbrc temp,AVR_H
+ ori z_flags,(1<<ZFL_C)
+ andi z_flags,(1<<ZFL_N)|(1<<ZFL_C) ; preserve C,N
+ ldpmx temp2, sz53p_tab, opl ; get S,Z,P
+ or z_flags,temp2
+ bmov z_flags,ZFL_H, temp,AVR_H ; H (?)
+ ret
+#else
+
+do_op_da:
+ sbrc z_flags,ZFL_N ; if add-op
+ rjmp do_op_da_sub ; then
+ ldi temp2,0 ;
+ mov temp,opl ;
+ andi temp,0x0f ;
+ cpi temp,0x0a ;if lower digit > 9
+ brlo do_op_da_h ;
+ ori temp2,0x06 ; add 6 to lower digit
+do_op_da_h: ;
+ sbrc z_flags,ZFL_H ; ... or H-Flag
+ ori temp2,0x06 ;
+ add opl,temp2 ;
+
+ ldi temp2,0 ;
+ mov temp,opl ;
+ andi temp,0xf0 ;
+ cpi temp,0xa0 ;
+ brlo do_op_da_c ;
+ ori temp2,0x60 ;
+do_op_da_c: ; else sub-op
+ sbrc z_flags,ZFL_C ;
+ ori temp2,0x60 ;
+ andi z_flags, ~( (1<<ZFL_S) | (1<<ZFL_Z) | (1<<ZFL_H) )
+ add opl,temp2 ;
+ in temp,SREG ;
+ bst temp,AVR_Z ;Z-Flag
+ bld z_flags,ZFL_Z ;
+ bst temp,AVR_N ;S-Flag
+ bst z_flags,ZFL_S ;
+ sbrc temp2,5 ;C-Flag, set if 0x06 added
+ ori z_flags,(1<<ZFL_C) ;
+ ;H-Flag?
+ ret
+
+do_op_da_sub: ;TODO:
+ rcall do_op_inv
+ ret
+#endif
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|SCF |--0-01|Set Carry Flag |CY=1 |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;
+;
+do_op_scf:
+ andi z_flags,~((1<<ZFL_H)|(1<<ZFL_N))
+ ori z_flags,(1<<ZFL_C)
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CCF |--?-0*|Complement Carry Flag|CY=~CY |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|SCF |---- 1|Set Carry Flag |CY=1 |
+;
+;TODO: H-Flag
+do_op_ccf:
+ do_z80_flags_clear_N
+ ldi temp,(1<<ZFL_C)
+ eor z_flags,temp
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CPL |--1-1-|Complement |A=~A |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|CPL |---- -|Complement |A=~A |
+;
+;
+do_op_cpl:
+ com z_a
+ do_z80_flags_set_HN
+ ret
+
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|PUSH xx |------|Push |-[SP]=xx |
+;|PUSH qq |------|Push |-[SP]=qq |
+;
+;
+do_op_push16:
+ movw xl,z_spl
+ sbiw x,1
+ mem_write_s oph
+ sbiw x,1
+ mem_write_s opl
+ movw z_spl,xl
+
+.if STACK_DBG
+ printnewline
+ printstring "Stack push "
+ movw temp,opl
+ rcall printhexw
+ printstring ", SP is now "
+ movw temp,z_spl
+ rcall printhexw
+ printstring ". "
+.endif
+
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|POP xx |------|Pop |xx=[SP]+ |
+;|POP qq |------|Pop |qq=[SP]+ |
+;
+;
+do_op_pop16:
+ movw x,z_spl
+ mem_read_d opl
+ adiw x,1
+ mem_read_d oph
+ adiw x,1
+ movw z_spl,x
+
+.if STACK_DBG
+ printnewline
+ printstring "Stack pop "
+ movw temp,opl
+ rcall printhexw
+ printstring ", SP is now "
+ movw temp,z_spl
+ rcall printhexw
+ printstring ". "
+.endif
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|EX [SP],HL|------|Exchange |[SP]<->HL |
+;|EX DE,HL |------|Exchange |DE<->HL |
+;-----------------------------Z80--------------------------------
+;
+do_op_exhl:
+ lds temp,z_l
+ lds temp2,z_h
+ sts z_l,opl
+ sts z_h,oph
+ movw opl,temp
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;
+; TODO: Implement IFF1, IFF2
+do_op_di:
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;
+; TODO: Implement IFF1, IFF2
+do_op_ei:
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CALL cc,nn|------|Conditional Call |If cc CALL |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|RET cc |------|Conditional Return |If cc RET |
+;
+;
+do_op_ifnz:
+ sbrs z_flags, ZFL_Z
+ ret
+ pop temp ; nix tun
+ pop temp ; direkt zuruech zu main
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CALL cc,nn|------|Conditional Call |If cc CALL |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|RET cc |------|Conditional Return |If cc RET |
+;
+;
+do_op_ifz:
+ sbrc z_flags, ZFL_Z
+ ret
+ pop temp ; nix tun
+ pop temp ; direkt zuruech zu main
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CALL cc,nn|------|Conditional Call |If cc CALL |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|RET cc |------|Conditional Return |If cc RET |
+;
+;
+do_op_ifnc:
+ sbrs z_flags, ZFL_C
+ ret
+ pop temp ; nix tun
+ pop temp ; direkt zuruech zu main
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CALL cc,nn|------|Conditional Call |If cc CALL |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|RET cc |------|Conditional Return |If cc RET |
+;
+;
+do_op_ifc:
+ sbrc z_flags, ZFL_C
+ ret
+ pop temp ; nix tun
+ pop temp ; direkt zuruech zu main
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CALL cc,nn|------|Conditional Call |If cc CALL |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|RET cc |------|Conditional Return |If cc RET |
+;
+;
+do_op_ifpo:
+ sbrs z_flags, ZFL_P
+ ret
+ pop temp ; nix tun
+ pop temp ; direkt zuruech zu main
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CALL cc,nn|------|Conditional Call |If cc CALL |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|RET cc |------|Conditional Return |If cc RET |
+;
+;
+do_op_ifpe:
+ sbrc z_flags, ZFL_P
+ ret
+ pop temp ; nix tun
+ pop temp ; direkt zuruech zu main
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CALL cc,nn|------|Conditional Call |If cc CALL |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|RET cc |------|Conditional Return |If cc RET |
+;
+;
+do_op_ifp: ;sign positive, aka s=0
+ sbrs z_flags, ZFL_S
+ ret
+ pop temp ; nix tun
+ pop temp ; direkt zuruech zu main
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CALL cc,nn|------|Conditional Call |If cc CALL |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|RET cc |------|Conditional Return |If cc RET |
+;
+;
+do_op_ifm: ;sign negative, aka s=1
+ sbrc z_flags, ZFL_S
+ ret
+ pop temp ; nix tun
+ 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.
+
+;.org (PC+255) & 0xff00
+todo_table:
+instr do_fetch_nop, op_nop, do_store_nop ;00 ;NOP
+instr do_fetch_DIR16, op_nop, do_store_BC ;01 nn nn ;LD BC,nn
+instr do_fetch_A, op_nop, do_store_MBC ;02 ;LD (BC),A
+instr do_fetch_BC, op_INC16, do_store_BC ;03 ;INC BC
+instr do_fetch_B, op_INC, do_store_B ;04 ;INC B
+instr do_fetch_B, op_DEC, do_store_B ;05 ;DEC B
+instr do_fetch_DIR8, op_nop, do_store_B ;06 ;LD B,n
+instr do_fetch_A, op_RLC, do_store_A ;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_MBC, op_nop, do_store_A ;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_C, op_DEC, do_store_C ;0D ;DEC C
+instr do_fetch_DIR8, op_nop, do_store_C ;0E nn ;LD C,n
+instr do_fetch_A, op_RRC, do_store_A ;0F ;RRCA
+instr do_fetch_nop, op_INV, do_store_nop ;10 oo ;DJNZ o
+instr do_fetch_DIR16, op_nop, do_store_DE ;11 nn nn ;LD DE,nn
+instr do_fetch_A, op_nop, do_store_MDE ;12 ;LD (DE),A
+instr do_fetch_DE, op_INC16, do_store_DE ;13 ;INC DE
+instr do_fetch_D, op_INC, do_store_D ;14 ;INC D
+instr do_fetch_D, op_DEC, do_store_D ;15 ;DEC D
+instr do_fetch_DIR8, op_nop, do_store_D ;16 nn ;LD D,n
+instr do_fetch_A, op_RL, do_store_A ;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_MDE, op_nop, do_store_A ;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_E, op_DEC, do_store_E ;1D ;DEC E
+instr do_fetch_DIR8, op_nop, do_store_E ;1E nn ;LD E,n
+instr do_fetch_A, op_RR, do_store_A ;1F ;RRA
+instr do_fetch_nop, op_INV, do_store_nop ;20 oo ;JR NZ,o
+instr do_fetch_DIR16, op_nop, do_store_HL ;21 nn nn ;LD HL,nn
+instr do_fetch_DIR16, op_STHL, do_store_nop ;22 nn nn ;LD (nn),HL
+instr do_fetch_HL, op_INC16, do_store_HL ;23 ;INC HL
+instr do_fetch_H, op_INC, do_store_H ;24 ;INC H
+instr do_fetch_H, op_DEC, do_store_H ;25 ;DEC H
+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_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_L, op_DEC, do_store_L ;2D ;DEC L
+instr do_fetch_DIR8, op_nop, do_store_L ;2E nn ;LD L,n
+instr do_fetch_nop, op_CPL, do_store_nop ;2F ;CPL
+instr do_fetch_nop, op_INV, do_store_nop ;30 oo ;JR NC,o
+instr do_fetch_DIR16, op_nop, do_store_SP ;31 nn nn ;LD SP,nn
+instr do_fetch_DIR16, op_nop, do_store_AM ;32 nn nn ;LD (nn),A
+instr do_fetch_SP, op_INC16, do_store_SP ;33 ;INC SP
+instr do_fetch_MHL, op_INC, do_store_MHL ;34 ;INC (HL)
+instr do_fetch_MHL, op_DEC, do_store_MHL ;35 ;DEC (HL)
+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_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_DECA, do_store_nop ;3D ;DEC A
+instr do_fetch_DIR8, op_nop, do_store_A ;3E nn ;LD A,n
+instr do_fetch_nop, op_CCF, do_store_nop ;3F ;CCF (Complement Carry Flag, gvd)
+instr do_fetch_B, op_nop, do_store_B ;40 ;LD B,B
+instr do_fetch_C, op_nop, do_store_B ;41 ;LD B,C
+instr do_fetch_D, op_nop, do_store_B ;42 ;LD B,D
+instr do_fetch_E, op_nop, do_store_B ;43 ;LD B,E
+instr do_fetch_H, op_nop, do_store_B ;44 ;LD B,H
+instr do_fetch_L, op_nop, do_store_B ;45 ;LD B,L
+instr do_fetch_MHL, op_nop, do_store_B ;46 ;LD B,(HL)
+instr do_fetch_A, op_nop, do_store_B ;47 ;LD B,A
+instr do_fetch_B, op_nop, do_store_C ;48 ;LD C,B
+instr do_fetch_C, op_nop, do_store_C ;49 ;LD C,C
+instr do_fetch_D, op_nop, do_store_C ;4A ;LD C,D
+instr do_fetch_E, op_nop, do_store_C ;4B ;LD C,E
+instr do_fetch_H, op_nop, do_store_C ;4C ;LD C,H
+instr do_fetch_L, op_nop, do_store_C ;4D ;LD C,L
+instr do_fetch_MHL, op_nop, do_store_C ;4E ;LD C,(HL)
+instr do_fetch_A, op_nop, do_store_C ;4F ;LD C,A
+instr do_fetch_B, op_nop, do_store_D ;50 ;LD D,B
+instr do_fetch_C, op_nop, do_store_D ;51 ;LD D,C
+instr do_fetch_D, op_nop, do_store_D ;52 ;LD D,D
+instr do_fetch_E, op_nop, do_store_D ;53 ;LD D,E
+instr do_fetch_H, op_nop, do_store_D ;54 ;LD D,H
+instr do_fetch_L, op_nop, do_store_D ;55 ;LD D,L
+instr do_fetch_MHL, op_nop, do_store_D ;56 ;LD D,(HL)
+instr do_fetch_A, op_nop, do_store_D ;57 ;LD D,A
+instr do_fetch_B, op_nop, do_store_E ;58 ;LD E,B
+instr do_fetch_C, op_nop, do_store_E ;59 ;LD E,C
+instr do_fetch_D, op_nop, do_store_E ;5A ;LD E,D
+instr do_fetch_E, op_nop, do_store_E ;5B ;LD E,E
+instr do_fetch_H, op_nop, do_store_E ;5C ;LD E,H
+instr do_fetch_L, op_nop, do_store_E ;5D ;LD E,L
+instr do_fetch_MHL, op_nop, do_store_E ;5E ;LD E,(HL)
+instr do_fetch_A, op_nop, do_store_E ;5F ;LD E,A
+instr do_fetch_B, op_nop, do_store_H ;60 ;LD H,B
+instr do_fetch_C, op_nop, do_store_H ;61 ;LD H,C
+instr do_fetch_D, op_nop, do_store_H ;62 ;LD H,D
+instr do_fetch_E, op_nop, do_store_H ;63 ;LD H,E
+instr do_fetch_H, op_nop, do_store_H ;64 ;LD H,H
+instr do_fetch_L, op_nop, do_store_H ;65 ;LD H,L
+instr do_fetch_MHL, op_nop, do_store_H ;66 ;LD H,(HL)
+instr do_fetch_A, op_nop, do_store_H ;67 ;LD H,A
+instr do_fetch_B, op_nop, do_store_L ;68 ;LD L,B
+instr do_fetch_C, op_nop, do_store_L ;69 ;LD L,C
+instr do_fetch_D, op_nop, do_store_L ;6A ;LD L,D
+instr do_fetch_E, op_nop, do_store_L ;6B ;LD L,E
+instr do_fetch_H, op_nop, do_store_L ;6C ;LD L,H
+instr do_fetch_L, op_nop, do_store_L ;6D ;LD L,L
+instr do_fetch_MHL, op_nop, do_store_L ;6E ;LD L,(HL)
+instr do_fetch_A, op_nop, do_store_L ;6F ;LD L,A
+instr do_fetch_B, op_nop, do_store_MHL ;70 ;LD (HL),B
+instr do_fetch_C, op_nop, do_store_MHL ;71 ;LD (HL),C
+instr do_fetch_D, op_nop, do_store_MHL ;72 ;LD (HL),D
+instr do_fetch_E, op_nop, do_store_MHL ;73 ;LD (HL),E
+instr do_fetch_H, op_nop, do_store_MHL ;74 ;LD (HL),H
+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_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_H, op_nop, do_store_A ;7C ;LD A,H
+instr do_fetch_L, op_nop, do_store_A ;7D ;LD A,L
+instr do_fetch_MHL, op_nop, do_store_A ;7E ;LD A,(HL)
+instr do_fetch_A, op_nop, do_store_A ;7F ;LD A,A
+instr do_fetch_B, op_ADDA, do_store_nop ;80 ;ADD A,B
+instr do_fetch_C, op_ADDA, do_store_nop ;81 ;ADD A,C
+instr do_fetch_D, op_ADDA, do_store_nop ;82 ;ADD A,D
+instr do_fetch_E, op_ADDA, do_store_nop ;83 ;ADD A,E
+instr do_fetch_H, op_ADDA, do_store_nop ;84 ;ADD A,H
+instr do_fetch_L, op_ADDA, do_store_nop ;85 ;ADD A,L
+instr do_fetch_MHL, op_ADDA, do_store_nop ;86 ;ADD A,(HL)
+instr do_fetch_A, op_ADDA, do_store_nop ;87 ;ADD A,A
+instr do_fetch_B, op_ADCA, do_store_nop ;88 ;ADC A,B
+instr do_fetch_C, op_ADCA, do_store_nop ;89 ;ADC A,C
+instr do_fetch_D, op_ADCA, do_store_nop ;8A ;ADC A,D
+instr do_fetch_E, op_ADCA, do_store_nop ;8B ;ADC A,E
+instr do_fetch_H, op_ADCA, do_store_nop ;8C ;ADC A,H
+instr do_fetch_L, op_ADCA, do_store_nop ;8D ;ADC A,L
+instr do_fetch_MHL, op_ADCA, do_store_nop ;8E ;ADC A,(HL)
+instr do_fetch_A, op_ADCA, do_store_nop ;8F ;ADC A,A
+instr do_fetch_B, op_SUBFA, do_store_nop ;90 ;SUB A,B
+instr do_fetch_C, op_SUBFA, do_store_nop ;91 ;SUB A,C
+instr do_fetch_D, op_SUBFA, do_store_nop ;92 ;SUB A,D
+instr do_fetch_E, op_SUBFA, do_store_nop ;93 ;SUB A,E
+instr do_fetch_H, op_SUBFA, do_store_nop ;94 ;SUB A,H
+instr do_fetch_L, op_SUBFA, do_store_nop ;95 ;SUB A,L
+instr do_fetch_MHL, op_SUBFA, do_store_nop ;96 ;SUB A,(HL)
+instr do_fetch_A, op_SUBFA, do_store_nop ;97 ;SUB A,A
+instr do_fetch_B, op_SBCFA, do_store_nop ;98 ;SBC A,B
+instr do_fetch_C, op_SBCFA, do_store_nop ;99 ;SBC A,C
+instr do_fetch_D, op_SBCFA, do_store_nop ;9A ;SBC A,D
+instr do_fetch_E, op_SBCFA, do_store_nop ;9B ;SBC A,E
+instr do_fetch_H, op_SBCFA, do_store_nop ;9C ;SBC A,H
+instr do_fetch_L, op_SBCFA, do_store_nop ;9D ;SBC A,L
+instr do_fetch_MHL, op_SBCFA, do_store_nop ;9E ;SBC A,(HL)
+instr do_fetch_A, op_SBCFA, do_store_nop ;9F ;SBC A,A
+instr do_fetch_B, op_ANDA, do_store_nop ;A0 ;AND A,B
+instr do_fetch_C, op_ANDA, do_store_nop ;A1 ;AND A,C
+instr do_fetch_D, op_ANDA, do_store_nop ;A2 ;AND A,D
+instr do_fetch_E, op_ANDA, do_store_nop ;A3 ;AND A,E
+instr do_fetch_H, op_ANDA, do_store_nop ;A4 ;AND A,H
+instr do_fetch_L, op_ANDA, do_store_nop ;A5 ;AND A,L
+instr do_fetch_MHL, op_ANDA, do_store_nop ;A6 ;AND A,(HL)
+instr do_fetch_A, op_ANDA, do_store_nop ;A7 ;AND A,A
+instr do_fetch_B, op_XORA, do_store_nop ;A8 ;XOR A,B
+instr do_fetch_C, op_XORA, do_store_nop ;A9 ;XOR A,C
+instr do_fetch_D, op_XORA, do_store_nop ;AA ;XOR A,D
+instr do_fetch_E, op_XORA, do_store_nop ;AB ;XOR A,E
+instr do_fetch_H, op_XORA, do_store_nop ;AC ;XOR A,H
+instr do_fetch_L, op_XORA, do_store_nop ;AD ;XOR A,L
+instr do_fetch_MHL, op_XORA, do_store_nop ;AE ;XOR A,(HL)
+instr do_fetch_A, op_XORA, do_store_nop ;AF ;XOR A,A
+instr do_fetch_B, op_ORA, do_store_nop ;B0 ;OR A,B
+instr do_fetch_C, op_ORA, do_store_nop ;B1 ;OR A,C
+instr do_fetch_D, op_ORA, do_store_nop ;B2 ;OR A,D
+instr do_fetch_E, op_ORA, do_store_nop ;B3 ;OR A,E
+instr do_fetch_H, op_ORA, do_store_nop ;B4 ;OR A,H
+instr do_fetch_L, op_ORA, do_store_nop ;B5 ;OR A,L
+instr do_fetch_MHL, op_ORA, do_store_nop ;B6 ;OR A,(HL)
+instr do_fetch_A, op_ORA, do_store_nop ;B7 ;OR A,A
+instr do_fetch_B, op_CPFA, do_store_nop ;B8 ;CP A,B
+instr do_fetch_C, op_CPFA, do_store_nop ;B9 ;CP A,C
+instr do_fetch_D, op_CPFA, do_store_nop ;BA ;CP A,D
+instr do_fetch_E, op_CPFA, do_store_nop ;BB ;CP A,E
+instr do_fetch_H, op_CPFA, do_store_nop ;BC ;CP A,H
+instr do_fetch_L, op_CPFA, do_store_nop ;BD ;CP A,L
+instr do_fetch_MHL, op_CPFA, do_store_nop ;BE ;CP A,(HL)
+instr do_fetch_A, op_CPFA, do_store_nop ;BF ;CP A,A
+instr do_fetch_nop, op_IFNZ, do_store_RET ;C0 ;RET NZ
+instr do_fetch_nop, op_POP16, do_store_BC ;C1 ;POP BC
+instr do_fetch_DIR16, op_IFNZ, do_store_PC ;C2 nn nn ;JP NZ,nn
+instr do_fetch_DIR16, op_nop, do_store_PC ;C3 nn nn ;JP nn
+instr do_fetch_DIR16, op_IFNZ, do_store_CALL ;C4 nn nn ;CALL NZ,nn
+instr do_fetch_BC, op_PUSH16, do_store_nop ;C5 ;PUSH BC
+instr do_fetch_DIR8, op_ADDA, do_store_nop ;C6 nn ;ADD A,n
+instr do_fetch_RST, op_nop, do_store_CALL ;C7 ;RST 0
+instr do_fetch_nop, op_IFZ, do_store_RET ;C8 ;RET Z
+instr do_fetch_nop, op_nop, do_store_RET ;C9 ;RET
+instr do_fetch_DIR16, op_IFZ, do_store_PC ;CA nn nn ;JP Z,nn
+instr do_fetch_nop, op_INV, do_store_nop ;CB ;(Z80 specific)
+instr do_fetch_DIR16, op_IFZ, do_store_CALL ;CC nn nn ;CALL Z,nn
+instr do_fetch_DIR16, op_nop, do_store_CALL ;CD nn nn ;CALL nn
+instr do_fetch_DIR8, op_ADCA, do_store_nop ;CE nn ;ADC A,n
+instr do_fetch_RST, op_nop, do_store_CALL ;CF ;RST 8H
+instr do_fetch_nop, op_IFNC, do_store_RET ;D0 ;RET NC
+instr do_fetch_nop, op_POP16, do_store_DE ;D1 ;POP DE
+instr do_fetch_DIR16, op_IFNC, do_store_PC ;D2 nn nn ;JP NC,nn
+instr do_fetch_DIR8, op_OUTA, do_store_nop ;D3 nn ;OUT (n),A
+instr do_fetch_DIR16, op_IFNC, do_store_CALL ;D4 nn nn ;CALL NC,nn
+instr do_fetch_DE, op_PUSH16, do_store_nop ;D5 ;PUSH DE
+instr do_fetch_DIR8, op_SUBFA, do_store_nop ;D6 nn ;SUB n
+instr do_fetch_RST, op_nop, do_store_CALL ;D7 ;RST 10H
+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_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
+instr do_fetch_RST, op_nop, do_store_CALL ;DF ;RST 18H
+instr do_fetch_nop, op_IFPO, do_store_RET ;E0 ;RET PO
+instr do_fetch_nop, op_POP16, do_store_HL ;E1 ;POP HL
+instr do_fetch_DIR16, op_IFPO, do_store_PC ;E2 nn nn ;JP PO,nn
+instr do_fetch_MSP, op_EXHL, do_store_MSP ;E3 ;EX (SP),HL
+instr do_fetch_DIR16, op_IFPO, do_store_CALL ;E4 nn nn ;CALL PO,nn
+instr do_fetch_HL, op_PUSH16, do_store_nop ;E5 ;PUSH HL
+instr do_fetch_DIR8, op_ANDA, do_store_nop ;E6 nn ;AND n
+instr do_fetch_RST, op_nop, do_store_CALL ;E7 ;RST 20H
+instr do_fetch_nop, op_IFPE, do_store_RET ;E8 ;RET PE
+instr do_fetch_HL, op_nop, do_store_PC ;E9 ;JP HL
+instr do_fetch_DIR16, op_IFPE, do_store_PC ;EA nn nn ;JP PE,nn
+instr do_fetch_DE, op_EXHL, do_store_DE ;EB ;EX DE,HL
+instr do_fetch_DIR16, op_IFPE, do_store_CALL ;EC nn nn ;CALL PE,nn
+instr do_fetch_nop, op_INV, do_store_nop ;ED ;(Z80 specific)
+instr do_fetch_DIR8, op_XORA, do_store_nop ;EE nn ;XOR n
+instr do_fetch_RST, op_nop, do_store_CALL ;EF ;RST 28H
+instr do_fetch_nop, op_IFP, do_store_RET ;F0 ;RET P
+instr do_fetch_nop, op_POP16, do_store_AF ;F1 ;POP AF
+instr do_fetch_DIR16, op_IFP, do_store_PC ;F2 nn nn ;JP P,nn
+instr do_fetch_nop, op_DI, do_store_nop ;F3 ;DI
+instr do_fetch_DIR16, op_IFP, do_store_CALL ;F4 nn nn ;CALL P,nn
+instr do_fetch_AF, op_PUSH16, do_store_nop ;F5 ;PUSH AF
+instr do_fetch_DIR8, op_ORA, do_store_nop ;F6 nn ;OR n
+instr do_fetch_RST, op_nop, do_store_CALL ;F7 ;RST 30H
+instr do_fetch_nop, op_IFM, do_store_RET ;F8 ;RET M
+instr do_fetch_HL, op_nop, do_store_SP ;F9 ;LD SP,HL
+instr do_fetch_DIR16, op_IFM, do_store_PC ;FA nn nn ;JP M,nn
+instr do_fetch_nop, op_EI, do_store_nop ;FB ;EI
+instr do_fetch_DIR16, op_IFM, do_store_CALL ;FC nn nn ;CALL M,nn
+instr do_fetch_nop, op_INV, do_store_nop ;FD ;(Z80 specific)
+instr do_fetch_DIR8, op_CPFA, do_store_nop ;FE nn ;CP n
+instr do_fetch_RST, op_nop, do_store_CALL ;FF ;RST 38H
+
+;----------------------------------------------------------------
+; 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
+
+ .org (PC+255) & 0xff00
+sz53p_tab:
+ .db 0x44,0x00,0x00,0x04,0x00,0x04,0x04,0x00
+ .db 0x08,0x0c,0x0c,0x08,0x0c,0x08,0x08,0x0c
+ .db 0x00,0x04,0x04,0x00,0x04,0x00,0x00,0x04
+ .db 0x0c,0x08,0x08,0x0c,0x08,0x0c,0x0c,0x08
+ .db 0x20,0x24,0x24,0x20,0x24,0x20,0x20,0x24
+ .db 0x2c,0x28,0x28,0x2c,0x28,0x2c,0x2c,0x28
+ .db 0x24,0x20,0x20,0x24,0x20,0x24,0x24,0x20
+ .db 0x28,0x2c,0x2c,0x28,0x2c,0x28,0x28,0x2c
+ .db 0x00,0x04,0x04,0x00,0x04,0x00,0x00,0x04
+ .db 0x0c,0x08,0x08,0x0c,0x08,0x0c,0x0c,0x08
+ .db 0x04,0x00,0x00,0x04,0x00,0x04,0x04,0x00
+ .db 0x08,0x0c,0x0c,0x08,0x0c,0x08,0x08,0x0c
+ .db 0x24,0x20,0x20,0x24,0x20,0x24,0x24,0x20
+ .db 0x28,0x2c,0x2c,0x28,0x2c,0x28,0x28,0x2c
+ .db 0x20,0x24,0x24,0x20,0x24,0x20,0x20,0x24
+ .db 0x2c,0x28,0x28,0x2c,0x28,0x2c,0x2c,0x28
+ .db 0x80,0x84,0x84,0x80,0x84,0x80,0x80,0x84
+ .db 0x8c,0x88,0x88,0x8c,0x88,0x8c,0x8c,0x88
+ .db 0x84,0x80,0x80,0x84,0x80,0x84,0x84,0x80
+ .db 0x88,0x8c,0x8c,0x88,0x8c,0x88,0x88,0x8c
+ .db 0xa4,0xa0,0xa0,0xa4,0xa0,0xa4,0xa4,0xa0
+ .db 0xa8,0xac,0xac,0xa8,0xac,0xa8,0xa8,0xac
+ .db 0xa0,0xa4,0xa4,0xa0,0xa4,0xa0,0xa0,0xa4
+ .db 0xac,0xa8,0xa8,0xac,0xa8,0xac,0xac,0xa8
+ .db 0x84,0x80,0x80,0x84,0x80,0x84,0x84,0x80
+ .db 0x88,0x8c,0x8c,0x88,0x8c,0x88,0x88,0x8c
+ .db 0x80,0x84,0x84,0x80,0x84,0x80,0x80,0x84
+ .db 0x8c,0x88,0x88,0x8c,0x88,0x8c,0x8c,0x88
+ .db 0xa0,0xa4,0xa4,0xa0,0xa4,0xa0,0xa0,0xa4
+ .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
+
--- /dev/null
+; 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.
+; Copyright (C) 2010 Horst S.
+
+; This file is part of avrcpm.
+;
+; avrcpm is free software: you can redistribute it and/or modify it
+; under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; avrcpm is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with avrcpm. If not, see <http://www.gnu.org/licenses/>.
+;
+; $Id$
+;
+
+;--------------------------------------------------
+; Generate a table entry for one instruction
+;
+; instr fetch, op, store
+;
+.macro instr
+ .db low(@2), low(@1), high(@1), low(@0)
+.endm
+
+
+ .dseg
+
+z_b: .byte 1
+z_c: .byte 1
+z_d: .byte 1
+z_e: .byte 1
+z_h: .byte 1
+z_l: .byte 1
+
+
+ .cseg
+
+;Init z80
+z80_init:
+ ldi z_pcl,low (IPLADDR)
+ ldi z_pch,high(IPLADDR)
+
+ cbi flags,trace
+ printnewline
+ printstring "Ok, CPU is live!"
+ printnewline
+
+;----------------------------------------------------------
+; 1 2 3 4
+;.db (low)do_store (low)do_op (hihg)do_op (low)do_fetch
+;
+;das kommt auf den stapel
+; main da solls zum schluss weitergehen
+;do_store wohin damit beenden mit RET
+;do_op was tun beenden mit RET
+;
+;das wird direkt angesprungen
+;do_fetch woher beenden mit RET
+;
+;
+main:
+.if INS_DEBUG
+ cbi flags,trace
+ cpi z_pch,DBG_TRACE_BOTTOM
+ brlo notraceon
+ cpi z_pch,DBG_TRACE_TOP
+ brsh notraceon
+ sbi flags,trace
+notraceon:
+.endif
+
+
+.if PRINT_PC
+ cpi z_pch,DBG_TRACE_BOTTOM
+ brlo noprintpc
+ cpi z_pch,DBG_TRACE_TOP
+ brsh noprintpc
+
+ printnewline
+ printstring "PC="
+ movw temp,z_pcl
+ rcall printhexw
+ printstring " "
+noprintpc:
+.endif
+
+.if INS_DEBUG
+ sbic flags,trace
+ rcall printregs
+.endif
+
+ ;hier kommt die Interruptbehandlung rein
+
+ ldi zl,low(main) ;da will ich wieder hin.
+ ldi zh,high(main) ;
+ push zl ;
+ push zh ;
+ mem_read_s z_pc ;temp=memReadByte(z_pc)
+ adiw z_pcl,1 ;++z_pc
+ ldi zl,low(todo_table*2) ;zhl=todo_table
+ ldi zh,high(todo_table*2) ;
+ ldi temp2,4 ;1
+ mul temp,temp2 ;2
+ add zl,r0 ;1
+ adc zh,r1 ;1
+ ldi temp2,high(store_ops) ;
+ lpm temp,Z+ ;do_store
+ push temp ; low
+ push temp2 ; high
+
+ 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
+
+
+
+; ------------ Fetch phase stuff -----------------
+
+.org (PC+255) & 0xff00 ; wichtig !!!fetch und store muessen in einer page liegen
+fetch_ops:
+do_nop:
+ ret
+
+do_fetch_a:
+ mov opl,z_a
+ ret
+
+do_fetch_b:
+ lds opl,z_b
+ ret
+
+do_fetch_c:
+ lds opl,z_c
+ ret
+
+do_fetch_d:
+ lds opl,z_d
+ ret
+
+do_fetch_e:
+ lds opl,z_e
+ ret
+
+do_fetch_h:
+ lds opl,z_h
+ ret
+
+do_fetch_l:
+ lds opl,z_l
+ ret
+
+do_fetch_af:
+ mov opl,z_flags
+ mov oph,z_a
+ ret
+
+do_fetch_bc:
+ lds opl,z_c
+ lds oph,z_b
+ ret
+
+do_fetch_de:
+ lds opl,z_e
+ lds oph,z_d
+ ret
+
+do_fetch_hl:
+ lds opl,z_l
+ lds oph,z_h
+ ret
+
+do_fetch_sp:
+ movw opl,z_spl
+ ret
+
+do_fetch_mbc:
+ lds xh,z_b
+ lds xl,z_c
+ mem_read_d opl
+ ret
+
+do_fetch_mde:
+ lds xh,z_d
+ lds xl,z_e
+ mem_read_d opl
+ ret
+
+do_fetch_mhl:
+ lds xh,z_h
+ lds xl,z_l
+ mem_read_d opl
+ ret
+
+do_fetch_msp:
+ movw x,z_spl
+ mem_read_d opl
+ adiw x,1
+ mem_read_d oph
+ ret
+
+do_fetch_dir8:
+ mem_read_ds opl, z_pc
+ adiw z_pcl,1
+ ret
+
+do_fetch_dir16:
+ mem_read_ds opl, z_pc
+ adiw z_pcl,1
+ mem_read_ds oph, z_pc
+ adiw z_pcl,1
+ ret
+
+do_fetch_rst:
+ movw x,z_pcl
+ sbiw x,1
+ mem_read_d opl
+ andi opl,0x38
+ ldi oph,0
+ ret
+
+; ------------ Store phase stuff -----------------
+
+.org (PC+255) & 0xff00 ; wichtig !!!fetch und store muessen in einer page liegen
+store_ops:
+ ret
+
+do_store_a:
+ mov z_a,opl
+ ret
+
+do_store_b:
+ sts z_b,opl
+ ret
+
+do_store_c:
+ sts z_c,opl
+ ret
+
+do_store_d:
+ sts z_d,opl
+ ret
+
+do_store_e:
+ sts z_e,opl
+ ret
+
+do_store_h:
+ sts z_h,opl
+ ret
+
+do_store_l:
+ sts z_l,opl
+ ret
+
+do_store_af:
+ mov z_a,oph
+ mov z_flags,opl
+ ret
+
+do_store_bc:
+ sts z_b,oph
+ sts z_c,opl
+ ret
+
+do_store_de:
+ sts z_d,oph
+ sts z_e,opl
+ ret
+
+do_store_hl:
+ sts z_h,oph
+ sts z_l,opl
+ ret
+
+do_store_mbc:
+ lds xh,z_b
+ lds xl,z_c
+ mem_write_s opl
+ ret
+
+do_store_mde:
+ lds xh,z_d
+ lds xl,z_e
+ mem_write_s opl
+ ret
+
+do_store_mhl:
+ lds xh,z_h
+ lds xl,z_l
+ mem_write_s opl
+ ret
+
+do_store_msp:
+ movw xl,z_spl
+ mem_write_s opl
+ adiw xl,1
+ mem_write_s oph
+ ret
+
+do_store_sp:
+ movw z_spl,opl
+ ret
+
+do_store_pc:
+ movw z_pcl,opl
+ ret
+
+do_store_ret:
+ movw x,z_spl
+ mem_read_d z_pcl
+ adiw x,1
+ mem_read_d z_pch
+ adiw x,1
+ movw z_spl,x
+
+.if STACK_DBG
+ printnewline
+ printstring "Stack pop "
+ movw temp,z_pcl
+ rcall printhexw
+ printstring ", SP is now "
+ movw temp,z_spl
+ rcall printhexw
+ printstring ". "
+.endif
+ ret
+
+do_store_call:
+ movw xl,z_spl
+ sbiw x,1
+ mem_write_s z_pch
+ sbiw x,1
+ mem_write_s z_pcl
+ movw z_spl,xl
+
+.if STACK_DBG
+ printnewline
+ printstring "Stack push "
+ movw temp,z_pcl
+ rcall printhexw
+ printstring ", SP is now "
+ movw temp,z_spl
+ rcall printhexw
+ printstring ". "
+.endif
+ movw z_pcl,opl
+ ret
+
+
+do_store_am:
+ mem_write_ds op, z_a
+ ret
+
+; ------------ Operation phase stuff -----------------
+
+
+;----------------------------------------------------------------
+;| |
+;| Zilog |
+;| |
+;| ZZZZZZZ 88888 000 |
+;| Z 8 8 0 0 |
+;| Z 8 8 0 0 0 |
+;| Z 88888 0 0 0 |
+;| Z 8 8 0 0 0 |
+;| Z 8 8 0 0 |
+;| ZZZZZZZ 88888 000 |
+;| |
+;| Z80 MICROPROCESSOR Instruction Set Summary |
+;| |
+;----------------------------------------------------------------
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;|----------+------+---------------------+----------------------|
+;|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 |
+;|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 |
+;|CALL nn |------|Unconditional Call |-[SP]=PC,PC=nn |
+;|CCF |--?-0*|Complement Carry Flag|CY=~CY |
+;|CP s |***V1*|Compare |A-s |
+;|CPD |****1-|Compare and Decrement|A-[HL],HL=HL-1,BC=BC-1|
+;|CPDR |****1-|Compare, Dec., Repeat|CPD till A=[HL]or BC=0|
+;|CPI |****1-|Compare and Increment|A-[HL],HL=HL+1,BC=BC-1|
+;|CPIR |****1-|Compare, Inc., Repeat|CPI till A=[HL]or BC=0|
+;|CPL |--1-1-|Complement |A=~A |
+;|DAA |***P-*|Decimal Adjust Acc. |A=BCD format |
+;|DEC s |***V1-|Decrement |s=s-1 |
+;|DEC xx |------|Decrement |xx=xx-1 |
+;|DEC ss |------|Decrement |ss=ss-1 |
+;|DI |------|Disable Interrupts | |
+;|DJNZ e |------|Dec., Jump Non-Zero |B=B-1 till B=0 |
+;|EI |------|Enable Interrupts | |
+;|EX [SP],HL|------|Exchange |[SP]<->HL |
+;|EX [SP],xx|------|Exchange |[SP]<->xx |
+;|EX AF,AF' |------|Exchange |AF<->AF' |
+;|EX DE,HL |------|Exchange |DE<->HL |
+;|EXX |------|Exchange |qq<->qq' (except AF)|
+;|HALT |------|Halt | |
+;|IM n |------|Interrupt Mode | (n=0,1,2)|
+;|IN A,[n] |------|Input |A=[n] |
+;|IN r,[C] |***P0-|Input |r=[C] |
+;|INC r |***V0-|Increment |r=r+1 |
+;|INC [HL] |***V0-|Increment |[HL]=[HL]+1 |
+;|INC xx |------|Increment |xx=xx+1 |
+;|INC [xx+d]|***V0-|Increment |[xx+d]=[xx+d]+1 |
+;|INC ss |------|Increment |ss=ss+1 |
+;|IND |?*??1-|Input and Decrement |[HL]=[C],HL=HL-1,B=B-1|
+;|INDR |?1??1-|Input, Dec., Repeat |IND till B=0 |
+;|INI |?*??1-|Input and Increment |[HL]=[C],HL=HL+1,B=B-1|
+;|INIR |?1??1-|Input, Inc., Repeat |INI till B=0 |
+;|JP [HL] |------|Unconditional Jump |PC=[HL] |
+;|JP [xx] |------|Unconditional Jump |PC=[xx] |
+;|JP nn |------|Unconditional Jump |PC=nn |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|JR e |------|Unconditional Jump |PC=PC+e |
+;|JR cc,e |------|Conditional Jump |If cc JR(cc=C,NC,NZ,Z)|
+;|LD dst,src|------|Load |dst=src |
+;|LD A,i |**0*0-|Load |A=i (i=I,R)|
+;|LDD |--0*0-|Load and Decrement |[DE]=[HL],HL=HL-1,# |
+;|LDDR |--000-|Load, Dec., Repeat |LDD till BC=0 |
+;|LDI |--0*0-|Load and Increment |[DE]=[HL],HL=HL+1,# |
+;|LDIR |--000-|Load, Inc., Repeat |LDI till BC=0 |
+;|NEG |***V1*|Negate |A=-A |
+;|NOP |------|No Operation | |
+;|OR s |**0P00|Logical inclusive OR |A=Avs |
+;|OTDR |?1??1-|Output, Dec., Repeat |OUTD till B=0 |
+;|OTIR |?1??1-|Output, Inc., Repeat |OUTI till B=0 |
+;|OUT [C],r |------|Output |[C]=r |
+;|OUT [n],A |------|Output |[n]=A |
+;|OUTD |?*??1-|Output and Decrement |[C]=[HL],HL=HL-1,B=B-1|
+;|OUTI |?*??1-|Output and Increment |[C]=[HL],HL=HL+1,B=B-1|
+;|POP xx |------|Pop |xx=[SP]+ |
+;|POP qq |------|Pop |qq=[SP]+ |
+;|PUSH xx |------|Push |-[SP]=xx |
+;|PUSH qq |------|Push |-[SP]=qq |
+;|RES b,m |------|Reset bit |m=m&{~2^b} |
+;|RET |------|Return |PC=[SP]+ |
+;|RET cc |------|Conditional Return |If cc RET |
+;|RETI |------|Return from Interrupt|PC=[SP]+ |
+;|RETN |------|Return from NMI |PC=[SP]+ |
+;|RL m |**0P0*|Rotate Left |m={CY,m}<- |
+;|RLA |--0-0*|Rotate Left Acc. |A={CY,A}<- |
+;|RLC m |**0P0*|Rotate Left Circular |m=m<- |
+;|RLCA |--0-0*|Rotate Left Circular |A=A<- |
+;|RLD |**0P0-|Rotate Left 4 bits |{A,[HL]}={A,[HL]}<- ##|
+;|RR m |**0P0*|Rotate Right |m=->{CY,m} |
+;|RRA |--0-0*|Rotate Right Acc. |A=->{CY,A} |
+;|RRC m |**0P0*|Rotate Right Circular|m=->m |
+;|RRCA |--0-0*|Rotate Right Circular|A=->A |
+;|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 |
+;|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 |
+;|SRA m |**0P0*|Shift Right Arith. |m=m/2 |
+;|SRL m |**0P0*|Shift Right Logical |m=->{0,m,CY} |
+;|SUB s |***V1*|Subtract |A=A-s |
+;|XOR s |**0P00|Logical Exclusive OR |A=Axs |
+;|----------+------+--------------------------------------------|
+;| F |-*01? |Flag unaffected/affected/reset/set/unknown |
+;| S |S |Sign flag (Bit 7) |
+;| Z | Z |Zero flag (Bit 6) |
+;| HC | H |Half Carry flag (Bit 4) |
+;| P/V | P |Parity/Overflow flag (Bit 2, V=overflow) |
+;| N | N |Add/Subtract flag (Bit 1) |
+;| CY | C|Carry flag (Bit 0) |
+;|-----------------+--------------------------------------------|
+;| n |Immediate addressing |
+;| nn |Immediate extended addressing |
+;| e |Relative addressing (PC=PC+2+offset) |
+;| [nn] |Extended addressing |
+;| [xx+d] |Indexed addressing |
+;| r |Register addressing |
+;| [rr] |Register indirect addressing |
+;| |Implied addressing |
+;| b |Bit addressing |
+;| p |Modified page zero addressing (see RST) |
+;|-----------------+--------------------------------------------|
+;|DEFB n(,...) |Define Byte(s) |
+;|DEFB 'str'(,...) |Define Byte ASCII string(s) |
+;|DEFS nn |Define Storage Block |
+;|DEFW nn(,...) |Define Word(s) |
+;|-----------------+--------------------------------------------|
+;| A B C D E |Registers (8-bit) |
+;| AF BC DE HL |Register pairs (16-bit) |
+;| F |Flag register (8-bit) |
+;| I |Interrupt page address register (8-bit) |
+;| IX IY |Index registers (16-bit) |
+;| PC |Program Counter register (16-bit) |
+;| R |Memory Refresh register |
+;| SP |Stack Pointer register (16-bit) |
+;|-----------------+--------------------------------------------|
+;| b |One bit (0 to 7) |
+;| cc |Condition (C,M,NC,NZ,P,PE,PO,Z) |
+;| d |One-byte expression (-128 to +127) |
+;| dst |Destination s, ss, [BC], [DE], [HL], [nn] |
+;| e |One-byte expression (-126 to +129) |
+;| m |Any register r, [HL] or [xx+d] |
+;| n |One-byte expression (0 to 255) |
+;| nn |Two-byte expression (0 to 65535) |
+;| pp |Register pair BC, DE, IX or SP |
+;| qq |Register pair AF, BC, DE or HL |
+;| qq' |Alternative register pair AF, BC, DE or HL |
+;| r |Register A, B, C, D, E, H or L |
+;| rr |Register pair BC, DE, IY or SP |
+;| s |Any register r, value n, [HL] or [xx+d] |
+;| src |Source s, ss, [BC], [DE], [HL], nn, [nn] |
+;| ss |Register pair BC, DE, HL or SP |
+;| xx |Index register IX or IY |
+;|-----------------+--------------------------------------------|
+;| + - * / ^ |Add/subtract/multiply/divide/exponent |
+;| & ~ v x |Logical AND/NOT/inclusive OR/exclusive OR |
+;| <- -> |Rotate left/right |
+;| [ ] |Indirect addressing |
+;| [ ]+ -[ ] |Indirect addressing auto-increment/decrement|
+;| { } |Combination of operands |
+;| # |Also BC=BC-1,DE=DE-1 |
+;| ## |Only lower 4 bits of accumulator A used |
+;----------------------------------------------------------------
+
+;How the flags are supposed to work:
+;7 ZFL_S - Sign flag (=MSBit of result)
+;6 ZFL_Z - Zero flag. Is 1 when the result is 0
+;4 ZFL_H - Half-carry (carry from bit 3 to 4)
+;2 ZFL_P - Parity/2-complement Overflow
+;1 ZFL_N - Subtract - set if last op was a subtract
+;0 ZFL_C - Carry
+;
+;I sure hope I got the mapping between flags and instructions correct...
+
+.equ ZFL_S = 7
+.equ ZFL_Z = 6
+.equ ZFL_H = 4
+.equ ZFL_P = 2
+.equ ZFL_N = 1
+.equ ZFL_C = 0
+
+.equ AVR_T = SREG_T
+.equ AVR_H = SREG_H
+.equ AVR_S = SREG_S
+.equ AVR_V = SREG_V
+.equ AVR_N = SREG_N
+.equ AVR_Z = SREG_Z
+.equ AVR_C = SREG_C
+
+;------------------------------------------------;
+; Load table value from flash indexed by source reg.
+;
+;ldpmx dstreg,tablebase,indexreg
+;
+; (6 words, 8 cycles)
+
+.macro ldpmx
+ ldi zh,high(@1*2) ; table must be page aligned
+ mov zl,@2
+ lpm @0,z
+.endm
+
+.macro do_z80_flags_HP
+#if EM_Z80
+ bmov z_flags, ZFL_P, temp, AVR_V
+ 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_set_HN
+#if EM_Z80
+ ori z_flags,(1<<ZFL_N)|(1<<ZFL_H)
+#endif
+.endm
+
+.macro do_z80_flags_clear_N
+#if EM_Z80
+ andi z_flags,~(1<<ZFL_N)
+#endif
+.endm
+
+.macro do_z80_flags_op_rotate
+ ; must not change avr carry flag!
+#if EM_Z80
+ andi z_flags, ~( (1<<ZFL_H) | (1<<ZFL_N) | (1<<ZFL_C) )
+#else
+ andi z_flags, ~( (1<<ZFL_C) )
+#endif
+.endm
+
+.macro do_z80_flags_op_and
+#if EM_Z80
+ ori z_flags,(1<<ZFL_H)
+#else
+ ori z_flags,(1<<ZFL_H)
+#endif
+.endm
+
+.macro do_z80_flags_op_or
+#if EM_Z80
+#endif
+.endm
+
+
+;----------------------------------------------------------------
+
+do_op_inv:
+ printstring "Invalid opcode @ PC="
+ movw temp,z_pcl
+ rcall printhexw
+
+haltinv:
+ rjmp haltinv
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|OUT [n],A |------|Output |[n]=A |
+;
+;
+;Interface with peripherials goes here :)
+do_op_outa: ; out (opl),a
+.if PORT_DEBUG
+ printnewline
+ printstring "Port write: "
+ mov temp,z_a
+ rcall printhex
+ printstring " -> ("
+ mov temp,opl
+ rcall printhex
+ printstring ") "
+.endif
+ mov temp,z_a
+ mov temp2,opl
+ rcall portWrite
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|IN A,[n] |------|Input |A=[n] |
+;
+;
+do_op_in: ; in a,(opl)
+.if PORT_DEBUG
+ printnewline
+ printstring "Port read: ("
+ mov temp,opl
+ rcall printhex
+ printstring ") -> "
+.endif
+
+ mov temp2,opl
+ rcall portRead
+ mov opl,temp
+
+.if PORT_DEBUG
+ rcall printhex
+ printstring " "
+.endif
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|INC r |***V0-|Increment |r=r+1 |
+;|INC [HL] |***V0-|Increment |[HL]=[HL]+1 |
+;|INC [xx+d]|***V0-|Increment |[xx+d]=[xx+d]+1 |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|INC r |**-P0-|Increment |r=r+1 |
+;|INC [HL] |**-P0-|Increment |[HL]=[HL]+1 |
+;
+;
+do_op_inc:
+ inc opl
+#if EM_Z80
+ in temp, sreg
+#endif
+ andi z_flags,(1<<ZFL_H)|(1<<ZFL_C) ; preserve C-, and H-flag
+ ldpmx temp2, sz53p_tab, opl
+ or z_flags,temp2 ;
+ do_z80_flags_HP
+ ret
+
+do_op_inca:
+ inc z_a
+#if EM_Z80
+ in temp, sreg
+#endif
+ andi z_flags,(1<<ZFL_H)|(1<<ZFL_C) ; preserve C-, and H-flag
+ ldpmx temp2, sz53p_tab, z_a
+ or z_flags,temp2 ;
+ do_z80_flags_HP
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|DEC r |***V1-|Decrement |s=s-1 |
+;|INC [HL] |***V0-|Increment |[HL]=[HL]+1 |
+;|INC [xx+d]|***V0-|Increment |[xx+d]=[xx+d]+1 |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|DEC r |**-P -|Increment |r=r+1 |
+;|DEC [HL] |**-P -|Increment |[HL]=[HL]+1 |
+;
+;
+do_op_dec:
+ dec opl
+#if EM_Z80
+ in temp, sreg
+#endif
+ andi z_flags,(1<<ZFL_H)|(1<<ZFL_C) ; preserve C-, and H-flag
+ ldpmx temp2, sz53p_tab, opl
+ or z_flags,temp2 ;
+ do_z80_flags_HP
+ do_z80_flags_set_N
+ ret
+
+do_op_deca:
+ dec z_a
+#if EM_Z80
+ in temp, sreg
+#endif
+ andi z_flags,(1<<ZFL_H)|(1<<ZFL_C) ; preserve C-, and H-flag
+ ldpmx temp2, sz53p_tab, z_a
+ or z_flags,temp2 ;
+ do_z80_flags_HP
+ do_z80_flags_set_N
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|INC xx |------|Increment |xx=xx+1 |
+;|INC ss |------|Increment |ss=ss+1 |
+;
+;
+do_op_inc16:
+ subi opl,low(-1)
+ sbci oph,high(-1)
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|DEC xx |------|Decrement |xx=xx-1 |
+;|DEC ss |------|Decrement |ss=ss-1 |
+;
+;
+do_op_dec16:
+ subi opl, 1
+ sbci oph, 0
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|RLCA |--0-0*|Rotate Left Circular |A=A<- |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|RLCA |---- *|Rotate Left Circular |A=A<- |
+;
+;
+do_op_rlc:
+ ;Rotate Left Cyclical. All bits move 1 to the
+ ;left, the msb becomes c and lsb.
+ do_z80_flags_op_rotate
+ lsl opl
+ brcc do_op_rlc_noc
+ ori opl, 1
+ ori z_flags, (1<<ZFL_C)
+do_op_rlc_noc:
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|RRCA |--0-0*|Rotate Right Circular|A=->A |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|RRCA |---- *|Rotate Right Circular|A=->A |
+;
+;
+do_op_rrc:
+ ;Rotate Right Cyclical. All bits move 1 to the
+ ;right, the lsb becomes c and msb.
+ do_z80_flags_op_rotate
+ lsr opl
+ brcc do_op_rrc_noc
+ ori opl, 0x80
+ ori z_flags, (1<<ZFL_C)
+do_op_rrc_noc:
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|RRA |--0-0*|Rotate Right Acc. |A=->{CY,A} |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|RRA |---- *|Rotate Right Acc. |A=->{CY,A} |
+;
+;
+do_op_rr:
+ ;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
+ sec
+ do_z80_flags_op_rotate ; (clear ZFL_C, doesn't change AVR_C)
+ bmov z_flags,ZFL_C, opl,0 ; Bit 0 --> CY
+ ror opl
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|RLA |--0-0*|Rotate Left Acc. |A={CY,A}<- |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|RLA |---- *|Rotate Left Acc. |A={CY,A}<- |
+;
+;
+do_op_rl:
+ ;Rotate Left. All bits move 1 to the left, the msb
+ ;becomes c, c becomes lsb.
+ clc
+ sbrc z_flags,ZFL_C
+ sec
+ do_z80_flags_op_rotate ; (clear ZFL_C, doesn't change AVR_C)
+ bmov z_flags,ZFL_C, opl,7 ; Bit 7 --> CY
+ rol opl
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|ADD A,s |***V0*|Add |A=A+s |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|ADD A,s |***P *|Add |A=A+s |
+;
+;
+do_op_adda:
+ add z_a,opl
+ in temp,sreg
+ ldpmx z_flags,sz53p_tab,z_a ;S,Z,P flag
+ bmov z_flags,ZFL_C, temp,AVR_C
+ do_z80_flags_HP
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|ADC A,s |***V0*|Add with Carry |A=A+s+CY |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|ADC A,s |***P *|Add with Carry |A=A+s+CY |
+;
+;
+do_op_adca:
+ clc
+ sbrc z_flags,ZFL_C
+ sec
+ adc z_a,opl
+ in temp,sreg
+ ldpmx z_flags,sz53p_tab,z_a ;S,Z,P
+ bmov z_flags,ZFL_C, temp,AVR_C
+ do_z80_flags_HP
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|SUB s |***V1*|Subtract |A=A-s |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|SUB s |***P *|Subtract |A=A-s |
+
+;
+do_op_subfa:
+ sub z_a,opl
+ in temp,sreg
+ ldpmx z_flags,sz53p_tab,z_a ;S,Z,P
+ bmov z_flags,ZFL_C, temp,AVR_C
+ do_z80_flags_HP
+ do_z80_flags_set_N
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CP s |***V1*|Compare |A-s |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|CP s |***P *|Compare |A-s |
+
+;
+do_op_cpfa:
+ mov temp,z_a
+ sub temp,opl
+ mov opl,temp
+ in temp,sreg
+ ldpmx z_flags,sz53p_tab,opl ;S,Z,P
+ bmov z_flags,ZFL_C, temp,AVR_C
+ do_z80_flags_HP
+ do_z80_flags_set_N
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|SBC A,s |***V1*|Subtract with Carry |A=A-s-CY |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|SBC A,s |***P *|Subtract with Carry |A=A-s-CY |
+;
+;
+do_op_sbcfa:
+ clc
+ sbrc z_flags,ZFL_C
+ sec
+ sbc z_a,opl
+ in temp,sreg
+ ldpmx z_flags,sz53p_tab,z_a ;S,Z,P
+ bmov z_flags,ZFL_C, temp,AVR_C
+ do_z80_flags_HP
+ do_z80_flags_set_N
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|AND s |**1P00|Logical AND |A=A&s |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|AND s |**-P 0|Logical AND |A=A&s |
+;
+; TODO H-Flag
+do_op_anda:
+ and z_a,opl ;
+ ldpmx z_flags,sz53p_tab,z_a ;S,Z,P,N,C
+ do_z80_flags_op_and
+ ret
+
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|OR s |**0P00|Logical inclusive OR |A=Avs |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|OR s |**-P00|Logical inclusive OR |A=Avs |
+;
+; TODO: H-Flag
+do_op_ora:
+ or z_a,opl
+ ldpmx z_flags,sz53p_tab,z_a ;S,Z,H,P,N,C
+ do_z80_flags_op_or
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|XOR s |**0P00|Logical Exclusive OR |A=Axs |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|XOR s |**-P 0|Logical Exclusive OR |A=Axs |
+;
+; TODO: H-Flag
+do_op_xora:
+ eor z_a,opl
+ ldpmx z_flags,sz53p_tab,z_a ;S,Z,H,P,N,C
+ do_z80_flags_op_or
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|ADD HL,ss |--?-0*|Add |HL=HL+ss |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|ADD HL,ss |---- *|Add |HL=HL+ss |
+;
+;
+do_op_addhl:
+ lds temp,z_l
+ lds temp2,z_h
+ add opl,temp
+ adc oph,temp2
+ in temp,sreg
+ bmov z_flags,ZFL_H, temp,AVR_H
+ bmov z_flags,ZFL_C, temp,AVR_C
+ do_z80_flags_clear_N
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|LD dst,src|------|Load |dst=src |
+;
+;
+do_op_sthl: ;store hl to mem loc in opl:h
+ movw xl,opl
+ lds temp,z_l
+ mem_write
+ adiw xl,1
+ lds temp,z_h
+ mem_write
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|LD dst,src|------|Load |dst=src |
+;
+;
+do_op_rmem16:
+ movw xl,opl
+ mem_read_d opl
+ adiw x,1
+ mem_read_d oph
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|LD dst,src|------|Load |dst=src |
+;
+;
+do_op_rmem8:
+ mem_read_ds opl, op
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|DAA |***P-*|Decimal Adjust Acc. | |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;
+; Not yet checked
+
+; Description (http://www.z80.info/z80syntx.htm#DAA):
+; This instruction conditionally adjusts the accumulator for BCD addition
+; and subtraction operations. For addition (ADD, ADC, INC) or subtraction
+; (SUB, SBC, DEC, NEC), the following table indicates the operation performed:
+;
+; -------------------------------------------------------------------------------
+; | | C Flag | HEX value in | H Flag | HEX value in | Number | C flag|
+; | Operation| Before | upper digit | Before | lower digit | added | After |
+; | | DAA | (bit 7-4) | DAA | (bit 3-0) | to byte | DAA |
+; |-----------------------------------------------------------------------------|
+; | | 0 | 0-9 | 0 | 0-9 | 00 | 0 |
+; | ADD | 0 | 0-8 | 0 | A-F | 06 | 0 |
+; | | 0 | 0-9 | 1 | 0-3 | 06 | 0 |
+; | ADC | 0 | A-F | 0 | 0-9 | 60 | 1 |
+; | | 0 | 9-F | 0 | A-F | 66 | 1 |
+; | INC | 0 | A-F | 1 | 0-3 | 66 | 1 |
+; | | 1 | 0-2 | 0 | 0-9 | 60 | 1 |
+; | | 1 | 0-2 | 0 | A-F | 66 | 1 |
+; | | 1 | 0-3 | 1 | 0-3 | 66 | 1 |
+; |-----------------------------------------------------------------------------|
+; | SUB | 0 | 0-9 | 0 | 0-9 | 00 | 0 |
+; | SBC | 0 | 0-8 | 1 | 6-F | FA | 0 |
+; | DEC | 1 | 7-F | 0 | 0-9 | A0 | 1 |
+; | NEG | 1 | 6-F | 1 | 6-F | 9A | 1 |
+; |-----------------------------------------------------------------------------|
+;
+; Flags:
+; C: See instruction.
+; N: Unaffected.
+; P/V: Set if Acc. is even parity after operation, reset otherwise.
+; H: See instruction.
+; 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:
+ ldi oph,0 ; what to add
+ sbrc z_flags,ZFL_H ; if H-Flag
+ rjmp op_da_06
+ mov temp,opl
+ andi temp,0x0f ; ... or lower digit > 9
+ cpi temp,0x0a
+ brlo op_da_06n
+op_da_06:
+ ori oph,0x06
+op_da_06n:
+ sbrc z_flags,(1<<ZFL_C)
+ rjmp op_da_60
+ cpi opl,0xa0
+ brlo op_da_60n
+op_da_60:
+ ori oph,0x60
+op_da_60n:
+ cpi opl,0x9a
+ brlo op_da_99n
+ ori z_flags,(1<<ZFL_C); set C
+op_da_99n:
+ sbrs z_flags,ZFL_N ; if sub-op
+ rjmp op_da_add ; then
+ sub opl,oph
+ rjmp op_da_ex
+op_da_add: ; else add-op
+ cpi opl,0x91
+ brlo op_da_60n2
+ mov temp,opl
+ andi temp,0x0f
+ cpi temp,0x0a
+ brlo op_da_60n2
+ ori oph,0x60
+op_da_60n2:
+ add opl,oph
+op_da_ex:
+ in temp,SREG
+ sbrc temp,AVR_H
+ ori z_flags,(1<<ZFL_C)
+ andi z_flags,(1<<ZFL_N)|(1<<ZFL_C) ; preserve C,N
+ ldpmx temp2, sz53p_tab, opl ; get S,Z,P
+ or z_flags,temp2
+ bmov z_flags,ZFL_H, temp,AVR_H ; H (?)
+ ret
+#else
+
+do_op_da:
+ sbrc z_flags,ZFL_N ; if add-op
+ rjmp do_op_da_sub ; then
+ ldi temp2,0 ;
+ mov temp,opl ;
+ andi temp,0x0f ;
+ cpi temp,0x0a ;if lower digit > 9
+ brlo do_op_da_h ;
+ ori temp2,0x06 ; add 6 to lower digit
+do_op_da_h: ;
+ sbrc z_flags,ZFL_H ; ... or H-Flag
+ ori temp2,0x06 ;
+ add opl,temp2 ;
+
+ ldi temp2,0 ;
+ mov temp,opl ;
+ andi temp,0xf0 ;
+ cpi temp,0xa0 ;
+ brlo do_op_da_c ;
+ ori temp2,0x60 ;
+do_op_da_c: ; else sub-op
+ sbrc z_flags,ZFL_C ;
+ ori temp2,0x60 ;
+ andi z_flags, ~( (1<<ZFL_S) | (1<<ZFL_Z) | (1<<ZFL_H) )
+ add opl,temp2 ;
+ in temp,SREG ;
+ bst temp,AVR_Z ;Z-Flag
+ bld z_flags,ZFL_Z ;
+ bst temp,AVR_N ;S-Flag
+ bst z_flags,ZFL_S ;
+ sbrc temp2,5 ;C-Flag, set if 0x06 added
+ ori z_flags,(1<<ZFL_C) ;
+ ;H-Flag?
+ ret
+
+do_op_da_sub: ;TODO:
+ rcall do_op_inv
+ ret
+#endif
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|SCF |--0-01|Set Carry Flag |CY=1 |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;
+;
+do_op_scf:
+ andi z_flags,~((1<<ZFL_H)|(1<<ZFL_N))
+ ori z_flags,(1<<ZFL_C)
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CCF |--?-0*|Complement Carry Flag|CY=~CY |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|SCF |---- 1|Set Carry Flag |CY=1 |
+;
+;TODO: H-Flag
+do_op_ccf:
+ do_z80_flags_clear_N
+ ldi temp,(1<<ZFL_C)
+ eor z_flags,temp
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CPL |--1-1-|Complement |A=~A |
+;|----------|SZHP C|---------- 8080 ----------------------------|
+;|CPL |---- -|Complement |A=~A |
+;
+;
+do_op_cpl:
+ com z_a
+ do_z80_flags_set_HN
+ ret
+
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|PUSH xx |------|Push |-[SP]=xx |
+;|PUSH qq |------|Push |-[SP]=qq |
+;
+;
+do_op_push16:
+ movw xl,z_spl
+ sbiw x,1
+ mem_write_s oph
+ sbiw x,1
+ mem_write_s opl
+ movw z_spl,xl
+
+.if STACK_DBG
+ printnewline
+ printstring "Stack push "
+ movw temp,opl
+ rcall printhexw
+ printstring ", SP is now "
+ movw temp,z_spl
+ rcall printhexw
+ printstring ". "
+.endif
+
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|POP xx |------|Pop |xx=[SP]+ |
+;|POP qq |------|Pop |qq=[SP]+ |
+;
+;
+do_op_pop16:
+ movw x,z_spl
+ mem_read_d opl
+ adiw x,1
+ mem_read_d oph
+ adiw x,1
+ movw z_spl,x
+
+.if STACK_DBG
+ printnewline
+ printstring "Stack pop "
+ movw temp,opl
+ rcall printhexw
+ printstring ", SP is now "
+ movw temp,z_spl
+ rcall printhexw
+ printstring ". "
+.endif
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|EX [SP],HL|------|Exchange |[SP]<->HL |
+;|EX DE,HL |------|Exchange |DE<->HL |
+;-----------------------------Z80--------------------------------
+;
+do_op_exhl:
+ lds temp,z_l
+ lds temp2,z_h
+ sts z_l,opl
+ sts z_h,oph
+ movw opl,temp
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;
+; TODO: Implement IFF1, IFF2
+do_op_di:
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;
+; TODO: Implement IFF1, IFF2
+do_op_ei:
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CALL cc,nn|------|Conditional Call |If cc CALL |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|RET cc |------|Conditional Return |If cc RET |
+;
+;
+do_op_ifnz:
+ sbrs z_flags, ZFL_Z
+ ret
+ pop temp ; nix tun
+ pop temp ; direkt zuruech zu main
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CALL cc,nn|------|Conditional Call |If cc CALL |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|RET cc |------|Conditional Return |If cc RET |
+;
+;
+do_op_ifz:
+ sbrc z_flags, ZFL_Z
+ ret
+ pop temp ; nix tun
+ pop temp ; direkt zuruech zu main
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CALL cc,nn|------|Conditional Call |If cc CALL |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|RET cc |------|Conditional Return |If cc RET |
+;
+;
+do_op_ifnc:
+ sbrs z_flags, ZFL_C
+ ret
+ pop temp ; nix tun
+ pop temp ; direkt zuruech zu main
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CALL cc,nn|------|Conditional Call |If cc CALL |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|RET cc |------|Conditional Return |If cc RET |
+;
+;
+do_op_ifc:
+ sbrc z_flags, ZFL_C
+ ret
+ pop temp ; nix tun
+ pop temp ; direkt zuruech zu main
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CALL cc,nn|------|Conditional Call |If cc CALL |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|RET cc |------|Conditional Return |If cc RET |
+;
+;
+do_op_ifpo:
+ sbrs z_flags, ZFL_P
+ ret
+ pop temp ; nix tun
+ pop temp ; direkt zuruech zu main
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CALL cc,nn|------|Conditional Call |If cc CALL |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|RET cc |------|Conditional Return |If cc RET |
+;
+;
+do_op_ifpe:
+ sbrc z_flags, ZFL_P
+ ret
+ pop temp ; nix tun
+ pop temp ; direkt zuruech zu main
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CALL cc,nn|------|Conditional Call |If cc CALL |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|RET cc |------|Conditional Return |If cc RET |
+;
+;
+do_op_ifp: ;sign positive, aka s=0
+ sbrs z_flags, ZFL_S
+ ret
+ pop temp ; nix tun
+ pop temp ; direkt zuruech zu main
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|CALL cc,nn|------|Conditional Call |If cc CALL |
+;|JP cc,nn |------|Conditional Jump |If cc JP |
+;|RET cc |------|Conditional Return |If cc RET |
+;
+;
+do_op_ifm: ;sign negative, aka s=1
+ sbrc z_flags, ZFL_S
+ ret
+ pop temp ; nix tun
+ 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.
+
+;.org (PC+255) & 0xff00
+todo_table:
+instr do_nop, do_NOP, do_nop ;00 ;NOP
+instr do_fetch_DIR16, do_NOP, do_store_BC ;01 nn nn ;LD BC,nn
+instr do_fetch_A, do_NOP, do_store_MBC ;02 ;LD (BC),A
+instr do_fetch_BC, do_op_INC16, do_store_BC ;03 ;INC BC
+instr do_fetch_B, do_op_INC, do_store_B ;04 ;INC B
+instr do_fetch_B, do_op_DEC, do_store_B ;05 ;DEC B
+instr do_fetch_DIR8, do_NOP, do_store_B ;06 ;LD B,n
+instr do_fetch_A, do_op_RLC, do_store_A ;07 ;RLCA
+instr do_nop, do_op_INV, do_nop ;08 ;EX AF,AF'
+instr do_fetch_BC, do_op_ADDHL, do_store_HL ;09 ;ADD HL,BC
+instr do_fetch_MBC, do_NOP, do_store_A ;0A ;LD A,(BC)
+instr do_fetch_BC, do_op_DEC16, do_store_BC ;0B ;DEC BC
+instr do_fetch_C, do_op_INC, do_store_C ;0C ;INC C
+instr do_fetch_C, do_op_DEC, do_store_C ;0D ;DEC C
+instr do_fetch_DIR8, do_NOP, do_store_C ;0E nn ;LD C,n
+instr do_fetch_A, do_op_RRC, do_store_A ;0F ;RRCA
+instr do_nop, do_op_INV, do_nop ;10 oo ;DJNZ o
+instr do_fetch_DIR16, do_NOP, do_store_DE ;11 nn nn ;LD DE,nn
+instr do_fetch_A, do_NOP, do_store_MDE ;12 ;LD (DE),A
+instr do_fetch_DE, do_op_INC16, do_store_DE ;13 ;INC DE
+instr do_fetch_D, do_op_INC, do_store_D ;14 ;INC D
+instr do_fetch_D, do_op_DEC, do_store_D ;15 ;DEC D
+instr do_fetch_DIR8, do_NOP, do_store_D ;16 nn ;LD D,n
+instr do_fetch_A, do_op_RL, do_store_A ;17 ;RLA
+instr do_NOP, do_op_INV, do_nop ;18 oo ;JR o
+instr do_fetch_DE, do_op_ADDHL, do_store_HL ;19 ;ADD HL,DE
+instr do_fetch_MDE, do_NOP, do_store_A ;1A ;LD A,(DE)
+instr do_fetch_DE, do_op_DEC16, do_store_DE ;1B ;DEC DE
+instr do_fetch_E, do_op_INC, do_store_E ;1C ;INC E
+instr do_fetch_E, do_op_DEC, do_store_E ;1D ;DEC E
+instr do_fetch_DIR8, do_NOP, do_store_E ;1E nn ;LD E,n
+instr do_fetch_A, do_op_RR, do_store_A ;1F ;RRA
+instr do_NOP, do_op_INV, do_nop ;20 oo ;JR NZ,o
+instr do_fetch_DIR16, do_NOP, do_store_HL ;21 nn nn ;LD HL,nn
+instr do_fetch_DIR16, do_op_STHL, do_nop ;22 nn nn ;LD (nn),HL
+instr do_fetch_HL, do_op_INC16, do_store_HL ;23 ;INC HL
+instr do_fetch_H, do_op_INC, do_store_H ;24 ;INC H
+instr do_fetch_H, do_op_DEC, do_store_H ;25 ;DEC H
+instr do_fetch_DIR8, do_NOP, do_store_H ;26 nn ;LD H,n
+instr do_fetch_A, do_op_DA, do_store_A ;27 ;DAA
+instr do_NOP, do_op_INV, do_nop ;28 oo ;JR Z,o
+instr do_fetch_HL, do_op_ADDHL, do_store_HL ;29 ;ADD HL,HL
+instr do_fetch_DIR16, do_op_RMEM16, do_store_HL ;2A nn nn ;LD HL,(nn)
+instr do_fetch_HL, do_op_DEC16, do_store_HL ;2B ;DEC HL
+instr do_fetch_L, do_op_INC, do_store_L ;2C ;INC L
+instr do_fetch_L, do_op_DEC, do_store_L ;2D ;DEC L
+instr do_fetch_DIR8, do_NOP, do_store_L ;2E nn ;LD L,n
+instr do_NOP, do_op_CPL, do_nop ;2F ;CPL
+instr do_NOP, do_op_INV, do_nop ;30 oo ;JR NC,o
+instr do_fetch_DIR16, do_NOP, do_store_SP ;31 nn nn ;LD SP,nn
+instr do_fetch_DIR16, do_NOP, do_store_AM ;32 nn nn ;LD (nn),A
+instr do_fetch_SP, do_op_INC16, do_store_SP ;33 ;INC SP
+instr do_fetch_MHL, do_op_INC, do_store_MHL ;34 ;INC (HL)
+instr do_fetch_MHL, do_op_DEC, do_store_MHL ;35 ;DEC (HL)
+instr do_fetch_DIR8, do_NOP, do_store_MHL ;36 nn ;LD (HL),n
+instr do_NOP, do_op_SCF, do_nop ;37 ;SCF
+instr do_NOP, do_op_INV, do_nop ;38 oo ;JR C,o
+instr do_fetch_SP, do_op_ADDHL, do_store_HL ;39 ;ADD HL,SP
+instr do_fetch_DIR16, do_op_RMEM8, do_store_A ;3A nn nn ;LD A,(nn)
+instr do_fetch_SP, do_op_DEC16, do_store_SP ;3B ;DEC SP
+instr do_NOP, do_op_INCA, do_nop ;3C ;INC A
+instr do_NOP, do_op_DECA, do_nop ;3D ;DEC A
+instr do_fetch_DIR8, do_NOP, do_store_A ;3E nn ;LD A,n
+instr do_NOP, do_op_CCF, do_nop ;3F ;CCF (Complement Carry Flag, gvd)
+instr do_fetch_B, do_NOP, do_store_B ;40 ;LD B,B
+instr do_fetch_C, do_NOP, do_store_B ;41 ;LD B,C
+instr do_fetch_D, do_NOP, do_store_B ;42 ;LD B,D
+instr do_fetch_E, do_NOP, do_store_B ;43 ;LD B,E
+instr do_fetch_H, do_NOP, do_store_B ;44 ;LD B,H
+instr do_fetch_L, do_NOP, do_store_B ;45 ;LD B,L
+instr do_fetch_MHL, do_NOP, do_store_B ;46 ;LD B,(HL)
+instr do_fetch_A, do_NOP, do_store_B ;47 ;LD B,A
+instr do_fetch_B, do_NOP, do_store_C ;48 ;LD C,B
+instr do_fetch_C, do_NOP, do_store_C ;49 ;LD C,C
+instr do_fetch_D, do_NOP, do_store_C ;4A ;LD C,D
+instr do_fetch_E, do_NOP, do_store_C ;4B ;LD C,E
+instr do_fetch_H, do_NOP, do_store_C ;4C ;LD C,H
+instr do_fetch_L, do_NOP, do_store_C ;4D ;LD C,L
+instr do_fetch_MHL, do_NOP, do_store_C ;4E ;LD C,(HL)
+instr do_fetch_A, do_NOP, do_store_C ;4F ;LD C,A
+instr do_fetch_B, do_NOP, do_store_D ;50 ;LD D,B
+instr do_fetch_C, do_NOP, do_store_D ;51 ;LD D,C
+instr do_fetch_D, do_NOP, do_store_D ;52 ;LD D,D
+instr do_fetch_E, do_NOP, do_store_D ;53 ;LD D,E
+instr do_fetch_H, do_NOP, do_store_D ;54 ;LD D,H
+instr do_fetch_L, do_NOP, do_store_D ;55 ;LD D,L
+instr do_fetch_MHL, do_NOP, do_store_D ;56 ;LD D,(HL)
+instr do_fetch_A, do_NOP, do_store_D ;57 ;LD D,A
+instr do_fetch_B, do_NOP, do_store_E ;58 ;LD E,B
+instr do_fetch_C, do_NOP, do_store_E ;59 ;LD E,C
+instr do_fetch_D, do_NOP, do_store_E ;5A ;LD E,D
+instr do_fetch_E, do_NOP, do_store_E ;5B ;LD E,E
+instr do_fetch_H, do_NOP, do_store_E ;5C ;LD E,H
+instr do_fetch_L, do_NOP, do_store_E ;5D ;LD E,L
+instr do_fetch_MHL, do_NOP, do_store_E ;5E ;LD E,(HL)
+instr do_fetch_A, do_NOP, do_store_E ;5F ;LD E,A
+instr do_fetch_B, do_NOP, do_store_H ;60 ;LD H,B
+instr do_fetch_C, do_NOP, do_store_H ;61 ;LD H,C
+instr do_fetch_D, do_NOP, do_store_H ;62 ;LD H,D
+instr do_fetch_E, do_NOP, do_store_H ;63 ;LD H,E
+instr do_fetch_H, do_NOP, do_store_H ;64 ;LD H,H
+instr do_fetch_L, do_NOP, do_store_H ;65 ;LD H,L
+instr do_fetch_MHL, do_NOP, do_store_H ;66 ;LD H,(HL)
+instr do_fetch_A, do_NOP, do_store_H ;67 ;LD H,A
+instr do_fetch_B, do_NOP, do_store_L ;68 ;LD L,B
+instr do_fetch_C, do_NOP, do_store_L ;69 ;LD L,C
+instr do_fetch_D, do_NOP, do_store_L ;6A ;LD L,D
+instr do_fetch_E, do_NOP, do_store_L ;6B ;LD L,E
+instr do_fetch_H, do_NOP, do_store_L ;6C ;LD L,H
+instr do_fetch_L, do_NOP, do_store_L ;6D ;LD L,L
+instr do_fetch_MHL, do_NOP, do_store_L ;6E ;LD L,(HL)
+instr do_fetch_A, do_NOP, do_store_L ;6F ;LD L,A
+instr do_fetch_B, do_NOP, do_store_MHL ;70 ;LD (HL),B
+instr do_fetch_C, do_NOP, do_store_MHL ;71 ;LD (HL),C
+instr do_fetch_D, do_NOP, do_store_MHL ;72 ;LD (HL),D
+instr do_fetch_E, do_NOP, do_store_MHL ;73 ;LD (HL),E
+instr do_fetch_H, do_NOP, do_store_MHL ;74 ;LD (HL),H
+instr do_fetch_L, do_NOP, do_store_MHL ;75 ;LD (HL),L
+instr do_NOP, do_op_INV, do_nop ;76 ;HALT
+instr do_fetch_A, do_NOP, do_store_MHL ;77 ;LD (HL),A
+instr do_fetch_B, do_NOP, do_store_A ;78 ;LD A,B
+instr do_fetch_C, do_NOP, do_store_A ;79 ;LD A,C
+instr do_fetch_D, do_NOP, do_store_A ;7A ;LD A,D
+instr do_fetch_E, do_NOP, do_store_A ;7B ;LD A,E
+instr do_fetch_H, do_NOP, do_store_A ;7C ;LD A,H
+instr do_fetch_L, do_NOP, do_store_A ;7D ;LD A,L
+instr do_fetch_MHL, do_NOP, do_store_A ;7E ;LD A,(HL)
+instr do_fetch_A, do_NOP, do_store_A ;7F ;LD A,A
+instr do_fetch_B, do_op_ADDA, do_nop ;80 ;ADD A,B
+instr do_fetch_C, do_op_ADDA, do_nop ;81 ;ADD A,C
+instr do_fetch_D, do_op_ADDA, do_nop ;82 ;ADD A,D
+instr do_fetch_E, do_op_ADDA, do_nop ;83 ;ADD A,E
+instr do_fetch_H, do_op_ADDA, do_nop ;84 ;ADD A,H
+instr do_fetch_L, do_op_ADDA, do_nop ;85 ;ADD A,L
+instr do_fetch_MHL, do_op_ADDA, do_nop ;86 ;ADD A,(HL)
+instr do_fetch_A, do_op_ADDA, do_nop ;87 ;ADD A,A
+instr do_fetch_B, do_op_ADCA, do_nop ;88 ;ADC A,B
+instr do_fetch_C, do_op_ADCA, do_nop ;89 ;ADC A,C
+instr do_fetch_D, do_op_ADCA, do_nop ;8A ;ADC A,D
+instr do_fetch_E, do_op_ADCA, do_nop ;8B ;ADC A,E
+instr do_fetch_H, do_op_ADCA, do_nop ;8C ;ADC A,H
+instr do_fetch_L, do_op_ADCA, do_nop ;8D ;ADC A,L
+instr do_fetch_MHL, do_op_ADCA, do_nop ;8E ;ADC A,(HL)
+instr do_fetch_A, do_op_ADCA, do_nop ;8F ;ADC A,A
+instr do_fetch_B, do_op_SUBFA, do_nop ;90 ;SUB A,B
+instr do_fetch_C, do_op_SUBFA, do_nop ;91 ;SUB A,C
+instr do_fetch_D, do_op_SUBFA, do_nop ;92 ;SUB A,D
+instr do_fetch_E, do_op_SUBFA, do_nop ;93 ;SUB A,E
+instr do_fetch_H, do_op_SUBFA, do_nop ;94 ;SUB A,H
+instr do_fetch_L, do_op_SUBFA, do_nop ;95 ;SUB A,L
+instr do_fetch_MHL, do_op_SUBFA, do_nop ;96 ;SUB A,(HL)
+instr do_fetch_A, do_op_SUBFA, do_nop ;97 ;SUB A,A
+instr do_fetch_B, do_op_SBCFA, do_nop ;98 ;SBC A,B
+instr do_fetch_C, do_op_SBCFA, do_nop ;99 ;SBC A,C
+instr do_fetch_D, do_op_SBCFA, do_nop ;9A ;SBC A,D
+instr do_fetch_E, do_op_SBCFA, do_nop ;9B ;SBC A,E
+instr do_fetch_H, do_op_SBCFA, do_nop ;9C ;SBC A,H
+instr do_fetch_L, do_op_SBCFA, do_nop ;9D ;SBC A,L
+instr do_fetch_MHL, do_op_SBCFA, do_nop ;9E ;SBC A,(HL)
+instr do_fetch_A, do_op_SBCFA, do_nop ;9F ;SBC A,A
+instr do_fetch_B, do_op_ANDA, do_nop ;A0 ;AND A,B
+instr do_fetch_C, do_op_ANDA, do_nop ;A1 ;AND A,C
+instr do_fetch_D, do_op_ANDA, do_nop ;A2 ;AND A,D
+instr do_fetch_E, do_op_ANDA, do_nop ;A3 ;AND A,E
+instr do_fetch_H, do_op_ANDA, do_nop ;A4 ;AND A,H
+instr do_fetch_L, do_op_ANDA, do_nop ;A5 ;AND A,L
+instr do_fetch_MHL, do_op_ANDA, do_nop ;A6 ;AND A,(HL)
+instr do_fetch_A, do_op_ANDA, do_nop ;A7 ;AND A,A
+instr do_fetch_B, do_op_XORA, do_nop ;A8 ;XOR A,B
+instr do_fetch_C, do_op_XORA, do_nop ;A9 ;XOR A,C
+instr do_fetch_D, do_op_XORA, do_nop ;AA ;XOR A,D
+instr do_fetch_E, do_op_XORA, do_nop ;AB ;XOR A,E
+instr do_fetch_H, do_op_XORA, do_nop ;AC ;XOR A,H
+instr do_fetch_L, do_op_XORA, do_nop ;AD ;XOR A,L
+instr do_fetch_MHL, do_op_XORA, do_nop ;AE ;XOR A,(HL)
+instr do_fetch_A, do_op_XORA, do_nop ;AF ;XOR A,A
+instr do_fetch_B, do_op_ORA, do_nop ;B0 ;OR A,B
+instr do_fetch_C, do_op_ORA, do_nop ;B1 ;OR A,C
+instr do_fetch_D, do_op_ORA, do_nop ;B2 ;OR A,D
+instr do_fetch_E, do_op_ORA, do_nop ;B3 ;OR A,E
+instr do_fetch_H, do_op_ORA, do_nop ;B4 ;OR A,H
+instr do_fetch_L, do_op_ORA, do_nop ;B5 ;OR A,L
+instr do_fetch_MHL, do_op_ORA, do_nop ;B6 ;OR A,(HL)
+instr do_fetch_A, do_op_ORA, do_nop ;B7 ;OR A,A
+instr do_fetch_B, do_op_CPFA, do_nop ;B8 ;CP A,B
+instr do_fetch_C, do_op_CPFA, do_nop ;B9 ;CP A,C
+instr do_fetch_D, do_op_CPFA, do_nop ;BA ;CP A,D
+instr do_fetch_E, do_op_CPFA, do_nop ;BB ;CP A,E
+instr do_fetch_H, do_op_CPFA, do_nop ;BC ;CP A,H
+instr do_fetch_L, do_op_CPFA, do_nop ;BD ;CP A,L
+instr do_fetch_MHL, do_op_CPFA, do_nop ;BE ;CP A,(HL)
+instr do_fetch_A, do_op_CPFA, do_nop ;BF ;CP A,A
+instr do_NOP, do_op_IFNZ, do_store_RET ;C0 ;RET NZ
+instr do_NOP, do_op_POP16, do_store_BC ;C1 ;POP BC
+instr do_fetch_DIR16, do_op_IFNZ, do_store_PC ;C2 nn nn ;JP NZ,nn
+instr do_fetch_DIR16, do_NOP, do_store_PC ;C3 nn nn ;JP nn
+instr do_fetch_DIR16, do_op_IFNZ, do_store_CALL ;C4 nn nn ;CALL NZ,nn
+instr do_fetch_BC, do_op_PUSH16, do_nop ;C5 ;PUSH BC
+instr do_fetch_DIR8, do_op_ADDA, do_nop ;C6 nn ;ADD A,n
+instr do_fetch_RST, do_NOP, do_store_CALL ;C7 ;RST 0
+instr do_NOP, do_op_IFZ, do_store_RET ;C8 ;RET Z
+instr do_NOP, do_nop, do_store_RET ;C9 ;RET
+instr do_fetch_DIR16, do_op_IFZ, do_store_PC ;CA nn nn ;JP Z,nn
+instr do_NOP, do_op_INV, do_nop ;CB ;(Z80 specific)
+instr do_fetch_DIR16, do_op_IFZ, do_store_CALL ;CC nn nn ;CALL Z,nn
+instr do_fetch_DIR16, do_NOP, do_store_CALL ;CD nn nn ;CALL nn
+instr do_fetch_DIR8, do_op_ADCA, do_nop ;CE nn ;ADC A,n
+instr do_fetch_RST, do_NOP, do_store_CALL ;CF ;RST 8H
+instr do_NOP, do_op_IFNC, do_store_RET ;D0 ;RET NC
+instr do_NOP, do_op_POP16, do_store_DE ;D1 ;POP DE
+instr do_fetch_DIR16, do_op_IFNC, do_store_PC ;D2 nn nn ;JP NC,nn
+instr do_fetch_DIR8, do_op_OUTA, do_nop ;D3 nn ;OUT (n),A
+instr do_fetch_DIR16, do_op_IFNC, do_store_CALL ;D4 nn nn ;CALL NC,nn
+instr do_fetch_DE, do_op_PUSH16, do_nop ;D5 ;PUSH DE
+instr do_fetch_DIR8, do_op_SUBFA, do_nop ;D6 nn ;SUB n
+instr do_fetch_RST, do_NOP, do_store_CALL ;D7 ;RST 10H
+instr do_NOP, do_op_IFC, do_store_RET ;D8 ;RET C
+instr do_NOP, do_nop, do_nop ;D9 ;EXX
+instr do_fetch_DIR16, do_op_IFC, do_store_PC ;DA nn nn ;JP C,nn
+instr do_fetch_DIR8, do_op_IN, do_store_A ;DB nn ;IN A,(n)
+instr do_fetch_DIR16, do_op_IFC, do_store_CALL ;DC nn nn ;CALL C,nn
+instr do_NOP, do_op_INV, do_nop ;DD ;(Z80 specific)
+instr do_fetch_DIR8, do_op_SBCFA, do_nop ;DE nn ;SBC A,n
+instr do_fetch_RST, do_NOP, do_store_CALL ;DF ;RST 18H
+instr do_NOP, do_op_IFPO, do_store_RET ;E0 ;RET PO
+instr do_NOP, do_op_POP16, do_store_HL ;E1 ;POP HL
+instr do_fetch_DIR16, do_op_IFPO, do_store_PC ;E2 nn nn ;JP PO,nn
+instr do_fetch_MSP, do_op_EXHL, do_store_MSP ;E3 ;EX (SP),HL
+instr do_fetch_DIR16, do_op_IFPO, do_store_CALL ;E4 nn nn ;CALL PO,nn
+instr do_fetch_HL, do_op_PUSH16, do_nop ;E5 ;PUSH HL
+instr do_fetch_DIR8, do_op_ANDA, do_nop ;E6 nn ;AND n
+instr do_fetch_RST, do_NOP, do_store_CALL ;E7 ;RST 20H
+instr do_NOP, do_op_IFPE, do_store_RET ;E8 ;RET PE
+instr do_fetch_HL, do_NOP, do_store_PC ;E9 ;JP HL
+instr do_fetch_DIR16, do_op_IFPE, do_store_PC ;EA nn nn ;JP PE,nn
+instr do_fetch_DE, do_op_EXHL, do_store_DE ;EB ;EX DE,HL
+instr do_fetch_DIR16, do_op_IFPE, do_store_CALL ;EC nn nn ;CALL PE,nn
+instr do_NOP, do_op_INV, do_nop ;ED ;(Z80 specific)
+instr do_fetch_DIR8, do_op_XORA, do_nop ;EE nn ;XOR n
+instr do_fetch_RST, do_NOP, do_store_CALL ;EF ;RST 28H
+instr do_NOP, do_op_IFP, do_store_RET ;F0 ;RET P
+instr do_NOP, do_op_POP16, do_store_AF ;F1 ;POP AF
+instr do_fetch_DIR16, do_op_IFP, do_store_PC ;F2 nn nn ;JP P,nn
+instr do_NOP, do_op_DI, do_nop ;F3 ;DI
+instr do_fetch_DIR16, do_op_IFP, do_store_CALL ;F4 nn nn ;CALL P,nn
+instr do_fetch_AF, do_op_PUSH16, do_nop ;F5 ;PUSH AF
+instr do_fetch_DIR8, do_op_ORA, do_nop ;F6 nn ;OR n
+instr do_fetch_RST, do_NOP, do_store_CALL ;F7 ;RST 30H
+instr do_NOP, do_op_IFM, do_store_RET ;F8 ;RET M
+instr do_fetch_HL, do_NOP, do_store_SP ;F9 ;LD SP,HL
+instr do_fetch_DIR16, do_op_IFM, do_store_PC ;FA nn nn ;JP M,nn
+instr do_NOP, do_op_EI, do_nop ;FB ;EI
+instr do_fetch_DIR16, do_op_IFM, do_store_CALL ;FC nn nn ;CALL M,nn
+instr do_NOP, do_op_INV, do_nop ;FD ;(Z80 specific)
+instr do_fetch_DIR8, do_op_CPFA, do_nop ;FE nn ;CP n
+instr do_fetch_RST, do_NOP, do_store_CALL ;FF ;RST 38H
+
+;----------------------------------------------------------------
+; 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
+
+ .org (PC+255) & 0xff00
+sz53p_tab:
+ .db 0x44,0x00,0x00,0x04,0x00,0x04,0x04,0x00
+ .db 0x08,0x0c,0x0c,0x08,0x0c,0x08,0x08,0x0c
+ .db 0x00,0x04,0x04,0x00,0x04,0x00,0x00,0x04
+ .db 0x0c,0x08,0x08,0x0c,0x08,0x0c,0x0c,0x08
+ .db 0x20,0x24,0x24,0x20,0x24,0x20,0x20,0x24
+ .db 0x2c,0x28,0x28,0x2c,0x28,0x2c,0x2c,0x28
+ .db 0x24,0x20,0x20,0x24,0x20,0x24,0x24,0x20
+ .db 0x28,0x2c,0x2c,0x28,0x2c,0x28,0x28,0x2c
+ .db 0x00,0x04,0x04,0x00,0x04,0x00,0x00,0x04
+ .db 0x0c,0x08,0x08,0x0c,0x08,0x0c,0x0c,0x08
+ .db 0x04,0x00,0x00,0x04,0x00,0x04,0x04,0x00
+ .db 0x08,0x0c,0x0c,0x08,0x0c,0x08,0x08,0x0c
+ .db 0x24,0x20,0x20,0x24,0x20,0x24,0x24,0x20
+ .db 0x28,0x2c,0x2c,0x28,0x2c,0x28,0x28,0x2c
+ .db 0x20,0x24,0x24,0x20,0x24,0x20,0x20,0x24
+ .db 0x2c,0x28,0x28,0x2c,0x28,0x2c,0x2c,0x28
+ .db 0x80,0x84,0x84,0x80,0x84,0x80,0x80,0x84
+ .db 0x8c,0x88,0x88,0x8c,0x88,0x8c,0x8c,0x88
+ .db 0x84,0x80,0x80,0x84,0x80,0x84,0x84,0x80
+ .db 0x88,0x8c,0x8c,0x88,0x8c,0x88,0x88,0x8c
+ .db 0xa4,0xa0,0xa0,0xa4,0xa0,0xa4,0xa4,0xa0
+ .db 0xa8,0xac,0xac,0xa8,0xac,0xa8,0xa8,0xac
+ .db 0xa0,0xa4,0xa4,0xa0,0xa4,0xa0,0xa0,0xa4
+ .db 0xac,0xa8,0xa8,0xac,0xa8,0xac,0xac,0xa8
+ .db 0x84,0x80,0x80,0x84,0x80,0x84,0x84,0x80
+ .db 0x88,0x8c,0x8c,0x88,0x8c,0x88,0x88,0x8c
+ .db 0x80,0x84,0x84,0x80,0x84,0x80,0x80,0x84
+ .db 0x8c,0x88,0x88,0x8c,0x88,0x8c,0x8c,0x88
+ .db 0xa0,0xa4,0xa4,0xa0,0xa4,0xa0,0xa0,0xa4
+ .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
+
#MCU = atmega8
MCU = atmega328P
-#F_CPU = 24576000
F_CPU = 20000000
#BAUD = 19200
BAUD = 57600
#BAUD = 115200
-TARGET = z80
-ASRC = z80.asm
+DRAM_8BIT = 1
+
+TARGET = avrcpm
+ASRC = avrcpm.asm
# Place -D or -U options here
-CDEFS = -DF_CPU=$(F_CPU) -DBAUD=$(BAUD) -D$(MCU)
+CDEFS = -DF_CPU=$(F_CPU) -DBAUD=$(BAUD) -D$(MCU) -DDRAM_8BIT=$(DRAM_8BIT)
WINEPATH = C:/Programme/Atmel/AVR\ Tools/AvrAssembler2
DEFS = $(WINEPATH)/Appnotes
--- /dev/null
+; Z80 emulator with CP/M support. The Z80-specific instructions themselves
+; actually aren't implemented yet, making this more of an i8080 emulator.
+; This is the main file, glueing all parts together.
+
+; Copyright (C) 2010 Sprite_tm
+; Copyright (C) 2010 Leo C.
+;
+; This file is part of avrcpm.
+;
+; avrcpm is free software: you can redistribute it and/or modify it
+; under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; avrcpm is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with avrcpm. If not, see <http://www.gnu.org/licenses/>.
+;
+; $Id$
+;
+
+.nolist
+#if defined atmega8
+ .include "m8def.inc"
+#elif defined atmega168
+ .include "m168def.inc"
+#elif defined atmega328P
+ .include "m328Pdef.inc"
+#else /* default */
+ .include "m88def.inc"
+#endif
+ .include "config.inc"
+ .include "macros.inc"
+#if DRAM_8BIT /* Implies software uart */
+ .include "dram-8bit.inc"
+#else
+ .include "dram-4bit.inc"
+#endif
+ .list
+ .cseg
+ .org 0
+ rjmp start ; reset vector
+
+ .org INT_VECTORS_SIZE
+
+ .include "init.asm"
+ .include "mmc.asm"
+; .include "mmc-old.asm"
+#if DRAM_8BIT /* Implies software uart */
+ .include "sw-uart.asm"
+ .include "dram-8bit.asm"
+#else /* 4 bit RAM, hardware uart */
+ .include "hw-uart.asm"
+ .include "dram-4bit.asm"
+#endif
+ .include "remainders.asm"
+; .include "z80int.asm" ;Old 8080 interpreter.
+; .include "8080int.asm" ;New 8080 interpreter.
+; .include "8080int-t3.asm"
+; .include "8080int-t3-jmp.asm"
+ .include "8080int-jmp.asm"
+
+
+ .dseg
+ramtop: .byte 0
+
+ .cseg
+
+; vim:set ts=8 noet nowrap
+
--- /dev/null
+; Configuration, hardware definition, ...
+;
+; Copyright (C) 2010 Sprite_tm
+; Copyright (C) 2010 Leo C.
+;
+; This file is part of avrcpm.
+;
+; avrcpm is free software: you can redistribute it and/or modify it
+; under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; avrcpm is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with avrcpm. If not, see <http://www.gnu.org/licenses/>.
+;
+; $Id$
+;
+
+
+#define VMAJOR 2 /* Version number */
+#define VMINOR 0
+
+#ifndef DRAM_8BIT
+ #define DRAM_8BIT 0 /* 1 = 8bit wide DRAM */
+#endif
+#ifndef F_CPU
+ #define F_CPU 20000000 /* system clock in Hz; defaults to 20MHz */
+#endif
+#ifndef BAUD
+ #define BAUD 38400 /* console baud rate */
+#endif
+
+#define PARTID 0x52 /* Partition table id */
+ /* http://www.win.tue.nl/~aeb/partitions/partition_types-1.html */
+#define K 1024
+#define M 1204*K
+
+;#define RAMSIZE 256*K*4 /* 1 chip 256Kx4 */
+#define RAMSIZE 4*M*4 * 2 /* 2 chips 4Mx4 */
+
+#define RAMDISKCNT 0 /* Number of RAM disks */
+#define RAMDISKNR 'I'-'A' /* Drive "letter" for first RAM disk */
+
+#define PARTID 0x52 /* Partition table id */
+ /* http://www.win.tue.nl/~aeb/partitions/partition_types-1.html */
+#define IPLADDR 0x2000 /* Bootloader load address */
+
+#define DRAM_WAITSTATES 1 /* Number of additional clock cycles for dram read access */
+#define REFR_RATE 64000 /* dram refresh rate in cycles/s. */
+ /* Most drams need 1/15.6µs. */
+#define RXBUFSIZE 128 /* USART recieve buffer size. Must be power of 2 */
+#define TXBUFSIZE 128 /* USART transmit buffer size. Must be power of 2 */
+
+
+
+#define EM_Z80 0 /* we don't have any z80 instructions yet */
+
+.equ BOOT_DEBUG = 0
+.equ MMC_DEBUG = 0 /* Increase for more debugging */
+.equ INS_DEBUG = 0
+.equ MEMTEST = 1
+.equ BOOTWAIT = 1
+.equ PORT_DEBUG = 0
+.equ DISK_DEBUG = 0 /* Increase for more debugging */
+.equ HOSTRW_DEBUG= 0
+.equ MEMFILL = 1
+.equ STACK_DBG = 0
+.equ PRINT_PC = 0
+
+#define MMC_SPI2X 1 /* 0 = SPI CLK/4, 1 = SPI CLK/2 */
+
+#define MEMFILL_VAL 0xCB /* Fill ram with cbs, which will trigger an invalid opcode error. */
+#define DBG_TRACE_BOTTOM 0x01 /* Page boundaries for INS_DEBUG and PRINT_PC */
+#define DBG_TRACE_TOP 0xdc /* Trace is off, below bottom page and above top page. */
+
+;-----------------------------------------------------------------------
+; Port declarations
+
+#if DRAM_8BIT /* Implies software uart */
+
+;Port D
+.equ RAM_D0 = 0
+.equ RAM_D1 = 1
+.equ RAM_D2 = 2
+.equ RAM_D3 = 3
+.equ RAM_D4 = 4
+.equ RAM_D5 = 5
+.equ RAM_D6 = 6
+.equ RAM_D7 = 7
+.equ RAM_A0 = 0
+.equ RAM_A1 = 1
+.equ RAM_A2 = 2
+.equ RAM_A3 = 3
+.equ RAM_A4 = 4
+.equ RAM_A5 = 5
+.equ RAM_A6 = 6
+.equ RAM_A7 = 7
+
+;Port B
+.equ MMC_MOSI = 3
+.equ MMC_MISO = 4
+.equ MMC_SCK = 5
+.equ RAM_A8 = 3
+.equ RAM_A9 = 4
+.equ RAM_A10 = 5
+
+.equ RXD = 0
+.equ TXD = 1
+.equ MMC_CS = 2
+
+.equ P_MMC_CS = PORTB
+.equ P_A8 = PORTB
+.equ P_RXD = PORTB
+
+;Port C
+.equ RAM_RAS = 0
+.equ RAM_CAS = 1
+.equ RAM_OE = 2
+.equ RAM_W = 3
+
+.equ P_RAS = PORTC
+.equ P_CAS = PORTC
+.equ P_OE = PORTC
+.equ P_W = PORTC
+
+
+#else /* 4 bit RAM, hardware uart */
+
+; Port D
+.equ RXD = 0
+.equ TXD = 1
+.equ RAM_OE = 2
+.equ RAM_A8 = 3
+.equ MMC_CS = 4
+.equ RAM_A5 = 5
+.equ RAM_A6 = 6
+.equ RAM_A7 = 7
+
+.equ P_RXD = PORTD
+.equ P_OE = PORTD
+.equ P_A8 = PORTD
+.equ P_MMC_CS = PORTD
+.equ P_AH = PORTD
+ ; RAM_A[7..5]
+.equ RAM_AH_MASK = (1<<RAM_A8)|(1<<RAM_A7)|(1<<RAM_A6)|(1<<RAM_A5)
+.equ PD_OUTPUT_MASK = (1<<MMC_CS) | (1<<RAM_OE) | RAM_AH_MASK
+
+
+;Port B
+.equ RAM_A4 = 0
+.equ RAM_A3 = 1
+.equ RAM_A2 = 2
+.equ RAM_A1 = 3
+.equ MMC_MOSI = 3
+.equ RAM_A0 = 4
+.equ MMC_MISO = 4
+.equ RAM_RAS = 5
+.equ MMC_SCK = 5
+
+.equ P_RAS = PORTB
+.equ P_AL = PORTB
+ ; RAM_A[4..0]
+.equ RAM_AL_MASK = (1<<RAM_A4)|(1<<RAM_A3)|(1<<RAM_A2)|(1<<RAM_A1)|(1<<RAM_A0)
+.equ PB_OUTPUT_MASK = (1<<RAM_ras) | RAM_AL_MASK
+
+;Port C
+.equ RAM_D0 = 0
+.equ RAM_D1 = 1
+.equ RAM_D2 = 2
+.equ RAM_D3 = 3
+.equ RAM_W = 4
+.equ RAM_CAS = 5
+
+.equ P_DQ = PORTC
+.equ P_W = PORTC
+.equ P_CAS = PORTC
+
+.equ RAM_DQ_MASK = (1<<RAM_D3)|(1<<RAM_D2)|(1<<RAM_D1)|(1<<RAM_D0)
+.equ PC_OUTPUT_MASK = (1<<RAM_CAS)|(1<<RAM_W)
+
+#endif /* DRAM_8BIT */
+
+
+;-----------------------------------------------------------------------
+;Register definitions
+
+.def _tmp0 = r0
+.def _tmp1 = r1
+
+.def _RAS0 = r2
+.def _CAS0 = r3
+.def _OE = r4
+.def _WE = r5
+.def _255 = r6
+.def _0 = r7
+.def z_a = r9
+;.def stx_bitcount = r9
+;.def stx_dr = r10
+.def srx_lastedgel = r10
+.def srx_lastedgeh = r11
+
+.def insstore= r8 ;
+;.def insop = r13 ;
+.def insdecl = r12 ;
+.def insdech = r13 ;
+.def z_spl = r14
+.def z_sph = r15 ;
+.def temp = r16 ;
+.def temp2 = r17 ;
+.def temp3 = r18
+.def temp4 = r19
+.def z_flags = r20 ;
+ ;
+.def opl = r22 ;
+.def oph = r23 ;
+.def z_pcl = r24 ;
+.def z_pch = r25 ;
+; xl ;r26
+; xh ;r27
+; yl ;r28
+; yh ;r29
+; zl ;r30 ;
+; zh ;r31 ;
+
+
+
+#if defined __ATmega8__
+.equ flags = TWBR
+.equ P_PUD = SFIOR
+#else
+.equ flags = GPIOR0
+.equ P_PUD = MCUCR
+#endif
+
+; Flags:
+ .equ hostact = 7 ;host active flag
+ .equ hostwrt = 6 ;host written flag
+ .equ rsflag = 5 ;read sector flag
+ .equ readop = 4 ;1 if read operation
+ .equ trace = 0
+
+; This is the base z80 port address for clock access
+#define TIMERPORT 0x40
+#define TIMER_CTL TIMERPORT
+#define TIMER_MSECS TIMERPORT+1
+#define TIMER_SECS TIMER_MSECS+2
+
+#define starttimercmd 1
+#define quitTimerCmd 2
+#define printTimerCmd 15
+#define uptimeCmd 16
+
+#if defined __ATmega8__
+.equ RXTXDR0 = UDR
+.equ UCSR0A = UCSRA
+.equ UDRE0 = UDRE
+.equ UCSR0B = UCSRB
+.equ RXCIE0 = RXCIE
+.equ UDRIE0 = UDRIE
+.equ RXEN0 = RXEN
+.equ TXEN0 = TXEN
+.equ UCSR0C = UCSRC
+.equ UCSZ00 = UCSZ0
+.equ UCSZ01 = UCSZ1
+.equ UBRR0H = UBRRH
+.equ UBRR0L = UBRRL
+.equ OCR2A = OCR2
+.equ OC2Aaddr= OC2addr
+.equ TCCR2A = TCCR2
+.equ TCCR2B = TCCR2
+.equ TIMSK1 = TIMSK
+.equ TIMSK2 = TIMSK
+.equ OCIE2A = OCIE2
+.equ TIFR1 = TIFR
+.equ ICIE1 = TICIE1
+#else
+.equ RXTXDR0 = UDR0
+#endif
+
+; vim:set ts=8 noet nowrap
+
+
--- /dev/null
+; DRAM interface for *one* 256K x 4 bit DRAM chip.
+; This is part of the Z80-CP/M emulator written by Sprite_tm.
+
+; Copyright (C) 2010 Sprite_tm
+; Copyright (C) 2010 Leo C.
+
+; This file is part of avrcpm.
+;
+; avrcpm is free software: you can redistribute it and/or modify it
+; under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; avrcpm is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with avrcpm. If not, see <http://www.gnu.org/licenses/>.
+;
+; $Id$
+;
+
+
+;----------------------------------------------
+
+; Loads the byte on address xh:xl into temp.
+; Uses temp2. Must not alter xh:xl
+
+ .cseg
+dram_read:
+; cli
+ DRAM_SETADDR xh, ~0,(1<<ram_ras), ~(1<<ram_a8), (1<<ram_oe)
+ cbi P_RAS,ram_ras
+ DRAM_SETADDR xl, ~(1<<ram_ras),0, ~((1<<ram_oe)), (1<<ram_a8)
+ cbi P_CAS,ram_cas
+ cbi P_A8,ram_a8
+ dram_wait DRAM_WAITSTATES ;
+ in temp,P_DQ-2 ; PIN
+ out P_CAS,_255
+
+ cbi P_CAS,ram_cas
+ andi temp,0x0f
+ swap temp
+ dram_wait DRAM_WAITSTATES ;
+ in temp2,P_DQ-2 ; PIN
+ andi temp2,0x0f
+ or temp,temp2
+
+ out P_OE, _255
+ out P_CAS,_255
+ out P_RAS,_255
+; sei
+ ret
+
+
+;Writes the byte in temp to xh:xl
+; Uses temp2. Must not alter xh:xl
+
+dram_write:
+; cli
+ ldi temp2,RAM_DQ_MASK | (1<<ram_w) | (1<<ram_cas)
+ out DDRC,temp2
+
+ mov temp2,temp
+ andi temp,RAM_DQ_MASK & ~(1<<ram_w)
+ ori temp,(1<<ram_cas)
+ out PORTC,temp
+ DRAM_SETADDR xh, ~0,(1<<ram_ras), ~(1<<ram_a8),(1<<ram_oe)
+ cbi P_RAS,ram_ras
+ DRAM_SETADDR xl, ~(1<<ram_ras),0, ~((1<<ram_a8)),(1<<ram_oe)
+ cbi PORTC,ram_cas
+ sbi PORTC,ram_cas
+
+ sbi PORTD,ram_a8
+ swap temp2
+
+ andi temp2,RAM_DQ_MASK & ~(1<<ram_w)
+ ori temp2,(1<<ram_cas)
+ out PORTC,temp2
+ cbr temp2,(1<<ram_cas)
+ out PORTC,temp2
+ ldi temp,~RAM_DQ_MASK | (1<<ram_w) | (1<<ram_cas)
+ out PORTC,_255
+ out DDRC,temp
+ out P_RAS,_255
+; sei
+ ret
+
+; vim:set ts=8 noet nowrap
+
--- /dev/null
+; DRAM interface for *one* 256K x 4 bit DRAM chip.
+; This is part of the Z80-CP/M emulator written by Sprite_tm.
+
+; Copyright (C) 2010 Sprite_tm
+; Copyright (C) 2010 Leo C.
+
+; This file is part of avrcpm.
+;
+; avrcpm is free software: you can redistribute it and/or modify it
+; under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; avrcpm is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with avrcpm. If not, see <http://www.gnu.org/licenses/>.
+;
+; $Id$
+;
+
+
+; -------------------- DRAM macros---------------
+
+; add wait states
+; dram_wait number_of_cycles
+
+.macro dram_wait
+.if @0 > 1
+ rjmp PC+1
+ dram_wait @0 - 2
+.elif @0 > 0
+ nop
+ dram_wait @0 - 1
+.endif
+.endm
+
+; ------------------------------------------------
+
+; DRAM_SETADDR val, low_and_mask, low_or_mask, high_and_mask, high_or_mask
+
+.macro DRAM_SETADDR
+ mov temp,@0
+.if low(@1) != 0xff
+ andi temp,@1
+.endif
+.if low(@2) != 0
+ ori temp, @2
+.endif
+ out P_AL,temp
+
+ mov temp,@0
+.if low(@3) != 0xff
+ andi temp,@3
+.endif
+ ori temp, @4 | (1<<mmc_cs)
+ out P_AH,temp
+.endm
+
+
+;----------------------------------------------
+; Read byte from DRAM
+; temp = destreg, xh = memaddrh, xl = memaddrl
+
+.macro mem_read
+ rcall dram_read
+.endm
+
+;----------------------------------------------
+; Read byte from DRAM
+; mem_read memaddr
+; temp = destreg
+
+.macro mem_read_s
+ movw xl,@0l
+ rcall dram_read
+.endm
+
+;----------------------------------------------
+; Read byte from DRAM
+; mem_read destreg
+; xh = memaddrh, xl = memaddrl
+
+.macro mem_read_d
+ rcall dram_read
+ mov @0,temp
+.endm
+
+;----------------------------------------------
+; Read byte from DRAM
+; mem_read destreg, memaddr
+
+.macro mem_read_ds
+ movw xl,@1l
+ rcall dram_read
+ mov @0,temp
+.endm
+
+;----------------------------------------------
+; Write byte to DRAM
+; xh = memaddrh, xl = memaddrl, temp = srcreg
+
+.macro mem_write
+ rcall dram_write
+.endm
+
+;----------------------------------------------
+; Write byte to DRAM
+; temp = srcreg
+; mem_write memaddr
+
+.macro mem_write_d
+ movw x,@0l
+ rcall dram_write
+.endm
+
+;----------------------------------------------
+; Write byte to DRAM
+; xh = memaddrh, xl = memaddrl
+; mem_write sourcereg
+
+.macro mem_write_s
+ mov temp,@0
+ rcall dram_write
+.endm
+
+;----------------------------------------------
+; Write byte to DRAM
+; mem_write memaddr, sourcereg
+
+.macro mem_write_ds
+ movw x,@0l
+ mov temp,@1
+ rcall dram_write
+.endm
+
+
--- /dev/null
+; DRAM interface for 2 RAM chips. Supports up to 4 Mbyte of DRAM.
+; This is part of the Z80-CP/M emulator written by Sprite_tm.
+
+; Copyright (C) 2010 Leo C.
+
+; This file is part of avrcpm.
+;
+; avrcpm is free software: you can redistribute it and/or modify it
+; under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; avrcpm is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with avrcpm. If not, see <http://www.gnu.org/licenses/>.
+;
+; $Id$
+;
+
+ .cseg
+
+; ------------------ DRAM routines -------------
+
+;Loads the byte on address xh:xl into temp.
+;must not alter xh:xl
+
+dram_read:
+ cli ;
+ out PORTD,xh ;1
+ out PORTC,_RAS0 ;1
+ out PORTD,xl ;1
+ out PORTC,_CAS0 ;1
+ out DDRD,_0 ;1
+ out PORTC,_OE ;1
+ rjmp PC+1 ;2
+ dram_wait DRAM_WAITSTATES ;
+ in temp,PIND ;1
+ out PORTC,_255 ;1
+ out DDRD,_255 ;1
+ sei ;
+ ret
+
+
+
+;Writes the byte in temp to xh:xl
+;must not alter xh:xl
+
+dram_write:
+ cli
+ out PORTD,xh ;1
+ out PORTC,_RAS0 ;1
+ out PORTD,xl ;1
+ out PORTC,_CAS0 ;1
+ out PORTD,temp ;1
+ out PORTC,_WE ;1
+ out PORTC,_255 ;1 = 7
+ sei
+ ret
+
+
--- /dev/null
+; DRAM interface for 2 RAM chips. Supports up to 4 Mbyte of DRAM.
+; This is part of the Z80-CP/M emulator written by Sprite_tm.
+
+; Copyright (C) 2010 Leo C.
+
+; This file is part of avrcpm.
+;
+; avrcpm is free software: you can redistribute it and/or modify it
+; under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; avrcpm is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with avrcpm. If not, see <http://www.gnu.org/licenses/>.
+;
+; $Id$
+;
+
+
+; -------------------- DRAM macros---------------
+
+; add wait states
+; dram_wait number_of_cycles
+
+.macro dram_wait
+.if @0 > 1
+ rjmp PC+1
+ dram_wait @0 - 2
+.elif @0 > 0
+ nop
+ dram_wait @0 - 1
+.endif
+.endm
+
+;----------------------------------------------
+; Read byte from DRAM
+; mem_read_ds destreg, memaddr
+
+.macro mem_read_ds
+ cli ;1
+ out PORTD,@1h ;1
+ out PORTC,_RAS0 ;1
+ out PORTD,@1l ;1
+ out PORTC,_CAS0 ;1
+ out DDRD,_0 ;1
+ out PORTC,_OE ;1
+ rjmp PC+1 ;2
+ dram_wait DRAM_WAITSTATES ;
+ in @0,PIND ;1
+ out PORTC,_255 ;1
+ sei ;1
+ out DDRD,_255 ;1 = 14 + DRAM_WAITSTATES
+.endm
+
+;----------------------------------------------
+; Read byte from DRAM
+; mem_read_d destreg
+; x = memaddr
+
+.macro mem_read_d
+ mem_read_ds @0, x
+.endm
+
+;----------------------------------------------
+; Read byte from DRAM
+; mem_read_s memaddr
+; temp = destreg
+
+.macro mem_read_s
+ mem_read_ds temp, @0
+.endm
+
+;----------------------------------------------
+; Read byte from DRAM
+; mem_read
+; temp = destreg, x = memaddr
+
+.macro mem_read
+ mem_read_ds temp, x
+.endm
+
+;----------------------------------------------
+; Write byte to DRAM
+; mem_write_ds memaddr, sourcereg
+
+.macro mem_write_ds
+ cli ;1
+ out PORTD,@0h ;1
+ out PORTC,_RAS0 ;1
+ out PORTD,@0l ;1
+ out PORTC,_CAS0 ;1
+ out PORTD,@1 ;1
+ out PORTC,_WE ;1
+ sei ;1
+ out PORTC,_255 ;1 = 9
+.endm
+
+;----------------------------------------------
+; Write byte to DRAM
+; mem_write_d memaddr
+; temp = srcreg
+
+.macro mem_write_d
+ mem_write_ds @0, temp
+.endm
+
+;----------------------------------------------
+; Write byte to DRAM
+; mem_write_s sourcereg
+; xh = memaddrh, xl = memaddrl
+
+.macro mem_write_s
+ mem_write_ds x, @0
+.endm
+
+;----------------------------------------------
+; Write byte to DRAM
+; mem_write
+; xh = memaddrh, xl = memaddrl, temp = srcreg
+
+.macro mem_write
+ mem_write_ds x, temp
+.endm
+
+
--- /dev/null
+; Serial interface using the ATmega8/88 USART.
+; This is part of the Z80-CP/M emulator written by Sprite_tm.
+;
+; Copyright (C) 2010 Leo C.
+;
+; This file is part of avrcpm.
+;
+; avrcpm is free software: you can redistribute it and/or modify it
+; under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; avrcpm is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with avrcpm. If not, see <http://www.gnu.org/licenses/>.
+;
+; $Id$
+;
+
+#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1) /* clever rounding */
+
+#define RXBUFMASK RXBUFSIZE-1
+#define TXBUFMASK TXBUFSIZE-1
+
+ .dseg
+
+rxcount:
+ .byte 1
+rxidx_w:
+ .byte 1
+rxidx_r:
+ .byte 1
+txcount:
+ .byte 1
+txidx_w:
+ .byte 1
+txidx_r:
+ .byte 1
+rxfifo:
+ .byte RXBUFSIZE
+txfifo:
+ .byte TXBUFSIZE
+
+
+ .cseg
+; Init
+uart_init:
+
+ ldi temp, (1<<TXEN0) | (1<<RXEN0) | (1<<RXCIE0)
+ outm8 UCSR0B,temp
+.ifdef URSEL
+ ldi temp, (1<<URSEL) | (1<<UCSZ01) | (1<<UCSZ00)
+.else
+ ldi temp, (1<<UCSZ01) | (1<<UCSZ00)
+.endif
+ outm8 UCSR0C,temp
+ ldi temp, HIGH(UBRR_VAL)
+ outm8 UBRR0H,temp
+ ldi temp, LOW(UBRR_VAL)
+ outm8 UBRR0L,temp
+ ret
+
+; Save received character in a circular buffer. Do nothing if buffer overflows.
+
+rxint:
+ .org URXCaddr
+ rjmp rxint ; USART receive int.
+
+ .org rxint
+ push temp
+ in temp,sreg
+ push temp
+ push zh
+ push zl
+ inm8 temp,RXTXDR0
+ lds zh,rxcount ;if rxcount < RXBUFSIZE
+ cpi zh,RXBUFSIZE ; (room for at least 1 char?)
+ brsh rxi_ov ;
+ inc zh ;
+ sts rxcount,zh ; rxcount++
+
+ ldi zl,low(rxfifo) ;
+ lds zh,rxidx_w ;
+ add zl,zh ;
+ inc zh ;
+ andi zh,RXBUFMASK ;
+ sts rxidx_w,zh ; rxidx_w = ++rxidx_w % RXBUFSIZE
+ ldi zh,high(rxfifo) ;
+ brcc PC+2 ;
+ inc zh ;
+ st z,temp ; rxfifo[rxidx_w] = char
+rxi_ov: ;endif
+ pop zl
+ pop zh
+ pop temp
+ out sreg,temp
+ pop temp
+ reti
+
+
+;Fetches a char from the buffer to temp. If none available, waits till one is.
+
+uartgetc:
+ lds temp,rxcount ; Number of characters in buffer
+ tst temp
+ breq uartgetc ;Wait for char
+
+ push zh
+ push zl
+ ldi zl,low(rxfifo)
+ ldi zh,high(rxfifo)
+ lds temp,rxidx_r
+ add zl,temp
+ brcc PC+2
+ inc zh
+ inc temp
+ andi temp,RXBUFMASK
+ sts rxidx_r,temp
+ cli
+ lds temp,rxcount
+ dec temp
+ sts rxcount,temp
+ sei
+ ld temp,z ;don't forget to get the char
+ pop zl
+ pop zh
+ ret
+
+txint:
+ .org UDREaddr
+ rjmp txint ; USART transmit int.
+
+ .org txint
+ push temp
+ in temp,sreg
+ push temp
+ lds temp,txcount ;if txcount != 0
+ tst temp ;
+ breq txi_e ;
+
+ dec temp ;
+ sts txcount,temp ; --txcount
+ push zh ;
+ push zl ;
+ ldi zl,low(txfifo) ;
+ ldi zh,high(txfifo) ;
+ lds temp,txidx_r ;
+ add zl,temp ;
+ brcc PC+2 ;
+ inc zh ;
+ inc temp ;
+ andi temp,TXBUFMASK ;
+ sts txidx_r,temp ;
+ ld temp,z
+ outm8 RXTXDR0,temp
+ pop zl
+ pop zh
+txi_e: ;endif
+ lds temp,txcount
+ tst temp
+ brne txi_x
+ ldi temp, (1<<TXEN0) | (1<<RXEN0) | (1<<RXCIE0)
+ outm8 UCSR0B,temp
+txi_x:
+ pop temp
+ out sreg,temp
+ pop temp
+ reti
+
+
+;Sends a char from temp to the uart.
+uartputc:
+ push zh
+ push zl
+ push temp
+putc_l:
+ lds temp,txcount ;do {
+ cpi temp,TXBUFSIZE ;
+ brsh putc_l ;} while (txcount >= TXBUFSIZE)
+
+ ldi zl,low(txfifo) ;
+ ldi zh,high(txfifo) ;
+ lds temp,txidx_w ;
+ add zl,temp ;
+ brcc PC+2 ;
+ inc zh ;
+ inc temp ;
+ andi temp,TXBUFMASK ;
+ sts txidx_w,temp ; txidx_w = ++txidx_w % TXBUFSIZE
+ pop temp ;
+ st z,temp ; txfifo[txidx_w] = char
+ cli
+ lds zl,txcount
+ inc zl
+ sts txcount,zl
+ ldi zl, (1<<UDRIE0) | (1<<TXEN0) | (1<<RXEN0) | (1<<RXCIE0)
+ outm8 UCSR0B,zl
+ sei
+ pop zl
+ pop zh
+ ret
+
+; vim:set ts=8 noet nowrap
+
--- /dev/null
+; Various functions: init, (RAM) disk, mmc, timer
+; This file needs to get split up.
+;
+; Copyright (C) 2010 Sprite_tm
+; Copyright (C) 2010 Leo C.
+;
+; This file is part of avrcpm.
+;
+; avrcpm is free software: you can redistribute it and/or modify it
+; under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; avrcpm is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with avrcpm. If not, see <http://www.gnu.org/licenses/>.
+;
+; $Id$
+;
+
+#define REFR_PRE 8 /* timer prescale factor 1/8 */
+#define REFR_CS 0x02 /* timer clock select for 1/8 */
+#define REFR_CNT F_CPU / REFR_RATE / REFR_PRE
+
+ .cseg
+regval_tab:
+ .db 0,0
+ .db 0xFE,0xFC ; _RAS0 _CAS0
+ .db 0xF8,0xF4 ; _OE _WE
+ .db 255,0 ; _255 _0
+regval_tab_e:
+
+start:
+ ldi temp,low(RAMEND) ; top of memory
+ out SPL,temp ; init stack pointer
+ ldi temp,high(RAMEND) ; top of memory
+ out SPH,temp ; init stack pointer
+
+; - Load some registers with constant values
+
+ ldiw z,regval_tab*2
+ ldiw y,0
+cp_l: lpm xh,z+
+ st y+,xh
+ cpi zl,low(regval_tab_e*2)
+ brne cp_l
+
+; - Kill wdt
+
+ wdr
+ out MCUSR,_0
+
+ ldi temp,(1<<WDCE) | (1<<WDE)
+ outm8 WDTCSR,temp
+ ldi temp,(1<<WDCE)
+ outm8 WDTCSR,temp
+
+; - Setup Ports
+
+ ldi temp,(1<<PUD) ;disable pullups
+ outm8 P_PUD,temp
+ out PORTD,_255 ;all pins high
+ out PORTB,_255
+ out PORTC,_255
+ out DDRD,_255 ; all outputs
+ out DDRB,_255
+ out DDRC,_255
+ cbi P_RXD-1,RXD ; RXD pin is input
+
+ outm8 TIMSK1,_0
+ outm8 TIMSK2,_0
+ outm8 TCCR2A,_0
+ outm8 TCCR2B,_0
+
+; - Clear RAM
+
+ ldiw z,SRAM_START
+ ldi temp2,high(ramtop)
+clr_l:
+ st z+,_0
+ cpi zl,low(ramtop)
+ cpc zh,temp2
+ brne clr_l
+
+
+; Init clock/timer system
+
+; Init timer 1 as 1 ms system clock tick.
+
+ ldi temp, low (F_CPU/1000)
+ ldi temp2,high(F_CPU/1000)
+ outm8 OCR1BH,temp2
+ outm8 OCR1BL,temp
+ ldi temp,(1<<ICNC1)|(1<<CS10) ;Noise cancel, fall. edge, Normal Mode, clk/1
+ outm8 TCCR1B,temp
+ inm8 temp,TIMSK1
+ ori temp,(1<<OCIE1B) ;Enable 1ms int.
+ outm8 TIMSK1,temp
+
+; - Init serial port
+
+ rcall uart_init
+
+;Init timer2. Refresh-call should happen every (8ms/512)=312 cycles.
+
+ ldi temp,REFR_CNT*2 ; 2 cycles per int
+ outm8 OCR2A,temp
+ inm8 temp,TCCR2A
+ ori temp,(1<<WGM21) ;CTC mode
+ outm8 TCCR2A,temp
+ inm8 temp,TCCR2B
+ ori temp,REFR_CS ;clk/REFR_PRE
+ outm8 TCCR2B,temp
+ inm8 temp,TIMSK2
+ ori temp, (1<<OCIE2A)
+ outm8 TIMSK2,temp
+
+ sei
+
+
+.if BOOTWAIT
+ ldi temp,10
+ rcall delay_ms
+
+.endif
+
+ rcall printstr
+ .db 13,13,"CPM on an AVR, v"
+ db_version VMAJOR, VMINOR
+
+.if MEMTEST
+ printnewline
+ printstring "Testing RAM: fill..."
+
+;Fill RAM
+ ldiw x,0
+ramtestw:
+ mov temp,xh
+ eor temp,xl
+ mem_write
+ adiw xl,1
+ brcc ramtestw
+ printstring "wait..."
+
+ ldi temp2,8
+ramtestwl:
+ ldi temp,255
+ rcall delay_ms
+ dec temp2
+ brne ramtestwl
+
+ printstring "reread..."
+
+;re-read RAM
+ ldiw x,0
+ clr temp3
+ramtestr:
+ mem_read
+ mov temp2,xh
+ eor temp2,xl
+ cp temp,temp2
+ breq ramtestrok
+ push temp
+ cpi temp3,0 ;if first error
+ brne ramtest2
+ inc temp3
+ ldi temp,10 ;newline
+ rcall uartPutc
+ramtest2:
+ ldi temp,13 ;return
+ rcall uartPutc
+ pop temp
+ rcall printhex
+ ldi temp,'<'
+ rcall uartPutc
+ mov temp,xh
+ eor temp,xl
+ rcall printhex
+ ldi temp,'@'
+ rcall uartPutc
+ movw temp,x
+ rcall printhexw
+ramtestrok:
+ adiw xl,1
+ brcc ramtestr
+
+.endif
+
+.if MEMFILL
+ ldiw x,0
+ramfillw:
+ ldi temp,MEMFILL_VAL
+ mem_write
+ adiw xl,1
+ brcc ramfillw
+.endif
+
+
+;----------------------------------------------------------------------------
+
+boot_again:
+ printnewline
+ printstring "Initing mmc...",0
+ rcall dsk_partinit
+
+ cbr temp,0x80
+ brne boot_ipl2
+ printstring "No bootable CP/M disk found! Please change MMC/SD-Card."
+ ldi temp2,18
+boot_iplwl:
+ ldi temp,255
+ rcall delay_ms
+ dec temp2
+ brne boot_iplwl
+ rjmp boot_again
+
+
+boot_ipl2:
+ rcall prnt_parttbl
+ printnewline
+ printstring "Partinit done."
+
+; Read first sector of first CP/M partition
+
+ lds xl,hostparttbl
+ lds xh,hostparttbl+1
+ lds yl,hostparttbl+2
+ lds yh,hostparttbl+3
+ rcall mmcReadSect
+
+ rcall dsk_cboot ;init (de)blocking buffer
+
+;First sector of disk or first CP/M partition is in hostbuf.
+
+;Save to Z80 RAM (only 128 bytes because that's retro)
+ ldiw z,hostbuf
+ ldiw x,IPLADDR
+iplwriteloop:
+ ld temp,z+
+ mem_write
+ adiw xl,1
+ cpi zl,low(hostbuf+128)
+ brne iplwriteloop
+ cpi zh,high(hostbuf+128)
+ brne iplwriteloop
+ rjmp z80_init
+
+
--- /dev/null
+; Commonly used macros
+;
+; Copyright (C) 2010 Leo C.
+;
+; This file is part of avrcpm.
+;
+; avrcpm is free software: you can redistribute it and/or modify it
+; under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; avrcpm is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with avrcpm. If not, see <http://www.gnu.org/licenses/>.
+;
+; $Id$
+;
+
+;------------------------------------------------
+;
+.macro outm8
+.if @0 > 0x3f
+ sts @0,@1
+.else
+ out @0,@1
+.endif
+.endm
+
+;------------------------------------------------
+;
+.macro inm8
+.if @1 > 0x3f
+ lds @0,@1
+.else
+ in @0,@1
+.endif
+.endm
+
+;------------------------------------------------
+;
+.macro sbism8
+.if @0 > 0x1f
+ in _tmp0,@0
+ sbrs _tmp0,@1
+.else
+ sbis @0,@1
+.endif
+.endm
+
+;------------------------------------------------
+; load 16 bit constant to register pair
+
+.macro ldiw
+ ldi @0l, low(@1)
+ ldi @0h, high(@1)
+.endm
+
+;------------------------------------------------
+; add 16 bit constant to register pair
+
+.macro addiw
+ subi @0l, low(-@1)
+ sbci @0h, high(-@1)
+.endm
+
+;------------------------------------------------
+; Move single bit between two registers
+;
+; bmov dstreg,dstbit,srcreg.srcbit
+
+.macro bmov
+ bst @2,@3
+ bld @0,@1
+.endm
+
+;------------------------------------------------
+; Print string.
+; printstring "String"
+
+.macro printstring
+ rcall printstr
+ .if strlen(@0) % 2
+ .db @0,0
+ .else
+ .db @0,0,0
+ .endif
+.endm
+
+;------------------------------------------------
+; Print newline
+; print cr, lf
+
+.macro printnewline
+ rcall printstr
+ .db 13,0
+.endm
+
+
+;------------------------------------------------
+; Print a Z80 flag
+; print_zflag F
+; where F is the flag to print
+
+.macro print_zflag
+
+.set S_ = 'S'
+.set Z_ = 'Z'
+.set H_ = 'H'
+.set P_ = 'P'
+.set N_ = 'N'
+.set C_ = 'C'
+
+ ldi temp, ' '
+ sbrc z_flags,ZFL_@0
+ ldi temp, @0_
+ rcall uartputc
+.endm
+
+;------------------------------------------------
+; db_version VMAJOR, VMINOR
+
+.macro db_version
+
+ .set maj1_ = @0 / 10
+ .set maj0_ = @0 % 10
+ .set min1_ = @1 / 10
+ .set min0_ = @1 % 10
+
+ .if maj1_
+ .if min1_
+ .db maj1_+'0',maj0_+'0','.',min1_+'0',min0_+'0',0
+ .else
+ .db maj1_+'0',maj0_+'0','.', min0_+'0',0,0
+ .endif
+ .else
+ .if min1_
+ .db maj0_+'0','.',min1_+'0',min0_+'0',0,0
+ .else
+ .db maj0_+'0','.', min0_+'0',0
+ .endif
+ .endif
+.endm
+
+; vim:set ts=8 noet nowrap
+
--- /dev/null
+; ----------------- MMC/SD routines ------------------
+
+mmcByteNoSend:
+ ldi temp,0xff
+mmcByte:
+
+.if MMC_DEBUG
+ printstring "MMC: <--"
+ rcall printhex
+.endif
+
+ out SPDR,temp
+mmcWrByteW:
+ in temp,SPSR
+ sbrs temp,7
+ rjmp mmcWrByteW
+ in temp,SPDR
+
+.if MMC_DEBUG
+ printstring ", -->"
+ rcall printhex
+ printnewline
+.endif
+ ret
+
+
+;Wait till the mmc answers with the response in temp2, or till a timeout happens.
+mmcWaitResp:
+ ldiw z,0
+mmcWaitResploop:
+ rcall mmcByteNoSend
+ cpi temp,0xff
+ brne mmcWaitResploopEnd
+ adiw zl,1
+ cpi zh,255
+ breq mmcWaitErr
+ rjmp mmcWaitResploop
+mmcWaitResploopEnd:
+ ret
+
+
+mmcWaitErr:
+ mov temp,temp2
+ rcall printhex
+ printstring ": Error: MMC resp timeout!"
+ printnewline
+ rjmp resetAVR
+
+mmcInit:
+ ldi temp,0x53
+ out SPCR,temp
+
+ ;Init start: send 80 clocks with cs disabled
+ sbi P_MMC_CS,mmc_cs
+
+; ldi temp2,20
+ ldi temp2,10 ; exactly 80 clocks
+mmcInitLoop:
+ mov temp,temp2
+ rcall mmcByte
+ dec temp2
+ brne mmcInitLoop
+
+ cbi P_MMC_CS,mmc_cs
+ rcall mmcByteNoSend
+ rcall mmcByteNoSend
+ rcall mmcByteNoSend
+ rcall mmcByteNoSend
+ rcall mmcByteNoSend
+ rcall mmcByteNoSend
+ sbi P_MMC_CS,mmc_cs
+ rcall mmcByteNoSend
+ rcall mmcByteNoSend
+ rcall mmcByteNoSend
+ rcall mmcByteNoSend
+
+ ;Send init command
+ cbi P_MMC_CS,mmc_cs
+ ldi temp,0xff ;dummy
+ rcall mmcByte
+ ldi temp,0xff ;dummy
+ rcall mmcByte
+ ldi temp,0x40 ;cmd
+ rcall mmcByte
+ ldi temp,0 ;pxh
+ rcall mmcByte
+ ldi temp,0 ;pxl
+ rcall mmcByte
+ ldi temp,0 ;pyh
+ rcall mmcByte
+ ldi temp,0 ;pyl
+ rcall mmcByte
+ ldi temp,0x95 ;crc
+ rcall mmcByte
+ ldi temp,0xff ;return byte
+ rcall mmcByte
+
+ ldi temp2,0 ;Error Code 0
+ rcall mmcWaitResp ;Test on CMD0 is OK
+
+ sbi P_MMC_CS,mmc_cs ;disable /CS
+ rcall mmcByteNoSend
+
+
+;Read OCR till card is ready
+ ldi temp2,100 ;repeat counter
+mmcInitOcrLoop:
+ push temp2
+
+ cbi P_MMC_CS,mmc_cs ;enable /CS
+ ldi temp,0xff ;dummy
+ rcall mmcByte
+ ldi temp,0x41 ;cmd
+ rcall mmcByte
+ ldi temp,0 ;pxh
+ rcall mmcByte
+ ldi temp,0 ;pxl
+ rcall mmcByte
+ ldi temp,0 ;pyh
+ rcall mmcByte
+ ldi temp,0 ;pyl
+ rcall mmcByte
+; ldi temp,0x95 ;crc
+ ldi temp,0x01 ;crc
+ rcall mmcByte
+ rcall mmcByteNoSend
+
+ ldi temp2,1
+ rcall mmcWaitResp ;wait until mmc-card send a byte <> 0xFF
+ ;the first answer must be 0x01 (Idle-Mode)
+ cpi temp,0
+ breq mmcInitOcrLoopDone ;second answer is 0x00 (Idle-Mode leave) CMD1 is OK
+
+ sbi P_MMC_CS,mmc_cs ;disable /CS
+
+ rcall mmcByteNoSend
+
+ ldi temp,10
+ rcall delay_ms
+
+ pop temp2
+ dec temp2
+ brne mmcInitOcrLoop ;repeat
+
+ ldi temp2,4
+ rjmp mmcWaitErr
+
+mmcInitOcrLoopDone:
+ pop temp2
+ sbi P_MMC_CS,mmc_cs ;disable /CS
+ rcall mmcByteNoSend
+
+ out SPCR,_0
+ ret
+
+
+;Call this with yh:yl:xh:xl = sector number
+;
+mmcReadSect:
+ ldi temp,0x50
+ out SPCR,temp
+
+ cbi P_MMC_CS,mmc_cs
+ rcall mmcByteNoSend
+ ldi temp,0x51 ;cmd (read sector)
+ rcall mmcByte
+ lsl xl ;convert to byte address (*512)
+ rol xh
+ rol yl
+ mov temp,yl
+ rcall mmcByte
+ mov temp,xh ;pxl
+ rcall mmcByte
+ mov temp,xl ;pyh
+ rcall mmcByte
+ ldi temp,0 ;pyl
+ rcall mmcByte
+ ldi temp,0x95 ;crc
+ rcall mmcByte
+ ldi temp,0xff ;return byte
+ rcall mmcByte
+
+ ;resp
+ ldi temp2,2
+ rcall mmcWaitResp
+
+ ;data token
+ ldi temp2,3
+ rcall mmcWaitResp
+
+ ;Read sector to AVR RAM
+ ldiw z,hostbuf
+mmcreadloop:
+ rcall mmcByteNoSend
+ st z+,temp
+ cpi zl,low(hostbuf+512)
+ brne mmcreadloop
+ cpi zh,high(hostbuf+512)
+ brne mmcreadloop
+
+ ;CRC
+ rcall mmcByteNoSend
+ rcall mmcByteNoSend
+
+ sbi P_MMC_CS,mmc_cs
+ rcall mmcByteNoSend
+
+ out SPCR,_0
+ ret
+
+
+;Call this with yh:yl:xh:xl = sector number
+;
+mmcWriteSect:
+ ldi temp,0x50
+ out SPCR,temp
+
+ cbi P_MMC_CS,mmc_cs
+ rcall mmcByteNoSend
+
+ ldi temp,0x58 ;cmd (write sector)
+ rcall mmcByte
+ lsl xl ;convert to byte address (*512)
+ rol xh
+ rol yl
+ mov temp,yl
+ rcall mmcByte
+ mov temp,xh ;pxl
+ rcall mmcByte
+ mov temp,xl ;pyh
+ rcall mmcByte
+ ldi temp,0 ;pyl
+ rcall mmcByte
+ ldi temp,0x95 ;crc
+ rcall mmcByte
+ ldi temp,0xff ;return byte
+ rcall mmcByte
+
+ ;resp
+ ldi temp2,1
+ rcall mmcWaitResp
+
+ ;Send data token
+ ldi temp,0xfe
+ rcall mmcByte
+
+ ;Write sector from AVR RAM
+ ldiw z,hostbuf
+mmcwriteloop:
+ ld temp,z+
+ rcall mmcByte
+ cpi zl,low(hostbuf+512)
+ brne mmcwriteloop
+ cpi zh,high(hostbuf+512)
+ brne mmcwriteloop
+
+ ;CRC
+ rcall mmcByteNoSend
+ rcall mmcByteNoSend
+
+ ;Status. Ignored for now.
+ rcall mmcByteNoSend
+
+;Wait till the mmc has written everything
+mmcwaitwritten:
+ rcall mmcByteNoSend
+ cpi temp,0xff
+ brne mmcwaitwritten
+
+ sbi P_MMC_CS,mmc_cs
+ rcall mmcByteNoSend
+
+ out SPCR,_0
+ ret
+
+
+;Set up wdt to time out after 1 sec.
+resetAVR:
+ lds temp,txcount ;Wait, till tx buffer is empty
+ tst temp
+ brne resetAVR
+
+ cli
+ ldi temp,(1<<WDCE)
+ outm8 WDTCSR,temp
+ ldi temp,(1<<WDCE) | (1<<WDE) | (110<<WDP0)
+ outm8 WDTCSR,temp
+resetwait:
+ rjmp resetwait
+
+
--- /dev/null
+; MMC/SD-Card routines
+;
+; Copyright (C) 2010 Leo C.
+;
+; This file is part of avrcpm.
+;
+; avrcpm is free software: you can redistribute it and/or modify it
+; under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; avrcpm is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with avrcpm. If not, see <http://www.gnu.org/licenses/>.
+;
+; $Id$
+;
+
+/* Definitions for MMC/SDC command */
+#define CMD0 (0) /* GO_IDLE_STATE */
+#define CMD1 (1) /* SEND_OP_COND (MMC) */
+#define ACMD41 (0x80+41) /* SEND_OP_COND (SDC) */
+#define CMD8 (8) /* SEND_IF_COND */
+#define CMD9 (9) /* SEND_CSD */
+#define CMD10 (10) /* SEND_CID */
+#define CMD12 (12) /* STOP_TRANSMISSION */
+#define ACMD13 (0x80+13) /* SD_STATUS (SDC) */
+#define CMD16 (16) /* SET_BLOCKLEN */
+#define CMD17 (17) /* READ_SINGLE_BLOCK */
+#define CMD18 (18) /* READ_MULTIPLE_BLOCK */
+#define CMD23 (23) /* SET_BLOCK_COUNT (MMC) */
+#define ACMD23 (0x80+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */
+#define CMD24 (24) /* WRITE_BLOCK */
+#define CMD25 (25) /* WRITE_MULTIPLE_BLOCK */
+#define CMD55 (55) /* APP_CMD */
+#define CMD58 (58) /* READ_OCR */
+
+/* Disk Status Bits (DSTATUS) */
+#define MMCST_NOINIT 0x01 /* Drive not initialized */
+#define MMCST_NODISK 0x02 /* No medium in the drive */
+#define MMCST_PROTECT 0x04 /* Write protected */
+
+/* Card type flags (CardType) */
+#define CT_MMC 0x01 /* MMC ver 3 */
+#define CT_SD1 0x02 /* SD ver 1 */
+#define CT_SD2 0x04 /* SD ver 2 */
+#define CT_SDC (CT_SD1|CT_SD2) /* SD */
+#define CT_BLOCK 0x08 /* Block addressing */
+
+#define RES_OK 0 /* 0: Successful */
+#define RES_ERROR 1 /* 1: R/W Error */
+#define RES_WRPRT 2 /* 2: Write Protected */
+#define RES_NOTRDY 3 /* 3: Not Ready */
+#define RES_PARERR 4 /* 4: Invalid Parameter */
+
+;------------------------------------------------
+;
+.macro spi_clkslow
+.if MMC_DEBUG > 1
+ printstring "SPI_CLK_SLOW "
+.endif
+ ldi temp,(1<<SPE)|(1<<MSTR)|(1<<SPR1)|(1<<SPR0) ;clk/128
+ out SPCR,temp
+ out SPSR,_0
+.endm
+
+;------------------------------------------------
+;
+.macro spi_clkfast
+.if MMC_DEBUG > 1
+ printstring "SPI_CLK_FAST "
+.endif
+ ldi temp,(1<<SPE)|(1<<MSTR) ;clk/4
+ out SPCR,temp
+#if MMC_SPI2X
+ ldi temp,(1<<SPI2X)
+ out SPSR,temp
+#else
+ out SPSR,_0
+#endif
+.endm
+
+;------------------------------------------------
+;
+.macro spi_disable
+.if MMC_DEBUG > 1
+ printstring "SPI_DISABLE "
+.endif
+ out SPCR,_0
+.endm
+
+
+;------------------------------------------------
+;
+.macro spi_waitm
+ .set spiwl_ = PC
+ sbism8 SPSR,SPIF
+ rjmp spiwl_
+.endm
+
+;------------------------------------------------
+
+ .dseg
+
+mmcStat:
+ .byte 1
+mmcCardType:
+ .byte 1
+mmc_ocr:
+ .byte 4
+
+
+
+ .cseg
+
+;------------------------------------------------
+; Multiply 32 bit value in yh,yl,xh,xl by 512
+
+mul_yx_512:
+ mov yh,yl
+ mov yl,xh
+ mov xh,xl
+ ldi xl,0
+ lsl xh
+ rol yl
+ rol yh
+ ret
+
+;------------------------------------------------
+spi_rcvr:
+ out SPDR,_255
+spi_rcvr_l:
+ sbism8 SPSR,SPIF
+ rjmp spi_rcvr_l
+ in temp,SPDR
+.if MMC_DEBUG > 2
+ push temp
+ printstring "<"
+ rcall printhex
+ printstring " "
+ pop temp
+.endif
+ ret
+
+;------------------------------------------------
+spi_xmit:
+.if MMC_DEBUG > 2
+ printstring ">"
+ rcall printhex
+ printstring " "
+.endif
+ out SPDR,temp
+ ;fall thru
+spi_wait:
+ sbism8 SPSR,SPIF
+ rjmp spi_wait
+ ret
+
+;------------------------------------------------
+; Wait for card ready
+; return 1:OK, 0:Timeout
+
+mmcWaitReady:
+ push temp2
+ ldi temp2,2 ;Wait for ready in timeout of 500ms.
+ rcall spi_rcvr
+mmc_wrl:
+ sts delay_timer2,_255
+mmc_wrl1:
+ rcall spi_rcvr
+ cp temp,_255
+ brne mmc_wrl2
+ ldi temp,1
+ rjmp mmc_wrbreak
+
+mmc_wrl2:
+ lds temp,delay_timer2
+ cpi temp,0
+ brne mmc_wrl1
+ dec temp2
+ brne mmc_wrl ;tmp is 0 here
+
+mmc_wrbreak:
+ pop temp2
+ tst temp ;set flags
+ ret
+
+
+;------------------------------------------------
+; Deselect the card and release SPI bus
+; return 0
+
+mmcDeselect:
+ sbi P_MMC_CS,mmc_cs ; CS high
+ rcall spi_rcvr
+ clr temp
+ ret
+
+;------------------------------------------------
+; Select the card and wait for ready
+; return 255:Successful, 0:Timeout
+
+mmcSelect:
+ cbi P_MMC_CS,mmc_cs ; CS low
+ rcall mmcWaitReady
+ breq mmcDeselect ;return via Deselect
+ sbr temp,255
+ ret
+
+
+;------------------------------------------------
+; Send a command packet to MMC
+; temp2: Command
+; yh..xl: Argument
+
+mmcCmd:
+ sbrs temp2,7
+ rjmp mmc_cmddo
+
+; ACMD<n> is the command sequence of CMD55-CMD<n>
+
+ push yh
+ push yl
+ push xh
+ push xl
+ push temp2
+ ldiw y,0
+ movw x,y
+ ldi temp2,CMD55
+ rcall mmcCmd
+ pop temp2
+ pop xl
+ pop xh
+ pop yl
+ pop yh
+
+ cpi temp,2
+ brlo mmc_cmddo ; fall thru, if (retval <= 1)
+
+ tst temp
+ ret ; else return error
+
+; Select the card and wait for ready
+
+mmc_cmddo:
+.if MMC_DEBUG
+ sbrc temp2,7
+ rjmp dmmccmd_nonl
+ printnewline
+
+dmmccmd_nonl:
+ printstring "mmcCMD: "
+ mov temp,temp2
+ cbr temp,0x80
+ rcall printhex
+ printstring " "
+ push temp2
+ movw temp,y
+ rcall printhexw
+ movw temp,x
+ rcall printhexw
+ printstring " "
+ pop temp2
+.endif
+ rcall mmcDeselect
+ rcall mmcSelect
+ brne mmc_cmd_p
+
+ ldi temp,0xFF
+ rjmp mmc_cmdexit
+
+; Send command packet
+
+mmc_cmd_p:
+ mov temp,temp2
+ cbr temp,0x80
+ sbr temp,0x40
+ rcall spi_xmit
+ out SPDR,yh
+ rcall spi_wait
+ out SPDR,yl
+ rcall spi_wait
+ out SPDR,xh
+ rcall spi_wait
+ out SPDR,xl
+ rcall spi_wait
+
+ ldi temp,0x95 ;CRC for CMD0(0)
+ cpi temp2,CMD0
+ breq mmc_cmdxcrc
+ ldi temp,0x87 ;CRC for CMD8(0x1AA)
+ cpi temp2,CMD8
+ breq mmc_cmdxcrc
+ ldi temp,0x01 ;Dummy CRC + Stop
+mmc_cmdxcrc:
+.if MMC_DEBUG
+ printstring ".. "
+ rcall printhex
+.endif
+ rcall spi_xmit
+
+; Receive command response
+
+ cpi temp2,CMD12 ; Skip a stuff byte when stop reading
+ brne mmc_cmdres
+ rcall spi_rcvr
+
+; Wait for a valid response in timeout of 10 attempts
+
+mmc_cmdres:
+ ldi temp,10
+ mov _tmp1,temp
+mmc_cmdrl:
+ rcall spi_rcvr
+ sbrs temp,7
+ rjmp mmc_cmdexit
+ dec _tmp1
+ brne mmc_cmdrl
+
+; Return with response value
+
+mmc_cmdexit:
+.if MMC_DEBUG
+ printstring " CMDRes: "
+ rcall printhex
+ printstring " "
+ rcall uart_wait_empty
+.endif
+ tst temp ;set flags
+ ret
+
+;------------------------------------------------
+; Check if 1 sec timeout
+; return Z-Flag set, if timeout
+
+mmc_timeout_1s:
+ lds temp,delay_timer1
+ tst temp
+ brne mmc_ttex
+ dec temp4
+ breq mmc_ttex
+ ldi temp,100
+ sts delay_timer1,temp
+mmc_ttex:
+ ret
+
+
+;------------------------------------------------
+; "Public" functions
+;------------------------------------------------
+
+;------------------------------------------------
+; Initialize MMC/SD card
+
+mmcInit:
+.if MMC_DEBUG
+ printnewline
+ printstring "mmcInit "
+.endif
+ lds temp,mmcStat ;Set 'NO INIT' status
+ sbr temp,MMCST_NOINIT
+ sts mmcStat,temp
+
+ spi_clkslow
+ ldi temp2,10
+mmci_lp:
+ rcall spi_rcvr
+ dec temp2 ;80 dummy clocks
+ brne mmci_lp
+
+ ldi temp3,0 ;Card type
+ ldi temp2,CMD0
+ ldiw y,0
+ movw x,y
+ rcall mmcCmd ;Enter Idle state
+ cpi temp,1
+ breq mmci_1
+ rjmp mmci_lend
+mmci_1:
+ ldi temp4,10 ;Initialization timeout of 1000 ms.
+ ldi temp,100
+ sts delay_timer1,temp
+ ldi temp2,CMD8
+ ldiw y,0
+ ldi xh,0x01
+ ldi xl,0xAA
+ rcall mmcCmd
+ cpi temp,1 ;SDv2?
+ brne mmci_sdv1
+
+; Get trailing return value of R7 response
+
+ ldi temp2,4
+ ldiw z,mmc_ocr
+mmci_v2l1:
+ rcall spi_rcvr
+ st z+,temp
+ dec temp2
+ brne mmci_v2l1
+ sbiw z,4
+ ldd temp,z+2
+ cpi temp,0x01
+ ldd temp,z+3
+ cpc temp,xl ;Reuse 0xAA value in xl
+ brne mmci_sdv1
+
+; The card can work at vdd range of 2.7-3.6V.
+; Wait for leaving idle state (ACMD41 with HCS bit).
+
+ ldi temp2,ACMD41
+ ldi yh,0x40
+ ldi yl,0
+ ldi xh,0
+ ldi xl,0
+mmci_v2l2:
+ rcall mmcCmd
+ breq mmci_ccc
+ rcall mmc_timeout_1s
+ brne mmci_v2l2
+ rjmp mmci_sdv2end
+
+; Check CCS bit in the OCR
+mmci_ccc:
+ ldi temp2,CMD58
+ ldi yh,0
+ rcall mmcCmd
+ brne mmci_sdv2end
+
+ ldi temp2,4
+mmci_v2l3:
+ rcall spi_rcvr
+ st z+,temp
+ dec temp2
+ brne mmci_v2l3
+ sbiw z,4
+
+ sbr temp3,CT_SD2
+ ldd temp,z+0
+ sbrc temp,6
+ sbr temp3,CT_BLOCK
+
+mmci_sdv2end:
+ rjmp mmci_lend
+
+; SDv1 or MMCv3
+
+mmci_sdv1:
+ ldi temp2,ACMD41
+ ldiw y,0
+ movw x,y
+ rcall mmcCmd
+ cpi temp,2
+ brsh mmci_mmcv3
+ sbr temp3,CT_SD1 ;SDv1
+ ldi temp2,ACMD41
+ rjmp mmci_v1_l
+mmci_mmcv3:
+ sbr temp3,CT_MMC ;MMCv3
+ ldi temp2,CMD1
+
+; Wait for leaving idle state
+mmci_v1_l:
+ rcall mmcCmd
+ breq mmci_v1_2
+ rcall mmc_timeout_1s
+ brne mmci_v1_l
+ rjmp mmci_lend ;Timeout
+
+; Set R/W block length to 512
+mmci_v1_2:
+ ldi temp2,CMD16
+ ldiw x,512
+ rcall mmcCmd
+ breq mmci_lend
+ ldi temp3,0
+
+mmci_lend:
+ sts mmcCardType,temp3
+ rcall mmcDeselect
+
+; Initialization succeded?
+
+ lds temp,mmcStat
+ tst temp3
+ breq mmci_lex
+ cbr temp,MMCST_NOINIT ;Yes, clear 'NO INIT' status
+ sts mmcStat,temp
+mmci_lex:
+
+.if MMC_DEBUG
+ printnewline
+ printstring " CT: "
+ push temp
+ lds temp,mmcCardType
+ rcall printhex
+ pop temp
+ printstring " InitRes: "
+ rcall printhex
+ printstring " "
+.endif
+
+ spi_disable
+ ret
+
+
+;--------------------------------------------------------------
+; Read sector
+; z: Pointer to the data buffer to store read data
+; yh..xl: Start sector number (LBA)
+
+mmcReadSect:
+.if MMC_DEBUG > 1
+ printnewline
+ printstring "mmcRdSect "
+.endif
+ ldiw z,hostbuf ;for now
+
+ lds _tmp0,mmcStat
+ ldi temp,RES_NOTRDY
+ sbrc _tmp0,MMCST_NOINIT
+ ret
+
+ spi_clkfast
+ lds temp,mmcCardType
+ sbrs temp,log2(CT_BLOCK)
+ rcall mul_yx_512 ;Convert to byte address (*512)
+
+ ldi temp2,CMD17
+ rcall mmcCmd
+ ldi temp2,RES_ERROR
+ brne mmc_rdex
+
+; Receive a data packet from MMC
+
+ ldiw y,512 ;Number of bytes to tranfer
+ ldi temp,200 ;Wait for data packet in timeout of 200ms.
+ sts delay_timer1,temp
+mmc_rcv_wl:
+ rcall spi_rcvr
+ cp temp,_255
+ brne mmc_rcv_start
+ lds _tmp0,delay_timer1
+ cp _tmp0,_0
+ brne mmc_rcv_wl
+.if MMC_DEBUG > 1
+ printstring "TIMEOUT "
+ rjmp mmc_rcv_dbg1
+.endif
+
+mmc_rcv_start:
+.if MMC_DEBUG > 1
+ cpi temp,0xFE ;If not valid data token,
+ breq mmc_rcv_dbg1
+ printstring "Token: "
+ rcall printhex
+ printstring " "
+mmc_rcv_dbg1:
+.endif
+ cpi temp,0xFE ;If not valid data token,
+ brne mmc_rdex
+
+ rcall spi_rcvr ;Shift in first byte.
+ out SPDR,_255 ;Start shift in next byte.
+mmc_rcv_rl:
+ sbiw yl,1
+ breq mmc_rcv_rle
+ st z+,temp
+ spi_waitm
+ in temp,SPDR
+ out SPDR,_255
+ rjmp mmc_rcv_rl
+
+mmc_rcv_rle:
+ st z+,temp ;Store last byte in buffer
+ rcall spi_wait ; while SPI module shifts in crc part1.
+ rcall spi_rcvr ;Read second crc.
+
+ ldi temp2,RES_OK ;Return success
+mmc_rdex:
+ rcall mmcDeselect
+ spi_disable
+ mov temp,temp2
+.if MMC_DEBUG > 1
+ printstring "RdSectRes: "
+ rcall printhex
+ printstring " "
+.endif
+ ret
+
+
+;--------------------------------------------------------------
+; Write sector
+; z: Pointer to the data to be written
+; yh..xl: Sector number (LBA)
+
+mmcWriteSect:
+.if MMC_DEBUG > 1
+ printnewline
+ printstring "mmcWrSect "
+.endif
+ ldiw z,hostbuf ;for now
+
+ lds _tmp0,mmcStat
+ ldi temp,RES_NOTRDY
+ sbrc _tmp0,MMCST_NOINIT
+ ret
+
+ spi_clkfast
+ lds temp,mmcCardType
+ sbrs temp,log2(CT_BLOCK)
+ rcall mul_yx_512 ;Convert to byte address (*512)
+
+ ldi temp2,CMD24
+ rcall mmcCmd
+ brne mmc_wrexer
+
+; Send a data packet to MMC
+
+.if MMC_DEBUG > 2
+; printnewline
+ printstring "mmcXMIT "
+.endif
+ rcall mmcWaitReady
+ breq mmc_wrexer
+
+ ldi temp,0xFE ;Data token
+ out SPDR,temp
+ ldiw y,512
+mmc_x_loop:
+ ld temp,z+
+ spi_waitm
+ out SPDR,temp
+ sbiw yl,1
+ brne mmc_x_loop
+
+ rcall spi_wait
+ ldi temp,0xFF ;dummy crc
+ rcall spi_xmit
+ rcall spi_xmit
+ rcall spi_rcvr
+.if MMC_DEBUG > 2
+ printstring "XMITRes: "
+ rcall printhex
+ printstring " "
+.endif
+ andi temp,0x1F ;If not accepted, return with error
+ cpi temp,0x05
+ ldi temp2,RES_OK ;Return success
+ breq mmc_wrex
+
+mmc_wrexer:
+ ldi temp,RES_ERROR
+mmc_wrex:
+ rcall mmcDeselect
+ spi_disable
+ mov temp,temp2
+.if MMC_DEBUG > 1
+ printstring "WrSectRes: "
+ rcall printhex
+ printstring " "
+.endif
+ ret
+
+;--------------------------------------------------------------
+; vim:set ts=8 noet nowrap
+
--- /dev/null
+; Various functions: init, (RAM) disk, mmc, timer
+; This file needs to get split up.
+;
+; Copyright (C) 2010 Sprite_tm
+; Copyright (C) 2010 Leo C.
+;
+; This file is part of avrcpm.
+;
+; avrcpm is free software: you can redistribute it and/or modify it
+; under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; avrcpm is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with avrcpm. If not, see <http://www.gnu.org/licenses/>.
+;
+; $Id$
+;
+
+
+; ------------------- DRAM Refresh Interrupt --------------------
+
+ .cseg
+; refresh interupt; exec 2 cbr cycles
+refrint: ;4
+ .org OC2Aaddr
+ rjmp refrint ; tim2cmpa
+
+ .org refrint
+ sbis P_RAS,ram_ras ;2
+ reti
+ ; CAS RAS
+ cbi P_CAS,ram_cas ;2 1| 1|
+ ; 1| 1|
+ cbi P_RAS,ram_ras ;2 |0 1|
+ ; |0 1|
+ nop ;1 |0 |0
+; nop ;1 |0 |0
+ sbi P_RAS,ram_ras ;2 |0 |0
+ ; |0 |0
+ dram_wait DRAM_WAITSTATES-1 ; | |
+; nop ;1 |0 |0
+ cbi P_RAS,ram_ras ;2 |0 1|
+ ; |0 1|
+ sbi P_CAS,ram_cas ;2 |0 |0
+ ; |0 |0
+ sbi P_RAS,ram_ras ;2 1| |0
+ ; 1| 1|
+ reti ;4 --> 21 cycles
+
+
+
+
+;Print a unsigned lonng value to the uart
+; temp4:temp3:temp2:temp = value
+
+print_ultoa:
+ push yh
+ push yl
+ push z_flags
+ push temp4
+ push temp3
+ push temp2
+ push temp
+
+ clr yl ;yl = stack level
+
+ultoa1: ldi z_flags, 32 ;yh = temp4:temp % 10
+ clr yh ;temp4:temp /= 10
+ultoa2: lsl temp
+ rol temp2
+ rol temp3
+ rol temp4
+ rol yh
+ cpi yh,10
+ brcs ultoa3
+ subi yh,10
+ inc temp
+ultoa3: dec z_flags
+ brne ultoa2
+ cpi yh, 10 ;yh is a numeral digit '0'-'9'
+ subi yh, -'0'
+ push yh ;Stack it
+ inc yl
+ cp temp,_0 ;Repeat until temp4:temp gets zero
+ cpc temp2,_0
+ cpc temp3,_0
+ cpc temp4,_0
+ brne ultoa1
+
+ ldi temp, '0'
+ultoa5: cpi yl,3 ; at least 3 digits (ms)
+ brge ultoa6
+ push temp
+ inc yl
+ rjmp ultoa5
+
+ultoa6: pop temp ;Flush stacked digits
+ rcall uartputc
+ dec yl
+ brne ultoa6
+
+ pop temp
+ pop temp2
+ pop temp3
+ pop temp4
+ pop z_flags
+ pop yl
+ pop yh
+ ret
+
+
+;Prints temp2:temp in hex to the uart
+printhexw:
+ push temp
+ mov temp,temp2
+ rcall printhex
+ pop temp
+ ;fall thru
+
+;Prints temp in hex to the uart
+printhex:
+ swap temp
+ rcall printhexn
+ swap temp
+ ;fall thru
+
+;Prints the lower nibble
+printhexn:
+ push temp
+ andi temp,0xf
+ cpi temp,0xA
+ brlo printhexn_isno
+ subi temp,-7
+printhexn_isno:
+ subi temp,-'0'
+ rcall uartputc
+ pop temp
+ ret
+
+;Prints the zero-terminated string following the call statement.
+
+printstr:
+ push zh
+ push zl
+ push yh
+ push yl
+ push temp
+ in yh,sph
+ in yl,spl
+ ldd zl,y+7
+ ldd zh,y+6
+
+ lsl zl
+ rol zh
+printstr_loop:
+ lpm temp,z+
+ cpi temp,0
+ breq printstr_end
+ rcall uartputc
+ cpi temp,13
+ brne printstr_loop
+ ldi temp,10
+ rcall uartputc
+ rjmp printstr_loop
+
+printstr_end:
+ adiw zl,1 ;rounding
+ lsr zh
+ ror zl
+
+ std y+7,zl
+ std y+6,zh
+ pop temp
+ pop yl
+ pop yh
+ pop zl
+ pop zh
+ ret
+
+; ---------------- Virtual peripherial interface ----------------
+
+;The hw is modelled to make writing a CPM BIOS easier.
+;Ports:
+;0 - Con status. Returns 0xFF if the UART has a byte, 0 otherwise.
+;1 - Console input, aka UDR.
+;2 - Console output
+;3 - "UART" status: bit 0=rx, bit 1 = tx
+;4 - "UART" data register, no wait
+;15 - Disk select
+;16,17 - Track select
+;18 - Sector select
+;20 - Write addr l
+;21 - Write addr h
+;22 - Trigger - write to read, to write a sector using the above info;
+; , write to allocated/dirctory/unallocated
+
+ .equ READ_FUNC = 7
+ .equ WRITE_FUNC = 6
+ .equ BOOT_FUNC = 5
+ .equ HOME_FUNC = 4
+
+
+
+;*****************************************************
+;* CP/M to host disk constants *
+;*****************************************************
+ .equ MAXDISKS = 4 ;Max number of Disks (partitions)
+ .equ blksize = 1024 ;CP/M allocation size
+ .equ hostsize = 512 ;host disk sector size
+; .equ hostspt = 20 ;host disk sectors/trk
+ .equ hostblk = hostsize/128 ;CP/M sects/host buff
+; .equ CPMSPT = hostblk*hostspt;CP/M sectors/track
+ .equ CPMSPT = 26 ;
+ .equ SECMSK = hostblk-1 ;sector mask
+ .equ SECSHF = log2(hostblk) ;sector shift
+
+;*****************************************************
+;* BDOS constants on entry to write *
+;*****************************************************
+ .equ WRALL = 0 ;write to allocated
+ .equ WRDIR = 1 ;write to directory
+ .equ WRUAL = 2 ;write to unallocated
+ .equ WRTMSK= 3 ;write type mask
+
+
+ .dseg
+ndisks: .byte 1 ;Number of CP/M disks
+
+seekdsk: .byte 1 ;seek disk number
+seektrk: .byte 2 ;seek track number
+seeksec: .byte 1 ;seek sector number
+
+hostparttbl: .byte 8*MAXDISKS ;host partition table (start sector, sector count)
+hostparttbltop:
+hostdsk: .byte 1 ;host disk number
+hostlba: .byte 3 ;host sector number (relative to partition start)
+
+unacnt: .byte 1 ;unalloc rec cnt
+unadsk: .byte 1 ;last unalloc disk
+unatrk: .byte 2 ;last unalloc track
+unasec: .byte 1 ;last unalloc sector
+
+erflag: .byte 1 ;error reporting
+wrtype: .byte 1 ;write operation type
+dmaadr: .byte 2 ;last dma address
+hostbuf: .byte hostsize ;host buffer (from/to SD-card)
+
+
+ .cseg
+
+conStatus:
+ lds temp,rxcount
+ cpse temp,_0
+ ldi temp,0xff
+ ret
+
+conInp:
+ rjmp uartgetc
+
+dbgOut:
+ printnewline
+ printstring "Debug: "
+ rcall printhex
+ ret
+
+conOut:
+ rjmp uartputc
+
+uartstat:
+ clr temp
+ lds temp2,rxcount
+ cpse temp2,_0
+ sbr temp,0x01
+ lds temp2,txcount
+ cpi temp2,TXBUFSIZE
+ breq uartst_1
+ sbr temp,0x02
+uartst_1:
+ ret
+
+uartout:
+ lds temp2,txcount
+ cpi temp2,TXBUFSIZE
+ breq uartout_1
+ rjmp uartputc
+uartout_1:
+ ret
+
+uartin:
+ clr temp
+ lds temp2,rxcount
+ cpse temp2,_0
+ rjmp uartgetc
+ ret
+
+;Called with port in temp2. Should return value in temp.
+portRead:
+ cpi temp2,0
+ breq conStatus
+ cpi temp2,1
+ breq conInp
+ cpi temp2,3
+ breq uartstat
+ cpi temp2,4
+ breq uartin
+
+ cpi temp2,15
+ breq dskDiskCheck
+ cpi temp2,22
+ breq dskErrorRet
+
+ cpi temp2,TIMER_MSECS
+ brlo pr_noclock
+ cpi temp2,TIMER_MSECS+6
+ brsh pr_noclock
+ rjmp clockget
+
+pr_noclock:
+ ldi temp,0xFF
+ ret
+
+;Called with port in temp2 and value in temp.
+portWrite:
+ cpi temp2,0
+ breq dbgOut
+ cpi temp2,2
+ breq conOut
+ cpi temp2,4
+ breq uartout
+
+ cpi temp2,15
+ breq dskDiskSel
+ cpi temp2,16
+ breq dskTrackSel_l
+ cpi temp2,17
+ breq dskTrackSel_h
+ cpi temp2,18
+ breq dskSecSel
+ cpi temp2,20
+ breq dskDmaL
+ cpi temp2,21
+ breq dskDmaH
+
+ cpi temp2,22
+ breq dskDoIt
+
+ cpi temp2,TIMERPORT
+ brlo pw_noclock
+ cpi temp2,TIMER_MSECS+6
+ brsh pw_noclock
+ rjmp clockput
+
+pw_noclock:
+ ret
+
+
+dskDiskCheck:
+ lds temp2,seekdsk
+ cpi temp2,RAMDISKNR
+ brsh dsk_dchrd ;maybe ramdisk
+
+; Check if selected disk # is less then # of disks.
+
+ lds temp,ndisks
+ tst temp
+ brne dsk_dchpart1
+
+; Need to init
+
+ rcall dsk_partinit
+ cbr temp,0x80
+ lds temp2,seekdsk
+
+dsk_dchpart1:
+ cp temp2,temp
+ brsh dsk_dcher
+
+dsk_dchend:
+ ldi temp,0
+ ret
+
+dsk_dchrd:
+#if RAMDISKCNT
+ cpi temp,RAMDISKNR+RAMDISKCNT
+ brlo dsk_dchend
+#endif
+dsk_dcher:
+ ldi temp,0xff ;error return
+ ret
+
+
+
+
+dskErrorRet:
+ lds temp,erflag
+ ret
+
+dskDiskSel:
+ sts seekdsk,temp
+ ret
+
+dskTrackSel_l:
+ sts seektrk,temp
+ sts seektrk+1,_0
+ ret
+
+dskTrackSel_h:
+ sts seektrk+1,temp
+ ret
+
+dskSecSel:
+ sts seeksec,temp
+ ret
+
+dskDmal:
+ sts dmaadr,temp
+ ret
+
+dskDmah:
+ sts dmaadr+1,temp
+ ret
+
+dskDoIt:
+.if DISK_DEBUG
+ push temp
+ sbrc temp,READ_FUNC
+ rjmp dskdbgr
+ sbrc temp,WRITE_FUNC
+ rjmp dskdbgw
+ rjmp dskdbge
+
+dskdbgr:
+ printnewline
+ printstring "Disk read: "
+ rjmp dskdbg1
+dskdbgw:
+ printnewline
+ printstring "Disk write: "
+dskdbg1:
+ lds temp,seekdsk
+ subi temp,-('A')
+ rcall uartputc
+ printstring ": track "
+ lds temp2,seektrk+1
+ lds temp,seektrk
+ rcall printhexw
+ printstring ", sector "
+ lds temp,seeksec
+ rcall printhex
+ printstring ", dma-addr "
+ lds temp2,dmaadr+1
+ lds temp,dmaadr
+ rcall printhexw
+ pop temp
+ push temp
+ sbrs temp,WRITE_FUNC
+ rjmp dskdbge
+ printstring " wrtype "
+ andi temp,3
+ rcall printhex
+dskdbge:
+ pop temp
+.endif
+ ;See what has to be done.
+ sbrc temp,READ_FUNC
+ rjmp dsk_read
+ sbrc temp,WRITE_FUNC
+ rjmp dsk_write
+ sbrc temp,HOME_FUNC
+ rjmp dsk_home
+ sbrc temp,BOOT_FUNC
+ rjmp dsk_boot
+
+ printstring "DISK I/O: Invalid Function code: "
+ rcall printhex
+ rjmp haltinv
+
+dsk_boot:
+ sts ndisks,_0 ;no active partitions
+dsk_cboot:
+ cbi flags,hostact ;host buffer inactive
+ sts unacnt,_0 ;clear unalloc count
+ ret
+
+dsk_home:
+ sbis flags,hostwrt ;check for pending write
+ cbi flags,hostact ;clear host active flag
+ ret
+
+
+dsk_read:
+
+ sbi flags,readop ;read operation
+ ;RAM disk?
+ lds temp2,seekdsk
+#if RAMDISKCNT
+ cpi temp2,RAMDISKNR
+ brlt PC+2
+ rjmp rdskDoIt
+#endif
+ sts unacnt,_0
+ sbi flags,rsflag ;must read data
+ ldi temp,WRUAL ;write type
+ sts wrtype,temp ;treat as unalloc
+ rjmp dsk_rwoper ;to perform the read
+
+
+dsk_write:
+ ;write the selected CP/M sector
+
+ cbi flags,readop ;not a read operation
+
+ ;RAM disk?
+ lds temp2,seekdsk
+#if RAMDISKCNT
+ cpi temp2,RAMDISKNR
+ brlt PC+2
+ rjmp rdskDoIt
+#endif
+ andi temp,WRTMSK
+ sts wrtype,temp ;save write type
+
+ cpi temp,WRUAL ;write unallocated?
+ brne dsk_chkuna ;check for unalloc
+
+; write to unallocated, set parameters
+ ldi temp,blksize/128 ;next unalloc recs
+ sts unacnt,temp
+ lds temp,seekdsk ;disk to seek
+ sts unadsk,temp ;unadsk = sekdsk
+ lds temp,seektrk
+ sts unatrk,temp ;unatrk = sectrk
+ lds temp,seektrk+1
+ sts unatrk+1,temp ;unatrk = sectrk
+ lds temp,seeksec
+ sts unasec,temp ;unasec = seksec
+;
+dsk_chkuna:
+ ;check for write to unallocated sector
+ lds temp,unacnt ;any unalloc remain?
+ tst temp
+ breq dsk_alloc ;skip if not
+
+; more unallocated records remain
+ dec temp ;unacnt = unacnt-1
+ sts unacnt,temp
+ lds temp,seekdsk ;same disk?
+ lds temp2,unadsk
+ cp temp,temp2 ;seekdsk = unadsk?
+ brne dsk_alloc ;skip if not
+
+; disks are the same
+ lds temp,unatrk
+ lds temp2,unatrk+1
+ lds temp3,seektrk
+ lds temp4,seektrk+1
+ cp temp,temp3 ;seektrk = unatrk?
+ cpc temp2,temp4
+ brne dsk_alloc ;skip if not
+
+; tracks are the same
+ lds temp,seeksec ;same sector?
+ lds temp2,unasec
+ cp temp,temp2 ;seeksec = unasec?
+ brne dsk_alloc ;skip if not
+
+; match, move to next sector for future ref
+ inc temp2 ;unasec = unasec+1
+ sts unasec,temp2
+ cpi temp2,CPMSPT ;end of track? (count CP/M sectors)
+ brlo dsk_noovf ;skip if no overflow
+
+; overflow to next track
+ sts unasec,_0 ;unasec = 0
+ lds temp,unatrk
+ lds temp2,unatrk+1
+ subi temp, low(-1) ;unatrk = unatrk+1
+ sbci temp2,high(-1)
+ sts unatrk,temp
+ sts unatrk+1,temp2
+;
+dsk_noovf:
+ cbi flags,rsflag ;rsflag = 0
+ rjmp dsk_rwoper ;to perform the write
+;
+dsk_alloc:
+ ;not an unallocated record, requires pre-read
+ sts unacnt,_0 ;unacnt = 0
+ sbi flags,rsflag ;rsflag = 1
+
+;*****************************************************
+;* Common code for READ and WRITE follows *
+;*****************************************************
+
+dsk_rwoper:
+ ;enter here to perform the read/write
+.if DISK_DEBUG
+ printstring ", flags: "
+ in temp,flags
+ rcall printhex
+.endif
+ sts erflag,_0 ;no errors (yet)
+
+ ;Convert track/sector to an LBA address (in 128byte blocks)
+
+ lds xl,seeksec ;
+ ldi xh,0 ;
+ ldi yl,0 ;
+ lds temp3,seektrk ;
+ lds temp4,seektrk+1 ;
+ ldi temp,CPMSPT ;
+ mul temp3,temp ;
+ add xl,r0 ;
+ adc xh,r1 ;
+ mul temp4,temp ;
+ add xh,r0 ;yl:xh:xl := sec + trk * SectorsPerTrack
+ adc yl,r1 ;
+
+ mov temp,xl
+ andi temp,SECMSK ;mask buffer number
+ push temp ;save for later
+
+ ;Convert from CP/M LBA blocks to host LBA blocks
+ ldi temp,SECSHF
+dsk_sh1:
+ lsr yl
+ ror xh
+ ror xl
+ dec temp
+ brne dsk_sh1
+ ;yl:xh:xl = host block to seek
+; active host sector?
+ in _tmp0,flags ;host active flag
+ sbi flags,hostact ;always becomes 1
+ sbrs _tmp0,hostact ;was it already?
+ rjmp dsk_filhst ;fill host if not
+
+; host buffer active, same as seek buffer?
+ lds temp,seekdsk
+ lds temp2,hostdsk ;same disk?
+ cp temp,temp2 ;seekdsk = hostdsk?
+ brne dsk_nomatch
+
+; same disk, same block?
+ lds temp,hostlba
+ lds temp2,hostlba+1
+ lds temp3,hostlba+2
+ cp xl,temp
+ cpc xh,temp2
+ cpc yl,temp3
+ breq dsk_match
+;
+dsk_nomatch:
+ ;proper disk, but not correct sector
+ sbis flags,hostwrt ;host written?
+ rjmp dsk_filhst
+ push xl
+ push xh
+ push yl
+ rcall dsk_writehost ;clear host buff
+ pop yl
+ pop xh
+ pop xl
+
+dsk_filhst:
+ ;may have to fill the host buffer
+ lds temp,seekdsk
+ sts hostdsk,temp
+ sts hostlba,xl
+ sts hostlba+1,xh
+ sts hostlba+2,yl
+
+ sbic flags,rsflag ;need to read?
+ rcall dsk_readhost ;yes, if 1
+ cbi flags,hostwrt ;no pending write
+
+dsk_match:
+
+ ;copy data to or from buffer
+ ldiw z,hostbuf
+ ldi temp,128
+ pop temp2 ;get buffer number (which part of hostbuf)
+ mul temp2,temp
+ add zl,r0 ;offset in hostbuf
+ adc zh,r1
+.if DISK_DEBUG > 2
+ push r0
+ push r1
+ printstring "; host buf adr: "
+ pop temp2
+ pop temp
+ rcall printhexw
+.endif
+
+ lds xl,dmaadr
+ lds xh,dmaadr+1
+ ldi temp3,128 ;length of move
+ sbic flags,readop ;which way?
+ rjmp dsk_rmove ;skip if read
+
+; mark write operation
+ sbi flags,hostwrt ;hostwrt = 1
+dsk_wmove:
+ mem_read
+ st z+,temp
+ adiw xl,1
+ dec temp3
+ brne dsk_wmove
+ rjmp dsk_rwmfin
+
+dsk_rmove:
+ ld temp,z+
+ mem_write
+ adiw xl,1
+ dec temp3
+ brne dsk_rmove
+dsk_rwmfin:
+; data has been moved to/from host buffer
+ lds temp,wrtype ;write type
+ cpi temp,WRDIR ;to directory?
+ breq dsk_wdir
+ ret ;no further processing
+dsk_wdir:
+; clear host buffer for directory write
+ lds temp,erflag
+ tst temp ;errors?
+ breq dsk_wdir1
+ ret ;skip if so
+dsk_wdir1:
+ rcall dsk_writehost ;clear host buff
+ cbi flags,hostwrt ;buffer written
+ ret
+
+;*****************************************************
+
+; hostdsk = host disk #, (partition #)
+; hostlba = host block #, relative to partition start
+; Read/Write "hostsize" bytes to/from hostbuf
+
+
+dsk_hostparam:
+ ldiw z,hostparttbl
+ lds temp,hostdsk
+.if HOSTRW_DEBUG
+ push temp
+ subi temp,-('A')
+ rcall uartputc
+ printstring ": "
+ pop temp
+.endif
+
+ lsl temp
+ lsl temp
+ lsl temp
+ add zl,temp
+ adc zh,_0
+
+ lds temp,hostlba
+ lds temp2,hostlba+1
+ lds temp3,hostlba+2
+
+.if HOSTRW_DEBUG
+ printstring "lba: "
+ clr temp4
+ rcall print_ultoa
+.endif
+
+ ldd xl,z+4
+ ldd xh,z+5
+ ldd yl,z+6
+
+ cp temp,xl
+ cpc temp2,xh
+ cpc temp3,yl
+ brcs dsk_hp1
+
+.if HOSTRW_DEBUG
+ printstring ", max: "
+ push temp4
+ push temp3
+ push temp2
+ push temp
+ movw temp,x
+ mov temp3,yl
+ clr temp4
+ rcall print_ultoa
+ pop temp
+ pop temp2
+ pop temp3
+ pop temp4
+ printstring " "
+.endif
+
+ clr temp
+ ret
+
+dsk_hp1:
+ ldd xl,z+0
+ ldd xh,z+1
+ ldd yl,z+2
+ ldd yh,z+3
+
+ add xl,temp
+ adc xh,temp2
+ adc yl,temp3
+ adc yh,_0
+.if HOSTRW_DEBUG
+ printstring ", abs:"
+ push temp4
+ push temp3
+ push temp2
+ push temp
+ movw temp,x
+ movw temp3,y
+ rcall print_ultoa
+ pop temp
+ pop temp2
+ pop temp3
+ pop temp4
+ printstring " "
+.endif
+ ori temp,255
+dsk_hpex:
+ ret
+
+;*****************************************************
+;* WRITEhost performs the physical write to *
+;* the host disk, READhost reads the physical *
+;* disk. *
+;*****************************************************
+
+dsk_writehost:
+.if HOSTRW_DEBUG
+ printnewline
+ printstring "host write "
+.endif
+ rcall dsk_hostparam
+ breq dsk_rdwr_err
+
+ rcall mmcWriteSect
+ tst temp
+ breq dsk_rdwr_ok
+
+ rcall dsk_partinit
+ cbr temp,0x80
+ breq dsk_rdwr_err
+
+ rcall dsk_hostparam
+ breq dsk_rdwr_err
+ rcall mmcWriteSect
+ tst temp
+ brne dsk_rdwr_err
+ rjmp dsk_rdwr_ok
+
+
+dsk_readhost:
+.if HOSTRW_DEBUG
+ printnewline
+ printstring "host read "
+.endif
+ rcall dsk_hostparam
+ breq dsk_rdwr_err
+
+ rcall mmcReadSect
+ tst temp
+ breq dsk_rdwr_ok
+
+ rcall dsk_partinit
+ cbr temp,0x80
+ breq dsk_rdwr_err
+
+ rcall dsk_hostparam
+ breq dsk_rdwr_err
+ rcall mmcReadSect
+ tst temp
+ brne dsk_rdwr_err
+
+dsk_rdwr_ok:
+ sts erflag,_0
+ ret
+
+dsk_rdwr_err:
+ sts erflag,_255
+ ret
+
+;***************************************************************************
+
+#if RAMDISKCNT
+
+; ----------------- RAM disk -----------------
+
+ .dseg
+rdskbuf:
+ .byte 128
+
+ .cseg
+;----------------------------------------------
+
+rdsk_adr:
+ ldi xl,0
+ lds xh,seeksec
+ lds temp2,seektrk
+
+ lsr xh
+ ror xl ;Col 0..7
+
+ mov temp,temp2
+ andi temp,0x0f
+ swap temp
+ or xh,temp ;Row 0..7
+
+ ldiw z,rdskbuf
+ ldi temp3,128
+ DRAM_SETADDR xh, ~0,(1<<ram_ras), ~0,(1<<ram_a8)|(1<<ram_oe)
+ cbi P_RAS,ram_ras
+
+.if DISK_DEBUG > 1
+ mov temp,xh
+ rcall printhex
+ printstring " "
+ mov temp,xl
+ rcall printhex
+ printstring " "
+.endif
+ ret
+
+;----------------------------------------------
+
+rdskDoIt:
+ sts erflag,_0
+ sbis flags,readop
+ rjmp rdsk_wr
+
+.if DISK_DEBUG > 1
+ printnewline
+ printstring "rd-adr: "
+.endif
+ rcall rdsk_adr
+rdsk_rdl:
+ DRAM_SETADDR xl, ~(1<<ram_ras),0, ~((1<<ram_oe)), (1<<ram_a8)
+ cbi P_CAS,ram_cas
+ cbi P_A8,ram_a8
+ inc xl
+ dram_wait DRAM_WAITSTATES ;
+ in temp,P_DQ-2 ; PIN
+ sbi P_CAS,ram_cas
+
+ cbi P_CAS,ram_cas
+ andi temp,0x0f
+ swap temp
+ dram_wait DRAM_WAITSTATES ;
+ in temp2,P_DQ-2 ; PIN
+ andi temp2,0x0f
+ or temp,temp2
+
+ sbi P_OE,ram_oe
+ sbi P_CAS,ram_cas
+ dec temp3
+ st z+,temp
+ brne rdsk_rdl
+
+ sbi P_RAS,ram_ras
+ ldiw z,rdskbuf
+ lds xl,dmaadr
+ lds xh,dmaadr+1
+ ldi temp3,128
+rdsk_rdstl:
+ ld temp,z+
+ mem_write
+ adiw x,1
+ dec temp3
+ brne rdsk_rdstl
+ ret
+
+
+rdsk_wr:
+.if DISK_DEBUG > 1
+ printnewline
+ printstring "wr-adr: "
+.endif
+ lds xl,dmaadr
+ lds xh,dmaadr+1
+ ldiw z,rdskbuf
+ ldi temp3,128
+rdsk_wrldl:
+ mem_read
+ st z+,temp
+ adiw x,1
+ dec temp3
+ brne rdsk_wrldl
+
+ ldi temp2,RAM_DQ_MASK | (1<<ram_w) | (1<<ram_cas)
+ out DDRC,temp2
+ rcall rdsk_adr
+rdsk_wrl:
+ ld temp,z+
+ mov temp2,temp
+ andi temp,RAM_DQ_MASK & ~(1<<ram_w)
+ ori temp,(1<<ram_cas)
+ out PORTC,temp
+ DRAM_SETADDR xl, ~(1<<ram_ras),0, ~((1<<ram_a8)),(1<<ram_oe)
+ cbi PORTC,ram_cas
+ sbi PORTD,ram_a8
+ sbi PORTC,ram_cas
+ swap temp2
+ andi temp2,RAM_DQ_MASK & ~(1<<ram_w)
+ ori temp2,(1<<ram_cas)
+ out PORTC,temp2
+ cbi PORTC,ram_cas
+ inc xl
+ sbi PORTC,ram_cas
+ dec temp3
+ brne rdsk_wrl
+
+ sbi P_RAS,ram_ras
+ ldi temp,~RAM_DQ_MASK | (1<<ram_w) | (1<<ram_cas)
+ out DDRC,temp
+ out PORTC,temp
+ ret
+
+
+#endif /* RAMDISKCNT */
+
+;---------------------------------------------------------------------
+
+; Partition table offsets:
+#define PART_TYPE 4
+#define PART_START 8
+#define PART_SIZE 12
+
+ .dseg
+tmp_tbl:
+ .byte 8*MAXDISKS
+
+ .cseg
+dsk_partinit:
+ sts ndisks,_0
+ rcall mmcInit
+ andi temp,MMCST_NOINIT & MMCST_NODISK
+ brne dsk_pierr
+
+;Load first sector from MMC (boot sector)
+ ldiw y,0 ; Sector 0
+ movw x,y
+ rcall mmcReadSect
+ tst temp
+ breq dsk_pi1
+
+dsk_pierr:
+ clr temp
+ ret
+
+dsk_pi1:
+ ldiw y,tmp_tbl
+ ldi temp2,8*MAXDISKS
+dsk_picl:
+ st y+,_0
+ dec temp2
+ brne dsk_picl
+ sbiw y,8*MAXDISKS
+
+;Test, if it has a valid MBR
+
+ ldiw z,hostbuf+510-1 ;Point to last byte of partition table
+
+ ldi temp3,0 ;temp3 holds number of found disks (paritions)
+ ldd temp,z+1 ;MBR signature (0xAA55) at and of sector?
+ ldd temp2,z+2
+ ldi temp4,0xAA
+ cpi temp,0x55
+ cpc temp2,temp4
+ breq dsk_part
+
+;No MBR, no partition table ...
+ inc temp3 ;pretend we have one.
+ ldi temp,high((1<<16) * 128/512)
+ std y+0,_0 ;start at beginning of card
+ std y+1,_0
+ std y+2,_0
+ std y+3,_0
+ std y+4,_0 ;max CP/M 2.2 disk size
+ std y+5,temp ;
+ std y+6,_0
+ std y+7,_0
+ rjmp dsk_pend
+
+;Search Partition Table for CP/M partitions
+dsk_part:
+ sbiw z,63 ;Now at first byte of partition table
+ ldi temp4,high(hostbuf+510)
+dsk_ploop:
+ ldd temp,z+PART_TYPE
+ cpi temp,PARTID
+ brne dsk_nextp
+
+; Found a CP/M partition
+
+ ldd temp,z+PART_START
+ st y+,temp
+ ldd temp,z+PART_START+1
+ st y+,temp
+ ldd temp,z+PART_START+2
+ st y+,temp
+ ldd temp,z+PART_START+3
+ st y+,temp
+
+ ldd temp,z+PART_SIZE
+ st y+,temp
+ ldd temp,z+PART_SIZE+1
+ st y+,temp
+ ldd temp,z+PART_SIZE+2
+ st y+,temp
+ ldd temp,z+PART_SIZE+3
+ st y+,temp
+
+ inc temp3
+ cpi temp3,MAXDISKS
+ breq dsk_pend
+dsk_nextp:
+ adiw zl,16
+ cpi zl,low(hostbuf+510)
+ cpc zh,temp4
+ brlo dsk_ploop
+
+dsk_pend:
+
+;Store new partitions and check if the SD card has been changed.
+
+ ldiw y,tmp_tbl
+ ldiw z,hostparttbl
+ ldi temp4,8*MAXDISKS
+ clt
+dsk_pcpl:
+ ld temp,y+
+ ld temp2,z
+ st z+,temp
+ cpse temp,temp2
+ set
+ dec temp4
+ brne dsk_pcpl
+
+ mov temp,temp3
+ sts ndisks,temp
+ brtc dsk_pcpe
+
+ tst temp
+ breq dsk_pcpe
+
+; SD card changed.
+ sbr temp,0x80
+
+dsk_pcpe:
+ ret
+
+;---------------------------------------------------------------------
+; Print partition table info
+
+prnt_parttbl:
+ ldiw z,hostparttbl
+pprl:
+ ldd xl,z+4 ;Get partition size
+ ldd xh,z+5
+ ldd yl,z+6
+ ldd yh,z+7
+ cp xl,_0 ;If zero ...
+ cpc xh,_0
+ cpc yl,_0
+ cpc yh,_0
+ breq pppre ;... No more partitions.
+
+ ldd temp,z+0 ;Get partition start
+ ldd temp2,z+1
+ ldd temp3,z+2
+ ldd temp4,z+3
+ printnewline
+ cp temp,_0 ;If zero ...
+ cpc temp2,_0
+ cpc temp3,_0
+ cpc temp4,_0
+ breq prnop ;... no partition table at 0
+
+ rcall prstr_table
+ rjmp pprsz
+prnop:
+ rcall prstr_image
+pprsz:
+ rcall print_ultoa
+ printstring ", size: "
+ movw temp,x
+ movw temp3,y
+
+ lsr temp4
+ ror temp3
+ ror temp2
+ ror temp
+ rcall print_ultoa
+ printstring "KB."
+
+ adiw z,8
+ ldi temp,high(hostparttbltop)
+ cpi zl, low (hostparttbltop)
+ cpc zh,temp
+ brlo pprl
+pppre:
+ ret
+
+prstr_table:
+ printstring "CP/M partition at: "
+ ret
+prstr_image:
+ printstring "Assuming CP/M image at: "
+ ret
+
+; ****************************************************************************
+
+; ------------- system timer 1ms ---------------
+
+ .dseg
+
+delay_timer1:
+ .byte 1
+delay_timer2:
+ .byte 1
+timer_base:
+timer_ms:
+ .byte 2
+timer_s:
+ .byte 4
+; don't change order here, clock put/get depends on it.
+cntms_out: ; register for ms
+ .byte 2
+utime_io: ; register for uptime.
+ .byte 4
+cnt_1ms:
+ .byte 2
+uptime:
+ .byte 4
+timer_top:
+.equ timer_size = timer_top - timer_base
+
+.equ clkofs = cnt_1ms-cntms_out
+.equ timerofs = cnt_1ms-timer_ms
+
+
+ .cseg
+sysclockint:
+ .org OC1Baddr ; Timer/Counter1 Compare Match B
+ rjmp sysclockint ; 1ms system timer
+
+ .org sysclockint
+ push zl
+ in zl,SREG
+ push zl
+ push zh
+ inm8 zl,OCR1BL
+ inm8 zh,OCR1BH
+ addiw z,F_CPU/1000
+ outm8 OCR1BH,zh
+ outm8 OCR1BL,zl
+
+#if DRAM_8BIT /* Implies software uart */
+ lds zl,srx_char_to
+ subi zl,1
+ brcs syscl0
+ sts srx_char_to,zl
+ brne syscl0
+ rcall srx_to
+syscl0:
+#endif
+ lds zl,delay_timer1
+ subi zl,1
+ brcs syscl_t1n
+ sts delay_timer1,zl
+syscl_t1n:
+ lds zl,delay_timer2
+ subi zl,1
+ brcs syscl_t2n
+ sts delay_timer2,zl
+syscl_t2n:
+ lds zl,cnt_1ms
+ lds zh,cnt_1ms+1
+ adiw z,1
+
+ sts cnt_1ms,zl
+ sts cnt_1ms+1,zh
+ cpi zl,low(1000)
+ ldi zl,high(1000) ;doesn't change flags
+ cpc zh,zl
+ brlo syscl_end
+
+ sts cnt_1ms,_0
+ sts cnt_1ms+1,_0
+
+ lds zl,uptime+0
+ inc zl
+ sts uptime+0,zl
+ brne syscl_end
+ lds zl,uptime+1
+ inc zl
+ sts uptime+1,zl
+ brne syscl_end
+ lds zl,uptime+2
+ inc zl
+ sts uptime+2,zl
+ brne syscl_end
+ lds zl,uptime+3
+ inc zl
+ sts uptime+3,zl
+
+syscl_end:
+ pop zh
+ pop zl
+ out SREG,zl
+ pop zl
+ reti
+
+; wait for temp ms
+
+delay_ms:
+ sts delay_timer1,temp
+dly_loop:
+ lds temp,delay_timer1
+ cpi temp,0
+ brne dly_loop
+ ret
+
+;
+
+clockget:
+ ldi temp,0xFF
+ subi temp2,TIMER_MSECS
+ brcs clkget_end ;Port number in range?
+ ldiw z,cntms_out
+ breq clkget_copy ;lowest byte requestet, latch clock
+ cpi temp2,6
+ brsh clkget_end ;Port number to high?
+
+ add zl,temp2
+ brcc PC+2
+ inc zh
+ ld temp,z
+clkget_end:
+ ret
+
+
+
+clkget_copy:
+ ldi temp2,6
+ cli
+clkget_l:
+ ldd temp,z+clkofs
+ st z+,temp
+ dec temp2
+ brne clkget_l
+ sei
+ lds temp,cntms_out
+ ;req. byte in temp
+ ret
+
+clockput:
+ subi temp2,TIMERPORT
+ brcs clkput_end ;Port number in range?
+ brne clkput_1
+
+ ; clock control
+
+ cpi temp,starttimercmd
+ breq timer_start
+ cpi temp,quitTimerCmd
+ breq timer_quit
+ cpi temp,printTimerCmd
+ breq timer_print
+ cpi temp,uptimeCmd
+ brne cp_ex
+ rjmp uptime_print
+cp_ex:
+ ret
+
+timer_quit:
+ rcall timer_print
+ rjmp timer_start
+
+clkput_1:
+ dec temp2
+ ldiw z,cntms_out
+ breq clkput_copy ;lowest byte requestet, latch clock
+ cpi temp2,6
+ brsh clkput_end ;Port number to high?
+
+ add zl,temp2
+ brcc PC+2
+ inc zh
+ st z,temp
+clkput_end:
+ ret
+
+clkput_copy:
+ st z,temp
+ adiw z,5
+ ldi temp2,6
+ cli
+clkput_l:
+ ldd temp,z+clkofs
+ st z+,temp
+ dec temp2
+ brne clkput_l
+ sei
+ ret
+
+; start/reset timer
+;
+timer_start:
+ ldiw z,timer_ms
+ ldi temp2,6
+ cli
+ts_loop:
+ ldd temp,z+timerofs
+ st z+,temp
+ dec temp2
+ brne ts_loop
+ sei
+ ret
+
+
+; print timer
+;
+
+timer_print:
+ push yh
+ push yl
+ ldiw z,timer_ms
+
+; put ms on stack (16 bit)
+
+ cli
+ ldd yl,z+timerofs
+ ld temp2,z+
+ sub yl,temp2
+ ldd yh,z+timerofs
+ ld temp2,z+
+ sbc yh,temp2
+ brsh tp_s
+
+ addiw y,1000
+ sec
+tp_s:
+ push yh
+ push yl
+
+ ldd temp,z+timerofs
+ ld yl,z+
+ sbc temp,yl
+
+ ldd temp2,z+timerofs
+ ld yh,z+
+ sbc temp2,yh
+
+ ldd temp3,z+timerofs
+ ld yl,z+
+ sbc temp3,yl
+
+ sei
+ ldd temp4,z+timerofs
+ ld yh,z+
+ sbc temp4,yh
+
+ printnewline
+ printstring "Timer running. Elapsed: "
+ rcall print_ultoa
+
+ printstring "."
+ pop temp
+ pop temp2
+ ldi temp3,0
+ ldi temp4,0
+ rcall print_ultoa
+ printstring "s."
+
+ pop yl
+ pop yh
+ ret
+
+uptime_print:
+
+ ldiw z,cnt_1ms
+
+ cli
+ ld temp,z+
+ push temp
+ ld temp,z+
+ push temp
+
+ ld temp,z+
+ ld temp2,z+
+ ld temp3,z+
+ sei
+ ld temp4,z+
+
+ printnewline
+ printstring "Uptime: "
+
+ rcall print_ultoa
+ printstring ","
+
+ ldi temp3,0
+ ldi temp4,0
+ pop temp2
+ pop temp
+ rcall print_ultoa
+ printstring "s."
+
+ ret
+
+
+
+; --------------- Debugging stuff ---------------
+; Print a line with the Z80 main registers
+
+;.if INS_DEBUG
+
+zflags_to_ch:
+ .db "SZ H PNC",0,0
+
+printregs:
+ printnewline
+
+ push zl
+ push zh
+ ldiw z,zflags_to_ch*2
+ mov temp2,z_flags
+pr_zfl_next:
+ lpm temp,z+
+ tst temp
+ breq pr_zfl_end
+ cpi temp,' ' ; Test if no flag
+ breq pr_zfl_noflag
+ sbrs temp2,7 ;
+ ldi temp,' ' ; Flag not set
+ rcall uartputc
+pr_zfl_noflag:
+ rol temp2
+ rjmp pr_zfl_next
+pr_zfl_end:
+ pop zh
+ pop zl
+
+ printstring " A ="
+ mov temp,z_a
+ rcall printhex
+ printstring " BC ="
+ lds temp2,z_b
+ lds temp, z_c
+ rcall printhexw
+ printstring " DE ="
+ lds temp2,z_d
+ lds temp, z_e
+ rcall printhexw
+ printstring " HL ="
+ lds temp2,z_h
+ lds temp, z_l
+ rcall printhexw
+ printstring " SP ="
+ movw temp, z_spl
+ rcall printhexw
+ printstring " PC ="
+ movw temp, z_pcl
+ rcall printhexw
+ printstring " "
+ movw xl,z_pcl
+ mem_read
+ rcall printhex
+ printstring " "
+ adiw x,1
+ mem_read
+ rcall printhex
+ printstring " "
+ adiw x,1
+ mem_read
+ rcall printhex
+ printstring " "
+ ret
+;.endif
+
+
--- /dev/null
+; Serial interface using the ATmega8/88 USART.
+; This is part of the Z80-CP/M emulator written by Sprite_tm.
+;
+; Copyright (C) 2010 Leo C.
+;
+; This file is part of avrcpm.
+;
+; avrcpm is free software: you can redistribute it and/or modify it
+; under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; avrcpm is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with avrcpm. If not, see <http://www.gnu.org/licenses/>.
+;
+; $Id$
+;
+
+#define SSER_BIT_TC (F_CPU+BAUD/2) / BAUD
+
+#define RXBUFMASK RXBUFSIZE-1
+#define TXBUFMASK TXBUFSIZE-1
+
+ .dseg
+
+srx_state:
+ .byte 1
+srx_char_to:
+ .byte 1
+srx_dr:
+ .byte 1
+;srx_lastedge:
+; .byte 2
+stx_bitcount:
+ .byte 1
+stx_dr:
+ .byte 1
+rxcount:
+ .byte 1
+rxidx_w:
+ .byte 1
+rxidx_r:
+ .byte 1
+txcount:
+ .byte 1
+txidx_w:
+ .byte 1
+txidx_r:
+ .byte 1
+rxfifo:
+ .byte RXBUFSIZE
+txfifo:
+ .byte TXBUFSIZE
+
+
+ .cseg
+
+; Init
+uart_init:
+
+; - Init clock/timer system and serial port
+
+; Init timer 1 as
+; - Soft UART TX (OC1A/OCR1A).
+; - Soft UART RX (ICP1/ICR1).
+; - 1ms System timer is already configured at this point.
+
+ ldi temp,(1<<COM1A1)|(1<<COM1A0) ;OC1A high on compare match (UART TX)
+ outm8 TCCR1A,temp
+
+ ldi temp,(1<<ICF1) ;clear pending int
+ out TIFR1,temp
+ inm8 temp,TIMSK1
+ ori temp,(1<<ICIE1) ;Enable input capture int. (UART RX)
+ outm8 TIMSK1,temp
+ ret
+
+;------------------------------------------------------------------
+
+ .cseg
+srxint:
+ .org ICP1addr ; Timer/Counter1 Input Capture
+ rjmp srxint ; Soft UART: RX
+
+ .org srxint
+
+ push temp
+ in temp,sreg
+ push temp
+ push zh
+ push zl
+ inm8 zl,ICR1L
+ inm8 zh,ICR1H
+ push temp2
+ ldi temp2,(1<<ICES1)
+ inm8 temp,TCCR1B
+ eor temp,temp2 ;toggle edge
+ outm8 TCCR1B,temp
+ ldi temp,(1<<ICF1) ;clear pending int
+ out TIFR1,temp
+
+#if 0
+ lds temp,srx_state
+ subi temp,-'0'
+ rcall uartputc
+ lds temp,srx_dr
+ rcall printhex
+#endif
+ lds temp,srx_state
+ cpi temp,0
+ brne srxi_S1
+
+; State 0: Wait for start bit
+
+; sts srx_lastedge,zl ;save beginning of start bit
+; sts srx_lastedge+1,zh
+ movw srx_lastedgel,zl
+ ldi temp,1
+ sts srx_state,temp
+ ldi temp,2
+ sts srx_char_to,temp
+ sbis P_RXD-2,RXD ;RXD still low?
+ rjmp srxi_end2
+ ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
+ outm8 TCCR1B,zl
+ ldi zh,(1<<ICF1) ;clear pending int
+ out TIFR1,zh
+ sts srx_state,_0
+ sts srx_char_to,_0
+ rjmp srxi_end2
+
+srxi_S1:
+ cpi temp,1
+ brne srxi_S2
+
+; State 1: Check start bit (and collect 0-bits)
+
+; lds temp,srx_lastedge
+; lds temp2,srx_lastedge+1
+; sts srx_lastedge,zl
+; sts srx_lastedge+1,zh
+
+ movw temp,srx_lastedgel
+ movw srx_lastedgel,zl
+
+ sub zl,temp
+ sbc zh,temp2
+ subi zl,low ((SSER_BIT_TC+1)/2)
+ sbci zh,high((SSER_BIT_TC+1)/2)
+ brcs srxi_sberr
+
+; mov temp,zh
+; rcall printhex
+; mov temp,zl
+; rcall printhex
+
+ ldi temp,0x80
+srxi_1l:
+ subi zl,low(SSER_BIT_TC)
+ sbci zh,high(SSER_BIT_TC)
+ brcs srxi_1be
+ lsr temp
+ brcc srxi_1l
+ rjmp srxi_complete
+srxi_1be:
+ sts srx_dr,temp
+ ldi temp,2
+ sts srx_state,temp
+ rjmp srxi_end2
+
+srxi_sberr:
+ ldi temp,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
+ outm8 TCCR1B,temp
+ ldi temp,(1<<ICF1) ;clear pending int
+ out TIFR1,temp
+ sts srx_state,_0 ;next state
+#if 1
+ ldi temp,'?'
+ rcall uartputc
+ subi zl,low (-(SSER_BIT_TC+1)/2)
+ sbci zh,high(-(SSER_BIT_TC+1)/2)
+ mov temp,zh
+ rcall printhex
+ mov temp,zl
+ rcall printhex
+#endif
+ rjmp srxi_end2
+
+srxi_S2:
+ cpi temp,2
+ brne srxi_S3
+
+; State 2: collect 1-bits
+
+; lds temp,srx_lastedge
+; lds temp2,srx_lastedge+1
+; sts srx_lastedge,zl
+; sts srx_lastedge+1,zh
+
+ movw temp,srx_lastedgel
+ movw srx_lastedgel,zl
+
+ sub zl,temp
+ sbc zh,temp2
+ subi zl,low ((SSER_BIT_TC+1)/2)
+ sbci zh,high((SSER_BIT_TC+1)/2)
+
+ lds temp,srx_dr
+srxi_2l:
+ sec ;one more 1 bit
+ ror temp
+ brcs srxi_complete1 ;8 bits recieved
+ subi zl,low(SSER_BIT_TC)
+ sbci zh,high(SSER_BIT_TC)
+ brcc srxi_2l
+
+ sts srx_dr,temp
+ ldi temp,3
+ sts srx_state,temp
+ rjmp srxi_end2
+
+srxi_complete1:
+ ldi temp2,1 ;We are in start bit now.
+ sts srx_state,temp2
+ ldi temp2,2
+ sts srx_char_to,temp2
+ rjmp srxi_complete
+
+srxi_S3:
+ cpi temp,3
+ brne srxi_S4
+
+; State 3: collect 0-bits
+
+; lds temp,srx_lastedge
+; lds temp2,srx_lastedge+1
+; sts srx_lastedge,zl
+; sts srx_lastedge+1,zh
+
+ movw temp,srx_lastedgel
+ movw srx_lastedgel,zl
+
+ sub zl,temp
+ sbc zh,temp2
+ subi zl,low ((SSER_BIT_TC+1)/2)
+ sbci zh,high((SSER_BIT_TC+1)/2)
+
+ lds temp,srx_dr
+srxi_3l:
+ ;one more 0 bit
+ lsr temp
+ brcs srxi_complete0 ;8 bits recieved
+ subi zl,low(SSER_BIT_TC)
+ sbci zh,high(SSER_BIT_TC)
+ brcc srxi_3l
+
+ sts srx_dr,temp
+ ldi temp,2
+ sts srx_state,temp
+ rjmp srxi_end2
+
+srxi_S4:
+ ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
+ outm8 TCCR1B,zl
+ ldi zl,(1<<ICF1) ;clear pending int
+ sts srx_state,_0 ;next state
+ rjmp srxi_end2
+
+srxi_complete0:
+ sts srx_char_to,_0 ;clear timeout
+ sts srx_state,_0 ;next state
+srxi_complete:
+#if 0
+ ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
+ outm8 TCCR1B,zl
+ ldi zl,(1<<ICF1) ;clear pending int
+ out TIFR1,zl
+#endif
+
+; Save received character in a circular buffer. Do nothing if buffer overflows.
+
+ lds zh,rxcount ;if rxcount < RXBUFSIZE
+ cpi zh,RXBUFSIZE ; (room for at least 1 char?)
+ brsh srxi_ov ;
+ inc zh ;
+ sts rxcount,zh ; rxcount++
+
+ ldi zl,low(rxfifo) ;
+ lds zh,rxidx_w ;
+ add zl,zh ;
+ inc zh ;
+ andi zh,RXBUFMASK ;
+ sts rxidx_w,zh ; rxidx_w = ++rxidx_w % RXBUFSIZE
+ ldi zh,high(rxfifo) ;
+ brcc PC+2 ;
+ inc zh ;
+ st z,temp ; rxfifo[rxidx_w] = char
+srxi_ov: ;endif
+
+srxi_end2:
+ pop temp2
+srxi_end:
+ pop zl
+ pop zh
+ pop temp
+ out sreg,temp
+ pop temp
+ reti
+
+
+;----------------------------------------------------------------------
+
+ .cseg
+stxint:
+ .org OC1Aaddr ; Timer/Counter1 Compare Match A
+ rjmp stxint ; Soft UART: TX
+
+ .org stxint
+
+ push temp
+ in temp,sreg
+ push temp
+ push zh
+
+ inm8 temp,OCR1AL
+ inm8 zh,OCR1AH
+ subi temp,low(-SSER_BIT_TC)
+ sbci zh,high(-SSER_BIT_TC)
+ outm8 OCR1AH,zh
+ outm8 OCR1AL,temp
+ lds temp,stx_bitcount
+ tst temp
+ breq stxi_nxtchar
+
+ dec temp
+ sts stx_bitcount,temp
+ ldi zh,9 ;Start bit?
+ cp temp,zh
+ ldi zh,(1<<COM1A1)
+ breq stxi_0
+ lds temp,stx_dr
+ sbrs temp,0
+ ldi zh,(1<<COM1A1)|(1<<COM1A0)
+ lsr temp
+ sts stx_dr,temp
+stxi_0:
+ outm8 TCCR1A,zh
+ pop zh
+ pop temp
+ out sreg,temp
+ pop temp
+ reti
+
+; more characters?
+stxi_nxtchar:
+ lds temp,txcount ;if txcount != 0
+ tst temp ;
+ breq stxi_dis
+; get next char
+ push zl
+ dec temp ;
+ sts txcount,temp ; --txcount
+ ldi zl,low(txfifo) ;
+ ldi zh,high(txfifo) ;
+ lds temp,txidx_r ;
+ add zl,temp ;
+ brcc PC+2 ;
+ inc zh ;
+ inc temp ;
+ andi temp,TXBUFMASK ;
+ sts txidx_r,temp ;
+ ld temp,z
+ com temp
+ sts stx_dr,temp
+ ldi temp,10
+ sts stx_bitcount,temp
+ pop zl
+ pop zh
+ pop temp
+ out sreg,temp
+ pop temp
+ reti
+
+; disable transmitter
+stxi_dis:
+ ldi temp,(1<<COM1A1)|(1<<COM1A0)
+ outm8 TCCR1A,temp
+ inm8 temp,TIMSK1
+ andi temp,~(1<<OCIE1A)
+ outm8 TIMSK1,temp
+ pop zh
+ pop temp
+ out sreg,temp
+ pop temp
+ reti
+;------------------------------------------------------------------
+
+srx_to:
+#if 0
+ ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
+ outm8 TCCR1B,zl
+ ldi zl,(1<<ICF1) ;clear pending int
+ out TIFR1,zl
+#endif
+ push temp
+
+#if 0
+ ldi temp,'|'
+ rcall uartputc
+#endif
+ lds temp,srx_dr
+ mov zl,temp
+ com zl
+ andi zl,0x80
+srxto_l:
+ lsr temp
+ or temp,zl
+ brcc srxto_l
+
+; Save received character in a circular buffer. Do nothing if buffer overflows.
+
+ lds zh,rxcount ;if rxcount < RXBUFSIZE
+ cpi zh,RXBUFSIZE ; (room for at least 1 char?)
+ brsh srxto_ov ;
+ inc zh ;
+ sts rxcount,zh ; rxcount++
+
+ ldi zl,low(rxfifo) ;
+ lds zh,rxidx_w ;
+ add zl,zh ;
+ inc zh ;
+ andi zh,RXBUFMASK ;
+ sts rxidx_w,zh ; rxidx_w = ++rxidx_w % RXBUFSIZE
+ ldi zh,high(rxfifo) ;
+ brcc PC+2 ;
+ inc zh ;
+ st z,temp ; rxfifo[rxidx_w] = char
+srxto_ov: ;endif
+ sts srx_state,_0 ;next state
+
+ pop temp
+ ret
+
+
+;Fetches a char from the buffer to temp. If none available, waits till one is.
+
+uartgetc:
+ lds temp,rxcount ;Number of characters in buffer
+ tst temp
+ breq uartgetc ;Wait for char
+
+ push zh
+ push zl
+ ldi zl,low(rxfifo)
+ ldi zh,high(rxfifo)
+ lds temp,rxidx_r
+ add zl,temp
+ brcc PC+2
+ inc zh
+ inc temp
+ andi temp,RXBUFMASK
+ sts rxidx_r,temp
+ cli
+ lds temp,rxcount
+ dec temp
+ sts rxcount,temp
+ sei
+ ld temp,z ;don't forget to get the char
+ pop zl
+ pop zh
+ ret
+
+;Sends a char from temp to the soft uart.
+
+uartputc:
+ push zh
+ push zl
+ in zl,sreg
+ push zl
+ push temp
+sputc_l:
+ lds temp,txcount ;do {
+ cpi temp,TXBUFSIZE ;
+ brsh sputc_l ;} while (txcount >= TXBUFSIZE)
+
+ ldi zl,low(txfifo) ;
+ ldi zh,high(txfifo) ;
+ lds temp,txidx_w ;
+ add zl,temp ;
+ brcc PC+2 ;
+ inc zh ;
+ inc temp ;
+ andi temp,TXBUFMASK ;
+ sts txidx_w,temp ; txidx_w = ++txidx_w % TXBUFSIZE
+ pop temp ;
+ st z,temp ; txfifo[txidx_w] = char
+ cli
+ lds zh,txcount
+ inc zh
+ sts txcount,zh
+ dec zh
+ brne sputc_e
+; Enable transmitter
+ inm8 zh,TIMSK1
+ ori zh,(1<<OCIE1A)
+ outm8 TIMSK1,zh
+sputc_e:
+ pop zl
+ out sreg,zl
+ pop zl
+ pop zh
+ ret
+
+
+; Wait, till tx buffer is empty.
+
+uart_wait_empty:
+ push temp
+uwe_loop:
+ lds temp,txcount
+ tst temp
+ brne uwe_loop
+ pop temp
+ ret
+
+
+; vim:set ts=8 noet nowrap
+
-; Z80 emulator with CP/M support. The Z80-specific instructions themselves actually aren't
-; implemented yet, making this more of an i8080 emulator.
-;
+; Z80 Interpreter.
+; This is part of the Z80-CP/M emulator written by Sprite_tm.
+; The Z80-specific instructions themselves actually aren't
+; implemented yet, making this more of an i8080 emulator.
+
; Copyright (C) 2010 Sprite_tm
+; Copyright (C) 2010 Leo C.
+
+; This file is part of avrcpm.
;
-; This program is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
+; avrcpm is free software: you can redistribute it and/or modify it
+; under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
-; This program is distributed in the hope that it will be useful,
+; avrcpm is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
-; along with this program. If not, see <http://www.gnu.org/licenses/>.
+; along with avrcpm. If not, see <http://www.gnu.org/licenses/>.
;
; $Id$
;
-;.nolist
-#if defined atmega8
- .include "m8def.inc"
-#elif defined atmega168
- .include "m168def.inc"
-#elif defined atmega328P
- .include "m328Pdef.inc"
-#else /* default */
- .include "m88def.inc"
- ;FUSE_H=0xDF
- ;FUSE_L=0xF7
-#endif
-.list
-.listmac
-
-
-
-#ifndef F_CPU
- #define F_CPU 20000000 /* system clock in Hz; defaults to 20MHz */
-#endif
-#ifndef BAUD
- #define BAUD 38400 /* console baud rate */
-#endif
-
-#define PARTID 0x52 /* Partition table id */
- /* http://www.win.tue.nl/~aeb/partitions/partition_types-1.html */
-#define RAMDISKNR 'I'-'A' /* Driveletter for first RAM disk */
-#define RAMDISKCNT 1 /* Number of RAM disks */
-
-#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1) /* clever rounding */
-
-#define RXBUFSIZE 64 /* USART recieve buffer size. Must be power of 2 */
-#define TXBUFSIZE 64 /* USART transmit buffer size. Must be power of 2 */
-
-#define DRAM_WAITSTATES 1 /* Number of additional clock cycles for dram read access */
-#define REFR_RATE 64000 /* dram refresh rate in cycles/s. */
- /* Most drams need 1/15.6µs. */
-#define REFR_PRE 8 /* timer prescale factor */
-#define REFR_CS 0x02 /* timer clock select for 1/8 */
-#define REFR_CNT F_CPU / REFR_RATE / REFR_PRE
-
-
-
-#define DRAM_WORD_ACCESS 0 /* experimental */
-
-#define EM_Z80 0 /* we don't have any z80 instructions yet */
-
-.equ MMC_DEBUG = 0
-.equ INS_DEBUG = 0
-.equ MEMTEST = 1
-.equ BOOTWAIT = 1
-.equ PORT_DEBUG = 0
-.equ DISK_DEBUG = 0 /* Increase for more debugging */
-.equ HOSTRW_DEBUG= 0
-.equ MEMFILL_CB = 1
-.equ STACK_DBG = 0
-.equ PRINT_PC = 0
-
-;Port declarations
-
-; Port D
-.equ rxd = 0
-.equ txd = 1
-.equ ram_oe = 2
-.equ ram_a8 = 3
-.equ mmc_cs = 4
-.equ ram_a5 = 5
-.equ ram_a6 = 6
-.equ ram_a7 = 7
-
-.equ P_OE = PORTD
-.equ P_AH = PORTD
-.equ P_A8 = PORTD
-.equ P_MMC_CS = PORTD
- ; ram_a[7..5]
-.equ RAM_AH_MASK = (1<<ram_a8)|(1<<ram_a7)|(1<<ram_a6)|(1<<ram_a5)
-.equ PD_OUTPUT_MASK = (1<<mmc_cs) | (1<<ram_oe) | RAM_AH_MASK
-
-
-;Port B
-.equ ram_a4 = 0
-.equ ram_a3 = 1
-.equ ram_a2 = 2
-.equ ram_a1 = 3
-.equ mmc_mosi = 3
-.equ ram_a0 = 4
-.equ mmc_miso = 4
-.equ ram_ras = 5
-.equ mmc_sck = 5
-
-
-.equ P_RAS = PORTB
-.equ P_AL = PORTB
- ; ram_a[4..0]
-.equ RAM_AL_MASK = (1<<ram_a4)|(1<<ram_a3)|(1<<ram_a2)|(1<<ram_a1)|(1<<ram_a0)
-.equ PB_OUTPUT_MASK = (1<<ram_ras) | RAM_AL_MASK
-
-;Port C
-.equ ram_d0 = 0
-.equ ram_d1 = 1
-.equ ram_d2 = 2
-.equ ram_d3 = 3
-.equ ram_w = 4
-.equ ram_cas= 5
-
-.equ P_DQ = PORTC
-.equ P_W = PORTC
-.equ P_CAS = PORTC
-.equ RAM_DQ_MASK = (1<<ram_d3)|(1<<ram_d2)|(1<<ram_d1)|(1<<ram_d0)
-.equ PC_OUTPUT_MASK = (1<<ram_cas)|(1<<ram_w)
-
-
-;Flag bits in z_flags
-.equ ZFL_S = 7
-.equ ZFL_Z = 6
-.equ ZFL_H = 4
-.equ ZFL_P = 2
-.equ ZFL_N = 1
-.equ ZFL_C = 0
-
-;Register definitions
-
-.def _tmp = r0 ; 0
-.def _0 = r1
-
-.def z_c = r4
-.def z_b = r5
-.def z_e = r6
-.def z_d = r7
-.def z_l = r8
-.def z_h = r9
-.def z_a = r10
-
-.def insdecl = r12 ;
-.def insdech = r13 ;
-.def z_spl = r14
-.def z_sph = r15 ;
-.def temp = r16 ;
-.def temp2 = r17 ;
-.def temp3 = r18
-.def temp4 = r19
-.def z_flags = r20 ;
- ;
-.def opl = r22 ;
-.def oph = r23 ;
-.def z_pcl = r24 ;
-.def z_pch = r25 ;
-; xl ;r26
-; xh ;r27
-; yl ;r28
-; yh ;r29
-; zl ;r30 ;
-; zh ;r31 ;
-
-
-
-#if defined __ATmega8__
-.equ flags = TWBR
-.equ P_PUD = SFIOR
-#else
-.equ flags = GPIOR0
-.equ P_PUD = MCUCR
-#endif
-
-; Flags:
- .equ hostact = 7 ;host active flag
- .equ hostwrt = 6 ;host written flag
- .equ rsflag = 5 ;read sector flag
- .equ readop = 4 ;1 if read operation
- .equ trace = 0
-
-; This is the base z80 port address for clock access
-#define TIMERPORT 0x40
-#define TIMER_CTL TIMERPORT
-#define TIMER_MSECS TIMERPORT+1
-#define TIMER_SECS TIMER_MSECS+2
-
-#define starttimercmd 1
-#define quitTimerCmd 2
-#define printTimerCmd 15
-#define uptimeCmd 16
-
-#if defined __ATmega8__
-.equ RXTXDR0 = UDR
-.equ UCSR0A = UCSRA
-.equ UDRE0 = UDRE
-.equ UCSR0B = UCSRB
-.equ RXCIE0 = RXCIE
-.equ UDRIE0 = UDRIE
-.equ RXEN0 = RXEN
-.equ TXEN0 = TXEN
-.equ UCSR0C = UCSRC
-.equ UCSZ00 = UCSZ0
-.equ UCSZ01 = UCSZ1
-.equ UBRR0H = UBRRH
-.equ UBRR0L = UBRRL
-.equ OCR2A = OCR2
-.equ OC2Aaddr= OC2addr
-.equ TCCR2A = TCCR2
-.equ TCCR2B = TCCR2
-.equ TIMSK1 = TIMSK
-.equ TIMSK2 = TIMSK
-.equ OCIE2A = OCIE2
-.equ TIFR1 = TIFR
-.equ ICIE1 = TICIE1
-#else
-.equ RXTXDR0 = UDR0
-#endif
-
-
-;----------------------------------------
-;
-.macro outm8
-.if @0 > 0x3f
- sts @0,@1
-.else
- out @0,@1
-.endif
-.endm
-
-;----------------------------------------
-;
-.macro inm8
-.if @1 > 0x3f
- lds @0,@1
-.else
- in @0,@1
-.endif
-.endm
-
-
-
-; -------------------- DRAM ---------------
-
-; DRAM_SETADDR val, low_and_mask, low_or_mask, high_and_mask, high_or_mask
-.macro DRAM_SETADDR
- mov temp,@0
-.if low(@1) != 0xff
- andi temp,@1
-.endif
-.if low(@2) != 0
- ori temp, @2
-.endif
- out P_AL,temp
-
- mov temp,@0
-.if low(@3) != 0xff
- andi temp,@3
-.endif
- ori temp, @4 | (1<<mmc_cs)
- out P_AH,temp
-.endm
-
-;----------------------------------------
-; add wait states
-; dram_wait number_of_cycles
-
-.macro dram_wait
-.if @0 > 1
- rjmp PC+1
- dram_wait @0 - 2
-.elif @0 > 0
- nop
- dram_wait @0 - 1
-.endif
-.endm
-
-
-.cseg
-.org 0
- rjmp start ; reset vector
-.org OC2Aaddr
- rjmp refrint ; tim2cmpa
-.org OC1Aaddr ; Timer/Counter1 Compare Match A
- rjmp sysclockint ; 1ms system timer
-.org URXCaddr
- rjmp rxint ; USART receive int.
-.org UDREaddr
- rjmp txint ; USART transmit int.
-
-.org INT_VECTORS_SIZE
-
-start:
- ldi temp,low(RAMEND) ; top of memory
- out SPL,temp ; init stack pointer
- ldi temp,high(RAMEND) ; top of memory
- out SPH,temp ; init stack pointer
-
- clr _0
-
-; - Kill wdt
- wdr
- out MCUSR,_0
-
- ldi temp,(1<<WDCE) | (1<<WDE)
- outm8 WDTCSR,temp
- ldi temp,(1<<WDCE)
- outm8 WDTCSR,temp
-
-; - Clear RAM
-
- ldi zl,low(SRAM_START)
- ldi zh,high(SRAM_START)
- ldi temp2,high(ramtop)
-clr_l:
- st z+,_0
- cpi zl,low(ramtop)
- cpc zh,temp2
- brne clr_l
-
-; - Setup Ports
- ldi temp,(1<<PUD) ;disable pullups
- outm8 P_PUD,temp
- ldi temp,0xFF
- out PORTD,temp ;all pins high
- out PORTB,temp
- out PORTC,temp
- out DDRD,temp ; all outputs
- out DDRB,temp
- out DDRC,temp
-
- outm8 TIMSK1,_0
- outm8 TIMSK2,_0
- outm8 TCCR2A,_0
- outm8 TCCR2B,_0
-
-
-; - Init serial port
-
- ldi temp, (1<<TXEN0) | (1<<RXEN0) | (1<<RXCIE0)
- outm8 UCSR0B,temp
-.ifdef URSEL
- ldi temp, (1<<URSEL) | (1<<UCSZ01) | (1<<UCSZ00)
-.else
- ldi temp, (1<<UCSZ01) | (1<<UCSZ00)
-.endif
- outm8 UCSR0C,temp
- ldi temp, HIGH(UBRR_VAL)
- outm8 UBRR0H,temp
- ldi temp, LOW(UBRR_VAL)
- outm8 UBRR0L,temp
-
-; Init clock/timer system
-
-; Init timer 1 as 1 ms system clock tick.
-
- ldi temp,high(F_CPU/1000)
- outm8 OCR1AH,temp
- ldi temp,low(F_CPU/1000)
- outm8 OCR1AL,temp
- ldi temp,(1<<WGM12) | (1<<CS10) ;CTC, clk/1
- outm8 TCCR1B,temp
- inm8 temp,TIMSK1
- ori temp,(1<<OCIE1A)
- outm8 TIMSK1,temp
-
-;Init timer2. Refresh-call should happen every (8ms/512)=312 cycles.
-
- ldi temp,REFR_CNT*2 ; 2 cycles per int
- outm8 OCR2A,temp
- inm8 temp,TCCR2A
- ori temp,(1<<WGM21) ;CTC mode
- outm8 TCCR2A,temp
- inm8 temp,TCCR2B
- ori temp,REFR_CS ;clk/REFR_PRE
- outm8 TCCR2B,temp
- inm8 temp,TIMSK2
- ori temp, (1<<OCIE2A)
- outm8 TIMSK2,temp
-
- sei
-
-
-.if BOOTWAIT
- ldi temp,10
- rcall delay_ms
-
-.endif
-
- rcall printstr
- .db 13,"CPM on an AVR, v1.0",13,0
-
-
-.if MEMTEST
- rcall printstr
- .db 13,"Testing RAM: fill...",0
-
-;Fill RAM
- ldi xl,0
- ldi xh,0
-ramtestw:
- mov temp,xh
- eor temp,xl
- rcall memwritebyte
- adiw xl,1
- brcc ramtestw
- rcall printstr
- .db "wait...",0
-
- ldi temp2,8
-ramtestwl:
- ldi temp,255
- rcall delay_ms
- dec temp2
- brne ramtestwl
-
- rcall printstr
- .db "reread...",13,0,0
-
-;re-read RAM
- ldi xl,0
- ldi xh,0
-ramtestr:
- rcall memReadByte
- mov temp2,xh
- eor temp2,xl
- cp temp,temp2
- breq ramtestrok
- rcall printhex
- ldi temp,'<'
- rcall uartPutc
- mov temp,xh
- eor temp,xl
- rcall printhex
- ldi temp,'@'
- rcall uartPutc
- movw temp,x
- rcall printhexw
- ldi temp,13
- rcall uartPutc
-ramtestrok:
- adiw xl,1
- brcc ramtestr
-
-.endif
-
-.if MEMFILL_CB
- ;Fill ram with cbs, which (for now) will trigger an invalid opcode error.
- ldi xl,0
- ldi xh,0
-ramfillw:
- ldi temp,0xcb
- rcall memwritebyte
- adiw xl,1
- brcc ramfillw
-.endif
-
-
-;----------------------------------------------------------------------------
-
-boot_again:
- rcall printstr
- .db 13,"Initing mmc...",0
- rcall dsk_partinit
- rcall printstr
- .db 13,"Partinit done.",0
-
- lds temp,ndisks
- tst temp
- brne boot_ipl2
- rcall printstr
- .db "No bootable CP/M disk found! Please change MMC/SD-Card",13,0
- ldi temp2,18
-boot_iplwl:
- ldi temp,255
- rcall delay_ms
- dec temp2
- brne boot_iplwl
- rjmp boot_again
-
-
-boot_ipl2:
-
-; Read first sector of first CP/M partition
-
- lds xl,hostparttbl
- lds xh,hostparttbl+1
- lds yl,hostparttbl+2
- lds yh,hostparttbl+3
- rcall mmcReadSect
-
- rcall dsk_cboot ;init (de)blocking buffer
-
-;First sector of disk or first CP/M partition is in hostbuf.
+ .dseg
-;Save to Z80 RAM (only 128 bytes because that's retro)
- ldi zl,low(hostbuf)
- ldi zh,high(hostbuf)
- ldi xh,0x20
- ldi xl,0x00
-iplwriteloop:
- ld temp,z+
- rcall memWriteByte
- adiw xl,1
- cpi zl,low(hostbuf+128)
- brne iplwriteloop
- cpi zh,high(hostbuf+128)
- brne iplwriteloop
+z_b: .byte 1
+z_c: .byte 1
+z_d: .byte 1
+z_e: .byte 1
+z_h: .byte 1
+z_l: .byte 1
+ .cseg
;Init z80
- ldi temp,0x00
- mov z_pcl,temp
- ldi temp,0x20
- mov z_pch,temp
+z80_init:
+ ldi z_pcl,low (IPLADDR)
+ ldi z_pch,high(IPLADDR)
cbi flags,trace
- rcall printstr
- .db 13,"Ok, CPU is live!",13,0,0
+ printnewline
+ printstring "Ok, CPU is live!"
+ printnewline
main:
+.if INS_DEBUG
cbi flags,trace
- cpi z_pch,1
+ cpi z_pch,DBG_TRACE_BOTTOM
brlo notraceon
- cpi z_pch,$dc
+ cpi z_pch,DBG_TRACE_TOP
brsh notraceon
sbi flags,trace
notraceon:
+.endif
.if PRINT_PC
- cpi z_pch,1
+ cpi z_pch,DBG_TRACE_BOTTOM
brlo noprintpc
- cpi z_pch,0xdc
+ cpi z_pch,DBG_TRACE_TOP
brsh noprintpc
- rcall printstr
- .db 13,"PC=",0
+ printnewline
+ printstring "PC="
movw temp,z_pcl
rcall printhexw
- ldi temp,' '
-; ldi temp,10
-; rcall uartputc
+ printstring " "
noprintpc:
.endif
; *** Stage 1: Fetch next opcode
- movw xl,z_pcl
- rcall memReadByte
+ mem_read_s z_pc
.if INS_DEBUG
sbis flags,trace
rjmp notrace1
- rcall printstr
- .db "PC=",0
+ printnewline
+ printstring "PC="
push temp
movw temp,z_pcl
rcall printhexw
pop temp
- rcall printstr
- .db ", opcode=",0
+ printstring ", opcode="
rcall printhex
notrace1:
.endif
.if INS_DEBUG
sbis flags,trace
rjmp notrace2
- rcall printstr
- .db ", decoded=",0,0
- movw temp,insdecl
- rcall printhexw
- rcall printstr
- .db ".",13,0,0
+ printstring ", decoded="
+ movw temp,insdecl
+ rcall printhexw
notrace2:
.endif
.if INS_DEBUG
sbis flags,trace
rjmp notrace3
- rcall printstr
- .db "pre: oph:l=",0
- mov tempw,opl
- rcall printhexw
- rcall printstr
- .db " -- ",0,0
+ printstring " pre: op="
+ movw temp,opl
+ rcall printhexw
notrace3:
+ rjmp nonofetch
.endif
nofetch:
+.if INS_DEBUG
+ sbis flags,trace
+ rjmp nonofetch
+ printstring " "
+
+nonofetch:
+.endif
; *** Stage 4: Execute operation :) Use the op jumptable for this.
mov temp,insdech
andi temp,0xFC
.if INS_DEBUG
sbis flags,trace
rjmp notrace4
- rcall printstr
- .db ",post:oph:l=",0,0
- movw temp,opl
- rcall printhexw
+ printstring " post: op="
+ movw temp,opl
+ rcall printhexw
notrace4:
+ rjmp nonooper
.endif
nooper:
+.if INS_DEBUG
+ sbis flags,trace
+ rjmp nonooper
+ printstring " "
+
+nonooper:
+.endif
; *** Stage 5: Store operand. Use the store jumptable for this.
swap insdecl
swap insdech
.if INS_DEBUG
sbis flags,trace
rjmp notrace5
- rcall printstr
- .db ", stored.",0
+ printstring " stored "
notrace5:
.endif
nostore:
-
-.if INS_DEBUG
- sbis flags,trace
- rjmp notrace6
- rcall printstr
- .db 13,0
-notrace6:
-.endif
-
;All done. Neeeext!
rjmp main
-
-
-
-; ----------------Virtual peripherial interface ------
-
-;The hw is modelled to make writing a CPM BIOS easier.
-;Ports:
-;0 - Con status. Returns 0xFF if the UART has a byte, 0 otherwise.
-;1 - Console input, aka UDR.
-;2 - Console output
-;15 - Disk select
-;16,17 - Track select
-;18 - Sector select
-;20 - Write addr l
-;21 - Write addr h
-;22 - Trigger - write to read, to write a sector using the above info;
-; , write to allocated/dirctory/unallocated
-
- .equ READ_FUNC = 7
- .equ WRITE_FUNC = 6
- .equ BOOT_FUNC = 5
- .equ HOME_FUNC = 4
-
-
-
-;*****************************************************
-;* CP/M to host disk constants *
-;*****************************************************
- .equ MAXDISKS = 4 ;Max number of Disks (partitions)
- .equ blksize = 1024 ;CP/M allocation size
- .equ hostsize = 512 ;host disk sector size
-; .equ hostspt = 20 ;host disk sectors/trk
- .equ hostblk = hostsize/128 ;CP/M sects/host buff
-; .equ CPMSPT = hostblk*hostspt;CP/M sectors/track
- .equ CPMSPT = 26 ;
- .equ SECMSK = hostblk-1 ;sector mask
- .equ SECSHF = log2(hostblk) ;sector shift
-
-;*****************************************************
-;* BDOS constants on entry to write *
-;*****************************************************
- .equ WRALL = 0 ;write to allocated
- .equ WRDIR = 1 ;write to directory
- .equ WRUAL = 2 ;write to unallocated
- .equ WRTMSK= 3 ;write type mask
-
-
- .dseg
-ndisks: .byte 1 ;Number of CP/M disks
-
-seekdsk: .byte 1 ;seek disk number
-seektrk: .byte 2 ;seek track number
-seeksec: .byte 1 ;seek sector number
-
-hostparttbl: .byte 8*MAXDISKS ; host partition table (start sector, sector count)
-hostdsk: .byte 1 ;host disk number
-hostlba: .byte 3 ;host sector number (relative to partition start)
-
-unacnt: .byte 1 ;unalloc rec cnt
-unadsk: .byte 1 ;last unalloc disk
-unatrk: .byte 2 ;last unalloc track
-unasec: .byte 1 ;last unalloc sector
-
-erflag: .byte 1 ;error reporting
-wrtype: .byte 1 ;write operation type
-dmaadr: .byte 2 ;last dma address
-hostbuf: .byte hostsize;host buffer (from/to SD-card)
-
-
- .cseg
-
-conStatus:
-
- lds temp,rxcount
- tst temp
- breq PC+2
- ldi temp,0xff
- ret
-
-conInp:
- rjmp uartGetc
-
-dbgOut:
- rcall printstr
- .db "Debug: ",0
- rcall printhex
- rcall printstr
- .db 13,0
- ret
-
-conOut:
- rjmp uartputc
-
-
-;Called with port in temp2. Should return value in temp.
-portRead:
- cpi temp2,0
- breq conStatus
- cpi temp2,1
- breq conInp
-
- cpi temp2,15
- breq dskDiskCheck
- cpi temp2,22
- breq dskErrorRet
-
- cpi temp2,TIMER_MSECS
- brlo pr_noclock
- cpi temp2,TIMER_MSECS+6
- brsh pr_noclock
- rjmp clockget
-
-pr_noclock:
- ldi temp,0xFF
- ret
-
-;Called with port in temp2 and value in temp.
-portWrite:
- cpi temp2,0
- breq dbgOut
- cpi temp2,2
- breq conOut
-
- cpi temp2,15
- breq dskDiskSel
- cpi temp2,16
- breq dskTrackSel_l
- cpi temp2,17
- breq dskTrackSel_h
- cpi temp2,18
- breq dskSecSel
- cpi temp2,20
- breq dskDmaL
- cpi temp2,21
- breq dskDmaH
-
- cpi temp2,22
- breq dskDoIt
-
- cpi temp2,TIMERPORT
- brlo pw_noclock
- cpi temp2,TIMER_MSECS+6
- brsh pw_noclock
- rjmp clockput
-
-pw_noclock:
- ret
-
-
-dskDiskCheck:
- lds temp,seekdsk
- cpi temp,RAMDISKNR
- brsh dsk_dchrd ;maybe ramdisk
-
- lds temp2,ndisks ;check if selected disk # is less then # of disks
- tst temp2
- brne dsk_dchpart1
-
-; Need to init
-
- rcall dsk_partinit
- lds temp2,ndisks
- lds temp,seekdsk
-
-dsk_dchpart1:
- cp temp,temp2
- brsh dsk_dcher
-
-dsk_dchend:
- ldi temp,0
- ret
-
-dsk_dchrd:
- cpi temp,RAMDISKNR+RAMDISKCNT
- brlo dsk_dchend
-dsk_dcher:
- ldi temp,0xff ;error return
- ret
-
-
-
-
-dskErrorRet:
- lds temp,erflag
- ret
-
-dskDiskSel:
- sts seekdsk,temp
- ret
-
-dskTrackSel_l:
- sts seektrk,temp
- sts seektrk+1,_0
- ret
-
-dskTrackSel_h:
- sts seektrk+1,temp
- ret
-
-dskSecSel:
- sts seeksec,temp
- ret
-
-dskDmal:
- sts dmaadr,temp
- ret
-
-dskDmah:
- sts dmaadr+1,temp
- ret
-
-dskDoIt:
-.if DISK_DEBUG
- push temp
- sbrc temp,READ_FUNC
- rjmp dskdbgr
- sbrc temp,WRITE_FUNC
- rjmp dskdbgw
- rjmp dskdbge
-
-dskdbgr:
- rcall printstr
- .db 13,"Disk read: ",0
- rjmp dskdbg1
-dskdbgw:
- rcall printstr
- .db 13,"Disk write: ",0
-dskdbg1:
- lds temp,seekdsk
- subi temp,-('A')
- rcall uartputc
- rcall printstr
- .db ": track ",0,0
- lds temp2,seektrk+1
- lds temp,seektrk
- rcall printhexw
- rcall printstr
- .db ", sector ",0
- lds temp,seeksec
- rcall printhex
- rcall printstr
- .db ", dma-addr ",0
- lds temp2,dmaadr+1
- lds temp,dmaadr
- rcall printhexw
- pop temp
- push temp
- sbrs temp,WRITE_FUNC
- rjmp dskdbge
- rcall printstr
- .db " wrtype ",0,0
- andi temp,3
- rcall printhex
-dskdbge:
- pop temp
-.endif
- ;See what has to be done.
- sbrc temp,READ_FUNC
- rjmp dsk_read
- sbrc temp,WRITE_FUNC
- rjmp dsk_write
- sbrc temp,HOME_FUNC
- rjmp dsk_home
- sbrc temp,BOOT_FUNC
- rjmp dsk_boot
-
- rcall printstr
- .db "DISK I/O: Invalid Function code: ",0
- rcall printhex
- rjmp haltinv
-
-dsk_boot:
- sts ndisks,_0 ;no active partitions
-dsk_cboot:
- cbi flags,hostact ;host buffer inactive
- sts unacnt,_0 ;clear unalloc count
- ret
-
-dsk_home:
- sbis flags,hostwrt ;check for pending write
- cbi flags,hostact ;clear host active flag
- ret
-
-
-dsk_read:
-
- sbi flags,readop ;read operation
- ;RAM disk?
- lds temp2,seekdsk
- cpi temp2,RAMDISKNR
- brlt PC+2
- rjmp rdskDoIt
-
- sts unacnt,_0
- sbi flags,rsflag ;must read data
- ldi temp,WRUAL ;write type
- sts wrtype,temp ;treat as unalloc
- rjmp dsk_rwoper ;to perform the read
-
-
-dsk_write:
- ;write the selected CP/M sector
-
- cbi flags,readop ;not a read operation
-
- ;RAM disk?
- lds temp2,seekdsk
- cpi temp2,RAMDISKNR
- brlt PC+2
- rjmp rdskDoIt
- andi temp,WRTMSK
- sts wrtype,temp ;save write type
-
- cpi temp,WRUAL ;write unallocated?
- brne dsk_chkuna ;check for unalloc
-
-; write to unallocated, set parameters
- ldi temp,blksize/128 ;next unalloc recs
- sts unacnt,temp
- lds temp,seekdsk ;disk to seek
- sts unadsk,temp ;unadsk = sekdsk
- lds temp,seektrk
- sts unatrk,temp ;unatrk = sectrk
- lds temp,seektrk+1
- sts unatrk+1,temp ;unatrk = sectrk
- lds temp,seeksec
- sts unasec,temp ;unasec = seksec
-;
-dsk_chkuna:
- ;check for write to unallocated sector
- lds temp,unacnt ;any unalloc remain?
- tst temp
- breq dsk_alloc ;skip if not
-
-; more unallocated records remain
- dec temp ;unacnt = unacnt-1
- sts unacnt,temp
- lds temp,seekdsk ;same disk?
- lds temp2,unadsk
- cp temp,temp2 ;seekdsk = unadsk?
- brne dsk_alloc ;skip if not
-
-; disks are the same
- lds temp,unatrk
- lds temp2,unatrk+1
- lds temp3,seektrk
- lds temp4,seektrk+1
- cp temp,temp3 ;seektrk = unatrk?
- cpc temp2,temp4
- brne dsk_alloc ;skip if not
-
-; tracks are the same
- lds temp,seeksec ;same sector?
- lds temp2,unasec
- cp temp,temp2 ;seeksec = unasec?
- brne dsk_alloc ;skip if not
-
-; match, move to next sector for future ref
- inc temp2 ;unasec = unasec+1
- sts unasec,temp2
- cpi temp2,CPMSPT ;end of track? (count CP/M sectors)
- brlo dsk_noovf ;skip if no overflow
-
-; overflow to next track
- sts unasec,_0 ;unasec = 0
- lds temp,unatrk
- lds temp2,unatrk+1
- subi temp, low(-1) ;unatrk = unatrk+1
- sbci temp2,high(-1)
- sts unatrk,temp
- sts unatrk+1,temp2
-;
-dsk_noovf:
- cbi flags,rsflag ;rsflag = 0
- rjmp dsk_rwoper ;to perform the write
-;
-dsk_alloc:
- ;not an unallocated record, requires pre-read
- sts unacnt,_0 ;unacnt = 0
- sbi flags,rsflag ;rsflag = 1
-
-;*****************************************************
-;* Common code for READ and WRITE follows *
-;*****************************************************
-
-dsk_rwoper:
- ;enter here to perform the read/write
-.if DISK_DEBUG
- rcall printstr
- .db ", flags: ",0
- in temp,flags
- rcall printhex
-.endif
- sts erflag,_0 ;no errors (yet)
-
- ;Convert track/sector to an LBA address (in 128byte blocks)
-
- lds xl,seeksec ;
- ldi xh,0 ;
- ldi yl,0 ;
- lds temp3,seektrk ;
- lds temp4,seektrk+1 ;
- ldi temp,CPMSPT ;
- mul temp3,temp ;
- add xl,r0 ;
- adc xh,r1 ;
- mul temp4,temp ;
- add xh,r0 ;yl:xh:xl := sec + trk * SectorsPerTrack
- adc yl,r1 ;
- clr _0
-
- mov temp,xl
- andi temp,SECMSK ;mask buffer number
- push temp ;save for later
-
- ;Convert from CP/M LBA blocks to host LBA blocks
- ldi temp,SECSHF
-dsk_sh1:
- lsr yl
- ror xh
- ror xl
- dec temp
- brne dsk_sh1
- ;yl:xh:xl = host block to seek
-; active host sector?
- in _tmp,flags ;host active flag
- sbi flags,hostact ;always becomes 1
- sbrs _tmp,hostact ;was it already?
- rjmp dsk_filhst ;fill host if not
-
-; host buffer active, same as seek buffer?
- lds temp,seekdsk
- lds temp2,hostdsk ;same disk?
- cp temp,temp2 ;seekdsk = hostdsk?
- brne dsk_nomatch
-
-; same disk, same block?
- lds temp,hostlba
- lds temp2,hostlba+1
- lds temp3,hostlba+2
- cp xl,temp
- cpc xh,temp2
- cpc yl,temp3
- breq dsk_match
-;
-dsk_nomatch:
- ;proper disk, but not correct sector
- sbis flags,hostwrt ;host written?
- rjmp dsk_filhst
- push xl
- push xh
- push yl
- rcall dsk_writehost ;clear host buff
- pop yl
- pop xh
- pop xl
-
-dsk_filhst:
- ;may have to fill the host buffer
- lds temp,seekdsk
- sts hostdsk,temp
- sts hostlba,xl
- sts hostlba+1,xh
- sts hostlba+2,yl
-
- sbic flags,rsflag ;need to read?
- rcall dsk_readhost ;yes, if 1
- cbi flags,hostwrt ;no pending write
-
-dsk_match:
-
- ;copy data to or from buffer
- ldi zl,low(hostbuf)
- ldi zh,high(hostbuf)
- ldi temp,128
- pop temp2 ;get buffer number (which part of hostbuf)
- mul temp2,temp
- add zl,r0 ;offset in hostbuf
- adc zh,r1
-.if DISK_DEBUG > 2
- push r0
- push r1
- clr _0
- rcall printstr
- .db "; host buf adr: ",0,0
- pop temp2
- pop temp
- rcall printhexw
-.endif
- clr _0
-
- lds xl,dmaadr
- lds xh,dmaadr+1
- ldi temp3,128 ;length of move
- sbic flags,readop ;which way?
- rjmp dsk_rmove ;skip if read
-
-; mark write operation
- sbi flags,hostwrt ;hostwrt = 1
-dsk_wmove:
- rcall memReadByte
- st z+,temp
- adiw xl,1
- dec temp3
- brne dsk_wmove
- rjmp dsk_rwmfin
-
-dsk_rmove:
- ld temp,z+
- rcall memWriteByte
- adiw xl,1
- dec temp3
- brne dsk_rmove
-dsk_rwmfin:
-; data has been moved to/from host buffer
- lds temp,wrtype ;write type
- cpi temp,WRDIR ;to directory?
- breq dsk_wdir
- ret ;no further processing
-dsk_wdir:
-; clear host buffer for directory write
- lds temp,erflag
- tst temp ;errors?
- breq dsk_wdir1
- ret ;skip if so
-dsk_wdir1:
- rcall dsk_writehost ;clear host buff
- cbi flags,hostwrt ;buffer written
- ret
-
-;*****************************************************
-
-; hostdsk = host disk #, (partition #)
-; hostlba = host block #, relative to partition start
-; Read/Write "hostsize" bytes to/from hostbuf
-
-
-dsk_hostparam:
- ldi zl,low(hostparttbl)
- ldi zh,high(hostparttbl)
- lds temp,hostdsk
-.if HOSTRW_DEBUG
- push temp
- subi temp,-('A')
- rcall uartputc
- rcall printstr
- .db ": ",0,0
- pop temp
-.endif
-
- lsl temp
- lsl temp
- lsl temp
- add zl,temp
- adc zh,_0
-
- lds temp,hostlba
- lds temp2,hostlba+1
- lds temp3,hostlba+2
-
-.if HOSTRW_DEBUG
- rcall printstr
- .db "lba: ",0
- clr temp4
- rcall print_ultoa
-.endif
-
- ldd xl,z+4
- ldd xh,z+5
- ldd yl,z+6
-
- cp temp,xl
- cpc temp2,xh
- cpc temp3,yl
- brcs dsk_hp1
-
-.if HOSTRW_DEBUG
- rcall printstr
- .db ", max: ",0
- push temp4
- push temp3
- push temp2
- push temp
- movw temp,x
- mov temp3,yl
- clr temp4
- rcall print_ultoa
- pop temp
- pop temp2
- pop temp3
- pop temp4
- rcall printstr
- .db " ",0
-.endif
-
- clr temp
- ret
-
-dsk_hp1:
- ldd xl,z+0
- ldd xh,z+1
- ldd yl,z+2
- ldd yh,z+3
-
- add xl,temp
- adc xh,temp2
- adc zl,temp3
- adc zh,_0
-.if HOSTRW_DEBUG
- rcall printstr
- .db ", abs:",0,0
- push temp4
- push temp3
- push temp2
- push temp
- movw temp,x
- movw temp3,y
- rcall print_ultoa
- pop temp
- pop temp2
- pop temp3
- pop temp4
- rcall printstr
- .db " ",0
-.endif
- ori temp,255
-dsk_hpex:
- ret
-
-;*****************************************************
-;* WRITEhost performs the physical write to *
-;* the host disk, READhost reads the physical *
-;* disk. *
-;*****************************************************
-
-dsk_writehost:
-.if HOSTRW_DEBUG
- rcall printstr
- .db 13,"host write ",0,0
-.endif
- rcall dsk_hostparam
- brne dsk_wr1
- ldi temp,255
- sts erflag,temp
- ret
-
-dsk_wr1:
- rcall mmcWriteSect
- sts erflag,_0
- ret
-
-dsk_readhost:
-.if HOSTRW_DEBUG
- rcall printstr
- .db 13,"host read ",0,0
-.endif
- rcall dsk_hostparam
- brne dsk_rd1
- ldi temp,255
- sts erflag,temp
- ret
-
-dsk_rd1:
- rcall mmcReadSect
- sts erflag,_0
- ret
-
-
-;***************************************************************************
-; ----------------- RAM disk -----------------
-
- .dseg
-rdskbuf:
- .byte 128
-
- .cseg
-;----------------------------------------------
-
-rdsk_adr:
- ldi xl,0
- lds xh,seeksec
- lds temp2,seektrk
-
- lsr xh
- ror xl ;Col 0..7
-
- mov temp,temp2
- andi temp,0x0f
- swap temp
- or xh,temp ;Row 0..7
-
- ldi zl,low (rdskbuf)
- ldi zh,high(rdskbuf)
- ldi temp3,128
- DRAM_SETADDR xh, ~0,(1<<ram_ras), ~0,(1<<ram_a8)|(1<<ram_oe)
- cbi P_RAS,ram_ras
-
-.if DISK_DEBUG > 1
- mov temp,xh
- rcall printhex
- rcall printstr
- .db " ",0
- mov temp,xl
- rcall printhex
- rcall printstr
- .db " ",0
-.endif
- ret
-
-;----------------------------------------------
-
-rdskDoIt:
- sts erflag,_0
- sbis flags,readop
- rjmp rdsk_wr
-
-.if DISK_DEBUG > 1
- rcall printstr
- .db 13,"rd-adr: ",0
-.endif
- rcall rdsk_adr
-rdsk_rdl:
- DRAM_SETADDR xl, ~(1<<ram_ras),0, ~((1<<ram_oe)), (1<<ram_a8)
- cbi P_CAS,ram_cas
- cbi P_A8,ram_a8
- inc xl
- dram_wait DRAM_WAITSTATES ;
- in temp,P_DQ-2 ; PIN
- sbi P_CAS,ram_cas
-
- cbi P_CAS,ram_cas
- andi temp,0x0f
- swap temp
- dram_wait DRAM_WAITSTATES ;
- in temp2,P_DQ-2 ; PIN
- andi temp2,0x0f
- or temp,temp2
-
- sbi P_OE,ram_oe
- sbi P_CAS,ram_cas
- dec temp3
- st z+,temp
- brne rdsk_rdl
-
- sbi P_RAS,ram_ras
- ldi zl,low (rdskbuf)
- ldi zh,high(rdskbuf)
- lds xl,dmaadr
- lds xh,dmaadr+1
- ldi temp3,128
-rdsk_rdstl:
- ld temp,z+
- rcall dram_write
- adiw x,1
- dec temp3
- brne rdsk_rdstl
- ret
-
-
-rdsk_wr:
-.if DISK_DEBUG > 1
- rcall printstr
- .db 13,"wr-adr: ",0
-.endif
- lds xl,dmaadr
- lds xh,dmaadr+1
- ldi zl,low (rdskbuf)
- ldi zh,high(rdskbuf)
- ldi temp3,128
-rdsk_wrldl:
- rcall dram_read
- st z+,temp
- adiw x,1
- dec temp3
- brne rdsk_wrldl
-
- ldi temp2,RAM_DQ_MASK | (1<<ram_w) | (1<<ram_cas)
- out DDRC,temp2
- rcall rdsk_adr
-rdsk_wrl:
- ld temp,z+
- mov temp2,temp
- andi temp,RAM_DQ_MASK & ~(1<<ram_w)
- ori temp,(1<<ram_cas)
- out PORTC,temp
- DRAM_SETADDR xl, ~(1<<ram_ras),0, ~((1<<ram_a8)),(1<<ram_oe)
- cbi PORTC,ram_cas
- sbi PORTD,ram_a8
- sbi PORTC,ram_cas
- swap temp2
- andi temp2,RAM_DQ_MASK & ~(1<<ram_w)
- ori temp2,(1<<ram_cas)
- out PORTC,temp2
- cbi PORTC,ram_cas
- inc xl
- sbi PORTC,ram_cas
- dec temp3
- brne rdsk_wrl
-
- sbi P_RAS,ram_ras
- ldi temp,~RAM_DQ_MASK | (1<<ram_w) | (1<<ram_cas)
- out DDRC,temp
- out PORTC,temp
- ret
-
-;---------------------------------------------------------------------
-
-; Partition table offsets:
-#define PART_TYPE 4
-#define PART_START 8
-#define PART_SIZE 12
-
- .dseg
-tmp_tbl:
- .byte 8*MAXDISKS
-
- .cseg
-dsk_partinit:
-
- rcall mmcInit
-
-;Load first sector from MMC (boot sector)
-
- ldi yh,0 ; Sector 0
- ldi yl,0
- movw x,y
- rcall mmcReadSect
-
- ldi yl,low(tmp_tbl)
- ldi yh,high(tmp_tbl)
- ldi temp2,8*MAXDISKS
-dsk_picl:
- st y+,_0
- dec temp2
- brne dsk_picl
- sbiw y,8*MAXDISKS
-#if 0
- rcall printstr
- .db ", ",0,0
- movw temp,y
- rcall printhexw
-#endif
-
-;Test, if it has a valid MBR
-
- ldi zl,low(hostbuf+510-1) ;Point to last byte of partition table
- ldi zh,high(hostbuf+510-1)
-
- ldi temp3,0 ;temp3 holds number of found disks (paritions)
- ldd temp,z+1 ;MBR signature (0xAA55) at and of sector?
- ldd temp2,z+2
- ldi temp4,0xAA
- cpi temp,0x55
- cpc temp2,temp4
- breq dsk_part
-
-;No MBR, no partition table ...
- inc temp3 ;pretend we have one.
- ldi temp,high((1<<16) * 128/512)
- std y+0,_0 ;start at beginning of card
- std y+1,_0
- std y+2,_0
- std y+3,_0
- std y+4,_0 ;max CP/M 2.2 disk size
- std y+5,temp ;
- std y+6,_0
- std y+7,_0
- rjmp dsk_pend
-
-;Search Partition Table for CP/M partitions
-dsk_part:
- sbiw z,63 ;Now at first byte of partition table
- ldi temp4,high(hostbuf+510)
-dsk_ploop:
- ldd temp,z+PART_TYPE
- cpi temp,PARTID
- brne dsk_nextp
-
-; Found a CP/M partition
-
- ldd temp,z+PART_START
- st y+,temp
- ldd temp,z+PART_START+1
- st y+,temp
- ldd temp,z+PART_START+2
- st y+,temp
- ldd temp,z+PART_START+3
- st y+,temp
-
- ldd temp,z+PART_SIZE
- st y+,temp
- ldd temp,z+PART_SIZE+1
- st y+,temp
- ldd temp,z+PART_SIZE+2
- st y+,temp
- ldd temp,z+PART_SIZE+3
- st y+,temp
-
-
- inc temp3
- cpi temp3,MAXDISKS
- breq dsk_pend
-dsk_nextp:
- adiw zl,16
- cpi zl,low(hostbuf+510)
- cpc zh,temp4
- brlo dsk_ploop
-
-dsk_pend:
- sts ndisks,temp3
-
-;Store new partitions and check if the SD card has been changed.
-
- ldi yl,low(tmp_tbl)
- ldi yh,high(tmp_tbl)
- ldi zl,low(hostparttbl)
- ldi zh,high(hostparttbl)
- ldi temp3,8*MAXDISKS
- clt
-dsk_pcpl:
- ld temp,y+
- ld temp2,z
- st z+,temp
- cp temp,temp2
- cpse temp,temp2
- set
- dec temp3
- brne dsk_pcpl
-
- brtc dsk_pcpe
-
- lds temp,ndisks
- tst temp
- breq dsk_pcpe
-
-; SD card changed, print Info.
-
- sbiw z,8*MAXDISKS
-
-dsk_pprl:
- ldd temp,z+4
- ldd temp2,z+5
- or temp,temp2
- ldd temp2,z+6
- or temp,temp2
- ldd temp2,z+7
- or temp,temp2
-
- breq dsk_pcpe
-
- rcall printstr
- .db 13,"CP/M partition at: ",0,0
- ldd temp,z+0
- ldd temp2,z+1
- ldd temp3,z+2
- ldd temp4,z+3
- rcall print_ultoa
- rcall printstr
- .db ", size: ",0,0
- ldd temp,z+4
- ldd temp2,z+5
- ldd temp3,z+6
- ldd temp4,z+7
- lsr temp4
- ror temp3
- ror temp2
- ror temp
- rcall print_ultoa
- rcall printstr
- .db "KB.",0
-
- adiw z,8
- ldi temp,high(hostparttbl)
- cpi xl,low (hostparttbl)
- cpc xh,temp
- brlo dsk_pprl
-
-dsk_pcpe:
- lds temp,ndisks
- ret
-
-
-;***************************************************************************
-
-; ----------------- MMC/SD routines ------------------
-
-mmcByteNoSend:
- ldi temp,0xff
-mmcByte:
-
-.if MMC_DEBUG
- rcall printstr
- .db "MMC: <--",0
- rcall printhex
-.endif
-
- out SPDR,temp
-mmcWrByteW:
- in temp,SPSR
- sbrs temp,7
- rjmp mmcWrByteW
- in temp,SPDR
-
-.if MMC_DEBUG
- rcall printstr
- .db ", -->",0
- rcall printhex
- rcall printstr
- .db ".",13,0
-.endif
- ret
-
-
-;Wait till the mmc answers with the response in temp2, or till a timeout happens.
-mmcWaitResp:
- ldi zl,0
- ldi zh,0
-mmcWaitResploop:
- rcall mmcByteNoSend
- cpi temp,0xff
- brne mmcWaitResploopEnd
- adiw zl,1
- cpi zh,255
- breq mmcWaitErr
- rjmp mmcWaitResploop
-mmcWaitResploopEnd:
- ret
-
-
-mmcWaitErr:
- mov temp,temp2
- rcall printhex
- rcall printstr
- .db ": Error: MMC resp timeout!",13,0
- rjmp resetAVR
-
-mmcInit:
- ldi temp,0x53
- out SPCR,temp
-
- ;Init start: send 80 clocks with cs disabled
- sbi P_MMC_CS,mmc_cs
-
-; ldi temp2,20
- ldi temp2,10 ; exactly 80 clocks
-mmcInitLoop:
- mov temp,temp2
- rcall mmcByte
- dec temp2
- brne mmcInitLoop
-
- cbi P_MMC_CS,mmc_cs
- rcall mmcByteNoSend
- rcall mmcByteNoSend
- rcall mmcByteNoSend
- rcall mmcByteNoSend
- rcall mmcByteNoSend
- rcall mmcByteNoSend
- sbi P_MMC_CS,mmc_cs
- rcall mmcByteNoSend
- rcall mmcByteNoSend
- rcall mmcByteNoSend
- rcall mmcByteNoSend
-
- ;Send init command
- cbi P_MMC_CS,mmc_cs
- ldi temp,0xff ;dummy
- rcall mmcByte
- ldi temp,0xff ;dummy
- rcall mmcByte
- ldi temp,0x40 ;cmd
- rcall mmcByte
- ldi temp,0 ;pxh
- rcall mmcByte
- ldi temp,0 ;pxl
- rcall mmcByte
- ldi temp,0 ;pyh
- rcall mmcByte
- ldi temp,0 ;pyl
- rcall mmcByte
- ldi temp,0x95 ;crc
- rcall mmcByte
- ldi temp,0xff ;return byte
- rcall mmcByte
-
- ldi temp2,0 ;Error Code 0
- rcall mmcWaitResp ;Test on CMD0 is OK
-
- sbi P_MMC_CS,mmc_cs ;disable /CS
- rcall mmcByteNoSend
-
-
-;Read OCR till card is ready
- ldi temp2,100 ;repeat counter
-mmcInitOcrLoop:
- push temp2
-
- cbi P_MMC_CS,mmc_cs ;enable /CS
- ldi temp,0xff ;dummy
- rcall mmcByte
- ldi temp,0x41 ;cmd
- rcall mmcByte
- ldi temp,0 ;pxh
- rcall mmcByte
- ldi temp,0 ;pxl
- rcall mmcByte
- ldi temp,0 ;pyh
- rcall mmcByte
- ldi temp,0 ;pyl
- rcall mmcByte
-; ldi temp,0x95 ;crc
- ldi temp,0x01 ;crc
- rcall mmcByte
- rcall mmcByteNoSend
-
- ldi temp2,1
- rcall mmcWaitResp ;wait until mmc-card send a byte <> 0xFF
- ;the first answer must be 0x01 (Idle-Mode)
- cpi temp,0
- breq mmcInitOcrLoopDone ;second answer is 0x00 (Idle-Mode leave) CMD1 is OK
-
- sbi P_MMC_CS,mmc_cs ;disable /CS
-
- rcall mmcByteNoSend
-
- ldi temp,10
- rcall delay_ms
-
- pop temp2
- dec temp2
- brne mmcInitOcrLoop ;repeat
-
- ldi temp2,4
- rjmp mmcWaitErr
-
-mmcInitOcrLoopDone:
- pop temp2
- sbi P_MMC_CS,mmc_cs ;disable /CS
- rcall mmcByteNoSend
-
- out SPCR,_0
- ret
-
-
-;Call this with yh:yl:xh:xl = sector number
-;
-mmcReadSect:
- ldi temp,0x50
- out SPCR,temp
-
- cbi P_MMC_CS,mmc_cs
- rcall mmcByteNoSend
- ldi temp,0x51 ;cmd (read sector)
- rcall mmcByte
- lsl xl ;convert to byte address (*512)
- rol xh
- rol yl
- mov temp,yl
- rcall mmcByte
- mov temp,xh ;pxl
- rcall mmcByte
- mov temp,xl ;pyh
- rcall mmcByte
- ldi temp,0 ;pyl
- rcall mmcByte
- ldi temp,0x95 ;crc
- rcall mmcByte
- ldi temp,0xff ;return byte
- rcall mmcByte
-
- ;resp
- ldi temp2,2
- rcall mmcWaitResp
-
- ;data token
- ldi temp2,3
- rcall mmcWaitResp
-
- ;Read sector to AVR RAM
- ldi zl,low(hostbuf)
- ldi zh,high(hostbuf)
-mmcreadloop:
- rcall mmcByteNoSend
- st z+,temp
- cpi zl,low(hostbuf+512)
- brne mmcreadloop
- cpi zh,high(hostbuf+512)
- brne mmcreadloop
-
- ;CRC
- rcall mmcByteNoSend
- rcall mmcByteNoSend
-
- sbi P_MMC_CS,mmc_cs
- rcall mmcByteNoSend
-
- out SPCR,_0
- ret
-
-
-;Call this with yh:yl:xh:xl = sector number
-;
-mmcWriteSect:
- ldi temp,0x50
- out SPCR,temp
-
- cbi P_MMC_CS,mmc_cs
- rcall mmcByteNoSend
-
- ldi temp,0x58 ;cmd (write sector)
- rcall mmcByte
- lsl xl ;convert to byte address (*512)
- rol xh
- rol yl
- mov temp,yl
- rcall mmcByte
- mov temp,xh ;pxl
- rcall mmcByte
- mov temp,xl ;pyh
- rcall mmcByte
- ldi temp,0 ;pyl
- rcall mmcByte
- ldi temp,0x95 ;crc
- rcall mmcByte
- ldi temp,0xff ;return byte
- rcall mmcByte
-
- ;resp
- ldi temp2,1
- rcall mmcWaitResp
-
- ;Send data token
- ldi temp,0xfe
- rcall mmcByte
-
- ;Write sector from AVR RAM
- ldi zl,low(hostbuf)
- ldi zh,high(hostbuf)
-mmcwriteloop:
- ld temp,z+
- rcall mmcByte
- cpi zl,low(hostbuf+512)
- brne mmcwriteloop
- cpi zh,high(hostbuf+512)
- brne mmcwriteloop
-
- ;CRC
- rcall mmcByteNoSend
- rcall mmcByteNoSend
-
- ;Status. Ignored for now.
- rcall mmcByteNoSend
-
-;Wait till the mmc has written everything
-mmcwaitwritten:
- rcall mmcByteNoSend
- cpi temp,0xff
- brne mmcwaitwritten
-
- sbi P_MMC_CS,mmc_cs
- rcall mmcByteNoSend
-
- out SPCR,_0
- ret
-
-
-;Set up wdt to time out after 1 sec.
-resetAVR:
- lds temp,txcount ;Wait, till tx buffer is empty
- tst temp
- brne resetAVR
-
- cli
- ldi temp,(1<<WDCE)
- outm8 WDTCSR,temp
- ldi temp,(1<<WDCE) | (1<<WDE) | (110<<WDP0)
- outm8 WDTCSR,temp
-resetwait:
- rjmp resetwait
-
-; ------------------ DRAM routines -------------
-
-;Loads the byte on address xh:xl into temp.
-;must not alter xh:xl
-
-dram_read:
- cli
- DRAM_SETADDR xh, ~0,(1<<ram_ras), ~(1<<ram_a8), (1<<ram_oe)
- cbi P_RAS,ram_ras
- DRAM_SETADDR xl, ~(1<<ram_ras),0, ~((1<<ram_oe)), (1<<ram_a8)
- cbi P_CAS,ram_cas
- cbi P_A8,ram_a8
- dram_wait DRAM_WAITSTATES ;
- in temp,P_DQ-2 ; PIN
- sbi P_CAS,ram_cas
-
- cbi P_CAS,ram_cas
- andi temp,0x0f
- swap temp
- dram_wait DRAM_WAITSTATES ;
- in temp2,P_DQ-2 ; PIN
- andi temp2,0x0f
- or temp,temp2
-
- sbi P_OE,ram_oe
- sbi P_CAS,ram_cas
- sbi P_RAS,ram_ras
- sei
- ret
-
-#if DRAM_WORD_ACCESS
-dram_read_w:
- cpi xl,255
- brne dram_read_w1
-
- rcall dram_read
- push temp
- adiw xl,1
- rcall dram_read
- mov temp2,temp
- pop temp
- ret
-
-dram_read_w1:
- cli
- DRAM_SETADDR xh, ~0,(1<<ram_ras), ~(1<<ram_a8),(1<<ram_oe)
- cbi P_RAS,ram_ras
- DRAM_SETADDR xl, ~(1<<ram_ras),0, ~((1<<ram_oe)), (1<<ram_a8)
- cbi P_CAS,ram_cas
- cbi P_A8,ram_a8
- nop
- in temp,P_DQ-2 ; PIN
- sbi P_CAS,ram_cas
- cbi P_CAS,ram_cas
- andi temp,0x0f
- swap temp
- nop
- in temp2,P_DQ-2 ; PIN
- sbi P_CAS,ram_cas
- andi temp2,0x0f
- or temp,temp2
-
-; push temp
- mov _wl,temp
- inc xl
- DRAM_SETADDR xl, ~(1<<ram_ras),0, ~((1<<ram_oe)), (1<<ram_a8)
- cbi P_CAS,ram_cas
- cbi P_A8,ram_a8
- nop
- in temp,P_DQ-2 ; PIN
- sbi P_CAS,ram_cas
- cbi P_CAS,ram_cas
- andi temp,0x0f
- swap temp
- nop
- in temp2,P_DQ-2 ; PIN
- sbi P_CAS,ram_cas
- andi temp2,0x0f
- or temp2,temp
-; pop temp
- mov temp,_wl
-
- sbi P_OE,ram_oe
- sbi P_RAS,ram_ras
- sei
- ret
-#endif
-
-;Writes the byte in temp to xh:xl
-;must not alter xh:xl
-
-dram_write:
- cli
- ldi temp2,RAM_DQ_MASK | (1<<ram_w) | (1<<ram_cas)
- out DDRC,temp2
-
- mov temp2,temp
- andi temp,RAM_DQ_MASK & ~(1<<ram_w)
- ori temp,(1<<ram_cas)
- out PORTC,temp
- DRAM_SETADDR xh, ~0,(1<<ram_ras), ~(1<<ram_a8),(1<<ram_oe)
- cbi P_RAS,ram_ras
- DRAM_SETADDR xl, ~(1<<ram_ras),0, ~((1<<ram_a8)),(1<<ram_oe)
- cbi PORTC,ram_cas
- sbi PORTC,ram_cas
-
- sbi PORTD,ram_a8
- swap temp2
-
- andi temp2,RAM_DQ_MASK & ~(1<<ram_w)
- ori temp2,(1<<ram_cas)
- out PORTC,temp2
-
- cbi PORTC,ram_cas
- sbi P_RAS,ram_ras
-
- ldi temp,~RAM_DQ_MASK | (1<<ram_w) | (1<<ram_cas)
- out DDRC,temp
- out PORTC,temp
- sei
- ret
-
-#if DRAM_WORD_ACCESS
-dram_write_w:
- cpi xl,255
- brne dram_write_w1
-
- push temp2
- rcall dram_write
- pop temp
- adiw xl,1
- rcall dram_write
- ret
-
-dram_write_w1:
- cli
- push temp2
- ldi temp2,RAM_DQ_MASK | (1<<ram_w) | (1<<ram_cas)
- out DDRC,temp2
-
- mov temp2,temp
- andi temp,RAM_DQ_MASK & ~(1<<ram_w)
- ori temp,(1<<ram_cas)
- out PORTC,temp
-
- DRAM_SETADDR xh, ~0,(1<<ram_ras), ~(1<<ram_a8),(1<<ram_oe)
- cbi P_RAS,ram_ras
- DRAM_SETADDR xl, ~(1<<ram_ras),0, ~((1<<ram_a8)),(1<<ram_oe)
- cbi PORTC,ram_cas
- sbi PORTC,ram_cas
-
- sbi PORTD,ram_a8
- swap temp2
-
- andi temp2,RAM_DQ_MASK & ~(1<<ram_w)
- ori temp2,(1<<ram_cas)
- out PORTC,temp2
-
- cbi PORTC,ram_cas
- sbi PORTC,ram_cas
-
- pop temp
- inc xl
- mov temp2,temp
- andi temp,RAM_DQ_MASK & ~(1<<ram_w)
- ori temp,(1<<ram_cas)
- out PORTC,temp
-
- DRAM_SETADDR xl, ~(1<<ram_ras),0, ~((1<<ram_a8)),(1<<ram_oe)
- cbi PORTC,ram_cas
- sbi PORTC,ram_cas
-
- sbi PORTD,ram_a8
- swap temp2
-
- andi temp2,RAM_DQ_MASK & ~(1<<ram_w)
- ori temp2,(1<<ram_cas)
- out PORTC,temp2
- cbi PORTC,ram_cas
-
- sbi P_RAS,ram_ras
-
- ldi temp,~RAM_DQ_MASK | (1<<ram_w) | (1<<ram_cas)
- out DDRC,temp
- out PORTC,temp
- sei
- ret
-#endif
-
-; ****************************************************************************
-
-; refresh interupt; exec 2 cbr cycles
-refrint: ;4
-
- sbis P_RAS,ram_ras ;2
- reti
- ; CAS RAS
- cbi P_CAS,ram_cas ;2 1| 1|
- ; 1| 1|
- cbi P_RAS,ram_ras ;2 |0 1|
- ; |0 1|
- nop ;1 |0 |0
-; nop ;1 |0 |0
- sbi P_RAS,ram_ras ;2 |0 |0
- ; |0 |0
- dram_wait DRAM_WAITSTATES-1 ;
-; nop ;1 |0 |0
- cbi P_RAS,ram_ras ;2 |0 1|
- ; |0 1|
- sbi P_CAS,ram_cas ;2 |0 |0
- ; |0 |0
- sbi P_RAS,ram_ras ;2 1| |0
- ; 1| 1|
- reti ;4 --> 21 cycles
-
-
-; ------------- system timer 1ms ---------------
- .dseg
-
-delay_timer:
- .byte 1
-timer_base:
-timer_ms:
- .byte 2
-timer_s:
- .byte 4
-; don't change order here, clock put/get depends on it.
-cntms_out: ; register for ms
- .byte 2
-utime_io: ; register for uptime.
- .byte 4
-cnt_1ms:
- .byte 2
-uptime:
- .byte 4
-timer_top:
- .equ timer_size = timer_top - timer_base
-
- .equ clkofs = cnt_1ms-cntms_out
- .equ timerofs = cnt_1ms-timer_ms
-
- .cseg
-sysclockint:
- push zl
- in zl,SREG
- push zl
- push zh
-
- lds zl,delay_timer
- subi zl,1
- brcs syscl1
- sts delay_timer,zl
-syscl1:
- lds zl,cnt_1ms
- lds zh,cnt_1ms+1
- adiw z,1
-
- sts cnt_1ms,zl
- sts cnt_1ms+1,zh
- cpi zl,low(1000)
- ldi zl,high(1000) ;doesn't change flags
- cpc zh,zl
- brlo syscl_end
-
- ldi zl,0 ;can't use _0 register in int.
- sts cnt_1ms,zl
- sts cnt_1ms+1,zl
-
- lds zl,uptime+0
- inc zl
- sts uptime+0,zl
- brne syscl_end
- lds zl,uptime+1
- inc zl
- sts uptime+1,zl
- brne syscl_end
- lds zl,uptime+2
- inc zl
- sts uptime+2,zl
- brne syscl_end
- lds zl,uptime+3
- inc zl
- sts uptime+3,zl
-
-syscl_end:
- pop zh
- pop zl
- out SREG,zl
- pop zl
- reti
-
-; wait for temp ms
-
-delay_ms:
- sts delay_timer,temp
-dly_loop:
- lds temp,delay_timer
- cpi temp,0
- brne dly_loop
- ret
-
-;
-
-clockget:
- ldi temp,0xFF
- subi temp2,TIMER_MSECS
- brcs clkget_end ;Port number in range?
- ldi zl,low(cntms_out)
- ldi zh,high(cntms_out)
- breq clkget_copy ;lowest byte requestet, latch clock
- cpi temp2,6
- brsh clkget_end ;Port number to high?
-
- add zl,temp2
- brcc PC+2
- inc zh
- ld temp,z
-clkget_end:
- ret
-
-
-
-clkget_copy:
- ldi temp2,6
- cli
-clkget_l:
- ldd temp,z+clkofs
- st z+,temp
- dec temp2
- brne clkget_l
- sei
- lds temp,cntms_out
- ;req. byte in temp
- ret
-
-clockput:
- subi temp2,TIMERPORT
- brcs clkput_end ;Port number in range?
- brne clkput_1
-
- ; clock control
-
- cpi temp,starttimercmd
- breq timer_start
- cpi temp,quitTimerCmd
- breq timer_quit
- cpi temp,printTimerCmd
- breq timer_print
- cpi temp,uptimeCmd
- brne cp_ex
- rjmp uptime_print
-cp_ex:
- ret
-
-timer_quit:
- rcall timer_print
- rjmp timer_start
-
-clkput_1:
- dec temp2
- ldi zl,low(cntms_out)
- ldi zh,high(cntms_out)
- breq clkput_copy ;lowest byte requestet, latch clock
- cpi temp2,6
- brsh clkput_end ;Port number to high?
-
- add zl,temp2
- brcc PC+2
- inc zh
- st z,temp
-clkput_end:
- ret
-
-clkput_copy:
- st z,temp
- adiw z,5
- ldi temp2,6
- cli
-clkput_l:
- ldd temp,z+clkofs
- st z+,temp
- dec temp2
- brne clkput_l
- sei
- ret
-
-; start/reset timer
-;
-timer_start:
- ldi zl,low(timer_ms)
- ldi zh,high(timer_ms)
- ldi temp2,6
- cli
-ts_loop:
- ldd temp,z+timerofs
- st z+,temp
- dec temp2
- brne ts_loop
- sei
- ret
-
-
-; print timer
-;
-
-timer_print:
- push yh
- push yl
- ldi zl,low(timer_ms)
- ldi zh,high(timer_ms)
-
-; put ms on stack (16 bit)
-
- cli
- ldd yl,z+timerofs
- ld temp2,z+
- sub yl,temp2
- ldd yh,z+timerofs
- ld temp2,z+
- sbc yh,temp2
- brsh tp_s
-
- subi yl,low(-1000)
- sbci yh,high(-1000)
- sec
-tp_s:
- push yh
- push yl
-
- ldd temp,z+timerofs
- ld yl,z+
- sbc temp,yl
-
- ldd temp2,z+timerofs
- ld yh,z+
- sbc temp2,yh
-
- ldd temp3,z+timerofs
- ld yl,z+
- sbc temp3,yl
-
- sei
- ldd temp4,z+timerofs
- ld yh,z+
- sbc temp4,yh
-
- rcall printstr
- .db 13,"Timer running. Elapsed: ",0
- rcall print_ultoa
-
- rcall printstr
- .db ".",0
- pop temp
- pop temp2
- ldi temp3,0
- ldi temp4,0
- rcall print_ultoa
- rcall printstr
- .db "s.",0,0
-
- pop yl
- pop yh
- ret
-
-uptime_print:
-
- ldi zl,low(cnt_1ms)
- ldi zh,high(cnt_1ms)
-
- cli
- ld temp,z+
- push temp
- ld temp,z+
- push temp
-
- ld temp,z+
- ld temp2,z+
- ld temp3,z+
- sei
- ld temp4,z+
-
- rcall printstr
- .db 13,"Uptime: ",0
-
- rcall print_ultoa
- rcall printstr
- .db ",",0
-
- ldi temp3,0
- ldi temp4,0
- pop temp2
- pop temp
- rcall print_ultoa
- rcall printstr
- .db "s.",0,0
-
- ret
-
-
-
-; --------------- Debugging stuff ---------------
-
-;Print a unsigned lonng value to the uart
-; temp4:temp3:temp2:temp = value
-
-print_ultoa:
- push yh
- push yl
- push z_flags
- push temp4
- push temp3
- push temp2
- push temp
-
- clr yl ;yl = stack level
-
-ultoa1: ldi z_flags, 32 ;yh = temp4:temp % 10
- clr yh ;temp4:temp /= 10
-ultoa2: lsl temp
- rol temp2
- rol temp3
- rol temp4
- rol yh
- cpi yh,10
- brcs ultoa3
- subi yh,10
- inc temp
-ultoa3: dec z_flags
- brne ultoa2
- cpi yh, 10 ;yh is a numeral digit '0'-'9'
- subi yh, -'0'
- push yh ;Stack it
- inc yl
- cp temp,_0 ;Repeat until temp4:temp gets zero
- cpc temp2,_0
- cpc temp3,_0
- cpc temp4,_0
- brne ultoa1
-
- ldi temp, '0'
-ultoa5: cpi yl,3 ; at least 3 digits (ms)
- brge ultoa6
- push temp
- inc yl
- rjmp ultoa5
-
-ultoa6: pop temp ;Flush stacked digits
- rcall uartputc
- dec yl
- brne ultoa6
-
- pop temp
- pop temp2
- pop temp3
- pop temp4
- pop z_flags
- pop yl
- pop yh
- ret
-
-
-;Prints temp2:temp in hex to the uart
-printhexw:
- push temp
- mov temp,temp2
- rcall printhex
- pop temp
- ;fall thru
-
-;Prints temp in hex to the uart
-printhex:
- swap temp
- rcall printhexn
- swap temp
- ;fall thru
-
-;Prints the lower nibble
-printhexn:
- push temp
- andi temp,0xf
- cpi temp,0xA
- brlo printhexn_isno
- subi temp,-7
-printhexn_isno:
- subi temp,-'0'
- rcall uartputc
- pop temp
- ret
-
-;Prints the zero-terminated string following the call statement.
-
-printstr:
- push zh
- push zl
- push yh
- push yl
- push temp
- in yh,sph
- in yl,spl
- ldd zl,y+7
- ldd zh,y+6
-
- lsl zl
- rol zh
-printstr_loop:
- lpm temp,z+
- cpi temp,0
- breq printstr_end
- rcall uartputc
- cpi temp,13
- brne printstr_loop
- ldi temp,10
- rcall uartputc
- rjmp printstr_loop
-
-printstr_end:
- adiw zl,1
- lsr zh
- ror zl
-
- std y+7,zl
- std y+6,zh
- pop temp
- pop yl
- pop yh
- pop zl
- pop zh
- ret
-
-; --------------- AVR HW <-> Z80 periph stuff ------------------
-
-.equ memReadByte = dram_read
-.equ memWriteByte = dram_write
-#if DRAM_WORD_ACCESS
-.equ memReadWord = dram_read_w
-.equ memWriteWord = dram_write_w
-#endif
-
; --------------------------------------------------------------
- .dseg
-
-#define RXBUFMASK RXBUFSIZE-1
-#define TXBUFMASK TXBUFSIZE-1
-
-rxcount:
- .byte 1
-rxidx_w:
- .byte 1
-rxidx_r:
- .byte 1
-txcount:
- .byte 1
-txidx_w:
- .byte 1
-txidx_r:
- .byte 1
-rxfifo:
- .byte RXBUFSIZE
-txfifo:
- .byte TXBUFSIZE
-
-ramtop: .byte 0
- .cseg
-
-; Save received character in a circular buffer. Do nothing if buffer overflows.
-
-rxint:
- push temp
- in temp,sreg
- push temp
- push zh
- push zl
- inm8 temp,RXTXDR0
- lds zh,rxcount ;if rxcount < RXBUFSIZE
- cpi zh,RXBUFSIZE ; (room for at least 1 char?)
- brsh rxi_ov ;
- inc zh ;
- sts rxcount,zh ; rxcount++
-
- ldi zl,low(rxfifo) ;
- lds zh,rxidx_w ;
- add zl,zh ;
- inc zh ;
- andi zh,RXBUFMASK ;
- sts rxidx_w,zh ; rxidx_w = ++rxidx_w % RXBUFSIZE
- ldi zh,high(rxfifo) ;
- brcc PC+2 ;
- inc zh ;
- st z,temp ; rxfifo[rxidx_w] = char
-rxi_ov: ;endif
- pop zl
- pop zh
- pop temp
- out sreg,temp
- pop temp
- reti
-
-
-;Fetches a char from the buffer to temp. If none available, waits till one is.
-
-uartgetc:
- lds temp,rxcount ; Number of characters in buffer
- tst temp
- breq uartgetc ;Wait for char
-
- push zh
- push zl
- ldi zl,low(rxfifo)
- ldi zh,high(rxfifo)
- lds temp,rxidx_r
- add zl,temp
- brcc PC+2
- inc zh
- inc temp
- andi temp,RXBUFMASK
- sts rxidx_r,temp
- cli
- lds temp,rxcount
- dec temp
- sts rxcount,temp
- sei
- ld temp,z ;don't forget to get the char
- pop zl
- pop zh
- ret
-
-txint:
- push temp
- in temp,sreg
- push temp
- lds temp,txcount ;if txcount != 0
- tst temp ;
- breq txi_e ;
-
- dec temp ;
- sts txcount,temp ; --txcount
- push zh ;
- push zl ;
- ldi zl,low(txfifo) ;
- ldi zh,high(txfifo) ;
- lds temp,txidx_r ;
- add zl,temp ;
- brcc PC+2 ;
- inc zh ;
- inc temp ;
- andi temp,TXBUFMASK ;
- sts txidx_r,temp ;
- ld temp,z
- outm8 RXTXDR0,temp
- pop zl
- pop zh
-txi_e: ;endif
- lds temp,txcount
- tst temp
- brne txi_x
- ldi temp, (1<<TXEN0) | (1<<RXEN0) | (1<<RXCIE0)
- outm8 UCSR0B,temp
-txi_x:
- pop temp
- out sreg,temp
- pop temp
- reti
-
-
-;Sends a char from temp to the uart.
-uartputc:
- push zh
- push zl
- push temp
-putc_l:
- lds temp,txcount ;do {
- cpi temp,TXBUFSIZE ;
- brsh putc_l ;} while (txcount >= TXBUFSIZE)
-
- ldi zl,low(txfifo) ;
- ldi zh,high(txfifo) ;
- lds temp,txidx_w ;
- add zl,temp ;
- brcc PC+2 ;
- inc zh ;
- inc temp ;
- andi temp,TXBUFMASK ;
- sts txidx_w,temp ; txidx_w = ++txidx_w % TXBUFSIZE
- pop temp ;
- st z,temp ; txfifo[txidx_w] = char
- cli
- lds zl,txcount
- inc zl
- sts txcount,zl
- ldi zl, (1<<UDRIE0) | (1<<TXEN0) | (1<<RXEN0) | (1<<RXCIE0)
- outm8 UCSR0B,zl
- sei
- pop zl
- pop zh
- ret
-
; ------------ Fetch phase stuff -----------------
.equ FETCH_NOP = (0<<0)
ret
do_fetch_b:
- mov opl,z_b
+ lds opl,z_b
ret
do_fetch_c:
- mov opl,z_c
+ lds opl,z_c
ret
do_fetch_d:
- mov opl,z_d
+ lds opl,z_d
ret
do_fetch_e:
- mov opl,z_e
+ lds opl,z_e
ret
do_fetch_h:
- mov opl,z_h
+ lds opl,z_h
ret
do_fetch_l:
- mov opl,z_l
+ lds opl,z_l
ret
do_fetch_af:
ret
do_fetch_bc:
- movw opl,z_c
+ lds opl,z_c
+ lds oph,z_b
ret
do_fetch_de:
- movw opl,z_e
+ lds opl,z_e
+ lds oph,z_d
ret
do_fetch_hl:
- movw opl,z_l
+ lds opl,z_l
+ lds oph,z_h
ret
do_fetch_sp:
ret
do_fetch_mbc:
- movw xl,z_c
- rcall memReadByte
- mov opl,temp
+ lds xh,z_b
+ lds xl,z_c
+ mem_read_d opl
ret
do_fetch_mde:
- movw xl,z_e
- rcall memReadByte
- mov opl,temp
+ lds xh,z_d
+ lds xl,z_e
+ mem_read_d opl
ret
do_fetch_mhl:
- movw xl,z_l
- rcall memReadByte
- mov opl,temp
+ lds xh,z_h
+ lds xl,z_l
+ mem_read_d opl
ret
do_fetch_msp:
- movw xl,z_spl
-#if DRAM_WORD_ACCESS
- rcall memReadWord
- movw opl,temp
-#else
- rcall memReadByte
- mov opl,temp
- adiw xl,1
- rcall memReadByte
- mov oph,temp
-#endif
+ movw x,z_spl
+ mem_read_d opl
+ adiw x,1
+ mem_read_d oph
ret
do_fetch_dir8:
- movw xl,z_pcl
- rcall memReadByte
+ mem_read_ds opl, z_pc
adiw z_pcl,1
- mov opl,temp
ret
do_fetch_dir16:
- movw xl,z_pcl
-#if DRAM_WORD_ACCESS
- rcall memReadWord
- movw opl,temp
-#else
- rcall memReadByte
- mov opl,temp
- adiw xl,1
- rcall memReadByte
- mov oph,temp
-#endif
- adiw z_pcl,2
+ mem_read_ds opl, z_pc
+ adiw z_pcl,1
+ mem_read_ds oph, z_pc
+ adiw z_pcl,1
ret
do_fetch_rst:
- movw xl,z_pcl
- subi xl,1
- sbci xh,0
- rcall memReadByte
- andi temp,0x38
+ movw x,z_pcl
+ sbiw x,1
+ mem_read_d opl
+ andi opl,0x38
ldi oph,0
- mov opl,temp
ret
ret
do_store_b:
- mov z_b,opl
+ sts z_b,opl
ret
do_store_c:
- mov z_c,opl
+ sts z_c,opl
ret
do_store_d:
- mov z_d,opl
+ sts z_d,opl
ret
do_store_e:
- mov z_e,opl
+ sts z_e,opl
ret
do_store_h:
- mov z_h,opl
+ sts z_h,opl
ret
do_store_l:
- mov z_l,opl
+ sts z_l,opl
ret
do_store_af:
ret
do_store_bc:
- mov z_b,oph
- mov z_c,opl
+ sts z_b,oph
+ sts z_c,opl
ret
do_store_de:
- mov z_d,oph
- mov z_e,opl
+ sts z_d,oph
+ sts z_e,opl
ret
do_store_hl:
- mov z_h,oph
- mov z_l,opl
+ sts z_h,oph
+ sts z_l,opl
ret
do_store_mbc:
- movw xl,z_c
- mov temp,opl
- rcall memWriteByte
+ lds xh,z_b
+ lds xl,z_c
+ mem_write_s opl
ret
do_store_mde:
- movw xl,z_e
- mov temp,opl
- rcall memWriteByte
+ lds xh,z_d
+ lds xl,z_e
+ mem_write_s opl
ret
do_store_mhl:
- movw xl,z_l
- mov temp,opl
- rcall memWriteByte
+ lds xh,z_h
+ lds xl,z_l
+ mem_write_s opl
ret
do_store_msp:
- movw xl,z_spl
-#if DRAM_WORD_ACCESS
- movw temp,opl
- rcall memWriteWord
-#else
- mov temp,opl
- rcall memWriteByte
+ movw xl,z_spl
+ mem_write_s opl
adiw xl,1
- mov temp,oph
- rcall memWriteByte
-#endif
+ mem_write_s oph
ret
do_store_sp:
ret
do_store_ret:
- rcall do_op_pop16
- movw z_pcl,opl
+ movw x,z_spl
+ mem_read_d z_pcl
+ adiw x,1
+ mem_read_d z_pch
+ adiw x,1
+ movw z_spl,x
+
+.if STACK_DBG
+ printnewline
+ printstring "Stack pop "
+ movw temp,z_pcl
+ rcall printhexw
+ printstring ", SP is now "
+ movw temp,z_spl
+ rcall printhexw
+ printstring ". "
+.endif
ret
do_store_call:
- push opl
- push oph
- movw opl,z_pcl
- rcall do_op_push16
- pop z_pch
- pop z_pcl
+ movw xl,z_spl
+ sbiw x,1
+ mem_write_s z_pch
+ sbiw x,1
+ mem_write_s z_pcl
+ movw z_spl,xl
+
+.if STACK_DBG
+ printnewline
+ printstring "Stack push "
+ movw temp,z_pcl
+ rcall printhexw
+ printstring ", SP is now "
+ movw temp,z_spl
+ rcall printhexw
+ printstring ". "
+.endif
+ movw z_pcl,opl
ret
+
do_store_am:
- movw xl,opl
- mov temp,z_a
- rcall memWriteByte
+ mem_write_ds op, z_a
ret
rjmp do_op_deca
-;How the flags are supposed to work:
-;7 ZFL_S - Sign flag (=MSBit of result)
-;6 ZFL_Z - Zero flag. Is 1 when the result is 0
-;4 ZFL_H - Half-carry (carry from bit 3 to 4)
-;2 ZFL_P - Parity/2-complement Overflow
-;1 ZFL_N - Subtract - set if last op was a subtract
-;0 ZFL_C - Carry
-;
-;I sure hope I got the mapping between flags and instructions correct...
-
;----------------------------------------------------------------
;| |
;| Zilog |
;| ## |Only lower 4 bits of accumulator A used |
;----------------------------------------------------------------
+;How the flags are supposed to work:
+;7 ZFL_S - Sign flag (=MSBit of result)
+;6 ZFL_Z - Zero flag. Is 1 when the result is 0
+;4 ZFL_H - Half-carry (carry from bit 3 to 4)
+;2 ZFL_P - Parity/2-complement Overflow
+;1 ZFL_N - Subtract - set if last op was a subtract
+;0 ZFL_C - Carry
+;
+;I sure hope I got the mapping between flags and instructions correct...
+
+.equ ZFL_S = 7
+.equ ZFL_Z = 6
+.equ ZFL_H = 4
+.equ ZFL_P = 2
+.equ ZFL_N = 1
+.equ ZFL_C = 0
.equ AVR_T = SREG_T
.equ AVR_H = SREG_H
.equ AVR_Z = SREG_Z
.equ AVR_C = SREG_C
-;------------------------------------------------;
-; Move single bit between two registers
-;
-; bmov dstreg,dstbit,srcreg.srcbit
-
-.macro bmov
- bst @2,@3
- bld @0,@1
-.endm
-
-
;------------------------------------------------;
; Load table value from flash indexed by source reg.
;
mov zl,@2
lpm @0,z
.endm
+
.macro do_z80_flags_HP
#if EM_Z80
bmov z_flags, ZFL_P, temp, AVR_V
.endm
+;----------------------------------------------------------------
+do_op_inv:
+ printstring "Invalid opcode @ PC="
+ movw temp,z_pcl
+ rcall printhexw
+haltinv:
+ rjmp haltinv
+
do_op_nop:
ret
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|OUT [n],A |------|Output |[n]=A |
+;
+;
+;Interface with peripherials goes here :)
+do_op_outa: ; out (opl),a
+.if PORT_DEBUG
+ printnewline
+ printstring "Port write: "
+ mov temp,z_a
+ rcall printhex
+ printstring " -> ("
+ mov temp,opl
+ rcall printhex
+ printstring ") "
+.endif
+ mov temp,z_a
+ mov temp2,opl
+ rcall portWrite
+ ret
+
+;----------------------------------------------------------------
+;|Mnemonic |SZHPNC|Description |Notes |
+;----------------------------------------------------------------
+;|IN A,[n] |------|Input |A=[n] |
+;
+;
+do_op_in: ; in a,(opl)
+.if PORT_DEBUG
+ printnewline
+ printstring "Port read: ("
+ mov temp,opl
+ rcall printhex
+ printstring ") -> "
+.endif
+
+ mov temp2,opl
+ rcall portRead
+ mov opl,temp
+
+.if PORT_DEBUG
+ rcall printhex
+ printstring " "
+.endif
+ ret
+
;----------------------------------------------------------------
;|Mnemonic |SZHPNC|Description |Notes |
;----------------------------------------------------------------
;
;
do_op_addhl:
- add opl,z_l
- adc oph,z_h
+ lds temp,z_l
+ lds temp2,z_h
+ add opl,temp
+ adc oph,temp2
in temp,sreg
bmov z_flags,ZFL_H, temp,AVR_H
bmov z_flags,ZFL_C, temp,AVR_C
;
do_op_sthl: ;store hl to mem loc in opl:h
movw xl,opl
-#if DRAM_WORD_ACCESS
- movw temp,z_l
- rcall memWriteWord
-#else
- mov temp,z_l
- rcall memWriteByte
+ lds temp,z_l
+ mem_write
adiw xl,1
- mov temp,z_h
- rcall memWriteByte
-#endif
+ lds temp,z_h
+ mem_write
ret
;----------------------------------------------------------------
;
do_op_rmem16:
movw xl,opl
-#if DRAM_WORD_ACCESS
- rcall memReadWord
- movw opl,temp
-#else
- rcall memReadByte
- mov opl,temp
- adiw xl,1
- rcall memReadByte
- mov oph,temp
-#endif
+ mem_read_d opl
+ adiw x,1
+ mem_read_d oph
ret
;----------------------------------------------------------------
;
;
do_op_rmem8:
- movw xl,opl
- rcall memReadByte
- mov opl,temp
+ mem_read_ds opl, op
ret
;----------------------------------------------------------------
;
;
do_op_push16:
- movw xl,z_spl
- subi xl,2
- sbci xh,0
- movw z_spl,xl
-#if DRAM_WORD_ACCESS
- movw temp,opl
- rcall memWriteWord
-#else
- mov temp,opl
- rcall memWriteByte
- adiw xl,1
- mov temp,oph
- rcall memWriteByte
-#endif
+ movw xl,z_spl
+ sbiw x,1
+ mem_write_s oph
+ sbiw x,1
+ mem_write_s opl
+ movw z_spl,xl
.if STACK_DBG
- rcall printstr
- .db "Stack push ",0
- mov tempw,opl
+ printnewline
+ printstring "Stack push "
+ movw temp,opl
rcall printhexw
- rcall printstr
- .db ", SP is now ",0
- mov tempw,z_spl
+ printstring ", SP is now "
+ movw temp,z_spl
rcall printhexw
- rcall printstr
- .db ".",13,0
+ printstring ". "
.endif
ret
;
;
do_op_pop16:
- movw xl,z_spl
-#if DRAM_WORD_ACCESS
- rcall memReadWord
- movw opl,temp
-#else
- rcall memReadByte
- mov opl,temp
- adiw xl,1
- rcall memReadByte
- mov oph,temp
-#endif
-
- ldi temp,2
- add z_spl,temp
- adc z_sph,_0
+ movw x,z_spl
+ mem_read_d opl
+ adiw x,1
+ mem_read_d oph
+ adiw x,1
+ movw z_spl,x
.if STACK_DBG
- rcall printstr
- .db "Stack pop: val ",0
+ printnewline
+ printstring "Stack pop "
movw temp,opl
rcall printhexw
- rcall printstr
- .db ", SP is now",0
+ printstring ", SP is now "
movw temp,z_spl
rcall printhexw
- rcall printstr
- .db ".",13,0
+ printstring ". "
.endif
ret
;
;
do_op_exhl:
- mov temp,z_h
- mov z_h,oph
- mov oph,temp
- mov temp,z_l
- mov z_l,opl
- mov opl,temp
+ lds temp,z_l
+ lds temp2,z_h
+ sts z_l,opl
+ sts z_h,oph
+ movw opl,temp
ret
;----------------------------------------------------------------
clr insdecl
ret
-;----------------------------------------------------------------
-;|Mnemonic |SZHPNC|Description |Notes |
-;----------------------------------------------------------------
-;|OUT [n],A |------|Output |[n]=A |
-;
-;
-;Interface with peripherials goes here :)
-do_op_outa: ; out (opl),a
-.if PORT_DEBUG
- rcall printstr
- .db 13,"Port write: ",0
- mov temp,z_a
- rcall printhex
- rcall printstr
- .db " -> (",0
- mov temp,opl
- rcall printhex
- rcall printstr
- .db ")",13,0
-.endif
- mov temp,z_a
- mov temp2,opl
- rcall portWrite
- ret
-
-;----------------------------------------------------------------
-;|Mnemonic |SZHPNC|Description |Notes |
-;----------------------------------------------------------------
-;|IN A,[n] |------|Input |A=[n] |
-;
-;
-do_op_in: ; in a,(opl)
-.if PORT_DEBUG
- rcall printstr
- .db 13,"Port read: (",0
- mov temp,opl
- rcall printhex
- rcall printstr
- .db ") -> ",0
-.endif
-
- mov temp2,opl
- rcall portRead
- mov opl,temp
-
-.if PORT_DEBUG
- rcall printhex
- rcall printstr
- .db 13,0
-.endif
- ret
-
-
-;----------------------------------------------------------------
-do_op_inv:
- rcall printstr
- .db "Invalid opcode @ PC=",0,0
- movw temp,z_pcl
- rcall printhexw
-
-;----------------------------------------------------------------
-haltinv:
- rjmp haltinv
-;----------------------------------------------------------------
-; 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
-.org (PC+255) & 0xff00
-sz53p_tab:
- .db 0x44,0x00,0x00,0x04,0x00,0x04,0x04,0x00
- .db 0x08,0x0c,0x0c,0x08,0x0c,0x08,0x08,0x0c
- .db 0x00,0x04,0x04,0x00,0x04,0x00,0x00,0x04
- .db 0x0c,0x08,0x08,0x0c,0x08,0x0c,0x0c,0x08
- .db 0x20,0x24,0x24,0x20,0x24,0x20,0x20,0x24
- .db 0x2c,0x28,0x28,0x2c,0x28,0x2c,0x2c,0x28
- .db 0x24,0x20,0x20,0x24,0x20,0x24,0x24,0x20
- .db 0x28,0x2c,0x2c,0x28,0x2c,0x28,0x28,0x2c
- .db 0x00,0x04,0x04,0x00,0x04,0x00,0x00,0x04
- .db 0x0c,0x08,0x08,0x0c,0x08,0x0c,0x0c,0x08
- .db 0x04,0x00,0x00,0x04,0x00,0x04,0x04,0x00
- .db 0x08,0x0c,0x0c,0x08,0x0c,0x08,0x08,0x0c
- .db 0x24,0x20,0x20,0x24,0x20,0x24,0x24,0x20
- .db 0x28,0x2c,0x2c,0x28,0x2c,0x28,0x28,0x2c
- .db 0x20,0x24,0x24,0x20,0x24,0x20,0x20,0x24
- .db 0x2c,0x28,0x28,0x2c,0x28,0x2c,0x2c,0x28
- .db 0x80,0x84,0x84,0x80,0x84,0x80,0x80,0x84
- .db 0x8c,0x88,0x88,0x8c,0x88,0x8c,0x8c,0x88
- .db 0x84,0x80,0x80,0x84,0x80,0x84,0x84,0x80
- .db 0x88,0x8c,0x8c,0x88,0x8c,0x88,0x88,0x8c
- .db 0xa4,0xa0,0xa0,0xa4,0xa0,0xa4,0xa4,0xa0
- .db 0xa8,0xac,0xac,0xa8,0xac,0xa8,0xa8,0xac
- .db 0xa0,0xa4,0xa4,0xa0,0xa4,0xa0,0xa0,0xa4
- .db 0xac,0xa8,0xa8,0xac,0xa8,0xac,0xac,0xa8
- .db 0x84,0x80,0x80,0x84,0x80,0x84,0x84,0x80
- .db 0x88,0x8c,0x8c,0x88,0x8c,0x88,0x88,0x8c
- .db 0x80,0x84,0x84,0x80,0x84,0x80,0x80,0x84
- .db 0x8c,0x88,0x88,0x8c,0x88,0x8c,0x8c,0x88
- .db 0xa0,0xa4,0xa4,0xa0,0xa4,0xa0,0xa0,0xa4
- .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
-
-
; ----------------------- Opcode decoding -------------------------
; Lookup table for Z80 opcodes. Translates the first byte of the instruction word into three
.dw (FETCH_DIR8 | OP_CPFA | STORE_NOP) ; FE nn CP n
.dw (FETCH_RST | OP_NOP | STORE_CALL) ; FF RST 38H
+;----------------------------------------------------------------
+; 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
+
+.org (PC+255) & 0xff00
+sz53p_tab:
+ .db 0x44,0x00,0x00,0x04,0x00,0x04,0x04,0x00
+ .db 0x08,0x0c,0x0c,0x08,0x0c,0x08,0x08,0x0c
+ .db 0x00,0x04,0x04,0x00,0x04,0x00,0x00,0x04
+ .db 0x0c,0x08,0x08,0x0c,0x08,0x0c,0x0c,0x08
+ .db 0x20,0x24,0x24,0x20,0x24,0x20,0x20,0x24
+ .db 0x2c,0x28,0x28,0x2c,0x28,0x2c,0x2c,0x28
+ .db 0x24,0x20,0x20,0x24,0x20,0x24,0x24,0x20
+ .db 0x28,0x2c,0x2c,0x28,0x2c,0x28,0x28,0x2c
+ .db 0x00,0x04,0x04,0x00,0x04,0x00,0x00,0x04
+ .db 0x0c,0x08,0x08,0x0c,0x08,0x0c,0x0c,0x08
+ .db 0x04,0x00,0x00,0x04,0x00,0x04,0x04,0x00
+ .db 0x08,0x0c,0x0c,0x08,0x0c,0x08,0x08,0x0c
+ .db 0x24,0x20,0x20,0x24,0x20,0x24,0x24,0x20
+ .db 0x28,0x2c,0x2c,0x28,0x2c,0x28,0x28,0x2c
+ .db 0x20,0x24,0x24,0x20,0x24,0x20,0x20,0x24
+ .db 0x2c,0x28,0x28,0x2c,0x28,0x2c,0x2c,0x28
+ .db 0x80,0x84,0x84,0x80,0x84,0x80,0x80,0x84
+ .db 0x8c,0x88,0x88,0x8c,0x88,0x8c,0x8c,0x88
+ .db 0x84,0x80,0x80,0x84,0x80,0x84,0x84,0x80
+ .db 0x88,0x8c,0x8c,0x88,0x8c,0x88,0x88,0x8c
+ .db 0xa4,0xa0,0xa0,0xa4,0xa0,0xa4,0xa4,0xa0
+ .db 0xa8,0xac,0xac,0xa8,0xac,0xa8,0xa8,0xac
+ .db 0xa0,0xa4,0xa4,0xa0,0xa4,0xa0,0xa0,0xa4
+ .db 0xac,0xa8,0xa8,0xac,0xa8,0xac,0xac,0xa8
+ .db 0x84,0x80,0x80,0x84,0x80,0x84,0x84,0x80
+ .db 0x88,0x8c,0x8c,0x88,0x8c,0x88,0x88,0x8c
+ .db 0x80,0x84,0x84,0x80,0x84,0x80,0x80,0x84
+ .db 0x8c,0x88,0x88,0x8c,0x88,0x8c,0x8c,0x88
+ .db 0xa0,0xa4,0xa4,0xa0,0xa4,0xa0,0xa0,0xa4
+ .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
+