diff --git a/lib/parfait/binary_code.rb b/lib/parfait/binary_code.rb index 15b88148..3c865d81 100644 --- a/lib/parfait/binary_code.rb +++ b/lib/parfait/binary_code.rb @@ -47,6 +47,12 @@ module Parfait @next end + def last_code + last = self + last = last.next while(last.next) + last + end + def each_block( &block ) block.call( self ) @next.each_block( &block ) if @next diff --git a/lib/risc/position/code_listener.rb b/lib/risc/position/code_listener.rb index 60c6381b..bf5d1f79 100644 --- a/lib/risc/position/code_listener.rb +++ b/lib/risc/position/code_listener.rb @@ -10,10 +10,10 @@ module Risc class CodeListener def position_inserted(position) - Position.log.debug "extending one in #{self}" + Position.log.debug "extending one at #{position}" pos = CodeListener.init( position.object.next ) - pos.set( position + position.object.padded_length) return unless position.valid? + pos.set( position + position.object.padded_length) set_jump_for(position) end diff --git a/lib/risc/position/instruction_listener.rb b/lib/risc/position/instruction_listener.rb index cf7d0e73..ed4d5c94 100644 --- a/lib/risc/position/instruction_listener.rb +++ b/lib/risc/position/instruction_listener.rb @@ -2,7 +2,7 @@ module Risc # Instructions are also a linked list, but their position is not really # the position of the object. # Rather it is the position of the assembled code in the binary. - # (Luckily arm is sane, so this is realtively simple) + # (Luckily arm is sane, so this is relatively simple) # # Really we only need to calculate Positions at a jump, so between the # Jump and the label it jumps too. The other instructions are "just" fill. @@ -13,85 +13,62 @@ module Risc # the same BinaryCode, or else move it and the code along # class InstructionListener - attr_reader :instruction , :binary - def initialize(instruction , binary) - @instruction = instruction + attr_reader :binary + + def initialize(binary) @binary = binary + @index = -1 end - def position_changing(position , to) - - end - - # if the position of the instruction before us changes, we need to - # adjust the position of this instruction accordingly + # if the position of the instruction changes, we need to adjust the position + # of the next instruction accordingly (if present) # Taking into account that BinaryCodes only take 13 instructions, # meaning that chain may have to be extended - def position_changed(position) - next_pos = position.at + position.object.byte_length - fix_binary_for(next_pos) - my_pos = Position.get(@instruction) - diff = next_pos - Position.get(@binary).at - Position.log.debug "Diff: 0x#{diff.to_s(16)} , next 0x#{next_pos.to_s(16)} , binary #{Position.get(@binary)}" - raise "Invalid position #{diff.to_s(16)} , next #{next_pos.to_s(16)} #{position}" if diff < 8 - if( (diff % (@binary.padded_length - @instruction.byte_length)) == 0 ) - @binary = @binary.ensure_next - next_pos = Position.get(@binary).at + Parfait::BinaryCode.byte_offset - #Insert/Position the jump (its missing) - Position.log.debug "Jump to: #{next_pos.to_s(16)}" + def position_changing(position , to) + update_index(to) + instruction = position.object + return unless instruction.next + if @index == (Parfait::BinaryCode.data_length - 1 ) + nekst_pos_diff = @binary.padded_length + else + nekst_pos_diff = @index * 4 + instruction.byte_length end - my_pos.set(next_pos) + Position.log.debug "Nekst + #{nekst_pos_diff + Parfait::BinaryCode.byte_offset}" + nekst = Position.get(position.object.next) + nekst.set(Position.get(@binary) + nekst_pos_diff + Parfait::BinaryCode.byte_offset) + end + + def update_index(to) + index = (to - Position.get(@binary).at) / 4 + raise "Invalid negative index #{@index} , #{Position.get(@binary)}" if index < Parfait::BinaryCode.type_length + while(index >= (Parfait::BinaryCode.memory_size - 1) ) + @binary = @binary.ensure_next + index = (to - Position.get(@binary).at) / 4 + end + @index = index - 2 + raise "Invalid negative index #{@index} , #{Position.get(@binary)}" if index < 0 + end + + def position_changed(position) + #code moved to position_changing end # When this is called, only the actual insert has happened (keeping the # position logic out of the instruction assembly). # - # This event happens at the listener that was dependent on the position - # before the insert, ie: + # This event happens at the listener of the positionwhere the insert happens, ie: # position : the arg is the first instruction in the chain where insert happened # position.object.next : is the newly inserted instruction we need to setup - # @instruction : previously dependent on position, now on inserted's position # # So we need to : - # - move the listener self to listen to the inserted instruction # - add a listener for the new instruction (to listen to the arg) - # - set the new position (moving the chain along) + # - trigger change for this (fake) to set position of inserted def position_inserted(position) inserted = position.object.next - raise "uups" unless inserted ## TODO: remove - position.remove_position_listener(self) new_pos = Position.new(inserted , -1) - new_pos.position_listener(self) + new_pos.position_listener(InstructionListener.new(@binary)) - listen = InstructionListener.new(inserted , @binary) - position.position_listener(listen) - - position.trigger_changed - end - - # check that the binary we use is the one where the current position falls - # if not move up and register/unregister (soon) - # - # Because the position for the @instruction may not be set yet, - # we use the one that it will be set to (the arg) - def fix_binary_for(new_pos) - raise "Binary has no position (-1)" if Position.get(@binary).at == -1 - count = 0 - bin_pos = Position.get(@binary) - while( !pos_in_binary(new_pos)) - @binary = @binary.ensure_next - count += 1 - raise "Positions too far out (#{count}) #{Position.get(@instruction)}:#{bin_pos}" if count > 5 - end - end - - # check if the given position is inside the @binary - # ie not below start or above end - def pos_in_binary(new_pos) - bin = Position.get(@binary) - return false if bin > new_pos - return false if new_pos > (bin + @binary.padded_length) - return true + position.trigger_changing(position.at) end # initialize the dependency graph for instructions @@ -110,12 +87,8 @@ module Risc while(instruction) position = Position.new(instruction , -1) first = position unless first - nekst = instruction.next - if nekst - listener = InstructionListener.new( nekst , code ) - position.position_listener(listener) - end - instruction = nekst + position.position_listener(InstructionListener.new( code )) + instruction = instruction.next end first end diff --git a/test/risc/position/test_instruction_listener.rb b/test/risc/position/test_instruction_listener.rb index 4e1d1c68..45d57f1e 100644 --- a/test/risc/position/test_instruction_listener.rb +++ b/test/risc/position/test_instruction_listener.rb @@ -24,7 +24,7 @@ module Risc end def test_listener_method @position.set(8) - listener = InstructionListener.new( @instruction , @binary ) + listener = InstructionListener.new( @binary ) listener.position_changed(@position) end def test_ins_propagates @@ -40,8 +40,8 @@ module Risc def test_label_has_no_length label = Label.new("Hi","Ho" , FakeAddress.new(5) , @instruction) InstructionListener.init(label , @binary) - Position.get(label).set(10) - assert_equal 10 , Position.get(@instruction).at + Position.get(label).set(12) + assert_equal 12 , Position.get(@instruction).at end def test_label_at_branch label = Label.new("Hi","Ho" , FakeAddress.new(5) , @instruction)