[Cryptech-Commits] [core/util/mkmif] 02/03: 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
Tue May 17 13:08:55 UTC 2016
This is an automated email from the git hooks/post-receive script.
paul at psgd.org pushed a commit to branch master
in repository core/util/mkmif.
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
+#=======================================================================
More information about the Commits
mailing list