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
===============
================
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
plain ones in this directory don't assemble to binary). Currently there is only the Arm module to actually do
that.
Our primary objective is to compile Phisol to this level, so the register machine has:
- object access instructions
- 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 objects that will be in the executable. Other than MethodSource, objects get transformed to data.
All data is in objects.
But MethodSource, which are made up of Blocks, are compiled into a stream of bytes,
which are the binary code for the function.
The register machine is aware of Parfait objects, and specifically uses Message and Frame to
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
- Message (arguments, method name, self)
- Frame (local and tmp variables)
- NewMessage ( to build the next message sent)
There is no stack, rather messages form a linked list, and preparing to call, the data is pre-filled
into the next message. Calling then means moving the new message to the current one and jumping
to the address of the method. Returning is the somewhat reverse process.
These are pretty much the first four registers. When the code goes from virtual to register,
we use register instructions to replace virtual ones.
Syscalls are implemented by *one* Syscall instruction. The Register machine does not specify/limit
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.
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.
Interpreter
===========
Another simple example is a Call. A simple case of a Class function call resolves the class object,
and with the method name the function to be found at compile-time.
And so this results in a Register::Call, which is an Arm instruction.
There is an interpreter that can interpret compiled register machine programs.
This is very handy for debugging (an nothing else).
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.
This is not at all as simple as the nice Class call described above.
Arm / Elf
=========
For syscall in Arm (linux) you have to load registers 0-x (depending on call), load R7 with the
syscall number and then issue the software interupt instruction.
If you get back something back, it's in R0.
There is also a (very strightforward) transformation to arm instructions.
Together with the also quite minimal elf module, arm binaries can be produced.
In short, lots of shuffling. And to make it fit with our four object architecture,
we need the Message to hold the data for the call and Sys (module) to be self.
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)
These binaries have no external dependencies and in fact can not even call c at the moment
(only syscalls :-)).

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