Hi Dave.
I have been giving your input and Mantis 210 some thought based on feedback from the committee. I believe that macros, default values of input ports, interfaces and configs provide features to achieve the goal of evolving a module's port definition over time. Would appreciate your feedback as well as feedback from the SV-BC.
Consider this design:
module svbc210();
logic ck;
logic d0,q0;
logic d1,q1;
dff dff0(d0,ck,q0);
dff dff1(d1,ck,q1);
endmodule
module dff (input logic d,ck, output logic q);
always_ff @(posedge ck)
q <= d;
endmodule
The first issue raised was:
1. Modules that need different views (RTL, DFT) at different points in
the design cycle. Additional ports are added as the view is refined.
A typical case might be a flip-flop with or without scan ports.
Option 1: Declare all ports and ground unused scan inputs early on:
module dff (input logic d,
input logic ck,
output logic q,
input logic si = 1'b0,
input logic se = 1'b0,
);
always_ff @(posedge ck)
q <= d;
endmodule
Option 2: Declare 2 modules and use configs to replace them
Before:
module dff (input logic d,ck, output logic q);
always_ff @(posedge ck)
q <= d;
endmodule
config top;
design rtlLib.svbc210;
default liblist rtlLib dfflib;
endconfig
After:
module dff (input logic d,
input logic ck,
output logic q,
input logic si = 0,
input logic se = 0,
);
always_ff @(posedge ck)
if (se)
q <= si;
else
q <= d;
endmodule
config top;
design rtlLib.svbc210;
default liblist rtlLib dfflib;
instance svbc2010.submodulea use lib1.submodulea:config;
endconfig
config submodulea;
design rtllib.submodulea;
default liblist rtlLib scandfflib;
endconfig
This approach allows one to address specific instances as needed. One
can add a parameter to the design to select scan or non-scan flop
behavior:
module dff #(parameter SE = 0)
(input logic d,
input logic ck,
output logic q,
input logic si = 0,
input logic se = 0,
);
if (SE)
always_ff @(posedge ck)
if (se)
q <= si;
else
q <= d;
else
always_ff @(posedge ck)
q <= d;
endmodule
Option 3: Use macros with default arguments
At project start define the DFF macro:
`define DFF(inst,d,ck,q) dff inst(d,ck,q)
As the project adds more features to the flop, add macro aruguments
with default values:
`define DFF(inst_a,d_a,ck_a,q_a,si_a=(1'b0),se_a=(1'b0)) \
dff inst(.d(d_a),.ck(c_a),.q(q_a),.si(si_a),.se(se_a));
Now `DFF can continue to be called as:
`DFF(inst,d,ck,q)
and as users address the new functionality, add port connections:
`DFF(inst,d,ck,q,si,se)
2. Modules that appear multiple times in the design with different ports.
This can happen when different generations of a common module are used in
different parts of an SoC.
See response to #1, Option 2. Configurations allow different definitions of
same module to be used by different IPs in SoC. In fact configurations become
a necessity when integration IP from many teams.
3. Modules that appear in multiple SoCs in the same family, with differences
controlled by per-design features. Here the desire is to maintain a single
codebase for all variants.
For SoCs I've seen that it's very challenging to get one module shared
by multiple IPs to be of the same version. If I have a sub-IP A and
it is integrated into IP B and IP C. It may be that IP B has rev 1.0
and IP C has rev 1.2, so despite appearances, IP B and IP C require
configs to ensure that they use their respective versions of IP A.
Lastly, this response has not proposed how to use an interface to address
this issue. Consider the dff module now coded using and interface:
interface dff_intf;
logic d;
logic q;
logic ck;
endinterface
module dff (interface intf);
always_ff @(posedge intf.ck)
intf.q <= intf.d;
endmodule
module dff_inst();
dff_intf intf;
dff dff(dff_intf);
endmodule
Now add scan and enable only where desired. First the interface is extended with scan
signals and scan and non-scan modports are added:
interface dff_int;
logic d;
logic q;
logic ck;
logic si;
logic se;
modport se_driver(output q, input d, input, ck, input si, input se);
modport driver(output q, input d, input, ck);
endinterface
The dff module can include scan if the appropriate parameter value is set:
module dff #(parameter SE=0) (interface intf);
if (SE) begin
always_ff @(posedge intf.ck)
if (intf.se)
intf.q <= intf.si;
else
intf.q <= intf.d;
end else begin
always_ff @(posedge intf.ck)
intf.q <= intf.d;
end
endmodule
And here are two instances of the dff, one with and one without scan:
module dff_inst();
dff_intf intf;
dff_intf se_intf;
dff dff(dff_intf.driver);
dff #(.SE(1)) se_dff (dff_intf.se_driver);
endmodule
An interface scenario was also offered. It covered a bus with a sideband.
module bus_master(
bus_if.master B
`ifdef USE_SIDEBAND
, sideband_if.master SB
`endif
)
endmodule
module bus_slave(
bus_if.slave B
`ifdef USE_SIDEBAND
, sideband_if.slave SB
`endif
);
endmodule
`ifdef USE_SIDEBAND
module bus_sideband_helper(
sideband_if.slave SBI,
sideband_if.master SBO
);
endmodule
`endif
module top();
bus_if B1();
`ifdef USE_SIDEBAND
sideband_if SB1(), SB2();
`endif
bus_master bm(
.B(B1)
`ifdef USE_SIDEBAND
, .SB(SB1)
`endif
);
bus_slave bs(
.B(B1)
`ifdef USE_SIDEBAND
, .SB(SB2)
`endif
);
`ifdef USE_SIDEBAND
bus_sideband_helper bsh( .SBI(SB1), .SBO(SB2) );
`endif
endmodule
This example attempts to add ports by changing the module definition. The suggestion
is to instead add ports by extending the bus interface. Consider the bus_master:
module bus_master(
bus_if.master B
`ifdef USE_SIDEBAND
, sideband_if.master SB
`endif
)
endmodule
There's a bus interface already. Isn't the sideband part of the larger bus specification?
Instead of introducing a sideband interface port, how about extending the bus interface:
interface bus_primary;
...
endinterface
interface bus_sideband;
...
endinterface
interface bus_if #(parameter USE_SIDEBAND=0)();
bus_primary bus_primary();
modport master(...);
modport slave(...);
if (USE_SIDEBAND) begin
bus_sideband bus_sideband();
modport sideband(...);
modport sideband_slave(...);
modport sideband_master(...);
end
endinterface
And use the corresponding modports:
module bus_master #(parameter USE_SIDEBAND=0) (
interface.master B
);
...
endmodule
module bus_slave #(parameter USE_SIDEBAND=0) (
interface.slave B
);
...
endmodule
module bus_sideband_helper(
interface.sideband SBI,
);
...
endmodule
module top #(USE_SIDEBAND=0) ();
bus_if #(.USE_SIDEBAND(USE_SIDEBAND) B1();
bus_master #(.USE_SIDEBAND(USE_SIDEBAND)) bm(
.B(B1)
);
bus_slave #(.USE_SIDEBAND(USE_SIDEBAND)) bs(
.B(B1)
);
if (USE_SIDEBAND)
bus_sideband_helper bsh( .SBI(B1));
endmodule
You could make this more flexible by choosing the modport at the instantiation
or by using tasks to access the interfaces.
It may be also interesting to note that each module uses only those modports of
which it's aware. Adding modports to address future bus specfications does not
necessarily require one to go back and change all agents on the bus. This
notion of feature control and visibility would be very helpful when trying to
address the following:
`ifdef BUS_GEN2
`define USE_SIDEBAND
`endif
interface bus_if;
logic signal1;
`ifdef BUS_GEN2
logic signal2;
`endif
...
endinterface
`ifdef BUS_GEN2
interface sideband_if;
logic signal1;
endinterface
...
`endif
"Here I have two different generations of the bus specification: Gen1 and Gen2. In the 2nd generation,
another signal is added to the main bus, and the sideband is introduced.
If one assumes that Gen1 and Gen2 are implemented in the same module with parameters, then
let's update the previous example accordingly. First the Gen1 and Gen2 bus:
interface bus_primary();
...
endinterface
interface bus_sideband();
...
endinterface
interface bus_if #(parameter GEN=1)();
bus_primary bus_primary();
if (GEN==2) begin: SIDEBAND
bus_sideband #(.GEN(GEN) bus_sideband();
modport default(...);
modport slave(...);
modport master(...);
end
modport master(...);
modport slave(...);
endinterface
module bus_master #(parameter GEN = 1) (
interface.master B
);
...
endmodule
module bus_slave #(parameter GEN = 1) (
interface.slave B
);
...
endmodule
module bus_sideband_helper #(parameter GEN = 1) (
interface.sideband SBI,
);
...
endmodule
module top #(GEN=1) ();
bus_if #(.GEN(GEN) B1();
bus_master #(.GEN(GEN)) bm(
.B(B1)
);
bus_slave #(.GEN(GEN)) bs(
.B(B1)
);
if (GEN==2)
bus_sideband_helper bsh( .SBI(B1));
endmodule
In summary, there appear to be several features in the language that enable one to
evolve the definition of module ports through the design process.
-- Matt Maidment mmaidmen@ichips.intel.com From: owner-sv-bc@eda.org [mailto:owner-sv-bc@eda.org] On Behalf Of Gates, David Sent: Monday, February 14, 2011 10:05 AM To: Gates, David; sv-bc@eda.org Subject: [sv-bc] RE: Mantis 210 Use Cases To expand on this a little, consider the following definitions of the interfaces: `ifdef BUS_GEN2 `define USE_SIDEBAND `endif interface bus_if; logic signal1; `ifdef BUS_GEN2 logic signal2; `endif ... endinterface `ifdef BUS_GEN2 interface sideband_if; logic signal1; endinterface ... `endif Here I have two different generations of the bus specification: Gen1 and Gen2. In the 2nd generation, another signal is added to the main bus, and the sideband is introduced. Suppose I want to create an SoC that wants to control two external instances of such a bus, one for Gen1 and one for Gen2. (Assume I've added appropriate I/O to module 'top' to create an interface controller.) I now need to instantiate both a Gen1 controller and a Gen2 controller. I want to replace all of my conditional `ifdef behavior with parametric behavior. With current SystemVerilog, I need to run an external preprocessor to generate modules top_gen1, top_gen2 (and two versions of all of the submodules) with different values for `define BUS_GEN2. Each user can do this, but it won't lead to very standard source code, especially as the configurability gets more complicated. (You can standardize the flow using IP-XACT generator chains though.) ~ Dave From: owner-sv-bc@eda.org [mailto:owner-sv-bc@eda.org] On Behalf Of Gates, David Sent: Monday, February 14, 2011 8:59 AM To: sv-bc@eda.org Subject: [sv-bc] RE: Mantis 210 Use Cases For my action item for the 1/31 meeting, I tried to figure out how to use interfaces with internal generate statements, but ran into the problem that we are internally using conditional interface ports. Here is a cooked-up example that uses `ifdef instead of parameters. module bus_master( bus_if.master B `ifdef USE_SIDEBAND , sideband_if.master SB `endif ) endmodule module bus_slave( bus_if.slave B `ifdef USE_SIDEBAND , sideband_if.slave SB `endif ); endmodule `ifdef USE_SIDEBAND module bus_sideband_helper( sideband_if.slave SBI, sideband_if.master SBO ); endmodule `endif module top(); bus_if B1(); `ifdef USE_SIDEBAND sideband_if SB1(), SB2(); `endif bus_master bm( .B(B1) `ifdef USE_SIDEBAND , .SB(SB1) `endif ); bus_slave bs( .B(B1) `ifdef USE_SIDEBAND , .SB(SB2) `endif ); `ifdef USE_SIDEBAND bus_sideband_helper bsh( .SBI(SB1), .SBO(SB2) ); `endif endmodule I don't see how using generate statements inside an interface can describe this situation parametrically. ~ Dave From: Gates, David Sent: Friday, January 28, 2011 11:01 AM To: 'sv-bc@eda.org' Subject: Mantis 210 Use Cases I polled internally at AMD and uncovered the following 5 use cases where language support for configurable module port lists would be useful: 1. Modules that need different views (RTL, DFT) at different points in the design cycle. Additional ports are added as the view is refined. A typical case might be a flip-flop with or without scan ports. 2. Modules that appear multiple times in the design with different ports. This can happen when different generations of a common module are used in different parts of an SoC. 3. Modules that appear in multiple SoCs in the same family, with differences controlled by per-design features. Here the desire is to maintain a single codebase for all variants. 4. Modules that might have the same types of ports, but where the port names are changed to indicate the actual client. This customizes the design to make debugging / tracing of signals easier. 5. Modules that have lists of ports with indexed names, because a parameterized port array cannot be or is not used for other reasons. I think generated ports/connections would be usable in the first 3 cases. The second case really isn't possible to cover using a global `ifdef, but I believe the SV configuration mechanism could be used to alias two different modules to the same name in different parts of a design. For the 4th & 5th cases, you'd need a more complex interaction between the SV lexer/parser, such that a parsed parameter can modify a lexical name. I don't think generate would solve that. Largely through the use of external preprocessors (aka language extensions), all 5 of these use cases appear within AMD designs, some of them extensively. One other note: although the description doesn't state this, a followup comment makes it clear you'll need generate for module instantiations as well to take advantage of this language change. ~ Dave // David A. Gates, Ph.D. 408.749.4497 // Fellow, Design Automation // Advanced Micro Devices www.amd.com<http://www.amd.com/> // The Doctor is IN. Primum non nocere. -- This message has been scanned for viruses and dangerous content by MailScanner<http://www.mailscanner.info/>, and is believed to be clean. -- This message has been scanned for viruses and dangerous content by MailScanner<http://www.mailscanner.info/>, and is believed to be clean. -- This message has been scanned for viruses and dangerous content by MailScanner, and is believed to be clean.Received on Wed May 11 08:58:13 2011
This archive was generated by hypermail 2.1.8 : Wed May 11 2011 - 08:58:27 PDT