Compare commits
No commits in common. "2810109764958026c5790684fbb01ba874e8f4c6" and "481301023e26fc919dd9f9206369ac485670728a" have entirely different histories.
2810109764
...
481301023e
225
assembler.rb
225
assembler.rb
|
@ -1,8 +1,28 @@
|
||||||
|
|
||||||
# assembler.rb
|
$bytes = []
|
||||||
|
|
||||||
|
def zero_fill(pos)
|
||||||
|
while ($bytes.length <= pos) do
|
||||||
|
$bytes.push(0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def word(i)
|
||||||
|
$bytes.push((i & 0x000000ff),
|
||||||
|
(i & 0x0000ff00) >> 8,
|
||||||
|
(i & 0x00ff0000) >> 16,
|
||||||
|
(i & 0xff000000) >> 24)
|
||||||
|
end
|
||||||
|
|
||||||
|
def string(s)
|
||||||
|
$bytes.push *s.bytes
|
||||||
|
while (($bytes.length % 4) != 0) do
|
||||||
|
$bytes.push 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
# # # REGISTER NAMES # # #
|
# # # REGISTER NAMES # # #
|
||||||
def r0() 0 end # zero
|
|
||||||
def at() 1 end # assembler temporary
|
def at() 1 end # assembler temporary
|
||||||
|
|
||||||
# subroutine return values, may be changed by subroutines
|
# subroutine return values, may be changed by subroutines
|
||||||
|
@ -35,71 +55,6 @@ def sp() 29 end # stack pointer
|
||||||
def fp() 30 end # frame pointer
|
def fp() 30 end # frame pointer
|
||||||
def ra() 31 end # return address
|
def ra() 31 end # return address
|
||||||
|
|
||||||
class Assembler
|
|
||||||
def initialize(base, size)
|
|
||||||
@base_addr = base
|
|
||||||
@file_size = size
|
|
||||||
end
|
|
||||||
|
|
||||||
def inspect
|
|
||||||
"(Assembler base_addr:0x#{@base_addr.to_s 16} file_size:0x#{@file_size.to_s 16})"
|
|
||||||
end
|
|
||||||
|
|
||||||
# TODO: Sub-labels
|
|
||||||
|
|
||||||
def label(l)
|
|
||||||
return if @first_pass == false
|
|
||||||
raise "error redefinition of label #{l.to_s}" if @labels.member?(l.to_s)
|
|
||||||
@labels[l.to_s] = @bytes.length + @base_addr
|
|
||||||
end
|
|
||||||
|
|
||||||
def method_missing(m, *args, &block)
|
|
||||||
return 0 if @first_pass
|
|
||||||
if m.to_s[0, 2] == "l_" then
|
|
||||||
return @labels[m.to_s[2..]] if @labels.member?(m.to_s[2..])
|
|
||||||
raise "label doesn't exist #{m.to_s}"
|
|
||||||
else
|
|
||||||
super
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def assemble(source)
|
|
||||||
@first_pass = true
|
|
||||||
@labels = {}
|
|
||||||
@bytes = []
|
|
||||||
binding.eval source
|
|
||||||
|
|
||||||
@first_pass = false
|
|
||||||
@bytes = []
|
|
||||||
binding.eval source
|
|
||||||
|
|
||||||
puts "assembled 0x#{@bytes.length.to_s 16} (#{@bytes.length}) bytes"
|
|
||||||
raise "CODE IS GREATER THAN FILESIZE" if @bytes.length > @file_size
|
|
||||||
zero_fill @file_size - 1
|
|
||||||
|
|
||||||
return @bytes
|
|
||||||
end
|
|
||||||
|
|
||||||
def zero_fill(pos)
|
|
||||||
while (@bytes.length <= pos) do
|
|
||||||
@bytes.push(0)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def word(i)
|
|
||||||
@bytes.push((i & 0x000000ff),
|
|
||||||
(i & 0x0000ff00) >> 8,
|
|
||||||
(i & 0x00ff0000) >> 16,
|
|
||||||
(i & 0xff000000) >> 24)
|
|
||||||
end
|
|
||||||
|
|
||||||
def string(s)
|
|
||||||
@bytes.push *s.bytes
|
|
||||||
@bytes.push 0 # null terminate
|
|
||||||
while ((@bytes.length % 4) != 0) do
|
|
||||||
@bytes.push 0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# # # INSTRUCTIONS # # #
|
# # # INSTRUCTIONS # # #
|
||||||
|
@ -165,33 +120,7 @@ class Assembler
|
||||||
word op
|
word op
|
||||||
end
|
end
|
||||||
|
|
||||||
# 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
|
|
||||||
|
|
||||||
# jump register
|
|
||||||
def jr(reg)
|
|
||||||
# oooooo rrrrr ----- ----- ----- oooooo
|
|
||||||
op = 0b000000_00000_00000_00000_00000_001000
|
|
||||||
op |= (reg & 0b11111) << 21
|
|
||||||
word op
|
|
||||||
end
|
|
||||||
|
|
||||||
# # # PSEUDO-INSTRUCTIONS # # #
|
# # # PSEUDO-INSTRUCTIONS # # #
|
||||||
def nop
|
def nop
|
||||||
|
@ -204,27 +133,117 @@ class Assembler
|
||||||
ori dest, val, dest
|
ori dest, val, dest
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def label
|
||||||
|
return $bytes.length + $base_addr
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# this is a terrible idea and im doing it
|
||||||
|
#$labels = {}
|
||||||
|
#def method_missing(m, *args)
|
||||||
|
# puts m.to_s
|
||||||
|
# super
|
||||||
|
#end
|
||||||
|
|
||||||
|
|
||||||
# # # CONSTANTS # # #
|
# # # CONSTANTS # # #
|
||||||
base_addr = 0x80010000 # 0x10000 # 0x80010000
|
$base_addr = 0x80010000 # 0x10000 # 0x80010000
|
||||||
file_size = 0x800 * 3
|
$file_size = 0x800 * 3
|
||||||
|
$gp0 = 0x1F801810
|
||||||
|
$gp1 = 0x1F801814
|
||||||
|
|
||||||
f = File.new "exe-header.asm.rb", "r"
|
# # # EXE HEADER # # #
|
||||||
exe_header = Assembler.new(base_addr, 0x800).assemble f.read
|
string "PS-X EXE"
|
||||||
f.close
|
zero_fill 0x00f
|
||||||
|
word $base_addr # initial pc
|
||||||
|
word 0x00000000 # initial GP/R28
|
||||||
|
word $base_addr # destintation address in RAM
|
||||||
|
word $file_size # file size excluding header (must be N * 0x800)
|
||||||
|
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
|
||||||
|
zero_fill 0x4b # Reserved for A(43h) Function
|
||||||
|
# Ascii marker would go here
|
||||||
|
zero_fill 0x7ff
|
||||||
|
$exe_header = $bytes[0..]
|
||||||
|
$bytes = []
|
||||||
|
|
||||||
f = File.new "main.asm.rb", "r"
|
|
||||||
binary = Assembler.new(base_addr, file_size).assemble f.read
|
|
||||||
f.close
|
|
||||||
|
# # # PROGRAM CODE # # #
|
||||||
|
nop
|
||||||
|
|
||||||
|
# ops should always be in format of
|
||||||
|
# src [args] -> dest
|
||||||
|
|
||||||
|
# THIS IS NEEDED
|
||||||
|
lwi $gp1, t0
|
||||||
|
lwi 0x03_00_00_00, t1 # display enable
|
||||||
|
sw t1, 0, t0
|
||||||
|
|
||||||
|
lwi $gp0, t0
|
||||||
|
|
||||||
|
lwi 0xe1_000000 + 0b0_0_0_1_0_01_00_0_0000, t1
|
||||||
|
sw t1, 0, t0
|
||||||
|
|
||||||
|
# THIS IS NEEDED
|
||||||
|
lwi 0xe4_000000 + (640) + (480 << 10), t1 # Drawing Area bottom right
|
||||||
|
sw t1, 0, t0
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
l_end_loop = label
|
||||||
|
line 0x0010_0010, 0x0030_0030
|
||||||
|
line 0x0030_0030, 0x0060_0000
|
||||||
|
line 0x0060_0000, 0x00f0_0060
|
||||||
|
|
||||||
|
nop ; nop ; nop ; nop
|
||||||
|
nop ; nop ; nop ; nop
|
||||||
|
nop ; nop ; nop ; nop
|
||||||
|
nop ; nop ; nop ; nop
|
||||||
|
|
||||||
|
# l_end_loop = label
|
||||||
|
nop
|
||||||
|
jmp l_end_loop
|
||||||
|
nop
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
string "this is a test lol"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
zero_fill $file_size - 1
|
||||||
|
|
||||||
f = File.new "LOADTHIS.EXE", "wb"
|
f = File.new "LOADTHIS.EXE", "wb"
|
||||||
f.write exe_header.pack("C*")
|
f.write $exe_header.pack("C*")
|
||||||
f.write binary.pack("C*")
|
f.write $bytes.pack("C*")
|
||||||
f.close
|
f.close
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
|
|
||||||
# exe-header.asm.rb
|
|
||||||
|
|
||||||
string "PS-X EXE"
|
|
||||||
zero_fill 0x00f
|
|
||||||
word @base_addr # initial pc
|
|
||||||
word 0x00000000 # initial GP/R28
|
|
||||||
word @base_addr # destintation address in RAM
|
|
||||||
word @file_size # file size excluding header (must be N * 0x800)
|
|
||||||
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
|
|
||||||
zero_fill 0x4b # Reserved for A(43h) Function
|
|
||||||
# Ascii marker would go here
|
|
||||||
zero_fill 0x7ff
|
|
78
main.asm.rb
78
main.asm.rb
|
@ -1,78 +0,0 @@
|
||||||
|
|
||||||
# main.asm.rb
|
|
||||||
|
|
||||||
$gp0 = 0x1F801810
|
|
||||||
$gp1 = 0x1F801814
|
|
||||||
|
|
||||||
jmp l_start
|
|
||||||
nop
|
|
||||||
|
|
||||||
label :hello_world
|
|
||||||
string "ello wrld!\n"
|
|
||||||
|
|
||||||
label :printf
|
|
||||||
addiu r0, 0xa0, at # address of bios func
|
|
||||||
jr at
|
|
||||||
addiu r0, 0x3f, t1 # printf number
|
|
||||||
|
|
||||||
label :draw_line
|
|
||||||
# todo: draw line function, take args in a0 - a3
|
|
||||||
# tood: implement shift left so we can use that
|
|
||||||
lwi $gp0, t0
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
label :start
|
|
||||||
nop ; nop ; nop ; nop
|
|
||||||
|
|
||||||
# THIS IS NEEDED
|
|
||||||
lwi $gp1, t0
|
|
||||||
lwi 0x03_00_00_00, t1 # display enable
|
|
||||||
sw t1, 0, t0
|
|
||||||
|
|
||||||
lwi $gp0, t0
|
|
||||||
|
|
||||||
lwi 0xe1_000000 + 0b0_0_0_1_0_01_00_0_0000, t1
|
|
||||||
sw t1, 0, t0
|
|
||||||
|
|
||||||
# THIS IS NEEDED
|
|
||||||
lwi 0xe4_000000 + (640) + (480 << 10), t1 # Drawing Area bottom right
|
|
||||||
sw t1, 0, t0
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
line 0x0010_0010, 0x0030_0030
|
|
||||||
line 0x0030_0030, 0x0060_0000
|
|
||||||
line 0x0060_000a, 0x00f0_0060
|
|
||||||
|
|
||||||
lwi l_hello_world, a0
|
|
||||||
jal l_printf
|
|
||||||
addiu sp, -16, sp # delay slot
|
|
||||||
addiu sp, 16, sp
|
|
||||||
|
|
||||||
label :end_loop
|
|
||||||
lwi l_end_loop, t9
|
|
||||||
jr t9
|
|
||||||
nop
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue