OpenCores
URL https://opencores.org/ocsvn/xulalx25soc/xulalx25soc/trunk

Subversion Repositories xulalx25soc

[/] [xulalx25soc/] [trunk/] [sw/] [usbi.cpp] - Blame information for rev 91

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 5 dgisselq
////////////////////////////////////////////////////////////////////////////////
2
//
3 11 dgisselq
// Filename:    usbi.cpp
4 5 dgisselq
//
5
// Project:     XuLA2 board
6
//
7
// Purpose:     Creates a USB port, similar to a serial port, out of the
8
//              XuLA2 JTAG interface S/W.
9
//
10
//
11
// Creator:     Dan Gisselquist, Ph.D.
12
//              Gisselquist Technology, LLC
13
//
14
////////////////////////////////////////////////////////////////////////////////
15
//
16 91 dgisselq
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
17 5 dgisselq
//
18
// This program is free software (firmware): you can redistribute it and/or
19
// modify it under the terms of  the GNU General Public License as published
20
// by the Free Software Foundation, either version 3 of the License, or (at
21
// your option) any later version.
22
//
23
// This program is distributed in the hope that it will be useful, but WITHOUT
24
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
25
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
26
// for more details.
27
//
28
// License:     GPL, v3, as defined and found on www.gnu.org,
29
//              http://www.gnu.org/licenses/gpl.html
30
//
31
//
32
////////////////////////////////////////////////////////////////////////////////
33
//
34
//
35
#include <stdio.h>
36
#include <stdlib.h>
37
#include <unistd.h>
38
#include <string.h>
39
#include <ctype.h>
40
// #include <usb.h>
41
 
42
#include <libusb.h>
43
 
44
#include "llcomms.h"
45
#include "usbi.h"
46
 
47 91 dgisselq
const   bool    DEBUG = false;
48
 
49 5 dgisselq
// Walk us through the JTAG Chain:
50
//      5-1's to go to test/reset
51
//      0        to go to Run-Test/Idle
52
//      1       to go to select-dr-scan
53
//      1       to go to select-ir-scan
54
//      0        to go to capture-ir
55
//      0        to go to shift-ir
56
//      (6-bit code 0x02 through TDI to IR, while sending 0-bits to TMS)
57
//      1       to leave shift IR and go to exit1-ir
58
//      1       to go to update-ir
59
//      1       to go to select-dr-scan
60
//      0        to go to capture-dr
61
//      0        to go to shift-dr
62
#define RESET_JTAG_LEN  12
63
static const char       RESET_TO_USER_DR[RESET_JTAG_LEN] = {
64
        JTAG_CMD,
65
        21, // clocks
66
        0,0,0,     // Also clocks, higher order bits
67
        PUT_TMS_MASK | PUT_TDI_MASK, // flags
68
        (char)(0x0df),  // TMS: Five ones, then one zero, and two ones -- low bits first
69
        0x00,   // TDI: irrelevant here
70
        (char)0x80,     // TMS: two zeros, then six zeros
71
        0x08,   // TDI: user command #1, bit reversed
72
        0x03,   // TMS: three ones, then two zeros
73
        0x00    // TDI byte -- irrelevant here
74
        //
75
        // 0xc0, // TDI byte -- user command #2
76
        // 0x40,        // TDI: user command #1
77
        // 0x0c, // TDI byte -- user command #2, bit reversed
78
};
79
 
80
//
81
//      TMS: 
82
#define TX_DR_LEN       12
83
static const    char    TX_DR_BITS[TX_DR_LEN] = {
84
        JTAG_CMD,
85
        48, // clocks
86
        0,0,0,     // Also clocks, higher order bits
87
        PUT_TDI_MASK, // flags
88
        (char)0x0ff, 0, 0, 0, 0, 0   // Six data bytes
89
        // module_id = 255
90
        // 32'h(payload.length)
91
        // payload
92
        // module_id + payload.len + num_result_bits, length=32 + payload ???
93
};
94
 
95
//
96
//      TMS: 
97
//      
98
#define REQ_RX_LEN      6
99
static const    char    REQ_RX_BITS[REQ_RX_LEN] = {
100
        JTAG_CMD,
101
        (const char)((USB_PKTLEN-REQ_RX_LEN)*8), // bits-requested
102
        0,0,0,     // Also clocks, higher order bits
103
        GET_TDO_MASK|TDI_VAL_MASK, // flags:TDI is kept low here, so no TDI flag
104
        // No data given, since there's no info to send or receive
105
        // Leave the result in shift-DR mode
106
};
107
 
108
/*
109
#define RETURN_TO_RESET_LEN     7
110
static const char       RETURN_TO_RESET[RETURN_TO_RESET_LEN] = {
111
        JTAG_CMD,
112
        5, // clocks
113
        0,0,0,  // Also clocks, higher order bits
114
        PUT_TMS_MASK, // flags
115
        (char)0x0ff, // Five ones
116
};
117
*/
118
 
119
USBI::USBI(void) {
120
        int     config;
121
 
122
        m_total_nread = 0;
123
 
124
        if (0 != libusb_init(&m_usb_context)) {
125
                fprintf(stderr, "Error initializing the USB library\n");
126
                perror("O/S Err:");
127
                exit(-1);
128
        }
129
 
130
        m_xula_usb_device = libusb_open_device_with_vid_pid(m_usb_context,
131
                VENDOR_ID, PRODUCT_ID);
132
        if (!m_xula_usb_device) {
133
                fprintf(stderr, "Could not open XuLA device\n");
134
                perror("O/S Err:");
135
 
136
                libusb_exit(m_usb_context);
137
                exit(-1);
138
        }
139
 
140
        if (0 != libusb_get_configuration(m_xula_usb_device, &config)) {
141
                fprintf(stderr, "Could not get configuration\n");
142
                perror("O/S Err:");
143
 
144
                libusb_close(m_xula_usb_device);
145
                libusb_exit(m_usb_context);
146
                exit(-1);
147
        }
148
 
149
        if (0 != libusb_claim_interface(m_xula_usb_device, XESS_INTERFACE)) {
150
                fprintf(stderr, "Could not claim interface\n");
151
                perror("O/S Err:");
152
 
153
                libusb_close(m_xula_usb_device);
154
                libusb_exit(m_usb_context);
155
                exit(-1);
156
        }
157
 
158
        unsigned char   abuf[RESET_JTAG_LEN];
159
        int     actual_length = RESET_JTAG_LEN, r;
160
 
161
        memcpy(abuf, RESET_TO_USER_DR, RESET_JTAG_LEN);
162
        r = libusb_bulk_transfer(m_xula_usb_device, XESS_ENDPOINT_OUT,
163
                abuf, RESET_JTAG_LEN, &actual_length, 4);
164
        if ((r!=0)||(actual_length != RESET_JTAG_LEN)) {
165
                // Try clearing the queue twice, then doing this
166
                do {
167
                        r = libusb_bulk_transfer(m_xula_usb_device, XESS_ENDPOINT_IN,
168
                                (unsigned char *)m_rxbuf, USB_PKTLEN, &actual_length, 20);
169
                } while((r==0)&&(actual_length > 0));
170
 
171
                r = libusb_bulk_transfer(m_xula_usb_device, XESS_ENDPOINT_OUT,
172
                        abuf, RESET_JTAG_LEN, &actual_length, 4);
173
                if ((r != 0)||(actual_length != RESET_JTAG_LEN)) {
174
                        printf("Some error took place requesting RESET_TO_USER_DR\n");
175
                        printf("r = %d, actual_length = %d (vs %d requested)\n",
176
                                r, actual_length, RESET_JTAG_LEN);
177
                        perror("O/S Err");
178
                        exit(-2);
179
                }
180
        }
181
 
182
        // Initialize our read FIFO
183
        m_rbeg = m_rend = 0;
184
 
185
        flush_read();
186
}
187
 
188
void    USBI::close(void) {
189
        // Release our interface
190
        if (0 != libusb_release_interface(m_xula_usb_device, XESS_INTERFACE)) {
191
                fprintf(stderr, "Could not release interface\n");
192
                perror("O/S Err:");
193
 
194
                libusb_close(m_xula_usb_device);
195
                libusb_exit(m_usb_context);
196
                exit(-1);
197
        }
198
 
199
        // And then close our device with
200
        libusb_close(m_xula_usb_device);
201
 
202
        // And just before exiting, we free our USB context
203
        libusb_exit(m_usb_context);
204
}
205
 
206
void    USBI::write(char *buf, int len) {
207
        int     r, actual_length;
208
 
209
        if (len >= USB_PKTLEN) {
210
                const int       nv = USB_PKTLEN/2-1;
211
                for(int pos=0; pos<len; pos+=nv)
212
                        write(&buf[pos], (len-pos>nv)?(nv):len-pos);
213
        } else {
214
                memset(m_txbuf, 0, len+6);
215
                m_txbuf[0] = JTAG_CMD;
216
                m_txbuf[1] = len * 8;
217
                m_txbuf[2] = 0;
218
                m_txbuf[3] = 0;
219
                m_txbuf[4] = 0;
220
                m_txbuf[5] = PUT_TDI_MASK | GET_TDO_MASK;
221
 
222
                for(int i=0; i<len; i++)
223
                        m_txbuf[6+i] = buf[i];
224 13 dgisselq
                // printf("WRITE::(buf=%*s, %d)\n", len, buf, len);
225 5 dgisselq
                r = libusb_bulk_transfer(m_xula_usb_device, XESS_ENDPOINT_OUT,
226
                        (unsigned char*)m_txbuf, len+6, &actual_length, 0);
227
                if ((r!=0)||(actual_length != len+6)) {
228
                        printf("WRITE::(buf, %d) -- ERR\n", len+6);
229
                        printf("r = %d, actual_length = %d (!= %d requested)\n", r,
230
                                actual_length, len+6);
231
 
232
                        if (r == -7) {
233
                                r = libusb_bulk_transfer(m_xula_usb_device,
234
                                        XESS_ENDPOINT_OUT,
235
                                        (unsigned char*)m_txbuf, len+6,
236
                                        &actual_length, 2);
237
                                if ((r!=0)||(actual_length != len+6)) {
238
                                        printf("WRITE::(buf, %d) -- ERR\n", len+6);
239
                                        printf("r = %d, actual_length = %d (!= %d requested)\n", r,
240
                                                actual_length, len+6);
241
                                        perror("O/S Err");
242
 
243
                                        exit(-2);
244
                                }
245
                        } else {
246
                                perror("O/S Err");
247
                                exit(-2);
248
                        }
249
                }
250
 
251
                // Try to read back however many bytes we can
252
                r = libusb_bulk_transfer(m_xula_usb_device, XESS_ENDPOINT_IN,
253
                        (unsigned char*)m_rxbuf, USB_PKTLEN, &actual_length, 20);
254
                if ((r==0)&&(actual_length > 0)) {
255
                        push_fifo(m_rxbuf, actual_length);
256
                } else {
257
                        printf("Some error took place in receiving\n");
258
                        perror("O/S Err");
259
                }
260
        }
261
}
262
 
263
int     USBI::read(char *buf, int len) {
264
        return read(buf, len, 4);
265
}
266
 
267
int     USBI::read(char *buf, int len, int timeout_ms) {
268
        int     left = len, nr=0;
269
 
270
        // printf("USBI::read(%d) (FIFO is %d-%d)\n", len, m_rend, m_rbeg);
271
        nr = pop_fifo(buf, left);
272
        left -= nr;
273
 
274
        while(left > 0) {
275
                raw_read(left, timeout_ms);
276 41 dgisselq
                nr = pop_fifo(&buf[len-left], left);
277 5 dgisselq
                left -= nr;
278
 
279
                // printf("\tWHILE (nr = %d, LEFT = %d, len=%d)\n", nr, left, len);
280
                if (nr == 0)
281
                        break;
282
        }
283
 
284
        // printf("READ %d characters (%d req, %d left)\n", len-left, len, left);
285
        return len-left;
286
}
287
 
288
void    USBI::raw_read(const int clen, int timeout_ms) {
289
        int     avail = (m_rbeg - m_rend)&(RCV_BUFMASK), actual_length;
290
        int     len = clen;
291
        if (len > RCV_BUFMASK-avail)
292
                len = RCV_BUFMASK-avail;
293
        if (len > 26)
294
                len = 26;
295
 
296 91 dgisselq
        if (DEBUG) printf("USBI::RAW-READ(%d, was %d)\n", len, clen);
297 5 dgisselq
        memcpy(m_txbuf, REQ_RX_BITS, REQ_RX_LEN);
298
 
299 46 dgisselq
        // I have chased process hangs to this line, but have no more
300
        // information than that somewhere within libusb_bulk_transfer,
301
        // libusb_handle_events_completed,
302
        // libusb_handle_events_timeout_completed, ?, poll(), there seems
303
        // to be a bug.
304
        //
305
        // I'm not certain if the bug is in the Linux kernel, or in the 
306
        // Xess tools.  I will note that, when a followup attempt is made
307
        // to read from the device, previously unread data may still get dumped
308
        // to it.  Therefore, be careful to clear the device upon starting
309
        // any process.
310
        //
311 91 dgisselq
        if(DEBUG) { printf("["); fflush(stdout); }
312 5 dgisselq
        int r = libusb_bulk_transfer(m_xula_usb_device, XESS_ENDPOINT_OUT,
313
                (unsigned char *)m_txbuf, REQ_RX_LEN, &actual_length,
314
                timeout_ms);
315 91 dgisselq
        if(DEBUG) { printf("]"); fflush(stdout); }
316 46 dgisselq
 
317 5 dgisselq
        if ((r==0)&&(actual_length == REQ_RX_LEN)) {
318
        } else if (r == -7) {
319
                // Nothing to read in the timeout provided
320
                // We'll have to request this data again ... later
321
                return;
322
        } else {
323
                printf("READ(WRITE,READ-REQ) -- ERR\n");
324
                printf("r = %d, actual_length = %d (!= %d requested)\n", r,
325
                        actual_length, len+6);
326
                perror("O/S Err");
327
                exit(-2);
328
        }
329
 
330
        // Try to read back however many bytes we can
331
        r = libusb_bulk_transfer(m_xula_usb_device, XESS_ENDPOINT_IN,
332
                (unsigned char *)m_rxbuf, USB_PKTLEN, &actual_length, 0);
333
        if ((r==0)&&(actual_length > 0)) {
334 91 dgisselq
                if (DEBUG) {
335
                        printf("RAW-READ() -> %d Read\n", actual_length);
336
                        for(int i=0; i<actual_length; i++)
337
                                printf("%02x ", m_rxbuf[i] & 0x0ff);
338
                        printf("\n");
339
                }
340 5 dgisselq
                push_fifo(m_rxbuf, actual_length);
341
        } else if (r == -7) {
342
                // Nothing to read in the timeout provided
343
                // Return, adding nothing to our FIFO
344
        } else {
345
                printf("Some error took place in receiving\n");
346
                perror("O/S Err");
347
        }
348
 
349
        // fprintf(stderr, "\tUSBI::RAW-READ() -- COMPLETE (%d avail)\n",
350
                // (m_rbeg-m_rend)&(RCV_BUFMASK));
351
}
352
 
353
void    USBI::flush_read(void) {
354
        while(poll(4)) {
355
                m_rbeg = m_rend = 0;
356
        }
357
}
358
 
359
void    USBI::push_fifo(char *buf, int len) {
360
        char    last = 0;
361
        char    *sptr = buf;
362
 
363
        // printf("Pushing %d items onto FIFO (%d - %d)\n", len, m_rend, m_rbeg);
364
        if (m_rbeg != m_rend)
365
                last = m_rbuf[m_rend];
366 91 dgisselq
        if (DEBUG)
367
                printf("\tPushing:");
368 5 dgisselq
        for(int i=0; i<len; i++) {
369
                char v = *sptr++;
370
                if (((v & 0x80)||((unsigned char)v < 0x10))&&(v == last)) {
371
                        // printf("\tSkipping: %02x\n", v & 0x0ff);
372
                } else if ((unsigned char)v == 0x0ff) {
373
                } else {
374
                        m_rbuf[m_rbeg] = v;
375
                        m_rbeg = (m_rbeg+1)&(RCV_BUFMASK);
376 91 dgisselq
                        if (DEBUG)
377
                                printf(" %02x", v & 0x0ff);
378 5 dgisselq
                } last = v;
379 91 dgisselq
        } if (DEBUG) printf("\n");
380 5 dgisselq
}
381
 
382
int     USBI::pop_fifo(char *buf, int len) {
383
        int     avail = (m_rbeg - m_rend)&(RCV_BUFMASK);
384
        int     left = len;
385
        int     nr = 0;
386
 
387
        // printf("Attempting to pop %d items from FIFO (%d - %d)\n",
388 41 dgisselq
        //              len, m_rend, m_rbeg);
389 5 dgisselq
        while((avail > 0)&&(left > 0)) {
390
                int ln = RCV_BUFLEN-m_rend;
391
                if (ln > left)
392
                        ln = left;
393
                if (ln > avail)
394
                        ln = avail;
395
                memcpy(&buf[len-left], &m_rbuf[m_rend], ln);
396
                left   -= ln;
397
                avail  -= ln;
398
                m_rend  = (m_rend + ln)&(RCV_BUFMASK);
399
                nr     += ln;
400
 
401 91 dgisselq
                if (DEBUG) {
402
                        printf("P:");
403
                        for(int i=0; i<ln; i++)
404
                                printf("%02x ", buf[len-left-ln+i]);
405
                }
406
        } if (DEBUG) printf("\n");
407 41 dgisselq
 
408 5 dgisselq
        /*
409
        if (nr > 0)
410
                printf("\tPopped %d items, buf[0] = %02x (%d - %d)\n",
411
                        nr, buf[0], m_rend, m_rbeg);
412
        else
413
                printf("\tPopped nothing, %d - %d\n", m_rend, m_rbeg);
414
        */
415 13 dgisselq
 
416 5 dgisselq
        return nr;
417
}
418
 
419
bool    USBI::poll(unsigned ms) {
420
        int     avail = (m_rbeg-m_rend)&(RCV_BUFMASK);
421
        bool    r = true;
422
 
423
        // printf("POLL request\n");
424
 
425
        if ((avail < 2)&&((avail<1)||(m_rbuf[m_rend]&0x80)||(m_rbuf[m_rend]<0x10))) {
426
                raw_read(4,ms);
427
                avail = (m_rbeg-m_rend)&(RCV_BUFMASK);
428
                // printf("%d availabe\n", avail);
429
 
430
                char    v = (m_rbuf[(m_rbeg-1)&(RCV_BUFMASK)]);
431
                while(((v&0x80)==0)&&((unsigned)v>=0x10)&&(avail < RCV_BUFMASK-32)) {
432
                        raw_read(26,ms);
433
                        avail = (m_rbeg-m_rend)&(RCV_BUFMASK);
434
                }
435
                if (avail < 1)
436
                        r = false;
437
                else if ((avail==1)&&((m_rbuf[m_rend]&0x80)||(m_rbuf[m_rend]<0x10)))
438
                        r = false;
439
        }
440
 
441
        // printf("USBI::poll() -> %s (%d avail)\n", (r)?"true":"false", avail);
442
        return r;
443
}
444 91 dgisselq
 
445
int     USBI::available(void) {
446
        int     avail = (m_rbeg-m_rend)&(RCV_BUFMASK);
447
 
448
        if (avail > 1)
449
                return avail;
450
        else if ((avail == 1)&&((m_rbuf[m_rend]&0x80)||(m_rbuf[m_rend]<0x10)))
451
                return 1;
452
        else
453
                return 0;
454
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.