2021-08-30 16:27:37 +00:00
|
|
|
|
|
|
|
$bytes = []
|
|
|
|
|
|
|
|
def zero_fill(pos)
|
|
|
|
while ($bytes.length <= pos) do
|
|
|
|
$bytes.push(0)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-08-30 18:38:26 +00:00
|
|
|
def word(i)
|
2021-08-30 16:27:37 +00:00
|
|
|
$bytes.push((i & 0x000000ff),
|
|
|
|
(i & 0x0000ff00) >> 8,
|
|
|
|
(i & 0x00ff0000) >> 16,
|
|
|
|
(i & 0xff000000) >> 24)
|
|
|
|
end
|
|
|
|
|
|
|
|
def string(s)
|
|
|
|
$bytes.push *s.bytes
|
2021-08-31 21:22:29 +00:00
|
|
|
$bytes.push 0 # null terminate
|
2021-08-30 16:27:37 +00:00
|
|
|
while (($bytes.length % 4) != 0) do
|
|
|
|
$bytes.push 0
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-08-31 09:11:25 +00:00
|
|
|
|
2021-08-31 10:13:55 +00:00
|
|
|
# # # REGISTER NAMES # # #
|
2021-08-31 20:37:31 +00:00
|
|
|
def r0() 0 end # zero
|
2021-08-31 10:13:55 +00:00
|
|
|
def at() 1 end # assembler temporary
|
|
|
|
|
|
|
|
# subroutine return values, may be changed by subroutines
|
|
|
|
def v0() 2 end ; def v0() 3 end
|
|
|
|
|
|
|
|
# subroutine arguments, may be changed by subroutines
|
|
|
|
def a0() 4 end ; def a1() 5 end
|
|
|
|
def a2() 6 end ; def a3() 7 end
|
|
|
|
|
|
|
|
# temporaries, may be changed by subroutines
|
|
|
|
def t0() 8 end ; def t1() 9 end
|
|
|
|
def t2() 10 end ; def t3() 11 end
|
|
|
|
def t4() 12 end ; def t5() 13 end
|
|
|
|
def t6() 14 end ; def t7() 15 end
|
|
|
|
|
|
|
|
# static variables, must be saved by subs
|
|
|
|
def s0() 16 end ; def s1() 17 end
|
|
|
|
def s2() 18 end ; def s3() 19 end
|
|
|
|
def s4() 20 end ; def s5() 21 end
|
|
|
|
def s6() 22 end ; def s7() 23 end
|
|
|
|
|
|
|
|
# temporaries, may be changed by subroutines
|
|
|
|
def t8() 24 end ; def t9() 25 end
|
|
|
|
|
|
|
|
# reserved for kernel, detroyed by some irq handlers
|
|
|
|
def k0() 26 end ; def k1() 27 end
|
|
|
|
|
|
|
|
def gp() 28 end # global pointer, rarely used
|
|
|
|
def sp() 29 end # stack pointer
|
|
|
|
def fp() 30 end # frame pointer
|
|
|
|
def ra() 31 end # return address
|
|
|
|
|
2021-08-31 09:11:25 +00:00
|
|
|
|
|
|
|
|
|
|
|
# # # INSTRUCTIONS # # #
|
2021-08-31 09:37:09 +00:00
|
|
|
|
|
|
|
# ops should always be in format of
|
|
|
|
# [src] [args] -> [dest]
|
|
|
|
|
2021-08-30 16:27:37 +00:00
|
|
|
def jmp(addr)
|
|
|
|
# TODO: this probs wont show up since we have < 3mb of ram but
|
|
|
|
# we can't jump to an address with a different 4 most significant bits
|
|
|
|
raise "jmp addr must be 4 byte aligned" if addr % 4 != 0
|
|
|
|
op = 0b0000_1000_0000_0000_0000_0000_0000_0000
|
|
|
|
op = op | ((addr >> 2) & 0b11_11111111_11111111_11111111)
|
2021-08-30 18:38:26 +00:00
|
|
|
word op
|
2021-08-30 16:27:37 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def jal(addr)
|
|
|
|
# TODO: same problem as jmp
|
|
|
|
raise "jmp addr must be 4 byte aligned" if addr % 4 != 0
|
|
|
|
op = 0b0000_1100_0000_0000_0000_0000_0000_0000
|
|
|
|
op = op | ((addr >> 2) & 0b11_11111111_11111111_11111111)
|
2021-08-30 18:38:26 +00:00
|
|
|
word op
|
2021-08-30 16:27:37 +00:00
|
|
|
end
|
|
|
|
|
2021-08-30 18:36:12 +00:00
|
|
|
# load upper immediate
|
2021-08-31 09:11:25 +00:00
|
|
|
# NOTE: val will be shifted left by 16
|
|
|
|
def lui(val, dest)
|
2021-08-31 09:37:09 +00:00
|
|
|
# oooooo ----- ddddd iiiiiiiiiiiiiiii
|
2021-08-30 18:36:12 +00:00
|
|
|
op = 0b001111_00000_00000_0000000000000000
|
|
|
|
op |= 0xffff & val
|
2021-08-31 09:11:25 +00:00
|
|
|
op |= (0b11111 & dest) << 16
|
2021-08-30 18:38:26 +00:00
|
|
|
word op
|
2021-08-30 18:36:12 +00:00
|
|
|
end
|
|
|
|
|
2021-08-30 19:12:26 +00:00
|
|
|
# shift right logical
|
|
|
|
def srl(src, amt, dest)
|
|
|
|
# oooooo ----- sssss ddddd hhhhh oooooo
|
|
|
|
op = 0b000000_00000_00000_00000_00000_000010
|
|
|
|
op |= (src & 0b11111) << 16
|
|
|
|
op |= (amt & 0b11111) << 6
|
|
|
|
op |= (dest & 0b11111) << 11
|
|
|
|
word op
|
|
|
|
end
|
|
|
|
|
2021-08-31 09:11:25 +00:00
|
|
|
# or immediate
|
|
|
|
def ori(src, bits, dest)
|
|
|
|
# oooooo sssss ddddd iiiiiiii iiiiiiii
|
|
|
|
op = 0b001101_00000_00000_00000000_00000000
|
|
|
|
op |= (src & 0b11111) << 21
|
|
|
|
op |= (bits & 0xffff)
|
2021-08-31 09:37:09 +00:00
|
|
|
op |= (dest & 0b11111) << 16
|
2021-08-31 09:11:25 +00:00
|
|
|
word op
|
|
|
|
end
|
|
|
|
|
2021-08-31 09:37:09 +00:00
|
|
|
# store word
|
2021-08-31 09:50:42 +00:00
|
|
|
# NOTE: this doesn't work unaligned
|
2021-08-31 09:37:09 +00:00
|
|
|
def sw(src, offset, dest)
|
|
|
|
# oooooo ddddd sssss iiiiiiii iiiiiiii
|
|
|
|
op = 0b101011_00000_00000_00000000_00000000
|
|
|
|
op |= (src & 0b11111) << 16
|
|
|
|
op |= (offset & 0xffff)
|
|
|
|
op |= (dest & 0b11111) << 21
|
|
|
|
word op
|
|
|
|
end
|
2021-08-31 09:11:25 +00:00
|
|
|
|
2021-08-31 20:37:31 +00:00
|
|
|
# add immediate unsigned
|
|
|
|
def addiu(src, val, dest)
|
|
|
|
# oooooo sssss ddddd iiiiiiii iiiiiiii
|
|
|
|
op = 0b001001_00000_00000_00000000_00000000
|
|
|
|
op |= (src & 0b11111) << 21
|
|
|
|
op |= (val & 0xffff)
|
|
|
|
op |= (dest & 0b11111) << 16
|
|
|
|
word op
|
|
|
|
end
|
|
|
|
|
|
|
|
# add immediate
|
|
|
|
def addi(src, val, dest)
|
|
|
|
# oooooo sssss ddddd iiiiiiii iiiiiiii
|
|
|
|
op = 0b001000_00000_00000_00000000_00000000
|
|
|
|
op |= (src & 0b11111) << 21
|
|
|
|
op |= (val & 0xffff)
|
|
|
|
op |= (dest & 0b11111) << 16
|
|
|
|
word op
|
|
|
|
end
|
2021-08-31 09:11:25 +00:00
|
|
|
|
2021-08-31 21:22:29 +00:00
|
|
|
# jump register
|
|
|
|
def jr(reg)
|
|
|
|
# oooooo rrrrr ----- ----- ----- oooooo
|
|
|
|
op = 0b000000_00000_00000_00000_00000_001000
|
|
|
|
op |= (reg & 0b11111) << 21
|
|
|
|
word op
|
|
|
|
end
|
|
|
|
|
|
|
|
|
2021-08-31 09:11:25 +00:00
|
|
|
|
|
|
|
# # # PSEUDO-INSTRUCTIONS # # #
|
|
|
|
def nop
|
|
|
|
word 0x00000000
|
|
|
|
end
|
|
|
|
|
2021-08-31 09:50:42 +00:00
|
|
|
# load word immediate
|
|
|
|
def lwi(val, dest)
|
|
|
|
lui val >> 16, dest
|
|
|
|
ori dest, val, dest
|
|
|
|
end
|
|
|
|
|
2021-08-31 09:11:25 +00:00
|
|
|
|
|
|
|
|
2021-08-30 18:36:12 +00:00
|
|
|
|
2021-08-31 16:32:08 +00:00
|
|
|
|
|
|
|
def label
|
|
|
|
return $bytes.length + $base_addr
|
|
|
|
end
|
|
|
|
|
2021-08-30 18:36:12 +00:00
|
|
|
# this is a terrible idea and im doing it
|
|
|
|
#$labels = {}
|
|
|
|
#def method_missing(m, *args)
|
|
|
|
# puts m.to_s
|
|
|
|
# super
|
|
|
|
#end
|
|
|
|
|
2021-08-30 19:12:26 +00:00
|
|
|
|
|
|
|
# # # CONSTANTS # # #
|
2021-08-30 16:27:37 +00:00
|
|
|
$base_addr = 0x80010000 # 0x10000 # 0x80010000
|
2021-08-31 10:13:55 +00:00
|
|
|
$file_size = 0x800 * 3
|
2021-08-31 09:11:25 +00:00
|
|
|
$gp0 = 0x1F801810
|
2021-08-31 16:32:08 +00:00
|
|
|
$gp1 = 0x1F801814
|
2021-08-30 18:36:12 +00:00
|
|
|
|
|
|
|
# # # EXE HEADER # # #
|
2021-08-30 16:27:37 +00:00
|
|
|
string "PS-X EXE"
|
|
|
|
zero_fill 0x00f
|
2021-08-30 18:38:26 +00:00
|
|
|
word $base_addr # initial pc
|
|
|
|
word 0x00000000 # initial GP/R28
|
|
|
|
word $base_addr # destintation address in RAM
|
2021-08-30 19:12:26 +00:00
|
|
|
word $file_size # file size excluding header (must be N * 0x800)
|
2021-08-30 18:38:26 +00:00
|
|
|
word 0x00000000 # Unknown/Unused
|
|
|
|
word 0x00000000 # Unknown/Unused
|
|
|
|
word 0x00000000 # Memfill start address
|
|
|
|
word 0x00000000 # Memfill size in bytes
|
|
|
|
word 0x801ffff0 # Initial SP/R29 & FP/R30 Base
|
|
|
|
word 0x00000000 # Initial SP/R29 & FP/R30 Offs
|
2021-08-30 16:27:37 +00:00
|
|
|
zero_fill 0x4b # Reserved for A(43h) Function
|
|
|
|
# Ascii marker would go here
|
|
|
|
zero_fill 0x7ff
|
2021-08-30 18:36:12 +00:00
|
|
|
$exe_header = $bytes[0..]
|
|
|
|
$bytes = []
|
|
|
|
|
|
|
|
|
2021-08-30 16:27:37 +00:00
|
|
|
|
2021-08-30 18:36:12 +00:00
|
|
|
|
|
|
|
# # # PROGRAM CODE # # #
|
2021-08-31 16:32:08 +00:00
|
|
|
nop
|
2021-08-31 21:22:29 +00:00
|
|
|
jmp $base_addr + 0x400
|
|
|
|
nop
|
|
|
|
|
|
|
|
l_hello_world = label
|
|
|
|
string "ello wrld!\n"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
l_printf = label
|
|
|
|
addiu r0, 0xa0, at # address of bios func
|
|
|
|
jr at
|
|
|
|
addiu r0, 0x3f, t1 # printf number
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
zero_fill 0x400 - 1
|
|
|
|
nop
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
lwi l_hello_world, a0
|
|
|
|
jal l_printf
|
|
|
|
addiu sp, -16, sp # delay slot
|
|
|
|
addiu sp, 16, sp
|
|
|
|
|
|
|
|
nop ; nop ; nop ; nop
|
2021-08-30 19:12:26 +00:00
|
|
|
|
|
|
|
|
2021-08-31 16:32:08 +00:00
|
|
|
# THIS IS NEEDED
|
|
|
|
lwi $gp1, t0
|
|
|
|
lwi 0x03_00_00_00, t1 # display enable
|
|
|
|
sw t1, 0, t0
|
2021-08-30 19:12:26 +00:00
|
|
|
|
2021-08-31 16:32:08 +00:00
|
|
|
lwi $gp0, t0
|
|
|
|
|
|
|
|
lwi 0xe1_000000 + 0b0_0_0_1_0_01_00_0_0000, t1
|
|
|
|
sw t1, 0, t0
|
2021-08-31 09:37:09 +00:00
|
|
|
|
2021-08-31 16:32:08 +00:00
|
|
|
# THIS IS NEEDED
|
|
|
|
lwi 0xe4_000000 + (640) + (480 << 10), t1 # Drawing Area bottom right
|
|
|
|
sw t1, 0, t0
|
2021-08-31 09:37:09 +00:00
|
|
|
|
2021-08-31 16:32:08 +00:00
|
|
|
def line(st, en)
|
|
|
|
lwi 0x40_ffffff, t1 # monochrome line, color ffffff
|
|
|
|
sw t1, 0, t0
|
|
|
|
|
|
|
|
lwi st, t1 # line vert 1
|
|
|
|
sw t1, 0, t0
|
|
|
|
|
|
|
|
lwi en, t1 # line vert 2
|
|
|
|
sw t1, 0, t0
|
|
|
|
end
|
|
|
|
|
2021-08-31 20:37:31 +00:00
|
|
|
# l_end_loop = label
|
2021-08-31 16:32:08 +00:00
|
|
|
line 0x0010_0010, 0x0030_0030
|
|
|
|
line 0x0030_0030, 0x0060_0000
|
2021-08-31 20:37:31 +00:00
|
|
|
line 0x0060_000a, 0x00f0_0060
|
2021-08-31 09:37:09 +00:00
|
|
|
|
2021-08-31 09:11:25 +00:00
|
|
|
nop ; nop ; nop ; nop
|
|
|
|
nop ; nop ; nop ; nop
|
|
|
|
nop ; nop ; nop ; nop
|
|
|
|
nop ; nop ; nop ; nop
|
2021-08-30 19:12:26 +00:00
|
|
|
|
2021-08-31 20:37:31 +00:00
|
|
|
l_end_loop = label
|
|
|
|
nop
|
2021-08-31 21:22:29 +00:00
|
|
|
lwi l_end_loop, t9
|
|
|
|
jr t9
|
2021-08-31 20:37:31 +00:00
|
|
|
nop
|
2021-08-30 19:12:26 +00:00
|
|
|
|
2021-08-30 16:27:37 +00:00
|
|
|
|
2021-08-30 18:36:12 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
2021-08-30 16:27:37 +00:00
|
|
|
|
2021-08-31 20:37:31 +00:00
|
|
|
puts "assembled 0x#{$bytes.length.to_s 16} (#{$bytes.length}) bytes"
|
|
|
|
raise "CODE IS GREATER THAN FILESIZE" if $bytes.length > $file_size
|
2021-08-30 19:12:26 +00:00
|
|
|
zero_fill $file_size - 1
|
2021-08-30 16:27:37 +00:00
|
|
|
|
|
|
|
f = File.new "LOADTHIS.EXE", "wb"
|
2021-08-30 18:36:12 +00:00
|
|
|
f.write $exe_header.pack("C*")
|
2021-08-30 16:27:37 +00:00
|
|
|
f.write $bytes.pack("C*")
|
|
|
|
f.close
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|