diff --git a/source/mojo_top.luc b/source/mojo_top.luc index 08014a0..2b77982 100644 --- a/source/mojo_top.luc +++ b/source/mojo_top.luc @@ -14,18 +14,35 @@ module mojo_top ( ) { sig rst; // reset signal + sig clk2; + sig subclk[3]; //alows for 8 subclock pulses .clk(clk) { // The reset conditioner is used to synchronize the reset signal to the FPGA // clock. This ensures the entire FPGA comes out of reset at the same time. reset_conditioner reset_cond; + + .rst(rst) { + counter slow_clk(#SIZE(15), #DIV(15)); + } + } + + .clk(clk2), .rst(rst), .subclk(subclk) { + node nodeA(.up_in(GNode.NULL), .right_in(GNode.NULL), .down_in(GNode.NULL), .left_in(GNode.NULL)); } always { reset_cond.in = ~rst_n; // input raw inverted reset signal rst = reset_cond.out; // conditioned reset + - led = 8h00; // turn LEDs off + clk2 = slow_clk.value[11]; + subclk = slow_clk.value[13:11]; + + led = c{nodeA.left_out.in[3:0], subclk, clk2}; + + + // led = 8h00; // turn LEDs off spi_miso = bz; // not using SPI spi_channel = bzzzz; // not using flags avr_rx = bz; // not using serial port diff --git a/source/node.luc b/source/node.luc index 4105df4..b653611 100644 --- a/source/node.luc +++ b/source/node.luc @@ -5,6 +5,8 @@ global GNode { 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 @@ -22,17 +24,18 @@ Register numbers: 3 = RIGHT 4 = DOWN 5 = LEFT - 6 = LAST - 7 = ANY + 6 = LAST (not implemented correctly) + 7 = ANY (not implemented correctly) - Subclk: + 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 = mark output as read - 5 = write to output - 6 = increment pc and reset everything thats not needed anymore + 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 */ @@ -54,42 +57,96 @@ module node ( output left_out, output error, - input subclk + 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 pc[4](#INIT(0)); //program counter dff 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 currentCmd; fsm currentCmdFSM = {MOV, // 2 args: 1const, 1reg or 2 reg - JEZ, JNZ, JGZ, JLZ, JRO, // 1 arg: 5bit(signed) const offset + 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)); + + #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 { - error = 0; - if(subclk == 0 && is_reading.q == 0 && is_writing.q == 0) { + + //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.q == 0 && is_writing.q == 0) { + } 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 @@ -101,10 +158,89 @@ module node ( 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; + //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 + } } diff --git a/source/nodeCon.luc b/source/nodeCon.luc index e761ec0..a16c321 100644 --- a/source/nodeCon.luc +++ b/source/nodeCon.luc @@ -6,13 +6,13 @@ */ global G_nodeCon { - const WIDTH = 10; + const WIDTH = 11; struct nodeConIn { write, read, enable, - in[WIDTH] + signed in[WIDTH] } } @@ -22,7 +22,7 @@ module nodeCon ( input rst, // reset input a_in, - output a_out[G_nodeCon.WIDTH], + signed output a_out[GNode.WORDLEN], output done, //erledigt (blokirung kann uafgehoben werden) @@ -31,9 +31,9 @@ module nodeCon ( input b_enable, input b_in[WIDTH],*/ input b_in, - output b_out[G_nodeCon.WIDTH], + signed output b_out[G_nodeCon.WIDTH], - output error + output error //output 1 on deadlock ) { dff internalBuff[G_nodeCon.WIDTH](#INIT(0), .clk(clk), .rst(rst)); diff --git a/source/registerDemultiplex.luc b/source/registerDemultiplex.luc new file mode 100644 index 0000000..53cd5b3 --- /dev/null +++ b/source/registerDemultiplex.luc @@ -0,0 +1,74 @@ +/** + + + Takes many registers and only reads from ONE selected + + +*/ +module registerDemultiplex ( + input clk, // clock + input rst, // reset + + + input selection[3], //which register? see node.luc for enumeration + + input acc[GNode.WORDLEN], + input up[GNode.WORDLEN], + input right[GNode.WORDLEN], + input down[GNode.WORDLEN], + input left[GNode.WORDLEN], + input last[GNode.REGISTERADDRLEN], //CAREFULL! this is NOT a register! this is a address! + input any[GNode.WORDLEN], + + output out[GNode.WORDLEN], + output done, //TODO: implement this fully + input read + + ) { + + dff outb[GNode.WORDLEN](.clk(clk), .rst(rst), #INIT(0)); + + always { + //reading + done = 0; + if(read) { + if(selection == 0) { + outb.d = 0; + done = 1; + } else if(selection == 1) { + outb.d = acc; + done = 1; + } else if(selection == 2) { + outb.d = up; + } else if(selection == 3) { + outb.d = right; + } else if(selection == 4) { + outb.d = down; + } else if(selection == 5) { + outb.d = left; + } else if(selection == 6) { + //inner selection for last register + case (last) { + 0: outb.d = 0; //NIL + done = 1; + 1: outb.d = acc; + 2: outb.d = up; + 3: outb.d = right; + 4: outb.d = down; + 5: outb.d = left; + 7: outb.d = 0; //ANY - not implemented correctly! + done = 1; + } + } else if(selection == 7) { + outb.d = any; + } else { + outb.d = 0; + done = 0; + } + } else { + outb.d = 0; + done = 0; + } + out = outb.q; + } +} \ No newline at end of file diff --git a/source/registerMultiplex.luc b/source/registerMultiplex.luc index d443668..d059237 100644 --- a/source/registerMultiplex.luc +++ b/source/registerMultiplex.luc @@ -1,3 +1,10 @@ +/** + + Takes a value and many registers and writes the value to one specified register + +*/ + + module registerMultiplex ( input clk, // clock input rst, // reset @@ -5,54 +12,44 @@ module registerMultiplex ( input selection[3], //which register? see node.luc for enumeration - input acc[GNode.WORDLEN], - input up[GNode.WORDLEN], - input right[GNode.WORDLEN], - input down[GNode.WORDLEN], - input left[GNode.WORDLEN], - input last[GNode.REGISTERADDRLEN], //CAREFULL! this is NOT a register! this is a address! - input any[GNode.WORDLEN], + output acc[GNode.WORDLEN], + output up[GNode.WORDLEN], + output right[GNode.WORDLEN], + output down[GNode.WORDLEN], + output left[GNode.WORDLEN], + input lastadr[GNode.REGISTERADDRLEN], //CAUTION! JUST AN ADDRESS! + output any[GNode.WORDLEN], + + output acc_w, + output up_w, + output right_w, + output down_w, + output left_w, + output any_w, - output out[GNode.WORDLEN], input in[GNode.WORDLEN], - input write, - input read - + input write ) { - - dff outb[GNode.WORDLEN](.clk(clk), .rst(rst), #INIT(0)); always { - //reading - if(read) { - if(selection == 0) { - outb.d = 0; - } else if(selection == 1) { - outb.d = acc; - } else if(selection == 2) { - outb.d = up; - } else if(selection == 3) { - outb.d = right; - } else if(selection == 4) { - outb.d = down; - } else if(selection == 5) { - outb.d = left; - } else if(selection == 6) { - if(last == 0) { //inenr selection for last - - } - } else if(selection == 7) { - outb.d = any; - } else { - outb.d = 0; - } - } else { - outb.d = 0; - } - out = outb.q; + acc_w = write && selection == 1; + up_w = write && selection == 2; + right_w = write && selection == 3; + down_w = write && selection == 4; + left_w = write && selection == 5; + any_w = write && selection == 7; - if(write) { - //TODO: fwd in to the register and set writing flags + acc = selection == 1 ? in : 0; + up = selection == 2 ? in : 0; + right = selection == 3 ? in : 0; + down = selection == 4 ? in : 0; + left = selection == 5 ? in : 0; + any = selection == 7 ? in : 0; + + if(write && selection == 6) { + //last register + + //TODO: this } } -} \ No newline at end of file +} diff --git a/tis-100.alp b/tis-100.alp index 83d87c6..537ed69 100644 --- a/tis-100.alp +++ b/tis-100.alp @@ -1,6 +1,8 @@ + registerDemultiplex.luc + counter.luc node.luc tis100.luc mojo_top.luc