harv/hdl/csr.vhd
Douglas Santos 3dcef8bce8 HARV project
2021-06-17 17:23:41 +02:00

357 lines
13 KiB
VHDL

library ieee;
use ieee.std_logic_1164.all;
use ieee.math_real.ceil;
use ieee.math_real.log2;
use ieee.numeric_std.all;
entity csr is
generic (
TMR_CONTROL : boolean;
TMR_ALU : boolean;
HAMMING_REGFILE : boolean;
HAMMING_PC : boolean
);
port (
-- sync
rstn_i : in std_logic;
clk_i : in std_logic;
-- access interface
addr_i : in std_logic_vector(11 downto 0);
data_o : out std_logic_vector(31 downto 0);
rs1_data_i : in std_logic_vector(31 downto 0);
imm_data_i : in std_logic_vector(4 downto 0);
-- write control
wren_i : in std_logic;
source_imm_i : in std_logic;
csr_maskop_i : in std_logic;
csr_clearop_i : in std_logic;
-- trap handling
trap_i : in std_logic;
uscratch_i : in std_logic_vector(31 downto 0);
uepc_i : in std_logic_vector(31 downto 0);
ucause_i : in std_logic_vector(31 downto 0);
utval_i : in std_logic_vector(31 downto 0);
uip_i : in std_logic_vector(31 downto 0);
-- error counter inputs
reg1_cen_i : in std_logic;
reg1_sbu_i : in std_logic;
reg1_dbu_i : in std_logic;
reg2_cen_i : in std_logic;
reg2_sbu_i : in std_logic;
reg2_dbu_i : in std_logic;
pc_cen_i : in std_logic;
pc_sbu_i : in std_logic;
pc_dbu_i : in std_logic;
dmem_cen_i : in std_logic;
dmem_sbu_i : in std_logic;
dmem_dbu_i : in std_logic;
control_cen_i : in std_logic;
control_err_i : in std_logic;
alu_cen_i : in std_logic;
alu_err_i : in std_logic;
-- hardening configuration outputs
hard_pc_o : out std_logic;
hard_regfile_o : out std_logic;
hard_dmem_o : out std_logic;
hard_control_o : out std_logic;
hard_alu_o : out std_logic;
-- reset cause input
poweron_rstn_i : in std_logic;
wdt_rstn_i : in std_logic
);
end entity;
architecture arch of csr is
-- USER: Counter/Timers
constant CYCLE_ADDR : std_logic_vector(11 downto 0) := x"C00";
constant TIME_ADDR : std_logic_vector(11 downto 0) := x"C01";
constant INSTRET_ADDR : std_logic_vector(11 downto 0) := x"C02";
constant CYCLEH_ADDR : std_logic_vector(11 downto 0) := x"C80";
constant TIMEH_ADDR : std_logic_vector(11 downto 0) := x"C81";
constant INSTRETH_ADDR : std_logic_vector(11 downto 0) := x"C82";
-- USER: trap handling
constant USCRATCH_ADDR : std_logic_vector(11 downto 0) := x"040";
constant UEPC_ADDR : std_logic_vector(11 downto 0) := x"041";
constant UCAUSE_ADDR : std_logic_vector(11 downto 0) := x"042";
constant UTVAL_ADDR : std_logic_vector(11 downto 0) := x"043";
constant UIP_ADDR : std_logic_vector(11 downto 0) := x"044";
-- MACHINE: custom error counter registers
constant REG1_SBU_ADDR : std_logic_vector(11 downto 0) := x"7C0";
constant REG1_DBU_ADDR : std_logic_vector(11 downto 0) := x"7C1";
constant REG2_SBU_ADDR : std_logic_vector(11 downto 0) := x"7C2";
constant REG2_DBU_ADDR : std_logic_vector(11 downto 0) := x"7C3";
constant PC_SBU_ADDR : std_logic_vector(11 downto 0) := x"7C4";
constant PC_DBU_ADDR : std_logic_vector(11 downto 0) := x"7C5";
constant DMEM_SBU_ADDR : std_logic_vector(11 downto 0) := x"7C6";
constant DMEM_DBU_ADDR : std_logic_vector(11 downto 0) := x"7C7";
constant CONTROL_ERR_ADDR : std_logic_vector(11 downto 0) := x"7C8";
constant ALU_ERR_ADDR : std_logic_vector(11 downto 0) := x"7C9";
-- MACHINE: hardening configuration
constant HARDEN_CONF_ADDR : std_logic_vector(11 downto 0) := x"BC0";
-- MACHINE: information
constant MVENDORID_ADDR : std_logic_vector(11 downto 0) := x"F11";
constant MARCHID_ADDR : std_logic_vector(11 downto 0) := x"F12";
constant MIMPID_ADDR : std_logic_vector(11 downto 0) := x"F13";
constant MHARTID_ADDR : std_logic_vector(11 downto 0) := x"F14";
-- MACHINE: reset cause
constant RSTCAUSE_ADDR : std_logic_vector(11 downto 0) := x"FC0";
-- Registers from unprivileged specification -- except float CSR
signal cycle_r : std_logic_vector(31 downto 0); -- read by RDCYCLE
signal time_r : std_logic_vector(31 downto 0); -- read by RDTIME
signal instret_r : std_logic_vector(31 downto 0); -- read by RDINSTRET
signal cycleh_r : std_logic_vector(31 downto 0); -- read by RDCYCLEH
signal timeh_r : std_logic_vector(31 downto 0); -- read by RDTIMEH
signal instreth_r : std_logic_vector(31 downto 0); -- read by RDINSTRETH
-- Registers for trap handling
signal uscratch_r : std_logic_vector(31 downto 0); --at 0x040
signal uepc_r : std_logic_vector(31 downto 0); --at 0x041
signal ucause_r : std_logic_vector(31 downto 0); --at 0x042
signal utval_r : std_logic_vector(31 downto 0); --at 0x043
signal uip_r : std_logic_vector(31 downto 0); --at 0x044
-- Registers for error counting
signal reg1_sbu_r : std_logic_vector(31 downto 0); -- at 0x7C0
signal reg1_dbu_r : std_logic_vector(31 downto 0); -- at 0x7C1
signal reg2_sbu_r : std_logic_vector(31 downto 0); -- at 0x7C2
signal reg2_dbu_r : std_logic_vector(31 downto 0); -- at 0x7C3
signal pc_sbu_r : std_logic_vector(31 downto 0); -- at 0x7C4
signal pc_dbu_r : std_logic_vector(31 downto 0); -- at 0x7C5
signal dmem_sbu_r : std_logic_vector(31 downto 0); -- at 0x7C6
signal dmem_dbu_r : std_logic_vector(31 downto 0); -- at 0x7C7
signal control_err_r : std_logic_vector(31 downto 0); -- at 0x7C8
signal alu_err_r : std_logic_vector(31 downto 0); -- at 0x7C9
-- Register for hardening flags
signal harden_conf_r : std_logic_vector(31 downto 0); -- at 0xBC0
-- Registers for information registers
signal mvendorid_r : std_logic_vector(31 downto 0);
signal marchid_r : std_logic_vector(31 downto 0);
signal mimpid_r : std_logic_vector(31 downto 0);
signal mhartid_r : std_logic_vector(31 downto 0);
-- Register for reset cause
signal rstcause_r : std_logic_vector(31 downto 0);
-- write and read signals
signal wdata_w : std_logic_vector(31 downto 0);
signal rdata_w : std_logic_vector(31 downto 0);
-- auxiliar signals
signal mask_w : std_logic_vector(31 downto 0);
signal cleared_data_w : std_logic_vector(31 downto 0);
signal setted_data_w : std_logic_vector(31 downto 0);
signal maskop_res_w : std_logic_vector(31 downto 0);
begin
rdata_w <= cycle_r when addr_i = CYCLE_ADDR else
time_r when addr_i = TIME_ADDR else
instret_r when addr_i = INSTRET_ADDR else
cycleh_r when addr_i = CYCLEH_ADDR else
timeh_r when addr_i = TIMEH_ADDR else
instreth_r when addr_i = INSTRETH_ADDR else
-- USER TRAP
uscratch_r when addr_i = USCRATCH_ADDR else
uepc_r when addr_i = UEPC_ADDR else
ucause_r when addr_i = UCAUSE_ADDR else
utval_r when addr_i = UTVAL_ADDR else
uip_r when addr_i = UIP_ADDR else
-- MACHINE INFORMATION
mvendorid_r when addr_i = MVENDORID_ADDR else
marchid_r when addr_i = MARCHID_ADDR else
mimpid_r when addr_i = MIMPID_ADDR else
mhartid_r when addr_i = MHARTID_ADDR else
-- MACHINE HARDENING CONFIGURATION
harden_conf_r when addr_i = HARDEN_CONF_ADDR else
-- MACHINE RSTCAUSE
rstcause_r when addr_i = RSTCAUSE_ADDR else
-- CUSTOM ERROR
reg1_sbu_r when addr_i = REG1_SBU_ADDR else
reg1_dbu_r when addr_i = REG1_DBU_ADDR else
reg2_sbu_r when addr_i = REG2_SBU_ADDR else
reg2_dbu_r when addr_i = REG2_DBU_ADDR else
pc_sbu_r when addr_i = PC_SBU_ADDR else
pc_dbu_r when addr_i = PC_DBU_ADDR else
dmem_sbu_r when addr_i = DMEM_SBU_ADDR else
dmem_dbu_r when addr_i = DMEM_DBU_ADDR else
control_err_r when addr_i = CONTROL_ERR_ADDR else
alu_err_r when addr_i = ALU_ERR_ADDR else
x"deadbeef";
data_o <= rdata_w;
-- define data to be written
mask_w <= ((31 downto 5 => '0') & imm_data_i) when source_imm_i = '1' else rs1_data_i;
cleared_data_w <= rdata_w and (not mask_w);
setted_data_w <= rdata_w or mask_w;
maskop_res_w <= cleared_data_w when csr_clearop_i = '1' else setted_data_w;
-- select data that will be written
wdata_w <= maskop_res_w when csr_maskop_i = '1' else rs1_data_i;
--------------------------------------------------------------------------------------
--------------------------------------- CSRs -----------------------------------------
--------------------------------------------------------------------------------------
p_CYCLE_COUNT : process(clk_i, rstn_i)
begin
if rstn_i = '0' then
cycle_r <= (others => '0');
cycleh_r <= (others => '0');
elsif rising_edge(clk_i) then
-- increment cycle
cycle_r <= std_logic_vector(unsigned(cycle_r) + 1);
-- in case of cycle_r overflow, increase cycleh_r
if cycle_r = x"FFFFFFFF" then
cycleh_r <= std_logic_vector(unsigned(cycleh_r) + 1);
end if;
end if;
end process;
p_TIME_COUNT : process(clk_i, rstn_i)
begin
if rstn_i = '0' then
time_r <= (others => '0');
timeh_r <= (others => '0');
elsif rising_edge(clk_i) then
-- increment time
time_r <= std_logic_vector(unsigned(time_r) + 1);
-- in case of time_r overflow, increase timeh_r
if time_r = x"FFFFFFFF" then
timeh_r <= std_logic_vector(unsigned(timeh_r) + 1);
end if;
end if;
end process;
p_TRAP_REGISTERS : process(clk_i)
begin
if rising_edge(clk_i) then
if trap_i = '1' then
uscratch_r <= uscratch_i;
uepc_r <= uepc_i;
ucause_r <= ucause_i;
utval_r <= utval_i;
uip_r <= uip_i;
end if;
end if;
end process;
-- information registers
mvendorid_r <= x"CAFECAFE";
marchid_r <= x"000000CA";
mimpid_r(31 downto 6) <= (others => '0');
mimpid_r( 3 downto 2) <= (others => '0');
mimpid_r(0) <= '1' when HAMMING_PC else '0';
mimpid_r(1) <= '1' when HAMMING_REGFILE else '0';
mimpid_r(4) <= '1' when TMR_CONTROL else '0';
mimpid_r(5) <= '1' when TMR_ALU else '0';
mhartid_r <= x"00000000";
p_RSTCAUSE : process(poweron_rstn_i, wdt_rstn_i)
begin
if poweron_rstn_i = '0' then
rstcause_r <= x"00000001";
elsif wdt_rstn_i = '0' then
rstcause_r <= x"00000002";
end if;
end process;
p_HARDENING : process(clk_i)
begin
if rising_edge(clk_i) then
if wren_i = '1' and addr_i = HARDEN_CONF_ADDR then
harden_conf_r <= wdata_w;
end if;
end if;
end process;
-- Hamming
hard_pc_o <= harden_conf_r(0);
hard_regfile_o <= harden_conf_r(1);
hard_dmem_o <= harden_conf_r(2);
-- TMR
hard_control_o <= harden_conf_r(4);
hard_alu_o <= harden_conf_r(5);
p_ERROR_COUNT : process(clk_i)
begin
if rising_edge(clk_i) then
-- Register file upsets
if wren_i = '1' and addr_i = REG1_SBU_ADDR then
reg1_sbu_r <= wdata_w;
elsif reg1_cen_i = '1' and reg1_sbu_i = '1' then
reg1_sbu_r <= std_logic_vector(unsigned(reg1_sbu_r)+1);
end if;
if wren_i = '1' and addr_i = REG1_DBU_ADDR then
reg1_dbu_r <= wdata_w;
elsif reg1_cen_i = '1' and reg1_dbu_i = '1' then
reg1_dbu_r <= std_logic_vector(unsigned(reg1_dbu_r)+1);
end if;
-- Register file upsets
if wren_i = '1' and addr_i = REG2_SBU_ADDR then
reg2_sbu_r <= wdata_w;
elsif reg2_cen_i = '1' and reg2_sbu_i = '1' then
reg2_sbu_r <= std_logic_vector(unsigned(reg2_sbu_r)+1);
end if;
if wren_i = '1' and addr_i = REG2_DBU_ADDR then
reg2_dbu_r <= wdata_w;
elsif reg2_cen_i = '1' and reg2_dbu_i = '1' then
reg2_dbu_r <= std_logic_vector(unsigned(reg2_dbu_r)+1);
end if;
-- PC upsets
if wren_i = '1' and addr_i = PC_SBU_ADDR then
pc_sbu_r <= wdata_w;
elsif pc_cen_i = '1' and pc_sbu_i = '1' then
pc_sbu_r <= std_logic_vector(unsigned(pc_sbu_r)+1);
end if;
if wren_i = '1' and addr_i = PC_DBU_ADDR then
pc_dbu_r <= wdata_w;
elsif pc_cen_i = '1' and pc_dbu_i = '1' then
pc_dbu_r <= std_logic_vector(unsigned(pc_dbu_r)+1);
end if;
-- Data memory upsets
if wren_i = '1' and addr_i = DMEM_SBU_ADDR then
dmem_sbu_r <= wdata_w;
elsif dmem_cen_i = '1' and dmem_sbu_i = '1' then
dmem_sbu_r <= std_logic_vector(unsigned(dmem_sbu_r)+1);
end if;
if wren_i = '1' and addr_i = DMEM_DBU_ADDR then
dmem_dbu_r <= wdata_w;
elsif dmem_cen_i = '1' and dmem_dbu_i = '1' then
dmem_dbu_r <= std_logic_vector(unsigned(dmem_dbu_r)+1);
end if;
-- CONTROL errors
if wren_i = '1' and addr_i = CONTROL_ERR_ADDR then
control_err_r <= wdata_w;
elsif control_cen_i = '1' and control_err_i = '1' then
control_err_r <= std_logic_vector(unsigned(control_err_r)+1);
end if;
-- ALU errors
if wren_i = '1' and addr_i = ALU_ERR_ADDR then
alu_err_r <= wdata_w;
elsif alu_cen_i = '1' and alu_err_i = '1' then
alu_err_r <= std_logic_vector(unsigned(alu_err_r)+1);
end if;
end if;
end process;
end architecture;