Source / Read the circuit
adc_fixed_correct.sv
lessons/adc_digital/rtl/adc_fixed_correct.sv
`timescale 1ns/1ps
// AD15: signed12/F0 raw, signed18/F4 offset, signed18/F16 inverse gain.
// Accepted at edge t, output after edge t+4. No backpressure. flush wins.
module adc_fixed_correct(input wire clk, rst_n, flush, in_valid,
input wire signed [11:0] raw,
input wire signed [17:0] offset, inverse_gain,
input wire [65:0] meta,
output reg out_valid, sat,
output reg signed [17:0] data,
output reg [65:0] out_meta);
reg [3:0] v;
reg [65:0] tag[0:3];
reg signed [18:0] difference;
reg signed [17:0] gain_q;
reg signed [36:0] product;
reg signed [37:0] rounded;
reg signed [17:0] clipped;
reg clipped_sat;
wire signed [18:0] extended={{7{raw[11]}},raw};
wire signed [18:0] off_extended={offset[17],offset};
wire signed [37:0] floor_q={{17{product[36]}},product[36:16]};
wire round_up=(product[15:0]>16'h8000) ||
((product[15:0]==16'h8000) && product[16]);
integer i;
always @(posedge clk) begin
if (!rst_n || flush) begin
v<=0; out_valid<=0; sat<=0; data<=0; out_meta<=0;
difference<=0; gain_q<=0; product<=0; rounded<=0; clipped<=0; clipped_sat<=0;
for(i=0;i<4;i=i+1) tag[i]<=0;
end else begin
v<={v[2:0],in_valid}; tag[0]<=meta;
for(i=1;i<4;i=i+1) tag[i]<=tag[i-1];
difference<=(extended<<<4)-off_extended; gain_q<=inverse_gain;
product<=difference*gain_q;
rounded<=floor_q+(round_up ? 38'sd1 : 38'sd0);
if(rounded>38'sd131071) begin clipped<=18'sd131071; clipped_sat<=1; end
else if(rounded< -38'sd131072) begin clipped<=-18'sd131072; clipped_sat<=1; end
else begin clipped<=rounded[17:0]; clipped_sat<=0; end
out_valid<=v[3]; data<=clipped; sat<=clipped_sat; out_meta<=tag[3];
end
end
endmodule