You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
783 lines
16 KiB
783 lines
16 KiB
12 years ago
|
/*
|
||
|
* xsvftool-xpcu - An (X)SVF player for the Xilinx Platform Cable USB
|
||
|
*
|
||
|
* Copyright (C) 2011 RIEGL Research ForschungsGmbH
|
||
|
* Copyright (C) 2011 Clifford Wolf <clifford@clifford.at>
|
||
|
*
|
||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||
|
* purpose with or without fee is hereby granted, provided that the above
|
||
|
* copyright notice and this permission notice appear in all copies.
|
||
|
*
|
||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* Command Reference (EP1)
|
||
|
* -----------------------
|
||
|
*
|
||
|
* Request: T<nn>
|
||
|
* Response: OK (T<nn>)
|
||
|
* Configure timing for EP2/JTAG transfers
|
||
|
*
|
||
|
* Request: R
|
||
|
* Response: OK (R)
|
||
|
* Perform internal and CPLD reset
|
||
|
*
|
||
|
* Request: W<n>
|
||
|
* Response: OK (W<n>)
|
||
|
* Wait for the CPLD sync signal to become <n>
|
||
|
*
|
||
|
* Request: C
|
||
|
* Response: <nnnnnn> (C)
|
||
|
* Read out the CPLD verilog checksum
|
||
|
*
|
||
|
* Request: B<n>
|
||
|
* Response: OK (B<n>)
|
||
|
* Set BUFFER_OE to <n>
|
||
|
*
|
||
|
* Request: I<n>
|
||
|
* Response: OK (I<n>)
|
||
|
* Set INIT_INT to <n>
|
||
|
*
|
||
|
* Request: S
|
||
|
* Response: <n><m><k><p><x><y><s> (S)
|
||
|
* Read and reset status bits
|
||
|
* (<n> = FX2-JTAG-ERR, <m> = CPLD-JTAG-ERR, <k> = INIT_B_INT,
|
||
|
* <p> = SLOE_INT, <x> = FX2-JTAG-TDO, <y> = CPLD-JTAG-TDO, <s> = SYNC)
|
||
|
*
|
||
|
* Request: P
|
||
|
* Response: <n><m><k><p><x><y><s> (P)
|
||
|
* Peek status bits without resetting them
|
||
|
*
|
||
|
* Request: J<bindata>
|
||
|
* Response: -- NONE --
|
||
|
* Execute JTAG transaction (4bit/cycle)
|
||
|
*
|
||
|
* Request: X
|
||
|
* Response: OK (X)
|
||
|
* Exit. Restore FX2 default settings and enter endless loop
|
||
|
*
|
||
|
*
|
||
|
* Target JTAG Programming (EP2)
|
||
|
* -----------------------------
|
||
|
*
|
||
|
* Raw JTAG transaction codes.
|
||
|
* (4bit/cycle when T=0, 8bit/cycle otherwise)
|
||
|
*
|
||
|
*
|
||
|
* JTAG Transaction codes
|
||
|
* ----------------------
|
||
|
*
|
||
|
* 0000:
|
||
|
* NOP
|
||
|
*
|
||
|
* 0001 xxxx:
|
||
|
* Set sync signal to 'xxxx' (engine on CPLD only)
|
||
|
*
|
||
|
* 001x:
|
||
|
* reserved for future use
|
||
|
*
|
||
|
* 01xy:
|
||
|
* JTAG transaction without TDO check. TMS=x, TDI=y
|
||
|
*
|
||
|
* 1zxy:
|
||
|
* JTAG transaction with TDO check. TDO=z, TMS=x, TDI=y
|
||
|
*
|
||
|
*
|
||
|
* FX2 <-> CPLD Interface
|
||
|
* ----------------------
|
||
|
*
|
||
|
* FD[7:0] ---> FD[7:0]
|
||
|
* CTL0 ---> STROBE_FD (neg)
|
||
|
* CTL1 ---> STROBE_SHIFT (neg)
|
||
|
* CTL2 ---> STROBE_PUSH (neg)
|
||
|
*
|
||
|
* PC[7:4] <--- SYNC
|
||
|
* PC3 <--- TDO
|
||
|
* PC2 <--- CKSUM
|
||
|
* PC1 <--- INIT_B_INT
|
||
|
* PC0 <--- ERR
|
||
|
*
|
||
|
* PD4 ---> RESET_SYNC
|
||
|
* PD3 ---> RESET_ERR
|
||
|
* PD2 ---> INIT_INT
|
||
|
* PD1 ---> SHIFT_CKSUM
|
||
|
* PD0 ---> RESET_CKSUM
|
||
|
*
|
||
|
*
|
||
|
* Other FX2 Connections
|
||
|
* ---------------------
|
||
|
*
|
||
|
* PA0 ---> LED_GREEN
|
||
|
* PA1 ---> LED_RED
|
||
|
* PA2 <--- SLOE_INT
|
||
|
* PA3 ---> CPLD_PWR
|
||
|
* PA5 ---> BUFFER_OE
|
||
|
*
|
||
|
* IOE[3] ---> CPLD TCK
|
||
|
* IOE[4] ---> CPLD TMS
|
||
|
* IOE[5] <--- CPLD TDO
|
||
|
* IOE[6] ---> CPLD TDI
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
// #include "fx2.h"
|
||
|
// #include "fx2regs.h"
|
||
|
// #include "fx2sdly.h"
|
||
|
#include "gpifprog_fixed.c"
|
||
|
|
||
|
// set to '1' on CPLD JTAG error
|
||
|
BYTE state_err;
|
||
|
|
||
|
// use quad buffering and larger buffers
|
||
|
#define ALL_RESOURCES_ON_EP2
|
||
|
|
||
|
void sleep3us(void)
|
||
|
{
|
||
|
SYNCDELAY;
|
||
|
SYNCDELAY;
|
||
|
SYNCDELAY;
|
||
|
SYNCDELAY;
|
||
|
SYNCDELAY;
|
||
|
SYNCDELAY;
|
||
|
SYNCDELAY;
|
||
|
SYNCDELAY;
|
||
|
}
|
||
|
|
||
|
void msleep(WORD ms)
|
||
|
{
|
||
|
WORD i;
|
||
|
while (ms-- > 0) {
|
||
|
for (i = 0; i < 1000; i += 3)
|
||
|
sleep3us();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void setup(void)
|
||
|
{
|
||
|
BYTE i;
|
||
|
|
||
|
/* CPU: 48MHz, don't drive CLKOUT */
|
||
|
CPUCS = 0x10;
|
||
|
|
||
|
#ifdef ALL_RESOURCES_ON_EP2
|
||
|
/* Configure the Endpoints (EP2 => 4x 1kB) */
|
||
|
EP2CFG = 0xA8; // VALID=1, DIR=0, TYPE=10, SIZE=1, BUF=00
|
||
|
EP4CFG = 0x00; // VALID=0, DIR=0, TYPE=00, SIZE=0, BUF=00
|
||
|
EP6CFG = 0x00; // VALID=0, DIR=0, TYPE=00, SIZE=0, BUF=00
|
||
|
EP8CFG = 0x00; // VALID=0, DIR=0, TYPE=00, SIZE=0, BUF=00
|
||
|
#else
|
||
|
/* Configure the Endpoints (default config) */
|
||
|
EP2CFG = 0xA2; // VALID=1, DIR=0, TYPE=10, SIZE=0, BUF=10
|
||
|
EP4CFG = 0xA0; // VALID=1, DIR=0, TYPE=10, SIZE=0, BUF=00
|
||
|
EP6CFG = 0xA2; // VALID=1, DIR=1, TYPE=10, SIZE=0, BUF=10
|
||
|
EP8CFG = 0xA0; // VALID=1, DIR=1, TYPE=10, SIZE=0, BUF=00
|
||
|
#endif
|
||
|
|
||
|
/* USB FIFO */
|
||
|
FIFORESET = 0x80;
|
||
|
SYNCDELAY;
|
||
|
FIFORESET = 2;
|
||
|
SYNCDELAY;
|
||
|
FIFORESET = 4;
|
||
|
SYNCDELAY;
|
||
|
FIFORESET = 6;
|
||
|
SYNCDELAY;
|
||
|
FIFORESET = 8;
|
||
|
SYNCDELAY;
|
||
|
FIFORESET = 0;
|
||
|
SYNCDELAY;
|
||
|
|
||
|
/* Set WORDWIDE=0 for all FIFOs */
|
||
|
EP2FIFOCFG &= ~bmWORDWIDE;
|
||
|
SYNCDELAY;
|
||
|
EP4FIFOCFG &= ~bmWORDWIDE;
|
||
|
SYNCDELAY;
|
||
|
EP6FIFOCFG &= ~bmWORDWIDE;
|
||
|
SYNCDELAY;
|
||
|
EP8FIFOCFG &= ~bmWORDWIDE;
|
||
|
SYNCDELAY;
|
||
|
|
||
|
/* Initialize GPIF Subsystem */
|
||
|
GpifInit();
|
||
|
|
||
|
/* Misc signals on port A */
|
||
|
PORTACFG = 0;
|
||
|
OEA = bmBIT0 | bmBIT1 | bmBIT3 | bmBIT5;
|
||
|
IOA = 0;
|
||
|
|
||
|
/* FX2 <-> CPLD signals on port C */
|
||
|
PORTCCFG = 0;
|
||
|
OEC = 0;
|
||
|
IOC = 0;
|
||
|
|
||
|
/* FX2 <-> CPLD signals on port D */
|
||
|
OED = bmBIT0 | bmBIT1 | bmBIT2 | bmBIT3 | bmBIT4;
|
||
|
IOD = 0;
|
||
|
|
||
|
/* TURN ON CPLD VCC */
|
||
|
PA3 = 1;
|
||
|
msleep(100);
|
||
|
|
||
|
/* XC2S256 JTAG on port E */
|
||
|
OEE = bmBIT3|bmBIT4|bmBIT6;
|
||
|
IOE = bmBIT3|bmBIT4|bmBIT6;
|
||
|
|
||
|
/* Set TAP to logic reset state */
|
||
|
for (i=0; i<16; i++) {
|
||
|
// TMS is high - just generate a few TCK pulses
|
||
|
sleep3us();
|
||
|
IOE &= ~bmBIT3;
|
||
|
sleep3us();
|
||
|
IOE |= bmBIT3;
|
||
|
}
|
||
|
|
||
|
/* All set up: Let the host find out about the new EP config */
|
||
|
#if 0
|
||
|
USBCS |= bmDISCON;
|
||
|
msleep(10);
|
||
|
USBCS &= ~bmDISCON;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void unsetup(void)
|
||
|
{
|
||
|
WORD i, j;
|
||
|
|
||
|
/* 1st TURN OFF CPLD VCC */
|
||
|
PA3 = 0;
|
||
|
msleep(100);
|
||
|
|
||
|
/*
|
||
|
* Restore default configuration as good as possible
|
||
|
*
|
||
|
* The idea is that one could load the xilinx firmware without
|
||
|
* the need to reconnect. Unfortunately it doesn't work. Something
|
||
|
* important is still different between the FX2 after reset and
|
||
|
* after running this unsetup() function.
|
||
|
*/
|
||
|
|
||
|
GPIFABORT = 0xFF;
|
||
|
SYNCDELAY;
|
||
|
|
||
|
CPUCS = 0x02;
|
||
|
SYNCDELAY;
|
||
|
IFCONFIG = 0x80;
|
||
|
SYNCDELAY;
|
||
|
|
||
|
EP2CFG = 0xA2;
|
||
|
SYNCDELAY;
|
||
|
EP4CFG = 0xA0;
|
||
|
SYNCDELAY;
|
||
|
EP6CFG = 0xA2;
|
||
|
SYNCDELAY;
|
||
|
EP8CFG = 0xA0;
|
||
|
SYNCDELAY;
|
||
|
|
||
|
EP2FIFOCFG = 0x05;
|
||
|
SYNCDELAY;
|
||
|
EP4FIFOCFG = 0x05;
|
||
|
SYNCDELAY;
|
||
|
EP6FIFOCFG = 0x05;
|
||
|
SYNCDELAY;
|
||
|
EP8FIFOCFG = 0x05;
|
||
|
SYNCDELAY;
|
||
|
|
||
|
FIFORESET = 0x80;
|
||
|
SYNCDELAY;
|
||
|
FIFORESET = 2;
|
||
|
SYNCDELAY;
|
||
|
FIFORESET = 4;
|
||
|
SYNCDELAY;
|
||
|
FIFORESET = 6;
|
||
|
SYNCDELAY;
|
||
|
FIFORESET = 8;
|
||
|
SYNCDELAY;
|
||
|
FIFORESET = 0;
|
||
|
SYNCDELAY;
|
||
|
|
||
|
IOA = 0;
|
||
|
IOC = 0;
|
||
|
IOD = 0;
|
||
|
IOE = 0;
|
||
|
|
||
|
OEA = 0;
|
||
|
OEC = 0;
|
||
|
OED = 0;
|
||
|
OEE = 0;
|
||
|
|
||
|
PORTACFG = 0;
|
||
|
PORTCCFG = 0;
|
||
|
|
||
|
OEA = 1;
|
||
|
for (i=0; i<3; i++) {
|
||
|
PA0 = 1;
|
||
|
for (j=0; j<3000; j++) sleep3us();
|
||
|
PA1 = 0;
|
||
|
for (j=0; j<3000; j++) sleep3us();
|
||
|
}
|
||
|
OEA = 0;
|
||
|
|
||
|
// just ack everything and wait
|
||
|
while (1) {
|
||
|
if((EP1OUTCS & bmBIT1) == 0) {
|
||
|
EP1OUTBC = 0xff; SYNCDELAY;
|
||
|
}
|
||
|
if((EP2CS & bmBIT2) == 0) {
|
||
|
EP2BCL = 0xff; SYNCDELAY;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BYTE nibble2hex(BYTE v)
|
||
|
{
|
||
|
return "0123456789ABCDEF"[v&0x0f];
|
||
|
}
|
||
|
|
||
|
BYTE hex2nibble(BYTE v)
|
||
|
{
|
||
|
if (v >= '0' && v <= '9')
|
||
|
return v - '0';
|
||
|
if (v >= 'a' && v <= 'f')
|
||
|
return 0x0A + v - 'a';
|
||
|
if (v >= 'A' && v <= 'F')
|
||
|
return 0x0A + v - 'A';
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
xdata at (0xE400 + 64) volatile BYTE GPIF_WAVE2_LEN0;
|
||
|
xdata at (0xE400 + 66) volatile BYTE GPIF_WAVE2_LEN2;
|
||
|
|
||
|
void proc_command_t(BYTE t)
|
||
|
{
|
||
|
if (t == 0) {
|
||
|
GPIFWFSELECT = 0x4E; SYNCDELAY;
|
||
|
} else {
|
||
|
GPIFWFSELECT = 0x4A; SYNCDELAY;
|
||
|
GPIF_WAVE2_LEN0 = t; SYNCDELAY;
|
||
|
GPIF_WAVE2_LEN2 = t; SYNCDELAY;
|
||
|
}
|
||
|
|
||
|
EP1INBUF[0] = 'O'; SYNCDELAY;
|
||
|
EP1INBUF[1] = 'K'; SYNCDELAY;
|
||
|
EP1INBUF[2] = ' '; SYNCDELAY;
|
||
|
EP1INBUF[3] = '('; SYNCDELAY;
|
||
|
EP1INBUF[4] = 'T'; SYNCDELAY;
|
||
|
EP1INBUF[5] = nibble2hex((t >> 4) & 0x0f); SYNCDELAY;
|
||
|
EP1INBUF[6] = nibble2hex((t >> 0) & 0x0f); SYNCDELAY;
|
||
|
EP1INBUF[7] = ')'; SYNCDELAY;
|
||
|
EP1INBC = 8; SYNCDELAY;
|
||
|
}
|
||
|
|
||
|
void proc_command_r(void)
|
||
|
{
|
||
|
BYTE i, *p = "OK (R)";
|
||
|
|
||
|
/* Reset TAP to logic reset state */
|
||
|
IOE = bmBIT3|bmBIT4|bmBIT6;
|
||
|
for (i=0; i<16; i++) {
|
||
|
// TMS is high - just generate a few TCK pulses
|
||
|
sleep3us();
|
||
|
IOE &= ~bmBIT3;
|
||
|
sleep3us();
|
||
|
IOE |= bmBIT3;
|
||
|
}
|
||
|
|
||
|
/* Reset speed to max. */
|
||
|
GPIFWFSELECT = 0x4E; SYNCDELAY;
|
||
|
|
||
|
/* Reset JTAG error state */
|
||
|
state_err = 0;
|
||
|
|
||
|
/* Reset LEDs and BUFFER_OE */
|
||
|
PA0 = PA1 = PA5 = 0;
|
||
|
|
||
|
/* Assert CPLD reset pins */
|
||
|
IOD = bmBIT0 | bmBIT3 | bmBIT4;
|
||
|
SYNCDELAY;
|
||
|
IOD |= bmBIT1;
|
||
|
SYNCDELAY;
|
||
|
IOD = 0;
|
||
|
|
||
|
/* Send response */
|
||
|
for (i = 0; p[i]; i++) {
|
||
|
EP1INBUF[i] = p[i]; SYNCDELAY;
|
||
|
}
|
||
|
EP1INBC = i; SYNCDELAY;
|
||
|
}
|
||
|
|
||
|
void proc_bulkdata(void);
|
||
|
|
||
|
void proc_command_w_ok(BYTE v)
|
||
|
{
|
||
|
EP1INBUF[0] = 'O'; SYNCDELAY;
|
||
|
EP1INBUF[1] = 'K'; SYNCDELAY;
|
||
|
EP1INBUF[2] = ' '; SYNCDELAY;
|
||
|
EP1INBUF[3] = '('; SYNCDELAY;
|
||
|
EP1INBUF[4] = 'W'; SYNCDELAY;
|
||
|
EP1INBUF[5] = nibble2hex(v); SYNCDELAY;
|
||
|
EP1INBUF[6] = ')'; SYNCDELAY;
|
||
|
EP1INBC = 7; SYNCDELAY;
|
||
|
}
|
||
|
|
||
|
void proc_command_w_timeout(BYTE v)
|
||
|
{
|
||
|
EP1INBUF[0] = 'T'; SYNCDELAY;
|
||
|
EP1INBUF[1] = 'I'; SYNCDELAY;
|
||
|
EP1INBUF[2] = 'M'; SYNCDELAY;
|
||
|
EP1INBUF[3] = 'E'; SYNCDELAY;
|
||
|
EP1INBUF[4] = 'O'; SYNCDELAY;
|
||
|
EP1INBUF[5] = 'U'; SYNCDELAY;
|
||
|
EP1INBUF[6] = 'T'; SYNCDELAY;
|
||
|
EP1INBUF[7] = '!'; SYNCDELAY;
|
||
|
EP1INBUF[8] = ' '; SYNCDELAY;
|
||
|
EP1INBUF[9] = 'S'; SYNCDELAY;
|
||
|
EP1INBUF[10] = '='; SYNCDELAY;
|
||
|
EP1INBUF[11] = nibble2hex(IOC >> 4); SYNCDELAY;
|
||
|
EP1INBUF[12] = ' '; SYNCDELAY;
|
||
|
EP1INBUF[13] = '('; SYNCDELAY;
|
||
|
EP1INBUF[14] = 'W'; SYNCDELAY;
|
||
|
EP1INBUF[15] = nibble2hex(v); SYNCDELAY;
|
||
|
EP1INBUF[16] = ')'; SYNCDELAY;
|
||
|
EP1INBC = 17; SYNCDELAY;
|
||
|
}
|
||
|
|
||
|
void proc_command_w(BYTE v)
|
||
|
{
|
||
|
WORD i, j;
|
||
|
|
||
|
for (i = 0; i < 1000; i++)
|
||
|
for (j = 0; j < 1000; j++)
|
||
|
{
|
||
|
/* check for wait condition */
|
||
|
if ((IOC >> 4) == v) {
|
||
|
proc_command_w_ok(v);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* check for data on EP2 */
|
||
|
if((EP2CS & bmBIT2) == 0) {
|
||
|
PA0 = 1;
|
||
|
proc_bulkdata();
|
||
|
PA0 = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
proc_command_w_timeout(v);
|
||
|
}
|
||
|
|
||
|
void proc_command_c(void)
|
||
|
{
|
||
|
BYTE i, j, buf;
|
||
|
|
||
|
/* Reset chksum register */
|
||
|
PD0 = 1;
|
||
|
PD1 = 0;
|
||
|
SYNCDELAY;
|
||
|
PD1 = 1;
|
||
|
SYNCDELAY;
|
||
|
PD0 = 0;
|
||
|
PD1 = 0;
|
||
|
|
||
|
for (i = 0; i < 6; i++) {
|
||
|
buf = 0;
|
||
|
for (j = 0; j < 4; j++) {
|
||
|
buf = buf << 1 | PC2;
|
||
|
SYNCDELAY;
|
||
|
PD1 = 1;
|
||
|
SYNCDELAY;
|
||
|
PD1 = 0;
|
||
|
}
|
||
|
EP1INBUF[i] = nibble2hex(buf); SYNCDELAY;
|
||
|
}
|
||
|
|
||
|
EP1INBUF[6] = ' '; SYNCDELAY;
|
||
|
EP1INBUF[7] = '('; SYNCDELAY;
|
||
|
EP1INBUF[8] = 'C'; SYNCDELAY;
|
||
|
EP1INBUF[9] = ')'; SYNCDELAY;
|
||
|
EP1INBC = 10; SYNCDELAY;
|
||
|
}
|
||
|
|
||
|
void proc_command_b(BYTE v)
|
||
|
{
|
||
|
PA5 = v;
|
||
|
|
||
|
EP1INBUF[0] = 'O'; SYNCDELAY;
|
||
|
EP1INBUF[1] = 'K'; SYNCDELAY;
|
||
|
EP1INBUF[2] = ' '; SYNCDELAY;
|
||
|
EP1INBUF[3] = '('; SYNCDELAY;
|
||
|
EP1INBUF[4] = 'B'; SYNCDELAY;
|
||
|
EP1INBUF[5] = v ? '1' : '0'; SYNCDELAY;
|
||
|
EP1INBUF[6] = ')'; SYNCDELAY;
|
||
|
EP1INBC = 7; SYNCDELAY;
|
||
|
}
|
||
|
|
||
|
void proc_command_i(BYTE v)
|
||
|
{
|
||
|
PD2 = v;
|
||
|
|
||
|
EP1INBUF[0] = 'O'; SYNCDELAY;
|
||
|
EP1INBUF[1] = 'K'; SYNCDELAY;
|
||
|
EP1INBUF[2] = ' '; SYNCDELAY;
|
||
|
EP1INBUF[3] = '('; SYNCDELAY;
|
||
|
EP1INBUF[4] = 'I'; SYNCDELAY;
|
||
|
EP1INBUF[5] = v ? '1' : '0'; SYNCDELAY;
|
||
|
EP1INBUF[6] = ')'; SYNCDELAY;
|
||
|
EP1INBC = 7; SYNCDELAY;
|
||
|
}
|
||
|
|
||
|
void proc_command_s(void)
|
||
|
{
|
||
|
EP1INBUF[0] = PC0 ? '1' : '0'; SYNCDELAY;
|
||
|
EP1INBUF[1] = state_err ? '1' : '0'; SYNCDELAY;
|
||
|
EP1INBUF[2] = PC1 ? '1' : '0'; SYNCDELAY;
|
||
|
EP1INBUF[3] = PA2 ? '1' : '0'; SYNCDELAY;
|
||
|
EP1INBUF[4] = PC3 ? '1' : '0'; SYNCDELAY;
|
||
|
EP1INBUF[5] = (IOE & bmBIT5) ? '1' : '0'; SYNCDELAY;
|
||
|
EP1INBUF[6] = nibble2hex(IOC >> 4); SYNCDELAY;
|
||
|
EP1INBUF[7] = ' '; SYNCDELAY;
|
||
|
EP1INBUF[8] = '('; SYNCDELAY;
|
||
|
EP1INBUF[9] = 'S'; SYNCDELAY;
|
||
|
EP1INBUF[10] = ')'; SYNCDELAY;
|
||
|
EP1INBC = 11; SYNCDELAY;
|
||
|
|
||
|
// reset error state
|
||
|
state_err = 0;
|
||
|
IOD = bmBIT3;
|
||
|
SYNCDELAY;
|
||
|
SYNCDELAY;
|
||
|
IOD &= ~bmBIT3;
|
||
|
}
|
||
|
|
||
|
void proc_command_p(void)
|
||
|
{
|
||
|
EP1INBUF[0] = PC0 ? '1' : '0'; SYNCDELAY;
|
||
|
EP1INBUF[1] = state_err ? '1' : '0'; SYNCDELAY;
|
||
|
EP1INBUF[2] = PC1 ? '1' : '0'; SYNCDELAY;
|
||
|
EP1INBUF[3] = PA2 ? '1' : '0'; SYNCDELAY;
|
||
|
EP1INBUF[4] = PC3 ? '1' : '0'; SYNCDELAY;
|
||
|
EP1INBUF[5] = (IOE & bmBIT5) ? '1' : '0'; SYNCDELAY;
|
||
|
EP1INBUF[6] = nibble2hex(IOC >> 4); SYNCDELAY;
|
||
|
EP1INBUF[7] = ' '; SYNCDELAY;
|
||
|
EP1INBUF[8] = '('; SYNCDELAY;
|
||
|
EP1INBUF[9] = 'P'; SYNCDELAY;
|
||
|
EP1INBUF[10] = ')'; SYNCDELAY;
|
||
|
EP1INBC = 11; SYNCDELAY;
|
||
|
}
|
||
|
|
||
|
BYTE proc_command_j_exec_skip_next;
|
||
|
void proc_command_j_exec(BYTE cmd)
|
||
|
{
|
||
|
if (proc_command_j_exec_skip_next) {
|
||
|
proc_command_j_exec_skip_next = 0;
|
||
|
return;
|
||
|
}
|
||
|
if (cmd == 0x00)
|
||
|
return;
|
||
|
if (cmd == 0x01) {
|
||
|
// 0001 xxxx: Set sync signal to 'xxxx' (engine on CPLD only)
|
||
|
proc_command_j_exec_skip_next = 1;
|
||
|
return;
|
||
|
}
|
||
|
if ((cmd & 0x0c) == 0x04)
|
||
|
{
|
||
|
// 01xy: JTAG transaction without TDO check. TMS=x, TDI=y
|
||
|
|
||
|
/* set tms line */
|
||
|
if (cmd & 0x02)
|
||
|
IOE |= bmBIT4;
|
||
|
else
|
||
|
IOE &= ~bmBIT4;
|
||
|
|
||
|
/* set tdi line */
|
||
|
if (cmd & 0x01)
|
||
|
IOE |= bmBIT6;
|
||
|
else
|
||
|
IOE &= ~bmBIT6;
|
||
|
|
||
|
/* generate tck pulse */
|
||
|
SYNCDELAY;
|
||
|
IOE &= ~bmBIT3;
|
||
|
sleep3us();
|
||
|
IOE |= bmBIT3;
|
||
|
SYNCDELAY;
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
if ((cmd & 0x08) == 0x08)
|
||
|
{
|
||
|
// 1zxy: JTAG transaction with TDO check. TDO=z, TMS=x, TDI=y
|
||
|
|
||
|
/* set tms line */
|
||
|
if (cmd & 0x02)
|
||
|
IOE |= bmBIT4;
|
||
|
else
|
||
|
IOE &= ~bmBIT4;
|
||
|
|
||
|
/* set tdi line */
|
||
|
if (cmd & 0x01)
|
||
|
IOE |= bmBIT6;
|
||
|
else
|
||
|
IOE &= ~bmBIT6;
|
||
|
|
||
|
/* generate tck pulse */
|
||
|
SYNCDELAY;
|
||
|
IOE &= ~bmBIT3;
|
||
|
sleep3us();
|
||
|
IOE |= bmBIT3;
|
||
|
SYNCDELAY;
|
||
|
|
||
|
/* perform tdo check */
|
||
|
if (((cmd & 0x04) == 0) != ((IOE & bmBIT5) == 0))
|
||
|
state_err = 1;
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void proc_command_j(BYTE len)
|
||
|
{
|
||
|
BYTE i;
|
||
|
proc_command_j_exec_skip_next = 0;
|
||
|
for (i = 1; i < len; i++) {
|
||
|
BYTE cmd = EP1OUTBUF[i];
|
||
|
proc_command_j_exec(cmd & 0x0f);
|
||
|
proc_command_j_exec(cmd >> 4);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void proc_command_x(void)
|
||
|
{
|
||
|
EP1INBUF[0] = 'O'; SYNCDELAY;
|
||
|
EP1INBUF[1] = 'K'; SYNCDELAY;
|
||
|
EP1INBUF[2] = ' '; SYNCDELAY;
|
||
|
EP1INBUF[3] = '('; SYNCDELAY;
|
||
|
EP1INBUF[4] = 'X'; SYNCDELAY;
|
||
|
EP1INBUF[5] = ')'; SYNCDELAY;
|
||
|
EP1INBC = 6; SYNCDELAY;
|
||
|
|
||
|
/* accept new data on EP1OUT */
|
||
|
EP1OUTBC = 0xff; SYNCDELAY;
|
||
|
|
||
|
unsetup();
|
||
|
}
|
||
|
|
||
|
void proc_command(void)
|
||
|
{
|
||
|
BYTE len, cmd;
|
||
|
|
||
|
/* process command(s) */
|
||
|
len = EP1OUTBC;
|
||
|
cmd = EP1OUTBUF[0];
|
||
|
|
||
|
if (cmd == 'T' && len == 3)
|
||
|
proc_command_t((hex2nibble(EP1OUTBUF[1]) << 4) | hex2nibble(EP1OUTBUF[2]));
|
||
|
else if (cmd == 'R' && len == 1)
|
||
|
proc_command_r();
|
||
|
else if (cmd == 'W' && len == 2)
|
||
|
proc_command_w(hex2nibble(EP1OUTBUF[1]));
|
||
|
else if (cmd == 'C' && len == 1)
|
||
|
proc_command_c();
|
||
|
else if (cmd == 'B' && len == 2)
|
||
|
proc_command_b(EP1OUTBUF[1] == '1');
|
||
|
else if (cmd == 'I' && len == 2)
|
||
|
proc_command_i(EP1OUTBUF[1] == '1');
|
||
|
else if (cmd == 'S' && len == 1)
|
||
|
proc_command_s();
|
||
|
else if (cmd == 'P' && len == 1)
|
||
|
proc_command_p();
|
||
|
else if (cmd == 'J')
|
||
|
proc_command_j(len);
|
||
|
else if (cmd == 'X')
|
||
|
proc_command_x();
|
||
|
else
|
||
|
{
|
||
|
/* send error response */
|
||
|
EP1INBUF[0] = 'E'; SYNCDELAY;
|
||
|
EP1INBUF[1] = 'R'; SYNCDELAY;
|
||
|
EP1INBUF[2] = 'R'; SYNCDELAY;
|
||
|
EP1INBUF[3] = 'O'; SYNCDELAY;
|
||
|
EP1INBUF[4] = 'R'; SYNCDELAY;
|
||
|
EP1INBUF[5] = '!'; SYNCDELAY;
|
||
|
EP1INBC = 6; SYNCDELAY;
|
||
|
}
|
||
|
|
||
|
/* accept new data on EP1OUT */
|
||
|
EP1OUTBC = 0xff; SYNCDELAY;
|
||
|
}
|
||
|
|
||
|
void proc_bulkdata(void)
|
||
|
{
|
||
|
WORD len;
|
||
|
|
||
|
len = (EP2BCH << 8) | EP2BCL;
|
||
|
if (len == 0)
|
||
|
{
|
||
|
/* ignore this and accept data on EP2 */
|
||
|
EP2BCL = 0xff; SYNCDELAY;
|
||
|
}
|
||
|
#if 0
|
||
|
else if (len == 1)
|
||
|
{
|
||
|
while ((GPIFTRIG & 0x80) == 0) { /* GPIF is busy */ }
|
||
|
|
||
|
/* transfer single byte */
|
||
|
XGPIFSGLDATH = 0; SYNCDELAY;
|
||
|
XGPIFSGLDATLX = EP2FIFOBUF[0]; SYNCDELAY;
|
||
|
|
||
|
/* accept new data on EP2 */
|
||
|
EP2BCL = 0xff; SYNCDELAY;
|
||
|
}
|
||
|
#endif
|
||
|
else
|
||
|
{
|
||
|
while ((GPIFTRIG & 0x80) == 0) { /* GPIF is busy */ }
|
||
|
|
||
|
/* pass pkt to GPIF master */
|
||
|
EP2GPIFTCH = EP2BCH;
|
||
|
EP2GPIFTCL = EP2BCL;
|
||
|
EP2BCL = 0x00;
|
||
|
EP2GPIFTRIG = 0xff;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void main(void)
|
||
|
{
|
||
|
state_err = 0;
|
||
|
|
||
|
setup();
|
||
|
|
||
|
/* accept data on EP2 */
|
||
|
EP2BCL = 0xff; SYNCDELAY; // 1st buffer
|
||
|
EP2BCL = 0xff; SYNCDELAY; // 2nd buffer
|
||
|
#ifdef ALL_RESOURCES_ON_EP2
|
||
|
EP2BCL = 0xff; SYNCDELAY; // 3rd buffer
|
||
|
EP2BCL = 0xff; SYNCDELAY; // 4th buffer
|
||
|
#endif
|
||
|
|
||
|
while (1)
|
||
|
{
|
||
|
/* check for data on EP1 */
|
||
|
if((EP1OUTCS & bmBIT1) == 0) {
|
||
|
PA1 = 1;
|
||
|
proc_command();
|
||
|
PA1 = 0;
|
||
|
}
|
||
|
|
||
|
/* check for data on EP2 */
|
||
|
if((EP2CS & bmBIT2) == 0) {
|
||
|
PA0 = 1;
|
||
|
proc_bulkdata();
|
||
|
PA0 = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|