Digital Multiplexer Design and Simulation Workflow

Project Architecture and Build Infrastructure

The development environment follows a standardized directory hierarchy to separate hardware description, testbench logic, constraint mapping, and build artifacts. Each multiplexer variant operates within this unified structure.

project_root/
├── constr/
│   └── top.nxdc
├── csrc/
│   ├── test_nvboard.cpp
│   └── test_wave.cpp
├── Makefile
├── vsrc/
│   └── top.v
├── obj_dir/
└── dump.vcd

The Makefile coordinates Verilator compilation, linking against the C++ testbenches, and generating executable simulation targets. Constraint files (.nxdc) map abstract Verilog ports to physical or virtual peripherals.

Implementation 1: 2-to-1 Multiplexer

Hardware Description

The 2-to-1 selector routes one of two single-bit inputs to a single output based on a control signal. The implementation utilizes a combinatorial always block with explicit conditional assignment.

module mux_2to1 (
  input  wire sel,
  input  wire in_a,
  input  wire in_b,
  output wire mux_out
);
  always_comb begin
    if (sel == 1'b0) begin
      mux_out = in_a;
    end else begin
      mux_out = in_b;
    end
  end
endmodule

Pin Constraints

top = mux_2to1

mux_out LD0
sel     BTNL
in_a    BTNR
in_b    BTNU

C++ Testbench: NVBoard Interface

#include <nvboard.h>
#include <Vtop.h>

static Vtop sim_dut;

void map_hardware_pins(Vtop* instance);
void run_clock_cycle();

int main() {
    map_hardware_pins(&sim_dut);
    nvboard_init();
    
    while (true) {
        nvboard_update();
        run_clock_cycle();
    }
}

void run_clock_cycle() {
    sim_dut.eval();
}

C++ Testbench: Waveform Generation

#include "verilated.h"
#include "verilated_vcd_c.h"
#include "obj_dir/Vtop.h"

VerilatedContext* sim_ctx = nullptr;
VerilatedVcdC* vcd_tracer = nullptr;
Vtop* design_instance = nullptr;

void advance_and_record() {
    design_instance->eval();
    sim_ctx->timeInc(1);
    vcd_tracer->dump(sim_ctx->time());
}

void initialize_simulation() {
    sim_ctx = new VerilatedContext;
    vcd_tracer = new VerilatedVcdC;
    design_instance = new Vtop;
    sim_ctx->traceEverOn(true);
    design_instance->trace(vcd_tracer, 0);
    vcd_tracer->open("trace_2to1.vcd");
}

void shutdown_simulation() {
    advance_and_record();
    vcd_tracer->close();
    delete vcd_tracer;
    delete design_instance;
    delete sim_ctx;
}

int main() {
    initialize_simulation();
    design_instance->sel = 0; design_instance->in_a = 0; design_instance->in_b = 0; advance_and_record();
    design_instance->in_b = 1; advance_and_record();
    design_instance->sel = 1; design_instance->in_a = 0; design_instance->in_b = 0; advance_and_record();
    design_instance->in_b = 1; advance_and_record();
    shutdown_simulation();
    return 0;
}

Implementation 2: 4-to-1 Multiplexer

Hardware Description

This variant selects among four single-bit data lines using a 2-bit control vector. The logic is expressed via a case statement inside a combinatorial procedural block.

module mux_4to1 (
  input  wire [1:0] ctrl,
  input  wire d0, d1, d2, d3,
  output wire out
);
  always_comb begin
    unique case (ctrl)
      2'b00: out = d0;
      2'b01: out = d1;
      2'b10: out = d2;
      2'b11: out = d3;
    endcase
  end
endmodule

Pin Constraints

top = mux_4to1

out  LD0
ctrl SW1 SW0
d0   SW5
d1   SW4
d2   SW3
d3   SW2

C++ Testbench Adaptation

For the waveform generator, the input initialization block is modified to cover all selector combinations. The NVBoard template remains structural identical; only the pin mapping in test_nvboard.cpp and the constraint file require updates.

  // Inside main() of test_wave.cpp
  initialize_simulation();
  design_instance->ctrl = 2'b00; design_instance->d0 = 1; design_instance->d1 = 0; design_instance->d2 = 1; design_instance->d3 = 0; advance_and_record();
  design_instance->ctrl = 2'b01; advance_and_record();
  design_instance->ctrl = 2'b10; advance_and_record();
  design_instance->ctrl = 2'b11; advance_and_record();
  shutdown_simulation();

Implementation 3: 2-Bit 4-to-1 Multiplexer

Hardware Description

Widening the data path requires declaring multi-bit vectors for inputs and outputs. The selection logic remains identical but operates on 2-bit chunks. The output reg declaration is replaced with output logic for modern Verilog compliance.

module mux_4to1_wide (
  input  wire [1:0] sel,
  input  wire [1:0] ch0, ch1, ch2, ch3,
  output logic [1:0] result
);
  always_comb begin
    case (sel)
      2'b00: result = ch0;
      2'b01: result = ch1;
      2'b10: result = ch2;
      2'b11: result = ch3;
    endcase
  end
endmodule

Pin Constraints

top = mux_4to1_wide

result[1:0] LD1 LD0
sel[1:0]    SW1 SW0
ch0[1:0]    SW3 SW2
ch1[1:0]    SW5 SW4
ch2[1:0]    SW7 SW6
ch3[1:0]    SW9 SW8

C++ Testbench Adaptasion

Multi-bit assignments in the C++ driver use binary literals to match the 2-bit width. The simulation loop structure is preserved.

  // Inside main() of test_wave.cpp
  initialize_simulation();
  design_instance->sel = 2'b00; design_instance->ch0 = 2'b11; design_instance->ch1 = 2'b00; design_instance->ch2 = 2'b10; design_instance->ch3 = 2'b01; advance_and_record();
  design_instance->sel = 2'b01; advance_and_record();
  design_instance->sel = 2'b10; advance_and_record();
  design_instance->sel = 2'b11; advance_and_record();
  shutdown_simulation();

Simulation and Deployment Commands

Compilation and execution follow a consistent sequence regardless of the specific multiplexer variant. Ensure the vsrc/top.v file contains the target module before running the toolchain.

# Step 1: Generate C++ simulation model from Verilog
verilator --cc vsrc/top.v --trace --exe csrc/test_wave.cpp

# Step 2: Compile the generated C++ code into an executable
make -C obj_dir -f Vtop.mk

# Step 3: Run simulation to produce VCD output
./obj_dir/Vtop

# Step 4: Visualize timing diagrams
gtkwave dump.vcd

For hardware deployment using the NVBoard framework, replace the wave testbench with the NVBoard variant during compilation:

verilator --cc vsrc/top.v --exe csrc/test_nvboard.cpp
make -C obj_dir -f Vtop.mk
./obj_dir/Vtop

Tags: Verilog multiplexer verilator nvboard waveform-simulation

Posted on Sun, 13 Sep 2026 16:43:04 +0000 by rdub