TIS-100-FPGA/source/node.luc

111 lines
3.6 KiB
Plaintext

global GNode {
const ROWS = 14; //number of commands to hold
const CMDLEN = 16; //number of bits a command is in size
const WORDLEN = 11; //bits to store a number (-999 to 999)
const REGISTERADDRLEN = 3; //bits to address a register
struct cmd {
cmd[4],
arg_is_const, //1 = argument is a 11bit signed integer, 0 argument is a register number
args[11] //11 bit number or at most 2 reigster (mov cmd)
}
}
/**
Register numbers:
0 = NIL
1 = ACC
2 = UP
3 = RIGHT
4 = DOWN
5 = LEFT
6 = LAST
7 = ANY
Subclk:
0 = Read cmd
1 = interpret cmd
2 = Mark input as read
3 = try to read
4 = mark output as read
5 = write to output
6 = increment pc and reset everything thats not needed anymore
cycles are skiped, if node is waiting for another node to read or write a connection
*/
module node (
input clk, // clock
input rst, // reset
input up_in[GNode.WORDLEN],
output<G_nodeCon.nodeConIn> up_out,
input right_in[GNode.WORDLEN],
output<G_nodeCon.nodeConIn> right_out,
input down_in[GNode.WORDLEN],
output<G_nodeCon.nodeConIn> down_out,
input left_in[GNode.WORDLEN],
output<G_nodeCon.nodeConIn> left_out,
output error,
input subclk
) {
.clk(clk), .rst(rst) {
dff pc[4](#INIT(0)); //program counter
dff<GNode.cmd> cmds[GNode.ROWS];
dff lastreg[3](#INIT(0)); // default = NIL
dff acc[GNode.WORDLEN](#INIT(0));
dff bak[GNode.WORDLEN](#INIT(0));
dff is_reading(#INIT(0));
dff is_writing(#INIT(0));
dff<GNode.cmd> currentCmd;
fsm currentCmdFSM = {MOV, // 2 args: 1const, 1reg or 2 reg
JEZ, JNZ, JGZ, JLZ, JRO, // 1 arg: 5bit(signed) const offset
ADD, SUB, // 1 arg: 1reg or 1 signed const
NEG, SWP, SAV}; // no arg
dff currentCmd_has_const(#INIT(0));
dff currentCmd_const[GNode.WORDLEN](#INIT(0));
dff currentCmd_has_reg[2](#INIT(0)); // only mov has two arguments (dst ist first; src ist second)
dff currentCmd_reg[2][3];//registers to use TODO: add #INIT(0)
registerMultiplex reg1(.selection(currentCmd_reg[0]), .acc(acc), .up(up), .right(right), .down(down), .left(left), .last(lastreg));
}
always {
error = 0;
if(subclk == 0 && is_reading.q == 0 && is_writing.q == 0) {
//read command
currentCmd.d = cmds.q[pc.q];
currentCmdFSM.d = cmds.q[pc.q];
} else if(subclk == 1 && is_reading.q == 0 && is_writing.q == 0) {
//interpret
//set them for all commands just set the _has_ flag if reguired
currentCmd_reg.d[0] = currentCmd.q.args[ GNode.REGISTERADDRLEN -1 : 0]; //3 LSB bytes = register 1
currentCmd_reg.d[1] = currentCmd.q.args[(2*GNode.REGISTERADDRLEN) -1 : GNode.REGISTERADDRLEN]; //3 next bytes = register 2
currentCmd_const.d = currentCmd.q.args;
//set the _has_ flags
currentCmd_has_const.d = (currentCmdFSM.q >= currentCmdFSM.JEZ && currentCmdFSM.q <= currentCmdFSM.JLZ) || currentCmd.q.arg_is_const == 1; //last bit of cmd indicates a constant for cmd's that can do both
currentCmd_has_reg.d[0] = (currentCmdFSM.q == currentCmdFSM.MOV || currentCmd.q.arg_is_const == 0); //mov cmd -> at least 1 reg or no constant
currentCmd_has_reg.d[1] = (currentCmdFSM.q == currentCmdFSM.MOV && currentCmd.q.arg_is_const == 0); //mov cmd und arg ist keine constante -> 2 register
} else if(subclk == 2 && is_reading.q == 0 && is_writing.q == 0) {
//mark input as read
is_reading.d = 1;
}
}