Masfix has 4 so called "registers":
h- position of the read-write head, effecfivelly the current memory addressm- contents of the currently selected memory cell (by the h register)r- general purpose internal register, keeps its contents with head movementsp- instruction pointer, contains the address of the currently executed instruction, increments after each instruction
These 4 instructions are used for setting the values of registers:
mov- stores the value into the h register, efectively moving the head along the memorystr- stores the value into the active memory cellld- stores the value into the internal r registerjmp- stores the value into the instruction pointer, effectively altering the execution flow
Instructions behave like simple variable assignments.
Suffixes specify shape of the assignment.
Left side of the assignment is the destination register of the instruction.
The right side (called target value) can take these forms:
- immediate value
- register
- operation between a register and an immediate value
The modifier operation changes the destination by the target like <destination> <operation>= <target>,
examples could be lda 1 ; r += 1 or strtrs 5 ; m *= r - 5.
Only the 4 basic instructions are allowed a modifier.
Immediate value supplied to the instruction. It's possible forms are:
- A numerical value in the range [0, 65535] (maximum of 16 bit unsigned int)
- A label name, gets replaced with the address of the label
ld 5 ; r = 5
movm ; h = m
strrs 2 ; m = r - 2
ldamt 2 ; r += m * 2
Breakdown of last instruction's ldamt 2 fields:
| field | ld (load) | a (add) | m (memory) | t (times) | 2 |
|---|---|---|---|---|---|
| type | instruction | modifier | register | intermediate operation | immediate value |
| description | specifies instruction performed, here the destination will be r | operation modifying the destination by target value | register used as argument | operation between register and immediate value | constant value |
- Instructions are generally evaluated from right to left:
- load the immediate value, if present
- load the register argument, if present
- perform the intermediate operation between the register and the immediate, if used
- perform the modifier operation, taking the instruction's destination as the first argument and the previously computed value as the second
- store the result into the destination
Test some condition between condition register (r / m) and target value.
Condition register may be omitted - default is r.
Example: lmltra 7 ; r = m < (r + 7)
| field | l | m | lt | r a 7 |
|---|---|---|---|---|
| type | conditional load | memory register | condition | other suffixes |
| description | loads condition result (0/1) to r | comparison LHS - memory (default r) | < - signed less than |
suffixes forming the RHS of comparison |
Branches test the condition register against 0.
If the condition holds, then the instruction pointer is assigned the value of target.
Examples:
beq <label> ; jumps to <label> if r == 0
bmge label2 ; jumps to label2 if m >= 0
brltm< 15 ; jumps to (m << 15) if r < 0
; WARNING - the above doesn't mean "jump to 15 if r < m"!
These perform a comparison between the condition register and target and store a boolean value {0, 1} into the destination.
l- stores the result in rs- stores the result in m
Examples:
seq 56 ; m = (r == 56)
lmltra 7 ; r = m < (r + 7)
Conditions compare two numbers either as signed or unsigned.
| cond | meaning | description |
|---|---|---|
eq |
reg == sec | true if all bits are equal |
ne |
reg != sec | true if any bits are not equal |
lt |
reg < sec | performs (reg - sec), then tests the sign bit of the result to be set |
le |
reg <= sec | performs (reg - sec), then tests the sign bit of the result to be set or the result equal to 0 |
gt |
reg > sec | performs (reg - sec), then tests the sign bit of the result to be clear and the result not equal to 0 |
ge |
reg >= sec | performs (reg - sec), then tests the sign bit of the result to be clear |
ab |
reg > sec | unsigned above |
ae |
reg >= sec | unsigned above equal |
bl |
reg < sec | unsigned below |
be |
reg <= sec | unsigned below equal |
These instructions are called "special" meaning they have restricted suffixes. They are mainly IO instructions.
outcaka "output char" - prints the lowest 8 bits of the target as a char into the stdoutoutuaka "output unsigned" - prints the target as an unsigned int into the stdout
The only suffix can be a register r / m specifying the destination, the default is r
incaka "input char" - blocks for input, eats a single char from the stdin and stores it in the destination.ipcaka "input peek char" - same as inc, but only peeks the char (doesn't consume it).inuaka "input unsigned" - blocks, eats all numerical chars, if it encounters a nonnumeric one it and stops and leaves it unconsumed. Constructs an unsigned int clamped to the wordsize out of the chars.inlaka "input new line" - consumes chars untill '\n' is eaten, does not influence any registers, has no suffixes nor immediate, it's main reason is to simplify handling of the '\n' or '\r\n' line breaks.
swap- swaps the contents of m and r, has no suffixes nor immediate
Examples:
Consider this example program when we feed it "xa065Ab\n-u \n" as stdin
inc ; r = 'x'
incm ; m = 'a'
inum ; m = 65
inl ; eats 'Ab\n'
inc ; r = '-'
ipc ; r = 'u', does not eat it
inu ; r = 0, leaves "u \n" unprocessed
swap ; r = 65, m = '-'
outcr ; prints 'A'
outcmt 2 ; prints ('-' * 2) = 90 = 'Z'
outurs 30 ; prints (65 - 30) = 35
Operations perform aritmetic or bitwise operations between registers and immediate value.
Operands "come in the same order" (L/R) as in the instruction suffix.
Their results are always constrained to 16 bits (even intermediate calculations)
a- additions- subtractiont- unsigned multiplication
&- bitwise and|- bitwise or^- bitwise xor<- binary shift left>- binary shift right.- bit
Note: The last three operations are defined only for shifts of 0 - 16 (technically 0 - 63) bits due to underlying implementation of bit shifts.
Examples:
; Assume r = 13 = 0x1101 for each line
ldr& 10 ; r = 0x1000
ldr| 17 ; r = 0x11101
ld^ 6 ; r = 0x1011
ld> 2 ; r = 0x11
ld< 3 ; r = 0x1101000
ld. 2 ; r = 1
ld. 1 ; r = 0
Labels are used to simplify addressing of instructions in the source code.
When used in instruction immediate, they are replaced with the exact address of instruction directly following the label definition.
Label definition needs to be first on line, starting with : followed by the label name.
:label <possible-instr>
- predefined labels:
begin- address 0end- address after the last instruction
Instruction / label names can be constructed from multiple fields.
Useful for defining labels / using instructions with preprocessor information.
In instructions first letter must be inplace.
%macro l_cond_instr(condReg, cond, op, imm) {
l(%condReg)(%cond)r(%op) %imm
}
%l_cond_instr(m, "lt", &, 15)
; expands to lmltr& 15