autoapproach: add bram and test
This commit is contained in:
parent
7ceaa730d9
commit
034f76da41
|
@ -0,0 +1,19 @@
|
||||||
|
# Makefile for tests and hardware verification.
|
||||||
|
|
||||||
|
.PHONY: test clean
|
||||||
|
|
||||||
|
test: obj_dir/Vbram_interface
|
||||||
|
|
||||||
|
bram_SRC= bram_interface.v bram_interface_sim.cpp
|
||||||
|
|
||||||
|
obj_dir/Vbram_interface.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
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf obj_dir/
|
|
@ -1,9 +1,12 @@
|
||||||
/* Autoapproach module. This module applies a waveform located in memory
|
/* Autoapproach module. This module applies a waveform located in memory
|
||||||
* (and copied into Block RAM). This waveform is arbitrary but of fixed
|
* (and copied into Block RAM). This waveform is arbitrary but of fixed
|
||||||
* length.
|
* length.
|
||||||
|
* time in between sent sample, total period 10-50ms
|
||||||
*/
|
*/
|
||||||
module autoapproach #(
|
module autoapproach #(
|
||||||
parameter DAC_WID = 24
|
parameter DAC_WID = 24,
|
||||||
|
parameter DAC_DATA_WID = 20,
|
||||||
|
parameter ADC_WID = 24
|
||||||
) (
|
) (
|
||||||
input clk,
|
input clk,
|
||||||
input arm,
|
input arm,
|
||||||
|
@ -11,13 +14,13 @@ module autoapproach #(
|
||||||
output detected,
|
output detected,
|
||||||
|
|
||||||
input polarity,
|
input polarity,
|
||||||
input [`ADC_WID-1:0] setpoint,
|
input [ADC_WID-1:0] setpoint,
|
||||||
|
|
||||||
/* BRAM memory interface. Each pulse returns the next value in
|
/* BRAM memory interface. Each pulse returns the next value in
|
||||||
* the sequence, and also informs the module if the sequence
|
* the sequence, and also informs the module if the sequence
|
||||||
* is completed. The kernel interacts primarily with this interface.
|
* is completed. The kernel interacts primarily with this interface.
|
||||||
*/
|
*/
|
||||||
input [`DAC_DATA_WID-1:0] word,
|
input [DAC_DATA_WID-1:0] word,
|
||||||
output word_next,
|
output word_next,
|
||||||
input word_last,
|
input word_last,
|
||||||
input word_ok,
|
input word_ok,
|
||||||
|
@ -26,12 +29,12 @@ module autoapproach #(
|
||||||
/* DAC wires. */
|
/* DAC wires. */
|
||||||
input dac_finished,
|
input dac_finished,
|
||||||
output dac_arm,
|
output dac_arm,
|
||||||
input [`DAC_WID-1:0] dac_in,
|
input [DAC_WID-1:0] dac_in,
|
||||||
output [`DAC_WID-1:0] dac_out,
|
output [DAC_WID-1:0] dac_out,
|
||||||
|
|
||||||
input adc_finished,
|
input adc_finished,
|
||||||
output adc_arm,
|
output adc_arm,
|
||||||
input [`ADC_WID-1:0] measurement
|
input [ADC_WID-1:0] measurement
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
@ -41,7 +44,6 @@ localparam WAIT_ON_DAC = 2;
|
||||||
localparam WAIT_ON_DETECTION = 3;
|
localparam WAIT_ON_DETECTION = 3;
|
||||||
localparam DETECTED = 4;
|
localparam DETECTED = 4;
|
||||||
reg [2:0] state = WAIT_ON_ARM;
|
reg [2:0] state = WAIT_ON_ARM;
|
||||||
reg save_word_last = 0;
|
|
||||||
|
|
||||||
always @ (posedge clk) case (state)
|
always @ (posedge clk) case (state)
|
||||||
WAIT_ON_ARM: if (arm) begin
|
WAIT_ON_ARM: if (arm) begin
|
||||||
|
@ -55,25 +57,25 @@ end
|
||||||
RECV_WORD: if (word_ok) begin
|
RECV_WORD: if (word_ok) begin
|
||||||
dac_out <= {4'b0001, word};
|
dac_out <= {4'b0001, word};
|
||||||
dac_arm <= 1;
|
dac_arm <= 1;
|
||||||
save_word_last <= word_last;
|
|
||||||
word_next <= 0;
|
word_next <= 0;
|
||||||
state <= WAIT_ON_DAC;
|
state <= WAIT_ON_DAC;
|
||||||
end
|
end
|
||||||
WAIT_ON_DAC: if (dac_finished) begin
|
WAIT_ON_DAC: if (dac_finished) begin
|
||||||
dac_arm <= 0;
|
dac_arm <= 0;
|
||||||
if (save_word_last) begin
|
/* Was the last word read *the* last word? */
|
||||||
|
if (word_last) begin
|
||||||
state <= WAIT_ON_DETECTION;
|
state <= WAIT_ON_DETECTION;
|
||||||
adc_arm <= 0;
|
adc_arm <= 1;
|
||||||
end else begin
|
end else begin
|
||||||
state <= WAIT_ON_ARM;
|
state <= WAIT_ON_ARM;
|
||||||
end
|
end
|
||||||
endcase
|
endcase
|
||||||
WAIT_ON_DETECTION: if (adc_finished) begin
|
WAIT_ON_DETECTION: if (adc_finished) begin
|
||||||
if (polarity && measurement >= setpt) begin
|
if ((polarity && measurement >= setpt) ||
|
||||||
|
(!polarity && measurement <= setpt)) begin
|
||||||
state <= DETECTED;
|
state <= DETECTED;
|
||||||
detected <= 1;
|
detected <= 1;
|
||||||
end else if (measurement <= setpt) begin
|
|
||||||
state <= WAIT_ON_ARM;
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
DETECTED: if (!arm) begin
|
DETECTED: if (!arm) begin
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
module bram_interface #(
|
||||||
|
parameter WORD_WID = 24,
|
||||||
|
parameter WORD_AMNT_WID = 11,
|
||||||
|
/* This is the last INDEX, not the LENGTH of the word array. */
|
||||||
|
parameter [WORD_AMNT_WID-1:0] WORD_AMNT = 2047,
|
||||||
|
parameter RAM_WID = 32,
|
||||||
|
parameter RAM_WORD_WID = 16,
|
||||||
|
parameter RAM_WORD_INCR = 2
|
||||||
|
) (
|
||||||
|
input clk,
|
||||||
|
|
||||||
|
/* autoapproach interface */
|
||||||
|
output reg [WORD_WID-1:0] word,
|
||||||
|
input word_next,
|
||||||
|
output reg word_last,
|
||||||
|
output reg word_ok,
|
||||||
|
input word_rst,
|
||||||
|
|
||||||
|
/* User interface */
|
||||||
|
input refresh_start,
|
||||||
|
input [RAM_WID-1:0] start_addr,
|
||||||
|
output reg refresh_finished,
|
||||||
|
|
||||||
|
/* RAM interface */
|
||||||
|
output reg [RAM_WID-1:0] ram_dma_addr,
|
||||||
|
input [RAM_WORD_WID-1:0] ram_word,
|
||||||
|
output reg ram_read,
|
||||||
|
input ram_valid
|
||||||
|
);
|
||||||
|
|
||||||
|
initial word = 0;
|
||||||
|
initial word_last = 0;
|
||||||
|
initial word_ok = 0;
|
||||||
|
initial refresh_finished = 0;
|
||||||
|
initial ram_dma_addr = 0;
|
||||||
|
initial ram_read = 0;
|
||||||
|
|
||||||
|
reg [WORD_WID-1:0] backing_buffer [WORD_AMNT:0];
|
||||||
|
|
||||||
|
localparam WAIT_ON_REFRESH = 0;
|
||||||
|
localparam READ_LOW_WORD = 1;
|
||||||
|
localparam READ_HIGH_WORD = 2;
|
||||||
|
localparam WAIT_ON_REFRESH_DEASSERT = 3;
|
||||||
|
|
||||||
|
reg [1:0] refresh_state = 0;
|
||||||
|
reg [WORD_AMNT_WID-1:0] word_cntr_refresh = 0;
|
||||||
|
|
||||||
|
always @ (posedge clk) case (refresh_state)
|
||||||
|
WAIT_ON_REFRESH: if (refresh_start) begin
|
||||||
|
ram_dma_addr <= start_addr;
|
||||||
|
refresh_state <= READ_LOW_WORD;
|
||||||
|
word_cntr_refresh <= 0;
|
||||||
|
end
|
||||||
|
READ_LOW_WORD: if (!ram_read) begin
|
||||||
|
ram_read <= 1;
|
||||||
|
end else if (ram_valid) begin
|
||||||
|
refresh_state <= READ_HIGH_WORD;
|
||||||
|
ram_dma_addr <= ram_dma_addr + RAM_WORD_INCR;
|
||||||
|
ram_read <= 0;
|
||||||
|
backing_buffer[word_cntr_refresh][RAM_WORD_WID-1:0] <= ram_word;
|
||||||
|
end
|
||||||
|
READ_HIGH_WORD: if (!ram_read) begin
|
||||||
|
ram_read <= 1;
|
||||||
|
end else if (ram_valid) begin
|
||||||
|
ram_dma_addr <= ram_dma_addr + RAM_WORD_INCR;
|
||||||
|
ram_read <= 0;
|
||||||
|
word_cntr_refresh <= word_cntr_refresh + 1;
|
||||||
|
backing_buffer[word_cntr_refresh][WORD_WID-1:RAM_WORD_WID] <= ram_word[WORD_WID-RAM_WORD_WID-1:0];
|
||||||
|
|
||||||
|
if (word_cntr_refresh == WORD_AMNT)
|
||||||
|
refresh_state <= WAIT_ON_REFRESH_DEASSERT;
|
||||||
|
else
|
||||||
|
refresh_state <= READ_LOW_WORD;
|
||||||
|
end
|
||||||
|
WAIT_ON_REFRESH_DEASSERT: begin
|
||||||
|
if (!refresh_start) begin
|
||||||
|
refresh_finished <= 0;
|
||||||
|
refresh_state <= WAIT_ON_REFRESH;
|
||||||
|
end else begin
|
||||||
|
refresh_finished <= 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
|
||||||
|
reg [WORD_AMNT_WID-1:0] auto_cntr = 0;
|
||||||
|
|
||||||
|
always @ (posedge clk) if (word_rst) begin
|
||||||
|
auto_cntr <= 0;
|
||||||
|
end else if (word_next && !word_ok) begin
|
||||||
|
if (refresh_state == WAIT_ON_REFRESH) begin
|
||||||
|
word <= backing_buffer[auto_cntr];
|
||||||
|
word_ok <= 1;
|
||||||
|
if (auto_cntr == WORD_AMNT) begin
|
||||||
|
auto_cntr <= 0;
|
||||||
|
word_last <= 1;
|
||||||
|
end else begin
|
||||||
|
auto_cntr <= auto_cntr + 1;
|
||||||
|
word_last <= 0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end else if (!word_next && word_ok) begin
|
||||||
|
word_ok <= 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
`ifdef VERILATOR
|
||||||
|
initial begin
|
||||||
|
$dumpfile("bram.fst");
|
||||||
|
$dumpvars;
|
||||||
|
end
|
||||||
|
`endif
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,112 @@
|
||||||
|
#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"
|
||||||
|
|
||||||
|
using ModType = Vbram_interface;
|
||||||
|
using V = uint32_t;
|
||||||
|
ModType *mod;
|
||||||
|
|
||||||
|
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() {
|
||||||
|
static int timer = 0;
|
||||||
|
constexpr auto TIMER_MAX = 10;
|
||||||
|
bool flip_flop = false;
|
||||||
|
|
||||||
|
if (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);
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (mod->ram_dma_addr % 4 == 0) {
|
||||||
|
mod->ram_word = ram_refresh_data[(mod->ram_dma_addr - start_addr)/4]& 0xFFFF;
|
||||||
|
} else {
|
||||||
|
mod->ram_word = ram_refresh_data[(mod->ram_dma_addr - start_addr)/4] >> 16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test reading the entire array twice. */
|
||||||
|
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)) {
|
||||||
|
handle_read_aa(ind);
|
||||||
|
run_clock();
|
||||||
|
}
|
||||||
|
my_assert(ind == WORD_AMNT, "read value %zu != %d\n", ind, WORD_AMNT);
|
||||||
|
|
||||||
|
mod->word_next = 1;
|
||||||
|
run_clock();
|
||||||
|
ind = 0;
|
||||||
|
while (!mod->word_last || (mod->word_last && mod->word_next)) {
|
||||||
|
handle_read_aa(ind);
|
||||||
|
run_clock();
|
||||||
|
}
|
||||||
|
my_assert(ind == WORD_AMNT, "second read value %zu != %d\n", ind, WORD_AMNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
init(argc, argv);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < RAM_WID; i++) {
|
||||||
|
ram_refresh_data[i] = mask_extend(rand(), 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
mod->refresh_start = 1;
|
||||||
|
mod->start_addr = start_addr;
|
||||||
|
run_clock();
|
||||||
|
|
||||||
|
while (!mod->refresh_finished) {
|
||||||
|
handle_ram();
|
||||||
|
run_clock();
|
||||||
|
}
|
||||||
|
|
||||||
|
mod->refresh_start = 0;
|
||||||
|
run_clock();
|
||||||
|
|
||||||
|
test_aa_read_1();
|
||||||
|
printf("ok\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
uint32_t main_time = 0;
|
||||||
|
|
||||||
|
double sc_time_stamp() {
|
||||||
|
return main_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
static 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__)
|
||||||
|
|
||||||
|
#ifdef BAILOUT_NUMBER
|
||||||
|
# define BAILOUT(...) __VA_ARGS__
|
||||||
|
#else
|
||||||
|
# define BAILOUT(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void run_clock() {
|
||||||
|
BAILOUT(static int bailout;)
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
mod->clk = !mod->clk;
|
||||||
|
mod->eval();
|
||||||
|
main_time++;
|
||||||
|
BAILOUT(bailout++;)
|
||||||
|
}
|
||||||
|
BAILOUT(if (bailout >= BAILOUT_NUMBER) exit(1);)
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef BAILOUT
|
||||||
|
|
||||||
|
static void cleanup_exit() {
|
||||||
|
mod->final();
|
||||||
|
delete mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init(int argc, char **argv) {
|
||||||
|
Verilated::commandArgs(argc, argv);
|
||||||
|
Verilated::traceEverOn(true);
|
||||||
|
mod = new ModType;
|
||||||
|
mod->clk = 0;
|
||||||
|
atexit(cleanup_exit);
|
||||||
|
|
||||||
|
char *seed = getenv("RANDOM_SEED");
|
||||||
|
if (seed) {
|
||||||
|
unsigned long i = strtoul(seed, NULL, 10);
|
||||||
|
srand((unsigned int)i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static 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))
|
||||||
|
|
||||||
|
static V mask_extend(V x, unsigned len) {
|
||||||
|
return sign_extend(MASK(x,len), len);
|
||||||
|
}
|
Loading…
Reference in New Issue