Addition of pc-hosted variant and extensions to other targets to support it.

This commit is contained in:
Dave Marples 2019-10-01 14:06:30 +02:00 committed by UweBonnes
parent 8a1d8bfba3
commit 90df8172ca
11 changed files with 1186 additions and 4 deletions

View File

@ -13,6 +13,10 @@ ifeq ($(PROBE_HOST), pc-stlinkv2)
PC_HOSTED = true PC_HOSTED = true
NO_LIBOPENCM3 = true NO_LIBOPENCM3 = true
endif endif
ifeq ($(PROBE_HOST), pc-hosted)
PC_HOSTED = true
NO_LIBOPENCM3 = true
endif
all: all:
ifndef NO_LIBOPENCM3 ifndef NO_LIBOPENCM3

View File

@ -46,7 +46,7 @@ SRC = \
nxpke04.c \ nxpke04.c \
platform.c \ platform.c \
sam3x.c \ sam3x.c \
sam4l.c \ sam4l.c \
samd.c \ samd.c \
stm32f1.c \ stm32f1.c \
stm32f4.c \ stm32f4.c \
@ -71,6 +71,9 @@ endif
ifndef OWN_HL ifndef OWN_HL
SRC += jtag_scan.c jtagtap.c swdptap.c SRC += jtag_scan.c jtagtap.c swdptap.c
SRC += remote.c
else
CFLAGS += -DOWN_HL
endif endif
OBJ = $(patsubst %.S,%.o,$(patsubst %.c,%.o,$(SRC))) OBJ = $(patsubst %.S,%.o,$(patsubst %.c,%.o,$(SRC)))

View File

@ -26,6 +26,7 @@
#include "gdb_if.h" #include "gdb_if.h"
#include "gdb_packet.h" #include "gdb_packet.h"
#include "hex_utils.h" #include "hex_utils.h"
#include "remote.h"
#include <stdarg.h> #include <stdarg.h>
@ -37,9 +38,52 @@ int gdb_getpacket(char *packet, int size)
int i; int i;
while(1) { while(1) {
/* Wait for packet start */ /* Wait for packet start */
while((packet[0] = gdb_if_getchar()) != '$') do {
if(packet[0] == 0x04) return 1; /* 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<size) {
packet[i++]=c;
} else {
/* Who knows what is going on...return to normality */
gettingRemotePacket=false;
}
break;
}
}
}
#endif
} while (packet[0] != '$');
i = 0; csum = 0; i = 0; csum = 0;
/* Capture packet data into buffer */ /* Capture packet data into buffer */

View File

@ -0,0 +1,12 @@
TARGET=blackmagic_hosted
SYS = $(shell $(CC) -dumpmachine)
CFLAGS += -DPC_HOSTED -DNO_LIBOPENCM3 -DENABLE_DEBUG
LDFLAGS += -lftdi1
ifneq (, $(findstring mingw, $(SYS)))
LDFLAGS += -lusb-1.0 -lws2_32
CFLAGS += -Wno-cast-function-type
else ifneq (, $(findstring cygwin, $(SYS)))
LDFLAGS += -lusb-1.0 -lws2_32
endif
VPATH += platforms/pc
SRC += timing.c \

View File

@ -0,0 +1,40 @@
PC Hosted variant
THIS IS INCOMPLETE - ONLY SUPPORTS SWD AT THE MOMENT
This variant will use any BMP probe with recent firmware as a remote
actuator, with the actual probe code running on the PC. The BMP itself
is 'dumb' and doesn't do anything (although any secondary serial port
remains available).
To use it, compile for the pc-hosted target and then connect to your normal
BMP GDB port;
src/blackmagic -s /dev/ttyACM0
...you can then connect your gdb session to localhost:2000 for all your
debugging goodness;
$arm-eabi-none-gdb
(gdb) monitor swdp_scan
Target voltage: not supported
Available Targets:
No. Att Driver
1 STM32F1 medium density M3/M4
(gdb) attach 1
Attaching to program: Builds/blackmagic/src/blackmagic, Remote target
0x08001978 in ?? ()
(gdb) file src/blackmagic
A program is being debugged already.
Are you sure you want to change the file? (y or n) y
Load new symbol table from "src/blackmagic"? (y or n) y
Reading symbols from src/blackmagic...
(gdb) load
Loading section .text, size 0x1201c lma 0x8002000
Loading section .data, size 0xd8 lma 0x801401c
Start address 0x800d9fc, load size 73972
Transfer rate: 2 KB/sec, 960 bytes/write.
(gdb)
...note that the speed of the probe in this way is about 10 times less than
running native. This build is intended for debug and development only.

View File

@ -0,0 +1,144 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2008 Black Sphere Technologies Ltd.
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
* Modified by Dave Marples <dave@marples.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 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 <http://www.gnu.org/licenses/>.
*/
/* Low level JTAG implementation using FT2232 with libftdi.
*
* Issues:
* Should share interface with swdptap.c or at least clean up...
*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#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]);
}

View File

@ -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 <gareth@blacksphere.co.nz>
* Additions by Dave Marples <dave@marples.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 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 <http://www.gnu.org/licenses/>.
*/
#include "general.h"
#include "gdb_if.h"
#include "version.h"
#include "platform.h"
#include "remote.h"
#include <assert.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
/* 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 "
"<http://gnu.org/licenses/gpl.html>\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<maxsize));
fprintf(stderr,"Failed to read\n");
exit(-3);
return 0;
}
#if defined(_WIN32) && !defined(__MINGW32__)
#warning "This vasprintf() is dubious!"
int vasprintf(char **strp, const char *fmt, va_list ap)
{
int size = 128, ret = 0;
*strp = malloc(size);
while(*strp && ((ret = vsnprintf(*strp, size, fmt, ap)) == size))
*strp = realloc(*strp, size <<= 1);
return ret;
}
#endif
const char *platform_target_voltage(void)
{
static uint8_t construct[PLATFORM_MAX_MSG_SIZE];
int s;
s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,"%s",REMOTE_VOLTAGE_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_voltage failed, error %s\n",s?(char *)&(construct[1]):"unknown");
exit(-1);
}
return (char *)&construct[1];
}
void platform_delay(uint32_t ms)
{
usleep(ms * 1000);
}
uint32_t platform_time_ms(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
}

View File

@ -0,0 +1,53 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2011 Black Sphere Technologies Ltd.
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
* Additions by Dave Marples <dave@marples.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 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 <http://www.gnu.org/licenses/>.
*/
#ifndef __PLATFORM_H
#define __PLATFORM_H
#include "timing.h"
#ifndef _WIN32
# include <alloca.h>
#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

View File

@ -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 <gareth@blacksphere.co.nz>
* Modified by Dave Marples <dave@marples.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 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 <http://www.gnu.org/licenses/>.
*/
/* MPSSE bit-banging SW-DP interface over FTDI with loop unrolled.
* Speed is sensible.
*/
#include <stdio.h>
#include <assert.h>
#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);
}
}

276
src/remote.c Normal file
View File

@ -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 <dave@marples.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 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 <http://www.gnu.org/licenses/>.
*/
#include "general.h"
#include "remote.h"
#include "gdb_packet.h"
#include "swdptap.h"
#include "jtagtap.h"
#include "gdb_if.h"
#include "version.h"
#include <stdarg.h>
#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(&param, 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;
}
}

131
src/remote.h Normal file
View File

@ -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 <dave@marples.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 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 <http://www.gnu.org/licenses/>.
*/
#ifndef _REMOTE_
#define _REMOTE_
#include <inttypes.h>
#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.
*
* !<CMD><PARAM>#
* <CMD> - 2 digit ASCII value
* <PARAM> - 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<PARAM> - hex value returned.
* resp: F<PARAM> - hex value returned, bad parity.
* X<err> - 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