Uxn is a portable 8-bit virtual computer inspired by forth-machines, capable of running simple tools and games programmable in its own esoteric assembly language. The distribution of Uxn projects is not unlike downloading a ROM for a console, as Uxn has its own emulator.
It comes with a few programs out of the box, a simple drawing program, a simple tracker, a simple editor.
It’s absolutely fascinating!
Sadly, I also don’t know how to write assembler, or how to think assembler, and I think I would need a very, very simple idea to get started. Something like a 2D game of life visualisation or something like that.
There’s this super short introduction to assembly and to uxambly, the programming language for the Uxn stack-machine. That’s all I had.
The idea was simple: have a line of cells. Every generation, a cell lives if it has at least one live neighbour and it dies if the neighbours are either both alive or both dead. Draw a dot for every live cell, draw a row for every generation.
Here’s the code that I managed to write over the last few days.
%RTN { JMP2r } %GOTO { JMP2 } %GOSUB { JSR2 } ( devices ) |0100 ;System { vector 2 pad 6 r 2 g 2 b 2 } |0110 ;Console { vector 2 pad 6 char 1 byte 1 short 2 string 2 } |0120 ;Screen { vector 2 width 2 height 2 pad 2 x 2 y 2 addr 2 color 1 } |0130 ;Audio { wave 2 envelope 2 pad 4 volume 1 pitch 1 play 1 value 2 delay 2 finish 1 } |0140 ;Controller { vector 2 button 1 key 1 } |0160 ;Mouse { vector 2 x 2 y 2 state 1 chord 1 } |0170 ;File { vector 2 pad 6 name 2 length 2 load 2 save 2 } |01a0 ;DateTime { year 2 month 1 day 1 hour 1 minute 1 second 1 dotw 1 doty 2 isdst 1 refresh 1 } ( program ) |0200 ( theme ) #54ac =System.r #269b =System.g #378d =System.b ,main GOTO BRK @main ( -- ) ( run for a few generations ) #00 #FF $loop OVR #00 SWP ,print-line GOSUB ,compute-next GOSUB ,copy-next GOSUB ( incr ) SWP #01 ADD SWP ( loop ) DUP2 LTH ^$loop JNZ POP2 BRK ( 64 cells ) @cell [ 0001 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ] @next [ 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ] @print-line ( y -- ) ( set ) =Screen.y ( loop through 64 cells ) #00 #FF $loop ( copy ) OVR #00 SWP DUP2 ( pos ) =Screen.x ( addr ) ,cell ADD2 ( draw ) PEK2 =Screen.color ( incr ) SWP #01 ADD SWP ( loop ) DUP2 LTH ^$loop JNZ POP2 RTN @compute-next ( -- ) ( loop through 62 cells ) #01 #FE $loop OVR DUP DUP ( three copies of the counter ) #01 SUB #00 SWP ,cell ADD2 PEK2 SWP #01 ADD #00 SWP ,cell ADD2 PEK2 ( the cell dies if the neighbors are either both dead or both alive, i.e. Rule 90 ) NEQ ( one copy of the counter and the life value ) SWP #00 SWP ,next ADD2 POK2 ( incr ) SWP #01 ADD SWP ( loop ) DUP2 LTH ^$loop JNZ POP2 RTN @copy-next ( -- ) ( loop through 64 cells ) #00 #FF $loop OVR DUP ( two copies of the counter ) #00 SWP ,next ADD2 PEK2 ( one copy of the counter and the value ) SWP #00 SWP ,cell ADD2 POK2 ( incr ) SWP #01 ADD SWP ( loop ) DUP2 LTH ^$loop JNZ POP2 RTN
Looks like a Sirpinski triangle
Looks like a Sierpiński triangle!
If you have suggestions for my assembler code, let me know!
#Programming #uxn
(Please contact me if you want to remove your comment.)
⁂
Now with a small pseudo-random number generator!
%RTN { JMP2r } %GOTO { JMP2 } %GOSUB { JSR2 } ;seed { x 1 w 2 s 2 } ( devices ) |0100 ;System { vector 2 pad 6 r 2 g 2 b 2 } |0110 ;Console { vector 2 pad 6 char 1 byte 1 short 2 string 2 } |0120 ;Screen { vector 2 width 2 height 2 pad 2 x 2 y 2 addr 2 color 1 } |0130 ;Audio { wave 2 envelope 2 pad 4 volume 1 pitch 1 play 1 value 2 delay 2 finish 1 } |0140 ;Controller { vector 2 button 1 key 1 } |0160 ;Mouse { vector 2 x 2 y 2 state 1 chord 1 } |0170 ;File { vector 2 pad 6 name 2 length 2 load 2 save 2 } |01a0 ;DateTime { year 2 month 1 day 1 hour 1 minute 1 second 1 dotw 1 doty 2 isdst 1 refresh 1 } ( program ) |0200 ( theme ) #2aac =System.r #269b =System.g #378d =System.b ,main GOTO BRK @main ( -- ) ,seed-line GOSUB ( run for a few generations ) #00 #FF $loop OVR #00 SWP ,print-line GOSUB ,compute-next GOSUB ,copy-next GOSUB ( incr ) SWP #01 ADD SWP ( loop ) DUP2 LTH ^$loop JNZ POP2 BRK ( cells ) @cell [ 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ] @next [ 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ] @print-line ( y -- ) ( set ) =Screen.y ( loop through cells ) #00 #FF $loop ( copy ) OVR #00 SWP DUP2 ( pos ) =Screen.x ( addr ) ,cell ADD2 ( draw ) PEK2 =Screen.color ( incr ) SWP #01 ADD SWP ( loop ) DUP2 LTH ^$loop JNZ POP2 RTN @compute-next ( -- ) ( loop through 62 cells ) #01 #FE $loop OVR DUP DUP ( three copies of the counter ) #01 SUB #00 SWP ,cell ADD2 PEK2 SWP #01 ADD #00 SWP ,cell ADD2 PEK2 ( the cell dies if the neighbors are either both dead or both alive, i.e. Rule 90 ) NEQ ( one copy of the counter and the life value ) SWP #00 SWP ,next ADD2 POK2 ( incr ) SWP #01 ADD SWP ( loop ) DUP2 LTH ^$loop JNZ POP2 RTN @copy-next ( -- ) ( loop through cells ) #00 #FF $loop OVR DUP ( two copies of the counter ) #00 SWP ,next ADD2 PEK2 ( one copy of the counter and the value ) SWP #00 SWP ,cell ADD2 POK2 ( incr ) SWP #01 ADD SWP ( loop ) DUP2 LTH ^$loop JNZ POP2 RTN @seed-line ( -- ) #00 =DateTime.refresh ~DateTime.second =seed.x #0000 =seed.w #e2a9 =seed.s ( loop through cells ) #01 #FE $loop OVR ( one copy of the counter ) ,rand GOSUB #10 AND ( pick a bit ) SWP #00 SWP ,cell ADD2 POK2 ( incr ) SWP #01 ADD SWP ( loop ) DUP2 LTH ^$loop JNZ POP2 RTN ( https://en.wikipedia.org/wiki/Middle-square_method ) @rand ( -- 1 ) ~seed.x #00 SWP DUP2 MUL2 ~seed.w ~seed.s ADD2 DUP2 =seed.w ADD2 #04 SFT SWP #40 SFT ADD DUP =seed RTN
– Alex 2021-04-22 18:49 UTC
---
Related stuff by @eloquence:
http://eloquence.github.io/elixor/
https://eloquence.github.io/xorworld/
– Alex 2021-04-23 09:31 UTC
---
On the web:
https://github.com/aduros/webuxn
http://compudanzas.net/uxn_tutorial.html
– Alex 2021-09-15 05:31 UTC