25c5a3fdae33e49111666428f61aec055343f537
[debian/gnuradio] / usrp2 / firmware / lib / bsm12.c
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2009 Free Software Foundation, Inc.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include "bsm12.h"
24 #include "memory_map.h"
25 #include "buffer_pool.h"
26 #include "bool.h"
27 #include "nonstdio.h"
28 #include "buffer_state.h"
29 #include <stdlib.h>
30
31 static uint32_t last_send_ctrl[NBUFFERS];
32
33 void
34 bsm12_init(bsm12_t *sm, int buf0,
35            const buf_cmd_args_t *recv,
36            const buf_cmd_args_t *send0,
37            const buf_cmd_args_t *send1,
38            bsm12_inspector_t inspect)
39 {
40   if (buf0 & 0x3)       // precondition: buf0 % 4 == 0
41     abort();
42
43   sm->buf0 = buf0;
44   sm->running = false;
45   sm->recv_args = *recv;
46   sm->send_args[0] = *send0;
47   sm->send_args[1] = *send1;
48
49   sm->rx_idle = true;
50   sm->tx_idle[0] = true;
51   sm->tx_idle[1] = true;
52
53   sm->inspect = inspect;
54
55   sm->bps_error = BPS_ERROR(buf0 + 0) | BPS_ERROR(buf0 + 1) | BPS_ERROR(buf0 + 2);
56   sm->bps_done  = BPS_DONE(buf0 + 0)  | BPS_DONE(buf0 + 1)  | BPS_DONE(buf0 + 2);
57   sm->bps_error_or_done = sm->bps_error | sm->bps_done;
58
59   // How much to adjust the last_line register.
60   // It's 1 for everything but the ethernet.
61   sm->last_line_adj = recv->port == PORT_ETH ? 3 : 1;
62
63   buffer_state[sm->buf0 + 0] = BS_EMPTY;
64   buffer_state[sm->buf0 + 1] = BS_EMPTY;
65   buffer_state[sm->buf0 + 2] = BS_EMPTY;
66
67   for (int i = 0; i < 3; i++){
68     sm->precomputed_receive_to_buf_ctrl_word[i] =
69       (BPC_READ
70        | BPC_BUFFER(sm->buf0 + i)
71        | BPC_PORT(sm->recv_args.port)
72        | BPC_STEP(1)
73        | BPC_FIRST_LINE(sm->recv_args.first_line)
74        | BPC_LAST_LINE(sm->recv_args.last_line));
75     
76     for (int j = 0; j < 2; j++){
77       sm->precomputed_send_from_buf_ctrl_word[i][j] =
78         (BPC_WRITE
79          | BPC_BUFFER(sm->buf0 + i)
80          | BPC_PORT(sm->send_args[j].port)
81          | BPC_STEP(1)
82          | BPC_FIRST_LINE(sm->send_args[j].first_line)
83          | BPC_LAST_LINE(0));           // last line filled in at runtime
84     }
85   }
86 }
87
88 static inline void
89 bsm12_receive_to_buf(bsm12_t *sm, int bufno)
90 {
91   buffer_pool_ctrl->ctrl = sm->precomputed_receive_to_buf_ctrl_word[bufno & 0x3];
92 }
93
94 static inline void
95 bsm12_send_from_buf(bsm12_t *sm, int bufno, int dst_idx)
96 {
97   uint32_t t = (sm->precomputed_send_from_buf_ctrl_word[bufno & 0x3][dst_idx]
98                 | BPC_LAST_LINE(buffer_pool_status->last_line[bufno] - sm->last_line_adj));
99
100   buffer_pool_ctrl->ctrl = t;
101   last_send_ctrl[bufno] = t;
102 }
103
104 static inline void
105 bsm12_resend_from_buf(bsm12_t *sm, int bufno)
106 {
107   buffer_pool_ctrl->ctrl = last_send_ctrl[bufno];
108 }
109
110 void
111 bsm12_start(bsm12_t *sm)
112 {
113   sm->running = true;
114
115   buffer_state[sm->buf0 + 0] = BS_EMPTY;
116   buffer_state[sm->buf0 + 1] = BS_EMPTY;
117   buffer_state[sm->buf0 + 2] = BS_EMPTY;
118
119   bp_clear_buf(sm->buf0 + 0);
120   bp_clear_buf(sm->buf0 + 1);
121   bp_clear_buf(sm->buf0 + 2);
122
123   sm->rx_idle = false;
124   sm->tx_idle[0] = true;
125   sm->tx_idle[1] = true;
126   bsm12_receive_to_buf(sm, sm->buf0);
127   buffer_state[sm->buf0] = BS_FILLING;
128 }
129
130 void
131 bsm12_stop(bsm12_t *sm)
132 {
133   sm->running = false;
134   bp_clear_buf(sm->buf0 + 0);
135   bp_clear_buf(sm->buf0 + 1);
136   bp_clear_buf(sm->buf0 + 2);
137   buffer_state[sm->buf0 + 0] = BS_EMPTY;
138   buffer_state[sm->buf0 + 1] = BS_EMPTY;
139   buffer_state[sm->buf0 + 2] = BS_EMPTY;
140 }
141
142 static void bsm12_process_helper(bsm12_t *sm, int buf_this);
143 static void bsm12_error_helper(bsm12_t *sm, int buf_this);
144
145 void
146 bsm12_process_status(bsm12_t *sm, uint32_t status)
147 {
148   // anything for us?
149   if ((status & sm->bps_error_or_done) == 0 || !sm->running)
150     return;
151
152   if (status & sm->bps_error){
153     // Most likely an ethernet Rx error.  We just restart the transfer.
154     if (status & (BPS_ERROR(sm->buf0 + 0)))
155       bsm12_error_helper(sm, sm->buf0 + 0);
156
157     if (status & (BPS_ERROR(sm->buf0 + 1)))
158       bsm12_error_helper(sm, sm->buf0 + 1);
159
160     if (status & (BPS_ERROR(sm->buf0 + 2)))
161       bsm12_error_helper(sm, sm->buf0 + 2);
162   }
163
164   if (status & BPS_DONE(sm->buf0 + 0))
165     bsm12_process_helper(sm, sm->buf0 + 0);
166
167   if (status & BPS_DONE(sm->buf0 + 1))
168     bsm12_process_helper(sm, sm->buf0 + 1);
169
170   if (status & BPS_DONE(sm->buf0 + 2))
171     bsm12_process_helper(sm, sm->buf0 + 2);
172 }
173
174 \fstatic void 
175 bsm12_process_helper(bsm12_t *sm, int buf_this)
176 {
177 }
178
179 static void
180 bsm12_error_helper(bsm12_t *sm, int buf_this)
181 {
182   bp_clear_buf(buf_this);                 // clears ERROR flag
183
184   if (buffer_state[buf_this] == BS_FILLING){
185     bsm12_receive_to_buf(sm, buf_this);   // restart the xfer
186   }
187   else { // buffer was emptying
188     bsm12_resend_from_buf(sm, buf_this);  // restart the xfer
189   }
190 }
191
192
193 void
194 bsm12_handle_tx_underrun(bsm12_t *sm)
195 {
196 }
197
198 void
199 bsm12_handle_rx_overrun(bsm12_t *sm)
200 {
201 }