clock gating verilog code not working correctly - verilog

I'm to trying to code a clock gating logic that allows data to pass only at the posedge write_clk_en. the code is compiled correctly in EDA playground but the output is not as intended.So according to code,
# (posedge write_clk_en)begin
data_in[3] <= 1'b1;
end
at this instance the write_clk_en is disabled, so data_in[3] NBA should be halted and it waits for next valid posedge (which is the next posedge of write_clk_en here), data_in[3] should be written. But that is not happening, rather the gated clock period is also getting considered and the NBA assignment is occurring even when write_clk_en is gated for 4th pulse.What could be the issue ?.the wave form is shown here.
the sv code :
module tb;
logic [4:0] data_in;
logic write_clk;
logic write_clk_en;
logic write_clk_mod;
logic [5:0] write_clk_init;
always//write_clk 500M
begin
write_clk =0;
#10 write_clk = 1;
#10 write_clk = 0;
end
initial begin
$dumpfile("dump.vcd");
$dumpvars;
#10000 $finish;
end
initial begin
data_in=5'b00000;
write_clk_init = 6'b000000;
write_clk_mod=0;
end
initial begin
write_clk_init =6'b110111;
end
initial begin
repeat (3) begin
#(posedge write_clk)begin
if(write_clk_init[0]==1 || write_clk_init[0]==0)
write_clk_mod<=write_clk_init[0];
end
#(posedge write_clk)begin
if(write_clk_init[1]==1 || write_clk_init[1]==0)
write_clk_mod<=write_clk_init[1];
end
#(posedge write_clk)begin
if(write_clk_init[2]==1 || write_clk_init[2]==0)
write_clk_mod<=write_clk_init[2];
end
#(posedge write_clk)begin
if(write_clk_init[3]==1 || write_clk_init[3]==0)
write_clk_mod<=write_clk_init[3];
end
#(posedge write_clk)begin
if(write_clk_init[4]==1 || write_clk_init[4]==0)
write_clk_mod<=write_clk_init[4];
end
#(posedge write_clk)begin
if(write_clk_init[5]==1 || write_clk_init[5]==0)
write_clk_mod<=write_clk_init[5];
end
end
end
always # (*) begin
write_clk_en = write_clk & write_clk_mod;
end
initial begin
# (posedge write_clk_en)begin
data_in[0] <= 1'b1;
end
# (posedge write_clk_en)begin
data_in[1] <= 1'b1;
end
# (posedge write_clk_en)begin
data_in[2] <= 1'b1;
end
# (posedge write_clk_en)begin
data_in[3] <= 1'b1;
end
# (posedge write_clk_en)begin
data_in[4] <= 1'b1;
end
end
endmodule

Within initial blocks, change your NBAs to BAs. NBAs should only be used within an always #(posedge clocksignal) block
Take also into account that in simulations, #(posedge clocksignal) blocks (without the reserved word always) are treated as delays (wait until a rising edge clk event happens, then continue simulation). By the way you have written these blocks in your initial statements, I didn't know for sure if you were aware of their true behaviour. I've rewritten those #(posedge) blocks to make the simulation flow a bit clear.
I have also merged some of your initial blocks into one. Every initial block you have is started at the same time (simulation time 0). Particulary, write_clk_init is assigned in two different initial blocks.
This edited code works as expected. It is also available at https://www.edaplayground.com/x/3VYk
module tb;
reg [4:0] data_in;
reg write_clk;
reg write_clk_en;
reg write_clk_mod;
reg [5:0] write_clk_init;
initial begin
$dumpfile("dump.vcd");
$dumpvars;
#10000 $finish;
end
initial begin
data_in = 5'b00000;
write_clk_init = 6'b110111;
write_clk_mod = 0;
write_clk = 0;
repeat (3) begin
#(posedge write_clk);
if(write_clk_init[0]==1 || write_clk_init[0]==0)
write_clk_mod = write_clk_init[0];
#(posedge write_clk);
if(write_clk_init[1]==1 || write_clk_init[1]==0)
write_clk_mod = write_clk_init[1];
#(posedge write_clk);
if(write_clk_init[2]==1 || write_clk_init[2]==0)
write_clk_mod = write_clk_init[2];
#(posedge write_clk);
if(write_clk_init[3]==1 || write_clk_init[3]==0)
write_clk_mod = write_clk_init[3];
#(posedge write_clk);
if(write_clk_init[4]==1 || write_clk_init[4]==0)
write_clk_mod = write_clk_init[4];
#(posedge write_clk);
if(write_clk_init[5]==1 || write_clk_init[5]==0)
write_clk_mod = write_clk_init[5];
end
end
always #* begin
write_clk_en = write_clk & write_clk_mod;
end
initial begin
#(posedge write_clk_en);
data_in[0] = 1'b1;
#(posedge write_clk_en);
data_in[1] = 1'b1;
#(posedge write_clk_en);
data_in[2] = 1'b1;
#(posedge write_clk_en);
data_in[3] = 1'b1;
#(posedge write_clk_en);
data_in[4] = 1'b1;
end
always begin
write_clk = #10 ~write_clk;
end
endmodule

Related

Monostable multivibrator simulation

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

Delay counter not incrementing? FSM

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.

Verilog deterministic behavior

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.

Valid-Ready handshake in Verilog

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.

Verilog + FPGA: If statement for switch

This is my code to control a RC Servo Motor. The code basically turns the 50MHz frequency to 1KHz.
I am using one of the switches on the FPGA to control the motor. Until the switch is on, none of the program should run.
But that doesn't seem to be happening. I don't know what I'm doing wrong. It's probably a very silly mistake.
module servo(clk,rst,clk_out,switch);
input clk,rst,switch;
output reg clk_out;
reg [15:0] counter;
always #(posedge clk or posedge rst or posedge switch)
if (switch) begin
if(rst) begin
counter <=16'd0;
clk_out <= 1'b0;
end
else if(counter==16'd25000) begin
counter <=16'd0;
clk_out <= ~clk_out;
end
else begin
counter<=counter+1;
end
end
endmodule
Also I tried changing the duty cycle so the motor rotates faster, but this doesn't seem to be working.
module servo (clk,rst,clk_out,switch);
input clk,rst,switch;
output reg clk_out;
reg [15:0] counter;
always #(posedge clk or posedge rst)
if(rst)
begin
counter<=16'd0;
clk_out <= 1'b0;
end
else if (switch)
begin
if(counter==16'd12500)
begin
clk_out <= 1'b1;
counter<=counter+1;
end
else
if(counter==16'd50000)
begin
counter <= 16'd0;
clk_out <= 1'b0;
end
else
begin
counter<=counter+1;
end
end
endmodule
Here's my cut at it - I haven't simulated it, so beware!
module servo(clk,rst,clk_out,switch);
input clk,rst,switch;
output reg clk_out;
reg [15:0] counter;
// clocked blocks should only have the clock and maybe a reset
// in the sensitivity list
always #(posedge clk or posedge rst) begin
if(rst) begin
counter <=16'd0;
clk_out <= 1'b0;
end
else if (switch) begin // 'switch' used as an enable
if(counter==16'd25000) begin
counter <=16'd0;
clk_out <= ~clk_out;
end
else begin
counter<=counter+1;
end
end
else begin
counter <= 16'd0;
end
end
endmodule
First thing I did was to remove the entry for switch in the sensitivity list - for synchronous logic, there should only be a clock and maybe a reset here.
The reset clause for the logic should be first, so I moved the test for switch using it as an enable signal in the main body of the always block. The counter will only run now if switch is high.

Resources