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

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

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

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

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