aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/rtl/keywrap.v146
-rw-r--r--src/rtl/keywrap_core.v139
-rw-r--r--src/rtl/keywrap_mkmif.v449
-rw-r--r--src/tb/tb_keywrap.v24
-rw-r--r--src/tb/tb_keywrap_core.v52
-rw-r--r--src/tb/tb_keywrap_mkmif.v434
-rw-r--r--src/tech/README.md14
7 files changed, 1181 insertions, 77 deletions
diff --git a/src/rtl/keywrap.v b/src/rtl/keywrap.v
index 2033b23..2e9a7f6 100644
--- a/src/rtl/keywrap.v
+++ b/src/rtl/keywrap.v
@@ -53,6 +53,11 @@ module keywrap #(parameter ADDR_BITS = 12)
input wire clk,
input wire reset_n,
+ output wire mkm_spi_sclk,
+ output wire mkm_spi_cs_n,
+ input wire mkm_spi_do,
+ output wire mkm_spi_di,
+
input wire cs,
input wire we,
@@ -65,42 +70,52 @@ module keywrap #(parameter ADDR_BITS = 12)
//----------------------------------------------------------------
// Internal constant and parameter definitions.
//----------------------------------------------------------------
- localparam ADDR_NAME0 = 8'h00;
- localparam ADDR_NAME1 = 8'h01;
- localparam ADDR_VERSION = 8'h02;
+ localparam ADDR_NAME0 = 8'h00;
+ localparam ADDR_NAME1 = 8'h01;
+ localparam ADDR_VERSION = 8'h02;
- localparam ADDR_CTRL = 8'h08;
- localparam CTRL_INIT_BIT = 0;
- localparam CTRL_NEXT_BIT = 1;
+ localparam ADDR_CTRL = 8'h08;
+ localparam CTRL_INIT_BIT = 0;
+ localparam CTRL_NEXT_BIT = 1;
+ localparam CTRL_READ_BIT = 2;
+ localparam CTRL_WRITE_BIT = 3;
localparam ADDR_STATUS = 8'h09;
localparam STATUS_READY_BIT = 0;
localparam STATUS_VALID_BIT = 1;
- localparam ADDR_CONFIG = 8'h0a;
- localparam CTRL_ENCDEC_BIT = 0;
- localparam CTRL_KEYLEN_BIT = 1;
+ localparam ADDR_CONFIG = 8'h0a;
+ localparam CONFIG_ENCDEC_BIT = 0;
+ localparam CONFIG_KEYLEN_BIT = 1;
+ localparam CONFIG_MKS_BIT = 2;
+
+ localparam ADDR_RLEN = 8'h0c;
+ localparam ADDR_A0 = 8'h0e;
+ localparam ADDR_A1 = 8'h0f;
+
+ localparam ADDR_KEY0 = 8'h10;
+ localparam ADDR_KEY1 = 8'h11;
+ localparam ADDR_KEY2 = 8'h12;
+ localparam ADDR_KEY3 = 8'h13;
+ localparam ADDR_KEY4 = 8'h14;
+ localparam ADDR_KEY5 = 8'h15;
+ localparam ADDR_KEY6 = 8'h16;
+ localparam ADDR_KEY7 = 8'h17;
- localparam ADDR_RLEN = 8'h0c;
- localparam ADDR_A0 = 8'h0e;
- localparam ADDR_A1 = 8'h0f;
+ localparam ADDR_MSTATUS = 8'h20;
- localparam ADDR_KEY0 = 8'h10;
- localparam ADDR_KEY1 = 8'h11;
- localparam ADDR_KEY2 = 8'h12;
- localparam ADDR_KEY3 = 8'h13;
- localparam ADDR_KEY4 = 8'h14;
- localparam ADDR_KEY5 = 8'h15;
- localparam ADDR_KEY6 = 8'h16;
- localparam ADDR_KEY7 = 8'h17;
+ localparam CORE_NAME0 = 32'h6b657920; // "key "
+ localparam CORE_NAME1 = 32'h77726170; // "wrap"
+ localparam CORE_VERSION = 32'h302e3830; // "0.80"
- localparam CORE_NAME0 = 32'h6b657920; // "key "
- localparam CORE_NAME1 = 32'h77726170; // "wrap"
- localparam CORE_VERSION = 32'h302e3830; // "0.80"
+ localparam MEM_BITS = ADDR_BITS - 1;
+ localparam RLEN_BITS = ADDR_BITS - 2;
+ localparam PAD = ADDR_BITS - 8;
- localparam MEM_BITS = ADDR_BITS - 1;
- localparam RLEN_BITS = ADDR_BITS - 2;
- localparam PAD = ADDR_BITS - 8;
+
+ // If set to one, will allow read access to key memory.
+ // Should be set to zero in all production FPGA bitstreams.
+ localparam DEBUG_MKM_READ = 1'h1;
//----------------------------------------------------------------
@@ -112,6 +127,15 @@ module keywrap #(parameter ADDR_BITS = 12)
reg next_reg;
reg next_new;
+ reg read_reg;
+ reg read_new;
+
+ reg write_reg;
+ reg write_new;
+
+ reg mkey_mstatus_reg;
+ reg mkey_mstatus_new;
+
reg encdec_reg;
reg keylen_reg;
reg config_we;
@@ -128,6 +152,9 @@ module keywrap #(parameter ADDR_BITS = 12)
reg [31 : 0] key_reg [0 : 7];
reg key_we;
+ reg [31 : 0] mstatus_reg;
+ reg mstatus_we;
+
reg [31 : 0] api_rd_delay_reg;
reg [31 : 0] api_rd_delay_new;
@@ -146,6 +173,8 @@ module keywrap #(parameter ADDR_BITS = 12)
wire core_ready;
wire core_valid;
wire [255 : 0] core_key;
+ wire [255 : 0] core_mkey;
+ wire [31 : 0] core_mstatus;
wire [63 : 0] core_a_init;
wire [63 : 0] core_a_result;
wire [31 : 0] core_api_rd_data;
@@ -166,15 +195,23 @@ module keywrap #(parameter ADDR_BITS = 12)
//----------------------------------------------------------------
- // core instantiation.
+ // keywrap core instantiation.
//----------------------------------------------------------------
keywrap_core #(.MEM_BITS(MEM_BITS))
core(
.clk(clk),
.reset_n(reset_n),
+ .mkm_spi_sclk(mkm_spi_sclk),
+ .mkm_spi_cs_n(mkm_spi_cs_n),
+ .mkm_spi_do(mkm_spi_do),
+ .mkm_spi_di(mkm_spi_di),
+
.init(init_reg),
.next(next_reg),
+ .read(read_reg),
+ .write(write_reg),
+ .mkey_mstatus(mkey_mstatus_reg),
.encdec(encdec_reg),
.ready(core_ready),
@@ -184,6 +221,9 @@ module keywrap #(parameter ADDR_BITS = 12)
.key(core_key),
.keylen(keylen_reg),
+ .status(mstatus_reg),
+ .mkey(core_mkey),
+ .mstatus(core_mstatus),
.a_init(core_a_init),
.a_result(core_a_result),
@@ -209,8 +249,12 @@ module keywrap #(parameter ADDR_BITS = 12)
init_reg <= 1'h0;
next_reg <= 1'h0;
+ read_reg <= 1'h0;
+ write_reg <= 1'h0;
+ mkey_mstatus_reg <= 1'h0;
encdec_reg <= 1'h0;
keylen_reg <= 1'h0;
+ mstatus_reg <= 32'h0;
rlen_reg <= {RLEN_BITS{1'h0}};
valid_reg <= 1'h0;
ready_reg <= 1'h0;
@@ -224,12 +268,16 @@ module keywrap #(parameter ADDR_BITS = 12)
valid_reg <= core_valid;
init_reg <= init_new;
next_reg <= next_new;
+ read_reg <= read_new;
+ write_reg <= write_new;
+ mkey_mstatus_reg <= mkey_mstatus_new;
api_rd_delay_reg <= api_rd_delay_new;
if (config_we)
begin
- encdec_reg <= write_data[CTRL_ENCDEC_BIT];
- keylen_reg <= write_data[CTRL_KEYLEN_BIT];
+ mkey_mstatus_reg <= write_data[CONFIG_MKS_BIT];
+ encdec_reg <= write_data[CONFIG_ENCDEC_BIT];
+ keylen_reg <= write_data[CONFIG_KEYLEN_BIT];
end
if (rlen_we)
@@ -241,6 +289,9 @@ module keywrap #(parameter ADDR_BITS = 12)
if (a1_we)
a1_reg <= write_data;
+ if (mstatus_we)
+ mstatus_reg <= write_data;
+
if (key_we)
key_reg[address[2 : 0]] <= write_data;
end
@@ -256,21 +307,25 @@ module keywrap #(parameter ADDR_BITS = 12)
begin : api
init_new = 1'h0;
next_new = 1'h0;
+ read_new = 1'h0;
+ write_new = 1'h0;
config_we = 1'h0;
rlen_we = 1'h0;
key_we = 1'h0;
core_api_we = 1'h0;
a0_we = 1'h0;
a1_we = 1'h0;
+ mstatus_we = 1'h0;
tmp_read_data = 32'h0;
tmp_error = 1'h0;
api_rd_delay_new = 32'h0;
// api_mux
- if (address[(ADDR_BITS - 1)])
- tmp_read_data = core_api_rd_data;
- else
- tmp_read_data = api_rd_delay_reg;
+ if (core_ready)
+ if (address[(ADDR_BITS - 1)])
+ tmp_read_data = core_api_rd_data;
+ else
+ tmp_read_data = api_rd_delay_reg;
if (cs)
begin
@@ -280,8 +335,10 @@ module keywrap #(parameter ADDR_BITS = 12)
begin
if (address == {{PAD{1'h0}}, ADDR_CTRL})
begin
- init_new = write_data[CTRL_INIT_BIT];
- next_new = write_data[CTRL_NEXT_BIT];
+ init_new = write_data[CTRL_INIT_BIT];
+ next_new = write_data[CTRL_NEXT_BIT];
+ read_new = write_data[CTRL_READ_BIT];
+ write_new = write_data[CTRL_WRITE_BIT];
end
if (address == {{PAD{1'h0}}, ADDR_CONFIG})
@@ -296,6 +353,9 @@ module keywrap #(parameter ADDR_BITS = 12)
if (address == {{PAD{1'h0}}, ADDR_A1})
a1_we = 1'h1;
+ if (address == {{PAD{1'h0}}, ADDR_MSTATUS})
+ mstatus_we = 1'h1;
+
if ((address >= {{PAD{1'h0}}, ADDR_KEY0}) &&
(address <= {{PAD{1'h0}}, ADDR_KEY7}))
key_we = 1'h1;
@@ -317,12 +377,10 @@ module keywrap #(parameter ADDR_BITS = 12)
api_rd_delay_new = CORE_VERSION;
if (address == {{PAD{1'h0}}, ADDR_CTRL})
- api_rd_delay_new = {28'h0, keylen_reg, encdec_reg, next_reg, init_reg};
+ api_rd_delay_new = {26'h0, keylen_reg, encdec_reg, write_reg, read_reg, next_reg, init_reg};
if (address == {{PAD{1'h0}}, ADDR_STATUS})
- begin
- api_rd_delay_new = {30'h0, valid_reg, ready_reg};
- end
+ api_rd_delay_new = {30'h0, valid_reg, ready_reg};
if (address == {{PAD{1'h0}}, ADDR_RLEN})
api_rd_delay_new = {{(32 - RLEN_BITS){1'h0}}, rlen_reg};
@@ -332,6 +390,16 @@ module keywrap #(parameter ADDR_BITS = 12)
if (address == {{PAD{1'h0}}, ADDR_A1})
api_rd_delay_new = core_a_result[31 : 0];
+
+ if (address == {{PAD{1'h0}}, ADDR_MSTATUS})
+ api_rd_delay_new = core_mstatus;
+
+ // Warning: Should be disabled after mkmif
+ // integration has been completed.
+ if (DEBUG_MKM_READ)
+ if ((address >= {{PAD{1'h0}},ADDR_KEY0}) && (address <= {{PAD{1'h0}}, ADDR_KEY7}))
+ api_rd_delay_new = core_mkey[(7 - (address - {{PAD{1'h0}}, ADDR_KEY7})) * 32 +: 32];
+
end // else: !if(we)
end // if (cs)
end // block: api
diff --git a/src/rtl/keywrap_core.v b/src/rtl/keywrap_core.v
index b3e17f6..3abe93c 100644
--- a/src/rtl/keywrap_core.v
+++ b/src/rtl/keywrap_core.v
@@ -44,17 +44,28 @@ module keywrap_core #(parameter MEM_BITS = 11)
input wire clk,
input wire reset_n,
+ output wire mkm_spi_sclk,
+ output wire mkm_spi_cs_n,
+ input wire mkm_spi_do,
+ output wire mkm_spi_di,
+
input wire init,
input wire next,
+ input wire read,
+ input wire write,
+ input wire mkey_mstatus,
+ input wire mkey_key,
input wire encdec,
output wire ready,
output wire valid,
input wire [(MEM_BITS - 2) : 0] rlen,
-
input wire [255 : 0] key,
input wire keylen,
+ input wire [31 : 0] status,
+ output wire [255 : 0] mkey,
+ output wire [31 : 0] mstatus,
input wire [63 : 0] a_init,
output wire [63 : 0] a_result,
@@ -71,17 +82,19 @@ module keywrap_core #(parameter MEM_BITS = 11)
//----------------------------------------------------------------
localparam MAX_ITERATIONS = 6 - 1;
- localparam CTRL_IDLE = 4'h0;
- localparam CTRL_INIT_WAIT = 4'h1;
- localparam CTRL_NEXT_WSTART = 4'h2;
- localparam CTRL_NEXT_USTART = 4'h3;
- localparam CTRL_NEXT_LOOP0 = 4'h4;
- localparam CTRL_NEXT_LOOP = 4'h5;
- localparam CTRL_NEXT_WAIT = 4'h6;
- localparam CTRL_NEXT_UPDATE = 4'h7;
- localparam CTRL_NEXT_WCHECK = 4'h8;
- localparam CTRL_NEXT_UCHECK = 4'h9;
- localparam CTRL_NEXT_FINALIZE = 4'ha;
+ localparam CTRL_RESET = 4'h0;
+ localparam CTRL_IDLE = 4'h1;
+ localparam CTRL_INIT_WAIT = 4'h2;
+ localparam CTRL_NEXT_WSTART = 4'h3;
+ localparam CTRL_NEXT_USTART = 4'h4;
+ localparam CTRL_NEXT_LOOP0 = 4'h5;
+ localparam CTRL_NEXT_LOOP = 4'h6;
+ localparam CTRL_NEXT_WAIT = 4'h7;
+ localparam CTRL_NEXT_UPDATE = 4'h8;
+ localparam CTRL_NEXT_WCHECK = 4'h9;
+ localparam CTRL_NEXT_UCHECK = 4'ha;
+ localparam CTRL_NEXT_FINALIZE = 4'hb;
+ localparam CTRL_MKM_WAIT = 4'hc;
//----------------------------------------------------------------
@@ -130,6 +143,7 @@ module keywrap_core #(parameter MEM_BITS = 11)
wire aes_valid;
reg [127 : 0] aes_block;
wire [127 : 0] aes_result;
+ reg [255 : 0] aes_key;
reg update_state;
@@ -138,6 +152,15 @@ module keywrap_core #(parameter MEM_BITS = 11)
reg [63 : 0] core_wr_data;
wire [63 : 0] core_rd_data;
+ reg mkm_init;
+ reg mkm_read;
+ reg mkm_write;
+ reg mkm_key_status;
+ wire mkm_ready;
+ wire [255 : 0] mkm_rd_key;
+ wire [31 : 0] mkm_rd_status;
+ wire [31 : 0] mkm_wr_status;
+
//----------------------------------------------------------------
// Instantiations.
@@ -166,7 +189,7 @@ module keywrap_core #(parameter MEM_BITS = 11)
.init(aes_init),
.next(aes_next),
- .key(key),
+ .key(aes_key),
.keylen(keylen),
.block(aes_block),
@@ -177,12 +200,36 @@ module keywrap_core #(parameter MEM_BITS = 11)
);
+ keywrap_mkmif mkmif(
+ .clk(clk),
+ .reset_n(reset_n),
+
+ .mkm_spi_sclk(mkm_spi_sclk),
+ .mkm_spi_cs_n(mkm_spi_cs_n),
+ .mkm_spi_do(mkm_spi_do),
+ .mkm_spi_di(mkm_spi_di),
+
+ .init(mkm_init),
+ .read(mkm_read),
+ .write(mkm_write),
+ .key_status(mkey_mstatus),
+ .ready(mkm_ready),
+
+ .wr_status(mkm_wr_status),
+ .rd_status(mkm_rd_status),
+ .wr_key(key),
+ .rd_key(mkm_rd_key)
+ );
+
+
//----------------------------------------------------------------
// Assignments for ports.
//----------------------------------------------------------------
- assign a_result = a_reg;
- assign ready = ready_reg;
- assign valid = valid_reg;
+ assign a_result = a_reg;
+ assign ready = ready_reg;
+ assign valid = valid_reg;
+ assign mkey = mkm_rd_key;
+ assign mstatus = mkm_rd_status;
//----------------------------------------------------------------
@@ -190,6 +237,8 @@ module keywrap_core #(parameter MEM_BITS = 11)
//----------------------------------------------------------------
always @ (posedge clk or negedge reset_n)
begin: reg_update
+ integer i;
+
if (!reset_n)
begin
a_reg <= 64'h0;
@@ -197,7 +246,7 @@ module keywrap_core #(parameter MEM_BITS = 11)
valid_reg <= 1'h0;
block_ctr_reg <= {(MEM_BITS - 1){1'h0}};
iteration_ctr_reg <= 3'h0;
- keywrap_core_ctrl_reg <= CTRL_IDLE;
+ keywrap_core_ctrl_reg <= CTRL_RESET;
end
else
@@ -333,6 +382,17 @@ module keywrap_core #(parameter MEM_BITS = 11)
end
+ //----------------------------------------------------------------
+ // aes_key_mux
+ //----------------------------------------------------------------
+ always @*
+ begin
+ if (mkey_key)
+ aes_key = mkm_rd_key;
+ else
+ aes_key = key;
+ end
+
//----------------------------------------------------------------
// keywrap_core_ctrl
@@ -347,6 +407,9 @@ module keywrap_core #(parameter MEM_BITS = 11)
update_state = 1'h0;
aes_init = 1'h0;
aes_next = 1'h0;
+ mkm_init = 1'h0;
+ mkm_read = 1'h0;
+ mkm_write = 1'h0;
block_ctr_dec = 1'h0;
block_ctr_inc = 1'h0;
block_ctr_rst = 1'h0;
@@ -355,11 +418,22 @@ module keywrap_core #(parameter MEM_BITS = 11)
iteration_ctr_dec = 1'h0;
iteration_ctr_set = 1'h0;
iteration_ctr_rst = 1'h0;
+
keywrap_core_ctrl_new = CTRL_IDLE;
keywrap_core_ctrl_we = 1'h0;
case (keywrap_core_ctrl_reg)
+ CTRL_RESET:
+ begin
+ mkm_init = 1'h1;
+ ready_new = 1'h0;
+ ready_we = 1'h1;
+ keywrap_core_ctrl_new = CTRL_MKM_WAIT;
+ keywrap_core_ctrl_we = 1'h0;
+ end
+
+
CTRL_IDLE:
begin
if (init)
@@ -386,6 +460,25 @@ module keywrap_core #(parameter MEM_BITS = 11)
keywrap_core_ctrl_new = CTRL_NEXT_USTART;
keywrap_core_ctrl_we = 1'h1;
end
+
+ if (read)
+ begin
+ mkm_read = 1'h1;
+ ready_new = 1'h0;
+ ready_we = 1'h1;
+ mkm_read = 1'h1;
+ keywrap_core_ctrl_new = CTRL_MKM_WAIT;
+ keywrap_core_ctrl_we = 1'h1;
+ end
+
+ if (write)
+ begin
+ mkm_write = 1'h1;
+ ready_new = 1'h0;
+ ready_we = 1'h1;
+ keywrap_core_ctrl_new = CTRL_MKM_WAIT;
+ keywrap_core_ctrl_we = 1'h1;
+ end
end
@@ -517,9 +610,19 @@ module keywrap_core #(parameter MEM_BITS = 11)
end
- default:
+ CTRL_MKM_WAIT:
begin
+ if (mkm_ready)
+ begin
+ ready_new = 1'h1;
+ ready_we = 1'h1;
+ keywrap_core_ctrl_new = CTRL_IDLE;
+ keywrap_core_ctrl_we = 1'h1;
+ end
+ end
+ default:
+ begin
end
endcase // case (keywrap_core_ctrl_reg)
end // keywrap_core_ctrl
diff --git a/src/rtl/keywrap_mkmif.v b/src/rtl/keywrap_mkmif.v
new file mode 100644
index 0000000..d73c5bd
--- /dev/null
+++ b/src/rtl/keywrap_mkmif.v
@@ -0,0 +1,449 @@
+//======================================================================
+//
+// keywrap_mkmif.v
+// ---------------
+// Wrapper for the mkmif_core. This allow us to simplify the
+// integration of the mkmif in keywrap_core.
+//
+//
+// 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.
+//
+//======================================================================
+
+module keywrap_mkmif (
+ input wire clk,
+ input wire reset_n,
+
+ output wire mkm_spi_sclk,
+ output wire mkm_spi_cs_n,
+ input wire mkm_spi_do,
+ output wire mkm_spi_di,
+
+ input wire init,
+ input wire read,
+ input wire write,
+ input wire key_status,
+ output wire ready,
+
+ input wire [31 : 0] wr_status,
+ output wire [31 : 0] rd_status,
+ input wire [255 : 0] wr_key,
+ output wire [255 : 0] rd_key
+ );
+
+
+ //----------------------------------------------------------------
+ // Paramenters and local defines.
+ //----------------------------------------------------------------
+ localparam CTRL_IDLE = 4'h0;
+ localparam CTRL_WAIT = 4'h1;
+ localparam CTRL_INIT = 4'h2;
+ localparam CTRL_READ = 4'h3;
+ localparam CTRL_READ_STATUS_WAIT = 4'h4;
+ localparam CTRL_READ_KEY = 4'h5;
+ localparam CTRL_READ_KEY_WAIT = 4'h6;
+ localparam CTRL_WRITE = 4'h8;
+ localparam CTRL_WRITE_KEY = 4'h9;
+ localparam CTRL_WRITE_KEY_WAIT = 4'ha;
+
+ // Addresses for storage in the mkm
+ localparam MKM_STATUS_WORD = 16'h00;
+ localparam MKM_KEY_BASE_WORD = 16'h04;
+
+ localparam DEFAULT_SCLK_DIV = 16'h0020;
+
+
+ //----------------------------------------------------------------
+ // Registers and memories including control signals.
+ //----------------------------------------------------------------
+ reg [31 : 0] key_reg [0 : 7];
+ reg key_we;
+
+ reg [2 : 0] key_word_ctr_reg;
+ reg [2 : 0] key_word_ctr_new;
+ reg key_word_ctr_we;
+ reg key_word_ctr_rst;
+ reg key_word_ctr_inc;
+
+ reg [15 : 0] mkm_addr_reg;
+ reg [15 : 0] mkm_addr_new;
+ reg mkm_addr_we;
+
+ reg [31 : 0] mkm_write_data_reg;
+ reg [31 : 0] mkm_write_data_new;
+ reg mkm_write_data_we;
+
+ reg [31 : 0] status_reg;
+ reg [31 : 0] status_new;
+ reg status_we;
+
+ reg ready_reg;
+ reg ready_new;
+ reg ready_we;
+
+ reg [3 : 0] keywrap_mkmif_ctrl_reg;
+ reg [3 : 0] keywrap_mkmif_ctrl_new;
+ reg keywrap_mkmif_ctrl_we;
+
+ reg init_op_reg;
+ reg read_op_reg;
+ reg write_op_reg;
+
+
+ //----------------------------------------------------------------
+ // Wires.
+ //----------------------------------------------------------------
+ reg mkm_init_op;
+ reg mkm_read_op;
+ reg mkm_write_op;
+ wire mkm_ready;
+ wire mkm_valid;
+ reg [15 : 0] mkm_addr;
+ reg [31 : 0] mkm_write_data;
+ wire [31 : 0] mkm_read_data;
+
+
+ //----------------------------------------------------------------
+ // Instantiations.
+ //----------------------------------------------------------------
+ mkmif_core mkm(
+ .clk(clk),
+ .reset_n(reset_n),
+
+ .spi_sclk(mkm_spi_sclk),
+ .spi_cs_n(mkm_spi_cs_n),
+ .spi_do(mkm_spi_do),
+ .spi_di(mkm_spi_di),
+
+ .init_op(init_op_reg),
+ .read_op(read_op_reh),
+ .write_op(write_op_reg),
+
+ .ready(mkm_ready),
+ .valid(mkm_valid),
+
+ .sclk_div(DEFAULT_SCLK_DIV),
+ .addr(mkm_addr_reg),
+ .write_data(mkm_write_data_reg),
+ .read_data(mkm_read_data)
+ );
+
+
+ //----------------------------------------------------------------
+ // Assignments for ports.
+ //----------------------------------------------------------------
+ assign ready = ready_reg;
+
+ assign rd_status = status_reg;
+
+ assign rd_key = {key_reg[7], key_reg[6], key_reg[5], key_reg[4],
+ key_reg[3], key_reg[2], key_reg[1], key_reg[0]};
+
+
+ //----------------------------------------------------------------
+ // reg_update
+ //----------------------------------------------------------------
+ always @ (posedge clk or negedge reset_n)
+ begin: reg_update
+ integer i;
+
+ if (!reset_n)
+ begin
+ for (i = 0 ; i < 8 ; i = i + 1)
+ key_reg[i] <= 32'h0;
+
+ ready_reg <= 1'h1;
+ status_reg <= 32'h0;
+ mkm_addr_reg <= 16'h0;
+ mkm_write_data_reg <= 32'h0;
+ key_word_ctr_reg <= 3'h0;
+ init_op_reg <= 1'h0;
+ read_op_reg <= 1'h0;
+ write_op_reg <= 1'h0;
+ keywrap_mkmif_ctrl_reg <= CTRL_IDLE;
+ end
+
+ else
+ begin
+ init_op_reg <= mkm_init_op;
+ read_op_reg <= mkm_read_op;
+ write_op_reg <= mkm_write_op;
+
+ if (ready_we)
+ ready_reg <= ready_new;
+
+ if (mkm_addr_we)
+ mkm_addr_reg <= mkm_addr_new;
+
+ if (mkm_write_data_we)
+ mkm_write_data_reg <= mkm_write_data_new;
+
+ if (key_we)
+ key_reg[key_word_ctr_reg] <= mkm_read_data;
+
+ if (status_we)
+ status_reg <= mkm_read_data;
+
+ if (key_word_ctr_we)
+ key_word_ctr_reg <= key_word_ctr_new;
+
+ if (keywrap_mkmif_ctrl_we)
+ keywrap_mkmif_ctrl_reg <= keywrap_mkmif_ctrl_new;
+ end
+ end // reg_update
+
+
+ //----------------------------------------------------------------
+ // key_word_ctr
+ //----------------------------------------------------------------
+ always @*
+ begin : key_word_ctr
+ key_word_ctr_new = 3'h0;
+ key_word_ctr_we = 1'h0;
+
+ if (key_word_ctr_rst)
+ begin
+ key_word_ctr_new = 3'h0;
+ key_word_ctr_we = 1'h1;
+ end
+
+ if (key_word_ctr_inc)
+ begin
+ key_word_ctr_new = key_word_ctr_reg + 1'h1;
+ key_word_ctr_we = 1'h1;
+ end
+
+ end
+
+
+ //----------------------------------------------------------------
+ // keywrap_mkmif_ctrl
+ //----------------------------------------------------------------
+ always @*
+ begin : keywrap_mkmif_ctrl
+ ready_new = 1'h0;
+ ready_we = 1'h0;
+ key_we = 1'h0;
+ key_word_ctr_rst = 1'h0;
+ key_word_ctr_inc = 1'h0;
+ status_we = 1'h0;
+ mkm_init_op = 1'h0;
+ mkm_read_op = 1'h0;
+ mkm_write_op = 1'h0;
+ mkm_addr_new = 16'h0;
+ mkm_addr_we = 1'h0;
+ mkm_write_data_new = 32'h0;
+ mkm_write_data_we = 1'h0;
+ keywrap_mkmif_ctrl_new = CTRL_IDLE;
+ keywrap_mkmif_ctrl_we = 1'h0;
+
+ case (keywrap_mkmif_ctrl_reg)
+ CTRL_IDLE:
+ begin
+ if (init)
+ begin
+ mkm_init_op = 1'h1;
+ ready_new = 1'h0;
+ ready_we = 1'h1;
+ keywrap_mkmif_ctrl_new = CTRL_INIT;
+ keywrap_mkmif_ctrl_we = 1'h1;
+ end
+
+ if (read)
+ begin
+ ready_new = 1'h0;
+ ready_we = 1'h1;
+ keywrap_mkmif_ctrl_new = CTRL_READ;
+ keywrap_mkmif_ctrl_we = 1'h1;
+ end
+
+ if (write)
+ begin
+ ready_new = 1'h0;
+ ready_we = 1'h1;
+ keywrap_mkmif_ctrl_new = CTRL_WRITE;
+ keywrap_mkmif_ctrl_we = 1'h1;
+ end
+ end
+
+
+ CTRL_INIT:
+ begin
+ keywrap_mkmif_ctrl_new = CTRL_WAIT;
+ keywrap_mkmif_ctrl_we = 1'h1;
+ end
+
+
+ CTRL_READ:
+ begin
+ if (key_status)
+ begin
+ key_word_ctr_rst = 1'h1;
+ keywrap_mkmif_ctrl_new = CTRL_READ_KEY;
+ keywrap_mkmif_ctrl_we = 1'h1;
+ end
+ else
+ begin
+ mkm_read_op = 1'h1;
+ mkm_addr_new = MKM_STATUS_WORD;
+ mkm_addr_we = 1'h1;
+ keywrap_mkmif_ctrl_new = CTRL_READ_STATUS_WAIT;
+ keywrap_mkmif_ctrl_we = 1'h1;
+ end
+ end
+
+
+ CTRL_WAIT:
+ begin
+ if (mkm_ready)
+ begin
+ ready_new = 1'h1;
+ ready_we = 1'h1;
+ keywrap_mkmif_ctrl_new = CTRL_IDLE;
+ keywrap_mkmif_ctrl_we = 1'h1;
+ end
+ end
+
+
+ CTRL_READ_STATUS_WAIT:
+ begin
+ ready_new = 1'h1;
+ ready_we = 1'h1;
+ keywrap_mkmif_ctrl_new = CTRL_IDLE;
+ keywrap_mkmif_ctrl_we = 1'h1;
+ if (mkm_ready)
+ begin
+ status_we = 1'h1;
+ ready_new = 1'h1;
+ ready_we = 1'h1;
+ keywrap_mkmif_ctrl_new = CTRL_IDLE;
+ keywrap_mkmif_ctrl_we = 1'h1;
+ end
+ end
+
+
+ CTRL_READ_KEY:
+ begin
+ if (key_word_ctr_reg < 8)
+ begin
+ mkm_read_op = 1'h1;
+ mkm_addr_new = MKM_KEY_BASE_WORD + {key_word_ctr_reg, 2'h0};
+ mkm_addr_we = 1'h1;
+ keywrap_mkmif_ctrl_new = CTRL_READ_KEY_WAIT;
+ keywrap_mkmif_ctrl_we = 1'h1;
+ end
+ else
+ begin
+ ready_new = 1'h1;
+ ready_we = 1'h1;
+ keywrap_mkmif_ctrl_new = CTRL_IDLE;
+ keywrap_mkmif_ctrl_we = 1'h1;
+ end
+ end
+
+
+ CTRL_READ_KEY_WAIT:
+ begin
+ if (mkm_ready)
+ begin
+ key_we = 1'h1;
+ key_word_ctr_inc = 1'h1;
+ keywrap_mkmif_ctrl_new = CTRL_READ_KEY;
+ keywrap_mkmif_ctrl_we = 1'h1;
+ end
+ end
+
+
+ CTRL_WRITE:
+ begin
+ if (key_status)
+ begin
+ key_word_ctr_rst = 1'h1;
+ keywrap_mkmif_ctrl_new = CTRL_WRITE_KEY;
+ keywrap_mkmif_ctrl_we = 1'h1;
+ end
+ else
+ begin
+ mkm_write_op = 1'h1;
+ mkm_addr_new = MKM_STATUS_WORD;
+ mkm_addr_we = 1'h1;
+ mkm_write_data_new = wr_status;
+ mkm_write_data_we = 1'h1;
+ keywrap_mkmif_ctrl_new = CTRL_WAIT;
+ keywrap_mkmif_ctrl_we = 1'h1;
+ end
+ end
+
+
+ CTRL_WRITE_KEY:
+ begin
+ if (key_word_ctr_reg < 8)
+ begin
+ mkm_write_op = 1'h1;
+ mkm_addr_new = MKM_KEY_BASE_WORD + {key_word_ctr_reg, 2'h0};
+ mkm_addr_we = 1'h1;
+ mkm_write_data_new = wr_key[key_word_ctr_reg * 32 +: 32];
+ mkm_write_data_we = 1'h1;
+ keywrap_mkmif_ctrl_new = CTRL_WRITE_KEY_WAIT;
+ keywrap_mkmif_ctrl_we = 1'h1;
+ end
+ else
+ begin
+ ready_new = 1'h1;
+ ready_we = 1'h1;
+ keywrap_mkmif_ctrl_new = CTRL_IDLE;
+ keywrap_mkmif_ctrl_we = 1'h1;
+ end
+ end
+
+
+ CTRL_WRITE_KEY_WAIT:
+ begin
+ if (mkm_ready)
+ begin
+ key_word_ctr_inc = 1'h1;
+ keywrap_mkmif_ctrl_new = CTRL_WRITE_KEY;
+ keywrap_mkmif_ctrl_we = 1'h1;
+ end
+ end
+
+
+ default:
+ begin
+ end
+ endcase // case (keywrap_mkmif_ctrl_reg)
+ end // keywrap_mkmif_ctrl
+
+endmodule // keywrap_mkmif
+
+//======================================================================
+// EOF keywrap_mkmif.v
+//======================================================================
diff --git a/src/tb/tb_keywrap.v b/src/tb/tb_keywrap.v
index b232ab3..fb02792 100644
--- a/src/tb/tb_keywrap.v
+++ b/src/tb/tb_keywrap.v
@@ -102,6 +102,10 @@ module tb_keywrap();
reg tb_clk;
reg tb_reset_n;
+ wire tb_mkm_spi_sclk;
+ wire tb_mkm_spi_cs_n;
+ reg tb_mkm_spi_do;
+ wire tb_mkm_spi_di;
reg tb_cs;
reg tb_we;
reg [(ADDR_BITS -1 ) : 0] tb_address;
@@ -116,6 +120,10 @@ module tb_keywrap();
keywrap 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),
.cs(tb_cs),
.we(tb_we),
.address(tb_address),
@@ -348,15 +356,17 @@ module tb_keywrap();
//----------------------------------------------------------------
task init_sim;
begin
- cycle_ctr = 0;
- error_ctr = 0;
- tc_ctr = 0;
+ cycle_ctr = 1'h0;
+ error_ctr = 1'h0;
+ tc_ctr = 1'h0;
- tb_clk = 0;
- tb_reset_n = 1;
+ tb_clk = 1'h0;
+ tb_reset_n = 1'h1;
- tb_cs = 0;
- tb_we = 0;
+ tb_mkm_spi_do = 1'h1;
+
+ tb_cs = 1'h0;
+ tb_we = 1'h0;
tb_address = 8'h0;
tb_write_data = 32'h0;
end
diff --git a/src/tb/tb_keywrap_core.v b/src/tb/tb_keywrap_core.v
index 6ec76be..b8857ea 100644
--- a/src/tb/tb_keywrap_core.v
+++ b/src/tb/tb_keywrap_core.v
@@ -64,7 +64,11 @@ module tb_keywrap_core();
reg tb_reset_n;
reg tb_init;
reg tb_next;
+ reg tb_read;
+ reg tb_write;
reg tb_encdec;
+ reg tb_mkey_mstatus;
+ reg tb_mkey_key;
wire tb_ready;
wire tb_valid;
wire tb_loaded;
@@ -74,7 +78,10 @@ module tb_keywrap_core();
wire tb_dut_timeout;
reg [(RLEN_BITS - 1) : 0] tb_rlen;
reg [255 : 0] tb_key;
+ reg [31 : 0] tb_status;
reg tb_keylen;
+ wire [255 : 0] tb_mkey;
+ wire [31 : 0] tb_mstatus;
reg [63 : 0] tb_a_init;
wire [63 : 0] tb_a_result;
reg tb_api_we;
@@ -82,6 +89,11 @@ module tb_keywrap_core();
reg [31 : 0] tb_api_wr_data;
wire [31 : 0] tb_api_rd_data;
+ wire tb_mkm_spi_sclk;
+ wire tb_mkm_spi_cs_n;
+ reg tb_mkm_spi_do;
+ wire tb_mkm_spi_di;
+
//----------------------------------------------------------------
// Device Under Test.
@@ -91,8 +103,17 @@ module tb_keywrap_core();
.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),
.next(tb_next),
+ .read(tb_read),
+ .write(tb_write),
+ .mkey_mstatus(tb_mkey_mstatus),
+ .mkey_key(tb_mkey_key),
.encdec(tb_encdec),
.ready(tb_ready),
@@ -107,6 +128,9 @@ module tb_keywrap_core();
.rlen(tb_rlen),
.key(tb_key),
.keylen(tb_keylen),
+ .status(tb_status),
+ .mkey(tb_mkey),
+ .mstatus(tb_mstatus),
.a_init(tb_a_init),
.a_result(tb_a_result),
@@ -158,19 +182,21 @@ module tb_keywrap_core();
tb_clk = 0;
tb_reset_n = 0;
- tb_init = 1'h0;
- tb_next = 1'h0;
- tb_encdec = 1'h0;
- tb_rlen = 13'h0;
- tb_key = 256'h0;
- tb_keylen = 1'h0;
- tb_timeout = 32'hdeadbeef;
- tb_ping = 1'h0;
- tb_zeroise = 1'h0;
- tb_a_init = 64'h0;
- tb_api_we = 1'h0;
- tb_api_addr = 14'h0;
- tb_api_wr_data = 32'h0;
+ tb_init = 0;
+ tb_next = 0;
+ tb_read = 0;
+ tb_write = 0;
+ tb_encdec = 0;
+ tb_mkey_mstatus = 0;
+ tb_mkey_key = 0;
+ tb_rlen = 13'h0;
+ tb_key = 256'h0;
+ tb_status = 32'h0;
+ tb_keylen = 0;
+ tb_a_init = 64'h0;
+ tb_api_we = 0;
+ tb_api_addr = 14'h0;
+ tb_api_wr_data = 32'h0;
#(CLK_PERIOD * 10);
diff --git a/src/tb/tb_keywrap_mkmif.v b/src/tb/tb_keywrap_mkmif.v
new file mode 100644
index 0000000..b275499
--- /dev/null
+++ b/src/tb/tb_keywrap_mkmif.v
@@ -0,0 +1,434 @@
+//======================================================================
+//
+// 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
+//======================================================================
diff --git a/src/tech/README.md b/src/tech/README.md
new file mode 100644
index 0000000..0e04542
--- /dev/null
+++ b/src/tech/README.md
@@ -0,0 +1,14 @@
+README.md
+=========
+This dir is where the vendor specific Verilog memory model should be
+stored.
+
+The memory used is the [Microchip
+23K640](https://www.microchip.com/wwwproducts/en/23A640) a 64kbit,
+SPI-connected serial SRAM.
+
+The Verilog memory model can be downloaded from that webpage or [by
+clicking on this link](http://ww1.microchip.com/downloads/en/DeviceDoc/23x640_Verilog_Model.zip).
+
+Download and unzip the file in this directory. This should produce two
+files, 23A640.v and 23K640.v. The one needed for simulation is 23K640.v