2 * BCM43xx device microcode
3 * For Wireless-Core Revision 5
5 * Copyright (C) 2009 University of Brescia
7 * Copyright (C) 2008, 2009 Lorenzo Nava <navalorenx@gmail.com>
8 * Francesco Gringoli <francesco.gringoli@ing.unibs.it>
9 * Copyright (C) 2008 Michael Buesch <mb@bu3sch.de>
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * version 2, as published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
21 // a few notes for beginners
23 // 1) this is very important: when removing bytes or copying from FIFO to somewhere
24 // bytes are copied on 32bit boundaries.
25 // So you cannot remove or copy 39 byte, the effect is to remove or copy 40 bytes!
27 // 2) when removing and copying bytes from FIFO to SHM you should carefully verify that
28 // the number of bytes left after the copy is greater than 4. Otherwise the system becomes
31 // 3) expiration of ack timeout enables COND_TX_PMQ so that handler tx_contention_params_update
34 // 4) remember to read clock info from SPR_TSF_WORDn always starting from the least significant bits
35 // So if you want to read SPR_TSF_WORD1 and SPR_TSF_WORD0 READ first SPR_TSF_WORD0 and then SPR_TSF_WORD1
37 // when a frame that needs to be acknowledged is received by rx_[stuff], the NEED_RESPONSEFR bit is
38 // set in SPR_BRC. This will trigger the condition COND_NEED_RESPONSEFR
39 // that will be honoured by tx_frame_now that will send and ACK frame.
41 // Attention: condition COND_FRAME_NEED_ACK instead evaluates true when
42 // the current frame that is being transmitted needs an ack: in this case
43 // we will transmit the frame and verify that it will be received within
44 // a timeout interval. The need for transmit a frame and verify that
45 // an ack will be received is determined inside the tx_frame_now function
46 // in the find_tx_frame_type section: if needed the section compute_expected_response
47 // will be executed so that the FRAME_NEED_ACK bit will be set in SPR_BRC.
50 // explanation for SPR_RXE_FIFOCTL
51 // the fifo queue is filled with an rxheader copied from shm, the frame received
52 // from air and the fcs. push_frame_into_fifo performs this operation
54 // air-buffer for incoming bytes from air
57 // || rx-buffer => FIFO to host =====> dma => host
60 // copy in SHM SHM with header
62 // bit 0x0800: it seems to be always set
63 // bit 0x0020: if set will align the frame in the rx-buffer on a 4 byte boundary after the header copied from shm
64 // bit 0x0010: reset: when set the rx-buffer is flushed.
65 // bit 0x0004: when set the air-buffer is flushed. Probably also the rooms dedicated to decode the PLCP and
66 // that raise the COND_RX_PLCP are flushed. Flushing complete when it is automatically switched back
68 // It is read when plcp is decoded to be sure that flushing is not going.
69 // bit 0x0002: when set, the rx buffer is filled with bytes coming from the air-buffer
70 // copying those already present in the air-buffer
71 // bit 0x0001: when set advance the rx buffer to the queue copying also the header and the fcs
75 // explanation for SPR_RXE_0x1a, something related to the pair of air-buffer and rx-buffer
77 // bit 0x8000: rxe is in overflow
78 // bit 0x4000: after COND_RX_COMPLETE is true, transition from 0 to 1 signals that all bytes have been copied
79 // to the rx-buffer (?), if this is true, i'm not sure, the same does not apply to the copy in shm
80 // (to the area pointed by SPR_RXE_Copy_Offset and whose length is given by SPR_RXE_Copy_Length)
81 // bit 0x1000: ?? it seems that we should verify it is zero before handling rx_badplcp
82 // bit 0x0800: when set the handler rx_badplcp should delay
83 // bit 0x0080: ?? used to skip to set a bit in GLOBAL_FLAGS_REG2 when it is not zero in tx_timers_setup
95 #define TS_PSPOLL 0x029
96 #define TS_BEACON 0x020
97 #define TS_PROBE_REQ 0x010
98 #define TS_PROBE_RESP 0x014
99 #define TS_ASSOC_REQ 0x000
100 #define TS_REASSOC_REQ 0x008
101 #define TS_AUTH 0x02C
102 #define TS_ATIM 0x024
104 #define DEFAULT_MAX_CW 0x03FF
105 #define DEFAULT_MIN_CW 0x001F
106 #define DEFAULT_RETRY_LIMIT 0x0007
110 mov 0, SPR_GPIO_OUT; /* Disable any GPIO pin */
112 // ***********************************************************************************************
114 // PURPOSE: Initializes the device.
119 orx 0, 1, 0x001, SPR_PHY_HDR_Parameter, SPR_PHY_HDR_Parameter; /* SPR_PHY_HDR_Parameter = MAC_PHY_CLOCK_EN | (SPR_PHY_HDR_Parameter & ~MAC_PHY_CLOCK_EN) */
120 jnzx 0, 5, SPR_MAC_CMD, 0x000, do_not_erase_shm;
121 mov 0x07FF, SPR_BASE5;
122 erase_shm:; /* loop through every register */
124 sub SPR_BASE5, 0x001, SPR_BASE5;
125 jges SPR_BASE5, 0x000, erase_shm;
127 mov 0x1, [SHM_UCODESTAT];
129 call lr0, sel_phy_reg;
130 srx 7, 0, SPR_Ext_IHR_Data, 0x000, [SHM_PHYVER];
131 srx 3, 8, SPR_Ext_IHR_Data, 0x000, [SHM_PHYTYPE];
132 mov 0xFC00, [SHM_PRPHYCTL];
133 mov 0x2, SPR_PHY_HDR_Parameter;
134 mov 0, ANTENNA_DIVERSITY_CTR;
135 mov 0, GPHY_SYM_WAR_FLAG;
136 mov 0, GLOBAL_FLAGS_REG2;
137 mov 0xFF00, [SHM_ACKCTSPHYCTL];
138 mov 0x019A, [SHM_UCODEREV]
139 mov 0x0870, [SHM_UCODEPATCH]
140 mov 0xFFFF, [SHM_UCODEDATE]
141 mov 0x7C0A, [SHM_UCODETIME]
142 mov 0, [SHM_PCTLWDPOS]
143 mov SHM_RXHEADER, SPR_BASE1; // rx header starts @ 0xa10: buffer never accessed by b43 driver, can be moved!
144 mov SHM_TXHEADER, SPR_BASE0; // tx header starts @ 0x858: buffer never accessed by b43 driver, can be moved!
145 mov DEFAULT_RETRY_LIMIT, SHORT_RETRY_LIMIT;
146 mov DEFAULT_MAX_CW, MAX_CONTENTION_WIN;
147 mov DEFAULT_MIN_CW, MIN_CONTENTION_WIN;
148 or MIN_CONTENTION_WIN, 0x000, CUR_CONTENTION_WIN;
149 and SPR_TSF_Random, MIN_CONTENTION_WIN, SPR_IFS_BKOFFDELAY;
150 mov 0, SHORT_RETRIES;
153 jext COND_TRUE, mac_suspend;
155 // ***********************************************************************************************
156 // HANDLER: state_machine_start
157 // PURPOSE: Checks conditions looking for something to do. If there is no coming job firmware sleeps for a while or suspends device.
161 jnzx 0, 3, GLOBAL_FLAGS_REG3, 0x000, state_machine_start; /* This bit was set and reset in bg_noise_sample */
162 jnzx 0, 9, [SHM_HF_MI], 0x000, state_machine_start;
163 mov 0xFFFF, SPR_MAC_MAX_NAP; /* Sleep for a while.. */
166 state_machine_start:;
167 jnext EOI(COND_RADAR), no_radar_workaround;
168 jzx 0, 13, [SHM_HF_LO], 0x000, no_radar_workaround; /* if (!(shm_host_flags_1 & MHF_RADARWAR)) */
169 mov 0x00C8, GP_REG5; /* GP_REG5 = APHY_RADAR_THRESH1 */
170 or [SHM_RADAR], 0x000, GP_REG6; /* write [SHM_RADAR] into GP_REG5 */
171 call lr0, write_phy_reg;
172 no_radar_workaround:;
173 extcond_eoi_only(COND_PHY0);
174 extcond_eoi_only(COND_PHY1);
175 orx 1, 3, 0x000, GLOBAL_FLAGS_REG2, GLOBAL_FLAGS_REG2; /* clear bits 0x18 */
176 jzx 0, 3, SPR_IFS_STAT, 0x000, check_mac_status; /* if (!(SPR_IFS_STAT & 0x08)) */
177 orx 1, 1, 0x000, GLOBAL_FLAGS_REG2, GLOBAL_FLAGS_REG2; /* GLOBAL_FLAGS_REG2 & ~AFTERBURNER_TX|AFTERBURNER_RX */
178 or [SHM_GCLASSCTL], 0x000, GP_REG6;
179 call lr1, gphy_classify_control_with_arg; /* Classify control from SHM to PHY */
181 jnext COND_MACEN, mac_suspend_check; /* Check if we can sleep */
182 jext COND_TX_FLUSH, check_conditions;
185 jext EOI(COND_TX_NOW), tx_frame_now;
186 jext EOI(COND_TX_POWER), tx_infos_update;
187 jext EOI(COND_TX_UNDERFLOW), tx_underflow;
188 jext COND_TX_DONE, tx_end_wait_10us;
190 check_conditions_no_tx:;
191 jext COND_TX_PHYERR, tx_phy_error;
193 check_rx_conditions:;
194 jext EOI(COND_RX_WME8), tx_timers_setup;
195 jext EOI(COND_RX_PLCP), rx_plcp;
196 jext COND_RX_COMPLETE, rx_complete;
197 jext COND_TX_PMQ, tx_contention_params_update;
198 jext EOI(COND_RX_BADPLCP), rx_badplcp;
199 jnext COND_RX_FIFOFULL, rx_fifofull;
200 jnext COND_REC_IN_PROGRESS, rx_fifo_overflow; /* if (SPR_RXE_0x1a & 0x8000) */
202 jnzx 0, 15, SPR_RXE_0x1a, 0x000, rx_fifo_overflow;
203 extcond_eoi_only(COND_TX_NAV)
204 jnext COND_FRAME_NEED_ACK, channel_setup;
205 extcond_eoi_only(COND_PHY6);
206 jext COND_TRUE, state_machine_idle;
209 /* --------------------------------------------------- HANDLERS ---------------------------------------------------------- */
212 // ***********************************************************************************************
213 // HANDLER: channel_setup
214 // PURPOSE: If TBTT expired prepares a beacon transmission else checks FIFO queue for incoming frames.
215 // The condition on SPR_BRC involves
216 // COND_NEED_BEACON|COND_NEED_RESPONSEFR|COND_NEED_PROBE_RESP|COND_CONTENTION_PARAM_MODIFIED|COND_MORE_FRAGMENT
219 call lr2, bg_noise_sample; /* Create noise sample */
220 jext COND_MORE_FRAGMENT, skip_beacon_ops;
221 jext COND_TX_TBTTEXPIRE, prepare_beacon_tx;
223 extcond_eoi_only(COND_RX_ATIMWINEND);
224 jand SPR_TXE0_CTL, 0x001, check_tx_data_with_disabled_engine;/* if TX engine was enabled goto check_tx_data */
226 jext EOI(COND_PHY6), check_tx_data;
227 jnand 0x01F, SPR_BRC, state_machine_idle; /* No transmission pending */
228 srx 6, 3, SPR_IFS_0x0c, 0x000, GP_REG5;
229 jl GP_REG5, 0x004, state_machine_start; /* Something related to IFS time... Maybe we must wait again */
230 jext COND_TRUE, state_machine_idle;
232 // ***********************************************************************************************
233 // HANDLER: prepare_beacon_tx
234 // PURPOSE: Prepares parameters (PHY and MAC) needed for a correct Beacon transmission.
235 // The condition on SPR_BRC involves
236 // COND_NEED_BEACON|COND_NEED_RESPONSEFR|COND_FRAME_BURST|COND_REC_IN_PROGRESS|COND_FRAME_NEED_ACK
239 jnand 0x0E3, SPR_BRC, state_machine_idle;
240 jnext 0x3D, beacon_tx_param_update;
241 jext 0x3E, beacon_tx_param_update;
243 call lr0, inhibit_sleep_at_tbtt;
244 jext COND_TRUE, state_machine_idle;
245 beacon_tx_param_update:
246 jzx 1, 0, SPR_MAC_CMD, 0x000, inhibit_sleep_call; /* if !(SPR_MAC_Command & (MCMD_BCN0VLD|MCMD_BCN1VLD)), comment this line to send beacon anyway */
248 jext COND_TRUE, flush_and_stop_tx_engine;
249 return_flush_into_prepare_beacon_tx:
250 or [SHM_BEACPHYCTL], 0x000, SPR_TXE0_PHY_CTL; /* SPR_TXE0_PHY_CTL = shm_beacon_phy_ctl_word */
251 jzx 0, 7, [SHM_HF_MI], 0x000, bcn_no_hw_pwr_ctl;
252 mov SHM_BCNVAL1, SPR_BASE5;
253 jne [SHM_PHYTYPE], 0x000, bcn_no_hw_pwr_ctl;
254 mov SHM_BCNVAL0, SPR_BASE5;
256 call lr1, prep_phy_txctl_encoding_already_set;
257 mov TS_BEACON, TX_TYPE_SUBTYPE;
258 jext COND_CONTENTION_PARAM_MODIFIED, skip_parameter_preservation;
259 mov IRQLO_TBTT_INDI, SPR_MAC_IRQLO;
260 mov 0, SPR_TSF_Random;
261 jext 0x3D, skip_parameter_preservation;
262 orx 0, 6, 0x000, GLOBAL_FLAGS_REG3, GLOBAL_FLAGS_REG3; /* GFR3 = GFR3 & ~0x40 */
263 or SPR_IFS_BKOFFDELAY, 0x000, NEXT_IFS;
264 or CUR_CONTENTION_WIN, 0x000, NEXT_CONTENTION_WIN;
265 jzx 0, 0, SPR_TSF_0x0e, 0x000, skip_brc_update;
266 orx 0, 10, 0x000, SPR_BRC, SPR_BRC; /* SPR_BRC = SPR_BRC & ~TX_MULTICAST_FRAME */
267 orx 0, 2, 0x001, 0x000, SPR_MAC_CMD; /* Directed frame queue valid */
269 orx 14, 1, MIN_CONTENTION_WIN, 0x001, GP_REG5;
270 and SPR_TSF_Random, GP_REG5, SPR_IFS_BKOFFDELAY;
271 skip_parameter_preservation:
272 or [SHM_BTSFOFF], 0x000, SPR_TSF_0x3a;
273 orx 2, 0, 0x001, SPR_BRC, SPR_BRC; /* SPR_BRC = NEED_BEACON | (SPR_BRC & ~(NEED_BEACON | NEED_RESPONSEFR | NEED_PROBE_RESP)) */
274 orx 0, 3, 0x001, SPR_BRC, SPR_BRC; /* SPR_BRC = SPR_BRC | CONTENTION_PARAM_MODIFIED */
275 jext 0x3D, goto_set_ifs;
276 mov 0x4D95, SPR_TXE0_CTL;
277 jext COND_TRUE, state_machine_idle;
279 mov 0x4D95, NEXT_TXE0_CTL;
280 jext COND_TRUE, set_ifs;
282 // ***********************************************************************************************
283 // HANDLER: check_tx_data
284 // PURPOSE: Checks if there is a frame into the FIFO queue. If a frame is incoming from host loads BCM
285 // header into SHM and analyzes frame properties, then prepares PHY and MAC parameters for transmission.
286 // This code should be invoke with TX engine disabled.
287 // The condition on SPR_BRC involves
288 // COND_NEED_BEACON|COND_NEED_RESPONSEFR|COND_NEED_PROBE_RESP|COND_CONTENTION_PARAM_MODIFIED|COND_FRAME_BURST
290 check_tx_data_with_disabled_engine:;
291 extcond_eoi_only(COND_PHY6);
292 orx 1, 8, 0x003, 0x000, SPR_RXE_FIFOCTL0; /* SPR_Receive_FIFO_Control = 0x300 */
293 jnand 0x02F, SPR_BRC, state_machine_idle; /* if (0x2f & SPR_BRC) goto state_machine_idle */
294 jext COND_TX_NOW, state_machine_start;
295 jnext 0x3E, ready_for_header_copy;
296 goon_with_frame_analysis:;
297 jnext COND_TX_MULTICAST_FRAME, ready_for_header_copy;
298 jnzx 0, 4, [SHM_HF_MI], 0x000, state_machine_start;
299 jne [SHM_MCASTCOOKIE], 0xFFFF, state_machine_start;
300 jext 0x3D, skip_slow_clock_control; /* check for slow clock control */
301 jzx 0, 2, SPR_MAC_CMD, 0x000, slow_clock_control;
302 skip_slow_clock_control:;
303 orx 0, 10, 0x000, SPR_BRC, SPR_BRC; /* SPR_BRC = SPR_BRC & ~TX_MULTICAST_FRAME */
304 ready_for_header_copy:;
305 jzx 0, 2, SPR_MAC_CMD, 0x000, slow_clock_control;
306 jext COND_MORE_FRAGMENT, copy_header_into_shm;
307 call lr0, update_wme_params_availability;
308 orx 0, 14, 0x000, GLOBAL_FLAGS_REG1, GLOBAL_FLAGS_REG1; /* This was the only edcf_swap_something operation */
309 jne [SHM_FIFO_RDY], 0x000, fifo_ready_for_tx; /* if (SHM_FIFO_RDY != 0) */
310 jext COND_TRUE, slow_clock_control;
312 mov 0x0100, [SHM_TXFCUR]; /* SHM_TXFCUR = 0x0100 */
313 copy_header_into_shm:;
314 call lr3, load_tx_header_into_shm;
315 jzx 0, 13, [TXHDR_MACLO,off0], 0x000, check_tx_channel; /* if !(tx_info.plcp & 2000) */
316 sub. [TXHDR_TOLO,off0], SPR_TSF_WORD0, GP_REG5; /* GP_REG5 = tx_info.tstamp_lo - SPR_TSF_word_0 [set carry] */
317 subc [TXHDR_TOHI,off0], SPR_TSF_WORD1, GP_REG6; /* GP_REG6 = tx_info.tstamp_hi - SPR_TSF_word_1 - carry */
318 jges GP_REG6, 0x000, check_tx_channel; /* if (GP_REG6 >=s 0x00) */
319 orx 2, 2, 0x005, [TXHDR_STAT,off0], [TXHDR_STAT,off0]; /* tx_info.tx_status = SUPP_EXPIRED | (tx_info.tx_status & ~SUPPRESS_MASK) */
320 jext COND_TRUE, suppress_this_frame;
322 srx 1, 7, [TXHDR_MACLO,off0], 0x000, GP_REG5; /* GP_REG5 = ((tx_info.MAC_ctl_lo) >> 7) & 0x03 */
323 srx 7, 8, [TXHDR_EFT,off0], 0x000, GP_REG6; /* GP_REG6 = ((tx_info.xtra_frame_types) >> 8) & 0xff */
324 orx 1, 8, GP_REG5, GP_REG6, GP_REG5; /* GP_REG5 = (((GP_REG5<<8) | (GP_REG5>>8)) & 0x300) | (GP_REG6 & ~0x300) */
325 je GP_REG5, [SHM_CHAN], check_pmq_tx_header_info; /* if (GP_REG5 == SHM_CHAN) */
326 orx 2, 2, 0x004, [TXHDR_STAT,off0], [TXHDR_STAT,off0]; /* tx_info.tx_status = SUPP_CHAN_MISMATCH | (tx_info.tx_status & ~SUPPRESS_MASK) */
327 jext COND_TRUE, suppress_this_frame;
328 check_pmq_tx_header_info:;
329 or [TXHDR_PHYCTL,off0], 0x000, SPR_TXE0_PHY_CTL; /* SPR_TXE0_PHY_CTL = tx_info.phy_ctl */
330 orx 1, 1, 0x002, [TXHDR_HK5,off0], [TXHDR_HK5,off0]; /* tx_info.housekeeping5 := 0x4 | (tx_info.housekeeping5 & ~0x6) */
331 jext COND_MORE_FRAGMENT, extract_phy_info;
332 or [TXHDR_FES,off0], 0x000, SPR_TX_FES_Time; /* SPR_TX_FES_Time := tx_info.fes_time */
333 jzx 0, 4, [TXHDR_HK5,off0], 0x000, extract_phy_info; /* if (!(tx_info.housekeeping5 & USE_FALLBACK)) */
334 or [TXHDR_FESFB,off0], 0x000, SPR_TX_FES_Time; /* SPR_TX_FES_Time := tx_info.fes_time_fb */
336 jnzx 0, 4, [TXHDR_HK5,off0], 0x000, extract_fallback_info; /* if (tx_info.housekeeping5 & USE_FALLBACK) */
337 srx 7, 0, [TXHDR_PHYRATES,off0], 0x000, GP_REG0; /* GP_REG0 = (tx_info.phy_rates) & 0xff */
338 srx 1, 0, [TXHDR_PHYCTL,off0], 0x000, GP_REG1; /* GP_REG1 = (tx_info.phy_ctl) & 0x3 */
339 jext COND_TRUE, extract_tx_type_subtype;
340 extract_fallback_info:;
341 srx 7, 0, [TXHDR_PLCPFB0,off0], 0x000, GP_REG0; /* GP_REG0 = (tx_info.plcp_fb0) & 0xff */
342 srx 1, 0, [TXHDR_EFT,off0], 0x000, GP_REG1; /* GP_REG1 = (tx_info.xtra_frame_types) & 0x3 */
343 extract_tx_type_subtype:;
344 srx 5, 2, [TXHDR_FCTL,off0], 0x000, TX_TYPE_SUBTYPE; /* TX_TYPE_SUBTYPE = ((tx_info.fctl) >> 2) & 0x3f */
345 call lr0, get_ptr_from_rate_table;
346 jzx 0, 7, [SHM_HF_MI], 0x000, check_tx_no_hw_pwr_ctl; /* if !(SHM_HF_MI & MHF_HWPWRCTL) */
347 or SPR_BASE3, 0x000, SPR_BASE5;
348 check_tx_no_hw_pwr_ctl:;
349 call lr1, prep_phy_txctl_with_encoding;
350 srx 0, 4, SPR_TXE0_PHY_CTL, 0x000, GP_REG1; /* GP_REG1 = (SPR_TXE0_PHY_CTL >> 4) & 0x01 */
351 orx 0, 4, GP_REG1, [SHM_CURMOD], GP_REG1; /* GP_REG1 = ((GP_REG1 << 4) & 0x10) | ([SHM_CURMOD] & ~0x10) -- ([SHM_CURMOD] == 0 ? CCK : OFDM) */
352 call lr0, get_rate_table_duration;
353 add GP_REG5, [SHM_SLOTT], GP_REG5;
354 orx 11, 3, GP_REG5, 0x000, SPR_TXE0_TIMEOUT; /* SPR_TXE0_TIMEOUT = ((GP_REG5<<3) | (GP_REG5>>13)) & 0x7ff8 */
355 jnext COND_MORE_FRAGMENT, check_tx_next_txe_ctl_1;
356 mov 0x4001, SPR_TXE0_CTL; /* Generate FCS and enable TX engine */
357 jext COND_TRUE, state_machine_idle;
358 check_tx_next_txe_ctl_1:;
359 mov 0x4C1D, NEXT_TXE0_CTL;
360 jne TX_TYPE_SUBTYPE, TS_PROBE_RESP, check_tx_next_txe_ctl_2; /* if (tx_frame_type_subtype != TS_PROBE_RESP) */
361 mov 0x4D1D, NEXT_TXE0_CTL;
362 check_tx_next_txe_ctl_2:;
363 jne TX_TYPE_SUBTYPE, TS_ATIM, check_tx_txe_ctl_edcf; /* if (tx_frame_type_subtype != TS_ATIM) */
364 mov 0x6E1D, NEXT_TXE0_CTL;
365 check_tx_txe_ctl_edcf:;
366 jzx 0, 8, [SHM_HF_LO], 0x000, end_check_tx_data; /* if (!(SHM_HF_LO & MHF_EDCF)) */
367 call lr0, mod_txe0_control_for_edcf;
369 jext COND_TRUE, set_ifs;
371 // ***********************************************************************************************
372 // HANDLER: suppress_this_frame
373 // PURPOSE: Flushes frame and tells the host that transmission failed.
375 suppress_this_frame:;
376 mov 0, SPR_TXE0_SELECT; /* SPR_TXE0_SELECT = 0x0000 */
377 jext COND_TRUE, report_tx_status_to_host;
379 // ***********************************************************************************************
381 // PURPOSE: Prepares backoff time (if it is equal to zero) for the next contention stage.
384 extcond_eoi_only(COND_RX_ATIMWINEND);
385 or NEXT_TXE0_CTL, 0x000, SPR_TXE0_CTL; /* SPR_TXE0_CTL = NEXT_TXE0_CTL */
386 jne SPR_IFS_BKOFFDELAY, 0x000, state_machine_idle; /* if (SPR_IFS_BKOFFDELAY != 0) */
387 call lr1, set_backoff_time;
388 jext COND_TRUE, state_machine_idle;
390 // ***********************************************************************************************
391 // HANDLER: tx_frame_now
392 // PURPOSE: Performs a data, ACK or Beacon frame transmission according to the PHY and MAC parameters that have been set.
395 orx 7, 8, 0x000, 0x004, SPR_RXE_FIFOCTL1; /* SPR_RXE_FIFOCTL1 = 0x0004 */
396 nand SPR_BRC, 0x180, SPR_BRC; /* SPR_BRC = SPR_BRC & ~(TX_ERROR | FRAME_NEED_ACK) */
397 mov 0x8300, SPR_WEP_CTL; /* Disable hardwarecrypto */
398 jzx 0, 8, [SHM_HF_LO], 0x000, no_param_update_needed; /* if (!(SHM_HF_LO & MHF_EDCF)) */
399 jext 0x28, check_for_param_update;
400 je [0x00,off4], 0x000, check_for_param_update; /* if (mem[offs4 + 0x0] == 0x00) */
401 jnzx 0, 9, GLOBAL_FLAGS_REG1, 0x000, check_for_param_update; /* if (GLOBAL_FLAGS_REG1 & 0x200) */
402 or SPR_TSF_0x42, 0x000, SPR_TSF_0x24; /* SPR_TSF_0x24 = SPR_TSF_0x42 */
403 or SHM_EDCFQCUR, 0x000, SPR_BASE4; /* SPR_BASE4 = shm_edcf1_paramptr */
404 or [SHM_EDCFQ_TXOP,off4], 0x000, SPR_TSF_0x2a; /* SPR_TSF_0x2a = mem[offs4 + 0x0] -- copy TXOP value into register */
405 orx 0, 9, 0x000, GLOBAL_FLAGS_REG1, GLOBAL_FLAGS_REG1; /* GLOBAL_FLAGS_REG1 = GLOBAL_FLAGS_REG1 & ~0x200 */
406 check_for_param_update:;
407 jnzx 0, 0, SPR_IFS_STAT, 0x000, no_param_update_needed; /* if (SPR_IFS_stat & 0x01) */
408 je SPR_IFS_0x0e, 0x000, no_param_update_needed; /* if no time was elapsed jump (we don't need param update) */
409 jext COND_MORE_FRAGMENT, no_param_update_needed;
411 call lr0, update_wme_params;
412 no_param_update_needed:;
413 orx 0, 5, 0x001, SPR_BRC, SPR_BRC; /* SPR_BRC = SPR_BRC | FRAME_BURST */
414 orx 0, 4, 0x001, SPR_IFS_CTL, SPR_IFS_CTL; /* SPR_IFS_CTL = SPR_IFS_CTL | 0x10 */
415 orx 1, 1, 0x000, SPR_BRWK0, SPR_BRWK0; /* SPR_BRWK_0 = SPR_BRWK_0 & ~0x6 */
416 mov 0, SPR_TXE0_WM0; /* Clear register for template ram byte selection */
417 mov 0, SPR_TXE0_WM1; /* Clear register for template ram byte selection */
418 jnext COND_NEED_RESPONSEFR, tx_beacon_or_data; /* If someone need a response send it, otherwise being tx-ting a beacon or data */
419 mov 0x00FF, SPR_TXE0_WM0; /* Encode the response (an ack here) */
420 srx 0, 5, GLOBAL_FLAGS_REG3, 0x000, GP_REG5; /* GP_REG5 = ((GLOBAL_FLAGS_REG3) >> 5) & 0x1 */
421 orx 0, 12, GP_REG5, SPR_TME_VAL6, SPR_TME_VAL6; /* SPR_TME_VAL6 = (((GP_REG5<<12) | (GP_REG5>>4)) & 0x1000) | (SPR_TME_VAL6 & ~0x1000) */
422 mov 0, SPR_TXE0_SELECT;
423 mov 0, SPR_TXE0_Template_TX_Pointer;
424 mov 0x0010, SPR_TXE0_TX_COUNT; /* 16 bytes = ack (10) + plcp (6) */
425 mov 0x0826, SPR_TXE0_SELECT; /* select "TX_Count" bytes from template ram, put into serializer and generate EOF */
426 jext COND_TRUE, complete_tx;
429 jnext COND_NEED_BEACON, tx_data;
430 orx 0, 3, 0x000, SPR_BRC, SPR_BRC; /* SPR_BRC = SPR_BRC & ~CONTENTION_PARAM_MODIFIED */
431 orx 0, 14, 0x001, SPR_TXE0_WM0, SPR_TXE0_WM0;
432 add SEQUENCE_CTR, 0x001, SEQUENCE_CTR;
433 orx 11, 4, SEQUENCE_CTR, 0x000, SPR_TME_VAL28;
434 jnext 0x3D, tx_beacon;
435 jnzx 0, 7, GLOBAL_FLAGS_REG3, 0x000, set_low_tmpl_addr; /* if (GLOBAL_FLAGS_REG3 & BEACON_TMPL_LOW) */
437 jext COND_TRUE, load_beacon_tim;
441 add GP_REG5, [SHM_TIMBPOS], GP_REG5;
442 mov SHM_BEACON_TIM_PTR, SPR_BASE5;
443 sl SPR_BASE5, 0x001, SPR_TXE0_TX_SHM_ADDR;
444 mov 0, SPR_TXE0_SELECT;
445 orx 1, 0, 0x000, GP_REG5, SPR_TXE0_Template_TX_Pointer;
446 mov 0x0008, SPR_TXE0_TX_COUNT;
447 mov 0x0805, SPR_TXE0_SELECT;
449 jnext COND_TX_BUSY, wait_tx_bcn_free;
451 jext COND_TX_BUSY, wait_tx_bcn_write;
452 sub CURRENT_DTIM_COUNT, 0x001, CURRENT_DTIM_COUNT;
454 jgs CURRENT_DTIM_COUNT, 0x000, not_a_dtim;
455 mov 0, CURRENT_DTIM_COUNT;
456 srx 0, 4, SPR_TXE0_FIFO_RDY, 0x000, GP_REG6; /* GP_REG6 = ((SPR_TXE0_FIFO_RDY) >> 4) & 0x1 -- multicast queue */
457 orx 0, 10, GP_REG6, SPR_BRC, SPR_BRC; /* SPR_BRC = (((GP_REG6<<10) | (GP_REG6>>6)) & TX_MULTICAST_FRAME) | (SPR_BRC & ~TX_MULTICAST_FRAME) */
459 jnand GP_REG5, 0x002, dtim_offs2;
460 jnand GP_REG5, 0x001, dtim_offs1;
461 orx 7, 0, CURRENT_DTIM_COUNT, [0x00,off5], [0x00,off5];
462 orx 0, 0, GP_REG6, [0x01,off5], [0x01,off5];
463 jext COND_TRUE, end_dtim_update;
465 orx 7, 8, CURRENT_DTIM_COUNT, [0x00,off5], [0x00,off5];
466 orx 0, 8, GP_REG6, [0x01,off5], [0x01,off5];
467 jext COND_TRUE, end_dtim_update;
469 jnand GP_REG5, 0x001, dtim_offs3;
470 orx 7, 0, CURRENT_DTIM_COUNT, [0x01,off5], [0x01,off5];
471 orx 0, 0, GP_REG6, [0x02,off5], [0x02,off5];
472 jext COND_TRUE, end_dtim_update;
474 orx 7, 8, CURRENT_DTIM_COUNT, [0x01,off5], [0x01,off5];
475 orx 0, 8, GP_REG6, [0x02,off5], [0x02,off5];
477 orx 1, 0, 0x000, GP_REG5, SPR_TXE0_Template_Pointer;
478 or [0x00,off5], 0x000, SPR_TXE0_Template_Data_Low;
479 or [0x01,off5], 0x000, SPR_TXE0_Template_Data_High;
481 jnzx 0, 0, SPR_TXE0_Template_Pointer, 0x000, wait_tmpl_ram;
482 add SPR_TXE0_Template_Pointer, 0x004, SPR_TXE0_Template_Pointer;
483 or [0x02,off5], 0x000, SPR_TXE0_Template_Data_Low;
484 or [0x03,off5], 0x000, SPR_TXE0_Template_Data_High;
485 jg CURRENT_DTIM_COUNT, 0x000, tx_beacon;
486 or [SHM_DTIMPER], 0x000, CURRENT_DTIM_COUNT;
488 mov 0, SPR_TXE0_SELECT;
489 mov 0x0068, SPR_TXE0_Template_TX_Pointer;
490 or [SHM_BTL0], 0x000, SPR_TXE0_TX_COUNT;
491 jnzx 0, 7, GLOBAL_FLAGS_REG3, 0x000, bcn_tmpl_off1; /* if (GLOBAL_FLAGS_REG3 & BEACON_TMPL_LOW) */
492 mov 0x0468, SPR_TXE0_Template_TX_Pointer;
493 or [SHM_BTL1], 0x000, SPR_TXE0_TX_COUNT;
495 mov 0x0826, SPR_TXE0_SELECT;
496 orx 0, 6, 0x001, GLOBAL_FLAGS_REG3, GLOBAL_FLAGS_REG3;
497 extcond_eoi_only(COND_TX_TBTTEXPIRE);
498 orx 0, 1, 0x001, SPR_TXE0_AUX, SPR_TXE0_AUX;
499 jext 0x3D, no_params_preservation;
500 jnzx 0, 0, SPR_TSF_0x0e, 0x000, params_restored;
501 or NEXT_IFS, 0x000, SPR_IFS_BKOFFDELAY;
503 or NEXT_CONTENTION_WIN, 0x000, CUR_CONTENTION_WIN;
504 or MIN_CONTENTION_WIN, 0x000, NEXT_CONTENTION_WIN;
505 jext COND_TRUE, params_restored;
506 no_params_preservation:
507 or MIN_CONTENTION_WIN, 0x000, CUR_CONTENTION_WIN;
508 jnzx 0, 0, SPR_TSF_0x0e, 0x000, params_restored;
509 and SPR_TSF_Random, CUR_CONTENTION_WIN, SPR_IFS_BKOFFDELAY;
511 mov IRQLO_BEACON_TX_OK, SPR_MAC_IRQLO;
513 orx 0, 8, 0x001, 0x000, SPR_WEP_CTL; /* SPR_WEP_CTL = 0x100 */
514 jext COND_NEED_BEACON, update_txe_timeout;
515 jzx 0, 12, GLOBAL_FLAGS_REG1, 0x000, update_txe_timeout; /* Am I coming from discard_frame? If I'm not goto update_txe_timeout */
516 mov 0, SPR_TXE0_CTL; /* Disable tx engine (?) */
517 jext COND_TRUE, pending_tx_resolved;
520 srx 0, 6, [TXHDR_MACLO,off0], 0x000, GP_REG5; /* GP_REG5 = ((tx_info.MAC_ctl_lo) >> 6) & 0x1 -- Set FCS calculation bit */
521 xor GP_REG5, 0x001, GP_REG5;
522 orx 0, 14, GP_REG5, SPR_TXE0_CTL, SPR_TXE0_CTL; /* SPR_TXE0_Control = (((GP_REG5<<14) | (GP_REG5>>2)) & 0x4000) | (SPR_TXE0_Control & ~0x4000) -- set FCS calculation on TXE0 control (if there is already an FCS we don't need it, else we must compute it (xor on GP_REG5)) */
523 jzx 0, 4, [TXHDR_HK5,off0], 0x000, no_fallback_updates; /* if (!(tx_info.housekeeping5 & USE_FALLBACK)) */
524 or [TXHDR_PLCPFB0,off0], 0x000, SPR_TME_VAL0; /* SPR_TME_VAL0 = tx_info.plcp_fb0 */
525 or [TXHDR_PLCPFB1,off0], 0x000, SPR_TME_VAL2; /* SPR_TME_VAL1 = tx_info.plcp_fb1 */
526 or [TXHDR_DURFB,off0], 0x000, SPR_TME_VAL8; /* SPR_TME_VAL8 = tx_info.dur_fb */
527 or SPR_TXE0_WM0, 0x013, SPR_TXE0_WM0; /* SPR_TXE0_WM_0 = SPR_TXE0_WM_0 | 0x13 */
528 no_fallback_updates:;
529 orx 0, 14, 0x001, [SHM_TXFCUR], SPR_TXE0_FIFO_CMD; /* SPR_TXE0_FIFO_CMD = SHM_TXFCUR | 0x4000 */
530 or [SHM_TXFCUR], 0x000, SPR_TXE0_SELECT; /* SPR_TXE0_SELECT = SHM_TXFCUR */
531 mov 0x0068, SPR_TXE0_TX_COUNT;
532 or [SHM_TXFCUR], 0x007, SPR_TXE0_SELECT; /* SPR_TXE0_SELECT = SHM_TXFCUR | 0x07 */
533 orx 1, 0, 0x002, [SHM_TXFCUR], SPR_TXE0_SELECT; /* SPR_TXE0_SELECT = 0x2 | (SHM_TXFCUR & ~0x3) -- Maybe from FIFO in SHM_TXFCUR to serializer, copy X bytes that you read somewhere (PLCP?) and generate EOF */
534 srx 1, 0, TX_TYPE_SUBTYPE, 0x000, GP_REG5; /* GP_REG5 = (TX_TYPE_SUBTYPE) & 0x3 */
535 je GP_REG5, 0x001, dont_update_seq_ctr_value_for_control_frame; /* If it is a control frame goto dont_update_seq_ctr_value_for_control_frame: control frame doesn't need sequence control */
536 jnzx 3, 12, [TXHDR_STAT,off0], 0x000, update_seq_ctr_value; /* if (tx_info.tx_status & 0xf000) goto update_seq_ctr_value -- If it is a retransmission don't increase SEQ NUM */
537 jzx 0, 3, [TXHDR_MACLO,off0], 0x000, update_seq_ctr_value; /* if (!(tx_info.MAC_ctl_lo & TX_CTL_START_MSDU)) goto update_seq_ctr_value -- Fragment of the same frame */
538 add SEQUENCE_CTR, 0x001, SEQUENCE_CTR;
539 srx 11, 0, SEQUENCE_CTR, 0x000, [TXHDR_RTSSEQCTR,off0]; /* tx_info.used_seqno = (sequence_ctr) & 0xfff */
540 update_seq_ctr_value:;
541 orx 11, 4, [TXHDR_RTSSEQCTR,off0], 0x000, SPR_TME_VAL28; /* SPR_SPR_TXE_Template_Val_seq = ((tx_info.used_seqno<<4) | (tx_info.used_seqno>>12)) & 0xfff0 */
542 orx 0, 14, 0x001, SPR_TXE0_WM0, SPR_TXE0_WM0; /* SPR_TXE0_WM0 = SPR_TXE0_WM0 | 0x4000 */
543 dont_update_seq_ctr_value_for_control_frame:;
544 srx 0, 9, SPR_MAC_CTLHI, 0x000, GP_REG5; /* GP_REG5 = ((SPR_MAC_Control_High) >> 9) & 0x1 */
545 orx 0, 5, GP_REG5, GLOBAL_FLAGS_REG3, GLOBAL_FLAGS_REG3; /* GLOBAL_FLAGS_REG3 = (((GP_REG5<<5) | (GP_REG5>>11)) & 0x20) | (GLOBAL_FLAGS_REG3 & ~0x20) */
546 jext 0x3D, tx_frame_update_status_info;
548 tx_frame_update_status_info:;
549 orx 0, 7, GP_REG5, [TXHDR_STAT,off0], [TXHDR_STAT,off0]; /* tx_info.tx_status = (((GP_REG5<<7) | (GP_REG5>>9)) & 0x80) | (tx_info.tx_status & ~0x80) */
550 orx 0, 12, GP_REG5, 0x000, SPR_TME_VAL6; /* SPR_SPR_TXE_Template_Val_fc = ((GP_REG5<<12) | (GP_REG5>>4)) & 0x1000 */
551 orx 0, 12, 0x001, 0x000, SPR_TME_MASK6; /* SPR_SPR_TXE_Template_Mask_fc = 0x1000 */
552 orx 0, 3, 0x001, SPR_TXE0_WM0, SPR_TXE0_WM0; /* SPR_TXE0_WM_0 = SPR_TXE0_WM_0 | 0x8 */
553 srx 1, 0, TX_TYPE_SUBTYPE, 0x000, GP_REG5; /* GP_REG5 = (tx_frame_type_subtype) & 0x3 */
554 je GP_REG5, 0x001, tx_frame_analysis; /* If it is a control frame goto tx_frame_analysis */
555 jzx 3, 12, [TXHDR_STAT,off0], 0x000, update_gpreg5_with_cur_fifo; /* if !(tx_info.tx_status & 0xf000) */
556 jzx 0, 8, [SHM_HF_LO], 0x000, set_cf_ack; /* if !(SHM_HF_LO & MHF_EDCF) */
557 or SHM_EDCFQCUR, 0x000, SPR_BASE4; /* offs4 = shm_edcf1_paramptr */
558 jzx 0, 9, [SHM_EDCFQ_STATUS,off4], 0x000, update_gpreg5_with_cur_fifo; /* if !(mem[offs4 + 0x7] & 0x200) */
560 orx 0, 11, 0x001, SPR_TME_VAL6, SPR_TME_VAL6; /* This sets the CF-Ack for the frame that is going to be send */
561 orx 0, 11, 0x001, SPR_TME_MASK6, SPR_TME_MASK6;
562 update_gpreg5_with_cur_fifo:;
563 srx 2, 8, [SHM_TXFCUR], 0x000, GP_REG5; /* GP_REG5 = ((SHM_TXFCUR) >> 8) & 0x7 */
565 orx 0, 8, 0x001, 0x000, SPR_WEP_CTL; /* SPR_WEP_CTL = 0x100 */
566 jext 0x3D, find_tx_frame_type;
567 jnext 0x71, find_tx_frame_type;
568 jne TX_TYPE_SUBTYPE, 0x024, find_tx_frame_type; /* if (TX_TYPE_SUBTYPE != TS_ATIM) */
569 orx 0, 6, 0x000, GLOBAL_FLAGS_REG3, GLOBAL_FLAGS_REG3; /* GLOBAL_FLAGS_REG3 = GLOBAL_FLAGS_REG3 & ~0x40 */
570 jzx 0, 0, [TXHDR_RA,off0], 0x000, find_tx_frame_type; /* if !(tx_info.RA0 & 0x01) -- If it is not a multicast frame goto find_tx_frame_type*/
571 orx 0, 10, 0x001, SPR_BRC, SPR_BRC; /* SPR_BRC = SPR_BRC | TX_MULTICAST_FRAME */
573 mov 0, SPR_TSF_Random;
574 or SPR_TSF_0x40, 0x000, [TXHDR_RTSPLCP,off0]; /* tx_info.housekeeping0 = SPR_TSF_0x40 */
575 mov 0, EXPECTED_CTL_RESPONSE; /* expected_control_response = TS_ASSOC_REQ */
576 je TX_TYPE_SUBTYPE, TS_RTS, compute_expected_response;
577 jzx 0, 0, [TXHDR_MACLO,off0], 0x000, reset_cur_contention_window; /* if !(tx_info.MAC_ctl_lo & TX_CTL_IMMED_ACK) */
578 compute_expected_response:;
579 orx 0, 7, 0x001, SPR_BRC, SPR_BRC; /* SPR_BRC = SPR_BRC | FRAME_NEED_ACK */
580 or SPR_BRC, 0x000, 0x000; /* 0x00 = SPR_BRC */
581 mov TS_CTS, EXPECTED_CTL_RESPONSE;
582 je TX_TYPE_SUBTYPE, TS_RTS, update_txe_timeout;
583 mov TS_ACK, EXPECTED_CTL_RESPONSE;
584 jext COND_TRUE, update_txe_timeout;
585 reset_cur_contention_window:;
586 or MIN_CONTENTION_WIN, 0x000, CUR_CONTENTION_WIN;
587 jnzx 0, 8, [SHM_HF_LO], 0x000, tx_frame_backoff_update_not_needed; /* if ((SHM_HF_LO >> 8) & 1) != 0) */
588 call lr1, set_backoff_time;
589 tx_frame_backoff_update_not_needed:;
590 mov 0, SHORT_RETRIES;
593 jnext COND_FRAME_NEED_ACK, dont_update_txe_timeout;
594 orx 0, 15, 0x001, SPR_TXE0_TIMEOUT, SPR_TXE0_TIMEOUT; /* SPR_TXE0_TIMEOUT = SPR_TXE0_TIMEOUT | 0x8000 */
595 jzx 0, 1, GLOBAL_FLAGS_REG2, 0x000, dont_update_txe_timeout; /* if (!(GLOBAL_FLAGS_REG2 & 0x02)) */
596 orx 7, 8, 0x080, 0x001, SPR_TXE0_TIMEOUT;
597 dont_update_txe_timeout:;
598 jzx 0, 13, [SHM_HF_LO], 0x000, no_radar_war; /* if !(SHM_HF_LO & MHF_RADARWAR) */
599 mov 0x00C8, GP_REG5; /* GP_REG5 = APHY_RADAR_THRESH1 */
601 call lr0, write_phy_reg;
603 jne [SHM_PHYTYPE], 0x001, tx_frame_no_B_phy; /* if (shm_phy_type != PHY_TYPE_B) */
604 jl [SHM_PHYVER], 0x002, state_machine_idle; /* if (shm_phy_ver <u 0x02) */
606 je [SHM_PHYTYPE], 0x000, tx_frame_A_phy; /* if (shm_phy_type == PHY_TYPE_A) */
607 jnzx 1, 0, SPR_TXE0_PHY_CTL, 0x000, tx_frame_A_phy; /* if (SPR_TXE0_PHY_Control & 0x03) */
608 add SPR_TSF_WORD0, 0x028, GP_REG5; /* GP_REG5 = SPR_TSF_word_0 + 0x28 */
609 jext COND_TRUE, tx_frame_wait_16us;
611 add SPR_TSF_WORD0, 0x010, GP_REG5; /* GP_REG5 = SPR_TSF_word_0 + 0x10 */
613 jext COND_TX_DONE, state_machine_idle; /* Wait for the packet to hit the PHY (16us OFDM, 40us CCK) */
614 jne SPR_TSF_WORD0, GP_REG5, tx_frame_wait_16us; /* if (SPR_TSF_word_0 != GP_REG5) */
615 jnzx 0, 0, SPR_TXE0_PHY_CTL, 0x000, aphy_tssi_selection; /* if (SPR_TXE0_PHY_CTL & 0x01) */
616 mov 0x0029, GP_REG5; /* GP_REG5 = BPHY_TSSI */
617 mov 0x002C, SPR_BASE5;
618 jext COND_TRUE, update_phy_params;
619 aphy_tssi_selection:;
620 mov 0x047B, GP_REG5; /* GP_REG5 = GPHY_TO_APHY_OFF | APHY_TSSI_STAT */
621 mov 0x0038, SPR_BASE5;
623 call lr0, sel_phy_reg;
624 rr [0x01,off5], 0x008, [0x01,off5]; /* mem[offs5 + 0x1] = (mem[offs5 + 0x1] >> 0x08) | (mem[offs5 + 0x1] << (16 - 0x08)) */
625 srx 7, 8, [0x00,off5], 0x000, GP_REG5; /* GP_REG5 = ((mem[offs5 + 0x0]) >> 8) & 0xff */
626 orx 7, 0, GP_REG5, [0x01,off5], [0x01,off5]; /* mem[offs5 + 0x1] = (GP_REG5 & 0xff) | (mem[offs5 + 0x1] & ~0xff) */
627 rr [0x00,off5], 0x008, [0x00,off5]; /* mem[offs5 + 0x0] = (mem[offs5 + 0x0] >> 0x08) | (mem[offs5 + 0x0] << (16 - 0x08)) */
628 orx 7, 0, SPR_Ext_IHR_Data, [0x00,off5], [0x00,off5]; /* mem[offs5 + 0x0] = (SPR_Ext_IHR_Data & 0xff) | (mem[offs5 + 0x0] & ~0xff) */
629 jzx 0, 10, GLOBAL_FLAGS_REG1, 0x000, tx_frame_no_cca_in_progress; /* if (!(GLOBAL_FLAGS_REG1 & CCA_INPROGR))) */
630 tx_frame_no_cca_in_progress:;
631 jnzx 0, 11, SPR_IFS_STAT, 0x000, state_machine_idle; /* if (SPR_IFS_stat & 0x800) */
632 jge SPR_NAV_0x04, 0x0A0, state_machine_idle; /* if (SPR_NAV_0x04 >=u 0xa0) */
633 mov 0xFFFF, SPR_NAV_0x04;
634 orx 0, 10, 0x001, 0x05F, GP_REG5; /* GP_REG5 = GPHY_TO_APHY_OFF | APHY_NUM_PKT_CNT */
635 wait_for_ihr_data_to_clear:;
636 call lr0, sel_phy_reg;
637 and SPR_Ext_IHR_Data, 0x01F, GP_REG6; /* GP_REG6 = SPR_Ext_IHR_Data & 0x1f */
638 je GP_REG6, 0x016, wait_for_ihr_data_to_clear; /* if (GP_REG6 == 0x16) */
640 jext COND_TRUE, state_machine_idle;
642 // ***********************************************************************************************
643 // HANDLER: tx_infos_update
644 // PURPOSE: Updates retries informations and looks for transmission error. If sent frame doesn't require ACK, tells the host that transmission was successfully performed.
647 orx 0, 5, 0x000, SPR_BRC, SPR_BRC; /* SPR_BRC = SPR_BRC & ~FRAME_BURST */
648 mov 0x8700, SPR_WEP_CTL; /* SPR_WEP_Control = 0x8700 */
649 jnzx 0, 10, [TXHDR_FCTL,off0], 0x000, need_ack; /* if (tx_info.fctl & 0x400) -- more fragment?? */
650 orx 0, 4, 0x000, SPR_BRC, SPR_BRC; /* SPR_BRC = SPR_BRC & ~MORE_FRAGMENT */
652 jext COND_NEED_RESPONSEFR, need_response_frame;
653 jext EOI(COND_TX_UNDERFLOW), tx_underflow;
654 jext EOI(COND_TX_PHYERR), tx_clear_issues;
655 jnext COND_NEED_BEACON, dont_need_beacon;
656 need_response_frame:;
657 orx 1, 0, 0x000, SPR_BRC, SPR_BRC; /* SPR_BRC = SPR_BRC & ~(COND_NEED_BEACON | COND_NEED_RESPONSEFR) */
658 jext COND_TRUE, state_machine_start;
660 mov DEFAULT_RETRY_LIMIT, SHORT_RETRY_LIMIT;
661 /* update_retries_info */
662 srx 3, 12, [TXHDR_STAT,off0], 0x000, GP_REG3; /* GP_REG3 = ((tx_info.tx_status) >> 12) & 0xf */
663 add GP_REG3, 0x001, GP_REG3; /* GP_REG3 = GP_REG3 + 1 */
664 orx 3, 12, GP_REG3, [TXHDR_STAT,off0], [TXHDR_STAT,off0]; /* tx_info.tx_status = (((GP_REG3<<12) | (GP_REG3>>4)) & 0xf000) | (tx_info.tx_status & ~0xf000) */
665 jext COND_FRAME_NEED_ACK, state_machine_start;
666 jext COND_TRUE, report_tx_status_to_host;
668 // ***********************************************************************************************
669 // HANDLER: tx_end_wait_10us
670 // PURPOSE: Doesn't allow noise measurement for 10us after transmission.
673 jnzx 0, 4, GLOBAL_FLAGS_REG1, 0x000, tx_end_completed; /* if (GLOBAL_FLAGS_REG1 & 0x10) */
674 orx 0, 4, 0x001, GLOBAL_FLAGS_REG1, GLOBAL_FLAGS_REG1; /* GLOBAL_FLAGS_REG1 = GLOBAL_FLAGS_REG1 | 0x10 */
675 or SPR_TSF_WORD0, 0x000, [SHM_WAIT10_CLOCK]; /* mem[SHM_WAIT10_CLOCK] = SPR_TSF_word_0 */
676 jzx 0, 6, [SHM_HF_LO], 0x000, tx_end_completed; /* if !(SHM_HF_LO & MHF_OFDMPWR) */
677 orx 0, 9, 0x000, SPR_GPIO_OUTEN, SPR_GPIO_OUTEN; /* SPR_GPIO_OUTEN = SPR_GPIO_OUTEN & ~0x200 */
679 sub SPR_TSF_WORD0, [SHM_WAIT10_CLOCK], GP_REG9; /* GP_REG9 = SPR_TSF_word_0 - mem[SHM_WAIT10_CLOCK] */
680 jl GP_REG9, 0x008, check_conditions_no_tx; /* if (GP_REG9 <u 0x08) goto check_conditions_no_tx */
681 mov 0x0027, GP_REG5; /* GP_REG5 = BPHY_JSSI */
682 call lr0, sel_phy_reg;
683 and SPR_Ext_IHR_Data, 0x0FF, [SHM_PHYTXNOI]; /* shm_phy_noise_after_TX = SPR_Ext_IHR_Data & 0xff */
684 orx 0, 4, 0x000, GLOBAL_FLAGS_REG1, GLOBAL_FLAGS_REG1; /* GLOBAL_FLAGS_REG1 = GLOBAL_FLAGS_REG1 & ~0x10 */
685 jext EOI(COND_TX_DONE), state_machine_idle;
686 jext COND_TRUE, report_tx_status_to_host;
688 // ***********************************************************************************************
689 // HANDLER: report_tx_status_to_host
690 // PURPOSE: Reports informations about transmission to the host, informing it about success or failure of the operation.
692 report_tx_status_to_host:;
693 jand [TXHDR_HK4,off0], 0x003, dont_clear_housekeeping; /* if !(tx_info.housekeeping4 & 0x03) */
694 extcond_eoi_only(COND_RX_FIFOFULL);
695 jext COND_RX_FIFOBUSY, report_tx_status_to_host;
696 jext COND_RX_CRYPTBUSY, report_tx_status_to_host;
697 mov 0, [TXHDR_RTS,off0]; /* tx_info.housekeeping3 = 0x0000 */
698 jnext COND_NEED_RTS, remove_frame_from_fifo;
699 orx 0, 6, 0x001, [TXHDR_STAT,off0], [TXHDR_STAT,off0]; /* tx_info.tx_status = tx_info.tx_status | 0x40 */
700 jext COND_TRUE, rise_status_interrupt;
701 remove_frame_from_fifo:;
702 orx 0, 13, 0x001, [SHM_TXFCUR], SPR_TXE0_FIFO_CMD; /* SPR_TXE0_FIFO_CMD = SHM_TXFCUR | 0x2000 */
703 jzx 0, 0, [TXHDR_STAT,off0], 0x000, rise_status_interrupt; /* if !(tx_info.tx_status & 0x01) */
704 or SPR_RXE_PHYRXSTAT1, 0x000, [TXHDR_RTS,off0]; /* tx_info.housekeeping3 = SPR_RXE_PHYRS_1 */
705 rise_status_interrupt:;
706 mov 0x0080, SPR_MAC_IRQLO; /* SPR_MAC_Interrupt_Status_Low = MI_NSPECGEN_0 */
707 jnzx 0, 13, SPR_MAC_CTLHI, 0x000, discard_tx_status; /* if (SPR_MAC_Control_High & MCTL_DISCARD_TXSTATUS) */
708 or [TXHDR_STAT,off0], 0x000, GP_REG5; /* GP_REG5 = tx_info.tx_status */
709 orx 0, 1, GP_REG5, GP_REG5, GP_REG5; /* GP_REG5 = (((GP_REG5<<1) | (GP_REG5>>15)) & 0x2) | (GP_REG5 & ~0x2) */
710 or [TXHDR_RTSPHYSTAT,off0], 0x000, SPR_TX_STATUS3; /* SPR_TX_Status_3 = tx_info.phy_tx_status */
711 or [TXHDR_RTSSEQCTR,off0], 0x000, SPR_TX_STATUS2; /* SPR_TX_Status_2 = tx_info.used_seqno */
712 or [TXHDR_COOKIE,off0], 0x000, SPR_TX_STATUS1; /* SPR_TX_Status_1 = tx_info.cookie */
713 orx 0, 0, 0x001, GP_REG5, SPR_TX_STATUS0; /* SPR_TX_Status_0 = GP_REG5 | 0x1 */
715 jnext COND_NEED_RTS, dont_clear_tx_retry_info;
716 orx 3, 8, 0x000, [TXHDR_STAT,off0], [TXHDR_STAT,off0]; /* tx_info.tx_status = tx_info.tx_status & ~0xf00 */
717 jext COND_TRUE, dont_clear_housekeeping;
718 dont_clear_tx_retry_info:;
719 orx 1, 0, 0x000, [TXHDR_HK4,off0], [TXHDR_HK4,off0]; /* tx_info.housekeeping4 = tx_info.housekeeping4 & ~0x3 */
720 dont_clear_housekeeping:;
721 orx 0, 6, 0x000, [TXHDR_STAT,off0], [TXHDR_STAT,off0]; /* tx_info.tx_status = tx_info.tx_status & ~0x40 */
722 orx 0, 11, 0x000, SPR_BRC, SPR_BRC; /* SPR_BRC = SPR_BRC & ~NEED_RTS */
723 mov 0, [TXHDR_RTSPHYSTAT,off0]; /* tx_info.phy_tx_status = 0x0000 */
724 jext COND_TRUE, state_machine_start;
726 // ***********************************************************************************************
727 // HANDLER: tx_contention_params_update
728 // PURPOSE: Updates current window parameter according to success or failure of transmission operation. Checks if retries reached the top limit and eventually commands a drop operation.
730 tx_contention_params_update:;
731 jnext COND_FRAME_NEED_ACK, finish_updates;
732 jext COND_REC_IN_PROGRESS, finish_updates;
733 jext COND_FRAME_BURST, finish_updates;
734 orx 0, 7, 0x000, SPR_BRC, SPR_BRC; /* SPR_BRC = SPR_BRC & ~FRAME_NEED_ACK */
735 jnext EOI(COND_TX_PMQ), reset_antenna_ctr_if_needed;
736 jzx 0, 8, [SHM_HF_LO], 0x000, skip_tsf_update; /* if !(SHM_HF_LO & MHF_EDCF) */
739 orx 0, 9, 0x000, GLOBAL_FLAGS_REG1, GLOBAL_FLAGS_REG1; /* GLOBAL_FLAGS_REG1 = GLOBAL_FLAGS_REG1 & ~0x200 */
741 jext COND_TRUE, update_contention_params;
742 reset_antenna_ctr_if_needed:;
743 jnext COND_RX_FCS_GOOD, dont_reset_antenna_ctr;
744 je RX_TYPE_SUBTYPE, TS_CTS, dont_reset_antenna_ctr;
745 mov 0, ANTENNA_DIVERSITY_CTR;
746 dont_reset_antenna_ctr:;
747 jext COND_TX_ERROR, update_contention_params;
748 jext EOI(COND_RX_FCS_GOOD), update_params_on_success;
749 je GPHY_SYM_WAR_FLAG, 0x001, update_params_on_success;
750 update_contention_params:;
751 orx 0, 8, 0x000, SPR_BRC, SPR_BRC; /* SPR_BRC = SPR_BRC & ~TX_ERROR */
752 call lr1, antenna_diversity_helper;
753 orx 0, 4, 0x000, SPR_BRC, SPR_BRC; /* SPR_BRC = SPR_BRC & ~MORE_FRAGMENT */
754 orx 14, 1, CUR_CONTENTION_WIN, 0x001, CUR_CONTENTION_WIN; /* CUR_CONTENTION_WIN = CUR_CONTENTION_WIN * 2 + 1 */
755 and CUR_CONTENTION_WIN, MAX_CONTENTION_WIN, CUR_CONTENTION_WIN; /* CUR_CONTENTION_WIN = CUR_CONTENTION_WIN & MAX_CONTENTION_WIN */
756 je EXPECTED_CTL_RESPONSE, TS_CTS, using_fallback;
757 jzx 0, 2, [TXHDR_MACLO,off0], 0x000, using_fallback; /* if !(tx_info.MAC_ctl_lo & TX_CTL_SEND_RTS) */
758 orx 0, 11, 0x001, SPR_BRC, SPR_BRC; /* SPR_BRC = SPR_BRC | NEED_RTS */
760 jl GP_REG3, [SHM_SFFBLIM], dont_use_fallback; /* if (GP_REG3 <u shm_short_frame_tx_count_fallbackrate_thresh) */
761 orx 0, 4, 0x001, [TXHDR_HK5,off0], [TXHDR_HK5,off0]; /* tx_info.housekeeping5 = USE_FALLBACK | (tx_info.housekeeping5 & ~USE_FALLBACK) */
763 add SHORT_RETRIES, 0x001, SHORT_RETRIES;
764 jne SHORT_RETRIES, SHORT_RETRY_LIMIT, short_retry_limit_not_reached_yet;
765 or MIN_CONTENTION_WIN, 0x000, CUR_CONTENTION_WIN; /* CUR_CONTENTION_WIN := MIN_CONTENTION_WIN */
766 short_retry_limit_not_reached_yet:;
767 jge GP_REG3, SHORT_RETRY_LIMIT, retry_limit_reached; /* if (GP_REG3 >=u SHORT_RETRY_LIMIT) */
768 jext COND_TRUE, retry_limit_not_reached;
769 retry_limit_reached:;
770 mov 0, SHORT_RETRIES;
771 extcond_eoi_only(COND_TX_PMQ);
772 jnzx 0, 8, [SHM_HF_LO], 0x000, backoff_update_not_needed_1; /* if (SHM_HF_LO & MHF_EDCF) */
773 call lr1, set_backoff_time;
774 backoff_update_not_needed_1:;
775 orx 0, 3, 0x001, [TXHDR_HK5,off0], [TXHDR_HK5,off0]; /* tx_info.housekeeping5 = FAILED | (tx_info.housekeeping5 & ~FAILED) */
776 orx 0, 11, 0x000, SPR_BRC, SPR_BRC; /* SPR_BRC = SPR_BRC & ~NEED_RTS */
777 jext COND_TRUE, report_tx_status_to_host; /* We must discard the frame due to short_retry_limit reaching */
778 retry_limit_not_reached:;
779 jnzx 0, 8, [SHM_HF_LO], 0x000, finish_updates; /* if (SHM_HF_LO & MHF_EDCF) */
780 call lr1, set_backoff_time;
782 extcond_eoi_only(COND_TX_PMQ);
783 jext COND_NEED_RTS, report_tx_status_to_host;
784 jext COND_TRUE, state_machine_start;
785 update_params_on_success:;
786 srx 1, 0, TX_TYPE_SUBTYPE, 0x000, GP_REG5; /* GP_REG5 = (TX_TYPE_SUBTYPE) & 0x3 */
787 je GP_REG5, 0x001, update_params_control_frame; /* if frame is a control frame goto update_params_control_frame */
788 or MIN_CONTENTION_WIN, 0x000, CUR_CONTENTION_WIN;
789 update_params_control_frame:;
790 jnzx 0, 8, [SHM_HF_LO], 0x000, backoff_update_not_needed_3; /* if (SHM_HF_LO & MHF_EDCF) */
791 call lr1, set_backoff_time;
792 backoff_update_not_needed_3:;
793 mov 0, SHORT_RETRIES;
794 jzx 0, 1, [TXHDR_MACLO,off0], 0x000, dont_update_long_frame_retries;/* if (!(tx_info.MAC_ctl_lo & TX_CTL_LONG_FRAME)) */
796 dont_update_long_frame_retries:;
797 orx 0, 0, 0x001, [TXHDR_STAT,off0], [TXHDR_STAT,off0]; /* tx_info.tx_status = tx_info.tx_status | 0x1 */
798 jext COND_TRUE, report_tx_status_to_host;
800 // ***********************************************************************************************
801 // HANDLER: send_response
802 // PURPOSE: Sends an ACK back to the station whose MAC was contained in the source address header field.
803 // At the end set the NEED_RESPONSEFR bit in SPR_BRC that will trigger the condition COND_NEED_RESPONSEFR
804 // that will be evaluated at next tx_frame_now
805 // Values are taken from the tables in initvals.asm
807 // 1Mb/s (A) off5=37E
808 // 2Mb/s (4) off5=389
809 // 5.5Mb/s (7) off5=394
810 // 11Mb/s (E) off5=39F
814 or [0x01,off2], 0x000, SPR_TME_VAL0; /* SPR_SPR_TXE_Template_Val_plcp0 = mem[offs2 + 0x1] */
815 je [SHM_CURMOD], 0x000, cck_mod; /* If we are using cck goto cck_mod */
816 orx 10, 5, GP_REG5, [0x01,off2], SPR_TME_VAL0; /* SPR_SPR_TXE_Template_Val_plcp0 = (((GP_REG5 << 5) | (GP_REG5 >> 11)) & 0xffe0) | (mem[offs2 + 0x1] & ~0xffe0) */
817 cck_mod:; /* Set receiver mac address */
818 or [0x02,off2], 0x000, SPR_TME_VAL2; /* SPR_SPR_TXE_Template_Val_plcp1 = mem[offs2 + 0x2] */
819 mov 0, SPR_TME_VAL4; /* SPR_SPR_TXE_Template_Val_plcp2 = 0x0000 */
820 or [RX_FRAME_ADDR2_1,off1], 0x000, SPR_TME_VAL10; /* SPR_SPR_TXE_Template_Val_ra0 = mem[rx_frame_offs + FR_OFFS_ADDR2] */
821 mov 0xFFFF, SPR_TME_MASK10; /* SPR_SPR_TXE_Template_Mask_ra0 = 0xffff */
822 or [RX_FRAME_ADDR2_2,off1], 0x000, SPR_TME_VAL12; /* SPR_SPR_TXE_Template_Val_ra1 = mem[rx_frame_offs + FR_OFFS_ADDR2 + 1] */
823 mov 0xFFFF, SPR_TME_MASK12; /* SPR_SPR_TXE_Template_Mask_ra1 = 0xffff */
824 or [RX_FRAME_ADDR2_3,off1], 0x000, SPR_TME_VAL14; /* SPR_SPR_TXE_Template_Val_ra2 = mem[rx_frame_offs + FR_OFFS_ADDR2 + 2] */
825 mov 0xFFFF, SPR_TME_MASK14; /* SPR_SPR_TXE_Template_Mask_ra2 = 0xffff */
826 or [SHM_ACKCTSPHYCTL], 0x000, SPR_TXE0_PHY_CTL; /* SPR_TXE0_PHY_CTL = SHM_ACKCTSPHYCTL */
827 jzx 0, 7, [SHM_HF_MI], 0x000, no_hw_pwr_ctl; /* if (!(SHM_HF_MI & MHF_HWPWRCTL)) */
828 or SPR_BASE2, 0x000, SPR_BASE5;
830 srx 1, 0, [SHM_CURMOD], 0x000, GP_REG1; /* GP_REG1 = modulation (OFDM or CCK) */
831 call lr1, prep_phy_txctl_with_encoding;
832 mov 0xFFFF, SPR_TME_MASK6;
833 mov 0xFFFF, SPR_TME_MASK8;
834 mov 0x00D4, SPR_TME_VAL6; /* SPR_SPR_TXE_Template_Val_fc = 0x00D4 */
835 mov TS_ACK, TX_TYPE_SUBTYPE;
836 je RX_TYPE_SUBTYPE, TS_PSPOLL, pspoll_frame;
837 jnzx 0, 10, [RX_FRAME_FC,off1], 0x000, ctl_more_frag; /* if (CTL_MORE_FRAG(rx_frame)) */
838 jext COND_TRUE, pspoll_frame;
840 or [SHM_CURMOD], 0x000, GP_REG1; /* GP_REG1 = [SHM_CURMOD] */
841 call lr0, get_rate_table_duration;
842 sub GP_REG5, [SHM_PREAMBLE_DURATION], GP_REG5; /* GP_REG5 = GP_REG5 - shm_preamble_duration */
843 jgs GP_REG5, [RX_FRAME_DURATION,off1], pspoll_frame; /* if (GP_REG5 >s mem[rx_frame_offs + FR_OFFS_DURID]) */
844 sub [RX_FRAME_DURATION,off1], GP_REG5, SPR_TME_VAL8; /* SPR_SPR_TXE_Template_Val_dur = mem[rx_frame_offs + FR_OFFS_DURID] - GP_REG5 */
845 jext COND_TRUE, trigger_cts_ack_transmission;
847 mov 0, SPR_TME_VAL8; /* SPR_SPR_TXE_Template_Val_dur = 0x0000 */
848 jnext 0x71, trigger_cts_ack_transmission;
849 orx 0, 15, 0x001, SPR_TME_VAL8, SPR_TME_VAL8; /* SPR_SPR_TXE_Template_Val_dur = SPR_SPR_TXE_Template_Val_dur | 0x8000 */
850 trigger_cts_ack_transmission:;
851 orx 2, 0, 0x002, SPR_BRC, SPR_BRC; /* SPR_BRC = NEED_RESPONSEFR | (SPR_BRC & ~(NEED_BEACON | NEED_RESPONSEFR | NEED_PROBE_RESP)) */
852 je GPHY_SYM_WAR_FLAG, 0x000, sym_war_txe_ctl;
853 mov 0x4001, NEXT_TXE0_CTL; /* Generate FCS and enable TX engine */
854 jext COND_TRUE, send_response_end;
856 mov 0x4021, NEXT_TXE0_CTL; /* Generate FCS (4), enable TX engine (1) and 2(??)*/
858 je RX_TYPE_SUBTYPE, TS_RTS, send_control_frame_to_host;
859 jext COND_RX_COMPLETE, rx_complete;
860 jext COND_TRUE, state_machine_idle;
862 // ***********************************************************************************************
863 // HANDLER: tx_timers_setup
864 // PURPOSE: Updates timers informations.
867 jzx 0, 8, SPR_BRPO0, 0x000, proceed_with_timer_update; /* if (!(SPR_BRPO0 & 0x100)) */
868 orx 1, 3, 0x000, GLOBAL_FLAGS_REG2, GLOBAL_FLAGS_REG2; /* GLOBAL_FLAGS_REG2 = GLOBAL_FLAGS_REG2 & ~0x18 */
869 orx 0, 8, 0x000, SPR_BRPO0, SPR_BRPO0; /* SPR_BRPO0 = SPR_BRPO0 & ~0x100 */
870 jzx 0, 10, GLOBAL_FLAGS_REG1, 0x000, cca_not_in_progress; /* if !(GLOBAL_FLAGS_REG1 & CCA_INPROGR) */
871 cca_not_in_progress:;
872 jzx 0, 8, [SHM_HF_LO], 0x000, no_timers_update_needed; /* if !(SHM_HF_LO & MHF_EDCF) */
873 jzx 0, 0, SPR_IFS_STAT, 0x000, no_timers_update_needed; /* if !(SPR_IFS_stat & 0x01) */
874 je SPR_IFS_0x0e, 0x000, no_timers_update_needed; /* if (SPR_IFS_0x0e == 0x00) */
876 call lr0, update_wme_params;
877 no_timers_update_needed:;
878 jext COND_TRUE, state_machine_idle;
879 proceed_with_timer_update:;
880 jnzx 0, 11, SPR_IFS_STAT, 0x000, timers_update_goon; /* if (SPR_IFS_stat & 0x800) */
881 orx 0, 8, 0x001, SPR_BRPO0, SPR_BRPO0; /* SPR_BRPO0 = SPR_BRPO0 | 0x100 */
882 jzx 0, 6, GLOBAL_FLAGS_REG2, 0x000, timers_update_goon; /* if !(GLOBAL_FLAGS_REG2 & 0x40) */
884 jzx 0, 11, [SHM_HF_LO], 0x000, no_ACI; /* if !(SHM_HF_LO & MHF_ACI) */
885 mov 0x048A, GP_REG5; /* GP_REG5 = GPHY_TO_APHY_OFF | APHY_N1_N2_THRESH */
886 call lr0, sel_phy_reg;
887 orx 2, 12, 0x003, SPR_Ext_IHR_Data, SPR_Ext_IHR_Data; /* SPR_Ext_IHR_Data = 0x3000 | (SPR_Ext_IHR_Data & ~0x7000) */
888 or SPR_Ext_IHR_Data, 0x000, GP_REG6; /* GP_REG6 = SPR_Ext_IHR_Data */
889 call lr0, write_phy_reg;
891 jzx 0, 4, GLOBAL_FLAGS_REG2, 0x000, end_tx_timers_setup; /* if !(GLOBAL_FLAGS_REG2 & 0x10) */
892 orx 1, 3, 0x001, GLOBAL_FLAGS_REG2, GLOBAL_FLAGS_REG2; /* GLOBAL_FLAGS_REG2 = 0x8 | (GLOBAL_FLAGS_REG2 & ~0x18) */
893 end_tx_timers_setup:;
894 jnzx 0, 7, SPR_RXE_0x1a, 0x000, state_machine_start; /* if (SPR_RXE_0x1a & 0x80) */
895 orx 1, 3, 0x001, GLOBAL_FLAGS_REG2, GLOBAL_FLAGS_REG2; /* GLOBAL_FLAGS_REG2 = 0x8 | (GLOBAL_FLAGS_REG2 & ~0x18) */
896 jext COND_TRUE, state_machine_start;
898 // ***********************************************************************************************
900 // PURPOSE: If header was successfully received, extracts from it frame related informations.
901 // Current time is stored inside four registers RX_TIME_WORD[0-3]
902 // RX_PHY_ENCODING stores the kind of encoding for all the succeeding analysis: 0 is CCK, 1 is OFDM
903 // At the beginning switch off the TX engine if it is not
906 jext EOI(COND_RX_FCS_GOOD), rx_plcp;
907 mov 0, GPHY_SYM_WAR_FLAG;
908 jnzx 0, 2, SPR_RXE_FIFOCTL1, 0x000, state_machine_idle; /* if (SPR_RXE_FIFOCTL1 & 0x04) -- Air-buffer is being flushed, try later */
909 jzx 0, 0, SPR_TXE0_CTL, 0x000, sync_rx_frame_time_with_TSF; /* if (!(SPR_TXE0_CTL & 0x01)) */
911 orx 2, 0, 0x000, SPR_BRC, SPR_BRC; /* SPR_BRC = SPR_BRC & ~(NEED_BEACON | NEED_RESPONSEFR | NEED_PROBE_RESP) */
912 sync_rx_frame_time_with_TSF:;
913 or SPR_TSF_WORD0, 0x000, RX_TIME_WORD0;
914 or SPR_TSF_WORD1, 0x000, RX_TIME_WORD1;
915 or SPR_TSF_WORD2, 0x000, RX_TIME_WORD2;
916 or SPR_TSF_WORD3, 0x000, RX_TIME_WORD3;
917 jne RX_TIME_WORD0, SPR_TSF_WORD0, sync_rx_frame_time_with_TSF;
918 srx 0, 13, SPR_RXE_ENCODING, 0x000, RX_PHY_ENCODING; /* rx_phy_encoding = ((SPR_RXE_0x1c) >> 13) & 0x1 -- can be 0 (CCK) or 1 (OFDM)*/
919 jne [SHM_PHYTYPE], 0x000, rx_plcp_not_A_phy; /* if (SHM_PHYTYPE != PHY_TYPE_A) */
920 mov 0x01, RX_PHY_ENCODING; /* RX_PHY_ENCODING = OFDM -- force OFDM for A phy type */
922 mov 0x0008, GP_REG5; /* GP_REG5 = channel */
923 call lr0, sel_phy_reg; /* read the channel */
924 srx 0, 8, [SHM_CHAN], 0x000, GP_REG5; /* GP_REG5 = (shm_cur_channel >> 8) & 0x01 */
925 orx 0, 8, GP_REG5, SPR_Ext_IHR_Data, GP_REG5; /* GP_REG5 = (((GP_REG5<<8) | (GP_REG5>>8)) & 0x100) | (SPR_Ext_IHR_Data & ~0x100) */
926 orx 9, 3, GP_REG5, [SHM_PHYTYPE], [SHM_RXHDR_RXCHAN]; /* rx_hdr.RxChan = (((GP_REG5<<3) | (GP_REG5>>13)) & 0x1ff8 | (shm_phy_type & ~01ff8) -- The channel was passed to the driver? */
927 or SPR_BRC, 0x140, SPR_BRC; /* SPR_BRC = SPR_BRC | (TX_ERROR | REC_IN_PROGRESS) */
928 orx 0, 9, 0x000, SPR_BRC, SPR_BRC; /* SPR_BRC = SPR_BRC & ~RX_ERROR */
929 orx 0, 0, 0x000, GLOBAL_FLAGS_REG3, GLOBAL_FLAGS_REG3; /* GLOBAL_FLAGS_REG3 = GLOBAL_FLAGS_REG3 & ~RX_FRAME_DISCARD */
930 wait_for_header_to_be_received:;
931 jext COND_RX_COMPLETE, header_received; /* Go on since rx was complete or frame length is >= 38 bytes (PLCP + MAC Header) */
932 jl SPR_RXE_FRAMELEN, 0x026, wait_for_header_to_be_received;
934 mov 0, [SHM_RXHDR_MACST_LOW]; /* rx_hdr.RxStatus1 = 0x0000 */
935 mov 0, [SHM_RXHDR_MACST_HIGH]; /* rx_hdr.RxStatus2 = 0x0000 */
936 jl SPR_RXE_FRAMELEN, 0x010, rx_too_short; /* Shortest frame must be at least 16 bytes (PLCP + 10 bytes (CTS,ACK)) */
937 srx 5, 2, [RX_FRAME_FC,off1], 0x000, RX_TYPE_SUBTYPE; /* RX_TYPE_SUBTYPE = ((mem[rx_frame_offs + FR_OFFS_CTL]) >> 2) & 0x3f -- Extract Type and subtype*/
938 srx 1, 2, [RX_FRAME_FC,off1], 0x000, RX_TYPE; /* RX_TYPE = ((mem[rx_frame_offs + FR_OFFS_CTL]) >> 2) & 0x3 -- Extract type*/
939 orx 1, 12, 0x000, GLOBAL_FLAGS_REG3, GLOBAL_FLAGS_REG3; /* GLOBAL_FLAGS_REG3 = GLOBAL_FLAGS_REG3 & ~NOT_REGULAR_ACK|QOS_DATA_FRAME */
940 srx 0, 8, [RX_FRAME_FC,off1], 0x000, GP_REG5; /* GP_REG5 = ((mem[rx_frame_offs + FR_OFFS_CTL]) >> 8) & 0x1 */
941 srx 0, 9, [RX_FRAME_FC,off1], 0x000, GP_REG6; /* GP_REG6 = ((mem[rx_frame_offs + FR_OFFS_CTL]) >> 9) & 0x1 */
942 and GP_REG5, GP_REG6, GP_REG6; /* GP_REG6 = GP_REG5 & GP_REG6 -- Check if both toDS and fromDS were set */
943 orx 0, 11, GP_REG6, GLOBAL_FLAGS_REG3, GLOBAL_FLAGS_REG3; /* GLOBAL_FLAGS_REG3 = (((GP_REG6<<11) | (GP_REG6>>5)) & 0x800) | (GLOBAL_FLAGS_REG3 & ~WDS_FRAME) */
944 and RX_TYPE_SUBTYPE, 0x023, GP_REG5; /* GP_REG5 = RX_TYPE_SUBTYPE & 0x23 -- determine if frame is a QoS data frame */
945 jne GP_REG5, 0x022, not_qos_data; /* if (GP_REG5 != 0x22) : if (subtype)(type)!=(1xyw)(10) skip qos check */
946 xor GP_REG6, 0x001, GP_REG6; /* bit 0 == 1 if (qos data+!wds frame)|(other+wds frame) */
947 add SPR_BASE1, 0x00F, SPR_BASE5; /* SPR_BASE5 = rx_frame_offs + FR_OFFS_DAT -- load offset to access data */
948 jzx 0, 11, GLOBAL_FLAGS_REG3, 0x000, rx_plcp_not_wds; /* if (!(GLOBAL_FLAGS_REG3 & WDS_FRAME)) */
949 add SPR_BASE5, 0x003, SPR_BASE5; /* add 6 bytes if wds (in this case we have addr4 present) */
951 jzx 1, 5, [0x00,off5], 0x000, not_qos_data; /* if (!(mem[offs5 + 0x0] & 0x60)) goto not_qos_data -- in case a non regular ack is needed */
952 orx 0, 13, 0x001, GLOBAL_FLAGS_REG3, GLOBAL_FLAGS_REG3; /* GLOBAL_FLAGS_REG3 = NOT_REGULAR_ACK | (GLOBAL_FLAGS_REG3 & ~NOT_REGULAR_ACK) */
954 orx 0, 5, GP_REG6, 0x000, SPR_RXE_FIFOCTL1; /* SPR_RXE_FIFOCTL1 = ((GP_REG6<<5) | (GP_REG6>>11)) & 0x20 -- maybe we must forward frames if we are a WDS (??), bit 0x20 will be set with strange combination of qos and wds type, e.g., with no qos data and !wds it is cleared */
955 jext COND_RX_RAMATCH, rx_plcp_and_ra_match; /* If the frame wasn't sent to me update NAV else goto rx_plcp_and_ra_match */
956 jnzx 0, 15, [RX_FRAME_DURATION,off1], 0x000, check_frame_version_validity; /* if (mem[rx_frame_offs + FR_OFFS_DURID] & 0x8000) */
957 or [RX_FRAME_DURATION,off1], 0x000, SPR_NAV_ALLOCATION; /* SPR_NAV_ALLOCATION = mem[rx_frame_offs + FR_OFFS_DURID] */
958 orx 4, 11, 0x002, SPR_NAV_CTL, SPR_NAV_CTL; /* SPR_NAV_Control = 0x1000 | (SPR_NAV_Control & ~0xf800) */
959 jext COND_TRUE, check_frame_version_validity;
960 rx_plcp_and_ra_match:;
961 jzx 0, 4, [SHM_HF_LO], 0x000, check_frame_version_validity; /* if !(SHM_HF_LO & MHF_BTCOEXIST) */
962 orx 0, 8, 0x001, SPR_GPIO_OUT, SPR_GPIO_OUT; /* SPR_GPIO_OUT = SPR_GPIO_OUT | 0x100 */
963 check_frame_version_validity:;
964 jzx 1, 0, [RX_FRAME_FC,off1], 0x000, disable_crypto_engine; /* if (!(mem[rx_frame_offs + FR_OFFS_CTL] & 0x03)) -- We can accept only 802.11 version 0 frames */
965 orx 0, 0, 0x001, GLOBAL_FLAGS_REG3, GLOBAL_FLAGS_REG3; /* GLOBAL_FLAGS_REG3 = RX_FRAME_DISCARD | (GLOBAL_FLAGS_REG3 & ~RX_FRAME_DISCARD) -- This set the bit that allow discard */
966 jext COND_TRUE, rx_too_short;
967 disable_crypto_engine:;
968 mov 0x8300, SPR_WEP_CTL; /* Disable crypto engine */
969 start_frame_analysis:;
970 orx 1, 0, 0x002, SPR_RXE_FIFOCTL1, SPR_RXE_FIFOCTL1; /* SPR_RXE_FIFOCTL1 = 0x2 | (SPR_RXE_FIFOCTL1 & ~0x3) -- clear bit 0*/
971 srx 7, 0, [RX_FRAME_PLCP_0,off1], 0x000, GP_REG0; /* GP_REG0 = first PLCP byte */
972 or RX_PHY_ENCODING, 0x000, GP_REG1; /* GP_REG1 = RX_PHY_ENCODING */
973 call lr0, get_ptr_from_rate_table; /* load off2 and off3 according to GP_REG0 and GP_REG1 */
974 jne RX_TYPE, 0x002, rx_plcp_not_data_frame; /* if (RX_TYPE != 0x02) -- if frame is not a data frame goto rx_plcp_not_data_frame */
975 and RX_TYPE_SUBTYPE, 0x023, GP_REG5; /* GP_REG5 = RX_TYPE_SUBTYPE & 0x23 -- (x000)(10) -> data, can be qos data */
976 je GP_REG5, 0x002, rx_data_plus; /* no qos data */
977 je GP_REG5, 0x022, rx_data_plus; /* qos data, unfortunately we do not implement yet qos... */
978 jext COND_TRUE, send_response_if_ra_match;
979 rx_plcp_not_data_frame:; /* If it is not a data frame */
980 jext COND_RX_FIFOFULL, rx_fifo_overflow;
981 jnzx 0, 15, SPR_RXE_0x1a, 0x000, rx_fifo_overflow; /* if (SPR_RXE_0x1a & 0x8000) */
982 jnext COND_RX_COMPLETE, rx_plcp_not_data_frame; /* Wait until reception is not complete */
983 rx_plcp_wait_RXE_x1a:;
984 jzx 0, 14, SPR_RXE_0x1a, 0x000, rx_plcp_wait_RXE_x1a; /* if (!(SPR_RXE_0x1a & 0x4000)) */
985 srx 0, 5, SPR_RXE_PHYRXSTAT0, 0x000, [SHM_LAST_RX_ANTENNA]; /* shm_last_rx_antenna = ((SPR_RXE_PHYRS_0) >> 5) & 0x1 */
986 jg SPR_RXE_FRAMELEN, [SHM_MAXPDULEN], rx_complete; /* if (SPR_RXE_RX_Frame_len >u shm_max_mpdu_len) */
987 jext COND_RX_FCS_GOOD, rx_plcp_good_fcs;
988 call lr1, check_gphy_sym_war;
989 je GPHY_SYM_WAR_FLAG, 0x000, rx_complete;
990 rx_plcp_good_fcs:; /* Good FCS */
991 jne RX_TYPE, 0x000, rx_plcp_control_frame; /* If it is a control frame goto rx_plcp_control_frame else it is a management frame*/
992 je RX_TYPE_SUBTYPE, TS_BEACON, rx_beacon_probe_resp;
993 je RX_TYPE_SUBTYPE, TS_PROBE_REQ, send_response_if_ra_match;
994 je RX_TYPE_SUBTYPE, TS_PROBE_RESP, rx_beacon_probe_resp;
995 jext COND_TRUE, send_response_if_ra_match;
996 rx_plcp_control_frame:; /* Control frame */
997 je RX_TYPE_SUBTYPE, TS_ACK, rx_ack;
998 je RX_TYPE_SUBTYPE, TS_CTS, rx_ack;
999 and RX_TYPE_SUBTYPE, 0xFFFB, GP_REG5; /* GP_REG5 = RX_TYPE_SUBTYPE & ~0x04 */
1000 jext COND_TRUE, send_control_frame_to_host;
1002 // ***********************************************************************************************
1003 // HANDLER: rx_too_short
1004 // PURPOSE: Reports reception error and checks if frame must be kept.
1007 mov 0x8300, SPR_WEP_CTL; /* Disable crypto engine */
1008 orx 0, 9, 0x001, SPR_BRC, SPR_BRC; /* SPR_BRC = SPR_BRC | RX_ERROR */
1009 jzx 0, 7, SPR_MAC_CTLHI, 0x000, start_frame_analysis; /* if (!(SPR_MAC_Control_High & MCTL_KEEPBADFRAMES)) -- If I don't keep bad frames goto start_frame_analysis */
1010 jext COND_TRUE, state_machine_idle;
1012 // ***********************************************************************************************
1013 // HANDLER: rx_complete
1014 // PURPOSE: Completes reception and classifies frame.
1017 jext COND_REC_IN_PROGRESS, clear_rxe_x1a;
1018 extcond_eoi_only(COND_RX_COMPLETE);
1019 jext COND_TRUE, update_RXE_FIFOCTL1_value;
1021 jzx 0, 14, SPR_RXE_0x1a, 0x000, clear_rxe_x1a; /* if (!(SPR_RXE_0x1a & 0x4000)) -- Wait for this condition to clear */
1022 or SPR_TSF_0x3e, 0x000, [SHM_RXHDR_MACTIME]; /* rx_hdr.RxTSFTime = SPR_TSF_0x3e -- Load TSF time into header */
1023 orx 0, 6, 0x000, SPR_BRC, SPR_BRC; /* SPR_BRC = SPR_BRC & ~REC_IN_PROGRESS */
1024 wait_for_rec_completion:;
1025 jnext EOI(COND_RX_COMPLETE), wait_for_rec_completion;
1026 jg SPR_RXE_FRAMELEN, [SHM_MAXPDULEN], rx_too_long; /* if (SPR_RXE_RX_Frame_len >u shm_max_mpdu_len) -- Too long frame */
1027 jext COND_RX_FCS_GOOD, frame_successfully_received;
1028 jne GPHY_SYM_WAR_FLAG, 0x000, frame_successfully_received;
1029 orx 0, 9, 0x001, SPR_BRC, SPR_BRC; /* SPR_BRC = SPR_BRC | RX_ERROR */
1030 orx 0, 1, 0x000, SPR_BRC, SPR_BRC; /* SPR_BRC = SPR_BRC & ~NEED_RESPONSEFR */
1031 jext COND_RX_FIFOFULL, rx_fifo_overflow;
1032 orx 0, 0, 0x001, [SHM_RXHDR_MACST_LOW], [SHM_RXHDR_MACST_LOW]; /* rx_hdr.RxStatus1 = rx_hdr.RxStatus1 | 0x1 -- Bad FCS? */
1033 orx 0, 0, 0x001, GLOBAL_FLAGS_REG3, GLOBAL_FLAGS_REG3; /* GLOBAL_FLAGS_REG3 = RX_FRAME_DISCARD | (GLOBAL_FLAGS_REG3 & ~RX_FRAME_DISCARD) */
1034 jext COND_TRUE, send_frame_to_host;
1035 frame_successfully_received:;
1036 jext COND_RX_FIFOFULL, rx_fifo_overflow;
1037 jnext COND_NEED_RESPONSEFR, check_frame_subtype;
1038 jzx 0, 13, GLOBAL_FLAGS_REG3, 0x000, need_regular_ack; /* if (!(GLOBAL_FLAGS_REG3 & NOT_REGULAR_ACK)) */
1039 orx 0, 1, 0x000, SPR_BRC, SPR_BRC; /* SPR_BRC = SPR_BRC & ~NEED_RESPONSEFR */
1040 jext COND_TRUE, check_frame_subtype;
1042 je [SHM_CURMOD], 0x001, ofdm_modulation; /* check if this response need short preamble */
1043 jne [SHM_CURMOD], 0x000, no_cck_modulation; /* Not CCK modulation */
1044 jzx 3, 4, [0x01,off2], 0x000, ofdm_modulation; /* if( ((mem[offs2 + 0x1] >> 4) & 0xF) == 0 ) */
1046 srx 0, 7, SPR_RXE_PHYRXSTAT0, 0x000, GP_REG5; /* GP_REG5 = ((SPR_RXE_PHYRXSTAT0) >> 7) & 0x1, if set the received frame used short preamble */
1047 orx 0, 4, GP_REG5, SPR_TXE0_PHY_CTL, SPR_TXE0_PHY_CTL; /* SPR_TXE0_PHY_Control = (((GP_REG5<<4) | (GP_REG5>>12)) & 0x10) | (SPR_TXE0_PHY_Control & ~0x10) */
1049 orx 0, 1, 0x001, [SHM_RXHDR_MACST_LOW], [SHM_RXHDR_MACST_LOW]; /* rx_hdr.RxStatus1 = rx_hdr.RxStatus1 | 0x2 */
1050 or NEXT_TXE0_CTL, 0x000, SPR_TXE0_CTL; /* SPR_TXE0_CTL = NEXT_TXE0_CTL */
1051 check_frame_subtype:;
1052 srx 1, 0, RX_TYPE_SUBTYPE, 0x000, GP_REG5; /* GP_REG5 = (RX_TYPE_SUBTYPE) & 0x3 */
1053 je GP_REG5, 0x001, rx_control_frame; /* If it is a control frame goto rx_control_frame */
1054 jext COND_RX_RAMATCH, rx_frame_and_ra_match;
1055 jzx 0, 0, [RX_FRAME_ADDR1_1,off1], 0x000, not_multicast_frame; /* if (!IS_MULTICAST(rx_frame)) */
1056 jne RX_TYPE, 0x002, rx_not_data_frame_type; /* if it is not a data frame (so it is a management frame) goto rx_not_data_frame_type*/
1057 rx_not_data_frame_type:;
1058 jnzx 0, 11, GLOBAL_FLAGS_REG3, 0x000, send_frame_to_host; /* if (GLOBAL_FLAGS_REG3 & WDS_FRAME) */
1059 jnzx 0, 8, [RX_FRAME_FC,off1], 0x000, discard_frame; /* if (CTL_TO_DS(rx_frame) -- Management frame not sent to me, we can discard it*/
1060 jnzx 0, 9, [RX_FRAME_FC,off1], 0x000, control_frame_from_ds; /* if (CTL_FROM_DS(rx_frame) -- Can be some management frame like beacon or probe response */
1061 jext COND_RX_BSSMATCH, frame_from_our_BSS; /* Is it a frame which belongs to our BSS? */
1062 jext COND_TRUE, could_be_multicast_frame;
1063 control_frame_from_ds:;
1064 jnext 0x62, could_be_multicast_frame;
1065 je RX_TYPE_SUBTYPE, TS_BEACON, frame_from_our_BSS; /* A beacon from my AP! */
1066 orx 0, 6, 0x001, GLOBAL_FLAGS_REG3, GLOBAL_FLAGS_REG3; /* GLOBAL_FLAGS_REG3 = GLOBAL_FLAGS_REG3 | 0x40 */
1067 frame_from_our_BSS:;
1068 je RX_TYPE_SUBTYPE, TS_PROBE_REQ, send_frame_to_host; /* A probe request from a station within our BSS */
1069 jext COND_TRUE, send_frame_to_host;
1070 not_multicast_frame:;
1071 jnext 0x3D, check_frame_type;
1072 jnext 0x62, check_frame_type;
1073 orx 0, 6, 0x000, GLOBAL_FLAGS_REG3, GLOBAL_FLAGS_REG3; /* GLOBAL_FLAGS_REG3 := GLOBAL_FLAGS_REG3 & ~0x40 */
1075 jne RX_TYPE, 0x002, not_data_frame_and_ra_doesnt_match; /* If it is not a data frame goto not_data_frame_and_ra_doesnt_match */
1076 jext COND_TRUE, data_frame_and_ra_doesnt_match;
1077 could_be_multicast_frame:;
1078 je RX_TYPE, 0x002, data_frame_and_ra_doesnt_match; /* If it is a data frame goto data_frame_and_ra_doesnt_match */
1079 jnzx 0, 0, [RX_FRAME_ADDR3_1,off1], 0x000, send_frame_to_host; /* if (mem[rx_frame_offs + FR_OFFS_ADDR3] & 0x01) -- Multicast frame? */
1080 not_data_frame_and_ra_doesnt_match:;
1081 jzx 0, 4, SPR_MAC_CTLHI, 0x000, data_frame_and_ra_doesnt_match; /* if (!(SPR_MAC_Control_High & MCTL_BCNS_PROMISC) */
1082 je RX_TYPE_SUBTYPE, TS_BEACON, send_frame_to_host;
1083 je RX_TYPE_SUBTYPE, TS_PROBE_RESP, send_frame_to_host;
1084 data_frame_and_ra_doesnt_match:;
1085 jzx 0, 8, SPR_MAC_CTLHI, 0x000, discard_frame; /* if (!(SPR_MAC_Control_High & MCTL_PROMISC)) */
1086 jext COND_TRUE, send_frame_to_host;
1088 jnext COND_RX_RAMATCH, send_frame_to_host;
1089 je RX_TYPE_SUBTYPE, TS_RTS, send_frame_to_host;
1090 je RX_TYPE_SUBTYPE, TS_PSPOLL, send_frame_to_host;
1091 jext COND_TRUE, send_frame_to_host;
1092 rx_frame_and_ra_match:; /* Here frames whose RA match my address */
1093 jzx 0, 11, GLOBAL_FLAGS_REG3, 0x000, not_wds_frame; /* if (!(GLOBAL_FLAGS_REG3 & WDS_FRAME)) */
1094 jext COND_TRUE, send_frame_to_host;
1096 jnext COND_FRAME_NEED_ACK, send_frame_to_host;
1097 srx 5, 2, [TXHDR_FCTL,off0], 0x000, GP_REG7; /* GP_REG7 = ((tx_info.fctl) >> 2) & 0x3f */
1099 // ***********************************************************************************************
1100 // HANDLER: send_frame_to_host
1101 // PURPOSE: Prepares the frame before sending it to the host.
1103 send_frame_to_host:;
1104 jnzx 0, 7, SPR_MAC_CTLHI, 0x000, keep_bad_frames; /* if (SPR_MAC_Control_High & MCTL_KEEPBADFRAMES) -- Keep bad frame for the Linux driver */
1105 jnzx 0, 0, GLOBAL_FLAGS_REG3, 0x000, discard_frame; /* if (GLOBAL_FLAGS_REG3 & RX_FRAME_DISCARD) -- If I don't keep bad frame set discard frame bit */
1107 or SPR_RXE_FRAMELEN, 0x000, GP_REG5; /* GP_REG5 = SPR_RXE_RX_Frame_len */
1108 or GP_REG5, 0x000, [SHM_RXHDR_FLEN]; /* rx_hdr.RxFrameSize = GP_REG5 */
1109 jzx 0, 5, SPR_RXE_FIFOCTL1, 0x000, no_hdr_length_update; /* if (!(SPR_RXE_FIFOCTL1 & 0x20)) */
1110 add GP_REG5, [SHM_RXPADOFF], [SHM_RXHDR_FLEN]; /* rx_hdr.RxFrameSize = GP_REG5 + shm_rx_pad_data_offset */
1111 orx 0, 2, 0x001, [SHM_RXHDR_MACST_LOW], [SHM_RXHDR_MACST_LOW]; /* rx_hdr.RxStatus1 = rx_hdr.RxStatus1 | 0x4: tell Linux we have padding */
1112 no_hdr_length_update:;
1113 srx 0, 4, GLOBAL_FLAGS_REG3, 0x000, GP_REG5; /* GP_REG5 = ((GLOBAL_FLAGS_REG3) >> 4) & 0x1 -- 1 if I received a beacon (not sure) */
1114 orx 0, 15, GP_REG5, [SHM_RXHDR_MACST_LOW], [SHM_RXHDR_MACST_LOW]; /* rx_hdr.RxStatus1 = (((GP_REG5<<15) | (GP_REG5>>1)) & 0x8000) | (rx_hdr.RxStatus1 & ~0x8000) */
1115 wait_crypto_engine:;
1116 jext COND_RX_FIFOFULL, rx_fifo_overflow;
1117 jext COND_RX_CRYPTBUSY, wait_crypto_engine;
1118 srx 0, 15, SPR_WEP_CTL, 0x000, GP_REG5; /* GP_REG5 = ((SPR_WEP_Control) >> 15) & 0x1 */
1119 orx 0, 4, GP_REG5, [SHM_RXHDR_MACST_LOW], [SHM_RXHDR_MACST_LOW]; /* rx_hdr.RxStatus1 := (((GP_REG5<<4) | (GP_REG5>>12)) & 0x10) | (rx_hdr.RxStatus1 & ~0x10) */
1120 or SPR_RXE_PHYRXSTAT0, 0x000, [SHM_RXHDR_PHYST0]; /* rx_hdr.PhyRxStatus_0 = SPR_RXE_PHYRS_0 */
1121 or SPR_RXE_PHYRXSTAT1, 0x000, [SHM_RXHDR_PHYST1]; /* rx_hdr.PhyRxStatus_1 = SPR_RXE_PHYRS_1 */
1122 or SPR_RXE_PHYRXSTAT2, 0x000, [SHM_RXHDR_PHYST2]; /* rx_hdr.PhyRxStatus_2 = SPR_RXE_PHYRS_2 */
1123 or SPR_RXE_PHYRXSTAT3, 0x000, [SHM_RXHDR_PHYST3]; /* rx_hdr.PhyRxStatus_3 = SPR_RXE_PHYRS_3 */
1124 srx 0, 5, SPR_RXE_PHYRXSTAT0, 0x000, [SHM_LAST_RX_ANTENNA]; /* shm_last_rx_antenna = ((SPR_RXE_PHYRS_0) >> 5) & 0x1 */
1125 mov 0xFFFE, ANTENNA_DIVERSITY_CTR;
1126 call lr1, antenna_diversity_helper;
1127 call lr0, push_frame_into_fifo;
1128 nand SPR_RXE_FIFOCTL1, 0x002, SPR_RXE_FIFOCTL1; /* SPR_RXE_FIFOCTL1 = SPR_RXE_FIFOCTL1 & ~0x02 */
1129 jext COND_TRUE, tx_contention_params_update;
1131 // ***********************************************************************************************
1132 // HANDLER: rx_too_long
1133 // PURPOSE: Reports reception error.
1136 orx 0, 8, 0x001, SPR_BRC, SPR_BRC; /* SPR_BRC = SPR_BRC | TX_ERROR */
1137 orx 0, 9, 0x001, SPR_BRC, SPR_BRC; /* SPR_BRC = SPR_BRC | RX_ERROR */
1138 jext COND_TRUE, discard_frame;
1140 // ***********************************************************************************************
1142 // PURPOSE:i Performs operations related to ACK reception.
1145 jnext COND_RX_RAMATCH, send_control_frame_to_host;
1146 jnext COND_FRAME_NEED_ACK, send_control_frame_to_host;
1147 jne RX_TYPE_SUBTYPE, EXPECTED_CTL_RESPONSE, send_control_frame_to_host;
1148 orx 0, 15, 0x000, SPR_TXE0_TIMEOUT, SPR_TXE0_TIMEOUT; /* SPR_TXE0_TIMEOUT = SPR_TXE0_TIMEOUT & ~0x8000 */
1149 orx 0, 8, 0x000, SPR_BRC, SPR_BRC; /* SPR_BRC = SPR_BRC & ~TX_ERROR */
1150 or GP_REG5, 0x000, GP_REG5;
1151 jle 0x000, 0x001, flush_pipe;
1153 extcond_eoi_only(COND_TX_PMQ);
1154 jzx 0, 8, [SHM_HF_LO], 0x000, send_control_frame_to_host; /* if (!(SHM_HF_LO & MHF_EDCF)) */
1155 jnext 0x28, send_control_frame_to_host;
1156 orx 0, 9, 0x001, GLOBAL_FLAGS_REG1, GLOBAL_FLAGS_REG1; /* GLOBAL_FLAGS_REG1 = GLOBAL_FLAGS_REG1 | 0x200 */
1158 // ***********************************************************************************************
1159 // HANDLER: send_control_frame_to_host
1160 // PURPOSE: Decides if control frame must be sent to host.
1162 send_control_frame_to_host:;
1163 jext COND_RX_RAMATCH, send_control_frame_and_ra_match;
1164 jzx 0, 8, SPR_MAC_CTLHI, 0x000, rx_discard_frame; /* if (!(SPR_MAC_Control_High & MCTL_PROMISC)) */
1165 send_control_frame_and_ra_match:;
1166 jnzx 0, 6, SPR_MAC_CTLHI, 0x000, rx_complete; /* if (SPR_MAC_Control_High & MCTL_KEEPCONTROL) */
1167 jext COND_TRUE, rx_discard_frame;
1169 // ***********************************************************************************************
1170 // HANDLER: rx_check_promisc
1171 // PURPOSE: Controls if promiscuous mode was enable.
1174 jnzx 0, 8, SPR_MAC_CTLHI, 0x000, rx_complete; /* if (SPR_MAC_Control_High & MCTL_PROMISC) */
1176 // ***********************************************************************************************
1177 // HANDLER: rx_discard_frame
1178 // PURPOSE: Commands a frame discard.
1181 orx 0, 0, 0x001, GLOBAL_FLAGS_REG3, GLOBAL_FLAGS_REG3; /* GLOBAL_FLAGS_REG3 = RX_FRAME_DISCARD | (GLOBAL_FLAGS_REG3 & ~RX_FRAME_DISCARD) */
1182 jext COND_TRUE, rx_complete;
1184 // ***********************************************************************************************
1185 // HANDLER: rx_data_plus
1186 // PURPOSE: Manages data frame reception.
1189 jext COND_RX_COMPLETE, end_rx_data_plus;
1190 jl SPR_RXE_FRAMELEN, 0x01C, rx_data_plus;
1192 jl SPR_RXE_FRAMELEN, 0x01C, rx_check_promisc;
1193 jnext COND_RX_RAMATCH, rx_ra_dont_match;
1194 jext COND_TRUE, send_response;
1196 // ***********************************************************************************************
1197 // HANDLER: tx_underflow
1198 // PURPOSE: Prepares device for TX underflow error management.
1201 orx 0, 14, 0x001, [SHM_TXFCUR], SPR_TXE0_FIFO_CMD; /* SPR_TXE0_FIFO_CMD = SHM_TXFCUR | 0x4000 */
1202 mov 0x0307, SPR_WEP_0x50;
1203 orx 0, 8, 0x001, SPR_BRC, SPR_BRC; /* SPR_BRC = SPR_BRC | TX_ERROR */
1204 jand 0x007, SPR_BRC, tx_fifo_underflow; /* if !(SPR_BRC & (COND_NEED_BEACON | COND_NEED_RESPONSEFR | COND_NEED_PROBE_RESP)) */
1205 jext COND_TRUE, check_underflow_cond;
1207 // ***********************************************************************************************
1208 // HANDLER: tx_fifo_underflow
1209 // PURPOSE: Manages TX underflow error.
1212 mov 0x0076, GP_REG5; /* GP_REG5 = M_TXFIFO_UFLO_OFFS */
1213 srx 2, 8, [SHM_TXFCUR], 0x000, GP_REG6; /* GP_REG6 = ((SHM_TXFCUR) >> 8) & 0x7 */
1214 add GP_REG5, GP_REG6, SPR_BASE5; /* SPR_BASE5 = GP_REG5 + GP_REG6 */
1215 add [0x00,off5], 0x001, [0x00,off5];
1216 orx 2, 2, 0x006, [TXHDR_STAT,off0], [TXHDR_STAT,off0]; /* tx_info.tx_status = SUPP_BUF_UFLO | (tx_info.tx_status & ~SUPPRESS_MASK) */
1218 mov 0x0001, GP_REG7;
1219 tx_dont_clear_issues:;
1220 jnext COND_FRAME_NEED_ACK, check_underflow_cond;
1221 orx 0, 7, 0x000, SPR_BRC, SPR_BRC; /* SPR_BRC = SPR_BRC & ~FRAME_NEED_ACK */
1222 mov 0, EXPECTED_CTL_RESPONSE;
1223 orx 0, 15, 0x000, SPR_TXE0_TIMEOUT, SPR_TXE0_TIMEOUT; /* SPR_TXE0_TIMEOUT = SPR_TXE0_TIMEOUT & ~0x8000 */
1224 orx 0, 4, 0x000, SPR_BRC, SPR_BRC; /* SPR_BRC = SPR_BRC & ~MORE_FRAGMENT */
1225 call lr1, set_backoff_time;
1226 check_underflow_cond:;
1227 extcond_eoi_only(COND_TX_POWER);
1228 extcond_eoi_only(COND_TX_NOW);
1229 orx 0, 5, 0x000, SPR_BRC, SPR_BRC; /* SPR_BRC = SPR_BRC & ~FRAME_BURST */
1230 extcond_eoi_only(COND_TX_UNDERFLOW);
1231 mov 0, SPR_TXE0_SELECT;
1232 mov 0x0007, GP_REG5;
1233 je [SHM_PHYTYPE], 0x000, end_tx_fifo_underflow; /* if (shm_phy_type == PHY_TYPE_A) */
1234 orx 0, 10, SPR_TXE0_PHY_CTL, GP_REG5, GP_REG5; /* GP_REG5 = (((SPR_TXE0_PHY_Control<<10) | (SPR_TXE0_PHY_Control>>6)) & 0x400) | (GP_REG5 & ~0x400) */
1235 end_tx_fifo_underflow:;
1236 call lr0, sel_phy_reg;
1237 or SPR_Ext_IHR_Data, 0x000, GP_REG9; /* GP_REG9 = SPR_Ext_IHR_Data */
1238 mov 0xFFFF, GP_REG6;
1239 call lr0, write_phy_reg;
1240 xor GP_REG5, GP_REG8, GP_REG5;
1241 call lr0, write_phy_reg;
1242 je GP_REG7, 0x000, state_machine_idle;
1243 or GP_REG9, 0x000, [TXHDR_RTSPHYSTAT,off0];
1244 jext COND_TRUE, suppress_this_frame;
1246 // ***********************************************************************************************
1247 // HANDLER: tx_phy_error
1248 // PURPOSE: Manages TX phy errors.
1251 jext COND_FRAME_BURST, check_rx_conditions;
1252 jext COND_FRAME_NEED_ACK, tx_clear_issues;
1254 jext COND_TRUE, tx_dont_clear_issues;
1256 // ***********************************************************************************************
1257 // HANDLER: rx_fifo_overflow
1258 // PURPOSE: Manages RX overflow error.
1259 // Is the first instruction useful to clear some hardware exception? Can be safely removed?
1262 jg SPR_RXE_FRAMELEN, [SHM_MAXPDULEN], overflow_frame_too_long; /* if (SPR_RXE_RX_Frame_len >u shm_max_mpdu_len) */
1263 overflow_frame_too_long:;
1264 jext COND_REC_IN_PROGRESS, rx_complete;
1265 extcond_eoi_only(COND_RX_FIFOFULL);
1266 orx 0, 9, 0x001, SPR_BRC, SPR_BRC; /* SPR_BRC = SPR_BRC | RX_ERROR */
1267 jext COND_TRUE, discard_frame;
1269 // ***********************************************************************************************
1270 // HANDLER: mac_suspend_check
1271 // PURPOSE: Checks if device can be suspended.
1272 // The condition on SPR_BRC involves
1273 // COND_NEED_RESPONSEFR|COND_FRAME_BURST|COND_REC_IN_PROGRESS|COND_FRAME_NEED_ACK
1276 jnand 0x0E2, SPR_BRC, check_conditions; /* if (0xe2 & SPR_BRC) */
1277 jnzx 0, 8, SPR_IFS_STAT, 0x000, check_conditions;
1278 jext COND_TX_DONE, check_conditions;
1279 jext COND_TX_PHYERR, check_conditions;
1281 mov 0x002, GP_REG11;
1282 jext COND_TRUE, flush_and_stop_tx_engine;
1283 return_flush_into_mac_suspend_check:
1285 // ***********************************************************************************************
1286 // HANDLER: mac_suspend
1287 // PURPOSE: Suspends device.
1290 mov 0x0001, SPR_MAC_IRQLO; /* SPR_MAC_Interrupt_Status_Low = MI_MACSSPNDD */
1291 mov 0x0003, [SHM_UCODESTAT]; /* shm_debug_status = DBGST_SUSPENDED */
1292 mov 0x0303, SPR_WEP_0x50; /* SPR_WEP_0x50 = 0x0303 */
1293 wait_for_mac_to_disable:;
1294 jnext COND_MACEN, wait_for_mac_to_disable;
1295 mov 0x0002, [SHM_UCODESTAT]; /* shm_debug_status = DBGST_ACTIVE */
1296 srx 0, 15, SPR_MAC_CTLHI, 0x000, GLOBAL_FLAGS_REG1; /* GLOBAL_FLAGS_REG1 = ((SPR_MAC_Control_High) >> 15) & GMODE */
1297 mov 0x0301, SPR_WEP_0x50; /* SPR_WEP_0x50 = 0x0301 */
1298 mov 0x8300, SPR_WEP_CTL; /* Disable hardware crypto */
1300 nand GLOBAL_FLAGS_REG2, 0x01A, GLOBAL_FLAGS_REG2; /* GLOBAL_FLAGS_REG2 = GLOBAL_FLAGS_REG2 & ~AFTERBURNER_TX|0x18 */
1301 mov 0xFFFF, SPR_BRCL0;
1302 mov 0xFFFF, SPR_BRCL1;
1303 mov 0xFFFF, SPR_BRCL2;
1304 mov 0xFFFF, SPR_BRCL3;
1305 orx 0, 2, 0x001, SPR_RXE_FIFOCTL1, SPR_RXE_FIFOCTL1; /* SPR_RXE_FIFOCTL1 = SPR_RXE_FIFOCTL1 | 0x4 */
1306 wait_RXE_FIFOCTL1_cond_to_clear:;
1307 jnzx 0, 2, SPR_RXE_FIFOCTL1, 0x000, wait_RXE_FIFOCTL1_cond_to_clear; /* if (SPR_RXE_FIFOCTL1 & 0x04) */
1312 srx 0, 14, SPR_MAC_CTLHI, 0x000, GP_REG5; /* GP_REG5 = ((SPR_MAC_Control_High) >> 14) & 0x1 */
1313 xor GP_REG5, 0x001, GP_REG5;
1314 mov 0x7360, SPR_BRWK0;
1316 mov 0x730F, SPR_BRWK2;
1317 mov 0x0057, SPR_BRWK3;
1318 jext COND_TRUE, state_machine_start;
1320 // ***********************************************************************************************
1321 // HANDLER: rx_badplcp
1322 // PURPOSE: Manages reception of a frame with not valid PLCP.
1325 jnzx 0, 11, SPR_RXE_0x1a, 0x000, state_machine_idle; /* if (SPR_RXE_0x1a & 0x800) */
1326 jnzx 0, 12, SPR_RXE_0x1a, 0x000, rx_badplcp; /* if (SPR_RXE_0x1a & 0x1000) */
1327 orx 0, 4, 0x001, GLOBAL_FLAGS_REG2, GLOBAL_FLAGS_REG2; /* GLOBAL_FLAGS_REG2 = GLOBAL_FLAGS_REG2 | 0x10 */
1328 jext COND_RX_FIFOFULL, rx_fifo_overflow;
1329 jnzx 0, 15, SPR_RXE_0x1a, 0x000, rx_fifo_overflow;
1330 update_RXE_FIFOCTL1_value:;
1331 mov 0x0004, SPR_RXE_FIFOCTL1; /* SPR_RXE_FIFOCTL1 = 0x0004 */
1332 or SPR_RXE_FIFOCTL1, 0x000, GP_REG5; /* GP_REG5 = SPR_RXE_FIFOCTL1 */
1333 jext COND_TRUE, state_machine_start;
1335 // ***********************************************************************************************
1336 // HANDLER: discard_frame
1337 // PURPOSE: Discards the frame into the FIFO.
1340 mov 0x0014, SPR_RXE_FIFOCTL1;
1341 or SPR_RXE_FIFOCTL1, 0x000, 0x000; /* 0x000 = SPR_RXE_FIFOCTL1 */
1342 srx 2, 5, SPR_WEP_CTL, 0x000, GP_REG5; /* GP_REG5 = ((SPR_WEP_Control) >> 5) & 0x7 */
1343 jnext COND_RX_ERROR, tx_contention_params_update;
1344 orx 0, 12, 0x001, GLOBAL_FLAGS_REG1, GLOBAL_FLAGS_REG1; /* GLOBAL_FLAGS_REG1 = GLOBAL_FLAGS_REG1 | 0x1000 */
1345 mov 0x003, GP_REG11;
1346 jext COND_TRUE, flush_and_stop_tx_engine;
1347 return_flush_into_discard_frame:
1348 orx 0, 0, 0x001, SPR_TXE0_AUX, SPR_TXE0_AUX; /* SPR_TXE0_Aux = SPR_TXE0_Aux | 0x1 */
1349 or GP_REG5, 0x000, GP_REG5;
1350 orx 0, 0, 0x000, SPR_TXE0_AUX, SPR_TXE0_AUX; /* SPR_TXE0_Aux = SPR_TXE0_Aux & ~0x1 */
1351 jext COND_TRUE, tx_contention_params_update;
1353 // ***********************************************************************************************
1354 // HANDLER: flush_and_stop_tx_engine
1355 // PURPOSE: Checks if there are any other frames into the queue, flushes the TX engine and stops it.
1357 flush_and_stop_tx_engine:;
1358 mov 0x4000, SPR_TXE0_CTL; /* Enable FCS calculation */
1359 or SPR_TXE0_CTL, 0x000, 0x000; /* 0x000 = SPR_TXE0_CTL */
1360 jle 0x000, 0x001, check_pending_tx_and_stop;
1361 check_pending_tx_and_stop:;
1362 jext EOI(COND_TX_NOW), tx_frame_now;
1363 pending_tx_resolved:;
1364 nand SPR_BRC, 0x027, SPR_BRC; /* SPR_BRC = (SPR_BRC & ~(FRAME_BURST | NEED_BEACON | NEED_RESPONSEFR | NEED_PROBE_RESP) */
1365 mov 0, SPR_TXE0_SELECT;
1366 orx 0, 15, 0x000, SPR_TXE0_TIMEOUT, SPR_TXE0_TIMEOUT; /* SPR_TXE0_TIMEOUT = SPR_TXE0_TIMEOUT & ~0x8000 */
1367 orx 0, 4, 0x000, SPR_BRC, SPR_BRC; /* SPR_BRC = SPR_BRC & ~MORE_FRAGMENT -- clear tx_more_frag bit */
1368 jnzx 0, 9, SPR_WEP_CTL, 0x000, jump_wep_update; /* if (SPR_WEP_Control & 0x200) */
1369 orx 7, 8, 0x002, 0x000, SPR_WEP_CTL; /* SPR_WEP_Control = 0x0200 */
1371 orx 1, 12, 0x000, GLOBAL_FLAGS_REG1, GLOBAL_FLAGS_REG1; /* GLOBAL_FLAGS_REG1 = GLOBAL_FLAGS_REG1 & ~0x3000 */
1372 jne GP_REG11, 0x001, no_prepare_beacon_tx_return;
1373 jext COND_TRUE, return_flush_into_prepare_beacon_tx;
1374 no_prepare_beacon_tx_return:
1375 jne GP_REG11, 0x002, no_mac_suspend_check_return;
1376 jext COND_TRUE, return_flush_into_mac_suspend_check;
1377 no_mac_suspend_check_return:;
1378 jne GP_REG11, 0x003, no_discard_frame_return;
1379 jext COND_TRUE, return_flush_into_discard_frame;
1380 no_discard_frame_return:
1381 jext COND_TRUE, return_flush_into_rx_beacon;
1383 // ***********************************************************************************************
1384 // HANDLER: rx_beacon_probe_resp
1385 // PURPOSE: Analyzes Beacon or Probe Response frame that has been received. Important for time synchronization.
1386 // off3 is a pointer that has been load before by get_ptr_from_rate_table with a value coming
1387 // from the second level rate tables, e.g., on a beacon in 2.4MHz off3 = 0x37E
1389 rx_beacon_probe_resp:;
1390 jl SPR_RXE_FRAMELEN, 0x02C, rx_discard_frame;
1391 jext COND_RX_BSSMATCH, rx_bss_match;
1392 je RX_TYPE_SUBTYPE, TS_PROBE_RESP, rx_beacon_probe_resp_end;
1393 jext COND_TRUE, no_time_informations;
1395 je RX_TYPE_SUBTYPE, TS_PROBE_RESP, check_beacon_time;
1396 jext 0x3E, rx_beacon_probe_resp_end;
1397 jext 0x3D, check_beacon_time;
1398 jext COND_CONTENTION_PARAM_MODIFIED, check_beacon_time;
1399 mov 0x004, GP_REG11;
1400 jext COND_TRUE, flush_and_stop_tx_engine;
1401 return_flush_into_rx_beacon:;
1402 extcond_eoi_only(COND_TX_TBTTEXPIRE);
1403 orx 0, 0, 0x000, SPR_BRC, SPR_BRC; /* SPR_BRC = SPR_BRC & ~NEED_BEACON */
1404 orx 0, 3, 0x000, SPR_BRC, SPR_BRC; /* SPR_BRC = SPR_BRC & ~CONTENTION_PARAM_MODIFIED */
1405 orx 7, 8, 0x000, 0x010, SPR_MAC_IRQLO;
1406 jnzx 0, 0, SPR_TSF_0x0e, 0x000, succ_bcn_tx;
1407 or NEXT_IFS, 0x000, SPR_IFS_BKOFFDELAY;
1408 orx 7, 8, 0x000, 0x000, NEXT_IFS;
1409 or NEXT_CONTENTION_WIN, 0x000, CUR_CONTENTION_WIN;
1410 or MIN_CONTENTION_WIN, 0x000, NEXT_CONTENTION_WIN;
1411 jext COND_TRUE, check_beacon_time;
1413 and SPR_TSF_Random, MIN_CONTENTION_WIN, SPR_IFS_BKOFFDELAY;
1415 jext 0x3E, rx_beacon_probe_resp_end;
1416 or [SHM_TBL_OFF2DUR], 0x000, GP_REG5;
1417 add GP_REG5, [0x00,off3], GP_REG5;
1418 add. RX_TIME_WORD0, GP_REG5, RX_TIME_WORD0;
1419 addc. RX_TIME_WORD1, 0x000, RX_TIME_WORD1;
1420 addc. RX_TIME_WORD2, 0x000, RX_TIME_WORD2;
1421 addc RX_TIME_WORD3, 0x000, RX_TIME_WORD3;
1422 jext 0x3D, sync_TSF;
1423 jg RX_TIME_WORD3, [RX_FRAME_BCN_TIMESTAMP_3,off1], rx_beacon_probe_resp_end; /* if (rx_time_word_3 >u mem[rx_frame_offs + FR_OFFS_BCN_TIMESTAMP_3]) */
1424 jl RX_TIME_WORD3, [RX_FRAME_BCN_TIMESTAMP_3,off1], sync_TSF; /* if (rx_time_word_3 <u mem[rx_frame_offs + FR_OFFS_BCN_TIMESTAMP_3]) */
1425 jg RX_TIME_WORD2, [RX_FRAME_BCN_TIMESTAMP_2,off1], rx_beacon_probe_resp_end; /* if (rx_time_word_2 >u mem[rx_frame_offs + FR_OFFS_BCN_TIMESTAMP_2]) */
1426 jl RX_TIME_WORD2, [RX_FRAME_BCN_TIMESTAMP_2,off1], sync_TSF; /* if (rx_time_word_2 <u mem[rx_frame_offs + FR_OFFS_BCN_TIMESTAMP_2]) */
1427 jg RX_TIME_WORD1, [RX_FRAME_BCN_TIMESTAMP_1,off1], rx_beacon_probe_resp_end; /* if (rx_time_word_1 >u mem[rx_frame_offs + FR_OFFS_BCN_TIMESTAMP_1]) */
1428 jl RX_TIME_WORD1, [RX_FRAME_BCN_TIMESTAMP_1,off1], sync_TSF; /* if (rx_time_word_1 <u mem[rx_frame_offs + FR_OFFS_BCN_TIMESTAMP_1]) */
1429 jge RX_TIME_WORD0, [RX_FRAME_BCN_TIMESTAMP_0,off1], rx_beacon_probe_resp_end; /* if (rx_time_word_0 >=u mem[rx_frame_offs + FR_OFFS_DATA]) */
1431 or SPR_TSF_WORD0, 0x000, [SHM_RX_TIME_WORD0];
1432 or SPR_TSF_WORD1, 0x000, [SHM_RX_TIME_WORD1];
1433 or SPR_TSF_WORD2, 0x000, [SHM_RX_TIME_WORD2];
1434 or SPR_TSF_WORD3, 0x000, [SHM_RX_TIME_WORD3];
1435 jne [SHM_RX_TIME_WORD0], SPR_TSF_WORD0, sync_TSF;
1436 sub. [SHM_RX_TIME_WORD0], RX_TIME_WORD0, RX_TIME_WORD0;
1437 subc. [SHM_RX_TIME_WORD1], RX_TIME_WORD1, RX_TIME_WORD1;
1438 subc. [SHM_RX_TIME_WORD2], RX_TIME_WORD2, RX_TIME_WORD2;
1439 subc [SHM_RX_TIME_WORD3], RX_TIME_WORD3, RX_TIME_WORD3;
1441 add. RX_TIME_WORD0, [RX_FRAME_BCN_TIMESTAMP_0,off1], GP_REG5;
1442 or GP_REG5, 0x000, SPR_TSF_WORD0;
1443 addc. RX_TIME_WORD1, [RX_FRAME_BCN_TIMESTAMP_1,off1], SPR_TSF_WORD1; /* SPR_TSF_word_1 = rx_time_word_1 + mem[rx_frame_offs + FR_OFFS_BCN_TIMESTAMP_1] + carry [set carry] */
1444 addc. RX_TIME_WORD2, [RX_FRAME_BCN_TIMESTAMP_2,off1], SPR_TSF_WORD2; /* SPR_TSF_word_2 = rx_time_word_2 + mem[rx_frame_offs + FR_OFFS_BCN_TIMESTAMP_2] + carry [set carry] */
1445 addc. RX_TIME_WORD3, [RX_FRAME_BCN_TIMESTAMP_3,off1], SPR_TSF_WORD3; /* SPR_TSF_word_3 = rx_time_word_3 + mem[rx_frame_offs + FR_OFFS_BCN_TIMESTAMP_3] + carry [set carry] */
1446 jne GP_REG5, SPR_TSF_WORD0, update_TSF_words;
1447 jnext 0x3D, rx_beacon_probe_resp_end;
1448 no_time_informations:;
1449 je RX_TYPE_SUBTYPE, TS_PROBE_RESP, rx_beacon_probe_resp_end;
1450 mov 0x051D, SPR_BASE5; /* 0x51d = rx_frame_offs + 42 --> plcp + fixed beacon fields */
1451 mov 0x0004, GP_REG8;
1452 call lr0, find_dtim_info_elem;
1453 jnext 0x3D, rx_beacon_probe_resp_end;
1454 jext 0x3E, rx_beacon_probe_resp_end;
1455 jnext COND_RX_BSSMATCH, rx_beacon_probe_resp_end;
1456 je RX_TYPE_SUBTYPE, TS_PROBE_RESP, rx_beacon_probe_resp_end;
1457 mov 0x0005, GP_REG8;
1458 call lr0, find_dtim_info_elem;
1459 jne GP_REG8, 0x005, rx_beacon_probe_resp_end;
1460 srx 7, 8, [0x01,off5], 0x000, CURRENT_DTIM_COUNT; /* current_dtim_count = ((mem[offs5 + 0x1]) >> 8) & 0xff */
1461 srx 7, 8, [0x02,off5], 0x000, GP_REG5; /* GP_REG5 = ((mem[offs5 + 0x2]) >> 8) & 0xff */
1462 orx 0, 6, GP_REG5, GLOBAL_FLAGS_REG3, GLOBAL_FLAGS_REG3; /* GLOBAL_FLAGS_REG3 = (((GP_REG5<<6) | (GP_REG5>>10)) & 0x40) | (GLOBAL_FLAGS_REG3 & ~0x40) */
1463 orx 0, 15, GP_REG5, SPR_TSF_GPT1_STAT, SPR_TSF_GPT1_STAT; /* SPR_TSF_GPT1_Stat = (((GP_REG5<<15) | (GP_REG5>>1)) & 0x8000) | (SPR_TSF_GPT1_Stat & ~TSF_GPT_ENABLE) */
1464 rx_beacon_probe_resp_end:;
1465 jext COND_RX_RAMATCH, send_response;
1466 jext COND_TRUE, rx_complete;
1468 // ***********************************************************************************************
1469 // HANDLER: send_response_if_ra_match
1470 // PURPOSE: Decides if frame needs a response.
1472 send_response_if_ra_match:;
1473 jext COND_RX_RAMATCH, send_response;
1475 jzx 0, 0, [RX_FRAME_ADDR1_1,off1], 0x000, rx_check_promisc; /* if (!IS_MULTICAST(rx_frame)) */
1476 jext COND_TRUE, rx_complete;
1478 // ***********************************************************************************************
1479 // HANDLER: slow_clock_control
1480 // PURPOSE: Updates SCC.
1483 jnand 0x0FF, SPR_BRC, state_machine_idle;
1484 jnzx 0, 2, GLOBAL_FLAGS_REG3, 0x000, skip_scc_update;
1485 jnzx 0, 1, SPR_SCC_Control, 0x000, state_machine_idle;
1486 orx 14, 1, SPR_SCC_Timer_Low, 0x000, SPR_SCC_Period_Divisor;
1487 srx 0, 15, SPR_SCC_Timer_Low, 0x000, GP_REG5;
1488 orx 14, 1, SPR_SCC_Timer_High, GP_REG5, SPR_SCC_Period;
1489 orx 0, 2, 0x001, GLOBAL_FLAGS_REG3, GLOBAL_FLAGS_REG3;
1491 jext COND_TRUE, state_machine_idle;
1494 /* --------------------------------------------------- FUNCTIONS ---------------------------------------------------------- */
1497 // ***********************************************************************************************
1498 // FUNCTION: push_frame_into_fifo
1499 // PURPOSE: Copies received frame into the RX host queue.
1501 push_frame_into_fifo:; /* Set frame offset and header length */
1502 mov SHM_RXHDR, SPR_RXE_RXHDR_OFFSET;
1503 mov SHM_RXHDR_LEN, SPR_RXE_RXHDR_LEN;
1504 orx 1, 0, 0x001, SPR_RXE_FIFOCTL1, SPR_RXE_FIFOCTL1; /* SPR_RXE_FIFOCTL1 = (SPR_RXE_FIFOCTL1 & ~0x3) | 0x1 */
1506 jext COND_RX_FIFOFULL, rx_fifo_overflow; /* Wait for the engine to stop its work */
1507 jnext COND_RX_FIFOBUSY, wait_rx_fifo_1;
1509 jext COND_RX_FIFOFULL, rx_fifo_overflow;
1510 jext COND_RX_FIFOBUSY, wait_rx_fifo_2;
1511 or GP_REG5, 0x000, GP_REG5;
1512 jle 0x000, 0x001, check_rx_fifo_overflow;
1513 check_rx_fifo_overflow:;
1514 jext COND_RX_FIFOFULL, rx_fifo_overflow;
1515 mov 0x0100, SPR_MAC_IRQLO; /* SPR_MAC_Interrupt_Status_Low = MI_NSPECGEN_1 -- There is a frame ready in the fifo */
1518 // ***********************************************************************************************
1519 // FUNCTION: load_tx_header_into_shm
1520 // PURPOSE: Loads BCM header into SHM.
1522 load_tx_header_into_shm:;
1523 mov SHM_TXHEADER, SPR_BASE0; /* off0 = SHM_TXHEADER */
1524 mov 0x0000, GP_REG5;
1525 jnzx 0, 1, [TXHDR_HK4,off0], 0x000, load_tx_hdr_done; /* if (tx_info.housekeeping4 & 0x02) */
1526 orx 0, 14, 0x001, [SHM_TXFCUR], SPR_TXE0_FIFO_CMD; /* SPR_TXE0_FIFO_CMD = SHM_TXFCUR | 0x4000 */
1527 sl SPR_BASE0, 0x001, SPR_TXE0_TX_SHM_ADDR; /* SPR_TXE0_TX_SHM_ADDR = SPR_BASE0 << 0x01 */
1528 or [SHM_TXFCUR], 0x000, SPR_TXE0_SELECT; /* SPR_TXE0_SELECT = SHM_TXFCUR */
1529 mov TXHDR_LEN, SPR_TXE0_TX_COUNT;
1530 or [SHM_TXFCUR], 0x005, SPR_TXE0_SELECT; /* SPR_TXE0_SELECT = SHM_TXFCUR | 0x05 */
1531 load_hdr_wait_for_tx_engine:;
1532 jnext COND_TX_BUSY, load_hdr_wait_for_tx_engine; /* Wait until header was copied from FIFO to SHM */
1533 load_hdr_wait_for_tx_engine_again:;
1534 jext COND_TX_BUSY, load_hdr_wait_for_tx_engine_again;
1535 orx 1, 0, 0x002, [TXHDR_HK4,off0], [TXHDR_HK4,off0]; /* tx_info.housekeeping4 = 0x2 | (tx_info.housekeeping4 & ~0x3) */
1536 jzx 0, 3, [TXHDR_MACLO,off0], 0x000, load_tx_hdr_done; /* if (!(tx_info.MAC_ctl_lo & TX_CTL_START_MSDU)) */
1537 nand [TXHDR_HK5,off0], 0x018, [TXHDR_HK5,off0]; /* tx_info.housekeeping5 = tx_info.housekeeping5 & ~(FAILED|USE_FALLBACK) */
1541 // ***********************************************************************************************
1542 // FUNCTION: inhibit_sleep_at_tbtt
1543 // PURPOSE: Forces device to not sleep at TBTT.
1545 inhibit_sleep_at_tbtt:;
1546 orx 7, 8, 0x000, 0x004, SPR_MAC_IRQLO;
1547 extcond_eoi_only(COND_TX_TBTTEXPIRE);
1548 sl [SHM_NOSLPZNATDTIM], 0x003, SPR_TSF_GPT1_CNTLO;
1549 sr [SHM_NOSLPZNATDTIM], 0x00D, SPR_TSF_GPT1_CNTHI;
1550 orx 7, 8, 0x0C0, 0x000, SPR_TSF_GPT1_STAT;
1553 // ***********************************************************************************************
1554 // FUNCTION: sel_phy_reg
1555 // PURPOSE: Selects a phy register.
1558 jnzx 0, 14, SPR_Ext_IHR_Address, 0x000, sel_phy_reg;
1559 orx 0, 12, 0x001, GP_REG5, SPR_Ext_IHR_Address;
1560 wait_sel_phy_cond_to_clear:;
1561 jnzx 0, 12, SPR_Ext_IHR_Address, 0x000, wait_sel_phy_cond_to_clear;
1562 or GP_REG5, 0x000, GP_REG5;
1565 // ***********************************************************************************************
1566 // FUNCTION: write_phy_reg
1567 // PURPOSE: Writes the value contained in GP_REG6 into phy register.
1570 jnzx 0, 14, SPR_Ext_IHR_Address, 0x000, write_phy_reg;
1571 or GP_REG6, 0x000, SPR_Ext_IHR_Data;
1572 orx 0, 13, 0x001, GP_REG5, SPR_Ext_IHR_Address;
1573 jnzx 0, 3, GLOBAL_FLAGS_REG1, 0x000, end_write_phy_reg;
1574 wait_write_phy_cond_to_clear:;
1575 jnzx 0, 13, SPR_Ext_IHR_Address, 0x000, wait_write_phy_cond_to_clear;
1577 or GP_REG5, 0x000, GP_REG5;
1580 // ***********************************************************************************************
1581 // FUNCTION: get_ptr_from_rate_table
1582 // PURPOSE: Makes pointer refers to the correct premable informations.
1583 // It takes the rate in GP_REG0 and the control in GP_REG1
1584 // rate values (from the b43 driver, xmit.c)
1586 // cck at [1, 2, 5, 11] => [ 0x0A, 0x14, 0x37, 0x6E ]
1587 // ofdm at [6, 9, 12, 18, 24, 36, 48, 54] => [0xB, 0xF, 0xA, 0xE, 0x9, 0xD, 0x8, 0xC]
1589 // e.g. on reception of a beacon we have gp_reg0 = 0x0A and gp_reg1 = 0x00
1591 get_ptr_from_rate_table:;
1592 mov 0x14, [SHM_PREAMBLE_DURATION]; /* SHM_PREAMBLE_DURATION = 0x14 */
1593 orx 11, 4, 0x000, GP_REG0, GP_REG0; /* GP_REG0 = GP_REG0 & ~0xFFF0 */
1594 je [SHM_PHYTYPE], 0x000, get_ptr_from_rate_table_ofdm; /* OFDM phy type */
1595 jzx 1, 0, GP_REG1, 0x000, get_ptr_from_rate_table_cck;
1596 get_ptr_from_rate_table_ofdm:;
1597 mov SHM_OFDMDIRECT, GP_REG5;
1598 add GP_REG0, GP_REG5, SPR_BASE5; /* SPR_BASE5 = GP_REG0 + GP_REG5 */
1599 add GP_REG0, GP_REG5, SPR_BASE4; /* SPR_BASE4 = GP_REG0 + GP_REG5 */
1600 mov 0x0001, [SHM_CURMOD]; /* [SHM_CURMOD] = 1 -> OFDM */
1601 jext COND_TRUE, get_ptr_from_rate_table_out;
1602 get_ptr_from_rate_table_cck:;
1603 mov SHM_CCKDIRECT, GP_REG5;
1604 add GP_REG0, GP_REG5, SPR_BASE5; /* SPR_BASE5 = GP_REG0 + GP_REG5 */
1605 add GP_REG0, GP_REG5, SPR_BASE4; /* SPR_BASE4 = GP_REG0 + GP_REG5 */
1606 mov 0x00C0, [SHM_PREAMBLE_DURATION]; /* SHM_PREAMBLE_DURATION = 0xC0 */
1607 mov 0, [SHM_CURMOD]; /* [SHM_CURMOD] = 0 -> CCK */
1608 get_ptr_from_rate_table_out:;
1609 or [0x00,off5], 0x000, SPR_BASE2; /* SPR_BASE2 = [0x00,off5] */
1610 or [0x00,off4], 0x000, SPR_BASE3; /* SPR_BASE3 = [0x00,off4] */
1613 // ***********************************************************************************************
1614 // FUNCTION: find_dtim_info_elem
1615 // PURPOSE: Extracts TIM informations from Beacon frame.
1617 find_dtim_info_elem:;
1618 sub SPR_RXE_FRAMELEN, 0x004, GP_REG5; /* GP_REG5 = SPR_RXE_RX_FRAMELEN - 0x04 */
1619 or SPR_RXE_Copy_Length, 0x000, GP_REG7; /* GP_REG7 = SPR_RXE_Copy_Length */
1620 jl GP_REG5, GP_REG7, align_offset_1; /* if (GP_REG5 <u GP_REG7) */
1621 sr GP_REG7, 0x001, GP_REG7; /* GP_REG7 = GP_REG7 >> 0x01 */
1622 jext COND_TRUE, align_offset_2;
1624 sr GP_REG5, 0x001, GP_REG7; /* GP_REG7 = GP_REG5 >> 0x01 */
1626 add GP_REG7, SPR_RXE_Copy_Offset, GP_REG7; /* GP_REG7 = GP_REG7 + SPR_RXE_Copy_Offset */
1627 loop_inside_beacon_infos:;
1628 orx 14, 0, SPR_BASE5, 0x000, GP_REG5; /* GP_REG5 = offs5 & 0x7fff */
1629 jge GP_REG5, GP_REG7, update_return_value; /* if (GP_REG5 >=u GP_REG7) */
1630 jnzx 0, 15, SPR_BASE5, 0x000, extract_beacon_informations; /* if (offs5 & 0x8000) */
1631 srx 7, 0, [0x00,off5], 0x000, GP_REG5; /* GP_REG5 = (mem[offs5 + 0x0]) & 0xff */
1632 srx 7, 8, [0x00,off5], 0x000, GP_REG6; /* GP_REG6 = ((mem[offs5 + 0x0]) >> 8) & 0xff */
1633 jext COND_TRUE, compute_oper_on_infos;
1634 extract_beacon_informations:;
1635 srx 7, 8, [0x00,off5], 0x000, GP_REG5; /* GP_REG5 = ((mem[offs5 + 0x0]) >> 8) & 0xff */
1636 srx 7, 0, [0x01,off5], 0x000, GP_REG6; /* GP_REG6 = (mem[offs5 + 0x1]) & 0xff */
1637 compute_oper_on_infos:;
1638 jge GP_REG5, GP_REG8, finish_operations_on_beacon; /* if (GP_REG5 >=u GP_REG8) */
1639 rr GP_REG6, 0x001, GP_REG6; /* GP_REG6 = (GP_REG6 >> 0x01) | (GP_REG6 << (16 - 0x01)) */
1640 add. SPR_BASE5, GP_REG6, SPR_BASE5; /* offs5 = offs5 + GP_REG6 [set carry] */
1641 addc. SPR_BASE5, 0x001, SPR_BASE5; /* offs5 = offs5 + 0x01 + carry [set carry] */
1642 jext COND_TRUE, loop_inside_beacon_infos;
1643 finish_operations_on_beacon:;
1644 jne GP_REG5, GP_REG8, update_return_value; /* if (GP_REG5 != GP_REG8) */
1645 rr GP_REG6, 0x001, GP_REG6; /* GP_REG6 = (GP_REG6 >> 0x01) | (GP_REG6 << (16 - 0x01)) */
1646 add. SPR_BASE5, GP_REG6, GP_REG5; /* GP_REG5 = offs5 + GP_REG6 [set carry] */
1647 addc. GP_REG5, 0x001, GP_REG5; /* GP_REG5 = GP_REG5 + 0x01 + carry [set carry] */
1648 orx 14, 0, GP_REG5, 0x000, GP_REG5; /* GP_REG5 = GP_REG5 & 0x7fff */
1649 jle GP_REG5, GP_REG7, end_find_dtim_info_elem; /* if (GP_REG5 <=u GP_REG7) goto end_find_dtim_info_elem */
1650 update_return_value:;
1651 mov 0xFFFF, GP_REG8; /* GP_REG8 = 0xffff */
1652 end_find_dtim_info_elem:;
1655 // ***********************************************************************************************
1656 // FUNCTION: prep_phy_txctl_with_encoding
1657 // PURPOSE: Sets PHY parameters correctly according to the transmission needs.
1659 prep_phy_txctl_with_encoding:;
1660 orx 1, 0, GP_REG1, SPR_TXE0_PHY_CTL, SPR_TXE0_PHY_CTL; /* SPR_TXE0_PHY_CTL = (r1 & 0x3) | (SPR_TXE0_PHY_CTL & ~0x3) */
1661 prep_phy_txctl_encoding_already_set:
1662 jzx 0, 9, SPR_TXE0_PHY_CTL, 0x000, no_phy_control_update; /* if (!(SPR_TXE0_PHY_Control & 0x200)) */
1663 orx 1, 8, [SHM_LAST_RX_ANTENNA], SPR_TXE0_PHY_CTL, SPR_TXE0_PHY_CTL; /* SPR_TXE0_PHY_CTL = (((shm_last_rx_antenna<<8) | (shm_last_rx_antenna>>8)) & 0x300) | (SPR_TXE0_PHY_CTL & ~0x300) */
1664 no_phy_control_update:;
1665 jzx 0, 7, [SHM_HF_MI], 0x000, end_prep_phy_txctl_with_encoding; /* if (!(SHM_HF_MI & MHF_HWPWRCTL)) */
1666 or [SHM_TXPWRCUR], 0x000, GP_REG5; /* GP_REG5 = shm_tx_pwr_cur */
1667 add GP_REG5, [0x07,off5], GP_REG5; /* GP_REG5 = GP_REG5 + mem[offs5 + 0x7] */
1668 orx 5, 10, GP_REG5, SPR_TXE0_PHY_CTL, SPR_TXE0_PHY_CTL; /* SPR_TXE0_PHY_CTL = (((GP_REG5<<10) | (GP_REG5>>6)) & 0xfc00) | (SPR_TXE0_PHY_Control & ~0xfc00) */
1669 end_prep_phy_txctl_with_encoding:;
1672 // ***********************************************************************************************
1673 // FUNCTION: get_rate_table_duration
1674 // PURPOSE: Provides duration parameter.
1675 // If short preamble is requested, then subracts half of the preamble duration
1676 // to overall duration
1678 get_rate_table_duration:;
1679 or [0x04,off2], 0x000, GP_REG5; /* GP_REG5 = mem[offs2 + 0x4] */
1680 jzx 0, 4, GP_REG1, 0x000, end_get_rate_table_duration; /* if !(GP_REG1 & 0x10) */
1681 jnzx 0, 0, GP_REG1, 0x000, end_get_rate_table_duration; /* if (GP_REG1 &0x01) */
1682 sr [SHM_PREAMBLE_DURATION], 0x001, GP_REG6; /* GP_REG6 := shm_preamble_duration >> 0x01 */
1683 sub [0x04,off2], GP_REG6, GP_REG5; /* GP_REG5 := mem[offs2 + 0x4] - GP_REG6 */
1684 end_get_rate_table_duration:;
1687 // ***********************************************************************************************
1688 // FUNCTION: antenna_diversity_helper
1689 // PURPOSE: Manages antenna diversity operations.
1691 antenna_diversity_helper:;
1692 jzx 0, 0, [SHM_HF_LO], 0x000, end_antenna_diversity_helper; /* if (!(SHM_HF_LO & MHF_ANTDIV)) */
1693 add ANTENNA_DIVERSITY_CTR, 0x001, ANTENNA_DIVERSITY_CTR; /* antenna_diversity_counter++ */
1694 jl ANTENNA_DIVERSITY_CTR, [SHM_ANTSWAP], end_antenna_diversity_helper; /* if (antenna_diversity_counter <u shm_antenna_swap_thresh) */
1695 mov 0x0001, GP_REG5; /* GP_REG5 = BPHY_BB_CONFIG */
1696 je [SHM_PHYTYPE], 0x001, B_phy; /* if (shm_phy_type == PHY_TYPE_B) */
1697 orx 0, 10, GLOBAL_FLAGS_REG1, 0x02B, GP_REG5; /* GP_REG5 = (((GLOBAL_FLAGS_REG1<<10) | (GLOBAL_FLAGS_REG1>>6)) & 0x400) | APHY_ANT_DWELL */
1699 call lr0, sel_phy_reg;
1700 jne ANTENNA_DIVERSITY_CTR, 0xFFFF, no_antenna_update; /* if (antenna_diversity_counter != ~0x00) */
1701 orx 0, 7, [SHM_LAST_RX_ANTENNA], SPR_Ext_IHR_Data, GP_REG6; /* GP_REG6 = (((shm_last_rx_antenna<<7) | (shm_last_rx_antenna>>9)) & 0x80) | (SPR_Ext_IHR_Data & ~0x80) */
1702 je [SHM_PHYTYPE], 0x001, B_phy_2; /* if (shm_phy_type == PHY_TYPE_B) */
1703 orx 0, 8, [SHM_LAST_RX_ANTENNA], SPR_Ext_IHR_Data, GP_REG6; /* GP_REG6 = (((shm_last_rx_antenna<<8) | (shm_last_rx_antenna>>8)) & 0x100) | (SPR_Ext_IHR_Data & ~0x100) */
1704 jext COND_TRUE, B_phy_2;
1706 xor SPR_Ext_IHR_Data, 0x080, GP_REG6; /* GP_REG6 = SPR_Ext_IHR_Data ^ 0x80 */
1707 je [SHM_PHYTYPE], 0x001, B_phy_2; /* if (shm_phy_type == PHY_TYPE_B) */
1708 xor SPR_Ext_IHR_Data, 0x100, GP_REG6; /* GP_REG6 = SPR_Ext_IHR_Data ^ 0x100 */
1710 call lr0, write_phy_reg;
1711 mov 0, ANTENNA_DIVERSITY_CTR; /* antenna_diversity_counter = 0x0000 */
1712 end_antenna_diversity_helper:;
1715 // ***********************************************************************************************
1716 // FUNCTION: gphy_classify_control_with_arg
1717 // PURPOSE: Manages classify control for G PHY devices.
1719 gphy_classify_control_with_arg:;
1720 jne [SHM_PHYTYPE], 0x002, end_gphy_classify_control_with_arg; /* if (shm_phy_type != PHY_TYPE_G) */
1721 mov 0x0802, GP_REG5; /* GP_REG5 = GPHY_CLASSIFY_CTRL */
1722 call lr0, write_phy_reg;
1723 end_gphy_classify_control_with_arg:;
1726 // ***********************************************************************************************
1727 // FUNCTION: check_gphy_sym_war
1728 // PURPOSE: Checks for workaround.
1730 check_gphy_sym_war:;
1731 jzx 0, 1, [SHM_HF_LO], 0x000, end_check_gphy_sym_war; /* if (!(SHM_HF_LO & MHF_SYMWAR)) */
1732 je [SHM_PHYTYPE], 0x000, end_check_gphy_sym_war; /* if (shm_phy_type == PHY_TYPE_A) */
1733 jnzx 1, 0, RX_PHY_ENCODING, 0x000, end_check_gphy_sym_war; /* if (rx_phy_encoding & 0x03) */
1734 jne RX_TYPE, 0x001, end_check_gphy_sym_war; /* if (RX_TYPE != 0x01) */
1735 srx 7, 0, [RX_FRAME_PLCP_0,off1], 0x000, GP_REG5; /* GP_REG5 = (mem[rx_frame_offs + FR_OFFS_PLCP_0]) & 0xff */
1736 jle GP_REG5, 0x014, end_check_gphy_sym_war; /* if (GP_REG5 <=u 0x14) */
1737 jne [RX_FRAME_PLCP_1,off1], 0x050, end_check_gphy_sym_war; /* if (mem[rx_frame_offs + FR_OFFS_PLCP_1] != 0x50) */
1738 mov 0x0001, GPHY_SYM_WAR_FLAG;
1739 orx 0, 4, 0x001, SPR_IFS_CTL, SPR_IFS_CTL; /* SPR_IFS_control = SPR_IFS_control | 0x10 */
1740 end_check_gphy_sym_war:;
1743 // ***********************************************************************************************
1744 // FUNCTION: bg_noise_sample
1745 // PURPOSE: Performs a noise measurement on the channel.
1748 jzx 0, 4, SPR_MAC_CMD, 0x000, stop_bg_noise_sample; /* if (!(SPR_MAC_Command & MCMD_BG_NOISE)) */
1749 jnzx 0, 3, GLOBAL_FLAGS_REG3, 0x000, bg_noise_inprogress; /* if (GLOBAL_FLAGS_REG3 & BG_NOISE_INPROGR) */
1750 orx 0, 3, 0x001, GLOBAL_FLAGS_REG3, GLOBAL_FLAGS_REG3; /* GLOBAL_FLAGS_REG3 = BG_NOISE_INPROGR | (GLOBAL_FLAGS_REG3 & ~BG_NOISE_INPROGR) */
1751 or SPR_TSF_WORD0, 0x000, 0x000;
1752 or SPR_TSF_WORD1, 0x000, [SHM_BGN_START_TSF1]; /* mem[SHM_BGN_START_TSF1] = SPR_TSF_word_1 */
1753 bg_noise_inprogress:;
1754 or SPR_TSF_WORD0, 0x000, 0x000; /* 0x00 = SPR_TSF_word_0 */
1755 sub SPR_TSF_WORD1, [SHM_BGN_START_TSF1], GP_REG8; /* GP_REG8 = SPR_TSF_word_1 - mem[SHM_BGN_START_TSF1] */
1756 mov 0x0008, GP_REG5;
1757 call lr0, sel_phy_reg;
1758 srx 7, 0, SPR_Ext_IHR_Data, 0x000, [SHM_JSSIAUX]; /* shm_JSSI_AUX = (SPR_Ext_IHR_Data) & 0xff */
1759 orx 0, 10, GLOBAL_FLAGS_REG1, 0x05F, GP_REG5; /* GP_REG5 = (((GLOBAL_FLAGS_REG1<<10) | (GLOBAL_FLAGS_REG1>>6)) & 0x400) | 0x5f */
1760 call lr0, sel_phy_reg;
1761 orx 7, 8, SPR_Ext_IHR_Data, [SHM_JSSIAUX], [SHM_JSSIAUX]; /* shm_JSSI_AUX = (SPR_Ext_IHR_Data << 8) | shm_JSSI_AUX */
1762 mov 0x0027, GP_REG5; /* GP_REG5 = BPHY_JSSI */
1763 mov 0x0044, SPR_BASE5;
1764 mov 0x0000, GP_REG6;
1766 add GP_REG6, 0x001, GP_REG6; /* GP_REG6 = GP_REG6 + 0x001 */
1767 add SPR_TSF_WORD0, 0x002, GP_REG7; /* GP_REG7 = SPR_TSF_word_0 + 0x02 */
1768 wait_for_time_to_be_elapsed_2us:;
1769 jext COND_TX_NOW, stop_bg_noise_sample;
1770 jzx 0, 11, SPR_IFS_STAT, 0x000, no_frame_to_transmit; /* if (!(SPR_IFS_stat & 0x800)) */
1771 jl GP_REG8, 0x002, stop_bg_noise_sample; /* if (GP_REG8 <u 0x02) */
1772 no_frame_to_transmit:;
1773 jne GP_REG7, SPR_TSF_WORD0, wait_for_time_to_be_elapsed_2us; /* if (GP_REG7 != SPR_TSF_word_0) */
1774 call lr0, sel_phy_reg;
1775 orx 8, 0, SPR_Ext_IHR_Data, [0x00,off5], [0x00,off5]; /* mem[offs5 + 0x0] = (SPR_Ext_IHR_Data & 0x1ff) | (mem[offs5 + 0x0] & ~0x1ff) */
1776 jne [SHM_PHYTYPE], 0x000, not_A_phy; /* if (shm_phy_type != PHY_TYPE_A) */
1777 jnzx 0, 8, SPR_Ext_IHR_Data, 0x000, rise_bg_noise_complete_irq; /* if (SPR_Ext_IHR_Data & 0x100) */
1778 jext COND_TRUE, A_phy;
1780 rr [0x00,off5], 0x008, [0x00,off5]; /* mem[offs5 + 0x0] = (mem[offs5 + 0x0] >> 0x08) | (mem[offs5 + 0x0] << (16 - 0x08)) */
1781 xor SPR_BASE5, 0x001, SPR_BASE5;
1783 jl GP_REG6, 0x004, loop_on_JSSI; /* if (GP_REG6 <u 0x04) */
1784 jge GP_REG8, 0x002, rise_bg_noise_complete_irq; /* if (GP_REG8 >=u 0x02) */
1785 add SPR_TSF_WORD0, 0x018, GP_REG7; /* GP_REG7 = SPR_TSF_word_0 + 0x18 */
1786 wait_for_time_to_be_elapsed_24us:;
1787 jext COND_TX_NOW, stop_bg_noise_sample; /* if (CR2 & 0x0001) */
1788 jnzx 0, 11, SPR_IFS_STAT, 0x000, stop_bg_noise_sample; /* if (SPR_IFS_stat & 0x800) */
1789 jne GP_REG7, SPR_TSF_WORD0, wait_for_time_to_be_elapsed_24us; /* if (GP_REG7 != SPR_TSF_word_0) */
1790 rise_bg_noise_complete_irq:;
1791 mov 0x0010, SPR_MAC_CMD;
1792 mov 0x0004, SPR_MAC_IRQHI; /* SPR_MAC_Interrupt_Status_High = MI_BG_NOISE */
1793 orx 0, 3, 0x000, GLOBAL_FLAGS_REG3, GLOBAL_FLAGS_REG3; /* GLOBAL_FLAGS_REG3 = GLOBAL_FLAGS_REG3 & ~BG_NOISE_INPROGR */
1794 stop_bg_noise_sample:;
1797 // ***********************************************************************************************
1798 // FUNCTION: update_wme_params
1799 // PURPOSE: Updates queue related contention informations.
1802 or SPR_IFS_0x0e, 0x000, GP_REG1;
1803 mov SHM_EDCFQCUR, SPR_BASE4;
1804 mov SHM_TXHEADER, SPR_BASE5;
1805 mov 0x0004, GP_REG5;
1806 je [SHM_EDCFQ_CWMIN,off4], DEFAULT_MIN_CW, cw_max_min_ok;
1807 mov DEFAULT_MAX_CW, [SHM_EDCFQ_CWMAX,off4];
1808 mov DEFAULT_MIN_CW, [SHM_EDCFQ_CWMIN,off4];
1810 jne GP_REG6, 0x001, update_wme_into_rx_wme8;
1811 orx 0, 9, 0x001, [SHM_EDCFQ_STATUS,off4], [SHM_EDCFQ_STATUS,off4]; /* update edcf status */
1812 or [SHM_EDCFQ_CWCUR,off4], 0x000, GP_REG0; /* GP_REG0 = cwcur */
1813 and SPR_TSF_Random, GP_REG0, GP_REG2; /* GP_REG2 = GP_REG0 & Random */
1814 or GP_REG2, 0x000, [SHM_EDCFQ_BSLOTS,off4]; /* bslots = GP_REG2 */
1815 add GP_REG2, [SHM_EDCFQ_AIFS,off4], [SHM_EDCFQ_REGGAP,off4]; /* reggap = GP_REG2 + aifs */
1816 update_wme_into_rx_wme8:;
1817 or [SHM_EDCFQ_AIFS,off4], 0x000, GP_REG2; /* GP_REG2 = aifs */
1818 sub GP_REG1, GP_REG2, GP_REG9; /* GP_REG9 = GP_REG1 - GP_REG2 */
1819 jles GP_REG9, 0x000, update_wme_end; /* GP_REG9 <= 0 ? update_wme_end (we need at least an aifs to be elapsed) */
1820 sub [SHM_EDCFQ_BSLOTS,off4], GP_REG9, [SHM_EDCFQ_BSLOTS,off4]; /* bslots = bslots - (elapsed_time - aifs) */
1821 jges [SHM_EDCFQ_BSLOTS,off4], 0x000, update_bslots; /* update bslots if greater then 0 */
1822 mov 0, [SHM_EDCFQ_BSLOTS,off4]; /* bslots can be at least 0 */
1824 or [SHM_EDCFQ_BSLOTS,off4], 0x000, GP_REG9; /* GP_REG9 = bslots */
1825 add [SHM_EDCFQ_AIFS,off4], GP_REG9, [SHM_EDCFQ_REGGAP,off4]; /* reggap = bslots + aifs */
1827 or GP_REG5, 0x000, GP_REG5;
1830 // ***********************************************************************************************
1831 // FUNCTION: update_wme_params_availability
1832 // PURPOSE: Updates queue related transmission informations.
1834 update_wme_params_availability:
1835 mov SHM_EDCFQCUR, SPR_BASE4; /* BASE4 points to the start of queue 1 params */
1836 mov SHM_TXHEADER, GP_REG8; /* GP_REG8 = queue 1 frame header */
1837 or CUR_CONTENTION_WIN, 0x000, [SHM_EDCFQ_CWCUR,off4]; /* mem[offs4_edcf_entry.cwcur] = cur_contention_win */
1838 orx 3, 0, SHORT_RETRIES, [SHM_EDCFQ_STATUS,off4], [SHM_EDCFQ_STATUS,off4]; /* mem[offs4 + 0x7] := (short_retries & 0xf) | (mem[offs4 + 0x7] & ~0xf) */
1839 orx 3, 3, LONG_RETRIES, [SHM_EDCFQ_STATUS,off4], [SHM_EDCFQ_STATUS,off4]; /* mem[offs4 + 0x7] := ((long_retries<<3 & 0x78) | (mem[offs4 + 0x7] & ~0x78) */
1840 or SPR_TXE0_FIFO_RDY, 0x000, GP_REG0;
1841 and GP_REG0, 0x00F, GP_REG0;
1842 or GP_REG0, 0x000, [SHM_FIFO_RDY];
1843 je GP_REG0, 0x000, no_frame_to_send;
1844 or [SHM_EDCFQ_CWCUR,off4], 0x000, CUR_CONTENTION_WIN; /* cur_contention_win = mem[offs4_edcf_entry.cwcur] */
1845 or [SHM_EDCFQ_CWMIN,off4], 0x000, MIN_CONTENTION_WIN; /* min_contention_win = mem[offs4_edcf_entry.cwmin] */
1846 or [SHM_EDCFQ_CWMAX,off4], 0x000, MAX_CONTENTION_WIN; /* max_contention_win = mem[offs4_edcf_entry.cwmax] */
1847 orx 3, 0, [SHM_EDCFQ_STATUS,off4], SHORT_RETRIES, SHORT_RETRIES; /* short_retries update */
1848 orx 3, 3, [SHM_EDCFQ_STATUS,off4], LONG_RETRIES, LONG_RETRIES; /* long_retries update */
1852 // ***********************************************************************************************
1853 // FUNCTION: set_backoff_time
1854 // PURPOSE: Updates backoff time for contention operation.
1857 srx 2, 8, [SHM_TXFCUR], 0x000, GP_REG5; /* GP_REG5 = ((SHM_TXFCUR) >> 8) & 0x7 */
1858 or SHM_EDCFQCUR, 0x000, SPR_BASE4; /* SPR_BASE4 = shm_edcf1_paramptr */
1859 and SPR_TSF_Random, CUR_CONTENTION_WIN, GP_REG5; /* GP_REG5 = SPR_TSF_Random & CUR_CONTENTION_WIN */
1860 or GP_REG5, 0x000, [SHM_EDCFQ_BSLOTS,off4]; /* mem[offs4_edcf_entry.bslots] = GP_REG5 */
1861 add [SHM_EDCFQ_AIFS,off4], GP_REG5, [SHM_EDCFQ_REGGAP,off4]; /* mem[offs4_edcf_entry.reggap] = mem[offs4_edcf_entry.aifs] + GP_REG5 */
1862 or [SHM_EDCFQ_REGGAP,off4], 0x000, GP_REG5; /* GP_REG5 = mem[offs4_edcf_entry.reggap] */
1863 jnzx 0, 11, SPR_IFS_STAT, 0x000, need_more_time_to_elapse; /* if (SPR_IFS_stat & 0x800) -- if time was elapsed */
1864 or SPR_IFS_0x0e, 0x000, GP_REG1; /* GP_REG1 = SPR_IFS_0x0e (elapsed time) */
1865 jl GP_REG5, GP_REG1, need_more_time_to_elapse; /* if (GP_REG5 <u GP_REG1) -- If reggap was already elapsed */
1866 sub GP_REG5, GP_REG1, GP_REG0; /* GP_REG0 = GP_REG5 - GP_REG1 */
1867 or GP_REG0, 0x000, SPR_IFS_BKOFFDELAY; /* SPR_IFS_BKOFFDELAY = GP_REG0 */
1868 jext COND_TRUE, end_backoff_time_update;
1869 need_more_time_to_elapse:;
1870 or GP_REG5, 0x000, SPR_IFS_BKOFFDELAY; /* SPR_IFS_BKOFFDELAY = GP_REG5 */
1871 end_backoff_time_update:;
1872 or CUR_CONTENTION_WIN, 0x000, [SHM_EDCFQ_CWCUR,off4]; /* mem[offs4_edcf_entry.cwcur] = CUR_CONTENTION_WINDOW */
1875 // ***********************************************************************************************
1876 // FUNCTION: mod_txe0_control_for_edcf
1877 // PURPOSE: Modifies NEXT_TXE0_CTL according to EDCF needs.
1879 mod_txe0_control_for_edcf:;
1880 jnext 0x28, update_txe0_control_for_edcf;
1881 orx 1, 1, 0x000, NEXT_TXE0_CTL, NEXT_TXE0_CTL; /* NEXT_TXE0_CTL = NEXT_TXE0_CTL & ~0x6 */
1882 jext COND_TRUE, end_txe0_control_for_edcf;
1883 update_txe0_control_for_edcf:;
1884 orx 0, 9, 0x000, GLOBAL_FLAGS_REG1, GLOBAL_FLAGS_REG1; /* GLOBAL_FLAGS_REG1 = GLOBAL_FLAGS_REG1 & ~0x200 */
1885 or NEXT_TXE0_CTL, 0x014, NEXT_TXE0_CTL; /* NEXT_TXE0_CTL = NEXT_TXE0_CTL | 0x14 */
1886 end_txe0_control_for_edcf:;
1888 @000 @000, @000, @000;
1890 #include "initvals.asm"