Initial commit. Tested on ArtyS7-RPU-SoC and passes SD bootloader and DDR3 memory testing.

This commit is contained in:
Colin Riley 2018-09-11 23:53:41 +01:00
parent 84a652b41c
commit 439781c194
12 changed files with 1526 additions and 0 deletions

View file

@ -1,2 +1,10 @@
# RPU
Basic RISC-V CPU implementation in VHDL.
This is a RV32I ISA CPU implementation, based off of my TPU CPU design. It is very simple, is missing several features, but can run rv32i-compiled GCC toolchain binaries at over 200MHz on a Digilent Arty S7-50 board, built with Xilinx Spartan 7 tools.
Implementation detail is written about via blogs available at http://labs.domipheus.com/blog/designing-a-cpu-in-vhdl-part-15-introducing-rpu/
The tests in the repo are incredibly old and basic, and included only as a baseline to help. They will be expanded upon in time.
Please let me know if you are using any of the RPU design in your own projects! I am contactable on twitter @domipheus.

BIN
rpu_core_diagram.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

View file

@ -0,0 +1,155 @@
--------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 16:43:32 12/10/2016
-- Design Name:
-- Module Name: C:/Users/colin/Desktop/riscy/ise/tb_unit_alu_RV32I_01.vhd
-- Project Name: riscv32_v1
-- Target Device:
-- Tool versions:
-- Description:
--
-- VHDL Test Bench Created by ISE for module: alu_RV32I
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
-- Notes:
-- This testbench has been automatically generated using types std_logic and
-- std_logic_vector for the ports of the unit under test. Xilinx recommends
-- that these types always be used for the top-level I/O of a design in order
-- to guarantee that the testbench will bind correctly to the post-implementation
-- simulation model.
--------------------------------------------------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
use work.constants.all;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--USE ieee.numeric_std.ALL;
ENTITY tb_unit_alu_RV32I_01 IS
END tb_unit_alu_RV32I_01;
ARCHITECTURE behavior OF tb_unit_alu_RV32I_01 IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT alu_RV32I
PORT(
I_clk : IN std_logic;
I_en : IN std_logic;
I_dataA : IN std_logic_vector(31 downto 0);
I_dataB : IN std_logic_vector(31 downto 0);
I_dataDwe : IN std_logic;
I_aluop : IN std_logic_vector(4 downto 0);
I_aluFunc : IN std_logic_vector(15 downto 0);
I_PC : IN std_logic_vector(31 downto 0);
I_dataIMM : IN std_logic_vector(31 downto 0);
O_dataResult : OUT std_logic_vector(31 downto 0);
O_branchTarget : OUT std_logic_vector(31 downto 0);
O_dataWriteReg : OUT std_logic;
O_shouldBranch : OUT std_logic
);
END COMPONENT;
--Inputs
signal I_clk : std_logic := '0';
signal I_en : std_logic := '0';
signal I_dataA : std_logic_vector(31 downto 0) := (others => '0');
signal I_dataB : std_logic_vector(31 downto 0) := (others => '0');
signal I_dataDwe : std_logic := '0';
signal I_aluop : std_logic_vector(4 downto 0) := (others => '0');
signal I_aluFunc : std_logic_vector(15 downto 0) := (others => '0');
signal I_PC : std_logic_vector(31 downto 0) := (others => '0');
signal I_dataIMM : std_logic_vector(31 downto 0) := (others => '0');
--Outputs
signal O_dataResult : std_logic_vector(31 downto 0);
signal O_branchTarget : std_logic_vector(31 downto 0);
signal O_dataWriteReg : std_logic := '0';
signal O_shouldBranch : std_logic := '0';
-- Clock period definitions
constant I_clk_period : time := 10 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: alu_RV32I PORT MAP (
I_clk => I_clk,
I_en => I_en,
I_dataA => I_dataA,
I_dataB => I_dataB,
I_dataDwe => I_dataDwe,
I_aluop => I_aluop,
I_aluFunc => I_aluFunc,
I_PC => I_PC,
I_dataIMM => I_dataIMM,
O_dataResult => O_dataResult,
O_branchTarget => O_branchTarget,
O_dataWriteReg => O_dataWriteReg,
O_shouldBranch => O_shouldBranch
);
-- Clock process definitions
I_clk_process :process
begin
I_clk <= '0';
wait for I_clk_period/2;
I_clk <= '1';
wait for I_clk_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ns.
wait for 100 ns;
wait for I_clk_period*10;
-- insert stimulus here
I_dataA <= X"00001000";
I_dataB <= X"01A01001";
I_aluOp <= OPCODE_OP;
I_aluFunc <= "000000" & F7_OP_ADD & F3_OP_ADD;
I_dataImm <= X"00000000";
I_PC <= X"A0000000";
I_dataDwe <= '1';
I_en <= '1';
wait for I_clk_period*2;
I_dataA <= X"00000001";
I_dataB <= X"00000006";
I_aluOp <= OPCODE_OP;
I_aluFunc <= "000000" & F7_OP_ADD & F3_OP_ADD;
I_dataImm <= X"00000000";
I_PC <= X"A0000004";
I_dataDwe <= '1';
I_en <= '1';
wait for I_clk_period*2;
I_dataA <= X"00346A00";
I_dataB <= X"120000B6";
I_aluOp <= OPCODE_OP;
I_aluFunc <= "000000" & F7_OP_OR & F3_OP_OR;
I_dataImm <= X"00000000";
I_PC <= X"A0000008";
I_dataDwe <= '1';
I_en <= '1';
wait;
end process;
END;

View file

@ -0,0 +1,136 @@
--------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 22:43:26 12/08/2016
-- Design Name:
-- Module Name: C:/Users/colin/Desktop/riscy/ise/tb_unit_decoder_RV32_01.vhd
-- Project Name: riscv32_v1
-- Target Device:
-- Tool versions:
-- Description:
--
-- VHDL Test Bench Created by ISE for module: decoder_RV32
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
-- Notes:
-- This testbench has been automatically generated using types std_logic and
-- std_logic_vector for the ports of the unit under test. Xilinx recommends
-- that these types always be used for the top-level I/O of a design in order
-- to guarantee that the testbench will bind correctly to the post-implementation
-- simulation model.
--------------------------------------------------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--USE ieee.numeric_std.ALL;
ENTITY tb_unit_decoder_RV32_01 IS
END tb_unit_decoder_RV32_01;
ARCHITECTURE behavior OF tb_unit_decoder_RV32_01 IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT decoder_RV32
PORT(
I_clk : IN std_logic;
I_en : IN std_logic;
I_dataInst : IN std_logic_vector(31 downto 0);
O_selRS1 : OUT std_logic_vector(4 downto 0);
O_selRS2 : OUT std_logic_vector(4 downto 0);
O_selD : OUT std_logic_vector(4 downto 0);
O_dataIMM : OUT std_logic_vector(31 downto 0);
O_regDwe : OUT std_logic;
O_aluOp : OUT std_logic_vector(6 downto 0);
O_aluFunc : OUT std_logic_vector(15 downto 0); -- ALU function
O_memOp : out STD_LOGIC_VECTOR(4 downto 0)
);
END COMPONENT;
--Inputs
signal I_clk : std_logic := '0';
signal I_en : std_logic := '0';
signal I_dataInst : std_logic_vector(31 downto 0) := (others => '0');
--Outputs
signal O_selRS1 : std_logic_vector(4 downto 0);
signal O_selRS2 : std_logic_vector(4 downto 0);
signal O_selD : std_logic_vector(4 downto 0);
signal O_dataIMM : std_logic_vector(31 downto 0);
signal O_regDwe : std_logic;
signal O_aluOp : std_logic_vector(6 downto 0);
signal O_aluFunc : std_logic_vector(15 downto 0);
signal O_memOp : STD_LOGIC_VECTOR(4 downto 0);
-- Clock period definitions
constant I_clk_period : time := 10 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: decoder_RV32 PORT MAP (
I_clk => I_clk,
I_en => I_en,
I_dataInst => I_dataInst,
O_selRS1 => O_selRS1,
O_selRS2 => O_selRS2,
O_selD => O_selD,
O_dataIMM => O_dataIMM,
O_regDwe => O_regDwe,
O_aluOp => O_aluOp,
O_aluFunc => O_aluFunc,
O_memOp => O_memOp
);
-- Clock process definitions
I_clk_process :process
begin
I_clk <= '0';
wait for I_clk_period/2;
I_clk <= '1';
wait for I_clk_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ns.
wait for 100 ns;
wait for I_clk_period*10;
-- insert stimulus here
I_dataInst <= "0000000" & "00001" & "00010" & "000" & "01001" & "0110011";
I_en <= '1';
wait for I_clk_period*2;
I_dataInst <= "000000000001" & "00010" & "000" & "01001" & "0010011";
I_en <= '1';
wait for I_clk_period*2;
I_dataInst <= "100000000001" & "00010" & "000" & "01001" & "0010011";
I_en <= '1';
wait for I_clk_period*2;
I_dataInst <= "100001000001" & "00000" & "010" & "00001" & "0000011";
I_en <= '1';
wait for I_clk_period*2;
wait;
end process;
END;

158
vhdl/constants.vhd Normal file
View file

@ -0,0 +1,158 @@
----------------------------------------------------------------------------------
-- Project Name: RISC-V CPU
-- Description: Constants for instruction forms, opcodes, conditional flags, etc.
--
-- Revision: 1
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.all;
package constants is
constant XLEN: integer := 32;
constant XLENM1: integer := XLEN - 1;
constant XLEN32: integer:= 32;
constant XLEN32M1: integer:= XLEN32 -1;
constant BWIDTH: integer:= 32;
constant BWIDTHM1: integer:= BWIDTH -1;
constant ADDR_RESET: std_logic_vector(XLEN32M1 downto 0) := X"00000000";
constant ADDR_INTVEC: std_logic_vector(XLEN32M1 downto 0) := X"00000100";
-- PC unit opcodes
constant PCU_OP_NOP: std_logic_vector(1 downto 0):= "00";
constant PCU_OP_INC: std_logic_vector(1 downto 0):= "01";
constant PCU_OP_ASSIGN: std_logic_vector(1 downto 0):= "10";
constant PCU_OP_RESET: std_logic_vector(1 downto 0):= "11";
-- Instruction Form Offsets
constant OPCODE_START: integer := 6;
constant OPCODE_END: integer := 0;
constant OPCODE_END_2: integer := 2;
constant RD_START: integer := 11;
constant RD_END: integer := 7;
constant FUNCT3_START: integer := 14;
constant FUNCT3_END: integer := 12;
constant R1_START: integer := 19;
constant R1_END: integer := 15;
constant R2_START: integer := 24;
constant R2_END: integer := 20;
constant FUNCT7_START: integer := 31;
constant FUNCT7_END: integer := 25;
constant IMM_I_START: integer := 31;
constant IMM_I_END: integer := 20;
constant IMM_U_START: integer := 31;
constant IMM_U_END: integer := 12;
constant IMM_S_A_START: integer := 31;
constant IMM_S_A_END: integer := 25;
constant IMM_S_B_START: integer := 11;
constant IMM_S_B_END: integer := 7;
-- Opcodes
constant OPCODE_LOAD: std_logic_vector(4 downto 0) := "00000";
constant OPCODE_STORE: std_logic_vector(4 downto 0) := "01000";
constant OPCODE_MADD: std_logic_vector(4 downto 0) := "10000";
constant OPCODE_BRANCH: std_logic_vector(4 downto 0) := "11000";
constant OPCODE_JALR: std_logic_vector(4 downto 0) := "11001";
constant OPCODE_JAL: std_logic_vector(4 downto 0) := "11011";
constant OPCODE_SYSTEM: std_logic_vector(4 downto 0) := "11100";
constant OPCODE_OP: std_logic_vector(4 downto 0) := "01100";
constant OPCODE_OPIMM: std_logic_vector(4 downto 0) := "00100";
constant OPCODE_MISCMEM: std_logic_vector(4 downto 0) := "00011";
constant OPCODE_AUIPC: std_logic_vector(4 downto 0) := "00101";
constant OPCODE_LUI: std_logic_vector(4 downto 0) := "01101";
-- Flags
constant F3_BRANCH_BEQ: std_logic_vector(2 downto 0) := "000";
constant F3_BRANCH_BNE: std_logic_vector(2 downto 0) := "001";
constant F3_BRANCH_BLT: std_logic_vector(2 downto 0) := "100";
constant F3_BRANCH_BGE: std_logic_vector(2 downto 0) := "101";
constant F3_BRANCH_BLTU: std_logic_vector(2 downto 0) := "110";
constant F3_BRANCH_BGEU: std_logic_vector(2 downto 0) := "111";
constant F3_JALR: std_logic_vector(2 downto 0) := "000";
constant F3_LOAD_LB: std_logic_vector(2 downto 0) := "000";
constant F3_LOAD_LH: std_logic_vector(2 downto 0) := "001";
constant F3_LOAD_LW: std_logic_vector(2 downto 0) := "010";
constant F3_LOAD_LBU: std_logic_vector(2 downto 0) := "100";
constant F3_LOAD_LHU: std_logic_vector(2 downto 0) := "101";
constant F2_MEM_LS_SIZE_B: std_logic_vector(1 downto 0) := "00";
constant F2_MEM_LS_SIZE_H: std_logic_vector(1 downto 0) := "01";
constant F2_MEM_LS_SIZE_W: std_logic_vector(1 downto 0) := "10";
constant F3_STORE_SB: std_logic_vector(2 downto 0) := "000";
constant F3_STORE_SH: std_logic_vector(2 downto 0) := "001";
constant F3_STORE_SW: std_logic_vector(2 downto 0) := "010";
constant F3_OPIMM_ADDI: std_logic_vector(2 downto 0) := "000";
constant F3_OPIMM_SLTI: std_logic_vector(2 downto 0) := "010";
constant F3_OPIMM_SLTIU: std_logic_vector(2 downto 0) := "011";
constant F3_OPIMM_XORI: std_logic_vector(2 downto 0) := "100";
constant F3_OPIMM_ORI: std_logic_vector(2 downto 0) := "110";
constant F3_OPIMM_ANDI: std_logic_vector(2 downto 0) := "111";
constant F3_OPIMM_SLLI: std_logic_vector(2 downto 0) := "001";
constant F7_OPIMM_SLLI: std_logic_vector(6 downto 0) := "0000000";
constant F3_OPIMM_SRLI: std_logic_vector(2 downto 0) := "101";
constant F7_OPIMM_SRLI: std_logic_vector(6 downto 0) := "0000000";
constant F3_OPIMM_SRAI: std_logic_vector(2 downto 0) := "101";
constant F7_OPIMM_SRAI: std_logic_vector(6 downto 0) := "0100000";
constant F3_OP_ADD: std_logic_vector(2 downto 0) := "000";
constant F7_OP_ADD: std_logic_vector(6 downto 0) := "0000000";
constant F3_OP_SUB: std_logic_vector(2 downto 0) := "000";
constant F7_OP_SUB: std_logic_vector(6 downto 0) := "0100000";
constant F3_OP_SLL: std_logic_vector(2 downto 0) := "001";
constant F7_OP_SLL: std_logic_vector(6 downto 0) := "0000000";
constant F3_OP_SLT: std_logic_vector(2 downto 0) := "010";
constant F7_OP_SLT: std_logic_vector(6 downto 0) := "0000000";
constant F3_OP_SLTU: std_logic_vector(2 downto 0) := "011";
constant F7_OP_SLTU: std_logic_vector(6 downto 0) := "0000000";
constant F3_OP_XOR: std_logic_vector(2 downto 0) := "100";
constant F7_OP_XOR: std_logic_vector(6 downto 0) := "0000000";
constant F3_OP_SRL: std_logic_vector(2 downto 0) := "101";
constant F7_OP_SRL: std_logic_vector(6 downto 0) := "0000000";
constant F3_OP_SRA: std_logic_vector(2 downto 0) := "101";
constant F7_OP_SRA: std_logic_vector(6 downto 0) := "0100000";
constant F3_OP_OR: std_logic_vector(2 downto 0) := "110";
constant F7_OP_OR: std_logic_vector(6 downto 0) := "0000000";
constant F3_OP_AND: std_logic_vector(2 downto 0) := "111";
constant F7_OP_AND: std_logic_vector(6 downto 0) := "0000000";
constant F3_MISCMEM_FENCE: std_logic_vector(2 downto 0) := "000";
constant F3_MISCMEM_FENCEI: std_logic_vector(2 downto 0) := "001";
constant F3_SYSTEM_ECALL: std_logic_vector(2 downto 0) := "000";
constant IMM_I_SYSTEM_ECALL: std_logic_vector(11 downto 0) := "000000000000";
constant F3_SYSTEM_EBREAK: std_logic_vector(2 downto 0) := "000";
constant IMM_I_SYSTEM_EBREAK: std_logic_vector(11 downto 0) := "000000000001";
constant F3_SYSTEM_CSRRW: std_logic_vector(2 downto 0) := "001";
constant F3_SYSTEM_CSRRS: std_logic_vector(2 downto 0) := "010";
constant F3_SYSTEM_CSRRC: std_logic_vector(2 downto 0) := "011";
constant F3_SYSTEM_CSRRWI: std_logic_vector(2 downto 0) := "101";
constant F3_SYSTEM_CSRRSI: std_logic_vector(2 downto 0) := "110";
constant F3_SYSTEM_CSRRCI: std_logic_vector(2 downto 0) := "111";
end constants;
package body constants is
end constants;

174
vhdl/control_unit.vhd Normal file
View file

@ -0,0 +1,174 @@
----------------------------------------------------------------------------------
-- Project Name: RPU
-- Description: control unit
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
library work;
use work.constants.all;
entity control_unit is
Port (
I_clk : in STD_LOGIC;
I_reset : in STD_LOGIC;
I_aluop : in STD_LOGIC_VECTOR (6 downto 0);
-- interrupts
I_int_enabled: in std_logic;
I_int: in STD_LOGIC;
O_int_ack: out STD_LOGIC;
I_int_mem_data: in STD_LOGIC_VECTOR(XLENM1 downto 0);
O_idata: out STD_LOGIC_VECTOR(XLENM1 downto 0);
O_set_idata:out STD_LOGIC;
O_set_ipc: out STD_LOGIC;
O_set_irpc: out STD_LOGIC;
-- mem controller state and control
I_ready: in STD_LOGIC;
O_execute: out STD_LOGIC;
I_dataReady: in STD_LOGIC;
O_state : out STD_LOGIC_VECTOR (6 downto 0)
);
end control_unit;
architecture Behavioral of control_unit is
signal s_state: STD_LOGIC_VECTOR(6 downto 0) := "0000001";
signal mem_ready: std_logic;
signal mem_execute: std_logic:='0';
signal mem_dataReady: std_logic;
signal mem_cycles : integer := 0;
signal next_s_state: STD_LOGIC_VECTOR(6 downto 0) := "0000001";
signal interrupt_state: STD_LOGIC_VECTOR(2 downto 0) := "000";
signal interrupt_ack: STD_LOGIC := '0';
signal interrupt_was_inactive: STD_LOGIC := '1';
signal set_idata: STD_LOGIC := '0';
signal set_ipc: STD_LOGIC := '0';
begin
O_execute <= mem_execute;
mem_ready <= I_ready;
mem_dataReady <= I_dataReady;
O_int_ack <= interrupt_ack;
O_set_idata <= set_idata;
O_set_irpc <= set_idata;
O_set_ipc <= set_ipc;
process(I_clk)
begin
if rising_edge(I_clk) then
if I_reset = '1' then
s_state <= "0000001";
next_s_state <= "0000001";
mem_cycles <= 0;
mem_execute <= '0';
interrupt_was_inactive <= '1';
interrupt_ack <= '0';
interrupt_state <= "000";
set_ipc <= '0';
O_idata <= X"00000000";
set_idata <= '0';
else
if I_int = '0' then
interrupt_was_inactive <= '1';
end if;
case s_state is
when "0000001" => -- fetch
if mem_cycles = 0 and mem_ready = '1' then
mem_execute <= '1';
mem_cycles <= 1;
elsif mem_cycles = 1 then
mem_execute <= '0';
mem_cycles <= 2;
elsif mem_cycles = 2 then
if mem_dataReady = '1' then
mem_cycles <= 0;
s_state <= "0000010";
end if;
end if;
when "0000010" => --- decode
s_state <= "0001000"; --E "0000100"; --R
when "0000100" => -- read -- DEPRECATED STAGE
s_state <= "0001000"; --E
when "0001000" => -- execute
--MEM/WB
-- if it's not a memory alu op, goto writeback
if (I_aluop(6 downto 2) = OPCODE_LOAD or
I_aluop(6 downto 2) = OPCODE_STORE) then
s_state <= "0010000"; -- MEM
else
s_state <= "0100000"; -- WB
end if;
when "0010000" => -- mem
-- sometimes memory can be busy, if so we need to relook here
if mem_cycles = 0 and mem_ready = '1' then
mem_execute <= '1';
mem_cycles <= 1;
elsif mem_cycles = 1 then
mem_execute <= '0';
-- if it's a write, go through
if I_aluop(6 downto 2) = OPCODE_STORE then
mem_cycles <= 0;
s_state <= "0100001";-- "0100000"; -- WB
elsif mem_dataReady = '1' then
-- if read, wait for data
mem_cycles <= 0;
s_state <= "0100000"; -- WB
end if;
end if;
when "0100000" => -- writeback
-- check interrupt?
if I_int_enabled='1' and interrupt_was_inactive = '1' and I_int = '1' then
interrupt_ack <= '1';
interrupt_was_inactive <= '0';
interrupt_state <= "001";
next_s_state <= "0000001"; --F
s_state <= "1000000"; --F
else
s_state <= "0000001"; --F
end if;
when "1000000" => -- stalls
-- interrupt stall
if interrupt_state = "001" then
-- give a cycle of latency
interrupt_state <= "010";
elsif interrupt_state = "010" then
-- sample input data for state?
O_idata <= I_int_mem_data;
set_idata <= '1';
interrupt_state <= "100";
elsif interrupt_state = "100" then
set_idata <= '0';
-- set PC to interrupt vector.
set_ipc <= '1';
interrupt_state <= "101";
elsif interrupt_state = "101" then
set_ipc <= '0';
interrupt_ack <= '0';
interrupt_state <= "000";
s_state <= "0000001"; --F
end if;
when others =>
s_state <= "0000001";
end case;
end if;
end if;
end process;
O_state <= s_state;
end Behavioral;

351
vhdl/core.vhd Normal file
View file

@ -0,0 +1,351 @@
----------------------------------------------------------------------------------
-- Project Name: RPU
-- Description: RPU core glue entity
--
-- Brings all core components together with a little logic.
-- This is the CPU interface required.
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
library work;
use work.constants.all;
entity core is
Port (
I_clk : in STD_LOGIC;
I_reset : in STD_LOGIC;
I_halt : in STD_LOGIC;
-- unused interrupt interface, relic from TPU implementation
I_int: in STD_LOGIC;
O_int_ack: out STD_LOGIC;
-- memory interface
MEM_I_ready : IN std_logic;
MEM_O_cmd : OUT std_logic;
MEM_O_we : OUT std_logic;
-- fixme: this is not a true byteEnable and so is confusing.
-- Will be fixed when memory swizzling is brought core-size
MEM_O_byteEnable : OUT std_logic_vector(1 downto 0);
MEM_O_addr : OUT std_logic_vector(XLEN32M1 downto 0);
MEM_O_data : OUT std_logic_vector(XLEN32M1 downto 0);
MEM_I_data : IN std_logic_vector(XLEN32M1 downto 0);
MEM_I_dataReady : IN std_logic
; -- This debug output contains some internal state for debugging
O_DBG:out std_logic_vector(XLEN32M1 downto 0)
);
end core;
architecture Behavioral of core is
COMPONENT pc_unit
PORT(
I_clk : IN std_logic;
I_nPC : IN std_logic_vector(XLENM1 downto 0);
I_nPCop : IN std_logic_vector(1 downto 0);
I_intVec: IN std_logic;
O_PC : OUT std_logic_vector(XLENM1 downto 0)
);
END COMPONENT;
COMPONENT control_unit
PORT (
I_clk : in STD_LOGIC;
I_reset : in STD_LOGIC;
I_aluop : in STD_LOGIC_VECTOR (6 downto 0);
O_state : out STD_LOGIC_VECTOR (6 downto 0);
I_int: in STD_LOGIC;
O_int_ack: out STD_LOGIC;
I_int_enabled: in STD_LOGIC;
I_int_mem_data: in STD_LOGIC_VECTOR(XLENM1 downto 0);
O_idata: out STD_LOGIC_VECTOR(XLENM1 downto 0);
O_set_idata:out STD_LOGIC;
O_set_ipc: out STD_LOGIC;
O_set_irpc: out STD_LOGIC;
I_ready: in STD_LOGIC;
O_execute: out STD_LOGIC;
I_dataReady: in STD_LOGIC
);
END COMPONENT;
COMPONENT decoder_RV32
PORT(
I_clk : IN std_logic;
I_en : IN std_logic;
I_dataInst : IN std_logic_vector(31 downto 0);
O_selRS1 : OUT std_logic_vector(4 downto 0);
O_selRS2 : OUT std_logic_vector(4 downto 0);
O_selD : OUT std_logic_vector(4 downto 0);
O_dataIMM : OUT std_logic_vector(31 downto 0);
O_regDwe : OUT std_logic;
O_aluOp : OUT std_logic_vector(6 downto 0);
O_aluFunc : OUT std_logic_vector(15 downto 0); -- ALU function
O_memOp : out STD_LOGIC_VECTOR(4 downto 0)
);
END COMPONENT;
component alu_RV32I is
Port ( I_clk : in STD_LOGIC;
I_en : in STD_LOGIC;
I_dataA : in STD_LOGIC_VECTOR (XLEN32M1 downto 0);
I_dataB : in STD_LOGIC_VECTOR (XLEN32M1 downto 0);
I_dataDwe : in STD_LOGIC;
I_aluop : in STD_LOGIC_VECTOR (4 downto 0);
I_aluFunc : in STD_LOGIC_VECTOR (15 downto 0);
I_PC : in STD_LOGIC_VECTOR (XLEN32M1 downto 0);
I_dataIMM : in STD_LOGIC_VECTOR (XLEN32M1 downto 0);
O_dataResult : out STD_LOGIC_VECTOR (XLEN32M1 downto 0);
O_branchTarget : out STD_LOGIC_VECTOR (XLEN32M1 downto 0);
O_dataWriteReg : out STD_LOGIC;
O_shouldBranch : out std_logic
);
end component;
COMPONENT register_set
PORT(
I_clk : IN std_logic;
I_en : IN std_logic;
I_dataD : IN std_logic_vector(31 downto 0);
I_selRS1 : IN std_logic_vector(4 downto 0);
I_selRS2 : IN std_logic_vector(4 downto 0);
I_selD : IN std_logic_vector(4 downto 0);
I_we : IN std_logic;
O_dataA : OUT std_logic_vector(31 downto 0);
O_dataB : OUT std_logic_vector(31 downto 0)
);
END COMPONENT;
COMPONENT mem_controller
PORT(
I_clk : IN std_logic;
I_reset : IN std_logic;
O_ready : OUT std_logic;
I_execute : IN std_logic;
I_dataWe : IN std_logic;
I_address : IN std_logic_vector(XLENM1 downto 0);
I_data : IN std_logic_vector(XLENM1 downto 0);
I_dataByteEn : IN std_logic_vector(1 downto 0);
O_data : OUT std_logic_vector(XLENM1 downto 0);
O_dataReady : OUT std_logic;
MEM_I_ready : IN std_logic;
MEM_O_cmd : OUT std_logic;
MEM_O_we : OUT std_logic;
MEM_O_byteEnable : OUT std_logic_vector(1 downto 0);
MEM_O_addr : OUT std_logic_vector(XLENM1 downto 0);
MEM_O_data : OUT std_logic_vector(XLENM1 downto 0);
MEM_I_data : IN std_logic_vector(XLENM1 downto 0);
MEM_I_dataReady : IN std_logic
);
END COMPONENT;
signal state : std_logic_vector(6 downto 0) := (others => '0');
signal pcop: std_logic_vector(1 downto 0);
signal in_pc: std_logic_vector(XLENM1 downto 0);
signal aluFunc: std_logic_vector(15 downto 0);
signal memOp: std_logic_vector(4 downto 0);
signal branchTarget:std_logic_vector(XLENM1 downto 0) := (others => '0');
signal instruction : std_logic_vector(XLENM1 downto 0) := (others => '0');
signal dataA : std_logic_vector(XLENM1 downto 0) := (others => '0');
signal dataB : std_logic_vector(XLENM1 downto 0) := (others => '0');
signal dataDwe : std_logic := '0';
signal aluop : std_logic_vector(6 downto 0) := (others => '0');
signal dataIMM : std_logic_vector(XLENM1 downto 0) := (others => '0');
signal selRS1 : std_logic_vector(4 downto 0) := (others => '0');
signal selRS2 : std_logic_vector(4 downto 0) := (others => '0');
signal selD : std_logic_vector(4 downto 0) := (others => '0');
signal dataregWrite: std_logic := '0';
signal dataResult : std_logic_vector(XLENM1 downto 0) := (others => '0');
signal dataWriteReg : std_logic := '0';
signal shouldBranch : std_logic := '0';
signal memMode : std_logic := '0';
signal ram_req_size : std_logic := '0';
signal reg_en: std_logic := '0';
signal reg_we: std_logic := '0';
signal registerWriteData : std_logic_vector(XLENM1 downto 0) := (others=>'0');
signal en_fetch : std_logic := '0';
signal en_decode : std_logic := '0';
signal en_alu : std_logic := '0';
signal en_memory : std_logic := '0';
signal en_regwrite : std_logic := '0';
signal en_stall : std_logic := '0';
signal PC : std_logic_vector(XLENM1 downto 0) := (others => '0');
signal memctl_ready : std_logic;
signal memctl_execute : std_logic := '0';
signal memctl_dataWe : std_logic;
signal memctl_address : std_logic_vector(XLENM1 downto 0);
signal memctl_in_data : std_logic_vector(XLENM1 downto 0);
signal memctl_dataByteEn : std_logic_vector(1 downto 0);
signal memctl_out_data : std_logic_vector(XLENM1 downto 0) := (others => '0');
signal memctl_dataReady : std_logic := '0';
signal memctl_size : std_logic_vector(1 downto 0);
signal memctl_signExtend: std_logic := '0';
signal PCintVec: STD_LOGIC := '0';
signal int_idata: STD_LOGIC_VECTOR(XLENM1 downto 0);
signal int_set_idata: STD_LOGIC;
signal int_enabled: std_logic;
signal int_set_irpc: STD_LOGIC;
signal core_clock:STD_LOGIC := '0';
begin
core_clock <= I_clk;
memctl: mem_controller PORT MAP (
I_clk => I_clk,
I_reset => I_reset,
O_ready => memctl_ready,
I_execute => memctl_execute,
I_dataWe => memctl_dataWe,
I_address => memctl_address,
I_data => memctl_in_data,
I_dataByteEn => memctl_dataByteEn,
O_data => memctl_out_data,
O_dataReady => memctl_dataReady,
MEM_I_ready => MEM_I_ready,
MEM_O_cmd => MEM_O_cmd,
MEM_O_we => MEM_O_we,
MEM_O_byteEnable => MEM_O_byteEnable,
MEM_O_addr => MEM_O_addr,
MEM_O_data => MEM_O_data,
MEM_I_data => MEM_I_data,
MEM_I_dataReady => MEM_I_dataReady
);
pcunit: pc_unit Port map (
I_clk => core_clock,
I_nPC => in_pc,
I_nPCop => pcop,
I_intVec => PCintVec,
O_PC => PC
);
control: control_unit PORT MAP (
I_clk => core_clock,
I_reset => I_reset,
I_aluop => aluop,
I_int => I_int,
O_int_ack => O_int_ack,
I_int_enabled => int_enabled,
I_int_mem_data=>MEM_I_data,
O_idata=> int_idata,
O_set_idata=> int_set_idata,
O_set_ipc=> PCintVec,
O_set_irpc => int_set_irpc,
I_ready => memctl_ready,
O_execute => memctl_execute,
I_dataReady => memctl_dataReady,
O_state => state
);
decoder: decoder_RV32 PORT MAP (
I_clk => core_clock,
I_en => en_decode,
I_dataInst => instruction,
O_selRS1 => selRS1,
O_selRS2 => selRS2,
O_selD => selD,
O_dataIMM => dataIMM,
O_regDwe => dataDwe,
O_aluOp => aluOp,
O_aluFunc => aluFunc,
O_memOp => memOp
);
alu: alu_RV32I PORT MAP (
I_clk => core_clock,
I_en => en_alu,
I_dataA => dataA,
I_dataB => dataB,
I_dataDwe => dataDwe,
I_aluop => aluop(6 downto 2),
I_aluFunc => aluFunc,
I_PC => PC,
I_dataIMM => dataIMM,
O_dataResult => dataResult,
O_branchTarget => branchTarget,
O_dataWriteReg => dataWriteReg,
O_shouldBranch => shouldBranch
);
reg: register_set PORT MAP (
I_clk => core_clock,
I_en => reg_en,
I_dataD => registerWriteData,
O_dataA => dataA,
O_dataB => dataB,
I_selRS1 => selRS1,
I_selRS2 => selRS2,
I_selD => selD,
I_we => reg_we
);
-- Register file controls
reg_en <= en_decode or en_regwrite;
reg_we <= dataWriteReg and en_regwrite;
-- These are the pipeline stage enable bits
en_fetch <= state(0);
en_decode <= state(1);
en_alu <= state(3);
en_memory <= state(4);
en_regwrite <= state(5);
en_stall <= state(6);
-- This decides what the next PC should be
pcop <= PCU_OP_RESET when I_reset = '1' else
PCU_OP_ASSIGN when shouldBranch = '1' and state(5) = '1' else
PCU_OP_INC when shouldBranch = '0' and state(5) = '1' else
PCU_OP_NOP;
-- The input PC is just always the branch target output from ALU
in_pc <= branchTarget;
-- The debug output just allows some internal state to be visible outside the core black box
O_DBG <= "000" & memctl_dataReady & "000" & MEM_I_dataReady & "0" & state & registerWriteData(15 downto 0);
-- Below statements are for memory interface use.
memctl_address <= dataResult when en_memory = '1' else PC;
ram_req_size <= memMode when en_memory = '1' else '0';
memctl_dataByteEn <= memctl_size when en_memory = '1' else F2_MEM_LS_SIZE_W;
memctl_in_data <= dataB;
memctl_dataWe <= '1' when en_memory = '1' and memOp(4 downto 3) = "11" else '0';
memctl_size <= memOp(1 downto 0);
memctl_signExtend <= memOp(2);
-- This chooses to write registers with memory data or ALU data
registerWriteData <= memctl_out_data when memOp(4 downto 3) = "10" else dataResult;
-- The instructions are delivered from memctl
instruction <= memctl_out_data;
end Behavioral;

101
vhdl/mem_controller.vhd Normal file
View file

@ -0,0 +1,101 @@
----------------------------------------------------------------------------------
-- Project Name: RPU
-- Description: Memory controller unit of RPU
--
-- Very simple. Allows for delays in reads, whilsts writes go through immediately.
-- MEM_ signals are expected to be exposted to any SoC fabric.
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
library work;
use work.constants.all;
entity mem_controller is
Port (
I_clk : in STD_LOGIC;
I_reset : in STD_LOGIC;
O_ready : out STD_LOGIC;
I_execute: in STD_LOGIC;
I_dataWe : in STD_LOGIC;
I_address : in STD_LOGIC_VECTOR (XLENM1 downto 0);
I_data : in STD_LOGIC_VECTOR (XLENM1 downto 0);
I_dataByteEn : in STD_LOGIC_VECTOR(1 downto 0);
O_data : out STD_LOGIC_VECTOR (XLENM1 downto 0);
O_dataReady: out STD_LOGIC;
MEM_I_ready: in STD_LOGIC;
MEM_O_cmd: out STD_LOGIC;
MEM_O_we : out STD_LOGIC;
MEM_O_byteEnable : out STD_LOGIC_VECTOR (1 downto 0);
MEM_O_addr : out STD_LOGIC_VECTOR (XLENM1 downto 0);
MEM_O_data : out STD_LOGIC_VECTOR (XLENM1 downto 0);
MEM_I_data : in STD_LOGIC_VECTOR (XLENM1 downto 0);
MEM_I_dataReady : in STD_LOGIC
);
end mem_controller;
architecture Behavioral of mem_controller is
signal we : std_logic := '0';
signal addr : STD_LOGIC_VECTOR (XLENM1 downto 0) := X"00000000";
signal indata: STD_LOGIC_VECTOR (XLENM1 downto 0) := X"00000000";
signal byteEnable: STD_LOGIC_VECTOR ( 1 downto 0) := "11";
signal cmd : STD_LOGIC := '0';
signal state: integer := 0;
signal ready: STD_LOGIC := '0';
begin
process (I_clk, I_execute)
begin
if rising_edge(I_clk) then
if I_reset = '1' then
we <= '0';
cmd <= '0';
state <= 0;
O_dataReady <= '0';
elsif state = 0 and I_execute = '1' and MEM_I_ready = '1' then
we <= I_dataWe;
addr <= I_address;
indata <= I_data;
byteEnable <= I_dataByteEn;
cmd <= '1';
O_dataReady <= '0';
if I_dataWe = '0' then
state <= 3;-- read
else
state <= 2;-- write
end if;
elsif state = 3 then
cmd <= '0';
state <= 1;
elsif state = 1 then
cmd <= '0';
if MEM_I_dataReady = '1' then
O_dataReady <= '1';
O_data <= MEM_I_data;
state <= 2;
end if;
elsif state = 2 then
cmd <= '0';
state <= 0;
O_dataReady <= '0';
end if;
end if;
end process;
O_ready <= ( MEM_I_ready and not I_execute ) when state = 0 else '0';
MEM_O_cmd <= cmd;
MEM_O_byteEnable <= byteEnable;
MEM_O_data <= indata;
MEM_O_addr <= addr;
MEM_O_we <= we;
end Behavioral;

52
vhdl/pc_unit.vhd Normal file
View file

@ -0,0 +1,52 @@
----------------------------------------------------------------------------------
-- Project Name: RPU
-- Description: Program Counter unit of RPU
--
-- Simple black box for holding and manipulating the PC
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
library work;
use work.constants.all;
entity pc_unit is
Port (
I_clk : in STD_LOGIC;
I_nPC : in STD_LOGIC_VECTOR (XLENM1 downto 0);
I_nPCop : in STD_LOGIC_VECTOR (1 downto 0);
I_intVec: in STD_LOGIC;
O_PC : out STD_LOGIC_VECTOR (XLENM1 downto 0)
);
end pc_unit;
architecture Behavioral of pc_unit is
signal current_pc: std_logic_vector( XLENM1 downto 0) := ADDR_RESET;
begin
process (I_clk)
begin
if rising_edge(I_clk) then
case I_nPCop is
when PCU_OP_NOP => -- NOP, keep PC the same/halt
if I_intVec = '1' then -- in a NOP, you can get intterupts. check.
current_pc <= ADDR_INTVEC;-- set PC to interrupt vector;
end if;
when PCU_OP_INC => -- increment
current_pc <= std_logic_vector(unsigned(current_pc) + 4); -- 32bit byte addressing
when PCU_OP_ASSIGN => -- set from external input
current_pc <= I_nPC;
when PCU_OP_RESET => -- Reset
current_pc <= ADDR_RESET;
when others =>
end case;
end if;
end process;
O_PC <= current_pc;
end Behavioral;

49
vhdl/register_set.vhd Normal file
View file

@ -0,0 +1,49 @@
----------------------------------------------------------------------------------
-- Project Name: RISC-V CPU
-- Description: Register file unit
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
library work;
use work.constants.all;
entity register_set is
Port (
I_clk : in STD_LOGIC;
I_en : in STD_LOGIC;
I_dataD : in STD_LOGIC_VECTOR (XLENM1 downto 0); -- Data to write to regD
I_selRS1 : in STD_LOGIC_VECTOR (4 downto 0); -- Select line for regRS1
I_selRS2 : in STD_LOGIC_VECTOR (4 downto 0); -- Select line for regRS2
I_selD : in STD_LOGIC_VECTOR (4 downto 0); -- Select line for regD
I_we : in STD_LOGIC; -- Write enable for regD
O_dataA : out STD_LOGIC_VECTOR (XLENM1 downto 0);-- regRS1 data out
O_dataB : out STD_LOGIC_VECTOR (XLENM1 downto 0) -- regRS2 data out
);
end register_set;
architecture Behavioral of register_set is
type store_t is array (0 to 31) of std_logic_vector(XLENM1 downto 0);
signal regs: store_t := (others => X"00000000");
signal dataAout: STD_LOGIC_VECTOR (XLENM1 downto 0) := (others=>'0');
signal dataBout: STD_LOGIC_VECTOR (XLENM1 downto 0) := (others=>'0');
begin
process(I_clk, I_en)
begin
if rising_edge(I_clk) and I_en='1' then
dataAout <= regs(to_integer(unsigned(I_selRS1)));
dataBout <= regs(to_integer(unsigned(I_selRS2)));
if (I_we = '1') then
regs(to_integer(unsigned(I_selD))) <= I_dataD;
end if;
end if;
end process;
O_dataA <= dataAout;
O_dataB <= dataBout;
end Behavioral;

215
vhdl/unit_alu_RV32_I.vhd Normal file
View file

@ -0,0 +1,215 @@
----------------------------------------------------------------------------------
-- Project Name: RISC-V CPU
-- Description: ALU unit suitable for RV32I operational use
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
library work;
use work.constants.all;
entity alu_RV32I is
Port (
I_clk : in STD_LOGIC;
I_en : in STD_LOGIC;
I_dataA : in STD_LOGIC_VECTOR (XLEN32M1 downto 0);
I_dataB : in STD_LOGIC_VECTOR (XLEN32M1 downto 0);
I_dataDwe : in STD_LOGIC;
I_aluop : in STD_LOGIC_VECTOR (4 downto 0);
I_aluFunc : in STD_LOGIC_VECTOR (15 downto 0);
I_PC : in STD_LOGIC_VECTOR (XLEN32M1 downto 0);
I_dataIMM : in STD_LOGIC_VECTOR (XLEN32M1 downto 0);
O_dataResult : out STD_LOGIC_VECTOR (XLEN32M1 downto 0);
O_branchTarget : out STD_LOGIC_VECTOR (XLEN32M1 downto 0);
O_dataWriteReg : out STD_LOGIC;
O_shouldBranch : out std_logic
);
end alu_RV32I;
architecture Behavioral of alu_RV32I is
-- The internal register for results of operations.
-- 32 bit + carry/overflow
signal s_branchTarget : STD_LOGIC_VECTOR (XLEN32M1 downto 0) := (others => '0');
signal s_result: STD_LOGIC_VECTOR(XLEN32M1+2 downto 0) := (others => '0');
signal s_shouldBranch: STD_LOGIC := '0';
begin
process (I_clk, I_en)
begin
if rising_edge(I_clk) and I_en = '1' then
O_dataWriteReg <= I_dataDwe;
case I_aluop is
when OPCODE_OPIMM =>
s_shouldBranch <= '0';
case I_aluFunc(2 downto 0) is
when F3_OPIMM_ADDI =>
s_result(31 downto 0) <= std_logic_vector(signed( I_dataA) + signed( I_dataIMM));
when F3_OPIMM_XORI =>
s_result(31 downto 0) <= I_dataA xor I_dataIMM;
when F3_OPIMM_ORI =>
s_result(31 downto 0) <= I_dataA or I_dataIMM;
when F3_OPIMM_ANDI =>
s_result(31 downto 0) <= I_dataA and I_dataIMM;
when F3_OPIMM_SLTI =>
if signed(I_dataA) < signed(I_dataIMM) then
s_result(31 downto 0) <= X"00000001";
else
s_result(31 downto 0) <= X"00000000";
end if;
when F3_OPIMM_SLTIU =>
if unsigned(I_dataA) < unsigned(I_dataIMM) then
s_result(31 downto 0) <= X"00000001";
else
s_result(31 downto 0) <= X"00000000";
end if;
when F3_OPIMM_SLLI =>
s_result(31 downto 0) <= std_logic_vector(shift_left(unsigned(I_dataA), to_integer(unsigned(I_dataIMM(4 downto 0)))));
when F3_OPIMM_SRLI =>
case I_aluFunc(9 downto 3) is
when F7_OPIMM_SRLI =>
s_result(31 downto 0) <= std_logic_vector(shift_right(unsigned(I_dataA), to_integer(unsigned(I_dataIMM(4 downto 0)))));
when F7_OPIMM_SRAI =>
s_result(31 downto 0) <= std_logic_vector(shift_right(signed(I_dataA), to_integer(unsigned(I_dataIMM(4 downto 0)))));
when others=>
end case;
when others =>
end case;
when OPCODE_OP =>
case I_aluFunc(9 downto 0) is
when F7_OP_ADD & F3_OP_ADD =>
s_result(31 downto 0) <= std_logic_vector(signed( I_dataA) + signed( I_dataB));
when F7_OP_SUB & F3_OP_SUB =>
s_result(31 downto 0) <= std_logic_vector(signed( I_dataA) - signed( I_dataB));
when F7_OP_SLT & F3_OP_SLT =>
if signed(I_dataA) < signed(I_dataB) then
s_result(31 downto 0) <= X"00000001";
else
s_result(31 downto 0) <= X"00000000";
end if;
when F7_OP_SLTU & F3_OP_SLTU =>
if unsigned(I_dataA) < unsigned(I_dataB) then
s_result(31 downto 0) <= X"00000001";
else
s_result(31 downto 0) <= X"00000000";
end if;
when F7_OP_XOR & F3_OP_XOR =>
s_result(31 downto 0) <= I_dataA xor I_dataB;
when F7_OP_OR & F3_OP_OR =>
s_result(31 downto 0) <= I_dataA or I_dataB;
when F7_OP_AND & F3_OP_AND =>
s_result(31 downto 0) <= I_dataA and I_dataB;
when F7_OP_SLL & F3_OP_SLL =>
s_result(31 downto 0) <= std_logic_vector(shift_left(unsigned(I_dataA), to_integer(unsigned(I_dataB(4 downto 0)))));
when F7_OP_SRL & F3_OP_SRL =>
s_result(31 downto 0) <= std_logic_vector(shift_right(unsigned(I_dataA), to_integer(unsigned(I_dataB(4 downto 0)))));
when F7_OP_SRA & F3_OP_SRA =>
s_result(31 downto 0) <= std_logic_vector(shift_right(signed(I_dataA), to_integer(unsigned(I_dataB(4 downto 0)))));
when others=>
s_result <= "00" & X"CDC1FEF1";
end case;
s_shouldBranch <= '0';
when OPCODE_LOAD | OPCODE_STORE =>
s_shouldBranch <= '0';
s_result(31 downto 0) <= std_logic_vector(signed( I_dataA) + signed( I_dataIMM));
when OPCODE_JALR =>
s_branchTarget <= std_logic_vector(signed( I_dataA) + signed( I_dataIMM));
s_shouldBranch <= '1';
s_result(31 downto 0) <= std_logic_vector(signed( I_PC) + 4);
when OPCODE_JAL =>
s_branchTarget <= std_logic_vector(signed( I_PC) + signed( I_dataIMM));
s_shouldBranch <= '1';
s_result(31 downto 0) <= std_logic_vector(signed( I_PC) + 4);
when OPCODE_LUI =>
s_shouldBranch <= '0';
s_result(31 downto 0) <= I_dataIMM;
when OPCODE_AUIPC =>
s_shouldBranch <= '0';
s_result(31 downto 0) <= std_logic_vector( signed( I_PC) + signed( I_dataIMM));
when OPCODE_BRANCH =>
s_branchTarget <= std_logic_vector(signed( I_PC) + signed( I_dataIMM));
case I_aluFunc(2 downto 0) is
when F3_BRANCH_BEQ =>
if I_dataA = I_dataB then
s_shouldBranch <= '1';
else
s_shouldBranch <= '0';
end if;
when F3_BRANCH_BNE =>
if I_dataA /= I_dataB then
s_shouldBranch <= '1';
else
s_shouldBranch <= '0';
end if;
when F3_BRANCH_BLT =>
if signed(I_dataA) < signed(I_dataB) then
s_shouldBranch <= '1';
else
s_shouldBranch <= '0';
end if;
when F3_BRANCH_BGE =>
if signed(I_dataA) >= signed(I_dataB) then
s_shouldBranch <= '1';
else
s_shouldBranch <= '0';
end if;
when F3_BRANCH_BLTU =>
if unsigned(I_dataA) < unsigned(I_dataB) then
s_shouldBranch <= '1';
else
s_shouldBranch <= '0';
end if;
when F3_BRANCH_BGEU =>
if unsigned(I_dataA) >= unsigned(I_dataB) then
s_shouldBranch <= '1';
else
s_shouldBranch <= '0';
end if;
when others =>
end case;
when others =>
s_result <= "00" & X"CDCDFEFE";
end case;
end if;
end process;
O_dataResult <= s_result(XLEN32M1 downto 0);
O_shouldBranch <= s_shouldBranch;
O_branchTarget <= s_branchTarget;
end Behavioral;

127
vhdl/unit_decoder_RV32I.vhd Normal file
View file

@ -0,0 +1,127 @@
----------------------------------------------------------------------------------
-- Project Name: RISC-V CPU
-- Description: decoder unit RV32I
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
library work;
use work.constants.all;
entity decoder_RV32 is
Port (
I_clk : in STD_LOGIC;
I_en : in STD_LOGIC;
I_dataInst : in STD_LOGIC_VECTOR (31 downto 0); -- Instruction to be decoded
O_selRS1 : out STD_LOGIC_VECTOR (4 downto 0); -- Selection out for regrs1
O_selRS2 : out STD_LOGIC_VECTOR (4 downto 0); -- Selection out for regrs2
O_selD : out STD_LOGIC_VECTOR (4 downto 0); -- Selection out for regD
O_dataIMM : out STD_LOGIC_VECTOR (31 downto 0); -- Immediate value out
O_regDwe : out STD_LOGIC; -- RegD wrtite enable
O_aluOp : out STD_LOGIC_VECTOR (6 downto 0); -- ALU opcode
O_aluFunc : out STD_LOGIC_VECTOR (15 downto 0); -- ALU function
O_memOp : out STD_LOGIC_VECTOR(4 downto 0) -- Memory operation
);
end decoder_RV32;
architecture Behavioral of decoder_RV32 is
begin
-- Register selects for reads are async
O_selRS1 <= I_dataInst(R1_START downto R1_END);
O_selRS2 <= I_dataInst(R2_START downto R2_END);
process (I_clk, I_en)
begin
if rising_edge(I_clk) and I_en = '1' then
O_selD <= I_dataInst(RD_START downto RD_END);
O_aluOp <= I_dataInst(OPCODE_START downto OPCODE_END);
O_aluFunc <= "000000" & I_dataInst(FUNCT7_START downto FUNCT7_END)
& I_dataInst(FUNCT3_START downto FUNCT3_END);
case I_dataInst(OPCODE_START downto OPCODE_END_2) is
when OPCODE_LUI =>
O_regDwe <= '1';
O_memOp <= "00000";
O_dataIMM <= I_dataInst(IMM_U_START downto IMM_U_END)
& "000000000000";
when OPCODE_AUIPC =>
O_regDwe <= '1';
O_memOp <= "00000";
O_dataIMM <= I_dataInst(IMM_U_START downto IMM_U_END)
& "000000000000";
when OPCODE_JAL =>
if I_dataInst(RD_START downto RD_END) = "00000" then
O_regDwe <= '0';
else
O_regDwe <= '1';
end if;
O_memOp <= "00000";
if I_dataInst(IMM_U_START) = '1' then
O_dataIMM <= "111111111111" & I_dataInst(19 downto 12) & I_dataInst(20) & I_dataInst(30 downto 21) & '0';
else
O_dataIMM <= "000000000000" & I_dataInst(19 downto 12) & I_dataInst(20) & I_dataInst(30 downto 21) & '0';
end if;
when OPCODE_JALR =>
if I_dataInst(RD_START downto RD_END) = "00000" then
O_regDwe <= '0';
else
O_regDwe <= '1';
end if;
O_memOp <= "00000";
if I_dataInst(IMM_U_START) = '1' then
O_dataIMM <= X"FFFF" & "1111" & I_dataInst(IMM_I_START downto IMM_I_END);
else
O_dataIMM <= X"0000" & "0000" & I_dataInst(IMM_I_START downto IMM_I_END);
end if;
when OPCODE_OPIMM =>
O_regDwe <= '1';
O_memOp <= "00000";
if I_dataInst(IMM_U_START) = '1' then
O_dataIMM <= X"FFFF" & "1111" & I_dataInst(IMM_I_START downto IMM_I_END);
else
O_dataIMM <= X"0000" & "0000" & I_dataInst(IMM_I_START downto IMM_I_END);
end if;
when OPCODE_LOAD =>
O_regDwe <= '1';
O_memOp <= "10" & I_dataInst(FUNCT3_START downto FUNCT3_END);
if I_dataInst(IMM_U_START) = '1' then
O_dataIMM <= X"FFFF" & "1111" & I_dataInst(IMM_I_START downto IMM_I_END);
else
O_dataIMM <= X"0000" & "0000" & I_dataInst(IMM_I_START downto IMM_I_END);
end if;
when OPCODE_STORE =>
O_regDwe <= '0';
O_memOp <= "11" & I_dataInst(FUNCT3_START downto FUNCT3_END);
if I_dataInst(IMM_U_START) = '1' then
O_dataIMM <= X"FFFF" & "1111" & I_dataInst(IMM_S_A_START downto IMM_S_A_END) & I_dataInst(IMM_S_B_START downto IMM_S_B_END);
else
O_dataIMM <= X"0000" & "0000" & I_dataInst(IMM_S_A_START downto IMM_S_A_END) & I_dataInst(IMM_S_B_START downto IMM_S_B_END);
end if;
when OPCODE_BRANCH =>
O_regDwe <= '0';
O_memOp <= "00000";
if I_dataInst(IMM_U_START) = '1' then
O_dataIMM <= X"FFFF" & "1111" & I_dataInst(7) & I_dataInst(30 downto 25) & I_dataInst(11 downto 8) & '0';
else
O_dataIMM <= X"0000" & "0000" & I_dataInst(7) & I_dataInst(30 downto 25) & I_dataInst(11 downto 8) & '0';
end if;
when OPCODE_MISCMEM =>
O_regDwe <= '0';
O_memOp <= "01000";
O_dataIMM <= I_dataInst;
when others =>
O_memOp <= "00000";
O_regDwe <= '1';
O_dataIMM <= I_dataInst(IMM_I_START downto IMM_S_B_END)
& "0000000";
end case;
end if;
end process;
end Behavioral;