Another delat on the structures proposal

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>&#9;{ 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.