Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
H
Hydra - a radiation-tolerant SoC
Manage
Activity
Members
Labels
Plan
Issues
0
Issue boards
Milestones
Wiki
Code
Merge requests
0
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Operate
Environments
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Projects
Hydra - a radiation-tolerant SoC
Commits
0372a11b
Commit
0372a11b
authored
3 years ago
by
Tristan Gingold
Browse files
Options
Downloads
Patches
Plain Diff
hydra: add ecc on dram, add a small memory test
parent
b7b8eb3a
Branches
Branches containing commit
No related merge requests found
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
hdl/rtl/hydra_core.vhd
+69
-50
69 additions, 50 deletions
hdl/rtl/hydra_core.vhd
hdl/rtl/hydra_dram.vhd
+291
-0
291 additions, 0 deletions
hdl/rtl/hydra_dram.vhd
hdl/top/sf2-test/sf2_test.vhd
+1
-1
1 addition, 1 deletion
hdl/top/sf2-test/sf2_test.vhd
sw/sf2-test/main.c
+38
-2
38 additions, 2 deletions
sw/sf2-test/main.c
with
399 additions
and
53 deletions
hdl/rtl/hydra_core.vhd
+
69
−
50
View file @
0372a11b
...
...
@@ -94,11 +94,13 @@ architecture arch of hydra_core is
signal
reg_dm_addr
,
reg_dm_data_s
:
std_logic_vector
(
31
downto
0
);
signal
reg_dm_data_select
:
std_logic_vector
(
3
downto
0
);
signal
reg_dm_load
,
reg_dm_store
:
std_logic
;
signal
reg_dm_en
:
std_logic
;
signal
dm_cycle_in_progress
,
reg_dm_is_wishbone
,
reg_dm_is_iram
:
std_logic
;
signal
dm_mem_rdata
,
dm_wb_rdata
:
std_logic_vector
(
31
downto
0
);
signal
dm_wb_write
,
dm_select_wb
:
std_logic
;
signal
dm_done
,
dm_err
:
std_logic
;
signal
dwb_out
:
t_wishbone_master_out
;
begin
...
...
@@ -143,11 +145,8 @@ begin
begin
if
rising_edge
(
clk_sys_i
)
then
if
rst_n_i
=
'0'
then
reg_dm_load
<=
'0'
;
reg_dm_store
<=
'0'
;
null
;
else
reg_dm_load
<=
dm_load
;
reg_dm_store
<=
dm_store
;
if
dm_load
=
'1'
or
dm_store
=
'1'
then
reg_dm_addr
<=
dm_addr
;
reg_dm_data_s
<=
dm_data_s
;
...
...
@@ -197,30 +196,29 @@ begin
-- 2nd 64KB is the DRAM
reg_dm_is_wishbone
<=
'1'
when
reg_dm_addr
(
31
downto
20
)
/=
x"000"
else
'0'
;
reg_dm_is_iram
<=
'1'
when
reg_dm_addr
(
16
)
=
'0'
and
reg_dm_is_wishbone
=
'0'
else
'0'
;
dm_data_l
<=
dm_wb_rdata
when
(
dm_select_wb
=
'1'
or
reg_dm_is_iram
=
'1'
)
else
dm_mem_rdata
;
dm_data_l
<=
dm_wb_rdata
;
p_ram
:
process
(
clk_sys_i
)
is
variable
dram
:
t_ram32_type
(
2
**
(
g_DRAM_LOG_SIZE
-
2
)
-
1
downto
0
);
variable
addr
:
natural
range
dram
'range
;
begin
if
rising_edge
(
clk_sys_i
)
then
if
reg_dm_load
=
'1'
then
addr
:
=
to_integer
(
unsigned
(
reg_dm_addr
(
g_DRAM_LOG_SIZE
-
1
downto
2
)));
dm_mem_rdata
<=
dram
(
addr
);
else
dm_mem_rdata
<=
(
others
=>
'X'
);
end
if
;
if
reg_dm_store
=
'1'
and
reg_dm_addr
(
16
)
=
'1'
and
reg_dm_is_wishbone
=
'0'
then
for
i
in
0
to
3
loop
if
reg_d
m_data
_select
(
i
)
=
'1'
then
dram
(
addr
)(
8
*
i
+
7
downto
8
*
i
)
:
=
reg_dm_data_s
(
8
*
i
+
7
downto
8
*
i
);
end
if
;
e
nd
loop
;
e
nd
if
;
end
if
;
end
process
;
reg_dm_en
<=
'1'
when
reg_dm_addr
(
16
)
=
'1'
and
reg_dm_is_wishbone
=
'0'
and
(
reg_dm_store
or
reg_dm_load
)
=
'1'
else
'0'
;
inst_
dram
:
entity
work
.
hydra_dram
generic
map
(
g_ram_log_size
=>
g_dram_log_size
)
port
map
(
clk_i
=>
clk_sys_i
,
rst_n_i
=>
rst_n_i
,
addr_i
=>
reg_dm_addr
(
g_DRAM_LOG_SIZE
-
1
downto
2
),
en_i
=>
reg_dm_en
,
we_i
=>
reg_dm_store
,
sel_i
=>
reg_dm_data_select
,
data_i
=>
reg_dm_data_s
,
data_o
=>
dm_me
m_
r
data
,
done_o
=>
dm_done
,
err_o
=>
dm_err
,
--
e
cc_one_o => ecc_one_o,
--
e
cc_fatal_o => ecc_fatal_o,
scrubber_period_i
=>
x"0010"
)
;
-- Data bus
-- Wishbone bus arbitration / internal RAM access
...
...
@@ -239,28 +237,29 @@ begin
dwb_out
.
dat
<=
(
others
=>
'0'
);
dm_cycle_in_progress
<=
'0'
;
dm_select_wb
<=
'0'
;
reg_dm_load
<=
'0'
;
reg_dm_store
<=
'0'
;
else
if
dm_cycle_in_progress
=
'0'
then
-- Data bus was idle.
dm_wb_write
<=
reg_dm_store
;
if
reg_dm_is_wishbone
=
'0'
then
-- Internal access
dm_select_wb
<=
'0'
;
if
reg_dm_store
=
'1'
then
dm_store_done
<=
'1'
;
elsif
reg_dm_load
=
'1'
then
if
reg_dm_is_iram
=
'1'
then
-- Need to wait for the done (may need extra cycles due to ECC)
dm_cycle_in_progress
<=
'1'
;
else
-- Immediate answer
dm_load_done
<=
'1'
;
end
if
;
end
if
;
else
-- Wishbone access
dm_select_wb
<=
'1'
;
if
reg_dm_load
=
'1'
or
reg_dm_store
=
'1'
then
if
dm_load
=
'1'
then
reg_dm_load
<=
'1'
;
end
if
;
if
dm_store
=
'1'
then
reg_dm_store
<=
'1'
;
end
if
;
if
reg_dm_load
=
'1'
or
reg_dm_store
=
'1'
then
dm_wb_write
<=
reg_dm_store
;
if
reg_dm_is_wishbone
=
'0'
then
-- Internal access
dm_select_wb
<=
'0'
;
-- Need to wait for the done (may need extra cycles due to ECC)
dm_cycle_in_progress
<=
'1'
;
-- TODO: detect write access to IRAM ?
else
-- Wishbone access
dm_select_wb
<=
'1'
;
dwb_out
.
cyc
<=
'1'
;
dwb_out
.
stb
<=
'1'
;
dwb_out
.
we
<=
reg_dm_store
;
...
...
@@ -272,6 +271,9 @@ begin
end
if
;
else
-- Transfer in progress
-- Cannot start a new transfer.
assert
dm_load
=
'0'
;
assert
dm_store
=
'0'
;
if
dm_select_wb
=
'1'
then
-- Wishbone transfer in progress.
if
dwb_i
.
stall
=
'0'
then
...
...
@@ -282,8 +284,10 @@ begin
if
dm_wb_write
=
'0'
then
dm_wb_rdata
<=
f_x_to_zero
(
dwb_i
.
dat
);
dm_load_done
<=
'1'
;
reg_dm_load
<=
'0'
;
else
dm_store_done
<=
'1'
;
reg_dm_store
<=
'0'
;
end
if
;
dm_cycle_in_progress
<=
'0'
;
...
...
@@ -291,10 +295,25 @@ begin
end
if
;
else
-- IRAM/DRAM transfer in progress
if
im1_done
=
'1'
and
im1_err
=
'0'
then
dm_wb_rdata
<=
im1_data
;
dm_load_done
<=
'1'
;
dm_cycle_in_progress
<=
'0'
;
if
reg_dm_is_iram
=
'1'
then
if
im1_done
=
'1'
and
im1_err
=
'0'
then
dm_wb_rdata
<=
im1_data
;
dm_load_done
<=
'1'
;
reg_dm_load
<=
'0'
;
dm_cycle_in_progress
<=
'0'
;
end
if
;
else
if
dm_done
=
'1'
and
dm_err
=
'0'
then
dm_wb_rdata
<=
dm_mem_rdata
;
dm_cycle_in_progress
<=
'0'
;
if
dm_wb_write
=
'0'
then
dm_load_done
<=
'1'
;
reg_dm_load
<=
'0'
;
else
dm_store_done
<=
'1'
;
reg_dm_store
<=
'0'
;
end
if
;
end
if
;
end
if
;
end
if
;
end
if
;
...
...
This diff is collapsed.
Click to expand it.
hdl/rtl/hydra_dram.vhd
0 → 100644
+
291
−
0
View file @
0372a11b
--------------------------------------------------------------------------------
-- CERN BE-CO-HT
-- Mock Turtle
-- https://gitlab.cern.ch/coht/mockturtle
--------------------------------------------------------------------------------
--
-- unit name: hydra_dram
--
-- 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_dram
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
;
-- Read port
-- RDONE_O is a pulse.
addr_i
:
in
std_logic_vector
(
g_RAM_LOG_SIZE
-
1
downto
2
);
en_i
:
in
std_logic
;
we_i
:
in
std_logic
;
sel_i
:
in
std_logic_vector
(
3
downto
0
);
data_i
:
in
std_logic_vector
(
31
downto
0
);
data_o
:
out
std_logic_vector
(
31
downto
0
);
done_o
:
out
std_logic
;
err_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_dram
;
architecture
arch
of
hydra_dram
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
addr
:
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
r_done
,
n_r_done
,
r_done_d
:
std_logic
;
signal
p_done
,
n_p_done
:
std_logic
;
signal
w_done
,
n_w_done
:
std_logic
;
signal
n_ecc_one
,
n_ecc_fatal
:
std_logic
;
signal
last_addr
,
n_last_addr
,
scrub_addr
:
std_logic_vector
(
g_RAM_LOG_SIZE
-
1
downto
2
);
signal
last_we
,
n_last_we
:
std_logic
;
signal
last_sel
,
n_last_sel
:
std_logic_vector
(
3
downto
0
);
signal
scrub_counter
:
unsigned
(
15
downto
0
);
signal
scrub_rd
,
scrub_done
,
scrub_done_d
,
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
);
variable
d
:
std_logic_vector
(
38
downto
0
);
variable
err
:
std_logic_vector
(
38
downto
0
)
:
=
(
0
=>
'1'
,
others
=>
'0'
);
variable
sim_cnt
:
natural
;
begin
if
rising_edge
(
clk_i
)
then
if
wen
=
'1'
then
iram
(
to_integer
(
unsigned
(
addr
)))
:
=
wdata_ecc
;
end
if
;
if
ren
=
'1'
then
d
:
=
iram
(
to_integer
(
unsigned
(
addr
)));
-- Simulate errors.
if
sim_cnt
<
7
then
sim_cnt
:
=
sim_cnt
+
1
;
else
sim_cnt
:
=
0
;
d
:
=
d
xor
err
;
err
:
=
err
(
err
'left
-
1
downto
0
)
&
err
(
err
'left
);
end
if
;
rdata_ecc
<=
d
;
else
rdata_ecc
<=
(
others
=>
'X'
);
end
if
;
ren_d
<=
ren
;
end
if
;
end
process
;
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
;
err_o
<=
rerr
;
done_o
<=
r_done
or
w_done
;
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'
and
rerr
=
'0'
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
,
p_done
,
r_done
,
scrub_done
,
rerr
,
rerr_one
,
rdata_ecc
,
rsyndrome
,
last_addr
,
last_we
,
last_sel
,
recc
,
en_i
,
addr_i
,
we_i
,
data_i
,
r_done_d
,
scrub_rd
,
scrub_addr
,
scrub_done_d
,
rst_n_i
)
is
variable
d
:
std_logic_vector
(
31
downto
0
);
begin
wen
<=
'0'
;
addr
<=
(
others
=>
'X'
);
wdata_ecc
<=
(
others
=>
'X'
);
n_w_done
<=
'0'
;
ren
<=
'0'
;
n_r_done
<=
'0'
;
n_p_done
<=
'0'
;
n_scrub_done
<=
'0'
;
n_last_we
<=
'0'
;
n_last_sel
<=
"0000"
;
n_ecc_one
<=
'0'
;
n_ecc_fatal
<=
'0'
;
n_state
<=
state
;
n_last_addr
<=
(
others
=>
'X'
);
case
state
is
when
S_READ
=>
if
(
p_done
=
'1'
or
r_done
=
'1'
or
scrub_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
;
addr
<=
last_addr
;
wen
<=
'1'
;
n_last_addr
<=
last_addr
;
n_last_we
<=
last_we
;
n_last_sel
<=
last_sel
;
n_state
<=
S_REWRITE
;
elsif
last_we
=
'1'
then
assert
last_sel
/=
"1111"
;
-- The partial write;
d
:
=
rdata_ecc
(
31
downto
0
);
for
i
in
3
downto
0
loop
if
last_sel
(
i
)
=
'1'
then
d
(
8
*
i
+
7
downto
8
*
i
)
:
=
data_i
(
8
*
i
+
7
downto
8
*
i
);
end
if
;
end
loop
;
wen
<=
'1'
;
wdata_ecc
<=
(
f_calc_ecc
(
d
)
&
d
);
addr
<=
last_addr
;
n_w_done
<=
'1'
;
elsif
scrub_rd
=
'1'
and
scrub_done
=
'0'
then
-- scrubber
addr
<=
scrub_addr
;
ren
<=
'1'
;
n_scrub_done
<=
'1'
;
n_last_addr
<=
scrub_addr
;
elsif
en_i
=
'1'
then
addr
<=
addr_i
;
n_last_addr
<=
addr_i
;
n_state
<=
S_READ
;
if
we_i
=
'1'
then
-- Write
if
sel_i
=
"1111"
then
-- Full write
wen
<=
'1'
;
wdata_ecc
<=
(
f_calc_ecc
(
data_i
)
&
data_i
);
n_w_done
<=
'1'
;
else
-- Partial write: first read the word
ren
<=
'1'
;
n_last_we
<=
we_i
;
n_last_sel
<=
sel_i
;
n_p_done
<=
'1'
;
end
if
;
else
-- Read.
ren
<=
'1'
;
n_r_done
<=
'1'
;
end
if
;
elsif
rst_n_i
=
'1'
then
-- scrub if idle (but not during reset)
addr
<=
scrub_addr
;
ren
<=
'1'
;
n_scrub_done
<=
'1'
;
n_last_addr
<=
scrub_addr
;
end
if
;
when
S_REWRITE
=>
-- Reread
addr
<=
last_addr
;
ren
<=
'1'
;
n_r_done
<=
r_done_d
;
n_scrub_done
<=
scrub_done_d
;
n_last_addr
<=
last_addr
;
n_last_we
<=
last_we
;
n_last_sel
<=
last_sel
;
n_state
<=
S_READ
;
end
case
;
end
process
;
p_ctrl_reg
:
process
(
clk_i
)
begin
if
rising_edge
(
clk_i
)
then
if
rst_n_i
=
'0'
then
r_done
<=
'0'
;
r_done_d
<=
'0'
;
scrub_done
<=
'0'
;
scrub_done_d
<=
'0'
;
p_done
<=
'0'
;
state
<=
S_READ
;
last_addr
<=
(
others
=>
'X'
);
last_we
<=
'0'
;
last_sel
<=
(
others
=>
'X'
);
ecc_one_o
<=
'0'
;
ecc_fatal_o
<=
'0'
;
else
r_done_d
<=
r_done
;
r_done
<=
n_r_done
;
p_done
<=
n_p_done
;
scrub_done_d
<=
scrub_done
;
scrub_done
<=
n_scrub_done
;
state
<=
n_state
;
last_addr
<=
n_last_addr
;
last_we
<=
n_last_we
;
last_sel
<=
n_last_sel
;
ecc_one_o
<=
n_ecc_one
;
ecc_fatal_o
<=
n_ecc_fatal
;
end
if
;
w_done
<=
n_w_done
;
end
if
;
end
process
;
end
arch
;
\ No newline at end of file
This diff is collapsed.
Click to expand it.
hdl/top/sf2-test/sf2_test.vhd
+
1
−
1
View file @
0372a11b
...
...
@@ -63,7 +63,7 @@ architecture behav of sf2_test is
signal
ahb_state
:
ahb_state_t
;
-- IRAM log size in bytes.
constant
IRAM_LOG_SIZE
:
natural
:
=
8
;
constant
IRAM_LOG_SIZE
:
natural
:
=
9
;
signal
iram_addr
:
std_logic_vector
(
IRAM_LOG_SIZE
-
1
downto
2
);
signal
iram_we
:
std_logic
;
...
...
This diff is collapsed.
Click to expand it.
sw/sf2-test/main.c
+
38
−
2
View file @
0372a11b
...
...
@@ -32,6 +32,35 @@ uart_puts (const char *s)
uart_putc
(
*
s
++
);
}
#define PAD_LEN 8
static
volatile
unsigned
pad
[
8
];
int
ram_test
(
void
)
{
int
i
;
volatile
unsigned
char
*
p
;
for
(
i
=
0
;
i
<
PAD_LEN
;
i
++
)
{
if
(
pad
[
i
]
!=
0
)
return
-
1
;
pad
[
i
]
=
0xffffffff
;
}
for
(
i
=
0
;
i
<
PAD_LEN
;
i
++
)
{
p
=
(
volatile
unsigned
char
*
)
&
pad
[
i
];
p
[
i
&
3
]
=
i
;
}
for
(
i
=
0
;
i
<
PAD_LEN
;
i
++
)
{
p
=
(
volatile
unsigned
char
*
)
&
pad
[
i
];
unsigned
v
=
0xffffffff
;
v
&=
~
(
0xff
<<
(
8
*
(
i
&
3
)));
v
|=
i
<<
(
8
*
(
i
&
3
));
if
(
pad
[
i
]
!=
v
)
return
-
2
;
}
return
0
;
}
int
main
(
void
)
{
...
...
@@ -48,7 +77,14 @@ main (void)
/* start operation. */
*
(
volatile
unsigned
*
)
UART_LCR
=
0x03
;
while
(
1
)
{
uart_puts
(
"Hello diot.
\n
"
);
uart_puts
(
"Ram
\n
"
);
if
(
ram_test
()
!=
0
)
{
while
(
1
)
uart_puts
(
"Error
\n
"
);
}
else
{
while
(
1
)
{
uart_puts
(
"Hello diot.
\n
"
);
}
}
}
This diff is collapsed.
Click to expand it.
Preview
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment