cr_x16 HDL Worker
Time-shared (folded) implementation of a 4th-power Costas carrier-recovery and derotation loop operating across 16 MSK channels with one physical datapath.
Detail
The worker is built around three concurrent processes that share the single clock
domain (ctl_in.clk). Reset is the logical OR of ctl_in.reset and the
init writable property.
Loop (error) path — 9-stage pipeline
Channels enter the pipeline one per clock in round-robin positional order. A
two-wide sideband pipeline (ch_p(0..9), vld_p(0..9)) carries the
channel id and valid flag alongside the data so that each per-channel RAM is
indexed by the channel that is in-flight at that stage, not by an external
injection counter. This prevents the cross-channel attribution error that would
arise from the 1-clock valid/data skews present in the sequential
carrier_correction_4p design.
S0 — capture:
i0/q0←input_in.data[31:16]/[15:0].S1 — complex square:
i_sqr = i0*i0,q_sqr = q0*q0,iq_2x = 2*(i0*q0)(full 32-bit products).S2 — combine to s²:
sqr_re = i_sqr - q_sqr,sqr_im = iq_2x; MSB-slice truncation back to 16 bits (combinational, outside the clocked process).S3 — square again: same structure on the s² slices, producing s⁴ products.
S4 — combine to s⁴: same MSB-slice truncation back to 16 bits.
S5 — 4x NCO mix: the
sin_cos_lutROM is looked up with the top 10 bits ofphase_4x[ch_p(4)]one clock before this stage’s registered multiply;mix_a = quad_im * cos_4x,mix_b = quad_re * sin_4x. The 4x NCO phase is advanced byfreq_4x[ch]on every valid beat at this stage (use-then-advance).S6 — phase error:
pll_err_raw = mix_a - mix_b(cross-product form of the Costas discriminant, sign-extended toSAMPLE_W + SINUSOID_W + 1= 29 bits).S7 — IIR low-pass filter:
lpf_acc[ch] += pll_err_raw - (lpf_acc[ch] >> LPF_ALPHA)whereLPF_ALPHA= 10. The pre-update accumulator value, right-shifted byLPF_ALPHA, formslpf_out(16 bits), which feeds both the PI and the lock detector. Lock detection runs an IIR energy tracker on|lpf_out|with a compile-time threshold of2^(LOCK_ACC_W-6)(LOCK_ACC_W= 24).S8 — PI filter: integral accumulator
i_acc[ch]is updated and saturated to[MAX_ACC_NEG, MAX_ACC_POS](overflow-wrap protection);i_val = (i_acc[ch] * ig) >> i_shift,p_val = (pg * lpf_out) >> p_shiftwhereig/pgare the 24-bit gain vectors fromcc_lpf_i_gain/cc_lpf_p_gainand the shifts come fromcc_lpf_i_shift/cc_lpf_p_shift.cc_lpf_freezeholdsi_accwithout zeroing;cc_lpf_zeroclearsi_accand forcesi_valto zero.S9 — NCO update:
freq_4x[ch] = p_val + i_val.
Fixed-point summary: input samples are Q1.15 (signed 16-bit); the s² and s⁴
intermediate products are computed at full width and the MSB slice restores Q1.15
at each squaring stage; the IIR accumulator is 40 bits (SAMPLE_W + SINUSOID_W
+ LPF_ALPHA + 2); the PI accumulators are 32-bit signed with
MAX_ACC_POS = 2^30, MAX_ACC_NEG = 3*2^30; the NCO frequency word is 32
bits (the top 10 bits select the sin/cos ROM phase).
Derotation (output) path — 2-stage pipeline
This path runs in parallel with and independently of the loop path. On every accepted input beat:
Stage A — the 1x derotation NCO phase for
cur_chis looked up in the secondsin_cos_lutROM (phase = top 10 bits ofphase_1x[cur_ch]); the four productsi*cos,q*sin,i*sin,q*cosare computed. The 1x NCO phase is then advanced byfreq_4x[cur_ch] >> 2.Stage B —
i_out = i*cos + q*sin,q_out = q*cos - i*sin; the unity-gain restoring slice ([SAMPLE_W + SINUSOID_W - 2 : SINUSOID_W - 1], i.e. bits[25:11]of a 28-bit product) maps the output back to Q1.15.
Output FIFO
A 128-entry synchronous FIFO (7-bit address, {iq[31:0], som, eom} per entry)
decouples the fixed-latency derotation pipeline from downstream backpressure.
can_accept drops when the FIFO occupancy reaches FIFO_DEPTH - 8, giving
enough headroom for the samples already in the derotation pipeline to drain
without loss.
Volatile status
cc_freq_word[ch] is freq_4x[ch] >> 2 (the 1x equivalent NCO frequency
word in the same units as the 32-bit NCO). cc_lock[ch] is set when the IIR
lock-energy tracker falls below the compile-time threshold.
Latency from input sample to derotated output sample: 2 clock cycles (derotation path A + B), plus FIFO read latency of 1 cycle when output is immediately ready — approximately 3 cycles total. The loop path has a 9-cycle latency that affects only the frequency-word update, not the derotated sample timing.
Worker Properties
ocpi_buffer_size_outputType:
ushortAccess:
Parameter:
FalseWritable:
FalseInitial:
TrueVolatile:
FalseRead back:
False
Default value:
0
ocpi_blocked_outputType:
ulongAccess:
Parameter:
FalseWritable:
FalseInitial:
FalseVolatile:
TrueRead back:
False
Default value:
None
ocpi_max_latency_outputType:
ushortAccess:
Parameter:
TrueWritable:
FalseInitial:
FalseVolatile:
FalseRead back:
False
Default value:
None
ocpi_latency_outputType:
ushortAccess:
Parameter:
FalseWritable:
FalseInitial:
FalseVolatile:
TrueRead back:
False
Default value:
None
ocpi_messages_outputType:
ulongAccess:
Parameter:
FalseWritable:
FalseInitial:
FalseVolatile:
TrueRead back:
False
Default value:
None
ocpi_bytes_outputType:
ulongAccess:
Parameter:
FalseWritable:
FalseInitial:
FalseVolatile:
TrueRead back:
False
Default value:
None
Worker Ports
inputProtocol:
complex_short_timed_sampleOptional:
False
outputProtocol:
complex_short_timed_sampleOptional:
False
Inputs:
Outputs:
Worker Ports
Inputs:
input:Type:
StreamInterfaceProtocol:
complex_short_timed_sample-protClockDirection:
inData width:
32
Outputs:
output:Type:
StreamInterfaceProtocol:
complex_short_timed_sample-protWorker EOF:
trueClock:
inputData width:
32
Utilisation
Utilization reporting is not currently implemented.