//======================================================================
//
// Copyright: 2019, The Commons Conservancy Cryptech Project
// SPDX-License-Identifier: BSD-3-Clause
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// - Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// - Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// - Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//======================================================================
`timescale 1ns / 1ps
module tb_wrapper;
//
// 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_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_bus) clk_bus_dly <= #(`CLK_BUS_PERIOD_HALF_NS - `CLK_PERIOD_QUARTER_NS) clk_bus;
//
// Clock Sync
//
task sync_clk_bus;
while (clk_bus_idle !== 1) _wait_quarter_clk_tick;
endtask
//
// Reset
//
reg rst_n = 1'b0;
//
// 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;
//
// UUT
//
modexpng_wrapper uut
(
.clk (clk_bus),
.rst_n (rst_n),
.clk_core (clk),
.cs (bus_cs),
.we (bus_we),
.address (bus_addr),
.write_data (bus_data_wr),
.read_data (bus_data_rd)
);
//
// Script
//
initial main;
//
// Main Routine (Control/Status, Bus)
//
reg [31:0] ti, to;
task main;
begin
sync_clk_bus;
wait_clk_bus_ticks(100);
rst_n = 1'b1;
wait_clk_bus_ticks(100);
// use the following code to observe how the core handles invalid parameter settings...
/*
bus_read('h11, to); $display("modulus_bits = %0d", to);
ti = 100; bus_write('h11, ti); bus_read('h11, to); $display("modulus_bits = %0d -> %0d", ti, to);
ti = 510; bus_write('h11, ti); bus_read('h11, to); $display("modulus_bits = %0d -> %0d", ti, to);
ti = 511; bus_write('h11, ti); bus_read('h11, to); $display("modulus_bits = %0d -> %0d", ti, to);
ti = 512; bus_write('h11, ti); bus_read('h11, to); $display("modulus_bits = %0d -> %0d", ti, to);
ti = 513; bus_write('h11, ti); bus_read('h11, to); $display("modulus_bits = %0d -> %0d", ti, to);
ti = 514; bus_write('h11, ti); bus_read('h11, to); $display("modulus_bits = %0d -> %0d", ti, to);
ti = 1022; bus_write('h11, ti); bus_read('h11, to); $display("modulus_bits = %0d -> %0d", ti, to);
ti = 1023; bus_write('h11, ti); bus_read('h11, to); $display("modulus_bits = %0d -> %0d", ti, to);
ti = 1024; bus_write('h11, ti); bus_read('h11, to); $display("modulus_bits = %0d -> %0d", ti, to);
ti = 1025; bus_write('h11, ti); bus_read('h11, to); $display("modulus_bits = %0d -> %0d", ti, to);
ti = 1026; bus_write('h11, ti); bus_read('h11, to); $display("modulus_bits = %0d -> %0d", ti, to);
ti = 4094; bus_write('h11, ti); bus_read('h11, to); $display("modulus_bits = %0d -> %0d", ti, to);
ti = 4095; bus_write('h11, ti); bus_read('h11, to); $display("modulus_bits = %0d -> %0d", ti, to);
ti = 4096; bus_write('h11, ti); bus_read('h11, to); $display("modulus_bits = %0d -> %0d", ti, to);
ti = 4097; bus_write('h11, ti); bus_read('h11, to); $display("modulus_bits = %0d -> %0d", ti, to);
ti = 4098; bus_write('h11, ti); bus_read('h11, to); $display("modulus_bits = %0d -> %0d", ti, to);
bus_read('h12, to); $display("exponent_bits = %0d", to);
ti = 0; bus_write('h12, ti); bus_read('h12, to); $display("exponent_bits = %0d -> %0d", ti, to);
ti = 1; bus_write('h12, ti); bus_read('h12, to); $display("exponent_bits = %0d -> %0d", ti, to);
ti = 2; bus_write('h12, ti); bus_read('h12, to); $display("exponent_bits = %0d -> %0d", ti, to);
ti = 3; bus_write('h12, ti); bus_read('h12, to); $display("exponent_bits = %0d -> %0d", ti, to);
ti = 4; bus_write('h12, ti); bus_read('h12, to); $display("exponent_bits = %0d -> %0d", ti, to);
ti = 5; bus_write('h12, ti); bus_read('h12, to); $display("exponent_bits = %0d -> %0d", ti, to);
ti = 6; bus_write('h12, ti); bus_read('h12, to); $display("exponent_bits = %0d -> %0d", ti, to);
ti = 7; bus_write('h12, ti); bus_read('h12, to); $display("exponent_bits = %0d -> %0d", ti, to);
ti = 8; bus_write('h12, ti); bus_read('h12, to); $display("exponent_bits = %0d -> %0d", ti, to);
ti = 100; bus_write('h12, ti); bus_read('h12, to); $display("exponent_bits = %0d -> %0d", ti, to);
ti = 510; bus_write('h12, ti); bus_read('h12, to); $display("exponent_bits = %0d -> %0d", ti, to);
ti = 511; bus_write('h12, ti); bus_read('h12, to); $display("exponent_bits = %0d -> %0d", ti, to);
ti = 512; bus_write('h12, ti); bus_read('h12, to); $display("exponent_bits = %0d -> %0d", ti, to);
ti = 513; bus_write('h12, ti); bus_read('h12, to); $display("exponent_bits = %0d -> %0d", ti, to);
ti = 514; bus_write('h12, ti); bus_read('h12, to); $display("exponent_bits = %0d -> %0d", ti, to);
ti = 1022; bus_write('h12, ti); bus_read('h12, to); $display("exponent_bits = %0d -> %0d", ti, to);
ti = 1023; bus_write('h12, ti); bus_read('h12, to); $display("exponent_bits = %0d -> %0d", ti, to);
ti = 1024; bus_write('h12, ti); bus_read('h12, to); $display("exponent_bits = %0d -> %0d", ti, to);
ti = 1025; bus_write('h12, ti); bus_read('h12, to); $display("exponent_bits = %0d -> %0d", ti, to);
ti = 1026; bus_write('h12, ti); bus_read('h12, to); $display("exponent_bits = %0d -> %0d", ti, to);
ti = 4094; bus_write('h12, ti); bus_read('h12, to); $display("exponent_bits = %0d -> %0d", ti, to);
ti = 4095; bus_write('h12, ti); bus_read('h12, to); $display("exponent_bits = %0d -> %0d", ti, to);
ti = 4096; bus_write('h12, ti); bus_read('h12, to); $display("exponent_bits = %0d -> %0d", ti, to);
ti = 4097; bus_write('h12, ti); bus_read('h12, to); $display("exponent_bits = %0d -> %0d", ti, to);
ti = 4098; bus_write('h12, ti); bus_read('h12, to); $display("exponent_bits = %0d -> %0d", ti, to);*/
// use the following to observe how the core handles "next" bit rising edge
//ti = 0; bus_write('h08, ti);
//ti = 2; bus_write('h08, ti);
//ti = 0; bus_write('h08, ti);
//ti = 2; bus_write('h08, ti);
//ti = 0; bus_write('h08, ti);
//ti = 2; bus_write('h08, ti);
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 [ 9:0] offset;
input [31:0] data;
begin
_bus_drive(1'b1, 1'b1, {2'b00, offset}, data);
wait_clk_bus_tick;
_bus_drive(1'b0, 1'b0, 12'hXXX, 32'hXXXXXXXX);
end
endtask
//
// bus_read()
//
task bus_read;
input [ 9:0] offset;
output [31:0] data;
begin
_bus_drive(1'b1, 1'b0, {2'b00, offset}, 32'hXXXXXXXX);
wait_clk_bus_tick;
data = bus_data_rd;
_bus_drive(1'b0, 1'b0, 12'hXXX, 32'hXXXXXXXX);
end
endtask
//
// Variables
//
integer _n;
//
// _wait_quarter_clk_tick()
//
task _wait_quarter_clk_tick;
#`CLK_PERIOD_QUARTER_NS;
endtask
//
// wait_clk_bus_tick()
//
task wait_clk_bus_tick;
#`CLK_BUS_PERIOD_NS;
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
endmodule