# sleigh specification file for Zilog Z80 # TODO: Improve Flag bit implementation so that bit operations on F register work properly define endian=little; define alignment=1; @if defined(Z180) define space ram type=ram_space size=2 default; @define PTRSIZE "2" @else define space ram type=ram_space size=2 default; @define PTRSIZE "2" @endif define space io type=ram_space size=2; define space register type=register_space size=1; define register offset=0x00 size=1 [ F A C B E D L H I R ]; define register offset=0x00 size=2 [ AF BC DE HL ]; define register offset=0x20 size=1 [ F_ A_ C_ B_ E_ D_ L_ H_ ]; # Alternate registers define register offset=0x20 size=2 [ AF_ BC_ DE_ HL_ ]; # Alternate registers define register offset=0x40 size=2 [ _ PC SP IX IY ]; define register offset=0x46 size=1 [ IXL IXH IYL IYH ]; # Undocumented registers define register offset=0x50 size=1 [ rCBAR rCBR rBBR ]; # Fake Registers used for pcode control define register offset=0x60 size=1 [ DECOMPILE_MODE ]; # Define context bits define register offset=0xf0 size=4 contextreg; define context contextreg assume8bitIOSpace =(0,0) # only applies to Z180 ; # Flag bits (?? manual is very confusing - could be typos!) @define C_flag "F[0,1]" # C: Carry @define N_flag "F[1,1]" # N: Add/Subtract - used by DAA to distinguish between ADD and SUB instructions (0=ADD,1=SUB) @define PV_flag "F[2,1]" # PV: Parity/Overflow @define H_flag "F[4,1]" # H: Half Carry @define Z_flag "F[6,1]" # Z: Zero @define S_flag "F[7,1]" # S: Sign define token opbyte (8) op0_8 = (0,7) op6_2 = (6,7) dRegPair4_2 = (4,5) pRegPair4_2 = (4,5) sRegPair4_2 = (4,5) qRegPair4_2 = (4,5) rRegPair4_2 = (4,5) reg3_3 = (3,5) bits3_3 = (3,5) bits0_4 = (0,3) reg0_3 = (0,2) bits0_3 = (0,2) ; define token data8 (8) imm8 = (0,7) sign8 = (7,7) simm8 = (0,7) signed ; define token data16 (16) timm4 = (12,15) imm16 = ( 0,15) sign16 = (15,15) simm16 = ( 0,15) signed ; attach variables [ reg0_3 reg3_3 ] [ B C D E H L _ A ]; attach variables [ sRegPair4_2 dRegPair4_2 ] [ BC DE HL SP ]; attach variables [ qRegPair4_2 ] [ BC DE HL AF ]; attach variables [ pRegPair4_2 ] [ BC DE IX SP ]; attach variables [ rRegPair4_2 ] [ BC DE IY SP ]; ################################################################ # Pseudo Instructions ################################################################ define pcodeop segment; # Define special pcodeop that calculates the RAM address # given the segment selector and offset as input define pcodeop BCDadjust; define pcodeop BCDadjustCarry; define pcodeop hasEvenParity; define pcodeop disableMaskableInterrupts; define pcodeop enableMaskableInterrupts; define pcodeop setInterruptMode; define pcodeop parity; define pcodeop sleep; define pcodeop halt; ################################################################ # Macros ################################################################ macro setResultFlags(result) { $(Z_flag) = (result == 0); $(S_flag) = (result s< 0); } macro additionFlags(operand1, operand2) { local AFmask = -1 >> 4; $(H_flag) = (((operand1 & AFmask) + (operand2 & AFmask)) & (AFmask + 1)) != 0; $(PV_flag) = scarry(operand1, operand2); $(N_flag) = 0; $(C_flag) = carry(operand1, operand2); } macro additionFlagsNoC(operand1, operand2) { local AFmask = -1 >> 4; $(H_flag) = (((operand1 & AFmask) + (operand2 & AFmask)) & (AFmask + 1)) != 0; $(PV_flag) = scarry(operand1, operand2); $(N_flag) = 0; # $(C_flag) is not affected } macro additionFlagsNoPV(operand1, operand2) { local AFmask = -1 >> 4; $(H_flag) = (((operand1 & AFmask) + (operand2 & AFmask)) & (AFmask + 1)) != 0; # $(PV_flag) is not affected $(N_flag) = 0; $(C_flag) = carry(operand1, operand2); } macro additionWithCarry(operand1, operand2, result) { local Ccopy = zext($(C_flag)); local AFmask = -1 >> 4; $(H_flag) = (((operand1 & AFmask) + (operand2 & AFmask) + Ccopy) & (AFmask + 1)) != 0; $(PV_flag) = scarry(operand1, operand2); $(N_flag) = 0; $(C_flag) = carry(operand1, operand2); local tempResult = operand1 + operand2; $(C_flag) = $(C_flag) || carry(tempResult, Ccopy); $(PV_flag) = $(PV_flag) ^^ scarry(tempResult, Ccopy); result = tempResult + Ccopy; } macro subtractionFlags(operand1, operand2) { local AFmask = -1 >> 4; $(H_flag) = (((operand1 & AFmask) - (operand2 & AFmask)) & (AFmask + 1)) != 0; $(PV_flag) = sborrow(operand1, operand2); $(N_flag) = 1; $(C_flag) = operand1 < operand2; } macro subtractionFlagsNoC(operand1, operand2) { local AFmask = -1 >> 4; $(H_flag) = (((operand1 & AFmask) - (operand2 & AFmask)) & (AFmask + 1)) != 0; $(PV_flag) = sborrow(operand1, operand2); $(N_flag) = 1; # $(C_flag) is not affected } macro subtractionWithCarry(operand1, operand2, result) { local Ccopy = zext($(C_flag)); local AFmask = -1 >> 4; $(H_flag) = (((operand1 & AFmask) - (operand2 & AFmask) - Ccopy) & (AFmask + 1)) != 0; $(PV_flag) = sborrow(operand1, operand2); $(N_flag) = 1; $(C_flag) = operand1 < operand2; local tempResult = operand1 - operand2; $(C_flag) = $(C_flag) || (tempResult < Ccopy); $(PV_flag) = $(PV_flag) ^^ sborrow(tempResult, Ccopy); result = tempResult - Ccopy; } macro setSubtractFlags(op1,op2) { $(C_flag) = (op1 < op2); } # places the parity bit of the given byte in out_parity_bit # the upper 7 bits of out_parity_bit are cleared macro setParity(in_byte) { local tmp = in_byte ^ (in_byte >> 1); tmp = tmp ^ (tmp >> 2); tmp = (tmp ^ (tmp >> 4)) & 1; $(PV_flag) = (tmp == 0); # $(PV_flag) = hasEvenParity(in_byte); } macro ioWrite(addr,val) { *[io]:1 addr = val; } macro ioRead(addr,dest) { dest = *[io]:1 addr; } @if defined(Z180_SEGMENTED) macro push16(val16) { SP = SP - 2; ptr:$(PTRSIZE) = segment(rBBR,SP); *:2 ptr = val16; } macro pop16(ret16) { ptr:$(PTRSIZE) = segment(rBBR,SP); ret16 = *:2 ptr; SP = SP + 2; } macro push8(val8) { SP = SP - 1; ptr:$(PTRSIZE) = segment(rBBR,SP); *:1 ptr = val8; } macro pop8(ret8) { ptr:$(PTRSIZE) = segment(rBBR,SP); ret8 = *:1 ptr; SP = SP + 1; } macro swap(val16) { ptr:$(PTRSIZE) = segment(rBBR,SP); tmp:2 = *:2 ptr; *:2 ptr = val16; val16 = tmp; } macro MemRead(dest,off) { ptr:$(PTRSIZE) = segment(rBBR,off); dest = *:1 ptr; } macro MemStore(off,val) { ptr:$(PTRSIZE) = segment(rBBR,off); *:1 ptr = val; } macro JumpToLoc(off) { ptr:$(PTRSIZE) = segment(rBBR,off); goto [ptr]; } @else macro push16(val16) { SP = SP - 2; *:2 SP = val16; } macro pop16(ret16) { ret16 = *:2 SP; SP = SP + 2; } macro push8(val8) { SP = SP - 1; ptr:$(PTRSIZE) = SP; *:1 ptr = val8; } macro pop8(ret8) { ptr:$(PTRSIZE) = SP; ret8 = *:1 ptr; SP = SP + 1; } macro swap(val16) { ptr:$(PTRSIZE) = SP; tmp:2 = *:2 ptr; *:2 ptr = val16; val16 = tmp; } macro MemRead(dest,off) { ptr:$(PTRSIZE) = off; dest = *:1 ptr; } macro MemStore(off,val) { ptr:$(PTRSIZE) = off; *:1 ptr = val; } macro JumpToLoc(off) { ptr:$(PTRSIZE) = off; goto [ptr]; } @endif ################################################################ @if defined(Z180) Flag: "Flag" is reg0_3 { } @endif @if defined(Z180_SEGMENTED) hlMem8: (HL) is HL { ptr:$(PTRSIZE) = segment(rBBR,HL); export *:1 ptr; } ixMem8: (IX+simm8) is IX & simm8 { off:2 = IX + simm8; ptr:$(PTRSIZE) = segment(rBBR,off); export *:1 ptr; } ixMem8: (IX-val) is IX & simm8 & sign8=1 [ val = -simm8; ] { off:2 = IX + simm8; ptr:$(PTRSIZE) = segment(rBBR,off); export *:1 ptr; } iyMem8: (IY+simm8) is IY & simm8 { off:$(PTRSIZE) = simm8; ptr:$(PTRSIZE) = segment(rBBR,IY); ptr = ptr + off; export *:1 ptr; } iyMem8: (IY-val) is IY & simm8 & sign8=1 [ val = -simm8; ] { off:$(PTRSIZE) = simm8; ptr:$(PTRSIZE) = segment(rBBR,IY); ptr = ptr + off; export *:1 ptr; } @else # if Z180_SEGMENTED @if defined(Z180) hlMem8: (HL) is HL { ptr:$(PTRSIZE) = HL; export *:1 ptr; } @endif ixMem8: (IX+simm8) is IX & simm8 { ptr:$(PTRSIZE) = IX + simm8; export *:1 ptr; } ixMem8: (IX-val) is IX & simm8 & sign8=1 [ val = -simm8; ] { ptr:$(PTRSIZE) = IX + simm8; export *:1 ptr; } iyMem8: (IY+simm8) is IY & simm8 { ptr:$(PTRSIZE) = IY + simm8; export *:1 ptr; } iyMem8: (IY-val) is IY & simm8 & sign8=1 [ val = -simm8; ] { ptr:$(PTRSIZE) = IY + simm8; export *:1 ptr; } @endif # end !Z180_SEGMENTED @if defined(Z180) Addr16: imm16 is imm16 { export *:1 imm16; } Mem8: (imm16) is imm16 { export *:1 imm16; } Mem16: (imm16) is imm16 { export *:2 imm16; } @else Addr16: imm16 is imm16 { export *:1 imm16; } Mem8: (imm16) is imm16 { export *:1 imm16; } Mem16: (imm16) is imm16 { export *:2 imm16; } @endif RelAddr8: loc is simm8 [ loc = inst_next + simm8; ] { export *:1 loc; } RstAddr: loc is bits3_3 [ loc = bits3_3 << 3; ] { export *:1 loc; } @if defined(Z180) IOAddr8: (imm8) is imm8 { export *[const]:2 imm8; } IOAddr8a: (imm8) is assume8bitIOSpace=0 & imm8 { ptr:2 = (zext(A) << 8) + imm8; export ptr; } IOAddr8a: (imm8) is assume8bitIOSpace=1 & imm8 { export *[const]:2 imm8; } IOAddrC: (C) is assume8bitIOSpace=0 & C { ptr:2 = (zext(B) << 8) + zext(C); export ptr; } IOAddrC: (C) is assume8bitIOSpace=1 & C { ptr:2 = zext(C); export ptr; } @else IOAddr8a: (imm8) is imm8 { export *[const]:2 imm8; } IOAddrC: (C) is C { ptr:2 = zext(C); export ptr; } @endif cc: "NZ" is bits3_3=0x0 { c:1 = ($(Z_flag) == 0); export c; } cc: "Z" is bits3_3=0x1 { c:1 = $(Z_flag); export c; } cc: "NC" is bits3_3=0x2 { c:1 = ($(C_flag) == 0); export c; } cc: "C" is bits3_3=0x3 { c:1 = $(C_flag); export c; } cc: "PO" is bits3_3=0x4 { c:1 = ($(PV_flag) == 0); export c; } cc: "PE" is bits3_3=0x5 { c:1 = $(PV_flag); export c; } cc: "P" is bits3_3=0x6 { c:1 = ($(S_flag) == 0); export c; } cc: "M" is bits3_3=0x7 { c:1 = $(S_flag); export c; } cc2: "NZ" is bits3_3=0x4 { c:1 = ($(Z_flag) == 0); export c; } cc2: "Z" is bits3_3=0x5 { c:1 = $(Z_flag); export c; } cc2: "NC" is bits3_3=0x6 { c:1 = ($(C_flag) == 0); export c; } cc2: "C" is bits3_3=0x7 { c:1 = $(C_flag); export c; } ################################################################ :LD reg3_3,reg0_3 is op6_2=0x1 & reg3_3 & reg0_3 { reg3_3 = reg0_3; } :LD reg3_3,imm8 is op6_2=0x0 & reg3_3 & bits0_3=0x6; imm8 { reg3_3 = imm8; } :LD reg3_3,(HL) is op6_2=0x1 & reg3_3 & bits0_3=0x6 & HL { MemRead(reg3_3,HL); } :LD reg3_3,ixMem8 is op0_8=0xdd; op6_2=0x1 & reg3_3 & bits3_3!=0x6 & bits0_3=0x6; ixMem8 { reg3_3 = ixMem8; } :LD reg3_3,iyMem8 is op0_8=0xfd; op6_2=0x1 & reg3_3 & bits3_3!=0x6 & bits0_3=0x6; iyMem8 { reg3_3 = iyMem8; } :LD (HL),reg0_3 is op6_2=0x1 & bits3_3=0x6 & reg0_3 & HL { MemStore(HL,reg0_3); } :LD ixMem8,reg0_3 is op0_8=0xdd; op6_2=0x1 & bits3_3=0x6 & reg0_3 & bits0_3!=0x6; ixMem8 { ixMem8 = reg0_3; } :LD iyMem8,reg0_3 is op0_8=0xfd; op6_2=0x1 & bits3_3=0x6 & reg0_3 & bits0_3!=0x6; iyMem8 { iyMem8 = reg0_3; } :LD (HL),imm8 is op0_8=0x36 & HL; imm8 { tmp:1 = imm8; MemStore(HL,tmp); } :LD ixMem8,imm8 is op0_8=0xdd; op6_2=0x0 & bits3_3=0x6 & bits0_3=0x6; ixMem8; imm8 { ixMem8 = imm8; } :LD iyMem8,imm8 is op0_8=0xfd; op6_2=0x0 & bits3_3=0x6 & bits0_3=0x6; iyMem8; imm8 { iyMem8 = imm8; } :LD A,(BC) is op0_8=0x0a & A & BC { MemRead(A,BC); } :LD A,(DE) is op0_8=0x1a & A & DE { MemRead(A,DE); } :LD A,Mem8 is op0_8=0x3a & A; Mem8 { A = Mem8; } :LD (BC),A is op0_8=0x2 & BC & A { MemStore(BC,A); } :LD (DE),A is op0_8=0x12 & DE & A { MemStore(DE,A); } :LD Mem8,A is op0_8=0x32 & A; Mem8 { Mem8 = A; } :LD A,I is op0_8=0xed & A & I; op0_8=0x57 { local val = I; A = val; setResultFlags(val); $(H_flag) = 0; # $(PV_flag) = IFF2; $(N_flag) = 0; } :LD A,R is op0_8=0xed & A & R; op0_8=0x5f { local val = R; A = val; setResultFlags(val); $(H_flag) = 0; # $(PV_flag) = IFF2; $(N_flag) = 0; } :LD I,A is op0_8=0xed & A & I; op0_8=0x47 { I = A; } :LD R,A is op0_8=0xed & A & R; op0_8=0x4f { R = A; } :LD dRegPair4_2,imm16 is op6_2=0x0 & dRegPair4_2 & bits0_4=0x1; imm16 { dRegPair4_2 = imm16; } :LD IX,imm16 is op0_8=0xdd & IX; op0_8=0x21; imm16 { IX = imm16; } :LD IY,imm16 is op0_8=0xfd & IY; op0_8=0x21; imm16 { IY = imm16; } :LD HL,Mem16 is op0_8=0x2a & HL; Mem16 { HL = Mem16; } :LD dRegPair4_2,Mem16 is op0_8=0xed; op6_2=0x1 & dRegPair4_2 & bits0_4=0xb; Mem16 { dRegPair4_2 = Mem16; } :LD IX,Mem16 is op0_8=0xdd & IX; op0_8=0x2a; Mem16 { IX = Mem16; } :LD IY,Mem16 is op0_8=0xfd & IY; op0_8=0x2a; Mem16 { IY = Mem16; } :LD Mem16,HL is op0_8=0x22 & HL; Mem16 { Mem16 = HL; } :LD Mem16,dRegPair4_2 is op0_8=0xed; op6_2=0x1 & dRegPair4_2 & bits0_4=0x3; Mem16 { Mem16 = dRegPair4_2; } :LD Mem16,IX is op0_8=0xdd & IX; op0_8=0x22; Mem16 { Mem16 = IX; } :LD Mem16,IY is op0_8=0xfd & IY; op0_8=0x22; Mem16 { Mem16 = IY; } :LD SP,HL is op0_8=0xf9 & SP & HL { SP = HL; } :LD SP,IX is op0_8=0xdd & SP & IX; op0_8=0xf9 { SP = IX; } :LD SP,IY is op0_8=0xfd & SP & IY; op0_8=0xf9 { SP = IY; } :PUSH qRegPair4_2 is op6_2=0x3 & qRegPair4_2 & bits0_4=0x5 { push16(qRegPair4_2); } :PUSH IX is op0_8=0xdd & IX; op0_8=0xe5 { push16(IX); } :PUSH IY is op0_8=0xfd & IY; op0_8=0xe5 { push16(IY); } :POP qRegPair4_2 is op6_2=0x3 & qRegPair4_2 & bits0_4=0x1 { pop16(qRegPair4_2); } :POP IX is op0_8=0xdd & IX; op0_8=0xe1 { pop16(IX); } # ?? Manual appears to have incorrect encoding :POP IY is op0_8=0xfd & IY; op0_8=0xe1 { pop16(IY); } :EX DE,HL is op0_8=0xeb & DE & HL { tmp:2 = DE; DE = HL; HL = tmp; } :EX AF, AF_ is op0_8=0x08 & AF & AF_ { tmp:2 = AF; AF = AF_; AF_ = tmp; } :EXX is op0_8=0xd9 { tmp:2 = BC; BC = BC_; BC_ = tmp; tmp = DE; DE = DE_; DE_ = tmp; tmp = HL; HL = HL_; HL_ = tmp; } :EX (SP),HL is op0_8=0xe3 & SP & HL { swap(HL); } :EX (SP),IX is op0_8=0xdd & SP & IX; op0_8=0xe3 { swap(IX); } :EX (SP),IY is op0_8=0xfd & SP & IY; op0_8=0xe3 { swap(IY); } :LDI is op0_8=0xed; op0_8=0xa0 { val:1 = 0; local inloc = HL; local outloc = DE; MemRead(val,inloc); MemStore(outloc,val); DE = outloc + 1; HL = inloc + 1; local test = BC - 1; BC = test; $(H_flag) = 0; $(PV_flag) = (test != 0); $(N_flag) = 0; } :LDIR is op0_8=0xed; op0_8=0xb0 { val:1 = 0; local inloc = HL; local outloc = DE; MemRead(val,inloc); MemStore(outloc,val); DE = outloc + 1; HL = inloc + 1; local test = BC - 1; BC = test; if (test != 0) goto inst_start; $(H_flag) = 0; $(PV_flag) = 0; $(N_flag) = 0; } :LDD is op0_8=0xed; op0_8=0xa8 { val:1 = 0; local inloc = HL; local outloc = DE; MemRead(val,inloc); MemStore(outloc,val); DE = outloc - 1; HL = inloc - 1; local test = BC - 1; BC = test; $(H_flag) = 0; $(PV_flag) = (test != 0); $(N_flag) = 0; } :LDDR is op0_8=0xed; op0_8=0xb8 { val:1 = 0; local inloc = HL; local outloc = DE; MemRead(val,inloc); MemStore(outloc,val); DE = outloc - 1; HL = inloc - 1; local test = BC - 1; BC = test; if (test != 0) goto inst_start; $(H_flag) = 0; $(PV_flag) = 0; $(N_flag) = 0; } :CPI is op0_8=0xed; op0_8=0xa1 { val:1 = 0; local loc = HL; MemRead(val,loc); local a_temp = A; cmp:1 = a_temp - val; setResultFlags(cmp); HL = loc + 1; local test = BC - 1; BC = test; carries:1 = (~a_temp & val) | (val & cmp) | (cmp & ~a_temp); $(H_flag) = (carries & 0b00001000) != 0; $(PV_flag) = (test != 0); $(N_flag) = 1; } :CPIR is op0_8=0xed; op0_8=0xb1 { val:1 = 0; local loc = HL; MemRead(val,loc); local a_temp = A; cmp:1 = a_temp - val; setResultFlags(cmp); HL = loc + 1; local test = BC - 1; BC = test; if (cmp != 0 || test != 0) goto inst_start; carries:1 = (~a_temp & val) | (val & cmp) | (cmp & ~a_temp); $(H_flag) = (carries & 0b00001000) != 0; $(PV_flag) = (test != 0); $(N_flag) = 1; } :CPD is op0_8=0xed; op0_8=0xa9 { val:1 = 0; local loc = HL; MemRead(val,loc); local a_temp = A; cmp:1 = a_temp - val; setResultFlags(cmp); HL = loc - 1; local test = BC - 1; BC = test; carries:1 = (~a_temp & val) | (val & cmp) | (cmp & ~a_temp); $(H_flag) = (carries & 0b00001000) != 0; $(PV_flag) = (test != 0); $(N_flag) = 1; } :CPDR is op0_8=0xed; op0_8=0xb9 { val:1 = 0; local loc = HL; MemRead(val,loc); local a_temp = A; cmp:1 = a_temp - val; setResultFlags(cmp); HL = loc - 1; local test = BC - 1; BC = test; if (cmp != 0 || test != 0) goto inst_start; carries:1 = (~a_temp & val) | (val & cmp) | (cmp & ~a_temp); $(H_flag) = (carries & 0b00001000) != 0; $(PV_flag) = (test != 0); $(N_flag) = 1; } :ADD A, reg0_3 is op6_2=0x2 & bits3_3=0x0 & reg0_3 & A { local a_temp = A; local reg_temp = reg0_3; additionFlags(a_temp, reg_temp); a_temp= a_temp + reg0_3; setResultFlags(a_temp); A = a_temp; } :ADD A, imm8 is op0_8=0xc6; imm8 & A { local a_temp = A; additionFlags(a_temp, imm8); a_temp = a_temp + imm8; setResultFlags(a_temp); A = a_temp; } :ADD A, (HL) is op0_8=0x86 & HL & A { val:1 = 0; MemRead(val,HL); local a_temp = A; additionFlags(a_temp, val); a_temp = a_temp + val; setResultFlags(a_temp); A = a_temp; } :ADD A, ixMem8 is op0_8=0xdd; op0_8=0x86; ixMem8 & A { val:1 = ixMem8; local a_temp = A; additionFlags(a_temp, val); a_temp = a_temp + val; setResultFlags(a_temp); A = a_temp; } :ADD A, iyMem8 is op0_8=0xfd; op0_8=0x86; iyMem8 & A { val:1 = iyMem8; local a_temp = A; additionFlags(a_temp, val); a_temp = a_temp + val; setResultFlags(a_temp); A = a_temp; } :ADC A, reg0_3 is op6_2=0x2 & bits3_3=0x1 & reg0_3 & A { local a_temp = A; local r_temp = reg0_3; additionWithCarry(a_temp, r_temp, a_temp); setResultFlags(a_temp); A = a_temp; } :ADC A, imm8 is op0_8=0xce; imm8 & A { val:1 = imm8; local a_temp = A; additionWithCarry(a_temp, val, a_temp); setResultFlags(a_temp); A = a_temp; } :ADC A, (HL) is op0_8=0x8e & HL & A { val:1 = 0; MemRead(val,HL); local a_temp = A; additionWithCarry(a_temp, val, a_temp); setResultFlags(a_temp); A = a_temp; } :ADC A, ixMem8 is op0_8=0xdd; op0_8=0x8e; ixMem8 & A{ val:1 = ixMem8; MemRead(val,HL); local a_temp = A; additionWithCarry(a_temp, val, a_temp); setResultFlags(a_temp); A = a_temp; } :ADC A, iyMem8 is op0_8=0xfd; op0_8=0x8e; iyMem8 & A { val:1 = iyMem8; MemRead(val,HL); local a_temp = A; additionWithCarry(a_temp, val, a_temp); setResultFlags(a_temp); A = a_temp; } :SUB reg0_3 is op6_2=0x2 & bits3_3=0x2 & reg0_3 { local a_temp = A; local r_temp = reg0_3; subtractionFlags(a_temp, r_temp); a_temp = a_temp - r_temp; setResultFlags(a_temp); a_temp = A; } :SUB imm8 is op0_8=0xd6; imm8 { local a_temp = A; subtractionFlags(a_temp, imm8); a_temp = a_temp - imm8; setResultFlags(a_temp); A = a_temp; } :SUB (HL) is op0_8=0x96 & HL { val:1 = 0; MemRead(val,HL); local a_temp = A; subtractionFlags(a_temp, val); a_temp = a_temp - val; setResultFlags(a_temp); A = a_temp; } :SUB ixMem8 is op0_8=0xdd; op0_8=0x96; ixMem8 { val:1 = ixMem8; local a_temp = A; subtractionFlags(a_temp, val); a_temp = a_temp - val; setResultFlags(a_temp); A = a_temp; } :SUB iyMem8 is op0_8=0xfd; op0_8=0x96; iyMem8 { val:1 = iyMem8; local a_temp = A; subtractionFlags(a_temp, val); a_temp = a_temp - val; setResultFlags(a_temp); A = a_temp; } :SBC A, reg0_3 is op6_2=0x2 & bits3_3=0x3 & reg0_3 & A { local a_temp = A; local r_temp = reg0_3; subtractionWithCarry(a_temp, r_temp, a_temp); setResultFlags(a_temp); A = a_temp; } :SBC A, imm8 is op0_8=0xde; imm8 & A { local a_temp = A; subtractionWithCarry(a_temp, imm8, a_temp); setResultFlags(a_temp); A = a_temp; } :SBC A, (HL) is op0_8=0x9e & HL & A { val:1 = 0; MemRead(val,HL); local a_temp = A; subtractionWithCarry(a_temp, val, a_temp); setResultFlags(a_temp); A = a_temp; } :SBC A, ixMem8 is op0_8=0xdd; op0_8=0x9e; ixMem8 & A { val:1 = ixMem8; local a_temp = A; subtractionWithCarry(a_temp, val, a_temp); setResultFlags(a_temp); A = a_temp; } :SBC A, iyMem8 is op0_8=0xfd; op0_8=0x9e; iyMem8 & A { val:1 = iyMem8; local a_temp = A; subtractionWithCarry(a_temp, val, a_temp); setResultFlags(a_temp); A = a_temp; } :AND reg0_3 is op6_2=0x2 & bits3_3=0x4 & reg0_3 { local a_temp = A; $(H_flag) = 1; $(C_flag) = 0; $(N_flag) = 0; a_temp = a_temp & reg0_3; setResultFlags(a_temp); setParity(a_temp); A = a_temp; } :AND imm8 is op0_8=0xe6; imm8 { local a_temp = A; $(H_flag) = 1; $(C_flag) = 0; $(N_flag) = 0; a_temp = a_temp & imm8; setResultFlags(a_temp); setParity(a_temp); A = a_temp; } :AND (HL) is op0_8=0xa6 & HL { val:1 = 0; MemRead(val,HL); local a_temp = A; $(H_flag) = 1; $(C_flag) = 0; $(N_flag) = 0; a_temp = a_temp & val; setResultFlags(a_temp); setParity(a_temp); A = a_temp; } :AND ixMem8 is op0_8=0xdd; op0_8=0xa6; ixMem8 { local a_temp = A; $(H_flag) = 1; $(C_flag) = 0; $(N_flag) = 0; a_temp = a_temp & ixMem8; setResultFlags(a_temp); setParity(a_temp); A = a_temp; } :AND iyMem8 is op0_8=0xfd; op0_8=0xa6; iyMem8 { local a_temp = A; $(H_flag) = 1; $(C_flag) = 0; $(N_flag) = 0; a_temp = a_temp & iyMem8; setResultFlags(a_temp); setParity(a_temp); A = a_temp; } :OR reg0_3 is op6_2=0x2 & bits3_3=0x6 & reg0_3 { local a_temp = A; $(H_flag) = 0; $(C_flag) = 0; $(N_flag) = 0; a_temp = a_temp | reg0_3; setResultFlags(a_temp); setParity(a_temp); A = a_temp; } :OR imm8 is op0_8=0xf6; imm8 { local a_temp = A; $(H_flag) = 0; $(C_flag) = 0; $(N_flag) = 0; a_temp = a_temp | imm8; setResultFlags(a_temp); setParity(a_temp); A = a_temp; } :OR (HL) is op0_8=0xb6 & HL { val:1 = 0; MemRead(val,HL); local a_temp = A; $(H_flag) = 0; $(C_flag) = 0; $(N_flag) = 0; a_temp = a_temp | val; setResultFlags(a_temp); setParity(a_temp); A = a_temp; } :OR ixMem8 is op0_8=0xdd; op0_8=0xb6; ixMem8 { local a_temp = A; $(H_flag) = 0; $(C_flag) = 0; $(N_flag) = 0; a_temp = a_temp | ixMem8; setResultFlags(a_temp); setParity(a_temp); A = a_temp; } :OR iyMem8 is op0_8=0xfd; op0_8=0xb6; iyMem8 { local a_temp = A; $(H_flag) = 0; $(C_flag) = 0; $(N_flag) = 0; a_temp = a_temp | iyMem8; setResultFlags(a_temp); setParity(a_temp); A = a_temp; } :XOR reg0_3 is op6_2=0x2 & bits3_3=0x5 & reg0_3 { local a_temp = A; $(H_flag) = 0; $(C_flag) = 0; $(N_flag) = 0; a_temp = a_temp ^ reg0_3; setResultFlags(a_temp); setParity(a_temp); A = a_temp; } :XOR imm8 is op0_8=0xee; imm8 { local a_temp = A; $(H_flag) = 0; $(C_flag) = 0; $(N_flag) = 0; a_temp = a_temp ^ imm8; setResultFlags(a_temp); setParity(a_temp); A = a_temp; } :XOR (HL) is op0_8=0xae & HL { val:1 = 0; MemRead(val,HL); local a_temp = A; $(H_flag) = 0; $(C_flag) = 0; $(N_flag) = 0; a_temp = a_temp ^ val; setResultFlags(a_temp); setParity(a_temp); A = a_temp; } :XOR ixMem8 is op0_8=0xdd; op0_8=0xae; ixMem8 { local a_temp = A; $(H_flag) = 0; $(C_flag) = 0; $(N_flag) = 0; a_temp = a_temp ^ ixMem8; setResultFlags(a_temp); setParity(a_temp); A = a_temp; } :XOR iyMem8 is op0_8=0xfd; op0_8=0xae; iyMem8 { local a_temp = A; $(H_flag) = 0; $(C_flag) = 0; $(N_flag) = 0; a_temp = a_temp ^ iyMem8; setResultFlags(a_temp); setParity(a_temp); A = a_temp; } :CP reg0_3 is op6_2=0x2 & bits3_3=0x7 & reg0_3 { local a_temp = A; local r_temp = reg0_3; cmp:1 = a_temp - r_temp; subtractionFlags(a_temp, r_temp); setResultFlags(cmp); } :CP imm8 is op0_8=0xfe; imm8 { local a_temp = A; cmp:1 = a_temp - imm8; subtractionFlags(a_temp, imm8); setResultFlags(cmp); } :CP (HL) is op0_8=0xbe & HL { val:1 = 0; MemRead(val,HL); local a_temp = A; cmp:1 = a_temp - val; subtractionFlags(a_temp, val); setResultFlags(cmp); } :CP ixMem8 is op0_8=0xdd; op0_8=0xbe; ixMem8 { val:1 = ixMem8; local a_temp = A; cmp:1 = a_temp - val; subtractionFlags(a_temp, val); setResultFlags(cmp); } :CP iyMem8 is op0_8=0xfd; op0_8=0xbe; iyMem8 { val:1 = iyMem8; local a_temp = A; cmp:1 = a_temp - val; subtractionFlags(a_temp, val); setResultFlags(cmp); } :INC reg3_3 is op6_2=0x0 & reg3_3 & bits0_3=0x4 { local r_temp = reg3_3; additionFlags(r_temp, 1); r_temp = r_temp + 1; reg3_3 = r_temp; setResultFlags(r_temp); } :INC (HL) is op0_8=0x34 & HL { val:1 = 0; MemRead(val,HL); val_temp:1 = val; val = val + 1; MemStore(HL,val); setResultFlags(val); additionFlagsNoC(val_temp, 1); } :INC ixMem8 is op0_8=0xdd; op0_8=0x34; ixMem8 { val:1 = ixMem8; val_temp:1 = val; val = val + 1; ixMem8 = val; setResultFlags(val); additionFlagsNoC(val_temp, 1); } :INC iyMem8 is op0_8=0xfd; op0_8=0x34; iyMem8 { val:1 = iyMem8; val_temp:1 = val; val = val + 1; iyMem8 = val; setResultFlags(val); additionFlagsNoC(val_temp, 1); } :DEC reg3_3 is op6_2=0x0 & reg3_3 & bits0_3=0x5 { local r_temp = reg3_3; subtractionFlagsNoC(r_temp, 1); r_temp = r_temp - 1; reg3_3 = r_temp; setResultFlags(r_temp); } :DEC (HL) is op0_8=0x35 & HL { val:1 = 0; MemRead(val,HL); val_temp:1 = val; val = val - 1; MemStore(HL,val); subtractionFlagsNoC(val_temp, 1); setResultFlags(val); } :DEC ixMem8 is op0_8=0xdd; op0_8=0x35; ixMem8 { val:1 = ixMem8; val_temp:1 = val; val = val - 1; ixMem8 = val; subtractionFlagsNoC(val_temp, 1); setResultFlags(val); } :DEC iyMem8 is op0_8=0xfd; op0_8=0x35; iyMem8 { val:1 = iyMem8; val_temp:1 = val; val = val - 1; iyMem8 = val; subtractionFlagsNoC(val_temp, 1); setResultFlags(val); } :DAA is op0_8=0x27 { local a_temp = A; if (DECOMPILE_MODE) goto ; HN:1 = a_temp >> 4; # high nibble LN:1 = a_temp & 0xF; # low nibbble # # If (C and H are both 0, and both nibbles are in range[0,9] no # adjustment is needed. # if (($(C_flag) == 0) & ($(H_flag) == 0) & (HN <= 0x9) & (LN <= 0x9)) goto ; if ($(N_flag) == 1) goto ; #, in effect if ($(C_flag) == 0 & $(H_flag) == 0 & HN <= 0x8 & LN >= 0xA & LN <= 0xF) goto ; if ($(C_flag) == 0 & $(H_flag) == 1 & HN <= 0x9 & LN <= 0x3) goto ; if ($(C_flag) == 0 & $(H_flag) == 0 & HN >= 0xA & HN <= 0xF & LN <= 0x9) goto ; if ($(C_flag) == 0 & $(H_flag) == 0 & HN >= 0x9 & HN <= 0xF & LN >= 0xA & LN <= 0xF) goto ; if ($(C_flag) == 0 & $(H_flag) == 1 & HN >= 0xA & HN <= 0xF & LN <= 0x3) goto ; if ($(C_flag) == 1 & $(H_flag) == 0 & HN <= 0x2 & LN <= 0x9) goto ; if ($(C_flag) == 1 & $(H_flag) == 0 & HN <= 0x2 & LN >= 0xA & LN <= 0xF) goto ; if ($(C_flag) == 1 & $(H_flag) == 1 & HN <= 0x3 & LN <= 0x3) goto ; goto ; # Cases for addition # # Isn't used a_temp = a_temp + 0x06; goto ; a_temp = a_temp + 0x06; goto ; a_temp = a_temp + 0x60; $(C_flag) = 1; goto ; a_temp = a_temp + 0x66; $(C_flag) = 1; goto ; a_temp = a_temp + 0x66; $(C_flag) = 1; goto ; a_temp = a_temp + 0x60; goto ; a_temp = a_temp + 0x66; goto ; a_temp = a_temp + 0x66; goto ; # Cases for subtraction #if ($(C_flag) == 0 & $(H_flag) == 0 & HN >= 0x0 & HN <= 0x9 & LN >= 0x0 & LN <= 0x9) goto ; if ($(C_flag) == 0 & $(H_flag) == 1 & HN <= 0x8 & LN >= 0x6 & LN <= 0xF) goto ; if ($(C_flag) == 1 & $(H_flag) == 0 & HN >= 0x7 & HN <= 0xF & LN <= 0x9) goto ; if ($(C_flag) == 1 & $(H_flag) == 1 & HN >= 0x6 & HN <= 0xF & LN >= 0x6 & LN <= 0xF) goto ; goto ; # # Isn't used a_temp = a_temp + 0xFA; goto ; a_temp = a_temp + 0xA0; goto ; a_temp = a_temp + 0x9A; setResultFlags(a_temp); setParity(a_temp); A = a_temp; goto ; a_temp = BCDadjust(a_temp, $(C_flag), $(H_flag)); $(C_flag) = BCDadjustCarry(a_temp, $(C_flag), $(H_flag)); setResultFlags(a_temp); $(PV_flag) = hasEvenParity(a_temp); A = a_temp; } :CPL is op0_8=0x2f { A = ~A; $(H_flag) = 1; $(N_flag) = 1; } :NEG is op0_8=0xed; op0_8=0x44 { local a_temp = A; subtractionFlags(0, a_temp); a_temp = -a_temp; A = a_temp; setResultFlags(a_temp); } :CCF is op0_8=0x3f { $(C_flag) = !$(C_flag); $(N_flag) = 0; } :SCF is op0_8=0x37 { $(C_flag) = 1; $(H_flag) = 0; $(N_flag) = 0; } :NOP is op0_8=0x0 { } :HALT is op0_8=0x76 { halt(); } :DI is op0_8=0xf3 { # IFF1 = 0; # IFF2 = 0; disableMaskableInterrupts(); } :EI is op0_8=0xfb { # IFF1 = 1; # IFF2 = 1; enableMaskableInterrupts(); } :IM 0 is op0_8=0xed; op0_8=0x46 { setInterruptMode(0:1); } :IM 1 is op0_8=0xed; op0_8=0x56 { setInterruptMode(1:1); } :IM 2 is op0_8=0xed; op0_8=0x5e { setInterruptMode(2:1); } :ADD HL,sRegPair4_2 is op6_2=0x0 & sRegPair4_2 & bits0_4=0x9 & HL { local HL_temp = HL; local Reg_temp = sRegPair4_2; additionFlagsNoPV(HL_temp, Reg_temp); HL = HL_temp + Reg_temp; } :ADC HL,sRegPair4_2 is op0_8=0xed & HL; op6_2=0x1 & sRegPair4_2 & bits0_4=0xa { local HL_temp = HL; local Reg_temp = sRegPair4_2; additionFlagsNoPV(HL_temp, Reg_temp); HL_temp = HL_temp + Reg_temp + zext($(C_flag)); setResultFlags(HL_temp); HL = HL_temp; } :SBC HL,sRegPair4_2 is op0_8=0xed & HL; op6_2=0x1 & sRegPair4_2 & bits0_4=0x2 { local HL_temp = HL; local Reg_temp = sRegPair4_2; subtractionWithCarry(HL_temp, sRegPair4_2, HL_temp); setResultFlags(HL_temp); HL = HL_temp; } :ADD IX,pRegPair4_2 is op0_8=0xdd & IX; op6_2=0x0 & pRegPair4_2 & bits0_4=0x9 { local IX_temp = IX; local Reg_temp = pRegPair4_2; additionFlagsNoPV(IX_temp, Reg_temp); IX = IX_temp + pRegPair4_2; } :ADD IY,pRegPair4_2 is op0_8=0xfd & IY; op6_2=0x0 & pRegPair4_2 & bits0_4=0x9 { local IY_temp = IY; local Reg_temp = pRegPair4_2; additionFlagsNoPV(IY_temp, Reg_temp); IY = IY_temp + Reg_temp; } :INC sRegPair4_2 is op6_2=0x0 & sRegPair4_2 & bits0_4=0x3 { sRegPair4_2 = sRegPair4_2 + 1; } :INC IX is op0_8=0xdd & IX; op0_8=0x23 { IX = IX + 1; } :INC IY is op0_8=0xfd & IY; op0_8=0x23 { IY = IY + 1; } :DEC sRegPair4_2 is op6_2=0x0 & sRegPair4_2 & bits0_4=0xb { sRegPair4_2 = sRegPair4_2 - 1; } :DEC IX is op0_8=0xdd & IX; op0_8=0x2b { IX = IX - 1; } :DEC IY is op0_8=0xfd & IY; op0_8=0x2b { IY = IY - 1; } :RLCA is op0_8=0x07 { local a_temp = A; $(C_flag) = (a_temp >> 7); A = (a_temp << 1) | $(C_flag); $(H_flag) = 0; $(N_flag) = 0; } :RLA is op0_8=0x17 { local a_temp = A; nextC:1 = (a_temp >> 7); A = (a_temp << 1) | $(C_flag); $(C_flag) = nextC; $(H_flag) = 0; $(N_flag) = 0; } :RRCA is op0_8=0x0f { local a_temp = A; $(C_flag) = (a_temp & 1); A = (a_temp >> 1) | ($(C_flag) << 7); $(H_flag) = 0; $(N_flag) = 0; } :RRA is op0_8=0x1f { local a_temp = A; nextC:1 = (a_temp & 1); A = (a_temp >> 1) | ($(C_flag) << 7); $(C_flag) = nextC; $(H_flag) = 0; $(N_flag) = 0; } :RLC reg0_3 is op0_8=0x0cb; op6_2=0x0 & bits3_3=0x0 & reg0_3 { local val = reg0_3; $(C_flag) = (val >> 7); val = (val << 1) | $(C_flag); reg0_3 = val; setResultFlags(val); $(H_flag) = 0; setParity(val); $(N_flag) = 0; } :RLC (HL) is op0_8=0x0cb & HL; op0_8=0x06 { val:1 = 0; MemRead(val,HL); $(C_flag) = (val >> 7); val = (val << 1) | $(C_flag); setResultFlags(val); MemStore(HL,val); $(H_flag) = 0; setParity(val); $(N_flag) = 0; } :RLC ixMem8 is op0_8=0x0dd; op0_8=0xcb; ixMem8; op0_8=0x06 { val:1 = ixMem8; $(C_flag) = (val >> 7); val = (val << 1) | $(C_flag); setResultFlags(val); ixMem8 = val; $(H_flag) = 0; $(N_flag) = 0; } :RLC iyMem8 is op0_8=0x0fd; op0_8=0xcb; iyMem8; op0_8=0x06 { val:1 = iyMem8; $(C_flag) = (val >> 7); val = (val << 1) | $(C_flag); setResultFlags(val); iyMem8 = val; $(H_flag) = 0; setParity(val); $(N_flag) = 0; } :RL reg0_3 is op0_8=0x0cb; op6_2=0x0 & bits3_3=0x2 & reg0_3 { local r_temp = reg0_3; nextC:1 = (r_temp >> 7); r_temp = (r_temp << 1) | $(C_flag); reg0_3 = r_temp; $(C_flag) = nextC; setResultFlags(r_temp); $(H_flag) = 0; setParity(r_temp); $(N_flag) = 0; } :RL (HL) is op0_8=0x0cb & HL; op0_8=0x16 { val:1 = 0; MemRead(val,HL); nextC:1 = (val >> 7); val = (val << 1) | $(C_flag); $(C_flag) = nextC; setResultFlags(val); MemStore(HL,val); $(H_flag) = 0; setParity(val); $(N_flag) = 0; } :RL ixMem8 is op0_8=0x0dd; op0_8=0xcb; ixMem8; op0_8=0x16 { val:1 = ixMem8; nextC:1 = (val >> 7); val = (val << 1) | $(C_flag); $(C_flag) = nextC; setResultFlags(val); ixMem8 = val; $(H_flag) = 0; setParity(val); $(N_flag) = 0; } :RL iyMem8 is op0_8=0x0fd; op0_8=0xcb; iyMem8; op0_8=0x16 { val:1 = iyMem8; nextC:1 = (val >> 7); val = (val << 1) | $(C_flag); $(C_flag) = nextC; setResultFlags(val); iyMem8 = val; $(H_flag) = 0; setParity(val); $(N_flag) = 0; } :RRC reg0_3 is op0_8=0x0cb; op6_2=0x0 & bits3_3=0x1 & reg0_3 { local r_temp = reg0_3; $(C_flag) = (r_temp & 1); r_temp = (r_temp >> 1) | ($(C_flag) << 7); reg0_3 = r_temp; setResultFlags(r_temp); $(H_flag) = 0; setParity(r_temp); $(N_flag) = 0; } :RRC (HL) is op0_8=0x0cb & HL; op0_8=0x0e { val:1 = 0; MemRead(val,HL); $(C_flag) = (val & 1); val = (val >> 1) | ($(C_flag) << 7); setResultFlags(val); MemStore(HL,val); $(H_flag) = 0; setParity(val); $(N_flag) = 0; } :RRC ixMem8 is op0_8=0x0dd; op0_8=0xcb; ixMem8; op0_8=0x0e { val:1 = ixMem8; $(C_flag) = (val & 1); val = (val >> 1) | ($(C_flag) << 7); setResultFlags(val); ixMem8 = val; $(H_flag) = 0; setParity(val); $(N_flag) = 0; } :RRC iyMem8 is op0_8=0x0fd; op0_8=0xcb; iyMem8; op0_8=0x0e { val:1 = iyMem8; $(C_flag) = (val & 1); val = (val >> 1) | ($(C_flag) << 7); setResultFlags(val); iyMem8 = val; $(H_flag) = 0; setParity(val); $(N_flag) = 0; } :RR reg0_3 is op0_8=0x0cb; op6_2=0x0 & bits3_3=0x3 & reg0_3 { local r_temp = reg0_3; nextC:1 = (r_temp & 1); r_temp = (r_temp >> 1) | ($(C_flag) << 7); reg0_3 = r_temp; $(C_flag) = nextC; setResultFlags(r_temp); $(H_flag) = 0; setParity(r_temp); $(N_flag) = 0; } :RR (HL) is op0_8=0x0cb & HL; op0_8=0x1e { val:1 = 0; MemRead(val,HL); nextC:1 = (val & 1); val = (val >> 1) | ($(C_flag) << 7); $(C_flag) = nextC; setResultFlags(val); MemStore(HL,val); $(H_flag) = 0; setParity(val); $(N_flag) = 0; } :RR ixMem8 is op0_8=0x0dd; op0_8=0xcb; ixMem8; op0_8=0x1e { val:1 = ixMem8; nextC:1 = (val & 1); val = (val >> 1) | ($(C_flag) << 7); $(C_flag) = nextC; setResultFlags(val); ixMem8 = val; $(H_flag) = 0; setParity(val); $(N_flag) = 0; } :RR iyMem8 is op0_8=0x0fd; op0_8=0xcb; iyMem8; op0_8=0x1e { val:1 = iyMem8; nextC:1 = (val & 1); val = (val >> 1) | ($(C_flag) << 7); $(C_flag) = nextC; setResultFlags(val); iyMem8 = val; $(H_flag) = 0; setParity(val); $(N_flag) = 0; } :SLA reg0_3 is op0_8=0x0cb; op6_2=0x0 & bits3_3=0x4 & reg0_3 { local r_temp = reg0_3; $(C_flag) = (r_temp >> 7); r_temp = r_temp << 1; reg0_3 = r_temp; setResultFlags(r_temp); $(H_flag) = 0; setParity(r_temp); $(N_flag) = 0; } :SLA (HL) is op0_8=0x0cb & HL; op0_8=0x26 { val:1 = 0; MemRead(val,HL); $(C_flag) = (val >> 7); val = val << 1; setResultFlags(val); MemStore(HL,val); $(H_flag) = 0; setParity(val); $(N_flag) = 0; } :SLA ixMem8 is op0_8=0x0dd; op0_8=0xcb; ixMem8; op0_8=0x26 { val:1 = ixMem8; $(C_flag) = (val >> 7); val = val << 1; setResultFlags(val); ixMem8 = val; $(H_flag) = 0; setParity(val); $(N_flag) = 0; } :SLA iyMem8 is op0_8=0x0fd; op0_8=0xcb; iyMem8; op0_8=0x26 { val:1 = iyMem8; $(C_flag) = (val >> 7); val = val << 1; setResultFlags(val); iyMem8 = val; $(H_flag) = 0; setParity(val); $(N_flag) = 0; } :SRA reg0_3 is op0_8=0x0cb; op6_2=0x0 & bits3_3=0x5 & reg0_3 { local _val = reg0_3; $(C_flag) = (_val & 1); _val = _val s>> 1; reg0_3 = _val; setResultFlags(_val); $(H_flag) = 0; setParity(_val); $(N_flag) = 0; } :SRA (HL) is op0_8=0x0cb & HL; op0_8=0x2e { val:1 = 0; MemRead(val,HL); $(C_flag) = (val & 1); val = val s>> 1; setResultFlags(val); MemStore(HL,val); $(H_flag) = 0; setParity(val); $(N_flag) = 0; } :SRA ixMem8 is op0_8=0x0dd; op0_8=0xcb; ixMem8; op0_8=0x2e { val:1 = ixMem8; $(C_flag) = (val & 1); val = val s>> 1; setResultFlags(val); ixMem8 = val; $(H_flag) = 0; setParity(val); $(N_flag) = 0; } :SRA iyMem8 is op0_8=0x0fd; op0_8=0xcb; iyMem8; op0_8=0x2e { val:1 = iyMem8; $(C_flag) = (val & 1); val = val s>> 1; setResultFlags(val); iyMem8 = val; $(H_flag) = 0; setParity(val); $(N_flag) = 0; } :SRL reg0_3 is op0_8=0x0cb; op6_2=0x0 & bits3_3=0x7 & reg0_3 { local val = reg0_3; $(C_flag) = (val & 1); val = val >> 1; reg0_3 = val; setResultFlags(val); $(H_flag) = 0; setParity(val); $(N_flag) = 0; } :SRL (HL) is op0_8=0x0cb & HL; op0_8=0x3e { val:1 = 0; MemRead(val,HL); $(C_flag) = (val & 1); val = val >> 1; setResultFlags(val); MemStore(HL,val); $(H_flag) = 0; setParity(val); $(N_flag) = 0; } :SRL ixMem8 is op0_8=0x0dd; op0_8=0xcb; ixMem8; op0_8=0x3e { val:1 = ixMem8; $(C_flag) = (val & 1); val = val >> 1; setResultFlags(val); ixMem8 = val; $(H_flag) = 0; setParity(val); $(N_flag) = 0; } :SRL iyMem8 is op0_8=0x0fd; op0_8=0xcb; iyMem8; op0_8=0x3e { val:1 = iyMem8; $(C_flag) = (val & 1); val = val >> 1; setResultFlags(val); iyMem8 = val; $(H_flag) = 0; setParity(val); $(N_flag) = 0; } :RLD is op0_8=0xed; op0_8=0x6f { val:1 = 0; local a_temp = A; MemRead(val,HL); nibA:1 = a_temp & 0x0f; nibM:1 = val >> 4; val = (val << 4) | nibA; a_temp = (a_temp & 0xf0) | nibM; A = a_temp; MemStore(HL,val); @if defined(Z180) setResultFlags(val); @else setResultFlags(a_temp); @endif $(H_flag) = 0; setParity(a_temp); $(N_flag) = 0; } :RRD is op0_8=0xed; op0_8=0x67 { val:1 = 0; MemRead(val,HL); local a_temp = A; nibA:1 = a_temp & 0x0f; nibM:1 = val & 0x0f; val = (val >> 4) | (nibA << 4); a_temp = (a_temp & 0xf0) | nibM; A = a_temp; MemStore(HL,val); @if defined(Z180) setResultFlags(val); @else setResultFlags(a_temp); @endif $(H_flag) = 0; setParity(a_temp); $(N_flag) = 0; } :BIT bits3_3,reg0_3 is op0_8=0xcb; op6_2=0x1 & bits3_3 & reg0_3 { mask:1 = (1 << bits3_3); $(Z_flag) = ((reg0_3 & mask) == 0); $(H_flag) = 1; $(N_flag) = 0; } :BIT bits3_3,(HL) is op0_8=0xcb & HL; op6_2=0x1 & bits3_3 & bits0_3=0x6 { mask:1 = (1 << bits3_3); val:1 = 0; MemRead(val,HL); $(Z_flag) = ((val & mask) == 0); $(H_flag) = 1; $(N_flag) = 0; } :BIT bits3_3,ixMem8 is op0_8=0xdd; op0_8=0xcb; ixMem8; op6_2=0x1 & bits3_3 & bits0_3=0x6 { mask:1 = (1 << bits3_3); val:1 = ixMem8; $(Z_flag) = ((val & mask) == 0); $(H_flag) = 1; $(N_flag) = 0; } :BIT bits3_3,iyMem8 is op0_8=0xfd; op0_8=0xcb; iyMem8; op6_2=0x1 & bits3_3 & bits0_3=0x6 { mask:1 = (1 << bits3_3); val:1 = iyMem8; $(Z_flag) = ((val & mask) == 0); $(H_flag) = 1; $(N_flag) = 0; } :SET bits3_3,reg0_3 is op0_8=0xcb; op6_2=0x3 & bits3_3 & reg0_3 { mask:1 = (1 << bits3_3); reg0_3 = reg0_3 | mask; } :SET bits3_3,(HL) is op0_8=0xcb & HL; op6_2=0x3 & bits3_3 & bits0_3=0x6 { mask:1 = (1 << bits3_3); val:1 = 0; MemRead(val,HL); val = val | mask; MemStore(HL,val); } :SET bits3_3,ixMem8 is op0_8=0xdd; op0_8=0xcb; ixMem8; op6_2=0x3 & bits3_3 & bits0_3=0x6 { mask:1 = (1 << bits3_3); val:1 = ixMem8; ixMem8 = val | mask; } :SET bits3_3,iyMem8 is op0_8=0xfd; op0_8=0xcb; iyMem8; op6_2=0x3 & bits3_3 & bits0_3=0x6 { mask:1 = (1 << bits3_3); val:1 = iyMem8; iyMem8 = val | mask; } :RES bits3_3,reg0_3 is op0_8=0xcb; op6_2=0x2 & bits3_3 & reg0_3 { mask:1 = ~(1 << bits3_3); reg0_3 = reg0_3 & mask; } :RES bits3_3,(HL) is op0_8=0xcb & HL; op6_2=0x2 & bits3_3 & bits0_3=0x6 { mask:1 = ~(1 << bits3_3); val:1 = 0; MemRead(val,HL); val = val & mask; MemStore(HL,val); } :RES bits3_3,ixMem8 is op0_8=0xdd; op0_8=0xcb; ixMem8; op6_2=0x2 & bits3_3 & bits0_3=0x6 { mask:1 = ~(1 << bits3_3); val:1 = ixMem8; ixMem8 = val & mask; } :RES bits3_3,iyMem8 is op0_8=0xfd; op0_8=0xcb; iyMem8; op6_2=0x2 & bits3_3 & bits0_3=0x6 { mask:1 = ~(1 << bits3_3); val:1 = iyMem8; iyMem8 = val & mask; } :JP Addr16 is op0_8=0xc3; Addr16 { goto Addr16; } :JP cc,Addr16 is op6_2=0x3 & cc & bits0_3=0x2; Addr16 { if (cc) goto Addr16; } :JR RelAddr8 is op0_8=0x18; RelAddr8 { goto RelAddr8; } :JR cc2,RelAddr8 is op6_2=0x0 & cc2 & bits0_3=0x0; RelAddr8 { if (cc2) goto RelAddr8; } :JP (HL) is op0_8=0xe9 & HL { off:2 = (zext(H) << 8) | zext(L); JumpToLoc(off); } :JP (IX) is op0_8=0xdd & IX; op0_8=0xe9 { JumpToLoc(IX); } :JP (IY) is op0_8=0xfd & IY; op0_8=0xe9 { JumpToLoc(IY); } :DJNZ RelAddr8 is op0_8=0x10; RelAddr8 { B = B - 1; if (B != 0) goto RelAddr8; } :CALL Addr16 is op0_8=0xcd; Addr16 { push16(&:2 inst_next); call Addr16; } :CALL cc,Addr16 is op6_2=0x3 & cc & bits0_3=0x4; Addr16 { if (!cc) goto inst_next; push16(&:2 inst_next); call Addr16; } :RET is op0_8=0xc9 { pop16(PC); ptr:$(PTRSIZE) = PC; return [ptr]; } :RET cc is op6_2=0x3 & cc & bits0_3=0x0 { if (!cc) goto inst_next; pop16(PC); ptr:$(PTRSIZE) = PC; return [ptr]; } :RETI is op0_8=0xed; op0_8=0x4d { pop16(PC); ptr:$(PTRSIZE) = PC; return [ptr]; } :RETN is op0_8=0xed; op0_8=0x45 { # IFF1 = IFF2; pop16(PC); ptr:$(PTRSIZE) = PC; return [ptr]; } :RST RstAddr is op6_2=0x3 & RstAddr & bits0_3=0x7 { push16(&:2 inst_next); call RstAddr; } :IN A,IOAddr8a is op0_8=0xdb & A; IOAddr8a { ioRead(IOAddr8a, A); } :IN reg3_3,IOAddrC is op0_8=0xed & IOAddrC; op6_2=0x1 & reg3_3 & bits0_3=0x0 { val:1 = 0; ioRead(IOAddrC, val); reg3_3 = val; setResultFlags(val); $(H_flag) = 0; setParity(val); $(N_flag) = 0; } :INI is op0_8=0xed & IOAddrC; op0_8=0xa2 { val:1 = 0; ioRead(IOAddrC, val); MemStore(HL,val); B = B - 1; HL = HL + 1; $(Z_flag) = (B == 0); $(N_flag) = (B s< 0); } :INIR is op0_8=0xed & IOAddrC; op0_8=0xb2 { val:1 = 0; ioRead(IOAddrC, val); MemStore(HL,val); B = B - 1; HL = HL + 1; if (B != 0) goto inst_start; $(Z_flag) = 1; $(N_flag) = 1; } :IND is op0_8=0xed & IOAddrC; op0_8=0xaa { val:1 = 0; ioRead(IOAddrC, val); MemStore(HL,val); B = B - 1; HL = HL - 1; $(Z_flag) = (B == 0); $(N_flag) = (B s< 0); } :INDR is op0_8=0xed & IOAddrC; op0_8=0xba { val:1 = 0; ioRead(IOAddrC, val); MemStore(HL,val); B = B - 1; HL = HL - 1; if (B != 0) goto inst_start; $(Z_flag) = 1; $(N_flag) = 1; } :OUT IOAddr8a,A is op0_8=0xd3 & A; IOAddr8a { ioWrite(IOAddr8a, A); } :OUT IOAddrC,reg3_3 is op0_8=0xed & IOAddrC; op6_2=0x1 & reg3_3 & bits0_3=0x1 { ioWrite(IOAddrC, reg3_3); } :OUTI is op0_8=0xed & IOAddrC; op0_8=0xa3 { local test = B - 1; B = test; val:1 = 0; MemRead(val,HL); ioWrite(IOAddrC, val); HL = HL + 1; $(Z_flag) = (test == 0); $(N_flag) = (test s< 0); } :OTIR is op0_8=0xed & IOAddrC; op0_8=0xb3 { B = B - 1; val:1 = 0; MemRead(val,HL); ioWrite(IOAddrC, val); HL = HL + 1; if (B != 0) goto inst_start; $(Z_flag) = 1; $(N_flag) = 1; } :OUTD is op0_8=0xed & IOAddrC; op0_8=0xab { local test = B - 1; B = test; val:1 = 0; MemRead(val,HL); ioWrite(IOAddrC, val); HL = HL - 1; $(Z_flag) = (test == 0); $(N_flag) = (test s< 0); } :OTDR is op0_8=0xed & IOAddrC; op0_8=0xbb { B = B - 1; val:1 = 0; MemRead(val,HL); ioWrite(IOAddrC, val); HL = HL - 1; if (B != 0) goto inst_start; $(Z_flag) = 1; $(N_flag) = 1; } @if defined(Z180) :MLT qRegPair4_2 is op0_8=0xed; op6_2=0x1 & qRegPair4_2 & bits0_4=0xc { local pair = qRegPair4_2; hi:2 = pair >> 8; lo:2 = pair & 0xff; qRegPair4_2 = hi * lo; } :TST reg3_3 is op0_8=0xed; op6_2=0x0 & reg3_3 & bits0_3=0x4 { local result = reg3_3 & A; setResultFlags(result); $(H_flag)=1; setParity(result); $(N_flag)=0; $(C_flag)=0; } :TST hlMem8 is op0_8=0xed; op0_8=0x34 & hlMem8 { val:1 = 0; MemRead(val,HL); local result = val & A; setResultFlags(result); $(H_flag)=1; setParity(result); $(N_flag)=0; $(C_flag)=0; } :TST imm8 is op0_8=0xed; op0_8=0x64; imm8 { val:1 = imm8 & A; setResultFlags(val); $(H_flag)=1; setParity(val); $(N_flag)=0; $(C_flag)=0; } :IN0 Flag,IOAddr8 is op0_8=0xed; op6_2=0x0 & bits3_3=0x6 & Flag & bits0_3=0x0; IOAddr8 { val:1 = 0; ioRead(IOAddr8,val); # read input location setResultFlags(val); $(H_flag)=0; setParity(val); $(N_flag)=0; } :IN0 reg3_3,IOAddr8 is op0_8=0xed; op6_2=0x0 & reg3_3 & bits0_3=0x0; IOAddr8 { local r_temp = reg3_3; ioRead(IOAddr8,r_temp); # read input location reg3_3 = r_temp; setResultFlags(r_temp); $(H_flag)=0; setParity(r_temp); $(N_flag)=0; } :OUT0 IOAddr8,reg3_3 is op0_8=0xed; op6_2=0x0 & reg3_3 & bits0_3=0x1; IOAddr8 { ioWrite(IOAddr8, reg3_3); } :OTDM is op0_8=0xed; op0_8=0x8b & hlMem8 & IOAddrC { val:1 = hlMem8; ioWrite(IOAddrC, val); HL = HL - 1; C = C - 1; local test = B; setSubtractFlags(test,1); # ?? sets $(C_flag) based upon B-1 ?? test = test - 1; B = test; setResultFlags(test); # P_flag = parity(r); $(PV_flag) = (val s< 0); } :OTDMR is op0_8=0xed; op0_8=0x9b & hlMem8 & IOAddrC { local test = B - 1; B = test; val:1 = hlMem8; ioWrite(IOAddrC, val); HL = HL - 1; C = C - 1; if (test != 0) goto inst_start; $(S_flag)=0; $(Z_flag)=1; $(H_flag) = 0; # $(PV_flag)=1; $(PV_flag) = (val s< 0); # based upon last output byte $(C_flag)=0; } :TSTIO IOAddr8 is op0_8=0xed; op0_8=0x74; IOAddr8 { val:1 = 0; ioRead(IOAddr8,val); local result = A & val; setResultFlags(result); $(H_flag) = 1; # P_flag = parity(v); $(N_flag) = 0; $(C_flag)=0; } :OTIM is op0_8=0xed; op0_8=0x83 & hlMem8 & IOAddrC { val:1 = hlMem8; ioWrite(IOAddrC, val); HL = HL + 1; C = C + 1; local test = B; setSubtractFlags(test,1); # ?? sets $(C_flag) based upon B-1 ?? test = test - 1; B = test; setResultFlags(test); $(H_flag) = 1; # P_flag = parity(r); $(PV_flag) = (val s< 0); $(N_flag) = 0; $(C_flag)=0; } :OTIMR is op0_8=0xed; op0_8=0x93 & hlMem8 & IOAddrC { val:1 = hlMem8; local test = B - 1; B = test; ioWrite(IOAddrC, val); HL = HL - 1; C = C + 1; if (test != 0) goto inst_start; $(S_flag)=0; $(Z_flag)=1; $(H_flag) = 0; # $(PV_flag)=1; $(PV_flag) = (val s< 0); # based upon last output byte $(C_flag)=0; } :SLP is op0_8=0xed; op0_8=0x76 { sleep(); } @endif # Undocumented instructions # information taken from https://clrhome.org/table @ifndef Z180 # Bad support on Z180 :IM 0 is op0_8=0xed; op0_8=0x4e { setInterruptMode(0:1); } :IM 1 is op0_8=0xed; op0_8=0x6e { setInterruptMode(1:1); } # CB range :SLL reg0_3 is op0_8=0x0cb; op6_2=0x0 & bits3_3=0x6 & reg0_3 { local r_temp = reg0_3; $(C_flag) = (r_temp >> 7); r_temp = (r_temp << 1) | 0x01; reg0_3 = r_temp; setResultFlags(r_temp); $(H_flag) = 0; setParity(r_temp); $(N_flag) = 0; } :SLL (HL) is op0_8=0x0cb & HL; op0_8=0x36 { val:1 = 0; MemRead(val,HL); $(C_flag) = (val >> 7); val = val << 1 | 0x01; setResultFlags(val); MemStore(HL,val); $(H_flag) = 0; setParity(val); $(N_flag) = 0; } ## DD range ixh_iyh: IXH is op0_8=0xdd & IXH { export IXH; } ixh_iyh: IYH is op0_8=0xfd & IYH { export IYH; } ixl_iyl: IXL is op0_8=0xdd & IXL { export IXL; } ixl_iyl: IYL is op0_8=0xfd & IYL { export IYL; } :INC ixh_iyh is ixh_iyh; op0_8=0x24 { local val = ixh_iyh; additionFlags(val, 1); val = val + 1; ixh_iyh = val; setResultFlags(val); } :DEC ixh_iyh is ixh_iyh; op0_8=0x25 { local val = ixh_iyh; subtractionFlagsNoC(val, 1); val = val - 1; ixh_iyh = val ; setResultFlags(val); } :INC ixl_iyl is ixl_iyl; op0_8=0x2c { local val = ixl_iyl; additionFlags(val, 1); val = val + 1; ixl_iyl = val; setResultFlags(val); } :DEC ixl_iyl is ixl_iyl; op0_8=0x2d { local val = ixl_iyl; subtractionFlagsNoC(val, 1); val = val - 1; ixl_iyl = val; setResultFlags(val); } :LD ixh_iyh,imm8 is ixh_iyh; op0_8=0x26; imm8 { ixh_iyh = imm8; } :LD ixl_iyl,imm8 is ixl_iyl; op0_8=0x2e; imm8 { ixl_iyl = imm8; } :LD B,ixh_iyh is ixh_iyh & B; op0_8=0x44 { B = ixh_iyh; } :LD B,ixl_iyl is ixl_iyl & B; op0_8=0x45 { B = ixl_iyl; } :LD C,ixh_iyh is ixh_iyh & C; op0_8=0x4c { C = ixh_iyh; } :LD C,ixl_iyl is ixl_iyl & C; op0_8=0x4d { C = ixl_iyl; } :LD D,ixh_iyh is ixh_iyh & D; op0_8=0x54 { D = ixh_iyh; } :LD D,ixl_iyl is ixl_iyl & D; op0_8=0x55 { D = ixl_iyl; } :LD E,ixh_iyh is ixh_iyh & E; op0_8=0x5c { E = ixh_iyh; } :LD E,ixl_iyl is ixl_iyl & E; op0_8=0x5d { E = ixl_iyl; } :LD ixh_iyh,reg0_3 is ixh_iyh; op6_2=0x1 & bits3_3=0x4 & reg0_3{ ixh_iyh = reg0_3; } :LD ixl_iyl,reg0_3 is ixl_iyl; op6_2=0x1 & bits3_3=0x5 & reg0_3 { ixl_iyl = reg0_3; } :LD ixh_iyh,ixl_iyl is ixh_iyh & ixl_iyl; op0_8=0x65 { ixh_iyh = ixl_iyl; } :LD ixh_iyh,A is ixh_iyh; op0_8=0x67 & A { ixh_iyh = A; } :LD ixl_iyl,ixh_iyh is ixl_iyl & ixh_iyh; op0_8=0x6c { ixl_iyl = ixh_iyh; } :LD ixl_iyl,A is ixl_iyl; op0_8=0x6f & A { ixl_iyl = A; } :LD A,ixh_iyh is ixh_iyh; op0_8=0x7c & A { A = ixh_iyh; } :LD A,ixl_iyl is ixl_iyl; op0_8=0x7d & A { A = ixl_iyl; } :ADD A, ixh_iyh is ixh_iyh; op0_8=0x84 & A { local a_temp = A; local val = ixh_iyh; additionFlags(a_temp, val); a_temp = a_temp + val; setResultFlags(a_temp); A = a_temp; } :ADD A, ixl_iyl is ixl_iyl; op0_8=0x85 & A { local a_temp = A; local val = ixl_iyl; additionFlags(a_temp, val); a_temp = a_temp + val; setResultFlags(a_temp); A = a_temp; } :ADC A, ixh_iyh is ixh_iyh; op0_8=0x8c & A { local a_temp = A; local val = ixh_iyh; additionWithCarry(a_temp, val, a_temp); setResultFlags(a_temp); A = a_temp; } :ADC A, ixl_iyl is ixl_iyl; op0_8=0x8d & A { local a_temp = A; local val = ixl_iyl; additionWithCarry(a_temp, val, a_temp); setResultFlags(a_temp); A = a_temp; } :SUB ixh_iyh is ixh_iyh; op0_8=0x94 { local a_temp = A; local val = ixh_iyh; subtractionFlags(a_temp, val); a_temp = a_temp - val; setResultFlags(a_temp); A = a_temp; } :SUB ixl_iyl is ixl_iyl; op0_8=0x95 { local a_temp = A; local val = ixl_iyl; subtractionFlags(a_temp, val); a_temp = a_temp - val; setResultFlags(a_temp); A = a_temp; } :SBC A, ixh_iyh is ixh_iyh; op0_8=0x9c & A { local a_temp = A; subtractionWithCarry(a_temp, ixh_iyh, a_temp); setResultFlags(A); A = a_temp; } :SBC A, ixl_iyl is ixl_iyl; op0_8=0x9d & A { local a_temp = A; subtractionWithCarry(a_temp, ixl_iyl, a_temp); setResultFlags(a_temp); A = a_temp; } :AND ixh_iyh is ixh_iyh; op0_8=0xa4 { local a_temp = A; $(H_flag) = 1; $(C_flag) = 0; $(N_flag) = 0; a_temp = a_temp & ixh_iyh; setResultFlags(a_temp); setParity(a_temp); A = a_temp; } :AND ixl_iyl is ixl_iyl; op0_8=0xa5 { local a_temp = A; $(H_flag) = 1; $(C_flag) = 0; $(N_flag) = 0; a_temp = a_temp & ixl_iyl; setResultFlags(a_temp); setParity(a_temp); A = a_temp; } :XOR ixh_iyh is ixh_iyh; op0_8=0xac { local a_temp = A; $(H_flag) = 0; $(C_flag) = 0; $(N_flag) = 0; a_temp = a_temp ^ ixh_iyh; setResultFlags(a_temp); setParity(a_temp); A = a_temp; } :XOR ixl_iyl is ixl_iyl; op0_8=0xad { local a_temp = A; $(H_flag) = 0; $(C_flag) = 0; $(N_flag) = 0; a_temp = a_temp ^ ixl_iyl; setResultFlags(a_temp); setParity(a_temp); A = a_temp; } :OR ixh_iyh is ixh_iyh; op0_8=0xb4 { local a_temp = A; $(H_flag) = 0; $(C_flag) = 0; $(N_flag) = 0; a_temp = a_temp | ixh_iyh; setResultFlags(a_temp); setParity(a_temp); A = a_temp; } :OR ixl_iyl is ixl_iyl; op0_8=0xb5 { local a_temp = A; $(H_flag) = 0; $(C_flag) = 0; $(N_flag) = 0; a_temp = a_temp | ixl_iyl; setResultFlags(a_temp); setParity(a_temp); A = a_temp; } :CP ixh_iyh is ixh_iyh; op0_8=0xbc { local a_temp = A; local r_temp = ixh_iyh; cmp:1 = a_temp - r_temp; subtractionFlags(a_temp, r_temp); setResultFlags(cmp); } :CP ixl_iyl is ixl_iyl; op0_8=0xbd { local a_temp = A; local r_temp = ixl_iyl; cmp:1 = a_temp - r_temp; subtractionFlags(a_temp, r_temp); setResultFlags(cmp); } @endif