We are currently working on new rules for what content should and shouldn't be allowed on this website, and are looking for feedback! See Esolang:2026 topicality proposal to view and give feedback on the current draft.
2 undigits, 121 undigytes
2 undigits, 121 undigytes is another assembly-like programming language sort of like 7 heptits, 49 heptytes and 3 pentits, 25 pentytes made by User:Mutasimos.
When I saw a septenary programming language after I made a quinary programming language, I felt like going further. Since using a composite number as the base would make it a bit easier (octal would just make it binary-ish) I picked the next prime number, 11. Maybe a tridecimal language will be made soon?
Terminology
- Undigit
- A single base-11 / undecimal digit. We use these characters for the 11 digits: 0123456789X.
- Undigyte
- Two undigits, and also the word size of the machine.
- The 0u prefix
- Throughout this page the 0u prefix is added to numbers if it is written in undecimal.
ISA
| Undecimal | Register | What it is | Initial value |
|---|---|---|---|
| 0u0 | ra | General purpose A register | 0u00 |
| 0u1 | rb | General purpose B register | 0u00 |
| 0u2 | rc | General purpose C register | 0u00 |
| 0u3 | rd | General purpose D register | 0u00 |
| 0u4 | re | General purpose E register | 0u00 |
| 0u5 | sp | Stack pointer register | 0uXX |
| 0u6 | bp | Base pointer register | 0u00 |
| Opcode | Instruction | What it does |
|---|---|---|
| 0u00 | nop | Do nothing (NOP) |
| 0u01 | hlt | Halt the program |
| 0u02 | mov [dst] [src] | Sets [dst] to the value in [src] |
| 0u03 | mov [dst] [imm] | Sets [dst] to [imm] |
| 0u04 | add [dst] [src] | Adds the value in [src] to [dst] (can wrap) |
| 0u05 | sub [dst] [src] | Subtracts the value in [src] from [dst] (can wrap) |
| 0u06 | mul [dst] [src] | Multiplies [dst] with [src] (can wrap) |
| 0u07 | div [dst] [src] | Divides [dst] with [src] (crashes on division by zero) |
| 0u08 | mod [dst] [src] | Remainder of division of [dst] with [src] (crashes on division by zero) |
| 0u09 | add [dst] [imm] | Adds [imm] to [dst] (can wrap) |
| 0u0X | sub [dst] [imm] | Subtracts [imm] from [dst] (can wrap) |
| 0u10 | mul [dst] [imm] | Multiplies [imm] with [src] (can wrap) |
| 0u11 | div [dst] [imm] | Divides [dst] with [imm] (crashes on division by zero) |
| 0u12 | mod [dst] [imm] | Remainder of division of [dst] with [imm] (crashes on division by zero) |
| 0u13 | Reserved | |
| 0u14 | jmp [abs] | Jumps to the specified absolute address |
| 0u15 | ldr [dst] [abs] | Loads value from memory into [dst] where address is [abs] |
| 0u16 | ldr [dst] [reg] | Loads value from memory into [dst] where address is in [reg] |
| 0u17 | str [abs] [src] | Store value from [src] into memory where address is [abs] |
| 0u18 | str [reg] [src] | Store value from [src] into memory where address is in [reg] |
| 0u19 | push [src] | Pushes register [src] onto the stack |
| 0u1X | pop [dst] | Pops register [dst] off the stack |
| 0u20 | call [abs] | Calls the specified absolute address, pushing the next instruction's address onto the stack |
| 0u21 | ret | Pops the new instruction pointer off the stack |
| 0u22 | jiz [reg] [abs] | If [reg] is 0, go to [abs] |
| 0u23 | jnz [reg] [abs] | If [reg] is not 0, go to [abs] |
| 0u24 | jeq [a] [b] [abs] | If [a] register equals [b] register, go to [abs] |
| 0u25 | jne [a] [b] [abs] | If [a] register does not equal [b] register, go to [abs] |
| 0u26 | jlt [a] [b] [abs] | If [a] register is less than [b] register, go to [abs] (unsigned comparison) |
| 0u27 | jgt [a] [b] [abs] | If [a] register is greater than [b] register, go to [abs] (unsigned comparison) |
| 0u28 | jlti [a] [b] [abs] | If [a] register is less than [b] register, go to [abs] (signed comparison) |
| 0u29 | jgti [a] [b] [abs] | If [a] register is greater than [b] register, go to [abs] (signed comparison) |
| 0u2X | outu [reg] | Writes [reg] as undecimal number, prefixed with 0u to standard out |
| 0u30 | outd [reg] | Writes [reg] as decimal number, without any prefix to standard out |
| 0u31 | outs [ptr_reg] [len_reg] | Writes the number of undigytes given by [len_reg] from [ptr_reg] according to the text encoding |
| 0u32 | outs [ptr_reg] [len_imm] | Writes the number of undigytes given by [len_imm] from [ptr_reg] according to the text encoding |
| 0u33 - 0uXX | Reserved |
Whenever an instruction takes two registers, the first register is the higher undigit and the second register is the lower undigit of an entire undigyte, allowing for 2 undigytes instead of 3 undigytes of memory. For example, assembling "mov ra, rb" into machine code would give us "0u02 0u01".
Text Encoding
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | X | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | null | lf | cr | nbsp | ¢ | £ | ¥ | § | ¶ | « | » |
| 1 | sp | ! | " | # | $ | % | & | ' | ( | ) | * |
| 2 | + | , | - | . | / | : | ; | [ | = | ] | ? |
| 3 | @ | [ | \ | ] | ^ | _ | ` | { | | | } | ~ |
| 4 | A | B | C | D | E | F | G | H | I | J | K |
| 5 | L | M | N | O | P | Q | R | S | T | U | V |
| 6 | W | X | Y | Z | ¡ | ¿ | ™ | … | · | µ | ¬ |
| 7 | a | b | c | d | e | f | g | h | i | j | k |
| 8 | l | m | n | o | p | q | r | s | t | u | v |
| 9 | w | x | y | z | ¼ | ½ | ¾ | ¹ | ² | ³ | ¦ |
| X | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ± |
Examples
The starting undigytes in memory in the examples given here are separated by spaces, and the ones which start with 0u are in undecimal and if not they are in decimal. There is also comments which start with ";".
Hello, world!
0u03 0u00 0u07 ; mov ra, msg (0u07) 0u32 0u00 14 ; outs ra, 14 0u01 ; hlt 0u47 0u74 0u80 ; msg: du "Hello, World!\n" 0u80 0u83 0u21 0u10 0u60 0u83 0u86 0u80 0u73 0u11 0u01
truth-machine
0u15 0u00 0u09 ; ldr ra, val (0u09) 0u30 0u00 ; loop: outd ra 0u23 0u00 0u03 ; jnz ra, loop (0u03) 0u01 ; hlt ;; Change this value to 1 for the other outcome 0 ; val: du 0
Fibonacci sequence
0u03 0u04 0u29 ; mov re, newline (0u29) 0u03 0u00 0 ; mov ra, 0 0u03 0u01 1 ; mov rb, 1 0u30 0u00 ; loop: outd ra 0u32 0u04 1 ; outs re, 1 0u02 0u20 ; mov rc, ra 0u02 0u01 ; mov ra, rb 0u04 0u12 ; add rb, rc 0u26 0u12 0u23 ; jlt rb, rc, drain (0u23) -- if rb < rc, it wrapped 0u14 0u09 ; jmp loop (0u09 = 9) 0u30 0u00 ; drain: outd ra -- print the last still-valid term 0u32 0u04 1 ; outs re, 1 0u01 ; hlt 0u01 ; newline: du '\n'
This program prints numbers until 89, otherwise the number would overflow.
Interpreter
The interpreter is here: [1]. The interpreter supports a debugging mode (very useful!) which can be used with the "--debug" flag.