//======================================================================
//
// tb_core_selector.v
// ------------------
//
// Author: Pavel Shatov
// Copyright 2020 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_core_selector;
//
// System Clock, System Reset
//
`define SYS_CLK_FREQUENCY_MHZ ( 100.0 )
`define SYS_CLK_PERIOD_NS (1000.0 / `SYS_CLK_FREQUENCY_MHZ)
`define SYS_CLK_PERIOD_HALF_NS ( 0.5 * `SYS_CLK_PERIOD_NS )
reg sys_clk = 1'b0;
initial forever #`SYS_CLK_PERIOD_HALF_NS sys_clk = ~sys_clk;
`define SYS_RST_N_ACTIVE 1'b0
`define SYS_RST_N_INACTIVE 1'b1
reg sys_rst_n = `SYS_RST_N_ACTIVE;
//
// System Bus
//
reg [23: 0] sys_fmc_addr;
reg sys_fmc_wr = 1'b0;
reg sys_fmc_rd = 1'b0;
wire [31: 0] sys_read_data;
reg [31: 0] sys_write_data;
wire sys_error;
//
// UUT
//
core_selector uut
(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.sys_fmc_addr (sys_fmc_addr),
.sys_fmc_wr (sys_fmc_wr),
.sys_fmc_rd (sys_fmc_rd),
.sys_read_data (sys_read_data),
.sys_write_data (sys_write_data),
.sys_error (sys_error),
.mkm_sclk (),
.mkm_cs_n (),
.mkm_do (1'b0),
.mkm_di (),
.core_clk (1'b0),
.noise (1'b0),
.debug ()
);
//
// Script
//
//
// Here's what the following routine does. We know that at address 0 there's always a BOARD_REGS core, which
// has a 32-bit dummy register at offset 255. ECDSA cores also have a 32-bit dummy register at offset 15.
// We write some values into the two dummy registers to test the address decoding logic (we write to two cores
// with different numbers, the offsets of registers are also different). Then we do a readback and compare
// the read value with the written one. The code assumes, that the default "hsm" core configuration is used,
// where the number of ECDSA-256 is 0x37. If this is not the case, adapt the first parameter passed to the
// sys_bus_write() calls.
//
localparam [31:0] MAGIC_1 = 32'hCCAA5533;
localparam [31:0] MAGIC_2 = 32'hCA5335AC;
reg [31:0] wr, rd;
initial begin
wait_sys_clk_ticks(200);
sys_rst_n = `SYS_RST_N_INACTIVE;
wait_sys_clk_ticks(100);
wr = MAGIC_1;
sys_bus_write(16'h0000, 8'd255, wr);
wait_sys_clk_ticks(10);
wr = MAGIC_2;
sys_bus_write(16'h0037, 8'd15, wr);
wait_sys_clk_ticks(10);
wr = MAGIC_1;
sys_bus_read(16'h0000, 8'd255, rd);
wait_sys_clk_ticks(10);
if (rd !== wr) begin
$display("ERROR: wr = 0x%08x, rd = 0x%08x", wr, rd);
wait_sys_clk_ticks(100);
$finish;
end
wr = MAGIC_2;
sys_bus_read(16'h0037, 8'd15, rd);
wait_sys_clk_ticks(10);
if (rd !== wr) begin
$display("ERROR: wr = 0x%08x, rd = 0x%08x", wr, rd);
wait_sys_clk_ticks(100);
$finish;
end
$display("Test passed.");
$finish;
end
//
// _wait_half_sys_clk_tick()
//
task _wait_half_sys_clk_tick;
#`SYS_CLK_PERIOD_HALF_NS;
endtask
//
// wait_sys_clk_tick()
//
task wait_sys_clk_tick;
begin
_wait_half_sys_clk_tick;
_wait_half_sys_clk_tick;
end
endtask
//
// wait_sys_clk_ticks()
//
task wait_sys_clk_ticks;
input integer _num_ticks;
integer _n;
for (_n=0; _n<_num_ticks; _n=_n+1)
wait_sys_clk_tick;
endtask
//
// _sys_bus_drive()
//
task _sys_bus_drive;
input [23: 0] _addr;
input _wr;
input _rd;
input [31: 0] _write_data;
{sys_fmc_addr, sys_fmc_wr, sys_fmc_rd, sys_write_data} <=
{ _addr, _wr, _rd, _write_data} ;
endtask
//
// sys_bus_read()
//
task sys_bus_read;
input [15:0] _num;
input [ 7:0] _reg;
output [31:0] _data;
begin
_sys_bus_drive({_num, _reg}, 1'b0, 1'b1, {32{1'bX}});
wait_sys_clk_tick;
_sys_bus_drive(24'hXXXX, 1'b0, 1'b0, {32{1'bX}});
wait_sys_clk_ticks(3);
_data = sys_read_data;
_sys_bus_drive(24'hXXXX, 1'b0, 1'b0, {32{1'bX}});
end
endtask
//
// sys_bus_write()
//
task sys_bus_write;
input [15:0] _num;
input [ 7:0] _reg;
input [31:0] _data;
begin
_sys_bus_drive({_num, _reg}, 1'b1, 1'b0, _data);
wait_sys_clk_tick;
_sys_bus_drive(24'hXXXX, 1'b0, 1'b0, {32{1'bX}});
end
endtask
endmodule