homing in on line length 100
This commit is contained in:
@ -9,15 +9,15 @@ module Arm
|
||||
|
||||
# Also, shortcuts are created to easily instantiate Instruction objects.
|
||||
# Example: 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
|
||||
# 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)
|
||||
CONDITIONS = [ :al , :eq , :ne , :lt , :le, :ge, :gt , :cs , :mi , :hi , :cc , :pl, :ls , :vc , :vs ]
|
||||
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
|
||||
@ -67,8 +67,8 @@ module Arm
|
||||
# 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
|
||||
# for an Arm machine, a class Arm::MoveInstruction < Register::MoveInstruction exists, and it will
|
||||
# be used to define the mov on an arm machine.
|
||||
# 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 = {} )
|
||||
|
@ -28,7 +28,8 @@ module Arm
|
||||
|
||||
#codition codes can be applied to many instructions and thus save branches
|
||||
# :al => always , :eq => equal and so on
|
||||
# eq mov if equal :moveq r1 r2 (also exists as function) will only execute if the last operation was 0
|
||||
# eq mov if equal :moveq r1 r2 (also exists as function) will only execute
|
||||
# if the last operation was 0
|
||||
COND_CODES = {
|
||||
:al => 0b1110, :eq => 0b0000,
|
||||
:ne => 0b0001, :cs => 0b0010,
|
||||
@ -39,7 +40,8 @@ module Arm
|
||||
:ge => 0b1010, :gt => 0b1100,
|
||||
:vs => 0b0110
|
||||
}
|
||||
#return the bit pattern for the @attributes[:condition_code] variable, which signals the conditional code
|
||||
# return the bit pattern for the @attributes[:condition_code] variable,
|
||||
# which signals the conditional code
|
||||
def cond_bit_code
|
||||
COND_CODES[@attributes[:condition_code]] or throw "no code found for #{@attributes[:condition_code]}"
|
||||
end
|
||||
@ -96,7 +98,8 @@ module Arm
|
||||
op = 0
|
||||
#codes that one can shift, first two probably most common.
|
||||
# l (in lsr) means logical, ie unsigned, a (in asr) is arithmetic, ie signed
|
||||
{'lsl' => 0b000, 'lsr' => 0b010, 'asr' => 0b100, 'ror' => 0b110, 'rrx' => 0b110}.each do |short, bin|
|
||||
shift_codes = {'lsl' => 0b000, 'lsr' => 0b010, 'asr' => 0b100, 'ror' => 0b110, 'rrx' => 0b110}
|
||||
shift_codes.each do |short, bin|
|
||||
long = "shift_#{short}".to_sym
|
||||
if shif = @attributes[long]
|
||||
# TODO delete this code, AFTER you understand it
|
||||
|
@ -36,8 +36,10 @@ module Arm
|
||||
if arg.is_a?(Virtual::Block) or arg.is_a?(Parfait::Method)
|
||||
#relative addressing for jumps/calls
|
||||
diff = arg.position - self.position
|
||||
# but because of the arm "theoretical" 3- stage pipeline, we have to subtract 2 words (fetch/decode)
|
||||
# But, for methods, this happens to be the size of the object header, so there it balances out, but not blocks
|
||||
# but because of the arm "theoretical" 3- stage pipeline,
|
||||
# we have to subtract 2 words (fetch/decode)
|
||||
# But, for methods, this happens to be the size of the object header,
|
||||
# so there it balances out, but not blocks
|
||||
diff -= 8 if arg.is_a?(Virtual::Block)
|
||||
arg = diff
|
||||
end
|
||||
|
@ -19,12 +19,12 @@ module Arm
|
||||
attr_accessor :to , :from
|
||||
|
||||
# arm intructions are pretty sensible, and always 4 bytes (thumb not supported)
|
||||
# but not all constants fit into the part of the instruction that is left after the instruction code,
|
||||
# so large moves have to be split into two instructions.
|
||||
# but not all constants fit into the part of the instruction that is left after the instruction
|
||||
# code, so large moves have to be split into two instructions.
|
||||
# we handle this "transparently", just this instruction looks longer
|
||||
# alas, full transparency is not achieved as we only know when to use 2 instruction once we know where the
|
||||
# other object is, and that position is only set after code positions have been determined (in link) and so
|
||||
# see below in assemble
|
||||
# alas, full transparency is not achieved as we only know when to use 2 instruction once we
|
||||
# know where the other object is, and that position is only set after code positions have been
|
||||
# determined (in link) and so see below in assemble
|
||||
def mem_length
|
||||
@extra ? 8 : 4
|
||||
end
|
||||
@ -52,13 +52,14 @@ module Arm
|
||||
operand = op_with_rot
|
||||
immediate = 1
|
||||
else
|
||||
# unfortunately i was wrong in thinking the pi is armv7. The good news is the code below implements
|
||||
# the movw instruction (armv7 for moving a word) and works
|
||||
# unfortunately i was wrong in thinking the pi is armv7. The good news is the code
|
||||
# below implements the movw instruction (armv7 for moving a word) and works
|
||||
#armv7 raise "Too big #{right} " if (right >> 16) > 0
|
||||
#armv7 operand = (right & 0xFFF)
|
||||
#armv7 immediate = 1
|
||||
#armv7 rn = (right >> 12)
|
||||
# a little STRANGE, that the armv7 movw (move a 2 byte word) is an old test opcode, but there it is
|
||||
# a little STRANGE, that the armv7 movw (move a 2 byte word) is an old test opcode,
|
||||
# but there it is
|
||||
#armv7 @attributes[:opcode] = :tst
|
||||
raise "No negatives implemented #{right} " if right < 0
|
||||
# and so it continues: when we notice that the const doesn't fit, first time we raise an
|
||||
@ -74,7 +75,8 @@ module Arm
|
||||
raise "no fit for #{right}" unless operand
|
||||
immediate = 1
|
||||
@extra = ArmMachine.add( to , to , (right & 0xFF) )
|
||||
#TODO: this is still a hack, as it does not encode all possible values. The way it _should_ be done
|
||||
#TODO: this is still a hack, as it does not encode all possible values.
|
||||
# The way it _should_ be done
|
||||
# is to check that the first part is doabe with u8_with_rr AND leaves a u8 remainder
|
||||
end
|
||||
elsif (right.is_a?(Symbol) or right.is_a?(::Register::RegisterReference))
|
||||
|
@ -43,16 +43,16 @@ module Arm
|
||||
syscall( function.insertion_point , 1 ) # 1 == exit
|
||||
end
|
||||
|
||||
|
||||
|
||||
# the number (a Virtual::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,
|
||||
# not really a function, more a macro,
|
||||
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
|
||||
# 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
|
||||
tmp = function.new_local
|
||||
function.instance_eval do
|
||||
function.instance_eval do
|
||||
sub( remainder , number , 10 )
|
||||
sub( number , number , number , shift_lsr: 2)
|
||||
add( number , number , number , shift_lsr: 4)
|
||||
@ -67,7 +67,8 @@ module Arm
|
||||
end
|
||||
|
||||
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
|
||||
# This is very arm specific, syscall number is passed in r7,
|
||||
# other arguments like a c call ie 0 and up
|
||||
sys = Virtual::Integer.new( Virtual::RegisterReference.new(SYSCALL_REG) )
|
||||
ret = Virtual::Integer.new( Virtual::RegisterReference.new(RETURN_REG) )
|
||||
block.add_code mov( sys , num )
|
||||
@ -78,4 +79,3 @@ module Arm
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1,9 +1,10 @@
|
||||
module Arm
|
||||
|
||||
# Arm stores the return address in a register (not on the stack)
|
||||
# The register is called link , or lr for short . Maybe because it provides the "link" back to the caller (?)
|
||||
# The register is called link , or lr for short .
|
||||
# Maybe because it provides the "link" back to the caller (?)
|
||||
|
||||
# the vm defines a register for the location, so we store it there.
|
||||
# the vm defines a register for the location, so we store it there.
|
||||
|
||||
class SaveImplementation
|
||||
def run block
|
||||
|
Reference in New Issue
Block a user