I'm working on an implementation of the lc3 -vm (
https://justinmeiners.github.io/lc3-vm/ ).

This a basic didactical architecture.

In the code, I have a TUPLE: that is used to keep the state of the vm.

TUPLE: lc3 { ram array } { registers array } { pc integer } { cond
> bit-array } ;
>

An instance of this TUPLE is passed around by some of the code to execute
instructions and change the internal state.

Instructions are coded as 16bit values where the highest 4 bits represent
an op-code that identifies the instruction to execute and the rest of the
bits contain informations about the necessary data to execute it.
In my code I'm using a map of pairs to dispatch to the correct ( quotated-
) words depending on the opcode.

CONSTANT: OPCODE_MAP H{
> { 0 { [ parse-br ] [ eval-br ] } }
> { 1 "add" }
> { 2 "ld" }
> { 3 "st" }
> { 4 "jsr" }
> { 5 "and" }
> { 6 "ldr" }
> { 7 "str" }
> { 8 "rti" }
> { 9 "not" }
> { 10 "ldi" }
> { 11 "sti" }
> { 12 "jmp" }
> { 14 "lea" }
> { 15 "trap" }
> }
>
> : parser-evaluator ( opcode -- parser evaluator )
> OPCODE_MAP at [ first ] [ second ] bi ;
>

The strings are there as temporary values that I still have to build.

Not all instructions encode informations in the same way. Some of them may
include 4 pieces of informations of different width and type and some
others may contain more or less of them.
To correctly retrieve informations and to execute the correct instruction
I'm using those parser-evaluator pairs.

All parsers, which cut instructions into the correct pieces of
informations, expects the stack to have an instruction at its top to
consume while pushing a variable number of values in its place.
All evaluators, which actually execute the given instruction modifying the
state of an lc3,  expects n values on the stack to consume and will
push-out a modified lc3.

Now, those parser-evaluator pairs are call( [ed] at runtime.
After many tries, I was able to construct a piece of code that would
compile ( Stack-effects are not completely clear to me yet ).
Unfortunately, when a parser-evaluator pair is actually called the program
will stop as the expressed stack effect of call( is considered incorrect.

: _eval ( lc3 parser: ( instruction -- ..a ) evaluator: ( ..a -- lc3 ) --
> lc3 )
> [ call( instruction -- ..a ) ] [ call( ..a -- lc3 ) ] bi* ; inline
>

(U) Quotation: [ set-namestack init-catchstack self quot>> call => stop ]
> (O) Word: listener-thread
> (O) Word: listener
> (O) Word: (listener)
> (O) Word: listener-step
> (U) Quotation: [
>         [ ~quotation~ dip swap ~quotation~ dip ] dip swap
>         [ call get-datastack ] dip => swap [ set-datastack ] dip
>     ]
> (U) Quotation: [ call => get-datastack ]
> (O) Word: eval
> (O) Word: wrong-values
> (O) Method: M\ object throw
> (U) Quotation: [
>         OBJ-CURRENT-THREAD special-object error-thread set-global
>         current-continuation => error-continuation set-global
>         [ original-error set-global ] [ rethrow ] bi
>     ]
>

After some tries, I'm at a kind of roadblock that I seem unable to untangle.
How can I express, if at all possible, this kind of polymorphism in factor
? What are some alternative ways to produce the same effect ?

For reference this is the relevant code:

USING: lc3-vm.core.lc3.private lc3-vm.core.lc3 sequences bit-arrays locals
> kernel assocs ;
> IN: lc3-vm.core.instructions
>
> <PRIVATE
>
> CONSTANT: OPCODE_LENGHT 4
>
> : instruction>opcode ( instruction -- instruction opcode )
> OPCODE_LENGHT cut* bit-array>integer ;
>
> : parse-br ( instruction -- n z p offset )
> 1 cut 1 cut 1 cut [ [ first ] tri@ ] dip bit-array>integer ;
>
> : n-and-cond-n? ( lc3 n -- ? )
> [ cond-n? ] dip and ;
>
> : z-and-cond-z? ( lc3 z -- ? )
> [ cond-z? ] dip and ;
>
> : p-and-cond-p? ( lc3 p -- ? )
> [ cond-p? ] dip and ;
>
> :: br-should-jump ( lc3 n z p -- ? )
> lc3 n n-and-cond-n? lc3 z z-and-cond-z? lc3 p p-and-cond-p? or or ;
>
> :: eval-br ( lc3 n z p offset -- lc3 )
> lc3 n z p br-should-jump [ lc3 offset jump-by ] [ lc3 ] if ;
>
> CONSTANT: OPCODE_MAP H{
> { 0 { [ parse-br ] [ eval-br ] } }
> { 1 "add" }
> { 2 "ld" }
> { 3 "st" }
> { 4 "jsr" }
> { 5 "and" }
> { 6 "ldr" }
> { 7 "str" }
> { 8 "rti" }
> { 9 "not" }
> { 10 "ldi" }
> { 11 "sti" }
> { 12 "jmp" }
> { 14 "lea" }
> { 15 "trap" }
> }
>
> : parser-evaluator ( opcode -- parser evaluator )
> OPCODE_MAP at [ first ] [ second ] bi ;
>
>
> : _eval ( lc3 parser: ( instruction -- ..a ) evaluator: ( ..a -- lc3 ) --
> lc3 )
> [ call( instruction -- ..a ) ] [ call( ..a -- lc3 ) ] bi* ; inline
>
> PRIVATE>
>
> ALIAS: instruction 16bit
>
> : eval ( instruction -- lc3 )
> instruction>opcode parser-evaluator _eval ;
>

A preemptive thanks to anyone who will take the time to help me get a
better understanding of this issue.

Best Regards,
Di Sera Luca
_______________________________________________
Factor-talk mailing list
Factor-talk@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/factor-talk

Reply via email to