upsilon/gateware/rtl/control_loop/control_loop_math_sim.cpp

118 lines
2.9 KiB
C++

/* Copyright 2023 (C) Peter McGoron
* This file is a part of Upsilon, a free and open source software project.
* For license terms, refer to the files in `doc/copying` in the Upsilon
* source distribution.
*/
/* TODO: add ADC_TO_DAC multiplication and verify */
#include <cstdio>
#include <cstdint>
#include "control_loop_math_implementation.h"
#include "Vcontrol_loop_math.h"
using ModType = Vcontrol_loop_math;
uint32_t main_time = 0;
double sc_time_stamp() {
return main_time;
}
ModType *mod;
static void run_clock() {
for (int i = 0; i < 2; i++) {
mod->clk = !mod->clk;
mod->eval();
main_time++;
}
}
static void init(int argc, char **argv) {
Verilated::commandArgs(argc, argv);
Verilated::traceEverOn(true);
mod = new ModType;
mod->clk = 0;
mod->rst_L = 1;
}
#define MASK(n) ((1 << (n)) - 1)
using V = int64_t;
constexpr V per100 = 0b010101011110011000;
constexpr V adc_to_dac = 0b0101110111000000000000000000000000000000000;
static void calculate() {
/* Multiplication adds an extra CONSTS_FRAC bits to the end,
* truncate them. */
V err_cur = mulsat((V)mod->setpt - (V)mod->measured, adc_to_dac, 64, CONSTS_FRAC);
V dt = mulsat(per100, (V)mod->cycles << CONSTS_FRAC, 64, CONSTS_FRAC);
V idt = mulsat(dt, mod->cl_I, 64, CONSTS_FRAC);
V epidt = mulsat(err_cur << CONSTS_FRAC, mod->cl_P + idt, 64, CONSTS_FRAC);
V ep = mulsat((V)mod->e_prev << CONSTS_FRAC, mod->cl_P, 64, CONSTS_FRAC);
V new_adjval = mod->adjval_prev + epidt - ep;
mod->arm = 1;
do {
run_clock();
} while (!mod->finished);
mod->arm = 0;
run_clock();
run_clock();
/* Stupid bug: verilator does not sign-extend signed ports */
printf("err_cur %ld %ld\n", err_cur, sign_extend(mod->e_cur, E_WID));
printf("dt %ld %ld\n", dt, mod->dt_reg);
printf("idt %ld %ld\n", idt, mod->idt_reg);
printf("epidt %ld %ld\n", epidt, mod->epidt_reg);
printf("ep %ld %ld\n", ep, mod->ep_reg);
printf("adj %ld %ld\n", new_adjval, mod->adj_val);
}
int main(int argc, char **argv) {
init(argc, argv);
mod->arm = 0;
mod->rst_L = 1;
run_clock();
Transfer func = Transfer{150, 0, 2, 1.1, 10, -1};
/* Initial conditions */
mod->setpt = 10000;
mod->cl_P = 0b11010111000010100011110101110000101000111; /* 0.21 */
mod->cl_I = (V)12 << CONSTS_FRAC;
mod->cycles = 20; /* dummy number for now */
mod->e_prev = 0;
mod->adjval_prev = 0;
V setting = 100000;
printf("running\n");
for (int i = 0; i < 200; i++) {
mod->measured = func.val(setting);
mod->stored_dac_val = setting;
calculate();
mod->e_prev = mod->e_cur;
mod->adjval_prev = mod->adj_val;
/* C++ has no standard arithmetic right shift */
V adj;
if ((V)mod->adj_val > 0) {
adj = mod->adj_val >> CONSTS_FRAC;
} else {
adj = -((-mod->adj_val) >> CONSTS_FRAC);
}
printf("#%d: setting: %ld, measured: %ld, setpt: %ld, adj: %ld\n", i, setting, mod->measured, mod->setpt, adj);
setting += adj;
printf("new_dac_val %ld %ld\n", setting, mod->new_dac_val);
}
mod->final();
delete mod;
return 0;
}