2023-01-22 23:43:51 -05:00
|
|
|
#include <memory>
|
|
|
|
#include <cassert>
|
|
|
|
#include <limits>
|
|
|
|
#include <cstdint>
|
|
|
|
#include <cstring>
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <iostream>
|
|
|
|
#include <random>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <verilated.h>
|
|
|
|
|
|
|
|
#include "Vbram_interface.h"
|
2023-01-27 17:27:20 -05:00
|
|
|
#include "../testbench.hpp"
|
2023-01-22 23:43:51 -05:00
|
|
|
|
2023-01-27 17:27:20 -05:00
|
|
|
TB<Vbram_interface> *tb;
|
2023-01-22 23:43:51 -05:00
|
|
|
constexpr uint32_t start_addr = 0x12340;
|
|
|
|
std::array<uint32_t, WORD_AMNT> ram_refresh_data;
|
|
|
|
|
|
|
|
static void handle_ram() {
|
|
|
|
static int timer = 0;
|
|
|
|
constexpr auto TIMER_MAX = 10;
|
|
|
|
bool flip_flop = false;
|
|
|
|
|
2023-01-27 17:27:20 -05:00
|
|
|
if (tb->mod.ram_read) {
|
2023-01-22 23:43:51 -05:00
|
|
|
timer++;
|
|
|
|
if (timer == TIMER_MAX) {
|
2023-01-27 17:27:20 -05:00
|
|
|
tb->mod.ram_valid = 1;
|
|
|
|
if (tb->mod.ram_dma_addr < start_addr ||
|
|
|
|
tb->mod.ram_dma_addr >= start_addr + WORD_AMNT*4) {
|
|
|
|
printf("bad address %x\n", tb->mod.ram_dma_addr);
|
2023-01-22 23:43:51 -05:00
|
|
|
exit(1);
|
|
|
|
}
|
2023-01-27 17:27:20 -05:00
|
|
|
my_assert(tb->mod.ram_dma_addr >= start_addr, "left oob access %x", tb->mod.ram_dma_addr);
|
|
|
|
my_assert(tb->mod.ram_dma_addr < start_addr + WORD_AMNT*4, "right oob access %x", tb->mod.ram_dma_addr);
|
|
|
|
my_assert(tb->mod.ram_dma_addr % 2 == 0, "unaligned access %x", tb->mod.ram_dma_addr);
|
2023-01-22 23:43:51 -05:00
|
|
|
|
2023-01-27 17:27:20 -05:00
|
|
|
if (tb->mod.ram_dma_addr % 4 == 0) {
|
|
|
|
tb->mod.ram_word = ram_refresh_data[(tb->mod.ram_dma_addr - start_addr)/4]& 0xFFFF;
|
2023-01-22 23:43:51 -05:00
|
|
|
} else {
|
2023-01-27 17:27:20 -05:00
|
|
|
tb->mod.ram_word = ram_refresh_data[(tb->mod.ram_dma_addr - start_addr)/4] >> 16;
|
2023-01-22 23:43:51 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2023-01-27 17:27:20 -05:00
|
|
|
tb->mod.ram_valid = 0;
|
2023-01-22 23:43:51 -05:00
|
|
|
timer = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void handle_read_aa(size_t &i) {
|
2023-01-27 17:27:20 -05:00
|
|
|
if (tb->mod.word_ok) {
|
|
|
|
uint32_t val = sign_extend(tb->mod.word, 20);
|
|
|
|
tb->mod.word_next = 0;
|
2023-01-22 23:43:51 -05:00
|
|
|
|
|
|
|
my_assert(val == ram_refresh_data[i], "received value %x (%zu) != %x", i, val, ram_refresh_data[i]);
|
|
|
|
i++;
|
2023-01-27 17:27:20 -05:00
|
|
|
} else if (!tb->mod.word_next) {
|
|
|
|
tb->mod.word_next = 1;
|
2023-01-22 23:43:51 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Test reading the entire array twice. */
|
|
|
|
static void test_aa_read_1() {
|
|
|
|
size_t ind = 0;
|
|
|
|
|
2023-01-27 17:27:20 -05:00
|
|
|
tb->mod.word_next = 1;
|
|
|
|
tb->run_clock();
|
|
|
|
while (!tb->mod.word_last || (tb->mod.word_last && tb->mod.word_next)) {
|
2023-01-22 23:43:51 -05:00
|
|
|
handle_read_aa(ind);
|
2023-01-27 17:27:20 -05:00
|
|
|
tb->run_clock();
|
2023-01-22 23:43:51 -05:00
|
|
|
}
|
|
|
|
my_assert(ind == WORD_AMNT, "read value %zu != %d\n", ind, WORD_AMNT);
|
|
|
|
|
2023-01-27 17:27:20 -05:00
|
|
|
tb->mod.word_next = 1;
|
|
|
|
tb->run_clock();
|
2023-01-22 23:43:51 -05:00
|
|
|
ind = 0;
|
2023-01-27 17:27:20 -05:00
|
|
|
while (!tb->mod.word_last || (tb->mod.word_last && tb->mod.word_next)) {
|
2023-01-22 23:43:51 -05:00
|
|
|
handle_read_aa(ind);
|
2023-01-27 17:27:20 -05:00
|
|
|
tb->run_clock();
|
2023-01-22 23:43:51 -05:00
|
|
|
}
|
|
|
|
my_assert(ind == WORD_AMNT, "second read value %zu != %d\n", ind, WORD_AMNT);
|
|
|
|
}
|
|
|
|
|
2023-01-22 23:58:38 -05:00
|
|
|
static void test_aa_read_interrupted() {
|
|
|
|
size_t ind = 0;
|
|
|
|
|
2023-01-27 17:27:20 -05:00
|
|
|
tb->mod.word_next = 1;
|
|
|
|
tb->run_clock();
|
2023-01-22 23:58:38 -05:00
|
|
|
for (int i = 0; i < 100; i++) {
|
|
|
|
handle_read_aa(ind);
|
2023-01-27 17:27:20 -05:00
|
|
|
tb->run_clock();
|
|
|
|
my_assert(!tb->mod.word_last, "too many reads");
|
2023-01-22 23:58:38 -05:00
|
|
|
}
|
2023-01-27 17:27:20 -05:00
|
|
|
tb->mod.word_rst = 1;
|
|
|
|
tb->run_clock();
|
|
|
|
tb->mod.word_rst = 0;
|
|
|
|
tb->run_clock();
|
2023-01-22 23:58:38 -05:00
|
|
|
|
|
|
|
test_aa_read_1();
|
|
|
|
}
|
|
|
|
|
2023-01-22 23:47:12 -05:00
|
|
|
static void refresh_data() {
|
2023-01-22 23:43:51 -05:00
|
|
|
for (size_t i = 0; i < RAM_WID; i++) {
|
|
|
|
ram_refresh_data[i] = mask_extend(rand(), 20);
|
|
|
|
}
|
|
|
|
|
2023-01-27 17:27:20 -05:00
|
|
|
tb->mod.refresh_start = 1;
|
|
|
|
tb->mod.start_addr = start_addr;
|
|
|
|
tb->run_clock();
|
2023-01-22 23:43:51 -05:00
|
|
|
|
2023-01-27 17:27:20 -05:00
|
|
|
while (!tb->mod.refresh_finished) {
|
2023-01-22 23:43:51 -05:00
|
|
|
handle_ram();
|
2023-01-27 17:27:20 -05:00
|
|
|
tb->run_clock();
|
2023-01-22 23:43:51 -05:00
|
|
|
}
|
|
|
|
|
2023-01-27 17:27:20 -05:00
|
|
|
tb->mod.refresh_start = 0;
|
|
|
|
tb->run_clock();
|
2023-01-22 23:43:51 -05:00
|
|
|
|
2023-01-22 23:47:12 -05:00
|
|
|
}
|
|
|
|
|
2023-01-27 17:27:20 -05:00
|
|
|
int main(int argc, char *argv[]) {
|
|
|
|
Verilated::commandArgs(argc, argv);
|
|
|
|
Verilated::traceEverOn(true);
|
|
|
|
tb = new TB<Vbram_interface>();
|
2023-01-22 23:47:12 -05:00
|
|
|
|
2023-01-22 23:58:38 -05:00
|
|
|
printf("test basic read/write\n");
|
2023-01-22 23:47:12 -05:00
|
|
|
refresh_data();
|
|
|
|
test_aa_read_1();
|
|
|
|
refresh_data();
|
2023-01-22 23:43:51 -05:00
|
|
|
test_aa_read_1();
|
2023-01-22 23:58:38 -05:00
|
|
|
|
|
|
|
printf("test resetting\n");
|
|
|
|
test_aa_read_interrupted();
|
|
|
|
|
2023-01-22 23:43:51 -05:00
|
|
|
printf("ok\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|