diff --git a/hdl/rtl/hydra_core.vhd b/hdl/rtl/hydra_core.vhd index 31f191033278c5fae4b4c653340073c3c2611185..7ee1a1d03f8ded4425172a8ca8e55f29477033a1 100644 --- a/hdl/rtl/hydra_core.vhd +++ b/hdl/rtl/hydra_core.vhd @@ -48,9 +48,10 @@ entity hydra_core is dwb_i : in t_wishbone_master_in; -- IRAM write access (during reset) - iram_addr : in std_logic_vector(g_IRAM_LOG_SIZE - 1 downto 2); - iram_we : in std_logic; - iram_data : in std_logic_vector(31 downto 0); + iram_addr_i : in std_logic_vector(g_IRAM_LOG_SIZE - 1 downto 2); + iram_we_i : in std_logic; + iram_data_i : in std_logic_vector(31 downto 0); + iram_ecc_i : in std_logic_vector(6 downto 0); cpu_err_o : out std_logic ); @@ -120,10 +121,16 @@ architecture arch of hydra_core is signal nbr_iram_ecc_corr : std_logic_vector (31 downto 0); signal nbr_dram_ecc_corr : std_logic_vector (31 downto 0); - signal nbr_iram_ecc_uncorr : std_logic_vector (31 downto 0); - signal nbr_dram_ecc_uncorr : std_logic_vector (31 downto 0); + signal nbr_iram_scrub_corr : std_logic_vector (31 downto 0); + signal nbr_dram_scrub_corr : std_logic_vector (31 downto 0); + signal nbr_iram_scrub_uncorr : std_logic_vector (31 downto 0); + signal nbr_dram_scrub_uncorr : std_logic_vector (31 downto 0); signal iram_ecc_err, iram_ecc_fatal : std_logic; + signal iram_scrub_se, iram_scrub_de : std_logic; signal dram_ecc_err, dram_ecc_fatal : std_logic; + signal dram_scrub_se, dram_scrub_de : std_logic; + signal iram_scrub_en, dram_scrub_en : std_logic; + signal scrub_cfg_wr, scrub_cfg_iram_val, scrub_cfg_dram_val : std_logic; signal nbr_cpu_data_err : std_logic_vector (31 downto 0); signal nbr_cpu_iaddr_err : std_logic_vector (31 downto 0); @@ -147,7 +154,7 @@ begin dwb_o <= dwb_out; cpu_rst2 <= "111" when rst_n_i = '0' or cpu_rst_n_i = '0' else cpu_rst; - cpu_err_o <= '1' when cpu_rst /= "111" else '0'; + cpu_err_o <= '1' when cpu_rst /= "111" and cpu_rst /= "000" else '0'; inst_cpus : entity work.hydra_triple_cpu port map ( @@ -201,7 +208,7 @@ begin port map ( clk_i => clk_sys_i, rst_n_i => rst_n_i, - cpu_rst_n_i => cpu_rst_n_i, + scrub_en_i => iram_scrub_en, -- uRV data read from iRAM r1_addr_i => reg_dm_addr(g_IRAM_LOG_SIZE - 1 downto 2), @@ -218,14 +225,16 @@ begin r2_err_o => im2_err, -- iRAM initialization - waddr_i => iram_addr, - we_i => iram_we, - wdata_i => iram_data, - wforce_i => (others => '0'), + waddr_i => iram_addr_i, + we_i => iram_we_i, + wdata_i => iram_data_i, + wecc_i => iram_ecc_i, wdone_o => open, ecc_one_o => iram_ecc_err, ecc_fatal_o => iram_ecc_fatal, + scrub_se_o => iram_scrub_se, + scrub_de_o => iram_scrub_de, scrubber_period_i => iram_scrub_period ); @@ -265,6 +274,8 @@ begin err_o => dm_err, ecc_one_o => dram_ecc_err, ecc_fatal_o => dram_ecc_fatal, + scrub_se_o => dram_scrub_se, + scrub_de_o => dram_scrub_de, scrubber_period_i => dram_scrub_period ); @@ -406,20 +417,28 @@ begin if rst_n_i = '0' then nbr_iram_ecc_corr <= (others => '0'); nbr_dram_ecc_corr <= (others => '0'); - nbr_iram_ecc_uncorr <= (others => '0'); - nbr_dram_ecc_uncorr <= (others => '0'); + nbr_iram_scrub_corr <= (others => '0'); + nbr_dram_scrub_corr <= (others => '0'); + nbr_iram_scrub_uncorr <= (others => '0'); + nbr_dram_scrub_uncorr <= (others => '0'); else if iram_ecc_err = '1' then nbr_iram_ecc_corr <= std_logic_vector(unsigned(nbr_iram_ecc_corr) + 1); end if; - if iram_ecc_fatal = '1' then - nbr_iram_ecc_uncorr <= std_logic_vector(unsigned(nbr_iram_ecc_uncorr) + 1); + if iram_scrub_se = '1' then + nbr_iram_scrub_corr <= std_logic_vector(unsigned(nbr_iram_scrub_corr) + 1); + end if; + if iram_scrub_de = '1' then + nbr_iram_scrub_uncorr <= std_logic_vector(unsigned(nbr_iram_scrub_uncorr) + 1); end if; if dram_ecc_err = '1' then nbr_dram_ecc_corr <= std_logic_vector(unsigned(nbr_dram_ecc_corr) + 1); end if; - if dram_ecc_fatal = '1' then - nbr_dram_ecc_uncorr <= std_logic_vector(unsigned(nbr_dram_ecc_uncorr) + 1); + if dram_scrub_se = '1' then + nbr_dram_scrub_corr <= std_logic_vector(unsigned(nbr_dram_scrub_corr) + 1); + end if; + if dram_scrub_de = '1' then + nbr_dram_scrub_uncorr <= std_logic_vector(unsigned(nbr_dram_scrub_uncorr) + 1); end if; end if; end if; @@ -458,6 +477,20 @@ begin end if; end process; + -- Scrubbers enable + p_scrub_cfg: process (clk_sys_i) + begin + if rising_edge(clk_sys_i) then + if rst_n_i = '0' then + iram_scrub_en <= '0'; + dram_scrub_en <= '0'; + elsif scrub_cfg_wr = '1' then + iram_scrub_en <= iram_scrub_en or scrub_cfg_iram_val; + dram_scrub_en <= dram_scrub_en or scrub_cfg_dram_val; + end if; + end if; + end process; + -- Any fatal error that should reset cpus cpu_rst_err <= dram_ecc_fatal or iram_ecc_fatal or wd_timeout; @@ -484,11 +517,18 @@ begin wd_key_o => wd_key_val, wd_key_wr_o => wd_key_wr, iram_ecc_se_i => nbr_iram_ecc_corr, - iram_ecc_de_i => nbr_iram_ecc_uncorr, + iram_scrub_se_i => nbr_iram_scrub_corr, + iram_scrub_de_i => nbr_iram_scrub_uncorr, dram_ecc_se_i => nbr_dram_ecc_corr, - dram_ecc_de_i => nbr_dram_ecc_uncorr, + dram_scrub_se_i => nbr_dram_scrub_corr, + dram_scrub_de_i => nbr_dram_scrub_uncorr, cpu_data_err_i => nbr_cpu_data_err, cpu_iaddr_err_i => nbr_cpu_iaddr_err, + scrub_cfg_iram_en_i => iram_scrub_en, + scrub_cfg_iram_en_o => scrub_cfg_iram_val, + scrub_cfg_dram_en_i => dram_scrub_en, + scrub_cfg_dram_en_o => scrub_cfg_dram_val, + scrub_cfg_wr_o => scrub_cfg_wr, iram_scrub_period_o => iram_scrub_period, dram_scrub_period_o => dram_scrub_period ); diff --git a/hdl/rtl/hydra_dram.vhd b/hdl/rtl/hydra_dram.vhd index c0896bde08969abd9afa5d658a66695090fe097a..63d7a7d720083e2ca576e9ed3204ee84ebd7a1b2 100644 --- a/hdl/rtl/hydra_dram.vhd +++ b/hdl/rtl/hydra_dram.vhd @@ -53,6 +53,8 @@ entity hydra_dram is -- For statistics ecc_one_o : out std_logic; ecc_fatal_o : out std_logic; + scrub_se_o : out std_logic; + scrub_de_o : out std_logic; -- Scrubber scrubber_period_i : in std_logic_vector(15 downto 0) @@ -80,6 +82,7 @@ architecture arch of hydra_dram is signal scrub_counter : unsigned(15 downto 0); signal scrub_rd, scrub_done, scrub_done_d, n_scrub_done : std_logic; + signal n_scrub_de, n_scrub_se : std_logic; type state_t is (S_READ, S_REWRITE); signal state, n_state : state_t; @@ -172,6 +175,8 @@ begin n_ecc_one <= '0'; n_ecc_fatal <= '0'; + n_scrub_se <= '0'; + n_scrub_de <= '0'; n_state <= state; n_last_addr <= (others => 'X'); @@ -182,11 +187,13 @@ begin -- Write to fix it. if rerr_one = '1' then -- Correctable: correct it. - n_ecc_one <= '1'; + n_scrub_se <= scrub_done; + n_ecc_one <= p_done or r_done; wdata_ecc <= f_fix_error(rsyndrome, rdata_ecc(38 downto 32), rdata_ecc(31 downto 0)); else -- Uncorrectable. Just recompute the ECC to be able to continue. - n_ecc_fatal <= '1'; + n_scrub_de <= scrub_done; + n_ecc_fatal <= p_done or r_done; wdata_ecc <= recc & rdata_ecc(31 downto 0); end if; addr <= last_addr; @@ -223,7 +230,7 @@ begin if sel_i = "1111" then -- Full write wen <= '1'; - wdata_ecc <= (f_calc_ecc (data_i) & data_i); + wdata_ecc <= f_calc_ecc (data_i) & data_i; n_w_done <= '1'; else -- Partial write: first read the word @@ -273,6 +280,8 @@ begin ecc_one_o <= '0'; ecc_fatal_o <= '0'; + scrub_se_o <= '0'; + scrub_de_o <= '0'; else r_done_d <= r_done; r_done <= n_r_done; @@ -287,6 +296,8 @@ begin ecc_one_o <= n_ecc_one; ecc_fatal_o <= n_ecc_fatal; + scrub_se_o <= n_scrub_se; + scrub_de_o <= n_scrub_de; end if; w_done <= n_w_done; diff --git a/hdl/rtl/hydra_iram.vhd b/hdl/rtl/hydra_iram.vhd index 472a4bd9ac6a0b9c67b6f79c7b40e929ef18cbc9..9769951f39c2086aa3880f6ed2f1202b9a1f7f68 100644 --- a/hdl/rtl/hydra_iram.vhd +++ b/hdl/rtl/hydra_iram.vhd @@ -37,7 +37,9 @@ entity hydra_iram is -- Note: only writes are allowed during reset. clk_i : in std_logic; rst_n_i : in std_logic; - cpu_rst_n_i : in std_logic; + + -- Enable scrubber + scrub_en_i : in std_logic; -- Port 1: read access (high priority) -- RDONE_O is a pulse. @@ -59,13 +61,15 @@ entity hydra_iram is -- WFORCE_I are raw bits modified after ECC. Can be used to force an ECC error. waddr_i : in std_logic_vector(g_RAM_LOG_SIZE - 1 downto 2); we_i : in std_logic; - wforce_i : in std_logic_vector(38 downto 0); + wecc_i : in std_logic_vector(6 downto 0); wdata_i : in std_logic_vector(31 downto 0); wdone_o : out std_logic; -- For statistics ecc_one_o : out std_logic; ecc_fatal_o : out std_logic; + scrub_se_o : out std_logic; + scrub_de_o : out std_logic; -- Scrubber scrubber_period_i : in std_logic_vector(15 downto 0) @@ -91,6 +95,7 @@ architecture arch of hydra_iram is signal scrub_counter : unsigned(15 downto 0); signal scrub_rd, scrub_done, scrub_done_d, n_scrub_done : std_logic; + signal n_scrub_se, n_scrub_de : std_logic; type state_t is (S_READ, S_REWRITE); signal state, n_state : state_t; @@ -155,7 +160,7 @@ begin scrub_counter <= unsigned(scrubber_period_i); scrub_addr <= std_logic_vector(unsigned(scrub_addr) + 1); scrub_rd <= '0'; - else + elsif scrub_en_i = '1' then if scrub_counter = (scrub_counter'range => '0') then scrub_rd <= '1'; else @@ -167,8 +172,8 @@ begin end process; p_ctrl: process (state, r1_done, r2_done, rerr, rerr_one, rdata_ecc, rsyndrome, last_raddr, recc, - r1_en_i, r1_addr_i, we_i, waddr_i, wdata_i, wforce_i, r1_done_d, r2_done_d, - r2_en_i, r2_addr_i, scrub_rd, scrub_addr, scrub_done, scrub_done_d, cpu_rst_n_i) + r1_en_i, r1_addr_i, we_i, waddr_i, wdata_i, wecc_i, r1_done_d, r2_done_d, + r2_en_i, r2_addr_i, scrub_rd, scrub_addr, scrub_done, scrub_done_d, scrub_en_i) begin wen <= '0'; waddr <= (others => 'X'); @@ -182,6 +187,8 @@ begin n_ecc_one <= '0'; n_ecc_fatal <= '0'; + n_scrub_se <= '0'; + n_scrub_de <= '0'; n_state <= state; n_last_raddr <= (others => 'X'); @@ -192,11 +199,13 @@ begin -- Write to fix it. if rerr_one = '1' then -- Correctable: correct it. - n_ecc_one <= '1'; + n_scrub_se <= scrub_done; + n_ecc_one <= not scrub_done; wdata_ecc <= f_fix_error(rsyndrome, rdata_ecc(38 downto 32), rdata_ecc(31 downto 0)); else -- Uncorrectable. Just recompute the ECC to be able to continue. - n_ecc_fatal <= '1'; + n_scrub_de <= scrub_done; + n_ecc_fatal <= not scrub_done; wdata_ecc <= recc & rdata_ecc(31 downto 0); end if; waddr <= last_raddr; @@ -207,7 +216,7 @@ begin -- Write waddr <= waddr_i; wen <= '1'; - wdata_ecc <= (f_calc_ecc (wdata_i) & wdata_i) xor wforce_i; + wdata_ecc <= wecc_i & wdata_i; n_wdone <= '1'; n_state <= S_READ; elsif scrub_rd = '1' and scrub_done = '0' then @@ -228,7 +237,7 @@ begin ren <= '1'; n_r2_done <= '1'; n_last_raddr <= r2_addr_i; - elsif cpu_rst_n_i = '1' then + elsif scrub_en_i = '1' then -- scrub if idle (but not during reset, as write is high priority -- and is a single pulse). raddr <= scrub_addr; @@ -263,6 +272,8 @@ begin ecc_one_o <= '0'; ecc_fatal_o <= '0'; + scrub_se_o <= '0'; + scrub_de_o <= '0'; else r1_done_d <= r1_done; r1_done <= n_r1_done; @@ -276,6 +287,8 @@ begin ecc_one_o <= n_ecc_one; ecc_fatal_o <= n_ecc_fatal; + scrub_se_o <= n_scrub_se; + scrub_de_o <= n_scrub_de; end if; wdone <= n_wdone; diff --git a/hdl/rtl/hydra_supervisor_regs.cheby b/hdl/rtl/hydra_supervisor_regs.cheby index ee7701c819ef52594e6c34d7e8bbd639acb45887..31220e52d901cbbaadb13593896474c1c6df3650 100644 --- a/hdl/rtl/hydra_supervisor_regs.cheby +++ b/hdl/rtl/hydra_supervisor_regs.cheby @@ -73,8 +73,13 @@ memory-map: width: 32 access: ro - reg: - name: iram_ecc_de - description: Number of ECC uncorrectable errors for iram + name: iram_scrub_se + description: Number of ECC corrected errors by scrubber in iram + width: 32 + access: ro + - reg: + name: iram_scrub_de + description: Number of ECC uncorrected errors by scrubber in iram width: 32 access: ro - reg: @@ -83,8 +88,13 @@ memory-map: width: 32 access: ro - reg: - name: dram_ecc_de - description: Number of ECC uncorrectable errors for dram + name: dram_scrub_se + description: Number of ECC corrected errors by scrubber in dram + width: 32 + access: ro + - reg: + name: dram_scrub_de + description: Number of ECC uncorrected errors by scrubber in dram width: 32 access: ro - reg: @@ -98,25 +108,32 @@ memory-map: width: 32 access: ro - reg: - name: iram_scrub - description: Maximum number of cycles between a scrub + name: scrub_cfg + description: configuration of scrubbers width: 32 access: rw + x-hdl: + type: wire + write-strobe: True children: - field: - name: period - description: Watchdog timeout - range: 15-0 - preset: 2048 + name: iram_en + description: Write 1 to enable iram scrubber + range: 0 + - field: + name: dram_en + description: Write 1 to enable dram scrubber + range: 1 - reg: - name: dram_scrub + name: iram_scrub_period description: Maximum number of cycles between a scrub - width: 32 + width: 16 access: rw - children: - - field: - name: period - description: Watchdog timeout - range: 15-0 - preset: 2048 + preset: 2048 + - reg: + name: dram_scrub_period + description: Maximum number of cycles between a scrub + width: 16 + access: rw + preset: 2048 diff --git a/hdl/rtl/hydra_supervisor_regs.vhd b/hdl/rtl/hydra_supervisor_regs.vhd index 300e81d88a11442e20350d5582872806090a3f73..89b5d9cd9f0dc6974e31815318148666f87b0d7b 100644 --- a/hdl/rtl/hydra_supervisor_regs.vhd +++ b/hdl/rtl/hydra_supervisor_regs.vhd @@ -35,7 +35,7 @@ entity hydra_supervisor_regs is force_divergence_i : in std_logic_vector(31 downto 0); force_divergence_rd_o : out std_logic; - -- Nbr of cycles before watchdog timeout. Can be written once per reset + -- Nbr of cycles before watchdog timeout. wd_period_i : in std_logic_vector(31 downto 0); wd_period_o : out std_logic_vector(31 downto 0); wd_period_wr_o : out std_logic; @@ -50,14 +50,20 @@ entity hydra_supervisor_regs is -- Number of ECC correctable errors for iram iram_ecc_se_i : in std_logic_vector(31 downto 0); - -- Number of ECC uncorrectable errors for iram - iram_ecc_de_i : in std_logic_vector(31 downto 0); + -- Number of ECC corrected errors by scrubber in iram + iram_scrub_se_i : in std_logic_vector(31 downto 0); + + -- Number of ECC uncorrected errors by scrubber in iram + iram_scrub_de_i : in std_logic_vector(31 downto 0); -- Number of ECC correctable errors for dram dram_ecc_se_i : in std_logic_vector(31 downto 0); - -- Number of ECC uncorrectable errors for dram - dram_ecc_de_i : in std_logic_vector(31 downto 0); + -- Number of ECC corrected errors by scrubber in dram + dram_scrub_se_i : in std_logic_vector(31 downto 0); + + -- Number of ECC uncorrected errors by scrubber in dram + dram_scrub_de_i : in std_logic_vector(31 downto 0); -- Number of CPU errors on data bus cpu_data_err_i : in std_logic_vector(31 downto 0); @@ -65,18 +71,25 @@ entity hydra_supervisor_regs is -- Number of CPU errors on instruction bus cpu_iaddr_err_i : in std_logic_vector(31 downto 0); + -- configuration of scrubbers + -- Write 1 to enable iram scrubber + scrub_cfg_iram_en_i : in std_logic; + scrub_cfg_iram_en_o : out std_logic; + -- Write 1 to enable dram scrubber + scrub_cfg_dram_en_i : in std_logic; + scrub_cfg_dram_en_o : out std_logic; + scrub_cfg_wr_o : out std_logic; + -- Maximum number of cycles between a scrub - -- Watchdog timeout iram_scrub_period_o : out std_logic_vector(15 downto 0); -- Maximum number of cycles between a scrub - -- Watchdog timeout dram_scrub_period_o : out std_logic_vector(15 downto 0) ); end hydra_supervisor_regs; architecture syn of hydra_supervisor_regs is - signal adr_int : std_logic_vector(5 downto 2); + signal adr_int : std_logic_vector(6 downto 2); signal rd_req_int : std_logic; signal wr_req_int : std_logic; signal rd_ack_int : std_logic; @@ -90,21 +103,22 @@ architecture syn of hydra_supervisor_regs is signal wd_key_reg : std_logic_vector(31 downto 0); signal wd_key_wreq : std_logic; signal wd_key_wack : std_logic; + signal scrub_cfg_wreq : std_logic; signal iram_scrub_period_reg : std_logic_vector(15 downto 0); - signal iram_scrub_wreq : std_logic; - signal iram_scrub_wack : std_logic; + signal iram_scrub_period_wreq : std_logic; + signal iram_scrub_period_wack : std_logic; signal dram_scrub_period_reg : std_logic_vector(15 downto 0); - signal dram_scrub_wreq : std_logic; - signal dram_scrub_wack : std_logic; + signal dram_scrub_period_wreq : std_logic; + signal dram_scrub_period_wack : std_logic; signal rd_ack_d0 : std_logic; signal rd_dat_d0 : std_logic_vector(31 downto 0); signal wr_req_d0 : std_logic; - signal wr_adr_d0 : std_logic_vector(5 downto 2); + signal wr_adr_d0 : std_logic_vector(6 downto 2); signal wr_dat_d0 : std_logic_vector(31 downto 0); begin -- WB decode signals - adr_int <= wb_i.adr(5 downto 2); + adr_int <= wb_i.adr(6 downto 2); wb_en <= wb_i.cyc and wb_i.stb; process (clk_i) begin @@ -185,103 +199,124 @@ begin -- Register iram_ecc_se - -- Register iram_ecc_de + -- Register iram_scrub_se + + -- Register iram_scrub_de -- Register dram_ecc_se - -- Register dram_ecc_de + -- Register dram_scrub_se + + -- Register dram_scrub_de -- Register cpu_data_err -- Register cpu_iaddr_err - -- Register iram_scrub + -- Register scrub_cfg + scrub_cfg_iram_en_o <= wr_dat_d0(0); + scrub_cfg_dram_en_o <= wr_dat_d0(1); + scrub_cfg_wr_o <= scrub_cfg_wreq; + + -- Register iram_scrub_period iram_scrub_period_o <= iram_scrub_period_reg; process (clk_i) begin if rising_edge(clk_i) then if rst_n_i = '0' then iram_scrub_period_reg <= "0000100000000000"; - iram_scrub_wack <= '0'; + iram_scrub_period_wack <= '0'; else - if iram_scrub_wreq = '1' then + if iram_scrub_period_wreq = '1' then iram_scrub_period_reg <= wr_dat_d0(15 downto 0); end if; - iram_scrub_wack <= iram_scrub_wreq; + iram_scrub_period_wack <= iram_scrub_period_wreq; end if; end if; end process; - -- Register dram_scrub + -- Register dram_scrub_period dram_scrub_period_o <= dram_scrub_period_reg; process (clk_i) begin if rising_edge(clk_i) then if rst_n_i = '0' then dram_scrub_period_reg <= "0000100000000000"; - dram_scrub_wack <= '0'; + dram_scrub_period_wack <= '0'; else - if dram_scrub_wreq = '1' then + if dram_scrub_period_wreq = '1' then dram_scrub_period_reg <= wr_dat_d0(15 downto 0); end if; - dram_scrub_wack <= dram_scrub_wreq; + dram_scrub_period_wack <= dram_scrub_period_wreq; end if; end if; end process; -- Process for write requests. - process (wr_adr_d0, wr_req_d0, wd_key_wack, iram_scrub_wack, dram_scrub_wack) begin + process (wr_adr_d0, wr_req_d0, wd_key_wack, iram_scrub_period_wack, + dram_scrub_period_wack) begin cpu_wreq <= '0'; wd_period_wreq <= '0'; wd_key_wreq <= '0'; - iram_scrub_wreq <= '0'; - dram_scrub_wreq <= '0'; - case wr_adr_d0(5 downto 2) is - when "0000" => + scrub_cfg_wreq <= '0'; + iram_scrub_period_wreq <= '0'; + dram_scrub_period_wreq <= '0'; + case wr_adr_d0(6 downto 2) is + when "00000" => -- Reg reset_cause wr_ack_int <= wr_req_d0; - when "0001" => + when "00001" => -- Reg cpu cpu_wreq <= wr_req_d0; wr_ack_int <= wr_req_d0; - when "0010" => + when "00010" => -- Reg force_divergence wr_ack_int <= wr_req_d0; - when "0011" => + when "00011" => -- Reg wd_period wd_period_wreq <= wr_req_d0; wr_ack_int <= wr_req_d0; - when "0100" => + when "00100" => -- Reg wd_count wr_ack_int <= wr_req_d0; - when "0101" => + when "00101" => -- Reg wd_key wd_key_wreq <= wr_req_d0; wr_ack_int <= wd_key_wack; - when "0110" => + when "00110" => -- Reg iram_ecc_se wr_ack_int <= wr_req_d0; - when "0111" => - -- Reg iram_ecc_de + when "00111" => + -- Reg iram_scrub_se + wr_ack_int <= wr_req_d0; + when "01000" => + -- Reg iram_scrub_de wr_ack_int <= wr_req_d0; - when "1000" => + when "01001" => -- Reg dram_ecc_se wr_ack_int <= wr_req_d0; - when "1001" => - -- Reg dram_ecc_de + when "01010" => + -- Reg dram_scrub_se wr_ack_int <= wr_req_d0; - when "1010" => + when "01011" => + -- Reg dram_scrub_de + wr_ack_int <= wr_req_d0; + when "01100" => -- Reg cpu_data_err wr_ack_int <= wr_req_d0; - when "1011" => + when "01101" => -- Reg cpu_iaddr_err wr_ack_int <= wr_req_d0; - when "1100" => - -- Reg iram_scrub - iram_scrub_wreq <= wr_req_d0; - wr_ack_int <= iram_scrub_wack; - when "1101" => - -- Reg dram_scrub - dram_scrub_wreq <= wr_req_d0; - wr_ack_int <= dram_scrub_wack; + when "01110" => + -- Reg scrub_cfg + scrub_cfg_wreq <= wr_req_d0; + wr_ack_int <= wr_req_d0; + when "01111" => + -- Reg iram_scrub_period + iram_scrub_period_wreq <= wr_req_d0; + wr_ack_int <= iram_scrub_period_wack; + when "10000" => + -- Reg dram_scrub_period + dram_scrub_period_wreq <= wr_req_d0; + wr_ack_int <= dram_scrub_period_wack; when others => wr_ack_int <= wr_req_d0; end case; @@ -291,73 +326,88 @@ begin process (adr_int, rd_req_int, reset_cause_cpu_i, reset_cause_ecc_i, reset_cause_watchdog_i, cpu_reset_i, cpu_recovery_i, force_divergence_i, wd_period_i, wd_count_i, iram_ecc_se_i, - iram_ecc_de_i, dram_ecc_se_i, dram_ecc_de_i, cpu_data_err_i, - cpu_iaddr_err_i, iram_scrub_period_reg, dram_scrub_period_reg) begin + iram_scrub_se_i, iram_scrub_de_i, dram_ecc_se_i, dram_scrub_se_i, + dram_scrub_de_i, cpu_data_err_i, cpu_iaddr_err_i, scrub_cfg_iram_en_i, + scrub_cfg_dram_en_i, iram_scrub_period_reg, dram_scrub_period_reg) begin -- By default ack read requests rd_dat_d0 <= (others => 'X'); force_divergence_rd_o <= '0'; - case adr_int(5 downto 2) is - when "0000" => + case adr_int(6 downto 2) is + when "00000" => -- Reg reset_cause rd_ack_d0 <= rd_req_int; rd_dat_d0(0) <= reset_cause_cpu_i; rd_dat_d0(1) <= reset_cause_ecc_i; rd_dat_d0(2) <= reset_cause_watchdog_i; rd_dat_d0(31 downto 3) <= (others => '0'); - when "0001" => + when "00001" => -- Reg cpu rd_ack_d0 <= rd_req_int; rd_dat_d0(2 downto 0) <= cpu_reset_i; rd_dat_d0(7 downto 3) <= (others => '0'); rd_dat_d0(8) <= cpu_recovery_i; rd_dat_d0(31 downto 9) <= (others => '0'); - when "0010" => + when "00010" => -- Reg force_divergence force_divergence_rd_o <= rd_req_int; rd_ack_d0 <= rd_req_int; rd_dat_d0 <= force_divergence_i; - when "0011" => + when "00011" => -- Reg wd_period rd_ack_d0 <= rd_req_int; rd_dat_d0 <= wd_period_i; - when "0100" => + when "00100" => -- Reg wd_count rd_ack_d0 <= rd_req_int; rd_dat_d0 <= wd_count_i; - when "0101" => + when "00101" => -- Reg wd_key rd_ack_d0 <= rd_req_int; - when "0110" => + when "00110" => -- Reg iram_ecc_se rd_ack_d0 <= rd_req_int; rd_dat_d0 <= iram_ecc_se_i; - when "0111" => - -- Reg iram_ecc_de + when "00111" => + -- Reg iram_scrub_se rd_ack_d0 <= rd_req_int; - rd_dat_d0 <= iram_ecc_de_i; - when "1000" => + rd_dat_d0 <= iram_scrub_se_i; + when "01000" => + -- Reg iram_scrub_de + rd_ack_d0 <= rd_req_int; + rd_dat_d0 <= iram_scrub_de_i; + when "01001" => -- Reg dram_ecc_se rd_ack_d0 <= rd_req_int; rd_dat_d0 <= dram_ecc_se_i; - when "1001" => - -- Reg dram_ecc_de + when "01010" => + -- Reg dram_scrub_se + rd_ack_d0 <= rd_req_int; + rd_dat_d0 <= dram_scrub_se_i; + when "01011" => + -- Reg dram_scrub_de rd_ack_d0 <= rd_req_int; - rd_dat_d0 <= dram_ecc_de_i; - when "1010" => + rd_dat_d0 <= dram_scrub_de_i; + when "01100" => -- Reg cpu_data_err rd_ack_d0 <= rd_req_int; rd_dat_d0 <= cpu_data_err_i; - when "1011" => + when "01101" => -- Reg cpu_iaddr_err rd_ack_d0 <= rd_req_int; rd_dat_d0 <= cpu_iaddr_err_i; - when "1100" => - -- Reg iram_scrub + when "01110" => + -- Reg scrub_cfg + rd_ack_d0 <= rd_req_int; + rd_dat_d0(0) <= scrub_cfg_iram_en_i; + rd_dat_d0(1) <= scrub_cfg_dram_en_i; + rd_dat_d0(31 downto 2) <= (others => '0'); + when "01111" => + -- Reg iram_scrub_period rd_ack_d0 <= rd_req_int; rd_dat_d0(15 downto 0) <= iram_scrub_period_reg; rd_dat_d0(31 downto 16) <= (others => '0'); - when "1101" => - -- Reg dram_scrub + when "10000" => + -- Reg dram_scrub_period rd_ack_d0 <= rd_req_int; rd_dat_d0(15 downto 0) <= dram_scrub_period_reg; rd_dat_d0(31 downto 16) <= (others => '0'); diff --git a/hdl/top/sf2-test/sf2_test.vhd b/hdl/top/sf2-test/sf2_test.vhd index f7d72f1ca3fd2c8024869c9ab8f717ac3c0a8788..7a6a1173de5ce30bd9599dda3271e13c89f46dc3 100644 --- a/hdl/top/sf2-test/sf2_test.vhd +++ b/hdl/top/sf2-test/sf2_test.vhd @@ -3,6 +3,7 @@ use ieee.std_logic_1164.all; use ieee.numeric_std.all; use work.wishbone_pkg.all; +use work.secded_32b_pkg.all; --library smartfusion2; --use smartfusion2.all; @@ -71,6 +72,7 @@ architecture behav of sf2_test is signal iram_addr : std_logic_vector(IRAM_LOG_SIZE - 1 downto 2); signal iram_we : std_logic; signal iram_data : std_logic_vector(31 downto 0); + signal iram_ecc, iram_ecc_force : std_logic_vector(6 downto 0); signal cpu_rst_n : std_logic := '0'; @@ -91,9 +93,10 @@ begin cpu_rst_n_i => cpu_rst_n, dwb_o => dwb_out, dwb_i => dwb_in, - iram_addr => iram_addr, - iram_data => iram_data, - iram_we => iram_we, + iram_addr_i => iram_addr, + iram_data_i => iram_data, + iram_we_i => iram_we, + iram_ecc_i => iram_ecc, cpu_err_o => cpu_err ); @@ -159,6 +162,11 @@ begin iram_addr <= iahb_addr (IRAM_LOG_SIZE - 1 downto 2); iram_data <= ahb_rdata; + -- Compute ECC except for the last 4 words. + iram_ecc_force <= b"000_0000" when iahb_addr(IRAM_LOG_SIZE - 1 downto 4) /= (IRAM_LOG_SIZE - 1 downto 4 => '1') + else b"000_0001" when iahb_addr(2) = '0' + else b"000_0011"; + iram_ecc <= f_calc_ecc (ahb_rdata) xor iram_ecc_force; proc_init: process (clk_100) constant delay : unsigned(27 downto 0) := x"0c0_0000" diff --git a/sw/include/hydra_supervisor_regs.h b/sw/include/hydra_supervisor_regs.h index 3a9f1bdeb7565897e211e62ca6473b7fc00ec214..287492cfe5236c00a1b2362ce54f7ce510342f8f 100644 --- a/sw/include/hydra_supervisor_regs.h +++ b/sw/include/hydra_supervisor_regs.h @@ -1,6 +1,6 @@ #ifndef __CHEBY__HYDRA_SUPERVISOR_REGS__H__ #define __CHEBY__HYDRA_SUPERVISOR_REGS__H__ -#define HYDRA_SUPERVISOR_REGS_SIZE 56 /* 0x38 */ +#define HYDRA_SUPERVISOR_REGS_SIZE 66 /* 0x42 */ /* Cause of a reset */ #define HYDRA_SUPERVISOR_REGS_RESET_CAUSE 0x0UL @@ -17,9 +17,8 @@ /* Each cpu will read a different value from this registers */ #define HYDRA_SUPERVISOR_REGS_FORCE_DIVERGENCE 0x8UL -/* Nbr of cycles before watchdog timeout. Can be written once per reset */ +/* Nbr of cycles before watchdog timeout. */ #define HYDRA_SUPERVISOR_REGS_WD_PERIOD 0xcUL -#define HYDRA_SUPERVISOR_REGS_WD_PERIOD_PRESET 0x7d0UL /* Current counter value (decremented) */ #define HYDRA_SUPERVISOR_REGS_WD_COUNT 0x10UL @@ -30,30 +29,39 @@ /* Number of ECC correctable errors for iram */ #define HYDRA_SUPERVISOR_REGS_IRAM_ECC_SE 0x18UL -/* Number of ECC uncorrectable errors for iram */ -#define HYDRA_SUPERVISOR_REGS_IRAM_ECC_DE 0x1cUL +/* Number of ECC corrected errors by scrubber in iram */ +#define HYDRA_SUPERVISOR_REGS_IRAM_SCRUB_SE 0x1cUL + +/* Number of ECC uncorrected errors by scrubber in iram */ +#define HYDRA_SUPERVISOR_REGS_IRAM_SCRUB_DE 0x20UL /* Number of ECC correctable errors for dram */ -#define HYDRA_SUPERVISOR_REGS_DRAM_ECC_SE 0x20UL +#define HYDRA_SUPERVISOR_REGS_DRAM_ECC_SE 0x24UL + +/* Number of ECC corrected errors by scrubber in dram */ +#define HYDRA_SUPERVISOR_REGS_DRAM_SCRUB_SE 0x28UL -/* Number of ECC uncorrectable errors for dram */ -#define HYDRA_SUPERVISOR_REGS_DRAM_ECC_DE 0x24UL +/* Number of ECC uncorrected errors by scrubber in dram */ +#define HYDRA_SUPERVISOR_REGS_DRAM_SCRUB_DE 0x2cUL /* Number of CPU errors on data bus */ -#define HYDRA_SUPERVISOR_REGS_CPU_DATA_ERR 0x28UL +#define HYDRA_SUPERVISOR_REGS_CPU_DATA_ERR 0x30UL /* Number of CPU errors on instruction bus */ -#define HYDRA_SUPERVISOR_REGS_CPU_IADDR_ERR 0x2cUL +#define HYDRA_SUPERVISOR_REGS_CPU_IADDR_ERR 0x34UL + +/* configuration of scrubbers */ +#define HYDRA_SUPERVISOR_REGS_SCRUB_CFG 0x38UL +#define HYDRA_SUPERVISOR_REGS_SCRUB_CFG_IRAM_EN 0x1UL +#define HYDRA_SUPERVISOR_REGS_SCRUB_CFG_DRAM_EN 0x2UL /* Maximum number of cycles between a scrub */ -#define HYDRA_SUPERVISOR_REGS_IRAM_SCRUB 0x30UL -#define HYDRA_SUPERVISOR_REGS_IRAM_SCRUB_PERIOD_MASK 0xffffUL -#define HYDRA_SUPERVISOR_REGS_IRAM_SCRUB_PERIOD_SHIFT 0 +#define HYDRA_SUPERVISOR_REGS_IRAM_SCRUB_PERIOD 0x3cUL +#define HYDRA_SUPERVISOR_REGS_IRAM_SCRUB_PERIOD_PRESET 0x800UL /* Maximum number of cycles between a scrub */ -#define HYDRA_SUPERVISOR_REGS_DRAM_SCRUB 0x34UL -#define HYDRA_SUPERVISOR_REGS_DRAM_SCRUB_PERIOD_MASK 0xffffUL -#define HYDRA_SUPERVISOR_REGS_DRAM_SCRUB_PERIOD_SHIFT 0 +#define HYDRA_SUPERVISOR_REGS_DRAM_SCRUB_PERIOD 0x40UL +#define HYDRA_SUPERVISOR_REGS_DRAM_SCRUB_PERIOD_PRESET 0x800UL struct hydra_supervisor_regs { /* [0x0]: REG (ro) Cause of a reset */ @@ -65,7 +73,7 @@ struct hydra_supervisor_regs { /* [0x8]: REG (ro) Each cpu will read a different value from this registers */ uint32_t force_divergence; - /* [0xc]: REG (rw) Nbr of cycles before watchdog timeout. Can be written once per reset */ + /* [0xc]: REG (rw) Nbr of cycles before watchdog timeout. */ uint32_t wd_period; /* [0x10]: REG (ro) Current counter value (decremented) */ @@ -77,26 +85,38 @@ struct hydra_supervisor_regs { /* [0x18]: REG (ro) Number of ECC correctable errors for iram */ uint32_t iram_ecc_se; - /* [0x1c]: REG (ro) Number of ECC uncorrectable errors for iram */ - uint32_t iram_ecc_de; + /* [0x1c]: REG (ro) Number of ECC corrected errors by scrubber in iram */ + uint32_t iram_scrub_se; + + /* [0x20]: REG (ro) Number of ECC uncorrected errors by scrubber in iram */ + uint32_t iram_scrub_de; - /* [0x20]: REG (ro) Number of ECC correctable errors for dram */ + /* [0x24]: REG (ro) Number of ECC correctable errors for dram */ uint32_t dram_ecc_se; - /* [0x24]: REG (ro) Number of ECC uncorrectable errors for dram */ - uint32_t dram_ecc_de; + /* [0x28]: REG (ro) Number of ECC corrected errors by scrubber in dram */ + uint32_t dram_scrub_se; - /* [0x28]: REG (ro) Number of CPU errors on data bus */ + /* [0x2c]: REG (ro) Number of ECC uncorrected errors by scrubber in dram */ + uint32_t dram_scrub_de; + + /* [0x30]: REG (ro) Number of CPU errors on data bus */ uint32_t cpu_data_err; - /* [0x2c]: REG (ro) Number of CPU errors on instruction bus */ + /* [0x34]: REG (ro) Number of CPU errors on instruction bus */ uint32_t cpu_iaddr_err; - /* [0x30]: REG (rw) Maximum number of cycles between a scrub */ - uint32_t iram_scrub; + /* [0x38]: REG (rw) configuration of scrubbers */ + uint32_t scrub_cfg; + + /* [0x3c]: REG (rw) Maximum number of cycles between a scrub */ + uint16_t iram_scrub_period; + + /* padding to: 64 words */ + uint8_t __padding_0[2]; - /* [0x34]: REG (rw) Maximum number of cycles between a scrub */ - uint32_t dram_scrub; + /* [0x40]: REG (rw) Maximum number of cycles between a scrub */ + uint16_t dram_scrub_period; }; #endif /* __CHEBY__HYDRA_SUPERVISOR_REGS__H__ */ diff --git a/sw/sf2-test/Makefile b/sw/sf2-test/Makefile index e7ce6c0974d56924398ca5922ea3d65eb7686c4a..056586f4089ba45a68fa012390e619ad011f566d 100644 --- a/sw/sf2-test/Makefile +++ b/sw/sf2-test/Makefile @@ -21,7 +21,7 @@ main.o: main.c ${OBJCOPY} -O binary $< $@ %.mem: %.bin - ./tomem.py $< 1024 > $@ + ./tomem.py $< 2048 > $@ $(OUTPUT).elf: $(LDS) $(OBJS) ${XCC} $(CFLAGS) -o $@ -nostartfiles $(OBJS) -T $(LDS) -Wl,-Map=$(OUTPUT).map diff --git a/sw/sf2-test/main.c b/sw/sf2-test/main.c index a8e20000a2d8fe8a1978365a7775568078dd3899..914ecd04ad6d54dd256888e61eaa41ec70aba747 100644 --- a/sw/sf2-test/main.c +++ b/sw/sf2-test/main.c @@ -18,6 +18,7 @@ extern void clear_bss(void); static enum t_test { + TEST_ECC_DE, TEST_WD, TEST_CPU1_RECOVER, TEST_CPU2_RECOVER, @@ -49,8 +50,10 @@ uart_raw_putc (unsigned char c) { /* Wait until TEMT (transmit empty) is set. */ /* NB: bit 5 for RX not empty */ - while (!(*(volatile unsigned*)UART_LSR & 0x20)) + do { SUPERVISOR->wd_key = WD_KEY; + } while (!(*(volatile unsigned*)UART_LSR & 0x20)); + *(volatile unsigned *)UART_TX = c; } @@ -141,17 +144,25 @@ unreachable(void) int main (void) { + unsigned v; + SUPERVISOR->wd_key = WD_KEY; uart_init (); uart_puts ("Rst: "); - unsigned v = SUPERVISOR->reset_cause; + v = SUPERVISOR->reset_cause; uart_put_hex_digit (v & 0x0f); uart_puts (", tst: "); uart_put_hex_digit (next_test); uart_putc('\n'); switch (next_test) { + case TEST_ECC_DE: + next_test = TEST_WD; + v = *(volatile unsigned *)0xfffc; + unreachable(); + break; + case TEST_WD: /* Test watchdog - infinite loop */ next_test = TEST_CPU1_RECOVER;