Skip to content

Commit

Permalink
Adds a general conditional jump instruction (#44)
Browse files Browse the repository at this point in the history
* Adds pseudo instructions for all comparisons
* Updates example programs
* Updates bf compiler
* Updates README
  • Loading branch information
Frank Stokes committed Aug 3, 2017
1 parent 8598714 commit 935290b
Show file tree
Hide file tree
Showing 19 changed files with 163 additions and 108 deletions.
27 changes: 23 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ A couple of examples illustrating the language can be found in the `asm/` folder
|`ATH`| `D, S, O, M, B` | `BBBMOOOOSSDD0100` | Perform an arithmetic operation on the source and destination registers. O specifies the operation (listed below) and M is the mode, where 0 = place result in destination register and 1 = place result in source register. If the instruction is right or left shift then B specifies the shifting value|
|`CAL`| `D` | `XXXXXXXXXXDD0101` | Call a function in memory pointed at by the destination register|
|`RET`| | `XXXXXXXXXXXX0110` | Return from function|
|`JLT`| `D, S` | `XXXXXXXXSSDD0111` | Jump to memory address pointed at by the source register, if value in the A register is less than value in destination register|
|`JCP`| `D, S, A, O` | `XXXOOOAASSDD0111` | Jump to memory address pointed at by the address register, depending on the comparison specified by the O operation of the destination register and the source register. Operation table specified below.|
|`PSH`| `S` | `XXXXXXXXSSXX1000` | Push the value in source register onto the stack|
|`POP`| `D` | `XXXXXXXXXXDD1001` | Pop the stack into the destination register|
|`SYS`| | `XXXXXXXXXXXX1010` | Perform a system call. This is described below in more detail.|
Expand Down Expand Up @@ -89,9 +89,14 @@ Pseudo instructions are prepocessed by the assembler and expanded into combinati
|`NOT` | `D` |1 | Binary not (invert) the destination|
|`LDV16` | `D, V` |2 | Load a 16 bit value into destination|
|`SWP` | `D, S` |3 | Swap the values in the source and destination registers|
|`JGE` | `D, A` |4 | Jump to address A if value in destination register is greater than or equal to the A register. Can potentially mutate all registers except A and destination|
|`JEQ` | `D, A` |11 | Jump to address A if value in destination register is equal to the A register. Can potentially mutate all registers except A and destination|
|`JNE` | `D, A` |14 | Jump to address A if value in destination register is not equal to the A register. Can potentially mutate all registers except A and destination|
|`JEQ` | `D, S, A` |1 | Jump to address A if value in destination register is equal to the source register.|
|`JNE` | `D, S, A` |1 | Jump to address A if value in destination register is not equal to the source register.|
|`JLT` | `D, S, A` |1 | Jump to address A if value in destination register is less than the source register.|
|`JGT` | `D, S, A` |1 | Jump to address A if value in destination register is greater than the source register.|
|`JLE` | `D, S, A` |1 | Jump to address A if value in destination register is less than or equal to the source register.|
|`JGE` | `D, S, A` |1 | Jump to address A if value in destination register is greater than or equal to the source register.|
|`JZE` | `D, S, A` |1 | Jump to address A if value in destination register is zero.|
|`JNZ` | `D, S, A` |1 | Jump to address A if value in destination register is not zero.|


#### Arithmetic Operation table
Expand All @@ -111,6 +116,20 @@ Pseudo instructions are prepocessed by the assembler and expanded into combinati
|`Xor` |`1010` |
|`Not` |`1011` |

#### Conditional Jump Operation table

|Operation |Value |
|-------------------------|-------|
|`Equal` |`000` |
|`Not equal` |`001` |
|`Less than` |`010` |
|`Greater than` |`011` |
|`Less than or equal` |`100` |
|`Greater than or equal` |`101` |
|`Zero` |`110` |
|`Not zero` |`111` |


#### System calls

A system call in the VM allows the program to ask resources outside of it's context, such as communication with stdin and stdout. System calls are passed off to the os module and can return their results directly into the CPUs registers.
Expand Down
2 changes: 1 addition & 1 deletion asm/factorial.asm
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ factorial:
pop A
ldv B, 3
ldv D, done:
jlt B, D
JLT A, B, D

psh a
psh b
Expand Down
4 changes: 2 additions & 2 deletions asm/get-name.asm
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ get_name:
ldv d, get_name:
mov a, b
ldv b, 1
jlt b, d ; if a < 1, loop
jlt a, b, d ; if a < 1, loop

;;;;; Place character into memory ;;;;
ldv b, .name ; get the start address of name
Expand All @@ -39,7 +39,7 @@ get_name:

;;;;; Got all the characters? ;;;;;;;;
ldv c, final_zero:
jlt b, c ; if (a < b) = (name_max < name_pointer), we are done
jlt a, b, c ; if (a < b) = (name_max < name_pointer), we are done
ldv c, get_name: ; otherwise jump back to the beginning to get the next character
jmr c

Expand Down
2 changes: 1 addition & 1 deletion asm/loop-until-a-is-pressed.asm
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ main:

loop:
cal D
jne B, C
jne A, B, C

hlt
5 changes: 3 additions & 2 deletions src/assembler/assembler/instruction-encoder.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ const {
SOURCE_SHIFT,
LONG_ADDRESS_SHIFT,
OFFSET_SHIFT,
ADDRESS_SHIFT,

JUMP,

ARITHMETIC_MODE_SHIFT,
OPERATION_SHIFT,
Expand Down Expand Up @@ -34,7 +35,7 @@ module.exports = {
STR: (args) => opcodes.STR | (reg[args[0]] << DESTINATION_SHIFT) | (reg[args[1]] << SOURCE_SHIFT) | (args.length > 2 ? (args[2] << OFFSET_SHIFT) : 0),
ATH: (args) => opcodes.ATH | (reg[args[0]] << DESTINATION_SHIFT) | (reg[args[1]] << SOURCE_SHIFT) | (args[2] << OPERATION_SHIFT) | (args[3] << ARITHMETIC_MODE_SHIFT) | (args[4] << BITWISE_SHIFT_SHIFT),
CAL: (args) => opcodes.CAL | (reg[args[0]] << DESTINATION_SHIFT),
JLT: (args) => opcodes.JLT | (reg[args[0]] << DESTINATION_SHIFT) | (reg[args[1]] << SOURCE_SHIFT),
JCP: (args) => opcodes.JCP | (reg[args[0]] << JUMP.R1) | (reg[args[1]] << JUMP.R2) | (reg[args[2]] << JUMP.AR) | (args[3] << JUMP.OP),
PSH: (args) => opcodes.PSH | (reg[args[0]] << SOURCE_SHIFT),
POP: (args) => opcodes.POP | (reg[args[0]] << DESTINATION_SHIFT),
JMP: (args) => opcodes.JMP | (reg[args[0]] << DESTINATION_SHIFT) | (args[1] << LONG_ADDRESS_SHIFT),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,43 +1,7 @@
const {
getInstructionArguments,
uniqueLabel,
getUsableRegister
} = require('../../../../utils');
const { getInstructionArguments } = require('../../../../utils');
const { JUMP } = require('../../../../../../constants');

module.exports = (instruction) => {
const [source, addressRegister] = getInstructionArguments(instruction);
const mutableRegister = getUsableRegister(source, addressRegister);

const firstCheck = uniqueLabel();
const equal = uniqueLabel();
const notEqual = uniqueLabel();

return [
`PSH ${mutableRegister}`, // Push mr [mr]

`PSH ${addressRegister}`, // Push ar [ar, mr]
`LDV16 ${addressRegister}, ${firstCheck}`,
`LDV16 ${mutableRegister}, ${notEqual}`,

`JGE ${source}, ${addressRegister}`,
`JMR ${mutableRegister}`,

`${firstCheck}`,
`LDV16 ${addressRegister}, ${equal}`,
`SWP A, ${source}`,
`JGE ${source}, ${addressRegister}`,

`SWP A, ${source}`,
`JMR ${mutableRegister}`,

`${equal}`,
`SWP A, ${source}`,
`POP ${addressRegister}`, // Pop ar [mr]
`POP ${mutableRegister}`, // Pop mr []
`JMR ${addressRegister}`,

`${notEqual}`,
`POP ${addressRegister}`, // Pop ar [mr]
`POP ${mutableRegister}` // Pop mr []
];
}
const [r1, r2, addressRegister] = getInstructionArguments(instruction);
return [`JCP ${r1}, ${r2}, ${addressRegister}, ${JUMP.EQ}`];
};
Original file line number Diff line number Diff line change
@@ -1,24 +1,7 @@
const {
getInstructionArguments,
uniqueLabel,
getUsableRegister
} = require('../../../../utils');

const { getInstructionArguments } = require('../../../../utils');
const { JUMP } = require('../../../../../../constants');

module.exports = (instruction) => {
const [source, addressRegister] = getInstructionArguments(instruction);
const lessThan = uniqueLabel();
const mutableRegister = getUsableRegister(source, addressRegister);

return [
`PSH ${mutableRegister}`,
`LDV16 ${mutableRegister}, ${lessThan}`,

`JLT ${source}, ${mutableRegister}`,
`POP ${mutableRegister}`,
`JMR ${addressRegister}`,

`${lessThan}`,
`POP ${mutableRegister}`
];
}
const [r1, r2, addressRegister] = getInstructionArguments(instruction);
return [`JCP ${r1}, ${r2}, ${addressRegister}, ${JUMP.GTE}`];
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const { getInstructionArguments } = require('../../../../utils');
const { JUMP } = require('../../../../../../constants');

module.exports = (instruction) => {
const [r1, r2, addressRegister] = getInstructionArguments(instruction);
return [`JCP ${r1}, ${r2}, ${addressRegister}, ${JUMP.GT}`];
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const { getInstructionArguments } = require('../../../../utils');
const { JUMP } = require('../../../../../../constants');

module.exports = (instruction) => {
const [r1, r2, addressRegister] = getInstructionArguments(instruction);
return [`JCP ${r1}, ${r2}, ${addressRegister}, ${JUMP.JLE}`];
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const { getInstructionArguments } = require('../../../../utils');
const { JUMP } = require('../../../../../../constants');

module.exports = (instruction) => {
const [r1, r2, addressRegister] = getInstructionArguments(instruction);
return [`JCP ${r1}, ${r2}, ${addressRegister}, ${JUMP.LT}`];
};
Original file line number Diff line number Diff line change
@@ -1,23 +1,7 @@
const {
getInstructionArguments,
uniqueLabel,
getUsableRegister
} = require('../../../../utils');
const { getInstructionArguments } = require('../../../../utils');
const { JUMP } = require('../../../../../../constants');

module.exports = (instruction) => {
const [source, addressRegister] = getInstructionArguments(instruction);
const equal = uniqueLabel();
const mutableRegister = getUsableRegister(source, addressRegister);

return [
`PSH ${mutableRegister}`,
`LDV16 ${mutableRegister}, ${equal}`,

`JEQ ${source}, ${mutableRegister}`,
`POP ${mutableRegister}`,
`JMR ${addressRegister}`,

`${equal}`,
`POP ${mutableRegister}`
];
}
const [r1, r2, addressRegister] = getInstructionArguments(instruction);
return [`JCP ${r1}, ${r2}, ${addressRegister}, ${JUMP.NEQ}`];
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const { getInstructionArguments } = require('../../../../utils');
const { JUMP } = require('../../../../../../constants');

module.exports = (instruction) => {
const [r1, r2, addressRegister] = getInstructionArguments(instruction);
return [`JCP ${r1}, ${r2}, ${addressRegister}, ${JUMP.NZE}`];
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const { getInstructionArguments } = require('../../../../utils');
const { JUMP } = require('../../../../../../constants');

module.exports = (instruction) => {
const [r1, r2, addressRegister] = getInstructionArguments(instruction);
return [`JCP ${r1}, ${r2}, ${addressRegister}, ${JUMP.ZER}`];
};
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
const JEQ = require('./JEQ');
const JGE = require('./JGE');
const JNE = require('./JNE');
const JLT = require('./JLT');
const JGT = require('./JGT');
const JLE = require('./JLE');
const JGE = require('./JGE');
const JZE = require('./JZE');
const JNZ = require('./JNZ');

module.exports = {
JEQ,
JNE,
JLT,
JGT,
JLE,
JGE,
JNE
JZE,
JNZ
};
2 changes: 1 addition & 1 deletion src/compilers/bf/asm/header.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ input:
mov A, B ; swap A and B
ldv B, 1 ; load 1 into B for comparison
ldv C, input: ; load the input address into C
jlt B, C ; if A < 1(B), loop back to input
jlt A, B, C ; if A < 1(B), loop back to input
psh A ; push the character into stack
ldv16 A, .offset ; Same procedure as inc_mem_ptr, except just set the value directly
ldr B, A
Expand Down
2 changes: 1 addition & 1 deletion src/compilers/bf/asm/loop-end.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ ldr B, A ; B = value at [memory + offset]
mov A, B ; A = value at [memory + offset]
ldv B, 1 ; Set B to comparison value of 1
ldv C, ${label}
jge B, C ; A(Memory value) >= B(1), then jump
jge A, B, C ; A(Memory value) >= B(1), then jump
`;
18 changes: 17 additions & 1 deletion src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ module.exports = {
'STA',
'ATH',
'CAL',
'JLT',
'JCP',
'RET',
'PSH',
'POP',
Expand All @@ -30,6 +30,22 @@ module.exports = {
ARITHMETIC_MODE_SHIFT: 12,
BITWISE_SHIFT_SHIFT: 13,

JUMP: {
EQ: 0,
NEQ: 1,
LT: 2,
GT: 3,
LTE: 4,
GTE: 5,
ZER: 6,
NZE: 7,

R1: 4,
R2: 6,
AR: 8,
OP: 10
},

ARITHMETIC: {
ADD: 0,
SUB: 1,
Expand Down
Loading

0 comments on commit 935290b

Please sign in to comment.