07-08-00 TT CV2.100 User Manual


This manual describes the TT CV2.100 Simple Verilog Compiler. This is a tool which will compile a circuit description in the Verilog language into a gate-level, hierarchic, netlist. This netlist may then be fed into other tools for simulation or layout and fabrication.

This manual also provides useful documentation for the VTOC tool, since many of the command line flags are the same and are explained in greater depth here.

CV2.100 is only a basic RTL compiler and the current release does not contain high-quality logic minimisation. In the future, TT CV2.200 is intended to be a behavioural compiler, based on the same core algorithm as TT CTOV.

CV2.100 has support for automatic generation of ROM, RAM, adder and multiplier instances taken from standard library blocks.

CV2.100 compiles general RTL into a set of standard gates and flip-flops whose definitions are found in the file cv100gates.cv. Specific modules found only in certain technology libraries, such as IO pads, need to be manually instantiated.

This software and manual are provided for use at your own risk. We accept no responsibility for any copyright or patent infringement or any other direct or consequential loss which may arise from using this software.


The figure shows that the CV2.100 program accepts a number (not necessarily four) of source files and produces a single object file, as well as console messages in the case of any warnings or errors.

All of the source files are in the Verilog language and normally have suffix `.cv'. One of the files contains a root module and the other files contain modules needed to synthesise the root module. These other files may be in the current directory or in libraries.

The output file is a net list in Verilog (suffix `.vnl') or an ML parse tree.

The tool should typically be used alongside a Verilog simulator which can simulate either the input or the output from CV2. Suitable simulators are CSIM (available within the University of Cambridge only) and Cadence Verilog-XL.

CV2.100 Verilog Language Subset and Syntax

The CV2.100-V2 compiler accepts a subset of the full Verilog language for compilation into a gate-level netlist. This section describes that subset. The subset is the main structural and RTL (register transfer level) set of the language, but excludes Verilog's built-in transistors and gates, and signal strengths.

CV2.100 is a basic RTL compiler and will not handle the following behavioural constructs: while , for , fork-join and more than one event control statement in the body of an always statement.

The full Verilog language is described in the OVI (Open Verilog International) `Language Reference Manual' available for ftp from various places, including `ftp.chronologic.com/pub/ovi'. This section describes the language subset supported by the CV2.100 synthesiser. Other useful reference books include

  • `The Verilog Hardware Description Language' by Donald E. Thomas and Philip Moorby. Published by Kluwer Academic Publishers. ISBN 0--7923-9126-8.
  • `Digital Design and Synthesis with Verilog HDL' by Eli Sternheim, Rajvir Singh, Rajeev Madhaven and Yatin Trivedi. Published by Automata. ISBN 0-9627488-2-X. This book comes with a demonstration disk of a Verilog simulator.

Verilog is quite a rich language and supports four main levels of hardware specification of increasing abstraction using the various language constructs available. These levels can be freely mixed in one circuit. A taxonomy of four levels is handy for the current purposes, as follows:

  • Structural Verilog: a hierarchic netlist form.
  • Continuous Assignment: allows advanced combinatorial expressions, including adders and bus comparison, etc.

  • RTL Behavioural Subset: allows clocked assignment, if-then-else and case statements, resulting in state machine synthesis.

  • The Behavioural Remainder: includes programming constructs such as unbounded while loops fork-join , disable and free placement of event control.

The CV2.100 compiler (cv2) supports levels 1 through 3 an CV2.100 supports level 4 as well.


Verilog Lexicography

A Verilog source file contains modules, comments and macro definitions. All whitespace characters (outside of macro definition lines) are optional and ignored, except where adjacent identifiers would elide.

Comments

One line comments are introduced with the revered double slash syntax and terminate at the end of line. Block comments are introduced with slash-star and terminate with star-slash. Block comments may not be nested.

   /*
    * This is a block comment.
    */

   // And this is a single line comment.

Identifiers

Identifier names consist of alphanumeric strings which can also contain underscores and must start with a letter. Case is significant. In this manual, uppercase identifiers are used by convention for module names, but this is not required by the language definition or CV2.100.

CV2.100 maintains separate identifier spaces for modules, nets, macros and instances, allowing the same identifier to be used in more than one context. The net identifier space also includes other classes of identifier that could be used in expressions, such as parameters and integers.

Many postprocessing tools do not maintain such separate namespaces, so it is possible to have clashes within these tools that were not a problem for CV2.100.

Module, Port and Net Definitions

A module is the top-level syntactic item in a Verilog source file. Each module starts with the word module and ends with endmodule and between the two are `module declarative items'.

   // Here is a module definition, called FRED
   module FRED(q, a, b);

      input a, b;    // These are the inputs
      output q;      // Make sure your comments are helpful

      // ..... Guts of module go here .....

     endmodule

After the module name comes a list of formal parameters in parenthesis. These are also known as the `ports'. In the module body, semicolons are used to terminate atomic statements, but not composite statements. Hence there is never one after an endmodule (or an end or an endcase ).

Valid module declarative items include the following statements parameter , input , output , inout , wire , reg , tri , pullup , pulldown , integer , event , time , assign , initial , always and gate and module structural instantiations.

Initialisation with initial initial statements are ignored unless they start `initial while(1) ...' or `initial forever ...' in which case they are treated as always statements.

Event definitions and activations are ignored.

The order of the declarative items is unimportant semantically, except that nets need to be declared before they are referenced.

Input and Output definitions

Each of the ports of a module must be explained using the keywords

  • input : signal coming into the module
  • output : signal going out of the module
  • inout : bidirectional signal.

These declarations take a comma separated list of ports which share a similar direction. When a modules are instantiated, CV2.100 checks that no two outputs are connected to each other and that all nets of type wire are are driven by exactly one output.

Pullups and Pulldowns

A net may be defined to float to logic zero or one by the inclusion of a pulldown or pullup, respectively. These statements should be used for inputs which are liable to be disconnected or to tristate bus lines.

   wire a;
   tri b;
   pullup (a);
   pulldown (b);
For synthesis, CV2.100 turns these Verilog language components into straightforward structural instances of a PULLUP or PULLDOWN. However, ignore the above, since with CV2, it is better to instantiate components called PULLUP and PULLDOWN instead of using the builtin pullup and pulldown declarators.

Bus definitions

A Verilog signal may either be a simple net or else a bus. When an identifier is introduced (using a declaration such as input or tri etc.), if it is given a range, then it is a bus, otherwise it is a simple net. When an identifier which denotes a bus is referred to without giving an index range, then the full range of the bus is implied. Most Verilog operators will operate on both busses and simple nets.

Busses are defined by putting a range in square brackets after the keyword which declares then. For example

     // Here is a module definition with two input busses
     module FRED(q, d, e);

      input [4:0] d, e;    // Ports d and e are each five bit busses
      output q;            // q is still one bit wide
 
     endmodule

Note that when a module port is actually a bus, the bus range specification is not given in the formal parameter list, just its identifier. However, some dialects of Verilog allow the range specifications in the formals.

In Verilog, width specifications may be from high to low or low to high. With CV2.100 however, the most significant bit (highest index) must be specified first and the least significant bit index second. Users who define their busses the other way around will later find that certain built-in operators (such as addition) may not work as expected. The least significant index does not have to be zero, which is helpful sometimes. Before logical operations on busses, such as addition or comparison, the numeric values of the bus indecies are normalised by effectively subtracting the least significant index from all bus wires.

Local signal names

Local signal names are introduced with the wire , reg and tri statements. There are slight variations in the way these types of nets can be used, as explained elsewhere in this manual, but the syntax of the three statements is the same. Here is an example using some wires:

   // Here are some local nets being defined
   module FRED(q, a);

input a; output q;

wire [2:0] xbus, ybus; // Two local busses of three bits each wire parity_x, parity_y; // Two simple local signals. endmodule

Verilog allows the words vectored and scalared to be put before range definitions, but they are ignored by the synthesiser.


Structural Specification

One further statement type, beyond the wire and port declarations, is all we need for structural specification of a hierarchic or flat netlist. This is the component instance statment. The syntax of a submodule or component instance is:

   ()  [ , () ] ;
where the square brackets are meta-syntax to indicate optional repetition and the angle brackets indicate that an identifier is not a keyword. The syntax allows several instances of the same submodule to be specified in one instance statement, if desired.
   // Here is a module definition with submodule instances.
   module FRED(q, a, b);

input a, b; // These are the inputs output q; // Make sure your comments are helpful wire qbar; // Local, unported net

NOR2 mygate(q, a, qbar), myothergate(qbar, b, q);

endmodule

The submodule NOR2 must be defined somewhere, as a leaf module in a technology library, or in the same or another design-specific Verilog source file.

Instance names, such as `mygate' in the example, are optional. CV2.100 will make up instance names for instances in its output netlists if they are not provided in the source Verilog. However, this is not recommended since these names are likely to change each time a circuit is compiled and this is often inconvenient if a simulator or placement tool has retained instance name state from one run to another.

Note that explicit instantiation of this type at the low level of individual gates is not normally done by a human, unless this is an especially critical section of logic. Such gate-level Verilog is normally synthesised from the higher levels of Verilog source by CV2.100 or other tools.

Positional and Named port mapping

The component instance example above, for NOR2, uses positional port mapping. The writer of the Verilog had to know that in the definition of NOR2, the output net was put first. That is

   // Here is the signature of NOR2
   module NOR2(y, x1, x2);

      input x1, x2;    // These are the inputs
      output y;        // Make sure your comments are always helpful

    endmodule

However, Verilog also allows named port mapping in the instance statement. Using named port mapping, the writer does not have to remember the order of the ports in the module definition, he must remember their names instead. The chance of misconnection though giving the wrong order is eliminated and the compiler is able to generate more helpful error messages when the wrong number of arguments is supplied to an instance.

   // Here is a module definition with named port mapping.
   module FRED(q, a, b);

      input a, b;    // These are the inputs
      output q;      // Make sure your comments are helpful
      wire qbar;     // Local, unported net

      NOR2 mygate(.x1(a), .y(q), .x2(qbar)),
           myothergate(.y(qbar), .x2(q), .x1(b));

      endmodule

As can be seen, the syntax of a named port association is
    .  (  )
whereas for the positional syntax, we just have a list of signal expressions.

I use the term `signal expression' since the actual parameters, for both syntaxes, do not have to be simply signal names, but for inputs to the submodule, can be any expression which results in a signal of the correct width. Signal expressions are explained shortly.

It is often necessary to pass a single net of a bus, or a subgroup of a bus to or from a module instance. This can be done using the bus subranging operator denoted by square brackets.

Continuous Assignment and Signal Expressions

The level of Verilog specification which comes above netlists and structural instantiation is continuous assignment. The syntax of a continuous assignment within CV2.100 is

   assign  =  ;
For example
   wire p;
   assign p = (q & r) | (~r & ~s);
The stile denotes Boolean OR, the ampersand denotes Boolean AND and the tilde denotes inversion. The signals q, r and s must be defined already using one of the declarations input, output, inout, wire, tri or reg.

A continuous assignment is synthesised into a set of gates which achieve the desired logic function. Logic minimisation is applied to the signal expression on the right-hand side, but CV2.100 does not eliminate explicitly declared nets or their interconnection pattern across continuous assignments.

In Verilog, the `hash' form of event control may be used as part of an assignment statement to introduce a delay. For example

   assign #10 p = q;
CV2.100 ignores delay specifications when they are present in assignment statements, but flags a warning at the end of compilation if the delays were in non-primitive modules.

Verilog allows a shorthand that combines a wire declaration with an assignment. The above example can be written more concisely

   wire p = (q & r) | (~r & ~s);
where the assignment to p is combined into the wire statement that introduced it. Multiple wires can be defined and initialised at once if they all have the same range. For example
   wire p = ~q, r = ~s;
   wire [3:0] bill = 15-ben, foo = 15-bar;

Constant numeric expressions

Numerical constants can be introduced in a number of bases using the syntax:

         '  
where the base is a single letter:
b binary
o octal
h hexadecimal
d decimal (the default)

For example

     wire [7:0] bus1, clipbus;
     assign clipbus = (bus1 > 8'd127) ? 8'd127 : bus1;
where 8'd127 is the decimal number 127 expressed to a width of eight bits.

If constants are given without a width, CV2.100 will attempt to provide an appropriate width to use. If the situation is ambiguous, an error is flagged. CV2.100 will also accept simple strings of digits and treat them as unsized decimal numbers.

Underscores are allowed in numbers. These are ignored by the compiler but can make the language more readable. For instance

      wire [23:0] mybus = yourbus & 24'b11110000_11110000_00001111;

Bus subranging and concatenation

To have access to parts of a bus, indexing can be used with a bit field in square brackets. When the index is left out, which is the case in the examples until now, the default width of the bus is used.

examples

        wire [31:0] dbus;
        wire bit7 = dbus[7];
        wire [7:0] lowsevenbits = dbus[7:0];
        wire [31:0] swapbus = dbus[0:31];
It is possible to assign to part of a bus using a set of assignment statements provided that each net of the bus is assigned to exactly once (i.e.\ the ranges are disjoint). For example
       wire [11:0] boo;
       input [3:0] src;
       assign boo[11:8] = src;
       assign boo[7:4] = 4'b0;
       assign boo[3:0] = src + 4'd1;

It is also possible to form anonymous busses using a concatenation of signals. Concatenations are introduced with curly braces and have width equal to the sum of their components. Hence, the previous example can be rewritten more briefly

      assign boo = { src, 4'b0, src + 4'd1 };

Note that all items within a concatenation must have a clearly specified width. In particular, unsized numbers may not be used.

Items in a concatenation may be prefixed with a repeat count if desired. The following two example lines are therefore identical in meaning.

    { bill, bill, ben, ben, ben, weed }
    { 2 { bill }, 3 { ben }, weed }

Note that CV2.100 does not support assignment to concatenations, although many Verilog dialects do. Instead, multiple separate assignments are needed.

Verilog Operators

The table defines the set of combinatorial operators available for use in signal expressions in order of binding power. Parenthesis can be used to overcome binding power in the normal sort of way.

All operators can be applied to simple nets or to busses. When a diadic operator (i.e., one that takes two arguments) is applied where one argument is a simple net and the other a bus, CV2.100 treats the simple net as the least significant bit of a bus with all other bits zero. This is also the case when busses of unequal size are combined.

CV2.100 has no support for two's complement or sign extension built in it treats all numbers as unsigned. When signed operation is needed, the user must create such behaviour around the built-in operators. (Of course, addition and subtraction work both with unsigned and two's complement numbers anyway). Although Verilog defines integers to be signed, they are unsigned with CV2.100. TODO fix.

There are both Boolean and logical versions of the AND and OR operators. These have different effects when applied to busses and also different precedence binding power. The Boolean operators `&' and or `|' produce bitwise ANDs and ORs of their two arguments. The logical operators `&&' and `||' first or-reduce their arguments and then combine them in a unit width AND or OR gate.

Symbol Function Resultant width
~ monadic negate as input width
- monadic complement as input width
! monadic logic not unit
* unsigned binary multiply sum of arg widths minus one (?)
/ unsigned binary division ?
% unsigned binary modulus width of rhs arg
+ unsigned binary addition maximum of input widths
- unsigned binary subtraction maximum of input widths
>> right shift operator as left argument
<< left shift operator as left argument
== net/bus comparison unit
!= inverted net/bus compare operator unit
< bus compare operator unit
> bus compare operator unit
>= bus compare operator unit
<= bus compare operator unit
& diadic bitwise and maximum of both inputs
^ diadic bitwise xor maximum of both inputs
~^ diadic bitwise xnor (*) maximum of both inputs
| diadic bitwise or maximum of both inputs
&& diadic logical and unit
|| diadic logical or unit
? : conditional expression maximum of data inputs

Unary Reduction

It is possible to reduce a bus to a wire under an operator: that is, to combine all of the wires of a bus using an associative Boolean diadic operator. This is called in Verilog `unary reduction' (in contrast to the mathematical use of a unary operator as a function that takes only one argument). The syntax of unary reduction required by CV2.100 insists on two sets of parenthesis.

     (  (  ))   
the unary-operator must be one of the ones in next table. For example
    wire [9:0] mybus;
    wire ex = (& (mybus));
constructs a ten-input AND gate such that ex will be a logical one if the bus contains all ones.
Symbol Function
& AND
| OR
^ XOR
~& NAND
~| NOR
~^ XNOR

Logical Not and Bitwise Not

The logical not operator is `!' and has a different meaning from the bitwise not operator `~' when applied to a bus. The logical not operator will or-reduce the wires of the bus and then negate the result, giving a unit width output. The bitwise not operator simply gives a bus the same width as its input but with each wire negated.

Carry and borrow in addition and subtraction.

In order to access the carry (borrow) bit which results when two busses of identical size are added (subtracted), it is necessary for the lhs expression to be one larger than the right hand side expression.

   wire [3:0] x0, x1;
   wire [4:0] sum_with_carry = x0 +  x1;

On the other hand, the following will not give access to the carry, and instead bit 4 of `sum_without_carry' will be always zeros and a width mismatch warning message will be given, since inside concatenations it is necessary to be strict about widths:

   wire [3:0] x0, x1;
   wire [4:0] sum_without_carry = { x0 + x1 };

Conditional Expressions

The conditional expression operator allows multiplexers to be made. It has the syntax

   () ?  : 
The value of the expression is the false-expression when the switch-expression is zero and the true-expression otherwise. If the switch-expression is a bus, then it is unary-reduced under the OR operator. CV2.100 does not insist on the parenthesis around the switch-expression, but they are recommended. The association of the conditional expression operator is defined to enable multiple cases to be tested without multiple parenthesis. Examples
    wire [7:0] p, q, r;
    wire s0, s1;

    wire [7:0] bus1 = (s0) ? p : q;
    wire [7:0] bus2 = (s0) ? p : (s1) ? q : r;

The bus comparison predicates (==, !=, <, >, <=, and >=) take a pair of busses and return a unity width result signal. For example

    wire yes = p > r;

The meta comparison operators (=== and !==) are the same as (== and !=) for synthesis.

Dynamic Subscription

CV2.100 supports dynamic subscription (indexing) of a bus in a signal expression provided that the selected width from the bus is one bit wide. Dynamic subscription is not supported on the left hand side of any assignment. Here is an example of use

  module TEST();
    wire [10:0] bus;
    wire [3:0] idx;
    ...
    wire bit = bus[idx];
    ... 
  endmodule


Behavioural Specification

Verilog HDL contains a full set of behavioural programming constructs, allowing one to write procedural style programs, with ordered assignments (as opposed to continuous assignments). The CV2.100-V2 Verilog compiler supports a subset of the language's behavioural constructs for logic synthesis. These are described in this section.

Behavioural statements must be included within an initial declaration or an always declaration. Initialisation with initial initial statements are ignored unless they start `initial while(1) ...' or `initial forever ...' in which case they are treated as always statements. CV2.100 ignores the contents of other initial statements which might simply assign to a variable: these may be present and are useful when simulating the source file with a Verilog simulator (e.g. Verilog-XL or CSIM).

CV2.100 supports only the following main form of the Verilog always construct. It has the syntax

   always @(  ) 
This statement causes execution of the behavioural statement each time an event in the sensitivity list occurs. The sensitivity list is described in a later section because we will first present the behavioural statements that are supported.

CV2.100 will synthesise the following behavioural statements into hardware: begin-end , if-then-else , case repeat , forever , task invocation and both the blocking and non-blocking behavioural assignment. TODO for and while loop.

begin-end Behavioural Statement

This statement is simply the sequencing construct required to extend the range of behavioural statements which include behavioural statements (such as if and always ) to cover multiple behavioural statements. The syntax is

   begin   [ ;  ] end
where multiple instances of the contents of the square brackets may be present. The order of statements inside a begin-end block is important when multiple blocking assignments are made to the same variable. Multiple non-blocking assignments to the same variable are not allowed unless they are in different branches of an if-then-else .

The repeat Behavioural Statement

The repeat statement is supported by CV2.100 provided it has a compile-time constant argument and is simply textually expanded into that many copies of its argument statement (which of course can be a block). The syntax is

   repeat () 

The if-then-else Behavioural Statement

The if statement enables selective execution of behavioural statements. The target behavioural statement (which can be any type of behavioural statement, including further if statements) is executed if the signal expression is non-zero.

    if (  )  [ else   ]
If the signal expression given for the condition is a bus it is or-reduced so that the target behavioural statement is executed if any of the wires in the bus are non-zero. When the optional else clause is present, the else clause is executed if the signal-expression condition is false.

The case Behavioural Statement

The case statement enables one of a number of behavioural statements to be executed depending on the value of an expression. The syntax of the statement is

    case (  )  endcase
where the case-items are a list of items of the form
     [ ,  ] : 
and the list may include one default item of the form
    default : 
The semantic is that the top signal expression is compared against each of the tag signal expressions and the behavioural statement of the first matching tag is executed. If no tags match, the statement provided as the default is executed, if present.

If the `parallel_case' flag is present in a comment immediately after the right hand parenthesis of the case top signal expression, then the semantic of the case statement is changed and all matching expressions are evaluated. This normally produces fewer gates than the sequential case semantic and is often helpful for one-hot state machines where the designer knows that only one state will actually match.

It may be observed that there are a number of variations from the case statements found in other languages, such as C. These are: the tag values do not have to be constants, but can be any signal expression; for each group of tag expressions there must be exactly one target statement (`begin-end' must be used to overcome this) and there is no `fall-through' from one case section to the next (i.e.\ the `break' of C is implied.)

The variant case statments casex and casez are supported and have the same syntax as the normal case statement. These can generate dont-care conditions which help in logic minimisation when `x', `z' or `?' are used in constant case tags. These are not explained in this tutoria.

Behavioural Assignment Statements

Behavioural assignment is used to change the values of nets which have type `reg'. These retain their value until the next assignment to them. CV2.100 supports two types of behavioural assignment (as well as the continuous assignment.

Non-blocking or `delayed' assignment.
Using the `<=' operator, an assignment is `non-blocking' (or is `delayed') in the sense that the value of the assigned variable does not change immediately and subsequent references to it in the same group of statements ( always block) will refer to its old value. This corresponds to the normal behaviour of synchronous logic, where each registered net corresponds to a D-type (or broadside register for a bus) clocked when events in the sensitivity list dictate. The syntax is
      <=   ;
The left hand side signal must have type reg. For example, to swap two registers we may use
    x <= y;
    y <= x;
Where a variable is updated by more than one delayed assignment per clock cycle, each new one simply cancels any previous one.

Blocking or `immediate' assignment.

When assignment is made using the `=' operator, the assignment is `blocking' and occurs immediately meaning that the values found by the right-hand-sides of subsequent behavioural statements in the block will use the newly assigned value. The term `blocking' is not helpful in the current context, but is useful in general Verilog when the assignment also contains arbitrary event control statements. This is why I have introduced the two synonyms `delayed' and `immediate' for the two types of assignment. The syntax for blocking assignment is

      =   ;
Again, the left hand side signal must have type reg. CV2.100 supports multiple such assignment to a variable to be made within one group of assignments. For example, two registers may be swapped using an intermediate register t as follows
    t = x;
    x = y;
    y = t;
This will result in a flip-flop called t being present in the CV2.100 output, but in fact it will not drive anything, and so it will normally be deleted by subsequent CAE tools.

Sensitivity lists

The full syntax of a sensitivity list is

       [ or   ]
where the edge qualifier is either null or one of posedge or negedge . There is also a hash delay form of senesitivity list, but this is ignored for synthesis.d The signal is the name of any net. If the net is a bus, subscripts are not allowed within the sensitivity list and the whole bus is implied. The square brackets indicate that any number of nets may be listed, separated with the keyword or .

CV2.100-V2 supports several forms of sensitivity list, including

  • posedge of a single net (which will become a clock),
  • negedge of a single net (which will become an inverted clock),
  • A pair of nets both either positive or negative edge sensitive. One will become a clock and the other an asynchronous reset or preset to the flip-flops. Which net is which and whether a set or reset and whether the clock is inverted or not depends on the divisibility of the expression assigned to the register by each of the nets.
  • a list of nets with no edge qualifiers.

The first two variations make an always block represent a block of synchronous logic with a global clock of either polarity.

The third form is the normal Verilog construct for introducing asynchronous presets or resets to the flip-flops within the block.

The last form allows a complex combinatorial function to be expressed using behavioural constructs ( if and case etc.). All of the inputs to the function (known as the support ) must be listed in the sensitivity list. If a signal is missing from the support list, a transparent latch would be implied. Creation of these is normally not useful and CV2 instead reports an error.

Behavioural Example and Style

To support registered outputs from a module, it is allowed for the same net name to appear both in a reg statement and an output statement.

For example:

     module EXAMPLE(ck, ex);
       input ck;
       output ex;

       reg ex, ez;       // ex is both a register and an output
       reg [2:0] q;

       always @(posedge ck)
         begin
         ex = 0;
         ez = ~ez;
         if (ez) begin
                q = q + 3'd1;
                if (q == 2) ex = 1;
                end
         end
     endmodule
The example defines a divide by two flip-flop ez and a three bit counter with clock enabled by ez. The output ex is also a register. In addition ex is updated twice within the always block, but under different conditions.

It is a matter of style whether to use many simple always declarations or fewer always declarations with large `begin-end' blocks, each containing a greater number of assignments. However, the interleaving of assignments in a simulation is not guaranteed across always blocks in the same module and can lead to random behaviour or different behaviour between simulation and synthesis. Therefore, it is usual practice to only use one always statement per clock in each module.

For synthesis with cv2.100, a given net can only be updated in one always declaration.

$display and $strobe etc.

The Verilog meta-statements $display , $write , and \$finish and some others may be embedded in the language accepted by CV2.100. They are in the syntactic category of behavioural statements and so must be inside an initial or always statement. Since these statements are only significant during simulation, CV2.100 completely ignores them.

Module Parameters and Overrides

A Verilog parameter is an identifier which takes on a numerical value which is typically used to provide such things as variable bus widths or variable division ratio in a divider.

In Verilog, parameters may be defined locally to a module with a constant value or passed in as a compile-time value from a structural instantiation of the module.

Here is an example of parameter definition and use.

    module MOD1(..... );

      parameter bussize = 10, fred = 3;
      parameter delta = 4;
      wire [bussize-1:0] mybus = yourbus + delta;
    ....
    endmodule

These parameters can be overridden each time the module is instantiated using a list of expressions (here numbers are used) inside parenthesis and starting with a hash sign. The overrides are applied to the parameters in the textual order they are defined in the module, which in the example, is bussize, fred, delta.

     
     MOD1  #(11, 4, 5) the_mod1 (.....  );
Not all the parameters are overridden if the list of overrides is shorter than number of parameters.

Tasks

The Verilog task system is supported for synthesis by CV2.100. Tasks must be non-recursive. Task definitions occur inside a module definition after the declaration of any free parameters, wires, regs, events and other identifiers which are referenced inside the task.

The syntax of a task definitions is

     task < name> ; < declarative-items>* < behav-statement> endtask
where the declarative items are restricted to input, output, inout, net, reg, integer and parameter declarations. Owing to the vagueries of Verilog syntax, unlike a module, the task does not have a signature in parenthesis. Arguments must be passed to it in the order of the declaration statments in the task definition. There is no semicolon after an endtask . Here is an example
  module TEST();

    reg a, freev;
    wire  [2:0] b;

    task andingtask;
      output x;
      input [2:0] d;
      x = (&(d)) | freev;
     endtask

  always @(posedge clk) andingtask(a, b);

  endmodule
Note that the task has scope of the enclosing module and is able to make access to the local signals of the module, such as freev in the example, much like free variables in Pascal or Modula.

Functions calls

Function calls are supported in CV2.100 but nor described in this version of the manual.

Asynchronous Resets and Clock Enables

The D-type flip-flops generated by CV2.100 have the following signature and possible implementation.

      module DFF(q, d, c_enable, a_reset);
        input d, c_enable, a_reset;
        output q;
        reg q;
        always @(posedge clk or posedge a_reset)
              if (a_reset) q = 0;
              else if (c_enable) q = d;
      endmodule
Contrarywise, synthesis of the above Verilog will result in one flip-flop, but whether the clock-enable input is actually used depends on compiler heuristics and surrounding context.

Here is an example of behavioural Verilog which CV2.100 will compile into flip-flops with asynchronous resets (for z0 ) and presets (for z1 ). Asynchronous presets are actually achieved with the same DFF leaf flip-flop and with inversion applied to the d input and q output.

        reg [1:0] z0, z1;
        always @(posedge r or negedge clk)
              begin
              z0 = (r) ? 0 : d;
              z1 = 1;
              if (r == 0) z1 = d;
              end

CV2.100 may not always spot that it can use an asynchronous reset to achieve a logic function and will stop with an error message. In these circumstances, simplify the logic that is assigned so that the division is easier for the compiler or else instantiate flip-flops structurally.

Here is a 3 bit binary counter with asynchronous reset.

// 3 bit binary counter with asynchronous reset
    module CTR3(q, ck, clear);        
       input ck;
       output [2:0] q;  reg [2:0] q;
       input clear;
       wire [2:0] e_d = q + 3'd1;
       DFF_AR ctr0(.q(q[0]), .d(e_d[0]), .ar(clear), .ck(ck)); 
       DFF_AR ctr1(.q(q[1]), .d(e_d[1]), .ar(clear), .ck(ck));
       DFF_AR ctr2(.q(q[2]), .d(e_d[2]), .ar(clear), .ck(ck)); 
    endmodule

And here is the source for the same using behavioural reset synthesis.

    module CTR3(q, ck, clear);        
       input ck;
       output [2:0] q;  reg [2:0] q;
       input clear;
       always @(posedge ck or posedge clear)
              q = (clear) ? 0 : q + 3'd1;
    endmodule

Primitive Modules

CV2.100 allows certain modules to be flagged as primitive. Primitive modules may be included by the user in his main source or in libraries. The purpose of a primitive module is to provided a prototype for a component or subcircuit which is to be later substituted for an alternative implementation. The alternative implementation may be an abstract simulation model that cannot be passed to CV2.100 (e.g. because it is written in C) or it might be a leaf module in the target technology library, such as a gate, pad or macrocell.

The compiler does not examine the bodies of primitive modules, except for input , output or inout port specification statements, and it does not include primitive module definitions in the output netlist.

There are three approved ways of marking that a module definition is a primitive prototype. The first is to use the keyword `primitive' instead of `module'. For example:

  primitive  MYAND2(o, x, y);
    input x, y;
    output o;
    // The body is ignored and may be absent
    // in a primitive module
  endprimitive

The second way is similar, but uses the preprocessor instead

  `celldefine
  module  MYAND2(o, x, y);
    input x, y;
    output o;
    // The body is ignored and may be absent
    // in a primitive module
  endmodule
  `endcelldefine

The third way it to place primitives in their own file and include this file on the command line (or contents of the -f file) after the -libs separator. Unflagged modules in such files will be treated as primitives. The -tech technology library is also treated in this way.

CV2.100 also supports the non-standard methods of defining primitive modules used in the older CV2.18, which include `primitive everything' and `primitive module(...);'.

Verilog Preprocessor

Verilog tools, such as CV2.100, include a preprocessor which is similar to the preprocessor defined for the C language. The following preprocessor commands are handled by CV2.100.

Macros

The define macro allows replacement of text with other text, for instance

    `define red 1
    `define amber 2
    `define green (`red+`amber)
introduces three identifiers whose scope is from their point of definition onwards, through all other subsequent files. The backquote must be given before the macro name at the point of macro expansion. The definition of `green' uses the fact that `red' and `amber' have been defined already.

Macros may be defined from the command line with the -D or +define+ flags.

The macro `SYNTHESIS' is defined by default in CV2.100.

Textual Inclusion

The include preprocessor command takes as an argument a file name (which must be in one of the directories on the CVPATH) and textually inserts it in the source file. Includes may be nested. Example of use:
    `include mylibrary.cv

Conditional Compilation

The if , ifdef and ifndef macro commands turn on and off processing of the following text, up to an endif . There is also an else command. The if command takes an argument which must be `1' or `0' (after macro expansion) and processing continues if it is a 1. The other two look up the given argument in the list of defined macros and proceed with processing if or if not respectively the macro is defined. Ifs may be nested.

    `ifdef synthesis
     ... lines included if defined
    `else
     ... lines included if not defined
    `endif

Default nettype

The directive default_nettype wire causes subsequent undefined net names to become automatically defined as type wire (or whatever else is specified) when encountered having not been declared.

  `default_nettype wire

Ignored Macros

The timescale macro, used during simulation, may be present, but is ignored by CV2.100.

CV2.100 Installation and Invocation

The CV2.100-V2 system consists of the executable binary file `cv3core' and several library files. The directory containing the binary file must be on the PATH.

In unix systems, a soft link to cv3core called cv2.100 should also be on the PATH.

The CVPATH is an environment variable which defines a search path for Verilog source files. It is a colon-separated list of directories. This list should normally include the current directory (dot), the CV2.100 library directory, and other technology and project specific libraries. The cv100gates.cv file should be on the CVPATH somewhere.

The CVMETAPATH is an environment variable which defines a search path for system files needed by CV2.100. These include a license and a the .sml metalanguage files.

No license is needed for CV2.100 for any user, whether commercial or academic. However, a license file called LICENSE.cv3 needs to be on the CVMETAPATH and the evaluation license will do for now.


CV2.100 Command line arguments

CV2.100 is run with the following command

    cv2.100  [ options ] filename [ filename ... ] [ -libs filename [ filename ... ]]
CV2.100 takes a list of one or more source files. Nothing is inferred from order of them, except for those that come before and after the -libs separator and the contents of all of the files are essentially concatenated during internal processing. The source files must either be in the current directory or in one of the directories given by the shell variable CVPATH.

The CV2.100 program expects Verilog source files to have the suffix `.cv' and will try to append such a suffix, unless the user-supplied filename already has a dot in it.

As well as the files that you specify, CV2.100 also reads a technology library specified using the -tech command line argument. This library defines the gates which the compiler will use in its synthesised logic and other leaf cells which are required for certain technologies, such as IO pads etc..

If the -tech command line argument is omitted, the standard library file `cvgates' will be used. This contains a set of unit delay `vanilla' gates. The library file must be on the CVPATH.

The source files must contain a Verilog module whose name is supplied in the -root command line option and also all modules structurally instantiated by the root and its instantiated modules. Any other module not used but present in the source files are checked for correct syntax by the compiler, but not processed otherwise.

Root command line option

The command line option
  -root < modname>
must refer to the top level module that you wish synthesised. The arg string `modname' refers to the name of the module. All leaf modules required for this module must be found on the CVPATH and will be cross checked for contact rules.

The -I command line option

The -I option allows a string to be specified which overrides the (or any) CVPATH environment variable. The string may either be the next command line argument or else directly after the -I as part of the same textual argument.

Warn command line option

If the -warn option is given, missing modules will cause only a warning, allowing partial checking to be done.

Libraries command line separator

The token -libs may occur on the command line and it has the effect of making all of the contents of all of the Verilog source files listed after the -libs separator primitive. This is useful if the simulation models of library components are going to be used only for their signatures during compile.

Compile-only command line option

The -c command line option disables most of the compiler and enables it to be used as quick source file syntax checker.

Macro define command line option

The -Dname command line option causes `name' to defined as a macro, so that `ifdef name will succeed.

The alternative form +define+name exists for users of Synopsys.

Both forms can follow the name with an equals sign and a value to define the macro as. For example +define+myname=david .

Delay specification command line options

The -mind and -maxd command line flags control selection of the speed variation fields in the Verilog souce code.

For instance, a builtin AND gate or equivalent continuous assign can have its speed set using the following syntax:


  and #(12:15:19) (y0, a1, a2);

  assign #(12:15:19) y0 = a1 & a2;

In the example, the default delay of 15 nanoseconds is overridden with the command line flags to either 12 or 19.

Parameter overrides can be processed in the same form, where a single override expression is replaced with a set of three with colons between.

Output format command line options

The -vnl command line causes the output from the compiler to be a Verilog netlist. A Verilog Netlist contains module definitions where the modules contain only wire definitions and instances of other more primitive modules.

The -mlout command line causes the output from the compiler to be a ML parse tree.

The -mlin command line causes the output from the compiler to be a ML parse tree, but the output is generated before any compilation is performed, so is semantically identical to the input source code.

Arg file command line options

The -f < filename> causes a file to be opened from which commands are read as though on the command line. The -files causes the file called "files" to be opened from which commands are read as though on the command line. The commands can be split over many lines, with all whitespace characters counting as delimiters. The file must lie in the current directory or a full path name given.

Verbose command line option

The -verbose command line option causes the compiler to augment certain error messages with additional information. This is useful if an error is hard to understand.

Output file name option

The -o < filename> option enables the output file name to be specified for synthesised netlists. The default is the standard output.

Listmods command line option

The -listmods option causes the compiler to print a list of the modules that have been defined in the set of input files.


Technology Libraries (and other files

CV2.100 takes a technology library using the -tech < techfn> command line flag. This has very little effect on the operation of CV2.100, but is a useful way to read in standard pads and other instantiatable modules. The currently available technology libraries are: xi4000, xi3000 and cv100gates.

The CV2.100 compiler generates these gates: BUF MUX2 AND2 OR2 INV XOR2 DFF CVLATCH. These must be present in all technology libraries used with CV2.100. They must have the following signatures.

         CVMUX2(o, a, b, c);            // Two input multiplexor
         DFF(q, d, ck, ce, ar, spare);  // D-type edge tiggered FF 
         CVLATCH(q, d, g, ar);          // Transparent latch
         XOR2(o, i1,i2);                // Binary xor gate
         AND2(o, i1,i2);                // Binary an gate
         BUFIF1(out, in, enable);       // Tristate buffer,active high enable
         OR2(o, i1,i2);                 // Binary or gate
         BUF(o, i);                     // Non-inverting buffer
         INV(o, i);                     // Invertor

The compiler also generates multipliers, adders and subtractors and RAMs as described in the next section.

CV2.100 can also output any other gate or module provided that it is structurally instantiated in the source file and a Verilog primitive prototype is provided in a library.


Use of Macro Block Generation

CV2 will generate macro blocks instances under certain circumstances. The blocks generated are RAMs, ROMs, adders and multipliers.

Array RAMs

CV2.100 will map arrays larger than `minarraysize' to memories. The value of minarraysize is given on the commandline.

Currently, CV2.100 will generate only simple, singled ported RAMs, but future versions of CV2.100 will generate more complex arbiters for the ports and instances of multi-port RAMs.

A typical RAM needed by CV2.100 at the moment is:

module SSRAM32768x8(y, clk, a, cen, d);
  
  input [7:0] d;
  output [7:0] y;
  input clk, cen;
  input [14:0] a;

  reg [7:0] mem [32767:0];

  always @(posedge clk) if (cen) mem[a] = d;
  assign y = mem[a];

endmodule

Verilog Scalar output

Scalar Verilog is the opposite to a net list. There are no component instances, only behavioural expressions. To use this, all leaf components must contain a Verilog behavioural model. CV2.100 has a pair of command line arguments which enable this form of output -scalar -dontbuild TODO define.


A collection of examples

Here are some simple Verilog examples. The modules called SIMSYS are not designed for synthesis, but are test wrappers which can be used to simulate the Verilog example either before or after synthesis.

First.cv - A 4 bit counter

   // first.cv
   // A divide by 16 counter with an exciting output.
   module CTR16(ck, o);
     input ck;
     output o;

      reg [3:0] count;
     always @(posedge ck) 
        begin
        // Add a four bit decimal value of one to count
        count <= count + 4'd1;
        if (count == 14) count <= 1;
        end

     // Note ^ is exclusive or operator
     assign o = count[3] ^ count[1];

   endmodule

   // Top level simulation model
   module SIMSYS();

     wire ck;
     wire boo;
     CLK10MHz clock(ck);
     CTR16 counter(ck, boo);
   endmodule

    // end of first.cv

SPDIF Generator

Here is an example module which generates a digital SP-DIF bit stream equivalent to that found in many CD players and so on.

   // daudio.cv
   module CDSRC(sds, aclk, adata);

     input aclk;  // audio clock 
     output sds;  // side select
     output adata;// audio data bit stream
     wire clk = aclk;

     reg [4:0] phase;
     reg [15:0] audio_data;
     reg sds, adata;

     always @(posedge clk)        begin
           if (phase == 19) begin  // This value may vary from one cd to another
                   phase <= 0; 
                   end
           else phase <= phase + 1;

           if (phase == 15) 
                   begin
                     // The `sound' is just a count sequence generated here
                   audio_data <= audio_data + 16'h0201;
                   sds <= ~sds;
                   end
     end

      always @(posedge clk) 
           if (phase < 16) adata <= audio_data[phase];
           else adata <= 0; 
   endmodule

HDB3 coder and decoder

Here is a decoder for the HDB3 line code used in European trunk PDH telehone systems.

// cbg HDB3DEC
module HDB3DEC(ck, rxpos, rxneg, dout);

  input   ck;        // Clock input
  input   rxpos;        // Positive pulse input
  input   rxneg;        // Negative pulse input
  output  dout;        // Decoded data out


  reg   R_a, R_b, R_c, R_pol;
 
  wire  ab = rxpos | rxneg;
  wire  delta = rxpos ^ R_pol;
  wire  mark = ab & delta;

  // This signal is not brought out, but could be to raise alarm.
  wire  violation = ab & ~delta;

  always @(posedge ck)
  begin
        R_c <= mark;
        R_b <= R_c;
        R_a <= R_b;
        R_pol <= (~ab & R_pol) | (ab & rxpos);
  end

  assign dout = R_a & ~violation;

endmodule // cbg HDB3DEC

Here is the associated HDB3 encoder.

module HDB3ENC (ck, din, txpos, txneg);

  input ck, din;        // Input clock and data
  output txpos, txneg;        // Output positive and negative pair


  reg R_a, R_b, R_c, R_d;
  reg [1:0] R_ct;
  reg R_apout, R_amout;
  reg R_pol, R_lastv;

  wire firstof4, viol_needed, mark;

  assign viol_needed = (R_ct == 2'b11) & ~R_a;

  always @(posedge ck)
  begin
  
        // Input data shifted into four bit register.
        R_a <= R_b;
        R_b <= R_c;
        R_c <= R_d;
        R_d <= din;


        // Counter of number of zeros, reset on ones.
        R_ct <= (R_a) ? 2'b00 : R_ct + 2'1;

        // Polarity reverses on bona-fida marks;
        R_pol <= R_pol ^ mark;   

        // Save polarity of last violation
        R_lastv <= (viol_needed) ? ~R_pol :  R_lastv;
  end


  // This is the magic rule defined in the spec.
  assign mark = R_a | (firstof4 & (R_lastv ^ R_pol));

  // Detect first zero of a group of 4.
  assign firstof4 = ~R_a & ~R_b & ~R_c & ~R_d & (R_ct == 2'b00);


// Generate the two outputs and register them.
  always @(posedge ck)
  begin
        R_apout <= ((mark & R_pol) | (viol_needed & ~R_pol));
        R_amout <= ((mark & ~R_pol) | (viol_needed & R_pol));
  end

  assign txpos = R_apout;
  assign txneg = R_amout;

endmodule // hdb3 encoder;

Traffic light controller

Here is an example traffic light controller which uses the case statement and some simple macros.

// Traffic light controller
    `define red 1
    `define amber 2
    `define green 4

    module TRAFFIC_LIGHTS(clk, lights);
       input clk;
       output [2:0] lights;
       reg [2:0] lights;

        reg [1:0] phase;

       always @(posedge clk)
        begin
           case (phase)
            0 : lights = `red;
            1 : lights = `red + `amber;
            2 : lights = `green;
            3 : lights = `amber;
           endcase 
           phase = phase + 1;
        end
    endmodule /* TRAFFIC_LIGHTS */

    module SIMSYS();
       wire clk;
       wire [2:0] lights;
       CLK1MHz clk(clk);
       TRAFFIC_LIGHTS traffic_lights(clk, lights);
    endmodule

Generation of Xilinx or other FPGAs from Verilog

Please see the separate document CV2 FOR FPGA .


CV2.100 Restrictions and Extensions

Multi-symbol preprocessor macros are not supported by current CV2.100.

The drive strength and delay qualifiers of a full Verilog continuous assignment are ignored by CV2.100.

Disable, specify, named blocks and functions are not supported by CV2.100-V2.15. Procedure continuous assignment is not supported. Global events and trigger with `->' is not supported. User defined primitives with transition tables are not supported.


End of document. (C) Tenison Tech 1996-2000. Products Home.