# Continuous assignment

*Combinational logic with assign*

A continuous assignment in Verilog (assign wire = expression) describes a piece of combinational logic that is always active, the same standing gate network the expression denotes, and it can be derived directly from a truth table as a sum of products using & for AND, | for OR, and ~ for NOT.

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

You have a [Verilog module](https://digiwleea.wleeaf.dev/learn/verilog-intro/) with a port list. This lesson covers the workhorse of combinational Verilog: the **continuous assignment**, the `assign F = ...;` line. It is Verilog's version of VHDL's [concurrent assignment](https://digiwleea.wleeaf.dev/learn/vhdl-concurrent/), a standing gate network, and because a [truth table](https://digiwleea.wleeaf.dev/learn/truth-tables/) completely specifies a combinational function, you can write it straight from the table.

## assign means always live

A statement like `assign F = A & B;` is **continuous**: it is not executed once, it describes a gate that drives `F` from `A` and `B` forever. Write several `assign` lines in a module and they all run at the same time, in parallel, in any order, because each is its own piece of hardware. The operators are C-like but mean gates: `&` is AND, `|` is OR, `~` is NOT, and `^` is XOR. (Watch the doubles: `&&` and `||` are *logical* operators for `if` conditions, not gates, so bitwise logic uses the single forms.)

> **TIP:** Because continuous assignments are parallel hardware, their **order in the file does not matter**. `assign F = t & C;` then `assign t = A & B;` describes the same circuit as the reverse: two gates wired together, and wires do not care which line you typed first. If reordering `assign` lines could change behavior, you are thinking in software, not hardware.

## From truth table to sum of products

Any combinational output can be written as a **sum of products**: OR together one product (an AND) for each input row where the output is `1`, with each input that is `0` in that row negated. "Sum" is OR, "product" is AND. Take [XOR](https://digiwleea.wleeaf.dev/learn/xor/), whose output is `1` exactly when the inputs differ:

| A | B | F |
| --- | --- | --- |
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |

_XOR's truth table. The output is 1 in two rows: (A=0, B=1) and (A=1, B=0). Each becomes one product term._

Read off the two rows where `F` is `1`. The row `A=0, B=1` gives the product `~A & B`. The row `A=1, B=0` gives `A & ~B`. OR them with `|` and you have the equation, which is also the Verilog, line for line:

```verilog
module xor_gate(
  input  A,
  input  B,
  output F
);
  assign F = (~A & B) | (A & ~B);
endmodule
```

_XOR as a continuous assignment, read straight off its truth table: the OR (sum) of the two rows where F is 1. It is the exact Verilog counterpart of the VHDL concurrent version._

That single expression is a complete description of XOR: two AND gates (the products), each fed by an inverter on one input, ORed together. It is the same structure you would draw by hand. The synthesis tool is free to optimise it (perhaps into NANDs), but the behavior is fixed by the equation.

_Circuit diagram: The XOR the equation describes. Open it in the lab and sweep the inputs: F is 1 only when A and B differ, matching (~A & B) | (A & ~B)._

> **TIP:** Verilog has a built-in XOR operator, so the whole gate is also just `assign F = A ^ B;`. That is the shortcut you would use in practice. Writing it as a full sum of products here is the point: it shows that *any* combinational function, not only the ones with a handy operator, comes straight from its truth table.

> **WARN:** A frequent mistake is forgetting to negate the inputs that are `0` in a row. The row `A=0, B=1` is **not** `A & B`, it is `~A & B`, the term must be true for that exact row and no other. Drop the `~` and your equation lights up for the wrong input combination. Always negate every input that reads `0` in the row you are encoding. (And use `&`/`|`, the bitwise gates, not `&&`/`||`, which are logical operators for conditions.)

## Structural style: name the gates and wire them

Every line so far describes logic by its **equation** and lets the tool choose the gates: this is **dataflow** style. Verilog has a second, lower-level way to say the same thing, **structural** style, where you name each gate and wire them together yourself, exactly as you would draw the schematic. Verilog ships **primitive gates** you can instantiate directly: `and`, `or`, `not`, `nand`, `nor`, `xor`, `xnor`. You write the gate keyword, an optional instance name, then the ports in parentheses with the **output first** and the inputs after. Any signal that carries a value between gates but is not a module port is declared as a [`wire`](https://digiwleea.wleeaf.dev/learn/wires-nets/) net. Naming each instance (`g1`, `g2`, and so on) is optional but makes simulation waveforms and error messages much easier to follow.

```verilog
module xor_gate(
  input  A,
  input  B,
  output F
);
  wire nA, nB, t1, t2;   // internal nets between the gates
  not  g1(nA, A);        // nA = ~A   (output nA first, then input A)
  not  g2(nB, B);        // nB = ~B
  and  g3(t1, nA, B);    // t1 = ~A & B
  and  g4(t2, A, nB);    // t2 = A & ~B
  or   g5(F, t1, t2);    // F  = t1 | t2
endmodule
```

_The same xor_gate, rebuilt structurally: five primitive gates joined by four internal wire nets. It is the sum-of-products equation drawn out gate by gate, with the output listed first in every gate's port list._

> **TIP:** You can attach a **propagation delay** to a primitive with `#`: `and #3 g3(t1, nA, B);` makes `t1` settle 3 simulation time units after its inputs change, modeling the real [gate delay](https://digiwleea.wleeaf.dev/learn/timing/) a signal takes to propagate. It affects **simulation timing only**: a synthesis tool ignores the number, since the actual delay comes from the target technology, not from you.

## Hierarchy: modules inside modules

A module can also contain **other modules**, the same way a canvas circuit can drop in a saved custom part. You instantiate a child by writing its name, an instance name, and a **port map**. Connect the ports **by name**: `.A(sig)` wires the child's port `A` to your signal `sig`, so the listing order does not matter and every connection is explicit. Here is a **[half adder](https://digiwleea.wleeaf.dev/learn/halfadder/)** (`SUM` is `A ^ B`, `CARRY` is `A & B`) built by instantiating the structural `xor_gate` above together with the `and_gate` from the [Verilog intro](https://digiwleea.wleeaf.dev/learn/verilog-intro/):

```verilog
module half_adder(
  input  A,
  input  B,
  output SUM,
  output CARRY
);
  xor_gate u1(.A(A), .B(B), .F(SUM));    // SUM   = A ^ B
  and_gate u2(.A(A), .B(B), .F(CARRY));  // CARRY = A & B
endmodule
```

_A half adder assembled from two child modules with named-port mapping. u1's output port F drives SUM; u2's F drives CARRY. This is Verilog hierarchy: the same composition you do on the canvas when you drop a saved part into a bigger circuit._

| A | B | SUM | CARRY |
| --- | --- | --- | --- |
| 0 | 0 | 0 | 0 |
| 0 | 1 | 1 | 0 |
| 1 | 0 | 1 | 0 |
| 1 | 1 | 0 | 1 |

_The half adder the two instances compute: SUM is xor_gate's output (A ^ B) and CARRY is and_gate's output (A & B)._

> **WARN:** Named ports (`.A(A)`) make each connection explicit, so their order is free. Verilog also allows **positional** connection (`xor_gate u1(A, B, SUM);`), which matches signals to ports purely by position: reorder the child's port list later and every positional instance silently miswires. Prefer named ports. And in a primitive gate, remember the **first** port is the output (`and g3(t1, nA, B)` means `t1 = nA & B`), the reverse of how the equation reads.

> **KEY:** Why this matters: sum of products is the bridge from the truth tables you have been filling in to real Verilog. Any combinational block you can describe with a table, a decoder, a comparator, one bit of an adder, you can now write as a continuous assignment. A [Karnaugh map](https://digiwleea.wleeaf.dev/learn/karnaugh/) then trims that equation to fewer gates. Logic that *remembers* needs one more tool, the clocked `always` block, which is next.

**Q (Try it):** Write the continuous assignment for a two-input function `F` that is `1` only when `A=1` and `B=0` (and `0` for the three other rows). How many product terms does it need?

**A:** Only **one** row has output `1`, so it is a single product term: `assign F = A & ~B;`. With just one `1` in the table there is nothing to OR together. (If two rows were `1`, you would OR two products with `|`; the count of product terms equals the count of `1` rows.)

### FAQ

**Q:** What is a continuous assignment in Verilog?

**A:** A continuous (or 'assign') statement, assign wire = expression, describes combinational logic that is always active: a standing gate network that continuously drives the wire from its inputs. It is not executed once like software; multiple assign statements all run in parallel. It is Verilog's equivalent of a VHDL concurrent assignment.

**Q:** What are the bitwise operators in Verilog?

**A:** & is AND, | is OR, ~ is NOT (invert), and ^ is XOR. These build gates. The doubled forms && and || are logical operators used in if conditions, not gates, so combinational logic uses the single (bitwise) forms.

**Q:** How do you write a Verilog equation from a truth table?

**A:** Use sum of products: OR together one product (AND) term for each row where the output is 1, negating every input that is 0 in that row. For XOR, the rows (A=0,B=1) and (A=1,B=0) give assign F = (~A & B) | (A & ~B); (or simply assign F = A ^ B;).

**Q:** What is the difference between assign in Verilog and a concurrent assignment in VHDL?

**A:** There is none in meaning: both describe a standing piece of combinational logic that is always live and runs in parallel with the others. Only the syntax differs, Verilog writes assign F = ... with & | ~, VHDL writes F <= ... with and or not.

**Q:** What is the difference between dataflow and structural Verilog?

**A:** Dataflow style uses continuous assignments (assign F = (~A & B) | (A & ~B);) to describe logic by its equation and lets the synthesis tool choose the gates. Structural style names each primitive gate and wires them by hand (not, and, or instances joined by wire nets), describing the schematic literally. Both compile to the same hardware: dataflow is more concise, structural gives you gate-by-gate control.

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

**A:** A wire is a net that carries a value from its driver to wherever it is read, the Verilog equivalent of a physical connection. You declare internal signals that pass between gates as wire (for example wire t1;), while a module's inputs and outputs are ports. A wire holds no memory: it simply reflects whatever is currently driving it.

**Q:** How do you instantiate a module in Verilog?

**A:** Write the child module's name, an instance name, and a port map: half_adder u1(.A(x), .B(y), .SUM(s), .CARRY(c));. Connecting ports by name (.port(signal)) makes the wiring explicit and order-independent, which is safer than positional connection. Instantiating modules inside modules is how Verilog builds hierarchy, the text equivalent of dropping a saved part into a bigger circuit.
