From 32e1903884d4864285f01b65de42c5bf2be8c5ba Mon Sep 17 00:00:00 2001 From: Torsten Ruger Date: Thu, 25 Jun 2015 16:31:09 +0300 Subject: [PATCH] finished init routine and better implemented sys calls --- lib/arm/instructions/call_instruction.rb | 3 ++- lib/arm/passes/constant_implementation.rb | 2 +- lib/arm/passes/syscall_implementation.rb | 30 +++++++++++++++++---- lib/parfait/space.rb | 5 ++++ lib/register/builtin/kernel.rb | 24 ++++++++++------- lib/register/instructions/load_constant.rb | 10 +++---- lib/register/passes/frame_implementation.rb | 2 +- lib/register/passes/set_implementation.rb | 2 +- lib/virtual/boot.rb | 3 +-- lib/virtual/machine.rb | 2 +- 10 files changed, 57 insertions(+), 26 deletions(-) diff --git a/lib/arm/instructions/call_instruction.rb b/lib/arm/instructions/call_instruction.rb index 68378606..c16bc9be 100644 --- a/lib/arm/instructions/call_instruction.rb +++ b/lib/arm/instructions/call_instruction.rb @@ -14,6 +14,7 @@ module Arm def initialize(first, attributes) super(attributes) + raise "no target" if first.nil? @first = first opcode = @attributes[:opcode].to_s if opcode.length == 3 and opcode[0] == "b" @@ -32,7 +33,7 @@ module Arm case @attributes[:opcode] when :b, :call arg = @first - #puts "BLAB #{arg.inspect}" + puts "BLAB #{arg.class}" if arg.is_a?(Virtual::Block) or arg.is_a?(Parfait::Method) #relative addressing for jumps/calls # but because of the arm "theoretical" 3- stage pipeline, diff --git a/lib/arm/passes/constant_implementation.rb b/lib/arm/passes/constant_implementation.rb index a497c980..d25904ce 100644 --- a/lib/arm/passes/constant_implementation.rb +++ b/lib/arm/passes/constant_implementation.rb @@ -4,7 +4,7 @@ module Arm def run block block.codes.dup.each do |code| next unless code.is_a? Register::LoadConstant - load = ArmMachine.ldr( code.value , code.constant ) + load = ArmMachine.ldr( code.register , code.constant ) block.replace(code , load ) #puts "replaced #{load.inspect.to_s[0..1000]}" end diff --git a/lib/arm/passes/syscall_implementation.rb b/lib/arm/passes/syscall_implementation.rb index 1bdbb3d3..5e5354db 100644 --- a/lib/arm/passes/syscall_implementation.rb +++ b/lib/arm/passes/syscall_implementation.rb @@ -1,17 +1,37 @@ module Arm class SyscallImplementation + CALLS_CODES = { :putstring => 4 , :exit => 0 } def run block block.codes.dup.each do |code| next unless code.is_a? Register::Syscall - raise "uups" unless code.name == :putstring - new_codes = [ ArmMachine.mov( :r1 , 20 ) ] - new_codes << ArmMachine.ldr( :r0 , Virtual::Slot::MESSAGE_REGISTER, Virtual::SELF_INDEX) - new_codes << ArmMachine.mov( :r7 , 4 ) - new_codes << ArmMachine.swi( 0 ) + new_codes = [] + int_code = CALLS_CODES[code.name] + raise "Not implemented syscall, #{code.name}" unless int_code + send( code.name , int_code , new_codes ) block.replace(code , new_codes ) end end + + def putstring int_code , codes + codes << ArmMachine.mov( :r1 , 20 ) # String length, obvious TODO + codes << ArmMachine.ldr( :r0 , Virtual::Slot::MESSAGE_REGISTER, Virtual::SELF_INDEX) + syscall(int_code , codes ) + end + + def exit int_code , codes + syscall int_code , codes + end + + private + + # syscall is always triggered by swi(0) + # The actual code (ie the index of the kernel function) is in r7 + def syscall int_code , codes + codes << ArmMachine.mov( :r7 , int_code ) + codes << ArmMachine.swi( 0 ) + end end + Virtual.machine.add_pass "Arm::SyscallImplementation" end diff --git a/lib/parfait/space.rb b/lib/parfait/space.rb index dd140b05..1c26a2db 100644 --- a/lib/parfait/space.rb +++ b/lib/parfait/space.rb @@ -62,6 +62,11 @@ module Parfait kernel.get_instance_method :main end + def get_init + kernel = get_class_by_name :Kernel + kernel.get_instance_method :__init__ + end + # this is the way to instantiate classes (not Parfait::Class.new) # so we get and keep exactly one per name def get_class_by_name name diff --git a/lib/register/builtin/kernel.rb b/lib/register/builtin/kernel.rb index a78febea..4a5b124a 100644 --- a/lib/register/builtin/kernel.rb +++ b/lib/register/builtin/kernel.rb @@ -1,18 +1,24 @@ module Builtin module Kernel module ClassMethods - # this is the really really first place the machine starts. + # this is the really really first place the machine starts (apart from the jump here) # it isn't really a function, ie it is jumped to (not called), exits and may not return - # so it is responsible for initial setup (and relocation) + # so it is responsible for initial setup def __init__ context function = Virtual::CompiledMethodInfo.create_method(:Kernel,:__init__ , []) -# puts "INIT LAYOUT #{function.get_layout.get_layout}" function.info.return_type = Virtual::Integer - main = Virtual.machine.space.get_main - me = Virtual::Self.new(Virtual::Reference) - code = Virtual::Set.new(me , Virtual::Self.new(me.type)) - function.info.add_code(code) - function.info.add_code Virtual::MethodCall.new(main) + # no method enter or return (automatically added), remove + function.info.blocks.first.codes.pop # no Method enter + function.info.blocks.last.codes.pop # no Method return + #Set up the Space as self upon init + space = Parfait::Space.object_space + function.info.add_code Register::LoadConstant.new( space , Virtual::Slot::SELF_REGISTER) + message_ind = space.get_layout().index_of( :next_message ) + # Load the message to message register (0) + function.info.add_code Register::GetSlot.new( Virtual::Slot::SELF_REGISTER , message_ind , Virtual::Slot::MESSAGE_REGISTER) + # now we are set up to issue a call to the main + function.info.add_code Virtual::MethodCall.new(Virtual.machine.space.get_main) + emit_syscall( function , :exit ) return function end def putstring context @@ -49,7 +55,7 @@ module Builtin space_tmp = Register::RegisterReference.tmp_reg ind = Parfait::Space.object_space.get_layout().index_of( :syscall_message ) raise "index not found for :syscall_message" unless ind - function.info.add_code Register::LoadConstant.new( space_tmp , Parfait::Space.object_space ) + function.info.add_code Register::LoadConstant.new( Parfait::Space.object_space , space_tmp) function.info.add_code Register::SetSlot.new( Virtual::Slot::MESSAGE_REGISTER , space_tmp , ind) end def restore_message(function) diff --git a/lib/register/instructions/load_constant.rb b/lib/register/instructions/load_constant.rb index 7a85a903..29e66735 100644 --- a/lib/register/instructions/load_constant.rb +++ b/lib/register/instructions/load_constant.rb @@ -1,14 +1,14 @@ module Register # load a constant into a register # - # first argument is the register the constant is loaded into - # second is the actual constant + # first is the actual constant, either immediate register or object reference (from the space) + # second argument is the register the constant is loaded into class LoadConstant < Instruction - def initialize value , constant - @value = value + def initialize constant , register + @register = register @constant = constant end - attr_accessor :value , :constant + attr_accessor :register , :constant end end diff --git a/lib/register/passes/frame_implementation.rb b/lib/register/passes/frame_implementation.rb index fcf8a2d6..3b125be5 100644 --- a/lib/register/passes/frame_implementation.rb +++ b/lib/register/passes/frame_implementation.rb @@ -34,7 +34,7 @@ module Register # a temporary place to store the new frame frame_tmp = space_tmp.next_reg_use # move the spave to it's register (mov instruction gets the address of the object) - new_codes = [ LoadConstant.new( space_tmp , Parfait::Space.object_space )] + new_codes = [ LoadConstant.new( Parfait::Space.object_space , space_tmp )] # find index in the space where to grab frame/message ind = Parfait::Space.object_space.get_layout().index_of( kind ) raise "index not found for #{kind}.#{kind.class}" unless ind diff --git a/lib/register/passes/set_implementation.rb b/lib/register/passes/set_implementation.rb index d4f45eb6..06c75d51 100644 --- a/lib/register/passes/set_implementation.rb +++ b/lib/register/passes/set_implementation.rb @@ -33,7 +33,7 @@ module Register tmp = RegisterReference.tmp_reg # for constants we have to "move" the constants value if( code.from.is_a?(Parfait::Value) or code.from.is_a?(Symbol)) - move1 = LoadConstant.new( tmp , code.from ) + move1 = LoadConstant.new( code.from , tmp ) else # while otherwise we "load" move1 = GetSlot.new( code.from.reg , code.from.index , tmp ) end diff --git a/lib/virtual/boot.rb b/lib/virtual/boot.rb index 2da33f95..e590458f 100644 --- a/lib/virtual/boot.rb +++ b/lib/virtual/boot.rb @@ -103,10 +103,9 @@ module Virtual end obj = @class_mappings[:Kernel ] # create dummy main first, __init__ calls it - [:putstring,:exit,:__send ].each do |f| + [:putstring,:exit,:__send , :__init__ ].each do |f| obj.add_instance_method Builtin::Kernel.send(f , nil) end - underscore_init = obj.add_instance_method Builtin::Kernel.send(:__init__, nil) obj = @class_mappings[:Integer ] [:putint,:fibo].each do |f| diff --git a/lib/virtual/machine.rb b/lib/virtual/machine.rb index 3c017c6a..a8f85fbd 100644 --- a/lib/virtual/machine.rb +++ b/lib/virtual/machine.rb @@ -123,7 +123,7 @@ module Virtual def boot boot_parfait! @init = Block.new("init",nil) - @init.add_code Register::RegisterMain.new( self.space.get_main ) + @init.add_code Register::RegisterMain.new( self.space.get_init ) @booted = true end