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 const NULL = 11h0; 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 (not implemented correctly) 7 = ANY (not implemented correctly) Subclk: (a counter that steps every clock cycle to execute one part of an command) 0 = Read cmd 1 = interpret cmd 2 = Mark input as read 3 = try to read 4 = calculate 5 = mark output as read 6 = write to output 7 = increment pc and reset everything thats not needed anymore and update last register special case: regiuster == 6! 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 up_out, input right_in[GNode.WORDLEN], output right_out, input down_in[GNode.WORDLEN], output down_out, input left_in[GNode.WORDLEN], output left_out, output error, input subclk[3] ) { sig to_reg[GNode.WORDLEN]; sig read_reg; sig write_reg; sig i[$clog2(GNode.ROWS)]; //DEBUG ONLY, counter variable for a for-loop signed sig mainarg[GNode.WORDLEN]; //always reading //sig argtwo[GNode.WORDLEN]; //always writing (mov cmd) .clk(clk), .rst(rst) { dff cmds[GNode.ROWS]; dff 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 #INIT(0) { dff currentCmd_has_const; signed dff currentCmd_const[GNode.WORDLEN]; dff currentCmd_has_reg[2]; // only mov has two arguments (dst ist first (every cmd); src ist second(only used for mov)) dff lastreg[3]; // which register to use with LAST keyword, default = NIL signed dff acc[GNode.WORDLEN]; signed dff bak[GNode.WORDLEN]; dff is_reading; //is command reading from a register? reading from ACC or BAK may not count (depending on context) dff is_writing; //is command writing to a register? writing to ACC or BAK may not count (should be a pseudonym for currentCmd == MOV) dff is_reading_inProgress; //is reading or writing in progress? (block every thing then) dff is_writing_inProgress; //only on of this two can be 1 ! dff pc[4]; //program counter (which instruction to execute?) } dff currentCmd_reg[2][3];//registers to use TODO: add #INIT(0) //TODO: fix selection! - when select what as read or as write reg? registerDemultiplex reg_read(.selection(currentCmd_reg.q[0]), .acc(acc.q), .up(up_in), .right(right_in), .down(down_in), .left(left_in), .last(lastreg.q), .any(11h0), .read(read_reg)); registerMultiplex reg_write(.selection(currentCmd_reg.q[1]), .lastadr(lastreg.q), .write(write_reg), .in(to_reg)); } always { //EXAMPLE CODE //ADD 1 cmds.d[0].cmd = currentCmdFSM.ADD; cmds.d[0].arg_is_const = 1; cmds.d[0].args = 11d1; //1 //MOV ACC, LEFT cmds.d[1].cmd = currentCmdFSM.MOV; cmds.d[1].arg_is_const = 0; cmds.d[1].args = 11b0101001; //0 5 1 (leer, left, acc) von acc -> left //write NULL-OP's to the rest of memory for(i = 2; i < GNode.ROWS; i++) { cmds.d[1].cmd = currentCmdFSM.ADD; cmds.d[1].arg_is_const = 1; cmds.d[1].args = 11h0; } error = 0; // no error read_reg = 0; //default to non reading //define outputs up_out.in = reg_write.up; up_out.write = reg_write.up_w; right_out.in = reg_write.right; right_out.write = reg_write.right_w; down_out.in = reg_write.down; down_out.write = reg_write.down_w; left_out.in = reg_write.left; left_out.write = reg_write.left_w; if(subclk == 0 && is_reading_inProgress.q == 0 && is_writing_inProgress.q == 0) { //read command currentCmd.d = cmds.q[pc.q]; currentCmdFSM.d = cmds.q[pc.q]; } else if(subclk == 1 && is_reading_inProgress.q == 0 && is_writing_inProgress.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 //set flags for reading and writing is_reading.d = (currentCmdFSM.q == currentCmdFSM.MOV || ((currentCmdFSM.q == currentCmdFSM.ADD || currentCmdFSM.q == currentCmdFSM.SUB) && currentCmd_has_const.q == 0)); //mov cmd or add/sub in register mode is_writing.d = (currentCmdFSM.q == currentCmdFSM.MOV); //only mov cmd can write to a register aparently } else if(subclk == 2 && is_reading_inProgress.q == 0 && is_writing_inProgress.q == 0) { //mark input as read if(is_reading.q == 1) { //do reading stuff //TODO: this read_reg = 1; } } else if(subclk == 3 && is_writing_inProgress.q == 0) { //reading if(is_reading.q == 1) { read_reg = 1; //try to read the register NOW is_reading_inProgress.d = ~reg_read.done; //wenn fertig -> kein read mehr in progress, sonst: nächsten zyklus nochmal } } else if(subclk == 4 && is_reading_inProgress.q == 0 && is_writing_inProgress.q == 0) { //calculate //args mainarg = currentCmd_has_const.q ? currentCmd_const.q : reg_read.out; case (currentCmdFSM.q) { currentCmdFSM.MOV: to_reg = mainarg; write_reg = 1; is_writing_inProgress.d = 1; currentCmdFSM.JEZ: //jump equals Zero if (acc.q == 0) { //jump pc.d = pc.q + mainarg; } currentCmdFSM.JNZ: //jump not equals zero if(acc.q != 0) { //jump pc.d = pc.q + mainarg; } currentCmdFSM.JGZ: //jmp greater zero if(acc.q > 0) { pc.d = pc.q + mainarg; } currentCmdFSM.JLZ: //jmp less zero if(acc.q < 0) { pc.d = pc.q + mainarg; } currentCmdFSM.JRO: //jmp ro (offset) unconditional pc.d = pc.q + mainarg; currentCmdFSM.ADD: acc.d = acc.q + mainarg; currentCmdFSM.SUB: acc.d = acc.q - mainarg; currentCmdFSM.NEG: acc.d = -acc.q; currentCmdFSM.SWP: bak.d = acc.q; //does this work? acc.d = bak.q; currentCmdFSM.SAV: bak.d = acc.q; } } else if(subclk == 7 && is_reading_inProgress.q == 0 && is_writing_inProgress.q == 0) { //increment pc if(pc.q + 1 >= GNode.ROWS) { pc.d = 0; //loop over } else { pc.d = pc.q + 1; } //reset everything } }