bit of cleaning, updated readme

This commit is contained in:
Torsten Ruger 2015-10-22 17:38:49 +03:00
parent c68577c3f4
commit f658ecf425
5 changed files with 33 additions and 89 deletions

View File

@ -1,50 +1,48 @@
Register Machine Register Machine
=============== ================
This is the logic that uses the compiled virtual object space to produce code and an executable binary. The RegisterMachine, is an abstract machine with registers. Think of it as an arm machine with
normal instruction names. It is not however an abstraction of existing hardware, but only
of that subset that we need.
There is a mechanism for an actual machine (derived class) to generate harware specific instructions (as the Our primary objective is to compile Phisol to this level, so the register machine has:
plain ones in this directory don't assemble to binary). Currently there is only the Arm module to actually do - object access instructions
that. - object load
- object oriented call semantics
- extended (and extensible) branching
- normal integer operators (but no sub word instructions)
The elf module is used to generate the actual binary from the final Space. Space is a virtual class representing All data is in objects.
all objects that will be in the executable. Other than MethodSource, objects get transformed to data.
But MethodSource, which are made up of Blocks, are compiled into a stream of bytes, The register machine is aware of Parfait objects, and specifically uses Message and Frame to
which are the binary code for the function. express call semantics.
Virtual Objects Calls and syscalls
---------------- ------------------
There are four virtual objects that are accessible (we can access their variables): The RegisterMachine only uses 1 fixed register, the currently worked on Message.
- Self There is no stack, rather messages form a linked list, and preparing to call, the data is pre-filled
- Message (arguments, method name, self) into the next message. Calling then means moving the new message to the current one and jumping
- Frame (local and tmp variables) to the address of the method. Returning is the somewhat reverse process.
- NewMessage ( to build the next message sent)
These are pretty much the first four registers. When the code goes from virtual to register, Syscalls are implemented by *one* Syscall instruction. The Register machine does not specify/limit
we use register instructions to replace virtual ones. the meaning or number of syscalls. This is implemented by the level below, eg the arm/interpreter.
Eg: A Virtual::Set can move data around inside those objects. Interpreter
And since in Arm this can not be done in one instruction, we use two, one to move to an unused register ===========
and then into the destination. And then we need some fiddling of bits to shift the type info.
Another simple example is a Call. A simple case of a Class function call resolves the class object, There is an interpreter that can interpret compiled register machine programs.
and with the method name the function to be found at compile-time. This is very handy for debugging (an nothing else).
And so this results in a Register::Call, which is an Arm instruction.
A C call Even more handy is the graphical interface for the interpreter, which is in it's own repository:
--------- salama-debugger.
Ok, there are no c calls. But syscalls are very similar. Arm / Elf
This is not at all as simple as the nice Class call described above. =========
For syscall in Arm (linux) you have to load registers 0-x (depending on call), load R7 with the There is also a (very strightforward) transformation to arm instructions.
syscall number and then issue the software interupt instruction. Together with the also quite minimal elf module, arm binaries can be produced.
If you get back something back, it's in R0.
In short, lots of shuffling. And to make it fit with our four object architecture, These binaries have no external dependencies and in fact can not even call c at the moment
we need the Message to hold the data for the call and Sys (module) to be self. (only syscalls :-)).
And then the actual functions do the shuffle, saving the data and restoring it.
And setting type information according to kernel documentation (as there is no runtime info)

View File

@ -1,51 +0,0 @@
module Register
class UnusedAndAbandonedInteger < Word
# needs to be here as Word's constructor is private (to make it abstract)
def initialize reg
super
end
def less_or_equal block , right
block.cmp( self , right )
Register::BranchCondition.new :le
end
def greater_or_equal block , right
block.cmp( self , right )
Register::BranchCondition.new :ge
end
def greater_than block , right
block.cmp( self , right )
Register::BranchCondition.new :gt
end
def less_than block , right
block.cmp( self , right )
Register::BranchCondition.new :lt
end
def plus block , first , right
block.add( self , left , right )
self
end
def minus block , left , right
block.sub( self , left , right )
self
end
def left_shift block , left , right
block.mov( self , left , shift_lsr: right )
self
end
def equals block , right
block.cmp( self , right )
Register::BranchCondition.new :eq
end
def is_true? function
function.cmp( self , 0 )
Register::BranchCondition.new :ne
end
def move block , right
block.mov( self , right )
self
end
end
end

View File

@ -1,3 +0,0 @@
module Register
end