Files
Progetto-reti-logiche/INFO/TO UPLOAD ON 1 JULY/10893566.vhd
T

339 lines
12 KiB
VHDL

-- Progetto di reti logiche 2025/2026 - Aleandro Pagani
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity project_reti_logiche is
port (
i_clk: in std_logic;
i_rst: in std_logic;
i_start: in std_logic;
i_task_id: in std_logic_vector(5 downto 0);
i_task_priority: in std_logic_vector(1 downto 0);
i_op: in std_logic_vector(1 downto 0);
o_done: out std_logic;
o_task_id: out std_logic_vector(5 downto 0);
o_mem_addr: out std_logic_vector(15 downto 0);
i_mem_data: in std_logic_vector(7 downto 0);
o_mem_data: out std_logic_vector(7 downto 0);
o_mem_we: out std_logic;
o_mem_en: out std_logic
);
end project_reti_logiche;
architecture FSM of project_reti_logiche is
-- STATI
type state_type is (
-- Gestione
S_IDLE,
S_RESET,
S_DONE,
-- OP = "00": Diminuzione priorita'
S_00_READ,
S_00_WAIT,
S_00_CHECK,
S_00_GO_NEXT,
-- OP = "01": Rimozione
S_01_CHECK_NUMBER,
S_01_WAIT,
S_01_WRITE,
S_01_CHECK_END,
S_01_COPY,
S_01_GO_NEXT,
S_01_WAIT_FOR_COUNT,
-- OP = "10": Inserimento
S_10_PLACE_AT_START,
S_10_WAIT_FOR_CHECK,
S_10_CHECK_ID,
S_10_WAIT,
S_10_COMPARE,
S_10_GO_NEXT,
S_10_UPDATE_COUNT,
S_10_WAIT_FOR_COUNT,
-- OP = "11": Svuotamento
S_11_UPDATE_COUNT,
S_11_WAIT_FOR_COUNT
);
-- SEGNALI
signal state: state_type;
signal next_state: state_type;
signal current_mem_addr: std_logic_vector(15 downto 0);
signal next_mem_addr: std_logic_vector(15 downto 0);
signal current_task_count: std_logic_vector(7 downto 0);
signal next_task_count: std_logic_vector(7 downto 0);
signal current_popped_id: std_logic_vector(5 downto 0);
signal next_popped_id: std_logic_vector(5 downto 0);
signal ctrl_done: std_logic;
signal ctrl_mem_en: std_logic;
signal ctrl_mem_we: std_logic;
signal ctrl_mem_data: std_logic_vector(7 downto 0);
signal ctrl_task_id: std_logic_vector(5 downto 0);
begin
-- PROCESSO COMBINATORIO:
-- Vengono fatte delle assegnazioni di default, calcolato lo stato successivo e i segnali di controllo.
process (state, i_start, i_op, i_mem_data, i_task_id, i_task_priority,
current_task_count, current_mem_addr, current_popped_id)
begin
next_state <= state;
next_task_count <= current_task_count;
next_mem_addr <= current_mem_addr;
next_popped_id <= current_popped_id;
ctrl_done <= '0';
ctrl_mem_en <= '0';
ctrl_mem_we <= '0';
ctrl_mem_data <= (others => '0');
ctrl_task_id <= (others => '0');
case state is
-- S_IDLE: Quando riceve il segnale di start sleeziona il primo stato dell'operazione.
when S_IDLE =>
if i_start = '1' then
next_popped_id <= (others => '0');
case i_op is
when "00" => next_state <= S_00_READ; -- Diminuzione priorita'
when "01" => next_state <= S_01_CHECK_NUMBER; -- Rimozione
when "10" => next_state <= S_10_PLACE_AT_START; -- Inserimento
when "11" => next_state <= S_11_UPDATE_COUNT; -- Svuotamento
when others => null;
end case;
end if;
-- S_RESET: Scrive 0 in mem[0] tenendo DONE a 1.
when S_RESET =>
next_state <= S_DONE;
next_task_count <= (others => '0');
next_mem_addr <= (others => '0');
next_popped_id <= (others => '0');
ctrl_done <= '1';
ctrl_mem_en <= '1';
ctrl_mem_we <= '1';
ctrl_mem_data <= (others => '0');
-- S_DONE: alza DONE e lo tiene a 1 finché START non torna a 0.
when S_DONE =>
if i_start = '1' then
ctrl_done <= '1';
ctrl_task_id <= current_popped_id;
else
next_state <= S_IDLE;
end if;
-- DIMINUZIONE PRIORITA':
-- Scorre la lista da mem[1] a mem[N]: per ogni task valido incrementata di 1 la priorita'.
-- Dato che c'e' il controllo sulla priorita' massima '11', si puo' fare facilmente una somma
-- sull'intero contenuto del task.
when S_00_READ =>
next_state <= S_00_WAIT;
next_mem_addr <= x"0001";
ctrl_mem_en <= '1';
when S_00_WAIT =>
next_state <= S_00_CHECK;
when S_00_CHECK =>
if unsigned(current_mem_addr) = resize(unsigned(current_task_count), 16) + 1 then
next_state <= S_DONE;
elsif i_mem_data(1 downto 0) /= "11" then
next_state <= S_00_GO_NEXT;
ctrl_mem_en <= '1';
ctrl_mem_we <= '1';
ctrl_mem_data <= std_logic_vector(unsigned(i_mem_data) + 1);
else
next_state <= S_00_GO_NEXT;
end if;
when S_00_GO_NEXT =>
next_state <= S_00_WAIT;
next_mem_addr <= std_logic_vector(unsigned(current_mem_addr) + 1);
ctrl_mem_en <= '1';
-- RIMOZIONE:
-- Se la lista è vuota termina subito, altrimenti salva l'ID di mem[1].
-- Successivamente, compatta la lista copiando ogni task una posizione più in alto e
-- decrementa di uno il contatore.
when S_01_CHECK_NUMBER =>
if current_task_count = x"00" then
next_state <= S_DONE;
else
next_state <= S_01_WAIT;
next_mem_addr <= x"0001";
ctrl_mem_en <= '1';
end if;
when S_01_WAIT =>
next_state <= S_01_WRITE;
when S_01_WRITE =>
next_state <= S_01_CHECK_END;
next_mem_addr <= std_logic_vector(unsigned(current_mem_addr) + 1);
ctrl_mem_en <= '1';
next_popped_id <= i_mem_data(7 downto 2);
when S_01_CHECK_END =>
if unsigned(current_mem_addr) = resize(unsigned(current_task_count), 16) + 1 then
next_state <= S_01_WAIT_FOR_COUNT;
next_task_count <= std_logic_vector(unsigned(current_task_count) - 1);
next_mem_addr <= x"0000";
ctrl_mem_en <= '1';
ctrl_mem_we <= '1';
ctrl_mem_data <= std_logic_vector(unsigned(current_task_count) - 1);
else
next_state <= S_01_COPY;
end if;
when S_01_COPY =>
next_state <= S_01_GO_NEXT;
next_mem_addr <= std_logic_vector(unsigned(current_mem_addr) - 1);
ctrl_mem_en <= '1';
ctrl_mem_we <= '1';
ctrl_mem_data <= i_mem_data;
when S_01_GO_NEXT =>
next_state <= S_01_CHECK_END;
next_mem_addr <= std_logic_vector(unsigned(current_mem_addr) + 2);
ctrl_mem_en <= '1';
when S_01_WAIT_FOR_COUNT =>
next_state <= S_DONE;
-- INSERIMENTO:
-- 1) Scansione duplicati: se viene trovato un task con lo stesso ID termina senza modifiche.
-- 2) Inserimento: confronta il task da inserire con mem[j] per j = N...1
-- - Se il nuovo task ha priorità maggiore (valore minore) sposta mem[j] in mem[j+1],
-- - Altrimenti scrive il nuovo task in mem[j+1].
-- Il confronto ">=" colloca il nuovo task DOPO quelli di
-- pari priorità.
--
-- Nota:
-- Con lista vuota la scansione legge il contatore in mem[0], ma questo confronto non puo' dare falsi duplicati
-- perche' in quel caso il contatore vale 0 (il nuovo task non puo' avere id 0)
when S_10_PLACE_AT_START =>
if i_task_id = "000000" then
next_state <= S_DONE;
else
next_state <= S_10_WAIT_FOR_CHECK;
next_mem_addr <= x"00" & current_task_count;
ctrl_mem_en <= '1';
end if;
when S_10_WAIT_FOR_CHECK =>
next_state <= S_10_CHECK_ID;
when S_10_CHECK_ID =>
if i_mem_data(7 downto 2) = i_task_id then
next_state <= S_DONE;
elsif unsigned(current_mem_addr) <= 1 then
next_state <= S_10_WAIT;
next_mem_addr <= x"00" & current_task_count;
ctrl_mem_en <= '1';
else
next_state <= S_10_WAIT_FOR_CHECK;
next_mem_addr <= std_logic_vector(unsigned(current_mem_addr) - 1);
ctrl_mem_en <= '1';
end if;
when S_10_WAIT =>
next_state <= S_10_COMPARE;
when S_10_COMPARE =>
if (current_mem_addr = x"0000") or
(unsigned(i_task_priority) >= unsigned(i_mem_data(1 downto 0))) then
-- posizione trovata: scrive il nuovo task in mem[j+1]
next_state <= S_10_UPDATE_COUNT;
next_mem_addr <= std_logic_vector(unsigned(current_mem_addr) + 1);
ctrl_mem_en <= '1';
ctrl_mem_we <= '1';
ctrl_mem_data <= i_task_id & i_task_priority;
else
-- il nuovo task deve stare più in alto: sposta mem[j] in mem[j+1] e prosegue verso l'alto
next_state <= S_10_GO_NEXT;
next_mem_addr <= std_logic_vector(unsigned(current_mem_addr) + 1);
ctrl_mem_en <= '1';
ctrl_mem_we <= '1';
ctrl_mem_data <= i_mem_data;
end if;
when S_10_GO_NEXT =>
next_state <= S_10_WAIT;
next_mem_addr <= std_logic_vector(unsigned(current_mem_addr) - 2);
ctrl_mem_en <= '1';
when S_10_UPDATE_COUNT =>
next_state <= S_10_WAIT_FOR_COUNT;
next_task_count <= std_logic_vector(unsigned(current_task_count) + 1);
next_mem_addr <= x"0000";
ctrl_mem_en <= '1';
ctrl_mem_we <= '1';
ctrl_mem_data <= std_logic_vector(unsigned(current_task_count) + 1);
when S_10_WAIT_FOR_COUNT =>
next_state <= S_DONE;
-- SVUOTAMENTO:
-- Scrive 0 nel contatore, invalidando tutta la lista
when S_11_UPDATE_COUNT =>
next_state <= S_11_WAIT_FOR_COUNT;
next_task_count <= (others => '0');
next_mem_addr <= (others => '0');
ctrl_mem_en <= '1';
ctrl_mem_we <= '1';
ctrl_mem_data <= (others => '0');
when S_11_WAIT_FOR_COUNT =>
next_state <= S_DONE;
end case;
end process;
-- PROCESSO SINCRONO:
-- Registra stato e uscite sul fronte di salita del clock.
-- Reset asincrono: porta la FSM in S_RESET con DONE = 1 e disabilita la memoria.
process (i_clk, i_rst)
begin
if i_rst = '1' then
state <= S_RESET;
o_done <= '1';
o_mem_en <= '0';
o_mem_we <= '0';
elsif rising_edge(i_clk) then
state <= next_state;
current_mem_addr <= next_mem_addr;
current_task_count <= next_task_count;
current_popped_id <= next_popped_id;
o_done <= ctrl_done;
o_mem_en <= ctrl_mem_en;
o_mem_we <= ctrl_mem_we;
o_mem_addr <= next_mem_addr;
o_mem_data <= ctrl_mem_data;
o_task_id <= ctrl_task_id;
end if;
end process;
end FSM;