OpenCores
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 +

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.