mirror of
https://github.com/Domipheus/RPU.git
synced 2025-04-18 19:15:13 -04:00
Updated ISA support to RV32IMZcsr - Passes riscv-compliance. Integer divide/rem in 34 cycles. Integer multiply in 2 cycles (when using xilinx dsp blocks!) Saved multiple cycles from fetch/memory load stages by short-cutting the start of memory requests. Compliant misaligned exceptions for jumps,loads and stores. Addrs starting 0xFxxxxxxx ignore alignment requests (assumes mmio space). Added CSRs for riscv-compliance requirements. Source ran through a formatter for ease of use.
302 lines
No EOL
14 KiB
VHDL
302 lines
No EOL
14 KiB
VHDL
----------------------------------------------------------------------------------
|
|
-- Project Name: RISC-V CPU
|
|
-- Description: decoder unit RV32I
|
|
--
|
|
----------------------------------------------------------------------------------
|
|
-- Copyright 2016,2018,2019,2020 Colin Riley
|
|
--
|
|
-- Licensed under the Apache License, Version 2.0 (the "License");
|
|
-- you may not use this file except in compliance with the License.
|
|
-- You may obtain a copy of the License at
|
|
--
|
|
-- http://www.apache.org/licenses/LICENSE-2.0
|
|
--
|
|
-- Unless required by applicable law or agreed to in writing, software
|
|
-- distributed under the License is distributed on an "AS IS" BASIS,
|
|
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
-- See the License for the specific language governing permissions and
|
|
-- limitations under the License.
|
|
----------------------------------------------------------------------------------
|
|
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
|
|
O_csrOP : out STD_LOGIC_VECTOR(4 downto 0); -- CSR operations
|
|
O_csrAddr : out STD_LOGIC_VECTOR(11 downto 0); -- CSR address
|
|
O_trapExit : out STD_LOGIC; -- request to exit trap handler
|
|
O_multycyAlu : out STD_LOGIC; -- is this a multi-cycle alu op?
|
|
O_int : out STD_LOGIC; -- is there a trap?
|
|
O_int_data : out STD_LOGIC_VECTOR (31 downto 0);-- trap descriptor
|
|
I_int_ack : in STD_LOGIC -- our int is now being serviced
|
|
);
|
|
end decoder_RV32;
|
|
|
|
architecture Behavioral of decoder_RV32 is
|
|
signal s_trapExit : STD_LOGIC := '0';
|
|
signal s_csrOP : STD_LOGIC_VECTOR(4 downto 0) := (others => '0');
|
|
signal s_csrAddr : STD_LOGIC_VECTOR(11 downto 0) := (others => '0');
|
|
signal s_int : STD_LOGIC := '0';
|
|
signal s_intdata : STD_LOGIC_VECTOR(31 downto 0) := (others => '0');
|
|
signal s_multicy : std_logic := '0';
|
|
begin
|
|
O_multycyAlu <= s_multicy;
|
|
O_int <= s_int;
|
|
O_int_data <= s_intdata;
|
|
O_csrOP <= s_csrOP;
|
|
O_csrAddr <= s_csrAddr;
|
|
O_trapExit <= s_trapExit;
|
|
|
|
-- 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) then
|
|
if 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 =>
|
|
s_multicy <= '0';
|
|
s_trapExit <= '0';
|
|
s_csrOP <= "00000";
|
|
s_int <= '0';
|
|
O_regDwe <= '1';
|
|
O_memOp <= "00000";
|
|
O_dataIMM <= I_dataInst(IMM_U_START downto IMM_U_END)
|
|
& "000000000000";
|
|
|
|
when OPCODE_AUIPC =>
|
|
s_multicy <= '0';
|
|
s_trapExit <= '0';
|
|
s_csrOP <= "00000";
|
|
s_int <= '0';
|
|
O_regDwe <= '1';
|
|
O_memOp <= "00000";
|
|
O_dataIMM <= I_dataInst(IMM_U_START downto IMM_U_END)
|
|
& "000000000000";
|
|
|
|
when OPCODE_JAL =>
|
|
s_multicy <= '0';
|
|
s_trapExit <= '0';
|
|
s_csrOP <= "00000";
|
|
s_int <= '0';
|
|
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 =>
|
|
s_multicy <= '0';
|
|
s_trapExit <= '0';
|
|
s_csrOP <= "00000";
|
|
s_int <= '0';
|
|
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 =>
|
|
s_multicy <= '0';
|
|
s_trapExit <= '0';
|
|
s_csrOP <= "00000";
|
|
s_int <= '0';
|
|
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_OP =>
|
|
s_trapExit <= '0';
|
|
s_csrOP <= "00000";
|
|
O_memOp <= "00000";
|
|
|
|
-- M based extension ops are multicycle, otherwise they are single-cycle
|
|
if (I_dataInst(FUNCT7_START downto FUNCT7_END) = F7_OP_M_EXT) then
|
|
s_multicy <= '1';
|
|
else
|
|
s_multicy <= '0';
|
|
end if;
|
|
|
|
s_int <= '0';
|
|
O_regDwe <= '1';
|
|
|
|
when OPCODE_LOAD =>
|
|
s_multicy <= '0';
|
|
-- Load's opcode is all 0s - but the first two bits of the word should be '11'
|
|
-- we check this here, because if we do not, null instructions will be treated as loads...
|
|
if I_dataInst(1 downto 0) = "11" then
|
|
s_trapExit <= '0';
|
|
s_csrOP <= "00000";
|
|
s_int <= '0';
|
|
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;
|
|
else
|
|
-- likely a null instruction - fault!
|
|
s_trapExit <= '0';
|
|
s_csrOP <= "00000";
|
|
s_int <= '1'; ---------------
|
|
s_intdata <= EXCEPTION_INSTRUCTION_ILLEGAL;
|
|
O_memOp <= "00000";
|
|
O_regDwe <= '0';
|
|
O_dataIMM <= I_dataInst(IMM_I_START downto IMM_S_B_END)
|
|
& "0000000";
|
|
end if;
|
|
|
|
when OPCODE_STORE =>
|
|
s_multicy <= '0';
|
|
s_trapExit <= '0';
|
|
s_csrOP <= "00000";
|
|
s_int <= '0';
|
|
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 =>
|
|
s_multicy <= '0';
|
|
s_trapExit <= '0';
|
|
s_csrOP <= "00000";
|
|
s_int <= '0';
|
|
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 =>
|
|
s_multicy <= '0';
|
|
s_trapExit <= '0';
|
|
s_csrOP <= "00000";
|
|
s_int <= '0';
|
|
O_regDwe <= '0';
|
|
O_memOp <= "01000";
|
|
O_dataIMM <= I_dataInst;
|
|
|
|
when OPCODE_SYSTEM =>
|
|
s_multicy <= '0';
|
|
O_memOp <= "00000";
|
|
if I_dataInst(FUNCT3_START downto FUNCT3_END) = F3_PRIVOP then
|
|
-- ECALL or EBREAK
|
|
case I_dataInst(IMM_I_START downto IMM_I_END) is
|
|
when IMM_I_SYSTEM_ECALL =>
|
|
-- raise trap, save pc, perform requiredCSR operations
|
|
s_trapExit <= '0';
|
|
s_csrOP <= "00000";
|
|
s_int <= '1';
|
|
O_regDwe <= '0';
|
|
s_intdata <= EXCEPTION_ENVIRONMENT_CALL_FROM_MMODE;
|
|
--todo: Priv level needs checked as to mask this to user/supervisor/machine level
|
|
when IMM_I_SYSTEM_EBREAK =>
|
|
s_trapExit <= '0';
|
|
s_csrOP <= "00000";
|
|
s_int <= '1';
|
|
s_intdata <= EXCEPTION_BREAKPOINT;
|
|
O_regDwe <= '0';
|
|
when F7_PRIVOP_MRET & R2_PRIV_RET =>
|
|
s_trapExit <= '1';
|
|
s_csrOP <= "00000";
|
|
s_int <= '0';
|
|
O_regDwe <= '0';
|
|
-- return from interrupt. implement as a branch - alu will branch to epc.
|
|
when others =>
|
|
end case;
|
|
else
|
|
s_trapExit <= '0';
|
|
s_int <= '0';
|
|
-- CSR
|
|
-- The immediate output is the zero-extended R1 value for Imm-form CSR ops
|
|
O_dataIMM <= X"000000" & "000" & I_dataInst(R1_START downto R1_END);
|
|
|
|
-- The 12bit immediate in the instruction forms the csr address.
|
|
s_csrAddr <= I_dataInst(IMM_I_START downto IMM_I_END);
|
|
|
|
-- is there a destination? if not, CSR is not read
|
|
if I_dataInst(RD_START downto RD_END) = "00000" then
|
|
s_csrOP(0) <= '0';
|
|
O_regDwe <= '0';
|
|
else
|
|
O_regDwe <= '1';
|
|
s_csrOP(0) <= '1';
|
|
end if;
|
|
|
|
-- is there source data? if not, CSR value is not written
|
|
-- is it's CSRRS/CSRRC/CSRRSI/CSRRCI ONLY! I.E (Func3 and 010) != 0
|
|
if (I_dataInst(FUNCT3_END + 1) = '1') and I_dataInst(R1_START downto R1_END) = "00000" then
|
|
s_csrOP(1) <= '0';
|
|
else
|
|
s_csrOP(1) <= '1';
|
|
end if;
|
|
|
|
s_csrOp(4 downto 2) <= I_dataInst(FUNCT3_START downto FUNCT3_END);
|
|
|
|
end if;
|
|
when others =>
|
|
s_multicy <= '0';
|
|
s_trapExit <= '0';
|
|
s_csrOP <= "00000";
|
|
s_int <= '1'; ---------------
|
|
s_intdata <= EXCEPTION_INSTRUCTION_ILLEGAL;
|
|
O_memOp <= "00000";
|
|
O_regDwe <= '0';
|
|
O_dataIMM <= I_dataInst(IMM_I_START downto IMM_S_B_END)
|
|
& "0000000";
|
|
end case;
|
|
elsif I_int_ack = '1' then
|
|
s_int <= '0';
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
end Behavioral; |