stuff
This commit is contained in:
parent
f88e0ef15c
commit
92091d0982
|
@ -183,3 +183,21 @@ In Verilog, in order to replace a macro identifier with the value of the
|
||||||
macro, you must put a backtick before the name: i.e.
|
macro, you must put a backtick before the name: i.e.
|
||||||
|
|
||||||
`VALUE
|
`VALUE
|
||||||
|
|
||||||
|
## Forth scripting
|
||||||
|
|
||||||
|
The user controls the kernel through Forth scripts. The particular
|
||||||
|
implementation used is zForth.
|
||||||
|
|
||||||
|
Forth has the following memory access primitives:
|
||||||
|
|
||||||
|
* `addr` `@`: get value at `addr`
|
||||||
|
* `val` `addr` `!`: write `val` to `addr`
|
||||||
|
* `val` `,`: allocate a cell in "data space" (think the heap) and store
|
||||||
|
the data there.
|
||||||
|
* `addr` `#`: return the size of the value at addr (not standard Forth)
|
||||||
|
|
||||||
|
Each of these are not primitives in zForth. zForth allows for peeks and
|
||||||
|
pokes to get values of different lengths, and the standard operators are
|
||||||
|
for addressing a variable length value.
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,13 @@ module autoapproach #(
|
||||||
parameter DAC_WID = 24,
|
parameter DAC_WID = 24,
|
||||||
parameter DAC_DATA_WID = 20,
|
parameter DAC_DATA_WID = 20,
|
||||||
parameter ADC_WID = 24,
|
parameter ADC_WID = 24,
|
||||||
parameter TIMER_WID = 32
|
parameter TIMER_WID = 32,
|
||||||
|
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_WORD_INCR = 2
|
||||||
) (
|
) (
|
||||||
input clk,
|
input clk,
|
||||||
input arm,
|
input arm,
|
||||||
|
@ -18,20 +24,20 @@ module autoapproach #(
|
||||||
input [ADC_WID-1:0] setpoint,
|
input [ADC_WID-1:0] setpoint,
|
||||||
input [TIMER_WID-1:0] time_to_wait,
|
input [TIMER_WID-1:0] time_to_wait,
|
||||||
|
|
||||||
/* BRAM memory interface. Each pulse returns the next value in
|
/* User interface */
|
||||||
* the sequence, and also informs the module if the sequence
|
input refresh_start,
|
||||||
* is completed. The kernel interacts primarily with this interface.
|
input [RAM_WID-1:0] start_addr,
|
||||||
*/
|
output reg refresh_finished,
|
||||||
input [DAC_DATA_WID-1:0] word,
|
|
||||||
output word_next,
|
/* RAM interface */
|
||||||
input word_last,
|
output reg [RAM_WID-1:0] ram_dma_addr,
|
||||||
input word_ok,
|
input [RAM_WORD_WID-1:0] ram_word,
|
||||||
output word_rst,
|
output reg ram_read,
|
||||||
|
input ram_valid,
|
||||||
|
|
||||||
/* DAC wires. */
|
/* DAC wires. */
|
||||||
input dac_finished,
|
input dac_finished,
|
||||||
output dac_arm,
|
output dac_arm,
|
||||||
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,
|
||||||
|
@ -39,6 +45,28 @@ module autoapproach #(
|
||||||
input [ADC_WID-1:0] measurement
|
input [ADC_WID-1:0] measurement
|
||||||
);
|
);
|
||||||
|
|
||||||
|
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 (
|
||||||
|
.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)
|
||||||
|
);
|
||||||
|
|
||||||
localparam WAIT_ON_ARM = 0;
|
localparam WAIT_ON_ARM = 0;
|
||||||
localparam DO_WAIT = 1;
|
localparam DO_WAIT = 1;
|
||||||
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
#include <random>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#include "Vautoapproach_sim.h"
|
||||||
|
#include "../testbench.hpp"
|
||||||
|
|
||||||
|
/* TODO: generalize so bram_interface_sim can use it.
|
||||||
|
* This should make a triangle wave.
|
||||||
|
*/
|
||||||
|
class RefreshModule {
|
||||||
|
uint32_t *store_32;
|
||||||
|
size_t word_amnt;
|
||||||
|
bool pending_refresh_start;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void posedge(uint8_t &refresh_start, uint32_t &start_addr,
|
||||||
|
uint8_t refresh_finished) {
|
||||||
|
if (refresh_start && refresh_finished) {
|
||||||
|
refresh_start = 0;
|
||||||
|
} else if (pending_refresh_start && !refresh_start) {
|
||||||
|
pending_refresh_start = false;
|
||||||
|
refresh_start = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RefreshModule(size_t _word_amnt, size_t _start_addr)
|
||||||
|
: word_amnt{_word_amnt}
|
||||||
|
, start_addr{_start_addr} {
|
||||||
|
store_32 = new uint32_t[_start_addr];
|
||||||
|
for (size_t i = 0; i < start_addr; i++) {
|
||||||
|
/* 0xFFFFF is the maximum DAC value */
|
||||||
|
store_32[i] = 0xFFFFF*max(double)i/start_addr;
|
||||||
|
}
|
||||||
|
pending_refresh_start = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
~RefreshModule() {
|
||||||
|
delete[] store_32;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* TODO: make generic SPI delay class because this code has been duplicated
|
||||||
|
* many times over now. This function is also similar to the control loop
|
||||||
|
* ADC simulation. */
|
||||||
|
class GaussianZPiezo {
|
||||||
|
std::default_random_engine generator;
|
||||||
|
std::normal_distribution<> dist;
|
||||||
|
double scale;
|
||||||
|
double setpt;
|
||||||
|
double midpt;
|
||||||
|
double stretch;
|
||||||
|
|
||||||
|
double sample() {return scale*dist(generator);}
|
||||||
|
|
||||||
|
GaussianZPiezo(double scale, double mean, double dev, double setpt,
|
||||||
|
double midpt, double stretch, int seed,
|
||||||
|
uint16_t dac_wait_count,
|
||||||
|
uint16_t adc_wait_count)
|
||||||
|
: scale{scale}, dist{mean,dev}, generator{},
|
||||||
|
, setpt{setpt}, midpt{midpt}, stretch{stretch},
|
||||||
|
, dac_wait_count_max{dac_wait_count}
|
||||||
|
, adc_wait_count_max{adc_wait_count} {
|
||||||
|
if (seed < 0) {
|
||||||
|
std::random_device rd;
|
||||||
|
generator.seed(rd());
|
||||||
|
} else {
|
||||||
|
generator.seed(seed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Sigmoid function. This function is
|
||||||
|
|
||||||
|
c(x-d)
|
||||||
|
f(x) = A*-------------------
|
||||||
|
sqrt(1+(c(x-d))^2)
|
||||||
|
|
||||||
|
where A is the setpoint and c is how compressed the sigmoid is.
|
||||||
|
*/
|
||||||
|
|
||||||
|
double f(uint32_t x) {
|
||||||
|
double x_shift = x - midpt + sample();
|
||||||
|
return setpt*stretch*x_shift/sqrt(fma(x_shift,x_shift,1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
void posedge(uint8_t &dac_finished, uint8_t dac_arm,
|
||||||
|
uint32_t dac_out,
|
||||||
|
uint8_t &adc_finished, uint8_t adc_arm,
|
||||||
|
uint32_t &adc_out) {
|
||||||
|
if (adc_arm && adc_wait_counter == adc_wait_counter_max &&
|
||||||
|
!adc_finished) {
|
||||||
|
adc_finished = 1;
|
||||||
|
adc_out = sample();
|
||||||
|
} else if (!adc_arm) {
|
||||||
|
adc_finished = 0;
|
||||||
|
adc_wait_counter = 0;
|
||||||
|
} else {
|
||||||
|
adc_wait_counter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dac_arm && dac_wait_counter == dac_wait_counter_max &&
|
||||||
|
!dac_finished) {
|
||||||
|
dac_finished = 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class AA_TB : TB<Vautoapproach_sim> {
|
||||||
|
RefreshModule refresh;
|
||||||
|
GaussianZPiezo piezo;
|
||||||
|
|
||||||
|
void posedge() override;
|
||||||
|
AA_TB(size_t word_amnt, uint32_t start_addr)
|
||||||
|
: refresh{word_amnt, start_addr} {}
|
||||||
|
|
||||||
|
~AA_TB() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
AA_TB::posedge() {
|
||||||
|
refresh.posedge(mod.refresh_start, mod.start_addr,
|
||||||
|
mod.refresh_finished);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
module autoapproach_sim #(
|
||||||
|
parameter DAC_WID = 24,
|
||||||
|
parameter DAC_DATA_WID = 20,
|
||||||
|
parameter ADC_WID = 24,
|
||||||
|
parameter TIMER_WID = 32,
|
||||||
|
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_WORD_INCR = 2,
|
||||||
|
parameter TOTAL_RAM_WORD_MINUS_ONE = 4095
|
||||||
|
) (
|
||||||
|
input clk,
|
||||||
|
input arm,
|
||||||
|
output stopped,
|
||||||
|
output detected,
|
||||||
|
|
||||||
|
input polarity,
|
||||||
|
input [ADC_WID-1:0] setpoint,
|
||||||
|
input [TIMER_WID-1:0] time_to_wait,
|
||||||
|
|
||||||
|
/* User interface */
|
||||||
|
input refresh_start,
|
||||||
|
input [RAM_WID-1:0] start_addr,
|
||||||
|
output refresh_finished,
|
||||||
|
|
||||||
|
/* DAC wires. */
|
||||||
|
input dac_finished,
|
||||||
|
output dac_arm,
|
||||||
|
output [DAC_WID-1:0] dac_out,
|
||||||
|
|
||||||
|
input adc_finished,
|
||||||
|
output adc_arm,
|
||||||
|
input [ADC_WID-1:0] measurement
|
||||||
|
|
||||||
|
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)
|
||||||
|
);
|
||||||
|
|
||||||
|
autoapproach #(
|
||||||
|
.DAC_WID(DAC_WID),
|
||||||
|
.DAC_DATA_WID(DAC_DATA_WID),
|
||||||
|
.ADC_WID(ADC_WID),
|
||||||
|
.TIMER_WID(TIMER_WID),
|
||||||
|
.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)
|
||||||
|
) aa (
|
||||||
|
.clk(clk),
|
||||||
|
.arm(arm),
|
||||||
|
.stopped(stopped),
|
||||||
|
.detected(detected),
|
||||||
|
.polarity(polarity),
|
||||||
|
.setpoint(setpoint),
|
||||||
|
.time_to_wait(time_to_wait),
|
||||||
|
.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),
|
||||||
|
.dac_finished(dac_finished),
|
||||||
|
.dac_arm(dac_arm),
|
||||||
|
.dac_out(dac_out),
|
||||||
|
.adc_finished(adc_finished),
|
||||||
|
.adc_arm(adc_arm),
|
||||||
|
.measurement(measurement)
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,59 @@
|
||||||
|
#include "bram_dma.hpp"
|
||||||
|
#include "../util.hpp"
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
BRAM_DMA_Sim::BRAM_DMA_Sim(uint32_t _start_addr,
|
||||||
|
size_t _word_amnt,
|
||||||
|
size_t _timer_max) {
|
||||||
|
my_assert(_start_addr / 4 == 0, "start addr %d not 16 bit aligned",
|
||||||
|
_start_addr);
|
||||||
|
start_addr = _start_addr;
|
||||||
|
word_amnt = _word_amnt;
|
||||||
|
timer_max = _timer_max;
|
||||||
|
|
||||||
|
ram = new uint32_t[word_amnt];
|
||||||
|
}
|
||||||
|
|
||||||
|
BRAM_DMA_SIM::~BRAM_DMA_Sim() {
|
||||||
|
delete[] ram;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BRAM_DMA_Sim::generate_random_data() {
|
||||||
|
for (size_t i = 0; i < word_amnt; i++) {
|
||||||
|
ram[i] = mask_extend(rand(), 20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BRAM_DMA_Sim::execute_ram_access(uint32_t ram_dma_addr,
|
||||||
|
uint32_t &ram_word,
|
||||||
|
uint32_t &ram_valid) {
|
||||||
|
ram_valid = 1;
|
||||||
|
my_assert(ram_dma_addr < start_addr
|
||||||
|
|| ram_dma_addr >= start_addr + word_amnt*4,
|
||||||
|
"bad address %x\n", ram_dma_addr);
|
||||||
|
my_assert(ram_dma_addr >= start_addr, "left oob access %x",
|
||||||
|
tb->mod.ram_dma_addr);
|
||||||
|
my_assert(ram_dma_addr < start_addr + WORD_AMNT*4,
|
||||||
|
"right oob access %x", ram_dma_addr);
|
||||||
|
my_assert(ram_dma_addr % 2 == 0, "unaligned access %x",
|
||||||
|
ram_dma_addr);
|
||||||
|
|
||||||
|
const auto addr = (ram_dma_addr - start_addr) / 4;
|
||||||
|
if (tb->mod.ram_dma_addr % 4 == 0) {
|
||||||
|
ram_word = ram_refresh_data[addr] & 0xFFFF;
|
||||||
|
} else {
|
||||||
|
ram_word = ram_refresh_data[addr] >> 16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BRAM_DMA_Sim::posedge(uint32_t ram_dma_addr, uint32_t &ram_word,
|
||||||
|
uint32_t ram_read, uint32_t &ram_valid) {
|
||||||
|
if (ram_read && timer < timer_max) {
|
||||||
|
timer++;
|
||||||
|
if (timer == timer_max)
|
||||||
|
execute_ram_access(ram_dma_addr, ram_word, ram_valid);
|
||||||
|
} else {
|
||||||
|
ram_valid = 0;
|
||||||
|
timer = 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
#pragma once
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
template<size_t WORD_AMNT, size_t TIMER_MAX>
|
||||||
|
class BRAM_DMA_Sim {
|
||||||
|
uint32_t *ram;
|
||||||
|
|
||||||
|
uint32_t start_addr;
|
||||||
|
size_t word_amnt;
|
||||||
|
size_t timer_max;
|
||||||
|
|
||||||
|
int sim_timer;
|
||||||
|
|
||||||
|
void execute_ram_access(uint32_t ram_dma_addr, uint32_t &ram_word,
|
||||||
|
uint32_t &ram_valid);
|
||||||
|
public:
|
||||||
|
void generate_random_data();
|
||||||
|
BRAM_DMA(uint32_t _start_addr = 0x12340,
|
||||||
|
size_t _word_amnt = 2048,
|
||||||
|
size_t _timer_max = 10);
|
||||||
|
~BRAM_DMA();
|
||||||
|
void posedge(uint32_t ram_dma_addr, uint32_t &ram_word,
|
||||||
|
uint32_t ram_read, uint32_t &ram_valid);
|
||||||
|
|
||||||
|
};
|
|
@ -63,7 +63,7 @@ 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 < WORD_AMNT; i++) {
|
||||||
uint32_t val = mask_extend(rand(), 20);
|
uint32_t val = mask_extend(rand(), 20);
|
||||||
ram_refresh_data[i] = val;
|
ram_refresh_data[i] = val;
|
||||||
tb->mod.backing_store[i*2] = val & 0xFFFF;
|
tb->mod.backing_store[i*2] = val & 0xFFFF;
|
||||||
|
|
|
@ -19,10 +19,13 @@ template <class TOP> class TB {
|
||||||
mod.final();
|
mod.final();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void posedge() {}
|
||||||
|
|
||||||
void run_clock() {
|
void run_clock() {
|
||||||
mod.clk = !mod.clk;
|
mod.clk = !mod.clk;
|
||||||
mod.eval();
|
mod.eval();
|
||||||
Verilated::timeInc(1);
|
Verilated::timeInc(1);
|
||||||
|
posedge();
|
||||||
|
|
||||||
mod.clk = !mod.clk;
|
mod.clk = !mod.clk;
|
||||||
mod.eval();
|
mod.eval();
|
||||||
|
|
Loading…
Reference in New Issue