diff --git a/README.md b/README.md index 851bc194..8b5f63a0 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Ie only in ruby code do i want to create machine code. Most instructions are in fact assembling correctly. Meaning i have tests, and i can use objbump to verify the correct assembler code is disasembled -I even polished the dsl an so (from the tests), this is a valid hello world: +I even polished the dsl and so (from the tests), this is a valid hello world: hello = "Hello World\n" @program.main do @@ -31,7 +31,7 @@ I even polished the dsl an so (from the tests), this is a valid hello world: Package the code into an executable. Run that and verify it's output. But full elf support (including externs) is eluding me for now. Still, this has proven to be a good review point for the arcitecture and means no libc for now. -Full rationale on the web (pages rep for now), but it means starting an extra step +Full rationale on the web pages, but it means starting an extra step. Above Hello World can be linked and run. And will say its thing. @@ -46,43 +46,20 @@ Parse simple code, using Parslet. Parsing is a surprisingly fiddly process, very space and order sensitive. But Parslet is great and simple expressions (including function definitions and calls) are starting to work. -I Spent some time on the parse testing framework, so it is safe to fiddle and add. +I spent some time on the parse testing framework, so it is safe to fiddle and add. -### Step 5 - Vm: Compile the Ast +### Step 5 - Virtual: Compile the Ast -Since we now have an Abstact syntax tree, it needs to be compiled to a machine Instruction format. +Since we now have an Abstact syntax tree, it needs to be compiled to a virtual machine Instruction format. -The machine/instruction/data definitions make up the Virtual Machine layer (vm directory) +It took me a while to come up with a decent but simple machine model. I had tried to map straight to hardware +but failed. The current Virtual directory represent a machine with basic oo features. -After some trying around, something has emerged. As it uses the instructions from Step 1, we are ready to say -our hellos in ruby +Instead of having more Layers to go from virtual to arm, i opted to have passes that go over the data structure +and modify it. -puts("Hello World") +This is where it's at really :-) -was the first to make the trip: parsed to ast, compiled to Instructions/Code, linked and assembled to binary -and executed, gives the surprising output of "Hello World" - -Time to add some meat. - -### Step 6 - Register allocation - -A first version of register allocation is done. I moved away from the standard c calling convention to pin a -type register and also not have passing and return overlapping. -That at least simplified thinking about register allocation. One has to remember the machine level is completely -value and pass by value based. - -As a side i got a return statement done now, and implicit return at the end has been working. Just making sure all -branches actually return implicitly is not done. But no rush there, as one can always write the return explicitly. - -### Step 7 - Basic type instructions - -As we want to work on values, all the value methods have to be implemented to map to machine instructions. - -Some are done, most are not. But they are straightforward. - -### Step 8 - Object creation - -Move to objects, static memory manager, class, superclass, metaclass stuff ### Step 9 - Compound types diff --git a/lib/kernel/README.md b/lib/kernel/README.md index cf154c21..008c41c3 100644 --- a/lib/kernel/README.md +++ b/lib/kernel/README.md @@ -2,7 +2,7 @@ As of writing Kernel is an "old style" module, aka a bunch of functions. -These functions return their code, ie a Vm::Function object, which can then be called by ruby code as if it were a "normal" +These functions return their code, ie a Register::Function object, which can then be called by ruby code as if it were a "normal" function. A normal ruby function is one that is parsed and transformed to code. But not all functionality can be written in ruby, diff --git a/lib/register/instruction.rb b/lib/register/instruction.rb index 2fa2df93..9b6326ed 100644 --- a/lib/register/instruction.rb +++ b/lib/register/instruction.rb @@ -1,15 +1,7 @@ require_relative "code" module Register - # Because the idea of what one instruction does, does not always map one to one to real machine - # instructions, and instruction may link to another instruction thus creating an arbitrary list - # to get the job (the original instruciton) done - - # Admittately it would be simpler just to create the (abstract) instructions and let the machine - # encode them into what-ever is neccessary, but this approach leaves more possibility to - # optimize the actual instruction stream (not just the salama instruction stream). Makes sense? - - # We have basic classes (literally) of instructions + # The register machine model is close to current hardware and has following instruction classes # - Memory # - Stack # - Logic diff --git a/lib/register/integer.rb b/lib/register/integer.rb index e0a47c45..2ba4aeb4 100644 --- a/lib/register/integer.rb +++ b/lib/register/integer.rb @@ -7,19 +7,19 @@ module Register def less_or_equal block , right block.cmp( self , right ) - Vm::BranchCondition.new :le + Register::BranchCondition.new :le end def greater_or_equal block , right block.cmp( self , right ) - Vm::BranchCondition.new :ge + Register::BranchCondition.new :ge end def greater_than block , right block.cmp( self , right ) - Vm::BranchCondition.new :gt + Register::BranchCondition.new :gt end def less_than block , right block.cmp( self , right ) - Vm::BranchCondition.new :lt + Register::BranchCondition.new :lt end def plus block , first , right block.add( self , left , right ) @@ -35,12 +35,12 @@ module Register end def equals block , right block.cmp( self , right ) - Vm::BranchCondition.new :eq + Register::BranchCondition.new :eq end def is_true? function function.cmp( self , 0 ) - Vm::BranchCondition.new :ne + Register::BranchCondition.new :ne end def move block , right diff --git a/lib/register/register_machine.rb b/lib/register/register_machine.rb index 934d41f1..af4c7aa4 100644 --- a/lib/register/register_machine.rb +++ b/lib/register/register_machine.rb @@ -85,7 +85,7 @@ module Register c_name = clazz.name my_module = self.class.name.split("::").first clazz_name = clazz.name.split("::").last - if(my_module != Vm ) + if(my_module != Register ) module_class = eval("#{my_module}::#{clazz_name}") rescue nil clazz = module_class if module_class end @@ -94,11 +94,11 @@ module Register private #defining the instruction (opcode, symbol) as an given class. - # the class is a Vm::Instruction derived base class and to create machine specific function + # the class is a Register::Instruction derived base class and to create machine specific function # an actual machine must create derived classes (from this base class) # These instruction classes must follow a naming pattern and take a hash in the contructor - # Example, a mov() opcode instantiates a Vm::MoveInstruction - # for an Arm machine, a class Arm::MoveInstruction < Vm::MoveInstruction exists, and it will + # Example, a mov() opcode instantiates a Register::MoveInstruction + # for an Arm machine, a class Arm::MoveInstruction < Register::MoveInstruction exists, and it will # be used to define the mov on an arm machine. # This methods picks up that derived class and calls a define_instruction methods that can # be overriden in subclasses @@ -108,7 +108,7 @@ module Register options = {} if options == nil options.merge defaults options[:opcode] = inst - first = Vm::Integer.new(first) if first.is_a? Symbol + first = Register::Integer.new(first) if first.is_a? Symbol clazz.new(first , options) end end @@ -119,8 +119,8 @@ module Register create_method(inst) do |left ,right , options = nil| options = {} if options == nil options.merge defaults - left = Vm::Integer.new(left) if left.is_a? Symbol - right = Vm::Integer.new(right) if right.is_a? Symbol + left = Register::Integer.new(left) if left.is_a? Symbol + right = Register::Integer.new(right) if right.is_a? Symbol options[:opcode] = inst clazz.new(left , right ,options) end @@ -133,9 +133,9 @@ module Register options = {} if options == nil options.merge defaults options[:opcode] = inst - result = Vm::Integer.new(result) if result.is_a? Symbol - left = Vm::Integer.new(left) if left.is_a? Symbol - right = Vm::Integer.new(right) if right.is_a? Symbol + result = Register::Integer.new(result) if result.is_a? Symbol + left = Register::Integer.new(left) if left.is_a? Symbol + right = Register::Integer.new(right) if right.is_a? Symbol clazz.new(result, left , right ,options) end end diff --git a/lib/register/transformations.rb b/lib/register/transformations.rb new file mode 100644 index 00000000..1721572b --- /dev/null +++ b/lib/register/transformations.rb @@ -0,0 +1,3 @@ +module Register + +end diff --git a/lib/virtual/method_definition.rb b/lib/virtual/method_definition.rb index 3043f576..948d8196 100644 --- a/lib/virtual/method_definition.rb +++ b/lib/virtual/method_definition.rb @@ -65,7 +65,7 @@ module Virtual def locals_at l_block used =[] # call assigns the return register, but as it is in l_block, it is not asked. - assigned = [ RegisterReference.new(Vm::RegisterMachine.instance.return_register) ] + assigned = [ RegisterReference.new(Register::RegisterMachine.instance.return_register) ] l_block.reachable.each do |b| b.uses.each {|u| (used << u) unless assigned.include?(u) diff --git a/lib/virtual/plock.rb b/lib/virtual/plock.rb index 7a663047..103b15df 100644 --- a/lib/virtual/plock.rb +++ b/lib/virtual/plock.rb @@ -30,7 +30,7 @@ module Virtual # Data gets assembled after methods def add_data o return if @objects.include? o - raise "must be derived from Code #{o.inspect}" unless o.is_a? Vm::Code + raise "must be derived from Code #{o.inspect}" unless o.is_a? Register::Code @data << o # TODO check type , no basic values allowed (must be wrapped) end diff --git a/test/fragments/test_while_fibo.rb b/test/fragments/test_while_fibo.rb index 09dbd621..55790289 100644 --- a/test/fragments/test_while_fibo.rb +++ b/test/fragments/test_while_fibo.rb @@ -30,12 +30,12 @@ HERE # a hand coded version of the fibonachi numbers (moved to kernel to be able to call it) # not my hand off course, found in the net from a basic introduction def test_kernel_fibo - int = Vm::Integer.new(Vm::RegisterMachine.instance.receiver_register) + int = Register::Integer.new(Register::RegisterMachine.instance.receiver_register) fibo = @object_space.get_or_create_class(:Object).resolve_function(:fibo) main = @object_space.main main.mov int , 10 main.call( fibo ) - main.mov( Vm::RegisterMachine.instance.receiver_register , Vm::RegisterMachine.instance.return_register ) + main.mov( Register::RegisterMachine.instance.receiver_register , Register::RegisterMachine.instance.return_register ) putint = @object_space.get_or_create_class(:Object).resolve_function(:putint) main.call( putint ) @should = [0x0,0x40,0x2d,0xe9,0x1,0x0,0x52,0xe3,0x2,0x0,0xa0,0xd1,0x7,0x0,0x0,0xda,0x1,0x30,0xa0,0xe3,0x0,0x40,0xa0,0xe3,0x4,0x30,0x83,0xe0,0x4,0x40,0x43,0xe0,0x1,0x20,0x42,0xe2,0x1,0x0,0x52,0xe3,0xfa,0xff,0xff,0x1a,0x3,0x0,0xa0,0xe1,0x0,0x80,0xbd,0xe8] diff --git a/test/test_runner.rb b/test/test_runner.rb index 918e1ca4..8ae198d8 100644 --- a/test/test_runner.rb +++ b/test/test_runner.rb @@ -20,7 +20,7 @@ class TestRunner < MiniTest::Test def execute file string = File.read(file) parser = Parser::Salama.new - object_space = Vm::Program.new "Arm" + object_space = Register::Program.new "Arm" syntax = parser.parse_with_debug(string) assert syntax parts = Parser::Transform.new.apply(syntax) @@ -31,7 +31,7 @@ class TestRunner < MiniTest::Test expr = part.compile( program.context ) else expr = part.compile( program.context ) - raise "should be function definition for now" unless expr.is_a? Vm::Function + raise "should be function definition for now" unless expr.is_a? Register::Function end end