diff --git a/lib/risc/machine.rb b/lib/risc/machine.rb index 6b30c6d1..9240ce4d 100644 --- a/lib/risc/machine.rb +++ b/lib/risc/machine.rb @@ -86,9 +86,9 @@ module Risc raise "Not translated " unless @translated #need the initial jump at 0 and then functions Position.set(cpu_init , 0 , nil) - @code_start = position_objects( @platform.padding ) + code_start = position_objects( @platform.padding ) # and then everything code - position_code + position_code(code_start) end # go through everything that is not code (BinaryCode) and set position @@ -97,10 +97,13 @@ module Risc def position_objects(at) # want to have the objects first in the executable sorted = objects.values.sort{|left,right| left.class.name <=> right.class.name} + previous = nil sorted.each do | objekt| next if objekt.is_a?( Parfait::BinaryCode) or objekt.is_a?( Risc::Label ) before = at - Position.set(objekt,at) + position = Position.set(objekt,at) + previous.register_event(:position_changed , Position::ObjectListener.new(objekt)) if previous + previous = position at += objekt.padded_length log.debug "Object #{objekt.class}:#{before.to_s(16)} len: #{(at - before).to_s(16)}" end @@ -112,17 +115,14 @@ module Risc # So that all code from one method is layed out linearly (for debugging) # we go through methods, and then through all codes from the method # - # start at @code_start. The method is called until - # assembly stops throwing errors - def position_code - at = @code_start + # start at code_start. + def position_code(code_start) first_method = Parfait.object_space.types.values.first.methods - before = at - Position.set( first_method.binary , at , first_method) - Position.set( first_method.cpu_instructions, at + Parfait::BinaryCode.byte_offset , first_method.binary) - log.debug "Method #{first_method.name}:#{before.to_s(16)} len: #{(at - before).to_s(16)}" + before = code_start + Position.set( first_method.binary , code_start , first_method) + Position.set( first_method.cpu_instructions, code_start + Parfait::BinaryCode.byte_offset , first_method.binary) + log.debug "Method #{first_method.name}:#{before.to_s(16)} len: #{(code_start - before).to_s(16)}" log.debug "Instructions #{first_method.cpu_instructions.object_id.to_s(16)}:#{(before+Parfait::BinaryCode.byte_offset).to_s(16)}" - at end # Create Binary code for all methods and the initial jump diff --git a/lib/risc/position/object_listener.rb b/lib/risc/position/object_listener.rb new file mode 100644 index 00000000..24d60d49 --- /dev/null +++ b/lib/risc/position/object_listener.rb @@ -0,0 +1,31 @@ + +module Risc + module Position + + # Listeners localise the changes that need to happen. + # + # An object listener assmes it is set up to the previous object. + # so when position changes, it places itself just behind the previous object + # + # This is handy, since the "normal" chaining of object is forward + # But the dependencies are backwards. This way we don't clutter the + # actual object (or even the position), but keep the logic seperate. + class ObjectListener + + # initialize with the object that needs to react to change + def initialize(object) + @object = object + end + + # when the argument changes position, we update the objects + # position to reflect that change + # + def position_changed(previous) + me = previous.at + previous.object.padded_length + object_pos = Position.get(@object) + return if me == object_pos.at + Position.set(@object , me) + end + end + end +end diff --git a/lib/risc/position/object_position.rb b/lib/risc/position/object_position.rb index dc9067f2..01af52da 100644 --- a/lib/risc/position/object_position.rb +++ b/lib/risc/position/object_position.rb @@ -31,6 +31,7 @@ module Risc end def reset_to(pos , guaranteed_nil ) return false if pos == at + trigger(:position_changed , self) if((at - pos).abs > 1000) raise "position set too far off #{pos}!=#{at} for #{object}:#{object.class}" end diff --git a/lib/risc/position/position.rb b/lib/risc/position/position.rb index 3936a5ef..6fb77b63 100644 --- a/lib/risc/position/position.rb +++ b/lib/risc/position/position.rb @@ -105,5 +105,6 @@ module Risc end end require_relative "object_position" +require_relative "object_listener" require_relative "instruction_position" require_relative "code_position" diff --git a/test/risc/position/test_object_listener.rb b/test/risc/position/test_object_listener.rb new file mode 100644 index 00000000..8a951bc5 --- /dev/null +++ b/test/risc/position/test_object_listener.rb @@ -0,0 +1,34 @@ +require_relative "../helper" + +module Risc + module Position + class Dummy + def padded_length + 4 + end + end + class TestObjectListener < MiniTest::Test + + def setup + @object = Dummy.new + @dependent = Dummy.new + @pos = Position.set(@object,0) + Position.set(@dependent,0) + @listener = ObjectListener.new(@dependent) + end + def test_register + assert @pos.register_event(:position_changed , @listener) + end + def test_no_fire + @pos.register_event(:position_changed , self) + @pos = Position.set(@object,0) + assert_equal 0 , Position.get(@dependent).at + end + def test_reset + @pos.register_event(:position_changed , @listener) + @pos = Position.set(@object,4) + assert_equal 4 , Position.get(@dependent).at + end + end + end +end