aboutsummaryrefslogtreecommitdiff
path: root/bench
diff options
context:
space:
mode:
authorPavel V. Shatov (Meister) <meisterpaul1@yandex.ru>2019-10-21 12:56:30 +0300
committerPavel V. Shatov (Meister) <meisterpaul1@yandex.ru>2019-10-21 12:56:30 +0300
commit9eac252242c69e51a38a9a88c87b564dd40b6257 (patch)
treeab6653950a7f2a811598c73f15116fa5c009ec5c /bench
parent36339014ec3d3ad3bb4622392d5075d674e7dbeb (diff)
Entire CRT signature algorithm works by now.
Moved micro-operations handler into a separate module file, this way we don't have any synthesized stuff in the top-level module, just instantiations. This is more consistent from the design partitioning point of view. Btw, Xilinx claims their tools work better that way too, but who knows... Added optional simulation-only code to assist debugging. Un-comment the ENABLE_DEBUG `define in 'rtl/modexpng_parameters.vh' to use, but don't ever try to synthesize the core with debugging enabled.
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