Uxntal Software
Here's a list of small self-hosted development tools:
- Drifblim is a Uxntal assembler.
- Uxnfor is a code formatter.
- Uxnlin is a peephole optimizer.
- Uxnbal is a program validator.
- Uxndis is a disassembler.
Here are some implementation tools:
- Uxn Opcode Test: Tests Uxn core support.
- Uxntal Acid Test: Tests Uxntal language support.
| Stack | Version | ||
|---|---|---|---|
| Uxn | 0K | ||
| Uxntal | 54K | ||
| Varvara | 80K | ||
Boostrapping
The steps below recover a working assembler from a hexdump and verify it reproduces itself. Since the assembler is written in the language it is assembling, you have a few choices:
- Download a pre-assembled rom.
- Assemble your own with the live REPL.
- Bootstrap from a hexdump.
If you are unable to assemble your own copy of Drifblim, lost its source file, or simply want to make sure that the assembler is unaltered, you will need the hexadecimal data of drifblim.rom. Here are some portable tools to help with the bootstrapping process:
Step 1: Make Binaries
First off, you need a way to create binary files from hex dumps. If you don't have access to xxd, you can paste the following line in a text file, and run a hex dump through it:
FAFAFXFZFwfaalFBFAAFFZFZXVGfoAAFXFZFFXXfoKgaam&/$AAAFXJgaam&/AFAAFXFFZZDYJF$/FXAKF|Bgaam/AAFXFZFXgBFAYXFEF|BGGoGAFAFXFZDYFEF|B/DAAFX_gBAGYgDAAFXFXAXZEEZXGPgBAAFXFFZZ_]GQFAPGA^GAQFAPgaamFPGAAFXFXFFXXW
cat drifblim.rom.txt | uxncli xh.txt > drifblim.rom
Step 2: Create Copies
At this point, you have recovered your own drifblim.rom from a hex dump. The next step is to make a new drifblim.rom from its source code, using the newly assembled rom.
uxncli drifblim.rom drifblim.tal.txt drifblim2.rom
Note that in Uxntal, hexadecimal numbers are valid code and so any rom can be recovered from a hex dump with a working assembler.
Step 3: Compare Results
Finally, we should have two identical roms of the assembler, where one was assembled from the textual source. If for some reason you do not have access to the unix diff command, you can compare the two hexadecimal dumps with the checksum, which takes two filepaths and compare their content.
uxncli drifblim.rom checksum.tal.txt checksum.rom uxncli checksum.rom drifblim.rom drifblim2.rom
1fa03ffb drifblim.rom 1fa03ffb drifblim2.rom
Alternatively, if your Varvara implementation does not support the File device, use the Drifloon assembler(tal/rom). To validate your own assembler, see the tests, and disassemble the result with uxndis.
Step 4: Deep Validation
At this point, you have verified that Drifblim assembles itself correctly, assuming that uxncli is trustworthy. Now, let's remove that assumption. uxnmin.tal is a complete Uxn virtual machine, written in Uxntal. It's small enough to audit from its hexdump against the Uxn specification:
cat uxnmin.rom.txt | uxncli xh.txt > uxnmin.rom
Next, we'll use Drifloon for this part, let's assemble it:
cat drifloon.rom.txt | uxncli xh.txt > drifloon.rom
Run Drifloon inside uxnmin and verify that it produces an identical assembler:
cat drifloon.tal.txt | uxncli uxnmin.rom drifloon.rom > drifloon2.rom uxncli checksum.rom drifloon.rom drifloon2.rom
566fd630 drifloon.rom 566fd630 drifloon2.rom
Lastly, verify that uxnmin assembles itself through that inner assembler:
cat uxnmin.tal.txt | uxncli uxnmin.rom drifloon.rom > uxnmin2.rom uxncli checksum.rom uxnmin.rom uxnmin2.rom
8f815450 uxnmin.rom 8f815450 uxnmin2.rom
The assembler and the virtual machine are each a witness to the other. If both comparisons pass, the trust boundary is the hexdump of uxnmin.rom(1kb). Everything above it is verified by the chain.
A collection of commonly used routines in Uxntal projects.
The following libraries are in the standard Drifblim style. If you discover faster and smaller helpers, please get in touch with me.
- LibString, parsing and printing routines.
- LibRandom, random number generators.
- LibDate, date parsing routines.
- LibDraw, shape drawing routines.
- LibMath, arithmetic routines.
Uxnfor is a formatter for Uxntal.
The formatter expects the standard Uxntal Notation, sometimes called Drifblim-style.
- Struct labels are capitalized.
- Source is indented with tabulators.
- Comments that should be on their own line begin with a ( | pipe ).
- Names of routines that are emitting are <wrapped> inside angle brackets.
- Subroutines definitions without an stack effect will be left inlined
- Tokens inside square brackets will be formatted as blocks of binary data.
- The zero-page is indicated by |000, the one-page is indicated by |100.
- Local forward references are indicated by &>loop for nesting.
- Routines that fall through to the next one end with ( >> ).
If a routine is printing, drawing, or sometimes ingesting all of its arguments, the routine can be wrapped within angular brackets to indicate that it should end a line to Uxnfor.
@<emit-num> ( num* -- ) LIT "0 ADD .Console/write DEO JMP2r
If a label should not be accessed from outside its scope, it is indicated by the &+name convention.
@scope/get-value ( -- value ) [ LIT &+value $1 ] JMP2r @scope/set-value ( value -- ) ,&+value STR JMP2r @main ( -> ) ;scope/+value LDA ( uxnlin will throw a warning ) POP BRK
- Source, Uxntal
Uxnbal is a stack effect validator.
Program validation is done at compile-time by comparing a routine's stack effect, against the resulting balance of all stack changes occurring in the routine's code. Words that do not pass the stack-checker are generating a warning, and so essentially this defines a very basic and permissive type system that nevertheless catches some invalid programs and enables compiler optimizations. For more details, see Uxnbal.
The simplest case is when a piece of code does not have any branches or recursion, and merely pushes literals and calls words. The stack effect routines is always known statically from the declaration.
@add-eight ( a -- a+8 ) #0008 ADD JMP2r
Working-stack imbalance of +1, in add-eight.
In the case of branching, each branch is evaluated and if an imbalance occurs inside one of the branches, the branch name is indicated:
@branching ( a* -- c ) LDAk #01 EQU ?&one LDAk #02 EQU ?&two POP2 #ff JMP2r &one ( a* -- c ) POP2 #12 JMP2r &two ( a* -- c d ) ADD JMP2r
Working-stack imbalance of -1, in branching/two.
In the case of a recursion, the validator will use the stack effect instead of repeatedly walking through the body of the routine.
@print-string ( str* -- )
LDAk DUP ?{ POP POP2 JMP2r }
emit-letter
INC2 !print-string
For loops that exits without affecting the stack depth, a > prefixed label is used as a shorthand to reduce the need for extraneous stack effect definitions in cases where it can be inferred:
@many-times ( a -- ) DUP &>l INC DUP ?&>l POP2 JMP2r
Routines that pull items from the stack beyond their allowed depth will also raise a warning, making the stack effect act a sort of boundary:
@shallow ( a -- ) POP2 JMP2r
Working-stack depth error of 1, in shallow.
Lastly, a runtime specific solution to validate the stack state at any one point during the execution of a program, is to read the System/wst port and compare it against a given stack pointer byte value.
@on-reset ( -> )
#abcd DUP2
.System/wst DEI #05 EQU ?{
#01 .System/debug DEO }
BRK
Uxnlin is an optimizer for Uxntal.
It finds known patterns in Uxntal(54K) programs that can be optimized, or that are unsafe.
- Source, Uxntal
Bicycle is an interactive Uxntal playground.
Bicycle is a little Uxntal interpreter designed for teach the language in front of an audience. Bicycle allows you to vizualize source code next to its equivalent bytecode and step through the evaluation.
As Companion
To launch Bicycle as a companion application, you need just pipe the
left.rom instance of uxnemu to the one of
bicycle.rom. Left can send both a selection of text to be
evaluated, or the entire working tal file, by pressing ctrl+p. The
result should be instantly displayed in the Bicycle window.
uxnemu left.rom | uxnemu bicycle.rom
As an alternative, to experiment with Uxntal you can also use the web-based REPL.
Beetbug is a step debugger.
Inspired from Uxn32's fantastic debugger, Beetbug is a step debugger for Varvara, written in Uxntal. It is the perfect tool to step through a running program. It uses Varvara's Console write port to print debug to the interface, and the System's debug port to put a breakpoint.
Beetbug supports symbol files, and will highlight both the return address on top of the return stack, and the address on top of the working stack, giving you a visual indication of the addresses that are being accessed.
Manual
Launch beetbug with the target rom to debug:
uxnemu beetbug.rom some_project.rom
Beetbug will evaluate the reset vector, starting at 0100, until a BRK is reached, to pause evaluation, you can use the System's debug port as follow:
#010e DEO
Controls
- left Back
- right Step
- A Play/Pause
- B Incr. Speed
- view source
- download rom, 4kb
incoming: uxntal devlog