Two Modports of same Interface have 1 clock cycle difference - system-verilog

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.

Related

Why use ports in interfaces?

The SystemVerilog LRM (IEEE 1800-2017) describes ports in interfaces as follows:
One limitation of simple interfaces is that the nets and variables declared within the interface are only used to connect to a port with the same nets and variables. To share an external net or variable, one that makes a connection from outside the interface as well as forming a common connection to all module ports that instantiate the interface, an interface port declaration is required. The difference between nets or variables in the interface port list and other nets or variables within the interface is that only those in the port list can be connected externally by name or position when the interface is instantiated. Interface port declaration syntax and semantics are the same as those of modules (see 23.2.2).
What is the first sentence saying exactly? I don't see the limitation.
In the second sentence, what is an example of an external signal? How do you decided whether a signal should be declared inside the interface or as a port to the interface? The text used in the LRM just doesn't click for me.
The problem is shown with the simple_bus example that follows the section of the IEEE 1800-2017 SystemVerilog LRM you quoted.
There are two instances of the interface sb_intf1 and sb_intf2 each creating a unique set of internal signals (req, int, ...). If clk had also been declared as internal signal, there would also be two clock signals. What's not shown in the example is the code generating the clock signal. That could have been in the top module or another module. They would have needed to add continuous assignments to get the generated clock signal to each the internal clk in each interface instance.
By putting the shared signals in the interface in their port declarations, it makes it much easier to join the common signals.
interface simple_bus (input logic clk); // Define the interface
logic req, gnt;
logic [7:0] addr, data;
logic [1:0] mode;
logic start, rdy;
endinterface: simple_bus
module memMod(simple_bus a); // Uses just the interface
logic avail;
always #(posedge a.clk) // the clk signal from the interface
a.gnt <= a.req & avail; // a.req is in the 'simple_bus' interface
endmodule
module cpuMod(simple_bus b);
...
endmodule
module top;
logic clk = 0;
simple_bus sb_intf1(clk); // Instantiate the interface
simple_bus sb_intf2(clk); // Instantiate the interface
memMod mem1(.a(sb_intf1)); // Reference simple_bus 1 to memory 1
cpuMod cpu1(.b(sb_intf1));
memMod mem2(.a(sb_intf2)); // Reference simple_bus 2 to memory 2
cpuMod cpu2(.b(sb_intf2));
endmodule

Can someone explain the control flow of modules in System Verilog

I know how to link modules but could someone explain the flow of calling the modules to be used when I want it to be used.
Like have a state machine and depending on the state I can call a module to activate, or like if I need to repeat a process how to go back to a module earlier in a state machine.
again I get the instantiating part like this
wire clk;
wire sig;
wire out;
A a(clk, sig, topout);
B b(clk, sig);
endmodule
but can someone explain how to call modules and how the control flow works in general for them?
(I am new to HDLs so I appreciate any help)
Verilog is a language specifically developed to simulate behavior of hardware. Hardware is a set of transistors and other elements which always statically presented and function in parallel. Functioning of such elements could be enabled or disabled, but the hardware is still present.
Verilog is similar to the hardware in the sense that all its elements are always present, intended for parallel functioning.
The basic functional elements of Verilog are gates, primitives and procedural blocks (i.e., always blocks). Those blocks are connected by wires.
All those elements are then grouped in modules. Modules are used to create logical partitioning of the hardware mode. They cannot be 'called'. They can be instantiated in a hierarchical manner to describe a logical structure of the model. They cannot be instantiated conditionally since they represent pieces of hardware. Different module instances are connected via wires to express hierarchical connectivity between lower-level elements.
There is one exception however, the contents of an always block is pure software. It describes an algorithmic behavior of it and as such, software flow constructs are allowed inside always block (specific considerations must be used to make it synthesizable).
As it comes to simulation, Verilog implements an event-driven simulation mode which is intended to mimic parallel execution of hardware. In other words, a Verilog low level primitive (gate or always block) is executed only if at least one of its inputs changes.
The only flow control which is usually used in such models is a sequence of input events and clocks. The latter are used to synchronize results of multiple parallel operations and to organize pipes or other sequential functions.
As I mentioned before, hardware elements can be enabled/disabled by different methods, so the only further control you can use by implementing such methods in your hardware description. For example, all hardware inside a particular module can be turned off by disabling clock signal which the module uses. There could be specific enable/disable signals on wires or in registers, and so on.
Now to your question: your code defines hierarchical instantiation of a couple of modules.
module top(out);
output wire out;
wire clk;
wire sig;
A a(clk, sig, out);
B b(clk, sig);
endmodule
Module 'top' (missing in your example) contains instances of two other modules, A and B. A and B are module definitions. They are instantiated as corresponding instances 'a' and 'b'. The instances are connected by signals 'clk', which is probably a clock signal, some signal 'sig' which is probably an output of one of the modules and input in another. 'out' is output of module top, which is probably connected to another module or an element in a higher level of hierarchy, not shown here.
The flow control in some sense is defined by the input/output relation between modules 'A' and 'B'. For example:
module A(input clk, input sig, output out);
assign out = sig;
...
endmodule
module B(input clk, output sig);
always#(posedge clk) sig <= some-new-value;
...
endmodule
However, in general it is defined by the input/output relation of the internal elements inside module (always blocks in the above example). input/output at the module port level is mostly used for semantic checking.
In the event-driven simulation it does not matter hardware of which module is executed first. However as soon as the value of the 'sig' changes in always#(posedge clk) of module 'B', simulation will cause hardware in module 'A' (the assign statement to be evaluated (or re-evaluated). This is the only way you can express a sequence in the flow at this level. Same as in hardware.
If you are like me you are looking at Verilog with the background of a software programmer. Confident in the idea that a program executes linearly. You think of ordered execution. Line 1 before line 2...
Verilog at its heart wants to execute all the lines simultaneously. All the time.
This is a very parallel way to program and until you get it, you will struggle to think the right way about it. It is not how normal software works. (I recall it took me weeks to get my head around it.)
You can prefix blocks of simultaneous execution with conditions, which are saying execute the lines in this block when the condition is true. All the time the condition is true. One class of such conditions is the rising edge of a clock: always #(posedge clk). Using this leads to a block of code that execute once every time the clk ticks (up).
Modules are not like subroutines. They are more like C macros - they effectively inline blocks of code where you place them. These blocks of code execute all the time any conditions that apply to them are true. Typically you conditionalize the internals of a module on the state of the module arguments (or internal register state). It is the connectivity of the modules through the shared arguments that ensures the logic of a system works together.

Using clocking blocks and modports inside Interfaces

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.

System Verilog Clocking block

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

system verilog interface for multiple clocks

My DUT is a memory controller. I have to write a system verilog interface for the DUT.
Memory Controller DUT supports 32 AXI Masters.
When I am writing an AXI interface, it will consist of ACLK which is generated and passed on through the top(verification). When I am connecting this interface to the DUT, will there be 32(AXI ACLK) + 1(clk on which DUT is working) , inall 33 clks to the DUT..
I am quite confused in these.
logically there should be only one clk in the DUT..
Thanks in advance for the answers
Shared interface signals should be declared as input ports to your interface. That way you can tie them all together to make one logical signal.
interface myintf(input wire sig_shared);
wire sig_internal;
endinterface
module top;
wire s1,s2;
myintf i1(s1);
myintf i2(s1);
myintf i[31:0](s2);
endmodule
Now signals i1.sig_internal and i2.sig_internal will be independent, but i1.sig_shared and i2.sig_shared are logically equivalent. Same thing for i[0].sig_shared thru i[31].sig_shared.