From 9025eb792861930e6af918d2727c4f5d97a69936 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 19 Dec 2008 21:11:45 -0800 Subject: Autotools. Signed-off-by: Keith Packard --- lib/ccdbg-manual.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 lib/ccdbg-manual.c (limited to 'lib/ccdbg-manual.c') diff --git a/lib/ccdbg-manual.c b/lib/ccdbg-manual.c new file mode 100644 index 00000000..b83dc450 --- /dev/null +++ b/lib/ccdbg-manual.c @@ -0,0 +1,70 @@ +/* + * Copyright © 2008 Keith Packard + * + * 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 "ccdbg.h" + +/* + * Manual bit-banging to debug the low level protocol + */ + +static void +get_bit(char *line, int i, char on, uint8_t bit, uint8_t *bits, uint8_t *masks) +{ + if (line[i] == on) { + *bits |= bit; + *masks |= bit; + return; + } + if (line[i] == '.') { + *masks |= bit; + return; + } + if (line[i] == '-') { + return; + } + fprintf(stderr, "bad line %s\n", line); + exit (1); +} + +void +ccdbg_manual(struct ccdbg *dbg, FILE *input) +{ + char line[80]; + uint8_t set, mask; + + while (fgets(line, sizeof line, input)) { + if (line[0] == '#' || line[0] == '\n') { + printf ("%s", line); + continue; + } + set = 0; + mask = 0; + get_bit(line, 0, 'C', CC_CLOCK, &set, &mask); + get_bit(line, 2, 'D', CC_DATA, &set, &mask); + get_bit(line, 4, 'R', CC_RESET_N, &set, &mask); + if (mask != (CC_CLOCK|CC_DATA|CC_RESET_N)) { + uint8_t read; + read = ccdbg_read(dbg); + ccdbg_print("\t%c %c %c", CC_CLOCK|CC_DATA|CC_RESET_N, read); + if ((set & CC_CLOCK) == 0) + printf ("\t%d", (read&CC_DATA) ? 1 : 0); + printf ("\n"); + } + ccdbg_send(dbg, mask, set); + } +} -- cgit v1.2.3 From 1264c3676e95427bba5d01e05c303d036a7f9eca Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 26 Dec 2008 23:05:04 -0800 Subject: Switch to libusb-1.0 and use async interface. The async libusb interface offers substantial performance benefits by not making each command wait for the reply. This makes talking over this interface almost reasonable. Signed-off-by: Keith Packard --- ccload/Makefile.am | 4 +- configure.ac | 4 ++ lib/Makefile.am | 5 +- lib/ccdbg-command.c | 2 + lib/ccdbg-debug.h | 44 +++++++++++++ lib/ccdbg-io.c | 70 ++++++++++++++++----- lib/ccdbg-manual.c | 2 +- lib/ccdbg.h | 48 ++++++-------- lib/cp-usb-async.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/cp-usb-async.h | 38 ++++++++++++ s51/Makefile.am | 4 +- 11 files changed, 344 insertions(+), 53 deletions(-) create mode 100644 lib/ccdbg-debug.h create mode 100644 lib/cp-usb-async.c create mode 100644 lib/cp-usb-async.h (limited to 'lib/ccdbg-manual.c') diff --git a/ccload/Makefile.am b/ccload/Makefile.am index f54f4aaa..3a754b23 100644 --- a/ccload/Makefile.am +++ b/ccload/Makefile.am @@ -1,10 +1,10 @@ bin_PROGRAMS=ccload -AM_CFLAGS=-I$(top_srcdir)/lib +AM_CFLAGS=-I$(top_srcdir)/lib $(LIBUSB_CFLAGS) CCLOAD_LIBS=../lib/libcc.a ccload_DEPENDENCIES = $(CCLOAD_LIBS) -ccload_LDADD=$(CCLOAD_LIBS) $(USB_LIBS) +ccload_LDADD=$(CCLOAD_LIBS) $(LIBUSB_LIBS) ccload_SOURCES = ccload.c diff --git a/configure.ac b/configure.ac index a14c802b..3ae80522 100644 --- a/configure.ac +++ b/configure.ac @@ -30,7 +30,9 @@ AC_PROG_CC AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_RANLIB +PKG_PROG_PKG_CONFIG +CFLAGS="-g" WARN_CFLAGS="" if test "x$GCC" = "xyes"; then WARN_CFLAGS="-Wall -Wpointer-arith -Wstrict-prototypes \ @@ -57,6 +59,8 @@ fi AC_MSG_RESULT([$CC_FOR_BUILD]) AC_SUBST(CC_FOR_BUILD) +PKG_CHECK_MODULES([LIBUSB], [libusb-1.0]) + AC_MSG_CHECKING([for suffix of executable build tools]) if test $cross_compiling = yes; then cat >conftest.c <<\_______EOF diff --git a/lib/Makefile.am b/lib/Makefile.am index a5e5932b..16f5b921 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,6 +1,6 @@ noinst_LIBRARIES = libcc.a -AM_CFLAGS=$(WARN_CFLAGS) +AM_CFLAGS=$(WARN_CFLAGS) $(LIBUSB_CFLAGS) libcc_a_SOURCES = \ ccdbg-command.c \ @@ -11,4 +11,5 @@ libcc_a_SOURCES = \ ccdbg-io.c \ ccdbg-manual.c \ ccdbg-memory.c \ - cp-usb.c + cp-usb.c \ + cp-usb-async.c diff --git a/lib/ccdbg-command.c b/lib/ccdbg-command.c index 30f5094d..2b29fdee 100644 --- a/lib/ccdbg-command.c +++ b/lib/ccdbg-command.c @@ -31,6 +31,7 @@ ccdbg_debug_mode(struct ccdbg *dbg) ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_DATA ); ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_DATA|CC_RESET_N); + ccdbg_sync_io(dbg); } void @@ -45,6 +46,7 @@ ccdbg_reset(struct ccdbg *dbg) ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); + ccdbg_sync_io(dbg); } uint8_t diff --git a/lib/ccdbg-debug.h b/lib/ccdbg-debug.h new file mode 100644 index 00000000..a09148d3 --- /dev/null +++ b/lib/ccdbg-debug.h @@ -0,0 +1,44 @@ +/* + * Copyright © 2008 Keith Packard + * + * 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. + */ + +#ifndef _CCDBG_DEBUG_H_ +#define _CCDBG_DEBUG_H_ +/* Debug levels + */ +#define CC_DEBUG_BITBANG 0x00000001 +#define CC_DEBUG_COMMAND 0x00000002 +#define CC_DEBUG_INSTRUCTIONS 0x00000004 +#define CC_DEBUG_EXECUTE 0x00000008 +#define CC_DEBUG_FLASH 0x00000010 +#define CC_DEBUG_MEMORY 0x00000020 +#define CC_DEBUG_USB_ASYNC 0x00000040 + +/* ccdbg-debug.c */ +void +ccdbg_debug(int level, char *format, ...); + +void +ccdbg_add_debug(int level); + +void +ccdbg_clear_debug(int level); + +void +ccdbg_flush(void); + +#endif /* _CCDBG_DEBUG_H_ */ diff --git a/lib/ccdbg-io.c b/lib/ccdbg-io.c index 5ecea769..53ea7583 100644 --- a/lib/ccdbg-io.c +++ b/lib/ccdbg-io.c @@ -18,6 +18,11 @@ #include "ccdbg.h" #include +#ifdef CP_USB_ASYNC +#include "cp-usb-async.h" +#else +#include "cp-usb.h" +#endif void ccdbg_half_clock(struct ccdbg *dbg) @@ -38,32 +43,60 @@ ccdbg_open(void) perror("calloc"); return NULL; } +#ifdef CP_USB_ASYNC + dbg->cp_async = cp_usb_async_open(); + if (!dbg->cp_async) { + free (dbg); + return NULL; + } +#else dbg->cp = cp_usb_open (); if (!dbg->cp) { free (dbg); return NULL; } +#endif return dbg; } void ccdbg_close(struct ccdbg *dbg) { +#ifdef CP_USB_ASYNC + cp_usb_async_close(dbg->cp_async); +#else cp_usb_close(dbg->cp); +#endif free (dbg); } int ccdbg_write(struct ccdbg *dbg, uint8_t mask, uint8_t value) { +#ifdef CP_USB_ASYNC + cp_usb_async_write(dbg->cp_async, mask, value); +#else cp_usb_write(dbg->cp, mask, value); +#endif return 0; } -uint8_t -ccdbg_read(struct ccdbg *dbg) +void +ccdbg_read(struct ccdbg *dbg, uint8_t *valuep) +{ +#ifdef CP_USB_ASYNC + cp_usb_async_read(dbg->cp_async, valuep); +#else + *valuep = cp_usb_read(dbg->cp); +#endif +} + +void +ccdbg_sync_io(struct ccdbg *dbg) { - return cp_usb_read(dbg->cp); +#ifdef CP_USB_ASYNC + cp_usb_async_sync(dbg->cp_async); +#endif } static char @@ -112,6 +145,7 @@ ccdbg_send_byte(struct ccdbg *dbg, uint8_t byte) if (bit == 3) ccdbg_debug(CC_DEBUG_BITBANG, "\n"); } + ccdbg_sync_io(dbg); } void @@ -121,43 +155,47 @@ ccdbg_send_bytes(struct ccdbg *dbg, uint8_t *bytes, int nbytes) ccdbg_send_byte(dbg, *bytes++); } -uint8_t -ccdbg_recv_bit(struct ccdbg *dbg, int first) +void +ccdbg_recv_bit(struct ccdbg *dbg, int first, uint8_t *bit) { uint8_t mask = first ? CC_DATA : 0; - uint8_t read; ccdbg_send(dbg, CC_CLOCK|mask|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); - read = ccdbg_read(dbg); - ccdbg_print("#\t%c %c %c\n", CC_DATA, read); + ccdbg_read(dbg, bit); ccdbg_send(dbg, CC_CLOCK| CC_RESET_N, CC_RESET_N); - return (read & CC_DATA) ? 1 : 0; } -uint8_t -ccdbg_recv_byte(struct ccdbg *dbg, int first) +void +ccdbg_recv_byte(struct ccdbg *dbg, int first, uint8_t *bytep) { uint8_t byte = 0; + uint8_t bits[8]; int bit; ccdbg_debug(CC_DEBUG_BITBANG, "#\n# Recv byte\n#\n"); + for (bit = 0; bit < 8; bit++) { + ccdbg_recv_bit(dbg, first, &bits[bit]); + first = 0; + } + ccdbg_sync_io(dbg); for (bit = 0; bit < 8; bit++) { byte = byte << 1; - byte |= ccdbg_recv_bit(dbg, first); + byte |= (bits[bit] & CC_DATA) ? 1 : 0; + ccdbg_print("#\t%c %c %c\n", CC_DATA, bits[bit]); if (bit == 3) ccdbg_debug(CC_DEBUG_BITBANG, "\n"); - first = 0; } ccdbg_debug(CC_DEBUG_BITBANG, "#\n# Recv 0x%02x\n#\n", byte); - return byte; + *bytep = byte; } void ccdbg_recv_bytes(struct ccdbg *dbg, uint8_t *bytes, int nbytes) { + int i; int first = 1; - while (nbytes--) { - *bytes++ = ccdbg_recv_byte(dbg, first); + for (i = 0; i < nbytes; i++) { + ccdbg_recv_byte(dbg, first, &bytes[i]); first = 0; } } diff --git a/lib/ccdbg-manual.c b/lib/ccdbg-manual.c index b83dc450..b48f8bb1 100644 --- a/lib/ccdbg-manual.c +++ b/lib/ccdbg-manual.c @@ -59,7 +59,7 @@ ccdbg_manual(struct ccdbg *dbg, FILE *input) get_bit(line, 4, 'R', CC_RESET_N, &set, &mask); if (mask != (CC_CLOCK|CC_DATA|CC_RESET_N)) { uint8_t read; - read = ccdbg_read(dbg); + ccdbg_read(dbg, &read); ccdbg_print("\t%c %c %c", CC_CLOCK|CC_DATA|CC_RESET_N, read); if ((set & CC_CLOCK) == 0) printf ("\t%d", (read&CC_DATA) ? 1 : 0); diff --git a/lib/ccdbg.h b/lib/ccdbg.h index e0e58104..834092b2 100644 --- a/lib/ccdbg.h +++ b/lib/ccdbg.h @@ -30,11 +30,12 @@ #include #include #include -#include "cp-usb.h" +#include "ccdbg-debug.h" + #define CC_CLOCK 0x1 #define CC_DATA 0x2 #define CC_RESET_N 0x4 -#define CC_CLOCK_US (40) +#define CC_CLOCK_US (0) /* 8051 instructions */ @@ -90,8 +91,14 @@ /* Bit-addressable accumulator */ #define ACC(bit) (0xE0 | (bit)) +#define CP_USB_ASYNC + struct ccdbg { +#ifdef CP_USB_ASYNC + struct cp_usb_async *cp_async; +#else struct cp_usb *cp; +#endif }; /* Intel hex file format data @@ -153,15 +160,6 @@ struct hex_image { #define CC_STEP_REPLACE(n) (0x64|(n)) #define CC_GET_CHIP_ID 0x68 -/* Debug levels - */ -#define CC_DEBUG_BITBANG 0x00000001 -#define CC_DEBUG_COMMAND 0x00000002 -#define CC_DEBUG_INSTRUCTIONS 0x00000004 -#define CC_DEBUG_EXECUTE 0x00000008 -#define CC_DEBUG_FLASH 0x00000010 -#define CC_DEBUG_MEMORY 0x00000020 - /* ccdbg-command.c */ void ccdbg_debug_mode(struct ccdbg *dbg); @@ -214,19 +212,6 @@ ccdbg_set_pc(struct ccdbg *dbg, uint16_t pc); uint8_t ccdbg_execute_hex_image(struct ccdbg *dbg, struct hex_image *image); -/* ccdbg-debug.c */ -void -ccdbg_debug(int level, char *format, ...); - -void -ccdbg_add_debug(int level); - -void -ccdbg_clear_debug(int level); - -void -ccdbg_flush(void); - /* ccdbg-flash.c */ uint8_t ccdbg_flash_hex_image(struct ccdbg *dbg, struct hex_image *image); @@ -254,8 +239,8 @@ ccdbg_half_clock(struct ccdbg *dbg); int ccdbg_write(struct ccdbg *dbg, uint8_t mask, uint8_t value); -uint8_t -ccdbg_read(struct ccdbg *dbg); +void +ccdbg_read(struct ccdbg *dbg, uint8_t *valuep); struct ccdbg * ccdbg_open(void); @@ -302,15 +287,18 @@ ccdbg_send_byte(struct ccdbg *dbg, uint8_t byte); void ccdbg_send_bytes(struct ccdbg *dbg, uint8_t *bytes, int nbytes); -uint8_t -ccdbg_recv_bit(struct ccdbg *dbg, int first); +void +ccdbg_recv_bit(struct ccdbg *dbg, int first, uint8_t *bit); -uint8_t -ccdbg_recv_byte(struct ccdbg *dbg, int first); +void +ccdbg_recv_byte(struct ccdbg *dbg, int first, uint8_t *byte); void ccdbg_recv_bytes(struct ccdbg *dbg, uint8_t *bytes, int nbytes); +void +ccdbg_sync_io(struct ccdbg *dbg); + void ccdbg_print(char *format, uint8_t mask, uint8_t set); diff --git a/lib/cp-usb-async.c b/lib/cp-usb-async.c new file mode 100644 index 00000000..3f5f76ab --- /dev/null +++ b/lib/cp-usb-async.c @@ -0,0 +1,176 @@ +/* + * Copyright © 2008 Keith Packard + * + * 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 +#include +#include +#include +#include "cp-usb-async.h" +#include "ccdbg-debug.h" + +#define MAX_OUTSTANDING 256 +#define CP_TIMEOUT 1000 /* ms */ + +struct cp_usb_packet { + struct libusb_transfer *transfer; + enum { packet_read, packet_write } direction; + unsigned char data[9]; + uint8_t *valuep; +}; + +struct cp_usb_async { + libusb_context *ctx; + libusb_device_handle *handle; + struct cp_usb_packet packet[MAX_OUTSTANDING]; + int p, ack; +}; + +struct cp_usb_async * +cp_usb_async_open(void) +{ + struct cp_usb_async *cp; + int ret; + + cp = calloc(sizeof (struct cp_usb_async), 1); + if (!cp) + return NULL; + ret = libusb_init(&cp->ctx); + if (ret) { + free(cp); + return NULL; + } + cp->handle = libusb_open_device_with_vid_pid(cp->ctx, + 0x10c4, 0xea60); + if (!cp->handle) { + libusb_exit(cp->ctx); + free(cp); + return NULL; + } + return cp; +} + +void +cp_usb_async_close(struct cp_usb_async *cp) +{ + libusb_close(cp->handle); + libusb_exit(cp->ctx); + free(cp); +} + +static void +cp_usb_async_transfer_callback(struct libusb_transfer *transfer) +{ + struct cp_usb_async *cp = transfer->user_data; + int p; + + for (p = 0; p < cp->p; p++) + if (cp->packet[p].transfer == transfer) + break; + if (p == cp->p) { + fprintf(stderr, "unknown transfer\n"); + return; + } + switch (cp->packet[p].direction) { + case packet_read: + ccdbg_debug(CC_DEBUG_USB_ASYNC, "ack read %d 0x%02x\n", + p, cp->packet[p].data[8]); + *cp->packet[p].valuep = cp->packet[p].data[8]; + break; + case packet_write: + ccdbg_debug(CC_DEBUG_USB_ASYNC, "ack write %d\n", p); + break; + } + if (p > cp->ack) + cp->ack = p; +} + +void +cp_usb_async_write(struct cp_usb_async *cp, uint8_t mask, uint8_t value) +{ + int p; + uint16_t gpio_set = ((uint16_t) value << 8) | mask; + int ret; + + if (cp->p == MAX_OUTSTANDING) + cp_usb_async_sync(cp); + p = cp->p; + if (!cp->packet[p].transfer) + cp->packet[p].transfer = libusb_alloc_transfer(0); + cp->packet[p].direction = packet_write; + libusb_fill_control_setup(cp->packet[p].data, + 0x40, /* request */ + 0xff, /* request type */ + 0x37e1, /* value */ + gpio_set, /* index */ + 0); /* length */ + + libusb_fill_control_transfer(cp->packet[p].transfer, + cp->handle, + cp->packet[p].data, + cp_usb_async_transfer_callback, + cp, + CP_TIMEOUT); + ccdbg_debug(CC_DEBUG_USB_ASYNC, "Write packet %d 0x%x 0x%x\n", p, mask, value); + ret = libusb_submit_transfer(cp->packet[p].transfer); + if (ret) + fprintf(stderr, "libusb_submit_transfer failed %d\n", ret); + cp->p++; +} + +void +cp_usb_async_read(struct cp_usb_async *cp, uint8_t *valuep) +{ + int p; + int ret; + + if (cp->p == MAX_OUTSTANDING) + cp_usb_async_sync(cp); + p = cp->p; + if (!cp->packet[p].transfer) + cp->packet[p].transfer = libusb_alloc_transfer(0); + cp->packet[p].valuep = valuep; + cp->packet[p].direction = packet_read; + libusb_fill_control_setup(cp->packet[p].data, + 0xc0, /* request */ + 0xff, /* request type */ + 0x00c2, /* value */ + 0, /* index */ + 1); /* length */ + + libusb_fill_control_transfer(cp->packet[p].transfer, + cp->handle, + cp->packet[p].data, + cp_usb_async_transfer_callback, + cp, + CP_TIMEOUT); + ccdbg_debug(CC_DEBUG_USB_ASYNC, "Read packet %d\n", p); + ret = libusb_submit_transfer(cp->packet[p].transfer); + if (ret) + fprintf(stderr, "libusb_submit_transfer failed %d\n", ret); + cp->p++; +} + +void +cp_usb_async_sync(struct cp_usb_async *cp) +{ + while (cp->ack < cp->p - 1) { + libusb_handle_events(cp->ctx); + } + cp->p = 0; + cp->ack = 0; +} diff --git a/lib/cp-usb-async.h b/lib/cp-usb-async.h new file mode 100644 index 00000000..976a320e --- /dev/null +++ b/lib/cp-usb-async.h @@ -0,0 +1,38 @@ +/* + * Copyright © 2008 Keith Packard + * + * 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. + */ + +#ifndef _CP_USB_ASYNC_H_ +#define _CP_USB_ASYNC_H_ +#include + +struct cp_usb_async * +cp_usb_async_open(void); + +void +cp_usb_async_close(struct cp_usb_async *cp); + +void +cp_usb_async_write(struct cp_usb_async *cp, uint8_t mask, uint8_t value); + +void +cp_usb_async_read(struct cp_usb_async *cp, uint8_t *valuep); + +void +cp_usb_async_sync(struct cp_usb_async *cp); + +#endif diff --git a/s51/Makefile.am b/s51/Makefile.am index cfa183d4..fa6fc692 100644 --- a/s51/Makefile.am +++ b/s51/Makefile.am @@ -1,10 +1,10 @@ bin_PROGRAMS=s51 -AM_CFLAGS=-I$(top_srcdir)/lib +AM_CFLAGS=-I$(top_srcdir)/lib $(LIBUSB_CFLAGS) S51_LIBS=../lib/libcc.a s51_DEPENDENCIES = $(S51_LIBS) -s51_LDADD=$(S51_LIBS) $(USB_LIBS) +s51_LDADD=$(S51_LIBS) $(LIBUSB_LIBS) s51_SOURCES = s51-parse.c s51-command.c s51-main.c -- cgit v1.2.3 From 77d754afc2d14aaa4413c13ebe3777ef385f62a9 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 7 Mar 2009 14:48:49 -0800 Subject: Sync after manual bit reading --- lib/ccdbg-manual.c | 1 + 1 file changed, 1 insertion(+) (limited to 'lib/ccdbg-manual.c') diff --git a/lib/ccdbg-manual.c b/lib/ccdbg-manual.c index b48f8bb1..4bbf0879 100644 --- a/lib/ccdbg-manual.c +++ b/lib/ccdbg-manual.c @@ -60,6 +60,7 @@ ccdbg_manual(struct ccdbg *dbg, FILE *input) if (mask != (CC_CLOCK|CC_DATA|CC_RESET_N)) { uint8_t read; ccdbg_read(dbg, &read); + ccdbg_sync_io(dbg); ccdbg_print("\t%c %c %c", CC_CLOCK|CC_DATA|CC_RESET_N, read); if ((set & CC_CLOCK) == 0) printf ("\t%d", (read&CC_DATA) ? 1 : 0); -- cgit v1.2.3 From ade11f88754b4ab0386ebf86afc5257e59238f62 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 7 Mar 2009 21:04:38 -0800 Subject: Make manual bit flipping sync after every transaction --- lib/ccdbg-manual.c | 1 + 1 file changed, 1 insertion(+) (limited to 'lib/ccdbg-manual.c') diff --git a/lib/ccdbg-manual.c b/lib/ccdbg-manual.c index 4bbf0879..df79d88d 100644 --- a/lib/ccdbg-manual.c +++ b/lib/ccdbg-manual.c @@ -67,5 +67,6 @@ ccdbg_manual(struct ccdbg *dbg, FILE *input) printf ("\n"); } ccdbg_send(dbg, mask, set); + ccdbg_sync_io(dbg); } } -- cgit v1.2.3 From 2d9b8a83a2d9f495199033e43f519d26f27938fe Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 6 Apr 2009 11:31:49 -0700 Subject: Add support for a serial-connected custom debug dongle This uses the cc1111 board as a custom debug dongle with faster methods for communicating with the debug target. --- lib/Makefile.am | 4 + lib/cc-bitbang.c | 270 +++++++++++++++++++++++++++++++++++++++ lib/cc-bitbang.h | 94 ++++++++++++++ lib/cc-usb.c | 355 ++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/cc-usb.h | 53 ++++++++ lib/ccdbg-command.c | 52 +++----- lib/ccdbg-debug.c | 9 ++ lib/ccdbg-io.c | 213 ++++++++----------------------- lib/ccdbg-manual.c | 15 ++- lib/ccdbg-memory.c | 4 + lib/ccdbg.h | 88 +++---------- lib/cp-usb.c | 1 + 12 files changed, 885 insertions(+), 273 deletions(-) create mode 100644 lib/cc-bitbang.c create mode 100644 lib/cc-bitbang.h create mode 100644 lib/cc-usb.c create mode 100644 lib/cc-usb.h (limited to 'lib/ccdbg-manual.c') diff --git a/lib/Makefile.am b/lib/Makefile.am index ba6f9725..4d9ded3a 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -13,5 +13,9 @@ libcc_a_SOURCES = \ ccdbg-memory.c \ ccdbg-rom.c \ ccdbg-state.c \ + cc-usb.c \ + cc-usb.h \ + cc-bitbang.c \ + cc-bitbang.h \ cp-usb.c \ cp-usb-async.c diff --git a/lib/cc-bitbang.c b/lib/cc-bitbang.c new file mode 100644 index 00000000..a5d2d369 --- /dev/null +++ b/lib/cc-bitbang.c @@ -0,0 +1,270 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 +#include +#include +#include "ccdbg-debug.h" +#include "cc-bitbang.h" + +#define CP_USB_ASYNC + +#ifdef CP_USB_ASYNC +#include "cp-usb-async.h" +#else +#include "cp-usb.h" +#endif + +struct cc_bitbang { +#ifdef CP_USB_ASYNC + struct cp_usb_async *cp_async; +#else + struct cp_usb *cp; +#endif +}; + +static uint32_t cc_clock_us = CC_CLOCK_US; +static uint32_t cc_reset_us = CC_RESET_US; + +void +cc_bitbang_set_clock(uint32_t us) +{ + cc_clock_us = us; +} + +void +cc_bitbang_half_clock(struct cc_bitbang *bb) +{ + struct timespec req, rem; + req.tv_sec = (cc_clock_us / 2) / 1000000; + req.tv_nsec = ((cc_clock_us / 2) % 1000000) * 1000; + nanosleep(&req, &rem); +} + +void +cc_bitbang_wait_reset(struct cc_bitbang *bb) +{ + struct timespec req, rem; + + cc_bitbang_sync(bb); + req.tv_sec = (cc_reset_us) / 1000000; + req.tv_nsec = ((cc_reset_us) % 1000000) * 1000; + nanosleep(&req, &rem); +} + +struct cc_bitbang * +cc_bitbang_open(void) +{ + struct cc_bitbang *bb; + + bb = calloc(sizeof (struct cc_bitbang), 1); + if (!bb) { + perror("calloc"); + return NULL; + } +#ifdef CP_USB_ASYNC + bb->cp_async = cp_usb_async_open(); + if (!bb->cp_async) { + free (bb); + return NULL; + } +#else + bb->cp = cp_usb_open (); + if (!bb->cp) { + free (bb); + return NULL; + } +#endif + return bb; +} + +void +cc_bitbang_close(struct cc_bitbang *bb) +{ +#ifdef CP_USB_ASYNC + cp_usb_async_close(bb->cp_async); +#else + cp_usb_close(bb->cp); +#endif + free (bb); +} + +void +cc_bitbang_debug_mode(struct cc_bitbang *bb) +{ + /* force two rising clocks while holding RESET_N low */ + ccdbg_debug(CC_DEBUG_COMMAND, "#\n"); + ccdbg_debug(CC_DEBUG_COMMAND, "# Debug mode\n"); + ccdbg_debug(CC_DEBUG_COMMAND, "#\n"); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_DATA ); + cc_bitbang_wait_reset(bb); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_DATA ); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_DATA|CC_RESET_N); + cc_bitbang_wait_reset(bb); +} + +void +cc_bitbang_reset(struct cc_bitbang *bb) +{ + ccdbg_debug(CC_DEBUG_COMMAND, "#\n"); + ccdbg_debug(CC_DEBUG_COMMAND, "# Reset\n"); + ccdbg_debug(CC_DEBUG_COMMAND, "#\n"); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); + cc_bitbang_wait_reset(bb); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); + cc_bitbang_wait_reset(bb); +} + +int +cc_bitbang_write(struct cc_bitbang *bb, uint8_t mask, uint8_t value) +{ +#ifdef CP_USB_ASYNC + cp_usb_async_write(bb->cp_async, mask, value); +#else + cp_usb_write(bb->cp, mask, value); +#endif + return 0; +} + +void +cc_bitbang_read(struct cc_bitbang *bb, uint8_t *valuep) +{ +#ifdef CP_USB_ASYNC + cp_usb_async_read(bb->cp_async, valuep); +#else + *valuep = cp_usb_read(bb->cp); +#endif +} + +void +cc_bitbang_sync(struct cc_bitbang *bb) +{ +#ifdef CP_USB_ASYNC + cp_usb_async_sync(bb->cp_async); +#endif +} + +static char +is_bit(uint8_t get, uint8_t mask, char on, uint8_t bit) +{ + if (mask&bit) { + if (get&bit) + return on; + else + return '.'; + } else + return '-'; +} + +void +cc_bitbang_print(char *format, uint8_t mask, uint8_t set) +{ + ccdbg_debug (CC_DEBUG_BITBANG, format, + is_bit(set, mask, 'C', CC_CLOCK), + is_bit(set, mask, 'D', CC_DATA), + is_bit(set, mask, 'R', CC_RESET_N)); +} + +void +cc_bitbang_send(struct cc_bitbang *bb, uint8_t mask, uint8_t set) +{ + cc_bitbang_write(bb, mask, set); + cc_bitbang_print("%c %c %c\n", mask, set); + cc_bitbang_half_clock(bb); +} + +void +cc_bitbang_send_bit(struct cc_bitbang *bb, uint8_t bit) +{ + if (bit) bit = CC_DATA; + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|bit|CC_RESET_N); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, bit|CC_RESET_N); +} + +void +cc_bitbang_send_byte(struct cc_bitbang *bb, uint8_t byte) +{ + int bit; + ccdbg_debug(CC_DEBUG_BITBANG, "#\n# Send Byte 0x%02x\n#\n", byte); + for (bit = 7; bit >= 0; bit--) { + cc_bitbang_send_bit(bb, (byte >> bit) & 1); + if (bit == 3) + ccdbg_debug(CC_DEBUG_BITBANG, "\n"); + } + cc_bitbang_sync(bb); +} + +void +cc_bitbang_send_bytes(struct cc_bitbang *bb, uint8_t *bytes, int nbytes) +{ + while (nbytes--) + cc_bitbang_send_byte(bb, *bytes++); +} + +void +cc_bitbang_recv_bit(struct cc_bitbang *bb, int first, uint8_t *bit) +{ + uint8_t mask = first ? CC_DATA : 0; + + cc_bitbang_send(bb, CC_CLOCK|mask|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); + cc_bitbang_read(bb, bit); + cc_bitbang_send(bb, CC_CLOCK| CC_RESET_N, CC_RESET_N); +} + +void +cc_bitbang_recv_byte(struct cc_bitbang *bb, int first, uint8_t *bytep) +{ + uint8_t byte = 0; + uint8_t bits[8]; + int bit; + + ccdbg_debug(CC_DEBUG_BITBANG, "#\n# Recv byte\n#\n"); + for (bit = 0; bit < 8; bit++) { + cc_bitbang_recv_bit(bb, first, &bits[bit]); + first = 0; + } + cc_bitbang_sync(bb); + for (bit = 0; bit < 8; bit++) { + byte = byte << 1; + byte |= (bits[bit] & CC_DATA) ? 1 : 0; + cc_bitbang_print("#\t%c %c %c\n", CC_DATA, bits[bit]); + if (bit == 3) + ccdbg_debug(CC_DEBUG_BITBANG, "\n"); + } + ccdbg_debug(CC_DEBUG_BITBANG, "#\n# Recv 0x%02x\n#\n", byte); + *bytep = byte; +} + +void +cc_bitbang_recv_bytes(struct cc_bitbang *bb, uint8_t *bytes, int nbytes) +{ + int i; + int first = 1; + for (i = 0; i < nbytes; i++) { + cc_bitbang_recv_byte(bb, first, &bytes[i]); + first = 0; + } +} + diff --git a/lib/cc-bitbang.h b/lib/cc-bitbang.h new file mode 100644 index 00000000..54b20e2c --- /dev/null +++ b/lib/cc-bitbang.h @@ -0,0 +1,94 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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. + */ + +#ifndef _CC_BITBANG_H_ +#define _CC_BITBANG_H_ + +#include + +#define CC_CLOCK 0x1 +#define CC_DATA 0x2 +#define CC_RESET_N 0x4 +#define CC_CLOCK_US (2) + +/* Telemetrum has a 10k pull-up to 3.3v, a 0.001uF cap to ground + * and a 2.7k resistor to the reset line. This takes about 6us + * to settle, so we'll wait longer than that after changing the reset line + */ +#define CC_RESET_US (12) + +struct cc_bitbang; + +void +cc_bitbang_set_clock(uint32_t us); + +void +cc_bitbang_half_clock(struct cc_bitbang *bb); + +void +cc_bitbang_wait_reset(struct cc_bitbang *bb); + +struct cc_bitbang * +cc_bitbang_open(void); + +void +cc_bitbang_close(struct cc_bitbang *bb); + +void +cc_bitbang_debug_mode(struct cc_bitbang *bb); + +void +cc_bitbang_reset(struct cc_bitbang *bb); + +int +cc_bitbang_write(struct cc_bitbang *bb, uint8_t mask, uint8_t value); + +void +cc_bitbang_read(struct cc_bitbang *bb, uint8_t *valuep); + +void +cc_bitbang_sync(struct cc_bitbang *bb); + +void +cc_bitbang_print(char *format, uint8_t mask, uint8_t set); + +void +cc_bitbang_print(char *format, uint8_t mask, uint8_t set); + +void +cc_bitbang_send(struct cc_bitbang *bb, uint8_t mask, uint8_t set); + +void +cc_bitbang_send_bit(struct cc_bitbang *bb, uint8_t bit); + +void +cc_bitbang_send_byte(struct cc_bitbang *bb, uint8_t byte); + +void +cc_bitbang_send_bytes(struct cc_bitbang *bb, uint8_t *bytes, int nbytes); + +void +cc_bitbang_recv_bit(struct cc_bitbang *bb, int first, uint8_t *bit); + +void +cc_bitbang_recv_byte(struct cc_bitbang *bb, int first, uint8_t *bytep); + +void +cc_bitbang_recv_bytes(struct cc_bitbang *bb, uint8_t *bytes, int nbytes); + +#endif /* _CC_BITBANG_H_ */ diff --git a/lib/cc-usb.c b/lib/cc-usb.c new file mode 100644 index 00000000..a85765af --- /dev/null +++ b/lib/cc-usb.c @@ -0,0 +1,355 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ccdbg-debug.h" +#include "cc-usb.h" + + +#define CC_NUM_READ 16 +#define CC_BUF 1024 +#define DEFAULT_TTY "/dev/ttyACM0" + +struct cc_read { + uint8_t *buf; + int len; +}; + +struct cc_usb { + int fd; + uint8_t in_buf[CC_BUF]; + int in_count; + uint8_t out_buf[CC_BUF]; + int out_count; + struct cc_read read_buf[CC_NUM_READ]; + int read_count; +}; + +#define NOT_HEX 0xff + +static uint8_t +cc_hex_nibble(uint8_t c) +{ + if ('0' <= c && c <= '9') + return c - '0'; + if ('a' <= c && c <= 'f') + return c - 'a' + 10; + if ('A' <= c && c <= 'F') + return c - 'A' + 10; + return NOT_HEX; +} + +/* + * Take raw input bytes, parse them as hex + * and write them to the waiting buffer + */ +static void +cc_handle_in(struct cc_usb *cc) +{ + uint8_t h, l; + int in_pos; + int read_pos; + + in_pos = 0; + read_pos = 0; + while (read_pos < cc->read_count && in_pos < cc->in_count) { + /* + * Skip to next hex character + */ + while (in_pos < cc->in_count && + cc_hex_nibble(cc->in_buf[in_pos]) == NOT_HEX) + in_pos++; + /* + * Make sure we have two characters left + */ + if (cc->in_count - in_pos < 2) + break; + /* + * Parse hex number + */ + h = cc_hex_nibble(cc->in_buf[in_pos]); + l = cc_hex_nibble(cc->in_buf[in_pos+1]); + if (h == NOT_HEX || l == NOT_HEX) { + fprintf(stderr, "hex read error\n"); + break; + } + in_pos += 2; + /* + * Store hex number + */ + *cc->read_buf[read_pos].buf++ = (h << 4) | l; + if (--cc->read_buf[read_pos].len <= 0) + read_pos++; + } + + /* Move remaining bytes to the start of the input buffer */ + if (in_pos) { + memmove(cc->in_buf, cc->in_buf + in_pos, + cc->in_count - in_pos); + cc->in_count -= in_pos; + } + + /* Move pending reads to the start of the array */ + if (read_pos) { + memmove(cc->read_buf, cc->read_buf + read_pos, + (cc->read_count - read_pos) * sizeof (cc->read_buf[0])); + cc->read_count -= read_pos; + } + + /* Once we're done reading, flush any pending input */ + if (cc->read_count == 0) + cc->in_count = 0; +} + +static void +cc_usb_dbg(int indent, uint8_t *bytes, int len) +{ + int eol = 1; + int i; + uint8_t c; + while (len--) { + c = *bytes++; + if (eol) { + for (i = 0; i < indent; i++) + ccdbg_debug(CC_DEBUG_BITBANG, " "); + eol = 0; + } + switch (c) { + case '\r': + ccdbg_debug(CC_DEBUG_BITBANG, "^M"); + break; + case '\n': + eol = 1; + default: + ccdbg_debug(CC_DEBUG_BITBANG, "%c", c); + } + } +} + +/* + * Flush pending writes, fill pending reads + */ +void +cc_usb_sync(struct cc_usb *cc) +{ + int ret; + struct pollfd fds; + int timeout; + + fds.fd = cc->fd; + for (;;) { + if (cc->read_count || cc->out_count) + timeout = -1; + else + timeout = 0; + fds.events = 0; + if (cc->in_count < CC_BUF) + fds.events |= POLLIN; + if (cc->out_count) + fds.events |= POLLOUT; + ret = poll(&fds, 1, timeout); + if (ret == 0) + break; + if (ret < 0) { + perror("poll"); + break; + } + if (fds.revents & POLLIN) { + ret = read(cc->fd, cc->in_buf + cc->in_count, + CC_BUF - cc->in_count); + if (ret > 0) { + cc_usb_dbg(24, cc->in_buf + cc->in_count, ret); + cc->in_count += ret; + cc_handle_in(cc); + } + } + if (fds.revents & POLLOUT) { + ret = write(cc->fd, cc->out_buf, + cc->out_count); + if (ret > 0) { + cc_usb_dbg(0, cc->out_buf, ret); + memmove(cc->out_buf, + cc->out_buf + ret, + cc->out_count - ret); + cc->out_count -= ret; + } + } + } +} + +static void +cc_usb_printf(struct cc_usb *cc, char *format, ...) +{ + char buf[1024], *b; + va_list ap; + int ret, this_time; + + /* sprintf to a local buffer */ + va_start(ap, format); + ret = vsnprintf(buf, sizeof(buf), format, ap); + va_end(ap); + if (ret > sizeof(buf)) { + fprintf(stderr, "printf overflow for format %s\n", + format); + } + + /* flush local buffer to the wire */ + b = buf; + while (ret > 0) { + this_time = ret; + if (this_time > CC_BUF - cc->out_count) + this_time = CC_BUF - cc->out_count; + memcpy(cc->out_buf + cc->out_count, b, this_time); + cc->out_count += this_time; + ret -= this_time; + while (cc->out_count >= CC_BUF) + cc_usb_sync(cc); + } +} + +int +cc_usb_send_bytes(struct cc_usb *cc, uint8_t *bytes, int len) +{ + int this_len; + int ret = len; + + while (len) { + this_len = len; + if (this_len > 8) + this_len = 8; + len -= this_len; + cc_usb_printf(cc, "P"); + while (this_len--) + cc_usb_printf (cc, " %02x", (*bytes++) & 0xff); + cc_usb_printf(cc, "\n"); + } + return ret; +} + +static void +cc_queue_read(struct cc_usb *cc, uint8_t *buf, int len) +{ + struct cc_read *read_buf; + while (cc->read_count >= CC_NUM_READ) + cc_usb_sync(cc); + read_buf = &cc->read_buf[cc->read_count++]; + read_buf->buf = buf; + read_buf->len = len; +} + +int +cc_usb_recv_bytes(struct cc_usb *cc, uint8_t *buf, int len) +{ + cc_queue_read(cc, buf, len); + cc_usb_printf(cc, "G %x\n", len); + return len; +} + +int +cc_usb_write_memory(struct cc_usb *cc, uint16_t addr, uint8_t *bytes, int len) +{ + cc_usb_printf(cc, "O %x %x\n", len, addr); + while (len--) + cc_usb_printf(cc, "%02x", *bytes++); + return 0; +} + +int +cc_usb_read_memory(struct cc_usb *cc, uint16_t addr, uint8_t *bytes, int len) +{ + int i; + cc_queue_read(cc, bytes, len); + cc_usb_printf(cc, "I %x %x\n", len, addr); + cc_usb_sync(cc); + for (i = 0; i < len; i++) { + if ((i & 15) == 0) { + if (i) + ccdbg_debug(CC_DEBUG_MEMORY, "\n"); + ccdbg_debug(CC_DEBUG_MEMORY, "\t%04x", addr + i); + } + ccdbg_debug(CC_DEBUG_MEMORY, " %02x", bytes[i]); + } + ccdbg_debug(CC_DEBUG_MEMORY, "\n"); + return 0; +} + +int +cc_usb_debug_mode(struct cc_usb *cc) +{ + cc_usb_sync(cc); + cc_usb_printf(cc, "D\n"); + return 1; +} + +int +cc_usb_reset(struct cc_usb *cc) +{ + cc_usb_sync(cc); + cc_usb_printf(cc, "R\n"); + return 1; +} + +static struct termios save_termios; + +struct cc_usb * +cc_usb_open(void) +{ + struct cc_usb *cc; + char *tty; + struct termios termios; + + tty = getenv("CCDBG_TTY"); + if (!tty) + tty = DEFAULT_TTY; + cc = calloc (sizeof (struct cc_usb), 1); + if (!cc) + return NULL; + cc->fd = open(tty, O_RDWR | O_NONBLOCK); + if (cc->fd < 0) { + perror(tty); + free (cc); + return NULL; + } + tcgetattr(cc->fd, &termios); + save_termios = termios; + cfmakeraw(&termios); + tcsetattr(cc->fd, TCSAFLUSH, &termios); + cc_usb_printf(cc, "E 0\n"); + cc_usb_sync(cc); + sleep(1); + cc_usb_sync(cc); + return cc; +} + +void +cc_usb_close(struct cc_usb *cc) +{ + tcsetattr(cc->fd, TCSAFLUSH, &save_termios); + close (cc->fd); + free (cc); +} + diff --git a/lib/cc-usb.h b/lib/cc-usb.h new file mode 100644 index 00000000..235e9918 --- /dev/null +++ b/lib/cc-usb.h @@ -0,0 +1,53 @@ +/* + * Copyright © 2009 Keith Packard + * + * 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. + */ + +#ifndef _CC_USB_H_ +#define _CC_USB_H_ + +#include + +struct cc_usb; + +struct cc_usb * +cc_usb_open(void); + +void +cc_usb_close(struct cc_usb *cc); + +int +cc_usb_send_bytes(struct cc_usb *cc, uint8_t *bytes, int len); + +int +cc_usb_recv_bytes(struct cc_usb *cc, uint8_t *bytes, int len); + +int +cc_usb_write_memory(struct cc_usb *cc, uint16_t addr, uint8_t *bytes, int len); + +int +cc_usb_read_memory(struct cc_usb *cc, uint16_t addr, uint8_t *bytes, int len); + +int +cc_usb_debug_mode(struct cc_usb *cc); + +int +cc_usb_reset(struct cc_usb *cc); + +void +cc_usb_sync(struct cc_usb *cc); + +#endif /* _CC_USB_H_ */ diff --git a/lib/ccdbg-command.c b/lib/ccdbg-command.c index 74313bdf..7d1ae067 100644 --- a/lib/ccdbg-command.c +++ b/lib/ccdbg-command.c @@ -18,39 +18,6 @@ #include "ccdbg.h" -void -ccdbg_debug_mode(struct ccdbg *dbg) -{ - /* force two rising clocks while holding RESET_N low */ - ccdbg_debug(CC_DEBUG_COMMAND, "#\n"); - ccdbg_debug(CC_DEBUG_COMMAND, "# Debug mode\n"); - ccdbg_debug(CC_DEBUG_COMMAND, "#\n"); - ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); - ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_DATA ); - ccdbg_wait_reset(dbg); - ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); - ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_DATA ); - ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); - ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_DATA|CC_RESET_N); - ccdbg_wait_reset(dbg); -} - -void -ccdbg_reset(struct ccdbg *dbg) -{ - ccdbg_debug(CC_DEBUG_COMMAND, "#\n"); - ccdbg_debug(CC_DEBUG_COMMAND, "# Reset\n"); - ccdbg_debug(CC_DEBUG_COMMAND, "#\n"); - ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); - ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); - ccdbg_wait_reset(dbg); - ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); - ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); - ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); - ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); - ccdbg_wait_reset(dbg); -} - uint8_t ccdbg_chip_erase(struct ccdbg *dbg) { @@ -117,6 +84,22 @@ ccdbg_debug_instr(struct ccdbg *dbg, uint8_t *instr, int nbytes) return ccdbg_cmd_write_read8(dbg, CC_DEBUG_INSTR(nbytes), instr, nbytes); } +void +ccdbg_debug_instr_discard(struct ccdbg *dbg, uint8_t *instr, int nbytes) +{ + static uint8_t discard; + ccdbg_cmd_write_queue8(dbg, CC_DEBUG_INSTR(nbytes), + instr, nbytes, &discard); +} + +void +ccdbg_debug_instr_queue(struct ccdbg *dbg, uint8_t *instr, int nbytes, + uint8_t *reply) +{ + return ccdbg_cmd_write_queue8(dbg, CC_DEBUG_INSTR(nbytes), + instr, nbytes, reply); +} + uint8_t ccdbg_step_instr(struct ccdbg *dbg) { @@ -148,12 +131,13 @@ ccdbg_execute(struct ccdbg *dbg, uint8_t *inst) ccdbg_debug(CC_DEBUG_INSTRUCTIONS, "\t%02x", inst[1]); for (i = 0; i < len - 1; i++) ccdbg_debug(CC_DEBUG_INSTRUCTIONS, " %02x", inst[i+2]); - status = ccdbg_debug_instr(dbg, inst+1, len); + ccdbg_debug_instr_queue(dbg, inst+1, len, &status); for (; i < 3; i++) ccdbg_debug(CC_DEBUG_INSTRUCTIONS, " "); ccdbg_debug(CC_DEBUG_INSTRUCTIONS, " -> %02x\n", status); inst += len + 1; } + ccdbg_sync(dbg); return status; } diff --git a/lib/ccdbg-debug.c b/lib/ccdbg-debug.c index 847361c7..6eb4e0c5 100644 --- a/lib/ccdbg-debug.c +++ b/lib/ccdbg-debug.c @@ -34,11 +34,20 @@ ccdbg_clear_debug(int level) ccdbg_level &= ~level; } +static int initialized; + void ccdbg_debug(int level, char *format, ...) { va_list ap; + if (!initialized) { + char *level; + initialized = 1; + level = getenv("CCDEBUG"); + if (level) + ccdbg_level |= strtoul(level, NULL, 0); + } if (ccdbg_level & level) { va_start(ap, format); vprintf(format, ap); diff --git a/lib/ccdbg-io.c b/lib/ccdbg-io.c index 3606c57c..acd44f10 100644 --- a/lib/ccdbg-io.c +++ b/lib/ccdbg-io.c @@ -18,41 +18,10 @@ #include "ccdbg.h" #include -#ifdef CP_USB_ASYNC -#include "cp-usb-async.h" -#else -#include "cp-usb.h" -#endif +#include "cc-usb.h" +#include "cc-bitbang.h" -static uint32_t cc_clock_us = CC_CLOCK_US; -static uint32_t cc_reset_us = CC_RESET_US; -void -ccdbg_set_clock(uint32_t us) -{ - cc_clock_us = us; -} - -void -ccdbg_half_clock(struct ccdbg *dbg) -{ - struct timespec req, rem; - req.tv_sec = (cc_clock_us / 2) / 1000000; - req.tv_nsec = ((cc_clock_us / 2) % 1000000) * 1000; - nanosleep(&req, &rem); -} - -void -ccdbg_wait_reset(struct ccdbg *dbg) -{ - struct timespec req, rem; - - ccdbg_sync_io(dbg); - req.tv_sec = (cc_reset_us) / 1000000; - req.tv_nsec = ((cc_reset_us) % 1000000) * 1000; - nanosleep(&req, &rem); -} - struct ccdbg * ccdbg_open(void) { @@ -63,170 +32,77 @@ ccdbg_open(void) perror("calloc"); return NULL; } -#ifdef CP_USB_ASYNC - dbg->cp_async = cp_usb_async_open(); - if (!dbg->cp_async) { - free (dbg); - return NULL; - } -#else - dbg->cp = cp_usb_open (); - if (!dbg->cp) { - free (dbg); - return NULL; + dbg->usb = cc_usb_open(); + if (!dbg->usb) { + dbg->bb = cc_bitbang_open(); + if (!dbg->bb) { + free(dbg); + return NULL; + } } -#endif return dbg; } void ccdbg_close(struct ccdbg *dbg) { -#ifdef CP_USB_ASYNC - cp_usb_async_close(dbg->cp_async); -#else - cp_usb_close(dbg->cp); -#endif + if (dbg->usb) + cc_usb_close(dbg->usb); + if (dbg->bb) + cc_bitbang_close(dbg->bb); free (dbg); } -int -ccdbg_write(struct ccdbg *dbg, uint8_t mask, uint8_t value) -{ -#ifdef CP_USB_ASYNC - cp_usb_async_write(dbg->cp_async, mask, value); -#else - cp_usb_write(dbg->cp, mask, value); -#endif - return 0; -} - -void -ccdbg_read(struct ccdbg *dbg, uint8_t *valuep) -{ -#ifdef CP_USB_ASYNC - cp_usb_async_read(dbg->cp_async, valuep); -#else - *valuep = cp_usb_read(dbg->cp); -#endif -} - -void -ccdbg_sync_io(struct ccdbg *dbg) -{ -#ifdef CP_USB_ASYNC - cp_usb_async_sync(dbg->cp_async); -#endif -} - -static char -is_bit(uint8_t get, uint8_t mask, char on, uint8_t bit) -{ - if (mask&bit) { - if (get&bit) - return on; - else - return '.'; - } else - return '-'; -} -void -ccdbg_print(char *format, uint8_t mask, uint8_t set) -{ - ccdbg_debug (CC_DEBUG_BITBANG, format, - is_bit(set, mask, 'C', CC_CLOCK), - is_bit(set, mask, 'D', CC_DATA), - is_bit(set, mask, 'R', CC_RESET_N)); -} - void -ccdbg_send(struct ccdbg *dbg, uint8_t mask, uint8_t set) +ccdbg_debug_mode(struct ccdbg *dbg) { - ccdbg_write(dbg, mask, set); - ccdbg_print("%c %c %c\n", mask, set); - ccdbg_half_clock(dbg); + if (dbg->usb) + cc_usb_debug_mode(dbg->usb); + else if (dbg->bb) + cc_bitbang_debug_mode(dbg->bb); } void -ccdbg_send_bit(struct ccdbg *dbg, uint8_t bit) +ccdbg_reset(struct ccdbg *dbg) { - if (bit) bit = CC_DATA; - ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|bit|CC_RESET_N); - ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, bit|CC_RESET_N); -} - -void -ccdbg_send_byte(struct ccdbg *dbg, uint8_t byte) -{ - int bit; - ccdbg_debug(CC_DEBUG_BITBANG, "#\n# Send Byte 0x%02x\n#\n", byte); - for (bit = 7; bit >= 0; bit--) { - ccdbg_send_bit(dbg, (byte >> bit) & 1); - if (bit == 3) - ccdbg_debug(CC_DEBUG_BITBANG, "\n"); - } - ccdbg_sync_io(dbg); + if (dbg->usb) + cc_usb_reset(dbg->usb); + else if (dbg->bb) + cc_bitbang_reset(dbg->bb); } void ccdbg_send_bytes(struct ccdbg *dbg, uint8_t *bytes, int nbytes) { - while (nbytes--) - ccdbg_send_byte(dbg, *bytes++); -} - -void -ccdbg_recv_bit(struct ccdbg *dbg, int first, uint8_t *bit) -{ - uint8_t mask = first ? CC_DATA : 0; - - ccdbg_send(dbg, CC_CLOCK|mask|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); - ccdbg_read(dbg, bit); - ccdbg_send(dbg, CC_CLOCK| CC_RESET_N, CC_RESET_N); + if (dbg->usb) + cc_usb_send_bytes(dbg->usb, bytes, nbytes); + else if (dbg->bb) + cc_bitbang_send_bytes(dbg->bb, bytes, nbytes); } void -ccdbg_recv_byte(struct ccdbg *dbg, int first, uint8_t *bytep) +ccdbg_recv_bytes(struct ccdbg *dbg, uint8_t *bytes, int nbytes) { - uint8_t byte = 0; - uint8_t bits[8]; - int bit; - - ccdbg_debug(CC_DEBUG_BITBANG, "#\n# Recv byte\n#\n"); - for (bit = 0; bit < 8; bit++) { - ccdbg_recv_bit(dbg, first, &bits[bit]); - first = 0; - } - ccdbg_sync_io(dbg); - for (bit = 0; bit < 8; bit++) { - byte = byte << 1; - byte |= (bits[bit] & CC_DATA) ? 1 : 0; - ccdbg_print("#\t%c %c %c\n", CC_DATA, bits[bit]); - if (bit == 3) - ccdbg_debug(CC_DEBUG_BITBANG, "\n"); - } - ccdbg_debug(CC_DEBUG_BITBANG, "#\n# Recv 0x%02x\n#\n", byte); - *bytep = byte; + if (dbg->usb) + cc_usb_recv_bytes(dbg->usb, bytes, nbytes); + else if (dbg->bb) + cc_bitbang_recv_bytes(dbg->bb, bytes, nbytes); } void -ccdbg_recv_bytes(struct ccdbg *dbg, uint8_t *bytes, int nbytes) +ccdbg_sync(struct ccdbg *dbg) { - int i; - int first = 1; - for (i = 0; i < nbytes; i++) { - ccdbg_recv_byte(dbg, first, &bytes[i]); - first = 0; - } + if (dbg->usb) + cc_usb_sync(dbg->usb); + else if (dbg->bb) + cc_bitbang_sync(dbg->bb); } void ccdbg_cmd_write(struct ccdbg *dbg, uint8_t cmd, uint8_t *data, int len) { - int i; - ccdbg_send_byte(dbg, cmd); - for (i = 0; i < len; i++) - ccdbg_send_byte(dbg, data[i]); + ccdbg_send_bytes(dbg, &cmd, 1); + ccdbg_send_bytes(dbg, data, len); } uint8_t @@ -235,6 +111,7 @@ ccdbg_cmd_write_read8(struct ccdbg *dbg, uint8_t cmd, uint8_t *data, int len) uint8_t byte[1]; ccdbg_cmd_write(dbg, cmd, data, len); ccdbg_recv_bytes(dbg, byte, 1); + ccdbg_sync(dbg); return byte[0]; } @@ -244,5 +121,15 @@ ccdbg_cmd_write_read16(struct ccdbg *dbg, uint8_t cmd, uint8_t *data, int len) uint8_t byte[2]; ccdbg_cmd_write(dbg, cmd, data, len); ccdbg_recv_bytes(dbg, byte, 2); + ccdbg_sync(dbg); return (byte[0] << 8) | byte[1]; } + +void +ccdbg_cmd_write_queue8(struct ccdbg *dbg, uint8_t cmd, + uint8_t *data, int len, + uint8_t *reply) +{ + ccdbg_cmd_write(dbg, cmd, data, len); + ccdbg_recv_bytes(dbg, reply, 1); +} diff --git a/lib/ccdbg-manual.c b/lib/ccdbg-manual.c index df79d88d..0e811b76 100644 --- a/lib/ccdbg-manual.c +++ b/lib/ccdbg-manual.c @@ -17,6 +17,7 @@ */ #include "ccdbg.h" +#include "cc-bitbang.h" /* * Manual bit-banging to debug the low level protocol @@ -47,6 +48,10 @@ ccdbg_manual(struct ccdbg *dbg, FILE *input) char line[80]; uint8_t set, mask; + if (dbg->bb == NULL) { + fprintf(stderr, "Must use bitbang API for manual mode\n"); + return; + } while (fgets(line, sizeof line, input)) { if (line[0] == '#' || line[0] == '\n') { printf ("%s", line); @@ -59,14 +64,14 @@ ccdbg_manual(struct ccdbg *dbg, FILE *input) get_bit(line, 4, 'R', CC_RESET_N, &set, &mask); if (mask != (CC_CLOCK|CC_DATA|CC_RESET_N)) { uint8_t read; - ccdbg_read(dbg, &read); - ccdbg_sync_io(dbg); - ccdbg_print("\t%c %c %c", CC_CLOCK|CC_DATA|CC_RESET_N, read); + cc_bitbang_read(dbg->bb, &read); + cc_bitbang_sync(dbg->bb); + cc_bitbang_print("\t%c %c %c", CC_CLOCK|CC_DATA|CC_RESET_N, read); if ((set & CC_CLOCK) == 0) printf ("\t%d", (read&CC_DATA) ? 1 : 0); printf ("\n"); } - ccdbg_send(dbg, mask, set); - ccdbg_sync_io(dbg); + cc_bitbang_send(dbg->bb, mask, set); + cc_bitbang_sync(dbg->bb); } } diff --git a/lib/ccdbg-memory.c b/lib/ccdbg-memory.c index 20a24799..878c5f97 100644 --- a/lib/ccdbg-memory.c +++ b/lib/ccdbg-memory.c @@ -50,6 +50,8 @@ ccdbg_write_memory(struct ccdbg *dbg, uint16_t addr, uint8_t *bytes, int nbytes) int i, nl = 0; struct ccstate state; + if (dbg->usb) + return cc_usb_write_memory(dbg->usb, addr, bytes, nbytes); ccdbg_state_save(dbg, &state, CC_STATE_ACC | CC_STATE_PSW | CC_STATE_DP); memory_init[HIGH_START] = addr >> 8; memory_init[LOW_START] = addr; @@ -83,6 +85,8 @@ ccdbg_read_memory(struct ccdbg *dbg, uint16_t addr, uint8_t *bytes, int nbytes) ccdbg_rom_replace_xmem(dbg, addr, bytes, nbytes); return 0; } + if (dbg->usb) + return cc_usb_read_memory(dbg->usb, addr, bytes, nbytes); ccdbg_state_save(dbg, &state, CC_STATE_ACC | CC_STATE_PSW | CC_STATE_DP); memory_init[HIGH_START] = addr >> 8; memory_init[LOW_START] = addr; diff --git a/lib/ccdbg.h b/lib/ccdbg.h index e0e12c8b..fe0ea3a0 100644 --- a/lib/ccdbg.h +++ b/lib/ccdbg.h @@ -31,17 +31,8 @@ #include #include #include "ccdbg-debug.h" - -#define CC_CLOCK 0x1 -#define CC_DATA 0x2 -#define CC_RESET_N 0x4 -#define CC_CLOCK_US (2) - -/* Telemetrum has a 10k pull-up to 3.3v, a 0.001uF cap to ground - * and a 2.7k resistor to the reset line. This takes about 6us - * to settle, so we'll wait longer than that after changing the reset line - */ -#define CC_RESET_US (12) +#include "cc-bitbang.h" +#include "cc-usb.h" /* 8051 instructions */ @@ -109,15 +100,10 @@ /* Bit-addressable status word */ #define PSW(bit) (0xD0 | (bit)) -#define CP_USB_ASYNC - struct ccdbg { -#ifdef CP_USB_ASYNC - struct cp_usb_async *cp_async; -#else - struct cp_usb *cp; -#endif - struct hex_image *rom; + struct cc_bitbang *bb; + struct cc_usb *usb; + struct hex_image *rom; }; /* Intel hex file format data @@ -225,6 +211,13 @@ ccdbg_resume(struct ccdbg *dbg); uint8_t ccdbg_debug_instr(struct ccdbg *dbg, uint8_t *instr, int nbytes); +void +ccdbg_debug_instr_discard(struct ccdbg *dbg, uint8_t *instr, int nbytes); + +void +ccdbg_debug_instr_queue(struct ccdbg *dbg, uint8_t *instr, int nbytes, + uint8_t *reply); + uint8_t ccdbg_step_instr(struct ccdbg *dbg); @@ -264,80 +257,33 @@ int ccdbg_hex_image_equal(struct hex_image *a, struct hex_image *b); /* ccdbg-io.c */ -void -ccdbg_set_clock(uint32_t us); - -void -ccdbg_half_clock(struct ccdbg *dbg); - -void -ccdbg_wait_reset(struct ccdbg *dbg); - -int -ccdbg_write(struct ccdbg *dbg, uint8_t mask, uint8_t value); - -void -ccdbg_read(struct ccdbg *dbg, uint8_t *valuep); - struct ccdbg * ccdbg_open(void); void ccdbg_close(struct ccdbg *dbg); -void -ccdbg_clock_1_0(struct ccdbg *dbg); - -void -ccdbg_clock_0_1(struct ccdbg *dbg); - -void -ccdbg_write_bit(struct ccdbg *dbg, uint8_t bit); - -void -ccdbg_write_byte(struct ccdbg *dbg, uint8_t byte); - -uint8_t -ccdbg_read_bit(struct ccdbg *dbg); - -uint8_t -ccdbg_read_byte(struct ccdbg *dbg); - void ccdbg_cmd_write(struct ccdbg *dbg, uint8_t cmd, uint8_t *data, int len); uint8_t ccdbg_cmd_write_read8(struct ccdbg *dbg, uint8_t cmd, uint8_t *data, int len); -uint16_t -ccdbg_cmd_write_read16(struct ccdbg *dbg, uint8_t cmd, uint8_t *data, int len); - void -ccdbg_send(struct ccdbg *dbg, uint8_t mask, uint8_t set); +ccdbg_cmd_write_queue8(struct ccdbg *dbg, uint8_t cmd, + uint8_t *data, int len, uint8_t *reply); -void -ccdbg_send_bit(struct ccdbg *dbg, uint8_t bit); - -void -ccdbg_send_byte(struct ccdbg *dbg, uint8_t byte); +uint16_t +ccdbg_cmd_write_read16(struct ccdbg *dbg, uint8_t cmd, uint8_t *data, int len); void ccdbg_send_bytes(struct ccdbg *dbg, uint8_t *bytes, int nbytes); -void -ccdbg_recv_bit(struct ccdbg *dbg, int first, uint8_t *bit); - -void -ccdbg_recv_byte(struct ccdbg *dbg, int first, uint8_t *byte); - void ccdbg_recv_bytes(struct ccdbg *dbg, uint8_t *bytes, int nbytes); void -ccdbg_sync_io(struct ccdbg *dbg); - -void -ccdbg_print(char *format, uint8_t mask, uint8_t set); +ccdbg_sync(struct ccdbg *dbg); /* ccdbg-manual.c */ diff --git a/lib/cp-usb.c b/lib/cp-usb.c index 6ab9092c..d227b78c 100644 --- a/lib/cp-usb.c +++ b/lib/cp-usb.c @@ -25,6 +25,7 @@ #include "cp-usb.h" #include #include +#include struct cp_usb { usb_dev_handle *usb_dev; -- cgit v1.2.3