diff --git a/lips/Preproc.lua b/lips/Preproc.lua index 06778c7..ab68da2 100644 --- a/lips/Preproc.lua +++ b/lips/Preproc.lua @@ -211,7 +211,7 @@ function Preproc:pop(kind) end function Preproc:expand(statements) - -- third pass: expand pseudo-instructions + -- third pass: expand pseudo-instructions and register arguments self.statements = {} for i=1, #statements do local s = statements[i] @@ -227,6 +227,23 @@ function Preproc:expand(statements) error('Internal Error: unknown instruction') end + if data.one_register_variants[name] then + self.i = 1 + local a = self:register(data.all_registers) + local b = s[2] + if b == nil or b.tt ~= 'REG' then + insert(s, 2, self:token(a)) + end + elseif data.two_register_variants[name] then + self.i = 1 + local a = self:register(data.all_registers) + local b = self:register(data.all_registers) + local c = s[3] + if c == nil or c.tt ~= 'REG' then + insert(s, 2, self:token(a)) + end + end + if overrides[name] then self.i = 1 overrides[name](self, name) diff --git a/lips/data.lua b/lips/data.lua index 2ce6444..079df18 100644 --- a/lips/data.lua +++ b/lips/data.lua @@ -86,7 +86,13 @@ data.fmt_double = 17 data.fmt_word = 20 data.fmt_long = 21 +-- set up dummy values for pseudo-instructions later local __ = {} +-- instructions with the first two arguments as registers, but not the third +local o1 = {} +-- instructions with all three arguments as registers +local o2 = {} + data.instructions = { --[[ data guide: @@ -248,6 +254,7 @@ data.instructions = { -- coprocessor-related instructions + -- TODO: these can take a code value TEQ = {0, 'st', 'st00C', 52}, TGE = {0, 'st', 'st00C', 48}, TGEU = {0, 'st', 'st00C', 49}, @@ -280,6 +287,7 @@ data.instructions = { CACHE = {47, 'iob', 'bio'}, -- misuses 'F' to write the initial bit +-- RFE = {16, '', 'F000C', 16, 16}, ERET = {16, '', 'F000C', 24, 16}, TLBP = {16, '', 'F000C', 8, 16}, TLBR = {16, '', 'F000C', 1, 16}, @@ -381,8 +389,11 @@ data.instructions = { CL = { 0, 'd', '00d0C', 37}, -- OR RD, R0, R0 MOV = { 0, 'ds', 's0d0C', 37}, -- OR RD, RS, R0 NEG = { 0, 'dt', '0td0C', 34}, -- SUB RD, R0, RT + NEGU = { 0, 'dt', '0td0C', 35}, -- SUBU RD, R0, RT NOP = { 0, '', '0'}, -- SLL R0, R0, 0 NOT = { 0, 'ds', 's0d0C', 39}, -- NOR RD, RS, R0 + SGT = { 0, 'dst', 'tsd0C', 42}, -- SLT RD, RT, RS + SGTU = { 0, 'dst', 'tsd0C', 43}, -- SLTU RD, RT, RS SUBI = { 8, 'tsk', 'sti'}, -- ADDI RT, RS, -immediate SUBIU = { 9, 'tsk', 'sti'}, -- ADDIU RT, RS, -immediate @@ -394,41 +405,95 @@ data.instructions = { PUSH = __, POP = __, JPOP = __, +-- CL = __, overridden to take varargs - ABS = __, -- BGEZ NOP SUBU? - MUL = __, -- MULT MFLO - --DIV = __, -- 3 arguments - REM = __, -- 3 arguments + ABS = o1, -- SRA XOR SUBU + MUL = o2, -- MULT MFLO +-- DIV = o2, -- 3 arguments + REM = o2, -- 3 arguments - NAND = __, -- AND, NOT - NANDI = __, -- ANDI, NOT - NORI = __, -- ORI, NOT - ROL = __, -- SLL, SRL, OR - ROR = __, -- SRL, SLL, OR + NAND = o2, -- AND, NOT + NANDI = o1, -- ANDI, NOT + NORI = o1, -- ORI, NOT + ROL = o1, -- SLL, SRL, OR + ROR = o1, -- SRL, SLL, OR - SEQ = __, SEQI = __, SEQIU = __, SEQU = __, - SGE = __, SGEI = __, SGEIU = __, SGEU = __, - SGT = __, SGTI = __, SGTIU = __, SGTU = __, - SLE = __, SLEI = __, SLEIU = __, SLEU = __, - SNE = __, SNEI = __, SNEIU = __, SNEU = __, + SEQ = o2, + SGE = o2, SGEU = o2, + SLE = o2, SLEU = o2, + SNE = o2, - BGE = __, - BLE = __, - BLT = __, - BGT = __, + SEQI = o1, SEQIU = o1, + SGEI = o1, SGEIU = o1, + SGTI = o1, SGTIU = o1, + SLEI = o1, SLEIU = o1, + SNEI = o1, SNEIU = o1, + + BGE = o1, BGEU = o1, + BLE = o1, BLEU = o1, + BLT = o1, BLTU = o1, + BGT = o1, BGTU = o1, BEQI = __, BEQIL = __, - BNEI = __, BNEIL = __, BGEI = __, BGEIL = __, + BGTI = __, BGTIL = __, BLEI = __, BLEIL = __, BLTI = __, BLTIL = __, - BGTI = __, BGTIL = __, + BNEI = __, BNEIL = __, + + BGEL = o1, BGEUL = o1, + BGTL = o1, BGTUL = o1, + BLEL = o1, BLEUL = o1, + BLTL = o1, BLTUL = o1, + } +local register_types = { + d = 0, + s = 0, + t = 0, + D = 1, + S = 1, + T = 1, + X = 2, + Y = 2, + Z = 2, +} + +data.one_register_variants = {} +data.two_register_variants = {} + data.all_instructions = {} local i = 1 for k, v in pairs(data.instructions) do - data.all_instructions[k:gsub('_', '.')] = i + local name = k:gsub('_', '.') + + -- if the first two args of an instructions are the same register type, + -- allow it to be used with just one argument to cover both. + -- likewise, if all three arguments are registers of the same type, + -- allow just two to be used. + local fmt = v[2] + if fmt then + local a = fmt:sub(1, 1) + local b = fmt:sub(2, 2) + local c = fmt:sub(3, 3) + a = register_types[a] + b = register_types[b] + c = register_types[c] + if a ~= nil and b ~= nil and a == b then + if c == nil then + data.one_register_variants[name] = true + elseif c == a then + data.two_register_variants[name] = true + end + end + elseif v == o1 then + data.one_register_variants[name] = true + elseif v == o2 then + data.two_register_variants[name] = true + end + + data.all_instructions[name] = i i = i + 1 end revtable(data.all_instructions) diff --git a/lips/overrides.lua b/lips/overrides.lua index 137bd47..7cdc7a5 100644 --- a/lips/overrides.lua +++ b/lips/overrides.lua @@ -177,6 +177,22 @@ function overrides:ROL(name) end overrides.ROR = overrides.ROL +function overrides:ABS(name) + local dest = self:pop('CPU') + local src = self:pop('CPU') + self:push_new('SRA', 'AT', src, 31) + self:push_new('XOR', dest, src, 'AT') + self:push_new('SUBU', dest, dest, 'AT') +end + +function overrides:CL(name) + self:expect{'REG'} -- assert there's at least one argument + for i=1, #self.s do + local reg = self:pop('CPU') + self:push_new('CL', reg) + end +end + function overrides:JR(name) local src = self:peek() and self:pop('CPU') or 'RA' self:push_new('JR', src)