mirror of
https://github.com/Domipheus/RPU.git
synced 2025-04-18 19:15:13 -04:00
351 lines
12 KiB
VHDL
351 lines
12 KiB
VHDL
----------------------------------------------------------------------------------
|
|
-- 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;
|
|
|