-- 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
