136 lines
4.1 KiB
VHDL
136 lines
4.1 KiB
VHDL
-- See the file "LICENSE" for the full license governing this code. --
|
|
|
|
library ieee;
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.numeric_std.all;
|
|
use work.lt16x32_global.all;
|
|
|
|
-- the interrupt controller constantly checks interrupt lines for interrupt signals,
|
|
-- which then are send to the processor.
|
|
entity irq_controller is
|
|
port(
|
|
-- clock signal
|
|
clk : in std_logic;
|
|
-- reset signal, active high, synchronous
|
|
rst : in std_logic;
|
|
|
|
-- signals from the processor
|
|
in_proc : in core_irq;
|
|
-- signals to the processor
|
|
out_proc : out irq_core;
|
|
|
|
-- irq lines from the "outside world"
|
|
irq_lines : in std_logic_vector((2 ** irq_num_width) - 1 downto 0)
|
|
);
|
|
end entity irq_controller;
|
|
|
|
architecture RTL of irq_controller is
|
|
-- interrupt number of current request, valid if req = '1'
|
|
signal num : unsigned(irq_num_width - 1 downto 0);
|
|
-- interrupt priority of current request, valid if req = '1'
|
|
signal priority : unsigned(irq_prio_width - 1 downto 0);
|
|
-- request signal, active high
|
|
signal req : std_logic;
|
|
-- non maskable interrupt signal, active high
|
|
signal nmi : std_logic;
|
|
|
|
-- storage of all interrupts that are pending currently
|
|
signal pending : std_logic_vector(irq_lines'range);
|
|
|
|
-- returns the priority of a given interrupt number, which
|
|
-- is - for simplicity - calculated as
|
|
-- priority = number modulo maximum priority
|
|
-- this could be extended/changed for each application
|
|
function get_priority(num : unsigned(irq_num_width - 1 downto 0)) return unsigned is
|
|
variable result : unsigned(irq_prio_width - 1 downto 0);
|
|
begin
|
|
result := num(result'range);
|
|
|
|
return result;
|
|
end function get_priority;
|
|
|
|
begin
|
|
-- simple signal forwarding
|
|
out_proc.req <= req;
|
|
out_proc.num <= num;
|
|
out_proc.nmi <= nmi;
|
|
out_proc.priority <= priority;
|
|
|
|
-- reading in both trap signal and external interrupt lines, setting the signal pending
|
|
read_in : process(clk) is
|
|
variable pendingVar : std_logic_vector(pending'range);
|
|
begin
|
|
if (rising_edge(clk)) then
|
|
if (rst = '1') then
|
|
-- in reset, all pending interrupts are cleared
|
|
pending <= (others => '0');
|
|
else
|
|
-- read in current pending interrupts
|
|
pendingVar := pending;
|
|
|
|
-- clear acknowledged interrupt
|
|
if (req = '1') and (in_proc.ack = '1') then
|
|
pendingVar(to_integer(num)) := '0';
|
|
end if;
|
|
|
|
-- read in trap request
|
|
if (in_proc.trap_req = '1') then
|
|
pendingVar(to_integer(unsigned(in_proc.trap_num))) := '1';
|
|
end if;
|
|
|
|
-- read in external interrupt request
|
|
if (irq_lines /= (irq_lines'range => '0')) then
|
|
pendingVar := pendingVar or irq_lines;
|
|
end if;
|
|
|
|
-- output variable to signal
|
|
pending <= pendingVar;
|
|
end if;
|
|
end if;
|
|
end process read_in;
|
|
|
|
-- generate request signals
|
|
request_gen : process(pending, rst) is
|
|
-- highest priority in search process
|
|
variable prio_highest : unsigned(irq_prio_width - 1 downto 0) := (others => '0');
|
|
-- number of interrupt with highes priority
|
|
variable num_highest : unsigned(irq_num_width - 1 downto 0) := (others => '0');
|
|
begin
|
|
-- if not in request, and something is pending (ignoring startup uninitialized state)
|
|
if ((rst = '0') and ((pending /= (pending'range => '0')))) then --and (pending /= (pending'range => 'U')))) then
|
|
-- something is pending
|
|
|
|
-- initialize variables before loop
|
|
prio_highest := to_unsigned(0, irq_prio_width);
|
|
num_highest := to_unsigned(0, irq_num_width);
|
|
|
|
-- get highest prioritized pending interrupt
|
|
for i in pending'range loop
|
|
if (pending(i) = '1') and (get_priority(to_unsigned(i, irq_num_width)) >= prio_highest) then
|
|
num_highest := to_unsigned(i, irq_num_width);
|
|
prio_highest := get_priority(to_unsigned(i, irq_num_width));
|
|
end if;
|
|
end loop;
|
|
|
|
-- output next interrupt
|
|
num <= num_highest;
|
|
priority <= prio_highest;
|
|
req <= '1';
|
|
|
|
-- interrupt 2 is NMI
|
|
if (num_highest = to_unsigned(2, irq_num_width)) then
|
|
nmi <= '1';
|
|
else
|
|
nmi <= '0';
|
|
end if;
|
|
else
|
|
-- nothing is pending
|
|
num <= to_unsigned(1, irq_num_width);
|
|
priority <= to_unsigned(2, irq_prio_width);
|
|
req <= '0';
|
|
nmi <= '0';
|
|
end if;
|
|
end process request_gen;
|
|
|
|
end architecture RTL;
|