OpenCores
URL https://opencores.org/ocsvn/simpcon/simpcon/trunk

Subversion Repositories simpcon

[/] [simpcon/] [trunk/] [vhdl/] [sc_sys.vhd] - Rev 29

Compare with Previous | Blame | View Log

--
--
--  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
--
--	counter, interrrupt handling and watchdog bit
--
--	Author: Martin Schoeberl	martin@jopdesign.com
--
--		address map:
--
--			0	read clk counter, write irq ena
--			1	read 1 MHz counter, write timer val (us)
--			2	write generates sw-int (for yield())
--			3	write wd port
--			4	write generates SW exception, read exception reason
--
--	todo:
--
--
--	2003-07-05	new IO standard
--	2003-08-15	us counter, irq added
--	2005-11-30	change interface to SimpCon
--	2006-01-11	added exception
--	2007-03-17	changed interrupts to records
--  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;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
 
use work.jop_types.all;
 
entity sc_sys is
 
generic (addr_bits : integer;
	clk_freq : integer;
	cpu_id	 : integer;
	cpu_cnt  : integer;
	num_io_int : integer := 2);		-- a default value to play with SW interrupts
port (
	clk		: in std_logic;
	reset	: in std_logic;
 
-- SimpCon interface
 
	address		: in std_logic_vector(addr_bits-1 downto 0);
	wr_data		: in std_logic_vector(31 downto 0);
	rd, wr		: in std_logic;
	rd_data		: out std_logic_vector(31 downto 0);
	rdy_cnt		: out unsigned(1 downto 0);
 
--
--	Interrupts from IO devices
--
	irq_in		: out irq_bcf_type;
	irq_out		: in irq_ack_type;
	exc_req		: in exception_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;
 
	wd				: out std_logic;
 
	-- remove the comment for RAM access counting
	-- ram_count	: in std_logic;
 
	inval		: out std_logic
 
);
end sc_sys ;
 
architecture rtl of sc_sys is
 
	signal clock_cnt		: std_logic_vector(31 downto 0);
	signal pre_scale		: std_logic_vector(7 downto 0);
	signal us_cnt			: std_logic_vector(31 downto 0);
 
	constant div_val	: integer := clk_freq/1000000-1;
 
	signal timer_int		: std_logic;
 
	signal timer_cnt		: std_logic_vector(31 downto 0);
	signal timer_equ		: std_logic;
	signal timer_dly		: std_logic;
 
	signal exc_type			: std_logic_vector(7 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
 
	cpu_identity <= std_logic_vector(to_unsigned(cpu_id,32));
	rdy_cnt <= "11" when (sync_out.halted='1' and lock_reqest='1') else "00";
 
--
--	read cnt values
--
process(clk, reset)
begin
 
	if reset='1' then
		rd_data <= (others => '0');
	elsif rising_edge(clk) then
 
		if rd='1' then
			case address(3 downto 0) is
				when "0000" =>
					rd_data <= clock_cnt;
				when "0001" =>
					rd_data <= us_cnt;
				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(31 downto 8) <= (others => '0');
				when "0101" =>
					rd_data(0) <= lock_reqest;
					rd_data(31 downto 1) <= (others => '0');				
				when "0110" =>
					rd_data <= cpu_identity;
				when "0111" =>
					rd_data(0) <= sync_out.s_out;
					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 if;
	end if;
 
end process;
 
--
--	compare timer value and us counter
--	and generate single shot
--
process(us_cnt, timer_cnt) begin
	timer_equ <= '0';
	if us_cnt = timer_cnt then
		timer_equ <= '1';
	end if;
end process;
 
process(clk, reset) begin
	if reset='1' then
		timer_dly <= '0';
	elsif rising_edge(clk) then
		timer_dly <= timer_equ;
	end if;
end process;
 
	timer_int <= timer_equ and not timer_dly;
 
--
--	int processing from timer and yield request
--
 
	hwreq(0) <= timer_int;
	hwreq(NUM_INT-1 downto 1) <= io_int;
 
process(prioint, irq_out.ack_irq) begin
	ack <= (others => '0');
	ack(to_integer(unsigned(prioint))) <= irq_out.ack_irq;
end process;
 
	gen_int: for i in 0 to NUM_INT-1 generate
		intreq(i) <= hwreq(i) or swreq(i);
		cis: entity work.intstate
			port map(clk, reset,
				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 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 process;
 
	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
--		pre_scale is 8 bit => fmax = 255 MHz
--
process(clk, reset) begin
 
	if (reset='1') then
 
		clock_cnt <= (others => '0');
		us_cnt <= (others => '0');
		pre_scale <= std_logic_vector(to_unsigned(div_val, pre_scale'length));
 
	elsif rising_edge(clk) then
 
		clock_cnt <= std_logic_vector(unsigned(clock_cnt) + 1);
		pre_scale <= std_logic_vector(unsigned(pre_scale) - 1);
		if pre_scale = "00000000" then
			pre_scale <= std_logic_vector(to_unsigned(div_val, pre_scale'length));
			us_cnt <= std_logic_vector(unsigned(us_cnt) + 1);
		end if;
 
	end if;
end process;
 
--
--	io write processing and exception processing
--
process(clk, reset)
 
begin
	if (reset='1') then
 
		int_ena <= '0';
		timer_cnt <= (others => '0');
		wd <= '0';
		sync_in.s_in <= '0';
		sync_in.lock_req <= '0';
		lock_reqest <= '0';
 
		exc_type <= (others => '0');
		exc_pend <= '0';
 
		swreq <= (others => '0');
		mask <= (others => '0');
		clearall <= '0';
 
	elsif rising_edge(clk) then
 
		exc_pend <= '0';
		swreq <= (others => '0');
		clearall <= '0';
		inval <= '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
			exc_type(2 downto 0) <= EXC_SPOV;
			exc_pend <= '1';
		end if;
		if exc_req.np='1' then
			exc_type(2 downto 0) <= EXC_NP;
			exc_pend <= '1';
		end if;
		if exc_req.ab='1' then
			exc_type(2 downto 0) <= EXC_AB;
			exc_pend <= '1';
		end if;
 
		if wr='1' then
			case address(3 downto 0) is
				when "0000" =>
					int_ena <= wr_data(0);
				when "0001" =>
					timer_cnt <= wr_data;
				when "0010" =>
					swreq(to_integer(unsigned(wr_data))) <= '1';
				when "0011" =>
					wd <= wr_data(0);
				when "0100" =>
					exc_type <= wr_data(7 downto 0);
					exc_pend <= '1';
				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
				when "0111" =>
					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 if;
 
	end if;
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;
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.