I was writing a code for DAC register and there is delay required. However, in the delay state, the DAC_counter_2 is not incrementing, and delay is not being achieved. I have copied the code to different project and tried to check. The problem still exists. Any help would be great.
module dac_card
( output reg DAC_SCLK,
output reg SYNC,
output reg SDIN,
input MHZ_50_CLK,
input RST,
output reg [7:0] DAC_counter_1,
output reg [7:0] DAC_counter_2
);
reg [7:0] pst_state, nxt_state;
reg [23:0] DAC_reg;
always #(posedge MHZ_50_CLK)
begin
if (RST)
begin
DAC_reg <= 24'hEEEEEE;
SYNC <= 1'b1;
DAC_SCLK <= 1'b0;
SDIN <=1'b0;
DAC_counter_1 <= 8'd0;
DAC_counter_2 <= 8'd0;
pst_state <= 8'd0;
end
else
begin
pst_state <= nxt_state;
DAC_counter_1 <= DAC_counter_1 + 1'b1;
end
end
always #(pst_state or DAC_counter_2)
begin
case (pst_state)
8'd0 : begin
if (DAC_counter_2 == 8'd24)
begin
DAC_counter_2 = 8'd0;
SYNC = 1'b1;
SDIN = 1'b0;
nxt_state = 8'd2;
end
else
begin
SYNC = 1'b0;
DAC_SCLK = 1'b1;
DAC_counter_2 = DAC_counter_2 + 1'b1;
SDIN = DAC_reg [23]; //Writing DAC register
DAC_reg = DAC_reg << 1;
nxt_state = 8'd1;
end
end
8'd1 : begin
DAC_SCLK = 1'b0;
nxt_state = 8'd0;
end
8'd2 : begin
if (DAC_counter_2 == 8'd10) //Minimum delay for SYNC to be low for write mode
begin
SYNC = 1'b1;
DAC_counter_2 = 8'd0;
nxt_state = 8'd3;
end
else
begin
SYNC = 1'b0;
//Not incrementing
DAC_counter_2 = DAC_counter_2 + 1'b1;
end
end
8'd3 : begin
nxt_state = 8'd0;
end
default : begin
nxt_state = 8'd0;
end
endcase
end
endmodule
Here is the test bench
module test_bench
();
//Analog Card DAC wires and registers
reg MHZ_50_CLK;
reg RST;
wire DAC_SCLK;
wire SYNC;
wire SDIN;
wire [7:0] DAC_counter_1;
wire [7:0] DAC_counter_2;
//Instatntiate DAC
dac_card dc (.DAC_SCLK(DAC_SCLK),
.SYNC(SYNC),
.SDIN(SDIN),
.MHZ_50_CLK(MHZ_50_CLK),
.RST(RST),
.DAC_counter_1(DAC_counter_1),
.DAC_counter_2(DAC_counter_2)
);
initial
begin
MHZ_50_CLK = 1'b0;
#10 RST = 1'b1;
#20 RST = 1'b0;
end
always
begin
#10 MHZ_50_CLK <= ~MHZ_50_CLK;
end
endmodule
Here is the waveform. After 24 counts of DAC_counter_2, delay for 8'd10 is not achieved.
You need to make an assignment to nxt_state in all branches of your case statement. This also avoids inferring unintended latches. For example, refer to the line // MISSING nxt_state = below:
8'd2 : begin
if (DAC_counter_2 == 8'd10) //Minimum delay for SYNC to be low for write mode
begin
SYNC = 1'b1;
DAC_counter_2 = 8'd0;
nxt_state = 8'd3;
end
else
begin
SYNC = 1'b0;
//Not incrementing
DAC_counter_2 = DAC_counter_2 + 1'b1;
// MISSING nxt_state =
end
end
As your waves show, once you enter state 2, you remain in state 2. Since DAC_counter_2 is not 10 in state 2, you always execute the else clause, which does not change nxt_state.
There are a couple other issues which may also be causing problems.
Good coding practices recommend making assignments to a reg from a single always block. DAC_counter_2 is assigned in 2 different blocks.
Also, the same signal should not appear on both the LHS and RHS of an assignment in a combinational always block since it creates a feedback loop. For example, DAC_counter_2 = DAC_counter_2 + 1 should probably be in a sequential always block like DAC_counter_1.
Related
I am looking to create an AND gate which gets the result after a delay of lets say 10ns an my clock is 500 ps. How will i delay the assignment without using # delays ?
I have tried to make a counter which increments but how to model it so that it only starts when my input changes. Also the input won't change till the first output is evaluated and assigned. Initial Counter is 0 and lets say delay is 3'b111 so i want the counter to go from 1 to 3'b111 and then assign it to y. Inputs are a and b to the and gate.
always#(posedge clk)begin
if (!reset) begin y <=0; counter <=0; end
else begin
counter <= counter +1'b1;
if(counter==delay)begin
y <= a & b;
counter <=0;
end
end
Well if your clock cycle is 500 ps then you will need to count to a higher value to reach 10ns. I rewrote your code and also added a testbench for you to try. It's kind of sloppy, I usually write vhdl and not verilog. Hope this helps.
//Module
module count_and (
input clk,
input reset,
input a,
input b,
output reg y,
output reg [4:0] counter
);
reg ready;
always#(posedge clk)begin
if (!reset) begin
y <=0;
counter <=0;
ready <= 0;
end
else if (ready == 1'b1) begin
counter <= counter +1'b1;
if (counter==5'b10011) begin
y <= a & b;
counter <=0;
ready <= 0; //turn it off after passing to y
end
end
end
always #(a,b) begin
ready <= 1'b1;
end
endmodule
//TestBench
`timescale 1ps/1ps
module tb_count ();
reg a,b;
reg clk;
reg reset;
wire [4:0] counter;
wire y;
initial begin
clk = 1'b1;
reset = 1'b0;
a = 1'b0;
b = 1'b0;
end
always begin
reset <= #50 1'b1;
clk = #250 ~clk;
a <= #1000 1'b1;
b <= #1000 1'b1;
end
count_and count_and_inst (
.clk(clk),
.reset(reset),
.a(a),
.b(b),
.y(y),
.counter(counter)
);
endmodule
I am trying to learn valid/ready handshake in verilog. In particular, I am interested to use ready as a flag that indicates the successful transaction of data (i.e., ready_in becomes high after valid_out goes high). I would like to explain my problem using a very simple Verilog example. I have written a convolutional encoder (code below)
module Conv_Encoder_Core(
input wire clk,
input wire reset,
input wire in_bit,
output reg out_A,
output reg out_B,
input wire sleep,
input wire valid_in,
input wire ready_in,
output reg valid_out,
output reg ready_out);
reg [5:0] S;
wire S_A, S_B, clkON;
assign S_A = S[1] ^ S[2] ^ S[4] ^S[5];
assign S_B = S[0] ^ S[1] ^ S[2] ^S[5];
assign clkON = clk & !sleep;
always #(posedge clkON)begin
if (reset) begin
S <=0;
valid_out <=0;
ready_out <=0;
end else if (valid_in) begin
out_A <= in_bit ^ S_A;
out_B <= in_bit ^ S_B;
valid_out <=1;
if (ready_in)begin
S<= S<<1;
S[0] <=in_bit;
ready_out <=1;
end else begin
ready_out <=0;
end
end else begin
valid_out <=0;
ready_out <=0;
end
end
endmodule
I am interested to use ready_in flag as an indicator that data out_A and out_B are received by the next block, so my block can accept the new data by setting ready_out flag high. I have written a testbench for this block, however, I am not getting the results I am expecting
`timescale 1 ns/1 ns
module TB_Conv();
reg clk;
//---------------clock generator-----------------------
initial begin
clk = 1'b0;
#5;
clk = 1'b1;
forever begin
#5 clk = ~clk;
end
end
//------------------ dump -----------------------
initial begin
$dumpfile("dumpVCD.vcd");
$dumpvars(10);
end
localparam N_DATA=10;
reg in_bits_vec [0:N_DATA-1];
initial begin
in_bits_vec[0] = 1'b1;
in_bits_vec[1] = 1'b0;
in_bits_vec[2] = 1'b0;
in_bits_vec[3] = 1'b0;
in_bits_vec[4] = 1'b0;
in_bits_vec[5] = 1'b0;
in_bits_vec[6] = 1'b0;
in_bits_vec[7] = 1'b0;
in_bits_vec[8] = 1'b0;
in_bits_vec[9] = 1'b1;
end
reg in_bit, ready_in,reset, valid_in;
Conv_Encoder_Core UUT(.clk(clk),
.reset(reset),
.in_bit(in_bit),
.out_A(out_A),
.out_B(out_B),
.sleep(1'b0),
.valid_in(valid_in),
.ready_in(ready_in),
.valid_out(valid_out),
.ready_out(ready_out));
//---------------- code starts here -------------------//
reg [3:0] addr;
always #(posedge clk) begin
if (reset)begin
addr<=0;
valid_in <=0;
in_bit <=0;
end else if (addr < 10) begin
in_bit <= in_bits_vec[addr];
valid_in <=1'b1;
if (ready_out) begin
addr <= addr+1'b1;
end
end else begin
in_bit <=0;
valid_in <=0;
end
if (valid_out==1) ready_in <= 1;
else ready_in <= 0;
end
// ----------- reset logic -----------//
reg [3:0] cnt;
initial cnt=0;
always #(negedge clk)begin
if (cnt<5) begin
reset = 1;
cnt=cnt+1;
end else reset =0;
end
initial begin
#1000;
$finish;
end
endmodule
if you look at the input data (in the testbech), you can see it is 1000000000. I am expecting to see 1 being passed through S register as follows:
S = 000000 //at beginning
S = 000001 // after ready_out=1
S = 000010
S = 000100
however, the results I get is entirely different(please see snapshot).
Another problem I have is that inbit=1 continues two clock cycles more than what I expect. in fact when ready_out=1, I expect to see that in_bit becomes zero but this happens two clock cycles later(yellow cursor in the snapshot ).
I would be most grateful if someone could explain what I do wrong in this example.
Conv_Encoder_Core
module Conv_Encoder_Core
(
input wire clk,
input wire reset,
input wire in_bit,
output reg out_A,
output reg out_B,
input wire sleep,
// input channel
input wire inp_valid_i,
output wire inp_ready_o,
// output channel
output reg out_valid_o,
input reg out_ready_i
);
reg [5:0] S;
wire S_A, S_B, clkON;
assign S_A = S[1] ^ S[2] ^ S[4] ^S[5];
assign S_B = S[0] ^ S[1] ^ S[2] ^S[5];
assign clkON = clk & !sleep;
// -- Changes start here -- //
wire wr_en;
reg full_r;
assign wr_en = ~full_r | out_ready_i;
always #(posedge clkON)begin
if (reset) begin
S <=0;
full_r <=0;
end else begin
if (wr_en) begin
if (inp_valid_i) begin
full_r <= 1;
out_A <= in_bit ^ S_A;
out_B <= in_bit ^ S_B;
S <= S<<1;
S[0] <=in_bit;
end else begin
full_r <= 0;
end
end
end
end
assign inp_ready_o = wr_en;
assign out_valid_o = full_r;
endmodule
tb
`timescale 1 ns/1 ns
module tb();
reg clk;
//---------------clock generator-----------------------
initial begin
clk = 1'b0;
#5;
clk = 1'b1;
forever begin
#5 clk = ~clk;
end
end
//------------------ dump -----------------------
initial begin
$dumpfile("dumpVCD.vcd");
$dumpvars(10);
end
localparam N_DATA=10;
reg in_bits_vec [0:N_DATA-1];
initial begin
in_bits_vec[0] = 1'b1;
in_bits_vec[1] = 1'b0;
in_bits_vec[2] = 1'b0;
in_bits_vec[3] = 1'b0;
in_bits_vec[4] = 1'b0;
in_bits_vec[5] = 1'b0;
in_bits_vec[6] = 1'b0;
in_bits_vec[7] = 1'b0;
in_bits_vec[8] = 1'b0;
in_bits_vec[9] = 1'b1;
end
reg in_bit, reset, inp_valid, inp_ready, out_valid, out_ready;
Conv_Encoder_Core UUT(.clk(clk),
.reset(reset),
.in_bit(in_bit),
.out_A(out_A),
.out_B(out_B),
.sleep(1'b0),
// input channel
.inp_valid_i(inp_valid),
.inp_ready_o(inp_ready),
// output channel
.out_valid_o(out_valid),
.out_ready_i(out_ready));
//---------------- code starts here -------------------//
reg [3:0] addr;
// -- Transmitter Side -- //
always #(posedge clk) begin: ff_addr
if (reset)begin
addr <= 0;
end else begin
if (addr < 10) begin
if (inp_valid && inp_ready) begin
addr <= addr + 1;
end
end else begin
addr <= 0;
end
end
end
assign inp_valid = (addr < 10) ? 1'b1 : 1'b0;
assign in_bit = in_bits_vec[addr];
// -- Receiver Side -- //
always #(posedge clk) begin: ff_ready_in
if (reset) begin
out_ready <= 0;
end else begin
out_ready <= $urandom_range(0, 1); // some randomness on the receiver, otherwise, we won't see if our DUT behaves correctly in case of ready=0
end
end
// ----------- reset logic -----------//
reg [3:0] cnt;
initial cnt=0;
always #(negedge clk)begin
if (cnt<5) begin
reset = 1;
cnt=cnt+1;
end else reset =0;
end
initial begin
#1000;
$finish;
end
endmodule
Issues with your implementation
Bad protocol definition & implementation
You are defining a protocol that looks more like "request/acknowledge" than "ready/valid" one, because data transmissions in your protocol are acknowledged after a one-cycle delay. What you need is concurrent transmission acknowledge in the same cycle, something like the following:
A valid data transmission is indicated by the Transmitter through valid=1 and are acknowledged by the Receiver through ready=1. So, a data transmission is valid only when valid && ready in the same cycle. Note that input data is equivalent to in_bit in your case, while output data is out_A and out_B.
Input/Output ready/valid channel confusion
If you add a processing/buffering unit between the Transmitter and the Receiver of the above channel, then what you got is something like this:
In that case, your buffer is the Conv_Encoder_Core module and, apart from its internal core logic, it must expose an input ready/valid channel, from which it receives input data, and an output one, from which it outputs its data. Also note that the Transmitter and the Receiver, are implemented by the testbench code (tb module). See
"Transmitter Side" and "Receiver Side" comments in code.
I'm implementing a repeating bit shifter for a 16 bit number. To do this, I have a bit counter that counts how many times I've shifted and resets when I reach 4'b1111. Then I have an assign statement that feeds the MSB to an output. However, the logic makes it so that the output skips the first MSB every time. What is the most succinct way to include the first MSB, before any shifting has occurred?
CODE
module DAC_Control(
input [15:0]data_in,
input clk,
input rst,
output data_out,
output reg cs,
output reg enable
);
//bit counter
reg [3:0] bit_counter;
//to help with shifting
reg [15:0] shifter;
always #(data_in)
shifter <= data_in;
//shifter
always #(posedge (clk)) begin
if (rst) begin
bit_counter <= 4'b0;
enable <= 1'b0;
cs <= 1'b1;
end
else if (bit_counter == 4'b1111) begin
bit_counter <= 4'b0;
enable <= 1'b1;
cs <= 1'b1;
end
else begin //this is the problem area
bit_counter <= bit_counter + 1'b1;
enable <= 1'b0;
cs <= 1'b0;
shifter <= shifter << 1;
end
end
assign data_out = shifter[15];
endmodule
Firstly it would be better to have a trigger to capture the data_in. If not then in simulation ,if the data_in changes in between the shifting it will update the shifter and cause the expected output to change. It would be preferable to capture the data_in based on a qualifying event ( e.g. counter_enable in the example below) . Synthesis will produce an error as shifter has two drivers . One the continuous assignment shifter <= data_in; and other the shifting logic shifter <= shifter << 1;
Updated sample code should serialize the data.
module DAC_Control(
input [15:0]data_in,
input counter_enable,
input clk,
input rst,
output data_out,
output reg cs,
output reg enable
);
//bit counter
reg [3:0] bit_counter;
//to help with shifting
reg [15:0] shifter;
//shifter
always #(posedge (clk)) begin
if (rst) begin
bit_counter <= 4'b0;
shifter <= 0;
end
else if (counter_enable == 1) begin
shifter <= data_in;
bit_counter <= 4'b0;
end
else begin
shifter <= shifter << 1; // shifting
bit_counter <= bit_counter + 1'b1; // counter
end
end
always #(posedge (clk)) begin
if (rst) begin
enable <= 1'b0;
cs <= 1'b1;
end
else if (bit_counter == 4'b1111) begin
enable <= 1'b1;
cs <= 1'b1;
end
else begin
enable <= 1'b0; // generate enable signals
cs <= 1'b0;
end
end
assign data_out = shifter[15];
endmodule
i'm a verilog beginner, i'm try to write a "event counter" on verilog.... this is my code, but it work only with "period" set to 16'b0000000000000001, if try set period to 16'b0000000000001000, result(out_event) is always '0'.
Someone can help me to fix it ?
module mymodule(
input wire clk,
input wire enable,
input wire reset,
input wire [15:0] period,
input wire in_event,
output reg out_event
);
reg en = 1'b0;
reg re = 1'b0;
reg [15:0] count = 16'b0000000000000000;
always #(posedge clk) en <= enable;
always #(posedge clk) re <= reset;
always #(in_event)begin
if(in_event == 1'b1)begin
if(re)begin
count <= 0 ;
out_event <= 1'b0;
end else begin
if(en) begin
if(count == period-1)begin
out_event <= 1'b1;
count <= 0;
end else begin
count <=count + 1;
out_event <= 1'b0;
end
end else begin
out_event <= 1'b0;
end
end
end else begin
out_event <= 1'b0;
end
end
endmodule
thanks in advance
The counter counts number of posedge of in_event wire. So, can you use #(posedge in_event)?
I simulated your code, providing a testbench to it.
I do not have much knowledge about hardware synthesis, but personally, I would suggest to write your logic based on edge/level of clock.
This code works completely well. Have a look at this link.
You can configure various values of period in testbench, hope this will be helpful.
I came up with a test bench and the design for your problem and it works.
`timescale 1s / 1s
module TB();
reg clk;
reg enable;
reg reset;
reg [15:0] period;
wire out_event;
wire [15:0] counter;
initial begin
clk = 1'b0;
forever begin
#1 clk = ~clk;
end
end
stack_exch_code test (.clk(clk),
.enable(enable),
.reset(reset),
.period(period),
.out_event(out_event),
.tb_counter(counter)
);
integer i;
initial
begin
#(negedge clk) reset = 1'b1; enable = 1'b0; period = 16'h0000;
#(negedge clk) reset = 1'b0; enable = 1'b1; period = 16'h00FF;
for (i = 0 ; i < 500 ; i = i + 1) begin
#(negedge clk) period = period - 1;
#(posedge clk) $display ("Period = %h , Counter = %h, Out_Event = %b ", period, counter, out_event);
end
#(negedge clk) $finish;
end
endmodule //TB
module stack_exch_code (input clk,
input enable,
input reset,
input [15:0] period,
//input inevent,
output reg out_event,
output [15:0] tb_counter
);
// initialization doesnt matter in hardware, its not C or C++
reg en;
reg re;
reg [15:0] count;
always # (posedge clk) begin
re <= reset;
en <= enable;
end
always # (posedge clk) begin
if (re) begin
count <= 16'h0000;
out_event <= 1'b0;
end
else if (en) begin
if ((count == period - 1) && !(period == 16'h0000)) begin
out_event <= 1'b1;
count <= 16'h0000;
end
else if (!(period == 16'h0000)) begin
count <= count + 1;
out_event <= 1'b0;
end
else if (period == 16'h0000)
out_event <= 1'b0;
end
end
assign tb_counter = count;
endmodule //stack_exch_code
I have a program written in Verilog and I want to convert it into a FSM automatically. Is this possible (just to visualize it)?
Here is the code :
module pci(reset,clk,frame,irdy,trdy,devsel,idsel,ad,cbe,par,stop,inta,led_out);
input reset;
input clk;
input frame;
input irdy;
output trdy;
output devsel;
input idsel;
inout [31:0] ad;
input [3:0] cbe;
inout par;
output stop;
output inta;
output [3:0] led_out;
parameter DEVICE_ID = 16'h9500;
parameter VENDOR_ID = 16'h106d; // Sequent!
parameter DEVICE_CLASS = 24'hFF0000; // Misc
parameter DEVICE_REV = 8'h01;
parameter SUBSYSTEM_ID = 16'h0001; // Card identifier
parameter SUBSYSTEM_VENDOR_ID = 16'hBEBE; // Card identifier
parameter DEVSEL_TIMING = 2'b00; // Fast!
reg [2:0] state;
reg [31:0] data;
reg [1:0] enable;
parameter EN_NONE = 0;
parameter EN_RD = 1;
parameter EN_WR = 2;
parameter EN_TR = 3;
reg memen; // respond to baseaddr?
reg [7:0] baseaddr;
reg [5:0] address;
parameter ST_IDLE = 3'b000;
parameter ST_BUSY = 3'b010;
parameter ST_MEMREAD = 3'b100;
parameter ST_MEMWRITE = 3'b101;
parameter ST_CFGREAD = 3'b110;
parameter ST_CFGWRITE = 3'b111;
parameter MEMREAD = 4'b0110;
parameter MEMWRITE = 4'b0111;
parameter CFGREAD = 4'b1010;
parameter CFGWRITE = 4'b1011;
`define LED
`ifdef LED
reg [3:0] led;
`endif
`undef STATE_DEBUG_LED
`ifdef STATE_DEBUG_LED
assign led_out = ~state;
`else
`ifdef LED
assign led_out = ~led; // board is wired for active low LEDs
`endif
`endif
assign ad = (enable == EN_RD) ? data : 32'bZ;
assign trdy = (enable == EN_NONE) ? 'bZ : (enable == EN_TR ? 1 : 0);
assign par = (enable == EN_RD) ? 0 : 'bZ;
reg devsel;
assign stop = 1'bZ;
assign inta = 1'bZ;
wire cfg_hit = ((cbe == CFGREAD || cbe == CFGWRITE) && idsel && ad[1:0] == 2'b00);
wire addr_hit = ((cbe == MEMREAD || cbe == MEMWRITE) && memen && ad[31:12] == {12'b0, baseaddr});
wire hit = cfg_hit | addr_hit;
always #(posedge clk)
begin
if (~reset) begin
state <= ST_IDLE;
enable <= EN_NONE;
baseaddr <= 0;
devsel <= 'bZ;
memen <= 0;
`ifdef LED
led <= 0;
`endif
end
else begin
case (state)
ST_IDLE: begin
enable <= EN_NONE;
devsel <= 'bZ;
if (~frame) begin
address <= ad[7:2];
if (hit) begin
state <= {1'b1, cbe[3], cbe[0]};
devsel <= 0;
// pipeline the write enable
if (cbe[0])
enable <= EN_WR;
end
else begin
state <= ST_BUSY;
enable <= EN_NONE;
end
end
end
ST_BUSY: begin
devsel <= 'bZ;
enable <= EN_NONE;
if (frame)
state <= ST_IDLE;
end
ST_CFGREAD: begin
enable <= EN_RD;
if (~irdy || trdy) begin
case (address)
0: data <= { DEVICE_ID, VENDOR_ID };
1: data <= { 5'b0, DEVSEL_TIMING, 9'b0, 14'b0, memen, 1'b0};
2: data <= { DEVICE_CLASS, DEVICE_REV };
4: data <= { 12'b0, baseaddr, 8'b0, 4'b0010 }; // baseaddr + request mem < 1Mbyte
11: data <= {SUBSYSTEM_ID, SUBSYSTEM_VENDOR_ID };
16: data <= { 24'b0, baseaddr };
default: data <= 'h00000000;
endcase
address <= address + 1;
end
if (frame && ~irdy && ~trdy) begin
devsel <= 1;
state <= ST_IDLE;
enable <= EN_TR;
end
end
ST_CFGWRITE: begin
enable <= EN_WR;
if (~irdy) begin
case (address)
4: baseaddr <= ad[19:12]; // XXX examine cbe
1: memen <= ad[1];
default: ;
endcase
address <= address + 1;
if (frame) begin
devsel <= 1;
state <= ST_IDLE;
enable <= EN_TR;
end
end
end
ST_MEMREAD: begin
enable <= EN_RD;
if (~irdy || trdy) begin
case (address)
`ifdef LED
0: data <= { 28'b0, led };
`endif
default: data <= 'h00000000;
endcase
address <= address + 1;
end
if (frame && ~irdy && ~trdy) begin
devsel <= 1;
state <= ST_IDLE;
enable <= EN_TR;
end
end
ST_MEMWRITE: begin
enable <= EN_WR;
if (~irdy) begin
case (address)
`ifdef LED
0: led <= ad[3:0];
`endif
default: ;
endcase
address <= address + 1;
if (frame) begin
devsel <= 1;
state <= ST_IDLE;
enable <= EN_TR;
end
end
end
endcase
end
end
endmodule
If there is no automatic way, could you explain a way of doing this?
Here is an FSM made with hand but can't test so ...
Does it seem ok?
It is sometimes easier to write the code and have the documentation generated from that. Sometimes you inherit legacy code without documentation, in these situations especially if new to a language tools to help visualise what is happening can be quite useful.
With cadence tools you can run your code with 'code coverage' then imc can load the coverage data and run FSM Analysis.
I have included a simple FSM below and show the generated state diagram.
module simple_fsm();
//Inputs to FSM
logic clk;
logic rst_n;
logic [1:0] state ;
logic [1:0] nextstate;
logic turn_on ;
logic turn_off ;
localparam S_OFF = 2'b00;
localparam S_GO_ON = 2'b01;
localparam S_ON = 2'b10;
localparam S_GO_OFF = 2'b11;
// State FlipFlop
always #(posedge clk or negedge rst_n) begin
if (~rst_n) begin
state <= 2'b0;
end
else begin
state <= nextstate;
end
end
//Nextstate Logic
always #* begin
case (state)
2'd0 : if (turn_on) begin
nextstate = S_GO_ON;
end
2'd1 : nextstate = S_ON;
2'd2 : if (turn_off) begin
nextstate = S_GO_OFF ;
end
2'd3 : nextstate = S_OFF;
endcase
end
//TB clk
initial begin
#1ns;
clk = 0;
forever begin
#20ns;
clk = ~clk;
end
end
//The Test
initial begin
rst_n = 1'b0;
turn_on = 1'b0;
turn_off = 1'b0;
#(posedge clk);
#(posedge clk);
rst_n = 1'b1 ;
#(posedge clk);
turn_on = 1'b1;
#(posedge clk);
turn_on = 1'b0;
#(posedge clk);
#(posedge clk);
#100ms;
$finish();
end
endmodule
Execute with :
$ irun simple_fsm.sv -coverage all -covdut simple_fsm
$ imc &
Load cov_work (folder created by above simulation) in imc, select simple_fsm and choose FSM Analysis.
imc also helps to visualise your test coverage as well. Arcs and states that have not been hit are shown in red.
We have seen that there are some tools which can visualise the FSM, another part of the question is; is the syntax of the purposed FSM suitable for these tools.
#vermaete has reported that Modelsim SE can not see the FSM. From imc I get :
Which does not seem to cover the complexity of the code, and is shown as only having 2 reachable states, IDLE and BUSY. I would recommend if OP is going down the route of using tools to visualise, adopt a simpler (syntax) FSM structure so that the tools can parse it better.
The better and expensive simulators can detect FSM's in the code and make a visualization of it. E.g. the Modelsim SE version. These can be nice to understand code and check the coveage.
But making you're own drawing of a 6-state FSM is not that hard.
The way to check if it's OK is to write a simulation and check that the behaviour is what you want. There is no point getting a bubble diagram out and seeing if it matches your hand-drawn one, as you have no way of knowing if your hand-drawn diagram is correct...
case(segmentRead)
//-------------------
SEGMENT0: begin
READ_Ready_EEPROM <= 1'b0;
READ_RDSR_Enable <= 1'b0;
Read_Enable <= 1'b0;
READ_RDSR_DATA_REG <= 8'b0;
// READ_DATA_REG <= 8'b0;
end
//-------------------
SEGMENT2: begin
READ_RDSR_Enable <= 1'b1;
READ_RDSR_DATA_REG <= 8'b0;
end
// //-------------------
SEGMENT3: begin
READ_RDSR_Enable <= 1'b0;
READ_RDSR_DATA_REG <= RDSR_Data;
end
//-------------------
SEGMENT4: begin
Read_Enable <= 1'b1;
end
//-------------------
SEGMENT5: begin
Read_Enable <= 1'b0;
READ_DATA_REG <= Read_Data;
end
//-------------------
SEGMENT6: begin
READ_Ready_EEPROM <= 1'b1;
end
//-------------------
endcase