control loop simulator passes lint
This commit is contained in:
parent
0114c449c3
commit
5909f548d5
|
@ -1,14 +1,17 @@
|
||||||
# Makefile for tests and hardware verification.
|
# Makefile for tests and hardware verification.
|
||||||
|
|
||||||
.PHONY: test clean
|
.PHONY: test clean
|
||||||
|
|
||||||
|
####### Tests ########
|
||||||
|
|
||||||
COMMON_CPP = control_loop_math_implementation.cpp
|
COMMON_CPP = control_loop_math_implementation.cpp
|
||||||
COMMON= ${COMMON_CPP} control_loop_math_implementation.h
|
COMMON= ${COMMON_CPP} control_loop_math_implementation.h
|
||||||
|
|
||||||
CONSTS_FRAC=43
|
CONSTS_FRAC=43
|
||||||
E_WID=21
|
E_WID=21
|
||||||
|
|
||||||
test: obj_dir/Vcontrol_loop_math
|
test: obj_dir/Vcontrol_loop_sim_top obj_dir/Vcontrol_loop_math
|
||||||
obj_dir/Vcontrol_loop_math
|
# obj_dir/Vcontrol_loop_math
|
||||||
clean:
|
clean:
|
||||||
rm -rf obj_dir *.fst
|
rm -rf obj_dir *.fst
|
||||||
|
|
||||||
|
@ -24,3 +27,24 @@ obj_dir/Vcontrol_loop_math.mk: control_loop_math_sim.cpp ${COMMON} \
|
||||||
obj_dir/Vcontrol_loop_math: obj_dir/Vcontrol_loop_math.mk
|
obj_dir/Vcontrol_loop_math: obj_dir/Vcontrol_loop_math.mk
|
||||||
cd obj_dir && make -f Vcontrol_loop_math.mk
|
cd obj_dir && make -f Vcontrol_loop_math.mk
|
||||||
|
|
||||||
|
obj_dir/Vcontrol_loop_sim_top.mk: control_loop_sim.cpp ${COMMON} \
|
||||||
|
adc_sim.v dac_sim.v \
|
||||||
|
../spi/spi_master_ss.v \
|
||||||
|
../spi/spi_slave_no_write.v \
|
||||||
|
control_loop_sim_top.v control_loop_sim_top.v
|
||||||
|
verilator --cc --exe -Wall --trace --trace-fst \
|
||||||
|
--top-module control_loop_sim_top \
|
||||||
|
-GCONSTS_FRAC=${CONSTS_FRAC} \
|
||||||
|
-CFLAGS -DCONSTS_FRAC=${CONSTS_FRAC} \
|
||||||
|
-CFLAGS -DE_WID=${E_WID} -I../spi \
|
||||||
|
control_loop_sim_top.v control_loop.v control_loop_sim.cpp \
|
||||||
|
${COMMON_CPP} adc_sim.v dac_sim.v ../spi/spi_master_ss.v \
|
||||||
|
../spi/spi_slave_no_read.v ../spi/spi_slave.v
|
||||||
|
obj_dir/Vcontrol_loop_sim_top: obj_dir/Vcontrol_loop_sim_top.mk control_loop_cmds.h
|
||||||
|
cd obj_dir && make -f Vcontrol_loop_sim_top.mk
|
||||||
|
|
||||||
|
####### Codegen ########
|
||||||
|
|
||||||
|
control_loop_cmds.h: control_loop_cmds.vh
|
||||||
|
echo '#pragma once' > control_loop_cmds.h
|
||||||
|
sed 's/`define/#define/g; s/`//g' control_loop_cmds.vh >> control_loop_cmds.h
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
module adc_sim #(
|
||||||
|
parameter POLARITY = 1,
|
||||||
|
parameter PHASE = 0,
|
||||||
|
parameter WID = 18,
|
||||||
|
parameter WID_LEN = 5
|
||||||
|
) (
|
||||||
|
input clk,
|
||||||
|
|
||||||
|
input [WID-1:0] indat,
|
||||||
|
output reg request,
|
||||||
|
input fulfilled,
|
||||||
|
output err,
|
||||||
|
|
||||||
|
output miso,
|
||||||
|
input sck,
|
||||||
|
input ss_L
|
||||||
|
);
|
||||||
|
|
||||||
|
wire ss = !ss_L;
|
||||||
|
reg ss_raised = 0;
|
||||||
|
reg fulfilled_raised = 0;
|
||||||
|
|
||||||
|
reg ss_buf_L = 1;
|
||||||
|
reg [WID-1:0] data = 0;
|
||||||
|
reg rdy = 0;
|
||||||
|
wire spi_fin;
|
||||||
|
|
||||||
|
always @ (posedge clk) begin
|
||||||
|
if (ss && !ss_raised) begin
|
||||||
|
request <= 1;
|
||||||
|
ss_raised <= 1;
|
||||||
|
end else if (ss_raised && !ss) begin
|
||||||
|
ss_raised <= 0;
|
||||||
|
ss_buf_L <= 1;
|
||||||
|
rdy <= 0;
|
||||||
|
request <= 0;
|
||||||
|
fulfilled_raised <= 0;
|
||||||
|
end else if (ss_raised && request && fulfilled && !fulfilled_raised) begin
|
||||||
|
data <= indat;
|
||||||
|
fulfilled_raised <= 1;
|
||||||
|
request <= 0;
|
||||||
|
end else if (ss_raised && request && !fulfilled && fulfilled_raised) begin
|
||||||
|
rdy <= 1;
|
||||||
|
fulfilled_raised <= 0;
|
||||||
|
ss_buf_L <= 0;
|
||||||
|
end else if (spi_fin) begin
|
||||||
|
rdy <= 0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
spi_slave_no_read #(
|
||||||
|
.WID(WID),
|
||||||
|
.WID_LEN(WID_LEN),
|
||||||
|
.POLARITY(POLARITY),
|
||||||
|
.PHASE(PHASE)
|
||||||
|
) spi (
|
||||||
|
.clk(clk),
|
||||||
|
.sck(sck),
|
||||||
|
.ss_L(ss_buf_L),
|
||||||
|
.miso(miso),
|
||||||
|
.to_master(data),
|
||||||
|
.finished(spi_fin),
|
||||||
|
.rdy(rdy),
|
||||||
|
.err(err)
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
`undefineall
|
|
@ -1,5 +1,4 @@
|
||||||
`include control_loop_cmds.vh
|
`include "control_loop_cmds.vh"
|
||||||
`define ERR_WID (ADC_WID + 1)
|
|
||||||
|
|
||||||
module control_loop
|
module control_loop
|
||||||
#(
|
#(
|
||||||
|
@ -17,14 +16,10 @@ module control_loop
|
||||||
|
|
||||||
parameter CONSTS_WHOLE = 21,
|
parameter CONSTS_WHOLE = 21,
|
||||||
parameter CONSTS_FRAC = 43,
|
parameter CONSTS_FRAC = 43,
|
||||||
|
parameter CONSTS_SIZ = 7,
|
||||||
`define CONSTS_WID (CONSTS_WHOLE + CONSTS_FRAC)
|
`define CONSTS_WID (CONSTS_WHOLE + CONSTS_FRAC)
|
||||||
parameter DELAY_WID = 16,
|
parameter DELAY_WID = 16,
|
||||||
/* [ERR_WID_SIZ-1:0] must be able to store
|
|
||||||
* ERR_WID (= ADC_WID + 1).
|
|
||||||
*/
|
|
||||||
parameter ERR_WID_SIZ = 6,
|
|
||||||
`define DATA_WID `CONSTS_WID
|
`define DATA_WID `CONSTS_WID
|
||||||
`define E_WID (ADC_WID + 1)
|
|
||||||
parameter READ_DAC_DELAY = 5,
|
parameter READ_DAC_DELAY = 5,
|
||||||
parameter CYCLE_COUNT_WID = 18,
|
parameter CYCLE_COUNT_WID = 18,
|
||||||
parameter DAC_WID = 24,
|
parameter DAC_WID = 24,
|
||||||
|
@ -34,6 +29,7 @@ module control_loop
|
||||||
*/
|
*/
|
||||||
parameter DAC_WID_SIZ = 5,
|
parameter DAC_WID_SIZ = 5,
|
||||||
parameter DAC_DATA_WID = 20,
|
parameter DAC_DATA_WID = 20,
|
||||||
|
`define E_WID (DAC_DATA_WID + 1)
|
||||||
parameter DAC_POLARITY = 0,
|
parameter DAC_POLARITY = 0,
|
||||||
parameter DAC_PHASE = 1,
|
parameter DAC_PHASE = 1,
|
||||||
parameter DAC_CYCLE_HALF_WAIT = 10,
|
parameter DAC_CYCLE_HALF_WAIT = 10,
|
||||||
|
@ -49,13 +45,13 @@ module control_loop
|
||||||
output dac_sck,
|
output dac_sck,
|
||||||
|
|
||||||
input adc_miso,
|
input adc_miso,
|
||||||
output adc_conv,
|
output adc_conv_L,
|
||||||
output adc_sck,
|
output adc_sck,
|
||||||
|
|
||||||
/* Hacky ad-hoc read-write interface. */
|
/* Hacky ad-hoc read-write interface. */
|
||||||
input reg [CONTROL_LOOP_CMD_WIDTH-1:0] cmd,
|
input reg [`CONTROL_LOOP_CMD_WIDTH-1:0] cmd,
|
||||||
input reg [DATA_WIDTH-1:0] word_in,
|
input reg [`DATA_WID-1:0] word_in,
|
||||||
output reg [DATA_WIDTH-1:0] word_out,
|
output reg [`DATA_WID-1:0] word_out,
|
||||||
input start_cmd,
|
input start_cmd,
|
||||||
output reg finish_cmd
|
output reg finish_cmd
|
||||||
);
|
);
|
||||||
|
@ -64,8 +60,13 @@ module control_loop
|
||||||
|
|
||||||
reg dac_arm;
|
reg dac_arm;
|
||||||
reg dac_finished;
|
reg dac_finished;
|
||||||
|
reg dac_ss = 0;
|
||||||
|
assign dac_ss_L = !dac_ss;
|
||||||
|
|
||||||
reg [DAC_WID-1:0] to_dac;
|
reg [DAC_WID-1:0] to_dac;
|
||||||
|
/* verilator lint_off UNUSED */
|
||||||
wire [DAC_WID-1:0] from_dac;
|
wire [DAC_WID-1:0] from_dac;
|
||||||
|
/* verilator lint_on UNUSED */
|
||||||
spi_master_ss #(
|
spi_master_ss #(
|
||||||
.WID(DAC_WID),
|
.WID(DAC_WID),
|
||||||
.WID_LEN(DAC_WID_SIZ),
|
.WID_LEN(DAC_WID_SIZ),
|
||||||
|
@ -77,7 +78,6 @@ spi_master_ss #(
|
||||||
.SS_WAIT_TIMER_LEN(DAC_SS_WAIT_SIZ)
|
.SS_WAIT_TIMER_LEN(DAC_SS_WAIT_SIZ)
|
||||||
) dac_master (
|
) dac_master (
|
||||||
.clk(clk),
|
.clk(clk),
|
||||||
.arm(dac_arm),
|
|
||||||
.mosi(dac_mosi),
|
.mosi(dac_mosi),
|
||||||
.miso(dac_miso),
|
.miso(dac_miso),
|
||||||
.sck_wire(dac_sck),
|
.sck_wire(dac_sck),
|
||||||
|
@ -92,7 +92,7 @@ reg adc_arm;
|
||||||
reg adc_finished;
|
reg adc_finished;
|
||||||
wire [ADC_WID-1:0] measured_value;
|
wire [ADC_WID-1:0] measured_value;
|
||||||
|
|
||||||
localparam [3-1:0] DAC_REGISTER = 3b'001;
|
localparam [3-1:0] DAC_REGISTER = 3'b001;
|
||||||
|
|
||||||
spi_master_ss_no_write #(
|
spi_master_ss_no_write #(
|
||||||
.WID(ADC_WID),
|
.WID(ADC_WID),
|
||||||
|
@ -109,7 +109,7 @@ spi_master_ss_no_write #(
|
||||||
.from_slave(measured_value),
|
.from_slave(measured_value),
|
||||||
.miso(adc_miso),
|
.miso(adc_miso),
|
||||||
.sck_wire(adc_sck),
|
.sck_wire(adc_sck),
|
||||||
.ss_L(!ss_conv),
|
.ss_L(adc_conv_L),
|
||||||
.finished(adc_finished)
|
.finished(adc_finished)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -143,12 +143,13 @@ reg running = 0;
|
||||||
|
|
||||||
reg signed [DAC_DATA_WID-1:0] stored_dac_val = 0;
|
reg signed [DAC_DATA_WID-1:0] stored_dac_val = 0;
|
||||||
reg [CYCLE_COUNT_WID-1:0] last_timer = 0;
|
reg [CYCLE_COUNT_WID-1:0] last_timer = 0;
|
||||||
reg [CYCLE_COUNT_WID-1:0] debug_timer = 0;
|
reg [CYCLE_COUNT_WID-1:0] counting_timer = 0;
|
||||||
reg [`CONSTS_WID-1:0] adjval_prev = 0;
|
reg [`CONSTS_WID-1:0] adjval_prev = 0;
|
||||||
|
|
||||||
reg signed [`E_WID-1:0] err_prev = 0;
|
reg signed [`E_WID-1:0] err_prev = 0;
|
||||||
wire signed [`E_WID-1:0] e_cur = 0;
|
wire signed [`E_WID-1:0] e_cur;
|
||||||
wire signed [`CONSTS_WID-1:0] adj_val = 0;
|
wire signed [`CONSTS_WID-1:0] adj_val;
|
||||||
|
wire signed [DAC_DATA_WID-1:0] new_dac_val;
|
||||||
|
|
||||||
reg arm_math = 0;
|
reg arm_math = 0;
|
||||||
reg math_finished = 0;
|
reg math_finished = 0;
|
||||||
|
@ -157,7 +158,10 @@ control_loop_math #(
|
||||||
.CONSTS_FRAC(CONSTS_FRAC),
|
.CONSTS_FRAC(CONSTS_FRAC),
|
||||||
.CONSTS_SIZ(CONSTS_SIZ),
|
.CONSTS_SIZ(CONSTS_SIZ),
|
||||||
.ADC_WID(ADC_WID),
|
.ADC_WID(ADC_WID),
|
||||||
.CYCLE_COUNT_WID(CYCLE_COUNT_WID)
|
.DAC_WID(DAC_DATA_WID),
|
||||||
|
.CYCLE_COUNT_WID(CYCLE_COUNT_WID),
|
||||||
|
.SEC_PER_CYCLE('b10101011110011000),
|
||||||
|
.ADC_TO_DAC({32'b01000001100, 32'b01001001101110100101111000110101})
|
||||||
) math (
|
) math (
|
||||||
.clk(clk),
|
.clk(clk),
|
||||||
.arm(arm_math),
|
.arm(arm_math),
|
||||||
|
@ -169,6 +173,8 @@ control_loop_math #(
|
||||||
.cycles(last_timer),
|
.cycles(last_timer),
|
||||||
.e_prev(err_prev),
|
.e_prev(err_prev),
|
||||||
.adjval_prev(adjval_prev),
|
.adjval_prev(adjval_prev),
|
||||||
|
.stored_dac_val(stored_dac_val),
|
||||||
|
.new_dac_val(new_dac_val),
|
||||||
.e_cur(e_cur),
|
.e_cur(e_cur),
|
||||||
.adj_val(adj_val)
|
.adj_val(adj_val)
|
||||||
);
|
);
|
||||||
|
@ -208,12 +214,13 @@ control_loop_math #(
|
||||||
localparam CYCLE_START = 0;
|
localparam CYCLE_START = 0;
|
||||||
localparam WAIT_ON_ADC = 1;
|
localparam WAIT_ON_ADC = 1;
|
||||||
localparam WAIT_ON_MATH = 2;
|
localparam WAIT_ON_MATH = 2;
|
||||||
|
localparam WAIT_ON_DAC = 6;
|
||||||
localparam INIT_READ_FROM_DAC = 3;
|
localparam INIT_READ_FROM_DAC = 3;
|
||||||
localparam WAIT_FOR_DAC_READ = 4;
|
localparam WAIT_FOR_DAC_READ = 4;
|
||||||
localparam WAIT_FOR_DAC_RESPONSE = 5;
|
localparam WAIT_FOR_DAC_RESPONSE = 5;
|
||||||
localparam STATESIZ = 3;
|
localparam STATESIZ = 3;
|
||||||
|
|
||||||
reg [STATESIZ-1:0] state = CYCLE_START;
|
reg [STATESIZ-1:0] state = INIT_READ_FROM_DAC;
|
||||||
|
|
||||||
reg [DELAY_WID-1:0] timer = 0;
|
reg [DELAY_WID-1:0] timer = 0;
|
||||||
|
|
||||||
|
@ -232,85 +239,88 @@ end
|
||||||
* the main loop is clearing the dirty bit.
|
* the main loop is clearing the dirty bit.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
wire write_control = state == CYCLE_START;
|
wire write_control = state == CYCLE_START || !running;
|
||||||
reg dirty_bit = 0;
|
reg dirty_bit = 0;
|
||||||
|
|
||||||
always @ (posedge clk) begin
|
always @ (posedge clk) begin
|
||||||
if (start_cmd && !finish_cmd) begin
|
if (start_cmd && !finish_cmd) begin
|
||||||
case (cmd)
|
case (cmd)
|
||||||
CONTROL_LOOP_NOOP: CONTROL_LOOP_NOOP | CONTROL_LOOP_WRITE_BIT:
|
`CONTROL_LOOP_NOOP:
|
||||||
finish_cmd <= 1;
|
finish_cmd <= 1;
|
||||||
CONTROL_LOOP_STATUS: begin
|
`CONTROL_LOOP_NOOP | `CONTROL_LOOP_WRITE_BIT:
|
||||||
word_out[DATA_WID-1:1] <= 0;
|
finish_cmd <= 1;
|
||||||
|
`CONTROL_LOOP_STATUS: begin
|
||||||
|
word_out[`DATA_WID-1:1] <= 0;
|
||||||
word_out[0] <= running;
|
word_out[0] <= running;
|
||||||
finish_cmd <= 1;
|
finish_cmd <= 1;
|
||||||
end
|
end
|
||||||
CONTROL_LOOP_STATUS | CONTROL_LOOP_WRITE_BIT:
|
`CONTROL_LOOP_STATUS | `CONTROL_LOOP_WRITE_BIT:
|
||||||
if (write_control) begin
|
if (write_control) begin
|
||||||
running <= word_in[0];
|
running <= word_in[0];
|
||||||
finish_cmd <= 1;
|
finish_cmd <= 1;
|
||||||
dirty_bit <= 1;
|
dirty_bit <= 1;
|
||||||
end
|
end
|
||||||
CONTROL_LOOP_SETPT: begin
|
`CONTROL_LOOP_SETPT: begin
|
||||||
word_out[DATA_WID-1:ADC_WID] <= 0;
|
word_out[`DATA_WID-1:ADC_WID] <= 0;
|
||||||
word_out[ADC_WID-1:0] <= setpt;
|
word_out[ADC_WID-1:0] <= setpt;
|
||||||
finish_cmd <= 1;
|
finish_cmd <= 1;
|
||||||
end
|
end
|
||||||
CONTROL_LOOP_SETPT | CONTROL_LOOP_WRITE_BIT:
|
`CONTROL_LOOP_SETPT | `CONTROL_LOOP_WRITE_BIT:
|
||||||
if (write_control) begin
|
if (write_control) begin
|
||||||
setpt_buffer <= word_in[ADC_WID-1:0];
|
setpt_buffer <= word_in[ADC_WID-1:0];
|
||||||
finish_cmd <= 1;
|
finish_cmd <= 1;
|
||||||
dirty_bit <= 1;
|
dirty_bit <= 1;
|
||||||
end
|
end
|
||||||
CONTROL_LOOP_P: begin
|
`CONTROL_LOOP_P: begin
|
||||||
word_out <= cl_p_reg;
|
word_out <= cl_p_reg;
|
||||||
finish_cmd <= 1;
|
finish_cmd <= 1;
|
||||||
end
|
end
|
||||||
CONTROL_LOOP_P | CONTROL_LOOP_WRITE_BIT: begin
|
`CONTROL_LOOP_P | `CONTROL_LOOP_WRITE_BIT: begin
|
||||||
if (write_control) begin
|
if (write_control) begin
|
||||||
cl_p_reg_buffer <= word_in;
|
cl_p_reg_buffer <= word_in;
|
||||||
finish_cmd <= 1;
|
finish_cmd <= 1;
|
||||||
dirty_bit <= 1;
|
dirty_bit <= 1;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
CONTROL_LOOP_I: begin
|
`CONTROL_LOOP_I: begin
|
||||||
word_out <= cl_I_reg;
|
word_out <= cl_I_reg;
|
||||||
finish_cmd <= 1;
|
finish_cmd <= 1;
|
||||||
end
|
end
|
||||||
CONTROL_LOOP_I | CONTROL_LOOP_WRITE_BIT: begin
|
`CONTROL_LOOP_I | `CONTROL_LOOP_WRITE_BIT: begin
|
||||||
if (write_control) begin
|
if (write_control) begin
|
||||||
cl_I_reg_buffer <= word_in;
|
cl_I_reg_buffer <= word_in;
|
||||||
finish_cmd <= 1;
|
finish_cmd <= 1;
|
||||||
dirty_bit <= 1;
|
dirty_bit <= 1;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
CONTROL_LOOP_DELAY: begin
|
`CONTROL_LOOP_DELAY: begin
|
||||||
word_out[DATA_WID-1:DELAY_WID] <= 0;
|
word_out[`DATA_WID-1:DELAY_WID] <= 0;
|
||||||
word_out[DELAY_WID-1:0] <= dely;
|
word_out[DELAY_WID-1:0] <= dely;
|
||||||
finish_cmd <= 1;
|
finish_cmd <= 1;
|
||||||
end
|
end
|
||||||
CONTROL_LOOP_DELAY | CONTROL_LOOP_WRITE_BIT: begin
|
`CONTROL_LOOP_DELAY | `CONTROL_LOOP_WRITE_BIT: begin
|
||||||
if (write_control) begin
|
if (write_control) begin
|
||||||
dely_buffer <= word_in[DELAY_WID-1:0];
|
dely_buffer <= word_in[DELAY_WID-1:0];
|
||||||
finish_cmd <= 1;
|
finish_cmd <= 1;
|
||||||
dirty_bit <= 1;
|
dirty_bit <= 1;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
CONTROL_LOOP_ERR: begin
|
`CONTROL_LOOP_ERR: begin
|
||||||
word_out[DATA_WID-1:ERR_WID] <= 0;
|
word_out[`DATA_WID-1:`E_WID] <= 0;
|
||||||
word_out[ERR_WID-1:0] <= err_prev;
|
word_out[`E_WID-1:0] <= err_prev;
|
||||||
finish_cmd <= 1;
|
finish_cmd <= 1;
|
||||||
end
|
end
|
||||||
CONTROL_LOOP_Z: begin
|
`CONTROL_LOOP_Z: begin
|
||||||
word_out[DATA_WID-1:DAC_DATA_WID] <= 0;
|
word_out[`DATA_WID-1:DAC_DATA_WID] <= 0;
|
||||||
word_out[DAC_DATA_WID-1:0] <= stored_dac_val;
|
word_out[DAC_DATA_WID-1:0] <= stored_dac_val;
|
||||||
finish_cmd <= 1;
|
finish_cmd <= 1;
|
||||||
end
|
end
|
||||||
CONTROL_LOOP_CYCLES: begin
|
`CONTROL_LOOP_CYCLES: begin
|
||||||
word_out[DATA_WID-1:CYCLE_COUNT_WID] <= 0;
|
word_out[`DATA_WID-1:CYCLE_COUNT_WID] <= 0;
|
||||||
word_out[CYCLE_COUNT_WID-1:0] <= last_timer;
|
word_out[CYCLE_COUNT_WID-1:0] <= last_timer;
|
||||||
finish_cmd <= 0;
|
finish_cmd <= 0;
|
||||||
end
|
end
|
||||||
|
endcase
|
||||||
end else if (!start_cmd) begin
|
end else if (!start_cmd) begin
|
||||||
finish_cmd <= 0;
|
finish_cmd <= 0;
|
||||||
end
|
end
|
||||||
|
@ -320,7 +330,7 @@ always @ (posedge clk) begin
|
||||||
case (state)
|
case (state)
|
||||||
INIT_READ_FROM_DAC: begin
|
INIT_READ_FROM_DAC: begin
|
||||||
if (running) begin
|
if (running) begin
|
||||||
to_dac <= {1, DAC_REGISTER, 20b'0};
|
to_dac <= {1'b1, DAC_REGISTER, 20'b0};
|
||||||
dac_arm <= 1;
|
dac_arm <= 1;
|
||||||
state <= WAIT_FOR_DAC_READ;
|
state <= WAIT_FOR_DAC_READ;
|
||||||
end
|
end
|
||||||
|
@ -337,13 +347,13 @@ always @ (posedge clk) begin
|
||||||
timer <= timer + 1;
|
timer <= timer + 1;
|
||||||
end else if (timer == READ_DAC_DELAY) begin
|
end else if (timer == READ_DAC_DELAY) begin
|
||||||
dac_arm <= 1;
|
dac_arm <= 1;
|
||||||
to_dac <= 24b'0;
|
to_dac <= 24'b0;
|
||||||
timer <= 0;
|
timer <= 0;
|
||||||
end else if (dac_finished) begin
|
end else if (dac_finished) begin
|
||||||
state <= CYCLE_START;
|
state <= CYCLE_START;
|
||||||
dac_ss <= 0;
|
dac_ss <= 0;
|
||||||
dac_arm <= 0;
|
dac_arm <= 0;
|
||||||
stored_dac_val <= from_dac;
|
stored_dac_val <= from_dac[DAC_DATA_WID-1:0];
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
CYCLE_START: begin
|
CYCLE_START: begin
|
||||||
|
@ -355,10 +365,10 @@ always @ (posedge clk) begin
|
||||||
/* On change of constants, previous values are invalidated. */
|
/* On change of constants, previous values are invalidated. */
|
||||||
if (dirty_bit) begin
|
if (dirty_bit) begin
|
||||||
setpt <= setpt_buffer;
|
setpt <= setpt_buffer;
|
||||||
dely <= dely_buf;
|
dely <= dely_buffer;
|
||||||
cl_alpha_reg <= cl_alpha_reg_buffer;
|
cl_I_reg <= cl_I_reg_buffer;
|
||||||
cl_p_reg <= cl_p_reg_buffer;
|
cl_p_reg <= cl_p_reg_buffer;
|
||||||
adj_prev <= 0;
|
adjval_prev <= 0;
|
||||||
err_prev <= 0;
|
err_prev <= 0;
|
||||||
|
|
||||||
dirty_bit <= 0;
|
dirty_bit <= 0;
|
||||||
|
@ -377,19 +387,19 @@ always @ (posedge clk) begin
|
||||||
WAIT_ON_MATH: if (math_finished) begin
|
WAIT_ON_MATH: if (math_finished) begin
|
||||||
arm_math <= 0;
|
arm_math <= 0;
|
||||||
dac_arm <= 1;
|
dac_arm <= 1;
|
||||||
stored_dac_val <= (stored_dac_val + adj_val[`CONSTS_WID-1:CONSTS_FRAC]);
|
stored_dac_val <= new_dac_val;
|
||||||
to_dac <= {0, DAC_REGISTER, (dac_adj_val + adj_val[`CONSTS_WID-1:CONSTS_FRAC]);
|
to_dac <= {1'b0, DAC_REGISTER, new_dac_val};
|
||||||
state <= WAIT_ON_DAC;
|
state <= WAIT_ON_DAC;
|
||||||
end
|
end
|
||||||
WAIT_ON_DAC: if (dac_finished) begin
|
WAIT_ON_DAC: if (dac_finished) begin
|
||||||
state <= CYCLE_START;
|
state <= CYCLE_START;
|
||||||
dac_ss <= 0;
|
|
||||||
dac_arm <= 0;
|
dac_arm <= 0;
|
||||||
|
|
||||||
err_prev <= err_cur;
|
err_prev <= e_cur;
|
||||||
adj_old <= newadj;
|
adjval_prev <= adj_val;
|
||||||
end
|
end
|
||||||
end
|
endcase
|
||||||
end
|
end
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
`undefineall
|
||||||
|
|
|
@ -6,5 +6,6 @@
|
||||||
`define CONTROL_LOOP_ERR 5
|
`define CONTROL_LOOP_ERR 5
|
||||||
`define CONTROL_LOOP_Z 6
|
`define CONTROL_LOOP_Z 6
|
||||||
`define CONTROL_LOOP_CYCLES 7
|
`define CONTROL_LOOP_CYCLES 7
|
||||||
`define CONTROL_LOOP_WRITE_BIT (1 << (CONTROL_LOOP_CMD_WIDTH-1))
|
`define CONTROL_LOOP_DELAY 8
|
||||||
`define CONTROL_LOOP_CMD_WIDTH 8
|
`define CONTROL_LOOP_CMD_WIDTH 8
|
||||||
|
`define CONTROL_LOOP_WRITE_BIT (1 << (`CONTROL_LOOP_CMD_WIDTH-1))
|
||||||
|
|
|
@ -33,7 +33,7 @@ module control_loop_math #(
|
||||||
/* The conversion between the ADC bit (20/2**18) and DAC bit (20.48/2**20)
|
/* The conversion between the ADC bit (20/2**18) and DAC bit (20.48/2**20)
|
||||||
* is 0.256.
|
* is 0.256.
|
||||||
*/
|
*/
|
||||||
parameter logic [`CONSTS_WID-1:0] ADC_TO_DAC = {32'b01000001100, 32'b01001001101110100101111000110101},
|
parameter [`CONSTS_WID-1:0] ADC_TO_DAC = 64'b0100000110001001001101110100101111000110101,
|
||||||
parameter CYCLE_COUNT_WID = 18,
|
parameter CYCLE_COUNT_WID = 18,
|
||||||
parameter DAC_WID = 20
|
parameter DAC_WID = 20
|
||||||
`define E_WID (DAC_WID + 1)
|
`define E_WID (DAC_WID + 1)
|
||||||
|
@ -49,6 +49,7 @@ module control_loop_math #(
|
||||||
input signed [CYCLE_COUNT_WID-1:0] cycles,
|
input signed [CYCLE_COUNT_WID-1:0] cycles,
|
||||||
input signed [`E_WID-1:0] e_prev,
|
input signed [`E_WID-1:0] e_prev,
|
||||||
input signed [`CONSTS_WID-1:0] adjval_prev,
|
input signed [`CONSTS_WID-1:0] adjval_prev,
|
||||||
|
input signed [DAC_WID-1:0] stored_dac_val,
|
||||||
|
|
||||||
`ifdef DEBUG_CONTROL_LOOP_MATH
|
`ifdef DEBUG_CONTROL_LOOP_MATH
|
||||||
output reg [`CONSTS_WID-1:0] dt_reg,
|
output reg [`CONSTS_WID-1:0] dt_reg,
|
||||||
|
@ -58,6 +59,7 @@ module control_loop_math #(
|
||||||
`endif
|
`endif
|
||||||
|
|
||||||
output reg signed [`E_WID-1:0] e_cur,
|
output reg signed [`E_WID-1:0] e_cur,
|
||||||
|
output signed [DAC_WID-1:0] new_dac_val,
|
||||||
output signed [`CONSTS_WID-1:0] adj_val
|
output signed [`CONSTS_WID-1:0] adj_val
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -127,6 +129,18 @@ intsat #(
|
||||||
.outp(saturated_add)
|
.outp(saturated_add)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/************************
|
||||||
|
* Safely calculate new DAC value.
|
||||||
|
************************/
|
||||||
|
reg signed [DAC_WID+1-1:0] add_sat_dac;
|
||||||
|
intsat #(
|
||||||
|
.IN_LEN(DAC_WID+1),
|
||||||
|
.LTRUNC(1)
|
||||||
|
) dac_saturate (
|
||||||
|
.inp(add_sat_dac),
|
||||||
|
.outp(new_dac_val)
|
||||||
|
);
|
||||||
|
|
||||||
localparam WAIT_ON_ARM = 0;
|
localparam WAIT_ON_ARM = 0;
|
||||||
localparam CALCULATE_ERR = 9;
|
localparam CALCULATE_ERR = 9;
|
||||||
localparam CALCULATE_DAC_E = 7;
|
localparam CALCULATE_DAC_E = 7;
|
||||||
|
@ -136,6 +150,7 @@ localparam CALCULATE_EPIDT = 3;
|
||||||
localparam CALCULATE_EP = 4;
|
localparam CALCULATE_EP = 4;
|
||||||
localparam CALCULATE_A_PART_1 = 5;
|
localparam CALCULATE_A_PART_1 = 5;
|
||||||
localparam CALCULATE_A_PART_2 = 6;
|
localparam CALCULATE_A_PART_2 = 6;
|
||||||
|
localparam CALCULATE_NEW_DAC_VALUE = 10;
|
||||||
localparam WAIT_ON_DISARM = 8;
|
localparam WAIT_ON_DISARM = 8;
|
||||||
|
|
||||||
reg [4:0] state = WAIT_ON_ARM;
|
reg [4:0] state = WAIT_ON_ARM;
|
||||||
|
@ -236,8 +251,14 @@ always @ (posedge clk) begin
|
||||||
end
|
end
|
||||||
CALCULATE_A_PART_2: begin
|
CALCULATE_A_PART_2: begin
|
||||||
add_sat <= tmpstore;
|
add_sat <= tmpstore;
|
||||||
|
state <= CALCULATE_NEW_DAC_VALUE;
|
||||||
|
end
|
||||||
|
CALCULATE_NEW_DAC_VALUE: begin
|
||||||
|
add_sat_dac <= saturated_add[CONSTS_FRAC+DAC_WID-1:CONSTS_FRAC]
|
||||||
|
+ stored_dac_val;
|
||||||
|
adj_val <= saturated_add;
|
||||||
state <= WAIT_ON_DISARM;
|
state <= WAIT_ON_DISARM;
|
||||||
end
|
end
|
||||||
WAIT_ON_DISARM: begin
|
WAIT_ON_DISARM: begin
|
||||||
adj_val <= saturated_add;
|
adj_val <= saturated_add;
|
||||||
if (!arm) begin
|
if (!arm) begin
|
||||||
|
|
|
@ -8,205 +8,77 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <verilated.h>
|
#include <verilated.h>
|
||||||
#include "Vcontrol_loop.h"
|
#include "control_loop_math_implementation.h"
|
||||||
|
#include "control_loop_cmds.h"
|
||||||
|
#include "Vcontrol_loop_sim_top.h"
|
||||||
|
using ModType = Vcontrol_loop_sim_top;
|
||||||
|
|
||||||
Vcontrol_loop *mod;
|
uint32_t main_time = 0;
|
||||||
|
double sc_time_stamp() {
|
||||||
/* Very simple simulation of measurement.
|
return main_time;
|
||||||
* A transfer function defines the mapping from the DAC values
|
|
||||||
* -2**(20) -> 2**(20)-1
|
|
||||||
* to the values -2**(18) -> 2**18 - 1.
|
|
||||||
*
|
|
||||||
* The transfer function has Gaussian noise which is added at each
|
|
||||||
* measurement.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Transfer {
|
|
||||||
std::default_random_engine generator;
|
|
||||||
std::normal_distribution dist;
|
|
||||||
double scale;
|
|
||||||
|
|
||||||
double sample() {return scale*dist(rd);}
|
|
||||||
|
|
||||||
public:
|
|
||||||
Transfer(double scale, double mean, double dev, double m, double b, int seed)
|
|
||||||
: scale{scale}, dist{mean,dev}, generator{} {
|
|
||||||
if (seed < 0) {
|
|
||||||
std::random_device rd;
|
|
||||||
generator.seed(rd());
|
|
||||||
} else {
|
|
||||||
generator.seed(seed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
double val(double x) {
|
|
||||||
return m*x + b + sample();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Each constant is 48 bits long, with 15 whole bits.
|
|
||||||
constexpr auto CONSTS_WHOLE_WID = 15;
|
|
||||||
constexpr auto CONSTS_WID = 48;
|
|
||||||
constexpr auto CONSTS_FRAC_WID = CONSTS_WID - CONSTS_WHOLE_WID;
|
|
||||||
constexpr auto CONSTS_FRAC_MASK = (1 << CONSTS_FRAC_WID) - 1;
|
|
||||||
|
|
||||||
constexpr uint64_t fractional_base_conv(uint64_t input) {
|
|
||||||
/* Fractional base conversion algorithm.
|
|
||||||
Given an integer in base M (i.e. 10) there is an expansion in base N (i.e. 2):
|
|
||||||
0.abcdefgh... = 0.ijklmnop...
|
|
||||||
where abcdefgh... are in base M and ijklmnop... are in base N. The algorithm
|
|
||||||
computes the digits in base N.
|
|
||||||
|
|
||||||
Multiply the converted number by N. Then there are new numbers:
|
|
||||||
A.BCDEFGH... = i.jklmnop...
|
|
||||||
Since 0.abcdefgh < 1, A.BCDEFGH < N. Therefore
|
|
||||||
the digit "A" must be a number less than N. Then i = A. Cutting off all the
|
|
||||||
other digits,
|
|
||||||
0.BCDEFGH... = 0.jklmnop...
|
|
||||||
continue until there are no more digits left.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Calculate the lowest power of 10 greater than input.
|
|
||||||
This can be done with logarithms, but floating point is not available on
|
|
||||||
some embedded platforms. This makes the code more portable.
|
|
||||||
*/
|
|
||||||
uint64_t pow10 = 1;
|
|
||||||
while (input / pow10 > 0)
|
|
||||||
pow10 *= 10;
|
|
||||||
|
|
||||||
uint64_t out = 0;
|
|
||||||
for (unsigned i = 0; i < CONSTS_FRAC_WID; i++) {
|
|
||||||
input *= 2;
|
|
||||||
uint64_t dig = input / pow10, mod = input % pow10;
|
|
||||||
out = dig | (out << 1);
|
|
||||||
input = mod;
|
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t multiply_unity(uint64_t i, int sign) {
|
ModType *mod;
|
||||||
if (sign > 0) {
|
|
||||||
return std::reinterpret_cast<int64_t>(i);
|
static void run_clock() {
|
||||||
} else {
|
for (int i = 0; i < 2; i++) {
|
||||||
return std::reinterpret_cast<int64_t>(~i + 1);
|
mod->clk = !mod->clk;
|
||||||
|
mod->eval();
|
||||||
|
main_time++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr uint64_t SCALE_WHOLE = 12820;
|
static void init(int argc, char **argv) {
|
||||||
constexpr uint64_t SCALE_FRAC = fractional_base_conv(51282051282);
|
|
||||||
constexpr uint64_t SCALE_NUM = (SCALE_WHOLE << CONSTS_FRAC_WID) | SCALE_FRAC;
|
|
||||||
|
|
||||||
static int64_t signed_to_fxp(char *s) {
|
|
||||||
// Skip whitespace.
|
|
||||||
while (isspace(*c++));
|
|
||||||
// Check if number is negative.
|
|
||||||
int sign = 1;
|
|
||||||
if (*s == '-') {
|
|
||||||
pos = -1;
|
|
||||||
s++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Split the number into whole and fractional components.
|
|
||||||
char *p = strchr(s, '.');
|
|
||||||
if (!p)
|
|
||||||
return multiply_unity(strtoull(s, NULL, 10), sign);
|
|
||||||
*p = 0;
|
|
||||||
// s now points to a NUL terminated string with the whole number
|
|
||||||
// component.
|
|
||||||
uint64_t whole = strtoull(s, NULL, 10);
|
|
||||||
|
|
||||||
p++;
|
|
||||||
// p is the start of the fractional component.
|
|
||||||
uint64_t frac_decimal = strtoull(p, NULL, 10);
|
|
||||||
uint64_t final = ((whole << CONSTS_FRAC_WID) | fractional_base_conv(frac_decimal, CONSTS_FRAC_WID))
|
|
||||||
* SCALE_NUM;
|
|
||||||
return multiply_unity(final, sign);
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string fxp_to_str(int64_t inum, unsigned decdigs) {
|
|
||||||
std::string s = "";
|
|
||||||
uint64_t num;
|
|
||||||
|
|
||||||
if (inum < 0) {
|
|
||||||
num = std::reinterpret_cast<uint64_t>(~inum) + 1;
|
|
||||||
s.insert(0,1, '-');
|
|
||||||
} else {
|
|
||||||
num = std::reinterpet_cast<uint64_t>(num);
|
|
||||||
}
|
|
||||||
|
|
||||||
s += std::to_string(num >> CONSTS_FRAC_WID);
|
|
||||||
|
|
||||||
int64_t frac = num & CONSTS_FRAC_MASK;
|
|
||||||
if (frac == 0 || decdigs == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
s += ".";
|
|
||||||
|
|
||||||
/* Applying the algorithm in fractional_base_conv() backwards. */
|
|
||||||
while (decdigs > 0 && frac != 0) {
|
|
||||||
num *= 2;
|
|
||||||
s += std::to_string(num >> CONSTS_FRAC_WID);
|
|
||||||
num = num & CONSTS_FRAC_WID;
|
|
||||||
}
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int64_t I_const, dt_const, P_const, setpt;
|
|
||||||
static unsigned long seed, ;
|
|
||||||
|
|
||||||
static void usage(char *argv0, int code) {
|
|
||||||
std::cout << argv0 << " -d deviation -m mean -I I -t dt -d delay -s seed -S setpt -P p [+verilator...]" << std::endl;
|
|
||||||
exit(code);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void parse_args(int argc, char *argv[]) {
|
|
||||||
const char *optstring = "I:t:s:P:d:m:h";
|
|
||||||
int opt;
|
|
||||||
Verilated::commandArgs(argc, argv);
|
Verilated::commandArgs(argc, argv);
|
||||||
|
Verilated::traceEverOn(true);
|
||||||
while ((opt = getopt(argc, argv, optstring)) != -1) {
|
mod = new ModType;
|
||||||
switch (opt) {
|
|
||||||
case 'm':
|
|
||||||
noise_mean = strtod(optstring, NULL);
|
|
||||||
break;
|
|
||||||
case 'd':
|
|
||||||
dev_mean = strtod(optstring, NULL);
|
|
||||||
break;
|
|
||||||
case 'I':
|
|
||||||
I_const = signed_to_fxp(optarg);
|
|
||||||
break;
|
|
||||||
case 't':
|
|
||||||
dt_const = signed_to_fxp(optarg);
|
|
||||||
break;
|
|
||||||
case 'S':
|
|
||||||
setpt = signed_to_fxp(optarg);
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
seed = strtoul(optarg, NULL, 10);
|
|
||||||
break;
|
|
||||||
case 'P':
|
|
||||||
P_const = strtoul(optarg, NULL, 10);
|
|
||||||
break;
|
|
||||||
case 'd':
|
|
||||||
dely = strtoul(optarg, NULL, 10);
|
|
||||||
break;
|
|
||||||
case 'h':
|
|
||||||
usage(argv[0], 0);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
usage(argv[1], 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Vtop *mod;
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
|
||||||
parse_args(argc, argv);
|
|
||||||
mod = new Vtop;
|
|
||||||
|
|
||||||
mod->clk = 0;
|
mod->clk = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void set_value(V val, unsigned name) {
|
||||||
|
mod->cmd = CONTROL_LOOP_WRITE_BIT | name;
|
||||||
|
mod->word_into_loop = val;
|
||||||
|
mod->start_cmd = 1;
|
||||||
|
|
||||||
|
do { run_clock(); } while (!mod->finish_cmd);
|
||||||
|
mod->start_cmd = 0;
|
||||||
|
run_clock();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
init(argc, argv);
|
||||||
|
mod = new ModType;
|
||||||
|
Transfer func = Transfer{150, 0, 2, 1.1, 10, -1};
|
||||||
|
|
||||||
|
mod->clk = 0;
|
||||||
|
|
||||||
|
set_value(10000, CONTROL_LOOP_STATUS);
|
||||||
|
set_value(0b11010111000010100011110101110000101000111, CONTROL_LOOP_P);
|
||||||
|
set_value((V)12 << CONSTS_FRAC, CONTROL_LOOP_I);
|
||||||
|
set_value(20, CONTROL_LOOP_DELAY);
|
||||||
|
set_value(1, CONTROL_LOOP_STATUS);
|
||||||
|
|
||||||
|
for (int tick = 0; tick < 10000; tick++) {
|
||||||
|
std::cout << tick << std::endl;
|
||||||
|
run_clock();
|
||||||
|
if (mod->request && !mod->fulfilled) {
|
||||||
|
mod->measured_value = func.val(mod->curset);
|
||||||
|
mod->fulfilled = 1;
|
||||||
|
} else if (mod->fulfilled && !mod->request) {
|
||||||
|
mod->fulfilled = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tick == 5000) {
|
||||||
|
mod->cmd = CONTROL_LOOP_WRITE_BIT | CONTROL_LOOP_P;
|
||||||
|
mod->word_into_loop = 0b010111000010100011110101110000101000111;
|
||||||
|
mod->start_cmd = 1;
|
||||||
|
}
|
||||||
|
if (mod->finish_cmd) {
|
||||||
|
mod->start_cmd = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod->final();
|
||||||
|
delete mod;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -1,117 +1,131 @@
|
||||||
`include control_loop_cmds.vh
|
`include "control_loop_cmds.vh"
|
||||||
|
|
||||||
module top
|
module control_loop_sim_top #(
|
||||||
#(
|
|
||||||
parameter ADC_WID = 18,
|
parameter ADC_WID = 18,
|
||||||
parameter ADC_WID_LEN = 5,
|
parameter ADC_WID_SIZ = 5,
|
||||||
parameter ADC_POLARITY = 1,
|
parameter ADC_POLARITY = 1,
|
||||||
parameter ADC_PHASE = 0,
|
parameter ADC_PHASE = 0,
|
||||||
parameter ADC_CYCLE_HALF_WAIT = 5,
|
|
||||||
parameter ADC_TIMER_LEN = 3,
|
|
||||||
|
|
||||||
parameter DAC_POLARITY = 0,
|
parameter DAC_POLARITY = 0,
|
||||||
parameter DAC_PHASE = 1,
|
parameter DAC_PHASE = 1,
|
||||||
parameter DAC_DATA_WID = 20,
|
parameter DAC_DATA_WID = 20,
|
||||||
parameter DAC_WID = 24,
|
parameter DAC_WID = 24,
|
||||||
parameter DAC_WID_LEN = 5,
|
parameter DAC_WID_SIZ = 5,
|
||||||
parameter DAC_CYCLE_HALF_WAIT = 10,
|
|
||||||
parameter DAC_TIMER_LEN = 4,
|
|
||||||
|
|
||||||
parameter CONSTS_WID = 48,
|
parameter CONSTS_WHOLE = 21,
|
||||||
|
parameter CONSTS_FRAC = 43,
|
||||||
|
`define CONSTS_WID (CONSTS_WHOLE + CONSTS_FRAC)
|
||||||
|
parameter CONSTS_SIZ = 7,
|
||||||
parameter DELAY_WID = 16
|
parameter DELAY_WID = 16
|
||||||
)(
|
)(
|
||||||
input clk,
|
input clk,
|
||||||
|
|
||||||
input signed [ADC_WID-1:0] measured_data,
|
output [DAC_DATA_WID-1:0] curset,
|
||||||
input [DAC_DATA_WID-1:0] dac_in,
|
output dac_err,
|
||||||
output [DAC_DATA_WID-1:0] dac_out,
|
|
||||||
output dac_input_ready,
|
|
||||||
|
|
||||||
input [CONSTS_WID-1:0] word_into_loop,
|
input [ADC_WID-1:0] measured_value,
|
||||||
output [CONSTS_WID-1:0] word_outof_loop,
|
output request,
|
||||||
|
input fulfilled,
|
||||||
|
output adc_err,
|
||||||
|
|
||||||
|
input [`CONSTS_WID-1:0] word_into_loop,
|
||||||
|
output [`CONSTS_WID-1:0] word_outof_loop,
|
||||||
input start_cmd,
|
input start_cmd,
|
||||||
output finish_cmd,
|
output finish_cmd,
|
||||||
input [CONTROL_LOOP_CMD_WIDTH-1:0] cmd
|
input [`CONTROL_LOOP_CMD_WIDTH-1:0] cmd
|
||||||
);
|
);
|
||||||
|
|
||||||
wire dac_miso;
|
|
||||||
wire dac_mosi;
|
|
||||||
wire dac_sck;
|
|
||||||
wire ss_L;
|
|
||||||
|
|
||||||
spi_master #(
|
|
||||||
.WID(DAC_WID),
|
|
||||||
.WID_LEN(DAC_WID_LEN),
|
|
||||||
.POLARITY(DAC_POLARITY),
|
|
||||||
.PHASE(DAC_PHASE),
|
|
||||||
.CYCLE_HALF_WAIT(DAC_CYCLE_HALF_WAIT),
|
|
||||||
.TIMER_LEN(DAC_TIMER_LEN)
|
|
||||||
) dac_master (
|
|
||||||
.clk(clk),
|
|
||||||
.from_slave(dac_set_data),
|
|
||||||
.miso(dac_miso),
|
|
||||||
.to_slave(
|
|
||||||
.mosi(dac_mosi),
|
|
||||||
|
|
||||||
wire adc_sck;
|
|
||||||
wire adc_ss;
|
|
||||||
wire adc_miso;
|
|
||||||
reg adc_finished = 0;
|
|
||||||
|
|
||||||
wire dac_mosi;
|
|
||||||
wire dac_sck;
|
|
||||||
wire dac_ss;
|
|
||||||
reg dac_finished = 0;
|
|
||||||
|
|
||||||
/* Emulate a control loop environment with simulator controlled
|
/* Emulate a control loop environment with simulator controlled
|
||||||
SPI interfaces.
|
SPI interfaces.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
wire adc_miso;
|
||||||
|
wire adc_sck;
|
||||||
|
wire adc_ss_L;
|
||||||
|
|
||||||
/* ADC */
|
/* ADC */
|
||||||
spi_slave_no_write #(
|
|
||||||
|
adc_sim #(
|
||||||
.WID(ADC_WID),
|
.WID(ADC_WID),
|
||||||
.WID_LEN(5),
|
.WID_LEN(5),
|
||||||
.ADC_POLARITY(ADC_POLARITY),
|
.POLARITY(ADC_POLARITY),
|
||||||
.ADC_PHASE(ADC_PHASE)
|
.PHASE(ADC_PHASE)
|
||||||
)(
|
) adc (
|
||||||
.clk(clk),
|
.clk(clk),
|
||||||
.to_master(measured_data),
|
.indat(measured_value),
|
||||||
.sck(adc_sck),
|
.request(request),
|
||||||
.ss_L(!adc_ss),
|
.fulfilled(fulfilled),
|
||||||
|
.err(adc_err),
|
||||||
|
|
||||||
.miso(adc_miso),
|
.miso(adc_miso),
|
||||||
.rdy(!dac_ss),
|
.sck(adc_sck),
|
||||||
.finished(adc_finished)
|
.ss_L(adc_ss_L)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
wire dac_miso;
|
||||||
|
wire dac_mosi;
|
||||||
|
wire dac_ss_L;
|
||||||
|
wire dac_sck;
|
||||||
|
|
||||||
/* DAC */
|
/* DAC */
|
||||||
spi_slave_no_read #(
|
dac_sim #(
|
||||||
.WID(DAC_WID),
|
.WID(DAC_WID),
|
||||||
|
.DATA_WID(DAC_DATA_WID),
|
||||||
.WID_LEN(5),
|
.WID_LEN(5),
|
||||||
.DAC_POLARITY(DAC_POLARITY),
|
.POLARITY(DAC_POLARITY),
|
||||||
.DAC_PHASE(DAC_PHASE)
|
.PHASE(DAC_PHASE)
|
||||||
)(
|
) dac (
|
||||||
.clk(clk),
|
.clk(clk),
|
||||||
.from_master(output_data),
|
.curset(curset),
|
||||||
.mosi(dac_mosi),
|
.mosi(dac_mosi),
|
||||||
|
.miso(dac_miso),
|
||||||
.sck(dac_sck),
|
.sck(dac_sck),
|
||||||
.ss_L(!dac_ss),
|
.ss_L(dac_ss_L),
|
||||||
.rdy(!dac_ss),
|
.err(dac_err)
|
||||||
.finished(dac_finished)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
control_loop #(
|
control_loop #(
|
||||||
.ADC_WID(ADC_WID),
|
.ADC_WID(ADC_WID),
|
||||||
.DAC_WID(DAC_WID),
|
.ADC_WID_SIZ(ADC_WID_SIZ),
|
||||||
.DAC_DATA_WID(DAC_DATA_WID),
|
|
||||||
.CONSTS_WID(CONSTS_WID),
|
|
||||||
.DELAY_WID(DELAY_WID),
|
|
||||||
.ADC_POLARITY(ADC_POLARITY),
|
.ADC_POLARITY(ADC_POLARITY),
|
||||||
.ADC_PHASE(ADC_PHASE),
|
.ADC_PHASE(ADC_PHASE),
|
||||||
|
/* Keeping cycle half wait and conv wait the same
|
||||||
|
* since it doesn't matter for this simulation */
|
||||||
|
|
||||||
|
.CONSTS_WHOLE(CONSTS_WHOLE),
|
||||||
|
.CONSTS_FRAC(CONSTS_FRAC),
|
||||||
|
.CONSTS_SIZ(CONSTS_SIZ),
|
||||||
|
.DELAY_WID(DELAY_WID),
|
||||||
|
|
||||||
|
.DAC_WID(DAC_WID),
|
||||||
|
.DAC_WID_SIZ(DAC_WID_SIZ),
|
||||||
|
.DAC_DATA_WID(DAC_DATA_WID),
|
||||||
.DAC_POLARITY(DAC_POLARITY),
|
.DAC_POLARITY(DAC_POLARITY),
|
||||||
.DAC_PHASE(DAC_PHASE)
|
.DAC_PHASE(DAC_PHASE)
|
||||||
) cloop (
|
) cloop (
|
||||||
.clk(clk),
|
.clk(clk),
|
||||||
|
.dac_mosi(dac_mosi),
|
||||||
|
.dac_miso(dac_miso),
|
||||||
|
.dac_ss_L(dac_ss_L),
|
||||||
|
.dac_sck(dac_sck),
|
||||||
|
|
||||||
|
.adc_miso(adc_miso),
|
||||||
|
.adc_conv_L(adc_ss_L),
|
||||||
|
.adc_sck(adc_sck),
|
||||||
|
|
||||||
|
.word_in(word_into_loop),
|
||||||
|
.word_out(word_outof_loop),
|
||||||
|
.start_cmd(start_cmd),
|
||||||
|
.finish_cmd(finish_cmd),
|
||||||
|
.cmd(cmd)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
`ifdef VERILATOR
|
||||||
|
initial begin
|
||||||
|
$dumpfile("control_loop.fst");
|
||||||
|
$dumpvars;
|
||||||
|
end
|
||||||
|
`endif
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
`undefineall
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
module dac_sim #(
|
||||||
|
parameter POLARITY = 0,
|
||||||
|
parameter PHASE = 1,
|
||||||
|
parameter WID = 24,
|
||||||
|
parameter DATA_WID = 20,
|
||||||
|
parameter WID_LEN = 5
|
||||||
|
) (
|
||||||
|
input clk,
|
||||||
|
|
||||||
|
output reg [DATA_WID-1:0] curset,
|
||||||
|
|
||||||
|
input mosi,
|
||||||
|
output miso,
|
||||||
|
input sck,
|
||||||
|
input ss_L,
|
||||||
|
output err
|
||||||
|
);
|
||||||
|
|
||||||
|
wire [WID-1:0] from_master;
|
||||||
|
reg [WID-1:0] to_master = 0;
|
||||||
|
reg rdy = 1;
|
||||||
|
wire spi_fin;
|
||||||
|
reg [WID-4-1:0] ctrl_register = 0;
|
||||||
|
|
||||||
|
always @ (posedge clk) begin
|
||||||
|
if (spi_fin) begin
|
||||||
|
rdy <= 0;
|
||||||
|
/* read current value. TODO: lower bit DACs have zero
|
||||||
|
* padding between register and DAC value. */
|
||||||
|
case (from_master[WID-1:WID-4])
|
||||||
|
4'b1001: begin
|
||||||
|
to_master <= {4'b1001, curset};
|
||||||
|
end
|
||||||
|
4'b0001: begin
|
||||||
|
curset <= from_master [DATA_WID-1:0];
|
||||||
|
to_master <= 0;
|
||||||
|
end
|
||||||
|
4'b0010: begin
|
||||||
|
ctrl_register <= to_master[WID-1-4:0];
|
||||||
|
to_master <= 0;
|
||||||
|
end
|
||||||
|
4'b1010: begin
|
||||||
|
to_master <= {4'b1010, ctrl_register};
|
||||||
|
end
|
||||||
|
default: ;
|
||||||
|
endcase
|
||||||
|
end else if (!rdy) begin
|
||||||
|
rdy <= 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
spi_slave #(
|
||||||
|
.WID(WID),
|
||||||
|
.WID_LEN(WID_LEN),
|
||||||
|
.POLARITY(POLARITY),
|
||||||
|
.PHASE(PHASE)
|
||||||
|
) spi (
|
||||||
|
.clk(clk),
|
||||||
|
.sck(sck),
|
||||||
|
.ss_L(ss_L),
|
||||||
|
.miso(miso),
|
||||||
|
.mosi(mosi),
|
||||||
|
.from_master(from_master),
|
||||||
|
.to_master(to_master),
|
||||||
|
.finished(spi_fin),
|
||||||
|
.rdy(rdy),
|
||||||
|
.err(err)
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
`undefineall
|
|
@ -106,3 +106,4 @@ always @ (posedge clk) begin
|
||||||
end
|
end
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
`undefineall
|
||||||
|
|
|
@ -146,3 +146,4 @@ always @ (posedge clk) begin
|
||||||
end
|
end
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
`undefineall
|
||||||
|
|
Loading…
Reference in New Issue