OpenCores
URL https://opencores.org/ocsvn/potato/potato/trunk

Subversion Repositories potato

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /potato/tags
    from Rev 1 to Rev 47
    Reverse comparison

Rev 1 → Rev 47

/v0.1/tests/sw-jal.S
0,0 → 1,41
# The Potato Processor - A simple RISC-V based processor for FPGAs
# (c) Kristian Klomsten Skordal 2014 - 2015 <kristian.skordal@wafflemail.net>
# Report bugs and issues on <http://opencores.org/project,potato,bugtracker>
 
#include "riscv_test.h"
#include "test_macros.h"
 
.section .text
RVTEST_RV32U
RVTEST_CODE_BEGIN
 
test_1:
li TESTNUM, 1
 
la ra, test_failed
la sp, temp
sw ra, 0(sp)
jal ra, test_cmp
 
1:
j fail
j pass
 
test_cmp:
la t0, 1b
bne ra, t0, fail
addi ra, ra, 4
ret
 
TEST_PASSFAIL
RVTEST_CODE_END
 
test_failed:
RVTEST_FAIL
# Allocate a 32-bit word to store some data into
.section .data
temp:
.word 0x00000000
 
 
/v0.1/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 <http://opencores.org/project,potato,bugtracker>
 
#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
 
/v0.1/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 <http://opencores.org/project,potato,bugtracker>
 
#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
 
/v0.1/src/pp_execute.vhd
0,0 → 1,519
-- The Potato Processor - A simple processor for FPGAs
-- (c) Kristian Klomsten Skordal 2014 - 2015 <kristian.skordal@wafflemail.net>
-- Report bugs and issues on <http://opencores.org/project,potato,bugtracker>
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
 
use work.pp_types.all;
use work.pp_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 do_jump : 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;
 
do_jump <= (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)) and not stall;
jump_out <= do_jump;
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) and not stall;
 
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: process(jump_target, branch, branch_condition, do_jump)
begin
if jump_target(1 downto 0) /= b"00" and do_jump = '1' then
instr_misaligned <= '1';
else
instr_misaligned <= '0';
end if;
end process instr_misalign_check;
 
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;
/v0.1/src/pp_types.vhd
0,0 → 1,70
-- The Potato Processor - A simple processor for FPGAs
-- (c) Kristian Klomsten Skordal 2014 - 2015 <kristian.skordal@wafflemail.net>
-- Report bugs and issues on <http://opencores.org/project,potato,bugtracker>
 
library ieee;
use ieee.std_logic_1164.all;
 
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, ALU_INVALID
);
 
--! 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
);
 
--! Wishbone master output signals:
type wishbone_master_outputs is record
adr : std_logic_vector(31 downto 0);
sel : std_logic_vector( 3 downto 0);
cyc : std_logic;
stb : std_logic;
we : std_logic;
dat : std_logic_vector(31 downto 0);
end record;
 
--! Wishbone master input signals:
type wishbone_master_inputs is record
dat : std_logic_vector(31 downto 0);
ack : std_logic;
end record;
 
end package pp_types;
 
package body pp_types is
 
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;
/v0.1/src/pp_potato.vhd
0,0 → 1,149
-- The Potato Processor - A simple processor for FPGAs
-- (c) Kristian Klomsten Skordal 2014 - 2015 <kristian.skordal@wafflemail.net>
-- Report bugs and issues on <http://opencores.org/project,potato,bugtracker>
 
library ieee;
use ieee.std_logic_1164.all;
 
use work.pp_types.all;
 
--! @brief 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;
 
-- Wishbone signals:
signal icache_inputs, dmem_if_inputs : wishbone_master_inputs;
signal icache_outputs, dmem_if_outputs : wishbone_master_outputs;
 
begin
processor: entity work.pp_core
generic map(
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
);
 
icache: entity work.pp_icache
generic map(
LINE_SIZE => 4,
NUM_LINES => 128
) port map(
clk => clk,
reset => reset,
cache_enable => '1',
cache_flush => '0',
cached_areas => (others => '1'),
mem_address_in => imem_address,
mem_data_out => imem_data,
mem_data_in => (others => '0'),
mem_data_size => b"00",
mem_read_req => imem_req,
mem_read_ack => imem_ack,
mem_write_req => '0',
mem_write_ack => open,
wb_inputs => icache_inputs,
wb_outputs => icache_outputs
);
 
dmem_if: entity work.pp_wb_adapter
port map(
clk => clk,
reset => reset,
dmem_address => dmem_address,
dmem_data_in => dmem_data_out,
dmem_data_out => dmem_data_in,
dmem_data_size => dmem_data_size,
dmem_read_req => dmem_read_req,
dmem_read_ack => dmem_read_ack,
dmem_write_req => dmem_write_req,
dmem_write_ack => dmem_write_ack,
wb_inputs => dmem_if_inputs,
wb_outputs => dmem_if_outputs
);
 
arbiter: entity work.pp_wb_arbiter
port map(
clk => clk,
reset => reset,
--m1_inputs => dmem_if_inputs,
--m1_outputs => dmem_if_outputs,
m1_inputs => icache_inputs,
m1_outputs => icache_outputs,
m2_inputs => dmem_if_inputs,
m2_outputs => dmem_if_outputs,
wb_adr_out => wb_adr_out,
wb_sel_out => wb_sel_out,
wb_cyc_out => wb_cyc_out,
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;
/v0.1/src/pp_wb_adapter.vhd
0,0 → 1,126
-- The Potato Processor - A simple processor for FPGAs
-- (c) Kristian Klomsten Skordal 2014 - 2015 <kristian.skordal@wafflemail.net>
-- Report bugs and issues on <http://opencores.org/project,potato,bugtracker>
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
 
use work.pp_types.all;
use work.pp_utilities.all;
 
--! @brief Wishbone adapter, for connecting the processor to a Wishbone bus when not using caches.
entity pp_wb_adapter is
port(
clk : in std_logic;
reset : in std_logic;
 
-- Processor data memory signals:
signal dmem_address : in std_logic_vector(31 downto 0);
signal dmem_data_in : in std_logic_vector(31 downto 0); -- Data in to the bus
signal dmem_data_out : out std_logic_vector(31 downto 0); -- Data out to the bus
signal dmem_data_size : in std_logic_vector( 1 downto 0);
signal dmem_read_req : in std_logic;
signal dmem_read_ack : out std_logic;
signal dmem_write_req : in std_logic;
signal dmem_write_ack : out std_logic;
 
-- Wishbone interface:
wb_inputs : in wishbone_master_inputs;
wb_outputs : out wishbone_master_outputs
);
end entity pp_wb_adapter;
 
architecture behaviour of pp_wb_adapter is
 
type states is (IDLE, READ_WAIT_ACK, WRITE_WAIT_ACK);
signal state : states;
 
signal dmem_r_ack : std_logic;
 
function get_data_shift(size : in std_logic_vector(1 downto 0); address : in std_logic_vector)
return natural is
begin
case size is
when b"01" =>
case address(1 downto 0) is
when b"00" =>
return 0;
when b"01" =>
return 8;
when b"10" =>
return 16;
when b"11" =>
return 24;
when others =>
return 0;
end case;
when b"10" =>
if address(1) = '0' then
return 0;
else
return 16;
end if;
when others =>
return 0;
end case;
end function get_data_shift;
 
begin
 
dmem_write_ack <= '1' when state = WRITE_WAIT_ACK and wb_inputs.ack = '1' else '0';
dmem_read_ack <= dmem_r_ack;
 
wishbone: process(clk)
begin
if rising_edge(clk) then
if reset = '1' then
state <= IDLE;
wb_outputs.cyc <= '0';
wb_outputs.stb <= '0';
dmem_r_ack <= '0';
else
case state is
when IDLE =>
dmem_r_ack <= '0';
 
-- Prioritize requests from the data memory:
if dmem_write_req = '1' then
wb_outputs.adr <= dmem_address;
wb_outputs.dat <= std_logic_vector(shift_left(unsigned(dmem_data_in),
get_data_shift(dmem_data_size, dmem_address)));
wb_outputs.sel <= wb_get_data_sel(dmem_data_size, dmem_address);
wb_outputs.cyc <= '1';
wb_outputs.stb <= '1';
wb_outputs.we <= '1';
state <= WRITE_WAIT_ACK;
elsif dmem_read_req = '1' then
wb_outputs.adr <= dmem_address;
wb_outputs.sel <= wb_get_data_sel(dmem_data_size, dmem_address);
wb_outputs.cyc <= '1';
wb_outputs.stb <= '1';
wb_outputs.we <= '0';
state <= READ_WAIT_ACK;
end if;
when READ_WAIT_ACK =>
if wb_inputs.ack = '1' then
dmem_data_out <= std_logic_vector(shift_right(unsigned(wb_inputs.dat),
get_data_shift(dmem_data_size, dmem_address)));
wb_outputs.cyc <= '0';
wb_outputs.stb <= '0';
dmem_r_ack <= '1';
state <= IDLE;
end if;
when WRITE_WAIT_ACK =>
if wb_inputs.ack = '1' then
wb_outputs.cyc <= '0';
wb_outputs.stb <= '0';
wb_outputs.we <= '0';
state <= IDLE;
end if;
end case;
end if;
end if;
end process wishbone;
 
end architecture behaviour;
v0.1/src/pp_wb_adapter.vhd Property changes : Added: svn:mergeinfo ## -0,0 +0,1 ## Merged /potato/branches/cache-playground/src/pp_wb_adapter.vhd:r31-33,44 Index: v0.1/src/pp_memory.vhd =================================================================== --- v0.1/src/pp_memory.vhd (nonexistent) +++ v0.1/src/pp_memory.vhd (revision 47) @@ -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 => (others => '0'), + 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: v0.1/src/pp_utilities.vhd =================================================================== --- v0.1/src/pp_utilities.vhd (nonexistent) +++ v0.1/src/pp_utilities.vhd (revision 47) @@ -0,0 +1,94 @@ +-- 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; + + -- Gets the value of the sel signals to the wishbone interconnect for the specified + -- operand size and address. + function wb_get_data_sel(size : in std_logic_vector(1 downto 0); address : in std_logic_vector) + return std_logic_vector; + +end package pp_utilities; + +package body pp_utilities is + + 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 30 loop -- FIXME: Simulator complains about 2^31 being out of range! + 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; + + function wb_get_data_sel(size : in std_logic_vector(1 downto 0); address : in std_logic_vector) + return std_logic_vector is + begin + case size is + when b"01" => + case address(1 downto 0) is + when b"00" => + return b"0001"; + when b"01" => + return b"0010"; + when b"10" => + return b"0100"; + when b"11" => + return b"1000"; + when others => + return b"0001"; + end case; + when b"10" => + if address(1) = '0' then + return b"0011"; + else + return b"1100"; + end if; + when others => + return b"1111"; + end case; + end function wb_get_data_sel; + +end package body pp_utilities; Index: v0.1/src/pp_icache.vhd =================================================================== --- v0.1/src/pp_icache.vhd (nonexistent) +++ v0.1/src/pp_icache.vhd (revision 47) @@ -0,0 +1,293 @@ +-- 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_utilities.all; + +--! @brief Simple read-only direct-mapped instruction cache. +entity pp_icache is + generic( + LINE_SIZE : natural := 4; --! Number of words per cache line + NUM_LINES : natural := 128 --! Number of lines in the cache + ); + port( + clk : in std_logic; + reset : in std_logic; + + -- Control interface: + cache_enable : in std_logic; + cache_flush : in std_logic; + cached_areas : in std_logic_vector(31 downto 0); + + -- Memory interface: + mem_address_in : in std_logic_vector(31 downto 0); + mem_data_in : in std_logic_vector(31 downto 0); + mem_data_out : out std_logic_vector(31 downto 0); + mem_data_size : in std_logic_vector( 1 downto 0); + mem_read_req : in std_logic; + mem_read_ack : out std_logic; + mem_write_req : in std_logic; + mem_write_ack : out std_logic; + + -- Wishbone interface: + wb_inputs : in wishbone_master_inputs; + wb_outputs : out wishbone_master_outputs + ); +end entity pp_icache; + +architecture behaviour of pp_icache is + + -- Counter types: + subtype line_counter_type is natural range 0 to NUM_LINES; + subtype word_counter_type is natural range 0 to LINE_SIZE; + + -- Cache line types: + subtype cache_line_type is std_logic_vector((LINE_SIZE * 32) - 1 downto 0); + type cache_line_word_array is array(0 to LINE_SIZE - 1) of std_logic_vector(31 downto 0); + type cache_line_array is array(0 to NUM_LINES - 1) of cache_line_type; + + -- Cache tag type: + subtype cache_tag_type is std_logic_vector(31 - log2(LINE_SIZE * 4) - log2(NUM_LINES) downto 0); + type cache_tag_array is array(0 to NUM_LINES - 1) of cache_tag_type; + + -- Cache memories: + signal cache_memory : cache_line_array; + signal tag_memory : cache_tag_array; + signal valid : std_logic_vector(NUM_LINES - 1 downto 0) := (others => '0'); + + attribute ram_style : string; + attribute ram_style of cache_memory: signal is "block"; + --attribute ram_style of tag_memory: signal is "block"; + + -- Cache controller signals: + type state_type is (IDLE, CACHE_READ_STALL, SINGLE_READ, SINGLE_WRITE, + LOAD_CACHELINE_START, LOAD_CACHELINE_WAIT_ACK, LOAD_CACHELINE_FINISH); + signal state : state_type := IDLE; + + -- Is the current input address in the cache? + signal input_address_cached : boolean; + + -- Input address components: + signal input_address_line : std_logic_vector(log2(NUM_LINES) - 1 downto 0); + signal input_address_word : std_logic_vector(log2(LINE_SIZE) - 1 downto 0); + signal input_address_tag : std_logic_vector(31 - log2(LINE_SIZE * 4) - log2(NUM_LINES) downto 0); + + -- Cacheline matching the current input address: + signal current_cache_line, cache_lookup : cache_line_type; + signal current_cache_line_words : cache_line_word_array; + signal current_tag : cache_tag_type; + + -- Base address to store a cacheline to: + signal cl_store_address : std_logic_vector(31 downto log2(LINE_SIZE * 4)); + -- Base address to load a cacheline from: + signal cl_load_address : std_logic_vector(31 downto log2(LINE_SIZE * 4)); + -- Cache line to load: + signal cl_current_line : line_counter_type; + -- Current word being loaded/stored: + signal cl_current_word : word_counter_type; + + -- Buffer for holding a cache line while loading: + signal load_buffer : cache_line_type; + signal load_buffer_tag : cache_tag_type; + + -- Causes a cache line to be stored in the cache memory: + signal store_cache_line : std_logic; + + -- Set when the current input address matches a cache line: + signal cache_hit : std_logic; + + -- For regular reads: + signal read_ack : std_logic; + signal read_data_out : std_logic_vector(31 downto 0); + + -- For regular writes: + signal write_ack : std_logic; + + -- Gets the amount to shift output data to the processor with for requests of size != 32 bits: + function get_data_shift(size : in std_logic_vector(1 downto 0); address : in std_logic_vector) + return natural is + begin + case size is + when b"01" => + case address(1 downto 0) is + when b"00" => + return 0; + when b"01" => + return 8; + when b"10" => + return 16; + when b"11" => + return 24; + when others => + return 0; + end case; + when b"10" => + if address(1) = '0' then + return 0; + else + return 16; + end if; + when others => + return 0; + end case; + end function get_data_shift; + +begin + + --assert is_pow2(LINE_SIZE) report "Cache line size must be a power of 2!" severity FAILURE; + --assert is_pow2(NUM_LINES) report "Number of cache lines must be a power of 2!" severity FAILURE; + + -- Check if the current input address should be/is in the cache: + input_address_cached <= cached_areas(to_integer(unsigned(mem_address_in(31 downto 27)))) = '1'; + + mem_data_out <= current_cache_line_words(to_integer(unsigned(input_address_word))) when + input_address_cached and cache_enable = '1' and cache_flush = '0' + else read_data_out; + mem_read_ack <= (cache_hit and mem_read_req) + when state = IDLE and input_address_cached and cache_enable = '1' and cache_flush = '0' + else read_ack; + write_ack <= wb_inputs.ack when state = SINGLE_WRITE else '0'; + mem_write_ack <= write_ack; + + input_address_line <= mem_address_in(log2(LINE_SIZE * 4) + log2(NUM_LINES) - 1 downto log2(LINE_SIZE * 4)); + input_address_tag <= mem_address_in(31 downto log2(LINE_SIZE * 4) + log2(NUM_LINES)); + + find_word: process(clk) + begin + if rising_edge(clk) then + input_address_word <= mem_address_in(log2(LINE_SIZE * 4) - 1 downto 2); + end if; + end process find_word; + + cacheline_lookup: process(clk) + begin + if rising_edge(clk) then + if store_cache_line = '1' then + cache_memory(cl_current_line) <= load_buffer; + end if; + + current_cache_line <= cache_memory(to_integer(unsigned(input_address_line))); + end if; + end process cacheline_lookup; + + decompose_cache_line: for i in 0 to LINE_SIZE - 1 generate + current_cache_line_words(i) <= current_cache_line(32 * i + 31 downto 32 * i); + end generate decompose_cache_line; + + tag_lookup: process(clk) + begin + if rising_edge(clk) then + if reset = '1' then + cache_hit <= '0'; + else + if store_cache_line = '1' then + tag_memory(cl_current_line) <= load_buffer_tag; + end if; + + current_tag <= tag_memory(to_integer(unsigned(input_address_line))); + cache_hit <= valid(to_integer(unsigned(input_address_line))) and to_std_logic(tag_memory(to_integer(unsigned(input_address_line))) = input_address_tag); + end if; + end if; + end process tag_lookup; + + controller: process(clk) + variable current_word : std_logic_vector(31 downto 0); + begin + if rising_edge(clk) then + if reset = '1' then + state <= IDLE; + wb_outputs.cyc <= '0'; + wb_outputs.stb <= '0'; + store_cache_line <= '0'; + read_ack <= '0'; + valid <= (others => '0'); + read_data_out <= (others => '0'); + else + case state is + when IDLE => + read_ack <= '0'; + if cache_flush = '1' then + valid <= (others => '0'); + elsif input_address_cached and cache_enable = '1' then + if (mem_read_req = '1' or mem_write_req = '1') and cache_hit = '0' then + wb_outputs.adr <= mem_address_in(31 downto log2(LINE_SIZE * 4)) & (log2(LINE_SIZE * 4) - 1 downto 0 => '0'); + wb_outputs.cyc <= '1'; + wb_outputs.we <= '0'; + wb_outputs.sel <= (others => '1'); + load_buffer_tag <= input_address_tag; + cl_load_address <= mem_address_in(31 downto log2(LINE_SIZE * 4)); + cl_store_address <= input_address_tag & input_address_line; + cl_current_line <= to_integer(unsigned(input_address_line)); + cl_current_word <= 0; + state <= LOAD_CACHELINE_START; + end if; + else + if mem_read_req = '1' and read_ack = '0' then -- Do an uncached read + wb_outputs.adr <= mem_address_in; + wb_outputs.sel <= wb_get_data_sel(mem_data_size, mem_address_in); + wb_outputs.cyc <= '1'; + wb_outputs.stb <= '1'; + wb_outputs.we <= '0'; + state <= SINGLE_READ; + elsif mem_write_req = '1' then -- Do an uncached write + wb_outputs.adr <= mem_address_in; + wb_outputs.dat <= std_logic_vector(shift_left(unsigned(mem_data_in), + get_data_shift(mem_data_size, mem_address_in))); + wb_outputs.sel <= wb_get_data_sel(mem_data_size, mem_address_in); + wb_outputs.cyc <= '1'; + wb_outputs.stb <= '1'; + wb_outputs.we <= '1'; + state <= SINGLE_WRITE; + end if; + end if; + when CACHE_READ_STALL => + state <= IDLE; + when SINGLE_READ => + if wb_inputs.ack = '1' then + read_data_out <= std_logic_vector(shift_right(unsigned(wb_inputs.dat), + get_data_shift(mem_data_size, mem_address_in))); + wb_outputs.cyc <= '0'; + wb_outputs.stb <= '0'; + read_ack <= '1'; + state <= IDLE; + end if; + when SINGLE_WRITE => + if wb_inputs.ack = '1' then + wb_outputs.cyc <= '0'; + wb_outputs.stb <= '0'; + wb_outputs.we <= '0'; + state <= IDLE; + end if; + when LOAD_CACHELINE_START => + wb_outputs.stb <= '1'; + wb_outputs.we <= '0'; + wb_outputs.adr <= cl_load_address & std_logic_vector(to_unsigned(cl_current_word, log2(LINE_SIZE))) & b"00"; + state <= LOAD_CACHELINE_WAIT_ACK; + when LOAD_CACHELINE_WAIT_ACK => + if wb_inputs.ack = '1' then + wb_outputs.stb <= '0'; + load_buffer(cl_current_word * 32 + 31 downto cl_current_word * 32) <= wb_inputs.dat; + if natural(cl_current_word) = LINE_SIZE - 1 then + wb_outputs.cyc <= '0'; + store_cache_line <= '1'; + state <= LOAD_CACHELINE_FINISH; + else + cl_current_word <= cl_current_word + 1; + state <= LOAD_CACHELINE_START; + end if; + end if; + when LOAD_CACHELINE_FINISH => + store_cache_line <= '0'; + valid(cl_current_line) <= '1'; + state <= CACHE_READ_STALL; + end case; + end if; + end if; + end process controller; + +end architecture behaviour; Index: v0.1/src/pp_wb_arbiter.vhd =================================================================== --- v0.1/src/pp_wb_arbiter.vhd (nonexistent) +++ v0.1/src/pp_wb_arbiter.vhd (revision 47) @@ -0,0 +1,100 @@ +-- 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; + +--! @brief Simple priority-based wishbone arbiter. +--! This module is used as an arbiter between the instruction and data caches. +entity pp_wb_arbiter is + port( + clk : in std_logic; + reset : in std_logic; + + -- Wishbone input 1: + m1_inputs : out wishbone_master_inputs; + m1_outputs : in wishbone_master_outputs; + + -- Wishbone input 2: + m2_inputs : out wishbone_master_inputs; + m2_outputs : in wishbone_master_outputs; + + -- Wishbone interface: + wb_adr_out : out std_logic_vector(31 downto 0); + wb_sel_out : out std_logic_vector( 3 downto 0); + wb_cyc_out : out std_logic; + wb_stb_out : out std_logic; + wb_we_out : out std_logic; + wb_dat_out : out std_logic_vector(31 downto 0); + wb_dat_in : in std_logic_vector(31 downto 0); + wb_ack_in : in std_logic + ); +end entity pp_wb_arbiter; + +architecture behaviour of pp_wb_arbiter is + + type state_type is (IDLE, M1_BUSY, M2_BUSY); + signal state : state_type := IDLE; + +begin + + m1_inputs <= (ack => wb_ack_in, dat => wb_dat_in) when state = M1_BUSY else (ack => '0', dat => (others => '0')); + m2_inputs <= (ack => wb_ack_in, dat => wb_dat_in) when state = M2_BUSY else (ack => '0', dat => (others => '0')); + + output_mux: process(state, m1_outputs, m2_outputs) + begin + case state is + when IDLE => + wb_adr_out <= (others => '0'); + wb_sel_out <= (others => '0'); + wb_dat_out <= (others => '0'); + wb_cyc_out <= '0'; + wb_stb_out <= '0'; + wb_we_out <= '0'; + when M1_BUSY => + wb_adr_out <= m1_outputs.adr; + wb_sel_out <= m1_outputs.sel; + wb_dat_out <= m1_outputs.dat; + wb_cyc_out <= m1_outputs.cyc; + wb_stb_out <= m1_outputs.stb; + wb_we_out <= m1_outputs.we; + when M2_BUSY => + wb_adr_out <= m2_outputs.adr; + wb_sel_out <= m2_outputs.sel; + wb_dat_out <= m2_outputs.dat; + wb_cyc_out <= m2_outputs.cyc; + wb_stb_out <= m2_outputs.stb; + wb_we_out <= m2_outputs.we; + end case; + end process output_mux; + + controller: process(clk) + begin + if rising_edge(clk) then + if reset = '1' then + state <= IDLE; + else + case state is + when IDLE => + if m1_outputs.cyc = '1' then + state <= M1_BUSY; + elsif m2_outputs.cyc = '1' then + state <= M2_BUSY; + end if; + when M1_BUSY => + if m1_outputs.cyc = '0' then + state <= IDLE; + end if; + when M2_BUSY => + if m2_outputs.cyc = '0' then + state <= IDLE; + end if; + end case; + end if; + end if; + end process controller; + +end architecture behaviour; Index: v0.1/src/pp_csr_unit.vhd =================================================================== --- v0.1/src/pp_csr_unit.vhd (nonexistent) +++ v0.1/src/pp_csr_unit.vhd (revision 47) @@ -0,0 +1,223 @@ +-- 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; + + status_out <= exception_context.status when exception_context_write = '1' else status_register; + + read: process(clk) + begin + if rising_edge(clk) then + --if exception_context_write = '1' then + -- status_out <= exception_context.status; + --else + -- status_out <= status_register; + --end if; + + if 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: v0.1/src/pp_fetch.vhd =================================================================== --- v0.1/src/pp_fetch.vhd (nonexistent) +++ v0.1/src/pp_fetch.vhd (revision 47) @@ -0,0 +1,89 @@ +-- 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 : 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 when cancel_fetch = '0' else pc; + + instruction_data <= imem_data_in; + instruction_ready <= imem_ack and (not stall) and (not cancel_fetch); + instruction_address <= pc; + + imem_req <= '1'; + + 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 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: v0.1/src/pp_core.vhd =================================================================== --- v0.1/src/pp_core.vhd (nonexistent) +++ v0.1/src/pp_core.vhd (revision 47) @@ -0,0 +1,446 @@ +-- 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; + signal csr_read_address, csr_read_address_p : csr_address; + + -- 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) and not stall_if; + flush_id <= (branch_taken or exception_taken) and not stall_id; + flush_ex <= (branch_taken or exception_taken) and not stall_ex; + + ------- 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 => csr_read_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 + ); + + csr_read_address <= id_csr_address when stall_ex = '0' else csr_read_address_p; + + store_previous_csr_addr: process(clk, stall_ex) + begin + if rising_edge(clk) and stall_ex = '0' then + csr_read_address_p <= id_csr_address; + end if; + end process store_previous_csr_addr; + + ------- 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 => csr_read_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: v0.1/src/pp_control_unit.vhd =================================================================== --- v0.1/src/pp_control_unit.vhd (nonexistent) +++ v0.1/src/pp_control_unit.vhd (revision 47) @@ -0,0 +1,220 @@ +-- 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_constants.all; +use work.pp_csr.all; +use work.pp_types.all; +use work.pp_utilities.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 + signal exception : std_logic; + signal exception_cause : std_logic_vector(4 downto 0); + signal alu_op_temp : alu_operation; +begin + + csr_imm <= funct3(2); + alu_op <= alu_op_temp; + + decode_exception <= exception or to_std_logic(alu_op_temp = ALU_INVALID); + decode_exception_cause <= exception_cause when alu_op_temp /= ALU_INVALID + else CSR_CAUSE_INVALID_INSTR; + + 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_temp + ); + + decode_ctrl: process(opcode, funct3, funct12) + begin + case opcode is + when b"01101" => -- Load upper immediate + rd_write <= '1'; + exception <= '0'; + exception_cause <= CSR_CAUSE_NONE; + branch <= BRANCH_NONE; + when b"00101" => -- Add upper immediate to PC + rd_write <= '1'; + exception <= '0'; + exception_cause <= CSR_CAUSE_NONE; + branch <= BRANCH_NONE; + when b"11011" => -- Jump and link + rd_write <= '1'; + exception <= '0'; + exception_cause <= CSR_CAUSE_NONE; + branch <= BRANCH_JUMP; + when b"11001" => -- Jump and link register + rd_write <= '1'; + exception <= '0'; + exception_cause <= CSR_CAUSE_NONE; + branch <= BRANCH_JUMP_INDIRECT; + when b"11000" => -- Branch operations + rd_write <= '0'; + exception <= '0'; + exception_cause <= CSR_CAUSE_NONE; + branch <= BRANCH_CONDITIONAL; + when b"00000" => -- Load instructions + rd_write <= '1'; + exception <= '0'; + exception_cause <= CSR_CAUSE_NONE; + branch <= BRANCH_NONE; + when b"01000" => -- Store instructions + rd_write <= '0'; + exception <= '0'; + exception_cause <= CSR_CAUSE_NONE; + branch <= BRANCH_NONE; + when b"00100" => -- Register-immediate operations + rd_write <= '1'; + exception <= '0'; + exception_cause <= CSR_CAUSE_NONE; + branch <= BRANCH_NONE; + when b"01100" => -- Register-register operations + rd_write <= '1'; + exception <= '0'; + exception_cause <= CSR_CAUSE_NONE; + branch <= BRANCH_NONE; + when b"00011" => -- Fence instructions, ignored + rd_write <= '0'; + exception <= '0'; + 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 + exception <= '1'; + exception_cause <= CSR_CAUSE_SYSCALL; + branch <= BRANCH_NONE; + elsif funct12 = x"001" then + exception <= '1'; + exception_cause <= CSR_CAUSE_BREAKPOINT; + branch <= BRANCH_NONE; + elsif funct12 = x"800" then + exception <= '0'; + exception_cause <= CSR_CAUSE_NONE; + branch <= BRANCH_SRET; + else + exception <= '1'; + exception_cause <= CSR_CAUSE_INVALID_INSTR; + branch <= BRANCH_NONE; + end if; + else + rd_write <= '1'; + exception <= '0'; + exception_cause <= CSR_CAUSE_NONE; + branch <= BRANCH_NONE; + end if; + when others => + rd_write <= '0'; + exception <= '1'; + 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: v0.1/src/pp_alu_control_unit.vhd =================================================================== --- v0.1/src/pp_alu_control_unit.vhd (nonexistent) +++ v0.1/src/pp_alu_control_unit.vhd (revision 47) @@ -0,0 +1,141 @@ +-- 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_INVALID; + 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_INVALID; + end case; + when b"00011" => -- Fence instructions, ignored + alu_x_src <= ALU_SRC_REG; + alu_y_src <= ALU_SRC_REG; + alu_op <= ALU_NOP; + 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_INVALID; + end case; + end process decode_alu; + +end architecture behaviour; Index: v0.1/src/pp_fifo.vhd =================================================================== --- v0.1/src/pp_fifo.vhd (nonexistent) +++ v0.1/src/pp_fifo.vhd (revision 47) @@ -0,0 +1,92 @@ +-- 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 A generic FIFO module. +--! Adopted from the FIFO module in . +entity pp_fifo is + generic( + DEPTH : natural := 64; + WIDTH : natural := 31 + ); + port( + -- Control lines: + clk : in std_logic; + reset : in std_logic; + + -- Status lines: + full : out std_logic; + empty : out std_logic; + + -- Data in: + data_in : in std_logic_vector(WIDTH - 1 downto 0); + data_out : out std_logic_vector(WIDTH - 1 downto 0); + push, pop : in std_logic + ); +end entity pp_fifo; + +architecture behaviour of pp_fifo is + + type memory_array is array(0 to DEPTH - 1) of std_logic_vector(WIDTH - 1 downto 0); + shared variable memory : memory_array := (others => (others => '0')); + + subtype index_type is integer range 0 to DEPTH - 1; + signal top, bottom : index_type; + + type fifo_op is (FIFO_POP, FIFO_PUSH); + signal prev_op : fifo_op := FIFO_POP; + +begin + + empty <= '1' when top = bottom and prev_op = FIFO_POP else '0'; + full <= '1' when top = bottom and prev_op = FIFO_PUSH else '0'; + + read: process(clk) + begin + if rising_edge(clk) then + if reset = '1' then + bottom <= 0; + else + if pop = '1' then + data_out <= memory(bottom); + bottom <= (bottom + 1) mod DEPTH; + end if; + end if; + end if; + end process read; + + write: process(clk) + begin + if rising_edge(clk) then + if reset = '1' then + top <= 0; + else + if push = '1' then + memory(top) := data_in; + top <= (top + 1) mod DEPTH; + end if; + end if; + end if; + end process write; + + set_prev_op: process(clk) + begin + if rising_edge(clk) then + if reset = '1' then + prev_op <= FIFO_POP; + else + if push = '1' and pop = '1' then + prev_op <= FIFO_POP; + elsif push = '1' then + prev_op <= FIFO_PUSH; + elsif pop = '1' then + prev_op <= FIFO_POP; + end if; + end if; + end if; + end process set_prev_op; + +end architecture behaviour; Index: v0.1/src/pp_comparator.vhd =================================================================== --- v0.1/src/pp_comparator.vhd (nonexistent) +++ v0.1/src/pp_comparator.vhd (revision 47) @@ -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: v0.1/src/pp_imm_decoder.vhd =================================================================== --- v0.1/src/pp_imm_decoder.vhd (nonexistent) +++ v0.1/src/pp_imm_decoder.vhd (revision 47) @@ -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: v0.1/src/pp_alu_mux.vhd =================================================================== --- v0.1/src/pp_alu_mux.vhd (nonexistent) +++ v0.1/src/pp_alu_mux.vhd (revision 47) @@ -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: v0.1/src/pp_writeback.vhd =================================================================== --- v0.1/src/pp_writeback.vhd (nonexistent) +++ v0.1/src/pp_writeback.vhd (revision 47) @@ -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: v0.1/src/pp_constants.vhd =================================================================== --- v0.1/src/pp_constants.vhd (nonexistent) +++ v0.1/src/pp_constants.vhd (revision 47) @@ -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: v0.1/src/pp_counter.vhd =================================================================== --- v0.1/src/pp_counter.vhd (nonexistent) +++ v0.1/src/pp_counter.vhd (revision 47) @@ -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: v0.1/src/pp_alu.vhd =================================================================== --- v0.1/src/pp_alu.vhd (nonexistent) +++ v0.1/src/pp_alu.vhd (revision 47) @@ -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: v0.1/src/pp_decode.vhd =================================================================== --- v0.1/src/pp_decode.vhd (nonexistent) +++ v0.1/src/pp_decode.vhd (revision 47) @@ -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: v0.1/src/pp_register_file.vhd =================================================================== --- v0.1/src/pp_register_file.vhd (nonexistent) +++ v0.1/src/pp_register_file.vhd (revision 47) @@ -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: v0.1/src/pp_csr.vhd =================================================================== --- v0.1/src/pp_csr.vhd (nonexistent) +++ v0.1/src/pp_csr.vhd (revision 47) @@ -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: v0.1/src/pp_csr_alu.vhd =================================================================== --- v0.1/src/pp_csr_alu.vhd (nonexistent) +++ v0.1/src/pp_csr_alu.vhd (revision 47) @@ -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: v0.1/example/toplevel.vhd =================================================================== --- v0.1/example/toplevel.vhd (nonexistent) +++ v0.1/example/toplevel.vhd (revision 47) @@ -0,0 +1,372 @@ +-- Practical Test Application for the Potato Processor +-- (c) Kristian Klomsten Skordal 2015 +-- Report bugs and issues on + +library ieee; +use ieee.std_logic_1164.all; + +entity toplevel is + port( + clk : in std_logic; -- System clock, 100 MHz + reset_n : in std_logic; -- CPU reset signal, active low + + -- External interrupt input: + external_interrupt : in std_logic; + + -- GPIO pins, must be inout to use with the GPIO module: + switches : inout std_logic_vector(15 downto 0); + leds : inout std_logic_vector(15 downto 0); + + -- UART1 (host) pins: + uart_txd : out std_logic; + uart_rxd : in std_logic + ); +end entity toplevel; + +architecture behaviour of toplevel is + signal system_clk : std_logic; + signal timer_clk : std_logic; + + -- Active high reset signal: + signal reset : std_logic; + + -- IRQs: + signal irq : std_logic_vector(7 downto 0); + signal uart_irq_rts, uart_irq_recv : std_logic; + signal timer_irq : std_logic; + + -- Processor wishbone interface: + 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_sel_out : std_logic_vector( 3 downto 0); + signal p_we_out : std_logic; + signal p_cyc_out, p_stb_out : std_logic; + signal p_ack_in : std_logic; + + -- Instruction memory wishbone interface: + signal imem_adr_in : std_logic_vector(12 downto 0); + signal imem_dat_out : std_logic_vector(31 downto 0); + signal imem_cyc_in, imem_stb_in : std_logic; + signal imem_ack_out : std_logic; + + -- Data memory wishbone interface: + signal dmem_adr_in : std_logic_vector(12 downto 0); + signal dmem_dat_in : std_logic_vector(31 downto 0); + signal dmem_dat_out : std_logic_vector(31 downto 0); + signal dmem_sel_in : std_logic_vector( 3 downto 0); + signal dmem_we_in : std_logic; + signal dmem_cyc_in, dmem_stb_in : std_logic; + signal dmem_ack_out : std_logic; + + -- GPIO module I (switches) wishbone interface: + signal gpio1_adr_in : std_logic_vector(1 downto 0); + signal gpio1_dat_in : std_logic_vector(31 downto 0); + signal gpio1_dat_out : std_logic_vector(31 downto 0); + signal gpio1_we_in : std_logic; + signal gpio1_cyc_in, gpio1_stb_in : std_logic; + signal gpio1_ack_out : std_logic; + + -- GPIO module II (LEDs) wishbone interface: + signal gpio2_adr_in : std_logic_vector(1 downto 0); + signal gpio2_dat_in : std_logic_vector(31 downto 0); + signal gpio2_dat_out : std_logic_vector(31 downto 0); + signal gpio2_we_in : std_logic; + signal gpio2_cyc_in, gpio2_stb_in : std_logic; + signal gpio2_ack_out : std_logic; + + -- UART module wishbone interface: + signal uart_adr_in : std_logic_vector(1 downto 0); + signal uart_dat_in : std_logic_vector(7 downto 0); + signal uart_dat_out : std_logic_vector(7 downto 0); + signal uart_we_in : std_logic; + signal uart_cyc_in, uart_stb_in : std_logic; + signal uart_ack_out : std_logic; + + -- Timer module wishbone interface: + signal timer_adr_in : std_logic_vector(1 downto 0); + signal timer_dat_in : std_logic_vector(31 downto 0); + signal timer_dat_out : std_logic_vector(31 downto 0); + signal timer_we_in : std_logic; + signal timer_cyc_in, timer_stb_in : std_logic; + signal timer_ack_out : std_logic; + + -- Dummy module interface: + signal dummy_dat_in : std_logic_vector(31 downto 0); + signal dummy_dat_out : std_logic_vector(31 downto 0); + signal dummy_we_in : std_logic; + signal dummy_cyc_in, dummy_stb_in : std_logic; + signal dummy_ack_out : std_logic; + + -- Address decoder signals: + type ad_state_type is (IDLE, BUSY); + signal ad_state : ad_state_type; + + type module_name is ( + MODULE_IMEM, MODULE_DMEM, -- Memory modules + MODULE_GPIO1, MODULE_GPIO2, -- GPIO modules + MODULE_UART, -- UART module + MODULE_TIMER, -- Timer module + MODULE_DUMMY, -- Dummy module, used for invalid addresses + MODULE_NONE -- Boring no-module mode + ); + signal active_module : module_name; + +begin + + reset <= not reset_n; + irq <= ( + 0 => external_interrupt, + 1 => uart_irq_rts, 2 => uart_irq_recv, + 5 => timer_irq, others => '0' + ); + + clkgen: entity work.clock_generator + port map( + clk => clk, + system_clk => system_clk, + timer_clk => timer_clk + ); + + processor: entity work.pp_potato + port map( + clk => system_clk, + reset => reset, + irq => irq, + fromhost_data => (others => '0'), + fromhost_updated => '0', + tohost_data => open, + tohost_updated => open, + wb_adr_out => p_adr_out, + wb_dat_out => p_dat_out, + wb_dat_in => p_dat_in, + wb_sel_out => p_sel_out, + wb_we_out => p_we_out, + wb_cyc_out => p_cyc_out, + wb_stb_out => p_stb_out, + wb_ack_in => p_ack_in + ); + + imem: entity work.imem_wrapper + port map( + clk => system_clk, + reset => reset, + wb_adr_in => imem_adr_in, + wb_dat_out => imem_dat_out, + wb_cyc_in => imem_cyc_in, + wb_stb_in => imem_stb_in, + wb_ack_out => imem_ack_out + ); + + dmem: entity work.pp_soc_memory + generic map( + MEMORY_SIZE => 8192 + ) port map( + clk => system_clk, + reset => reset, + wb_adr_in => dmem_adr_in, + wb_dat_in => dmem_dat_in, + wb_dat_out => dmem_dat_out, + wb_sel_in => dmem_sel_in, + wb_we_in => dmem_we_in, + wb_cyc_in => dmem_cyc_in, + wb_stb_in => dmem_stb_in, + wb_ack_out => dmem_ack_out + ); + + gpio1: entity work.pp_soc_gpio + generic map( + NUM_GPIOS => 16 + ) port map( + clk => system_clk, + reset => reset, + gpio => switches, + wb_adr_in => gpio1_adr_in, + wb_dat_in => gpio1_dat_in, + wb_dat_out => gpio1_dat_out, + wb_cyc_in => gpio1_cyc_in, + wb_stb_in => gpio1_stb_in, + wb_we_in => gpio1_we_in, + wb_ack_out => gpio1_ack_out + ); + + gpio2: entity work.pp_soc_gpio + generic map( + NUM_GPIOS => 16 + ) port map( + clk => system_clk, + reset => reset, + gpio => leds, + wb_adr_in => gpio2_adr_in, + wb_dat_in => gpio2_dat_in, + wb_dat_out => gpio2_dat_out, + wb_cyc_in => gpio2_cyc_in, + wb_stb_in => gpio2_stb_in, + wb_we_in => gpio2_we_in, + wb_ack_out => gpio2_ack_out + ); + + uart1: entity work.pp_soc_uart + generic map( + FIFO_DEPTH => 64, + SAMPLE_CLK_DIVISOR => 27 -- For 50 MHz + --SAMPLE_CLK_DIVISOR => 33 -- For 60 MHz + ) port map( + clk => system_clk, + reset => reset, + txd => uart_txd, + rxd => uart_rxd, + irq_send_buffer_empty => uart_irq_rts, + irq_data_received => uart_irq_recv, + wb_adr_in => uart_adr_in, + wb_dat_in => uart_dat_in, + wb_dat_out => uart_dat_out, + wb_cyc_in => uart_cyc_in, + wb_stb_in => uart_stb_in, + wb_we_in => uart_we_in, + wb_ack_out => uart_ack_out + ); + + timer1: entity work.pp_soc_timer + port map( + clk => system_clk, + reset => reset, + irq => timer_irq, + wb_adr_in => timer_adr_in, + wb_dat_in => timer_dat_in, + wb_dat_out => timer_dat_out, + wb_cyc_in => timer_cyc_in, + wb_stb_in => timer_stb_in, + wb_we_in => timer_we_in, + wb_ack_out => timer_ack_out + ); + + dummy: entity work.pp_soc_dummy + port map( + clk => system_clk, + reset => reset, + wb_dat_in => dummy_dat_in, + wb_dat_out => dummy_dat_out, + wb_cyc_in => dummy_cyc_in, + wb_stb_in => dummy_stb_in, + wb_we_in => dummy_we_in, + wb_ack_out => dummy_ack_out + ); + + imem_cyc_in <= p_cyc_out when active_module = MODULE_IMEM else '0'; + dmem_cyc_in <= p_cyc_out when active_module = MODULE_DMEM else '0'; + gpio1_cyc_in <= p_cyc_out when active_module = MODULE_GPIO1 else '0'; + gpio2_cyc_in <= p_cyc_out when active_module = MODULE_GPIO2 else '0'; + uart_cyc_in <= p_cyc_out when active_module = MODULE_UART else '0'; + timer_cyc_in <= p_cyc_out when active_module = MODULE_TIMER else '0'; + dummy_cyc_in <= p_cyc_out when active_module = MODULE_DUMMY else '0'; + + imem_stb_in <= p_stb_out when active_module = MODULE_IMEM else '0'; + dmem_stb_in <= p_stb_out when active_module = MODULE_DMEM else '0'; + gpio1_stb_in <= p_stb_out when active_module = MODULE_GPIO1 else '0'; + gpio2_stb_in <= p_stb_out when active_module = MODULE_GPIO2 else '0'; + uart_stb_in <= p_stb_out when active_module = MODULE_UART else '0'; + timer_stb_in <= p_stb_out when active_module = MODULE_TIMER else '0'; + dummy_stb_in <= p_stb_out when active_module = MODULE_DUMMY else '0'; + + imem_adr_in <= p_adr_out(12 downto 0); + dmem_adr_in <= p_adr_out(12 downto 0); + gpio1_adr_in <= p_adr_out(3 downto 2); + gpio2_adr_in <= p_adr_out(3 downto 2); + uart_adr_in <= p_adr_out(3 downto 2); + timer_adr_in <= p_adr_out(3 downto 2); + + dmem_dat_in <= p_dat_out; + gpio1_dat_in <= p_dat_out; + gpio2_dat_in <= p_dat_out; + uart_dat_in <= p_dat_out(7 downto 0); + timer_dat_in <= p_dat_out; + dummy_dat_in <= p_dat_out; + + dmem_sel_in <= p_sel_out; + + gpio1_we_in <= p_we_out; + gpio2_we_in <= p_we_out; + dmem_we_in <= p_we_out; + uart_we_in <= p_we_out; + timer_we_in <= p_we_out; + dummy_we_in <= p_we_out; + + address_decoder: process(system_clk) + begin + if rising_edge(system_clk) then + if reset = '1' then + ad_state <= IDLE; + active_module <= MODULE_NONE; + else + case ad_state is + when IDLE => + if p_cyc_out = '1' then + if p_adr_out(31 downto 13) = b"0000000000000000000" then + active_module <= MODULE_IMEM; + ad_state <= BUSY; + elsif p_adr_out(31 downto 13) = b"0000000000000000001" then -- 0x2000 + active_module <= MODULE_DMEM; + ad_state <= BUSY; + elsif p_adr_out(31 downto 11) = b"000000000000000001000" then -- 0x4000 + active_module <= MODULE_GPIO1; + ad_state <= BUSY; + elsif p_adr_out(31 downto 11) = b"000000000000000001001" then -- 0x4800 + active_module <= MODULE_GPIO2; + ad_state <= BUSY; + elsif p_adr_out(31 downto 11) = b"000000000000000001010" then -- 0x5000 + active_module <= MODULE_UART; + ad_state <= BUSY; + elsif p_adr_out(31 downto 11) = b"000000000000000001011" then -- 0x5800 + active_module <= MODULE_TIMER; + ad_state <= BUSY; + else + active_module <= MODULE_DUMMY; + ad_state <= BUSY; + end if; + else + active_module <= MODULE_NONE; + end if; + when BUSY => + if p_cyc_out = '0' then + active_module <= MODULE_NONE; + ad_state <= IDLE; + end if; + end case; + end if; + end if; + end process address_decoder; + + module_mux: process(active_module, imem_ack_out, imem_dat_out, dmem_ack_out, dmem_dat_out, + gpio1_ack_out, gpio1_dat_out, gpio2_ack_out, gpio2_dat_out, uart_ack_out, uart_dat_out, + timer_ack_out, timer_dat_out, dummy_ack_out, dummy_dat_out) + begin + case active_module is + when MODULE_IMEM => + p_ack_in <= imem_ack_out; + p_dat_in <= imem_dat_out; + when MODULE_DMEM => + p_ack_in <= dmem_ack_out; + p_dat_in <= dmem_dat_out; + when MODULE_GPIO1 => + p_ack_in <= gpio1_ack_out; + p_dat_in <= gpio1_dat_out; + when MODULE_GPIO2 => + p_ack_in <= gpio2_ack_out; + p_dat_in <= gpio2_dat_out; + when MODULE_UART => + p_ack_in <= uart_ack_out; + p_dat_in <= (31 downto 8 => '0') & uart_dat_out; + when MODULE_TIMER => + p_ack_in <= timer_ack_out; + p_dat_in <= timer_dat_out; + when MODULE_DUMMY => + p_ack_in <= dummy_ack_out; + p_dat_in <= dummy_dat_out; + when MODULE_NONE => + p_ack_in <= '0'; + p_dat_in <= (others => '0'); + end case; + end process module_mux; + +end architecture behaviour; Index: v0.1/example/README =================================================================== --- v0.1/example/README (nonexistent) +++ v0.1/example/README (revision 47) @@ -0,0 +1,35 @@ +# Demo design for the Nexys 4 board + +This folder contains a design for a simple demo design using the Potato +processor. It has been tested using Vivado 2014.4. + +## Quick Start + +In order to use the design, first import all source files from the folders +`src/`, `soc/` and `example/` into your project. Make sure the testbench files +(the files starting with "tb_") is added as simulation-only files. + +### Clocking + +Add a clock generator using the Clocking Wizard. To seamlessly integrate +it into the design, name it "clock_generator". Choose the following options: + +* Frequency Synthesis +* Safe Clock Startup + +Set up two output clocks, `clk_out1` with frequency 60 MHz, and `clk_out2` with +a frequency of 10 MHz. Rename the corresponding ports to `system_clk` and +`timer_clk` respectively. Name the input clock `clk`. + +### Instruction memory + +Add a block RAM to use as instruction ROM using the Block Memory Generator. +Choose "Single Port ROM" as memory type, name it "instruction_rom" and set +port A width to 32 bits and port A depth to 2048. Initialize it with your +application binary and, optionally, fill the remaining memory locations with +0x00000013 (no-operation opcode). + +### Test it! + +Now you can test it and hopefully it works :-) + Index: v0.1/example/tb_toplevel.vhd =================================================================== --- v0.1/example/tb_toplevel.vhd (nonexistent) +++ v0.1/example/tb_toplevel.vhd (revision 47) @@ -0,0 +1,58 @@ +-- Practical Test Application for the Potato Processor +-- (c) Kristian Klomsten Skordal 2015 +-- Report bugs and issues on + +library ieee; +use ieee.std_logic_1164.all; + +entity tb_toplevel is +end entity tb_toplevel; + +architecture testbench of tb_toplevel is + + signal clk : std_logic; + constant clk_period : time := 10 ns; + + signal reset_n : std_logic := '0'; + signal external_interrupt : std_logic := '0'; + + signal switches : std_logic_vector(15 downto 0); + signal leds : std_logic_vector(15 downto 0); + + signal uart_rxd : std_logic := '1'; + signal uart_txd : std_logic; + +begin + + switches <= x"a0a0"; + + uut: entity work.toplevel + port map( + clk => clk, + reset_n => reset_n, + external_interrupt => external_interrupt, + switches => switches, + leds => leds, + uart_rxd => uart_rxd, + uart_txd => uart_txd + ); + + clock: process + begin + clk <= '0'; + wait for clk_period / 2; + clk <= '1'; + wait for clk_period / 2; + end process clock; + + stimulus: process + begin + wait for clk_period * 125; + reset_n <= '0'; + wait for clk_period * 3; + reset_n <= '1'; + + wait; + end process stimulus; + +end architecture testbench; Index: v0.1/example/imem_wrapper.vhd =================================================================== --- v0.1/example/imem_wrapper.vhd (nonexistent) +++ v0.1/example/imem_wrapper.vhd (revision 47) @@ -0,0 +1,68 @@ +-- The Potato Processor - A simple processor for FPGAs +-- (c) Kristian Klomsten Skordal 2015 +-- Report bugs and issues on + +library ieee; +use ieee.std_logic_1164.all; + +entity imem_wrapper is + port( + clk : in std_logic; + reset : in std_logic; + + -- Wishbone interface: + wb_adr_in : in std_logic_vector(12 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_ack_out : out std_logic + ); +end entity imem_wrapper; + +architecture behaviour of imem_wrapper is + + type wb_state is (IDLE, READ_ACK); + signal state : wb_state := IDLE; + + signal address : std_logic_vector(10 downto 0); + signal data : std_logic_vector(31 downto 0); + + signal ack : std_logic := '0'; + +begin + + imem: entity work.instruction_rom + port map( + clka => clk, + addra => address, + douta => wb_dat_out + ); + + wb_ack_out <= ack and wb_cyc_in and wb_stb_in; + + wishbone: process(clk) + begin + if rising_edge(clk) then + if reset = '1' then + ack <= '0'; + state <= IDLE; + else + case state is + when IDLE => + if wb_cyc_in = '1' and wb_stb_in = '1' then + address <= wb_adr_in(12 downto 2); + state <= READ_ACK; + end if; + when READ_ACK => + if ack = '0' then + ack <= '1'; + elsif wb_stb_in = '0' then + ack <= '0'; + state <= IDLE; + end if; + end case; + end if; + end if; + end process wishbone; + +end architecture behaviour; Index: v0.1/example/tb_imem_wrapper.vhd =================================================================== --- v0.1/example/tb_imem_wrapper.vhd (nonexistent) +++ v0.1/example/tb_imem_wrapper.vhd (revision 47) @@ -0,0 +1,69 @@ +-- The Potato Processor - A simple processor for FPGAs +-- (c) Kristian Klomsten Skordal 2015 +-- Report bugs and issues on + +library ieee; +use ieee.std_logic_1164.all; + +entity tb_imem_wrapper is +end entity tb_imem_wrapper; + +architecture testbench of tb_imem_wrapper is + + -- Clock signal: + signal clk : std_logic := '0'; + constant clk_period : time := 10 ns; + + -- Reset signal: + signal reset : std_logic := '1'; + + -- Wishbone signals: + signal wb_adr_in : std_logic_vector(10 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_ack_out : std_logic; + +begin + + uut: entity work.imem_wrapper + port map( + clk => clk, + reset => reset, + wb_adr_in => wb_adr_in, + wb_dat_out => wb_dat_out, + wb_cyc_in => wb_cyc_in, + wb_stb_in => wb_stb_in, + wb_ack_out => wb_ack_out + ); + + clock: process + begin + clk <= '1'; + wait for clk_period; + clk <= '0'; + wait for clk_period; + end process clock; + + stimulus: process + begin + wait for clk_period * 2; + reset <= '0'; + wait for clk_period; + + -- Read an instruction: + wb_adr_in <= (others => '0'); + wb_cyc_in <= '1'; + wb_stb_in <= '1'; + wait for clk_period; + wait until wb_ack_out = '1'; + wait for clk_period; + wb_cyc_in <= '0'; + wb_stb_in <= '0'; + + -- TODO: Make testbench automated. + + wait; + end process stimulus; + +end architecture testbench; Index: v0.1/example/nexys4_constraints.xdc =================================================================== --- v0.1/example/nexys4_constraints.xdc (nonexistent) +++ v0.1/example/nexys4_constraints.xdc (revision 47) @@ -0,0 +1,94 @@ +# The Potato Processor - A simple processor for FPGAs +# (c) Kristian Klomsten Skordal 2014 +# Report bugs and issues on + +# Set operating conditions to improve temperature estimation: +set_operating_conditions -airflow 0 +set_operating_conditions -heatsink low + +# Clock: +set_property PACKAGE_PIN E3 [get_ports clk] + set_property IOSTANDARD LVCMOS33 [get_ports clk] + create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports clk] + + # Reset: + set_property PACKAGE_PIN C12 [get_ports reset_n] + set_property IOSTANDARD LVCMOS33 [get_ports reset_n] + + # External interrupt button: + set_property PACKAGE_PIN E16 [get_ports external_interrupt] + set_property IOSTANDARD LVCMOS33 [get_ports external_interrupt] + +# UART (to host) lines: +set_property PACKAGE_PIN C4 [get_ports uart_rxd] + set_property IOSTANDARD LVCMOS33 [get_ports uart_rxd] +set_property PACKAGE_PIN D4 [get_ports uart_txd] + set_property IOSTANDARD LVCMOS33 [get_ports uart_txd] + +# Switches: +set_property PACKAGE_PIN U9 [get_ports {switches[0]}] + set_property IOSTANDARD LVCMOS33 [get_ports {switches[0]}] +set_property PACKAGE_PIN U8 [get_ports {switches[1]}] + set_property IOSTANDARD LVCMOS33 [get_ports {switches[1]}] +set_property PACKAGE_PIN R7 [get_ports {switches[2]}] + set_property IOSTANDARD LVCMOS33 [get_ports {switches[2]}] +set_property PACKAGE_PIN R6 [get_ports {switches[3]}] + set_property IOSTANDARD LVCMOS33 [get_ports {switches[3]}] +set_property PACKAGE_PIN R5 [get_ports {switches[4]}] + set_property IOSTANDARD LVCMOS33 [get_ports {switches[4]}] +set_property PACKAGE_PIN V7 [get_ports {switches[5]}] + set_property IOSTANDARD LVCMOS33 [get_ports {switches[5]}] +set_property PACKAGE_PIN V6 [get_ports {switches[6]}] + set_property IOSTANDARD LVCMOS33 [get_ports {switches[6]}] +set_property PACKAGE_PIN V5 [get_ports {switches[7]}] + set_property IOSTANDARD LVCMOS33 [get_ports {switches[7]}] +set_property PACKAGE_PIN U4 [get_ports {switches[8]}] + set_property IOSTANDARD LVCMOS33 [get_ports {switches[8]}] +set_property PACKAGE_PIN V2 [get_ports {switches[9]}] + set_property IOSTANDARD LVCMOS33 [get_ports {switches[9]}] +set_property PACKAGE_PIN U2 [get_ports {switches[10]}] + set_property IOSTANDARD LVCMOS33 [get_ports {switches[10]}] +set_property PACKAGE_PIN T3 [get_ports {switches[11]}] + set_property IOSTANDARD LVCMOS33 [get_ports {switches[11]}] +set_property PACKAGE_PIN T1 [get_ports {switches[12]}] + set_property IOSTANDARD LVCMOS33 [get_ports {switches[12]}] +set_property PACKAGE_PIN R3 [get_ports {switches[13]}] + set_property IOSTANDARD LVCMOS33 [get_ports {switches[13]}] +set_property PACKAGE_PIN P3 [get_ports {switches[14]}] + set_property IOSTANDARD LVCMOS33 [get_ports {switches[14]}] +set_property PACKAGE_PIN P4 [get_ports {switches[15]}] + set_property IOSTANDARD LVCMOS33 [get_ports {switches[15]}] + +# LEDs: +set_property PACKAGE_PIN T8 [get_ports {leds[0]}] + set_property IOSTANDARD LVCMOS33 [get_ports {leds[0]}] +set_property PACKAGE_PIN V9 [get_ports {leds[1]}] + set_property IOSTANDARD LVCMOS33 [get_ports {leds[1]}] +set_property PACKAGE_PIN R8 [get_ports {leds[2]}] + set_property IOSTANDARD LVCMOS33 [get_ports {leds[2]}] +set_property PACKAGE_PIN T6 [get_ports {leds[3]}] + set_property IOSTANDARD LVCMOS33 [get_ports {leds[3]}] +set_property PACKAGE_PIN T5 [get_ports {leds[4]}] + set_property IOSTANDARD LVCMOS33 [get_ports {leds[4]}] +set_property PACKAGE_PIN T4 [get_ports {leds[5]}] + set_property IOSTANDARD LVCMOS33 [get_ports {leds[5]}] +set_property PACKAGE_PIN U7 [get_ports {leds[6]}] + set_property IOSTANDARD LVCMOS33 [get_ports {leds[6]}] +set_property PACKAGE_PIN U6 [get_ports {leds[7]}] + set_property IOSTANDARD LVCMOS33 [get_ports {leds[7]}] +set_property PACKAGE_PIN V4 [get_ports {leds[8]}] + set_property IOSTANDARD LVCMOS33 [get_ports {leds[8]}] +set_property PACKAGE_PIN U3 [get_ports {leds[9]}] + set_property IOSTANDARD LVCMOS33 [get_ports {leds[9]}] +set_property PACKAGE_PIN V1 [get_ports {leds[10]}] + set_property IOSTANDARD LVCMOS33 [get_ports {leds[10]}] +set_property PACKAGE_PIN R1 [get_ports {leds[11]}] + set_property IOSTANDARD LVCMOS33 [get_ports {leds[11]}] +set_property PACKAGE_PIN P5 [get_ports {leds[12]}] + set_property IOSTANDARD LVCMOS33 [get_ports {leds[12]}] +set_property PACKAGE_PIN U1 [get_ports {leds[13]}] + set_property IOSTANDARD LVCMOS33 [get_ports {leds[13]}] +set_property PACKAGE_PIN R2 [get_ports {leds[14]}] + set_property IOSTANDARD LVCMOS33 [get_ports {leds[14]}] +set_property PACKAGE_PIN P2 [get_ports {leds[15]}] + set_property IOSTANDARD LVCMOS33 [get_ports {leds[15]}] Index: v0.1/Makefile =================================================================== --- v0.1/Makefile (nonexistent) +++ v0.1/Makefile (revision 47) @@ -0,0 +1,136 @@ +# 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_icache.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_arbiter.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 \ + sw-jal + +all: potato.prj run-tests + +potato.prj: + -$(RM) potato.prj + for file in $(SOURCE_FILES) $(TESTBENCHES); do \ + echo "vhdl work $$file" >> potato.prj; \ + done + +copy-riscv-tests: + for test in $(RISCV_TESTS); do \ + cp riscv-tests/$$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 -c -m32 -march=RV32I -Iriscv-tests -o tests-build/$$test.o tests/$$test.S; \ + $(TOOLCHAIN_PREFIX)-ld -m elf32lriscv -T tests.ld tests-build/$$test.o -o tests-build/$$test.elf; \ + scripts/extract_hex.sh tests-build/$$test.elf tests-build/$$test-imem.hex tests-build/$$test-dmem.hex; \ + done + +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 + Index: v0.1/benchmarks/hello/main.c =================================================================== --- v0.1/benchmarks/hello/main.c (nonexistent) +++ v0.1/benchmarks/hello/main.c (revision 47) @@ -0,0 +1,26 @@ +// The Potato Processor Benchmark Applications +// (c) Kristian Klomsten Skordal 2015 +// Report bugs and issues on + +#include +#include "../platform.h" + +void exception_handler(uint32_t cause, void * epc, void * regbase) +{ + // Not used in this application +} + +int main(void) +{ + const char * hello_string = "Hello world\n\r"; + volatile uint32_t * uart = IO_ADDRESS(UART_BASE); + + for(int i = 0; hello_string[i] != 0; ++i) + { + while(uart[UART_STATUS >> 2] & (1 << 3)); + uart[UART_TX >> 2] = hello_string[i] & 0x000000ff; + } + + return 0; +} + Index: v0.1/benchmarks/hello/Makefile =================================================================== --- v0.1/benchmarks/hello/Makefile (nonexistent) +++ v0.1/benchmarks/hello/Makefile (revision 47) @@ -0,0 +1,46 @@ +# The Potato Processor Benchmark Applications +# (c) Kristian Klomsten Skordal 2015 +# Report bugs and issues on + +.PHONY: all clean + +TARGET_PREFIX ?= riscv64-unknown-elf +TARGET_CC := $(TARGET_PREFIX)-gcc +TARGET_LD := $(TARGET_PREFIX)-ld +TARGET_SIZE := $(TARGET_PREFIX)-size +TARGET_OBJCOPY := $(TARGET_PREFIX)-objcopy +HEXDUMP ?= hexdump + +TARGET_CFLAGS += -m32 -march=RV32I -Wall -O2 -fomit-frame-pointer \ + -ffreestanding -fno-builtin -I.. -std=gnu99 +TARGET_LDFLAGS += -m elf32lriscv -T../benchmark.ld + +OBJECTS := main.o start.o + +all: hello.coe + +hello.elf: $(OBJECTS) + $(TARGET_LD) -o hello.elf $(TARGET_LDFLAGS) $(OBJECTS) + $(TARGET_SIZE) hello.elf + +hello.bin: hello.elf + $(TARGET_OBJCOPY) -j .text -j .data -O binary hello.elf hello.bin + +hello.coe: hello.bin + echo "memory_initialization_radix=16;" > hello.coe + echo "memory_initialization_vector=" >> hello.coe + $(HEXDUMP) -v -e '1/4 "%08x\n"' hello.bin >> hello.coe + echo ";" >> hello.coe + +clean: + -$(RM) $(OBJECTS) + -$(RM) hello.elf hello.bin hello.coe + +# Object file rules: + +main.o: main.c ../platform.h ../potato.h + $(TARGET_CC) -c -o $@ $(TARGET_CFLAGS) $< + +start.o: ../start.S ../platform.h + $(TARGET_CC) -c -o $@ $(TARGET_CFLAGS) $< + Index: v0.1/benchmarks/platform.h =================================================================== --- v0.1/benchmarks/platform.h (nonexistent) +++ v0.1/benchmarks/platform.h (revision 47) @@ -0,0 +1,49 @@ +// The Potato Processor Benchmark Applications +// (c) Kristian Klomsten Skordal 2015 +// Report bugs and issues on + +// This file contains various platform details. The default defines in this file +// correspond to the "official" test platform, the Potato SoC for the Nexys4 board. + +#ifndef PLATFORM_H +#define PLATFORM_H + +// Clock frequency in Hz: +#define SYSTEM_CLK_FREQ 50000000 + +// Macro for using the addresses below in C code: +#define IO_ADDRESS(x) ((volatile void *) x) + +// Base addresses for the various peripherals in the system: +#define IMEM_BASE 0x00000000 +#define DMEM_BASE 0x00002000 +#define GPIO1_BASE 0x00004000 +#define GPIO2_BASE 0x00004800 +#define UART_BASE 0x00005000 +#define TIMER_BASE 0x00005800 + +// IRQs: +#define EXTERNAL_IRQ 0 +#define TIMER_IRQ 5 + +// GPIO register offsets: +#define GPIO_INPUT 0 +#define GPIO_OUTPUT 4 +#define GPIO_DIR 8 + +// UART register offsets: +#define UART_TX 0 +#define UART_RX 4 +#define UART_STATUS 8 + +// Timer register offsets: +#define TIMER_CTRL 0 +#define TIMER_COMPARE 4 +#define TIMER_COUNTER 8 + +// Timer control register bits: +#define TIMER_CTRL_RUN 0 +#define TIMER_CTRL_CLEAR 1 + +#endif + Index: v0.1/benchmarks/potato.h =================================================================== --- v0.1/benchmarks/potato.h (nonexistent) +++ v0.1/benchmarks/potato.h (revision 47) @@ -0,0 +1,90 @@ +// The Potato Processor +// (c) Kristian Klomsten Skordal 2015 +// Report bugs and issues on + +#ifndef POTATO_H +#define POTATO_H + +// This file contains various defines neccessary for using the Potato processor +// with current RISC-V compilers. It also makes sure that applications keep +// working even though the supervisor extension specification should change. + +// Control and status registers: +#define CSR_SUP0 0x500 +#define CSR_SUP1 0x501 +#define CSR_EPC 0x502 +#define CSR_BADVADDR 0x503 +#define CSR_EVEC 0x508 +#define CSR_CAUSE 0x509 +#define CSR_STATUS 0x50a +#define CSR_HARTID 0x50b +#define CSR_TOHOST 0x51e +#define CSR_FROMHOST 0x51f +#define CSR_CYCLE 0xc00 +#define CSR_CYCLEH 0xc80 +#define CSR_TIME 0xc01 +#define CSR_TIMEH 0xc81 +#define CSR_INSTRET 0xc02 +#define CSR_INSTRETH 0xc82 + +// Exception cause values: +#define CAUSE_INSTR_MISALIGN 0x00 +#define CAUSE_INSTR_FETCH 0x01 +#define CAUSE_INVALID_INSTR 0x02 +#define CAUSE_SYSCALL 0x06 +#define CAUSE_BREAKPOINT 0x07 +#define CAUSE_LOAD_MISALIGN 0x08 +#define CAUSE_STORE_MISALIGN 0x09 +#define CAUSE_LOAD_ERROR 0x0a +#define CAUSE_STORE_ERROR 0x0b +#define CAUSE_FROMHOST 0x1e + +#define CAUSE_IRQ_BASE 0x10 + +// Status register bit indices: +#define STATUS_EI 2 // Enable Interrupts +#define STATUS_PEI 3 // Previous value of Enable Interrupts +#define STATUS_IM_MASK 0x00ff0000 // Interrupt Mask +#define STATUS_PIM_MASK 0xff000000 // Previous Interrupt Mask + +#define potato_enable_interrupts() asm volatile("csrsi %[status], 1 << %[ei_bit]\n" \ + :: [status] "i" (CSR_STATUS), [ei_bit] "i" (STATUS_EI)) +#define potato_disable_interrupts() asm volatile("csrci %[status], 1 << %[ei_bit] | 1 << %[pei_bit]\n" \ + :: [status] "i" (CSR_STATUS), [ei_bit] "i" (STATUS_EI), [pei_bit] "i" (STATUS_PEI)) + +#define potato_write_host(data) \ + do { \ + register uint32_t temp = data; \ + asm volatile("csrw %[tohost], %[temp]\n" \ + :: [tohost] "i" (CSR_TOHOST), [temp] "r" (temp)); \ + } while(0); + +#define potato_enable_irq(n) \ + do { \ + register uint32_t temp = 0; \ + asm volatile( \ + "li %[temp], 1 << %[shift]\n" \ + "csrs %[status], %[temp]\n" \ + :: [temp] "r" (temp), [shift] "i" (n + 16), [status] "i" (CSR_STATUS)); \ + } while(0) + +#define potato_disable_irq(n) \ + do { \ + register uint32_t temp = 0; \ + asm volatile( \ + "li %[temp], 1 << %[shift]\n" \ + "csrc %[status], %[temp]\n" \ + :: [temp] "r" (temp), [shift] "i" (n + 24), [status] "i" (CSR_STATUS)); \ + } while(0) + +#define potato_get_badvaddr(n) \ + do { \ + register uint32_t __temp = 0; \ + asm volatile ( \ + "csrr %[temp], %[badvaddr]\n" \ + : [temp] "=r" (__temp) : [badvaddr] "i" (CSR_BADVADDR)); \ + n = __temp; \ + } while(0) + +#endif + Index: v0.1/benchmarks/sha256/main.c =================================================================== --- v0.1/benchmarks/sha256/main.c (nonexistent) +++ v0.1/benchmarks/sha256/main.c (revision 47) @@ -0,0 +1,96 @@ +// The Potato Processor Benchmark Applications +// (c) Kristian Klomsten Skordal 2015 +// Report bugs and issues on + +#include +#include + +#include "platform.h" +#include "potato.h" + +#include "gpio.h" +#include "sha256.h" +#include "timer.h" +#include "uart.h" + +static int led_status = 0; +static volatile int hashes_per_second = 0; + +// Handle an exception/interrupt. +// Arguments: +// - cause: exception cause, see potato.h for values +// - epc: exception return address +// - regbase: base of the stored context, can be used for printing all +// registers with regbase[0] = x1 and upwards. +void exception_handler(uint32_t cause, void * epc, void * regbase) +{ + if(cause == (CAUSE_IRQ_BASE + 5)) // Timer interrupt + { + uart_puts(IO_ADDRESS(UART_BASE), "Hashes per second: "); + uart_puth(IO_ADDRESS(UART_BASE), hashes_per_second); + uart_puts(IO_ADDRESS(UART_BASE), "\n\r"); + + if(led_status == 0) + { + gpio_set_output(IO_ADDRESS(GPIO2_BASE), 1); + led_status = 1; + } else { + gpio_set_output(IO_ADDRESS(GPIO2_BASE), 0); + led_status = 0; + } + + hashes_per_second = 0; + timer_reset(IO_ADDRESS(TIMER_BASE)); + } else { + uart_puts(IO_ADDRESS(UART_BASE), "Unhandled exception!\n\r"); + uart_puts(IO_ADDRESS(UART_BASE), "Cause: "); + uart_puth(IO_ADDRESS(UART_BASE), cause); + uart_puts(IO_ADDRESS(UART_BASE), "\n\r"); + uart_puts(IO_ADDRESS(UART_BASE), "EPC: "); + uart_puth(IO_ADDRESS(UART_BASE), (uint32_t) epc); + uart_puts(IO_ADDRESS(UART_BASE), "\n\r"); + + while(1) asm volatile("nop\n"); + } +} + +int main(void) +{ + // Configure GPIOs: + gpio_set_direction(IO_ADDRESS(GPIO1_BASE), 0x0000); // Switches + gpio_set_direction(IO_ADDRESS(GPIO2_BASE), 0xffff); // LEDs + + // Set up the timer: + timer_set(IO_ADDRESS(TIMER_BASE), SYSTEM_CLK_FREQ); + + // Print a startup message: + uart_puts(IO_ADDRESS(UART_BASE), "The Potato Processor SHA256 Benchmark\n\r\n\r"); + + // Enable interrupts: + potato_enable_irq(TIMER_IRQ); + potato_enable_interrupts(); + + struct sha256_context context; + + // Prepare a block for hashing: + uint32_t block[16]; + uint8_t * block_ptr = (uint8_t *) block; + block_ptr[0] = 'a'; + block_ptr[1] = 'b'; + block_ptr[2] = 'c'; + sha256_pad_le_block(block_ptr, 3, 3); + + // Repeatedly hash the same data over and over again: + while(true) + { + uint8_t hash[32]; + + sha256_reset(&context); + sha256_hash_block(&context, block); + sha256_get_hash(&context, hash); + ++hashes_per_second; + } + + return 0; +} + Index: v0.1/benchmarks/sha256/Makefile =================================================================== --- v0.1/benchmarks/sha256/Makefile (nonexistent) +++ v0.1/benchmarks/sha256/Makefile (revision 47) @@ -0,0 +1,61 @@ +# The Potato Processor Benchmark Applications +# (c) Kristian Klomsten Skordal 2015 +# Report bugs and issues on + +.PHONY: all clean + +TARGET_PREFIX ?= riscv64-unknown-elf +TARGET_CC := $(TARGET_PREFIX)-gcc +TARGET_LD := $(TARGET_PREFIX)-ld +TARGET_SIZE := $(TARGET_PREFIX)-size +TARGET_OBJCOPY := $(TARGET_PREFIX)-objcopy +HEXDUMP ?= hexdump + +TARGET_CFLAGS += -m32 -march=RV32I -Wall -Os -fomit-frame-pointer \ + -ffreestanding -fno-builtin -I.. -std=gnu99 +TARGET_LDFLAGS += -m elf32lriscv -T../benchmark.ld + +OBJECTS := gpio.o main.o sha256.o start.o timer.o uart.o utilities.o + +all: sha256.coe + +sha256.elf: $(OBJECTS) + $(TARGET_LD) -o sha256.elf $(TARGET_LDFLAGS) $(OBJECTS) + $(TARGET_SIZE) sha256.elf + +sha256.bin: sha256.elf + $(TARGET_OBJCOPY) -j .text -j .data -O binary sha256.elf sha256.bin + +sha256.coe: sha256.bin + echo "memory_initialization_radix=16;" > sha256.coe + echo "memory_initialization_vector=" >> sha256.coe + $(HEXDUMP) -v -e '1/4 "%08x\n"' sha256.bin >> sha256.coe + echo ";" >> sha256.coe + +clean: + -$(RM) $(OBJECTS) + -$(RM) sha256.elf sha256.bin sha256.coe + +# Object file rules: + +gpio.o: gpio.c gpio.h ../platform.h + $(TARGET_CC) -c -o $@ $(TARGET_CFLAGS) $< + +main.o: main.c gpio.h timer.h sha256.h ../platform.h ../potato.h + $(TARGET_CC) -c -o $@ $(TARGET_CFLAGS) $< + +sha256.o: sha256.c sha256.h + $(TARGET_CC) -c -o $@ $(TARGET_CFLAGS) $< + +start.o: ../start.S ../platform.h + $(TARGET_CC) -c -o $@ $(TARGET_CFLAGS) $< + +timer.o: timer.c timer.h ../platform.h + $(TARGET_CC) -c -o $@ $(TARGET_CFLAGS) $< + +uart.o: uart.c uart.h ../platform.h + $(TARGET_CC) -c -o $@ $(TARGET_CFLAGS) $< + +utilities.o: utilities.c utilities.h + $(TARGET_CC) -c -o $@ $(TARGET_CFLAGS) $< + Index: v0.1/benchmarks/sha256/sha256.c =================================================================== --- v0.1/benchmarks/sha256/sha256.c (nonexistent) +++ v0.1/benchmarks/sha256/sha256.c (revision 47) @@ -0,0 +1,167 @@ +// The Potato Processor Benchmark Applications +// (c) Kristian Klomsten Skordal 2015 +// Report bugs and issues on + +#include "platform.h" +#include "gpio.h" + +#include "sha256.h" + +#define htobe32(n) ((uint32_t) ((n << 24) | ((n << 8) & 0xff0000) | ((n >> 8) & 0xff00) | (n >> 24))) + +// Software SHA256 module + +static const uint32_t initial[8] = +{ + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 +}; + +static const uint32_t constants[64] = +{ + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +static uint32_t rotate_right(uint32_t x, int n) +{ + return (x >> n) | (x << (32 - n)); +} + +static uint32_t Ch(uint32_t x, uint32_t y, uint32_t z) +{ + return (x & y) ^ ((~x) & z); +} + +static uint32_t Maj(uint32_t x, uint32_t y, uint32_t z) +{ + return (x & y) ^ (x & z) ^ (y & z); +} + +static uint32_t s0(uint32_t x) +{ + return rotate_right(x, 2) ^ rotate_right(x, 13) ^ rotate_right(x, 22); +} + +static uint32_t s1(uint32_t x) +{ + return rotate_right(x, 6) ^ rotate_right(x, 11) ^ rotate_right(x, 25); +} + +static uint32_t o0(uint32_t x) +{ + return rotate_right(x, 7) ^ rotate_right(x, 18) ^ (x >> 3); +} + +static uint32_t o1(uint32_t x) +{ + return rotate_right(x, 17) ^ rotate_right(x, 19) ^ (x >> 10); +} + +static uint32_t schedule(uint32_t input, const uint32_t * W, int i) +{ + if(i < 16) + return input; + else + return o1(W[i - 2]) + W[i - 7] + o0(W[i - 15]) + W[i - 16]; +} + +static void compress(uint32_t * i, uint32_t W, uint32_t K) +{ + uint32_t a = i[0], b = i[1], c = i[2], d = i[3]; + uint32_t e = i[4], f = i[5], g = i[6], h = i[7]; + + uint32_t t1 = h + s1(e) + Ch(e, f, g) + K + W; + uint32_t t2 = s0(a) + Maj(a, b, c); + + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + + i[0] = a; + i[1] = b; + i[2] = c; + i[3] = d; + i[4] = e; + i[5] = f; + i[6] = g; + i[7] = h; +} + +void sha256_reset(struct sha256_context * ctx) +{ + for(int i = 0; i < 8; ++i) + ctx->intermediate[i] = initial[i]; +} + +void sha256_hash_block(struct sha256_context * ctx, const uint32_t * data) +{ + uint32_t W[64]; + uint32_t temp[8]; + + for(int i = 0; i < 8; ++i) + temp[i] = ctx->intermediate[i]; + + for(int i = 0; i < 64; ++i) + { + uint32_t v = i < 16 ? data[i] : 0; + W[i] = schedule(v, W, i); + compress(temp, W[i], constants[i]); + } + + for(int i = 0; i < 8; ++i) + ctx->intermediate[i] += temp[i]; +} + +void sha256_pad_le_block(uint8_t * block, int block_length, uint64_t total_length) +{ + block[block_length] = 0x80; // Add a one to the end of the message; + for(int i = block_length + 1; i < 64; ++i) + block[i] = 0; + + ((uint32_t *) block)[14] = total_length * 8 >> 32; + ((uint32_t *) block)[15] = total_length * 8 & 0xffffffff; + + // Convert the block to big-endian: + for(int i = 0; i < 14; ++i) + ((uint32_t *) block)[i] = htobe32(((uint32_t *) block)[i]); +} + +void sha256_get_hash(const struct sha256_context * ctx, uint8_t * hash) +{ + for(int i = 0; i < 8; ++i) + { + // Return the hash in little-endian format: + hash[i * 4 + 3] = (ctx->intermediate[i] >> 0) & 0xff; + hash[i * 4 + 2] = (ctx->intermediate[i] >> 8) & 0xff; + hash[i * 4 + 1] = (ctx->intermediate[i] >> 16) & 0xff; + hash[i * 4 + 0] = (ctx->intermediate[i] >> 24) & 0xff; + } +} + +void sha256_format_hash(const uint8_t * hash, char * output) +{ + static const char * hex_digits = "0123456789abcdef"; + for(int i = 0; i < 32; i++) + { + uint8_t h = hash[i]; + + output[i * 2 + 0] = hex_digits[(h >> 4) & 0xf]; + output[i * 2 + 1] = hex_digits[h & 0xf]; + } + + output[64] = 0; +} + + Index: v0.1/benchmarks/sha256/gpio.c =================================================================== --- v0.1/benchmarks/sha256/gpio.c (nonexistent) +++ v0.1/benchmarks/sha256/gpio.c (revision 47) @@ -0,0 +1,23 @@ +// The Potato Processor Benchmark Applications +// (c) Kristian Klomsten Skordal 2015 +// Report bugs and issues on + +#include "gpio.h" +#include "platform.h" + +void gpio_set_direction(volatile uint32_t * base, uint32_t direction) +{ + base[GPIO_DIR >> 2] = direction; +} + +void gpio_set_output(volatile uint32_t * base, uint32_t output) +{ + base[GPIO_OUTPUT >> 2] = output; +} + +uint32_t gpio_get_value(volatile uint32_t * base) +{ + return base[GPIO_INPUT >> 2]; +} + + Index: v0.1/benchmarks/sha256/utilities.h =================================================================== --- v0.1/benchmarks/sha256/utilities.h (nonexistent) +++ v0.1/benchmarks/sha256/utilities.h (revision 47) @@ -0,0 +1,11 @@ +// The Potato Processor Benchmark Applications +// (c) Kristian Klomsten Skordal 2015 +// Report bugs and issues on + +#ifndef UTILITIES_H +#define UTILITIES_H + +void * memset(void * s, int c, int n); + +#endif + Index: v0.1/benchmarks/sha256/uart.h =================================================================== --- v0.1/benchmarks/sha256/uart.h (nonexistent) +++ v0.1/benchmarks/sha256/uart.h (revision 47) @@ -0,0 +1,17 @@ +// The Potato Processor Benchmark Applications +// (c) Kristian Klomsten Skordal 2015 +// Report bugs and issues on + +#ifndef UART_H +#define UART_H + +#include + +// TODO: Implement the M extension and then write a printf function. + +void uart_puts(volatile uint32_t * base, const char * s); +void uart_putc(volatile uint32_t * base, char c); +void uart_puth(volatile uint32_t * base, uint32_t n); + +#endif + Index: v0.1/benchmarks/sha256/timer.c =================================================================== --- v0.1/benchmarks/sha256/timer.c (nonexistent) +++ v0.1/benchmarks/sha256/timer.c (revision 47) @@ -0,0 +1,18 @@ +// The Potato Processor Benchmark Applications +// (c) Kristian Klomsten Skordal 2015 +// Report bugs and issues on + +#include "platform.h" +#include "timer.h" + +void timer_set(volatile uint32_t * base, uint32_t compare) +{ + base[TIMER_COMPARE >> 2] = compare; + timer_reset(base); +} + +void timer_reset(volatile uint32_t * base) +{ + base[TIMER_CTRL >> 2] = 1 << TIMER_CTRL_RUN | 1 << TIMER_CTRL_CLEAR; +} + Index: v0.1/benchmarks/sha256/gpio.h =================================================================== --- v0.1/benchmarks/sha256/gpio.h (nonexistent) +++ v0.1/benchmarks/sha256/gpio.h (revision 47) @@ -0,0 +1,18 @@ +// The Potato Processor Benchmark Applications +// (c) Kristian Klomsten Skordal 2015 +// Report bugs and issues on + +#ifndef GPIO_H +#define GPIO_H + +#include + +#define DIRECTION_INPUT 0 +#define DIRECTION_OUTPUT 1 + +void gpio_set_direction(volatile uint32_t * base, uint32_t direction); +void gpio_set_output(volatile uint32_t * base, uint32_t output); +uint32_t gpio_get_value(volatile uint32_t * base); + +#endif + Index: v0.1/benchmarks/sha256/timer.h =================================================================== --- v0.1/benchmarks/sha256/timer.h (nonexistent) +++ v0.1/benchmarks/sha256/timer.h (revision 47) @@ -0,0 +1,14 @@ +// The Potato Processor Benchmark Applications +// (c) Kristian Klomsten Skordal 2015 +// Report bugs and issues on + +#ifndef TIMER_H +#define TIMER_H + +#include + +void timer_set(volatile uint32_t * base, uint32_t compare); +void timer_reset(volatile uint32_t * base); + +#endif + Index: v0.1/benchmarks/sha256/utilities.c =================================================================== --- v0.1/benchmarks/sha256/utilities.c (nonexistent) +++ v0.1/benchmarks/sha256/utilities.c (revision 47) @@ -0,0 +1,14 @@ +// The Potato Processor Benchmark Applications +// (c) Kristian Klomsten Skordal 2015 +// Report bugs and issues on + +#include "utilities.h" + +void * memset(void * s, int c, int n) +{ + char * temp = s; + for(int i = 0; i < n; ++i) + temp[i] = c; + return s; +} + Index: v0.1/benchmarks/sha256/uart.c =================================================================== --- v0.1/benchmarks/sha256/uart.c (nonexistent) +++ v0.1/benchmarks/sha256/uart.c (revision 47) @@ -0,0 +1,32 @@ +// The Potato Processor Benchmark Applications +// (c) Kristian Klomsten Skordal 2015 +// Report bugs and issues on + +#include +#include + +#include "platform.h" +#include "uart.h" + +void uart_puts(volatile uint32_t * base, const char * s) +{ + for(int i = 0; s[i] != 0; ++i) + uart_putc(base, s[i]); +} + +void uart_putc(volatile uint32_t * base, char c) +{ + // Wait until there is room in the transmit buffer: + while(base[UART_STATUS >> 2] & (1 << 3)); + base[UART_TX >> 2] = c & 0x000000ff; +} + +void uart_puth(volatile uint32_t * base, uint32_t n) +{ + static const char * hex_digits = "0123456789abcdef"; + uart_putc(base, '0'); + uart_putc(base, 'x'); + for(int i = 28; i >= 0; i -= 4) + uart_putc(base, hex_digits[(n >> i) & 0xf]); +} + Index: v0.1/benchmarks/sha256/sha256.h =================================================================== --- v0.1/benchmarks/sha256/sha256.h (nonexistent) +++ v0.1/benchmarks/sha256/sha256.h (revision 47) @@ -0,0 +1,31 @@ +// The Potato Processor Benchmark Applications +// (c) Kristian Klomsten Skordal 2015 +// Report bugs and issues on + +#ifndef SHA256_H +#define SHA256_H + +#include + +struct sha256_context +{ + uint32_t intermediate[8]; +}; + +// Resets a SHA256 context: +void sha256_reset(struct sha256_context * ctx); + +// Hash a block of data: +void sha256_hash_block(struct sha256_context * ctx, const uint32_t * data); + +// Pad a block of data to hash: +void sha256_pad_le_block(uint8_t * block, int block_length, uint64_t total_length); + +// Get the hash from a SHA256 context: +void sha256_get_hash(const struct sha256_context * ctx, uint8_t * hash); + +// Formats a hash for printing: +void sha256_format_hash(const uint8_t * hash, char * output); + +#endif + Index: v0.1/benchmarks/start.S =================================================================== --- v0.1/benchmarks/start.S (nonexistent) +++ v0.1/benchmarks/start.S (revision 47) @@ -0,0 +1,142 @@ +// The Potato Processor Benchmark Applications +// (c) Kristian Klomsten Skordal 2015 +// Report bugs and issues on + +// This file contains startup and initialization code for the Potato benchmark +// applications. + +#include "platform.h" +#include "potato.h" + +.section .init + +.global _start +_start: + +// Copies the .data section into the data memory section: +.hidden copy_data +copy_data: + la x1, __text_end // Copy source address + la x2, __data_begin // Copy destination address + la x3, __data_end // Copy destination end address + + beq x2, x3, 2f // Skip if there is no data to copy + +1: + lw x4, (x1) + sw x4, (x2) + addi x1, x1, 4 + addi x2, x2, 4 + + bne x2, x3, 1b // Repeat as long as there is more data to copy +2: + +.hidden clear_bss +clear_bss: + la x1, __bss_begin + la x2, __bss_end + beq x1, x2, 2f // Skip if there is no .bss section + +1: + sw x0, (x1) + addi x1, x1, 4 + bne x1, x2, 1b + +2: + +.hidden set_evec +set_evec: + // Set up an exception handler: + la x1, exception_handler_wrapper + csrw evec, x1 + +.hidden call_main +call_main: + la sp, __stack_top + jal main + csrw tohost, a0 +1: + j 1b + +.section .text + +.global exception_handler_wrapper +exception_handler_wrapper: + // Save all registers (even those that are saved by the IRQ handler + // function, to aid in debugging): + addi sp, sp, -124 + sw x1, 0(sp) + sw x2, 4(sp) + sw x3, 8(sp) + sw x4, 12(sp) + sw x5, 16(sp) + sw x6, 20(sp) + sw x7, 24(sp) + sw x8, 28(sp) + sw x9, 32(sp) + sw x10, 36(sp) + sw x11, 40(sp) + sw x12, 44(sp) + sw x13, 48(sp) + sw x14, 52(sp) + sw x15, 56(sp) + sw x16, 60(sp) + sw x17, 64(sp) + sw x18, 68(sp) + sw x19, 72(sp) + sw x20, 76(sp) + sw x21, 80(sp) + sw x22, 84(sp) + sw x23, 88(sp) + sw x24, 92(sp) + sw x25, 96(sp) + sw x26, 100(sp) + sw x27, 104(sp) + sw x28, 108(sp) + sw x29, 112(sp) + sw x30, 116(sp) + sw x31, 120(sp) + + csrr a0, cause + csrr a1, epc + mv a2, sp + jal exception_handler + +.hidden exception_return +exception_return: + // Restore all registers: + lw x1, 0(sp) + lw x2, 4(sp) + lw x3, 8(sp) + lw x4, 12(sp) + lw x5, 16(sp) + lw x6, 20(sp) + lw x7, 24(sp) + lw x8, 28(sp) + lw x9, 32(sp) + lw x10, 36(sp) + lw x11, 40(sp) + lw x12, 44(sp) + lw x13, 48(sp) + lw x14, 52(sp) + lw x15, 56(sp) + lw x16, 60(sp) + lw x17, 64(sp) + lw x18, 68(sp) + lw x19, 72(sp) + lw x20, 76(sp) + lw x21, 80(sp) + lw x22, 84(sp) + lw x23, 88(sp) + lw x24, 92(sp) + lw x25, 96(sp) + lw x26, 100(sp) + lw x27, 104(sp) + lw x28, 108(sp) + lw x29, 112(sp) + lw x30, 116(sp) + lw x31, 120(sp) + addi sp, sp, 124 + + sret + Index: v0.1/benchmarks/benchmark.ld =================================================================== --- v0.1/benchmarks/benchmark.ld (nonexistent) +++ v0.1/benchmarks/benchmark.ld (revision 47) @@ -0,0 +1,41 @@ +/* + * Linker Script for the Potato Processor benchmark applications + * (c) Kristian Klomsten Skordal 2014 - 2015 +// Report bugs and issues on + */ + +/* + * The linker script is intended to be used with the "official" test platform, + * described in platform.h. + */ + +ENTRY(_start); + +SECTIONS +{ + .text 0x0 : + { + *(.init*) + *(.text*) + __text_end = .; + } + + .data 0x2000 : AT(ADDR(.text) + SIZEOF(.text)) + { + __data_begin = .; + *(.rodata*) + *(.data*) + __data_end = ALIGN(4); + } + + .bss ALIGN(4): + { + __bss_begin = .; + *(.bss*) + __bss_end = ALIGN(4); + } + + __stack_top = 0x4000; +} + + Index: v0.1/docs/manual.tex =================================================================== --- v0.1/docs/manual.tex (nonexistent) +++ v0.1/docs/manual.tex (revision 47) @@ -0,0 +1,309 @@ +% The Potato Processor - User's Manual +% (c) Kristian Klomsten Skordal 2015 +% Report bugs and issues on + +\documentclass[12pt,a4paper]{report} + +\usepackage[utf8]{inputenc} +\usepackage[pdftitle={The Potato Processor: Technical Reference Manual}, + pdfauthor={Kristian Klomsten Skordal}]{hyperref} +\usepackage{placeins} +\usepackage{titlesec} +\usepackage[english]{babel} + +\newcommand{\register}[1]{\textsc{#1}} + +\titleformat{\chapter}[block]{\normalfont\huge\bfseries}{\thechapter}{20pt}{\Huge}\titlespacing*{\chapter}{0pt}{50pt}{40pt} + +\begin{document} + +\begin{titlepage} + \begin{center} + \vspace*{3cm} + {\large The Potato Processor}\\[0.5cm] + {\Huge\bf Technical Reference Manual}\\[6cm] + + \textsc{Kristian Klomsten Skordal}\\\href{mailto:skordal@opencores.org}{skordal@opencores.org}\\[3em] + + \vfill + {Project page:\\\url{http://opencores.org/project,potato}}\\[0.2em] + {Report bugs and issues on\\\url{http://opencores.org/project,potato,bugtracker}}\\[1.2em] + {\small Updated \today} + \end{center} +\end{titlepage} + +\tableofcontents + +\chapter{Introduction} + +The Potato processor is an implementation of the 32-bit integer subset of the RISC-V +instruction set v2.0. It is designed around a standard 5-stage pipeline. All instructions +execute in 1 cycle, with the exception of load and store instructions when the processor +has to wait for external memory. + +The processor has been tested on an Artix~7 (xc7a100tcsg324-1) FPGA from Xilinx, on the +Nexys 4 board from Digilent. More details about the test design can be found in chapter +\ref{cha:quickstart}. + +\section{Features} +Here is a highlight of the current features of the Potato processor: + +\begin{itemize} +\item Implements the complete 32-bit integer subset of the RISC-V ISA v2.0. +\item Implements the \textsc{csr*} instructions from the RISC-V supervisor extensions v1.0. +\item Supports using the \register{fromhost}/\register{tohost} registers for communicating + with a host environment, such as a simulator, or peripherals. +\item Supports exception handling, with support for 8 individually maskable IRQ inputs. +\item Includes a wishbone B4 compatible interface. +\end{itemize} + +\section{Planned features} +Here is a highlight of the future planned features of the Potato processor: + +\begin{itemize} +\item Caches. +\item Branch prediction. +\item Hardware multiplication and division support (the RISC-V M extension). +\item Compressed instruction support (the RISC-V C extension). +\item Supervisor mode support +\end{itemize} + +\chapter{Quick Start Guide} +\label{cha:quickstart} + +This chapter contains instructions on getting started with the demo/example design that is +included in the Potato source distribution. The example design targets the Nexys 4 board +available from Digilent\footnote{See \url{http://www.digilentinc.com/Products/Detail.cfm?Prod=NEXYS4}}. + +\section{Setting up the Vivado Project} + +Start by creating a new project in Vivado. Import all source files from the \texttt{src/} directory, +which contains all source files required for using the processor. Then import all source files from +the \texttt{example/} directory, which contains the toplevel setup for the example SoC design, +and from the \texttt{soc/} directory, which contains various peripherals for the processor. + +\section{Adding IP Modules} + +The example design requires two additional IP modules. These are not included in the source +distribution and must be added separately. + +\subsection{Clock Generator} + +Add a clock generator using the Clocking Wizard. Name the component ``\texttt{clock\_generator}'' +and make sure that the checkboxes for ``frequency synthesis'' and ``safe clock startup'' are +selected. + +Add two output clocks with frequencies of 50~MHz and 10~MHz. Rename the corresponding ports +to ``\texttt{system\_clk}'' and ``\texttt{timer\_clk}''. Rename the input clock signal to +``\texttt{clk}''. + +The added module should appear in the hierarchy under the toplevel module as ``\texttt{clkgen}''. + +\subsection{Instruction memory} + +Add a block RAM to use for storing the test application using the Block Memory Generator. +Choose ``Single-port ROM'' as memory type and name the module ``\texttt{instruction\_rom}''. +Set port A width to 32 bits and the depth to 2048 words. Initialize the block RAM with +your application or use one of the provided benchmarks, such as the SHA256 benchmark, +which, when built, produces a \texttt{.coe} file that can be used for this purpose. + +Note that in order to build a benchmark application, you have to install a RISC-V toolchain. +See section \ref{sec:toolchain} for instructions on how to accomplish this. + +\section{Running an Example Application} + +Assuming you initialized the instruction memory with the SHA256 benchmark, synthesize and +implement the design, generate a bitfile and load it into the FPGA. Using a serial port +application, such as \texttt{minicom}, watch as the number of hashes per second are +printed to the screen and rejoice because it works! + +\chapter{Instantiating} + +The Potato processor can be used either with or without a wishbone interface. Using the wishbone +interface allows the processor to communicate with other wishbone-compatible peripherals. However, +if no such peripherals are to be used, the processor can, for instance, be connected directly to +block RAM memories for full performance without needing to use caches. + +\section{Customizing the Processor Core} +The processor can be customized using generics. The following list details the parameters +that can be changed: + +\begin{description} + \item[\texttt{PROCESSOR\_ID}:] Any 32-bit value used as the processor ID. This value can + be read back from the hardware thread ID register, \register{hartid}. + \item[\texttt{RESET\_ADDRESS}:] Any 32-bit value used as the address of the first instruction + fetched by the processor after it has been reset. +\end{description} + +\section{Instantiating in a Wishbone System} +\label{sec:instantiating-wishbone} + +In order to integrate the Potato processor into a wishbone-based system, the module \texttt{pp\_potato} +is used. It provides signals for the wishbone master interface, prefixed with \texttt{wb\_}, and +inputs for interrupts and the HTIF interface. + +The specifics of the wishbone interface is listed in table \ref{tab:wishbone}. To see an example +of the processor used in a Wishbone system, see the example design under the \texttt{example/} +directory. + +\begin{table} + \centering + \begin{tabular}{|l|l|} + \hline + 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 transfer & Not specified \\ + \hline + \end{tabular} + \caption{Wishbone Interface Specifics} + \label{tab:wishbone} +\end{table} + +\FloatBarrier + +\section{Instantiating in a Standalone System} +\label{sec:instantiating-standalone} + +The processor can also be used without connecting it to the Wishbone bus. An example +of this can be seen in the processor testbench, \texttt{tb\_processor.vhd}. + +\section{Verifying} + +The processor provides an automatic testing environment for verifying that the processor +correctly executes the instructions of the ISA. The tests have been extracted from the +official test suite available at \url{https://github.com/riscv/riscv-tests} and covers +most of the available instructions. + +Two testbenches are used to execute the test programmes: \texttt{tb\_processor.vhd}, in +which the processor is directly connected to block-RAM-like memories so the processor +never stalls to wait for memory operations to finish (see section \ref{sec:instantiating-standalone} +for more details about this kind of setup), and \texttt{tb\_soc.vhd}, which models a +simple system-on-chip with the processor connected to memories through the +wishbone interface (see section \ref{sec:instantiating-wishbone} for more information +about this kind of setup). + +To run the test suites, run \texttt{make run-tests} or \texttt{make run-soc-tests}. + +Make sure that \texttt{xelab} and \texttt{xsim} is in your \texttt{PATH} or the +tests will fail. + +\chapter{Programming} + +The processor implements the RISC-V instruction set, and can be programmed with tools +such as GCC. + +\section{Building a RISC-V Toolchain} +\label{sec:toolchain} + +An ``official'' toolchain is provided by the RISC-V project. In order to install it, clone +the ``riscv-tools'' Git repository from \url{https://github.com/riscv/riscv-tools} and follow +the instructions provided by the README file. + +\section{Control and Status Registers} + +The supported control and status registers are shown in table \ref{tab:csr_list}. The registers +can be manipulated using the \textsc{csr*} family of instructions, listed in \ref{sec:csr_instrs}. + +\begin{table} + \centering + \begin{tabular}{|l|l|l|} + \hline + \textbf{Name} & \textbf{ID} & \textbf{Description} \\ + \hline + \register{hartid} & 0x50b & Hardware thread ID \\ + \register{evec} & 0x508 & Exception vector address \\ + \register{epc} & 0x502 & Return address for exceptions \\ + \register{cause} & 0x509 & Exception cause \\ + \register{sup0} & 0x500 & Support register 0, for operating system use \\ + \register{sup1} & 0x501 & Support register 1, for operating system use \\ + \register{badvaddr} & 0x503 & Bad address, used for invalid address exceptions \\ + \register{status} & 0x50a & Processor status and control register \\ + \register{tohost} & 0x51e & Register for sending data to a host system \\ + \register{fromhost} & 0x51f & Register where data received from a host system is stored \\ + \register{cycle} & 0xc00 & Cycle counter, low 32 bits \\ + \register{cycleh} & 0xc80 & Cycle counter, high 32 bits \\ + \register{time} & 0xc01 & Timer tick counter, low 32 bits \\ + \register{timeh} & 0xc81 & Timer tick counter, high 32 bits \\ + \register{instret} & 0xc02 & Retired instruction counter, low 32 bits \\ + \register{instreth} & 0xc82 & Retired instruction counter, high 32 bits \\ + \hline + \end{tabular} + \caption{List of Control and Status Registers} + \label{tab:csr_list} +\end{table} +\FloatBarrier + +\chapter{Instruction Set} + +The Potato processor is designed to support the full 32-bit integer subset of +the RISC-V instruction set, version 2.0. The ISA documentation is available +from \url{http://riscv.org}. + +\section{Status and Control Register Instructions} +\label{sec:csr_instrs} + +In addition to the base ISA, some additional instructions have been imported +from the RISC-V supervisor specification\footnote{The processor is in +the process of being upgraded to the new specification.} version 1.0. + +\begin{table}[htb] + \centering + \begin{tabular}{|l|l|} + \hline + \textbf{Mnemonic} & \textbf{Description} \\ + \hline + \texttt{scall} & System call \\ + \texttt{sbreak} & Breakpoint instruction \\ + \texttt{sret} & Exception return \\ + \hline + \texttt{csrrw rd, rs1, CSR} & Writes rs1 into CSR, place sold value in rd \\ + \texttt{csrrs rd, rs1, CSR} & Ors rs1 with CSR, places old value in rd \\ + \texttt{csrrc rd, rs1, CSR} & Ands the inverse of rs1 with CSR, places old value in rd \\ + \texttt{csrrwi rd, imm, CSR} & Writes imm into CSR, places old value in rd \\ + \texttt{csrrsi rd, imm, CSR} & Ors CSR with imm, places old value in rd \\ + \texttt{csrrci rd, imm, CSR} & Ands the inverse of imm with CSR, places old value in rd \\ + \hline + \end{tabular} + \caption{List of CSR Instructions} +\end{table} + +\appendix + +\chapter{Peripherals} + +The source distribution of the processor contains several peripheral modules that can be +used in system-on-chip designs using the Potato processor (or other processors). + +This chapter briefly describes each of the modules. + +\section{GPIO} + +The GPIO module provides a simple GPIO interface for up to 32 general purpose pins. +Each pin can be separately configured to work as either an input or an output pin. + +Registers are provided to set the direction of each pin. Additional registers +provide the ability to read or write the values of the pins. + +\section{Timer} + +The timer module provides a timer that fires off an interrupt at a specified +interval. + +\section{UART} + +The UART module provies a fixed-baudrate serial port interface. It features +separate FIFOs for buffering input and output data, and interrupts for when +the module is ready to send or has received data. + +\section{Memory} + +The memory module is basically a simple block RAM wrapper with support for +byte-writes. + +\end{document} + Index: v0.1/soc/pp_soc_gpio.vhd =================================================================== --- v0.1/soc/pp_soc_gpio.vhd (nonexistent) +++ v0.1/soc/pp_soc_gpio.vhd (revision 47) @@ -0,0 +1,95 @@ +-- 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 Generic Wishbone GPIO Module. +--! The following registers are defined: +--! * 0: Input values, one bit per GPIO (read-only) +--! * 1: Output values, one bit per GPIO (read/write) +--! * 2: Direction register, 0 means input, 1 means output. +entity pp_soc_gpio is + generic( + NUM_GPIOS : natural := 32 + ); + port( + clk : in std_logic; + reset : in std_logic; + + -- GPIO interface: + gpio : inout std_logic_vector(NUM_GPIOS - 1 downto 0); + + -- Wishbone interface: + wb_adr_in : in std_logic_vector( 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_we_in : in std_logic; + wb_ack_out : out std_logic + ); +end entity pp_soc_gpio; + +architecture behaviour of pp_soc_gpio is + + signal direction_register : std_logic_vector(NUM_GPIOS - 1 downto 0); + signal output_register : std_logic_vector(NUM_GPIOS - 1 downto 0); + signal input_register : std_logic_vector(NUM_GPIOS - 1 downto 0); + + signal ack : std_logic := '0'; + +begin + + assert NUM_GPIOS > 0 and NUM_GPIOS <= 32 + report "Only a number between 1 and 32 (inclusive) GPIOs are supported!" + severity FAILURE; + + io_setup: for i in 0 to NUM_GPIOS - 1 generate + gpio(i) <= 'Z' when direction_register(i) = '0' else output_register(i); + input_register(i) <= gpio(i) when direction_register(i) = '0' else '0'; + end generate; + + wb_ack_out <= ack and wb_cyc_in and wb_stb_in; + + wishbone: process(clk) + begin + if rising_edge(clk) then + if reset = '1' then + direction_register <= (others => '0'); + output_register <= (others => '0'); + wb_dat_out <= (others => '0'); + ack <= '0'; + else + if wb_cyc_in = '1' and wb_stb_in = '1' and ack = '0' then + if wb_we_in = '1' then + case wb_adr_in is + when b"01" => + output_register <= wb_dat_in(NUM_GPIOS - 1 downto 0); + when b"10" => + direction_register <= wb_dat_in(NUM_GPIOS - 1 downto 0); + when others => + end case; + ack <= '1'; + else + case wb_adr_in is + when b"00" => + wb_dat_out <= std_logic_vector(resize(unsigned(input_register), wb_dat_out'length)); + when b"01" => + wb_dat_out <= std_logic_vector(resize(unsigned(output_register), wb_dat_out'length)); + when b"10" => + wb_dat_out <= std_logic_vector(resize(unsigned(direction_register), wb_dat_out'length)); + when others => + end case; + ack <= '1'; + end if; + elsif wb_stb_in = '0' then + ack <= '0'; + end if; + end if; + end if; + end process wishbone; + +end architecture behaviour; Index: v0.1/soc/pp_soc_timer.vhd =================================================================== --- v0.1/soc/pp_soc_timer.vhd (nonexistent) +++ v0.1/soc/pp_soc_timer.vhd (revision 47) @@ -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; + +--! @brief Simple timer module for generating periodic interrupts. +--! The following registers are defined: +--! * 0: Control register. The bits are: +--! - 0: Run - set to '1' to enable the counter +--! - 1: Clear - set to '1' to clear the counter after a comparison match or just to reset it +--! * 1: Compare register, set this to the value where an interrupt should be generated. +--! * 2: Counter register, should only be read, but can be written if you want to. +entity pp_soc_timer is + port( + clk : in std_logic; + reset : in std_logic; + + -- Timer interrupt: + irq : out std_logic; + + -- Wishbone interface: + wb_adr_in : in std_logic_vector( 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_we_in : in std_logic; + wb_ack_out : out std_logic + ); +end entity; + +architecture behaviour of pp_soc_timer is + signal ctrl_run : std_logic; + + signal counter : std_logic_vector(31 downto 0); + signal compare : std_logic_vector(31 downto 0); + + -- Wishbone acknowledge signal: + signal ack : std_logic; +begin + + wb_ack_out <= ack and wb_cyc_in and wb_stb_in; + irq <= '1' when counter = compare else '0'; + + timer: process(clk) + begin + if rising_edge(clk) then + if reset = '1' then + wb_dat_out <= (others => '0'); + ack <= '0'; + + ctrl_run <= '0'; + counter <= (others => '0'); + compare <= (others => '1'); + else + if ctrl_run = '1' and counter /= compare then + counter <= std_logic_vector(unsigned(counter) + 1); + end if; + + if wb_cyc_in = '1' and wb_stb_in = '1' and ack = '0' then + if wb_we_in = '1' then + case wb_adr_in is + when b"00" => -- Write control register + ctrl_run <= wb_dat_in(0); + if wb_dat_in(1) = '1' then + counter <= (others => '0'); + end if; + when b"01" => -- Write compare register + compare <= wb_dat_in; + when b"10" => -- Write count register + counter <= wb_dat_in; + when b"11" => -- Unused register + when others => + end case; + ack <= '1'; + else + case wb_adr_in is + when b"00" => -- Read control register + wb_dat_out <= (0 => ctrl_run, others => '0'); + when b"01" => -- Read compare register + wb_dat_out <= compare; + when b"10" => -- Read count register + wb_dat_out <= counter; + when b"11" => -- Unused register + when others => + end case; + ack <= '1'; + end if; + elsif wb_stb_in = '0' then + ack <= '0'; + end if; + end if; + end if; + end process timer; + +end architecture behaviour; Index: v0.1/soc/pp_soc_dummy.vhd =================================================================== --- v0.1/soc/pp_soc_dummy.vhd (nonexistent) +++ v0.1/soc/pp_soc_dummy.vhd (revision 47) @@ -0,0 +1,56 @@ +-- 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 Dummy module for an SoC implementation. +--! Reads returns whatever was last written into the module. +entity pp_soc_dummy is + port( + clk : in std_logic; + reset : in std_logic; + + -- Wishbone signals: + 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_we_in : in std_logic; + wb_ack_out : out std_logic + ); +end entity pp_soc_dummy; + +architecture behaviour of pp_soc_dummy is + + signal reg : std_logic_vector(31 downto 0); + signal ack : std_logic; + +begin + + wb_ack_out <= ack and wb_cyc_in and wb_stb_in; + + wishbone: process(clk) + begin + if rising_edge(clk) then + if reset = '1' then + reg <= (others => '0'); + ack <= '0'; + else + if wb_cyc_in = '1' and wb_stb_in = '1' and ack = '0' then + if wb_we_in = '1' then + reg <= wb_dat_in; + ack <= '1'; + else + wb_dat_out <= reg; + ack <= '1'; + end if; + elsif wb_stb_in = '0' then + ack <= '0'; + end if; + end if; + end if; + end process wishbone; + +end architecture behaviour; Index: v0.1/soc/pp_soc_uart.vhd =================================================================== --- v0.1/soc/pp_soc_uart.vhd (nonexistent) +++ v0.1/soc/pp_soc_uart.vhd (revision 47) @@ -0,0 +1,333 @@ +-- 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 Simple UART module. +--! The following registers are defined: +--! 0 - Transmit data register (write-only) +--! 1 - Receive data register (read-only) +--! 2 - Status register; (read-only) +--! - Bit 0: data in receive buffer +--! - Bit 1: no data in transmit buffer +--! - Bit 2: receive buffer full +--! - Bit 3: transmit buffer full +--! 3 - Control register, currently unused. +entity pp_soc_uart is + generic( + FIFO_DEPTH : natural := 64; --! Depth of the input and output FIFOs. + SAMPLE_CLK_DIVISOR : natural := 54 --! Divisor used to obtain the sample clock, f_clk / (16 * baudrate). + ); + port( + clk : in std_logic; + reset : in std_logic; + + -- UART ports: + txd : out std_logic; + rxd : in std_logic; + + -- Interrupt signals: + irq_send_buffer_empty : out std_logic; + irq_data_received : out std_logic; + + -- Wishbone ports: + wb_adr_in : in std_logic_vector(1 downto 0); + wb_dat_in : in std_logic_vector(7 downto 0); + wb_dat_out : out std_logic_vector(7 downto 0); + wb_we_in : in std_logic; + wb_cyc_in : in std_logic; + wb_stb_in : in std_logic; + wb_ack_out : out std_logic + ); +end entity pp_soc_uart; + +architecture behaviour of pp_soc_uart is + + subtype bitnumber is natural range 0 to 7; + + -- UART sample clock signals: + signal sample_clk : std_logic; + + subtype sample_clk_counter_type is natural range 0 to SAMPLE_CLK_DIVISOR - 1; + signal sample_clk_counter : sample_clk_counter_type := 0; + + -- UART receive process signals: + type rx_state_type is (IDLE, RECEIVE, STOPBIT); + signal rx_state : rx_state_type; + signal rx_byte : std_logic_vector(7 downto 0); + signal rx_current_bit : bitnumber; + + subtype rx_sample_counter_type is natural range 0 to 15; + signal rx_sample_counter : rx_sample_counter_type; + signal rx_sample_value : rx_sample_counter_type; + + -- UART transmit process signals: + type tx_state_type is (IDLE, TRANSMIT, STOPBIT); + signal tx_state : tx_state_type; + signal tx_byte : std_logic_vector(7 downto 0); + signal tx_current_bit : bitnumber; + + -- UART transmit clock: + subtype uart_tx_counter_type is natural range 0 to 15; + signal uart_tx_counter : uart_tx_counter_type := 0; + signal uart_tx_clk : std_logic; + + -- Buffer signals: + signal send_buffer_full, send_buffer_empty : std_logic; + signal recv_buffer_full, recv_buffer_empty : std_logic; + signal send_buffer_input, send_buffer_output : std_logic_vector(7 downto 0); + signal recv_buffer_input, recv_buffer_output : std_logic_vector(7 downto 0); + signal send_buffer_push, send_buffer_pop : std_logic := '0'; + signal recv_buffer_push, recv_buffer_pop : std_logic := '0'; + + -- Wishbone signals: + type wb_state_type is (IDLE, WRITE_ACK, READ_ACK); + signal wb_state : wb_state_type; + + signal wb_ack : std_logic; --! Wishbone acknowledge signal + +begin + + irq_send_buffer_empty <= send_buffer_empty; + irq_data_received <= not recv_buffer_empty; + + ---------- UART receive ---------- + + recv_buffer_input <= rx_byte; + + uart_receive: process(clk) + begin + if rising_edge(clk) then + if reset = '1' then + rx_state <= IDLE; + else + case rx_state is + when IDLE => + if sample_clk = '1' and rxd = '0' then + rx_sample_value <= rx_sample_counter; + rx_current_bit <= 0; + rx_state <= RECEIVE; + end if; + when RECEIVE => + if sample_clk = '1' and rx_sample_counter = rx_sample_value then + if rx_current_bit /= 7 then + rx_byte(rx_current_bit) <= rxd; + rx_current_bit <= rx_current_bit + 1; + else + rx_byte(rx_current_bit) <= rxd; + rx_state <= STOPBIT; + + if recv_buffer_full = '0' then + recv_buffer_push <= '1'; + end if; + end if; + end if; + when STOPBIT => + recv_buffer_push <= '0'; + + if sample_clk = '1' and rx_sample_counter = rx_sample_value then + rx_state <= IDLE; + end if; + end case; + end if; + end if; + end process uart_receive; + + sample_counter: process(clk) + begin + if rising_edge(clk) then + if reset = '1' then + rx_sample_counter <= 0; + elsif sample_clk = '1' then + if rx_sample_counter = 15 then + rx_sample_counter <= 0; + else + rx_sample_counter <= rx_sample_counter + 1; + end if; + end if; + end if; + end process sample_counter; + + ---------- UART transmit ---------- + + tx_byte <= send_buffer_output; + + uart_transmit: process(clk) + begin + if rising_edge(clk) then + if reset = '1' then + txd <= '1'; + tx_state <= IDLE; + send_buffer_pop <= '0'; + tx_current_bit <= 0; + else + case tx_state is + when IDLE => + if send_buffer_empty = '0' and uart_tx_clk = '1' then + txd <= '0'; + send_buffer_pop <= '1'; + tx_current_bit <= 0; + tx_state <= TRANSMIT; + elsif uart_tx_clk = '1' then + txd <= '1'; + end if; + when TRANSMIT => + if send_buffer_pop = '1' then + send_buffer_pop <= '0'; + elsif uart_tx_clk = '1' and tx_current_bit = 7 then + txd <= tx_byte(tx_current_bit); + tx_state <= STOPBIT; + elsif uart_tx_clk = '1' then + txd <= tx_byte(tx_current_bit); + tx_current_bit <= tx_current_bit + 1; + end if; + when STOPBIT => + if uart_tx_clk = '1' then + txd <= '1'; + tx_state <= IDLE; + end if; + end case; + end if; + end if; + end process uart_transmit; + + uart_tx_clock_generator: process(clk) + begin + if rising_edge(clk) then + if reset = '1' then + uart_tx_counter <= 0; + uart_tx_clk <= '0'; + else + if sample_clk = '1' then + if uart_tx_counter = 15 then + uart_tx_counter <= 0; + uart_tx_clk <= '1'; + else + uart_tx_counter <= uart_tx_counter + 1; + uart_tx_clk <= '0'; + end if; + else + uart_tx_clk <= '0'; + end if; + end if; + end if; + end process uart_tx_clock_generator; + + ---------- Sample clock generator ---------- + + sample_clock_generator: process(clk) + begin + if rising_edge(clk) then + if reset = '1' then + sample_clk_counter <= 0; + sample_clk <= '0'; + else + if sample_clk_counter = SAMPLE_CLK_DIVISOR - 1 then + sample_clk_counter <= 0; + sample_clk <= '1'; + else + sample_clk_counter <= sample_clk_counter + 1; + sample_clk <= '0'; + end if; + end if; + end if; + end process sample_clock_generator; + + ---------- Data Buffers ---------- + + send_buffer: entity work.pp_fifo + generic map( + DEPTH => FIFO_DEPTH, + WIDTH => 8 + ) port map( + clk => clk, + reset => reset, + full => send_buffer_full, + empty => send_buffer_empty, + data_in => send_buffer_input, + data_out => send_buffer_output, + push => send_buffer_push, + pop => send_buffer_pop + ); + + recv_buffer: entity work.pp_fifo + generic map( + DEPTH => FIFO_DEPTH, + WIDTH => 8 + ) port map( + clk => clk, + reset => reset, + full => recv_buffer_full, + empty => recv_buffer_empty, + data_in => recv_buffer_input, + data_out => recv_buffer_output, + push => recv_buffer_push, + pop => recv_buffer_pop + ); + + ---------- Wishbone Interface ---------- + + wb_ack_out <= wb_ack and wb_cyc_in and wb_stb_in; + + wishbone: process(clk) + begin + if rising_edge(clk) then + if reset = '1' then + wb_ack <= '0'; + wb_state <= IDLE; + send_buffer_push <= '0'; + else + case wb_state is + when IDLE => + if wb_cyc_in = '1' and wb_stb_in = '1' then + if wb_we_in = '1' then -- Write to register + if wb_adr_in = b"00" then + send_buffer_input <= wb_dat_in; + send_buffer_push <= '1'; + wb_ack <= '1'; + wb_state <= WRITE_ACK; + else -- Invalid write, just ack and ignore + wb_ack <= '1'; + wb_state <= WRITE_ACK; + end if; + else -- Read from register + if wb_adr_in = b"01" then + recv_buffer_pop <= '1'; + wb_state <= READ_ACK; + elsif wb_adr_in = b"10" then + wb_dat_out <= x"0" & send_buffer_full & recv_buffer_full & send_buffer_empty & not recv_buffer_empty; + wb_ack <= '1'; + wb_state <= READ_ACK; + else + wb_dat_out <= (others => '0'); + wb_ack <= '1'; + wb_state <= READ_ACK; + end if; + end if; + end if; + when WRITE_ACK => + send_buffer_push <= '0'; + + if wb_stb_in = '0' then + wb_ack <= '0'; + wb_state <= IDLE; + end if; + when READ_ACK => + if recv_buffer_pop = '1' then + wb_ack <= '1'; + recv_buffer_pop <= '0'; + wb_dat_out <= recv_buffer_output; + end if; + + if wb_stb_in = '0' then + wb_ack <= '0'; + wb_state <= IDLE; + end if; + end case; + end if; + end if; + end process wishbone; + +end architecture behaviour; Index: v0.1/soc/pp_soc_memory.vhd =================================================================== --- v0.1/soc/pp_soc_memory.vhd (nonexistent) +++ v0.1/soc/pp_soc_memory.vhd (revision 47) @@ -0,0 +1,88 @@ +-- 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 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; Index: v0.1/testbenches/tb_soc_uart.vhd =================================================================== --- v0.1/testbenches/tb_soc_uart.vhd (nonexistent) +++ v0.1/testbenches/tb_soc_uart.vhd (revision 47) @@ -0,0 +1,95 @@ +-- 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; + +entity tb_soc_uart is +end entity tb_soc_uart; + +architecture testbench of tb_soc_uart is + + -- Clock signal: + signal clk : std_logic := '0'; + constant clk_period : time := 10 ns; + + -- Reset signal: + signal reset : std_logic := '1'; + + -- UART ports: + signal txd : std_logic; + signal rxd : std_logic := '1'; + + -- interrupt signals: + signal irq_send_buffer_empty : std_logic; + signal irq_data_received : std_logic; + + -- Wishbone ports: + signal wb_adr_in : std_logic_vector(1 downto 0) := (others => '0'); + signal wb_dat_in : std_logic_vector(7 downto 0) := (others => '0'); + signal wb_dat_out : std_logic_vector(7 downto 0); + signal wb_we_in : std_logic := '0'; + signal wb_cyc_in : std_logic := '0'; + signal wb_stb_in : std_logic := '0'; + signal wb_ack_out : std_logic; + +begin + + uut: entity work.pp_soc_uart + port map( + clk => clk, + reset => reset, + txd => txd, + rxd => rxd, + irq_send_buffer_empty => irq_send_buffer_empty, + irq_data_received => irq_data_received, + wb_adr_in => wb_adr_in, + wb_dat_in => wb_dat_in, + wb_dat_out => wb_dat_out, + wb_we_in => wb_we_in, + wb_cyc_in => wb_cyc_in, + wb_stb_in => wb_stb_in, + wb_ack_out => wb_ack_out + ); + + -- Set up an internal loopback: + rxd <= txd; + + 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 * 2; + reset <= '0'; + + -- Write a 'P' (for Potato the Processor) to the UART: + wb_adr_in <= b"00"; + wb_dat_in <= x"50"; + wb_we_in <= '1'; + wb_cyc_in <= '1'; + wb_stb_in <= '1'; + + wait until wb_ack_out = '1'; + wait for clk_period; + wb_stb_in <= '0'; + wait for clk_period; + + -- Write an 'o': + wb_dat_in <= x"6f"; + wb_stb_in <= '1'; + wait until wb_ack_out = '1'; + wait for clk_period; + wb_stb_in <= '0'; + wait for clk_period; + + wait; + end process stimulus; + +end architecture testbench; Index: v0.1/testbenches/tb_soc_gpio.vhd =================================================================== --- v0.1/testbenches/tb_soc_gpio.vhd (nonexistent) +++ v0.1/testbenches/tb_soc_gpio.vhd (revision 47) @@ -0,0 +1,91 @@ +-- 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; + +entity tb_soc_gpio is +end entity tb_soc_gpio; + +architecture testbench of tb_soc_gpio is + + -- Clock signal: + signal clk : std_logic := '0'; + constant clk_period : time := 10 ns; + + -- Reset signal: + signal reset : std_logic := '1'; + + -- GPIOs: + signal gpio : std_logic_vector(31 downto 0); + + -- Wishbone bus: + signal wb_adr_in : std_logic_vector( 1 downto 0) := (others => '0'); + signal wb_dat_in : std_logic_vector(31 downto 0) := (others => '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_we_in : std_logic := '0'; + signal wb_ack_out : std_logic; +begin + + uut: entity work.pp_soc_gpio + generic map( + NUM_GPIOS => 32 + ) port map( + clk => clk, + reset => reset, + gpio => gpio, + 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_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 * 2; + reset <= '0'; + + -- Set the upper half of the GPIOs as inputs, the rest as outputs: + wb_dat_in <= x"0000ffff"; + wb_adr_in <= b"10"; + wb_we_in <= '1'; + wb_cyc_in <= '1'; + wb_stb_in <= '1'; + wait until wb_ack_out = '1'; + wait for clk_period; + wb_stb_in <= '0'; + wb_cyc_in <= '0'; + wb_we_in <= '0'; + wait for clk_period; + + -- Set the outputs to aa, see if the upper half gets ignored correctly: + wb_dat_in <= x"aaaaaaaa"; + wb_adr_in <= b"01"; + wb_we_in <= '1'; + wb_cyc_in <= '1'; + wb_stb_in <= '1'; + wait until wb_ack_out = '1'; + wait for clk_period; + wb_stb_in <= '0'; + wb_cyc_in <= '0'; + wb_we_in <= '0'; + wait for clk_period; + + wait; + end process stimulus; + +end architecture testbench; Index: v0.1/testbenches/tb_soc_timer.vhd =================================================================== --- v0.1/testbenches/tb_soc_timer.vhd (nonexistent) +++ v0.1/testbenches/tb_soc_timer.vhd (revision 47) @@ -0,0 +1,108 @@ +-- 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; + +entity tb_soc_timer is +end entity tb_soc_timer; + +architecture behaviour of tb_soc_timer is + + -- Clock signal: + signal clk : std_logic := '0'; + constant clk_period : time := 10 ns; + + -- Reset signal: + signal reset : std_logic := '1'; + + -- IRQ signal: + signal irq : std_logic; + + -- Wishbone interface: + signal wb_adr_in : std_logic_vector(1 downto 0) := (others => '0'); + signal wb_dat_in : std_logic_vector(31 downto 0) := (others => '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_we_in : std_logic := '0'; + signal wb_ack_out : std_logic; + +begin + + uut: entity work.pp_soc_timer + port map( + clk => clk, + reset => reset, + irq => irq, + 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_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 * 2; + reset <= '0'; + + wait for clk_period; + + -- Set the compare register to 50: + wb_cyc_in <= '1'; + wb_stb_in <= '1'; + wb_adr_in <= b"01"; + wb_dat_in <= x"00000032"; + wb_we_in <= '1'; + wait until wb_ack_out = '1'; + wait for clk_period; + + wb_stb_in <= '0'; + wait for clk_period; + + -- Start the timer: + wb_stb_in <= '1'; + wb_adr_in <= b"00"; + wb_dat_in <= x"00000003"; + wait until wb_ack_out = '1'; + wait for clk_period; + + wb_stb_in <= '0'; + wb_cyc_in <= '0'; + wb_we_in <= '0'; + wait for clk_period; + + -- Wait for the interrupt: + wait until irq = '1'; + wait for clk_period; + + -- Reset the interrupt: + wb_cyc_in <= '1'; + wb_stb_in <= '1'; + wb_we_in <= '1'; + wb_adr_in <= b"00"; + wb_dat_in <= x"00000003"; + wait until wb_ack_out = '1'; + wait for clk_period; + + wb_stb_in <= '0'; + wb_cyc_in <= '0'; + wb_we_in <= '0'; + wait for clk_period; + + wait; + end process stimulus; + +end architecture behaviour; Index: v0.1/testbenches/tb_soc_memory.vhd =================================================================== --- v0.1/testbenches/tb_soc_memory.vhd (nonexistent) +++ v0.1/testbenches/tb_soc_memory.vhd (revision 47) @@ -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: v0.1/testbenches/tb_processor.vhd =================================================================== --- v0.1/testbenches/tb_processor.vhd (nonexistent) +++ v0.1/testbenches/tb_processor.vhd (revision 47) @@ -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: v0.1/testbenches/tb_soc.vhd =================================================================== --- v0.1/testbenches/tb_soc.vhd (nonexistent) +++ v0.1/testbenches/tb_soc.vhd (revision 47) @@ -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: v0.1/riscv-tests/or.S =================================================================== --- v0.1/riscv-tests/or.S (nonexistent) +++ v0.1/riscv-tests/or.S (revision 47) @@ -0,0 +1,69 @@ +# See LICENSE for license details. + +#***************************************************************************** +# or.S +#----------------------------------------------------------------------------- +# +# Test or instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + #------------------------------------------------------------- + # Logical tests + #------------------------------------------------------------- + + TEST_RR_OP( 2, or, 0xff0fff0f, 0xff00ff00, 0x0f0f0f0f ); + TEST_RR_OP( 3, or, 0xfff0fff0, 0x0ff00ff0, 0xf0f0f0f0 ); + TEST_RR_OP( 4, or, 0x0fff0fff, 0x00ff00ff, 0x0f0f0f0f ); + TEST_RR_OP( 5, or, 0xf0fff0ff, 0xf00ff00f, 0xf0f0f0f0 ); + + #------------------------------------------------------------- + # Source/Destination tests + #------------------------------------------------------------- + + TEST_RR_SRC1_EQ_DEST( 6, or, 0xff0fff0f, 0xff00ff00, 0x0f0f0f0f ); + TEST_RR_SRC2_EQ_DEST( 7, or, 0xff0fff0f, 0xff00ff00, 0x0f0f0f0f ); + TEST_RR_SRC12_EQ_DEST( 8, or, 0xff00ff00, 0xff00ff00 ); + + #------------------------------------------------------------- + # Bypassing tests + #------------------------------------------------------------- + + TEST_RR_DEST_BYPASS( 9, 0, or, 0xff0fff0f, 0xff00ff00, 0x0f0f0f0f ); + TEST_RR_DEST_BYPASS( 10, 1, or, 0xfff0fff0, 0x0ff00ff0, 0xf0f0f0f0 ); + TEST_RR_DEST_BYPASS( 11, 2, or, 0x0fff0fff, 0x00ff00ff, 0x0f0f0f0f ); + + TEST_RR_SRC12_BYPASS( 12, 0, 0, or, 0xff0fff0f, 0xff00ff00, 0x0f0f0f0f ); + TEST_RR_SRC12_BYPASS( 13, 0, 1, or, 0xfff0fff0, 0x0ff00ff0, 0xf0f0f0f0 ); + TEST_RR_SRC12_BYPASS( 14, 0, 2, or, 0x0fff0fff, 0x00ff00ff, 0x0f0f0f0f ); + TEST_RR_SRC12_BYPASS( 15, 1, 0, or, 0xff0fff0f, 0xff00ff00, 0x0f0f0f0f ); + TEST_RR_SRC12_BYPASS( 16, 1, 1, or, 0xfff0fff0, 0x0ff00ff0, 0xf0f0f0f0 ); + TEST_RR_SRC12_BYPASS( 17, 2, 0, or, 0x0fff0fff, 0x00ff00ff, 0x0f0f0f0f ); + + TEST_RR_SRC21_BYPASS( 18, 0, 0, or, 0xff0fff0f, 0xff00ff00, 0x0f0f0f0f ); + TEST_RR_SRC21_BYPASS( 19, 0, 1, or, 0xfff0fff0, 0x0ff00ff0, 0xf0f0f0f0 ); + TEST_RR_SRC21_BYPASS( 20, 0, 2, or, 0x0fff0fff, 0x00ff00ff, 0x0f0f0f0f ); + TEST_RR_SRC21_BYPASS( 21, 1, 0, or, 0xff0fff0f, 0xff00ff00, 0x0f0f0f0f ); + TEST_RR_SRC21_BYPASS( 22, 1, 1, or, 0xfff0fff0, 0x0ff00ff0, 0xf0f0f0f0 ); + TEST_RR_SRC21_BYPASS( 23, 2, 0, or, 0x0fff0fff, 0x00ff00ff, 0x0f0f0f0f ); + + TEST_RR_ZEROSRC1( 24, or, 0xff00ff00, 0xff00ff00 ); + TEST_RR_ZEROSRC2( 25, or, 0x00ff00ff, 0x00ff00ff ); + TEST_RR_ZEROSRC12( 26, or, 0 ); + TEST_RR_ZERODEST( 27, or, 0x11111111, 0x22222222 ); + + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +RVTEST_DATA_END Index: v0.1/riscv-tests/blt.S =================================================================== --- v0.1/riscv-tests/blt.S (nonexistent) +++ v0.1/riscv-tests/blt.S (revision 47) @@ -0,0 +1,73 @@ +# See LICENSE for license details. + +#***************************************************************************** +# blt.S +#----------------------------------------------------------------------------- +# +# Test blt instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + #------------------------------------------------------------- + # Branch tests + #------------------------------------------------------------- + + # Each test checks both forward and backward branches + + TEST_BR2_OP_TAKEN( 2, blt, 0, 1 ); + TEST_BR2_OP_TAKEN( 3, blt, -1, 1 ); + TEST_BR2_OP_TAKEN( 4, blt, -2, -1 ); + + TEST_BR2_OP_NOTTAKEN( 5, blt, 1, 0 ); + TEST_BR2_OP_NOTTAKEN( 6, blt, 1, -1 ); + TEST_BR2_OP_NOTTAKEN( 7, blt, -1, -2 ); + TEST_BR2_OP_NOTTAKEN( 8, blt, 1, -2 ); + + #------------------------------------------------------------- + # Bypassing tests + #------------------------------------------------------------- + + TEST_BR2_SRC12_BYPASS( 9, 0, 0, blt, 0, -1 ); + TEST_BR2_SRC12_BYPASS( 10, 0, 1, blt, 0, -1 ); + TEST_BR2_SRC12_BYPASS( 11, 0, 2, blt, 0, -1 ); + TEST_BR2_SRC12_BYPASS( 12, 1, 0, blt, 0, -1 ); + TEST_BR2_SRC12_BYPASS( 13, 1, 1, blt, 0, -1 ); + TEST_BR2_SRC12_BYPASS( 14, 2, 0, blt, 0, -1 ); + + TEST_BR2_SRC12_BYPASS( 15, 0, 0, blt, 0, -1 ); + TEST_BR2_SRC12_BYPASS( 16, 0, 1, blt, 0, -1 ); + TEST_BR2_SRC12_BYPASS( 17, 0, 2, blt, 0, -1 ); + TEST_BR2_SRC12_BYPASS( 18, 1, 0, blt, 0, -1 ); + TEST_BR2_SRC12_BYPASS( 19, 1, 1, blt, 0, -1 ); + TEST_BR2_SRC12_BYPASS( 20, 2, 0, blt, 0, -1 ); + + #------------------------------------------------------------- + # Test delay slot instructions not executed nor bypassed + #------------------------------------------------------------- + + TEST_CASE( 21, x1, 3, \ + li x1, 1; \ + blt x0, x1, 1f; \ + addi x1, x1, 1; \ + addi x1, x1, 1; \ + addi x1, x1, 1; \ + addi x1, x1, 1; \ +1: addi x1, x1, 1; \ + addi x1, x1, 1; \ + ) + + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +RVTEST_DATA_END Index: v0.1/riscv-tests/xori.S =================================================================== --- v0.1/riscv-tests/xori.S (nonexistent) +++ v0.1/riscv-tests/xori.S (revision 47) @@ -0,0 +1,55 @@ +# See LICENSE for license details. + +#***************************************************************************** +# xori.S +#----------------------------------------------------------------------------- +# +# Test xori instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + #------------------------------------------------------------- + # Logical tests + #------------------------------------------------------------- + + TEST_IMM_OP( 2, xori, 0xff00f00f, 0x00ff0f00, 0xf0f ); + TEST_IMM_OP( 3, xori, 0x0ff00f00, 0x0ff00ff0, 0x0f0 ); + TEST_IMM_OP( 4, xori, 0x00ff0ff0, 0x00ff08ff, 0x70f ); + TEST_IMM_OP( 5, xori, 0xf00ff0ff, 0xf00ff00f, 0x0f0 ); + + #------------------------------------------------------------- + # Source/Destination tests + #------------------------------------------------------------- + + TEST_IMM_SRC1_EQ_DEST( 6, xori, 0xff00f00f, 0xff00f700, 0x70f ); + + #------------------------------------------------------------- + # Bypassing tests + #------------------------------------------------------------- + + TEST_IMM_DEST_BYPASS( 7, 0, xori, 0x0ff00f00, 0x0ff00ff0, 0x0f0 ); + TEST_IMM_DEST_BYPASS( 8, 1, xori, 0x00ff0ff0, 0x00ff08ff, 0x70f ); + TEST_IMM_DEST_BYPASS( 9, 2, xori, 0xf00ff0ff, 0xf00ff00f, 0x0f0 ); + + TEST_IMM_SRC1_BYPASS( 10, 0, xori, 0x0ff00f00, 0x0ff00ff0, 0x0f0 ); + TEST_IMM_SRC1_BYPASS( 11, 1, xori, 0x00ff0ff0, 0x00ff0fff, 0x00f ); + TEST_IMM_SRC1_BYPASS( 12, 2, xori, 0xf00ff0ff, 0xf00ff00f, 0x0f0 ); + + TEST_IMM_ZEROSRC1( 13, xori, 0x0f0, 0x0f0 ); + TEST_IMM_ZERODEST( 14, xori, 0x00ff00ff, 0x70f ); + + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +RVTEST_DATA_END Index: v0.1/riscv-tests/lbu.S =================================================================== --- v0.1/riscv-tests/lbu.S (nonexistent) +++ v0.1/riscv-tests/lbu.S (revision 47) @@ -0,0 +1,92 @@ +# See LICENSE for license details. + +#***************************************************************************** +# lbu.S +#----------------------------------------------------------------------------- +# +# Test lbu instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + #------------------------------------------------------------- + # Basic tests + #------------------------------------------------------------- + + TEST_LD_OP( 2, lbu, 0x000000ff, 0, tdat ); + TEST_LD_OP( 3, lbu, 0x00000000, 1, tdat ); + TEST_LD_OP( 4, lbu, 0x000000f0, 2, tdat ); + TEST_LD_OP( 5, lbu, 0x0000000f, 3, tdat ); + + # Test with negative offset + + TEST_LD_OP( 6, lbu, 0x000000ff, -3, tdat4 ); + TEST_LD_OP( 7, lbu, 0x00000000, -2, tdat4 ); + TEST_LD_OP( 8, lbu, 0x000000f0, -1, tdat4 ); + TEST_LD_OP( 9, lbu, 0x0000000f, 0, tdat4 ); + + # Test with a negative base + + TEST_CASE( 10, x3, 0x000000ff, \ + la x1, tdat; \ + addi x1, x1, -32; \ + lbu x3, 32(x1); \ + ) + + # Test with unaligned base + + TEST_CASE( 11, x3, 0x00000000, \ + la x1, tdat; \ + addi x1, x1, -6; \ + lbu x3, 7(x1); \ + ) + + #------------------------------------------------------------- + # Bypassing tests + #------------------------------------------------------------- + + TEST_LD_DEST_BYPASS( 12, 0, lbu, 0x000000f0, 1, tdat2 ); + TEST_LD_DEST_BYPASS( 13, 1, lbu, 0x0000000f, 1, tdat3 ); + TEST_LD_DEST_BYPASS( 14, 2, lbu, 0x00000000, 1, tdat1 ); + + TEST_LD_SRC1_BYPASS( 15, 0, lbu, 0x000000f0, 1, tdat2 ); + TEST_LD_SRC1_BYPASS( 16, 1, lbu, 0x0000000f, 1, tdat3 ); + TEST_LD_SRC1_BYPASS( 17, 2, lbu, 0x00000000, 1, tdat1 ); + + #------------------------------------------------------------- + # Test write-after-write hazard + #------------------------------------------------------------- + + TEST_CASE( 18, x2, 2, \ + la x3, tdat; \ + lbu x2, 0(x3); \ + li x2, 2; \ + ) + + TEST_CASE( 19, x2, 2, \ + la x3, tdat; \ + lbu x2, 0(x3); \ + nop; \ + li x2, 2; \ + ) + + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +tdat: +tdat1: .byte 0xff +tdat2: .byte 0x00 +tdat3: .byte 0xf0 +tdat4: .byte 0x0f + +RVTEST_DATA_END Index: v0.1/riscv-tests/bgeu.S =================================================================== --- v0.1/riscv-tests/bgeu.S (nonexistent) +++ v0.1/riscv-tests/bgeu.S (revision 47) @@ -0,0 +1,76 @@ +# See LICENSE for license details. + +#***************************************************************************** +# bgeu.S +#----------------------------------------------------------------------------- +# +# Test bgeu instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + #------------------------------------------------------------- + # Branch tests + #------------------------------------------------------------- + + # Each test checks both forward and backward branches + + TEST_BR2_OP_TAKEN( 2, bgeu, 0x00000000, 0x00000000 ); + TEST_BR2_OP_TAKEN( 3, bgeu, 0x00000001, 0x00000001 ); + TEST_BR2_OP_TAKEN( 4, bgeu, 0xffffffff, 0xffffffff ); + TEST_BR2_OP_TAKEN( 5, bgeu, 0x00000001, 0x00000000 ); + TEST_BR2_OP_TAKEN( 6, bgeu, 0xffffffff, 0xfffffffe ); + TEST_BR2_OP_TAKEN( 7, bgeu, 0xffffffff, 0x00000000 ); + + TEST_BR2_OP_NOTTAKEN( 8, bgeu, 0x00000000, 0x00000001 ); + TEST_BR2_OP_NOTTAKEN( 9, bgeu, 0xfffffffe, 0xffffffff ); + TEST_BR2_OP_NOTTAKEN( 10, bgeu, 0x00000000, 0xffffffff ); + TEST_BR2_OP_NOTTAKEN( 11, bgeu, 0x7fffffff, 0x80000000 ); + + #------------------------------------------------------------- + # Bypassing tests + #------------------------------------------------------------- + + TEST_BR2_SRC12_BYPASS( 12, 0, 0, bgeu, 0xefffffff, 0xf0000000 ); + TEST_BR2_SRC12_BYPASS( 13, 0, 1, bgeu, 0xefffffff, 0xf0000000 ); + TEST_BR2_SRC12_BYPASS( 14, 0, 2, bgeu, 0xefffffff, 0xf0000000 ); + TEST_BR2_SRC12_BYPASS( 15, 1, 0, bgeu, 0xefffffff, 0xf0000000 ); + TEST_BR2_SRC12_BYPASS( 16, 1, 1, bgeu, 0xefffffff, 0xf0000000 ); + TEST_BR2_SRC12_BYPASS( 17, 2, 0, bgeu, 0xefffffff, 0xf0000000 ); + + TEST_BR2_SRC12_BYPASS( 18, 0, 0, bgeu, 0xefffffff, 0xf0000000 ); + TEST_BR2_SRC12_BYPASS( 19, 0, 1, bgeu, 0xefffffff, 0xf0000000 ); + TEST_BR2_SRC12_BYPASS( 20, 0, 2, bgeu, 0xefffffff, 0xf0000000 ); + TEST_BR2_SRC12_BYPASS( 21, 1, 0, bgeu, 0xefffffff, 0xf0000000 ); + TEST_BR2_SRC12_BYPASS( 22, 1, 1, bgeu, 0xefffffff, 0xf0000000 ); + TEST_BR2_SRC12_BYPASS( 23, 2, 0, bgeu, 0xefffffff, 0xf0000000 ); + + #------------------------------------------------------------- + # Test delay slot instructions not executed nor bypassed + #------------------------------------------------------------- + + TEST_CASE( 24, x1, 3, \ + li x1, 1; \ + bgeu x1, x0, 1f; \ + addi x1, x1, 1; \ + addi x1, x1, 1; \ + addi x1, x1, 1; \ + addi x1, x1, 1; \ +1: addi x1, x1, 1; \ + addi x1, x1, 1; \ + ) + + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +RVTEST_DATA_END Index: v0.1/riscv-tests/sra.S =================================================================== --- v0.1/riscv-tests/sra.S (nonexistent) +++ v0.1/riscv-tests/sra.S (revision 47) @@ -0,0 +1,90 @@ +# See LICENSE for license details. + +#***************************************************************************** +# sra.S +#----------------------------------------------------------------------------- +# +# Test sra instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + #------------------------------------------------------------- + # Arithmetic tests + #------------------------------------------------------------- + + TEST_RR_OP( 2, sra, 0x80000000, 0x80000000, 0 ); + TEST_RR_OP( 3, sra, 0xc0000000, 0x80000000, 1 ); + TEST_RR_OP( 4, sra, 0xff000000, 0x80000000, 7 ); + TEST_RR_OP( 5, sra, 0xfffe0000, 0x80000000, 14 ); + TEST_RR_OP( 6, sra, 0xffffffff, 0x80000001, 31 ); + + TEST_RR_OP( 7, sra, 0x7fffffff, 0x7fffffff, 0 ); + TEST_RR_OP( 8, sra, 0x3fffffff, 0x7fffffff, 1 ); + TEST_RR_OP( 9, sra, 0x00ffffff, 0x7fffffff, 7 ); + TEST_RR_OP( 10, sra, 0x0001ffff, 0x7fffffff, 14 ); + TEST_RR_OP( 11, sra, 0x00000000, 0x7fffffff, 31 ); + + TEST_RR_OP( 12, sra, 0x81818181, 0x81818181, 0 ); + TEST_RR_OP( 13, sra, 0xc0c0c0c0, 0x81818181, 1 ); + TEST_RR_OP( 14, sra, 0xff030303, 0x81818181, 7 ); + TEST_RR_OP( 15, sra, 0xfffe0606, 0x81818181, 14 ); + TEST_RR_OP( 16, sra, 0xffffffff, 0x81818181, 31 ); + + # Verify that shifts only use bottom five bits + + TEST_RR_OP( 17, sra, 0x81818181, 0x81818181, 0xffffffc0 ); + TEST_RR_OP( 18, sra, 0xc0c0c0c0, 0x81818181, 0xffffffc1 ); + TEST_RR_OP( 19, sra, 0xff030303, 0x81818181, 0xffffffc7 ); + TEST_RR_OP( 20, sra, 0xfffe0606, 0x81818181, 0xffffffce ); + TEST_RR_OP( 21, sra, 0xffffffff, 0x81818181, 0xffffffff ); + + #------------------------------------------------------------- + # Source/Destination tests + #------------------------------------------------------------- + + TEST_RR_SRC1_EQ_DEST( 22, sra, 0xff000000, 0x80000000, 7 ); + TEST_RR_SRC2_EQ_DEST( 23, sra, 0xfffe0000, 0x80000000, 14 ); + TEST_RR_SRC12_EQ_DEST( 24, sra, 0, 7 ); + + #------------------------------------------------------------- + # Bypassing tests + #------------------------------------------------------------- + + TEST_RR_DEST_BYPASS( 25, 0, sra, 0xff000000, 0x80000000, 7 ); + TEST_RR_DEST_BYPASS( 26, 1, sra, 0xfffe0000, 0x80000000, 14 ); + TEST_RR_DEST_BYPASS( 27, 2, sra, 0xffffffff, 0x80000000, 31 ); + + TEST_RR_SRC12_BYPASS( 28, 0, 0, sra, 0xff000000, 0x80000000, 7 ); + TEST_RR_SRC12_BYPASS( 29, 0, 1, sra, 0xfffe0000, 0x80000000, 14 ); + TEST_RR_SRC12_BYPASS( 30, 0, 2, sra, 0xffffffff, 0x80000000, 31 ); + TEST_RR_SRC12_BYPASS( 31, 1, 0, sra, 0xff000000, 0x80000000, 7 ); + TEST_RR_SRC12_BYPASS( 32, 1, 1, sra, 0xfffe0000, 0x80000000, 14 ); + TEST_RR_SRC12_BYPASS( 33, 2, 0, sra, 0xffffffff, 0x80000000, 31 ); + + TEST_RR_SRC21_BYPASS( 34, 0, 0, sra, 0xff000000, 0x80000000, 7 ); + TEST_RR_SRC21_BYPASS( 35, 0, 1, sra, 0xfffe0000, 0x80000000, 14 ); + TEST_RR_SRC21_BYPASS( 36, 0, 2, sra, 0xffffffff, 0x80000000, 31 ); + TEST_RR_SRC21_BYPASS( 37, 1, 0, sra, 0xff000000, 0x80000000, 7 ); + TEST_RR_SRC21_BYPASS( 38, 1, 1, sra, 0xfffe0000, 0x80000000, 14 ); + TEST_RR_SRC21_BYPASS( 39, 2, 0, sra, 0xffffffff, 0x80000000, 31 ); + + TEST_RR_ZEROSRC1( 40, sra, 0, 15 ); + TEST_RR_ZEROSRC2( 41, sra, 32, 32 ); + TEST_RR_ZEROSRC12( 42, sra, 0 ); + TEST_RR_ZERODEST( 43, sra, 1024, 2048 ); + + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +RVTEST_DATA_END Index: v0.1/riscv-tests/lhu.S =================================================================== --- v0.1/riscv-tests/lhu.S (nonexistent) +++ v0.1/riscv-tests/lhu.S (revision 47) @@ -0,0 +1,92 @@ +# See LICENSE for license details. + +#***************************************************************************** +# lhu.S +#----------------------------------------------------------------------------- +# +# Test lhu instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + #------------------------------------------------------------- + # Basic tests + #------------------------------------------------------------- + + TEST_LD_OP( 2, lhu, 0x000000ff, 0, tdat ); + TEST_LD_OP( 3, lhu, 0x0000ff00, 2, tdat ); + TEST_LD_OP( 4, lhu, 0x00000ff0, 4, tdat ); + TEST_LD_OP( 5, lhu, 0x0000f00f, 6, tdat ); + + # Test with negative offset + + TEST_LD_OP( 6, lhu, 0x000000ff, -6, tdat4 ); + TEST_LD_OP( 7, lhu, 0x0000ff00, -4, tdat4 ); + TEST_LD_OP( 8, lhu, 0x00000ff0, -2, tdat4 ); + TEST_LD_OP( 9, lhu, 0x0000f00f, 0, tdat4 ); + + # Test with a negative base + + TEST_CASE( 10, x3, 0x000000ff, \ + la x1, tdat; \ + addi x1, x1, -32; \ + lhu x3, 32(x1); \ + ) + + # Test with unaligned base + + TEST_CASE( 11, x3, 0x0000ff00, \ + la x1, tdat; \ + addi x1, x1, -5; \ + lhu x3, 7(x1); \ + ) + + #------------------------------------------------------------- + # Bypassing tests + #------------------------------------------------------------- + + TEST_LD_DEST_BYPASS( 12, 0, lhu, 0x00000ff0, 2, tdat2 ); + TEST_LD_DEST_BYPASS( 13, 1, lhu, 0x0000f00f, 2, tdat3 ); + TEST_LD_DEST_BYPASS( 14, 2, lhu, 0x0000ff00, 2, tdat1 ); + + TEST_LD_SRC1_BYPASS( 15, 0, lhu, 0x00000ff0, 2, tdat2 ); + TEST_LD_SRC1_BYPASS( 16, 1, lhu, 0x0000f00f, 2, tdat3 ); + TEST_LD_SRC1_BYPASS( 17, 2, lhu, 0x0000ff00, 2, tdat1 ); + + #------------------------------------------------------------- + # Test write-after-write hazard + #------------------------------------------------------------- + + TEST_CASE( 18, x2, 2, \ + la x3, tdat; \ + lhu x2, 0(x3); \ + li x2, 2; \ + ) + + TEST_CASE( 19, x2, 2, \ + la x3, tdat; \ + lhu x2, 0(x3); \ + nop; \ + li x2, 2; \ + ) + + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +tdat: +tdat1: .half 0x00ff +tdat2: .half 0xff00 +tdat3: .half 0x0ff0 +tdat4: .half 0xf00f + +RVTEST_DATA_END Index: v0.1/riscv-tests/ori.S =================================================================== --- v0.1/riscv-tests/ori.S (nonexistent) +++ v0.1/riscv-tests/ori.S (revision 47) @@ -0,0 +1,55 @@ +# See LICENSE for license details. + +#***************************************************************************** +# ori.S +#----------------------------------------------------------------------------- +# +# Test ori instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + #------------------------------------------------------------- + # Logical tests + #------------------------------------------------------------- + + TEST_IMM_OP( 2, ori, 0xffffff0f, 0xff00ff00, 0xf0f ); + TEST_IMM_OP( 3, ori, 0x0ff00ff0, 0x0ff00ff0, 0x0f0 ); + TEST_IMM_OP( 4, ori, 0x00ff07ff, 0x00ff00ff, 0x70f ); + TEST_IMM_OP( 5, ori, 0xf00ff0ff, 0xf00ff00f, 0x0f0 ); + + #------------------------------------------------------------- + # Source/Destination tests + #------------------------------------------------------------- + + TEST_IMM_SRC1_EQ_DEST( 6, ori, 0xff00fff0, 0xff00ff00, 0x0f0 ); + + #------------------------------------------------------------- + # Bypassing tests + #------------------------------------------------------------- + + TEST_IMM_DEST_BYPASS( 7, 0, ori, 0x0ff00ff0, 0x0ff00ff0, 0x0f0 ); + TEST_IMM_DEST_BYPASS( 8, 1, ori, 0x00ff07ff, 0x00ff00ff, 0x70f ); + TEST_IMM_DEST_BYPASS( 9, 2, ori, 0xf00ff0ff, 0xf00ff00f, 0x0f0 ); + + TEST_IMM_SRC1_BYPASS( 10, 0, ori, 0x0ff00ff0, 0x0ff00ff0, 0x0f0 ); + TEST_IMM_SRC1_BYPASS( 11, 1, ori, 0xffffffff, 0x00ff00ff, 0xf0f ); + TEST_IMM_SRC1_BYPASS( 12, 2, ori, 0xf00ff0ff, 0xf00ff00f, 0x0f0 ); + + TEST_IMM_ZEROSRC1( 13, ori, 0x0f0, 0x0f0 ); + TEST_IMM_ZERODEST( 14, ori, 0x00ff00ff, 0x70f ); + + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +RVTEST_DATA_END Index: v0.1/riscv-tests/simple.S =================================================================== --- v0.1/riscv-tests/simple.S (nonexistent) +++ v0.1/riscv-tests/simple.S (revision 47) @@ -0,0 +1,27 @@ +# See LICENSE for license details. + +#***************************************************************************** +# simple.S +#----------------------------------------------------------------------------- +# +# This is the most basic self checking test. If your simulator does not +# pass thiss then there is little chance that it will pass any of the +# more complicated self checking tests. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + +RVTEST_PASS + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +RVTEST_DATA_END Index: v0.1/riscv-tests/sw.S =================================================================== --- v0.1/riscv-tests/sw.S (nonexistent) +++ v0.1/riscv-tests/sw.S (revision 47) @@ -0,0 +1,92 @@ +# See LICENSE for license details. + +#***************************************************************************** +# sw.S +#----------------------------------------------------------------------------- +# +# Test sw instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + #------------------------------------------------------------- + # Basic tests + #------------------------------------------------------------- + + TEST_ST_OP( 2, lw, sw, 0x00aa00aa, 0, tdat ); + TEST_ST_OP( 3, lw, sw, 0xaa00aa00, 4, tdat ); + TEST_ST_OP( 4, lw, sw, 0x0aa00aa0, 8, tdat ); + TEST_ST_OP( 5, lw, sw, 0xa00aa00a, 12, tdat ); + + # Test with negative offset + + TEST_ST_OP( 6, lw, sw, 0x00aa00aa, -12, tdat8 ); + TEST_ST_OP( 7, lw, sw, 0xaa00aa00, -8, tdat8 ); + TEST_ST_OP( 8, lw, sw, 0x0aa00aa0, -4, tdat8 ); + TEST_ST_OP( 9, lw, sw, 0xa00aa00a, 0, tdat8 ); + + # Test with a negative base + + TEST_CASE( 10, x3, 0x12345678, \ + la x1, tdat9; \ + li x2, 0x12345678; \ + addi x4, x1, -32; \ + sw x2, 32(x4); \ + lw x3, 0(x1); \ + ) + + # Test with unaligned base + + TEST_CASE( 11, x3, 0x58213098, \ + la x1, tdat9; \ + li x2, 0x58213098; \ + addi x1, x1, -3; \ + sw x2, 7(x1); \ + la x4, tdat10; \ + lw x3, 0(x4); \ + ) + + #------------------------------------------------------------- + # Bypassing tests + #------------------------------------------------------------- + + TEST_ST_SRC12_BYPASS( 12, 0, 0, lw, sw, 0xaabbccdd, 0, tdat ); + TEST_ST_SRC12_BYPASS( 13, 0, 1, lw, sw, 0xdaabbccd, 4, tdat ); + TEST_ST_SRC12_BYPASS( 14, 0, 2, lw, sw, 0xddaabbcc, 8, tdat ); + TEST_ST_SRC12_BYPASS( 15, 1, 0, lw, sw, 0xcddaabbc, 12, tdat ); + TEST_ST_SRC12_BYPASS( 16, 1, 1, lw, sw, 0xccddaabb, 16, tdat ); + TEST_ST_SRC12_BYPASS( 17, 2, 0, lw, sw, 0xbccddaab, 20, tdat ); + + TEST_ST_SRC21_BYPASS( 18, 0, 0, lw, sw, 0x00112233, 0, tdat ); + TEST_ST_SRC21_BYPASS( 19, 0, 1, lw, sw, 0x30011223, 4, tdat ); + TEST_ST_SRC21_BYPASS( 20, 0, 2, lw, sw, 0x33001122, 8, tdat ); + TEST_ST_SRC21_BYPASS( 21, 1, 0, lw, sw, 0x23300112, 12, tdat ); + TEST_ST_SRC21_BYPASS( 22, 1, 1, lw, sw, 0x22330011, 16, tdat ); + TEST_ST_SRC21_BYPASS( 23, 2, 0, lw, sw, 0x12233001, 20, tdat ); + + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +tdat: +tdat1: .word 0xdeadbeef +tdat2: .word 0xdeadbeef +tdat3: .word 0xdeadbeef +tdat4: .word 0xdeadbeef +tdat5: .word 0xdeadbeef +tdat6: .word 0xdeadbeef +tdat7: .word 0xdeadbeef +tdat8: .word 0xdeadbeef +tdat9: .word 0xdeadbeef +tdat10: .word 0xdeadbeef + +RVTEST_DATA_END Index: v0.1/riscv-tests/sll.S =================================================================== --- v0.1/riscv-tests/sll.S (nonexistent) +++ v0.1/riscv-tests/sll.S (revision 47) @@ -0,0 +1,90 @@ +# See LICENSE for license details. + +#***************************************************************************** +# sll.S +#----------------------------------------------------------------------------- +# +# Test sll instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + #------------------------------------------------------------- + # Arithmetic tests + #------------------------------------------------------------- + + TEST_RR_OP( 2, sll, 0x00000001, 0x00000001, 0 ); + TEST_RR_OP( 3, sll, 0x00000002, 0x00000001, 1 ); + TEST_RR_OP( 4, sll, 0x00000080, 0x00000001, 7 ); + TEST_RR_OP( 5, sll, 0x00004000, 0x00000001, 14 ); + TEST_RR_OP( 6, sll, 0x80000000, 0x00000001, 31 ); + + TEST_RR_OP( 7, sll, 0xffffffff, 0xffffffff, 0 ); + TEST_RR_OP( 8, sll, 0xfffffffe, 0xffffffff, 1 ); + TEST_RR_OP( 9, sll, 0xffffff80, 0xffffffff, 7 ); + TEST_RR_OP( 10, sll, 0xffffc000, 0xffffffff, 14 ); + TEST_RR_OP( 11, sll, 0x80000000, 0xffffffff, 31 ); + + TEST_RR_OP( 12, sll, 0x21212121, 0x21212121, 0 ); + TEST_RR_OP( 13, sll, 0x42424242, 0x21212121, 1 ); + TEST_RR_OP( 14, sll, 0x90909080, 0x21212121, 7 ); + TEST_RR_OP( 15, sll, 0x48484000, 0x21212121, 14 ); + TEST_RR_OP( 16, sll, 0x80000000, 0x21212121, 31 ); + + # Verify that shifts only use bottom five bits + + TEST_RR_OP( 17, sll, 0x21212121, 0x21212121, 0xffffffe0 ); + TEST_RR_OP( 18, sll, 0x42424242, 0x21212121, 0xffffffe1 ); + TEST_RR_OP( 19, sll, 0x90909080, 0x21212121, 0xffffffe7 ); + TEST_RR_OP( 20, sll, 0x48484000, 0x21212121, 0xffffffee ); + TEST_RR_OP( 21, sll, 0x00000000, 0x21212120, 0xffffffff ); + + #------------------------------------------------------------- + # Source/Destination tests + #------------------------------------------------------------- + + TEST_RR_SRC1_EQ_DEST( 22, sll, 0x00000080, 0x00000001, 7 ); + TEST_RR_SRC2_EQ_DEST( 23, sll, 0x00004000, 0x00000001, 14 ); + TEST_RR_SRC12_EQ_DEST( 24, sll, 24, 3 ); + + #------------------------------------------------------------- + # Bypassing tests + #------------------------------------------------------------- + + TEST_RR_DEST_BYPASS( 25, 0, sll, 0x00000080, 0x00000001, 7 ); + TEST_RR_DEST_BYPASS( 26, 1, sll, 0x00004000, 0x00000001, 14 ); + TEST_RR_DEST_BYPASS( 27, 2, sll, 0x80000000, 0x00000001, 31 ); + + TEST_RR_SRC12_BYPASS( 28, 0, 0, sll, 0x00000080, 0x00000001, 7 ); + TEST_RR_SRC12_BYPASS( 29, 0, 1, sll, 0x00004000, 0x00000001, 14 ); + TEST_RR_SRC12_BYPASS( 30, 0, 2, sll, 0x80000000, 0x00000001, 31 ); + TEST_RR_SRC12_BYPASS( 31, 1, 0, sll, 0x00000080, 0x00000001, 7 ); + TEST_RR_SRC12_BYPASS( 32, 1, 1, sll, 0x00004000, 0x00000001, 14 ); + TEST_RR_SRC12_BYPASS( 33, 2, 0, sll, 0x80000000, 0x00000001, 31 ); + + TEST_RR_SRC21_BYPASS( 34, 0, 0, sll, 0x00000080, 0x00000001, 7 ); + TEST_RR_SRC21_BYPASS( 35, 0, 1, sll, 0x00004000, 0x00000001, 14 ); + TEST_RR_SRC21_BYPASS( 36, 0, 2, sll, 0x80000000, 0x00000001, 31 ); + TEST_RR_SRC21_BYPASS( 37, 1, 0, sll, 0x00000080, 0x00000001, 7 ); + TEST_RR_SRC21_BYPASS( 38, 1, 1, sll, 0x00004000, 0x00000001, 14 ); + TEST_RR_SRC21_BYPASS( 39, 2, 0, sll, 0x80000000, 0x00000001, 31 ); + + TEST_RR_ZEROSRC1( 40, sll, 0, 15 ); + TEST_RR_ZEROSRC2( 41, sll, 32, 32 ); + TEST_RR_ZEROSRC12( 42, sll, 0 ); + TEST_RR_ZERODEST( 43, sll, 1024, 2048 ); + + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +RVTEST_DATA_END Index: v0.1/riscv-tests/bge.S =================================================================== --- v0.1/riscv-tests/bge.S (nonexistent) +++ v0.1/riscv-tests/bge.S (revision 47) @@ -0,0 +1,76 @@ +# See LICENSE for license details. + +#***************************************************************************** +# bge.S +#----------------------------------------------------------------------------- +# +# Test bge instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + #------------------------------------------------------------- + # Branch tests + #------------------------------------------------------------- + + # Each test checks both forward and backward branches + + TEST_BR2_OP_TAKEN( 2, bge, 0, 0 ); + TEST_BR2_OP_TAKEN( 3, bge, 1, 1 ); + TEST_BR2_OP_TAKEN( 4, bge, -1, -1 ); + TEST_BR2_OP_TAKEN( 5, bge, 1, 0 ); + TEST_BR2_OP_TAKEN( 6, bge, 1, -1 ); + TEST_BR2_OP_TAKEN( 7, bge, -1, -2 ); + + TEST_BR2_OP_NOTTAKEN( 8, bge, 0, 1 ); + TEST_BR2_OP_NOTTAKEN( 9, bge, -1, 1 ); + TEST_BR2_OP_NOTTAKEN( 10, bge, -2, -1 ); + TEST_BR2_OP_NOTTAKEN( 11, bge, -2, 1 ); + + #------------------------------------------------------------- + # Bypassing tests + #------------------------------------------------------------- + + TEST_BR2_SRC12_BYPASS( 12, 0, 0, bge, -1, 0 ); + TEST_BR2_SRC12_BYPASS( 13, 0, 1, bge, -1, 0 ); + TEST_BR2_SRC12_BYPASS( 14, 0, 2, bge, -1, 0 ); + TEST_BR2_SRC12_BYPASS( 15, 1, 0, bge, -1, 0 ); + TEST_BR2_SRC12_BYPASS( 16, 1, 1, bge, -1, 0 ); + TEST_BR2_SRC12_BYPASS( 17, 2, 0, bge, -1, 0 ); + + TEST_BR2_SRC12_BYPASS( 18, 0, 0, bge, -1, 0 ); + TEST_BR2_SRC12_BYPASS( 19, 0, 1, bge, -1, 0 ); + TEST_BR2_SRC12_BYPASS( 20, 0, 2, bge, -1, 0 ); + TEST_BR2_SRC12_BYPASS( 21, 1, 0, bge, -1, 0 ); + TEST_BR2_SRC12_BYPASS( 22, 1, 1, bge, -1, 0 ); + TEST_BR2_SRC12_BYPASS( 23, 2, 0, bge, -1, 0 ); + + #------------------------------------------------------------- + # Test delay slot instructions not executed nor bypassed + #------------------------------------------------------------- + + TEST_CASE( 24, x1, 3, \ + li x1, 1; \ + bge x1, x0, 1f; \ + addi x1, x1, 1; \ + addi x1, x1, 1; \ + addi x1, x1, 1; \ + addi x1, x1, 1; \ +1: addi x1, x1, 1; \ + addi x1, x1, 1; \ + ) + + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +RVTEST_DATA_END Index: v0.1/riscv-tests/lb.S =================================================================== --- v0.1/riscv-tests/lb.S (nonexistent) +++ v0.1/riscv-tests/lb.S (revision 47) @@ -0,0 +1,92 @@ +# See LICENSE for license details. + +#***************************************************************************** +# lb.S +#----------------------------------------------------------------------------- +# +# Test lb instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + #------------------------------------------------------------- + # Basic tests + #------------------------------------------------------------- + + TEST_LD_OP( 2, lb, 0xffffffff, 0, tdat ); + TEST_LD_OP( 3, lb, 0x00000000, 1, tdat ); + TEST_LD_OP( 4, lb, 0xfffffff0, 2, tdat ); + TEST_LD_OP( 5, lb, 0x0000000f, 3, tdat ); + + # Test with negative offset + + TEST_LD_OP( 6, lb, 0xffffffff, -3, tdat4 ); + TEST_LD_OP( 7, lb, 0x00000000, -2, tdat4 ); + TEST_LD_OP( 8, lb, 0xfffffff0, -1, tdat4 ); + TEST_LD_OP( 9, lb, 0x0000000f, 0, tdat4 ); + + # Test with a negative base + + TEST_CASE( 10, x3, 0xffffffff, \ + la x1, tdat; \ + addi x1, x1, -32; \ + lb x3, 32(x1); \ + ) + + # Test with unaligned base + + TEST_CASE( 11, x3, 0x00000000, \ + la x1, tdat; \ + addi x1, x1, -6; \ + lb x3, 7(x1); \ + ) + + #------------------------------------------------------------- + # Bypassing tests + #------------------------------------------------------------- + + TEST_LD_DEST_BYPASS( 12, 0, lb, 0xfffffff0, 1, tdat2 ); + TEST_LD_DEST_BYPASS( 13, 1, lb, 0x0000000f, 1, tdat3 ); + TEST_LD_DEST_BYPASS( 14, 2, lb, 0x00000000, 1, tdat1 ); + + TEST_LD_SRC1_BYPASS( 15, 0, lb, 0xfffffff0, 1, tdat2 ); + TEST_LD_SRC1_BYPASS( 16, 1, lb, 0x0000000f, 1, tdat3 ); + TEST_LD_SRC1_BYPASS( 17, 2, lb, 0x00000000, 1, tdat1 ); + + #------------------------------------------------------------- + # Test write-after-write hazard + #------------------------------------------------------------- + + TEST_CASE( 18, x2, 2, \ + la x3, tdat; \ + lb x2, 0(x3); \ + li x2, 2; \ + ) + + TEST_CASE( 19, x2, 2, \ + la x3, tdat; \ + lb x2, 0(x3); \ + nop; \ + li x2, 2; \ + ) + + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +tdat: +tdat1: .byte 0xff +tdat2: .byte 0x00 +tdat3: .byte 0xf0 +tdat4: .byte 0x0f + +RVTEST_DATA_END Index: v0.1/riscv-tests/srl.S =================================================================== --- v0.1/riscv-tests/srl.S (nonexistent) +++ v0.1/riscv-tests/srl.S (revision 47) @@ -0,0 +1,90 @@ +# See LICENSE for license details. + +#***************************************************************************** +# srl.S +#----------------------------------------------------------------------------- +# +# Test srl instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + #------------------------------------------------------------- + # Arithmetic tests + #------------------------------------------------------------- + + TEST_RR_OP( 2, srl, 0xffff8000, 0xffff8000, 0 ); + TEST_RR_OP( 3, srl, 0x7fffc000, 0xffff8000, 1 ); + TEST_RR_OP( 4, srl, 0x01ffff00, 0xffff8000, 7 ); + TEST_RR_OP( 5, srl, 0x0003fffe, 0xffff8000, 14 ); + TEST_RR_OP( 6, srl, 0x0001ffff, 0xffff8001, 15 ); + + TEST_RR_OP( 7, srl, 0xffffffff, 0xffffffff, 0 ); + TEST_RR_OP( 8, srl, 0x7fffffff, 0xffffffff, 1 ); + TEST_RR_OP( 9, srl, 0x01ffffff, 0xffffffff, 7 ); + TEST_RR_OP( 10, srl, 0x0003ffff, 0xffffffff, 14 ); + TEST_RR_OP( 11, srl, 0x00000001, 0xffffffff, 31 ); + + TEST_RR_OP( 12, srl, 0x21212121, 0x21212121, 0 ); + TEST_RR_OP( 13, srl, 0x10909090, 0x21212121, 1 ); + TEST_RR_OP( 14, srl, 0x00424242, 0x21212121, 7 ); + TEST_RR_OP( 15, srl, 0x00008484, 0x21212121, 14 ); + TEST_RR_OP( 16, srl, 0x00000000, 0x21212121, 31 ); + + # Verify that shifts only use bottom five bits + + TEST_RR_OP( 17, srl, 0x21212121, 0x21212121, 0xffffffe0 ); + TEST_RR_OP( 18, srl, 0x10909090, 0x21212121, 0xffffffe1 ); + TEST_RR_OP( 19, srl, 0x00424242, 0x21212121, 0xffffffe7 ); + TEST_RR_OP( 20, srl, 0x00008484, 0x21212121, 0xffffffee ); + TEST_RR_OP( 21, srl, 0x00000000, 0x21212121, 0xffffffff ); + + #------------------------------------------------------------- + # Source/Destination tests + #------------------------------------------------------------- + + TEST_RR_SRC1_EQ_DEST( 22, srl, 0x7fffc000, 0xffff8000, 1 ); + TEST_RR_SRC2_EQ_DEST( 23, srl, 0x0003fffe, 0xffff8000, 14 ); + TEST_RR_SRC12_EQ_DEST( 24, srl, 0, 7 ); + + #------------------------------------------------------------- + # Bypassing tests + #------------------------------------------------------------- + + TEST_RR_DEST_BYPASS( 25, 0, srl, 0x7fffc000, 0xffff8000, 1 ); + TEST_RR_DEST_BYPASS( 26, 1, srl, 0x0003fffe, 0xffff8000, 14 ); + TEST_RR_DEST_BYPASS( 27, 2, srl, 0x0001ffff, 0xffff8000, 15 ); + + TEST_RR_SRC12_BYPASS( 28, 0, 0, srl, 0x7fffc000, 0xffff8000, 1 ); + TEST_RR_SRC12_BYPASS( 29, 0, 1, srl, 0x01ffff00, 0xffff8000, 7 ); + TEST_RR_SRC12_BYPASS( 30, 0, 2, srl, 0x0001ffff, 0xffff8000, 15 ); + TEST_RR_SRC12_BYPASS( 31, 1, 0, srl, 0x7fffc000, 0xffff8000, 1 ); + TEST_RR_SRC12_BYPASS( 32, 1, 1, srl, 0x01ffff00, 0xffff8000, 7 ); + TEST_RR_SRC12_BYPASS( 33, 2, 0, srl, 0x0001ffff, 0xffff8000, 15 ); + + TEST_RR_SRC21_BYPASS( 34, 0, 0, srl, 0x7fffc000, 0xffff8000, 1 ); + TEST_RR_SRC21_BYPASS( 35, 0, 1, srl, 0x01ffff00, 0xffff8000, 7 ); + TEST_RR_SRC21_BYPASS( 36, 0, 2, srl, 0x0001ffff, 0xffff8000, 15 ); + TEST_RR_SRC21_BYPASS( 37, 1, 0, srl, 0x7fffc000, 0xffff8000, 1 ); + TEST_RR_SRC21_BYPASS( 38, 1, 1, srl, 0x01ffff00, 0xffff8000, 7 ); + TEST_RR_SRC21_BYPASS( 39, 2, 0, srl, 0x0001ffff, 0xffff8000, 15 ); + + TEST_RR_ZEROSRC1( 40, srl, 0, 15 ); + TEST_RR_ZEROSRC2( 41, srl, 32, 32 ); + TEST_RR_ZEROSRC12( 42, srl, 0 ); + TEST_RR_ZERODEST( 43, srl, 1024, 2048 ); + + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +RVTEST_DATA_END Index: v0.1/riscv-tests/slt.S =================================================================== --- v0.1/riscv-tests/slt.S (nonexistent) +++ v0.1/riscv-tests/slt.S (revision 47) @@ -0,0 +1,84 @@ +# See LICENSE for license details. + +#***************************************************************************** +# slt.S +#----------------------------------------------------------------------------- +# +# Test slt instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + #------------------------------------------------------------- + # Arithmetic tests + #------------------------------------------------------------- + + TEST_RR_OP( 2, slt, 0, 0x00000000, 0x00000000 ); + TEST_RR_OP( 3, slt, 0, 0x00000001, 0x00000001 ); + TEST_RR_OP( 4, slt, 1, 0x00000003, 0x00000007 ); + TEST_RR_OP( 5, slt, 0, 0x00000007, 0x00000003 ); + + TEST_RR_OP( 6, slt, 0, 0x00000000, 0xffff8000 ); + TEST_RR_OP( 7, slt, 1, 0x80000000, 0x00000000 ); + TEST_RR_OP( 8, slt, 1, 0x80000000, 0xffff8000 ); + + TEST_RR_OP( 9, slt, 1, 0x00000000, 0x00007fff ); + TEST_RR_OP( 10, slt, 0, 0x7fffffff, 0x00000000 ); + TEST_RR_OP( 11, slt, 0, 0x7fffffff, 0x00007fff ); + + TEST_RR_OP( 12, slt, 1, 0x80000000, 0x00007fff ); + TEST_RR_OP( 13, slt, 0, 0x7fffffff, 0xffff8000 ); + + TEST_RR_OP( 14, slt, 0, 0x00000000, 0xffffffff ); + TEST_RR_OP( 15, slt, 1, 0xffffffff, 0x00000001 ); + TEST_RR_OP( 16, slt, 0, 0xffffffff, 0xffffffff ); + + #------------------------------------------------------------- + # Source/Destination tests + #------------------------------------------------------------- + + TEST_RR_SRC1_EQ_DEST( 17, slt, 0, 14, 13 ); + TEST_RR_SRC2_EQ_DEST( 18, slt, 1, 11, 13 ); + TEST_RR_SRC12_EQ_DEST( 19, slt, 0, 13 ); + + #------------------------------------------------------------- + # Bypassing tests + #------------------------------------------------------------- + + TEST_RR_DEST_BYPASS( 20, 0, slt, 1, 11, 13 ); + TEST_RR_DEST_BYPASS( 21, 1, slt, 0, 14, 13 ); + TEST_RR_DEST_BYPASS( 22, 2, slt, 1, 12, 13 ); + + TEST_RR_SRC12_BYPASS( 23, 0, 0, slt, 0, 14, 13 ); + TEST_RR_SRC12_BYPASS( 24, 0, 1, slt, 1, 11, 13 ); + TEST_RR_SRC12_BYPASS( 25, 0, 2, slt, 0, 15, 13 ); + TEST_RR_SRC12_BYPASS( 26, 1, 0, slt, 1, 10, 13 ); + TEST_RR_SRC12_BYPASS( 27, 1, 1, slt, 0, 16, 13 ); + TEST_RR_SRC12_BYPASS( 28, 2, 0, slt, 1, 9, 13 ); + + TEST_RR_SRC21_BYPASS( 29, 0, 0, slt, 0, 17, 13 ); + TEST_RR_SRC21_BYPASS( 30, 0, 1, slt, 1, 8, 13 ); + TEST_RR_SRC21_BYPASS( 31, 0, 2, slt, 0, 18, 13 ); + TEST_RR_SRC21_BYPASS( 32, 1, 0, slt, 1, 7, 13 ); + TEST_RR_SRC21_BYPASS( 33, 1, 1, slt, 0, 19, 13 ); + TEST_RR_SRC21_BYPASS( 34, 2, 0, slt, 1, 6, 13 ); + + TEST_RR_ZEROSRC1( 35, slt, 0, -1 ); + TEST_RR_ZEROSRC2( 36, slt, 1, -1 ); + TEST_RR_ZEROSRC12( 37, slt, 0 ); + TEST_RR_ZERODEST( 38, slt, 16, 30 ); + + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +RVTEST_DATA_END Index: v0.1/riscv-tests/lh.S =================================================================== --- v0.1/riscv-tests/lh.S (nonexistent) +++ v0.1/riscv-tests/lh.S (revision 47) @@ -0,0 +1,92 @@ +# See LICENSE for license details. + +#***************************************************************************** +# lh.S +#----------------------------------------------------------------------------- +# +# Test lh instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + #------------------------------------------------------------- + # Basic tests + #------------------------------------------------------------- + + TEST_LD_OP( 2, lh, 0x000000ff, 0, tdat ); + TEST_LD_OP( 3, lh, 0xffffff00, 2, tdat ); + TEST_LD_OP( 4, lh, 0x00000ff0, 4, tdat ); + TEST_LD_OP( 5, lh, 0xfffff00f, 6, tdat ); + + # Test with negative offset + + TEST_LD_OP( 6, lh, 0x000000ff, -6, tdat4 ); + TEST_LD_OP( 7, lh, 0xffffff00, -4, tdat4 ); + TEST_LD_OP( 8, lh, 0x00000ff0, -2, tdat4 ); + TEST_LD_OP( 9, lh, 0xfffff00f, 0, tdat4 ); + + # Test with a negative base + + TEST_CASE( 10, x3, 0x000000ff, \ + la x1, tdat; \ + addi x1, x1, -32; \ + lh x3, 32(x1); \ + ) + + # Test with unaligned base + + TEST_CASE( 11, x3, 0xffffff00, \ + la x1, tdat; \ + addi x1, x1, -5; \ + lh x3, 7(x1); \ + ) + + #------------------------------------------------------------- + # Bypassing tests + #------------------------------------------------------------- + + TEST_LD_DEST_BYPASS( 12, 0, lh, 0x00000ff0, 2, tdat2 ); + TEST_LD_DEST_BYPASS( 13, 1, lh, 0xfffff00f, 2, tdat3 ); + TEST_LD_DEST_BYPASS( 14, 2, lh, 0xffffff00, 2, tdat1 ); + + TEST_LD_SRC1_BYPASS( 15, 0, lh, 0x00000ff0, 2, tdat2 ); + TEST_LD_SRC1_BYPASS( 16, 1, lh, 0xfffff00f, 2, tdat3 ); + TEST_LD_SRC1_BYPASS( 17, 2, lh, 0xffffff00, 2, tdat1 ); + + #------------------------------------------------------------- + # Test write-after-write hazard + #------------------------------------------------------------- + + TEST_CASE( 18, x2, 2, \ + la x3, tdat; \ + lh x2, 0(x3); \ + li x2, 2; \ + ) + + TEST_CASE( 19, x2, 2, \ + la x3, tdat; \ + lh x2, 0(x3); \ + nop; \ + li x2, 2; \ + ) + + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +tdat: +tdat1: .half 0x00ff +tdat2: .half 0xff00 +tdat3: .half 0x0ff0 +tdat4: .half 0xf00f + +RVTEST_DATA_END Index: v0.1/riscv-tests/slli.S =================================================================== --- v0.1/riscv-tests/slli.S (nonexistent) +++ v0.1/riscv-tests/slli.S (revision 47) @@ -0,0 +1,68 @@ +# See LICENSE for license details. + +#***************************************************************************** +# slli.S +#----------------------------------------------------------------------------- +# +# Test slli instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + #------------------------------------------------------------- + # Arithmetic tests + #------------------------------------------------------------- + + TEST_IMM_OP( 2, slli, 0x00000001, 0x00000001, 0 ); + TEST_IMM_OP( 3, slli, 0x00000002, 0x00000001, 1 ); + TEST_IMM_OP( 4, slli, 0x00000080, 0x00000001, 7 ); + TEST_IMM_OP( 5, slli, 0x00004000, 0x00000001, 14 ); + TEST_IMM_OP( 6, slli, 0x80000000, 0x00000001, 31 ); + + TEST_IMM_OP( 7, slli, 0xffffffff, 0xffffffff, 0 ); + TEST_IMM_OP( 8, slli, 0xfffffffe, 0xffffffff, 1 ); + TEST_IMM_OP( 9, slli, 0xffffff80, 0xffffffff, 7 ); + TEST_IMM_OP( 10, slli, 0xffffc000, 0xffffffff, 14 ); + TEST_IMM_OP( 11, slli, 0x80000000, 0xffffffff, 31 ); + + TEST_IMM_OP( 12, slli, 0x21212121, 0x21212121, 0 ); + TEST_IMM_OP( 13, slli, 0x42424242, 0x21212121, 1 ); + TEST_IMM_OP( 14, slli, 0x90909080, 0x21212121, 7 ); + TEST_IMM_OP( 15, slli, 0x48484000, 0x21212121, 14 ); + TEST_IMM_OP( 16, slli, 0x80000000, 0x21212121, 31 ); + + #------------------------------------------------------------- + # Source/Destination tests + #------------------------------------------------------------- + + TEST_IMM_SRC1_EQ_DEST( 17, slli, 0x00000080, 0x00000001, 7 ); + + #------------------------------------------------------------- + # Bypassing tests + #------------------------------------------------------------- + + TEST_IMM_DEST_BYPASS( 18, 0, slli, 0x00000080, 0x00000001, 7 ); + TEST_IMM_DEST_BYPASS( 19, 1, slli, 0x00004000, 0x00000001, 14 ); + TEST_IMM_DEST_BYPASS( 20, 2, slli, 0x80000000, 0x00000001, 31 ); + + TEST_IMM_SRC1_BYPASS( 21, 0, slli, 0x00000080, 0x00000001, 7 ); + TEST_IMM_SRC1_BYPASS( 22, 1, slli, 0x00004000, 0x00000001, 14 ); + TEST_IMM_SRC1_BYPASS( 23, 2, slli, 0x80000000, 0x00000001, 31 ); + + TEST_IMM_ZEROSRC1( 24, slli, 0, 31 ); + TEST_IMM_ZERODEST( 25, slli, 33, 20 ); + + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +RVTEST_DATA_END Index: v0.1/riscv-tests/jal.S =================================================================== --- v0.1/riscv-tests/jal.S (nonexistent) +++ v0.1/riscv-tests/jal.S (revision 47) @@ -0,0 +1,60 @@ +# See LICENSE for license details. + +#***************************************************************************** +# jal.S +#----------------------------------------------------------------------------- +# +# Test jal instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + #------------------------------------------------------------- + # Test 2: Basic test + #------------------------------------------------------------- + +test_2: + li TESTNUM, 2 + li ra, 0 + +linkaddr_2: + jal target_2 + nop + nop + + j fail + +target_2: + la x2, linkaddr_2 + addi x2, x2, 4 + bne x2, ra, fail + + #------------------------------------------------------------- + # Test delay slot instructions not executed nor bypassed + #------------------------------------------------------------- + + TEST_CASE( 3, x2, 3, \ + li x2, 1; \ + jal 1f; \ + addi x2, x2, 1; \ + addi x2, x2, 1; \ + addi x2, x2, 1; \ + addi x2, x2, 1; \ +1: addi x2, x2, 1; \ + addi x2, x2, 1; \ + ) + + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +RVTEST_DATA_END Index: v0.1/riscv-tests/beq.S =================================================================== --- v0.1/riscv-tests/beq.S (nonexistent) +++ v0.1/riscv-tests/beq.S (revision 47) @@ -0,0 +1,73 @@ +# See LICENSE for license details. + +#***************************************************************************** +# beq.S +#----------------------------------------------------------------------------- +# +# Test beq instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + #------------------------------------------------------------- + # Branch tests + #------------------------------------------------------------- + + # Each test checks both forward and backward branches + + TEST_BR2_OP_TAKEN( 2, beq, 0, 0 ); + TEST_BR2_OP_TAKEN( 3, beq, 1, 1 ); + TEST_BR2_OP_TAKEN( 4, beq, -1, -1 ); + + TEST_BR2_OP_NOTTAKEN( 5, beq, 0, 1 ); + TEST_BR2_OP_NOTTAKEN( 6, beq, 1, 0 ); + TEST_BR2_OP_NOTTAKEN( 7, beq, -1, 1 ); + TEST_BR2_OP_NOTTAKEN( 8, beq, 1, -1 ); + + #------------------------------------------------------------- + # Bypassing tests + #------------------------------------------------------------- + + TEST_BR2_SRC12_BYPASS( 9, 0, 0, beq, 0, -1 ); + TEST_BR2_SRC12_BYPASS( 10, 0, 1, beq, 0, -1 ); + TEST_BR2_SRC12_BYPASS( 11, 0, 2, beq, 0, -1 ); + TEST_BR2_SRC12_BYPASS( 12, 1, 0, beq, 0, -1 ); + TEST_BR2_SRC12_BYPASS( 13, 1, 1, beq, 0, -1 ); + TEST_BR2_SRC12_BYPASS( 14, 2, 0, beq, 0, -1 ); + + TEST_BR2_SRC12_BYPASS( 15, 0, 0, beq, 0, -1 ); + TEST_BR2_SRC12_BYPASS( 16, 0, 1, beq, 0, -1 ); + TEST_BR2_SRC12_BYPASS( 17, 0, 2, beq, 0, -1 ); + TEST_BR2_SRC12_BYPASS( 18, 1, 0, beq, 0, -1 ); + TEST_BR2_SRC12_BYPASS( 19, 1, 1, beq, 0, -1 ); + TEST_BR2_SRC12_BYPASS( 20, 2, 0, beq, 0, -1 ); + + #------------------------------------------------------------- + # Test delay slot instructions not executed nor bypassed + #------------------------------------------------------------- + + TEST_CASE( 21, x1, 3, \ + li x1, 1; \ + beq x0, x0, 1f; \ + addi x1, x1, 1; \ + addi x1, x1, 1; \ + addi x1, x1, 1; \ + addi x1, x1, 1; \ +1: addi x1, x1, 1; \ + addi x1, x1, 1; \ + ) + + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +RVTEST_DATA_END Index: v0.1/riscv-tests/srli.S =================================================================== --- v0.1/riscv-tests/srli.S (nonexistent) +++ v0.1/riscv-tests/srli.S (revision 47) @@ -0,0 +1,69 @@ +# See LICENSE for license details. + +#***************************************************************************** +# srli.S +#----------------------------------------------------------------------------- +# +# Test srli instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + #------------------------------------------------------------- + # Arithmetic tests + #------------------------------------------------------------- + + TEST_IMM_OP( 2, srli, 0xffff8000, 0xffff8000, 0 ); + TEST_IMM_OP( 3, srli, 0x7fffc000, 0xffff8000, 1 ); + TEST_IMM_OP( 4, srli, 0x01ffff00, 0xffff8000, 7 ); + TEST_IMM_OP( 5, srli, 0x0003fffe, 0xffff8000, 14 ); + TEST_IMM_OP( 6, srli, 0x0001ffff, 0xffff8001, 15 ); + + TEST_IMM_OP( 7, srli, 0xffffffff, 0xffffffff, 0 ); + TEST_IMM_OP( 8, srli, 0x7fffffff, 0xffffffff, 1 ); + TEST_IMM_OP( 9, srli, 0x01ffffff, 0xffffffff, 7 ); + TEST_IMM_OP( 10, srli, 0x0003ffff, 0xffffffff, 14 ); + TEST_IMM_OP( 11, srli, 0x00000001, 0xffffffff, 31 ); + + TEST_IMM_OP( 12, srli, 0x21212121, 0x21212121, 0 ); + TEST_IMM_OP( 13, srli, 0x10909090, 0x21212121, 1 ); + TEST_IMM_OP( 14, srli, 0x00424242, 0x21212121, 7 ); + TEST_IMM_OP( 15, srli, 0x00008484, 0x21212121, 14 ); + TEST_IMM_OP( 16, srli, 0x00000000, 0x21212121, 31 ); + + #------------------------------------------------------------- + # Source/Destination tests + #------------------------------------------------------------- + + TEST_IMM_SRC1_EQ_DEST( 21, srli, 0x7fffc000, 0xffff8000, 1 ); + + #------------------------------------------------------------- + # Bypassing tests + #------------------------------------------------------------- + + TEST_IMM_DEST_BYPASS( 22, 0, srl, 0x7fffc000, 0xffff8000, 1 ); + TEST_IMM_DEST_BYPASS( 23, 1, srl, 0x0003fffe, 0xffff8000, 14 ); + TEST_IMM_DEST_BYPASS( 24, 2, srl, 0x0001ffff, 0xffff8000, 15 ); + + TEST_IMM_SRC1_BYPASS( 25, 0, srl, 0x7fffc000, 0xffff8000, 1 ); + TEST_IMM_SRC1_BYPASS( 26, 1, srl, 0x0003fffe, 0xffff8000, 14 ); + TEST_IMM_SRC1_BYPASS( 27, 2, srl, 0x0001ffff, 0xffff8000, 15 ); + + + TEST_IMM_ZEROSRC1( 28, srli, 0, 31 ); + TEST_IMM_ZERODEST( 29, srli, 33, 20 ); + + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +RVTEST_DATA_END Index: v0.1/riscv-tests/riscv_test.h =================================================================== --- v0.1/riscv-tests/riscv_test.h (nonexistent) +++ v0.1/riscv-tests/riscv_test.h (revision 47) @@ -0,0 +1,127 @@ +// See LICENSE for license details. + +#ifndef _ENV_PHYSICAL_SINGLE_CORE_H +#define _ENV_PHYSICAL_SINGLE_CORE_H + +#include "encoding.h" +//#include "../hwacha_xcpt.h" + +//----------------------------------------------------------------------- +// Begin Macro +//----------------------------------------------------------------------- + +#define RVTEST_RV64U \ + .macro init; \ + .endm + +#define RVTEST_RV64UF \ + .macro init; \ + RVTEST_FP_ENABLE; \ + .endm + +#define RVTEST_RV64UV \ + .macro init; \ + RVTEST_FP_ENABLE; \ + RVTEST_VEC_ENABLE; \ + .endm + +#define RVTEST_RV32U \ + .macro init; \ + RVTEST_32_ENABLE; \ + .endm + +#define RVTEST_RV32UF \ + .macro init; \ + RVTEST_32_ENABLE; \ + RVTEST_FP_ENABLE; \ + .endm + +#define RVTEST_RV32UV \ + .macro init; \ + RVTEST_32_ENABLE; \ + RVTEST_FP_ENABLE; \ + RVTEST_VEC_ENABLE; \ + .endm + +#define RVTEST_RV64S \ + .macro init; \ + .endm + +#define RVTEST_RV32S \ + .macro init; \ + RVTEST_32_ENABLE; \ + .endm + +#define RVTEST_32_ENABLE \ + li a0, SR_S64; \ + csrc status, a0; \ + +#define RVTEST_FP_ENABLE \ + li a0, SR_EF; \ + csrs status, a0; \ + csrr a1, status; \ + and a0, a0, a1; \ + bnez a0, 2f; \ + RVTEST_PASS; \ +2:fssr x0; \ + +#define RVTEST_VEC_ENABLE \ + li a0, SR_EA; \ + csrs status, a0; \ + csrr a1, status; \ + and a0, a0, a1; \ + bnez a0, 2f; \ + RVTEST_PASS; \ +2: \ + +#define RISCV_MULTICORE_DISABLE \ + csrr a0, hartid; \ + 1: bnez a0, 1b; \ + +#define EXTRA_INIT +#define EXTRA_INIT_TIMER + +#define RVTEST_CODE_BEGIN \ + .text; \ + .align 4; \ + .global _start; \ +_start: \ + RISCV_MULTICORE_DISABLE; \ + init; \ + EXTRA_INIT; \ + EXTRA_INIT_TIMER; \ + +//----------------------------------------------------------------------- +// End Macro +//----------------------------------------------------------------------- + +#define RVTEST_CODE_END \ + +//----------------------------------------------------------------------- +// Pass/Fail Macro +//----------------------------------------------------------------------- + +#define RVTEST_PASS \ + fence; \ + csrw tohost, 1; \ +1: j 1b; \ + +#define TESTNUM x28 +#define RVTEST_FAIL \ + fence; \ + beqz TESTNUM, 1f; \ + sll TESTNUM, TESTNUM, 1; \ + or TESTNUM, TESTNUM, 1; \ + csrw tohost, TESTNUM; \ +1: j 1b; \ + +//----------------------------------------------------------------------- +// Data Section Macro +//----------------------------------------------------------------------- + +#define EXTRA_DATA + +#define RVTEST_DATA_BEGIN EXTRA_DATA .align 4; .global begin_signature; begin_signature: +#define RVTEST_DATA_END .align 4; .global end_signature; end_signature: + +#endif Index: v0.1/riscv-tests/encoding.h =================================================================== --- v0.1/riscv-tests/encoding.h (nonexistent) +++ v0.1/riscv-tests/encoding.h (revision 47) @@ -0,0 +1,727 @@ +// See LICENSE for license details. + +#ifndef RISCV_CSR_ENCODING_H +#define RISCV_CSR_ENCODING_H + +#define SR_S 0x00000001 +#define SR_PS 0x00000002 +#define SR_EI 0x00000004 +#define SR_PEI 0x00000008 +#define SR_EF 0x00000010 +#define SR_U64 0x00000020 +#define SR_S64 0x00000040 +#define SR_VM 0x00000080 +#define SR_EA 0x00000100 +#define SR_IM 0x00FF0000 +#define SR_IP 0xFF000000 +#define SR_ZERO ~(SR_S|SR_PS|SR_EI|SR_PEI|SR_EF|SR_U64|SR_S64|SR_VM|SR_EA|SR_IM|SR_IP) +#define SR_IM_SHIFT 16 +#define SR_IP_SHIFT 24 + +#define IRQ_COP 2 +#define IRQ_IPI 5 +#define IRQ_HOST 6 +#define IRQ_TIMER 7 + +#define IMPL_SPIKE 1 +#define IMPL_ROCKET 2 + +// page table entry (PTE) fields +#define PTE_V 0x001 // Entry is a page Table descriptor +#define PTE_T 0x002 // Entry is a page Table, not a terminal node +#define PTE_G 0x004 // Global +#define PTE_UR 0x008 // User Write permission +#define PTE_UW 0x010 // User Read permission +#define PTE_UX 0x020 // User eXecute permission +#define PTE_SR 0x040 // Supervisor Read permission +#define PTE_SW 0x080 // Supervisor Write permission +#define PTE_SX 0x100 // Supervisor eXecute permission +#define PTE_PERM (PTE_SR | PTE_SW | PTE_SX | PTE_UR | PTE_UW | PTE_UX) + +#ifdef __riscv + +#ifdef __riscv64 +# define RISCV_PGLEVELS 3 +# define RISCV_PGSHIFT 13 +#else +# define RISCV_PGLEVELS 2 +# define RISCV_PGSHIFT 12 +#endif +#define RISCV_PGLEVEL_BITS 10 +#define RISCV_PGSIZE (1 << RISCV_PGSHIFT) + +#ifndef __ASSEMBLER__ + +#define read_csr(reg) ({ long __tmp; \ + asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \ + __tmp; }) + +#define write_csr(reg, val) \ + asm volatile ("csrw " #reg ", %0" :: "r"(val)) + +#define swap_csr(reg, val) ({ long __tmp; \ + asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "r"(val)); \ + __tmp; }) + +#define set_csr(reg, bit) ({ long __tmp; \ + if (__builtin_constant_p(bit) && (bit) < 32) \ + asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \ + else \ + asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \ + __tmp; }) + +#define clear_csr(reg, bit) ({ long __tmp; \ + if (__builtin_constant_p(bit) && (bit) < 32) \ + asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \ + else \ + asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \ + __tmp; }) + +#define rdtime() ({ unsigned long __tmp; \ + asm volatile ("rdtime %0" : "=r"(__tmp)); \ + __tmp; }) + +#define rdcycle() ({ unsigned long __tmp; \ + asm volatile ("rdcycle %0" : "=r"(__tmp)); \ + __tmp; }) + +#define rdinstret() ({ unsigned long __tmp; \ + asm volatile ("rdinstret %0" : "=r"(__tmp)); \ + __tmp; }) + +#endif + +#endif + +#endif +/* Automatically generated by parse-opcodes */ +#ifndef RISCV_ENCODING_H +#define RISCV_ENCODING_H +#define MATCH_FMV_S_X 0xf0000053 +#define MASK_FMV_S_X 0xfff0707f +#define MATCH_AMOXOR_W 0x2000202f +#define MASK_AMOXOR_W 0xf800707f +#define MATCH_REMUW 0x200703b +#define MASK_REMUW 0xfe00707f +#define MATCH_FMIN_D 0x2a000053 +#define MASK_FMIN_D 0xfe00707f +#define MATCH_AMOMAX_D 0xa000302f +#define MASK_AMOMAX_D 0xf800707f +#define MATCH_BLTU 0x6063 +#define MASK_BLTU 0x707f +#define MATCH_FSGNJN_D 0x22001053 +#define MASK_FSGNJN_D 0xfe00707f +#define MATCH_FMIN_S 0x28000053 +#define MASK_FMIN_S 0xfe00707f +#define MATCH_CSRRW 0x1073 +#define MASK_CSRRW 0x707f +#define MATCH_SLLIW 0x101b +#define MASK_SLLIW 0xfe00707f +#define MATCH_LB 0x3 +#define MASK_LB 0x707f +#define MATCH_FMAX_S 0x28001053 +#define MASK_FMAX_S 0xfe00707f +#define MATCH_LH 0x1003 +#define MASK_LH 0x707f +#define MATCH_FCVT_D_W 0xd2000053 +#define MASK_FCVT_D_W 0xfff0007f +#define MATCH_LW 0x2003 +#define MASK_LW 0x707f +#define MATCH_ADD 0x33 +#define MASK_ADD 0xfe00707f +#define MATCH_CSRRC 0x3073 +#define MASK_CSRRC 0x707f +#define MATCH_FMAX_D 0x2a001053 +#define MASK_FMAX_D 0xfe00707f +#define MATCH_BNE 0x1063 +#define MASK_BNE 0x707f +#define MATCH_FCVT_S_D 0x40100053 +#define MASK_FCVT_S_D 0xfff0007f +#define MATCH_BGEU 0x7063 +#define MASK_BGEU 0x707f +#define MATCH_FADD_D 0x2000053 +#define MASK_FADD_D 0xfe00007f +#define MATCH_SLTIU 0x3013 +#define MASK_SLTIU 0x707f +#define MATCH_FADD_S 0x53 +#define MASK_FADD_S 0xfe00007f +#define MATCH_FCLASS_D 0xe2001053 +#define MASK_FCLASS_D 0xfff0707f +#define MATCH_FCVT_S_W 0xd0000053 +#define MASK_FCVT_S_W 0xfff0007f +#define MATCH_MUL 0x2000033 +#define MASK_MUL 0xfe00707f +#define MATCH_AMOMINU_D 0xc000302f +#define MASK_AMOMINU_D 0xf800707f +#define MATCH_FCVT_S_LU 0xd0300053 +#define MASK_FCVT_S_LU 0xfff0007f +#define MATCH_SRLI 0x5013 +#define MASK_SRLI 0xfc00707f +#define MATCH_AMOMINU_W 0xc000202f +#define MASK_AMOMINU_W 0xf800707f +#define MATCH_DIVUW 0x200503b +#define MASK_DIVUW 0xfe00707f +#define MATCH_MULW 0x200003b +#define MASK_MULW 0xfe00707f +#define MATCH_SRLW 0x503b +#define MASK_SRLW 0xfe00707f +#define MATCH_DIV 0x2004033 +#define MASK_DIV 0xfe00707f +#define MATCH_FDIV_D 0x1a000053 +#define MASK_FDIV_D 0xfe00007f +#define MATCH_FENCE 0xf +#define MASK_FENCE 0x707f +#define MATCH_FNMSUB_S 0x4b +#define MASK_FNMSUB_S 0x600007f +#define MATCH_FCVT_L_S 0xc0200053 +#define MASK_FCVT_L_S 0xfff0007f +#define MATCH_SBREAK 0x100073 +#define MASK_SBREAK 0xffffffff +#define MATCH_FLE_S 0xa0000053 +#define MASK_FLE_S 0xfe00707f +#define MATCH_FDIV_S 0x18000053 +#define MASK_FDIV_S 0xfe00007f +#define MATCH_FLE_D 0xa2000053 +#define MASK_FLE_D 0xfe00707f +#define MATCH_FENCE_I 0x100f +#define MASK_FENCE_I 0x707f +#define MATCH_FNMSUB_D 0x200004b +#define MASK_FNMSUB_D 0x600007f +#define MATCH_ADDW 0x3b +#define MASK_ADDW 0xfe00707f +#define MATCH_SLL 0x1033 +#define MASK_SLL 0xfe00707f +#define MATCH_XOR 0x4033 +#define MASK_XOR 0xfe00707f +#define MATCH_SUB 0x40000033 +#define MASK_SUB 0xfe00707f +#define MATCH_BLT 0x4063 +#define MASK_BLT 0x707f +#define MATCH_SCALL 0x73 +#define MASK_SCALL 0xffffffff +#define MATCH_FCLASS_S 0xe0001053 +#define MASK_FCLASS_S 0xfff0707f +#define MATCH_SC_W 0x1800202f +#define MASK_SC_W 0xf800707f +#define MATCH_REM 0x2006033 +#define MASK_REM 0xfe00707f +#define MATCH_SRLIW 0x501b +#define MASK_SRLIW 0xfe00707f +#define MATCH_LUI 0x37 +#define MASK_LUI 0x7f +#define MATCH_CSRRCI 0x7073 +#define MASK_CSRRCI 0x707f +#define MATCH_ADDI 0x13 +#define MASK_ADDI 0x707f +#define MATCH_MULH 0x2001033 +#define MASK_MULH 0xfe00707f +#define MATCH_FMUL_S 0x10000053 +#define MASK_FMUL_S 0xfe00007f +#define MATCH_CSRRSI 0x6073 +#define MASK_CSRRSI 0x707f +#define MATCH_SRAI 0x40005013 +#define MASK_SRAI 0xfc00707f +#define MATCH_AMOAND_D 0x6000302f +#define MASK_AMOAND_D 0xf800707f +#define MATCH_FLT_D 0xa2001053 +#define MASK_FLT_D 0xfe00707f +#define MATCH_SRAW 0x4000503b +#define MASK_SRAW 0xfe00707f +#define MATCH_FMUL_D 0x12000053 +#define MASK_FMUL_D 0xfe00007f +#define MATCH_LD 0x3003 +#define MASK_LD 0x707f +#define MATCH_ORI 0x6013 +#define MASK_ORI 0x707f +#define MATCH_CSRRS 0x2073 +#define MASK_CSRRS 0x707f +#define MATCH_FLT_S 0xa0001053 +#define MASK_FLT_S 0xfe00707f +#define MATCH_ADDIW 0x1b +#define MASK_ADDIW 0x707f +#define MATCH_AMOAND_W 0x6000202f +#define MASK_AMOAND_W 0xf800707f +#define MATCH_FEQ_S 0xa0002053 +#define MASK_FEQ_S 0xfe00707f +#define MATCH_FSGNJX_D 0x22002053 +#define MASK_FSGNJX_D 0xfe00707f +#define MATCH_SRA 0x40005033 +#define MASK_SRA 0xfe00707f +#define MATCH_BGE 0x5063 +#define MASK_BGE 0x707f +#define MATCH_SRAIW 0x4000501b +#define MASK_SRAIW 0xfe00707f +#define MATCH_SRL 0x5033 +#define MASK_SRL 0xfe00707f +#define MATCH_FSUB_D 0xa000053 +#define MASK_FSUB_D 0xfe00007f +#define MATCH_FSGNJX_S 0x20002053 +#define MASK_FSGNJX_S 0xfe00707f +#define MATCH_FEQ_D 0xa2002053 +#define MASK_FEQ_D 0xfe00707f +#define MATCH_FCVT_D_WU 0xd2100053 +#define MASK_FCVT_D_WU 0xfff0007f +#define MATCH_OR 0x6033 +#define MASK_OR 0xfe00707f +#define MATCH_FCVT_WU_D 0xc2100053 +#define MASK_FCVT_WU_D 0xfff0007f +#define MATCH_SUBW 0x4000003b +#define MASK_SUBW 0xfe00707f +#define MATCH_FCVT_D_L 0xd2200053 +#define MASK_FCVT_D_L 0xfff0007f +#define MATCH_AMOMAXU_D 0xe000302f +#define MASK_AMOMAXU_D 0xf800707f +#define MATCH_XORI 0x4013 +#define MASK_XORI 0x707f +#define MATCH_AMOXOR_D 0x2000302f +#define MASK_AMOXOR_D 0xf800707f +#define MATCH_AMOMAXU_W 0xe000202f +#define MASK_AMOMAXU_W 0xf800707f +#define MATCH_FCVT_WU_S 0xc0100053 +#define MASK_FCVT_WU_S 0xfff0007f +#define MATCH_ANDI 0x7013 +#define MASK_ANDI 0x707f +#define MATCH_FMV_X_S 0xe0000053 +#define MASK_FMV_X_S 0xfff0707f +#define MATCH_SRET 0x80000073 +#define MASK_SRET 0xffffffff +#define MATCH_FNMADD_S 0x4f +#define MASK_FNMADD_S 0x600007f +#define MATCH_JAL 0x6f +#define MASK_JAL 0x7f +#define MATCH_LWU 0x6003 +#define MASK_LWU 0x707f +#define MATCH_FMV_X_D 0xe2000053 +#define MASK_FMV_X_D 0xfff0707f +#define MATCH_FCVT_D_S 0x42000053 +#define MASK_FCVT_D_S 0xfff0007f +#define MATCH_FNMADD_D 0x200004f +#define MASK_FNMADD_D 0x600007f +#define MATCH_AMOADD_D 0x302f +#define MASK_AMOADD_D 0xf800707f +#define MATCH_LR_D 0x1000302f +#define MASK_LR_D 0xf9f0707f +#define MATCH_FCVT_W_S 0xc0000053 +#define MASK_FCVT_W_S 0xfff0007f +#define MATCH_MULHSU 0x2002033 +#define MASK_MULHSU 0xfe00707f +#define MATCH_AMOADD_W 0x202f +#define MASK_AMOADD_W 0xf800707f +#define MATCH_FCVT_D_LU 0xd2300053 +#define MASK_FCVT_D_LU 0xfff0007f +#define MATCH_LR_W 0x1000202f +#define MASK_LR_W 0xf9f0707f +#define MATCH_FCVT_W_D 0xc2000053 +#define MASK_FCVT_W_D 0xfff0007f +#define MATCH_SLT 0x2033 +#define MASK_SLT 0xfe00707f +#define MATCH_SLLW 0x103b +#define MASK_SLLW 0xfe00707f +#define MATCH_AMOOR_D 0x4000302f +#define MASK_AMOOR_D 0xf800707f +#define MATCH_SLTI 0x2013 +#define MASK_SLTI 0x707f +#define MATCH_REMU 0x2007033 +#define MASK_REMU 0xfe00707f +#define MATCH_FLW 0x2007 +#define MASK_FLW 0x707f +#define MATCH_REMW 0x200603b +#define MASK_REMW 0xfe00707f +#define MATCH_SLTU 0x3033 +#define MASK_SLTU 0xfe00707f +#define MATCH_SLLI 0x1013 +#define MASK_SLLI 0xfc00707f +#define MATCH_AMOOR_W 0x4000202f +#define MASK_AMOOR_W 0xf800707f +#define MATCH_BEQ 0x63 +#define MASK_BEQ 0x707f +#define MATCH_FLD 0x3007 +#define MASK_FLD 0x707f +#define MATCH_FSUB_S 0x8000053 +#define MASK_FSUB_S 0xfe00007f +#define MATCH_AND 0x7033 +#define MASK_AND 0xfe00707f +#define MATCH_FMV_D_X 0xf2000053 +#define MASK_FMV_D_X 0xfff0707f +#define MATCH_LBU 0x4003 +#define MASK_LBU 0x707f +#define MATCH_FSGNJ_S 0x20000053 +#define MASK_FSGNJ_S 0xfe00707f +#define MATCH_AMOMAX_W 0xa000202f +#define MASK_AMOMAX_W 0xf800707f +#define MATCH_FSGNJ_D 0x22000053 +#define MASK_FSGNJ_D 0xfe00707f +#define MATCH_MULHU 0x2003033 +#define MASK_MULHU 0xfe00707f +#define MATCH_FCVT_L_D 0xc2200053 +#define MASK_FCVT_L_D 0xfff0007f +#define MATCH_FCVT_S_WU 0xd0100053 +#define MASK_FCVT_S_WU 0xfff0007f +#define MATCH_FCVT_LU_S 0xc0300053 +#define MASK_FCVT_LU_S 0xfff0007f +#define MATCH_FCVT_S_L 0xd0200053 +#define MASK_FCVT_S_L 0xfff0007f +#define MATCH_AUIPC 0x17 +#define MASK_AUIPC 0x7f +#define MATCH_FCVT_LU_D 0xc2300053 +#define MASK_FCVT_LU_D 0xfff0007f +#define MATCH_CSRRWI 0x5073 +#define MASK_CSRRWI 0x707f +#define MATCH_SC_D 0x1800302f +#define MASK_SC_D 0xf800707f +#define MATCH_FMADD_S 0x43 +#define MASK_FMADD_S 0x600007f +#define MATCH_FSQRT_S 0x58000053 +#define MASK_FSQRT_S 0xfff0007f +#define MATCH_AMOMIN_W 0x8000202f +#define MASK_AMOMIN_W 0xf800707f +#define MATCH_FSGNJN_S 0x20001053 +#define MASK_FSGNJN_S 0xfe00707f +#define MATCH_AMOSWAP_D 0x800302f +#define MASK_AMOSWAP_D 0xf800707f +#define MATCH_FSQRT_D 0x5a000053 +#define MASK_FSQRT_D 0xfff0007f +#define MATCH_FMADD_D 0x2000043 +#define MASK_FMADD_D 0x600007f +#define MATCH_DIVW 0x200403b +#define MASK_DIVW 0xfe00707f +#define MATCH_AMOMIN_D 0x8000302f +#define MASK_AMOMIN_D 0xf800707f +#define MATCH_DIVU 0x2005033 +#define MASK_DIVU 0xfe00707f +#define MATCH_AMOSWAP_W 0x800202f +#define MASK_AMOSWAP_W 0xf800707f +#define MATCH_JALR 0x67 +#define MASK_JALR 0x707f +#define MATCH_FSD 0x3027 +#define MASK_FSD 0x707f +#define MATCH_SW 0x2023 +#define MASK_SW 0x707f +#define MATCH_FMSUB_S 0x47 +#define MASK_FMSUB_S 0x600007f +#define MATCH_LHU 0x5003 +#define MASK_LHU 0x707f +#define MATCH_SH 0x1023 +#define MASK_SH 0x707f +#define MATCH_FSW 0x2027 +#define MASK_FSW 0x707f +#define MATCH_SB 0x23 +#define MASK_SB 0x707f +#define MATCH_FMSUB_D 0x2000047 +#define MASK_FMSUB_D 0x600007f +#define MATCH_SD 0x3023 +#define MASK_SD 0x707f +#define CSR_FFLAGS 0x1 +#define CSR_FRM 0x2 +#define CSR_FCSR 0x3 +#define CSR_STATS 0xc0 +#define CSR_SUP0 0x500 +#define CSR_SUP1 0x501 +#define CSR_EPC 0x502 +#define CSR_BADVADDR 0x503 +#define CSR_PTBR 0x504 +#define CSR_ASID 0x505 +#define CSR_COUNT 0x506 +#define CSR_COMPARE 0x507 +#define CSR_EVEC 0x508 +#define CSR_CAUSE 0x509 +#define CSR_STATUS 0x50a +#define CSR_HARTID 0x50b +#define CSR_IMPL 0x50c +#define CSR_FATC 0x50d +#define CSR_SEND_IPI 0x50e +#define CSR_CLEAR_IPI 0x50f +#define CSR_RESET 0x51d +#define CSR_TOHOST 0x51e +#define CSR_FROMHOST 0x51f +#define CSR_CYCLE 0xc00 +#define CSR_TIME 0xc01 +#define CSR_INSTRET 0xc02 +#define CSR_UARCH0 0xcc0 +#define CSR_UARCH1 0xcc1 +#define CSR_UARCH2 0xcc2 +#define CSR_UARCH3 0xcc3 +#define CSR_UARCH4 0xcc4 +#define CSR_UARCH5 0xcc5 +#define CSR_UARCH6 0xcc6 +#define CSR_UARCH7 0xcc7 +#define CSR_UARCH8 0xcc8 +#define CSR_UARCH9 0xcc9 +#define CSR_UARCH10 0xcca +#define CSR_UARCH11 0xccb +#define CSR_UARCH12 0xccc +#define CSR_UARCH13 0xccd +#define CSR_UARCH14 0xcce +#define CSR_UARCH15 0xccf +#define CSR_COUNTH 0x586 +#define CSR_CYCLEH 0xc80 +#define CSR_TIMEH 0xc81 +#define CSR_INSTRETH 0xc82 +#define CAUSE_MISALIGNED_FETCH 0x0 +#define CAUSE_FAULT_FETCH 0x1 +#define CAUSE_ILLEGAL_INSTRUCTION 0x2 +#define CAUSE_PRIVILEGED_INSTRUCTION 0x3 +#define CAUSE_FP_DISABLED 0x4 +#define CAUSE_SYSCALL 0x6 +#define CAUSE_BREAKPOINT 0x7 +#define CAUSE_MISALIGNED_LOAD 0x8 +#define CAUSE_MISALIGNED_STORE 0x9 +#define CAUSE_FAULT_LOAD 0xa +#define CAUSE_FAULT_STORE 0xb +#define CAUSE_ACCELERATOR_DISABLED 0xc +#endif +#ifdef DECLARE_INSN +DECLARE_INSN(fmv_s_x, MATCH_FMV_S_X, MASK_FMV_S_X) +DECLARE_INSN(amoxor_w, MATCH_AMOXOR_W, MASK_AMOXOR_W) +DECLARE_INSN(remuw, MATCH_REMUW, MASK_REMUW) +DECLARE_INSN(fmin_d, MATCH_FMIN_D, MASK_FMIN_D) +DECLARE_INSN(amomax_d, MATCH_AMOMAX_D, MASK_AMOMAX_D) +DECLARE_INSN(bltu, MATCH_BLTU, MASK_BLTU) +DECLARE_INSN(fsgnjn_d, MATCH_FSGNJN_D, MASK_FSGNJN_D) +DECLARE_INSN(fmin_s, MATCH_FMIN_S, MASK_FMIN_S) +DECLARE_INSN(csrrw, MATCH_CSRRW, MASK_CSRRW) +DECLARE_INSN(slliw, MATCH_SLLIW, MASK_SLLIW) +DECLARE_INSN(lb, MATCH_LB, MASK_LB) +DECLARE_INSN(fmax_s, MATCH_FMAX_S, MASK_FMAX_S) +DECLARE_INSN(lh, MATCH_LH, MASK_LH) +DECLARE_INSN(fcvt_d_w, MATCH_FCVT_D_W, MASK_FCVT_D_W) +DECLARE_INSN(lw, MATCH_LW, MASK_LW) +DECLARE_INSN(add, MATCH_ADD, MASK_ADD) +DECLARE_INSN(csrrc, MATCH_CSRRC, MASK_CSRRC) +DECLARE_INSN(fmax_d, MATCH_FMAX_D, MASK_FMAX_D) +DECLARE_INSN(bne, MATCH_BNE, MASK_BNE) +DECLARE_INSN(fcvt_s_d, MATCH_FCVT_S_D, MASK_FCVT_S_D) +DECLARE_INSN(bgeu, MATCH_BGEU, MASK_BGEU) +DECLARE_INSN(fadd_d, MATCH_FADD_D, MASK_FADD_D) +DECLARE_INSN(sltiu, MATCH_SLTIU, MASK_SLTIU) +DECLARE_INSN(fadd_s, MATCH_FADD_S, MASK_FADD_S) +DECLARE_INSN(fclass_d, MATCH_FCLASS_D, MASK_FCLASS_D) +DECLARE_INSN(fcvt_s_w, MATCH_FCVT_S_W, MASK_FCVT_S_W) +DECLARE_INSN(mul, MATCH_MUL, MASK_MUL) +DECLARE_INSN(amominu_d, MATCH_AMOMINU_D, MASK_AMOMINU_D) +DECLARE_INSN(fcvt_s_lu, MATCH_FCVT_S_LU, MASK_FCVT_S_LU) +DECLARE_INSN(srli, MATCH_SRLI, MASK_SRLI) +DECLARE_INSN(amominu_w, MATCH_AMOMINU_W, MASK_AMOMINU_W) +DECLARE_INSN(divuw, MATCH_DIVUW, MASK_DIVUW) +DECLARE_INSN(mulw, MATCH_MULW, MASK_MULW) +DECLARE_INSN(srlw, MATCH_SRLW, MASK_SRLW) +DECLARE_INSN(div, MATCH_DIV, MASK_DIV) +DECLARE_INSN(fdiv_d, MATCH_FDIV_D, MASK_FDIV_D) +DECLARE_INSN(fence, MATCH_FENCE, MASK_FENCE) +DECLARE_INSN(fnmsub_s, MATCH_FNMSUB_S, MASK_FNMSUB_S) +DECLARE_INSN(fcvt_l_s, MATCH_FCVT_L_S, MASK_FCVT_L_S) +DECLARE_INSN(sbreak, MATCH_SBREAK, MASK_SBREAK) +DECLARE_INSN(fle_s, MATCH_FLE_S, MASK_FLE_S) +DECLARE_INSN(fdiv_s, MATCH_FDIV_S, MASK_FDIV_S) +DECLARE_INSN(fle_d, MATCH_FLE_D, MASK_FLE_D) +DECLARE_INSN(fence_i, MATCH_FENCE_I, MASK_FENCE_I) +DECLARE_INSN(fnmsub_d, MATCH_FNMSUB_D, MASK_FNMSUB_D) +DECLARE_INSN(addw, MATCH_ADDW, MASK_ADDW) +DECLARE_INSN(sll, MATCH_SLL, MASK_SLL) +DECLARE_INSN(xor, MATCH_XOR, MASK_XOR) +DECLARE_INSN(sub, MATCH_SUB, MASK_SUB) +DECLARE_INSN(blt, MATCH_BLT, MASK_BLT) +DECLARE_INSN(scall, MATCH_SCALL, MASK_SCALL) +DECLARE_INSN(fclass_s, MATCH_FCLASS_S, MASK_FCLASS_S) +DECLARE_INSN(sc_w, MATCH_SC_W, MASK_SC_W) +DECLARE_INSN(rem, MATCH_REM, MASK_REM) +DECLARE_INSN(srliw, MATCH_SRLIW, MASK_SRLIW) +DECLARE_INSN(lui, MATCH_LUI, MASK_LUI) +DECLARE_INSN(csrrci, MATCH_CSRRCI, MASK_CSRRCI) +DECLARE_INSN(addi, MATCH_ADDI, MASK_ADDI) +DECLARE_INSN(mulh, MATCH_MULH, MASK_MULH) +DECLARE_INSN(fmul_s, MATCH_FMUL_S, MASK_FMUL_S) +DECLARE_INSN(csrrsi, MATCH_CSRRSI, MASK_CSRRSI) +DECLARE_INSN(srai, MATCH_SRAI, MASK_SRAI) +DECLARE_INSN(amoand_d, MATCH_AMOAND_D, MASK_AMOAND_D) +DECLARE_INSN(flt_d, MATCH_FLT_D, MASK_FLT_D) +DECLARE_INSN(sraw, MATCH_SRAW, MASK_SRAW) +DECLARE_INSN(fmul_d, MATCH_FMUL_D, MASK_FMUL_D) +DECLARE_INSN(ld, MATCH_LD, MASK_LD) +DECLARE_INSN(ori, MATCH_ORI, MASK_ORI) +DECLARE_INSN(csrrs, MATCH_CSRRS, MASK_CSRRS) +DECLARE_INSN(flt_s, MATCH_FLT_S, MASK_FLT_S) +DECLARE_INSN(addiw, MATCH_ADDIW, MASK_ADDIW) +DECLARE_INSN(amoand_w, MATCH_AMOAND_W, MASK_AMOAND_W) +DECLARE_INSN(feq_s, MATCH_FEQ_S, MASK_FEQ_S) +DECLARE_INSN(fsgnjx_d, MATCH_FSGNJX_D, MASK_FSGNJX_D) +DECLARE_INSN(sra, MATCH_SRA, MASK_SRA) +DECLARE_INSN(bge, MATCH_BGE, MASK_BGE) +DECLARE_INSN(sraiw, MATCH_SRAIW, MASK_SRAIW) +DECLARE_INSN(srl, MATCH_SRL, MASK_SRL) +DECLARE_INSN(fsub_d, MATCH_FSUB_D, MASK_FSUB_D) +DECLARE_INSN(fsgnjx_s, MATCH_FSGNJX_S, MASK_FSGNJX_S) +DECLARE_INSN(feq_d, MATCH_FEQ_D, MASK_FEQ_D) +DECLARE_INSN(fcvt_d_wu, MATCH_FCVT_D_WU, MASK_FCVT_D_WU) +DECLARE_INSN(or, MATCH_OR, MASK_OR) +DECLARE_INSN(fcvt_wu_d, MATCH_FCVT_WU_D, MASK_FCVT_WU_D) +DECLARE_INSN(subw, MATCH_SUBW, MASK_SUBW) +DECLARE_INSN(fcvt_d_l, MATCH_FCVT_D_L, MASK_FCVT_D_L) +DECLARE_INSN(amomaxu_d, MATCH_AMOMAXU_D, MASK_AMOMAXU_D) +DECLARE_INSN(xori, MATCH_XORI, MASK_XORI) +DECLARE_INSN(amoxor_d, MATCH_AMOXOR_D, MASK_AMOXOR_D) +DECLARE_INSN(amomaxu_w, MATCH_AMOMAXU_W, MASK_AMOMAXU_W) +DECLARE_INSN(fcvt_wu_s, MATCH_FCVT_WU_S, MASK_FCVT_WU_S) +DECLARE_INSN(andi, MATCH_ANDI, MASK_ANDI) +DECLARE_INSN(fmv_x_s, MATCH_FMV_X_S, MASK_FMV_X_S) +DECLARE_INSN(sret, MATCH_SRET, MASK_SRET) +DECLARE_INSN(fnmadd_s, MATCH_FNMADD_S, MASK_FNMADD_S) +DECLARE_INSN(jal, MATCH_JAL, MASK_JAL) +DECLARE_INSN(lwu, MATCH_LWU, MASK_LWU) +DECLARE_INSN(fmv_x_d, MATCH_FMV_X_D, MASK_FMV_X_D) +DECLARE_INSN(fcvt_d_s, MATCH_FCVT_D_S, MASK_FCVT_D_S) +DECLARE_INSN(fnmadd_d, MATCH_FNMADD_D, MASK_FNMADD_D) +DECLARE_INSN(amoadd_d, MATCH_AMOADD_D, MASK_AMOADD_D) +DECLARE_INSN(lr_d, MATCH_LR_D, MASK_LR_D) +DECLARE_INSN(fcvt_w_s, MATCH_FCVT_W_S, MASK_FCVT_W_S) +DECLARE_INSN(mulhsu, MATCH_MULHSU, MASK_MULHSU) +DECLARE_INSN(amoadd_w, MATCH_AMOADD_W, MASK_AMOADD_W) +DECLARE_INSN(fcvt_d_lu, MATCH_FCVT_D_LU, MASK_FCVT_D_LU) +DECLARE_INSN(lr_w, MATCH_LR_W, MASK_LR_W) +DECLARE_INSN(fcvt_w_d, MATCH_FCVT_W_D, MASK_FCVT_W_D) +DECLARE_INSN(slt, MATCH_SLT, MASK_SLT) +DECLARE_INSN(sllw, MATCH_SLLW, MASK_SLLW) +DECLARE_INSN(amoor_d, MATCH_AMOOR_D, MASK_AMOOR_D) +DECLARE_INSN(slti, MATCH_SLTI, MASK_SLTI) +DECLARE_INSN(remu, MATCH_REMU, MASK_REMU) +DECLARE_INSN(flw, MATCH_FLW, MASK_FLW) +DECLARE_INSN(remw, MATCH_REMW, MASK_REMW) +DECLARE_INSN(sltu, MATCH_SLTU, MASK_SLTU) +DECLARE_INSN(slli, MATCH_SLLI, MASK_SLLI) +DECLARE_INSN(amoor_w, MATCH_AMOOR_W, MASK_AMOOR_W) +DECLARE_INSN(beq, MATCH_BEQ, MASK_BEQ) +DECLARE_INSN(fld, MATCH_FLD, MASK_FLD) +DECLARE_INSN(fsub_s, MATCH_FSUB_S, MASK_FSUB_S) +DECLARE_INSN(and, MATCH_AND, MASK_AND) +DECLARE_INSN(fmv_d_x, MATCH_FMV_D_X, MASK_FMV_D_X) +DECLARE_INSN(lbu, MATCH_LBU, MASK_LBU) +DECLARE_INSN(fsgnj_s, MATCH_FSGNJ_S, MASK_FSGNJ_S) +DECLARE_INSN(amomax_w, MATCH_AMOMAX_W, MASK_AMOMAX_W) +DECLARE_INSN(fsgnj_d, MATCH_FSGNJ_D, MASK_FSGNJ_D) +DECLARE_INSN(mulhu, MATCH_MULHU, MASK_MULHU) +DECLARE_INSN(fcvt_l_d, MATCH_FCVT_L_D, MASK_FCVT_L_D) +DECLARE_INSN(fcvt_s_wu, MATCH_FCVT_S_WU, MASK_FCVT_S_WU) +DECLARE_INSN(fcvt_lu_s, MATCH_FCVT_LU_S, MASK_FCVT_LU_S) +DECLARE_INSN(fcvt_s_l, MATCH_FCVT_S_L, MASK_FCVT_S_L) +DECLARE_INSN(auipc, MATCH_AUIPC, MASK_AUIPC) +DECLARE_INSN(fcvt_lu_d, MATCH_FCVT_LU_D, MASK_FCVT_LU_D) +DECLARE_INSN(csrrwi, MATCH_CSRRWI, MASK_CSRRWI) +DECLARE_INSN(sc_d, MATCH_SC_D, MASK_SC_D) +DECLARE_INSN(fmadd_s, MATCH_FMADD_S, MASK_FMADD_S) +DECLARE_INSN(fsqrt_s, MATCH_FSQRT_S, MASK_FSQRT_S) +DECLARE_INSN(amomin_w, MATCH_AMOMIN_W, MASK_AMOMIN_W) +DECLARE_INSN(fsgnjn_s, MATCH_FSGNJN_S, MASK_FSGNJN_S) +DECLARE_INSN(amoswap_d, MATCH_AMOSWAP_D, MASK_AMOSWAP_D) +DECLARE_INSN(fsqrt_d, MATCH_FSQRT_D, MASK_FSQRT_D) +DECLARE_INSN(fmadd_d, MATCH_FMADD_D, MASK_FMADD_D) +DECLARE_INSN(divw, MATCH_DIVW, MASK_DIVW) +DECLARE_INSN(amomin_d, MATCH_AMOMIN_D, MASK_AMOMIN_D) +DECLARE_INSN(divu, MATCH_DIVU, MASK_DIVU) +DECLARE_INSN(amoswap_w, MATCH_AMOSWAP_W, MASK_AMOSWAP_W) +DECLARE_INSN(jalr, MATCH_JALR, MASK_JALR) +DECLARE_INSN(fsd, MATCH_FSD, MASK_FSD) +DECLARE_INSN(sw, MATCH_SW, MASK_SW) +DECLARE_INSN(fmsub_s, MATCH_FMSUB_S, MASK_FMSUB_S) +DECLARE_INSN(lhu, MATCH_LHU, MASK_LHU) +DECLARE_INSN(sh, MATCH_SH, MASK_SH) +DECLARE_INSN(fsw, MATCH_FSW, MASK_FSW) +DECLARE_INSN(sb, MATCH_SB, MASK_SB) +DECLARE_INSN(fmsub_d, MATCH_FMSUB_D, MASK_FMSUB_D) +DECLARE_INSN(sd, MATCH_SD, MASK_SD) +#endif +#ifdef DECLARE_CSR +DECLARE_CSR(fflags, CSR_FFLAGS) +DECLARE_CSR(frm, CSR_FRM) +DECLARE_CSR(fcsr, CSR_FCSR) +DECLARE_CSR(stats, CSR_STATS) +DECLARE_CSR(sup0, CSR_SUP0) +DECLARE_CSR(sup1, CSR_SUP1) +DECLARE_CSR(epc, CSR_EPC) +DECLARE_CSR(badvaddr, CSR_BADVADDR) +DECLARE_CSR(ptbr, CSR_PTBR) +DECLARE_CSR(asid, CSR_ASID) +DECLARE_CSR(count, CSR_COUNT) +DECLARE_CSR(compare, CSR_COMPARE) +DECLARE_CSR(evec, CSR_EVEC) +DECLARE_CSR(cause, CSR_CAUSE) +DECLARE_CSR(status, CSR_STATUS) +DECLARE_CSR(hartid, CSR_HARTID) +DECLARE_CSR(impl, CSR_IMPL) +DECLARE_CSR(fatc, CSR_FATC) +DECLARE_CSR(send_ipi, CSR_SEND_IPI) +DECLARE_CSR(clear_ipi, CSR_CLEAR_IPI) +DECLARE_CSR(reset, CSR_RESET) +DECLARE_CSR(tohost, CSR_TOHOST) +DECLARE_CSR(fromhost, CSR_FROMHOST) +DECLARE_CSR(cycle, CSR_CYCLE) +DECLARE_CSR(time, CSR_TIME) +DECLARE_CSR(instret, CSR_INSTRET) +DECLARE_CSR(uarch0, CSR_UARCH0) +DECLARE_CSR(uarch1, CSR_UARCH1) +DECLARE_CSR(uarch2, CSR_UARCH2) +DECLARE_CSR(uarch3, CSR_UARCH3) +DECLARE_CSR(uarch4, CSR_UARCH4) +DECLARE_CSR(uarch5, CSR_UARCH5) +DECLARE_CSR(uarch6, CSR_UARCH6) +DECLARE_CSR(uarch7, CSR_UARCH7) +DECLARE_CSR(uarch8, CSR_UARCH8) +DECLARE_CSR(uarch9, CSR_UARCH9) +DECLARE_CSR(uarch10, CSR_UARCH10) +DECLARE_CSR(uarch11, CSR_UARCH11) +DECLARE_CSR(uarch12, CSR_UARCH12) +DECLARE_CSR(uarch13, CSR_UARCH13) +DECLARE_CSR(uarch14, CSR_UARCH14) +DECLARE_CSR(uarch15, CSR_UARCH15) +DECLARE_CSR(counth, CSR_COUNTH) +DECLARE_CSR(cycleh, CSR_CYCLEH) +DECLARE_CSR(timeh, CSR_TIMEH) +DECLARE_CSR(instreth, CSR_INSTRETH) +#endif +#ifdef DECLARE_CAUSE +DECLARE_CAUSE("fflags", CAUSE_FFLAGS) +DECLARE_CAUSE("frm", CAUSE_FRM) +DECLARE_CAUSE("fcsr", CAUSE_FCSR) +DECLARE_CAUSE("stats", CAUSE_STATS) +DECLARE_CAUSE("sup0", CAUSE_SUP0) +DECLARE_CAUSE("sup1", CAUSE_SUP1) +DECLARE_CAUSE("epc", CAUSE_EPC) +DECLARE_CAUSE("badvaddr", CAUSE_BADVADDR) +DECLARE_CAUSE("ptbr", CAUSE_PTBR) +DECLARE_CAUSE("asid", CAUSE_ASID) +DECLARE_CAUSE("count", CAUSE_COUNT) +DECLARE_CAUSE("compare", CAUSE_COMPARE) +DECLARE_CAUSE("evec", CAUSE_EVEC) +DECLARE_CAUSE("cause", CAUSE_CAUSE) +DECLARE_CAUSE("status", CAUSE_STATUS) +DECLARE_CAUSE("hartid", CAUSE_HARTID) +DECLARE_CAUSE("impl", CAUSE_IMPL) +DECLARE_CAUSE("fatc", CAUSE_FATC) +DECLARE_CAUSE("send_ipi", CAUSE_SEND_IPI) +DECLARE_CAUSE("clear_ipi", CAUSE_CLEAR_IPI) +DECLARE_CAUSE("reset", CAUSE_RESET) +DECLARE_CAUSE("tohost", CAUSE_TOHOST) +DECLARE_CAUSE("fromhost", CAUSE_FROMHOST) +DECLARE_CAUSE("cycle", CAUSE_CYCLE) +DECLARE_CAUSE("time", CAUSE_TIME) +DECLARE_CAUSE("instret", CAUSE_INSTRET) +DECLARE_CAUSE("uarch0", CAUSE_UARCH0) +DECLARE_CAUSE("uarch1", CAUSE_UARCH1) +DECLARE_CAUSE("uarch2", CAUSE_UARCH2) +DECLARE_CAUSE("uarch3", CAUSE_UARCH3) +DECLARE_CAUSE("uarch4", CAUSE_UARCH4) +DECLARE_CAUSE("uarch5", CAUSE_UARCH5) +DECLARE_CAUSE("uarch6", CAUSE_UARCH6) +DECLARE_CAUSE("uarch7", CAUSE_UARCH7) +DECLARE_CAUSE("uarch8", CAUSE_UARCH8) +DECLARE_CAUSE("uarch9", CAUSE_UARCH9) +DECLARE_CAUSE("uarch10", CAUSE_UARCH10) +DECLARE_CAUSE("uarch11", CAUSE_UARCH11) +DECLARE_CAUSE("uarch12", CAUSE_UARCH12) +DECLARE_CAUSE("uarch13", CAUSE_UARCH13) +DECLARE_CAUSE("uarch14", CAUSE_UARCH14) +DECLARE_CAUSE("uarch15", CAUSE_UARCH15) +DECLARE_CAUSE("counth", CAUSE_COUNTH) +DECLARE_CAUSE("cycleh", CAUSE_CYCLEH) +DECLARE_CAUSE("timeh", CAUSE_TIMEH) +DECLARE_CAUSE("instreth", CAUSE_INSTRETH) +#endif Index: v0.1/riscv-tests/slti.S =================================================================== --- v0.1/riscv-tests/slti.S (nonexistent) +++ v0.1/riscv-tests/slti.S (revision 47) @@ -0,0 +1,70 @@ +# See LICENSE for license details. + +#***************************************************************************** +# slti.S +#----------------------------------------------------------------------------- +# +# Test slti instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + #------------------------------------------------------------- + # Arithmetic tests + #------------------------------------------------------------- + + TEST_IMM_OP( 2, slti, 0, 0x00000000, 0x000 ); + TEST_IMM_OP( 3, slti, 0, 0x00000001, 0x001 ); + TEST_IMM_OP( 4, slti, 1, 0x00000003, 0x007 ); + TEST_IMM_OP( 5, slti, 0, 0x00000007, 0x003 ); + + TEST_IMM_OP( 6, slti, 0, 0x00000000, 0x800 ); + TEST_IMM_OP( 7, slti, 1, 0x80000000, 0x000 ); + TEST_IMM_OP( 8, slti, 1, 0x80000000, 0x800 ); + + TEST_IMM_OP( 9, slti, 1, 0x00000000, 0x7ff ); + TEST_IMM_OP( 10, slti, 0, 0x7fffffff, 0x000 ); + TEST_IMM_OP( 11, slti, 0, 0x7fffffff, 0x7ff ); + + TEST_IMM_OP( 12, slti, 1, 0x80000000, 0x7ff ); + TEST_IMM_OP( 13, slti, 0, 0x7fffffff, 0x800 ); + + TEST_IMM_OP( 14, slti, 0, 0x00000000, 0xfff ); + TEST_IMM_OP( 15, slti, 1, 0xffffffff, 0x001 ); + TEST_IMM_OP( 16, slti, 0, 0xffffffff, 0xfff ); + + #------------------------------------------------------------- + # Source/Destination tests + #------------------------------------------------------------- + + TEST_IMM_SRC1_EQ_DEST( 17, sltiu, 1, 11, 13 ); + + #------------------------------------------------------------- + # Bypassing tests + #------------------------------------------------------------- + + TEST_IMM_DEST_BYPASS( 18, 0, slti, 0, 15, 10 ); + TEST_IMM_DEST_BYPASS( 19, 1, slti, 1, 10, 16 ); + TEST_IMM_DEST_BYPASS( 20, 2, slti, 0, 16, 9 ); + + TEST_IMM_SRC1_BYPASS( 21, 0, slti, 1, 11, 15 ); + TEST_IMM_SRC1_BYPASS( 22, 1, slti, 0, 17, 8 ); + TEST_IMM_SRC1_BYPASS( 23, 2, slti, 1, 12, 14 ); + + TEST_IMM_ZEROSRC1( 24, slti, 0, 0xfff ); + TEST_IMM_ZERODEST( 25, slti, 0x00ff00ff, 0xfff ); + + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +RVTEST_DATA_END Index: v0.1/riscv-tests/LICENSE =================================================================== --- v0.1/riscv-tests/LICENSE (nonexistent) +++ v0.1/riscv-tests/LICENSE (revision 47) @@ -0,0 +1,24 @@ +Copyright (c) 2012-2015, The Regents of the University of California (Regents). +All Rights Reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name of the Regents nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, +SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING +OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS +BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED +HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. Index: v0.1/riscv-tests/lw.S =================================================================== --- v0.1/riscv-tests/lw.S (nonexistent) +++ v0.1/riscv-tests/lw.S (revision 47) @@ -0,0 +1,92 @@ +# See LICENSE for license details. + +#***************************************************************************** +# lw.S +#----------------------------------------------------------------------------- +# +# Test lw instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + #------------------------------------------------------------- + # Basic tests + #------------------------------------------------------------- + + TEST_LD_OP( 2, lw, 0x00ff00ff, 0, tdat ); + TEST_LD_OP( 3, lw, 0xff00ff00, 4, tdat ); + TEST_LD_OP( 4, lw, 0x0ff00ff0, 8, tdat ); + TEST_LD_OP( 5, lw, 0xf00ff00f, 12, tdat ); + + # Test with negative offset + + TEST_LD_OP( 6, lw, 0x00ff00ff, -12, tdat4 ); + TEST_LD_OP( 7, lw, 0xff00ff00, -8, tdat4 ); + TEST_LD_OP( 8, lw, 0x0ff00ff0, -4, tdat4 ); + TEST_LD_OP( 9, lw, 0xf00ff00f, 0, tdat4 ); + + # Test with a negative base + + TEST_CASE( 10, x3, 0x00ff00ff, \ + la x1, tdat; \ + addi x1, x1, -32; \ + lw x3, 32(x1); \ + ) + + # Test with unaligned base + + TEST_CASE( 11, x3, 0xff00ff00, \ + la x1, tdat; \ + addi x1, x1, -3; \ + lw x3, 7(x1); \ + ) + + #------------------------------------------------------------- + # Bypassing tests + #------------------------------------------------------------- + + TEST_LD_DEST_BYPASS( 12, 0, lw, 0x0ff00ff0, 4, tdat2 ); + TEST_LD_DEST_BYPASS( 13, 1, lw, 0xf00ff00f, 4, tdat3 ); + TEST_LD_DEST_BYPASS( 14, 2, lw, 0xff00ff00, 4, tdat1 ); + + TEST_LD_SRC1_BYPASS( 15, 0, lw, 0x0ff00ff0, 4, tdat2 ); + TEST_LD_SRC1_BYPASS( 16, 1, lw, 0xf00ff00f, 4, tdat3 ); + TEST_LD_SRC1_BYPASS( 17, 2, lw, 0xff00ff00, 4, tdat1 ); + + #------------------------------------------------------------- + # Test write-after-write hazard + #------------------------------------------------------------- + + TEST_CASE( 18, x2, 2, \ + la x3, tdat; \ + lw x2, 0(x3); \ + li x2, 2; \ + ) + + TEST_CASE( 19, x2, 2, \ + la x3, tdat; \ + lw x2, 0(x3); \ + nop; \ + li x2, 2; \ + ) + + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +tdat: +tdat1: .word 0x00ff00ff +tdat2: .word 0xff00ff00 +tdat3: .word 0x0ff00ff0 +tdat4: .word 0xf00ff00f + +RVTEST_DATA_END Index: v0.1/riscv-tests/add.S =================================================================== --- v0.1/riscv-tests/add.S (nonexistent) +++ v0.1/riscv-tests/add.S (revision 47) @@ -0,0 +1,85 @@ +# See LICENSE for license details. + +#***************************************************************************** +# add.S +#----------------------------------------------------------------------------- +# +# Test add instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + #------------------------------------------------------------- + # Arithmetic tests + #------------------------------------------------------------- + + TEST_RR_OP( 2, add, 0x00000000, 0x00000000, 0x00000000 ); + TEST_RR_OP( 3, add, 0x00000002, 0x00000001, 0x00000001 ); + TEST_RR_OP( 4, add, 0x0000000a, 0x00000003, 0x00000007 ); + + TEST_RR_OP( 5, add, 0xffff8000, 0x00000000, 0xffff8000 ); + TEST_RR_OP( 6, add, 0x80000000, 0x80000000, 0x00000000 ); + TEST_RR_OP( 7, add, 0x7fff8000, 0x80000000, 0xffff8000 ); + + TEST_RR_OP( 8, add, 0x00007fff, 0x00000000, 0x00007fff ); + TEST_RR_OP( 9, add, 0x7fffffff, 0x7fffffff, 0x00000000 ); + TEST_RR_OP( 10, add, 0x80007ffe, 0x7fffffff, 0x00007fff ); + + TEST_RR_OP( 11, add, 0x80007fff, 0x80000000, 0x00007fff ); + TEST_RR_OP( 12, add, 0x7fff7fff, 0x7fffffff, 0xffff8000 ); + + TEST_RR_OP( 13, add, 0xffffffff, 0x00000000, 0xffffffff ); + TEST_RR_OP( 14, add, 0x00000000, 0xffffffff, 0x00000001 ); + TEST_RR_OP( 15, add, 0xfffffffe, 0xffffffff, 0xffffffff ); + + TEST_RR_OP( 16, add, 0x80000000, 0x00000001, 0x7fffffff ); + + #------------------------------------------------------------- + # Source/Destination tests + #------------------------------------------------------------- + + TEST_RR_SRC1_EQ_DEST( 17, add, 24, 13, 11 ); + TEST_RR_SRC2_EQ_DEST( 18, add, 25, 14, 11 ); + TEST_RR_SRC12_EQ_DEST( 19, add, 26, 13 ); + + #------------------------------------------------------------- + # Bypassing tests + #------------------------------------------------------------- + + TEST_RR_DEST_BYPASS( 20, 0, add, 24, 13, 11 ); + TEST_RR_DEST_BYPASS( 21, 1, add, 25, 14, 11 ); + TEST_RR_DEST_BYPASS( 22, 2, add, 26, 15, 11 ); + + TEST_RR_SRC12_BYPASS( 23, 0, 0, add, 24, 13, 11 ); + TEST_RR_SRC12_BYPASS( 24, 0, 1, add, 25, 14, 11 ); + TEST_RR_SRC12_BYPASS( 25, 0, 2, add, 26, 15, 11 ); + TEST_RR_SRC12_BYPASS( 26, 1, 0, add, 24, 13, 11 ); + TEST_RR_SRC12_BYPASS( 27, 1, 1, add, 25, 14, 11 ); + TEST_RR_SRC12_BYPASS( 28, 2, 0, add, 26, 15, 11 ); + + TEST_RR_SRC21_BYPASS( 29, 0, 0, add, 24, 13, 11 ); + TEST_RR_SRC21_BYPASS( 30, 0, 1, add, 25, 14, 11 ); + TEST_RR_SRC21_BYPASS( 31, 0, 2, add, 26, 15, 11 ); + TEST_RR_SRC21_BYPASS( 32, 1, 0, add, 24, 13, 11 ); + TEST_RR_SRC21_BYPASS( 33, 1, 1, add, 25, 14, 11 ); + TEST_RR_SRC21_BYPASS( 34, 2, 0, add, 26, 15, 11 ); + + TEST_RR_ZEROSRC1( 35, add, 15, 15 ); + TEST_RR_ZEROSRC2( 36, add, 32, 32 ); + TEST_RR_ZEROSRC12( 37, add, 0 ); + TEST_RR_ZERODEST( 38, add, 16, 30 ); + + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +RVTEST_DATA_END Index: v0.1/riscv-tests/jalr.S =================================================================== --- v0.1/riscv-tests/jalr.S (nonexistent) +++ v0.1/riscv-tests/jalr.S (revision 47) @@ -0,0 +1,88 @@ +# See LICENSE for license details. + +#***************************************************************************** +# jalr.S +#----------------------------------------------------------------------------- +# +# Test jalr instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + #------------------------------------------------------------- + # Test 2: Basic test + #------------------------------------------------------------- + +test_2: + li TESTNUM, 2 + li x31, 0 + la x2, target_2 + +linkaddr_2: + jalr x19, x2, 0 + nop + nop + + j fail + +target_2: + la x1, linkaddr_2 + addi x1, x1, 4 + bne x1, x19, fail + + #------------------------------------------------------------- + # Test 3: Check r0 target and that r31 is not modified + #------------------------------------------------------------- + +test_3: + li TESTNUM, 3 + li x31, 0 + la x3, target_3 + +linkaddr_3: + jalr x0, x3, 0 + nop + + j fail + +target_3: + bne x31, x0, fail + + #------------------------------------------------------------- + # Bypassing tests + #------------------------------------------------------------- + + TEST_JALR_SRC1_BYPASS( 4, 0, jalr ); + TEST_JALR_SRC1_BYPASS( 5, 1, jalr ); + TEST_JALR_SRC1_BYPASS( 6, 2, jalr ); + + #------------------------------------------------------------- + # Test delay slot instructions not executed nor bypassed + #------------------------------------------------------------- + + TEST_CASE( 7, x1, 4, \ + li x1, 1; \ + la x2, 1f; + jalr x19, x2, -4; \ + addi x1, x1, 1; \ + addi x1, x1, 1; \ + addi x1, x1, 1; \ + addi x1, x1, 1; \ +1: addi x1, x1, 1; \ + addi x1, x1, 1; \ + ) + + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +RVTEST_DATA_END Index: v0.1/riscv-tests/sub.S =================================================================== --- v0.1/riscv-tests/sub.S (nonexistent) +++ v0.1/riscv-tests/sub.S (revision 47) @@ -0,0 +1,83 @@ +# See LICENSE for license details. + +#***************************************************************************** +# sub.S +#----------------------------------------------------------------------------- +# +# Test sub instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + #------------------------------------------------------------- + # Arithmetic tests + #------------------------------------------------------------- + + TEST_RR_OP( 2, sub, 0x00000000, 0x00000000, 0x00000000 ); + TEST_RR_OP( 3, sub, 0x00000000, 0x00000001, 0x00000001 ); + TEST_RR_OP( 4, sub, 0xfffffffc, 0x00000003, 0x00000007 ); + + TEST_RR_OP( 5, sub, 0x00008000, 0x00000000, 0xffff8000 ); + TEST_RR_OP( 6, sub, 0x80000000, 0x80000000, 0x00000000 ); + TEST_RR_OP( 7, sub, 0x80008000, 0x80000000, 0xffff8000 ); + + TEST_RR_OP( 8, sub, 0xffff8001, 0x00000000, 0x00007fff ); + TEST_RR_OP( 9, sub, 0x7fffffff, 0x7fffffff, 0x00000000 ); + TEST_RR_OP( 10, sub, 0x7fff8000, 0x7fffffff, 0x00007fff ); + + TEST_RR_OP( 11, sub, 0x7fff8001, 0x80000000, 0x00007fff ); + TEST_RR_OP( 12, sub, 0x80007fff, 0x7fffffff, 0xffff8000 ); + + TEST_RR_OP( 13, sub, 0x00000001, 0x00000000, 0xffffffff ); + TEST_RR_OP( 14, sub, 0xfffffffe, 0xffffffff, 0x00000001 ); + TEST_RR_OP( 15, sub, 0x00000000, 0xffffffff, 0xffffffff ); + + #------------------------------------------------------------- + # Source/Destination tests + #------------------------------------------------------------- + + TEST_RR_SRC1_EQ_DEST( 16, sub, 2, 13, 11 ); + TEST_RR_SRC2_EQ_DEST( 17, sub, 3, 14, 11 ); + TEST_RR_SRC12_EQ_DEST( 18, sub, 0, 13 ); + + #------------------------------------------------------------- + # Bypassing tests + #------------------------------------------------------------- + + TEST_RR_DEST_BYPASS( 19, 0, sub, 2, 13, 11 ); + TEST_RR_DEST_BYPASS( 20, 1, sub, 3, 14, 11 ); + TEST_RR_DEST_BYPASS( 21, 2, sub, 4, 15, 11 ); + + TEST_RR_SRC12_BYPASS( 22, 0, 0, sub, 2, 13, 11 ); + TEST_RR_SRC12_BYPASS( 23, 0, 1, sub, 3, 14, 11 ); + TEST_RR_SRC12_BYPASS( 24, 0, 2, sub, 4, 15, 11 ); + TEST_RR_SRC12_BYPASS( 25, 1, 0, sub, 2, 13, 11 ); + TEST_RR_SRC12_BYPASS( 26, 1, 1, sub, 3, 14, 11 ); + TEST_RR_SRC12_BYPASS( 27, 2, 0, sub, 4, 15, 11 ); + + TEST_RR_SRC21_BYPASS( 28, 0, 0, sub, 2, 13, 11 ); + TEST_RR_SRC21_BYPASS( 29, 0, 1, sub, 3, 14, 11 ); + TEST_RR_SRC21_BYPASS( 30, 0, 2, sub, 4, 15, 11 ); + TEST_RR_SRC21_BYPASS( 31, 1, 0, sub, 2, 13, 11 ); + TEST_RR_SRC21_BYPASS( 32, 1, 1, sub, 3, 14, 11 ); + TEST_RR_SRC21_BYPASS( 33, 2, 0, sub, 4, 15, 11 ); + + TEST_RR_ZEROSRC1( 34, sub, 15, -15 ); + TEST_RR_ZEROSRC2( 35, sub, 32, 32 ); + TEST_RR_ZEROSRC12( 36, sub, 0 ); + TEST_RR_ZERODEST( 37, sub, 16, 30 ); + + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +RVTEST_DATA_END Index: v0.1/riscv-tests/j.S =================================================================== --- v0.1/riscv-tests/j.S (nonexistent) +++ v0.1/riscv-tests/j.S (revision 47) @@ -0,0 +1,49 @@ +# See LICENSE for license details. + +#***************************************************************************** +# j.S +#----------------------------------------------------------------------------- +# +# Test j instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + #------------------------------------------------------------- + # Test basic + #------------------------------------------------------------- + + li TESTNUM, 2; + j test_2; + j fail; +test_2: + + #------------------------------------------------------------- + # Test delay slot instructions not executed nor bypassed + #------------------------------------------------------------- + + TEST_CASE( 3, x1, 3, \ + li x1, 1; \ + j 1f; \ + addi x1, x1, 1; \ + addi x1, x1, 1; \ + addi x1, x1, 1; \ + addi x1, x1, 1; \ +1: addi x1, x1, 1; \ + addi x1, x1, 1; \ + ) + + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +RVTEST_DATA_END Index: v0.1/riscv-tests/README =================================================================== --- v0.1/riscv-tests/README (nonexistent) +++ v0.1/riscv-tests/README (revision 47) @@ -0,0 +1,5 @@ +# RISC-V ISA Tests + +This directory contains a mirror of the tests from the riscv-tests repository +(https://github.com/riscv/riscv-tests) that are used in the Potato processor. + Index: v0.1/riscv-tests/srai.S =================================================================== --- v0.1/riscv-tests/srai.S (nonexistent) +++ v0.1/riscv-tests/srai.S (revision 47) @@ -0,0 +1,68 @@ +# See LICENSE for license details. + +#***************************************************************************** +# srai.S +#----------------------------------------------------------------------------- +# +# Test srai instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + #------------------------------------------------------------- + # Arithmetic tests + #------------------------------------------------------------- + + TEST_IMM_OP( 2, srai, 0x00000000, 0x00000000, 0 ); + TEST_IMM_OP( 3, srai, 0xc0000000, 0x80000000, 1 ); + TEST_IMM_OP( 4, srai, 0xff000000, 0x80000000, 7 ); + TEST_IMM_OP( 5, srai, 0xfffe0000, 0x80000000, 14 ); + TEST_IMM_OP( 6, srai, 0xffffffff, 0x80000001, 31 ); + + TEST_IMM_OP( 7, srai, 0x7fffffff, 0x7fffffff, 0 ); + TEST_IMM_OP( 8, srai, 0x3fffffff, 0x7fffffff, 1 ); + TEST_IMM_OP( 9, srai, 0x00ffffff, 0x7fffffff, 7 ); + TEST_IMM_OP( 10, srai, 0x0001ffff, 0x7fffffff, 14 ); + TEST_IMM_OP( 11, srai, 0x00000000, 0x7fffffff, 31 ); + + TEST_IMM_OP( 12, srai, 0x81818181, 0x81818181, 0 ); + TEST_IMM_OP( 13, srai, 0xc0c0c0c0, 0x81818181, 1 ); + TEST_IMM_OP( 14, srai, 0xff030303, 0x81818181, 7 ); + TEST_IMM_OP( 15, srai, 0xfffe0606, 0x81818181, 14 ); + TEST_IMM_OP( 16, srai, 0xffffffff, 0x81818181, 31 ); + + #------------------------------------------------------------- + # Source/Destination tests + #------------------------------------------------------------- + + TEST_IMM_SRC1_EQ_DEST( 17, srai, 0xff000000, 0x80000000, 7 ); + + #------------------------------------------------------------- + # Bypassing tests + #------------------------------------------------------------- + + TEST_IMM_DEST_BYPASS( 18, 0, srai, 0xff000000, 0x80000000, 7 ); + TEST_IMM_DEST_BYPASS( 19, 1, srai, 0xfffe0000, 0x80000000, 14 ); + TEST_IMM_DEST_BYPASS( 20, 2, srai, 0xffffffff, 0x80000001, 31 ); + + TEST_IMM_SRC1_BYPASS( 21, 0, srai, 0xff000000, 0x80000000, 7 ); + TEST_IMM_SRC1_BYPASS( 22, 1, srai, 0xfffe0000, 0x80000000, 14 ); + TEST_IMM_SRC1_BYPASS( 23, 2, srai, 0xffffffff, 0x80000001, 31 ); + + TEST_IMM_ZEROSRC1( 24, srai, 0, 31 ); + TEST_IMM_ZERODEST( 25, srai, 33, 20 ); +# + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +RVTEST_DATA_END Index: v0.1/riscv-tests/addi.S =================================================================== --- v0.1/riscv-tests/addi.S (nonexistent) +++ v0.1/riscv-tests/addi.S (revision 47) @@ -0,0 +1,71 @@ +# See LICENSE for license details. + +#***************************************************************************** +# addi.S +#----------------------------------------------------------------------------- +# +# Test addi instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + #------------------------------------------------------------- + # Arithmetic tests + #------------------------------------------------------------- + + TEST_IMM_OP( 2, addi, 0x00000000, 0x00000000, 0x000 ); + TEST_IMM_OP( 3, addi, 0x00000002, 0x00000001, 0x001 ); + TEST_IMM_OP( 4, addi, 0x0000000a, 0x00000003, 0x007 ); + + TEST_IMM_OP( 5, addi, 0xfffff800, 0x00000000, 0x800 ); + TEST_IMM_OP( 6, addi, 0x80000000, 0x80000000, 0x000 ); + TEST_IMM_OP( 7, addi, 0x7ffff800, 0x80000000, 0x800 ); + + TEST_IMM_OP( 8, addi, 0x000007ff, 0x00000000, 0x7ff ); + TEST_IMM_OP( 9, addi, 0x7fffffff, 0x7fffffff, 0x000 ); + TEST_IMM_OP( 10, addi, 0x800007fe, 0x7fffffff, 0x7ff ); + + TEST_IMM_OP( 11, addi, 0x800007ff, 0x80000000, 0x7ff ); + TEST_IMM_OP( 12, addi, 0x7ffff7ff, 0x7fffffff, 0x800 ); + + TEST_IMM_OP( 13, addi, 0xffffffff, 0x00000000, 0xfff ); + TEST_IMM_OP( 14, addi, 0x00000000, 0xffffffff, 0x001 ); + TEST_IMM_OP( 15, addi, 0xfffffffe, 0xffffffff, 0xfff ); + + TEST_IMM_OP( 16, addi, 0x80000000, 0x7fffffff, 0x001 ); + + #------------------------------------------------------------- + # Source/Destination tests + #------------------------------------------------------------- + + TEST_IMM_SRC1_EQ_DEST( 17, addi, 24, 13, 11 ); + + #------------------------------------------------------------- + # Bypassing tests + #------------------------------------------------------------- + + TEST_IMM_DEST_BYPASS( 18, 0, addi, 24, 13, 11 ); + TEST_IMM_DEST_BYPASS( 19, 1, addi, 23, 13, 10 ); + TEST_IMM_DEST_BYPASS( 20, 2, addi, 22, 13, 9 ); + + TEST_IMM_SRC1_BYPASS( 21, 0, addi, 24, 13, 11 ); + TEST_IMM_SRC1_BYPASS( 22, 1, addi, 23, 13, 10 ); + TEST_IMM_SRC1_BYPASS( 23, 2, addi, 22, 13, 9 ); + + TEST_IMM_ZEROSRC1( 24, addi, 32, 32 ); + TEST_IMM_ZERODEST( 25, addi, 33, 50 ); + + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +RVTEST_DATA_END Index: v0.1/riscv-tests/auipc.S =================================================================== --- v0.1/riscv-tests/auipc.S (nonexistent) +++ v0.1/riscv-tests/auipc.S (revision 47) @@ -0,0 +1,39 @@ +# See LICENSE for license details. + +#***************************************************************************** +# auipc.S +#----------------------------------------------------------------------------- +# +# Test auipc instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + TEST_CASE(2, a0, 10000, \ + .align 3; \ + lla a0, 1f + 10000; \ + jal a1, 1f; \ + 1: sub a0, a0, a1; \ + ) + + TEST_CASE(3, a0, -10000, \ + .align 3; \ + lla a0, 1f - 10000; \ + jal a1, 1f; \ + 1: sub a0, a0, a1; \ + ) + + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +RVTEST_DATA_END Index: v0.1/riscv-tests/and.S =================================================================== --- v0.1/riscv-tests/and.S (nonexistent) +++ v0.1/riscv-tests/and.S (revision 47) @@ -0,0 +1,69 @@ +# See LICENSE for license details. + +#***************************************************************************** +# and.S +#----------------------------------------------------------------------------- +# +# Test and instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + #------------------------------------------------------------- + # Logical tests + #------------------------------------------------------------- + + TEST_RR_OP( 2, and, 0x0f000f00, 0xff00ff00, 0x0f0f0f0f ); + TEST_RR_OP( 3, and, 0x00f000f0, 0x0ff00ff0, 0xf0f0f0f0 ); + TEST_RR_OP( 4, and, 0x000f000f, 0x00ff00ff, 0x0f0f0f0f ); + TEST_RR_OP( 5, and, 0xf000f000, 0xf00ff00f, 0xf0f0f0f0 ); + + #------------------------------------------------------------- + # Source/Destination tests + #------------------------------------------------------------- + + TEST_RR_SRC1_EQ_DEST( 6, and, 0x0f000f00, 0xff00ff00, 0x0f0f0f0f ); + TEST_RR_SRC2_EQ_DEST( 7, and, 0x00f000f0, 0x0ff00ff0, 0xf0f0f0f0 ); + TEST_RR_SRC12_EQ_DEST( 8, and, 0xff00ff00, 0xff00ff00 ); + + #------------------------------------------------------------- + # Bypassing tests + #------------------------------------------------------------- + + TEST_RR_DEST_BYPASS( 9, 0, and, 0x0f000f00, 0xff00ff00, 0x0f0f0f0f ); + TEST_RR_DEST_BYPASS( 10, 1, and, 0x00f000f0, 0x0ff00ff0, 0xf0f0f0f0 ); + TEST_RR_DEST_BYPASS( 11, 2, and, 0x000f000f, 0x00ff00ff, 0x0f0f0f0f ); + + TEST_RR_SRC12_BYPASS( 12, 0, 0, and, 0x0f000f00, 0xff00ff00, 0x0f0f0f0f ); + TEST_RR_SRC12_BYPASS( 13, 0, 1, and, 0x00f000f0, 0x0ff00ff0, 0xf0f0f0f0 ); + TEST_RR_SRC12_BYPASS( 14, 0, 2, and, 0x000f000f, 0x00ff00ff, 0x0f0f0f0f ); + TEST_RR_SRC12_BYPASS( 15, 1, 0, and, 0x0f000f00, 0xff00ff00, 0x0f0f0f0f ); + TEST_RR_SRC12_BYPASS( 16, 1, 1, and, 0x00f000f0, 0x0ff00ff0, 0xf0f0f0f0 ); + TEST_RR_SRC12_BYPASS( 17, 2, 0, and, 0x000f000f, 0x00ff00ff, 0x0f0f0f0f ); + + TEST_RR_SRC21_BYPASS( 18, 0, 0, and, 0x0f000f00, 0xff00ff00, 0x0f0f0f0f ); + TEST_RR_SRC21_BYPASS( 19, 0, 1, and, 0x00f000f0, 0x0ff00ff0, 0xf0f0f0f0 ); + TEST_RR_SRC21_BYPASS( 20, 0, 2, and, 0x000f000f, 0x00ff00ff, 0x0f0f0f0f ); + TEST_RR_SRC21_BYPASS( 21, 1, 0, and, 0x0f000f00, 0xff00ff00, 0x0f0f0f0f ); + TEST_RR_SRC21_BYPASS( 22, 1, 1, and, 0x00f000f0, 0x0ff00ff0, 0xf0f0f0f0 ); + TEST_RR_SRC21_BYPASS( 23, 2, 0, and, 0x000f000f, 0x00ff00ff, 0x0f0f0f0f ); + + TEST_RR_ZEROSRC1( 24, and, 0, 0xff00ff00 ); + TEST_RR_ZEROSRC2( 25, and, 0, 0x00ff00ff ); + TEST_RR_ZEROSRC12( 26, and, 0 ); + TEST_RR_ZERODEST( 27, and, 0x11111111, 0x22222222 ); + + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +RVTEST_DATA_END Index: v0.1/riscv-tests/sb.S =================================================================== --- v0.1/riscv-tests/sb.S (nonexistent) +++ v0.1/riscv-tests/sb.S (revision 47) @@ -0,0 +1,102 @@ +# See LICENSE for license details. + +#***************************************************************************** +# sb.S +#----------------------------------------------------------------------------- +# +# Test sb instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + #------------------------------------------------------------- + # Basic tests + #------------------------------------------------------------- + + TEST_ST_OP( 2, lb, sb, 0xffffffaa, 0, tdat ); + TEST_ST_OP( 3, lb, sb, 0x00000000, 1, tdat ); +#ifdef __RISCVEL + TEST_ST_OP( 4, lh, sb, 0xffffefa0, 2, tdat ); +#elif defined(__RISCVEB) +#else + TEST_ST_OP( 4, lh, sb, 0xffffa0ef, 2, tdat ); +#error unknown endianness! +#endif + TEST_ST_OP( 5, lb, sb, 0x0000000a, 3, tdat ); + + # Test with negative offset + + TEST_ST_OP( 6, lb, sb, 0xffffffaa, -3, tdat8 ); + TEST_ST_OP( 7, lb, sb, 0x00000000, -2, tdat8 ); + TEST_ST_OP( 8, lb, sb, 0xffffffa0, -1, tdat8 ); + TEST_ST_OP( 9, lb, sb, 0x0000000a, 0, tdat8 ); + + # Test with a negative base + + TEST_CASE( 10, x3, 0x78, \ + la x1, tdat9; \ + li x2, 0x12345678; \ + addi x4, x1, -32; \ + sb x2, 32(x4); \ + lb x3, 0(x1); \ + ) + + # Test with unaligned base + + TEST_CASE( 11, x3, 0xffffff98, \ + la x1, tdat9; \ + li x2, 0x00003098; \ + addi x1, x1, -6; \ + sb x2, 7(x1); \ + la x4, tdat10; \ + lb x3, 0(x4); \ + ) + + #------------------------------------------------------------- + # Bypassing tests + #------------------------------------------------------------- + + TEST_ST_SRC12_BYPASS( 12, 0, 0, lb, sb, 0xffffffdd, 0, tdat ); + TEST_ST_SRC12_BYPASS( 13, 0, 1, lb, sb, 0xffffffcd, 1, tdat ); + TEST_ST_SRC12_BYPASS( 14, 0, 2, lb, sb, 0xffffffcc, 2, tdat ); + TEST_ST_SRC12_BYPASS( 15, 1, 0, lb, sb, 0xffffffbc, 3, tdat ); + TEST_ST_SRC12_BYPASS( 16, 1, 1, lb, sb, 0xffffffbb, 4, tdat ); + TEST_ST_SRC12_BYPASS( 17, 2, 0, lb, sb, 0xffffffab, 5, tdat ); + + TEST_ST_SRC21_BYPASS( 18, 0, 0, lb, sb, 0x33, 0, tdat ); + TEST_ST_SRC21_BYPASS( 19, 0, 1, lb, sb, 0x23, 1, tdat ); + TEST_ST_SRC21_BYPASS( 20, 0, 2, lb, sb, 0x22, 2, tdat ); + TEST_ST_SRC21_BYPASS( 21, 1, 0, lb, sb, 0x12, 3, tdat ); + TEST_ST_SRC21_BYPASS( 22, 1, 1, lb, sb, 0x11, 4, tdat ); + TEST_ST_SRC21_BYPASS( 23, 2, 0, lb, sb, 0x01, 5, tdat ); + + li a0, 0xef + la a1, tdat + sb a0, 3(a1) + + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +tdat: +tdat1: .byte 0xef +tdat2: .byte 0xef +tdat3: .byte 0xef +tdat4: .byte 0xef +tdat5: .byte 0xef +tdat6: .byte 0xef +tdat7: .byte 0xef +tdat8: .byte 0xef +tdat9: .byte 0xef +tdat10: .byte 0xef + +RVTEST_DATA_END Index: v0.1/riscv-tests/bne.S =================================================================== --- v0.1/riscv-tests/bne.S (nonexistent) +++ v0.1/riscv-tests/bne.S (revision 47) @@ -0,0 +1,73 @@ +# See LICENSE for license details. + +#***************************************************************************** +# bne.S +#----------------------------------------------------------------------------- +# +# Test bne instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + #------------------------------------------------------------- + # Branch tests + #------------------------------------------------------------- + + # Each test checks both forward and backward branches + + TEST_BR2_OP_TAKEN( 2, bne, 0, 1 ); + TEST_BR2_OP_TAKEN( 3, bne, 1, 0 ); + TEST_BR2_OP_TAKEN( 4, bne, -1, 1 ); + TEST_BR2_OP_TAKEN( 5, bne, 1, -1 ); + + TEST_BR2_OP_NOTTAKEN( 6, bne, 0, 0 ); + TEST_BR2_OP_NOTTAKEN( 7, bne, 1, 1 ); + TEST_BR2_OP_NOTTAKEN( 8, bne, -1, -1 ); + + #------------------------------------------------------------- + # Bypassing tests + #------------------------------------------------------------- + + TEST_BR2_SRC12_BYPASS( 9, 0, 0, bne, 0, 0 ); + TEST_BR2_SRC12_BYPASS( 10, 0, 1, bne, 0, 0 ); + TEST_BR2_SRC12_BYPASS( 11, 0, 2, bne, 0, 0 ); + TEST_BR2_SRC12_BYPASS( 12, 1, 0, bne, 0, 0 ); + TEST_BR2_SRC12_BYPASS( 13, 1, 1, bne, 0, 0 ); + TEST_BR2_SRC12_BYPASS( 14, 2, 0, bne, 0, 0 ); + + TEST_BR2_SRC12_BYPASS( 15, 0, 0, bne, 0, 0 ); + TEST_BR2_SRC12_BYPASS( 16, 0, 1, bne, 0, 0 ); + TEST_BR2_SRC12_BYPASS( 17, 0, 2, bne, 0, 0 ); + TEST_BR2_SRC12_BYPASS( 18, 1, 0, bne, 0, 0 ); + TEST_BR2_SRC12_BYPASS( 19, 1, 1, bne, 0, 0 ); + TEST_BR2_SRC12_BYPASS( 20, 2, 0, bne, 0, 0 ); + + #------------------------------------------------------------- + # Test delay slot instructions not executed nor bypassed + #------------------------------------------------------------- + + TEST_CASE( 21, x1, 3, \ + li x1, 1; \ + bne x1, x0, 1f; \ + addi x1, x1, 1; \ + addi x1, x1, 1; \ + addi x1, x1, 1; \ + addi x1, x1, 1; \ +1: addi x1, x1, 1; \ + addi x1, x1, 1; \ + ) + + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +RVTEST_DATA_END Index: v0.1/riscv-tests/bltu.S =================================================================== --- v0.1/riscv-tests/bltu.S (nonexistent) +++ v0.1/riscv-tests/bltu.S (revision 47) @@ -0,0 +1,73 @@ +# See LICENSE for license details. + +#***************************************************************************** +# bltu.S +#----------------------------------------------------------------------------- +# +# Test bltu instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + #------------------------------------------------------------- + # Branch tests + #------------------------------------------------------------- + + # Each test checks both forward and backward branches + + TEST_BR2_OP_TAKEN( 2, bltu, 0x00000000, 0x00000001 ); + TEST_BR2_OP_TAKEN( 3, bltu, 0xfffffffe, 0xffffffff ); + TEST_BR2_OP_TAKEN( 4, bltu, 0x00000000, 0xffffffff ); + + TEST_BR2_OP_NOTTAKEN( 5, bltu, 0x00000001, 0x00000000 ); + TEST_BR2_OP_NOTTAKEN( 6, bltu, 0xffffffff, 0xfffffffe ); + TEST_BR2_OP_NOTTAKEN( 7, bltu, 0xffffffff, 0x00000000 ); + TEST_BR2_OP_NOTTAKEN( 8, bltu, 0x80000000, 0x7fffffff ); + + #------------------------------------------------------------- + # Bypassing tests + #------------------------------------------------------------- + + TEST_BR2_SRC12_BYPASS( 9, 0, 0, bltu, 0xf0000000, 0xefffffff ); + TEST_BR2_SRC12_BYPASS( 10, 0, 1, bltu, 0xf0000000, 0xefffffff ); + TEST_BR2_SRC12_BYPASS( 11, 0, 2, bltu, 0xf0000000, 0xefffffff ); + TEST_BR2_SRC12_BYPASS( 12, 1, 0, bltu, 0xf0000000, 0xefffffff ); + TEST_BR2_SRC12_BYPASS( 13, 1, 1, bltu, 0xf0000000, 0xefffffff ); + TEST_BR2_SRC12_BYPASS( 14, 2, 0, bltu, 0xf0000000, 0xefffffff ); + + TEST_BR2_SRC12_BYPASS( 15, 0, 0, bltu, 0xf0000000, 0xefffffff ); + TEST_BR2_SRC12_BYPASS( 16, 0, 1, bltu, 0xf0000000, 0xefffffff ); + TEST_BR2_SRC12_BYPASS( 17, 0, 2, bltu, 0xf0000000, 0xefffffff ); + TEST_BR2_SRC12_BYPASS( 18, 1, 0, bltu, 0xf0000000, 0xefffffff ); + TEST_BR2_SRC12_BYPASS( 19, 1, 1, bltu, 0xf0000000, 0xefffffff ); + TEST_BR2_SRC12_BYPASS( 20, 2, 0, bltu, 0xf0000000, 0xefffffff ); + + #------------------------------------------------------------- + # Test delay slot instructions not executed nor bypassed + #------------------------------------------------------------- + + TEST_CASE( 21, x1, 3, \ + li x1, 1; \ + bltu x0, x1, 1f; \ + addi x1, x1, 1; \ + addi x1, x1, 1; \ + addi x1, x1, 1; \ + addi x1, x1, 1; \ +1: addi x1, x1, 1; \ + addi x1, x1, 1; \ + ) + + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +RVTEST_DATA_END Index: v0.1/riscv-tests/test_macros.h =================================================================== --- v0.1/riscv-tests/test_macros.h (nonexistent) +++ v0.1/riscv-tests/test_macros.h (revision 47) @@ -0,0 +1,710 @@ +// See LICENSE for license details. + +#ifndef __TEST_MACROS_SCALAR_H +#define __TEST_MACROS_SCALAR_H + + +#----------------------------------------------------------------------- +# Helper macros +#----------------------------------------------------------------------- + +#define TEST_CASE( testnum, testreg, correctval, code... ) \ +test_ ## testnum: \ + code; \ + li x29, correctval; \ + li TESTNUM, testnum; \ + bne testreg, x29, fail; + +# We use a macro hack to simpify code generation for various numbers +# of bubble cycles. + +#define TEST_INSERT_NOPS_0 +#define TEST_INSERT_NOPS_1 nop; TEST_INSERT_NOPS_0 +#define TEST_INSERT_NOPS_2 nop; TEST_INSERT_NOPS_1 +#define TEST_INSERT_NOPS_3 nop; TEST_INSERT_NOPS_2 +#define TEST_INSERT_NOPS_4 nop; TEST_INSERT_NOPS_3 +#define TEST_INSERT_NOPS_5 nop; TEST_INSERT_NOPS_4 +#define TEST_INSERT_NOPS_6 nop; TEST_INSERT_NOPS_5 +#define TEST_INSERT_NOPS_7 nop; TEST_INSERT_NOPS_6 +#define TEST_INSERT_NOPS_8 nop; TEST_INSERT_NOPS_7 +#define TEST_INSERT_NOPS_9 nop; TEST_INSERT_NOPS_8 +#define TEST_INSERT_NOPS_10 nop; TEST_INSERT_NOPS_9 + + +#----------------------------------------------------------------------- +# RV64UI MACROS +#----------------------------------------------------------------------- + +#----------------------------------------------------------------------- +# Tests for instructions with immediate operand +#----------------------------------------------------------------------- + +#define SEXT_IMM(x) ((x) | (-(((x) >> 11) & 1) << 11)) + +#define TEST_IMM_OP( testnum, inst, result, val1, imm ) \ + TEST_CASE( testnum, x3, result, \ + li x1, val1; \ + inst x3, x1, SEXT_IMM(imm); \ + ) + +#define TEST_IMM_SRC1_EQ_DEST( testnum, inst, result, val1, imm ) \ + TEST_CASE( testnum, x1, result, \ + li x1, val1; \ + inst x1, x1, SEXT_IMM(imm); \ + ) + +#define TEST_IMM_DEST_BYPASS( testnum, nop_cycles, inst, result, val1, imm ) \ + TEST_CASE( testnum, x6, result, \ + li x4, 0; \ +1: li x1, val1; \ + inst x3, x1, SEXT_IMM(imm); \ + TEST_INSERT_NOPS_ ## nop_cycles \ + addi x6, x3, 0; \ + addi x4, x4, 1; \ + li x5, 2; \ + bne x4, x5, 1b \ + ) + +#define TEST_IMM_SRC1_BYPASS( testnum, nop_cycles, inst, result, val1, imm ) \ + TEST_CASE( testnum, x3, result, \ + li x4, 0; \ +1: li x1, val1; \ + TEST_INSERT_NOPS_ ## nop_cycles \ + inst x3, x1, SEXT_IMM(imm); \ + addi x4, x4, 1; \ + li x5, 2; \ + bne x4, x5, 1b \ + ) + +#define TEST_IMM_ZEROSRC1( testnum, inst, result, imm ) \ + TEST_CASE( testnum, x1, result, \ + inst x1, x0, SEXT_IMM(imm); \ + ) + +#define TEST_IMM_ZERODEST( testnum, inst, val1, imm ) \ + TEST_CASE( testnum, x0, 0, \ + li x1, val1; \ + inst x0, x1, SEXT_IMM(imm); \ + ) + +#----------------------------------------------------------------------- +# Tests for vector config instructions +#----------------------------------------------------------------------- + +#define TEST_VSETCFGIVL( testnum, nxpr, nfpr, bank, vl, result ) \ + TEST_CASE( testnum, x1, result, \ + li x1, (bank << 12); \ + vsetcfg x1,nxpr,nfpr; \ + li x1, vl; \ + vsetvl x1,x1; \ + ) + +#define TEST_VVCFG( testnum, nxpr, nfpr, bank, vl, result ) \ + TEST_CASE( testnum, x1, result, \ + li x1, (bank << 12) | (nfpr << 6) | nxpr; \ + vsetcfg x1; \ + li x1, vl; \ + vsetvl x1,x1; \ + ) + +#define TEST_VSETVL( testnum, nxpr, nfpr, bank, vl, result ) \ + TEST_CASE( testnum, x1, result, \ + li x1, (bank << 12); \ + vsetcfg x1,nxpr,nfpr; \ + li x1, vl; \ + vsetvl x1, x1; \ + ) + +#----------------------------------------------------------------------- +# Tests for an instruction with register operands +#----------------------------------------------------------------------- + +#define TEST_R_OP( testnum, inst, result, val1 ) \ + TEST_CASE( testnum, x3, result, \ + li x1, val1; \ + inst x3, x1; \ + ) + +#define TEST_R_SRC1_EQ_DEST( testnum, inst, result, val1 ) \ + TEST_CASE( testnum, x1, result, \ + li x1, val1; \ + inst x1, x1; \ + ) + +#define TEST_R_DEST_BYPASS( testnum, nop_cycles, inst, result, val1 ) \ + TEST_CASE( testnum, x6, result, \ + li x4, 0; \ +1: li x1, val1; \ + inst x3, x1; \ + TEST_INSERT_NOPS_ ## nop_cycles \ + addi x6, x3, 0; \ + addi x4, x4, 1; \ + li x5, 2; \ + bne x4, x5, 1b \ + ) + +#----------------------------------------------------------------------- +# Tests for an instruction with register-register operands +#----------------------------------------------------------------------- + +#define TEST_RR_OP( testnum, inst, result, val1, val2 ) \ + TEST_CASE( testnum, x3, result, \ + li x1, val1; \ + li x2, val2; \ + inst x3, x1, x2; \ + ) + +#define TEST_RR_SRC1_EQ_DEST( testnum, inst, result, val1, val2 ) \ + TEST_CASE( testnum, x1, result, \ + li x1, val1; \ + li x2, val2; \ + inst x1, x1, x2; \ + ) + +#define TEST_RR_SRC2_EQ_DEST( testnum, inst, result, val1, val2 ) \ + TEST_CASE( testnum, x2, result, \ + li x1, val1; \ + li x2, val2; \ + inst x2, x1, x2; \ + ) + +#define TEST_RR_SRC12_EQ_DEST( testnum, inst, result, val1 ) \ + TEST_CASE( testnum, x1, result, \ + li x1, val1; \ + inst x1, x1, x1; \ + ) + +#define TEST_RR_DEST_BYPASS( testnum, nop_cycles, inst, result, val1, val2 ) \ + TEST_CASE( testnum, x6, result, \ + li x4, 0; \ +1: li x1, val1; \ + li x2, val2; \ + inst x3, x1, x2; \ + TEST_INSERT_NOPS_ ## nop_cycles \ + addi x6, x3, 0; \ + addi x4, x4, 1; \ + li x5, 2; \ + bne x4, x5, 1b \ + ) + +#define TEST_RR_SRC12_BYPASS( testnum, src1_nops, src2_nops, inst, result, val1, val2 ) \ + TEST_CASE( testnum, x3, result, \ + li x4, 0; \ +1: li x1, val1; \ + TEST_INSERT_NOPS_ ## src1_nops \ + li x2, val2; \ + TEST_INSERT_NOPS_ ## src2_nops \ + inst x3, x1, x2; \ + addi x4, x4, 1; \ + li x5, 2; \ + bne x4, x5, 1b \ + ) + +#define TEST_RR_SRC21_BYPASS( testnum, src1_nops, src2_nops, inst, result, val1, val2 ) \ + TEST_CASE( testnum, x3, result, \ + li x4, 0; \ +1: li x2, val2; \ + TEST_INSERT_NOPS_ ## src1_nops \ + li x1, val1; \ + TEST_INSERT_NOPS_ ## src2_nops \ + inst x3, x1, x2; \ + addi x4, x4, 1; \ + li x5, 2; \ + bne x4, x5, 1b \ + ) + +#define TEST_RR_ZEROSRC1( testnum, inst, result, val ) \ + TEST_CASE( testnum, x2, result, \ + li x1, val; \ + inst x2, x0, x1; \ + ) + +#define TEST_RR_ZEROSRC2( testnum, inst, result, val ) \ + TEST_CASE( testnum, x2, result, \ + li x1, val; \ + inst x2, x1, x0; \ + ) + +#define TEST_RR_ZEROSRC12( testnum, inst, result ) \ + TEST_CASE( testnum, x1, result, \ + inst x1, x0, x0; \ + ) + +#define TEST_RR_ZERODEST( testnum, inst, val1, val2 ) \ + TEST_CASE( testnum, x0, 0, \ + li x1, val1; \ + li x2, val2; \ + inst x0, x1, x2; \ + ) + +#----------------------------------------------------------------------- +# Test memory instructions +#----------------------------------------------------------------------- + +#define TEST_LD_OP( testnum, inst, result, offset, base ) \ + TEST_CASE( testnum, x3, result, \ + la x1, base; \ + inst x3, offset(x1); \ + ) + +#define TEST_ST_OP( testnum, load_inst, store_inst, result, offset, base ) \ + TEST_CASE( testnum, x3, result, \ + la x1, base; \ + li x2, result; \ + store_inst x2, offset(x1); \ + load_inst x3, offset(x1); \ + ) + +#define TEST_LD_DEST_BYPASS( testnum, nop_cycles, inst, result, offset, base ) \ +test_ ## testnum: \ + li TESTNUM, testnum; \ + li x4, 0; \ +1: la x1, base; \ + inst x3, offset(x1); \ + TEST_INSERT_NOPS_ ## nop_cycles \ + addi x6, x3, 0; \ + li x29, result; \ + bne x6, x29, fail; \ + addi x4, x4, 1; \ + li x5, 2; \ + bne x4, x5, 1b; \ + +#define TEST_LD_SRC1_BYPASS( testnum, nop_cycles, inst, result, offset, base ) \ +test_ ## testnum: \ + li TESTNUM, testnum; \ + li x4, 0; \ +1: la x1, base; \ + TEST_INSERT_NOPS_ ## nop_cycles \ + inst x3, offset(x1); \ + li x29, result; \ + bne x3, x29, fail; \ + addi x4, x4, 1; \ + li x5, 2; \ + bne x4, x5, 1b \ + +#define TEST_ST_SRC12_BYPASS( testnum, src1_nops, src2_nops, load_inst, store_inst, result, offset, base ) \ +test_ ## testnum: \ + li TESTNUM, testnum; \ + li x4, 0; \ +1: la x1, result; \ + TEST_INSERT_NOPS_ ## src1_nops \ + la x2, base; \ + TEST_INSERT_NOPS_ ## src2_nops \ + store_inst x1, offset(x2); \ + load_inst x3, offset(x2); \ + li x29, result; \ + bne x3, x29, fail; \ + addi x4, x4, 1; \ + li x5, 2; \ + bne x4, x5, 1b \ + +#define TEST_ST_SRC21_BYPASS( testnum, src1_nops, src2_nops, load_inst, store_inst, result, offset, base ) \ +test_ ## testnum: \ + li TESTNUM, testnum; \ + li x4, 0; \ +1: la x2, base; \ + TEST_INSERT_NOPS_ ## src1_nops \ + la x1, result; \ + TEST_INSERT_NOPS_ ## src2_nops \ + store_inst x1, offset(x2); \ + load_inst x3, offset(x2); \ + li x29, result; \ + bne x3, x29, fail; \ + addi x4, x4, 1; \ + li x5, 2; \ + bne x4, x5, 1b \ + +#----------------------------------------------------------------------- +# Test branch instructions +#----------------------------------------------------------------------- + +#define TEST_BR1_OP_TAKEN( testnum, inst, val1 ) \ +test_ ## testnum: \ + li TESTNUM, testnum; \ + li x1, val1; \ + inst x1, 2f; \ + bne x0, TESTNUM, fail; \ +1: bne x0, TESTNUM, 3f; \ +2: inst x1, 1b; \ + bne x0, TESTNUM, fail; \ +3: + +#define TEST_BR1_OP_NOTTAKEN( testnum, inst, val1 ) \ +test_ ## testnum: \ + li TESTNUM, testnum; \ + li x1, val1; \ + inst x1, 1f; \ + bne x0, TESTNUM, 2f; \ +1: bne x0, TESTNUM, fail; \ +2: inst x1, 1b; \ +3: + +#define TEST_BR1_SRC1_BYPASS( testnum, nop_cycles, inst, val1 ) \ +test_ ## testnum: \ + li TESTNUM, testnum; \ + li x4, 0; \ +1: li x1, val1; \ + TEST_INSERT_NOPS_ ## nop_cycles \ + inst x1, fail; \ + addi x4, x4, 1; \ + li x5, 2; \ + bne x4, x5, 1b \ + +#define TEST_BR2_OP_TAKEN( testnum, inst, val1, val2 ) \ +test_ ## testnum: \ + li TESTNUM, testnum; \ + li x1, val1; \ + li x2, val2; \ + inst x1, x2, 2f; \ + bne x0, TESTNUM, fail; \ +1: bne x0, TESTNUM, 3f; \ +2: inst x1, x2, 1b; \ + bne x0, TESTNUM, fail; \ +3: + +#define TEST_BR2_OP_NOTTAKEN( testnum, inst, val1, val2 ) \ +test_ ## testnum: \ + li TESTNUM, testnum; \ + li x1, val1; \ + li x2, val2; \ + inst x1, x2, 1f; \ + bne x0, TESTNUM, 2f; \ +1: bne x0, TESTNUM, fail; \ +2: inst x1, x2, 1b; \ +3: + +#define TEST_BR2_SRC12_BYPASS( testnum, src1_nops, src2_nops, inst, val1, val2 ) \ +test_ ## testnum: \ + li TESTNUM, testnum; \ + li x4, 0; \ +1: li x1, val1; \ + TEST_INSERT_NOPS_ ## src1_nops \ + li x2, val2; \ + TEST_INSERT_NOPS_ ## src2_nops \ + inst x1, x2, fail; \ + addi x4, x4, 1; \ + li x5, 2; \ + bne x4, x5, 1b \ + +#define TEST_BR2_SRC21_BYPASS( testnum, src1_nops, src2_nops, inst, val1, val2 ) \ +test_ ## testnum: \ + li TESTNUM, testnum; \ + li x4, 0; \ +1: li x2, val2; \ + TEST_INSERT_NOPS_ ## src1_nops \ + li x1, val1; \ + TEST_INSERT_NOPS_ ## src2_nops \ + inst x1, x2, fail; \ + addi x4, x4, 1; \ + li x5, 2; \ + bne x4, x5, 1b \ + +#----------------------------------------------------------------------- +# Test jump instructions +#----------------------------------------------------------------------- + +#define TEST_JR_SRC1_BYPASS( testnum, nop_cycles, inst ) \ +test_ ## testnum: \ + li TESTNUM, testnum; \ + li x4, 0; \ +1: la x6, 2f; \ + TEST_INSERT_NOPS_ ## nop_cycles \ + inst x6; \ + bne x0, TESTNUM, fail; \ +2: addi x4, x4, 1; \ + li x5, 2; \ + bne x4, x5, 1b \ + +#define TEST_JALR_SRC1_BYPASS( testnum, nop_cycles, inst ) \ +test_ ## testnum: \ + li TESTNUM, testnum; \ + li x4, 0; \ +1: la x6, 2f; \ + TEST_INSERT_NOPS_ ## nop_cycles \ + inst x19, x6, 0; \ + bne x0, TESTNUM, fail; \ +2: addi x4, x4, 1; \ + li x5, 2; \ + bne x4, x5, 1b \ + + +#----------------------------------------------------------------------- +# RV64UF MACROS +#----------------------------------------------------------------------- + +#----------------------------------------------------------------------- +# Tests floating-point instructions +#----------------------------------------------------------------------- + +#define TEST_FP_OP_S_INTERNAL( testnum, flags, result, val1, val2, val3, code... ) \ +test_ ## testnum: \ + li TESTNUM, testnum; \ + la a0, test_ ## testnum ## _data ;\ + flw f0, 0(a0); \ + flw f1, 4(a0); \ + flw f2, 8(a0); \ + lw a3, 12(a0); \ + code; \ + fsflags a1, x0; \ + li a2, flags; \ + bne a0, a3, fail; \ + bne a1, a2, fail; \ + j 2f; \ + .align 2; \ + .data; \ + test_ ## testnum ## _data: \ + .float val1; \ + .float val2; \ + .float val3; \ + .result; \ + .text; \ +2: + +#define TEST_FP_OP_D_INTERNAL( testnum, flags, result, val1, val2, val3, code... ) \ +test_ ## testnum: \ + li TESTNUM, testnum; \ + la a0, test_ ## testnum ## _data ;\ + fld f0, 0(a0); \ + fld f1, 8(a0); \ + fld f2, 16(a0); \ + ld a3, 24(a0); \ + code; \ + fsflags a1, x0; \ + li a2, flags; \ + bne a0, a3, fail; \ + bne a1, a2, fail; \ + j 2f; \ + .data; \ + .align 3; \ + test_ ## testnum ## _data: \ + .double val1; \ + .double val2; \ + .double val3; \ + .result; \ + .text; \ +2: + +#define TEST_FCVT_S_D( testnum, result, val1 ) \ + TEST_FP_OP_D_INTERNAL( testnum, 0, double result, val1, 0.0, 0.0, \ + fcvt.s.d f3, f0; fcvt.d.s f3, f3; fmv.x.d a0, f3) + +#define TEST_FCVT_D_S( testnum, result, val1 ) \ + TEST_FP_OP_S_INTERNAL( testnum, 0, float result, val1, 0.0, 0.0, \ + fcvt.d.s f3, f0; fcvt.s.d f3, f3; fmv.x.s a0, f3) + +#define TEST_FP_OP1_S( testnum, inst, result, val1 ) \ + TEST_FP_OP_S_INTERNAL( testnum, 0, float result, val1, 0.0, 0.0, \ + inst f3, f0; fmv.x.s a0, f3) + +#define TEST_FP_OP1_D( testnum, inst, result, val1 ) \ + TEST_FP_OP_D_INTERNAL( testnum, 0, double result, val1, 0.0, 0.0, \ + inst f3, f0; fmv.x.d a0, f3) + +#define TEST_FP_OP2_S( testnum, inst, flags, result, val1, val2 ) \ + TEST_FP_OP_S_INTERNAL( testnum, flags, float result, val1, val2, 0.0, \ + inst f3, f0, f1; fmv.x.s a0, f3) + +#define TEST_FP_OP2_D( testnum, inst, flags, result, val1, val2 ) \ + TEST_FP_OP_D_INTERNAL( testnum, flags, double result, val1, val2, 0.0, \ + inst f3, f0, f1; fmv.x.d a0, f3) + +#define TEST_FP_OP3_S( testnum, inst, flags, result, val1, val2, val3 ) \ + TEST_FP_OP_S_INTERNAL( testnum, flags, float result, val1, val2, val3, \ + inst f3, f0, f1, f2; fmv.x.s a0, f3) + +#define TEST_FP_OP3_D( testnum, inst, flags, result, val1, val2, val3 ) \ + TEST_FP_OP_D_INTERNAL( testnum, flags, double result, val1, val2, val3, \ + inst f3, f0, f1, f2; fmv.x.d a0, f3) + +#define TEST_FP_INT_OP_S( testnum, inst, flags, result, val1, rm ) \ + TEST_FP_OP_S_INTERNAL( testnum, flags, word result, val1, 0.0, 0.0, \ + inst a0, f0, rm) + +#define TEST_FP_INT_OP_D( testnum, inst, flags, result, val1, rm ) \ + TEST_FP_OP_D_INTERNAL( testnum, flags, dword result, val1, 0.0, 0.0, \ + inst a0, f0, rm) + +#define TEST_FP_CMP_OP_S( testnum, inst, result, val1, val2 ) \ + TEST_FP_OP_S_INTERNAL( testnum, 0, word result, val1, val2, 0.0, \ + inst a0, f0, f1) + +#define TEST_FP_CMP_OP_D( testnum, inst, result, val1, val2 ) \ + TEST_FP_OP_D_INTERNAL( testnum, 0, dword result, val1, val2, 0.0, \ + inst a0, f0, f1) + +#define TEST_INT_FP_OP_S( testnum, inst, result, val1 ) \ +test_ ## testnum: \ + li TESTNUM, testnum; \ + la a0, test_ ## testnum ## _data ;\ + lw a3, 0(a0); \ + li a0, val1; \ + inst f0, a0; \ + fsflags x0; \ + fmv.x.s a0, f0; \ + bne a0, a3, fail; \ + j 1f; \ + .align 2; \ + test_ ## testnum ## _data: \ + .float result; \ +1: + +#define TEST_INT_FP_OP_D( testnum, inst, result, val1 ) \ +test_ ## testnum: \ + li TESTNUM, testnum; \ + la a0, test_ ## testnum ## _data ;\ + ld a3, 0(a0); \ + li a0, val1; \ + inst f0, a0; \ + fsflags x0; \ + fmv.x.d a0, f0; \ + bne a0, a3, fail; \ + j 1f; \ + .align 3; \ + test_ ## testnum ## _data: \ + .double result; \ +1: + + +#----------------------------------------------------------------------- +# RV64SV MACROS +#----------------------------------------------------------------------- + +#define TEST_ILLEGAL_TVEC_REGID( testnum, nxreg, nfreg, inst, reg1, reg2) \ + csrs status, SR_EI; \ + la a0, handler ## testnum; \ + csrw evec, a0; \ + vsetcfg nxreg, nfreg; \ + li a0, 4; \ + vsetvl a0, a0; \ + la a0, src1; \ + la a1, src2; \ + vld vx2, a0; \ + vld vx3, a1; \ + lui a0,%hi(vtcode1 ## testnum); \ + vf %lo(vtcode1 ## testnum)(a0); \ + la reg2, dest; \ +illegal ## testnum: \ + inst reg1, reg2; \ + la a3, dest; \ + vsd vx2, a3; \ + fence; \ +vtcode1 ## testnum: \ + add x2, x2, x3; \ + stop; \ +vtcode2 ## testnum: \ + add x2, x2, x3; \ + stop; \ +handler ## testnum: \ + vxcptkill; \ + li TESTNUM,2; \ + vxcptcause a0; \ + li a1,HWACHA_CAUSE_TVEC_ILLEGAL_REGID; \ + bne a0,a1,fail; \ + vxcptaux a0; \ + la a1, illegal ## testnum; \ + lw a2, 0(a1); \ + bne a0, a2, fail; \ + vsetcfg 32,0; \ + li a0,4; \ + vsetvl a0,a0; \ + la a0,src1; \ + la a1,src2; \ + vld vx2,a0; \ + vld vx3,a1; \ + lui a0,%hi(vtcode2 ## testnum); \ + vf %lo(vtcode2 ## testnum)(a0); \ + la a3,dest; \ + vsd vx2,a3; \ + fence; \ + ld a1,0(a3); \ + li a2,5; \ + li TESTNUM,2; \ + bne a1,a2,fail; \ + ld a1,8(a3); \ + li TESTNUM,3; \ + bne a1,a2,fail; \ + ld a1,16(a3); \ + li TESTNUM,4; \ + bne a1,a2,fail; \ + ld a1,24(a3); \ + li TESTNUM,5; \ + bne a1,a2,fail; \ + +#define TEST_ILLEGAL_VT_REGID( testnum, nxreg, nfreg, inst, reg1, reg2, reg3) \ + csrs status, SR_EI; \ + la a0, handler ## testnum; \ + csrw evec, a0; \ + vsetcfg nxreg, nfreg; \ + li a0, 4; \ + vsetvl a0, a0; \ + la a0, src1; \ + la a1, src2; \ + vld vx2, a0; \ + vld vx3, a1; \ + lui a0,%hi(vtcode1 ## testnum); \ + vf %lo(vtcode1 ## testnum)(a0); \ + la a3, dest; \ + vsd vx2, a3; \ + fence; \ +vtcode1 ## testnum: \ + add x2, x2, x3; \ +illegal ## testnum: \ + inst reg1, reg2, reg3; \ + stop; \ +vtcode2 ## testnum: \ + add x2, x2, x3; \ + stop; \ +handler ## testnum: \ + vxcptkill; \ + li TESTNUM,2; \ + vxcptcause a0; \ + li a1,HWACHA_CAUSE_VF_ILLEGAL_REGID; \ + bne a0,a1,fail; \ + vxcptaux a0; \ + la a1,illegal ## testnum; \ + bne a0,a1,fail; \ + vsetcfg 32,0; \ + li a0,4; \ + vsetvl a0,a0; \ + la a0,src1; \ + la a1,src2; \ + vld vx2,a0; \ + vld vx3,a1; \ + lui a0,%hi(vtcode2 ## testnum); \ + vf %lo(vtcode2 ## testnum)(a0); \ + la a3,dest; \ + vsd vx2,a3; \ + fence; \ + ld a1,0(a3); \ + li a2,5; \ + li TESTNUM,2; \ + bne a1,a2,fail; \ + ld a1,8(a3); \ + li TESTNUM,3; \ + bne a1,a2,fail; \ + ld a1,16(a3); \ + li TESTNUM,4; \ + bne a1,a2,fail; \ + ld a1,24(a3); \ + li TESTNUM,5; \ + bne a1,a2,fail; \ + +#----------------------------------------------------------------------- +# Pass and fail code (assumes test num is in TESTNUM) +#----------------------------------------------------------------------- + +#define TEST_PASSFAIL \ + bne x0, TESTNUM, pass; \ +fail: \ + RVTEST_FAIL \ +pass: \ + RVTEST_PASS \ + + +#----------------------------------------------------------------------- +# Test data section +#----------------------------------------------------------------------- + +#define TEST_DATA + +#endif Index: v0.1/riscv-tests/xor.S =================================================================== --- v0.1/riscv-tests/xor.S (nonexistent) +++ v0.1/riscv-tests/xor.S (revision 47) @@ -0,0 +1,69 @@ +# See LICENSE for license details. + +#***************************************************************************** +# xor.S +#----------------------------------------------------------------------------- +# +# Test xor instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + #------------------------------------------------------------- + # Logical tests + #------------------------------------------------------------- + + TEST_RR_OP( 2, xor, 0xf00ff00f, 0xff00ff00, 0x0f0f0f0f ); + TEST_RR_OP( 3, xor, 0xff00ff00, 0x0ff00ff0, 0xf0f0f0f0 ); + TEST_RR_OP( 4, xor, 0x0ff00ff0, 0x00ff00ff, 0x0f0f0f0f ); + TEST_RR_OP( 5, xor, 0x00ff00ff, 0xf00ff00f, 0xf0f0f0f0 ); + + #------------------------------------------------------------- + # Source/Destination tests + #------------------------------------------------------------- + + TEST_RR_SRC1_EQ_DEST( 6, xor, 0xf00ff00f, 0xff00ff00, 0x0f0f0f0f ); + TEST_RR_SRC2_EQ_DEST( 7, xor, 0xf00ff00f, 0xff00ff00, 0x0f0f0f0f ); + TEST_RR_SRC12_EQ_DEST( 8, xor, 0x00000000, 0xff00ff00 ); + + #------------------------------------------------------------- + # Bypassing tests + #------------------------------------------------------------- + + TEST_RR_DEST_BYPASS( 9, 0, xor, 0xf00ff00f, 0xff00ff00, 0x0f0f0f0f ); + TEST_RR_DEST_BYPASS( 10, 1, xor, 0xff00ff00, 0x0ff00ff0, 0xf0f0f0f0 ); + TEST_RR_DEST_BYPASS( 11, 2, xor, 0x0ff00ff0, 0x00ff00ff, 0x0f0f0f0f ); + + TEST_RR_SRC12_BYPASS( 12, 0, 0, xor, 0xf00ff00f, 0xff00ff00, 0x0f0f0f0f ); + TEST_RR_SRC12_BYPASS( 13, 0, 1, xor, 0xff00ff00, 0x0ff00ff0, 0xf0f0f0f0 ); + TEST_RR_SRC12_BYPASS( 14, 0, 2, xor, 0x0ff00ff0, 0x00ff00ff, 0x0f0f0f0f ); + TEST_RR_SRC12_BYPASS( 15, 1, 0, xor, 0xf00ff00f, 0xff00ff00, 0x0f0f0f0f ); + TEST_RR_SRC12_BYPASS( 16, 1, 1, xor, 0xff00ff00, 0x0ff00ff0, 0xf0f0f0f0 ); + TEST_RR_SRC12_BYPASS( 17, 2, 0, xor, 0x0ff00ff0, 0x00ff00ff, 0x0f0f0f0f ); + + TEST_RR_SRC21_BYPASS( 18, 0, 0, xor, 0xf00ff00f, 0xff00ff00, 0x0f0f0f0f ); + TEST_RR_SRC21_BYPASS( 19, 0, 1, xor, 0xff00ff00, 0x0ff00ff0, 0xf0f0f0f0 ); + TEST_RR_SRC21_BYPASS( 20, 0, 2, xor, 0x0ff00ff0, 0x00ff00ff, 0x0f0f0f0f ); + TEST_RR_SRC21_BYPASS( 21, 1, 0, xor, 0xf00ff00f, 0xff00ff00, 0x0f0f0f0f ); + TEST_RR_SRC21_BYPASS( 22, 1, 1, xor, 0xff00ff00, 0x0ff00ff0, 0xf0f0f0f0 ); + TEST_RR_SRC21_BYPASS( 23, 2, 0, xor, 0x0ff00ff0, 0x00ff00ff, 0x0f0f0f0f ); + + TEST_RR_ZEROSRC1( 24, xor, 0xff00ff00, 0xff00ff00 ); + TEST_RR_ZEROSRC2( 25, xor, 0x00ff00ff, 0x00ff00ff ); + TEST_RR_ZEROSRC12( 26, xor, 0 ); + TEST_RR_ZERODEST( 27, xor, 0x11111111, 0x22222222 ); + + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +RVTEST_DATA_END Index: v0.1/riscv-tests/sh.S =================================================================== --- v0.1/riscv-tests/sh.S (nonexistent) +++ v0.1/riscv-tests/sh.S (revision 47) @@ -0,0 +1,102 @@ +# See LICENSE for license details. + +#***************************************************************************** +# sh.S +#----------------------------------------------------------------------------- +# +# Test sh instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + #------------------------------------------------------------- + # Basic tests + #------------------------------------------------------------- + + TEST_ST_OP( 2, lh, sh, 0x000000aa, 0, tdat ); + TEST_ST_OP( 3, lh, sh, 0xffffaa00, 2, tdat ); +#ifdef __RISCVEL + TEST_ST_OP( 4, lw, sh, 0xbeef0aa0, 4, tdat ); +#elif defined(__RISCVEB) +#else + TEST_ST_OP( 4, lw, sh, 0x0aa0beef, 4, tdat ); +#error unknown endianness! +#endif + TEST_ST_OP( 5, lh, sh, 0xffffa00a, 6, tdat ); + + # Test with negative offset + + TEST_ST_OP( 6, lh, sh, 0x000000aa, -6, tdat8 ); + TEST_ST_OP( 7, lh, sh, 0xffffaa00, -4, tdat8 ); + TEST_ST_OP( 8, lh, sh, 0x00000aa0, -2, tdat8 ); + TEST_ST_OP( 9, lh, sh, 0xffffa00a, 0, tdat8 ); + + # Test with a negative base + + TEST_CASE( 10, x3, 0x5678, \ + la x1, tdat9; \ + li x2, 0x12345678; \ + addi x4, x1, -32; \ + sh x2, 32(x4); \ + lh x3, 0(x1); \ + ) + + # Test with unaligned base + + TEST_CASE( 11, x3, 0x3098, \ + la x1, tdat9; \ + li x2, 0x00003098; \ + addi x1, x1, -5; \ + sh x2, 7(x1); \ + la x4, tdat10; \ + lh x3, 0(x4); \ + ) + + #------------------------------------------------------------- + # Bypassing tests + #------------------------------------------------------------- + + TEST_ST_SRC12_BYPASS( 12, 0, 0, lh, sh, 0xffffccdd, 0, tdat ); + TEST_ST_SRC12_BYPASS( 13, 0, 1, lh, sh, 0xffffbccd, 2, tdat ); + TEST_ST_SRC12_BYPASS( 14, 0, 2, lh, sh, 0xffffbbcc, 4, tdat ); + TEST_ST_SRC12_BYPASS( 15, 1, 0, lh, sh, 0xffffabbc, 6, tdat ); + TEST_ST_SRC12_BYPASS( 16, 1, 1, lh, sh, 0xffffaabb, 8, tdat ); + TEST_ST_SRC12_BYPASS( 17, 2, 0, lh, sh, 0xffffdaab, 10, tdat ); + + TEST_ST_SRC21_BYPASS( 18, 0, 0, lh, sh, 0x2233, 0, tdat ); + TEST_ST_SRC21_BYPASS( 19, 0, 1, lh, sh, 0x1223, 2, tdat ); + TEST_ST_SRC21_BYPASS( 20, 0, 2, lh, sh, 0x1122, 4, tdat ); + TEST_ST_SRC21_BYPASS( 21, 1, 0, lh, sh, 0x0112, 6, tdat ); + TEST_ST_SRC21_BYPASS( 22, 1, 1, lh, sh, 0x0011, 8, tdat ); + TEST_ST_SRC21_BYPASS( 23, 2, 0, lh, sh, 0x3001, 10, tdat ); + + li a0, 0xbeef + la a1, tdat + sh a0, 6(a1) + + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +tdat: +tdat1: .half 0xbeef +tdat2: .half 0xbeef +tdat3: .half 0xbeef +tdat4: .half 0xbeef +tdat5: .half 0xbeef +tdat6: .half 0xbeef +tdat7: .half 0xbeef +tdat8: .half 0xbeef +tdat9: .half 0xbeef +tdat10: .half 0xbeef + +RVTEST_DATA_END Index: v0.1/riscv-tests/andi.S =================================================================== --- v0.1/riscv-tests/andi.S (nonexistent) +++ v0.1/riscv-tests/andi.S (revision 47) @@ -0,0 +1,55 @@ +# See LICENSE for license details. + +#***************************************************************************** +# andi.S +#----------------------------------------------------------------------------- +# +# Test andi instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + #------------------------------------------------------------- + # Logical tests + #------------------------------------------------------------- + + TEST_IMM_OP( 2, andi, 0xff00ff00, 0xff00ff00, 0xf0f ); + TEST_IMM_OP( 3, andi, 0x000000f0, 0x0ff00ff0, 0x0f0 ); + TEST_IMM_OP( 4, andi, 0x0000000f, 0x00ff00ff, 0x70f ); + TEST_IMM_OP( 5, andi, 0x00000000, 0xf00ff00f, 0x0f0 ); + + #------------------------------------------------------------- + # Source/Destination tests + #------------------------------------------------------------- + + TEST_IMM_SRC1_EQ_DEST( 6, andi, 0x00000000, 0xff00ff00, 0x0f0 ); + + #------------------------------------------------------------- + # Bypassing tests + #------------------------------------------------------------- + + TEST_IMM_DEST_BYPASS( 7, 0, andi, 0x00000700, 0x0ff00ff0, 0x70f ); + TEST_IMM_DEST_BYPASS( 8, 1, andi, 0x000000f0, 0x00ff00ff, 0x0f0 ); + TEST_IMM_DEST_BYPASS( 9, 2, andi, 0xf00ff00f, 0xf00ff00f, 0xf0f ); + + TEST_IMM_SRC1_BYPASS( 10, 0, andi, 0x00000700, 0x0ff00ff0, 0x70f ); + TEST_IMM_SRC1_BYPASS( 11, 1, andi, 0x000000f0, 0x00ff00ff, 0x0f0 ); + TEST_IMM_SRC1_BYPASS( 12, 2, andi, 0x0000000f, 0xf00ff00f, 0x70f ); + + TEST_IMM_ZEROSRC1( 13, andi, 0, 0x0f0 ); + TEST_IMM_ZERODEST( 14, andi, 0x00ff00ff, 0x70f ); + + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +RVTEST_DATA_END Index: v0.1/README =================================================================== --- v0.1/README (nonexistent) +++ v0.1/README (revision 47) @@ -0,0 +1,43 @@ +# 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: v0.1/LICENSE =================================================================== --- v0.1/LICENSE (nonexistent) +++ v0.1/LICENSE (revision 47) @@ -0,0 +1,12 @@ +Copyright (c) 2015, Kristian Klomsten Skordal +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Index: v0.1/tests.ld =================================================================== --- v0.1/tests.ld (nonexistent) +++ v0.1/tests.ld (revision 47) @@ -0,0 +1,38 @@ +/* + * Linker Script for the Potato Processor test applications. + * (c) Kristian Klomsten Skordal 2014 - 2015 + * Report bugs and issues on + */ + +/* + * 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; +} + Index: v0.1/scripts/extract_hex.sh =================================================================== --- v0.1/scripts/extract_hex.sh (nonexistent) +++ v0.1/scripts/extract_hex.sh (revision 47) @@ -0,0 +1,25 @@ +#!/bin/bash +# The Potato Processor - A simple processor for FPGAs +# (c) Kristian Klomsten Skordal 2014 - 2015 +# Report bugs and issues on + +# 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 " + 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 +
v0.1/scripts/extract_hex.sh Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: v0.1/empty_dmem.hex =================================================================== --- v0.1/empty_dmem.hex (nonexistent) +++ v0.1/empty_dmem.hex (revision 47) @@ -0,0 +1 @@ +00000000 Index: v0.1 =================================================================== --- v0.1 (nonexistent) +++ v0.1 (revision 47)
v0.1 Property changes : Added: svn:mergeinfo ## -0,0 +0,1 ## Merged /potato/branches/cache-playground:r23-44

powered by: WebSVN 2.1.0

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