/* 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); }