From b75ff4830078b61ca1ae40e1c703965c5269c0cf Mon Sep 17 00:00:00 2001 From: Redo Date: Wed, 4 Jan 2023 13:29:55 -0600 Subject: [PATCH] fix conditions, add ien flag, improve keyboard, add gpio --- emulator/8608emulator.c | 8 +- emulator/8608emulator.dll | Bin 164439 -> 164507 bytes emulator/8608emulator.lua | 162 ++++++++++++++++++++++++++++-------- emulator/instructions_gen.c | 12 +-- emulator/keycodes.lua | 1 + instructionList.txt | 10 ++- readme.txt | 8 +- rom-8608-defs.lua | 12 +-- 8 files changed, 160 insertions(+), 53 deletions(-) diff --git a/emulator/8608emulator.c b/emulator/8608emulator.c index 56d804c..c51e5e9 100644 --- a/emulator/8608emulator.c +++ b/emulator/8608emulator.c @@ -42,7 +42,7 @@ #define ldi cpu->instr = readmemory(cpu->i); cpu->cycle = 0; #define addf(x,y) { x=(x+y); cpu->cf=x>=256; x&=0xFF; setzf(x); } #define subf(x,y) addf(x,-y); -#define cmpf(x,y) { int t=x-y; cpu->cf=(t>=256); setzf(t); } +#define cmpf(x,y) { int t=x-y; cpu->cf=(t<0); setzf(t); } #define rol(x,y) x=(x<>(8-y)); #define ror(x,y) x=(x>>y)|(x<<(8-y)); #define sra(x,y) x=(x>>y); @@ -80,6 +80,7 @@ struct CPU { int irq; int ifg; int rfg; + int ien; int instr; int cycle; int instrpre; @@ -130,14 +131,15 @@ typedef void(*CPUInstruction)(struct CPU* const cpu, struct Memory* const mem); #include "instructions_gen.c" -int TickCPU(struct CPU* const cpu, struct Memory* const mem, const int count, const int countinstrs) { +int TickCPU(struct CPU* const cpu, struct Memory* const mem, const int count, const int countinstrs, const int breakaddr) { int i = 0; while(iirq && !cpu->ifg && cpu->cycle==0) { cpu->instr = 0xF2; } + if(cpu->irq && !cpu->ifg && cpu->cycle==0 && cpu->ien) { cpu->instr = 0xF2; } if(cpu->rfg || cpu->ifg || cpu->irq) { CPUInstruction instr = CPUInstructions[cpu->instr][cpu->cycle]; if(instr) instr(cpu, mem); if(!countinstrs || cpu->cycle==0) { i++; } + if(cpu->i==breakaddr) { i = count; break; } } else { i = count; break; } if(mem->numevents!=0) { break; } } diff --git a/emulator/8608emulator.dll b/emulator/8608emulator.dll index c7f8e0a1da4b24e6cdc06bb96f2b0b97ec07f20a..99234eca487edb73b565f8d3b92bfd62427a13b9 100644 GIT binary patch delta 33468 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 z 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 kb.queueSize then table.remove(kb.queue, 1) end kb.queueEmpty = false kbSetNext(kb, cpu, mem) if kb.interrupts then CPURequestInterrupt(cpu) end end -local function RedrawFPSCounter(x,y) +local function RedrawFPSCounter(x, y) lg.setColor(0,0,0) lg.rectangle("fill",x,y,64,12) lg.setColor(1,1,1) lg.print("FPS: "..lt.getFPS(), x,y) end +local function printHighlight(s, o, h, x, y) + x = x+o*7 + local w = 7*#s + lg.setColor(1,1,1) + if h then + lg.rectangle("fill", x, y, w, 12) + lg.setColor(0,0,0) + end + lg.print(s, x, y) +end +local function RedrawKeyInfo(x, y, uk, run) + lg.setColor(0,0,0) + lg.rectangle("fill",x,y,768,12) + lg.setColor(1,1,1) + printHighlight("[ESC] Toggle keyboard", 0, lk.isDown("escape"), x, y) + lg.setColor(1,1,1) + if uk then + printHighlight("Keystrokes passed to device", 23, false, x, y) + else + printHighlight("[R] "..(run and "Stop" or "Run "), 23, lk.isDown("r"), x, y) + printHighlight("[T] Tick once", 33, lk.isDown("t"), x, y) + printHighlight("[S] Step once", 48, lk.isDown("s"), x, y) + printHighlight("[Q] Quit", 63, lk.isDown("q"), x, y) + end +end + +local GPIO = {} +local function InitGPIO(gpio) + gpio.mulLeft = 0 + gpio.mulRight = 0 + gpio.divLeft = 0 + gpio.divRight = 0 + gpio.intQueued = false +end +local function UpdateGPIO(gpio, cpu, mem) + if gpio.intQueued then + gpio.intQueued = false + CPURequestInterrupt(cpu) + end +end +local function gpioSetValue(name, func) + return function(addr, cpu, mem, gpio) + gpio[name] = ReadMemory(mem, addr) + func(addr, cpu, mem, gpio) + end +end +local function gpioMul(addr, cpu, mem, gpio) + local base = math.floor(addr/256)*256 + local res = gpio.mulLeft*gpio.mulRight + WriteMemory(mem, base+0x00, math.floor(res/256)) + WriteMemory(mem, base+0x01, res%256) +end +local function gpioDiv(addr, cpu, mem, gpio) + local base = math.floor(addr/256)*256 + WriteMemory(mem, base+0x02, math.floor(gpio.divLeft/gpio.divRight)) + WriteMemory(mem, base+0x03, gpio.divLeft%gpio.divRight) +end +local gpioFunctions = { + [0x00] = gpioSetValue("mulLeft" , gpioMul), + [0x01] = gpioSetValue("mulRight", gpioMul), + [0x02] = gpioSetValue("divLeft" , gpioDiv), + [0x03] = gpioSetValue("divRight", gpioDiv), + [0x04] = function(addr, cpu, mem, gpio) WriteMemory(mem, addr, gpioPopcount(readMemory(mem, addr))) end, + [0x05] = function(addr, cpu, mem, gpio) gpio.intQueued = true; WriteMemory(mem, addr, 0); end +} +local function GPIOOnWrite(addr, cpu, mem, gpio) + local offset = addr%256 + local func = gpioFunctions[offset] + if func then + func(addr, cpu, mem, gpio) + end +end local peripherals = { CharDisplay = { range = {0x0800, 0x0FFF}, write = true }, @@ -371,6 +439,9 @@ local peripherals = { onread = function(addr, cpu, mem) KeyboardOnRead (addr, cpu, mem, Keyboard) end, onwrite = function(addr, cpu, mem) KeyboardOnWrite(addr, cpu, mem, Keyboard) end, }, + GPIO = { range = {0x0400, 0x04FF}, write = true, + onwrite = function(addr, cpu, mem) GPIOOnWrite(addr, cpu, mem, GPIO) end, + }, } ---- @@ -413,7 +484,7 @@ end ReadMemory = function(mem, addr) return mem.c.data[addr%65536]%256 end -local function WriteMemory(mem, addr, val) +WriteMemory = function(mem, addr, val) if mem.c.canwrite[addr%65536]~=0 then mem.c.data[addr%65536] = val%256 end @@ -445,21 +516,22 @@ struct CPU { int irq; int ifg; int rfg; + int ien; int instr; int cycle; int instrpre; int frame; }; -int TickCPU(struct CPU* const cpu, struct Memory* const mem, const int count, const int countinstrs); +int TickCPU(struct CPU* const cpu, struct Memory* const mem, const int count, const int countinstrs, const int breakaddr); ]] local CPU = { c = ffi.new("struct CPU"), } local cpuDll = ffi.load("8608emulator.dll") -local function TickCPU(cpu, mem, count, countinstrs) +local function TickCPU(cpu, mem, count, countinstrs, breakaddr) local countleft = count while countleft>0 do - countleft = cpuDll.TickCPU(cpu.c, mem.c, countleft, countinstrs and 1 or 0) + countleft = cpuDll.TickCPU(cpu.c, mem.c, countleft, countinstrs and 1 or 0, breakaddr or 0xFFFFFFFF) handleEvents(cpu, mem) end end @@ -470,6 +542,10 @@ CPURequestInterrupt = function(cpu) cpu.c.irq = 1; end +function RunToNextInstr(cpu) + +end + ---- local function RedrawVideoDisplay(vd, mem) @@ -497,9 +573,11 @@ local function RedrawCharDisplay(cd, mem) local abase = cy*cd.cols + cx local achar = cd.addrChar + abase local acolor = cd.addrColor + abase - local colorid = ReadMemory(mem, acolor)%64 + local colormem = ReadMemory(mem, acolor) + local colorid = colormem%64 + local highlight = colormem>=128 lg.setColor(ColorSet[colorid]) - if cd.highlight[a] then + if highlight then lg.rectangle("fill", cd.scrX + cx*cd.fontWidth, cd.scrY + cy*cd.fontHeight, cd.fontWidth, cd.fontHeight) lg.setColor(0, 0, 0) end @@ -524,7 +602,7 @@ local function InitWindowCanvas() lg.setFont(InfoFont) lg.print("8608 CPU Emulator", 4, 4) end -local function RedrawWindow() +local function RedrawWindow(usekeyboard, runcpu) lg.setCanvas(WindowCanvas) lg.setFont(InfoFont) RedrawCharDisplay(CharDisplay, Memory) @@ -534,6 +612,7 @@ local function RedrawWindow() RedrawProgramDisplay(ProgramDisplay, CPU, Memory) for _, md in ipairs(MemoryDisplays) do RedrawMemoryDisplay(md, CPU, Memory) end RedrawFPSCounter(128+32, 4) + RedrawKeyInfo(128+32+64+16, 4, usekeyboard, runcpu) lg.setCanvas() end @@ -547,6 +626,7 @@ function love.load() InitMemory(Memory, peripherals) InitWindowCanvas() InitCPU(CPU) + InitGPIO(GPIO) --InitVideoDisplay(VideoDisplay) InitCharDisplay(CharDisplay) InitRegDisplay(RegDisplay) @@ -560,24 +640,38 @@ end local RunCPU = false local CPUSpeed = 4999 +local UseKeyboard = false function love.draw() + UpdateGPIO(GPIO, CPU, Memory) + CPU.c.frame = CPU.c.frame + 1 if RunCPU then - TickCPU(CPU, Memory, CPUSpeed, false) + TickCPU(CPU, Memory, CPUSpeed, false, nil) end - RedrawWindow() + RedrawWindow(UseKeyboard, RunCPU) lg.setColor(1,1,1) lg.draw(WindowCanvas, 0, 0, 0, 2, 2) - lg.print(CPU.c.frame) end + function love.keypressed(k) - if k=="escape" then le.quit() - elseif k=="t" then TickCPU(CPU, Memory, 1, true ) - elseif k=="e" then TickCPU(CPU, Memory, 1, false) - elseif k=="r" then RunCPU = not RunCPU - elseif k=="i" then CPU.c.irq = 1 - else KeyboardOnKey(Keyboard, k, true, CPU, Memory) + if k=="escape" then + UseKeyboard = not UseKeyboard + else + if UseKeyboard then + KeyboardOnKey(Keyboard, k, true, CPU, Memory) + else + if k=="q" then le.quit() + elseif k=="s" then TickCPU(CPU, Memory, 1, true , nil) + elseif k=="t" then TickCPU(CPU, Memory, 1, false, nil) + elseif k=="o" then RunToNextInstr(cpu) + elseif k=="r" then RunCPU = not RunCPU + elseif k=="i" then CPU.c.irq = 1 + end + end end end +function love.keyreleased(k) + if k~="escape" and UseKeyboard then KeyboardOnKey(Keyboard, k, false, CPU, Memory) end +end diff --git a/emulator/instructions_gen.c b/emulator/instructions_gen.c index 5bfbb12..24e9fb9 100644 --- a/emulator/instructions_gen.c +++ b/emulator/instructions_gen.c @@ -1,6 +1,6 @@ // Auto-generated by gendefs.lua -void cpu_instr_0_0(struct CPU* const cpu, struct Memory* const mem) { cpu->a=0; cpu->b=0; cpu->c=0; cpu->u=0; cpu->t=0; cpu->p=0; cpu->q=0; cpu->s=0; cpu->v=0; cpu->i=0; cpu->cf=0; cpu->nz=0; cpu->irq=0; cpu->ifg=0; cpu->rfg=1; lni; } +void cpu_instr_0_0(struct CPU* const cpu, struct Memory* const mem) { cpu->a=0; cpu->b=0; cpu->c=0; cpu->u=0; cpu->t=0; cpu->p=0; cpu->q=0; cpu->s=0; cpu->v=0; cpu->i=0; cpu->cf=0; cpu->nz=0; cpu->irq=0; cpu->ifg=0; cpu->rfg=1; cpu->ien=0; lni; } void cpu_instr_16_0(struct CPU* const cpu, struct Memory* const mem) { addf(cpu->a, 1 ); lni; } void cpu_instr_17_0(struct CPU* const cpu, struct Memory* const mem) { addf(cpu->a,-1 ); lni; } void cpu_instr_18_0(struct CPU* const cpu, struct Memory* const mem) { cpu->p++; lni; } @@ -73,9 +73,9 @@ void cpu_instr_51_1(struct CPU* const cpu, struct Memory* const mem) { if(!cpu-> void cpu_instr_52_0(struct CPU* const cpu, struct Memory* const mem) { loadimmedt cpu->cycle++; } void cpu_instr_52_1(struct CPU* const cpu, struct Memory* const mem) { if( cpu->cf ) { jmprelt } else { lni } } void cpu_instr_53_0(struct CPU* const cpu, struct Memory* const mem) { loadimmedt cpu->cycle++; } -void cpu_instr_53_1(struct CPU* const cpu, struct Memory* const mem) { if( cpu->nz && cpu->cf) { jmprelt } else { lni } } +void cpu_instr_53_1(struct CPU* const cpu, struct Memory* const mem) { if(cpu->nz && (!cpu->cf)) { jmprelt } else { lni } } void cpu_instr_54_0(struct CPU* const cpu, struct Memory* const mem) { loadimmedt cpu->cycle++; } -void cpu_instr_54_1(struct CPU* const cpu, struct Memory* const mem) { if(!cpu->nz && !cpu->cf) { jmprelt } else { lni } } +void cpu_instr_54_1(struct CPU* const cpu, struct Memory* const mem) { if((!cpu->nz) || cpu->cf) { jmprelt } else { lni } } void cpu_instr_55_0(struct CPU* const cpu, struct Memory* const mem) { cpu->b=lobyte(cpu->p); lni; } void cpu_instr_56_0(struct CPU* const cpu, struct Memory* const mem) { cpu->c=hibyte(cpu->p); lni; } void cpu_instr_57_0(struct CPU* const cpu, struct Memory* const mem) { cpu->b=lobyte(cpu->q); lni; } @@ -445,6 +445,8 @@ void cpu_instr_241_0(struct CPU* const cpu, struct Memory* const mem) { cpu->rfg void cpu_instr_242_0(struct CPU* const cpu, struct Memory* const mem) { cpu->irq=0; cpu->ifg=1; int t=cpu->i; cpu->i=cpu->v; cpu->v=(t-1)%65536; lni; } void cpu_instr_243_0(struct CPU* const cpu, struct Memory* const mem) { cpu->ifg=1; int t=cpu->i; cpu->i=cpu->v; cpu->v=t; lni; } void cpu_instr_244_0(struct CPU* const cpu, struct Memory* const mem) { cpu->ifg=0; int t=cpu->i; cpu->i=cpu->v; cpu->v=t; lni; } +void cpu_instr_245_0(struct CPU* const cpu, struct Memory* const mem) { cpu->ien=1; lni; } +void cpu_instr_246_0(struct CPU* const cpu, struct Memory* const mem) { cpu->ien=0; lni; } void cpu_instr_255_0(struct CPU* const cpu, struct Memory* const mem) { lni; } CPUInstruction CPUInstructions[256][8] = { @@ -693,8 +695,8 @@ CPUInstruction CPUInstructions[256][8] = { {cpu_instr_242_0,0,0,0,0,0,0,0}, {cpu_instr_243_0,0,0,0,0,0,0,0}, {cpu_instr_244_0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0}, + {cpu_instr_245_0,0,0,0,0,0,0,0}, + {cpu_instr_246_0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, diff --git a/emulator/keycodes.lua b/emulator/keycodes.lua index 9e40dc5..fb1aa34 100644 --- a/emulator/keycodes.lua +++ b/emulator/keycodes.lua @@ -18,6 +18,7 @@ return { ["="] = 25, [","] = 26, ["."] = 27, + ["-"] = 28, ["/"] = 29, ["`"] = 30, diff --git a/instructionList.txt b/instructionList.txt index 062bb90..a752f9d 100644 --- a/instructionList.txt +++ b/instructionList.txt @@ -6,6 +6,8 @@ run F1 1 Resume non-interrupt execution brk F3 1 Trigger interrupt irt F4 1 Return from interrupt nop FF 1 Do nothing +ien F5 1 Enbale interrupts +idi F6 1 Disable interrupts 16-bit Inc/Dec (I): inc p 12 1 P++ @@ -127,8 +129,8 @@ rts E1 3 I=*(----S)+1 jpr imm8 31 2 I+=imm8 jnz imm8 30 2 I+=imm8 if !Zero jpz imm8 32 2 I+=imm8 if Zero -jlt imm8 33 2 I+=imm8 if !Carry -jge imm8 34 2 I+=imm8 if Carry +jge imm8 33 2 I+=imm8 if !Carry +jlt imm8 34 2 I+=imm8 if Carry jgt imm8 35 2 I+=imm8 if !Zero & Carry jle imm8 36 2 I+=imm8 if Zero | !Carry @@ -238,7 +240,7 @@ ldq p 8E 1 Q=P lds p 8F 1 S=P ldv p 90 1 V=P -Opcodes used: 226/255 +Opcodes used: 228/255 0123456789ABCDEF 00 | C--------------- 10 | UUIIUIIUUUUUUUUU @@ -255,4 +257,4 @@ B0 | AAAAAAAAAAAAAAAA C0 | BBBBBBBBBBBBWWWW D0 | AAAAAAAAAAAAAAAA E0 | MJJJJJXXXSS----- -F0 | CCCCC----------C +F0 | CCCCCCC--------C diff --git a/readme.txt b/readme.txt index d857140..b3a071c 100644 --- a/readme.txt +++ b/readme.txt @@ -1,5 +1,7 @@ -8608 +8608 - an 8-bit data, 16-bit address, CISC architecture. + +For a list of instructions, see instructionList.txt How to use the assembler: 1. Install bllua3 from https://notabug.org/redo/bllua3 @@ -11,4 +13,6 @@ How to use the assembler: You can also run the assembler from the command line to get a memory dump and disassembly in stdout, if you have lua installed: luajit "your_path/assembler-8608.lua" "other_path/filename.asm" -For a list of instructions, see instructionList.txt +How to use the emulator: +1. Install love2d from https://love2d.org +2. Open a command prompt in the "emulator" folder and run "love . C:/path/filename.asm" diff --git a/rom-8608-defs.lua b/rom-8608-defs.lua index 0838e59..e09fc7e 100644 --- a/rom-8608-defs.lua +++ b/rom-8608-defs.lua @@ -130,13 +130,15 @@ operations = { instructions = { { category = "Control", catlet="C" }, - { mnem="rst" , opcode=0x00, {"base","intFlgClk","irqFlgClk","runFlgClk","runFlgVal","clearRegs","loadInstr"}, desc="Clear all registers and set I=0", ccode={"cpu.a=0; cpu.b=0; cpu.c=0; cpu.u=0; cpu.t=0; cpu.p=0; cpu.q=0; cpu.s=0; cpu.v=0; cpu.i=0; cpu.cf=0; cpu.nz=0; cpu.irq=0; cpu.ifg=0; cpu.rfg=1; lni;"} }, + { mnem="rst" , opcode=0x00, {"base","intFlgClk","irqFlgClk","runFlgClk","runFlgVal","clearRegs","loadInstr"}, desc="Clear all registers and set I=0", ccode={"cpu.a=0; cpu.b=0; cpu.c=0; cpu.u=0; cpu.t=0; cpu.p=0; cpu.q=0; cpu.s=0; cpu.v=0; cpu.i=0; cpu.cf=0; cpu.nz=0; cpu.irq=0; cpu.ifg=0; cpu.rfg=1; cpu.ien=0; lni;"} }, { mnem="hlt" , opcode=0xF0, {"runFlgClk","instrNext"}, desc="Halt non-interrupt execution", ccode={"cpu.rfg=0; lni;"} }, { mnem="run" , opcode=0xF1, {"runFlgClk","runFlgVal","instrNext"}, desc ="Resume non-interrupt execution", ccode={"cpu.rfg=1; lni;"} }, { mnem="int" , opcode=0xF2, {"instrSwapIV","intFlgVal","intFlgClk","irqFlgClk"}, ccode={"cpu.irq=0; cpu.ifg=1; int t=cpu.i; cpu.i=cpu.v; cpu.v=(t-1)%65536; lni;"} }, { mnem="brk" , opcode=0xF3, {"instrSwapIV","adwInc","intFlgVal","intFlgClk"}, desc="Trigger interrupt", ccode={"cpu.ifg=1; int t=cpu.i; cpu.i=cpu.v; cpu.v=t; lni;"} }, { mnem="irt" , opcode=0xF4, {"instrSwapIV","adwInc","intFlgClk"}, desc="Return from interrupt", ccode={"cpu.ifg=0; int t=cpu.i; cpu.i=cpu.v; cpu.v=t; lni;"} }, { mnem="nop" , opcode=0xFF, {"instrNext"}, desc="Do nothing", ccode={"lni;"}, }, + { mnem="ien" , opcode=0xF5, {"instrNext"}, desc="Enbale interrupts", ccode={"cpu.ien=1; lni;"}, }, + { mnem="idi" , opcode=0xF6, {"instrNext"}, desc="Disable interrupts", ccode={"cpu.ien=0; lni;"}, }, { category = "16-bit Inc/Dec", catlet="I" }, { mnem="inc p" , opcode=0x12, {"adwlP","adwInc","adwSaveP","instrNext"}, desc="P++", ccode={"cpu.p++; lni;"} }, @@ -258,10 +260,10 @@ instructions = { { mnem="jpr imm8" , opcode=0x31, jmp=true, rel=true, ncycles=2, {"loadImmed","memSaveT","instrSub1"}, {"jmpRelT"}, desc="I+=imm8", ccode={"loadimmedt","jmprelt"} }, { mnem="jnz imm8" , opcode=0x30, jmp=true, rel=true, ncycles=2, {"loadImmed","memSaveT","instrSub23Cond","instrNext0NZ" }, {}, {"instrNext"}, {"jmpRelT"}, desc="I+=imm8 if !Zero" , ccode={"loadimmedt","if( cpu.nz ) { jmprelt } else { lni }"} }, { mnem="jpz imm8" , opcode=0x32, jmp=true, rel=true, ncycles=2, {"loadImmed","memSaveT","instrSub23Cond","instrNext0Z" }, {}, {"instrNext"}, {"jmpRelT"}, desc="I+=imm8 if Zero" , ccode={"loadimmedt","if(!cpu.nz ) { jmprelt } else { lni }"} }, - { mnem="jlt imm8" , opcode=0x33, jmp=true, rel=true, ncycles=2, {"loadImmed","memSaveT","instrSub23Cond","instrNext0NC" }, {}, {"instrNext"}, {"jmpRelT"}, desc="I+=imm8 if !Carry" , ccode={"loadimmedt","if(!cpu.cf ) { jmprelt } else { lni }"} }, - { mnem="jge imm8" , opcode=0x34, jmp=true, rel=true, ncycles=2, {"loadImmed","memSaveT","instrSub23Cond","instrNext0C" }, {}, {"instrNext"}, {"jmpRelT"}, desc="I+=imm8 if Carry" , ccode={"loadimmedt","if( cpu.cf ) { jmprelt } else { lni }"} }, - { mnem="jgt imm8" , opcode=0x35, jmp=true, rel=true, ncycles=2, {"loadImmed","memSaveT","instrSub23Cond","instrNext0NC","instrNext0Z"}, {}, {"jmpRelT"}, {"instrNext"}, desc="I+=imm8 if !Zero & Carry", ccode={"loadimmedt","if( cpu.nz && cpu.cf) { jmprelt } else { lni }"} }, - { mnem="jle imm8" , opcode=0x36, jmp=true, rel=true, ncycles=2, {"loadImmed","memSaveT","instrSub23Cond","instrNext0NC","instrNext0Z"}, {}, {"instrNext"}, {"jmpRelT"}, desc="I+=imm8 if Zero | !Carry", ccode={"loadimmedt","if(!cpu.nz && !cpu.cf) { jmprelt } else { lni }"} }, + { mnem="jge imm8" , opcode=0x33, jmp=true, rel=true, ncycles=2, {"loadImmed","memSaveT","instrSub23Cond","instrNext0NC" }, {}, {"instrNext"}, {"jmpRelT"}, desc="I+=imm8 if !Carry" , ccode={"loadimmedt","if(!cpu.cf ) { jmprelt } else { lni }"} }, + { mnem="jlt imm8" , opcode=0x34, jmp=true, rel=true, ncycles=2, {"loadImmed","memSaveT","instrSub23Cond","instrNext0C" }, {}, {"instrNext"}, {"jmpRelT"}, desc="I+=imm8 if Carry" , ccode={"loadimmedt","if( cpu.cf ) { jmprelt } else { lni }"} }, + { mnem="jgt imm8" , opcode=0x35, jmp=true, rel=true, ncycles=2, {"loadImmed","memSaveT","instrSub23Cond","instrNext0C","instrNext0Z"}, {}, {"jmpRelT"}, {"instrNext"}, desc="I+=imm8 if !Zero & Carry", ccode={"loadimmedt","if(cpu.nz && (!cpu.cf)) { jmprelt } else { lni }"} }, + { mnem="jle imm8" , opcode=0x36, jmp=true, rel=true, ncycles=2, {"loadImmed","memSaveT","instrSub23Cond","instrNext0C","instrNext0Z"}, {}, {"instrNext"}, {"jmpRelT"}, desc="I+=imm8 if Zero | !Carry", ccode={"loadimmedt","if((!cpu.nz) || cpu.cf) { jmprelt } else { lni }"} }, { category = "Stack", catlet="S" }, { mnem="psh a" , opcode=0x40, {"pushReg","alurA","instrSub1"}, {"instrNext"}, desc="*(S++)=A", ccode={"pushbyte(cpu.a);","lni;"} },