//======================================================================
//
// 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 : 351];
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
//======================================================================