Multiple modules in FSM and how it's working?

63 Views Asked by At

I am new with Verilog, I tried to make a FSM for a multiplier based on Robertson’s procedure I tested every module and they work but i cant seem to understand how they work together in a FSM

Here is the code:

module robertson(
    input clk,       
    input reset,     
    input [15:0] Q,  
    input [15:0] M,  
    output reg [31:0] z 
);

parameter STATE_IDLE = 2'b00;
parameter STATE_PROCESS = 2'b01;
parameter STATE_DONE = 2'b10;


reg [1:0] state_reg;
reg [4:0] counter;
reg F;


wire overflow;

reg [15:0] A_reg;
wire [15:0] A_wire;

reg [15:0] Q_reg;
wire [15:0] Q_wire;

wire [15:0] M_neg;
wire [31:0] AQ_wire;
wire [3:0] moved_time_wire;



zero zero_i(.z(moved_time_wire));


noop noop_i(.x(M),.z(M_neg));


shifter shifter_i(  .f(F),
                    .x({A_reg,Q_reg}),
                    .y(AQ_wire),
                    .counter(moved_time_wire));


CSkA CSkA_i(
    .x(AQ_wire[31:16]),
    .y(M),
    .c_in(1'b0),
    .z(A_wire),
    .c_fin(overflow)
);


always @(posedge clk or negedge reset) begin
    if (~reset) begin
        state_reg <= STATE_IDLE;
        counter <= 0;
        F = 1'b0;
        Q_reg = Q;
        A_reg = 16'b0;
    end else begin
        case(state_reg)
            STATE_IDLE: begin
                state_reg <= STATE_PROCESS;
            end
            STATE_PROCESS: begin
                if (counter == 15) begin
                    state_reg <= STATE_DONE;
                end
            end
            STATE_DONE: begin
                state_reg <= STATE_IDLE;
            end
        endcase
    end
end


always @(posedge clk) begin
    if (state_reg == STATE_PROCESS) begin
        
        if(moved_time_wire != 0) begin
            counter <= counter + moved_time_wire;
        end
        else begin
            counter <= counter + 1;
        end
        A_reg <= A_wire;
        Q_reg <= AQ_wire[15:0];
    end
end

always @(posedge clk) begin
    if (state_reg == STATE_DONE) begin
        if(Q_reg[0] == 1'b1) begin
            A_reg <= A_reg + M_neg;
            Q_reg[0] <= 0; 
            z <= {A_reg,Q_reg};
        end
        else begin
            z <= {A_reg,Q_reg};
        end
    end
end

endmodule

When i try to see what values I get it's only a line x for z, can someone explain me what I do wrong or from where I can learn more about how to use modules in FSM?

Testbench:

module robertson_tb;

    reg clk;
    reg reset;

    reg [15:0] Q;
    reg [15:0] M;
    wire [31:0] z;

    robertson uut (
        .clk(clk),
        .reset(reset),
        .Q(Q),
        .M(M),
        .z(z)
    );

    initial begin
        Q = 0;
        M = 0;
        clk = 0;
        reset = 1'b1;
        #10;
        reset = 1'b0;
        Q = 16'b0000000000001111;
        M = 16'b0000000000000011;
    end

    always #20 clk = ~clk;

    initial begin
        $display("Time, Q, M, Z");
        repeat (50) begin
            #20; 
            $display("%t, %b, %b, %b", $time, Q, M, z);
        end
        $finish;       
    end

endmodule

1

There are 1 best solutions below

0
Mikef On

Here are three improvements for your post:

  1. The logic for your states looks 'pulled out' or extracted from the original state machine process and put into separate processes. I put it back for you so that you no longer have separate processes, which eliminates the possibility of multiple drivers which was pointed out by @Greg in the comments.

    I added comments and block names to make the SM easier to read.

module robertson(
    input clk,       
    input reset,     
    input [15:0] Q,  
    input [15:0] M,  
    output reg [31:0] z 
);

parameter STATE_IDLE = 2'b00;
parameter STATE_PROCESS = 2'b01;
parameter STATE_DONE = 2'b10;


reg [1:0] state_reg;
reg [4:0] counter;
reg F;


wire overflow;

reg [15:0] A_reg;
wire [15:0] A_wire;

reg [15:0] Q_reg;
wire [15:0] Q_wire;

wire [15:0] M_neg;
wire [31:0] AQ_wire;
wire [3:0] moved_time_wire;



zero zero_i(.z(moved_time_wire));


noop noop_i(.x(M),.z(M_neg));


shifter shifter_i(  .f(F),
                    .x({A_reg,Q_reg}),
                    .y(AQ_wire),
                    .counter(moved_time_wire));


CSkA CSkA_i(
    .x(AQ_wire[31:16]),
    .y(M),
    .c_in(1'b0),
    .z(A_wire),
    .c_fin(overflow)
);


always @(posedge clk or negedge reset) begin
    if (~reset) begin
        state_reg <= STATE_IDLE;
        counter <= 0;
        F = 1'b0;
        Q_reg = Q;
        A_reg = 16'b0;
    end else begin
        case(state_reg)
             
            // --------------------------------------
            // idle
            // --------------------------------------
            STATE_IDLE: begin
                state_reg <= STATE_PROCESS;
            end
          
            // --------------------------------------
            //  process
            // --------------------------------------
            STATE_PROCESS: begin :STATE_PROCESS_BLOCK
                if (counter == 15) begin
                    state_reg <= STATE_DONE;
                end
              
              //*****************************************  
              // Move code here to avoid multiple drivers  
              //*****************************************  
              if(moved_time_wire != 0) begin
                counter <= counter + moved_time_wire;
              end
              else begin
                counter <= counter + 1;
              end
              A_reg <= A_wire;
              Q_reg <= AQ_wire[15:0];
              
            end :STATE_PROCESS_BLOCK
            
            // --------------------------------------
            // done
            // --------------------------------------
            STATE_DONE: begin :STATE_DONE_BLOCK
                state_reg <= STATE_IDLE;
                if (state_reg == STATE_DONE) begin
                  if(Q_reg[0] == 1'b1) begin
                    A_reg <= A_reg + M_neg;
                    Q_reg[0] <= 0; 
                    z <= {A_reg,Q_reg};
                  end
                else begin
                  z <= {A_reg,Q_reg};
                    end
                  end              
            end :STATE_DONE_BLOCK
          
        endcase
    end
end

endmodule
  1. In this snippet of code
    if (~reset) begin
        state_reg <= STATE_IDLE;
        counter <= 0;
        F = 1'b0;
        Q_reg = Q;    // this line is bad
        A_reg = 16'b0;
    end else begin

Don't assign one variable to another in the reset part of a synchronous process. In this example you are assigning Q_reg = Q; You want to assign it elsewhere. The reset is used to initialize to a constant value (0, 1, 3'b111, etc).

  1. In the same snippet of code use non-blocking assignments <= rather than blocking assignments =. Non-blocking is used for modeling synchronous logic, blocking is used for modeling combinational logic.
    if (~reset) begin
        state_reg <= STATE_IDLE;
        counter <= 0;
        F     <= 1'b0;  // changed to non-blocking
        Q_reg <= Q;     // changed to non-blocking
        A_reg <= 16'b0; // changed to non-blocking
    end else begin