1
0
Fork 0
mirror of https://github.com/notwa/lips synced 2024-05-18 08:23:23 -07:00
lips/lips/overrides.lua

319 lines
8.2 KiB
Lua

local insert = table.insert
local data = require "lips.data"
local instructions = data.instructions
local overrides = {}
-- note: "self" is an instance of Parser
function overrides.LI(self, name)
local lui = instructions['LUI']
local ori = instructions['ORI']
local addiu = instructions['ADDIU']
local args = {}
args.rt = self:register()
self:optional_comma()
local im = self:const()
-- for us, this is just semantics. for a "real" assembler,
-- LA could add appropriate RELO LUI/ADDIU directives.
if im[1] == 'LABELSYM' then
self:error('use LA for labels')
end
im[2] = im[2] % 0x100000000
if im[2] >= 0x10000 and im[2] <= 0xFFFF8000 then
args.rs = args.rt
args.immediate = {'UPPER', im}
self:format_out(lui, args)
if im[2] % 0x10000 ~= 0 then
args.immediate = {'LOWER', im}
self:format_out(ori, args)
end
elseif im[2] >= 0x8000 and im[2] < 0x10000 then
args.rs = 'R0'
args.immediate = {'LOWER', im}
self:format_out(ori, args)
else
args.rs = 'R0'
args.immediate = {'LOWER', im}
self:format_out(addiu, args)
end
end
function overrides.LA(self, name)
local lui = instructions['LUI']
local addiu = instructions['ADDIU']
local args = {}
args.rt = self:register()
self:optional_comma()
local im = self:const()
args.rs = args.rt
args.immediate = {'UPPEROFF', im}
self:format_out(lui, args)
args.immediate = {'LOWER', im}
self:format_out(addiu, args)
end
function overrides.PUSH(self, name)
local addi = instructions['ADDI']
local w = instructions[name == 'PUSH' and 'SW' or 'LW']
local jr = instructions['JR']
local stack = {}
while not self:is_EOL() do
if self.tt == 'NUM' then
if self.tok < 0 then
self:error("can't push a negative number of spaces")
end
for i=1,self.tok do
insert(stack, '')
end
self:advance()
else
insert(stack, self:register())
end
if not self:is_EOL() then
self:optional_comma()
end
end
if #stack == 0 then
self:error(name..' requires at least one argument')
end
local args = {}
if name == 'PUSH' then
args.rt = 'SP'
args.rs = 'SP'
args.immediate = {'NEGATE', {'NUM', #stack*4}}
self:format_out(addi, args)
end
args.base = 'SP'
for i, r in ipairs(stack) do
args.rt = r
if r ~= '' then
args.offset = {'NUM', (i - 1)*4}
self:format_out(w, args)
end
end
if name == 'JPOP' then
args.rs = 'RA'
self:format_out(jr, args)
end
if name == 'POP' or name == 'JPOP' then
args.rt = 'SP'
args.rs = 'SP'
args.immediate = {'NUM', #stack*4}
self:format_out(addi, args)
end
end
overrides.POP = overrides.PUSH
overrides.JPOP = overrides.PUSH
function overrides.NAND(self, name)
local and_ = instructions['AND']
local nor = instructions['NOR']
local args = {}
args.rd = self:register()
self:optional_comma()
args.rs = self:register()
self:optional_comma()
args.rt = self:register()
self:format_out(and_, args)
args.rs = args.rd
args.rt = 'R0'
self:format_out(nor, args)
end
function overrides.NANDI(self, name)
local andi = instructions['ANDI']
local nor = instructions['NOR']
local args = {}
args.rt = self:register()
self:optional_comma()
args.rs = self:register()
self:optional_comma()
args.immediate = self:const()
self:format_out(andi[3], andi[1], args, andi[4], andi[5])
args.rd = args.rt
args.rs = args.rt
args.rt = 'R0'
self:format_out(nor[3], nor[1], args, nor[4], nor[5])
end
function overrides.NORI(self, name)
local ori = instructions['ORI']
local nor = instructions['NOR']
local args = {}
args.rt = self:register()
self:optional_comma()
args.rs = self:register()
self:optional_comma()
args.immediate = self:const()
self:format_out(ori, args)
args.rd = args.rt
args.rs = args.rt
args.rt = 'R0'
self:format_out(nor, args)
end
function overrides.ROL(self, name)
local sll = instructions['SLL']
local srl = instructions['SRL']
local or_ = instructions['OR']
local args = {}
local left = self:register()
self:optional_comma()
args.rt = self:register()
self:optional_comma()
args.immediate = self:const()
args.rd = left
if args.rd == 'AT' or args.rt == 'AT' then
self:error('registers cannot be AT in this pseudo-instruction')
end
if args.rd == args.rt and args.rd ~= 'R0' then
self:error('registers cannot be the same')
end
self:format_out(sll, args)
args.rd = 'AT'
args.immediate = {'NUM', 32 - args.immediate[2]}
self:format_out(srl, args)
args.rd = left
args.rs = left
args.rt = 'AT'
self:format_out(or_, args)
end
function overrides.ROR(self, name)
local sll = instructions['SLL']
local srl = instructions['SRL']
local or_ = instructions['OR']
local args = {}
local right = self:register()
self:optional_comma()
args.rt = self:register()
self:optional_comma()
args.immediate = self:const()
args.rd = right
if args.rt == 'AT' or args.rd == 'AT' then
self:error('registers cannot be AT in a pseudo-instruction that uses AT')
end
if args.rd == args.rt and args.rd ~= 'R0' then
self:error('registers cannot be the same')
end
self:format_out(srl, args)
args.rd = 'AT'
args.immediate = {'NUM', 32 - args.immediate[2]}
self:format_out(sll, args)
args.rd = right
args.rs = right
args.rt = 'AT'
self:format_out(or_, args)
end
function overrides.JR(self, name)
local jr = instructions['JR']
local args = {}
if self:is_EOL() then
args.rs = 'RA'
else
args.rs = self:register()
end
self:format_out(jr, args)
end
local branch_basics = {
BEQI = "BEQ",
BGEI = "BEQ",
BGTI = "BEQ",
BLEI = "BNE",
BLTI = "BNE",
BNEI = "BNE",
}
function overrides.BEQI(self, name)
local addiu = instructions['ADDIU']
local branch = instructions[branch_basics[name]]
local args = {}
local reg = self:register()
self:optional_comma()
args.immediate = self:const()
self:optional_comma()
args.offset = {'SIGNED', self:const('relative')}
if reg == 'AT' then
self:error('register cannot be AT in this pseudo-instruction')
end
args.rt = 'AT'
args.rs = 'R0'
self:format_out(addiu, args)
args.rs = reg
self:format_out(branch, args)
end
overrides.BNEI = overrides.BEQI
function overrides.BLTI(self, name)
local slti = instructions['SLTI']
local branch = instructions[branch_basics[name]]
local args = {}
args.rs = self:register()
self:optional_comma()
args.immediate = self:const()
self:optional_comma()
args.offset = {'SIGNED', self:const('relative')}
if args.rs == 'AT' then
self:error('register cannot be AT in this pseudo-instruction')
end
args.rt = 'AT'
self:format_out(slti, args)
args.rs = 'AT'
args.rt = 'R0'
self:format_out(branch, args)
end
overrides.BGEI = overrides.BLTI
function overrides.BLEI(self, name)
-- TODO: this can probably be optimized
local addiu = instructions['ADDIU']
local slt = instructions['SLT']
local branch = instructions[branch_basics[name]]
local beq = instructions['BEQ']
local args = {}
local reg = self:register()
self:optional_comma()
args.immediate = self:const()
self:optional_comma()
local offset = {'SIGNED', self:const('relative')}
if reg == 'AT' then
self:error('register cannot be AT in this pseudo-instruction')
end
args.rt = 'AT'
args.rs = 'R0'
self:format_out(addiu, args)
if name == 'BLEI' then
args.offset = offset
else
args.offset = 2 -- branch to delay slot of the next branch
end
args.rs = reg
self:format_out(beq, args)
args.rd = 'AT'
self:format_out(slt, args)
args.rs = 'AT'
args.rt = 'R0'
args.offset = offset
self:format_out(branch, args)
end
overrides.BGTI = overrides.BLEI
return overrides