reimplement instruction listeners with indexes

easier to understand, as indexes map to Binarycode indexes, and can thus later be used to assemble directoy into the  code
Almost no change in tests (now only multiples of 4 addresses allowed)
This commit is contained in:
Torsten Ruger 2018-06-09 17:41:39 +03:00
parent cf94227b2c
commit ec1d38f5a6
4 changed files with 50 additions and 71 deletions

View File

@ -47,6 +47,12 @@ module Parfait
@next @next
end end
def last_code
last = self
last = last.next while(last.next)
last
end
def each_block( &block ) def each_block( &block )
block.call( self ) block.call( self )
@next.each_block( &block ) if @next @next.each_block( &block ) if @next

View File

@ -10,10 +10,10 @@ module Risc
class CodeListener class CodeListener
def position_inserted(position) 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 = CodeListener.init( position.object.next )
pos.set( position + position.object.padded_length)
return unless position.valid? return unless position.valid?
pos.set( position + position.object.padded_length)
set_jump_for(position) set_jump_for(position)
end end

View File

@ -2,7 +2,7 @@ module Risc
# Instructions are also a linked list, but their position is not really # Instructions are also a linked list, but their position is not really
# the position of the object. # the position of the object.
# Rather it is the position of the assembled code in the binary. # 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 # 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. # 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 # the same BinaryCode, or else move it and the code along
# #
class InstructionListener class InstructionListener
attr_reader :instruction , :binary attr_reader :binary
def initialize(instruction , binary)
@instruction = instruction def initialize(binary)
@binary = binary @binary = binary
@index = -1
end end
def position_changing(position , to) # if the position of the instruction changes, we need to adjust the position
# of the next instruction accordingly (if present)
end
# if the position of the instruction before us changes, we need to
# adjust the position of this instruction accordingly
# Taking into account that BinaryCodes only take 13 instructions, # Taking into account that BinaryCodes only take 13 instructions,
# meaning that chain may have to be extended # meaning that chain may have to be extended
def position_changed(position) def position_changing(position , to)
next_pos = position.at + position.object.byte_length update_index(to)
fix_binary_for(next_pos) instruction = position.object
my_pos = Position.get(@instruction) return unless instruction.next
diff = next_pos - Position.get(@binary).at if @index == (Parfait::BinaryCode.data_length - 1 )
Position.log.debug "Diff: 0x#{diff.to_s(16)} , next 0x#{next_pos.to_s(16)} , binary #{Position.get(@binary)}" nekst_pos_diff = @binary.padded_length
raise "Invalid position #{diff.to_s(16)} , next #{next_pos.to_s(16)} #{position}" if diff < 8 else
if( (diff % (@binary.padded_length - @instruction.byte_length)) == 0 ) nekst_pos_diff = @index * 4 + instruction.byte_length
@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)}"
end 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 end
# When this is called, only the actual insert has happened (keeping the # When this is called, only the actual insert has happened (keeping the
# position logic out of the instruction assembly). # position logic out of the instruction assembly).
# #
# This event happens at the listener that was dependent on the position # This event happens at the listener of the positionwhere the insert happens, ie:
# before the insert, ie:
# position : the arg is the first instruction in the chain where insert happened # 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 # 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 : # 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) # - 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) def position_inserted(position)
inserted = position.object.next inserted = position.object.next
raise "uups" unless inserted ## TODO: remove
position.remove_position_listener(self)
new_pos = Position.new(inserted , -1) new_pos = Position.new(inserted , -1)
new_pos.position_listener(self) new_pos.position_listener(InstructionListener.new(@binary))
listen = InstructionListener.new(inserted , @binary) position.trigger_changing(position.at)
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
end end
# initialize the dependency graph for instructions # initialize the dependency graph for instructions
@ -110,12 +87,8 @@ module Risc
while(instruction) while(instruction)
position = Position.new(instruction , -1) position = Position.new(instruction , -1)
first = position unless first first = position unless first
nekst = instruction.next position.position_listener(InstructionListener.new( code ))
if nekst instruction = instruction.next
listener = InstructionListener.new( nekst , code )
position.position_listener(listener)
end
instruction = nekst
end end
first first
end end

View File

@ -24,7 +24,7 @@ module Risc
end end
def test_listener_method def test_listener_method
@position.set(8) @position.set(8)
listener = InstructionListener.new( @instruction , @binary ) listener = InstructionListener.new( @binary )
listener.position_changed(@position) listener.position_changed(@position)
end end
def test_ins_propagates def test_ins_propagates
@ -40,8 +40,8 @@ module Risc
def test_label_has_no_length def test_label_has_no_length
label = Label.new("Hi","Ho" , FakeAddress.new(5) , @instruction) label = Label.new("Hi","Ho" , FakeAddress.new(5) , @instruction)
InstructionListener.init(label , @binary) InstructionListener.init(label , @binary)
Position.get(label).set(10) Position.get(label).set(12)
assert_equal 10 , Position.get(@instruction).at assert_equal 12 , Position.get(@instruction).at
end end
def test_label_at_branch def test_label_at_branch
label = Label.new("Hi","Ho" , FakeAddress.new(5) , @instruction) label = Label.new("Hi","Ho" , FakeAddress.new(5) , @instruction)