#ifndef __FT2232JTAG_H__ #define __FT2232JTAG_H__ #include #include "cable.h" #include "long_bits.h" //#define WIN32 #ifdef WIN32 #define USE_FT2232JTAG #include "FTCJTAG/FTCJTAG.h" struct pin_state_t { BOOL &in_out; BOOL &low_high; pin_state_t(BOOL &_in_out, BOOL &_low_high) : in_out(_in_out), low_high(_low_high) {} ~pin_state_t(){} static const BOOL dir_out = true; static const BOOL dir_in = false; static const BOOL level_high = true; static const BOOL level_low = false; }; class FT2232JTAG : public cable { protected: FTC_HANDLE ftHandle; DWORD dwDeviceNameIndex; DWORD dwClockFrequencyHz; DWORD dwClockDivisor; DWORD dwTapNext; bool is_highspeed; FTC_INPUT_OUTPUT_PINS LowInputOutputPinsData; FTH_INPUT_OUTPUT_PINS HighInputOutputPinsData; FTC_LOW_HIGH_PINS LowPinsInputData; FTH_LOW_HIGH_PINS HighPinsInputData; protected: virtual const pin_state_t *jtag_oe_n () const = 0; virtual const pin_state_t *vref_n_in () const = 0; virtual const pin_state_t *trst_n_oe_n () const = 0; virtual const pin_state_t *trst_n_out () const = 0; virtual const pin_state_t *srst_n_oe_n () const = 0; virtual const pin_state_t *srst_n_out () const = 0; virtual const pin_state_t *srst_n_in () const = 0; public: FT2232JTAG(const char* param) throw (std::exception) : cable(), dwDeviceNameIndex(0), dwClockDivisor(0), is_highspeed(false) { LowInputOutputPinsData.bPin1InputOutputState = false; // = input LowInputOutputPinsData.bPin2InputOutputState = false; LowInputOutputPinsData.bPin3InputOutputState = false; LowInputOutputPinsData.bPin4InputOutputState = false; LowInputOutputPinsData.bPin1LowHighState = false; // = low LowInputOutputPinsData.bPin2LowHighState = false; LowInputOutputPinsData.bPin3LowHighState = false; LowInputOutputPinsData.bPin4LowHighState = false; HighInputOutputPinsData.bPin1InputOutputState = false; HighInputOutputPinsData.bPin2InputOutputState = false; HighInputOutputPinsData.bPin3InputOutputState = false; HighInputOutputPinsData.bPin4InputOutputState = false; HighInputOutputPinsData.bPin5InputOutputState = false; HighInputOutputPinsData.bPin6InputOutputState = false; HighInputOutputPinsData.bPin7InputOutputState = false; HighInputOutputPinsData.bPin8InputOutputState = false; HighInputOutputPinsData.bPin1LowHighState = false; HighInputOutputPinsData.bPin2LowHighState = false; HighInputOutputPinsData.bPin3LowHighState = false; HighInputOutputPinsData.bPin4LowHighState = false; HighInputOutputPinsData.bPin5LowHighState = false; HighInputOutputPinsData.bPin6LowHighState = false; HighInputOutputPinsData.bPin7LowHighState = false; HighInputOutputPinsData.bPin8LowHighState = false; if(param){ // [[nakatomo]] char *dummy; dwClockDivisor = strtol(param, &dummy, 10); tracef(2, "FT2232: dwClockDivisor = %d; clock = %f Hz\n", dwClockDivisor, (double)(12e6) / ((1 + dwClockDivisor) * 2)); } // Dll check { FTC_STATUS Status; char szDllVersion[10]; Status = JTAG_GetDllVersion(szDllVersion, 10); if(Status != FTC_SUCCESS){ char msg[] = "Dll error!!"; printf("%s\n", msg); throw std::exception(msg); } tracef(3, "FT2232: szDllVersion = %s\n", szDllVersion); /*if(strcmp("1.9", szDllVersion) != 0){ char msg[] = "Dll version mismatch, 1.9 required!!"; printf("%s\n", msg); throw std::exception(msg); }*/ } } virtual ~FT2232JTAG() { close(); } FTC_STATUS setGPIOs( bool bControlLowIO, PFTC_INPUT_OUTPUT_PINS pLowIOData, bool bControlHighIO, PFTH_INPUT_OUTPUT_PINS pHighIOData){ if(is_highspeed){ return JTAG_SetHiSpeedDeviceGPIOs(ftHandle, bControlLowIO, pLowIOData, bControlHighIO, pHighIOData); }else{ // probably static_cast available... FTC_INPUT_OUTPUT_PINS HighIOData; HighIOData.bPin1InputOutputState = pHighIOData->bPin1InputOutputState; HighIOData.bPin1LowHighState = pHighIOData->bPin1LowHighState; HighIOData.bPin2InputOutputState = pHighIOData->bPin2InputOutputState; HighIOData.bPin2LowHighState = pHighIOData->bPin2LowHighState; HighIOData.bPin3InputOutputState = pHighIOData->bPin3InputOutputState; HighIOData.bPin3LowHighState = pHighIOData->bPin3LowHighState; HighIOData.bPin4InputOutputState = pHighIOData->bPin4InputOutputState; HighIOData.bPin4LowHighState = pHighIOData->bPin4LowHighState; return JTAG_SetGPIOs(ftHandle, bControlLowIO, pLowIOData, bControlHighIO, &HighIOData); } } FTC_STATUS getGPIOs( bool bControlLowIO, PFTC_LOW_HIGH_PINS pLowIData, bool bControlHighIO, PFTH_LOW_HIGH_PINS pHighIData){ if(is_highspeed){ return JTAG_GetHiSpeedDeviceGPIOs(ftHandle, bControlLowIO, pLowIData, bControlHighIO, pHighIData); }else{ // probably static_cast available... FTC_LOW_HIGH_PINS HighIData; FTC_STATUS res(JTAG_GetGPIOs(ftHandle, bControlLowIO, pLowIData, bControlHighIO, &HighIData)); pHighIData->bPin1LowHighState = HighIData.bPin1LowHighState; pHighIData->bPin2LowHighState = HighIData.bPin2LowHighState; pHighIData->bPin3LowHighState = HighIData.bPin3LowHighState; pHighIData->bPin4LowHighState = HighIData.bPin4LowHighState; return res; } } public: cable::res_t open(){ FTC_STATUS Status; DWORD dwNumDevices = 0; while(true){ // detection of high speed device preferentially Status = JTAG_GetNumHiSpeedDevices(&dwNumDevices); if((Status == FTC_SUCCESS) && (dwNumDevices > 0)){ is_highspeed = true; break; } Status = JTAG_GetNumDevices(&dwNumDevices); if((Status != FTC_SUCCESS) || (dwNumDevices <= 0)){return cable::res_fail;} break; } if(is_highspeed){ char szDeviceName[100]; char szChannel[5]; DWORD dwLocationID; DWORD dwHiSpeedDeviceType; while(dwDeviceNameIndex < dwNumDevices){ Status = JTAG_GetHiSpeedDeviceNameLocIDChannel( dwDeviceNameIndex, szDeviceName, sizeof(szDeviceName), &dwLocationID, szChannel, sizeof(szChannel), &dwHiSpeedDeviceType); if((Status == FTC_SUCCESS) /*&& (strcmp(szChannel, "A") != 0)*/){ // using the first detected device break; } dwDeviceNameIndex++; } Status = JTAG_OpenHiSpeedDevice(szDeviceName, dwLocationID, szChannel, &ftHandle); if(Status != FTC_SUCCESS){return cable::res_fail;} //Status = JTAG_GetHiSpeedDeviceType(ftHandle, &dwHiSpeedDeviceType); //if(Status != FTC_SUCCESS){return cable::res_fail;} tracef(3, "Type = %s, Name = %s\n", ((dwHiSpeedDeviceType == FT4232H_DEVICE_TYPE) ? "FT4232H" : "FT2232H"), szDeviceName); }else{ char szDeviceName[100]; DWORD dwLocationID; Status = JTAG_GetDeviceNameLocID( dwDeviceNameIndex, szDeviceName, sizeof(szDeviceName), &dwLocationID); if(Status != FTC_SUCCESS){return cable::res_fail;} Status = JTAG_OpenEx(szDeviceName, dwLocationID, &ftHandle); if(Status != FTC_SUCCESS){return cable::res_fail;} } Status = JTAG_InitDevice(ftHandle, dwClockDivisor); if(Status != FTC_SUCCESS){return cable::res_fail;} dwTapNext = RUN_TEST_IDLE_STATE; Status = is_highspeed ? JTAG_GetHiSpeedDeviceClock(dwClockDivisor, &dwClockFrequencyHz) : JTAG_GetClock(dwClockDivisor, &dwClockFrequencyHz); if(Status != FTC_SUCCESS){return cable::res_fail;} Status = JTAG_SetLoopback(ftHandle, false); if (Status != FTC_SUCCESS){return cable::res_fail;} // GPIO setting { const pin_state_t *state; if(state = jtag_oe_n()){ state->in_out = pin_state_t::dir_out; state->low_high = pin_state_t::level_low; } if(state = vref_n_in()){ state->in_out = pin_state_t::dir_in; } if(state = trst_n_oe_n()){ state->in_out = pin_state_t::dir_out; state->low_high = pin_state_t::level_low; } if(state = trst_n_out()){ state->in_out = pin_state_t::dir_out; state->low_high = pin_state_t::level_low; } if(state = srst_n_oe_n()){ state->in_out = pin_state_t::dir_out; state->low_high = pin_state_t::level_low; } if(state = srst_n_out()){ state->in_out = pin_state_t::dir_out; state->low_high = pin_state_t::level_low; } if(state = srst_n_in()){ state->in_out = pin_state_t::dir_in; } } Status = setGPIOs(true, &LowInputOutputPinsData, true, &HighInputOutputPinsData); if(Status != FTC_SUCCESS){return cable::res_fail;} Status = getGPIOs(true, &LowPinsInputData, true, &HighPinsInputData); if(Status != FTC_SUCCESS){return cable::res_fail;} return cable::res_success; } cable::res_t close(){ if(!ftHandle){ // [[nakatomo]] return cable::res_success; } FTC_STATUS Status = JTAG_Close(ftHandle); return (Status == FTC_SUCCESS) ? cable::res_success : cable::res_fail; } int get_desc(char* desc, int len){ FTC_STATUS Status; char szDeviceName[100]; char szChannel[5]; DWORD dwLocationID; DWORD dwHiSpeedDeviceType; // detection of high speed device preferentially Status = JTAG_GetHiSpeedDeviceNameLocIDChannel( dwDeviceNameIndex, szDeviceName, sizeof(szDeviceName), &dwLocationID, szChannel, sizeof(szChannel), &dwHiSpeedDeviceType); if(Status != FTC_SUCCESS){ Status = JTAG_GetDeviceNameLocID( dwDeviceNameIndex, szDeviceName, sizeof(szDeviceName), &dwLocationID); } return snprintf(desc, len, "%s", (Status == FTC_SUCCESS) ? szDeviceName : "FT2232 based cable"); } //virtual int set_option(const char* name, const char* value); //virtual int get_option(const char* name, char* value, int len); cable::res_t set_tms(int b){ return cable::res_success; } cable::res_t set_tck(int b){ return cable::res_success; } cable::res_t pulse_tck(int count){ FTC_STATUS Status = JTAG_GenerateClockPulses(ftHandle, count); return (Status == FTC_SUCCESS) ? cable::res_success : cable::res_fail; } cable::res_t state_transit(int state_from, int state_to){ switch(state_to){ case TAPSTATE_RESET: dwTapNext = TEST_LOGIC_STATE; break; case TAPSTATE_EXIT1DR: case TAPSTATE_EXIT2DR: case TAPSTATE_UPDATEDR: case TAPSTATE_EXIT1IR: case TAPSTATE_EXIT2IR: case TAPSTATE_UPDATEIR: case TAPSTATE_IDLE: dwTapNext = RUN_TEST_IDLE_STATE; break; case TAPSTATE_PAUSEDR: dwTapNext = PAUSE_TEST_DATA_REGISTER_STATE; break; case TAPSTATE_PAUSEIR: dwTapNext = PAUSE_INSTRUCTION_REGISTER_STATE; break; case TAPSTATE_SELECTDR: case TAPSTATE_CAPTUREDR: case TAPSTATE_SHIFTDR: dwTapNext = SHIFT_TEST_DATA_REGISTER_STATE; break; case TAPSTATE_SELECTIR: case TAPSTATE_CAPTUREIR: case TAPSTATE_SHIFTIR: dwTapNext = SHIFT_INSTRUCTION_REGISTER_STATE; break; } return cable::res_success; } cable::res_t shift(int num_bits, const void* wbuff, void* rbuff, bool exit_shift_state){ BOOL bInstructionTestData; switch(dwTapNext){ case PAUSE_TEST_DATA_REGISTER_STATE: case SHIFT_TEST_DATA_REGISTER_STATE: bInstructionTestData = FALSE; break; case PAUSE_INSTRUCTION_REGISTER_STATE: case SHIFT_INSTRUCTION_REGISTER_STATE: bInstructionTestData = TRUE; break; default: return cable::res_fail; } if(exit_shift_state){ dwTapNext = RUN_TEST_IDLE_STATE; }else{ switch(dwTapNext){ case SHIFT_TEST_DATA_REGISTER_STATE: dwTapNext = PAUSE_TEST_DATA_REGISTER_STATE; break; case SHIFT_INSTRUCTION_REGISTER_STATE: dwTapNext = PAUSE_INSTRUCTION_REGISTER_STATE; break; } } tracef(3, "FT2232: shift(): inst=%d, num_bits=%d\n", bInstructionTestData, num_bits); tracef(4, "FT2232: wbuff: "); trace(4, LongBits((unsigned char *)wbuff, num_bits)); tracef(4, "\n"); // should be w_num_bits > 0 or r_num_bits > 0 if(num_bits == 0){ tracef(2, "FT2232: num_bits == 0\n"); return cable::res_fail; } ReadDataByteBuffer ReadDataBuffer; DWORD dwNumBytesReturned; FTC_STATUS Status; #define min_which(a, b) (((a) < (b)) ? (a) : (b)) static const int max_bytes( (min_which( MAX_WRITE_DATA_BYTES_BUFFER_SIZE, MAX_READ_DATA_BYTES_BUFFER_SIZE) >> 1)); BYTE *_wbuff((BYTE *)wbuff), *_rbuff((BYTE *)rbuff); int bytes_per_1op((num_bits + 8 - 1) / 8); // 大きすぎる場合、均等に書き込む for(int i(1); i++; ){ int temp(bytes_per_1op / i); if(temp <= max_bytes){ bytes_per_1op = temp; break; } } while(num_bits > 0){ int bytes((num_bits + 8 - 1) / 8); int bits(num_bits); DWORD tapNext(dwTapNext); if(bytes > max_bytes){ bytes = bytes_per_1op; bits = bytes * 8; tapNext = (bInstructionTestData ? SHIFT_INSTRUCTION_REGISTER_STATE : SHIFT_TEST_DATA_REGISTER_STATE); } Status = JTAG_WriteRead(ftHandle, bInstructionTestData, bits, (PWriteDataByteBuffer)_wbuff, bytes, &ReadDataBuffer, &dwNumBytesReturned, tapNext); if(Status != FTC_SUCCESS){ return cable::res_fail; } tracef(3, "FT2232: shift(): code=%d, returned byte=%d, tap=%d\n", Status, dwNumBytesReturned, tapNext); tracef(4, "FT2232: rbuff: "); trace(4, LongBits((unsigned char *)ReadDataBuffer, dwNumBytesReturned * 8)); tracef(4, "\n" ); if(dwNumBytesReturned > 0 && rbuff){ memcpy(_rbuff, &ReadDataBuffer, dwNumBytesReturned); _rbuff += bytes; } num_bits -= bits; _wbuff += bytes; } #undef min_which return cable::res_success; } }; class AmontecJTAGKey : public FT2232JTAG { protected: pin_state_t _jtag_oe_n; pin_state_t _vref_n_in; pin_state_t _trst_n_oe_n; pin_state_t _trst_n_out; pin_state_t _srst_n_oe_n; pin_state_t _srst_n_out; pin_state_t _srst_n_in; public: AmontecJTAGKey(const char* param) : FT2232JTAG(param), _jtag_oe_n( // 20 => GPIOL0 FT2232JTAG::LowInputOutputPinsData.bPin1InputOutputState, FT2232JTAG::LowInputOutputPinsData.bPin1LowHighState), _vref_n_in( // 19 => GPIOL1 FT2232JTAG::LowInputOutputPinsData.bPin2InputOutputState, FT2232JTAG::LowInputOutputPinsData.bPin2LowHighState), _trst_n_oe_n( // 12 => GPIOH2 FT2232JTAG::HighInputOutputPinsData.bPin3InputOutputState, FT2232JTAG::HighInputOutputPinsData.bPin3LowHighState), _trst_n_out( // 15 => GPIOH0 FT2232JTAG::HighInputOutputPinsData.bPin1InputOutputState, FT2232JTAG::HighInputOutputPinsData.bPin1LowHighState), _srst_n_oe_n( // 11 => GPIOH3 FT2232JTAG::HighInputOutputPinsData.bPin4InputOutputState, FT2232JTAG::HighInputOutputPinsData.bPin4LowHighState), _srst_n_out( // 13 => GPIOH1 FT2232JTAG::HighInputOutputPinsData.bPin2InputOutputState, FT2232JTAG::HighInputOutputPinsData.bPin2LowHighState), _srst_n_in( // 17 => GPIOL2 FT2232JTAG::LowInputOutputPinsData.bPin3InputOutputState, FT2232JTAG::LowInputOutputPinsData.bPin3LowHighState){ } ~AmontecJTAGKey(){} const pin_state_t *jtag_oe_n() const {return &_jtag_oe_n;} const pin_state_t *vref_n_in() const {return &_vref_n_in;} const pin_state_t *trst_n_oe_n() const {return &_trst_n_oe_n;} const pin_state_t *trst_n_out() const {return &_trst_n_out;} const pin_state_t *srst_n_oe_n() const {return &_srst_n_oe_n;} const pin_state_t *srst_n_out() const {return &_srst_n_out;} const pin_state_t *srst_n_in() const {return &_srst_n_in;} }; #endif #endif /* __FT2232JTAG_H__ */