mirror of
https://github.com/notwa/lips
synced 2024-05-09 20:33:23 -07:00
rewrite overrides, reimplement ROL/ROR
This commit is contained in:
parent
43e08af5c5
commit
6433227c26
|
@ -1,6 +1,6 @@
|
||||||
package.path = package.path..";?/init.lua"
|
package.path = package.path..";?/init.lua"
|
||||||
local lips = require "lips"
|
local lips = require "lips"
|
||||||
local err = lips('example.asm', nil, {offset=0})
|
local err = lips('example.asm')
|
||||||
if err then
|
if err then
|
||||||
print(err)
|
print(err)
|
||||||
end
|
end
|
||||||
|
|
|
@ -45,7 +45,7 @@ end
|
||||||
|
|
||||||
function Dumper:desym(t)
|
function Dumper:desym(t)
|
||||||
if t.tt == 'REL' then
|
if t.tt == 'REL' then
|
||||||
return self:label_delta(self:pc(), t.tok)
|
return t.tok
|
||||||
elseif type(t.tok) == 'number' then
|
elseif type(t.tok) == 'number' then
|
||||||
if t.offset then
|
if t.offset then
|
||||||
return t.tok + t.offset
|
return t.tok + t.offset
|
||||||
|
|
|
@ -53,6 +53,7 @@ function lips.assemble(fn_or_asm, writer, options)
|
||||||
options.origin = options.offset
|
options.origin = options.offset
|
||||||
options.base = 0
|
options.base = 0
|
||||||
else
|
else
|
||||||
|
options.origin = options.origin or 0
|
||||||
options.base = options.base or 0x80000000
|
options.base = options.base or 0x80000000
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ local overrides = {}
|
||||||
|
|
||||||
local function tob_override(self, name)
|
local function tob_override(self, name)
|
||||||
-- handle all the addressing modes for lw/sw-like instructions
|
-- handle all the addressing modes for lw/sw-like instructions
|
||||||
local rt = self:pop('CPU')
|
local dest = self:pop('CPU')
|
||||||
local offset, base
|
local offset, base
|
||||||
if self:peek('DEREF') then
|
if self:peek('DEREF') then
|
||||||
offset = 0
|
offset = 0
|
||||||
|
@ -28,12 +28,12 @@ local function tob_override(self, name)
|
||||||
end
|
end
|
||||||
-- attempt to use the fewest possible instructions for this offset
|
-- attempt to use the fewest possible instructions for this offset
|
||||||
if not o.portion and (o.tt == 'LABELSYM' or o.tok >= 0x80000000) then
|
if not o.portion and (o.tt == 'LABELSYM' or o.tok >= 0x80000000) then
|
||||||
local immediate = self:token(o):set('portion', 'upperoff')
|
local temp = self:token(o):set('portion', 'upperoff')
|
||||||
self:push_new('LUI', 'AT', immediate)
|
self:push_new('LUI', 'AT', temp)
|
||||||
if self.s[self.i] ~= nil then
|
if self.s[self.i] ~= nil then
|
||||||
local reg = self:pop('DEREF'):set('tt', 'REG')
|
local reg = self:pop('DEREF'):set('tt', 'REG')
|
||||||
if reg.tok ~= 'R0' then
|
if reg.tok ~= 'R0' then
|
||||||
self:push_new('ADDU', 'AT', 'AT', 'R0')
|
self:push_new('ADDU', 'AT', 'AT', reg)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
base = self:token('DEREF', 'AT')
|
base = self:token('DEREF', 'AT')
|
||||||
|
@ -41,7 +41,7 @@ local function tob_override(self, name)
|
||||||
base = self:pop('DEREF')
|
base = self:pop('DEREF')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
self:push_new(name, rt, offset, base)
|
self:push_new(name, dest, offset, base)
|
||||||
end
|
end
|
||||||
|
|
||||||
for k, v in pairs(data.instructions) do
|
for k, v in pairs(data.instructions) do
|
||||||
|
@ -50,8 +50,8 @@ for k, v in pairs(data.instructions) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function overrides.LI(self, name)
|
function overrides:LI(name)
|
||||||
local rt = self:pop('CPU')
|
local dest = self:pop('CPU')
|
||||||
local im = self:pop('CONST')
|
local im = self:pop('CONST')
|
||||||
|
|
||||||
-- for us, this is just semantics. for a "real" assembler,
|
-- for us, this is just semantics. for a "real" assembler,
|
||||||
|
@ -62,40 +62,38 @@ function overrides.LI(self, name)
|
||||||
|
|
||||||
if im.portion then
|
if im.portion then
|
||||||
-- FIXME: use appropriate instruction based on portion?
|
-- FIXME: use appropriate instruction based on portion?
|
||||||
self:push_new('ADDIU', rt, 'R0', im)
|
self:push_new('ADDIU', dest, 'R0', im)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
im.tok = im.tok % 0x100000000
|
im.tok = im.tok % 0x100000000
|
||||||
if im.tok >= 0x10000 and im.tok <= 0xFFFF8000 then
|
if im.tok >= 0x10000 and im.tok <= 0xFFFF8000 then
|
||||||
local rs = rt
|
local temp = self:token(im):set('portion', 'upper')
|
||||||
local immediate = self:token(im):set('portion', 'upper')
|
self:push_new('LUI', dest, temp)
|
||||||
self:push_new('LUI', rt, immediate)
|
|
||||||
if im.tok % 0x10000 ~= 0 then
|
if im.tok % 0x10000 ~= 0 then
|
||||||
local immediate = self:token(im):set('portion', 'lower')
|
local temp = self:token(im):set('portion', 'lower')
|
||||||
self:push_new('ORI', rt, rs, immediate)
|
self:push_new('ORI', dest, dest, temp)
|
||||||
end
|
end
|
||||||
elseif im.tok >= 0x8000 and im.tok < 0x10000 then
|
elseif im.tok >= 0x8000 and im.tok < 0x10000 then
|
||||||
local immediate = self:token(im):set('portion', 'lower')
|
local temp = self:token(im):set('portion', 'lower')
|
||||||
self:push_new('ORI', rt, 'R0', immediate)
|
self:push_new('ORI', dest, 'R0', temp)
|
||||||
else
|
else
|
||||||
local immediate = self:token(im):set('portion', 'lower')
|
local temp = self:token(im):set('portion', 'lower')
|
||||||
self:push_new('ADDIU', rt, 'R0', immediate)
|
self:push_new('ADDIU', dest, 'R0', temp)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function overrides.LA(self, name)
|
function overrides:LA(name)
|
||||||
local rt = self:pop('CPU')
|
local dest = self:pop('CPU')
|
||||||
local im = self:pop('CONST')
|
local im = self:pop('CONST')
|
||||||
|
|
||||||
local rs = rt
|
local im = self:token(im):set('portion', 'upperoff')
|
||||||
local immediate = self:token(im):set('portion', 'upperoff')
|
self:push_new('LUI', dest, im)
|
||||||
self:push_new('LUI', rt, immediate)
|
local im = self:token(im):set('portion', 'lower')
|
||||||
local immediate = self:token(im):set('portion', 'lower')
|
self:push_new('ADDIU', dest, dest, im)
|
||||||
self:push_new('ADDIU', rt, rt, immediate)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function overrides.PUSH(self, name)
|
function overrides:PUSH(name)
|
||||||
local w = name == 'PUSH' and 'SW' or 'LW'
|
local w = name == 'PUSH' and 'SW' or 'LW'
|
||||||
local stack = {}
|
local stack = {}
|
||||||
for _, t in ipairs(self.s) do
|
for _, t in ipairs(self.s) do
|
||||||
|
@ -115,8 +113,8 @@ function overrides.PUSH(self, name)
|
||||||
self:error(name..' requires at least one argument')
|
self:error(name..' requires at least one argument')
|
||||||
end
|
end
|
||||||
if name == 'PUSH' then
|
if name == 'PUSH' then
|
||||||
local immediate = self:token(#stack*4):set('negate')
|
local im = self:token(#stack*4):set('negate')
|
||||||
self:push_new('ADDIU', 'SP', 'SP', immediate)
|
self:push_new('ADDIU', 'SP', 'SP', im)
|
||||||
end
|
end
|
||||||
for i, r in ipairs(stack) do
|
for i, r in ipairs(stack) do
|
||||||
if r ~= '' then
|
if r ~= '' then
|
||||||
|
@ -128,65 +126,60 @@ function overrides.PUSH(self, name)
|
||||||
self:push_new('JR', 'RA')
|
self:push_new('JR', 'RA')
|
||||||
end
|
end
|
||||||
if name == 'POP' or name == 'JPOP' then
|
if name == 'POP' or name == 'JPOP' then
|
||||||
local immediate = #stack * 4
|
local im = #stack * 4
|
||||||
self:push_new('ADDIU', 'SP', 'SP', immediate)
|
self:push_new('ADDIU', 'SP', 'SP', im)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
overrides.POP = overrides.PUSH
|
overrides.POP = overrides.PUSH
|
||||||
overrides.JPOP = overrides.PUSH
|
overrides.JPOP = overrides.PUSH
|
||||||
|
|
||||||
function overrides.NAND(self, name)
|
function overrides:NAND(name)
|
||||||
local rd = self:pop('CPU')
|
local dest = self:pop('CPU')
|
||||||
local rs = self:pop('CPU')
|
local src = self:pop('CPU')
|
||||||
local rt = self:pop('CPU')
|
local target = self:pop('CPU')
|
||||||
self:push_new('AND', rd, rs, rt)
|
self:push_new('AND', dest, src, target)
|
||||||
local rs = rd
|
self:push_new('NOR', dest, dest, 'R0') -- NOT
|
||||||
local rt = 'R0'
|
|
||||||
self:push_new('NOR', rd, rs, rt)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function overrides.NANDI(self, name)
|
function overrides:NANDI(name)
|
||||||
local rt = self:pop('CPU')
|
local dest = self:pop('CPU')
|
||||||
local rs = self:pop('CPU')
|
local src = self:pop('CPU')
|
||||||
local immediate = self:pop('CONST')
|
local im = self:pop('CONST')
|
||||||
self:push_new('ANDI', rt, rs, immediate)
|
self:push_new('ANDI', dest, src, im)
|
||||||
local rd = rt
|
self:push_new('NOR', dest, dest, 'R0') -- NOT
|
||||||
local rs = rt
|
|
||||||
local rt = 'R0'
|
|
||||||
self:push_new('NOR', rd, rs, rt)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function overrides.NORI(self, name)
|
function overrides:NORI(name)
|
||||||
local rt = self:pop('CPU')
|
local dest = self:pop('CPU')
|
||||||
local rs = self:pop('CPU')
|
local src = self:pop('CPU')
|
||||||
local immediate = self:pop('CONST')
|
local im = self:pop('CONST')
|
||||||
self:push_new('ORI', rt, rs, immediate)
|
self:push_new('ORI', dest, src, im)
|
||||||
local rd = rt
|
self:push_new('NOR', dest, dest, 'R0') -- NOT
|
||||||
local rs = rt
|
|
||||||
local rt = 'R0'
|
|
||||||
self:push_new('NOR', rd, rs, rt)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function overrides.ROL(self, name)
|
function overrides:ROL(name)
|
||||||
-- FIXME
|
local first = name == 'ROL' and 'SLL' or 'SRL'
|
||||||
local rd, rs, rt
|
local second = name == 'ROL' and 'SRL' or 'SLL'
|
||||||
local left = self:pop('CPU')
|
local dest = self:pop('CPU')
|
||||||
rt = self:pop('CPU')
|
local src = self:pop('CPU')
|
||||||
local immediate = self:pop('CONST')
|
local im = self:pop('CONST')
|
||||||
error('Internal Error: unimplemented')
|
if dest == 'AT' or src == 'AT' then
|
||||||
end
|
self:error('registers cannot be AT in this pseudo-instruction')
|
||||||
|
end
|
||||||
|
|
||||||
function overrides.ROR(self, name)
|
self:push_new(first, dest, src, im)
|
||||||
-- FIXME
|
local temp, err = im:compute()
|
||||||
local right = self:pop('CPU')
|
if err then
|
||||||
local rt = self:pop('CPU')
|
self:error(err, temp)
|
||||||
local immediate = self:pop('CONST')
|
end
|
||||||
error('Internal Error: unimplemented')
|
self:push_new(second, 'AT', src, 32 - temp)
|
||||||
|
self:push_new('OR', dest, dest, 'AT')
|
||||||
end
|
end
|
||||||
|
overrides.ROR = overrides.ROL
|
||||||
|
|
||||||
function overrides.JR(self, name)
|
function overrides:JR(name)
|
||||||
local rs = self:peek() and self:pop('CPU') or 'RA'
|
local src = self:peek() and self:pop('CPU') or 'RA'
|
||||||
self:push_new('JR', rs)
|
self:push_new('JR', src)
|
||||||
end
|
end
|
||||||
|
|
||||||
local branch_basics = {
|
local branch_basics = {
|
||||||
|
@ -204,17 +197,17 @@ local branch_basics = {
|
||||||
BNEIL = 'BNEL',
|
BNEIL = 'BNEL',
|
||||||
}
|
}
|
||||||
|
|
||||||
function overrides.BEQI(self, name)
|
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 immediate = self:pop('CONST')
|
local im = self:pop('CONST')
|
||||||
local offset = self:pop('REL'):set('signed')
|
local offset = self:pop('REL'):set('signed')
|
||||||
|
|
||||||
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')
|
||||||
end
|
end
|
||||||
|
|
||||||
self:push_new('ADDIU', 'AT', 'R0', immediate)
|
self:push_new('ADDIU', 'AT', 'R0', im)
|
||||||
|
|
||||||
self:push_new(branch, reg, 'AT', offset)
|
self:push_new(branch, reg, 'AT', offset)
|
||||||
end
|
end
|
||||||
|
@ -222,17 +215,17 @@ overrides.BNEI = overrides.BEQI
|
||||||
overrides.BEQIL = overrides.BEQI
|
overrides.BEQIL = overrides.BEQI
|
||||||
overrides.BNEIL = overrides.BEQI
|
overrides.BNEIL = overrides.BEQI
|
||||||
|
|
||||||
function overrides.BLTI(self, name)
|
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 immediate = self:pop('CONST')
|
local im = self:pop('CONST')
|
||||||
local offset = self:pop('REL'):set('signed')
|
local offset = self:pop('REL'):set('signed')
|
||||||
|
|
||||||
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')
|
||||||
end
|
end
|
||||||
|
|
||||||
self:push_new('SLTI', 'AT', reg, immediate)
|
self:push_new('SLTI', 'AT', reg, im)
|
||||||
|
|
||||||
self:push_new(branch, 'R0', 'AT', offset)
|
self:push_new(branch, 'R0', 'AT', offset)
|
||||||
end
|
end
|
||||||
|
@ -240,29 +233,31 @@ overrides.BGEI = overrides.BLTI
|
||||||
overrides.BLTIL = overrides.BLTI
|
overrides.BLTIL = overrides.BLTI
|
||||||
overrides.BGEIL = overrides.BLTI
|
overrides.BGEIL = overrides.BLTI
|
||||||
|
|
||||||
function overrides.BLEI(self, name)
|
function overrides:BLEI(name)
|
||||||
-- TODO: this can probably be optimized
|
-- TODO: this can probably be optimized
|
||||||
|
if name:sub(#name) == 'L' then
|
||||||
|
self:error('unimplemented pseudo-instruction', name)
|
||||||
|
end
|
||||||
local branch = branch_basics[name]
|
local branch = branch_basics[name]
|
||||||
local reg = self:pop('CPU')
|
local reg = self:pop('CPU')
|
||||||
local immediate = self:pop('CONST')
|
local im = self:pop('CONST')
|
||||||
local offset = self:pop('REL'):set('signed')
|
local offset = self:pop('REL'):set('signed')
|
||||||
|
|
||||||
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')
|
||||||
end
|
end
|
||||||
|
|
||||||
self:push_new('ADDIU', 'AT', 'R0', immediate)
|
self:push_new('ADDIU', 'AT', 'R0', im)
|
||||||
|
|
||||||
local beq_offset
|
local beq_offset
|
||||||
if name == 'BLEI' then
|
if name == 'BLEI' or name =='BLEIL' then
|
||||||
beq_offset = offset
|
beq_offset = offset
|
||||||
else
|
else
|
||||||
-- FIXME: this probably isn't correct for branch-likely instructions
|
|
||||||
beq_offset = 2 -- branch to delay slot of the next branch
|
beq_offset = 2 -- branch to delay slot of the next branch
|
||||||
end
|
end
|
||||||
self:push_new('BEQ', reg, 'R0', beq_offset)
|
self:push_new('BEQ', reg, 'AT', beq_offset)
|
||||||
|
|
||||||
self:push_new('SLTI', 'AT', reg, immediate)
|
self:push_new('SLT', 'AT', reg, 'AT')
|
||||||
|
|
||||||
self:push_new(branch, 'AT', 'R0', offset)
|
self:push_new(branch, 'AT', 'R0', offset)
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue
Block a user