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:
parent
68fb9b1bdc
commit
ce3cc72f9e
@ -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" }
|
||||||
|
@ -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
|
||||||
|
@ -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
|
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
Loading…
Reference in New Issue
Block a user