refactoring: move dma simulation to verilog
This commit is contained in:
parent
4afc655104
commit
b3a79f41ec
|
@ -2,18 +2,18 @@
|
|||
|
||||
.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 \
|
||||
-CFLAGS -DWORD_AMNT=2048 \
|
||||
-CFLAGS -DRAM_WID=32 \
|
||||
$(bram_SRC)
|
||||
obj_dir/Vbram_interface: obj_dir/Vbram_interface.mk
|
||||
cd obj_dir && make -f Vbram_interface.mk
|
||||
./obj_dir/Vbram_interface
|
||||
obj_dir/Vbram_interface_sim: obj_dir/Vbram_interface_sim.mk
|
||||
cd obj_dir && make -f Vbram_interface_sim.mk
|
||||
./obj_dir/Vbram_interface_sim
|
||||
|
||||
clean:
|
||||
rm -rf obj_dir/
|
||||
|
|
|
@ -105,11 +105,4 @@ end else if (!word_next && word_ok) begin
|
|||
word_ok <= 0;
|
||||
end
|
||||
|
||||
`ifdef VERILATOR
|
||||
initial begin
|
||||
$dumpfile("bram.fst");
|
||||
$dumpvars;
|
||||
end
|
||||
`endif
|
||||
|
||||
endmodule
|
||||
|
|
|
@ -4,42 +4,11 @@
|
|||
#include <unistd.h>
|
||||
#include <verilated.h>
|
||||
|
||||
#include "Vbram_interface.h"
|
||||
#include "Vbram_interface_sim.h"
|
||||
#include "../testbench.hpp"
|
||||
|
||||
TB<Vbram_interface> *tb;
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
TB<Vbram_interface_sim> *tb;
|
||||
|
||||
static void handle_read_aa(size_t &i) {
|
||||
if (tb->mod.word_ok) {
|
||||
|
@ -95,17 +64,18 @@ static void test_aa_read_interrupted() {
|
|||
|
||||
static void refresh_data() {
|
||||
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.start_addr = start_addr;
|
||||
tb->mod.start_addr = 0x12340;
|
||||
tb->run_clock();
|
||||
|
||||
while (!tb->mod.refresh_finished) {
|
||||
handle_ram();
|
||||
while (!tb->mod.refresh_finished)
|
||||
tb->run_clock();
|
||||
}
|
||||
|
||||
tb->mod.refresh_start = 0;
|
||||
tb->run_clock();
|
||||
|
@ -113,8 +83,11 @@ static void refresh_data() {
|
|||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
Verilated::commandArgs(argc, argv);
|
||||
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");
|
||||
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:
|
||||
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;
|
||||
tick_count = 0;
|
||||
}
|
||||
|
@ -26,14 +22,16 @@ template <class TOP> class TB {
|
|||
void run_clock() {
|
||||
mod.clk = !mod.clk;
|
||||
mod.eval();
|
||||
vc.timeInc(1);
|
||||
Verilated::timeInc(1);
|
||||
|
||||
mod.clk = !mod.clk;
|
||||
mod.eval();
|
||||
vc.timeInc(1);
|
||||
Verilated::timeInc(1);
|
||||
tick_count++;
|
||||
|
||||
if (bailout > 0 && tick_count >= bailout)
|
||||
exit(1);
|
||||
if (Verilated::gotError())
|
||||
exit(1);
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue