diff --git a/lib/risc/interpreter.rb b/lib/risc/interpreter.rb index 260e70c2..4ffa77ab 100644 --- a/lib/risc/interpreter.rb +++ b/lib/risc/interpreter.rb @@ -14,7 +14,7 @@ module Risc # fire events for changed pc and register contents include Util::Eventable include Util::Logging - log_level :debug + log_level :info attr_reader :instruction , :clock , :pc # current instruction and pc attr_reader :registers # the registers, 16 (a hash, sym -> contents) diff --git a/lib/risc/machine.rb b/lib/risc/machine.rb index d6d8818c..54f83296 100644 --- a/lib/risc/machine.rb +++ b/lib/risc/machine.rb @@ -120,12 +120,13 @@ module Risc Parfait.object_space.types.values.each do |type| next unless type.methods type.methods.each_method do |method| - Position.log.debug "Position starts for method #{method.name}" - last_code = CodeListener.init(method.binary) - last_code.set(code_start) - first_position = InstructionListener.init(method.cpu_instructions, method.binary) - first_position.set( code_start + Parfait::BinaryCode.byte_offset) - code_start = last_code.next_slot + #next unless method.name == :main or method.name == :__init__ + Position.log.debug "Method start #{code_start.to_s(16)} #{method.name}" + code_pos = CodeListener.init(method.binary) + InstructionListener.init(method.cpu_instructions, method.binary) + code_pos.position_listener( LabelListener.new(method.cpu_instructions)) + code_pos.set(code_start) + code_start = Position.get(method.binary.last_code).next_slot end end #Position.set( first_method.cpu_instructions, code_start + Parfait::BinaryCode.byte_offset , first_method.binary) diff --git a/lib/risc/position/instruction_listener.rb b/lib/risc/position/instruction_listener.rb index ed4d5c94..2dbc2de5 100644 --- a/lib/risc/position/instruction_listener.rb +++ b/lib/risc/position/instruction_listener.rb @@ -25,6 +25,7 @@ module Risc # Taking into account that BinaryCodes only take 13 instructions, # meaning that chain may have to be extended def position_changing(position , to) + Position.log.debug "Changing #{position} to #{to.to_s(16)}, bin #{Position.get(@binary)}" update_index(to) instruction = position.object return unless instruction.next @@ -40,7 +41,7 @@ module Risc 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 + 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 diff --git a/lib/risc/position/label_listener.rb b/lib/risc/position/label_listener.rb new file mode 100644 index 00000000..ea673c09 --- /dev/null +++ b/lib/risc/position/label_listener.rb @@ -0,0 +1,39 @@ +module Risc + + # LabelListener is the one point that connects the BinaryCode + # and Instruction positions. + # + # LabelListener is instantiated with the first label of a Method + # and attached to the first BinaryCode. + # + # When the code moves, the label position is updated. + # + # The first code may get pushed by a previous method, and there is otherwise + # no way to react to this. + class LabelListener + + attr_reader :label + + # initialize with the first label of the method + def initialize(label) + @label = label + end + + + # The incoming position is the first BinaryCode of the method + # We simply position the Label (instance, see initialize) as the + # first entry in the BinaryCode, at BinaryCode.byte_offset + def position_changed(position) + label_pos = Position.get(@label) + label_pos.set(position + Parfait::BinaryCode.byte_offset) + end + + # don't react to insertion, as the CodeListener will take care + def position_inserted(position) + end + + # dont react, as we do the work in position_changed + def position_changing(position , to) + end + end +end diff --git a/lib/risc/position/position.rb b/lib/risc/position/position.rb index 50c15edb..1e0f602d 100644 --- a/lib/risc/position/position.rb +++ b/lib/risc/position/position.rb @@ -190,3 +190,4 @@ end require_relative "position_listener" require_relative "instruction_listener" require_relative "code_listener" +require_relative "label_listener" diff --git a/test/risc/position/test_label_listener.rb b/test/risc/position/test_label_listener.rb new file mode 100644 index 00000000..aaf7a986 --- /dev/null +++ b/test/risc/position/test_label_listener.rb @@ -0,0 +1,25 @@ +require_relative "helper" + +module Risc + class TestLabelListener < MiniTest::Test + + def setup + Risc.machine.boot + @label = Label.new("Hi","Ho" , FakeAddress.new(5)) + @label_pos = Position.new(@label , -1) + @code = Parfait::BinaryCode.new(1) + @code_pos = Position.new(@code , -1) + @code_pos.position_listener( LabelListener.new(@label)) + end + + def test_move + @code_pos.set(0) + assert_equal 8 , @label_pos.at + end + def test_move_twice + @code_pos.set(0) + @code_pos.set(0x40) + assert_equal 72 , @label_pos.at + end + end +end diff --git a/test/risc/test_machine.rb b/test/risc/test_machine.rb index e5d5cf78..e2715836 100644 --- a/test/risc/test_machine.rb +++ b/test/risc/test_machine.rb @@ -34,6 +34,18 @@ module Risc assert_equal 5, count end end + class TestMachinePos < MiniTest::Test + def setup + @machine = Risc.machine.boot + @machine.translate(:arm) + @machine.position_all + end + def test_positions_set + @machine.objects.each do |id,obj| + assert Position.get(obj).valid? , "#{Position.get(obj)} , #{obj.object_id.to_s(16)}" + end + end + end class TestMachineInit < MiniTest::Test def setup @machine = Risc.machine.boot @@ -45,10 +57,7 @@ module Risc assert_equal 0 , Position.get(@machine.cpu_init).at end def test_cpu_at - assert_equal "0x5e08" , Position.get(@machine.cpu_init.first).to_s - end - def pest_cpu_bin - assert_equal "0x5ecc" , Position.get(@machine.cpu_init).to_s + assert_equal "0x5eb4" , Position.get(@machine.cpu_init.first).to_s end def test_cpu_label assert_equal Position , Position.get(@machine.cpu_init.first).class @@ -61,5 +70,11 @@ module Risc bin = Parfait.object_space.get_init.binary.next assert 0 != bin.get_word(0) , "index 0 is 0 #{bin.inspect}" end + def test_positions_set + @machine.objects.each do |id,obj| + assert Position.get(obj).valid? , "#{Position.get(obj)} , #{obj.object_id.to_s(16)}" + end + end + end end