0

I'm trying to implement a simple multicycle processor and I ran into some problems that I don't seem to be getting through. The code is below. I'm just experimenting right now to get this flowing. When I'm done, I'll begin implementing instructions and ALU. However, I'm stuck at this point. In the code below, I'm aware that data_memory is never used (I'll get to there if I can resolve this), some inputs and outputs are also not used for now, x1 and x2 are just variables I created to see what's really going on. What's in definitions.v file is self-evident.

I'm using Altera Quartus 15.1 with Verilog2001. This code compiles fine excepts some warnings due to unused stuff but when I try to simulate it with a clock period of 20ns it gives an error saying that "Error (suppressible): (vsim-3601) Iteration limit 5000 reached at time 100 ns". It also says this is suppressible but I don't know how to suppress either.

I looked up for this error and I learned that this is happening because at some point the code goes into an infinite loop. I tried to solve this by creating another variable ok. A cycle will start by setting ok to 0 and after microoperations for that cycle are done, I set ok to 1. So the cycle will not change at an improper time (it's like locking the cycle). Unfortunately, this resulted with the same error.

I tried another flow, too. Instead of cycle and next_cycle, I created one variable for cycle. At every rising edge of clock, I checked the current state and did things accordingly, then set the cycle for next step. Example:

always @ (posedge clk) begin
    case (cycle)
        3'b000: begin
            MAR <= PC;
            cycle <= 3'b001;
            ire <= 1'b1;
            x2 <= 2'b00; 
        3'b001: begin
            ...
            ...

This also compiles fine, and can be simulated without error! However, is not functioning correctly, giving weird(or unexpected) results. I find other approach more intuitive. So I will try to make it work.

How can I resolve/implement this?

`include "definitions.v"

module controller(
    input                           clk,
    input                           nres,
    output reg                      ire,
    output reg                      dwe,
    output reg                      dre,
    output reg  [1:0]               x2,
    output reg  [`IADR_WIDTH-1:0]   i_address,
    output reg  [`DADR_WIDTH-1:0]   d_address,
    output reg  [`DATA_WIDTH-1:0]   data_out);

    reg [2:0] cycle = 3'b000;
    reg [2:0] next_cycle;

    reg [`IADR_WIDTH-1:0] PC  = 6'b000000;
    reg [`INST_WIDTH-1:0] IR  = 12'b00000_0000000;
    reg [`DADR_WIDTH-1:0] MAR = 6'b000000;        
    reg [4:0]             OPC = 5'b00000;

    wire [`DATA_WIDTH-1:0] data_in;
    wire [`INST_WIDTH-1:0] instruction;

    reg [1:0] x1;

    data_memory dmem        (   .clk        (clk),
                                .dwe        (dwe),
                                .dre        (dre),
                                .nres       (nres),
                                .d_address  (d_address),
                                .d_data     (data_out),
                                .d_q        (data_in));

    instruction_memory imem (   .clk        (clk),
                                .ire        (ire),
                                .i_address  (i_address),
                                .i_q        (instruction));

    reg ok = 1;

    always @ (posedge clk) begin
        cycle = (ok) ? next_cycle : cycle;
    end

    always @ (cycle) begin
        case (cycle)
            3'b000: begin
                ok = 0;
                MAR = PC;
                next_cycle = 3'b001;
                ire = 1'b1;
                x2 = 2'b00;
                ok = 1;
            end
            3'b001: begin
                ok = 0;
                i_address = MAR;
                IR = instruction;
                ire = 1'b0;
                next_cycle = 3'b010;
                x2 = 2'b01;
                ok = 1;
            end
            3'b010: begin
                ok = 0;
                OPC = IR;
                next_cycle = 3'b011;
                x2 = 2'b10;
                ok = 1;
            end
            3'b011: begin
                ok = 0;
                if (OPC==5'b01011)  x1 = 2'b11;
                PC = PC + 1;
                next_cycle = 3'b000;
                x2 = 2'b11;
                ok = 1;
            end
        endcase    
    end

endmodule
Motun
  • 2,149
  • 3
  • 16
  • 23
  • Some suggestions: 1) Use `always@(*)` instead of `always@(cycle)` - it won't fix anything but it's a good habit; 2) Add a `default` case to prevent latching behaviour - otherwise, Quartus will infer a latch (instead of a wire); 3) Use non-blocking assignments (`<=`) inside edge-triggered `always` blocks; 4) Post your testbench code, in case in it the source of your error. – wilcroft Jun 06 '16 at 03:39
  • You have `PC = PC + 1;` in a combinatorial block. This should likely be advanced on a clock edge. – Morgan Jun 06 '16 at 06:54
  • @Morgan But it's controlled by a state (cycle), and that state is controlled by positive edge of the clock. Do you think that's causing the problem? – Motun Jun 06 '16 at 07:48
  • 1
    Only because you wrote `always@(cycle)` which when synthesised will work like `always@(*)`. This is why using the * is best practice. A combinatorial addition which loops onits self could hit a simulator timestep iteration limit. not sure if that is the exact problem you were seeing. – Morgan Jun 06 '16 at 08:22
  • @Morgan I commented out `PC = PC + 1` statement and the error was gone which is a nice progress for me right now. To understand the problem better: Assume we were at the state `3'b011`. At this state we increase `PC`. If when we are done with everything in this state, but the next clock pulse hasn't arrived yet, will we do everyting once again? Setting `ok` to `0` again, getting `OPC`, increasing `PC` one more time etc. Maybe when we are increasing `PC` once again, next clock pulse will hit but we already set `ok` to `0`. So `PC` will be increased so many times that we reach iteration limit. – Motun Jun 06 '16 at 08:36
  • @Morgan Is this what's going on in the background? – Motun Jun 06 '16 at 08:36

1 Answers1

1

When we write always @(signal) in verilog, a specified sensitivity list, the logic is triggered on a change in that signal. This can lead to misunderstanding of how hardware actually works. The only hardware we have that changes on an edge is a flip-flop and you need to specify the posedge or negedge keyword for that.

When always @(signal) is synthesised you actually get a combinatorial block, which has the effect of behaving like always @(*). This is an automatic sensitivity list.

So from the comments we will look at this small section of code:

 always @ (*) begin
    case (cycle)
      3'b011: begin
        ok = 0;
        if (OPC==5'b01011)  x1 = 2'b11;
        PC = PC + 1;
        next_cycle = 3'b000;
        x2 = 2'b11;
        ok = 1;

This a combinatorial block, triggered in the simulator when anything which can effect he output changes. Most signals are assigned to static signals, or other known values with out loops.

PC = PC +1;

The above line though updates the value of PC, this new value of PC should trigger the combinatorial block to be re-evaluated, hitting the PC increment again, etc. This all happens inside the delta cycle of the simulator.

With hardware description languages (HDLs) like Verilog we have to remember that we are describing parallel statements, not serially executed lines of code.

Morgan
  • 19,934
  • 8
  • 58
  • 84