Compare commits

..

5 Commits

64 changed files with 6049 additions and 2585 deletions

2
.gitignore vendored
View File

@ -1,2 +0,0 @@
.vscode
programs

251
8608-definition.lua Normal file
View File

@ -0,0 +1,251 @@
-- 8608-definition.lua
-- This file contains information about the instruction set and microcode for the 8608 architecture.
-- It is used by generate-architecture.lua, alongside the instruction definitions in 8608-instructions.lua, to generate the following:
-- instructionList.txt, a human-readable list of all instructions.
-- 8608.asm, a set of definitions for CustomAsm that allows it to assemble 8608 programs.
-- The microcode ROM data, which is built into the physical CPU to control it.
local arch8608 = {
-- List of every control line in the CPU
-- Organized by bit position within the four microcode ROMs
roms = {
{ pos = {0, 0, 0}, size = {64, 16, 64}, signals = {
"alulU", "alulT", "alulC", "alulB", "alulA", "alurIL", "alurIH", "alurVL",
"alurVH", "alurSL", "alurSH", "alurQL", "alurQH", "alurPL", "alurPH", "alurU",
"alurT", "alurC", "alurB", "alurA", "alur1", "alur2", "alurm1", "alurm2",
"adrrhU", "adrrhC", "adrrlT", "adrrTX", "_", "adrr2A", "adwrhU", "adwrhC",
"adwrlT", "adwrTX", "adwrlA", "adwrAX", "adwlI", "adwlV", "adwlS", "adwlQ",
"adwlP", "adrlI", "adrlV", "adrlS", "adrlQ", "adrlP", "aluAdd", "adwSaveV",
"aluRun", "aluRInv", "aluCinOn", "aluCinC", "memWriteAlur", "adrInc", "adwInc", "aluXor",
"aluIor", "aluAnd", "memWriteAlur", "adrOut", "adrSaveI", "adwSaveP", "adwSaveQ", "adwSaveS",
} },
{ pos = {-34, 16, 0}, size = {32, 32, 8}, signals = {
"aluSaveU", "aluSaveT", "aluSaveC", "aluSaveB", "aluSaveA", "aluSaveCarry", "aluSaveNZ", "always1",
} },
{ pos = {-34, 16, 17}, size = {32, 32, 32}, signals = {
"_", "_", "_", "_", "_", "_", "_", "_",
"_", "memSaveF", "memSaveNZ", "instrPre", "instrLoadPre", "always1", "instrLoadSel", "adrOut",
"memWriteAlur", "memSave", "instrNext0NZ", "instrNext0Z", "instrNext0NC", "instrNext0C", "instrLoadSub", "instrLoad",
"instrNext2", "instrNext1", "instrNext0", "memSaveU", "memSaveT", "memSaveC", "memSaveB", "memSaveA",
} },
{ pos = {66, 16, 0}, size = {32, 32, 32}, signals = {
"adrr1", "adrrm1", "adrrm4", "adrr2", "adwrm1", "adwrm2", "adwr2", "adwr1",
"memRead", "memWrite", "runFlgVal", "runFlgClk", "intFlgVal", "intFlgClk", "irqFlgClk", "always1",
"aluShiftArith", "aluShiftRoll", "aluShiftRight", "aluShift", "alurF", "_", "_", "_",
"_", "_", "_", "_", "_", "_", "_", "_",
} },
},
-- Macro operations
-- These can be used as a shortcut to convey that multiple control lines should be set
-- Macro definitions may contain other macros
operations = {
base = {"always1"},
instrNext = {"base","adrlI","adrInc","adrSaveI","loadInstr"},
instrSub1 = {"base","instrLoadSub", "instrNext0"},
instrSub2 = {"base","instrLoadSub", "instrNext1", },
instrSub3 = {"base","instrLoadSub", "instrNext1","instrNext0"},
instrSub4 = {"base","instrLoadSub","instrNext2", },
instrSub5 = {"base","instrLoadSub","instrNext2", "instrNext0"},
instrSub6 = {"base","instrLoadSub","instrNext2","instrNext1", },
instrSub7 = {"base","instrLoadSub","instrNext2","instrNext1","instrNext0"},
instrSub23Cond = {"base","instrLoadSub","instrNext1"},
-- instrSwapIV = {"base","adwlI","adwSaveV","adrlV","adrSaveI","loadInstr"},
instrPreload = {"adrlI","adrInc","adrSaveI","adrOut","memRead","instrLoadSel","instrLoadPre"},
instrNextPre = {"base","instrPre","instrLoad","instrLoadSub"},
loadInstr = {"adrOut","memRead","instrLoadSel","instrLoad","instrLoadSub"},
loadReg = {"adrOut","memRead","memSave"},
storeReg = {"adrOut","memWrite","memWriteAlur"},
loadRegT = {"loadReg","memSaveT"},
pushReg = {"storeReg","adrlS","adwlS","adwInc","adwSaveS"},
popReg = {"loadReg","adrlS","adrrm1","adwlS","adwrm1","adwSaveS"},
pop161 = {"popReg","memSaveT"},
pop162 = {"popReg","memSaveU"},
loadImmed = {"adrlI","adrInc","adrSaveI","loadReg"},
loadImmedT = {"loadImmed","memSaveT"},
loadImm161 = {"loadImmed","memSaveU"},
loadImm162 = {"loadImmed","memSaveT"},
--loadStackRel = {"adrlS","adrrTX","loadReg"},
loadStackRel = {"adrrlT","loadReg"},
loadStackRelT = {"loadStackRel","memSaveT"},
loadStackRelU = {"loadStackRel","memSaveU"},
loadStackRel161 = {"loadStackRel", "memSaveU"},
loadStackRel162 = {"loadStackRel","adrInc","memSaveT"},
--storeStackRel = {"adrlS","adrrTX","storeReg"},
storeStackRel = {"adrrlT","storeReg"},
storeStackRel161 = {"storeStackRel" },
storeStackRel162 = {"storeStackRel","adrInc"},
storeStackRelU = {"storeStackRel","alurU"},
load161 = { "loadReg","memSaveU"},
load162 = {"adrInc","loadReg","memSaveT"},
store161 = { "storeReg"},
store162 = {"adrInc","storeReg"},
loadUTU = {"adrrUT", "loadReg","memSaveU"},
storeUT = {"adrrUT", "storeReg"},
storeUTP = {"adrrUT","adrlP","storeReg"},
storeUTQ = {"adrrUT","adrlQ","storeReg"},
memSaveFlags = {"memSaveNZ"},
load16FE1 = {"adrrm4","adrr2","load161"},
load16FE2 = {"adrrm4","adrr2","load162"},
load16FC1 = {"adrrm4", "load161"},
load16FC2 = {"adrrm4", "load162"},
adwrUT = {"adwrhU","adwrlT"},
adrrUT = {"adrrhU","adrrlT"},
-- adwrCB = {"adwrhC","adwrlB"},
adwIncUT = {"adwrUT", "adwInc"},
adwIncUTP = {"adwrUT","adwlP","adwInc"},
adwIncUTQ = {"adwrUT","adwlQ","adwInc"},
adwP = {"adwlP","adwSaveP"},
adwQ = {"adwlQ","adwSaveQ"},
adwS = {"adwlS","adwSaveS"},
incP = {"adwP","adwInc"},
incQ = {"adwQ","adwInc"},
incP2 = {"adwP","adwr2"},
incQ2 = {"adwP","adwr2"},
saveIV = {"adwlI","adwSaveV"},
jmpRelT = {"instrNext","adrrTX"},
jmpAbs = {"base","loadInstr","adrSaveI"},
jmpAbsUT = {"jmpAbs","adrrUT"},
jmpAbsP = {"jmpAbs","adrlP"},
jmpAbsQ = {"jmpAbs","adrlQ"},
jmpAbsV = {"jmpAbs","adrlV"},
saveRetAddr = {"adwlI","adwInc","adwSaveQ"},
pushRetAddr1 = {"alurIH","pushReg"},
pushRetAddr2 = {"alurIL","pushReg"},
aluA = {"alulA","aluSaveA"},
aluB = {"alulB","aluSaveB"},
aluC = {"alulC","aluSaveC"},
aluT = {"alulT","aluSaveT"},
aluU = {"alulU","aluSaveU"},
aluOpAdd = {"aluRun","aluAdd","aluSaveCarry","aluSaveNZ" },
aluOpAddC= {"aluRun","aluAdd","aluSaveCarry","aluSaveNZ", "aluCinC" },
aluOpSub = {"aluRun","aluAdd","aluSaveCarry","aluSaveNZ","aluRInv","aluCinOn"},
aluOpSubC= {"aluRun","aluAdd","aluSaveCarry","aluSaveNZ","aluRInv","aluCinC" },
aluOpAnd = {"aluRun","aluAnd" , "aluSaveNZ"},
aluOpIor = {"aluRun","aluIor" , "aluSaveNZ"},
aluOpXor = {"aluRun","aluXor" , "aluSaveNZ"},
aluOpCmp = {"aluOpSub"},
aluOpInc = {"aluOpAdd","aluCinOn"},
aluOpDec = {"aluOpAdd","aluRInv"},
aluOpMov = {"aluAdd","aluSaveNZ"},
aluOpShl = {"aluRun", "aluShift" ,"aluSaveNZ"},
aluOpShr = {"aluRun", "aluShift","aluShiftRight" ,"aluSaveNZ"},
aluOpRol = {"aluRun", "aluShift", "aluShiftRoll" ,"aluSaveNZ"},
aluOpRor = {"aluRun", "aluShift","aluShiftRight","aluShiftRoll" ,"aluSaveNZ"},
aluOpSra = {"aluRun", "aluShift","aluShiftRight", "aluShiftArith","aluSaveNZ"},
clearRegs = {
"aluSaveA","aluSaveB","aluSaveC","aluSaveU","aluSaveT",
"adwSaveP","adwSaveQ","adwSaveS","adwSaveV",
"adrSaveI",
"aluSaveNZ","aluSaveCarry",
"intFlgClk",
"irqFlgClk",
"runFlgClk","runFlgVal",
},
},
-- Shortcuts for instruction descriptions
-- These strings will be substituted into instruction descriptions wherever their [key] occurs
descShortcuts = {
{"%mem", "a value from memory"},
{"%mem16", "a value from memory"},
{"%imm8", "a given 8-bit value"},
{"%imm16", "a given 16-bit value"},
{"%A", "the value in the A register"},
{"%B", "the value in the B register"},
{"%C", "the value in the C register"},
{"%xInc16", "increment the X register by 2 bytes"},
{"%yInc16", "increment the Y register by 2 bytes"},
{"%xInc", "increment the X register"},
{"%yInc", "increment the Y register"},
{"%Xin16", "the 16-bit value in memory at the address in X"},
{"%Yinn16", "the 16-bit value in memory at the address in Y"},
{"%xIn", "the value in memory at the address in X"},
{"%yIn", "the value in memory at the address in Y"},
{"%XofsIn16", "the 16-bit value in memory at the address (X plus a given 8-bit offset)"},
{"%YofsIn16", "the 16-bit value in memory at the address (Y plus a given 8-bit offset)"},
{"%XofsIn", "the value in memory at the address (X plus a given 8-bit offset)"},
{"%YofsIn", "the value in memory at the address (Y plus a given 8-bit offset)"},
{"%Xofs", "the address (X plus a given 8-bit offset)"},
{"%Yofs", "the address (Y plus a given 8-bit offset)"},
{"%X", "the 16-bit value in the X register"},
{"%Y", "the 16-bit value in the Y register"},
{"%adrX", "the address in X"},
{"%adrY", "the address in Y"},
{"%zpgIn16", "the 16-bit value in memory at a given 8-bit address"},
{"%zpgIn", "the value in memory at a given 8-bit address"},
{"%zpg", "an given 8-bit address"},
{"%absIn16", "the 16-bit value in memory at a given 16-bit address"},
{"%absIn", "the value in memory at a given 16-bit address"},
{"%abs", "a given 16-bit address"},
{"%alu", "and store the result in the A register"},
{"%flags", " and set the Carry Flag and Zero Flag according to the result"},
{"%zflag", " and set the Zero Flag according to the result"},
{"%cmp", "Set the Carry Flag and Zero Flag according to the result of subtracting"},
{"%brel", "Add a signed 8-bit offset to the Program Counter, jumping forward or backward in the program"},
{"%brelc", "Otherwise, do nothing"},
{"%if", "If the result of the last math operation was"},
{"%zFlgMem", "and set the Zero Flag according to the value loaded"},
},
-- Aliases for instructions
-- Used to generate the assembler definitions.
-- imm8neg instead of imm8 means the immediate value will be negated when assembling.
transformMnemonic = function(mnem)
mnem = mnem:gsub("zpg", "imm8u")
mnem = mnem:gsub("ofs", "imm8u")
mnem = mnem:gsub("rel", "imm8rel")
mnem = mnem:gsub("abs", "imm16")
mnem = mnem:gsub("ind", "imm16")
mnem = mnem:gsub("#", "#imm8")
mnem = mnem:gsub("#imm8#imm8", "#imm16")
return mnem
end,
aliases = {
-- ["jmp q" ] = {"ret" },
["ADD imm8" ] = {"SUB imm8neg"},
-- ["adb imm8" ] = {"sbb imm8neg"},
-- ["adc imm8" ] = {"sbc imm8neg"},
["ADC imm8" ] = {"SBC imm8neg"},
},
-- Filename to generate the assembler definitions file to.
assemblerDefsFile = "8608.asm",
-- Header to be inserted at the top of the assembler definitions file
assemblerDefsHeader = [[
; 8608.asm
; Include this file into a CustomAsm assembly file to use the 8608 architecture, like so:
; #include "8608.asm"
; See CustomAsm for more info: https://github.com/hlorenzi/customasm
; Generated by generate-architecture.lua using the definitions in 8608-definition.lua
; Definitions for all instructions in the 8608 architecture.
]],
-- Filename to generate the instruction listing file to.
instructionListFile = "instructionList.txt",
-- Header to be inserted at the top of the instruction listing file
instructionListHeader = [[
instructionList.txt
List of all instructions in the 8608 architecture.
Instructions are encoded as the opcode, followed by any immediate values.
16-bit immediates are encoded in big-endian byte order.
Each instruction is described in order of: Mnemonic, Opcode, Clock cycles, Description
]],
}
return arch8608

299
8608-instructions.lua Normal file
View File

@ -0,0 +1,299 @@
-- 8608-instructions.lua
-- This file contains the formal definitions for each instruction in the 8608 architecture.
-- It is used by generate-architecture.lua, alongside the definitions in 8608-definition.lua, to generate the following:
-- instructionList.txt, a human-readable list of all instructions.
-- 8608.asm, a set of definitions for CustomAsm that allows it to assemble 8608 programs.
-- The microcode ROM data, which is built into the physical CPU to control it.
-- List of definitions for every instruction
-- Each instruction definition contains:
-- Mnemonic: The mnemonic used to generate the assembler definitions and instruction list.
-- This is what must literally appear in the assembly code in order to generate this instruction, other than immediate values.
-- "imm8" means an 8-bit value.
-- "imm16" means a 16-bit value.
-- Opcode: The machine code byte that represents this operation.
-- Used by the assembler generator to map mnemonics to opcodes.
-- Used by the microcode generator to place the instruction's data within the microcode ROM, which is addressed by opcode.
-- List of control signals: Specifies the control lines that will be activated by the microcode when the instruction is executed.
-- Instructions may take multiple clock cycles. To convey this, each clock cycle is represented by an independent list of microcode signals.
-- Under the hood, the microcode ROM uses a 10-bit address: 8 bits for the opcode, and 2 bits for the clock cycle.
-- Because of this, each opcode may only use up to 4 clock cycles.
-- If more are required, the least significant bit of the opcode can be set by a control line, incrementing the opcode.
-- This causes one instruction to use up multiple opcodes.
-- The need for this is determined automatically by the microcode generator: whenever an instruction specifies more than 4 lists of control signals.
-- Description: A brief description of the instruction. Used to generate the instruction list.
-- C Code: Used to generate an emulator (as part of a separate project).
-- Categories can be specified. These serve only to organize the instruction list.
-- The category letter determines what letter will be used to represent the instructions in the opcode map, located at the bottom of the instruction list.
local instructions = {
{ category = "Control", catlet="C" },
{ mnem="RST" , opcode=0x41, {"clearRegs","load16FC1","instrSub1"},{"load16FC2","instrSub2"},{ "jmpAbsUT"}, desc="Clear all registers and flags, load the Program Counter from memory addresses $FFFC-$FFFD, and execute the code at the address given by those bytes" , 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.rfg=1; cpu.ien=0; cpu.irq=0; cpu.ifg=0; cpu.u=readmemory(0xFFFC);","cpu.t=readmemory(0xFFFD);","jmpabsut;"} },
{ mnem="INT" , opcode=0x01, { "load16FE1","instrSub1"},{"load16FE2","instrSub2"},{"intFlgVal","intFlgClk","irqFlgClk","saveIV", "jmpAbsUT"}, ccode={" cpu.irq=0; cpu.ifg=1; cpu.u=readmemory(0xFFFE);","cpu.t=readmemory(0xFFFF);","cpu.v=(cpu.i-1)%65536; jmpabsut;"} },
{ mnem="BRK" , opcode=0x00, { "load16FE1","instrSub1"},{"load16FE2","instrSub2"},{"intFlgVal","intFlgClk" ,"saveIV","adwInc","jmpAbsUT"}, desc="Trigger an interrupt from software, saving the current Program Counter in the V register and jumping to the Interrupt Vector stored at memory addresses $FFFE-$FFFF", ccode={" cpu.ifg=1; cpu.u=readmemory(0xFFFE);","cpu.t=readmemory(0xFFFF);","cpu.v=(cpu.i )%65536; jmpabsut;"} },
{ mnem="RTI" , opcode=0x40, {"adwInc","intFlgClk","jmpAbsV"}, desc="Return from an interrupt, resuming normal execution where it left off when the interrupt occurred", ccode={"cpu.ifg=0; int t=cpu.i; cpu.i=cpu.v; cpu.v=t; lni;"} },
{ mnem="NOP" , opcode=0xEA, {"instrNext"}, desc="Do nothing", ccode={"lni;"}, },
{ mnem="CLI" , opcode=0x58, {"instrNext"}, desc="Enable interrupts to be triggered by external hardware", ccode={"cpu.ien=1; lni;"}, }, -- todo
{ mnem="SEI" , opcode=0x78, {"instrNext"}, desc="Disable interrupts being triggered by external hardware", ccode={"cpu.ien=0; lni;"}, }, -- todo
{ mnem="HLT" , opcode=0x18, {"runFlgClk","instrNext"}, desc="Clear the Run Flag, preventing the CPU from running until an interrupt is triggered", ccode={"cpu.rfg=0; lni;"} },
{ mnem="RUN" , opcode=0x38, {"runFlgClk","runFlgVal","instrNext"}, desc ="Set the Run Flag, allowing the CPU to run once the current interrupt finishes", ccode={"cpu.rfg=1; lni;"} },
-- { category = "16-bit Increment/Decrement", catlet="I" },
-- { mnem="INX" , opcode=0x11, {"adwlP","adwInc","adwSaveP","instrNext"}, desc="Increment the 16-bit X register", ccode={"cpu.p++; lni;"} },
-- { mnem="DEX" , opcode=0x31, {"adwlP","adwrm1","adwSaveP","instrNext"}, desc="Decrement the 16-bit X register", ccode={"cpu.p--; lni;"} },
-- { mnem="INY" , opcode=0x51, {"adwlQ","adwInc","adwSaveQ","instrNext"}, desc="Increment the 16-bit Y register", ccode={"cpu.q++; lni;"} },
-- { mnem="DEY" , opcode=0x71, {"adwlQ","adwrm1","adwSaveQ","instrNext"}, desc="Decrement the 16-bit Y register", ccode={"cpu.q--; lni;"} },
{ category = "8-bit Unary Arithmetic", catlet="U" },
{ mnem="INC A" , opcode=0xF6, {"aluA","alur1" ,"aluOpAdd" ,"instrNext"}, desc="Increment the A register, %flags" , ccode={"addf(cpu.a, 1 ); lni;"} },
{ mnem="DEC A" , opcode=0xD6, {"aluA","alurm1","aluOpAdd" ,"instrNext"}, desc="Decrement the A register, %flags" , ccode={"addf(cpu.a,-1 ); lni;"} },
{ mnem="ICC A" , opcode=0x57, {"aluA", "aluOpAddC","instrNext"}, desc="Add the Carry Flag to the A register, %flags", ccode={"addf(cpu.a,cpu.cf); lni;"} },
{ mnem="INC B" , opcode=0xFE, {"aluB","alur1" ,"aluOpAdd" ,"instrNext"}, desc="Increment the B register, %flags" , ccode={"addf(cpu.b, 1 ); lni;"} },
{ mnem="DEC B" , opcode=0xDE, {"aluB","alurm1","aluOpAdd" ,"instrNext"}, desc="Decrement the B register, %flags" , ccode={"addf(cpu.b,-1 ); lni;"} },
{ mnem="ICC B" , opcode=0x5F, {"aluB", "aluOpAddC","instrNext"}, desc="Add the Carry Flag to the B register, %flags", ccode={"addf(cpu.b,cpu.cf); lni;"} },
{ mnem="INC C" , opcode=0xFA, {"aluC","alur1" ,"aluOpAdd" ,"instrNext"}, desc="Increment the C register, %flags" , ccode={"addf(cpu.c, 1 ); lni;"} },
{ mnem="DEC C" , opcode=0xDA, {"aluC","alurm1","aluOpAdd" ,"instrNext"}, desc="Decrement the C register, %flags" , ccode={"addf(cpu.c,-1 ); lni;"} },
{ mnem="ICC C" , opcode=0x5B, {"aluC", "aluOpAddC","instrNext"}, desc="Add the Carry Flag to the C register, %flags", ccode={"addf(cpu.c,cpu.cf); lni;"} },
-- { mnem="TST A" , opcode=0x , {"alulA", "aluOpCmp" ,"instrNext"}, desc="Set flags according to A-0", ccode={"tst(cpu.a); lni;"} },
-- { mnem="TST B" , opcode=0x , {"alulB", "aluOpCmp" ,"instrNext"}, desc="Set flags according to B-0", ccode={"tst(cpu.b); lni;"} },
-- { mnem="TST C" , opcode=0x , {"alulC", "aluOpCmp" ,"instrNext"}, desc="Set flags according to C-0", ccode={"tst(cpu.c); lni;"} },
{ mnem="INC zpg" , opcode=0xE6, {"loadImmedT","instrSub1"}, {"loadStackRelU","instrSub2"}, {"aluU","alur1" ,"aluOpAdd" ,"instrSub3","instrPreload"}, {"storeStackRelU","instrNextPre"}, desc="Increment the value at %zpg, %flags" , ccode={"loadimmedt","loadstackrelu","instrpreload; addf(cpu.u, 1 );","storestackrelu; instrloadpre"} },
{ mnem="DEC zpg" , opcode=0xC6, {"loadImmedT","instrSub1"}, {"loadStackRelU","instrSub2"}, {"aluU","alurm1","aluOpAdd" ,"instrSub3","instrPreload"}, {"storeStackRelU","instrNextPre"}, desc="Decrement the value at %zpg, %flags" , ccode={"loadimmedt","loadstackrelu","instrpreload; addf(cpu.u,-1 );","storestackrelu; instrloadpre"} },
{ mnem="ICC zpg" , opcode=0x47, {"loadImmedT","instrSub1"}, {"loadStackRelU","instrSub2"}, {"aluU", "aluOpAddC","instrSub3","instrPreload"}, {"storeStackRelU","instrNextPre"}, desc="Add the Carrry Flag to the value at %zpg, %flags", ccode={"loadimmedt","loadstackrelu","instrpreload; addf(cpu.u,cpu.cf);","storestackrelu; instrloadpre"} },
-- { mnem="TST zpg" , opcode=0x , {"loadImmedT","instrSub1"}, {"loadStackRelU","instrSub2"}, {"alulU", "aluOpCmp" ,"instrNext"}, desc="Set flags according to *(S+imm8)-0", ccode={"loadimmedt","loadstackrelu","tst(cpu.u); lni;"} },
{ category = "8-bit Arithmetic and Logic", catlet="A" },
{ mnem="ADD #" , opcode=0x6B, {"loadImmedT","instrSub1"}, {"aluA", "alurT","aluOpAdd" ,"instrNext"}, desc="Add %imm8 to %A, %flags" , ccode={"loadimmedt","addf(cpu.a,cpu.t); lni;"} },
-- { mnem="ADB #" , opcode=0x , {"loadImmedT","instrSub1"}, {"aluB", "alurT","aluOpAdd" ,"instrNext"}, desc="" , ccode={"loadimmedt","addf(cpu.b,cpu.t); lni;"} },
-- { mnem="ADC #" , opcode=0x , {"loadImmedT","instrSub1"}, {"aluC", "alurT","aluOpAdd" ,"instrNext"}, desc="" , ccode={"loadimmedt","addf(cpu.c,cpu.t); lni;"} },
{ mnem="SUB #" , opcode=0xEB, {"loadImmedT","instrSub1"}, {"aluA", "alurT","aluOpSub" ,"instrNext"}, desc="Subtract %imm8 from %A, %flags" , ccode={"loadimmedt","subf(cpu.a,cpu.t); lni;"} },
{ mnem="ADC #" , opcode=0x69, {"loadImmedT","instrSub1"}, {"aluA", "alurT","aluOpAddC","instrNext"}, desc="Add %imm8 plus the Carry Flag to %A, %flags" , ccode={"loadimmedt","addf(cpu.a,cpu.t+cpu.cf); lni;"} },
{ mnem="SBC #" , opcode=0xE9, {"loadImmedT","instrSub1"}, {"aluA", "alurT","aluOpSubC","instrNext"}, desc="Subtract %imm8 from %A including the Carry Flag, %flags" , ccode={"loadimmedt","addf(cpu.a,~cpu.t+cpu.cf); lni;"} },
{ mnem="CMP #" , opcode=0xC9, {"loadImmedT","instrSub1"}, {"alulA","alurT","aluOpSub" ,"instrNext"}, desc="%cmp %imm8 from %A" , ccode={"loadimmedt","cmpf(cpu.a,cpu.t); lni;"} },
{ mnem="AND #" , opcode=0x29, {"loadImmedT","instrSub1"}, {"aluA", "alurT","aluOpAnd" ,"instrNext"}, desc="Bitwise AND %A with %imm8, %zflag" , ccode={"loadimmedt","cpu.a&=cpu.t; setzf(cpu.a); lni;"} },
{ mnem="ORA #" , opcode=0x09, {"loadImmedT","instrSub1"}, {"aluA", "alurT","aluOpIor" ,"instrNext"}, desc="Bitwise OR %A with %imm8, %zflag" , ccode={"loadimmedt","cpu.a|=cpu.t; setzf(cpu.a); lni;"} },
{ mnem="EOR #" , opcode=0x49, {"loadImmedT","instrSub1"}, {"aluA", "alurT","aluOpXor" ,"instrNext"}, desc="Bitwise Exclusive OR %A with %imm8, %zflag" , ccode={"loadimmedt","cpu.a^=cpu.t; setzf(cpu.a); lni;"} },
{ mnem="ASL #" , opcode=0x15, {"loadImmedT","instrSub1"}, {"aluA", "alurT","aluOpShl" ,"instrNext"}, desc="Bit-shift %A left by a given number of bits, %zflag" , ccode={"loadimmedt","cpu.a<<=cpu.t; setzf(cpu.a); lni;"} },
{ mnem="LSR #" , opcode=0x55, {"loadImmedT","instrSub1"}, {"aluA", "alurT","aluOpShr" ,"instrNext"}, desc="Bit-shift %A right by a given number of bits, %zflag" , ccode={"loadimmedt","cpu.a>>=cpu.t; setzf(cpu.a); lni;"} },
{ mnem="ROL #" , opcode=0x35, {"loadImmedT","instrSub1"}, {"aluA", "alurT","aluOpRol" ,"instrNext"}, desc="Bit-rotate %A left by a given number of bits, %zflag" , ccode={"loadimmedt","cpu.a=rol(cpu.a,cpu.t); setzf(cpu.a); lni;"} },
{ mnem="ROR #" , opcode=0x75, {"loadImmedT","instrSub1"}, {"aluA", "alurT","aluOpRor" ,"instrNext"}, desc="Bit-rotate %A right by a given number of bits, %zflag" , ccode={"loadimmedt","cpu.a=ror(cpu.a,cpu.t); setzf(cpu.a); lni;"} },
-- { mnem="ASR #" , opcode=0x , {"loadImmedT","instrSub1"}, {"aluA", "alurT","aluOpSra" ,"instrNext"}, desc="A>>a=imm8, set zero flag" , ccode={"loadimmedt","cpu.a=sra(cpu.a,cpu.t); setzf(cpu.a); lni;"} },
{ mnem="ADD zpg" , opcode=0x67, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluA", "alurT","aluOpAdd" ,"instrNext"}, desc="Add %zpgIn to %A, %flags" , ccode={"loadimmedt","loadstackrelu","addf(cpu.a,cpu.u); lni;"} },
-- { mnem="adb zpg" , opcode=0x , {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluB", "alurT","aluOpAdd" ,"instrNext"}, desc="B+=*(S+imm8), set flags" , ccode={"loadimmedt","loadstackrelu","addf(cpu.b,cpu.u); lni;"} },
-- { mnem="adc zpg" , opcode=0x , {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluC", "alurT","aluOpAdd" ,"instrNext"}, desc="C+=*(S+imm8), set flags" , ccode={"loadimmedt","loadstackrelu","addf(cpu.c,cpu.u); lni;"} },
{ mnem="SUB zpg" , opcode=0xE7, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluA", "alurT","aluOpSub" ,"instrNext"}, desc="Subtract %zpgIn from %A, %flags" , ccode={"loadimmedt","loadstackrelu","subf(cpu.a,cpu.u); lni;"} },
-- { mnem="sbb zpg" , opcode=0x , {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluB", "alurT","aluOpSub" ,"instrNext"}, desc="B-=*(S+imm8), set flags" , ccode={"loadimmedt","loadstackrelu","subf(cpu.b,cpu.u); lni;"} },
-- { mnem="sbc zpg" , opcode=0x , {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluC", "alurT","aluOpSub" ,"instrNext"}, desc="C-=*(S+imm8), set flags" , ccode={"loadimmedt","loadstackrelu","subf(cpu.c,cpu.u); lni;"} },
{ mnem="ADC zpg" , opcode=0x65, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluA", "alurT","aluOpAddC","instrNext"}, desc="Add %zpgIn plus the Carry Flag to %A, %flags" , ccode={"loadimmedt","loadstackrelu","addf(cpu.a,cpu.u+cpu.cf); lni;"} },
{ mnem="SBC zpg" , opcode=0xE5, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluA", "alurT","aluOpSubC","instrNext"}, desc="Subtract %zpgIn from %A including the Carry Flag, %flags", ccode={"loadimmedt","loadstackrelu","addf(cpu.a,~cpu.u+cpu.cf); lni;"} },
{ mnem="CMP zpg" , opcode=0xC5, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"alulA","alurT","aluOpSub" ,"instrNext"}, desc="%cmp %zpgIn from %A" , ccode={"loadimmedt","loadstackrelu","cmpf(cpu.a,cpu.u); lni;"} },
{ mnem="AND zpg" , opcode=0x25, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluA", "alurT","aluOpAnd" ,"instrNext"}, desc="Bitwise AND %A with %zpgIn, %flags" , ccode={"loadimmedt","loadstackrelu","cpu.a&=cpu.u; setzf(cpu.a); lni;"} },
{ mnem="ORA zpg" , opcode=0x05, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluA", "alurT","aluOpIor" ,"instrNext"}, desc="Bitwise OR %A with %zpgIn, %flags" , ccode={"loadimmedt","loadstackrelu","cpu.a|=cpu.u; setzf(cpu.a); lni;"} },
{ mnem="EOR zpg" , opcode=0x45, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluA", "alurT","aluOpXor" ,"instrNext"}, desc="Bitwise Exclusive OR %A with %zpgIn, %flags" , ccode={"loadimmedt","loadstackrelu","cpu.a^=cpu.u; setzf(cpu.a); lni;"} },
-- { mnem="ASL zpg" , opcode=0x , {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluA", "alurT","aluOpShl" ,"instrNext"}, desc="A<<=*(S+imm8), set zero flag" , ccode={"loadimmedt","loadstackrelu","cpu.a<<=cpu.u; setzf(cpu.a); lni;"} },
-- { mnem="LSR zpg" , opcode=0x , {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluA", "alurT","aluOpShr" ,"instrNext"}, desc="A<<=*(S+imm8), set zero flag" , ccode={"loadimmedt","loadstackrelu","cpu.a>>=cpu.u; setzf(cpu.a); lni;"} },
-- { mnem="ROL zpg" , opcode=0x , {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluA", "alurT","aluOpRol" ,"instrNext"}, desc="A<<<=*(S+imm8), set zero flag" , ccode={"loadimmedt","loadstackrelu","cpu.a=rol(cpu.a,cpu.u); setzf(cpu.a); lni;"} },
-- { mnem="ROR zpg" , opcode=0x , {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluA", "alurT","aluOpRor" ,"instrNext"}, desc="A>>>=*(S+imm8), set zero flag" , ccode={"loadimmedt","loadstackrelu","cpu.a=ror(cpu.a,cpu.u); setzf(cpu.a); lni;"} },
-- { mnem="ASR zpg" , opcode=0x , {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluA", "alurT","aluOpSra" ,"instrNext"}, desc="A>>a=*(S+imm8), set zero flag" , ccode={"loadimmedt","loadstackrelu","cpu.a=sra(cpu.a,cpu.u); setzf(cpu.a); lni;"} },
{ mnem="ADD B" , opcode=0x7F, {"aluA", "alurB","aluOpAdd" ,"instrNext"}, desc="Add %B to %A, %flags" , ccode={"addf(cpu.a,cpu.b); lni;"} },
-- { mnem="adc B" , opcode=0x , {"aluC", "alurB","aluOpAdd" ,"instrNext"}, desc="C+=B, set flags" , ccode={"addf(cpu.c,cpu.b); lni;"} },
{ mnem="SUB B" , opcode=0xFF, {"aluA", "alurB","aluOpSub" ,"instrNext"}, desc="Subtract %B from %A, %flags" , ccode={"subf(cpu.a,cpu.b); lni;"} },
-- { mnem="sbc B" , opcode=0x , {"aluC", "alurB","aluOpSub" ,"instrNext"}, desc="C-=B, set flags" , ccode={"subf(cpu.c,cpu.b); lni;"} },
{ mnem="ADC B" , opcode=0x7D, {"aluA", "alurB","aluOpAddC","instrNext"}, desc="Add %B plus the Carry Flag to %A, %flags" , ccode={"addf(cpu.a,cpu.b+cpu.cf); lni;"} },
{ mnem="SBC B" , opcode=0xFD, {"aluA", "alurB","aluOpSubC","instrNext"}, desc="Subtract %B form %A including the Carry Flag, %flags" , ccode={"addf(cpu.a,-cpu.b+cpu.cf); lni;"} },
{ mnem="CMP B" , opcode=0xDD, {"alulA","alurB","aluOpSub" ,"instrNext"}, desc="%cmp %B from %A" , ccode={"cmpf(cpu.a,cpu.b); lni;"} },
{ mnem="AND B" , opcode=0x3D, {"aluA", "alurB","aluOpAnd" ,"instrNext"}, desc="Bitwise AND %A with %B, %flags" , ccode={"cpu.a&=cpu.b; setzf(cpu.a); lni;"} },
{ mnem="ORA B" , opcode=0x1D, {"aluA", "alurB","aluOpIor" ,"instrNext"}, desc="Bitwise OR %A with %B, %flags" , ccode={"cpu.a|=cpu.b; setzf(cpu.a); lni;"} },
{ mnem="EOR B" , opcode=0x5D, {"aluA", "alurB","aluOpXor" ,"instrNext"}, desc="Bitwise Exclusive OR %A with %B, %flags" , ccode={"cpu.a^=cpu.b; setzf(cpu.a); lni;"} },
-- { mnem="ASL B" , opcode=0x , {"aluA", "alurB","aluOpShl" ,"instrNext"}, desc="A<<=B, set zero flag" , ccode={"cpu.a<<=cpu.b; setzf(cpu.a); lni;"} },
-- { mnem="LSR B" , opcode=0x , {"aluA", "alurB","aluOpShr" ,"instrNext"}, desc="A>>=B, set zero flag" , ccode={"cpu.a>>=cpu.b; setzf(cpu.a); lni;"} },
-- { mnem="ROL B" , opcode=0x , {"aluA", "alurB","aluOpRol" ,"instrNext"}, desc="A<<<=B, set zero flag" , ccode={"cpu.a=rol(cpu.a,cpu.b); setzf(cpu.a); lni;"} },
-- { mnem="ROR B" , opcode=0x , {"aluA", "alurB","aluOpRor" ,"instrNext"}, desc="A>>>=B, set zero flag" , ccode={"cpu.a=ror(cpu.a,cpu.b); setzf(cpu.a); lni;"} },
-- { mnem="ASR B" , opcode=0x , {"aluA", "alurB","aluOpSra" ,"instrNext"}, desc="A>>a=B, set zero flag" , ccode={"cpu.a=sra(cpu.a,cpu.b); setzf(cpu.a); lni;"} },
{ mnem="ADD C" , opcode=0x7B, {"aluA", "alurC","aluOpAdd" ,"instrNext"}, desc="Add %C to %A, %flags" , ccode={"addf(cpu.a,cpu.c); lni;"} },
-- { mnem="adb C" , opcode=0x , {"aluB", "alurC","aluOpAdd" ,"instrNext"}, desc="B+=C, set flags" , ccode={"addf(cpu.b,cpu.c); lni;"} },
{ mnem="SUB C" , opcode=0xFB, {"aluA", "alurC","aluOpSub" ,"instrNext"}, desc="Subtract %C from %A, %flags" , ccode={"subf(cpu.a,cpu.c); lni;"} },
-- { mnem="sbb C" , opcode=0x , {"aluB", "alurC","aluOpSub" ,"instrNext"}, desc="B-=C, set flags" , ccode={"subf(cpu.b,cpu.c); lni;"} },
{ mnem="ADC C" , opcode=0x79, {"aluA", "alurC","aluOpAddC","instrNext"}, desc="Add %C plus the Carry Flag to %A, %flags" , ccode={"addf(cpu.a,cpu.c+cpu.cf); lni;"} },
{ mnem="SBC C" , opcode=0xF9, {"aluA", "alurC","aluOpSubC","instrNext"}, desc="Subtract %C form %A including the Carry Flag, %flags" , ccode={"addf(cpu.a,~cpu.c+cpu.cf); lni;"} },
{ mnem="CMP C" , opcode=0xD9, {"alulA","alurC","aluOpSub" ,"instrNext"}, desc="%cmp %C from %A" , ccode={"cmpf(cpu.a,cpu.c); lni;"} },
{ mnem="AND C" , opcode=0x39, {"aluA", "alurC","aluOpAnd" ,"instrNext"}, desc="Bitwise AND %A with %C, %flags" , ccode={"cpu.a&=cpu.c; setzf(cpu.a); lni;"} },
{ mnem="ORA C" , opcode=0x19, {"aluA", "alurC","aluOpIor" ,"instrNext"}, desc="Bitwise OR %A with %C, %flags" , ccode={"cpu.a|=cpu.c; setzf(cpu.a); lni;"} },
{ mnem="EOR C" , opcode=0x59, {"aluA", "alurC","aluOpXor" ,"instrNext"}, desc="Bitwise Exclusive OR %A with %C, %flags" , ccode={"cpu.a^=cpu.c; setzf(cpu.a); lni;"} },
-- { mnem="ASL C" , opcode=0x , {"aluA", "alurC","aluOpShl" ,"instrNext"}, desc="A<<=C, set zero flag" , ccode={"cpu.a<<=cpu.c; setzf(cpu.a); lni;"} },
-- { mnem="LSR C" , opcode=0x , {"aluA", "alurC","aluOpShr" ,"instrNext"}, desc="A>>=C, set zero flag" , ccode={"cpu.a>>=cpu.c; setzf(cpu.a); lni;"} },
-- { mnem="ROL C" , opcode=0x , {"aluA", "alurC","aluOpRol" ,"instrNext"}, desc="A<<<=C, set zero flag" , ccode={"cpu.a=rol(cpu.a,cpu.c); setzf(cpu.a); lni;"} },
-- { mnem="ROR C" , opcode=0x , {"aluA", "alurC","aluOpRor" ,"instrNext"}, desc="A>>>=C, set zero flag" , ccode={"cpu.a=ror(cpu.a,cpu.c); setzf(cpu.a); lni;"} },
-- { mnem="ASR C" , opcode=0x , {"aluA", "alurC","aluOpSra" ,"instrNext"}, desc="A>>a=C, set zero flag" , ccode={"cpu.a=sra(cpu.a,cpu.c); setzf(cpu.a); lni;"} },
-- { mnem="adb a" , opcode=0x , {"aluB", "alurA","aluOpAdd" ,"instrNext"}, desc="B+=A, set flags" , ccode={"addf(cpu.b,cpu.a); lni;"} },
-- { mnem="sbb a" , opcode=0x , {"aluB", "alurA","aluOpSub" ,"instrNext"}, desc="B-=A, set flags" , ccode={"subf(cpu.b,cpu.a); lni;"} },
-- { mnem="adc a" , opcode=0x , {"aluC", "alurA","aluOpAdd" ,"instrNext"}, desc="C+=A, set flags" , ccode={"addf(cpu.c,cpu.a); lni;"} },
-- { mnem="sbc a" , opcode=0x , {"aluC", "alurA","aluOpSub" ,"instrNext"}, desc="C-=A, set flags" , ccode={"subf(cpu.c,cpu.a); lni;"} },
{ category = "Conditional Branches", catlet="B"},
{ mnem="BNE rel" , opcode=0xD0, ncycles=2, {"loadImmedT","instrSub23Cond","instrNext0NZ" }, {}, {"instrNext"}, {"jmpRelT"}, desc="%if not 0, %brel; %brelc" , ccode={"loadimmedt","if( cpu.nz ) { jmprelt } else { lni }"} },
{ mnem="BEQ rel" , opcode=0xF0, ncycles=2, {"loadImmedT","instrSub23Cond","instrNext0Z" }, {}, {"instrNext"}, {"jmpRelT"}, desc="%if 0, %brel; %brelc" , ccode={"loadimmedt","if(!cpu.nz ) { jmprelt } else { lni }"} },
{ mnem="BLT rel" , opcode=0x90, ncycles=2, {"loadImmedT","instrSub23Cond","instrNext0NC" }, {}, {"instrNext"}, {"jmpRelT"}, desc="%if negative, %brel; %brelc" , ccode={"loadimmedt","if(!cpu.cf ) { jmprelt } else { lni }"} },
{ mnem="BGE rel" , opcode=0xB0, ncycles=2, {"loadImmedT","instrSub23Cond","instrNext0C" }, {}, {"instrNext"}, {"jmpRelT"}, desc="%if positive or 0, %brel; %brelc", ccode={"loadimmedt","if( cpu.cf ) { jmprelt } else { lni }"} },
{ mnem="BGT rel" , opcode=0x30, ncycles=2, {"loadImmedT","instrSub23Cond","instrNext0NC","instrNext0Z"}, {}, {"jmpRelT"}, {"instrNext"}, desc="%if positive, %brel; %brelc" , ccode={"loadimmedt","if( cpu.nz && cpu.cf ) { jmprelt } else { lni }"} },
{ mnem="BLE rel" , opcode=0x10, ncycles=2, {"loadImmedT","instrSub23Cond","instrNext0NC","instrNext0Z"}, {}, {"instrNext"}, {"jmpRelT"}, desc="%if negative or 0, %brel; %brelc", ccode={"loadimmedt","if((!cpu.nz) || (!cpu.cf)) { jmprelt } else { lni }"} },
{ mnem="BRA rel" , opcode=0x98, {"loadImmedT", "instrSub1"}, {"jmpRelT"}, desc="%brel" , ccode={"loadimmedt", "jmprelt" } },
{ category = "16-bit Arithmetic", catlet = "X"},
{ mnem="ADX #" , opcode=0xE8, {"loadImmedT","instrSub1"}, {"adwP","adwrTX","instrNext"}, desc="Add %imm8 to the 16-bit X register" , ccode={ "loadimmedt","cpu.p=(cpu.p+signed8(cpu.t))%65536; lni;"} },
{ mnem="ADY #" , opcode=0xC8, {"loadImmedT","instrSub1"}, {"adwQ","adwrTX","instrNext"}, desc="Add %imm8 to the 16-bit Y register" , ccode={ "loadimmedt","cpu.q=(cpu.q+signed8(cpu.t))%65536; lni;"} },
-- { mnem="ADS #" , opcode=0x , {"loadImmedT","instrSub1"}, {"adwS","adwrTX","instrNext"}, desc="S+=imm8 signed" , ccode={ "loadimmedt","cpu.s=(cpu.s+signed8(cpu.t))%65536; lni;"} },
{ mnem="ADX ##" , opcode=0x8A, {"loadImm161","instrSub1"},{"loadImm162","instrSub2"}, {"adwP","adwrUT","instrNext"}, desc="Add %imm16 to the 16-bit X register" , ccode={"loadimm161","loadimm162","cpu.p=(cpu.p+wordut )%65536; lni;"} },
{ mnem="ADY ##" , opcode=0x88, {"loadImm161","instrSub1"},{"loadImm162","instrSub2"}, {"adwQ","adwrUT","instrNext"}, desc="Add %imm16 to the 16-bit Y register" , ccode={"loadimm161","loadimm162","cpu.q=(cpu.p+wordut )%65536; lni;"} },
{ mnem="ADX A" , opcode=0xFC, {"adwP","adwrAX","instrNext"}, desc="Add the 8-bit signed value in the A register to the 16-bit X register", ccode={ "cpu.p=(cpu.p+signed8(cpu.a))%65536; lni;"} },
{ mnem="ADY A" , opcode=0xDC, {"adwQ","adwrAX","instrNext"}, desc="Add the 8-bit signed value in the A register to the 16-bit Y register", ccode={ "cpu.q=(cpu.p+signed8(cpu.a))%65536; lni;"} },
-- { mnem="ADS A" , opcode=0x , {"adwS","adwrAX","instrNext"}, desc="S+=B signed", ccode={"cpu.s+=signed8(cpu.b); lni;"} },
{ category = "Jumps" , catlet="J" },
{ mnem="JMP abs" , opcode=0xCC, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"jmpAbsUT" }, desc="Jump - Set the Program Counter to %imm16, executing the code at that address" , ccode={"loadimm161","loadimm162", "jmpabsut" } },
-- { mnem="jsy abs" , opcode=0x , {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"jmpAbsUT","saveRetAddr"}, desc="I=imm16, Q=I" , ccode={"loadimm161","loadimm162", "jmpabsut saveretaddr"} },
{ mnem="JSR abs" , opcode=0x20, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"pushRetAddr1","instrSub3"}, {"pushRetAddr2","instrSub4"}, {"jmpAbsUT" }, desc="Jump to Subroutine - Save the Program Counter on the Stack, then set it to %imm16, executing the code at that address" , ccode={"loadimm161","loadimm162","pushretaddr1","pushretaddr2", "jmpabsut" } }, -- 0x21
{ mnem="JMP [ind]", opcode=0x6C, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"load161","adrrUT", "adrSaveI","instrSub3"}, {"load162","adrlI","instrSub4"}, {"jmpAbsUT" }, desc="Load a subroutine pointer from memory at a given 16-bit address, then jump to that subroutine, saving the return address on the stack.", ccode={"loadimm161","loadimm162", "cpu.i=(wordut+cpu.a)%65536;cpu.u=readmemory(cpu.i);","cpu.t=readmemory((cpu.i+1)%65536);","jmpabsut" } }, -- 0x6D
{ mnem="JSR [ind]", opcode=0x2C, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"pushRetAddr1","instrSub3"}, {"pushRetAddr2","instrSub4"}, {"load161","adrrUT", "adrSaveI","instrSub5"}, {"load162","adrlI","instrSub6"}, {"jmpAbsUT" }, desc="Load a code pointer from memory at a given 16-bit address, then jump to that code." , ccode={"loadimm161","loadimm162","pushretaddr1","pushretaddr2","cpu.i=(wordut+cpu.a)%65536;cpu.u=readmemory(cpu.i);","cpu.t=readmemory((cpu.i+1)%65536);","jmpabsut" } }, -- 0x2D
{ mnem="JMP [ind,A]",opcode=0x4C,{"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"load161","adrrUT","adrr2A","adrSaveI","instrSub3"}, {"load162","adrlI","instrSub4"}, {"jmpAbsUT" }, desc="Load a subroutine pointer from memory at a given 16-bit address, then jump to that subroutine, saving the return address on the stack.", ccode={"loadimm161","loadimm162", "cpu.i=(wordut+cpu.a)%65536;cpu.u=readmemory(cpu.i);","cpu.t=readmemory((cpu.i+1)%65536);","jmpabsut" } }, -- 0x6D
{ mnem="JSR [ind,A]",opcode=0x0C,{"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"pushRetAddr1","instrSub3"}, {"pushRetAddr2","instrSub4"}, {"load161","adrrUT","adrr2A","adrSaveI","instrSub5"}, {"load162","adrlI","instrSub6"}, {"jmpAbsUT" }, desc="Load a code pointer from memory at a given 16-bit address, then jump to that code." , ccode={"loadimm161","loadimm162","pushretaddr1","pushretaddr2","cpu.i=(wordut+cpu.a)%65536;cpu.u=readmemory(cpu.i);","cpu.t=readmemory((cpu.i+1)%65536);","jmpabsut" } }, -- 0x2D
{ mnem="JMP X" , opcode=0x64, {"jmpAbsP" }, desc="Set the Program Counter to the 16-bit value in the X register, executing the code at that address" , ccode={ "jmpabsp" } },
{ mnem="JMP Y" , opcode=0x44, {"jmpAbsQ" }, desc="Set the Program Counter to the 16-bit value in the Y register, executing the code at that address" , ccode={ "jmpabsq" } },
-- { mnem="jsy X" , opcode=0x , {"jmpAbsP" ,"saveRetAddr"}, desc="I=P, Q=I" , ccode={ "jmpabsp saveretaddr"} },
-- { mnem="jsy Y" , opcode=0x , {"jmpAbsQ" ,"saveRetAddr"}, desc="I=Q, Q=I" , ccode={ "jmpabsq saveretaddr"} },
{ mnem="JSR X" , opcode=0x24, {"pushRetAddr1","instrSub1"}, {"pushRetAddr2","instrSub2"}, {"jmpAbsP" }, desc="Save the Program Counter on the Stack, then set it to %X, executing the code at that address" , ccode={ "pushretaddr1","pushretaddr2", "jmpabsp" } },
{ mnem="JSR Y" , opcode=0x04, {"pushRetAddr1","instrSub1"}, {"pushRetAddr2","instrSub2"}, {"jmpAbsQ" }, desc="Save the Program Counter on the Stack, then set it to %Y, executing the code at that address" , ccode={ "pushretaddr1","pushretaddr2", "jmpabsq" } },
{ mnem="RTS" , opcode=0x60, {"pop161" ,"instrSub1"}, {"pop162" ,"instrSub2"}, {"jmpAbsUT","adrInc" }, desc="Retrieve the Program Counter from the stack, returning to where the last JSR instruction was executed" , ccode={"pop161" ,"pop162" , "jmpabsutplus1" } },
{ category = "Stack", catlet="S" },
{ mnem="PHA" , opcode=0x48, {"pushReg","alurA" ,"instrSub1"}, { "instrNext"}, desc="Push %A onto the Stack" , ccode={"pushbyte(cpu.a);","lni;"} },
{ mnem="PHB" , opcode=0x5C, {"pushReg","alurB" ,"instrSub1"}, { "instrNext"}, desc="Push %B onto the Stack" , ccode={"pushbyte(cpu.b);","lni;"} },
{ mnem="PHC" , opcode=0x1C, {"pushReg","alurC" ,"instrSub1"}, { "instrNext"}, desc="Push %C onto the Stack" , ccode={"pushbyte(cpu.c);","lni;"} },
{ mnem="PHP" , opcode=0x08, {"pushReg","alurF" ,"instrSub1"}, { "instrNext"}, desc="Push a byte containing the Carry Flag and Zero Flag onto the Stack" , ccode={"int f = cpu.nz | (cpu.cf<<1); pushbyte(f);","lni;"} },
{ mnem="PHX" , opcode=0x54, {"pushReg","alurPH","instrSub1"}, {"pushReg","alurPL" ,"instrSub2"}, { "instrNext"}, desc="Push %X onto the Stack" , ccode={"push161(cpu.p);","push162(cpu.p);","lni;"} },
{ mnem="PHY" , opcode=0x14, {"pushReg","alurQH","instrSub1"}, {"pushReg","alurQL" ,"instrSub2"}, { "instrNext"}, desc="Push %Y onto the Stack" , ccode={"push161(cpu.q);","push162(cpu.q);","lni;"} },
{ mnem="PLA" , opcode=0x68, {"popReg","memSaveA","instrSub1"}, { "instrNext"}, desc="Pull a byte from the Stack, and store it in the A register" , ccode={"cpu.a=popbyte;","lni;"} },
{ mnem="PLB" , opcode=0x7C, {"popReg","memSaveB","instrSub1"}, { "instrNext"}, desc="Pull a byte from the Stack, and store it in the B register" , ccode={"cpu.b=popbyte;","lni;"} },
{ mnem="PLC" , opcode=0x3C, {"popReg","memSaveC","instrSub1"}, { "instrNext"}, desc="Pull a byte from the Stack, and store it in the C register" , ccode={"cpu.c=popbyte;","lni;"} },
{ mnem="PLP" , opcode=0x28, {"popReg","memSaveF","instrSub1"}, { "instrNext"}, desc="Pull a byte from the Stack, and use it to set the Carry Flag and Zero flag" , ccode={"int f=popbyte; cpu.nz = f&1; cpu.cf = (f>>1)&1;","lni;"} },
{ mnem="PLX" , opcode=0x74, {"pop161", "instrSub1"}, {"pop162", "instrSub2"}, {"adwrUT","adwSaveP","instrNext"}, desc="Pull two bytes from the stack, and store the resulting 16-bit value in the X register", ccode={"pop161","pop162","cpu.p=wordut; lni;"} },
{ mnem="PLY" , opcode=0x34, {"pop161", "instrSub1"}, {"pop162", "instrSub2"}, {"adwrUT","adwSaveQ","instrNext"}, desc="Pull two bytes from the stack, and store the resulting 16-bit value in the Y register", ccode={"pop161","pop162","cpu.q=wordut; lni;"} },
-- { mnem="psh imm8" , opcode=0x , {"loadImmedT","instrSub1"}, {"pushReg","alurT","instrSub2"}, {"instrNext"}, desc="*(S++)=imm8", ccode={"loadimmedt;","pushbyte(cpu.t);","lni;"} },
-- { mnem="phw imm16", opcode=0x , {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"pushReg","alurU","instrSub3"}, {"pushReg","alurT","instrSub4"}, {"instrNext"}, desc="*(S++++)=imm16", ccode={"loadimm161","loadimm162","pushbyte(cpu.u);","pushbyte(cpu.t);","lni;"} }, -- 0x3D
{ category = "8-bit Load/Store", catlet="B" },
{ mnem="LDA #" , opcode=0xA9, {"loadImmed" , "memSaveA", "memSaveFlags","instrSub1"}, {"instrNext"}, desc="Set the A register to %imm8" , ccode={"cpu.a=loadimmed; setzf(cpu.a);","lni;"} },
{ mnem="LDB #" , opcode=0xAB, {"loadImmed" , "memSaveB", "memSaveFlags","instrSub1"}, {"instrNext"}, desc="Set the B register to %imm8" , ccode={"cpu.b=loadimmed; setzf(cpu.b);","lni;"} },
{ mnem="LDC #" , opcode=0x2B, {"loadImmed" , "memSaveC", "memSaveFlags","instrSub1"}, {"instrNext"}, desc="Set the C register to %imm8" , ccode={"cpu.c=loadimmed; setzf(cpu.c);","lni;"} },
{ mnem="LDA zpg" , opcode=0xA5, {"loadImmedT","instrSub1"}, {"loadStackRel" , "memSaveA", "memSaveFlags","instrSub2"}, {"instrNext"}, desc="Set the A register to %zpgIn, %zFlgMem" , ccode={"loadimmedt;","cpu.a=loadstackrel; setzf(cpu.a);","lni;"} },
{ mnem="LDB zpg" , opcode=0xA7, {"loadImmedT","instrSub1"}, {"loadStackRel" , "memSaveB", "memSaveFlags","instrSub2"}, {"instrNext"}, desc="Set the B register to %zpgIn, %zFlgMem" , ccode={"loadimmedt;","cpu.b=loadstackrel; setzf(cpu.b);","lni;"} },
{ mnem="LDC zpg" , opcode=0x27, {"loadImmedT","instrSub1"}, {"loadStackRel" , "memSaveC", "memSaveFlags","instrSub2"}, {"instrNext"}, desc="Set the C register to %zpgIn, %zFlgMem" , ccode={"loadimmedt;","cpu.c=loadstackrel; setzf(cpu.c);","lni;"} },
{ mnem="STA zpg" , opcode=0x85, {"loadImmedT","instrSub1"}, {"storeStackRel", "alurA", "instrSub2"}, {"instrNext"}, desc="Store %A in memory at %zpg" , ccode={"loadimmedt;","storestackrel(cpu.a);","lni;"} },
{ mnem="STB zpg" , opcode=0x87, {"loadImmedT","instrSub1"}, {"storeStackRel", "alurB", "instrSub2"}, {"instrNext"}, desc="Store %B in memory at %zpg" , ccode={"loadimmedt;","storestackrel(cpu.a);","lni;"} },
{ mnem="STC zpg" , opcode=0x07, {"loadImmedT","instrSub1"}, {"storeStackRel", "alurC", "instrSub2"}, {"instrNext"}, desc="Store %C in memory at %zpg" , ccode={"loadimmedt;","storestackrel(cpu.a);","lni;"} },
{ mnem="LDA abs" , opcode=0xED, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"adrrUT", "loadReg" ,"memSaveA", "memSaveFlags","instrSub3"}, {"instrNext"}, desc="Set the A register to %absIn, %zFlgMem" , ccode={"loadimm161","loadimm162","cpu.a=loadut; setzf(cpu.a);", "lni;"} },
{ mnem="LDB abs" , opcode=0xEF, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"adrrUT", "loadReg" ,"memSaveB", "memSaveFlags","instrSub3"}, {"instrNext"}, desc="Set the B register to %absIn, %zFlgMem" , ccode={"loadimm161","loadimm162","cpu.b=loadut; setzf(cpu.b);", "lni;"} },
{ mnem="LDC abs" , opcode=0x6F, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"adrrUT", "loadReg" ,"memSaveC", "memSaveFlags","instrSub3"}, {"instrNext"}, desc="Set the C register to %absIn, %zFlgMem" , ccode={"loadimm161","loadimm162","cpu.c=loadut; setzf(cpu.c);", "lni;"} },
{ mnem="STA abs" , opcode=0xCD, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"adrrUT", "storeReg","alurA", "instrSub3"}, {"instrNext"}, desc="Store %A in memory at %abs" , ccode={"loadimm161","loadimm162","storeut(cpu.a);", "lni;"} },
{ mnem="STB abs" , opcode=0xCF, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"adrrUT", "storeReg","alurB", "instrSub3"}, {"instrNext"}, desc="Store %B in memory at %abs" , ccode={"loadimm161","loadimm162","storeut(cpu.b);", "lni;"} },
{ mnem="STC abs" , opcode=0x4F, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"adrrUT", "storeReg","alurC", "instrSub3"}, {"instrNext"}, desc="Store %C in memory at %abs" , ccode={"loadimm161","loadimm162","storeut(cpu.c);", "lni;"} },
{ mnem="LDA X" , opcode=0xA1, {"adrlP", "loadReg" ,"memSaveA", "memSaveFlags","instrSub1"}, {"instrNext"}, desc="Set the A register to %xIn, %zFlgMem" , ccode={"cpu.a=loadp; setzf(cpu.a);","lni;"} },
{ mnem="LDB X" , opcode=0xA3, {"adrlP", "loadReg" ,"memSaveB", "memSaveFlags","instrSub1"}, {"instrNext"}, desc="Set the B register to %xIn, %zFlgMem" , ccode={"cpu.b=loadp; setzf(cpu.b);","lni;"} },
{ mnem="LDC X" , opcode=0x23, {"adrlP", "loadReg" ,"memSaveC", "memSaveFlags","instrSub1"}, {"instrNext"}, desc="Set the C register to %xIn, %zFlgMem" , ccode={"cpu.c=loadp; setzf(cpu.c);","lni;"} },
{ mnem="LDA Y" , opcode=0xB1, {"adrlQ", "loadReg" ,"memSaveA", "memSaveFlags","instrSub1"}, {"instrNext"}, desc="Set the A register to %yIn, %zFlgMem" , ccode={"cpu.a=loadq; setzf(cpu.a);","lni;"} },
{ mnem="LDB Y" , opcode=0xB3, {"adrlQ", "loadReg" ,"memSaveB", "memSaveFlags","instrSub1"}, {"instrNext"}, desc="Set the B register to %yIn, %zFlgMem" , ccode={"cpu.b=loadq; setzf(cpu.b);","lni;"} },
{ mnem="LDC Y" , opcode=0x33, {"adrlQ", "loadReg" ,"memSaveC", "memSaveFlags","instrSub1"}, {"instrNext"}, desc="Set the C register to %yIn, %zFlgMem" , ccode={"cpu.c=loadq; setzf(cpu.c);","lni;"} },
{ mnem="STA X" , opcode=0x81, {"adrlP", "storeReg","alurA", "instrSub1"}, {"instrNext"}, desc="Store %A in memory at %adrX" , ccode={"storep(cpu.a);","lni;"} },
{ mnem="STB X" , opcode=0x83, {"adrlP", "storeReg","alurB", "instrSub1"}, {"instrNext"}, desc="Store %B in memory at %adrX" , ccode={"storep(cpu.b);","lni;"} },
{ mnem="STC X" , opcode=0x03, {"adrlP", "storeReg","alurC", "instrSub1"}, {"instrNext"}, desc="Store %C in memory at %adrX" , ccode={"storep(cpu.c);","lni;"} },
{ mnem="STA Y" , opcode=0x91, {"adrlQ", "storeReg","alurA", "instrSub1"}, {"instrNext"}, desc="Store %A in memory at %adrY" , ccode={"storeq(cpu.a);","lni;"} },
{ mnem="STB Y" , opcode=0x93, {"adrlQ", "storeReg","alurB", "instrSub1"}, {"instrNext"}, desc="Store %B in memory at %adrY" , ccode={"storeq(cpu.b);","lni;"} },
{ mnem="STC Y" , opcode=0x13, {"adrlQ", "storeReg","alurC", "instrSub1"}, {"instrNext"}, desc="Store %C in memory at %adrY" , ccode={"storeq(cpu.c);","lni;"} },
{ mnem="LDA X+" , opcode=0xE1, {"adrlP", "loadReg" ,"memSaveA","incP","memSaveFlags","instrSub1"}, {"instrNext"}, desc="Set the A register to %xIn, %xInc, %zFlgMem", ccode={"cpu.a=loadpinc; setzf(cpu.a);","lni;"} },
{ mnem="LDB X+" , opcode=0xE3, {"adrlP", "loadReg" ,"memSaveB","incP","memSaveFlags","instrSub1"}, {"instrNext"}, desc="Set the B register to %xIn, %xInc, %zFlgMem", ccode={"cpu.b=loadpinc; setzf(cpu.b);","lni;"} },
{ mnem="LDC X+" , opcode=0x63, {"adrlP", "loadReg" ,"memSaveC","incP","memSaveFlags","instrSub1"}, {"instrNext"}, desc="Set the C register to %xIn, %xInc, %zFlgMem", ccode={"cpu.c=loadpinc; setzf(cpu.c);","lni;"} },
{ mnem="LDA Y+" , opcode=0xF1, {"adrlQ", "loadReg" ,"memSaveA","incQ","memSaveFlags","instrSub1"}, {"instrNext"}, desc="Set the A register to %yIn, %yInc, %zFlgMem", ccode={"cpu.a=loadqinc; setzf(cpu.a);","lni;"} },
{ mnem="LDB Y+" , opcode=0xF3, {"adrlQ", "loadReg" ,"memSaveB","incQ","memSaveFlags","instrSub1"}, {"instrNext"}, desc="Set the B register to %yIn, %yInc, %zFlgMem", ccode={"cpu.b=loadqinc; setzf(cpu.b);","lni;"} },
{ mnem="LDC Y+" , opcode=0x73, {"adrlQ", "loadReg" ,"memSaveC","incQ","memSaveFlags","instrSub1"}, {"instrNext"}, desc="Set the C register to %yIn, %yInc, %zFlgMem", ccode={"cpu.c=loadqinc; setzf(cpu.c);","lni;"} },
{ mnem="STA X+" , opcode=0xC1, {"adrlP", "storeReg","alurA", "incP", "instrSub1"}, {"instrNext"}, desc="Store %A in memory at %adrX, and %xInc" , ccode={"storepinc(cpu.a);","lni;"} },
{ mnem="STB X+" , opcode=0xC3, {"adrlP", "storeReg","alurB", "incP", "instrSub1"}, {"instrNext"}, desc="Store %B in memory at %adrX, and %xInc" , ccode={"storepinc(cpu.b);","lni;"} },
{ mnem="STC X+" , opcode=0x43, {"adrlP", "storeReg","alurC", "incP", "instrSub1"}, {"instrNext"}, desc="Store %C in memory at %adrX, and %xInc" , ccode={"storepinc(cpu.c);","lni;"} },
{ mnem="STA Y+" , opcode=0xD1, {"adrlQ", "storeReg","alurA", "incQ", "instrSub1"}, {"instrNext"}, desc="Store %A in memory at %adrY, and %yInc" , ccode={"storeqinc(cpu.a);","lni;"} },
{ mnem="STB Y+" , opcode=0xD3, {"adrlQ", "storeReg","alurB", "incQ", "instrSub1"}, {"instrNext"}, desc="Store %B in memory at %adrY, and %yInc" , ccode={"storeqinc(cpu.b);","lni;"} },
{ mnem="STC Y+" , opcode=0x53, {"adrlQ", "storeReg","alurC", "incQ", "instrSub1"}, {"instrNext"}, desc="Store %C in memory at %adrY, and %yInc" , ccode={"storeqinc(cpu.c);","lni;"} },
{ mnem="LDA X,ofs", opcode=0xBD, {"loadImmedT","instrSub1"}, {"adrlP","adrrlT","loadReg" ,"memSaveA", "memSaveFlags","instrSub2"}, {"instrNext"}, desc="Set the A register to %XofsIn, %zFlgMem" , ccode={"loadimm161","loadimm162","cpu.a=loadput; setzf(cpu.a);","lni;"} },
{ mnem="LDB X,ofs", opcode=0xBF, {"loadImmedT","instrSub1"}, {"adrlP","adrrlT","loadReg" ,"memSaveB", "memSaveFlags","instrSub2"}, {"instrNext"}, desc="Set the B register to %XofsIn, %zFlgMem" , ccode={"loadimm161","loadimm162","cpu.b=loadput; setzf(cpu.b);","lni;"} },
{ mnem="LDC X,ofs", opcode=0x3F, {"loadImmedT","instrSub1"}, {"adrlP","adrrlT","loadReg" ,"memSaveC", "memSaveFlags","instrSub2"}, {"instrNext"}, desc="Set the C register to %XofsIn, %zFlgMem" , ccode={"loadimm161","loadimm162","cpu.c=loadput; setzf(cpu.c);","lni;"} },
{ mnem="LDA Y,ofs", opcode=0xB9, {"loadImmedT","instrSub1"}, {"adrlQ","adrrlT","loadReg" ,"memSaveA", "memSaveFlags","instrSub2"}, {"instrNext"}, desc="Set the A register to %YofsIn, %zFlgMem" , ccode={"loadimm161","loadimm162","cpu.a=loadqut; setzf(cpu.a);","lni;"} },
{ mnem="LDB Y,ofs", opcode=0xBB, {"loadImmedT","instrSub1"}, {"adrlQ","adrrlT","loadReg" ,"memSaveB", "memSaveFlags","instrSub2"}, {"instrNext"}, desc="Set the B register to %YofsIn, %zFlgMem" , ccode={"loadimm161","loadimm162","cpu.b=loadqut; setzf(cpu.b);","lni;"} },
{ mnem="LDC Y,ofs", opcode=0x3B, {"loadImmedT","instrSub1"}, {"adrlQ","adrrlT","loadReg" ,"memSaveC", "memSaveFlags","instrSub2"}, {"instrNext"}, desc="Set the C register to %YofsIn, %zFlgMem" , ccode={"loadimm161","loadimm162","cpu.c=loadqut; setzf(cpu.c);","lni;"} },
{ mnem="STA X,ofs", opcode=0x9D, {"loadImmedT","instrSub1"}, {"adrlP","adrrlT","storeReg","alurA", "instrSub2"}, {"instrNext"}, desc="Store %A in memory at %Xofs" , ccode={"loadimm161","loadimm162","storeput(cpu.a);", "lni;"} },
{ mnem="STB X,ofs", opcode=0x9F, {"loadImmedT","instrSub1"}, {"adrlP","adrrlT","storeReg","alurB", "instrSub2"}, {"instrNext"}, desc="Store %A in memory at %Xofs" , ccode={"loadimm161","loadimm162","storeput(cpu.b);", "lni;"} },
{ mnem="STC X,ofs", opcode=0x1F, {"loadImmedT","instrSub1"}, {"adrlP","adrrlT","storeReg","alurC", "instrSub2"}, {"instrNext"}, desc="Store %A in memory at %Xofs" , ccode={"loadimm161","loadimm162","storeput(cpu.c);", "lni;"} },
{ mnem="STA Y,ofs", opcode=0x99, {"loadImmedT","instrSub1"}, {"adrlQ","adrrlT","storeReg","alurA", "instrSub2"}, {"instrNext"}, desc="Store %A in memory at %Yofs" , ccode={"loadimm161","loadimm162","storequt(cpu.a);", "lni;"} },
{ mnem="STB Y,ofs", opcode=0x9B, {"loadImmedT","instrSub1"}, {"adrlQ","adrrlT","storeReg","alurB", "instrSub2"}, {"instrNext"}, desc="Store %A in memory at %Yofs" , ccode={"loadimm161","loadimm162","storequt(cpu.b);", "lni;"} },
{ mnem="STC Y,ofs", opcode=0x1B, {"loadImmedT","instrSub1"}, {"adrlQ","adrrlT","storeReg","alurC", "instrSub2"}, {"instrNext"}, desc="Store %A in memory at %Yofs" , ccode={"loadimm161","loadimm162","storequt(cpu.c);", "lni;"} },
{ category = "16-bit Load/Store", catlet="W" },
{ mnem="LDX ##" , opcode=0xAA, {"loadImm161" ,"instrSub1"}, {"loadImm162" ,"instrSub2"}, {"adwrUT","adwSaveP","instrNext"}, desc="Set the X register to %imm16" , ccode={"loadimm161","loadimm162","cpu.p=wordut; lni;"} },
{ mnem="LDY ##" , opcode=0xA8, {"loadImm161" ,"instrSub1"}, {"loadImm162" ,"instrSub2"}, {"adwrUT","adwSaveQ","instrNext"}, desc="Set the X register to %imm16" , ccode={"loadimm161","loadimm162","cpu.q=wordut; lni;"} },
-- { mnem="lds imm16", opcode=0x , {"loadImm161" ,"instrSub1"}, {"loadImm162" ,"instrSub2"}, {"adwrUT","adwSaveS","instrNext"}, desc="S=imm16" , ccode={"loadimm161","loadimm162","cpu.s=wordut; lni;"} },
-- { mnem="ldv imm16", opcode=0x , {"loadImm161" ,"instrSub1"}, {"loadImm162" ,"instrSub2"}, {"adwrUT","adwSaveV","instrNext"}, desc="V=imm16" , ccode={"loadimm161","loadimm162","cpu.v=wordut; lni;"} },
{ mnem="LDX zpg" , opcode=0xA6, {"loadImmedT","instrSub1"}, {"loadStackRel161" ,"instrSub2"}, {"loadStackRel162" ,"instrSub3"}, {"adwrUT","adwSaveP","instrNext"}, desc="Set the X register to %zpgIn16" , ccode={"loadimmedt","loadstackrel161","loadstackrel162","cpu.p=wordut; lni;"} },
{ mnem="LDY zpg" , opcode=0xA4, {"loadImmedT","instrSub1"}, {"loadStackRel161" ,"instrSub2"}, {"loadStackRel162" ,"instrSub3"}, {"adwrUT","adwSaveQ","instrNext"}, desc="Set the Y register to %zpgIn16" , ccode={"loadimmedt","loadstackrel161","loadstackrel162","cpu.p=wordut; lni;"} },
{ mnem="STX zpg" , opcode=0x86, {"loadImmedT","instrSub1"}, {"storeStackRel161" ,"alurPH" ,"instrSub2"}, {"storeStackRel162" ,"alurPL" ,"instrSub3"}, { "instrNext"}, desc="Store %X in memory at %zpg" , ccode={"loadimmedt","storestackrel161(cpu.p);","storestackrel162(cpu.p);","lni;"} },
{ mnem="STY zpg" , opcode=0x84, {"loadImmedT","instrSub1"}, {"storeStackRel161" ,"alurQH" ,"instrSub2"}, {"storeStackRel162" ,"alurQL" ,"instrSub3"}, { "instrNext"}, desc="Store %Y in memory at %zpg" , ccode={"loadimmedt","storestackrel161(cpu.q);","storestackrel162(cpu.q);","lni;"} },
{ mnem="LDX abs" , opcode=0xAE, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"loadUTU","adwIncUT" ,"adwSaveP","instrSub3"}, {"adrlP","loadRegT" ,"instrSub4"}, {"adwrUT","adwSaveP","instrNext"}, desc="Set the X register to %absIn16" , ccode={"loadimm161","loadimm162","cpu.p=wordut; cpu.u=loadut;","cpu.t=loadpp1;","cpu.p=wordut; lni;"} }, -- 0x69
{ mnem="LDY abs" , opcode=0xAC, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"loadUTU","adwIncUT" ,"adwSaveQ","instrSub3"}, {"adrlQ","loadRegT" ,"instrSub4"}, {"adwrUT","adwSaveQ","instrNext"}, desc="Set the Y register to %absIn16" , ccode={"loadimm161","loadimm162","cpu.q=wordut; cpu.u=loadut;","cpu.t=loadqp1;","cpu.q=wordut; lni;"} }, -- 0x6B
{ mnem="STX abs" , opcode=0x8E, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"storeUT" ,"alurPH" ,"instrSub3"}, {"storeUT","adrInc" ,"alurPL" ,"instrSub4"}, { "instrNext"}, desc="Store %X in memory at %abs" , ccode={"loadimm161","loadimm162","storeut(hibyte(cpu.p));","storeutp1(lobyte(cpu.p));","lni;" } }, -- 0x6D
{ mnem="STY abs" , opcode=0x8C, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"storeUT" ,"alurQH" ,"instrSub3"}, {"storeUT","adrInc" ,"alurQL" ,"instrSub4"}, { "instrNext"}, desc="Store %X in memory at %abs" , ccode={"loadimm161","loadimm162","storeut(hibyte(cpu.q));","storeutp1(lobyte(cpu.q));","lni;" } }, -- 0x6F
{ mnem="LDX X,ofs", opcode=0xBE, {"loadImmedT","instrSub1"}, {"adrlP","adrrlT","loadReg" ,"memSaveU","instrSub2"}, {"adrlP","adrrlT","adrInc","loadReg" ,"memSaveT","instrSub3"}, {"adwrUT","adwSaveP","instrNext"}, desc="Set the X register to %XofsIn16" , ccode={"loadimm161","loadimm162","cpu.p=wordut; cpu.u=loadut;","cpu.t=loadpp1;","cpu.p=wordut; lni;"} },
{ mnem="LDX Y,ofs", opcode=0xBA, {"loadImmedT","instrSub1"}, {"adrlQ","adrrlT","loadReg" ,"memSaveU","instrSub2"}, {"adrlP","adrrlT","adrInc","loadReg" ,"memSaveT","instrSub3"}, {"adwrUT","adwSaveP","instrNext"}, desc="Set the Y register to %XofsIn16" , ccode={"loadimm161","loadimm162","cpu.q=wordut; cpu.u=loadut;","cpu.t=loadqp1;","cpu.q=wordut; lni;"} },
{ mnem="LDY X,ofs", opcode=0xBC, {"loadImmedT","instrSub1"}, {"adrlP","adrrlT","loadReg" ,"memSaveU","instrSub2"}, {"adrlP","adrrlT","adrInc","loadReg" ,"memSaveT","instrSub3"}, {"adwrUT","adwSaveP","instrNext"}, desc="Set the X register to %YofsIn16" , ccode={"loadimm161","loadimm162","cpu.p=wordut; cpu.u=loadut;","cpu.t=loadpp1;","cpu.p=wordut; lni;"} },
{ mnem="LDY Y,ofs", opcode=0xB8, {"loadImmedT","instrSub1"}, {"adrlQ","adrrlT","loadReg" ,"memSaveU","instrSub2"}, {"adrlP","adrrlT","adrInc","loadReg" ,"memSaveT","instrSub3"}, {"adwrUT","adwSaveP","instrNext"}, desc="Set the Y register to %YofsIn16" , ccode={"loadimm161","loadimm162","cpu.q=wordut; cpu.u=loadut;","cpu.t=loadqp1;","cpu.q=wordut; lni;"} },
{ mnem="STX Y,ofs", opcode=0x9A, {"loadImmedT","instrSub1"}, {"adrlQ","adrrlT","storeReg","alurPH" ,"instrSub2"}, {"adrlP","adrrlT","adrInc","storeReg","alurPL" ,"instrSub3"}, { "instrNext"}, desc="Store %X in memory at %Yofs" , ccode={"loadimm161","loadimm162","storeut(hibyte(cpu.p));","storeutp1(lobyte(cpu.p));","lni;" } },
{ mnem="STY X,ofs", opcode=0x9C, {"loadImmedT","instrSub1"}, {"adrlP","adrrlT","storeReg","alurQH" ,"instrSub2"}, {"adrlP","adrrlT","adrInc","storeReg","alurQL" ,"instrSub3"}, { "instrNext"}, desc="Store %Y in memory at %Xofs" , ccode={"loadimm161","loadimm162","storeut(hibyte(cpu.q));","storeutp1(lobyte(cpu.q));","lni;" } },
{ mnem="LDX X" , opcode=0xA2, {"adrlP","load161" ,"instrSub1"}, {"adrlP","load162" ,"instrSub2"}, {"adwrUT","adwSaveP","instrNext"}, desc="Set the X register to %Xin16" , ccode={"cpu.u=loadp;","cpu.t=loadpp1;","cpu.p=wordut; lni;"} },
{ mnem="LDY X" , opcode=0xA0, {"adrlP","load161" ,"instrSub1"}, {"adrlP","load162" ,"instrSub2"}, {"adwrUT","adwSaveQ","instrNext"}, desc="Set the Y register to %Xin16" , ccode={"cpu.u=loadp;","cpu.t=loadpp1;","cpu.q=wordut; lni;"} },
{ mnem="LDX Y" , opcode=0xB2, {"adrlQ","load161" ,"instrSub1"}, {"adrlQ","load162" ,"instrSub2"}, {"adwrUT","adwSaveP","instrNext"}, desc="Set the X register to %Yin16" , ccode={"cpu.u=loadq;","cpu.t=loadqp1;","cpu.p=wordut; lni;"} },
{ mnem="LDY Y" , opcode=0xE2, {"adrlQ","load161" ,"instrSub1"}, {"adrlQ","load162" ,"instrSub2"}, {"adwrUT","adwSaveQ","instrNext"}, desc="Set the Y register to %Yin16" , ccode={"cpu.u=loadq;","cpu.t=loadqp1;","cpu.q=wordut; lni;"} },
{ mnem="STX Y" , opcode=0x92, {"adrlQ","store161" ,"alurPH" ,"instrSub1"}, {"adrlQ","store162" ,"alurPL" ,"instrSub2"}, { "instrNext"}, desc="Store %X in memory at %adrY" , ccode={"storeq(hibyte(cpu.p));","storeqp1(lobyte(cpu.p));","lni;"} },
{ mnem="STY X" , opcode=0x80, {"adrlP","store161" ,"alurQH" ,"instrSub1"}, {"adrlP","store162" ,"alurQL" ,"instrSub2"}, { "instrNext"}, desc="Store %Y in memory at %adrX" , ccode={"storep(hibyte(cpu.q));","storepp1(lobyte(cpu.q));","lni;"} },
{ mnem="LDX Y+" , opcode=0xF2, {"adrlQ","load161" ,"instrSub1"}, {"adrlQ","load162" ,"incQ2" ,"instrSub2"}, {"adwrUT","adwSaveP","instrNext"}, desc="Set the X register to %Yin16, %Yinc16", ccode={"cpu.u=loadqinc;","cpu.t=loadqinc;","cpu.p=wordut; lni;"} },
{ mnem="LDY X+" , opcode=0xE0, {"adrlP","load161" ,"instrSub1"}, {"adrlP","load162" ,"incP2" ,"instrSub2"}, {"adwrUT","adwSaveQ","instrNext"}, desc="Set the Y register to %Xin16, %Xinc16", ccode={"cpu.u=loadpinc;","cpu.t=loadpinc;","cpu.q=wordut; lni;"} },
{ mnem="STX Y+" , opcode=0xD2, {"adrlQ","store161" ,"alurPH" ,"instrSub1"}, {"adrlQ","store162","incQ2" ,"alurPL" ,"instrSub2"}, { "instrNext"}, desc="Store %X in memory at %adrY, %Yinc16" , ccode={"storeqinc(hibyte(cpu.p));","storeqinc(lobyte(cpu.p));","lni;"} },
{ mnem="STY X+" , opcode=0xC0, {"adrlP","store161" ,"alurQH" ,"instrSub1"}, {"adrlP","store162","incP2" ,"alurQL" ,"instrSub2"}, { "instrNext"}, desc="Store %Y in memory at %adrX, %Xinc16" , ccode={"storepinc(hibyte(cpu.q));","storepinc(lobyte(cpu.q));","lni;"} },
{ category = "Moves", catlet="M" },
{ mnem="TBA" , opcode=0x97, {"alurB" ,"aluOpMov","aluSaveA","instrNext"}, desc="Copy %B into the A register", ccode={"cpu.a=cpu.b; lni;"} },
{ mnem="TCA" , opcode=0x17, {"alurC" ,"aluOpMov","aluSaveA","instrNext"}, desc="Copy %C into the A register", ccode={"cpu.a=cpu.c; lni;"} },
{ mnem="TAB" , opcode=0xB7, {"alurA" ,"aluOpMov","aluSaveB","instrNext"}, desc="Copy %A into the B register", ccode={"cpu.b=cpu.a; lni;"} },
{ mnem="TCB" , opcode=0xD7, {"alurC" ,"aluOpMov","aluSaveB","instrNext"}, desc="Copy %C into the B register", ccode={"cpu.b=cpu.c; lni;"} },
{ mnem="TAC" , opcode=0x37, {"alurA" ,"aluOpMov","aluSaveC","instrNext"}, desc="Copy %A into the C register", ccode={"cpu.c=cpu.a; lni;"} },
{ mnem="TBC" , opcode=0xF7, {"alurB" ,"aluOpMov","aluSaveC","instrNext"}, desc="Copy %B into the C register", ccode={"cpu.c=cpu.b; lni;"} },
-- { mnem="lda pl" , opcode=0x , {"alurPL","aluOpMov","aluSaveA","instrNext"}, desc="A=P&FF" , ccode={"cpu.a=lobyte(cpu.p); lni;"} },
-- { mnem="lda ph" , opcode=0x , {"alurPH","aluOpMov","aluSaveA","instrNext"}, desc="A=P>>8" , ccode={"cpu.a=hibyte(cpu.p); lni;"} },
-- { mnem="lda ql" , opcode=0x , {"alurQL","aluOpMov","aluSaveA","instrNext"}, desc="A=Q&FF" , ccode={"cpu.a=lobyte(cpu.q); lni;"} },
-- { mnem="lda qh" , opcode=0x , {"alurQH","aluOpMov","aluSaveA","instrNext"}, desc="A=Q>>8" , ccode={"cpu.a=hibyte(cpu.q); lni;"} },
-- { mnem="ldb pl" , opcode=0x , {"alurPL","aluOpMov","aluSaveB","instrNext"}, desc="B=P&FF" , ccode={"cpu.b=lobyte(cpu.p); lni;"} },
-- { mnem="ldc ph" , opcode=0x , {"alurPH","aluOpMov","aluSaveC","instrNext"}, desc="C=P>>8" , ccode={"cpu.c=hibyte(cpu.p); lni;"} },
-- { mnem="ldb ql" , opcode=0x , {"alurQL","aluOpMov","aluSaveB","instrNext"}, desc="B=Q&FF" , ccode={"cpu.b=lobyte(cpu.q); lni;"} },
-- { mnem="ldc qh" , opcode=0x , {"alurQH","aluOpMov","aluSaveC","instrNext"}, desc="C=Q>>8" , ccode={"cpu.c=hibyte(cpu.q); lni;"} },
{ mnem="TYX" , opcode=0xB4, {"adwlQ" , "adwSaveP","instrNext"}, desc="Copy %Y into the 16-bit X register", ccode={"cpu.p=cpu.q; lni;"} },
{ mnem="TXY" , opcode=0x94, {"adwlP" , "adwSaveQ","instrNext"}, desc="Copy %X into the 16-bit Y register", ccode={"cpu.q=cpu.p; lni;"} },
{ mnem="TVX" , opcode=0xB6, {"adwlV" , "adwSaveP","instrNext"}, desc="Copy the 16-bit Interrupt Return Address into the X register", ccode={"cpu.v=cpu.p; lni;"} },
{ mnem="TXV" , opcode=0x96, {"adwlP" , "adwSaveV","instrNext"}, desc="Copy %X into the 16-bit Interrupt Return Address register", ccode={"cpu.p=cpu.v; lni;"} },
-- { mnem="ldp i" , opcode=0x , {"adwlI" , "adwSaveP","instrNext"}, desc="P=I", ccode={"cpu.p=cpu.i; lni;"} },
-- { mnem="ldp cb" , opcode=0x , {"adwrCB", "adwSaveP","instrNext"}, desc="P=(C<<8)+B", ccode={"cpu.p=wordcb; lni;"} },
-- { mnem="ldq cb" , opcode=0x , {"adwrCB", "adwSaveQ","instrNext"}, desc="Q=(C<<8)+B", ccode={"cpu.q=wordcb; lni;"} },
{ mnem="TAS" , opcode=0x95, {"adwrlA", "adwSaveS","instrNext"}, desc="Copy %A into the 8-bit Stack Pointer register", ccode={"cpu.p=cpu.s; lni;"} },
{ mnem="TSA" , opcode=0xB5, {"alurSL","aluOpMov","aluSaveB","instrNext"}, desc="Copy the 8-bit Stack Pointer into the A register", ccode={"cpu.s=cpu.p; lni;"} },
}
if not __ARCH_INCLUDED then
local arch8608 = require("8608-definition")
arch8608.instructions = instructions
local gen = require("generate-architecture")
gen(arch8608, true, true)
end
return instructions

204
8608.asm Normal file
View File

@ -0,0 +1,204 @@
; 8608.asm
; Include this file into a CustomAsm assembly file to use the 8608 architecture, like so:
; #include "8608.asm"
; See CustomAsm for more info: https://github.com/hlorenzi/customasm
; Generated by generate-architecture.lua using the definitions in 8608-definition.lua
; Definitions for all instructions in the 8608 architecture.
#subruledef rel8 {
{addr} => {
reladdr = addr - $ - 2
assert(reladdr <= 127, "Relative jump target is too far away")
assert(reladdr >= -128, "Relative jump target is too far away")
reladdr`8
}
}
#subruledef neg8 {
{value} => {
mvalue = -value
mvalue`8
}
}
#ruledef {
RST => $41
BRK => $00
RTI => $40
NOP => $EA
CLI => $58
SEI => $78
HLT => $18
RUN => $38
INC A => $F6
DEC A => $D6
ICC A => $57
INC B => $FE
DEC B => $DE
ICC B => $5F
INC C => $FA
DEC C => $DA
ICC C => $5B
INC {value: u8} => $E6 @ value
DEC {value: u8} => $C6 @ value
ICC {value: u8} => $47 @ value
ADD #{value: i8} => $6B @ value
SUB #{value: i8} => $EB @ value
ADC #{value: i8} => $69 @ value
SBC #{value: i8} => $E9 @ value
CMP #{value: i8} => $C9 @ value
AND #{value: i8} => $29 @ value
ORA #{value: i8} => $09 @ value
EOR #{value: i8} => $49 @ value
ASL #{value: i8} => $15 @ value
LSR #{value: i8} => $55 @ value
ROL #{value: i8} => $35 @ value
ROR #{value: i8} => $75 @ value
ADD {value: u8} => $67 @ value
SUB {value: u8} => $E7 @ value
ADC {value: u8} => $65 @ value
SBC {value: u8} => $E5 @ value
CMP {value: u8} => $C5 @ value
AND {value: u8} => $25 @ value
ORA {value: u8} => $05 @ value
EOR {value: u8} => $45 @ value
ADD B => $7F
SUB B => $FF
ADC B => $7D
SBC B => $FD
CMP B => $DD
AND B => $3D
ORA B => $1D
EOR B => $5D
ADD C => $7B
SUB C => $FB
ADC C => $79
SBC C => $F9
CMP C => $D9
AND C => $39
ORA C => $19
EOR C => $59
BNE {value: rel8} => $D0 @ value
BEQ {value: rel8} => $F0 @ value
BLT {value: rel8} => $90 @ value
BGE {value: rel8} => $B0 @ value
BGT {value: rel8} => $30 @ value
BLE {value: rel8} => $10 @ value
BRA {value: rel8} => $98 @ value
ADX #{value: i8} => $E8 @ value
ADY #{value: i8} => $C8 @ value
ADX #{value: i16} => $8A @ value
ADY #{value: i16} => $88 @ value
ADX A => $FC
ADY A => $DC
JMP {value: i16} => $CC @ value
JSR {value: i16} => $20 @ value
JMP [{value: i16}] => $6C @ value
JSR [{value: i16}] => $2C @ value
JMP [{value: i16},A] => $4C @ value
JSR [{value: i16},A] => $0C @ value
JMP X => $64
JMP Y => $44
JSR X => $24
JSR Y => $04
RTS => $60
PHA => $48
PHB => $5C
PHC => $1C
PHP => $08
PHX => $54
PHY => $14
PLA => $68
PLB => $7C
PLC => $3C
PLP => $28
PLX => $74
PLY => $34
LDA #{value: i8} => $A9 @ value
LDB #{value: i8} => $AB @ value
LDC #{value: i8} => $2B @ value
LDA {value: u8} => $A5 @ value
LDB {value: u8} => $A7 @ value
LDC {value: u8} => $27 @ value
STA {value: u8} => $85 @ value
STB {value: u8} => $87 @ value
STC {value: u8} => $07 @ value
LDA {value: i16} => $ED @ value
LDB {value: i16} => $EF @ value
LDC {value: i16} => $6F @ value
STA {value: i16} => $CD @ value
STB {value: i16} => $CF @ value
STC {value: i16} => $4F @ value
LDA X => $A1
LDB X => $A3
LDC X => $23
LDA Y => $B1
LDB Y => $B3
LDC Y => $33
STA X => $81
STB X => $83
STC X => $03
STA Y => $91
STB Y => $93
STC Y => $13
LDA X+ => $E1
LDB X+ => $E3
LDC X+ => $63
LDA Y+ => $F1
LDB Y+ => $F3
LDC Y+ => $73
STA X+ => $C1
STB X+ => $C3
STC X+ => $43
STA Y+ => $D1
STB Y+ => $D3
STC Y+ => $53
LDA X,{value: u8} => $BD @ value
LDB X,{value: u8} => $BF @ value
LDC X,{value: u8} => $3F @ value
LDA Y,{value: u8} => $B9 @ value
LDB Y,{value: u8} => $BB @ value
LDC Y,{value: u8} => $3B @ value
STA X,{value: u8} => $9D @ value
STB X,{value: u8} => $9F @ value
STC X,{value: u8} => $1F @ value
STA Y,{value: u8} => $99 @ value
STB Y,{value: u8} => $9B @ value
STC Y,{value: u8} => $1B @ value
LDX #{value: i16} => $AA @ value
LDY #{value: i16} => $A8 @ value
LDX {value: u8} => $A6 @ value
LDY {value: u8} => $A4 @ value
STX {value: u8} => $86 @ value
STY {value: u8} => $84 @ value
LDX {value: i16} => $AE @ value
LDY {value: i16} => $AC @ value
STX {value: i16} => $8E @ value
STY {value: i16} => $8C @ value
LDX X,{value: u8} => $BE @ value
LDX Y,{value: u8} => $BA @ value
LDY X,{value: u8} => $BC @ value
LDY Y,{value: u8} => $B8 @ value
STX Y,{value: u8} => $9A @ value
STY X,{value: u8} => $9C @ value
LDX X => $A2
LDY X => $A0
LDX Y => $B2
LDY Y => $E2
STX Y => $92
STY X => $80
LDX Y+ => $F2
LDY X+ => $E0
STX Y+ => $D2
STY X+ => $C0
TBA => $97
TCA => $17
TAB => $B7
TCB => $D7
TAC => $37
TBC => $F7
TYX => $B4
TXY => $94
TVX => $B6
TXV => $96
TAS => $95
TSA => $B5
}

Binary file not shown.

1
architecture.md Normal file
View File

@ -0,0 +1 @@
WIP

View File

@ -1,716 +0,0 @@
local function loadutf8table(fn)
local tt = {}
for l in io.lines(fn) do if l~="" then
local c, d = l:match("^([^ ]+) (.+)$")
local t = {}; for v in d:gmatch("[^ ]+") do table.insert(t, tonumber(v, 16)) end;
tt[c] = t
end end
return tt
end
local utf8table = loadutf8table((RelPath or "./").."utf8table.txt")
local function trim(s) return s:gsub("^ +", ""):gsub(" +$", "").."" end
local function getutf8len(c)
local d = c:byte()
if bit.band(d, 0xE0)==0xC0 then return 2
elseif bit.band(d, 0xF0)==0xE0 then return 3
elseif bit.band(d, 0xF8)==0xF0 then return 4
else error("invalid utf8 first byte: "..string.format("%02X", d)) end
end
local function validWordsFromInstrs(instrs)
local words = {}
for mnem, _ in pairs(instrs) do
for word in mnem:gmatch("[^ ]+") do
words[word] = true
end
end
return words
end
local function lobyte(n) return n%256 end
local function hibyte(n) return math.floor(n/256) end
local function decodeNumber(n)
n = trim(n)
local sign = 1; if n:sub(1, 1)=="-" then sign = -1; n = n:sub(2, #n); end;
if n:sub(1, 1)=="$" then return sign*(tonumber(n:sub(2, #n ), 16) or error("invalid hex number "..n)), math.ceil((#n-1)/2)
elseif n:sub(1, 2)=="0x" then return sign*(tonumber(n:sub(3, #n ), 16) or error("invalid hex number "..n)), math.ceil((#n-2)/2)
elseif n:sub(#n, #n)=="h" and n:find("^[0-9a-fA-F]+h$") then return sign*(tonumber(n:sub(1, #n-1), 16) or error("invalid hex number "..n)), math.ceil((#n-1)/2)
elseif n:sub(1, 2)=="0b" then return sign*(tonumber(n:sub(3, #n ), 2) or error("invalid binary number "..n)), math.ceil((#n-2)/8)
elseif n:sub(#n, #n)=="b" and n:find("^[01]+b$") then return sign*(tonumber(n:sub(1, #n-1), 2) or error("invalid binary number "..n)), math.ceil((#n-1)/8)
elseif n:sub(1, 3)=="lo(" and n:sub(#n, #n)==")" then return lobyte(decodeNumber(n:sub(4, #n-1))), 1
elseif n:sub(1, 3)=="hi(" and n:sub(#n, #n)==")" then return hibyte(decodeNumber(n:sub(4, #n-1))), 1
elseif n:find("^[0-9]+$") then
local v = sign*(tonumber(n) or error("invalid decimal number "..n))
if v>=-128 and v<=255 then return v, 1
elseif v>=-32768 and v<=65535 then return v, 2
else error("out-of-range number "..v) end
else
return nil
end
end
local function mnemFromLine(line, instrs, validWords)
local imms = {}
local function addNum(n)
n = trim(n)
local val, len = decodeNumber(n)
assert(val and len, "invalid number "..n)
local linei8 = line:gsub(n, "imm8", 1, true):lower()
local linei16 = line:gsub(n, "imm16", 1, true):lower()
if len==1 and (not instrs[linei8]) and instrs[linei16] then len = 2 end
table.insert(imms, { val = val, len = len } )
return " imm"..(len*8).." "
end
local function addLabel(n)
n = trim(n)
local len = 2
local linei8 = line:gsub(n, "imm8", 1, true):lower()
if instrs[linei8] then len = 1 end
table.insert(imms, { label = n, len = len } )
return " imm"..(len*8).." "
end
local mnem = " "..line:gsub(" ", " ").." "
mnem = mnem:gsub("%- *", " %+%-")
mnem = mnem:gsub("([%*%+])", " %1 ")
mnem = mnem:gsub(" %-?%$[0-9a-fA-F]+ " , function(n) return addNum (n) end)
mnem = mnem:gsub(" %-?0x[0-9a-fA-F]+ " , function(n) return addNum (n) end)
mnem = mnem:gsub(" %-?0b[01]+ " , function(n) return addNum (n) end)
mnem = mnem:gsub(" %-?[0-9a-fA-F]+h " , function(n) if not validWords[trim(n)] then return addNum (n) end end)
mnem = mnem:gsub(" %-?[01]+b " , function(n) if not validWords[trim(n)] then return addNum (n) end end)
mnem = mnem:gsub(" %-?[0-9]+ " , function(n) if not validWords[trim(n)] then return addNum (n) end end)
mnem = mnem:gsub(" [a-zA-Z_][a-zA-Z0-9_%.]* ", function(n) if not validWords[trim(n)] then return addLabel(n) end end)
mnem = trim(mnem):gsub(" +", " "):lower()
if not instrs[mnem] then mnem = mnem:gsub("%+ imm", "imm") end
return mnem, imms
end
local function addByte(state, val, code)
assert(val>=-128 and val<=255, "invalid byte "..val)
assert(state.memory[state.curAddr]==nil, "overwriting memory at $"..string.format("%04X", state.curAddr))
state.memory[state.curAddr] = val%256
if code then state.codeMap[state.curAddr] = true end
state.curAddr = state.curAddr + 1
end
local function addWord(state, val, code)
assert(val>=0 and val<=65535, "invalid word "..val)
addByte(state, math.floor(val/256), code)
addByte(state, val%256, code)
end
local function addSpace(state, len)
for i = 1, len do
assert(state.memory[state.curAddr]==nil, "overwriting memory at $"..string.format("%04X", state.curAddr))
state.memory[state.curAddr] = false
state.curAddr = state.curAddr + 1
end
end
local function assembleInstruction(line, state, instrs, validWords)
local mnem, imms = mnemFromLine(line, instrs, validWords)
local opcode = instrs[mnem] or error("invalid instruction \""..line.."\" (mnem \""..mnem.."\")")
local writeimms = true
local padlen = 0
local isInstr
if type(opcode)=="function" then
padlen, writeimms = opcode(imms)
addSpace(state, padlen)
elseif opcode>=0 then
isInstr = true
addByte(state, opcode, isInstr)
end
if writeimms then
for _, imm in ipairs(imms) do
if imm.val then
if imm.len==1 then addByte(state, imm.val, isInstr)
elseif imm.len==2 then addWord(state, imm.val, isInstr)
else error("invalid imm len") end
elseif imm.label then
table.insert(state.labelReplacements, {
name = imm.label,
addr = state.curAddr,
len = imm.len,
rel = imm.len==1,
isCode = isInstr,
})
state.curAddr = state.curAddr + imm.len
else error("invalid imm") end
end
end
end
local directiveFunctions = {
fn = function(state, fn) state.fileName = fn end,
ln = function(state, ln) state.lineNum = tonumber(ln) end,
org = function(state, addr) state.curAddr = decodeNumber(addr) or error("Invalid origin \""..addr.."\"") end,
align = function(state, alns) local aln = decodeNumber(alns); if state.curAddr % aln ~= 0 then state.curAddr = state.curAddr + (aln - state.curAddr%aln) end end,
define = true,
space = function(state, amts) local amt = decodeNumber(amts); state.curAddr = state.curAddr + amt; end,
}
local function postEvaluateExpression(expr, labels)
end
local function assembleCode(code, instrs, uexprs)
local validWords = validWordsFromInstrs(instrs)
local state = {
lineNum = 0,
fileName = "",
curAddr = 0,
memory = {},
codeMap = {},
labelReplacements = {},
labelAddrs = {},
}
for line in code:gmatch("[^\n]+") do
line = trim(line)
if line:sub(1, 1)=="." then -- directive
local dir, rest = line:match("^%.([^ ]+) *(.*)$")
assert(dir and rest, "no directive on line "..line)
local dirf = directiveFunctions[dir] or error("invalid directive "..dir)
dirf(state, rest)
elseif line:sub(#line, #line)==":" then -- label
local name = line:sub(1, #line-1)
assert(not state.labelAddrs[name], "redefinition of label "..name)
state.labelAddrs[name] = state.curAddr
elseif line:find("[^ ]") then
assembleInstruction(line, state, instrs, validWords)
end
end
for _, rep in ipairs(state.labelReplacements) do
local expr = uexprs[rep.name]
if expr then
local val = postEvaluateExpression(expr, state.labelAddrs)
if rep.len==1 then addByte(state, val, rep.isCode)
elseif rep.len==2 then addWord(state, val, rep.isCode)
else error("invalid expr replace len "..rep.len) end
else
local labelAddr = state.labelAddrs[rep.name] or error("no label named "..rep.name)
state.curAddr = rep.addr
if rep.len==1 then addByte(state, labelAddr-(rep.addr+1), rep.isCode)
elseif rep.len==2 then addWord(state, labelAddr , rep.isCode)
else error("invalid labelreplace len "..rep.len) end
end
end
return state.memory, state.codeMap
end
local function readFile(fn)
local fi, err = io.open(fn, "r")
if not fi then error("could not open file "..fn..": "..err) end
local text = fi:read("*a")
fi:close()
return text
end
local function separateCommas(l)
local c = {}; for a in l:gmatch("[^,]+") do table.insert(c, trim(a)) end; return c;
end
local function evaluateExpression(expr, uexprs)
expr = expr:gsub("[^%+%-%*%/]+", function(word)
local val = decodeNumber(word) or error("invalid number in expression: "..word)
return val
end)
assert(not expr:find("[^a-zA-Z0-9_%(%)%+%-%*%/ \t\r\n]"), "invalid char in expression: "..expr)
local exprf = loadstring("return "..expr)
local eval = exprf() or error("invalid expr: "..expr)
return eval
end
local function preprocessCode(code)
code = "\n"..code.."\n"
local curscope = ""
local codet = {}
local wordt = {}
local lastword = ""
local function addword(word)
lastword = word
if word:sub(1, 1)=="." and not directiveFunctions[word:sub(2, #word)] then word = curscope..word end
table.insert(codet, word)
end
for i = 1, #code do
local c = code:sub(i, i)
if c:find("[%.a-zA-Z0-9_]") then table.insert(wordt, c)
else
if #wordt>0 then
addword(table.concat(wordt))
wordt = {}
end
if c==":" and lastword:sub(1, 1)~="." and not lastword:find("_BRACE_") then
curscope = lastword
end
table.insert(codet, c)
end
end
code = "\n"..table.concat(codet).."\n"
local funcmacros = {}
code = code:gsub(".define ([%.a-zA-Z0-9_]+)%(([^%)]+)%) ([^\n]+)", function(name, args, repl)
local argt = separateCommas(args)
for argidx, arg in ipairs(argt) do assert(not arg:find("[^a-zA-Z0-9_]"), "invalid character in macro arg name: "..name.." "..arg) end
repl = " "..repl.." "
local invoc = 0
funcmacros[name] = function(b, callargs)
invoc = invoc + 1
local callargt = separateCommas(callargs)
local callrepl = repl
for argidx, arg in ipairs(argt) do
local callarg = callargt[argidx]
callrepl = callrepl:gsub("([^a-zA-Z0-9_])"..arg.."([^a-zA-Z0-9_])", "%1"..callarg.."%2")
end
callrepl = callrepl:gsub("(_BRACE_[0-9]+_)", "%1"..invoc.."_")
return b..callrepl
end
return ""
end)
for name, replf in pairs(funcmacros) do code = code:gsub("([^a-zA-Z0-9_])"..name.." *%(([^%)]+)%)", replf) end
local simplemacros = {}
code = code:gsub("%.define +([%.a-zA-Z0-9_]+) +([^\n]+)", function(name, repl)
assert(not simplemacros[name], "Redefinition of macro "..name)
simplemacros[name] = repl
return ""
end)
--for name, repl in pairs(simplemacros) do code = code:gsub(name, repl, 1, true) end
for name, repl in pairs(simplemacros) do
local invoc = 0
code = code:gsub("([^a-zA-Z0-9_])"..name.."([^a-zA-Z0-9_])", function(b, a)
invoc = invoc+1
return b..(repl:gsub("(_BRACE_[0-9]+_)", "%1"..invoc.."_"))..a
end)
end
code = code:gsub("\\", "\n")
local uexprs = {}
local codet = {}
local exprt = {}
local parenLevel = 0
for i = 1, #code do
local c = code:sub(i, i)
if c=="(" then
if parenLevel>0 then table.insert(exprt, c) end
parenLevel = parenLevel+1
elseif c==")" then
parenLevel = parenLevel-1
if parenLevel==0 then
table.insert(codet, evaluateExpression(table.concat(exprt), uexprs))
exprt = {}
else
table.insert(exprt, c)
end
else
if parenLevel==0 then table.insert(codet, c)
else table.insert(exprt, c) end
end
end
code = table.concat(codet)
return code, uexprs
end
local function fixCode(code)
code = code:gsub(",", " ")
code = code:gsub(":([^\\/])", ":\n%1")
code = code:gsub("[ \t]+:", ":")
code = code:gsub("%]", " %] ")
code = code:gsub("%[", " %[ ")
code = code:gsub("%*", " %* ")
code = code:gsub("\n[ \t\r\n]*", "\n")
code = code:gsub(" +", " ")
return code
end
local stringEscapes = { ["\\"] = "\\", ["n"] = "\n", ["r"] = "\r", ["t"] = "\t", ["0"] = "\0", ["\""] = "\"", ["\'"] = "\'", }
local prefixIdx = 0
local function prefixCode(code, fn) -- fix strings, add line numbers
prefixIdx = prefixIdx + 1
local outt = {}
local outnextnl = {}
local linenum = 1
local skipnl = false
local function last() return outt[#outt] end
local function out(c) assert(type(c)=="string"); table.insert(outt, c); end
local function outn(n) out("$"..string.format("%02X", n)) out("\\") end
local function outnext(c) assert(type(c)=="string"); table.insert(outnextnl, c); end
local state = "code" -- code, comment, string, stringesc, commentml
local lastbracelabel = 0
local function bracelabel() lastbracelabel = lastbracelabel+1; return "_BRACE_"..string.format("%02d", prefixIdx)..lastbracelabel.."_"; end
local bracestack = {}
local bracehasmid = {}
local lastnl = false
local utf8str = ""
local utf8len = 0
local function newline()
lastnl = true
for _, v in ipairs(outnextnl) do
if v=="\n" and skipnl then out("\\")
else out(v) end
end; outnextnl = {};
end
out(".ln 1"); out("\n");
for i = 1, #code do
local c = code:sub(i, i)
local cn = code:sub(i+1, i+1)
local cp = code:sub(i-1, i-1)
if state=="code" then
if c=="\r" then
elseif c=="\n" or (c=="/" and cn~="/" and cn~="*") then
linenum = linenum+1
if not skipnl then out("\n") out(".ln "..linenum); out("\n"); end
newline()
skipnl = false
elseif c=="#" or c==";" or (c=="/" and cn=="/") then state = "comment"
elseif c=="/" and cn=="*" then state = "commentml"
elseif c=="\t" or c==" " then if (not lastnl) then out(" ") end
elseif c=="\"" then state = "string" lastnl = false
elseif c=="\\" then skipnl = true; out("\\");
elseif c==":" then out(c); if skipnl then out("\\") else out("\n") end; lastnl = true;
elseif c:find("^[a-zA-Z0-9_%.%$%(%)%*,%[%]%+%-%*%/]$") then out(c); lastnl = false
elseif c=="{" then
table.insert(bracestack, bracelabel())
if not lastnl then out(bracestack[#bracestack].."MID") end
outnext(bracestack[#bracestack].."START:"); outnext("\n");
elseif c=="}" then
if not lastnl then out(bracestack[#bracestack].."START") end
if not bracehasmid[#bracestack] then outnext(bracestack[#bracestack].."MID:"); outnext("\n"); end
outnext(bracestack[#bracestack].."END:"); outnext("\n");
bracehasmid[#bracestack] = nil
bracestack[#bracestack] = nil
elseif c=="|" then
if not lastnl then out(bracestack[#bracestack].."END") end
outnext(bracestack[#bracestack].."MID:"); outnext("\n");
bracehasmid[#bracestack] = true
else error("invalid char "..c) end
elseif state=="comment" then
if c=="\n" then state = "code" out("\n") newline() end
elseif state=="commentml" then
if c=="/" and cp=="*" then state = "code" end
elseif state=="string" then
if c=="\\" then state = "stringesc"
elseif c=="\"" then state = "code"
elseif c:byte()>=128 then
utf8str = c
utf8len = getutf8len(c)
state = "stringutf8"
else outn(c:byte()) end
elseif state=="stringesc" then
outn(string.byte(stringEscapes[c] or error("invalid escape "..c))); state = "string";
elseif state=="stringutf8" then
utf8str = utf8str..c
if #utf8str == utf8len then
local valt = utf8table[utf8str]
if not valt then local datastr = ""; for i = 1, #utf8str do datastr = datastr .. string.format("%02X ", utf8str:sub(i, i):byte()) end;
error("Unrecognized UTF-8 character: "..datastr); end
for i, v in ipairs(valt) do outn(v) end
state = "string"
end
end
end
assert(#bracestack==0, "unclosed brace")
local code2 = table.concat(outt)
return code2
end
local function fixFilename(fn)
fn = fn:gsub("[^a-zA-Z0-9_]", "_")
return fn
end
local function includeFile(fn)
local code = readFile(fn)
code = prefixCode(code, fn)
local fnf = fixFilename(fn)
code = ".fn "..fnf.."\n"..code
code = code:gsub(".include ([^\r\n]+)", function(fn2)
fn2 = fn:gsub("[^\\/]+$", "")..fn2
return "\n"..includeFile(fn2).."\n"..".fn "..fnf.."\n"
end)
return code
end
local function instrsFromArch(arch)
local function arraySize(imms) local s = 1; for i = 1, #imms do s = s*(imms[i].val or error("invalid array size")) end; return s; end
local instrs = {
imm8 = function() return 0, true end,
imm16 = function() return 0, true end,
byte = function() return 1, false end,
word = function() return 2, false end,
["byte imm8"] = function() return 0, true end,
["word imm16"] = function() return 0, true end,
["byte [ imm8 ]" ] = function(imms) return arraySize(imms) , false end,
["byte [ imm16 ]"] = function(imms) return arraySize(imms) , false end,
["word [ imm8 ]" ] = function(imms) return arraySize(imms)*2, false end,
["word [ imm16 ]"] = function(imms) return arraySize(imms)*2, false end,
}
local function addMnem(mnem, opcode)
instrs[mnem] = opcode
if mnem:find("%*") then instrs[mnem:gsub("%*", "%[").." ]"] = opcode end
end
for _, instr in ipairs(arch.instructions) do
if instr.mnem then
local mnem = instr.mnem
mnem = mnem:gsub("([%*%+%-])", " %1 ")
mnem = trim(mnem):gsub(" +", " ")
addMnem(mnem, instr.opcode)
local alias = arch.aliases[trim(mnem)]
if alias then for _, v in ipairs(alias) do addMnem(v, instr.opcode) end end
end
end
return instrs
end
local function assembleFile(fn, arch)
local code = includeFile(fn)
code, uexprs = preprocessCode(code)
code = fixCode(code)
local instrs = instrsFromArch(arch)
local mem, code = assembleCode(code, instrs, uexprs)
return mem, code
end
local function mnemsFromArch(arch)
local mnems = {}
for _, instr in ipairs(arch.instructions) do
if instr.mnem then
local len = 1
for l in instr.mnem:gmatch("imm([0-9]+)") do len = len + tonumber(l)/8 end
mnems[instr.opcode] = { mnem = instr.mnem, rel = instr.rel, jmp = instr.jmp, len = len, }
end
end
return mnems
end
local function toSigned8(x) return x>=128 and x-256 or x end
local function disassembleMemory(mem, code, arch)
local mnems = mnemsFromArch(arch)
local addr = 0
local function nextByte(d) local b = mem[addr]; addr = addr+1; return b or d; end
local lastaddr = 0
local jmpaddrs = {}
while addr<=0xFFFF do
local startaddr = addr
local opcode = nextByte()
if opcode and ((not code) or code[startaddr]) then
local mnem = mnems[opcode]
if mnem then
if mnem.jmp then
local jmpdest
if mnem.rel then jmpdest = toSigned8(nextByte(0)) + addr
else jmpdest = nextByte(0)*256 + nextByte(0)
end
if jmpdest then
if not jmpaddrs[jmpdest] then
jmpaddrs[jmpdest] = { rel = mnem.rel, from = {}, }
end
table.insert(jmpaddrs[jmpdest].from, startaddr)
jmpaddrs[jmpdest].rel = jmpaddrs[jmpdest].rel and mnem.rel
end
else
addr = addr + mnem.len - 1
end
end
end
end
local labelnum, subnum = 0, 0
for _, jmp in pairs(jmpaddrs) do
if jmp.rel then jmp.name = "label_" ..labelnum; labelnum = labelnum+1;
else jmp.name = "subroutine_"..subnum ; subnum = subnum +1; end
end
local lines = {}
addr = 0
while addr<=0xFFFF do
local startaddr = addr
local opcode = nextByte()
if opcode and ((not code) or code[startaddr]) then
local line = {}
local mnem = mnems[opcode].mnem or "???"
table.insert(line, trim(mnem:gsub("imm[0-9]+", "")))
local tlen = 1
for lens in mnem:gmatch("imm([0-9]+)") do local len = tonumber(lens)/8
if len==1 then
local data = nextByte(0)
local jmp
if mnems[opcode].rel then
local jmpdest = (addr + toSigned8(data))%65536
jmp = jmpaddrs[jmpdest]
if jmp then
table.insert(line, jmp.name)
--table.insert(line, ";")
--table.insert(line, "$"..string.format("%04X", jmpdest)..",")
end
end
if not jmp then table.insert(line, "$"..string.format("%02X", data)) end
elseif len==2 then
local data = nextByte(0)*256 + nextByte(0)
local jmp
if mnems[opcode].jmp then
local jmpdest = data
jmp = jmpaddrs[jmpdest]
if jmp then
table.insert(line, jmp.name)
--table.insert(line, ";")
end
end
if not jmp then table.insert(line, "$"..string.format("%04X", data)) end
else error("invalid imm len") end
tlen = tlen + len
end
local lineb = {}
for i = addr-tlen, addr-1 do
table.insert(lineb, string.format("%02X", mem[i] or 0))
end
local label = ""
local jmp = jmpaddrs[startaddr]
if jmp then label = jmp.name..":" end
local lb = table.concat(lineb, " ")
if lastaddr~=addr-tlen then table.insert(lines, "...") end
table.insert(lines, string.format("%04X", addr-tlen).." | "..(" "):rep(8-#lb)..lb.." | "..(" "):rep(13-#label)..label.." "..table.concat(line, " "))
lastaddr = addr
end
end
return table.concat(lines, "\n")
end
local function memToHex(hex)
local mem = {}
local addr = 0
for d in hex:gmatch("[0-9a-fA-F][0-9a-fA-F]") do
mem[addr] = tonumber(d, 16)
addr = addr+1
end
return mem
end
local function disassembleHex(hex, arch)
return disassembleMemory(memToHex(hex), arch)
end
local printableCharsS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789`-=[]\\;\',./~!@#$%^&*()_+{}|:\"<> "
local printableChars = {}; for i = 1, #printableCharsS do printableChars[printableCharsS:sub(i, i)] = true end;
local function toPrintableChar(n)
local c = string.char(n)
return printableChars[c] and c or "?"
end
local function printMemory(mem)
local anynonempty = false
local lastbase = -16
local lastline = ""
local numreps = 0
local lines = {}
local function closereps(base)
if numreps~=0 then
table.insert(lines, "(repeated "..numreps.." more times, up to "..string.format("%04X", base+15)..")")
numreps = 0
end
end
for base = 0, 0xFFF0, 16 do
local line = {}
local strt = {}
local nonempty = false
for addr = base, base+15 do
if addr%4==0 then table.insert(line, " ") end
if mem[addr]==false then
nonempty = true
table.insert(line, "XX ")
table.insert(strt, "X")
elseif mem[addr] then
nonempty = true
table.insert(line, string.format("%02X", mem[addr]).." ")
table.insert(strt, toPrintableChar(mem[addr]))
else
table.insert(line, "-- ")
table.insert(strt, "-")
end
end
if nonempty then
local l = table.concat(line)
if l~=lastline or base~=lastbase+16 then
closereps(base-16)
if base ~= lastbase+16 then table.insert(lines, "...") end
table.insert(lines, string.format("%04X", base).." | "..l.." | "..table.concat(strt))
else
numreps = numreps+1
end
lastline = l
lastbase = base
anynonempty = true
end
end
closereps(lastbase)
if not anynonempty then table.insert(lines, "Empty") end
return table.concat(lines, "\n")
end
local HasTs = ts~=nil
local ts = ts or {
call = function() end,
eval = function() end,
}
ts.eval [[
function commandShiftBrick(%x, %y, %z) { commandToServer('shiftBrick', %x, %y, %z); }
function commandPlantBrick() { commandToServer('plantBrick'); }
]]
local function plantBrickAt(brickpos, pos)
local dx, dy, dz = pos[1]-brickpos[1], pos[2]-brickpos[2], pos[3]-brickpos[3]
ts.call("commandShiftBrick", dy, -dx, dz)
ts.call("commandPlantBrick")
brickpos[1], brickpos[2], brickpos[3] = pos[1], pos[2], pos[3]
end
local function buildMemory(mem, romsize, offset, len)
offset = offset or 0
local rombytes = romsize[1]*romsize[2]*romsize[3]/8
if len and len>rombytes then error("rom not big enough to hold "..len.." bytes (holds "..rombytes..")") end
if not len then
for i = 0, 0xFFFF do
if mem[i] and (i<offset or i>=offset+rombytes) then error("memory does not fit in rom at addr "..string.format("%04X", i)) end
end
end
local brickpos = {0, 0, 0}
for x = 0, romsize[1]-1 do
for y = 0, romsize[2]-1 do
for z = 0, romsize[3]-1 do
local addr = offset + ((romsize[3]/8)*(x + y*romsize[1]) + math.floor(z/8))
local pow = math.pow(2, z%8)
local data = (addr>=offset and ((not len) or addr<offset+len) and mem[addr]) or 0
local bit = math.floor(data/pow)%2
if bit==1 then plantBrickAt(brickpos, {x, -y, z}) end
end
end
end
end
local function strtovec(str) local v = {}; for word in str:gmatch("[^ \t\r\n]+") do table.insert(v, tonumber(word)) end; return v; end
if HasTs or (not AsmIncluded) then
function AssembleBuildFile(fn, romsizes, offsets, lens) local offset = tonumber(offsets); local len = tonumber(lens); local romsize = strtovec(romsizes);
local arch = require("rom-8608-defs")
local mem, code = assembleFile(fn, arch)
print(""..fn:match("[^/\\]+$").."\n")
print("Memory Dump:")
print(printMemory(mem))
print()
print("Disassembly:")
print(disassembleMemory(mem, code, arch))
print()
assert(#romsize==3, "incorrect rom size")
buildMemory(mem, romsize, offset, len)
end
ts.eval [[
function AssembleBuildFile(%fn, %romsize, %offset, %len) { luacall("AssembleBuildFile", strReplace(%fn, "$", "Add-ons/_misc/rom/8608programs/"), %romsize, %offset, %len); }
]]
if not HasTs then AssembleBuildFile(arg[1] or "../8608programs/test.asm", "16 16 8", "0", "256") end
end
return {
assembleFile = assembleFile,
disassembleMemory = disassembleMemory,
printMemory = printMemory,
}

View File

@ -0,0 +1,20 @@
@echo off
rem This is the main process to run the 8608 Emulator.
rem To use it, simply drag an .asm file onto this batch file.
if [%1] == [] goto noarg
cd /d %~dp0
mkdir temp
"third-party/customasm/customasm.exe" -f binary -o "temp/temp.bin" %~dpnx1
"third-party/customasm/customasm.exe" -f annotated -o "temp/temp.lis" %~dpnx1
"third-party/love/love.exe" %~dp0 "temp/temp.bin"
goto done
:noarg
echo No input file specified.
echo Drag-and-drop an assembly code file onto this .bat file to use the emulator.
echo.
pause
:done

View File

@ -1,3 +0,0 @@
luajit gendefs.lua
gcc 8608emulator.c -shared -Ofast -o 8608emulator.dll
pause

View File

@ -1,43 +1,51 @@
// 8608emulator.c
// This is the backend portion of the 8608 emulator application.
// It uses the generated instruction code from instructions_gen.c to emulate the internals of the 8608 CPU.
// It is included into the application by 8608emulator.lua, which provides the frontend.
#define lobyte(x) (x&0xFF)
#define hibyte(x) ((x>>8)&0xFF)
#define wordfrombytes(h,l) (((h<<8)&0xFF00)|(l&0xFF))
#define popbyte readmemory(--cpu->s)
#define popbyte readmemory(((--cpu->s)%256)+0x0100)
#define loadimmed readmemory(cpu->i++)
#define loadstackrel readmemory((cpu->s+signed8(cpu->t))%65536)
#define loadstackrelp1 readmemory((cpu->s+signed8(cpu->t)+1)%65536)
#define loadstackrel readmemory(cpu->t)
#define loadstackrelp1 readmemory(cpu->t+1)
#define wordut (wordfrombytes(cpu->u, cpu->t))
#define wordcb (wordfrombytes(cpu->c, cpu->b))
#define loadut readmemory(wordut)
#define loadutp1 readmemory((wordut+1)%65536)
#define loadp readmemory(cpu->p)
#define loadpinc readmemory(cpu->p++)
#define loadpp1 readmemory((cpu->p+1)%65536)
#define loadq readmemory(cpu->q)
#define loadqinc readmemory(cpu->q++)
#define loadpinc readmemory((cpu->p++)%65536)
#define loadqinc readmemory((cpu->q++)%65536)
#define loadpp1 readmemory((cpu->p+1)%65536)
#define loadqp1 readmemory((cpu->q+1)%65536)
#define loadput readmemory((cpu->p+wordut)%65536)
#define loadqut readmemory((cpu->q+wordut)%65536)
#define signed8(x) (x>=128 ? x|0xFF00 : x)
#define setzf(x) cpu->nz=(x!=0);
#define loadimmedt cpu->t = loadimmed;
#define loadimm161 cpu->u = loadimmed;
#define loadimm162 cpu->t = loadimmed;
#define loadstackrelu cpu->u = loadstackrel;
#define storestackrel(x) writememory(cpu->s+signed8(cpu->t), x);
#define storestackrel161(x) writememory((cpu->s+signed8(cpu->t) )%65536, hibyte(x));
#define storestackrel162(x) writememory((cpu->s+signed8(cpu->t)+1)%65536, lobyte(x));
#define storestackrel(x) writememory(cpu->t, x);
#define storestackrelu storestackrel(cpu->u);
#define storestackrel161(x) writememory(cpu->t , hibyte(x));
#define storestackrel162(x) writememory(cpu->t+1, lobyte(x));
#define loadstackrel161 cpu->u=loadstackrel;
#define loadstackrel162 cpu->t=loadstackrelp1;
#define storeut(x) writememory(wordut, x);
#define storeutp1(x) writememory((wordut+1)%65536, x);
#define storep(x) writememory(cpu->p, x);
#define storepinc(x) writememory(cpu->p++, x);
#define storepp1(x) writememory((cpu->p+1)%65536, x);
#define storeq(x) writememory(cpu->q, x);
#define storepinc(x) writememory(cpu->p++, x);
#define storeqinc(x) writememory(cpu->q++, x);
#define storepp1(x) writememory((cpu->p+1)%65536, x);
#define storeqp1(x) writememory((cpu->q+1)%65536, x);
#define pushretaddr1 writememory(cpu->s++, hibyte((cpu->i-1)%65536));
#define pushretaddr2 writememory(cpu->s++, lobyte((cpu->i-1)%65536));
#define storeput(x) writememory((cpu->p+wordut)%65536, x);
#define storequt(x) writememory((cpu->q+wordut)%65536, x);
#define pushretaddr1 writememory(((cpu->s++)%256)+0x0100, hibyte((cpu->i-1)%65536));
#define pushretaddr2 writememory(((cpu->s++)%256)+0x0100, lobyte((cpu->i-1)%65536));
#define lni cpu->instr = readmemory(cpu->i++); cpu->cycle = 0;
#define ldi cpu->instr = readmemory(cpu->i); cpu->cycle = 0;
#define addf(x,y) { x=(x+y)&0x1FF; cpu->cf=x>=256; x&=0xFF; setzf(x); }
@ -50,14 +58,14 @@
#define jmpabsq cpu->i=cpu->q; lni;
#define jmpabsut cpu->i=wordut; lni;
#define jmpabsutplus1 cpu->i=(wordut+1)%65536; lni;
#define pushbyte(b) writememory(cpu->s++, b);
#define pushbyte(b) writememory(((cpu->s++)%256)+0x0100, b);
#define push161(x) pushbyte(hibyte(x));
#define push162(x) pushbyte(lobyte(x));
#define pop161 cpu->t=popbyte;
#define pop162 cpu->u=popbyte;
#define tst(x) cpu->cf = x>=128; cpu->nz = x!=0;
#define instrpreload cpu->instrpre = loadimmed;
#define instrloadpre cpu->instr = cpu->instrpre;
#define instrloadpre cpu->instr = cpu->instrpre; cpu->cycle = 0;
#define jmprelt cpu->i = (cpu->i + signed8(cpu->t))%65536; lni;
#define saveretaddr cpu->q = (cpu->i+1)%65536;
@ -134,8 +142,8 @@ typedef void(*CPUInstruction)(struct CPU* const cpu, struct Memory* const mem);
int TickCPU(struct CPU* const cpu, struct Memory* const mem, const int count, const int countinstrs, const int breakaddr) {
int i = 0;
while(i<count) {
if(cpu->irq && !cpu->ifg && cpu->cycle==0 && cpu->ien) { cpu->instr = 0xF2; }
if(cpu->rfg || cpu->ifg || cpu->irq) {
if(cpu->irq && !cpu->ifg && cpu->cycle==0 && cpu->ien) { cpu->instr = 0x01; }
if(cpu->rfg || cpu->ifg || (cpu->irq && cpu->ien)) {
CPUInstruction instr = CPUInstructions[cpu->instr][cpu->cycle];
if(instr) instr(cpu, mem);
if(!countinstrs || cpu->cycle==0) { i++; }

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,8 @@
-- Colorset definitions
-- This is used by the emulator to convert color codes into colors for the text and video displays.
-- It should correspond with the colorset used in-game.
-- Colors are listed in order of color code from 0 to 63.
-- The format is 8-bit RGBA. The alpha channel is currently ignored.
ColorSet = {
{222,52,52,255},

View File

@ -7,4 +7,5 @@ function love.conf(t)
t.console = true
t.window.width = WindowX*WindowScale
t.window.height = WindowY*WindowScale
t.window.title = "8608 Emulator"
end

BIN
emulator/content/enter.wav Normal file

Binary file not shown.

BIN
emulator/content/error.wav Normal file

Binary file not shown.

Binary file not shown.

BIN
emulator/content/keyOff.wav Normal file

Binary file not shown.

BIN
emulator/content/keyOn.wav Normal file

Binary file not shown.

BIN
emulator/content/runOff.wav Normal file

Binary file not shown.

BIN
emulator/content/runOn.wav Normal file

Binary file not shown.

BIN
emulator/content/start.wav Normal file

Binary file not shown.

BIN
emulator/content/step.wav Normal file

Binary file not shown.

Binary file not shown.

BIN
emulator/content/write.wav Normal file

Binary file not shown.

Binary file not shown.

View File

@ -1,3 +1,6 @@
-- gendefs.lua
-- This code generates instructions_gen.c from the instruction definitions in 8608-instructions.lua.
-- It is executed as part of the compilation process for the 8608 emulator DLL.
local function fixCode(code)
code = code:gsub("cpu%.", "cpu%->")
@ -60,7 +63,9 @@ local function ccodeFromArch(arch)
)
end
local arch = dofile("../rom-8608-defs.lua")
__ARCH_INCLUDED = true
local arch = dofile("../8608-definition.lua")
arch.instructions = dofile("../8608-instructions.lua")
local fo = io.open("instructions_gen.c", "w")
fo:write(ccodeFromArch(arch))
fo:close()

View File

@ -0,0 +1,7 @@
rem This is the procedure to generate the C code for the emulator backend
rem from the instruction definitions in the parent directory,
rem and compile it.
luajit gendefs.lua
gcc 8608emulator.c -shared -Ofast -o 8608emulator.dll
pause

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +1,18 @@
-- copied from Brick_LuaLogic/bricks/input/keyboard-global.lua
-- with some key names changed from Torque format to LOVE format.
return {
["backspace"] = 8,
["tab"] = 9,
["return"] = 13,
["lshift"] = 16,
["lshift"] = 16, -- 0x10
["lctrl"] = 17, --["lcontrol"] = 17,
["lalt"] = 18,
-- this block does not match vkey codes
["rshift"] = 20,
["rshift"] = 20, -- 0x14
["rctrl"] = 21, --["rcontrol"] = 21,
["ralt"] = 22,
@ -108,5 +111,5 @@ return {
["f11"] = 122,
["f12"] = 123,
["invalid"] = 127,
--["invalid"] = 127,
}

BIN
emulator/temp/temp.bin Normal file

Binary file not shown.

16
emulator/temp/temp.hex Normal file
View File

@ -0,0 +1,16 @@
outp | addr | data (base 16)
ff00:0 | ff00 | ; PRINTCHAR:
ff00:0 | ff00 | aa ff 0d ; LDX #HELLOSTR
ff03:0 | ff03 | a8 c0 00 ; LDY #$C000
ff06:0 | ff06 | ; PRINTLP:
ff06:0 | ff06 | e1 ; LDA X+
ff07:0 | ff07 | 48 ; PHA
ff08:0 | ff08 | d1 ; STA Y+
ff09:0 | ff09 | d0 fb ; BNE PRINTLP
ff0b:0 | ff0b | 18 ; HLT
ff0c:0 | ff0c | 41 ; RST
ff0d:0 | ff0d | ; HELLOSTR:
ff0d:0 | ff0d | 48 65 6c 6c 6f 2c 20 77 6f 72 6c 64 21 00 ; "Hello, world!\0"
fffc:0 | fffc | ff 00 ; PRINTCHAR
fffe:0 | fffe | 00 00 ; 0

260
emulator/temp/temp.lis Normal file
View File

@ -0,0 +1,260 @@
outp | addr | data (base 16)
0:0 | 0 | ; CURSORPOS:
2:0 | 2 | ; SHIFTDOWN:
3:0 | 3 | ; TESTCHAR:
fc00:0 | fc00 | fc 20 ; PRINTCHAR
fc02:0 | fc02 | fd 1b ; GETCHAR
fc04:0 | fc04 | fc 92 ; PRINTSTRING
fc06:0 | fc06 | fd 59 ; GETSTRING
fc08:0 | fc08 | fc 9f ; PRINTHEX
fc0a:0 | fc0a | fd 8e ; SLEEP
fc20:0 | fc20 | ; PRINTCHAR:
fc20:0 | fc20 | 48 ; PHA
fc21:0 | fc21 | 54 ; PHX
fc22:0 | fc22 | c9 0a ; CMP #$0A
fc24:0 | fc24 | f0 1a ; BEQ PRINTCHAR_NL
fc26:0 | fc26 | c9 0c ; CMP #$0C
fc28:0 | fc28 | f0 3d ; BEQ PRINT_CLS
fc2a:0 | fc2a | c9 08 ; CMP #$08
fc2c:0 | fc2c | f0 28 ; BEQ BACKSPACE
fc2e:0 | fc2e | a6 00 ; LDX CURSORPOS
fc30:0 | fc30 | c1 ; STA X+
fc31:0 | fc31 | 86 00 ; STX CURSORPOS
fc33:0 | fc33 | a5 01 ; LDA CURSORPOS+1
fc35:0 | fc35 | d0 06 ; BNE PRINTCHAR_RETURN
fc37:0 | fc37 | a5 00 ; LDA CURSORPOS
fc39:0 | fc39 | c9 c4 ; CMP #SCREEN_CHAR_OVFPG
fc3b:0 | fc3b | f0 2f ; BEQ SCROLLUP
fc3d:0 | fc3d | ; PRINTCHAR_RETURN:
fc3d:0 | fc3d | 74 ; PLX
fc3e:0 | fc3e | 68 ; PLA
fc3f:0 | fc3f | 60 ; RTS
fc40:0 | fc40 | ; PRINTCHAR_NL:
fc40:0 | fc40 | a5 01 ; LDA CURSORPOS+1
fc42:0 | fc42 | 29 c0 ; AND #$100-SCREEN_WIDTH
fc44:0 | fc44 | c9 c0 ; CMP #$100-SCREEN_WIDTH
fc46:0 | fc46 | d0 06 ; BNE NOSCROLLUP
fc48:0 | fc48 | a5 00 ; LDA CURSORPOS
fc4a:0 | fc4a | c9 c3 ; CMP #SCREEN_CHAR_MAXPG
fc4c:0 | fc4c | f0 1e ; BEQ SCROLLUP
fc4e:0 | fc4e | ; NOSCROLLUP:
fc4e:0 | fc4e | 6b 40 ; ADD #$40
fc50:0 | fc50 | 47 00 ; ICC CURSORPOS
fc52:0 | fc52 | 85 01 ; STA CURSORPOS+1
fc54:0 | fc54 | 98 e7 ; BRA PRINTCHAR_RETURN
fc56:0 | fc56 | ; BACKSPACE:
fc56:0 | fc56 | a5 01 ; LDA CURSORPOS+1
fc58:0 | fc58 | 29 3f ; AND #SCREEN_WIDTH-1
fc5a:0 | fc5a | f0 e1 ; BEQ PRINTCHAR_RETURN
fc5c:0 | fc5c | a6 00 ; LDX CURSORPOS
fc5e:0 | fc5e | e8 ff ; ADX #-1
fc60:0 | fc60 | 86 00 ; STX CURSORPOS
fc62:0 | fc62 | a9 00 ; LDA #$00
fc64:0 | fc64 | 81 ; STA X
fc65:0 | fc65 | 98 d6 ; BRA PRINTCHAR_RETURN
fc67:0 | fc67 | ; PRINT_CLS:
fc67:0 | fc67 | 20 fc a0 ; JSR CLEARSCREEN
fc6a:0 | fc6a | 98 d1 ; BRA PRINTCHAR_RETURN
fc6c:0 | fc6c | ; SCROLLUP:
fc6c:0 | fc6c | 14 ; PHY
fc6d:0 | fc6d | 48 ; PHA
fc6e:0 | fc6e | 5c ; PHB
fc6f:0 | fc6f | 1c ; PHC
fc70:0 | fc70 | aa c0 00 ; LDX #SCREEN_CHAR
fc73:0 | fc73 | a8 c0 40 ; LDY #SCREEN_CHAR+SCREEN_WIDTH
fc76:0 | fc76 | 2b 0f ; LDC #SCREEN_HEIGHT-1
fc78:0 | fc78 | ; SCROLLUP_LPOUT:
fc78:0 | fc78 | ab 40 ; LDB #SCREEN_WIDTH
fc7a:0 | fc7a | ; SCROLLUP_LPIN:
fc7a:0 | fc7a | f1 ; LDA Y+
fc7b:0 | fc7b | c1 ; STA X+
fc7c:0 | fc7c | de ; DEC B
fc7d:0 | fc7d | d0 fb ; BNE SCROLLUP_LPIN
fc7f:0 | fc7f | da ; DEC C
fc80:0 | fc80 | d0 f6 ; BNE SCROLLUP_LPOUT
fc82:0 | fc82 | 86 00 ; STX CURSORPOS
fc84:0 | fc84 | a9 00 ; LDA #$00
fc86:0 | fc86 | ab 40 ; LDB #SCREEN_WIDTH
fc88:0 | fc88 | ; SCROLLUP_LPC:
fc88:0 | fc88 | c1 ; STA X+
fc89:0 | fc89 | de ; DEC B
fc8a:0 | fc8a | d0 fc ; BNE SCROLLUP_LPC
fc8c:0 | fc8c | 3c ; PLC
fc8d:0 | fc8d | 7c ; PLB
fc8e:0 | fc8e | 68 ; PLA
fc8f:0 | fc8f | 34 ; PLY
fc90:0 | fc90 | 98 ab ; BRA PRINTCHAR_RETURN
fc92:0 | fc92 | ; PRINTSTRING:
fc92:0 | fc92 | 48 ; PHA
fc93:0 | fc93 | 54 ; PHX
fc94:0 | fc94 | ; PRINTSTRING_LOOP:
fc94:0 | fc94 | e1 ; LDA X+
fc95:0 | fc95 | f0 05 ; BEQ PRINTSTRING_DONE
fc97:0 | fc97 | 20 fc 20 ; JSR PRINTCHAR
fc9a:0 | fc9a | 98 f8 ; BRA PRINTSTRING_LOOP
fc9c:0 | fc9c | ; PRINTSTRING_DONE:
fc9c:0 | fc9c | 74 ; PLX
fc9d:0 | fc9d | 68 ; PLA
fc9e:0 | fc9e | 60 ; RTS
fc9f:0 | fc9f | ; PRINTHEX:
fc9f:0 | fc9f | 60 ; RTS
fca0:0 | fca0 | ; CLEARSCREEN:
fca0:0 | fca0 | 54 ; PHX
fca1:0 | fca1 | 14 ; PHY
fca2:0 | fca2 | 48 ; PHA
fca3:0 | fca3 | 5c ; PHB
fca4:0 | fca4 | 1c ; PHC
fca5:0 | fca5 | aa c0 00 ; LDX #SCREEN_CHAR
fca8:0 | fca8 | a8 c8 00 ; LDY #SCREEN_COLOR
fcab:0 | fcab | a9 10 ; LDA #SCREEN_HEIGHT
fcad:0 | fcad | 85 00 ; STA CURSORPOS
fcaf:0 | fcaf | a9 00 ; LDA #0
fcb1:0 | fcb1 | ab 26 ; LDB #SCREEN_BLACK
fcb3:0 | fcb3 | ; CLSLPOUT:
fcb3:0 | fcb3 | 2b 40 ; LDC #SCREEN_WIDTH
fcb5:0 | fcb5 | ; CLSLPIN:
fcb5:0 | fcb5 | c1 ; STA X+
fcb6:0 | fcb6 | d3 ; STB Y+
fcb7:0 | fcb7 | da ; DEC C
fcb8:0 | fcb8 | d0 fb ; BNE CLSLPIN
fcba:0 | fcba | c6 00 ; DEC CURSORPOS
fcbc:0 | fcbc | d0 f5 ; BNE CLSLPOUT
fcbe:0 | fcbe | aa c0 00 ; LDX #SCREEN_CHAR
fcc1:0 | fcc1 | 86 00 ; STX CURSORPOS
fcc3:0 | fcc3 | 3c ; PLC
fcc4:0 | fcc4 | 7c ; PLB
fcc5:0 | fcc5 | 68 ; PLA
fcc6:0 | fcc6 | 34 ; PLY
fcc7:0 | fcc7 | 74 ; PLX
fcc8:0 | fcc8 | 60 ; RTS
fcc9:0 | fcc9 | ; WAITKEY:
fcc9:0 | fcc9 | 20 fd 8e ; JSR SLEEP
fccc:0 | fccc | ; GETKEY:
fccc:0 | fccc | ed f1 00 ; LDA KEYBOARD
fccf:0 | fccf | f0 f8 ; BEQ WAITKEY
fcd1:0 | fcd1 | 60 ; RTS
fcd2:0 | fcd2 | ; KEY_SYMBOLS:
fcd2:0 | fcd2 | 30 30 29 31 31 21 32 32 40 33 33 23 34 34 24 35 35 25 36 36 5e 37 37 26 38 38 2a 39 39 28 ; "00)11!22@33#44$55%66^77&88*99("
fcf0:0 | fcf0 | 18 3b 3a 19 3d 2b 1a 2c 3c 1b 2e 3e 1c 2d 5f 1d 2f 3f 1e 60 7e ; "\x18;:\x19=+\x1A,<\x1B.>\x1C-_\x1D/?\x1E`~"
fd05:0 | fd05 | 3c 5b 7b 3d 5c 7c 3e 5d 7d 3f 27 22 ; "\x3C[{\x3D\\|\x3E]}\x3F'\x22"
fd11:0 | fd11 | 0d 0a 0a ; "\x0d\x0A\x0A"
fd14:0 | fd14 | 20 20 20 08 08 08 ; " \x08\x08\x08"
fd1a:0 | fd1a | 00 ; "\0"
fd1b:0 | fd1b | ; GETCHAR:
fd1b:0 | fd1b | 5c ; PHB
fd1c:0 | fd1c | ; GETCHAR_RESTART:
fd1c:0 | fd1c | 20 fc cc ; JSR GETKEY
fd1f:0 | fd1f | b7 ; TAB
fd20:0 | fd20 | 29 7b ; AND #$7B
fd22:0 | fd22 | c9 10 ; CMP #$10
fd24:0 | fd24 | f0 2c ; BEQ SHIFTKEY
fd26:0 | fd26 | 97 ; TBA
fd27:0 | fd27 | c9 80 ; CMP #$80
fd29:0 | fd29 | 90 f1 ; BLT GETCHAR_RESTART
fd2b:0 | fd2b | 29 7f ; AND #$7F
fd2d:0 | fd2d | c9 41 ; CMP #$41
fd2f:0 | fd2f | 90 04 ; BLT NOT_LETTER
fd31:0 | fd31 | c9 5a ; CMP #$5A
fd33:0 | fd33 | 10 1b ; BLE GETCHAR_RETURN
fd35:0 | fd35 | ; NOT_LETTER:
fd35:0 | fd35 | 54 ; PHX
fd36:0 | fd36 | aa fc d2 ; LDX #KEY_SYMBOLS
fd39:0 | fd39 | ; KEY_SYM_LP:
fd39:0 | fd39 | e3 ; LDB X+
fd3a:0 | fd3a | f0 11 ; BEQ KEY_SYM_DONE
fd3c:0 | fd3c | ; KEY_SYM_CONTINUE:
fd3c:0 | fd3c | dd ; CMP B
fd3d:0 | fd3d | f0 04 ; BEQ KEY_SYM_MATCH
fd3f:0 | fd3f | e8 02 ; ADX #2
fd41:0 | fd41 | 98 f6 ; BRA KEY_SYM_LP
fd43:0 | fd43 | ; KEY_SYM_MATCH:
fd43:0 | fd43 | a7 02 ; LDB SHIFTDOWN
fd45:0 | fd45 | f0 02 ; BEQ KEY_SYM_NOSHIFT
fd47:0 | fd47 | e8 01 ; ADX #1
fd49:0 | fd49 | ; KEY_SYM_NOSHIFT:
fd49:0 | fd49 | a1 ; LDA X
fd4a:0 | fd4a | 74 ; PLX
fd4b:0 | fd4b | 98 03 ; BRA GETCHAR_RETURN
fd4d:0 | fd4d | ; KEY_SYM_DONE:
fd4d:0 | fd4d | 74 ; PLX
fd4e:0 | fd4e | 98 cc ; BRA GETCHAR_RESTART
fd50:0 | fd50 | ; GETCHAR_RETURN:
fd50:0 | fd50 | 7c ; PLB
fd51:0 | fd51 | 60 ; RTS
fd52:0 | fd52 | ; SHIFTKEY:
fd52:0 | fd52 | 97 ; TBA
fd53:0 | fd53 | 29 80 ; AND #$80
fd55:0 | fd55 | 85 02 ; STA SHIFTDOWN
fd57:0 | fd57 | 98 c3 ; BRA GETCHAR_RESTART
fd59:0 | fd59 | ; GETSTRING:
fd59:0 | fd59 | 48 ; PHA
fd5a:0 | fd5a | 54 ; PHX
fd5b:0 | fd5b | ; GETSTRING_LOOP:
fd5b:0 | fd5b | 20 fd 1b ; JSR GETCHAR
fd5e:0 | fd5e | 20 fc 20 ; JSR PRINTCHAR
fd61:0 | fd61 | c1 ; STA X+
fd62:0 | fd62 | c9 08 ; CMP #$08
fd64:0 | fd64 | d0 02 ; BNE GETSTRING_NOBK
fd66:0 | fd66 | e8 fe ; ADX #-2
fd68:0 | fd68 | ; GETSTRING_NOBK:
fd68:0 | fd68 | c9 0a ; CMP #$0A
fd6a:0 | fd6a | d0 ef ; BNE GETSTRING_LOOP
fd6c:0 | fd6c | e8 ff ; ADX #-1
fd6e:0 | fd6e | a9 00 ; LDA #$00
fd70:0 | fd70 | 81 ; STA X
fd71:0 | fd71 | 74 ; PLX
fd72:0 | fd72 | 68 ; PLA
fd73:0 | fd73 | 60 ; RTS
fd74:0 | fd74 | ; STRCMP:
fd74:0 | fd74 | 54 ; PHX
fd75:0 | fd75 | 14 ; PHY
fd76:0 | fd76 | 48 ; PHA
fd77:0 | fd77 | 5c ; PHB
fd78:0 | fd78 | ; STRCMP_NEXTCHAR:
fd78:0 | fd78 | e1 ; LDA X+
fd79:0 | fd79 | f0 08 ; BEQ STRCMP_XOVER
fd7b:0 | fd7b | f3 ; LDB Y+
fd7c:0 | fd7c | f0 08 ; BEQ STRCMP_YOVER
fd7e:0 | fd7e | dd ; CMP B
fd7f:0 | fd7f | f0 f7 ; BEQ STRCMP_NEXTCHAR
fd81:0 | fd81 | 98 06 ; BRA STRCMP_RETURN
fd83:0 | fd83 | ; STRCMP_XOVER:
fd83:0 | fd83 | b1 ; LDA Y
fd84:0 | fd84 | 98 03 ; BRA STRCMP_RETURN
fd86:0 | fd86 | ; STRCMP_YOVER:
fd86:0 | fd86 | e8 ff ; ADX #-1
fd88:0 | fd88 | a1 ; LDA X
fd89:0 | fd89 | ; STRCMP_RETURN:
fd89:0 | fd89 | 7c ; PLB
fd8a:0 | fd8a | 68 ; PLA
fd8b:0 | fd8b | 34 ; PLY
fd8c:0 | fd8c | 74 ; PLX
fd8d:0 | fd8d | 60 ; RTS
fd8e:0 | fd8e | ; SLEEP:
fd8e:0 | fd8e | cd f0 05 ; STA TIMER
fd91:0 | fd91 | 18 ; HLT
fd92:0 | fd92 | 60 ; RTS
fd93:0 | fd93 | ; STR_HI:
fd93:0 | fd93 | 48 49 00 ; "HI\0"
fd96:0 | fd96 | ; STR_HIRES:
fd96:0 | fd96 | 48 45 4c 4c 4f 21 0a 00 ; "HELLO!\n\0"
fd9e:0 | fd9e | ; RESET:
fd9e:0 | fd9e | 20 fc a0 ; JSR CLEARSCREEN
fda1:0 | fda1 | 58 ; CLI
fda2:0 | fda2 | ; INPUTLP:
fda2:0 | fda2 | aa 02 00 ; LDX #$0200
fda5:0 | fda5 | 20 fd 59 ; JSR GETSTRING
fda8:0 | fda8 | a8 fd 93 ; LDY #STR_HI
fdab:0 | fdab | 20 fd 74 ; JSR STRCMP
fdae:0 | fdae | d0 f2 ; BNE INPUTLP
fdb0:0 | fdb0 | aa fd 96 ; LDX #STR_HIRES
fdb3:0 | fdb3 | 20 fc 92 ; JSR PRINTSTRING
fdb6:0 | fdb6 | 98 ea ; BRA INPUTLP
fdb8:0 | fdb8 | 18 ; HLT
fdb9:0 | fdb9 | 41 ; RST
fdba:0 | fdba | ; INTERRUPT:
fdba:0 | fdba | 38 ; RUN
fdbb:0 | fdbb | 40 ; RTI
fffc:0 | fffc | fd 9e ; RESET
fffe:0 | fffe | fd ba ; INTERRUPT

View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Binary file not shown.

BIN
emulator/third-party/love/OpenAL32.dll vendored Normal file

Binary file not shown.

BIN
emulator/third-party/love/SDL2.dll vendored Normal file

Binary file not shown.

1440
emulator/third-party/love/changes.txt vendored Normal file

File diff suppressed because it is too large Load Diff

BIN
emulator/third-party/love/game.ico vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 KiB

1355
emulator/third-party/love/license.txt vendored Normal file

File diff suppressed because it is too large Load Diff

BIN
emulator/third-party/love/love.dll vendored Normal file

Binary file not shown.

BIN
emulator/third-party/love/love.exe vendored Normal file

Binary file not shown.

BIN
emulator/third-party/love/love.ico vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 KiB

BIN
emulator/third-party/love/lovec.exe vendored Normal file

Binary file not shown.

BIN
emulator/third-party/love/lua51.dll vendored Normal file

Binary file not shown.

BIN
emulator/third-party/love/mpg123.dll vendored Normal file

Binary file not shown.

BIN
emulator/third-party/love/msvcp120.dll vendored Normal file

Binary file not shown.

BIN
emulator/third-party/love/msvcr120.dll vendored Normal file

Binary file not shown.

111
emulator/third-party/love/readme.txt vendored Normal file
View File

@ -0,0 +1,111 @@
LÖVE is an *awesome* framework you can use to make 2D games in Lua. It's free, open-source, and works on Windows, macOS, Linux, Android, and iOS.
[![Build Status: Windows](https://ci.appveyor.com/api/projects/status/chc0hdr08wv1d5c7?svg=true)](https://ci.appveyor.com/project/slime73/love)
[![Build Status: Github CI](https://github.com/love2d/love/workflows/continuous-integration/badge.svg)](https://github.com/love2d/love/actions?query=workflow%3Acontinuous-integration)
Documentation
-------------
We use our [wiki][wiki] for documentation.
If you need further help, feel free to ask on our [forums][forums], our [Discord server][discord], or our [subreddit][subreddit].
Repository
----------
We use the 'main' branch for patch development of the current major release, and therefore it should not be considered stable.
There may also be a branch for the next major version in development, which is named after that version.
We tag all our releases (since we started using mercurial and git), and have binary downloads available for them.
Experimental changes are developed in a separate [love-experiments][love-experiments] repository.
Builds
------
Files for releases are in the [releases][releases] section on GitHub. [The site][site] has links to files and additional platform content for the latest release.
There are also unstable/nightly builds:
- Builds for some platforms are automatically created after each commit and are available through GitHub's CI interfaces.
- For ubuntu linux they are in [ppa:bartbes/love-unstable][unstableppa]
- For arch linux there's [love-git][aur] in the AUR.
Contributing
------------
The best places to contribute are through the issue tracker and the official Discord server or IRC channel.
For code contributions, pull requests and patches are welcome. Be sure to read the [source code style guide][codestyle].
Changes and new features typically get discussed in the issue tracker or on Discord or the forums before a pull request is made.
Compilation
-----------
### Windows
Follow the instructions at the [megasource][megasource] repository page.
### *nix
Run `platform/unix/automagic` from the repository root, then run ./configure and make.
$ platform/unix/automagic
$ ./configure
$ make
When using a source release, automagic has already been run, and the first step can be skipped.
### macOS
Download or clone [this repository][dependencies-apple] and copy, move, or symlink the `macOS/Frameworks` subfolder into love's `platform/xcode/macosx` folder.
Then use the Xcode project found at `platform/xcode/love.xcodeproj` to build the `love-macosx` target.
### iOS
Building for iOS requires macOS and Xcode.
#### LÖVE 11.4 and newer
Download the `love-apple-dependencies` zip file corresponding to the LÖVE version being used from the [Releases page][dependencies-ios],
unzip it, and place the `iOS/libraries` subfolder into love's `platform/xcode/ios` folder.
Or, download or clone [this repository][dependencies-apple] and copy, move, or symlink the `iOS/libraries` subfolder into love's `platform/xcode/ios` folder.
Then use the Xcode project found at `platform/xcode/love.xcodeproj` to build the `love-ios` target.
See `readme-iOS.rtf` for more information.
#### LÖVE 11.3 and older
Download the `ios-libraries` zip file corresponding to the LÖVE version being used from the [Releases page][dependencies-ios],
unzip it, and place the `include` and `libraries` subfolders into love's `platform/xcode/ios` folder.
Then use the Xcode project found at `platform/xcode/love.xcodeproj` to build the `love-ios` target.
See `readme-iOS.rtf` for more information.
### Android
Visit the [Android build repository][android-repository] for build instructions.
Dependencies
------------
- SDL2
- OpenGL 2.1+ / OpenGL ES 2+
- OpenAL
- Lua / LuaJIT / LLVM-lua
- FreeType
- ModPlug
- mpg123
- Vorbisfile
- Theora
[site]: https://love2d.org
[wiki]: https://love2d.org/wiki
[forums]: https://love2d.org/forums
[discord]: https://discord.gg/rhUets9
[subreddit]: https://www.reddit.com/r/love2d
[dependencies-apple]: https://github.com/love2d/love-apple-dependencies
[dependencies-ios]: https://github.com/love2d/love/releases
[megasource]: https://github.com/love2d/megasource
[unstableppa]: https://launchpad.net/~bartbes/+archive/love-unstable
[aur]: https://aur.archlinux.org/packages/love-git
[love-experiments]: https://github.com/slime73/love-experiments
[codestyle]: https://love2d.org/wiki/Code_Style
[android-repository]: https://github.com/love2d/love-android
[releases]: https://github.com/love2d/love/releases

View File

@ -1,30 +0,0 @@
.include _hwdefs.asm
.include _clrdefs.asm
;; Variables
.org SYSRAM
stack: byte[128]
;; Main
.org SYSROM
lds stack
jss cls
hlt
;; Clear the screen
FUNC cls:
ldp screen.char
ldc $00 ;; Blank
ldq screen.color
ldb CLR_BLACK ;; Black
.cls_loop: {
stc *p++
stb *q++
lda pl
cmp (lo(COLOR))
jnz .cls_loop
lda ph
cmp (hi(COLOR))
jnz }
rts

View File

@ -1,8 +0,0 @@
lda 1
ldb 0
fib_loop:
ldc b
ldb a
add c
jlt fib_loop ; Stop when carry flag is set

View File

@ -1,50 +0,0 @@
.include _hwdefs.asm
.include _clrdefs.asm
;; Defines
.define VARS $0100
;; Variables
.org SYSRAM
stack: byte[128]
.org VARS
hello_str: "Hello world!\0"
;; Main
.org SYSROM
lds stack
jss cls
ldp screen.char
ldq hello_str
jss print
hlt
;; Clear the screen
FUNC cls:
ldp screen.char
ldc $00 ;; Blank
ldq screen.color
ldb CLR_BLACK ;; Black
.cls_loop: {
stc *p++
stb *q++
lda pl
cmp (lo(COLOR))
jnz .cls_loop
lda ph
cmp (hi(COLOR))
jnz }
rts
;; Print string (Q) to the current screen cursor (P)
FUNC print:
lda *q++
jpz .print_end
sta *p++
jmp print
.print_end:
rts

View File

@ -1,16 +0,0 @@
.org $0100 ; Static data
hello_str:
"Hello world\0"
.org $0000 ; Program must start at $0000
ldp $0800 ; Char display
ldq hello_str
print:
lda *q++
jpz print_end
sta *p++
jmp print
print_end:
hlt

View File

@ -1,8 +0,0 @@
; This program adds 1 to register A until it equals 64, then halts.
loop:
inc a
cmp 64
jnz loop
hlt

296
generate-architecture.lua Normal file
View File

@ -0,0 +1,296 @@
-- generate-architecture.lua
-- This program uses the definitions in 8610-definition.lua to generate the assembler definitions, instruction list, and microcode.
-- Also see 8610-definition.lua
local debugInfo = {}
local function getDebugInfo()
return " ("..debugInfo.mnem.." sub "..debugInfo.sub..")"
end
local function hex(n) return string.format("%02X", n) end
local function cycleAddSignals(cycle, cyc2, cyc2t, ops, sigs, opsUsed, sigsUsed)
for _, name in ipairs(cycle) do
if ops[name] then
opsUsed[name] = true
cycleAddSignals(ops[name], cyc2, cyc2t, ops, sigs, opsUsed, sigsUsed)
elseif sigs[name] then
sigsUsed[name] = true
if not cyc2t[name] then
cyc2t[name] = true
table.insert(cyc2, name)
else
error("overspecified signal name: "..name..getDebugInfo())
end
else
error("invalid signal name: "..name.." does not name a signal or operation")
end
end
end
local function cycleSimplify(cycle, ops, sigs, opsUsed, sigsUsed)
local cyc2, cyc2t = {}, {}
cycleAddSignals(cycle, cyc2, cyc2t, ops, sigs, opsUsed, sigsUsed)
return cyc2
end
local function cycleToUcycle(cycle, ops, sigs, opsUsed, sigsUsed)
local ucycle = {}
local cyc2 = cycleSimplify(cycle, ops, sigs, opsUsed, sigsUsed)
local nonempty = false
for _, name in ipairs(cyc2) do
nonempty = true
local sig = sigs[name]
assert(sig, "no signal named "..name)
for i, sbit in ipairs(sig) do
ucycle[sbit.rom] = ucycle[sbit.rom] or {}
assert(not ucycle[sbit.rom][sbit.bit], "multiply defined bit")
ucycle[sbit.rom][sbit.bit] = true
end
end
return ucycle
end
local function encodeInstruction(opcode, instr, ucode, ops, sigs, opsUsed, sigsUsed)
for sub, cycle in ipairs(instr) do
debugInfo.sub = sub-1
local ucycle = cycleToUcycle(cycle, ops, sigs, opsUsed, sigsUsed)
local uaddr = opcode*4 + (sub-1)
assert(not ucode[uaddr], "overused ucode addr "..uaddr)
ucode[uaddr] = ucycle
end
end
local function sigsFromRoms(roms)
local sigs = {}
for romidx, rom in ipairs(roms) do
for sigidx, sig in ipairs(rom.signals) do
sigs[sig] = sigs[sig] or {}
table.insert(sigs[sig], {
rom = romidx,
bit = sigidx-1,
})
end
end
return sigs
end
local subruleDefs = [[
#subruledef rel8 {
{addr} => {
reladdr = addr - $ - 2
assert(reladdr <= 127, "Relative jump target is too far away")
assert(reladdr >= -128, "Relative jump target is too far away")
reladdr`8
}
}
#subruledef neg8 {
{value} => {
mvalue = -value
mvalue`8
}
}]]
local function getAsmCode(mnem, instr)
local opcodeS = string.format("$%02X", instr.opcode)
local mnemPreImm = mnem
mnem = mnem:gsub("imm8rel", "{value: rel8}")
mnem = mnem:gsub("imm8neg", "{value: neg8}")
mnem = mnem:gsub("imm8s" , "{value: s8}")
mnem = mnem:gsub("imm8u" , "{value: u8}")
mnem = mnem:gsub("imm8" , "{value: i8}" )
mnem = mnem:gsub("imm16" , "{value: i16}" )
if mnem == mnemPreImm then
return mnem.." => "..opcodeS
else
return mnem.." => "..opcodeS.." @ value"
end
end
local function getAsmsFromInstr(mnem, instr, aliases)
local t = {}
table.insert(t, getAsmCode(mnem, instr))
if aliases and aliases[mnem] then
for _, mnem2 in ipairs(aliases[mnem]) do
table.insert(t, getAsmCode(mnem2, instr))
end
end
return t
end
local function transformDescription(arch, desc)
if arch.descShortcuts then
for _, sc in ipairs(arch.descShortcuts) do
pat, rep = unpack(sc)
pat = pat:gsub("%%", "%%%%")
desc = desc:gsub(pat, rep)
end
end
return desc
end
local function printUnusedThing(thing, all, used)
for name, _ in pairs(all) do
if not used[name] then
print("Unused "..thing..": "..name)
end
end
end
local function printUnused(ops, sigs, opsUsed, sigsUsed)
printUnusedThing("Macro-operation", ops, opsUsed)
printUnusedThing("Control Signal", sigs, sigsUsed)
end
local asmDataStr = [[
%s
#ruledef {
%s
}
]]
local function archToUcode(arch, writeFiles)
local sigs = sigsFromRoms(arch.roms)
local ops = arch.operations
local sigsUsed = {}
local opsUsed = {}
local ucode = {}
local opcodesUsed = {}
local numOpcodesUsed = 0
local infolines = {}
local asmlines = {}
local catlet = "X"
for _, instr in ipairs(arch.instructions) do
if instr.category or instr.catlet then
assert(instr.catlet, "category header has no catlet")
catlet = instr.catlet
if instr.category then
assert(not instr.mnem, "mnem in category header")
assert(not instr.opcode, "opcode in category header")
table.insert(infolines, "\n")
table.insert(infolines, instr.category.." ("..catlet.."):\n")
end
else
local mnem = instr.mnem or error("instr has no mnem")
local opcode = instr.opcode or error("instr has no opcode "..mnem)
local ncycles = instr.ncycles or #instr
assert(#instr <= 8, "operation too long "..opcode)
local len = math.ceil(#instr / 4)
if len>1 then assert(opcode%2==0, "len>1 on odd opcode") end
for i = 1, len do
local opcode2 = opcode+i-1
if opcodesUsed[opcode2] then
local other = opcodesUsed[opcode2]
error("overused opcode "..hex(opcode2)..": "..mnem.." part "..i.." overwrites "..other[2].." part "..other[3])
end
opcodesUsed[opcode2] = {catlet, mnem, i}
numOpcodesUsed = numOpcodesUsed+1
end
debugInfo.mnem = mnem
encodeInstruction(opcode, instr, ucode, ops, sigs, opsUsed, sigsUsed)
if instr.desc then
local desc = transformDescription(arch, instr.desc)
table.insert(infolines, mnem..(" "):rep(13-#mnem)..hex(opcode).." "..ncycles.." "..desc.."\n")
local mnem2 = arch.transformMnemonic and arch.transformMnemonic(mnem) or mnem
local asms = getAsmsFromInstr(mnem2, instr, arch.aliases)
for _, a in ipairs(asms) do table.insert(asmlines, a) end
end
end
end
printUnused(ops, sigs, opsUsed, sigsUsed)
local lt = {"Opcodes used: "..numOpcodesUsed.."/256\n", " "}
for i = 0, 15 do table.insert(lt, hex(i):sub(2, 2)) end
table.insert(lt, "\n")
for line = 0, 255, 16 do
table.insert(lt, hex(line).." | ")
for opcode = line, line+15 do
if opcodesUsed[opcode] then table.insert(lt, opcodesUsed[opcode][1])
else table.insert(lt, "-") end
end
table.insert(lt, "\n")
end
if writeFiles then
-- Output instruction list
local info = arch.instructionListHeader..table.concat(infolines).."\n"..table.concat(lt)
--print(info)
local fo = io.open(arch.instructionListFile, "w")
if fo then
fo:write(info)
fo:close()
else
print("Could not open \""..arch.instructionListFile.."\" for write")
end
-- Output customASM definitions
local asmTable = arch.assemblerDefsHeader..string.format(asmDataStr,
subruleDefs,
table.concat(asmlines, "\n\t")
)
local fo = io.open(arch.assemblerDefsFile, "w")
if fo then
fo:write(asmTable)
fo:close()
else
print("Could not open \""..arch.assemblerDefsFile.."\" for write")
end
end
return ucode
end
local function ucodeToBricks(ucode, roms)
local bricks = {}
for uaddr, ucycle in pairs(ucode) do
for romidx, uline in ipairs(ucycle) do
for bitidx, t in pairs(uline) do
local rom = roms[romidx]
assert(bitidx >=0 and bitidx <= rom.size[3]-1)
local x = rom.pos[1] + (uaddr % rom.size[1])
local y = rom.pos[2] - math.floor(uaddr / rom.size[1])
local z = rom.pos[3] + bitidx
bricks[x] = bricks[x] or {}
bricks[x][y] = bricks[x][y] or {}
assert(not bricks[x][y][z], "overlapping brick at "..x.." "..y.." "..z)
bricks[x][y][z] = true
end
end
end
return bricks
end
ts = ts or {
eval = function() end,
call = function() end,
}
ts.eval [[
function commandShiftBrick(%x, %y, %z) { commandToServer('shiftBrick', %x, %y, %z); }
function commandPlantBrick() { commandToServer('plantBrick'); }
]]
local function plantBrickAt(pos, brickPos)
local dx, dy, dz = pos[1]-brickPos[1], pos[2]-brickPos[2], pos[3]-brickPos[3]
ts.call("commandShiftBrick", dy, -dx, dz)
brickPos[1] = pos[1]; brickPos[2] = pos[2]; brickPos[3] = pos[3];
ts.call("commandPlantBrick")
end
local function buildBricks(bricks)
local brickPos = {0, 0, 0}
for x, xb in pairs(bricks) do
for y, xyb in pairs(xb) do
for z, t in pairs(xyb) do
plantBrickAt({x, y, z}, brickPos)
end
end
end
end
local function generateArchitecture(arch, writeFiles, build)
local ucode = archToUcode(arch, writeFiles)
if build then
local bricks = ucodeToBricks(ucode, arch.roms)
buildBricks(bricks)
end
end
return generateArchitecture

1
getting-started.md Normal file
View File

@ -0,0 +1 @@
WIP

BIN
instruction-map.ods Normal file

Binary file not shown.

View File

@ -1,260 +1,227 @@
instructionList.txt
List of all instructions in the 8608 architecture.
Instructions are encoded as the opcode, followed by any immediate values.
16-bit immediates are encoded in big-endian byte order.
Each instruction is described in order of: Mnemonic, Opcode, Clock cycles, Description
Control (C):
rst 00 1 Clear all registers and set I=0
hlt F0 1 Halt non-interrupt execution
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
RST 41 3 Clear all registers and flags, load the Program Counter from memory addresses $FFFC-$FFFD, and execute the code at the address given by those bytes
BRK 00 3 Trigger an interrupt from software, saving the current Program Counter in the V register and jumping to the Interrupt Vector stored at memory addresses $FFFE-$FFFF
RTI 40 1 Return from an interrupt, resuming normal execution where it left off when the interrupt occurred
NOP EA 1 Do nothing
CLI 58 1 Enable interrupts to be triggered by external hardware
SEI 78 1 Disable interrupts being triggered by external hardware
HLT 18 1 Clear the Run Flag, preventing the CPU from running until an interrupt is triggered
RUN 38 1 Set the Run Flag, allowing the CPU to run once the current interrupt finishes
16-bit Inc/Dec (I):
inc p 12 1 P++
dec p 15 1 P--
inc q 13 1 Q++
dec q 16 1 Q--
8-bit Unary Arithmetic (U):
INC A F6 1 Increment the A register, and set the Carry Flag and Zero Flag according to the result
DEC A D6 1 Decrement the A register, and set the Carry Flag and Zero Flag according to the result
ICC A 57 1 Add the Carry Flag to the A register, and set the Carry Flag and Zero Flag according to the result
INC B FE 1 Increment the B register, and set the Carry Flag and Zero Flag according to the result
DEC B DE 1 Decrement the B register, and set the Carry Flag and Zero Flag according to the result
ICC B 5F 1 Add the Carry Flag to the B register, and set the Carry Flag and Zero Flag according to the result
INC C FA 1 Increment the C register, and set the Carry Flag and Zero Flag according to the result
DEC C DA 1 Decrement the C register, and set the Carry Flag and Zero Flag according to the result
ICC C 5B 1 Add the Carry Flag to the C register, and set the Carry Flag and Zero Flag according to the result
INC zpg E6 4 Increment the value at an given 8-bit address, and set the Carry Flag and Zero Flag according to the result
DEC zpg C6 4 Decrement the value at an given 8-bit address, and set the Carry Flag and Zero Flag according to the result
ICC zpg 47 4 Add the Carrry Flag to the value at an given 8-bit address, and set the Carry Flag and Zero Flag according to the result
8-bit Unary (U):
inc a 10 1 A++, set flags
dec a 11 1 A--, set flags
icc a 1B 1 A+=CF, set flags
inc b 19 1 B++, set flags
dec b 1A 1 B--, set flags
icc b 1C 1 B+=CF, set flags
inc c 17 1 C++, set flags
dec c 18 1 C--, set flags
icc c 1D 1 C+=CF, set flags
tst a 14 1 Set flags according to A-0
tst b 1E 1 Set flags according to B-0
tst c 1F 1 Set flags according to C-0
inc *s+imm8 2B 4 *(S+imm8)++, set flags
dec *s+imm8 2C 4 *(S+imm8)--, set flags
icc *s+imm8 2D 4 *(S+imm8)+=CF, set flags
tst *s+imm8 2E 3 Set flags according to *(S+imm8)-0
8-bit Arithmetic and Logic (A):
ADD # 6B 2 Add a given 8-bit value to the value in the A register, and set the Carry Flag and Zero Flag according to the result
SUB # EB 2 Subtract a given 8-bit value from the value in the A register, and set the Carry Flag and Zero Flag according to the result
ADC # 69 2 Add a given 8-bit value plus the Carry Flag to the value in the A register, and set the Carry Flag and Zero Flag according to the result
SBC # E9 2 Subtract a given 8-bit value from the value in the A register including the Carry Flag, and set the Carry Flag and Zero Flag according to the result
CMP # C9 2 Set the Carry Flag and Zero Flag according to the result of subtracting a given 8-bit value from the value in the A register
AND # 29 2 Bitwise AND the value in the A register with a given 8-bit value, and set the Zero Flag according to the result
ORA # 09 2 Bitwise OR the value in the A register with a given 8-bit value, and set the Zero Flag according to the result
EOR # 49 2 Bitwise Exclusive OR the value in the A register with a given 8-bit value, and set the Zero Flag according to the result
ASL # 15 2 Bit-shift the value in the A register left by a given number of bits, and set the Zero Flag according to the result
LSR # 55 2 Bit-shift the value in the A register right by a given number of bits, and set the Zero Flag according to the result
ROL # 35 2 Bit-rotate the value in the A register left by a given number of bits, and set the Zero Flag according to the result
ROR # 75 2 Bit-rotate the value in the A register right by a given number of bits, and set the Zero Flag according to the result
ADD zpg 67 3 Add the value in memory at a given 8-bit address to the value in the A register, and set the Carry Flag and Zero Flag according to the result
SUB zpg E7 3 Subtract the value in memory at a given 8-bit address from the value in the A register, and set the Carry Flag and Zero Flag according to the result
ADC zpg 65 3 Add the value in memory at a given 8-bit address plus the Carry Flag to the value in the A register, and set the Carry Flag and Zero Flag according to the result
SBC zpg E5 3 Subtract the value in memory at a given 8-bit address from the value in the A register including the Carry Flag, and set the Carry Flag and Zero Flag according to the result
CMP zpg C5 3 Set the Carry Flag and Zero Flag according to the result of subtracting the value in memory at a given 8-bit address from the value in the A register
AND zpg 25 3 Bitwise AND the value in the A register with the value in memory at a given 8-bit address, and set the Carry Flag and Zero Flag according to the result
ORA zpg 05 3 Bitwise OR the value in the A register with the value in memory at a given 8-bit address, and set the Carry Flag and Zero Flag according to the result
EOR zpg 45 3 Bitwise Exclusive OR the value in the A register with the value in memory at a given 8-bit address, and set the Carry Flag and Zero Flag according to the result
ADD B 7F 1 Add the value in the B register to the value in the A register, and set the Carry Flag and Zero Flag according to the result
SUB B FF 1 Subtract the value in the B register from the value in the A register, and set the Carry Flag and Zero Flag according to the result
ADC B 7D 1 Add the value in the B register plus the Carry Flag to the value in the A register, and set the Carry Flag and Zero Flag according to the result
SBC B FD 1 Subtract the value in the B register form the value in the A register including the Carry Flag, and set the Carry Flag and Zero Flag according to the result
CMP B DD 1 Set the Carry Flag and Zero Flag according to the result of subtracting the value in the B register from the value in the A register
AND B 3D 1 Bitwise AND the value in the A register with the value in the B register, and set the Carry Flag and Zero Flag according to the result
ORA B 1D 1 Bitwise OR the value in the A register with the value in the B register, and set the Carry Flag and Zero Flag according to the result
EOR B 5D 1 Bitwise Exclusive OR the value in the A register with the value in the B register, and set the Carry Flag and Zero Flag according to the result
ADD C 7B 1 Add the value in the C register to the value in the A register, and set the Carry Flag and Zero Flag according to the result
SUB C FB 1 Subtract the value in the C register from the value in the A register, and set the Carry Flag and Zero Flag according to the result
ADC C 79 1 Add the value in the C register plus the Carry Flag to the value in the A register, and set the Carry Flag and Zero Flag according to the result
SBC C F9 1 Subtract the value in the C register form the value in the A register including the Carry Flag, and set the Carry Flag and Zero Flag according to the result
CMP C D9 1 Set the Carry Flag and Zero Flag according to the result of subtracting the value in the C register from the value in the A register
AND C 39 1 Bitwise AND the value in the A register with the value in the C register, and set the Carry Flag and Zero Flag according to the result
ORA C 19 1 Bitwise OR the value in the A register with the value in the C register, and set the Carry Flag and Zero Flag according to the result
EOR C 59 1 Bitwise Exclusive OR the value in the A register with the value in the C register, and set the Carry Flag and Zero Flag according to the result
Conditional Branches (B):
BNE rel D0 2 If the result of the last math operation was not 0, Add a signed 8-bit offset to the Program Counter, jumping forward or backward in the program; Add a signed 8-bit offset to the Program Counter, jumping forward or backward in the programc
BEQ rel F0 2 If the result of the last math operation was 0, Add a signed 8-bit offset to the Program Counter, jumping forward or backward in the program; Add a signed 8-bit offset to the Program Counter, jumping forward or backward in the programc
BLT rel 90 2 If the result of the last math operation was negative, Add a signed 8-bit offset to the Program Counter, jumping forward or backward in the program; Add a signed 8-bit offset to the Program Counter, jumping forward or backward in the programc
BGE rel B0 2 If the result of the last math operation was positive or 0, Add a signed 8-bit offset to the Program Counter, jumping forward or backward in the program; Add a signed 8-bit offset to the Program Counter, jumping forward or backward in the programc
BGT rel 30 2 If the result of the last math operation was positive, Add a signed 8-bit offset to the Program Counter, jumping forward or backward in the program; Add a signed 8-bit offset to the Program Counter, jumping forward or backward in the programc
BLE rel 10 2 If the result of the last math operation was negative or 0, Add a signed 8-bit offset to the Program Counter, jumping forward or backward in the program; Add a signed 8-bit offset to the Program Counter, jumping forward or backward in the programc
BRA rel 98 2 Add a signed 8-bit offset to the Program Counter, jumping forward or backward in the program
16-bit Arithmetic (X):
adp imm8 4A 2 P+=imm8 signed
adq imm8 4B 2 Q+=imm8 signed
ads imm8 4C 2 S+=imm8 signed
adp b E6 1 P+=B signed
adq b E7 1 Q+=B signed
ads b E8 1 S+=B signed
8-bit Arithmetic/Logic (A):
add imm8 24 2 A+=imm8, set flags
adb imm8 72 2 B+=imm8, set flags
adc imm8 73 2 C+=imm8, set flags
sub imm8 70 2 A-=imm8, set flags
sbb imm8 99 2 B-=imm8, set flags
sbc imm8 9A 2 C-=imm8, set flags
acc imm8 78 2 A+=imm8+CF, set flags
scc imm8 79 2 A-=imm8+CF, set flags
cmp imm8 71 2 set flags according to A-imm8
and imm8 74 2 A&=imm8, set zero flag
ior imm8 75 2 A|=imm8, set zero flag
xor imm8 76 2 A^=imm8, set zero flag
ann imm8 77 2 A&=~imm8, set zero flag
shl imm8 D0 2 A<<=imm8, set zero flag
shr imm8 D1 2 A>>=imm8, set zero flag
rol imm8 D2 2 A<<<=imm8, set zero flag
ror imm8 D3 2 A>>>=imm8, set zero flag
sra imm8 D4 2 A>>a=imm8, set zero flag
add *s+imm8 AE 3 A+=*(S+imm8), set flags
adb *s+imm8 9B 3 B+=*(S+imm8), set flags
adc *s+imm8 9C 3 C+=*(S+imm8), set flags
sub *s+imm8 AF 3 A-=*(S+imm8), set flags
sbb *s+imm8 9D 3 B-=*(S+imm8), set flags
sbc *s+imm8 9E 3 C-=*(S+imm8), set flags
acc *s+imm8 B5 3 A+=*(S+imm8)+CF, set flags
scc *s+imm8 B7 3 A-=*(S+imm8)+CF, set flags
cmp *s+imm8 B0 3 set flags according to A-*(S+imm8)
and *s+imm8 B1 3 A&=*(S+imm8), set zero flag
ior *s+imm8 B2 3 A|=*(S+imm8), set zero flag
xor *s+imm8 B3 3 A^=*(S+imm8), set zero flag
ann *s+imm8 B4 3 A&=~*(S+imm8), set zero flag
shl *s+imm8 D5 3 A<<=*(S+imm8), set zero flag
shr *s+imm8 D6 3 A<<=*(S+imm8), set zero flag
rol *s+imm8 D7 3 A<<<=*(S+imm8), set zero flag
ror *s+imm8 D8 3 A>>>=*(S+imm8), set zero flag
sra *s+imm8 D9 3 A>>a=*(S+imm8), set zero flag
add b A0 1 A+=B, set flags
adc b 9F 1 C+=B, set flags
sub b A1 1 A-=B, set flags
sbc b B6 1 C-=B, set flags
acc b B8 1 A+=B+CF, set flags
scc b B9 1 A-=B+CF, set flags
cmp b A2 1 set flags according to A-B
and b A3 1 A&=B, set zero flag
ior b A4 1 A|=B, set zero flag
xor b A5 1 A^=B, set zero flag
ann b A6 1 A&=~B, set zero flag
shl b DA 1 A<<=B, set zero flag
shr b DB 1 A>>=B, set zero flag
rol b DC 1 A<<<=B, set zero flag
ror b DD 1 A>>>=B, set zero flag
sra b DE 1 A>>a=B, set zero flag
add c A7 1 A+=C, set flags
adb c BD 1 B+=C, set flags
sub c A8 1 A-=C, set flags
sbb c BC 1 B-=C, set flags
acc c BA 1 A+=C+CF, set flags
scc c BB 1 A-=C+CF, set flags
cmp c A9 1 set flags according to A-C
and c AA 1 A&=C, set zero flag
ior c AB 1 A|=C, set zero flag
xor c AC 1 A^=C, set zero flag
ann c AD 1 A&=~C, set zero flag
shl c DF 1 A<<=C, set zero flag
shr c 4D 1 A>>=C, set zero flag
rol c 3E 1 A<<<=C, set zero flag
ror c 3F 1 A>>>=C, set zero flag
sra c 2F 1 A>>a=C, set zero flag
adb a BE 1 B+=A, set flags
sbb a BF 1 B-=A, set flags
adc a 4E 1 C+=A, set flags
sbc a 4F 1 C-=A, set flags
ADX # E8 2 Add a given 8-bit value to the 16-bit X register
ADY # C8 2 Add a given 8-bit value to the 16-bit Y register
ADX ## 8A 3 Add a given 16-bit value to the 16-bit X register
ADY ## 88 3 Add a given 16-bit value to the 16-bit Y register
ADX A FC 1 Add the 8-bit signed value in the A register to the 16-bit X register
ADY A DC 1 Add the 8-bit signed value in the A register to the 16-bit Y register
Jumps (J):
jmp imm16 60 3 I=imm16
jsr imm16 63 3 I=imm16, Q=I
jss imm16 E2 5 I=imm16, *(S++++)=I-1
jmp p 64 1 I=P
jmp q 66 1 I=Q
jsr p 65 1 I=P, Q=I
jsr q 67 1 I=Q, Q=I
jss p E4 3 I=P, *(S++++)=I-1
jss q E5 3 I=Q, *(S++++)=I-1
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
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
JMP abs CC 3 Jump - Set the Program Counter to a given 16-bit value, executing the code at that address
JSR abs 20 5 Jump to Subroutine - Save the Program Counter on the Stack, then set it to a given 16-bit value, executing the code at that address
JMP [ind] 6C 5 Load a subroutine pointer from memory at a given 16-bit address, then jump to that subroutine, saving the return address on the stack.
JSR [ind] 2C 7 Load a code pointer from memory at a given 16-bit address, then jump to that code.
JMP [ind,A] 4C 5 Load a subroutine pointer from memory at a given 16-bit address, then jump to that subroutine, saving the return address on the stack.
JSR [ind,A] 0C 7 Load a code pointer from memory at a given 16-bit address, then jump to that code.
JMP X 64 1 Set the Program Counter to the 16-bit value in the X register, executing the code at that address
JMP Y 44 1 Set the Program Counter to the 16-bit value in the Y register, executing the code at that address
JSR X 24 3 Save the Program Counter on the Stack, then set it to the 16-bit value in the X register, executing the code at that address
JSR Y 04 3 Save the Program Counter on the Stack, then set it to the 16-bit value in the Y register, executing the code at that address
RTS 60 3 Retrieve the Program Counter from the stack, returning to where the last JSR instruction was executed
Stack (S):
psh a 40 2 *(S++)=A
psh b 44 2 *(S++)=B
psh c 45 2 *(S++)=C
psh f E9 2 *(S++)=F
psh p 41 3 *(S++++)=P
psh q 46 3 *(S++++)=Q
pop a 42 2 A=*(--S)
pop b 47 2 B=*(--S)
pop c 48 2 C=*(--S)
pop f EA 2 F=*(--S)
pop p 43 3 P=*(----S)
pop q 49 3 Q=*(----S)
psh imm8 3B 3 *(S++)=imm8
phw imm16 3C 5 *(S++++)=imm16
PHA 48 2 Push the value in the A register onto the Stack
PHB 5C 2 Push the value in the B register onto the Stack
PHC 1C 2 Push the value in the C register onto the Stack
PHP 08 2 Push a byte containing the Carry Flag and Zero Flag onto the Stack
PHX 54 3 Push the 16-bit value in the X register onto the Stack
PHY 14 3 Push the 16-bit value in the Y register onto the Stack
PLA 68 2 Pull a byte from the Stack, and store it in the A register
PLB 7C 2 Pull a byte from the Stack, and store it in the B register
PLC 3C 2 Pull a byte from the Stack, and store it in the C register
PLP 28 2 Pull a byte from the Stack, and use it to set the Carry Flag and Zero flag
PLX 74 3 Pull two bytes from the stack, and store the resulting 16-bit value in the X register
PLY 34 3 Pull two bytes from the stack, and store the resulting 16-bit value in the Y register
8-bit Load/Store (B):
lda imm8 20 2 A=imm8, update zero flag
ldb imm8 26 2 B=imm8, update zero flag
ldc imm8 27 2 C=imm8, update zero flag
lda *s+imm8 28 3 A=*s+imm8, update zero flag
ldb *s+imm8 29 3 B=*s+imm8, update zero flag
ldc *s+imm8 2A 3 C=*s+imm8, update zero flag
sta *s+imm8 96 3 *s+imm8=A
stb *s+imm8 97 3 *s+imm8=B
stc *s+imm8 98 3 *s+imm8=C
lda *imm16 51 4 A=*imm16, update zero flag
ldb *imm16 56 4 B=*imm16, update zero flag
ldc *imm16 57 4 C=*imm16, update zero flag
sta *imm16 50 4 *imm16=A
stb *imm16 58 4 *imm16=B
stc *imm16 59 4 *imm16=C
sta *p 52 2 *P=A
stb *p 5A 2 *P=B
stc *p 5B 2 *P=C
sta *q 54 2 *Q=A
stb *q 5C 2 *Q=B
stc *q 5D 2 *Q=C
lda *p 53 2 A=*P, update zero flag
ldb *p 5E 2 B=*P, update zero flag
ldc *p 5F 2 C=*P, update zero flag
lda *q 55 2 A=*Q, update zero flag
ldb *q 61 2 B=*Q, update zero flag
ldc *q 62 2 C=*Q, update zero flag
sta *p++ C0 2 *P++=A
stb *p++ C1 2 *P++=B
stc *p++ C2 2 *P++=C
sta *q++ C3 2 *Q++=A
stb *q++ C4 2 *Q++=B
stc *q++ C5 2 *Q++=C
lda *p++ C6 2 A=*P++, update zero flag
ldb *p++ C7 2 B=*P++, update zero flag
ldc *p++ C8 2 C=*P++, update zero flag
lda *q++ C9 2 A=*Q++, update zero flag
ldb *q++ CA 2 B=*Q++, update zero flag
ldc *q++ CB 2 C=*Q++, update zero flag
LDA # A9 2 Set the A register to a given 8-bit value
LDB # AB 2 Set the B register to a given 8-bit value
LDC # 2B 2 Set the C register to a given 8-bit value
LDA zpg A5 3 Set the A register to the value in memory at a given 8-bit address, and set the Zero Flag according to the value loaded
LDB zpg A7 3 Set the B register to the value in memory at a given 8-bit address, and set the Zero Flag according to the value loaded
LDC zpg 27 3 Set the C register to the value in memory at a given 8-bit address, and set the Zero Flag according to the value loaded
STA zpg 85 3 Store the value in the A register in memory at an given 8-bit address
STB zpg 87 3 Store the value in the B register in memory at an given 8-bit address
STC zpg 07 3 Store the value in the C register in memory at an given 8-bit address
LDA abs ED 4 Set the A register to the value in memory at a given 16-bit address, and set the Zero Flag according to the value loaded
LDB abs EF 4 Set the B register to the value in memory at a given 16-bit address, and set the Zero Flag according to the value loaded
LDC abs 6F 4 Set the C register to the value in memory at a given 16-bit address, and set the Zero Flag according to the value loaded
STA abs CD 4 Store the value in the A register in memory at a given 16-bit address
STB abs CF 4 Store the value in the B register in memory at a given 16-bit address
STC abs 4F 4 Store the value in the C register in memory at a given 16-bit address
LDA X A1 2 Set the A register to the value in memory at the address in X, and set the Zero Flag according to the value loaded
LDB X A3 2 Set the B register to the value in memory at the address in X, and set the Zero Flag according to the value loaded
LDC X 23 2 Set the C register to the value in memory at the address in X, and set the Zero Flag according to the value loaded
LDA Y B1 2 Set the A register to the value in memory at the address in Y, and set the Zero Flag according to the value loaded
LDB Y B3 2 Set the B register to the value in memory at the address in Y, and set the Zero Flag according to the value loaded
LDC Y 33 2 Set the C register to the value in memory at the address in Y, and set the Zero Flag according to the value loaded
STA X 81 2 Store the value in the A register in memory at the address in X
STB X 83 2 Store the value in the B register in memory at the address in X
STC X 03 2 Store the value in the C register in memory at the address in X
STA Y 91 2 Store the value in the A register in memory at the address in Y
STB Y 93 2 Store the value in the B register in memory at the address in Y
STC Y 13 2 Store the value in the C register in memory at the address in Y
LDA X+ E1 2 Set the A register to the value in memory at the address in X, increment the X register, and set the Zero Flag according to the value loaded
LDB X+ E3 2 Set the B register to the value in memory at the address in X, increment the X register, and set the Zero Flag according to the value loaded
LDC X+ 63 2 Set the C register to the value in memory at the address in X, increment the X register, and set the Zero Flag according to the value loaded
LDA Y+ F1 2 Set the A register to the value in memory at the address in Y, increment the Y register, and set the Zero Flag according to the value loaded
LDB Y+ F3 2 Set the B register to the value in memory at the address in Y, increment the Y register, and set the Zero Flag according to the value loaded
LDC Y+ 73 2 Set the C register to the value in memory at the address in Y, increment the Y register, and set the Zero Flag according to the value loaded
STA X+ C1 2 Store the value in the A register in memory at the address in X, and increment the X register
STB X+ C3 2 Store the value in the B register in memory at the address in X, and increment the X register
STC X+ 43 2 Store the value in the C register in memory at the address in X, and increment the X register
STA Y+ D1 2 Store the value in the A register in memory at the address in Y, and increment the Y register
STB Y+ D3 2 Store the value in the B register in memory at the address in Y, and increment the Y register
STC Y+ 53 2 Store the value in the C register in memory at the address in Y, and increment the Y register
LDA X,ofs BD 3 Set the A register to the value in memory at the address (X plus a given 8-bit offset), and set the Zero Flag according to the value loaded
LDB X,ofs BF 3 Set the B register to the value in memory at the address (X plus a given 8-bit offset), and set the Zero Flag according to the value loaded
LDC X,ofs 3F 3 Set the C register to the value in memory at the address (X plus a given 8-bit offset), and set the Zero Flag according to the value loaded
LDA Y,ofs B9 3 Set the A register to the value in memory at the address (Y plus a given 8-bit offset), and set the Zero Flag according to the value loaded
LDB Y,ofs BB 3 Set the B register to the value in memory at the address (Y plus a given 8-bit offset), and set the Zero Flag according to the value loaded
LDC Y,ofs 3B 3 Set the C register to the value in memory at the address (Y plus a given 8-bit offset), and set the Zero Flag according to the value loaded
STA X,ofs 9D 3 Store the value in the A register in memory at the address (X plus a given 8-bit offset)
STB X,ofs 9F 3 Store the value in the A register in memory at the address (X plus a given 8-bit offset)
STC X,ofs 1F 3 Store the value in the A register in memory at the address (X plus a given 8-bit offset)
STA Y,ofs 99 3 Store the value in the A register in memory at the address (Y plus a given 8-bit offset)
STB Y,ofs 9B 3 Store the value in the A register in memory at the address (Y plus a given 8-bit offset)
STC Y,ofs 1B 3 Store the value in the A register in memory at the address (Y plus a given 8-bit offset)
16-bit Load/Store (W):
ldp imm16 21 3 P=imm16
ldq imm16 23 3 Q=imm16
lds imm16 25 3 S=imm16
ldv imm16 22 3 V=imm16
ldp *s+imm8 7A 4 P=*S+imm8
ldq *s+imm8 7B 4 Q=*S+imm8
stp *s+imm8 7E 4 *S+imm8=P
stq *s+imm8 7F 4 *S+imm8=Q
ldp *imm16 68 5 P=*imm16
ldq *imm16 6A 5 Q=*imm16
stp *imm16 6C 5 *imm16=P
stq *imm16 6E 5 *imm16=Q
ldp *p 92 3 P=*P
ldq *p 93 3 Q=*P
ldp *q 94 3 P=*Q
ldq *q 95 3 Q=*Q
stp *q 7C 3 *Q=P
stq *p 7D 3 *P=Q
ldq *p++ CC 3 Q=*P++++
ldp *q++ CD 3 P=*Q++++
stp *q++ CE 3 *Q++++=P
stq *p++ CF 3 *P++++=Q
LDX ## AA 3 Set the X register to a given 16-bit value
LDY ## A8 3 Set the X register to a given 16-bit value
LDX zpg A6 4 Set the X register to the 16-bit value in memory at a given 8-bit address
LDY zpg A4 4 Set the Y register to the 16-bit value in memory at a given 8-bit address
STX zpg 86 4 Store the 16-bit value in the X register in memory at an given 8-bit address
STY zpg 84 4 Store the 16-bit value in the Y register in memory at an given 8-bit address
LDX abs AE 5 Set the X register to the 16-bit value in memory at a given 16-bit address
LDY abs AC 5 Set the Y register to the 16-bit value in memory at a given 16-bit address
STX abs 8E 5 Store the 16-bit value in the X register in memory at a given 16-bit address
STY abs 8C 5 Store the 16-bit value in the X register in memory at a given 16-bit address
LDX X,ofs BE 4 Set the X register to the 16-bit value in memory at the address (X plus a given 8-bit offset)
LDX Y,ofs BA 4 Set the Y register to the 16-bit value in memory at the address (X plus a given 8-bit offset)
LDY X,ofs BC 4 Set the X register to the 16-bit value in memory at the address (Y plus a given 8-bit offset)
LDY Y,ofs B8 4 Set the Y register to the 16-bit value in memory at the address (Y plus a given 8-bit offset)
STX Y,ofs 9A 4 Store the 16-bit value in the X register in memory at the address (Y plus a given 8-bit offset)
STY X,ofs 9C 4 Store the 16-bit value in the Y register in memory at the address (X plus a given 8-bit offset)
LDX X A2 3 Set the X register to the 16-bit value in memory at the address in X
LDY X A0 3 Set the Y register to the 16-bit value in memory at the address in X
LDX Y B2 3 Set the X register to the 16-bit value in the Y registerin16
LDY Y E2 3 Set the Y register to the 16-bit value in the Y registerin16
STX Y 92 3 Store the 16-bit value in the X register in memory at the address in Y
STY X 80 3 Store the 16-bit value in the Y register in memory at the address in X
LDX Y+ F2 3 Set the X register to the 16-bit value in the Y registerin16, the 16-bit value in the Y registerinc16
LDY X+ E0 3 Set the Y register to the 16-bit value in memory at the address in X, the 16-bit value in the X registerinc16
STX Y+ D2 3 Store the 16-bit value in the X register in memory at the address in Y, the 16-bit value in the Y registerinc16
STY X+ C0 3 Store the 16-bit value in the Y register in memory at the address in X, the 16-bit value in the X registerinc16
Moves (M):
lda b 80 1 A=B
lda c 81 1 A=C
ldb a 82 1 B=A
ldb c 83 1 B=C
ldc a 84 1 C=A
ldc b 85 1 C=B
lda pl 86 1 A=P&FF
lda ph 87 1 A=P>>8
lda ql 88 1 A=Q&FF
lda qh 89 1 A=Q>>8
ldb pl 37 1 B=P&FF
ldc ph 38 1 C=P>>8
ldb ql 39 1 B=Q&FF
ldc qh 3A 1 C=Q>>8
ldp q 8A 1 P=Q
ldp s 8B 1 P=S
ldp v 8C 1 P=V
ldp i 8D 1 P=I
ldp cb 91 1 P=(C<<8)+B
ldq cb E0 1 Q=(C<<8)+B
ldq p 8E 1 Q=P
lds p 8F 1 S=P
ldv p 90 1 V=P
TBA 97 1 Copy the value in the B register into the A register
TCA 17 1 Copy the value in the C register into the A register
TAB B7 1 Copy the value in the A register into the B register
TCB D7 1 Copy the value in the C register into the B register
TAC 37 1 Copy the value in the A register into the C register
TBC F7 1 Copy the value in the B register into the C register
TYX B4 1 Copy the 16-bit value in the Y register into the 16-bit X register
TXY 94 1 Copy the 16-bit value in the X register into the 16-bit Y register
TVX B6 1 Copy the 16-bit Interrupt Return Address into the X register
TXV 96 1 Copy the 16-bit value in the X register into the 16-bit Interrupt Return Address register
TAS 95 1 Copy the value in the A register into the 8-bit Stack Pointer register
TSA B5 1 Copy the 8-bit Stack Pointer into the A register
Opcodes used: 228/255
Opcodes used: 191/256
0123456789ABCDEF
00 | C---------------
10 | UUIIUIIUUUUUUUUU
20 | BWWWAWBBBBBUUUUA
30 | JJJJJJJMMMMSSSAA
40 | SSSSSSSSSSXXXAAA
50 | BBBBBBBBBBBBBBBB
60 | JBBJJJJJWWWWWWWW
70 | AAAAAAAAAAWWWWWW
80 | MMMMMMMMMMMMMMMM
90 | MMWWWWBBBAAAAAAA
A0 | AAAAAAAAAAAAAAAA
B0 | AAAAAAAAAAAAAAAA
C0 | BBBBBBBBBBBBWWWW
D0 | AAAAAAAAAAAAAAAA
E0 | MJJJJJXXXSS-----
F0 | CCCCCCC--------C
00 | CC-BJA-BSA--JJ--
10 | B--BSA-MCA-BSA-B
20 | JJ-BJA-BSA-BJJ--
30 | B--BSA-MCA-BSA-B
40 | CC-BJA-USA--JJ-B
50 | ---BSA-UCA-USA-U
60 | J--BJA-ASA-AJJ-B
70 | ---BSA--CA-ASA-A
80 | WB-BWBWBX-X-WWWW
90 | BBWBMMMMBBWBWB-B
A0 | WBWBWBWBWBWBWWWW
B0 | BBWBMMMMWBWBWBWB
C0 | WB-B-AU-XA--JB-B
D0 | BBWB--UM-AU-XAU-
E0 | WBWB-AUAXACA-B-B
F0 | BBWB--UM-AUAXAUA

View File

@ -1,45 +1,45 @@
## Boot ROM
Execution starts here, at address `$0000`.<br>
The main program is located here, or the OS bootloader if an OS is present.
## GPIO
Contains hardware multiplication (`$0400 * $0401 -> $0400`) and division (`$0402 / $0403 -> $0402 r $0403`), popcount (`$0404 -> $0404`), and a timer (`$0405`).<br>
Value written to timer register = number of game ticks (32 ms) between interrupt triggers.<br>
Write 0 to disable.
## Keyboard
Read address `$0500` to get the next key event<br>
7-bit Windows VKey code, MSB 1 = press, 0 = release<br>
Returns 0 if buffer is empty.
Write 1 to `$0500` to enable keyboard interrupts, 0 to disable.
## Serial Peripheral Interface
Not yet implemented.
## Robot Controller
Write to `$0701` to control the robot. Each bit is an action - MSB to LSB: Plant brick, destroy brick, move forward, backward, left, right, up, down.<br>
Write a 6-bit color ID to `$0700` to set the color of the bricks the robot plants.<br>
Read `$0700` to get the color of the brick the robot is on. MSB = brick exists. Returns 0 if no brick.
## Main RAM
8 KiB of random-access memory.<br>
Located at addresses `$8000` to `$9FFF`.<br>
Programs can write data to these addresses, and retrieve the data at a later time.<br>
Machine code can also be stored here and executed.
## Text Display
Write ASCII values to `$0800` to `$0BFF` to display characters at certain positions on screen.<br>
`$0800` is top left, `$0BFF` is bottom right, rows are 64 bytes.
Write ASCII values to addresses `$2000` to `$27FF` to display characters at certain positions on the screen.<br>
`$2000` is the top left, `$27FF` is the bottom right.<br>
Rows are 64 bytes long.<br>
For example, `$2040` would be the first character of the second row from the top.<br>
Values can also be read back out of the display memory, as if it were RAM.
## Text Display Color
Write 6-bit color IDs to `$0C00` to `$0FFF` to set the color of characters on screen.<br>
MSB = whether to invert character mask (i.e. for highlighting).
Write 6-bit color IDs to addresses `$0C00` to `$0FFF` to set the color of characters on the screen.<br>
If the most significant bit is 1, the character and background colors will be inverted, i.e. highlighted.<br>
Values can also be read back out of the display color memory, as if it were RAM.
## System RAM
The OS may use this memory for the stack, system variables, etc.<br>
If no OS is present, this memory can be used for any purpose, etc.<br>
Located at `$1000` to `$1FFF`.
## Main ROM
1 KiB of read-only memory.<br>
Located at addresses `$0000` to `$03FF`.<br>
When the CPU is first turned on, or is reset, it will start executing code from here, starting at address `$0000`.<br>
Bricks can be physically placed on top of the ROM brick to set bits within the ROM.<br>
A bootloader, operating system, or hex monitor may be loaded here.
## User ROM
User program and data can go here.<br>
If no OS is present, the boot ROM will need to jump into this code.<br>
Located at `$2000` to `$2FFF`.
## GPIO
Contains hardware multiplication, division, popcount, and a timer.<br>
When two 8-bit values are written to the multiplier registers `$0400` and `$0401`, the result will be available as a big-endian 16-bit value at `$0400`. Read from `$0401` to retrieve an 8-bit result.<br>
When two 8-bit values are written to the divider registers `$0402` and `$0403`, the quotient can be read from `$0402` and the remainder from `$0403`<br>
When any 8-bit value is written to the timer register `$0404`, the popcount of that value (The number of bits that are 1) can be read from the same location.
When any value is written to the timer register at `$0405`, an interrupt will be triggered after 32 milliseconds.
## User RAM
Your code can use this memory for variables, arrays, a heap, etc.<br>
Located at `$3000` to `$3FFF`.
## Keyboard
Read address `$0500` to get the next keycode from the buffer.<br>
Keycodes are 7-bit Windows VKey codes, plus a press/release bit. If the MSB is 1, the event is a key press; if 0, a release.<br>
Result will be 0 if the buffer is empty.<br>
If 1 is written to `$0500`, an interrupt will be triggered whenever a key event is available. Write 0 to disable again.
## Robot Controller
Write to `$0701` to control a 1x1f-sized "robot" that can place and destroy bricks.<br>
Each bit indicates an action; if that bit is set, that action will be taken. From MSB to LSB: Plant brick, destroy brick, move forward, backward, left, right, up, down.<br>
Write a 6-bit color ID to `$0700` to set the color of the bricks the robot will plant.<br>
Read `$0700` to get the color of the brick the robot is currently overlapping. If the MSB is 1, a brick exists at this location. Result will be 0 if no brick is present.<br>
The robot should only be given new actions once per game tick. The timer at `$0405` can be used for this purpose.

View File

@ -1,31 +1,16 @@
# 8608 - An 8-bit data, 16-bit address, CISC architecture.
For a list of instructions, see [instructionList.txt](instructionList.txt).
For a quick guide on how to use this project, see [getting-started.md](getting-started.md)<br>
## How to use the assembler:
1. Install `bllua3` from [https://notabug.org/redo/bllua3](https://notabug.org/redo/bllua3)
2. Download this repo into `Add-Ons/8608` or anywhere within one of Blockland's main directories.
3. In BL console, execute:
```
luaexec("Add-Ons/8608/assembler-8608.lua");
```
4. To assemble a program, place a 1x1f ghost brick on the top-left corner of the ROM, face forward, and in BL console do:
```
AssembleBuildFile("Add-Ons/8608/examples/program.asm", "RomX RomY RomZ");
```
where `RomX` is the width of the ROM, `RomY` is the depth front to back, and `RomZ` is the height in bits, i.e., "16 16 8".
For a detailed description of the architecture, see [architecture.md](architecture.md)<br>
For a list of instructions, see [instructionList.txt](instructionList.txt)<br>
For a memory map of the 8608-based computer, see [memoryMap.md](memoryMap.md)
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 "Add-Ons/8608/assembler-8608.lua" "Add-Ons/8608/examples/program.asm"
```
To use the emulator, simply drag-and-drop an assembly code file onto [emulator/8608-emulator.bat](emulator/8608-emulator.bat)<br>
You must include the 8608 architecture file into your assembly code: [8608.asm](8608.asm)<br>
`#include "8608/8608.asm"`
## How to use the emulator:
1. Install love2d from [https://love2d.org](https://love2d.org)
2. Open a command prompt in the "emulator" folder and run:
```
love . C:/path/filename.asm
```
## Memory Map
[memory map](memoryMap.md)
Note: This project depends on several pieces of free and open-source software,<br>
whose binaries are included in the repository:<br>
customasm: [https://github.com/hlorenzi/customasm](https://github.com/hlorenzi/customasm)<br>
LÖVE: [https://love2d.org/](https://love2d.org/)

View File

@ -1,381 +0,0 @@
return {
roms = {
{ pos = {0, 0, 0}, size = {64, 16, 64}, signals = {
"alulU", "alulT", "alulC", "alulB", "alulA", "alurIL", "alurIH", "alurVL",
"alurVH", "alurSL", "alurSH", "alurQL", "alurQH", "alurPL", "alurPH", "alurU",
"alurT", "alurC", "alurB", "alurA", "alur1", "alur2", "alurm1", "alurm2",
"adrrhU", "adrrhC", "adrrlT", "adrrTX", "adrrlB", "adrrBX", "adwrhU", "adwrhC",
"adwrlT", "adwrTX", "adwrlB", "adwrBX", "adwlI", "adwlV", "adwlS", "adwlQ",
"adwlP", "adrlI", "adrlV", "adrlS", "adrlQ", "adrlP", "aluAdd", "adwSaveV",
"aluRun", "aluRInv", "aluCinOn", "aluCinC", "memWriteAlur", "adrInc", "adwInc", "aluXor",
"aluIor", "aluAnd", "memWriteAlur", "adrOut", "adrSaveI", "adwSaveP", "adwSaveQ", "adwSaveS",
} },
{ pos = {-34, 16, 0}, size = {32, 32, 8}, signals = {
"aluSaveU", "aluSaveT", "aluSaveC", "aluSaveB", "aluSaveA", "aluSaveCarry", "aluSaveNZ", "always1",
} },
{ pos = {-34, 16, 17}, size = {32, 32, 32}, signals = {
"_", "_", "_", "_", "_", "_", "_", "_",
"_", "memSaveF", "memSaveNZ", "instrPre", "instrLoadPre", "always1", "instrLoadSel", "adrOut",
"memWriteAlur", "memSave", "instrNext0NZ", "instrNext0Z", "instrNext0NC", "instrNext0C", "instrLoadSub", "instrLoad",
"instrNext2", "instrNext1", "instrNext0", "memSaveU", "memSaveT", "memSaveC", "memSaveB", "memSaveA",
} },
{ pos = {66, 16, 0}, size = {32, 32, 32}, signals = {
"adrr1", "adrrm1", "adrrm2", "adrr2", "adwrm1", "adwrm2", "adwr2", "adwr1",
"memRead", "memWrite", "runFlgVal", "runFlgClk", "intFlgVal", "intFlgClk", "irqFlgClk", "always1",
"aluShiftArith", "aluShiftRoll", "aluShiftRight", "aluShift", "alurF", "_", "_", "_",
"_", "_", "_", "_", "_", "_", "_", "_",
} },
},
operations = {
base = {"always1"},
instrNext = {"base","adrlI","adrInc","adrSaveI","loadInstr"},
instrSub1 = {"base","instrLoadSub", "instrNext0"},
instrSub2 = {"base","instrLoadSub", "instrNext1", },
instrSub3 = {"base","instrLoadSub", "instrNext1","instrNext0"},
instrSub4 = {"base","instrLoadSub","instrNext2", },
instrSub5 = {"base","instrLoadSub","instrNext2", "instrNext0"},
instrSub6 = {"base","instrLoadSub","instrNext2","instrNext1", },
instrSub7 = {"base","instrLoadSub","instrNext2","instrNext1","instrNext0"},
instrSub23Cond = {"base","instrLoadSub","instrNext1"},
instrSwapIV = {"base","adwlI","adwSaveV","adrlV","adrSaveI","loadInstr"},
instrPreload = {"adrlI","adrInc","adrSaveI","adrOut","memRead","instrLoadSel","instrLoadPre"},
instrNextPre = {"base","instrPre","instrLoad","instrLoadSub"},
loadInstr = {"adrOut","memRead","instrLoadSel","instrLoad","instrLoadSub"},
loadReg = {"adrOut","memRead","memSave"},
storeReg = {"adrOut","memWrite","memWriteAlur"},
loadRegT = {"loadReg","memSaveT"},
pushReg = {"storeReg","adrlS","adwlS","adwInc","adwSaveS"},
popReg = {"loadReg","adrlS","adrrm1","adwlS","adwrm1","adwSaveS"},
pop161 = {"popReg","memSaveT"},
pop162 = {"popReg","memSaveU"},
loadImmed = {"adrlI","adrInc","adrSaveI","loadReg"},
loadImmedT = {"loadImmed","memSaveT"},
loadImm161 = {"loadImmed","memSaveU"},
loadImm162 = {"loadImmed","memSaveT"},
loadStackRel = {"adrlS","adrrTX","loadReg"},
loadStackRelT = {"loadStackRel","memSaveT"},
loadStackRelU = {"loadStackRel","memSaveU"},
loadStackRel161 = {"loadStackRel", "memSaveU"},
loadStackRel162 = {"loadStackRel","adrInc","memSaveT"},
storeStackRel = {"adrlS","adrrTX","storeReg"},
storeStackRel161 = {"storeStackRel" },
storeStackRel162 = {"storeStackRel","adrInc"},
storeStackRelU = {"storeStackRel","alurU"},
load161 = { "loadReg","memSaveU"},
load162 = {"adrInc","loadReg","memSaveT"},
store161 = { "storeReg"},
store162 = {"adrInc","storeReg"},
loadUTU = {"adrrUT","loadReg","memSaveU"},
storeUT = {"adrrUT","storeReg"},
memSaveFlags = {"memSaveNZ"},
adwrUT = {"adwrhU","adwrlT"},
adrrUT = {"adrrhU","adrrlT"},
adwrCB = {"adwrhC","adwrlB"},
adwIncUT = {"adwrUT","adwInc"},
adwP = {"adwlP","adwSaveP"},
adwQ = {"adwlQ","adwSaveQ"},
adwS = {"adwlS","adwSaveS"},
incP = {"adwP","adwInc"},
incQ = {"adwQ","adwInc"},
incP2 = {"adwP","adwr2"},
incQ2 = {"adwP","adwr2"},
jmpRelT = {"instrNext","adrrTX"},
jmpAbs = {"base","loadInstr","adrSaveI"},
jmpAbsUT = {"jmpAbs","adrrUT"},
jmpAbsP = {"jmpAbs","adrlP"},
jmpAbsQ = {"jmpAbs","adrlQ"},
saveRetAddr = {"adwlI","adwInc","adwSaveQ"},
pushRetAddr1 = {"alurIH","pushReg"},
pushRetAddr2 = {"alurIL","pushReg"},
aluA = {"alulA","aluSaveA"},
aluB = {"alulB","aluSaveB"},
aluC = {"alulC","aluSaveC"},
aluT = {"alulT","aluSaveT"},
aluU = {"alulU","aluSaveU"},
aluOpAdd = {"aluRun","aluAdd","aluSaveCarry","aluSaveNZ" },
aluOpAddC= {"aluRun","aluAdd","aluSaveCarry","aluSaveNZ", "aluCinC" },
aluOpSub = {"aluRun","aluAdd","aluSaveCarry","aluSaveNZ","aluRInv","aluCinOn"},
aluOpSubC= {"aluRun","aluAdd","aluSaveCarry","aluSaveNZ","aluRInv","aluCinC" },
aluOpAnd = {"aluRun","aluAnd" , "aluSaveNZ"},
aluOpIor = {"aluRun","aluIor" , "aluSaveNZ"},
aluOpXor = {"aluRun","aluXor" , "aluSaveNZ"},
aluOpAnn = {"aluRun","aluAnd","aluRInv", "aluSaveNZ"},
aluOpCmp = {"aluOpSub"},
aluOpInc = {"aluOpAdd","aluCinOn"},
aluOpDec = {"aluOpAdd","aluRInv"},
aluOpMov = {"aluAdd","aluSaveNZ"},
aluOpShl = {"aluRun", "aluShift" ,"aluSaveNZ"},
aluOpShr = {"aluRun", "aluShift","aluShiftRight" ,"aluSaveNZ"},
aluOpRol = {"aluRun", "aluShift", "aluShiftRoll" ,"aluSaveNZ"},
aluOpRor = {"aluRun", "aluShift","aluShiftRight","aluShiftRoll" ,"aluSaveNZ"},
aluOpSra = {"aluRun", "aluShift","aluShiftRight", "aluShiftArith","aluSaveNZ"},
clearRegs = {
"aluSaveA","aluSaveB","aluSaveC","aluSaveU","aluSaveT",
"adwSaveP","adwSaveQ","adwSaveS","adwSaveV",
"adrSaveI",
"aluSaveNZ","aluSaveCarry",
}
},
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; 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;"}, }, -- todo
{ mnem="idi" , opcode=0xF6, {"instrNext"}, desc="Disable interrupts", ccode={"cpu.ien=0; lni;"}, }, -- todo
{ category = "16-bit Inc/Dec", catlet="I" },
{ mnem="inc p" , opcode=0x12, {"adwlP","adwInc","adwSaveP","instrNext"}, desc="P++", ccode={"cpu.p++; lni;"} },
{ mnem="dec p" , opcode=0x15, {"adwlP","adwrm1","adwSaveP","instrNext"}, desc="P--", ccode={"cpu.p--; lni;"} },
{ mnem="inc q" , opcode=0x13, {"adwlQ","adwInc","adwSaveQ","instrNext"}, desc="Q++", ccode={"cpu.q++; lni;"} },
{ mnem="dec q" , opcode=0x16, {"adwlQ","adwrm1","adwSaveQ","instrNext"}, desc="Q--", ccode={"cpu.q--; lni;"} },
{ category = "8-bit Unary", catlet="U" },
{ mnem="inc a" , opcode=0x10, {"aluA","alur1" ,"aluOpAdd" ,"instrNext"}, desc="A++, set flags" , ccode={"addf(cpu.a, 1 ); lni;"} },
{ mnem="dec a" , opcode=0x11, {"aluA","alurm1","aluOpAdd" ,"instrNext"}, desc="A--, set flags" , ccode={"addf(cpu.a,-1 ); lni;"} },
{ mnem="icc a" , opcode=0x1B, {"aluA", "aluOpAddC","instrNext"}, desc="A+=CF, set flags", ccode={"addf(cpu.a,cpu.cf); lni;"} },
{ mnem="inc b" , opcode=0x19, {"aluB","alur1" ,"aluOpAdd" ,"instrNext"}, desc="B++, set flags" , ccode={"addf(cpu.b, 1 ); lni;"} },
{ mnem="dec b" , opcode=0x1A, {"aluB","alurm1","aluOpAdd" ,"instrNext"}, desc="B--, set flags" , ccode={"addf(cpu.b,-1 ); lni;"} },
{ mnem="icc b" , opcode=0x1C, {"aluB", "aluOpAddC","instrNext"}, desc="B+=CF, set flags", ccode={"addf(cpu.b,cpu.cf); lni;"} },
{ mnem="inc c" , opcode=0x17, {"aluC","alur1" ,"aluOpAdd" ,"instrNext"}, desc="C++, set flags" , ccode={"addf(cpu.c, 1 ); lni;"} },
{ mnem="dec c" , opcode=0x18, {"aluC","alurm1","aluOpAdd" ,"instrNext"}, desc="C--, set flags" , ccode={"addf(cpu.c,-1 ); lni;"} },
{ mnem="icc c" , opcode=0x1D, {"aluC", "aluOpAddC","instrNext"}, desc="C+=CF, set flags", ccode={"addf(cpu.c,cpu.cf); lni;"} },
{ mnem="tst a" , opcode=0x14, {"alulA", "aluOpCmp" ,"instrNext"}, desc="Set flags according to A-0", ccode={"tst(cpu.a); lni;"} },
{ mnem="tst b" , opcode=0x1E, {"alulB", "aluOpCmp" ,"instrNext"}, desc="Set flags according to B-0", ccode={"tst(cpu.b); lni;"} },
{ mnem="tst c" , opcode=0x1F, {"alulC", "aluOpCmp" ,"instrNext"}, desc="Set flags according to C-0", ccode={"tst(cpu.c); lni;"} },
{ mnem="inc *s+imm8", opcode=0x2B, {"loadImmedT","instrSub1"}, {"loadStackRelU","instrSub2"}, {"aluU","alur1" ,"aluOpAdd" ,"instrSub3","instrPreload"}, {"storeStackRelU","instrNextPre"}, desc="*(S+imm8)++, set flags" , ccode={"loadimmedt","loadstackrelu","instrpreload; addf(cpu.u, 1 );","instrloadpre"} },
{ mnem="dec *s+imm8", opcode=0x2C, {"loadImmedT","instrSub1"}, {"loadStackRelU","instrSub2"}, {"aluU","alurm1","aluOpAdd" ,"instrSub3","instrPreload"}, {"storeStackRelU","instrNextPre"}, desc="*(S+imm8)--, set flags" , ccode={"loadimmedt","loadstackrelu","instrpreload; addf(cpu.u,-1 );","instrloadpre"} },
{ mnem="icc *s+imm8", opcode=0x2D, {"loadImmedT","instrSub1"}, {"loadStackRelU","instrSub2"}, {"aluU", "aluOpAddC","instrSub3","instrPreload"}, {"storeStackRelU","instrNextPre"}, desc="*(S+imm8)+=CF, set flags", ccode={"loadimmedt","loadstackrelu","instrpreload; addf(cpu.u,cpu.cf);","instrloadpre"} },
{ mnem="tst *s+imm8", opcode=0x2E, {"loadImmedT","instrSub1"}, {"loadStackRelU","instrSub2"}, {"alulU", "aluOpCmp" ,"instrNext"}, desc="Set flags according to *(S+imm8)-0", ccode={"loadimmedt","loadstackrelu","tst(cpu.u); lni;"} },
{ category = "16-bit Arithmetic", catlet = "X"},
{ mnem="adp imm8" , opcode=0x4A, {"loadImmedT","instrSub1"}, {"adwP","adwrTX","instrNext"}, desc="P+=imm8 signed", ccode={"loadimmedt","cpu.p+=signed8(cpu.t); lni;"} },
{ mnem="adq imm8" , opcode=0x4B, {"loadImmedT","instrSub1"}, {"adwQ","adwrTX","instrNext"}, desc="Q+=imm8 signed", ccode={"loadimmedt","cpu.q+=signed8(cpu.t); lni;"} },
{ mnem="ads imm8" , opcode=0x4C, {"loadImmedT","instrSub1"}, {"adwS","adwrTX","instrNext"}, desc="S+=imm8 signed", ccode={"loadimmedt","cpu.s+=signed8(cpu.t); lni;"} },
{ mnem="adp b" , opcode=0xE6, {"adwP","adwrBX","instrNext"}, desc="P+=B signed", ccode={"cpu.p+=signed8(cpu.b); lni;"} },
{ mnem="adq b" , opcode=0xE7, {"adwQ","adwrBX","instrNext"}, desc="Q+=B signed", ccode={"cpu.q+=signed8(cpu.b); lni;"} },
{ mnem="ads b" , opcode=0xE8, {"adwS","adwrBX","instrNext"}, desc="S+=B signed", ccode={"cpu.s+=signed8(cpu.b); lni;"} },
{ category = "8-bit Arithmetic/Logic", catlet="A" },
{ mnem="add imm8" , opcode=0x24, {"loadImmedT","instrSub1"}, {"aluA", "alurT","aluOpAdd" ,"instrNext"}, desc="A+=imm8, set flags" , ccode={"loadimmedt","addf(cpu.a,cpu.t); lni;"} },
{ mnem="adb imm8" , opcode=0x72, {"loadImmedT","instrSub1"}, {"aluB", "alurT","aluOpAdd" ,"instrNext"}, desc="B+=imm8, set flags" , ccode={"loadimmedt","addf(cpu.b,cpu.t); lni;"} },
{ mnem="adc imm8" , opcode=0x73, {"loadImmedT","instrSub1"}, {"aluC", "alurT","aluOpAdd" ,"instrNext"}, desc="C+=imm8, set flags" , ccode={"loadimmedt","addf(cpu.c,cpu.t); lni;"} },
{ mnem="sub imm8" , opcode=0x70, {"loadImmedT","instrSub1"}, {"aluA", "alurT","aluOpSub" ,"instrNext"}, desc="A-=imm8, set flags" , ccode={"loadimmedt","subf(cpu.a,cpu.t); lni;"} },
{ mnem="sbb imm8" , opcode=0x99, {"loadImmedT","instrSub1"}, {"aluB", "alurT","aluOpSub" ,"instrNext"}, desc="B-=imm8, set flags" , ccode={"loadimmedt","subf(cpu.b,cpu.t); lni;"} },
{ mnem="sbc imm8" , opcode=0x9A, {"loadImmedT","instrSub1"}, {"aluC", "alurT","aluOpSub" ,"instrNext"}, desc="C-=imm8, set flags" , ccode={"loadimmedt","subf(cpu.c,cpu.t); lni;"} },
{ mnem="acc imm8" , opcode=0x78, {"loadImmedT","instrSub1"}, {"aluA", "alurT","aluOpAddC","instrNext"}, desc="A+=imm8+CF, set flags" , ccode={"loadimmedt","addf(cpu.a,cpu.t+cpu.cf); lni;"} },
{ mnem="scc imm8" , opcode=0x79, {"loadImmedT","instrSub1"}, {"aluA", "alurT","aluOpSubC","instrNext"}, desc="A-=imm8+CF, set flags" , ccode={"loadimmedt","addf(cpu.a,-cpu.t+cpu.cf); lni;"} },
{ mnem="cmp imm8" , opcode=0x71, {"loadImmedT","instrSub1"}, {"alulA","alurT","aluOpSub" ,"instrNext"}, desc="set flags according to A-imm8" , ccode={"loadimmedt","cmpf(cpu.a,cpu.t); lni;"} },
{ mnem="and imm8" , opcode=0x74, {"loadImmedT","instrSub1"}, {"aluA", "alurT","aluOpAnd" ,"instrNext"}, desc="A&=imm8, set zero flag" , ccode={"loadimmedt","cpu.a&=cpu.t; setzf(cpu.a); lni;"} },
{ mnem="ior imm8" , opcode=0x75, {"loadImmedT","instrSub1"}, {"aluA", "alurT","aluOpIor" ,"instrNext"}, desc="A|=imm8, set zero flag" , ccode={"loadimmedt","cpu.a|=cpu.t; setzf(cpu.a); lni;"} },
{ mnem="xor imm8" , opcode=0x76, {"loadImmedT","instrSub1"}, {"aluA", "alurT","aluOpXor" ,"instrNext"}, desc="A^=imm8, set zero flag" , ccode={"loadimmedt","cpu.a^=cpu.t; setzf(cpu.a); lni;"} },
{ mnem="ann imm8" , opcode=0x77, {"loadImmedT","instrSub1"}, {"aluA", "alurT","aluOpAnn" ,"instrNext"}, desc="A&=~imm8, set zero flag" , ccode={"loadimmedt","cpu.a&=~cpu.t; setzf(cpu.a); lni;"} },
{ mnem="shl imm8" , opcode=0xD0, {"loadImmedT","instrSub1"}, {"aluA", "alurT","aluOpShl" ,"instrNext"}, desc="A<<=imm8, set zero flag" , ccode={"loadimmedt","cpu.a<<=cpu.t; setzf(cpu.a); lni;"} },
{ mnem="shr imm8" , opcode=0xD1, {"loadImmedT","instrSub1"}, {"aluA", "alurT","aluOpShr" ,"instrNext"}, desc="A>>=imm8, set zero flag" , ccode={"loadimmedt","cpu.a>>=cpu.t; setzf(cpu.a); lni;"} },
{ mnem="rol imm8" , opcode=0xD2, {"loadImmedT","instrSub1"}, {"aluA", "alurT","aluOpRol" ,"instrNext"}, desc="A<<<=imm8, set zero flag" , ccode={"loadimmedt","cpu.a=rol(cpu.a,cpu.t); setzf(cpu.a); lni;"} },
{ mnem="ror imm8" , opcode=0xD3, {"loadImmedT","instrSub1"}, {"aluA", "alurT","aluOpRor" ,"instrNext"}, desc="A>>>=imm8, set zero flag" , ccode={"loadimmedt","cpu.a=ror(cpu.a,cpu.t); setzf(cpu.a); lni;"} },
{ mnem="sra imm8" , opcode=0xD4, {"loadImmedT","instrSub1"}, {"aluA", "alurT","aluOpSra" ,"instrNext"}, desc="A>>a=imm8, set zero flag" , ccode={"loadimmedt","cpu.a=sra(cpu.a,cpu.t); setzf(cpu.a); lni;"} },
{ mnem="add *s+imm8", opcode=0xAE, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluA", "alurT","aluOpAdd" ,"instrNext"}, desc="A+=*(S+imm8), set flags" , ccode={"loadimmedt","loadstackrelu","addf(cpu.a,cpu.u); lni;"} },
{ mnem="adb *s+imm8", opcode=0x9B, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluB", "alurT","aluOpAdd" ,"instrNext"}, desc="B+=*(S+imm8), set flags" , ccode={"loadimmedt","loadstackrelu","addf(cpu.b,cpu.u); lni;"} },
{ mnem="adc *s+imm8", opcode=0x9C, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluC", "alurT","aluOpAdd" ,"instrNext"}, desc="C+=*(S+imm8), set flags" , ccode={"loadimmedt","loadstackrelu","addf(cpu.c,cpu.u); lni;"} },
{ mnem="sub *s+imm8", opcode=0xAF, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluA", "alurT","aluOpSub" ,"instrNext"}, desc="A-=*(S+imm8), set flags" , ccode={"loadimmedt","loadstackrelu","subf(cpu.a,cpu.u); lni;"} },
{ mnem="sbb *s+imm8", opcode=0x9D, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluB", "alurT","aluOpSub" ,"instrNext"}, desc="B-=*(S+imm8), set flags" , ccode={"loadimmedt","loadstackrelu","subf(cpu.b,cpu.u); lni;"} },
{ mnem="sbc *s+imm8", opcode=0x9E, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluC", "alurT","aluOpSub" ,"instrNext"}, desc="C-=*(S+imm8), set flags" , ccode={"loadimmedt","loadstackrelu","subf(cpu.c,cpu.u); lni;"} },
{ mnem="acc *s+imm8", opcode=0xB5, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluA", "alurT","aluOpAddC","instrNext"}, desc="A+=*(S+imm8)+CF, set flags" , ccode={"loadimmedt","loadstackrelu","addf(cpu.a,cpu.u+cpu.cf); lni;"} },
{ mnem="scc *s+imm8", opcode=0xB7, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluA", "alurT","aluOpSubC","instrNext"}, desc="A-=*(S+imm8)+CF, set flags" , ccode={"loadimmedt","loadstackrelu","addf(cpu.a,-cpu.u+cpu.cf); lni;"} },
{ mnem="cmp *s+imm8", opcode=0xB0, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"alulA","alurT","aluOpSub" ,"instrNext"}, desc="set flags according to A-*(S+imm8)", ccode={"loadimmedt","loadstackrelu","cmpf(cpu.a,cpu.u); lni;"} },
{ mnem="and *s+imm8", opcode=0xB1, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluA", "alurT","aluOpAnd" ,"instrNext"}, desc="A&=*(S+imm8), set zero flag" , ccode={"loadimmedt","loadstackrelu","cpu.a&=cpu.u; setzf(cpu.a); lni;"} },
{ mnem="ior *s+imm8", opcode=0xB2, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluA", "alurT","aluOpIor" ,"instrNext"}, desc="A|=*(S+imm8), set zero flag" , ccode={"loadimmedt","loadstackrelu","cpu.a|=cpu.u; setzf(cpu.a); lni;"} },
{ mnem="xor *s+imm8", opcode=0xB3, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluA", "alurT","aluOpXor" ,"instrNext"}, desc="A^=*(S+imm8), set zero flag" , ccode={"loadimmedt","loadstackrelu","cpu.a^=cpu.u; setzf(cpu.a); lni;"} },
{ mnem="ann *s+imm8", opcode=0xB4, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluA", "alurT","aluOpAnn" ,"instrNext"}, desc="A&=~*(S+imm8), set zero flag" , ccode={"loadimmedt","loadstackrelu","cpu.a&=~cpu.u; setzf(cpu.a); lni;"} },
{ mnem="shl *s+imm8", opcode=0xD5, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluA", "alurT","aluOpShl" ,"instrNext"}, desc="A<<=*(S+imm8), set zero flag" , ccode={"loadimmedt","loadstackrelu","cpu.a<<=cpu.u; setzf(cpu.a); lni;"} },
{ mnem="shr *s+imm8", opcode=0xD6, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluA", "alurT","aluOpShr" ,"instrNext"}, desc="A<<=*(S+imm8), set zero flag" , ccode={"loadimmedt","loadstackrelu","cpu.a>>=cpu.u; setzf(cpu.a); lni;"} },
{ mnem="rol *s+imm8", opcode=0xD7, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluA", "alurT","aluOpRol" ,"instrNext"}, desc="A<<<=*(S+imm8), set zero flag" , ccode={"loadimmedt","loadstackrelu","cpu.a=rol(cpu.a,cpu.u); setzf(cpu.a); lni;"} },
{ mnem="ror *s+imm8", opcode=0xD8, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluA", "alurT","aluOpRor" ,"instrNext"}, desc="A>>>=*(S+imm8), set zero flag" , ccode={"loadimmedt","loadstackrelu","cpu.a=ror(cpu.a,cpu.u); setzf(cpu.a); lni;"} },
{ mnem="sra *s+imm8", opcode=0xD9, {"loadImmedT","instrSub1"}, {"loadStackRelT","instrSub2"}, {"aluA", "alurT","aluOpSra" ,"instrNext"}, desc="A>>a=*(S+imm8), set zero flag" , ccode={"loadimmedt","loadstackrelu","cpu.a=sra(cpu.a,cpu.u); setzf(cpu.a); lni;"} },
{ mnem="add b" , opcode=0xA0, {"aluA", "alurB","aluOpAdd" ,"instrNext"}, desc="A+=B, set flags" , ccode={"addf(cpu.a,cpu.b); lni;"} },
{ mnem="adc b" , opcode=0x9F, {"aluC", "alurB","aluOpAdd" ,"instrNext"}, desc="C+=B, set flags" , ccode={"addf(cpu.c,cpu.b); lni;"} },
{ mnem="sub b" , opcode=0xA1, {"aluA", "alurB","aluOpSub" ,"instrNext"}, desc="A-=B, set flags" , ccode={"subf(cpu.a,cpu.b); lni;"} },
{ mnem="sbc b" , opcode=0xB6, {"aluC", "alurB","aluOpSub" ,"instrNext"}, desc="C-=B, set flags" , ccode={"subf(cpu.c,cpu.b); lni;"} },
{ mnem="acc b" , opcode=0xB8, {"aluA", "alurB","aluOpAddC","instrNext"}, desc="A+=B+CF, set flags" , ccode={"addf(cpu.a,cpu.b+cpu.cf); lni;"} },
{ mnem="scc b" , opcode=0xB9, {"aluA", "alurB","aluOpSubC","instrNext"}, desc="A-=B+CF, set flags" , ccode={"addf(cpu.a,-cpu.b+cpu.cf); lni;"} },
{ mnem="cmp b" , opcode=0xA2, {"alulA","alurB","aluOpSub" ,"instrNext"}, desc="set flags according to A-B" , ccode={"cmpf(cpu.a,cpu.b); lni;"} },
{ mnem="and b" , opcode=0xA3, {"aluA", "alurB","aluOpAnd" ,"instrNext"}, desc="A&=B, set zero flag" , ccode={"cpu.a&=cpu.b; setzf(cpu.a); lni;"} },
{ mnem="ior b" , opcode=0xA4, {"aluA", "alurB","aluOpIor" ,"instrNext"}, desc="A|=B, set zero flag" , ccode={"cpu.a|=cpu.b; setzf(cpu.a); lni;"} },
{ mnem="xor b" , opcode=0xA5, {"aluA", "alurB","aluOpXor" ,"instrNext"}, desc="A^=B, set zero flag" , ccode={"cpu.a^=cpu.b; setzf(cpu.a); lni;"} },
{ mnem="ann b" , opcode=0xA6, {"aluA", "alurB","aluOpAnn" ,"instrNext"}, desc="A&=~B, set zero flag" , ccode={"cpu.a&=~cpu.b; setzf(cpu.a); lni;"} },
{ mnem="shl b" , opcode=0xDA, {"aluA", "alurB","aluOpShl" ,"instrNext"}, desc="A<<=B, set zero flag" , ccode={"cpu.a<<=cpu.b; setzf(cpu.a); lni;"} },
{ mnem="shr b" , opcode=0xDB, {"aluA", "alurB","aluOpShr" ,"instrNext"}, desc="A>>=B, set zero flag" , ccode={"cpu.a>>=cpu.b; setzf(cpu.a); lni;"} },
{ mnem="rol b" , opcode=0xDC, {"aluA", "alurB","aluOpRol" ,"instrNext"}, desc="A<<<=B, set zero flag" , ccode={"cpu.a=rol(cpu.a,cpu.b); setzf(cpu.a); lni;"} },
{ mnem="ror b" , opcode=0xDD, {"aluA", "alurB","aluOpRor" ,"instrNext"}, desc="A>>>=B, set zero flag" , ccode={"cpu.a=ror(cpu.a,cpu.b); setzf(cpu.a); lni;"} },
{ mnem="sra b" , opcode=0xDE, {"aluA", "alurB","aluOpSra" ,"instrNext"}, desc="A>>a=B, set zero flag" , ccode={"cpu.a=sra(cpu.a,cpu.b); setzf(cpu.a); lni;"} },
{ mnem="add c" , opcode=0xA7, {"aluA", "alurC","aluOpAdd" ,"instrNext"}, desc="A+=C, set flags" , ccode={"addf(cpu.a,cpu.c); lni;"} },
{ mnem="adb c" , opcode=0xBD, {"aluB", "alurC","aluOpAdd" ,"instrNext"}, desc="B+=C, set flags" , ccode={"addf(cpu.b,cpu.c); lni;"} },
{ mnem="sub c" , opcode=0xA8, {"aluA", "alurC","aluOpSub" ,"instrNext"}, desc="A-=C, set flags" , ccode={"subf(cpu.a,cpu.c); lni;"} },
{ mnem="sbb c" , opcode=0xBC, {"aluB", "alurC","aluOpSub" ,"instrNext"}, desc="B-=C, set flags" , ccode={"subf(cpu.b,cpu.c); lni;"} },
{ mnem="acc c" , opcode=0xBA, {"aluA", "alurC","aluOpAddC","instrNext"}, desc="A+=C+CF, set flags" , ccode={"addf(cpu.a,cpu.c+cpu.cf); lni;"} },
{ mnem="scc c" , opcode=0xBB, {"aluA", "alurC","aluOpSubC","instrNext"}, desc="A-=C+CF, set flags" , ccode={"addf(cpu.a,-cpu.c+cpu.cf); lni;"} },
{ mnem="cmp c" , opcode=0xA9, {"alulA","alurC","aluOpSub" ,"instrNext"}, desc="set flags according to A-C" , ccode={"cmpf(cpu.a,cpu.c); lni;"} },
{ mnem="and c" , opcode=0xAA, {"aluA", "alurC","aluOpAnd" ,"instrNext"}, desc="A&=C, set zero flag" , ccode={"cpu.a&=cpu.c; setzf(cpu.a); lni;"} },
{ mnem="ior c" , opcode=0xAB, {"aluA", "alurC","aluOpIor" ,"instrNext"}, desc="A|=C, set zero flag" , ccode={"cpu.a|=cpu.c; setzf(cpu.a); lni;"} },
{ mnem="xor c" , opcode=0xAC, {"aluA", "alurC","aluOpXor" ,"instrNext"}, desc="A^=C, set zero flag" , ccode={"cpu.a^=cpu.c; setzf(cpu.a); lni;"} },
{ mnem="ann c" , opcode=0xAD, {"aluA", "alurC","aluOpAnn" ,"instrNext"}, desc="A&=~C, set zero flag" , ccode={"cpu.a&=~cpu.c; setzf(cpu.a); lni;"} },
{ mnem="shl c" , opcode=0xDF, {"aluA", "alurC","aluOpShl" ,"instrNext"}, desc="A<<=C, set zero flag" , ccode={"cpu.a<<=cpu.c; setzf(cpu.a); lni;"} },
{ mnem="shr c" , opcode=0x4D, {"aluA", "alurC","aluOpShr" ,"instrNext"}, desc="A>>=C, set zero flag" , ccode={"cpu.a>>=cpu.c; setzf(cpu.a); lni;"} },
{ mnem="rol c" , opcode=0x3E, {"aluA", "alurC","aluOpRol" ,"instrNext"}, desc="A<<<=C, set zero flag" , ccode={"cpu.a=rol(cpu.a,cpu.c); setzf(cpu.a); lni;"} },
{ mnem="ror c" , opcode=0x3F, {"aluA", "alurC","aluOpRor" ,"instrNext"}, desc="A>>>=C, set zero flag" , ccode={"cpu.a=ror(cpu.a,cpu.c); setzf(cpu.a); lni;"} },
{ mnem="sra c" , opcode=0x2F, {"aluA", "alurC","aluOpSra" ,"instrNext"}, desc="A>>a=C, set zero flag" , ccode={"cpu.a=sra(cpu.a,cpu.c); setzf(cpu.a); lni;"} },
{ mnem="adb a" , opcode=0xBE, {"aluB", "alurA","aluOpAdd" ,"instrNext"}, desc="B+=A, set flags" , ccode={"addf(cpu.b,cpu.a); lni;"} },
{ mnem="sbb a" , opcode=0xBF, {"aluB", "alurA","aluOpSub" ,"instrNext"}, desc="B-=A, set flags" , ccode={"subf(cpu.b,cpu.a); lni;"} },
{ mnem="adc a" , opcode=0x4E, {"aluC", "alurA","aluOpAdd" ,"instrNext"}, desc="C+=A, set flags" , ccode={"addf(cpu.c,cpu.a); lni;"} },
{ mnem="sbc a" , opcode=0x4F, {"aluC", "alurA","aluOpSub" ,"instrNext"}, desc="C-=A, set flags" , ccode={"subf(cpu.c,cpu.a); lni;"} },
{ category = "Jumps", catlet="J" },
{ mnem="jmp imm16" , opcode=0x60, jmp=true, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"jmpAbsUT" }, desc="I=imm16" , ccode={"loadimm161","loadimm162","jmpabsut"} },
{ mnem="jsr imm16" , opcode=0x63, jmp=true, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"jmpAbsUT","saveRetAddr"}, desc="I=imm16, Q=I", ccode={"loadimm161","loadimm162","jmpabsut saveretaddr"} },
{ mnem="jss imm16" , opcode=0xE2, jmp=true, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"pushRetAddr1","instrSub3"}, {"pushRetAddr2","instrSub4"}, {"jmpAbsUT"}, desc="I=imm16, *(S++++)=I-1", ccode={"loadimm161","loadimm162","pushretaddr1","pushretaddr2","jmpabsut"} },
{ mnem="jmp p" , opcode=0x64, {"jmpAbsP" }, desc="I=P" , ccode={"jmpabsp"} },
{ mnem="jmp q" , opcode=0x66, {"jmpAbsQ" }, desc="I=Q" , ccode={"jmpabsq"} },
{ mnem="jsr p" , opcode=0x65, {"jmpAbsP","saveRetAddr"}, desc="I=P, Q=I", ccode={"jmpabsp","saveretaddr"} },
{ mnem="jsr q" , opcode=0x67, {"jmpAbsQ","saveRetAddr"}, desc="I=Q, Q=I", ccode={"jmpabsq","saveretaddr"} },
{ mnem="jss p" , opcode=0xE4, {"pushRetAddr1","instrSub1"}, {"pushRetAddr2","instrSub2"}, {"jmpAbsP"}, desc="I=P, *(S++++)=I-1", ccode={"pushretaddr1","pushretaddr2","jmpabsp"} },
{ mnem="jss q" , opcode=0xE5, {"pushRetAddr1","instrSub1"}, {"pushRetAddr2","instrSub2"}, {"jmpAbsQ"}, desc="I=Q, *(S++++)=I-1", ccode={"pushretaddr1","pushretaddr2","jmpabsq"} },
{ mnem="rts" , opcode=0xE1, {"pop161","instrSub1"}, {"pop162","instrSub2"}, {"jmpAbsUT","adrInc"}, desc="I=*(----S)+1", ccode={"pop161","pop162","jmpabsutplus1"} },
{ 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 }"} },
{ category = "Stack", catlet="S" },
{ mnem="psh a" , opcode=0x40, {"pushReg","alurA","instrSub1"}, {"instrNext"}, desc="*(S++)=A", ccode={"pushbyte(cpu.a);","lni;"} },
{ mnem="psh b" , opcode=0x44, {"pushReg","alurB","instrSub1"}, {"instrNext"}, desc="*(S++)=B", ccode={"pushbyte(cpu.b);","lni;"} },
{ mnem="psh c" , opcode=0x45, {"pushReg","alurC","instrSub1"}, {"instrNext"}, desc="*(S++)=C", ccode={"pushbyte(cpu.c);","lni;"} },
{ mnem="psh f" , opcode=0xE9, {"pushReg","alurF","instrSub1"}, {"instrNext"}, desc="*(S++)=F", ccode={"int f = cpu.nz | (cpu.cf<<1); pushbyte(f);","lni;"} },
{ mnem="psh p" , opcode=0x41, {"pushReg","alurPH","instrSub1"}, {"pushReg","alurPL","instrSub2"}, {"instrNext"}, desc="*(S++++)=P", ccode={"push161(cpu.p);","push162(cpu.p);","lni;"} },
{ mnem="psh q" , opcode=0x46, {"pushReg","alurQH","instrSub1"}, {"pushReg","alurQL","instrSub2"}, {"instrNext"}, desc="*(S++++)=Q", ccode={"push161(cpu.q);","push162(cpu.q);","lni;"} },
{ mnem="pop a" , opcode=0x42, {"popReg","memSaveA","instrSub1"}, {"instrNext"}, desc="A=*(--S)", ccode={"cpu.a=popbyte;","lni;"} },
{ mnem="pop b" , opcode=0x47, {"popReg","memSaveB","instrSub1"}, {"instrNext"}, desc="B=*(--S)", ccode={"cpu.b=popbyte;","lni;"} },
{ mnem="pop c" , opcode=0x48, {"popReg","memSaveC","instrSub1"}, {"instrNext"}, desc="C=*(--S)", ccode={"cpu.c=popbyte;","lni;"} },
{ mnem="pop f" , opcode=0xEA, {"popReg","memSaveF","instrSub1"}, {"instrNext"}, desc="F=*(--S)", ccode={"int f=popbyte; cpu.nz = f&1; cpu.cf = (f>>1)&1;","lni;"} },
{ mnem="pop p" , opcode=0x43, {"pop161","instrSub1"}, {"pop162","instrSub2"}, {"adwrUT","adwSaveP","instrNext"}, desc="P=*(----S)", ccode={"pop161","pop162","cpu.p=wordut; lni;"} },
{ mnem="pop q" , opcode=0x49, {"pop161","instrSub1"}, {"pop162","instrSub2"}, {"adwrUT","adwSaveQ","instrNext"}, desc="Q=*(----S)", ccode={"pop161","pop162","cpu.q=wordut; lni;"} },
{ mnem="psh imm8" , opcode=0x3B, {"loadImmedT","instrSub1"}, {"pushReg","alurT","instrSub2"}, {"instrNext"}, desc="*(S++)=imm8", ccode={"loadimmedt;","pushbyte(cpu.t);","lni;"} },
{ mnem="phw imm16" , opcode=0x3C, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"pushReg","alurU","instrSub3"}, {"pushReg","alurT","instrSub4"}, {"instrNext"}, desc="*(S++++)=imm16", ccode={"loadimm161","loadimm162","pushbyte(cpu.u);","pushbyte(cpu.t);","lni;"} }, -- 0x3D
{ category = "8-bit Load/Store", catlet="B" },
{ mnem="lda imm8" , opcode=0x20, {"loadImmed", "memSaveA","memSaveFlags","instrSub1"}, {"instrNext"}, desc="A=imm8, update zero flag", ccode={"cpu.a=loadimmed; setzf(cpu.a);","lni;"} },
{ mnem="ldb imm8" , opcode=0x26, {"loadImmed", "memSaveB","memSaveFlags","instrSub1"}, {"instrNext"}, desc="B=imm8, update zero flag", ccode={"cpu.b=loadimmed; setzf(cpu.b);","lni;"} },
{ mnem="ldc imm8" , opcode=0x27, {"loadImmed", "memSaveC","memSaveFlags","instrSub1"}, {"instrNext"}, desc="C=imm8, update zero flag", ccode={"cpu.c=loadimmed; setzf(cpu.c);","lni;"} },
{ mnem="lda *s+imm8", opcode=0x28, {"loadImmedT","instrSub1"}, {"loadStackRel","memSaveA","memSaveFlags","instrSub2"}, {"instrNext"}, desc="A=*s+imm8, update zero flag", ccode={"loadimmedt;","cpu.a=loadstackrel; setzf(cpu.a);","lni;"} },
{ mnem="ldb *s+imm8", opcode=0x29, {"loadImmedT","instrSub1"}, {"loadStackRel","memSaveB","memSaveFlags","instrSub2"}, {"instrNext"}, desc="B=*s+imm8, update zero flag", ccode={"loadimmedt;","cpu.b=loadstackrel; setzf(cpu.b);","lni;"} },
{ mnem="ldc *s+imm8", opcode=0x2A, {"loadImmedT","instrSub1"}, {"loadStackRel","memSaveC","memSaveFlags","instrSub2"}, {"instrNext"}, desc="C=*s+imm8, update zero flag", ccode={"loadimmedt;","cpu.c=loadstackrel; setzf(cpu.c);","lni;"} },
{ mnem="sta *s+imm8", opcode=0x96, {"loadImmedT","instrSub1"}, {"storeStackRel","alurA","instrSub2"}, {"instrNext"}, desc="*s+imm8=A", ccode={"loadimmedt;","storestackrel(cpu.a);","lni;"} },
{ mnem="stb *s+imm8", opcode=0x97, {"loadImmedT","instrSub1"}, {"storeStackRel","alurB","instrSub2"}, {"instrNext"}, desc="*s+imm8=B", ccode={"loadimmedt;","storestackrel(cpu.a);","lni;"} },
{ mnem="stc *s+imm8", opcode=0x98, {"loadImmedT","instrSub1"}, {"storeStackRel","alurC","instrSub2"}, {"instrNext"}, desc="*s+imm8=C", ccode={"loadimmedt;","storestackrel(cpu.a);","lni;"} },
{ mnem="lda *imm16" , opcode=0x51, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2",}, {"adrrUT","loadReg","memSaveA","memSaveFlags","instrSub3"}, {"instrNext"}, desc="A=*imm16, update zero flag", ccode={"loadimm161","loadimm162","cpu.a=loadut; setzf(cpu.a);","lni;"} },
{ mnem="ldb *imm16" , opcode=0x56, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2",}, {"adrrUT","loadReg","memSaveB","memSaveFlags","instrSub3"}, {"instrNext"}, desc="B=*imm16, update zero flag", ccode={"loadimm161","loadimm162","cpu.b=loadut; setzf(cpu.b);","lni;"} },
{ mnem="ldc *imm16" , opcode=0x57, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2",}, {"adrrUT","loadReg","memSaveC","memSaveFlags","instrSub3"}, {"instrNext"}, desc="C=*imm16, update zero flag", ccode={"loadimm161","loadimm162","cpu.c=loadut; setzf(cpu.c);","lni;"} },
{ mnem="sta *imm16" , opcode=0x50, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2",}, {"adrrUT","storeReg","alurA","instrSub3"}, {"instrNext"}, desc="*imm16=A", ccode={"loadimm161","loadimm162","storeut(cpu.a);","lni;"} },
{ mnem="stb *imm16" , opcode=0x58, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2",}, {"adrrUT","storeReg","alurB","instrSub3"}, {"instrNext"}, desc="*imm16=B", ccode={"loadimm161","loadimm162","storeut(cpu.b);","lni;"} },
{ mnem="stc *imm16" , opcode=0x59, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2",}, {"adrrUT","storeReg","alurC","instrSub3"}, {"instrNext"}, desc="*imm16=C", ccode={"loadimm161","loadimm162","storeut(cpu.c);","lni;"} },
{ mnem="sta *p" , opcode=0x52, {"adrlP","storeReg","alurA", "memSaveFlags","instrSub1"}, {"instrNext"}, desc="*P=A", ccode={"storep(cpu.a);","lni;"} },
{ mnem="stb *p" , opcode=0x5A, {"adrlP","storeReg","alurB", "memSaveFlags","instrSub1"}, {"instrNext"}, desc="*P=B", ccode={"storep(cpu.b);","lni;"} },
{ mnem="stc *p" , opcode=0x5B, {"adrlP","storeReg","alurC", "memSaveFlags","instrSub1"}, {"instrNext"}, desc="*P=C", ccode={"storep(cpu.c);","lni;"} },
{ mnem="sta *q" , opcode=0x54, {"adrlQ","storeReg","alurA", "memSaveFlags","instrSub1"}, {"instrNext"}, desc="*Q=A", ccode={"storeq(cpu.a);","lni;"} },
{ mnem="stb *q" , opcode=0x5C, {"adrlQ","storeReg","alurB", "memSaveFlags","instrSub1"}, {"instrNext"}, desc="*Q=B", ccode={"storeq(cpu.b);","lni;"} },
{ mnem="stc *q" , opcode=0x5D, {"adrlQ","storeReg","alurC", "memSaveFlags","instrSub1"}, {"instrNext"}, desc="*Q=C", ccode={"storeq(cpu.c);","lni;"} },
{ mnem="lda *p" , opcode=0x53, {"adrlP","loadReg","memSaveA", "memSaveFlags","instrSub1"}, {"instrNext"}, desc="A=*P, update zero flag", ccode={"cpu.a=loadp; setzf(cpu.a);","lni;"} },
{ mnem="ldb *p" , opcode=0x5E, {"adrlP","loadReg","memSaveB", "memSaveFlags","instrSub1"}, {"instrNext"}, desc="B=*P, update zero flag", ccode={"cpu.b=loadp; setzf(cpu.b);","lni;"} },
{ mnem="ldc *p" , opcode=0x5F, {"adrlP","loadReg","memSaveC", "memSaveFlags","instrSub1"}, {"instrNext"}, desc="C=*P, update zero flag", ccode={"cpu.c=loadp; setzf(cpu.c);","lni;"} },
{ mnem="lda *q" , opcode=0x55, {"adrlQ","loadReg","memSaveA", "memSaveFlags","instrSub1"}, {"instrNext"}, desc="A=*Q, update zero flag", ccode={"cpu.a=loadq; setzf(cpu.a);","lni;"} },
{ mnem="ldb *q" , opcode=0x61, {"adrlQ","loadReg","memSaveB", "memSaveFlags","instrSub1"}, {"instrNext"}, desc="B=*Q, update zero flag", ccode={"cpu.b=loadq; setzf(cpu.b);","lni;"} },
{ mnem="ldc *q" , opcode=0x62, {"adrlQ","loadReg","memSaveC", "memSaveFlags","instrSub1"}, {"instrNext"}, desc="C=*Q, update zero flag", ccode={"cpu.c=loadq; setzf(cpu.c);","lni;"} },
{ mnem="sta *p++" , opcode=0xC0, {"adrlP","storeReg","alurA", "incP","memSaveFlags","instrSub1"}, {"instrNext"}, desc="*P++=A", ccode={"storepinc(cpu.a);","lni;"} },
{ mnem="stb *p++" , opcode=0xC1, {"adrlP","storeReg","alurB", "incP","memSaveFlags","instrSub1"}, {"instrNext"}, desc="*P++=B", ccode={"storepinc(cpu.b);","lni;"} },
{ mnem="stc *p++" , opcode=0xC2, {"adrlP","storeReg","alurC", "incP","memSaveFlags","instrSub1"}, {"instrNext"}, desc="*P++=C", ccode={"storepinc(cpu.c);","lni;"} },
{ mnem="sta *q++" , opcode=0xC3, {"adrlQ","storeReg","alurA", "incQ","memSaveFlags","instrSub1"}, {"instrNext"}, desc="*Q++=A", ccode={"storeqinc(cpu.a);","lni;"} },
{ mnem="stb *q++" , opcode=0xC4, {"adrlQ","storeReg","alurB", "incQ","memSaveFlags","instrSub1"}, {"instrNext"}, desc="*Q++=B", ccode={"storeqinc(cpu.b);","lni;"} },
{ mnem="stc *q++" , opcode=0xC5, {"adrlQ","storeReg","alurC", "incQ","memSaveFlags","instrSub1"}, {"instrNext"}, desc="*Q++=C", ccode={"storeqinc(cpu.c);","lni;"} },
{ mnem="lda *p++" , opcode=0xC6, {"adrlP","loadReg","memSaveA","incP","memSaveFlags","instrSub1"}, {"instrNext"}, desc="A=*P++, update zero flag", ccode={"cpu.a=loadpinc; setzf(cpu.a);","lni;"} },
{ mnem="ldb *p++" , opcode=0xC7, {"adrlP","loadReg","memSaveB","incP","memSaveFlags","instrSub1"}, {"instrNext"}, desc="B=*P++, update zero flag", ccode={"cpu.b=loadpinc; setzf(cpu.b);","lni;"} },
{ mnem="ldc *p++" , opcode=0xC8, {"adrlP","loadReg","memSaveC","incP","memSaveFlags","instrSub1"}, {"instrNext"}, desc="C=*P++, update zero flag", ccode={"cpu.c=loadpinc; setzf(cpu.c);","lni;"} },
{ mnem="lda *q++" , opcode=0xC9, {"adrlQ","loadReg","memSaveA","incQ","memSaveFlags","instrSub1"}, {"instrNext"}, desc="A=*Q++, update zero flag", ccode={"cpu.a=loadqinc; setzf(cpu.a);","lni;"} },
{ mnem="ldb *q++" , opcode=0xCA, {"adrlQ","loadReg","memSaveB","incQ","memSaveFlags","instrSub1"}, {"instrNext"}, desc="B=*Q++, update zero flag", ccode={"cpu.b=loadqinc; setzf(cpu.b);","lni;"} },
{ mnem="ldc *q++" , opcode=0xCB, {"adrlQ","loadReg","memSaveC","incQ","memSaveFlags","instrSub1"}, {"instrNext"}, desc="C=*Q++, update zero flag", ccode={"cpu.c=loadqinc; setzf(cpu.c);","lni;"} },
{ category = "16-bit Load/Store", catlet="W" },
{ mnem="ldp imm16" , opcode=0x21, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"adwrUT","adwSaveP","instrNext"}, desc="P=imm16", ccode={"loadimm161","loadimm162","cpu.p=wordut; lni;"} },
{ mnem="ldq imm16" , opcode=0x23, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"adwrUT","adwSaveQ","instrNext"}, desc="Q=imm16", ccode={"loadimm161","loadimm162","cpu.q=wordut; lni;"} },
{ mnem="lds imm16" , opcode=0x25, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"adwrUT","adwSaveS","instrNext"}, desc="S=imm16", ccode={"loadimm161","loadimm162","cpu.s=wordut; lni;"} },
{ mnem="ldv imm16" , opcode=0x22, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"adwrUT","adwSaveV","instrNext"}, desc="V=imm16", ccode={"loadimm161","loadimm162","cpu.v=wordut; lni;"} },
{ mnem="ldp *s+imm8", opcode=0x7A, {"loadImmedT","instrSub1"}, {"loadStackRel161","instrSub2"}, {"loadStackRel162","instrSub3"}, {"adwrUT","adwSaveP","instrNext"}, desc="P=*S+imm8", ccode={"loadimmedt","loadstackrel161","loadstackrel162","cpu.p=wordut; lni;"} },
{ mnem="ldq *s+imm8", opcode=0x7B, {"loadImmedT","instrSub1"}, {"loadStackRel161","instrSub2"}, {"loadStackRel162","instrSub3"}, {"adwrUT","adwSaveQ","instrNext"}, desc="Q=*S+imm8", ccode={"loadimmedt","loadstackrel161","loadstackrel162","cpu.p=wordut; lni;"} },
{ mnem="stp *s+imm8", opcode=0x7E, {"loadImmedT","instrSub1"}, {"storeStackRel161","alurPH","instrSub2"}, {"storeStackRel162","alurPL","instrSub3"}, {"instrNext"}, desc="*S+imm8=P", ccode={"loadimmedt","storestackrel161(cpu.p);","storestackrel162(cpu.p);","lni;"} },
{ mnem="stq *s+imm8", opcode=0x7F, {"loadImmedT","instrSub1"}, {"storeStackRel161","alurQH","instrSub2"}, {"storeStackRel162","alurQL","instrSub3"}, {"instrNext"}, desc="*S+imm8=Q", ccode={"loadimmedt","storestackrel161(cpu.q);","storestackrel162(cpu.q);","lni;"} },
{ mnem="ldp *imm16" , opcode=0x68, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"loadUTU","adwIncUT","adwSaveP","instrSub3"}, {"adrlP","loadRegT","instrSub4"}, {"adwrUT","adwSaveP","instrNext"}, desc="P=*imm16", ccode={"loadimm161","loadimm162","cpu.p=wordut; cpu.u=loadut;","cpu.t=loadpp1;","cpu.p=wordut; lni;"} }, -- 0x69
{ mnem="ldq *imm16" , opcode=0x6A, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"loadUTU","adwIncUT","adwSaveQ","instrSub3"}, {"adrlQ","loadRegT","instrSub4"}, {"adwrUT","adwSaveQ","instrNext"}, desc="Q=*imm16", ccode={"loadimm161","loadimm162","cpu.q=wordut; cpu.u=loadut;","cpu.t=loadqp1;","cpu.q=wordut; lni;"} }, -- 0x6B
{ mnem="stp *imm16" , opcode=0x6C, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"storeUT","alurPH","instrSub3"}, {"storeUT","adrInc","alurPL","instrSub4"}, {"instrNext"}, desc="*imm16=P", ccode={"loadimm161","loadimm162","storeut(hibyte(cpu.p));","storeutp1(lobyte(cpu.p));","lni;"} }, -- 0x6D
{ mnem="stq *imm16" , opcode=0x6E, {"loadImm161","instrSub1"}, {"loadImm162","instrSub2"}, {"storeUT","alurQH","instrSub3"}, {"storeUT","adrInc","alurQL","instrSub4"}, {"instrNext"}, desc="*imm16=Q", ccode={"loadimm161","loadimm162","storeut(hibyte(cpu.q));","storeutp1(lobyte(cpu.q));","lni;"} }, -- 0x6F
{ mnem="ldp *p" , opcode=0x92, {"adrlP","load161","instrSub1"}, {"adrlP","load162","instrSub2"}, {"adwrUT","adwSaveP","instrNext"}, desc="P=*P", ccode={"cpu.u=loadp;","cpu.t=loadpp1;","cpu.p=wordut; lni;"} },
{ mnem="ldq *p" , opcode=0x93, {"adrlP","load161","instrSub1"}, {"adrlP","load162","instrSub2"}, {"adwrUT","adwSaveQ","instrNext"}, desc="Q=*P", ccode={"cpu.u=loadp;","cpu.t=loadpp1;","cpu.q=wordut; lni;"} },
{ mnem="ldp *q" , opcode=0x94, {"adrlQ","load161","instrSub1"}, {"adrlQ","load162","instrSub2"}, {"adwrUT","adwSaveP","instrNext"}, desc="P=*Q", ccode={"cpu.u=loadq;","cpu.t=loadqp1;","cpu.p=wordut; lni;"} },
{ mnem="ldq *q" , opcode=0x95, {"adrlQ","load161","instrSub1"}, {"adrlQ","load162","instrSub2"}, {"adwrUT","adwSaveQ","instrNext"}, desc="Q=*Q", ccode={"cpu.u=loadq;","cpu.t=loadqp1;","cpu.q=wordut; lni;"} },
{ mnem="stp *q" , opcode=0x7C, {"adrlQ","store161","alurPH","instrSub1"}, {"adrlQ","store162","alurPL","instrSub2"}, {"instrNext"}, desc="*Q=P", ccode={"storeq(hibyte(cpu.p));","storeqp1(lobyte(cpu.p));","lni;"} },
{ mnem="stq *p" , opcode=0x7D, {"adrlP","store161","alurQH","instrSub1"}, {"adrlP","store162","alurQL","instrSub2"}, {"instrNext"}, desc="*P=Q", ccode={"storep(hibyte(cpu.q));","storepp1(lobyte(cpu.q));","lni;"} },
{ mnem="ldq *p++" , opcode=0xCC, {"adrlP","load161","instrSub1"}, {"adrlP","load162","instrSub2","incP2"}, {"adwrUT","adwSaveQ","instrNext"}, desc="Q=*P++++", ccode={"cpu.u=loadpinc;","cpu.t=loadpinc;","cpu.q=wordut; lni;"} },
{ mnem="ldp *q++" , opcode=0xCD, {"adrlQ","load161","instrSub1"}, {"adrlQ","load162","instrSub2","incQ2"}, {"adwrUT","adwSaveP","instrNext"}, desc="P=*Q++++", ccode={"cpu.u=loadqinc;","cpu.t=loadqinc;","cpu.p=wordut; lni;"} },
{ mnem="stp *q++" , opcode=0xCE, {"adrlQ","store161","alurPH","instrSub1"}, {"adrlQ","store162","alurPL","instrSub2","incQ2"}, {"instrNext"}, desc="*Q++++=P", ccode={"storeqinc(hibyte(cpu.p));","storeqinc(lobyte(cpu.p));","lni;"} },
{ mnem="stq *p++" , opcode=0xCF, {"adrlP","store161","alurQH","instrSub1"}, {"adrlP","store162","alurQL","instrSub2","incP2"}, {"instrNext"}, desc="*P++++=Q", ccode={"storepinc(hibyte(cpu.q));","storepinc(lobyte(cpu.q));","lni;"} },
{ category = "Moves", catlet="M" },
{ mnem="lda b" , opcode=0x80, {"alurB" ,"aluOpMov","aluSaveA","instrNext"}, desc="A=B", ccode={"cpu.a=cpu.b; lni;"} },
{ mnem="lda c" , opcode=0x81, {"alurC" ,"aluOpMov","aluSaveA","instrNext"}, desc="A=C", ccode={"cpu.a=cpu.c; lni;"} },
{ mnem="ldb a" , opcode=0x82, {"alurA" ,"aluOpMov","aluSaveB","instrNext"}, desc="B=A", ccode={"cpu.b=cpu.a; lni;"} },
{ mnem="ldb c" , opcode=0x83, {"alurC" ,"aluOpMov","aluSaveB","instrNext"}, desc="B=C", ccode={"cpu.b=cpu.c; lni;"} },
{ mnem="ldc a" , opcode=0x84, {"alurA" ,"aluOpMov","aluSaveC","instrNext"}, desc="C=A", ccode={"cpu.c=cpu.a; lni;"} },
{ mnem="ldc b" , opcode=0x85, {"alurB" ,"aluOpMov","aluSaveC","instrNext"}, desc="C=B", ccode={"cpu.c=cpu.b; lni;"} },
{ mnem="lda pl" , opcode=0x86, {"alurPL","aluOpMov","aluSaveA","instrNext"}, desc="A=P&FF", ccode={"cpu.a=lobyte(cpu.p); lni;"} },
{ mnem="lda ph" , opcode=0x87, {"alurPH","aluOpMov","aluSaveA","instrNext"}, desc="A=P>>8", ccode={"cpu.a=hibyte(cpu.p); lni;"} },
{ mnem="lda ql" , opcode=0x88, {"alurQL","aluOpMov","aluSaveA","instrNext"}, desc="A=Q&FF", ccode={"cpu.a=lobyte(cpu.q); lni;"} },
{ mnem="lda qh" , opcode=0x89, {"alurQH","aluOpMov","aluSaveA","instrNext"}, desc="A=Q>>8", ccode={"cpu.a=hibyte(cpu.q); lni;"} },
{ mnem="ldb pl" , opcode=0x37, {"alurPL","aluOpMov","aluSaveB","instrNext"}, desc="B=P&FF", ccode={"cpu.b=lobyte(cpu.p); lni;"} },
{ mnem="ldc ph" , opcode=0x38, {"alurPH","aluOpMov","aluSaveC","instrNext"}, desc="C=P>>8", ccode={"cpu.c=hibyte(cpu.p); lni;"} },
{ mnem="ldb ql" , opcode=0x39, {"alurQL","aluOpMov","aluSaveB","instrNext"}, desc="B=Q&FF", ccode={"cpu.b=lobyte(cpu.q); lni;"} },
{ mnem="ldc qh" , opcode=0x3A, {"alurQH","aluOpMov","aluSaveC","instrNext"}, desc="C=Q>>8", ccode={"cpu.c=hibyte(cpu.q); lni;"} },
{ mnem="ldp q" , opcode=0x8A, {"adwlQ" , "adwSaveP","instrNext"}, desc="P=Q", ccode={"cpu.p=cpu.q; lni;"} },
{ mnem="ldp s" , opcode=0x8B, {"adwlS" , "adwSaveP","instrNext"}, desc="P=S", ccode={"cpu.p=cpu.s; lni;"} },
{ mnem="ldp v" , opcode=0x8C, {"adwlV" , "adwSaveP","instrNext"}, desc="P=V", ccode={"cpu.p=cpu.v; lni;"} },
{ mnem="ldp i" , opcode=0x8D, {"adwlI" , "adwSaveP","instrNext"}, desc="P=I", ccode={"cpu.p=cpu.i; lni;"} },
{ mnem="ldp cb" , opcode=0x91, {"adwrCB", "adwSaveP","instrNext"}, desc="P=(C<<8)+B", ccode={"cpu.p=wordcb; lni;"} },
{ mnem="ldq cb" , opcode=0xE0, {"adwrCB", "adwSaveQ","instrNext"}, desc="Q=(C<<8)+B", ccode={"cpu.q=wordcb; lni;"} },
{ mnem="ldq p" , opcode=0x8E, {"adwlP" , "adwSaveQ","instrNext"}, desc="Q=P", ccode={"cpu.q=cpu.p; lni;"} },
{ mnem="lds p" , opcode=0x8F, {"adwlP" , "adwSaveS","instrNext"}, desc="S=P", ccode={"cpu.s=cpu.p; lni;"} },
{ mnem="ldv p" , opcode=0x90, {"adwlP" , "adwSaveV","instrNext"}, desc="V=P", ccode={"cpu.v=cpu.p; lni;"} },
},
aliases = {
["jpz imm8"] = {"jeq imm8"},
["jnz imm8"] = {"jne imm8"},
["jmp q" ] = {"ret" },
},
}

View File

@ -1,187 +0,0 @@
local debugInfo = {}
local function getDebugInfo()
return " ("..debugInfo.mnem.." sub "..debugInfo.sub..")"
end
local function hex(n) return string.format("%02X", n) end
local function cycleAddSignals(cycle, cyc2, cyc2t, ops, sigs)
for _, name in ipairs(cycle) do
if ops[name] then
cycleAddSignals(ops[name], cyc2, cyc2t, ops, sigs)
elseif sigs[name] then
if not cyc2t[name] then
cyc2t[name] = true
table.insert(cyc2, name)
else
error("overspecified signal name: "..name..getDebugInfo())
end
else
error("invalid signal name: "..name.." does not name a signal or operation")
end
end
end
local function cycleSimplify(cycle, ops, sigs)
local cyc2, cyc2t = {}, {}
cycleAddSignals(cycle, cyc2, cyc2t, ops, sigs)
return cyc2
end
local function cycleToUcycle(cycle, ops, sigs)
local ucycle = {}
local cyc2 = cycleSimplify(cycle, ops, sigs)
local hasbase = false
local nonempty = false
for _, name in ipairs(cyc2) do
nonempty = true
if name=="always1" then hasbase = true end
local sig = sigs[name]
assert(sig, "no signal named "..name)
for i, sbit in ipairs(sig) do
ucycle[sbit.rom] = ucycle[sbit.rom] or {}
assert(not ucycle[sbit.rom][sbit.bit], "multiply defined bit")
ucycle[sbit.rom][sbit.bit] = true
end
end
if nonempty and (not hasbase) then error("cycle has no base"..getDebugInfo()) end
return ucycle
end
local function encodeInstruction(opcode, instr, ucode, ops, sigs)
for sub, cycle in ipairs(instr) do
debugInfo.sub = sub-1
local ucycle = cycleToUcycle(cycle, ops, sigs)
local uaddr = opcode*4 + (sub-1)
assert(not ucode[uaddr], "overused ucode addr "..uaddr)
ucode[uaddr] = ucycle
end
end
local function sigsFromRoms(roms)
local sigs = {}
for romidx, rom in ipairs(roms) do
for sigidx, sig in ipairs(rom.signals) do
sigs[sig] = sigs[sig] or {}
table.insert(sigs[sig], {
rom = romidx,
bit = sigidx-1,
})
end
end
return sigs
end
local function archToUcode(arch)
local sigs = sigsFromRoms(arch.roms)
local ops = arch.operations
local ucode = {}
local opcodesUsed = {}
local numOpcodesUsed = 0
local infolines = {}
local catlet = "X"
for _, instr in ipairs(arch.instructions) do
if instr.category then
catlet = instr.catlet
table.insert(infolines, "\n")
table.insert(infolines, instr.category.." ("..catlet.."):\n")
else
local mnem = instr.mnem or error("instr has no mnem")
local opcode = instr.opcode or error("instr has no opcode "..mnem)
local ncycles = instr.ncycles or #instr
assert(#instr <= 8, "operation too long "..opcode)
local len = math.ceil(#instr / 4)
if len>1 then assert(opcode%2==0, "len>1 on odd opcode") end
for i = 1, len do
local opcode2 = opcode+i-1
assert(not opcodesUsed[opcode2], "overused opcode "..hex(opcode))
opcodesUsed[opcode2] = catlet
numOpcodesUsed = numOpcodesUsed+1
end
debugInfo.mnem = mnem
encodeInstruction(opcode, instr, ucode, ops, sigs)
if instr.desc then
table.insert(infolines, mnem..(" "):rep(13-#mnem)..hex(opcode).." "..ncycles.." "..instr.desc.."\n")
end
end
end
local lt = {"Opcodes used: "..numOpcodesUsed.."/255\n", " "}
for i = 0, 15 do table.insert(lt, hex(i):sub(2, 2)) end
table.insert(lt, "\n")
for line = 0, 255, 16 do
table.insert(lt, hex(line).." | ")
for opcode = line, line+15 do
if opcodesUsed[opcode] then table.insert(lt, opcodesUsed[opcode])
else table.insert(lt, "-") end
end
table.insert(lt, "\n")
end
local info = table.concat(infolines).."\n"..table.concat(lt)
print(info)
local fo = io.open("instructionList.txt", "w")
if fo then
fo:write(info)
fo:close()
end
return ucode
end
local function ucodeToBricks(ucode, roms)
local bricks = {}
for uaddr, ucycle in pairs(ucode) do
for romidx, uline in ipairs(ucycle) do
for bitidx, t in pairs(uline) do
local rom = roms[romidx]
assert(bitidx >=0 and bitidx <= rom.size[3]-1)
local x = rom.pos[1] + (uaddr % rom.size[1])
local y = rom.pos[2] - math.floor(uaddr / rom.size[1])
local z = rom.pos[3] + bitidx
bricks[x] = bricks[x] or {}
bricks[x][y] = bricks[x][y] or {}
assert(not bricks[x][y][z], "overlapping brick at "..x.." "..y.." "..z)
bricks[x][y][z] = true
end
end
end
return bricks
end
ts = ts or {
eval = function() end,
call = function() end,
}
ts.eval [[
function commandShiftBrick(%x, %y, %z) { commandToServer('shiftBrick', %x, %y, %z); }
function commandPlantBrick() { commandToServer('plantBrick'); }
]]
local function plantBrickAt(pos, brickPos)
local dx, dy, dz = pos[1]-brickPos[1], pos[2]-brickPos[2], pos[3]-brickPos[3]
ts.call("commandShiftBrick", dy, -dx, dz)
brickPos[1] = pos[1]; brickPos[2] = pos[2]; brickPos[3] = pos[3];
ts.call("commandPlantBrick")
end
local function buildBricks(bricks)
local brickPos = {0, 0, 0}
for x, xb in pairs(bricks) do
for y, xyb in pairs(xb) do
for z, t in pairs(xyb) do
plantBrickAt({x, y, z}, brickPos)
end
end
end
end
local function buildArch(arch)
local ucode = archToUcode(arch)
local bricks = ucodeToBricks(ucode, arch.roms)
buildBricks(bricks)
end
local arch = require("rom-8608-defs")
buildArch(arch)

View File

@ -1,88 +0,0 @@
。 A1
「 A2
」 A3
、 A4
・ A5
ヲ A6
ァ A7
ィ A8
ゥ A9
ェ AA
ォ AB
ャ AC
ュ AD
ョ AE
ッ AF
ー B0
ア B1
イ B2
ウ B3
エ B4
オ B5
カ B6
キ B7
ク B8
ケ B9
コ BA
サ BB
シ BC
ス BD
セ BE
ソ BF
タ C0
チ C1
ツ C2
テ C3
ト C4
ナ C5
ニ C6
ヌ C7
ネ C8
C9
ハ CA
ヒ CB
フ CC
ヘ CD
ホ CE
マ CF
ミ D0
ム D1
メ D2
モ D3
ヤ D4
ユ D5
ヨ D6
ラ D7
リ D8
ル D9
レ DA
ロ DB
ワ DC
ン DD
゛ DE
゜ DF
ガ B6 DE
ギ B7 DE
グ B8 DE
ゲ B9 DE
ゴ BA DE
ザ BB DE
ジ BC DE
ズ BD DE
ゼ BE DE
ゾ BF DE
ダ C0 DE
ヂ C1 DE
ヅ C2 DE
デ C3 DE
ド C4 DE
バ CA DE
ビ CB DE
ブ CC DE
ベ CD DE
ボ CE DE
パ CA DF
ピ CB DF
プ CC DF
ペ CD DF
ポ CE DF