From 439781c194da1241571534fe506fae4c14430599 Mon Sep 17 00:00:00 2001 From: Colin Riley Date: Tue, 11 Sep 2018 23:53:41 +0100 Subject: [PATCH] Initial commit. Tested on ArtyS7-RPU-SoC and passes SD bootloader and DDR3 memory testing. --- README.md | 8 + rpu_core_diagram.png | Bin 0 -> 89123 bytes tests/tb_unit_alu_RV32I_01.vhd | 155 +++++++++++++ tests/tb_unit_decoder_RV32_01.vhd | 136 ++++++++++++ vhdl/constants.vhd | 158 ++++++++++++++ vhdl/control_unit.vhd | 174 +++++++++++++++ vhdl/core.vhd | 351 ++++++++++++++++++++++++++++++ vhdl/mem_controller.vhd | 101 +++++++++ vhdl/pc_unit.vhd | 52 +++++ vhdl/register_set.vhd | 49 +++++ vhdl/unit_alu_RV32_I.vhd | 215 ++++++++++++++++++ vhdl/unit_decoder_RV32I.vhd | 127 +++++++++++ 12 files changed, 1526 insertions(+) create mode 100644 rpu_core_diagram.png create mode 100644 tests/tb_unit_alu_RV32I_01.vhd create mode 100644 tests/tb_unit_decoder_RV32_01.vhd create mode 100644 vhdl/constants.vhd create mode 100644 vhdl/control_unit.vhd create mode 100644 vhdl/core.vhd create mode 100644 vhdl/mem_controller.vhd create mode 100644 vhdl/pc_unit.vhd create mode 100644 vhdl/register_set.vhd create mode 100644 vhdl/unit_alu_RV32_I.vhd create mode 100644 vhdl/unit_decoder_RV32I.vhd diff --git a/README.md b/README.md index 5f8b581..9a9ce35 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/rpu_core_diagram.png b/rpu_core_diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..b4f86ab5fb94a6e2ec37e063aa0ed1fd40134013 GIT binary patch literal 89123 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≤=ao;XzAYue0 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 literal 0 HcmV?d00001 diff --git a/tests/tb_unit_alu_RV32I_01.vhd b/tests/tb_unit_alu_RV32I_01.vhd new file mode 100644 index 0000000..dbda8ca --- /dev/null +++ b/tests/tb_unit_alu_RV32I_01.vhd @@ -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; diff --git a/tests/tb_unit_decoder_RV32_01.vhd b/tests/tb_unit_decoder_RV32_01.vhd new file mode 100644 index 0000000..49afe34 --- /dev/null +++ b/tests/tb_unit_decoder_RV32_01.vhd @@ -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; diff --git a/vhdl/constants.vhd b/vhdl/constants.vhd new file mode 100644 index 0000000..2361afe --- /dev/null +++ b/vhdl/constants.vhd @@ -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; diff --git a/vhdl/control_unit.vhd b/vhdl/control_unit.vhd new file mode 100644 index 0000000..e149653 --- /dev/null +++ b/vhdl/control_unit.vhd @@ -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; + + + diff --git a/vhdl/core.vhd b/vhdl/core.vhd new file mode 100644 index 0000000..278c3dd --- /dev/null +++ b/vhdl/core.vhd @@ -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; + diff --git a/vhdl/mem_controller.vhd b/vhdl/mem_controller.vhd new file mode 100644 index 0000000..b41feb0 --- /dev/null +++ b/vhdl/mem_controller.vhd @@ -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; + diff --git a/vhdl/pc_unit.vhd b/vhdl/pc_unit.vhd new file mode 100644 index 0000000..e824323 --- /dev/null +++ b/vhdl/pc_unit.vhd @@ -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; + diff --git a/vhdl/register_set.vhd b/vhdl/register_set.vhd new file mode 100644 index 0000000..9208463 --- /dev/null +++ b/vhdl/register_set.vhd @@ -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; + diff --git a/vhdl/unit_alu_RV32_I.vhd b/vhdl/unit_alu_RV32_I.vhd new file mode 100644 index 0000000..881c7cb --- /dev/null +++ b/vhdl/unit_alu_RV32_I.vhd @@ -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; \ No newline at end of file diff --git a/vhdl/unit_decoder_RV32I.vhd b/vhdl/unit_decoder_RV32I.vhd new file mode 100644 index 0000000..7ec7b9e --- /dev/null +++ b/vhdl/unit_decoder_RV32I.vhd @@ -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; +