From 4d30208d6aea2d61d278799d61a0e00ef0e06441 Mon Sep 17 00:00:00 2001
From: Tristan Gingold <tristan.gingold@cern.ch>
Date: Thu, 9 Dec 2021 15:29:33 +0100
Subject: [PATCH] hydra_core: WIP to add ECC on IRAM

---
 hdl/rtl/hydra_core.vhd | 55 ++++++++++++++++++++++++++++++++----------
 1 file changed, 42 insertions(+), 13 deletions(-)

diff --git a/hdl/rtl/hydra_core.vhd b/hdl/rtl/hydra_core.vhd
index 259163b..427caab 100644
--- a/hdl/rtl/hydra_core.vhd
+++ b/hdl/rtl/hydra_core.vhd
@@ -31,6 +31,7 @@ use work.genram_pkg.all;
 --use work.memory_loader_pkg.all;
 use work.wishbone_pkg.all;
 use work.urv_pkg.all;
+use work.secded_32b_pkg.all;
 
 entity hydra_core is
   generic(
@@ -155,30 +156,58 @@ begin
   p_rom: process (clk_sys_i)
   is
     constant IRAM_WSIZE : natural := 2 ** (g_IRAM_LOG_SIZE - 2);
-    variable iram : t_ram32_type(0 to IRAM_WSIZE - 1);
+    type t_ram39_type is array(natural range <>) of std_logic_vector(38 downto 0);
+    variable iram : t_ram39_type(0 to IRAM_WSIZE - 1);
 --     := f_load_mem32_from_file ("../../../sw/fip_urv/fip_dbg.ram", IRAM_WSIZE, True);
-    variable addr : std_logic_vector (g_IRAM_LOG_SIZE - 1 downto 2);
+    variable addr : std_logic_vector (g_IRAM_LOG_SIZE + 1 downto 2);
+    variable data, wdata : std_logic_vector(38 downto 0);
+    variable syndrome : std_logic_vector(6 downto 0);
+    type state_t is (S_READ, S_REWRITE, S_WRITE);
+    variable state : state_t;
   begin
     if rising_edge(clk_sys_i) then
       if cpu_rst = '1' then
         if iram_we = '1' then
-          iram (to_integer(unsigned(iram_addr))) := iram_data;
+          iram (to_integer(unsigned(iram_addr))) := f_calc_ecc (iram_data) & iram_data;
         end if;
         im_valid <= '0';
         cpu_rst_d <= '1';
+        state := S_WRITE;
       else
         cpu_rst_d <= cpu_rst;
-        if reg_dm_load = '1' and reg_dm_is_wishbone = '0' and reg_dm_addr (16) = '0' then
-          --  Data read from iram
-          addr := reg_dm_addr(g_IRAM_LOG_SIZE - 1 downto 2);
-          im_valid <= '0';
-        else
-          --  Data read from dram.
-          addr := im_addr(g_IRAM_LOG_SIZE - 1 downto 2);
-          im_valid  <= (not cpu_rst_d);
-        end if;
-        im_data <= iram (to_integer(unsigned(addr)));
       end if;
+
+      case state is
+        when S_READ =>
+          if reg_dm_load = '1' and reg_dm_is_wishbone = '0' and reg_dm_addr (16) = '0' then
+            --  Data read from iram
+            addr := reg_dm_addr(g_IRAM_LOG_SIZE + 1 downto 2);
+            im_valid <= '0';
+          else
+            --  Data read from dram.
+            addr := im_addr(g_IRAM_LOG_SIZE + 1 downto 2);
+            im_valid  <= (not cpu_rst_d);
+          end if;
+          data := iram (to_integer(unsigned(addr)));
+          syndrome := data(38 downto 32) xor f_calc_ecc(data(31 downto 0));
+          im_data <= data(31 downto 0);
+          if f_ecc_errors(syndrome) = '1' then
+            im_valid <= '0';
+            --  id_valid <= '0';
+            state := S_REWRITE;
+          end if;
+        when S_WRITE | S_REWRITE =>
+          if cpu_rst = '1' and iram_we = '1' then
+            addr := iram_addr;
+            wdata := f_calc_ecc (iram_data) & iram_data;
+          else
+            wdata := f_fix_error (syndrome, data(38 downto 32), data(31 downto 0));
+          end if;
+          iram (to_integer(unsigned(iram_addr))) := wdata;
+          if cpu_rst = '0' then
+            state := S_READ;
+          end if;
+      end case;
     end if;
   end process;
 
-- 
GitLab