Wednesday, July 18, 2007

Asm-generator continued...

I decided to integrate assembler generator with standard smalltalk parser/compiler, so devs can use common tools to submit asm-code.

To indicate that method source contains assembler source, just put <assembler> pragma in its source body. This activates an asm-parser, and if parser found errors, it shows them in same manner, as smalltalk parser - by inserting error message at corresponding place in edit buffer.

The one good reason, why i decided to integrate parser with system browser is for automation:
- when you submitting asm code, its parsed, compiled and ready for execution by registering it with Exupery. So, in most cases, you don't need to make any extra moves - just edit and submit.
- if method have inline calls to other methods, they automatically parsed (if was not parsed before) to include in compiled code.
- when you submitting new source for method, which was inlined in other methods, this automatically causes to recompile them using new code.

So, after successful submission, new versions of native methods automatically get used (if they already was).

I also decided to slightly modify syntax of asm-code.

Changed flow control syntax.

Now, instead of smalltalk-like flow control, which implies to use blocks, you have labels and jumps.

So, instead of writing something like:

ifZero: [ ... ]

you placing a label in code:

self label: #somelabel.

then from at other point in code you placing jumps on it:

self jump: #somelabel.

or

self jumpCarry: #somelabel.

Labels and jumps must be the outermost messages (can't be passed as arguments to other messages).
Writing something like:

a := b + (self label: #somelabel).


is not an error in smalltalk, but error in assembler.

Later i'll add support for calls on label
( self call: #somelabel )
so, you can write methods like:

....
self call: #somelabel
....
....
self return: result.
self label: #somelabel
result := 1.
self ret.

loading address of label in register ( a := #somelabel),
and indirect jumps/calls: self call: a

global labels:

method1

self globalLabel: #globalOne
self ret.

--
method2
^ self call: #globalOne

jump tables :

self jumpTable: #table1 with: #(
#label1
#label2
#label3
)

....

addr := (#table1 + index) loadDword.
self jump: addr.

or maybe like this:
self jump: (#table1 at: index)

global data storage :

self dataDWord: #mydwords size: 10.

a:= (#mydwords + 5) loadDWord.


accessing VM values:

a:= self VMAddr: #someName

or just:

a := #someName

or

self call: #someVmFunction

i didn't decided yet, mix VM global names with own global labels/data or not.
Maybe someone have some better ideas?

No comments: