Files
gps/hardware/external/gps/rtl/apb_wrappers/tracking_wrapper.sv
T
onur f59d6ebb43 fix(gps): correct week-number handling across almanac, ephemeris and flash
Persisting navigation data changed its lifetime from one power cycle to
weeks, and every piece of arithmetic that had only ever run over the
shorter lifetime turned out to be wrong. Each fix below reproduces in a
host test that fails against the previous behaviour.

Almanac (gps_almanac.c, gps_lnav_parser.c)

WNa was lifted against gps_ephems.toe.week, a field nothing ever writes,
so any WNa above 128 underflowed to ~4.29e9. The propagation then reduced
tk with a while-loop, turning one visibility refresh into 4.29e9
iterations - hours on the target, inside a 10 s periodic call. WNa is the
week modulo 256, so this armed at GPS week 2433 and then for 127 weeks in
every 256. Now lifted against tow.week in signed arithmetic, refused if
impossible, and the propagation is closed form.

The IS-GPS-200 20.3.3.5.2.3 half-week wrap was also applied to tk
unconditionally. It is a week-crossover correction, not a general
reduction: a GPS week is 14.0384 orbital periods, so aliasing one week
moves a satellite 5161 km, enough to report one 5.1 degrees below the
horizon as 5.7 above. The crossover guess now lives in
gps_almanac_assumed_week(), used only before page 25 arrives, and an
almanac too old to propagate yields no prediction rather than a wrong one.

Ephemeris age (gps_ephemeris_validity.c, gps_lnav_parser.c)

The curve-fit check compared two second-of-week values and never read a
week at all, so a record exactly N weeks old read as current. Harmless
while ephemeris lived in RAM; directly reachable once persisted across a
power-off. gps_resolve_toe_week() now reconstructs Toe's week at commit
time from the subframe 1 week number and the handover word; an
unresolvable week yields no age, which reads as a rejection.

A restored record could also outrank the live broadcast, because the Toe
ordering inverts past half a week. Flash records are now marked restored
and are candidates, never incumbents.

Flash wear (gps_nav_context_store.c, gps_interrupt_handlers.c)

The CRC wear policy never engaged: the payload carried the live WLS
position and a receiver timestamp nothing on the restore path read, so
every 60 s save was an erase - about 139 days to wear-out. The seed is
now held and refreshed only on 5 km of movement, at most hourly: one
erase per day instead of 1440.

Measurement model (NavEquations.c)

The elevation weighting was floored at 10 degrees, capping its term at
17.3 m where the model's own answer is 34.4 m at 5 degrees and 86 m at 2,
so a low satellite was trusted several times more than the model allowed.
Floor lowered to 3 degrees, which is where 1/sin must still be bounded
because a zero weight fails the whole epoch. Measured on a six-satellite
geometry, 30 m of uncorrected delay now moves the fix 4.18 m through a
4-degree satellite against 48.50 m through a 72-degree one.

Both atmospheric corrections switched off below the horizon, so a
satellite crossing it lost 78.8 m of tropospheric delay in one step.
Elevation is now clamped at the horizon for the models, and the
extrapolation is paid for in variance.

Also: gps_pps_select_reference() returned early on the preferred PRN,
leaving later non-finite capture times unscreened.

Checked and found correct, with regressions added: the epoch assembly
under satellite connect/disconnect and reassignment, coalesced captures,
the 32-bit RF sample counter wrap (pseudoranges agree to 3.3 um across
it), the refusal to publish a solvable subset of an incoherent epoch, and
the Klobuchar model against IS-GPS-200 20.3.3.5.2.5.

Tests: 22 host suites, 5 RTL testbenches, sanitizer clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 01:45:35 +03:00

923 lines
39 KiB
Systemverilog

import definitions::*;
module tracking_wrapper #(
parameter HIGH_ADDRESS = 32'h20000,
parameter LOW_ADDRESS = 32'h10000,
parameter DATA_BUS_WIDTH = 32,
parameter ADDR_BUS_WIDTH = 12
)
(
// ########## APB BUS ####################
// input
input logic PCLK,
input logic PRESETN,
input logic[(ADDR_BUS_WIDTH - 1) : 0] PADDR,
input logic PSEL,
input logic PENABLE,
input logic PWRITE,
input logic[(DATA_BUS_WIDTH - 1) : 0] PWDATA,
// output
output logic PREADY, // ready handshake signal from slave
output logic[(DATA_BUS_WIDTH - 1) : 0] PRDATA, // read data from slave module
output logic PSLVERR, // read data from slave module
// ########## APB BUS ####################
input trck_resetn,
input afe_resetn,
input logic trck_clk,
input logic afe_clk,
input logic[3 : 0] afe_data,
input logic sample_align,
input logic[31 : 0] sample_counter,
// INTERRUPT LINES / PPS epoch timestamp request
output logic gps_frame_ready,
output logic pps_capture
);
import gps_top_pkg::*;
import trck_pkg::*;
localparam int unsigned MEAS_CARRIER_WL =
ACQUIRED_FREQ_IL + TRCK_CARR_NCO_FREQ_FL;
localparam int unsigned MEAS_SUM_WL =
TRCK_CORR_WL + $clog2(MS_PER_BIT);
localparam int unsigned MEAS_WBP_WL =
(2 * TRCK_CORR_WL) + 1 + $clog2(MS_PER_BIT);
localparam int unsigned MEAS_COUNT_WL = $clog2(MS_PER_BIT + 1);
// apb state machine
apb_state_e apb_bus_ps, apb_bus_ns;
// tracking lock state machine
//trck_state_e trck_state_p, trck_state_n;
// internal net declarations.
logic intr_clear; // generic interrupt flag clear signal.
logic start_trck;
logic stop_trck;
logic timeout_stop;
logic to_start_trck_pin;
logic to_stop_trck_pin;
logic to_start_trck_pin_ff;
logic to_stop_trck_pin_ff;
// nav solve timer I/O
logic nav_solve_timer_reached;
logic nav_solve_timer_load_abs_sample_signal;
logic nav_solve_phase_seed_consumed;
logic nav_solve_provisional;
//
logic [1 : 0] bit_vld_cc_p, bit_vld_cc_n, load_sigs_cc_p, load_sigs_cc_n;
// signals to be syned.
logic lock, lock_syned, busy, busy_syned;
logic bit_valid, load_sigs, bit_valid_syned; // -> loads sigs, load internal registers & signals.
logic nav_bit, nav_bit_syned; // navigation bits.
logic [31 : 0] abs_sample, abs_sample_syned;
logic [REM_CODE_PH_I_WL-1 : 0] rem_code_ph, rem_code_ph_syned;
logic measurement_valid, measurement_valid_syned;
logic measurement_bit, measurement_bit_syned;
logic [31:0] measurement_abs_sample, measurement_abs_sample_syned;
logic [REM_CODE_PH_I_WL-1:0] measurement_rem_code_ph;
logic [REM_CODE_PH_I_WL-1:0] measurement_rem_code_ph_syned;
logic signed [MEAS_CARRIER_WL-1:0] measurement_carrier_freq_q7;
logic [MEAS_CARRIER_WL-1:0] measurement_carrier_freq_q7_syned;
logic signed [MEAS_SUM_WL-1:0] measurement_cn0_sum_i;
logic signed [MEAS_SUM_WL-1:0] measurement_cn0_sum_q;
logic [MEAS_SUM_WL-1:0] measurement_cn0_sum_i_syned;
logic [MEAS_SUM_WL-1:0] measurement_cn0_sum_q_syned;
logic [MEAS_WBP_WL-1:0] measurement_cn0_wbp;
logic [MEAS_WBP_WL-1:0] measurement_cn0_wbp_syned;
logic [MEAS_COUNT_WL-1:0] measurement_cn0_sample_count;
logic [MEAS_COUNT_WL-1:0] measurement_cn0_sample_count_syned;
logic [15:0] measurement_sequence, measurement_sequence_syned;
logic preamble_ok;
// ( internal flags )
logic intr_pending_p, intr_pending_n; // generic interrupt flag.
logic trck_nav_bit_rcv_flag_p, trck_nav_bit_rcv_flag_n;
logic trck_timeout_flag_p, trck_timeout_flag_n;
logic trck_nav_solve_flag_p, trck_nav_solve_flag_n;
logic trck_measurement_flag_p, trck_measurement_flag_n;
logic [31 : 0] timeout_counter_p, timeout_counter_n; // tracking auto timeout value
logic [309 : 0] shift_reg_p, shift_reg_n;
// registers. (not be syned in this case since software write delay will be enough)
logic [13 : 0] code_phase_reg_p, code_phase_reg_n;
logic [4 : 0] prn_no_reg_p, prn_no_reg_n;
logic [21 : 0] doppler_reg_p, doppler_reg_n;
logic [31 : 0] abs_sample_reg_p, abs_sample_reg_n;
logic [REM_CODE_PH_I_WL-1 : 0] rem_code_ph_reg_p, rem_code_ph_reg_n;
logic [31 : 0] control_reg_p, control_reg_n;
logic [31 : 0] timeout_reg_p, timeout_reg_n;
logic [31 : 0] nav_solve_timer_reg_p, nav_solve_timer_reg_n;
logic [31 : 0] nav_solve_phase_seed_reg_p, nav_solve_phase_seed_reg_n;
logic [30 : 0] nav_bit_read_reg_p[10], nav_bit_read_reg_n[10];
// Atomic APB-domain copy of the 20 ms measurement.
logic measurement_valid_r;
logic measurement_capture_pending;
logic [1:0] measurement_settle_count;
logic measurement_capture;
logic measurement_interrupt_pulse;
logic measurement_data_valid_reg;
logic measurement_bit_reg;
logic measurement_lock_reg;
logic [31:0] measurement_abs_sample_reg;
logic [REM_CODE_PH_I_WL-1:0] measurement_rem_code_ph_reg;
logic signed [MEAS_CARRIER_WL-1:0] measurement_carrier_freq_q7_reg;
logic signed [MEAS_SUM_WL-1:0] measurement_cn0_sum_i_reg;
logic signed [MEAS_SUM_WL-1:0] measurement_cn0_sum_q_reg;
logic [MEAS_WBP_WL-1:0] measurement_cn0_wbp_reg;
logic [MEAS_COUNT_WL-1:0] measurement_cn0_sample_count_reg;
logic [15:0] measurement_sequence_reg;
logic[2 : 0] start_trck_ctl_p, start_trck_ctl_n;
logic[2 : 0] stop_trck_ctl_p, stop_trck_ctl_n;
assign to_start_trck_pin = (start_trck_ctl_p != 0) ? 1 : 0;
assign to_stop_trck_pin = (stop_trck_ctl_p != 0) ? 1 : 0;
// ABS_SAMPLE and REM_CODE_PHASE are latched on this same PCLK pulse. PPS
// timestamps only navigation-solve epochs; subframe-ready is not a position
// epoch and therefore must not create a PPS anchor.
assign pps_capture = nav_solve_timer_reached;
// comb. logic register cdc
always_ff @(posedge PCLK) begin : start_stop_cdc_ff
to_start_trck_pin_ff <= to_start_trck_pin;
to_stop_trck_pin_ff <= to_stop_trck_pin;
end : start_stop_cdc_ff
// syn. modules
double_ff_syn#(1, 2) i_bit_vld_syn(
.clk(PCLK),
.aresetn(PRESETN),
.Din(bit_valid),
.Dout(bit_valid_syned)
);
double_ff_syn#(1, 2) i_lock_syn( // multi bit acqusition status and acqusition end
.clk(PCLK),
.aresetn(PRESETN),
.Din(lock),
.Dout(lock_syned)
);
double_ff_syn#(1, 2) i_nav_bit_syn(
.clk(PCLK),
.aresetn(PRESETN),
.Din(nav_bit),
.Dout(nav_bit_syned)
);
double_ff_syn#(1, 2) i_busy_syn(
.clk(PCLK),
.aresetn(PRESETN),
.Din(busy),
.Dout(busy_syned)
);
double_ff_syn#(32, 2) i_abs_sample_syn(
.clk(PCLK),
.aresetn(PRESETN),
.Din(abs_sample),
.Dout(abs_sample_syned)
);
double_ff_syn#(REM_CODE_PH_I_WL, 2) i_rem_code_ph_syn(
.clk(PCLK),
.aresetn(PRESETN),
.Din(rem_code_ph),
.Dout(rem_code_ph_syned)
);
double_ff_syn#(1, 2) i_measurement_valid_syn(
.clk(PCLK), .aresetn(PRESETN),
.Din(measurement_valid), .Dout(measurement_valid_syned)
);
double_ff_syn#(1, 2) i_measurement_bit_syn(
.clk(PCLK), .aresetn(PRESETN),
.Din(measurement_bit), .Dout(measurement_bit_syned)
);
double_ff_syn#(32, 2) i_measurement_abs_sample_syn(
.clk(PCLK), .aresetn(PRESETN),
.Din(measurement_abs_sample), .Dout(measurement_abs_sample_syned)
);
double_ff_syn#(REM_CODE_PH_I_WL, 2) i_measurement_rem_code_ph_syn(
.clk(PCLK), .aresetn(PRESETN),
.Din(measurement_rem_code_ph), .Dout(measurement_rem_code_ph_syned)
);
double_ff_syn#(MEAS_CARRIER_WL, 2) i_measurement_carrier_syn(
.clk(PCLK), .aresetn(PRESETN),
.Din(measurement_carrier_freq_q7),
.Dout(measurement_carrier_freq_q7_syned)
);
double_ff_syn#(MEAS_SUM_WL, 2) i_measurement_sum_i_syn(
.clk(PCLK), .aresetn(PRESETN),
.Din(measurement_cn0_sum_i), .Dout(measurement_cn0_sum_i_syned)
);
double_ff_syn#(MEAS_SUM_WL, 2) i_measurement_sum_q_syn(
.clk(PCLK), .aresetn(PRESETN),
.Din(measurement_cn0_sum_q), .Dout(measurement_cn0_sum_q_syned)
);
double_ff_syn#(MEAS_WBP_WL, 2) i_measurement_wbp_syn(
.clk(PCLK), .aresetn(PRESETN),
.Din(measurement_cn0_wbp), .Dout(measurement_cn0_wbp_syned)
);
double_ff_syn#(MEAS_COUNT_WL, 2) i_measurement_count_syn(
.clk(PCLK), .aresetn(PRESETN),
.Din(measurement_cn0_sample_count),
.Dout(measurement_cn0_sample_count_syned)
);
double_ff_syn#(16, 2) i_measurement_sequence_syn(
.clk(PCLK), .aresetn(PRESETN),
.Din(measurement_sequence), .Dout(measurement_sequence_syned)
);
trck_top i_trck_top(
// common signals
.trk_rstn(trck_resetn),
.afe_rstn(afe_resetn),
.trk_clk(trck_clk),
.afe_clk(afe_clk),
.sample_align_i(sample_align), // from afe
.sample_counter_i(sample_counter), // from afe
.rf_data_i(afe_data), // from afe
// intputs from regs. destination module should implement cdc.
.start_i(to_start_trck_pin_ff),
.stop_i(to_stop_trck_pin_ff),
.prn_i(prn_no_reg_p),
.carr_freq_i(doppler_reg_p),
.code_phase_i(code_phase_reg_p),
// output to regs. (all values are valid on bit_vld except lock ?)
.bit_o(nav_bit),
.bit_vld_o(bit_valid),
.abs_sample_o(abs_sample), // 20 ms bit valid aligned
.rem_code_ph_o(rem_code_ph),
.measurement_vld_o(measurement_valid),
.measurement_bit_o(measurement_bit),
.measurement_abs_sample_o(measurement_abs_sample),
.measurement_rem_code_ph_o(measurement_rem_code_ph),
.measurement_carrier_freq_q7_o(measurement_carrier_freq_q7),
.measurement_cn0_sum_i_o(measurement_cn0_sum_i),
.measurement_cn0_sum_q_o(measurement_cn0_sum_q),
.measurement_cn0_wbp_o(measurement_cn0_wbp),
.measurement_cn0_sample_count_o(measurement_cn0_sample_count),
.measurement_sequence_o(measurement_sequence),
.lock_o(lock),
.busy_o(busy),
//unconnected ( for debug purposes )
.fifo_of_o()
);
/*
* The source payload is stable for 20 ms. Its valid marker and every data
* bit pass through the same three-stage synchronizer; two extra PCLK cycles
* after the synchronized rising edge provide a conservative bus-settle
* margin before the software-visible registers and interrupt are updated.
*/
always_ff @(posedge PCLK or negedge PRESETN) begin : measurement_capture_seq
if(!PRESETN) begin
measurement_valid_r <= 1'b0;
measurement_capture_pending <= 1'b0;
measurement_settle_count <= '0;
measurement_capture <= 1'b0;
measurement_interrupt_pulse <= 1'b0;
measurement_data_valid_reg <= 1'b0;
measurement_bit_reg <= 1'b0;
measurement_lock_reg <= 1'b0;
measurement_abs_sample_reg <= '0;
measurement_rem_code_ph_reg <= '0;
measurement_carrier_freq_q7_reg <= '0;
measurement_cn0_sum_i_reg <= '0;
measurement_cn0_sum_q_reg <= '0;
measurement_cn0_wbp_reg <= '0;
measurement_cn0_sample_count_reg <= '0;
measurement_sequence_reg <= '0;
end else begin
measurement_valid_r <= measurement_valid_syned;
measurement_capture <= 1'b0;
measurement_interrupt_pulse <= measurement_capture;
if(measurement_valid_syned && !measurement_valid_r) begin
measurement_capture_pending <= 1'b1;
measurement_settle_count <= 2;
end else if(measurement_capture_pending) begin
if(measurement_settle_count != 0) begin
measurement_settle_count <= measurement_settle_count - 1'b1;
end else begin
measurement_capture_pending <= 1'b0;
measurement_capture <= 1'b1;
measurement_data_valid_reg <= 1'b1;
measurement_bit_reg <= measurement_bit_syned;
measurement_lock_reg <= lock_syned;
measurement_abs_sample_reg <= measurement_abs_sample_syned;
measurement_rem_code_ph_reg <= measurement_rem_code_ph_syned;
measurement_carrier_freq_q7_reg <=
$signed(measurement_carrier_freq_q7_syned);
measurement_cn0_sum_i_reg <=
$signed(measurement_cn0_sum_i_syned);
measurement_cn0_sum_q_reg <=
$signed(measurement_cn0_sum_q_syned);
measurement_cn0_wbp_reg <= measurement_cn0_wbp_syned;
measurement_cn0_sample_count_reg <=
measurement_cn0_sample_count_syned;
measurement_sequence_reg <= measurement_sequence_syned;
end
end
end
end
// internal signals & assignments
assign PREADY = (apb_bus_ps == APB_STATE_IDLE) ? 1'b0 : 1'b1;
assign bit_vld_cc_n = {bit_vld_cc_p[0], bit_valid_syned};
assign load_sigs_cc_n = {load_sigs_cc_p[0], load_sigs};
// APB NEXT STATE LOGIC && INTERNAL SIGNAL SEQ. LOGIC.
always_ff @(posedge PCLK or negedge PRESETN) begin : intr_sig_reg_seq
if(!PRESETN) begin
apb_bus_ps <= APB_STATE_IDLE;
//trck_state_p <= TRCK_STATE_IDLE;
shift_reg_p <= '0;
code_phase_reg_p <= '0;
prn_no_reg_p <= '0;
control_reg_p <= '0;
doppler_reg_p <= '0;
abs_sample_reg_p <= '0;
rem_code_ph_reg_p <= '0;
bit_vld_cc_p <= '0;
load_sigs_cc_p <= '0;
intr_pending_p <= '0;
timeout_reg_p <= trck_pkg::TRCK_TIMEOUT_RESET_VAL;
nav_solve_timer_reg_p <= 'ha;
nav_solve_phase_seed_reg_p <= '0;
timeout_counter_p <= '0;
start_trck_ctl_p <= '0;
stop_trck_ctl_p <= '0;
trck_timeout_flag_p <= '0;
trck_nav_solve_flag_p <= '0;
trck_nav_bit_rcv_flag_p <= '0;
trck_measurement_flag_p <= '0;
// control reg bit fields set by reset.
control_reg_p[TRCK_NAV_BITS_FLAG_ENABLE_POS] <= 1'b1;
control_reg_p[TRCK_NAV_SOLVE_FLAG_EN_POS] <= 1'b1;
control_reg_p[TRCK_STOP_ON_UNLOCK_FLAG_EN_POS] <= 1'b1;
control_reg_p[TRCK_MEASUREMENT_FLAG_EN_POS] <= 1'b1;
foreach(nav_bit_read_reg_p[i])
nav_bit_read_reg_p[i] <= '0;
end
else begin
apb_bus_ps <= apb_bus_ns;
//trck_state_p <= trck_state_n;
shift_reg_p <= shift_reg_n;
code_phase_reg_p <= code_phase_reg_n;
prn_no_reg_p <= prn_no_reg_n;
control_reg_p <= control_reg_n;
doppler_reg_p <= doppler_reg_n;
abs_sample_reg_p <= abs_sample_reg_n;
rem_code_ph_reg_p <= rem_code_ph_reg_n;
bit_vld_cc_p <= bit_vld_cc_n;
load_sigs_cc_p <= load_sigs_cc_n;
intr_pending_p <= intr_pending_n;
timeout_reg_p <= timeout_reg_n;
nav_solve_timer_reg_p <= nav_solve_timer_reg_n;
nav_solve_phase_seed_reg_p <= nav_solve_phase_seed_reg_n;
timeout_counter_p <= timeout_counter_n;
start_trck_ctl_p <= start_trck_ctl_n;
stop_trck_ctl_p <= stop_trck_ctl_n;
trck_timeout_flag_p <= trck_timeout_flag_n;
trck_nav_bit_rcv_flag_p <= trck_nav_bit_rcv_flag_n;
trck_nav_solve_flag_p <= trck_nav_solve_flag_n;
trck_measurement_flag_p <= trck_measurement_flag_n;
foreach(nav_bit_read_reg_p[i])
nav_bit_read_reg_p[i] <= nav_bit_read_reg_n[i];
end
end : intr_sig_reg_seq
// tracking pulse counter
always_comb begin : start_stop_pulse_comb
start_trck_ctl_n = '0;
stop_trck_ctl_n = '0;
if(start_trck) begin
start_trck_ctl_n = (start_trck_ctl_p + 1);
end
if(start_trck_ctl_p != 0) begin
start_trck_ctl_n = (start_trck_ctl_p + 1);
end
if(stop_trck || timeout_stop) begin // signals that cause to stop trck
stop_trck_ctl_n = (stop_trck_ctl_p + 1);
end
if(stop_trck_ctl_p != 0) begin
stop_trck_ctl_n = (stop_trck_ctl_p + 1);
end
end : start_stop_pulse_comb
// tracking auto stop tracking.
always_comb begin : tracking_auto_stop_ctr_comb
timeout_counter_n = '0;
timeout_stop = '0;
if(control_reg_p[TRCK_STOP_ON_UNLOCK_EN_POS] && busy_syned && !lock_syned) begin
timeout_counter_n = (timeout_counter_p + 1);
if(timeout_counter_p == (timeout_reg_p - 1)) begin
timeout_counter_n = '0;
timeout_stop = '1;
end
end
end : tracking_auto_stop_ctr_comb
// next state comb. logic (might be obsolated.) TODO remove if unused.
always_comb begin :apb_bus_comb_logic
apb_bus_ns = apb_bus_ps;
//trck_state_n = trck_state_p;
case(apb_bus_ps)
APB_STATE_IDLE : if(PSEL) apb_bus_ns = APB_STATE_SEL;
APB_STATE_SEL : apb_bus_ns = APB_STATE_WR;
APB_STATE_WR : apb_bus_ns = APB_STATE_IDLE;
endcase
//case(trck_state_p)
// TRCK_STATE_IDLE: if(start_trck) trck_state_n = TRCK_STATE_UNLOCK; // only after reset
// TRCK_STATE_UNLOCK:
// begin
// if(stop_trck)
// trck_state_n = TRCK_STATE_IDLE;
// if(lock_syned)
// trck_state_n = TRCK_STATE_LOCK;
// end
// TRCK_STATE_LOCK:
// begin
// if(stop_trck)
// trck_state_n = TRCK_STATE_IDLE;
// if(!lock_syned)
// trck_state_n = TRCK_STATE_UNLOCK;
// end
//endcase
end : apb_bus_comb_logic
//always_comb begin : nav_bit_shift_comb_logic
// abs_sample_reg_n = abs_sample_reg_p;
// shift_reg_n = shift_reg_p;
// if(bit_vld_cc_p[0] & !bit_vld_cc_p[1]) begin
// abs_sample_reg_n = abs_sample;
// shift_reg_n = {shift_reg_p[308 : 0], nav_bit_syned};
// end
//end : nav_bit_shift_comb_logic
always_comb begin : nav_bit_shift_comb_logic
abs_sample_reg_n = abs_sample_reg_p;
rem_code_ph_reg_n = rem_code_ph_reg_p;
shift_reg_n = shift_reg_p;
if(bit_vld_cc_p[0] & !bit_vld_cc_p[1]) begin
shift_reg_n = {shift_reg_p[308 : 0], nav_bit_syned};
end
if((load_sigs) || (nav_solve_timer_reached)) begin
abs_sample_reg_n = abs_sample_syned;
rem_code_ph_reg_n = rem_code_ph_syned;
//abs_sample_reg_n = abs_sample;
end
end : nav_bit_shift_comb_logic
// preamble search comb. logic
always_comb begin : preamble_search_comb
preamble_ok = 1'b0;
if(lock_syned) begin
if(shift_reg_p[307-:8] == trck_pkg::PREAMBLE && (shift_reg_p[7 : 0] == ~(trck_pkg::PREAMBLE))) begin
preamble_ok = 1'b1;
end
else if(shift_reg_p[307-:8] == ~(trck_pkg::PREAMBLE) && (shift_reg_p[7 : 0] == trck_pkg::PREAMBLE))
preamble_ok = 1'b1;
else if(shift_reg_p[307-:8] == trck_pkg::PREAMBLE && (shift_reg_p[7 : 0] == trck_pkg::PREAMBLE))
preamble_ok = 1'b1;
else if(shift_reg_p[307-:8] == ~(trck_pkg::PREAMBLE) && (shift_reg_p[7 : 0] == ~(trck_pkg::PREAMBLE)))
preamble_ok = 1'b1;
end
end : preamble_search_comb
logic [301 : 0] shift_reg_resultant;
logic [16 : 0] how_z_count;
assign shift_reg_resultant[301-:2] = shift_reg_p[309-:2]; // always assign last 2 bit from previous subframe
/* Normalized HOW word is nav word 2 at [269:240]; bits [29:13] are
* the 17-bit Z-count used to align NAV solve timer phase globally. */
assign how_z_count = shift_reg_resultant[269-:17];
generate
genvar j;
for(j = 0 ; j < 10 ; j = j + 1) begin : inv_words
assign shift_reg_resultant[(299 - (j * 30))-: 24] = shift_reg_p[(308 - (j * 30))] ? ~shift_reg_p[(307 - (j * 30)) -:24] : shift_reg_p[(307 - (j * 30))-:24];
assign shift_reg_resultant[(275 - (j * 30))-: 6] = shift_reg_p[(283 - (j * 30))-:6];
end : inv_words
endgenerate
// parity CALCULATION
logic[9 : 0] D25;
logic[9 : 0] D26;
logic[9 : 0] D27;
logic[9 : 0] D28;
logic[9 : 0] D29;
logic[9 : 0] D30;
logic[9 : 0] pcw;
generate
genvar i;
for(i = 0 ; i < 10 ; i = i + 1) begin : parity_calc
assign D25[i] = shift_reg_resultant[301 - (30 * i)] ^ shift_reg_resultant[299 - (30 * i)] ^ shift_reg_resultant[298 -(30 * i)] ^ shift_reg_resultant[297 - (30 * i)] ^ shift_reg_resultant[295 -(30 * i)] ^ shift_reg_resultant[294 -(30 * i)] ^ shift_reg_resultant[290 -(30 * i)] ^ shift_reg_resultant[289 -(30 * i)] ^ shift_reg_resultant[288 -(30 * i)] ^ shift_reg_resultant[287 -(30 * i)] ^ shift_reg_resultant[286 -(30 * i)] ^ shift_reg_resultant[283 -(30 * i)] ^ shift_reg_resultant[282 -(30 * i)] ^ shift_reg_resultant[280 -(30 * i)] ^ shift_reg_resultant[277 -(30 * i)];
assign D26[i] = shift_reg_resultant[300 - (30 * i)] ^ shift_reg_resultant[298 - (30 * i)] ^ shift_reg_resultant[297 -(30 * i)] ^ shift_reg_resultant[296 - (30 * i)] ^ shift_reg_resultant[294 -(30 * i)] ^ shift_reg_resultant[293 -(30 * i)] ^ shift_reg_resultant[289 -(30 * i)] ^ shift_reg_resultant[288 -(30 * i)] ^ shift_reg_resultant[287 -(30 * i)] ^ shift_reg_resultant[286 -(30 * i)] ^ shift_reg_resultant[285 -(30 * i)] ^ shift_reg_resultant[282 -(30 * i)] ^ shift_reg_resultant[281 -(30 * i)] ^ shift_reg_resultant[279 -(30 * i)] ^ shift_reg_resultant[276 -(30 * i)];
assign D27[i] = shift_reg_resultant[301 - (30 * i)] ^ shift_reg_resultant[299 - (30 * i)] ^ shift_reg_resultant[297 -(30 * i)] ^ shift_reg_resultant[296 - (30 * i)] ^ shift_reg_resultant[295 -(30 * i)] ^ shift_reg_resultant[293 -(30 * i)] ^ shift_reg_resultant[292 -(30 * i)] ^ shift_reg_resultant[288 -(30 * i)] ^ shift_reg_resultant[287 -(30 * i)] ^ shift_reg_resultant[286 -(30 * i)] ^ shift_reg_resultant[285 -(30 * i)] ^ shift_reg_resultant[284 -(30 * i)] ^ shift_reg_resultant[281 -(30 * i)] ^ shift_reg_resultant[280 -(30 * i)] ^ shift_reg_resultant[278 -(30 * i)];
assign D28[i] = shift_reg_resultant[300 - (30 * i)] ^ shift_reg_resultant[298 - (30 * i)] ^ shift_reg_resultant[296 -(30 * i)] ^ shift_reg_resultant[295 - (30 * i)] ^ shift_reg_resultant[294 -(30 * i)] ^ shift_reg_resultant[292 -(30 * i)] ^ shift_reg_resultant[291 -(30 * i)] ^ shift_reg_resultant[287 -(30 * i)] ^ shift_reg_resultant[286 -(30 * i)] ^ shift_reg_resultant[285 -(30 * i)] ^ shift_reg_resultant[284 -(30 * i)] ^ shift_reg_resultant[283 -(30 * i)] ^ shift_reg_resultant[280 -(30 * i)] ^ shift_reg_resultant[279 -(30 * i)] ^ shift_reg_resultant[277 -(30 * i)];
assign D29[i] = shift_reg_resultant[300 - (30 * i)] ^ shift_reg_resultant[299 - (30 * i)] ^ shift_reg_resultant[297 -(30 * i)] ^ shift_reg_resultant[295 - (30 * i)] ^ shift_reg_resultant[294 -(30 * i)] ^ shift_reg_resultant[293 -(30 * i)] ^ shift_reg_resultant[291 -(30 * i)] ^ shift_reg_resultant[290 -(30 * i)] ^ shift_reg_resultant[286 -(30 * i)] ^ shift_reg_resultant[285 -(30 * i)] ^ shift_reg_resultant[284 -(30 * i)] ^ shift_reg_resultant[283 -(30 * i)] ^ shift_reg_resultant[282 -(30 * i)] ^ shift_reg_resultant[279 -(30 * i)] ^ shift_reg_resultant[278 -(30 * i)] ^ shift_reg_resultant[276 - (30 * i)];
assign D30[i] = shift_reg_resultant[301 - (30 * i)] ^ shift_reg_resultant[297 - (30 * i)] ^ shift_reg_resultant[295 -(30 * i)] ^ shift_reg_resultant[294 - (30 * i)] ^ shift_reg_resultant[292 -(30 * i)] ^ shift_reg_resultant[291 -(30 * i)] ^ shift_reg_resultant[290 -(30 * i)] ^ shift_reg_resultant[289 -(30 * i)] ^ shift_reg_resultant[287 -(30 * i)] ^ shift_reg_resultant[285 -(30 * i)] ^ shift_reg_resultant[281 -(30 * i)] ^ shift_reg_resultant[278 -(30 * i)] ^ shift_reg_resultant[277 -(30 * i)] ^ shift_reg_resultant[276 -(30 * i)];
assign pcw[i] = ({D25[i], D26[i], D27[i], D28[i], D29[i], D30[i]} == shift_reg_resultant[(275 - (i * 30)):(270 - (i * 30))]) ? 1 : 0;
end : parity_calc
endgenerate
assign load_sigs = ((bit_vld_cc_p[0] && !bit_vld_cc_p[1]) && (&pcw) && (preamble_ok)) ? '1 : '0;
// TODO: intr generation logic will be revised. handle all interrupts individually.
//assign gps_frame_ready = ((control_reg_p[TRCK_INTRPT_ENABLE_POS] && (!load_sigs_cc_p[1] & load_sigs_cc_p[0])) || (control_reg_p[TRCK_INTRPT_ENABLE_POS] && control_reg_p[TRCK_STOP_ON_UNLOCK_POS] && (timeout_counter_p == (timeout_reg_p - 1)))) ? '1 : '0; // 1 clock cycle delay after internal register update.
// Please notice that all if condition signals are 1 cc pulse based on SoC clock. (PCLK)
always_comb begin : intr_gen_comb_logic
gps_frame_ready = '0;
if(control_reg_p[TRCK_INTRPT_ENABLE_POS]) begin // if generic interrupt is enabled.
// intr due to nav bits ready.
if((control_reg_p[TRCK_NAV_BITS_INTR_ENABLE_POS]) && (!load_sigs_cc_p[1] & load_sigs_cc_p[0])) begin
gps_frame_ready = '1;
end
// intr due to nav stop on unlock.
if((control_reg_p[TRCK_STOP_ON_UNLOCK_INTR_EN_POS]) && (timeout_counter_p == (timeout_reg_p - 1))) begin
gps_frame_ready = '1;
end
// intr due to nav solve counter value reach.
if((control_reg_p[TRCK_NAV_SOLVE_INTR_EN_POS]) & (nav_solve_timer_reached)) begin
gps_frame_ready = '1;
end
// intr due to a coherent 20 ms Doppler/CN0 measurement.
if(control_reg_p[TRCK_MEASUREMENT_INTR_EN_POS] && measurement_interrupt_pulse) begin
gps_frame_ready = '1;
end
end
end
always_comb begin : nav_bit_load_and_intr_flag_comb
// internal interrupt flags.
intr_pending_n = intr_pending_p;
trck_timeout_flag_n = trck_timeout_flag_p; // (all internal clear signals are tied to generic int_clear signal)
trck_nav_bit_rcv_flag_n = trck_nav_bit_rcv_flag_p;
trck_nav_solve_flag_n = trck_nav_solve_flag_p;
trck_measurement_flag_n = trck_measurement_flag_p;
foreach(nav_bit_read_reg_n[i])
nav_bit_read_reg_n[i] = nav_bit_read_reg_p[i];
// load navigation bit registers.
if(load_sigs) begin
foreach(nav_bit_read_reg_n[i])
nav_bit_read_reg_n[i] = shift_reg_resultant[(((i + 1) * 30) - 1)-:30];
if(control_reg_p[TRCK_NAV_BITS_FLAG_ENABLE_POS]) trck_nav_bit_rcv_flag_n = '1;
if(control_reg_p[TRCK_INTRPT_ENABLE_POS] && control_reg_p[TRCK_NAV_BITS_INTR_ENABLE_POS]) intr_pending_n = '1;
end
// tracking stop generic interrupt pending flag set.
if(timeout_counter_p == (timeout_reg_p - 1)) begin
if(control_reg_p[TRCK_STOP_ON_UNLOCK_FLAG_EN_POS]) trck_timeout_flag_n = '1;
if(control_reg_p[TRCK_INTRPT_ENABLE_POS] && control_reg_p[TRCK_STOP_ON_UNLOCK_INTR_EN_POS]) intr_pending_n = '1;
end
if(nav_solve_timer_reached) begin
if(control_reg_p[TRCK_NAV_SOLVE_FLAG_EN_POS]) trck_nav_solve_flag_n = '1;
if(control_reg_p[TRCK_INTRPT_ENABLE_POS] && control_reg_p[TRCK_NAV_SOLVE_INTR_EN_POS]) intr_pending_n = '1;
end
if(measurement_capture) begin
if(control_reg_p[TRCK_MEASUREMENT_FLAG_EN_POS])
trck_measurement_flag_n = '1;
if(control_reg_p[TRCK_INTRPT_ENABLE_POS] &&
control_reg_p[TRCK_MEASUREMENT_INTR_EN_POS])
intr_pending_n = '1;
end
// generic clear all interrupt pending flag and other flags.
if(intr_clear) begin // all internal flag clear
intr_pending_n = '0;
trck_timeout_flag_n = '0;
trck_nav_bit_rcv_flag_n = '0;
trck_nav_solve_flag_n = '0;
trck_measurement_flag_n = '0;
end
end : nav_bit_load_and_intr_flag_comb
// navitation solution period timer
nav_solve_timer i_nav_solve_timer(
.clk(PCLK), // clock.
.resetn(PRESETN), // active low reset.
.enable(control_reg_p[TRCK_NAV_SOLVE_ENABLE_POS]), // timer enable bit.
.counter_max_val(nav_solve_timer_reg_p), // timer generates interrupt when internal timer reaches this value.
.bit_valid(bit_valid_syned), // timer counts bit valid signals.
.subframe_ready(load_sigs), // signal that asserts 1 clock cycle after a subframe bit reached ( in essence, 300 bit + 8 preamble bit !!!)
.subframe_count(how_z_count), // HOW Z-count of this globally identified subframe boundary.
.trck_busy(busy_syned), // stop counting when tracking is unlocked or do not start to count anyways.
.phase_seed_arm(control_reg_p[TRCK_NAV_SOLVE_SEED_ARM_POS]), // firmware warm-start phase estimate is pending.
.phase_seed_value(nav_solve_phase_seed_reg_p), // navigation-bit phase, already reduced modulo counter_max_val.
// output from module.
.phase_seed_consumed(nav_solve_phase_seed_consumed), // timer answered the seed; clears the arm bit.
.nav_solve_provisional(nav_solve_provisional), // epochs are running on an unconfirmed seed.
.nav_solve_timer_reached(nav_solve_timer_reached), // timer internal count is equal to predefined count value. (status flag) asserted 1 clock cycle. INTERRUPT SIGNAL TO CPU FROM TIMER TODO: will be integrated to main interrupt generation mechanishm.
.load_abs_sample(nav_solve_timer_load_abs_sample_signal) // when counter reaches to predefined value, trigger 1 clock cycle wide abs. sample load signal.
);
// reg r & w com. logic
always_comb begin : apb_register_write_read_comb
PRDATA = '0;
PSLVERR = '0;
start_trck = '0;
stop_trck = '0;
intr_clear = '0;
//clear_timeout_stop_sig = '0;
//trck_reset = '0;
code_phase_reg_n = code_phase_reg_p;
doppler_reg_n = doppler_reg_p;
prn_no_reg_n = prn_no_reg_p;
control_reg_n = control_reg_p;
timeout_reg_n = timeout_reg_p;
nav_solve_timer_reg_n = nav_solve_timer_reg_p;
nav_solve_phase_seed_reg_n = nav_solve_phase_seed_reg_p;
if(apb_bus_ps == APB_STATE_SEL) begin
if(PWRITE) begin // write to register
case(PADDR)
(LOW_ADDRESS + CONTROL_REG_OFFSET):
begin
if(PWDATA[TRCK_START_POS]) start_trck = '1;
if(PWDATA[TRCK_STOP_POS]) stop_trck = '1;
//if(PWDATA[TRCK_RESET_POS]) trck_reset = '1;
if(PWDATA[TRCK_INTRPT_ENABLE_POS]) control_reg_n[TRCK_INTRPT_ENABLE_POS] = 1'b1;
if(!PWDATA[TRCK_INTRPT_ENABLE_POS]) control_reg_n[TRCK_INTRPT_ENABLE_POS] = 1'b0;
if(PWDATA[TRCK_INTRPT_CLEAR_POS]) intr_clear = '1;
if(PWDATA[TRCK_STOP_ON_UNLOCK_EN_POS]) control_reg_n[TRCK_STOP_ON_UNLOCK_EN_POS] = 1'b1;
if(!PWDATA[TRCK_STOP_ON_UNLOCK_EN_POS]) control_reg_n[TRCK_STOP_ON_UNLOCK_EN_POS] = 1'b0;
if(PWDATA[TRCK_STOP_ON_UNLOCK_INTR_EN_POS]) control_reg_n[TRCK_STOP_ON_UNLOCK_INTR_EN_POS] = 1'b1;
if(!PWDATA[TRCK_STOP_ON_UNLOCK_INTR_EN_POS]) control_reg_n[TRCK_STOP_ON_UNLOCK_INTR_EN_POS] = 1'b0;
if(PWDATA[TRCK_NAV_SOLVE_ENABLE_POS]) control_reg_n[TRCK_NAV_SOLVE_ENABLE_POS] = 1'b1;
if(!PWDATA[TRCK_NAV_SOLVE_ENABLE_POS]) control_reg_n[TRCK_NAV_SOLVE_ENABLE_POS] = 1'b0;
if(PWDATA[TRCK_NAV_SOLVE_INTR_EN_POS]) control_reg_n[TRCK_NAV_SOLVE_INTR_EN_POS] = 1'b1;
if(!PWDATA[TRCK_NAV_SOLVE_INTR_EN_POS]) control_reg_n[TRCK_NAV_SOLVE_INTR_EN_POS] = 1'b0;
if(PWDATA[TRCK_NAV_BITS_INTR_ENABLE_POS]) control_reg_n[TRCK_NAV_BITS_INTR_ENABLE_POS] = 1'b1;
if(!PWDATA[TRCK_NAV_BITS_INTR_ENABLE_POS]) control_reg_n[TRCK_NAV_BITS_INTR_ENABLE_POS] = 1'b0;
if(PWDATA[TRCK_NAV_BITS_FLAG_ENABLE_POS]) control_reg_n[TRCK_NAV_BITS_FLAG_ENABLE_POS] = 1'b1;
if(!PWDATA[TRCK_NAV_BITS_FLAG_ENABLE_POS]) control_reg_n[TRCK_NAV_BITS_FLAG_ENABLE_POS] = 1'b0;
if(PWDATA[TRCK_STOP_ON_UNLOCK_FLAG_EN_POS]) control_reg_n[TRCK_STOP_ON_UNLOCK_FLAG_EN_POS] = 1'b1;
if(!PWDATA[TRCK_STOP_ON_UNLOCK_FLAG_EN_POS]) control_reg_n[TRCK_STOP_ON_UNLOCK_FLAG_EN_POS] = 1'b0;
if(PWDATA[TRCK_NAV_SOLVE_FLAG_EN_POS]) control_reg_n[TRCK_NAV_SOLVE_FLAG_EN_POS] = 1'b1;
if(!PWDATA[TRCK_NAV_SOLVE_FLAG_EN_POS]) control_reg_n[TRCK_NAV_SOLVE_FLAG_EN_POS] = 1'b0;
if(PWDATA[TRCK_MEASUREMENT_INTR_EN_POS]) control_reg_n[TRCK_MEASUREMENT_INTR_EN_POS] = 1'b1;
if(!PWDATA[TRCK_MEASUREMENT_INTR_EN_POS]) control_reg_n[TRCK_MEASUREMENT_INTR_EN_POS] = 1'b0;
if(PWDATA[TRCK_MEASUREMENT_FLAG_EN_POS]) control_reg_n[TRCK_MEASUREMENT_FLAG_EN_POS] = 1'b1;
if(!PWDATA[TRCK_MEASUREMENT_FLAG_EN_POS]) control_reg_n[TRCK_MEASUREMENT_FLAG_EN_POS] = 1'b0;
if(PWDATA[TRCK_NAV_SOLVE_SEED_ARM_POS]) control_reg_n[TRCK_NAV_SOLVE_SEED_ARM_POS] = 1'b1;
if(!PWDATA[TRCK_NAV_SOLVE_SEED_ARM_POS]) control_reg_n[TRCK_NAV_SOLVE_SEED_ARM_POS] = 1'b0;
end
(LOW_ADDRESS + PRN_NUMBER_REG_OFFSET):
begin
prn_no_reg_n = PWDATA;
end
(LOW_ADDRESS + CODE_PHASE_REG_OFFSET):
begin
code_phase_reg_n = PWDATA;
end
(LOW_ADDRESS + DOPPLER_REG_OFFSET):
begin
doppler_reg_n = PWDATA;
end
(LOW_ADDRESS + TRCK_TIMEOUT_REG_OFFSET):
begin
timeout_reg_n = PWDATA;
end
(LOW_ADDRESS + NAV_SOLVE_TIMER_REG_OFFSET):
begin
nav_solve_timer_reg_n = PWDATA;
end
(LOW_ADDRESS + NAV_SOLVE_PHASE_SEED_REG_OFFSET):
begin
nav_solve_phase_seed_reg_n = PWDATA;
end
default:
begin
PSLVERR = '1;
end
endcase
end
else if(!PWRITE) begin
case(PADDR)
(LOW_ADDRESS + CONTROL_REG_OFFSET):
begin
PRDATA = 32'(
(control_reg_p[TRCK_INTRPT_ENABLE_POS] << trck_pkg::TRCK_INTRPT_ENABLE_POS) |
(control_reg_p[TRCK_NAV_BITS_INTR_ENABLE_POS] << trck_pkg::TRCK_NAV_BITS_INTR_ENABLE_POS) |
(control_reg_p[TRCK_STOP_ON_UNLOCK_EN_POS] << trck_pkg::TRCK_STOP_ON_UNLOCK_EN_POS) |
(control_reg_p[TRCK_STOP_ON_UNLOCK_INTR_EN_POS] << trck_pkg::TRCK_STOP_ON_UNLOCK_INTR_EN_POS) |
(control_reg_p[TRCK_NAV_SOLVE_ENABLE_POS] << trck_pkg::TRCK_NAV_SOLVE_ENABLE_POS) |
(control_reg_p[TRCK_NAV_SOLVE_INTR_EN_POS] << trck_pkg::TRCK_NAV_SOLVE_INTR_EN_POS) |
(control_reg_p[TRCK_NAV_BITS_FLAG_ENABLE_POS] << trck_pkg::TRCK_NAV_BITS_FLAG_ENABLE_POS) |
(control_reg_p[TRCK_STOP_ON_UNLOCK_FLAG_EN_POS] << trck_pkg::TRCK_STOP_ON_UNLOCK_FLAG_EN_POS) |
(control_reg_p[TRCK_NAV_SOLVE_FLAG_EN_POS] << trck_pkg::TRCK_NAV_SOLVE_FLAG_EN_POS) |
(control_reg_p[TRCK_MEASUREMENT_INTR_EN_POS] << trck_pkg::TRCK_MEASUREMENT_INTR_EN_POS) |
(control_reg_p[TRCK_MEASUREMENT_FLAG_EN_POS] << trck_pkg::TRCK_MEASUREMENT_FLAG_EN_POS) |
(control_reg_p[TRCK_NAV_SOLVE_SEED_ARM_POS] << trck_pkg::TRCK_NAV_SOLVE_SEED_ARM_POS)
);
end
(LOW_ADDRESS + STATUS_REG_OFFSET):
begin
PRDATA = 32'(
(busy_syned << TRCK_BUSY_POS) |
(lock_syned << TRCK_LOCKED_POS) |
(0 << TRCK_FIFO_OV_POS) | // fifo overflow is not considered for now.
(intr_pending_p << TRCK_INTR_PEND_POS) |
(trck_timeout_flag_p << TRCK_UNLOCK_FLAG_POS) |
(trck_nav_bit_rcv_flag_p << TRCK_NAV_BITS_RCV_FLAG_POS) |
(trck_nav_solve_flag_p << TRCK_NAV_SOLVE_FLAG_POS) |
(trck_measurement_flag_p << TRCK_MEASUREMENT_FLAG_POS) |
(nav_solve_provisional << TRCK_NAV_SOLVE_PROVISIONAL_POS)
);
end
(LOW_ADDRESS + PRN_NUMBER_REG_OFFSET):
begin
PRDATA = prn_no_reg_p;
end
(LOW_ADDRESS + CODE_PHASE_REG_OFFSET):
begin
PRDATA = code_phase_reg_p;
end
(LOW_ADDRESS + ABS_SAMPLE_REG_OFFSET):
begin
PRDATA = abs_sample_reg_p;
end
(LOW_ADDRESS + DOPPLER_REG_OFFSET):
begin
PRDATA = doppler_reg_p;
end
(LOW_ADDRESS + NAV_DATA_0_REG_OFFSET):
begin
PRDATA = {2'b00, nav_bit_read_reg_p[0]};
end
(LOW_ADDRESS + NAV_DATA_1_REG_OFFSET):
begin
PRDATA = {2'b00, nav_bit_read_reg_p[1]};
end
(LOW_ADDRESS + NAV_DATA_2_REG_OFFSET):
begin
PRDATA = {2'b00, nav_bit_read_reg_p[2]};
end
(LOW_ADDRESS + NAV_DATA_3_REG_OFFSET):
begin
PRDATA = {2'b00, nav_bit_read_reg_p[3]};
end
(LOW_ADDRESS + NAV_DATA_4_REG_OFFSET):
begin
PRDATA = {2'b00, nav_bit_read_reg_p[4]};
end
(LOW_ADDRESS + NAV_DATA_5_REG_OFFSET):
begin
PRDATA = {2'b00, nav_bit_read_reg_p[5]};
end
(LOW_ADDRESS + NAV_DATA_6_REG_OFFSET):
begin
PRDATA = {2'b00, nav_bit_read_reg_p[6]};
end
(LOW_ADDRESS + NAV_DATA_7_REG_OFFSET):
begin
PRDATA = {2'b00, nav_bit_read_reg_p[7]};
end
(LOW_ADDRESS + NAV_DATA_8_REG_OFFSET):
begin
PRDATA = {2'b00, nav_bit_read_reg_p[8]};
end
(LOW_ADDRESS + NAV_DATA_9_REG_OFFSET):
begin
PRDATA = {2'b00, nav_bit_read_reg_p[9]};
end
(LOW_ADDRESS + TRCK_TIMEOUT_REG_OFFSET):
begin
PRDATA = timeout_reg_p;
end
(LOW_ADDRESS + NAV_SOLVE_TIMER_REG_OFFSET):
begin
PRDATA = nav_solve_timer_reg_p;
end
(LOW_ADDRESS + NAV_SOLVE_PHASE_SEED_REG_OFFSET):
begin
PRDATA = nav_solve_phase_seed_reg_p;
end
(LOW_ADDRESS + REM_CODE_PH_REG_OFFSET):
begin
//PRDATA = rem_code_ph_reg_p;
PRDATA = {{(32-REM_CODE_PH_I_WL){1'b0}}, rem_code_ph_reg_p};
end
(LOW_ADDRESS + MEASUREMENT_META_REG_OFFSET):
begin
PRDATA = {
8'h01,
11'b0,
measurement_cn0_sample_count_reg,
5'b0,
measurement_lock_reg,
measurement_bit_reg,
measurement_data_valid_reg
};
end
(LOW_ADDRESS + MEASUREMENT_SEQUENCE_REG_OFFSET):
begin
PRDATA = {16'b0, measurement_sequence_reg};
end
(LOW_ADDRESS + MEASUREMENT_CARRIER_REG_OFFSET):
begin
PRDATA = {{(32-MEAS_CARRIER_WL){
measurement_carrier_freq_q7_reg[MEAS_CARRIER_WL-1]}},
measurement_carrier_freq_q7_reg};
end
(LOW_ADDRESS + MEASUREMENT_ABS_SAMPLE_REG_OFFSET):
begin
PRDATA = measurement_abs_sample_reg;
end
(LOW_ADDRESS + MEASUREMENT_REM_CODE_REG_OFFSET):
begin
PRDATA = {{(32-REM_CODE_PH_I_WL){1'b0}},
measurement_rem_code_ph_reg};
end
(LOW_ADDRESS + MEASUREMENT_SUM_I_REG_OFFSET):
begin
PRDATA = {{(32-MEAS_SUM_WL){
measurement_cn0_sum_i_reg[MEAS_SUM_WL-1]}},
measurement_cn0_sum_i_reg};
end
(LOW_ADDRESS + MEASUREMENT_SUM_Q_REG_OFFSET):
begin
PRDATA = {{(32-MEAS_SUM_WL){
measurement_cn0_sum_q_reg[MEAS_SUM_WL-1]}},
measurement_cn0_sum_q_reg};
end
(LOW_ADDRESS + MEASUREMENT_WBP_LO_REG_OFFSET):
begin
PRDATA = measurement_cn0_wbp_reg[31:0];
end
(LOW_ADDRESS + MEASUREMENT_WBP_HI_REG_OFFSET):
begin
PRDATA = {{(64-MEAS_WBP_WL){1'b0}},
measurement_cn0_wbp_reg[MEAS_WBP_WL-1:32]};
end
endcase
end
end
/* The timer answers an armed seed in one cycle and in every state, so
* clearing the arm bit here cannot race an APB write: firmware can only
* observe the bit set on the cycle after its own write, and consumption
* requires the bit to already be registered. Applying the clear after
* the decode keeps it authoritative. */
if(nav_solve_phase_seed_consumed) begin
control_reg_n[TRCK_NAV_SOLVE_SEED_ARM_POS] = 1'b0;
end
end : apb_register_write_read_comb
endmodule