URL
https://opencores.org/ocsvn/potato/potato/trunk
Subversion Repositories potato
Compare Revisions
- This comparison shows the changes necessary to convert path
/potato/branches
- from Rev 23 to Rev 25
- ↔ Reverse comparison
Rev 23 → Rev 25
/cache-playground/src/pp_wb_adapter.vhd
File deleted
/cache-playground/src/pp_cache.vhd
0,0 → 1,185
-- The Potato Processor - A simple processor for FPGAs |
-- (c) Kristian Klomsten Skordal 2014 - 2015 <kristian.skordal@wafflemail.net> |
-- Report bugs and issues on <http://opencores.org/project,potato,bugtracker> |
|
library ieee; |
use ieee.std_logic_1164.all; |
use ieee.numeric_std.all; |
|
use work.pp_types.all; |
use work.pp_utilities.all; |
|
--! @brief Simple cache module. |
entity pp_cache is |
generic( |
LINE_SIZE : natural := 8; --! Number of words per cache way |
NUM_WAYS : natural := 2; --! Number of ways per set |
NUM_SETS : natural := 128 --! Number of sets in the cache |
); |
port( |
clk : in std_logic; |
reset : in std_logic; |
|
-- Control interface: |
cache_enable : in std_logic; |
cache_flush : in std_logic; |
cached_areas : in std_logic_vector(31 downto 0); |
|
-- Memory interface: |
mem_address_in : in std_logic_vector(31 downto 0); |
mem_data_in : in std_logic_vector(31 downto 0); |
mem_data_out : out std_logic_vector(31 downto 0); |
mem_data_size : in std_logic_vector( 1 downto 0); |
mem_read_req : in std_logic; |
mem_read_ack : out std_logic; |
mem_write_req : in std_logic; |
mem_write_ack : out std_logic; |
|
-- Wishbone interface: |
wb_inputs : in wishbone_master_inputs; |
wb_outputs : out wishbone_master_outputs |
); |
end entity pp_cache; |
|
architecture behaviour of pp_cache is |
|
-- Input-related signals: |
signal input_address_set : std_logic_vector(log2(NUM_SETS) - 1 downto 0); |
signal input_address_word : std_logic_vector(log2(LINE_SIZE / 4) - 1 downto 0); |
signal input_address_tag : std_logic_vector(31 - log2(NUM_SETS) - log2(LINE_SIZE / 4) downto 0); |
signal input_address_cached : boolean; |
|
-- Cache controller signals: |
type state_type is (IDLE, SINGLE_READ, SINGLE_WRITE); |
signal state : state_type := IDLE; |
|
-- Gets the amount to shift output data to the processor with for requests of size != 32 bits: |
function get_data_shift(size : in std_logic_vector(1 downto 0); address : in std_logic_vector) |
return natural is |
begin |
case size is |
when b"01" => |
case address(1 downto 0) is |
when b"00" => |
return 0; |
when b"01" => |
return 8; |
when b"10" => |
return 16; |
when b"11" => |
return 24; |
when others => |
return 0; |
end case; |
when b"10" => |
if address(1) = '0' then |
return 0; |
else |
return 16; |
end if; |
when others => |
return 0; |
end case; |
end function get_data_shift; |
|
-- Gets the value of the sel signals to the wishbone interconnect for the specified |
-- operand size and address. |
function get_data_sel(size : in std_logic_vector(1 downto 0); address : in std_logic_vector) |
return std_logic_vector is |
begin |
case size is |
when b"01" => |
case address(1 downto 0) is |
when b"00" => |
return b"0001"; |
when b"01" => |
return b"0010"; |
when b"10" => |
return b"0100"; |
when b"11" => |
return b"1000"; |
when others => |
return b"0001"; |
end case; |
when b"10" => |
if address(1) = '0' then |
return b"0011"; |
else |
return b"1100"; |
end if; |
when others => |
return b"1111"; |
end case; |
end function get_data_sel; |
|
begin |
|
-- Decompose the input address: |
input_address_word <= mem_address_in(log2(LINE_SIZE / 4) - 1 downto 0); |
input_address_set <= mem_address_in(log2(NUM_SETS) + log2(LINE_SIZE / 4) - 1 downto log2(LINE_SIZE / 4)); |
input_address_tag <= mem_address_in(31 downto log2(NUM_SETS) + log2(LINE_SIZE / 4)); |
|
-- Check if the current input address should be/is in the cache: |
input_address_cached <= cached_areas(to_integer(unsigned(mem_address_in(31 downto 27)))) = '1'; |
|
-- Acknowledge signals: |
mem_write_ack <= '1' when state = SINGLE_WRITE and wb_inputs.ack = '1' else '0'; |
|
controller: process(clk) |
begin |
if rising_edge(clk) then |
if reset = '1' then |
state <= IDLE; |
wb_outputs.cyc <= '0'; |
wb_outputs.stb <= '0'; |
mem_read_ack <= '0'; |
else |
case state is |
when IDLE => |
mem_read_ack <= '0'; |
|
--if input_address_cached and cache_enable = '1' then |
-- if mem_read_req = '1' then |
-- elsif mem_write_req = '1' then |
-- end if; |
--else |
if mem_read_req = '1' then -- Do an uncached read |
wb_outputs.adr <= mem_address_in; |
wb_outputs.sel <= get_data_sel(mem_data_size, mem_address_in); |
wb_outputs.cyc <= '1'; |
wb_outputs.stb <= '1'; |
wb_outputs.we <= '0'; |
state <= SINGLE_READ; |
elsif mem_write_req = '1' then -- Do an uncached write |
wb_outputs.adr <= mem_address_in; |
wb_outputs.dat <= std_logic_vector(shift_left(unsigned(mem_data_in), |
get_data_shift(mem_data_size, mem_address_in))); |
wb_outputs.sel <= get_data_sel(mem_data_size, mem_address_in); |
wb_outputs.cyc <= '1'; |
wb_outputs.stb <= '1'; |
wb_outputs.we <= '1'; |
state <= SINGLE_WRITE; |
end if; |
--end if; |
when SINGLE_READ => |
if wb_inputs.ack = '1' then |
mem_data_out <= std_logic_vector(shift_right(unsigned(wb_inputs.dat), |
get_data_shift(mem_data_size, mem_address_in))); |
wb_outputs.cyc <= '0'; |
wb_outputs.stb <= '0'; |
mem_read_ack <= '1'; |
state <= IDLE; |
end if; |
when SINGLE_WRITE => |
if wb_inputs.ack = '1' then |
wb_outputs.cyc <= '0'; |
wb_outputs.stb <= '0'; |
wb_outputs.we <= '0'; |
state <= IDLE; |
end if; |
end case; |
end if; |
end if; |
end process controller; |
|
end architecture behaviour; |
/cache-playground/src/pp_types.vhd
42,6 → 42,22
MEMOP_SIZE_BYTE, MEMOP_SIZE_HALFWORD, MEMOP_SIZE_WORD |
); |
|
--! Wishbone master output signals: |
type wishbone_master_outputs is record |
adr : std_logic_vector(31 downto 0); |
sel : std_logic_vector( 3 downto 0); |
cyc : std_logic; |
stb : std_logic; |
we : std_logic; |
dat : std_logic_vector(31 downto 0); |
end record; |
|
--! Wishbone master input signals: |
type wishbone_master_inputs is record |
dat : std_logic_vector(31 downto 0); |
ack : std_logic; |
end record; |
|
end package pp_types; |
|
package body pp_types is |
/cache-playground/src/pp_potato.vhd
5,6 → 5,8
library ieee; |
use ieee.std_logic_1164.all; |
|
use work.pp_types.all; |
|
--! @brief The Potato Processor. |
--! This file provides a Wishbone-compatible interface to the Potato processor. |
entity pp_potato is |
54,6 → 56,10
signal dmem_write_req : std_logic; |
signal dmem_write_ack : std_logic; |
|
-- Wishbone signals: |
signal icache_inputs, dcache_inputs : wishbone_master_inputs; |
signal icache_outputs, dcache_outputs : wishbone_master_outputs; |
|
begin |
processor: entity work.pp_core |
generic map( |
82,22 → 88,52
irq => irq |
); |
|
wb_if: entity work.pp_wb_adapter |
icache: entity work.pp_cache |
port map( |
clk => clk, |
reset => reset, |
imem_address => imem_address, |
imem_data_out => imem_data, |
imem_read_req => imem_req, |
imem_read_ack => imem_ack, |
dmem_address => dmem_address, |
dmem_data_in => dmem_data_out, |
dmem_data_out => dmem_data_in, |
dmem_data_size => dmem_data_size, |
dmem_read_req => dmem_read_req, |
dmem_write_req => dmem_write_req, |
dmem_read_ack => dmem_read_ack, |
dmem_write_ack => dmem_write_ack, |
cache_enable => '0', |
cache_flush => '0', |
cached_areas => (others => '0'), |
mem_address_in => imem_address, |
mem_data_out => imem_data, |
mem_data_in => (others => '0'), |
mem_data_size => b"00", |
mem_read_req => imem_req, |
mem_read_ack => imem_ack, |
mem_write_req => '0', |
mem_write_ack => open, |
wb_inputs => icache_inputs, |
wb_outputs => icache_outputs |
); |
|
dcache: entity work.pp_cache |
port map( |
clk => clk, |
reset => reset, |
cache_enable => '0', |
cache_flush => '0', |
cached_areas => (others => '0'), |
mem_address_in => dmem_address, |
mem_data_in => dmem_data_out, |
mem_data_out => dmem_data_in, |
mem_data_size => dmem_data_size, |
mem_read_req => dmem_read_req, |
mem_read_ack => dmem_read_ack, |
mem_write_req => dmem_write_req, |
mem_write_ack => dmem_write_ack, |
wb_inputs => dcache_inputs, |
wb_outputs => dcache_outputs |
); |
|
arbiter: entity work.pp_wb_arbiter |
port map( |
clk => clk, |
reset => reset, |
m1_inputs => dcache_inputs, |
m1_outputs => dcache_outputs, |
m2_inputs => icache_inputs, |
m2_outputs => icache_outputs, |
wb_adr_out => wb_adr_out, |
wb_sel_out => wb_sel_out, |
wb_cyc_out => wb_cyc_out, |
/cache-playground/src/pp_wb_arbiter.vhd
0,0 → 1,99
-- The Potato Processor - A simple processor for FPGAs |
-- (c) Kristian Klomsten Skordal 2014 - 2015 <kristian.skordal@wafflemail.net> |
-- Report bugs and issues on <http://opencores.org/project,potato,bugtracker> |
|
library ieee; |
use ieee.std_logic_1164.all; |
|
use work.pp_types.all; |
|
--! @brief Simple priority-based wishbone arbiter. |
--! This module is used as an arbiter between the instruction and data caches. |
entity pp_wb_arbiter is |
port( |
clk : in std_logic; |
reset : in std_logic; |
|
-- Wishbone input 1: |
m1_inputs : out wishbone_master_inputs; |
m1_outputs : in wishbone_master_outputs; |
|
-- Wishbone input 2: |
m2_inputs : out wishbone_master_inputs; |
m2_outputs : in wishbone_master_outputs; |
|
-- Wishbone interface: |
wb_adr_out : out std_logic_vector(31 downto 0); |
wb_sel_out : out std_logic_vector( 3 downto 0); |
wb_cyc_out : out std_logic; |
wb_stb_out : out std_logic; |
wb_we_out : out std_logic; |
wb_dat_out : out std_logic_vector(31 downto 0); |
wb_dat_in : in std_logic_vector(31 downto 0); |
wb_ack_in : in std_logic |
); |
end entity pp_wb_arbiter; |
|
architecture behaviour of pp_wb_arbiter is |
|
type state_type is (IDLE, M1_BUSY, M2_BUSY); |
signal state : state_type := IDLE; |
|
begin |
|
m1_inputs <= (ack => wb_ack_in, dat => wb_dat_in) when state = M1_BUSY else (ack => '0', dat => (others => '0')); |
m2_inputs <= (ack => wb_ack_in, dat => wb_dat_in) when state = M2_BUSY else (ack => '0', dat => (others => '0')); |
|
output_mux: process(state, m1_outputs, m2_outputs) |
begin |
case state is |
when IDLE => |
wb_adr_out <= (others => '0'); |
wb_sel_out <= (others => '0'); |
wb_dat_out <= (others => '0'); |
wb_cyc_out <= '0'; |
wb_stb_out <= '0'; |
wb_we_out <= '0'; |
when M1_BUSY => |
wb_adr_out <= m1_outputs.adr; |
wb_sel_out <= m1_outputs.sel; |
wb_dat_out <= m1_outputs.dat; |
wb_cyc_out <= m1_outputs.cyc; |
wb_stb_out <= m1_outputs.stb; |
wb_we_out <= m1_outputs.we; |
when M2_BUSY => |
wb_adr_out <= m2_outputs.adr; |
wb_sel_out <= m2_outputs.sel; |
wb_dat_out <= m2_outputs.dat; |
wb_cyc_out <= m2_outputs.cyc; |
wb_stb_out <= m2_outputs.stb; |
wb_we_out <= m2_outputs.we; |
end case; |
end process output_mux; |
|
controller: process(clk) |
begin |
if rising_edge(clk) then |
if reset = '1' then |
else |
case state is |
when IDLE => |
if m1_outputs.cyc = '1' then |
state <= M1_BUSY; |
elsif m2_outputs.cyc = '1' then |
state <= M2_BUSY; |
end if; |
when M1_BUSY => |
if m1_outputs.cyc = '0' then |
state <= IDLE; |
end if; |
when M2_BUSY => |
if m2_outputs.cyc = '0' then |
state <= IDLE; |
end if; |
end case; |
end if; |
end if; |
end process controller; |
|
end architecture behaviour; |
/cache-playground/Makefile
8,6 → 8,7
src/pp_alu.vhd \ |
src/pp_alu_mux.vhd \ |
src/pp_alu_control_unit.vhd \ |
src/pp_cache.vhd \ |
src/pp_comparator.vhd \ |
src/pp_constants.vhd \ |
src/pp_control_unit.vhd \ |
25,7 → 26,7
src/pp_register_file.vhd \ |
src/pp_types.vhd \ |
src/pp_utilities.vhd \ |
src/pp_wb_adapter.vhd \ |
src/pp_wb_arbiter.vhd \ |
src/pp_writeback.vhd |
TESTBENCHES := \ |
testbenches/tb_processor.vhd \ |
95,7 → 96,7
test -d tests-build || mkdir tests-build |
for test in $(RISCV_TESTS) $(LOCAL_TESTS); do \ |
echo "Compiling test $$test..."; \ |
$(TOOLCHAIN_PREFIX)-gcc -c -m32 -Iriscv-tests -o tests-build/$$test.o tests/$$test.S; \ |
$(TOOLCHAIN_PREFIX)-gcc -c -m32 -march=RV32I -Iriscv-tests -o tests-build/$$test.o tests/$$test.S; \ |
$(TOOLCHAIN_PREFIX)-ld -m elf32lriscv -T tests.ld tests-build/$$test.o -o tests-build/$$test.elf; \ |
scripts/extract_hex.sh tests-build/$$test.elf tests-build/$$test-imem.hex tests-build/$$test-dmem.hex; \ |
done |