homing in on line length 100

This commit is contained in:
Torsten Ruger
2015-05-30 12:20:39 +03:00
parent 33d464f032
commit e651b57d08
29 changed files with 159 additions and 108 deletions

View File

@ -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 = {} )

View File

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

View File

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

View File

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

View File

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

View File

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