change control_loop to m4 scripts, add common makefile
This commit is contained in:
parent
7af907ffb4
commit
953e42b80c
|
@ -9,12 +9,8 @@ See also [Dan Gisselquist][1]'s rules for FPGA development.
|
|||
* Stick to Verilog 2005. F4PGA will accept SystemVerilog but yosys sometimes
|
||||
synthesizes it incorrectly.
|
||||
* Do not use parameters that are calculated from other parameters (yosys
|
||||
will not parse them correctly). Use macros instead.
|
||||
* Only use Verlog macros for basic expression replacement (replacing calculated
|
||||
parameters). For more advanced code generation, use m4 (see `base.m4` as an
|
||||
example).
|
||||
* Add `undefineall` at the end of *every single module*. If you do not,
|
||||
you will get many confusing errors.
|
||||
will not parse them correctly). Use m4 macros instead.
|
||||
* Do not use Verilog macros. Use m4.
|
||||
* Do all code and test generation in Makefiles.
|
||||
* Simulate *every* module, even the trivial ones using Verilator.
|
||||
Simulation must be simulatable with open-source software (Verilator is
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
.PHONY: lint
|
||||
base.v: base.m4
|
||||
m4 -P --synclines base.m4 | awk -v filename=base.m4 '/^#line/ {printf("`line %s %d 0\n", filename, $$2); next} {print}' > base.v
|
||||
include ../common.makefile
|
||||
base.v: base.v.m4
|
||||
lint: base.v
|
||||
verilator --lint-only base.v -I../spi -I../control_loop -I../waveform
|
||||
|
|
|
@ -135,7 +135,7 @@ m4_define(m4_adc_switch, ⟨
|
|||
`include "control_loop_cmds.vh"
|
||||
module base #(
|
||||
parameter DAC_PORTS = 2,
|
||||
`define DAC_PORTS_CONTROL_LOOP (DAC_PORTS + 1)
|
||||
m4_define(DAC_PORTS_CONTROL_LOOP, (DAC_PORTS + 1))
|
||||
|
||||
parameter DAC_NUM = 8,
|
||||
parameter DAC_WID = 24,
|
||||
|
@ -156,7 +156,7 @@ module base #(
|
|||
parameter WF_RAM_WORD_INCR = 2,
|
||||
|
||||
parameter ADC_PORTS = 1,
|
||||
`define ADC_PORTS_CONTROL_LOOP (ADC_PORTS + 1)
|
||||
m4_define(ADC_PORTS_CONTROL_LOOP, (ADC_PORTS + 1))
|
||||
parameter ADC_NUM = 8,
|
||||
/* Three types of ADC. For now assume that their electronics
|
||||
* are similar enough, just need different numbers for the width.
|
||||
|
@ -179,8 +179,8 @@ module base #(
|
|||
parameter CL_CONSTS_FRAC = 43,
|
||||
parameter CL_CONSTS_SIZ = 7,
|
||||
parameter CL_DELAY_WID = 16,
|
||||
`define CL_CONSTS_WID (CL_CONSTS_WHOLE + CL_CONSTS_FRAC)
|
||||
`define CL_DATA_WID `CL_CONSTS_WID
|
||||
m4_define(CL_CONSTS_WID, (CL_CONSTS_WHOLE + CL_CONSTS_FRAC))
|
||||
m4_define(CL_DATA_WID, CL_CONSTS_WID)
|
||||
parameter CL_READ_DAC_DELAY = 5,
|
||||
parameter CL_CYCLE_COUNT_WID = 18
|
||||
) (
|
||||
|
@ -195,7 +195,7 @@ module base #(
|
|||
input [ADC_NUM-1:0] adc_sdo,
|
||||
output [ADC_NUM-1:0] adc_sck,
|
||||
|
||||
m4_dac_wires(`DAC_PORTS_CONTROL_LOOP, 0),
|
||||
m4_dac_wires(DAC_PORTS_CONTROL_LOOP, 0),
|
||||
m4_dac_wires(DAC_PORTS, 1),
|
||||
m4_dac_wires(DAC_PORTS, 2),
|
||||
m4_dac_wires(DAC_PORTS, 3),
|
||||
|
@ -204,7 +204,7 @@ module base #(
|
|||
m4_dac_wires(DAC_PORTS, 6),
|
||||
m4_dac_wires(DAC_PORTS, 7),
|
||||
|
||||
input [`ADC_PORTS_CONTROL_LOOP-1:0] adc_sel_0,
|
||||
input [ADC_PORTS_CONTROL_LOOP-1:0] adc_sel_0,
|
||||
|
||||
m4_adc_wires(ADC_TYPE1_WID, 0),
|
||||
m4_adc_wires(ADC_TYPE1_WID, 1),
|
||||
|
@ -217,8 +217,8 @@ module base #(
|
|||
|
||||
output cl_in_loop,
|
||||
input [`CONTROL_LOOP_CMD_WIDTH-1:0] cl_cmd,
|
||||
input [`CL_DATA_WID-1:0] cl_word_in,
|
||||
output reg [`CL_DATA_WID-1:0] cl_word_out,
|
||||
input [CL_DATA_WID-1:0] cl_word_in,
|
||||
output reg [CL_DATA_WID-1:0] cl_word_out,
|
||||
input cl_start_cmd,
|
||||
output reg cl_finish_cmd
|
||||
);
|
||||
|
@ -226,7 +226,7 @@ module base #(
|
|||
wire [ADC_NUM-1:0] adc_conv_L;
|
||||
assign adc_conv = ~adc_conv_L;
|
||||
|
||||
m4_dac_switch(`DAC_PORTS_CONTROL_LOOP, 0);
|
||||
m4_dac_switch(DAC_PORTS_CONTROL_LOOP, 0);
|
||||
m4_dac_switch(DAC_PORTS, 1);
|
||||
m4_dac_switch(DAC_PORTS, 2);
|
||||
m4_dac_switch(DAC_PORTS, 3);
|
||||
|
@ -237,14 +237,14 @@ m4_dac_switch(DAC_PORTS, 7);
|
|||
|
||||
/* 1st adc is Type 1 (18 bit) */
|
||||
|
||||
wire [`ADC_PORTS_CONTROL_LOOP-1:0] adc_conv_L_port_0;
|
||||
wire [`ADC_PORTS_CONTROL_LOOP-1:0] adc_sdo_port_0;
|
||||
wire [`ADC_PORTS_CONTROL_LOOP-1:0] adc_sck_port_0;
|
||||
wire [`ADC_PORTS_CONTROL_LOOP-1:0] adc_mosi_port_0_unassigned;
|
||||
wire [ADC_PORTS_CONTROL_LOOP-1:0] adc_conv_L_port_0;
|
||||
wire [ADC_PORTS_CONTROL_LOOP-1:0] adc_sdo_port_0;
|
||||
wire [ADC_PORTS_CONTROL_LOOP-1:0] adc_sck_port_0;
|
||||
wire [ADC_PORTS_CONTROL_LOOP-1:0] adc_mosi_port_0_unassigned;
|
||||
wire adc_mosi_unassigned;
|
||||
|
||||
spi_switch #(
|
||||
.PORTS(`ADC_PORTS_CONTROL_LOOP)
|
||||
.PORTS(ADC_PORTS_CONTROL_LOOP)
|
||||
) switch_adc_0 (
|
||||
.select(adc_sel_0),
|
||||
.mosi(adc_mosi_unassigned),
|
||||
|
@ -327,4 +327,3 @@ m4_adc_switch(ADC_TYPE1_WID, 6);
|
|||
m4_adc_switch(ADC_TYPE1_WID, 7);
|
||||
|
||||
endmodule
|
||||
`undefineall
|
|
@ -0,0 +1,3 @@
|
|||
# Generate verilog from m4 file
|
||||
%.v: %.v.m4
|
||||
m4 -P --synclines $< | awk -v filename=$< '/^#line/ {printf("`line %d %s 0\n", $$2, filename); next} {print}' > $@
|
|
@ -1,11 +1,14 @@
|
|||
# Makefile for tests and hardware verification.
|
||||
|
||||
.PHONY: test clean
|
||||
.PHONY: test clean codegen all
|
||||
|
||||
all: test codegen
|
||||
|
||||
####### Tests ########
|
||||
|
||||
COMMON_CPP = control_loop_math_implementation.cpp
|
||||
COMMON= ${COMMON_CPP} control_loop_math_implementation.h
|
||||
control_loop_math_verilog = control_loop_math.v boothmul.v intsat.v sign_extend.v
|
||||
|
||||
CONSTS_FRAC=43
|
||||
E_WID=21
|
||||
|
@ -16,7 +19,7 @@ clean:
|
|||
rm -rf obj_dir *.fst
|
||||
|
||||
obj_dir/Vcontrol_loop_math.mk: control_loop_math_sim.cpp ${COMMON} \
|
||||
control_loop_math.v
|
||||
${control_loop_math_verilog}
|
||||
verilator --cc --exe -Wall --trace --trace-fst \
|
||||
--top-module control_loop_math \
|
||||
-GCONSTS_FRAC=${CONSTS_FRAC} -DDEBUG_CONTROL_LOOP_MATH \
|
||||
|
@ -31,7 +34,9 @@ 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
|
||||
control_loop_sim_top.v control_loop_sim_top.v \
|
||||
control_loop_cmds.vh control_loop.v \
|
||||
${control_loop_math_verilog}
|
||||
verilator --cc --exe -Wall --trace --trace-fst \
|
||||
--top-module control_loop_sim_top \
|
||||
-GCONSTS_FRAC=${CONSTS_FRAC} \
|
||||
|
@ -45,6 +50,10 @@ obj_dir/Vcontrol_loop_sim_top: obj_dir/Vcontrol_loop_sim_top.mk control_loop_cmd
|
|||
|
||||
####### Codegen ########
|
||||
|
||||
control_loop_cmds.h: control_loop_cmds.vh
|
||||
include ../common.makefile
|
||||
codegen: control_loop_cmds.h boothmul.v control_loop_math.v control_loop.v control_loop_cmds.vh
|
||||
control_loop_cmds.vh: control_loop_cmds.m4
|
||||
m4 -P control_loop_cmds.vh.m4 > control_loop_cmds.vh
|
||||
control_loop_cmds.h: control_loop_cmds.m4
|
||||
echo '#pragma once' > control_loop_cmds.h
|
||||
sed 's/`define/#define/g; s/`//g' control_loop_cmds.vh >> control_loop_cmds.h
|
||||
m4 -P control_loop_cmds.h.m4 >> control_loop_cmds.h
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
m4_changequote(`⟨', `⟩')
|
||||
m4_changecom(⟨/*⟩, ⟨*/⟩)
|
||||
/* Booth Multiplication v1.0
|
||||
* Written by Peter McGoron, 2022.
|
||||
*
|
||||
|
@ -28,11 +30,12 @@ module boothmul
|
|||
input arm,
|
||||
input [A1_LEN-1:0] a1,
|
||||
input [A2_LEN-1:0] a2,
|
||||
output [A1_LEN+A2_LEN-1:0] outn,
|
||||
m4_define(M4_OUT_LEN, (A1_LEN + A2_LEN))
|
||||
output [M4_OUT_LEN-1:0] outn,
|
||||
`ifdef DEBUG
|
||||
output [A1_LEN+A2_LEN+1:0] debug_a,
|
||||
output [A1_LEN+A2_LEN+1:0] debug_s,
|
||||
output [A1_LEN+A2_LEN+1:0] debug_p,
|
||||
output [M4_OUT_LEN+1:0] debug_a,
|
||||
output [M4_OUT_LEN+1:0] debug_s,
|
||||
output [M4_OUT_LEN+1:0] debug_p,
|
||||
output [A2LEN_SIZ-1:0] debug_state,
|
||||
`endif
|
||||
output reg fin
|
||||
|
@ -42,8 +45,7 @@ module boothmul
|
|||
* Booth Parameters
|
||||
**********************/
|
||||
|
||||
`define OUT_LEN (A1_LEN + A2_LEN)
|
||||
`define REG_LEN (`OUT_LEN + 2)
|
||||
m4_define(M4_REG_LEN, (M4_OUT_LEN + 2))
|
||||
|
||||
/* The Booth multiplication algorithm is a sequential algorithm for
|
||||
* twos-compliment integers.
|
||||
|
@ -71,24 +73,24 @@ module boothmul
|
|||
|
||||
reg [A1_LEN-1:0] a1_reg;
|
||||
|
||||
wire [`REG_LEN-1:0] a;
|
||||
wire [M4_REG_LEN-1:0] a;
|
||||
assign a[A2_LEN:0] = 0;
|
||||
assign a[`REG_LEN-2:A2_LEN+1] = a1_reg;
|
||||
assign a[`REG_LEN-1] = a1_reg[A1_LEN-1];
|
||||
wire signed [`REG_LEN-1:0] a_signed;
|
||||
assign a[M4_REG_LEN-2:A2_LEN+1] = a1_reg;
|
||||
assign a[M4_REG_LEN-1] = a1_reg[A1_LEN-1];
|
||||
wire signed [M4_REG_LEN-1:0] a_signed;
|
||||
assign a_signed = a;
|
||||
|
||||
wire [`REG_LEN-1:0] s;
|
||||
wire [M4_REG_LEN-1:0] s;
|
||||
assign s[A2_LEN:0] = 0;
|
||||
assign s[`REG_LEN-1:A2_LEN+1] = ~{a1_reg[A1_LEN-1],a1_reg} + 1;
|
||||
wire signed [`REG_LEN-1:0] s_signed;
|
||||
assign s[M4_REG_LEN-1:A2_LEN+1] = ~{a1_reg[A1_LEN-1],a1_reg} + 1;
|
||||
wire signed [M4_REG_LEN-1:0] s_signed;
|
||||
assign s_signed = s;
|
||||
|
||||
reg [`REG_LEN-1:0] p;
|
||||
wire signed [`REG_LEN-1:0] p_signed;
|
||||
reg [M4_REG_LEN-1:0] p;
|
||||
wire signed [M4_REG_LEN-1:0] p_signed;
|
||||
assign p_signed = p;
|
||||
|
||||
assign outn = p[`REG_LEN-2:1];
|
||||
assign outn = p[M4_REG_LEN-2:1];
|
||||
|
||||
/**********************
|
||||
* Loop Implementation
|
||||
|
@ -110,7 +112,7 @@ always @ (posedge clk) begin
|
|||
end else if (loop_accul == 0) begin
|
||||
p[0] <= 0;
|
||||
p[A2_LEN:1] <= a2;
|
||||
p[`REG_LEN-1:A2_LEN+1] <= 0;
|
||||
p[M4_REG_LEN-1:A2_LEN+1] <= 0;
|
||||
|
||||
a1_reg <= a1;
|
||||
|
||||
|
@ -142,4 +144,3 @@ end
|
|||
`endif
|
||||
|
||||
endmodule
|
||||
`undefineall
|
|
@ -1,4 +1,7 @@
|
|||
`include "control_loop_cmds.vh"
|
||||
m4_changequote(`⟨', `⟩')
|
||||
m4_changecom(⟨/*⟩, ⟨*/⟩)
|
||||
m4_define(generate_macro, ⟨m4_define(M4_$1, $2)⟩)
|
||||
m4_include(control_loop_cmds.m4)
|
||||
|
||||
module control_loop
|
||||
#(
|
||||
|
@ -17,9 +20,9 @@ module control_loop
|
|||
parameter CONSTS_WHOLE = 21,
|
||||
parameter CONSTS_FRAC = 43,
|
||||
parameter CONSTS_SIZ = 7,
|
||||
`define CONSTS_WID (CONSTS_WHOLE + CONSTS_FRAC)
|
||||
m4_define(M4_CONSTS_WID, (CONSTS_WHOLE + CONSTS_FRAC))
|
||||
parameter DELAY_WID = 16,
|
||||
`define DATA_WID `CONSTS_WID
|
||||
m4_define(M4_DATA_WID, M4_CONSTS_WID)
|
||||
parameter READ_DAC_DELAY = 5,
|
||||
parameter CYCLE_COUNT_WID = 18,
|
||||
parameter DAC_WID = 24,
|
||||
|
@ -29,7 +32,7 @@ module control_loop
|
|||
*/
|
||||
parameter DAC_WID_SIZ = 5,
|
||||
parameter DAC_DATA_WID = 20,
|
||||
`define E_WID (DAC_DATA_WID + 1)
|
||||
m4_define(M4_E_WID, (DAC_DATA_WID + 1))
|
||||
parameter DAC_POLARITY = 0,
|
||||
parameter DAC_PHASE = 1,
|
||||
parameter DAC_CYCLE_HALF_WAIT = 10,
|
||||
|
@ -50,9 +53,9 @@ module control_loop
|
|||
output adc_sck,
|
||||
|
||||
/* Hacky ad-hoc read-write interface. */
|
||||
input [`CONTROL_LOOP_CMD_WIDTH-1:0] cmd,
|
||||
input [`DATA_WID-1:0] word_in,
|
||||
output reg [`DATA_WID-1:0] word_out,
|
||||
input [M4_CONTROL_LOOP_CMD_WIDTH-1:0] cmd,
|
||||
input [M4_DATA_WID-1:0] word_in,
|
||||
output reg [M4_DATA_WID-1:0] word_out,
|
||||
input start_cmd,
|
||||
output reg finish_cmd
|
||||
);
|
||||
|
@ -125,12 +128,12 @@ reg signed [ADC_WID-1:0] setpt = 0;
|
|||
reg signed [ADC_WID-1:0] setpt_buffer = 0;
|
||||
|
||||
/* Integral parameter */
|
||||
reg signed [`CONSTS_WID-1:0] cl_I_reg = 0;
|
||||
reg signed [`CONSTS_WID-1:0] cl_I_reg_buffer = 0;
|
||||
reg signed [M4_CONSTS_WID-1:0] cl_I_reg = 0;
|
||||
reg signed [M4_CONSTS_WID-1:0] cl_I_reg_buffer = 0;
|
||||
|
||||
/* Proportional parameter */
|
||||
reg signed [`CONSTS_WID-1:0] cl_p_reg = 0;
|
||||
reg signed [`CONSTS_WID-1:0] cl_p_reg_buffer = 0;
|
||||
reg signed [M4_CONSTS_WID-1:0] cl_p_reg = 0;
|
||||
reg signed [M4_CONSTS_WID-1:0] cl_p_reg_buffer = 0;
|
||||
|
||||
/* Delay parameter (to make the loop run slower) */
|
||||
reg [DELAY_WID-1:0] dely = 0;
|
||||
|
@ -143,11 +146,11 @@ reg running = 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] counting_timer = 0;
|
||||
reg [`CONSTS_WID-1:0] adjval_prev = 0;
|
||||
reg [M4_CONSTS_WID-1:0] adjval_prev = 0;
|
||||
|
||||
reg signed [`E_WID-1:0] err_prev = 0;
|
||||
wire signed [`E_WID-1:0] e_cur;
|
||||
wire signed [`CONSTS_WID-1:0] adj_val;
|
||||
reg signed [M4_E_WID-1:0] err_prev = 0;
|
||||
wire signed [M4_E_WID-1:0] e_cur;
|
||||
wire signed [M4_CONSTS_WID-1:0] adj_val;
|
||||
wire signed [DAC_DATA_WID-1:0] new_dac_val;
|
||||
|
||||
reg arm_math = 0;
|
||||
|
@ -244,78 +247,78 @@ reg dirty_bit = 0;
|
|||
always @ (posedge clk) begin
|
||||
if (start_cmd && !finish_cmd) begin
|
||||
case (cmd)
|
||||
`CONTROL_LOOP_NOOP:
|
||||
M4_CONTROL_LOOP_NOOP:
|
||||
finish_cmd <= 1;
|
||||
`CONTROL_LOOP_NOOP | `CONTROL_LOOP_WRITE_BIT:
|
||||
M4_CONTROL_LOOP_NOOP | M4_CONTROL_LOOP_WRITE_BIT:
|
||||
finish_cmd <= 1;
|
||||
`CONTROL_LOOP_STATUS: begin
|
||||
word_out[`DATA_WID-1:1] <= 0;
|
||||
M4_CONTROL_LOOP_STATUS: begin
|
||||
word_out[M4_DATA_WID-1:1] <= 0;
|
||||
word_out[0] <= running;
|
||||
finish_cmd <= 1;
|
||||
end
|
||||
`CONTROL_LOOP_STATUS | `CONTROL_LOOP_WRITE_BIT:
|
||||
M4_CONTROL_LOOP_STATUS | M4_CONTROL_LOOP_WRITE_BIT:
|
||||
if (write_control) begin
|
||||
running <= word_in[0];
|
||||
finish_cmd <= 1;
|
||||
dirty_bit <= 1;
|
||||
end
|
||||
`CONTROL_LOOP_SETPT: begin
|
||||
word_out[`DATA_WID-1:ADC_WID] <= 0;
|
||||
M4_CONTROL_LOOP_SETPT: begin
|
||||
word_out[M4_DATA_WID-1:ADC_WID] <= 0;
|
||||
word_out[ADC_WID-1:0] <= setpt;
|
||||
finish_cmd <= 1;
|
||||
end
|
||||
`CONTROL_LOOP_SETPT | `CONTROL_LOOP_WRITE_BIT:
|
||||
M4_CONTROL_LOOP_SETPT | M4_CONTROL_LOOP_WRITE_BIT:
|
||||
if (write_control) begin
|
||||
setpt_buffer <= word_in[ADC_WID-1:0];
|
||||
finish_cmd <= 1;
|
||||
dirty_bit <= 1;
|
||||
end
|
||||
`CONTROL_LOOP_P: begin
|
||||
M4_CONTROL_LOOP_P: begin
|
||||
word_out <= cl_p_reg;
|
||||
finish_cmd <= 1;
|
||||
end
|
||||
`CONTROL_LOOP_P | `CONTROL_LOOP_WRITE_BIT: begin
|
||||
M4_CONTROL_LOOP_P | M4_CONTROL_LOOP_WRITE_BIT: begin
|
||||
if (write_control) begin
|
||||
cl_p_reg_buffer <= word_in;
|
||||
finish_cmd <= 1;
|
||||
dirty_bit <= 1;
|
||||
end
|
||||
end
|
||||
`CONTROL_LOOP_I: begin
|
||||
M4_CONTROL_LOOP_I: begin
|
||||
word_out <= cl_I_reg;
|
||||
finish_cmd <= 1;
|
||||
end
|
||||
`CONTROL_LOOP_I | `CONTROL_LOOP_WRITE_BIT: begin
|
||||
M4_CONTROL_LOOP_I | M4_CONTROL_LOOP_WRITE_BIT: begin
|
||||
if (write_control) begin
|
||||
cl_I_reg_buffer <= word_in;
|
||||
finish_cmd <= 1;
|
||||
dirty_bit <= 1;
|
||||
end
|
||||
end
|
||||
`CONTROL_LOOP_DELAY: begin
|
||||
word_out[`DATA_WID-1:DELAY_WID] <= 0;
|
||||
M4_CONTROL_LOOP_DELAY: begin
|
||||
word_out[M4_DATA_WID-1:DELAY_WID] <= 0;
|
||||
word_out[DELAY_WID-1:0] <= dely;
|
||||
finish_cmd <= 1;
|
||||
end
|
||||
`CONTROL_LOOP_DELAY | `CONTROL_LOOP_WRITE_BIT: begin
|
||||
M4_CONTROL_LOOP_DELAY | M4_CONTROL_LOOP_WRITE_BIT: begin
|
||||
if (write_control) begin
|
||||
dely_buffer <= word_in[DELAY_WID-1:0];
|
||||
finish_cmd <= 1;
|
||||
dirty_bit <= 1;
|
||||
end
|
||||
end
|
||||
`CONTROL_LOOP_ERR: begin
|
||||
word_out[`DATA_WID-1:`E_WID] <= 0;
|
||||
word_out[`E_WID-1:0] <= err_prev;
|
||||
M4_CONTROL_LOOP_ERR: begin
|
||||
word_out[M4_DATA_WID-1:M4_E_WID] <= 0;
|
||||
word_out[M4_E_WID-1:0] <= err_prev;
|
||||
finish_cmd <= 1;
|
||||
end
|
||||
`CONTROL_LOOP_Z: begin
|
||||
word_out[`DATA_WID-1:DAC_DATA_WID] <= 0;
|
||||
M4_CONTROL_LOOP_Z: begin
|
||||
word_out[M4_DATA_WID-1:DAC_DATA_WID] <= 0;
|
||||
word_out[DAC_DATA_WID-1:0] <= stored_dac_val;
|
||||
finish_cmd <= 1;
|
||||
end
|
||||
`CONTROL_LOOP_CYCLES: begin
|
||||
word_out[`DATA_WID-1:CYCLE_COUNT_WID] <= 0;
|
||||
M4_CONTROL_LOOP_CYCLES: begin
|
||||
word_out[M4_DATA_WID-1:CYCLE_COUNT_WID] <= 0;
|
||||
word_out[CYCLE_COUNT_WID-1:0] <= last_timer;
|
||||
finish_cmd <= 0;
|
||||
end
|
||||
|
@ -403,4 +406,3 @@ always @ (posedge clk) begin
|
|||
end
|
||||
|
||||
endmodule
|
||||
`undefineall
|
|
@ -0,0 +1,11 @@
|
|||
generate_macro(CONTROL_LOOP_NOOP, 0)
|
||||
generate_macro(CONTROL_LOOP_STATUS, 1)
|
||||
generate_macro(CONTROL_LOOP_SETPT, 2)
|
||||
generate_macro(CONTROL_LOOP_P, 3)
|
||||
generate_macro(CONTROL_LOOP_I, 4)
|
||||
generate_macro(CONTROL_LOOP_ERR, 5)
|
||||
generate_macro(CONTROL_LOOP_Z, 6)
|
||||
generate_macro(CONTROL_LOOP_CYCLES, 7)
|
||||
generate_macro(CONTROL_LOOP_DELAY, 8)
|
||||
generate_macro(CONTROL_LOOP_CMD_WIDTH, 8)
|
||||
generate_macro(CONTROL_LOOP_WRITE_BIT, (1 << (M4_CONTROL_LOOP_CMD_WIDTH-1)))
|
|
@ -1,11 +0,0 @@
|
|||
`define CONTROL_LOOP_NOOP 0
|
||||
`define CONTROL_LOOP_STATUS 1
|
||||
`define CONTROL_LOOP_SETPT 2
|
||||
`define CONTROL_LOOP_P 3
|
||||
`define CONTROL_LOOP_I 4
|
||||
`define CONTROL_LOOP_ERR 5
|
||||
`define CONTROL_LOOP_Z 6
|
||||
`define CONTROL_LOOP_CYCLES 7
|
||||
`define CONTROL_LOOP_DELAY 8
|
||||
`define CONTROL_LOOP_CMD_WIDTH 8
|
||||
`define CONTROL_LOOP_WRITE_BIT (1 << (`CONTROL_LOOP_CMD_WIDTH-1))
|
|
@ -1,3 +1,5 @@
|
|||
m4_changequote(`⟨', `⟩')
|
||||
m4_changecom(⟨/*⟩, ⟨*/⟩)
|
||||
/*************** Precision **************
|
||||
* The control loop is designed around these values, but generally
|
||||
* does not hardcode them.
|
||||
|
@ -25,18 +27,18 @@
|
|||
module control_loop_math #(
|
||||
parameter CONSTS_WHOLE = 21,
|
||||
parameter CONSTS_FRAC = 43,
|
||||
`define CONSTS_WID (CONSTS_WHOLE + CONSTS_FRAC)
|
||||
m4_define(M4_CONSTS_WID, (CONSTS_WHOLE + CONSTS_FRAC))
|
||||
parameter CONSTS_SIZ=7,
|
||||
|
||||
parameter ADC_WID = 18,
|
||||
parameter [`CONSTS_WID-1:0] SEC_PER_CYCLE = 'b10101011110011000,
|
||||
parameter [M4_CONSTS_WID-1:0] SEC_PER_CYCLE = 'b10101011110011000,
|
||||
/* The conversion between the ADC bit (20/2**18) and DAC bit (20.48/2**20)
|
||||
* is 0.256.
|
||||
*/
|
||||
parameter [`CONSTS_WID-1:0] ADC_TO_DAC = 64'b0100000110001001001101110100101111000110101,
|
||||
parameter [M4_CONSTS_WID-1:0] ADC_TO_DAC = 64'b0100000110001001001101110100101111000110101,
|
||||
parameter CYCLE_COUNT_WID = 18,
|
||||
parameter DAC_WID = 20
|
||||
`define E_WID (DAC_WID + 1)
|
||||
m4_define(M4_E_WID, (DAC_WID + 1))
|
||||
) (
|
||||
input clk,
|
||||
input arm,
|
||||
|
@ -44,23 +46,23 @@ module control_loop_math #(
|
|||
|
||||
input signed [ADC_WID-1:0] setpt,
|
||||
input signed [ADC_WID-1:0] measured,
|
||||
input signed [`CONSTS_WID-1:0] cl_P,
|
||||
input signed [`CONSTS_WID-1:0] cl_I,
|
||||
input signed [M4_CONSTS_WID-1:0] cl_P,
|
||||
input signed [M4_CONSTS_WID-1:0] cl_I,
|
||||
input signed [CYCLE_COUNT_WID-1:0] cycles,
|
||||
input signed [`E_WID-1:0] e_prev,
|
||||
input signed [`CONSTS_WID-1:0] adjval_prev,
|
||||
input signed [M4_E_WID-1:0] e_prev,
|
||||
input signed [M4_CONSTS_WID-1:0] adjval_prev,
|
||||
input signed [DAC_WID-1:0] stored_dac_val,
|
||||
|
||||
`ifdef DEBUG_CONTROL_LOOP_MATH
|
||||
output reg [`CONSTS_WID-1:0] dt_reg,
|
||||
output reg [`CONSTS_WID-1:0] idt_reg,
|
||||
output reg [`CONSTS_WID-1:0] epidt_reg,
|
||||
output reg [`CONSTS_WID-1:0] ep_reg,
|
||||
output reg [M4_CONSTS_WID-1:0] dt_reg,
|
||||
output reg [M4_CONSTS_WID-1:0] idt_reg,
|
||||
output reg [M4_CONSTS_WID-1:0] epidt_reg,
|
||||
output reg [M4_CONSTS_WID-1:0] ep_reg,
|
||||
`endif
|
||||
|
||||
output reg signed [`E_WID-1:0] e_cur,
|
||||
output reg signed [M4_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 [M4_CONSTS_WID-1:0] adj_val
|
||||
);
|
||||
|
||||
/*******
|
||||
|
@ -69,16 +71,16 @@ module control_loop_math #(
|
|||
* to be a 64 bit output, according to fixed-point rules.
|
||||
*/
|
||||
|
||||
reg signed [`CONSTS_WID-1:0] a1;
|
||||
reg signed [`CONSTS_WID-1:0] a2;
|
||||
reg signed [M4_CONSTS_WID-1:0] a1;
|
||||
reg signed [M4_CONSTS_WID-1:0] a2;
|
||||
/* verilator lint_off UNUSED */
|
||||
wire signed [`CONSTS_WID+`CONSTS_WID-1:0] out_untrunc;
|
||||
wire signed [M4_CONSTS_WID+M4_CONSTS_WID-1:0] out_untrunc;
|
||||
wire mul_fin;
|
||||
reg mul_arm = 0;
|
||||
|
||||
boothmul #(
|
||||
.A1_LEN(`CONSTS_WID),
|
||||
.A2_LEN(`CONSTS_WID),
|
||||
.A1_LEN(M4_CONSTS_WID),
|
||||
.A2_LEN(M4_CONSTS_WID),
|
||||
.A2LEN_SIZ(CONSTS_SIZ)
|
||||
) multiplier (
|
||||
.a1(a1),
|
||||
|
@ -95,11 +97,11 @@ boothmul #(
|
|||
* Q(2X).Y
|
||||
*/
|
||||
|
||||
`define OUT_RTRUNC_WID (`CONSTS_WID+`CONSTS_WID-CONSTS_FRAC)
|
||||
wire signed [`OUT_RTRUNC_WID-1:0] out_rtrunc
|
||||
= out_untrunc[`CONSTS_WID+`CONSTS_WID-1:CONSTS_FRAC];
|
||||
m4_define(M4_OUT_RTRUNC_WID, (M4_CONSTS_WID+M4_CONSTS_WID-CONSTS_FRAC))
|
||||
wire signed [M4_OUT_RTRUNC_WID-1:0] out_rtrunc
|
||||
= out_untrunc[M4_CONSTS_WID+M4_CONSTS_WID-1:CONSTS_FRAC];
|
||||
|
||||
wire signed [`CONSTS_WID-1:0] mul_out;
|
||||
wire signed [M4_CONSTS_WID-1:0] mul_out;
|
||||
|
||||
/***************************
|
||||
* Saturate higher X bits away.
|
||||
|
@ -107,7 +109,7 @@ wire signed [`CONSTS_WID-1:0] mul_out;
|
|||
*/
|
||||
|
||||
intsat #(
|
||||
.IN_LEN(`OUT_RTRUNC_WID),
|
||||
.IN_LEN(M4_OUT_RTRUNC_WID),
|
||||
.LTRUNC(CONSTS_WHOLE)
|
||||
) multiplier_saturate (
|
||||
.inp(out_rtrunc),
|
||||
|
@ -118,11 +120,11 @@ intsat #(
|
|||
* Safely get rid of high bit in addition.
|
||||
************************/
|
||||
|
||||
reg signed [`CONSTS_WID+1-1:0] add_sat;
|
||||
wire signed [`CONSTS_WID-1:0] saturated_add;
|
||||
reg signed [M4_CONSTS_WID+1-1:0] add_sat;
|
||||
wire signed [M4_CONSTS_WID-1:0] saturated_add;
|
||||
|
||||
intsat #(
|
||||
.IN_LEN(`CONSTS_WID + 1),
|
||||
.IN_LEN(M4_CONSTS_WID + 1),
|
||||
.LTRUNC(1)
|
||||
) addition_saturate (
|
||||
.inp(add_sat),
|
||||
|
@ -168,8 +170,8 @@ localparam CALCULATE_NEW_DAC_VALUE_PART_2 = 11;
|
|||
localparam WAIT_ON_DISARM = 8;
|
||||
|
||||
reg [4:0] state = WAIT_ON_ARM;
|
||||
reg signed [`CONSTS_WID+1-1:0] tmpstore = 0;
|
||||
wire signed [`CONSTS_WID-1:0] tmpstore_view = tmpstore[`CONSTS_WID-1:0];
|
||||
reg signed [M4_CONSTS_WID+1-1:0] tmpstore = 0;
|
||||
wire signed [M4_CONSTS_WID-1:0] tmpstore_view = tmpstore[M4_CONSTS_WID-1:0];
|
||||
|
||||
|
||||
always @ (posedge clk) begin
|
||||
|
@ -185,8 +187,8 @@ always @ (posedge clk) begin
|
|||
end
|
||||
CALCULATE_ERR: begin
|
||||
/* Sign-extend */
|
||||
a1[`CONSTS_WID-1:CONSTS_FRAC + ADC_WID + 1] <=
|
||||
{(`CONSTS_WID-(CONSTS_FRAC + ADC_WID + 1)){a1[ADC_WID+1-1+CONSTS_FRAC]}};
|
||||
a1[M4_CONSTS_WID-1:CONSTS_FRAC + ADC_WID + 1] <=
|
||||
{(M4_CONSTS_WID-(CONSTS_FRAC + ADC_WID + 1)){a1[ADC_WID+1-1+CONSTS_FRAC]}};
|
||||
a2 <= ADC_TO_DAC;
|
||||
mul_arm <= 1;
|
||||
state <= CALCULATE_DAC_E;
|
||||
|
@ -195,7 +197,7 @@ always @ (posedge clk) begin
|
|||
if (mul_fin) begin
|
||||
/* Discard other bits. This works without saturation because
|
||||
* CONSTS_WHOLE = E_WID. */
|
||||
e_cur <= mul_out[`CONSTS_WID-1:CONSTS_FRAC];
|
||||
e_cur <= mul_out[M4_CONSTS_WID-1:CONSTS_FRAC];
|
||||
|
||||
a1 <= SEC_PER_CYCLE;
|
||||
/* No sign extension, cycles is positive */
|
||||
|
@ -228,7 +230,7 @@ always @ (posedge clk) begin
|
|||
idt_reg <= mul_out;
|
||||
`endif
|
||||
|
||||
a2 <= {{(CONSTS_WHOLE-`E_WID){e_cur[`E_WID-1]}},e_cur, {(CONSTS_FRAC){1'b0}}};
|
||||
a2 <= {{(CONSTS_WHOLE-M4_E_WID){e_cur[M4_E_WID-1]}},e_cur, {(CONSTS_FRAC){1'b0}}};
|
||||
state <= CALCULATE_EPIDT;
|
||||
end
|
||||
CALCULATE_EPIDT:
|
||||
|
@ -237,14 +239,14 @@ always @ (posedge clk) begin
|
|||
mul_arm <= 1;
|
||||
end else if (mul_fin) begin
|
||||
mul_arm <= 0;
|
||||
tmpstore <= {mul_out[`CONSTS_WID-1],mul_out};
|
||||
tmpstore <= {mul_out[M4_CONSTS_WID-1],mul_out};
|
||||
|
||||
`ifdef DEBUG_CONTROL_LOOP_MATH
|
||||
epidt_reg <= mul_out;
|
||||
`endif
|
||||
|
||||
a1 <= cl_P;
|
||||
a2 <= {{(CONSTS_WHOLE-`E_WID){e_prev[`E_WID-1]}},e_prev, {(CONSTS_FRAC){1'b0}}};
|
||||
a2 <= {{(CONSTS_WHOLE-M4_E_WID){e_prev[M4_E_WID-1]}},e_prev, {(CONSTS_FRAC){1'b0}}};
|
||||
state <= CALCULATE_EP;
|
||||
end
|
||||
CALCULATE_EP:
|
||||
|
@ -268,7 +270,7 @@ always @ (posedge clk) begin
|
|||
state <= CALCULATE_NEW_DAC_VALUE_PART_1;
|
||||
end
|
||||
CALCULATE_NEW_DAC_VALUE_PART_1: begin
|
||||
adj_sat <= saturated_add[`CONSTS_WID-1:CONSTS_FRAC];
|
||||
adj_sat <= saturated_add[M4_CONSTS_WID-1:CONSTS_FRAC];
|
||||
adj_val <= saturated_add;
|
||||
state <= CALCULATE_NEW_DAC_VALUE_PART_2;
|
||||
end
|
||||
|
@ -296,4 +298,3 @@ end
|
|||
`endif
|
||||
|
||||
endmodule
|
||||
`undefineall
|
|
@ -19,6 +19,7 @@ module control_loop_sim_top #(
|
|||
parameter DELAY_WID = 16
|
||||
)(
|
||||
input clk,
|
||||
output in_loop,
|
||||
|
||||
output [DAC_DATA_WID-1:0] curset,
|
||||
output dac_err,
|
||||
|
@ -104,6 +105,7 @@ control_loop #(
|
|||
.DAC_PHASE(DAC_PHASE)
|
||||
) cloop (
|
||||
.clk(clk),
|
||||
.in_loop(in_loop),
|
||||
.dac_mosi(dac_mosi),
|
||||
.dac_miso(dac_miso),
|
||||
.dac_ss_L(dac_ss_L),
|
||||
|
|
Loading…
Reference in New Issue