diff --git a/lips/Dumper.lua b/lips/Dumper.lua index bdae542..3563eaf 100644 --- a/lips/Dumper.lua +++ b/lips/Dumper.lua @@ -36,6 +36,8 @@ function Dumper:export_labels(t) end function Dumper:label_delta(from, to) + from = from % 0x80000000 + to = to % 0x80000000 local rel = floor(to/4) - 1 - floor(from/4) if rel > 0x8000 or rel <= -0x8000 then self:error('branch too far', rel) @@ -44,12 +46,10 @@ function Dumper:label_delta(from, to) end function Dumper:desym(t) - if t.tt == 'REL' then - return t.tok + -- note: don't run t:compute() here; let valvar handle that + if t.tt == 'REL' and not t.fixed then + return self:label_delta(self:pc(), t.tok) elseif type(t.tok) == 'number' then - if t.offset then - return t.tok + t.offset - end return t.tok elseif t.tt == 'REG' then assert(data.all_registers[t.tok], 'Internal Error: unknown register') @@ -59,9 +59,6 @@ function Dumper:desym(t) if label == nil then self:error('undefined label', t.tok) end - if t.offset then - label = label + t.offset - end if t.tt == 'LABELSYM' then return label end @@ -138,6 +135,7 @@ function Dumper:format_in(informat) -- see data.lua for a guide on what all these mean local args = {} --if #informat ~= #s then error('mismatch') end + self.i = 0 for i=1, #informat do self.i = i local c = informat:sub(i, i) @@ -168,7 +166,7 @@ function Dumper:format_in(informat) elseif c == 'I' and not args.index then args.index = self:const():set('index') elseif c == 'k' and not args.immediate then - args.immediate = self:const(nil, 'no label'):set('negate') + args.immediate = self:const(nil, 'no label'):set('signed'):set('negate') elseif c == 'K' and not args.immediate then args.immediate = self:const(nil, 'no label'):set('signed') elseif c == 'b' and not args.base then @@ -220,6 +218,9 @@ function Dumper:assemble(s) self.s = s if h[2] ~= nil then local args = self:format_in(h[2]) + if self.i ~= #s then + self:error('expected EOL; too many arguments') + end return self:format_out(h, args) else self:error('unimplemented instruction', name) diff --git a/lips/Muncher.lua b/lips/Muncher.lua index 355ee6c..a9794ed 100644 --- a/lips/Muncher.lua +++ b/lips/Muncher.lua @@ -122,13 +122,6 @@ function Muncher:const(relative, no_label) self:error('labels are not allowed here', self.tt) end local t = self:token(self.t) - if relative then - if self.tt == 'LABELSYM' then - t.tt = 'LABELREL' - else - t.tt = 'REL' - end - end self:advance() return t end diff --git a/lips/Parser.lua b/lips/Parser.lua index 78c66f6..66d2766 100644 --- a/lips/Parser.lua +++ b/lips/Parser.lua @@ -41,14 +41,25 @@ function Parser:tokenize(asm) end function Parser:debug_dump() + local boring = { + tt = true, + tok = true, + fn = true, + line = true, + } for i, s in ipairs(self.statements) do local values = '' - for j, v in ipairs(s) do - local tok = v.tok + for j, t in ipairs(s) do + local tok = t.tok if type(tok) == 'number' then tok = ("$%X"):format(tok) end - values = values..'\t'..v.tt..'('..tostring(tok)..')' + values = values..'\t'..t.tt..'('..tostring(tok)..')' + for k, v in pairs(t) do + if not boring[k] then + values = values..'['..k..'='..tostring(v)..']' + end + end end values = values:sub(2) print(s.line, s.type, values) @@ -62,14 +73,17 @@ function Parser:parse(asm) local preproc = Preproc(self.options) self.statements = preproc:process(self.statements) - self.statements = preproc:expand(self.statements) if self.options.debug_pre then self:debug_dump() end + self.statements = preproc:expand(self.statements) + + if self.options.debug_post then self:debug_dump() end + local dumper = Dumper(self.writer, self.options) self.statements = dumper:load(self.statements) - if self.options.debug_dump then self:debug_dump() end + if self.options.debug_asm then self:debug_dump() end if self.options.labels then dumper:export_labels(self.options.labels) diff --git a/lips/Preproc.lua b/lips/Preproc.lua index 60ba783..06778c7 100644 --- a/lips/Preproc.lua +++ b/lips/Preproc.lua @@ -198,11 +198,9 @@ function Preproc:pop(kind) ret = self:deref() elseif kind == 'CONST' then ret = self:const() - elseif kind == 'REL' then - ret = self:const('REL') elseif kind == 'END' then - if self.s[self.i + 1] ~= nil then - self:error('too many arguments') + if self.s[self.i] ~= nil then + self:error('expected EOL; too many arguments') end return -- don't increment self.i past end of arguments else diff --git a/lips/Reader.lua b/lips/Reader.lua index f405edb..ca1468a 100644 --- a/lips/Reader.lua +++ b/lips/Reader.lua @@ -68,7 +68,7 @@ function Reader:const(relative, no_label) self:expect{'NUM', 'LABELREL'} end local new = Token(t) - if relative then + if relative then -- you probably shouldn't use this in Preproc if t.tt == 'LABELSYM' then new.tt = 'LABELREL' elseif t.tt == 'NUM' then diff --git a/lips/Token.lua b/lips/Token.lua index 482b9f8..1911034 100644 --- a/lips/Token.lua +++ b/lips/Token.lua @@ -68,11 +68,15 @@ function Token:set(key, value) return self end -function Token:compute() - assert(self.tt == 'NUM', 'Internal Error: cannot compute a non-number token') - local n = self.tok +function Token:compute(n) + local n = n or self.tok + assert(n or self.tt == 'NUM', 'Internal Error: cannot compute a non-number token') + + if self.offset then + n = n + self.offset + end + if self.index then - -- TODO: should this still be here now that we have .base? n = n % 0x80000000 n = floor(n/4) end @@ -94,7 +98,7 @@ function Token:compute() n = upper end - if self.negate or self.signed then + if self.signed then if n >= 0x10000 or n < -0x8000 then return n, 'value out of range' end diff --git a/lips/overrides.lua b/lips/overrides.lua index 1850183..137bd47 100644 --- a/lips/overrides.lua +++ b/lips/overrides.lua @@ -201,7 +201,7 @@ function overrides:BEQI(name) local branch = branch_basics[name] local reg = self:pop('CPU') local im = self:pop('CONST') - local offset = self:pop('REL'):set('signed') + local offset = self:pop('CONST') if reg == 'AT' then self:error('register cannot be AT in this pseudo-instruction') @@ -219,7 +219,7 @@ function overrides:BLTI(name) local branch = branch_basics[name] local reg = self:pop('CPU') local im = self:pop('CONST') - local offset = self:pop('REL'):set('signed') + local offset = self:pop('CONST') if reg == 'AT' then self:error('register cannot be AT in this pseudo-instruction') @@ -241,7 +241,7 @@ function overrides:BLEI(name) local branch = branch_basics[name] local reg = self:pop('CPU') local im = self:pop('CONST') - local offset = self:pop('REL'):set('signed') + local offset = self:pop('CONST') if reg == 'AT' then self:error('register cannot be AT in this pseudo-instruction') @@ -253,7 +253,8 @@ function overrides:BLEI(name) if name == 'BLEI' or name =='BLEIL' then beq_offset = offset else - beq_offset = 2 -- branch to delay slot of the next branch + -- branch to delay slot of the next branch + beq_offset = self:token('NUM', 2):set('fixed') end self:push_new('BEQ', reg, 'AT', beq_offset)