aboutsummaryrefslogblamecommitdiff
path: root/bench/tb_mmm_x8_dual.v
blob: aa25900af8b2e07c0f558d67c47d06e37bace838 (plain) (tree)






































































































































































































































































































































                                                                                                           
`timescale 1ns / 1ps

module tb_mmm_x8_dual;


    //
    // Headers
    //
    `include "../rtl/modexpng_parameters.vh"
    `include "../rtl/modexpng_parameters_x8.vh"
    

    //
    // Settings
    //
    localparam INDEX_WIDTH = 6;
    
	wire [INDEX_WIDTH-1:0] index_last = 31;  // 512 bits
    
	
    //
    // Clock
    //
    `define CLK_FREQUENCY_MHZ   100.0
    `define CLK_PERIOD_NS       (1000.0 / `CLK_FREQUENCY_MHZ)
    `define CLK_PERIOD_HALF_NS  (0.5 * `CLK_PERIOD_NS)
    
	reg clk = 1'b0;

    always begin
        #`CLK_PERIOD_HALF_NS clk = 1'b1;
        #`CLK_PERIOD_HALF_NS clk = 1'b0;
    end    

    
    //
    // Reset
    //
    reg  rst   = 1'b1;
	wire rst_n = ~rst;
    
    
    //
    // Control
    //
    reg  ena = 1'b0;
    wire rdy;

    reg  mode;
    reg  transfer;


    //
    // Interface
    //

    
    //
    // Interface - Data Buses
    //
	wire [NUM_MULTS*WORD_WIDTH-1:0] x_din;
	wire [NUM_MULTS*WORD_WIDTH-1:0] y_din;
	wire [NUM_MULTS*WORD_WIDTH-1:0] x_dout;
	wire [NUM_MULTS*WORD_WIDTH-1:0] y_dout;

    
    //
    // Interface - Address Buses
    //
	wire [INDEX_WIDTH-4:0] x_din_addr;
	wire [INDEX_WIDTH-4:0] y_din_addr;
	wire [INDEX_WIDTH-4:0] x_dout_addr;
	wire [INDEX_WIDTH-4:0] y_dout_addr;

    
    //
    // Interface - Enable Buses
    //
	wire [        1-1:0] x_din_ena;
	wire [        1-1:0] y_din_ena;
	wire [        1-1:0] x_din_reg_ena;
	wire [        1-1:0] y_din_reg_ena;
    wire [NUM_MULTS-1:0] x_dout_ena;
    wire [NUM_MULTS-1:0] y_dout_ena;
    
    
    //
    // Interface - Bank Buses
    //
    wire [3-1:0] x_din_bank;
    wire [3-1:0] y_din_bank;
    wire [3-1:0] x_dout_bank;
    wire [3-1:0] y_dout_bank;


    //
    // Operands
    //
    reg [WORD_WIDTH-1:0] T1[0:2**INDEX_WIDTH-1];
    reg [WORD_WIDTH-1:0] T2[0:2**INDEX_WIDTH-1];
    reg [WORD_WIDTH-1:0] N[0:2**INDEX_WIDTH-1];
    reg [WORD_WIDTH-1:0] N_COEFF[0:2**INDEX_WIDTH];

    
    //
    // Memories
    //
    genvar z;
    generate for (z=0; z<NUM_MULTS; z=z+1)
        //
        begin : gen_z_mem
            //
            modexpng_mem /*bram_1wo_1ro_readfirst_ce*/ #
            (
                .MEM_WIDTH(WORD_WIDTH),
                .MEM_ADDR_BITS(INDEX_WIDTH) // - clog2(NUM_MULTS) + clog2(NUM_BANKS)
            )
            gen_z_mem_x
            (
                .clk        (clk),

                .a_addr     ({x_dout_bank, x_dout_addr}),
                .a_en       (x_dout_ena[z]),
                .a_wr       (x_dout_ena[z]),
                .a_in       (x_dout[z*WORD_WIDTH+:WORD_WIDTH]),
                .a_out      (), // unused

                .b_addr     ({x_din_bank, x_din_addr}),
                .b_en       (x_din_ena),
                .b_reg_en   (x_din_reg_ena),
                .b_out      (x_din[z*WORD_WIDTH+:WORD_WIDTH])
            );
            //
            modexpng_mem /*bram_1wo_1ro_readfirst_ce*/ #
            (
                .MEM_WIDTH(WORD_WIDTH),
                .MEM_ADDR_BITS(INDEX_WIDTH) // - clog2(NUM_MULTS) + clog2(NUM_BANKS)
            )
            gen_z_mem_y
            (
                .clk        (clk),

                .a_addr     ({y_dout_bank, y_dout_addr}),
                .a_en       (y_dout_ena[z]),
                .a_wr       (y_dout_ena[z]),
                .a_in       (y_dout[z*WORD_WIDTH+:WORD_WIDTH]),
                .a_out      (), // unused

                .b_addr     ({y_din_bank, y_din_addr}),
                .b_en       (y_din_ena),
                .b_reg_en   (y_din_reg_ena),
                .b_out      (y_din[z*WORD_WIDTH+:WORD_WIDTH])
            );
            //
        end
        //
    endgenerate
    

    // T1 / T2
    // N  / N_COEFF
    // AB_LSB
    // AB_MSB
    // M
    // Q_LSB
    // Q_MSB
    // ?


    //
    // Operands - Values
    //
    initial begin
        //
        T1[ 0] = 18'h0b27b; T1[ 1] = 18'h0fc7d; T1[ 2] = 18'h0a214; T1[ 3] = 18'h08d2b;
        T1[ 4] = 18'h1c80c; T1[ 5] = 18'h145f1; T1[ 6] = 18'h00db6; T1[ 7] = 18'h1cf0f;
        T1[ 8] = 18'h19386; T1[ 9] = 18'h02ad9; T1[10] = 18'h1a8b5; T1[11] = 18'h1479b;
        T1[12] = 18'h08b5f; T1[13] = 18'h14806; T1[14] = 18'h0e6f7; T1[15] = 18'h0ce9d;
        T1[16] = 18'h0cbc2; T1[17] = 18'h16ef1; T1[18] = 18'h0e14e; T1[19] = 18'h1796f;
        T1[20] = 18'h14901; T1[21] = 18'h06666; T1[22] = 18'h0cb9f; T1[23] = 18'h09ab4;
        T1[24] = 18'h12ffc; T1[25] = 18'h0a86d; T1[26] = 18'h19d35; T1[27] = 18'h0cda9;
        T1[28] = 18'h16a19; T1[29] = 18'h09a36; T1[30] = 18'h0b176; T1[31] = 18'h0e0dc;
        //
        T2[ 0] = 18'h0b21a; T2[ 1] = 18'h13e71; T2[ 2] = 18'h03459; T2[ 3] = 18'h1063f;
        T2[ 4] = 18'h18cef; T2[ 5] = 18'h1b8a5; T2[ 6] = 18'h082d1; T2[ 7] = 18'h1b1be;
        T2[ 8] = 18'h18979; T2[ 9] = 18'h1409a; T2[10] = 18'h1713c; T2[11] = 18'h0cda3;
        T2[12] = 18'h11c7d; T2[13] = 18'h0c943; T2[14] = 18'h12d7c; T2[15] = 18'h1531e;
        T2[16] = 18'h0a45a; T2[17] = 18'h1c637; T2[18] = 18'h0906a; T2[19] = 18'h1670e;
        T2[20] = 18'h12f78; T2[21] = 18'h08ce6; T2[22] = 18'h1c5c7; T2[23] = 18'h1292d;
        T2[24] = 18'h0fc4b; T2[25] = 18'h064fb; T2[26] = 18'h0cc3c; T2[27] = 18'h19b37;
        T2[28] = 18'h1b721; T2[29] = 18'h0f424; T2[30] = 18'h0f608; T2[31] = 18'h03e9b;
        //
        N[ 0] = 18'h00a9d; N[ 1] = 18'h01175; N[ 2] = 18'h0254f; N[ 3] = 18'h0ee38;
        N[ 4] = 18'h00a6a; N[ 5] = 18'h0c7bd; N[ 6] = 18'h0ddac; N[ 7] = 18'h069fe;
        N[ 8] = 18'h0e9d6; N[ 9] = 18'h0b6bf; N[10] = 18'h09230; N[11] = 18'h04fc5;
        N[12] = 18'h05c9f; N[13] = 18'h09502; N[14] = 18'h0cbc5; N[15] = 18'h03109;
        N[16] = 18'h08029; N[17] = 18'h0b27c; N[18] = 18'h0eeb8; N[19] = 18'h0c191;
        N[20] = 18'h0ff86; N[21] = 18'h027ab; N[22] = 18'h07d76; N[23] = 18'h0ff1a;
        N[24] = 18'h02afc; N[25] = 18'h0b25a; N[26] = 18'h0d3c1; N[27] = 18'h05589;
        N[28] = 18'h09f7c; N[29] = 18'h0ddd6; N[30] = 18'h0b4fc; N[31] = 18'h0e8e7;
        //
        N_COEFF[ 0] = 18'h0344b; N_COEFF[ 1] = 18'h0ca66; N_COEFF[ 2] = 18'h0d9e8; N_COEFF[ 3] = 18'h070d5;
        N_COEFF[ 4] = 18'h0ce4b; N_COEFF[ 5] = 18'h049b2; N_COEFF[ 6] = 18'h0abb3; N_COEFF[ 7] = 18'h0c3b2;
        N_COEFF[ 8] = 18'h0ad38; N_COEFF[ 9] = 18'h05672; N_COEFF[10] = 18'h0fd47; N_COEFF[11] = 18'h06671;
        N_COEFF[12] = 18'h00b7f; N_COEFF[13] = 18'h0fa35; N_COEFF[14] = 18'h0d4ac; N_COEFF[15] = 18'h0f1ca;
        N_COEFF[16] = 18'h08e0a; N_COEFF[17] = 18'h05858; N_COEFF[18] = 18'h02dc6; N_COEFF[19] = 18'h08cfc;
        N_COEFF[20] = 18'h01941; N_COEFF[21] = 18'h0f855; N_COEFF[22] = 18'h01e43; N_COEFF[23] = 18'h053f0;
        N_COEFF[24] = 18'h0a479; N_COEFF[25] = 18'h0ae7e; N_COEFF[26] = 18'h05c66; N_COEFF[27] = 18'h02413;
        N_COEFF[28] = 18'h0b5f8; N_COEFF[29] = 18'h0eb06; N_COEFF[30] = 18'h0de5b; N_COEFF[31] = 18'h0a751;
        N_COEFF[32] = 18'h0c1ec;
        //
    end
    
    
    //
    // Load Interface
    //
    wire                   load_phase;
    wire [  INDEX_WIDTH:0] load_xy_addr;
    wire                   load_xy_addr_vld;
    wire                   load_xy_req;
    reg  [ WORD_WIDTH-1:0] load_x_din;
    reg  [ WORD_WIDTH-1:0] load_y_din;
    reg  [ WORD_WIDTH-1:0] load_x_pipe;
    reg  [ WORD_WIDTH-1:0] load_y_pipe;

    always @(posedge clk)
        //
        if (load_xy_addr_vld) begin
        
            if (!load_phase) begin
                load_x_pipe <= T1[load_xy_addr];
                load_y_pipe <= T2[load_xy_addr];
            end else begin
                load_x_pipe <= !load_xy_addr[INDEX_WIDTH] ? N[load_xy_addr] : {WORD_WIDTH{1'bX}};
                load_y_pipe <= N_COEFF[load_xy_addr];
            end 
        end

    always @(posedge clk)
        //
        if (load_xy_req)
            {load_y_din, load_x_din} <= {load_y_pipe, load_x_pipe};
        else
            {load_y_din, load_x_din} <= {2*WORD_WIDTH{1'bX}};

        
    //
    // UUT
    //
    modexpng_mmm_x8_dual #
    (
        .INDEX_WIDTH(INDEX_WIDTH)
    )
    uut
    (
		.clk                (clk),
		.rst_n              (rst_n),
        
		.ena                (ena),
		.rdy                (rdy),
        
        .mode               (mode),
        .transfer           (transfer),

		.index_last         (index_last),

        .x_din              (x_din),
        .y_din              (y_din),
        .x_dout             (x_dout),
        .y_dout             (y_dout),

        .x_din_addr         (x_din_addr),
        .y_din_addr         (y_din_addr),
        .x_dout_addr        (x_dout_addr),
        .y_dout_addr        (y_dout_addr),

        .x_din_ena          (x_din_ena),
        .y_din_ena          (y_din_ena),
        .x_dout_ena         (x_dout_ena),
        .y_dout_ena         (y_dout_ena),
        
        .x_din_reg_ena      (x_din_reg_ena),
        .y_din_reg_ena      (y_din_reg_ena),
    
        .x_din_bank         (x_din_bank),
        .y_din_bank         (y_din_bank),
        .x_dout_bank        (x_dout_bank),
        .y_dout_bank        (y_dout_bank),
        
        .load_phase         (load_phase),
        .load_xy_addr       (load_xy_addr),
        .load_xy_addr_vld   (load_xy_addr_vld),
        .load_xy_req        (load_xy_req),
        .load_x_din         (load_x_din),
        .load_y_din         (load_y_din)
	);


    //
    // Script
    //
	initial begin
        #(100.0*`CLK_PERIOD_NS)     rst      = 1'b0;
        #(100.0*`CLK_PERIOD_NS)     ena      = 1'b1;
                                    transfer = 1'b1;
                                    mode     = 1'b0;
        #(  1.0*`CLK_PERIOD_NS)     ena      = 1'b0;
                                    transfer = 1'bX;
                                    mode     = 1'bX;
                                    
        while (!rdy) #`CLK_PERIOD_NS;
        
        #(100.0*`CLK_PERIOD_NS)     ena      = 1'b1;
                                    transfer = 1'b0;
                                    mode     = 1'b0;
        #(  1.0*`CLK_PERIOD_NS)     ena      = 1'b0;
                                    transfer = 1'bX;
                                    mode     = 1'bX;
                                    
        while (!rdy) #`CLK_PERIOD_NS;
        
	end

      
endmodule