mirror of
https://github.com/notwa/mm
synced 2025-02-05 05:23:22 -08:00
base spawn asms on one file
This commit is contained in:
parent
ce1d440bfb
commit
d5c7097713
5 changed files with 93 additions and 157 deletions
|
@ -107,5 +107,5 @@ end
|
||||||
if oot then
|
if oot then
|
||||||
inject('spawn oot.asm')
|
inject('spawn oot.asm')
|
||||||
else
|
else
|
||||||
inject('spawn.asm')
|
inject('spawn mm.asm')
|
||||||
end
|
end
|
||||||
|
|
|
@ -33,6 +33,16 @@ local function bitrange(x, lower, upper)
|
||||||
return floor(x/2^lower) % 2^(upper - lower + 1)
|
return floor(x/2^lower) % 2^(upper - lower + 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function readfile(fn)
|
||||||
|
local f = io.open(fn, 'r')
|
||||||
|
if not f then
|
||||||
|
error('could not open assembly file for reading: '..tostring(fn), 2)
|
||||||
|
end
|
||||||
|
local asm = f:read('*a')
|
||||||
|
f:close()
|
||||||
|
return asm
|
||||||
|
end
|
||||||
|
|
||||||
local registers = {
|
local registers = {
|
||||||
[0]=
|
[0]=
|
||||||
'R0', 'AT', 'V0', 'V1', 'A0', 'A1', 'A2', 'A3',
|
'R0', 'AT', 'V0', 'V1', 'A0', 'A1', 'A2', 'A3',
|
||||||
|
@ -446,9 +456,10 @@ end
|
||||||
revtable(all_instructions)
|
revtable(all_instructions)
|
||||||
|
|
||||||
local Lexer = Class()
|
local Lexer = Class()
|
||||||
function Lexer:init(asm, fn)
|
function Lexer:init(asm, fn, options)
|
||||||
self.asm = asm
|
self.asm = asm
|
||||||
self.fn = fn or '(string)'
|
self.fn = fn or '(string)'
|
||||||
|
self.options = options or {}
|
||||||
self.pos = 1
|
self.pos = 1
|
||||||
self.line = 1
|
self.line = 1
|
||||||
self.EOF = -1
|
self.EOF = -1
|
||||||
|
@ -459,21 +470,22 @@ local Dumper = Class()
|
||||||
function Dumper:init(writer, fn, options)
|
function Dumper:init(writer, fn, options)
|
||||||
self.writer = writer
|
self.writer = writer
|
||||||
self.fn = fn or '(string)'
|
self.fn = fn or '(string)'
|
||||||
|
self.options = options or {}
|
||||||
self.labels = {}
|
self.labels = {}
|
||||||
self.commands = {}
|
self.commands = {}
|
||||||
self.buff = ''
|
self.buff = ''
|
||||||
self.pos = 0
|
self.pos = 0
|
||||||
self.size = 0
|
self.size = 0
|
||||||
self.lastcommand = nil
|
self.lastcommand = nil
|
||||||
self.options = options or {}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local Parser = Class()
|
local Parser = Class()
|
||||||
function Parser:init(writer, fn, options)
|
function Parser:init(writer, fn, options)
|
||||||
self.fn = fn or '(string)'
|
self.fn = fn or '(string)'
|
||||||
|
self.main_fn = self.fn
|
||||||
|
self.options = options or {}
|
||||||
self.dumper = Dumper(writer, fn, options)
|
self.dumper = Dumper(writer, fn, options)
|
||||||
self.defines = {}
|
self.defines = {}
|
||||||
self.options = options or {}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function Lexer:error(msg)
|
function Lexer:error(msg)
|
||||||
|
@ -655,7 +667,39 @@ function Lexer:lex_block_comment(yield)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function Lexer:lex(yield)
|
function Lexer:lex_string(yield)
|
||||||
|
-- TODO: support escaping
|
||||||
|
if self.chr ~= '"' then
|
||||||
|
print(self.chr, self.ord)
|
||||||
|
self:error("expected opening double quote")
|
||||||
|
end
|
||||||
|
self:nextc()
|
||||||
|
local buff = self:read_chars('[^"\n]')
|
||||||
|
if self.chr ~= '"' then
|
||||||
|
print(self.chr)
|
||||||
|
self:error("expected closing double quote")
|
||||||
|
end
|
||||||
|
self:nextc()
|
||||||
|
yield('STRING', buff)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Lexer:lex_include(_yield)
|
||||||
|
self:read_chars('%s')
|
||||||
|
local fn
|
||||||
|
self:lex_string(function(tt, tok)
|
||||||
|
fn = tok
|
||||||
|
end)
|
||||||
|
if self.options.path then
|
||||||
|
fn = self.options.path..fn
|
||||||
|
end
|
||||||
|
local sublexer = Lexer(readfile(fn), fn, self.options)
|
||||||
|
sublexer:lex(_yield)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Lexer:lex(_yield)
|
||||||
|
local function yield(tt, tok)
|
||||||
|
return _yield(tt, tok, self.fn)
|
||||||
|
end
|
||||||
while true do
|
while true do
|
||||||
if self.chr == '\n' then
|
if self.chr == '\n' then
|
||||||
self:nextc()
|
self:nextc()
|
||||||
|
@ -709,6 +753,7 @@ function Lexer:lex(yield)
|
||||||
end
|
end
|
||||||
if up == 'INC' or up == 'INCASM' or up == 'INCLUDE' then
|
if up == 'INC' or up == 'INCASM' or up == 'INCLUDE' then
|
||||||
yield('DIR', 'INC')
|
yield('DIR', 'INC')
|
||||||
|
self:lex_include(_yield)
|
||||||
else
|
else
|
||||||
yield('DIR', up)
|
yield('DIR', up)
|
||||||
end
|
end
|
||||||
|
@ -769,16 +814,11 @@ function Parser:advance()
|
||||||
local t = self.tokens[self.i]
|
local t = self.tokens[self.i]
|
||||||
self.tt = t.tt
|
self.tt = t.tt
|
||||||
self.tok = t.tok
|
self.tok = t.tok
|
||||||
|
self.fn = t.fn
|
||||||
self.line = t.line
|
self.line = t.line
|
||||||
return t.tt, t.tok
|
return t.tt, t.tok
|
||||||
end
|
end
|
||||||
|
|
||||||
function Parser:lookahead()
|
|
||||||
local t = self.tokens[self.i] + 1
|
|
||||||
if t == nil then return end
|
|
||||||
return t.tt, t.tok
|
|
||||||
end
|
|
||||||
|
|
||||||
function Parser:is_EOL()
|
function Parser:is_EOL()
|
||||||
return self.tt == 'EOL' or self.tt == 'EOF'
|
return self.tt == 'EOL' or self.tt == 'EOF'
|
||||||
end
|
end
|
||||||
|
@ -837,7 +877,9 @@ function Parser:directive()
|
||||||
self:expect_EOL()
|
self:expect_EOL()
|
||||||
elseif name == 'HEX' then
|
elseif name == 'HEX' then
|
||||||
self:error('unimplemented')
|
self:error('unimplemented')
|
||||||
elseif name == 'INC' or name == 'INCBIN' then
|
elseif name == 'INC' then
|
||||||
|
-- noop
|
||||||
|
elseif name == 'INCBIN' then
|
||||||
self:error('unimplemented')
|
self:error('unimplemented')
|
||||||
elseif name == 'FLOAT' or name == 'ASCII' or name == 'ASCIIZ' then
|
elseif name == 'FLOAT' or name == 'ASCII' or name == 'ASCIIZ' then
|
||||||
self:error('unimplemented')
|
self:error('unimplemented')
|
||||||
|
@ -1211,27 +1253,28 @@ function Parser:instruction()
|
||||||
self:expect_EOL()
|
self:expect_EOL()
|
||||||
end
|
end
|
||||||
|
|
||||||
function Parser:tokenize()
|
function Parser:tokenize(asm)
|
||||||
self.tokens = {}
|
self.tokens = {}
|
||||||
self.i = 0
|
self.i = 0
|
||||||
local line = 1
|
local line = 1
|
||||||
|
|
||||||
local routine = coroutine.create(function()
|
local routine = coroutine.create(function()
|
||||||
local lexer = Lexer(self.asm, self.fn)
|
local lexer = Lexer(asm, self.main_fn, self.options)
|
||||||
lexer:lex(coroutine.yield)
|
lexer:lex(coroutine.yield)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
local lex = function()
|
local function lex()
|
||||||
local t = {line=line}
|
local t = {line=line}
|
||||||
local ok, a, b = coroutine.resume(routine)
|
local ok, a, b, c = coroutine.resume(routine)
|
||||||
if not ok then
|
if not ok then
|
||||||
a = a or 'Internal Error: lexer coroutine has stopped'
|
a = a or 'Internal Error: lexer coroutine has stopped'
|
||||||
error(a)
|
error(a)
|
||||||
end
|
end
|
||||||
t.tt = a
|
t.tt = a
|
||||||
t.tok = b
|
t.tok = b
|
||||||
|
t.fn = c
|
||||||
table.insert(self.tokens, t)
|
table.insert(self.tokens, t)
|
||||||
return t.tt, t.tok
|
return t.tt, t.tok, t.fn
|
||||||
end
|
end
|
||||||
|
|
||||||
-- first pass: collect tokens and constants.
|
-- first pass: collect tokens and constants.
|
||||||
|
@ -1241,7 +1284,7 @@ function Parser:tokenize()
|
||||||
-- this would cause a recursive problem to solve,
|
-- this would cause a recursive problem to solve,
|
||||||
-- which is too much for our simple assembler.
|
-- which is too much for our simple assembler.
|
||||||
while true do
|
while true do
|
||||||
local tt, tok = lex()
|
local tt, tok, fn = lex()
|
||||||
if tt == 'DEF' then
|
if tt == 'DEF' then
|
||||||
local tt2, tok2 = lex()
|
local tt2, tok2 = lex()
|
||||||
if tt2 ~= 'NUM' then
|
if tt2 ~= 'NUM' then
|
||||||
|
@ -1251,8 +1294,11 @@ function Parser:tokenize()
|
||||||
elseif tt == 'EOL' then
|
elseif tt == 'EOL' then
|
||||||
line = line + 1
|
line = line + 1
|
||||||
elseif tt == 'EOF' then
|
elseif tt == 'EOF' then
|
||||||
break
|
if fn == self.main_fn then
|
||||||
|
break
|
||||||
|
end
|
||||||
elseif tt == nil then
|
elseif tt == nil then
|
||||||
|
--require("pt"){self.tokens, writer=print}
|
||||||
error('Internal Error: missing token', 1)
|
error('Internal Error: missing token', 1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1271,12 +1317,14 @@ function Parser:tokenize()
|
||||||
end
|
end
|
||||||
|
|
||||||
function Parser:parse(asm)
|
function Parser:parse(asm)
|
||||||
self.asm = asm
|
self:tokenize(asm)
|
||||||
self:tokenize()
|
|
||||||
self:advance()
|
self:advance()
|
||||||
while true do
|
while true do
|
||||||
if self.tt == 'EOF' then
|
if self.tt == 'EOF' then
|
||||||
break
|
if self.fn == self.main_fn then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
self:advance()
|
||||||
elseif self.tt == 'EOL' then
|
elseif self.tt == 'EOL' then
|
||||||
-- empty line
|
-- empty line
|
||||||
self:advance()
|
self:advance()
|
||||||
|
@ -1354,7 +1402,6 @@ function Dumper:add_bytes(line, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Dumper:add_directive(line, name, a, b)
|
function Dumper:add_directive(line, name, a, b)
|
||||||
-- ORG ALIGN SKIP BYTE HALFWORD WORD
|
|
||||||
local t = {}
|
local t = {}
|
||||||
t.line = line
|
t.line = line
|
||||||
if name == 'BYTE' then
|
if name == 'BYTE' then
|
||||||
|
@ -1585,17 +1632,13 @@ function assembler.assemble(fn_or_asm, writer, options)
|
||||||
|
|
||||||
function main()
|
function main()
|
||||||
local fn = nil
|
local fn = nil
|
||||||
local asm = ''
|
local asm
|
||||||
if fn_or_asm:find('[\r\n]') then
|
if fn_or_asm:find('[\r\n]') then
|
||||||
asm = fn_or_asm
|
asm = fn_or_asm
|
||||||
else
|
else
|
||||||
fn = fn_or_asm
|
fn = fn_or_asm
|
||||||
local f = io.open(fn, 'r')
|
asm = readfile(fn)
|
||||||
if not f then
|
options.path = fn:match(".*/")
|
||||||
error('could not read assembly file', 1)
|
|
||||||
end
|
|
||||||
asm = f:read('*a')
|
|
||||||
f:close()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local parser = Parser(writer, fn, options)
|
local parser = Parser(writer, fn, options)
|
||||||
|
|
19
Lua/inject/spawn mm.asm
Normal file
19
Lua/inject/spawn mm.asm
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
[actor_spawn]: 0x800BAE14
|
||||||
|
[max_actor_no]: 0x2B1
|
||||||
|
|
||||||
|
[global_context]: 0x803E6B20
|
||||||
|
[buttons_offset]: 0x14
|
||||||
|
[actor_spawn_offset]: 0x1CA0
|
||||||
|
|
||||||
|
[link_actor]: 0x803FFDB0
|
||||||
|
[actor_x]: 0x24
|
||||||
|
[actor_y]: 0x28
|
||||||
|
[actor_z]: 0x2C
|
||||||
|
[actor_horiz_angle]: 0x32
|
||||||
|
|
||||||
|
[link_save]: 0x801EF670
|
||||||
|
[rupees_offset]: 0x3A
|
||||||
|
[upgrades_offset]: 0xB8
|
||||||
|
[upgrades_2_offset]: 0xBA
|
||||||
|
|
||||||
|
.include "spawn.asm"
|
|
@ -16,112 +16,4 @@
|
||||||
[upgrades_offset]: 0xA0
|
[upgrades_offset]: 0xA0
|
||||||
[upgrades_2_offset]: 0xA2
|
[upgrades_2_offset]: 0xA2
|
||||||
|
|
||||||
[button_L]: 0x0020
|
.include "spawn.asm"
|
||||||
[button_D_right]: 0x0100
|
|
||||||
[button_D_left]: 0x0200
|
|
||||||
[button_D_down]: 0x0400
|
|
||||||
[button_D_up]: 0x0800
|
|
||||||
[button_any]: 0x0F20
|
|
||||||
|
|
||||||
[hold_delay_amount]: 3
|
|
||||||
|
|
||||||
push 4, s1, ra
|
|
||||||
li t0, @link_save
|
|
||||||
li t1, @global_context
|
|
||||||
// give max rupee upgrade (set bit 13, clear bit 12 of lower halfword)
|
|
||||||
lh t2, @upgrades_2_offset(t0)
|
|
||||||
ori t2, t2, 0x2000
|
|
||||||
andi t2, t2, 0xEFFF
|
|
||||||
sh t2, @upgrades_2_offset(t0)
|
|
||||||
//
|
|
||||||
lhu t2, @buttons_offset(t1)
|
|
||||||
lh t9, @rupees_offset(t0)
|
|
||||||
lw s1, hold_delay
|
|
||||||
andi t4, t2, @button_any
|
|
||||||
bne t4, r0, no_reset
|
|
||||||
addi s1, s1, 1
|
|
||||||
li s1, 0
|
|
||||||
no_reset:
|
|
||||||
subi t4, s1, 1
|
|
||||||
beq t4, r0, first_time
|
|
||||||
nop
|
|
||||||
subi t4, s1, @hold_delay_amount
|
|
||||||
bltz t4, return
|
|
||||||
nop
|
|
||||||
first_time:
|
|
||||||
andi t3, t2, @button_D_up
|
|
||||||
beq t3, r0, no_D_up
|
|
||||||
nop
|
|
||||||
addi t9, t9, 1
|
|
||||||
no_D_up:
|
|
||||||
andi t3, t2, @button_D_down
|
|
||||||
beq t3, r0, no_D_down
|
|
||||||
nop
|
|
||||||
subi t9, t9, 1
|
|
||||||
no_D_down:
|
|
||||||
andi t3, t2, @button_D_right
|
|
||||||
beq t3, r0, no_D_right
|
|
||||||
nop
|
|
||||||
addi t9, t9, 10
|
|
||||||
no_D_right:
|
|
||||||
andi t3, t2, @button_D_left
|
|
||||||
beq t3, r0, no_D_left
|
|
||||||
nop
|
|
||||||
subi t9, t9, 10
|
|
||||||
no_D_left:
|
|
||||||
subi t4, t9, 1
|
|
||||||
bgez t4, no_min
|
|
||||||
nop
|
|
||||||
li t9, @max_actor_no
|
|
||||||
no_min:
|
|
||||||
subi t4, t9, @max_actor_no
|
|
||||||
blez t4, no_max
|
|
||||||
nop
|
|
||||||
li t9, 1
|
|
||||||
no_max:
|
|
||||||
sh t9, @rupees_offset(t0)
|
|
||||||
andi t3, t2, @button_L
|
|
||||||
beq t3, r0, return
|
|
||||||
nop
|
|
||||||
mov a0, t9
|
|
||||||
bal simple_spawn
|
|
||||||
nop
|
|
||||||
return:
|
|
||||||
sw s1, hold_delay
|
|
||||||
jpop 4, s1, ra
|
|
||||||
|
|
||||||
simple_spawn: // args: a0 (actor to spawn)
|
|
||||||
push 4, 9, ra
|
|
||||||
mov a2, a0
|
|
||||||
li a1, @global_context
|
|
||||||
addi a0, a1, @actor_spawn_offset
|
|
||||||
li t0, @link_actor
|
|
||||||
lw t1, @actor_x(t0)
|
|
||||||
lw t2, @actor_y(t0)
|
|
||||||
lw t3, @actor_z(t0)
|
|
||||||
mov a3, t1 // X position
|
|
||||||
sw t2, 0x10(sp) // Y position
|
|
||||||
sw t3, 0x14(sp) // Z position
|
|
||||||
|
|
||||||
li t9, 0x0
|
|
||||||
sw t9, 0x18(sp) // rotation?
|
|
||||||
lh t7, @actor_horiz_angle(t0)
|
|
||||||
sw t7, 0x1C(sp) // horizontal rotation
|
|
||||||
li t9, 0x0
|
|
||||||
sw t9, 0x20(sp) // rotation?
|
|
||||||
|
|
||||||
lh t7, @actor_horiz_angle(t0)
|
|
||||||
sw t7, 0x24(sp) // actor variable
|
|
||||||
|
|
||||||
li t9, 0x0000007F
|
|
||||||
sw t9, 0x28(sp) // unknown
|
|
||||||
li t9, 0x000003FF
|
|
||||||
sw t9, 0x2C(sp) // unknown
|
|
||||||
li t9, 0x00000000
|
|
||||||
sw t9, 0x30(sp) // unknown
|
|
||||||
jal @actor_spawn
|
|
||||||
nop
|
|
||||||
jpop 4, 9, ra
|
|
||||||
|
|
||||||
hold_delay:
|
|
||||||
.word 0
|
|
||||||
|
|
|
@ -1,21 +1,3 @@
|
||||||
[actor_spawn]: 0x800BAE14
|
|
||||||
[max_actor_no]: 0x2B1
|
|
||||||
|
|
||||||
[global_context]: 0x803E6B20
|
|
||||||
[buttons_offset]: 0x14
|
|
||||||
[actor_spawn_offset]: 0x1CA0
|
|
||||||
|
|
||||||
[link_actor]: 0x803FFDB0
|
|
||||||
[actor_x]: 0x24
|
|
||||||
[actor_y]: 0x28
|
|
||||||
[actor_z]: 0x2C
|
|
||||||
[actor_horiz_angle]: 0x32
|
|
||||||
|
|
||||||
[link_save]: 0x801EF670
|
|
||||||
[rupees_offset]: 0x3A
|
|
||||||
[upgrades_offset]: 0xB8
|
|
||||||
[upgrades_2_offset]: 0xBA
|
|
||||||
|
|
||||||
[button_L]: 0x0020
|
[button_L]: 0x0020
|
||||||
[button_D_right]: 0x0100
|
[button_D_right]: 0x0100
|
||||||
[button_D_left]: 0x0200
|
[button_D_left]: 0x0200
|
||||||
|
|
Loading…
Add table
Reference in a new issue