Setting up repository
[linux-libre-firmware.git] / openfwwf / ucode5.asm
1 /*
2 *  BCM43xx device microcode
3 *   For Wireless-Core Revision 5
4 *
5 *  Copyright (C) 2009           University of Brescia
6 *
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>
10 *
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.
14 *
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.
19 */
20
21 // a few notes for beginners
22 //
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!
26 //
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
29 //    unstable!!
30 //
31 // 3) expiration of ack timeout enables COND_TX_PMQ so that handler tx_contention_params_update
32 //    is invoked
33 //
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
36 //
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.
40 //
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.
48 // 
49
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
53 //
54 // air-buffer for incoming bytes from air
55 //     ||         ||
56 //     ||         \/
57 //     ||      rx-buffer => FIFO to host =====> dma => host
58 //     ||                    /\
59 //     \/                    ||
60 //  copy in SHM        SHM with header
61 //
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
67 //             to zero.
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
72 //
73 //
74
75 // explanation for SPR_RXE_0x1a, something related to the pair of air-buffer and rx-buffer
76 //
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
84
85
86         #include "spr.inc"
87         #include "shm.inc"
88         #include "cond.inc"
89         #include "myreg.inc"
90
91         #define         TS_DATA                 0x002
92         #define         TS_ACK                  0x035
93         #define         TS_CTS                  0x031
94         #define         TS_RTS                  0x02D   
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
103
104         #define         DEFAULT_MAX_CW          0x03FF
105         #define         DEFAULT_MIN_CW          0x001F
106         #define         DEFAULT_RETRY_LIMIT     0x0007
107
108         %arch 5;
109         
110                 mov     0, SPR_GPIO_OUT;                                        /* Disable any GPIO pin */                      
111
112 // ***********************************************************************************************
113 // HANDLER:     init
114 // PURPOSE:     Initializes the device.
115 //
116         init:;
117                 mov     0, SPR_PSM_0x4e;                        
118                 mov     0, SPR_PSM_0x0c;                                                
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 */
123                 mov     0, [0x00,off5];                 
124                 sub     SPR_BASE5, 0x001, SPR_BASE5;                            
125                 jges    SPR_BASE5, 0x000, erase_shm;
126         do_not_erase_shm:;
127                 mov     0x1, [SHM_UCODESTAT];                   
128                 mov     0, GP_REG5;                             
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;
151                 mov     0, LONG_RETRIES;                                
152                 mov     0, GP_REG12;
153                 jext    COND_TRUE, mac_suspend;
154
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. 
158 //
159         state_machine_idle:;
160                 mov     0, WATCHDOG                     
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.. */
164                 nap;                                                            
165
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 */
180         check_mac_status:;                                                      
181                 jnext   COND_MACEN, mac_suspend_check;                          /* Check if we can sleep */             
182                 jext    COND_TX_FLUSH, check_conditions;
183
184         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;                                 
189
190         check_conditions_no_tx:;
191                 jext    COND_TX_PHYERR, tx_phy_error;
192
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) */        
201         rx_fifofull:;
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;                          
207
208
209 /* --------------------------------------------------- HANDLERS ---------------------------------------------------------- */
210
211
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
217 //
218         channel_setup:;
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;
222         skip_beacon_ops:
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 */
225         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;
231
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
237 //
238         prepare_beacon_tx:
239                 jnand   0x0E3, SPR_BRC, state_machine_idle;
240                 jnext   0x3D, beacon_tx_param_update;
241                 jext    0x3E, beacon_tx_param_update;
242         inhibit_sleep_call:;
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 */
247                 mov     0x001, GP_REG11;
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; 
255         bcn_no_hw_pwr_ctl:
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 */
268         skip_brc_update:
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;
278         goto_set_ifs:
279                 mov     0x4D95, NEXT_TXE0_CTL; 
280                 jext    COND_TRUE, set_ifs;
281
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
289 //
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;                          
311         fifo_ready_for_tx:;
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;                         
321         check_tx_channel:;
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 */                                    
335         extract_phy_info:;
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;                         
368         end_check_tx_data:;
369                 jext    COND_TRUE, set_ifs;                                             
370
371 // ***********************************************************************************************
372 // HANDLER:     suppress_this_frame
373 // PURPOSE:     Flushes frame and tells the host that transmission failed.
374 //
375         suppress_this_frame:;
376                 mov     0, SPR_TXE0_SELECT;                                     /* SPR_TXE0_SELECT = 0x0000 */                  
377                 jext    COND_TRUE, report_tx_status_to_host;                    
378
379 // ***********************************************************************************************
380 // HANDLER:     set_ifs
381 // PURPOSE:     Prepares backoff time (if it is equal to zero) for the next contention stage.
382 // 
383         set_ifs:;
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;                          
389
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.
393 //
394         tx_frame_now:;
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;                                             
410                 mov     0x0001, GP_REG6;                                
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; 
427
428         tx_beacon_or_data:;
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) */ 
436                 mov     0x046A, GP_REG5;
437                 jext    COND_TRUE, load_beacon_tim;
438         set_low_tmpl_addr:
439                 mov     0x006A, GP_REG5;
440         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;
448         wait_tx_bcn_free:;
449                 jnext   COND_TX_BUSY, wait_tx_bcn_free;
450         wait_tx_bcn_write:;
451                 jext    COND_TX_BUSY, wait_tx_bcn_write;
452                 sub     CURRENT_DTIM_COUNT, 0x001, CURRENT_DTIM_COUNT;
453                 mov     0, GP_REG6;
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) */
458         not_a_dtim:;
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;
464         dtim_offs1:;
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;
468         dtim_offs2:;
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;
473         dtim_offs3:;
474                 orx     7, 8, CURRENT_DTIM_COUNT, [0x01,off5], [0x01,off5];
475                 orx     0, 8, GP_REG6, [0x02,off5], [0x02,off5];
476         end_dtim_update:;
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;
480         wait_tmpl_ram:;
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;
487         tx_beacon:;
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;
494         bcn_tmpl_off1:
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;
502                 mov     0, NEXT_IFS;
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;
510         params_restored:
511                 mov     IRQLO_BEACON_TX_OK, SPR_MAC_IRQLO;
512         complete_tx:
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;                                 
518         
519         tx_data:;
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;                                              
547                 mov     0, GP_REG5;                             
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) */
559         set_cf_ack:;
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 */
564         tx_frame_analysis:;
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 */
572         find_tx_frame_type:;
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;                               
591                 mov     0, LONG_RETRIES;                                
592         update_txe_timeout:;
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 */      
600                 mov     0x03D8, GP_REG6;                                
601                 call    lr0, write_phy_reg;                                     
602         no_radar_war:;
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) */
605         tx_frame_no_B_phy:;
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;                                  
610         tx_frame_A_phy:;
611                 add     SPR_TSF_WORD0, 0x010, GP_REG5;                          /* GP_REG5 = SPR_TSF_word_0 + 0x10 */
612         tx_frame_wait_16us:;
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;                              
622         update_phy_params:;
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) */
639                 mov     0, SPR_NAV_0x04;                        
640                 jext    COND_TRUE, state_machine_idle;                          
641
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.
645 //
646         tx_infos_update:;       
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 */
651         need_ack:;
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;                         
659         dont_need_beacon:;
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;                    
667
668 // ***********************************************************************************************
669 // HANDLER:     tx_end_wait_10us
670 // PURPOSE:     Doesn't allow noise measurement for 10us after transmission. 
671 //
672         tx_end_wait_10us:;
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 */
678         tx_end_completed:;
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;                    
687
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.
691 //
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 */
714         discard_tx_status:;
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;                         
725
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.
729 //
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) */
737                 mov     0, SPR_TSF_0x24;                        
738                 mov     0, SPR_TSF_0x2a;                        
739                 orx     0, 9, 0x000, GLOBAL_FLAGS_REG1, GLOBAL_FLAGS_REG1;      /* GLOBAL_FLAGS_REG1 = GLOBAL_FLAGS_REG1 & ~0x200 */                                                    
740         skip_tsf_update:
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 */                                              
759         using_fallback:;
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) */
762         dont_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;                                  
781         finish_updates:;
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)) */
795                 mov     0, LONG_RETRIES;                                
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;                    
799
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
806 //              e.g. for CCK
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
811 //
812         send_response:;
813                 mov     0x000E, GP_REG5;                                
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;                            
829         no_hw_pwr_ctl:;
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;                                        
839         ctl_more_frag:;
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;                                        
846         pspoll_frame:;
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;                                   
855         sym_war_txe_ctl:;
856                 mov     0x4021, NEXT_TXE0_CTL;                                  /* Generate FCS (4), enable TX engine (1) and 2(??)*/
857         send_response_end:;
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;  
861
862 // ***********************************************************************************************
863 // HANDLER:     tx_timers_setup
864 // PURPOSE:     Updates timers informations.
865 //
866         tx_timers_setup:;
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) */
875                 mov     0, GP_REG6;                             
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) */            
883         timers_update_goon:;
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;                                     
890         no_ACI:;
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;                         
897
898 // ***********************************************************************************************
899 // HANDLER:     rx_plcp
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
904 //
905         rx_plcp:;
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)) */
910                 mov     0, SPR_TXE0_CTL;                        
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 */               
921         rx_plcp_not_A_phy:;
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;                                 
933         header_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) */
950         rx_plcp_not_wds:;
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) */
953         not_qos_data:;
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;                  
1001
1002 // ***********************************************************************************************
1003 // HANDLER:     rx_too_short
1004 // PURPOSE:     Reports reception error and checks if frame must be kept.
1005 //      
1006         rx_too_short:;
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;                          
1011
1012 // ***********************************************************************************************
1013 // HANDLER:     rx_complete
1014 // PURPOSE:     Completes reception and classifies frame. 
1015 //
1016         rx_complete:;
1017                 jext    COND_REC_IN_PROGRESS, clear_rxe_x1a;                                    
1018                 extcond_eoi_only(COND_RX_COMPLETE);
1019                 jext    COND_TRUE, update_RXE_FIFOCTL1_value;                                   
1020         clear_rxe_x1a:;
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;                                 
1041         need_regular_ack:;
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 ) */
1045         no_cck_modulation:;
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) */
1048         ofdm_modulation:;
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 */                            
1074         check_frame_type:;
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;                          
1087         rx_control_frame:;
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;                          
1095         not_wds_frame:;
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 */                            
1098
1099 // ***********************************************************************************************
1100 // HANDLER:     send_frame_to_host
1101 // PURPOSE:     Prepares the frame before sending it to the host.
1102 //
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 */      
1106         keep_bad_frames:;
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;                                 
1130
1131 // ***********************************************************************************************
1132 // HANDLER:     rx_too_long
1133 // PURPOSE:     Reports reception error.        
1134 //
1135         rx_too_long:;                   
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;                               
1139
1140 // ***********************************************************************************************
1141 // HANDLER:     rx_ack
1142 // PURPOSE:i    Performs operations related to ACK reception.   
1143 //
1144         rx_ack:;
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;
1152         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 */                                                             
1157
1158 // ***********************************************************************************************
1159 // HANDLER:     send_control_frame_to_host
1160 // PURPOSE:     Decides if control frame must be sent to host.  
1161 //
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;                            
1168
1169 // ***********************************************************************************************
1170 // HANDLER:     rx_check_promisc
1171 // PURPOSE:     Controls if promiscuous mode was enable.        
1172 //
1173         rx_check_promisc:;
1174                 jnzx    0, 8, SPR_MAC_CTLHI, 0x000, rx_complete;                /* if (SPR_MAC_Control_High & MCTL_PROMISC) */  
1175
1176 // ***********************************************************************************************
1177 // HANDLER:     rx_discard_frame        
1178 // PURPOSE:     Commands a frame discard.
1179 //
1180         rx_discard_frame:;
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;                                                         
1183
1184 // ***********************************************************************************************
1185 // HANDLER:     rx_data_plus
1186 // PURPOSE:     Manages data frame reception.   
1187 //
1188         rx_data_plus:;
1189                 jext    COND_RX_COMPLETE, end_rx_data_plus;                                     
1190                 jl      SPR_RXE_FRAMELEN, 0x01C, rx_data_plus;                  
1191         end_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;                               
1195
1196 // ***********************************************************************************************
1197 // HANDLER:     tx_underflow    
1198 // PURPOSE:     Prepares device for TX underflow error management.      
1199 //
1200         tx_underflow:;
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;                                        
1206
1207 // ***********************************************************************************************
1208 // HANDLER:     tx_fifo_underflow
1209 // PURPOSE:     Manages TX underflow error.     
1210 //
1211         tx_fifo_underflow:;
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) */
1217         tx_clear_issues:;
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;                         
1245
1246 // ***********************************************************************************************
1247 // HANDLER:     tx_phy_error
1248 // PURPOSE:     Manages TX phy errors.
1249 //
1250         tx_phy_error:;
1251                 jext    COND_FRAME_BURST, check_rx_conditions;
1252                 jext    COND_FRAME_NEED_ACK, tx_clear_issues; 
1253                 mov     0, GP_REG7;
1254                 jext    COND_TRUE, tx_dont_clear_issues;
1255
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?
1260 //
1261         rx_fifo_overflow:;
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;                               
1268
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
1274 //
1275         mac_suspend_check:;
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;                       
1280
1281                 mov     0x002, GP_REG11;
1282                 jext    COND_TRUE, flush_and_stop_tx_engine;    
1283         return_flush_into_mac_suspend_check:
1284                         
1285 // ***********************************************************************************************
1286 // HANDLER:     mac_suspend     
1287 // PURPOSE:     Suspends device.
1288 //              
1289         mac_suspend:;
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 */
1299                 mov     0, SPR_BRC;                                             
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) */
1308                 mov     0, SPR_BRCL0;                           
1309                 mov     0, SPR_BRCL1;                           
1310                 mov     0, SPR_BRCL2;                           
1311                 mov     0, SPR_BRCL3;                           
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;                              
1315                 mov     0, SPR_BRWK1;                           
1316                 mov     0x730F, SPR_BRWK2;                              
1317                 mov     0x0057, SPR_BRWK3;                              
1318                 jext    COND_TRUE, state_machine_start;                         
1319
1320 // ***********************************************************************************************
1321 // HANDLER:     rx_badplcp      
1322 // PURPOSE:     Manages reception of a frame with not valid PLCP.
1323 //
1324         rx_badplcp:;
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;                         
1334
1335 // ***********************************************************************************************
1336 // HANDLER:     discard_frame   
1337 // PURPOSE:     Discards the frame into the FIFO.
1338 //
1339         discard_frame:;
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;                                 
1352
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.
1356 //
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 */
1370         jump_wep_update:;
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;
1382
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
1388 //
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;                                        
1394         rx_bss_match:;
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;
1412         succ_bcn_tx:
1413                 and     SPR_TSF_Random, MIN_CONTENTION_WIN, SPR_IFS_BKOFFDELAY;
1414         check_beacon_time:;
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]) */         
1430         sync_TSF:;
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;                                      
1440         update_TSF_words:;
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;                                 
1467
1468 // ***********************************************************************************************
1469 // HANDLER:     send_response_if_ra_match
1470 // PURPOSE:     Decides if frame needs a response.
1471 //
1472         send_response_if_ra_match:;
1473                 jext    COND_RX_RAMATCH, send_response;                         
1474         rx_ra_dont_match:;
1475                 jzx     0, 0, [RX_FRAME_ADDR1_1,off1], 0x000, rx_check_promisc;         /* if (!IS_MULTICAST(rx_frame)) */      
1476                 jext    COND_TRUE, rx_complete;                                 
1477
1478 // ***********************************************************************************************
1479 // HANDLER:     slow_clock_control
1480 // PURPOSE:     Updates SCC.
1481 //
1482         slow_clock_control:
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;
1490         skip_scc_update:
1491                 jext    COND_TRUE, state_machine_idle;
1492
1493
1494 /* --------------------------------------------------- FUNCTIONS ---------------------------------------------------------- */
1495
1496
1497 // ***********************************************************************************************
1498 // FUNCTION:    push_frame_into_fifo
1499 // PURPOSE:     Copies received frame into the RX host queue.
1500 //
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 */
1505         wait_rx_fifo_1:;
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;                                       
1508         wait_rx_fifo_2:;
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 */
1516                 ret     lr0, lr0;
1517
1518 // ***********************************************************************************************
1519 // FUNCTION:    load_tx_header_into_shm
1520 // PURPOSE:     Loads BCM header into SHM.
1521 //
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) */
1538         load_tx_hdr_done:;
1539                 ret     lr3, lr3;
1540
1541 // ***********************************************************************************************
1542 // FUNCTION:    inhibit_sleep_at_tbtt
1543 // PURPOSE:     Forces device to not sleep at TBTT.
1544 //
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;
1551                 ret     lr0, lr0;
1552
1553 // ***********************************************************************************************
1554 // FUNCTION:    sel_phy_reg
1555 // PURPOSE:     Selects a phy register.
1556 //
1557         sel_phy_reg:;
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;
1563                 ret     lr0, lr0;
1564
1565 // ***********************************************************************************************
1566 // FUNCTION:    write_phy_reg
1567 // PURPOSE:     Writes the value contained in GP_REG6 into phy register. 
1568 //
1569         write_phy_reg:;
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;
1576         end_write_phy_reg:;
1577                 or      GP_REG5, 0x000, GP_REG5;
1578                 ret     lr0, lr0;
1579
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)
1585 //
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]
1588 //
1589 //              e.g. on reception of a beacon we have gp_reg0 = 0x0A and gp_reg1 = 0x00
1590 //
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] */   
1611                 ret     lr0, lr0;                                               
1612
1613 // ***********************************************************************************************
1614 // FUNCTION:    find_dtim_info_elem
1615 // PURPOSE:     Extracts TIM informations from Beacon frame.
1616 //
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;                                              
1623         align_offset_1:;
1624                 sr      GP_REG5, 0x001, GP_REG7;                                /* GP_REG7 = GP_REG5 >> 0x01 */
1625         align_offset_2:;
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:;
1653                 ret     lr0, lr0;
1654
1655 // ***********************************************************************************************
1656 // FUNCTION:    prep_phy_txctl_with_encoding    
1657 // PURPOSE:     Sets PHY parameters correctly according to the transmission needs.
1658 //
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:;
1670                 ret     lr1, lr1;
1671
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
1677 //
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:;
1685                 ret     lr0, lr0;
1686
1687 // ***********************************************************************************************
1688 // FUNCTION:    antenna_diversity_helper
1689 // PURPOSE:     Manages antenna diversity operations.
1690 //
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 */           
1698         B_phy:;
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;                                     
1705         no_antenna_update:;
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 */
1709         B_phy_2:;
1710                 call    lr0, write_phy_reg;                                     
1711                 mov     0, ANTENNA_DIVERSITY_CTR;                                               /* antenna_diversity_counter = 0x0000 */                
1712         end_antenna_diversity_helper:;
1713                 ret     lr1, lr1;
1714
1715 // ***********************************************************************************************
1716 // FUNCTION:    gphy_classify_control_with_arg
1717 // PURPOSE:     Manages classify control for G PHY devices.
1718 //
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:;
1724                 ret     lr1, lr1;
1725
1726 // ***********************************************************************************************
1727 // FUNCTION:    check_gphy_sym_war      
1728 // PURPOSE:     Checks for workaround.
1729 //
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:;
1741                 ret     lr1, lr1;
1742
1743 // ***********************************************************************************************
1744 // FUNCTION:    bg_noise_sample 
1745 // PURPOSE:     Performs a noise measurement on the channel.
1746 //
1747         bg_noise_sample:
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;                                
1765         loop_on_JSSI:;
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;                                       
1779         not_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;                            
1782         A_phy:;
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:;
1795                 ret     lr3, lr2;
1796
1797 // ***********************************************************************************************
1798 // FUNCTION:    update_wme_params       
1799 // PURPOSE:     Updates queue related contention informations.
1800 //
1801         update_wme_params:;     
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];
1809         cw_max_min_ok:
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 */
1823         update_bslots:;
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 */    
1826         update_wme_end:;
1827                 or      GP_REG5, 0x000, GP_REG5;
1828                 ret     lr0, lr0;
1829
1830 // ***********************************************************************************************
1831 // FUNCTION:    update_wme_params_availability
1832 // PURPOSE:     Updates queue related transmission informations.
1833 //
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 */
1849         no_frame_to_send:
1850                 ret     lr0, lr0;
1851
1852 // ***********************************************************************************************
1853 // FUNCTION:    set_backoff_time
1854 // PURPOSE:     Updates backoff time for contention operation.
1855 //
1856         set_backoff_time:;
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 */
1873                 ret     lr1, lr1;
1874
1875 // ***********************************************************************************************
1876 // FUNCTION:    mod_txe0_control_for_edcf       
1877 // PURPOSE:     Modifies NEXT_TXE0_CTL according to EDCF needs.
1878 //
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:;
1887                 ret     lr0, lr0;
1888                 @000    @000, @000, @000;
1889
1890 #include "initvals.asm"