// fdbk_loop.v
// Feedback computations for LLRF
// $Id$
// Larry Doolittle, LBNL
// llc-suite Copyright (c) 2004, The Regents of the University of
// California, through Lawrence Berkeley National Laboratory (subject
// to receipt of any required approvals from the U.S. Dept. of Energy).
// All rights reserved.
// Your use of this software is pursuant to a "BSD-style" open
// source license agreement, the text of which is in license.txt
// (md5sum a1e0e81c78f6eba050b0e96996f49fd5) that should accompany
// this file. If the license agreement is not there, or if you
// have questions about the license, please contact Berkeley Lab's
// Technology Transfer Department at TTD@lbl.gov referring to
// "llc-suite (LBNL Ref CR-1988)"
// similar in concept to the original VHDL written by Larry Doolittle
// and Justin Oo in summer 2002 - January 2003
`timescale 1ns / 1ns
module fdbk_loop
(
input [13:0] fdbk_input, // interconnect
input [15:0] set_wave, // interconnect
input [21:0] dkcm_bus, // interconnect
input host_clk, // interconnect
input feedback_enable, // interconnect
input integrate_enable, // interconnect
input [12:0] feedforward_data, // interconnect
input clk40, // interconnect
input dds_substitute, // interconnect
output [11:0] outsig40 // interconnect
);
reg [11:0] fdbk_err_out;
assign outsig40 = dds_substitute ? set_wave[15:4] : fdbk_err_out;
// synchronize
reg corrupted_multiplier;
always @(posedge clk40) corrupted_multiplier <= dkcm_bus[21];
reg [13:0] input_180, input_90;
always @(posedge clk40) begin
input_90 <= fdbk_input;
input_180 <= input_90;
end
wire [15:0] target = {set_wave[15],set_wave[15:1]} + {{2{input_180[13]}},input_180};
wire [15:0] e1 = {{2{fdbk_input[13]}},fdbk_input} - target;
// saturate the 16-bit initial error to 11 bits
// e1 is the old iERROR
// e1s is the old ERROR_sat_latched
reg [10:0] e1s, e2, e3;
always @(posedge clk40) begin
e1s <= ((e1[15:10]==6'b000000) | (e1[15:10]==6'b111111)) ? e1[10:0] : {e1[15],{10{~e1[15]}}};
e2 <= e1s; // formerly ERR1 in error3.v
e3 <= e2; // formerly ERR2 in error3.v
end
wire [23:0] prod1, prod2, prod3;
reg [12:0] e4; // formerly ERR3_loc in error3.v
always @(posedge clk40) e4 <= (feedback_enable & ~corrupted_multiplier) ?
({prod1[23],prod1[23:12]} + {prod2[23],prod2[23:12]}) : 0;
// Three loadable Constant Coefficient Multipliers (KCM)
// Note the unique three-bit addresses (ident)
dkcm_bussed MUL1( .var({e2,1'b0}), .product(prod1),
.clk(host_clk), .dkcm_bus(dkcm_bus), .ident(3'b001));
dkcm_bussed MUL2( .var({e3,1'b0}), .product(prod2),
.clk(host_clk), .dkcm_bus(dkcm_bus), .ident(3'b010));
dkcm_bussed MUL3( .var(e4[12:1]), .product(prod3),
.clk(host_clk), .dkcm_bus(dkcm_bus), .ident(3'b011));
reg [11:0] e6;
always @(posedge clk40) begin
e6 <= prod3[23:12]; // formerly ERR4 in error3.v
end
// Isolate downconversion to DC, or upconversion to 30 MHz, to afterburner.
// Integrator works on pseudo-10MHz signal, +I/+Q/-I/-Q.
reg [15:0] integrate_out;
reg [12:0] ff_pipe, integrate_input;
reg [16:0] integrate_sum;
// arithmetic saturation from 17 bits down to 16 bits
wire [15:0] integrate_sat = ((integrate_sum[16:15]==2'b00) | (integrate_sum[16:15]==2'b11)) ?
integrate_sum[15:0] : {integrate_sum[16],{15{~integrate_sum[16]}}};
always @(posedge clk40) begin
integrate_out <= integrate_enable ? integrate_sat : 16'b0;
integrate_sum <= {~integrate_out[15], ~integrate_out} + 1'b1 +
{{4{integrate_input[12]}}, integrate_input};
ff_pipe <= feedforward_data;
integrate_input <= ff_pipe + (corrupted_multiplier?13'b0:{e6,1'b0});
end
// Combine low-latency linear feedback with the integration results
// Saturation and sign extension are claimed valid
wire [12:0] fdbk_err_wide = {integrate_out[15], integrate_out[15:4] } + e4;
// arithmetic saturation from 13 bits down to 12 bits
wire [11:0] fdbk_err = ((fdbk_err_wide[12:11]==2'b00) | (fdbk_err_wide[12:11]==2'b11)) ?
fdbk_err_wide[11:0] : {fdbk_err_wide[12],{11{~fdbk_err_wide[12]}}};
always @(posedge clk40) fdbk_err_out <= fdbk_err;
endmodule