-- 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;