1
0
Fork 0
mirror of https://github.com/notwa/lips synced 2024-04-30 09:03:23 -07:00

various fixes, mostly for labels

reimplement modulo by 0x80000000 for labels.
allow numeric label values ("REL") to be "fixed" to bypass label calculation.
add offsets after label calculation instead of before.
properly check for EOL after all expected arguments have been exhausted.
finally, add token properties to debug dumps.
This commit is contained in:
Connor Olding 2016-04-24 03:55:12 -07:00
parent 6433227c26
commit f851540b24
7 changed files with 46 additions and 35 deletions

View File

@ -36,6 +36,8 @@ function Dumper:export_labels(t)
end end
function Dumper:label_delta(from, to) function Dumper:label_delta(from, to)
from = from % 0x80000000
to = to % 0x80000000
local rel = floor(to/4) - 1 - floor(from/4) local rel = floor(to/4) - 1 - floor(from/4)
if rel > 0x8000 or rel <= -0x8000 then if rel > 0x8000 or rel <= -0x8000 then
self:error('branch too far', rel) self:error('branch too far', rel)
@ -44,12 +46,10 @@ function Dumper:label_delta(from, to)
end end
function Dumper:desym(t) function Dumper:desym(t)
if t.tt == 'REL' then -- note: don't run t:compute() here; let valvar handle that
return t.tok if t.tt == 'REL' and not t.fixed then
return self:label_delta(self:pc(), t.tok)
elseif type(t.tok) == 'number' then elseif type(t.tok) == 'number' then
if t.offset then
return t.tok + t.offset
end
return t.tok return t.tok
elseif t.tt == 'REG' then elseif t.tt == 'REG' then
assert(data.all_registers[t.tok], 'Internal Error: unknown register') assert(data.all_registers[t.tok], 'Internal Error: unknown register')
@ -59,9 +59,6 @@ function Dumper:desym(t)
if label == nil then if label == nil then
self:error('undefined label', t.tok) self:error('undefined label', t.tok)
end end
if t.offset then
label = label + t.offset
end
if t.tt == 'LABELSYM' then if t.tt == 'LABELSYM' then
return label return label
end end
@ -138,6 +135,7 @@ function Dumper:format_in(informat)
-- see data.lua for a guide on what all these mean -- see data.lua for a guide on what all these mean
local args = {} local args = {}
--if #informat ~= #s then error('mismatch') end --if #informat ~= #s then error('mismatch') end
self.i = 0
for i=1, #informat do for i=1, #informat do
self.i = i self.i = i
local c = informat:sub(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 elseif c == 'I' and not args.index then
args.index = self:const():set('index') args.index = self:const():set('index')
elseif c == 'k' and not args.immediate then 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 elseif c == 'K' and not args.immediate then
args.immediate = self:const(nil, 'no label'):set('signed') args.immediate = self:const(nil, 'no label'):set('signed')
elseif c == 'b' and not args.base then elseif c == 'b' and not args.base then
@ -220,6 +218,9 @@ function Dumper:assemble(s)
self.s = s self.s = s
if h[2] ~= nil then if h[2] ~= nil then
local args = self:format_in(h[2]) 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) return self:format_out(h, args)
else else
self:error('unimplemented instruction', name) self:error('unimplemented instruction', name)

View File

@ -122,13 +122,6 @@ function Muncher:const(relative, no_label)
self:error('labels are not allowed here', self.tt) self:error('labels are not allowed here', self.tt)
end end
local t = self:token(self.t) 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() self:advance()
return t return t
end end

View File

@ -41,14 +41,25 @@ function Parser:tokenize(asm)
end end
function Parser:debug_dump() function Parser:debug_dump()
local boring = {
tt = true,
tok = true,
fn = true,
line = true,
}
for i, s in ipairs(self.statements) do for i, s in ipairs(self.statements) do
local values = '' local values = ''
for j, v in ipairs(s) do for j, t in ipairs(s) do
local tok = v.tok local tok = t.tok
if type(tok) == 'number' then if type(tok) == 'number' then
tok = ("$%X"):format(tok) tok = ("$%X"):format(tok)
end 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 end
values = values:sub(2) values = values:sub(2)
print(s.line, s.type, values) print(s.line, s.type, values)
@ -62,14 +73,17 @@ function Parser:parse(asm)
local preproc = Preproc(self.options) local preproc = Preproc(self.options)
self.statements = preproc:process(self.statements) self.statements = preproc:process(self.statements)
self.statements = preproc:expand(self.statements)
if self.options.debug_pre then self:debug_dump() end 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) local dumper = Dumper(self.writer, self.options)
self.statements = dumper:load(self.statements) 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 if self.options.labels then
dumper:export_labels(self.options.labels) dumper:export_labels(self.options.labels)

View File

@ -198,11 +198,9 @@ function Preproc:pop(kind)
ret = self:deref() ret = self:deref()
elseif kind == 'CONST' then elseif kind == 'CONST' then
ret = self:const() ret = self:const()
elseif kind == 'REL' then
ret = self:const('REL')
elseif kind == 'END' then elseif kind == 'END' then
if self.s[self.i + 1] ~= nil then if self.s[self.i] ~= nil then
self:error('too many arguments') self:error('expected EOL; too many arguments')
end end
return -- don't increment self.i past end of arguments return -- don't increment self.i past end of arguments
else else

View File

@ -68,7 +68,7 @@ function Reader:const(relative, no_label)
self:expect{'NUM', 'LABELREL'} self:expect{'NUM', 'LABELREL'}
end end
local new = Token(t) local new = Token(t)
if relative then if relative then -- you probably shouldn't use this in Preproc
if t.tt == 'LABELSYM' then if t.tt == 'LABELSYM' then
new.tt = 'LABELREL' new.tt = 'LABELREL'
elseif t.tt == 'NUM' then elseif t.tt == 'NUM' then

View File

@ -68,11 +68,15 @@ function Token:set(key, value)
return self return self
end end
function Token:compute() function Token:compute(n)
assert(self.tt == 'NUM', 'Internal Error: cannot compute a non-number token') local n = n or self.tok
local n = 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 if self.index then
-- TODO: should this still be here now that we have .base?
n = n % 0x80000000 n = n % 0x80000000
n = floor(n/4) n = floor(n/4)
end end
@ -94,7 +98,7 @@ function Token:compute()
n = upper n = upper
end end
if self.negate or self.signed then if self.signed then
if n >= 0x10000 or n < -0x8000 then if n >= 0x10000 or n < -0x8000 then
return n, 'value out of range' return n, 'value out of range'
end end

View File

@ -201,7 +201,7 @@ function overrides:BEQI(name)
local branch = branch_basics[name] local branch = branch_basics[name]
local reg = self:pop('CPU') local reg = self:pop('CPU')
local im = self:pop('CONST') local im = self:pop('CONST')
local offset = self:pop('REL'):set('signed') local offset = self:pop('CONST')
if reg == 'AT' then if reg == 'AT' then
self:error('register cannot be AT in this pseudo-instruction') self:error('register cannot be AT in this pseudo-instruction')
@ -219,7 +219,7 @@ function overrides:BLTI(name)
local branch = branch_basics[name] local branch = branch_basics[name]
local reg = self:pop('CPU') local reg = self:pop('CPU')
local im = self:pop('CONST') local im = self:pop('CONST')
local offset = self:pop('REL'):set('signed') local offset = self:pop('CONST')
if reg == 'AT' then if reg == 'AT' then
self:error('register cannot be AT in this pseudo-instruction') self:error('register cannot be AT in this pseudo-instruction')
@ -241,7 +241,7 @@ function overrides:BLEI(name)
local branch = branch_basics[name] local branch = branch_basics[name]
local reg = self:pop('CPU') local reg = self:pop('CPU')
local im = self:pop('CONST') local im = self:pop('CONST')
local offset = self:pop('REL'):set('signed') local offset = self:pop('CONST')
if reg == 'AT' then if reg == 'AT' then
self:error('register cannot be AT in this pseudo-instruction') 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 if name == 'BLEI' or name =='BLEIL' then
beq_offset = offset beq_offset = offset
else 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 end
self:push_new('BEQ', reg, 'AT', beq_offset) self:push_new('BEQ', reg, 'AT', beq_offset)