//======================================================================
//
// tb_keywrap_mkm.v
// ----------------
// Testbench for the mkmif wrapper in keywrap.
//
//
// Author: Joachim Strombergson
// Copyright (c) 2018, NORDUnet A/S
// All rights reserved.
//
// 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 NORDUnet 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.
//
//======================================================================
// We need this since the specific memory module sets timescale.
`timescale 1ns/10ps
module tb_keywrap_mkmif();
//----------------------------------------------------------------
// Parameters.
//----------------------------------------------------------------
parameter DEBUG = 1;
parameter CLK_HALF_PERIOD = 1;
parameter CLK_PERIOD = 2 * CLK_HALF_PERIOD;
//----------------------------------------------------------------
// Variables, regs and wires.
//----------------------------------------------------------------
integer cycle_ctr;
integer error_ctr;
integer tc_ctr;
integer show_spi;
integer show_dut_state;
integer show_mem_state;
integer show_mkm_state;
reg tb_clk;
reg tb_reset_n;
wire tb_mkm_spi_sclk;
wire tb_mkm_spi_cs_n;
wire tb_mkm_spi_do;
wire tb_mkm_spi_di;
reg tb_init;
reg tb_read;
reg tb_write;
reg tb_key_status;
wire tb_ready;
reg [31 : 0] tb_wr_status;
wire [31 : 0] tb_rd_status;
reg [255 : 0] tb_wr_key;
wire [255 : 0] tb_rd_key;
wire mem_hold_n = 1'b1;
//----------------------------------------------------------------
// Device Under Test.
//----------------------------------------------------------------
keywrap_mkmif dut(
.clk(tb_clk),
.reset_n(tb_reset_n),
.mkm_spi_sclk(tb_mkm_spi_sclk),
.mkm_spi_cs_n(tb_mkm_spi_cs_n),
.mkm_spi_do(tb_mkm_spi_do),
.mkm_spi_di(tb_mkm_spi_di),
.init(tb_init),
.read(tb_read),
.write(tb_write),
.key_status(tb_key_status),
.ready(tb_ready),
.wr_status(tb_wr_status),
.rd_status(tb_rd_status),
.wr_key(tb_wr_key),
.rd_key(tb_rd_key)
);
//----------------------------------------------------------------
// Memory model. See README.md in src/tech for info on how
// to get the vendor specific model needed here.
//----------------------------------------------------------------
M23K640 mem(.SI(tb_mkm_spi_di),
.SO(tb_mkm_spi_do),
.SCK(tb_mkm_spi_sclk),
.CS_N(tb_mkm_spi_cs_n),
.HOLD_N(mem_hold_n),
.RESET(tb_reset_n));
//----------------------------------------------------------------
// clk_gen
//
// Always running clock generator process.
//----------------------------------------------------------------
always
begin : clk_gen
#CLK_HALF_PERIOD;
tb_clk = !tb_clk;
end // clk_gen
//----------------------------------------------------------------
// sys_monitor()
//
// An always running process that creates a cycle counter and
// conditionally displays information about the DUT.
//----------------------------------------------------------------
always
begin : sys_monitor
cycle_ctr = cycle_ctr + 1;
$display("cycle: %08d", cycle_ctr);
if (show_dut_state)
begin
$display("DUT control state:");
$display("init: 0x%01x read: 0x%01x write: 0x%01x key_status: 0x%01x",
dut.init, dut.read, dut.write, dut.key_status);
$display("ready: 0x%01x ctrl_state: 0x%02x", dut.ready, dut.keywrap_mkmif_ctrl_reg);
$display();
end
if (show_mkm_state)
begin
$display("MKM control state:");
$display("ready: 0x%1x ctrl: 0x%1x", dut.mkm_ready, dut.mkm.mkmif_ctrl_reg);
$display();
end
if (show_mem_state)
begin
$display("Memory control state:");
$display("Hold: 0x%1x BitCounter: 0x%04x", mem.Hold, mem.BitCounter);
$display("DataShifterI: 0x%02x DataShifterO: 0x%1x", mem.DataShifterI, mem.DataShifterO);
$display("InstRegister: 0x%1x AddrRegister: 0x%02x", mem.InstRegister, mem.AddrRegister);
$display("OpMode0: 0x%1x OpMode1: 0x%1x", mem.OpMode0, mem.OpMode1);
$display("InstructionREAD: 0x%1x InstructionRDSR: 0x%1x", mem.InstructionREAD, mem.InstructionRDSR);
$display("InstructionWRSR: 0x%1x InstructionWRITE: 0x%1x", mem.InstructionWRSR, mem.InstructionWRITE);
$display();
end
if (show_spi)
begin
$display("SPI interface state:");
$display("spi_clk: 0x%01x, spi_cs_n: 0x%01x, spi_do: 0x%01x, spi_di: 0x%01x",
tb_mkm_spi_sclk, tb_mkm_spi_cs_n, tb_mkm_spi_do, tb_mkm_spi_di);
end
$display("\n");
#(CLK_PERIOD);
end
//----------------------------------------------------------------
// dump_mem
//
// Dump the contents of the memory model.
//----------------------------------------------------------------
task dump_mem;
begin : dump_mem
integer i;
$display("Contents of the first 256 bytes in the serial memory:");
for (i = 0 ; i < 256 ; i = i + 8)
$display("0x%01x 0x%01x 0x%01x 0x%01x 0x%01x 0x%01x 0x%01x 0x%01x",
mem.MemoryBlock[i], mem.MemoryBlock[i + 1],
mem.MemoryBlock[i + 2], mem.MemoryBlock[i + 3],
mem.MemoryBlock[i + 4], mem.MemoryBlock[i + 5],
mem.MemoryBlock[i + 6], mem.MemoryBlock[i + 7]);
end
endtask // dump_mem
//----------------------------------------------------------------
// init_sim()
//
// Initialize all counters and testbed functionality as well
// as setting the DUT inputs to defined values.
//----------------------------------------------------------------
task init_sim;
begin
cycle_ctr = 0;
error_ctr = 0;
tc_ctr = 0;
show_spi = 0;
show_dut_state = 0;
show_mem_state = 0;
show_mkm_state = 0;
tb_clk = 1'h0;
tb_reset_n = 1'h1;
tb_init = 1'h0;
tb_read = 1'h0;
tb_write = 1'h0;
tb_key_status = 1'h0;
tb_wr_status = 32'h0;
tb_wr_key = 256'h0;
#(CLK_PERIOD);
end
endtask // init_sim
//----------------------------------------------------------------
// reset_dut()
//
// Toggle reset to put the DUT into a well known state.
//----------------------------------------------------------------
task reset_dut;
begin
$display("Asserting reset.");
$display();
tb_reset_n = 0;
#(2 * CLK_PERIOD);
tb_reset_n = 1;
$display("Deasserting reset.");
$display();
end
endtask // reset_dut
//----------------------------------------------------------------
// wait_ready()
//
// Wait for ready to be asserted.
//----------------------------------------------------------------
task wait_ready;
begin
#(2 * CLK_PERIOD);
while (!tb_ready)
#(CLK_PERIOD);
$display("Ready has been set.");
$display();
end
endtask // wait_ready
//----------------------------------------------------------------
// test_init_mem
//----------------------------------------------------------------
task test_init_mem;
begin
tc_ctr = tc_ctr + 1;
$display("TEST INIT-MEM START");
$display("Check that the memory is configured when pulling init.");
$display();
show_spi = 0;
tb_init = 1'h1;
#(CLK_PERIOD);
tb_init = 1'h0;
wait_ready();
show_spi = 0;
$display("TEST INIT-MEM END");
$display("");
end
endtask // test_init_mem
//----------------------------------------------------------------
// test_write_status
//----------------------------------------------------------------
task test_write_status;
begin
tc_ctr = tc_ctr + 1;
$display("TEST WRITE-STATUS START");
$display("Check that we can write the status word.");
// Observe SPI for a number of cycles. Reset the DUT during observation.
show_spi = 0;
#(10 * CLK_PERIOD);
$display("Trying to write 0xdeadbeef to status address.");
tb_wr_status = 32'hdeadbeef;
tb_key_status = 1'h0;
tb_write = 1'h1;
#(CLK_PERIOD);
tb_write = 1'h0;
wait_ready();
show_spi = 0;
// Check content in memory.
if ((mem.MemoryBlock[0] == 8'hde) && (mem.MemoryBlock[1] == 8'had) &&
(mem.MemoryBlock[2] == 8'hbe) && (mem.MemoryBlock[3] == 8'hef))
$display("Correct status word was written into the memory.");
else
begin
$display("Correct status word was NOT written into the memory.");
error_ctr = error_ctr + 1;
end
$display("TEST WRITE-STATUS END");
$display("");
end
endtask // test_write_status
//----------------------------------------------------------------
// test_read_status
// Note: This test should be called after test_write_status.
// If not the contents of the memort will be undefined.
//----------------------------------------------------------------
task test_read_status;
begin
tc_ctr = tc_ctr + 1;
$display("TEST READ-STATUS START");
$display("Check that we can read the status word.");
// Observe SPI for a number of cycles. Reset the DUT during observation.
show_spi = 0;
show_dut_state = 1;
#(10 * CLK_PERIOD);
$display("Trying to read 0xdeadbeef from the status address.");
tb_key_status = 1'h0;
tb_read = 1'h1;
#(CLK_PERIOD);
tb_read = 1'h0;
wait_ready();
show_spi = 0;
$display("The word read: 0x%04x", tb_rd_status);
$display("TEST READ-STATUS END");
$display("");
end
endtask // test_read_status
//----------------------------------------------------------------
// test_write_key
//----------------------------------------------------------------
task test_write_key;
begin
tc_ctr = tc_ctr + 1;
$display("TEST WRITE-KEY START");
$display("Check that we can write the key words.");
// Observe SPI for a number of cycles. Reset the DUT during observation.
show_spi = 0;
#(10 * CLK_PERIOD);
$display("Trying to write test key to key address.");
$display("test key: 0x01020304 0xaa55aa55 0x00ff00ff 0x0f0e0d0c");
$display(" 0x11121314 0x55aa55aa 0x11ee11ee 0x1f1e1d1c");
tb_wr_key = 256'h01020304_aa55aa55_00ff00ff_0f0e0d0c_11121314_55aa55aa_11ee11ee_1f1e1d1c;
tb_key_status = 1'h1;
tb_write = 1'h1;
#(CLK_PERIOD);
tb_write = 1'h0;
wait_ready();
show_spi = 0;
$display("TEST WRITE-KEY END");
$display("");
end
endtask // test_write_key
//----------------------------------------------------------------
// main
//----------------------------------------------------------------
initial
begin : main
$display(" -= Testbench for Keywrap mkmif integration started =-");
$display(" ====================================================");
$display("");
init_sim();
reset_dut();
dump_mem();
test_init_mem();
test_write_status();
// test_read_status();
// test_write_key();
dump_mem();
$display("");
$display("*** Keywrap mkmif integration testbench done. ***");
$finish;
end // main
endmodule // tb_keywrap_mkmif
//======================================================================
// EOF tb_keywrap_mkmif.v
//======================================================================