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

Add hydra_ram.vhd

parent 4d30208d
Branches
No related merge requests found
...@@ -43,7 +43,8 @@ entity hydra_core is ...@@ -43,7 +43,8 @@ entity hydra_core is
dwb_o : out t_wishbone_master_out; dwb_o : out t_wishbone_master_out;
dwb_i : in t_wishbone_master_in; dwb_i : in t_wishbone_master_in;
iram_addr : in std_logic_vector(g_IRAM_LOG_SIZE + 1 downto 2); -- IRAM write access (during reset)
iram_addr : in std_logic_vector(g_IRAM_LOG_SIZE - 1 downto 2);
iram_we : in std_logic; iram_we : in std_logic;
iram_data : in std_logic_vector(31 downto 0) iram_data : in std_logic_vector(31 downto 0)
); );
...@@ -79,11 +80,11 @@ architecture arch of hydra_core is ...@@ -79,11 +80,11 @@ architecture arch of hydra_core is
end function f_x_to_zero; end function f_x_to_zero;
signal cpu_rst : std_logic; signal cpu_rst : std_logic;
signal cpu_rst_d : std_logic;
signal im_addr : std_logic_vector(31 downto 0); signal im_addr : std_logic_vector(31 downto 0);
signal im_data : std_logic_vector(31 downto 0); signal im_data, im1_data : std_logic_vector(31 downto 0);
signal im_valid : std_logic; signal im_rd, im_valid : std_logic;
signal im1_done, im1_dm_en, im1_err : std_logic;
signal dm_addr, dm_data_s, dm_data_l : std_logic_vector(31 downto 0); 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); signal dm_data_select : std_logic_vector(3 downto 0);
...@@ -116,6 +117,7 @@ begin ...@@ -116,6 +117,7 @@ begin
rst_i => cpu_rst, rst_i => cpu_rst,
irq_i => '0', irq_i => '0',
im_addr_o => im_addr, im_addr_o => im_addr,
im_rd_o => im_rd,
im_data_i => im_data, im_data_i => im_data,
im_valid_i => im_valid, im_valid_i => im_valid,
dm_addr_o => dm_addr, dm_addr_o => dm_addr,
...@@ -153,63 +155,34 @@ begin ...@@ -153,63 +155,34 @@ begin
end if; end if;
end process; end process;
p_rom: process (clk_sys_i) im1_dm_en <= '1' when reg_dm_load = '1' and reg_dm_is_wishbone = '0' and reg_dm_addr (16) = '0' else '0';
is
constant IRAM_WSIZE : natural := 2 ** (g_IRAM_LOG_SIZE - 2);
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 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))) := 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;
end if;
case state is inst_rom: entity work.hydra_ram
when S_READ => generic map (
if reg_dm_load = '1' and reg_dm_is_wishbone = '0' and reg_dm_addr (16) = '0' then g_RAM_LOG_SIZE => g_IRAM_LOG_SIZE
-- Data read from iram )
addr := reg_dm_addr(g_IRAM_LOG_SIZE + 1 downto 2); port map (
im_valid <= '0'; clk_i => clk_sys_i,
else rst_n_i => rst_n_i,
-- Data read from dram.
addr := im_addr(g_IRAM_LOG_SIZE + 1 downto 2); r1_addr_i => reg_dm_addr(g_IRAM_LOG_SIZE - 1 downto 2),
im_valid <= (not cpu_rst_d); r1_en_i => im1_dm_en,
end if; r1_data_o => im1_data,
data := iram (to_integer(unsigned(addr))); r1_done_o => im1_done,
syndrome := data(38 downto 32) xor f_calc_ecc(data(31 downto 0)); r1_err_o => im1_err,
im_data <= data(31 downto 0);
if f_ecc_errors(syndrome) = '1' then r2_addr_i => im_addr(g_IRAM_LOG_SIZE - 1 downto 2),
im_valid <= '0'; r2_en_i => im_rd, --rst_n_i,
-- id_valid <= '0'; r2_data_o => im_data,
state := S_REWRITE; r2_done_o => im_valid,
end if;
when S_WRITE | S_REWRITE => waddr_i => iram_addr,
if cpu_rst = '1' and iram_we = '1' then we_i => iram_we,
addr := iram_addr; wdata_i => iram_data,
wdata := f_calc_ecc (iram_data) & iram_data; wforce_i => (others => '0'),
else
wdata := f_fix_error (syndrome, data(38 downto 32), data(31 downto 0)); scrubber_period_i => x"0010"
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;
-- 1st MByte of the mem is the RAM -- 1st MByte of the mem is the RAM
-- 1st 64KB is the IRAM. -- 1st 64KB is the IRAM.
......
--------------------------------------------------------------------------------
-- CERN BE-CO-HT
-- Mock Turtle
-- https://gitlab.cern.ch/coht/mockturtle
--------------------------------------------------------------------------------
--
-- unit name: hydra_ram
--
-- description: a 32b RAM for rad-tol systems (with ECC and scrubing)
-- 2 ports: 1 ro, 1 wo.
--
--------------------------------------------------------------------------------
-- Copyright CERN 2014-2018
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.secded_32b_pkg.all;
entity hydra_ram is
generic(
g_RAM_LOG_SIZE : natural := 12); -- In bytes
port(
-- Note: only writes are allowed during reset.
clk_i : in std_logic;
rst_n_i : in std_logic;
-- Port 1: read access (high priority)
-- RDONE_O is a pulse.
r1_addr_i : in std_logic_vector(g_RAM_LOG_SIZE - 1 downto 2);
r1_en_i : in std_logic;
r1_data_o : out std_logic_vector(31 downto 0);
r1_done_o : out std_logic;
r1_err_o : out std_logic;
-- Port 2: read access (low priority)
-- RDONE_O is a pulse.
r2_addr_i : in std_logic_vector(g_RAM_LOG_SIZE - 1 downto 2);
r2_en_i : in std_logic;
r2_data_o : out std_logic_vector(31 downto 0);
r2_done_o : out std_logic;
r2_err_o : out std_logic;
-- Write access
-- 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);
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;
-- Scrubber
scrubber_period_i : in std_logic_vector(15 downto 0)
);
end hydra_ram;
architecture arch of hydra_ram is
constant RAM_WSIZE : natural := 2 ** (g_RAM_LOG_SIZE - 2);
type t_ram39_type is array(natural range <>) of std_logic_vector(38 downto 0);
signal raddr, waddr : std_logic_vector(g_RAM_LOG_SIZE - 1 downto 2);
signal rdata_ecc, wdata_ecc : std_logic_vector(38 downto 0);
signal wen, ren, ren_d : std_logic;
signal recc, rsyndrome : std_logic_vector(6 downto 0);
signal rerr, rerr_one : std_logic;
signal r1_done, n_r1_done : std_logic;
signal r2_done, n_r2_done : std_logic;
signal wdone, n_wdone : std_logic;
signal n_ecc_one, n_ecc_fatal : std_logic;
signal last_raddr, n_last_raddr, scrub_addr : std_logic_vector(g_RAM_LOG_SIZE - 1 downto 2);
signal scrub_counter : unsigned(15 downto 0);
signal scrub_rd, scrub_done, n_scrub_done : std_logic;
type state_t is (S_READ, S_REWRITE);
signal state, n_state : state_t;
begin
-- The raw ram.
p_ram: process (clk_i)
is
variable iram : t_ram39_type(0 to RAM_WSIZE - 1);
begin
if rising_edge(clk_i) then
if wen = '1' then
iram (to_integer(unsigned(waddr))) := wdata_ecc;
end if;
if ren = '1' then
rdata_ecc <= iram (to_integer(unsigned(raddr)));
else
rdata_ecc <= (others => 'X');
end if;
ren_d <= ren;
end if;
end process;
r1_data_o <= rdata_ecc (31 downto 0);
r2_data_o <= rdata_ecc (31 downto 0);
recc <= f_calc_ecc(rdata_ecc (31 downto 0));
rsyndrome <= recc xor rdata_ecc(38 downto 32);
rerr <= f_ecc_errors(rsyndrome) and ren_d;
rerr_one <= f_ecc_one_error(rsyndrome) and ren_d;
r1_err_o <= rerr;
r1_done_o <= r1_done;
r2_err_o <= rerr;
r2_done_o <= r2_done;
wdone_o <= wdone;
p_scrub: process (clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
scrub_counter <= unsigned(scrubber_period_i);
scrub_addr <= (others => '0');
scrub_rd <= '0';
else
if scrub_done = '1' then
scrub_counter <= unsigned(scrubber_period_i);
scrub_addr <= std_logic_vector(unsigned(scrub_addr) + 1);
scrub_rd <= '0';
else
if scrub_counter = (scrub_counter'range => '0') then
scrub_rd <= '1';
else
scrub_counter <= scrub_counter - 1;
end if;
end if;
end if;
end if;
end process;
p_ctrl: process (state, r1_done, r2_done, rerr, rdata_ecc, rsyndrome, last_raddr,
r1_en_i, r1_addr_i, we_i, waddr_i, wdata_i, wforce_i,
r2_en_i, r2_addr_i, scrub_rd, scrub_addr, scrub_done)
begin
wen <= '0';
waddr <= (others => 'X');
wdata_ecc <= (others => 'X');
n_wdone <= '0';
ren <= '0';
raddr <= (others => 'X');
n_r1_done <= '0';
n_r2_done <= '0';
n_scrub_done <= '0';
n_ecc_one <= '0';
n_ecc_fatal <= '0';
n_state <= state;
n_last_raddr <= (others => 'X');
case state is
when S_READ =>
if (r2_done = '1' or r1_done = '1') and rerr = '1' then
-- There was an error on the last access.
-- Write to fix it.
if rerr_one = '1' then
-- Correctable: correct it.
n_ecc_one <= '1';
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';
wdata_ecc <= rdata_ecc;
end if;
waddr <= last_raddr;
wen <= '1';
n_last_raddr <= last_raddr;
n_state <= S_REWRITE;
elsif we_i = '1' then
-- Write
waddr <= waddr_i;
wen <= '1';
wdata_ecc <= (f_calc_ecc (wdata_i) & wdata_i) xor wforce_i;
n_wdone <= '1';
n_state <= S_READ;
elsif scrub_rd = '1' and scrub_done = '0' then
-- scrubber
raddr <= scrub_addr;
ren <= '1';
n_scrub_done <= '1';
n_last_raddr <= scrub_addr;
elsif r1_en_i = '1' then
-- Read.
raddr <= r1_addr_i;
ren <= '1';
n_r1_done <= '1';
n_last_raddr <= r1_addr_i;
elsif r2_en_i = '1' then
-- Read.
raddr <= r2_addr_i;
ren <= '1';
n_r2_done <= '1';
n_last_raddr <= r2_addr_i;
else
-- scrub if idle.
raddr <= scrub_addr;
ren <= '1';
n_scrub_done <= '1';
n_last_raddr <= scrub_addr;
end if;
when S_REWRITE =>
-- Reread
raddr <= last_raddr;
ren <= '1';
n_r1_done <= '1';
n_last_raddr <= last_raddr;
end case;
end process;
p_ctrl_reg: process (clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
r1_done <= '0';
r2_done <= '0';
scrub_done <= '0';
state <= S_READ;
last_raddr <= (others => 'X');
ecc_one_o <= '0';
ecc_fatal_o <= '0';
else
r1_done <= n_r1_done;
r2_done <= n_r2_done;
scrub_done <= n_scrub_done;
assert ((r2_done or scrub_done) and rerr) = '0' severity error; -- TODO
state <= n_state;
last_raddr <= n_last_raddr;
ecc_one_o <= n_ecc_one;
ecc_fatal_o <= n_ecc_fatal;
end if;
wdone <= n_wdone;
end if;
end process;
end arch;
\ No newline at end of file
...@@ -91,7 +91,7 @@ begin ...@@ -91,7 +91,7 @@ begin
lock <= '1'; lock <= '1';
process process
variable mem: mem_t (4095 downto 0); variable mem: mem_t (4095 downto 0) := (others => (others => '0'));
begin begin
read_mem (mem, "../../../sw/sf2-test/main.mem"); read_mem (mem, "../../../sw/sf2-test/main.mem");
......
...@@ -65,7 +65,7 @@ architecture behav of sf2_test is ...@@ -65,7 +65,7 @@ architecture behav of sf2_test is
-- IRAM log size in bytes. -- IRAM log size in bytes.
constant IRAM_LOG_SIZE : natural := 8; constant IRAM_LOG_SIZE : natural := 8;
signal iram_addr : std_logic_vector(IRAM_LOG_SIZE - 1 downto 0); signal iram_addr : std_logic_vector(IRAM_LOG_SIZE - 1 downto 2);
signal iram_we : std_logic; signal iram_we : std_logic;
signal iram_data : std_logic_vector(31 downto 0); signal iram_data : std_logic_vector(31 downto 0);
...@@ -133,7 +133,7 @@ begin ...@@ -133,7 +133,7 @@ begin
end if; end if;
end process; end process;
iram_addr <= iahb_addr (IRAM_LOG_SIZE + 2 - 1 downto 2); iram_addr <= iahb_addr (IRAM_LOG_SIZE - 1 downto 2);
iram_data <= ahb_rdata; iram_data <= ahb_rdata;
proc_init: process (clk_100) proc_init: process (clk_100)
......
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