Memory Tester
The MEM_TESTER component is used to test external DDR memory.
It detects hardware failures and measures the overall performance of the memory.
Key Features
Interface Compatibility Compatible with the Avalon Memory-Mapped (AMM) interface and Intel EMIF Hard IP.
Basic Test Workflow
Sequentially writes pseudo-random data to every memory address.
Resets the pseudo-random generator (to reproduce the exact same sequence).
Sequentially reads back from all addresses and compares the received data with the expected values.
Random Addressing Mode (optional)
Generates random addresses to simulate more realistic memory access patterns and measure performance.
Warning
Random Addressing Mode is not suitable for error detection (address overlaps can cause false error reports). Use it only for performance measurement, not for memory testing.
Additional Configurable Options
Incremental Read mode: The next read request is issued only after the previous one completes. Ideal for precise latency measurements because the memory is not loaded with concurrent requests.
Auto precharge support (for random addressing).
Manual control of the memory refresh period.
Configuration & Control All test parameters are configured via the MI bus.
Reporting Includes a Python script that generates PDF performance reports.
Measurement Logging Handled by the MEM_LOGGER component.
Clock Domain Must be instantiated in the external memory controller’s clock domain.
The MI bus is automatically bridged using the internal
MI_ASYNCcomponent.
Manual Memory Access You can also perform manual read/write operations on the memory using the AMM_GEN component.
Component port and generics description
- ENTITY MEM_TESTER IS
- Generics
PortsGeneric
Type
Default
Description
AMM_DATA_WIDTH
integer
512
Avalon Memory-Mapped (memory interface) data width
AMM_ADDR_WIDTH
integer
26
AMM_BURST_COUNT_WIDTH
integer
7
AMM_FREQ_KHZ
integer
266660
Avalon Memory-Mapped (memory interface) frequency in kHz
MI_DATA_WIDTH
integer
32
MI bus data width
MI_ADDR_WIDTH
integer
32
RAND_GEN_DATA_WIDTH
integer
64
Random data generators width Random data will be made by adding these generators in series For alowed values se LFSR_SIMPLE_RANDOM_GEN (4, 8, 16, 20, 24, 26, 32, 64)
RAND_GEN_ADDR_WIDTH
integer
26
Width of random generator for addresses (should be equal or larger then AMM_ADDR width)
RANDOM_DATA_SEED
slv_array_t(0 to AMM_DATA_WIDTH / RAND_GEN_DATA_WIDTH - 1)(RAND_GEN_DATA_WIDTH - 1 downto 0)
UNDEFINED
Random data generator seed
= UNDEFINED
UNDEFINED
RANDOM_ADDR_SEED
std_logic_vector(RAND_GEN_ADDR_WIDTH - 1 downto 0)
resize(X”3FBF807”, RAND_GEN_ADDR_WIDTH)
REFR_REQ_BEFORE_TEST
boolean
false
Manual refresh enable
REFR_PERIOD_WIDTH
integer
MI_DATA_WIDTH
DEF_REFR_PERIOD
std_logic_vector(REFR_PERIOD_WIDTH - 1 downto 0)
(others => ‘0’)
AMM_PROBE_EN
boolean
false
Enable AMM probe for measurement (depreciated)
HISTOGRAM_BOXES
integer
256
Latency histogram precision for AMM probe (depreciated)
DEFAULT_BURST_CNT
integer
4
Default memory burst count
DEFAULT_ADDR_LIMIT
integer
2**AMM_ADDR_WIDTH - 2 ** AMM_BURST_COUNT_WIDTH
Until which address should be test done (to reduce simulation resources) Shoud be power of 2
DEBUG_RAND_ADDR
boolean
false
Force random address generator to generate in range 0 to DEFAULT_ADDR_LIMIT (for simulation)
DEVICE
string
UNDEFINED
Port
Type
Mode
Description
=====
Avalon interface from EMIF IP
=====
=====
AMM_CLK
std_logic
in
AMM_RST
std_logic
in
AMM_READY
std_logic
in
Indicates when controller is ready
AMM_READ
std_logic
out
When asserted, transaction to current address with current burst count is generated
AMM_WRITE
std_logic
out
Has to be high for every word in transaction
AMM_ADDRESS
std_logic_vector(AMM_ADDR_WIDTH - 1 downto 0)
out
Indexed by AMM words (can be set just for the first word of each transaction)
AMM_READ_DATA
std_logic_vector(AMM_DATA_WIDTH - 1 downto 0)
in
AMM_WRITE_DATA
std_logic_vector(AMM_DATA_WIDTH - 1 downto 0)
out
AMM_BURST_COUNT
std_logic_vector(AMM_BURST_COUNT_WIDTH - 1 downto 0)
out
Number of AMM words in one r/w transaction
AMM_READ_DATA_VALID
std_logic
in
REFR_PERIOD
std_logic_vector(REFR_PERIOD_WIDTH - 1 downto 0)
out
Manual memory refresh period
REFR_REQ
std_logic
out
REFR_ACK
std_logic
in
=====
Other EMIF IP signals
=====
=====
EMIF_RST_REQ
std_logic
out
Force reset and calibration, must be at least 2 clk at ‘1’
EMIF_RST_DONE
std_logic
in
EMIF_ECC_ISR
std_logic
in
Interrupt to indicate whenever bit error occurred
EMIF_CAL_SUCCESS
std_logic
in
Calibration successful
EMIF_CAL_FAIL
std_logic
in
Calibration failed
EMIF_AUTO_PRECHARGE
std_logic
out
Auto precharge request
=====
MI bus interface
=====
=====
MI_CLK
std_logic
in
MI_RST
std_logic
in
MI_DWR
std_logic_vector(MI_DATA_WIDTH - 1 downto 0)
in
MI_ADDR
std_logic_vector(MI_ADDR_WIDTH - 1 downto 0)
in
MI_BE
std_logic_vector(MI_DATA_WIDTH / 8 - 1 downto 0)
in
MI_RD
std_logic
in
MI_WR
std_logic
in
MI_ARDY
std_logic
out
MI_DRD
std_logic_vector(MI_DATA_WIDTH - 1 downto 0)
out
MI_DRDY
std_logic
out
Control Software
Requirements
NFB python package
See: ndk-sw
Open FPGA Modules python package
It includes packages for
DATA_LOGGERandMEM_LOGGER.See: ndk-fpga/python/ofm
Basic usage of mem_tester.py
No arguments … Run basic sequential memory test and show result
-p… Print current state ofMEM_TESTER-r… Run test with random addressing (performance only)-d <device>… Specify NFB device (default:/dev/nfb0)-i <index>… SpecifyMEM_TESTERinstance (also applies toMEM_LOGGER)--gen-*… Manual read/write access to memory viaAMM_GEN
Example output (with no arguments)
|| ------------------- ||
|| TEST WAS SUCCESSFUL ||
|| ------------------- ||
Mem_logger statistics:
----------------------
write requests 16777215
write words 67108860
read requests 16777215
...
Flow:
write 137.03 [Gb/s]
read 24.66 [Gb/s]
total 41.80 [Gb/s]
Latency:
min 75.00 [ns]
max 630.00 [ns]
avg 80.04 [ns]
Errors:
zero burst count 0
simultaneous r+w 0
Full usage of mem_tester.py
$ python sw/mem_tester.py -h
usage: mem_tester.py [-h] [-d device] [-c compatible] [-C compatible]
[-i index] [-I index] [-p] [--rst] [--rst-tester]
[--rst-logger] [--rst-emif] [-r] [-b BURST] [-s SCALE]
[-o] [-f] [--auto-precharge] [--refresh REFRESH]
[--set-buff burst data] [--get-buff] [--gen-wr addr]
[--gen-rd addr] [--gen-burst GEN_BURST]
mem_tester control script
optional arguments:
-h, --help show this help message and exit
card access arguments:
-d device, --device device
device with target FPGA card.
-c compatible, --comp compatible
mem_tester compatible inside DevTree.
-C compatible, --logger-comp compatible
mem_logger compatible inside DevTree.
-i index, --index index
mem_tester index inside DevTree.
-I index, --logger-index index
mem_logger index inside DevTree.
common arguments:
-p, --print print registers
--rst reset mem_tester and mem_logger
--rst-tester reset mem_tester
--rst-logger reset mem_logger
--rst-emif reset memory driver
test related arguments:
-r, --rand use random indexing during test
-b BURST, --burst BURST
burst count during test
-s SCALE, --scale SCALE
tested address space (1.0 = whole)
-o, --one-simult use only one simultaneous read during test
-f, --to-first measure latency to the first received word
--auto-precharge use auto precharge during test
--refresh REFRESH set refresh period in ticks
amm_gen control arguments:
--set-buff burst data
set specific burst data in amm_gen buffer
--get-buff print amm_gen buffer
--gen-wr addr writes amm_gen buffer to specific address
--gen-rd addr reads memory data to amm_gen buffer
--gen-burst GEN_BURST
sets burst count for amm_gen
Pytest Automated Testing
You can run fully automated tests with pytest:
pip install pytest
python -m pytest -xs --tb=short test_mem_tester.py
Useful flags:
-s… show measured data-x… stop after first failure--tb=short… show only assertion messages
The script automatically finds all MEM_TESTER and MEM_LOGGER instances and runs sequential tests with minimal and maximal burst counts.
To use a different device, edit the device variable in test_mem_tester.py.
PDF Report Generator
The report_gen.py script runs the MEM_TESTER with many different configurations and creates a PDF (or Markdown) report with plots.
Report content:
Basic configuration of
MEM_TESTERandMEM_LOGGERFull memory test results for every interface
Tables and plots with latencies, bandwidth, etc.
Requirements for PDF output:
sudo yum install pandoc texlive-latex texlive
Generate report:
python report_gen.py # Markdown + PDF report
python report_gen.py md # Markdown only
Files created:
mem_tester_report.mdandmem_tester_report.pdfwith plotsPlots:
fig/folderRaw data:
data.npz
Internal Architecture
MI bus logic is in a separate file:
mem_tester_mi.vhdMI_ASYNC bridges MI bus and Avalon clock domains
MI_SPLITTER_PLUS_GEN splits the bus for
MEM_TESTERandAMM_GEN
AMM_GEN enables manual memory access
Random data/addresses are generated by
LFSR_SIMPLE_RANDOM_GENAMM_MUXselects between test logic and manual accessEverything is controlled by a FSM
Manual MI Bus Control
Register map
Address |
Name |
Description |
|---|---|---|
0x0000 |
ctrl_in |
Control register (bits below) |
0x0004 |
ctrl_out |
Status register |
0x0008 |
err_cnt |
Error counter |
0x000C |
burst_cnt |
Burst length used in test |
0x0010 |
limit_addr |
Tested address space limit |
0x0014 |
refresh_period |
Current refresh period |
0x0018 |
default_refresh |
Default refresh period |
0x0040 |
AMM_GEN base |
Base address for manual access |
ctrl_in bits (write only, rising-edge triggered for reset/run):
bit 0 … reset
bit 1 … reset EMIF IP
bit 2 … run test
bit 3 … enable AMM_GEN
bit 4 … random addressing
bit 5 … one simultaneous read only (latency measurement)
bit 6 … auto precharge
ctrl_out bits (read):
bit 0 … test done
bit 1 … test successful
bit 2 … ECC error
bit 3 … calibration success
bit 4 … calibration fail
bit 5 … AMM_READY
Usage
Reset sequence:
Set
resetbit to1and then to0To reset EMIF IP set
reset EMIF IPbit to1and then to0and wait for eithercalibration successfulbit orcalibration failbit
Run test:
To run the test set
run testbit to1After the test is finished
test donebit will be set to1and the result will be available intest successfulbitError count during test will be available inside err cnt register