Files
Jungfraujoch/fpga/hls/jf_conversion.cpp

292 lines
14 KiB
C++

// Copyright (2019-2023) Paul Scherrer Institute
#ifndef JFJOCH_HLS_NOSYNTH
#include <hls_math.h>
#else
namespace hls {
inline float recip(float f) {return 1.0f/f;}
}
#endif
#include "hls_jfjoch.h"
// HBM and in-memory order:
// (HBM) p0, p1 - gain G0
// (HBM) p2, p3 - gain G1
// (HBM) p4, p5 - gain G2
// (HBM) p6, p7 - pedestal G0
// (HBM) p8, p9 - pedestal G1
// (HBM) p10, p11 - pedestal G2
ap_uint<768> convert(ap_uint<512> data_in,
ap_uint<256> packed_gainG0_1, ap_uint<256> packed_gainG0_2,
ap_uint<256> packed_gainG1_1, ap_uint<256> packed_gainG1_2,
ap_uint<256> packed_gainG2_1, ap_uint<256> packed_gainG2_2,
ap_uint<256> packed_pedeG0_1, ap_uint<256> packed_pedeG0_2,
ap_uint<256> packed_pedeG1_1, ap_uint<256> packed_pedeG1_2,
ap_uint<256> packed_pedeG2_1, ap_uint<256> packed_pedeG2_2,
ap_uint<1> save_raw,
ap_uint<1> fixed_g1,
one_over_energy_t one_over_energy_in_keV)
{
#pragma HLS PIPELINE
#pragma HLS INLINE off
const ap_fixed<37, 34, AP_RND_CONV> half = 0.5f;
ap_uint<16> in_val[32];
ap_int<24> out_val[32];
Loop0: for (int i = 0; i < 512; i++) in_val[i/16][i%16] = data_in[i];
ap_uint<16> pedeG0[32];
ap_uint<16> pedeG1[32];
ap_uint<16> pedeG2[32];
gainG0_t gainG0[32];
gainG1_t gainG1[32];
gainG2_t gainG2[32];
unpack_2xhbm_to_32x16bit(packed_gainG0_1, packed_gainG0_2, gainG0);
unpack_2xhbm_to_32x16bit(packed_gainG1_1, packed_gainG1_2, gainG1);
unpack_2xhbm_to_32x16bit(packed_gainG2_1, packed_gainG2_2, gainG2);
unpack_2xhbm_to_32x16bit(packed_pedeG0_1, packed_pedeG0_2, pedeG0);
unpack_2xhbm_to_32x16bit(packed_pedeG1_1, packed_pedeG1_2, pedeG1);
unpack_2xhbm_to_32x16bit(packed_pedeG2_1, packed_pedeG2_2, pedeG2);
Convert:
for (int i = 0; i < 32; i++) {
ap_uint<2> gain = in_val[i](15,14);
if (save_raw) for (int j = 0; j < 16; j++) out_val[i][j] = in_val[i][j];
else if ((gain == 0) && (gainG0[i] == 0)) out_val[i] = INT24_MIN; // if G0 gain factor is zero - mask pixel
else if ((gain == 1) && (gainG1[i] == 0)) out_val[i] = INT24_MIN; // if G1 gain factor is zero - mask pixel
else if ((gain == 3) && (gainG2[i] == 0)) out_val[i] = INT24_MIN; // if G2 gain factor is zero - mask pixel
else if (in_val[i] == 0xc000) out_val[i] = fixed_g1 ? INT24_MIN : INT24_MAX; // can saturate G2 - overload (but not when fixed G1)
else if (in_val[i] == 0xffff) out_val[i] = INT24_MIN; //error
else if (in_val[i] == 0x4000) out_val[i] = fixed_g1 ? INT24_MAX : INT24_MIN; // Cannot saturate G1 - error (but it is possible in fixed G1 mode)
else if (gain == 2) out_val[i] = INT24_MIN; // invalid gain
else if ((pedeG0[i] > 16383) && (gain == 0)) out_val[i] = INT24_MIN;
else if ((pedeG1[i] > 16383) && (gain == 1)) out_val[i] = INT24_MIN;
else if ((pedeG2[i] > 16383) && (gain == 3)) out_val[i] = INT24_MIN;
else if ((gain != 1) && fixed_g1) out_val[i] = INT24_MIN; // With fixed gain G1, don't expected anything else!
else {
ap_fixed<18,16, AP_RND_CONV> val_diff = 0;
ap_ufixed<25,6,AP_RND_CONV> val_gain = 0;
ap_uint<14> adu = in_val[i](13,0); // take first two bits
if (gain == 0) {
val_diff = adu - pedeG0[i];
val_gain = ap_ufixed<25,6,AP_RND_CONV>(gainG0[i]) / 32;
} else if (gain == 1) {
if (fixed_g1)
val_diff = adu - pedeG1[i];
else
val_diff = pedeG1[i] - adu;
val_gain = gainG1[i];
} else {
val_diff = pedeG2[i] - adu;
val_gain = gainG2[i];
}
ap_fixed<37, 34, AP_RND_CONV> val_result = (val_diff * val_gain) * one_over_energy_in_keV;
if (val_result > INT24_MAX)
out_val[i] = INT24_MAX;
else if (val_result >= 0)
out_val[i] = val_result + half;
else
out_val[i] = val_result - half;
}
}
return pack32(out_val);
}
void jf_conversion(STREAM_512 &data_in, STREAM_768 &data_out,
hls::stream<axis_completion > &s_axis_completion,
hls::stream<axis_completion > &m_axis_completion,
hls::burst_maxi<hbm256_t> d_hbm_p0, hls::burst_maxi<hbm256_t> d_hbm_p1,
hls::burst_maxi<hbm256_t> d_hbm_p2, hls::burst_maxi<hbm256_t> d_hbm_p3,
hls::burst_maxi<hbm256_t> d_hbm_p4, hls::burst_maxi<hbm256_t> d_hbm_p5,
hls::burst_maxi<hbm256_t> d_hbm_p6, hls::burst_maxi<hbm256_t> d_hbm_p7,
hls::burst_maxi<hbm256_t> d_hbm_p8, hls::burst_maxi<hbm256_t> d_hbm_p9,
hls::burst_maxi<hbm256_t> d_hbm_p10, hls::burst_maxi<hbm256_t> d_hbm_p11,
ap_uint<32> hbm_size_bytes) {
#pragma HLS INTERFACE ap_ctrl_none port=return
#pragma HLS INTERFACE register both axis port=data_in
#pragma HLS INTERFACE register both axis port=data_out
#pragma HLS INTERFACE register both axis port=s_axis_completion
#pragma HLS INTERFACE register both axis port=m_axis_completion
#pragma HLS INTERFACE register ap_none port=hbm_size_bytes
#pragma HLS INTERFACE m_axi port=d_hbm_p0 bundle=d_hbm_p0 depth=512 offset=off \
max_read_burst_length=16 max_write_burst_length=2 latency=120 num_write_outstanding=2 num_read_outstanding=9
#pragma HLS INTERFACE m_axi port=d_hbm_p1 bundle=d_hbm_p1 depth=512 offset=off \
max_read_burst_length=16 max_write_burst_length=2 latency=120 num_write_outstanding=2 num_read_outstanding=9
#pragma HLS INTERFACE m_axi port=d_hbm_p2 bundle=d_hbm_p2 depth=512 offset=off \
max_read_burst_length=16 max_write_burst_length=2 latency=120 num_write_outstanding=2 num_read_outstanding=9
#pragma HLS INTERFACE m_axi port=d_hbm_p3 bundle=d_hbm_p3 depth=512 offset=off \
max_read_burst_length=16 max_write_burst_length=2 latency=120 num_write_outstanding=2 num_read_outstanding=9
#pragma HLS INTERFACE m_axi port=d_hbm_p4 bundle=d_hbm_p4 depth=512 offset=off \
max_read_burst_length=16 max_write_burst_length=2 latency=120 num_write_outstanding=2 num_read_outstanding=9
#pragma HLS INTERFACE m_axi port=d_hbm_p5 bundle=d_hbm_p5 depth=512 offset=off \
max_read_burst_length=16 max_write_burst_length=2 latency=120 num_write_outstanding=2 num_read_outstanding=9
#pragma HLS INTERFACE m_axi port=d_hbm_p6 bundle=d_hbm_p6 depth=512 offset=off \
max_read_burst_length=16 max_write_burst_length=2 latency=120 num_write_outstanding=2 num_read_outstanding=9
#pragma HLS INTERFACE m_axi port=d_hbm_p7 bundle=d_hbm_p7 depth=512 offset=off \
max_read_burst_length=16 max_write_burst_length=2 latency=120 num_write_outstanding=2 num_read_outstanding=9
#pragma HLS INTERFACE m_axi port=d_hbm_p8 bundle=d_hbm_p8 depth=512 offset=off \
max_read_burst_length=16 max_write_burst_length=2 latency=120 num_write_outstanding=2 num_read_outstanding=9
#pragma HLS INTERFACE m_axi port=d_hbm_p9 bundle=d_hbm_p9 depth=512 offset=off \
max_read_burst_length=16 max_write_burst_length=2 latency=120 num_write_outstanding=2 num_read_outstanding=9
#pragma HLS INTERFACE m_axi port=d_hbm_p10 bundle=d_hbm_p10 depth=512 offset=off \
max_read_burst_length=16 max_write_burst_length=2 latency=120 num_write_outstanding=2 num_read_outstanding=9
#pragma HLS INTERFACE m_axi port=d_hbm_p11 bundle=d_hbm_p11 depth=512 offset=off \
max_read_burst_length=16 max_write_burst_length=2 latency=120 num_write_outstanding=2 num_read_outstanding=9
packet_512_t packet_in;
packet_768_t packet_out;
{
#pragma HLS PROTOCOL fixed
data_in >> packet_in;
ap_wait();
packet_out.data = packet_in.data;
packet_out.last = packet_in.last;
packet_out.user = packet_in.user;
data_out << packet_out;
ap_wait();
}
float_uint32 in_energy_kev;
ap_uint<64> mode = ACT_REG_MODE(packet_in.data);
ap_uint<1> conversion = (mode & MODE_CONV) ? 1 : 0;
ap_uint<1> fixed_g1 = (mode & MODE_FIXG1) ? 1 : 0;
ap_uint<1> mode_unsigned = ((mode & MODE_UNSIGNED) ? 1 : 0);
ap_uint<6> modules = ACT_REG_NMODULES(packet_in.data) + 1;
in_energy_kev.u = ACT_REG_ENERGY_KEV_FLOAT(packet_in.data);
ap_uint<5> storage_cells = ACT_REG_NSTORAGE_CELLS(packet_in.data);
ap_uint<32> offset_hbm_0 = 0 * hbm_size_bytes / 32;
ap_uint<32> offset_hbm_1 = 1 * hbm_size_bytes / 32;
ap_uint<32> offset_hbm_2 = 2 * hbm_size_bytes / 32;
ap_uint<32> offset_hbm_3 = 3 * hbm_size_bytes / 32;
ap_uint<32> offset_hbm_4 = 4 * hbm_size_bytes / 32;
ap_uint<32> offset_hbm_5 = 5 * hbm_size_bytes / 32;
ap_uint<32> offset_hbm_6 = 6 * hbm_size_bytes / 32;
ap_uint<32> offset_hbm_7 = 7 * hbm_size_bytes / 32;
ap_uint<32> offset_hbm_8 = 8 * hbm_size_bytes / 32;
ap_uint<32> offset_hbm_9 = 9 * hbm_size_bytes / 32;
ap_uint<32> offset_hbm_10 = 10 * hbm_size_bytes / 32;
ap_uint<32> offset_hbm_11 = 11 * hbm_size_bytes / 32;
one_over_energy_t one_over_energy;
if (hls::isfinite(in_energy_kev.f) && (in_energy_kev.f != 0.0))
one_over_energy = hls::recip(in_energy_kev.f);
else
one_over_energy = 0;
axis_completion cmpl;
s_axis_completion >> cmpl;
convert_images:
while (!cmpl.last) {
m_axis_completion << cmpl;
if (conversion && (cmpl.detector_type == SLS_DETECTOR_TYPE_JUNGFRAU)) {
for (ap_uint<15> i = 0; i < RAW_MODULE_SIZE * sizeof(uint16_t) / 64; i++) {
#pragma HLS PIPELINE II=1
if (i % 16 == 0) {
ap_uint<19> gain_offset = (cmpl.module, i(13, 0));
ap_uint<12> pedestal_location = cmpl.module;
if (storage_cells > 1) {
ap_uint<4> storage_cell_id = cmpl.frame_number % storage_cells;
pedestal_location += modules * storage_cell_id;
}
ap_uint<26> pedestal_offset = (pedestal_location, i(13, 0));
d_hbm_p0.read_request(offset_hbm_0 + gain_offset, 16);
d_hbm_p1.read_request(offset_hbm_1 + gain_offset, 16);
d_hbm_p2.read_request(offset_hbm_2 + gain_offset, 16);
d_hbm_p3.read_request(offset_hbm_3 + gain_offset, 16);
d_hbm_p4.read_request(offset_hbm_4 + gain_offset, 16);
d_hbm_p5.read_request(offset_hbm_5 + gain_offset, 16);
d_hbm_p6.read_request(offset_hbm_6 + pedestal_offset, 16);
d_hbm_p7.read_request(offset_hbm_7 + pedestal_offset, 16);
d_hbm_p8.read_request(offset_hbm_8 + pedestal_offset, 16);
d_hbm_p9.read_request(offset_hbm_9 + pedestal_offset, 16);
d_hbm_p10.read_request(offset_hbm_10 + pedestal_offset, 16);
d_hbm_p11.read_request(offset_hbm_11 + pedestal_offset, 16);
}
ap_uint<256> packed_gainG0_1 = d_hbm_p0.read();
ap_uint<256> packed_gainG0_2 = d_hbm_p1.read();
ap_uint<256> packed_gainG1_1 = d_hbm_p2.read();
ap_uint<256> packed_gainG1_2 = d_hbm_p3.read();
ap_uint<256> packed_gainG2_1 = d_hbm_p4.read();
ap_uint<256> packed_gainG2_2 = d_hbm_p5.read();
ap_uint<256> packed_pedeG0_1 = d_hbm_p6.read();
ap_uint<256> packed_pedeG0_2 = d_hbm_p7.read();
ap_uint<256> packed_pedeG1_1 = d_hbm_p8.read();
ap_uint<256> packed_pedeG1_2 = d_hbm_p9.read();
ap_uint<256> packed_pedeG2_1 = d_hbm_p10.read();
ap_uint<256> packed_pedeG2_2 = d_hbm_p11.read();
data_in >> packet_in;
packet_out.data = convert(packet_in.data,
packed_gainG0_1, packed_gainG0_2,
packed_gainG1_1, packed_gainG1_2,
packed_gainG2_1, packed_gainG2_2,
packed_pedeG0_1, packed_pedeG0_2,
packed_pedeG1_1, packed_pedeG1_2,
packed_pedeG2_1, packed_pedeG2_2,
packet_in.id[0],
fixed_g1,
one_over_energy);
packet_out.last = packet_in.last;
packet_out.user = packet_in.user;
data_out << packet_out;
}
} else {
for (int i = 0; i < RAW_MODULE_SIZE * sizeof(uint16_t) / 64; i++) {
#pragma HLS PIPELINE II=1
data_in >> packet_in;
ap_int<24> val_out[32];
if (mode_unsigned) {
ap_uint<16> val_in[32];
unpack32(packet_in.data, val_in);
for (int i = 0; i < 32; i++) {
if (val_in[i] == UINT16_MAX)
val_out[i] = INT24_MAX;
else
val_out[i] = val_in[i];
}
} else {
ap_int<16> val_in[32];
unpack32(packet_in.data, val_in);
for (int i = 0; i < 32; i++) {
if (val_in[i] == INT16_MAX)
val_out[i] = INT24_MAX;
else if (val_in[i] == INT16_MIN)
val_out[i] = INT24_MIN;
else
val_out[i] = val_in[i];
}
}
packet_out.data = pack32(val_out);
packet_out.last = packet_in.last;
packet_out.user = packet_in.user;
data_out << packet_out;
}
}
s_axis_completion >> cmpl;
}
m_axis_completion << cmpl;
data_in >> packet_in;
packet_out.data = packet_in.data;
packet_out.last = packet_in.last;
packet_out.user = packet_in.user;
data_out << packet_out;
}