-----------------------------------------------------------------------------
---                                                                 Top Level      
---                                                   Random Number Generator
-----------------------------------------------------------------------------
--- File Name:  top_level.vhd
---
--- Description:
--- This block is the top level for the Random Number Generator. 
--- 
--- The Random Number Generator (RNG) is an implementation of a Asyncronous
--- Stop-and-Go genrator. It uses three LFSRs. This design is based on the
--- one found in Aplied Cryptography. The only changes that are made are
--- the two source LFSRs are seeded with a known value on reset and the
--- control LFSR is seeded with the number passed into the block.
---
--- I am not sure if this is safe or if the whole thing should be seeded 
--- externally. But, I think it is ok.
---
--- This RNG needs data_width clock cycles to complete. It could be done
--- quicker if an internal clock can be generated. But, that is possible
--- but getting the timing right would be a pain.
---
--- Limitations:
--- I dont fully understand the math behind LFSRs and I am using polynomials
--- from the internet. Not the smartest thing in the world to do, I have not
--- tested them to see if they are maximal length...But this not for secure
--- use. A properly genrated set of poly's should be used in needed.
---
--- More importantly I am generating 8bit byte random numbers. This means 
--- that the RNG needs to be clocked 8 times per cycle. I dont have the space
--- in the size of device that i can afford to play with to parallel them.
---
--- Errors:
---  None known.
---
--- Dependancies:
---  None.
---
--- Current Target: any lattice part with >186 macrocells (for 32 bit)
--- Simulator:      Symphony EDA - Sonata
--- Target Builder: Latice ispExpert
---
--- Author: Peter Antoine       Date: 30 Jun 2004
----------------------------------------------------------------------------
---                                         Copyright (c) 2004 Peter Antoine
----------------------------------------------------------------------------
--- Version   Author Date        Changes
--- -------   ------ ----------  -------------------------------------------
--- 0.1       PA     30.06.2004  Initial revision
--- 0.2       PA     02.07.2004  Now runs constantly rather than on req.
--- 0.3       PA     12.08.2004  Now will only assert dstrobe after data_width
---                              clock cycles. This will make sure that
---                              the bits presended are unique and not just
---                              ovelapping repeats.
--- 0.4       PA     21.08.2004  Change the clocking of the LFSR's to remove
---                              some silly code.
--- 0.5       PA     22.08.2004  Changes to fix synthesis problems.
----------------------------------------------------------------------------


library ieee;
use ieee.std_logic_1164.all;
use work.definitions.all;

entity  RandomNumberGenerator is
    port (  enable  : in    std_logic;                                  --- enables the bus output.
            clock   : in    std_logic;                                  --- system clock
            reset   : in    std_logic;                                  --- resets the block
            seed    : in    std_logic_vector(data_width-1 downto 0);    --- reset value
            dstrobe : out   std_logic;                                  --- set when the output is latched
            result  : out   std_logic_vector(data_width-1 downto 0));   --- the random number
end entity RandomNumberGenerator;

architecture rtl of RandomNumberGenerator is

    --- Components that are used in the random number generator
    component SShiftRegister is
        port (      load    : in std_logic;
                    clock   : in std_logic;
                    cin     : in std_logic;
                    din     : in std_logic_vector(data_width-1 downto 0);
                    dout    : out std_logic_vector(data_width-1 downto 0));
    end component SShiftRegister;

    component TriDataBuffer is
        port (      enable  : in std_logic;
                    clock   : in std_logic;
                    din     : in std_logic_vector(data_width-1 downto 0);
                    dstrobe : out std_logic;
                    dout    : out std_logic_vector(data_width-1 downto 0));
    end component TriDataBuffer;

    component RollOverCounter is
        port (      reset   : in std_logic;
                    clock   : in std_logic;
                    cout    : out std_logic);
    end component RollOverCounter;


    --- Internal signals
    signal  LFSR1FB : std_logic;
    signal  LFSR2FB : std_logic;
    signal  LFSR3FB : std_logic;

    signal  data_in:        std_logic;
    signal  bit_eight:      std_logic;
    signal  data_valid:     std_logic;
    signal  data_read:      std_logic;
    signal  data_enable:    std_logic;
    signal  lfsr_state:     std_logic;
    signal  lfsr2_clock:    std_logic;
    signal  lfsr3_clock:    std_logic;

    signal  LFSR_1  : std_logic_vector (data_width-1 downto 0);
    signal  LFSR_2  : std_logic_vector (data_width-1 downto 0);
    signal  LFSR_3  : std_logic_vector (data_width-1 downto 0);

    signal  rdata   : std_logic_vector (data_width-1 downto 0);

begin

    --- Generate the data enable
    --- Cant latch the data until the next data_width bits has been thought the RES shift register
    --- from the last read.
    ROC:    RollOverCounter port map (reset=>reset,clock=>clock,cout=>bit_eight);

    process (bit_eight,enable,reset,data_read)
    begin
        if ((data_read = '1' and enable = '0') or reset = '1')
        then
            data_valid <= '0';

        elsif (bit_eight'event and bit_eight = '1')
        then
            data_valid <= '1';

        end if;
    end process;

    process (enable,data_valid,reset)
    begin
        if (data_valid = '0' or reset = '1')
        then
            data_read <= '0';

        elsif (enable'event and enable = '0')
        then
            data_read <= data_valid;
        end if;
    end process;

    --- Set the data enable (the not clock is just here as a paranoid thing I dont like
    --- the idea of all the signals changing on the same edge. (simulates fine without it).
    data_enable <= (enable and data_valid and not clock);

    --- Handle the LFSRs themselves.
    LFSR1SR:    SShiftRegister port map (load=>reset,clock=>clock,cin=>LFSR1FB,din=>seed,dout=>LFSR_1);
    LFSR2SR:    SShiftRegister port map (load=>reset,clock=>lfsr2_clock,cin=>LFSR2FB,din=>LFSR2_SEED,dout=>LFSR_2);
    LFSR3SR:    SShiftRegister port map (load=>reset,clock=>lfsr3_clock,cin=>LFSR3FB,din=>LFSR3_SEED,dout=>LFSR_3);

    LFSR1FB <= LFSR_1_FeedbackFunction(LFSR_1);
    LFSR2FB <= LFSR_2_FeedbackFunction(LFSR_2);
    LFSR3FB <= LFSR_3_FeedbackFunction(LFSR_3);

    --- Latch the generator output.
    data_in <= (LFSR_2(0) xor LFSR_3(0)) when clock'event and clock = '0';

    --- clocking for the two LFSR's
    lfsr_state <= LFSR_1(0) when (clock'event and clock = '0');
    lfsr2_clock <= clock and lfsr_state;
    lfsr3_clock <= clock and not lfsr_state;

    --- Create the output word
    RES: SShiftRegister port map (load=>reset,clock=>clock,cin=>data_in,din=>ZERO_ARRAY,dout=>rdata);

    --- now the output stage -- give a stable output
    DBUFF: TriDataBuffer port map (enable=>enable,clock=>data_enable,din=>rdata,dout=>result,dstrobe=>dstrobe);

end architecture rtl;

--- $Id: top_level.vhd,v 1.10 2004/08/22 09:38:54 hardware Exp $
--- vi:nocin:sw=4 ts=4