From ce3cc72f9ecc9e193e4189f7e3012a9c30716c20 Mon Sep 17 00:00:00 2001 From: Torsten Ruger Date: Mon, 7 May 2018 22:30:43 +0300 Subject: [PATCH] move all position setting into position MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Position and subclasses handle the logic, external to the classes, so it can be swapped out later (at runtime positions can’t change) --- Guardfile | 3 + lib/arm/instructions/instruction.rb | 18 +---- lib/arm/machine_code.rb | 81 ------------------- lib/risc/instructions/label.rb | 6 -- lib/risc/machine.rb | 20 ++--- lib/risc/position.rb | 27 ++++++- test/arm/test_logic.rb | 8 +- test/arm/test_move.rb | 2 +- test/risc/test_padding.rb | 2 +- .../{test_position.rb => test_position1.rb} | 8 +- 10 files changed, 52 insertions(+), 123 deletions(-) delete mode 100644 lib/arm/machine_code.rb rename test/risc/{test_position.rb => test_position1.rb} (83%) diff --git a/Guardfile b/Guardfile index ecebb84e..5bf2111e 100644 --- a/Guardfile +++ b/Guardfile @@ -12,6 +12,9 @@ guard :minitest do # with Minitest::Unit # if any file XX in any directory in the /lib changes, run a test_XX in the # shadow directory in the /test watch(%r{^lib/(.*/)?([^/]+)\.rb$}) { |m| "test/#{m[1]}test_#{m[2]}.rb" } + watch(%r{^lib/(.*/)?([^/]+)\.rb$}) { |m| "test/#{m[1]}test_#{m[2]}1.rb" } + watch(%r{^lib/(.*/)?([^/]+)\.rb$}) { |m| "test/#{m[1]}test_#{m[2]}2.rb" } + watch(%r{^lib/(.*/)?([^/]+)\.rb$}) { |m| "test/#{m[1]}test_#{m[2]}3.rb" } #Arm instructions watch(%r{^lib/arm/instructions/(.+)_instruction.rb}) { |m| "test/arm/test_#{m[1]}.rb" } diff --git a/lib/arm/instructions/instruction.rb b/lib/arm/instructions/instruction.rb index fb5d8e0a..a3013096 100644 --- a/lib/arm/instructions/instruction.rb +++ b/lib/arm/instructions/instruction.rb @@ -24,23 +24,7 @@ module Arm def insert(instruction) super my_pos = Risc::Position.get(self) - @next.set_position( my_pos + self.byte_length , 0 , my_pos.binary) + Risc::Position.set( my_pos + self.byte_length , 0 , my_pos.binary) end - - def set_position( position , count , extra = nil) - Risc::Position.set(self,position , extra) - position += byte_length - if self.next - count += 1 #assumes 4 byte instructions, as does the whole setup - if( 0 == count % 12) # 12 is the amount of instructions that fit into a BinaryCode - count = 0 - position += 12 # 12=3*4 , 3 for marker,type,next words to jump over - end - self.next.set_position( position , count , extra) - else - position - end - end - end end diff --git a/lib/arm/machine_code.rb b/lib/arm/machine_code.rb deleted file mode 100644 index 764772f8..00000000 --- a/lib/arm/machine_code.rb +++ /dev/null @@ -1,81 +0,0 @@ -module Arm - class MachineCode - - def function_call( into , call ) - raise "Not CallSite #{call.inspect}" unless call.is_a? Risc::CallSite - raise "Not linked #{call.inspect}" unless call.function - into.add_code call( call.function ) - raise "No return type for #{call.function.name}" unless call.function.return_type - call.function.return_type - end - - def main_start( context ) - entry = Risc::Block.new("main_entry",nil,nil) - entry.add_code mov( :fp , 0 ) - entry.add_code call( context.function ) - entry - end - def main_exit( context ) - exit = Risc::Block.new("main_exit",nil,nil) - syscall(exit , 1) - exit - end - def function_entry( block, f_name ) - block.add_code push( [:lr] ) - block - end - def function_exit( entry , f_name ) - entry.add_code pop( [:pc] ) - entry - end - - # assumes string in standard receiver reg (r2) and moves them down for the syscall - def write_stdout( function ) #, string - # TODO save and restore r0 - function.mov( :r0 , 1 ) # 1 == stdout - function.mov( :r1 , receiver_register ) - function.mov( receiver_register , :r3 ) - syscall( function.insertion_point , 4 ) # 4 == write - end - - # stop, do not return - def exit( function )#, string - syscall( function.insertion_point , 1 ) # 1 == exit - end - - - # the number (a Risc::Integer) is (itself) divided by 10, ie overwritten by the result - # and the remainder is overwritten (ie an out argument) - # not really a function, more a macro, - def div10( function, number , remainder ) - # Note about division: devision is MUCH more expensive than one would have thought - # And coding it is a bit of a mind leap: it's all about finding a a result that gets the - # remainder smaller than an int. i'll post some links sometime. This is from the arm manual - tmp = function.new_local - function.instance_eval do - sub( remainder , number , 10 ) - sub( number , number , number , shift_lsr: 2) - add( number , number , number , shift_lsr: 4) - add( number , number , number , shift_lsr: 8) - add( number , number , number , shift_lsr: 16) - mov( number , number , shift_lsr: 3) - add( tmp , number , number , shift_lsl: 2) - sub( remainder , remainder , tmp , shift_lsl: 1 , update_status: 1) - add( number , number, 1 , condition_code: :pl ) - add( remainder , remainder , 10 , condition_code: :mi ) - end - end - - def syscall( block , num ) - # This is very arm specific, syscall number is passed in r7, - # other arguments like a c call ie 0 and up - sys = Risc::Integer.new( Risc::RiscValue.new(SYSCALL_REG) ) - ret = Risc::Integer.new( Risc::RiscValue.new(RETURN_REG) ) - block.add_code mov( sys , num ) - block.add_code swi( 0 ) - #todo should write type into r1 according to syscall - ret - end - - end -end diff --git a/lib/risc/instructions/label.rb b/lib/risc/instructions/label.rb index 757a4874..7d5e30a5 100644 --- a/lib/risc/instructions/label.rb +++ b/lib/risc/instructions/label.rb @@ -44,12 +44,6 @@ module Risc ret end - # labels have the same position as their next - def set_position( position , count = 0 , extra = nil) - Position.set(self,position , extra) - self.next.set_position(position,count,extra) if self.next - end - # shame we need this, just for logging def byte_length 0 diff --git a/lib/risc/machine.rb b/lib/risc/machine.rb index b640f659..022323e1 100644 --- a/lib/risc/machine.rb +++ b/lib/risc/machine.rb @@ -78,7 +78,7 @@ module Risc translate_arm unless @translated #need the initial jump at 0 and then functions Position.set(binary_init,0) - cpu_init.set_position( 12 ,0 , binary_init) + Position.set(cpu_init , 3 , binary_init) @code_start = position_objects( binary_init.padded_length ) # and then everything code position_code @@ -91,8 +91,8 @@ module Risc # want to have the objects first in the executable objects.each do | id , objekt| next if objekt.is_a?( Parfait::BinaryCode) or objekt.is_a?( Risc::Label ) - Position.set(objekt,at) before = at + Position.set(objekt,at) at += objekt.padded_length log.debug "Object #{objekt.class}:#{before.to_s(16)} len: #{(at - before).to_s(16)}" end @@ -110,14 +110,16 @@ module Risc at = @code_start objects.each do |id , method| next unless method.is_a? Parfait::TypedMethod - method.cpu_instructions.set_position( at + 12 , 0 , method.binary) before = at - nekst = method.binary - while(nekst) - Position.set(nekst , at , method) - at += nekst.padded_length - nekst = nekst.next - end + Position.set( method.binary , at , method) + Position.set( method.cpu_instructions, 3 , method.binary) + # before = at + # nekst = method.binary + # while(nekst) + # Position.set(nekst , at , method) + # at += nekst.padded_length + # nekst = nekst.next + # end log.debug "Method #{method.name}:#{before.to_s(16)} len: #{(at - before).to_s(16)}" log.debug "Instructions #{method.cpu_instructions.object_id.to_s(16)}:#{(before+12).to_s(16)}" end diff --git a/lib/risc/position.rb b/lib/risc/position.rb index 37f3d9d9..eba9dd13 100644 --- a/lib/risc/position.rb +++ b/lib/risc/position.rb @@ -35,6 +35,9 @@ module Risc def to_s "0x#{@at.to_s(16)}" end + # just a callback after creation AND insertion + def init + end def reset_to(pos) return false if pos == at if((at - pos).abs > 1000) @@ -72,7 +75,10 @@ module Risc old.reset_to(pos) return old end - self.positions[object] = for_at( object , pos , extra) + position = for_at( object , pos , extra) + self.positions[object] = position + position.init + position end def self.for_at(object , at , extra) @@ -96,9 +102,26 @@ module Risc @binary = binary end + def set_position( position , binary = nil) + raise "invalid position #{position}" if position > 15 + binary = Risc::Position.get(self).binary unless binary + Risc::Position.set(self, position , binary) + position += byte_length / 4 #assumes 4 byte instructions, as does the whole setup + if self.next + if( 3 == position % 15) # 12 is the amount of instructions that fit into a BinaryCode + position = 3 + binary = binary.next + end + self.next.set_position( position , binary) + else + position + end + end + + def reset_to(pos) changed = super(pos) - puts "Reset (#{changed}) #{instruction}" + #puts "Reset (#{changed}) #{instruction}" return unless changed return unless instruction.next instruction.next.set_position( pos + instruction.byte_length , 0) diff --git a/test/arm/test_logic.rb b/test/arm/test_logic.rb index 2824f6c3..0dbe1c4e 100644 --- a/test/arm/test_logic.rb +++ b/test/arm/test_logic.rb @@ -82,22 +82,22 @@ module Arm end def test_too_big_add code = @machine.add :r1 , :r1, 0x222 - code.set_position(0,0) + Risc::Position.set(0,0) # add 0x02 (first instruction) and then 0x220 shifted assert_code code , :add , [0x02,0x1c,0x91,0xe2] #e2 91 1e 02 # added extra instruction to add "extra" assert_code code.next , :add , [0x22,0x10,0x91,0xe2] #e2 91 10 22 end - def label pos = 0x22 + 8 + def label( pos = 0x22 + 8) l = Risc.label("some" , "Label") - l.set_position pos + Risc::Position.set(l,pos , 1) l end def test_move_object code = @machine.add( :r1 , label) - code.set_position(0,0) + Risc::Position.set(code,0,0) assert_code code , :add , [0x22,0x10,0x9f,0xe2] #e2 9f 10 22 end diff --git a/test/arm/test_move.rb b/test/arm/test_move.rb index deca4b05..7aecec29 100644 --- a/test/arm/test_move.rb +++ b/test/arm/test_move.rb @@ -22,7 +22,7 @@ module Arm end def test_mov_big code = @machine.mov :r0, 0x222 # is not 8 bit and can't be rotated by the arm system in one instruction - code.set_position(0,0) + Risc::Position.set(code,0,1) begin # mov 512(0x200) = e3 a0 0c 02 add 34(0x22) = e2 90 00 22 assert_code code , :mov , [ 0x02,0x0c,0xb0,0xe3] rescue Risc::LinkException diff --git a/test/risc/test_padding.rb b/test/risc/test_padding.rb index b8e1df66..a133cf48 100644 --- a/test/risc/test_padding.rb +++ b/test/risc/test_padding.rb @@ -42,7 +42,7 @@ module Risc end def test_pos_arm mov = Arm::ArmMachine.mov :r1, 128 - mov.set_position(0,0) + Risc::Position.set(0,0) end end diff --git a/test/risc/test_position.rb b/test/risc/test_position1.rb similarity index 83% rename from test/risc/test_position.rb rename to test/risc/test_position1.rb index 4a9203f4..2cbda8a5 100644 --- a/test/risc/test_position.rb +++ b/test/risc/test_position1.rb @@ -1,8 +1,12 @@ require_relative "../helper" module Risc - class TestPosition < MiniTest::Test + class TestPositionBasic < MiniTest::Test + def setup + Risc.machine.boot + @binary = Parfait::BinaryCode.new(1) + end def test_creation_ok assert Position.new(0) end @@ -26,7 +30,7 @@ module Risc assert_equal 5 , pos.at end def test_set_instr - pos = Position.set( Risc::Label.new("hi","ho") , 0) + pos = Position.set( Risc::Label.new("hi","ho") , 0 , @binary) assert_equal IPosition , pos.class end def tet_tos