I am trying to perform a simple test with demo code of Clocking block, but encountered the error.
The code could be find at "EDA playground" http://www.edaplayground.com/x/3Ga
And the error says:
** Error: testbench.sv(38): A default clocking block must be specified to use the ##n timing statement.
** Error: testbench.sv(40): A default clocking block must be specified to use the ##n timing statement.
I think the clocking block has already been specified in the code.
Any Help?
As the error message says, you have to define the clocking block as default:
default clocking cb_counter #(posedge Clock);
Full code here: http://www.edaplayground.com/x/37_
The SV 2012 standard specifies that the ##n operator can only be used if there is a default clocking block defined for the module/program/interface, otherwise it wouldn't be able to know what clock event to use for the delay.
##N delays are not a very useful feature unless you can put them in the same module or interface that the clocking block is defined in. That is typically not the case because you usually put your driver code inside a class inside a package.
repeat (N) #cb_counter;
This works uniformly, even if referencing the cb through a virtual interface.
To resolve the error add default clocking cb_counter; after your clocking block.
SystemVerilog IEEE1800-2012 Section 14 Covers Clocking Blocks.
// Test program
program test_counter;
// SystemVerilog "clocking block"
// Clocking outputs are DUT inputs and vice versa
clocking cb_counter #(posedge Clock);
default input #1step output #4;
output negedge Reset;
output Enable, Load, UpDn, Data;
input Q;
endclocking
default clocking cb_counter; //<-- Set default clocking
// Apply the test stimulus
initial begin
//..
Below I have included a my method of creating a testbench clock, with the initial it is easy to work out when it will be triggered, compared to the original always the time for the first trigger my vary depending on how when the Clk is initialised.
initial begin
Clk = 0;
forever begin
#5ns Clk = ~Clk;
end
end
If you simulator allows system-verilog, I would use #5ns so that it does not rely on the timestep, I find this to more readable and reliable for code reuse.
The version from the question, used an always block.
timeunit 1ns;
// Clock generator
always
begin
#5 Clock = 1;
#5 Clock = 0;
end
Related
I'm writing some test environment for practise but facing some strange issue. I have interface and made 2 modports for master and slave. But when I check the waveforms I see that when I change something in using master modports it takes additional clock cycle to be seen by slave modport. Same happens on the opposite side too.
Can you please explain why is that happening and what I have done wrong?
Here are portions of my code.
interface axi_if ();
wire wready;
...
clocking m_cb #(posedge aclk);
default input #setup_time output #hold_time ;
...
input wready ;
...
endclocking: m_cb
clocking s_cb #(posedge aclk);
default input #setup_time output #hold_time ;
...
output wready ;
...
endclocking: c_cb
modport axi_master_modport(clocking m_cb, output aresetn);
modport axi_slave_modport( clocking s_cb, input aresetn);
endinterface
Thanks
The modports are used to create different views of the same interface, just like in the example you gave, the same ports viewed from the perspective of the master or the slave.
But I noticed you are using clocking blocks. Clocking blocks are used to view the signals in a specific clock domain. And specially, inputs and outputs sampled at different moments as I explain here.
Which one is to be used with clock generation for a simple testbench?
For eg:
always #20 clk <= ~clk
if I change it to either always_ff or always_comb both gives error
Statements in an always_comb shall not include those that block, have
blocking timing or event controls, or forkjoin statements. The always_ff
procedure imposes the restriction that it contains one and only one event
control and no blocking timing controls.
Neither. Stick to the ordinary always. always_comb and always_ff are for your design.
Can someone give me a hint as to why this interface with modports and clocking blocks might not work?
interface axis (input logic aclk );
logic [15:0] tdata_s;
logic tvalid_s;
logic tready_s;
logic [15:0] tdata_m;
logic tvalid_m;
logic tready_m;
// clocking block for AXI Stream master
clocking cb_axis_mst #(posedge aclk);
default input #1step output #3ns;
output tdata_m;
output tvalid_m;
input tready_m;
endclocking
// clocking block for AXI Stream slave
clocking cb_axis_slv #(posedge aclk);
default input #1step output #1ns;
input tdata_s;
input tvalid_s;
output tready_s;
endclocking
// AXI stream master modport for testbench only
modport tb_axis_mst_mp(clocking cb_axis_mst);
// AXI stream slave modport for testbench only
modport tb_axis_slv_mp(clocking cb_axis_slv);
endinterface
QuestaSIM 10.5c gives me a series of errors like this:
** Error: (vsim-3773) ../../../../rtl/test_driver.sv(37): Interface item 'tvalid_m' is not in modport 'tb_axis_mst_mp'.
The problem goes away if I add the ports to the modport, but my understanding was that it was sufficient to just use the clocking block.
Full code is here: https://www.edaplayground.com/x/5FzC
Your understanding is not correct. Adding a clocking block to a modport only gives you access to the signals created by the clocking block, not the signals it references.
When using clocking block signals you need to reference the clocking block scope, i.e. AXIS_MST.cb_axis_mst.tvalid_m. And instead of #posedge AXIS_MST.aclk, just use #AXIS_MST.cb_axis_mst.
One other comment about your testbench: remove the nested program/endprogram statements; they serve no purpose. Do not use program blocks.
I've met a situation where I think I have to use blocking assignment in a #(posedge clk) block. The snippet below is from a tsetbench. I want to input the data to a DUT through the testbench. input_intf is the name of an interface and wcb is a clocking block synchronizing to wclk.
#(posedge input_intf.wclk)
begin
input_intf.winc = 1;
input_intf.wcb.wdata = 8'd7;
input_intf.winc = 0;
end
I want to do the following: after the positive clock edge, inc=1 and data reading is enabled. After data is read, let inc=0. I guess maybe winc signal has no need to be synchronous with wclk? If it's the case then the snippet should be like following.
input_intf.winc = 1;
#(posedge input_intf.wclk)
input_intf.wcb.wdata <= 8'd7;
input_intf.winc = 0;
So is it true that we must use non-blocking assignment in a procedural block? When learning Verilog, I was told it's true.
Thanks!
The statement input_intf.wcb.wdata = 8'd7; is illegal. You do not use blocking or non-blocking assignments to drive clocking block outputs. See 14.16.1 Drives and non-blocking assignments in the IEEE Std 1800-2012 LRM. For other non-clocking block variables inside your interface, you use the same rules that you learned with Verilog: use non-blocking assignments to write to variables that are synchronous to a clock, and will be read by other procedural blocks on the same clock edge. That is how you avoid races.
The use of clocking blocks is generally an all or nothing approach. you should not be mixing writing to clocking block and non-clocking variables in the same procedure, and you should only be using the clocking block event to synchronize your code.
#(input_intf.wcb) // do not use posedge of any signal here.
input_intf.wcb.wdata <= 8'd7;
There are exceptions to these rules, of course, but I would make sure you know exactly how clocking blocks work before going there.
I added a clock generator to my module, and now the simulation never finishes.
always #10 clk = ~clk;
Why does the sim not finish after all initial code is done?
module test;
reg clk;
initial begin
clk = 0;
$display("Hello");
end
always #10 clk = ~clk;
endmodule
Sim results on EDA Playground: http://www.edaplayground.com/s/4/15
When you're using an always block, you need to have $finish statement in one of your initial blocks to finish the sim.
Fixed code:
module test;
reg clk;
initial begin
clk = 0;
$display("Hello");
$finish(); // <-- FIX
end
always #10 clk = ~clk;
endmodule
Sim results here: http://www.edaplayground.com/s/4/16
That said, if you also have a SystemVerilog program in your environment, the sim will automatically finish after all the initial code in your program blocks is done. From section 24.3 of IEEE 1800-2012 standard:
When all initial procedures within a program have reached their end,
that program shall immediately terminate all descendent threads of
initial procedures within that program. If there is at least one
initial procedure within at least one program block, the entire
simulation shall terminate by means of an implicit call to the $finish
system task immediately after all the threads and all their descendent
threads originating from all initial procedures within all programs
have ended.
There's no fundamental difference between initial and always: always is just initial forever. As long as anything is scheduled for future execution, then the simulation will continue (unless it is explicitly stopped); your statement continuously re-schedules the clock assignment, so the sim never stops. There really is nothing special about initial: it's not even guaranteed to run before any always blocks.
This wasn't an SV question (which I know nothing about), but I was interested to see VL's comment about automatically finishing the sim when the initial code is finished. This would break Verilog compatibility, and I'd be interested to see an LRM reference that confirms this.