change control_loop to m4 scripts, add common makefile

This commit is contained in:
Peter McGoron 2023-03-15 18:30:08 +00:00
parent 7af907ffb4
commit 953e42b80c
11 changed files with 145 additions and 132 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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}' > $@

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)))

View File

@ -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))

View File

@ -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

View File

@ -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),