# Verilog Modelling Styles

## Introduction to Modeling Styles
In Verilog, hardware can be described at different levels of abstraction. The two primary modeling styles are Behavioral and Structural.

- **Behavioral Modeling**: This is the highest level of abstraction. It describes what a circuit does, its function, without specifying how it is implemented with logic gates. It focuses on the algorithm and the flow of data. Behavioral models often use procedural blocks (`always`, `initial`) and high-level continuous assignments.

- **Structural Modeling**: This describes the implementation of a circuit. It specifies how a module is composed of smaller sub-modules and/or primitive logic gates, and how these components are interconnected. It is analogous to a netlist or a schematic diagram.

A typical design process involves starting with a behavioral description to define and verify the functionality, followed by a process of hierarchical refinement to create a detailed structural model that can be synthesized into hardware.

---

## Hierarchical Design Example 1: A 16-to-1 Multiplexer
This example illustrates the design of a 16-to-1 multiplexer (MUX) by progressively refining the design from a pure behavioral model to a full structural one.

### Version 1: Pure Behavioral Model
The simplest way to model a MUX is with a single behavioral statement. The vector `in` is treated as an array, and the `sel` input is used as the index to select one of the input bits.
```verilog
// Pure behavioral model of a 16-to-1 MUX
module mux16to1 (in, sel, out);
  input [15:0] in;
  input [3:0] sel;
  output out;

  assign out = in[sel];
endmodule

Version 2: Structural Model using 4-to-1 MUX Components

A 16-to-1 MUX can be built from five 4-to-1 MUXes. Four MUXes select one output from four groups of four inputs, and a final MUX selects the ultimate output from the results of the first four. This version is structural at the top level, but the 4-to-1 MUX component is modeled behaviorally.

// Behavioral model of a 4-to-1 MUX component
module mux4to1 (in, sel, out);
  input [3:0] in;
  input [1:0] sel;
  output out;
  assign out = in[sel];
endmodule

// Structural model of a 16-to-1 MUX
module mux16to1 (in, sel, out);
  input [15:0] in;
  input [3:0] sel;
  output out;
  wire [3:0] t; // Intermediate lines

  mux4to1 M0 (in[3:0],   sel[1:0], t[0]);
  mux4to1 M1 (in[7:4],   sel[1:0], t[1]);
  mux4to1 M2 (in[11:8],  sel[1:0], t[2]);
  mux4to1 M3 (in[15:12], sel[1:0], t[3]);
  mux4to1 M4 (t,         sel[3:2], out);
endmodule

Version 3: Deeper Structural Hierarchy

The refinement continues by modeling the 4-to-1 MUX structurally using three 2-to-1 MUX components. The 2-to-1 MUX itself is modeled behaviorally.

// Behavioral model of a 2-to-1 MUX component
module mux2to1 (in, sel, out);
  input [1:0] in;
  input sel;
  output out;
  assign out = in[sel];
endmodule

// Structural model of a 4-to-1 MUX
module mux4to1 (in, sel, out);
  input [3:0] in;
  input [1:0] sel;
  output out;
  wire [1:0] t;

  mux2to1 M0 (in[1:0], sel[0], t[0]);
  mux2to1 M1 (in[3:2], sel[0], t[1]);
  mux2to1 M2 (t,       sel[1], out);
endmodule

Version 4: Gate-Level Structural Model

The final step in the refinement is to describe the base component, the 2-to-1 MUX, using primitive logic gates. This results in a fully structural design, from the top-level 16-to-1 MUX down to the gate level.

// Gate-level structural model of a 2-to-1 MUX
module mux2to1 (in, sel, out);
  input [1:0] in;
  input sel;
  output out;
  wire t1, t2, t3;

  NOT G1 (t1, sel);
  AND G2 (t2, in[0], t1);
  AND G3 (t3, in[1], sel);
  OR  G4 (out, t2, t3);
endmodule

Hierarchical Design Example 2: A 16-bit ALU

This example demonstrates modeling a 16-bit Arithmetic Logic Unit (ALU) that performs addition and generates five common status flags.

  • Sign: Whether the sum is negative (MSB is 1).
  • Zero: Whether the sum is zero.
  • Carry: Whether there was a carry out of the last stage.
  • Parity: Whether the number of 1s in the sum is even or odd.
  • Overflow: Whether the signed sum cannot fit in 16 bits.

Version 1: Pure Behavioral Model

The ALU is described behaviorally using high-level continuous assignments for the addition and all flag generation logic.

module ALU (X, Y, Z, Sign, Zero, Carry, Parity, Overflow);
  input [15:0] X, Y;
  output [15:0] Z;
  output Sign, Zero, Carry, Parity, Overflow;

  // 16-bit addition
  assign {Carry, Z} = X + Y;

  // Generation of status flags
  assign Sign = Z[15];
  assign Zero = ~|Z;         // Reduction NOR
  assign Parity = ~^Z;       // Reduction XNOR
  assign Overflow = (X[15] & Y[15] & ~Z[15]) |
                    (~X[15] & ~Y[15] & Z[15]);
endmodule

Version 2: Structural Model (Ripple-Carry using Behavioral Blocks)

A 16-bit ripple-carry adder is built by structurally connecting four 4-bit adder blocks. The 4-bit adder component is described behaviorally. This is an example of mixed-style modeling.

// Behavioral description of a 4-bit adder
module adder4 (S, cout, A, B, cin);
  input [3:0] A, B;
  input cin;
  output [3:0] S;
  output cout;
  assign {cout, S} = A + B + cin;
endmodule

// Structural ALU using 4-bit adder blocks
module ALU (...); // ports as before
  ...
  wire c[3:1];

  // Instantiation of 4-bit adders
  adder4 A0 (Z[3:0],   c[1], X[3:0],   Y[3:0],   1'b0);
  adder4 A1 (Z[7:4],   c[2], X[7:4],   Y[7:4],   c[1]);
  adder4 A2 (Z[11:8],  c[3], X[11:8],  Y[11:8],  c[2]);
  adder4 A3 (Z[15:12], Carry,X[15:12], Y[15:12], c[3]);

  // Flag logic remains behavioral
  assign Sign = Z[15];
  ...
endmodule

Version 3: Structural Model (Ripple-Carry using Gate-Level Full Adders)

The design is refined further by building the 4-bit adder from four gate-level full-adder components.

// Gate-level structural model of a full adder
module fulladder (s, cout, a, b, c);
  input a, b, c;
  output s, cout;
  wire s1, c1, c2;

  xor G1 (s1, a, b);
  xor G2 (s, s1, c);
  and G3 (c1, a, b);
  and G4 (c2, s1, c);
  or  G5 (cout, c2, c1);
endmodule

// Structural 4-bit adder using full adders
module adder4 (S, cout, A, B, cin);
  ...
  wire c1,c2,c3;
  fulladder FA0 (S[0], c1, A[0], B[0], cin);
  fulladder FA1 (S[1], c2, A[1], B[1], c1);
  fulladder FA2 (S[2], c3, A[2], B[2], c2);
  fulladder FA3 (S[3], cout, A[3], B[3], c3);
endmodule

Version 4: Dataflow Model (Carry Lookahead Adder)

An alternative to the slow ripple-carry architecture is the Carry Lookahead Adder (CLA). It computes all carry bits simultaneously using two-level logic, making it much faster. This is modeled using pure dataflow (assign statements).

The theory relies on carry propagate ($p_i = A_i \oplus B_i$) and carry generate ($g_i = A_i \cdot B_i$) functions. The carry for each stage is calculated directly from these functions and the initial carry-in.

// 4-bit Carry Lookahead Adder using dataflow modeling
module adder4 (S, cout, A, B, cin);
  input [3:0] A, B;
  input cin;
  output [3:0] S;
  output cout;
  wire [3:0] p, g;
  wire c1, c2, c3;

  // Generate p and g terms
  assign p = A ^ B;
  assign g = A & B;

  // Generate carry bits using lookahead logic
  assign c1 = g[0] | (p[0] & cin);
  assign c2 = g[1] | (p[1] & g[0]) | (p[1] & p[0] & cin);
  assign c3 = g[2] | (p[2] & g[1]) | (p[2] & p[1] & g[0]) | (p[2] & p[1] & p[0] & cin);
  assign cout = g[3] | (p[3] & g[2]) | (p[3] & p[2] & g[1]) | (p[3] & p[2] & p[1] & g[0]) | (p[3] & p[2] & p[1] & p[0] & cin);

  // Generate sum bits
  assign S[0] = p[0] ^ cin;
  assign S[1] = p[1] ^ c1;
  assign S[2] = p[2] ^ c2;
  assign S[3] = p[3] ^ c3;
endmodule

Verification using a Testbench

A testbench is a Verilog module written to test another module, referred to as the Device Under Test (DUT). It is not synthesizable. A testbench typically includes:

  1. Instantiation of the DUT.
  2. reg variables to model the inputs to the DUT.
  3. wire variables to capture the outputs from the DUT.
  4. An initial block to provide a sequence of input stimuli.
  5. System tasks like $monitor, $display, $dumpfile, and $dumpvars to observe and record the DUT’s response.

A key advantage of hierarchical design is that the same testbench can be used to verify all versions of a module, from the most abstract behavioral model to the most detailed structural one, ensuring functional equivalence throughout the design process.

// Example testbench for the 16-bit ALU
module alutest;
  reg [15:0] X, Y;
  wire [15:0] Z;
  wire S, ZR, CY, P, V;

  ALU DUT (X, Y, Z, S, ZR, CY, P, V);

  initial
  begin
    $dumpfile("alu.vcd"); $dumpvars(0,alutest);
    $monitor($time," X=%h, Y=%h, Z=%h, S=%b, Z=%b, CY=%b, P=%b, V=%b",
             X, Y, Z, S, ZR, CY, P, V);
    #5 X = 16'h8fff; Y = 16'h8000;
    #5 X = 16'hfffe; Y = 16'h0002;
    #5 X = 16'hAAAA; Y = 16'h5555;
    #5 $finish;
  end
endmodule