polish docs

and a bit of code style
This commit is contained in:
Torsten Ruger
2018-03-11 16:11:15 +05:30
parent d6a2ea4cfc
commit f7aac1d1a4
14 changed files with 65 additions and 72 deletions

View File

@ -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|

View File

@ -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) )

View File

@ -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