4.1 Verification and Testbenches
Verification is a crucial aspect of digital circuit design in Verilog. It involves confirming that your design functions correctly under various conditions. Testbenches are used to automate the verification process by applying stimulus to the design and checking the responses. In this section, we'll explore verification and testbench creation in Verilog.
-
Verification Process:
Verification is the process of ensuring that your digital circuit design operates correctly according to its specifications. It involves the following steps:
- Design Under Test (DUT): The circuit or module you want to verify.
- Testbench: A separate Verilog module that generates stimulus for the DUT and monitors its outputs.
- Simulation: Running the testbench and DUT through a simulation tool to observe behavior.
- Assertions: Adding assertions in your testbench to check if expected conditions are met.
- Coverage Analysis: Ensuring that you have tested various scenarios to achieve high test coverage.
-
Testbench Structure:
A typical testbench in Verilog consists of the following components:
- Module Instantiation: Instantiate the DUT and connect it to the testbench.
- Clock Generation: Generate clock signals if the DUT relies on a clock.
- Input Generation: Create input stimulus for the DUT.
- Output Monitoring: Capture and compare DUT outputs to expected values.
-
Example Testbench:
Below is a simple example of a testbench for a 2-to-1 multiplexer (MUX) designed to verify its functionality:
tb_mux_2to1.vmodule tb_mux_2to1; // Inputs and outputs for the testbench reg [1:0] A, B; reg select; wire Y; // Instantiate the MUX DUT mux_2to1 DUT ( .A(A), .B(B), .select(select), .Y(Y) ); // Clock generation (if needed) reg clk = 0; always begin #5 clk = ~clk; end // Testbench stimulus initial begin // Apply test cases A = 2'b00; B = 2'b11; select = 1'b0; #10 if (Y !== 1'b0) $display("Test 1 failed"); A = 2'b10; B = 2'b01; select = 1'b1; #10 if (Y !== 1'b1) $display("Test 2 failed"); // Add more test cases as needed // Terminate simulation $finish; end endmodule
-
Running Simulation:
To run the simulation with this testbench, you can use a Verilog simulation tool like Icarus Verilog or ModelSim. Here's an example command to simulate the testbench:
-
For Icarus Verilog:
cmdiverilog -o tb_mux_2to1 tb_mux_2to1.v mux_2to1.v
cmdvvp tb_mux_2to1
-
For ModelSim:
Compilecmdvlog mux_2to1.v tb_mux_2to1.v
cmdvsim -c tb_mux_2to1 -do "run -all; exit"
-
-
Analyzing Results:
The simulation tool will provide output indicating whether the testbench passed or failed for each test case. You can use this feedback to debug and refine your design.
Creating effective testbenches and thoroughly verifying your Verilog designs are essential steps in ensuring the correctness and reliability of your digital circuits.
4.2 Examples for Combinational Logic
Combinational logic circuits are fundamental components in digital design, performing operations based solely on the current input values. In this section, we'll explore practical Verilog examples for various combinational logic circuits to illustrate their implementation.
-
Basic Logic Gates:
AND Gate:
and_gate.vmodule and_gate ( input wire A, input wire B, output wire Y ); assign Y = A & B; endmodule
Testbench for AND Gate:
tb_and_gate.vmodule tb_and_gate; reg a; reg b; wire y; // Instantiate the AND gate module and_gate and_gate_inst ( .a(a), .b(b), .y(y) ); // Test scenario initial begin // Initialize inputs a = 0; b = 0; // Test case 1: Both inputs are 0 #10 assert(y === 0) else $display("Test case 1 failed"); // Test case 2: Input a is 1, b is 0 a = 1; #10 assert(y === 0) else $display("Test case 2 failed"); // Test case 3: Both inputs are 1 b = 1; #10 assert(y === 1) else $display("Test case 3 failed"); // End simulation $finish; end endmodule
OR Gate:
or_gate.vmodule or_gate ( input wire a, input wire b, output wire y ); assign y = a | b; // OR operation endmodule
Testbench for OR Gate:
tb_or_gate.vmodule tb_or_gate; reg a; reg b; wire y; // Instantiate the OR gate module or_gate or_gate_inst ( .a(a), .b(b), .y(y) ); // Test scenario initial begin // Initialize inputs a = 0; b = 0; // Test case 1: Both inputs are 0 #10 assert(y === 0) else $display("Test case 1 failed"); // Test case 2: Input a is 1, b is 0 a = 1; #10 assert(y === 1) else $display("Test case 2 failed"); // Test case 3: Both inputs are 1 b = 1; #10 assert(y === 1) else $display("Test case 3 failed"); // End simulation $finish; end endmodule
NOT Gate:
not_gate.vmodule not_gate ( input wire a, output wire y ); assign y = ~a; // NOT operation endmodule
Testbench for NOT Gate:
or_gate.vmodule tb_not_gate; reg a; wire y; // Instantiate the NOT gate module not_gate not_gate_inst ( .a(a), .y(y) ); // Test scenario initial begin // Initialize input a = 0; // Test case 1: Input is 0 #10 assert(y === 1) else $display("Test case 1 failed"); // Test case 2: Input is 1 a = 1; #10 assert(y === 0) else $display("Test case 2 failed"); // End simulation $finish; end endmodule
XOR Gate:
xor_gate.vmodule xor_gate ( input wire a, input wire b, output wire y ); assign y = a ^ b; // XOR operation endmodule
Testbench for XOR Gate:
tb_xor_gate.vmodule tb_xor_gate; reg a; reg b; wire y; // Instantiate the XOR gate module xor_gate xor_gate_inst ( .a(a), .b(b), .y(y) ); // Test scenario initial begin // Initialize inputs a = 0; b = 0; // Test case 1: Both inputs are 0 #10 assert(y === 0) else $display("Test case 1 failed"); // Test case 2: Input a is 1, b is 0 a = 1; #10 assert(y === 1) else $display("Test case 2 failed"); // Test case 3: Both inputs are 1 b = 1; #10 assert(y === 0) else $display("Test case 3 failed"); // End simulation $finish; end endmodule
-
Multiplexers (MUX):
2-to-1 MUX:
mux_2to1.vmodule mux_2to1 ( input wire a, // Input A input wire b, // Input B input wire sel, // Selection signal output wire y // Output ); assign y = (sel) ? b : a; // MUX operation endmodule
Testbench for 2-to-1 MUX:
tb_mux_2to1.vmodule tb_mux_2to1; reg a; reg b; reg sel; wire y; // Instantiate the 2-to-1 MUX module mux_2to1 mux ( .a(a), .b(b), .sel(sel), .y(y) ); // Test scenario initial begin // Initialize signals a = 0; b = 1; sel = 0; // Test case 1: Select A (sel=0) #10 assert(y === 0) else $display("Test case 1 failed"); // Test case 2: Select B (sel=1) sel = 1; #10 assert(y === 1) else $display("Test case 2 failed"); // End simulation $finish; end endmodule
4-to-1 MUX:
mux_4to1.vmodule mux_4to1 ( input wire [3:0] a, // 4-bit Input A input wire [3:0] b, // 4-bit Input B input wire [1:0] sel, // 2-bit Selection signal output wire [3:0] y // 4-bit Output ); assign y = (sel == 2'b00) ? a : (sel == 2'b01) ? b : (sel == 2'b10) ? 4'b0 : // Default output (sel == 2'b11) ? 4'bz : // High-Z output 4'bx; // Invalid state endmodule
Testbench for 4-to-1 MUX:
tb_mux_4to1.vmodule tb_mux_4to1; reg [3:0] a; reg [3:0] b; reg [1:0] sel; wire [3:0] y; // Instantiate the 4-to-1 MUX module mux_4to1 mux ( .a(a), .b(b), .sel(sel), .y(y) ); // Test scenario initial begin // Initialize signals a = 4'b1101; b = 4'b0010; sel = 2'b00; // Test case 1: Select A (sel=00) #10 assert(y === 4'b1101) else $display("Test case 1 failed"); // Test case 2: Select B (sel=01) sel = 2'b01; #10 assert(y === 4'b0010) else $display("Test case 2 failed"); // Test case 3: Default output (sel=10) sel = 2'b10; #10 assert(y === 4'b0000) else $display("Test case 3 failed"); // Test case 4: High-Z output (sel=11) sel = 2'b11; #10 assert(y === 4'bz) else $display("Test case 4 failed"); // End simulation $finish; end endmodule
These Verilog code examples and testbenches demonstrate the functionality of 2-to-1 and 4-to-1 multiplexers, along with various test cases to verify their operation. You can use a Verilog simulator to run these testbenches and observe the results.
-
DeMUX :
1-to-2 Demultiplexer (DeMUX):
demux_1to2.vmodule demux_1to2 ( input wire a, // Input input wire select, // Selection control output wire y0, // Output 0 output wire y1 // Output 1 ); assign y0 = (select) ? 1'b0 : a; // Output 0 when select is 1, else input a assign y1 = (select) ? a : 1'b0; // Output 1 when select is 1, else 0 endmodule
Testbench for 1-to-2 Demultiplexer (DeMUX):
tb_demux_1to2.vmodule tb_demux_1to2; reg a; reg select; wire y0; wire y1; // Instantiate the 1-to-2 Demultiplexer module demux_1to2 demux ( .a(a), .select(select), .y0(y0), .y1(y1) ); // Test scenario initial begin // Initialize inputs a = 0; select = 0; // Test case 1: Select is 0, input is 0 #10 assert(y0 === 0 && y1 === 0) else $display("Test case 1 failed"); // Test case 2: Select is 0, input is 1 a = 1; #10 assert(y0 === 1 && y1 === 0) else $display("Test case 2 failed"); // Test case 3: Select is 1, input is 0 select = 1; a = 0; #10 assert(y0 === 0 && y1 === 0) else $display("Test case 3 failed"); // Test case 4: Select is 1, input is 1 a = 1; #10 assert(y0 === 0 && y1 === 1) else $display("Test case 4 failed"); // End simulation $finish; end endmodule
1-to-4 Demultiplexer (DeMUX):
demux_1to4.vmodule demux_1to4 ( input wire a, // Input input wire [1:0] select, // 2-bit selection control output wire y0, // Output 0 output wire y1, // Output 1 output wire y2, // Output 2 output wire y3 // Output 3 ); assign y0 = (select == 2'b00) ? a : 1'b0; // Output 0 when select is 00, else 0 assign y1 = (select == 2'b01) ? a : 1'b0; // Output 1 when select is 01, else 0 assign y2 = (select == 2'b10) ? a : 1'b0; // Output 2 when select is 10, else 0 assign y3 = (select == 2'b11) ? a : 1'b0; // Output 3 when select is 11, else 0 endmodule
Testbench for 1-to-4 Demultiplexer (DeMUX):
demux_1to4.vmodule tb_demux_1to4; reg a; reg [1:0] select; wire y0; wire y1; wire y2; wire y3; // Instantiate the 1-to-4 Demultiplexer module demux_1to4 demux ( .a(a), .select(select), .y0(y0), .y1(y1), .y2(y2), .y3(y3) ); // Test scenario initial begin // Initialize inputs a = 0; select = 2'b00; // Test case 1: Select is 00, input is 0 #10 assert(y0 === 0 && y1 === 0 && y2 === 0 && y3 === 0) else $display("Test case 1 failed"); // Test case 2: Select is 00, input is 1 a = 1; #10 assert(y0 === 1 && y1 === 0 && y2 === 0 && y3 === 0) else $display("Test case 2 failed"); // Test case 3: Select is 01, input is 0 select = 2'b01; a = 0; #10 assert(y0 === 0 && y1 === 0 && y2 === 0 && y3 === 0) else $display("Test case 3 failed"); // Test case 4: Select is 01, input is 1 a = 1; #10 assert(y0 === 0 && y1 === 1 && y2 === 0 && y3 === 0) else $display("Test case 4 failed"); // End simulation $finish; end endmodule
These Verilog code examples and testbenches demonstrate the functionality of 1-to-2 and 1-to-4 Demultiplexers (DeMUX) along with various test cases to verify their operation. You can use a Verilog simulator to run these testbenches and observe the results.
-
Decoders:
3-to-8 Decoder:
decoder_3to8_1.vmodule decoder_3to8_1 ( input wire [2:0] a, // 3-bit Input output wire [7:0] y // 8-bit Output ); assign y = (a == 3'b000) ? 8'b00000001 : (a == 3'b001) ? 8'b00000010 : (a == 3'b010) ? 8'b00000100 : (a == 3'b011) ? 8'b00001000 : (a == 3'b100) ? 8'b00010000 : (a == 3'b101) ? 8'b00100000 : (a == 3'b110) ? 8'b01000000 : (a == 3'b111) ? 8'b10000000 : 8'b00000000; // Default output (invalid input) endmodule
Testbench for 3-to-8 Decoder:
tb_decoder_3to8.vmodule tb_decoder_3to8; reg [2:0] a; wire [7:0] y; // Instantiate the 3-to-8 Decoder module decoder_3to8 decoder ( .a(a), .y(y) ); // Test scenario initial begin // Initialize signals a = 3'b000; // Test case 1: Input = 000 #10 assert(y === 8'b00000001) else $display("Test case 1 failed"); // Test case 2: Input = 110 a = 3'b110; #10 assert(y === 8'b01000000) else $display("Test case 2 failed"); // Test case 3: Default output (invalid input) a = 3'b101; #10 assert(y === 8'b00000000) else $display("Test case 3 failed"); // End simulation $finish; end endmodule
2-to-4 Decoder:
decoder_2to4.vmodule decoder_2to4 ( input wire [1:0] a, // 2-bit Input output wire [3:0] y // 4-bit Output ); assign y = (a == 2'b00) ? 4'b0001 : (a == 2'b01) ? 4'b0010 : (a == 2'b10) ? 4'b0100 : (a == 2'b11) ? 4'b1000 : 4'b0000; // Default output (invalid input) endmodule
Testbench for 2-to-4 Decoder:
tb_decoder_2to4.vmodule tb_decoder_2to4; reg [1:0] a; wire [3:0] y; // Instantiate the 2-to-4 Decoder module decoder_2to4 decoder ( .a(a), .y(y) ); // Test scenario initial begin // Initialize signals a = 2'b01; // Test case 1: Input = 01 #10 assert(y === 4'b0010) else $display("Test case 1 failed"); // Test case 2: Input = 10 a = 2'b10; #10 assert(y === 4'b0100) else $display("Test case 2 failed"); // Test case 3: Default output (invalid input) a = 2'b11; #10 assert(y === 4'b0000) else $display("Test case 3 failed"); // End simulation $finish; end endmodule
These Verilog code examples and testbenches demonstrate the functionality of 3-to-8 and 2-to-4 decoders, along with various test cases to verify their operation. You can use a Verilog simulator to run these testbenches and observe the results.
-
Encoders
2-to-4 Priority Encoder:
priority_encoder_2to4.vmodule priority_encoder_2to4 ( input wire [1:0] a, // 2-bit Input output wire [3:0] y // 4-bit Output ); assign y[0] = (a[0] == 1'b1) ? 1'b1 : 1'b0; assign y[1] = (a[1] == 1'b1) ? 1'b1 : (a[0] == 1'b1) ? 1'b0 : 1'b0; assign y[2] = (a[1] == 1'b1 && a[0] == 1'b1) ? 1'b1 : 1'b0; assign y[3] = (a[1] == 1'b0 && a[0] == 1'b0) ? 1'b1 : 1'b0; endmodule
Testbench for 2-to-4 Priority Encoder:
tb_priority_encoder_2to4.vmodule tb_priority_encoder_2to4; reg [1:0] a; wire [3:0] y; // Instantiate the 2-to-4 Priority Encoder module priority_encoder_2to4 encoder ( .a(a), .y(y) ); // Test scenario initial begin // Initialize inputs a = 2'b00; // Test case 1: Input is 00 #10 assert(y === 4'b1000) else $display("Test case 1 failed"); // Test case 2: Input is 01 a = 2'b01; #10 assert(y === 4'b0100) else $display("Test case 2 failed"); // Test case 3: Input is 10 a = 2'b10; #10 assert(y === 4'b0010) else $display("Test case 3 failed"); // Test case 4: Input is 11 a = 2'b11; #10 assert(y === 4'b0001) else $display("Test case 4 failed"); // End simulation $finish; end endmodule
4-to-2 Binary Encoder:
binary_encoder_4to2.vmodule binary_encoder_4to2 ( input wire [3:0] a, // 4-bit Input output wire [1:0] y // 2-bit Output ); assign y = (a != 4'b0000) ? {1'b1, 1'b0} : (a != 4'b0001) ? {1'b0, 1'b1} : (a != 4'b0010) ? {1'b0, 1'b1} : (a != 4'b0100) ? {1'b0, 1'b1} : {1'b0, 1'b0}; endmodule
Testbench for 4-to-2 Binary Encoder:
tb_binary_encoder_4to2.vmodule tb_binary_encoder_4to2; reg [3:0] a; wire [1:0] y; // Instantiate the 4-to-2 Binary Encoder module binary_encoder_4to2 encoder ( .a(a), .y(y) ); // Test scenario initial begin // Initialize inputs a = 4'b0000; // Test case 1: Input is 0000 #10 assert(y === 2'b00) else $display("Test case 1 failed"); // Test case 2: Input is 0001 a = 4'b0001; #10 assert(y === 2'b01) else $display("Test case 2 failed"); // Test case 3: Input is 0010 a = 4'b0010; #10 assert(y === 2'b10) else $display("Test case 3 failed"); // Test case 4: Input is 0100 a = 4'b0100; #10 assert(y === 2'b11) else $display("Test case 4 failed"); // End simulation $finish; end endmodule
-
Arithmetic Logic Units (ALU):
alu_4bit.vmodule alu_4bit ( input [3:0] A, input [3:0] B, input [2:0] opcode, output [3:0] Y ); always @(*) begin case (opcode) 3'b000: Y = A + B; // Add 3'b001: Y = A - B; // Subtract 3'b010: Y = A & B; // AND 3'b011: Y = A | B; // OR // Add more operations as needed default: Y = 4'bxxxx; // Output 'x' for unsupported opcode endcase end endmodule
These Verilog examples cover various combinational logic circuits, from basic gates to more complex components like multiplexers, decoders, and arithmetic logic units (ALUs).
4.3 Examples for Synchronous Logic
-
Flip-Flops (FFs):
D flip-flop activated at positive edge of clock (posedge) :
d_flip_flop.vmodule d_flip_flop ( input wire clk, // Clock input input wire reset, // Reset input (asynchronous) input wire d, // Data input output wire q // Output ); always @(posedge clk or posedge reset) begin if (reset) q <= 1'b0; // Reset the flip-flop asynchronously else q <= d; // Store the data input on the rising clock edge end endmodule
Testbench for D FF :
tb_d_flip_flop.vmodule tb_d_flip_flop; reg clk; reg reset; reg d; wire q; // Instantiate the D Flip-Flop module d_flip_flop dflop ( .clk(clk), .reset(reset), .d(d), .q(q) ); // Clock generation always begin #5 clk = ~clk; end // Test scenario initial begin // Initialize signals clk = 0; reset = 0; d = 0; // Apply reset reset = 1; #10 reset = 0; // Test case 1: Set D to 1 d = 1; #10 assert(q === 1) else $display("Test case 1 failed"); // Test case 2: Toggle D while clock is high d = 0; #5 d = 1; #5 d = 0; #5 d = 1; #10 assert(q === 1) else $display("Test case 2 failed"); // Test case 3: Set D to 0 d = 0; #10 assert(q === 0) else $display("Test case 3 failed"); // End simulation $finish; end endmodule
JK flip-flop activated at positive edge of clock (posedge) :
jk_flip_flop.vmodule jk_flip_flop ( input wire clk, // Clock input input wire reset, // Reset input (asynchronous) input wire j, // J input input wire k, // K input output wire q, // Output output wire q_bar // Complement of Q ); reg q_next; // Next state of Q always @(posedge clk or posedge reset) begin if (reset) q_next <= 1'b0; // Reset the flip-flop asynchronously else q_next <= (j & q_bar) | (k & q); // JK flip-flop behavior end assign q = q_next; assign q_bar = ~q_next; endmodule
Testbench for JK FF :
tb_jk_flip_flop.vmodule tb_jk_flip_flop; reg clk; reg reset; reg j; reg k; wire q; wire q_bar; // Instantiate the JK Flip-Flop module jk_flip_flop jkflop ( .clk(clk), .reset(reset), .j(j), .k(k), .q(q), .q_bar(q_bar) ); // Clock generation always begin #5 clk = ~clk; end // Test scenario initial begin // Initialize signals clk = 0; reset = 0; j = 0; k = 0; // Apply reset reset = 1; #10 reset = 0; // Test case 1: J=1, K=0 (Toggle) j = 1; k = 0; #10 assert(q === 1 && q_bar === 0) else $display("Test case 1 failed"); // Test case 2: J=0, K=1 (Toggle) j = 0; k = 1; #10 assert(q === 0 && q_bar === 1) else $display("Test case 2 failed"); // Test case 3: J=1, K=1 (No change) j = 1; k = 1; #10 assert(q === 1 && q_bar === 0) else $display("Test case 3 failed"); // End simulation $finish; end endmodule
T flip-flop at positive edge of clock (posedge) :
t_flip_flop.vmodule t_flip_flop ( input wire clk, // Clock input input wire reset, // Reset input (asynchronous) input wire t, // Toggle input output wire q, // Output output wire q_bar // Complement of Q ); reg q_next; // Next state of Q always @(posedge clk or posedge reset) begin if (reset) q_next <= 1'b0; // Reset the flip-flop asynchronously else if (t) q_next <= ~q_next; // Toggle the flip-flop state on the rising clock edge end assign q = q_next; assign q_bar = ~q_next; endmodule
Testbench for T FF :
tb_t_flip_flop.vmodule tb_t_flip_flop; reg clk; reg reset; reg t; wire q; wire q_bar; // Instantiate the T Flip-Flop module t_flip_flop tflop ( .clk(clk), .reset(reset), .t(t), .q(q), .q_bar(q_bar) ); // Clock generation always begin #5 clk = ~clk; end // Test scenario initial begin // Initialize signals clk = 0; reset = 0; t = 0; // Apply reset reset = 1; #10 reset = 0; // Test case 1: Toggle T input t = 1; #10 assert(q === 1 && q_bar === 0) else $display("Test case 1 failed"); // Test case 2: Toggle T input again t = 0; #5 t = 1; #10 assert(q === 0 && q_bar === 1) else $display("Test case 2 failed"); // Test case 3: No change (T=0) t = 0; #10 assert(q === 0 && q_bar === 1) else $display("Test case 3 failed"); // End simulation $finish; end endmodule
These Verilog examples cover various synchronous logic FFs, including D FFs , JK FFs , T FFs with testbenches to simulate them.
-
Counters
3-bit Up Counter:
up_counter_3bit.vmodule up_counter_3bit ( input wire clk, // Clock input input wire reset, // Reset input (asynchronous) output wire [2:0] y // 3-bit Output ); reg [2:0] count; // Counter register always @(posedge clk or posedge reset) begin if (reset) count <= 3'b000; // Reset the counter asynchronously else if (count == 3'b111) count <= 3'b000; // Reset when reaching maximum else count <= count + 1; // Increment on rising clock edge end assign y = count; endmodule
Testbench for 3-bit Up Counter:
tb_up_counter_3bit.vmodule tb_up_counter_3bit; reg clk; reg reset; wire [2:0] y; // Instantiate the 3-bit Up Counter module up_counter_3bit counter ( .clk(clk), .reset(reset), .y(y) ); // Clock generation always begin #5 clk = ~clk; end // Test scenario initial begin // Initialize signals clk = 0; reset = 0; // Apply reset reset = 1; #10 reset = 0; // Test case 1: Count from 0 to 7 #20 assert(y === 3'b000) else $display("Test case 1 failed"); #10 assert(y === 3'b001) else $display("Test case 2 failed"); #10 assert(y === 3'b010) else $display("Test case 3 failed"); #10 assert(y === 3'b011) else $display("Test case 4 failed"); #10 assert(y === 3'b100) else $display("Test case 5 failed"); #10 assert(y === 3'b101) else $display("Test case 6 failed"); #10 assert(y === 3'b110) else $display("Test case 7 failed"); #10 assert(y === 3'b111) else $display("Test case 8 failed"); // End simulation $finish; end endmodule
4-bit Ring Counter:
ring_counter_4bit.vmodule ring_counter_4bit ( input wire clk, // Clock input input wire reset, // Reset input (asynchronous) output wire [3:0] y // 4-bit Output ); reg [3:0] count; // Counter register always @(posedge clk or posedge reset) begin if (reset) count <= 4'b0000; // Reset the counter asynchronously else if (count == 4'b1111) count <= 4'b0001; // Wrap around to 0001 when reaching maximum else count <= count + 1; // Increment on rising clock edge end assign y = count; endmodule
Testbench for 4-bit Ring Counter:
tb_ring_counter_4bit.vmodule tb_ring_counter_4bit; reg clk; reg reset; wire [3:0] y; // Instantiate the 4-bit Ring Counter module ring_counter_4bit counter ( .clk(clk), .reset(reset), .y(y) ); // Clock generation always begin #5 clk = ~clk; end // Test scenario initial begin // Initialize signals clk = 0; reset = 0; // Apply reset reset = 1; #10 reset = 0; // Test case 1: Count in a ring from 0000 to 1111 #10 assert(y === 4'b0000) else $display("Test case 1 failed"); #10 assert(y === 4'b0001) else $display("Test case 2 failed"); #10 assert(y === 4'b0010) else $display("Test case 3 failed"); #10 assert(y === 4'b0100) else $display("Test case 4 failed"); #10 assert(y === 4'b1000) else $display("Test case 5 failed"); #10 assert(y === 4'b1100) else $display("Test case 6 failed"); #10 assert(y === 4'b1110) else $display("Test case 7 failed"); #10 assert(y === 4'b1111) else $display("Test case 8 failed"); // End simulation $finish; end endmodule
These Verilog code examples and testbenches demonstrate the functionality of a 3-bit Up Counter and a 4-bit Ring Counter, along with various test cases to verify their operation.
-
Memories
4x4 SRAM (Static Random Access Memory):
sram_4x4.vmodule sram_4x4 ( input wire [1:0] addr, // 2-bit Address input wire write_en, // Write Enable input wire [3:0] data_in, // 4-bit Data Input output wire [3:0] data_out // 4-bit Data Output ); reg [3:0] memory [3:0]; // 4x4 memory array always @(addr, write_en, data_in) begin if (write_en) memory[addr] <= data_in; // Write data to the selected address end assign data_out = memory[addr]; // Read data from the selected address endmodule
Testbench for 4x4 SRAM:
tb_sram_4x4.vmodule tb_sram_4x4; reg [1:0] addr; reg write_en; reg [3:0] data_in; wire [3:0] data_out; // Instantiate the 4x4 SRAM module sram_4x4 sram ( .addr(addr), .write_en(write_en), .data_in(data_in), .data_out(data_out) ); // Test scenario initial begin // Initialize signals addr = 2'b00; write_en = 0; data_in = 4'b0000; // Write data to address 00 write_en = 1; data_in = 4'b1100; #10 write_en = 0; // Read data from address 00 addr = 2'b00; #10 assert(data_out === 4'b1100) else $display("Test case 1 failed"); // Write data to address 01 write_en = 1; data_in = 4'b0011; #10 write_en = 0; // Read data from address 01 addr = 2'b01; #10 assert(data_out === 4'b0011) else $display("Test case 2 failed"); // End simulation $finish; end endmodule
2x2 ROM (Read-Only Memory):
rom_2x2.vmodule rom_2x2 ( input wire [1:0] addr, // 2-bit Address output wire [3:0] data // 4-bit Data Output ); // Define ROM contents reg [3:0] memory [3:0]; initial begin memory[2'b00] = 4'b1100; memory[2'b01] = 4'b0011; memory[2'b10] = 4'b1010; memory[2'b11] = 4'b0101; end assign data = memory[addr]; // Read data based on the address endmodule
Testbench for 2x2 ROM:
rom_2x2.vmodule tb_rom_2x2; reg [1:0] addr; wire [3:0] data; // Instantiate the 2x2 ROM module rom_2x2 rom ( .addr(addr), .data(data) ); // Test scenario initial begin // Initialize signals addr = 2'b00; // Read data from address 00 #10 assert(data === 4'b1100) else $display("Test case 1 failed"); // Change address to 01 addr = 2'b01; #10 assert(data === 4'b0011) else $display("Test case 2 failed"); // Change address to 10 addr = 2'b10; #10 assert(data === 4'b1010) else $display("Test case 3 failed"); // Change address to 11 addr = 2'b11; #10 assert(data === 4'b0101) else $display("Test case 4 failed"); // End simulation $finish; end endmodule
These Verilog code examples and testbenches demonstrate the functionality of a 4x4 SRAM and a 2x2 ROM, along with various test cases to verify their operation. You can use a Verilog simulator to run these testbenches and observe the results.
4x4 DRAM :
rom_2x2.vmodule dram_4x4 ( input wire clk, // Clock input input wire rst_n, // Reset input (active low) input wire write_en, // Write enable input wire [1:0] addr, // 2-bit Address input wire [3:0] data_in, // 4-bit Data Input output wire [3:0] data_out // 4-bit Data Output ); reg [3:0] memory [3:0]; // 4x4 memory array reg row_addr; // Row address register reg col_addr; // Column address register always @(posedge clk or negedge rst_n) begin if (!rst_n) begin row_addr <= 0; col_addr <= 0; end else if (write_en) begin // Write data to the selected address memory[row_addr][col_addr] <= data_in; end else begin // Read data from the selected address data_out <= memory[row_addr][col_addr]; end end always @(posedge clk) begin if (write_en) begin // Update row and column addresses on a write operation row_addr <= addr[1:0]; col_addr <= addr[1:0]; end end endmodule
This simplified DRAM module includes a 4x4 memory array and basic row and column address management. It responds to read and write operations based on the clock and reset signals. However, it doesn't implement complex DRAM features like refresh cycles or page management, which are crucial in real-world DRAM designs.
Here's a basic testbench for the simplified DRAM module:
tb_dram_4x4.vmodule tb_dram_4x4; reg clk; reg rst_n; reg write_en; reg [1:0] addr; reg [3:0] data_in; wire [3:0] data_out; // Instantiate the 4x4 DRAM module dram_4x4 dram ( .clk(clk), .rst_n(rst_n), .write_en(write_en), .addr(addr), .data_in(data_in), .data_out(data_out) ); // Clock generation always begin #5 clk = ~clk; end // Test scenario initial begin // Initialize signals clk = 0; rst_n = 0; write_en = 0; addr = 2'b00; data_in = 4'b0000; // Release reset rst_n = 1; // Write data to address 00 write_en = 1; data_in = 4'b1100; addr = 2'b00; #10 write_en = 0; // Read data from address 00 addr = 2'b00; write_en = 0; #10 assert(data_out === 4'b1100) else $display("Test case 1 failed"); // End simulation $finish; end endmodule
This testbench provides a basic scenario where data is written to and read from the DRAM module. In a real DRAM design, you would need to consider complex timing requirements, refresh cycles, and address multiplexing. This example serves as a starting point for understanding the basic principles of a DRAM model.