aboutsummaryrefslogtreecommitdiff
path: root/src/rtl/mkmif_spi.v
diff options
context:
space:
mode:
Diffstat (limited to 'src/rtl/mkmif_spi.v')
-rw-r--r--src/rtl/mkmif_spi.v378
1 files changed, 378 insertions, 0 deletions
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
+//======================================================================