refactor bram interface simulation
This commit is contained in:
parent
c68027f24f
commit
285b6d9501
|
@ -64,6 +64,7 @@ DO_WAIT: if (!arm) begin
|
|||
end else if (wait_timer == 0) begin
|
||||
word_next <= 1;
|
||||
state <= RECV_WORD;
|
||||
wait_timer <= time_to_wait;
|
||||
end else begin
|
||||
wait_timer <= wait_timer - 1;
|
||||
end
|
||||
|
|
|
@ -10,16 +10,10 @@
|
|||
#include <verilated.h>
|
||||
|
||||
#include "Vbram_interface.h"
|
||||
#include "../testbench.hpp"
|
||||
|
||||
using ModType = Vbram_interface;
|
||||
using V = uint32_t;
|
||||
ModType *mod;
|
||||
|
||||
TB<Vbram_interface> *tb;
|
||||
constexpr uint32_t start_addr = 0x12340;
|
||||
|
||||
// #define BAILOUT_NUMBER 100000
|
||||
#include "../boilerplate.cpp"
|
||||
|
||||
std::array<uint32_t, WORD_AMNT> ram_refresh_data;
|
||||
|
||||
static void handle_ram() {
|
||||
|
@ -27,40 +21,40 @@ static void handle_ram() {
|
|||
constexpr auto TIMER_MAX = 10;
|
||||
bool flip_flop = false;
|
||||
|
||||
if (mod->ram_read) {
|
||||
if (tb->mod.ram_read) {
|
||||
timer++;
|
||||
if (timer == TIMER_MAX) {
|
||||
mod->ram_valid = 1;
|
||||
if (mod->ram_dma_addr < start_addr ||
|
||||
mod->ram_dma_addr >= start_addr + WORD_AMNT*4) {
|
||||
printf("bad address %x\n", mod->ram_dma_addr);
|
||||
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);
|
||||
exit(1);
|
||||
}
|
||||
my_assert(mod->ram_dma_addr >= start_addr, "left oob access %x", mod->ram_dma_addr);
|
||||
my_assert(mod->ram_dma_addr < start_addr + WORD_AMNT*4, "right oob access %x", mod->ram_dma_addr);
|
||||
my_assert(mod->ram_dma_addr % 2 == 0, "unaligned access %x", mod->ram_dma_addr);
|
||||
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);
|
||||
|
||||
if (mod->ram_dma_addr % 4 == 0) {
|
||||
mod->ram_word = ram_refresh_data[(mod->ram_dma_addr - start_addr)/4]& 0xFFFF;
|
||||
if (tb->mod.ram_dma_addr % 4 == 0) {
|
||||
tb->mod.ram_word = ram_refresh_data[(tb->mod.ram_dma_addr - start_addr)/4]& 0xFFFF;
|
||||
} else {
|
||||
mod->ram_word = ram_refresh_data[(mod->ram_dma_addr - start_addr)/4] >> 16;
|
||||
tb->mod.ram_word = ram_refresh_data[(tb->mod.ram_dma_addr - start_addr)/4] >> 16;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mod->ram_valid = 0;
|
||||
tb->mod.ram_valid = 0;
|
||||
timer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_read_aa(size_t &i) {
|
||||
if (mod->word_ok) {
|
||||
uint32_t val = sign_extend(mod->word, 20);
|
||||
mod->word_next = 0;
|
||||
if (tb->mod.word_ok) {
|
||||
uint32_t val = sign_extend(tb->mod.word, 20);
|
||||
tb->mod.word_next = 0;
|
||||
|
||||
my_assert(val == ram_refresh_data[i], "received value %x (%zu) != %x", i, val, ram_refresh_data[i]);
|
||||
i++;
|
||||
} else if (!mod->word_next) {
|
||||
mod->word_next = 1;
|
||||
} else if (!tb->mod.word_next) {
|
||||
tb->mod.word_next = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,20 +62,20 @@ static void handle_read_aa(size_t &i) {
|
|||
static void test_aa_read_1() {
|
||||
size_t ind = 0;
|
||||
|
||||
mod->word_next = 1;
|
||||
run_clock();
|
||||
while (!mod->word_last || (mod->word_last && mod->word_next)) {
|
||||
tb->mod.word_next = 1;
|
||||
tb->run_clock();
|
||||
while (!tb->mod.word_last || (tb->mod.word_last && tb->mod.word_next)) {
|
||||
handle_read_aa(ind);
|
||||
run_clock();
|
||||
tb->run_clock();
|
||||
}
|
||||
my_assert(ind == WORD_AMNT, "read value %zu != %d\n", ind, WORD_AMNT);
|
||||
|
||||
mod->word_next = 1;
|
||||
run_clock();
|
||||
tb->mod.word_next = 1;
|
||||
tb->run_clock();
|
||||
ind = 0;
|
||||
while (!mod->word_last || (mod->word_last && mod->word_next)) {
|
||||
while (!tb->mod.word_last || (tb->mod.word_last && tb->mod.word_next)) {
|
||||
handle_read_aa(ind);
|
||||
run_clock();
|
||||
tb->run_clock();
|
||||
}
|
||||
my_assert(ind == WORD_AMNT, "second read value %zu != %d\n", ind, WORD_AMNT);
|
||||
}
|
||||
|
@ -89,17 +83,17 @@ static void test_aa_read_1() {
|
|||
static void test_aa_read_interrupted() {
|
||||
size_t ind = 0;
|
||||
|
||||
mod->word_next = 1;
|
||||
run_clock();
|
||||
tb->mod.word_next = 1;
|
||||
tb->run_clock();
|
||||
for (int i = 0; i < 100; i++) {
|
||||
handle_read_aa(ind);
|
||||
run_clock();
|
||||
my_assert(!mod->word_last, "too many reads");
|
||||
tb->run_clock();
|
||||
my_assert(!tb->mod.word_last, "too many reads");
|
||||
}
|
||||
mod->word_rst = 1;
|
||||
run_clock();
|
||||
mod->word_rst = 0;
|
||||
run_clock();
|
||||
tb->mod.word_rst = 1;
|
||||
tb->run_clock();
|
||||
tb->mod.word_rst = 0;
|
||||
tb->run_clock();
|
||||
|
||||
test_aa_read_1();
|
||||
}
|
||||
|
@ -109,22 +103,24 @@ static void refresh_data() {
|
|||
ram_refresh_data[i] = mask_extend(rand(), 20);
|
||||
}
|
||||
|
||||
mod->refresh_start = 1;
|
||||
mod->start_addr = start_addr;
|
||||
run_clock();
|
||||
tb->mod.refresh_start = 1;
|
||||
tb->mod.start_addr = start_addr;
|
||||
tb->run_clock();
|
||||
|
||||
while (!mod->refresh_finished) {
|
||||
while (!tb->mod.refresh_finished) {
|
||||
handle_ram();
|
||||
run_clock();
|
||||
tb->run_clock();
|
||||
}
|
||||
|
||||
mod->refresh_start = 0;
|
||||
run_clock();
|
||||
tb->mod.refresh_start = 0;
|
||||
tb->run_clock();
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
init(argc, argv);
|
||||
int main(int argc, char *argv[]) {
|
||||
Verilated::commandArgs(argc, argv);
|
||||
Verilated::traceEverOn(true);
|
||||
tb = new TB<Vbram_interface>();
|
||||
|
||||
printf("test basic read/write\n");
|
||||
refresh_data();
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
/* https://zipcpu.com/blog/2017/06/21/looking-at-verilator.html */
|
||||
template <class TOP> class TB {
|
||||
int tick_count;
|
||||
int bailout;
|
||||
|
||||
public: TOP mod;
|
||||
TB(int _bailout = 0) : mod(), bailout(_bailout) {
|
||||
mod.clk = 0;
|
||||
tick_count = 0;
|
||||
}
|
||||
|
||||
virtual ~TB() {
|
||||
mod.final();
|
||||
}
|
||||
|
||||
virtual void run_clock() {
|
||||
mod.clk = !mod.clk;
|
||||
mod.eval();
|
||||
Verilated::timeInc(1);
|
||||
mod.clk = !mod.clk;
|
||||
mod.eval();
|
||||
Verilated::timeInc(1);
|
||||
tick_count++;
|
||||
|
||||
if (bailout > 0 && tick_count >= bailout)
|
||||
exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
static inline void _assert(const char *file, int line, const char *exp, bool ev, const char *fmt, ...) {
|
||||
if (!ev) {
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
fprintf(stderr, "%s:%d: assertion failed: %s\n", file, line, exp);
|
||||
vfprintf(stderr, fmt, va);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(va);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
#define STRINGIFY(s) #s
|
||||
/* ,##__VA_ARGS__ is a GNU C extension */
|
||||
#define my_assert(e, fmt, ...) _assert(__FILE__, __LINE__, STRINGIFY(e), (e), fmt ,##__VA_ARGS__)
|
||||
|
||||
template<typename V>
|
||||
static inline V sign_extend(V x, unsigned len) {
|
||||
/* if high bit is 1 */
|
||||
if (x >> (len - 1) & 1) {
|
||||
V mask = (1 << len) - 1;
|
||||
return ~mask | x;
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
#define MASK(x,v) ((x) & ((1 << (v)) - 1))
|
||||
template<typename V>
|
||||
static inline V mask_extend(V x, unsigned len) {
|
||||
return sign_extend<V>(MASK(x,len), len);
|
||||
}
|
Loading…
Reference in New Issue