HDLbits Problem set

Verilog Language

Basics

Wire

Wires (and other signals) in Verilog are directional: information flows in only one direction, from (usually one, often called a driver that drives a value onto a wire) source to the sinks.

A module with 1 input and 1 output behaves like a wire.

The ports on a module also have a direction. An input port is driven by something from outside the module, while an output port drives something outside. Viewed from inside the module, an input port is a driver or source, while an output port is a sink.

A wire cannot have more than one driver. A wire that has no drivers will have an undefined value (often treated as 0 when synthesizing hardware).

Declaration

Any wire(or other ypes) to connect internal components together needs to be declared in the body of the module before it is first used.

continuous assignment

In a Verilog “continuous assignment” (assign left_side = right_side;), the value of the signal on the right side is driven onto the wire on the left side. The assignment is “continuous” because the assignment continues all the time even if the right side’s value changes. (Not a one-time event.)

The order of multiple assign statements in which they appear in the code does not matter !!!.

assign describe connections between things, not the action of copying a value from one thing to another. And it must be highlighted that assign are not creating wires but creating the connections between wires.

An assign statement drives a wire with a value. This value can be any as long as it’s a combinational function.

Gate

NOT Gate/Inverter
1
2
3
module Not_Gate( input in, output out );
assign out = ~in;
endmodule
And Gate

Verilog has separate bitwise-AND (&) and logical-AND (&&) operators.

1
2
3
4
5
6
7
8
9
10
11
12
13
module Add_Gate( 
input a,
input b,
output out );
assign out = a & b;
endmodule

module NAdd_Gate(
input a,
input b,
output out );
assign out = ~(a & b);
endmodule
Or/Nor Gate

Verilog has separate bitwise-OR (|) and logical-OR (||) operators.

1
2
3
4
5
6
7
8
9
10
11
12
13
module Or_Gate( 
input a,
input b,
output out );
assign out = a | b;
endmodule

module Nor_Gate(
input a,
input b,
output out );
assign out = ~(a | b);
endmodule
Xor/ Xnor Gate
1
2
3
4
5
6
7
8
9
10
11
12
13
module XNor_Gate( 
input a,
input b,
output out );
assign out = (a & ~b) | (~a & b);
endmodule

module XNor_Gate(
input a,
input b,
output out );
assign out = (~a & ~b) | (a & b); //assign out = a^b
endmodule

Vectors

Vectors are used to group related signals using one name to make it more convenient to manipulate.

1
2
3
4
wire [31: 0] myVec;           //The declaration places the dimensions before the vector name.
wire [ 3: 0] outVec;
assign out = myVec[10]; //The part select places the dimensions after the vector name.
assign outVec = myVec[3:0];

Declaration

Vectors must be declared

1
type [upper:lower] vector_name;

where type specifies the datatype of the vector, usually wireor reg, and additionallyinput and output (port type).

The endianness of a vector is whether little-endian(the the least significant bit has a lower index e.g. [3:0]) or big-endian(, e.g.[0:3]). But it must always be the same way once a vector is declared with a particular endianness.

1
2
3
wire [3:0] vec1;             //little-endian
wire [0:3] vec2; //big-endian
assign vec1[0:3] = {1,0,0} //bad

NOTEImplicit nets are often a source of hard-to-detect bugs. Net-type signals can be implicitly created by:

  1. an assign statement
  2. attaching something undeclared to a module port.

Implicit nets are always one-bit wires and causes bugs if you had intended to use a vector. Disabling creation of implicit nets can be done using the ``default_nettype none` directive.

Unpacked vs. Packed Arrays

Packed dimensions Unpacked dimensions
declared before the vector name after the name
The bits are packed together into a blob
NOTE relevant in a simulator but not in hardware used to declare memory arrays

Access

Accessing an entire vector is done using the vector name.

1
2
3
wire [8:0] w;
wire [4:0] a;
assign w = a;

It takes the entire 4-bit vector a and assigns it to the entire 8-bit vector w. It is zero-extended or truncated as appropriate If the lengths of the right and left sides don’t match.

Accessing a portion of a vector is done bypart-select.

1
2
3
4
5
6
reg [4:1] x;
input wire [3:-2] z;
w[3:0] // Only the lower 4 bits of w
x[1] // The lowest bit of x
x[1:1] // The lowest bit of x
z[-1:-2] // Two lowest bits of z

Concatenation and replication

The concatenation operator {,} is used to create larger vectors by concatenating smaller portions of a vector together.

NOTEConcatenation needs to know the width of every component. Thus {1, 2, 3} is illegal and results in the error message: unsized constants are not allowed in concatenations.

1
2
3
4
5
6
input [15:0] in;
output [23:0] out;
assign {out[7:0], out[15:8]} = in; // Swap two bytes.
assign out[15:0] = {in[7:0], in[15:8]}; // Swap two bytes, out[23:16] are not assigned.
assign out = {in[7:0], in[15:8]}; // The 16-bit vector on the right is extended to match the 24-bit out.
// So out[23:16] are zero.

The replication operator allows repeating a vector and concatenating them together when sometimes you want the same thing concatenated together many times.

1
{num{vector}}                               //replicates `vector` by `num` times. 

num must be a constant and both sets of braces are required.

1
2
3
4
{5{1'b1}}           // 5'b11111
{2{a,b,c}} // {a,b,c,a,b,c}
{3'd5, {2{3'd6}}}
{3'd5, 2{3'd6}} //illegal

Bitwise vs. Logical Operators

between Description Output
bitwise operation 2 N-bit vectors replicates the operation for each bit 1 N-bit output
logical operation 2 N-bit vectors treats the entire vector as a boolean value, truefor non-zero and false for zero. 1-bit output

Module

A module is a circuit that interacts with its outside through input and output ports. Larger and more complex circuits are built by composing bigger modules out of smaller modules and other pieces (e.g. assign and always blocks) i.e. hierarchy.

  • Modules can contain instances of other modules as long as all of the modules used belong to the same project (so the compiler knows where to find them all).

  • Code for different modules are not nested.

When connecting modules, only the ports on the module are important.

Connecting Signals to Ports

By position

Ports are connected left to right according to the module’s declaration when instantiating a module.

1
mod_a instance1 ( wa, wb, wc );
  • instantiates a module of type mod_a
  • gives an instance name of “instance1
  • connects signal wa, wb and wc to the first, second and third ports (in1,in2 and out) of the new module.

Drawbacks If the module’s port list changes, all instantiations of the module will also need to be found and changed to match.

By name
1
mod_a instance2 ( .out(wc), .in1(wa), .in2(wb) );
  • instantiates a module of type mod_a
  • gives an instance name of “*instance 2”
  • connects signal wa, wb and wc to the ports named in1,in2 and out of the module.

AdvantagesIt allows wires to remain correctly connected even if the port list changes. This syntax is more verbose, although.

Note The ordering of ports is irrelevant because the connection will be made to the correct name, regardless of its position in the sub-module’s port list.

Multiple-signal ports: Like everywhere else in Verilog, the vector length of the port does not have to match the wire connecting to it(zero-padding or trucation will work to make them match).


HDLbits Problem set
http://example.com/2023/03/02/HDLbits/
Author
Tekhne Chen
Posted on
March 2, 2023
Licensed under