move all position setting into position

Position and subclasses handle the logic, external to
the classes, so it can be swapped out later
(at runtime positions can’t change)
This commit is contained in:
Torsten Ruger 2018-05-07 22:30:43 +03:00
parent 68fb9b1bdc
commit ce3cc72f9e
10 changed files with 52 additions and 123 deletions

View File

@ -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 # if any file XX in any directory in the /lib changes, run a test_XX in the
# shadow directory in the /test # 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]}.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 #Arm instructions
watch(%r{^lib/arm/instructions/(.+)_instruction.rb}) { |m| "test/arm/test_#{m[1]}.rb" } watch(%r{^lib/arm/instructions/(.+)_instruction.rb}) { |m| "test/arm/test_#{m[1]}.rb" }

View File

@ -24,23 +24,7 @@ module Arm
def insert(instruction) def insert(instruction)
super super
my_pos = Risc::Position.get(self) 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 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
end end

View File

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

View File

@ -44,12 +44,6 @@ module Risc
ret ret
end 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 # shame we need this, just for logging
def byte_length def byte_length
0 0

View File

@ -78,7 +78,7 @@ module Risc
translate_arm unless @translated translate_arm unless @translated
#need the initial jump at 0 and then functions #need the initial jump at 0 and then functions
Position.set(binary_init,0) 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 ) @code_start = position_objects( binary_init.padded_length )
# and then everything code # and then everything code
position_code position_code
@ -91,8 +91,8 @@ module Risc
# want to have the objects first in the executable # want to have the objects first in the executable
objects.each do | id , objekt| objects.each do | id , objekt|
next if objekt.is_a?( Parfait::BinaryCode) or objekt.is_a?( Risc::Label ) next if objekt.is_a?( Parfait::BinaryCode) or objekt.is_a?( Risc::Label )
Position.set(objekt,at)
before = at before = at
Position.set(objekt,at)
at += objekt.padded_length at += objekt.padded_length
log.debug "Object #{objekt.class}:#{before.to_s(16)} len: #{(at - before).to_s(16)}" log.debug "Object #{objekt.class}:#{before.to_s(16)} len: #{(at - before).to_s(16)}"
end end
@ -110,14 +110,16 @@ module Risc
at = @code_start at = @code_start
objects.each do |id , method| objects.each do |id , method|
next unless method.is_a? Parfait::TypedMethod next unless method.is_a? Parfait::TypedMethod
method.cpu_instructions.set_position( at + 12 , 0 , method.binary)
before = at before = at
nekst = method.binary Position.set( method.binary , at , method)
while(nekst) Position.set( method.cpu_instructions, 3 , method.binary)
Position.set(nekst , at , method) # before = at
at += nekst.padded_length # nekst = method.binary
nekst = nekst.next # while(nekst)
end # 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 "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)}" log.debug "Instructions #{method.cpu_instructions.object_id.to_s(16)}:#{(before+12).to_s(16)}"
end end

View File

@ -35,6 +35,9 @@ module Risc
def to_s def to_s
"0x#{@at.to_s(16)}" "0x#{@at.to_s(16)}"
end end
# just a callback after creation AND insertion
def init
end
def reset_to(pos) def reset_to(pos)
return false if pos == at return false if pos == at
if((at - pos).abs > 1000) if((at - pos).abs > 1000)
@ -72,7 +75,10 @@ module Risc
old.reset_to(pos) old.reset_to(pos)
return old return old
end end
self.positions[object] = for_at( object , pos , extra) position = for_at( object , pos , extra)
self.positions[object] = position
position.init
position
end end
def self.for_at(object , at , extra) def self.for_at(object , at , extra)
@ -96,9 +102,26 @@ module Risc
@binary = binary @binary = binary
end 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) def reset_to(pos)
changed = super(pos) changed = super(pos)
puts "Reset (#{changed}) #{instruction}" #puts "Reset (#{changed}) #{instruction}"
return unless changed return unless changed
return unless instruction.next return unless instruction.next
instruction.next.set_position( pos + instruction.byte_length , 0) instruction.next.set_position( pos + instruction.byte_length , 0)

View File

@ -82,22 +82,22 @@ module Arm
end end
def test_too_big_add def test_too_big_add
code = @machine.add :r1 , :r1, 0x222 code = @machine.add :r1 , :r1, 0x222
code.set_position(0,0) Risc::Position.set(0,0)
# add 0x02 (first instruction) and then 0x220 shifted # add 0x02 (first instruction) and then 0x220 shifted
assert_code code , :add , [0x02,0x1c,0x91,0xe2] #e2 91 1e 02 assert_code code , :add , [0x02,0x1c,0x91,0xe2] #e2 91 1e 02
# added extra instruction to add "extra" # added extra instruction to add "extra"
assert_code code.next , :add , [0x22,0x10,0x91,0xe2] #e2 91 10 22 assert_code code.next , :add , [0x22,0x10,0x91,0xe2] #e2 91 10 22
end end
def label pos = 0x22 + 8 def label( pos = 0x22 + 8)
l = Risc.label("some" , "Label") l = Risc.label("some" , "Label")
l.set_position pos Risc::Position.set(l,pos , 1)
l l
end end
def test_move_object def test_move_object
code = @machine.add( :r1 , label) 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 assert_code code , :add , [0x22,0x10,0x9f,0xe2] #e2 9f 10 22
end end

View File

@ -22,7 +22,7 @@ module Arm
end end
def test_mov_big 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 = @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 begin # mov 512(0x200) = e3 a0 0c 02 add 34(0x22) = e2 90 00 22
assert_code code , :mov , [ 0x02,0x0c,0xb0,0xe3] assert_code code , :mov , [ 0x02,0x0c,0xb0,0xe3]
rescue Risc::LinkException rescue Risc::LinkException

View File

@ -42,7 +42,7 @@ module Risc
end end
def test_pos_arm def test_pos_arm
mov = Arm::ArmMachine.mov :r1, 128 mov = Arm::ArmMachine.mov :r1, 128
mov.set_position(0,0) Risc::Position.set(0,0)
end end
end end

View File

@ -1,8 +1,12 @@
require_relative "../helper" require_relative "../helper"
module Risc 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 def test_creation_ok
assert Position.new(0) assert Position.new(0)
end end
@ -26,7 +30,7 @@ module Risc
assert_equal 5 , pos.at assert_equal 5 , pos.at
end end
def test_set_instr 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 assert_equal IPosition , pos.class
end end
def tet_tos def tet_tos