From 22b5117c8b3910a55e860f9829ebd78f980362fb Mon Sep 17 00:00:00 2001 From: Torsten Ruger Date: Tue, 6 May 2014 00:12:04 +0300 Subject: [PATCH] getting a _start and _exit, just missing the actual code --- lib/arm/arm_machine.rb | 9 ++-- lib/arm/assembler.rb | 4 +- lib/arm/block.rb | 83 ------------------------------- lib/arm/call_instruction.rb | 1 + lib/arm/logic_instruction.rb | 3 +- lib/crystal.rb | 3 +- lib/vm/block.rb | 6 ++- lib/vm/code.rb | 10 ++-- lib/vm/function.rb | 24 ++++++--- lib/vm/kernel.rb | 2 +- lib/{arm => vm}/string_literal.rb | 2 +- lib/vm/values.rb | 1 + 12 files changed, 43 insertions(+), 105 deletions(-) delete mode 100644 lib/arm/block.rb rename lib/{arm => vm}/string_literal.rb (98%) diff --git a/lib/arm/arm_machine.rb b/lib/arm/arm_machine.rb index 2f178c9b..fd76f532 100644 --- a/lib/arm/arm_machine.rb +++ b/lib/arm/arm_machine.rb @@ -40,14 +40,15 @@ module Arm end def main_entry - mov( :left => :fp , :right => 0 ) + entry = Vm::Block.new("main_entry") + entry.add_code mov( :left => :fp , :right => 0 ) end def main_exit - syscall(0) + entry = Vm::Block.new("main_exit") + entry.add_code syscall(0) end def syscall num - mov( :left => 7 , :right => num ) - swi( :left => 0 ) + [mov( :left => :r7 , :right => num ) , swi( :left => 0 )] end end end \ No newline at end of file diff --git a/lib/arm/assembler.rb b/lib/arm/assembler.rb index 70915deb..3fb4850b 100644 --- a/lib/arm/assembler.rb +++ b/lib/arm/assembler.rb @@ -1,5 +1,5 @@ require 'arm/nodes' -require 'arm/block' +require 'vm/block' require 'stream_reader' require 'stringio' require "arm/string_literal" @@ -43,7 +43,7 @@ module Arm def add_string str code = @string_table[str] return code if code - data = Arm::StringLiteral.new(str) + data = Vm::StringLiteral.new(str) @string_table[str] = data end diff --git a/lib/arm/block.rb b/lib/arm/block.rb deleted file mode 100644 index 0f7168f7..00000000 --- a/lib/arm/block.rb +++ /dev/null @@ -1,83 +0,0 @@ -require_relative 'call_instruction' -require_relative 'stack_instruction' -require_relative 'logic_instruction' -require_relative 'memory_instruction' - -module Arm - - class Code ; end - - # A Block is the smalles unit of code, a list of instructions as it were - # It is also a point to jump/branch to. An address in the final stream. - # To allow for forward branches creation does not fix the position. - # Thee position is fixed in one of three ways - # - create the block with ruby block, signalling that the instantiation poin is the position - # - call block.code with the code or if you wish program.add_block (and add you code with calls) - # - the assmebly process will pin it if it wasn't set - - # creating blocks is done by calling the blocks name/label on either a program or a block - # (method missing will cathc the call and create the block) - # and the easiest way is to go into a ruby block and start writing instructions - # Example (backward jump): - # program.loop do create a new block with label loop - # sub r1 , r1 , 1 count the r1 register down - # bne :loop jump back to loop when the counter is not zero - # end (initialization and actual code missing off course) - - # Example (forward jump) - # else_block = program.else - # program.if do - # test r1 , 0 test some condition - # beq :else_block - # mov . . .. .. do whatever the if block does - # end - # else_block.code do - # ldr .... do whatever else does - # end - - # Blocks are also used to create instructions, and so Block has functions for every cpu instruction - # and to make using the apu function easier, there are functions that create registers as well - class Block < Code - - def initialize(name , prog) - super() - @name = name.to_sym - @codes = [] - @position = 0 - @program = prog - end - attr_reader :name - - # length of the codes. In arm it would be the length * 4 - # (strings are stored globally in the Assembler) - def length - @codes.inject(0) {| sum , item | sum + item.length} - end - - def add_code(kode) - kode.at(@position) - length = kode.length - @position += length - @codes << kode - end - - def assemble(io) - @codes.each do |obj| - obj.assemble io - end - end - - # this is used to create blocks. - # All functions that have no args are interpreted as block names - # In fact the block calls are delegated to the program which then instantiates the blocks - def method_missing(meth, *args, &block) - if args.length == 0 - @program.send(meth , *args , &block) - else - super - end - end - - end - -end \ No newline at end of file diff --git a/lib/arm/call_instruction.rb b/lib/arm/call_instruction.rb index 1a1dd946..e2fdab47 100644 --- a/lib/arm/call_instruction.rb +++ b/lib/arm/call_instruction.rb @@ -35,6 +35,7 @@ module Arm case @opcode when :b, :bl arg = @args[0] + #puts "BLAB #{arg.inspect}" if( arg.is_a? Fixnum ) #HACK to not have to change the code just now arg = Arm::NumLiteral.new( arg ) end diff --git a/lib/arm/logic_instruction.rb b/lib/arm/logic_instruction.rb index c2b3795b..b6c0884d 100644 --- a/lib/arm/logic_instruction.rb +++ b/lib/arm/logic_instruction.rb @@ -17,7 +17,7 @@ module Arm #(stays in subclases, while build is overriden to provide different arguments) def do_build(arg) - if arg.is_a?(Arm::StringLiteral) + if arg.is_a?(Vm::StringLiteral) # do pc relative addressing with the difference to the instuction # 8 is for the funny pipeline adjustment (ie oc pointing to fetch and not execute) arg = Arm::NumLiteral.new( arg.position - self.position - 8 ) @@ -71,6 +71,7 @@ module Arm def assemble(io) build instuction_class = 0b00 # OPC_DATA_PROCESSING + puts inspect val = @operand.is_a?(Symbol) ? reg_code(@operand) : @operand val |= (reg_code(@rd) << 12) val |= (reg_code(@rn) << 12+4) diff --git a/lib/crystal.rb b/lib/crystal.rb index 7ef6a116..1eab46d5 100644 --- a/lib/crystal.rb +++ b/lib/crystal.rb @@ -1,8 +1,9 @@ require 'parslet' -require "arm/assembler" require "elf/object_writer" require 'parser/composed' require 'parser/transform' require "vm/context" require "vm/machine" +require "vm/program" +require "stream_reader" \ No newline at end of file diff --git a/lib/vm/block.rb b/lib/vm/block.rb index c391ab58..f4483648 100644 --- a/lib/vm/block.rb +++ b/lib/vm/block.rb @@ -34,7 +34,11 @@ module Vm end def add_code(kode) - @codes << kode + if( kode.is_a? Array ) + kode.each { |code| @codes << code } + else + @codes << kode + end self end diff --git a/lib/vm/code.rb b/lib/vm/code.rb index 85271cc1..b56830ad 100644 --- a/lib/vm/code.rb +++ b/lib/vm/code.rb @@ -13,7 +13,7 @@ module Vm # set the position to zero, will have to reset later def initialize - @address = 0 + @position = 0 end # the position in the stream. Think of it as an address if you want. The difference is small. @@ -21,19 +21,19 @@ module Vm # in other words, during assembly the position _must_ be resolved into a pc relative address # and not used as is def position - throw "Not set" unless @address - @address + throw "Not set" unless @position + @position end # The containing class (assembler/function) call this to tell the instruction/data where it is in the # stream. During assembly the position is then used to calculate pc relative addresses. def link_at address , context - @address = address + @position = address end # length for this code in bytes def length - raise "Not implemented #{self}" + raise "Not implemented #{inspect}" end # so currently the interface passes the io (usually string_io) in for the code to assemble itself. diff --git a/lib/vm/function.rb b/lib/vm/function.rb index ae6d1599..506ae359 100644 --- a/lib/vm/function.rb +++ b/lib/vm/function.rb @@ -24,16 +24,28 @@ module Vm @args.length end + def link_at address , context +# function = context.program.get_function(name) +# unless function +# function = Vm::Kernel.send(name) +# context.program.get_or_create_function( name , function , arity ) +# end + + @entry.link_at address , context + address += @entry.length + super(address , context) + address += @entry.length + @exit.link_at(address,context) + end + def length @entry.length + @exit.length + super end - def compiled context - function = context.program.get_function(name) - unless function - function = Vm::Kernel.send(name) - context.program.get_or_create_function( name , function , arity ) - end + def assemble io + @entry.assemble io + super(io) + @exit.assemble(io) end private diff --git a/lib/vm/kernel.rb b/lib/vm/kernel.rb index 4ba7ffbf..30587e74 100644 --- a/lib/vm/kernel.rb +++ b/lib/vm/kernel.rb @@ -5,7 +5,7 @@ module Vm Machine.instance.main_entry end def self.exit - # Machine.exit swi 0 + # Machine.exit mov r7 , 0 + swi 0 Machine.instance.main_exit end def self.puts string diff --git a/lib/arm/string_literal.rb b/lib/vm/string_literal.rb similarity index 98% rename from lib/arm/string_literal.rb rename to lib/vm/string_literal.rb index 04a0d908..704aecde 100644 --- a/lib/arm/string_literal.rb +++ b/lib/vm/string_literal.rb @@ -1,6 +1,6 @@ require "vm/code" -module Arm +module Vm # The name really says it all. # The only interesting thing is storage. # Currently string are stored "inline" , ie in the code segment. diff --git a/lib/vm/values.rb b/lib/vm/values.rb index 1cf76afd..5bd71d39 100644 --- a/lib/vm/values.rb +++ b/lib/vm/values.rb @@ -77,3 +77,4 @@ module Vm end end +require_relative "string_literal" \ No newline at end of file