URL
https://opencores.org/ocsvn/potato/potato/trunk
Subversion Repositories potato
Compare Revisions
- This comparison shows the changes necessary to convert path
/potato
- from Rev 1 to Rev 2
- ↔ Reverse comparison
Rev 1 → Rev 2
/trunk/tests.ld
0,0 → 1,38
/* |
* Linker Script for the Potato Processor test applications. |
* (c) Kristian Klomsten Skordal 2014 - 2015 <kristian.skordal@wafflemail.net> |
* Report bugs and issues on <https://github.com/skordal/potato/issues> |
*/ |
|
/* |
* The linker script assumes that default testbench settings are used, that is, |
* 2048 bytes (each) of separate instruction and data memory. |
*/ |
|
ENTRY(_start); |
|
SECTIONS |
{ |
.text 0x0 : |
{ |
*(.init*) |
*(.text*) |
} |
|
.data 0x800 : |
{ |
__data_begin = .; |
*(.data*) |
} |
|
.bss : |
{ |
__bss_begin = .; |
*(.bss*) |
__bss_end = .; |
} |
__data_end = .; |
|
__stack_top = 0x1000; |
} |
|
/trunk/tests/scall.S
0,0 → 1,39
# 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 <https://github.com/skordal/potato/issues> |
|
#include "riscv_test.h" |
#include "test_macros.h" |
|
.section .text |
RVTEST_RV32U |
RVTEST_CODE_BEGIN |
|
test_1: |
la x1, handle_exception |
csrw evec, x1 |
|
li TESTNUM, 1 |
scall |
|
j fail |
j pass |
|
TEST_PASSFAIL |
|
RVTEST_CODE_END |
|
test_failed: |
RVTEST_FAIL |
|
# Exception handlers: |
handle_exception: |
li x1, 6 # Cause value for syscall exceptions |
csrr x2, cause |
bne x1, x2, test_failed |
|
csrr x1, epc |
addi x1, x1, 8 |
csrw epc, x1 |
sret |
|
/trunk/tests/sbreak.S
0,0 → 1,39
# 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 <https://github.com/skordal/potato/issues> |
|
#include "riscv_test.h" |
#include "test_macros.h" |
|
.section .text |
RVTEST_RV32U |
RVTEST_CODE_BEGIN |
|
test_1: |
la x1, handle_exception |
csrw evec, x1 |
|
li TESTNUM, 1 |
sbreak |
|
j fail |
j pass |
|
TEST_PASSFAIL |
|
RVTEST_CODE_END |
|
test_failed: |
RVTEST_FAIL |
|
# Exception handlers: |
handle_exception: |
li x1, 7 # Cause value for breakpoint exceptions |
csrr x2, cause |
bne x1, x2, test_failed |
|
csrr x1, epc |
addi x1, x1, 8 |
csrw epc, x1 |
sret |
|
/trunk/empty_dmem.hex
0,0 → 1,39
00000000 |
/trunk/soc/pp_soc_memory.vhd
0,0 → 1,88
-- The Potato Processor - A simple processor for FPGAs |
-- (c) Kristian Klomsten Skordal 2014 - 2015 <kristian.skordal@wafflemail.net> |
-- Report bugs and issues on <https://github.com/skordal/potato/issues> |
|
library ieee; |
use ieee.std_logic_1164.all; |
use ieee.numeric_std.all; |
use ieee.std_logic_textio.all; |
use std.textio.all; |
|
use work.pp_utilities.all; |
|
--! @brief Simple memory module for use in Wishbone-based systems. |
entity pp_soc_memory is |
generic( |
MEMORY_SIZE : natural := 4096 --! Memory size in bytes. |
); |
port( |
clk : in std_logic; |
reset : in std_logic; |
|
-- Wishbone interface: |
wb_adr_in : in std_logic_vector(log2(MEMORY_SIZE) - 1 downto 0); |
wb_dat_in : in std_logic_vector(31 downto 0); |
wb_dat_out : out std_logic_vector(31 downto 0); |
wb_cyc_in : in std_logic; |
wb_stb_in : in std_logic; |
wb_sel_in : in std_logic_vector( 3 downto 0); |
wb_we_in : in std_logic; |
wb_ack_out : out std_logic |
); |
end entity pp_soc_memory; |
|
architecture behaviour of pp_soc_memory is |
type memory_array is array(0 to (MEMORY_SIZE / 4) - 1) of std_logic_vector(31 downto 0); |
signal memory : memory_array := (others => (others => '0')); |
|
attribute ram_style : string; |
attribute ram_style of memory : signal is "block"; |
|
type state_type is (IDLE, ACK); |
signal state : state_type; |
|
signal read_ack : std_logic; |
|
begin |
|
wb_ack_out <= read_ack and wb_stb_in; |
|
process(clk) |
begin |
if rising_edge(clk) then |
if reset = '1' then |
read_ack <= '0'; |
state <= IDLE; |
else |
if wb_cyc_in = '1' then |
case state is |
when IDLE => |
if wb_stb_in = '1' and wb_we_in = '1' then |
for i in 0 to 3 loop |
if wb_sel_in(i) = '1' then |
memory(to_integer(unsigned(wb_adr_in(wb_adr_in'left downto 2))))(((i + 1) * 8) - 1 downto i * 8) |
<= wb_dat_in(((i + 1) * 8) - 1 downto i * 8); |
end if; |
end loop; |
read_ack <= '1'; |
state <= ACK; |
elsif wb_stb_in = '1' then |
wb_dat_out <= memory(to_integer(unsigned(wb_adr_in(wb_adr_in'left downto 2)))); |
read_ack <= '1'; |
state <= ACK; |
end if; |
when ACK => |
if wb_stb_in = '0' then |
read_ack <= '0'; |
state <= IDLE; |
end if; |
end case; |
else |
state <= IDLE; |
read_ack <= '0'; |
end if; |
end if; |
end if; |
end process clk; |
|
end architecture behaviour; |
/trunk/scripts/extract_hex.sh
0,0 → 1,25
#!/bin/bash |
# The Potato Processor - A simple processor for FPGAs |
# (c) Kristian Klomsten Skordal 2014 - 2015 <kristian.skordal@wafflemail.net> |
# Report bugs and issues on <https://github.com/skordal/potato/issues> |
|
# This script extracts the code and data sections from executables and |
# produces hex files that can be used to initialize the instruction and |
# data memories in the testbench. |
|
if [ -z "$1" -o -z "$2" -o -z "$3" ]; then |
echo "exctract_hex <input elf file> <imem hex file> <dmem hex file>" |
exit 1 |
fi |
|
if [ -z "$TOOLCHAIN_PREFIX" ]; then |
TOOLCHAIN_PREFIX=riscv64-unknown-elf |
fi; |
|
$TOOLCHAIN_PREFIX-objdump -d -w $1 | sed '1,5d' | awk '!/:$/ { print $2; }' | sed '/^$/d' > $2; \ |
test -z "$($TOOLCHAIN_PREFIX-readelf -l $1 | grep .data)" || \ |
$TOOLCHAIN_PREFIX-objdump -s -j .data $1 | sed '1,4d' | \ |
awk '!/:$/ { for (i = 2; i < 6; i++) print $i; }' | sed '/^$/d' > $3; |
|
exit 0 |
|
trunk/scripts/extract_hex.sh
Property changes :
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/src/pp_execute.vhd
===================================================================
--- trunk/src/pp_execute.vhd (nonexistent)
+++ trunk/src/pp_execute.vhd (revision 2)
@@ -0,0 +1,510 @@
+-- The Potato Processor - A simple processor for FPGAs
+-- (c) Kristian Klomsten Skordal 2014 - 2015
+-- Report bugs and issues on
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+use work.pp_types.all;
+use work.pp_csr.all;
+use work.pp_utilities.all;
+
+entity pp_execute is
+ port(
+ clk : in std_logic;
+ reset : in std_logic;
+
+ stall, flush : in std_logic;
+
+ -- IRQ input:
+ irq : in std_logic_vector(7 downto 0);
+
+ -- Data memory outputs:
+ dmem_address : out std_logic_vector(31 downto 0);
+ dmem_data_out : out std_logic_vector(31 downto 0);
+ dmem_data_size : out std_logic_vector( 1 downto 0);
+ dmem_read_req : out std_logic;
+ dmem_write_req : out std_logic;
+
+ -- Register addresses:
+ rs1_addr_in, rs2_addr_in, rd_addr_in : in register_address;
+ rd_addr_out : out register_address;
+
+ -- Register values:
+ rs1_data_in, rs2_data_in : in std_logic_vector(31 downto 0);
+ rd_data_out : out std_logic_vector(31 downto 0);
+
+ -- Constant values:
+ shamt_in : in std_logic_vector(4 downto 0);
+ immediate_in : in std_logic_vector(31 downto 0);
+
+ -- Instruction address:
+ pc_in : in std_logic_vector(31 downto 0);
+ pc_out : out std_logic_vector(31 downto 0);
+
+ -- Funct3 value from the instruction, used to choose which comparison
+ -- is used when branching:
+ funct3_in : in std_logic_vector(2 downto 0);
+
+ -- CSR signals:
+ csr_addr_in : in csr_address;
+ csr_addr_out : out csr_address;
+ csr_write_in : in csr_write_mode;
+ csr_write_out : out csr_write_mode;
+ csr_value_in : in std_logic_vector(31 downto 0);
+ csr_value_out : out std_logic_vector(31 downto 0);
+ csr_writeable_in : in boolean;
+ csr_use_immediate_in : in std_logic;
+
+ -- Control signals:
+ alu_op_in : in alu_operation;
+ alu_x_src_in : in alu_operand_source;
+ alu_y_src_in : in alu_operand_source;
+ rd_write_in : in std_logic;
+ rd_write_out : out std_logic;
+ branch_in : in branch_type;
+ branch_out : out branch_type;
+
+ -- Memory control signals:
+ mem_op_in : in memory_operation_type;
+ mem_op_out : out memory_operation_type;
+ mem_size_in : in memory_operation_size;
+ mem_size_out : out memory_operation_size;
+
+ -- Whether the instruction should be counted:
+ count_instruction_in : in std_logic;
+ count_instruction_out : out std_logic;
+
+ -- Exception control registers:
+ status_in : in csr_status_register;
+ evec_in : in std_logic_vector(31 downto 0);
+ evec_out : out std_logic_vector(31 downto 0);
+
+ -- Exception signals:
+ decode_exception_in : in std_logic;
+ decode_exception_cause_in : in csr_exception_cause;
+
+ -- Exception outputs:
+ exception_out : out std_logic;
+ exception_context_out : out csr_exception_context;
+
+ -- Control outputs:
+ jump_out : out std_logic;
+ jump_target_out : out std_logic_vector(31 downto 0);
+
+ -- Inputs to the forwarding logic from the MEM stage:
+ mem_rd_write : in std_logic;
+ mem_rd_addr : in register_address;
+ mem_rd_value : in std_logic_vector(31 downto 0);
+ mem_csr_addr : in csr_address;
+ mem_csr_write : in csr_write_mode;
+ mem_csr_value : in std_logic_vector(31 downto 0);
+ mem_exception : in std_logic;
+ mem_exception_context : in csr_exception_context;
+
+ -- Inputs to the forwarding logic from the WB stage:
+ wb_rd_write : in std_logic;
+ wb_rd_addr : in register_address;
+ wb_rd_value : in std_logic_vector(31 downto 0);
+ wb_csr_addr : in csr_address;
+ wb_csr_write : in csr_write_mode;
+ wb_csr_value : in std_logic_vector(31 downto 0);
+ wb_exception : in std_logic;
+ wb_exception_context : in csr_exception_context;
+
+ -- Hazard detection unit signals:
+ mem_mem_op : in memory_operation_type;
+ hazard_detected : out std_logic
+ );
+end entity pp_execute;
+
+architecture behaviour of pp_execute is
+ signal alu_op : alu_operation;
+ signal alu_x_src, alu_y_src : alu_operand_source;
+
+ signal alu_x, alu_y, alu_result : std_logic_vector(31 downto 0);
+
+ signal rs1_addr, rs2_addr : register_address;
+ signal rs1_data, rs2_data : std_logic_vector(31 downto 0);
+
+ signal mem_op : memory_operation_type;
+ signal mem_size : memory_operation_size;
+
+ signal pc : std_logic_vector(31 downto 0);
+ signal immediate : std_logic_vector(31 downto 0);
+ signal shamt : std_logic_vector( 4 downto 0);
+ signal funct3 : std_logic_vector( 2 downto 0);
+
+ signal rs1_forwarded, rs2_forwarded : std_logic_vector(31 downto 0);
+
+ signal branch : branch_type;
+ signal branch_condition : std_logic;
+ signal jump_target : std_logic_vector(31 downto 0);
+
+ signal sr : csr_status_register;
+ signal evec, evec_forwarded : std_logic_vector(31 downto 0);
+
+ signal csr_write : csr_write_mode;
+ signal csr_addr : csr_address;
+ signal csr_use_immediate : std_logic;
+ signal csr_writeable : boolean;
+
+ signal csr_value, csr_value_forwarded : std_logic_vector(31 downto 0);
+
+ signal decode_exception : std_logic;
+ signal decode_exception_cause : csr_exception_cause;
+
+ signal exception_taken : std_logic;
+ signal exception_cause : csr_exception_cause;
+ signal exception_vaddr : std_logic_vector(31 downto 0);
+
+ signal exception_context_forwarded : csr_exception_context;
+
+ signal data_misaligned, instr_misaligned : std_logic;
+
+ signal irq_asserted : std_logic;
+ signal irq_asserted_num : std_logic_vector(3 downto 0);
+begin
+
+ -- Register values should not be latched in by a clocked process,
+ -- this is already done in the register files.
+ csr_value <= csr_value_in;
+ rd_data_out <= alu_result;
+
+ branch_out <= branch;
+
+ mem_op_out <= mem_op;
+ mem_size_out <= mem_size;
+
+ csr_write_out <= csr_write;
+ csr_addr_out <= csr_addr;
+
+ pc_out <= pc;
+
+ exception_out <= exception_taken;
+ exception_context_out <= (
+ status => exception_context_forwarded.status,
+ cause => exception_cause,
+ badvaddr => exception_vaddr
+ ) when exception_taken = '1' else exception_context_forwarded;
+
+ jump_out <= to_std_logic(branch = BRANCH_JUMP or branch = BRANCH_JUMP_INDIRECT)
+ or (to_std_logic(branch = BRANCH_CONDITIONAL) and branch_condition)
+ or to_std_logic(branch = BRANCH_SRET);
+ 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;
+
+ 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;
+ rs2_data <= rs2_data_in;
+
+ dmem_address <= alu_result;
+ dmem_data_out <= rs2_forwarded;
+ dmem_write_req <= '1' when mem_op = MEMOP_TYPE_STORE else '0';
+ dmem_read_req <= '1' when memop_is_load(mem_op) else '0';
+
+ pipeline_register: process(clk)
+ begin
+ if rising_edge(clk) then
+ if reset = '1' or flush = '1' then
+ rd_write_out <= '0';
+ branch <= BRANCH_NONE;
+ csr_write <= CSR_WRITE_NONE;
+ mem_op <= MEMOP_TYPE_NONE;
+ decode_exception <= '0';
+ count_instruction_out <= '0';
+ elsif stall = '0' then
+ pc <= pc_in;
+ count_instruction_out <= count_instruction_in;
+
+ -- Register signals:
+ rd_write_out <= rd_write_in;
+ rd_addr_out <= rd_addr_in;
+ rs1_addr <= rs1_addr_in;
+ rs2_addr <= rs2_addr_in;
+
+ -- ALU signals:
+ alu_op <= alu_op_in;
+ alu_x_src <= alu_x_src_in;
+ alu_y_src <= alu_y_src_in;
+
+ -- Control signals:
+ branch <= branch_in;
+ mem_op <= mem_op_in;
+ mem_size <= mem_size_in;
+
+ -- Constant values:
+ immediate <= immediate_in;
+ shamt <= shamt_in;
+ funct3 <= funct3_in;
+
+ -- CSR signals:
+ csr_write <= csr_write_in;
+ csr_addr <= csr_addr_in;
+ csr_use_immediate <= csr_use_immediate_in;
+ csr_writeable <= csr_writeable_in;
+
+ -- Status register;
+ sr <= status_in;
+
+ -- Exception vector base:
+ evec <= evec_in;
+
+ -- Instruction decoder exceptions:
+ decode_exception <= decode_exception_in;
+ decode_exception_cause <= decode_exception_cause_in;
+ end if;
+ end if;
+ end process pipeline_register;
+
+ set_data_size: process(mem_size)
+ begin
+ case mem_size is
+ when MEMOP_SIZE_BYTE =>
+ dmem_data_size <= b"01";
+ when MEMOP_SIZE_HALFWORD =>
+ dmem_data_size <= b"10";
+ when MEMOP_SIZE_WORD =>
+ dmem_data_size <= b"00";
+ when others =>
+ dmem_data_size <= b"11";
+ end case;
+ end process set_data_size;
+
+ get_irq_num: process(irq, exception_context_forwarded)
+ variable temp : std_logic_vector(3 downto 0);
+ begin
+ temp := (others => '0');
+
+ for i in 0 to 7 loop
+ if irq(i) = '1' and exception_context_forwarded.status.im(i) = '1' then
+ temp := std_logic_vector(to_unsigned(i, temp'length));
+ exit;
+ end if;
+ end loop;
+
+ irq_asserted_num <= temp;
+ end process get_irq_num;
+
+ data_misalign_check: process(mem_size, alu_result)
+ begin
+ case mem_size is
+ when MEMOP_SIZE_HALFWORD =>
+ if alu_result(0) /= '0' then
+ data_misaligned <= '1';
+ else
+ data_misaligned <= '0';
+ end if;
+ when MEMOP_SIZE_WORD =>
+ if alu_result(1 downto 0) /= b"00" then
+ data_misaligned <= '1';
+ else
+ data_misaligned <= '0';
+ end if;
+ when others =>
+ data_misaligned <= '0';
+ end case;
+ end process data_misalign_check;
+
+ instr_misalign_check: instr_misaligned <= '1' when jump_target(1 downto 0) /= b"00" else '0';
+
+ find_exception_cause: process(decode_exception, decode_exception_cause, mem_op,
+ data_misaligned, instr_misaligned, irq_asserted, irq_asserted_num)
+ begin
+ if irq_asserted = '1' then
+ exception_cause <= std_logic_vector(unsigned(CSR_CAUSE_IRQ_BASE) + unsigned(irq_asserted_num));
+ elsif decode_exception = '1' then
+ exception_cause <= decode_exception_cause;
+ elsif mem_op = MEMOP_TYPE_INVALID then
+ exception_cause <= CSR_CAUSE_INVALID_INSTR;
+ elsif instr_misaligned = '1' then
+ exception_cause <= CSR_CAUSE_INSTR_MISALIGN;
+ elsif data_misaligned = '1' and mem_op = MEMOP_TYPE_STORE then
+ exception_cause <= CSR_CAUSE_STORE_MISALIGN;
+ elsif data_misaligned = '1' and memop_is_load(mem_op) then
+ exception_cause <= CSR_CAUSE_LOAD_MISALIGN;
+ else
+ exception_cause <= CSR_CAUSE_NONE;
+ end if;
+ end process find_exception_cause;
+
+ find_exception_vaddr: process(instr_misaligned, data_misaligned, jump_target, alu_result)
+ begin
+ if instr_misaligned = '1' then
+ exception_vaddr <= jump_target;
+ elsif data_misaligned = '1' then
+ exception_vaddr <= alu_result;
+ else
+ exception_vaddr <= (others => '0');
+ end if;
+ end process find_exception_vaddr;
+
+ calc_jump_tgt: process(branch, pc, rs1_forwarded, immediate, csr_value_forwarded)
+ begin
+ case branch is
+ when BRANCH_JUMP | BRANCH_CONDITIONAL =>
+ jump_target <= std_logic_vector(unsigned(pc) + unsigned(immediate));
+ when BRANCH_JUMP_INDIRECT =>
+ jump_target <= std_logic_vector(unsigned(rs1_forwarded) + unsigned(immediate));
+ when BRANCH_SRET =>
+ jump_target <= csr_value_forwarded; -- Will be the EPC value in the case of SRET
+ when others =>
+ jump_target <= (others => '0');
+ end case;
+ end process calc_jump_tgt;
+
+ alu_x_mux: entity work.pp_alu_mux
+ port map(
+ source => alu_x_src,
+ register_value => rs1_forwarded,
+ immediate_value => immediate,
+ shamt_value => shamt,
+ pc_value => pc,
+ csr_value => csr_value_forwarded,
+ output => alu_x
+ );
+
+ alu_y_mux: entity work.pp_alu_mux
+ port map(
+ source => alu_y_src,
+ register_value => rs2_forwarded,
+ immediate_value => immediate,
+ shamt_value => shamt,
+ pc_value => pc,
+ csr_value => csr_value_forwarded,
+ output => alu_y
+ );
+
+ alu_x_forward: process(mem_rd_write, mem_rd_value, mem_rd_addr, rs1_addr,
+ rs1_data, wb_rd_write, wb_rd_addr, wb_rd_value)
+ begin
+ if mem_rd_write = '1' and mem_rd_addr = rs1_addr and mem_rd_addr /= b"00000" then
+ rs1_forwarded <= mem_rd_value;
+ elsif wb_rd_write = '1' and wb_rd_addr = rs1_addr and wb_rd_addr /= b"00000" then
+ rs1_forwarded <= wb_rd_value;
+ else
+ rs1_forwarded <= rs1_data;
+ end if;
+ end process alu_x_forward;
+
+ alu_y_forward: process(mem_rd_write, mem_rd_value, mem_rd_addr, rs2_addr,
+ rs2_data, wb_rd_write, wb_rd_addr, wb_rd_value)
+ begin
+ if mem_rd_write = '1' and mem_rd_addr = rs2_addr and mem_rd_addr /= b"00000" then
+ rs2_forwarded <= mem_rd_value;
+ elsif wb_rd_write = '1' and wb_rd_addr = rs2_addr and wb_rd_addr /= b"00000" then
+ rs2_forwarded <= wb_rd_value;
+ else
+ rs2_forwarded <= rs2_data;
+ end if;
+ end process alu_y_forward;
+
+ csr_forward: process(mem_csr_write, wb_csr_write, csr_addr, mem_csr_addr, wb_csr_addr,
+ csr_value, mem_csr_value, wb_csr_value, csr_writeable, mem_exception, wb_exception,
+ mem_exception_context, wb_exception_context)
+ begin
+ if csr_addr = CSR_CAUSE and mem_exception = '1' then
+ csr_value_forwarded <= to_std_logic_vector(mem_exception_context.cause);
+ elsif csr_addr = CSR_STATUS and mem_exception = '1' then
+ csr_value_forwarded <= to_std_logic_vector(mem_exception_context.status);
+ elsif csr_addr = CSR_BADVADDR and mem_exception = '1' then
+ csr_value_forwarded <= mem_exception_context.badvaddr;
+ elsif mem_csr_write /= CSR_WRITE_NONE and mem_csr_addr = csr_addr and csr_writeable then
+ csr_value_forwarded <= mem_csr_value;
+ elsif csr_addr = CSR_CAUSE and wb_exception = '1' then
+ csr_value_forwarded <= to_std_logic_vector(wb_exception_context.cause);
+ elsif csr_addr = CSR_STATUS and wb_exception = '1' then
+ csr_value_forwarded <= to_std_logic_vector(wb_exception_context.status);
+ elsif csr_addr = CSR_BADVADDR and wb_exception = '1' then
+ csr_value_forwarded <= wb_exception_context.badvaddr;
+ elsif wb_csr_write /= CSR_WRITE_NONE and wb_csr_addr = csr_addr and csr_writeable then
+ csr_value_forwarded <= wb_csr_value;
+ else
+ csr_value_forwarded <= csr_value;
+ end if;
+ end process csr_forward;
+
+ evec_forward: process(mem_csr_write, mem_csr_addr, mem_csr_value,
+ wb_csr_write, wb_csr_addr, wb_csr_value, evec)
+ begin
+ if mem_csr_write /= CSR_WRITE_NONE and mem_csr_addr = CSR_EVEC then
+ evec_forwarded <= mem_csr_value;
+ elsif wb_csr_write /= CSR_WRITE_NONE and wb_csr_addr = CSR_EVEC then
+ evec_forwarded <= wb_csr_value;
+ else
+ evec_forwarded <= evec;
+ end if;
+ end process evec_forward;
+
+ exception_ctx_forward: process(mem_exception, wb_exception, mem_exception_context, wb_exception_context,
+ exception_cause, exception_vaddr, mem_csr_write, mem_csr_addr, mem_csr_value,
+ wb_csr_write, wb_csr_addr, wb_csr_value, sr)
+ begin
+ if mem_exception = '1' then
+ exception_context_forwarded <= mem_exception_context;
+ elsif mem_csr_write /= CSR_WRITE_NONE and mem_csr_addr = CSR_STATUS then
+ exception_context_forwarded <= (
+ status => to_csr_status_register(mem_csr_value),
+ cause => mem_exception_context.cause,
+ badvaddr => mem_exception_context.badvaddr);
+ elsif wb_exception = '1' then
+ exception_context_forwarded <= wb_exception_context;
+ elsif wb_csr_write /= CSR_WRITE_NONE and wb_csr_addr = CSR_STATUS then
+ exception_context_forwarded <= (
+ status => to_csr_status_register(wb_csr_value),
+ cause => wb_exception_context.cause,
+ badvaddr => wb_exception_context.badvaddr);
+ else
+ exception_context_forwarded.status <= sr;
+ exception_context_forwarded.cause <= exception_cause;
+ exception_context_forwarded.badvaddr <= exception_vaddr;
+ end if;
+ end process exception_ctx_forward;
+
+ detect_load_hazard: process(mem_mem_op, mem_rd_addr, rs1_addr, rs2_addr,
+ alu_x_src, alu_y_src)
+ begin
+ if (mem_mem_op = MEMOP_TYPE_LOAD or mem_mem_op = MEMOP_TYPE_LOAD_UNSIGNED) and
+ ((alu_x_src = ALU_SRC_REG and mem_rd_addr = rs1_addr and rs1_addr /= b"00000")
+ or
+ (alu_y_src = ALU_SRC_REG and mem_rd_addr = rs2_addr and rs2_addr /= b"00000"))
+ then
+ hazard_detected <= '1';
+ else
+ hazard_detected <= '0';
+ end if;
+ end process detect_load_hazard;
+
+ branch_comparator: entity work.pp_comparator
+ port map(
+ funct3 => funct3,
+ rs1 => rs1_forwarded,
+ rs2 => rs2_forwarded,
+ result => branch_condition
+ );
+
+ alu_instance: entity work.pp_alu
+ port map(
+ result => alu_result,
+ x => alu_x,
+ y => alu_y,
+ operation => alu_op
+ );
+
+ csr_alu_instance: entity work.pp_csr_alu
+ port map(
+ x => csr_value_forwarded,
+ y => rs1_forwarded,
+ result => csr_value_out,
+ immediate => rs1_addr,
+ use_immediate => csr_use_immediate,
+ write_mode => csr_write
+ );
+
+
+end architecture behaviour;
Index: trunk/src/pp_types.vhd
===================================================================
--- trunk/src/pp_types.vhd (nonexistent)
+++ trunk/src/pp_types.vhd (revision 2)
@@ -0,0 +1,54 @@
+-- The Potato Processor - A simple processor for FPGAs
+-- (c) Kristian Klomsten Skordal 2014 - 2015
+-- Report bugs and issues on
+
+library ieee;
+use ieee.std_logic_1164.all;
+
+package pp_types is
+
+ --! Type used for register addresses.
+ subtype register_address is std_logic_vector(4 downto 0);
+
+ --! The available ALU operations.
+ type alu_operation is (
+ ALU_AND, ALU_OR, ALU_XOR,
+ ALU_SLT, ALU_SLTU,
+ ALU_ADD, ALU_SUB,
+ ALU_SRL, ALU_SLL, ALU_SRA,
+ ALU_NOP
+ );
+
+ --! Types of branches.
+ type branch_type is (
+ BRANCH_NONE, BRANCH_JUMP, BRANCH_JUMP_INDIRECT, BRANCH_CONDITIONAL, BRANCH_SRET
+ );
+
+ --! Source of an ALU operand.
+ type alu_operand_source is (
+ ALU_SRC_REG, ALU_SRC_IMM, ALU_SRC_SHAMT, ALU_SRC_PC, ALU_SRC_PC_NEXT, ALU_SRC_NULL, ALU_SRC_CSR
+ );
+
+ --! Type of memory operation:
+ type memory_operation_type is (
+ MEMOP_TYPE_NONE, MEMOP_TYPE_INVALID, MEMOP_TYPE_LOAD, MEMOP_TYPE_LOAD_UNSIGNED, MEMOP_TYPE_STORE
+ );
+
+ -- Determines if a memory operation is a load:
+ function memop_is_load(input : in memory_operation_type) return boolean;
+
+ --! Size of a memory operation:
+ type memory_operation_size is (
+ MEMOP_SIZE_BYTE, MEMOP_SIZE_HALFWORD, MEMOP_SIZE_WORD
+ );
+
+end package pp_types;
+
+package body pp_types is
+
+ function memop_is_load(input : in memory_operation_type) return boolean is
+ begin
+ return (input = MEMOP_TYPE_LOAD or input = MEMOP_TYPE_LOAD_UNSIGNED);
+ end function memop_is_load;
+
+end package body pp_types;
Index: trunk/src/pp_potato.vhd
===================================================================
--- trunk/src/pp_potato.vhd (nonexistent)
+++ trunk/src/pp_potato.vhd (revision 2)
@@ -0,0 +1,111 @@
+-- The Potato Processor - A simple processor for FPGAs
+-- (c) Kristian Klomsten Skordal 2014 - 2015
+-- Report bugs and issues on
+
+library ieee;
+use ieee.std_logic_1164.all;
+
+--! @brief The Potato Processor.
+--! This file provides a Wishbone-compatible interface to the Potato processor.
+entity pp_potato is
+ generic(
+ PROCESSOR_ID : std_logic_vector(31 downto 0) := x"00000000"; --! Processor ID.
+ RESET_ADDRESS : std_logic_vector(31 downto 0) := x"00000000" --! Address of the first instruction to execute.
+ );
+ port(
+ clk : in std_logic;
+ reset : in std_logic;
+
+ -- Interrupts:
+ irq : in std_logic_vector(7 downto 0);
+
+ -- Host/Target interface:
+ fromhost_data : in std_logic_vector(31 downto 0);
+ fromhost_updated : in std_logic;
+ tohost_data : out std_logic_vector(31 downto 0);
+ tohost_updated : out std_logic;
+
+ -- 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_potato;
+
+architecture behaviour of pp_potato is
+
+ -- Instruction memory signals:
+ signal imem_address : std_logic_vector(31 downto 0);
+ signal imem_data : std_logic_vector(31 downto 0);
+ signal imem_req, imem_ack : std_logic;
+
+ -- Data memory signals:
+ signal dmem_address : std_logic_vector(31 downto 0);
+ signal dmem_data_in : std_logic_vector(31 downto 0);
+ signal dmem_data_out : std_logic_vector(31 downto 0);
+ signal dmem_data_size : std_logic_vector( 1 downto 0);
+ signal dmem_read_req : std_logic;
+ signal dmem_read_ack : std_logic;
+ signal dmem_write_req : std_logic;
+ signal dmem_write_ack : std_logic;
+
+begin
+ processor: entity work.pp_core
+ generic map(
+ PROCESSOR_ID => PROCESSOR_ID,
+ RESET_ADDRESS => RESET_ADDRESS
+ ) port map(
+ clk => clk,
+ reset => reset,
+ timer_clk => clk,
+ imem_address => imem_address,
+ imem_data_in => imem_data,
+ imem_req => imem_req,
+ imem_ack => imem_ack,
+ dmem_address => dmem_address,
+ dmem_data_in => dmem_data_in,
+ dmem_data_out => dmem_data_out,
+ 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,
+ fromhost_data => fromhost_data,
+ fromhost_write_en => fromhost_updated,
+ tohost_data => tohost_data,
+ tohost_write_en => tohost_updated,
+ irq => irq
+ );
+
+ wb_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_write_req => dmem_write_req,
+ dmem_read_ack => dmem_read_ack,
+ dmem_write_ack => dmem_write_ack,
+ wb_adr_out => wb_adr_out,
+ wb_sel_out => wb_sel_out,
+ wb_cyc_out => wb_cyc_out,
+ wb_stb_out => wb_stb_out,
+ wb_we_out => wb_we_out,
+ wb_dat_out => wb_dat_out,
+ wb_dat_in => wb_dat_in,
+ wb_ack_in => wb_ack_in
+ );
+
+end architecture behaviour;
Index: trunk/src/pp_imm_decoder.vhd
===================================================================
--- trunk/src/pp_imm_decoder.vhd (nonexistent)
+++ trunk/src/pp_imm_decoder.vhd (revision 2)
@@ -0,0 +1,35 @@
+-- The Potato Processor - A simple processor for FPGAs
+-- (c) Kristian Klomsten Skordal 2014
+-- Report bugs and issues on
+
+library ieee;
+use ieee.std_logic_1164.all;
+
+--! @brief Module decoding immediate values from instruction words.
+entity pp_imm_decoder is
+ port(
+ instruction : in std_logic_vector(31 downto 2);
+ immediate : out std_logic_vector(31 downto 0)
+ );
+end entity pp_imm_decoder;
+
+architecture behaviour of pp_imm_decoder is
+begin
+ decode: process(instruction)
+ begin
+ case instruction(6 downto 2) is
+ when b"01101" | b"00101" => -- U type
+ immediate <= instruction(31 downto 12) & (11 downto 0 => '0');
+ when b"11011" => -- UJ type
+ immediate <= (31 downto 20 => instruction(31)) & instruction(19 downto 12) & instruction(20) & instruction(30 downto 21) & '0';
+ when b"11001" | b"00000" | b"00100" | b"11100"=> -- I type
+ immediate <= (31 downto 11 => instruction(31)) & instruction(30 downto 20);
+ when b"11000" => -- SB type
+ immediate <= (31 downto 12 => instruction(31)) & instruction(7) & instruction(30 downto 25) & instruction(11 downto 8) & '0';
+ when b"01000" => -- S type
+ immediate <= (31 downto 11 => instruction(31)) & instruction(30 downto 25) & instruction(11 downto 7);
+ when others =>
+ immediate <= (others => '0');
+ end case;
+ end process decode;
+end architecture behaviour;
Index: trunk/src/pp_comparator.vhd
===================================================================
--- trunk/src/pp_comparator.vhd (nonexistent)
+++ trunk/src/pp_comparator.vhd (revision 2)
@@ -0,0 +1,43 @@
+-- The Potato Processor - A simple processor for FPGAs
+-- (c) Kristian Klomsten Skordal 2014
+-- Report bugs and issues on
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+use work.pp_utilities.all;
+
+--! @brief Component for comparing two registers in the ID stage whens branching.
+entity pp_comparator is
+ port(
+ funct3 : in std_logic_vector(14 downto 12);
+ rs1, rs2 : in std_logic_vector(31 downto 0);
+ result : out std_logic --! Result of the comparison.
+ );
+end entity pp_comparator;
+
+architecture behaviour of pp_comparator is
+begin
+
+ compare: process(funct3, rs1, rs2)
+ begin
+ case funct3 is
+ when b"000" => -- EQ
+ result <= to_std_logic(rs1 = rs2);
+ when b"001" => -- NE
+ result <= to_std_logic(rs1 /= rs2);
+ when b"100" => -- LT
+ result <= to_std_logic(signed(rs1) < signed(rs2));
+ when b"101" => -- GE
+ result <= to_std_logic(signed(rs1) >= signed(rs2));
+ when b"110" => -- LTU
+ result <= to_std_logic(unsigned(rs1) < unsigned(rs2));
+ when b"111" => -- GEU
+ result <= to_std_logic(unsigned(rs1) >= unsigned(rs2));
+ when others =>
+ result <= '0';
+ end case;
+ end process compare;
+
+end architecture behaviour;
Index: trunk/src/pp_wb_adapter.vhd
===================================================================
--- trunk/src/pp_wb_adapter.vhd (nonexistent)
+++ trunk/src/pp_wb_adapter.vhd (revision 2)
@@ -0,0 +1,173 @@
+-- The Potato Processor - A simple processor for FPGAs
+-- (c) Kristian Klomsten Skordal 2014 - 2015
+-- Report bugs and issues on
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.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 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
+ 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_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
+ );
+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);
+ 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;
+
+ 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_read_ack <= dmem_r_ack;
+
+ wishbone: process(clk)
+ begin
+ if rising_edge(clk) then
+ if reset = '1' then
+ state <= IDLE;
+ wb_cyc_out <= '0';
+ wb_stb_out <= '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_adr_out <= dmem_address;
+ wb_dat_out <= 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';
+ 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';
+ 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),
+ get_data_shift(dmem_data_size, dmem_address)));
+ wb_cyc_out <= '0';
+ wb_stb_out <= '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';
+ state <= IDLE;
+ end if;
+ end case;
+ end if;
+ end if;
+ end process wishbone;
+
+end architecture behaviour;
Index: trunk/src/pp_memory.vhd
===================================================================
--- trunk/src/pp_memory.vhd (nonexistent)
+++ trunk/src/pp_memory.vhd (revision 2)
@@ -0,0 +1,161 @@
+-- The Potato Processor - A simple processor for FPGAs
+-- (c) Kristian Klomsten Skordal 2014 - 2015
+-- Report bugs and issues on
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+use work.pp_types.all;
+use work.pp_csr.all;
+use work.pp_utilities.all;
+
+entity pp_memory is
+ port(
+ clk : in std_logic;
+ reset : in std_logic;
+ stall : in std_logic;
+
+ -- Data memory inputs:
+ dmem_read_ack : in std_logic;
+ dmem_write_ack : in std_logic;
+ dmem_data_in : in std_logic_vector(31 downto 0);
+
+ -- Current PC value:
+ pc : in std_logic_vector(31 downto 0);
+
+ -- Destination register signals:
+ rd_write_in : in std_logic;
+ rd_write_out : out std_logic;
+ rd_data_in : in std_logic_vector(31 downto 0);
+ rd_data_out : out std_logic_vector(31 downto 0);
+ rd_addr_in : in register_address;
+ rd_addr_out : out register_address;
+
+ -- Control signals:
+ branch : in branch_type;
+ mem_op_in : in memory_operation_type;
+ mem_size_in : in memory_operation_size;
+ mem_op_out : out memory_operation_type;
+
+ -- Whether the instruction should be counted:
+ count_instr_in : in std_logic;
+ count_instr_out : out std_logic;
+
+ -- Exception signals:
+ exception_in : in std_logic;
+ exception_out : out std_logic;
+ exception_context_in : in csr_exception_context;
+ exception_context_out : out csr_exception_context;
+
+ -- CSR signals:
+ csr_addr_in : in csr_address;
+ csr_addr_out : out csr_address;
+ csr_write_in : in csr_write_mode;
+ csr_write_out : out csr_write_mode;
+ csr_data_in : in std_logic_vector(31 downto 0);
+ csr_data_out : out std_logic_vector(31 downto 0)
+ );
+end entity pp_memory;
+
+architecture behaviour of pp_memory is
+ signal mem_op : memory_operation_type;
+ signal mem_size : memory_operation_size;
+
+ signal rd_data : std_logic_vector(31 downto 0);
+begin
+
+ mem_op_out <= mem_op;
+
+ pipeline_register: process(clk)
+ begin
+ if rising_edge(clk) then
+ if reset = '1' then
+ rd_write_out <= '0';
+ csr_write_out <= CSR_WRITE_NONE;
+ count_instr_out <= '0';
+ mem_op <= MEMOP_TYPE_NONE;
+ elsif stall = '0' then
+ mem_size <= mem_size_in;
+ rd_data <= rd_data_in;
+ rd_addr_out <= rd_addr_in;
+
+ if exception_in = '1' then
+ mem_op <= MEMOP_TYPE_NONE;
+ rd_write_out <= '0';
+ csr_write_out <= CSR_WRITE_REPLACE;
+ csr_addr_out <= CSR_EPC;
+ csr_data_out <= pc;
+ count_instr_out <= '0';
+ else
+ mem_op <= mem_op_in;
+ rd_write_out <= rd_write_in;
+ csr_write_out <= csr_write_in;
+ csr_addr_out <= csr_addr_in;
+ csr_data_out <= csr_data_in;
+ count_instr_out <= count_instr_in;
+ end if;
+ end if;
+ end if;
+ end process pipeline_register;
+
+ update_exception_context: process(clk)
+ begin
+ if rising_edge(clk) then
+ if reset = '1' then
+ exception_out <= '0';
+ else
+ exception_out <= exception_in or to_std_logic(branch = BRANCH_SRET);
+
+ if exception_in = '1' then
+ exception_context_out.status <= (
+ pim => exception_context_in.status.im,
+ im => exception_context_in.status.im,
+ pei => exception_context_in.status.ei,
+ ei => '0'
+ );
+ exception_context_out.cause <= exception_context_in.cause;
+ exception_context_out.badvaddr <= exception_context_in.badvaddr;
+ elsif branch = BRANCH_SRET then
+ exception_context_out.status <= (
+ pim => exception_context_in.status.pim,
+ im => exception_context_in.status.pim,
+ pei => exception_context_in.status.pei,
+ ei => exception_context_in.status.pei
+ );
+ exception_context_out.cause <= CSR_CAUSE_NONE;
+ exception_context_out.badvaddr <= (others => '0');
+ else
+ exception_context_out.status <= exception_context_in.status;
+ exception_context_out.cause <= CSR_CAUSE_NONE;
+ exception_context_out.badvaddr <= (others => '0');
+ end if;
+ end if;
+ end if;
+ end process update_exception_context;
+
+ rd_data_mux: process(rd_data, dmem_data_in, mem_op, mem_size)
+ begin
+ if mem_op = MEMOP_TYPE_LOAD or mem_op = MEMOP_TYPE_LOAD_UNSIGNED then
+ case mem_size is
+ when MEMOP_SIZE_BYTE =>
+ if mem_op = MEMOP_TYPE_LOAD_UNSIGNED then
+ rd_data_out <= std_logic_vector(resize(unsigned(dmem_data_in(7 downto 0)), rd_data_out'length));
+ else
+ rd_data_out <= std_logic_vector(resize(signed(dmem_data_in(7 downto 0)), rd_data_out'length));
+ end if;
+ when MEMOP_SIZE_HALFWORD =>
+ if mem_op = MEMOP_TYPE_LOAD_UNSIGNED then
+ rd_data_out <= std_logic_vector(resize(unsigned(dmem_data_in(15 downto 0)), rd_data_out'length));
+ else
+ rd_data_out <= std_logic_vector(resize(signed(dmem_data_in(15 downto 0)), rd_data_out'length));
+ end if;
+ when MEMOP_SIZE_WORD =>
+ rd_data_out <= dmem_data_in;
+ end case;
+ else
+ rd_data_out <= rd_data;
+ end if;
+ end process rd_data_mux;
+
+end architecture behaviour;
Index: trunk/src/pp_alu_mux.vhd
===================================================================
--- trunk/src/pp_alu_mux.vhd (nonexistent)
+++ trunk/src/pp_alu_mux.vhd (revision 2)
@@ -0,0 +1,49 @@
+-- The Potato Processor - A simple processor for FPGAs
+-- (c) Kristian Klomsten Skordal 2014
+-- Report bugs and issues on
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+use work.pp_types.all;
+
+--! @brief Multiplexer used to choose between ALU inputs.
+entity pp_alu_mux is
+ port(
+ source : in alu_operand_source;
+
+ register_value : in std_logic_vector(31 downto 0);
+ immediate_value : in std_logic_vector(31 downto 0);
+ shamt_value : in std_logic_vector( 4 downto 0);
+ pc_value : in std_logic_vector(31 downto 0);
+ csr_value : in std_logic_vector(31 downto 0);
+
+ output : out std_logic_vector(31 downto 0)
+ );
+end entity pp_alu_mux;
+
+architecture behaviour of pp_alu_mux is
+begin
+
+ mux: process(source, register_value, immediate_value, shamt_value, pc_value, csr_value)
+ begin
+ case source is
+ when ALU_SRC_REG =>
+ output <= register_value;
+ when ALU_SRC_IMM =>
+ output <= immediate_value;
+ when ALU_SRC_PC =>
+ output <= pc_value;
+ when ALU_SRC_PC_NEXT =>
+ output <= std_logic_vector(unsigned(pc_value) + 4);
+ when ALU_SRC_CSR =>
+ output <= csr_value;
+ when ALU_SRC_SHAMT =>
+ output <= (31 downto 5 => '0') & shamt_value;
+ when ALU_SRC_NULL =>
+ output <= (others => '0');
+ end case;
+ end process mux;
+
+end architecture behaviour;
Index: trunk/src/pp_utilities.vhd
===================================================================
--- trunk/src/pp_utilities.vhd (nonexistent)
+++ trunk/src/pp_utilities.vhd (revision 2)
@@ -0,0 +1,61 @@
+-- The Potato Processor - A simple processor for FPGAs
+-- (c) Kristian Klomsten Skordal 2014
+-- Report bugs and issues on
+
+library ieee;
+use ieee.std_logic_1164.all;
+
+use work.pp_types.all;
+use work.pp_constants.all;
+
+package pp_utilities is
+
+ --! Converts a boolean to an std_logic.
+ function to_std_logic(input : in boolean) return std_logic;
+
+ -- Checks if a number is 2^n:
+ function is_pow2(input : in natural) return boolean;
+
+ --! Calculates log2 with integers.
+ function log2(input : in natural) return natural;
+
+end package pp_utilities;
+
+package body pp_utilities is
+
+ function to_std_logic(input : in boolean) return std_logic is
+ begin
+ if input then
+ return '1';
+ else
+ return '0';
+ end if;
+ end function to_std_logic;
+
+ function is_pow2(input : in natural) return boolean is
+ variable c : natural := 1;
+ begin
+ for i in 0 to 31 loop
+ if input = i then
+ return true;
+ end if;
+
+ c := c * 2;
+ end loop;
+
+ return false;
+ end function is_pow2;
+
+ function log2(input : in natural) return natural is
+ variable retval : natural := 0;
+ variable temp : natural := input;
+ begin
+ while temp > 1 loop
+ retval := retval + 1;
+ temp := temp / 2;
+ end loop;
+
+ return retval;
+ end function log2;
+
+end package body pp_utilities;
Index: trunk/src/pp_writeback.vhd
===================================================================
--- trunk/src/pp_writeback.vhd (nonexistent)
+++ trunk/src/pp_writeback.vhd (revision 2)
@@ -0,0 +1,71 @@
+-- The Potato Processor - A simple processor for FPGAs
+-- (c) Kristian Klomsten Skordal 2014 - 2015
+-- Report bugs and issues on
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+use work.pp_types.all;
+use work.pp_csr.all;
+
+entity pp_writeback is
+ port(
+ clk : in std_logic;
+ reset : in std_logic;
+
+ -- Count instruction:
+ count_instr_in : in std_logic;
+ count_instr_out : out std_logic;
+
+ -- Exception signals:
+ exception_ctx_in : in csr_exception_context;
+ exception_in : in std_logic;
+ exception_ctx_out : out csr_exception_context;
+ exception_out : out std_logic;
+
+ -- CSR signals:
+ csr_write_in : in csr_write_mode;
+ csr_write_out : out csr_write_mode;
+ csr_data_in : in std_logic_vector(31 downto 0);
+ csr_data_out : out std_logic_vector(31 downto 0);
+ csr_addr_in : in csr_address;
+ csr_addr_out : out csr_address;
+
+ -- Destination register interface:
+ rd_addr_in : in register_address;
+ rd_addr_out : out register_address;
+ rd_write_in : in std_logic;
+ rd_write_out : out std_logic;
+ rd_data_in : in std_logic_vector(31 downto 0);
+ rd_data_out : out std_logic_vector(31 downto 0)
+ );
+end entity pp_writeback;
+
+architecture behaviour of pp_writeback is
+begin
+
+ pipeline_register: process(clk)
+ begin
+ if rising_edge(clk) then
+ if reset = '1' then
+ rd_write_out <= '0';
+ exception_out <= '0';
+ count_instr_out <= '0';
+ else
+ count_instr_out <= count_instr_in;
+ rd_data_out <= rd_data_in;
+ rd_write_out <= rd_write_in;
+ rd_addr_out <= rd_addr_in;
+
+ exception_out <= exception_in;
+ exception_ctx_out <= exception_ctx_in;
+
+ csr_write_out <= csr_write_in;
+ csr_data_out <= csr_data_in;
+ csr_addr_out <= csr_addr_in;
+ end if;
+ end if;
+ end process pipeline_register;
+
+end architecture behaviour;
Index: trunk/src/pp_constants.vhd
===================================================================
--- trunk/src/pp_constants.vhd (nonexistent)
+++ trunk/src/pp_constants.vhd (revision 2)
@@ -0,0 +1,15 @@
+-- The Potato Processor - A simple processor for FPGAs
+-- (c) Kristian Klomsten Skordal 2014
+-- Report bugs and issues on
+
+library ieee;
+use ieee.std_logic_1164.all;
+
+use work.pp_types.all;
+
+package pp_constants is
+
+ --! No-operation instruction, addi x0, x0, 0.
+ constant RISCV_NOP : std_logic_vector(31 downto 0) := (31 downto 5 => '0') & b"10011"; --! ADDI x0, x0, 0.
+
+end package pp_constants;
Index: trunk/src/pp_counter.vhd
===================================================================
--- trunk/src/pp_counter.vhd (nonexistent)
+++ trunk/src/pp_counter.vhd (revision 2)
@@ -0,0 +1,40 @@
+-- The Potato Processor - A simple processor for FPGAs
+-- (c) Kristian Klomsten Skordal 2014 -2015
+-- Report bugs and issues on
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+entity pp_counter is
+ generic(
+ COUNTER_WIDTH : natural := 64;
+ COUNTER_STEP : natural := 1
+ );
+ port(
+ clk : in std_logic;
+ reset : in std_logic;
+
+ count : out std_logic_vector(COUNTER_WIDTH - 1 downto 0);
+ increment : in std_logic
+ );
+end entity pp_counter;
+
+architecture behaviour of pp_counter is
+ signal current_count : std_logic_vector(COUNTER_WIDTH - 1 downto 0);
+begin
+
+ count <= current_count;
+
+ counter: process(clk)
+ begin
+ if rising_edge(clk) then
+ if reset = '1' then
+ current_count <= (others => '0');
+ elsif increment = '1' then
+ current_count <= std_logic_vector(unsigned(current_count) + COUNTER_STEP);
+ end if;
+ end if;
+ end process counter;
+
+end architecture behaviour;
Index: trunk/src/pp_control_unit.vhd
===================================================================
--- trunk/src/pp_control_unit.vhd (nonexistent)
+++ trunk/src/pp_control_unit.vhd (revision 2)
@@ -0,0 +1,211 @@
+-- The Potato Processor - A simple processor for FPGAs
+-- (c) Kristian Klomsten Skordal 2014 - 2015
+-- Report bugs and issues on
+
+library ieee;
+use ieee.std_logic_1164.all;
+
+use work.pp_types.all;
+use work.pp_constants.all;
+use work.pp_csr.all;
+
+--! @brief Unit decoding instructions and setting control signals apropriately.
+entity pp_control_unit is
+ port(
+ -- Inputs, indices correspond to instruction word indices:
+ opcode : in std_logic_vector( 4 downto 0);
+ funct3 : in std_logic_vector( 2 downto 0);
+ funct7 : in std_logic_vector( 6 downto 0);
+ funct12 : in std_logic_vectoR(11 downto 0);
+
+ -- Control signals:
+ rd_write : out std_logic;
+ branch : out branch_type;
+
+ -- Exception signals:
+ decode_exception : out std_logic;
+ decode_exception_cause : out std_logic_vector(4 downto 0);
+
+ -- Control register signals:
+ csr_write : out csr_write_mode;
+ csr_imm : out std_logic; --! Indicating an immediate variant of the csrr* instructions.
+
+ -- Sources of operands to the ALU:
+ alu_x_src, alu_y_src : out alu_operand_source;
+
+ -- ALU operation:
+ alu_op : out alu_operation;
+
+ -- Memory transaction parameters:
+ mem_op : out memory_operation_type;
+ mem_size : out memory_operation_size
+ );
+end entity pp_control_unit;
+
+architecture behaviour of pp_control_unit is
+begin
+
+ csr_imm <= funct3(2);
+
+ alu_control: entity work.pp_alu_control_unit
+ port map(
+ opcode => opcode,
+ funct3 => funct3,
+ funct7 => funct7,
+ alu_x_src => alu_x_src,
+ alu_y_src => alu_y_src,
+ alu_op => alu_op
+ );
+
+ decode_ctrl: process(opcode, funct3, funct12)
+ begin
+ case opcode is
+ when b"01101" => -- Load upper immediate
+ rd_write <= '1';
+ decode_exception <= '0';
+ decode_exception_cause <= CSR_CAUSE_NONE;
+ branch <= BRANCH_NONE;
+ when b"00101" => -- Add upper immediate to PC
+ rd_write <= '1';
+ decode_exception <= '0';
+ decode_exception_cause <= CSR_CAUSE_NONE;
+ branch <= BRANCH_NONE;
+ when b"11011" => -- Jump and link
+ rd_write <= '1';
+ decode_exception <= '0';
+ decode_exception_cause <= CSR_CAUSE_NONE;
+ branch <= BRANCH_JUMP;
+ when b"11001" => -- Jump and link register
+ rd_write <= '1';
+ decode_exception <= '0';
+ decode_exception_cause <= CSR_CAUSE_NONE;
+ branch <= BRANCH_JUMP_INDIRECT;
+ when b"11000" => -- Branch operations
+ rd_write <= '0';
+ decode_exception <= '0';
+ decode_exception_cause <= CSR_CAUSE_NONE;
+ branch <= BRANCH_CONDITIONAL;
+ when b"00000" => -- Load instructions
+ rd_write <= '1';
+ decode_exception <= '0';
+ decode_exception_cause <= CSR_CAUSE_NONE;
+ branch <= BRANCH_NONE;
+ when b"01000" => -- Store instructions
+ rd_write <= '0';
+ decode_exception <= '0';
+ decode_exception_cause <= CSR_CAUSE_NONE;
+ branch <= BRANCH_NONE;
+ when b"00100" => -- Register-immediate operations
+ rd_write <= '1';
+ decode_exception <= '0';
+ decode_exception_cause <= CSR_CAUSE_NONE;
+ branch <= BRANCH_NONE;
+ when b"01100" => -- Register-register operations
+ rd_write <= '1';
+ decode_exception <= '0';
+ decode_exception_cause <= CSR_CAUSE_NONE;
+ branch <= BRANCH_NONE;
+ when b"00011" => -- Fence instructions, ignored
+ rd_write <= '0';
+ decode_exception <= '0';
+ decode_exception_cause <= CSR_CAUSE_NONE;
+ branch <= BRANCH_NONE;
+ when b"11100" => -- System instructions
+ if funct3 = b"000" then
+ rd_write <= '0';
+
+ if funct12 = x"000" then
+ decode_exception <= '1';
+ decode_exception_cause <= CSR_CAUSE_SYSCALL;
+ branch <= BRANCH_NONE;
+ elsif funct12 = x"001" then
+ decode_exception <= '1';
+ decode_exception_cause <= CSR_CAUSE_BREAKPOINT;
+ branch <= BRANCH_NONE;
+ elsif funct12 = x"800" then
+ decode_exception <= '0';
+ decode_exception_cause <= CSR_CAUSE_NONE;
+ branch <= BRANCH_SRET;
+ else
+ decode_exception <= '1';
+ decode_exception_cause <= CSR_CAUSE_INVALID_INSTR;
+ branch <= BRANCH_NONE;
+ end if;
+ else
+ rd_write <= '1';
+ decode_exception <= '0';
+ decode_exception_cause <= CSR_CAUSE_NONE;
+ branch <= BRANCH_NONE;
+ end if;
+ when others =>
+ rd_write <= '0';
+ decode_exception <= '1';
+ decode_exception_cause <= CSR_CAUSE_INVALID_INSTR;
+ branch <= BRANCH_NONE;
+ end case;
+ end process decode_ctrl;
+
+ decode_csr: process(opcode, funct3)
+ begin
+ if opcode = b"11100" then
+ case funct3 is
+ when b"001" | b"101" => -- csrrw/i
+ csr_write <= CSR_WRITE_REPLACE;
+ when b"010" | b"110" => -- csrrs/i
+ csr_write <= CSR_WRITE_SET;
+ when b"011" | b"111" => -- csrrc/i
+ csr_write <= CSR_WRITE_CLEAR;
+ when others =>
+ csr_write <= CSR_WRITE_NONE;
+ end case;
+ else
+ csr_write <= CSR_WRITE_NONE;
+ end if;
+ end process decode_csr;
+
+ decode_mem: process(opcode, funct3)
+ begin
+ case opcode is
+ when b"00000" => -- Load instructions
+ case funct3 is
+ when b"000" => -- lw
+ mem_size <= MEMOP_SIZE_BYTE;
+ mem_op <= MEMOP_TYPE_LOAD;
+ when b"001" => -- lh
+ mem_size <= MEMOP_SIZE_HALFWORD;
+ mem_op <= MEMOP_TYPE_LOAD;
+ when b"010" | b"110" => -- lw
+ mem_size <= MEMOP_SIZE_WORD;
+ mem_op <= MEMOP_TYPE_LOAD;
+ when b"100" => -- lbu
+ mem_size <= MEMOP_SIZE_BYTE;
+ mem_op <= MEMOP_TYPE_LOAD_UNSIGNED;
+ when b"101" => -- lhu
+ mem_size <= MEMOP_SIZE_HALFWORD;
+ mem_op <= MEMOP_TYPE_LOAD_UNSIGNED;
+ when others => -- FIXME: Treat others as lw.
+ mem_size <= MEMOP_SIZE_WORD;
+ mem_op <= MEMOP_TYPE_INVALID;
+ end case;
+ when b"01000" => -- Store instructions
+ case funct3 is
+ when b"000" =>
+ mem_op <= MEMOP_TYPE_STORE;
+ mem_size <= MEMOP_SIZE_BYTE;
+ when b"001" =>
+ mem_op <= MEMOP_TYPE_STORE;
+ mem_size <= MEMOP_SIZE_HALFWORD;
+ when b"010" =>
+ mem_op <= MEMOP_TYPE_STORE;
+ mem_size <= MEMOP_SIZE_WORD;
+ when others =>
+ mem_op <= MEMOP_TYPE_INVALID;
+ mem_size <= MEMOP_SIZE_WORD;
+ end case;
+ when others =>
+ mem_op <= MEMOP_TYPE_NONE;
+ mem_size <= MEMOP_SIZE_WORD;
+ end case;
+ end process decode_mem;
+
+end architecture behaviour;
Index: trunk/src/pp_alu_control_unit.vhd
===================================================================
--- trunk/src/pp_alu_control_unit.vhd (nonexistent)
+++ trunk/src/pp_alu_control_unit.vhd (revision 2)
@@ -0,0 +1,137 @@
+-- The Potato Processor - A simple processor for FPGAs
+-- (c) Kristian Klomsten Skordal 2014 - 2015
+-- Report bugs and issues on
+
+library ieee;
+use ieee.std_logic_1164.all;
+
+use work.pp_types.all;
+use work.pp_constants.all;
+
+entity pp_alu_control_unit is
+ port(
+ opcode : in std_logic_vector( 4 downto 0);
+ funct3 : in std_logic_vector( 2 downto 0);
+ funct7 : in std_logic_vector( 6 downto 0);
+
+ -- Sources of ALU operands:
+ alu_x_src, alu_y_src : out alu_operand_source;
+
+ -- ALU operation:
+ alu_op : out alu_operation
+ );
+end entity pp_alu_control_unit;
+
+architecture behaviour of pp_alu_control_unit is
+begin
+
+ decode_alu: process(opcode, funct3, funct7)
+ begin
+ case opcode is
+ when b"01101" => -- Load upper immediate
+ alu_x_src <= ALU_SRC_NULL;
+ alu_y_src <= ALU_SRC_IMM;
+ alu_op <= ALU_ADD;
+ when b"00101" => -- Add upper immediate to PC
+ alu_x_src <= ALU_SRC_PC;
+ alu_y_src <= ALU_SRC_IMM;
+ alu_op <= ALU_ADD;
+ when b"11011" => -- Jump and link
+ alu_x_src <= ALU_SRC_PC_NEXT;
+ alu_y_src <= ALU_SRC_NULL;
+ alu_op <= ALU_ADD;
+ when b"11001" => -- Jump and link register
+ alu_x_src <= ALU_SRC_PC_NEXT;
+ alu_y_src <= ALU_SRC_NULL;
+ alu_op <= ALU_ADD;
+ when b"11000" => -- Branch operations
+ -- The funct3 field decides which type of branch comparison is
+ -- done; this is decoded in the branch comparator module.
+ alu_x_src <= ALU_SRC_NULL;
+ alu_y_src <= ALU_SRC_NULL;
+ alu_op <= ALU_NOP;
+ when b"00000" => -- Load instruction
+ alu_x_src <= ALU_SRC_REG;
+ alu_y_src <= ALU_SRC_IMM;
+ alu_op <= ALU_ADD;
+ when b"01000" => -- Store instruction
+ alu_x_src <= ALU_SRC_REG;
+ alu_y_src <= ALU_SRC_IMM;
+ alu_op <= ALU_ADD;
+ when b"00100" => -- Register-immediate operations
+ alu_x_src <= ALU_SRC_REG;
+
+ if funct3 = b"001" or funct3 = b"101" then
+ alu_y_src <= ALU_SRC_SHAMT;
+ else
+ alu_y_src <= ALU_SRC_IMM;
+ end if;
+
+ case funct3 is
+ when b"000" =>
+ alu_op <= ALU_ADD;
+ when b"001" =>
+ alu_op <= ALU_SLL;
+ when b"010" =>
+ alu_op <= ALU_SLT;
+ when b"011" =>
+ alu_op <= ALU_SLTU;
+ when b"100" =>
+ alu_op <= ALU_XOR;
+ when b"101" =>
+ if funct7 = b"0000000" then
+ alu_op <= ALU_SRL;
+ else
+ alu_op <= ALU_SRA;
+ end if;
+ when b"110" =>
+ alu_op <= ALU_OR;
+ when b"111" =>
+ alu_op <= ALU_AND;
+ when others =>
+ alu_op <= ALU_NOP;
+ end case;
+ when b"01100" => -- Register-register operations
+ alu_x_src <= ALU_SRC_REG;
+ alu_y_src <= ALU_SRC_REG;
+
+ case funct3 is
+ when b"000" =>
+ if funct7 = b"0000000" then
+ alu_op <= ALU_ADD;
+ else
+ alu_op <= ALU_SUB;
+ end if;
+ when b"001" =>
+ alu_op <= ALU_SLL;
+ when b"010" =>
+ alu_op <= ALU_SLT;
+ when b"011" =>
+ alu_op <= ALU_SLTU;
+ when b"100" =>
+ alu_op <= ALU_XOR;
+ when b"101" =>
+ if funct7 = b"0000000" then
+ alu_op <= ALU_SRL;
+ else
+ alu_op <= ALU_SRA;
+ end if;
+ when b"110" =>
+ alu_op <= ALU_OR;
+ when b"111" =>
+ alu_op <= ALU_AND;
+ when others =>
+ alu_op <= ALU_NOP;
+ end case;
+ when b"11100" => -- System instructions
+ alu_x_src <= ALU_SRC_CSR;
+ alu_y_src <= ALU_SRC_NULL;
+ alu_op <= ALU_ADD;
+ when others =>
+ alu_x_src <= ALU_SRC_REG;
+ alu_y_src <= ALU_SRC_REG;
+ alu_op <= ALU_NOP;
+ end case;
+ end process decode_alu;
+
+end architecture behaviour;
Index: trunk/src/pp_alu.vhd
===================================================================
--- trunk/src/pp_alu.vhd (nonexistent)
+++ trunk/src/pp_alu.vhd (revision 2)
@@ -0,0 +1,58 @@
+-- The Potato Processor - A simple processor for FPGAs
+-- (c) Kristian Klomsten Skordal 2014
+-- Report bugs and issues on
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+use work.pp_types.all;
+
+entity pp_alu is
+ port(
+ x, y : in std_logic_vector(31 downto 0);
+ result : out std_logic_vector(31 downto 0);
+ operation : in alu_operation
+ );
+end entity pp_alu;
+
+architecture behaviour of pp_alu is
+begin
+
+ calculate: process(operation, x, y)
+ begin
+ case operation is
+ when ALU_AND =>
+ result <= x and y;
+ when ALU_OR =>
+ result <= x or y;
+ when ALU_XOR =>
+ result <= x xor y;
+ when ALU_SLT =>
+ if signed(x) < signed(y) then
+ result <= (0 => '1', others => '0');
+ else
+ result <= (others => '0');
+ end if;
+ when ALU_SLTU =>
+ if unsigned(x) < unsigned(y) then
+ result <= (0 => '1', others => '0');
+ else
+ result <= (others => '0');
+ end if;
+ when ALU_ADD =>
+ result <= std_logic_vector(unsigned(x) + unsigned(y));
+ when ALU_SUB =>
+ result <= std_logic_vector(unsigned(x) - unsigned(y));
+ when ALU_SRL =>
+ result <= std_logic_vector(shift_right(unsigned(x), to_integer(unsigned(y(4 downto 0)))));
+ when ALU_SLL =>
+ result <= std_logic_vector(shift_left(unsigned(x), to_integer(unsigned(y(4 downto 0)))));
+ when ALU_SRA =>
+ result <= std_logic_vector(shift_right(signed(x), to_integer(unsigned(y(4 downto 0)))));
+ when others =>
+ result <= (others => '0');
+ end case;
+ end process calculate;
+
+end architecture behaviour;
Index: trunk/src/pp_register_file.vhd
===================================================================
--- trunk/src/pp_register_file.vhd (nonexistent)
+++ trunk/src/pp_register_file.vhd (revision 2)
@@ -0,0 +1,55 @@
+-- The Potato Processor - A simple processor for FPGAs
+-- (c) Kristian Klomsten Skordal 2014
+-- Report bugs and issues on
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+use work.pp_types.all;
+use work.pp_utilities.all;
+
+--! @brief 32-bit RISC-V register file.
+entity pp_register_file is
+ port(
+ clk : in std_logic;
+
+ -- Read port 1:
+ rs1_addr : in register_address;
+ rs1_data : out std_logic_vector(31 downto 0);
+
+ -- Read port 2:
+ rs2_addr : in register_address;
+ rs2_data : out std_logic_vector(31 downto 0);
+
+ -- Write port:
+ rd_addr : in register_address;
+ rd_data : in std_logic_vector(31 downto 0);
+ rd_write : in std_logic
+ );
+end entity pp_register_file;
+
+architecture behaviour of pp_register_file is
+
+ --! Register array type.
+ type regfile_array is array(0 to 31) of std_logic_vector(31 downto 0);
+
+ --! Register array.
+ --shared variable registers : regfile_array := (others => (others => '0')); -- Shared variable used to simulate write-first RAM
+
+begin
+
+ regfile: process(clk)
+ variable registers : regfile_array := (others => (others => '0'));
+ begin
+ if rising_edge(clk) then
+ if rd_write = '1' and rd_addr /= b"00000" then
+ registers(to_integer(unsigned(rd_addr))) := rd_data;
+ end if;
+
+ rs1_data <= registers(to_integer(unsigned(rs1_addr)));
+ rs2_data <= registers(to_integer(unsigned(rs2_addr)));
+ end if;
+ end process regfile;
+
+end architecture behaviour;
Index: trunk/src/pp_decode.vhd
===================================================================
--- trunk/src/pp_decode.vhd (nonexistent)
+++ trunk/src/pp_decode.vhd (revision 2)
@@ -0,0 +1,140 @@
+-- The Potato Processor - A simple processor for FPGAs
+-- (c) Kristian Klomsten Skordal 2014 - 2015
+-- Report bugs and issues on
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+use work.pp_types.all;
+use work.pp_constants.all;
+use work.pp_csr.all;
+
+--! @brief Instruction decode unit.
+entity pp_decode is
+ generic(
+ RESET_ADDRESS : std_logic_vector(31 downto 0);
+ PROCESSOR_ID : std_logic_vector(31 downto 0)
+ );
+ port(
+ clk : in std_logic;
+ reset : in std_logic;
+
+ flush : in std_logic;
+ stall : in std_logic;
+
+ -- Instruction input:
+ instruction_data : in std_logic_vector(31 downto 0);
+ instruction_address : in std_logic_vector(31 downto 0);
+ instruction_ready : in std_logic;
+ instruction_count : in std_logic;
+
+ -- Register addresses:
+ rs1_addr, rs2_addr, rd_addr : out register_address;
+ csr_addr : out csr_address;
+
+ -- Shamt value for shift operations:
+ shamt : out std_logic_vector(4 downto 0);
+ funct3 : out std_logic_vector(2 downto 0);
+
+ -- Immediate value for immediate instructions:
+ immediate : out std_logic_vector(31 downto 0);
+
+ -- Control signals:
+ rd_write : out std_logic;
+ branch : out branch_type;
+ alu_x_src : out alu_operand_source;
+ alu_y_src : out alu_operand_source;
+ alu_op : out alu_operation;
+ mem_op : out memory_operation_type;
+ mem_size : out memory_operation_size;
+ count_instruction : out std_logic;
+
+ -- Instruction address:
+ pc : out std_logic_vector(31 downto 0);
+
+ -- CSR control signals:
+ csr_write : out csr_write_mode;
+ csr_use_imm : out std_logic;
+
+ -- Exception output signals:
+ decode_exception : out std_logic;
+ decode_exception_cause : out csr_exception_cause
+ );
+
+end entity pp_decode;
+
+architecture behaviour of pp_decode is
+ signal instruction : std_logic_vector(31 downto 0);
+ signal immediate_value : std_logic_vector(31 downto 0);
+begin
+
+ immediate <= immediate_value;
+
+ get_instruction: process(clk)
+ begin
+ if rising_edge(clk) then
+ if reset = '1' then
+ instruction <= RISCV_NOP;
+ pc <= RESET_ADDRESS;
+ count_instruction <= '0';
+ elsif stall = '1' then
+ count_instruction <= '0';
+ elsif flush = '1' or instruction_ready = '0' then
+ instruction <= RISCV_NOP;
+ count_instruction <= '0';
+ else
+ instruction <= instruction_data;
+ count_instruction <= instruction_count;
+ pc <= instruction_address;
+ end if;
+ end if;
+ end process get_instruction;
+
+-- -- Extract register addresses from the instruction word:
+ rs1_addr <= instruction(19 downto 15);
+ rs2_addr <= instruction(24 downto 20);
+ rd_addr <= instruction(11 downto 7);
+
+ -- Extract the shamt value from the instruction word:
+ shamt <= instruction(24 downto 20);
+
+ -- Extract the value specifying which comparison to do in branch instructions:
+ funct3 <= instruction(14 downto 12);
+
+ -- Extract the immediate value from the instruction word:
+ immediate_decoder: entity work.pp_imm_decoder
+ port map(
+ instruction => instruction(31 downto 2),
+ immediate => immediate_value
+ );
+
+ decode_csr_addr: process(immediate_value)
+ begin
+ if immediate_value(11 downto 0) = CSR_EPC_SRET then
+ csr_addr <= CSR_EPC;
+ else
+ csr_addr <= immediate_value(11 downto 0);
+ end if;
+ end process decode_csr_addr;
+
+ control_unit: entity work.pp_control_unit
+ port map(
+ opcode => instruction(6 downto 2),
+ funct3 => instruction(14 downto 12),
+ funct7 => instruction(31 downto 25),
+ funct12 => instruction(31 downto 20),
+ rd_write => rd_write,
+ branch => branch,
+ alu_x_src => alu_x_src,
+ alu_y_src => alu_y_src,
+ alu_op => alu_op,
+ mem_op => mem_op,
+ mem_size => mem_size,
+ decode_exception => decode_exception,
+ decode_exception_cause => decode_exception_cause,
+ csr_write => csr_write,
+ csr_imm => csr_use_imm
+ );
+
+end architecture behaviour;
Index: trunk/src/pp_csr_unit.vhd
===================================================================
--- trunk/src/pp_csr_unit.vhd (nonexistent)
+++ trunk/src/pp_csr_unit.vhd (revision 2)
@@ -0,0 +1,221 @@
+-- The Potato Processor - A simple processor for FPGAs
+-- (c) Kristian Klomsten Skordal 2014 - 2015
+-- Report bugs and issues on
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+use work.pp_csr.all;
+
+entity pp_csr_unit is
+ generic(
+ PROCESSOR_ID : std_logic_vector(31 downto 0)
+ );
+ port(
+ clk, timer_clk : in std_logic;
+ reset : in std_logic;
+
+ -- Count retired instruction:
+ count_instruction : in std_logic;
+
+ -- HTIF interface:
+ fromhost_data : in std_logic_vector(31 downto 0);
+ fromhost_updated : in std_logic;
+ tohost_data : out std_logic_vector(31 downto 0);
+ tohost_updated : out std_logic;
+
+ -- Read port:
+ read_address : in csr_address;
+ read_data_out : out std_logic_vector(31 downto 0);
+ read_writeable : out boolean;
+
+ -- Write port:
+ write_address : in csr_address;
+ write_data_in : in std_logic_vector(31 downto 0);
+ write_mode : in csr_write_mode;
+
+ -- Exception context write port:
+ exception_context : in csr_exception_context;
+ exception_context_write : in std_logic;
+
+ -- Registers needed for exception handling, always read:
+ status_out : out csr_status_register;
+ evec_out : out std_logic_vector(31 downto 0)
+ );
+end entity pp_csr_unit;
+
+architecture behaviour of pp_csr_unit is
+
+ -- Implemented counters:
+ signal counter_time : std_logic_vector(63 downto 0);
+ signal counter_cycle : std_logic_vector(63 downto 0);
+ signal counter_instret : std_logic_vector(63 downto 0);
+
+ -- Implemented registers:
+ signal sup0, sup1 : std_logic_vector(31 downto 0) := (others => '0');
+ signal epc, evec : std_logic_vector(31 downto 0) := (others => '0');
+ signal badvaddr : std_logic_vector(31 downto 0) := (others => '0');
+ signal cause : csr_exception_cause;
+
+ -- HTIF FROMHOST register:
+ signal fromhost: std_logic_vector(31 downto 0);
+
+ -- Status register:
+ signal status_register : csr_status_register;
+
+begin
+
+ read_writeable <= csr_is_writeable(read_address);
+
+ --! Updates the FROMHOST register when new data is available.
+ htif_fromhost: process(clk)
+ begin
+ if rising_edge(clk) then
+ if fromhost_updated = '1' then
+ fromhost <= fromhost_data;
+ end if;
+ end if;
+ end process htif_fromhost;
+
+ --! Sends a word to the host over the HTIF interface.
+ htif_tohost: process(clk)
+ begin
+ if rising_edge(clk) then
+ if reset = '1' then
+ tohost_data <= (others => '0');
+ tohost_updated <= '0';
+ else
+ if write_mode /= CSR_WRITE_NONE and write_address = CSR_TOHOST then
+ tohost_data <= write_data_in;
+ tohost_updated <= '1';
+ else
+ tohost_updated <= '0';
+ end if;
+ end if;
+ end if;
+ end process htif_tohost;
+
+ write: process(clk)
+ begin
+ if rising_edge(clk) then
+ if reset = '1' then
+ status_register <= CSR_SR_DEFAULT;
+ else
+ if exception_context_write = '1' then
+ status_register <= exception_context.status;
+ cause <= exception_context.cause;
+ badvaddr <= exception_context.badvaddr;
+ end if;
+
+ if write_mode /= CSR_WRITE_NONE then
+ case write_address is
+ when CSR_STATUS =>
+ if exception_context_write = '0' then
+ status_register <= to_csr_status_register(write_data_in);
+ end if;
+ when CSR_EPC =>
+ epc <= write_data_in;
+ when CSR_EVEC =>
+ evec <= write_data_in;
+ when CSR_SUP0 =>
+ sup0 <= write_data_in;
+ when CSR_SUP1 =>
+ sup1 <= write_data_in;
+ when others =>
+ -- Ignore writes to invalid or read-only registers
+ end case;
+ end if;
+ end if;
+ end if;
+ end process write;
+
+ 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 write_mode /= CSR_WRITE_NONE and write_address = CSR_EVEC then
+ evec_out <= write_data_in;
+ else
+ evec_out <= evec;
+ end if;
+
+ if write_mode /= CSR_WRITE_NONE and write_address = read_address then
+ read_data_out <= write_data_in;
+ else
+ case read_address is
+
+ -- Status and control registers:
+ when CSR_STATUS => -- Status register
+ read_data_out <= to_std_logic_vector(status_register);
+ when CSR_HARTID => -- Processor ID
+ read_data_out <= PROCESSOR_ID;
+ when CSR_FROMHOST => -- Fromhost data
+ read_data_out <= fromhost;
+ when CSR_EPC | CSR_EPC_SRET => -- Exception PC value
+ read_data_out <= epc;
+ when CSR_EVEC => -- Exception handler address
+ read_data_out <= evec;
+ when CSR_CAUSE => -- Exception cause
+ read_data_out <= to_std_logic_vector(cause);
+ when CSR_BADVADDR => -- Load/store address responsible for the exception
+ read_data_out <= badvaddr;
+
+ -- Supporting registers:
+ when CSR_SUP0 =>
+ read_data_out <= sup0;
+ when CSR_SUP1 =>
+ read_data_out <= sup1;
+
+ -- Timers and counters:
+ when CSR_TIME =>
+ read_data_out <= counter_time(31 downto 0);
+ when CSR_TIMEH =>
+ read_data_out <= counter_time(63 downto 32);
+ when CSR_CYCLE =>
+ read_data_out <= counter_cycle(31 downto 0);
+ when CSR_CYCLEH =>
+ read_data_out <= counter_cycle(63 downto 32);
+ when CSR_INSTRET =>
+ read_data_out <= counter_instret(31 downto 0);
+ when CSR_INSTRETH =>
+ read_data_out <= counter_instret(63 downto 32);
+
+ -- Return zero from write-only registers and invalid register addresses:
+ when others =>
+ read_data_out <= (others => '0');
+ end case;
+ end if;
+ end if;
+ end process read;
+
+ timer_counter: entity work.pp_counter
+ port map(
+ clk => timer_clk,
+ reset => reset,
+ count => counter_time,
+ increment => '1'
+ );
+
+ cycle_counter: entity work.pp_counter
+ port map(
+ clk => clk,
+ reset => reset,
+ count => counter_cycle,
+ increment => '1'
+ );
+
+ instret_counter: entity work.pp_counter
+ port map(
+ clk => clk,
+ reset => reset,
+ count => counter_instret,
+ increment => count_instruction
+ );
+
+end architecture behaviour;
Index: trunk/src/pp_csr.vhd
===================================================================
--- trunk/src/pp_csr.vhd (nonexistent)
+++ trunk/src/pp_csr.vhd (revision 2)
@@ -0,0 +1,144 @@
+-- The Potato Processor - A simple processor for FPGAs
+-- (c) Kristian Klomsten Skordal 2014 - 2015
+-- Report bugs and issues on
+
+library ieee;
+use ieee.std_logic_1164.all;
+
+--! @brief Package containing constants and utility functions relating to status and control registers.
+package pp_csr is
+
+ --! Type used for specifying control and status register addresses.
+ subtype csr_address is std_logic_vector(11 downto 0);
+
+ --! Type used for exception cause values.
+ subtype csr_exception_cause is std_logic_vector(4 downto 0);
+
+ function to_std_logic_vector(input : in csr_exception_cause) return std_logic_vector;
+
+ --! Control/status register write mode:
+ type csr_write_mode is (
+ CSR_WRITE_NONE, CSR_WRITE_SET, CSR_WRITE_CLEAR, CSR_WRITE_REPLACE
+ );
+
+ -- Exception cause values:
+ constant CSR_CAUSE_INSTR_MISALIGN : csr_exception_cause := b"00000";
+ constant CSR_CAUSE_INSTR_FETCH : csr_exception_cause := b"00001";
+ constant CSR_CAUSE_INVALID_INSTR : csr_exception_cause := b"00010";
+ constant CSR_CAUSE_SYSCALL : csr_exception_cause := b"00110";
+ constant CSR_CAUSE_BREAKPOINT : csr_exception_cause := b"00111";
+ constant CSR_CAUSE_LOAD_MISALIGN : csr_exception_cause := b"01000";
+ constant CSR_CAUSE_STORE_MISALIGN : csr_exception_cause := b"01001";
+ constant CSR_CAUSE_LOAD_ERROR : csr_exception_cause := b"01010";
+ constant CSR_CAUSE_STORE_ERROR : csr_exception_cause := b"01011";
+ constant CSR_CAUSE_FROMHOST : csr_exception_cause := b"11110";
+ constant CSR_CAUSE_NONE : csr_exception_cause := b"11111";
+
+ constant CSR_CAUSE_IRQ_BASE : csr_exception_cause := b"10000";
+
+ -- Control register IDs, specified in the immediate of csr* instructions:
+ constant CSR_STATUS : csr_address := x"50a";
+ constant CSR_HARTID : csr_address := x"50b";
+ constant CSR_SUP0 : csr_address := x"500";
+ constant CSR_SUP1 : csr_address := x"501";
+ constant CSR_BADVADDR : csr_address := x"503";
+ constant CSR_TOHOST : csr_address := x"51e";
+ constant CSR_FROMHOST : csr_address := x"51f";
+ constant CSR_CYCLE : csr_address := x"c00";
+ constant CSR_CYCLEH : csr_address := x"c80";
+ constant CSR_TIME : csr_address := x"c01";
+ constant CSR_TIMEH : csr_address := x"c81";
+ constant CSR_INSTRET : csr_address := x"c02";
+ constant CSR_INSTRETH : csr_address := x"c82";
+ constant CSR_EPC : csr_address := x"502";
+ constant CSR_EVEC : csr_address := x"508";
+ constant CSR_CAUSE : csr_address := x"509";
+
+ -- Values used as control register IDs in SRET, SCALL and SBREAK:
+ constant CSR_EPC_SRET : csr_address := x"800";
+
+ -- Status register bit indices:
+ constant CSR_SR_S : natural := 0;
+ constant CSR_SR_PS : natural := 1;
+ constant CSR_SR_EI : natural := 2;
+ constant CSR_SR_PEI : natural := 3;
+
+ -- Status register in Potato:
+ -- * Bit 0, S: Supervisor mode, always 1
+ -- * Bit 1, PS: Previous supervisor mode bit, always 1
+ -- * Bit 2, EI: Enable interrupts bit
+ -- * Bit 3, PEI: Previous enable interrupts bit
+ -- * Bits 23 downto 16, IM: Interrupt mask
+ -- * Bits 31 downto 24, PIM: Previous interrupt mask
+
+ -- Status register record:
+ type csr_status_register is
+ record
+ ei, pei : std_logic;
+ im, pim : std_logic_vector(7 downto 0);
+ end record;
+
+ -- Exception context; this record contains all state that is stored
+ -- when an exception is taken.
+ type csr_exception_context is
+ record
+ status : csr_status_register;
+ cause : csr_exception_cause;
+ badvaddr : std_logic_vector(31 downto 0);
+ end record;
+
+ -- Reset value of the status register:
+ constant CSR_SR_DEFAULT : csr_status_register := (ei => '0', pei => '0', im => x"00", pim => x"00");
+
+ -- Converts a status register record into an std_logic_vector:
+ function to_std_logic_vector(input : in csr_status_register)
+ return std_logic_vector;
+
+ -- Converts an std_logic_vector into a status register record:
+ function to_csr_status_register(input : in std_logic_vector(31 downto 0))
+ return csr_status_register;
+
+ --! Checks if a control register is writeable.
+ function csr_is_writeable(csr : in csr_address) return boolean;
+
+end package pp_csr;
+
+package body pp_csr is
+
+ function to_std_logic_vector(input : in csr_exception_cause)
+ return std_logic_vector is
+ begin
+ return (31 downto 5 => '0') & input;
+ end function to_std_logic_vector;
+
+ function to_std_logic_vector(input : in csr_status_register)
+ return std_logic_vector is
+ begin
+ return input.pim & input.im & (15 downto 4 => '0') & input.pei & input.ei & '1' & '1';
+ end function to_std_logic_vector;
+
+ function to_csr_status_register(input : in std_logic_vector(31 downto 0))
+ return csr_status_register
+ is
+ variable retval : csr_status_register;
+ begin
+ retval.ei := input(CSR_SR_EI);
+ retval.pei := input(CSR_SR_PEI);
+ retval.im := input(23 downto 16);
+ retval.pim := input(31 downto 24);
+ return retval;
+ end function to_csr_status_register;
+
+ function csr_is_writeable(csr : in csr_address) return boolean is
+ begin
+ case csr is
+ when CSR_FROMHOST | CSR_CYCLE | CSR_CYCLEH | CSR_HARTID
+ | CSR_TIME | CSR_TIMEH | CSR_INSTRET | CSR_INSTRETH
+ | CSR_CAUSE | CSR_BADVADDR =>
+ return false;
+ when others =>
+ return true;
+ end case;
+ end function csr_is_writeable;
+
+end package body pp_csr;
Index: trunk/src/pp_csr_alu.vhd
===================================================================
--- trunk/src/pp_csr_alu.vhd (nonexistent)
+++ trunk/src/pp_csr_alu.vhd (revision 2)
@@ -0,0 +1,43 @@
+-- The Potato Processor - A simple processor for FPGAs
+-- (c) Kristian Klomsten Skordal 2014
+-- Report bugs and issues on
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+use work.pp_csr.all;
+
+--! @brief ALU used for calculating new values of control and status registers.
+entity pp_csr_alu is
+ port(
+ x, y : in std_logic_vector(31 downto 0);
+ result : out std_logic_vector(31 downto 0);
+ immediate : in std_logic_vector(4 downto 0);
+ use_immediate : in std_logic;
+ write_mode : in csr_write_mode
+ );
+end entity pp_csr_alu;
+
+architecture behaviour of pp_csr_alu is
+ signal a, b : std_logic_vector(31 downto 0);
+begin
+
+ a <= x;
+ b <= y when use_immediate = '0' else std_logic_vector(resize(unsigned(immediate), b'length));
+
+ calculate: process(a, b, write_mode)
+ begin
+ case write_mode is
+ when CSR_WRITE_NONE =>
+ result <= a;
+ when CSR_WRITE_SET =>
+ result <= a or b;
+ when CSR_WRITE_CLEAR =>
+ result <= a and (not b);
+ when CSR_WRITE_REPLACE =>
+ result <= b;
+ end case;
+ end process calculate;
+
+end architecture behaviour;
Index: trunk/src/pp_core.vhd
===================================================================
--- trunk/src/pp_core.vhd (nonexistent)
+++ trunk/src/pp_core.vhd (revision 2)
@@ -0,0 +1,436 @@
+-- The Potato Processor - A simple processor for FPGAs
+-- (c) Kristian Klomsten Skordal 2014 - 2015
+-- Report bugs and issues on
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+use work.pp_types.all;
+use work.pp_constants.all;
+use work.pp_utilities.all;
+use work.pp_csr.all;
+
+--! @brief The Potato Processor is a simple processor core for use in FPGAs.
+--! @details
+--! It implements the RV32I (RISC-V base integer subset) ISA with additional
+--! instructions for manipulation of control and status registers from the
+--! currently unpublished supervisor extension.
+entity pp_core is
+ generic(
+ PROCESSOR_ID : std_logic_vector(31 downto 0) := x"00000000"; --! Processor ID.
+ RESET_ADDRESS : std_logic_vector(31 downto 0) := x"00000000" --! Address of the first instruction to execute.
+ );
+ port(
+ -- Control inputs:
+ clk : in std_logic; --! Processor clock
+ reset : in std_logic; --! Reset signal
+
+ timer_clk : in std_logic; --! Clock used for the timer/counter
+
+ -- Instruction memory interface:
+ imem_address : out std_logic_vector(31 downto 0); --! Address of the next instruction
+ imem_data_in : in std_logic_vector(31 downto 0); --! Instruction input
+ imem_req : out std_logic;
+ imem_ack : in std_logic;
+
+ -- Data memory interface:
+ dmem_address : out std_logic_vector(31 downto 0); --! Data address
+ dmem_data_in : in std_logic_vector(31 downto 0); --! Input from the data memory
+ dmem_data_out : out std_logic_vector(31 downto 0); --! Ouptut to the data memory
+ dmem_data_size : out std_logic_vector( 1 downto 0); --! Size of the data, 1 = 8 bits, 2 = 16 bits, 0 = 32 bits.
+ dmem_read_req : out std_logic; --! Data memory read request
+ dmem_read_ack : in std_logic; --! Data memory read acknowledge
+ dmem_write_req : out std_logic; --! Data memory write request
+ dmem_write_ack : in std_logic; --! Data memory write acknowledge
+
+ -- Tohost/fromhost interface:
+ fromhost_data : in std_logic_vector(31 downto 0); --! Data from the host/simulator.
+ fromhost_write_en : in std_logic; --! Write enable signal from the host/simulator.
+ tohost_data : out std_logic_vector(31 downto 0); --! Data to the host/simulator.
+ tohost_write_en : out std_logic; --! Write enable signal to the host/simulator.
+
+ -- External interrupt input:
+ irq : in std_logic_vector(7 downto 0) --! IRQ inputs.
+ );
+end entity pp_core;
+
+architecture behaviour of pp_core is
+
+ ------- Flush signals -------
+ signal flush_if, flush_id, flush_ex : std_logic;
+
+ ------- Stall signals -------
+ signal stall_if, stall_id, stall_ex, stall_mem : std_logic;
+
+ -- Signals used to determine if an instruction should be counted
+ -- by the instret counter:
+ signal if_count_instruction, id_count_instruction : std_logic;
+ signal ex_count_instruction, mem_count_instruction : std_logic;
+ signal wb_count_instruction : std_logic;
+
+ -- CSR read port signals:
+ signal csr_read_data : std_logic_vector(31 downto 0);
+ signal csr_read_writeable : boolean;
+
+ -- Status register outputs:
+ signal status : csr_status_register;
+ signal evec : std_logic_vector(31 downto 0);
+
+ -- Load hazard detected in the execute stage:
+ signal load_hazard_detected : std_logic;
+
+ -- Branch targets:
+ signal exception_target, branch_target : std_logic_vector(31 downto 0);
+ signal branch_taken, exception_taken : std_logic;
+
+ -- Register file read ports:
+ signal rs1_address_p, rs2_address_p : register_address;
+ signal rs1_address, rs2_address : register_address;
+ signal rs1_data, rs2_data : std_logic_vector(31 downto 0);
+
+ -- Data memory signals:
+ signal dmem_address_p : std_logic_vector(31 downto 0);
+ signal dmem_data_size_p : std_logic_vector(1 downto 0);
+ signal dmem_data_out_p : std_logic_vector(31 downto 0);
+ signal dmem_read_req_p : std_logic;
+ signal dmem_write_req_p : std_logic;
+
+ -- Fetch stage signals:
+ signal if_instruction, if_pc : std_logic_vector(31 downto 0);
+ signal if_instruction_ready : std_logic;
+
+ -- Decode stage signals:
+ signal id_funct3 : std_logic_vector(2 downto 0);
+ signal id_rd_address : register_address;
+ signal id_rd_write : std_logic;
+ signal id_rs1_address : register_address;
+ signal id_rs2_address : register_address;
+ signal id_csr_address : csr_address;
+ signal id_csr_write : csr_write_mode;
+ signal id_csr_use_immediate : std_logic;
+ signal id_shamt : std_logic_vector(4 downto 0);
+ signal id_immediate : std_logic_vector(31 downto 0);
+ signal id_branch : branch_type;
+ signal id_alu_x_src, id_alu_y_src : alu_operand_source;
+ signal id_alu_op : alu_operation;
+ signal id_mem_op : memory_operation_type;
+ signal id_mem_size : memory_operation_size;
+ signal id_pc : std_logic_vector(31 downto 0);
+ signal id_exception : std_logic;
+ signal id_exception_cause : csr_exception_cause;
+
+ -- Execute stage signals:
+ signal ex_dmem_address : std_logic_vector(31 downto 0);
+ signal ex_dmem_data_size : std_logic_vector(1 downto 0);
+ signal ex_dmem_data_out : std_logic_vector(31 downto 0);
+ signal ex_dmem_read_req : std_logic;
+ signal ex_dmem_write_req : std_logic;
+ signal ex_rd_address : register_address;
+ signal ex_rd_data : std_logic_vector(31 downto 0);
+ signal ex_rd_write : std_logic;
+ signal ex_pc : std_logic_vector(31 downto 0);
+ signal ex_csr_address : csr_address;
+ signal ex_csr_write : csr_write_mode;
+ signal ex_csr_data : std_logic_vector(31 downto 0);
+ signal ex_branch : branch_type;
+ signal ex_mem_op : memory_operation_type;
+ signal ex_mem_size : memory_operation_size;
+ signal ex_exception_context : csr_exception_context;
+
+ -- Memory stage signals:
+ signal mem_rd_write : std_logic;
+ signal mem_rd_address : register_address;
+ signal mem_rd_data : std_logic_vector(31 downto 0);
+ signal mem_csr_address : csr_address;
+ signal mem_csr_write : csr_write_mode;
+ signal mem_csr_data : std_logic_vector(31 downto 0);
+ signal mem_mem_op : memory_operation_type;
+
+ signal mem_exception : std_logic;
+ signal mem_exception_context : csr_exception_context;
+
+ -- Writeback signals:
+ signal wb_rd_address : register_address;
+ signal wb_rd_data : std_logic_vector(31 downto 0);
+ signal wb_rd_write : std_logic;
+ signal wb_csr_address : csr_address;
+ signal wb_csr_write : csr_write_mode;
+ signal wb_csr_data : std_logic_vector(31 downto 0);
+
+ signal wb_exception : std_logic;
+ signal wb_exception_context : csr_exception_context;
+
+begin
+
+ stall_if <= stall_id;
+ stall_id <= stall_ex;
+ stall_ex <= load_hazard_detected or stall_mem;
+ stall_mem <= to_std_logic(memop_is_load(mem_mem_op) and dmem_read_ack = '0')
+ or to_std_logic(mem_mem_op = MEMOP_TYPE_STORE and dmem_write_ack = '0');
+
+ flush_if <= branch_taken or exception_taken;
+ flush_id <= branch_taken or exception_taken;
+ flush_ex <= branch_taken or exception_taken;
+
+ ------- Control and status module -------
+ csr_unit: entity work.pp_csr_unit
+ generic map(
+ PROCESSOR_ID => PROCESSOR_ID
+ ) port map(
+ clk => clk,
+ reset => reset,
+ timer_clk => timer_clk,
+ count_instruction => wb_count_instruction,
+ fromhost_data => fromhost_data,
+ fromhost_updated => fromhost_write_en,
+ tohost_data => tohost_data,
+ tohost_updated => tohost_write_en,
+ read_address => id_csr_address,
+ read_data_out => csr_read_data,
+ read_writeable => csr_read_writeable,
+ write_address => wb_csr_address,
+ write_data_in => wb_csr_data,
+ write_mode => wb_csr_write,
+ exception_context => wb_exception_context,
+ exception_context_write => wb_exception,
+ status_out => status,
+ evec_out => evec
+ );
+
+ ------- Register file -------
+ regfile: entity work.pp_register_file
+ port map(
+ clk => clk,
+ rs1_addr => rs1_address,
+ rs2_addr => rs2_address,
+ rs1_data => rs1_data,
+ rs2_data => rs2_data,
+ rd_addr => wb_rd_address,
+ rd_data => wb_rd_data,
+ rd_write => wb_rd_write
+ );
+
+ rs1_address <= id_rs1_address when stall_ex = '0' else rs1_address_p;
+ rs2_address <= id_rs2_address when stall_ex = '0' else rs2_address_p;
+
+ store_previous_rsaddr: process(clk, stall_ex)
+ begin
+ if rising_edge(clk) and stall_ex = '0' then
+ rs1_address_p <= id_rs1_address;
+ rs2_address_p <= id_rs2_address;
+ end if;
+ end process store_previous_rsaddr;
+
+ ------- Instruction Fetch (IF) Stage -------
+ fetch: entity work.pp_fetch
+ generic map(
+ RESET_ADDRESS => RESET_ADDRESS
+ ) port map(
+ clk => clk,
+ reset => reset,
+ imem_address => imem_address,
+ imem_data_in => imem_data_in,
+ imem_req => imem_req,
+ imem_ack => imem_ack,
+ stall => stall_if,
+ flush => flush_if,
+ branch => branch_taken,
+ exception => exception_taken,
+ branch_target => branch_target,
+ evec => exception_target,
+ instruction_data => if_instruction,
+ instruction_address => if_pc,
+ instruction_ready => if_instruction_ready
+ );
+ if_count_instruction <= if_instruction_ready;
+
+ ------- Instruction Decode (ID) Stage -------
+ decode: entity work.pp_decode
+ generic map(
+ RESET_ADDRESS => RESET_ADDRESS,
+ PROCESSOR_ID => PROCESSOR_ID
+ ) port map(
+ clk => clk,
+ reset => reset,
+ flush => flush_id,
+ stall => stall_id,
+ instruction_data => if_instruction,
+ instruction_address => if_pc,
+ instruction_ready => if_instruction_ready,
+ instruction_count => if_count_instruction,
+ funct3 => id_funct3,
+ rs1_addr => id_rs1_address,
+ rs2_addr => id_rs2_address,
+ rd_addr => id_rd_address,
+ csr_addr => id_csr_address,
+ shamt => id_shamt,
+ immediate => id_immediate,
+ rd_write => id_rd_write,
+ branch => id_branch,
+ alu_x_src => id_alu_x_src,
+ alu_y_src => id_alu_y_src,
+ alu_op => id_alu_op,
+ mem_op => id_mem_op,
+ mem_size => id_mem_size,
+ count_instruction => id_count_instruction,
+ pc => id_pc,
+ csr_write => id_csr_write,
+ csr_use_imm => id_csr_use_immediate,
+ decode_exception => id_exception,
+ decode_exception_cause => id_exception_cause
+ );
+
+ ------- Execute (EX) Stage -------
+ execute: entity work.pp_execute
+ port map(
+ clk => clk,
+ reset => reset,
+ stall => stall_ex,
+ flush => flush_ex,
+ irq => irq,
+ dmem_address => ex_dmem_address,
+ dmem_data_size => ex_dmem_data_size,
+ dmem_data_out => ex_dmem_data_out,
+ dmem_read_req => ex_dmem_read_req,
+ dmem_write_req => ex_dmem_write_req,
+ rs1_addr_in => rs1_address,
+ rs2_addr_in => rs2_address,
+ rd_addr_in => id_rd_address,
+ rd_addr_out => ex_rd_address,
+ rs1_data_in => rs1_data,
+ rs2_data_in => rs2_data,
+ shamt_in => id_shamt,
+ immediate_in => id_immediate,
+ funct3_in => id_funct3,
+ pc_in => id_pc,
+ pc_out => ex_pc,
+ csr_addr_in => id_csr_address,
+ csr_addr_out => ex_csr_address,
+ csr_write_in => id_csr_write,
+ csr_write_out => ex_csr_write,
+ csr_value_in => csr_read_data,
+ csr_value_out => ex_csr_data,
+ csr_writeable_in => csr_read_writeable,
+ csr_use_immediate_in => id_csr_use_immediate,
+ alu_op_in => id_alu_op,
+ alu_x_src_in => id_alu_x_src,
+ alu_y_src_in => id_alu_y_src,
+ rd_write_in => id_rd_write,
+ rd_write_out => ex_rd_write,
+ rd_data_out => ex_rd_data,
+ branch_in => id_branch,
+ branch_out => ex_branch,
+ mem_op_in => id_mem_op,
+ mem_op_out => ex_mem_op,
+ mem_size_in => id_mem_size,
+ mem_size_out => ex_mem_size,
+ count_instruction_in => id_count_instruction,
+ count_instruction_out => ex_count_instruction,
+ status_in => status,
+ evec_in => evec,
+ evec_out => exception_target,
+ decode_exception_in => id_exception,
+ decode_exception_cause_in => id_exception_cause,
+ exception_out => exception_taken,
+ exception_context_out => ex_exception_context,
+ jump_out => branch_taken,
+ jump_target_out => branch_target,
+ mem_rd_write => mem_rd_write,
+ mem_rd_addr => mem_rd_address,
+ mem_rd_value => mem_rd_data,
+ mem_csr_addr => mem_csr_address,
+ mem_csr_value => mem_csr_data,
+ mem_csr_write => mem_csr_write,
+ mem_exception => mem_exception,
+ mem_exception_context => mem_exception_context,
+ wb_rd_write => wb_rd_write,
+ wb_rd_addr => wb_rd_address,
+ wb_rd_value => wb_rd_data,
+ wb_csr_addr => wb_csr_address,
+ wb_csr_value => wb_csr_data,
+ wb_csr_write => wb_csr_write,
+ wb_exception => wb_exception,
+ wb_exception_context => wb_exception_context,
+ mem_mem_op => mem_mem_op,
+ hazard_detected => load_hazard_detected
+ );
+
+ dmem_address <= ex_dmem_address when stall_mem = '0' else dmem_address_p;
+ dmem_data_size <= ex_dmem_data_size when stall_mem = '0' else dmem_data_size_p;
+ dmem_data_out <= ex_dmem_data_out when stall_mem = '0' else dmem_data_out_p;
+ dmem_read_req <= ex_dmem_read_req when stall_mem = '0' else dmem_read_req_p;
+ dmem_write_req <= ex_dmem_write_req when stall_mem = '0' else dmem_write_req_p;
+
+ store_previous_dmem_address: process(clk, stall_mem)
+ begin
+ if rising_edge(clk) and stall_mem = '0' then
+ dmem_address_p <= ex_dmem_address;
+ dmem_data_size_p <= ex_dmem_data_size;
+ dmem_data_out_p <= ex_dmem_data_out;
+ dmem_read_req_p <= ex_dmem_read_req;
+ dmem_write_req_p <= ex_dmem_write_req;
+ end if;
+ end process store_previous_dmem_address;
+
+ ------- Memory (MEM) Stage -------
+ memory: entity work.pp_memory
+ port map(
+ clk => clk,
+ reset => reset,
+ stall => stall_mem,
+ dmem_data_in => dmem_data_in,
+ dmem_read_ack => dmem_read_ack,
+ dmem_write_ack => dmem_write_ack,
+ pc => ex_pc,
+ rd_write_in => ex_rd_write,
+ rd_write_out => mem_rd_write,
+ rd_data_in => ex_rd_data,
+ rd_data_out => mem_rd_data,
+ rd_addr_in => ex_rd_address,
+ rd_addr_out => mem_rd_address,
+ branch => ex_branch,
+ mem_op_in => ex_mem_op,
+ mem_op_out => mem_mem_op,
+ mem_size_in => ex_mem_size,
+ count_instr_in => ex_count_instruction,
+ count_instr_out => mem_count_instruction,
+ exception_in => exception_taken,
+ exception_out => mem_exception,
+ exception_context_in => ex_exception_context,
+ exception_context_out => mem_exception_context,
+ csr_addr_in => ex_csr_address,
+ csr_addr_out => mem_csr_address,
+ csr_write_in => ex_csr_write,
+ csr_write_out => mem_csr_write,
+ csr_data_in => ex_csr_data,
+ csr_data_out => mem_csr_data
+ );
+
+ ------- Writeback (WB) Stage -------
+ writeback: entity work.pp_writeback
+ port map(
+ clk => clk,
+ reset => reset,
+ count_instr_in => mem_count_instruction,
+ count_instr_out => wb_count_instruction,
+ exception_ctx_in => mem_exception_context,
+ exception_ctx_out => wb_exception_context,
+ exception_in => mem_exception,
+ exception_out => wb_exception,
+ csr_write_in => mem_csr_write,
+ csr_write_out => wb_csr_write,
+ csr_data_in => mem_csr_data,
+ csr_data_out => wb_csr_data,
+ csr_addr_in => mem_csr_address,
+ csr_addr_out => wb_csr_address,
+ rd_addr_in => mem_rd_address,
+ rd_addr_out => wb_rd_address,
+ rd_write_in => mem_rd_write,
+ rd_write_out => wb_rd_write,
+ rd_data_in => mem_rd_data,
+ rd_data_out => wb_rd_data
+ );
+
+end architecture behaviour;
+
Index: trunk/src/pp_fetch.vhd
===================================================================
--- trunk/src/pp_fetch.vhd (nonexistent)
+++ trunk/src/pp_fetch.vhd (revision 2)
@@ -0,0 +1,97 @@
+-- The Potato Processor - A simple processor for FPGAs
+-- (c) Kristian Klomsten Skordal 2014 - 2015
+-- Report bugs and issues on
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+use work.pp_constants.all;
+
+--! @brief Instruction fetch unit.
+entity pp_fetch is
+ generic(
+ RESET_ADDRESS : std_logic_vector(31 downto 0) := x"00000000"
+ );
+ port(
+ clk : in std_logic;
+ reset : in std_logic;
+
+ -- Instruction memory connections:
+ imem_address : out std_logic_vector(31 downto 0);
+ imem_data_in : in std_logic_vector(31 downto 0);
+ imem_req : out std_logic;
+ imem_ack : in std_logic;
+
+ -- Control inputs:
+ stall : in std_logic;
+ flush : in std_logic;
+ branch : in std_logic;
+ exception : in std_logic;
+
+ branch_target : in std_logic_vector(31 downto 0);
+ evec : in std_logic_vector(31 downto 0);
+
+ -- Outputs to the instruction decode unit:
+ instruction_data : out std_logic_vector(31 downto 0);
+ instruction_address : out std_logic_vector(31 downto 0);
+ instruction_ready : out std_logic
+ );
+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 cancel_fetch : std_logic;
+begin
+
+ imem_address <= pc_next;
+
+ 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)
+ begin
+ if rising_edge(clk) then
+ if reset = '1' then
+ pc <= RESET_ADDRESS;
+ cancel_fetch <= '0';
+ else
+ if (exception = '1' or branch = '1') and imem_ack = '0' then
+ cancel_fetch <= '1';
+ pc <= pc_next;
+ elsif cancel_fetch = '1' and imem_ack = '1' then
+ --pc <= pc_next;
+ cancel_fetch <= '0';
+ else
+ pc <= pc_next;
+ end if;
+ end if;
+ end if;
+ end process set_pc;
+
+ 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
+ pc_next <= evec;
+ elsif branch = '1' then
+ pc_next <= branch_target;
+ elsif imem_ack = '1' and stall = '0' and cancel_fetch = '0' then
+ pc_next <= std_logic_vector(unsigned(pc) + 4);
+ else
+ pc_next <= pc;
+ end if;
+ end process calc_next_pc;
+
+end architecture behaviour;
Index: trunk/testbenches/tb_soc_memory.vhd
===================================================================
--- trunk/testbenches/tb_soc_memory.vhd (nonexistent)
+++ trunk/testbenches/tb_soc_memory.vhd (revision 2)
@@ -0,0 +1,99 @@
+-- The Potato Processor - A simple processor for FPGAs
+-- (c) Kristian Klomsten Skordal 2014 - 2015
+-- Report bugs and issues on
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+entity tb_soc_memory is
+end entity tb_soc_memory;
+
+architecture testbench of tb_soc_memory is
+
+ -- Clock signal:
+ signal clk : std_logic;
+ constant clk_period : time := 10 ns;
+
+ -- Reset signal:
+ signal reset : std_logic := '1';
+
+ -- Wishbone signals:
+ signal wb_adr_in : std_logic_vector(31 downto 0);
+ signal wb_dat_in : std_logic_vector(31 downto 0);
+ signal wb_dat_out : std_logic_vector(31 downto 0);
+ signal wb_cyc_in : std_logic := '0';
+ signal wb_stb_in : std_logic := '0';
+ signal wb_sel_in : std_logic_vector(3 downto 0) := (others => '1');
+ signal wb_we_in : std_logic := '0';
+ signal wb_ack_out : std_logic;
+
+begin
+
+ uut: entity work.pp_soc_memory
+ port map(
+ clk => clk,
+ reset => reset,
+ wb_adr_in => wb_adr_in,
+ wb_dat_in => wb_dat_in,
+ wb_dat_out => wb_dat_out,
+ wb_cyc_in => wb_cyc_in,
+ wb_stb_in => wb_stb_in,
+ wb_sel_in => wb_sel_in,
+ wb_we_in => wb_we_in,
+ wb_ack_out => wb_ack_out
+ );
+
+ clock: process
+ begin
+ clk <= '1';
+ wait for clk_period / 2;
+ clk <= '0';
+ wait for clk_period / 2;
+ end process clock;
+
+ stimulus: process
+ begin
+ wait for clk_period;
+ reset <= '0';
+
+ -- Write 32 bit of data to address 0:
+ wb_adr_in <= x"00000000";
+ wb_dat_in <= x"deadbeef";
+ wb_cyc_in <= '1';
+ wb_stb_in <= '1';
+ wb_we_in <= '1';
+ wait for clk_period;
+ wb_stb_in <= '0';
+ wb_cyc_in <= '0';
+ wait for clk_period;
+
+ -- Write a block write of two 32-bit words at address 0 and 1:
+ wb_adr_in <= x"00000000";
+ wb_dat_in <= x"feedbeef";
+ wb_cyc_in <= '1';
+ wb_stb_in <= '1';
+ wait for clk_period;
+ wb_stb_in <= '0';
+ wb_adr_in <= x"00000004";
+ wb_dat_in <= x"f00dd00d";
+ wait for clk_period;
+ wb_stb_in <= '1';
+ wait for clk_period;
+ wb_stb_in <= '0';
+ wb_cyc_in <= '0';
+
+ -- Read address 4:
+ wait for clk_period;
+ wb_we_in <= '0';
+ wb_adr_in <= x"00000000";
+ wb_cyc_in <= '1';
+ wb_stb_in <= '1';
+ wait for clk_period;
+
+ -- TODO: Make this testbench automatic.
+
+ wait;
+ end process stimulus;
+
+end architecture testbench;
Index: trunk/testbenches/tb_processor.vhd
===================================================================
--- trunk/testbenches/tb_processor.vhd (nonexistent)
+++ trunk/testbenches/tb_processor.vhd (revision 2)
@@ -0,0 +1,291 @@
+-- The Potato Processor - A simple processor for FPGAs
+-- (c) Kristian Klomsten Skordal 2014
+-- Report bugs and issues on
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+use ieee.std_logic_textio.all;
+use std.textio.all;
+
+use work.pp_constants.all;
+
+entity tb_processor is
+ generic(
+ IMEM_SIZE : natural := 2048; --! Size of the instruction memory in bytes.
+ DMEM_SIZE : natural := 2048; --! Size of the data memory in bytes.
+ IMEM_FILENAME : string := "imem_testfile.hex"; --! File containing the contents of instruction memory.
+ DMEM_FILENAME : string := "dmem_testfile.hex" --! File containing the contents of data memory.
+ );
+end entity tb_processor;
+
+architecture testbench of tb_processor is
+
+ -- Processor component prototype:
+ component pp_core is
+ port(
+ -- Common inputs:
+ clk : in std_logic; --! Processor clock
+ reset : in std_logic; --! Reset signal
+ timer_clk : in std_logic; --! Timer clock input
+
+ -- Instruction memory interface:
+ imem_address : out std_logic_vector(31 downto 0); --! Address of the next instruction
+ imem_data_in : in std_logic_vector(31 downto 0); --! Instruction input
+ imem_req : out std_logic;
+ imem_ack : in std_logic;
+
+ -- Data memory interface:
+ dmem_address : out std_logic_vector(31 downto 0); --! Data address
+ dmem_data_in : in std_logic_vector(31 downto 0); --! Input from the data memory
+ dmem_data_out : out std_logic_vector(31 downto 0); --! Ouptut to the data memory
+ dmem_data_size : out std_logic_vector( 1 downto 0); --! Size of the data, 1 = 8 bits, 2 = 16 bits, 0 = 32 bits.
+ dmem_read_req : out std_logic; --! Data memory read request
+ dmem_read_ack : in std_logic; --! Data memory read acknowledge
+ dmem_write_req : out std_logic; --! Data memory write request
+ dmem_write_ack : in std_logic; --! Data memory write acknowledge
+
+ -- Tohost/fromhost interface:
+ fromhost_data : in std_logic_vector(31 downto 0); --! Data from the host/simulator.
+ fromhost_write_en : in std_logic; --! Write enable signal from the host/simulator.
+ tohost_data : out std_logic_vector(31 downto 0); --! Data to the host/simulator.
+ tohost_write_en : out std_logic; --! Write enable signal to the host/simulator.
+
+ -- External interrupt input:
+ irq : in std_logic_vector(7 downto 0) --! IRQ input
+ );
+ end component pp_core;
+
+ -- Clock signal:
+ signal clk : std_logic := '0';
+ constant clk_period : time := 10 ns;
+
+ -- Common inputs:
+ signal reset : std_logic := '1';
+
+ -- Instruction memory interface:
+ signal imem_address : std_logic_vector(31 downto 0);
+ signal imem_data_in : std_logic_vector(31 downto 0) := (others => '0');
+ signal imem_req : std_logic;
+ signal imem_ack : std_logic := '0';
+
+ -- Data memory interface:
+ signal dmem_address : std_logic_vector(31 downto 0);
+ signal dmem_data_in : std_logic_vector(31 downto 0) := (others => '0');
+ signal dmem_data_out : std_logic_vector(31 downto 0);
+ signal dmem_data_size : std_logic_vector( 1 downto 0);
+ signal dmem_read_req, dmem_write_req : std_logic;
+ signal dmem_read_ack, dmem_write_ack : std_logic := '1';
+
+ -- Tohost/Fromhost:
+ signal tohost_data : std_logic_vector(31 downto 0);
+ signal fromhost_data : std_logic_vectoR(31 downto 0) := (others => '0');
+ signal tohost_write_en : std_logic;
+ signal fromhost_write_en : std_logic := '0';
+
+ -- External interrupt input:
+ signal irq : std_logic_vector(7 downto 0) := (others => '0');
+
+ -- Simulation initialized:
+ signal imem_initialized, dmem_initialized, initialized : boolean := false;
+
+ -- Memory array type:
+ type memory_array is array(natural range <>) of std_logic_vector(7 downto 0);
+ constant IMEM_BASE : natural := 0;
+ constant IMEM_END : natural := IMEM_SIZE - 1;
+ constant DMEM_BASE : natural := IMEM_SIZE;
+ constant DMEM_END : natural := IMEM_SIZE + DMEM_SIZE - 1;
+
+ -- Memories:
+ signal imem_memory : memory_array(IMEM_BASE to IMEM_END);
+ signal dmem_memory : memory_array(DMEM_BASE to DMEM_END);
+
+ signal simulation_finished : boolean := false;
+
+begin
+
+ uut: pp_core
+ port map(
+ clk => clk,
+ reset => reset,
+ timer_clk => clk,
+ imem_address => imem_address,
+ imem_data_in => imem_data_in,
+ imem_req => imem_req,
+ imem_ack => imem_ack,
+ dmem_address => dmem_address,
+ dmem_data_in => dmem_data_in,
+ dmem_data_out => dmem_data_out,
+ 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,
+ tohost_data => tohost_data,
+ tohost_write_en => tohost_write_en,
+ fromhost_data => fromhost_data,
+ fromhost_write_en => fromhost_write_en,
+ irq => irq
+ );
+
+ clock: process
+ begin
+ clk <= '0';
+ wait for clk_period / 2;
+ clk <= '1';
+ wait for clk_period / 2;
+
+ if simulation_finished then
+ wait;
+ end if;
+ end process clock;
+
+ --! Initializes the instruction memory from file.
+ imem_init: process
+ file imem_file : text open READ_MODE is IMEM_FILENAME;
+ variable input_line : line;
+ variable input_index : natural;
+ variable input_value : std_logic_vector(31 downto 0);
+ begin
+ for i in IMEM_BASE / 4 to IMEM_END / 4 loop
+ if not endfile(imem_file) then
+ readline(imem_file, input_line);
+ hread(input_line, input_value);
+ imem_memory(i * 4 + 0) <= input_value( 7 downto 0);
+ imem_memory(i * 4 + 1) <= input_value(15 downto 8);
+ imem_memory(i * 4 + 2) <= input_value(23 downto 16);
+ imem_memory(i * 4 + 3) <= input_value(31 downto 24);
+ else
+ imem_memory(i * 4 + 0) <= RISCV_NOP( 7 downto 0);
+ imem_memory(i * 4 + 1) <= RISCV_NOP(15 downto 8);
+ imem_memory(i * 4 + 2) <= RISCV_NOP(23 downto 16);
+ imem_memory(i * 4 + 3) <= RISCV_NOP(31 downto 24);
+ end if;
+ end loop;
+
+ imem_initialized <= true;
+ wait;
+ end process imem_init;
+
+ --! Initializes and handles writes to the data memory.
+ dmem_init_and_write: process(clk)
+ file dmem_file : text open READ_MODE is DMEM_FILENAME;
+ variable input_line : line;
+ variable input_index : natural;
+ variable input_value : std_logic_vector(31 downto 0);
+ begin
+ if not dmem_initialized then
+ for i in DMEM_BASE / 4 to DMEM_END / 4 loop
+ if not endfile(dmem_file) then
+ readline(dmem_file, input_line);
+ hread(input_line, input_value);
+
+ -- Read from a big-endian file:
+ dmem_memory(i * 4 + 3) <= input_value( 7 downto 0);
+ dmem_memory(i * 4 + 2) <= input_value(15 downto 8);
+ dmem_memory(i * 4 + 1) <= input_value(23 downto 16);
+ dmem_memory(i * 4 + 0) <= input_value(31 downto 24);
+ else
+ dmem_memory(i * 4 + 0) <= (others => '0');
+ dmem_memory(i * 4 + 1) <= (others => '0');
+ dmem_memory(i * 4 + 2) <= (others => '0');
+ dmem_memory(i * 4 + 3) <= (others => '0');
+ end if;
+ end loop;
+
+ dmem_initialized <= true;
+ end if;
+
+ if rising_edge(clk) then
+ if dmem_write_ack = '1' then
+ dmem_write_ack <= '0';
+ elsif dmem_write_req = '1' then
+ case dmem_data_size is
+ when b"00" => -- 32 bits
+ dmem_memory(to_integer(unsigned(dmem_address)) + 0) <= dmem_data_out(7 downto 0);
+ dmem_memory(to_integer(unsigned(dmem_address)) + 1) <= dmem_data_out(15 downto 8);
+ dmem_memory(to_integer(unsigned(dmem_address)) + 2) <= dmem_data_out(23 downto 16);
+ dmem_memory(to_integer(unsigned(dmem_address)) + 3) <= dmem_data_out(31 downto 24);
+ when b"01" => -- 8 bits
+ dmem_memory(to_integer(unsigned(dmem_address))) <= dmem_data_out(7 downto 0);
+ when b"10" => -- 16 bits
+ dmem_memory(to_integer(unsigned(dmem_address)) + 0) <= dmem_data_out( 7 downto 0);
+ dmem_memory(to_integer(unsigned(dmem_address)) + 1) <= dmem_data_out(15 downto 8);
+ when others => -- Reserved for possible future 64 bit support
+ end case;
+ dmem_write_ack <= '1';
+ end if;
+ end if;
+ end process dmem_init_and_write;
+
+ initialized <= imem_initialized and dmem_initialized;
+
+ --! Instruction memory read process.
+ imem_read: process(clk)
+ begin
+ if rising_edge(clk) then
+ if reset = '1' then
+ imem_ack <= '0';
+ else
+ if to_integer(unsigned(imem_address)) > IMEM_END then
+ imem_data_in <= (others => 'X');
+ else
+ imem_data_in <= imem_memory(to_integer(unsigned(imem_address)) + 3)
+ & imem_memory(to_integer(unsigned(imem_address)) + 2)
+ & imem_memory(to_integer(unsigned(imem_address)) + 1)
+ & imem_memory(to_integer(unsigned(imem_address)) + 0);
+ end if;
+
+ imem_ack <= '1';
+ end if;
+ end if;
+ end process imem_read;
+
+ --! Data memory read process.
+ dmem_read: process(clk)
+ begin
+ if rising_edge(clk) then
+ if dmem_read_ack = '1' then
+ dmem_read_ack <= '0';
+ elsif dmem_read_req = '1' then
+ case dmem_data_size is
+ when b"00" => -- 32 bits
+ dmem_data_in <= dmem_memory(to_integer(unsigned(dmem_address) + 3))
+ & dmem_memory(to_integer(unsigned(dmem_address) + 2))
+ & dmem_memory(to_integer(unsigned(dmem_address) + 1))
+ & dmem_memory(to_integer(unsigned(dmem_address) + 0));
+ when b"10" => -- 16 bits
+ dmem_data_in(15 downto 8) <= dmem_memory(to_integer(unsigned(dmem_address)) + 1);
+ dmem_data_in( 7 downto 0) <= dmem_memory(to_integer(unsigned(dmem_address)) + 0);
+ when b"01" => -- 8 bits
+ dmem_data_in(7 downto 0) <= dmem_memory(to_integer(unsigned(dmem_address)));
+ when others => -- Reserved for possible future 64 bit support
+ end case;
+ dmem_read_ack <= '1';
+ end if;
+ end if;
+ end process dmem_read;
+
+ stimulus: process
+ begin
+ wait until initialized = true;
+ report "Testbench initialized, starting behavioural simulation..." severity NOTE;
+ wait for clk_period * 2;
+
+ -- Release the processor from reset:
+ reset <= '0';
+ wait for clk_period;
+
+ wait until tohost_write_en = '1';
+ wait for clk_period; -- Let the signal "settle", because of clock edges
+ if tohost_data = x"00000001" then
+ report "Success!" severity NOTE;
+ else
+ report "Failure in test " & integer'image(to_integer(shift_right(unsigned(tohost_data), 1))) & "!" severity NOTE;
+ end if;
+
+ simulation_finished <= true;
+ wait;
+ end process stimulus;
+
+end architecture testbench;
Index: trunk/testbenches/tb_soc.vhd
===================================================================
--- trunk/testbenches/tb_soc.vhd (nonexistent)
+++ trunk/testbenches/tb_soc.vhd (revision 2)
@@ -0,0 +1,296 @@
+-- The Potato Processor - A simple processor for FPGAs
+-- (c) Kristian Klomsten Skordal 2014
+-- Report bugs and issues on
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+use ieee.std_logic_textio.all;
+use std.textio.all;
+
+use work.pp_constants.all;
+use work.pp_utilities.all;
+
+--! @brief Testbench providing a full SoC architecture connected with a Wishbone bus.
+entity tb_soc is
+ generic(
+ IMEM_SIZE : natural := 2048; --! Size of the instruction memory in bytes.
+ DMEM_SIZE : natural := 2048; --! Size of the data memory in bytes.
+ IMEM_FILENAME : string := "imem_testfile.hex"; --! File containing the contents of instruction memory.
+ DMEM_FILENAME : string := "dmem_testfile.hex" --! File containing the contents of data memory.
+ );
+end entity tb_soc;
+
+architecture testbench of tb_soc is
+
+ -- Clock signals:
+ signal clk : std_logic;
+ constant clk_period : time := 10 ns;
+
+ -- Reset:
+ signal reset : std_logic := '1';
+
+ -- Interrupts:
+ signal irq : std_logic_vector(7 downto 0) := (others => '0');
+
+ -- HTIF:
+ signal fromhost_data, tohost_data : std_logic_vector(31 downto 0);
+ signal fromhost_updated : std_logic := '0';
+ signal tohost_updated : std_logic;
+
+ -- Instruction memory signals:
+ signal imem_adr_in : std_logic_vector(log2(IMEM_SIZE) - 1 downto 0);
+ signal imem_dat_in : std_logic_vector(31 downto 0);
+ signal imem_dat_out : std_logic_vector(31 downto 0);
+ signal imem_cyc_in : std_logic;
+ signal imem_stb_in : std_logic;
+ signal imem_sel_in : std_logic_vector(3 downto 0);
+ signal imem_we_in : std_logic;
+ signal imem_ack_out : std_logic;
+
+ -- Data memory signals:
+ signal dmem_adr_in : std_logic_vector(log2(DMEM_SIZE) - 1 downto 0);
+ signal dmem_dat_in : std_logic_vector(31 downto 0);
+ signal dmem_dat_out : std_logic_vector(31 downto 0);
+ signal dmem_cyc_in : std_logic;
+ signal dmem_stb_in : std_logic;
+ signal dmem_sel_in : std_logic_vector(3 downto 0);
+ signal dmem_we_in : std_logic;
+ signal dmem_ack_out : std_logic;
+
+ -- Processor signals:
+ signal p_adr_out : std_logic_vector(31 downto 0);
+ signal p_dat_out : std_logic_vector(31 downto 0);
+ signal p_dat_in : std_logic_vector(31 downto 0);
+ signal p_cyc_out : std_logic;
+ signal p_stb_out : std_logic;
+ signal p_sel_out : std_logic_vector(3 downto 0);
+ signal p_we_out : std_logic;
+ signal p_ack_in : std_logic;
+
+ -- Arbitrated wishbone signals:
+ signal wb_adr : std_logic_vector(31 downto 0);
+ signal wb_dat : std_logic_vector(31 downto 0);
+ signal wb_sel : std_logic_vector( 3 downto 0);
+ signal wb_cyc : std_logic;
+ signal wb_stb : std_logic;
+ signal wb_we : std_logic;
+
+ -- Initialization "module" signals:
+ signal init_adr_out : std_logic_vector(31 downto 0) := (others => '0');
+ signal init_dat_out : std_logic_vector(31 downto 0) := (others => '0');
+ signal init_cyc_out : std_logic := '0';
+ signal init_stb_out : std_logic := '0';
+ signal init_we_out : std_logic := '1';
+
+ -- Processor reset signals:
+ signal processor_reset : std_logic := '1';
+
+ -- Simulation control:
+ signal initialized : boolean := false;
+ signal simulation_finished : boolean := false;
+
+begin
+
+ processor: entity work.pp_potato
+ port map(
+ clk => clk,
+ reset => processor_reset,
+ irq => irq,
+ fromhost_data => fromhost_data,
+ fromhost_updated => fromhost_updated,
+ tohost_data => tohost_data,
+ tohost_updated => tohost_updated,
+ wb_adr_out => p_adr_out,
+ wb_sel_out => p_sel_out,
+ wb_cyc_out => p_cyc_out,
+ wb_stb_out => p_stb_out,
+ wb_we_out => p_we_out,
+ wb_dat_out => p_dat_out,
+ wb_dat_in => p_dat_in,
+ wb_ack_in => p_ack_in
+ );
+
+ imem: entity work.pp_soc_memory
+ generic map(
+ MEMORY_SIZE => IMEM_SIZE
+ ) port map(
+ clk => clk,
+ reset => reset,
+ wb_adr_in => imem_adr_in,
+ wb_dat_in => imem_dat_in,
+ wb_dat_out => imem_dat_out,
+ wb_cyc_in => imem_cyc_in,
+ wb_stb_in => imem_stb_in,
+ wb_sel_in => imem_sel_in,
+ wb_we_in => imem_we_in,
+ wb_ack_out => imem_ack_out
+ );
+
+ dmem: entity work.pp_soc_memory
+ generic map(
+ MEMORY_SIZE => DMEM_SIZE
+ ) port map(
+ clk => clk,
+ reset => reset,
+ wb_adr_in => dmem_adr_in,
+ wb_dat_in => dmem_dat_in,
+ wb_dat_out => dmem_dat_out,
+ wb_cyc_in => dmem_cyc_in,
+ wb_stb_in => dmem_stb_in,
+ wb_sel_in => dmem_sel_in,
+ wb_we_in => dmem_we_in,
+ wb_ack_out => dmem_ack_out
+ );
+
+ imem_adr_in <= wb_adr(imem_adr_in'range);
+ imem_dat_in <= wb_dat;
+ imem_we_in <= wb_we;
+ imem_sel_in <= wb_sel;
+ dmem_adr_in <= wb_adr(dmem_adr_in'range);
+ dmem_dat_in <= wb_dat;
+ dmem_we_in <= wb_we;
+ dmem_sel_in <= wb_sel;
+
+ address_decoder: process(wb_adr, imem_dat_out, imem_ack_out, dmem_dat_out, dmem_ack_out,
+ wb_cyc, wb_stb)
+ begin
+ if to_integer(unsigned(wb_adr)) < IMEM_SIZE then
+ p_dat_in <= imem_dat_out;
+ p_ack_in <= imem_ack_out;
+ imem_cyc_in <= wb_cyc;
+ imem_stb_in <= wb_stb;
+ dmem_cyc_in <= '0';
+ dmem_stb_in <= '0';
+ else
+ p_dat_in <= dmem_dat_out;
+ p_ack_in <= dmem_ack_out;
+ dmem_cyc_in <= wb_cyc;
+ dmem_stb_in <= wb_stb;
+ imem_cyc_in <= '0';
+ imem_stb_in <= '0';
+ end if;
+ end process address_decoder;
+
+ arbiter: process(initialized, init_adr_out, init_dat_out, init_cyc_out, init_stb_out, init_we_out,
+ p_adr_out, p_dat_out, p_cyc_out, p_stb_out, p_we_out, p_sel_out)
+ begin
+ if not initialized then
+ wb_adr <= init_adr_out;
+ wb_dat <= init_dat_out;
+ wb_cyc <= init_cyc_out;
+ wb_stb <= init_stb_out;
+ wb_we <= init_we_out;
+ wb_sel <= x"f";
+ else
+ wb_adr <= p_adr_out;
+ wb_dat <= p_dat_out;
+ wb_cyc <= p_cyc_out;
+ wb_stb <= p_stb_out;
+ wb_we <= p_we_out;
+ wb_sel <= p_sel_out;
+ end if;
+ end process arbiter;
+
+ initializer: process
+ file imem_file : text open READ_MODE is IMEM_FILENAME;
+ file dmem_file : text open READ_MODE is DMEM_FILENAME;
+ variable input_line : line;
+ variable input_index : natural;
+ variable input_value : std_logic_vector(31 downto 0);
+ variable temp : std_logic_vector(31 downto 0);
+
+ constant DMEM_START : natural := IMEM_SIZE;
+ begin
+ if not initialized then
+ -- Read the instruction memory file:
+ for i in 0 to IMEM_SIZE loop
+ exit when endfile(imem_file);
+
+ readline(imem_file, input_line);
+ hread(input_line, input_value);
+
+ init_adr_out <= std_logic_vector(to_unsigned(i * 4, init_adr_out'length));
+ init_dat_out <= input_value;
+ init_cyc_out <= '1';
+ init_stb_out <= '1';
+ wait until imem_ack_out = '1';
+ wait for clk_period;
+ init_stb_out <= '0';
+ wait until imem_ack_out = '0';
+ wait for clk_period;
+ end loop;
+
+ init_cyc_out <= '0';
+ init_stb_out <= '0';
+ wait for clk_period;
+
+ -- Read the data memory file:
+ for i in 0 to DMEM_SIZE loop
+ exit when endfile(dmem_file);
+
+ readline(dmem_file, input_line);
+ hread(input_line, input_value);
+
+
+ -- Swap endianness, TODO: prevent this, fix scripts/extract_hex.sh
+ temp(7 downto 0) := input_value(31 downto 24);
+ temp(15 downto 8) := input_value(23 downto 16);
+ temp(23 downto 16) := input_value(15 downto 8);
+ temp(31 downto 24) := input_value(7 downto 0);
+
+ input_value := temp;
+
+ init_adr_out <= std_logic_vector(to_unsigned(DMEM_START + (i * 4), init_adr_out'length));
+ init_dat_out <= input_value;
+ init_cyc_out <= '1';
+ init_stb_out <= '1';
+ wait until dmem_ack_out = '1';
+ wait for clk_period;
+ init_stb_out <= '0';
+ wait until dmem_ack_out = '0';
+ wait for clk_period;
+ end loop;
+
+ init_cyc_out <= '0';
+ init_stb_out <= '0';
+ wait for clk_period;
+
+ initialized <= true;
+ wait;
+ end if;
+ end process initializer;
+
+ clock: process
+ begin
+ clk <= '1';
+ wait for clk_period / 2;
+ clk <= '0';
+ wait for clk_period / 2;
+
+ if simulation_finished then
+ wait;
+ end if;
+ end process clock;
+
+ stimulus: process
+ begin
+ wait for clk_period * 2;
+ reset <= '0';
+
+ wait until initialized;
+ processor_reset <= '0';
+
+ wait until tohost_updated = '1';
+ wait for clk_period; -- Let the signal "settle", because of stupid clock edges
+ if tohost_data = x"00000001" then
+ report "Success!" severity NOTE;
+ else
+ report "Failure in test " & integer'image(to_integer(shift_right(unsigned(tohost_data), 1))) & "!" severity NOTE;
+ end if;
+
+ simulation_finished <= true;
+ wait;
+ end process stimulus;
+
+end architecture testbench;
Index: trunk/README.md
===================================================================
--- trunk/README.md (nonexistent)
+++ trunk/README.md (revision 2)
@@ -0,0 +1,41 @@
+# The Potato Processor
+
+Potato is a simple processor for use in FPGAs, implementing the RV32I subset of the RISC-V ISA specification.
+
+## Features
+
+* Supports the full RV32I (RISC-V 32-bit integer subset) ISA.
+* Additionally supports the csrr\* and sret instructions from the (previous) supervisor extension (draft).
+* Includes an interface for the HTIF (Host/Target interface) registers, TOHOST and FROMHOST.
+* Wishbone interface.
+
+## Wishbone details
+
+The wishbone interface for the processor is provided by the pp_wb_adapter module. Its details are as follows:
+
+| Name | Value |
+| --------------------- | ------------- |
+| Wishbone revision | B4 |
+| Interface type | Master |
+| Address port width | 32 bits |
+| Data port width | 32 bits |
+| Data port granularity | 8 bits |
+| Maximum operand size | 32 bits |
+| Endianess | Little endian |
+| Sequence of data xfer | Undefined |
+
+For all Wishbone interfaces included in this project, the Wishbone signals are prefixed with `wb` and suffixed by the
+signal direction.
+
+## Potato Processor Quick Start
+
+To instantiate the processor, add the source files from the `src/` folder to your project. Use the `pp_potato` core to
+instantiate a processor core with a Wishbone interface. Additional peripherals for use in Wishbone-based Potato systems
+can be found in the `soc/` folder.
+
+Use the `pp_core` module to instantiate a processor core with a more generic interface, for instance for use with block
+memories. In this instance, connect the data and instruction memory ports directly to the block RAM modules/interfaces
+and set the acknowledge inputs to `'1'`.
+
+Interrupts are triggered when an IRQ signal is high and the corresponding mask bit is set in the control/status register.
+
Index: trunk/Makefile
===================================================================
--- trunk/Makefile (nonexistent)
+++ trunk/Makefile (revision 2)
@@ -0,0 +1,146 @@
+# The Potato Processor - A simple RISC-V based processor for FPGAs
+# (c) Kristian Klomsten Skordal 2014 - 2015
+# Report bugs and issues on
+
+.PHONY: all clean checkout-riscv-tests potato.prj
+
+SOURCE_FILES := \
+ src/pp_alu.vhd \
+ src/pp_alu_mux.vhd \
+ src/pp_alu_control_unit.vhd \
+ src/pp_comparator.vhd \
+ src/pp_constants.vhd \
+ src/pp_control_unit.vhd \
+ src/pp_core.vhd \
+ src/pp_counter.vhd \
+ src/pp_csr.vhd \
+ src/pp_csr_unit.vhd \
+ src/pp_csr_alu.vhd \
+ src/pp_decode.vhd \
+ src/pp_execute.vhd \
+ src/pp_fetch.vhd \
+ src/pp_imm_decoder.vhd \
+ src/pp_memory.vhd \
+ src/pp_potato.vhd \
+ src/pp_register_file.vhd \
+ src/pp_types.vhd \
+ src/pp_utilities.vhd \
+ src/pp_wb_adapter.vhd \
+ src/pp_writeback.vhd
+TESTBENCHES := \
+ testbenches/tb_processor.vhd \
+ testbenches/tb_soc.vhd \
+ soc/pp_soc_memory.vhd
+
+TOOLCHAIN_PREFIX ?= riscv64-unknown-elf
+
+# ISA tests to use from the riscv-tests repository:
+RISCV_TESTS += \
+ simple \
+ add \
+ addi \
+ and \
+ andi \
+ auipc \
+ beq \
+ bge \
+ bgeu \
+ blt \
+ bltu \
+ bne \
+ jal \
+ jalr \
+ j \
+ or \
+ ori \
+ sll \
+ slli \
+ slt \
+ slti \
+ sra \
+ srai \
+ srl \
+ srli \
+ sub \
+ sb \
+ sh \
+ sw \
+ xor \
+ xori \
+ lb \
+ lbu \
+ lh \
+ lhu \
+ lw
+
+# Local tests to run:
+LOCAL_TESTS ?= \
+ scall \
+ sbreak
+
+all: potato.prj run-tests
+
+potato.prj:
+ -$(RM) potato.prj
+ for file in $(SOURCE_FILES) $(TESTBENCHES); do \
+ echo "vhdl work $$file" >> potato.prj; \
+ done
+
+checkout-riscv-tests:
+ if [ ! -d riscv-tests ]; then \
+ git clone https://github.com/ucb-bar/riscv-tests.git; \
+ pushd riscv-tests; \
+ git submodule update --init --recursive; \
+ popd; \
+ else \
+ pushd riscv-tests; \
+ git pull; \
+ popd; \
+ fi
+
+copy-riscv-tests: checkout-riscv-tests
+ for test in $(RISCV_TESTS); do \
+ cp riscv-tests/isa/rv32ui/$$test.S tests; \
+ done
+
+compile-tests: copy-riscv-tests
+ test -d tests-build || mkdir tests-build
+ for test in $(RISCV_TESTS) $(LOCAL_TESTS); do \
+ echo "Compiling test $$test..."; \
+ $(TOOLCHAIN_PREFIX)-gcc -I riscv-tests/env/p -c -I riscv-tests/isa/macros/scalar -m32 -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
+
+run-tests: potato.prj compile-tests
+ for test in $(RISCV_TESTS) $(LOCAL_TESTS); do \
+ echo -ne "Running test $$test:\t"; \
+ DMEM_FILENAME="empty_dmem.hex"; \
+ test -f tests-build/$$test-dmem.hex && DMEM_FILENAME="tests-build/$$test-dmem.hex"; \
+ xelab tb_processor -generic_top "IMEM_FILENAME=tests-build/$$test-imem.hex" -generic_top "DMEM_FILENAME=$$DMEM_FILENAME" -prj potato.prj > /dev/null; \
+ xsim tb_processor -R --onfinish quit > tests-build/$$test.results; \
+ cat tests-build/$$test.results | awk '/Note:/ {print}' | sed 's/Note://' | awk '/Success|Failure/ {print}'; \
+ done
+
+run-soc-tests: potato.prj compile-tests
+ for test in $(RISCV_TESTS) $(LOCAL_TESTS); do \
+ echo -ne "Running SOC test $$test:\t"; \
+ DMEM_FILENAME="empty_dmem.hex"; \
+ test -f tests-build/$$test-dmem.hex && DMEM_FILENAME="tests-build/$$test-dmem.hex"; \
+ xelab tb_soc -generic_top "IMEM_FILENAME=tests-build/$$test-imem.hex" -generic_top "DMEM_FILENAME=$$DMEM_FILENAME" -prj potato.prj > /dev/null; \
+ xsim tb_soc -R --onfinish quit > tests-build/$$test.results-soc; \
+ cat tests-build/$$test.results-soc | awk '/Note:/ {print}' | sed 's/Note://' | awk '/Success|Failure/ {print}'; \
+ done
+
+remove-xilinx-garbage:
+ -$(RM) -r xsim.dir
+ -$(RM) xelab.* webtalk* xsim*
+
+clean: remove-xilinx-garbage
+ for test in $(RISCV_TESTS); do $(RM) tests/$$test.S; done
+ -$(RM) -r tests-build
+ -$(RM) potato.prj
+
+distclean: clean
+ -$(RM) -r riscv-tests
+