111 lines
3.6 KiB
Plaintext
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;
|
|
|
|
|
|
}
|
|
}
|