0

The synthesis I'm trying to do is on a GCD algorithm Finite State Machine that works using the "subtract if bigger" method. I will attach the code and try and formulate a decent question.

module GCD_R (A,B,out,nrst,act,clk,fla_g);
  input [31:0] A, B;
  input clk, act, nrst;
  output reg fla_g;     
  output reg [31:0] out;
  reg [3:0] state, next_state;
  reg [31:0] A_reg, B_reg, Aint_reg, Bint_reg, out_reg;//2 registers will keep intermediate numbers+out, and next numbers
  parameter IDLE = 3'b001;
  parameter ABIG = 3'b010;
  parameter BBIG = 3'b100;
  reg next_flag;


  always @(*)   
    case (state)
      IDLE: begin
        $display("start");
        if(act == 0) begin
          A_reg = A; //A,B are wires that contain numbers from an external source
          B_reg = B; //first assign to A_reg and B_reg
          out_reg = 31'bx;
          next_flag = 1'b0;
          next_state = IDLE;
        end
        if(act == 1)
          if(A_reg==0) begin
            out_reg = B_reg;
            next_flag = 1'b1; //testbench will know when we stopped 
            Aint_reg = A_reg; //taking care not to infer latches
            Bint_reg = B_reg; 
            next_state = IDLE;
          end
          else if (B_reg==0) begin  
            out_reg = A_reg;
            next_flag = 1'b1;
            Aint_reg = A_reg; //taking care not to infer latches
            Bint_reg = B_reg;
            next_state = IDLE;
          end                       
          else if (A_reg >= B_reg) begin
            out_reg = 31'bx;
            next_flag = 1'b0;
            Aint_reg = A_reg;
            Bint_reg = B_reg;
            next_state = ABIG;
          end
          else begin
            out_reg = 4'bxxx;
            next_flag = 1'b0;
            Aint_reg = A_reg;
            Bint_reg = B_reg;
            next_state = BBIG;
         end
       else
        begin
         Aint_reg = A_reg;
         Bint_reg = B_reg;
         out_reg = 4'bxxx;
         next_flag = 1'b0;  
         next_state = 4'bx;
        end
     end

     ABIG: begin
       if (A_reg==0 | B_reg==0) begin
         out_reg = 31'bx;
         next_flag = 1'b0;
         next_state = IDLE;
         Aint_reg = A_reg;
         Bint_reg = B_reg;
       end
       else if (B_reg > A_reg) begin
         out_reg = 31'bx;
         next_flag = 1'b0;
         next_state = BBIG;
         Aint_reg = A_reg;
         Bint_reg = B_reg;
       end
       else begin
         out_reg = 31'bx;
         next_flag = 1'b0;
         next_state = ABIG; 
         Aint_reg = A_reg - B_reg;
         Bint_reg = B_reg;
       end
     end

     BBIG: begin 
       if (A_reg==0 | B_reg==0) begin
         out_reg = 31'bx;
         next_flag = 1'b0;
         next_state = IDLE;
         Aint_reg = A_reg;
         Bint_reg = B_reg;
       end 
       else if (A_reg > B_reg) begin 
         out_reg = 31'bx;
         next_flag = 1'b0;
         next_state = ABIG;
         Aint_reg = A_reg;
         Bint_reg = B_reg;
       end
       else begin 
         out_reg = 31'bx;
         next_flag = 1'b0;
         next_state = BBIG; 
         Aint_reg = A_reg;
         Bint_reg = B_reg - A_reg;
       end  
     end

     default: begin
       out_reg = 31'bx;
       next_flag = 1'b0;
       next_state = 4'bx;
       Aint_reg = A_reg;
       Bint_reg = B_reg;
       $display("%t: State machine not initialized/n",$time);
     end
   endcase

 always @(posedge clk or negedge nrst)
   if (~nrst) begin
     state <=  IDLE;//we get the new values by resetting first
     out <= 4'bx;//we don't want anything there at the reset
     fla_g <= 1'b0;
   end
   else begin
     state <=  next_state;//otherwise, get the next state and the next registers to the intermediate ones
     A_reg <=  Aint_reg;// 2nd assign to A_reg and B_reg- that's the problem
     B_reg <=  Bint_reg;
     out <=  out_reg;
     fla_g <= next_flag;
   end

endmodule

first, A and B are wires that will receive a list of numbers to compare via external source(some textfile in a testbench).

A_reg and B_reg are the intermediate registers that keep the numbers that we are checking the "if" statements on,

Aint_reg and Bint_reg are registers that keep the intermediate values of registers after the operations only to send them back to A_reg and B_reg when the clock is rising,

act decides whether the machine is on "on" mode and can perform the algorithm

nrst is the negative reset toggle

how was the problem formed:

you can see that at the beginning, there is an if(act == 0) condition. It was put there to ensure that the values at the A,B wires(received externally) will enter the registers there, instead of entering them in the sequential block while we were on the if(~nrst) condition since it made no sense entering a dynamic value while in reset.

This takes us to the current problem- I know that assigning a value to A and B both in the sequential and combinatoric blocks is what creates the problem, but I just can't find an alternative.

p.s. the fact that I'm using A_reg = A creates latches since I don't assign to A_reg anywhere else, and that's another problem since writing
Aint_reg = A_reg; A_reg = Aint_reg;
to satisfy latches doesn't sit right with me.

p.s.2. I tried looking into the similar questions on the site, but owing to my lack of enough knowledge on the subject I couldn't relate my problem to the ones out there

I'll be glad to receive any help, thanks

EDIT: I deleted the nonblocking assignments in the if(~nrst) sequential block so as to not to multiple assign A_reg <= 0 there and A_reg = A in the combinatoric block, but the multiple assignment problem still bugs it somehow

EDIT2: seems that I forgot a fundamental thing- don't assign to the same variable in two different "always" block, but I just can't think of a good enough solution to assign the wires A,B to a register and not assign to it again in the sequential block

1 Answers1

1

You are correct in identifying the major problem in your code is that you are not handling registers and combinational logic correctly. Whenever you have a register (register, not reg type, they are not the same and it is confusing for those new to Verilog), you need to define it in a particular way so synthesis and simulation tools can handle it. The safest practice is to create a clean separation between combinational logic and sequential storage (ie, actual registers). You started to do this with Aint_reg, Bint_reg, out_reg, etc; but you need to do it for all registered values whose values come from conbinational blocks. So, all these ideas together yields a struct for code like this (not completely your code but something similar):

input [31:0] A, B;
output reg [31:0] out;

reg [31:0] regA, regB;
reg [3:0] state, nextState;

always @(posedge clk or negedge rst) begin
  if (~rst) begin
    regA <= '0;
    regB <= '0;
    state <= IDLE;
  end
  else begin
    regA <= nextA;
    regB <= nextB;
    state <= nextState;
  end
end

always @(*) begin
  // Default; I always do this here to ensure there are no cases in which I dont assign a combinational value for this block
  // it always helps me keep track of which variables are assigned in which block
  nextA = regA;
  nextB = regB;
  nextState = state;

  out = '0;

  case (state)
    // In here is your case body, where you can reassign nextA, nextB, nextState and out
    // where the assignments are only dependent on A, B, regA, regB and state (ie, the values NOT assigned in this block)  
  endcase
end

With this in mind, you need to have only the Aint_reg, Bint_reg, etc in the combinational block; so you dont need to assign A_reg, Breg, etc in the combinational block. Note also that if this will mean the timing of out will be delayed, so you can always bypass the register if you need to push a value out from a combination block immediately. From what I understand, you might be having issues with loading during a reset, which is understandable as so long as reset (nrst) is asserted (ie, 0), nothing will load. That is the entire point of a reset, to hold the system in a known state until it is lifted. So until nrst is deasserted, your module shouldnt do anything. A few other points:

  • Formating your code correctly is very important, make sure your code is always clean as it helps spot bugs. I reformatted it and there seems to be a missing begin..end in the last block of the IDLE state
  • Always begin..end your blocks, it will avoid so many bugs
  • Watch out for the size of things, I see you declared your variables to be 32 bits reg [31:0] but are only assigning them using 31'd which is 31 bits. Use '0 syntax to zero fill for any size.
  • Setting registers to 'x is not ideal, you should have registers just retain their state (as you do thing for register values and next register values).

Hope this clarifies things for you.

Unn
  • 4,775
  • 18
  • 30
  • First of all, you were right about the syntax, I wrote the code without using tabs as I should(I worked on a linux environment and a friend referred me to a code segment that makes them automatically as in other windows platforms). There's one thing that I didn't quite understand about the code segment you wrote before the case statement- as I said, A and B are wires that will hold the values from an external source, A_reg is probably the "A"(same for B_reg) in the segment, and Aint_reg stands for nextA. did you mean I should write A_reg=A at the beginning to put the initial value? ........ – Roman Andreevitch Biriukov Dec 08 '17 at 11:25
  • ......that would indeed mean I won't need to assign to A_reg in the case because it's external to it, but then again, since it's a always@(*) condition, won't it always put a wire value into A_reg even if I'm in the middle of computing the output? – Roman Andreevitch Biriukov Dec 08 '17 at 11:28
  • @RomanAndreevitchBiriukov The code segment I shared is just a template and doesnt directly address the form your code needs to take. I have updated to to make that more clear; with a few more comments to see how everything fits together – Unn Dec 08 '17 at 17:50
  • Hopefully this clarifies the general structure of how code like this should look and you can then adapt it to your own. Note that if there are specific timing problems with the current implementation, those will require more indepth requirements from you for us to help out. – Unn Dec 08 '17 at 17:56
  • thanks, your edit made it clearer. Like I wrote in the last edit, I am trying to tackle how I should assign the initial values from the A,B wires into the registers(before I start the operation) without having a multiple drive situation such as assigning (A_reg = A) in the initial always block, and assigning (A_reg=Aint_reg) in the sequential- because that's assigning 2 different values in 2 different always blocks and that's not synthesizable. I thank you for the help until now and hope I don't bother you to overexplain, because as of now, your help was way beyond what I needed. thanks – Roman Andreevitch Biriukov Dec 08 '17 at 21:32
  • @RomanAndreevitchBiriukov All you need to do is have `nextA` take on the value of `A` so long as you are in the `IDLE` state. You dont have to worry then about the initial state of `regA` before operation as it will have the value from `nrst` until its deasserted and then will take on the value of `A` via `nextA` (this is just to directly answer that questions; SO is all about over explaining to help you and the next guy who finds this post :) ). – Unn Dec 08 '17 at 22:54
  • OH! Now I get it, latches and multiple drivers are finally gone, the timing reallocation in the testbench is all that is left, but that's less important for the elaboration. Thanks alot! – Roman Andreevitch Biriukov Dec 09 '17 at 10:06