'Is this a true FSM?
I have a conceptual question about FSM's and whether or not the following code is a true FSM. This is for my own curiosity and understanding about the subject. When I wrote this code, I was under the impression that this was an FSM, but now I am not so sure. According to a lot of reading I have done, a TRUE FSM should only consist of a sequential state transition block, followed by either one or two combination blocks to calculate the next state and the output logic.
My current code synthesizes and works on my Basys3 board, so I understand there may be an argument for "if it ain't broke, don't fix it" but it's been bugging me for a while now that I may have an incorrect understanding about how to write an FSM in HDL.
I have tried at least 4 or 5 different ways to rewrite my code using the format mentioned above, but I can't seem to get it without inferring latches, mainly due to the use of a counter, and the fact that pckd_bcd needs to remember its previous value.
Could somebody please explain to me either why this algorithm isn't fit for a true FSM, why it is fit for a true FSM and where my misunderstanding is, or how to rewrite this into the format mentioned above.
module double_dabble #
(
parameter NUM_BITS = 8
)
(
input wire i_clk,
input wire i_rst,
input wire [NUM_BITS-1:0] i_binary,
output wire [15:0] o_pckd_bcd
);
localparam s_IDLE = 3'b000;
localparam s_SHIFT = 3'b001;
localparam s_CHECK = 3'b010;
localparam s_ADD = 3'b011;
localparam s_DONE = 3'b100;
reg [2:0] state;
reg [NUM_BITS-1:0] bin;
reg [3:0] count;
reg [15:0] pckd_bcd;
reg [NUM_BITS-1:0] input_reg;
reg [15:0] output_reg;
assign o_pckd_bcd = output_reg;
always @(posedge i_clk)
begin
if(i_rst)
begin
state <= s_IDLE;
bin <= 0;
count <= 0;
pckd_bcd <= 0;
output_reg <= 0;
input_reg <= 0;
end
else
begin
input_reg <= i_binary;
state <= s_IDLE;
// FSM
case(state)
s_IDLE :
begin
state <= s_IDLE;
bin <= 0;
count <= 0;
pckd_bcd <= 0;
if (input_reg!=i_binary)
begin
bin <= i_binary;
state <= s_SHIFT;
end
end
s_SHIFT :
begin
state <= s_CHECK;
bin <= bin<<1;
count <= count+1;
pckd_bcd <= pckd_bcd<<1;
pckd_bcd[0] <= bin[NUM_BITS-1];
end
s_CHECK :
begin
state <= s_ADD;
if(count>=NUM_BITS)
state <= s_DONE;
end
s_ADD :
begin
state <= s_SHIFT;
pckd_bcd[15:12] <= add_three(pckd_bcd[15:12]);
pckd_bcd[11:8] <= add_three(pckd_bcd[11:8]);
pckd_bcd[7:4] <= add_three(pckd_bcd[7:4]);
pckd_bcd[3:0] <= add_three(pckd_bcd[3:0]);
end
s_DONE :
begin
state <= s_IDLE;
output_reg <= pckd_bcd;
end
endcase
end
end
function [3:0] add_three;
input [3:0] bcd;
if (bcd > 4)
add_three = bcd +3;
else
add_three = bcd;
endfunction
endmodule
Solution 1:[1]
In general, your code looks like it implements an FSM. You have evidence that the design is working as desired on your board.
The coding style you have chosen (one always block) is a valid Verilog approach. Another common FSM coding style involves two always blocks: one sequential and one combinational. See here for an example. It is not mandatory for an FSM to use two always blocks in Verilog.
One thing that I do notice in your code is that you are making multiple nonblocking assignments to the state signal at the same time. That is unusual.
For example, right before the case statement, you have:
state <= s_IDLE;
Then, in the IDLE case-item, you have the same code:
state <= s_IDLE;
I recommend trying to clean that up by adding a default to the case statement. A default is also a good coding practice when you have some undefined states, as in your FSM. You have only defined 5 of the 8 possible states (state is a 3-bit register).
Another example of multiple nonblocking assignments is:
s_CHECK :
begin
state <= s_ADD;
if(count>=NUM_BITS)
state <= s_DONE;
end
That would be better coded as:
s_CHECK :
begin
state <= (count>=NUM_BITS) ? s_DONE : s_ADD;
end
Following recommended coding practices yields more predictable simulation and synthesis results.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
