// DESCRIPTION: Verilator: Verilog Test module // // This file ONLY is placed into the Public Domain, for any use, // without warranty, 2008 by Lane Brooks. // // This implements a 4096:1 mux via two stages of 64:1 muxing. // change these two parameters to see the speed differences //`define DATA_WIDTH 12 //`define MUX2_SIZE 32 `define DATA_WIDTH 2 `define MUX2_SIZE 8 // if you change these, then the testbench will break `define ADDR_WIDTH 12 `define MUX1_SIZE 64 // Total of DATA_WIDTH*MUX2_SIZE*(MUX1_SIZE+1) instantiations of mux64 module t (/*AUTOARG*/ // Inputs clk ); input clk; /*AUTOWIRE*/ // Beginning of automatic wires (for undeclared instantiated-module outputs) wire [`DATA_WIDTH-1:0] datao; // From mux4096 of mux4096.v // End of automatics reg [`DATA_WIDTH*`MUX1_SIZE*`MUX2_SIZE-1:0] datai; reg [`ADDR_WIDTH-1:0] addr; // Mux: takes in addr and datai and outputs datao mux4096 mux4096 (/*AUTOINST*/ // Outputs .datao (datao[`DATA_WIDTH-1:0]), // Inputs .datai (datai[`DATA_WIDTH*`MUX1_SIZE*`MUX2_SIZE-1:0]), .addr (addr[`ADDR_WIDTH-1:0])); // calculate what the answer should be from datai. This is bit // tricky given the way datai gets sliced. datai is in bit // planes where all the LSBs are contiguous and then the next bit. reg [`DATA_WIDTH-1:0] datao_check; integer j; always @(datai or addr) begin for(j=0;j<`DATA_WIDTH;j=j+1) begin /* verilator lint_off WIDTH */ datao_check[j] = datai >> ((`MUX1_SIZE*`MUX2_SIZE*j)+addr); /* verilator lint_on WIDTH */ end end // Run the test loop. This just increments the address integer i, result; always @ (posedge clk) begin // initial the input data with random values if (addr == 0) begin result = 1; datai = 0; for(i=0; i<`MUX1_SIZE*`MUX2_SIZE; i=i+1) begin /* verilator lint_off WIDTH */ datai = (datai << `DATA_WIDTH) | ($random & {`DATA_WIDTH{1'b1}}); /* verilator lint_on WIDTH */ end end addr <= addr + 1; if (datao_check != datao) begin result = 0; $stop; end $write("Addr=%d datao_check=%d datao=%d\n", addr, datao_check, datao); // only run the first 10 addresses for now if (addr > 10) begin $write("*-* All Finished *-*\n"); $finish; end end endmodule module mux4096 (input [`DATA_WIDTH*`MUX1_SIZE*`MUX2_SIZE-1:0] datai, input [`ADDR_WIDTH-1:0] addr, output [`DATA_WIDTH-1:0] datao ); // DATA_WIDTH instantiations of mux4096_1bit mux4096_1bit mux4096_1bit[`DATA_WIDTH-1:0] (.addr(addr), .datai(datai), .datao(datao) ); endmodule module mux4096_1bit (input [`MUX1_SIZE*`MUX2_SIZE-1:0] datai, input [`ADDR_WIDTH-1:0] addr, output datao ); // address decoding wire [3:0] A = (4'b1) << addr[1:0]; wire [3:0] B = (4'b1) << addr[3:2]; wire [3:0] C = (4'b1) << addr[5:4]; wire [3:0] D = (4'b1) << addr[7:6]; wire [3:0] E = (4'b1) << addr[9:8]; wire [3:0] F = (4'b1) << addr[11:10]; wire [`MUX2_SIZE-1:0] data0; // DATA_WIDTH*(MUX2_SIZE)*MUX1_SIZE instantiations of mux64 // first stage of 64:1 muxing mux64 #(.MUX_SIZE(`MUX1_SIZE)) mux1[`MUX2_SIZE-1:0] (.A(A), .B(B), .C(C), .datai(datai), .datao(data0)); // DATA_WIDTH*MUX2_SIZE instantiations of mux64 // second stage of 64:1 muxing mux64 #(.MUX_SIZE(`MUX2_SIZE)) mux2 (.A(D), .B(E), .C(F), .datai(data0), .datao(datao)); endmodule module mux64 #(parameter MUX_SIZE=64) (input [3:0] A, input [3:0] B, input [3:0] C, input [MUX_SIZE-1:0] datai, output datao ); wire [63:0] colSelA = { 16{ A[3:0] }}; wire [63:0] colSelB = { 4{ {4{B[3]}}, {4{B[2]}}, {4{B[1]}}, {4{B[0]}}}}; wire [63:0] colSelC = { {16{C[3]}}, {16{C[2]}}, {16{C[1]}}, {16{C[0]}}}; wire [MUX_SIZE-1:0] data_bus; // Note each of these becomes a separate wire. //.colSelA(colSelA[MUX_SIZE-1:0]), //.colSelB(colSelB[MUX_SIZE-1:0]), //.colSelC(colSelC[MUX_SIZE-1:0]), drv drv[MUX_SIZE-1:0] (.colSelA(colSelA[MUX_SIZE-1:0]), .colSelB(colSelB[MUX_SIZE-1:0]), .colSelC(colSelC[MUX_SIZE-1:0]), .datai(datai), .datao(data_bus) ); assign datao = |data_bus; endmodule module drv (input colSelA, input colSelB, input colSelC, input datai, output datao ); assign datao = colSelC & colSelB & colSelA & datai; endmodule