# Wires, registers, and vectors

*wire vs reg, and multi-bit buses*

In Verilog a wire carries a continuously-driven value while a reg holds a value assigned inside a procedural block; either can be a single bit or a vector such as [7:0] for a multi-bit bus, and every bit is four-state (0, 1, x for unknown, z for high-impedance).

Group: HDL
URL: https://digiwleea.wleeaf.dev/learn/verilog-values/

So far the signals in your Verilog have been single bits. Real designs move **buses** and need to know *what kind* of thing each name is. Verilog has two: a **wire** (driven continuously, like the output of an [assign](https://digiwleea.wleeaf.dev/learn/verilog-combinational/)) and a **reg** (assigned inside a procedural block, like the `always` block of a [flip-flop](https://digiwleea.wleeaf.dev/learn/verilog-sequential/)). Getting these right, and writing multi-bit values, is most of day-to-day Verilog.

## wire versus reg

A **wire** is exactly what it sounds like: a connection driven by something else, an `assign`, a module output, a gate. You cannot assign a wire inside an `always` block. A **reg** is a name that *holds* its value between assignments and is written inside procedural blocks (`always`, `initial`). The rule of thumb: if a signal is driven by `assign` or a port connection, it is a `wire`; if it is assigned inside an `always` block, it must be a `reg`.

> **WARN:** The single most misleading name in Verilog: a **`reg` is not necessarily a register**. A `reg` assigned in `always @(posedge clk)` becomes a flip-flop, but a `reg` assigned in `always @(*)` (combinational) is just a wire with a procedural style, no memory at all. `reg` only means "assigned procedurally," not "stored in hardware." What makes it a real register is a clock edge, not the keyword.

## Vectors: a bus in one name

A **vector** is a multi-bit signal, written with a range: `wire [7:0] bus;` is an 8-bit [bus](https://digiwleea.wleeaf.dev/learn/buses/). `bus[7]` is the most-significant bit, `bus[0]` the least; `bus[3:0]` is the low nibble, a slice. This is how you carry a whole byte on one name instead of eight separate wires, exactly the `A[7:0]` notation from the hardware. An 8-bit register is just the [flip-flop](https://digiwleea.wleeaf.dev/learn/verilog-sequential/) widened to a vector:

```verilog
module reg8(
  input            clk,
  input      [7:0] D,
  output reg [7:0] Q
);
  always @(posedge clk)
    Q <= D;
endmodule
```

_An 8-bit register: the same posedge-clocked pattern as a one-bit flip-flop, but D and Q are now [7:0] vectors, so all eight bits are captured together on the clock edge. This is the register you built as REG8, in Verilog._

Number literals name a width and base: `8'hFF` is eight bits of hex FF (all ones), `8'b1010_0101` is a binary byte (underscores are just for readability), and `4'd5` is four bits of decimal 5. The width before the quote keeps you honest about how many wires a value really occupies.

## Parametric modules: one width, any size

You wrote `reg8` at exactly eight bits. Tomorrow you need the same thing at 5 bits, or 16, or 32. Copy-pasting the module and hand-editing every `[7:0]` is how off-by-one bugs get in. A **parameter** is a named constant you set when you *instantiate* a module, so one source describes a whole family of widths. Declare it in the module header with `#(...)` and use it in the port ranges, exactly the [8-bit adder](https://digiwleea.wleeaf.dev/learn/adder8/) you built, but width-generic:

```verilog
module adder #(parameter WIDTH = 8) (
  input  [WIDTH-1:0] A,
  input  [WIDTH-1:0] B,
  output [WIDTH:0]   sum
);
  assign sum = A + B;
endmodule
```

_A width-generic adder. WIDTH defaults to 8, but every range is written in terms of it, so the same source becomes a 5-bit or 32-bit adder just by changing one number at instantiation. The sum is WIDTH+1 bits wide to hold the carry-out._

To use it, override the parameter with `#(...)` before the instance name. The one `adder` source becomes both a 5-bit and an 8-bit adder in the same design:

```verilog
// 5-bit adder: A, B are [4:0], sum is [5:0]
adder #(.WIDTH(5)) small (.A(a5), .B(b5), .sum(s5));

// 8-bit adder from the SAME module: A, B are [7:0], sum is [8:0]
adder #(.WIDTH(8)) big   (.A(a8), .B(b8), .sum(s8));
```

_Two instances of one module at two widths. #(.WIDTH(5)) makes A and B [4:0] and sum [5:0]; #(.WIDTH(8)) makes A and B [7:0] and sum [8:0]. Leaving the override off would use the declared default of 8. You can also write it positionally as #(5), but naming the parameter is clearer._

> **TIP:** A `parameter` is an **elaboration-time** constant, fixed the moment the design is built, one value per instance. It is not a signal that changes as the clock ticks. So a parameter can size a bus or count loop iterations, but you cannot drive it from logic at run time. Think of it as filling in a blank on the blueprint before the part is manufactured, not flipping a switch on the running board.

## Arrays: many vectors, a memory

A vector `[7:0]` is a row of 8 bits. Stack many such rows and you get an **array**, Verilog's model of a memory. Write the element width first (the **packed** range, `[7:0]`, before the name) and the number of elements after the name (the **unpacked** range, `[0:255]`):

```verilog
reg [7:0] mem [0:255];   // 256 locations, each one byte

mem[0]   = 8'h00;        // whole byte at address 0
mem[255] = 8'hFF;        // whole byte at address 255
data     = mem[addr];    // read the byte selected at runtime by addr
```

_mem is 256 separate 8-bit registers. mem[addr] selects one of them, and addr can be a live signal, so the location is chosen at run time. This is exactly the storage inside the RAM you built._

The two ranges do different jobs: the packed `[7:0]` says each element is 8 bits wide, and the unpacked `[0:255]` says there are 256 of them. To reach a single bit you index both: `mem[addr][0]` is the least-significant bit of the byte at `addr`. Putting it together, a byte-addressable [RAM](https://digiwleea.wleeaf.dev/learn/ram/) is one clocked write plus one continuous read:

```verilog
module ram256(
  input            clk,
  input            we,      // write enable
  input      [7:0] addr,
  input      [7:0] din,
  output     [7:0] dout
);
  reg [7:0] mem [0:255];    // 256 bytes of storage
  always @(posedge clk)
    if (we) mem[addr] <= din;
  assign dout = mem[addr];
endmodule
```

_The RAM from the course in Verilog: 256 bytes, written on a clock edge when we is high, read continuously through dout. mem[addr] on the left of <= writes that location; on the right of assign it reads it._

> **WARN:** You can only touch an array **one element (or slice) at a time**: `mem[addr]` is a value, but `mem` alone is not, so you cannot assign or wire up a whole memory by name. And an unpacked array is not a wide vector: `reg [7:0] mem [0:255]` is 256 addressable bytes (you reach one with `mem[addr]`), while `reg [2047:0] flat` is one 2048-bit number (you reach a byte only by slicing, `flat[8*addr +: 8]`). Same bit count, completely different thing.

## Four-state values

Like the [signals](https://digiwleea.wleeaf.dev/learn/signals/) on your canvas, each Verilog bit is **four-state**: `0` and `1` (driven low and high), `x` (unknown, the simulator does not know), and `z` (high-impedance, driven by nothing, a floating or released [tri-state](https://digiwleea.wleeaf.dev/learn/tristate/) line). An uninitialised `reg` starts as `x`; a released bus reads `z`. Seeing `x` or `z` in a simulation is the same debugging signal as `X` or `Z` on the canvas: something is uninitialised, contended, or floating.

> **KEY:** Why this matters: `wire`/`reg` and vectors are the vocabulary for every real Verilog module. A [datapath](https://digiwleea.wleeaf.dev/learn/datapath/) is buses (`wire [7:0]`) between blocks; a [register](https://digiwleea.wleeaf.dev/learn/register8/) or the accumulator of your CPU is a `reg [7:0]` clocked on an edge; and `x`/`z` in simulation are how you catch an uninitialised or floating signal before it reaches silicon. Master these and you can read production HDL.

**Q (Try it):** You write `always @(*) y = a & b;` where `y` is combinational (no clock). Should `y` be declared `wire` or `reg`, and does it create a stored register?

**A:** `y` must be declared **`reg`**, because it is assigned inside an `always` block (only regs can be). But it creates **no** stored register: with `always @(*)` and no clock edge, it is pure combinational logic, an AND gate, that re-evaluates whenever `a` or `b` changes. This is the classic point that `reg` means "assigned procedurally," not "a hardware register"; only a clock edge makes real storage.

### FAQ

**Q:** What is the difference between wire and reg in Verilog?

**A:** A wire is driven continuously by something else (an assign, a gate, a module output) and cannot be assigned inside a procedural block. A reg holds its value and is assigned inside always or initial blocks. Rule of thumb: assign-driven signals are wires; signals assigned in an always block must be regs.

**Q:** Does reg in Verilog mean a hardware register?

**A:** No, that is the classic trap. A reg is just a signal assigned procedurally. A reg in always @(posedge clk) becomes a flip-flop, but a reg in always @(*) is plain combinational logic with no memory. Only a clock edge makes real storage; the keyword does not.

**Q:** What is a vector in Verilog?

**A:** A vector is a multi-bit signal declared with a range, like wire [7:0] bus for an 8-bit bus. bus[7] is the top bit, bus[0] the bottom, and bus[3:0] is a slice. It lets one name carry a whole byte instead of eight separate wires.

**Q:** What are the four states of a Verilog signal?

**A:** 0 (driven low), 1 (driven high), x (unknown, the simulator cannot tell), and z (high-impedance, driven by nothing). These match the 0/1/X/Z states of a wire in hardware: x usually means uninitialised or contended, z means floating or a released tri-state line.

**Q:** What is a parameter in Verilog?

**A:** A parameter is a named constant set when a module is instantiated, so one source can describe many sizes. You declare it in the module header, for example module adder #(parameter WIDTH = 8), use it in the port ranges like input [WIDTH-1:0] A, and override it per instance with adder #(.WIDTH(5)). It is fixed when the design is built, not a signal that changes over time.

**Q:** How do you declare a memory or array in Verilog?

**A:** Put the element width before the name and the number of elements after it: reg [7:0] mem [0:255] is 256 bytes. The packed range [7:0] is each element's bit width, the unpacked range [0:255] is how many elements there are. Index it with mem[addr] to read or write one location at run time, and mem[addr][0] to reach a single bit.
