Portability and Maintainability

Portability and Maintainability

In a design team, it is essential to have a uniform style guideline so that code, which may range from tens of thousands to a couple million lines, is easy to maintain and reuse. In this section, let's take on a top-down approach in discussing portability and maintainability: first, projectwide file structure, then common code resources, and finally individual file format.

Project Code Layout

A large project often involves tens of thousands of RTL files. An obvious question is how to organize them for easy maintenance and reuse, and which files should contain what. The following is a list of guidelines found in practice:

  • The design RTL file structure should reflect the structure of the top-level functional blocks. For example, if the top-level blocks in the design are M1, M2, M3, and M4, then there should be subdirectories under the main RTL source directory named M1, M2, M3, and M4 that contain RTL files for the respective blocks.

  • Except for the cell library, each file should contain only one module.

  • The top-level module should consist only of module instantiations and interconnects; no logic should be present. The rationale is that the top-level module represents a partition of the design's functional blocks, and thus all low-level logic should belong to one of the functional blocks.

  • The RTL files may contain several models, each of which can be activated by using Verilog's ifdef keyword. The main reason for having more than one model embedded in the code is to enhance simulation performance. Namely, a behavioral model coexists with a structural modelthe former for fast simulation and the latter for implementation and synthesis. If more than one model coexists in the code, equivalence among the models needs to be ensured, thus creating maintenance overhead. It cannot be emphasized enough that a project team must strive to minimize the number of embedded models because maintaining multiple-model equivalence has a high cost later in the project. In addition, the other models should exist only in the cell library or macro library, not in the RTL files.

  • The design hierarchy represents a partition of the system's functionality and should correspond to the physical layout hierarchy. This rule makes equivalence checking between design and layout simpler. An example of a design hierarchy and its corresponding physical layout is shown in Figure.

    10. Correspondence between design hierarchy and physical layout

  • Hierarchical path access enables reading or writing to a signal directly over a design hierarchy without going through ports. Hierarchical path access should be permitted only in test benches. Therefore, all access inside the design must be done through ports. The reason for this is that hierarchical access sometimes is a necessity for a test bench because the signal monitored is only for testing purposes and may not be conveniently accessible through ports; whereas, within the design, all accesses are part of the design and thus it is reasonable to access only through the ports.

Centralized Resource

It is imperative to have centralized control over common resources. A project should have a minimum set of centralized common sources that include a cell library and a set of macro definitions as an include file. The macro files contain project constant definitions, memory array macro definitions, and others. All designers must instantiate gates from the project library, instead of creating their own. Similarly, memory arrays should be derived from the macro library, which expands to generate the desired structural model. No hard coding is allowed: All constants should be coded as macros. No global variables are allowed.

A cell library contains all gates and memory arrays, which may also embed other models (for example, for simulation performance). Embedding of other models is done via ifdef, where by defining IMPLEMENTATION_MODEL, the implementation version of the design is activated. If IMPLEMENTATION_MODEL is not defined, the faster behavioral model is selected. The equivalence between these two models needs to be maintained:

module adder (sum, in1, in2, carry_out);

'ifdef IMPLEMENTATION_MODEL // this is the implementation
   XOR gate1(.out(sum),.a(t1)...);
   OR gate2(.out(carry_out),.a(t2),...);
'else // for simulation performance, the following behavioral
model is used
   {carry_out, sum} = in1 + in2 ;


No initialization is allowed inside a cell. Embedding initialization inside a cell adds an artifact to the true physical property of the cell, because a real physical cell does not initialize by itself. Therefore, a cell's initialization should be done by explicit reset or external loading (for example, a PLI).

RTL Design File Format

Each RTL design file should contain only one module, and the filename should match that of the module. The beginning is a section about the designer and the design (for example, name, date of creation, a description of the module, and revision history). Next is header file inclusion. Header files should contain only macro definitions, not RTL code.

In the declaration of module ports, brief descriptions about the ports are recommended. Large blocks and complex operations should have comments about their functionality and why they are coded as such. Remember that comments are not simply English translations of Verilog code: Comments should explain the intention and operation of the code. Each begin-and-end pair should have markers to identify the pair. For example,

begin // start of search;
   begin // found it
   end // end of found it
end // end of search.

Indent to show code structure. Each project should have a naming convention (for example, uppercase letters for constants/macros), a unit name should precede a module name, and markers for buses, wires, and reg (for example, first letter capitalized for bus names). An example file is presented in the following code:

Designer: Joe Smith
Date: July 5 2003
Functionality: This module extracts the header from input stream
Revision history:
   June 11 2003: added a new counter.
   May 4 2003: fixed overflow problem.

'include "project_header.h" // include macro definitions
module InputDataEncoder (DataIn, valid, clock, ...);
input [31:0] DataIn; // this port receives the data to be

always @(posedge clock) begin // this block calculates ECC
   checksum = ....
      if (checksum == 1'b1) begin // find out the cause of the
      end // end of cause of error
end // end of always block
end module

Rules to Check

  1. There is a one-to-one correspondence between the logical hierarchy and the physical hierarchy.

  2. Except for libraries, a file should contain only one module.

  3. The name of the file should match the name of the module.

  4. The top-level module should consist only of instantiations and connections.

  5. The number of variant models embedded should be minimized.

  6. No hierarchical paths are allowed inside the design.

  7. Use library cells as much as possible, instead of writing code with the same functionality.

  8. Check for project-specific file format (for example, header, line length, name convention, and indentation).

     Python   SQL   Java   php   Perl 
     game development   web development   internet   *nix   graphics   hardware 
     telecommunications   C++ 
     Flash   Active Directory   Windows