FRAK
From Esolang
FRAK is an assembler for the esoteric language brainfuck. It works by simulating an 8-bit conventional computer on the brainfuck machine. The simulated architecture is a RISC whose instruction set is inspired by Processor/1. The word "Frak" is the offensive word used in Battlestar Galactica instead of fuck. It was selected to represent the fact that an assembler 'fracked' the goal of brainfuck by allowing the writing of brainfuck program in an intuitive and not clever way.
Since FRAK's goal is to produce a proof of concept, it has many limitations: programs cannot address more than 256 bytes of memory (8-bit addresses), some operations are slow (those which are unknown to native brainfuck such as bitwise manipulations, if-then-else, etc.) and the instruction set is limited (no floating point support, etc.).
FRAK could be improved by widening registers (16-bit would be enough to map the standard 30 000 byte memory, but 64 or 128 would taste more esoteric), extending the instruction set (a CISC would allow more efficient instructions on brainfuck 'hardware').
Contents |
[edit] Architecture
FRAK has General Purpose Registers (GPR) accessible by the programmer, a System Register (SR) hidden from the programmer, Control Registers (CR) accessible to the programmer but altered as a side effect of operations, and Scratch Cells that are used by the system.
[edit] Instruction Set
| Name | Description | CR0 change | Example | ||
|---|---|---|---|---|---|
A r0,r1
| ADD | Adds register r1 to register r0. | 1 if carry, 0 otherwise | A 3,1
| Adds r1 to r3 |
AND r0,r1
| BITWISE AND | Performs a bitwise AND between register r0 and register r1 and stores the result into register r0. | AND 3,1
| r1 AND r3 | |
BAND r0,r1
| BOOLEAN AND | Performs a boolean AND between register r0 and register r1 and stores the result into register r0. | BAND 3,1
| r1 and r3 | |
BNOT r0
| BOOLEAN NOT | Applies a boolean NOT to register r0. | BNOT 3
| not r3 | |
BOR r0,r1
| BOOLEAN OR | Performs a boolean OR between register r0 and register r1 and stores the result into register r0. | BAND 3,1
| r1 and r3 | |
DEC r0
| DECREMENT | Subtracts 1 from register r0. | 1 if wrap around, 0 otherwise | DEC 3
| Subtracts 1 from r3 |
DO r0
| LOOP STATEMENT | While r0 is not null, execution will continue. Otherwise, execution jumps to after the matching OD. When the matching OD is encountered, execution jumps back to the matching DO and r0 is tested again. |
|
Sets r1 to 1 | |
DIV r0,r1
| DIVIDE | Divides register r0 by register r1. | 1 if the remainder is not 0, 0 otherwise | DIV 2,0
| Divides r2 by r0 |
ELSE r0
| CONDITIONAL STATEMENT | If the value of register r0 is null, execution will continue. Otherwise, execution will jump to after the matching ESLE instruction. |
|
If r3 = 0 | |
GET r0
| INPUT | Inputs the next byte into register r0. | GET 1
| Inputs the next byte into r1. | |
IF r0
| CONDITIONAL STATEMENT | If the value of register r0 is not zero, execution will continue. Otherwise, execution will jump to after the matching FI instruction. |
|
If r3 is not null | |
LI r0,i0
| LOAD IMMEDIATE | Sets the value of register r0 to the immediate value i0. | LI 3,15
| Sets r3 to 15 | |
INC r0
| INCREMENT | Adds 1 to register r0. | 1 if carry, 0 otherwise | INC 3
| Adds 1 to r3 |
L r0,r1
| LOAD | Loads the byte at the address pointed by register r1 into register r0. | L 1,3
| Loads the byte at the address pointed to by r3 into r0. | |
LR r0,r1
| LOAD REGISTER | Copies register r1 to register r0. | LR 2,0
| Copies r0 to r2 | |
MOD r0,r1
| MODULO | Divides register r0 by register r1 and sets register r0 to the remainder. | 1 if the remainder is not 0, 0 otherwise | MOD 2,0
| Divides r2 by r0 and sets r2 to the remainder |
MUL r0,r1
| MULTIPLY | Multiplies register r0 by register r1. | 1 if overflow, 0 otherwise | MUL 2,0
| Multiplies r2 by r0 |
NOT r0
| BITWISE NOT | Applies a bitwise NOT to the value of register r0. | NOT 0
| Invert r0 | |
OR r0,r1
| BITWISE OR | Performs a bitwise OR between register r0 and register r1 and stores the result into register r0. | OR 2,1
| r2 OR r1 | |
PUT r0
| OUTPUT | Outputs the byte in register r0. | PUT 1
| Outputs r1. | |
S r0,r1
| SUBTRACT | Subtracts register r1 from register r0. | 1 if wrap around, 0 otherwise | S 3,1
| Subtracts r1 to r3 |
SL r0
| SHIFT LEFT | Shifts register r0 to the left. | 1 if the leftmost bit was on | SL 3
| Shift left r3 |
SR r0
| SHIFT RIGHT | Shifts register r0 to the right. | 1 if the rightmost bit was on | SR 3
| Shift right r3 |
ST r0,r1
| STORE | Stores register r0 at the address pointed to by register r1. | ST 1,3
| Store r1 at the address pointed to by r3 | |
[edit] Code examples
This program adds 100 to 200 and sets register 2 to 255 if the result overflows (which is always the case ...):
LI 0,200 LOADS IMMEDIATE VALUE 200 INTO GPR 0 LI 1,100 LOADS IMMEDIATE VALUE 100 INTO GPR 0 A 0,1 ADDS GPR 1 TO GPR 0 IF c0 IF CR 0 IS NULL JUMP TO THE MATCHING FI LI 2,X'FF' LOADS IMMEDIATE VALUE 0xFF (255) INTO GPR 2 FI c0
[edit] External resources
- FRAK assembler (JavaScript implementation, with 8 GPR)

