779 lines
30 KiB
C
779 lines
30 KiB
C
/*
|
|
Turbo BDM Light ColdFire - interface DLL
|
|
Copyright (C) 2006 Daniel Malik
|
|
|
|
Changed to support the BDM project.
|
|
Chris Johns (cjohns@user.sourgeforge.net)
|
|
|
|
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 "log.h"
|
|
#include "version.h"
|
|
#include "tblcf.h"
|
|
#include "tblcf_usb.h"
|
|
#include "tblcf_hwdesc.h"
|
|
#include "commands.h"
|
|
|
|
/* define symbol "LOG" during compilation to produce a log file tblcf_dll.log */
|
|
|
|
static unsigned char usb_data[MAX_DATA_SIZE+2];
|
|
|
|
/* returns version of the DLL in BCD format */
|
|
unsigned char tblcf_version(void) {
|
|
return(TBLCF_DLL_VERSION);
|
|
}
|
|
|
|
/* initialises USB and returns number of devices found */
|
|
unsigned char tblcf_init(void) {
|
|
unsigned char i;
|
|
tblcf_usb_init();
|
|
tblcf_usb_find_devices(TBLCF_PID); /* look for devices on all USB busses */
|
|
i=tblcf_usb_cnt();
|
|
tblcf_print("TBDML_INIT: Usb initialised, found %d device(s)\r\n",i);
|
|
return(i); /* count the devices found and return the number */
|
|
}
|
|
|
|
/* opens a device with given number name */
|
|
/* returns device number on success and -1 on error */
|
|
int tblcf_open(const char *device) {
|
|
tblcf_print("TBLCF_OPEN: Trying to open device %s\r\n", device);
|
|
return(tblcf_usb_open(device));
|
|
}
|
|
|
|
/* closes currently open device */
|
|
void tblcf_close(int dev) {
|
|
tblcf_print("TBLCF_CLOSE: Trying to close the device\r\n");
|
|
tblcf_usb_close(dev);
|
|
}
|
|
|
|
/* gets version of the interface (HW and SW) in BCD format */
|
|
unsigned int tblcf_get_version(int dev) {
|
|
usb_data[0]=3; /* get 3 bytes */
|
|
usb_data[1]=CMD_GET_VER;
|
|
tblcf_usb_recv_ep0(dev, usb_data);
|
|
tblcf_print("TBLCF_GET_VERSION: Reported cable version (0x%02X) - %02X.%02X (HW.SW)\r\n",
|
|
usb_data[0],usb_data[2],usb_data[1]);
|
|
return((*((unsigned int *)(usb_data+1)))&0xffff);
|
|
}
|
|
|
|
/* returns status of the last command: 0 on sucess and non-zero on failure */
|
|
unsigned char tblcf_get_last_sts_value(int dev) {
|
|
usb_data[0]=1; /* get 1 byte */
|
|
usb_data[1]=CMD_GET_LAST_STATUS;
|
|
tblcf_usb_recv_ep0(dev, usb_data);
|
|
tblcf_print("TBLCF_GET_LAST_STATUS: Reported last command status 0x%02X\r\n",usb_data[0]);
|
|
return usb_data[0];
|
|
}
|
|
/* returns status of the last command: 0 on sucess and non-zero on failure */
|
|
unsigned char tblcf_get_last_sts(int dev) {
|
|
unsigned char status = tblcf_get_last_sts_value(dev);
|
|
if ((status==CMD_FAILED)||(status==CMD_UNKNOWN)) return(1); else return(0);
|
|
}
|
|
|
|
/* requests bootloader execution on next power-up */
|
|
/* returns 0 on success and non-zero on failure */
|
|
unsigned char tblcf_request_boot(int dev) {
|
|
usb_data[0]=1; /* return 1 byte */
|
|
usb_data[1]=CMD_SET_BOOT;
|
|
usb_data[2]='B';
|
|
usb_data[3]='O';
|
|
usb_data[4]='O';
|
|
usb_data[5]='T';
|
|
tblcf_usb_recv_ep0(dev, usb_data);
|
|
tblcf_print("TBLCF_REQUEST_BOOT: Requested bootloader on next power-up (0x%02X)\r\n",usb_data[0]);
|
|
return(!(usb_data[0]==CMD_SET_BOOT));
|
|
}
|
|
|
|
/* sets target MCU type */
|
|
/* returns 0 on success and non-zero on failure */
|
|
unsigned char tblcf_set_target_type(int dev, target_type_e target_type) {
|
|
usb_data[0]=1; /* get 1 byte */
|
|
usb_data[1]=CMD_SET_TARGET;
|
|
usb_data[2]=target_type;
|
|
tblcf_usb_recv_ep0(dev, usb_data);
|
|
tblcf_print("TBLCF_SET_TARGET_TYPE: Set target type 0x%02X (0x%02X)\r\n",usb_data[2],usb_data[0]);
|
|
return(!(usb_data[0]==CMD_SET_TARGET));
|
|
}
|
|
|
|
/* resets the target to normal or BDM mode */
|
|
/* returns 0 on success and non-zero on failure */
|
|
unsigned char tblcf_target_reset(int dev, target_mode_e target_mode) {
|
|
usb_data[0]=1; /* get 1 byte */
|
|
usb_data[1]=CMD_RESET;
|
|
usb_data[2]=target_mode;
|
|
tblcf_usb_recv_ep0(dev, usb_data);
|
|
tblcf_print("TBLCF_TARGET_RESET: Target reset into mode 0x%02X (0x%02X)\r\n",usb_data[2],usb_data[0]);
|
|
return(!(usb_data[0]==CMD_RESET));
|
|
}
|
|
|
|
/* fills user supplied structure with current state of the BDM communication channel */
|
|
/* returns 0 on success and non-zero on failure */
|
|
unsigned char tblcf_bdm_sts(int dev, bdmcf_status_t *bdmcf_status) {
|
|
usb_data[0]=3; /* get 3 bytes */
|
|
usb_data[1]=CMD_GET_STATUS;
|
|
tblcf_usb_recv_ep0(dev, usb_data);
|
|
if (usb_data[0]!=CMD_GET_STATUS) return(1);
|
|
bdmcf_status->reset_state = ((usb_data[1]*256+usb_data[2])&RSTO_STATE_MASK)?RSTO_INACTIVE:RSTO_ACTIVE;
|
|
bdmcf_status->reset_detection =
|
|
((usb_data[1]*256+usb_data[2])&RESET_DETECTED_MASK)?RESET_DETECTED:RESET_NOT_DETECTED;
|
|
tblcf_print("TBLCF_BDM_STATUS: Reported communication status 0x%04X (0x%02X)\r\n",
|
|
(usb_data[1]*256+usb_data[2]),usb_data[0]);
|
|
return(0);
|
|
}
|
|
|
|
/* brings the target into BDM mode */
|
|
/* returns 0 on success and non-zero on failure */
|
|
unsigned char tblcf_target_halt(int dev) {
|
|
usb_data[0]=1; /* get 1 byte */
|
|
usb_data[1]=CMD_HALT;
|
|
tblcf_usb_recv_ep0(dev, usb_data);
|
|
tblcf_print("TBLCF_TARGET_HALT: (0x%02X)\r\n",usb_data[0]);
|
|
return(!(usb_data[0]==CMD_HALT));
|
|
}
|
|
|
|
/* starts target execution from current PC address */
|
|
/* returns 0 on success and non-zero on failure */
|
|
unsigned char tblcf_target_go(int dev) {
|
|
usb_data[0]=1; /* get 1 byte */
|
|
usb_data[1]=CMD_GO;
|
|
tblcf_usb_recv_ep0(dev, usb_data);
|
|
tblcf_print("TBLCF_TARGET_GO: (0x%02X)\r\n",usb_data[0]);
|
|
return(!(usb_data[0]==CMD_GO));
|
|
}
|
|
|
|
/* steps over a single target instruction */
|
|
/* returns 0 on success and non-zero on failure */
|
|
unsigned char tblcf_target_step(int dev) {
|
|
usb_data[0]=1; /* get 1 byte */
|
|
usb_data[1]=CMD_STEP;
|
|
tblcf_usb_recv_ep0(dev, usb_data);
|
|
tblcf_print("TBLCF_TARGET_STEP: (0x%02X)\r\n",usb_data[0]);
|
|
return(!(usb_data[0]==CMD_STEP));
|
|
}
|
|
|
|
/* resynchronizes communication with the target (in case of noise, etc.) */
|
|
/* returns 0 on success and non-zero on failure */
|
|
unsigned char tblcf_resynchronize(int dev) {
|
|
usb_data[0]=1; /* get 1 byte */
|
|
usb_data[1]=CMD_RESYNCHRONIZE;
|
|
tblcf_usb_recv_ep0(dev, usb_data);
|
|
tblcf_print("TBLCF_RESYNCHRONIZE: (0x%02X)\r\n",usb_data[0]);
|
|
return(!(usb_data[0]==CMD_RESYNCHRONIZE));
|
|
}
|
|
|
|
/* asserts the TA signal for the specified time (in 10us ticks) */
|
|
/* returns 0 on success and non-zero on failure */
|
|
unsigned char tblcf_assert_ta(int dev, unsigned char duration_10us) {
|
|
usb_data[0]=1; /* get 1 byte */
|
|
usb_data[1]=CMD_ASSERT_TA;
|
|
usb_data[2]=duration_10us;
|
|
tblcf_usb_recv_ep0(dev, usb_data);
|
|
tblcf_print("TBLCF_ASSERT_TA: duration %d us (0x%02X)\r\n",(int)10*usb_data[2],usb_data[0]);
|
|
return(!(usb_data[0]==CMD_ASSERT_TA));
|
|
}
|
|
|
|
/* reads control register at the specified address and writes its contents into the supplied buffer */
|
|
/* returns 0 on success and non-zero on failure */
|
|
unsigned char tblcf_read_creg(int dev, unsigned int address, unsigned long int * result) {
|
|
usb_data[0]=5; /* get 5 bytes */
|
|
usb_data[1]=CMD_READ_CREG;
|
|
usb_data[2]=(address>>8)&0xff; /* address in big endian */
|
|
usb_data[3]=address&0xff;
|
|
tblcf_usb_recv_ep0(dev, usb_data);
|
|
*result = (((unsigned long int)usb_data[1])<<24)+(usb_data[2]<<16)+(usb_data[3]<<8)+usb_data[4]; /* result is in big endian */
|
|
tblcf_print("TBLCF_READ_CREG: Read control register from address 0x%04X, result: 0x%08lX (0x%02X)\r\n",address,*result,usb_data[0]);
|
|
return(!(usb_data[0]==CMD_READ_CREG));
|
|
}
|
|
|
|
/* writes control register at the specified address */
|
|
void tblcf_write_creg(int dev, unsigned int address, unsigned long int value) {
|
|
usb_data[0]=7; /* send 7 bytes */
|
|
usb_data[1]=CMD_WRITE_CREG;
|
|
usb_data[2]=(address>>8)&0xff; /* address in big endian */
|
|
usb_data[3]=address&0xff;
|
|
usb_data[4]=(value>>24)&0xff;
|
|
usb_data[5]=(value>>16)&0xff;
|
|
usb_data[6]=(value>>8)&0xff;
|
|
usb_data[7]=(value)&0xff;
|
|
tblcf_print("TBLCF_WRITE_CREG: Write control register at address 0x%04X with 0x%08lX\r\n",address,value);
|
|
tblcf_usb_send_ep0(dev, usb_data);
|
|
}
|
|
|
|
/* reads the specified debug register and writes its contents into the supplied buffer */
|
|
/* returns 0 on success and non-zero on failure */
|
|
unsigned char tblcf_read_dreg(int dev, unsigned char dreg_index, unsigned long int * result) {
|
|
usb_data[0]=5; /* get 5 bytes */
|
|
usb_data[1]=CMD_READ_DREG;
|
|
usb_data[2]=dreg_index;
|
|
tblcf_usb_recv_ep0(dev, usb_data);
|
|
*result = (((unsigned long int)usb_data[1])<<24)+(usb_data[2]<<16)+(usb_data[3]<<8)+usb_data[4]; /* result is in big endian */
|
|
tblcf_print("TBLCF_READ_DREG: Read debug register #0x%02X, result: 0x%08lX (0x%02X)\r\n",
|
|
dreg_index,*result,usb_data[0]);
|
|
return(!(usb_data[0]==CMD_READ_DREG));
|
|
}
|
|
|
|
/* writes specified debug register */
|
|
void tblcf_write_dreg(int dev, unsigned char dreg_index, unsigned long int value) {
|
|
usb_data[0]=6; /* send 6 bytes */
|
|
usb_data[1]=CMD_WRITE_DREG;
|
|
usb_data[2]=dreg_index&0xff;
|
|
usb_data[3]=(value>>24)&0xff;
|
|
usb_data[4]=(value>>16)&0xff;
|
|
usb_data[5]=(value>>8)&0xff;
|
|
usb_data[6]=(value)&0xff;
|
|
tblcf_print("TBLCF_WRITE_DREG: Write debug register #0x%02X with 0x%08lX\r\n",dreg_index,value);
|
|
tblcf_usb_send_ep0(dev, usb_data);
|
|
}
|
|
|
|
/* reads the specified register and writes its contents into the supplied buffer */
|
|
/* returns 0 on success and non-zero on failure */
|
|
unsigned char tblcf_read_reg(int dev, unsigned char reg_index, unsigned long int * result) {
|
|
usb_data[0]=5; /* get 5 bytes */
|
|
usb_data[1]=CMD_READ_REG;
|
|
usb_data[2]=reg_index;
|
|
tblcf_usb_recv_ep0(dev, usb_data);
|
|
*result = (((unsigned long int)usb_data[1])<<24)+(usb_data[2]<<16)+(usb_data[3]<<8)+usb_data[4]; /* result is in big endian */
|
|
tblcf_print("TBLCF_READ_REG: Read register #0x%02X, result: 0x%08lX (0x%02X)\r\n",
|
|
reg_index,*result,usb_data[0]);
|
|
return(!(usb_data[0]==CMD_READ_REG));
|
|
}
|
|
|
|
/* writes specified register */
|
|
void tblcf_write_reg(int dev, unsigned char reg_index, unsigned long int value) {
|
|
usb_data[0]=6; /* send 6 bytes */
|
|
usb_data[1]=CMD_WRITE_REG;
|
|
usb_data[2]=reg_index&0xff;
|
|
usb_data[3]=(value>>24)&0xff;
|
|
usb_data[4]=(value>>16)&0xff;
|
|
usb_data[5]=(value>>8)&0xff;
|
|
usb_data[6]=(value)&0xff;
|
|
tblcf_print("TBLCF_WRITE_REG: Write register #0x%02X with 0x%08lX\r\n",reg_index,value);
|
|
tblcf_usb_send_ep0(dev, usb_data);
|
|
}
|
|
|
|
/* reads byte from the specified address */
|
|
/* returns 0 on success and non-zero on failure */
|
|
unsigned char tblcf_read_mem8(int dev, unsigned long int address, unsigned char * result) {
|
|
usb_data[0]=2; /* get 2 bytes */
|
|
usb_data[1]=CMD_READ_MEM8;
|
|
usb_data[2]=(address>>24)&0xff;
|
|
usb_data[3]=(address>>16)&0xff;
|
|
usb_data[4]=(address>>8)&0xff;
|
|
usb_data[5]=(address)&0xff;
|
|
tblcf_usb_recv_ep0(dev, usb_data);
|
|
*result = usb_data[1];
|
|
tblcf_print("TBLCF_READ_MEM8: Read byte from address 0x%08lX, result: 0x%02X (0x%02X)\r\n",
|
|
address,*result,usb_data[0]);
|
|
return(!(usb_data[0]==CMD_READ_MEM8));
|
|
}
|
|
|
|
/* reads word from the specified address */
|
|
/* returns 0 on success and non-zero on failure */
|
|
unsigned char tblcf_read_mem16(int dev, unsigned long int address, unsigned int * result) {
|
|
usb_data[0]=3; /* get 3 bytes */
|
|
usb_data[1]=CMD_READ_MEM16;
|
|
usb_data[2]=(address>>24)&0xff;
|
|
usb_data[3]=(address>>16)&0xff;
|
|
usb_data[4]=(address>>8)&0xff;
|
|
usb_data[5]=(address)&0xff;
|
|
tblcf_usb_recv_ep0(dev, usb_data);
|
|
*result = ((unsigned int)usb_data[1]<<8)+usb_data[2];
|
|
tblcf_print("TBLCF_READ_MEM16: Read word from address 0x%08lX, result: 0x%04X (0x%02X)\r\n",
|
|
address,*result,usb_data[0]);
|
|
return(!(usb_data[0]==CMD_READ_MEM16));
|
|
}
|
|
|
|
/* reads long word from the specified address */
|
|
/* returns 0 on success and non-zero on failure */
|
|
unsigned char tblcf_read_mem32(int dev, unsigned long int address, unsigned long int * result) {
|
|
usb_data[0]=5; /* get 5 bytes */
|
|
usb_data[1]=CMD_READ_MEM32;
|
|
usb_data[2]=(address>>24)&0xff;
|
|
usb_data[3]=(address>>16)&0xff;
|
|
usb_data[4]=(address>>8)&0xff;
|
|
usb_data[5]=(address)&0xff;
|
|
tblcf_usb_recv_ep0(dev, usb_data);
|
|
*result = (((unsigned long int)usb_data[1])<<24)+(usb_data[2]<<16)+(usb_data[3]<<8)+usb_data[4];
|
|
tblcf_print("TBLCF_READ_MEM32: Read long word from address 0x%08lX, result: 0x%08lX (0x%02X)\r\n",address,*result,usb_data[0]);
|
|
return(!(usb_data[0]==CMD_READ_MEM32));
|
|
}
|
|
|
|
/* writes byte at the specified address */
|
|
void tblcf_write_mem8(int dev, unsigned long int address, unsigned char value) {
|
|
usb_data[0]=6; /* send 6 bytes */
|
|
usb_data[1]=CMD_WRITE_MEM8;
|
|
usb_data[2]=(address>>24)&0xff;
|
|
usb_data[3]=(address>>16)&0xff;
|
|
usb_data[4]=(address>>8)&0xff;
|
|
usb_data[5]=(address)&0xff;
|
|
usb_data[6]=(value)&0xff;
|
|
tblcf_print("TBLCF_WRITE_MEM8: Write byte 0x%02X to address 0x%08lX\r\n",value,address);
|
|
tblcf_usb_send_ep0(dev, usb_data);
|
|
}
|
|
|
|
/* writes word at the specified address */
|
|
void tblcf_write_mem16(int dev, unsigned long int address, unsigned int value) {
|
|
usb_data[0]=7; /* send 7 bytes */
|
|
usb_data[1]=CMD_WRITE_MEM16;
|
|
usb_data[2]=(address>>24)&0xff;
|
|
usb_data[3]=(address>>16)&0xff;
|
|
usb_data[4]=(address>>8)&0xff;
|
|
usb_data[5]=(address)&0xff;
|
|
usb_data[6]=(value>>8)&0xff;
|
|
usb_data[7]=(value)&0xff;
|
|
tblcf_print("TBLCF_WRITE_MEM16: Write word 0x%04X to address 0x%08lX\r\n",value,address);
|
|
tblcf_usb_send_ep0(dev, usb_data);
|
|
}
|
|
|
|
/* writes long word at the specified address */
|
|
void tblcf_write_mem32(int dev, unsigned long int address, unsigned long int value) {
|
|
usb_data[0]=9; /* send 9 bytes */
|
|
usb_data[1]=CMD_WRITE_MEM32;
|
|
usb_data[2]=(address>>24)&0xff;
|
|
usb_data[3]=(address>>16)&0xff;
|
|
usb_data[4]=(address>>8)&0xff;
|
|
usb_data[5]=(address)&0xff;
|
|
usb_data[6]=(value>>24)&0xff;
|
|
usb_data[7]=(value>>16)&0xff;
|
|
usb_data[8]=(value>>8)&0xff;
|
|
usb_data[9]=(value)&0xff;
|
|
tblcf_print("TBLCF_WRITE_MEM32: Write long word 0x%08lX to address 0x%08lX\r\n",value,address);
|
|
tblcf_usb_send_ep0(dev, usb_data);
|
|
}
|
|
|
|
/* reads the requested number of bytes from target memory from the supplied address and stores results into the user supplied buffer */
|
|
/* uses byte accesses only */
|
|
/* returns 0 on success and non-zero on failure */
|
|
unsigned char tblcf_read_block8(int dev, unsigned long int address,
|
|
unsigned long int bytecount, unsigned char *buffer) {
|
|
int i;
|
|
tblcf_print("TBLCF_READ_BLOCK8: Read 0x%08lX byte(s) from address 0x%08lX:\r\n",bytecount,address);
|
|
while (bytecount>=MAX_DATA_SIZE) {
|
|
usb_data[0]=MAX_DATA_SIZE+1; /* receive block of maximum size */
|
|
usb_data[1]=CMD_READ_MEMBLOCK8;
|
|
usb_data[2]=(address>>24)&0xff;
|
|
usb_data[3]=(address>>16)&0xff;
|
|
usb_data[4]=(address>>8)&0xff;
|
|
usb_data[5]=(address)&0xff;
|
|
tblcf_usb_recv_ep0(dev, usb_data);
|
|
tblcf_print("TBLCF_READ_BLOCK8: Block read, size 0x%02X (0x%02X):\r\n",MAX_DATA_SIZE,usb_data[0]);
|
|
tblcf_print_dump(usb_data+1, MAX_DATA_SIZE);
|
|
if (usb_data[0]!=CMD_READ_MEMBLOCK8) return(1);
|
|
for (i=0;i<MAX_DATA_SIZE;i++) *(buffer++)=usb_data[1+i]; /* copy results */
|
|
bytecount-=MAX_DATA_SIZE;
|
|
address+=MAX_DATA_SIZE;
|
|
}
|
|
if (bytecount) {
|
|
usb_data[0]=bytecount+1;
|
|
usb_data[1]=CMD_READ_MEMBLOCK8;
|
|
usb_data[2]=(address>>24)&0xff;
|
|
usb_data[3]=(address>>16)&0xff;
|
|
usb_data[4]=(address>>8)&0xff;
|
|
usb_data[5]=(address)&0xff;
|
|
tblcf_usb_recv_ep0(dev, usb_data);
|
|
tblcf_print("TBLCF_READ_BLOCK8: Block read, size 0x%02X (0x%02X):\r\n",bytecount,usb_data[0]);
|
|
tblcf_print_dump(usb_data+1, bytecount);
|
|
if (usb_data[0]!=CMD_READ_MEMBLOCK8) return(1);
|
|
for (i=0;i<bytecount;i++) *(buffer++)=usb_data[1+i]; /* copy results */
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/* reads the requested number of bytes from target memory from the supplied address and stores results into the user supplied buffer */
|
|
/* uses word accesses */
|
|
/* if the address is odd a byte read is performed to make it even before performing the word reads */
|
|
/* returns 0 on success and non-zero on failure */
|
|
unsigned char tblcf_read_block16(int dev, unsigned long int address,
|
|
unsigned long int bytecount, unsigned char *buffer) {
|
|
int i;
|
|
tblcf_print("TBLCF_READ_BLOCK16: Read 0x%08lX byte(s) from address 0x%08lX:\r\n",bytecount,address);
|
|
if (address&0x01) {
|
|
tblcf_print("TBLCF_READ_BLOCK16: Address is odd, performing 1 byte read\r\n");
|
|
if (tblcf_read_mem8(dev, address, buffer)) return(1);
|
|
bytecount--;
|
|
address++;
|
|
buffer++;
|
|
}
|
|
while (bytecount>=(MAX_DATA_SIZE&0xfffe)) {
|
|
usb_data[0]=(MAX_DATA_SIZE&0xfffe)+1; /* receive block of maximum size */
|
|
usb_data[1]=CMD_READ_MEMBLOCK16;
|
|
usb_data[2]=(address>>24)&0xff;
|
|
usb_data[3]=(address>>16)&0xff;
|
|
usb_data[4]=(address>>8)&0xff;
|
|
usb_data[5]=(address)&0xff;
|
|
tblcf_usb_recv_ep0(dev, usb_data);
|
|
tblcf_print("TBLCF_READ_BLOCK16: Block read, size 0x%02X (0x%02X):\r\n",MAX_DATA_SIZE&0xfffe,usb_data[0]);
|
|
tblcf_print_dump(usb_data+1, MAX_DATA_SIZE&0xfffe);
|
|
for (i=0;i<(MAX_DATA_SIZE&0xfffe);i++) *(buffer++)=usb_data[1+i]; /* copy results */
|
|
bytecount-=(MAX_DATA_SIZE&0xfffe);
|
|
address+=(MAX_DATA_SIZE&0xfffe);
|
|
if (usb_data[0]!=CMD_READ_MEMBLOCK16) return(1);
|
|
|
|
}
|
|
if (bytecount) {
|
|
usb_data[0]=bytecount+1;
|
|
if ((bytecount&0x01)==1) usb_data[0]++; /* increase the number of bytes to return to a whole number of words */
|
|
usb_data[1]=CMD_READ_MEMBLOCK16;
|
|
usb_data[2]=(address>>24)&0xff;
|
|
usb_data[3]=(address>>16)&0xff;
|
|
usb_data[4]=(address>>8)&0xff;
|
|
usb_data[5]=(address)&0xff;
|
|
tblcf_usb_recv_ep0(dev, usb_data);
|
|
tblcf_print("TBLCF_READ_BLOCK16: Block read, size 0x%02X (0x%02X):\r\n",bytecount,usb_data[0]);
|
|
tblcf_print_dump(usb_data+1, bytecount);
|
|
if (usb_data[0]!=CMD_READ_MEMBLOCK16) return(1);
|
|
for (i=0;i<bytecount;i++) *(buffer++)=usb_data[1+i]; /* copy results */
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/* reads the requested number of bytes from target memory from the supplied address and stores results into the user supplied buffer */
|
|
/* uses long word accesses */
|
|
/* if the address is not aligned byte/word reads are performed to align it */
|
|
/* returns 0 on success and non-zero on failure */
|
|
unsigned char tblcf_read_block32(int dev, unsigned long int address,
|
|
unsigned long int bytecount, unsigned char *buffer) {
|
|
int i;
|
|
tblcf_print("TBLCF_READ_BLOCK32: Read 0x%08lX byte(s) from address 0x%08lX:\r\n",bytecount,address);
|
|
if (address&0x01) {
|
|
tblcf_print("TBLCF_READ_BLOCK32: Address is odd, performing 1 byte read\r\n");
|
|
if (tblcf_read_mem8(dev, address, buffer)) return(1);
|
|
bytecount--;
|
|
address++;
|
|
buffer++;
|
|
}
|
|
if (address&0x02) {
|
|
tblcf_print("TBLCF_READ_BLOCK32: Address is not aligned, performing 1 word read\r\n");
|
|
if (tblcf_read_mem16(dev, address, (unsigned int*) buffer)) return(1);
|
|
bytecount-=2;
|
|
address+=2;
|
|
buffer+=2;
|
|
}
|
|
while (bytecount>=(MAX_DATA_SIZE&0xfffc)) {
|
|
usb_data[0]=(MAX_DATA_SIZE&0xfffc)+1; /* receive block of maximum size */
|
|
usb_data[1]=CMD_READ_MEMBLOCK32;
|
|
usb_data[2]=(address>>24)&0xff;
|
|
usb_data[3]=(address>>16)&0xff;
|
|
usb_data[4]=(address>>8)&0xff;
|
|
usb_data[5]=(address)&0xff;
|
|
tblcf_usb_recv_ep0(dev, usb_data);
|
|
tblcf_print("TBLCF_READ_BLOCK32: Block read, size 0x%02X (0x%02X):\r\n",MAX_DATA_SIZE&0xfffc,usb_data[0]);
|
|
tblcf_print_dump(usb_data+1, MAX_DATA_SIZE&0xfffc);
|
|
for (i=0;i<(MAX_DATA_SIZE&0xfffc);i++) *(buffer++)=usb_data[1+i]; /* copy results */
|
|
bytecount-=(MAX_DATA_SIZE&0xfffc);
|
|
address+=(MAX_DATA_SIZE&0xfffc);
|
|
if (usb_data[0]!=CMD_READ_MEMBLOCK32) return(1);
|
|
|
|
}
|
|
if (bytecount) {
|
|
usb_data[0]=bytecount+1;
|
|
usb_data[0]+=((4-(bytecount&0x03))&0x03); /* increase the number of bytes to make it a multiple of 4 */
|
|
usb_data[1]=CMD_READ_MEMBLOCK32;
|
|
usb_data[2]=(address>>24)&0xff;
|
|
usb_data[3]=(address>>16)&0xff;
|
|
usb_data[4]=(address>>8)&0xff;
|
|
usb_data[5]=(address)&0xff;
|
|
tblcf_usb_recv_ep0(dev, usb_data);
|
|
tblcf_print("TBLCF_READ_BLOCK32: Block read, size 0x%02X (0x%02X):\r\n",bytecount,usb_data[0]);
|
|
tblcf_print_dump(usb_data+1, bytecount);
|
|
if (usb_data[0]!=CMD_READ_MEMBLOCK32) return(1);
|
|
for (i=0;i<bytecount;i++) *(buffer++)=usb_data[1+i]; /* copy results */
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/* writes the requested number of bytes to target memory from the supplied address */
|
|
/* uses byte accesses only */
|
|
/* returns 0 on success and non-zero on failure (must be compiled with WRITE_BLOCK_CHECK, otherwise always returns 0) */
|
|
unsigned char tblcf_write_block8(int dev, unsigned long int address,
|
|
unsigned long int bytecount, unsigned char *buffer) {
|
|
int i;
|
|
tblcf_print("TBLCF_WRITE_BLOCK8: Write 0x%08lX byte(s) to address 0x%08lX:\r\n",bytecount,address);
|
|
while (bytecount>=MAX_DATA_SIZE) {
|
|
usb_data[0]=MAX_DATA_SIZE+5; /* write block of maximum size */
|
|
usb_data[1]=CMD_WRITE_MEMBLOCK8;
|
|
usb_data[2]=(address>>24)&0xff;
|
|
usb_data[3]=(address>>16)&0xff;
|
|
usb_data[4]=(address>>8)&0xff;
|
|
usb_data[5]=(address)&0xff;
|
|
for (i=0;i<MAX_DATA_SIZE;i++) usb_data[6+i]=*(buffer++); /* copy data */
|
|
tblcf_print("TBLCF_WRITE_BLOCK8: Block write, size 0x%02X:\r\n",MAX_DATA_SIZE);
|
|
tblcf_print_dump(usb_data+6, MAX_DATA_SIZE);
|
|
tblcf_usb_send_ep0(dev, usb_data);
|
|
#ifdef WRITE_BLOCK_CHECK
|
|
if (tblcf_get_last_sts(dev)) return(1);
|
|
#endif
|
|
bytecount-=MAX_DATA_SIZE;
|
|
address+=MAX_DATA_SIZE;
|
|
}
|
|
if (bytecount) {
|
|
usb_data[0]=bytecount+5;
|
|
usb_data[1]=CMD_WRITE_MEMBLOCK8;
|
|
usb_data[2]=(address>>24)&0xff;
|
|
usb_data[3]=(address>>16)&0xff;
|
|
usb_data[4]=(address>>8)&0xff;
|
|
usb_data[5]=(address)&0xff;
|
|
for (i=0;i<bytecount;i++) usb_data[6+i]=*(buffer++); /* copy data */
|
|
tblcf_print("TBLCF_WRITE_BLOCK8: Block write, size 0x%02X:\r\n",bytecount);
|
|
tblcf_print_dump(usb_data+6, bytecount);
|
|
tblcf_usb_send_ep0(dev, usb_data);
|
|
#ifdef WRITE_BLOCK_CHECK
|
|
if (tblcf_get_last_sts(dev)) return(1);
|
|
#endif
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/* writes the requested number of bytes to target memory at the supplied address */
|
|
/* uses word accesses */
|
|
/* if the address is odd a byte write is performed to make it even before performing the word writes */
|
|
/* if there is an odd byte at the end of the block it is written using a byte write */
|
|
/* returns 0 on success and non-zero on failure (must be compiled with WRITE_BLOCK_CHECK, otherwise always returns 0) */
|
|
unsigned char tblcf_write_block16(int dev, unsigned long int address,
|
|
unsigned long int bytecount, unsigned char *buffer) {
|
|
int i;
|
|
tblcf_print("TBLCF_WRITE_BLOCK16: Write 0x%08lX byte(s) from address 0x%08lX:\r\n",bytecount,address);
|
|
if (address&0x01) {
|
|
tblcf_print("TBLCF_WRITE_BLOCK16: Address is odd, performing 1 byte write\r\n");
|
|
tblcf_write_mem8(dev, address, *buffer);
|
|
#ifdef WRITE_BLOCK_CHECK
|
|
if (tblcf_get_last_sts(dev)) return(1);
|
|
#endif
|
|
bytecount--;
|
|
address++;
|
|
buffer++;
|
|
}
|
|
while (bytecount>=(MAX_DATA_SIZE&0xfffe)) {
|
|
usb_data[0]=(MAX_DATA_SIZE&0xfffe)+5; /* send block of maximum size */
|
|
usb_data[1]=CMD_WRITE_MEMBLOCK16;
|
|
usb_data[2]=(address>>24)&0xff;
|
|
usb_data[3]=(address>>16)&0xff;
|
|
usb_data[4]=(address>>8)&0xff;
|
|
usb_data[5]=(address)&0xff;
|
|
for (i=0;i<(MAX_DATA_SIZE&0xfffe);i++) usb_data[6+i]=*(buffer++); /* copy data */
|
|
tblcf_print("TBLCF_WRITE_BLOCK16: Block write, size 0x%02X:\r\n",MAX_DATA_SIZE&0xfffe);
|
|
tblcf_print_dump(usb_data+6, MAX_DATA_SIZE&0xfffe);
|
|
tblcf_usb_send_ep0(dev, usb_data);
|
|
bytecount-=(MAX_DATA_SIZE&0xfffe);
|
|
address+=(MAX_DATA_SIZE&0xfffe);
|
|
#ifdef WRITE_BLOCK_CHECK
|
|
if (tblcf_get_last_sts(dev)) return(1);
|
|
#endif
|
|
}
|
|
if (bytecount>=2) {
|
|
usb_data[0]=bytecount+5;
|
|
if ((bytecount&0x01)==1) usb_data[0]--; /* decrease the number of bytes to write a whole number of words */
|
|
usb_data[1]=CMD_WRITE_MEMBLOCK16;
|
|
usb_data[2]=(address>>24)&0xff;
|
|
usb_data[3]=(address>>16)&0xff;
|
|
usb_data[4]=(address>>8)&0xff;
|
|
usb_data[5]=(address)&0xff;
|
|
for (i=0;i<(bytecount&0xfffe);i++) usb_data[6+i]=*(buffer++); /* copy data */
|
|
tblcf_print("TBLCF_WRITE_BLOCK16: Block write, size 0x%02X:\r\n",(bytecount&0xfffe));
|
|
tblcf_print_dump(usb_data+6, (bytecount&0xfffe));
|
|
tblcf_usb_send_ep0(dev, usb_data);
|
|
#ifdef WRITE_BLOCK_CHECK
|
|
if (tblcf_get_last_sts(dev)) return(1);
|
|
#endif
|
|
address+=(bytecount&0xfffe);
|
|
bytecount&=0x01;
|
|
}
|
|
if (bytecount) { /* leftover byte */
|
|
tblcf_print("TBLCF_WRITE_BLOCK16: Misaligned byte at the end of the block, performing 1 byte write\r\n");
|
|
tblcf_write_mem8(dev, address, *buffer);
|
|
#ifdef WRITE_BLOCK_CHECK
|
|
if (tblcf_get_last_sts(dev)) return(1);
|
|
#endif
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/* writes the requested number of bytes to target memory at the supplied address */
|
|
/* uses long word accesses */
|
|
/* if the address is not aligned byte/word writes are performed */
|
|
/* if there are odd bytes at the end of the block they is written using byte/word writes */
|
|
/* returns 0 on success and non-zero on failure (must be compiled with WRITE_BLOCK_CHECK, otherwise always returns 0) */
|
|
unsigned char tblcf_write_block32(int dev, unsigned long int address,
|
|
unsigned long int bytecount, unsigned char *buffer) {
|
|
int i;
|
|
tblcf_print("TBLCF_WRITE_BLOCK32: Write 0x%08lX byte(s) at address 0x%08lX:\r\n",bytecount,address);
|
|
if (address&0x01) {
|
|
tblcf_print("TBLCF_WRITE_BLOCK32: Address is odd, performing 1 byte write\r\n");
|
|
tblcf_write_mem8(dev, address, *buffer);
|
|
#ifdef WRITE_BLOCK_CHECK
|
|
if (tblcf_get_last_sts(dev)) return(1);
|
|
#endif
|
|
bytecount--;
|
|
address++;
|
|
buffer++;
|
|
}
|
|
if (address&0x02) {
|
|
tblcf_print("TBLCF_WRITE_BLOCK32: Address is not aligned, performing 1 word write\r\n");
|
|
tblcf_write_mem16(dev, address, (*(buffer+0))*256+*(buffer+1));
|
|
#ifdef WRITE_BLOCK_CHECK
|
|
if (tblcf_get_last_sts(dev)) return(1);
|
|
#endif
|
|
bytecount-=2;
|
|
address+=2;
|
|
buffer+=2;
|
|
}
|
|
while (bytecount>=(MAX_DATA_SIZE&0xfffc)) {
|
|
usb_data[0]=(MAX_DATA_SIZE&0xfffc)+5; /* send block of maximum size */
|
|
usb_data[1]=CMD_WRITE_MEMBLOCK32;
|
|
usb_data[2]=(address>>24)&0xff;
|
|
usb_data[3]=(address>>16)&0xff;
|
|
usb_data[4]=(address>>8)&0xff;
|
|
usb_data[5]=(address)&0xff;
|
|
for (i=0;i<(MAX_DATA_SIZE&0xfffc);i++) usb_data[6+i]=*(buffer++); /* copy data */
|
|
tblcf_print("TBLCF_WRITE_BLOCK32: Block write, size 0x%02X:\r\n",MAX_DATA_SIZE&0xfffc);
|
|
tblcf_print_dump(usb_data+6, MAX_DATA_SIZE&0xfffc);
|
|
tblcf_usb_send_ep0(dev, usb_data);
|
|
bytecount-=(MAX_DATA_SIZE&0xfffc);
|
|
address+=(MAX_DATA_SIZE&0xfffc);
|
|
#ifdef WRITE_BLOCK_CHECK
|
|
if (tblcf_get_last_sts(dev)) return(1);
|
|
#endif
|
|
}
|
|
if (bytecount>=4) {
|
|
usb_data[0]=bytecount+5;
|
|
usb_data[0]-=(bytecount&0x03); /* decrease the number of bytes to write a whole number of long words */
|
|
usb_data[1]=CMD_WRITE_MEMBLOCK32;
|
|
usb_data[2]=(address>>24)&0xff;
|
|
usb_data[3]=(address>>16)&0xff;
|
|
usb_data[4]=(address>>8)&0xff;
|
|
usb_data[5]=(address)&0xff;
|
|
for (i=0;i<(bytecount&0xfffc);i++) usb_data[6+i]=*(buffer++); /* copy data */
|
|
tblcf_print("TBLCF_WRITE_BLOCK32: Block write, size 0x%02X:\r\n",(bytecount&0xfffc));
|
|
tblcf_print_dump(usb_data+6, (bytecount&0xfffc));
|
|
tblcf_usb_send_ep0(dev, usb_data);
|
|
#ifdef WRITE_BLOCK_CHECK
|
|
if (tblcf_get_last_sts(dev)) return(1);
|
|
#endif
|
|
address+=(bytecount&0xfffc);
|
|
bytecount&=0x03;
|
|
}
|
|
if (bytecount>=2) { /* leftover word */
|
|
tblcf_print("TBLCF_WRITE_BLOCK32: Misaligned word at the end of the block, performing 1 word write\r\n");
|
|
tblcf_write_mem16(dev, address, (*(buffer+0))*256+*(buffer+1));
|
|
#ifdef WRITE_BLOCK_CHECK
|
|
if (tblcf_get_last_sts(dev)) return(1);
|
|
#endif
|
|
address+=2;
|
|
bytecount-=2;
|
|
buffer+=2;
|
|
}
|
|
if (bytecount) { /* leftover byte */
|
|
tblcf_print("TBLCF_WRITE_BLOCK32: Misaligned byte at the end of the block, performing 1 byte write\r\n");
|
|
tblcf_write_mem8(dev, address, *(buffer));
|
|
#ifdef WRITE_BLOCK_CHECK
|
|
if (tblcf_get_last_sts(dev)) return(1);
|
|
#endif
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/* JTAG - go from RUN-TEST/IDLE to SHIFT-DR or SHIFT-IR state */
|
|
/* returns 0 on success and non-zero on failure */
|
|
unsigned char tblcf_jtag_sel_shift(int dev, unsigned char mode) {
|
|
usb_data[0]=1; /* get 1 byte */
|
|
usb_data[1]=CMD_JTAG_GOTOSHIFT;
|
|
usb_data[2]=mode;
|
|
tblcf_usb_recv_ep0(dev, usb_data);
|
|
tblcf_print("TBLCF_JTAG_SEL_SHIFT: SHIFT-%cR\r\n",mode?'I':'D');
|
|
return(!(usb_data[0]==CMD_JTAG_GOTOSHIFT));
|
|
}
|
|
|
|
/* JTAG - go from RUN-TEST/IDLE to TEST-LOGIC-RESET state */
|
|
/* returns 0 on success and non-zero on failure */
|
|
unsigned char tblcf_jtag_sel_reset(int dev) {
|
|
usb_data[0]=1; /* get 1 byte */
|
|
usb_data[1]=CMD_JTAG_GOTORESET;
|
|
tblcf_usb_recv_ep0(dev, usb_data);
|
|
tblcf_print("TBLCF_JTAG_SEL_RESET\r\n");
|
|
return(!(usb_data[0]==CMD_JTAG_GOTORESET));
|
|
}
|
|
|
|
/* JTAG - write data */
|
|
/* parameter exit: ==0 : stay in SHIFT-xx, !=0 : go to RUN-TEST/IDLE when done */
|
|
/* data: shifted in LSB (last byte) first, unused bits (if any) are in the MSB (first) byte */
|
|
void tblcf_jtag_write(int dev, unsigned char bit_count, unsigned char exit, unsigned char *buffer) {
|
|
int i;
|
|
usb_data[0]=(bit_count>>3)+((bit_count&0x07)!=0)+3; /* send all data bits & 3 more bytes */
|
|
usb_data[1]=CMD_JTAG_WRITE;
|
|
usb_data[2]=exit;
|
|
usb_data[3]=bit_count;
|
|
for (i=0;i<((bit_count>>3)+1);i++) usb_data[4+i]=*(buffer+i); /* copy data */
|
|
tblcf_usb_send_ep0(dev, usb_data);
|
|
tblcf_print("TBLCF_JTAG_WRITE: %d bits (%sexit to RUN-TEST/IDLE)\r\n",bit_count,exit?"":"NO ");
|
|
tblcf_print_dump(usb_data+4,(bit_count>>3)+((bit_count&0x07)!=0));
|
|
}
|
|
|
|
/* JTAG - read data */
|
|
/* parameter exit: ==0 : stay in SHIFT-xx, !=0 : go to RUN-TEST/IDLE when done */
|
|
/* data: shifted in LSB (last byte) first, unused bits (if any) are in the MSB (first) byte */
|
|
/* returns 0 on success and non-zero on failure */
|
|
unsigned char tblcf_jtag_read(int dev, unsigned char bit_count, unsigned char exit, unsigned char *buffer) {
|
|
int i;
|
|
usb_data[0]=(bit_count>>3)+((bit_count&0x07)!=0)+1; /* get all data bits & the status byte */
|
|
usb_data[1]=CMD_JTAG_READ;
|
|
usb_data[2]=exit;
|
|
usb_data[3]=bit_count;
|
|
tblcf_usb_recv_ep0(dev, usb_data);
|
|
for (i=0;i<((bit_count>>3)+((bit_count&0x07)!=0));i++) *(buffer+i)=usb_data[1+i]; /* copy data */
|
|
tblcf_print("TBLCF_JTAG_READ: %d bits (%sexit to RUN-TEST/IDLE)\r\n",bit_count,exit?"":"NO ");
|
|
tblcf_print_dump(usb_data+1,(bit_count>>3)+((bit_count&0x07)!=0));
|
|
return(!(usb_data[0]==CMD_JTAG_READ));
|
|
}
|
|
|
|
#if 0
|
|
BOOL LibMain(HINSTANCE hDLLInst, DWORD fdwReason, LPVOID lpvReserved) {
|
|
char path[MAX_PATH];
|
|
char *charp;
|
|
time_t time_now;
|
|
switch (fdwReason) {
|
|
case DLL_PROCESS_ATTACH:
|
|
tblcf_usb_init(); /* initialise USB */
|
|
#ifdef LOG
|
|
GetModuleFileName(NULL,path,sizeof(path));
|
|
charp=strchr(path,'\\');
|
|
if (charp!=NULL) {
|
|
while (strchr(charp+1,'\\')) charp=strchr(charp+1,'\\'); /* find the last backslash */
|
|
strcpy(charp+1,"tblcf_dll.log");
|
|
log_file=fopen(path,"wb");
|
|
}
|
|
tblcf_print("Log file path: %s\r\n",path);
|
|
tblcf_print("Turbo BDM Light DLL v%1d.%1d. Compiled on %s, %s.\r\n",
|
|
TBLCF_DLL_VERSION/16,TBLCF_DLL_VERSION&0x0f,__DATE__,__TIME__);
|
|
time(&time_now);
|
|
tblcf_print("Log file created on: %s\r", ctime(&time_now));
|
|
#endif
|
|
break;
|
|
case DLL_PROCESS_DETACH:
|
|
#ifdef LOG
|
|
time(&time_now);
|
|
tblcf_print("End of log file: %s\r", ctime(&time_now));
|
|
fclose(log_file);
|
|
#endif
|
|
break;
|
|
case DLL_THREAD_ATTACH:
|
|
break;
|
|
case DLL_THREAD_DETACH:
|
|
break;
|
|
}
|
|
return TRUE;
|
|
}
|
|
#endif
|