aboutsummaryrefslogblamecommitdiff
path: root/src/rtl/mkmif.v
blob: 4f448781b6f99be1f9aefc3ef4ddc59babe6c364 (plain) (tree)































































































































































































































































                                                                           
//======================================================================
//
// 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
//======================================================================