1
0
Fork 0
mirror of https://github.com/notwa/mm synced 2024-11-05 04:39:03 -08:00
mm/Lua/lib/lips/overrides.lua

274 lines
7.6 KiB
Lua
Raw Normal View History

2016-01-13 07:56:18 -08:00
local insert = table.insert
2016-04-21 13:04:49 -07:00
local path = string.gsub(..., "[^.]+$", "")
local data = require(path.."data")
2016-01-13 07:56:18 -08:00
local overrides = {}
2016-04-21 13:04:49 -07:00
-- note: "self" is an instance of Preproc
local function tob_override(self, name)
-- handle all the addressing modes for lw/sw-like instructions
local rt = self:pop('CPU')
local offset, base
if self:peek('DEREF') then
offset = 0
base = self:pop('DEREF')
else -- NUM or LABELSYM
local o = self:pop('CONST')
if self:peek('NUM') then
local temp, err = self:pop('CONST'):compute()
if err then
self:error(err, temp)
end
o:set('offset', temp)
end
offset = self:token(o)
if not o.portion then
offset:set('portion', 'lower')
end
-- attempt to use the fewest possible instructions for this offset
if not o.portion and (o.tt == 'LABELSYM' or o.tok >= 0x80000000) then
local immediate = self:token(o):set('portion', 'upperoff')
self:push_new('LUI', 'AT', immediate)
if self.s[self.i] ~= nil then
local reg = self:pop('DEREF'):set('tt', 'REG')
if reg.tok ~= 'R0' then
self:push_new('ADDU', 'AT', 'AT', 'R0')
end
end
base = self:token('DEREF', 'AT')
else
base = self:pop('DEREF')
end
end
self:push_new(name, rt, offset, base)
end
for k, v in pairs(data.instructions) do
if v[2] == 'tob' then
overrides[k] = tob_override
end
end
2016-01-13 07:56:18 -08:00
function overrides.LI(self, name)
2016-04-21 13:04:49 -07:00
local rt = self:pop('CPU')
local im = self:pop('CONST')
2016-01-13 07:56:18 -08:00
-- for us, this is just semantics. for a "real" assembler,
-- LA could add appropriate RELO LUI/ADDIU directives.
2016-01-13 11:20:28 -08:00
if im.tt == 'LABELSYM' then
2016-01-13 07:56:18 -08:00
self:error('use LA for labels')
end
2016-01-13 11:20:28 -08:00
if im.portion then
2016-04-21 13:04:49 -07:00
-- FIXME: use appropriate instruction based on portion?
self:push_new('ADDIU', rt, 'R0', im)
2016-01-13 11:20:28 -08:00
return
end
im.tok = im.tok % 0x100000000
if im.tok >= 0x10000 and im.tok <= 0xFFFF8000 then
2016-04-21 13:04:49 -07:00
local rs = rt
local immediate = self:token(im):set('portion', 'upper')
self:push_new('LUI', rt, immediate)
2016-01-13 11:20:28 -08:00
if im.tok % 0x10000 ~= 0 then
2016-04-21 13:04:49 -07:00
local immediate = self:token(im):set('portion', 'lower')
self:push_new('ORI', rt, rs, immediate)
2016-01-13 07:56:18 -08:00
end
2016-01-13 11:20:28 -08:00
elseif im.tok >= 0x8000 and im.tok < 0x10000 then
2016-04-21 13:04:49 -07:00
local immediate = self:token(im):set('portion', 'lower')
self:push_new('ORI', rt, 'R0', immediate)
2016-01-13 07:56:18 -08:00
else
2016-04-21 13:04:49 -07:00
local immediate = self:token(im):set('portion', 'lower')
self:push_new('ADDIU', rt, 'R0', immediate)
2016-01-13 07:56:18 -08:00
end
end
function overrides.LA(self, name)
2016-04-21 13:04:49 -07:00
local rt = self:pop('CPU')
local im = self:pop('CONST')
local rs = rt
local immediate = self:token(im):set('portion', 'upperoff')
self:push_new('LUI', rt, immediate)
local immediate = self:token(im):set('portion', 'lower')
self:push_new('ADDIU', rt, rt, immediate)
2016-01-13 07:56:18 -08:00
end
function overrides.PUSH(self, name)
2016-04-21 13:04:49 -07:00
local w = name == 'PUSH' and 'SW' or 'LW'
2016-01-13 07:56:18 -08:00
local stack = {}
2016-04-21 13:04:49 -07:00
for _, t in ipairs(self.s) do
if t.tt == 'NUM' then
if t.tok < 0 then
self:error("can't push a negative number of spaces", t.tok)
2016-01-13 07:56:18 -08:00
end
2016-04-21 13:04:49 -07:00
for i=1, t.tok do
2016-01-13 07:56:18 -08:00
insert(stack, '')
end
2016-04-21 13:04:49 -07:00
self:pop()
2016-01-13 07:56:18 -08:00
else
2016-04-21 13:04:49 -07:00
insert(stack, self:pop('CPU'))
2016-01-13 07:56:18 -08:00
end
end
if #stack == 0 then
self:error(name..' requires at least one argument')
end
if name == 'PUSH' then
2016-04-21 13:04:49 -07:00
local immediate = self:token(#stack*4):set('negate')
self:push_new('ADDIU', 'SP', 'SP', immediate)
2016-01-13 07:56:18 -08:00
end
for i, r in ipairs(stack) do
if r ~= '' then
2016-04-21 13:04:49 -07:00
local offset = (i - 1)*4
self:push_new(w, r, offset, self:token('DEREF', 'SP'))
2016-01-13 07:56:18 -08:00
end
end
if name == 'JPOP' then
2016-04-21 13:04:49 -07:00
self:push_new('JR', 'RA')
2016-01-13 07:56:18 -08:00
end
if name == 'POP' or name == 'JPOP' then
2016-04-21 13:04:49 -07:00
local immediate = #stack * 4
self:push_new('ADDIU', 'SP', 'SP', immediate)
2016-01-13 07:56:18 -08:00
end
end
overrides.POP = overrides.PUSH
overrides.JPOP = overrides.PUSH
function overrides.NAND(self, name)
2016-04-21 13:04:49 -07:00
local rd = self:pop('CPU')
local rs = self:pop('CPU')
local rt = self:pop('CPU')
self:push_new('AND', rd, rs, rt)
local rs = rd
local rt = 'R0'
self:push_new('NOR', rd, rs, rt)
2016-01-13 07:56:18 -08:00
end
function overrides.NANDI(self, name)
2016-04-21 13:04:49 -07:00
local rt = self:pop('CPU')
local rs = self:pop('CPU')
local immediate = self:pop('CONST')
self:push_new('ANDI', rt, rs, immediate)
local rd = rt
local rs = rt
local rt = 'R0'
self:push_new('NOR', rd, rs, rt)
2016-01-13 07:56:18 -08:00
end
function overrides.NORI(self, name)
2016-04-21 13:04:49 -07:00
local rt = self:pop('CPU')
local rs = self:pop('CPU')
local immediate = self:pop('CONST')
self:push_new('ORI', rt, rs, immediate)
local rd = rt
local rs = rt
local rt = 'R0'
self:push_new('NOR', rd, rs, rt)
2016-01-13 07:56:18 -08:00
end
function overrides.ROL(self, name)
2016-04-21 13:04:49 -07:00
-- FIXME
local rd, rs, rt
local left = self:pop('CPU')
rt = self:pop('CPU')
local immediate = self:pop('CONST')
error('Internal Error: unimplemented')
2016-01-13 07:56:18 -08:00
end
function overrides.ROR(self, name)
2016-04-21 13:04:49 -07:00
-- FIXME
local right = self:pop('CPU')
local rt = self:pop('CPU')
local immediate = self:pop('CONST')
error('Internal Error: unimplemented')
2016-01-13 07:56:18 -08:00
end
function overrides.JR(self, name)
2016-04-21 13:04:49 -07:00
local rs = self:peek() and self:pop('CPU') or 'RA'
self:push_new('JR', rs)
2016-01-13 07:56:18 -08:00
end
local branch_basics = {
2016-04-21 13:04:49 -07:00
BEQI = 'BEQ',
BGEI = 'BEQ',
BGTI = 'BEQ',
BLEI = 'BNE',
BLTI = 'BNE',
BNEI = 'BNE',
BEQIL = 'BEQL',
BGEIL = 'BEQL',
BGTIL = 'BEQL',
BLEIL = 'BNEL',
BLTIL = 'BNEL',
BNEIL = 'BNEL',
2016-01-13 07:56:18 -08:00
}
function overrides.BEQI(self, name)
2016-04-21 13:04:49 -07:00
local branch = branch_basics[name]
local reg = self:pop('CPU')
local immediate = self:pop('CONST')
local offset = self:pop('REL'):set('signed')
2016-01-13 07:56:18 -08:00
if reg == 'AT' then
self:error('register cannot be AT in this pseudo-instruction')
end
2016-04-21 13:04:49 -07:00
self:push_new('ADDIU', 'AT', 'R0', immediate)
2016-01-13 07:56:18 -08:00
2016-04-21 13:04:49 -07:00
self:push_new(branch, reg, 'AT', offset)
2016-01-13 07:56:18 -08:00
end
overrides.BNEI = overrides.BEQI
2016-04-07 10:29:21 -07:00
overrides.BEQIL = overrides.BEQI
overrides.BNEIL = overrides.BEQI
2016-01-13 07:56:18 -08:00
function overrides.BLTI(self, name)
2016-04-21 13:04:49 -07:00
local branch = branch_basics[name]
local reg = self:pop('CPU')
local immediate = self:pop('CONST')
local offset = self:pop('REL'):set('signed')
if reg == 'AT' then
2016-01-13 07:56:18 -08:00
self:error('register cannot be AT in this pseudo-instruction')
end
2016-04-21 13:04:49 -07:00
self:push_new('SLTI', 'AT', reg, immediate)
2016-01-13 07:56:18 -08:00
2016-04-21 13:04:49 -07:00
self:push_new(branch, 'R0', 'AT', offset)
2016-01-13 07:56:18 -08:00
end
overrides.BGEI = overrides.BLTI
2016-04-07 10:29:21 -07:00
overrides.BLTIL = overrides.BLTI
overrides.BGEIL = overrides.BLTI
2016-01-13 07:56:18 -08:00
function overrides.BLEI(self, name)
-- TODO: this can probably be optimized
2016-04-21 13:04:49 -07:00
local branch = branch_basics[name]
local reg = self:pop('CPU')
local immediate = self:pop('CONST')
local offset = self:pop('REL'):set('signed')
2016-01-13 07:56:18 -08:00
if reg == 'AT' then
self:error('register cannot be AT in this pseudo-instruction')
end
2016-04-21 13:04:49 -07:00
self:push_new('ADDIU', 'AT', 'R0', immediate)
2016-01-13 07:56:18 -08:00
2016-04-21 13:04:49 -07:00
local beq_offset
2016-01-13 07:56:18 -08:00
if name == 'BLEI' then
2016-04-21 13:04:49 -07:00
beq_offset = offset
2016-01-13 07:56:18 -08:00
else
2016-04-21 13:04:49 -07:00
-- FIXME: this probably isn't correct for branch-likely instructions
beq_offset = 2 -- branch to delay slot of the next branch
2016-01-13 07:56:18 -08:00
end
2016-04-21 13:04:49 -07:00
self:push_new('BEQ', reg, 'R0', beq_offset)
2016-01-13 07:56:18 -08:00
2016-04-21 13:04:49 -07:00
self:push_new('SLT', 'AT', reg, immediate)
2016-01-13 07:56:18 -08:00
2016-04-21 13:04:49 -07:00
self:push_new(branch, 'AT', 'R0', offset)
2016-01-13 07:56:18 -08:00
end
overrides.BGTI = overrides.BLEI
2016-04-07 10:29:21 -07:00
overrides.BLEIL = overrides.BLEI
overrides.BGTIL = overrides.BLEI
2016-01-13 07:56:18 -08:00
return overrides