1
0
mirror of git://projects.qi-hardware.com/nn-usb-fpga.git synced 2025-01-09 23:50:14 +02:00
nn-usb-fpga/Software/xc3sprog/iobase.cpp

353 lines
6.9 KiB
C++
Raw Normal View History

/* JTAG low level functions and base class for cables
Copyright (C) 2004 Andrew Rogers
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "iobase.h"
#include <stdio.h>
using namespace std;
IOBase::IOBase()
{
current_state=UNKNOWN;
}
int IOBase::shiftTDITDO(const unsigned char *tdi, unsigned char *tdo, int length, bool last)
{
if(length==0)return 0;
int i=0;
int j=0;
unsigned char tdo_byte=0;
unsigned char tdi_byte=tdi[j];
while(i<length-1){
tdo_byte=tdo_byte+(txrx(false, (tdi_byte&1)==1)<<(i%8));
tdi_byte=tdi_byte>>1;
i++;
if((i%8)==0){ // Next byte
tdo[j]=tdo_byte; // Save the TDO byte
tdo_byte=0;
j++;
tdi_byte=tdi[j]; // Get the next TDI byte
}
};
tdo_byte=tdo_byte+(txrx(last, (tdi_byte&1)==1)<<(i%8)); // TMS set if last=true
tdo[j]=tdo_byte;
nextTapState(last); // If TMS is set the the state of the tap changes
}
int IOBase::shiftTDI(const unsigned char *tdi, int length, bool last)
{
if(length==0)return 0;
int i=0;
int j=0;
unsigned char tdi_byte=tdi[j];
while(i<length-1){
tx(false, (tdi_byte&1)==1);
tdi_byte=tdi_byte>>1;
i++;
if((i%8)==0){ // Next byte
j++;
tdi_byte=tdi[j]; //Get the next TDI byte
}
};
tx(last, (tdi_byte&1)==1); // TMS set if last=true
nextTapState(last); // If TMS is set the the state of the tap changes
}
// TDI gets a load of zeros, we just record TDO.
int IOBase::shiftTDO(unsigned char *tdo, int length, bool last)
{
if(length==0)return 0;
int i=0;
int j=0;
unsigned char tdo_byte=0;
while(i<length-1){
tdo_byte=tdo_byte+(txrx(false, false)<<(i%8));
i++;
if((i%8)==0){ // Next byte
tdo[j]=tdo_byte; // Save the TDO byte
tdo_byte=0;
j++;
}
};
tdo_byte=tdo_byte+(txrx(last, false)<<(i%8)); // TMS set if last=true
tdo[j]=tdo_byte;
nextTapState(last); // If TMS is set the the state of the tap changes
}
// TDI gets a load of zeros or ones, and we ignore TDO
int IOBase::shift(bool tdi, int length, bool last)
{
if(length==0)return 0;
int i=0;
while(i<length-1){
tx(false, tdi);
i++;
};
tx(last, tdi); // TMS set if last=true
nextTapState(last); // If TMS is set the the state of the tap changes
}
int IOBase::setTapState(tapState_t state)
{
bool tms;
while(current_state!=state){
switch(current_state){
case TEST_LOGIC_RESET:
switch(state){
case TEST_LOGIC_RESET:
tms=true;
break;
default:
tms=false;
current_state=RUN_TEST_IDLE;
};
break;
case RUN_TEST_IDLE:
switch(state){
case RUN_TEST_IDLE:
tms=false;
break;
default:
tms=true;
current_state=SELECT_DR_SCAN;
};
break;
case SELECT_DR_SCAN:
switch(state){
case CAPTURE_DR:
case SHIFT_DR:
case EXIT1_DR:
case PAUSE_DR:
case EXIT2_DR:
case UPDATE_DR:
tms=false;
current_state=CAPTURE_DR;
break;
default:
tms=true;
current_state=SELECT_IR_SCAN;
};
break;
case CAPTURE_DR:
switch(state){
case SHIFT_DR:
tms=false;
current_state=SHIFT_DR;
break;
default:
tms=true;
current_state=EXIT1_DR;
};
break;
case SHIFT_DR:
switch(state){
case SHIFT_DR:
tms=false;
break;
default:
tms=true;
current_state=EXIT1_DR;
};
break;
case EXIT1_DR:
switch(state){
case PAUSE_DR:
case EXIT2_DR:
case SHIFT_DR:
case EXIT1_DR:
tms=false;
current_state=PAUSE_DR;
break;
default:
tms=true;
current_state=UPDATE_DR;
};
break;
case PAUSE_DR:
switch(state){
case PAUSE_DR:
tms=false;
break;
default:
tms=true;
current_state=EXIT2_DR;
};
break;
case EXIT2_DR:
switch(state){
case SHIFT_DR:
case EXIT1_DR:
case PAUSE_DR:
tms=false;
current_state=SHIFT_DR;
break;
default:
tms=true;
current_state=UPDATE_DR;
};
break;
case UPDATE_DR:
switch(state){
case RUN_TEST_IDLE:
tms=false;
current_state=RUN_TEST_IDLE;
break;
default:
tms=true;
current_state=SELECT_DR_SCAN;
};
break;
case SELECT_IR_SCAN:
switch(state){
case CAPTURE_IR:
case SHIFT_IR:
case EXIT1_IR:
case PAUSE_IR:
case EXIT2_IR:
case UPDATE_IR:
tms=false;
current_state=CAPTURE_IR;
break;
default:
tms=true;
current_state=TEST_LOGIC_RESET;
};
break;
case CAPTURE_IR:
switch(state){
case SHIFT_IR:
tms=false;
current_state=SHIFT_IR;
break;
default:
tms=true;
current_state=EXIT1_IR;
};
break;
case SHIFT_IR:
switch(state){
case SHIFT_IR:
tms=false;
break;
default:
tms=true;
current_state=EXIT1_IR;
};
break;
case EXIT1_IR:
switch(state){
case PAUSE_IR:
case EXIT2_IR:
case SHIFT_IR:
case EXIT1_IR:
tms=false;
current_state=PAUSE_IR;
break;
default:
tms=true;
current_state=UPDATE_IR;
};
break;
case PAUSE_IR:
switch(state){
case PAUSE_IR:
tms=false;
break;
default:
tms=true;
current_state=EXIT2_IR;
};
break;
case EXIT2_IR:
switch(state){
case SHIFT_IR:
case EXIT1_IR:
case PAUSE_IR:
tms=false;
current_state=SHIFT_IR;
break;
default:
tms=true;
current_state=UPDATE_IR;
};
break;
case UPDATE_IR:
switch(state){
case RUN_TEST_IDLE:
tms=false;
current_state=RUN_TEST_IDLE;
break;
default:
tms=true;
current_state=SELECT_DR_SCAN;
};
break;
default:
tapTestLogicReset();
tms=true;
};
tx(tms,false);
};
}
// After shift data into the DR or IR we goto the next state
// This function should only be called from the end of a shift function
int IOBase::nextTapState(bool tms)
{
if(current_state==SHIFT_DR){
if(tms)current_state=EXIT1_DR; // If TMS was set then goto next state
}
else if(current_state==SHIFT_IR){
if(tms)current_state=EXIT1_IR; // If TMS was set then goto next state
}
else tapTestLogicReset(); // We were in an unexpected state
}
void IOBase::tapTestLogicReset()
{
for(int i=0; i<5; i++)tx(true,false);
current_state=TEST_LOGIC_RESET;
}
void IOBase::cycleTCK(int n, bool tdi)
{
bool tms=false;
if(current_state==TEST_LOGIC_RESET)tms=true;
for(int i=0; i<n; i++)tx(tms,tdi);
}