diff --git a/example.lua b/example.lua index e76873c..3fa85f9 100644 --- a/example.lua +++ b/example.lua @@ -1,6 +1,6 @@ package.path = package.path..";?/init.lua" local lips = require "lips" -local err = lips('example.asm', nil, {offset=0}) +local err = lips('example.asm') if err then print(err) end diff --git a/lips/Dumper.lua b/lips/Dumper.lua index 769d989..bdae542 100644 --- a/lips/Dumper.lua +++ b/lips/Dumper.lua @@ -45,7 +45,7 @@ end function Dumper:desym(t) if t.tt == 'REL' then - return self:label_delta(self:pc(), t.tok) + return t.tok elseif type(t.tok) == 'number' then if t.offset then return t.tok + t.offset diff --git a/lips/init.lua b/lips/init.lua index 9e823b7..f7f6242 100644 --- a/lips/init.lua +++ b/lips/init.lua @@ -53,6 +53,7 @@ function lips.assemble(fn_or_asm, writer, options) options.origin = options.offset options.base = 0 else + options.origin = options.origin or 0 options.base = options.base or 0x80000000 end diff --git a/lips/overrides.lua b/lips/overrides.lua index 70ac6ea..1850183 100644 --- a/lips/overrides.lua +++ b/lips/overrides.lua @@ -8,7 +8,7 @@ local overrides = {} local function tob_override(self, name) -- handle all the addressing modes for lw/sw-like instructions - local rt = self:pop('CPU') + local dest = self:pop('CPU') local offset, base if self:peek('DEREF') then offset = 0 @@ -28,12 +28,12 @@ local function tob_override(self, name) end -- attempt to use the fewest possible instructions for this offset if not o.portion and (o.tt == 'LABELSYM' or o.tok >= 0x80000000) then - local immediate = self:token(o):set('portion', 'upperoff') - self:push_new('LUI', 'AT', immediate) + local temp = self:token(o):set('portion', 'upperoff') + self:push_new('LUI', 'AT', temp) if self.s[self.i] ~= nil then local reg = self:pop('DEREF'):set('tt', 'REG') if reg.tok ~= 'R0' then - self:push_new('ADDU', 'AT', 'AT', 'R0') + self:push_new('ADDU', 'AT', 'AT', reg) end end base = self:token('DEREF', 'AT') @@ -41,7 +41,7 @@ local function tob_override(self, name) base = self:pop('DEREF') end end - self:push_new(name, rt, offset, base) + self:push_new(name, dest, offset, base) end for k, v in pairs(data.instructions) do @@ -50,8 +50,8 @@ for k, v in pairs(data.instructions) do end end -function overrides.LI(self, name) - local rt = self:pop('CPU') +function overrides:LI(name) + local dest = self:pop('CPU') local im = self:pop('CONST') -- for us, this is just semantics. for a "real" assembler, @@ -62,40 +62,38 @@ function overrides.LI(self, name) if im.portion then -- FIXME: use appropriate instruction based on portion? - self:push_new('ADDIU', rt, 'R0', im) + self:push_new('ADDIU', dest, 'R0', im) return end im.tok = im.tok % 0x100000000 if im.tok >= 0x10000 and im.tok <= 0xFFFF8000 then - local rs = rt - local immediate = self:token(im):set('portion', 'upper') - self:push_new('LUI', rt, immediate) + local temp = self:token(im):set('portion', 'upper') + self:push_new('LUI', dest, temp) if im.tok % 0x10000 ~= 0 then - local immediate = self:token(im):set('portion', 'lower') - self:push_new('ORI', rt, rs, immediate) + local temp = self:token(im):set('portion', 'lower') + self:push_new('ORI', dest, dest, temp) end elseif im.tok >= 0x8000 and im.tok < 0x10000 then - local immediate = self:token(im):set('portion', 'lower') - self:push_new('ORI', rt, 'R0', immediate) + local temp = self:token(im):set('portion', 'lower') + self:push_new('ORI', dest, 'R0', temp) else - local immediate = self:token(im):set('portion', 'lower') - self:push_new('ADDIU', rt, 'R0', immediate) + local temp = self:token(im):set('portion', 'lower') + self:push_new('ADDIU', dest, 'R0', temp) end end -function overrides.LA(self, name) - local rt = self:pop('CPU') +function overrides:LA(name) + local dest = self:pop('CPU') local im = self:pop('CONST') - local rs = rt - local immediate = self:token(im):set('portion', 'upperoff') - self:push_new('LUI', rt, immediate) - local immediate = self:token(im):set('portion', 'lower') - self:push_new('ADDIU', rt, rt, immediate) + local im = self:token(im):set('portion', 'upperoff') + self:push_new('LUI', dest, im) + local im = self:token(im):set('portion', 'lower') + self:push_new('ADDIU', dest, dest, im) end -function overrides.PUSH(self, name) +function overrides:PUSH(name) local w = name == 'PUSH' and 'SW' or 'LW' local stack = {} for _, t in ipairs(self.s) do @@ -115,8 +113,8 @@ function overrides.PUSH(self, name) self:error(name..' requires at least one argument') end if name == 'PUSH' then - local immediate = self:token(#stack*4):set('negate') - self:push_new('ADDIU', 'SP', 'SP', immediate) + local im = self:token(#stack*4):set('negate') + self:push_new('ADDIU', 'SP', 'SP', im) end for i, r in ipairs(stack) do if r ~= '' then @@ -128,65 +126,60 @@ function overrides.PUSH(self, name) self:push_new('JR', 'RA') end if name == 'POP' or name == 'JPOP' then - local immediate = #stack * 4 - self:push_new('ADDIU', 'SP', 'SP', immediate) + local im = #stack * 4 + self:push_new('ADDIU', 'SP', 'SP', im) end end overrides.POP = overrides.PUSH overrides.JPOP = overrides.PUSH -function overrides.NAND(self, name) - local rd = self:pop('CPU') - local rs = self:pop('CPU') - local rt = self:pop('CPU') - self:push_new('AND', rd, rs, rt) - local rs = rd - local rt = 'R0' - self:push_new('NOR', rd, rs, rt) +function overrides:NAND(name) + local dest = self:pop('CPU') + local src = self:pop('CPU') + local target = self:pop('CPU') + self:push_new('AND', dest, src, target) + self:push_new('NOR', dest, dest, 'R0') -- NOT end -function overrides.NANDI(self, name) - local rt = self:pop('CPU') - local rs = self:pop('CPU') - local immediate = self:pop('CONST') - self:push_new('ANDI', rt, rs, immediate) - local rd = rt - local rs = rt - local rt = 'R0' - self:push_new('NOR', rd, rs, rt) +function overrides:NANDI(name) + local dest = self:pop('CPU') + local src = self:pop('CPU') + local im = self:pop('CONST') + self:push_new('ANDI', dest, src, im) + self:push_new('NOR', dest, dest, 'R0') -- NOT end -function overrides.NORI(self, name) - local rt = self:pop('CPU') - local rs = self:pop('CPU') - local immediate = self:pop('CONST') - self:push_new('ORI', rt, rs, immediate) - local rd = rt - local rs = rt - local rt = 'R0' - self:push_new('NOR', rd, rs, rt) +function overrides:NORI(name) + local dest = self:pop('CPU') + local src = self:pop('CPU') + local im = self:pop('CONST') + self:push_new('ORI', dest, src, im) + self:push_new('NOR', dest, dest, 'R0') -- NOT end -function overrides.ROL(self, name) - -- FIXME - local rd, rs, rt - local left = self:pop('CPU') - rt = self:pop('CPU') - local immediate = self:pop('CONST') - error('Internal Error: unimplemented') -end +function overrides:ROL(name) + local first = name == 'ROL' and 'SLL' or 'SRL' + local second = name == 'ROL' and 'SRL' or 'SLL' + local dest = self:pop('CPU') + local src = self:pop('CPU') + local im = self:pop('CONST') + if dest == 'AT' or src == 'AT' then + self:error('registers cannot be AT in this pseudo-instruction') + end -function overrides.ROR(self, name) - -- FIXME - local right = self:pop('CPU') - local rt = self:pop('CPU') - local immediate = self:pop('CONST') - error('Internal Error: unimplemented') + self:push_new(first, dest, src, im) + local temp, err = im:compute() + if err then + self:error(err, temp) + end + self:push_new(second, 'AT', src, 32 - temp) + self:push_new('OR', dest, dest, 'AT') end +overrides.ROR = overrides.ROL -function overrides.JR(self, name) - local rs = self:peek() and self:pop('CPU') or 'RA' - self:push_new('JR', rs) +function overrides:JR(name) + local src = self:peek() and self:pop('CPU') or 'RA' + self:push_new('JR', src) end local branch_basics = { @@ -204,17 +197,17 @@ local branch_basics = { BNEIL = 'BNEL', } -function overrides.BEQI(self, name) +function overrides:BEQI(name) local branch = branch_basics[name] local reg = self:pop('CPU') - local immediate = self:pop('CONST') + local im = self:pop('CONST') local offset = self:pop('REL'):set('signed') if reg == 'AT' then self:error('register cannot be AT in this pseudo-instruction') end - self:push_new('ADDIU', 'AT', 'R0', immediate) + self:push_new('ADDIU', 'AT', 'R0', im) self:push_new(branch, reg, 'AT', offset) end @@ -222,17 +215,17 @@ overrides.BNEI = overrides.BEQI overrides.BEQIL = overrides.BEQI overrides.BNEIL = overrides.BEQI -function overrides.BLTI(self, name) +function overrides:BLTI(name) local branch = branch_basics[name] local reg = self:pop('CPU') - local immediate = self:pop('CONST') + local im = self:pop('CONST') local offset = self:pop('REL'):set('signed') if reg == 'AT' then self:error('register cannot be AT in this pseudo-instruction') end - self:push_new('SLTI', 'AT', reg, immediate) + self:push_new('SLTI', 'AT', reg, im) self:push_new(branch, 'R0', 'AT', offset) end @@ -240,29 +233,31 @@ overrides.BGEI = overrides.BLTI overrides.BLTIL = overrides.BLTI overrides.BGEIL = overrides.BLTI -function overrides.BLEI(self, name) +function overrides:BLEI(name) -- TODO: this can probably be optimized + if name:sub(#name) == 'L' then + self:error('unimplemented pseudo-instruction', name) + end local branch = branch_basics[name] local reg = self:pop('CPU') - local immediate = self:pop('CONST') + local im = self:pop('CONST') local offset = self:pop('REL'):set('signed') if reg == 'AT' then self:error('register cannot be AT in this pseudo-instruction') end - self:push_new('ADDIU', 'AT', 'R0', immediate) + self:push_new('ADDIU', 'AT', 'R0', im) local beq_offset - if name == 'BLEI' then + if name == 'BLEI' or name =='BLEIL' then beq_offset = offset else - -- FIXME: this probably isn't correct for branch-likely instructions beq_offset = 2 -- branch to delay slot of the next branch end - self:push_new('BEQ', reg, 'R0', beq_offset) + self:push_new('BEQ', reg, 'AT', beq_offset) - self:push_new('SLTI', 'AT', reg, immediate) + self:push_new('SLT', 'AT', reg, 'AT') self:push_new(branch, 'AT', 'R0', offset) end