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