examples: add muri-with-hex.retro (#37)

FossilOrigin-Name: 049c678e5f76769e9768e1fdbdf3437be3dc014275ba01752996ea8c77794898
This commit is contained in:
crc 2021-01-06 16:15:38 +00:00
parent da436a5ef5
commit 9e9903eee6
2 changed files with 164 additions and 0 deletions

View file

@ -37,6 +37,7 @@
* retro-amalgamate.py added to generate a single file Python source
* faster retro-extend.py
* added retro-embedimage.py
----
@ -65,5 +66,6 @@
* added "2020 Advent of Code", days 1-5
* added palindromic numbers detection (SVFIG challenge)
* added bindings over curl
* added muri with direct use of hex values
* refactoring & general cleanups in Atua-WWW
* Atua-WWW now ignores ?... appended to URLs

162
example/muri-with-hex.retro Normal file
View file

@ -0,0 +1,162 @@
# Muri, Extended
Muri is my minimalist assembler for Nga. Using it requires
some knowledge of the Nga architecture to be useful.
Nga has 30 instructions. These are:
0 nop 5 push 10 ret 15 fetch 20 div 25 zret
1 lit 6 pop 11 eq 16 store 21 and 26 halt
2 dup 7 jump 12 neq 17 add 22 or 27 ienum
3 drop 8 call 13 lt 18 sub 23 xor 28 iquery
4 swap 9 ccall 14 gt 19 mul 24 shift 29 iinvoke
The mnemonics allow for each name to be reduced to just two
characters. In the same order as above:
0 .. 5 pu 10 re 15 fe 20 di 25 zr
1 li 6 po 11 eq 16 st 21 an 26 ha
2 du 7 ju 12 ne 17 ad 22 or 27 ie
3 dr 8 ca 13 lt 18 su 23 xo 28 iq
4 sw 9 cc 14 gt 19 mu 24 sh 29 ii
Up to four instructions can be packed into a single memory
location. (You can only use *no*p after a *ju*mp, *ca*ll,
*cc*all, *re*t, or *zr*et as these alter the instruction
pointer.)
So a bundled sequence like:
lit 100
lit 200
add
ret
Would look like:
'liliadre i
100 d
200 d
And:
lit s:eq?
call
Would become:
'lica.... i
's:eq? r
Note the use of `..` instead of `no` for the nop's; this is
done to improve readability a little.
Instruction bundles are specified as strings, and are converted
to actual instructions by the `i` word. As in the standard Muri
assembler, the RETRO version uses `d` for decimal values and `r`
for references to named functions.
----
This implements an extended version of `i`, the instruction
assembler. It allows for use of hex constants (in uppercase)
in place of (or in addition to) the instruction names. This can
be useful if you are running on a VM with an extended instruction
set.
When loaded, it will *replace* the original `i` with a jump to
the one provided here, allowing existing words (like `prefix:\`)
to use this instead.
----
I'm keeping everything in a private namespace to keep the final
dictionary clean.
~~~
{{
~~~
It begins with an array of instruction names. The index matches
the opcode, so these must be in order.
~~~
{ '.. 'li 'du 'dr 'sw 'pu 'po 'ju 'ca 'cc 're 'eq 'ne 'lt
'gt 'fe 'st 'ad 'su 'mu 'di 'an 'or 'xo 'sh 'zr 'ha 'ie
'iq 'ii } 'Instructions const
~~~
Then I define a `quad` combinator to simplify the later debundling
of the instruction names.
~~~
:quad (xqqqq-)
'abcde 'abacadae reorder
\pupupupu \pupuca..
\popoca.. \popoca..
\popoca.. ;
~~~
Next, a word to handle hex numbers. A standard Retro system only
handles decimal by default, so this just implements a quick hex
conversion.
~~~
'0123456789ABCDEF 'DIGITS s:const
'Number var
:convert (c-) &DIGITS swap s:index-of @Number #16 * + !Number ;
:check-sign (s-ns) dup fetch $- eq? [ #-1 swap n:inc ] [ #1 swap ] choose ;
:s:to-hex-number (s-n)
#0 !Number check-sign [ convert ] s:for-each @Number * ;
~~~
Decoding an instruction is simple. If it's in the `Instructions`
array, return the index. If not, convert to a number using the
hex conversion above.
~~~
:decode (s-n)
dup &Instructions a:contains-string?
[ &Instructions swap a:index-of-string ]
[ s:to-hex-number ] choose ;
~~~
The `debundle` word breaks a string into four two byte substrings
and runs `decode` against each.
~~~
:debundle (s-abcd)
[ #0 #2 s:substr decode ]
[ #2 #2 s:substr decode ]
[ #4 #2 s:substr decode ]
[ #6 #2 s:substr decode ] quad ;
~~~
Once debundled and decoded, I can then pack the opcodes into a
single cell. This is simple, just some quick shifts and addition.
~~~
:pack (abcd-n)
#-24 shift swap #-16 shift + swap #-8 shift + + ;
~~~
Nearing completion, I wrap everything up into a single word and
then patch the original `i` to jump to this.
(The 1793 corresponds to the liju.... instruction sequence)
~~~
:assemble (s-) debundle pack , ;
#1793 &i store
&assemble &i n:inc store
~~~
And finally, close off the namespace leaving the dictionary clean
of all the words used to implement this.
~~~
}}
'muri s:put nl
~~~