bit of documentation

This commit is contained in:
Torsten Ruger 2018-08-14 11:23:19 +03:00
parent fb54d68020
commit 0bf008b351
6 changed files with 88 additions and 45 deletions

View File

@ -14,9 +14,12 @@ of the system, see below. The overhaul is done and rubyx produces working binari
Processing goes through layers: Ruby --> Vool --> Mom --> Risc --> Arm --> binary .
Currently most functional constructs work to some (usable) degree, ie if, while,
assignment, ivars, calling and dynamic dispatch all work. Work continues
on blocks currently, see below.
Currently most basic constructs work to some (usable) degree, ie if, while,
assignment, ivars, calling and dynamic dispatch all work. Simple blocks, those
that ruby passes implicitly also work (lambdas not).
Work continues on memory management, which turns out to be pretty basic to do just about
anything, even counting to a million.
## Layers
@ -149,38 +152,22 @@ Specifically here is a list of what works:
- assignment (local/args/ivar)
- static calling (where method is determined at compile time)
- dynamic dispatch with caching
- implicit blocks, ie the ones that ruby passes implicitly and are used in enumerating
Current work is on implicit blocks, which are surprisingly like static method calls
and lambdas like dynamic dispatch.
## Contributing to rubyx
Probably best to talk to me, if it's not a typo or so.
There is a todo, for inspiration, though actual tasks that result in pulls, should start
their live as a github issue. There we can discuss details so that no work is done
in vain. There are some small issues there already, just comment if you're interested.
I've started to put some github issues out, some basic some not so. Also there is a todo
for the adventurous (bigger things, no BIG things).
Actual tasks that result in pulls, should start their life as a github issue.
There we can discuss details so that no work is done
in vain. If you're interested in an existing issues, just comment on it.
Fork and create a branch before sending pulls.
### Stary sky
Iterate:
1. more cpus (ie intel)
2. more systems (ie mac)
3. more syscalls, there are after all some hundreds
5. A lot of modern cpu's functionality has to be mapped to ruby and implemented in assembler to be useful
6. Different sized machines, with different register types ?
7. on 64bit, there would be 8 bits for types and thus allow for rational, complex, and whatnot
8. Housekeeping (the superset of gc) is abundant
9. Any amount of time could be spent on a decent digital tree (see judy). Or possibly Dr.Cliffs hash.
10. Also better string/arrays would be good.
11. The minor point of threads and hopefully lock free primitives to deal with that.
12. Other languages, python at least, maybe others
And generally optimise and work towards that perfect world (we never seem to be able to attain).
## Copyright
Copyright (c) 2014-8 Torsten Ruger.

35
ToDo.md
View File

@ -10,8 +10,7 @@ Some things that would be nice . .
- utf8 support (string improvements generally)
Platforms
---------
## Platforms
x86 is up for grabs. I have intentionally started on arm (the most sold cpu) because i do
this for fun. And my pi is fun.
@ -19,24 +18,40 @@ this for fun. And my pi is fun.
There is a ruby intel assembler called wilson out there. Or then there is Metasm, with
good support for many other cpu's (and a lot more code)
Compliance
----------
## Compliance
Is admittedly a little more fun, but also not really my goal in the near future.
Is admittedly a little more fun, but also not really my personal goal in the near future.
If i am really honest about this, i think ruby is a little quirky around the edges and i
think a lot of that can/should be done as a compatibility layer. Keeping the core clean (and shiny).
Stdlib
------
## Stdlib
Stdlib is not clean. More like a layer that accumulated over the years.
Very nice solutions exist for most of the important things. Like celluloid for concurrency. Celluloid-io for
Very nice solutions exist for most of the important things.
Like celluloid for concurrency. Celluloid-io for
good performance io with or without zero-mq. Fiddle looks nice admittedly.
Interesting
-----------
## Concurrency
Solving concurrency is up for grabs. Any solution is a start, channels ala go are nice and
lock free stuff is the ultimate goal.
## Stary sky
Iterate:
1. more cpus (ie intel)
2. more systems (ie mac)
3. more syscalls, there are after all some hundreds (most as external gems)
5. A lot of modern cpu's functionality has to be mapped to ruby and implemented in assembler to be useful
6. Different sized machines, with different register types ?
7. on 64bit, there would be 8 bits for types and thus allow for rational, complex, and whatnot
8. Housekeeping (the superset of gc) is abundant
9. Any amount of time could be spent on a decent digital tree (see judy). Or possibly Dr.Cliffs hash.
10. Also better string/arrays would be good.
11. The minor point of threads and hopefully lock free primitives to deal with that.
12. Other languages, python at least, maybe others
And generally optimise and work towards that perfect world (we never seem to be able to attain).

View File

@ -1,10 +1,16 @@
#integer related kernel functions
module Risc
module Builtin
# integer related kernel functions
# all these functions (return the functione they implement) assume interger input
#
# This means they will have to be renamed at some point and wrapped
module Integer
module ClassMethods
include CompileHelper
# div by 4, ie shift two left
# Mostly created for testing at this point, as it is short
# return new int with result
def div4(context)
compiler = compiler_for(:Integer,:div4 ,{})
compiler.compiler_builder(compiler.source).build do
@ -18,18 +24,30 @@ module Risc
compiler.add_mom( Mom::ReturnSequence.new)
return compiler
end
# implemented by the comparison
def >( context )
comparison( :> )
end
# implemented by the comparison
def <( context )
comparison( :< )
end
# implemented by the comparison
def <=( context )
comparison( :<= )
end
# implemented by the comparison
def >=( context )
comparison( :>= )
end
# all (four) comparison operation are quite similar and implemented here
# - reduce the ints (assume int as input)
# - subtract the fixnums
# - check for minus ( < and > )
# - also check for zero (<= and >=)
# - load true or false object into return, depending on check
# - return
def comparison( operator )
compiler = compiler_for(:Integer, operator ,{other: :Integer})
builder = compiler.compiler_builder(compiler.source)
@ -54,11 +72,19 @@ module Risc
return compiler
end
# not implemented, would need a itos and that needs "new" (wip)
def putint(context)
compiler = compiler_for(:Integer,:putint ,{})
compiler.add_mom( Mom::ReturnSequence.new)
return compiler
end
# implemented all known binary operators that map straight to machine codes
# this function (similar to comparison):
# - unpacks the intergers to fixnum
# - applies the operator (at a risc level)
# - gets a new integer and stores the result
# - returns the new int
def operator_method( op_sym )
compiler = compiler_for(:Integer, op_sym ,{other: :Integer})
builder = compiler.compiler_builder(compiler.source)
@ -76,6 +102,7 @@ module Risc
return compiler
end
# old helper function for div10 (which doesn't use builder yet)
def add_receiver(builder)
message = Risc.message_reg
ret_type = builder.compiler.receiver_type

View File

@ -6,7 +6,6 @@ module Risc
# self[index] basically. Index is the first arg
# return is stored in return_value
# (this method returns a new method off course, like all builtin)
def get_internal_word( context )
compiler = compiler_for(:Object , :get_internal_word ,{at: :Integer})
compiler.compiler_builder(compiler.source).build do
@ -22,7 +21,7 @@ module Risc
end
# self[index] = val basically. Index is the first arg , value the second
# no return
# return the value passed in
def set_internal_word( context )
compiler = compiler_for(:Object , :set_internal_word , {at: :Integer, :value => :Object} )
compiler.compiler_builder(compiler.source).build do
@ -48,8 +47,11 @@ module Risc
# 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
def __init__ context
# so it is responsible for initial setup:
# - load fist message, set up Space as receiver
# - call main, ie set up message for that etc
# - exit (exit_sequence) which passes a machine int out to c
def __init__( context )
compiler = MethodCompiler.compiler_for_class(:Object,:__init__ ,
Parfait::NamedList.type_for({}) , Parfait::NamedList.type_for({}))
builder = compiler.compiler_builder(compiler.source)
@ -82,6 +84,7 @@ module Risc
# a sort of inline version of exit method.
# Used by exit and __init__ (so it doesn't have to call it)
# Assumes int return value and extracts the fixnum for process exit code
def exit_sequence(builder)
save_message( builder )
message = Risc.message_reg
@ -90,6 +93,8 @@ module Risc
builder.add_code Syscall.new("emit_syscall(exit)", :exit )
end
# the exit function
# mainly calls exit_sequence
def exit( context )
compiler = compiler_for(:Object,:exit ,{})
builder = compiler.compiler_builder(compiler.source)
@ -97,6 +102,8 @@ module Risc
return compiler
end
# emit the syscall with given name
# there is a Syscall instruction, but the message has to be saved and restored
def emit_syscall( builder , name )
save_message( builder )
builder.add_code Syscall.new("emit_syscall(#{name})", name )
@ -114,6 +121,9 @@ module Risc
builder.add_transfer("save_message", Risc.message_reg , r8 )
end
# restore the message that we save in r8
# get a new int and save the c return into it
# tht int gets retured, ie is the return_value of the message
def restore_message(builder)
r8 = RegisterValue.new( :r8 , :Message)
int = builder.compiler.use_reg(:Integer)

View File

@ -1,4 +1,3 @@
module Risc
module Builtin
class Space

View File

@ -4,6 +4,12 @@ module Risc
module ClassMethods
include CompileHelper
# wrapper for the syscall
# io/file currently hardcoded to stdout
# set up registers for syscall, ie
# - pointer in r1
# - length in r2
# - emit_syscall (which does the return of an integer, see there)
def putstring( context)
compiler = compiler_for(:Word , :putstring ,{})
builder = compiler.compiler_builder(compiler.source)
@ -18,7 +24,7 @@ module Risc
end
# self[index] basically. Index is the first arg > 0
# return (and word sized int) is stored in return_value
# return a word sized new int, in return_value
def get_internal_byte( context)
compiler = compiler_for(:Word , :get_internal_byte , {at: :Integer})
compiler.compiler_builder(compiler.source).build do
@ -30,14 +36,13 @@ module Risc
add_new_int("get_internal_byte", object , integer)
message[:return_value] << integer
end
compiler.add_mom( Mom::ReturnSequence.new)
return compiler
end
# self[index] = val basically. Index is the first arg ( >0),
# value the second
# return self
# return value
def set_internal_byte( context )
compiler = compiler_for(:Word, :set_internal_byte , {at: :Integer , :value => :Integer} )
compiler.compiler_builder(compiler.source).build do