URL
https://opencores.org/ocsvn/potato/potato/trunk
Subversion Repositories potato
Compare Revisions
- This comparison shows the changes necessary to convert path
/potato/trunk
- from Rev 36 to Rev 45
- ↔ Reverse comparison
Rev 36 → Rev 45
/tests/sw-jal.S
0,0 → 1,41
# The Potato Processor - A simple RISC-V based processor for FPGAs |
# (c) Kristian Klomsten Skordal 2014 - 2015 <kristian.skordal@wafflemail.net> |
# Report bugs and issues on <http://opencores.org/project,potato,bugtracker> |
|
#include "riscv_test.h" |
#include "test_macros.h" |
|
.section .text |
RVTEST_RV32U |
RVTEST_CODE_BEGIN |
|
test_1: |
li TESTNUM, 1 |
|
la ra, test_failed |
la sp, temp |
sw ra, 0(sp) |
jal ra, test_cmp |
|
1: |
j fail |
j pass |
|
test_cmp: |
la t0, 1b |
bne ra, t0, fail |
addi ra, ra, 4 |
ret |
|
TEST_PASSFAIL |
RVTEST_CODE_END |
|
test_failed: |
RVTEST_FAIL |
|
# Allocate a 32-bit word to store some data into |
.section .data |
temp: |
.word 0x00000000 |
|
|
/src/pp_execute.vhd
197,9 → 197,9
jump_target_out <= jump_target; |
|
evec_out <= evec_forwarded; |
exception_taken <= decode_exception or to_std_logic(exception_cause /= CSR_CAUSE_NONE) or irq_asserted; |
exception_taken <= (decode_exception or to_std_logic(exception_cause /= CSR_CAUSE_NONE) or irq_asserted) and not stall; |
|
irq_asserted <= (not stall) and to_std_logic(exception_context_forwarded.status.ei = '1' and |
irq_asserted <= to_std_logic(exception_context_forwarded.status.ei = '1' and |
(irq and exception_context_forwarded.status.im) /= x"00"); |
|
rs1_data <= rs1_data_in; |
/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 |
/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, dmem_if_inputs : wishbone_master_inputs; |
signal icache_outputs, dmem_if_outputs : wishbone_master_outputs; |
|
begin |
processor: entity work.pp_core |
generic map( |
82,22 → 88,54
irq => irq |
); |
|
wb_if: entity work.pp_wb_adapter |
icache: entity work.pp_icache |
generic map( |
LINE_SIZE => 4, |
NUM_LINES => 128 |
) port map( |
clk => clk, |
reset => reset, |
cache_enable => '1', |
cache_flush => '0', |
cached_areas => (others => '1'), |
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 |
); |
|
dmem_if: entity work.pp_wb_adapter |
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_read_ack => dmem_read_ack, |
dmem_write_req => dmem_write_req, |
dmem_read_ack => dmem_read_ack, |
dmem_write_ack => dmem_write_ack, |
wb_inputs => dmem_if_inputs, |
wb_outputs => dmem_if_outputs |
); |
|
arbiter: entity work.pp_wb_arbiter |
port map( |
clk => clk, |
reset => reset, |
--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, |
/src/pp_wb_adapter.vhd
6,6 → 6,9
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( |
12,12 → 15,6
clk : in std_logic; |
reset : in std_logic; |
|
-- Processor instruction memory signals: |
signal imem_address : in std_logic_vector(31 downto 0); |
signal imem_data_out : out std_logic_vector(31 downto 0); |
signal imem_read_req : in std_logic; |
signal imem_read_ack : out 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 |
29,20 → 26,14
signal dmem_write_ack : out std_logic; |
|
-- Wishbone interface: |
wb_adr_out : out std_logic_vector(31 downto 0); |
wb_dat_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_in : in std_logic_vector(31 downto 0); |
wb_ack_in : in std_logic |
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, IREAD_WAIT_ACK); |
type states is (IDLE, READ_WAIT_ACK, WRITE_WAIT_ACK); |
signal state : states; |
|
signal dmem_r_ack : std_logic; |
75,40 → 66,9
end case; |
end function get_data_shift; |
|
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 |
|
imem_read_ack <= '1' when state = IREAD_WAIT_ACK and wb_ack_in = '1' else '0'; |
imem_data_out <= wb_dat_in; |
|
dmem_write_ack <= '1' when state = WRITE_WAIT_ACK and wb_ack_in = '1' else '0'; |
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) |
116,8 → 76,8
if rising_edge(clk) then |
if reset = '1' then |
state <= IDLE; |
wb_cyc_out <= '0'; |
wb_stb_out <= '0'; |
wb_outputs.cyc <= '0'; |
wb_outputs.stb <= '0'; |
dmem_r_ack <= '0'; |
else |
case state is |
126,43 → 86,36
|
-- Prioritize requests from the data memory: |
if dmem_write_req = '1' then |
wb_adr_out <= dmem_address; |
wb_dat_out <= std_logic_vector(shift_left(unsigned(dmem_data_in), |
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_sel_out <= get_data_sel(dmem_data_size, dmem_address); |
wb_cyc_out <= '1'; |
wb_stb_out <= '1'; |
wb_we_out <= '1'; |
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' and dmem_r_ack = '0' then |
wb_adr_out <= dmem_address; |
wb_sel_out <= get_data_sel(dmem_data_size, dmem_address); |
wb_cyc_out <= '1'; |
wb_stb_out <= '1'; |
wb_we_out <= '0'; |
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; |
elsif imem_read_req = '1' then |
wb_adr_out <= imem_address; |
wb_sel_out <= (others => '1'); |
wb_cyc_out <= '1'; |
wb_stb_out <= '1'; |
wb_we_out <= '0'; |
state <= IREAD_WAIT_ACK; |
end if; |
when READ_WAIT_ACK => |
if wb_ack_in = '1' then |
dmem_data_out <= std_logic_vector(shift_right(unsigned(wb_dat_in), |
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_cyc_out <= '0'; |
wb_stb_out <= '0'; |
wb_outputs.cyc <= '0'; |
wb_outputs.stb <= '0'; |
dmem_r_ack <= '1'; |
state <= IDLE; |
end if; |
when WRITE_WAIT_ACK | IREAD_WAIT_ACK => |
if wb_ack_in = '1' then |
wb_cyc_out <= '0'; |
wb_stb_out <= '0'; |
wb_we_out <= '0'; |
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; |
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,44
Index: src/pp_memory.vhd
===================================================================
--- src/pp_memory.vhd (revision 36)
+++ src/pp_memory.vhd (revision 45)
@@ -110,7 +110,7 @@
if exception_in = '1' then
exception_context_out.status <= (
pim => exception_context_in.status.im,
- im => exception_context_in.status.im,
+ im => (others => '0'),
pei => exception_context_in.status.ei,
ei => '0'
);
Index: src/pp_utilities.vhd
===================================================================
--- src/pp_utilities.vhd (revision 36)
+++ src/pp_utilities.vhd (revision 45)
@@ -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;
/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; |
/src/pp_wb_arbiter.vhd
0,0 → 1,100
-- 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 |
state <= IDLE; |
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; |
/src/pp_csr_unit.vhd
130,14 → 130,16
end if; |
end process write; |
|
status_out <= exception_context.status when exception_context_write = '1' else status_register; |
|
read: process(clk) |
begin |
if rising_edge(clk) then |
if exception_context_write = '1' then |
status_out <= exception_context.status; |
else |
status_out <= status_register; |
end if; |
--if exception_context_write = '1' then |
-- status_out <= exception_context.status; |
--else |
-- status_out <= status_register; |
--end if; |
|
if write_mode /= CSR_WRITE_NONE and write_address = CSR_EVEC then |
evec_out <= write_data_in; |
/src/pp_fetch.vhd
40,23 → 40,17
end entity pp_fetch; |
|
architecture behaviour of pp_fetch is |
--signal pc, pc_next : std_logic_vector(31 downto 0); |
--signal acknowledge, ready : std_logic; |
|
signal pc : std_logic_vector(31 downto 0); |
signal pc_next : std_logic_vector(31 downto 0); |
|
signal pc : std_logic_vector(31 downto 0); |
signal pc_next : std_logic_vector(31 downto 0); |
signal cancel_fetch : std_logic; |
begin |
|
imem_address <= pc_next; |
imem_address <= pc_next when cancel_fetch = '0' else pc; |
|
instruction_data <= imem_data_in; |
instruction_ready <= imem_ack and (not stall) and (not cancel_fetch); |
instruction_address <= pc; |
|
--imem_req <= '1' when cancel_fetch = '0' and |
|
imem_req <= '1'; |
|
set_pc: process(clk) |
81,9 → 75,7
|
calc_next_pc: process(reset, stall, branch, exception, imem_ack, branch_target, evec, pc, cancel_fetch) |
begin |
if reset = '1' then |
pc_next <= RESET_ADDRESS; |
elsif exception = '1' then |
if exception = '1' then |
pc_next <= evec; |
elsif branch = '1' then |
pc_next <= branch_target; |
/example/toplevel.vhd
209,8 → 209,8
uart1: entity work.pp_soc_uart |
generic map( |
FIFO_DEPTH => 64, |
--SAMPLE_CLK_DIVISOR => 27 -- For 50 MHz |
SAMPLE_CLK_DIVISOR => 33 -- For 60 MHz |
SAMPLE_CLK_DIVISOR => 27 -- For 50 MHz |
--SAMPLE_CLK_DIVISOR => 33 -- For 60 MHz |
) port map( |
clk => system_clk, |
reset => reset, |
301,7 → 301,7
else |
case ad_state is |
when IDLE => |
if p_cyc_out = '1' and p_stb_out = '1' then |
if p_cyc_out = '1' then |
if p_adr_out(31 downto 13) = b"0000000000000000000" then |
active_module <= MODULE_IMEM; |
ad_state <= BUSY; |
324,6 → 324,8
active_module <= MODULE_DUMMY; |
ad_state <= BUSY; |
end if; |
else |
active_module <= MODULE_NONE; |
end if; |
when BUSY => |
if p_cyc_out = '0' then |
/Makefile
8,6 → 8,7
src/pp_alu.vhd \ |
src/pp_alu_mux.vhd \ |
src/pp_alu_control_unit.vhd \ |
src/pp_icache.vhd \ |
src/pp_comparator.vhd \ |
src/pp_constants.vhd \ |
src/pp_control_unit.vhd \ |
25,6 → 26,7
src/pp_register_file.vhd \ |
src/pp_types.vhd \ |
src/pp_utilities.vhd \ |
src/pp_wb_arbiter.vhd \ |
src/pp_wb_adapter.vhd \ |
src/pp_writeback.vhd |
TESTBENCHES := \ |
76,7 → 78,8
# Local tests to run: |
LOCAL_TESTS ?= \ |
scall \ |
sbreak |
sbreak \ |
sw-jal |
|
all: potato.prj run-tests |
|
95,7 → 98,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 |
/benchmarks/hello/main.c
0,0 → 1,26
// The Potato Processor Benchmark Applications |
// (c) Kristian Klomsten Skordal 2015 <kristian.skordal@wafflemail.net> |
// Report bugs and issues on <http://opencores.org/project,potato,bugtracker> |
|
#include <stdint.h> |
#include "../platform.h" |
|
void exception_handler(uint32_t cause, void * epc, void * regbase) |
{ |
// Not used in this application |
} |
|
int main(void) |
{ |
const char * hello_string = "Hello world\n\r"; |
volatile uint32_t * uart = IO_ADDRESS(UART_BASE); |
|
for(int i = 0; hello_string[i] != 0; ++i) |
{ |
while(uart[UART_STATUS >> 2] & (1 << 3)); |
uart[UART_TX >> 2] = hello_string[i] & 0x000000ff; |
} |
|
return 0; |
} |
|
/benchmarks/hello/Makefile
0,0 → 1,46
# The Potato Processor Benchmark Applications |
# (c) Kristian Klomsten Skordal 2015 <kristian.skordal@wafflemail.net> |
# Report bugs and issues on <http://opencores.org/project,potato,bugtracker> |
|
.PHONY: all clean |
|
TARGET_PREFIX ?= riscv64-unknown-elf |
TARGET_CC := $(TARGET_PREFIX)-gcc |
TARGET_LD := $(TARGET_PREFIX)-ld |
TARGET_SIZE := $(TARGET_PREFIX)-size |
TARGET_OBJCOPY := $(TARGET_PREFIX)-objcopy |
HEXDUMP ?= hexdump |
|
TARGET_CFLAGS += -m32 -march=RV32I -Wall -O2 -fomit-frame-pointer \ |
-ffreestanding -fno-builtin -I.. -std=gnu99 |
TARGET_LDFLAGS += -m elf32lriscv -T../benchmark.ld |
|
OBJECTS := main.o start.o |
|
all: hello.coe |
|
hello.elf: $(OBJECTS) |
$(TARGET_LD) -o hello.elf $(TARGET_LDFLAGS) $(OBJECTS) |
$(TARGET_SIZE) hello.elf |
|
hello.bin: hello.elf |
$(TARGET_OBJCOPY) -j .text -j .data -O binary hello.elf hello.bin |
|
hello.coe: hello.bin |
echo "memory_initialization_radix=16;" > hello.coe |
echo "memory_initialization_vector=" >> hello.coe |
$(HEXDUMP) -v -e '1/4 "%08x\n"' hello.bin >> hello.coe |
echo ";" >> hello.coe |
|
clean: |
-$(RM) $(OBJECTS) |
-$(RM) hello.elf hello.bin hello.coe |
|
# Object file rules: |
|
main.o: main.c ../platform.h ../potato.h |
$(TARGET_CC) -c -o $@ $(TARGET_CFLAGS) $< |
|
start.o: ../start.S ../platform.h |
$(TARGET_CC) -c -o $@ $(TARGET_CFLAGS) $< |
|
/benchmarks/platform.h
9,7 → 9,7
#define PLATFORM_H |
|
// Clock frequency in Hz: |
#define SYSTEM_CLK_FREQ 60000000 |
#define SYSTEM_CLK_FREQ 50000000 |
|
// Macro for using the addresses below in C code: |
#define IO_ADDRESS(x) ((volatile void *) x) |
/benchmarks/potato.h
52,6 → 52,13
#define potato_disable_interrupts() asm volatile("csrci %[status], 1 << %[ei_bit] | 1 << %[pei_bit]\n" \ |
:: [status] "i" (CSR_STATUS), [ei_bit] "i" (STATUS_EI), [pei_bit] "i" (STATUS_PEI)) |
|
#define potato_write_host(data) \ |
do { \ |
register uint32_t temp = data; \ |
asm volatile("csrw %[tohost], %[temp]\n" \ |
:: [tohost] "i" (CSR_TOHOST), [temp] "r" (temp)); \ |
} while(0); |
|
#define potato_enable_irq(n) \ |
do { \ |
register uint32_t temp = 0; \ |
.
Property changes :
Modified: svn:mergeinfo
## -0,0 +0,1 ##
Merged /potato/branches/cache-playground:r23-30,34-44