Verilog: Using parameter in if statement - verilog

How can I check for a parameter based value in an if statement?
I have a parametrized counter and I cannot find answers to how to check the max size i.e. e.g.
if(count_val == WIDTH'b1) count_pulse = 1'b1;
Any chance i could get some help :) ?
module counter #(
parameter WIDTH=3,
parameter DIR = 0
)(CLK, EN, RST, COUNT_VAL, COUNT_PULSE);
input CLK, EN, RST;
output [WIDTH:0] COUNT_VAL;
output COUNT_PULSE;
reg[WIDTH:0] count_val=0;
reg count_pulse;
always #(posedge CLK)
begin
if(RST == 1'b1) count_val <= 0;
else if(EN == 1'b1) begin
if(DIR == 1'b0) count_val <= count_val + 1;
else if(DIR == 1'b1) count_val <= count_val - 1;
if(count_val == WIDTH'b1) count_pulse = 1'b1;
else count_pulse = 1'b0;
end
end
assign COUNT_VAL = count_val;
endmodule

You can use a replication.
if(count_val == {WIDTH{1'b1}}) count_pulse = 1'b1;
or a shift
if(count_val == ((32'b1<<WIDTH)-1) count_pulse = 1'b1;
or in SystemVerilog, a bit fill
if(count_val == '1) count_pulse = 1'b1;

The syntax you have been trying to use WIDTH'b1 should be translated to 3'b1 which is 001. If this is the case, you do not really need the width specifier. The following will do:
if (counter_val == 1)
or to use precise widths:
if (counter_val == { {WIDTH-1{0}}, 1'b1} )
If you meant, 111, the see dave_59's answer.

Related

Rising Edge Counter

I'm new to fpgas in general. I want to make counter that iterates each time SCK sees a rising edge. The issue i'm having with my code is that it seems to count twice. Two leds are lit each time there is a rising edge transition - as opposed to just one led. Any idea where this may be coming from?
module spi_slave(pcEn, LED, clk, SCK);
input clk, SCK;
output reg pcEn;
output reg [7:0] LED = 8'h00;
reg r1 = 0;
reg r2 = 0;
reg r3 = 0;
reg [3:0] cnt = 4'b0000;
always #(posedge clk)
begin
r1 <= SCK;
r2 <= r1;
pcEn <= r1 && !r3;
if (pcEn == 1) begin
cnt = cnt + 4'b0001;
if (cnt == 4'b0001) begin
LED[0] = 1'b1;
end
else if (cnt == 4'b0010) begin
LED[1] = 1'b1;
end
else if (cnt == 4'b0011) begin
LED[2] = 1'b1;
end
else if (cnt == 4'b0100) begin
LED[3] = 1'b1;
end
else if (cnt == 4'b0101) begin
LED[4] = 1'b1;
end
else if (cnt == 4'b0110) begin
LED[5] = 1'b1;
end
else if (cnt == 4'b0111) begin
LED[6] = 1'b1;
end
else if (cnt == 4'b1000) begin
LED[7] = 1'b1;
end
else
LED = 8'h00;
end
else
#100;
r3 <= r2;
end
endmodule
The counter is counting twice because you are comparing r1 & !r3.
r1->r2->r3 .it takes 2 clocks for r3 to be set after r1 equal 1. This implies that r1&!r3 condition will remain valid for 2 clocks. The pcEn will be generated for 2 clocks , Hence the counter will count twice.
r1 && !r2 or if you want a delay r2 && !r3 should work fine.
you should be able to see this behavior in a waveform to debug.Use $dumpvars; in your simulation to view the waveform.
Also there are couple of change to improve the code.
use of reset.
consistently use non-blocking assignment .
there is no need for #100 delay.
module spi_slave(pcEn, LED, clk, SCK,rst_n);
input clk, SCK,rst_n;
output reg pcEn;
output reg [7:0] LED ;
reg r1 ;
reg r2 ;
reg r3 ;
reg [3:0] cnt ;
always #(posedge clk or negedge rst_n)
begin
if ( rst_n == 0 )
begin
r1 <=0 ;
r2 <= 0 ;
r3 <= 0 ;
cnt <= 0 ;
LED <=0 ;
pcEn <=0 ;
end
else
begin
r1 <= SCK;
r2 <= r1;
r3 <= r2;
pcEn <= r2 && !r3;
if (pcEn == 1) begin
cnt <= cnt + 4'b0001;
if (cnt == 4'b0001) begin
LED[0] <= 1'b1;
end
else if (cnt == 4'b0010) begin
LED[1] <= 1'b1;
end
else if (cnt == 4'b0011) begin
LED[2] <= 1'b1;
end
else if (cnt == 4'b0100) begin
LED[3] <= 1'b1;
end
else if (cnt == 4'b0101) begin
LED[4] <= 1'b1;
end
else if (cnt == 4'b0110) begin
LED[5] <= 1'b1;
end
else if (cnt == 4'b0111) begin
LED[6] <= 1'b1;
end
else if (cnt == 4'b1000) begin
LED[7] <= 1'b1;
end
else
LED <= 8'h00;
end
end
end
endmodule
First of # delays are not synthesizable, they are delays for simulation only.
Generally is considered best practice to separate block and non-blocking logic into different always blocks. always #* for combinational (blocking assignments), and always #(posedge clk) for sequential (non-blocking assignments). FYI : Verilog supports case-statements which make coding value compare easier then nesting else-if.
I thing you may want to use r2 && !r3 instead of r1 && !r3 as Rahul also pointed out
always #* begin
if (pcEn == 1'b0) begin
next_cnt = cnt;
next_LED = LED;
else begin
next_cnt = cnt + 4'b0001;
next_LED = 8'h00; // Rest all to 0s
if(cnt >= 8'h8) next_cnt = 4'b0000; // optional : assuming you want to roll back before waiting another 8 SCK toggles
case(cnt)
4'b0000 : next_LED[0] = 1'b1;
4'b0001 : next_LED[1] = 1'b1;
// ...
4'b0111 : next_LED[7] = 1'b1;
endcase
end
end
always #(posedge clk) begin
r1 <= SCK;
r2 <= r1;
r3 <= r2;
pcEn <= r2 && !r3;
cnt <= next_cnt;
LED <= next_LED;
end

Verilog 4x16 Decoder outputs wrong data

I have implemented a 4x16 Decoder using Verilog along with it's test. For each case the decoder should output a 16-bit digit with only one of the bits high. I can't manage to get all the desired outputs when I run the program. Here is the code for the Decoder and test, and the output at the console:
4x16 Decoder:
module Decoder4x16 (input [3:0] select, input enable, output reg [16:0] out);
always #(select, enable)
begin
if(enable == 1'b0)
out = 16'b0000000000000000;
else if(enable == 1'b1)
if(select == 4'b0000)
out <= 16'b0000000000000001;
else if(select == 4'b0001)
out <= 16'b0000000000000010;
else if(select == 4'b0010)
out <= 16'b0000000000000100;
else if(select == 4'b0011)
out <= 16'b0000000000001000;
else if(select == 4'b0100)
out <= 16'b0000000000010000;
else if(select == 4'b0101)
out <= 16'b0000000000100000;
else if(select == 4'b0110)
out <= 16'b0000000001000000;
else if(select == 4'b0111)
out <= 16'b0000000010000000;
else if(select == 4'b1000)
out <= 16'b0000000100000000;
else if(select == 4'b1001)
out <= 16'b0000001000000000;
else if(select == 4'b1010)
out <= 16'b0000010000000000;
else if(select == 4'b1011)
out <= 16'b0000100000000000;
else if(select == 4'b1100)
out <= 16'b0001000000000000;
else if(select == 4'b1101)
out <= 16'b0010000000000000;
else if(select == 4'b111)
out <= 16'b0100000000000000;
else if(select == 4'b1111)
out <= 16'b1000000000000000;
end
endmodule
Test:
module Decoder4x16_test;
reg [3:0] select;
reg enable;
wire [16:0] out;
parameter sim_time = 2800;
Decoder4x16 decoder(select, enable, out);
initial #sim_time $finish;
initial
begin
select = 4'b0000;
enable = 1'b0;
repeat(16) #10 begin
enable = 1'b1;
#85 $display("select = %b \t out = %b", select, out);
select = select + 4'b0001;
end
end
endmodule
When I run the program it outputs the correct output until it reaches the test case where the input is 1101. After that the decoder outputs the wrong value that it is suppose to display. Here is the output:
select = 0000 out = 00000000000000001
select = 0001 out = 00000000000000010
select = 0010 out = 00000000000000100
select = 0011 out = 00000000000001000
select = 0100 out = 00000000000010000
select = 0101 out = 00000000000100000
select = 0110 out = 00000000001000000
select = 0111 out = 00000000010000000
select = 1000 out = 00000000100000000
select = 1001 out = 00000001000000000
select = 1010 out = 00000010000000000
select = 1011 out = 00000100000000000
select = 1100 out = 00001000000000000
select = 1101 out = 00010000000000000
select = 1110 out = 00010000000000000
select = 1111 out = 01000000000000000
Here, out is a reg that means it holds a value that is assigned to it. There is no else if condition for select=4'b1110. So, out holds or retains its previous value which was from select=4'b1101. That is, out holds value 00010000000000000 which is displayed.
So, add an else if condition for select=4'b1110 and the code works fine.
else if(select == 4'b1110)
out <= 16'b0100000000000000;
Moreover, a decoder is purely combinational circuit. While creating any combinational logic, the use of blocking assignments(=) is preferred. So, use the following syntax.
else if(select == 4'b1110)
out = 16'b0100000000000000; // blocking
One more thing just to elaborate, use always#(*) instead of manual sensitivity list. This will help reducing confusion of sensitivity lists.
Try this simple code,
module Decoder4x16 (input [3:0] select,
input enable,
output wire [16:0] out);
assign out = {17{enable}} & (1'b1 << select);
endmodule
Synthesized in ISE too.

Creating pulses of different width

I have written following code which produces pulse of different width.I want the code to produce a single pulse according to select line.
If select line is
00 pulse width = 1 us ,
01 pulse width = 10 us
. .
11 pulse width = 1000 us
The input clock is of 10 Mhz.
But according to code I am getting continuous pulse if I don't provide any other value of selection line.How can I achieve only one pulse?
module pulse(input wire [1:0] sel , //selection lines s1 s0
input clk,
input rst_n,
output reg flag, //for checking conditions
output reg [13:0] Q, // output of 14 bit counter
output reg pulse, //output pulse
output reg count); //also for checking conditions
wire flag_d , count_d;
assign flag_d = ( (sel == 2'b00 | sel == 2'b01 | sel == 2'b10 | sel == 2'b11) && count == 1'b0)? 1'b1 : flag;
assign count_d = ( (sel == 2'b00 | sel == 2'b01 | sel == 2'b10 | sel == 2'b11) && count == 1'b0)? 1'b1 : count;
always #(posedge clk , negedge rst_n)
begin
if(!rst_n)
begin
Q <= 14'h0;
count <= 1'b0;
pulse <= 1'b0;
flag <= 1'b0;
end
else
begin
flag <= flag_d;
count <= count_d;
if(flag)
begin
case(sel)
2'b00: Q <= 14'd11;//count from 11 to 1
2'b01: Q <= 14'd101;//count from 101 to 1
2'b10: Q <= 14'd1001;//count from 1001 to 1
2'b11: Q <= 14'd10001;//count from 10001 to 1
default: Q <= 14'd0;
endcase
flag <= 1'b0;
end
else
begin
if(Q != 14'h1 && Q != 14'h0)
begin
Q <= Q - 14'h1;
pulse <= 1'b1;
end
else
begin
pulse <= 1'b0;
count <= 1'b0;
end
end
end
end
endmodule
Is this code in a good coding style considering the synthesis and hardware of the circuit? if not than what changes I should apply?..
I couldn't figure out the point of flag_d and count_d. Also ( (sel == 2'b00 | sel == 2'b01 | sel == 2'b10 | sel == 2'b11) && count == 1'b0) simplifies to (count == 1'b0). sel should not be Xs or Zs.
I think you want something more like the following:
reg [13:0] next_Q;
always #* begin
if (Q==0) begin
case(sel)
2'b00 : next_Q = 14'd10;
2'b01 : next_Q = 14'd100;
2'b10 : next_Q = 14'd1000;
2'b11 : next_Q = 14'd10000;
endcase
end
else begin
next_Q = Q - 1;
end
end
always #(posedge clk, negedge rst_n) begin
if (!rst_n) begin
pulse <= 1'b0;
Q <= 14'd0;
end
else begin
// if (Q==0) pulse <= !pulse; // high and low pulse will have equal if sel is constant
pulse <= (Q!=0); // or high pulse based on sel, low is one clk
Q <= next_Q;
end
end
working example: http://www.edaplayground.com/x/GRv
module pulse(input wire [1:0] sel, // No need for the sel to be wire
input clk,
input rst_n,
output reg [13:0] Q,
output reg pulse,
input input_stb, // Input is valid
input output_ack,
output output_stb,
output input_ack); // 2 Flag model
reg s_input_ack ;
reg s_output_stb;
parameter get_inputs = 4'd0,
counter = 4'd1;
always #(posedge clk , negedge rst_n)
begin
case (state)
get_inputs:
s_input_ack <= 1;
if (s_input_ack && input_a_stb)
begin
s_input_ack <= 0;
case(sel)
00: Q <= 14'd11;//00000000001010;
01: Q <= 14'd101;//00000001100100;
10: Q <= 14'd1001;//00001111101000;
11: Q <= 14'd10001;//10011100010000;
default: Q <= 14'd0;
endcase
state <= counter;
end
counter:
begin
s_output_stb <= 1;
if (s_output_stb && output_z_ack)
begin
s_output_stb <= 0;
if(Q != 14'h1 && Q != 14'h0)
begin
Q <= Q - 1'b1;
pulse <= 1'b1;
end
else
begin
pulse <= 1'b0;
end
end
state <= get_inputs;
end
endcase
if(!rst_n)
begin
Q <= 14'h0;
pulse <= 1'b0;
s_input_ack <= 0;
s_output_stb <= 0;
end
assign input_ack = s_input_ack;
assign output_stb = s_output_stb;
end
endmodule
*Still needs work , add registers and necessary signals accordingly. Will edit at a later point in time

verilog why doesn't it make proper result in register file?

i'm making 8x32b register file below is my verilog code
module register_file(clk, reset, dstW, valW, write, srcA, srcB, valA, valB );
input clk;
input reset;
input[2:0] dstW;
input[31:0] valW;
input write;
input[2:0] srcA;
input[2:0] srcB;
output[31:0] valA;
output[31:0] valB;
reg[31:0] r0eax, r1ecx, r2edx, r3ebx, r4esi, r5edi, r6esp, r7edi;
wire[31:0] reg_input_0, reg_input_1, reg_input_2, reg_input3, reg_input4,
reg_input5, reg_input6, reg_input7;
wire[7:0] decoder_out, select;
assign valA =
(srcA == 3'b000) ? r0eax:
(srcA == 3'b001) ? r1ecx:
(srcA == 3'b010) ? r2edx:
(srcA == 3'b011) ? r3ebx:
(srcA == 3'b100) ? r4esi:
(srcA == 3'b101) ? r5edi:
(srcA == 3'b110) ? r6esp:
(srcA == 3'b111) ? r7edi: 32'bx;
assign valB =
(srcB == 3'b000) ? r0eax:
(srcB == 3'b001) ? r1ecx:
(srcB == 3'b010) ? r2edx:
(srcB == 3'b011) ? r3ebx:
(srcB == 3'b100) ? r4esi:
(srcB == 3'b101) ? r5edi:
(srcB == 3'b110) ? r6esp:
(srcB == 3'b111) ? r7edi: 32'bx;
assign decoder_out[0] = (dstW == 3'b000)? 1'b1 : 1'b0;
assign decoder_out[1] = (dstW == 3'b001)? 1'b1 : 1'b0;
assign decoder_out[2] = (dstW == 3'b010)? 1'b1 : 1'b0;
assign decoder_out[3] = (dstW == 3'b011)? 1'b1 : 1'b0;
assign decoder_out[4] = (dstW == 3'b100)? 1'b1 : 1'b0;
assign decoder_out[5] = (dstW == 3'b101)? 1'b1 : 1'b0;
assign decoder_out[6] = (dstW == 3'b110)? 1'b1 : 1'b0;
assign decoder_out[7] = (dstW == 3'b111)? 1'b1 : 1'b0;
and(select[0], write, decoder_out[0]);
and(select[1], write, decoder_out[1]);
and(select[2], write, decoder_out[2]);
and(select[3], write, decoder_out[3]);
and(select[4], write, decoder_out[4]);
and(select[5], write, decoder_out[5]);
and(select[6], write, decoder_out[6]);
and(select[7], write, decoder_out[7]);
assign reg_input_0 = select[0] ? valW : r0eax;
assign reg_input_1 = select[1] ? valW : r1ecx;
assign reg_input_2 = select[2] ? valW : r2edx;
assign reg_input_3 = select[3] ? valW : r3ebx;
assign reg_input_4 = select[4] ? valW : r4esi;
assign reg_input_5 = select[5] ? valW : r5edi;
assign reg_input_6 = select[6] ? valW : r6esp;
assign reg_input_7 = select[7] ? valW : r7edi;
always #(posedge clk or negedge reset)
begin
if(!reset) begin
r0eax <= 32'b0;
r1ecx <= 32'b0;
r2edx <= 32'b0;
r3ebx <= 32'b0;
r4esi <= 32'b0;
r5edi <= 32'b0;
r6esp <= 32'b0;
r7edi <= 32'b0;
end
else begin
r0eax <= reg_input_0;
r1ecx <= reg_input_1;
r2edx <= reg_input_2;
r3ebx <= reg_input_3;
r4esi <= reg_input_4;
r5edi <= reg_input_5;
r6esp <= reg_input_6;
r7edi <= reg_input_7;
end
end
endmodule
and testbench is as follows
module tttt;
// Inputs
reg clk;
reg reset;
reg [2:0] dstW;
reg [31:0] valW;
reg write;
reg [2:0] srcA;
reg [2:0] srcB;
// Outputs
wire [31:0] valA;
wire [31:0] valB;
integer i;
// Instantiate the Unit Under Test (UUT)
register_file uut (
.clk(clk),
.reset(reset),
.dstW(dstW),
.valW(valW),
.write(write),
.srcA(srcA),
.srcB(srcB),
.valA(valA),
.valB(valB)
);
initial begin
// Initialize Inputs
clk = 0;
reset = 1;
dstW = 0;
valW = 0;
write = 0;
srcA = 0;
srcB = 0;
i =0;
#10
reset = 0;
#10
reset = 1;
// Wait 100 ns for global reset to finish
#100;
clk=1;
valW = 100;
write = 1;
for(i=0; i<8; i = i+1) begin
clk =0;
#10;
dstW = i;
clk = 1;
#10;
clk =0;
#10;
valW = valW + 10;
clk =1;
#10;
end
#100;
write =0;
for(i=0; i<8; i=i+1 ) begin
clk = 0;
#10;
srcA = i;
srcB = i;
#10;
clk=1;
#10;
end
clk =0;
#10;
clk = 1;
// Add stimulus here
end
endmodule
and result
it just results 0 value after third i value.
i checked using red rectangular. could you give me a advice ? thanks in advance
When you synthetize your design, these warnings show up:
WARNING:Xst:1780 - Signal <reg_input7> is never used or assigned. This unconnected signal will be trimmed during the optimization process.
WARNING:Xst:1780 - Signal <reg_input6> is never used or assigned. This unconnected signal will be trimmed during the optimization process.
WARNING:Xst:1780 - Signal <reg_input5> is never used or assigned. This unconnected signal will be trimmed during the optimization process.
WARNING:Xst:1780 - Signal <reg_input4> is never used or assigned. This unconnected signal will be trimmed during the optimization process.
WARNING:Xst:1780 - Signal <reg_input3> is never used or assigned. This unconnected signal will be trimmed during the optimization process.
If the synthetizer detects that those signals are not being used, it discards them. Note that these signals affect the selection of registers 3 to 7, and because of that, you cannot see the loaded value when you read them.
But... your code assigns and use these signals, doesn't it?
assign reg_input_0 = select[0] ? valW : r0eax;
assign reg_input_1 = select[1] ? valW : r1ecx;
assign reg_input_2 = select[2] ? valW : r2edx;
assign reg_input_3 = select[3] ? valW : r3ebx;
assign reg_input_4 = select[4] ? valW : r4esi;
assign reg_input_5 = select[5] ? valW : r5edi;
assign reg_input_6 = select[6] ? valW : r6esp;
assign reg_input_7 = select[7] ? valW : r7edi;
What makes reg_input_0,1 and 2 different from reg_input_3,4,5,6 and 7 ? This:
wire[31:0] reg_input_0, reg_input_1, reg_input_2, reg_input3, reg_input4,
reg_input5, reg_input6, reg_input7;
Look: reg_input_0, reg_input_1 and reg_input_2. Then, reg_input3 (where's the underscore??)
As reg_input_3 to reg_input_7 are not defined, they default to a 1-bit signal, instead of 32 bits. When you use the multiplexer, at reg_input_3 for instance, to define its value...
assign reg_input_3 = select[3] ? valW : r3ebx;
You are actually synthetizing this:
assign reg_input_3 = select[3] ? valW[0] : r3ebx[0];
And in your clocked always, the actual register assignment is not as this:
r3ebx <= reg_input_3;
But as this:
r3ebx[0] <= reg_input_3;
This description of yours causes feedback from the register output through the input via the mentioned multiplexor. While this is ok when the there's a clock triggered register, if the synthetizer doesn't detect it, you will end up generating a lot of unnecesary multiplexers. Look at this generated schematic from the results of the synthesis process (synthetizer is XST)
The eight squares at the right are your eight registers. At the left, there are a massive amount of multiplexers. I cannot show you all of them, because the generated schematic it's too large for screen capture.
I suggest not to use an explicit loopback path with the multiplexor to decide when to write a new value to the register. Instead of that, modify your synchronous always to load a new value into the register only if that register is selected for writting:
always #(posedge clk or negedge reset)
begin
if(!reset) begin
r0eax <= 32'b0;
r1ecx <= 32'b0;
r2edx <= 32'b0;
r3ebx <= 32'b0;
r4esi <= 32'b0;
r5edi <= 32'b0;
r6esp <= 32'b0;
r7edi <= 32'b0;
end
else begin
if (select[0])
r0eax <= valW;
if (select[1])
r1ecx <= valW;
if (select[2])
r2edx <= valW;
if (select[3])
r3ebx <= valW;
if (select[4])
r4esi <= valW;
if (select[5])
r5edi <= valW;
if (select[6])
r6esp <= valW;
if (select[7])
r7edi <= valW;
end
end
This description allows the synthetizer to infer a register with CLK and CE inputs: the register will accept a new value from its D input if CE is enabled. If not, the value doesn't change. Your description makes the register to change its value on every clock cycle, whether is needed or not.
Now the circuit inferred is as this (it actually fits on screen!):
With this proposed solution, the first block, where the different reg_input_X signals are assigned, can be eliminated.
Tested using ISIM with ISE Webpack 12.4 and works :)

verilog to FSM convert

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

Resources