Line 1... |
Line 1... |
--
|
--
|
|
--
|
|
-- This file is a part of JOP, the Java Optimized Processor
|
|
--
|
|
-- Copyright (C) 2001-2008, Martin Schoeberl (martin@jopdesign.com)
|
|
--
|
|
-- This program is free software: you can redistribute it and/or modify
|
|
-- it under the terms of the GNU General Public License as published by
|
|
-- the Free Software Foundation, either version 3 of the License, or
|
|
-- (at your option) any later version.
|
|
--
|
|
-- This program is distributed in the hope that it will be useful,
|
|
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
-- GNU General Public License for more details.
|
|
--
|
|
-- You should have received a copy of the GNU General Public License
|
|
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
--
|
|
|
|
|
|
--
|
-- sc_sys.vhd
|
-- sc_sys.vhd
|
--
|
--
|
-- counter, interrrupt handling and watchdog bit
|
-- counter, interrrupt handling and watchdog bit
|
--
|
--
|
-- Author: Martin Schoeberl martin@good-ear.com
|
-- Author: Martin Schoeberl martin@jopdesign.com
|
--
|
--
|
-- address map:
|
-- address map:
|
--
|
--
|
-- 0 read clk counter, write irq ena
|
-- 0 read clk counter, write irq ena
|
-- 1 read 1 MHz counter, write timer val (us) + irq ack
|
-- 1 read 1 MHz counter, write timer val (us)
|
-- 2 write generates sw-int (for yield())
|
-- 2 write generates sw-int (for yield())
|
-- 3 write wd port
|
-- 3 write wd port
|
-- 4 write generates SW exception, read exception reason
|
-- 4 write generates SW exception, read exception reason
|
--
|
--
|
-- todo:
|
-- todo:
|
Line 20... |
Line 41... |
-- 2003-08-15 us counter, irq added
|
-- 2003-08-15 us counter, irq added
|
-- 2005-11-30 change interface to SimpCon
|
-- 2005-11-30 change interface to SimpCon
|
-- 2006-01-11 added exception
|
-- 2006-01-11 added exception
|
-- 2007-03-17 changed interrupts to records
|
-- 2007-03-17 changed interrupts to records
|
-- 2007-06-01 changed name from sc_cnt to sc_sys
|
-- 2007-06-01 changed name from sc_cnt to sc_sys
|
|
-- 2007-11-22 added global lock and bootup of CMP
|
|
-- 2007-12-03 prioritized interrupt processing
|
|
-- 2007-12-07 global lock redesign
|
|
|
|
|
|
--
|
|
-- state for a single interrupt
|
--
|
--
|
|
library ieee;
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.numeric_std.all;
|
|
|
|
entity intstate is
|
|
|
|
port (
|
|
clk : in std_logic;
|
|
reset : in std_logic;
|
|
|
|
irq : in std_logic; -- external request
|
|
ena : in std_logic; -- local enable
|
|
ack : in std_logic; -- is served
|
|
clear : in std_logic; -- reset pending interrupt
|
|
pending : out std_logic -- the output request
|
|
);
|
|
end intstate;
|
|
|
|
architecture rtl of intstate is
|
|
|
|
signal flag : std_logic;
|
|
|
|
begin
|
|
|
|
-- TODO: add minimum interarrival time
|
|
|
|
process(clk, reset) begin
|
|
|
|
if reset='1' then
|
|
flag <= '0';
|
|
elsif rising_edge(clk) then
|
|
if ack='1' or clear='1' then
|
|
flag <= '0';
|
|
elsif irq='1' then
|
|
flag <= '1';
|
|
end if;
|
|
end if;
|
|
|
|
end process;
|
|
|
|
pending <= flag and ena;
|
|
|
|
end rtl;
|
|
|
|
--
|
|
-- the sc_sys component
|
|
--
|
library ieee;
|
library ieee;
|
use ieee.std_logic_1164.all;
|
use ieee.std_logic_1164.all;
|
use ieee.numeric_std.all;
|
use ieee.numeric_std.all;
|
|
|
use work.jop_types.all;
|
use work.jop_types.all;
|
|
|
entity sc_sys is
|
entity sc_sys is
|
|
|
generic (addr_bits : integer;
|
generic (addr_bits : integer;
|
clk_freq : integer;
|
clk_freq : integer;
|
cpu_id : integer);
|
cpu_id : integer;
|
|
cpu_cnt : integer;
|
|
num_io_int : integer := 2); -- a default value to play with SW interrupts
|
port (
|
port (
|
clk : in std_logic;
|
clk : in std_logic;
|
reset : in std_logic;
|
reset : in std_logic;
|
|
|
-- SimpCon interface
|
-- SimpCon interface
|
Line 48... |
Line 124... |
rdy_cnt : out unsigned(1 downto 0);
|
rdy_cnt : out unsigned(1 downto 0);
|
|
|
--
|
--
|
-- Interrupts from IO devices
|
-- Interrupts from IO devices
|
--
|
--
|
irq_in : out irq_in_type;
|
irq_in : out irq_bcf_type;
|
|
irq_out : in irq_ack_type;
|
exc_req : in exception_type;
|
exc_req : in exception_type;
|
|
|
sync_out : in sync_out_type;
|
io_int : in std_logic_vector(num_io_int-1 downto 0) := "00";
|
|
|
|
sync_out : in sync_out_type := NO_SYNC;
|
sync_in : out sync_in_type;
|
sync_in : out sync_in_type;
|
|
|
wd : out std_logic
|
wd : out std_logic;
|
|
|
|
-- remove the comment for RAM access counting
|
|
-- ram_count : in std_logic;
|
|
|
|
inval : out std_logic
|
|
|
);
|
);
|
end sc_sys ;
|
end sc_sys ;
|
|
|
architecture rtl of sc_sys is
|
architecture rtl of sc_sys is
|
Line 68... |
Line 152... |
signal us_cnt : std_logic_vector(31 downto 0);
|
signal us_cnt : std_logic_vector(31 downto 0);
|
|
|
constant div_val : integer := clk_freq/1000000-1;
|
constant div_val : integer := clk_freq/1000000-1;
|
|
|
signal timer_int : std_logic;
|
signal timer_int : std_logic;
|
signal yield_int : std_logic;
|
|
signal int_ack : std_logic;
|
|
|
|
signal timer : std_logic;
|
signal timer_cnt : std_logic_vector(31 downto 0);
|
signal yield : std_logic;
|
|
|
|
signal irq_cnt : std_logic_vector(31 downto 0);
|
|
signal timer_equ : std_logic;
|
signal timer_equ : std_logic;
|
signal timer_dly : std_logic;
|
signal timer_dly : std_logic;
|
|
|
signal exc_type : std_logic_vector(7 downto 0);
|
signal exc_type : std_logic_vector(7 downto 0);
|
|
|
signal cpu_identity : std_logic_vector(31 downto 0);
|
signal cpu_identity : std_logic_vector(31 downto 0);
|
|
signal lock_reqest : std_logic;
|
|
|
|
-- remove the comment for RAM access counting
|
|
-- signal ram_counter : std_logic_vector(31 downto 0);
|
|
|
|
|
|
signal cnt_ena : unsigned(31 downto 0);
|
|
|
|
--
|
|
-- signals for interrupt handling
|
|
--
|
|
signal int_pend : std_logic;
|
|
signal int_ena : std_logic;
|
|
signal exc_pend : std_logic;
|
|
signal irq_gate : std_logic;
|
|
signal irq_dly : std_logic;
|
|
signal exc_dly : std_logic;
|
|
|
|
--
|
|
-- signals for interrupt source state machines
|
|
--
|
|
constant NUM_INT : integer := num_io_int+1; -- plus timer interrupt
|
|
signal hwreq : std_logic_vector(NUM_INT-1 downto 0);
|
|
signal swreq : std_logic_vector(NUM_INT-1 downto 0);
|
|
signal intreq : std_logic_vector(NUM_INT-1 downto 0);
|
|
signal mask : std_logic_vector(NUM_INT-1 downto 0);
|
|
signal ack : std_logic_vector(NUM_INT-1 downto 0);
|
|
signal pending : std_logic_vector(NUM_INT-1 downto 0);
|
|
signal prioint : std_logic_vector(4 downto 0);
|
|
signal intnr : std_logic_vector(4 downto 0); -- processing int number
|
|
signal clearall : std_logic;
|
|
|
begin
|
begin
|
|
|
cpu_identity <= std_logic_vector(to_unsigned(cpu_id,32));
|
cpu_identity <= std_logic_vector(to_unsigned(cpu_id,32));
|
rdy_cnt <= "00"; -- no wait states
|
rdy_cnt <= "11" when (sync_out.halted='1' and lock_reqest='1') else "00";
|
|
|
--
|
--
|
-- read cnt values
|
-- read cnt values
|
--
|
--
|
process(clk, reset)
|
process(clk, reset)
|
begin
|
begin
|
|
|
if (reset='1') then
|
if reset='1' then
|
rd_data <= (others => '0');
|
rd_data <= (others => '0');
|
elsif rising_edge(clk) then
|
elsif rising_edge(clk) then
|
|
|
if rd='1' then
|
if rd='1' then
|
case address(2 downto 0) is
|
case address(3 downto 0) is
|
when "000" =>
|
when "0000" =>
|
rd_data <= clock_cnt;
|
rd_data <= clock_cnt;
|
when "001" =>
|
when "0001" =>
|
rd_data <= us_cnt;
|
rd_data <= us_cnt;
|
when "100" =>
|
when "0010" =>
|
|
rd_data(4 downto 0) <= intnr;
|
|
rd_data(31 downto 5) <= (others => '0');
|
|
when "0100" =>
|
rd_data(7 downto 0) <= exc_type;
|
rd_data(7 downto 0) <= exc_type;
|
rd_data(31 downto 8) <= (others => '0');
|
rd_data(31 downto 8) <= (others => '0');
|
when "110" =>
|
when "0101" =>
|
|
rd_data(0) <= lock_reqest;
|
|
rd_data(31 downto 1) <= (others => '0');
|
|
when "0110" =>
|
rd_data <= cpu_identity;
|
rd_data <= cpu_identity;
|
-- when "111" =>
|
when "0111" =>
|
when others =>
|
|
rd_data(0) <= sync_out.s_out;
|
rd_data(0) <= sync_out.s_out;
|
rd_data(31 downto 1) <= (others => '0');
|
rd_data(31 downto 1) <= (others => '0');
|
|
-- remove the comment for RAM access counting
|
|
-- when "1010" =>
|
|
-- rd_data(31 downto 0) <= ram_counter;
|
|
when "1011" =>
|
|
rd_data <= std_logic_vector(to_unsigned(cpu_cnt, 32));
|
|
when "1111" =>
|
|
-- nothing, cache inval is write only
|
|
when others =>
|
|
-- nothing
|
end case;
|
end case;
|
end if;
|
end if;
|
end if;
|
end if;
|
|
|
end process;
|
end process;
|
|
|
--
|
--
|
-- compare timer value and us counter
|
-- compare timer value and us counter
|
-- and generate single shot
|
-- and generate single shot
|
--
|
--
|
process(us_cnt, irq_cnt) begin
|
process(us_cnt, timer_cnt) begin
|
timer_equ <= '0';
|
timer_equ <= '0';
|
if us_cnt = irq_cnt then
|
if us_cnt = timer_cnt then
|
timer_equ <= '1';
|
timer_equ <= '1';
|
end if;
|
end if;
|
end process;
|
end process;
|
|
|
process(clk, reset, timer_equ) begin
|
process(clk, reset) begin
|
if (reset='1') then
|
if reset='1' then
|
timer_dly <= '0';
|
timer_dly <= '0';
|
elsif rising_edge(clk) then
|
elsif rising_edge(clk) then
|
timer_dly <= timer_equ;
|
timer_dly <= timer_equ;
|
end if;
|
end if;
|
end process;
|
end process;
|
Line 143... |
Line 266... |
timer_int <= timer_equ and not timer_dly;
|
timer_int <= timer_equ and not timer_dly;
|
|
|
--
|
--
|
-- int processing from timer and yield request
|
-- int processing from timer and yield request
|
--
|
--
|
process(clk, reset, timer_int, yield_int) begin
|
|
|
|
if (reset='1') then
|
hwreq(0) <= timer_int;
|
timer <= '0';
|
hwreq(NUM_INT-1 downto 1) <= io_int;
|
yield <= '0';
|
|
elsif rising_edge(clk) then
|
process(prioint, irq_out.ack_irq) begin
|
if int_ack='1' then
|
ack <= (others => '0');
|
timer <= '0';
|
ack(to_integer(unsigned(prioint))) <= irq_out.ack_irq;
|
yield <= '0';
|
end process;
|
else
|
|
if timer_int='1' then
|
gen_int: for i in 0 to NUM_INT-1 generate
|
timer <= '1';
|
intreq(i) <= hwreq(i) or swreq(i);
|
end if;
|
cis: entity work.intstate
|
if yield_int='1' then
|
port map(clk, reset,
|
yield <= '1';
|
irq => intreq(i),
|
|
ena => mask(i),
|
|
ack => ack(i),
|
|
clear => clearall,
|
|
pending => pending(i)
|
|
);
|
|
|
|
|
|
end generate;
|
|
|
|
-- find highest priority pending interrupt
|
|
process(pending) begin
|
|
|
|
int_pend <= '0';
|
|
prioint <= (others => '0');
|
|
for i in NUM_INT-1 downto 0 loop
|
|
if pending(i)='1' then
|
|
int_pend <= '1';
|
|
prioint <= std_logic_vector(to_unsigned(i, 5));
|
|
exit;
|
end if;
|
end if;
|
|
end loop;
|
|
end process;
|
|
|
|
--
|
|
-- interrupt processing
|
|
--
|
|
process(clk, reset) begin
|
|
|
|
if reset='1' then
|
|
irq_dly <= '0';
|
|
exc_dly <= '0';
|
|
intnr <= (others => '0');
|
|
|
|
elsif rising_edge(clk) then
|
|
|
|
irq_dly <= irq_gate;
|
|
exc_dly <= exc_pend;
|
|
-- save processing interrupt number
|
|
if irq_out.ack_irq='1' then
|
|
intnr <= prioint;
|
end if;
|
end if;
|
|
|
end if;
|
end if;
|
|
|
end process;
|
end process;
|
|
|
irq_in.irq <= timer or yield;
|
irq_gate <= int_pend and int_ena;
|
|
irq_in.irq <= irq_gate and not irq_dly;
|
|
irq_in.exc <= exc_pend and not exc_dly;
|
|
irq_in.ena <= int_ena;
|
|
|
|
|
|
|
--
|
--
|
-- counters
|
-- counters
|
-- pre_scale is 8 bit => fmax = 255 MHz
|
-- pre_scale is 8 bit => fmax = 255 MHz
|
Line 199... |
Line 365... |
process(clk, reset)
|
process(clk, reset)
|
|
|
begin
|
begin
|
if (reset='1') then
|
if (reset='1') then
|
|
|
irq_in.irq_ena <= '0';
|
int_ena <= '0';
|
irq_cnt <= (others => '0');
|
timer_cnt <= (others => '0');
|
int_ack <= '0';
|
|
wd <= '0';
|
wd <= '0';
|
sync_in.s_in <= '0';
|
sync_in.s_in <= '0';
|
|
sync_in.lock_req <= '0';
|
|
lock_reqest <= '0';
|
|
|
exc_type <= (others => '0');
|
exc_type <= (others => '0');
|
irq_in.exc_int <= '0';
|
exc_pend <= '0';
|
|
|
|
swreq <= (others => '0');
|
|
mask <= (others => '0');
|
|
clearall <= '0';
|
|
|
elsif rising_edge(clk) then
|
elsif rising_edge(clk) then
|
|
|
int_ack <= '0';
|
exc_pend <= '0';
|
yield_int <= '0';
|
swreq <= (others => '0');
|
|
clearall <= '0';
|
|
inval <= '0';
|
|
|
irq_in.exc_int <= '0';
|
-- disable interrupts on a taken interrupt or excption
|
|
if irq_out.ack_irq='1' or irq_out.ack_exc='1' then
|
|
int_ena <= '0';
|
|
end if;
|
|
|
|
-- exceptions from core or memory
|
if exc_req.spov='1' then
|
if exc_req.spov='1' then
|
exc_type(2 downto 0) <= EXC_SPOV;
|
exc_type(2 downto 0) <= EXC_SPOV;
|
irq_in.exc_int <= '1';
|
exc_pend <= '1';
|
end if;
|
end if;
|
if exc_req.np='1' then
|
if exc_req.np='1' then
|
exc_type(2 downto 0) <= EXC_NP;
|
exc_type(2 downto 0) <= EXC_NP;
|
irq_in.exc_int <= '1';
|
exc_pend <= '1';
|
end if;
|
end if;
|
if exc_req.ab='1' then
|
if exc_req.ab='1' then
|
exc_type(2 downto 0) <= EXC_AB;
|
exc_type(2 downto 0) <= EXC_AB;
|
irq_in.exc_int <= '1';
|
exc_pend <= '1';
|
end if;
|
end if;
|
|
|
if wr='1' then
|
if wr='1' then
|
case address(2 downto 0) is
|
case address(3 downto 0) is
|
when "000" =>
|
when "0000" =>
|
irq_in.irq_ena <= wr_data(0);
|
int_ena <= wr_data(0);
|
when "001" =>
|
when "0001" =>
|
irq_cnt <= wr_data;
|
timer_cnt <= wr_data;
|
int_ack <= '1';
|
when "0010" =>
|
when "010" =>
|
swreq(to_integer(unsigned(wr_data))) <= '1';
|
yield_int <= '1';
|
when "0011" =>
|
when "011" =>
|
|
wd <= wr_data(0);
|
wd <= wr_data(0);
|
when "100" =>
|
when "0100" =>
|
exc_type <= wr_data(7 downto 0);
|
exc_type <= wr_data(7 downto 0);
|
irq_in.exc_int <= '1';
|
exc_pend <= '1';
|
when "110" =>
|
when "0101" =>
|
|
sync_in.lock_req <= wr_data(0);
|
|
lock_reqest <= wr_data(0);
|
|
-- implicit cache invalidation on monitorenter
|
|
inval <= wr_data(0);
|
|
when "0110" =>
|
-- nothing, processor id is read only
|
-- nothing, processor id is read only
|
when others =>
|
when "0111" =>
|
-- when "111" =>
|
|
sync_in.s_in <= wr_data(0);
|
sync_in.s_in <= wr_data(0);
|
|
when "1000" =>
|
|
mask <= wr_data(NUM_INT-1 downto 0);
|
|
when "1001" =>
|
|
clearall <= '1';
|
|
when "1010" =>
|
|
-- nothing, ram_counter is read only
|
|
when "1111" =>
|
|
-- explicit cache invalidation
|
|
inval <= '1';
|
|
when others =>
|
end case;
|
end case;
|
end if;
|
end if;
|
|
|
end if;
|
end if;
|
end process;
|
end process;
|
|
|
|
-- remove the comment for RAM access counting
|
|
-- process(clk, reset)
|
|
-- begin
|
|
-- if reset = '1' then
|
|
-- ram_counter <= (others => '0');
|
|
-- elsif rising_edge(clk) then
|
|
-- if (ram_count='0') then
|
|
-- ram_counter <= std_logic_vector(unsigned(ram_counter) + 1);
|
|
-- end if;
|
|
-- end if;
|
|
-- end process;
|
|
|
end rtl;
|
end rtl;
|
|
|
No newline at end of file
|
No newline at end of file
|