rubyx/lib/arm/arm_machine.rb

123 lines
5.1 KiB
Ruby
Raw Normal View History

require_relative "instruction"
module Arm
# A Machines main responsibility in the framework is to instantiate Instructions
# Value functions are mapped to machines by concatenating the values class name + the methd name
# Example: IntegerValue.plus( value ) -> Machine.signed_plus (value )
# Also, shortcuts are created to easily instantiate Instruction objects.
# Example: pop -> StackInstruction.new( {:opcode => :pop}.merge(options) )
2015-05-30 11:20:39 +02:00
# Instructions work with options, so you can pass anything in, and the only thing the functions
# does is save you typing the clazz.new. It passes the function name as the :opcode
class ArmMachine
# conditions specify all the possibilities for branches. Branches are b + condition
# Example: beq means brach if equal.
# :al means always, so bal is an unconditional branch (but b() also works)
2015-05-30 11:20:39 +02:00
CONDITIONS = [:al ,:eq ,:ne ,:lt ,:le ,:ge,:gt ,:cs ,:mi ,:hi ,:cc ,:pl,:ls ,:vc ,:vs]
# here we create the shortcuts for the "standard" instructions, see above
# Derived machines may use own instructions and define functions for them if so desired
def self.init
[:push, :pop].each do |inst|
define_instruction_one(inst , StackInstruction)
end
[:adc, :add, :and, :bic, :eor, :orr, :rsb, :rsc, :sbc, :sub].each do |inst|
define_instruction_three(inst , LogicInstruction)
end
[:mov, :mvn].each do |inst|
define_instruction_two(inst , MoveInstruction)
end
[:cmn, :cmp, :teq, :tst].each do |inst|
define_instruction_two(inst , CompareInstruction)
end
[:strb, :str , :ldrb, :ldr].each do |inst|
define_instruction_three(inst , MemoryInstruction)
end
[:b, :call , :swi].each do |inst|
define_instruction_one(inst , CallInstruction)
end
# create all possible brach instructions, but the CallInstruction demangles the
# code, and has opcode set to :b and :condition_code set to the condition
CONDITIONS.each do |suffix|
define_instruction_one("b#{suffix}".to_sym , CallInstruction)
define_instruction_one("call#{suffix}".to_sym , CallInstruction)
end
end
def self.create_method(name, &block)
self.class.send(:define_method, name , &block)
end
def self.class_for clazz
my_module = self.class.name.split("::").first
clazz_name = clazz.name.split("::").last
if(my_module != Register )
module_class = eval("#{my_module}::#{clazz_name}") rescue nil
clazz = module_class if module_class
end
clazz
end
#defining the instruction (opcode, symbol) as an given class.
# the class is a Register::Instruction derived base class and to create machine specific function
# an actual machine must create derived classes (from this base class)
# These instruction classes must follow a naming pattern and take a hash in the contructor
# Example, a mov() opcode instantiates a Register::MoveInstruction
2015-05-30 11:20:39 +02:00
# for an Arm machine, a class Arm::MoveInstruction < Register::MoveInstruction exists, and it
# will be used to define the mov on an arm machine.
# This methods picks up that derived class and calls a define_instruction methods that can
# be overriden in subclasses
def self.define_instruction_one(inst , clazz , defaults = {} )
clazz = class_for(clazz)
create_method(inst) do |first , options = nil|
options = {} if options == nil
options.merge defaults
options[:opcode] = inst
first = Register::RegisterReference.convert(first)
clazz.new(first , options)
end
end
# same for two args (left right, from to etc)
def self.define_instruction_two(inst , clazz , defaults = {} )
clazz = self.class_for(clazz)
create_method(inst) do |left ,right , options = nil|
options = {} if options == nil
options.merge defaults
left = Register::RegisterReference.convert(left)
right = Register::RegisterReference.convert(right)
options[:opcode] = inst
clazz.new(left , right ,options)
end
end
# same for three args (result = left right,)
def self.define_instruction_three(inst , clazz , defaults = {} )
clazz = self.class_for(clazz)
create_method(inst) do |result , left ,right = nil , options = nil|
options = {} if options == nil
options.merge defaults
options[:opcode] = inst
result = Register::RegisterReference.convert(result)
left = Register::RegisterReference.convert(left)
right = Register::RegisterReference.convert(right)
clazz.new(result, left , right ,options)
end
end
end
end
Arm::ArmMachine.init
require_relative "passes/call_implementation"
require_relative "passes/branch_implementation"
require_relative "passes/syscall_implementation"
require_relative "passes/save_implementation"
require_relative "passes/transfer_implementation"
require_relative "passes/get_implementation"
require_relative "passes/set_implementation"
require_relative "passes/return_implementation"
require_relative "passes/constant_implementation"