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;