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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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