diff --git a/lib/arm/move_instruction.rb b/lib/arm/move_instruction.rb index 023f407c..0629e3be 100644 --- a/lib/arm/move_instruction.rb +++ b/lib/arm/move_instruction.rb @@ -13,37 +13,18 @@ module Arm @immediate = 0 @rn = :r0 # register zero = zero bit pattern @from = Virtual::IntegerConstant.new( @from ) if( @from.is_a? Fixnum ) + @extra = nil end # arm intrucions 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 instrucitons. we handle this here, just this instruciton looks - # longer + # 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 def 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 - return 4 - is_simple ? 4 : 8 - end - - # a constant (the one we want to move) can either be < 256 or be rotated in a funny arm way - # if neither works (not simple !) we need two instructions to make the move - def is_simple - right = @from - if right.is_a?(Virtual::ObjectConstant) - r_pos = right.position - # do pc relative addressing with the difference to the instuction - # 8 is for the funny pipeline adjustment (ie pc pointing to fetch and not execute) - right = Virtual::IntegerConstant.new( r_pos - self.position - 8 ) - end - if (right.is_a?(Virtual::IntegerConstant)) - if (right.fits_u8?) - return true - elsif (calculate_u8_with_rr(right)) - return true - else - return false - end - end - return true + @extra ? 8 : 4 end def assemble(io) @@ -72,10 +53,15 @@ module Arm immediate = 1 raise "hmm" else - operand = right.integer / 256 - immediate = 1 - - raise "cannot fit numeric literal argument in operand #{right.inspect}" + # and so it continues: when we notice that the const doesn't fit, first time we raise an + # error,but set the extra flag, to say the instruction is now 8 bytes + # then on subsequent assemlies we can assemble + unless @extra + @extra = 1 + raise ::Register::LinkException.new("cannot fit numeric literal argument in operand #{right.inspect}") + end + # now we can do the actual breaking of instruction + raise "at leat we got here" end elsif (right.is_a?(Symbol) or right.is_a?(Virtual::Integer)) operand = reg_code(right) #integer means the register the integer is in (otherwise constant) diff --git a/lib/register/assembler.rb b/lib/register/assembler.rb index b5d0ec0b..c9a1210e 100644 --- a/lib/register/assembler.rb +++ b/lib/register/assembler.rb @@ -1,5 +1,6 @@ module Register - + class LinkException < Exception + end # Assmble the object space into a binary. # Link first to get positions, then assemble # link and assemble functions for each class are close to each other, so to get them the same. @@ -36,20 +37,25 @@ module Register end def assemble - link - @stream = StringIO.new - mid , main = @objects.find{|k,objekt| objekt.is_a?(Virtual::CompiledMethod) and (objekt.name == :__init__ )} - puts "function found #{main.name}" - initial_jump = RegisterMachine.instance.b( main ) - initial_jump.set_position( 0) - initial_jump.assemble( @stream ) - @objects.each_value do |objekt| - next unless objekt.is_a? Virtual::CompiledMethod - assemble_object( objekt ) - end - @objects.each_value do | objekt| - next if objekt.is_a? Virtual::CompiledMethod - assemble_object( objekt ) + begin + link + @stream = StringIO.new + mid , main = @objects.find{|k,objekt| objekt.is_a?(Virtual::CompiledMethod) and (objekt.name == :__init__ )} + puts "function found #{main.name}" + initial_jump = RegisterMachine.instance.b( main ) + initial_jump.set_position( 0) + initial_jump.assemble( @stream ) + @objects.each_value do |objekt| + next unless objekt.is_a? Virtual::CompiledMethod + assemble_object( objekt ) + end + @objects.each_value do | objekt| + next if objekt.is_a? Virtual::CompiledMethod + assemble_object( objekt ) + end + rescue LinkException => e + puts "coought #{e}" + retry end puts "Assembled #{@stream.length.to_s(16)}" return @stream.string diff --git a/lib/register/instruction.rb b/lib/register/instruction.rb index fe3912db..d6374b01 100644 --- a/lib/register/instruction.rb +++ b/lib/register/instruction.rb @@ -1,4 +1,3 @@ -require_relative "code" module Register # The register machine model is close to current hardware and has following instruction classes diff --git a/lib/virtual/constants.rb b/lib/virtual/constants.rb index 892f4f76..ffdc9637 100644 --- a/lib/virtual/constants.rb +++ b/lib/virtual/constants.rb @@ -56,6 +56,10 @@ module Virtual def mem_length padded(1 + string.length) end + def set_position pos + puts "STRING #{pos} #{string}" + super + end def position return @position if @position return @string.position if @string.position diff --git a/lib/virtual/object.rb b/lib/virtual/object.rb index 2fe963a0..253d5a79 100644 --- a/lib/virtual/object.rb +++ b/lib/virtual/object.rb @@ -26,7 +26,10 @@ module Virtual @position end def set_position pos - raise "position set again #{pos}!=#{@position} for #{self}" if @position != nil and (@position != pos) + # resetting of position used to be error, but since relink and dynamic instruction size it is ok. in measures + if @position != nil and ((@position - pos).abs > 15) + raise "position set again #{pos}!=#{@position} for #{self}" + end @position = pos end def inspect