This semester, you will design your project using Verilog HDL, a hardware
description language commonly used in industry. While behavioral
Verilog can be used to describe designs at a high level of abstraction,
you will design your processor at the gate level in order to quantify the
complexity and timing requirements of your design. Hence you will
use structural Verilog only.

You will be provided Verilog libraries containing modules that will
be the basic building blocks for your design. These library parts
include simple logic gates, registers, and memory modules, for example.
While the library parts are designed behaviorally, they incorporate some
timing information that will be used in your simulations. Using the
class libraries ensures a uniform timing standard for everyone.

Structural Verilog allows designers to describe a digital system as
a hierarchical interconnection of modules. The Verilog code for your
project will consist only of module definitions and their instances, although
you may decide to use some behavioral Verilog for debugging purposes.
This manual will cover all aspects of the Verilog language that you will
need to be familiar with.

The data types that you will use are reg (register) and
wire. Wires cannot hold a value; they are used to connect modules of
combinational logic. Registers are used to store values.
Since regs keep state, a reg cannot be the output of
combinational logic.

Note: The register datatype is not what you use to make flip-flops and
registers. When implemented at the structural level, flip-flops and
registers are still made out of wires and logic gates or other modules,
as you will see in the D latch example in section 4. Registers are only
used in behavioral Verilog.

A module definition is delimited by the keywords module
and endmodule, as shown in the example below.

The module header consists of the module keyword, the
name of the module, and the port list in parenthesis, followed by a semicolon:

module d_latch (d, q, qbar, wen);

Following the module header are the port declarations.
Ports may be of type input, output, or inout,
for input, output, or bidirectional ports. Ports may be either scalar
or vector. The port names in the declarations do not have to occur
in the same order as they did in the port list.

The body of the module (consisting of wire and reg declarations
and module instances) follows the port declarations.

In this example, there are 5 module instances. inv1$
and nand2$ (1-input inverter and 2-input NAND gate) are modules
that are defined in the class libraries. For both of these gates,
the first port is the output of the gate, and the remaining ports are inputs.

A module instance consists of the module name followed by an instance
identifier, port list, and semicolon. Several instantiations of
the same type of module can be made in a list like this:

When instantiating a module, you can omit ports from the port list.
For example, if we wanted to instantiate d_latch in another module
but did not care about the qbar output, we could instantiate it
as follows:

d_latch latch1 (din, q_out, , wen);

In this example, din and wen could be either wires,
registers, or ports declared in the higher-level module, but q_out
cannot be a register.

You should know that any undeclared identifiers are implicitly declared
as scalar wires. So watch out for typos in your port lists.

The assign keyword can be used to tie two wires together or to continually
assign a behavioral expression to a wire. Examples:

wire a, b, c;
assign a = b;
assign c = ~b; //c is assigned to NOT b

With a continuous assignment, whenever the value of a variable on the
right-hand side changes, the expression is re-evaluated and the value of
the left-hand side is updated. The left-hand side of the assignment
must be a wire.

You will use registers primarily in testing your code. Unlike
wires, regs will hold a value until it is re-assigned. In other words,
it maintains state. Delays, indicated by a number following a pound
sign, can be used to specify an amount of time before the value held by
the reg changes. Here is an example.

This example makes procedural assignments to register A. Any code
in a begin-end block following the initial keyword executes only
once, starting at the beginning (time 0) of a simulation. The first
assignment to register A is made at time 0. The #10 indicates
a delay of 10 time units before the next assignments are made. A
is set to 0 at time 10, and A is set to 5 at time 20.

An initial description may be used without a block delimited
by begin and
end if there is only one statement (see
example in next section).

Note that your code can have multiple procedural assignments.
If you have more than one initial block in your code, they will
be executed concurrently.

The repeat statement can be used to specify how many times
a begin-end block is executed. The block following the repeat statement
is executed the number of times indicated by the expression in parenthesis
following the repeat keyword. In the following example, the
block is executed four times. Note that I added a time delay after
the last statement in the block to avoid a race condition.

Use $strobe to display a message on your screen. The
format is similar to that of printf in C. Note that if the
$strobe
command is called at the same simulation time that other registers or wires
are changing values, the value changes will happen before the strobe
command is executed. Example:

always @(posedge clk)
$strobe ("at time %0d, a = %b", $time, a);

This statement is executed every time clk transitions
from 0 to 1, printing the simulation time in decimal and the value of a
in binary. If a changed right at the clock edge, the new
value would be printed.

The starting_address parameter is the address of the memory module
where you begin initialization. If starting_address
is greater than zero, the memory locations at the beginning will remain
unitialized (logic value x). The data file is just a text
file that contains a list of binary or hex numbers. An example of
a data file will be given later in the semester.

You can dump out a a waveform file in text format using VCS the following tasks:

$dumpfile is used to specify the name of the waveform file:

$dumpfile ("file.dump");

$dumpvars specifies the wires and registers whose values you
want to record. The syntax is:

$dumpvars (number_of_levels, instance_name);

If number_of_levels is 1, it will dump all the signals instantiated
in the top level of the instance specified. If number_of_levels
is greater than 1, it will dump all signals instantiated number_of_levels
levels hierarchically below the specified instance. If number_of_levels
is 0, it will dump all signals instantiated under instance_name
at any level. In the examples below, suppose you have an instance
called reg_file in an instance called data_path in an
instance called exec_core in your TOP module.

The first statement will dump all wires and registers instantiated at
any level under the module called reg_file.
The second statement will dump all wires and registers instantiated
in the top level of exec_core, and the top level of data_path,
or any other modules instantiated in exec_core.

You will need to examine the library files to figure out the timing
delays of the library modules. Below is an example of a module from
the library. The delays between the rise or fall of any input and
the change of the output are specified. Two sets of three numbers
are specified for each input. The first set are the minimum, typical,
and maximum delays when the output transitions from 0 to 1. The second
set are the delays when the output transitions from 1 to 0. For this
module, the delays are the same regardless of which way the inputs are
changing.

In this class we will always use the typical delays, so you need only
use the middle number (0.2 in this case for both rise and fall times) when
making your critical path and cycle time calculations.

Here is a small example of a complete program
illustrating use of the D latch. You can read the VCS Manual to learn how to simulate it. When simulated,
it will dump a waveform file of all signals instantiated under TOP. It will also print any transitions of the d register to standard output.

To clarify the difference between structural and behavioral verilog:
structural verilog is composed of module instances and their interconnections
(by wires) only. The use of regs, explicit time delays, arithmetic
expressions, procedural assignments, or other verilog control flow structures
are considered behavioral verilog.

As stated earlier, your project code will consist primarily of structural
verilog. You may use behavioral statements for debugging purposes
only. In fact, you will probably only instantiate two
regs
in your whole design: one for the clock and one for a reset signal that
is asserted at the beginning of your simulation.