mirror of
https://github.com/Domipheus/RPU.git
synced 2025-04-18 19:15:13 -04:00
Initial commit. Tested on ArtyS7-RPU-SoC and passes SD bootloader and DDR3 memory testing.
This commit is contained in:
parent
84a652b41c
commit
439781c194
12 changed files with 1526 additions and 0 deletions
|
@ -1,2 +1,10 @@
|
||||||
# RPU
|
# RPU
|
||||||
Basic RISC-V CPU implementation in VHDL.
|
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
BIN
rpu_core_diagram.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 87 KiB |
155
tests/tb_unit_alu_RV32I_01.vhd
Normal file
155
tests/tb_unit_alu_RV32I_01.vhd
Normal 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;
|
136
tests/tb_unit_decoder_RV32_01.vhd
Normal file
136
tests/tb_unit_decoder_RV32_01.vhd
Normal 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
158
vhdl/constants.vhd
Normal 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
174
vhdl/control_unit.vhd
Normal 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
351
vhdl/core.vhd
Normal 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
101
vhdl/mem_controller.vhd
Normal 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
52
vhdl/pc_unit.vhd
Normal 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
49
vhdl/register_set.vhd
Normal 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
215
vhdl/unit_alu_RV32_I.vhd
Normal 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
127
vhdl/unit_decoder_RV32I.vhd
Normal 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;
|
||||||
|
|
Loading…
Add table
Reference in a new issue