Modulating a signal on-off at 10kHz - verilog

I have written the code for the input clk = 10MHz and output_clk = 5MHz. I want to modulate the output_clk on-off at 10kHz as shown in the example signal. But, my current code only modifies the output_clk to be 10kHz rather than modulating the signal on-off at 10kHz while output_clk remains 5MHz. Any suggestions how to achieve the same?
Please see the example output_clk signal I want as the output.
// mclk1 = 10MHz
always#(50)
begin
mclk1 <= ~mclk1;
end
reg [31:0]count_500;
always#(posedge mclk1)
begin
if (count_500 == 500-1)
begin
mdata1 <= ~mdata1;
count_500 <= 0;
end
else
begin
count_500 <= count_500 + 1;
end
end

You can create a new signal which follows mclk1 but is gated by the 10kHz signal:
wire mclk1gated = mdata1 ? mclk1 : 0;
Here is a complete code example:
module tb;
bit mclk1,mdata1;
// mclk1 = 10MHz
always#(50)
begin
mclk1 <= ~mclk1;
end
reg [31:0]count_500=0;
always#(posedge mclk1)
begin
if (count_500 == 500-1)
begin
mdata1 <= ~mdata1;
count_500 <= 0;
end
else
begin
count_500 <= count_500 + 1;
end
end
wire mclk1gated = mdata1 ? mclk1 : 0;
initial begin
#300us $finish;
end
endmodule

Related

Module instantiation with the "number sign"

I have the main module with FIFO stuff.
Here it is:
module syn_fifo #(
parameter DATA_WIDTH = 8, // inpit capacity
parameter DATA_DEPTH = 8 // the depth of the FIFO
)
(
input wire clk,
input wire rst,
// Write_______________________________________________
input wire [DATA_WIDTH-1:0]din, // the input data
input wire wren, // Write anable
output wire full,
// Read________________________________________________
output wire [DATA_WIDTH-1:0]dout, // The output data
input wire rden, // Read enable
output wire empty
);
integer q_size; // The queue size(length)
integer golova; // The queue beginning
integer hvost; // The end of queue
reg [DATA_WIDTH-1:0]fifo[DATA_DEPTH-1:0];
assign full = (q_size == DATA_DEPTH) ? 1'b1: 1'b0; // FIFO is full
/*
True { full = (q_size==DATA_TEPTH) = 1 }, then wire "full" goes to "1" value
False { full = (q_size==DATA_TEPTH) = 0 }, then wire "full" goes to "0" value
*/
assign empty = (golova == hvost); // FIFO is empty
assign dout = fifo[hvost]; // FWFT (other write mode)
integer i;
//___________(The queue fullness)___________________
always #(posedge clk or posedge rst)
begin
if (rst == 1'b1)
begin
for (i = 0; i < DATA_DEPTH; i = i + 1) // incrementing the FIFO
fifo[i] <= 0; // Resetting the FIFO
golova <= 0; // Resetting the queue start variable
end
else
begin //Write_______________________________________
if (wren && ~full)
begin
fifo[golova] <= din; // putting data in to the golova
if (golova == DATA_DEPTH-1) // restrictions for the queue beginning
golova <= 0; // Reset the beginning
else
golova <= golova + 1; // other occurence incrementing
end
end
end
//Reading
always #(posedge clk or posedge rst)
begin
if (rst == 1'b1)
begin
hvost <= 0;
end
else
begin
if (rden && !empty)
/*for staying inside the queue limits - make the check of non equality of the "hvost" & "queue size"*/
begin
if (hvost == DATA_DEPTH-1) // if hvost = DATA_DEPTH-1, then
hvost <= 0; // Reset hvost
else
hvost <= hvost + 1;
end
end
end
always # (posedge clk)
begin
if (rst == 1'b1) begin
q_size <= 0;
end
else
begin
case ({wren && ~full, rden && ~empty} )
2'b01: q_size <= q_size + 1; // RO
2'b10: q_size <= q_size - 1; // WO
default: q_size <= q_size; // read and write at the same time
endcase
end
end
endmodule
Also i've got the testbench module down delow:
`timescale 1ns / 1ps
module fifo_tb();
localparam CLK_PERIOD = 10;
reg clk;
reg rst;
always begin
clk <= 1'b0;
#(CLK_PERIOD / 2);
clk <= 1'b1;
#(CLK_PERIOD / 2);
end
localparam DATA_WIDTH = 8;
localparam DATA_DEPTH = 4;
reg [DATA_WIDTH-1:0]din;
reg wren;
reg rden;
wire [DATA_WIDTH-1:0]dout;
wire empty;
wire full;
wire wr_valid;
wire rd_valid;
task write;
input integer length;
begin
if (length) begin
#(posedge clk);
wren <= 1'b1;
while (length) begin
#(posedge clk);
if (wr_valid) begin
length <= length - 1;
if (length == 1) begin
wren <= 1'b0;
end
end
end
end
end
endtask
task read;
input integer length;
begin
if (length) begin
#(posedge clk);
rden <= 1'b1;
while (length) begin
#(posedge clk);
if (rd_valid) begin
length <= length - 1;
if (length == 1) begin
rden <= 1'b0;
end
end
end
end
end
endtask
initial begin
rst <= 1'b0;
wren <= 1'b0;
rden <= 1'b0;
#50;
rst <= 1'b1;
#50;
rst <= 1'b0;
#200;
/* Test Start */
//write(4);
//read(4);
/* Test Stop */
#1000;
$finish;
end
assign wr_valid = wren & ~full;
assign rd_valid = rden & ~empty;
always #(posedge clk) begin
if (rst == 1'b1) begin
din <= 0;
end else begin
if (wr_valid == 1'b1) begin
din <= din + 1;
end
end
end
// write?
always begin
#400;
write(5);
#15;
write(7);
#25;
write(3);
#15;
write(9);
#15;
write(1);
#10000;
end
// read?
always begin
#420;
read(3);
#37;
read(13);
#21;
read(7);
#15;
read(9);
#15;
read(4);
#20;
read(7);
#10000;
end
initial begin
$dumpfile("test.vcd");
$dumpvars(0,fifo_tb);
end
syn_fifo #(.DATA_WIDTH(DATA_WIDTH),
.DATA_DEPTH(DATA_DEPTH)) dut ( .clk(clk),
.rst(rst),
.din(din),
.wren(wren),
.full(full),
.dout(dout),
.rden(rden),
.empty(empty));
endmodule
Trying to compile all of it with iVerilog + GTKwave + Win10 by next command:
C:\Program Files\iverilog\bin>iverilog -o fifo.v fifo_tb.v
The compiler gives me the next message:
fifo_tb.v:138:error: Unknown module type:syn_fifo
2 error(s) during elaboration.
These modules were missing:syn_fifo referenced 1 times
At the necessary line "138" maybe the main mistake is covered by the "Number sign" in module instantiation?
/*132|*/ initial begin
/*133|*/ $dumpfile("test.vcd");
/*134|*/ $dumpvars(0,fifo_tb);
/*135|*/ end
/*136|*/
/*137|*/ syn_fifo #(.DATA_WIDTH(DATA_WIDTH),
/*138|*/ .DATA_DEPTH(DATA_DEPTH)) dut ( .clk(clk),
/*139|*/ .rst(rst),
/*140|*/ .din(din),
/*141|*/ .wren(wren),
/*142|*/ .full(full),
/*143|*/ .dout(dout),
/*144|*/ .rden(rden),
/*145|*/ .empty(empty));
/*146|*/
/*147|*/ endmodule
I'm not shure of that.
Seems like you are indicating fifo.v to be your output file, try:
iverilog -o syn_fifo.tb -s fifo_tb fifo_tb.v fifo.v
-o -> output file
-s -> top module (in this case, the test one)
(after everything, include all the files)
Then, to run it:
vvp syn_fifo.tb
Thank you, dear #m4j0rt0m
I just forgot to type in the output file name at the CMD window. Was very exhausted so haven't noticed such a detail)))
Usually it looks like:
iverilog -o OUTPUT_FILE_NAME fifo_tb.v fifo.v
And also I tried your advice, and it's finally done!

how to properly connect receiver, sender and top and make them dependent from each other - RS232

I've got a simple project which requires me to write a code for RS232 receiver and sender, then put them together and, finally, test if it works properly. I've prepared code for both sender and receiver (and also connecting block - top). My problem is that I don't know how to connect them, so they could work with each other properly.
The main issue is that I can't "transfer" data from data_o to data_i because of the fact that one is reg and second - wire. I wouldn't like to use inout for these purposes. I can't figure out any possible modifications to make it work.
Another issue is putting some flags that could kind of follow idea like this: if receiving -> not sending, if sending -> not receiving.
Here's my code:
top.v
`timescale 1ns / 1ps
module top (
clk_i,
rst_i,
RXD_i,
data_i,
TXD_o,
data_o
);
input clk_i;
input rst_i;
input RXD_i;
output TXD_o;
//the problem is here, can't data_i <= data_o because output is reg
input [7:0] data_i;
output [7:0] data_o;
receiver r1(clk_i, RXD_i, data_o);
sender s1(clk_i, data_i, TXD_o);
endmodule
receiver.v
`timescale 1ns / 1ps
module receiver (
clk_i,
RXD_i,
data_o
);
//inputs and outputs
input clk_i;
input RXD_i;
output reg [7:0] data_o;
//counter values
parameter received_bit_period = 5208;
parameter half_received_bit_period = 2604;
//state definitions
parameter ready = 2'b00;
parameter start_bit = 2'b01;
parameter data_bits = 2'b10;
parameter stop_bit = 2'b11;
//operational regs
reg [12:0] counter = 0; //9765.625Hz
reg [7:0] received_data = 8'b00000000;
reg [3:0] data_bit_count = 0;
reg [1:0] state = ready;
//latching part
reg internal_RXD;
always #(posedge clk_i) //latch RXD_i value to internal_RXD
begin
internal_RXD = RXD_i;
end
always #(clk_i) //receiving process
begin
case (state)
ready :
begin
if (internal_RXD == 0)
begin
state <= start_bit;
counter <= counter + 1;
end
else
begin
state <= ready;
counter <= 0;
data_bit_count <= 0;
end
end
start_bit :
begin
if (counter == half_received_bit_period)
begin
if (internal_RXD == 0)
begin
state <= data_bits;
counter <= 0;
end
end
else
begin
state <= start_bit;
counter <= counter + 1;
end
end
data_bits :
begin
if (counter == received_bit_period)
begin
received_data[data_bit_count] <= internal_RXD;
data_bit_count <= data_bit_count + 1;
counter <= 0;
if (data_bit_count == 8)
state <= stop_bit;
end
else
counter <= counter + 1;
end
stop_bit:
begin
counter <= counter + 1;
if (counter == received_bit_period)
begin
state <= ready;
data_o <= received_data;
end
end
endcase
end
endmodule
sender.v
`timescale 1ns / 1ps
module sender (
clk_i,
data_i,
TXD_o
);
//inputs and outputs
input clk_i;
input [7:0] data_i;
output reg TXD_o;
//counter values
parameter received_bit_period = 5208;
parameter half_received_bit_period = 2604;
//state definitions
parameter ready = 1'b0;
parameter data_bits = 1'b1;
//operational regs
reg [12:0] counter = 0; //9765.625Hz
reg [9:0] framed_data = 0;
reg [3:0] data_bit_count = 0;
reg state = ready;
always #(posedge clk_i) //sending process
begin
case (state)
ready :
begin // flag needed?
state <= data_bits;
TXD_o <= 1;
framed_data[0] <= 1'b0;
framed_data[8:1] <= data_i;
framed_data[9] <= 1'b1;
counter <= 0;
end
data_bits :
begin
counter <= counter + 1;
if (data_bit_count == 10)
begin // flag needed?
state <= ready;
data_bit_count <= 0;
TXD_o <= 1;
end
else
begin
if (counter == received_bit_period)
begin
data_bit_count <= data_bit_count + 1;
end
TXD_o <= framed_data[data_bit_count];
end
end
endcase
end
endmodule
You don't!
In all CPU's and FPGA nowadays the read and write data path are separate buses. You will find that also with all CPU cores. Have a look at AXI or AHB bus protocols from ARM.
What is more worrying is the way you have implemented your functions. You would at least need some 'data valid' signal for the transmitter to know when there is valid data to transmit and for the receive when valid data has arrived.
Even that is not enough because for the TX the connecting logic would need to know when the data has been send and the next byte can go out.
You need to make a (preferably standard) CPU interface which talks to your UART. (For beginner I would not use AXI.)
As to your flags: they would come from within the CPU interface.
Last: a UART should be capable of transmitting and receiving at the same time.

Independent Nexys 4 clocks desynchronizing over time

We are developing a program which needs synchronized clocks on two devices to measure the fly time of ultrasound signals.
The problem is that when we synthesize the program and test it on two independent Nexys4 FPGAs the distance tends to decrease over time (0.13 cm/s). This ratio is constant, and always decreasing, leading us to think that the problem is in the code.
And when we synthesize the program in only one Nexys 4, no decrease is seen over time.
We have a module to listen for signals (3 signals per slave, and 3 slaves) called dataListener: the signal SendCommand is the control signal for an UART module which sends the direction and command to an SRF02 ultrasound, this module is exactly the same on both devices.
module dataListener(
input mclk,
input clkSync,
input reset,
input rxDataRdy,
output wire[7:0] command,
output reg[7:0] direction,
output reg read,
output reg sendCommand,
output reg dataChanged,
output reg [1:0] slave,
output reg [1:0] sensor
);
parameter dir0 = 8'd0;
parameter dir1 = 8'd3;
parameter dir2 = 8'd6;
parameter rangingCommand = 8'd87;
parameter readCommand = 8'd94;
//parameter clkTime = 0.000000001; // 1ns Simulation // 10ns FPGA
//parameter windowTime = 0.08; // 80 ms
//parameter listenTime = 0.07; // 70ms
parameter windowCyclesDuration = 8000000;
parameter listenCyclesDuration = 7000000;
reg [54:0] windowCounter;
reg emitSent;
reg readSent;
reg slave1;
reg slave2;
reg slave3;
assign command = emitSent ? readCommand : rangingCommand;
///////////////////////////////////////////////////////////////////
always #(posedge mclk) begin
if( reset )begin
sensor <= 2'b0;
windowCounter <= 55'b0;
emitSent <= 0;
readSent <= 0;
slave <=0;
end else begin
if( clkSync ) begin
if( windowCounter >= windowCyclesDuration )begin //Window ended
windowCounter <= 55'b0; //resetCounter
emitSent <= 0;
readSent <= 0;
if( sensor == 2'd2 )begin
sensor <= 2'b0;
if(slave == 2'd2)
slave <= 2'b0;
else
slave <= slave+1'b1;
end else begin
sensor <= sensor + 1'b1;
end
end else begin
windowCounter <= windowCounter + 1'b1; //Window in process
if(!emitSent)begin
sendCommand <= 1;
end
else if( (windowCounter >= listenCyclesDuration) && !readSent)begin //listen done, time to send the read command
sendCommand <= 1;
end
end
if(sendCommand)begin
sendCommand <= 0; //Shut down "sendCommand" signal.
if(!emitSent)
emitSent <= 1;
else
readSent <= 1;
end
end
/// Process incoming data
if( rxDataRdy )begin
read <= 1;
end else if( read )begin
read <= 0;
end
end
end
//////////////////////////////////////////////////////////////////
always #( sensor ) begin
case(sensor)
2'd0: begin
direction <= dir0;
end
2'd1: begin
direction <= dir1;
end
2'd2: begin
direction <= dir2;
end
default: begin
direction <= dir0;
end
endcase
end
endmodule
A module on the slave device which sends the commands:
module slave(
input mclk,
input clkSync,
input reset,
output [7:0] command,
output [7:0] direction,
output reg sendCommand,
output inWindow
);
parameter numSlave = 2'b0; //Between 0-2
parameter dir=8'd0; //Depends on the slaves direction
parameter comm=8'd92;
assign command = comm;
assign direction = dir;
parameter windowCyclesDuration = 8000000;
reg [54:0] windowCounter;
reg [1:0] sensor, slave;
reg commandSent;
assign inWindow = (slave == numSlave);
always #(posedge mclk) begin
if( reset )begin
windowCounter <= 55'b0;
sendCommand <=0;
commandSent <= 1;
slave <= 2'b0;
sensor <= 2'b0;
end else begin
if( clkSync ) begin
if( windowCounter >= windowCyclesDuration )begin //Window ended
windowCounter <= 55'b0; //resetCounter
commandSent <= 0;
if( sensor == 2'd2 )begin
sensor <= 2'b0;
if(slave == 2'd2)
slave <= 2'b0;
else
slave <= slave + 1'b1;
end else begin
sensor <= sensor + 1'b1;
end
end else begin
windowCounter <= windowCounter + 1'b1; //Window in process
if( inWindow && !commandSent)begin //im in my window and command not sent yet
sendCommand <= 1;//send when a new window is about to begin
commandSent <= 1;
end
end
if(sendCommand)begin
sendCommand <= 0; //Shut down "sendCommand" signal.
end
end
end
end
endmodule
The signal clkSync is only activated when both devices are 'Sync', which happend only at the start of functioning through a cable which is then remove to allow movement.
Here is the sync module of the master:
module SyncM(
input mclk,
input reset,
input response1,
input response2,
input response3,
output reg call1,
output reg call2,
output reg call3,
output reg clkSync,
output reg slave1,
output reg slave2,
output reg slave3
);
always # (posedge mclk) begin
if(reset)begin
clkSync <= 0;
slave1 <= 0;
slave2 <= 0;
slave3 <= 0;
call1 <= 0;
call2 <= 0;
call3 <= 0;
end else begin
if( btn && !call1 )begin
call1 <= 1;
call2 <= 1;
call3 <= 1;
clkSync <= 1;
end
if(response1)
slave1 <= 1;
if(response2)
slave2 <= 1;
if(response3)
slave3 <= 1;
end
end
endmodule
And the slave sync module, the call signal is send from the master to slave by a cable.
`timescale 1ns / 1ps
module SyncS(
input reset,
input call,
output reg clkSync,
output reg response
);
always # (reset or call) begin
if(reset) begin
clkSync <= 0;
response <= 0;
end else begin
if (call) begin
response <= 1;
clkSync <= 1;
end
end
end
endmodule
I haven't understand all of your code. But, the problems seems to be, that you rely on the external oscillator on your FPGA board. If you use two boards, both oscillators will not run on exactly the same frequency. So, if you compensate for the phase shift right only once after startup, the clocks will desynchronize after some time. That's why it worked with just one board.
There are two possible solutions:
Use just one clock source (oscillator) and forward the clock to other board.
Periodically compensate for phase shifts.
Both solutions require a more or less steady connection between both boards.

Place 30-574 Poor placement for routing between an IO pin and BUFG

`timescale 1ns / 1ps
module stopwatch(
input clock,
input reset,
input increment,
input start,
output [6:0] seg,
output dp,
output [3:0] an
);
reg [3:0] reg_d0, reg_d1, reg_d2, reg_d3; //registers that will hold the individual counts
reg [22:0] ticker;
wire click;
//the mod 1kHz clock to generate a tick ever 0.001 second
always # (posedge (clock) or posedge (reset))
begin
if(reset)
begin
ticker <= 0;
end
else
begin
if (start)
begin
if(ticker == (100000 - 1)) //if it reaches the desired max value reset it
ticker <= 0;
else if (increment)
ticker <= ticker;
else
ticker <= ticker + 1;
end
end
end
//increment a second everytime rising edge of down button
reg [3:0] inc_temp;
always # (posedge (increment))
begin
if (reg_d3 == 9)
inc_temp = 0;
else
inc_temp = reg_d3 + 1;
end
assign click = ((ticker == (100000 - 1))?1'b1:1'b0); //click to be assigned high every 0.001 second
//update data start from here
always # (posedge (clock) or posedge (reset))
begin
if(reset)
begin
reg_d0 <= 0;
reg_d1 <= 0;
reg_d2 <= 0;
reg_d3 <= 0;
end
else
begin
if (increment)
begin
reg_d3 <= inc_temp;
reg_d0 <= reg_d0;
reg_d1 <= reg_d1;
reg_d2 <= reg_d2;
end
else if (click) //increment at every click
begin
if(reg_d0 == 9) //xxx9 - 1th milisecond
begin
reg_d0 <= 0;
if (reg_d1 == 9) //xx99 - 10th milisecond
begin
reg_d1 <= 0;
if (reg_d2 == 9) //x999 - 100th milisecond
begin
reg_d2 <= 0;
if(reg_d3 == 9) //9999 - The second digit
reg_d3 <= 0;
else
reg_d3 <= reg_d3 + 1;
end
else
reg_d2 <= reg_d2 + 1;
end
else
reg_d1 <= reg_d1 + 1;
end
else
reg_d0 <= reg_d0 + 1;
end
else
begin
reg_d3 <= reg_d3;
reg_d0 <= reg_d0;
reg_d1 <= reg_d1;
reg_d2 <= reg_d2;
end
end
end
//Mux for display 4 7segs LEDs
localparam N = 18;
reg [N-1:0]count;
always # (posedge clock or posedge reset)
begin
if (reset)
count <= 0;
else
count <= count + 1;
end
reg [6:0]sseg;
reg [3:0]an_temp;
reg reg_dp;
always # (*)
begin
case(count[N-1:N-2])
2'b00 :
begin
sseg = reg_d0;
an_temp = 4'b1110;
reg_dp = 1'b1;
end
2'b01:
begin
sseg = reg_d1;
an_temp = 4'b1101;
reg_dp = 1'b0;
end
2'b10:
begin
sseg = reg_d2;
an_temp = 4'b1011;
reg_dp = 1'b1;
end
2'b11:
begin
sseg = reg_d3;
an_temp = 4'b0111;
reg_dp = 1'b0;
end
endcase
end
assign an = an_temp;
//update the data to display to LEDs
reg [6:0] sseg_temp;
always # (*)
begin
case(sseg)
4'd0 : sseg_temp = 7'b1000000;
4'd1 : sseg_temp = 7'b1111001;
4'd2 : sseg_temp = 7'b0100100;
4'd3 : sseg_temp = 7'b0110000;
4'd4 : sseg_temp = 7'b0011001;
4'd5 : sseg_temp = 7'b0010010;
4'd6 : sseg_temp = 7'b0000010;
4'd7 : sseg_temp = 7'b1111000;
4'd8 : sseg_temp = 7'b0000000;
4'd9 : sseg_temp = 7'b0010000;
default : sseg_temp = 7'b0111111; //dash
endcase
end
assign seg = sseg_temp;
assign dp = reg_dp;
endmodule
I'm trying to design a stop watch, but I'm stuck at the increment thing. The intent is when I press increment(a button), the reg_d3 will increment by one and hold its state until the button is released. I'm able to make the clock stop when the button is pressed, but I can't update the reg_d3. I always receive
[Place 30-574] Poor placement for routing between an IO pin and BUFG
I don't know why; I use increment in the clkdivider just find.
I think the problem is related to this part of your code:
always # (posedge (increment))
begin
if (reg_d3 == 9)
inc_temp = 0;
else
inc_temp = reg_d3 + 1;
end
You are basically using an input signal as a clock, and that is completely discouraged when designing for a FPGA. The P&R tries to re-route an IO pin to a BUFG (global buffer) inside the FPGA so it can be used as a clock.
For FPGA design, you should use one clock signal for all your always #(posedge...) constructions, and use input signals to conditionally load/update the register.
To do that, you have first to synchronize your increment signal to your clk, so avoiding metastability issues:
reg incr1=1'b0, incr2=1'b0;
always #(posedge clk) begin
incr1 <= increment;
incr2 <= incr1;
end
wire increment_synched = incr2;
Then, deglitch increment_synched and detect a rising edge in it:
reg [15:0] incrhistory = 16'h0000;
reg incr_detected = 1'b0;
always #(posedge clk) begin
incrhistory <= { incrhistory[14:0] , increment_synched };
if (incrhistory == 16'b0011111111111111)
incr_detected <= 1'b1;
else
incr_detected <= 1'b0;
end
To detect a valid rising edge, we store a history of the last 16 values of increment_synched. When a valid steady change from 0 to 1 is produced, the history pattern will match the pattern 0011111111111111. Then, and only then, we signal it by raising incr_detected to 1. The next clock cycle, the history pattern won't match the above sequence, and incr_detected will go down to 0 again.
Prior to that, multiple bounces in the push button increment is connected to would cause many transitions, leading to many increments. Using a pattern matching like that eliminates those glitches caused by multiple bounces. With 1Khz clock as you seem to use, this pattern should be enough.
Now you can use incr_detected in your original code, incr_detected wil be 1 for just a single clk cycle.
always # (posedge clk) begin
if (incr_detected) begin
if (reg_d3 == 9)
inc_temp = 0;
else
inc_temp = reg_d3 + 1;
end
end
You can test these additions using the following simulation:
http://www.edaplayground.com/x/AQY
What you will see there is a module that takes your increment input signal from the outside, and generate a glitch-free one-cycle pulse when the input signal makes a final transition from low to high level.
Actually, I've written two versions. The second one tries to mimic the behaviour of a monostable, so the input won't be sampled for a specific period of time after the first low to high transition is detected.
You will see that the second version produces a pulse much sooner than the first version, but it's also prone to take a glitch as valid rising edge, as showed in the simulation. I'd stick with the first version then.

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