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 43 to Rev 44
- ↔ Reverse comparison
Rev 43 → Rev 44
/cache-playground/src/pp_cache.vhd
File deleted
/cache-playground/src/pp_potato.vhd
57,8 → 57,8
signal dmem_write_ack : std_logic; |
|
-- Wishbone signals: |
signal icache_inputs, dcache_inputs : wishbone_master_inputs; |
signal icache_outputs, dcache_outputs : wishbone_master_outputs; |
signal icache_inputs, dmem_if_inputs : wishbone_master_inputs; |
signal icache_outputs, dmem_if_outputs : wishbone_master_outputs; |
|
begin |
processor: entity work.pp_core |
88,13 → 88,16
irq => irq |
); |
|
icache: entity work.pp_cache |
port map( |
icache: entity work.pp_icache |
generic map( |
LINE_SIZE => 4, |
NUM_LINES => 128 |
) port map( |
clk => clk, |
reset => reset, |
cache_enable => '0', |
cache_enable => '1', |
cache_flush => '0', |
cached_areas => (others => '0'), |
cached_areas => (others => '1'), |
mem_address_in => imem_address, |
mem_data_out => imem_data, |
mem_data_in => (others => '0'), |
107,23 → 110,20
wb_outputs => icache_outputs |
); |
|
dcache: entity work.pp_cache |
dmem_if: entity work.pp_wb_adapter |
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 |
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_read_ack => dmem_read_ack, |
dmem_write_req => dmem_write_req, |
dmem_write_ack => dmem_write_ack, |
wb_inputs => dmem_if_inputs, |
wb_outputs => dmem_if_outputs |
); |
|
arbiter: entity work.pp_wb_arbiter |
130,10 → 130,12
port map( |
clk => clk, |
reset => reset, |
m1_inputs => dcache_inputs, |
m1_outputs => dcache_outputs, |
m2_inputs => icache_inputs, |
m2_outputs => icache_outputs, |
--m1_inputs => dmem_if_inputs, |
--m1_outputs => dmem_if_outputs, |
m1_inputs => icache_inputs, |
m1_outputs => icache_outputs, |
m2_inputs => dmem_if_inputs, |
m2_outputs => dmem_if_outputs, |
wb_adr_out => wb_adr_out, |
wb_sel_out => wb_sel_out, |
wb_cyc_out => wb_cyc_out, |
/cache-playground/src/pp_wb_adapter.vhd
0,0 → 1,126
-- 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 Wishbone adapter, for connecting the processor to a Wishbone bus when not using caches. |
entity pp_wb_adapter is |
port( |
clk : in std_logic; |
reset : in std_logic; |
|
-- Processor data memory signals: |
signal dmem_address : in std_logic_vector(31 downto 0); |
signal dmem_data_in : in std_logic_vector(31 downto 0); -- Data in to the bus |
signal dmem_data_out : out std_logic_vector(31 downto 0); -- Data out to the bus |
signal dmem_data_size : in std_logic_vector( 1 downto 0); |
signal dmem_read_req : in std_logic; |
signal dmem_read_ack : out std_logic; |
signal dmem_write_req : in std_logic; |
signal dmem_write_ack : out std_logic; |
|
-- Wishbone interface: |
wb_inputs : in wishbone_master_inputs; |
wb_outputs : out wishbone_master_outputs |
); |
end entity pp_wb_adapter; |
|
architecture behaviour of pp_wb_adapter is |
|
type states is (IDLE, READ_WAIT_ACK, WRITE_WAIT_ACK); |
signal state : states; |
|
signal dmem_r_ack : std_logic; |
|
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; |
|
begin |
|
dmem_write_ack <= '1' when state = WRITE_WAIT_ACK and wb_inputs.ack = '1' else '0'; |
dmem_read_ack <= dmem_r_ack; |
|
wishbone: process(clk) |
begin |
if rising_edge(clk) then |
if reset = '1' then |
state <= IDLE; |
wb_outputs.cyc <= '0'; |
wb_outputs.stb <= '0'; |
dmem_r_ack <= '0'; |
else |
case state is |
when IDLE => |
dmem_r_ack <= '0'; |
|
-- Prioritize requests from the data memory: |
if dmem_write_req = '1' then |
wb_outputs.adr <= dmem_address; |
wb_outputs.dat <= std_logic_vector(shift_left(unsigned(dmem_data_in), |
get_data_shift(dmem_data_size, dmem_address))); |
wb_outputs.sel <= wb_get_data_sel(dmem_data_size, dmem_address); |
wb_outputs.cyc <= '1'; |
wb_outputs.stb <= '1'; |
wb_outputs.we <= '1'; |
state <= WRITE_WAIT_ACK; |
elsif dmem_read_req = '1' then |
wb_outputs.adr <= dmem_address; |
wb_outputs.sel <= wb_get_data_sel(dmem_data_size, dmem_address); |
wb_outputs.cyc <= '1'; |
wb_outputs.stb <= '1'; |
wb_outputs.we <= '0'; |
state <= READ_WAIT_ACK; |
end if; |
when READ_WAIT_ACK => |
if wb_inputs.ack = '1' then |
dmem_data_out <= std_logic_vector(shift_right(unsigned(wb_inputs.dat), |
get_data_shift(dmem_data_size, dmem_address))); |
wb_outputs.cyc <= '0'; |
wb_outputs.stb <= '0'; |
dmem_r_ack <= '1'; |
state <= IDLE; |
end if; |
when WRITE_WAIT_ACK => |
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 wishbone; |
|
end architecture behaviour; |
cache-playground/src/pp_wb_adapter.vhd
Property changes :
Added: svn:mergeinfo
## -0,0 +0,1 ##
Merged /potato/branches/cache-playground/src/pp_wb_adapter.vhd:r31-33
Index: cache-playground/src/pp_utilities.vhd
===================================================================
--- cache-playground/src/pp_utilities.vhd (revision 43)
+++ cache-playground/src/pp_utilities.vhd (revision 44)
@@ -19,6 +19,11 @@
--! Calculates log2 with integers.
function log2(input : in natural) return natural;
+ -- Gets the value of the sel signals to the wishbone interconnect for the specified
+ -- operand size and address.
+ function wb_get_data_sel(size : in std_logic_vector(1 downto 0); address : in std_logic_vector)
+ return std_logic_vector;
+
end package pp_utilities;
package body pp_utilities is
@@ -35,7 +40,7 @@
function is_pow2(input : in natural) return boolean is
variable c : natural := 1;
begin
- for i in 0 to 31 loop
+ for i in 0 to 30 loop -- FIXME: Simulator complains about 2^31 being out of range!
if input = i then
return true;
end if;
@@ -58,4 +63,32 @@
return retval;
end function log2;
+ function wb_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 wb_get_data_sel;
+
end package body pp_utilities;
/cache-playground/src/pp_icache.vhd
0,0 → 1,293
-- 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 read-only direct-mapped instruction cache. |
entity pp_icache is |
generic( |
LINE_SIZE : natural := 4; --! Number of words per cache line |
NUM_LINES : natural := 128 --! Number of lines 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_icache; |
|
architecture behaviour of pp_icache is |
|
-- Counter types: |
subtype line_counter_type is natural range 0 to NUM_LINES; |
subtype word_counter_type is natural range 0 to LINE_SIZE; |
|
-- Cache line types: |
subtype cache_line_type is std_logic_vector((LINE_SIZE * 32) - 1 downto 0); |
type cache_line_word_array is array(0 to LINE_SIZE - 1) of std_logic_vector(31 downto 0); |
type cache_line_array is array(0 to NUM_LINES - 1) of cache_line_type; |
|
-- Cache tag type: |
subtype cache_tag_type is std_logic_vector(31 - log2(LINE_SIZE * 4) - log2(NUM_LINES) downto 0); |
type cache_tag_array is array(0 to NUM_LINES - 1) of cache_tag_type; |
|
-- Cache memories: |
signal cache_memory : cache_line_array; |
signal tag_memory : cache_tag_array; |
signal valid : std_logic_vector(NUM_LINES - 1 downto 0) := (others => '0'); |
|
attribute ram_style : string; |
attribute ram_style of cache_memory: signal is "block"; |
--attribute ram_style of tag_memory: signal is "block"; |
|
-- Cache controller signals: |
type state_type is (IDLE, CACHE_READ_STALL, SINGLE_READ, SINGLE_WRITE, |
LOAD_CACHELINE_START, LOAD_CACHELINE_WAIT_ACK, LOAD_CACHELINE_FINISH); |
signal state : state_type := IDLE; |
|
-- Is the current input address in the cache? |
signal input_address_cached : boolean; |
|
-- Input address components: |
signal input_address_line : std_logic_vector(log2(NUM_LINES) - 1 downto 0); |
signal input_address_word : std_logic_vector(log2(LINE_SIZE) - 1 downto 0); |
signal input_address_tag : std_logic_vector(31 - log2(LINE_SIZE * 4) - log2(NUM_LINES) downto 0); |
|
-- Cacheline matching the current input address: |
signal current_cache_line, cache_lookup : cache_line_type; |
signal current_cache_line_words : cache_line_word_array; |
signal current_tag : cache_tag_type; |
|
-- Base address to store a cacheline to: |
signal cl_store_address : std_logic_vector(31 downto log2(LINE_SIZE * 4)); |
-- Base address to load a cacheline from: |
signal cl_load_address : std_logic_vector(31 downto log2(LINE_SIZE * 4)); |
-- Cache line to load: |
signal cl_current_line : line_counter_type; |
-- Current word being loaded/stored: |
signal cl_current_word : word_counter_type; |
|
-- Buffer for holding a cache line while loading: |
signal load_buffer : cache_line_type; |
signal load_buffer_tag : cache_tag_type; |
|
-- Causes a cache line to be stored in the cache memory: |
signal store_cache_line : std_logic; |
|
-- Set when the current input address matches a cache line: |
signal cache_hit : std_logic; |
|
-- For regular reads: |
signal read_ack : std_logic; |
signal read_data_out : std_logic_vector(31 downto 0); |
|
-- For regular writes: |
signal write_ack : std_logic; |
|
-- 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; |
|
begin |
|
--assert is_pow2(LINE_SIZE) report "Cache line size must be a power of 2!" severity FAILURE; |
--assert is_pow2(NUM_LINES) report "Number of cache lines must be a power of 2!" severity FAILURE; |
|
-- 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'; |
|
mem_data_out <= current_cache_line_words(to_integer(unsigned(input_address_word))) when |
input_address_cached and cache_enable = '1' and cache_flush = '0' |
else read_data_out; |
mem_read_ack <= (cache_hit and mem_read_req) |
when state = IDLE and input_address_cached and cache_enable = '1' and cache_flush = '0' |
else read_ack; |
write_ack <= wb_inputs.ack when state = SINGLE_WRITE else '0'; |
mem_write_ack <= write_ack; |
|
input_address_line <= mem_address_in(log2(LINE_SIZE * 4) + log2(NUM_LINES) - 1 downto log2(LINE_SIZE * 4)); |
input_address_tag <= mem_address_in(31 downto log2(LINE_SIZE * 4) + log2(NUM_LINES)); |
|
find_word: process(clk) |
begin |
if rising_edge(clk) then |
input_address_word <= mem_address_in(log2(LINE_SIZE * 4) - 1 downto 2); |
end if; |
end process find_word; |
|
cacheline_lookup: process(clk) |
begin |
if rising_edge(clk) then |
if store_cache_line = '1' then |
cache_memory(cl_current_line) <= load_buffer; |
end if; |
|
current_cache_line <= cache_memory(to_integer(unsigned(input_address_line))); |
end if; |
end process cacheline_lookup; |
|
decompose_cache_line: for i in 0 to LINE_SIZE - 1 generate |
current_cache_line_words(i) <= current_cache_line(32 * i + 31 downto 32 * i); |
end generate decompose_cache_line; |
|
tag_lookup: process(clk) |
begin |
if rising_edge(clk) then |
if reset = '1' then |
cache_hit <= '0'; |
else |
if store_cache_line = '1' then |
tag_memory(cl_current_line) <= load_buffer_tag; |
end if; |
|
current_tag <= tag_memory(to_integer(unsigned(input_address_line))); |
cache_hit <= valid(to_integer(unsigned(input_address_line))) and to_std_logic(tag_memory(to_integer(unsigned(input_address_line))) = input_address_tag); |
end if; |
end if; |
end process tag_lookup; |
|
controller: process(clk) |
variable current_word : std_logic_vector(31 downto 0); |
begin |
if rising_edge(clk) then |
if reset = '1' then |
state <= IDLE; |
wb_outputs.cyc <= '0'; |
wb_outputs.stb <= '0'; |
store_cache_line <= '0'; |
read_ack <= '0'; |
valid <= (others => '0'); |
read_data_out <= (others => '0'); |
else |
case state is |
when IDLE => |
read_ack <= '0'; |
if cache_flush = '1' then |
valid <= (others => '0'); |
elsif input_address_cached and cache_enable = '1' then |
if (mem_read_req = '1' or mem_write_req = '1') and cache_hit = '0' then |
wb_outputs.adr <= mem_address_in(31 downto log2(LINE_SIZE * 4)) & (log2(LINE_SIZE * 4) - 1 downto 0 => '0'); |
wb_outputs.cyc <= '1'; |
wb_outputs.we <= '0'; |
wb_outputs.sel <= (others => '1'); |
load_buffer_tag <= input_address_tag; |
cl_load_address <= mem_address_in(31 downto log2(LINE_SIZE * 4)); |
cl_store_address <= input_address_tag & input_address_line; |
cl_current_line <= to_integer(unsigned(input_address_line)); |
cl_current_word <= 0; |
state <= LOAD_CACHELINE_START; |
end if; |
else |
if mem_read_req = '1' and read_ack = '0' then -- Do an uncached read |
wb_outputs.adr <= mem_address_in; |
wb_outputs.sel <= wb_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 <= wb_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 CACHE_READ_STALL => |
state <= IDLE; |
when SINGLE_READ => |
if wb_inputs.ack = '1' then |
read_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'; |
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; |
when LOAD_CACHELINE_START => |
wb_outputs.stb <= '1'; |
wb_outputs.we <= '0'; |
wb_outputs.adr <= cl_load_address & std_logic_vector(to_unsigned(cl_current_word, log2(LINE_SIZE))) & b"00"; |
state <= LOAD_CACHELINE_WAIT_ACK; |
when LOAD_CACHELINE_WAIT_ACK => |
if wb_inputs.ack = '1' then |
wb_outputs.stb <= '0'; |
load_buffer(cl_current_word * 32 + 31 downto cl_current_word * 32) <= wb_inputs.dat; |
if natural(cl_current_word) = LINE_SIZE - 1 then |
wb_outputs.cyc <= '0'; |
store_cache_line <= '1'; |
state <= LOAD_CACHELINE_FINISH; |
else |
cl_current_word <= cl_current_word + 1; |
state <= LOAD_CACHELINE_START; |
end if; |
end if; |
when LOAD_CACHELINE_FINISH => |
store_cache_line <= '0'; |
valid(cl_current_line) <= '1'; |
state <= CACHE_READ_STALL; |
end case; |
end if; |
end if; |
end process controller; |
|
end architecture behaviour; |