From c03aa37d4f237f2eb90d9a958428011ca2bd455c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20Stro=CC=88mbergson?= Date: Wed, 11 May 2016 17:13:04 +0200 Subject: Adding all source files and testbenches for the mkmif core. Adding Makefile for building simulation and linting. Adding top level license file. --- src/rtl/mkmif.v | 256 ++++++++++++++++++++++++++++++++++ src/rtl/mkmif_core.v | 292 +++++++++++++++++++++++++++++++++++++++ src/rtl/mkmif_spi.v | 378 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 926 insertions(+) create mode 100644 src/rtl/mkmif.v create mode 100644 src/rtl/mkmif_core.v create mode 100644 src/rtl/mkmif_spi.v (limited to 'src/rtl') 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 +//====================================================================== -- cgit v1.2.3