====== Synchronous FIFO ======
===== Parametereinstellung =====
Eine kurze Funktions- und Schnittstellenbeschreibung:
* Das Modell ist in der Speichertiefe (@SPTF) und der Speicherbreite (@BITBR) parametrisierbar.
* Ein- und Auslesen erfolgt erfolgt bei einer positiven Flanke des anliegenden Taktsignals
{{:synthesizeable_vhdl-model-library:lib_sync_fifo.svg?nolink&300|Synchronous FIFO block diagram}}
===== Schnittstellen =====
* takt : Taktsignal für die Zähler innerhalb des FIFOs
* shift_in : mit Aktivierung diese Signals zeigt ein angeschlossenes Modul an, daß es gültige Daten an den Eingang des FIFOs angelegt hat.
* input_ready : FIFO signalisiert damit, daß es bereit ist, Daten aufzunehmen.
* data_in : Vektor für die Eingabedaten
* master_reset : Rücksetzsignal für gesamtes FIFO
* output_enable : FIFO signalisiert damit, daß es bereit ist, Daten auszugeben
* data_out : Vektor für die Ausgabedaten
* shift_out : mit Aktivierung dieses Signals zeigt ein angeschlossenes Modul an, daß es Daten aus dem FIFO auslesen möchte
* output_ready : FIFO signalisiert damit, daß es bereit ist, Daten auszugeben
===== Model =====
-- ############################################################################
-- # Project : VHDL-Modellbibliothek #
-- # #
-- # Filename : sync_fifo.vhd #
-- # #
-- # Schaltung : "First In First Out" - Speicher #
-- # #
-- # #
-- # Modell : sync_fifo.vhd #
-- # #
-- # Designer : Wolfgang Sehr; ueberarbeitet von Stefan Schmechtig #
-- # Abteilung : Lehrstul fuer rechnergestuetzten Schaltungsentwurf #
-- # Datum : 20.02.1995 #
-- ############################################################################
-- ############################################################################
-- # IEEE PACKAGES #
-- ############################################################################
Library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
-- ############################################################################
-- ############################################################################
-- # PROJEKT - SPEZIFISCHE PACKAGES #
-- ############################################################################
use WORK.local.all;
-- ############################################################################
ENTITY sync_fifo IS
GENERIC(X : INTEGER := @BITBR; -- X: Bitbreite
Y : INTEGER := @SPTF -- Y: Speichertiefe
);
PORT(takt : IN STD_LOGIC;
shift_in : IN STD_LOGIC;
input_ready : OUT STD_LOGIC;
data_in : IN UNSIGNED ((X-1) DOWNTO 0);
master_reset : IN STD_LOGIC;
output_enable : IN STD_LOGIC;
data_out : OUT UNSIGNED ((X-1) DOWNTO 0);
shift_out : IN STD_LOGIC;
output_ready : OUT STD_LOGIC
);
-- takt : Taktsignal fuer die Zaehler innerhalb des FIFOs
-- :
-- shift_in : mit Aktivierung diese Signals zeigt angeschlossenes
-- : Modul an, dass es gueltige Daten an den Eingang des
-- : FIFOs angelegt hat
-- :
-- input_ready : FIFO signalisiert damit, ob es bereit ist,
-- : Daten aufzunehmen
-- :
-- data_in : Vektor fuer die Eingabedaten
-- :
-- master_reset : Ruecksetzsignal fuer gesamtes FIFO
-- :
-- output_enable: FIFO signalisiert damit, ob es bereit ist,
-- : Daten auszugeben
-- :
-- data_out : Vektor fuer die Ausgabedaten
-- :
-- shift_out : mit Aktivierung diese Signals zeigt angeschlossenes
-- : Modul an, dass es Daten aus dem FIFO auslesen moechte
-- :
-- output_ready : FIFO signalisiert damit, dass es bereit ist,
-- : Daten auszugeben
-- :
END sync_fifo;
ARCHITECTURE verhalten OF sync_fifo IS
SIGNAL ram : UNSIGNED(((X*Y)-1) DOWNTO 0);
SIGNAL ram_naechst : UNSIGNED(((X*Y)-1) DOWNTO 0);
SIGNAL write_pointer : UNSIGNED(LOG_2(Y) DOWNTO 0);
SIGNAL read_pointer : UNSIGNED(LOG_2(Y) DOWNTO 0);
SIGNAL write_pointer_naechst : UNSIGNED(LOG_2(Y) DOWNTO 0);
SIGNAL read_pointer_naechst : UNSIGNED(LOG_2(Y) DOWNTO 0);
SIGNAL content_counter : UNSIGNED(LOG_2(Y) DOWNTO 0);
SIGNAL content_counter_naechst : UNSIGNED(LOG_2(Y) DOWNTO 0);
SIGNAL input_ready_naechst : STD_LOGIC;
SIGNAL output_ready_naechst : STD_LOGIC;
SIGNAL input_ready_sig : STD_LOGIC;
SIGNAL output_ready_sig : STD_LOGIC;
SIGNAL data_out_naechst : UNSIGNED ((X-1) DOWNTO 0);
-- ram : eigentlicher Speicher
-- :
-- write_pointer : zeigt auf die Plazierung des zu
-- : schreibenden Datums
-- :
-- write_pointer_naechst : zeigt auf die Plazierung des naechsten
-- : zu schreibenden Datums
-- :
-- read_pointer : zeigt auf die Plazierung des zu
-- : lesenden Datums
-- :
-- read_pointer_naechst : zeigt auf die Plazierung des naechsten
-- : zu Lesenden Datums
-- :
-- content_counter : gibt die Anzahl der aktuell einge-
-- : schriebenen Daten an
-- :
-- content_counter_naechst : gibt die Anzahl der beim naechsten
-- : Taktzyklus eingeschriebenen Daten an
-- :
-- input_ready_sig : gleiche Bedeutung wie 'input_ready'
-- : -Port
-- : jedoch auch innerhalb der Architecture
-- : lesbar
-- :
-- output_ready_sig : gleiche Bedeutung wie 'output_ready'
-- : -Port, jedoch auch innerhalb der
-- : Architecture lesbar
-- :
-- input_ready_naechst : input_ready Signal fuer den naechsten
-- : Taktzyklus
-- output_ready_naechst : output_ready Signal fuer den naechsten
-- : Zustand
-- :
-- data_out_naechst : Wert von 'data_out', der bei der
-- : naechsten positiven Taktflanke ueber-
-- : nommen wird
BEGIN
input_ready <= input_ready_sig;
output_ready <= output_ready_sig;
cont_komb: PROCESS(master_reset, shift_in, shift_out, data_in,
read_pointer, write_pointer, output_enable,
input_ready_sig, output_ready_sig,
content_counter, ram)
VARIABLE content_counter_var : UNSIGNED((content_counter'LENGTH-1) DOWNTO 0);
VARIABLE content_counter_var_naechst
: UNSIGNED((content_counter'LENGTH-1) DOWNTO 0);
VARIABLE input_ready_var : STD_LOGIC;
VARIABLE output_ready_var : STD_LOGIC;
VARIABLE input_ready_var_naechst : STD_LOGIC;
VARIABLE output_ready_var_naechst : STD_LOGIC;
VARIABLE ram_var : UNSIGNED((ram'LENGTH-1) DOWNTO 0);
VARIABLE data_out_var : UNSIGNED ((data_out'LENGTH-1) DOWNTO 0);
VARIABLE write_pointer_var : UNSIGNED((write_pointer'LENGTH-1) DOWNTO 0);
VARIABLE write_pointer_var_naechst
: UNSIGNED((write_pointer'LENGTH-1) DOWNTO 0);
VARIABLE read_pointer_var : UNSIGNED((read_pointer'LENGTH-1) DOWNTO 0);
VARIABLE read_pointer_var_naechst
: UNSIGNED((read_pointer'LENGTH-1) DOWNTO 0);
VARIABLE ents : UNSIGNED(6 DOWNTO 0);
VARIABLE ents_log : STD_LOGIC_VECTOR(6 DOWNTO 0);
VARIABLE cont_count_var_kl_Y : STD_LOGIC;
VARIABLE rd_pt_var_gl_Y : STD_LOGIC;
VARIABLE wr_pt_var_gl_Y : STD_LOGIC;
VARIABLE write_var : STD_LOGIC;
VARIABLE read_var : STD_LOGIC;
-- content_counter_var : Variable fuer den Zaehlerinhalt von
-- : 'content_counter'
-- :
-- content_counter_var_naechst : Variable fuer den im naechsten
-- : Taktzyklus gueltigen Zaehlerinhalt von
-- : 'content_counter'
-- :
-- input_ready_var : Variable fuer 'input_ready' Signal
-- :
-- output_ready_var : Variable fuer 'output_ready' Signal
-- :
-- input_ready_var_naechst : Variable fuer den im naechsten Takt-
-- : zyklus gueltigen Wert des Signals
-- : 'input_ready_var'
-- :
-- output_ready_var_naechst : Variable fuer den im naechsten Takt-
-- : zyklus gueltigen Wert des Signals
-- : 'output_ready_var'
-- :
-- ram_var : Variable fuer den Wert des Speichers
-- :
-- write_pointer_var : gibt aktuellen Wert des write-pointer
-- : an
-- :
-- write_pointer_var_naechst : gibt den Wert des write-pointers im
-- : naechsten Taktzyklus an
-- :
-- read_pointer_var : gibt aktuellen Wert des read-pointers
-- : an
-- :
-- read_pointer_var_naechst : gibt den im naechsten Taktzyklus
-- : gueltigen Wert von read_pointer an
-- :
-- ents : Entscheidungsvariable im UNSIGNED-
-- : Format
-- :
-- ents_log : Entscheidungsvariable als STD_LOGIC_
-- : VECTOR
-- :
-- cont_count_var_kl_Y : o '1', wenn content_counter kleiner Y
-- : o '0', sonst
-- :
-- rd_pt_var_gl_Y : o '1', wenn "write_pointer" = (Y-1)
-- : o '0', sonst
-- :
-- wr_pt_var_gl_Y : o '1', wenn "read_pointer" = (Y-1)
-- : o '0', sonst
-- :
-- write_var : o '1', wenn in das Ram geschrieben
-- : werden soll
-- : o '0', wenn nicht in das Ram ge-
-- : schrieben werden soll
-- read_var : o '1', wenn aus dem Ram gelesen werden
-- : soll
-- : o '0', wenn nicht aus dem Ram gelesen
-- : werden soll
BEGIN
-- ######################################################################
-- ### Variablen-Zuweisungen ###
-- ######################################################################
content_counter_var := content_counter;
input_ready_var := input_ready_sig;
output_ready_var := output_ready_sig;
ram_var := ram;
read_pointer_var := read_pointer;
write_pointer_var := write_pointer;
data_out_var := CONV_UNSIGNED(0, data_out_var'LENGTH);
read_var := '0';
write_var := '0';
IF (content_counter_var < Y) THEN cont_count_var_kl_Y := '1';
ELSE
cont_count_var_kl_Y := '0';
END IF;
IF (read_pointer_var = (Y-1)) THEN
rd_pt_var_gl_Y := '1';
ELSE
rd_pt_var_gl_Y := '0';
END IF;
IF (write_pointer_var = (Y-1)) THEN
wr_pt_var_gl_Y := '1';
ELSE
wr_pt_var_gl_Y := '0';
END IF;
ents := shift_in &
shift_out &
input_ready_var &
output_ready_var &
cont_count_var_kl_Y &
wr_pt_var_gl_Y &
rd_pt_var_gl_Y;
ents_log := CONV_STD_LOGIC_VECTOR(ents, ents_log'LENGTH);
-- ######################################################################
-- ######################################################################
-- ### Bestimmung des naechsten Inhaltes der einzelnen Zaehler ###
-- ######################################################################
IF (master_reset ='1') THEN
content_counter_var_naechst
:= CONV_UNSIGNED(0,content_counter_var_naechst'LENGTH);
write_pointer_var_naechst
:= CONV_UNSIGNED(0, write_pointer_var_naechst'LENGTH);
read_pointer_var_naechst
:= CONV_UNSIGNED(0, read_pointer_var_naechst'LENGTH);
ram_var := CONV_UNSIGNED(0, ram_var'LENGTH);
ELSE
IF (ents_log AND "1110110") = "1010100"
THEN -- Fall_1: ents= "101-10-"
content_counter_var_naechst := content_counter_var + 1;
write_pointer_var_naechst := write_pointer_var + 1;
read_pointer_var_naechst := read_pointer_var;
write_var := '1';
read_var := '0';
ELSIF (ents_log AND "1110110") = "1010110"
THEN -- Fall_2: ents= "101-11-" oder
content_counter_var_naechst := content_counter_var + 1;
write_pointer_var_naechst := CONV_UNSIGNED(0,
write_pointer_var_naechst'LENGTH);
read_pointer_var_naechst := read_pointer_var;
write_var := '1';
read_var := '0';
ELSIF ((ents_log AND "1101001") = "0101000") OR
((ents_log AND "1111001") = "1101000")
THEN -- Fall_3: ents= "01-1--0" oder
-- ents= "1101--0"
content_counter_var_naechst := content_counter_var - 1;
write_pointer_var_naechst := write_pointer_var;
read_pointer_var_naechst := read_pointer_var + 1;
write_var := '0';
read_var := '1';
ELSIF ((ents_log AND "1101001") = "0101001") OR
((ents_log AND "1111001") = "1101001")
THEN -- Fall_4: ents= "01-1--1" oder
-- ents= "1101--1"
content_counter_var_naechst := content_counter_var - 1;
write_pointer_var_naechst := write_pointer_var;
read_pointer_var_naechst := CONV_UNSIGNED(0,
read_pointer_var_naechst'LENGTH);
write_var := '0';
read_var := '1';
ELSIF ((ents_log AND "1110011") = "1110000")
THEN -- Fall_5: ents= "111--00"
content_counter_var_naechst := content_counter_var;
write_pointer_var_naechst := write_pointer_var + 1;
read_pointer_var_naechst := read_pointer_var + 1;
write_var := '1';
read_var := '1';
ELSIF ((ents_log AND "1110011")= "1110001")
THEN -- Fall_6: ents= "111--01"
content_counter_var_naechst := content_counter_var;
write_pointer_var_naechst := write_pointer_var + 1;
read_pointer_var_naechst := CONV_UNSIGNED(0,
read_pointer_var_naechst'LENGTH);
write_var := '1';
read_var := '1';
ELSIF ((ents_log AND "1110011") = "1110010")
THEN -- Fall_7: ents= "111--10"
content_counter_var_naechst := content_counter_var;
write_pointer_var_naechst := CONV_UNSIGNED(0,
write_pointer_var_naechst'LENGTH);
read_pointer_var_naechst := read_pointer_var + 1;
write_var := '1';
read_var := '1';
ELSIF ((ents_log AND "1110011") = "1110011")
THEN -- Fall_8: ents= "111--11"
content_counter_var_naechst := content_counter_var;
write_pointer_var_naechst := CONV_UNSIGNED(0,
write_pointer_var_naechst'LENGTH);
read_pointer_var_naechst := CONV_UNSIGNED(0,
read_pointer_var_naechst'LENGTH);
write_var := '1';
read_var := '1';
ELSE
content_counter_var_naechst := content_counter_var;
write_pointer_var_naechst := write_pointer_var;
read_pointer_var_naechst := read_pointer_var;
write_var := '0';
read_var := '0';
END IF;
END IF;
-- ######################################################################
-- #####################################################################
-- ### Bestimmung der Ausgangssignale / des RAM-Inhalts ###
-- #####################################################################
FOR i IN 0 TO (Y-1) LOOP
IF ((i = CONV_INTEGER(write_pointer_var)) AND
(write_var='1')) THEN
FOR j IN 0 TO (X-1) LOOP
ram_var(X*i + j) := data_in(j);
END LOOP;
END IF;
END LOOP;
FOR i IN 0 TO (Y-1) LOOP
IF ((i = CONV_INTEGER(read_pointer_var)) AND
(read_var='1')) THEN
FOR j IN 0 TO (X-1) LOOP
data_out_var(j) := ram_var(X*i + j);
END LOOP;
END IF;
END LOOP;
IF (content_counter_var_naechst < Y) THEN
input_ready_var_naechst := '1';
ELSE
input_ready_var_naechst := '0';
END IF;
IF (content_counter_var_naechst /= 0) THEN
output_ready_var_naechst := '1';
ELSE
output_ready_var_naechst := '0';
END IF;
IF (output_enable /= '1') OR (read_var = '0')THEN
data_out_var := CONV_UNSIGNED('Z', data_out_var'LENGTH);
END IF;
-- ####################################################################
content_counter_naechst <= content_counter_var_naechst;
input_ready_naechst <= input_ready_var_naechst;
output_ready_naechst <= output_ready_var_naechst;
write_pointer_naechst <= write_pointer_var_naechst;
read_pointer_naechst <= read_pointer_var_naechst;
data_out_naechst <= data_out_var;
ram_naechst <= ram_var;
END PROCESS;
cont_FF: PROCESS(takt, content_counter_naechst, input_ready_naechst,
output_ready_naechst, write_pointer_naechst,
read_pointer_naechst)
BEGIN
IF (takt = '1') AND (takt'EVENT) THEN
content_counter <= content_counter_naechst;
input_ready_sig <= input_ready_naechst;
output_ready_sig <= output_ready_naechst;
write_pointer <= write_pointer_naechst;
read_pointer <= read_pointer_naechst;
data_out <= data_out_naechst;
ram <= ram_naechst;
END IF;
END PROCESS;
END verhalten;
CONFIGURATION CFG_sync_fifo OF sync_fifo IS
FOR verhalten
END FOR;
END CFG_sync_fifo;
===== Testbench =====
-- ############################################################################
-- # Project : VHDL-Modellbibliothek #
-- # #
-- # Filename : tb_sync_fifo.vhd #
-- # #
-- # Schaltung : Testbench fuer parametrisierbaren FIFO-Speicher #
-- # #
-- # Modell : tb_sync_fifo #
-- # #
-- # Designer : Wolfgang Sehr; ueberarbeitet von Stefan Schmechtig #
-- # Abteilung : Lehrstul fuer rechnergestuetzten Schaltungsentwurf #
-- # Datum : 08.02.1995 #
-- ############################################################################
-- ############################################################################
-- # SYNOPSYS PACKAGES #
-- ############################################################################
Library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
USE IEEE.math_real.all; -- wird fuer die Erzeugung von Zufallszahlen
-- benoetigt
-- ############################################################################
ENTITY TB_sync_fifo IS
GENERIC (X : INTEGER := @BITBR; -- X: Bitbreite
Y : INTEGER := @SPTF);
END TB_sync_fifo;
ARCHITECTURE behaviour of TB_sync_fifo IS
SIGNAL tb_takt : STD_LOGIC;
SIGNAL tb_shift_in : STD_LOGIC;
SIGNAL tb_input_ready : STD_LOGIC;
SIGNAL tb_data_in : UNSIGNED ((X-1) DOWNTO 0);
SIGNAL tb_master_reset : STD_LOGIC;
SIGNAL tb_output_enable : STD_LOGIC;
SIGNAL tb_data_out : UNSIGNED ((X-1) DOWNTO 0);
SIGNAL tb_shift_out : STD_LOGIC;
SIGNAL tb_output_ready : STD_LOGIC;
-- tb_takt : Taktsignal der Testbench
-- tb_shift_in : generiertes shift_in Signal
-- tb_input_ready : empfangenes input_ready Signal
-- tb_data_in : von der Testbench gelieferte Daten
-- tb_master_reset : generiertes Resetsignal
-- tb_output_enable : generiertes output_enable Signal
-- tb_data_out : empfangene Ausgabedaten des UUT
-- tb_shift_out : generiertes shift_out Signal
-- tb_output_ready : empfangenes output_ready Signal
COMPONENT sync_fifo
PORT( takt : IN STD_LOGIC;
shift_in : IN STD_LOGIC;
input_ready : OUT STD_LOGIC;
data_in : IN UNSIGNED ((X-1) DOWNTO 0);
master_reset : IN STD_LOGIC;
output_enable : IN STD_LOGIC;
data_out : OUT UNSIGNED ((X-1) DOWNTO 0);
shift_out : IN STD_LOGIC;
output_ready : OUT STD_LOGIC
);
END COMPONENT;
BEGIN
UUT: sync_fifo -- einzige Schaltung
PORT MAP( takt => tb_takt,
shift_in => tb_shift_in,
input_ready => tb_input_ready,
data_in => tb_data_in,
master_reset => tb_master_reset,
output_enable => tb_output_enable,
data_out => tb_data_out,
shift_out => tb_shift_out,
output_ready => tb_output_ready
);
tkt: PROCESS
-- Generierung des Taktsignals
BEGIN
tb_takt <= '0';
WAIT FOR 2 ns;
LOOP
tb_takt <= NOT(tb_takt);
WAIT FOR 5 ns;
END LOOP;
END PROCESS;
res: PROCESS
-- Generierung des Resetsignals
BEGIN
tb_master_reset <= '1';
WAIT FOR 5 ns;
LOOP
tb_master_reset <= not(tb_master_reset);
WAIT FOR 300 ns;
tb_master_reset <= not(tb_master_reset);
WAIT FOR 10 ns;
END LOOP;
END PROCESS;
write: PROCESS
-- Generierung der Eingabedaten
VARIABLE data_in_int : INTEGER;
BEGIN
tb_shift_in <= '0';
WAIT FOR 10 ns;
LOOP
data_in_int := RAND;
tb_data_in <= CONV_UNSIGNED(data_in_int, tb_data_in'LENGTH);
tb_shift_in <= NOT(tb_shift_in);
WAIT FOR 10 ns;
END LOOP;
END PROCESS;
read: PROCESS
-- Generierung des shift_out Signals
BEGIN
tb_shift_out <= '0';
WAIT FOR 20 ns;
LOOP
tb_shift_out <= NOT(tb_shift_out);
WAIT FOR 17 ns;
END LOOP;
END PROCESS;
aus: PROCESS
-- Generierung des output_enable Signals
BEGIN
tb_output_enable <= '1';
WAIT FOR 100 ns;
LOOP
tb_output_enable <= NOT(tb_output_enable);
WAIT FOR 20 ns;
tb_output_enable <= NOT(tb_output_enable);
WAIT FOR 100 ns;
END LOOP;
END PROCESS;
END behaviour;
CONFIGURATION CFG_TB_sync_fifo OF TB_sync_fifo IS
FOR behaviour
FOR UUT: sync_fifo
USE CONFIGURATION WORK.CFG_sync_fifo;
END FOR;
END FOR;
END CFG_TB_sync_fifo;
===== Synopsys VSS Trace =====
tr tb_master_reset
tr tb_takt
tr tb_shift_in
tr tb_input_ready
tr tb_shift_out
tr tb_output_ready
tr tb_output_enable
tr tb_data_in
tr tb_data_out
cd UUT
tr ram