Skip to content
Snippets Groups Projects
Commit 645cf505 authored by Tristan Gingold's avatar Tristan Gingold
Browse files

Add lock-step mode

parent fb094809
Branches
No related merge requests found
......@@ -83,15 +83,16 @@ architecture arch of hydra_core is
return x;
end function f_x_to_zero;
signal cpu_rst : std_logic;
signal cpu_rst : std_logic_vector(1 to 3);
signal cpu_rst_err : std_logic;
signal cpu_sync : std_logic_vector(1 to 3);
signal im_addr : std_logic_vector(31 downto 0);
signal im_data, im1_data : std_logic_vector(31 downto 0);
signal im_rd, im_valid : std_logic;
signal im1_done, im1_dm_en, im1_err : std_logic;
signal im2_err, im2_valid : std_logic;
signal err_cpu : std_logic;
signal err_cpu_dm : std_logic;
signal dm_addr, dm_data_s, dm_data_l : std_logic_vector(31 downto 0);
signal dm_data_select : std_logic_vector(3 downto 0);
......@@ -121,6 +122,8 @@ architecture arch of hydra_core is
signal nbr_dram_ecc_uncorr : std_logic_vector (31 downto 0);
signal iram_ecc_err, iram_ecc_fatal : std_logic;
signal dram_ecc_err, dram_ecc_fatal : std_logic;
signal nbr_cpu_data_err : std_logic_vector (31 downto 0);
signal nbr_cpu_iaddr_err : std_logic_vector (31 downto 0);
signal reset_cause_cpu, reset_cause_ecc, reset_cause_wd : std_logic;
signal dram_scrub_period, iram_scrub_period : std_logic_vector(15 downto 0);
......@@ -129,15 +132,19 @@ architecture arch of hydra_core is
signal wd_period_wr, wd_key_wr, wd_timeout : std_logic;
signal force_divergence, force_divergence_d, dm_force_divergence : std_logic;
begin
cpu_rst <= cpu_rst_err or (not cpu_rst_n_i);
signal cpu_wr : std_logic;
type t_state is (S_VOTER, S_LOCK);
signal state : t_state;
signal cpu_recovery, cpu_recovery_in : std_logic;
begin
dwb_o <= dwb_out;
U_cpu_core : entity work.hydra_triple_cpu
inst_cpus : entity work.hydra_triple_cpu
port map (
clk_i => clk_sys_i,
rst_i => cpu_rst,
cpu_rst_i => cpu_rst,
im_addr_o => im_addr,
im_rd_o => im_rd,
im_data_i => im_data,
......@@ -151,8 +158,9 @@ begin
dm_load_done_i => dm_load_done,
dm_store_done_i => dm_store_done,
cpu_sync_o => cpu_sync,
dm_force_divergence_i => dm_force_divergence,
err_cpu_o => err_cpu);
err_cpu_dm_o => err_cpu_dm);
-- Add registers on uRV data bus
process (clk_sys_i)
......@@ -170,7 +178,6 @@ begin
end if;
end process;
inst_iram: entity work.hydra_iram
generic map (
g_RAM_LOG_SIZE => g_IRAM_LOG_SIZE,
......@@ -416,7 +423,7 @@ begin
-- Timeout
wd_timeout <= '1';
wd_counter <= wd_period;
elsif cpu_rst = '1' or (wd_key_wr = '1' and wd_key_val = x"c0423bc9") then
elsif cpu_rst = "111" or (wd_key_wr = '1' and wd_key_val = x"c0423bc9") then
-- Key -> reload
-- Also restart the watchdog if the cpu is reset.
wd_counter <= wd_period;
......@@ -429,27 +436,8 @@ begin
end if;
end process;
-- Supervisor
p_sv: process (clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
reset_cause_cpu <= '0';
reset_cause_ecc <= '0';
reset_cause_wd <= '0';
cpu_rst_err <= '0';
else
cpu_rst_err <= '0';
if dram_ecc_fatal = '1' or iram_ecc_fatal = '1' or wd_timeout = '1' or err_cpu = '1' then
-- Reset CPU on error.
cpu_rst_err <= '1';
reset_cause_cpu <= err_cpu;
reset_cause_ecc <= dram_ecc_fatal or iram_ecc_fatal;
reset_cause_wd <= wd_timeout;
end if;
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;
inst_sv_regs: entity work.hydra_supervisor_regs
port map (
......@@ -460,9 +448,11 @@ begin
reset_cause_cpu_i => reset_cause_cpu,
reset_cause_ecc_i => reset_cause_ecc,
reset_cause_watchdog_i => reset_cause_wd,
cpu_status_i => "000",
cpu_status_i => cpu_rst,
cpu_boot_done_i => '0',
cpu_recovery_i => '0',
cpu_recovery_i => cpu_recovery,
cpu_recovery_o => cpu_recovery_in,
cpu_wr_o => cpu_wr,
force_divergence_i => x"00000000",
force_divergence_rd_o => force_divergence,
wd_period_i => wd_period,
......@@ -478,4 +468,51 @@ begin
iram_scrub_period_o => iram_scrub_period,
dram_scrub_period_o => dram_scrub_period
);
process (clk_sys_i) is
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' or cpu_rst_n_i = '0' then
state <= S_VOTER;
cpu_rst <= (others => '1');
cpu_recovery <= '0';
nbr_cpu_data_err <= (others => '0');
nbr_cpu_iaddr_err <= (others => '0');
reset_cause_cpu <= '0';
reset_cause_ecc <= '0';
reset_cause_wd <= '0';
else
case state is
when S_VOTER =>
cpu_rst <= "000";
-- Software can clear recovery flag.
if cpu_wr = '1' and cpu_recovery_in = '0' then
cpu_recovery <= '0';
end if;
if err_cpu_dm = '1' then
nbr_cpu_data_err <= std_logic_vector(unsigned(nbr_cpu_data_err) + 1);
end if;
if cpu_sync = "110" or cpu_sync = "101" or cpu_sync = "011" then
-- Disable the cpu out of sync.
cpu_rst <= not cpu_sync;
nbr_cpu_iaddr_err <= std_logic_vector(unsigned(nbr_cpu_iaddr_err) + 1);
state <= S_LOCK;
end if;
when S_LOCK =>
if cpu_wr = '1' and cpu_recovery_in = '1' then
cpu_recovery <= '1';
end if;
end case;
if cpu_sync = "000" or cpu_rst_err = '1' or (err_cpu_dm = '1' and state = S_LOCK) then
-- Fatal error
cpu_rst <= (others => '1');
reset_cause_cpu <= not cpu_rst_err;
reset_cause_ecc <= dram_ecc_fatal or iram_ecc_fatal;
reset_cause_wd <= wd_timeout;
state <= S_VOTER;
end if;
end if;
end if;
end process;
end arch;
......@@ -6,7 +6,7 @@ use work.urv_pkg.all;
entity hydra_triple_cpu is
port (
clk_i : in std_logic;
rst_i : in std_logic;
cpu_rst_i : in std_logic_vector(3 downto 1);
im_data_i : in std_logic_vector (31 downto 0);
im_valid_i : in std_logic;
im_addr_o : out std_logic_vector (31 downto 0);
......@@ -19,25 +19,27 @@ entity hydra_triple_cpu is
dm_data_select_o : out std_logic_vector (3 downto 0);
dm_store_o : out std_logic;
dm_load_o : out std_logic;
-- True when a cpu is in sync with at least another one.
-- (ie same outputs on the instruction bus)
cpu_sync_o : out std_logic_vector(3 downto 1);
-- If set, will give different values to each cpu.
dm_force_divergence_i : in std_logic;
-- Set to 1 if an output differs
err_cpu_o : out std_logic);
-- Set to 1 if an output differs on the data bus
err_cpu_dm_o : out std_logic);
end entity hydra_triple_cpu;
architecture arch of hydra_triple_cpu is
type t_slv32_x3 is array(1 to 3) of std_logic_vector(31 downto 0);
type t_slv4_x3 is array(1 to 3) of std_logic_vector(3 downto 0);
subtype t_sl_x3 is std_logic_vector(1 to 3);
subtype t_sl_x3 is std_logic_vector(3 downto 1);
signal im_addr, dm_addr, dm_data_s, dm_data_l : t_slv32_x3;
signal err_im_addr, err_dm_addr, err_dm_data_s : std_logic;
signal dm_data_select : t_slv4_x3;
signal err_dm_data_select : std_logic;
signal im_rd, dm_store, dm_load : t_sl_x3;
signal err_dm_store, err_dm_load, err_im_rd : std_logic;
signal en_im, en_dm_load, en_dm_store : std_logic;
signal ok_dm_addr, ok_dm_data, ok_dm_select, ok_dm_load, ok_dm_store, ok_dm : std_logic_vector(3 downto 1);
begin
gen_triple: for i in 1 to 3 generate
inst_cpu : urv_cpu
......@@ -49,7 +51,7 @@ begin
)
port map (
clk_i => clk_i,
rst_i => rst_i,
rst_i => cpu_rst_i(i),
irq_i => '0',
im_addr_o => im_addr(i),
im_rd_o => im_rd(i),
......@@ -82,7 +84,7 @@ begin
b => im_addr(2),
c => im_addr(3),
res => im_addr_o,
err => err_im_addr
err => open
);
inst_voter_dm_addr: entity work.voter_vec_status
......@@ -94,7 +96,7 @@ begin
b => dm_addr(2),
c => dm_addr(3),
res => dm_addr_o,
err => err_dm_addr
err => open
);
inst_voter_dm_data_s: entity work.voter_vec_status
......@@ -106,7 +108,7 @@ begin
b => dm_data_s(2),
c => dm_data_s(3),
res => dm_data_s_o,
err => err_dm_data_s
err => open
);
inst_voter_dm_data_select: entity work.voter_vec_status
......@@ -118,38 +120,71 @@ begin
b => dm_data_select(2),
c => dm_data_select(3),
res => dm_data_select_o,
err => err_dm_data_select
err => open
);
inst_voter_im_rd: entity work.voter_status
port map (
inp => im_rd,
res => im_rd_o,
err => err_im_rd
err => open
);
inst_voter_dm_load: entity work.voter_status
port map (
inp => dm_load,
res => dm_load_o,
err => err_dm_load
err => open
);
inst_voter_dm_store: entity work.voter_status
port map (
inp => dm_store,
res => dm_store_o,
err => err_dm_store
err => open
);
dm_data_l(1) <= dm_data_l_i when dm_force_divergence_i = '0' else x"0000_0001";
dm_data_l(2) <= dm_data_l_i when dm_force_divergence_i = '0' else x"0000_0002";
dm_data_l(3) <= dm_data_l_i when dm_force_divergence_i = '0' else x"0000_0004";
en_im <= im_rd(1) or im_rd(2) or im_rd(3);
en_dm_load <= dm_load(1) or dm_load(2) or dm_load(3);
en_dm_store <= dm_store(1) or dm_store(2) or dm_store(3);
err_cpu_o <= (en_im and err_im_addr) or err_im_rd
or ((en_dm_load or en_dm_store) and err_dm_addr)
or (en_dm_store and (err_dm_data_s or err_dm_data_select)) or err_dm_load or err_dm_store;
gen_s: for i in 0 to 2 generate
constant n0 : natural := 1 + i;
constant n1 : natural := 1 + (i + 1) mod 3;
constant n2 : natural := 1 + (i + 2) mod 3;
begin
cpu_sync_o(n0) <= '1' when cpu_rst_i(n0) = '1'
or (im_rd(n0) = '0' and (im_rd(n1) = '0' or im_rd(n2) = '0'))
or (im_rd(n0) = '1' and ((im_rd(n1) = '1' and im_addr(n1) = im_addr(n0))
or (im_rd(n2) = '1' and im_addr(n2) = im_addr(n0)))) else '0';
ok_dm_addr (n0) <= '1' when cpu_rst_i(n0) = '1'
or (dm_load(n0) = '0' and (dm_load(n1) = '0' or dm_load(n2) = '0'))
or (dm_store(n0) = '0' and (dm_store(n1) = '0' or dm_store(n2) = '0'))
or (((dm_load(n0) = '1' and dm_load(n1) = '1') or (dm_store(n0) = '1' and dm_store(n1) = '1'))
and dm_addr(n0) = dm_addr(n1))
or (((dm_load(n0) = '1' and dm_load(n2) = '1') or (dm_store(n0) = '1' and dm_store(n2) = '1'))
and dm_addr(n0) = dm_addr(n2))
else '0';
ok_dm_data (n0) <= '1' when cpu_rst_i(n0) = '1'
or (dm_store(n0) = '0' and (dm_store(n1) = '0' or dm_store(n2) = '0'))
or ((dm_store(n0) = '1' and dm_store(n1) = '1') and dm_data_s(n0) = dm_data_s(n1))
or ((dm_store(n0) = '1' and dm_store(n2) = '1') and dm_data_s(n0) = dm_data_s(n2))
else '0';
ok_dm_select (n0) <= '1' when cpu_rst_i(n0) = '1'
or (dm_store(n0) = '0' and (dm_store(n1) = '0' or dm_store(n2) = '0'))
or ((dm_store(n0) = '1' and dm_store(n1) = '1') and dm_data_select(n0) = dm_data_select(n1))
or ((dm_store(n0) = '1' and dm_store(n2) = '1') and dm_data_select(n0) = dm_data_select(n2))
else '0';
ok_dm_store (n0) <= '1' when cpu_rst_i(n0) = '1'
or (dm_store(n0) = dm_store(n1))
or (dm_store(n0) = dm_store(n2)) else '0';
ok_dm_load (n0) <= '1' when cpu_rst_i(n0) = '1'
or (dm_load(n0) = dm_load(n1))
or (dm_load(n0) = dm_load(n2)) else '0';
ok_dm (n0) <= ok_dm_addr(n0) and ok_dm_data(n0) and ok_dm_select(n0) and ok_dm_store(n0) and ok_dm_load(n0);
end generate;
err_cpu_dm_o <= '1' when ok_dm /= "111" else '0';
end arch;
......@@ -14,6 +14,29 @@
#define SUPERVISOR ((volatile struct hydra_supervisor_regs *)SUPERVISOR_BASE)
#define WD_KEY 0xc0423bc9
static enum t_test
{
TEST_WD,
TEST_CPU0_ERR
} cur_test;
static void
uart_init (void)
{
/* Unreset UART 0 */
*(volatile unsigned *)SYS_RESET &= 0xffffff7f;
/* Select baud. */
*(volatile unsigned *)UART_LCR = 0x80;
/* Set baudrate */
*(volatile unsigned *)UART_DLR = 0x36;
*(volatile unsigned *)UART_DMR = 0x00;
/* start operation. */
*(volatile unsigned *)UART_LCR = 0x03;
}
static void
uart_raw_putc (unsigned char c)
{
......@@ -88,24 +111,16 @@ ram_test(void)
int
main (void)
{
/* Unreset UART 0 */
*(volatile unsigned *)SYS_RESET &= 0xffffff7f;
/* Select baud. */
*(volatile unsigned *)UART_LCR = 0x80;
/* Set baudrate */
*(volatile unsigned *)UART_DLR = 0x36;
*(volatile unsigned *)UART_DMR = 0x00;
/* start operation. */
*(volatile unsigned *)UART_LCR = 0x03;
uart_init ();
uart_puts ("Rst: ");
unsigned v = SUPERVISOR->reset_cause;
uart_put_hex_digit (v & 0x0f);
uart_putc('\n');
/* On the first reset, v=0 (no cause), so watchdog won't be restarted
and will expire during ram test.
On later reset, there is always a reset cause. */
if (v)
SUPERVISOR->wd_key = WD_KEY;
......@@ -115,7 +130,22 @@ main (void)
uart_puts("Error\n");
}
/* Read a different value. */
/* Read a different value.
This will trigger a vote and a data error increment. */
v = SUPERVISOR->force_divergence;
uart_put_hex_digit(v & 0x0f);
/* Force divergence by executing different code. */
v = SUPERVISOR->force_divergence;
if (v != 1)
uart_putc('D');
/* Must be in lock-step. */
v = SUPERVISOR->cpu;
uart_put_hex_digit(v & 0x0f);
/* Force a data error in lock-step.
This will generate a reset. */
v = SUPERVISOR->force_divergence;
uart_put_hex_digit(v & 0x0f);
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment