124 lines
3.0 KiB
Ruby
124 lines
3.0 KiB
Ruby
require 'asm/instruction'
|
|
require 'asm/nodes'
|
|
require 'stream_reader'
|
|
require 'stringio'
|
|
require "asm/string_literal"
|
|
|
|
module Asm
|
|
|
|
class ArmAssembler
|
|
|
|
%w(r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12
|
|
r13 r14 r15 a1 a2 a3 a4 v1 v2 v3 v4 v5 v6
|
|
rfp sl fp ip sp lr pc
|
|
).each { |reg|
|
|
define_method(reg) {
|
|
Asm::Register.new(reg)
|
|
}
|
|
}
|
|
|
|
def initialize
|
|
@values = []
|
|
@position = 0 # marks not set
|
|
@labels = []
|
|
@string_table = {}
|
|
end
|
|
attr_reader :values , :position
|
|
|
|
def instruction(clazz,name, *args)
|
|
opcode = name.to_s
|
|
arg_nodes = []
|
|
|
|
args.each { |arg|
|
|
if (arg.is_a?(Asm::Register))
|
|
arg_nodes << arg
|
|
elsif (arg.is_a?(Integer))
|
|
arg_nodes << Asm::NumLiteral.new(arg)
|
|
elsif (arg.is_a?(String))
|
|
arg_nodes << add_string(arg)
|
|
elsif (arg.is_a?(Asm::Label))
|
|
arg_nodes << arg
|
|
else
|
|
raise 'Invalid argument `%s\' for instruction' % arg.inspect
|
|
end
|
|
}
|
|
|
|
add_value clazz.new(opcode , arg_nodes)
|
|
end
|
|
|
|
|
|
def self.define_instruction(inst , clazz )
|
|
define_method(inst) do |*args|
|
|
instruction clazz , inst.to_sym, *args
|
|
end
|
|
define_method(inst+'s') do |*args|
|
|
instruction clazz , (inst+'s').to_sym, *args
|
|
end
|
|
%w(al eq ne cs mi hi cc pl ls vc lt le ge gt vs).each do |cond_suffix|
|
|
define_method(inst+cond_suffix) do |*args|
|
|
instruction clazz , (inst+cond_suffix).to_sym, *args
|
|
end
|
|
define_method(inst+'s'+cond_suffix) do |*args|
|
|
instruction clazz , (inst+'s'+cond_suffix).to_sym, *args
|
|
end
|
|
end
|
|
end
|
|
|
|
["push", "pop"].each do |inst|
|
|
define_instruction(inst , StackInstruction)
|
|
end
|
|
|
|
%w(adc add and bic eor orr rsb rsc sbc sub mov mvn cmn cmp teq tst b bl bx
|
|
swi str strb ldr ldrb ).each do |inst|
|
|
define_instruction(inst , Instruction)
|
|
end
|
|
|
|
def assemble_to_string
|
|
#put the strings at the end of the assembled code.
|
|
# adding them will fix their position and make them assemble after
|
|
@string_table.values.each do |data|
|
|
add_value data
|
|
end
|
|
io = StringIO.new
|
|
assemble(io)
|
|
io.string
|
|
end
|
|
|
|
def add_string str
|
|
value = @string_table[str]
|
|
return value if value
|
|
data = Asm::StringLiteral.new(str)
|
|
@string_table[str] = data
|
|
end
|
|
|
|
def strings
|
|
@string_table.values
|
|
end
|
|
|
|
def add_value(val)
|
|
val.at(@position)
|
|
length = val.length
|
|
@position += length
|
|
@values << val
|
|
end
|
|
|
|
def label name
|
|
label = Label.new(name , self)
|
|
@labels << label
|
|
label
|
|
end
|
|
|
|
def label! name
|
|
label(name).set!
|
|
end
|
|
|
|
def assemble(io)
|
|
@values.each do |obj|
|
|
obj.assemble io, self
|
|
end
|
|
end
|
|
|
|
end
|
|
end
|
|
|