This discussion of the reg / logic duality prompts me to reopen a
correspondence resulting from some experience using System Verilog.
The enhancement that a variable (reg / logic) may be continuously
assigned or driven by a module output or assigned by one always_ff
process is very useful for design implementation. However there are
still many scenarios where multiple drivers or bi-directionality is
desired, at which point wires must be used.
The use of wires has currently a major disadvantage, the inability to
conveniently pass structure 'shape' through wires. A further
disadvantage is that wires cannot usefully be used as arguments to
overloaded operators if there is no deeper meaning within them.
I admit now that the following is an improvement on my original
proposition, enhanced by the other participants of the discussion. They
may disclose themselves, whether they are still in alignment with this
enhancement.
As I believe this enhancement does not alter the existing meaning of
System Verilog, I propose that the extension should be considered.
However it implies some effort and discussion within the relevant
workgroups regarding its schedule in the standardisation process.
Regards
Jonathan Bradford
Complex Data Types of Wires
Motivation
This is a request based on usage of System Verilog for an extension to
System Verilog for accessing wires with complex data structures implied
by their driving registers or data destinations. The examples have been
modified to the proposed syntax in the summary.
In System Verilog the interface can have signals declared as wires or
variables.
The wires can be declared as vectors or vectors of vectors or arrays of
vectors, reflecting whether they are packed or unpacked data types. The
wire can also be of various resolved types, such as tri1 (pullup) or
trireg (holding) etc. The wire can also be in signed or unsigned
(default) arithmetic.
The variables can also be declared as vectors and vectors of vectors and
arrays of vectors. They can also be defined as many other data types, as
packed types for implementation such as structures etc, or unpacked for
verification such as dynamic arrays etc. Again these may have attributes
for signed or unsigned arithmetic and packed or unpacked data storage.
But there is no resolution capability. i.e. they may be written to
discretely by assignments in procedural code or a single structural
assignment (continuous or connectivity).
When implementing an RTL design it is safe to model states in the design
using variables in the interfaces, so long as there is a single
direction of signal flow and no multiple drivers.
There are a number of constructs in System Verilog language to ensure
this, such as interface modports with output statements for the variable
to be written and the use of always_ff to constrict the assignments to
these interface variables. These constructs restrict structural and
procedural assignment to the state variables and implicate registered
outputs in the single driving blocks.
This allows the use of variables with complex data definitions such as
structs etc in RTL implementation.
However there are scenarios in RTL implementation where it is necessary
to allow bidirectionality or at least multiple drivers (and enables)
onto a common bus.
This implies that only wires can be used for these interface signals.
The driving variables are then explicitly assigned to, from the modules
interfaced to the bus.
But wires cannot be defined with such complex data structures as
variables. Hence once a value is on the wires in the bus in the
interface, it is not possible to use those signal values as easily as in
the original variables. This is especially the case for structs.
There are two main problems
o wires containing values driven by variables of complex type must be
correctly sized, throughout the interface hierarchy.
o components of values on wires implied by the 'shape' of the driving
variable need to be made accessible wrt those `shapes' rather than
the explicit 'shape' of the wire.
i.e.
// a register driving the bus might be :-
typedef struct packed { logic ecc; logic [7:0] data; } MemLoc;
MemLoc mem_r;
// whereas the signal in the interface - driven by multiple modules
(enabled) :-
wire [8:0] memsig;
modport driver (inout [8:0] memsig);
// a user of the interface signal needs to know where ecc and data
are !
my_ecc = memsig[8];
my_data = memsig[7:0];
If the definition of the structure were changed, the design hierarchy
must be worked through to change all these structural references to the
wires that transport signal values.
One way to do this particular example is to use casting:
my_ecc = MemLoc'(memsig).ecc
my_data = MemLoc'(memsig).data
However a cast cannot be an lvalue or an output port, so a more general
facility is needed. A language extension to allow a packed data type to
be associated with a wire vector can provide this generality and reduce
the typing:
The structure must be packed. The structure can be either 4-state or
2-state, but 4-state is recommended to maintain compatibility between
variables and wires of the same type. There is one wire for each bit or
logic, and the wire can have the normal range of strength values. The
wire can be of type tri1, tri0, trireg, supply0, supply1 etc.
Example
// wire and interface definition
wire <MemLoc> memsig;
modport driver (inout <MemLoc> memsig);
// this is similar to
// wire [$bits(MemLoc)-1:0] memsig;
// wire element of `shape` access
my_ecc = memsig.ecc;
my_data = memsig.data;
assign memsig = mem_r;
assign memsig.ecc = ^mem_r.data;
Hence if the structure MemLoc changes, the slice access routines for the
wire signals remain unchanged.
In reality there is nothing changed in the behaviour of variables and
wires, only in how their content is perceived.
This perception of the shape is also independent of the driver, as there
can be multiple drivers of the aggregate wire. The same wire may
therefore be perceived in multiple ways :-
typedef struct packed {logic [1:0] ignore, logic [6:0] ascii}
CharLoc;
my_data [7:0] = memsig.data;
my_data [7:0] = CharLoc'(memsig).ascii;
// msb becomes 0
typedef union packed {MemLoc ML; CharLoc CL;} AnyLoc;
AnyLoc anysig;
my_data [7:0] = {anysig.ML.ecc, anysig.CL.ascii};
Furthermore if the structure definition contains attributes such as
signed for the arithmetic of its members, this is maintained for a
member access, but not for the corresponding slice.
typedef struct packed { logic signed [7:0] a; logic [7:0] b; } Slog;
wire <Slog> slog_sig;
if (slog_sig.a >>1 == slog_sig[15:8] >>1)
$display ("Not all the time, No");
The problem with respect to overloaded operators can be exemplified by
considering a user defined structure to represent a fixed point number
with fields for mantissa and exponent. Currently when a wire is used as
an argument to such an operator, there is no way to infer that the value
within the wire should be the mantissa and exponent as opposed to the
integral integer value of a wire. However this is resolved when a wire
has a structure definition.
Summary
A proposal for a collection of wires to be treated as a structure, as
explained above.
This proposal is to allow a type identifier to be used instead of
signing and packed dimensions in net declarations.
net declaration ::= net_type_or_trireg
[ drive_strength | charge_strength ]
[ vectored | scalared ]
[ signing ] { packed_dimension } [ delay3 ]
list_of_net_decl_assignments
| net_type_or_trireg
[ drive_strength | charge_strength ]
[ vectored | scalared ]
< type_identifier > [ delay3 ]
list_of_net_decl_assignments ;
The type_identifier should be limited to packed types.
The < > characters are used to remove ambiguity.
-- ________________________________________________________________________________ /\ Jonathan Bradford mailto:bradford@micronas.com \/ /\/\ MICRONAS GmbH http://www.micronas.com /\/\/\ \/\/\/ Hans-Bunte-Str.19 Tel: +49 (0)761 517 2884 \/\/ D-79108 Freiburg Fax: +49 (0)761 517 2880 \/ GermanyReceived on Thu Jul 29 03:32:50 2004
This archive was generated by hypermail 2.1.8 : Thu Jul 29 2004 - 03:33:24 PDT