URL
https://opencores.org/ocsvn/simpcon/simpcon/trunk
Subversion Repositories simpcon
Compare Revisions
- This comparison shows the changes necessary to convert path
/simpcon
- from Rev 28 to Rev 29
- ↔ Reverse comparison
Rev 28 → Rev 29
/trunk/vhdl/sc_uart_tal.vhd
1,4 → 1,25
-- |
-- |
-- 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_uart_tal.vhd |
-- |
-- 8-N-1 serial interface |
/trunk/vhdl/sc2ahbsl.vhd
1,4 → 1,25
-- |
-- |
-- 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/>. |
-- |
|
|
-- |
-- sc2ahbsl.vhd |
-- |
-- SimpCon to AMBA bridge |
55,9 → 76,9
ahbsi.hsel(1 to NAHBSLV-1) <= (others => '0'); -- we use only slave 0 |
ahbsi.hsel(0) <= scmo.rd or scmo.wr; -- slave select |
-- do we need to store the addrsss in a register? |
ahbsi.haddr(MEM_ADDR_SIZE-1+2 downto 2) <= scmo.address; -- address bus (byte) |
ahbsi.haddr(SC_ADDR_SIZE-1+2 downto 2) <= scmo.address; -- address bus (byte) |
ahbsi.haddr(1 downto 0) <= (others => '0'); |
ahbsi.haddr(31 downto MEM_ADDR_SIZE+2) <= (others => '0'); |
ahbsi.haddr(31 downto SC_ADDR_SIZE+2) <= (others => '0'); |
ahbsi.hwrite <= scmo.wr; -- read/write |
ahbsi.htrans <= HTRANS_NONSEQ; -- transfer type |
ahbsi.hsize <= "010"; -- transfer size 32 bits |
/trunk/vhdl/sc_isa.vhd
1,4 → 1,25
-- |
-- |
-- 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_isa.vhd |
-- |
-- ISA bus for ethernet chip |
/trunk/vhdl/sc_pack.vhd
1,45 → 1,174
-- |
-- sc_pack.vhd |
-- |
-- Package for SimpCon defines |
-- |
-- Author: Martin Schoeberl (martin@jopdesign.com) |
-- |
-- |
-- 2007-03-16 first version |
-- |
-- |
|
library ieee; |
use ieee.std_logic_1164.all; |
use ieee.numeric_std.all; |
|
package sc_pack is |
|
constant MEM_ADDR_SIZE : integer := 21; |
constant IO_ADDR_SIZE : integer := 7; |
constant RDY_CNT_SIZE : integer := 2; |
|
type sc_mem_out_type is record |
address : std_logic_vector(MEM_ADDR_SIZE-1 downto 0); |
wr_data : std_logic_vector(31 downto 0); |
rd : std_logic; |
wr : std_logic; |
end record; |
|
type sc_io_out_type is record |
address : std_logic_vector(IO_ADDR_SIZE-1 downto 0); |
wr_data : std_logic_vector(31 downto 0); |
rd : std_logic; |
wr : std_logic; |
end record; |
|
type sc_in_type is record |
rd_data : std_logic_vector(31 downto 0); |
rdy_cnt : unsigned(RDY_CNT_SIZE-1 downto 0); |
end record; |
|
type sc_io_out_array_type is array (integer range <>) of sc_io_out_type; |
type sc_in_array_type is array (integer range <>) of sc_in_type; |
|
end sc_pack; |
-- |
-- |
-- 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_pack.vhd |
-- |
-- Package for SimpCon defines |
-- |
-- Author: Martin Schoeberl (martin@jopdesign.com) |
-- |
-- |
-- 2007-03-16 first version |
-- |
-- |
|
library std; |
use std.textio.all; |
|
library ieee; |
use ieee.std_logic_1164.all; |
use ieee.numeric_std.all; |
|
package sc_pack is |
|
-- two more bits than needed for the main memory |
-- one to distinguishe between memory and IO access |
-- one more to allow memory mirroring for size auto |
-- detection at boot time |
constant SC_ADDR_SIZE : integer := 23; |
constant RDY_CNT_SIZE : integer := 2; |
|
type sc_out_type is record |
address : std_logic_vector(SC_ADDR_SIZE-1 downto 0); |
wr_data : std_logic_vector(31 downto 0); |
rd : std_logic; |
wr : std_logic; |
atomic : std_logic; |
nc : std_logic; |
end record; |
|
type sc_in_type is record |
rd_data : std_logic_vector(31 downto 0); |
rdy_cnt : unsigned(RDY_CNT_SIZE-1 downto 0); |
end record; |
|
type sc_out_array_type is array (integer range <>) of sc_out_type; |
type sc_in_array_type is array (integer range <>) of sc_in_type; |
|
constant TIMEOUT : integer := 50; |
|
procedure sc_write( |
signal clk : in std_logic; |
constant addr : in natural; |
constant data : in natural; |
signal sc_out : out sc_out_type; |
signal sc_in : in sc_in_type); |
|
procedure sc_read( |
signal clk : in std_logic; |
constant addr : in natural; |
variable data : out natural; |
signal sc_out : out sc_out_type; |
signal sc_in : in sc_in_type); |
|
end sc_pack; |
|
package body sc_pack is |
|
procedure sc_write( |
signal clk : in std_logic; |
constant addr : in natural; |
constant data : in natural; |
signal sc_out : out sc_out_type; |
signal sc_in : in sc_in_type) is |
|
variable txt : line; |
|
begin |
|
write(txt, now, right, 8); |
write(txt, string'(" wrote ")); |
write(txt, data); |
write(txt, string'(" to addr. ")); |
write(txt, addr); |
|
sc_out.wr_data <= std_logic_vector(to_unsigned(data, sc_out.wr_data'length)); |
sc_out.address <= std_logic_vector(to_unsigned(addr, sc_out.address'length)); |
sc_out.wr <= '1'; |
sc_out.rd <= '0'; |
|
-- one cycle valid |
wait until rising_edge(clk); |
sc_out.wr_data <= (others => 'X'); |
sc_out.address <= (others => 'X'); |
sc_out.wr <= '0'; |
|
for i in 1 to TIMEOUT loop |
wait until rising_edge(clk); |
exit when sc_in.rdy_cnt = "00"; |
if (i = TIMEOUT) then |
write (txt, string'("No acknowledge recevied!")); |
end if; |
end loop; |
|
writeline(output, txt); |
|
end; |
|
procedure sc_read( |
signal clk : in std_logic; |
constant addr : in natural; |
variable data : out natural; |
signal sc_out : out sc_out_type; |
signal sc_in : in sc_in_type) is |
|
variable txt : line; |
variable in_data : natural; |
|
begin |
|
write(txt, now, right, 8); |
write(txt, string'(" read from addr. ")); |
write(txt, addr); |
writeline(output, txt); |
|
sc_out.address <= std_logic_vector(to_unsigned(addr, sc_out.address'length)); |
sc_out.wr_data <= (others => 'X'); |
sc_out.wr <= '0'; |
sc_out.rd <= '1'; |
|
-- one cycle valid |
wait until rising_edge(clk); |
sc_out.address <= (others => 'X'); |
sc_out.rd <= '0'; |
|
-- wait for acknowledge |
for i in 1 to TIMEOUT loop |
wait until rising_edge(clk); |
exit when sc_in.rdy_cnt = "00"; |
if (i = TIMEOUT) then |
write (txt, string'("No acknowledge recevied!")); |
end if; |
end loop; |
|
in_data := to_integer(unsigned(sc_in.rd_data)); |
data := in_data; |
|
write(txt, now, right, 8); |
write(txt, string'(" value: ")); |
write(txt, in_data); |
|
writeline(output, txt); |
|
end; |
|
end sc_pack; |
/trunk/vhdl/sc_arbiter_fixedpr_int.vhd
0,0 → 1,480
-- |
-- 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! |
-- 261107: Fixed Priority Interruptive Arbiter |
|
|
library ieee; |
use ieee.std_logic_1164.all; |
use ieee.numeric_std.all; |
|
use work.sc_pack.all; |
use work.sc_arbiter_pack.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 |
|
-- signals for the input 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_array_type is array (0 to cpu_cnt-1) of reg_type; |
signal reg_in : reg_array_type; |
|
-- one fsm for each CPU |
|
type state_type is (idle, read, write, waitingR, sendR, |
waitingW, sendW, pipeBlocked); |
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, serv); |
type serve_array is array (0 to cpu_cnt-1) of serve_type; |
signal this_state : serve_array; |
signal follow_state : serve_array; |
|
-- arbiter |
|
type set_type is array (0 to cpu_cnt-1) of std_logic; |
signal set : set_type; |
signal waiting : set_type; |
signal masterWaiting : std_logic; |
|
|
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_in(i).rd <= '0'; |
reg_in(i).wr <= '0'; |
reg_in(i).wr_data <= (others => '0'); |
reg_in(i).address <= (others => '0'); |
elsif rising_edge(clk) then |
if arb_out(i).rd = '1' or arb_out(i).wr = '1' then |
reg_in(i).rd <= arb_out(i).rd; |
reg_in(i).wr <= arb_out(i).wr; |
reg_in(i).address <= arb_out(i).address; |
reg_in(i).wr_data <= arb_out(i).wr_data; |
end if; |
end if; |
end process; |
end generate; |
|
-- Register for masterWaiting |
process(clk, reset) |
begin |
if reset = '1' then |
masterWaiting <= '0'; |
elsif rising_edge(clk) then |
for i in 0 to cpu_cnt-1 loop |
if waiting(i) = '1' then |
masterWaiting <= '1'; |
exit; |
else |
masterWaiting <= '0'; |
end if; |
end loop; |
end if; |
end process; |
|
-- Generates next state of the FSM for each master |
gen_next_state: for i in 0 to cpu_cnt-1 generate |
process(reset, state, arb_out, mem_in, this_state, reg_in, masterWaiting) |
begin |
|
next_state(i) <= state(i); |
waiting(i) <= '0'; |
|
case state(i) is |
when idle => |
|
-- checks if this CPU is on turn (pipelined access) |
if this_state(i) = serv then |
|
if mem_in.rdy_cnt = 1 and arb_out(i).rd = '1' then |
-- check if higher priority CPU wants to access and blocks pipelined access |
next_state(i) <= read; |
|
if arb_out(i).atomic = '1' then |
for j in 0 to cpu_cnt-1 loop |
if arb_out(j).rd = '1' or arb_out(j).wr = '1' then |
if j<i then |
next_state(i) <= pipeBlocked; |
--wait_cycles <= 1; |
exit; |
end if; |
end if; |
end loop; |
end if; |
|
elsif (mem_in.rdy_cnt = 0 and (arb_out(i).rd = '1' or arb_out(i).wr = '1')) then |
|
-- check if some master is waiting |
if masterWaiting = '1' then |
if arb_out(i).rd = '1' then |
next_state(i) <= waitingR; |
waiting(i) <= '1'; |
elsif arb_out(i).wr = '1' then |
next_state(i) <= waitingW; |
waiting(i) <= '1'; |
end if; |
|
-- check if parallel access |
else |
for j in 0 to cpu_cnt-1 loop |
if arb_out(j).rd = '1' or arb_out(j).wr = '1' then |
if i<=j then |
if arb_out(i).rd = '1' then |
next_state(i) <= read; |
exit; |
elsif arb_out(i).wr = '1' then |
next_state(i) <= write; |
exit; |
end if; |
else |
if arb_out(i).rd = '1' then |
next_state(i) <= waitingR; |
waiting(i) <= '1'; |
exit; |
elsif arb_out(i).wr = '1' then |
next_state(i) <= waitingW; |
waiting(i) <= '1'; |
exit; |
end if; |
end if; |
end if; |
end loop; |
end if; |
|
-- all other kinds of rdy_cnt |
else |
if arb_out(i).rd = '1' then |
next_state(i) <= waitingR; |
waiting(i) <= '1'; |
elsif arb_out(i).wr = '1' then |
next_state(i) <= waitingW; |
waiting(i) <= '1'; |
end if; |
end if; |
|
-- CPU is not already pipelined accessing the memory |
else |
if (mem_in.rdy_cnt = 0 and (arb_out(i).rd = '1' or arb_out(i).wr = '1')) then |
-- check if some master is waiting |
if masterWaiting = '1' then |
if arb_out(i).rd = '1' then |
next_state(i) <= waitingR; |
waiting(i) <= '1'; |
elsif arb_out(i).wr = '1' then |
next_state(i) <= waitingW; |
waiting(i) <= '1'; |
end if; |
|
-- check if another CPU wants to access in parallel |
else |
for j in 0 to cpu_cnt-1 loop |
if arb_out(j).rd = '1' or arb_out(j).wr = '1' then |
if i<=j then |
if arb_out(i).rd = '1' then |
next_state(i) <= read; |
exit; |
elsif arb_out(i).wr = '1' then |
next_state(i) <= write; |
exit; |
end if; |
else |
if arb_out(i).rd = '1' then |
next_state(i) <= waitingR; |
waiting(i) <= '1'; |
exit; |
elsif arb_out(i).wr = '1' then |
next_state(i) <= waitingW; |
waiting(i) <= '1'; |
exit; |
end if; |
end if; |
-- ** cannot ever happen!!!!!!! ** |
-- if no parallel access, master can access |
--else |
-- if arb_out(i).rd = '1' then |
-- next_state(i) <= read; |
-- elsif arb_out(i).wr = '1' then |
-- next_state(i) <= write; |
-- end if; |
end if; |
end loop; |
end if; |
|
-- rdy_cnt != 0 |
else |
if arb_out(i).rd = '1' then |
next_state(i) <= waitingR; |
waiting(i) <= '1'; |
elsif arb_out(i).wr = '1' then |
next_state(i) <= waitingW; |
waiting(i) <= '1'; |
end if; |
end if; |
end if; |
|
|
when read => |
next_state(i) <= idle; |
|
-- pipelined gets blocked |
if mem_in.rdy_cnt = 2 and arb_out(i).atomic = '1' then |
for j in 0 to cpu_cnt-1 loop |
if arb_out(j).rd = '1' or arb_out(j).wr = '1' then |
if j<i then |
next_state(i) <= pipeBlocked; |
--wait_cycles <= 3; |
exit; |
end if; |
end if; |
end loop; |
end if; |
|
when write => |
next_state(i) <= idle; |
|
when waitingR => |
if mem_in.rdy_cnt = 0 then |
-- checks which CPU in waitingR has highest priority |
for j in 0 to cpu_cnt-1 loop |
if (state(j) = waitingR) or (state(j) = waitingW) then |
if j<i then |
next_state(i) <= waitingR; |
waiting(i) <= '1'; |
exit; |
else |
next_state(i) <= sendR; |
exit; |
end if; |
else |
next_state(i) <= sendR; |
end if; |
end loop; |
else |
next_state(i) <= waitingR; |
waiting(i) <= '1'; |
end if; |
|
when sendR => |
next_state(i) <= idle; |
|
when waitingW => |
|
if mem_in.rdy_cnt = 0 then |
for j in 0 to cpu_cnt-1 loop |
if (state(j) = waitingR) or (state(j) = waitingW) then |
if j<i then |
next_state(i) <= waitingW; |
waiting(i) <= '1'; |
exit; |
else |
next_state(i) <= sendW; |
exit; |
end if; |
else |
next_state(i) <= sendW; |
end if; |
end loop; |
else |
next_state(i) <= waitingW; |
waiting(i) <= '1'; |
end if; |
|
when sendW => |
next_state(i) <= idle; |
|
when pipeBlocked => |
if mem_in.rdy_cnt = 0 then -- to be in serv Mode until request done |
next_state(i) <= waitingR; --no waitingW possible because we don't use pipelined write!!!!! |
else |
next_state(i) <= pipeBlocked; |
end if; |
|
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; |
elsif (rising_edge(clk)) then |
state(i) <= next_state(i); |
end if; |
end process; |
end generate; |
|
|
-- The arbiter output |
process (arb_out, reg_in, 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) <= '0'; |
|
case next_state(i) is |
when idle => |
|
when read => |
set(i) <= '1'; |
mem_out.rd <= arb_out(i).rd; |
mem_out.address <= arb_out(i).address; |
|
when write => |
set(i) <= '1'; |
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) <= '1'; |
mem_out.rd <= reg_in(i).rd; |
mem_out.address <= reg_in(i).address; |
|
when waitingW => |
|
when sendW => |
set(i) <= '1'; |
mem_out.wr <= reg_in(i).wr; |
mem_out.address <= reg_in(i).address; |
mem_out.wr_data <= reg_in(i).wr_data; |
|
when pipeBlocked => |
set(i) <= '1'; |
|
end case; |
end loop; |
end process; |
|
-- generation of follow_state |
gen_serve: for i in 0 to cpu_cnt-1 generate |
process(mem_in, set, this_state) |
begin |
case this_state(i) is |
when idl => |
follow_state(i) <= idl; |
if set(i) = '1' then |
follow_state(i) <= serv; |
end if; |
when serv => |
follow_state(i) <= serv; |
if mem_in.rdy_cnt = 0 and set(i) = '0' then |
follow_state(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 |
this_state(i) <= idl; |
elsif (rising_edge(clk)) then |
this_state(i) <= follow_state(i); |
end if; |
end process; |
end generate; |
|
gen_rdy_cnt: for i in 0 to cpu_cnt-1 generate |
process (mem_in, state, this_state) |
begin |
arb_in(i).rdy_cnt <= mem_in.rdy_cnt; |
arb_in(i).rd_data <= mem_in.rd_data; |
|
case state(i) is |
when idle => |
case this_state(i) is |
when idl => |
arb_in(i).rdy_cnt <= "00"; |
when serv => |
end case; |
|
when read => |
|
when write => |
|
when waitingR => |
arb_in(i).rdy_cnt <= "11"; |
|
when sendR => |
|
when waitingW => |
arb_in(i).rdy_cnt <= "11"; |
|
when sendW => |
|
when pipeBlocked => |
arb_in(i).rdy_cnt <= "11"; |
|
end case; |
end process; |
end generate; |
|
end rtl; |
/trunk/vhdl/sc_lego.vhd
1,4 → 1,25
-- |
-- |
-- 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_lego.vhd |
-- |
-- Motor and sensor interface for LEGO MindStorms |
/trunk/vhdl/sc_usb.vhd
1,4 → 1,25
-- |
-- |
-- 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_usb.vhd |
-- |
-- Interface to FTDI FT2232C parallel port B |
/trunk/vhdl/sc2wb.vhd
1,4 → 1,25
-- |
-- |
-- 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/>. |
-- |
|
|
-- |
-- sc2wb.vhd |
-- |
-- SimpCon/Wishbone bridge |
/trunk/vhdl/sc_test_top.vhd
1,4 → 1,25
-- |
-- |
-- 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/>. |
-- |
|
|
-- |
-- scio_test_top.vhd |
-- |
-- The top level to test SimpCon IO devices. |
/trunk/vhdl/sc_sigdel.vhd
1,4 → 1,25
-- |
-- |
-- 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_sigdel.vhd |
-- |
-- A simple sigma-delta ADC and PWM DAC for the SimpCon interface |
/trunk/vhdl/sc_control_channel.vhd
0,0 → 1,179
-- |
-- |
-- This file is a part of JOP, the Java Optimized Processor |
-- |
-- Copyright (C) 2008, Jack Whitham |
-- |
-- 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_control_channel.vhd |
-- |
-- 32 bit parallel interface for the control channel; |
-- mimics a serial port UART device. Data is sent in a packet |
-- form (with a header word and zero or more payload words). |
-- |
|
|
library ieee; |
use ieee.std_logic_1164.all; |
use ieee.std_logic_unsigned."+"; |
use ieee.numeric_std.all; |
|
entity sc_control_channel is |
generic (addr_bits : integer); |
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); |
|
cc_out_data : out std_logic_vector(31 downto 0); |
cc_out_wr : out std_logic; |
cc_out_rdy : in std_logic; |
|
cc_in_data : in std_logic_vector(31 downto 0); |
cc_in_wr : in std_logic; |
cc_in_rdy : out std_logic |
); |
end sc_control_channel; |
|
architecture rtl of sc_control_channel is |
|
signal incoming_message : std_logic_vector(31 downto 0); |
signal outgoing_message : std_logic_vector(31 downto 0); |
signal send_ack, send_flag : std_logic; |
|
type StateType is ( IDLE, RELAY, SEND, AWAIT_REPLY, AWAIT_REPLY_RELAY ); |
|
signal state : StateType; |
|
begin |
|
process ( clk , reset ) is |
begin |
if ( reset = '1' ) |
then |
send_flag <= '0'; |
|
elsif ( clk = '1' ) |
and ( clk'event ) |
then |
if ( send_ack = '1' ) |
then |
send_flag <= '0'; |
end if; |
|
if ( rd = '1' ) |
then |
null; |
elsif ( wr = '1' ) |
then |
outgoing_message <= wr_data; |
send_flag <= '1'; |
end if; |
end if; |
end process; |
|
rdy_cnt <= "00" when (( state = IDLE ) and ( send_flag = '0' )) else "11"; |
rd_data <= incoming_message; |
|
process ( clk , reset ) is |
begin |
if ( reset = '1' ) |
then |
state <= IDLE; |
cc_in_rdy <= '0'; |
cc_out_wr <= '0'; |
send_ack <= '0'; |
|
elsif ( clk = '1' ) |
and ( clk'event ) |
then |
cc_in_rdy <= '0'; |
cc_out_wr <= '0'; |
send_ack <= '0'; |
|
case state is |
when IDLE => |
if ( send_flag = '1' ) |
then |
-- A message to be sent |
cc_out_data <= outgoing_message; |
send_ack <= '1'; |
state <= SEND; |
elsif ( cc_in_wr = '1' ) |
then |
-- Relay incoming message since we are not |
-- waiting for a message |
cc_out_data <= cc_in_data; |
state <= RELAY; |
else |
-- Ready for CC data |
cc_in_rdy <= '1'; |
end if; |
|
when RELAY => |
if ( cc_out_rdy = '1' ) |
then |
cc_out_wr <= '1'; |
state <= IDLE; |
end if; |
|
when SEND => |
if ( cc_out_rdy = '1' ) |
then |
cc_out_wr <= '1'; |
state <= AWAIT_REPLY; |
end if; |
|
when AWAIT_REPLY => |
if ( cc_in_wr = '1' ) |
then |
-- Examine incoming message |
if ( cc_in_data ( 30 downto 16 ) = outgoing_message ( 30 downto 16 ) ) |
then |
-- Correct message |
incoming_message <= cc_in_data; |
state <= IDLE; |
else |
-- Wrong message (for someone else) |
cc_out_data <= cc_in_data; |
state <= AWAIT_REPLY_RELAY; |
end if; |
else |
-- Ready for CC data |
cc_in_rdy <= '1'; |
end if; |
|
when AWAIT_REPLY_RELAY => |
if ( cc_out_rdy = '1' ) |
then |
cc_out_wr <= '1'; |
state <= AWAIT_REPLY; |
end if; |
end case; |
end if; |
end process; |
|
end rtl; |
|
/trunk/vhdl/sc_uart.vhd
1,4 → 1,25
-- |
-- |
-- 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_uart.vhd |
-- |
-- 8-N-1 serial interface |
/trunk/vhdl/sc_sys.vhd
1,14 → 1,35
-- |
-- |
-- 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@good-ear.com |
-- Author: Martin Schoeberl martin@jopdesign.com |
-- |
-- address map: |
-- |
-- 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()) |
-- 3 write wd port |
-- 4 write generates SW exception, read exception reason |
22,8 → 43,61
-- 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; |
34,7 → 108,9
|
generic (addr_bits : 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 ( |
clk : in std_logic; |
reset : in std_logic; |
50,14 → 126,22
-- |
-- 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; |
|
io_int : in std_logic_vector(num_io_int-1 downto 0) := "00"; |
|
sync_out : in sync_out_type; |
sync_out : in sync_out_type := NO_SYNC; |
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 ; |
|
70,26 → 154,51
constant div_val : integer := clk_freq/1000000-1; |
|
signal timer_int : std_logic; |
signal yield_int : std_logic; |
signal int_ack : std_logic; |
|
signal timer : std_logic; |
signal yield : std_logic; |
|
signal irq_cnt : std_logic_vector(31 downto 0); |
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 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 <= "00"; -- no wait states |
|
rdy_cnt <= "11" when (sync_out.halted='1' and lock_reqest='1') else "00"; |
|
-- |
-- read cnt values |
-- |
96,25 → 205,39
process(clk, reset) |
begin |
|
if (reset='1') then |
if reset='1' then |
rd_data <= (others => '0'); |
elsif rising_edge(clk) then |
|
if rd='1' then |
case address(2 downto 0) is |
when "000" => |
case address(3 downto 0) is |
when "0000" => |
rd_data <= clock_cnt; |
when "001" => |
when "0001" => |
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(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; |
-- when "111" => |
when others => |
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; |
125,15 → 248,15
-- compare timer value and us counter |
-- and generate single shot |
-- |
process(us_cnt, irq_cnt) begin |
process(us_cnt, timer_cnt) begin |
timer_equ <= '0'; |
if us_cnt = irq_cnt then |
if us_cnt = timer_cnt then |
timer_equ <= '1'; |
end if; |
end process; |
|
process(clk, reset, timer_equ) begin |
if (reset='1') then |
process(clk, reset) begin |
if reset='1' then |
timer_dly <= '0'; |
elsif rising_edge(clk) then |
timer_dly <= timer_equ; |
145,30 → 268,73
-- |
-- int processing from timer and yield request |
-- |
process(clk, reset, timer_int, yield_int) begin |
|
if (reset='1') then |
timer <= '0'; |
yield <= '0'; |
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 |
if int_ack='1' then |
timer <= '0'; |
yield <= '0'; |
else |
if timer_int='1' then |
timer <= '1'; |
end if; |
if yield_int='1' then |
yield <= '1'; |
end if; |
|
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_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 |
-- pre_scale is 8 bit => fmax = 255 MHz |
201,54 → 367,78
begin |
if (reset='1') then |
|
irq_in.irq_ena <= '0'; |
irq_cnt <= (others => '0'); |
int_ack <= '0'; |
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'); |
irq_in.exc_int <= '0'; |
exc_pend <= '0'; |
|
swreq <= (others => '0'); |
mask <= (others => '0'); |
clearall <= '0'; |
|
elsif rising_edge(clk) then |
|
int_ack <= '0'; |
yield_int <= '0'; |
exc_pend <= '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 |
exc_type(2 downto 0) <= EXC_SPOV; |
irq_in.exc_int <= '1'; |
exc_pend <= '1'; |
end if; |
if exc_req.np='1' then |
exc_type(2 downto 0) <= EXC_NP; |
irq_in.exc_int <= '1'; |
exc_pend <= '1'; |
end if; |
if exc_req.ab='1' then |
exc_type(2 downto 0) <= EXC_AB; |
irq_in.exc_int <= '1'; |
exc_pend <= '1'; |
end if; |
|
if wr='1' then |
case address(2 downto 0) is |
when "000" => |
irq_in.irq_ena <= wr_data(0); |
when "001" => |
irq_cnt <= wr_data; |
int_ack <= '1'; |
when "010" => |
yield_int <= '1'; |
when "011" => |
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 "100" => |
when "0100" => |
exc_type <= wr_data(7 downto 0); |
irq_in.exc_int <= '1'; |
when "110" => |
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 => |
-- when "111" => |
sync_in.s_in <= wr_data(0); |
end case; |
end if; |
|
255,4 → 445,16
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; |
/trunk/vhdl/sc_cnt.vhd
1,4 → 1,25
-- |
-- |
-- 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_cnt.vhd |
-- |
-- counter, interrrupt handling and watchdog bit |
/trunk/vhdl/sc_arbiter_pack.vhd
1,3 → 1,23
-- |
-- 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/>. |
-- |
|
|
library ieee; |
use ieee.std_logic_1164.all; |
use ieee.numeric_std.all; |
6,7 → 26,7
|
package sc_arbiter_pack is |
|
type arb_out_type is array (integer range <>) of sc_mem_out_type; |
type arb_out_type is array (integer range <>) of sc_out_type; |
type arb_in_type is array (integer range <>) of sc_in_type; |
|
end sc_arbiter_pack; |
/trunk/vhdl/sc_arbiter_fair.vhd
0,0 → 1,442
-- |
-- 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; |
/trunk/vhdl/sc_fpu.vhd
1,3 → 1,24
-- |
-- |
-- 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/>. |
-- |
|
|
-- This is the SimpCon interface to the FPU |
-- |
|
/trunk/vhdl/sc_spi.vhd
0,0 → 1,290
-- |
-- |
-- address map: |
-- |
-- 0 SS Register |
-- 1 SCLK Divider |
-- 2 Data in |
-- 3 Data out |
-- 4 Interrupt Config Status |
-- |
|
|
library ieee; |
use ieee.std_logic_1164.all; |
use ieee.numeric_std.all; |
|
use work.jop_types.all; |
|
entity sc_spi is |
|
generic (addr_bits : integer; |
clk_freq : integer); |
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); |
|
-- SPI Con |
|
slave_s : out std_logic_vector(7 downto 0); |
miso : in std_logic; |
mosi : out std_logic; |
sclk : out std_logic; |
|
); |
end sc_spi; |
|
architecture rtl of sc_spi is |
|
signal spi_out : std_logic_vector(7 downto 0); |
signal spi_in : std_logic_vector(7 downto 0); |
|
signal read_ack : std_logic; |
signal fifo_wr : std_logic; |
|
-- |
-- |
constant WS : integer := (clk_freq/20000000)+1; |
signal cnt : integer range 0 to WS; |
|
-- |
-- FIFO signals |
-- |
signal tf_dout : std_logic_vector(7 downto 0); -- fifo out |
signal tf_rd : std_logic; |
signal tf_empty : std_logic; |
signal tf_full : std_logic; |
|
signal rf_din : std_logic_vector(7 downto 0); -- fifo input |
signal rf_wr : std_logic; |
signal rf_empty : std_logic; |
signal rf_full : std_logic; |
|
|
-- |
-- USB interface signals |
-- |
type state_type is (idle, inact, rx1, rx2, tx1, tx2); |
signal state : state_type; |
|
signal spi_dout : std_logic_vector(7 downto 0); |
signal spi_din : std_logic_vector(7 downto 0); |
|
--signal nrxf_buf : std_logic_vector(1 downto 0); |
--signal ntxe_buf : std_logic_vector(1 downto 0); |
--signal rdr, wrr : std_logic_vector(7 downto 0); |
--signal data_oe : std_logic; |
|
begin |
|
rdy_cnt <= "00"; -- no wait states |
rd_data(31 downto 8) <= std_logic_vector(to_unsigned(0, 24)); |
-- |
-- The registered MUX is all we need for a SimpCon read. |
-- The read data is stored in registered rd_data. |
-- |
process(clk, reset) |
begin |
|
if (reset='1') then |
rd_data(7 downto 0) <= (others => '0'); |
elsif rising_edge(clk) then |
|
read_ack <= '0'; |
if rd='1' then |
case address(2 downto 0) is |
when "000" => |
rd_data(7 downto 0) <= slave_s; |
rd_data(31 downto 8) <= (others => '0'); |
when "001" => |
rd_data(7 downto 0) <= WS; |
rd_data(31 downto 8) <= (others => '0'); |
when "010" => |
rd_data(7 downto 0) <= spi_din; |
rd_data(31 downto 8) <= (others => '0'); |
when "011" => |
rd_data(7 downto 0) <= spi_dout; |
rd_data(31 downto 8) <= (others => '0'); |
when "100" => |
rd_data(7 downto 0) <= spi_dout; |
rd_data(31 downto 8) <= (others => '0'); |
-- when "111" => |
when others => |
rd_data(0) <= '0'; |
rd_data(31 downto 1) <= (others => '0'); |
end case; |
end if; |
end if; |
|
if wr='1' then |
case address(2 downto 0) is |
when "000" => |
irq_in.irq_ena <= wr_data(0); |
when "001" => |
irq_cnt <= wr_data; |
int_ack <= '1'; |
when "010" => |
spi_din <= wr_data;; |
when "011" => |
spi_dout <= wr_data;; |
when "100" => |
spi_dout <= wr_data;; |
when "110" => |
-- nothing, processor id is read only |
when others => |
-- when "111" => |
sync_in.s_in <= wr_data(0); |
end case; |
end if; |
|
end process; |
|
|
-- we don't use the send immediate |
nsi <= '1'; |
|
|
-- |
-- receive fifo |
-- |
rxfifo: entity work.fifo generic map ( |
width => 8, |
depth => 4, |
thres => 2 -- we don't care about the half signal |
) port map ( |
clk => clk, |
reset => reset, |
din => rf_din, |
dout => usb_dout, |
rd => read_ack, |
wr => rf_wr, |
empty => rf_empty, |
full => rf_full, |
half => open |
); |
|
-- |
-- transmit fifo |
-- |
txfifo: entity work.fifo generic map ( |
width => 8, |
depth => 4, |
thres => 2 -- we don't care about the half signal |
) port map ( |
clk => clk, |
reset => reset, |
din => wr_data(7 downto 0), |
dout => tf_dout, |
rd => tf_rd, |
wr => fifo_wr, |
empty => tf_empty, |
full => tf_full, |
half => open |
); |
|
|
-- |
-- state machine for the usb bus |
-- |
process(clk, reset) |
|
begin |
|
if (reset='1') then |
state <= idle; |
nrxf_buf <= "11"; |
ntxe_buf <= "11"; |
cnt <= WS; |
|
rdr <= (others => '0'); |
wrr <= (others => '0'); |
|
tf_rd <= '0'; |
rf_wr <= '0'; |
|
nrd <= '1'; |
ft_wr <= '0'; |
|
elsif rising_edge(clk) then |
|
-- input register |
nrxf_buf(0) <= nrxf; |
nrxf_buf(1) <= nrxf_buf(0); |
ntxe_buf(0) <= ntxe; |
ntxe_buf(1) <= ntxe_buf(0); |
|
case state is |
|
when idle => |
cnt <= WS; |
tf_rd <= '0'; |
rf_wr <= '0'; |
nrd <= '1'; |
ft_wr <= '0'; |
data_oe <= '0'; |
if rf_full='0' and nrxf_buf(1)='0' then |
nrd <= '0'; |
state <= rx1; |
elsif tf_empty='0' and ntxe_buf(1)='0' then |
ft_wr <= '1'; |
wrr <= tf_dout; |
tf_rd <= '1'; |
state <= tx1; |
end if; |
|
when inact => |
tf_rd <= '0'; |
rf_wr <= '0'; |
nrd <= '1'; |
ft_wr <= '0'; |
data_oe <= '0'; |
cnt <= cnt-1; |
if cnt=0 then |
state <= idle; |
end if; |
|
|
when rx1 => |
cnt <= cnt-1; |
if cnt=0 then |
state <= rx2; |
rdr <= data; |
end if; |
|
when rx2 => |
nrd <= '1'; |
rf_wr <= '1'; |
cnt <= WS; |
state <= inact; |
|
when tx1 => |
tf_rd <= '0'; |
data_oe <= '1'; |
cnt <= cnt-1; |
if cnt=0 then |
state <= tx2; |
ft_wr <= '0'; |
end if; |
|
when tx2 => |
data_oe <= '0'; |
cnt <= WS; |
state <= inact; |
|
end case; |
end if; |
|
end process; |
|
data <= wrr when data_oe='1' else (others => 'Z'); |
rf_din <= data; |
|
end rtl; |
/trunk/vhdl/sc_arbiter_tdma.vhd
0,0 → 1,504
-- |
-- 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 |
-- 190208: Development of TDMA Arbiter |
-- 130308: * Renaming of this_state to mode, follow_state to next_mode |
-- * counter dependencies moved from FSM to slot generation |
-- * changed set to 2 bits |
-- * changed serv to servR and servW |
-- * added signal pipelined |
-- * added rd_data register for each CPU |
-- 140308: Working version |
-- 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 |
|
-- TODO: - Add atomic for Wolfgang |
-- - full pipelined version |
-- - add period and time slots from software using RAM |
|
|
|
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; |
signal period : integer; |
signal slot_length : integer; |
type time_type is array (0 to cpu_cnt-1) of integer; |
signal cpu_time : time_type; -- how much clock cycles each CPU |
type slot_type is array (0 to cpu_cnt-1) of std_logic; |
signal slot : slot_type; -- defines which CPU is on turn |
|
-- read and write gaps |
|
signal read_gap : integer; |
signal write_gap : integer; |
|
|
begin |
|
-- Constants for read_gap, write_gap, slot_length: |
-- DE2 board: 6 cycle memory write, 4 cycle memory read |
-- write_gap <= 5; read_gap <= 3; |
-- minimal slot_length <= 6; |
-- cyc12 board: 3 cycle memory write, 2 cycle memory read |
-- write_gap <= 2; read_gap <= 1; |
-- minimal slot_length <= 3; |
|
write_gap <= 2; |
read_gap <= 1; |
slot_length <=7; |
period <= cpu_cnt*slot_length; |
|
-- generate slot information |
slots: for i in 0 to cpu_cnt-1 generate |
cpu_time(i) <= (i+1)*slot_length; |
end generate; |
|
-- TODO: should really be configrable with: number of CPUs, slot length, |
-- and memory access time. Should use assert to check that the slot length |
-- is longer than the memory access time. |
|
|
-- 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; |
if counter = period-1 then |
counter <= 0; |
end if; |
end if; |
end process; |
|
-- A time slot is assigned to each CPU |
process(counter, cpu_time, read_gap, write_gap, arb_out) |
begin |
for j in 0 to cpu_cnt-1 loop |
slot(j) <= '0'; |
end loop; |
|
if (counter > -1) and (counter < cpu_time(0)-write_gap) then |
slot(0) <= '1'; |
elsif (counter > -1) and (counter < cpu_time(0)-read_gap) and (arb_out(0).rd = '1') then -- rd is 2 cycles longer allowed |
slot(0) <= '1'; |
|
elsif (counter > cpu_time(0)-1) and (counter < cpu_time(1)-write_gap) then |
slot(1) <= '1'; |
elsif (counter > cpu_time(0)-1) and (counter < cpu_time(1)-read_gap) and (arb_out(1).rd = '1') then -- rd is 2 cycles longer allowed |
slot(1) <= '1'; |
|
elsif (counter > cpu_time(1)-1) and (counter < cpu_time(2)-write_gap) then |
slot(2) <= '1'; |
elsif (counter > cpu_time(1)-1) and (counter < cpu_time(2)-read_gap) and (arb_out(2).rd = '1') then -- rd is 2 cycles longer allowed |
slot(2) <= '1'; |
-- |
-- elsif (counter > cpu_time(2)-1) and (counter < cpu_time(3)-write_gap) then |
-- slot(3) <= '1'; |
-- elsif (counter > cpu_time(2)-1) and (counter < cpu_time(3)-read_gap) and (arb_out(3).rd = '1') then -- rd is 2 cycles longer allowed |
-- slot(3) <= '1'; |
-- |
-- elsif (counter > cpu_time(3)-1) and (counter < cpu_time(4)-write_gap) then |
-- slot(4) <= '1'; |
-- elsif (counter > cpu_time(3)-1) and (counter < cpu_time(4)-read_gap) and (arb_out(4).rd = '1') then -- rd is 2 cycles longer allowed |
-- slot(4) <= '1'; |
-- |
-- elsif (counter > cpu_time(4)-1) and (counter < cpu_time(5)-write_gap) then |
-- slot(5) <= '1'; |
-- elsif (counter > cpu_time(4)-1) and (counter < cpu_time(5)-read_gap) and (arb_out(5).rd = '1') then -- rd is 2 cycles longer allowed |
-- slot(5) <= '1'; |
-- |
-- elsif (counter > cpu_time(5)-1) and (counter < cpu_time(6)-write_gap) then |
-- slot(6) <= '1'; |
-- elsif (counter > cpu_time(5)-1) and (counter < cpu_time(6)-read_gap) and (arb_out(6).rd = '1') then -- rd is 2 cycles longer allowed |
-- slot(6) <= '1'; |
-- |
-- elsif (counter > cpu_time(6)-1) and (counter < cpu_time(7)-write_gap) then |
-- slot(7) <= '1'; |
-- elsif (counter > cpu_time(6)-1) and (counter < cpu_time(7)-read_gap) and (arb_out(7).rd = '1') then -- rd is 2 cycles longer allowed |
-- slot(7) <= '1'; |
end if; |
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, counter, 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, next_pipelined, reg_in_rd_data) |
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. |
-- 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 |
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; |
/trunk/vhdl/sc_mac.vhd
1,4 → 1,25
-- |
-- |
-- 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_mac.vhd |
-- |
-- A simple MAC unit with a SimpCon interface |
/trunk/vhdl/sc2avalon.vhd
1,4 → 1,25
-- |
-- |
-- 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/>. |
-- |
|
|
-- |
-- sc2avalon.vhd |
-- |
-- SimpCon to Avalon bridge |
/trunk/vhdl/sc_test_slave.vhd
1,4 → 1,25
-- |
-- |
-- 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_test_slave.vhd |
-- |
-- A simple test slave for the SimpCon interface |
/trunk/vhdl/sc_arbiter_fixedpr.vhd
0,0 → 1,446
-- |
-- 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! |
-- 210208: Does not use atomic |
|
|
library ieee; |
use ieee.std_logic_1164.all; |
use ieee.numeric_std.all; |
|
use work.sc_pack.all; |
use work.sc_arbiter_pack.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 |
|
-- signals for the input 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_array_type is array (0 to cpu_cnt-1) of reg_type; |
signal reg_in : reg_array_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, serv); |
type serve_array is array (0 to cpu_cnt-1) of serve_type; |
signal this_state : serve_array; |
signal follow_state : serve_array; |
|
-- arbiter |
|
type set_type is array (0 to cpu_cnt-1) of std_logic; |
signal set : set_type; |
signal waiting : set_type; |
signal masterWaiting : std_logic; |
|
|
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_in(i).rd <= '0'; |
reg_in(i).wr <= '0'; |
reg_in(i).wr_data <= (others => '0'); |
reg_in(i).address <= (others => '0'); |
elsif rising_edge(clk) then |
if arb_out(i).rd = '1' or arb_out(i).wr = '1' then |
reg_in(i).rd <= arb_out(i).rd; |
reg_in(i).wr <= arb_out(i).wr; |
reg_in(i).address <= arb_out(i).address; |
reg_in(i).wr_data <= arb_out(i).wr_data; |
end if; |
end if; |
end process; |
end generate; |
|
-- Register for masterWaiting |
process(clk, reset) |
begin |
if reset = '1' then |
masterWaiting <= '0'; |
elsif rising_edge(clk) then |
for i in 0 to cpu_cnt-1 loop |
if waiting(i) = '1' then |
masterWaiting <= '1'; |
exit; |
else |
masterWaiting <= '0'; |
end if; |
end loop; |
end if; |
end process; |
|
-- Generates next state of the FSM for each master |
gen_next_state: for i in 0 to cpu_cnt-1 generate |
process(reset, state, arb_out, mem_in, this_state, reg_in, masterWaiting) |
begin |
|
next_state(i) <= state(i); |
waiting(i) <= '0'; |
|
case state(i) is |
when idle => |
|
-- checks if this CPU is on turn (pipelined access) |
if this_state(i) = serv then |
-- pipelined access |
if mem_in.rdy_cnt = 1 and arb_out(i).rd = '1' then |
next_state(i) <= read; |
|
elsif (mem_in.rdy_cnt = 0 and (arb_out(i).rd = '1' or arb_out(i).wr = '1')) then |
|
-- check if some master is waiting |
if masterWaiting = '1' then |
if arb_out(i).rd = '1' then |
next_state(i) <= waitingR; |
waiting(i) <= '1'; |
elsif arb_out(i).wr = '1' then |
next_state(i) <= waitingW; |
waiting(i) <= '1'; |
end if; |
|
-- check if parallel access |
else |
for j in 0 to cpu_cnt-1 loop |
if arb_out(j).rd = '1' or arb_out(j).wr = '1' then |
if i<=j then |
if arb_out(i).rd = '1' then |
next_state(i) <= read; |
exit; |
elsif arb_out(i).wr = '1' then |
next_state(i) <= write; |
exit; |
end if; |
else |
if arb_out(i).rd = '1' then |
next_state(i) <= waitingR; |
waiting(i) <= '1'; |
exit; |
elsif arb_out(i).wr = '1' then |
next_state(i) <= waitingW; |
waiting(i) <= '1'; |
exit; |
end if; |
end if; |
end if; |
end loop; |
end if; |
|
-- all other kinds of rdy_cnt |
else |
if arb_out(i).rd = '1' then |
next_state(i) <= waitingR; |
waiting(i) <= '1'; |
elsif arb_out(i).wr = '1' then |
next_state(i) <= waitingW; |
waiting(i) <= '1'; |
end if; |
end if; |
|
-- CPU is not on turn (no pipelined access possible) |
else |
if (mem_in.rdy_cnt = 0 and (arb_out(i).rd = '1' or arb_out(i).wr = '1')) then |
-- check if some master is waiting |
if masterWaiting = '1' then |
if arb_out(i).rd = '1' then |
next_state(i) <= waitingR; |
waiting(i) <= '1'; |
elsif arb_out(i).wr = '1' then |
next_state(i) <= waitingW; |
waiting(i) <= '1'; |
end if; |
|
-- check if parallel access |
else |
for j in 0 to cpu_cnt-1 loop |
if arb_out(j).rd = '1' or arb_out(j).wr = '1' then |
if i<=j then |
if arb_out(i).rd = '1' then |
next_state(i) <= read; |
exit; |
elsif arb_out(i).wr = '1' then |
next_state(i) <= write; |
exit; |
end if; |
else |
if arb_out(i).rd = '1' then |
next_state(i) <= waitingR; |
waiting(i) <= '1'; |
exit; |
elsif arb_out(i).wr = '1' then |
next_state(i) <= waitingW; |
waiting(i) <= '1'; |
exit; |
end if; |
end if; |
-- if no parallel access, master can access |
else |
if arb_out(i).rd = '1' then |
next_state(i) <= read; |
elsif arb_out(i).wr = '1' then |
next_state(i) <= write; |
end if; |
end if; |
end loop; |
end if; |
|
-- rdy_cnt != 0 |
else |
if arb_out(i).rd = '1' then |
next_state(i) <= waitingR; |
waiting(i) <= '1'; |
elsif arb_out(i).wr = '1' then |
next_state(i) <= waitingW; |
waiting(i) <= '1'; |
end if; |
end if; |
end if; |
|
|
when read => |
next_state(i) <= idle; |
|
when write => |
next_state(i) <= idle; |
|
when waitingR => |
if mem_in.rdy_cnt = 0 then |
-- checks which CPU in waitingR has highest priority |
for j in 0 to cpu_cnt-1 loop |
if (state(j) = waitingR) or (state(j) = waitingW) then |
if j<i then |
next_state(i) <= waitingR; |
waiting(i) <= '1'; |
exit; |
elsif j=i then |
next_state(i) <= sendR; |
exit; |
else |
next_state(i) <= sendR; |
exit; |
end if; |
else |
next_state(i) <= sendR; |
end if; |
end loop; |
else |
next_state(i) <= waitingR; |
waiting(i) <= '1'; |
end if; |
|
when sendR => |
next_state(i) <= idle; |
|
when waitingW => |
|
if mem_in.rdy_cnt = 0 then |
for j in 0 to cpu_cnt-1 loop |
if (state(j) = waitingR) or (state(j) = waitingW) then |
if j<i then |
next_state(i) <= waitingW; |
waiting(i) <= '1'; |
exit; |
elsif j=i then |
next_state(i) <= sendW; |
exit; |
else |
next_state(i) <= sendW; |
exit; |
end if; |
else |
next_state(i) <= sendW; |
end if; |
end loop; |
else |
next_state(i) <= waitingW; |
waiting(i) <= '1'; |
end if; |
|
when sendW => |
next_state(i) <= idle; |
|
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; |
elsif (rising_edge(clk)) then |
state(i) <= next_state(i); |
end if; |
end process; |
end generate; |
|
|
-- The arbiter output |
process (arb_out, reg_in, 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) <= '0'; |
|
case next_state(i) is |
when idle => |
|
when read => |
set(i) <= '1'; |
mem_out.rd <= arb_out(i).rd; |
mem_out.address <= arb_out(i).address; |
|
when write => |
set(i) <= '1'; |
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) <= '1'; |
mem_out.rd <= reg_in(i).rd; |
mem_out.address <= reg_in(i).address; |
|
when waitingW => |
|
when sendW => |
set(i) <= '1'; |
mem_out.wr <= reg_in(i).wr; |
mem_out.address <= reg_in(i).address; |
mem_out.wr_data <= reg_in(i).wr_data; |
|
end case; |
end loop; |
end process; |
|
-- generation of follow_state |
gen_serve: for i in 0 to cpu_cnt-1 generate |
process(mem_in, set, this_state) |
begin |
case this_state(i) is |
when idl => |
follow_state(i) <= idl; |
if set(i) = '1' then |
follow_state(i) <= serv; |
end if; |
when serv => |
follow_state(i) <= serv; |
if mem_in.rdy_cnt = 0 and set(i) = '0' then |
follow_state(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 |
this_state(i) <= idl; |
elsif (rising_edge(clk)) then |
this_state(i) <= follow_state(i); |
end if; |
end process; |
end generate; |
|
gen_rdy_cnt: for i in 0 to cpu_cnt-1 generate |
process (mem_in, state, this_state) |
begin |
arb_in(i).rdy_cnt <= mem_in.rdy_cnt; |
arb_in(i).rd_data <= mem_in.rd_data; |
|
case state(i) is |
when idle => |
case this_state(i) is |
when idl => |
arb_in(i).rdy_cnt <= "00"; |
when serv => |
end case; |
|
when read => |
|
when write => |
|
when waitingR => |
arb_in(i).rdy_cnt <= "11"; |
|
when sendR => |
|
when waitingW => |
arb_in(i).rdy_cnt <= "11"; |
|
when sendW => |
|
end case; |
end process; |
end generate; |
|
end rtl; |