aboutsummaryrefslogtreecommitdiff
path: root/bench
diff options
context:
space:
mode:
Diffstat (limited to 'bench')
-rw-r--r--bench/tb_core_full_1024.v (renamed from bench/tb_core_full.v)6
-rw-r--r--bench/tb_core_full_512.v458
2 files changed, 461 insertions, 3 deletions
diff --git a/bench/tb_core_full.v b/bench/tb_core_full_1024.v
index e592ac5..e6b1a66 100644
--- a/bench/tb_core_full.v
+++ b/bench/tb_core_full_1024.v
@@ -1,6 +1,6 @@
`timescale 1ns / 1ps
-module tb_core_full;
+module tb_core_full_1024;
//
@@ -274,7 +274,7 @@ module tb_core_full;
word_index_last_pq = CORE_NUM_WORDS_PQ - 1;
bit_index_last_n = TB_MODULUS_LENGTH_N - 1;
- bit_index_last_pq = 9;//TB_MODULUS_LENGTH_N / 2 - 1;
+ bit_index_last_pq = 9; //TB_MODULUS_LENGTH_N / 2 - 1;
core_crt_mode = 1'b1;
@@ -295,7 +295,7 @@ module tb_core_full;
$display("Core output banks read.");
- //verify;
+ verify;
end
diff --git a/bench/tb_core_full_512.v b/bench/tb_core_full_512.v
new file mode 100644
index 0000000..221a2c6
--- /dev/null
+++ b/bench/tb_core_full_512.v
@@ -0,0 +1,458 @@
+`timescale 1ns / 1ps
+
+module tb_core_full_512;
+
+
+ //
+ // Headers
+ //
+ `include "../rtl/modexpng_parameters.vh"
+
+
+ //
+ // Test Vectors
+ //
+ localparam TB_MODULUS_LENGTH_N = 512;
+ 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] 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'h8d3b583b; M[ 1] = 32'hc370f07e; M[ 2] = 32'hb9078738; M[ 3] = 32'haf37f86c;
+ M[ 4] = 32'h02f0e161; M[ 5] = 32'h0506a68a; M[ 6] = 32'h1ae65107; M[ 7] = 32'hcd3a97f1;
+ M[ 8] = 32'hb27244b8; M[ 9] = 32'h9bc3c400; M[ 10] = 32'he4d5636e; M[ 11] = 32'h35187c07;
+ M[ 12] = 32'h78a661c9; M[ 13] = 32'h1e7ec273; M[ 14] = 32'hcdc31041; M[ 15] = 32'h002291d8;
+ N[ 0] = 32'hcb703101; N[ 1] = 32'h82bc8290; N[ 2] = 32'hdb2372c2; N[ 3] = 32'hdeeb692e;
+ N[ 4] = 32'ha3ee352a; N[ 5] = 32'h81a711ba; N[ 6] = 32'h14ee23bd; N[ 7] = 32'h8ad351c0;
+ N[ 8] = 32'h75ecd3d5; N[ 9] = 32'h51c9b22f; N[ 10] = 32'hc1d3496e; N[ 11] = 32'h48176f3e;
+ N[ 12] = 32'hd2aca749; N[ 13] = 32'hf236cea9; N[ 14] = 32'h7f4525ed; N[ 15] = 32'hb4fc5067;
+ N_FACTOR[ 0] = 32'he253bfbf; N_FACTOR[ 1] = 32'h8e0b26aa; N_FACTOR[ 2] = 32'h0480b661; N_FACTOR[ 3] = 32'h9a13f7a1;
+ N_FACTOR[ 4] = 32'h464b7342; N_FACTOR[ 5] = 32'hfb6f8e41; N_FACTOR[ 6] = 32'h081208e4; N_FACTOR[ 7] = 32'h63d8328a;
+ N_FACTOR[ 8] = 32'h604d2b71; N_FACTOR[ 9] = 32'hc987dabe; N_FACTOR[ 10] = 32'h8a474e35; N_FACTOR[ 11] = 32'hc053ba1c;
+ N_FACTOR[ 12] = 32'h15b82dd9; N_FACTOR[ 13] = 32'h42c2bbfa; N_FACTOR[ 14] = 32'h1681e95d; N_FACTOR[ 15] = 32'h07dee5fa;
+ N_COEFF[ 0] = 32'h730f30ff; N_COEFF[ 1] = 32'h50ed900a; N_COEFF[ 2] = 32'h0b9038c5; N_COEFF[ 3] = 32'h974ddd03;
+ N_COEFF[ 4] = 32'he2c118c8; N_COEFF[ 5] = 32'hbe1bc7e1; N_COEFF[ 6] = 32'h224d548c; N_COEFF[ 7] = 32'h48ea2ee4;
+ N_COEFF[ 8] = 32'heb379247; N_COEFF[ 9] = 32'had97b934; N_COEFF[ 10] = 32'hfc6dfd93; N_COEFF[ 11] = 32'h3a0246ef;
+ N_COEFF[ 12] = 32'h1baa167c; N_COEFF[ 13] = 32'h7d7ee254; N_COEFF[ 14] = 32'h657f0a53; N_COEFF[ 15] = 32'hea9e7245;
+ N_COEFF[ 16] = 32'h0000f88c;
+ X[ 0] = 32'h2d532c22; X[ 1] = 32'h2d3c3b06; X[ 2] = 32'he2862a8f; X[ 3] = 32'he8616ce4;
+ X[ 4] = 32'h5d77ee51; X[ 5] = 32'he609de07; X[ 6] = 32'hef718044; X[ 7] = 32'h82f35f8b;
+ X[ 8] = 32'hcdb9dcfe; X[ 9] = 32'hff6ea364; X[ 10] = 32'h0994ae28; X[ 11] = 32'h409b369b;
+ X[ 12] = 32'hcfabda4e; X[ 13] = 32'h5cd52bbc; X[ 14] = 32'hd90e1715; X[ 15] = 32'h00f4dcf2;
+ Y[ 0] = 32'h34fff653; Y[ 1] = 32'h50f52544; Y[ 2] = 32'h0ebf96a7; Y[ 3] = 32'h98352265;
+ Y[ 4] = 32'hbe372927; Y[ 5] = 32'h5b2f6394; Y[ 6] = 32'h9acfccb3; Y[ 7] = 32'h7b5bd4b2;
+ Y[ 8] = 32'h79b09448; Y[ 9] = 32'h08f11fa6; Y[ 10] = 32'h8411d066; Y[ 11] = 32'h58ba5021;
+ Y[ 12] = 32'h03c1cb72; Y[ 13] = 32'hacf0689d; Y[ 14] = 32'h983c65bd; Y[ 15] = 32'h29a39dcc;
+ P[ 0] = 32'hebfc2433; P[ 1] = 32'ha2cfbc81; P[ 2] = 32'hea08812b; P[ 3] = 32'h0adf004f;
+ P[ 4] = 32'hb987a8c6; P[ 5] = 32'h2860f873; P[ 6] = 32'haf2cfe12; P[ 7] = 32'hddd53c3a;
+ Q[ 0] = 32'hdc1981fb; Q[ 1] = 32'h01184053; Q[ 2] = 32'h7ab8d640; Q[ 3] = 32'h62ba8a22;
+ Q[ 4] = 32'h6cb226a1; Q[ 5] = 32'he1f08e16; Q[ 6] = 32'h13e990b5; Q[ 7] = 32'hd0dc7ce3;
+ P_FACTOR[ 0] = 32'h043fb284; P_FACTOR[ 1] = 32'hcaab7ce3; P_FACTOR[ 2] = 32'h543c62ef; P_FACTOR[ 3] = 32'h8aa74942;
+ P_FACTOR[ 4] = 32'hefa2ea7b; P_FACTOR[ 5] = 32'hdb8513b5; P_FACTOR[ 6] = 32'h0ea607a4; P_FACTOR[ 7] = 32'h6a59e5a7;
+ Q_FACTOR[ 0] = 32'h089dcd43; Q_FACTOR[ 1] = 32'h5b23611b; Q_FACTOR[ 2] = 32'h02f0f47c; Q_FACTOR[ 3] = 32'h952ababd;
+ Q_FACTOR[ 4] = 32'hc4ee13fe; Q_FACTOR[ 5] = 32'h3feb46fa; Q_FACTOR[ 6] = 32'h96b679df; Q_FACTOR[ 7] = 32'h831126dd;
+ P_COEFF[ 0] = 32'h647c8905; P_COEFF[ 1] = 32'hcb7c6b7d; P_COEFF[ 2] = 32'h8053b8be; P_COEFF[ 3] = 32'hb28f33a7;
+ P_COEFF[ 4] = 32'hb3207e05; P_COEFF[ 5] = 32'h4e3d416e; P_COEFF[ 6] = 32'h1911d8d9; P_COEFF[ 7] = 32'hd569156e;
+ P_COEFF[ 8] = 32'h00003dd7;
+ Q_COEFF[ 0] = 32'h5eee9ecd; Q_COEFF[ 1] = 32'h085153b0; Q_COEFF[ 2] = 32'h85326da6; Q_COEFF[ 3] = 32'h7521931a;
+ Q_COEFF[ 4] = 32'h99e0eef1; Q_COEFF[ 5] = 32'ha219917b; Q_COEFF[ 6] = 32'he8e9087a; Q_COEFF[ 7] = 32'h5239d12b;
+ Q_COEFF[ 8] = 32'h0000ed92;
+ DP[ 0] = 32'h3891ed91; DP[ 1] = 32'h775046c2; DP[ 2] = 32'h60180c26; DP[ 3] = 32'h5130700a;
+ DP[ 4] = 32'hb13c8216; DP[ 5] = 32'h833fcf78; DP[ 6] = 32'h7ab89b12; DP[ 7] = 32'hb976758c;
+ DQ[ 0] = 32'h28cc59ad; DQ[ 1] = 32'h3ce6ed45; DQ[ 2] = 32'ha1f53aeb; DQ[ 3] = 32'h06ca05e1;
+ DQ[ 4] = 32'hc5195df6; DQ[ 5] = 32'h42cf91f8; DQ[ 6] = 32'h93d6f054; DQ[ 7] = 32'h3d3bc769;
+ QINV[ 0] = 32'h50201af6; QINV[ 1] = 32'h85d97b7f; QINV[ 2] = 32'h4247e697; QINV[ 3] = 32'h9fd231fe;
+ QINV[ 4] = 32'h21e98610; QINV[ 5] = 32'ha0bc58dc; QINV[ 6] = 32'ha86f266c; QINV[ 7] = 32'h838688c8;
+ XM[ 0] = 32'hf9980f33; XM[ 1] = 32'hb444f483; XM[ 2] = 32'h0a6f8294; XM[ 3] = 32'h1c74da49;
+ XM[ 4] = 32'h0aa4151f; XM[ 5] = 32'ha1dfb66f; XM[ 6] = 32'h1415da79; XM[ 7] = 32'had7d3272;
+ XM[ 8] = 32'h43d7b612; XM[ 9] = 32'h56626cce; XM[ 10] = 32'ha65edef6; XM[ 11] = 32'h28c49eb8;
+ XM[ 12] = 32'h5364b7f8; XM[ 13] = 32'hd170915e; XM[ 14] = 32'h5a4c960d; XM[ 15] = 32'h27cb1911;
+ YM[ 0] = 32'h7640c2ca; YM[ 1] = 32'hf49d583a; YM[ 2] = 32'he4ae0f22; YM[ 3] = 32'ha3dad5ed;
+ YM[ 4] = 32'hbe88ab4d; YM[ 5] = 32'h9fb50b38; YM[ 6] = 32'h223feceb; YM[ 7] = 32'hfc4893ff;
+ YM[ 8] = 32'hb40556c2; YM[ 9] = 32'hb25b27fa; YM[ 10] = 32'h7e277535; YM[ 11] = 32'h42e1e9ab;
+ YM[ 12] = 32'hebd55ef2; YM[ 13] = 32'h8b6d8c0b; YM[ 14] = 32'h4d91ad9a; YM[ 15] = 32'h0e8bf565;
+ S[ 0] = 32'h2f89f059; S[ 1] = 32'hdbc41170; S[ 2] = 32'h1d7ea6c0; S[ 3] = 32'h1df9add6;
+ S[ 4] = 32'ha619e2e1; S[ 5] = 32'h253fcd88; S[ 6] = 32'h6c03a351; S[ 7] = 32'h795b1df0;
+ S[ 8] = 32'h2854a51a; S[ 9] = 32'h0245619b; S[ 10] = 32'hfb67ef8f; S[ 11] = 32'hcc5bdd4f;
+ S[ 12] = 32'ha70f58bd; S[ 13] = 32'h31f15702; S[ 14] = 32'hd6f36259; S[ 15] = 32'h280e67e0;
+ 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_BUS_FREQUENCY_MHZ (50.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_bus = 1'b0;
+
+ always #`CLK_PERIOD_HALF_NS clk = ~clk;
+
+ always #`CLK_BUS_PERIOD_HALF_NS clk_bus = ~clk_bus;
+
+
+ //
+ // Reset
+ //
+ reg rst = 1'b1;
+
+
+ //
+ // 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_ready;
+ 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 (rst),
+
+ .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)
+ );
+
+
+ //
+ // Routine (Bus)
+ //
+ initial begin
+
+ bus_ready = 1'b0;
+
+ while (rst) wait_clock_bus_tick;
+ wait_clock_bus_ticks(10);
+ $display("Core came out of reset.");
+
+ set_input_1;
+ set_input_2;
+
+ wait_clock_bus_ticks(10);
+ bus_ready = 1'b1;
+
+ end
+
+
+ //
+ // Routine (Control/Status, Bus)
+ //
+ initial begin
+
+ _wait_half_clock_tick;
+ wait_clock_ticks(100);
+ rst = 1'b0;
+
+ while (!bus_ready) wait_clock_tick;
+ wait_clock_ticks(10);
+ $display("Core input banks written.");
+
+ 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;
+
+ core_crt_mode = 1'b1;
+
+ core_next = 1'b1;
+ wait_clock_tick;
+ core_next = 1'b0;
+ $display("Pulsed 'next' control signal.");
+
+ while (!core_valid) wait_clock_tick;
+ wait_clock_ticks(10);
+
+ $display("Detected high 'valid' status signal.");
+ core_crt_mode = 1'bX;
+
+ wait_clock_ticks(10);
+ get_output;
+ wait_clock_ticks(10);
+
+ $display("Core output banks read.");
+
+ verify;
+
+ end
+
+
+ //
+ // Variables
+ //
+ integer _w, _n;
+
+
+ //
+ // set_input_1;
+ //
+ task 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'd0, BANK_IN_1_M, _w[6:0], M[_w]);
+ for (_w=0; _w<TB_NUM_WORDS_N; _w=_w+1) bus_write(2'd0, BANK_IN_1_N, _w[6:0], N[_w]);
+ for (_w=0; _w<TB_NUM_WORDS_N; _w=_w+1) bus_write(2'd0, 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'd0, BANK_IN_1_N_COEFF, _w[6:0], N_COEFF[_w]);
+ bus_write(2'd0, _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'd0, BANK_IN_1_X, _w[6:0], X[_w]);
+ for (_w=0; _w<TB_NUM_WORDS_N; _w=_w+1) bus_write(2'd0, BANK_IN_1_Y, _w[6:0], Y[_w]);
+ end
+ endtask
+
+
+ //
+ // set_input_2;
+ //
+ task set_input_2;
+ begin
+// for (_w=0; _w<TB_NUM_WORDS_N; _w=_w+1) bus_write(2'd0, BANK_IN_1_M, _w[6:0], M[_w]);
+ for (_w=0; _w< TB_NUM_WORDS_PQ; _w=_w+1) bus_write(2'd1, 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'd1, 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'd1, 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'd1, 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'd1, 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'd1, 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'd1, 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'd1, 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'd1, BANK_IN_2_QINV, { _w[6:0]}, QINV [_w]);
+ end
+ endtask
+
+
+ //
+ // get_output;
+ //
+ task get_output;
+ begin
+ for (_w=0; _w<TB_NUM_WORDS_N; _w=_w+1) bus_read(2'd2, BANK_OUT_XM, _w[6:0], XM_READBACK[_w]);
+ for (_w=0; _w<TB_NUM_WORDS_N; _w=_w+1) bus_read(2'd2, BANK_OUT_YM, _w[6:0], YM_READBACK[_w]);
+ for (_w=0; _w<TB_NUM_WORDS_N; _w=_w+1) bus_read(2'd2, BANK_OUT_S, _w[6:0], S_READBACK[_w]);
+ end
+ endtask
+
+
+ //
+ // verify;
+ //
+ task verify;
+ //
+ 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_clock_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_clock_bus_tick;
+ data = bus_data_rd;
+ _bus_drive(1'b0, 1'b0, 12'hXXX, 32'hXXXXXXXX);
+ end
+ endtask
+
+
+ //
+ // _wait_half_clock_tick()
+ //
+ task _wait_half_clock_tick;
+ #`CLK_PERIOD_HALF_NS;
+ endtask
+
+ //
+ // wait_clock_tick()
+ //
+ task wait_clock_tick;
+ begin
+ _wait_half_clock_tick;
+ _wait_half_clock_tick;
+ end
+ endtask
+
+
+ //
+ // wait_clock_bus_tick()
+ //
+ task wait_clock_bus_tick;
+ #`CLK_BUS_PERIOD_NS;
+ endtask
+
+
+ //
+ // wait_clock_ticks()
+ //
+ task wait_clock_ticks;
+ input integer num_ticks;
+ for (_n=0; _n<num_ticks; _n=_n+1)
+ wait_clock_tick;
+ endtask
+
+
+ //
+ // wait_clock_bus_ticks()
+ //
+ task wait_clock_bus_ticks;
+ input integer num_ticks;
+ for (_n=0; _n<num_ticks; _n=_n+1)
+ wait_clock_bus_tick;
+ endtask
+
+endmodule