aboutsummaryrefslogblamecommitdiff
path: root/src/rtl/trng_csprng_fifo.v
blob: f71a1526861ea58c12cf054695ea9dc83b3988ec (plain) (tree)






























































































































































































































































                                                                           
                                                





































































































































































































































































































                                                                        
//======================================================================
//
// trng_csprng_fifo.v
// ------------------
// Output FIFO for the CSPRNG in the TRNG.
//
//
// Author: Joachim Strombergson
// Copyright (c) 2014, 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 trng_csprng_fifo(
                        // Clock and reset.
                        input wire           clk,
                        input wire           reset_n,

                        input wire [511 : 0] csprng_data,
                        input wire           csprng_data_valid,
                        input wire           discard,
                        output wire          more_data,

                        output wire          rnd_syn,
                        output wire [31 : 0] rnd_data,
                        input wire           rnd_ack
                       );


  //----------------------------------------------------------------
  // Internal constant and parameter definitions.
  //----------------------------------------------------------------
  parameter FIFO_DEPTH = 32;
  parameter FIFO_MAX = FIFO_DEPTH - 1;

  parameter WR_IDLE    = 0;
  parameter WR_WAIT    = 1;
  parameter WR_WRITE   = 2;
  parameter WR_DISCARD = 7;

  parameter RD_IDLE    = 0;
  parameter RD_ACK     = 1;
  parameter RD_DISCARD = 7;


  //----------------------------------------------------------------
  // Registers including update variables and write enable.
  //----------------------------------------------------------------
  reg [31 : 0] fifo_mem [0 : FIFO_MAX];
  reg          fifo_mem_we;

  reg [3 : 0] mux_data_ptr_reg;
  reg [3 : 0] mux_data_ptr_new;
  reg         mux_data_ptr_inc;
  reg         mux_data_ptr_rst;
  reg         mux_data_ptr_we;

  reg [7 : 0] wr_ptr_reg;
  reg [7 : 0] wr_ptr_new;
  reg         wr_ptr_inc;
  reg         wr_ptr_rst;
  reg         wr_ptr_we;

  reg [7 : 0] rd_ptr_reg;
  reg [7 : 0] rd_ptr_new;
  reg         rd_ptr_inc;
  reg         rd_ptr_rst;
  reg         rd_ptr_we;

  reg [31 : 0] rnd_data_reg;

  reg          rnd_syn_reg;
  reg          rnd_syn_new;
  reg          rnd_syn_we;

  reg [2 : 0]  wr_ctrl_reg;
  reg [2 : 0]  wr_ctrl_new;
  reg          wr_ctrl_we;

  reg [2 : 0]  rd_ctrl_reg;
  reg [2 : 0]  rd_ctrl_new;
  reg          rd_ctrl_we;

  reg [5 : 0]  fifo_ctr_reg;
  reg [5 : 0]  fifo_ctr_new;
  reg          fifo_ctr_inc;
  reg          fifo_ctr_dec;
  reg          fifo_ctr_rst;
  reg          fifo_ctr_we;
  reg          fifo_empty;
  reg          fifo_full;

  reg          more_data_reg;
  reg          more_data_new;
  reg          more_data_we;


  //----------------------------------------------------------------
  // Wires.
  //----------------------------------------------------------------
  reg [31 : 0] muxed_data;


  //----------------------------------------------------------------
  // Concurrent connectivity for ports etc.
  //----------------------------------------------------------------
  assign rnd_data = rnd_data_reg;
  assign rnd_syn  = rnd_syn_reg;
  assign more_data = more_data_reg;


  //----------------------------------------------------------------
  // reg_update
  //----------------------------------------------------------------
  always @ (posedge clk or negedge reset_n)
    begin
      if (!reset_n)
        begin
          fifo_mem[00]     <= 32'h00000000;
          fifo_mem[01]     <= 32'h00000000;
          fifo_mem[02]     <= 32'h00000000;
          fifo_mem[03]     <= 32'h00000000;
          fifo_mem[04]     <= 32'h00000000;
          fifo_mem[05]     <= 32'h00000000;
          fifo_mem[06]     <= 32'h00000000;
          fifo_mem[07]     <= 32'h00000000;
          fifo_mem[08]     <= 32'h00000000;
          fifo_mem[09]     <= 32'h00000000;
          fifo_mem[10]     <= 32'h00000000;
          fifo_mem[11]     <= 32'h00000000;
          fifo_mem[12]     <= 32'h00000000;
          fifo_mem[13]     <= 32'h00000000;
          fifo_mem[14]     <= 32'h00000000;
          fifo_mem[15]     <= 32'h00000000;
          fifo_mem[16]     <= 32'h00000000;
          fifo_mem[17]     <= 32'h00000000;
          fifo_mem[18]     <= 32'h00000000;
          fifo_mem[19]     <= 32'h00000000;
          fifo_mem[20]     <= 32'h00000000;
          fifo_mem[21]     <= 32'h00000000;
          fifo_mem[22]     <= 32'h00000000;
          fifo_mem[23]     <= 32'h00000000;
          fifo_mem[24]     <= 32'h00000000;
          fifo_mem[25]     <= 32'h00000000;
          fifo_mem[26]     <= 32'h00000000;
          fifo_mem[27]     <= 32'h00000000;
          fifo_mem[28]     <= 32'h00000000;
          fifo_mem[29]     <= 32'h00000000;
          fifo_mem[30]     <= 32'h00000000;
          fifo_mem[31]     <= 32'h00000000;

          mux_data_ptr_reg <= 4'h0;
          wr_ptr_reg       <= 8'h00;
          rd_ptr_reg       <= 8'h00;
          fifo_ctr_reg     <= 6'h00;
          rnd_data_reg     <= 32'h00000000;
          rnd_syn_reg      <= 0;
          more_data_reg    <= 0;
          wr_ctrl_reg      <= 3'h0;
          rd_ctrl_reg      <= 3'h0;
        end
      else
        begin
          rnd_data_reg <= fifo_mem[rd_ptr_reg];

          if (rnd_syn_we)
            begin
              rnd_syn_reg  <= rnd_syn_new;
            end

          if (fifo_mem_we)
            begin
              fifo_mem[wr_ptr_reg] <= muxed_data;
            end

          if (mux_data_ptr_we)
            begin
              mux_data_ptr_reg <= mux_data_ptr_new;
            end

          if (wr_ptr_we)
            begin
              wr_ptr_reg <= wr_ptr_new;
            end

          if (rd_ptr_we)
            begin
              rd_ptr_reg <= rd_ptr_new;
            end

          if (fifo_ctr_we)
            begin
              fifo_ctr_reg <= fifo_ctr_new;
            end

          if (more_data_we)
            begin
              more_data_reg <= more_data_new;
            end

          if (wr_ctrl_we)
            begin
              wr_ctrl_reg <= wr_ctrl_new;
            end

          if (rd_ctrl_we)
            begin
              rd_ctrl_reg <= rd_ctrl_new;
            end
        end
    end // reg_update


  //----------------------------------------------------------------
  // data_mux
  //----------------------------------------------------------------
  always @*
    begin : data_mux
      case(mux_data_ptr_reg)
        00: muxed_data = csprng_data[031 : 000];
        01: muxed_data = csprng_data[063 : 032];
        02: muxed_data = csprng_data[095 : 064];
        03: muxed_data = csprng_data[127 : 096];
        04: muxed_data = csprng_data[159 : 128];
        05: muxed_data = csprng_data[191 : 160];
        06: muxed_data = csprng_data[223 : 192];
        07: muxed_data = csprng_data[255 : 224];
        08: muxed_data = csprng_data[287 : 256];
        09: muxed_data = csprng_data[313 : 282];
        10: muxed_data = csprng_data[351 : 320];
        11: muxed_data = csprng_data[383 : 352];
        12: muxed_data = csprng_data[415 : 384];
        13: muxed_data = csprng_data[447 : 416];
        14: muxed_data = csprng_data[479 : 448];
        15: muxed_data = csprng_data[511 : 480];
      endcase // case (mux_data_ptr_reg)
    end // data_mux


  //----------------------------------------------------------------
  // mux_data_ptr
  //----------------------------------------------------------------
  always @*
    begin : mux_data_ptr
      mux_data_ptr_new = 4'h0;
      mux_data_ptr_we  = 0;

      if (mux_data_ptr_rst)
        begin
          mux_data_ptr_new = 4'h0;
          mux_data_ptr_we  = 1;
        end

      if (mux_data_ptr_inc)
        begin
          mux_data_ptr_new = mux_data_ptr_reg + 1'b1;
          mux_data_ptr_we  = 1;
        end
    end // mux_data_ptr


  //----------------------------------------------------------------
  // fifo_rd_ptr
  //----------------------------------------------------------------
  always @*
    begin : fifo_rd_ptr
      rd_ptr_new = 8'h00;
      rd_ptr_we  = 0;

      if (rd_ptr_rst)
        begin
          rd_ptr_new = 8'h00;
          rd_ptr_we  = 1;
        end

      if (rd_ptr_inc)
        begin
          if (rd_ptr_reg == FIFO_MAX)
            begin
              rd_ptr_new = 8'h00;
              rd_ptr_we  = 1;
            end
          else
            begin
              rd_ptr_new = rd_ptr_reg + 1'b1;
              rd_ptr_we  = 1;
            end
        end
    end // fifo_rd_ptr


  //----------------------------------------------------------------
  // fifo_wr_ptr
  //----------------------------------------------------------------
  always @*
    begin : fifo_wr_ptr
      wr_ptr_new = 8'h00;
      wr_ptr_we  = 0;

      if (wr_ptr_rst)
        begin
          wr_ptr_new = 8'h00;
          wr_ptr_we  = 1;
        end

      if (wr_ptr_inc)
        begin
          if (wr_ptr_reg == FIFO_MAX)
            begin
              wr_ptr_new = 8'h00;
              wr_ptr_we  = 1;
            end
          else
            begin
              wr_ptr_new = wr_ptr_reg + 1'b1;
              wr_ptr_we  = 1;
            end
        end
    end // fifo_wr_ptr


  //----------------------------------------------------------------
  // fifo_ctr
  //
  // fifo counter tracks the number of elements and provides
  // signals for full and empty fifo.
  //----------------------------------------------------------------
  always @*
    begin : fifo_ctr
      fifo_empty = 0;
      fifo_full = 0;
      fifo_ctr_new = 6'h00;
      fifo_ctr_we  = 0;

      if (fifo_ctr_reg == FIFO_DEPTH)
        begin
          fifo_full = 1;
        end

      if (fifo_ctr_reg < 6'h0f)
        begin
          fifo_empty = 1;
        end

      if (fifo_ctr_inc)
        begin
          fifo_ctr_new = fifo_ctr_reg + 1'b1;
          fifo_ctr_we  = 1;
        end

      if (fifo_ctr_dec)
        begin
          fifo_ctr_new = fifo_ctr_reg - 1'b1;
          fifo_ctr_we  = 1;
        end

      if (fifo_ctr_rst)
        begin
          fifo_ctr_new = 6'h00;
          fifo_ctr_we  = 1;
        end
    end // fifo_ctr


  //----------------------------------------------------------------
  // rd_ctrl
  //----------------------------------------------------------------
  always @*
    begin : rd_ctrl
      fifo_ctr_dec = 0;
      rnd_syn_new  = 0;
      rnd_syn_we   = 0;
      rd_ptr_inc   = 0;
      rd_ptr_rst   = 0;
      rd_ctrl_new  = RD_IDLE;
      rd_ctrl_we   = 0;

      case (rd_ctrl_reg)
        RD_IDLE:
          begin
            if (discard)
              begin
                rd_ctrl_new = RD_DISCARD;
                rd_ctrl_we  = 1;
              end
            else
              begin
                if (!fifo_empty)
                  begin
                    rnd_syn_new = 1;
                    rnd_syn_we  = 1;
                    rd_ctrl_new = RD_ACK;
                    rd_ctrl_we  = 1;
                  end
              end
          end

        RD_ACK:
          begin
            if (discard)
              begin
                rd_ctrl_new = RD_DISCARD;
                rd_ctrl_we  = 1;
              end
            else
              begin
                if (rnd_ack)
                  begin
                    fifo_ctr_dec = 1;
                    rd_ptr_inc   = 1;
                    rnd_syn_new  = 0;
                    rnd_syn_we   = 1;
                    rd_ctrl_new  = RD_IDLE;
                    rd_ctrl_we   = 1;
                  end
              end
          end

        RD_DISCARD:
          begin
            rnd_syn_new = 0;
            rnd_syn_we  = 1;
            rd_ptr_rst  = 1;
            rd_ctrl_new = RD_IDLE;
            rd_ctrl_we  = 1;

          end

      endcase // case (rd_ctrl_reg)

    end // rd_ctrl


  //----------------------------------------------------------------
  // wr_ctrl
  //----------------------------------------------------------------
  always @*
    begin : wr_ctrl
      more_data_new    = 0;
      more_data_we     = 0;
      mux_data_ptr_rst = 0;
      mux_data_ptr_inc = 0;
      wr_ptr_inc       = 0;
      wr_ptr_rst       = 0;
      fifo_mem_we      = 0;
      fifo_ctr_inc     = 0;
      fifo_ctr_rst     = 0;
      wr_ctrl_new      = WR_IDLE;
      wr_ctrl_we       = 0;

      case (wr_ctrl_reg)
        WR_IDLE:
          begin
            if (discard)
              begin
                wr_ctrl_new = WR_DISCARD;
                wr_ctrl_we  = 1;
              end
            else if (!fifo_full)
              begin
                more_data_new = 1;
                more_data_we  = 1;
                wr_ctrl_new   = WR_WAIT;
                wr_ctrl_we    = 1;
              end
          end

        WR_WAIT:
          begin
            if (discard)
              begin
                wr_ctrl_new      = WR_DISCARD;
                wr_ctrl_we       = 1;
              end
            else if (csprng_data_valid)
              begin
                more_data_new    = 0;
                more_data_we     = 1;
                mux_data_ptr_rst = 1;
                wr_ctrl_new      = WR_WRITE;
                wr_ctrl_we       = 1;
              end
          end

        WR_WRITE:
          begin
            if (discard)
              begin
                wr_ctrl_new      = WR_DISCARD;
                wr_ctrl_we       = 1;
              end
            else if (!fifo_full)
              begin
                fifo_mem_we      = 1;
                wr_ptr_inc       = 1;
                mux_data_ptr_inc = 1;
                fifo_ctr_inc     = 1;

                if (mux_data_ptr_new == 4'h0)
                  begin
                    wr_ctrl_new = WR_IDLE;
                    wr_ctrl_we  = 1;
                  end
              end
          end

        WR_DISCARD:
          begin
            fifo_ctr_rst     = 1;
            more_data_new    = 0;
            more_data_we     = 1;
            mux_data_ptr_rst = 1;
            wr_ptr_rst       = 1;
            wr_ctrl_new      = WR_IDLE;
            wr_ctrl_we       = 1;
          end
      endcase // case (wr_ctrl_reg)

    end // wr_ctrl

endmodule // trng_csprng_fifo

//======================================================================
// EOF trng_csprng_fifo.v
//======================================================================