Reputation: 86865
I'm trying to convert a flow chart simple state machine
into Verilog
code.
But I'm somehow stuck with the following, and as I have hardly any knowledge in Verilog I'm probably missing something.
The statemachine detects for an input stream of 0 and 1
, if the count of 1
s can be divided by 3 (or simply: if there have been 3 times number 1).
module example (
input clk,
input rst,
input input1,
output output
);
reg state;
reg nextstate;
localparam state2 = 3'd0;
localparam state1 = 3'd1;
localparam state0 = 3'd2;
always @(posedge clk or posedge rst) begin
if (rst)
state <= state0;
else
state <= nextstate;
end
always @* begin
case(state)
state0: begin
if(input1)
nextstate = state1;
end
state2: begin
if(input1)
nextstate = state0;
end
state1: begin
if(input1)
nextstate = state2;
end
default: nextstate = state0;
endcase
end
always @* begin
output1 = state0 & input1;
end
endmodule
I'm not sure:
do I have to define the inputs + outputs as reg
or wire
? Or is input
and output
! sufficient?
must I provide a vector dimension for the reg state, nextstate
? If yes, how to I know which dimension to pick?
can I write these kind of assertions at the end like state0 & input1
? Or should I use state = state0 & input1 = ??
- yes, what?
Upvotes: 5
Views: 13806
Reputation: 43
Although its too late but i got on the band wagon of learning Verilog and decided to take a shot at your inquiry. I wrote the design module and also created a test bench for it. This works according to your expectation.
`timescale 1ns/1ns
`define WIDTH 4
module FSM_Detect_Stream_Top();
reg in_clk;
reg in_rst_n;
reg [`WIDTH-1:0] in_input;
wire out_ouput;
FSM Test (.i_clk(in_clk), .i_rst_n(in_rst_n), .i_input(in_input), .o_output(out_output));
initial
begin
in_clk = 1'b0; // clk at t=0
#1 in_rst_n = 1'b1;
#2 in_rst_n = 1'b0;
#5 in_rst_n = 1'b1;
@ (negedge in_clk)
in_input = 2'b01;
@ (posedge in_clk)
$display("output:%b ", out_output);
@ (negedge in_clk)
in_input = 2'b01;
@ (posedge in_clk)
$display("output:%b ", out_output);
@ (negedge in_clk)
in_input = 2'b01;
@ (posedge in_clk)
$display("output:%b ", out_output);
@ (negedge in_clk)
in_input = 2'b01;
@ (posedge in_clk)
$display("output:%b ", out_output);
@ (negedge in_clk)
in_input = 2'b01;
@ (posedge in_clk)
$display("output:%b ", out_output);
@ (negedge in_clk)
in_input = 2'b00;
@ (posedge in_clk)
$display("output:%b ", out_output);
@ (negedge in_clk)
in_rst_n = 1'b0;
@ (posedge in_clk)
$display("output:%b ", out_output);
@ (negedge in_clk)
in_input = 2'b00; in_rst_n = 1'b1;
@ (posedge in_clk)
$display("output:%b ", out_output);
$finish;
end
// Generating a 20ns width clock pulse with 50% duty cycle
always
#10 in_clk = ~in_clk;
endmodule // FSM_Detect_Stream_Top
//*********************************************************************************************
module FSM(input i_clk, input i_rst_n, input [`WIDTH-1:0] i_input, output reg o_output);
//*********************************************************************************************
parameter S0 = 2'b00; //FIRST STATE or DEFAULT
parameter S1 = 2'b01; //SECOND STATE
parameter S2 = 2'b10; //THIRD STATE
parameter S3 = 2'b11; //FOURTH STATE
reg [`WIDTH-3:0] curr_state;
reg [`WIDTH-3:0] next_state;
//Sequential Logic for Storing Current State
always @ (posedge i_clk or negedge i_rst_n) begin
if(~i_rst_n)
curr_state <= S0;
else
curr_state <= next_state;
end
//Combinational Logic for Next State
always @ (curr_state or i_input) begin
case(curr_state)
S0: begin
if (i_input == 2'b01)
next_state <= S1;
else
next_state <= S0;
end
S1: begin
if (i_input == 2'b01)
next_state <= S2;
else
next_state <= S1;
end
S2: begin
if (i_input == 2'b01)
next_state <= S3;
else
next_state <= S2;
end
S3: begin
if (i_input == 2'b01)
next_state <= S0;
else
next_state <= S3;
end
default: next_state <= S0;
endcase // curr_state
end
// Output Logic
always @(posedge i_clk) begin
if (~i_rst_n)
o_output <= 1'b0;
else begin
case(curr_state)
S0: begin
if (i_input == 2'b01)
o_output <= 1'b1;
else
o_output <= 1'b1;
end
S1: begin
if (i_input == 2'b01)
o_output <= 1'b1;
else
o_output <= 1'b0;
end
S2: begin
if (i_input == 2'b01)
o_output <= 1'b1;
else
o_output <= 1'b0;
end
S3: begin
if (i_input == 2'b01)
o_output <= 1'b1;
else
o_output <= 1'b0;
end
default: o_output <= 1'b0;
endcase
end
end
endmodule
Upvotes: 2
Reputation: 1639
always @* begin
case(state)
state0: begin
if(input1)begin
nextstate = state1;
output1 = 0;
end end
else begin
nextstate = state0;
output1 = 1;
end
state2: begin
if(input1)begin
nextstate = state0;
output1 = 1 ;
end end
begin
nextstate = state2;
output1 = 0;
end
state1: begin
if(input1)begin
nextstate = state2;
output1 = 0;
end end
else begin
nextstate = state1;
output1 = 0;
end
default: nextstate = state0;
endcase
end
Upvotes: 2
Reputation: 35943
do I have to define the inputs + outputs as reg or wire? Or is input and output! sufficient?
Inputs are always wires, though it doesn't really matter as you don't assign to them. Outputs are wires by default, though you can also declare output reg
if you want a register instead.
must I provide a vector dimension for the reg state, nextstate? If yes, how to I know which dimension to pick?
Yes you must declare a dimension, or else your design will catastrophically fail when verilog silently truncates all your states to 0
or 1
. The width of the states should be the same width of the localparams that you use to define the state names, or more generically the width should be log2(number of input states)
.
can I write these kind of assertions at the end like state0 & input1?
I don't think this is what you want. State0 is just a constant number. If you want to know if the state machine is in state0, then you need to compare the current state with the constant state0. Also you likely don't want a bitwise AND here, so use the regular and &&
. Should be:
output = (state == state0) && input1;
Upvotes: 2