For learning purposes, I am trying to implement a very simple processor in verilog. The idea is that every clock cycle the machine either fetches the next 4 instructions from memory (each instruction is 8-bits) or executes an instruction. However, I am having a lot of trouble with the PC (I call it iptr). My iptr is an edge triggered flipflop, I think that when there is a rising edge of the clock and the enable signal is high the iptr should change the value. Also, this new value should be immediately propagated (through a wire) to the fetch unit to decide whether it is already loaded or whether it should force an instruction fetch. The problem is that the fetch unit sees the previous value of the iptr and not the new value (or at least that is what I think the problem is), its like the new value that is being stored in the iptr in the register file is not propageted quickly enough. I am not sure how to fix this, but help is greatly appreciated. This is the relevant peace of code:
Note: The processor is a stack machine. I have copied the relevant parts of the code and patched up a bit the module definitions because they are a bit long.
module regfile(input wareg, wbreg, wcreg, woreg, wwptr, wiptr, input enareg, enbreg, encreg, enoreg, enwptr, eniptr, input clk, output rareg, rbreg, rcreg, roreg, rwptr, riptr); .... // drive the outputs assign rareg = areg; assign rbreg = breg; assign rcreg = creg; assign roreg = oreg; assign rwptr = wptr; assign riptr = iptr; initial begin areg = 32'b0; breg = 32'b0; creg = 32'b0; oreg = 32'b0; wptr = 32'b0; iptr = 32'b0; end always @ (posedge clk) begin // If any of the registers are enabled then write if (enareg) begin areg <= wareg; end if (enbreg) begin breg <= wbreg; end if (encreg) begin creg <= wcreg; end if (enoreg) begin oreg <= woreg; end if (enwptr) begin wptr <= wwptr; end if (eniptr) begin iptr <= wiptr; end end
module fetch(input iptr, data, clear_buff, clk, output reg instr, exec_stat, ack_clear); .... initial begin // Initially the buffer is empty // when exec_stat == 1 then we are fetching an instruction // when exec_stat == 0 then we are executing the instruction at address iptr empty_instr = 4'b1111; exec_stat = 1'b1; end always @ (posedge clk) begin // NOTE: in this block is where the problem occurs. The processor fetched the instruction // just fine when the buffer is empty, then it executed the instruction at 'iptr[1:0] == 0', the // iptr is incremented correctly. However, in this module the condition 'iptr[1:0] == 0' is still //true in the next clock cycle and causes theprocessor to go into a fetch, which is clearly wrong //since I expected "iptr[1:0] == 2'b1" if (exec_stat == 1'b1) begin // If we are fetching, store the instruction in the 'data' buffer and set exec_stat low exec_stat <= 1'b0; empty_instr[3:0] <= 4'b0000; instr0 <= data[7:0]; instr1 <= data[15:8]; instr2 <= data[23:16]; instr3 <= data[31:24]; end else if (iptr[1:0] == 2'b00) begin // the last two bits of the iptr address define which 8-bits from the buffer we need to use as instruction if (empty_instr) begin // if there is no instruction at this address then // go to fetch state exec_stat <= 1'b1; end else begin instr <= instr0; empty_instr <= 1'b1; end end else if (iptr[1:0] == 2'b01) begin if (empty_instr) begin exec_stat <= 1'b1; end else begin instr <= instr1; empty_instr <= 1'b1; end end else if (iptr[1:0] == 2'b10) begin if (empty_instr) begin exec_stat <= 1'b1; end else begin instr <= instr2; empty_instr <= 1'b1; end end else if (iptr[1:0] == 2'b11) begin if (empty_instr) begin exec_stat <= 1'b1; end else begin instr <= instr3; empty_instr <= 1'b1; end end end
module datapath(clk); //this seems a bit odd to me because the iptr input to the nextpc is the same than that to fetch, //which is connected to the read port of the regfile. I was hoping that the value that fetch would //see is the updated one and not the old one, but maybe that is too much to hope for. i.e. the value in the regfile is not propagated quickly enough... // This is the module that increments the iptr, there is also some other // logic that handles adding offsets for jumps, but that is not being used // at the momment. nextpc nextpc(ack_clear, riptr, instr_oreg, jump_type, alu_bool, clk, wiptr, clear_buff); regfile regfile(wareg, wbreg, wcreg, woreg, wwptr, wiptr, mux_enareg, mux_enbreg, encreg, enoreg, enwptr, eniptr, clk, rareg, rbreg, rcreg, roreg, rwptr, riptr); // Input iptr is the ouutput from read port of the regfile fetch fetch(riptr, mem_rdata, clear_buff, clk, instr, exec_stat, ack_clear); ....