polish docs
and a bit of code style
This commit is contained in:
@ -2,25 +2,26 @@ require_relative "attributed"
|
||||
|
||||
module Arm
|
||||
|
||||
# A Machines main responsibility in the named_listwork is to instantiate Instructions
|
||||
# A Machines main responsibility is to instantiate Instructions.
|
||||
# Arm instructions live in their own directory and are derived from their Risc
|
||||
# couterparts to inherit list functionality
|
||||
|
||||
# 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) )
|
||||
# Shortcuts are created to easily instantiate Instruction objects.
|
||||
# Example: ArmMachine.pop -> StackInstruction.new( {:opcode => :pop}.merge(options) )
|
||||
#
|
||||
# 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
|
||||
# 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)
|
||||
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
|
||||
# here we create the shortcuts for the "standard" arm instructions that we use.
|
||||
# (note that it is possible to add instructions by adding new classes and optionally
|
||||
# new factory functions to this class)
|
||||
def self.init
|
||||
[:push, :pop].each do |inst|
|
||||
define_instruction_one(inst , StackInstruction)
|
||||
@ -40,7 +41,8 @@ module Arm
|
||||
[:b, :call , :swi].each do |inst|
|
||||
define_instruction_one(inst , CallInstruction)
|
||||
end
|
||||
# create all possible brach instructions, but the CallInstruction demangles the
|
||||
|
||||
# create all possible branch 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)
|
||||
@ -64,13 +66,10 @@ module Arm
|
||||
|
||||
#defining the instruction (opcode, symbol) as an given class.
|
||||
# the class is a Risc::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 Risc::MoveInstruction
|
||||
# for an Arm machine, a class Arm::MoveInstruction < Risc::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
|
||||
# Example, a mov() opcode instantiates a Arm::MoveInstruction < Risc::MoveInstruction ,
|
||||
#
|
||||
def self.define_instruction_one(inst , clazz , defaults = {} )
|
||||
clazz = class_for(clazz)
|
||||
def_method(inst) do |first , options = nil|
|
||||
|
@ -1,7 +1,7 @@
|
||||
module Arm
|
||||
class MachineCode
|
||||
|
||||
def function_call into , call
|
||||
def function_call( into , call )
|
||||
raise "Not CallSite #{call.inspect}" unless call.is_a? Risc::CallSite
|
||||
raise "Not linked #{call.inspect}" unless call.function
|
||||
into.add_code call( call.function )
|
||||
@ -9,28 +9,28 @@ module Arm
|
||||
call.function.return_type
|
||||
end
|
||||
|
||||
def main_start context
|
||||
def main_start( context )
|
||||
entry = Risc::Block.new("main_entry",nil,nil)
|
||||
entry.add_code mov( :fp , 0 )
|
||||
entry.add_code call( context.function )
|
||||
entry
|
||||
end
|
||||
def main_exit context
|
||||
def main_exit( context )
|
||||
exit = Risc::Block.new("main_exit",nil,nil)
|
||||
syscall(exit , 1)
|
||||
exit
|
||||
end
|
||||
def function_entry block, f_name
|
||||
def function_entry( block, f_name )
|
||||
block.add_code push( [:lr] )
|
||||
block
|
||||
end
|
||||
def function_exit entry , f_name
|
||||
def function_exit( entry , f_name )
|
||||
entry.add_code pop( [:pc] )
|
||||
entry
|
||||
end
|
||||
|
||||
# assumes string in standard receiver reg (r2) and moves them down for the syscall
|
||||
def write_stdout function #, string
|
||||
def write_stdout( function ) #, string
|
||||
# TODO save and restore r0
|
||||
function.mov( :r0 , 1 ) # 1 == stdout
|
||||
function.mov( :r1 , receiver_register )
|
||||
@ -39,7 +39,7 @@ module Arm
|
||||
end
|
||||
|
||||
# stop, do not return
|
||||
def exit function #, string
|
||||
def exit( function )#, string
|
||||
syscall( function.insertion_point , 1 ) # 1 == exit
|
||||
end
|
||||
|
||||
@ -47,7 +47,7 @@ module Arm
|
||||
# the number (a Risc::integer) is (itself) divided by 10, ie overwritten by the result
|
||||
# and the remainder is overwritten (ie an out argument)
|
||||
# not really a function, more a macro,
|
||||
def div10 function, number , remainder
|
||||
def div10( function, number , remainder )
|
||||
# Note about division: devision is MUCH more expensive than one would have thought
|
||||
# And coding it is a bit of a mind leap: it's all about finding a a result that gets the
|
||||
# remainder smaller than an int. i'll post some links sometime. This is from the arm manual
|
||||
@ -66,7 +66,7 @@ module Arm
|
||||
end
|
||||
end
|
||||
|
||||
def syscall block , num
|
||||
def syscall( block , num )
|
||||
# This is very arm specific, syscall number is passed in r7,
|
||||
# other arguments like a c call ie 0 and up
|
||||
sys = Risc::Integer.new( Risc::RiscValue.new(SYSCALL_REG) )
|
||||
|
@ -5,20 +5,20 @@ module Arm
|
||||
# for each instruction we call the translator with translate_XXX
|
||||
# with XXX being the class name.
|
||||
# the result is replaced in the stream
|
||||
def translate instruction
|
||||
def translate( instruction )
|
||||
class_name = instruction.class.name.split("::").last
|
||||
self.send( "translate_#{class_name}".to_sym , instruction)
|
||||
end
|
||||
|
||||
# don't replace labels
|
||||
def translate_Label code
|
||||
def translate_Label( code )
|
||||
nil
|
||||
end
|
||||
|
||||
# arm indexes are
|
||||
# in bytes, so *4
|
||||
# if an instruction is passed in we get the index with index function
|
||||
def arm_index index
|
||||
def arm_index( index )
|
||||
index = index.index if index.is_a?(Risc::Instruction)
|
||||
raise "index error 0" if index == 0
|
||||
index * 4
|
||||
|
Reference in New Issue
Block a user