diff --git a/Makefile b/Makefile index db9178f4..15ce20aa 100644 --- a/Makefile +++ b/Makefile @@ -13,6 +13,10 @@ ifeq ($(PROBE_HOST), pc-stlinkv2) PC_HOSTED = true NO_LIBOPENCM3 = true endif +ifeq ($(PROBE_HOST), pc-hosted) + PC_HOSTED = true + NO_LIBOPENCM3 = true +endif all: ifndef NO_LIBOPENCM3 diff --git a/src/Makefile b/src/Makefile index 7a76aca3..502d30d2 100644 --- a/src/Makefile +++ b/src/Makefile @@ -46,7 +46,7 @@ SRC = \ nxpke04.c \ platform.c \ sam3x.c \ - sam4l.c \ + sam4l.c \ samd.c \ stm32f1.c \ stm32f4.c \ @@ -71,6 +71,9 @@ endif ifndef OWN_HL SRC += jtag_scan.c jtagtap.c swdptap.c +SRC += remote.c +else +CFLAGS += -DOWN_HL endif OBJ = $(patsubst %.S,%.o,$(patsubst %.c,%.o,$(SRC))) diff --git a/src/gdb_packet.c b/src/gdb_packet.c index 0396e0d3..f0f1f1d2 100644 --- a/src/gdb_packet.c +++ b/src/gdb_packet.c @@ -26,6 +26,7 @@ #include "gdb_if.h" #include "gdb_packet.h" #include "hex_utils.h" +#include "remote.h" #include @@ -37,9 +38,52 @@ int gdb_getpacket(char *packet, int size) int i; while(1) { - /* Wait for packet start */ - while((packet[0] = gdb_if_getchar()) != '$') - if(packet[0] == 0x04) return 1; + /* Wait for packet start */ + do { + /* Spin waiting for a start of packet character - either a gdb + * start ('$') or a BMP remote packet start ('!'). + */ + do { + packet[0] = gdb_if_getchar(); + if (packet[0]==0x04) return 1; + } while ((packet[0] != '$') && (packet[0] != REMOTE_SOM)); +#ifndef OWN_HL + if (packet[0]==REMOTE_SOM) { + /* This is probably a remote control packet + * - get and handle it */ + i=0; + bool gettingRemotePacket=true; + while (gettingRemotePacket) { + c=gdb_if_getchar(); + switch (c) { + case REMOTE_SOM: /* Oh dear, packet restarts */ + i=0; + break; + + case REMOTE_EOM: /* Complete packet for processing */ + packet[i]=0; + remotePacketProcess(i,packet); + gettingRemotePacket=false; + break; + + case '$': /* A 'real' gdb packet, best stop squatting now */ + packet[0]='$'; + gettingRemotePacket=false; + break; + + default: + if (i + * Modified by Dave Marples + * + * 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 3 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, see . + */ + +/* Low level JTAG implementation using FT2232 with libftdi. + * + * Issues: + * Should share interface with swdptap.c or at least clean up... + */ + +#include +#include +#include + +#include + +#include "general.h" +#include "remote.h" +#include "jtagtap.h" + +/* See remote.c/.h for protocol information */ + +int jtagtap_init(void) +{ + uint8_t construct[PLATFORM_MAX_MSG_SIZE]; + int s; + + s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,"%s",REMOTE_JTAG_INIT_STR); + platform_buffer_write(construct,s); + + s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE); + if ((!s) || (construct[0]==REMOTE_RESP_ERR)) + { + fprintf(stderr,"jtagtap_init failed, error %s\n",s?(char *)&(construct[1]):"unknown"); + exit(-1); + } + + return 0; +} + +void jtagtap_reset(void) +{ + uint8_t construct[PLATFORM_MAX_MSG_SIZE]; + int s; + + s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,"%s",REMOTE_JTAG_RESET_STR); + platform_buffer_write(construct,s); + + s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE); + if ((!s) || (construct[0]==REMOTE_RESP_ERR)) + { + fprintf(stderr,"jtagtap_reset failed, error %s\n",s?(char *)&(construct[1]):"unknown"); + exit(-1); + } +} + +void jtagtap_tms_seq(uint32_t MS, int ticks) + +{ + uint8_t construct[PLATFORM_MAX_MSG_SIZE]; + int s; + + s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,REMOTE_JTAG_TMS_STR,ticks,MS); + platform_buffer_write(construct,s); + + s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE); + if ((!s) || (construct[0]==REMOTE_RESP_ERR)) + { + fprintf(stderr,"jtagtap_tms_seq failed, error %s\n",s?(char *)&(construct[1]):"unknown"); + exit(-1); + } +} + +void jtagtap_tdi_tdo_seq(uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks) +{ + uint8_t construct[PLATFORM_MAX_MSG_SIZE]; + int s; + + uint64_t DIl=*(uint64_t *)DI; + uint64_t *DOl=(uint64_t *)DO; + + if(!ticks) return; + if (!DI && !DO) return; + + /* Reduce the length of DI according to the bits we're transmitting */ + DIl&=(1L<<(ticks+1))-1; + + s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,REMOTE_JTAG_TDIDO_STR,final_tms?REMOTE_TDITDO_TMS:REMOTE_TDITDO_NOTMS,ticks,DIl); + platform_buffer_write(construct,s); + + s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE); + if ((!s) || (construct[0]==REMOTE_RESP_ERR)) + { + fprintf(stderr,"jtagtap_tms_seq failed, error %s\n",s?(char *)&(construct[1]):"unknown"); + exit(-1); + } + + if (DO) + *DOl=remotehston(-1,(char *)&construct[1]); +} + +void jtagtap_tdi_seq(const uint8_t final_tms, const uint8_t *DI, int ticks) + +{ + return jtagtap_tdi_tdo_seq(NULL, final_tms, DI, ticks); +} + + +uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI) + +{ + uint8_t construct[PLATFORM_MAX_MSG_SIZE]; + int s; + + s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,REMOTE_JTAG_NEXT,dTMS?'1':'0',dTDI?'1':'0'); + + platform_buffer_write(construct,s); + + s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE); + if ((!s) || (construct[0]==REMOTE_RESP_ERR)) + { + fprintf(stderr,"jtagtap_next failed, error %s\n",s?(char *)&(construct[1]):"unknown"); + exit(-1); + } + + return remotehston(-1,(char *)&construct[1]); +} diff --git a/src/platforms/pc-hosted/platform.c b/src/platforms/pc-hosted/platform.c new file mode 100644 index 00000000..ca88d31f --- /dev/null +++ b/src/platforms/pc-hosted/platform.c @@ -0,0 +1,352 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2011 Black Sphere Technologies Ltd. + * Written by Gareth McMullin + * Additions by Dave Marples + * + * 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 3 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, see . + */ +#include "general.h" +#include "gdb_if.h" +#include "version.h" +#include "platform.h" +#include "remote.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Allow 100mS for responses to reach us */ +#define RESP_TIMEOUT (100) + +/* Define this to see the transactions across the link */ +//#define DUMP_TRANSACTIONS + +static int f; /* File descriptor for connection to GDB remote */ + +int set_interface_attribs (int fd, int speed, int parity) + +/* A nice routine grabbed from + * https://stackoverflow.com/questions/6947413/how-to-open-read-and-write-from-serial-port-in-c + */ + +{ + struct termios tty; + memset (&tty, 0, sizeof tty); + if (tcgetattr (fd, &tty) != 0) + { + fprintf(stderr,"error %d from tcgetattr", errno); + return -1; + } + + cfsetospeed (&tty, speed); + cfsetispeed (&tty, speed); + + tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars + // disable IGNBRK for mismatched speed tests; otherwise receive break + // as \000 chars + tty.c_iflag &= ~IGNBRK; // disable break processing + tty.c_lflag = 0; // no signaling chars, no echo, + // no canonical processing + tty.c_oflag = 0; // no remapping, no delays + tty.c_cc[VMIN] = 0; // read doesn't block + tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout + + tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl + + tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls, + // enable reading + tty.c_cflag &= ~(PARENB | PARODD); // shut off parity + tty.c_cflag |= parity; + tty.c_cflag &= ~CSTOPB; + tty.c_cflag &= ~CRTSCTS; + + if (tcsetattr (fd, TCSANOW, &tty) != 0) + { + fprintf(stderr,"error %d from tcsetattr", errno); + return -1; + } + return 0; +} + + +void platform_init(int argc, char **argv) +{ + int c; + char construct[PLATFORM_MAX_MSG_SIZE]; + char *serial = NULL; + while((c = getopt(argc, argv, "s:")) != -1) { + switch(c) + { + case 's': + serial = optarg; + break; + } + } + + printf("\nBlack Magic Probe (" FIRMWARE_VERSION ")\n"); + printf("Copyright (C) 2019 Black Sphere Technologies Ltd.\n"); + printf("License GPLv3+: GNU GPL version 3 or later " + "\n\n"); + + assert(gdb_if_init() == 0); + + f=open(serial,O_RDWR|O_SYNC|O_NOCTTY); + if (f<0) + { + fprintf(stderr,"Couldn't open serial port %s\n",serial); + exit(-1); + } + + if (set_interface_attribs (f, 115000, 0)<0) + { + exit(-1); + } + + c=snprintf(construct,PLATFORM_MAX_MSG_SIZE,"%s",REMOTE_START_STR); + platform_buffer_write((uint8_t *)construct,c); + c=platform_buffer_read((uint8_t *)construct, PLATFORM_MAX_MSG_SIZE); + + if ((!c) || (construct[0]==REMOTE_RESP_ERR)) + { + fprintf(stderr,"Remote Start failed, error %s\n",c?(char *)&(construct[1]):"unknown"); + exit(-1); + } + + printf("Remote is %s\n",&construct[1]); +} + +bool platform_target_get_power(void) +{ + uint8_t construct[PLATFORM_MAX_MSG_SIZE]; + int s; + + s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,"%s",REMOTE_PWR_GET_STR); + platform_buffer_write(construct,s); + + s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE); + + if ((!s) || (construct[0]==REMOTE_RESP_ERR)) + { + fprintf(stderr,"platform_target_get_power failed, error %s\n",s?(char *)&(construct[1]):"unknown"); + exit(-1); + } + + return (construct[1]=='1'); +} + +void platform_target_set_power(bool power) +{ + uint8_t construct[PLATFORM_MAX_MSG_SIZE]; + int s; + + s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,REMOTE_PWR_SET_STR,power?'1':'0'); + platform_buffer_write(construct,s); + + s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE); + + if ((!s) || (construct[0]==REMOTE_RESP_ERR)) + { + fprintf(stderr,"platform_target_set_power failed, error %s\n",s?(char *)&(construct[1]):"unknown"); + exit(-1); + } +} + +void platform_srst_set_val(bool assert) +{ + uint8_t construct[PLATFORM_MAX_MSG_SIZE]; + int s; + + s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,REMOTE_SRST_SET_STR,assert?'1':'0'); + platform_buffer_write(construct,s); + + s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE); + + if ((!s) || (construct[0]==REMOTE_RESP_ERR)) + { + fprintf(stderr,"platform_srst_set_val failed, error %s\n",s?(char *)&(construct[1]):"unknown"); + exit(-1); + } +} + +bool platform_srst_get_val(void) + +{ + uint8_t construct[PLATFORM_MAX_MSG_SIZE]; + int s; + + s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,"%s",REMOTE_SRST_GET_STR); + platform_buffer_write(construct,s); + + s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE); + + if ((!s) || (construct[0]==REMOTE_RESP_ERR)) + { + fprintf(stderr,"platform_srst_set_val failed, error %s\n",s?(char *)&(construct[1]):"unknown"); + exit(-1); + } + + return (construct[1]=='1'); +} + +void platform_buffer_flush(void) +{ + +} + +int platform_buffer_write(const uint8_t *data, int size) +{ + int s; + +#ifdef DUMP_TRANSACTIONS + printf("%s\n",data); +#endif + s=write(f,data,size); + if (s<0) + { + fprintf(stderr,"Failed to write\n"); + exit(-2); + } + + return size; +} + +int platform_buffer_read(uint8_t *data, int maxsize) + +{ + uint8_t *c; + int s; + int ret; + uint32_t endTime; + fd_set rset; + struct timeval tv; + + c=data; + tv.tv_sec=0; + + endTime=platform_time_ms()+RESP_TIMEOUT; + tv.tv_usec=1000*(endTime-platform_time_ms()); + + /* Look for start of response */ + do + { + FD_ZERO(&rset); + FD_SET(f, &rset); + + ret = select(f + 1, &rset, NULL, NULL, &tv); + if (ret < 0) + { + fprintf(stderr,"Failed on select\n"); + exit(-4); + } + if(ret == 0) + { + fprintf(stderr,"Timeout on read\n"); + exit(-3); + } + + s=read(f,c,1); + } + while ((s>0) && (*c!=REMOTE_RESP)); + + /* Now collect the response */ + do + { + FD_ZERO(&rset); + FD_SET(f, &rset); + ret = select(f + 1, &rset, NULL, NULL, &tv); + if (ret < 0) + { + fprintf(stderr,"Failed on select\n"); + exit(-4); + } + if(ret == 0) + { + fprintf(stderr,"Timeout on read\n"); + exit(-3); + } + s=read(f,c,1); + if (*c==REMOTE_EOM) + { + *c=0; +#ifdef DUMP_TRANSACTIONS + printf(" %s\n",data); +#endif + return (c-data); + } + else + c++; + } + while ((s>=0) && (c-data + * Additions by Dave Marples + * + * 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 3 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, see . + */ + +#ifndef __PLATFORM_H +#define __PLATFORM_H + +#include "timing.h" + +#ifndef _WIN32 +# include +#else +# ifndef alloca +# define alloca __builtin_alloca +# endif +#endif + +#define PLATFORM_HAS_DEBUG +#define PLATFORM_HAS_POWER_SWITCH +#define PLATFORM_MAX_MSG_SIZE (256) +#define PLATFORM_IDENT "PC-HOSTED" +#define BOARD_IDENT PLATFORM_IDENT +#define SET_RUN_STATE(state) +#define SET_IDLE_STATE(state) +#define SET_ERROR_STATE(state) + +void platform_buffer_flush(void); +int platform_buffer_write(const uint8_t *data, int size); +int platform_buffer_read(uint8_t *data, int size); + +static inline int platform_hwversion(void) +{ + return 0; +} + +#endif diff --git a/src/platforms/pc-hosted/swdptap.c b/src/platforms/pc-hosted/swdptap.c new file mode 100644 index 00000000..e63ed521 --- /dev/null +++ b/src/platforms/pc-hosted/swdptap.c @@ -0,0 +1,123 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2018 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de) + * Written by Gareth McMullin + * Modified by Dave Marples + * + * 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 3 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, see . + */ + +/* MPSSE bit-banging SW-DP interface over FTDI with loop unrolled. + * Speed is sensible. + */ + +#include +#include + +#include "general.h" +#include "swdptap.h" +#include "remote.h" + +int swdptap_init(void) + +{ + uint8_t construct[PLATFORM_MAX_MSG_SIZE]; + int s; + + s=sprintf((char *)construct,"%s",REMOTE_SWDP_INIT_STR); + platform_buffer_write(construct,s); + + s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE); + if ((!s) || (construct[0]==REMOTE_RESP_ERR)) + { + fprintf(stderr,"swdptap_init failed, error %s\n",s?(char *)&(construct[1]):"unknown"); + exit(-1); + } + + return 0; +} + + +bool swdptap_seq_in_parity(uint32_t *res, int ticks) + +{ + uint8_t construct[PLATFORM_MAX_MSG_SIZE]; + int s; + + s=sprintf((char *)construct,REMOTE_SWDP_IN_PAR_STR,ticks); + platform_buffer_write(construct,s); + + s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE); + if ((s<2) || (construct[0]==REMOTE_RESP_ERR)) + { + fprintf(stderr,"swdptap_seq_in_parity failed, error %s\n",s?(char *)&(construct[1]):"short response"); + exit(-1); + } + + *res=remotehston(-1,(char *)&construct[1]); + return (construct[0]!=REMOTE_RESP_OK); +} + + +uint32_t swdptap_seq_in(int ticks) +{ + uint8_t construct[PLATFORM_MAX_MSG_SIZE]; + int s; + + s=sprintf((char *)construct,REMOTE_SWDP_IN_STR,ticks); + platform_buffer_write(construct,s); + + s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE); + if ((s<2) || (construct[0]==REMOTE_RESP_ERR)) + { + fprintf(stderr,"swdptap_seq_in failed, error %s\n",s?(char *)&(construct[1]):"short response"); + exit(-1); + } + + return remotehston(-1,(char *)&construct[1]); +} + +void swdptap_seq_out(uint32_t MS, int ticks) +{ + uint8_t construct[PLATFORM_MAX_MSG_SIZE]; + int s; + + s=sprintf((char *)construct,REMOTE_SWDP_OUT_STR,ticks,MS); + platform_buffer_write(construct,s); + + s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE); + if ((s<1) || (construct[0]==REMOTE_RESP_ERR)) + { + fprintf(stderr,"swdptap_seq_out failed, error %s\n",s?(char *)&(construct[1]):"short response"); + exit(-1); + } +} + + +void swdptap_seq_out_parity(uint32_t MS, int ticks) +{ + uint8_t construct[PLATFORM_MAX_MSG_SIZE]; + int s; + + s=sprintf((char *)construct,REMOTE_SWDP_OUT_PAR_STR,ticks,MS); + platform_buffer_write(construct,s); + + s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE); + if ((s<1) || (construct[1]==REMOTE_RESP_ERR)) + { + fprintf(stderr,"swdptap_seq_out_parity failed, error %s\n",s?(char *)&(construct[2]):"short response"); + exit(-1); + } +} diff --git a/src/remote.c b/src/remote.c new file mode 100644 index 00000000..d54f0e22 --- /dev/null +++ b/src/remote.c @@ -0,0 +1,276 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2019 Black Sphere Technologies Ltd. + * Written by Dave Marples + * + * 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 3 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, see . + */ + +#include "general.h" +#include "remote.h" +#include "gdb_packet.h" +#include "swdptap.h" +#include "jtagtap.h" +#include "gdb_if.h" +#include "version.h" +#include + + +#define NTOH(x) ((x<=9)?x+'0':'a'+x-10) +#define HTON(x) ((x<='9')?x-'0':((TOUPPER(x))-'A'+10)) +#define TOUPPER(x) ((((x)>='a') && ((x)<='z'))?((x)-('a'-'A')):(x)) +#define ISHEX(x) ( \ + (((x)>='0') && ((x)<='9')) || \ + (((x)>='A') && ((x)<='F')) || \ + (((x)>='a') && ((x)<='f')) \ + ) + + +uint64_t remotehston(uint32_t limit, char *s) + +/* Return numeric version of string, until illegal hex digit, or limit */ + +{ + uint64_t ret=0L; + char c; + + while (limit--) { + c=*s++; + if (!ISHEX(c)) + return ret; + ret=(ret<<4)|HTON(c); + } + + return ret; +} + +static void _respond(char respCode, uint64_t param) + +/* Send response to far end */ + +{ + char buf[34]; + char *p=buf; + + gdb_if_putchar(REMOTE_RESP,0); + gdb_if_putchar(respCode,0); + + do { + *p++=NTOH((param&0x0f)); + param>>=4; + } + while (param); + + /* At this point the number to print is the buf, but backwards, so spool it out */ + do { + gdb_if_putchar(*--p,0); + } while (p>buf); + gdb_if_putchar(REMOTE_EOM,1); +} + +static void _respondS(char respCode, const char *s) +/* Send response to far end */ +{ + gdb_if_putchar(REMOTE_RESP,0); + gdb_if_putchar(respCode,0); + while (*s) { + /* Just clobber illegal characters so they don't disturb the protocol */ + if ((*s=='$') || (*s==REMOTE_SOM) || (*s==REMOTE_EOM)) + gdb_if_putchar(' ', 0); + else + gdb_if_putchar(*s, 0); + s++; + } + gdb_if_putchar(REMOTE_EOM,1); +} + +void remotePacketProcessSWD(uint8_t i, char *packet) +{ + uint8_t ticks; + uint32_t param; + bool badParity; + + switch (packet[1]) { + case REMOTE_INIT: /* SS = initialise ================================= */ + if (i==2) { + swdptap_init(); + _respond(REMOTE_RESP_OK, 0); + } else { + _respond(REMOTE_RESP_ERR,REMOTE_ERROR_WRONGLEN); + } + break; + + case REMOTE_IN_PAR: /* = In parity ================================== */ + ticks=remotehston(2,&packet[2]); + badParity=swdptap_seq_in_parity(¶m, ticks); + _respond(badParity?REMOTE_RESP_PARERR:REMOTE_RESP_OK,param); + break; + + case REMOTE_IN: /* = In ========================================= */ + ticks=remotehston(2,&packet[2]); + param=swdptap_seq_in(ticks); + _respond(REMOTE_RESP_OK,param); + break; + + case REMOTE_OUT: /* = Out ======================================== */ + ticks=remotehston(2,&packet[2]); + param=remotehston(-1, &packet[4]); + swdptap_seq_out(param, ticks); + _respond(REMOTE_RESP_OK, 0); + break; + + case REMOTE_OUT_PAR: /* = Out parity ================================= */ + ticks=remotehston(2,&packet[2]); + param=remotehston(-1, &packet[4]); + swdptap_seq_out_parity(param, ticks); + _respond(REMOTE_RESP_OK, 0); + break; + + default: + _respond(REMOTE_RESP_ERR,REMOTE_ERROR_UNRECOGNISED); + break; + } +} + +void remotePacketProcessJTAG(uint8_t i, char *packet) +{ + uint32_t MS; + uint64_t DO; + uint8_t ticks; + uint64_t DI; + + switch (packet[1]) { + case REMOTE_INIT: /* = initialise ================================= */ + jtagtap_init(); + _respond(REMOTE_RESP_OK, 0); + break; + + case REMOTE_RESET: /* = reset ================================= */ + jtagtap_reset(); + _respond(REMOTE_RESP_OK, 0); + break; + + case REMOTE_TMS: /* = TMS Sequence ================================== */ + ticks=remotehston(2,&packet[2]); + MS=remotehston(2,&packet[4]); + + if (i<4) { + _respond(REMOTE_RESP_ERR,REMOTE_ERROR_WRONGLEN); + } else { + jtagtap_tms_seq( MS, ticks); + _respond(REMOTE_RESP_OK, 0); + } + break; + + case REMOTE_TDITDO_TMS: /* = TDI/TDO ========================================= */ + case REMOTE_TDITDO_NOTMS: + + if (i<5) { + _respond(REMOTE_RESP_ERR,REMOTE_ERROR_WRONGLEN); + } else { + ticks=remotehston(2,&packet[2]); + DI=remotehston(-1,&packet[4]); + jtagtap_tdi_tdo_seq((void *)&DO, (packet[1]==REMOTE_TDITDO_TMS), (void *)&DI, ticks); + + /* Mask extra bits on return value... */ + DO&=(1<<(ticks+1))-1; + + _respond(REMOTE_RESP_OK, DO); + } + break; + + case REMOTE_NEXT: /* = NEXT ======================================== */ + if (i!=4) { + _respond(REMOTE_RESP_ERR,REMOTE_ERROR_WRONGLEN); + } else { + uint32_t dat=jtagtap_next( (packet[2]=='1'), (packet[3]=='1')); + _respond(REMOTE_RESP_OK,dat); + } + break; + + default: + _respond(REMOTE_RESP_ERR,REMOTE_ERROR_UNRECOGNISED); + break; + } +} + +void remotePacketProcessGEN(uint8_t i, char *packet) + +{ + (void)i; + switch (packet[1]) { + case REMOTE_VOLTAGE: + _respondS(REMOTE_RESP_OK,platform_target_voltage()); + break; + + case REMOTE_SRST_SET: + platform_srst_set_val(packet[2]=='1'); + _respond(REMOTE_RESP_OK,0); + break; + + case REMOTE_SRST_GET: + _respond(REMOTE_RESP_OK,platform_srst_get_val()); + break; + + case REMOTE_PWR_SET: +#ifdef PLATFORM_HAS_POWER_SWITCH + platform_target_set_power(packet[2]=='1'); + _respond(REMOTE_RESP_OK,0); +#else + _respond(REMOTE_RESP_NOTSUP,0); +#endif + break; + + case REMOTE_PWR_GET: +#ifdef PLATFORM_HAS_POWER_SWITCH + _respond(REMOTE_RESP_OK,platform_target_get_power()); +#else + _respond(REMOTE_RESP_NOTSUP,0); +#endif + break; + +#if !defined(BOARD_IDENT) && defined(PLATFORM_IDENT) +# define BOARD_IDENT PLATFORM_IDENT +#endif + case REMOTE_START: + _respondS(REMOTE_RESP_OK, BOARD_IDENT " " FIRMWARE_VERSION); + break; + + default: + _respond(REMOTE_RESP_ERR,REMOTE_ERROR_UNRECOGNISED); + break; + } +} + +void remotePacketProcess(uint8_t i, char *packet) +{ + switch (packet[0]) { + case REMOTE_SWDP_PACKET: + remotePacketProcessSWD(i,packet); + break; + + case REMOTE_JTAG_PACKET: + remotePacketProcessJTAG(i,packet); + break; + + case REMOTE_GEN_PACKET: + remotePacketProcessGEN(i,packet); + break; + + default: /* Oh dear, unrecognised, return an error */ + _respond(REMOTE_RESP_ERR,REMOTE_ERROR_UNRECOGNISED); + break; + } +} diff --git a/src/remote.h b/src/remote.h new file mode 100644 index 00000000..bddab64e --- /dev/null +++ b/src/remote.h @@ -0,0 +1,131 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2019 Black Sphere Technologies Ltd. + * Written by Dave Marples + * + * 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 3 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, see . + */ + +#ifndef _REMOTE_ +#define _REMOTE_ + +#include +#include "general.h" + +/* + * Commands to remote end, and responses + * ===================================== + * + * All commands as sent as ASCII and begin with !, ending with #. + * Parameters are hex digits and format is per command. + * + * !# + * - 2 digit ASCII value + * - x digits (according to command) ASCII value + * + * So, for example; + * + * SI - swdptap_seq_in_parity + * tt - Ticks + * e.g. SI21 : Request input with parity, 33 ticks + * resp: K - hex value returned. + * resp: F - hex value returned, bad parity. + * X - error occured + * + * The whole protocol is defined in this header file. Parameters have + * to be marshalled in remote.c, swdptap.c and jtagtap.c, so be + * careful to ensure the parameter handling matches the protocol + * definition when anything is changed. + */ + +/* Protocol error messages */ +#define REMOTE_ERROR_UNRECOGNISED 1 +#define REMOTE_ERROR_WRONGLEN 2 + +/* Start and end of message identifiers */ +#define REMOTE_SOM '!' +#define REMOTE_EOM '#' +#define REMOTE_RESP '&' + +/* Generic protocol elements */ +#define REMOTE_START 'A' +#define REMOTE_TDITDO_TMS 'D' +#define REMOTE_TDITDO_NOTMS 'd' +#define REMOTE_IN_PAR 'I' +#define REMOTE_IN 'i' +#define REMOTE_NEXT 'N' +#define REMOTE_OUT_PAR 'O' +#define REMOTE_OUT 'o' +#define REMOTE_PWR_SET 'P' +#define REMOTE_PWR_GET 'p' +#define REMOTE_RESET 'R' +#define REMOTE_INIT 'S' +#define REMOTE_TMS 'T' +#define REMOTE_VOLTAGE 'V' +#define REMOTE_SRST_SET 'Z' +#define REMOTE_SRST_GET 'z' + +/* Protocol response options */ +#define REMOTE_RESP_OK 'K' +#define REMOTE_RESP_PARERR 'P' +#define REMOTE_RESP_ERR 'E' +#define REMOTE_RESP_NOTSUP 'N' + +/* Generic protocol elements */ +#define REMOTE_GEN_PACKET 'G' + +#define REMOTE_START_STR (char []){ '+', REMOTE_EOM, REMOTE_SOM, REMOTE_GEN_PACKET, REMOTE_START, REMOTE_EOM, 0 } +#define REMOTE_VOLTAGE_STR (char []){ REMOTE_SOM, REMOTE_GEN_PACKET, REMOTE_VOLTAGE, REMOTE_EOM, 0 } +#define REMOTE_SRST_SET_STR (char []){ REMOTE_SOM, REMOTE_GEN_PACKET, REMOTE_SRST_SET, '%', 'c', REMOTE_EOM, 0 } +#define REMOTE_SRST_GET_STR (char []){ REMOTE_SOM, REMOTE_GEN_PACKET, REMOTE_SRST_GET, REMOTE_EOM, 0 } +#define REMOTE_PWR_SET_STR (char []){ REMOTE_SOM, REMOTE_GEN_PACKET, REMOTE_PWR_SET, '%', 'c', REMOTE_EOM, 0 } +#define REMOTE_PWR_GET_STR (char []){ REMOTE_SOM, REMOTE_GEN_PACKET, REMOTE_PWR_GET, REMOTE_EOM, 0 } + +/* SWDP protocol elements */ +#define REMOTE_SWDP_PACKET 'S' +#define REMOTE_SWDP_INIT_STR (char []){ REMOTE_SOM, REMOTE_SWDP_PACKET, REMOTE_INIT, REMOTE_EOM, 0 } + +#define REMOTE_SWDP_IN_PAR_STR (char []){ REMOTE_SOM, REMOTE_SWDP_PACKET, REMOTE_IN_PAR, \ + '%','0','2','x',REMOTE_EOM, 0 } + +#define REMOTE_SWDP_IN_STR (char []){ REMOTE_SOM, REMOTE_SWDP_PACKET, REMOTE_IN, \ + '%','0','2','x',REMOTE_EOM, 0 } + +#define REMOTE_SWDP_OUT_STR (char []){ REMOTE_SOM, REMOTE_SWDP_PACKET, REMOTE_OUT, \ + '%','0','2','x','%','x',REMOTE_EOM, 0 } + +#define REMOTE_SWDP_OUT_PAR_STR (char []){ REMOTE_SOM, REMOTE_SWDP_PACKET, REMOTE_OUT_PAR, \ + '%','0','2','x','%','x',REMOTE_EOM, 0 } + +/* JTAG protocol elements */ +#define REMOTE_JTAG_PACKET 'J' + +#define REMOTE_JTAG_INIT_STR (char []){ '+',REMOTE_EOM, REMOTE_SOM, REMOTE_JTAG_PACKET, REMOTE_INIT, REMOTE_EOM, 0 } + +#define REMOTE_JTAG_RESET_STR (char []){ '+',REMOTE_EOM, REMOTE_SOM, REMOTE_JTAG_PACKET, REMOTE_RESET, REMOTE_EOM, 0 } + +#define REMOTE_JTAG_TMS_STR (char []){ REMOTE_SOM, REMOTE_JTAG_PACKET, REMOTE_TMS, \ + '%','0','2','x','%','x',REMOTE_EOM, 0 } + +#define REMOTE_JTAG_TDIDO_STR (char []){ REMOTE_SOM, REMOTE_JTAG_PACKET, '%', 'c', \ + '%','0','2','x','%','l', 'x', REMOTE_EOM, 0 } + +#define REMOTE_JTAG_NEXT (char []){ REMOTE_SOM, REMOTE_JTAG_PACKET, REMOTE_NEXT, \ + '%','c','%','c',REMOTE_EOM, 0 } + +uint64_t remotehston(uint32_t limit, char *s); +void remotePacketProcess(uint8_t i, char *packet); + +#endif