mirror of
https://github.com/xarc/harv.git
synced 2025-04-18 19:24:51 -04:00
268 lines
9.8 KiB
VHDL
268 lines
9.8 KiB
VHDL
library ieee;
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.numeric_std.all;
|
|
|
|
library work;
|
|
use work.harv_pkg.all;
|
|
|
|
entity control is
|
|
port (
|
|
-- input ports
|
|
-- processor status
|
|
imem_gnt_i : in std_logic;
|
|
imem_err_i : in std_logic;
|
|
dmem_gnt_i : in std_logic;
|
|
dmem_err_i : in std_logic;
|
|
dmem_sbu_i : in std_logic;
|
|
dmem_dbu_i : in std_logic;
|
|
|
|
-- instruction decode
|
|
opcode_i : in std_logic_vector(6 downto 0);
|
|
funct3_i : in std_logic_vector(2 downto 0);
|
|
funct7_i : in std_logic_vector(6 downto 0);
|
|
funct12_i : in std_logic_vector(11 downto 0);
|
|
|
|
-- sync
|
|
rstn_i : in std_logic;
|
|
clk_i : in std_logic;
|
|
start_i : in std_logic;
|
|
|
|
-- output ports
|
|
-- processor status
|
|
imem_req_o : out std_logic;
|
|
dmem_req_o : out std_logic;
|
|
|
|
update_pc_o : out std_logic;
|
|
trap_o : out std_logic;
|
|
|
|
-- ALU operations
|
|
aluop_o : out std_logic_vector(ALUOP_SIZE-1 downto 0);
|
|
alusrc_imm_o : out std_logic;
|
|
-- immediate selector
|
|
imm_shamt_o : out std_logic;
|
|
imm_up_o : out std_logic;
|
|
-- register file
|
|
regwr_o : out std_logic;
|
|
-- control transfer
|
|
inv_branch_o : out std_logic;
|
|
branch_o : out std_logic;
|
|
jump_o : out std_logic;
|
|
jalr_o : out std_logic;
|
|
ecall_o : out std_logic;
|
|
-- mem access
|
|
mem_rd_o : out std_logic;
|
|
mem_wr_o : out std_logic;
|
|
mem_ben_o : out std_logic_vector(1 downto 0);
|
|
mem_usgn_o : out std_logic; -- unsigned data
|
|
-- U type
|
|
load_upimm_o : out std_logic;
|
|
auipc_o : out std_logic;
|
|
-- csr control
|
|
csr_enable_o : out std_logic;
|
|
csr_source_imm_o : out std_logic;
|
|
csr_maskop_o : out std_logic;
|
|
csr_clearop_o : out std_logic
|
|
);
|
|
end entity;
|
|
|
|
architecture arch of control is
|
|
--------- PROCESSOR STATUS -----------
|
|
subtype proc_status_t is std_logic_vector(2 downto 0);
|
|
constant STAT_IDLE : proc_status_t := "000";
|
|
constant STAT_REQ_INSTR : proc_status_t := "001";
|
|
constant STAT_RUN : proc_status_t := "010";
|
|
constant STAT_DMEM_STALL : proc_status_t := "011";
|
|
constant STAT_UPDATE_PC : proc_status_t := "100";
|
|
constant STAT_TRAP : proc_status_t := "101";
|
|
|
|
signal proc_status_r : proc_status_t;
|
|
signal next_proc_status_w : proc_status_t;
|
|
|
|
-------- INSTRUCTION DECODE ----------
|
|
constant R : std_logic_vector(3 downto 0) := x"1";
|
|
constant I_jalr : std_logic_vector(3 downto 0) := x"2";
|
|
constant I_load : std_logic_vector(3 downto 0) := x"3";
|
|
constant I_arith : std_logic_vector(3 downto 0) := x"4";
|
|
constant I_fence : std_logic_vector(3 downto 0) := x"5";
|
|
constant I_system : std_logic_vector(3 downto 0) := x"6";
|
|
constant S : std_logic_vector(3 downto 0) := x"7";
|
|
constant B : std_logic_vector(3 downto 0) := x"8";
|
|
constant U_lui : std_logic_vector(3 downto 0) := x"9";
|
|
constant U_auipc : std_logic_vector(3 downto 0) := x"A";
|
|
constant U_jal : std_logic_vector(3 downto 0) := x"B";
|
|
|
|
signal instr_format_w : std_logic_vector(3 downto 0);
|
|
|
|
--- CSR TYPES ---
|
|
constant SYS_ECALL : std_logic_vector(2 downto 0) := "000";
|
|
constant SYS_CSRRW : std_logic_vector(2 downto 0) := "001"; -- Atomic Read/Write CSR
|
|
constant SYS_CSRRS : std_logic_vector(2 downto 0) := "010"; -- Atomic Read and Set Bits in CSR
|
|
constant SYS_CSRRC : std_logic_vector(2 downto 0) := "011"; -- Atomic Read and Clear Bits in CSR
|
|
constant SYS_CSRRWI : std_logic_vector(2 downto 0) := "101";
|
|
constant SYS_CSRRSI : std_logic_vector(2 downto 0) := "110";
|
|
constant SYS_CSRRCI : std_logic_vector(2 downto 0) := "111";
|
|
|
|
-- auxiliar signals
|
|
signal mem_wr_w : std_logic;
|
|
signal mem_rd_w : std_logic;
|
|
signal mem_req_w : std_logic;
|
|
|
|
-- signal rshift_op_w : std_logic_vector(ALUOP_SIZE-1 downto 0);
|
|
-- signal add_op_w : std_logic_vector(ALUOP_SIZE-1 downto 0);
|
|
signal shift_op_w : std_logic;
|
|
signal add_sub_op_w : std_logic;
|
|
signal aluop_w : std_logic_vector(ALUOP_SIZE-1 downto 0);
|
|
signal branch_op_w : std_logic_vector(ALUOP_SIZE-1 downto 0);
|
|
|
|
begin
|
|
------------------------- PROCESSOR STATUS ------------------------------
|
|
-- STAT_REQ_INSTR
|
|
imem_req_o <= '1' when proc_status_r = STAT_REQ_INSTR else '0';
|
|
|
|
-- STAT_DMEM_STALL
|
|
mem_req_w <= mem_rd_w or mem_wr_w;
|
|
dmem_req_o <= '1' when proc_status_r = STAT_DMEM_STALL else '0';
|
|
|
|
-- STAT_UPDATE_PC
|
|
update_pc_o <= '1' when proc_status_r = STAT_UPDATE_PC else
|
|
'1' when proc_status_r = STAT_TRAP else
|
|
'0';
|
|
trap_o <= '1' when proc_status_r = STAT_TRAP else '0';
|
|
|
|
|
|
PROC_CURRENT_STATUS : process(clk_i, rstn_i)
|
|
begin
|
|
if rstn_i = '0' then
|
|
proc_status_r <= STAT_IDLE;
|
|
elsif rising_edge(clk_i) then
|
|
proc_status_r <= next_proc_status_w;
|
|
end if;
|
|
end process;
|
|
|
|
PROC_NEXT_STATUS : process(proc_status_r, start_i, imem_gnt_i, imem_err_i, dmem_err_i, mem_req_w, dmem_gnt_i)
|
|
begin
|
|
case proc_status_r is
|
|
|
|
when STAT_IDLE =>
|
|
if start_i = '1' then
|
|
next_proc_status_w <= STAT_REQ_INSTR;
|
|
else
|
|
next_proc_status_w <= STAT_IDLE;
|
|
end if;
|
|
|
|
when STAT_REQ_INSTR =>
|
|
if imem_err_i = '1' then
|
|
next_proc_status_w <= STAT_IDLE;
|
|
|
|
elsif imem_gnt_i = '1' then
|
|
next_proc_status_w <= STAT_RUN;
|
|
|
|
else
|
|
next_proc_status_w <= STAT_REQ_INSTR;
|
|
end if;
|
|
|
|
when STAT_RUN =>
|
|
if mem_req_w = '1' then
|
|
next_proc_status_w <= STAT_DMEM_STALL;
|
|
else
|
|
next_proc_status_w <= STAT_UPDATE_PC;
|
|
end if;
|
|
|
|
when STAT_DMEM_STALL =>
|
|
if dmem_err_i = '1' then -- or dmem_sbu_i = '1' or dmem_dbu_i = '1' then
|
|
next_proc_status_w <= STAT_TRAP;
|
|
elsif dmem_gnt_i = '1' then
|
|
next_proc_status_w <= STAT_UPDATE_PC;
|
|
else
|
|
next_proc_status_w <= STAT_DMEM_STALL;
|
|
end if;
|
|
|
|
when STAT_UPDATE_PC =>
|
|
next_proc_status_w <= STAT_REQ_INSTR;
|
|
|
|
when STAT_TRAP =>
|
|
next_proc_status_w <= STAT_REQ_INSTR;
|
|
|
|
when others =>
|
|
next_proc_status_w <= STAT_TRAP;
|
|
|
|
end case;
|
|
end process;
|
|
|
|
------------------------ INSTRUCTIONS DECODE ----------------------------
|
|
with opcode_i select instr_format_w <=
|
|
R when "0110011",
|
|
I_jalr when "1100111",
|
|
I_load when "0000011",
|
|
I_arith when "0010011",
|
|
I_fence when "0001111",
|
|
I_system when "1110011",
|
|
S when "0100011",
|
|
B when "1100011",
|
|
U_lui when "0110111",
|
|
U_auipc when "0010111",
|
|
U_jal when "1101111",
|
|
(others => '0') when others;
|
|
--------------------------------- ALU -----------------------------------
|
|
|
|
with funct3_i(2 downto 1) select branch_op_w <=
|
|
ALU_XOR_OP when "00", -- beq or bne
|
|
ALU_SLT_OP when "10", -- blt or bge
|
|
ALU_SLTU_OP when "11", -- bltu or bgeu
|
|
ALU_XOR_OP when others; -- not in specification
|
|
|
|
shift_op_w <= '1' when funct3_i(1 downto 0) = "01" else '0';
|
|
add_sub_op_w <= '1' when funct3_i = "000" else '0';
|
|
|
|
aluop_w <= (funct7_i(5) and shift_op_w) & funct3_i when instr_format_w = I_arith else
|
|
(funct7_i(5) and (shift_op_w or add_sub_op_w)) & funct3_i when instr_format_w = R else
|
|
branch_op_w when instr_format_w = B else
|
|
ALU_ADD_OP; -- when instr_format_w = U_auipc, I_load, S
|
|
aluop_o <= aluop_w;
|
|
alusrc_imm_o <= '1' when instr_format_w /= R and instr_format_w /= B else '0';
|
|
|
|
------------------------ IMMEDIATE SELECTOR ------------------------------
|
|
-- instr[24:20]
|
|
imm_shamt_o <= '1' when (instr_format_w = I_arith or instr_format_w = R) and shift_op_w = '1' else '0';
|
|
-- instr[31:12] -> imm[31:12]
|
|
imm_up_o <= '1' when instr_format_w = U_lui or
|
|
instr_format_w = U_auipc else '0';
|
|
|
|
----------------------------- REGISTER FILE -------------------------------
|
|
regwr_o <= '1' when proc_status_r = STAT_UPDATE_PC and not (
|
|
instr_format_w = I_fence or
|
|
(instr_format_w = I_system and funct3_i = SYS_ECALL) or
|
|
instr_format_w = S or instr_format_w = I_load or
|
|
instr_format_w = B) else
|
|
'1' when proc_status_r = STAT_DMEM_STALL and
|
|
instr_format_w = I_load and
|
|
dmem_gnt_i = '1' else
|
|
'0';
|
|
|
|
--------------------------- CONTROL TRANSFER ------------------------------
|
|
inv_branch_o <= funct3_i(2) xor funct3_i(0);
|
|
branch_o <= '1' when instr_format_w = B else '0';
|
|
jump_o <= '1' when instr_format_w = U_jal or instr_format_w = I_jalr else '0';
|
|
jalr_o <= '1' when instr_format_w = I_jalr else '0';
|
|
|
|
ecall_o <= '0'; -- '1' when instr_format_w = I_system else
|
|
|
|
------------------------------ MEM ACCESS ---------------------------------
|
|
mem_rd_w <= '1' when instr_format_w = I_load else '0';
|
|
mem_rd_o <= mem_rd_w;
|
|
mem_wr_w <= '1' when instr_format_w = S else '0';
|
|
mem_wr_o <= mem_wr_w;
|
|
mem_ben_o <= funct3_i(1 downto 0) when funct3_i(1) = '0' else "11"; -- byte or halfword -- else word
|
|
mem_usgn_o <= funct3_i(2);
|
|
|
|
-------------------------------- U type -----------------------------------
|
|
load_upimm_o <= '1' when instr_format_w = U_lui else '0';
|
|
auipc_o <= '1' when instr_format_w = U_auipc else '0';
|
|
|
|
-------------------------- CSR instructions ------------------------------
|
|
csr_enable_o <= '1' when instr_format_w = I_system and funct3_i /= SYS_ECALL else '0';
|
|
csr_source_imm_o <= funct3_i(2); -- select source to write the CSR (immediate or register)
|
|
csr_maskop_o <= funct3_i(1); -- write operation based on mask
|
|
csr_clearop_o <= funct3_i(0); -- operation is CLEAR, if not, operation is SET
|
|
|
|
end architecture;
|