i got a code like below with clk = #10 ~clk
always# (posedge clk)begin
for (g=0;g<8;g=g+1) begin
ws = 1;
#20
ws = 0;
#20;
end
so is there any other way to make the delay 20 synthesizaeble in the coding above?
A flip-flop is the only way of synthesising a delay:
always #(posedge clk)
q <= d;
With clk = #10 ~clk;, q will be #10 later than d.
The question appear not to be how to synthesis a #20 but how to control the timing for signals in to a RAM. Digital design are based around clock edges, with each positive or negative edge a set distance a part, this is the period of the clock or 1/frequency.
To sequence events as you describe you need a FSM (Finite state machine) to control or sequence it. I have included a small example below:
Available on EDA Playground
module tb;
//Tb component
reg clk;
reg rst_n;
initial begin :clk_and_reset
clk = 0;
rst_n = 0;
#40 rst_n = 1;
#40;
forever begin
#20 clk = ~clk;
end
end
//Design
reg [1:0] state;
reg [1:0] next_state;
reg [31:0] counter;
reg ws;
localparam S_IDLE = 'd0;
localparam S_WAIT = 'd1;
localparam S_OFF = 'd2;
always #(posedge clk, negedge rst_n) begin
if (~rst_n) begin
state <= S_IDLE;
end
else begin
case(state)
S_IDLE : begin
state <= S_WAIT;
counter <= 'b0;
S_WAIT :
if (counter < 32'd10) begin
state <= S_WAIT; //Wait for 10 clock cycles
counter <= counter + 1;
end
else begin
state <= S_OFF;
counter <= 'b0;
end
S_OFF : state <= S_IDLE;
default : state <= S_IDLE; //IDLE
end
end
//Output decode based on state
always #* begin
//ws goes high when in Wait state
ws = (state == S_WAIT);
end
//Test program
initial begin
repeat (10) begin
#(posedge clk);
$display("%4t : State %b: ws :%b", $realtime, state, ws);
end
$finish();
end
endmodule
This could be expanded by staying in idle until triggered then by having counter and staying in wait for x number of clocks, x number of clocks in OFF before going back to idle and waiting to be triggered again.
Update
I have updated the code example to stay in the WAIT state for 10 clock cycles to demonstrate how to control the delay between transitions.
Related
The monostable module implements a monostable multivibrator. It takes in three inputs (clk, reset, trigger) and outputs a single (pulse).
The trigger input triggers the module. When triggered, the output signal (pulse) will switch to a high position for a period of clock ticks, and then return to a low position. The pulse width of the output signal can be set via the PULSE_WIDTH parameter, which represents the period in clock ticks that the signal should stay high.
Now, what is happening is when it gets triggered, immediately output signal (pulse) is getting high.
When triggered, the output signal (pulse) should be high on the next active edge of clk. What changes can be done ?
module monostable(
input clk,
input reset,
input trigger,
output reg pulse = 0
);
parameter PULSE_WIDTH = 20;
reg [4:0] count = 0;
wire countReset = reset | (count == PULSE_WIDTH);
always #(posedge trigger, posedge countReset) begin
if (countReset) begin
pulse <= 1'b0;
end else begin
pulse <= 1'b1;
end
end
always #(posedge clk, posedge countReset) begin
if(countReset) begin
count <= 0;
end else begin
if(pulse) begin
count <= count + 1'b1;
end
end
end
endmodule
module monostable_tb();
reg clk;
reg reset;
reg trigger;
wire pulse;
parameter PULSE_WIDTH = 20;
monostable imonostable(.*);
initial begin
clk=0;
forever #50 clk=~clk;
end
initial begin
$monitor("trigger=%b pulse=%b, count = %0d",trigger,pulse,imonostable.count);
$dumpfile("monostable_tb.vcd");
$dumpvars(0,monostable_tb);
trigger=1'b0;
reset = 1'b0;
#(posedge clk) reset = 1'b1;
#(posedge clk) reset = 1'b0;
#(posedge clk) trigger=1'b1;
#(posedge clk) trigger=1'b0;
repeat(25) #(posedge clk);
$finish;
end
endmodule
Here is a simplified design which sets the output one cycle after the input trigger pulse, and keeps the output high for 20 cycles:
module monostable(
input clk,
input reset,
input trigger,
output reg pulse = 0
);
parameter PULSE_WIDTH = 20;
reg [4:0] count;
always #(posedge clk, posedge reset) begin
if (reset) begin
pulse <= 1'b0;
end else if (trigger) begin
pulse <= 1'b1;
end else if (count == PULSE_WIDTH-1) begin
pulse <= 1'b0;
end
end
always #(posedge clk, posedge reset) begin
if(reset) begin
count <= 0;
end else if (pulse) begin
count <= count + 1'b1;
end
end
endmodule
It now uses a single clock signal, instead of 2. It also uses a simple reset signal, which can avoid potential glitches causing unwanted asynchronous resets.
You should also use nonblocking assignments in the testbench:
#(posedge clk) reset <= 1'b1;
#(posedge clk) reset <= 1'b0;
#(posedge clk) trigger<= 1'b1;
#(posedge clk) trigger<= 1'b0;
If a 1-clock synchronous delay is needed, then run the output thru a flip flop.
module monostable(
input clk,
input reset,
input trigger,
output reg pulse = 0
);
parameter PULSE_WIDTH = 20;
reg [4:0] count = 0;
reg reg_pulse_temp;
wire countReset = reset | (count == PULSE_WIDTH);
always #(posedge trigger, posedge countReset) begin
if (countReset) begin
reg_pulse_temp <= 1'b0;
end else begin
reg_pulse_temp <= 1'b1;
end
end
always #(posedge clk, posedge countReset) begin
if(countReset) begin
count <= 0;
// reset the flop
pulse <= 0;
end else begin
if(pulse) begin
count <= count + 1'b1;
end
end
// flip flop
pulse <= reg_pulse_temp;
end
endmodule
I am not getting any response from the uut in the testbench. The module exp2_up_down_counter works ok without testbench, but gives output as xxxx when instantiated in the testbench.
Here is the main module of the up-down counter:
`timescale 1ns/1ps
module exp2_up_down_counter (input clk, reset, mode, output reg [3:0] count);
always #(posedge clk)
if (reset == 1)
count <= 0; // reset the counter if reset is high
else if (mode == 1)
count <= count + 1; // works as up counter if mode pin is high
else
count <= count - 1; // works as down counter if mode pin is low
endmodule
Simulation without testbench:
Testbench for up-down counter
`timescale 1ns/1ps
module exp2_up_down_counter_tb;
reg clk, reset, mode;
wire [3:0] count;
exp2_up_down_counter uut(.clk(clk), .reset(reset), .mode(mode), .count(count));
initial begin
clk = 1'b0;
end
always #(*) #5 clk <= ~clk;
initial begin
// initializing the inputs
reset = 1;
mode = 0;
#5;
reset = 0;
#10
mode = 1;
#5000 $finish;
end
endmodule
Simulation with testbench:
In exp2_up_down_counter, count is declared as a reg. This means that its default value is X at time 0. Since the reset signal is synchronous to the clock, you need to wait for the 1st posedge of clock before you release the reset. Currently, the reset is released at the 1st posedge of clock in the testbench, which is a race condition. Therefore, count does not get assigned the value of 0, and it retains the value of X for the whole simulation.
You need to delay the reset release. For example, change:
#5;
reset = 0;
to:
#15;
reset = 0;
However, it is better to drive your synchronous inputs in the testbench the same way you drive your signals in the design: using #(posedge clk) and using nonblocking assignments (<=):
initial begin
reset = 1;
mode = 0;
repeat (2) #(posedge clk);
reset <= 0;
repeat (1) #(posedge clk);
mode <= 1;
#5000 $finish;
end
Also, this is a more standard way to drive the clock in the testbench:
always #5 clk = ~clk;
Is following code deterministic? i.e Can it trigger error1 or error2? Is there a recommended way for generating clk2 (same as clk3)
module Test();
reg clk1;
reg clk2;
reg clk3;
reg reset;
initial
begin
clk1 <= 0;
forever
begin
#100;
clk1 <= ~clk1; // 2x freq of clk2/clk3
end
end
always #(posedge clk1)
begin
if(reset) clk2 <= 0;
else clk2 <= ~clk2;
end
initial
begin
clk3 <= 0;
#300;
forever
begin
#200;
clk3 <= ~clk3;
end
end
initial
begin
reset <= 1;
#500;
reset <= 0;
#100;
repeat (20) #(posedge clk1);
$display("Test end");
$finish;
end
always #(posedge clk2)
begin
if(clk1 == 0) $display("Error1");
end
always #(posedge clk3)
begin
if(clk1 == 0) $display("Error2");
end
endmodule;
Your code has problems, but nothing to do with determinism—it is fully deterministic. This is one case where using NBAs <= creates a problem. clk2 gets updated in a delta cycle after clk1 and clk3. That means if you have clock domain crossings from the latter to clk2 like
always_ff #(posedge clk3)
A <= B;
always_ff #(posedge clk2)
C <= A; // A has already been updated with the value of B
So never use NBAs to make assignments to clocks.
I wanted to design a FIFO having a certain depth and width. The Verilog code of the FIFO is written in Vivado 2017.4. The code is able to to read the input data, but it is only showing XX as the output. The design sources and test bench of the FIFO is given below. Help me to find the problem.
module fifo #(parameter WIDTH=8, parameter DEPTH=8) (
input wire [WIDTH-1:0] data_in,
output reg [WIDTH-1:0] data_out,
output reg data_valid,
input wire reset,
input wire clk
);
function integer clog2(input reg [32-1:0] value);
begin
value = value-1;
for (clog2=0; value>0; clog2=clog2+1)
value = value>>1;
end
endfunction
reg [WIDTH-1:0] data [DEPTH-1:0];
reg [clog2(DEPTH)-1:0] write_pointer;
reg [clog2(DEPTH)-1:0] read_pointer;
always #(posedge clk) begin
if (reset == 1'b0) begin
write_pointer <= 0;
read_pointer <= 1;
data_valid <= 0;
end else begin
if (write_pointer == DEPTH-1) write_pointer <= 0;
else write_pointer <= write_pointer + 1;
if (read_pointer == DEPTH-1) read_pointer <= 0;
else read_pointer <= read_pointer + 1;
data[write_pointer] <= data_in;
data_out <= data[read_pointer];
end
if (read_pointer == 0) data_valid <= 1'b1;
end
endmodule
test bench
`timescale 1ns / 1ps
module fifo_tb;
parameter WIDTH = 16;
parameter DEPTH = 8;
reg reset;
reg clk;
reg [(WIDTH-1):0] data_in;
wire [(WIDTH-1):0] data_out;
wire data_valid;
fifo #(WIDTH,DEPTH) U0(data_in,data_out,data_valid,reset,clk);
initial begin
clk = 0;
reset = 1;
#1 reset = 0;
#1 reset = 1;
end
// Create clock
always
#5 clk = ~clk;
reg signed [15:0] rom_memory [4096-1:0];
integer i=0;
initial
begin
$readmemh("C:\\Users\\input_7_zz.txt",rom_memory);
end
always#(posedge clk )
begin
if(~reset)
begin
data_in <= 0;
end
else
begin
data_in <= rom_memory[i];
i <= i+ 1;
end
end
endmodule
In your test bench code the clock is changed every 5 ticks:
// Create clock
always
#5 clk = ~clk;
The reset in RTL uses posedge of this clock:
always #(posedge clk) begin
if (reset == 1'b0) begin
write_pointer <= 0;
read_pointer <= 1;
data_valid <= 0;
So, the reset action could happen only if the posedge clk could be detected during the reset period. In other words you have a synchronous reset.
Nevertheless, in your test bench code your reset lasts only a single tick:
initial begin
clk = 0;
reset = 1;
#1 reset = 0;
#1 reset = 1; // << one tick after the reset was asserted.
end
Potentially you have 2 possible solutions.
1) keep the synchronous reset, but make sure that the posedge of the clk could be detected during the reset. So, make it bigger than a clock cycle (or at least half clock cycle if you are sure when it comes). Something like 5 should work in your case. Make it 10 or more to be sure for arbitrary starting points.
initial begin
clk = 0;
reset = 1;
#1 reset = 0;
#5 reset = 1; // << 5 tick after the reset was asserted.
The reset above will last from time 1 to time 6. The first posegde will happen at time 5. So, it should be sufficient in your case.
2) you can use an asynchronous reset in RTL which will look as the following:
always #(posedge clk or reset) begin
if (reset == 1'b0) begin
write_pointer <= 0;
read_pointer <= 1;
data_valid <= 0;
In the above case the always block will be executed whenever 'reset' changes. However you have to be careful about the timing of other assignment there. They could happen when you deassert reset with some offset from the posedge clk.
As I have known, D flipflop samples its input value at every positive edge
of the clock.
Thus, it will produce a 1 cycle delay. Right?
But why does my D flip flop does not produce a 1 cycle delay?
module flipflop(
input clk,
input rstn,
input [7:0] i_data,
output reg [7:0] o_data
);
always #(posedge clk) begin
if (~rstn) begin
o_data <= 0;
end
else begin
o_data <= i_data;
end
end
endmodule
module test;
reg clk;
reg [7:0] i_data;
reg rstn;
wire [7:0] o_data;
initial begin
clk = 0;
rstn = 1;
i_data = 0;
#20;
rstn = 0;
#30;
rstn = 1;
#20;
i_data = 8'hFA;
#20;
i_data = 8'hF0;
#20
i_data = 8'hF1;
#20
#10 $finish;
end
always #10 clk = !clk;
flipflop flipflop(
.clk (clk),
.rstn(rstn),
.i_data(i_data),
.o_data(o_data)
);
initial begin
$dumpfile("flipflop.vcd");
$dumpvars();
end
endmodule
My D flip flop functions like a combinational circuit here.
You've run up against Verilog simulator event scheduling subtleties! Changing the data assignments to use nonblocking assignments is probably the easiest fix.
#20;
i_data <= 8'hFA;
#20;
i_data <= 8'hF0;
#20
i_data <= 8'hF1;
#20
What was happening in your original version is that the clock and the input data were scheduled to happen at the same time. Since the simulator can only do one thing at a time, it has to decide if it will change the clock or the data first. It changed the data first, so when the clock edge comes along, the input data has already changed to the next value so it looks like the data is slipping through the FF.
Nonblocking assignments (<=) are scheduled to happen after all the blocking assignments (=) have been done. So making the data assignments nonblocking ensures that they happen after the blocking-assigned clock edges.
Another way to rewrite things to work would be:
initial begin
#(posedge clk) i_data = 8'hFA;
#(posedge clk) i_data = 8'hF0;
#(posedge clk) i_data = 8'hF1;
end
The simulator is probably doing something like this:
initial begin
clk = 0;
rstn = 1;
i_data = 0;
#10;
clk = !clk;
#10;
rstn = 0;
clk = !clk;
#10;
clk = !clk;
#10;
clk = !clk;
#10;
rstn = 1;
clk = !clk;
#10;
clk = !clk;
#10
i_data = 8'hFA; //Input updated
clk = !clk; //Clock event
//o_data assigned here
#10;
clk = !clk;
#10;
i_data = 8'hF0;
clk = !clk;
#20
i_data = 8'hF1;
#20
#10 $finish;
end
Since the clock event is occurring last in each time step from your testbench, it looks like the flop is being assigned immediately. You likely want your testbench to be entirely slaved off the clock so Marty's suggestion of using #(posedge...) will achieve this. You could also simply delay your assignments once at the very beginning:
initial begin
clk = 0;
#1;
rstn = 1;
i_data = 0;
#20;
rstn = 0;
#30;
rstn = 1;
#20;
i_data = 8'hFA;
#20;
i_data = 8'hF0;
#20
i_data = 8'hF1;
#20
#10 $finish;
end