[Cryptech-Commits] [user/js/mkmif] branch master updated: Adding all source files and testbenches for the mkmif core. Adding Makefile for building simulation and linting. Adding top level license file.

git at cryptech.is git at cryptech.is
Wed May 11 15:13:10 UTC 2016


This is an automated email from the git hooks/post-receive script.

joachim at secworks.se pushed a commit to branch master
in repository user/js/mkmif.

The following commit(s) were added to refs/heads/master by this push:
       new  c03aa37   Adding all source files and testbenches for the mkmif core. Adding Makefile for building simulation and linting. Adding top level license file.
c03aa37 is described below

commit c03aa37d4f237f2eb90d9a958428011ca2bd455c
Author: Joachim Strömbergson <joachim at secworks.se>
AuthorDate: Wed May 11 17:13:04 2016 +0200

    Adding all source files and testbenches for the mkmif core. Adding Makefile for building simulation and linting. Adding top level license file.
---
 LICENSE.txt            |  27 +++
 src/rtl/mkmif.v        | 256 +++++++++++++++++++++++++++++
 src/rtl/mkmif_core.v   | 292 +++++++++++++++++++++++++++++++++
 src/rtl/mkmif_spi.v    | 378 ++++++++++++++++++++++++++++++++++++++++++
 src/tb/tb_mkmif.v      | 438 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/tb/tb_mkmif_core.v | 285 ++++++++++++++++++++++++++++++++
 src/tb/tb_mkmif_spi.v  | 286 ++++++++++++++++++++++++++++++++
 toolruns/Makefile      |  85 ++++++++++
 8 files changed, 2047 insertions(+)

diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..50b916a
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,27 @@
+Copyright (c) 2011, 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.
diff --git a/src/rtl/mkmif.v b/src/rtl/mkmif.v
new file mode 100644
index 0000000..4f44878
--- /dev/null
+++ b/src/rtl/mkmif.v
@@ -0,0 +1,256 @@
+//======================================================================
+//
+// mkmif.v
+// -------
+// Top level wrapper for the Master Key Memory (MKM) interface.
+// The interface is implemented to use the Microchip 23K640 serial
+// sram as external storage. The core acts as a SPI Master for the
+// external memory including SPI clock generation.
+//
+// The current version of the core does not provide any functionality
+// to protect against remanence.
+//
+//
+// Author: Joachim Strombergson
+// Copyright (c) 2011, 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 mkmif(
+             input wire           clk,
+             input wire           reset_n,
+
+             output wire          spi_sclk,
+             output wire          spi_cs_n,
+             input wire           spi_do,
+             output wire          spi_di,
+
+             input wire           cs,
+             input wire           we,
+             input wire  [7 : 0]  address,
+             input wire  [31 : 0] write_data,
+             output wire [31 : 0] read_data
+            );
+
+
+  //----------------------------------------------------------------
+  // Internal constant and parameter definitions.
+  //----------------------------------------------------------------
+  localparam ADDR_NAME0       = 8'h00;
+  localparam ADDR_NAME1       = 8'h01;
+  localparam ADDR_VERSION     = 8'h02;
+  localparam ADDR_CTRL        = 8'h08;
+  localparam CTRL_READ_BIT    = 0;
+  localparam CTRL_WRITE_BIT   = 1;
+  localparam CTRL_INIT_BIT    = 2;
+  localparam ADDR_STATUS      = 8'h09;
+  localparam STATUS_READY_BIT = 0;
+  localparam STATUS_VALID_BIT = 1;
+  localparam ADDR_SCLK_DIV    = 8'h0a;
+  localparam ADDR_EMEM_ADDR   = 8'h10;
+  localparam ADDR_EMEM_DATA   = 8'h20;
+
+  localparam DEFAULT_SCLK_DIV = 16'h0020;
+
+  localparam CORE_NAME0   = 32'h6d6b6d69; // "mkmi"
+  localparam CORE_NAME1   = 32'h66202020; // "f   "
+  localparam CORE_VERSION = 32'h302e3130; // "0.10"
+
+
+  //----------------------------------------------------------------
+  // Registers including update variables and write enable.
+  //----------------------------------------------------------------
+  reg          read_op_reg;
+  reg          read_op_new;
+  reg          write_op_reg;
+  reg          write_op_new;
+  reg          init_op_reg;
+  reg          init_op_new;
+
+  reg [15 : 0] addr_reg;
+  reg          addr_we;
+
+  reg [15 : 0] sclk_div_reg;
+  reg          sclk_div_we;
+
+  reg [31 : 0] write_data_reg;
+  reg          write_data_we;
+
+
+  //----------------------------------------------------------------
+  // Wires.
+  //----------------------------------------------------------------
+  wire          core_ready;
+  wire          core_valid;
+  wire [31 : 0] core_read_data;
+  reg [31 : 0]  tmp_read_data;
+
+
+  //----------------------------------------------------------------
+  // Concurrent connectivity for ports etc.
+  //----------------------------------------------------------------
+  assign read_data = tmp_read_data;
+
+
+  //----------------------------------------------------------------
+  // core
+  //----------------------------------------------------------------
+  mkmif_core core(
+                  .clk(clk),
+                  .reset_n(reset_n),
+
+                  .spi_sclk(spi_sclk),
+                  .spi_cs_n(spi_cs_n),
+                  .spi_do(spi_do),
+                  .spi_di(spi_di),
+
+                  .read_op(read_op_reg),
+                  .write_op(write_op_reg),
+                  .init_op(init_op_reg),
+                  .ready(core_ready),
+                  .valid(core_valid),
+                  .sclk_div(sclk_div_reg),
+                  .addr(addr_reg),
+                  .write_data(write_data_reg),
+                  .read_data(core_read_data)
+                 );
+
+
+  //----------------------------------------------------------------
+  // reg_update
+  // Update functionality for all registers in the core.
+  // All registers are positive edge triggered with asynchronous
+  // active low reset.
+  //----------------------------------------------------------------
+  always @ (posedge clk or negedge reset_n)
+    begin
+      if (!reset_n)
+        begin
+          read_op_reg    <= 1'h0;
+          write_op_reg   <= 1'h0;
+          addr_reg       <= 16'h0;
+          sclk_div_reg   <= DEFAULT_SCLK_DIV;
+          write_data_reg <= 32'h0;
+        end
+      else
+        begin
+          read_op_reg  <= read_op_new;
+          write_op_reg <= write_op_new;
+          init_op_reg  <= init_op_new;
+
+          if (sclk_div_we)
+            sclk_div_reg <= write_data[15 : 0];
+
+          if (addr_we)
+            addr_reg <= write_data[15 : 0];
+
+          if (write_data_we)
+            write_data_reg <= write_data;
+        end
+    end // reg_update
+
+
+  //----------------------------------------------------------------
+  // api
+  //----------------------------------------------------------------
+  always @*
+    begin : api
+      read_op_new   = 0;
+      write_op_new  = 0;
+      init_op_new   = 0;
+      addr_we       = 0;
+      sclk_div_we   = 0;
+      write_data_we = 0;
+      tmp_read_data = 32'h00000000;
+
+      if (cs)
+        begin
+          if (we)
+            begin
+              case (address)
+                ADDR_CTRL:
+                  begin
+                    read_op_new  = write_data[CTRL_READ_BIT];
+                    write_op_new = write_data[CTRL_WRITE_BIT];
+                    init_op_new  = write_data[CTRL_INIT_BIT];
+                  end
+
+                ADDR_SCLK_DIV:
+                  sclk_div_we = 1;
+
+                ADDR_EMEM_ADDR:
+                  addr_we = 1;
+
+                ADDR_EMEM_DATA:
+                  write_data_we = 1;
+
+                default:
+                  begin
+                  end
+              endcase // case (address)
+            end // if (we)
+
+          else
+            begin
+              case (address)
+                ADDR_NAME0:
+                  tmp_read_data = CORE_NAME0;
+
+                ADDR_NAME1:
+                  tmp_read_data = CORE_NAME1;
+
+                ADDR_VERSION:
+                  tmp_read_data = CORE_VERSION;
+
+                ADDR_STATUS:
+                    tmp_read_data = {30'h0, {core_valid, core_ready}};
+
+                ADDR_SCLK_DIV:
+                  tmp_read_data = {16'h0, sclk_div_reg};
+
+                ADDR_EMEM_ADDR:
+                  tmp_read_data = {16'h0, addr_reg};
+
+                ADDR_EMEM_DATA:
+                  begin
+                    tmp_read_data = core_read_data;
+                  end
+
+                default:
+                  begin
+                  end
+              endcase // case (address)
+            end
+        end
+    end // api
+endmodule // mkmif
+
+//======================================================================
+// EOF mkmif.v
+//======================================================================
diff --git a/src/rtl/mkmif_core.v b/src/rtl/mkmif_core.v
new file mode 100644
index 0000000..0f90bf0
--- /dev/null
+++ b/src/rtl/mkmif_core.v
@@ -0,0 +1,292 @@
+//======================================================================
+//
+// mkmif_core.v
+// ------------
+// The actual core module for the Master Key Memory (MKM) interface.
+// The interface is implemented to use the Microchip 23K640 serial
+// sram as external storage. The core acts as a SPI Master for the
+// external memory including SPI clock generation.
+//
+// The current version of the core does not provide any functionality
+// to protect against remanence.
+//
+//
+// Author: Joachim Strombergson
+// Copyright (c) 2011, 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 mkmif_core(
+                  input wire           clk,
+                  input wire           reset_n,
+
+                  output wire          spi_sclk,
+                  output wire          spi_cs_n,
+                  input wire           spi_do,
+                  output wire          spi_di,
+
+                  input wire           read_op,
+                  input wire           write_op,
+                  input wire           init_op,
+                  output wire          ready,
+                  output wire          valid,
+                  input wire [15 : 0]  sclk_div,
+                  input wire [15 : 0]  addr,
+                  input wire [31 : 0]  write_data,
+                  output wire [31 : 0] read_data
+                 );
+
+
+  //----------------------------------------------------------------
+  // Internal constant and parameter definitions.
+  //----------------------------------------------------------------
+  localparam SPI_READ_DATA_CMD    = 8'h03;
+  localparam SPI_WRITE_DATA_CMD   = 8'h02;
+  localparam SPI_READ_STATUS_CMD  = 8'h05;
+  localparam SPI_WRITE_STATUS_CMD = 8'h01;
+
+  localparam SEQ_MODE_NO_HOLD = 8'b01000001;
+
+  localparam CTRL_IDLE        = 0;
+  localparam CTRL_READY       = 1;
+  localparam CTRL_READ        = 2;
+  localparam CTRL_WRITE       = 3;
+  localparam CTRL_INIT        = 4;
+  localparam CTRL_OP_START    = 5;
+  localparam CTRL_OP_WAIT     = 6;
+
+
+  //----------------------------------------------------------------
+  // Registers including update variables and write enable.
+  //----------------------------------------------------------------
+  reg          ready_reg;
+  reg          ready_new;
+  reg          ready_we;
+  reg          valid_reg;
+  reg          valid_new;
+  reg          valid_we;
+
+  reg [31 : 0] read_data_reg;
+  reg          read_data_we;
+
+  reg [3 : 0]  mkmif_ctrl_reg;
+  reg [3 : 0]  mkmif_ctrl_new;
+  reg          mkmif_ctrl_we;
+
+
+  //----------------------------------------------------------------
+  // Wires.
+  //----------------------------------------------------------------
+  wire [31 : 0] spi_read_data;
+  reg  [55 : 0] spi_write_data;
+  reg           spi_set;
+  reg           spi_start;
+  wire          spi_ready;
+  reg   [2 : 0] spi_length;
+
+
+  //----------------------------------------------------------------
+  // Concurrent connectivity for ports etc.
+  //----------------------------------------------------------------
+  assign ready     = ready_reg;
+  assign valid     = valid_reg;
+  assign read_data = read_data_reg;
+
+
+  //----------------------------------------------------------------
+  // spi
+  // The actual spi interfacce
+  //----------------------------------------------------------------
+  mkmif_spi spi(
+                .clk(clk),
+                .reset_n(reset_n),
+
+                .spi_sclk(spi_sclk),
+                .spi_cs_n(spi_cs_n),
+                .spi_do(spi_do),
+                .spi_di(spi_di),
+
+                .set(spi_set),
+                .start(spi_start),
+                .length(spi_length),
+                .divisor(sclk_div),
+                .ready(spi_ready),
+                .wr_data(spi_write_data),
+                .rd_data(spi_read_data)
+               );
+
+
+  //----------------------------------------------------------------
+  // reg_update
+  // Update functionality for all registers in the core.
+  // All registers are positive edge triggered with asynchronous
+  // active low reset.
+  //----------------------------------------------------------------
+  always @ (posedge clk or negedge reset_n)
+    begin
+      if (!reset_n)
+        begin
+          ready_reg      <= 0;
+          valid_reg      <= 0;
+          read_data_reg  <= 32'h0;
+          mkmif_ctrl_reg <= CTRL_IDLE;
+        end
+      else
+        begin
+          if (ready_we)
+            ready_reg <= ready_new;
+
+          if (valid_we)
+            valid_reg <= valid_new;
+
+          if (read_data_we)
+            read_data_reg <= spi_read_data;
+
+          if (mkmif_ctrl_we)
+            mkmif_ctrl_reg <= mkmif_ctrl_new;
+        end
+    end // reg_update
+
+
+  //----------------------------------------------------------------
+  // mkmif_ctrl
+  // Main control FSM.
+  //----------------------------------------------------------------
+  always @*
+    begin : mkmif_ctrl
+      spi_set        = 0;
+      spi_start      = 0;
+      spi_length     = 3'h0;
+      spi_write_data = 56'h0;
+      read_data_we   = 0;
+      ready_new      = 0;
+      ready_we       = 0;
+      valid_new      = 0;
+      valid_we       = 0;
+      mkmif_ctrl_new = CTRL_IDLE;
+      mkmif_ctrl_we  = 0;
+
+      case (mkmif_ctrl_reg)
+        CTRL_IDLE:
+          begin
+            mkmif_ctrl_new = CTRL_INIT;
+            mkmif_ctrl_we  = 1;
+          end
+
+        CTRL_READY:
+          begin
+            ready_new = 1;
+            ready_we  = 1;
+
+            if (read_op)
+              begin
+                ready_new      = 0;
+                ready_we       = 1;
+                valid_new      = 0;
+                valid_we       = 1;
+                mkmif_ctrl_new = CTRL_READ;
+                mkmif_ctrl_we  = 1;
+              end
+
+            if (write_op)
+              begin
+                ready_new      = 0;
+                ready_we       = 1;
+                mkmif_ctrl_new = CTRL_WRITE;
+                mkmif_ctrl_we  = 1;
+              end
+
+            if (init_op)
+              begin
+                ready_new      = 0;
+                ready_we       = 1;
+                mkmif_ctrl_new = CTRL_INIT;
+                mkmif_ctrl_we  = 1;
+              end
+          end
+
+        CTRL_READ:
+          begin
+            spi_set        = 1;
+            spi_write_data = {SPI_READ_DATA_CMD, addr, 32'h0};
+            spi_length     = 3'h7;
+            mkmif_ctrl_new = CTRL_OP_START;
+            mkmif_ctrl_we  = 1;
+          end
+
+        CTRL_WRITE:
+          begin
+            spi_set        = 1;
+            spi_write_data = {SPI_WRITE_DATA_CMD, addr, write_data};
+            spi_length     = 3'h7;
+            mkmif_ctrl_new = CTRL_OP_START;
+            mkmif_ctrl_we  = 1;
+          end
+
+        CTRL_INIT:
+          begin
+            if (spi_ready)
+              begin
+                spi_set        = 1;
+                spi_write_data = {SPI_WRITE_STATUS_CMD, SEQ_MODE_NO_HOLD, 40'h0};
+                spi_length     = 3'h2;
+                mkmif_ctrl_new = CTRL_OP_START;
+                mkmif_ctrl_we  = 1;
+              end
+          end
+
+        CTRL_OP_START:
+          begin
+            spi_start      = 1;
+            mkmif_ctrl_new = CTRL_OP_WAIT;
+            mkmif_ctrl_we  = 1;
+          end
+
+        CTRL_OP_WAIT:
+          begin
+            if (spi_ready)
+              begin
+                read_data_we   = 1;
+                valid_new      = 1;
+                valid_we       = 1;
+                mkmif_ctrl_new = CTRL_READY;
+                mkmif_ctrl_we  = 1;
+              end
+          end
+
+        default:
+          begin
+          end
+      endcase // case (mkmif_ctrl_reg)
+    end // mkmif_ctrl
+endmodule // mkmif
+
+//======================================================================
+// EOF mkmif.v
+//======================================================================
diff --git a/src/rtl/mkmif_spi.v b/src/rtl/mkmif_spi.v
new file mode 100644
index 0000000..fc80470
--- /dev/null
+++ b/src/rtl/mkmif_spi.v
@@ -0,0 +1,378 @@
+//======================================================================
+//
+// mkmif_spi.v
+// -----------
+// SPI interface for the master key memory. When enabled the
+// interface waits for command to transmit and receive a given
+// number of bytes. Data is transmitted onto the spi_di port
+// from the MSB of the spi_data register. Simultaneously,
+// data captured on the spi_do port is inserted at LSB in the
+// spi_data register. The spi clock is generated when data is to be
+// sent or recived.
+//
+//
+// Author: Joachim Strombergson
+// Copyright (c) 2011, 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 mkmif_spi(
+                 input wire           clk,
+                 input wire           reset_n,
+
+                 output wire          spi_sclk,
+                 output wire          spi_cs_n,
+                 input wire           spi_do,
+                 output wire          spi_di,
+
+                 input wire           set,
+                 input wire           start,
+                 input wire [2 : 0]   length,
+                 input wire [15 : 0]  divisor,
+                 output wire          ready,
+                 input wire [55 : 0]  wr_data,
+                 output wire [31 : 0] rd_data
+                );
+
+
+  //----------------------------------------------------------------
+  // Internal constant and parameter definitions.
+  //----------------------------------------------------------------
+  localparam CTRL_IDLE  = 2'h0;
+  localparam CTRL_START = 2'h1;
+  localparam CTRL_WAIT  = 2'h2;
+  localparam CTRL_DONE  = 2'h3;
+
+
+  //----------------------------------------------------------------
+  // Registers including update variables and write enable.
+  //----------------------------------------------------------------
+  reg          do_sample0_reg;
+  reg          do_sample1_reg;
+
+  reg          cs_n_reg;
+  reg          cs_n_new;
+  reg          cs_n_we;
+
+  reg          ready_reg;
+  reg          ready_new;
+  reg          ready_we;
+
+  reg [55 : 0] data_reg;
+  reg [55 : 0] data_new;
+  reg          data_set;
+  reg          data_nxt;
+  reg          data_we;
+
+  reg          sclk_reg;
+  reg          sclk_new;
+  reg          sclk_rst;
+  reg          sclk_en;
+  reg          sclk_we;
+
+  reg [15 : 0] clk_ctr_reg;
+  reg [15 : 0] clk_ctr_new;
+  reg          clk_ctr_we;
+
+  reg  [5 : 0] bit_ctr_reg;
+  reg  [5 : 0] bit_ctr_new;
+  reg          bit_ctr_rst;
+  reg          bit_ctr_inc;
+  reg          bit_ctr_done;
+  reg          bit_ctr_we;
+
+  reg [2 : 0]  length_reg;
+  reg          length_we;
+
+  reg [15 : 0] divisor_reg;
+  reg          divisor_we;
+
+  reg  [1 : 0] spi_ctrl_reg;
+  reg  [1 : 0] spi_ctrl_new;
+  reg          spi_ctrl_we;
+
+
+  //----------------------------------------------------------------
+  // Wires.
+  //----------------------------------------------------------------
+
+
+  //----------------------------------------------------------------
+  // Concurrent connectivity for ports etc.
+  //----------------------------------------------------------------
+  assign spi_sclk = sclk_reg;
+  assign spi_cs_n = cs_n_reg;
+  assign spi_di   = data_reg[55];
+  assign rd_data  = data_reg[31 : 0];
+  assign ready    = ready_reg;
+
+
+  //----------------------------------------------------------------
+  // reg_update
+  // Update functionality for all registers in the core.
+  // All registers are positive edge triggered with asynchronous
+  // active low reset.
+  //----------------------------------------------------------------
+  always @ (posedge clk or negedge reset_n)
+    begin
+      if (!reset_n)
+        begin
+          do_sample0_reg <= 1'h0;
+          do_sample1_reg <= 1'h0;
+          cs_n_reg       <= 1'h1;
+          ready_reg      <= 1'h0;
+          length_reg     <= 3'h0;
+          divisor_reg    <= 16'h0;
+          data_reg       <= 56'h0;
+          sclk_reg       <= 1'h0;
+          clk_ctr_reg    <= 16'h0;
+          bit_ctr_reg    <= 6'h0;
+          spi_ctrl_reg   <= CTRL_IDLE;
+        end
+      else
+        begin
+          do_sample0_reg <= spi_do;
+          do_sample1_reg <= do_sample0_reg;
+
+          if (cs_n_we)
+            cs_n_reg <= cs_n_new;
+
+          if (ready_we)
+            ready_reg <= ready_new;
+
+          if (data_we)
+            data_reg <= data_new;
+
+          if (length_we)
+            length_reg <= length;
+
+          if (divisor_we)
+            divisor_reg <= divisor;
+
+          if (sclk_we)
+            sclk_reg <= sclk_new;
+
+          if (clk_ctr_we)
+            clk_ctr_reg <= clk_ctr_new;
+
+          if (bit_ctr_we)
+            bit_ctr_reg <= bit_ctr_new;
+
+          if (spi_ctrl_we)
+            spi_ctrl_reg <= spi_ctrl_new;
+
+        end
+    end // reg_update
+
+
+  //----------------------------------------------------------------
+  // data_gen
+  //
+  // Generate the data bitstream to be written out to the external
+  // SPI connected memory. Basically a shift register.
+  // Note that we also shift in data received from the external
+  // memory.
+  //----------------------------------------------------------------
+  always @*
+    begin : data_gen
+      data_new = 56'h0;
+      data_we  = 0;
+
+      if (data_set)
+        begin
+          data_new = wr_data;
+          data_we  = 1;
+        end
+
+      if (data_nxt)
+        begin
+          data_new = {data_reg[54 : 0], do_sample1_reg};
+          data_we  = 1;
+        end
+    end // data_gen
+
+
+  //----------------------------------------------------------------
+  // sclk_gen
+  //
+  // Generator of the spi_sclk clock.
+  //----------------------------------------------------------------
+  always @*
+    begin : sclk_gen
+      sclk_new     = 0;
+      sclk_we      = 0;
+      clk_ctr_new  = 0;
+      clk_ctr_we   = 0;
+      data_nxt     = 0;
+      bit_ctr_rst  = 0;
+      bit_ctr_inc  = 0;
+
+      if (sclk_rst)
+        begin
+          clk_ctr_new = 0;
+          clk_ctr_we  = 1;
+          bit_ctr_rst = 1;
+          sclk_new    = 0;
+          sclk_we     = 1;
+        end
+
+      if (sclk_en)
+        begin
+          if (clk_ctr_reg == divisor_reg)
+            begin
+              clk_ctr_new = 0;
+              clk_ctr_we  = 1'b1;
+              sclk_new    = ~sclk_reg;
+              sclk_we     = 1;
+
+              if (sclk_reg)
+                begin
+                  bit_ctr_inc = 1;
+                  data_nxt    = 1;
+                end
+            end
+          else
+            begin
+              clk_ctr_new = clk_ctr_reg + 1'b1;
+              clk_ctr_we  = 1'b1;
+            end
+        end
+    end // sclk_gen
+
+
+  //----------------------------------------------------------------
+  // bit_ctr
+  //
+  // Bit counter used by the FSM to keep track of the number bits
+  // being read from or written to the memory.
+  //----------------------------------------------------------------
+  always @*
+    begin : bit_ctr
+      bit_ctr_new  = 6'h0;
+      bit_ctr_we   = 1'b0;
+      bit_ctr_done = 1'b0;
+
+      if (bit_ctr_reg == {length_reg, 3'h0})
+        bit_ctr_done = 1'b1;
+
+      if (bit_ctr_rst)
+        begin
+          bit_ctr_new = 6'h0;
+          bit_ctr_we  = 1'b1;
+        end
+
+      if (bit_ctr_inc)
+        begin
+          bit_ctr_new = bit_ctr_reg + 1'b1;
+          bit_ctr_we  = 1'b1;
+        end
+    end // bit_ctr
+
+
+  //----------------------------------------------------------------
+  // spi_ctrl
+  //
+  // Control FSM for the SPI interface.
+  //----------------------------------------------------------------
+  always @*
+    begin : spi_ctrl
+      sclk_en      = 0;
+      sclk_rst     = 0;
+      cs_n_new     = 1;
+      cs_n_we      = 0;
+      data_set     = 0;
+      length_we    = 0;
+      divisor_we   = 0;
+      ready_new    = 0;
+      ready_we     = 0;
+      spi_ctrl_new = CTRL_IDLE;
+      spi_ctrl_we  = 0;
+
+      case (spi_ctrl_reg)
+        CTRL_IDLE:
+          begin
+            ready_new = 1;
+            ready_we  = 1;
+
+            if (set)
+              begin
+                data_set   = 1;
+                length_we  = 1;
+                divisor_we = 1;
+              end
+
+            if (start)
+              begin
+                ready_new    = 0;
+                ready_we     = 1;
+                sclk_rst     = 1;
+                spi_ctrl_new = CTRL_START;
+                spi_ctrl_we  = 1;
+              end
+          end
+
+        CTRL_START:
+          begin
+            cs_n_new    = 0;
+            cs_n_we     = 1;
+            spi_ctrl_new = CTRL_WAIT;
+            spi_ctrl_we  = 1;
+          end
+
+        CTRL_WAIT:
+          begin
+            sclk_en = 1;
+            if (bit_ctr_done)
+              begin
+                spi_ctrl_new = CTRL_DONE;
+                spi_ctrl_we  = 1;
+              end
+          end
+
+        CTRL_DONE:
+          begin
+            ready_new    = 1;
+            ready_we     = 1;
+            cs_n_new     = 1;
+            cs_n_we      = 1;
+            spi_ctrl_new = CTRL_IDLE;
+            spi_ctrl_we  = 1;
+          end
+
+        default:
+          begin
+          end
+      endcase // case (spi_ctrl_reg)
+    end // spi_ctrl
+
+endmodule // mkmif_spi
+
+//======================================================================
+// EOF mkmif_spi.v
+//======================================================================
diff --git a/src/tb/tb_mkmif.v b/src/tb/tb_mkmif.v
new file mode 100644
index 0000000..4142574
--- /dev/null
+++ b/src/tb/tb_mkmif.v
@@ -0,0 +1,438 @@
+//======================================================================
+//
+// tb_mkmif.v
+// ------------
+// Testbench for the mkmif top level wrapper.
+//
+//
+// Author: Joachim Strombergson
+// Copyright (c) 2011, 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.
+//
+//======================================================================
+
+//------------------------------------------------------------------
+// Compiler directives.
+//------------------------------------------------------------------
+`timescale 1ns/100ps
+
+module tb_mkmif();
+
+  //----------------------------------------------------------------
+  // Internal constant and parameter definitions.
+  //----------------------------------------------------------------
+  parameter DEBUG = 1;
+
+  parameter CLK_HALF_PERIOD = 2;
+  parameter CLK_PERIOD      = 2 * CLK_HALF_PERIOD;
+
+  localparam ADDR_NAME0        = 8'h00;
+  localparam ADDR_NAME1        = 8'h01;
+  localparam ADDR_VERSION      = 8'h02;
+  localparam ADDR_CTRL         = 8'h08;
+  localparam ADDR_STATUS       = 8'h09;
+  localparam ADDR_CONFIG       = 8'h0a;
+  localparam ADDR_EMEM_ADDR    = 8'h10;
+  localparam ADDR_EMEM_DATA    = 8'h20;
+
+  localparam CORE_NAME0   = 32'h6d6b6d69; // "mkmi"
+  localparam CORE_NAME1   = 32'h66202020; // "f   "
+  localparam CORE_VERSION = 32'h302e3130; // "0.10"
+
+
+  //----------------------------------------------------------------
+  // Register and Wire declarations.
+  //----------------------------------------------------------------
+  reg [31 : 0] cycle_ctr;
+  reg [31 : 0] test_ctr;
+  reg [31 : 0] error_ctr;
+
+  reg           tb_clk;
+  reg           tb_reset_n;
+  wire          tb_spi_sclk;
+  wire          tb_spi_cs_n;
+  reg           tb_spi_do;
+  wire          tb_spi_di;
+  reg           tb_cs;
+  reg           tb_we;
+  reg [7 : 0]   tb_address;
+  reg [31 : 0]  tb_write_data;
+  wire [31 : 0] tb_read_data;
+  reg           tb_dump_state;
+  wire          tb_error;
+  reg [31 : 0]  read_data;
+
+
+  //----------------------------------------------------------------
+  // mkmif device under test.
+  //----------------------------------------------------------------
+  mkmif dut(
+            .clk(tb_clk),
+            .reset_n(tb_reset_n),
+
+            .spi_sclk(tb_spi_sclk),
+            .spi_cs_n(tb_spi_cs_n),
+            .spi_do(tb_spi_di),
+            .spi_di(tb_spi_di),
+
+            .cs(tb_cs),
+            .we(tb_we),
+            .address(tb_address),
+            .write_data(tb_write_data),
+            .read_data(tb_read_data)
+           );
+
+
+  //----------------------------------------------------------------
+  // clk_gen
+  // Clock generator process.
+  //----------------------------------------------------------------
+  always
+    begin : clk_gen
+      #CLK_HALF_PERIOD tb_clk = !tb_clk;
+    end // clk_gen
+
+
+  //--------------------------------------------------------------------
+  // dut_monitor
+  // Monitor for observing the inputs and outputs to the dut.
+  // Includes the cycle counter.
+  //--------------------------------------------------------------------
+  always @ (posedge tb_clk)
+    begin : dut_monitor
+      cycle_ctr = cycle_ctr + 1;
+
+      if (DEBUG)
+        $display("cycle = %8x:", cycle_ctr);
+
+      if (tb_dump_state)
+        dump_state();
+    end // dut_monitor
+
+
+  //----------------------------------------------------------------
+  // inc_test_ctr
+  //----------------------------------------------------------------
+  task inc_test_ctr;
+    begin
+      test_ctr = test_ctr +1;
+    end
+  endtask // inc_test_ctr
+
+
+  //----------------------------------------------------------------
+  // inc_error_ctr
+  //----------------------------------------------------------------
+  task inc_error_ctr;
+    begin
+      error_ctr = error_ctr +1;
+    end
+  endtask // inc_error_ctr
+
+
+
+  //----------------------------------------------------------------
+  // dump_state
+  // Dump the internal MKMIF state to std out.
+  //----------------------------------------------------------------
+  task dump_state;
+    begin
+
+      $display("mkmif_core_ctrl_reg: 0x%02x, core ready: 0x%01x, core valid: 0x%01x",
+               dut.core.mkmif_ctrl_reg, dut.core_ready, dut.core_valid);
+      $display("sclk: 0x%01x, cs_n: 0x%01x, di: 0x%01x, do: 0x%01x, nxt: 0x%01x",
+               tb_spi_sclk, tb_spi_cs_n, tb_spi_di, tb_spi_do, dut.core.spi.data_nxt);
+      $display("spi_ctrl_reg: 0x%01x, spi_clk_ctr: 0x%04x, spi_bit_ctr: 0x%02x",
+               dut.core.spi.spi_ctrl_reg, dut.core.spi.clk_ctr_reg, dut.core.spi.bit_ctr_reg);
+      $display("spi length: 0x%02x, spi divisor: 0x%04x, spi set: 0x%01x, spi start: 0x%01x, spi ready: 0x%01x",
+               dut.core.spi.length_reg, dut.core.spi.divisor_reg, dut.core.spi.set, dut.core.spi.start, dut.core.spi.ready);
+      $display("read data: 0x%08x, write_data: 0x%014x", dut.core.spi.rd_data, dut.core.spi.wr_data);
+      $display("spi data reg: 0x%014x", dut.core.spi.data_reg);
+      $display("");
+    end
+  endtask // dump_state
+
+
+  //----------------------------------------------------------------
+  // tb_init
+  // Initialize varibles, dut inputs at start.
+  //----------------------------------------------------------------
+  task tb_init;
+    begin
+      test_ctr      = 0;
+      error_ctr     = 0;
+      cycle_ctr     = 0;
+      tb_clk        = 0;
+      tb_reset_n    = 1;
+      tb_spi_do     = 0;
+      tb_cs         = 1'b0;
+      tb_we         = 1'b0;
+      tb_address    = 8'h00;
+      tb_write_data = 32'h00;
+      tb_dump_state = 1;
+    end
+  endtask // tb_init
+
+
+  //----------------------------------------------------------------
+  // toggle_reset
+  // Toggle the reset.
+  //----------------------------------------------------------------
+  task toggle_reset;
+    begin
+      $display("  --- Toggling reset started.");
+      dump_state();
+      #(2 * CLK_PERIOD);
+      tb_reset_n = 0;
+      #(10 * CLK_PERIOD);
+      @(negedge tb_clk)
+      tb_reset_n = 1;
+      dump_state();
+      $display("  --- Toggling of reset done.");
+      $display("");
+    end
+  endtask // toggle_reset
+
+
+  //----------------------------------------------------------------
+  // read_word()
+  //
+  // Read a data word from the given address in the DUT.
+  // the word read will be available in the global variable
+  // read_data.
+  //----------------------------------------------------------------
+  task read_word(input [7 : 0]  address);
+    begin
+      tb_address = address;
+      tb_cs = 1;
+      tb_we = 0;
+      #(CLK_PERIOD);
+      read_data = tb_read_data;
+      tb_cs = 0;
+
+      if (DEBUG)
+        begin
+          $display("*** Reading 0x%08x from 0x%02x.", read_data, address);
+          $display("");
+        end
+    end
+  endtask // read_word
+
+
+  //----------------------------------------------------------------
+  // write_word()
+  //
+  // Write the given word to the DUT using the DUT interface.
+  //----------------------------------------------------------------
+  task write_word(input [7 : 0]  address,
+                  input [31 : 0] word);
+    begin
+      if (DEBUG)
+        begin
+          $display("*** Writing 0x%08x to 0x%02x.", word, address);
+          $display("");
+        end
+
+      tb_address = address;
+      tb_write_data = word;
+      tb_cs = 1;
+      tb_we = 1;
+      #(CLK_PERIOD);
+      tb_cs = 0;
+      tb_we = 0;
+    end
+  endtask // write_word
+
+
+  //----------------------------------------------------------------
+  // wait_ready()
+  //
+  // Wait for ready word to be set in the DUT API.
+  //----------------------------------------------------------------
+  task wait_ready;
+    reg ready;
+    begin
+      ready = 0;
+
+      while (ready == 0)
+        begin
+          read_word(ADDR_STATUS);
+          ready = read_data & 32'h00000001;
+        end
+    end
+  endtask // read_word
+
+
+  //----------------------------------------------------------------
+  // check_name_version()
+  //
+  // Read the name and version from the DUT.
+  //----------------------------------------------------------------
+  task check_name_version;
+    reg [31 : 0] name0;
+    reg [31 : 0] name1;
+    reg [31 : 0] version;
+    begin
+      inc_test_ctr();
+
+      $display("  -- Test of reading name and version started.");
+
+      read_word(ADDR_NAME0);
+      name0 = read_data;
+      read_word(ADDR_NAME1);
+      name1 = read_data;
+      read_word(ADDR_VERSION);
+      version = read_data;
+
+      if ((name0 == CORE_NAME0) && (name1 == CORE_NAME1) && (version == CORE_VERSION))
+        $display("Correct name and version read from dut.");
+      else
+        begin
+          inc_error_ctr();
+          $display("Error:");
+          $display("Got name:      %c%c%c%c%c%c%c%c",
+                   name0[31 : 24], name0[23 : 16], name0[15 : 8], name0[7 : 0],
+                   name1[31 : 24], name1[23 : 16], name1[15 : 8], name1[7 : 0]);
+          $display("Expected name: %c%c%c%c%c%c%c%c",
+                   CORE_NAME0[31 : 24], CORE_NAME0[23 : 16], CORE_NAME0[15 : 8], CORE_NAME0[7 : 0],
+                   CORE_NAME1[31 : 24], CORE_NAME1[23 : 16], CORE_NAME1[15 : 8], CORE_NAME1[7 : 0]);
+
+          $display("Got version:      %c%c%c%c",
+                   version[31 : 24], version[23 : 16], version[15 : 8], version[7 : 0]);
+          $display("Expected version: %c%c%c%c",
+                   CORE_VERSION[31 : 24], CORE_VERSION[23 : 16], CORE_VERSION[15 : 8], CORE_VERSION[7 : 0]);
+
+          $display("  -- Test of reading name and version done.");
+          $display("");
+        end
+    end
+  endtask // check_name_version
+
+
+  //----------------------------------------------------------------
+  // write_test
+  //
+  // Try to write a few words of data.
+  //----------------------------------------------------------------
+  task write_test;
+    begin
+      inc_test_ctr();
+      $display("  -- Test of writing words to the memory started.");
+
+      wait_ready();
+      $display("Ready has been set. Starting write commands.");
+      write_word(ADDR_EMEM_ADDR, 16'h0010);
+      write_word(ADDR_EMEM_DATA, 32'hdeadbeef);
+      write_word(ADDR_CTRL, 32'h2);
+      #(10 * CLK_PERIOD);
+      wait_ready();
+      read_word(ADDR_EMEM_DATA);
+      $display("First write completed. Read: 0x%08x", read_data);
+
+      write_word(ADDR_EMEM_ADDR, 16'h0020);
+      write_word(ADDR_EMEM_DATA, 32'haa55aa55);
+      write_word(ADDR_CTRL, 32'h2);
+      #(10 * CLK_PERIOD);
+      wait_ready();
+      read_word(ADDR_EMEM_DATA);
+      $display("Second write completed. Read: 0x%08x", read_data);
+
+//      write_word(ADDR_EMEM_ADDR, 16'h0100);
+//      write_word(ADDR_EMEM_DATA, 32'h004488ff);
+//      write_word(ADDR_CTRL, 32'h2);
+//      #(1000 * CLK_PERIOD);
+//      wait_ready();
+
+      $display("  -- Test of writing words to the memory done.");
+      $display("");
+    end
+  endtask // write_test
+
+
+  //----------------------------------------------------------------
+  // read_test
+  //
+  // Try to read a few words of data.
+  //----------------------------------------------------------------
+  task read_test;
+    begin
+      inc_test_ctr();
+      $display("  -- Test of reading from the memory started.");
+
+//      wait_ready();
+//      $display("Ready has been set. Starting write commands.");
+//      write_word(ADDR_EMEM_ADDR, 16'h0010);
+//      write_word(ADDR_EMEM_DATA, 32'hdeadbeef);
+//      write_word(ADDR_CTRL, 32'h2);
+//      #(1000 * CLK_PERIOD);
+//      wait_ready();
+
+//      write_word(ADDR_EMEM_ADDR, 16'h0020);
+//      write_word(ADDR_EMEM_DATA, 32'haa55aa55);
+//      write_word(ADDR_CTRL, 32'h2);
+//      #(1000 * CLK_PERIOD);
+//      wait_ready();
+//
+//      write_word(ADDR_EMEM_ADDR, 16'h0100);
+//      write_word(ADDR_EMEM_DATA, 32'h004488ff);
+//      write_word(ADDR_CTRL, 32'h2);
+//      #(1000 * CLK_PERIOD);
+//      wait_ready();
+
+      $display("  -- Test of reading from the memory done.");
+      $display("");
+    end
+  endtask // read_test
+
+
+  //----------------------------------------------------------------
+  // mkmif_test
+  // The main test functionality.
+  //----------------------------------------------------------------
+  initial
+    begin : mkmif_test
+      $display("   --*** Test of mkmif started ***--");
+
+      tb_init();
+      toggle_reset();
+      check_name_version();
+      write_test();
+      read_test();
+
+      $display("");
+      $display("   --*** Test of mkmif completed ***--");
+      $display("Tests executed: %04d", test_ctr);
+      $display("Tests failed:   %04d", error_ctr);
+      $finish;
+    end // mkmif_test
+
+endmodule // tb_mkmif
+
+//======================================================================
+// EOF tb_mkmif.v
+//======================================================================
diff --git a/src/tb/tb_mkmif_core.v b/src/tb/tb_mkmif_core.v
new file mode 100644
index 0000000..48042f4
--- /dev/null
+++ b/src/tb/tb_mkmif_core.v
@@ -0,0 +1,285 @@
+//======================================================================
+//
+// tb_mkmif_core.v
+// ---------------
+// Testbench for the mkmif core module.
+//
+//
+// Author: Joachim Strombergson
+// Copyright (c) 2011, 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.
+//
+//======================================================================
+
+//------------------------------------------------------------------
+// Compiler directives.
+//------------------------------------------------------------------
+`timescale 1ns/100ps
+
+module tb_mkmif_core();
+
+  //----------------------------------------------------------------
+  // Internal constant and parameter definitions.
+  //----------------------------------------------------------------
+  parameter DEBUG = 1;
+
+  parameter CLK_HALF_PERIOD = 2;
+  parameter CLK_PERIOD      = 2 * CLK_HALF_PERIOD;
+
+
+  //----------------------------------------------------------------
+  // Register and Wire declarations.
+  //----------------------------------------------------------------
+  reg [31 : 0] cycle_ctr;
+  reg [31 : 0] test_ctr;
+  reg [31 : 0] error_ctr;
+
+  reg           tb_clk;
+  reg           tb_reset_n;
+  wire          tb_spi_sclk;
+  wire          tb_spi_do;
+  wire          tb_spi_di;
+  reg           tb_read_op;
+  reg           tb_write_op;
+  reg           tb_init_op;
+  wire          tb_ready;
+  wire          tb_valid;
+  reg  [15 : 0] tb_sclk_div;
+  reg  [15 : 0] tb_addr;
+  reg  [31 : 0] tb_write_data;
+  wire [31 : 0] tb_read_data;
+
+  reg           tb_display_state;
+  reg [31 : 0]  read_data;
+
+
+  //----------------------------------------------------------------
+  // Concurrent connectivity.
+  //----------------------------------------------------------------
+  // We loop back the inverted SPI serial transmit data from
+  // the DUT as the data from the memory (do) to the DUT.
+  assign tb_spi_do = ~tb_spi_di;
+
+
+  //----------------------------------------------------------------
+  // mkmif device under test.
+  //----------------------------------------------------------------
+  mkmif_core dut(
+                 .clk(tb_clk),
+                 .reset_n(tb_reset_n),
+
+                 .spi_sclk(tb_spi_sclk),
+                 .spi_cs_n(tb_cs_n),
+                 .spi_do(tb_spi_do),
+                 .spi_di(tb_spi_di),
+
+                 .read_op(tb_read_op),
+                 .write_op(tb_write_op),
+                 .init_op(tb_init_op),
+                 .ready(tb_ready),
+                 .valid(tb_valid),
+                 .sclk_div(tb_sclk_div),
+                 .addr(tb_addr),
+                 .write_data(tb_write_data),
+                 .read_data(tb_read_data)
+                );
+
+
+  //----------------------------------------------------------------
+  // clk_gen
+  // Clock generator process.
+  //----------------------------------------------------------------
+  always
+    begin : clk_gen
+      #CLK_HALF_PERIOD tb_clk = !tb_clk;
+    end // clk_gen
+
+
+  //--------------------------------------------------------------------
+  // dut_monitor
+  // Monitor for observing the inputs and outputs to the dut.
+  // Includes the cycle counter.
+  //--------------------------------------------------------------------
+  always @ (posedge tb_clk)
+    begin : dut_monitor
+      cycle_ctr = cycle_ctr + 1;
+
+      if (tb_display_state)
+        begin
+          $display("cycle = %8x:", cycle_ctr);
+          dump_state();
+        end
+    end // dut_monitor
+
+
+  //----------------------------------------------------------------
+  // inc_test_ctr
+  //----------------------------------------------------------------
+  task inc_test_ctr;
+    begin
+      test_ctr = test_ctr +1;
+    end
+  endtask // inc_test_ctr
+
+
+  //----------------------------------------------------------------
+  // inc_error_ctr
+  //----------------------------------------------------------------
+  task inc_error_ctr;
+    begin
+      error_ctr = error_ctr +1;
+    end
+  endtask // inc_error_ctr
+
+
+  //----------------------------------------------------------------
+  // dump_state
+  // Dump the internal MKMIF state to std out.
+  //----------------------------------------------------------------
+  task dump_state;
+    begin
+      $display("mkmif_ctrl_reg: 0x%02x", dut.mkmif_ctrl_reg);
+      $display("sclk: 0x%01x, cs_n: 0x%01x, di: 0x%01x, do: 0x%01x, nxt: 0x%01x",
+               tb_spi_sclk, tb_cs_n, tb_spi_di, tb_spi_do, dut.spi.data_nxt);
+      $display("spi_ctrl_reg: 0x%01x, spi_clk_ctr: 0x%04x, spi_bit_ctr: 0x%02x",
+               dut.spi.spi_ctrl_reg, dut.spi.clk_ctr_reg, dut.spi.bit_ctr_reg);
+      $display("spi length: 0x%02x, spi divisor: 0x%04x, spi set: 0x%01x, spi start: 0x%01x, spi ready: 0x%01x",
+               dut.spi.length_reg, dut.spi.divisor_reg, dut.spi.set, dut.spi.start, dut.spi.ready);
+      $display("read data: 0x%08x, write_data: 0x%014x", dut.spi.rd_data, dut.spi.wr_data);
+      $display("");
+    end
+  endtask // dump_state
+
+
+  //----------------------------------------------------------------
+  // tb_init
+  // Initialize varibles, dut inputs at start.
+  //----------------------------------------------------------------
+  task tb_init;
+    begin
+      test_ctr      = 0;
+      error_ctr     = 0;
+      cycle_ctr     = 0;
+
+      tb_clk        = 0;
+      tb_reset_n    = 1;
+      tb_read_op    = 0;
+      tb_write_op   = 0;
+      tb_init_op    = 0;
+      tb_sclk_div   = 16'h0004;
+      tb_addr       = 16'h0010;
+      tb_write_data = 32'haa55aa55;
+
+      tb_display_state = 1;
+    end
+  endtask // tb_init
+
+
+  //----------------------------------------------------------------
+  // wait_ready()
+  //
+  // Wait for ready word to be set in the DUT API.
+  //----------------------------------------------------------------
+  task wait_ready;
+    reg ready;
+    begin
+      ready = 0;
+
+      while (tb_ready == 0)
+        begin
+          #(CLK_PERIOD);
+        end
+    end
+  endtask // read_word
+
+
+  //----------------------------------------------------------------
+  // toggle_reset
+  // Toggle the reset.
+  //----------------------------------------------------------------
+  task toggle_reset;
+    begin
+      $display("  -- Toggling reset.");
+      dump_state();
+      #(2 * CLK_PERIOD);
+      tb_reset_n = 0;
+      #(10 * CLK_PERIOD);
+      @(negedge tb_clk)
+      tb_reset_n = 1;
+      dump_state();
+      $display("  -- Toggling of reset done.");
+      $display("");
+    end
+  endtask // toggle_reset
+
+
+  //----------------------------------------------------------------
+  // write_test
+  //----------------------------------------------------------------
+  task write_test;
+    begin
+      $display("  -- Write Test started.");
+      inc_test_ctr();
+      wait_ready();
+      tb_sclk_div      = 16'h0004;
+      tb_addr          = 16'h0012;
+      tb_write_data    = 32'hdeadbeef;
+      tb_write_op      = 1;
+      #(2 * CLK_PERIOD);
+      tb_write_op      = 0;
+      wait_ready();
+      $display("  -- Write Test done.");
+      $display("");
+    end
+  endtask // write_test
+
+
+  //----------------------------------------------------------------
+  // mkmif_core_test
+  // The main test functionality.
+  //----------------------------------------------------------------
+  initial
+    begin : mkmif__core_test
+      $display("   -- Test of mkmif core started --");
+
+      tb_init();
+      toggle_reset();
+      write_test();
+
+      $display("");
+      $display("   -- Test of mkmif core completed --");
+      $display("Tests executed: %04d", test_ctr);
+      $display("Tests failed:   %04d", error_ctr);
+      $finish;
+    end // mkmif_core_test
+
+endmodule // tb_mkmif_core
+
+//======================================================================
+// EOF tb_mkmif_core.v
+//======================================================================
diff --git a/src/tb/tb_mkmif_spi.v b/src/tb/tb_mkmif_spi.v
new file mode 100644
index 0000000..763defe
--- /dev/null
+++ b/src/tb/tb_mkmif_spi.v
@@ -0,0 +1,286 @@
+//======================================================================
+//
+// tb_mkmif_spi.v
+// --------------
+// Testbench for the mkmif SPI module.
+//
+//
+// Author: Joachim Strombergson
+// Copyright (c) 2011, 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.
+//
+//======================================================================
+
+//------------------------------------------------------------------
+// Compiler directives.
+//------------------------------------------------------------------
+`timescale 1ns/100ps
+
+module tb_mkmif_spi();
+
+  //----------------------------------------------------------------
+  // Internal constant and parameter definitions.
+  //----------------------------------------------------------------
+  parameter DEBUG = 1;
+
+  parameter CLK_HALF_PERIOD = 2;
+  parameter CLK_PERIOD      = 2 * CLK_HALF_PERIOD;
+
+
+  //----------------------------------------------------------------
+  // Register and Wire declarations.
+  //----------------------------------------------------------------
+  reg [31 : 0] cycle_ctr;
+  reg [31 : 0] test_ctr;
+  reg [31 : 0] error_ctr;
+
+  reg           tb_clk;
+  reg           tb_reset_n;
+  wire          tb_spi_sclk;
+  wire          tb_spi_cs_n;
+  reg           tb_spi_do;
+  wire          tb_spi_di;
+  reg           tb_set;
+  reg           tb_start;
+  reg [2 : 0]   tb_length;
+  reg [15 : 0]  tb_divisor;
+  wire          tb_ready;
+  reg [55 : 0]  tb_write_data;
+  wire [31 : 0] tb_read_data;
+  reg           tb_dump_state;
+
+
+  //----------------------------------------------------------------
+  // mkmif device under test.
+  //----------------------------------------------------------------
+  mkmif_spi dut(
+                .clk(tb_clk),
+                .reset_n(tb_reset_n),
+
+                .spi_sclk(tb_spi_sclk),
+                .spi_cs_n(tb_spi_cs_n),
+                .spi_do(tb_spi_di),
+                .spi_di(tb_spi_di),
+
+                .set(tb_set),
+                .start(tb_start),
+                .length(tb_length),
+                .divisor(tb_divisor),
+                .ready(tb_ready),
+                .wr_data(tb_write_data),
+                .rd_data(tb_read_data)
+               );
+
+
+  //----------------------------------------------------------------
+  // clk_gen
+  // Clock generator process.
+  //----------------------------------------------------------------
+  always
+    begin : clk_gen
+      #CLK_HALF_PERIOD tb_clk = !tb_clk;
+    end // clk_gen
+
+
+  //--------------------------------------------------------------------
+  // dut_monitor
+  // Monitor for observing the inputs and outputs to the dut.
+  // Includes the cycle counter.
+  //--------------------------------------------------------------------
+  always @ (posedge tb_clk)
+    begin : dut_monitor
+      cycle_ctr = cycle_ctr + 1;
+    end // dut_monitor
+
+
+  //----------------------------------------------------------------
+  // inc_test_ctr
+  //----------------------------------------------------------------
+  task inc_test_ctr;
+    begin
+      test_ctr = test_ctr +1;
+    end
+  endtask // inc_test_ctr
+
+
+  //----------------------------------------------------------------
+  // inc_error_ctr
+  //----------------------------------------------------------------
+  task inc_error_ctr;
+    begin
+      error_ctr = error_ctr +1;
+    end
+  endtask // inc_error_ctr
+
+
+  //----------------------------------------------------------------
+  // dump_ports
+  // Dump the status of the dut ports.
+  //----------------------------------------------------------------
+  task dump_ports;
+    begin
+      $display("");
+    end
+  endtask // dump_ports
+
+
+  //----------------------------------------------------------------
+  // dump_state
+  // Dump the internal MKMIF state to std out.
+  //----------------------------------------------------------------
+  task dump_state;
+    begin
+      $display("Dut state:");
+      $display("data_reg: 0x%014x", dut.data_reg);
+      $display("clk_ctr:   0x%08x", dut.clk_ctr_reg);
+      $display("bit_ctr:   0x%02x", dut.bit_ctr_reg);
+      $display("ctrl:      0x%02x, done: 0x%01x, ready: 0x%01x",
+               dut.spi_ctrl_reg, dut.bit_ctr_done, tb_ready);
+      $display("Output:");
+      $display("en: 0x%01x, sclk: 0x%01x, di: 0x%01x, do: 0x%01x",
+               tb_spi_cs_n, tb_spi_sclk, tb_spi_di, tb_spi_di);
+      $display("read data: 0x%08x", tb_read_data);
+      $display("");
+    end
+  endtask // dump_state
+
+
+  //----------------------------------------------------------------
+  // wait_ready()
+  //
+  // Wait for ready word to be set in the DUT API.
+  //----------------------------------------------------------------
+  task wait_ready;
+    reg ready;
+    begin
+      ready = 0;
+
+      while (tb_ready == 0)
+        begin
+          #(CLK_PERIOD);
+          dump_state();
+        end
+    end
+  endtask // read_word
+
+
+  //----------------------------------------------------------------
+  // tb_init
+  // Initialize varibles, dut inputs at start.
+  //----------------------------------------------------------------
+  task tb_init;
+    begin
+      test_ctr      = 0;
+      error_ctr     = 0;
+      cycle_ctr     = 0;
+
+      tb_clk        = 0;
+      tb_reset_n    = 1;
+      tb_spi_do     = 0;
+      tb_set        = 0;
+      tb_start      = 0;
+      tb_length     = 3'h7;
+      tb_divisor    = 16'h0008;
+      tb_write_data = 32'haa55aa55;
+
+      tb_dump_state = 0;
+    end
+  endtask // tb_init
+
+
+  //----------------------------------------------------------------
+  // toggle_reset
+  // Toggle the reset.
+  //----------------------------------------------------------------
+  task toggle_reset;
+    begin
+      $display("  -- Toggling reset.");
+      dump_state();
+      #(2 * CLK_PERIOD);
+      tb_reset_n = 0;
+      #(10 * CLK_PERIOD);
+      @(negedge tb_clk)
+      tb_reset_n = 1;
+      dump_state();
+      $display("  -- Toggling of reset done.");
+    end
+  endtask // toggle_reset
+
+
+  //----------------------------------------------------------------
+  // transmit_data
+  // Test case for testing that the dut will transmit data
+  // on the interface.
+  //----------------------------------------------------------------
+  task transmit_data;
+    begin
+      $display("  -- Trying to transmit data.");
+      tb_set = 1;
+      tb_write_data = 56'hdeadbeeff18244;
+      #(2 * CLK_PERIOD);
+      $display("Contents of data reg in dut after set: 0x%14x",
+               dut.data_reg);
+
+      #(2 * CLK_PERIOD);
+      tb_divisor    = 16'h8;
+      tb_length     = 3'h4;
+      tb_start      = 1;
+      #(2 * CLK_PERIOD);
+      tb_start      = 0;
+
+      wait_ready();
+
+      $display("  -- Transmit data test done..");
+    end
+  endtask // transmit_data
+
+
+  //----------------------------------------------------------------
+  // mkmif_spi_test
+  // The main test functionality.
+  //----------------------------------------------------------------
+  initial
+    begin : mkmif_spi_test
+      $display("   -- Test of mkmif spi started --");
+
+      tb_init();
+      toggle_reset();
+      transmit_data();
+
+      $display("");
+      $display("   -- Test of mkmif spi completed --");
+      $display("Tests executed: %04d", test_ctr);
+      $display("Tests failed:   %04d", error_ctr);
+      $finish;
+    end // mkmif_spi_test
+
+endmodule // tb_mkmif_spi
+
+//======================================================================
+// EOF tb_mkmif_spi.v
+//======================================================================
diff --git a/toolruns/Makefile b/toolruns/Makefile
new file mode 100644
index 0000000..4d36b5c
--- /dev/null
+++ b/toolruns/Makefile
@@ -0,0 +1,85 @@
+#=======================================================================
+#
+# Makefile
+# --------
+# Makefile for building the mkmif core.
+#
+#
+# Copyright (c) 2011, 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.
+#
+#=======================================================================
+
+SPI_SRC = ../src/rtl/mkmif_spi.v
+SPI_TB = ../src/tb/tb_mkmif_spi.v
+
+CORE_SRC = ../src/rtl/mkmif_core.v $(SPI_SRC)
+CORE_TB = ../src/tb/tb_mkmif_core.v
+
+TOP_SRC = ../src/rtl/mkmif.v $(CORE_SRC)
+TOP_TB = ../src/tb/tb_mkmif.v
+
+CC = iverilog
+LINT=verilator
+
+
+all:    top.sim core.sim spi.sim
+
+
+spi.sim:	$(SPI_TB) $(SPI_SRC)
+	iverilog -Wall -o spi.sim $(SPI_TB) $(SPI_SRC)
+
+
+core.sim:	$(CORE_TB) $(CORE_SRC)
+	iverilog -Wall -o core.sim $(CORE_TB) $(CORE_SRC)
+
+
+top.sim:	$(TOP_TB) $(TOP_SRC)
+	iverilog -Wall -o top.sim $(TOP_TB) $(TOP_SRC)
+
+
+lint:
+	verilator +1364-2001ext+ --lint-only -Wall $(TOP_SRC)
+
+
+clean:
+	rm *.sim
+
+
+help:
+	@echo "Supported targets:"
+	@echo "------------------"
+	@echo "all:      Build all simulation targets."
+	@echo "core:     Build the core simulation target."
+	@echo "top:      Build the top simulation target."
+	@echo "lint:     Run the linter on the source"
+	@echo "clean:    Delete all built files."
+
+#=======================================================================
+# EOF Makefile
+#=======================================================================

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the Commits mailing list