-- LEGGERE CON ATTENZIONE tutta la sezione introdutiva

-- COMPLETARE L'ANAGRAFICA
-- * Cognome: ...
-- * Nome: ...
-- * Matricola: ...

-- DESCRIZIONE DELLA PROVA:
-- il candiato progetti, disegni su foglio e descriva in VHDL un circuito che
-- ad ogni colpo di CLK campioni l'ingresso ovvero un vettore di 4 bit (DATAIN)  
-- e verifichi se si presenta la sequenza 1 - 2 - 3 ; 
-- in tal caso, al successivo colpo di CLK, l'uscita GOAL deve andare ad '1' e ci starà fino a quando all'ingresso non si presenta il numero 0
-- il numero 0 ovvero "0000" agisce da RESET del sistema

-- OSSERVAZIONI
-- si realizzi circuito come si crede purchè in modo RTL
-- a tal fine si possono utilizzare come COMPONENT le entity presenti in testa al progetto
-- ATTENZIONE: se si intendesse utilizzare una MSF (Macchina a Stati Finiti) si tenga presente che
-- NON è necessario assegnare una codifica esplicita agli stati
-- il TestBench è già predisposto per la simulazione
-- per editare il file si consiglia di utilizzare l'editor NOTEPAD++ (copiatene un collegamento sul desktop)

-- ISTRUZIONI:
-- si noti che per verificare e simulare il circuito si deve fare in modo che il programma GHDL sia nel PATH, per cui:
-- 1. aprire una finestra di comando: START-> Esegui -> CMD ed indirizzarla nella direcotry di lavoro
-- 2. digitare: set path=%path%;C:\Programmi\GHDL\bin;C:\Programmi\GHDL\gtk\bin;
-- il punto 2 va eseguito solo la prima volta e vale finché non si chiude la finestra di comando
-- 3. digitare: GHDL -a [nomefile.vhdl]
-- 4. digitare: GHDL -e [nome entity]
-- il punto 4 deve essere ripetuto per tutte le entity presenti nel file [nomefile.vhdl]
-- 5. digitare GHDL -r [nome entity_tb] --vcd=out.vcd
-- 6. se dopo il punto 5 non compare nulla nella riga di comando allora la simulazione è OK 
-- se invece compare un messaggio di Warning è necessario controllare con gtkwave 
-- dove il vostro segnale differisce quello del processo di riferimento, ovvero 'Processo_di_Test'
-- 7. digitare: gtkwave out.vcd 

-- CONSIGLI IMPORTANTI:
-- 1. la realizzazione mediante instanziazione dei COMPONENT già previsti è consigliata
-- 2. per avere un'idea dell'andamento che devono avere i segnali e per provare la procedura 
-- di compilazione e visualizzazione, prima di cominciare a scrivere alcunché, si esegua 
-- tutta la procedura e vi visualizza il risultato utilizzando il TestBench già predisposto
-- 3. chi  lo preferisce può utilizzare il file MAKE.BAT già predisposto
-- 4. FACENDO PRIMA IL DISEGNO DEL CIRCUITO LA PROVA RISULTA MOLTO SEMPLIFICATA
----------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------

-- descrizione del FFD da usare come componente
-- questa parte non deve essere modificata
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

	entity FFD is
  	port(CLK, D, reset : in std_logic;
		 Q : out std_logic);
	end FFD;
	
	architecture behaviour of FFD is
	begin
		process(CLK, reset)
		begin
			if reset='1' then Q<='0';  
			elsif (clk'event and clk='1') then Q<=D;											
			else null;
			end if;
		end process;
	end behaviour;

-- descrizione del FFT da usare come componente
-- questa parte non deve essere modificata
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

	entity FFT is
  	port(CLK, T, reset : in std_logic;
		 Q : out std_logic);
	end FFT;
	
	architecture behaviour of FFT is
	signal x: std_logic:='0';
	begin
		process(CLK, reset)
		begin
		if reset='1' then x<='0';  
		elsif (clk'event and clk='1') then 
											if T='1' then x<=not x;
											else null;
											end if;
		else null;
		end if;
		end process;
		Q<=x;
	end behaviour;

-- descrizione del Comparatore di Uguaglianza Sincrono da usare come componente
-- questa parte non deve essere modificata	
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity CdUS is
port( A,B: in std_logic_vector(3 downto 0);
	  CLK: in std_logic;
		Z: out std_logic );
end CdUS;

architecture dataflow of CdUS is
begin
	process(CLK)
		begin
		if (clk'event and clk='1') then 
										if A=B then Z<='1';
										else Z<='0';
										end if;
		else null;
		end if;
	end process;
	
end dataflow;

----------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------

-- descrizione dell'entità oggetto di progetto: TOP
-- si modifichi solo la sezione 'architecture'
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity TOP is
	port (	CLK: in std_logic;
			DATAIN: in std_logic_vector (3 downto 0);
			GOAL : out std_logic);
end entity TOP;

architecture RTL of TOP is
--dichiarazione dei SIGNAL
signal mem1_1, mem1_2, mem2_1: std_logic;
signal zero, one, two, three: std_logic;
signal seq_found, pre_mem, pre_goal: std_logic;
  
--dichiarazione dei COMPONENT
	component FFD is
  	port(CLK, D, reset : in std_logic;
		 Q : out std_logic);
	end component;
	
	component FFT is
  	port(CLK, T, reset : in std_logic;
		 Q : out std_logic);
	end component;
	
	component CdUS is
	port(A,B: in std_logic_vector(3 downto 0);
	     CLK: in std_logic;
		  Z : out std_logic );
	end component CdUS;

-- si modifichi questa sezione; 
-- ATTENZIONE a dichiarare opportunamente i signal che si intende utilizzare
begin
	--inst0:  CdUS port map (A => DATAIN, B => "0000", CLK=>CLK, Z=>zero);

  -- Comparators
  comp_0: CdUS port map (A=>DATAIN, B=>"0000", CLK=>CLK, Z=>zero);
  comp_1: CdUS port map (A=>DATAIN, B=>"0001", CLK=>CLK, Z=>one);
  comp_2: CdUS port map (A=>DATAIN, B=>"0010", CLK=>CLK, Z=>two);
  comp_3: CdUS port map (A=>DATAIN, B=>"0011", CLK=>CLK, Z=>three);

  -- Memories
  mem_1_1: FFD port map (D=>one, CLK=>CLK, reset=>zero, Q=>mem1_1);
  mem_1_2: FFD port map (D=>mem1_1, CLK=>CLK, reset=>zero, Q=>mem1_2);
  mem_2_1: FFD port map (D=>two, CLK=>CLK, reset=>zero, Q=>mem2_1);

  -- Sequence check
  seq_found <= mem1_2 and mem2_1 and three;

  -- Memory
  pre_mem <= seq_found or pre_goal;
  state: FFD port map (D=>pre_mem, CLK=>CLK, reset=>zero, Q=>pre_goal);
  GOAL <= pre_goal;

	
end architecture RTL;

----------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------

-- descrizione del Test_bench
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity TOP_tb is
end TOP_tb;

architecture behaviour of TOP_tb is

--dichiarazione dei COMPONENT ovvero la Unit Under Test
component TOP is
	port (	CLK: in std_logic;
			DATAIN: in std_logic_vector (3 downto 0);
			GOAL : out std_logic);
end component;

-- Clock period definitions
constant clk_period : time := 1 us; 
   
signal CLK: std_logic := '0';
signal DATAIN: std_logic_vector (3 downto 0) := "0000";
signal GOAL: std_logic ;

signal I : integer := 0; -- variabile per il conteggio dei clock
signal TEST_GOAL, errore: std_logic := '0';

begin
		clk_process: process --processo di generazione del CLK
		begin
			clk <= '0';
			wait for clk_period/2;
			clk <= '1';
			wait for clk_period/2;
			I<=I+1;
		
			if I=20 then wait; -- durata della simulazione: 20 colpi di CLK
			else null;
			end if;
		
		end process;
	
	-- instanziazione della Unit Under Test
	UUT: TOP port map (CLK => CLK, DATAIN=>DATAIN, GOAL=>GOAL);

	stimoli: process
    begin		
		DATAIN <= "0000";
		wait for clk_period*1;
		DATAIN <= "0001";
		wait for clk_period*1;
		DATAIN <= "0010";
		wait for clk_period*1;
		DATAIN <= "0011";
		wait for clk_period*1;
		DATAIN <= "0100";
		wait for clk_period*1;
		DATAIN <= "0101";
		wait for clk_period*1;
		DATAIN <= "0110";
		wait for clk_period*1;
		DATAIN <= "0111";
		wait for clk_period*1;
		DATAIN <= "1000";
		wait for clk_period*1;
		DATAIN <= "1001";
		wait for clk_period*1;
		DATAIN <= "1010";
		wait for clk_period*1;
		DATAIN <= "1011";
		wait for clk_period*1;
		DATAIN <= "1100";
		wait for clk_period*1;
		DATAIN <= "1101";
		wait for clk_period*1;
		DATAIN <= "1110";
		wait for clk_period*1;
		DATAIN <= "1111";
		wait for clk_period*1;
		DATAIN <= "0000";
		wait for clk_period*1;
		DATAIN <= "1000";
		wait for clk_period*1;
		DATAIN <= "0111";
		wait for clk_period*1;
		DATAIN <= "0110";
		wait for clk_period*1;

		wait;
		
    end process;
	
	
	Processo_di_Test: process
	begin
		test_goal<='0'; 
		wait for clk_period/2;
		wait for clk_period*4;
		test_goal<='1'; 
		wait for clk_period*12;
		test_goal<='0'; 
		wait;
	end process;
	
   
   
   ERRORE <= '0' when (goal=test_goal) else '1' after 1 ns;  
   assert (ERRORE='0')
   report "attenzione! controlla con GTKWAVE"
   severity WARNING;
   
end behaviour;
	
	
	
	
