1 /*-----------------------------------------------------------------------------
\r
2 * Code that turns a Cypress FX2 USB Controller into an USB JTAG adapter
\r
3 *-----------------------------------------------------------------------------
\r
4 * Copyright (C) 2005..2007 Kolja Waschk, ixo.de
\r
5 *-----------------------------------------------------------------------------
\r
6 * Check hardware.h/.c if it matches your hardware configuration (e.g. pinout).
\r
7 * Changes regarding USB identification should be made in product.inc!
\r
8 *-----------------------------------------------------------------------------
\r
9 * This code is part of usbjtag. usbjtag is free software; you can redistribute
\r
10 * it and/or modify it under the terms of the GNU General Public License as
\r
11 * published by the Free Software Foundation; either version 2 of the License,
\r
12 * or (at your option) any later version. usbjtag is distributed in the hope
\r
13 * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
\r
14 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
15 * GNU General Public License for more details. You should have received a
\r
16 * copy of the GNU General Public License along with this program in the file
\r
17 * COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin
\r
18 * St, Fifth Floor, Boston, MA 02110-1301 USA
\r
19 *-----------------------------------------------------------------------------
\r
22 // The firmware version should be regularly updated.
\r
23 #define FWVERSION "4.2.0"
\r
28 #include "fx2regs.h"
\r
29 #include "fx2utils.h"
\r
30 #include "usb_common.h"
\r
31 #include "usb_descriptors.h"
\r
32 #include "usb_requests.h"
\r
34 #include "syncdelay.h"
\r
37 #include "hardware.h"
\r
39 //-----------------------------------------------------------------------------
\r
40 // Define USE_MOD256_OUTBUFFER:
\r
41 // Saves about 256 bytes in code size, improves speed a little.
\r
42 // A further optimization could be not to use an extra output buffer at
\r
43 // all, but to write directly into EP1INBUF. Not implemented yet. When
\r
44 // downloading large amounts of data _to_ the target, there is no output
\r
45 // and thus the output buffer isn't used at all and doesn't slow down things.
\r
47 #define USE_MOD256_OUTBUFFER 1
\r
49 //-----------------------------------------------------------------------------
\r
55 static BOOL Running;
\r
56 static BOOL WriteOnly;
\r
58 static BYTE ClockBytes;
\r
59 static WORD Pending;
\r
61 #ifdef USE_MOD256_OUTBUFFER
\r
62 static BYTE FirstDataInOutBuffer;
\r
63 static BYTE FirstFreeInOutBuffer;
\r
65 static WORD FirstDataInOutBuffer;
\r
66 static WORD FirstFreeInOutBuffer;
\r
69 #ifdef USE_MOD256_OUTBUFFER
\r
70 /* Size of output buffer must be exactly 256 */
\r
71 #define OUTBUFFER_LEN 0x100
\r
72 /* Output buffer must begin at some address with lower 8 bits all zero */
\r
73 xdata at 0xE000 BYTE OutBuffer[OUTBUFFER_LEN];
\r
75 #define OUTBUFFER_LEN 0x200
\r
76 static xdata BYTE OutBuffer[OUTBUFFER_LEN];
\r
79 //-----------------------------------------------------------------------------
\r
81 void usb_jtag_init(void) // Called once at startup
\r
89 FirstDataInOutBuffer = 0;
\r
90 FirstFreeInOutBuffer = 0;
\r
96 // Make Timer2 reload at 100 Hz to trigger Keepalive packets
\r
97 tmp = 65536 - ( 48000000 / 12 / 100 );
\r
99 RCAP2L = tmp & 0xFF;
\r
100 CKCON = 0; // Default Clock
\r
101 T2CON = 0x04; // Auto-reload mode using internal clock, no baud clock.
\r
103 // Enable Autopointer
\r
104 EXTACC = 1; // Enable
\r
105 APTR1FZ = 1; // Don't freeze
\r
106 APTR2FZ = 1; // Don't freeze
\r
108 // define endpoint configuration
\r
110 REVCTL = 3; SYNCDELAY; // Allow FW access to FIFO buffer
\r
111 FIFORESET = 0x80; SYNCDELAY; // From now on, NAK all, reset all FIFOS
\r
112 FIFORESET = 0x02; SYNCDELAY; // Reset FIFO 2
\r
113 FIFORESET = 0x04; SYNCDELAY; // Reset FIFO 4
\r
114 FIFORESET = 0x06; SYNCDELAY; // Reset FIFO 6
\r
115 FIFORESET = 0x08; SYNCDELAY; // Reset FIFO 8
\r
116 FIFORESET = 0x00; SYNCDELAY; // Restore normal behaviour
\r
118 EP1OUTCFG = 0xA0; SYNCDELAY; // Endpoint 1 Type Bulk
\r
119 EP1INCFG = 0xA0; SYNCDELAY; // Endpoint 1 Type Bulk
\r
121 EP2FIFOCFG = 0x00; SYNCDELAY; // Endpoint 2
\r
122 EP2CFG = 0xA2; SYNCDELAY; // Endpoint 2 Valid, Out, Type Bulk, Double buffered
\r
124 EP4FIFOCFG = 0x00; SYNCDELAY; // Endpoint 4 not used
\r
125 EP4CFG = 0xA0; SYNCDELAY; // Endpoint 4 not used
\r
127 REVCTL = 0; SYNCDELAY; // Reset FW access to FIFO buffer, enable auto-arming when AUTOOUT is switched to 1
\r
129 EP6CFG = 0xA2; SYNCDELAY; // Out endpoint, Bulk, Double buffering
\r
130 EP6FIFOCFG = 0x00; SYNCDELAY; // Firmware has to see a rising edge on auto bit to enable auto arming
\r
131 EP6FIFOCFG = bmAUTOOUT | bmWORDWIDE; SYNCDELAY; // Endpoint 6 used for user communicationn, auto commitment, 16 bits data bus
\r
133 EP8CFG = 0xE0; SYNCDELAY; // In endpoint, Bulk
\r
134 EP8FIFOCFG = 0x00; SYNCDELAY; // Firmware has to see a rising edge on auto bit to enable auto arming
\r
135 EP8FIFOCFG = bmAUTOIN | bmWORDWIDE; SYNCDELAY; // Endpoint 8 used for user communication, auto commitment, 16 bits data bus
\r
137 EP8AUTOINLENH = 0x00; SYNCDELAY; // Size in bytes of the IN data automatically commited (64 bytes here, but changed dynamically depending on the connection)
\r
138 EP8AUTOINLENL = 0x40; SYNCDELAY; // Can use signal PKTEND if you want to commit a shorter packet
\r
140 // Out endpoints do not come up armed
\r
141 // Since the defaults are double buffered we must write dummy byte counts twice
\r
142 EP2BCL = 0x80; SYNCDELAY; // Arm EP2OUT by writing byte count w/skip.=
\r
143 EP4BCL = 0x80; SYNCDELAY;
\r
144 EP2BCL = 0x80; SYNCDELAY; // Arm EP4OUT by writing byte count w/skip.=
\r
145 EP4BCL = 0x80; SYNCDELAY;
\r
147 // JTAG from FX2 enabled by default
\r
150 // Put the system in high speed by default (REM: USB-Blaster is in full speed)
\r
151 // This can be changed by vendor commands
\r
153 // Put the FIFO in sync mode
\r
154 IFCONFIG &= ~bmASYNC;
\r
157 void OutputByte(BYTE d)
\r
159 #ifdef USE_MOD256_OUTBUFFER
\r
160 OutBuffer[FirstFreeInOutBuffer] = d;
\r
161 FirstFreeInOutBuffer = ( FirstFreeInOutBuffer + 1 ) & 0xFF;
\r
163 OutBuffer[FirstFreeInOutBuffer++] = d;
\r
164 if(FirstFreeInOutBuffer >= OUTBUFFER_LEN) FirstFreeInOutBuffer = 0;
\r
169 //-----------------------------------------------------------------------------
\r
170 // usb_jtag_activity does most of the work. It now happens to behave just like
\r
171 // the combination of FT245BM and Altera-programmed EPM7064 CPLD in Altera's
\r
172 // USB-Blaster. The CPLD knows two major modes: Bit banging mode and Byte
\r
173 // shift mode. It starts in Bit banging mode. While bytes are received
\r
174 // from the host on EP2OUT, each byte B of them is processed as follows:
\r
176 // Please note: nCE, nCS, LED pins and DATAOUT actually aren't supported here.
\r
177 // Support for these would be required for AS/PS mode and isn't too complicated,
\r
178 // but I haven't had the time yet.
\r
180 // Bit banging mode:
\r
182 // 1. Remember bit 6 (0x40) in B as the "Read bit".
\r
184 // 2. If bit 7 (0x40) is set, switch to Byte shift mode for the coming
\r
185 // X bytes ( X := B & 0x3F ), and don't do anything else now.
\r
187 // 3. Otherwise, set the JTAG signals as follows:
\r
188 // TCK/DCLK high if bit 0 was set (0x01), otherwise low
\r
189 // TMS/nCONFIG high if bit 1 was set (0x02), otherwise low
\r
190 // nCE high if bit 2 was set (0x04), otherwise low
\r
191 // nCS high if bit 3 was set (0x08), otherwise low
\r
192 // TDI/ASDI/DATA0 high if bit 4 was set (0x10), otherwise low
\r
193 // Output Enable/LED active if bit 5 was set (0x20), otherwise low
\r
195 // 4. If "Read bit" (0x40) was set, record the state of TDO(CONF_DONE) and
\r
196 // DATAOUT(nSTATUS) pins and put it as a byte ((DATAOUT<<1)|TDO) in the
\r
197 // output FIFO _to_ the host (the code here reads TDO only and assumes
\r
200 // Byte shift mode:
\r
202 // 1. Load shift register with byte from host
\r
204 // 2. Do 8 times (i.e. for each bit of the byte; implemented in shift.a51)
\r
205 // 2a) if nCS=1, set carry bit from TDO, else set carry bit from DATAOUT
\r
206 // 2b) Rotate shift register through carry bit
\r
207 // 2c) TDI := Carry bit
\r
208 // 2d) Raise TCK, then lower TCK.
\r
210 // 3. If "Read bit" was set when switching into byte shift mode,
\r
211 // record the shift register content and put it into the FIFO
\r
214 // Some more (minor) things to consider to emulate the FT245BM:
\r
216 // a) The FT245BM seems to transmit just packets of no more than 64 bytes
\r
217 // (which perfectly matches the USB spec). Each packet starts with
\r
218 // two non-data bytes (I use 0x31,0x60 here). A USB sniffer on Windows
\r
219 // might show a number of packets to you as if it was a large transfer
\r
220 // because of the way that Windows understands it: it _is_ a large
\r
221 // transfer until terminated with an USB packet smaller than 64 byte.
\r
223 // b) The Windows driver expects to get some data packets (with at least
\r
224 // the two leading bytes 0x31,0x60) immediately after "resetting" the
\r
225 // FT chip and then in regular intervals. Otherwise a blue screen may
\r
226 // appear... In the code below, I make sure that every 10ms there is
\r
229 // c) Vendor specific commands to configure the FT245 are mostly ignored
\r
230 // in my code. Only those for reading the EEPROM are processed. See
\r
231 // DR_GetStatus and DR_VendorCmd below for my implementation.
\r
233 // All other TD_ and DR_ functions remain as provided with CY3681.
\r
235 //-----------------------------------------------------------------------------
\r
237 void usb_jtag_activity(void) // Called repeatedly while the device is idle
\r
239 if(!Running) return;
\r
243 if(!(EP1INCS & bmEPBUSY))
\r
249 AUTOPTRH2 = MSB( EP1INBUF );
\r
250 AUTOPTRL2 = LSB( EP1INBUF );
\r
255 if(Pending > 0x3E) { n = 0x3E; Pending -= n; }
\r
256 else { n = Pending; Pending = 0; };
\r
260 #ifdef USE_MOD256_OUTBUFFER
\r
261 APTR1H = MSB( OutBuffer );
\r
262 APTR1L = FirstDataInOutBuffer;
\r
265 XAUTODAT2 = XAUTODAT1;
\r
266 APTR1H = MSB( OutBuffer ); // Stay within 256-Byte-Buffer
\r
268 FirstDataInOutBuffer = APTR1L;
\r
270 APTR1H = MSB( &(OutBuffer[FirstDataInOutBuffer]) );
\r
271 APTR1L = LSB( &(OutBuffer[FirstDataInOutBuffer]) );
\r
274 XAUTODAT2 = XAUTODAT1;
\r
276 if(++FirstDataInOutBuffer >= OUTBUFFER_LEN)
\r
278 FirstDataInOutBuffer = 0;
\r
279 APTR1H = MSB( OutBuffer );
\r
280 APTR1L = LSB( OutBuffer );
\r
286 TF2 = 1; // Make sure there will be a short transfer soon
\r
290 EP1INBUF[0] = 0x31;
\r
291 EP1INBUF[1] = 0x60;
\r
298 if(!(EP2468STAT & bmEP2EMPTY) && (Pending < OUTBUFFER_LEN-0x3F))
\r
300 WORD i, n = EP2BCL|EP2BCH<<8;
\r
302 APTR1H = MSB( EP2FIFOBUF );
\r
303 APTR1L = LSB( EP2FIFOBUF );
\r
312 if(ClockBytes < m) m = ClockBytes;
\r
316 /* Shift out 8 bits from d */
\r
318 if(WriteOnly) /* Shift out 8 bits from d */
\r
320 while(m--) ProgIO_ShiftOut(XAUTODAT1);
\r
322 else /* Shift in 8 bits at the other end */
\r
324 while(m--) OutputByte(ProgIO_ShiftInOut(XAUTODAT1));
\r
329 BYTE d = XAUTODAT1;
\r
330 WriteOnly = (d & bmBIT6) ? FALSE : TRUE;
\r
334 /* Prepare byte transfer, do nothing else yet */
\r
336 ClockBytes = d & 0x3F;
\r
341 ProgIO_Set_State(d);
\r
343 OutputByte(ProgIO_Set_Get_State(d));
\r
350 EP2BCL = 0x80; // Re-arm endpoint 2
\r
354 //-----------------------------------------------------------------------------
\r
355 // Handler for Vendor Requests (
\r
356 //-----------------------------------------------------------------------------
\r
358 unsigned char app_vendor_cmd(void)
\r
360 // OUT requests. Pretend we handle them all...
\r
361 if ((bRequestType & bmRT_DIR_MASK) == bmRT_DIR_OUT){
\r
362 if(bRequest == RQ_GET_STATUS){
\r
370 case 0x90: // Read EEPROM
\r
371 { // We need a block for addr
\r
372 BYTE addr = (wIndexL<<1) & 0x7F;
\r
373 EP0BUF[0] = eeprom[addr];
\r
374 EP0BUF[1] = eeprom[addr+1];
\r
375 EP0BCL = (wLengthL<2) ? wLengthL : 2;
\r
379 case 0x91: // change USB speed
\r
380 if (wIndexL == 0){ // high speed
\r
383 fx2_renumerate(); // renumerate
\r
384 }else{ // full speed
\r
387 fx2_renumerate(); // renumerate
\r
389 EP0BCH = 0; // Arm endpoint
\r
390 EP0BCL = 1; // # bytes to transfer
\r
393 case 0x92: // change JTAG enable
\r
394 if (wIndexL == 0){ // FX2 is master of JTAG
\r
396 }else{ // external connector is master of JTAG
\r
399 EP0BCH = 0; // Arm endpoint
\r
400 EP0BCL = 0; // # bytes to transfer
\r
403 case 0x93: // change synchronous/asynchronous mode
\r
404 if(wIndexL == 0){ // sync
\r
405 IFCONFIG &= ~bmASYNC;
\r
408 IFCONFIG |= bmASYNC; // async
\r
411 EP0BCH = 0; // Arm endpoint
\r
415 case 0x94: // get Firmware version
\r
418 char* ver=FWVERSION;
\r
419 while(ver[i]!='\0'){
\r
423 EP0BCH = 0; // Arm endpoint
\r
432 EP0BCL = (wLengthL<2) ? wLengthL : 2;
\r
438 //-----------------------------------------------------------------------------
\r
440 static void main_loop(void)
\r
444 if(usb_setup_packet_avail()) usb_handle_setup_packet();
\r
445 usb_jtag_activity();
\r
449 //-----------------------------------------------------------------------------
\r
453 EA = 0; // disable all interrupts
\r
457 setup_autovectors ();
\r
458 usb_install_handlers ();
\r
461 EA = 1; // enable interrupts
\r
463 fx2_renumerate(); // simulates disconnect / reconnect
\r