Fastest way to react to an external trigger signal - verilog

An external trigger signal is sent to the FPGA. The trigger signal should be accepted only if and1 and and2 are also high at the time the trigger is received. If the trigger is accepted, a 10 microsecond duration trigger out pulse should be created. The goal is to try and minimise the time that the FPGA takes to accept/reject this external trigger signal.
module trigger(
input CLK,
input trigger,
input and1,
input and2,
output triggerOut,
);
The first attempt at a solution was the following;
assign triggerOut = trigger & and1 & and2;
The reaction time is fast but I don't think this allows the 10 microsecond trigger duration to be implemented.
The current solution is the following;
always #(posedge CLK) begin
if(trigger & and1 & and2)
triggerOut <= 1;
end
This solution allows a counter to be added, which allows the 10 microsecond trigger pulse to be implemented. The caveat is that now the reaction time to the external trigger is tied to the frequency of CLK. The reaction time can be improved by increasing the CLK frequency, but there is a limit to how high CLK can be increased.
Another possible solution may be sensitivity to the changing trigger input;
always #(posedge trigger) begin
if(trigger & and1 & and2)
triggerOut <= 1;
end
I have read that this may be bad practice. It was not clear to me why using #(posedge CLK) is preferred to #(posedge trigger). What defines the reaction time of the FPGA to a sensitivity like #(posedge trigger)? I suppose this must still be somehow tied to CLK - is this approach potentially any faster?
Are there any better approaches to improve the reaction time to the trigger input?

It's difficult to reach that goal without resorting to asynchronous logic. Fortunately, recent FPGAs have level triggered latches as primitives, so incomplete combinational always blocks not always are a bad practice.
OTOH, the 10us width triggerOutput signal needs a synchronous clock to count time, but this timer will, at a first approach, be triggered by an asynchronous input. That will surely pose a problem of cross domain clocking and the trivial solution (synchronizing with two flip-flops) will introduce some latency so the 10us pulse may not start at the same time that trigger is internally accepted, and/or be exactly 10us width. To avoid the metastability issue with triggerOutput, it can be used as an asynchronous reset signal for the 1 to 10 counter.
That all said, this module is a implementation of an asynchronous approach to your trigger detector and acceptor:
module detect_trigger (
input wire clk, // let's say it's 1 MHz (period = 1us)
input wire trigger,
input wire and1,
input wire and2,
output reg triggerOut
);
reg [3:0] cnt = 4'd0;
initial triggerOut = 1'b0;
always #* begin
if (cnt >= 4'd11)
triggerOut = 1'b0;
else if (trigger && and1 && and2)
triggerOut = 1'b1;
end
always #(posedge clk or negedge triggerOut) begin
if (triggerOut == 1'b0)
cnt <= 4'd0;
else if (cnt < 4'd11)
cnt <= cnt + 4'd1;
end
endmodule
A test bench module could be as this:
module tb;
reg clk;
reg trigger;
reg and1, and2;
wire triggerOut;
detect_trigger uut (
.clk(clk),
.trigger(trigger),
.and1(and1),
.and2(and2),
.triggerOut(triggerOut)
);
initial begin
$dumpfile ("dump.vcd");
$dumpvars(1, tb);
clk = 1'b0;
and1 = 1'b0;
and2 = 1'b0;
trigger = 1'b0;
repeat (5) begin
#3023;
and1 = 1'b1;
#2419;
and2 = 1'b1;
#1865;
and1 = 1'b0;
and2 = 1'b0;
end
$finish;
end
always begin
clk = #500 ~clk;
end
always begin
trigger = 1'b0;
#1753;
trigger = 1'b1;
#2;
end
endmodule
The output of this test bench is as follows:
You can modify and run the above design with EDA Playground here:
https://www.edaplayground.com/x/3SGs

Related

Not seeing a clock cycle delay in Vivado simulation during a register/flipflop assignment

I am trying to generate a pulse from a signal ext_sample_clk. My design currently has 2 clock signals, clk and ext_sample_clk, which I am generating through a testbench. The following is my simplified code. Besides this, I also have the clk and reset generation logic, which I have not shown for simplicity. I can share those if needed.
module tb;
reg clk;
reg rst;
reg ext_sample_clk;
reg ext_sample_clk_r1;
wire ext_sample_pulse_orig;
//clock gen logic
always
begin
clk = 1'b1;
#5; // 10 ns
clk = 1'b0;
#5;
end
// reset gen logic
initial
begin
rst = 1;
#(100);
rst = 0;
end
// ext_sample_clk logic
always
begin
ext_sample_clk = 1'b1;
#50;
ext_sample_clk = 1'b0;
#50;
end
// register the ext_sample_clk logic, should infer a flip flop
always #(posedge clk) begin
if (rst)
ext_sample_clk_r1 <= 0;
else
ext_sample_clk_r1 <= ext_sample_clk; // lhs doesn't appear to be delayed by 1 clock cycle wrt to rhs
end
assign ext_sample_pulse_orig = ext_sample_clk && !ext_sample_clk_r1;
endmodule
I am expecting to see ext_sample_clk_r1 delayed by one clock pulse compared to ext_sample_clk. But the following is what I observe when I run a simulation on Vivado.
Can anyone explain why I am not seeing a clock cycle delay in ext_sample_clk_r1 with reference to ext_sample_clk. Am I missing something ?
Since you want ext_sample_clk_r1 and ext_sample_clk to be synchronous to the same clock (clk), you need to drive them both off of posedge clk, using nonblocking assignments (<=):
initial begin
ext_sample_clk = 1'b1;
forever begin
repeat (10) #(posedge clk);
ext_sample_clk <= ~ext_sample_clk;
end
end
Here is a running example on edaplayground.
The most probably way of getting the results you see is by using a blocking assignment to ext_sample_clk instead of a non-blocking assignment. Your testbench needs to follow the same rules as if it were part of the design to avoid race conditions. Use a non-blocking assignment or have your testbench apply signals on the opposite edge.

Testbench clk not advancing

All my testbench is trying to do is verify whether or not the LED signal went high, but on Modelsim when I try and simulate it, the clock doesn't even start, but it initializes to zero. I can also step through my design so I don't appear to have an infinite loop or anything like that. Is there anything obviously wrong here, especially with regards to clock initialization and generation?
`timescale 1ns/100ps
module fir_filter_tb();
reg clk, reset_n;
reg led;
top top_level (
.clk(clk),
.reset_n(reset_n),
.led(led)
);
initial
begin
$display($time, " << Starting the Simulation >>");
clk = 1'b0; // at time 0
reset_n = 0; // reset is active
led = 0; // output is low
#10 reset_n = 1'b1; // at time 20 release reset
end
always #10 clk = ~clk;
always
begin
if (led == 1'b1) begin
$write($time, "Filter Successful");
end else begin
$write($time, "bleh you suck");
end
end
endmodule : fir_filter_tb
The problem is with the always block with led in it. Since there is no timing control, it prevents time from advancing (time remains stuck at 0). It creates an infinite zero-time loop.
One way to fix it is to use:
always #*
This will only trigger the block when led changes.

4 bit countetr using verilog not incrementing

Sir,
I have done a 4 bit up counter using verilog. but it was not incrementing during simulation. A frequency divider circuit is used to provide necessory clock to the counter.please help me to solve this. The code is given below
module my_upcount(
input clk,
input clr,
output [3:0] y
);
reg [26:0] temp1;
wire clk_1;
always #(posedge clk or posedge clr)
begin
temp1 <= ( (clr) ? 4'b0 : temp1 + 1'b1 );
end
assign clk_1 = temp1[26];
reg [3:0] temp;
always #(posedge clk_1 or posedge clr)
begin
temp <= ( (clr) ? 4'b0 : temp + 1'b1 );
end
assign y = temp;
endmodule
Did you run your simulation for at least (2^27) / 2 + 1 iterations? If not then your clk_1 signal will never rise to 1, and your counter will never increment. Try using 4 bits for the divisor counter so you won't have to run the simulation for so long. Also, the clk_1 signal should activate when divisor counter reaches its max value, not when the MSB bit is one.
Apart from that, there are couple of other issues with your code:
Drive all registers with a single clock - Using different clocks within a single hardware module is a very bad idea as it violates the principles of synchronous design. All registers should be driven by the same clock signal otherwise you're looking for trouble.
Separate current and next register value - It is a good practice to separate current register value from the next register value. The next register value will then be assigned in a combinational portion of the circuit (not driven by the clock) and stored in the register on the beginning of the next clock cycle (check code below for example). This makes the code much more clear and understandable and minimises the probability of race conditions and unwanted inferred memory.
Define all signals at the beginning of the module - All signals should be defined at the beginning of the module. This helps to keep the module logic as clean as possible.
Here's you example rewritten according to my suggestions:
module my_counter
(
input wire clk, clr,
output [3:0] y
);
reg [3:0] dvsr_reg, counter_reg;
wire [3:0] dvsr_next, counter_next;
wire dvsr_tick;
always #(posedge clk, posedge clr)
if (clr)
begin
counter_reg <= 4'b0000;
dvsr_reg <= 4'b0000;
end
else
begin
counter_reg <= counter_next;
dvsr_reg <= dvsr_next;
end
/// Combinational next-state logic
assign dvsr_next = dvsr_reg + 4'b0001;
assign counter_next = (dvsr_reg == 4'b1111) ? counter_reg + 4'b0001 : counter_reg;
/// Set the output signals
assign y = counter_reg;
endmodule
And here's the simple testbench to verify its operation:
module my_counter_tb;
localparam
T = 20;
reg clk, clr;
wire [3:0] y;
my_counter uut(.clk(clk), .clr(clr), .y(y));
always
begin
clk = 1'b1;
#(T/2);
clk = 1'b0;
#(T/2);
end
initial
begin
clr = 1'b1;
#(negedge clk);
clr = 1'b0;
repeat(50) #(negedge clk);
$stop;
end
endmodule

gate control clock generation

Here is the code first...
always#(posedge clk)
begin
if(cstate==idle) rclk<=1;
else rclk<=0;
end
always#(negedge clk)
rclk<=0;
What I want to achieve is this: every time at the rising edge of clock signal, if the signal cstate equals idle(4'b0000), the the rclk goes to one, else to zero, at the same time, every time the falling edge of clk will set the rclk to zero. THIS CODE IS NOT SYNTHESIZABLE since the compiler gives the error " the rclk signal is driven by multiple drivers".
How can I achieve the same function by other techniques?
It looks like you want a clock gate cell. Based on a 1 cycle wide enable signal generate a clock pulse which has the same high time as the input clock.
A naive way of doing this might be :
assign rclk = (cstate==idle) ? clk : 1'b0 ;
Which could easily be synthesised assign rclk = (cstate==idle) & clk ;
cstate == idle is going to glitch which is why it would normally be used by a flip-flop allowing the answer to settle before being used.
Using a clock gate cell stops you from creating glitches on the (rclk) clock line. It is common to instantiate your libraries clock gate cell in the rtl for this. In RTL it might be similar to :
reg result;
always #(posedge clk or negedge rst_n) begin
if (~rst_n) begin
result <= 1'b0;
end
else begin
result <= (cstate == idle);
end
end
assign rclk = (result) ? clk : 1'b0 ;
This means result will be stable for each clock cycle, not allowing glitches through from the comparator.
Expanded answer
I have included my example again below with waveform, I have replaced your state comparison with a simple counter which overflows to reset itself. Not the comparison is matching to 2'b10; which means the clock appears on the following count (2'b11). If the clock was to appear in exactly the same time your comparison matched then you have no glitch suppression on your clock and will likely generate unreliable hardware.
reg [1:0] counter = 0;
always #(posedge clk)
counter <= counter+1;
reg result;
wire result_a = (counter == 2'b10 );
always #(posedge clk or negedge rst_n) begin
if (~rst_n) begin
result <= 1'b0;
end
else begin
result <= result_a;
end
end
assign rclk = (result) ? clk : 1'b0 ;

My Verilog behavioral code getting simulated properly but not working as expected on FPGA

I wrote a behavioral program for booth multiplier(radix 2) using state machine concept. I am getting the the results properly during the program simulation using modelsim, but when I port it to fpga (spartan 3) the results are not as expected.
Where have I gone wrong?
module booth_using_statemachine(Mul_A,Mul_B,Mul_Result,clk,reset);
input Mul_A,Mul_B,clk,reset;
output Mul_Result;
wire [7:0] Mul_A,Mul_B;
reg [7:0] Mul_Result;
reg [15:0] R_B;
reg [7:0] R_A;
reg prev;
reg [1:0] state;
reg [3:0] count;
parameter start=1 ,add=2 ,shift=3;
always #(state)
begin
case(state)
start:
begin
R_A <= Mul_A;
R_B <= {8'b00000000,Mul_B};
prev <= 1'b0;
count <= 3'b000;
Mul_Result <= R_B[7:0];
end
add:
begin
case({R_B[0],prev})
2'b00:
begin
prev <= 1'b0;
end
2'b01:
begin
R_B[15:8] <= R_B[15:8] + R_A;
prev <= 1'b0;
end
2'b10:
begin
R_B[15:8] <= R_B[15:8] - R_A;
prev <= 1'b1;
end
2'b11:
begin
prev <=1'b1;
end
endcase
end
shift:
begin
R_B <= {R_B[15],R_B[15:1]};
count <= count + 1;
end
endcase
end
always #(posedge clk or posedge reset)
begin
if(reset==1)
state <= start;
else
begin
case(state)
start:
state <= add;
add:
state <= shift;
shift:
begin
if(count>7)
state <= start;
else
state <=add;
end
endcase
end
end
endmodule
You have an incomplete sensitivity list in your combinational always block. Change:
always #(state)
to:
always #*
This may be synthesizing latches.
Use blocking assignments in your combinational always block. Change <= to =.
Good synthesis and linting tools should warn you about these constructs.
Follow the following checklist if something does work in the simulation but not in reality:
Did you have initialized every register? (yes)
Do you use 2 registers for one working variable that you transfer after each clock (no)
(use for state 2 signals/wires, for example state and state_next and transfer after each clock state_next to state)
A Example for the second point is here, you need the next stage logic, the current state logic and the output logic.
For more informations about how to proper code a FSM for an FPGA see here (go to HDL Coding Techniques -> Basic HDL Coding Techniques)
You've got various problems here.
Your sensitivity list for the first always block is incomplete. You're only looking at state, but there's numerous other signals which need to be in there. If your tools support it, use always #*, which automatically generates the sensitivity list. Change this and your code will start to simulate like it's running on the FPGA.
This is hiding the other problems with the code because it's causing signals to update at the wrong time. You've managed to get your code to work in the simulator, but it's based on a lie. The lie is that R_A, R_B, prev, count & Mul_Result are only dependent on changes in state, but there's more signals which are inputs to that logic.
You've fallen into the trap that the Verilog keyword reg creates registers. It doesn't. I know it's silly, but that's the way it is. What reg means is that it's a variable that can be assigned to from a procedural block. wires can't be assigned to inside a procedural block.
A register is created when you assign something within a clocked procedural block (see footnote), like your state variable. R_A, R_B, prev and count all appear to be holding values across cycles, so need to be registers. I'd change the code like this:
First I'd create a set of next_* variables. These will contain the value we want in each register next clock.
reg [15:0] next_R_B;
reg [7:0] next_R_A;
reg next_prev;
reg [3:0] next_count;
Then I'd change the clocked process to use these:
always #(posedge clk or posedge reset) begin
if(reset==1) begin
state <= start;
R_A <= '0;
R_B <= '0;
prev <= '0;
count <= '0;
end else begin
R_A <= next_R_A;
R_B <= next_R_B;
prev <= next_prev;
count <= next_count;
case (state)
.....
Then finally change the first process to assign to the next_* variables:
always #* begin
next_R_A <= R_A;
next_R_B <= R_B;
next_prev <= prev;
next_count <= count;
case(state)
start: begin
next_R_A <= Mul_A;
next_R_B <= {8'b00000000,Mul_B};
next_prev <= 1'b0;
next_count <= 3'b000;
Mul_Result <= R_B[7:0];
end
add: begin
case({R_B[0],prev})
2'b00: begin
next_prev <= 1'b0;
end
.....
Note:
All registers now have a reset
The next_ value for any register defaults to it's previous value.
next_ values are never read, except for the clocked process
non-next_ values are never written, except in the clocked process.
I also suspect you want Mul_Result to be a wire and have it assign Mul_Result = R_B[7:0]; rather than it being another register that's only updated in the start state, but I'm not sure what you're going for there.
A register is normally a reg, but a reg doesn't have to be a register.

Resources