Abuse filter log

Abuse Filter navigation (Home | Recent filter changes | Examine past edits | Abuse log)
Jump to navigation Jump to search
Details for log entry 9,642

09:29, 27 January 2026: Oscarlo (talk | contribs) triggered filter 16, performing the action "edit" on Tina. Actions taken: Disallow; Filter description: the "User:" must not be hidden on links to userspace (examine)

Changes made in edit

'''Tina''' ('''T'''his '''i'''s '''n'''ot '''a'''ssembly) is an [[esoteric programming language]] with an assembly-like syntax and a deliberately overpowered “ALU matrix” instruction format. A Tina program is assembled into a linear list of instructions plus an initial memory image, then executed on a simple machine with unbounded signed integer cells and non-negative addresses.
'''Tina''' ('''T'''his '''i'''s '''n'''ot '''a'''ssembly) is an [[esoteric programming language]] made by user [[User:Oscarlo|Oscarlo]] with an assembly-like syntax and a deliberately overpowered “ALU matrix” instruction format. A Tina program is assembled into a linear list of instructions plus an initial memory image, then executed on a simple machine with unbounded signed integer cells and non-negative addresses.


A reference interpreter/assembler is implemented in Python.
A reference interpreter/assembler is implemented in Python.

Action parameters

VariableValue
Edit count of the user (user_editcount)
2
Name of the user account (user_name)
'Oscarlo'
Age of the user account (user_age)
3320
Page ID (page_id)
24813
Page namespace (page_namespace)
0
Page title (without namespace) (page_title)
'Tina'
Full page title (page_prefixedtitle)
'Tina'
Action (action)
'edit'
Edit summary/reason (summary)
''
Old content model (old_content_model)
'wikitext'
New content model (new_content_model)
'wikitext'
Old page wikitext, before the edit (old_wikitext)
''''Tina''' ('''T'''his '''i'''s '''n'''ot '''a'''ssembly) is an [[esoteric programming language]] with an assembly-like syntax and a deliberately overpowered “ALU matrix” instruction format. A Tina program is assembled into a linear list of instructions plus an initial memory image, then executed on a simple machine with unbounded signed integer cells and non-negative addresses. A reference interpreter/assembler is implemented in Python. ==Etymology== “Tina” is a backronym for “This is not assembly”. The language is intentionally close to assembly in feel (labels, cells, jumps, stack operations), while also featuring higher-level conveniences like conditional-branching ALU instructions and built-in memory/string operations. ==Computational model== Tina executes a sequence of instructions over: * An unbounded memory of signed integers (cells default to 0). * A program counter (PC) indexing the instruction list. * Optional stack/frame support using two conventional cells named <code>SP</code> and <code>FP</code> when stack instructions are used. Memory addresses must be non-negative; attempting to access a negative address is an error. ==Syntax overview== * One instruction or directive per line. * Labels are written as <code>name:</code> (multiple labels may precede a statement). * Comments begin with <code>;</code> and continue to end of line. * Mnemonics are case-insensitive (the reference interpreter uppercases internally). Example line: <pre> loop: ADD32SNEZ #1, counter, loop ; increment and loop while counter != 0 (example only) </pre> ==Assembler directives== These directives allocate and/or initialize memory in the initial image. ; <code>.cell name = value</code> : Allocate one cell, optionally initialized. If omitted, initializes to 0. Character literals like <code>'A'</code> are allowed (one character only). ; <code>.block name, n</code> : Allocate <code>n</code> zero-initialized cells. ; <code>.data name v1, v2, ...</code> : Allocate a list of cells initialized to the given integers (supports decimal/hex via Python-style <code>0x</code>). ; <code>.zstr name "text"</code> : Allocate a null-terminated byte string. Each character must be in 0..255, and a trailing 0 cell is appended. Symbols defined by these directives can be used as memory operands and (in immediates) as numeric addresses. ==Operands and addressing modes== Tina instructions take ''operands'' which can be immediate values or memory references. ===Immediate=== ; <code>#n</code> : Immediate integer <code>n</code>. In immediates, <code>n</code> may be: :* a numeric literal (<code>#10</code>, <code>#0xFF</code>, <code>#-3</code>) :* a memory symbol (<code>#MSG</code> yields MSG’s address) :* a code label (<code>#loop</code> yields the instruction index of <code>loop:</code>) :* optionally with a small decimal offset: <code>#LABEL+3</code>, <code>#var-1</code> Immediates are not addressable (you cannot write to <code>#...</code>). ===Memory (direct / indexed)=== ; <code>x</code> : Direct cell at address <code>x</code> (where <code>x</code> is a symbol or numeric address). ; <code>x+K</code> / <code>x-K</code> : Direct cell at address <code>x+K</code> (offset is decimal in the reference interpreter). ===Indirect (pointer)=== ; <code>@x</code> : Indirect cell at address <code>mem[x]</code>. ; <code>@x+K</code> : Indirect indexed cell at address <code>mem[x]+K</code>. In pseudocode, reading <code>@p+2</code> means <code>mem[mem[p] + 2]</code>. ==ALU instruction matrix== Most arithmetic/logic operations are expressed with a single general pattern: <pre> <OP><WIDTH><OVF><COND> src, dst [, label] </pre> Execution model: 1. Read <code>src</code> and <code>dst</code>. 2. Compute a new value (<code>new_dst</code>) using <code>OP</code>. 3. Write <code>new_dst</code> back to <code>dst</code>. 4. If a condition suffix (<code>COND</code>) is present, branch to <code>label</code> if the condition is true when applied to <code>new_dst</code>; otherwise fall through. ===Base operations (OP)=== The reference interpreter implements these ALU base ops: * Data movement/arithmetic: <code>MOV ADD SUB MUL DIV MOD</code> * Convenience arithmetic: <code>INC DEC NEG ABS MIN MAX</code> * Bitwise: <code>AND OR XOR XNOR NOR NAND NOT</code> * Shifts/rotates: <code>SHL SHR SAR ROL ROR</code> * Bit tricks: <code>POPCNT CLZ CTZ</code> * Comparisons (write results into <code>dst</code>): <code>CMPEQ CMPLT CMPLE CMPGT CMP3</code> * Swap: <code>SWP</code> (special: swaps two addressable operands; immediates are not allowed) === Width (WIDTH) === Optional: <code>8</code>, <code>16</code>, <code>32</code>, <code>64</code>. If provided, results are interpreted as signed integers of that width. If omitted, Tina uses unbounded integers (except some bit-operations internally assume a 64-bit “view” for operations like rotate/counting, per the reference interpreter). === Overflow/checked behavior (OVF) === Only meaningful when a width is present: * (none): wrap to the given width (two’s complement wrap) * <code>S</code>: saturating (clamp to min/max representable signed value) * <code>C</code>: checked (raises an error on overflow) === Conditional suffix (COND) === If present, the instruction takes an additional <code>label</code> argument. Simple conditions (applied to <code>new_dst</code>): * <code>LEQ</code> (≤ 0), <code>EQZ</code> (== 0), <code>NEZ</code> (!= 0) * <code>LTZ</code>, <code>GEZ</code>, <code>GTZ</code> * <code>ODD</code>, <code>EVN</code> * <code>POS</code> (≥ 0), <code>NEG</code> (< 0) Bit-test conditions: * <code>BSET0</code>..<code>BSET63</code> (branch if bit k is 1) * <code>BCLR0</code>..<code>BCLR63</code> (branch if bit k is 0) === SUBLEQ alias === <code>SUBLEQ</code> is an alias for: <pre> SUBLEQ src, dst, label ≡ SUB src, dst, label (branch if new_dst <= 0) </pre> This makes it easy to write classic SUBLEQ-style code while still having a larger instruction set available. ==Control flow and non-ALU instructions== These instructions are not expressed through the ALU matrix: * <code>JMP label</code> — unconditional jump * <code>JMPI op</code> — jump to the value read from <code>op</code> * <code>BR op, label</code> — branch if <code>op != 0</code> Dedicated branches (branch based on <code>op</code>): * <code>BZ</code>, <code>BNZ</code>, <code>BLTZ</code>, <code>BLEQZ</code>, <code>BGEZ</code>, <code>BGTZ</code>, <code>BODD</code>, <code>BEVN</code> Loop helper: * <code>DJNZ dst, label</code> — decrement <code>dst</code>, branch if the result is not zero Misc memory ops: * <code>ZAP dst</code> — set destination to 0 * <code>XCH a, b</code> — exchange two addressable operands (no immediates) ==Stack and calls== These instructions use a conventional stack in memory and rely on two special cells if used: * <code>.cell SP = ...</code> must exist for <code>PUSH/POP/CALL/RET/ENTER/LEAVE</code> * <code>.cell FP = ...</code> must exist for <code>ENTER/LEAVE</code> Instructions: * <code>PUSH op</code> — store value at <code>mem[SP]</code>, then increment <code>SP</code> * <code>POP dst</code> — decrement <code>SP</code>, then load from <code>mem[SP]</code> into <code>dst</code> * <code>CALL label</code>, <code>CALLI op</code> — push return address, jump * <code>RET</code> — pop return address into PC * <code>ENTER #n</code> — push old FP, set FP = SP, allocate <code>n</code> locals by advancing SP * <code>LEAVE</code> — restore SP = FP, restore old FP from stack ==Built-in memory/string instructions== These are “library-like” instructions implemented directly by the interpreter: * <code>MEMSET dstAddr, byte, n</code> : Set <code>n</code> bytes at address <code>dstAddr</code> to <code>byte & 0xFF</code>. * <code>MEMCPY srcAddr, dstAddr, n</code> : Copy <code>n</code> cells; overlap-safe in the reference interpreter. * <code>MEMCMP aAddr, bAddr, n, dst</code> : Compare <code>n</code> cells lexicographically; write -1/0/1 into <code>dst</code>. * <code>STRLENZ srcAddr, dst</code> : Length of a null-terminated byte string. * <code>STRCPYZ srcAddr, dstAddr</code> : Copy a null-terminated byte string including terminator. * <code>STRCMPZ aAddr, bAddr, dst</code> : Compare two null-terminated byte strings; write -1/0/1. Note: <code>srcAddr</code>/<code>dstAddr</code> operands are read as values (addresses). For example, if <code>p</code> contains 100, then <code>STRLENZ p, len</code> measures from address 100. ==Input and output== Input is byte-based or integer-based and shares a single input stream. * <code>INB dst, labelEOF</code> : Read one byte. On EOF, writes -1 to <code>dst</code> and jumps to <code>labelEOF</code>. * <code>INN dst, labelEOF</code> : Read a signed decimal integer token (skipping whitespace). On EOF (or no integer available), jumps to <code>labelEOF</code> (reference interpreter does not guarantee writing anything to <code>dst</code> in this case). Output: * <code>OUTB op</code> — output low byte (<code>&amp; 0xFF</code>) * <code>OUTD op</code> — output decimal integer text (no newline) * <code>OUTHEX op</code> — output as 64-bit-masked hex with <code>0x</code> prefix * <code>OUTBIN op</code> — output as 64-bit-masked binary with <code>0b</code> prefix * <code>OUTZ symbolOrAddr</code> — output null-terminated bytes starting at that address (note: this takes a symbol/address, not a full addressing-mode operand) * <code>OUTZI op</code> — output null-terminated bytes starting at the address read from <code>op</code> * <code>OUTS op</code> — output a length-prefixed string: <code>addr = op</code>, <code>mem[addr]</code> is length, bytes follow at <code>addr+1..</code> * <code>EOL</code> — output newline ==Debug/abort== * <code>TRAP #code</code> — terminate the program with exit code <code>code</code> * <code>ASSERT op, #code</code> — if <code>op == 0</code>, terminate with <code>code</code> * <code>BREAK</code>, <code>WATCH op</code> — present but treated as no-ops by the reference interpreter (useful with tracing/debugging in other implementations) ==Program termination== * <code>HALT</code> returns exit code 0. * Falling off the end of the instruction list ends execution (exit code 0 in the reference interpreter). * <code>TRAP</code>/<code>ASSERT</code> can terminate with non-zero codes. ==Implementation== The reference implementation is a combined assembler and interpreter written in Python 3. Usage: <pre> python tina.py program.tina &lt; input &gt; output python tina.py program.tina --trace </pre> ==Examples== This is a traditional "Hello World" program in Tina: <pre> .zstr MSG "Hello, world!\n" start: OUTZ MSG HALT </pre> This program is a typical truth machine: <pre> .cell ZERO = 0 .cell C48 = 48 ; '0' .cell ch = 0 .cell tmp = 0 start: INB ch, done OUTB ch MOV ch, tmp SUBEQZ C48, tmp, done ; tmp = ch - 48; if tmp == 0 => input was '0' loop: OUTB ch SUBLEQ ZERO, ZERO, loop ; unconditional jump (classic SUBLEQ trick) done: HALT </pre> This program is a simple cat program: <pre> .cell ZERO = 0 .cell ch = 0 loop: INB ch, done OUTB ch SUBLEQ ZERO, ZERO, loop done: HALT </pre> This program is an implementation of Fizz Buzz: <pre> .cell ZERO = 0 .cell ONE = 1 .cell THREE = 3 .cell FIVE = 5 .cell i = 1 .cell rem = 100 .cell c3 = 3 .cell c5 = 5 .cell f = 0 .cell b = 0 .cell tmp = 0 .cell sum = 0 .zstr SFIZZ "Fizz" .zstr SBUZZ "Buzz" loop: ZAP f ZAP b DJNZ c3, no_fizz MOV THREE, c3 MOV ONE, f no_fizz: DJNZ c5, no_buzz MOV FIVE, c5 MOV ONE, b no_buzz: ; if f != 0 print "Fizz" MOV f, tmp SUBEQZ ZERO, tmp, skip_fizz OUTZ SFIZZ skip_fizz: ; if b != 0 print "Buzz" MOV b, tmp SUBEQZ ZERO, tmp, skip_buzz OUTZ SBUZZ skip_buzz: ; if (f+b)==0 print the number MOV f, sum ADD b, sum SUBEQZ ZERO, sum, print_num SUBLEQ ZERO, ZERO, after_num print_num: OUTD i after_num: EOL ADD ONE, i DJNZ rem, loop HALT </pre> This takes a number as input and calculates its factorial: <pre> .cell ZERO = 0 .cell ONE = 1 .cell n = 0 .cell fact = 1 .cell tmp = 0 start: INN n, eof MOV ONE, fact loop: MOV n, tmp SUBLEQ ONE, tmp, print ; tmp = n-1; if tmp <= 0 => n <= 1 => done MUL n, fact ; fact *= n SUB ONE, n ; n-- SUBLEQ ZERO, ZERO, loop print: OUTD fact EOL HALT eof: HALT </pre> This implements a simple [[Brainfuck]] interpreter: <pre> ; Brainfuck interpreter in Tina ; ; Input format on stdin: ; 1) First line: the Brainfuck program (only ><+-.,[] are kept; other chars ignored) ; 2) Remaining bytes after the newline are used as Brainfuck input for ','. ; ; Notes: ; - Tape cells are treated as 8-bit (wrapping) via ADD8/SUB8. ; - Data pointer moves right/left by 1 cell. Moving to a negative address will error. ; -------- fixed “heap” base addresses (picked far away from our .cell area) -------- .cell PROGBASE = 100000 ; program bytes stored at PROGBASE + i .cell JUMPBASE = 200000 ; matching-bracket table at JUMPBASE + i (only for [ and ]) .cell STACKBASE = 300000 ; stack for bracket matching during load .cell TAPEBASE = 400000 ; BF data tape starts here ; -------- required register cells for PUSH/POP -------- .cell SP = 0 .cell FP = 0 ; -------- interpreter state -------- .cell PLEN = 0 ; program length (#instructions kept) .cell IP = 0 ; BF instruction pointer (0..PLEN) .cell DP = 0 ; BF data pointer (address into tape) .cell OP = 0 ; current program byte .cell TMP = 0 .cell FLAG = 0 ; pointers for indirect addressing .cell PPROG = 0 .cell PJUMP = 0 start: MOV STACKBASE, SP ZAP PLEN ZAP IP MOV TAPEBASE, DP JMP load_loop ; --------------------------- load / filter program --------------------------- load_loop: INB OP, load_done ; EOF => done ; stop reading program at newline (LF) MOV OP, FLAG CMPEQNEZ #10, FLAG, load_done ; keep only ><+-.,[] MOV OP, FLAG CMPEQNEZ #62, FLAG, load_store ; '>' MOV OP, FLAG CMPEQNEZ #60, FLAG, load_store ; '<' MOV OP, FLAG CMPEQNEZ #43, FLAG, load_store ; '+' MOV OP, FLAG CMPEQNEZ #45, FLAG, load_store ; '-' MOV OP, FLAG CMPEQNEZ #46, FLAG, load_store ; '.' MOV OP, FLAG CMPEQNEZ #44, FLAG, load_store ; ',' MOV OP, FLAG CMPEQNEZ #91, FLAG, load_store ; '[' MOV OP, FLAG CMPEQNEZ #93, FLAG, load_store ; ']' JMP load_loop load_store: ; PROG[PLEN] = OP MOV PROGBASE, PPROG ADD PLEN, PPROG MOV OP, @PPROG ; if OP == '[' => push its index MOV OP, FLAG CMPEQNEZ #91, FLAG, load_push ; if OP == ']' => pop and create jump links MOV OP, FLAG CMPEQNEZ #93, FLAG, load_pop INC #0, PLEN JMP load_loop load_push: PUSH PLEN INC #0, PLEN JMP load_loop load_pop: ; underflow check: if (SP-STACKBASE) <= 0 => unmatched ']' MOV SP, TMP SUB STACKBASE, TMP BLEQZ TMP, trap_unmatched_close POP TMP ; TMP = matching '[' index ; JUMP[TMP] = PLEN MOV JUMPBASE, PJUMP ADD TMP, PJUMP MOV PLEN, @PJUMP ; JUMP[PLEN] = TMP MOV JUMPBASE, PJUMP ADD PLEN, PJUMP MOV TMP, @PJUMP INC #0, PLEN JMP load_loop load_done: ; if stack not empty => unmatched '[' MOV SP, TMP SUB STACKBASE, TMP BNZ TMP, trap_unmatched_open MOV STACKBASE, SP ; reset stack ZAP IP ; start execution JMP exec_loop ; --------------------------- execute BF program --------------------------- exec_loop: ; if IP >= PLEN => halt MOV PLEN, TMP SUB IP, TMP BLEQZ TMP, done ; OP = PROG[IP] MOV PROGBASE, PPROG ADD IP, PPROG MOV @PPROG, OP ; dispatch on OP MOV OP, FLAG CMPEQNEZ #62, FLAG, op_gt ; '>' MOV OP, FLAG CMPEQNEZ #60, FLAG, op_lt ; '<' MOV OP, FLAG CMPEQNEZ #43, FLAG, op_plus ; '+' MOV OP, FLAG CMPEQNEZ #45, FLAG, op_minus ; '-' MOV OP, FLAG CMPEQNEZ #46, FLAG, op_dot ; '.' MOV OP, FLAG CMPEQNEZ #44, FLAG, op_comma ; ',' MOV OP, FLAG CMPEQNEZ #91, FLAG, op_lbr ; '[' MOV OP, FLAG CMPEQNEZ #93, FLAG, op_rbr ; ']' ; should not happen INC #0, IP JMP exec_loop op_gt: ; '>' INC #0, DP INC #0, IP JMP exec_loop op_lt: ; '<' DEC #0, DP INC #0, IP JMP exec_loop op_plus: ; '+' ADD8 #1, @DP INC #0, IP JMP exec_loop op_minus: ; '-' SUB8 #1, @DP INC #0, IP JMP exec_loop op_dot: ; '.' OUTB @DP INC #0, IP JMP exec_loop op_comma: ; ',' INB TMP, op_comma_eof MOV TMP, @DP INC #0, IP JMP exec_loop op_comma_eof: MOV #0, @DP INC #0, IP JMP exec_loop op_lbr: ; '[' BZ @DP, op_lbr_zero INC #0, IP JMP exec_loop op_lbr_zero: ; IP = JUMP[IP] + 1 MOV JUMPBASE, PJUMP ADD IP, PJUMP MOV @PJUMP, TMP MOV TMP, IP INC #0, IP JMP exec_loop op_rbr: ; ']' BNZ @DP, op_rbr_nz INC #0, IP JMP exec_loop op_rbr_nz: ; IP = JUMP[IP] + 1 (jump back to after matching '[') MOV JUMPBASE, PJUMP ADD IP, PJUMP MOV @PJUMP, TMP MOV TMP, IP INC #0, IP JMP exec_loop done: HALT ; --------------------------- error exits --------------------------- trap_unmatched_close: TRAP #1 ; saw ']' with no matching '[' trap_unmatched_open: TRAP #2 ; program ended with unmatched '[' remaining </pre> ==Computational class== With unbounded memory, arithmetic, and conditional/unconditional jumps, Tina can implement a register machine (or simulate other Turing-complete models). Therefore Tina is [[Turing-complete]] (assuming unbounded time and memory). ==See also== * [[OISC]] * [[Assembly language]] ==External resources== * Reference interpreter/assembler: [[https://github.com/OscarLo11212821/Tina/tree/main|Tina Interpreter]] [[Category:Languages]] [[Category:Implemented]] [[Category:Low-level]] [[Category:Assembly]] [[Category:Turing complete]]'
New page wikitext, after the edit (new_wikitext)
''''Tina''' ('''T'''his '''i'''s '''n'''ot '''a'''ssembly) is an [[esoteric programming language]] made by user [[User:Oscarlo|Oscarlo]] with an assembly-like syntax and a deliberately overpowered “ALU matrix” instruction format. A Tina program is assembled into a linear list of instructions plus an initial memory image, then executed on a simple machine with unbounded signed integer cells and non-negative addresses. A reference interpreter/assembler is implemented in Python. ==Etymology== “Tina” is a backronym for “This is not assembly”. The language is intentionally close to assembly in feel (labels, cells, jumps, stack operations), while also featuring higher-level conveniences like conditional-branching ALU instructions and built-in memory/string operations. ==Computational model== Tina executes a sequence of instructions over: * An unbounded memory of signed integers (cells default to 0). * A program counter (PC) indexing the instruction list. * Optional stack/frame support using two conventional cells named <code>SP</code> and <code>FP</code> when stack instructions are used. Memory addresses must be non-negative; attempting to access a negative address is an error. ==Syntax overview== * One instruction or directive per line. * Labels are written as <code>name:</code> (multiple labels may precede a statement). * Comments begin with <code>;</code> and continue to end of line. * Mnemonics are case-insensitive (the reference interpreter uppercases internally). Example line: <pre> loop: ADD32SNEZ #1, counter, loop ; increment and loop while counter != 0 (example only) </pre> ==Assembler directives== These directives allocate and/or initialize memory in the initial image. ; <code>.cell name = value</code> : Allocate one cell, optionally initialized. If omitted, initializes to 0. Character literals like <code>'A'</code> are allowed (one character only). ; <code>.block name, n</code> : Allocate <code>n</code> zero-initialized cells. ; <code>.data name v1, v2, ...</code> : Allocate a list of cells initialized to the given integers (supports decimal/hex via Python-style <code>0x</code>). ; <code>.zstr name "text"</code> : Allocate a null-terminated byte string. Each character must be in 0..255, and a trailing 0 cell is appended. Symbols defined by these directives can be used as memory operands and (in immediates) as numeric addresses. ==Operands and addressing modes== Tina instructions take ''operands'' which can be immediate values or memory references. ===Immediate=== ; <code>#n</code> : Immediate integer <code>n</code>. In immediates, <code>n</code> may be: :* a numeric literal (<code>#10</code>, <code>#0xFF</code>, <code>#-3</code>) :* a memory symbol (<code>#MSG</code> yields MSG’s address) :* a code label (<code>#loop</code> yields the instruction index of <code>loop:</code>) :* optionally with a small decimal offset: <code>#LABEL+3</code>, <code>#var-1</code> Immediates are not addressable (you cannot write to <code>#...</code>). ===Memory (direct / indexed)=== ; <code>x</code> : Direct cell at address <code>x</code> (where <code>x</code> is a symbol or numeric address). ; <code>x+K</code> / <code>x-K</code> : Direct cell at address <code>x+K</code> (offset is decimal in the reference interpreter). ===Indirect (pointer)=== ; <code>@x</code> : Indirect cell at address <code>mem[x]</code>. ; <code>@x+K</code> : Indirect indexed cell at address <code>mem[x]+K</code>. In pseudocode, reading <code>@p+2</code> means <code>mem[mem[p] + 2]</code>. ==ALU instruction matrix== Most arithmetic/logic operations are expressed with a single general pattern: <pre> <OP><WIDTH><OVF><COND> src, dst [, label] </pre> Execution model: 1. Read <code>src</code> and <code>dst</code>. 2. Compute a new value (<code>new_dst</code>) using <code>OP</code>. 3. Write <code>new_dst</code> back to <code>dst</code>. 4. If a condition suffix (<code>COND</code>) is present, branch to <code>label</code> if the condition is true when applied to <code>new_dst</code>; otherwise fall through. ===Base operations (OP)=== The reference interpreter implements these ALU base ops: * Data movement/arithmetic: <code>MOV ADD SUB MUL DIV MOD</code> * Convenience arithmetic: <code>INC DEC NEG ABS MIN MAX</code> * Bitwise: <code>AND OR XOR XNOR NOR NAND NOT</code> * Shifts/rotates: <code>SHL SHR SAR ROL ROR</code> * Bit tricks: <code>POPCNT CLZ CTZ</code> * Comparisons (write results into <code>dst</code>): <code>CMPEQ CMPLT CMPLE CMPGT CMP3</code> * Swap: <code>SWP</code> (special: swaps two addressable operands; immediates are not allowed) === Width (WIDTH) === Optional: <code>8</code>, <code>16</code>, <code>32</code>, <code>64</code>. If provided, results are interpreted as signed integers of that width. If omitted, Tina uses unbounded integers (except some bit-operations internally assume a 64-bit “view” for operations like rotate/counting, per the reference interpreter). === Overflow/checked behavior (OVF) === Only meaningful when a width is present: * (none): wrap to the given width (two’s complement wrap) * <code>S</code>: saturating (clamp to min/max representable signed value) * <code>C</code>: checked (raises an error on overflow) === Conditional suffix (COND) === If present, the instruction takes an additional <code>label</code> argument. Simple conditions (applied to <code>new_dst</code>): * <code>LEQ</code> (≤ 0), <code>EQZ</code> (== 0), <code>NEZ</code> (!= 0) * <code>LTZ</code>, <code>GEZ</code>, <code>GTZ</code> * <code>ODD</code>, <code>EVN</code> * <code>POS</code> (≥ 0), <code>NEG</code> (< 0) Bit-test conditions: * <code>BSET0</code>..<code>BSET63</code> (branch if bit k is 1) * <code>BCLR0</code>..<code>BCLR63</code> (branch if bit k is 0) === SUBLEQ alias === <code>SUBLEQ</code> is an alias for: <pre> SUBLEQ src, dst, label ≡ SUB src, dst, label (branch if new_dst <= 0) </pre> This makes it easy to write classic SUBLEQ-style code while still having a larger instruction set available. ==Control flow and non-ALU instructions== These instructions are not expressed through the ALU matrix: * <code>JMP label</code> — unconditional jump * <code>JMPI op</code> — jump to the value read from <code>op</code> * <code>BR op, label</code> — branch if <code>op != 0</code> Dedicated branches (branch based on <code>op</code>): * <code>BZ</code>, <code>BNZ</code>, <code>BLTZ</code>, <code>BLEQZ</code>, <code>BGEZ</code>, <code>BGTZ</code>, <code>BODD</code>, <code>BEVN</code> Loop helper: * <code>DJNZ dst, label</code> — decrement <code>dst</code>, branch if the result is not zero Misc memory ops: * <code>ZAP dst</code> — set destination to 0 * <code>XCH a, b</code> — exchange two addressable operands (no immediates) ==Stack and calls== These instructions use a conventional stack in memory and rely on two special cells if used: * <code>.cell SP = ...</code> must exist for <code>PUSH/POP/CALL/RET/ENTER/LEAVE</code> * <code>.cell FP = ...</code> must exist for <code>ENTER/LEAVE</code> Instructions: * <code>PUSH op</code> — store value at <code>mem[SP]</code>, then increment <code>SP</code> * <code>POP dst</code> — decrement <code>SP</code>, then load from <code>mem[SP]</code> into <code>dst</code> * <code>CALL label</code>, <code>CALLI op</code> — push return address, jump * <code>RET</code> — pop return address into PC * <code>ENTER #n</code> — push old FP, set FP = SP, allocate <code>n</code> locals by advancing SP * <code>LEAVE</code> — restore SP = FP, restore old FP from stack ==Built-in memory/string instructions== These are “library-like” instructions implemented directly by the interpreter: * <code>MEMSET dstAddr, byte, n</code> : Set <code>n</code> bytes at address <code>dstAddr</code> to <code>byte & 0xFF</code>. * <code>MEMCPY srcAddr, dstAddr, n</code> : Copy <code>n</code> cells; overlap-safe in the reference interpreter. * <code>MEMCMP aAddr, bAddr, n, dst</code> : Compare <code>n</code> cells lexicographically; write -1/0/1 into <code>dst</code>. * <code>STRLENZ srcAddr, dst</code> : Length of a null-terminated byte string. * <code>STRCPYZ srcAddr, dstAddr</code> : Copy a null-terminated byte string including terminator. * <code>STRCMPZ aAddr, bAddr, dst</code> : Compare two null-terminated byte strings; write -1/0/1. Note: <code>srcAddr</code>/<code>dstAddr</code> operands are read as values (addresses). For example, if <code>p</code> contains 100, then <code>STRLENZ p, len</code> measures from address 100. ==Input and output== Input is byte-based or integer-based and shares a single input stream. * <code>INB dst, labelEOF</code> : Read one byte. On EOF, writes -1 to <code>dst</code> and jumps to <code>labelEOF</code>. * <code>INN dst, labelEOF</code> : Read a signed decimal integer token (skipping whitespace). On EOF (or no integer available), jumps to <code>labelEOF</code> (reference interpreter does not guarantee writing anything to <code>dst</code> in this case). Output: * <code>OUTB op</code> — output low byte (<code>&amp; 0xFF</code>) * <code>OUTD op</code> — output decimal integer text (no newline) * <code>OUTHEX op</code> — output as 64-bit-masked hex with <code>0x</code> prefix * <code>OUTBIN op</code> — output as 64-bit-masked binary with <code>0b</code> prefix * <code>OUTZ symbolOrAddr</code> — output null-terminated bytes starting at that address (note: this takes a symbol/address, not a full addressing-mode operand) * <code>OUTZI op</code> — output null-terminated bytes starting at the address read from <code>op</code> * <code>OUTS op</code> — output a length-prefixed string: <code>addr = op</code>, <code>mem[addr]</code> is length, bytes follow at <code>addr+1..</code> * <code>EOL</code> — output newline ==Debug/abort== * <code>TRAP #code</code> — terminate the program with exit code <code>code</code> * <code>ASSERT op, #code</code> — if <code>op == 0</code>, terminate with <code>code</code> * <code>BREAK</code>, <code>WATCH op</code> — present but treated as no-ops by the reference interpreter (useful with tracing/debugging in other implementations) ==Program termination== * <code>HALT</code> returns exit code 0. * Falling off the end of the instruction list ends execution (exit code 0 in the reference interpreter). * <code>TRAP</code>/<code>ASSERT</code> can terminate with non-zero codes. ==Implementation== The reference implementation is a combined assembler and interpreter written in Python 3. Usage: <pre> python tina.py program.tina &lt; input &gt; output python tina.py program.tina --trace </pre> ==Examples== This is a traditional "Hello World" program in Tina: <pre> .zstr MSG "Hello, world!\n" start: OUTZ MSG HALT </pre> This program is a typical truth machine: <pre> .cell ZERO = 0 .cell C48 = 48 ; '0' .cell ch = 0 .cell tmp = 0 start: INB ch, done OUTB ch MOV ch, tmp SUBEQZ C48, tmp, done ; tmp = ch - 48; if tmp == 0 => input was '0' loop: OUTB ch SUBLEQ ZERO, ZERO, loop ; unconditional jump (classic SUBLEQ trick) done: HALT </pre> This program is a simple cat program: <pre> .cell ZERO = 0 .cell ch = 0 loop: INB ch, done OUTB ch SUBLEQ ZERO, ZERO, loop done: HALT </pre> This program is an implementation of Fizz Buzz: <pre> .cell ZERO = 0 .cell ONE = 1 .cell THREE = 3 .cell FIVE = 5 .cell i = 1 .cell rem = 100 .cell c3 = 3 .cell c5 = 5 .cell f = 0 .cell b = 0 .cell tmp = 0 .cell sum = 0 .zstr SFIZZ "Fizz" .zstr SBUZZ "Buzz" loop: ZAP f ZAP b DJNZ c3, no_fizz MOV THREE, c3 MOV ONE, f no_fizz: DJNZ c5, no_buzz MOV FIVE, c5 MOV ONE, b no_buzz: ; if f != 0 print "Fizz" MOV f, tmp SUBEQZ ZERO, tmp, skip_fizz OUTZ SFIZZ skip_fizz: ; if b != 0 print "Buzz" MOV b, tmp SUBEQZ ZERO, tmp, skip_buzz OUTZ SBUZZ skip_buzz: ; if (f+b)==0 print the number MOV f, sum ADD b, sum SUBEQZ ZERO, sum, print_num SUBLEQ ZERO, ZERO, after_num print_num: OUTD i after_num: EOL ADD ONE, i DJNZ rem, loop HALT </pre> This takes a number as input and calculates its factorial: <pre> .cell ZERO = 0 .cell ONE = 1 .cell n = 0 .cell fact = 1 .cell tmp = 0 start: INN n, eof MOV ONE, fact loop: MOV n, tmp SUBLEQ ONE, tmp, print ; tmp = n-1; if tmp <= 0 => n <= 1 => done MUL n, fact ; fact *= n SUB ONE, n ; n-- SUBLEQ ZERO, ZERO, loop print: OUTD fact EOL HALT eof: HALT </pre> This implements a simple [[Brainfuck]] interpreter: <pre> ; Brainfuck interpreter in Tina ; ; Input format on stdin: ; 1) First line: the Brainfuck program (only ><+-.,[] are kept; other chars ignored) ; 2) Remaining bytes after the newline are used as Brainfuck input for ','. ; ; Notes: ; - Tape cells are treated as 8-bit (wrapping) via ADD8/SUB8. ; - Data pointer moves right/left by 1 cell. Moving to a negative address will error. ; -------- fixed “heap” base addresses (picked far away from our .cell area) -------- .cell PROGBASE = 100000 ; program bytes stored at PROGBASE + i .cell JUMPBASE = 200000 ; matching-bracket table at JUMPBASE + i (only for [ and ]) .cell STACKBASE = 300000 ; stack for bracket matching during load .cell TAPEBASE = 400000 ; BF data tape starts here ; -------- required register cells for PUSH/POP -------- .cell SP = 0 .cell FP = 0 ; -------- interpreter state -------- .cell PLEN = 0 ; program length (#instructions kept) .cell IP = 0 ; BF instruction pointer (0..PLEN) .cell DP = 0 ; BF data pointer (address into tape) .cell OP = 0 ; current program byte .cell TMP = 0 .cell FLAG = 0 ; pointers for indirect addressing .cell PPROG = 0 .cell PJUMP = 0 start: MOV STACKBASE, SP ZAP PLEN ZAP IP MOV TAPEBASE, DP JMP load_loop ; --------------------------- load / filter program --------------------------- load_loop: INB OP, load_done ; EOF => done ; stop reading program at newline (LF) MOV OP, FLAG CMPEQNEZ #10, FLAG, load_done ; keep only ><+-.,[] MOV OP, FLAG CMPEQNEZ #62, FLAG, load_store ; '>' MOV OP, FLAG CMPEQNEZ #60, FLAG, load_store ; '<' MOV OP, FLAG CMPEQNEZ #43, FLAG, load_store ; '+' MOV OP, FLAG CMPEQNEZ #45, FLAG, load_store ; '-' MOV OP, FLAG CMPEQNEZ #46, FLAG, load_store ; '.' MOV OP, FLAG CMPEQNEZ #44, FLAG, load_store ; ',' MOV OP, FLAG CMPEQNEZ #91, FLAG, load_store ; '[' MOV OP, FLAG CMPEQNEZ #93, FLAG, load_store ; ']' JMP load_loop load_store: ; PROG[PLEN] = OP MOV PROGBASE, PPROG ADD PLEN, PPROG MOV OP, @PPROG ; if OP == '[' => push its index MOV OP, FLAG CMPEQNEZ #91, FLAG, load_push ; if OP == ']' => pop and create jump links MOV OP, FLAG CMPEQNEZ #93, FLAG, load_pop INC #0, PLEN JMP load_loop load_push: PUSH PLEN INC #0, PLEN JMP load_loop load_pop: ; underflow check: if (SP-STACKBASE) <= 0 => unmatched ']' MOV SP, TMP SUB STACKBASE, TMP BLEQZ TMP, trap_unmatched_close POP TMP ; TMP = matching '[' index ; JUMP[TMP] = PLEN MOV JUMPBASE, PJUMP ADD TMP, PJUMP MOV PLEN, @PJUMP ; JUMP[PLEN] = TMP MOV JUMPBASE, PJUMP ADD PLEN, PJUMP MOV TMP, @PJUMP INC #0, PLEN JMP load_loop load_done: ; if stack not empty => unmatched '[' MOV SP, TMP SUB STACKBASE, TMP BNZ TMP, trap_unmatched_open MOV STACKBASE, SP ; reset stack ZAP IP ; start execution JMP exec_loop ; --------------------------- execute BF program --------------------------- exec_loop: ; if IP >= PLEN => halt MOV PLEN, TMP SUB IP, TMP BLEQZ TMP, done ; OP = PROG[IP] MOV PROGBASE, PPROG ADD IP, PPROG MOV @PPROG, OP ; dispatch on OP MOV OP, FLAG CMPEQNEZ #62, FLAG, op_gt ; '>' MOV OP, FLAG CMPEQNEZ #60, FLAG, op_lt ; '<' MOV OP, FLAG CMPEQNEZ #43, FLAG, op_plus ; '+' MOV OP, FLAG CMPEQNEZ #45, FLAG, op_minus ; '-' MOV OP, FLAG CMPEQNEZ #46, FLAG, op_dot ; '.' MOV OP, FLAG CMPEQNEZ #44, FLAG, op_comma ; ',' MOV OP, FLAG CMPEQNEZ #91, FLAG, op_lbr ; '[' MOV OP, FLAG CMPEQNEZ #93, FLAG, op_rbr ; ']' ; should not happen INC #0, IP JMP exec_loop op_gt: ; '>' INC #0, DP INC #0, IP JMP exec_loop op_lt: ; '<' DEC #0, DP INC #0, IP JMP exec_loop op_plus: ; '+' ADD8 #1, @DP INC #0, IP JMP exec_loop op_minus: ; '-' SUB8 #1, @DP INC #0, IP JMP exec_loop op_dot: ; '.' OUTB @DP INC #0, IP JMP exec_loop op_comma: ; ',' INB TMP, op_comma_eof MOV TMP, @DP INC #0, IP JMP exec_loop op_comma_eof: MOV #0, @DP INC #0, IP JMP exec_loop op_lbr: ; '[' BZ @DP, op_lbr_zero INC #0, IP JMP exec_loop op_lbr_zero: ; IP = JUMP[IP] + 1 MOV JUMPBASE, PJUMP ADD IP, PJUMP MOV @PJUMP, TMP MOV TMP, IP INC #0, IP JMP exec_loop op_rbr: ; ']' BNZ @DP, op_rbr_nz INC #0, IP JMP exec_loop op_rbr_nz: ; IP = JUMP[IP] + 1 (jump back to after matching '[') MOV JUMPBASE, PJUMP ADD IP, PJUMP MOV @PJUMP, TMP MOV TMP, IP INC #0, IP JMP exec_loop done: HALT ; --------------------------- error exits --------------------------- trap_unmatched_close: TRAP #1 ; saw ']' with no matching '[' trap_unmatched_open: TRAP #2 ; program ended with unmatched '[' remaining </pre> ==Computational class== With unbounded memory, arithmetic, and conditional/unconditional jumps, Tina can implement a register machine (or simulate other Turing-complete models). Therefore Tina is [[Turing-complete]] (assuming unbounded time and memory). ==See also== * [[OISC]] * [[Assembly language]] ==External resources== * Reference interpreter/assembler: [[https://github.com/OscarLo11212821/Tina/tree/main|Tina Interpreter]] [[Category:Languages]] [[Category:Implemented]] [[Category:Low-level]] [[Category:Assembly]] [[Category:Turing complete]]'
Unified diff of changes made by edit (edit_diff)
'@@ -1,3 +1,3 @@ -'''Tina''' ('''T'''his '''i'''s '''n'''ot '''a'''ssembly) is an [[esoteric programming language]] with an assembly-like syntax and a deliberately overpowered “ALU matrix” instruction format. A Tina program is assembled into a linear list of instructions plus an initial memory image, then executed on a simple machine with unbounded signed integer cells and non-negative addresses. +'''Tina''' ('''T'''his '''i'''s '''n'''ot '''a'''ssembly) is an [[esoteric programming language]] made by user [[User:Oscarlo|Oscarlo]] with an assembly-like syntax and a deliberately overpowered “ALU matrix” instruction format. A Tina program is assembled into a linear list of instructions plus an initial memory image, then executed on a simple machine with unbounded signed integer cells and non-negative addresses. A reference interpreter/assembler is implemented in Python. '
New page size (new_size)
18238
Old page size (old_size)
18200
Lines added in edit (added_lines)
[ 0 => ''''Tina''' ('''T'''his '''i'''s '''n'''ot '''a'''ssembly) is an [[esoteric programming language]] made by user [[User:Oscarlo|Oscarlo]] with an assembly-like syntax and a deliberately overpowered “ALU matrix” instruction format. A Tina program is assembled into a linear list of instructions plus an initial memory image, then executed on a simple machine with unbounded signed integer cells and non-negative addresses.' ]
Unix timestamp of change (timestamp)
'1769506156'