mirror of
https://github.com/notwa/lips
synced 2024-11-14 09:29:03 -08: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:
parent
6433227c26
commit
f851540b24
7 changed files with 46 additions and 35 deletions
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
Loading…
Reference in a new issue