NOTE: Planning upgrades around 8pm-10pm UTC today. Expect some downtime and possibly read-only wiki. Avoid major editing sessions during that time.

2 septendigits, 289 septendigytes

From Esolang
Jump to navigation Jump to search

2 septendigits, 289 septendigytes is another assembly-like programming language sort of like 2 undigits, 121 undigytes, 7 heptits, 49 heptytes and 3 pentits, 25 pentytes made by User:Mutasimos. There is a slight chance I won't continue going up the memory size because it just removes the tight memory constraints of 2 trits, 3 trytes, the first language in the family that didnt use base-2.

Terminology

Septendigit
A single base-17 / septendecimal digit. We use these characters for the 17 digits: 0123456789ABCDEFG.
Septendigyte
Two septendigits, and also the word size of the machine.
The 0s prefix
Throughout this page the 0s prefix is added to numbers if it is written in septendecimal.

ISA

Registers
Septendecimal Register What it is Initial value
0s0 r0 General purpose register 0s00
0s1 r1 General purpose register 0s00
0s2 r2 General purpose register 0s00
0s3 r3 General purpose register 0s00
0s4 r4 General purpose register 0s00
0s5 r5 General purpose register 0s00
0s6 r6 General purpose register 0s00
0s7 r7 General purpose register 0s00
0s8 r8 General purpose register 0s00
0s9 r9 General purpose register 0s00
0sA ra General purpose register 0s00
0sB rb General purpose register 0s00
0sC rc General purpose register 0s00
0sD rd General purpose register 0s00
0sE re General purpose register 0s00
0sF sp Stack pointer register 0sGG
0sG bp Base pointer register 0s00
Instructions
Opcode Instruction What it does
0s00 nop Do nothing (NOP)
0s01 hlt Halt the program
0s02 - 0s0G Reserved
0s10 mov [dst] [src] Sets [dst] to the value in [src]
0s11 mov [dst] [imm] Sets [dst] to [imm]
0s12 ldr [dst] [abs] Loads value from memory into [dst] where address is [abs]
0s13 ldr [dst] [reg] Loads value from memory into [dst] where address is in [reg]
0s14 str [abs] [src] Store value from [src] into memory where address is [abs]
0s15 str [reg] [src] Store value from [src] into memory where address is in [reg]
0s16 push [src] Pushes register [src] onto the stack
0s17 push [imm] Pushes [imm] onto the stack
0s18 pop [dst] Pops the top of the stack into [dst]
0s19 - 0s1G Reserved
0s20 add [dst] [src] Adds the value in [src] to [dst] (can wrap)
0s21 sub [dst] [src] Subtracts the value in [src] from [dst] (can wrap)
0s22 mul [dst] [src] Multiplies [dst] with [src] (can wrap)
0s23 div [dst] [src] Divides [dst] by [src] (crashes on division by zero)
0s24 mod [dst] [src] Remainder of division of [dst] by [src] (crashes on division by zero)
0s25 add [dst] [imm] Adds [imm] to [dst] (can wrap)
0s26 sub [dst] [imm] Subtracts [imm] from [dst] (can wrap)
0s27 mul [dst] [imm] Multiplies [dst] by [imm] (can wrap)
0s28 div [dst] [imm] Divides [dst] by [imm] (crashes on division by zero)
0s29 mod [dst] [imm] Remainder of division of [dst] by [imm] (crashes on division by zero)
0s2A neg [dst] Negates [dst] (two's complement, can wrap)
0s2B dnot [dst] Sets [dst] to its digit-wise complement (each septendigit d becomes 16 - d)
0s2C dmin [dst] [src] Sets [dst] to whichever of [dst] and [src] is smaller
0s2D dmax [dst] [src] Sets [dst] to whichever of [dst] and [src] is larger
0s2E dmin [dst] [imm] Sets [dst] to whichever of [dst] and [imm] is smaller
0s2F dmax [dst] [imm] Sets [dst] to whichever of [dst] and [imm] is larger
0s2G Reserved
0s30 jiz [reg] [abs] If [reg] is 0, go to [abs]
0s31 jnz [reg] [abs] If [reg] is not 0, go to [abs]
0s32 jeq [a] [b] [abs] If [a] register equals [b] register, go to [abs]
0s33 jne [a] [b] [abs] If [a] register does not equal [b] register, go to [abs]
0s34 jlt [a] [b] [abs] If [a] register is less than [b] register, go to [abs] (unsigned comparison)
0s35 jgt [a] [b] [abs] If [a] register is greater than [b] register, go to [abs] (unsigned comparison)
0s36 jlti [a] [b] [abs] If [a] register is less than [b] register, go to [abs] (signed comparison)
0s37 jgti [a] [b] [abs] If [a] register is greater than [b] register, go to [abs] (signed comparison)
0s38 - 0s3G Reserved
0s40 jmp [abs] Jumps to the specified absolute address
0s41 call [abs] Calls the specified absolute address, pushing the next instruction's address onto the stack
0s42 ret Pops the new instruction pointer off the stack
0s43 - 0s4G Reserved
0s50 out17 [reg] Writes [reg] as a septendecimal number, prefixed with 0s, to standard out
0s51 out10 [reg] Writes [reg] as a decimal number, without any prefix, to standard out
0s52 outc [reg] Writes [reg] as a single character according to the text encoding
0s53 outc [imm] Writes [imm] as a single character according to the text encoding
0s54 outs [ptr_reg] [len_reg] Writes the number of septendigytes given by [len_reg] from [ptr_reg] according to the text encoding
0s55 outs [ptr_reg] [len_imm] Writes the number of septendigytes given by [len_imm] from [ptr_reg] according to the text encoding
0s56 - 0sGG Reserved

Whenever an instruction takes two registers, the first register is the higher septendigit and the second register is the lower septendigit of an entire septendigyte, allowing for 2 septendigytes instead of 3 septendigytes of memory. For example, assembling "mov r0, r1" into machine code would give us "0s10 0s01". For instructions that take one register and an immediate or address (like ldr, str, push, pop, neg, dnot, outc, or the immediate arithmetic instructions), the register is encoded as the lower septendigit of the septendigyte following the opcode, with the upper septendigit unused.

Memory is 289 septendigytes, addressed 0s00 through 0sGG, and the instruction pointer wraps around at the end back to 0s00, allowing for more "complicated" programs (but the bigger memory space should be more than enough). Execution keeps looping unless a HLT instruction is encountered.

Text Encoding

Septendigytes 0s00 through 0sF0 (0 through 255 in decimal) map directly to their corresponding Latin-1 / extended ASCII byte value.

The remaining septendigytes, 0sF1 through 0sGG, are given over to a small set of box-drawing and mathematical symbols, since 17² conveniently leaves 33 codepoints spare above the byte range:

0 1 2 3 4 5 6 7 8 9 A B C D E F G
F
G

Examples

The starting septendigytes in memory in the examples given here are separated by spaces, and the ones which start with 0s are in septendecimal and if not they are in decimal. There is also comments which start with ";".

Hello, world!

0s11 0s00 0s07 ; mov r0, msg (0s07)
0s55 0s00 14   ; outs ra, 14
0s01           ; hlt

0s44 0s5g 0s66 ; msg: ds "Hello, World!\n"
0s66 0s69 0s2a
0s1f 0s52 0s69
0s6c 0s66 0s5f
0s1g 0s0a

truth-machine

0s12 0s00 0s09 ; ldr r0, val (0s09)
               ; loop:
0s51 0s00      ;   out10 r0
0s31 0s00 0s03 ;   jnz r0, loop
0s01           ; hlt

;; Change this value to 1 for the other outcome
0              ; val: ds 0

= Fibonacci sequence

0s11 0s00 0    ; mov r0, 0
0s11 0s01 1    ; mov r1, 1
               ; loop:
0s51 0s00      ;   out10 r0
0s53 0s0a      ;   outc '\n'
0s10 0s20      ;   mov r2, r0
0s10 0s01      ;   mov r0, r1
0s20 0s12      ;   add r1, r2
0s34 0s12 0s14 ;   jlt r1, r2, drain (0s14)  ; if rb < rc, it wrapped
0s40 0s06      ;   jmp loop (0s06)
               ; drain:
0s51 0s00      ;   out10 r0             ; print the last still-valid term
0s53 0s0a      ;   outc '\n'
0s01           ;   hlt

This program prints numbers until 223, otherwise the number would overflow.

See also