`timescale 1ns / 1ps
module tb_core_full_1024;
//
// Headers
//
`include "../rtl/modexpng_parameters.vh"
//
// Test Vectors
//
localparam TB_MODULUS_LENGTH_N = 1024;
localparam TB_MODULUS_LENGTH_PQ = TB_MODULUS_LENGTH_N / 2;
localparam TB_NUM_WORDS_PQ = TB_MODULUS_LENGTH_PQ / BUS_DATA_W;
localparam TB_NUM_WORDS_N = TB_MODULUS_LENGTH_N / BUS_DATA_W;
localparam CORE_NUM_WORDS_PQ = TB_MODULUS_LENGTH_PQ / WORD_W;
localparam CORE_NUM_WORDS_N = TB_MODULUS_LENGTH_N / WORD_W;
reg [31:0] M[0:TB_NUM_WORDS_N-1];
reg [31:0] N[0:TB_NUM_WORDS_N-1];
reg [31:0] N_FACTOR[0:TB_NUM_WORDS_N-1];
reg [31:0] N_COEFF[0:TB_NUM_WORDS_N];
reg [31:0] X[0:TB_NUM_WORDS_N-1];
reg [31:0] Y[0:TB_NUM_WORDS_N-1];
reg [31:0] P[0:TB_NUM_WORDS_PQ-1];
reg [31:0] Q[0:TB_NUM_WORDS_PQ-1];
reg [31:0] P_FACTOR[0:TB_NUM_WORDS_PQ-1];
reg [31:0] Q_FACTOR[0:TB_NUM_WORDS_PQ-1];
reg [31:0] P_COEFF[0:TB_NUM_WORDS_PQ];
reg [31:0] Q_COEFF[0:TB_NUM_WORDS_PQ];
reg [31:0] D[0:TB_NUM_WORDS_N-1];
reg [31:0] DP[0:TB_NUM_WORDS_PQ-1];
reg [31:0] DQ[0:TB_NUM_WORDS_PQ-1];
reg [31:0] QINV[0:TB_NUM_WORDS_PQ-1];
reg [31:0] XM[0:TB_NUM_WORDS_N-1];
reg [31:0] YM[0:TB_NUM_WORDS_N-1];
reg [31:0] S[0:TB_NUM_WORDS_N-1];
reg [31:0] XM_READBACK[0:TB_NUM_WORDS_N-1];
reg [31:0] YM_READBACK[0:TB_NUM_WORDS_N-1];
reg [31:0] S_READBACK[0:TB_NUM_WORDS_N-1];
initial begin
M[ 0] = 32'he1b3c6ac; M[ 1] = 32'haa2c5d8c; M[ 2] = 32'hbecc676a; M[ 3] = 32'hda087a3e;
M[ 4] = 32'hf0816496; M[ 5] = 32'hf9e17fd8; M[ 6] = 32'h304d4896; M[ 7] = 32'h81d4e9ab;
M[ 8] = 32'h80eff76c; M[ 9] = 32'he5b8f9b6; M[ 10] = 32'h4b1ebe55; M[ 11] = 32'ha1feb9dc;
M[ 12] = 32'heca4192f; M[ 13] = 32'h6ad6ea8e; M[ 14] = 32'hf34aed05; M[ 15] = 32'had38c275;
M[ 16] = 32'h8d3b583b; M[ 17] = 32'hc370f07e; M[ 18] = 32'hb9078738; M[ 19] = 32'haf37f86c;
M[ 20] = 32'h02f0e161; M[ 21] = 32'h0506a68a; M[ 22] = 32'h1ae65107; M[ 23] = 32'hcd3a97f1;
M[ 24] = 32'hb27244b8; M[ 25] = 32'h9bc3c400; M[ 26] = 32'he4d5636e; M[ 27] = 32'h35187c07;
M[ 28] = 32'h78a661c9; M[ 29] = 32'h1e7ec273; M[ 30] = 32'hcdc31041; M[ 31] = 32'h002291d8;
N[ 0] = 32'h6719997f; N[ 1] = 32'hef2df706; N[ 2] = 32'h9ba95792; N[ 3] = 32'h747e0580;
N[ 4] = 32'h7507684c; N[ 5] = 32'h7a10d0d1; N[ 6] = 32'h83a33941; N[ 7] = 32'haef9fda5;
N[ 8] = 32'h17972933; N[ 9] = 32'h0a98251a; N[ 10] = 32'h7dce3d13; N[ 11] = 32'hdad49a60;
N[ 12] = 32'h9f98006b; N[ 13] = 32'h46fd4a05; N[ 14] = 32'h51966e1d; N[ 15] = 32'hb1c59fab;
N[ 16] = 32'h8ab3096e; N[ 17] = 32'hef1f0436; N[ 18] = 32'heeed776f; N[ 19] = 32'h106d9d82;
N[ 20] = 32'hdd2a44af; N[ 21] = 32'h17c32585; N[ 22] = 32'hc854e454; N[ 23] = 32'h600fb6df;
N[ 24] = 32'h25c2d4bb; N[ 25] = 32'h5f09d790; N[ 26] = 32'he5a2bb93; N[ 27] = 32'h5bc6b044;
N[ 28] = 32'h2ecbb15f; N[ 29] = 32'h464817f5; N[ 30] = 32'h05cae32b; N[ 31] = 32'hde97bb85;
N_FACTOR[ 0] = 32'ha06a1113; N_FACTOR[ 1] = 32'hc9974806; N_FACTOR[ 2] = 32'h572d7a20; N_FACTOR[ 3] = 32'h04000838;
N_FACTOR[ 4] = 32'hb275c37a; N_FACTOR[ 5] = 32'hea78a046; N_FACTOR[ 6] = 32'h029e13b8; N_FACTOR[ 7] = 32'hae540753;
N_FACTOR[ 8] = 32'h1e98bc21; N_FACTOR[ 9] = 32'h34ede47a; N_FACTOR[ 10] = 32'h0c565ecd; N_FACTOR[ 11] = 32'h027ff3bf;
N_FACTOR[ 12] = 32'h08290d30; N_FACTOR[ 13] = 32'hb92857df; N_FACTOR[ 14] = 32'he6c59eb3; N_FACTOR[ 15] = 32'h09e53d6a;
N_FACTOR[ 16] = 32'h980d127e; N_FACTOR[ 17] = 32'h4dd6ced0; N_FACTOR[ 18] = 32'h3b9400d0; N_FACTOR[ 19] = 32'h276c6711;
N_FACTOR[ 20] = 32'h72eaf2e6; N_FACTOR[ 21] = 32'h749f81eb; N_FACTOR[ 22] = 32'h17b7d05f; N_FACTOR[ 23] = 32'h41a3a2cd;
N_FACTOR[ 24] = 32'h1ba098f3; N_FACTOR[ 25] = 32'h9b884af9; N_FACTOR[ 26] = 32'hdafd920c; N_FACTOR[ 27] = 32'h7b1f5cc6;
N_FACTOR[ 28] = 32'hb0a0d098; N_FACTOR[ 29] = 32'h4ee55bcf; N_FACTOR[ 30] = 32'haed9b905; N_FACTOR[ 31] = 32'h42d541fb;
N_COEFF[ 0] = 32'hb383d981; N_COEFF[ 1] = 32'h9bf1c20c; N_COEFF[ 2] = 32'h268999ff; N_COEFF[ 3] = 32'h11a3c01a;
N_COEFF[ 4] = 32'h12665495; N_COEFF[ 5] = 32'h515b0d96; N_COEFF[ 6] = 32'hb704fb07; N_COEFF[ 7] = 32'h8e1bd1d6;
N_COEFF[ 8] = 32'h62c5f506; N_COEFF[ 9] = 32'hfdcd0163; N_COEFF[ 10] = 32'h8dd55dee; N_COEFF[ 11] = 32'h6d79c8b1;
N_COEFF[ 12] = 32'hca16d0b9; N_COEFF[ 13] = 32'h88bead48; N_COEFF[ 14] = 32'hbcdb1e94; N_COEFF[ 15] = 32'h950c171d;
N_COEFF[ 16] = 32'h4fa810af; N_COEFF[ 17] = 32'h9b63e6d2; N_COEFF[ 18] = 32'ha2d0c26b; N_COEFF[ 19] = 32'hafa1ef25;
N_COEFF[ 20] = 32'h111bd21e; N_COEFF[ 21] = 32'hc2d896f0; N_COEFF[ 22] = 32'h189dc2cf; N_COEFF[ 23] = 32'h6144156a;
N_COEFF[ 24] = 32'hd1c67123; N_COEFF[ 25] = 32'ha127e4f3; N_COEFF[ 26] = 32'h40d342ef; N_COEFF[ 27] = 32'hee476d42;
N_COEFF[ 28] = 32'hee05f26a; N_COEFF[ 29] = 32'h4fc717bd; N_COEFF[ 30] = 32'h6baa4d60; N_COEFF[ 31] = 32'h1d6b10db;
N_COEFF[ 32] = 32'h00006545;
X[ 0] = 32'ha838f053; X[ 1] = 32'h8eb9747c; X[ 2] = 32'h5991b9eb; X[ 3] = 32'h74e6e776;
X[ 4] = 32'hcb5aa9e2; X[ 5] = 32'h7f8083d4; X[ 6] = 32'h3f7d47ec; X[ 7] = 32'hbd76a787;
X[ 8] = 32'hf4c166b7; X[ 9] = 32'hdbf67229; X[ 10] = 32'h975a5cfb; X[ 11] = 32'he8c35dca;
X[ 12] = 32'h6abc86e8; X[ 13] = 32'hfee472cb; X[ 14] = 32'h83ac8f2e; X[ 15] = 32'h82825cff;
X[ 16] = 32'h2d532c22; X[ 17] = 32'h2d3c3b06; X[ 18] = 32'he2862a8f; X[ 19] = 32'he8616ce4;
X[ 20] = 32'h5d77ee51; X[ 21] = 32'he609de07; X[ 22] = 32'hef718044; X[ 23] = 32'h82f35f8b;
X[ 24] = 32'hcdb9dcfe; X[ 25] = 32'hff6ea364; X[ 26] = 32'h0994ae28; X[ 27] = 32'h409b369b;
X[ 28] = 32'hcfabda4e; X[ 29] = 32'h5cd52bbc; X[ 30] = 32'hd90e1715; X[ 31] = 32'h00f4dcf2;
Y[ 0] = 32'h01b2730a; Y[ 1] = 32'h04ff1664; Y[ 2] = 32'h6d55dc06; Y[ 3] = 32'h1cda0da7;
Y[ 4] = 32'h98c812b4; Y[ 5] = 32'ha8f79f3b; Y[ 6] = 32'hb18d9ee1; Y[ 7] = 32'ha53e97db;
Y[ 8] = 32'hfbbfd687; Y[ 9] = 32'h6b8a8bf6; Y[ 10] = 32'h59fe5575; Y[ 11] = 32'he6ee62ca;
Y[ 12] = 32'h9fe3f32a; Y[ 13] = 32'h6d758eaa; Y[ 14] = 32'h121e3dac; Y[ 15] = 32'h31d77884;
Y[ 16] = 32'h8f2701dd; Y[ 17] = 32'hca5e7ac3; Y[ 18] = 32'h731977a3; Y[ 19] = 32'hc3c1af70;
Y[ 20] = 32'h5606786a; Y[ 21] = 32'h94b71191; Y[ 22] = 32'hd044c7e2; Y[ 23] = 32'h7d899cd7;
Y[ 24] = 32'hb17d4f5d; Y[ 25] = 32'h446e04de; Y[ 26] = 32'h9c40b33d; Y[ 27] = 32'habc2e23e;
Y[ 28] = 32'hbb98b1f6; Y[ 29] = 32'hf1f87f7e; Y[ 30] = 32'hf19f3050; Y[ 31] = 32'h91305f4c;
P[ 0] = 32'h18bb0f97; P[ 1] = 32'h08588a44; P[ 2] = 32'h042c6647; P[ 3] = 32'hc8d3fa09;
P[ 4] = 32'he2ddbbc7; P[ 5] = 32'hef4a17fd; P[ 6] = 32'h90c102ef; P[ 7] = 32'h28b132db;
P[ 8] = 32'hebfd5f0a; P[ 9] = 32'h958717ca; P[ 10] = 32'h563cd266; P[ 11] = 32'h433f41af;
P[ 12] = 32'hbc198e83; P[ 13] = 32'h5b5300b2; P[ 14] = 32'h9bc50e5d; P[ 15] = 32'hefffa822;
Q[ 0] = 32'h25de0259; Q[ 1] = 32'hd81461d0; Q[ 2] = 32'h613815b3; Q[ 3] = 32'h9bf274e0;
Q[ 4] = 32'hbfd89a48; Q[ 5] = 32'hc53e71ac; Q[ 6] = 32'hcce7aed3; Q[ 7] = 32'hce1d017c;
Q[ 8] = 32'h646547e1; Q[ 9] = 32'hd6779694; Q[ 10] = 32'h20ae39c0; Q[ 11] = 32'hef0d4b5b;
Q[ 12] = 32'h8e5f59d6; Q[ 13] = 32'h7e267974; Q[ 14] = 32'h14c86644; Q[ 15] = 32'hed6efcd0;
P_FACTOR[ 0] = 32'h614f99ce; P_FACTOR[ 1] = 32'hbcee5381; P_FACTOR[ 2] = 32'h10b70a9a; P_FACTOR[ 3] = 32'h1a697756;
P_FACTOR[ 4] = 32'h1a972b27; P_FACTOR[ 5] = 32'hd7c43f9e; P_FACTOR[ 6] = 32'h48cbad9c; P_FACTOR[ 7] = 32'hc350e206;
P_FACTOR[ 8] = 32'h51098b50; P_FACTOR[ 9] = 32'h93388ec6; P_FACTOR[ 10] = 32'h548960b5; P_FACTOR[ 11] = 32'h5ecd6b04;
P_FACTOR[ 12] = 32'h04d1d543; P_FACTOR[ 13] = 32'ha53994af; P_FACTOR[ 14] = 32'hd390be70; P_FACTOR[ 15] = 32'h0acdced0;
Q_FACTOR[ 0] = 32'h8a19423f; Q_FACTOR[ 1] = 32'h9d729c78; Q_FACTOR[ 2] = 32'h26ed5239; Q_FACTOR[ 3] = 32'h5a7eba92;
Q_FACTOR[ 4] = 32'h8465f60f; Q_FACTOR[ 5] = 32'hd50817dd; Q_FACTOR[ 6] = 32'hba703ab1; Q_FACTOR[ 7] = 32'h3d59bd42;
Q_FACTOR[ 8] = 32'h2c197fcc; Q_FACTOR[ 9] = 32'hed14f573; Q_FACTOR[ 10] = 32'hb860c105; Q_FACTOR[ 11] = 32'h89af91e7;
Q_FACTOR[ 12] = 32'h13a3742d; Q_FACTOR[ 13] = 32'h96e41677; Q_FACTOR[ 14] = 32'h86506b4d; Q_FACTOR[ 15] = 32'h4a834535;
P_COEFF[ 0] = 32'hb3679fd9; P_COEFF[ 1] = 32'hde24e467; P_COEFF[ 2] = 32'hf0e82022; P_COEFF[ 3] = 32'h99012919;
P_COEFF[ 4] = 32'h023bda43; P_COEFF[ 5] = 32'hf04eebf8; P_COEFF[ 6] = 32'h29e9942f; P_COEFF[ 7] = 32'h8c257cb0;
P_COEFF[ 8] = 32'h5cdc4e60; P_COEFF[ 9] = 32'h279bdff7; P_COEFF[ 10] = 32'hf04a610d; P_COEFF[ 11] = 32'h342901dc;
P_COEFF[ 12] = 32'hc3e2f78c; P_COEFF[ 13] = 32'h39c00ed8; P_COEFF[ 14] = 32'hf7032ac2; P_COEFF[ 15] = 32'h22d9c54e;
P_COEFF[ 16] = 32'h0000f994;
Q_COEFF[ 0] = 32'h95beda17; Q_COEFF[ 1] = 32'ha4b101fa; Q_COEFF[ 2] = 32'hd0b854bc; Q_COEFF[ 3] = 32'h5c952a67;
Q_COEFF[ 4] = 32'h56722aa8; Q_COEFF[ 5] = 32'h2176cace; Q_COEFF[ 6] = 32'h69beef2d; Q_COEFF[ 7] = 32'h95bf6eb2;
Q_COEFF[ 8] = 32'h0cf1175c; Q_COEFF[ 9] = 32'h4911b74e; Q_COEFF[ 10] = 32'h331e61cb; Q_COEFF[ 11] = 32'he9527ead;
Q_COEFF[ 12] = 32'h8d6a5911; Q_COEFF[ 13] = 32'hae42d654; Q_COEFF[ 14] = 32'he10d29a8; Q_COEFF[ 15] = 32'h50a5dd76;
Q_COEFF[ 16] = 32'h0000ed75;
D[ 0] = 32'h6d4e7831; D[ 1] = 32'ha96f72d6; D[ 2] = 32'h3b47788f; D[ 3] = 32'h07207984;
D[ 4] = 32'h3247b99f; D[ 5] = 32'hfe6ade84; D[ 6] = 32'h0e0fdec4; D[ 7] = 32'hc31450bd;
D[ 8] = 32'hb8624e9a; D[ 9] = 32'h362966c6; D[ 10] = 32'h4d8a15bf; D[ 11] = 32'h845b6e48;
D[ 12] = 32'h0b2259bf; D[ 13] = 32'h793bfff7; D[ 14] = 32'h28eeceb0; D[ 15] = 32'h8d6fde7f;
D[ 16] = 32'h0d618632; D[ 17] = 32'hfb371e4b; D[ 18] = 32'h0b80a9a0; D[ 19] = 32'h5c1a1381;
D[ 20] = 32'h8dfe755c; D[ 21] = 32'h82564b31; D[ 22] = 32'heee93cbd; D[ 23] = 32'h22bb686e;
D[ 24] = 32'hf2ccae97; D[ 25] = 32'he3400736; D[ 26] = 32'h11c4a85e; D[ 27] = 32'ha0c904d0;
D[ 28] = 32'hb495cecf; D[ 29] = 32'h32ceb818; D[ 30] = 32'ha2e46c28; D[ 31] = 32'h6915229e;
DP[ 0] = 32'h63d165e5; DP[ 1] = 32'h856ac81e; DP[ 2] = 32'hc4b8779d; DP[ 3] = 32'h8b119544;
DP[ 4] = 32'had780837; DP[ 5] = 32'h3e920266; DP[ 6] = 32'he9d10f2e; DP[ 7] = 32'h7c1b42b2;
DP[ 8] = 32'hc7daca3b; DP[ 9] = 32'h7883be11; DP[ 10] = 32'ha384548d; DP[ 11] = 32'he0848b23;
DP[ 12] = 32'h0b62bdff; DP[ 13] = 32'h11c64350; DP[ 14] = 32'h2aa1e225; DP[ 15] = 32'h9c2bcaa7;
DQ[ 0] = 32'hd7ffdc71; DQ[ 1] = 32'hed01b8aa; DQ[ 2] = 32'h2f99d3a6; DQ[ 3] = 32'h8ccb4428;
DQ[ 4] = 32'hb1574616; DQ[ 5] = 32'hfc218e36; DQ[ 6] = 32'h4fe24f91; DQ[ 7] = 32'h9c367c42;
DQ[ 8] = 32'h69dfa208; DQ[ 9] = 32'h3ee3de79; DQ[ 10] = 32'h54ded59b; DQ[ 11] = 32'hcb3b487d;
DQ[ 12] = 32'hbcc0db4e; DQ[ 13] = 32'hb3e6678c; DQ[ 14] = 32'h3d13ec03; DQ[ 15] = 32'h99e0f684;
QINV[ 0] = 32'h9a2f0db2; QINV[ 1] = 32'h4a8075a5; QINV[ 2] = 32'hb61201fa; QINV[ 3] = 32'h0e876a42;
QINV[ 4] = 32'h94667476; QINV[ 5] = 32'h7538b796; QINV[ 6] = 32'h8d8dfa35; QINV[ 7] = 32'h689ee4a7;
QINV[ 8] = 32'h6779dd63; QINV[ 9] = 32'he15b6b5e; QINV[ 10] = 32'h8275500c; QINV[ 11] = 32'he4dcd058;
QINV[ 12] = 32'haf54b86c; QINV[ 13] = 32'hba76dc50; QINV[ 14] = 32'h473d0d6d; QINV[ 15] = 32'ha023ba44;
XM[ 0] = 32'h9b067dd2; XM[ 1] = 32'hf47b497a; XM[ 2] = 32'he8044305; XM[ 3] = 32'hf74f1735;
XM[ 4] = 32'h494825f4; XM[ 5] = 32'h077bf4a3; XM[ 6] = 32'h637a9f36; XM[ 7] = 32'h3c3821a2;
XM[ 8] = 32'haa1fe167; XM[ 9] = 32'h01c7289a; XM[ 10] = 32'hb463d63d; XM[ 11] = 32'hc992252e;
XM[ 12] = 32'he43762bf; XM[ 13] = 32'h351d9416; XM[ 14] = 32'h10e7f813; XM[ 15] = 32'h33187c87;
XM[ 16] = 32'h9eb98306; XM[ 17] = 32'hb29be7b6; XM[ 18] = 32'h32b237a8; XM[ 19] = 32'h6c1d5e46;
XM[ 20] = 32'h1cf10b4a; XM[ 21] = 32'hd874a710; XM[ 22] = 32'h7d2df198; XM[ 23] = 32'h463701cc;
XM[ 24] = 32'h9b648da0; XM[ 25] = 32'hdc5d3b10; XM[ 26] = 32'hef88e7fd; XM[ 27] = 32'hcb888210;
XM[ 28] = 32'h24397651; XM[ 29] = 32'h9b9bd5a2; XM[ 30] = 32'hbc796763; XM[ 31] = 32'h5be48377;
YM[ 0] = 32'h78aba2bd; YM[ 1] = 32'h6885ed1d; YM[ 2] = 32'h0d4983a2; YM[ 3] = 32'h3b775d20;
YM[ 4] = 32'hf83145f4; YM[ 5] = 32'h66e52536; YM[ 6] = 32'h25c2377e; YM[ 7] = 32'h91ef1342;
YM[ 8] = 32'h73013f57; YM[ 9] = 32'h3862aa1a; YM[ 10] = 32'h37846437; YM[ 11] = 32'ha6ddd3c9;
YM[ 12] = 32'h3974d1b2; YM[ 13] = 32'h02aea3f6; YM[ 14] = 32'h2e71b229; YM[ 15] = 32'hb898d5b6;
YM[ 16] = 32'h71258bb8; YM[ 17] = 32'h654f94e8; YM[ 18] = 32'h5539e56e; YM[ 19] = 32'hd49567f2;
YM[ 20] = 32'he73efaa1; YM[ 21] = 32'h3e4e2162; YM[ 22] = 32'h772d786a; YM[ 23] = 32'hc27be96a;
YM[ 24] = 32'h9911c92d; YM[ 25] = 32'hddc1b0fd; YM[ 26] = 32'h829186bb; YM[ 27] = 32'h1bab454e;
YM[ 28] = 32'h2f9fd9ce; YM[ 29] = 32'ha57103d4; YM[ 30] = 32'h1a93390c; YM[ 31] = 32'hc0376429;
S[ 0] = 32'h8eb4aa6e; S[ 1] = 32'hababa077; S[ 2] = 32'h8758f3f6; S[ 3] = 32'h8282e4f4;
S[ 4] = 32'h747947ce; S[ 5] = 32'h9ac7dbb0; S[ 6] = 32'h9184f0b5; S[ 7] = 32'h4b572f47;
S[ 8] = 32'hf4807458; S[ 9] = 32'h6da8dcd4; S[ 10] = 32'h9f331c40; S[ 11] = 32'h65e2b7a2;
S[ 12] = 32'hd3704e85; S[ 13] = 32'h3366f4f0; S[ 14] = 32'h035044b1; S[ 15] = 32'h54758bc4;
S[ 16] = 32'h2a7e0970; S[ 17] = 32'hbcc7783c; S[ 18] = 32'hf62193e6; S[ 19] = 32'h5d7bb220;
S[ 20] = 32'hb0fcabdd; S[ 21] = 32'he6dc5c88; S[ 22] = 32'h8e4d5e53; S[ 23] = 32'haa40acba;
S[ 24] = 32'h1dfc9178; S[ 25] = 32'h842821bc; S[ 26] = 32'h318fc8e1; S[ 27] = 32'h0f8161fe;
S[ 28] = 32'hbf3d7945; S[ 29] = 32'he33612c7; S[ 30] = 32'h7eec7f9d; S[ 31] = 32'h66da2c5a;
end
//
// Clocks
//
`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)
`define CLK_PERIOD_QUARTER_NS (0.5 * `CLK_PERIOD_HALF_NS)
`define CLK_BUS_FREQUENCY_MHZ (25.0)
`define CLK_BUS_PERIOD_NS (1000.0 / `CLK_BUS_FREQUENCY_MHZ)
`define CLK_BUS_PERIOD_HALF_NS (0.5 * `CLK_BUS_PERIOD_NS)
reg clk = 1'b1;
reg clk_dly = 1'b0;
wire clk_idle = clk & clk_dly;
reg clk_bus = 1'b1;
reg clk_bus_dly = 1'b0;
wire clk_bus_idle = clk_bus & clk_bus_dly;
always #`CLK_PERIOD_HALF_NS clk <= ~clk;
always #`CLK_BUS_PERIOD_HALF_NS clk_bus <= ~clk_bus;
always @(clk ) clk_dly <= #(`CLK_PERIOD_HALF_NS - `CLK_PERIOD_QUARTER_NS) clk;
always @(clk_bus) clk_bus_dly <= #(`CLK_BUS_PERIOD_HALF_NS - `CLK_PERIOD_QUARTER_NS) clk_bus;
//
// Clock Sync
//
task sync_clk;
while (clk_idle !== 1) _wait_quarter_clk_tick;
endtask
task sync_clk_bus;
while (clk_bus_idle !== 1) _wait_quarter_clk_tick;
endtask
//
// Reset
//
reg rst = 1'b1;
wire rst_n = ~rst;
//
// Control / Status
//
reg [ 7:0] word_index_last_n;
reg [ 7:0] word_index_last_pq;
reg [11:0] bit_index_last_n;
reg [11:0] bit_index_last_pq;
reg core_next = 1'b0;
wire core_valid;
reg core_crt_mode;
//
// System Bus
//
reg bus_cs = 1'b0;
reg bus_we = 1'b0;
reg [11:0] bus_addr;
reg [31:0] bus_data_wr;
wire [31:0] bus_data_rd;
wire [ 1:0] bus_addr_sel = bus_addr[11:10];
wire [ 2:0] bus_addr_bank = bus_addr[9:7];
wire [ 6:0] bus_addr_data = bus_addr[6:0];
//
// UUT
//
modexpng_core_top uut
(
.clk (clk),
.clk_bus (clk_bus),
.rst_n (rst_n),
.next (core_next),
.valid (core_valid),
.crt_mode (core_crt_mode),
.word_index_last_n (word_index_last_n),
.word_index_last_pq (word_index_last_pq),
.bit_index_last_n (bit_index_last_n),
.bit_index_last_pq (bit_index_last_pq),
.bus_cs (bus_cs),
.bus_we (bus_we),
.bus_addr (bus_addr),
.bus_data_wr (bus_data_wr),
.bus_data_rd (bus_data_rd)
);
//
// Bus Init Routine
//
task core_set_input;
begin
core_set_input_1;
core_set_input_2;
wait_clk_bus_ticks(10);
$display("Core input banks written.");
end
endtask
//
// Script
//
initial main;
//
// Main Routine (Control/Status, Bus)
//
integer i, j, k;
task main;
begin
sync_clk; // switch to fast core clock
core_reset; // reset core
core_set_params; // set parameters (modulus width, exponent length)
sync_clk_bus; // switch to slow bus clock
core_set_input; // write to core input banks
sync_clk; // switch to fast core clock
core_set_crt_mode(1); // enable CRT signing
core_pulse_next; // assert 'next' bit for one cycle
core_wait_valid; // wait till 'valid' bit gets asserted
sync_clk_bus; // switch to slow bus clock
core_get_output; // read from core output banks
core_verify_output; // check, whether core output matches precomputed known good refrence values
core_print_load; //
sync_clk; // switch to fast core clock
core_set_crt_mode(0); // disable CRT signing
core_pulse_next; // assert 'next' bit for one cycle
core_wait_valid; // wait till 'valid' bit gets asserted
sync_clk_bus; // switch to slow bus clock
core_get_output; // read from core output banks
core_verify_output; // check, whether core output matches precomputed known good refrence values
core_print_load; //
end
endtask
task core_reset;
begin
wait_clk_ticks(100);
rst = 1'b0;
wait_clk_ticks(10);
$display("Core reset finished.");
end
endtask
task core_set_params;
begin
word_index_last_n = CORE_NUM_WORDS_N - 1;
word_index_last_pq = CORE_NUM_WORDS_PQ - 1;
bit_index_last_n = TB_MODULUS_LENGTH_N - 1;
bit_index_last_pq = TB_MODULUS_LENGTH_N / 2 - 1;
$display("Core parameters set.");
end
endtask
task core_set_crt_mode;
input _crt;
begin
core_crt_mode = _crt;
if (_crt) $display("Enabled CRT mode.");
else $display("Disabled CRT mode.");
end
endtask
task core_pulse_next;
begin
core_next = 1'b1;
wait_clk_tick;
core_next = 1'b0;
$display("Pulsed core 'next' control signal.");
end
endtask
task core_wait_valid;
begin
while (!core_valid) wait_clk_tick;
wait_clk_ticks(10);
$display("Detected high core 'valid' status signal.");
end
endtask
//
// Variables
//
integer _w, _n;
//
// core_set_input_1
//
task core_set_input_1;
reg [9:0] _tn;
begin
_tn = BANK_IN_1_N_COEFF * 2 ** BUS_OP_ADDR_W + TB_NUM_WORDS_N; // trick to write extra trailer word
for (_w=0; _w<TB_NUM_WORDS_N; _w=_w+1) bus_write(2'd1, BANK_IN_1_M, _w[6:0], M[_w]);
for (_w=0; _w<TB_NUM_WORDS_N; _w=_w+1) bus_write(2'd1, BANK_IN_1_N, _w[6:0], N[_w]);
for (_w=0; _w<TB_NUM_WORDS_N; _w=_w+1) bus_write(2'd1, BANK_IN_1_N_FACTOR, _w[6:0], N_FACTOR[_w]);
for (_w=0; _w<TB_NUM_WORDS_N; _w=_w+1) bus_write(2'd1, BANK_IN_1_N_COEFF, _w[6:0], N_COEFF[_w]);
bus_write(2'd1, _tn[9:7], _tn[6:0], N_COEFF[TB_NUM_WORDS_N]);
for (_w=0; _w<TB_NUM_WORDS_N; _w=_w+1) bus_write(2'd1, BANK_IN_1_X, _w[6:0], X[_w]);
for (_w=0; _w<TB_NUM_WORDS_N; _w=_w+1) bus_write(2'd1, BANK_IN_1_Y, _w[6:0], Y[_w]);
end
endtask
//
// core_set_input_2
//
task core_set_input_2;
begin
for (_w=0; _w< TB_NUM_WORDS_N; _w=_w+1) bus_write(2'd2, BANK_IN_2_D, { _w[6:0]}, D [_w]);
for (_w=0; _w< TB_NUM_WORDS_PQ; _w=_w+1) bus_write(2'd2, BANK_IN_2_P, {1'b0, _w[5:0]}, P [_w]);
for (_w=0; _w< TB_NUM_WORDS_PQ; _w=_w+1) bus_write(2'd2, BANK_IN_2_P, {1'b1, _w[5:0]}, DP [_w]);
for (_w=0; _w< TB_NUM_WORDS_PQ; _w=_w+1) bus_write(2'd2, BANK_IN_2_P_FACTOR, { _w[6:0]}, P_FACTOR[_w]);
for (_w=0; _w<=TB_NUM_WORDS_PQ; _w=_w+1) bus_write(2'd2, BANK_IN_2_P_COEFF, { _w[6:0]}, P_COEFF [_w]);
for (_w=0; _w< TB_NUM_WORDS_PQ; _w=_w+1) bus_write(2'd2, BANK_IN_2_Q, {1'b0, _w[5:0]}, Q [_w]);
for (_w=0; _w< TB_NUM_WORDS_PQ; _w=_w+1) bus_write(2'd2, BANK_IN_2_Q, {1'b1, _w[5:0]}, DQ [_w]);
for (_w=0; _w< TB_NUM_WORDS_PQ; _w=_w+1) bus_write(2'd2, BANK_IN_2_Q_FACTOR, { _w[6:0]}, Q_FACTOR[_w]);
for (_w=0; _w<=TB_NUM_WORDS_PQ; _w=_w+1) bus_write(2'd2, BANK_IN_2_Q_COEFF, { _w[6:0]}, Q_COEFF [_w]);
for (_w=0; _w< TB_NUM_WORDS_PQ; _w=_w+1) bus_write(2'd2, BANK_IN_2_QINV, { _w[6:0]}, QINV [_w]);
end
endtask
//
// core_get_output
//
task core_get_output;
begin
for (_w=0; _w<TB_NUM_WORDS_N; _w=_w+1) bus_read(2'd3, BANK_OUT_XM, _w[6:0], XM_READBACK[_w]);
for (_w=0; _w<TB_NUM_WORDS_N; _w=_w+1) bus_read(2'd3, BANK_OUT_YM, _w[6:0], YM_READBACK[_w]);
for (_w=0; _w<TB_NUM_WORDS_N; _w=_w+1) bus_read(2'd3, BANK_OUT_S, _w[6:0], S_READBACK[_w]);
wait_clk_bus_ticks(10);
$display("Core output banks read.");
end
endtask
//
// core_verify_output
//
task core_verify_output;
//
reg xm_ok;
reg ym_ok;
reg s_ok;
//
begin
//
xm_ok = 1;
ym_ok = 1;
s_ok = 1;
//
for (_w=0; _w<TB_NUM_WORDS_N; _w=_w+1) begin
if (XM_READBACK[_w] !== XM[_w]) xm_ok = 0;
if (YM_READBACK[_w] !== YM[_w]) ym_ok = 0;
if (S_READBACK[_w] !== S[_w]) s_ok = 0;
end
//
if (!xm_ok)
//
for (_w=0; _w<TB_NUM_WORDS_N; _w=_w+1) begin
$write("XM / XM_READBACK [%3d] = 0x%08x / 0x%08x", _w, XM[_w], XM_READBACK[_w]);
if (XM[_w] !== XM_READBACK[_w]) $write(" <???: 0x%08x> ", XM[_w] ^ XM_READBACK[_w]);
$write("\n");
end
//
if (!ym_ok)
//
for (_w=0; _w<TB_NUM_WORDS_N; _w=_w+1) begin
$write("YM / YM_READBACK [%3d] = 0x%08x / 0x%08x", _w, YM[_w], YM_READBACK[_w]);
if (YM[_w] !== YM_READBACK[_w]) $write(" <???: 0x%08x> ", YM[_w] ^ YM_READBACK[_w]);
$write("\n");
end
//
if (!s_ok)
//
for (_w=0; _w<TB_NUM_WORDS_N; _w=_w+1) begin
$write("S / S_READBACK [%3d] = 0x%08x / 0x%08x", _w, S[_w], S_READBACK[_w]);
if (S[_w] !== S_READBACK[_w]) $write(" <???: 0x%08x> ", S[_w] ^ S_READBACK[_w]);
$write("\n");
end
//
$write("XM is ");
if (xm_ok) $write("OK.\n");
else $write("WRONG!\n");
//
$write("YM is ");
if (ym_ok) $write("OK.\n");
else $write("WRONG!\n");
//
$write("S is ");
if (s_ok) $write("OK.\n");
else $write("WRONG!\n");
//
end
//
endtask
//
// _bus_drive()
//
task _bus_drive;
input cs;
input we;
input [11:0] addr;
input [31:0] data;
{bus_cs, bus_we, bus_addr, bus_data_wr} <= {cs, we, addr, data};
endtask
//
// bus_write()
//
task bus_write;
input [ 1:0] sel;
input [ 2:0] bank;
input [ 6:0] addr;
input [31:0] data;
begin
_bus_drive(1'b1, 1'b1, {sel, bank, addr}, data);
wait_clk_bus_tick;
_bus_drive(1'b0, 1'b0, 12'hXXX, 32'hXXXXXXXX);
end
endtask
//
// bus_read()
//
task bus_read;
input [ 1:0] sel;
input [ 2:0] bank;
input [ 6:0] addr;
output [31:0] data;
begin
_bus_drive(1'b1, 1'b0, {sel, bank, addr}, 32'hXXXXXXXX);
wait_clk_bus_tick;
data = bus_data_rd;
_bus_drive(1'b0, 1'b0, 12'hXXX, 32'hXXXXXXXX);
end
endtask
//
// _wait_quarter_clk_tick()
//
task _wait_quarter_clk_tick;
#`CLK_PERIOD_QUARTER_NS;
endtask
//
// _wait_half_clk_tick()
//
task _wait_half_clk_tick;
begin
_wait_quarter_clk_tick;
_wait_quarter_clk_tick;
end
endtask
//
// wait_clk_tick()
//
task wait_clk_tick;
begin
_wait_half_clk_tick;
_wait_half_clk_tick;
end
endtask
//
// wait_clk_bus_tick()
//
task wait_clk_bus_tick;
#`CLK_BUS_PERIOD_NS;
endtask
//
// wait_clk_ticks()
//
task wait_clk_ticks;
input integer num_ticks;
for (_n=0; _n<num_ticks; _n=_n+1)
wait_clk_tick;
endtask
//
// wait_clk_bus_ticks()
//
task wait_clk_bus_ticks;
input integer num_ticks;
for (_n=0; _n<num_ticks; _n=_n+1)
wait_clk_bus_tick;
endtask
//
// Multiplier Load Calculator
//
real load_cyc_total_prev = 0.0;
real load_cyc_mult_prev = 0.0;
real load_cyc_total = 0.0;
always @(posedge clk)
//
if (!core_valid)
load_cyc_total <= load_cyc_total + 1.0;
task core_print_load;
real delta_cyc_total, delta_cyc_mult, load_pct;
begin
`ifndef MODEXPNG_ENABLE_DEBUG
$display("core_print_load: Multiplier load was not calculated, since MODEXPNG_ENABLE_DEBUG was no defined.");
`else
delta_cyc_total = load_cyc_total - load_cyc_total_prev;
delta_cyc_mult = uut.mmm_x.load_cyc_mult - load_cyc_mult_prev;
load_pct = 100.0 * delta_cyc_mult / delta_cyc_total;
$display("Multiplier load: %.1f%%", load_pct);
load_cyc_total_prev = load_cyc_total;
load_cyc_mult_prev = uut.mmm_x.load_cyc_mult;
`endif
end
endtask
endmodule