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

add .base directive; PC calculation

This commit is contained in:
Connor Olding 2016-04-21 11:46:20 -07:00
parent e25ee2013c
commit 1266dfd18f
6 changed files with 60 additions and 27 deletions

View File

@ -216,9 +216,13 @@ if `fill` is omitted, no bytes are overwritten,
and only the position is changed.
* `.org {address}`
set the current address for writing to; seek.
until lips is a little more optimized,
be cautious of seeking to large addresses.
set the current address for writing to; seek to origin.
* `.base {offset}`
sets a virtual offset relative to the origin (.org).
defaults to 0x80000000.
this allows you to have a PC value different from origin:
`PC = origin + base`
* `HEX { ... }`
write a series of bytes given in hexadecimal.

View File

@ -83,7 +83,7 @@ function Collector:directive()
local function add(kind, ...)
insert(self.statements, self:statement('!'..kind, ...))
end
if name == 'ORG' then
if name == 'ORG' or name == 'BASE' then
add(name, self:const(nil, 'no labels'))
elseif name == 'ALIGN' or name == 'SKIP' then
if self:is_EOL() and name == 'ALIGN' then
@ -199,6 +199,16 @@ function Collector:collect(tokens, fn)
self.statements = {}
-- this works, but probably shouldn't be in this function specifically
if self.options.offset then
local s = Statement('(options)', 0, '!ORG', self.options.offset)
insert(self.statements, s)
end
if self.options.base then
local s = Statement('(options)', 0, '!BASE', self.options.base)
insert(self.statements, s)
end
self.i = 0 -- set up Muncher iteration
self:advance() -- load up the first token
while true do

View File

@ -12,14 +12,22 @@ local Reader = require(path.."Reader")
local bitrange = util.bitrange
local function label_delta(from, to)
-- TODO: consider removing the % here since .base should handle that now
to = to
from = from
return floor(to/4) - 1 - floor(from/4)
end
local Dumper = Reader:extend()
function Dumper:init(writer, options)
self.writer = writer
self.options = options or {}
self.labels = setmetatable({}, {__index=options.labels})
self.commands = {}
self.pos = options.offset or 0
self.lastcommand = nil
self.pos = 0
self.base = 0
end
function Dumper:export_labels(t)
@ -35,9 +43,7 @@ end
function Dumper:desym(t)
if t.tt == 'REL' then
local target = t.tok % 0x80000000
local pos = self.pos % 0x80000000
local rel = floor(target/4) - 1 - floor(pos/4)
local rel = label_delta(self:pc(), t.tok)
if rel > 0x8000 or rel <= -0x8000 then
self:error('branch too far')
end
@ -62,9 +68,7 @@ function Dumper:desym(t)
return label
end
label = label % 0x80000000
local pos = self.pos % 0x80000000
local rel = floor(label/4) - 1 - floor(pos/4)
local rel = label_delta(self:pc(), label)
if rel > 0x8000 or rel <= -0x8000 then
self:error('branch too far')
end
@ -79,7 +83,7 @@ function Dumper:validate(n, bits)
self:error('value is nil') -- internal error?
end
if n > max or n < 0 then
self:error('value out of range', n)
self:error('value out of range', ("%X"):format(n))
end
return n
end
@ -267,22 +271,30 @@ function Dumper:fill(length, content)
return s
end
function Dumper:pc()
return self.pos + self.base
end
function Dumper:load(statements)
local pos = self.options.offset or 0
local new_statements = {}
self.pos = 0
self.base = 0
for i=1, #statements do
local s = statements[i]
self.fn = s.fn
self.line = s.line
if s.type:sub(1, 1) == '!' then
if s.type == '!LABEL' then
self.labels[s[1].tok] = pos
self.labels[s[1].tok] = self:pc()
elseif s.type == '!DATA' then
s.length = util.measure_data(s) -- cache for next pass
pos = pos + s.length
self.pos = self.pos + s.length
insert(new_statements, s)
elseif s.type == '!ORG' then
pos = s[1].tok
self.pos = s[1].tok
insert(new_statements, s)
elseif s.type == '!BASE' then
self.base = s[1].tok
insert(new_statements, s)
elseif s.type == '!ALIGN' or s.type == '!SKIP' then
local length, content
@ -294,24 +306,24 @@ function Dumper:load(statements)
else
align = 2^align
end
local temp = pos + align - 1
length = temp - (temp % align) - pos
local temp = self:pc() + align - 1
length = temp - (temp % align) - self:pc()
else
length = s[1] and s[1].tok or 0
content = s[2] and s[2].tok or nil
end
pos = pos + length
self.pos = self.pos + length
if content == nil then
local new = Statement(self.fn, self.line, '!ORG', pos)
local new = Statement(self.fn, self.line, '!ORG', self.pos)
insert(new_statements, new)
elseif length > 0 then
insert(new_statements, self:fill(length, content))
elseif length < 0 then
local new = Statement(self.fn, self.line, '!ORG', pos)
local new = Statement(self.fn, self.line, '!ORG', self.pos)
insert(new_statements, new)
insert(new_statements, self:fill(length, content))
local new = Statement(self.fn, self.line, '!ORG', pos)
local new = Statement(self.fn, self.line, '!ORG', self.pos)
insert(new_statements, new)
else
-- length is 0, noop
@ -320,14 +332,16 @@ function Dumper:load(statements)
error('Internal Error: unknown statement, got '..s.type)
end
else
pos = pos + 4
self.pos = self.pos + 4
insert(new_statements, s)
end
end
statements = new_statements
new_statements = {}
self.pos = self.options.offset or 0
self.pos = 0
self.base = 0
for i=1, #statements do
local s = statements[i]
self.fn = s.fn
@ -352,6 +366,8 @@ function Dumper:load(statements)
elseif s.type == '!ORG' then
self.pos = s[1].tok
insert(new_statements, s)
elseif s.type == '!BASE' then
self.base = s[1].tok
elseif s.type == '!LABEL' then
-- noop
else
@ -364,8 +380,8 @@ function Dumper:load(statements)
end
function Dumper:dump()
-- TODO: have options insert .org and/or .base; pos is always 0 at start
self.pos = self.options.offset or 0
self.pos = 0
self.base = nil
for i, s in ipairs(self.statements) do
if s.type == '!DATA' then
for j, t in ipairs(s) do

View File

@ -72,6 +72,7 @@ function Token:compute()
assert(self.tt == 'NUM', 'Internal Error: cannot compute a non-number token')
local n = self.tok
if self.index then
-- TODO: should this still be here now that we have .base?
n = n % 0x80000000
n = floor(n/4)
end

View File

@ -29,7 +29,7 @@ data.fpu_registers = {
}
data.all_directives = {
'ORG', 'ALIGN', 'SKIP',
'ORG', 'BASE', 'ALIGN', 'SKIP',
'ASCII', 'ASCIIZ',
'BYTE', 'HALFWORD', 'WORD',
--'HEX', -- excluded here due to different syntax

View File

@ -63,6 +63,8 @@ function lips.assemble(fn_or_asm, writer, options)
end
end
options.base = options.base or 0x80000000
if options.unsafe then
return main()
else