refactoring: move dma simulation to verilog
This commit is contained in:
parent
4afc655104
commit
b3a79f41ec
|
@ -2,18 +2,18 @@
|
||||||
|
|
||||||
.PHONY: test clean
|
.PHONY: test clean
|
||||||
|
|
||||||
test: obj_dir/Vbram_interface
|
test: obj_dir/Vbram_interface_sim
|
||||||
|
|
||||||
bram_SRC= bram_interface.v bram_interface_sim.cpp
|
bram_SRC= bram_interface_sim.v dma_sim.v bram_interface.v bram_interface_sim.cpp
|
||||||
|
|
||||||
obj_dir/Vbram_interface.mk: $(bram_SRC)
|
obj_dir/Vbram_interface_sim.mk: $(bram_SRC)
|
||||||
verilator --cc --exe -Wall --trace --trace-fst \
|
verilator --cc --exe -Wall --trace --trace-fst \
|
||||||
-CFLAGS -DWORD_AMNT=2048 \
|
-CFLAGS -DWORD_AMNT=2048 \
|
||||||
-CFLAGS -DRAM_WID=32 \
|
-CFLAGS -DRAM_WID=32 \
|
||||||
$(bram_SRC)
|
$(bram_SRC)
|
||||||
obj_dir/Vbram_interface: obj_dir/Vbram_interface.mk
|
obj_dir/Vbram_interface_sim: obj_dir/Vbram_interface_sim.mk
|
||||||
cd obj_dir && make -f Vbram_interface.mk
|
cd obj_dir && make -f Vbram_interface_sim.mk
|
||||||
./obj_dir/Vbram_interface
|
./obj_dir/Vbram_interface_sim
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf obj_dir/
|
rm -rf obj_dir/
|
||||||
|
|
|
@ -105,11 +105,4 @@ end else if (!word_next && word_ok) begin
|
||||||
word_ok <= 0;
|
word_ok <= 0;
|
||||||
end
|
end
|
||||||
|
|
||||||
`ifdef VERILATOR
|
|
||||||
initial begin
|
|
||||||
$dumpfile("bram.fst");
|
|
||||||
$dumpvars;
|
|
||||||
end
|
|
||||||
`endif
|
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
|
@ -4,42 +4,11 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <verilated.h>
|
#include <verilated.h>
|
||||||
|
|
||||||
#include "Vbram_interface.h"
|
#include "Vbram_interface_sim.h"
|
||||||
#include "../testbench.hpp"
|
#include "../testbench.hpp"
|
||||||
|
|
||||||
TB<Vbram_interface> *tb;
|
|
||||||
constexpr uint32_t start_addr = 0x12340;
|
|
||||||
std::array<uint32_t, WORD_AMNT> ram_refresh_data;
|
std::array<uint32_t, WORD_AMNT> ram_refresh_data;
|
||||||
|
TB<Vbram_interface_sim> *tb;
|
||||||
static void handle_ram() {
|
|
||||||
static int timer = 0;
|
|
||||||
constexpr auto TIMER_MAX = 10;
|
|
||||||
bool flip_flop = false;
|
|
||||||
|
|
||||||
if (tb->mod.ram_read) {
|
|
||||||
timer++;
|
|
||||||
if (timer == TIMER_MAX) {
|
|
||||||
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(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 (tb->mod.ram_dma_addr % 4 == 0) {
|
|
||||||
tb->mod.ram_word = ram_refresh_data[(tb->mod.ram_dma_addr - start_addr)/4]& 0xFFFF;
|
|
||||||
} else {
|
|
||||||
tb->mod.ram_word = ram_refresh_data[(tb->mod.ram_dma_addr - start_addr)/4] >> 16;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
tb->mod.ram_valid = 0;
|
|
||||||
timer = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_read_aa(size_t &i) {
|
static void handle_read_aa(size_t &i) {
|
||||||
if (tb->mod.word_ok) {
|
if (tb->mod.word_ok) {
|
||||||
|
@ -95,17 +64,18 @@ static void test_aa_read_interrupted() {
|
||||||
|
|
||||||
static void refresh_data() {
|
static void refresh_data() {
|
||||||
for (size_t i = 0; i < RAM_WID; i++) {
|
for (size_t i = 0; i < RAM_WID; i++) {
|
||||||
ram_refresh_data[i] = mask_extend(rand(), 20);
|
uint32_t val = mask_extend(rand(), 20);
|
||||||
|
ram_refresh_data[i] = val;
|
||||||
|
tb->mod.backing_store[i*2] = val & 0xFFFF;
|
||||||
|
tb->mod.backing_store[i*2+1] = val >> 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
tb->mod.refresh_start = 1;
|
tb->mod.refresh_start = 1;
|
||||||
tb->mod.start_addr = start_addr;
|
tb->mod.start_addr = 0x12340;
|
||||||
tb->run_clock();
|
tb->run_clock();
|
||||||
|
|
||||||
while (!tb->mod.refresh_finished) {
|
while (!tb->mod.refresh_finished)
|
||||||
handle_ram();
|
|
||||||
tb->run_clock();
|
tb->run_clock();
|
||||||
}
|
|
||||||
|
|
||||||
tb->mod.refresh_start = 0;
|
tb->mod.refresh_start = 0;
|
||||||
tb->run_clock();
|
tb->run_clock();
|
||||||
|
@ -113,8 +83,11 @@ static void refresh_data() {
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
Verilated::commandArgs(argc, argv);
|
||||||
Verilated::traceEverOn(true);
|
Verilated::traceEverOn(true);
|
||||||
tb = new TB<Vbram_interface>(argc, argv);
|
Verilated::fatalOnError(false);
|
||||||
|
|
||||||
|
tb = new TB<Vbram_interface_sim>(argc, argv);
|
||||||
|
|
||||||
printf("test basic read/write\n");
|
printf("test basic read/write\n");
|
||||||
refresh_data();
|
refresh_data();
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
module bram_interface_sim #(
|
||||||
|
parameter WORD_WID = 24,
|
||||||
|
parameter WORD_AMNT_WID = 11,
|
||||||
|
parameter [WORD_AMNT_WID-1:0] WORD_AMNT = 2047,
|
||||||
|
parameter RAM_WID = 32,
|
||||||
|
parameter RAM_WORD_WID = 16,
|
||||||
|
parameter RAM_REAL_START = 32'h12340,
|
||||||
|
parameter RAM_CNTR_LEN = 12,
|
||||||
|
parameter TOTAL_RAM_WORD_MINUS_ONE = 4095,
|
||||||
|
parameter DELAY_CNTR_LEN = 8,
|
||||||
|
parameter DELAY_TOTAL = 12,
|
||||||
|
parameter RAM_WORD_INCR = 2
|
||||||
|
) (
|
||||||
|
input clk,
|
||||||
|
|
||||||
|
/* autoapproach interface */
|
||||||
|
output [WORD_WID-1:0] word,
|
||||||
|
input word_next,
|
||||||
|
output word_last,
|
||||||
|
output word_ok,
|
||||||
|
input word_rst,
|
||||||
|
|
||||||
|
/* User interface */
|
||||||
|
input refresh_start,
|
||||||
|
input [RAM_WID-1:0] start_addr,
|
||||||
|
output refresh_finished,
|
||||||
|
|
||||||
|
input[RAM_WORD_WID-1:0] backing_store [TOTAL_RAM_WORD_MINUS_ONE:0]
|
||||||
|
);
|
||||||
|
|
||||||
|
wire [RAM_WID-1:0] ram_dma_addr;
|
||||||
|
wire [RAM_WORD_WID-1:0] ram_word;
|
||||||
|
wire ram_read;
|
||||||
|
wire ram_valid;
|
||||||
|
|
||||||
|
dma_sim #(
|
||||||
|
.RAM_WID(RAM_WID),
|
||||||
|
.RAM_WORD_WID(RAM_WORD_WID),
|
||||||
|
.RAM_REAL_START(RAM_REAL_START),
|
||||||
|
.RAM_CNTR_LEN(RAM_CNTR_LEN),
|
||||||
|
.TOTAL_RAM_WORD_MINUS_ONE(TOTAL_RAM_WORD_MINUS_ONE),
|
||||||
|
.DELAY_CNTR_LEN(DELAY_CNTR_LEN),
|
||||||
|
.DELAY_TOTAL(DELAY_TOTAL)
|
||||||
|
) dma_sim (
|
||||||
|
.clk(clk),
|
||||||
|
.ram_dma_addr(ram_dma_addr),
|
||||||
|
.ram_word(ram_word),
|
||||||
|
.ram_read(ram_read),
|
||||||
|
.ram_valid(ram_valid),
|
||||||
|
.backing_store(backing_store)
|
||||||
|
);
|
||||||
|
|
||||||
|
bram_interface #(
|
||||||
|
.WORD_WID(WORD_WID),
|
||||||
|
.WORD_AMNT_WID(WORD_AMNT_WID),
|
||||||
|
.WORD_AMNT(WORD_AMNT),
|
||||||
|
.RAM_WID(RAM_WID),
|
||||||
|
.RAM_WORD_WID(RAM_WORD_WID),
|
||||||
|
.RAM_WORD_INCR(RAM_WORD_INCR)
|
||||||
|
) bram_interface (
|
||||||
|
.clk(clk),
|
||||||
|
.word(word),
|
||||||
|
.word_next(word_next),
|
||||||
|
.word_last(word_last),
|
||||||
|
.word_ok(word_ok),
|
||||||
|
.word_rst(word_rst),
|
||||||
|
.refresh_start(refresh_start),
|
||||||
|
.start_addr(start_addr),
|
||||||
|
.refresh_finished(refresh_finished),
|
||||||
|
.ram_dma_addr(ram_dma_addr),
|
||||||
|
.ram_word(ram_word),
|
||||||
|
.ram_read(ram_read),
|
||||||
|
.ram_valid(ram_valid)
|
||||||
|
);
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
$dumpfile("bram.fst");
|
||||||
|
$dumpvars();
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,44 @@
|
||||||
|
/* This module is used to simulate direct memory access, where only
|
||||||
|
* a small amount of memory is valid to read.
|
||||||
|
*/
|
||||||
|
module dma_sim #(
|
||||||
|
parameter RAM_WID = 32,
|
||||||
|
parameter RAM_WORD_WID = 16,
|
||||||
|
parameter RAM_REAL_START = 32'h12340,
|
||||||
|
parameter RAM_CNTR_LEN = 12,
|
||||||
|
parameter TOTAL_RAM_WORD_MINUS_ONE = 4095,
|
||||||
|
parameter DELAY_CNTR_LEN = 8,
|
||||||
|
parameter DELAY_TOTAL = 12
|
||||||
|
) (
|
||||||
|
input clk,
|
||||||
|
|
||||||
|
/* DMA interface */
|
||||||
|
input [RAM_WID-1:0] ram_dma_addr,
|
||||||
|
output reg [RAM_WORD_WID-1:0] ram_word,
|
||||||
|
input ram_read,
|
||||||
|
output reg ram_valid,
|
||||||
|
|
||||||
|
/*- Verilator interface */
|
||||||
|
input [RAM_WORD_WID-1:0] backing_store[TOTAL_RAM_WORD_MINUS_ONE:0]
|
||||||
|
);
|
||||||
|
|
||||||
|
reg [DELAY_CNTR_LEN-1:0] delay_cntr = 0;
|
||||||
|
|
||||||
|
always @ (posedge clk) begin
|
||||||
|
if (!ram_read) begin
|
||||||
|
delay_cntr <= 0;
|
||||||
|
ram_valid <= 0;
|
||||||
|
end else if (delay_cntr < DELAY_TOTAL) begin
|
||||||
|
delay_cntr <= delay_cntr + 1;
|
||||||
|
end else if (!ram_valid) begin
|
||||||
|
if (ram_dma_addr < RAM_REAL_START || ram_dma_addr > RAM_REAL_START + 2*TOTAL_RAM_WORD_MINUS_ONE) begin
|
||||||
|
$display("ram_dma_addr %x out of bounds", ram_dma_addr);
|
||||||
|
$stop();
|
||||||
|
end else begin
|
||||||
|
ram_word <= backing_store[(RAM_CNTR_LEN)'((ram_dma_addr - RAM_REAL_START)/2)];
|
||||||
|
ram_valid <= 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
|
@ -9,12 +9,8 @@ template <class TOP> class TB {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TOP mod;
|
TOP mod;
|
||||||
VerilatedContext vc;
|
|
||||||
|
|
||||||
TB(int argc, char *argv[], int _bailout = 0) : mod(), bailout(_bailout), vc() {
|
|
||||||
vc.commandArgs(argc, argv);
|
|
||||||
vc.traceEverOn(true);
|
|
||||||
|
|
||||||
|
TB(int argc, char *argv[], int _bailout = 0) : mod(), bailout(_bailout) {
|
||||||
mod.clk = 0;
|
mod.clk = 0;
|
||||||
tick_count = 0;
|
tick_count = 0;
|
||||||
}
|
}
|
||||||
|
@ -26,14 +22,16 @@ template <class TOP> class TB {
|
||||||
void run_clock() {
|
void run_clock() {
|
||||||
mod.clk = !mod.clk;
|
mod.clk = !mod.clk;
|
||||||
mod.eval();
|
mod.eval();
|
||||||
vc.timeInc(1);
|
Verilated::timeInc(1);
|
||||||
|
|
||||||
mod.clk = !mod.clk;
|
mod.clk = !mod.clk;
|
||||||
mod.eval();
|
mod.eval();
|
||||||
vc.timeInc(1);
|
Verilated::timeInc(1);
|
||||||
tick_count++;
|
tick_count++;
|
||||||
|
|
||||||
if (bailout > 0 && tick_count >= bailout)
|
if (bailout > 0 && tick_count >= bailout)
|
||||||
exit(1);
|
exit(1);
|
||||||
|
if (Verilated::gotError())
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue