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

Subversion Repositories simpcon

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

Compare with Previous | Blame | View Log

--
--  This file is part of JOP, the Java Optimized Processor
--
--  Copyright (C) 2007,2008, Christof Pitter
--
--  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/>.
--
 
 
 
 
-- 150407: first working version with records
-- 170407: produce number of registers depending on the cpu_cnt
-- 110507: * arbiter that can be used with prefered number of masters
--				 * full functional arbiter with two masters
--				 * short modelsim test with 3 masters carried out
-- 190607: Problem found: Both CPU1 and CPU2 start to read cache line!!!
-- 030707: Several bugs are fixed now. CMP with 3 running masters functions!
-- 150108: Quasi Round Robin Arbiter -- added sync signal to arbiter
-- 160108: First tests running with new Round Robin Arbiter
-- 250408: Renaming of this_state to mode, follow_state to next_mode, reg_in to reg_out
-- 240708: added data_reg for each CPU in arbiter
-- 070808: removed combinatorial loop (pipelined bug)
-- 210808: - reg_in_rd_data(i) also gets loaded when rdy_cnt = 3 using pipelined access
--				 - arb_in(i).rd_data gets mem_in.rd_data when rdy_cnt 3 using pipelined access
 
 
-- Functioning: See description of SIES08 paper
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
 
use work.sc_pack.all;
use work.sc_arbiter_pack.all;
use work.jop_types.all;
 
entity arbiter is
generic(
			addr_bits : integer;
			cpu_cnt	: integer);		-- number of masters for the arbiter
port (
			clk, reset	: in std_logic;			
			arb_out			: in arb_out_type(0 to cpu_cnt-1);
			arb_in			: out arb_in_type(0 to cpu_cnt-1);
			mem_out			: out sc_out_type;
			mem_in			: in sc_in_type
);
end arbiter;
 
 
architecture rtl of arbiter is
 
-- stores the signals in a register of each master
 
	type reg_type is record
		rd : std_logic;
		wr : std_logic;
		wr_data : std_logic_vector(31 downto 0);
		address : std_logic_vector(addr_bits-1 downto 0);
	end record; 
 
	type reg_out_type is array (0 to cpu_cnt-1) of reg_type;
	signal reg_out : reg_out_type;
 
-- register to CPU for rd_data
 
	type reg_in_type is array (0 to cpu_cnt-1) of std_logic_vector(31 downto 0);
	signal reg_in_rd_data : reg_in_type;
 
-- one fsm for each CPU
 
	type state_type is (idle, read, write, waitingR, sendR, 
	waitingW, sendW);
	type state_array is array (0 to cpu_cnt-1) of state_type;
	signal state : state_array;
	signal next_state : state_array;
 
-- one fsm for each serve
 
	type serve_type is (idl, servR, servW);
	type serve_array is array (0 to cpu_cnt-1) of serve_type;
	signal mode : serve_array;
	signal next_mode : serve_array;
 
-- arbiter 
 
	type set_type is array (0 to cpu_cnt-1) of std_logic_vector(1 downto 0);
	signal set : set_type;
	type pipelined_type is array (0 to cpu_cnt-1) of std_logic;
	signal pipelined : pipelined_type;
	signal next_pipelined : pipelined_type;
 
-- counter
	signal counter : integer;
	type slot_type is array (0 to cpu_cnt-1) of std_logic;
	signal slot : slot_type; -- defines which CPU is on turn
 
 
begin
 
 
-- Generates the input register and saves incoming data for each master
gen_register: for i in 0 to cpu_cnt-1 generate
	process(clk, reset)
	begin
		if reset = '1' then
			reg_out(i).rd <= '0';
			reg_out(i).wr <= '0';
			reg_out(i).wr_data <= (others => '0'); 
			reg_out(i).address <= (others => '0');
		elsif rising_edge(clk) then
			if arb_out(i).rd = '1' or arb_out(i).wr = '1' then
				reg_out(i).rd <= arb_out(i).rd;
				reg_out(i).wr <= arb_out(i).wr;
				reg_out(i).address <= arb_out(i).address;
				reg_out(i).wr_data <= arb_out(i).wr_data;
			end if;
		end if;
	end process;
end generate;
 
-- Generate Counter
process(clk, reset)
	begin
		if reset = '1' then
			counter <= 0;
		elsif rising_edge(clk) then
			counter <= counter + 1;
 
			for i in 0 to cpu_cnt-1 loop
				if next_mode(i) = servR or next_mode(i) = servW then
					if mem_in.rdy_cnt = 1 and arb_out(i).rd = '0' then
						if counter = cpu_cnt-1 then
							counter <= 0;
						else
							counter <= counter+1;
						end if;
						exit;
					else
						counter <= counter;
						exit;
					end if;
				elsif counter = cpu_cnt-1 then
						counter <= 0;
				end if;
			end loop;
		end if;
end process;
 
-- The slot is assigned depending on the counter 
process(counter)
	begin
		for j in 0 to cpu_cnt-1 loop
			if j = counter then
				slot(j) <= '1';
			else
				slot(j) <= '0';
			end if;
		end loop;
end process;	
 
 
-- Generates next state of the FSM for each master
gen_next_state: for i in 0 to cpu_cnt-1 generate
	process(state, mode, slot, mem_in, arb_out, pipelined)	 
	begin
 
		next_state(i) <= state(i);
 
		case state(i) is
			when idle =>
				next_pipelined(i) <= '0';
 
				-- is CPU allowed to access
				if (slot(i) = '1') then
 
					-- pipelined read access
					if (mode(i) = servR) and (mem_in.rdy_cnt = 1) and (arb_out(i).rd = '1') then
						next_state(i) <= read;
						next_pipelined(i) <= '1';
 
					elsif (mode(i) = servR) and (mem_in.rdy_cnt = 0) then
						if arb_out(i).rd = '1' then
							next_state(i) <= read;
						elsif arb_out(i).wr = '1' then
							next_state(i) <= write;				
						end if;
 
					elsif (mode(i) = servW) and (mem_in.rdy_cnt = 0) then
						if arb_out(i).rd = '1' then
							next_state(i) <= read;
						elsif arb_out(i).wr = '1' then
							next_state(i) <= write;				
						end if;
 
					elsif (mode(i) = idl) and (mem_in.rdy_cnt = 0) then
						if arb_out(i).rd = '1' then
							next_state(i) <= read;
						elsif arb_out(i).wr = '1' then
							next_state(i) <= write;				
						end if;
 
					-- all other kinds (can that happen at all?)
					else
						if arb_out(i).rd = '1' then
							next_state(i) <= waitingR;
						elsif arb_out(i).wr = '1' then
							next_state(i) <= waitingW;
						end if;
					end if;
 
				-- CPU is not allowed to access
				else
					if arb_out(i).rd = '1' then
						next_state(i) <= waitingR;
					elsif arb_out(i).wr = '1' then
						next_state(i) <= waitingW;
					end if;
				end if;
 
			when read =>
				next_state(i) <= idle;
				next_pipelined(i) <= '0';
 
				if pipelined(i) = '1' then
					next_pipelined(i) <= '1';
				end if;
 
			when write =>
				next_state(i) <= idle;
				next_pipelined(i) <= '0';
 
			when waitingR =>	
				next_pipelined(i) <= '0';
				if ((mem_in.rdy_cnt = 0) and (slot(i) = '1')) then
					next_state(i) <= sendR;
				else
					next_state(i) <= waitingR;
				end if;
 
			when sendR =>
				next_state(i) <= idle;
				next_pipelined(i) <= '0';
 
			when waitingW =>
				next_pipelined(i) <= '0';
				if ((mem_in.rdy_cnt = 0) and (slot(i) = '1')) then
					next_state(i) <= sendW;
				else
					next_state(i) <= waitingW;
				end if;
 
			when sendW =>
				next_state(i) <= idle;
				next_pipelined(i) <= '0';
 
		end case;
	end process;
end generate;
 
 
-- Generates the FSM state for each master
gen_state: for i in 0 to cpu_cnt-1 generate
	process (clk, reset)
	begin
		if (reset = '1') then
			state(i) <= idle;
			pipelined(i) <= '0';
  	elsif (rising_edge(clk)) then
			state(i) <= next_state(i);	
			pipelined(i) <= next_pipelined(i);
		end if;
	end process;
end generate;
 
 
-- The arbiter output
process (arb_out, reg_out, next_state)
begin
 
	mem_out.rd <= '0';
	mem_out.wr <= '0';
	mem_out.address <= (others => '0');
	mem_out.wr_data <= (others => '0');
	mem_out.atomic <= '0';
 
	for i in 0 to cpu_cnt-1 loop
		set(i) <= "00";
 
		case next_state(i) is
			when idle =>
 
			when read =>
				set(i) <= "01";
				mem_out.rd <= arb_out(i).rd;
				mem_out.address <= arb_out(i).address;
 
			when write =>
				set(i) <= "10";
				mem_out.wr <= arb_out(i).wr;
				mem_out.address <= arb_out(i).address;
				mem_out.wr_data <= arb_out(i).wr_data;			
 
			when waitingR =>
 
			when sendR =>
				set(i) <= "01";
				mem_out.rd <= reg_out(i).rd;
				mem_out.address <= reg_out(i).address;
 
			when waitingW =>
 
			when sendW =>
				set(i) <= "10";
				mem_out.wr <= reg_out(i).wr;
				mem_out.address <= reg_out(i).address;
				mem_out.wr_data <= reg_out(i).wr_data;
 
		end case;
	end loop;
end process;
 
-- generation of next_mode
gen_serve: for i in 0 to cpu_cnt-1 generate
	process(mem_in, set, mode)
	begin
		case mode(i) is
			when idl =>
				next_mode(i) <= idl;
				if set(i) = "01" then 
					next_mode(i) <= servR;
				elsif set(i) = "10" then
					next_mode(i) <= servW;
				end if;
			when servR =>
				next_mode(i) <= servR;
				if mem_in.rdy_cnt = 0 and set(i) = "00" then
					next_mode(i) <= idl;
				end if;
			when servW =>
				next_mode(i) <= servW;
				if mem_in.rdy_cnt = 0 and set(i) = "00" then
					next_mode(i) <= idl;
				end if;
		end case;
	end process;
end generate;
 
gen_serve2: for i in 0 to cpu_cnt-1 generate
	process (clk, reset)
	begin
		if (reset = '1') then
			mode(i) <= idl;
  	elsif (rising_edge(clk)) then
			mode(i) <= next_mode(i);	
		end if;
	end process;
end generate;
 
 
 
-- Registers rd_data for each CPU
gen_reg_in: for i in 0 to cpu_cnt-1 generate
	process(clk, reset)
	begin
		if reset = '1' then
			reg_in_rd_data(i) <= (others => '0'); 
		elsif rising_edge(clk) then
			if mode(i) = servR then
				if mem_in.rdy_cnt = 0 then
					reg_in_rd_data(i) <= mem_in.rd_data;
 
				-- added mem_in.rdy_cnt = 3. 
				-- More correct would be: ((mem_in.rdy_cnt = ram_cnt) or (mem_in.rdy_cnt = 3))
				elsif ((( mem_in.rdy_cnt = 2 ) or ( mem_in.rdy_cnt = 3 )) and (next_pipelined(i) = '1')) then
					reg_in_rd_data(i) <= mem_in.rd_data;
				end if;			
			end if;
		end if;
	end process;
end generate;
 
 
 
-- Generates rdy_cnt and rd_data for all CPUs
gen_rdy_cnt: for i in 0 to cpu_cnt-1 generate
	process (mem_in, state, mode, reg_in_rd_data, next_pipelined)
	begin  
 
		arb_in(i).rd_data <= reg_in_rd_data(i);
		arb_in(i).rdy_cnt <= mem_in.rdy_cnt;
 
		case state(i) is
			when idle =>
				if (mode(i) = idl) then
					arb_in(i).rdy_cnt <= "00";
				elsif (mode(i) = servR) and (mem_in.rdy_cnt = 0) then
					arb_in(i).rd_data <= mem_in.rd_data;
				end if;
 
			when read =>
				if (mode(i) = servR) then
					if (mem_in.rdy_cnt = 0) then
						arb_in(i).rd_data <= mem_in.rd_data;
					-- added mem_in.rdy_cnt = 3
					elsif ((( mem_in.rdy_cnt = 2 ) or ( mem_in.rdy_cnt = 3 )) and (next_pipelined(i) = '1')) then
						arb_in(i).rd_data <= mem_in.rd_data;
					end if;
				end if;
 
			when write =>		
 
			when waitingR =>
				arb_in(i).rdy_cnt <= "11";
				if mode(i) = servR then
					arb_in(i).rd_data <= mem_in.rd_data;
				end if;
 
			when sendR =>
 
			when waitingW =>
				arb_in(i).rdy_cnt <= "11";
 
			when sendW =>
 
		end case;
	end process;
end generate;
 
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.