From: Michael McNamara (mac@surefirev.com)
Date: Wed Jun 03 1998 - 18:10:30 PDT
I've incorporated some suggestions from Adam Krolnik in the structure
section.
<p><!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<title>ANSI Port Declarations, and Structures for Verilog</title>
</head>
<body>
<h1>ANSI Port Declarations, and Structures for Verilog</h1>
<p>
This proposal adds an alternate method for declaring module
ports, as well as introducing structures to the Verilog Hardware
Description Language.</p>
<p>
<hr width="10%" align=center>
<h2> Port Declaration </h2>
<hr>
<p>
At present, the Verilog language requires that the ports of a
module be listed, by name, in parenthetical list just after the
module name. Further, it is required that each port be again
declared somewhere in the module as one of an <b>input</b>,
<b>output</b> or <b>inout</b>. Optionally the port may again be
declared as a <b>wire</b> (the default) or as a <b>reg</b>.
</p>
<table border=1>
<td>
<table>
<tr>
<td>module_declaration </td><td>::= module_keyword <I>module</I>_identifier [ list_of_ports ] <B>;</B>	{ module_item } <B>endmodule</b> </td>
</tr>
<tr>
<td>module_keyword</td><td>::= <B>module</B> | <B>macromodule</b></td>
</tr>
<tr>
<td>list_of_ports</td><td>::= <B>(</B> port { <B>,</B> port } <B>)</b></td>
</tr>
<tr>
<td>port</td> <td>::= [ port_expression ]</td>
</tr>
<td></td> <td>| <B>.</B> <I>port</I>_identifier <B>(</B> [ port_expression ] <B>) </td>
<tr>
<td>port_expression</td><td>::= port_reference </td>
</tr>
<tr>
<td></td><td>| <B>{</B> port_reference { <B>,</B> port_reference } <B>}</B></td>
</tr>
<tr>
<td>port_reference</td><td>::= <I>port</I>_identifier </td>
</tr>
<tr>
<td></td><td>| <I>port</I>_identifier <B>[</B> constant_expression <B>]</B></td></tr>
<tr>
<td></td><td>| <I>port</I>_identifier <B>[</B> <I>msb</I>_constant_expression <B>:</B> <I>lsb</I>_constant_expression <B>]</td></tr>
</table>
</td>
</table>
<p>And then as a module item we have:</p>
<table border=1>
<td>
<table>
<tr>
<td>module_item</td><td>::= module_item_declaration</td>
</tr>
<tr>
<tr><td>module_item_declaration</td><td>::= parameter_declaration</td></tr>
<tr><td></td><td>| input_declaration</td></tr>
<tr><td></td><td>| output_declaration</td></tr>
<tr><td></td><td>| inout_declaration</td></tr>
<tr><td></td><td>| net_declaration</td></tr>
<tr><td></td><td>| reg_declaration</td></tr>
<tr><td></td><td><b>...</b></td></tr>
<tr><td>input_declaration </td><td>::= <B>input</B> <B>[</B> range <B>]</B> list_of_port_identifiers <B>;</b></td></tr>
<tr><td><P>output_declaration </td><td>::= <B>output</B> <B>[</B> range <B>]</B> list_of_port_identifiers <B>;</b> </td></tr>
<tr><td><P>inout_declaration </td><td>::= <B>inout</B> <B>[</B> range <B>]</B> list_of_port_identifiers <B>;</b> </td></tr>
</table>
</td>
</table>
<p> Of course this is very similar to the original C Programming
Language, (affectionately known as K&R C), which was enhanced by
simpler port declarations in ANSI C.
</p>
<p> There is much attraction to the proposer in following the ANSI
C enhancement directly, and pull the input and output declaration
directly into the parenthesized port list. However, it has been
pointed out that this causes problems with parameterized port
widths, which require a definition of the parameter before the
first use. The proposer has bowed to pressure to alter this
proposal to simplify module port declaration by following the
example of tasks and functions.</p>
<p> Therefore this proposal does the following:
<ol type="1">
<li> Enhances the input_declaration, output_declaration, and
inout declaration, by allowing in a single declaration the size,
width, type and direction of each port.
<li>This proposal further allows the list_of_ports to be
ommitted, and inferred by the order of the input_declaration,
output_declaration and inout_declaration, as they occur in the
module. This of course is familiar, as it is how port order is
defined in the <b>function</b> and <b>task</b> declarations.
<li> The list_of_ports is not removed from the language, for a
number of reasons: 1) backwards compatibility; 2) it is still
useful for including port_expressions in the module for
interface hiding.
</ol>
<p> <b>Proposal 1) R E S O L V E D :</b>
<ol type="a">
<li> The BNF for input_declaration, output_declaration and
inout_declaration shall be changed to:
<table border=1>
<td>
<table>
<tr><td>input_declaration </td><td>::= <B>input</B>[ <B>signed </B>] [ net_type ] <B>[</B> range <B>]</B> list_of_port_identifiers <B></td></tr>
<tr><td>output_declaration </td><td>::= <B>output</B>[ <B>signed </B>] [ net_type ] <B>[</B> range <B>]</B> list_of_port_identifiers <B> </td></tr>
<tr><td>output_declaration </td><td>::= <B>output</B>[ <B>signed </B>] [ reg_type ] <B>[</B> range <B>]</B> list_of_port_identifiers <B> </td></tr>
<tr><td>inout_declaration </td><td>::= <B>inout</B> [ <B>signed </B>] [ net_type ] <B>[</B> range <B>]</B> list_of_port_identifiers <B> </td></tr>
<tr>
</table>
</td>
</table>
<p> Note that a separate proposal is adding the keyword
<b>signed</b> to the language; and the optional keyword signed
is merely included here to show that should signed constructs
be introduced, it would be legal to include the declaration in
the port_reference production</p>
</li>
<li> Section <b>21.1 Modules</b> shall be changed by adding the
underlined sentence:
<p>... The optional list of ports shall specify an ordered
list of the ports in the module. <u>If a port list is not
supplied, then the ports are ordered by the order of the port
declarations in the module.</u> The order can be signifigant
when instatiating the module (See section 12.1.2). ...</p>
<li> The wording in Section <b>12.3 Port Declarations</b>, page
142 shall be to reflect this change. (Yatin to implement). In
truth there is another proposal which greatly cleans up this
section, and hence I do not try to wordsmith in this area right
now. However we need to direct that that wordsmithing handle the
new semantics we propose for optional port_lists..</li>
</ol>
<p>Given this syntax, the following two module declarations are
equivalent:<p> <table border=1><td>
<xmp>
module acc_fsm( CLK, RST, IT_IL_RQ, IT_RQ_VLD, RdMsg,
WrMsg, AccessOK, XX_IL_PIODONE, OM_IL_GT,
RespVld, IL_IT_GT, CaptureAddress, CaptureData,
IL_XX_PIORD, IL_XX_PIOWR, IL_OM_RQ,
SelectResp, SetRespVld, ClrRespVld);
input CLK, RST;
input IT_IL_RQ,
IT_RQ_VLD,
RdMsg,
WrMsg,
AccessOK,
XX_IL_PIODONE;
input OM_IL_GT,
RespVld;
output [31:0] CaptureAddress;
output [63:0] CaptureData;
output IL_IT_GT,
IL_XX_PIORD,
IL_XX_PIOWR,
IL_OM_RQ,
SelectResp,
SetRespVld,
ClrRespVld;
reg [31:0] CaptureAddress;
reg [63:0] CaptureData,
reg [2:0] LE_NxtState,
LE_State;
reg IL_IT_GT,
IL_XX_PIORD;
reg IL_XX_PIOWR,
IL_OM_RQ,
SelectResp,
SetRespVld,
ClrRespVld;
</xmp>
</td></table>
<p>and</p>
<table border=1><td>
<xmp>
module acc_fsm ;
input wire CLK, RST;
input wire IT_IL_RQ,
IT_RQ_VLD,
RdMsg,
WrMsg,
AccessOK,
XX_IL_PIODONE;
input wire OM_IL_GT,
RespVld;
output reg [31:0] CaptureAddress;
output reg [63:0] CaptureData;
output reg IL_IT_GT,
IL_XX_PIORD,
IL_XX_PIOWR,
IL_OM_RQ,
SelectResp,
SetRespVld,
ClrRespVld;
reg [2:0] LE_NxtState,
LE_State;
</xmp>
</td></table>
<p> Things to note:
<ol>
<li> The second module declaration is much more compact.(38
words instead of 70). Also note that this is a <b>small</b>
example; many datapath modules contain as many as a thousand
ports, each which may need to be declared three times.
<li> The second module declaration is much easier to reuse:
changing the width of the CaptureAddress bus to 48 bits requires
modifying one location, instead of two, which potentially are
many lines apart.
<li> The second module declaration is parametric port width
friendly; one could define a parameter before any input or
output port which used that parameter.
<li> The second module declaration is familiar; the <b>task</b>
and <b>function</b> declarations currently include no port list,
and take as the order of arguments the order that input and
output declarations appear in the declaration.
</ol>
<hr>
<hr width="10%" align=center>
<h2> Structures </h2>
<hr>
<p> Structures are very familiar to users of modern computer
languages, yet Verilog does not support them. This proposal adds
structures to the language, in manner consistent with Verilog's
concept of the directionality of a data reference.</p>
<p>Verilog does have a notion of hierarchy, and the dot (<b>.</b>)
is reserved in the language to refer to sub elements of an
object. At present there is no use of the dot to reference sub
elements of signals, and hence we propose using the dot to
references to elements of a structure.</p>
<h3> Directions </h3>
<p>In the Verilog language, signals are connected between modules
via ports. These ports can be <b>input</b>, <b>output</b> or
<b>inout</b> connections. Input ports can only be read from; the
module cannot drive a value to these ports. Output ports can be
driven, yet when read from will only show the resolved values of
the local drivers; essentially these drivers are isolated from any
external drivers of the port. Inout ports can be driven, and when
read will show the final resolved value of all the drivers of that
object, whether internal or external to the module.</p>
<p>A group of signals that quite logically might be contained in a
structure could quite conceivably have elements that are read-only
(wire), write-only (output) and/or read-write (inout) -- at
different times according to the module accessing the object. For
example, consider a bus:</p>
<xmp>
wire [31:0] address;
wire [63:0] data;
wire [15:0] req;
wire [15:0] grt;
wire buserr;
</xmp>
<p>The bus arbiter module needs just read access to the <b>req</b>
wires, and needs write access to the <b>grt</b> lines, and
read-write access to the <b>buserror</b> line, and really no access
to any other line.</p>
<p>A bus master needs write access to one of the <b>req</b> lines,
read access to the matching <b>grt</b> line, and read-write access
to the <b>address</b>, <b>data</b> and <b>buserror</b> lines. </p>
<p>A bus slave might need just read-write access to the
<b>address</b>, <b>data</b> and <b>buserror</b> lines.
<p>A bus monitor would need read access to all the bus lines.</p>
<p>Therefore including direction in a structure declaration would
be less than useful.</p>
<h3>Proposal</h3>
<p> The following syntax is proposed:
<table border=1>
<td>
<table>
<td>structure_declaration</td><td>::= <b>struct</b> <b>[</b> range <b>]</b> <i>struct</i>_identifier struct_items <b>endstruct</b></td></tr>
<tr><td>struct_items</td><td>::= struct_item { struct_item }
<tr><td>struct_item</td><td>::= net_declaration <b>;</b></td></tr>
<tr><td></td><td><b>|</b> reg_declaration<b>;</b></td></tr>
<tr><td></td><td><b>|</b> parameter_declaration<b>;</b></td></tr>
</table>
</td>
</table>
<p>
The structure definition is global, at the same scope as the module
declaration. If two structures are declared with the same
struct_identifier, then they must match exactly; otherwise the system
shall signal an error.</p>
<p>If there is a range specified, the structure is limited to the size
of that range [and an error shall be generated if the number of bits
required to implement the structure is not equal to the size of the
range.] Bit and part selects of the structure would have to fall
within the range. If there is no range specified, the size of the
structure is the sum of the sizes of the individual elements.</p>
<p>Structures are used in net and reg declarations as an alternate for
the <b>range</b> production, as follows:
<table border=1>
<td>
<table>
<tr><td>reg_declaration</td><td> ::= <B>reg</B> <B>[</B> range <B>]</B> list_of_register_identifiers <B>;</td></tr>
<tr><td>list_of_real_identifiers</td><td> ::= <I>real</I>_identifier { <B>,</B> <I>real</I>_identifier }</td></tr>
<tr><td>list_of_register_identifiers</td><td> ::= register_name { <B>,</B> register_name }</td></tr>
<tr><td>register_name</td><td> ::= <I>register</I>_identifier</td></tr>
<tr><td></td><td>| <I>memory</I>_identifier <B>[ </B><I>upper_limit</I>_constant_expression <B>:</B> <I>lower_limit</I>_constant_expression <B>]</b></td></tr>
<tr><td>time_declaration</td><td> ::= <B>time</B> list_of_register_identifiers <B>;</td></tr>
<tr><td>integer_declaration</td><td> ::= <B>integer</B> list_of_register_identifiers <B>;</td></tr>
<tr><td>real_declaration</td><td> ::= <B>real</B> list_of_real_identifiers <B>;</td></tr>
<tr><td>realtime_declaration</td><td> ::= <B>realtime</B> list_of_real_identifiers <B>;</td></tr>
<tr><td>event_declaration</td><td> ::= <B>event</B> <I>event</I>_identifier { <B>,</B> <I>event</I>_identifier } <B>;</td></tr>
<tr><td>net_declaration</td><td> ::=net_type [ <B>vectored</B> | <B>scalared</B> ] [ <B>signed </B>| <B>unsigned </B>] [ range ] [ delay3 ] list_of_net_identifiers <B>;</td></tr>
<tr><td></td><td>| <B>trireg</B> [ <B>vectored</B> | <B>scalared</B> ] [ <B>signed </B>| <B>unsigned </B>] [ charge_strength ] [ range ] [ delay3 ] list_of_net_identifiers <B>;</B></td></tr>
<tr><td></td><td>| net_type [ <B>vectored</B> | <B>scalared</B> ] [ <B>signed </B>| <B>unsigned </B>] [ drive_strength ] [ range ] [ delay3 ] list_of_net_decl_assignments</td></tr>
<tr><td>net_type</td><td> ::= <B>wire</B> | <B>tri</B> | <B>tri1</B> | <B>supply0</B> | <B>wand</B> | <B>triand</B> | <B>tri0</B> | <B>supply1</B> | <B>wor</B> | <B>trior</td></tr>
<tr><td>drive_strength</td><td> ::= <B>(</B> strength0 <B>,</B> strength1 <B>)</td></tr>
<tr><td><td><td>| <B>(</B> strength1 <B>,</B> strength0 <B>)</td></tr>
<tr><td><td><td>| <B>(</B> strength0 <B>,</B> <B>highz1</B> <B>)</td></tr>
<tr><td><td><td>| <B>(</B> strength1 <B>,</B> <B>highz0</B> <B>)</td></tr>
<tr><td><td><td>| <B>(</B> <B>highz0</B> <B>,</B> strength1 <B>)</td></tr>
<tr><td><td><td>| <B>(</B> <B>highz1,</B> strength0 <B>)</td></tr>
<tr><td>strength0</td><td> ::= <B>supply0</B> | <B>strong0</B> | <B>pull0</B> | <B>weak0</td></tr>
<tr><td>strength1</td><td> ::= <B>supply1</B> | <B>strong1</B> | <B>pull1</B> | <B>weak1</td></tr>
<tr><td>charge_strength</td><td> ::= <B>( small )</B> | <B>( medium )</B> | <B>( large )</td></tr>
<tr><td>delay3</td><td> ::= <B>#</B> delay_value | <B>#</B> <B>(</B>delay_value [ <B>,</B> delay_value [ <B>,</B> delay_value ] ] <B>)</td></tr>
<tr><td>delay2</td><td> ::= <B>#</B> delay_value | <B>#</B> <B>(</B>delay_value [ <B>,</B> delay_value ] <B>)</td></tr>
<tr><td>delay_value</td><td> ::= unsigned_number | <I>parameter</I>_identifier | constant_mintypmax_expression</td></tr>
<tr><td>list_of_net_identifiers</td><td> ::= <I>net</I>_identifier { <B>,</B> <I>net</I>_identifier }</td></tr>
<tr><td>list_of_net_decl_assignments</td><td> ::= net_decl_assignment { <B>,</B> net_decl_assignment }</td></tr>
<tr><td>net_decl_assignment</td><td> ::= <I>net</I>_identifier = expression</td></tr>
<tr><td>range</td><td> ::= <B>[ </B><I>msb</I>_constant_expression <B>:</B> <I>lsb</I>_constant_expression <B>]</td></tr>
<tr><td></td><td bgcolor=red>| <i>struct</i>_identifier</td></tr>
<tr><td><i>net</i>_identifier</td><td> ::= identifier</td></tr>
<tr><td></td><td bgcolor=red>| { <i>struct</i>_identifier<b>.</b>} identifier</td></tr>
<tr><td><i>reg</i>_identifier</td><td> ::= identifier</td></tr>
<tr><td></td><td bgcolor=red>| { <i>struct</i>_identifier<b>.</b>} identifier</td></tr>
</table>
</td>
</table>
<p>
Given the above additions to the BNF, one could code the bus devices as follows:
<xmp>
struct Pbus
parameter NDEV = 4;
wire [31:0] address;
wire [63:0] data;
wire [1<<NDEV:0] req;
wire [1<<NDEV:0] grt;
wire buserr;
endstruct // Pbus
module top;
wire Pbus thePbus;
wire clk;
pbus_monitor p_mon( .Pbus(thePbus),.clk(clk));
pbus_arb p_arb( .Pbus(thePbus), .clk(clk));
pbus_cpu p_cpu0( .Pbus(thePbus), .clk(clk) .id(4'd0));
pbus_cpu p_cpu1( .Pbus(thePbus), .clk(clk) .id(4'd1));
pbus_mem p_mem0( .Pbus(thePbus), .clk(clk) .id(4'd2));
pbus_mem p_mem1( .Pbus(thePbus), .clk(clk) .id(4'd3));
pbus_mem p_mem2( .Pbus(thePbus), .clk(clk) .id(4'd4));
pbus_mem p_mem3( .Pbus(thePbus), .clk(clk) .id(4'd5));
endmodule
module pbus_monitor( input Pbus my_Pbus );
always @(my_Pbus.buserr) begin
$display($time,,"BUSERR!!");
end
...
endmodule // pbus_monitor
module pbus_arb;
input Pbus.req;
output reg Pbus.grt;
inout Pbus.buserr;
input clk;
always @(clk) begin
case(Pbus.req)
0,1,2,4,8,16,32,64 : Pbus.grt = Pbus.req;
default: // left as exercise...
endcase // case(Pbus.req)
end
endmodule
module pbus_cpu;
output reg Pbus.req;
input Pbus.grt;
inout Pbus.buserr;
inout Pbus.data;
inout Pbus.address; // for cache invalidate logic
input [Pbus.NDEV:0] id;
input clk;
always @(clk) begin
case (state)
WANT_TO_WRITE: begin
Pbus.req[id] = 1;
state <= WAIT_FOR_WRITE_GRANT;
end // case: WANT_TO_WRITE
WANT_TO_READ: begin
Pbus.req[id] = 1;
state <= WAIT_FOR_READ_GRANT;
end // case: WANT_TO_READ
...
endcase // case(state)
end // always @ (clk)
endmodule // pbus_cpu
</xmp>
<address><a href="mailto:mac@silicon-sorcery.com">Michael McNamara</a></address>
<!-- Created: Wed Apr 1 15:28:56 PST 1998 -->
<!-- hhmts start -->
Last modified: Wed Jun 3 18:08:53 PDT 1998
<!-- hhmts end -->
</body>
</html>
This archive was generated by hypermail 2.1.4
: Mon Jul 08 2002 - 12:52:54 PDT
and
sponsored by Boyd Technology, Inc.