Merge ccdbg and altos sources into one giant repository
authorKeith Packard <keithp@keithp.com>
Thu, 4 Jun 2009 18:13:15 +0000 (11:13 -0700)
committerKeith Packard <keithp@keithp.com>
Thu, 4 Jun 2009 18:13:15 +0000 (11:13 -0700)
Keeping these separate isn't making things any easier.

Signed-off-by: Keith Packard <keithp@keithp.com>
35 files changed:
1  2 
.gitignore
INSTALL
Makefile.am
aoload/aoload.c
aoview/Makefile.am
ccload/ccload.c
ccmanual/ccmanual.c
configure.ac
lib/cc-bitbang.c
lib/cc-usb.c
lib/ccdbg-command.c
lib/ccdbg-flash.c
lib/ccdbg-hex.c
lib/ccdbg-memory.c
lib/ccdbg-rom.c
lib/ccdbg.h
lib/cp-usb-async.c
lib/cp-usb.c
s51/commands
s51/s51-command.c
s51/s51-main.c
s51/s51-parse.c
s51/s51.1
target/adc-serial/adc_serial.c
target/adc/adc.c
target/beep-timer/beep_timer.c
target/dma/dma.c
target/ee/ee.c
target/isr.c
target/radio/init.c
target/radio/recv.c
target/serial/serial.c
target/timer/cc1111.h
tests/debug_mode
tests/get_status

diff --cc .gitignore
@@@ -1,32 -1,20 +1,44 @@@
 -*.o
+ *.a
 +*.adb
 +*.asm
- *.lst
- *.ihx
- *.rel
- *.sym
- *.rst
 +*.cdb
++*.ihx
 +*.lnk
++*.lst
 +*.map
 +*.mem
- telemetrum
- teleterra
- tidongle
- teledongle
++*.o
++*.rel
++*.rst
++*.sym
+ .deps
 -tags
 -Makefile
 -Makefile.in
+ aclocal.m4
 +ao_flight_test
++ao-teledongle.h
 +ao-telemetrum.h
 +ao-teleterra.h
- ao-teledongle.h
 +ao-tidongle.h
- Makefile.in
- aclocal.m4
- .deps
++aoload/aoload
++ccdump/ccdump
++ccmanual/ccmanual
++aoview/Makefile
++aoview/aoview
  autom4te.cache
 +config.*
+ config.h
+ config.h.in
+ config.h.in~
+ config.log
+ config.status
+ configure
  depcomp
  install-sh
++Makefile
+ Makefile.in
  missing
  stamp-h1
- configure
- Makefile
- aoview/Makefile
 -
++tags
++teledongle
++telemetrum
++teleterra
++tidongle
diff --cc INSTALL
+++ b/INSTALL
@@@ -276,15 -232,6 +232,5 @@@ an Autoconf bug.  Until the bug is fixe
       Look for the package's source code in directory DIR.  Usually
       `configure' can determine that directory automatically.
  
- `--prefix=DIR'
-      Use DIR as the installation prefix.  *Note Installation Names::
-      for more details, including other options available for fine-tuning
-      the installation locations.
- `--no-create'
- `-n'
-      Run the configure checks, but stop before creating any output
-      files.
  `configure' also accepts some other, not widely useful, options.  Run
  `configure --help' for more details.
 -
diff --cc Makefile.am
@@@ -1,1 -1,1 +1,1 @@@
- SUBDIRS=src aoview
 -SUBDIRS=lib ccload s51 ccmanual ccdump aoload
++SUBDIRS=src aoview lib ccload s51 ccmanual ccdump aoload
diff --cc aoload/aoload.c
index 0000000,a36ad37..b84a88a
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,231 +1,231 @@@
 -      
+ /*
+  * Copyright © 2008 Keith Packard <keithp@keithp.com>
+  *
+  * 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 <stdlib.h>
+ #include <limits.h>
+ #include <stdint.h>
+ #include "ccdbg.h"
+ #define AO_USB_DESC_STRING            3
+ void
+ usage(char *program)
+ {
+       fprintf(stderr, "usage: %s <filename.ihx> <serial>\n", program);
+       exit(1);
+ }
+ struct sym {
+       unsigned        addr;
+       char            *name;
+ } serial_symbols[] = {
+       { 0,    "_ao_serial_number" },
+ #define AO_SERIAL_NUMBER      (serial_symbols[0].addr)
+       { 0,    "_ao_usb_descriptors" },
+ #define AO_USB_DESCRIPTORS    (serial_symbols[1].addr)
+ };
+ #define NUM_SERIAL_SYMBOLS    (sizeof(serial_symbols)/sizeof(serial_symbols[0]))
+ static int
+ find_symbols(FILE *map)
+ {
+       char    line[2048];
+       char    *addr, *addr_end;
+       char    *name;
+       char    *save;
+       char    *colon;
+       unsigned long   a;
+       int     s;
+       int     found = 0;
+       while (fgets(line, sizeof(line), map) != NULL) {
+               line[sizeof(line)-1] = '\0';
+               addr = strtok_r(line, " \t\n", &save);
+               if (!addr)
+                       continue;
+               name = strtok_r(NULL, " \t\n", &save);
+               if (!name)
+                       continue;
+               colon = strchr (addr, ':');
+               if (!colon)
+                       continue;
+               a = strtoul(colon+1, &addr_end, 16);
+               if (a == ULONG_MAX || addr_end == addr)
+                       continue;
+               for (s = 0; s < NUM_SERIAL_SYMBOLS; s++)
+                       if (!strcmp(serial_symbols[s].name, name)) {
+                               serial_symbols[s].addr = (unsigned) a;
+                               ++found;
+                               break;
+                       }
+       }
+       return found == NUM_SERIAL_SYMBOLS;
+ }
+ static int
+ rewrite(struct hex_image *image, unsigned addr, char *data, int len)
+ {
+       int i;
+       if (addr < image->address || image->address + image->length < addr + len)
+               return 0;
+       printf("rewrite %04x:", addr);
+       for (i = 0; i < len; i++)
+               printf (" %02x", image->data[addr - image->address + i]);
+       printf(" ->");
+       for (i = 0; i < len; i++)
+               printf (" %02x", data[i]);
+       printf("\n");
+       memcpy(image->data + addr - image->address, data, len);
+ }
+ int
+ main (int argc, char **argv)
+ {
+       struct ccdbg    *dbg;
+       uint8_t         status;
+       uint16_t        pc;
+       struct hex_file *hex;
+       struct hex_image *image;
+       char *filename;
+       FILE *file;
+       FILE *map;
+       char *serial_string;
+       unsigned int serial;
+       char *mapname, *dot;
+       char            *serial_ucs2;
+       int             serial_ucs2_len;
+       char            serial_int[2];
+       unsigned int    s;
+       int             i;
+       unsigned        usb_descriptors;
+       int             string_num;
+       filename = argv[1];
+       if (filename == NULL)
+               usage(argv[0]);
+       mapname = strdup(filename);
+       dot = strrchr(mapname, '.');
+       if (!dot || strcmp(dot, ".ihx") != 0)
+               usage(argv[0]);
+       strcpy(dot, ".map");
+       serial_string = argv[2];
+       if (serial_string == NULL)
+               usage(argv[0]);
 -      
++
+       file = fopen(filename, "r");
+       if (!file) {
+               perror(filename);
+               exit(1);
+       }
+       map = fopen(mapname, "r");
+       if (!map) {
+               perror(mapname);
+               exit(1);
+       }
+       if (!find_symbols(map)) {
+               fprintf(stderr, "Cannot find symbols in \"%s\"\n", mapname);
+               exit(1);
+       }
+       fclose(map);
+       hex = ccdbg_hex_file_read(file, filename);
+       fclose(file);
+       if (!hex) {
+               perror(filename);
+               exit (1);
+       }
+       image = ccdbg_hex_image_create(hex);
+       if (!image) {
+               fprintf(stderr, "image create failed\n");
+               exit (1);
+       }
+       ccdbg_hex_file_free(hex);
+       serial = strtoul(serial_string, NULL, 0);
+       if (!serial)
+               usage(argv[0]);
+       serial_int[0] = serial & 0xff;
+       serial_int[1] = (serial >> 8) & 0xff;
+       if (!rewrite(image, AO_SERIAL_NUMBER, serial_int, sizeof (serial_int))) {
+               fprintf(stderr, "Cannot rewrite serial integer at %04x\n",
+                       AO_SERIAL_NUMBER);
+               exit(1);
+       }
 -              
++
+       usb_descriptors = AO_USB_DESCRIPTORS - image->address;
+       string_num = 0;
+       while (image->data[usb_descriptors] != 0 && usb_descriptors < image->length) {
+               if (image->data[usb_descriptors+1] == AO_USB_DESC_STRING) {
+                       ++string_num;
+                       if (string_num == 4)
+                               break;
+               }
+               usb_descriptors += image->data[usb_descriptors];
+       }
+       if (usb_descriptors >= image->length || image->data[usb_descriptors] == 0 ) {
+               fprintf(stderr, "Cannot rewrite serial string at %04x\n", AO_USB_DESCRIPTORS);
+               exit(1);
+       }
 -      
++
+       serial_ucs2_len = image->data[usb_descriptors] - 2;
+       serial_ucs2 = malloc(serial_ucs2_len);
+       if (!serial_ucs2) {
+               fprintf(stderr, "Malloc(%d) failed\n", serial_ucs2_len);
+               exit(1);
+       }
+       s = serial;
+       for (i = serial_ucs2_len / 2; i; i--) {
+               serial_ucs2[i * 2 - 1] = 0;
+               serial_ucs2[i * 2 - 2] = (s % 10) + '0';
+               s /= 10;
+       }
+       if (!rewrite(image, usb_descriptors + 2 + image->address, serial_ucs2, serial_ucs2_len))
+               usage(argv[0]);
 -      
++
+       dbg = ccdbg_open();
+       if (!dbg)
+               exit (1);
++
+       ccdbg_add_debug(CC_DEBUG_FLASH);
+       ccdbg_debug_mode(dbg);
+       ccdbg_halt(dbg);
+       if (image->address == 0xf000) {
+               printf("Loading %d bytes to execute from RAM\n",
+                      image->length);
+               ccdbg_write_hex_image(dbg, image, 0);
+       } else if (image->address == 0x0000) {
+               printf("Loading %d bytes to execute from FLASH\n",
+                      image->length);
+               ccdbg_flash_hex_image(dbg, image);
+       } else {
+               printf("Cannot load code to 0x%04x\n",
+                      image->address);
+               ccdbg_hex_image_free(image);
+               ccdbg_close(dbg);
+               exit(1);
+       }
+       ccdbg_set_pc(dbg, image->address);
+       ccdbg_resume(dbg);
+       ccdbg_close(dbg);
+       exit (0);
+ }
index 9f67ac4,0000000..be3fbac
mode 100644,000000..100644
--- /dev/null
@@@ -1,28 -1,0 +1,28 @@@
- AM_CFLAGS=$(AOVIEW_CFLAGS) -I$(top_srcdir)/src -DAOVIEW_VERSION=\"$(VERSION)\"
 +VERSION=$(shell git describe)
- aoview_LDADD=$(AOVIEW_LIBS)
++AM_CFLAGS=$(GNOME_CFLAGS) -I$(top_srcdir)/src -DAOVIEW_VERSION=\"$(VERSION)\"
 +
 +bin_PROGRAMS=aoview
 +
++aoview_LDADD=$(GNOME_LIBS)
 +
 +aoview_SOURCES = \
 +      aoview_main.c \
 +      aoview_dev.c \
 +      aoview_dev_dialog.c \
 +      aoview_serial.c \
 +      aoview_monitor.c \
 +      aoview_state.c \
 +      aoview_convert.c \
 +      aoview_log.c \
 +      aoview_table.c \
 +      aoview_util.c \
 +      aoview_file.c \
 +      aoview_eeprom.c \
 +      aoview.h
 +
 +BUILT_SOURCES = aoview_glade.h
 +
 +CLEANFILES = aoview_glade.h
 +
 +aoview_glade.h: aoview.glade
 +      sed -e 's/"/\\"/g' -e 's/^/"/' -e 's/$$/"/' $< > $@
diff --cc ccload/ccload.c
index 0000000,3e22091..5f7708f
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,80 +1,80 @@@
 -      
+ /*
+  * Copyright © 2008 Keith Packard <keithp@keithp.com>
+  *
+  * 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"
+ int
+ main (int argc, char **argv)
+ {
+       struct ccdbg    *dbg;
+       uint8_t         status;
+       uint16_t        pc;
+       struct hex_file *hex;
+       struct hex_image *image;
+       char *filename;
+       FILE *file;
+       filename = argv[1];
+       if (filename == NULL) {
+               fprintf(stderr, "usage: %s <filename.ihx>\n", argv[0]);
+               exit(1);
+       }
+       file = fopen(filename, "r");
+       if (!file) {
+               perror(filename);
+               exit(1);
+       }
+       hex = ccdbg_hex_file_read(file, filename);
+       fclose(file);
+       if (!hex)
+               exit (1);
+       image = ccdbg_hex_image_create(hex);
+       if (!image) {
+               fprintf(stderr, "image create failed\n");
+               exit (1);
+       }
 -      
++
+       ccdbg_hex_file_free(hex);
+       dbg = ccdbg_open();
+       if (!dbg)
+               exit (1);
++
+       ccdbg_add_debug(CC_DEBUG_FLASH);
+       ccdbg_debug_mode(dbg);
+       ccdbg_halt(dbg);
+       if (image->address == 0xf000) {
+               printf("Loading %d bytes to execute from RAM\n",
+                      image->length);
+               ccdbg_write_hex_image(dbg, image, 0);
+       } else if (image->address == 0x0000) {
+               printf("Loading %d bytes to execute from FLASH\n",
+                      image->length);
+               ccdbg_flash_hex_image(dbg, image);
+       } else {
+               printf("Cannot load code to 0x%04x\n",
+                      image->address);
+               ccdbg_hex_image_free(image);
+               ccdbg_close(dbg);
+               exit(1);
+       }
+       ccdbg_set_pc(dbg, image->address);
+       ccdbg_resume(dbg);
+       ccdbg_close(dbg);
+       exit (0);
+ }
index 0000000,402d9b1..7090c9a
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,33 +1,33 @@@
 -      
+ /*
+  * Copyright © 2009 Keith Packard <keithp@keithp.com>
+  *
+  * 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"
+ int
+ main (int argc, char **argv)
+ {
+       struct ccdbg    *dbg;
+       dbg = ccdbg_open();
+       if (!dbg)
+               exit (1);
++
+       ccdbg_add_debug(CC_DEBUG_BITBANG);
+       ccdbg_manual(dbg, stdin);
+ }
diff --cc configure.ac
@@@ -1,6 -1,6 +1,6 @@@
 -dnl 
 -dnl  Copyright © 2008 Keith Packard <keithp@keithp.com>
 -dnl 
 +dnl
- dnl  Copyright © 2008 Keith Packard <keithp@keithp.com>
++dnl  Copyright © 2008,2009 Keith Packard <keithp@keithp.com>
 +dnl
  dnl  This program is free software; you can redistribute it and/or modify
  dnl  it under the terms of the GNU General Public License as published by
  dnl  the Free Software Foundation; either version 2 of the License, or
@@@ -17,9 -17,9 +17,9 @@@ dnl  59 Temple Place, Suite 330, Boston
  dnl
  dnl Process this file with autoconf to create configure.
  
- AC_INIT(aoview)
+ AC_INIT(COPYING)
  
- AM_INIT_AUTOMAKE(aoview, 0.1)
 -AM_INIT_AUTOMAKE(cctools, 0.1)
++AM_INIT_AUTOMAKE(altos, 0.1)
  AM_MAINTAINER_MODE
  
  dnl ==========================================================================
@@@ -43,16 -43,61 +43,17 @@@ if test "x$GCC" = "xyes"; the
  fi
  AC_SUBST(WARN_CFLAGS)
  
--dnl ==========================================================================
--
--AM_CONDITIONAL(CROSS_COMPILING, test $cross_compiling = yes)
--
--dnl ==========================================================================
--
 -# Setup for compiling build tools (fc-glyphname, etc)
 -AC_MSG_CHECKING([for a C compiler for build tools])
 -if test $cross_compiling = yes; then
 -  AC_CHECK_PROGS(CC_FOR_BUILD, gcc cc)
 -else
 -  CC_FOR_BUILD=$CC
 -fi
 -AC_MSG_RESULT([$CC_FOR_BUILD])
 -AC_SUBST(CC_FOR_BUILD)
++PKG_CHECK_MODULES([GNOME], [gtk+-2.0 libglade-2.0 gconf-2.0])
  
- PKG_CHECK_MODULES([AOVIEW], [gtk+-2.0 libglade-2.0 gconf-2.0])
+ 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
 -int
 -main ()
 -{
 -  exit (0);
 -}
 -_______EOF
 -  for i in .exe ""; do
 -    compile="$CC_FOR_BUILD conftest.c -o conftest$i"
 -    if AC_TRY_EVAL(compile); then
 -      if (./conftest) 2>&AC_FD_CC; then
 -      EXEEXT_FOR_BUILD=$i
 -      break
 -      fi
 -    fi
 -  done
 -  rm -f conftest*
 -  if test "${EXEEXT_FOR_BUILD+set}" != set; then
 -    AC_MSG_ERROR([Cannot determine suffix of executable build tools])
 -  fi
 -else
 -  EXEEXT_FOR_BUILD=$EXEEXT
 -fi
 -AC_MSG_RESULT([$EXEEXT_FOR_BUILD])
 -AC_SUBST(EXEEXT_FOR_BUILD)
 -
 -USB_LIBS="-lusb"
 -AC_SUBST(USB_LIBS)
 -
  AC_OUTPUT([
 -Makefile 
 +Makefile
 +aoview/Makefile
+ lib/Makefile
+ ccload/Makefile
+ s51/Makefile
+ ccmanual/Makefile
+ ccdump/Makefile
+ aoload/Makefile
  ])
index 0000000,a5d2d36..1d3ba47
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,270 +1,269 @@@
 -      
+ /*
+  * Copyright © 2009 Keith Packard <keithp@keithp.com>
+  *
+  * 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 <time.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #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 --cc lib/cc-usb.c
index 0000000,2efe572..dc764c2
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,360 +1,359 @@@
 -      
+ /*
+  * Copyright © 2009 Keith Packard <keithp@keithp.com>
+  *
+  * 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 <sys/types.h>
+ #include <sys/stat.h>
+ #include <fcntl.h>
+ #include <stdarg.h>
+ #include <poll.h>
+ #include <stdlib.h>
+ #include <stdio.h>
+ #include <unistd.h>
+ #include <string.h>
+ #include <termios.h>
+ #include "ccdbg-debug.h"
+ #include "cc-usb.h"
+ #define CC_NUM_READ           16
+ /*
+  * AltOS has different buffer sizes for in/out packets
+  */
+ #define CC_IN_BUF             256
+ #define CC_OUT_BUF            64
+ #define DEFAULT_TTY           "/dev/ttyACM0"
+ struct cc_read {
+       uint8_t *buf;
+       int     len;
+ };
+ struct cc_usb {
+       int             fd;
+       uint8_t         in_buf[CC_IN_BUF];
+       int             in_count;
+       uint8_t         out_buf[CC_OUT_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;
 -              while (in_pos < cc->in_count && 
++
+       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_IN_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_IN_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);
+                       } else if (ret < 0)
+                               perror("read");
+               }
+               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;
+                       } else if (ret < 0)
+                               perror("write");
+               }
+       }
+ }
+ 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_OUT_BUF - cc->out_count)
+                       this_time = CC_OUT_BUF - cc->out_count;
+               memcpy(cc->out_buf + cc->out_count, b, this_time);
+               cc->out_count += this_time;
+               ret -= this_time;
+               b += this_time;
+               while (cc->out_count >= CC_OUT_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;
+ }
+ 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(char *tty)
+ {
+       struct cc_usb   *cc;
+       struct termios  termios;
 -
++
+       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);
+ }
index 0000000,7d1ae06..a100287
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,177 +1,176 @@@
 -      
+ /*
+  * Copyright © 2008 Keith Packard <keithp@keithp.com>
+  *
+  * 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"
+ uint8_t
+ ccdbg_chip_erase(struct ccdbg *dbg)
+ {
+       return ccdbg_cmd_write_read8(dbg, CC_CHIP_ERASE, NULL, 0);
+ }
+ uint8_t
+ ccdbg_wr_config(struct ccdbg *dbg, uint8_t config)
+ {
+       return ccdbg_cmd_write_read8(dbg, CC_WR_CONFIG, &config, 1);
+ }
+ uint8_t
+ ccdbg_rd_config(struct ccdbg *dbg)
+ {
+       return ccdbg_cmd_write_read8(dbg, CC_RD_CONFIG, NULL, 0);
+ }
+ uint16_t
+ ccdbg_get_pc(struct ccdbg *dbg)
+ {
+       uint16_t        pc1, pc2;
+       pc1 = ccdbg_cmd_write_read16(dbg, CC_GET_PC, NULL, 0);
+       pc2 = ccdbg_cmd_write_read16(dbg, CC_GET_PC, NULL, 0);
+       if (pc1 != pc2)
+               fprintf (stderr, "Invalid pc %04x != %04x\n",
+                        pc1, pc2);
+       return pc2;
+ }
+ uint8_t
+ ccdbg_read_status(struct ccdbg *dbg)
+ {
+       return ccdbg_cmd_write_read8(dbg, CC_READ_STATUS, NULL, 0);
+ }
+ uint8_t
+ ccdbg_set_hw_brkpnt(struct ccdbg *dbg, uint8_t number, uint8_t enable, uint16_t addr)
+ {
+       uint8_t data[3];
+       data[0] = (number << 3) | (enable << 2);
+       data[1] = (addr >> 8);
+       data[2] = addr;
+       return ccdbg_cmd_write_read8(dbg, CC_SET_HW_BRKPNT, data, 3);
+ }
+ uint8_t
+ ccdbg_halt(struct ccdbg *dbg)
+ {
+       return ccdbg_cmd_write_read8(dbg, CC_HALT, NULL, 0);
+ }
+ uint8_t
+ ccdbg_resume(struct ccdbg *dbg)
+ {
+       return ccdbg_cmd_write_read8(dbg, CC_RESUME, NULL, 0);
+ }
+ uint8_t
+ 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)
+ {
+       return ccdbg_cmd_write_read8(dbg, CC_STEP_INSTR, NULL, 0);
+ }
+ uint8_t
+ ccdbg_step_replace(struct ccdbg *dbg, uint8_t *instr, int nbytes)
+ {
+       return ccdbg_cmd_write_read8(dbg, CC_STEP_REPLACE(nbytes), instr, nbytes);
+ }
+ uint16_t
+ ccdbg_get_chip_id(struct ccdbg *dbg)
+ {
+       return ccdbg_cmd_write_read16(dbg, CC_GET_CHIP_ID, NULL, 0);
+ }
+ /*
+  * Execute a sequence of instructions
+  */
+ uint8_t
+ ccdbg_execute(struct ccdbg *dbg, uint8_t *inst)
+ {
+       uint8_t status = 0;
+       while(inst[0] != 0) {
+               uint8_t len = inst[0];
+               int i;
+               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]);
+               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;
+ }
+ static uint8_t jump_mem[] = {
+       3, LJMP, 0xf0, 0x00,
+ #define PC_HIGH       2
+ #define PC_LOW        3
+       0
+ };
+ uint8_t
+ ccdbg_set_pc(struct ccdbg *dbg, uint16_t pc)
+ {
+       jump_mem[PC_HIGH] = pc >> 8;
+       jump_mem[PC_LOW] = pc & 0xff;
+       return ccdbg_execute(dbg, jump_mem);
+ }
+ uint8_t
+ ccdbg_execute_hex_image(struct ccdbg *dbg, struct hex_image *image)
+ {
+       uint16_t pc;
+       uint8_t status;
 -
++
+       if (image->address < 0xf000) {
+               fprintf(stderr, "Cannot execute program starting at 0x%04x\n", image->address);
+               return -1;
+       }
+       ccdbg_write_hex_image(dbg, image, 0);
+       ccdbg_set_pc(dbg, image->address);
+       pc = ccdbg_get_pc(dbg);
+       ccdbg_debug(CC_DEBUG_EXECUTE, "pc starts at 0x%04x\n", pc);
+       status = ccdbg_resume(dbg);
+       ccdbg_debug(CC_DEBUG_EXECUTE, "resume status: 0x%02x\n", status);
+       return 0;
+ }
index 0000000,8a586a2..3e67298
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,356 +1,356 @@@
 -      
+ /*
+  * Copyright © 2008 Keith Packard <keithp@keithp.com>
+  *
+  * 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"
+ /* From SWRA124 section 3.1.6 */
+ static uint8_t flash_page[] = {
+       MOV_direct_data, P1DIR, 0x02,
+       MOV_direct_data, P1,    0xFF,
+       MOV_direct_data, FADDRH, 0,
+ #define FLASH_ADDR_HIGH       8
+       MOV_direct_data, FADDRL, 0,
+ #define FLASH_ADDR_LOW        11
+       MOV_DPTR_data16, 0, 0,
+ #define RAM_ADDR_HIGH 13
+ #define RAM_ADDR_LOW  14
+       MOV_Rn_data(7), 0,
+ #define FLASH_WORDS_HIGH      16
 -      
++
+       MOV_Rn_data(6), 0,
+ #define FLASH_WORDS_LOW               18
 -      
++
+       MOV_direct_data, FWT, 0x20,
+ #define FLASH_TIMING          21
+       MOV_direct_data, FCTL, FCTL_ERASE,
+ /* eraseWaitLoop: */
+               MOV_A_direct,           FCTL,
+       JB, ACC(FCTL_BUSY_BIT), 0xfb,
+       MOV_direct_data, P1, 0xfd,
+       MOV_direct_data, FCTL, FCTL_WRITE,
+ /* writeLoop: */
+               MOV_Rn_data(5), 2,
+ /* writeWordLoop: */
+                       MOVX_A_atDPTR,
+                       INC_DPTR,
+                       MOV_direct_A, FWDATA,
+               DJNZ_Rn_rel(5), 0xfa,           /* writeWordLoop */
+ /* writeWaitLoop: */
+                       MOV_A_direct, FCTL,
+               JB, ACC(FCTL_SWBSY_BIT), 0xfb,          /* writeWaitLoop */
+       DJNZ_Rn_rel(6), 0xf1,                   /* writeLoop */
+       DJNZ_Rn_rel(7), 0xef,                   /* writeLoop */
+       MOV_direct_data, P1DIR, 0x00,
+       MOV_direct_data, P1,    0xFF,
+       TRAP,
+ };
+ #define FLASH_RAM     0xf000
+ #if 0
+ static uint8_t        flash_erase_page[] = {
+       3,      MOV_direct_data, FADDRH, 0,
+ #define ERASE_PAGE_HIGH       3
 -      
++
+       3,      MOV_direct_data, FADDRL, 0,
+ #define ERASE_PAGE_LOW        7
+       3,      MOV_direct_data, FWT, 0x2A,
+       3,      MOV_direct_data, FCTL, FCTL_ERASE,
+       0
+ };
+ static uint8_t        flash_read_control[] = {
+       2,      MOV_A_direct,   FCTL,
+       0
+ };
+ #endif
+ #if 0
+ static uint8_t        flash_control_clear[] = {
+       3,      MOV_direct_data,        FCTL, 0,
+       2,      MOV_A_direct,           FCTL,
+       0
+ };
+ #endif
+ #if 0
+ static uint8_t
+ ccdbg_flash_erase_page(struct ccdbg *dbg, uint16_t addr)
+ {
+       uint16_t        page_addr = addr >> 1;
+       uint8_t         status;
+       uint8_t         old[0x10], new[0x10];
+       int             i;
 -      
++
+       ccdbg_read_memory(dbg, addr, old, 0x10);
+       flash_erase_page[ERASE_PAGE_HIGH] = page_addr >> 8;
+       flash_erase_page[ERASE_PAGE_LOW] = page_addr & 0xff;
+       status = ccdbg_execute(dbg, flash_erase_page);
+       ccdbg_debug(CC_DEBUG_FLASH, "erase status 0x%02x\n", status);
+       do {
+               status = ccdbg_execute(dbg, flash_read_control);
+               ccdbg_debug(CC_DEBUG_FLASH, "fctl 0x%02x\n", status);
+       } while (status & FCTL_BUSY);
+       ccdbg_read_memory(dbg, addr, new, 0x10);
+       for (i = 0; i < 0x10; i++)
+               ccdbg_debug(CC_DEBUG_FLASH, "0x%02x -> 0x%02x\n", old[i], new[i]);
+       status = ccdbg_execute(dbg, flash_control_clear);
+       ccdbg_debug(CC_DEBUG_FLASH, "clear fctl 0x%02x\n", status);
+       return 0;
+ }
+ #endif
+ #if 0
+ static uint8_t flash_write[] = {
+       MOV_direct_data, P1DIR, 0x02,
+       MOV_direct_data, P1,    0xFD,
 -      
++
+       MOV_A_direct, FCTL,
+       JB,     ACC(FCTL_BUSY_BIT), 0xf1,
+       MOV_direct_data, FCTL, 0x20,
+       MOV_direct_data, FADDRH, 0,
+ #define WRITE_PAGE_HIGH       16
 -      
++
+       MOV_direct_data, FADDRL, 0,
+ #define WRITE_PAGE_LOW        19
 -      
++
+       MOV_direct_data, FCTL, FCTL_WRITE,
+       MOV_direct_data, FWDATA, 0,
+ #define WRITE_BYTE_0  25
+       MOV_direct_data, FWDATA, 0,
+ #define WRITE_BYTE_1  28
+       MOV_A_direct, FCTL,
+       JB,     ACC(FCTL_SWBSY_BIT), 0xf1,
+       MOV_direct_data, P1,    0xFF,
+       TRAP,
+ };
+ #endif
+ static uint8_t
+ ccdbg_clock_init(struct ccdbg *dbg)
+ {
+       static uint8_t set_clkcon_fast[] = {
+               3,      MOV_direct_data,        CLKCON, 0x00,
+               0
+       };
+       static uint8_t get_sleep[] = {
+               2,      MOV_A_direct, SLEEP,
+               0
+       };
+       uint8_t status;
+       ccdbg_execute(dbg, set_clkcon_fast);
+       do {
+               status = ccdbg_execute(dbg, get_sleep);
+       } while (!(status & 0x40));
+       return 0;
+ }
+ #if 0
+ static uint8_t
+ ccdbg_flash_write_word(struct ccdbg *dbg, uint16_t addr, uint8_t data[2])
+ {
+       uint16_t page_addr = addr >> 1;
+       uint8_t check[2];
+       uint8_t status;
+       int i;
+       flash_write[WRITE_PAGE_HIGH] = page_addr >> 8;
+       flash_write[WRITE_PAGE_LOW] = page_addr & 0xff;
+       flash_write[WRITE_BYTE_0] = data[0];
+       flash_write[WRITE_BYTE_1] = data[1];
+       ccdbg_debug(CC_DEBUG_FLASH, "upload flash write\n");
+       ccdbg_write_memory(dbg, 0xf000, flash_write, sizeof(flash_write));
+       ccdbg_set_pc(dbg, 0xf000);
+       ccdbg_resume(dbg);
+       for (;;) {
+               status = ccdbg_read_status(dbg);
+               ccdbg_debug(CC_DEBUG_FLASH, "waiting for write 0x%02x\n", status);
+               if ((status & CC_STATUS_CPU_HALTED) != 0)
+                       break;
+               sleep (1);
+       }
+       status = ccdbg_execute(dbg, flash_control_clear);
+       ccdbg_debug(CC_DEBUG_FLASH, "clear fctl 0x%02x\n", status);
+       ccdbg_read_memory(dbg, addr, check, 2);
+       for (i = 0; i < 2; i++)
+               ccdbg_debug(CC_DEBUG_FLASH, "0x%02x : 0x%02x\n", data[i], check[i]);
+       return 0;
+ }
+ #endif
+ #define TIMERS_OFF            0x08
+ #define DMA_PAUSE             0x04
+ #define TIMER_SUSPEND         0x02
+ #define SEL_FLASH_INFO_PAGE   0x01
+ #if 0
+ static uint8_t
+ ccdbg_flash_lock(struct ccdbg *dbg, uint8_t lock)
+ {
+       uint8_t config;
+       uint8_t bytes[2];
+       uint8_t old[1], new[1];
+       config = ccdbg_rd_config(dbg);
+       ccdbg_wr_config(dbg, config|SEL_FLASH_INFO_PAGE);
+       bytes[0] = lock;
+       bytes[1] = 0;
+       ccdbg_flash_erase_page(dbg, 0);
+       ccdbg_read_memory(dbg, 0, old, 1);
+       ccdbg_flash_write_word(dbg, 0, bytes);
+       ccdbg_read_memory(dbg, 0, new, 1);
+       ccdbg_debug(CC_DEBUG_FLASH, "flash lock 0x%02x -> 0x%02x\n", old[0], new[0]);
+       ccdbg_wr_config(dbg, config & ~SEL_FLASH_INFO_PAGE);
+       return 0;
+ }
+ #endif
+ uint8_t
+ ccdbg_flash_hex_image(struct ccdbg *dbg, struct hex_image *image)
+ {
+       uint16_t offset;
+       uint16_t flash_prog;
+       uint16_t flash_len;
+       uint8_t fwt;
+       uint16_t flash_addr;
+       uint16_t flash_word_addr;
+       uint16_t flash_words;
+       uint8_t flash_words_high, flash_words_low;
+       uint16_t ram_addr;
+       uint16_t pc;
+       uint8_t status;
+       uint16_t remain, this_time, start;
+       uint8_t verify[0x400];
+       int times;
+       ccdbg_clock_init(dbg);
+       if (image->address + image->length > 0x8000) {
+               fprintf(stderr, "cannot flash image from 0x%04x to 0x%04x\n",
+                       image->address, image->address + image->length);
+               return 1;
+       }
+       if (image->address & 0x3ff) {
+               fprintf(stderr, "flash image must start on page boundary\n");
+               return 1;
+       }
+       ram_addr = 0xf000;
 -      
++
+       flash_prog = 0xf400;
+       fwt = 0x20;
+       flash_page[FLASH_TIMING] = fwt;
+       ccdbg_debug(CC_DEBUG_FLASH, "Upload %d flash program bytes to 0x%04x\n",
+              sizeof (flash_page), flash_prog);
+       ccdbg_write_memory(dbg, flash_prog, flash_page, sizeof(flash_page));
 -              
++
+       remain = image->length;
+       start = 0;
+       while (remain) {
+               this_time = remain;
+               if (this_time > 0x400)
+                       this_time = 0x400;
+               offset = ram_addr - (image->address + start);
+               ccdbg_debug(CC_DEBUG_FLASH, "Upload %d bytes at 0x%04x\n", this_time, ram_addr);
+               ccdbg_write_memory(dbg, ram_addr, image->data + start, this_time);
+ #if 0
+               ccdbg_debug(CC_DEBUG_FLASH, "Verify %d bytes in ram\n", this_time);
+               ccdbg_read_memory(dbg, ram_addr, verify, this_time);
+               if (memcmp (image->data + start, verify, this_time) != 0) {
+                       fprintf(stderr, "ram verify failed\n");
+                       return 1;
+               }
+ #endif
 -              
++
+               flash_addr = image->address + start;
+               flash_word_addr = flash_addr >> 1;
+               flash_len = this_time + (this_time & 1);
+               flash_words = flash_len >> 1;
+               flash_words_low = flash_words & 0xff;
+               flash_words_high = flash_words >> 8;
 -      
++
+               /* The flash code above is lame */
+               if (flash_words_low)
+                       flash_words_high++;
 -              
++
+               ccdbg_write_uint8(dbg, flash_prog + FLASH_ADDR_HIGH, flash_word_addr >> 8);
+               ccdbg_write_uint8(dbg, flash_prog + FLASH_ADDR_LOW, flash_word_addr & 0xff);
+               ccdbg_write_uint8(dbg, flash_prog + RAM_ADDR_HIGH, ram_addr >> 8);
+               ccdbg_write_uint8(dbg, flash_prog + RAM_ADDR_LOW, ram_addr & 0xff);
+               ccdbg_write_uint8(dbg, flash_prog + FLASH_WORDS_HIGH, flash_words_high);
+               ccdbg_write_uint8(dbg, flash_prog + FLASH_WORDS_LOW, flash_words_low);
+               ccdbg_set_pc(dbg, flash_prog);
+               pc = ccdbg_get_pc(dbg);
+               ccdbg_debug(CC_DEBUG_FLASH, "Flashing %d bytes at 0x%04x\n",
+                           this_time, flash_addr);
+               status = ccdbg_resume(dbg);
+               for (times = 0; times < 10; times++) {
+                       status = ccdbg_read_status(dbg);
+                       ccdbg_debug(CC_DEBUG_FLASH, ".");
+                       ccdbg_flush(CC_DEBUG_FLASH);
+                       if ((status & CC_STATUS_CPU_HALTED) != 0)
+                               break;
+                       usleep(10000);
+               }
+               ccdbg_debug(CC_DEBUG_FLASH, "\n");
+               if (times == 10) {
+                       fprintf(stderr, "flash page timed out\n");
+                       return 1;
+               }
++
+               ccdbg_debug(CC_DEBUG_FLASH, "Verify %d bytes in flash\n", this_time);
+               ccdbg_read_memory(dbg, flash_addr, verify, this_time);
+               if (memcmp (image->data + start, verify, this_time) != 0) {
+                       int i;
+                       fprintf(stderr, "flash verify failed\n");
+                       for (i = 0; i < this_time; i++) {
+                               if (image->data[start + i] != verify[i])
+                                       fprintf(stderr, "0x%04x: 0x%02x != 0x%02x\n",
+                                               start + i, image->data[start+i], verify[i]);
+                       }
+                       return 1;
+               }
+               remain -= this_time;
+               start += this_time;
+       }
+       return 0;
+ }
diff --cc lib/ccdbg-hex.c
index 0000000,86478da..dfea915
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,330 +1,330 @@@
 -                      
+ /*
+  * Copyright © 2008 Keith Packard <keithp@keithp.com>
+  *
+  * 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"
+ #include <stdarg.h>
+ #include <ctype.h>
+ struct hex_input {
+       FILE    *file;
+       int     line;
+       char    *name;
+ };
+ enum hex_read_state {
+       read_marker,
+       read_length,
+       read_address,
+       read_type,
+       read_data,
+       read_checksum,
+       read_newline,
+       read_white,
+       read_done,
+ };
+ static void
+ ccdbg_hex_error(struct hex_input *input, char *format, ...)
+ {
+       va_list ap;
+       va_start(ap, format);
+       fprintf(stderr, "Hex error %s:%d: ", input->name, input->line);
+       vfprintf(stderr, format, ap);
+       fprintf(stderr, "\n");
+       va_end(ap);
+ }
+ static void
+ ccdbg_hex_free(struct hex_record *record)
+ {
+       if (!record) return;
+       free(record);
+ }
+ static struct hex_record *
+ ccdbg_hex_alloc(uint8_t length)
+ {
+       struct hex_record *record;
+       record = calloc(1, sizeof(struct hex_record) + length);
+       record->length = length;
+       return record;
+ }
+ static int
+ ishex(char c)
+ {
+       return isdigit(c) || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F');
+ }
+ static int
+ fromhex(char c)
+ {
+       if (isdigit(c))
+               return c - '0';
+       if ('a' <= c && c <= 'f')
+               return c - 'a' + 10;
+       if ('A' <= c && c <= 'F')
+               return c - 'A' + 10;
+       abort();
+       return 0;
+ }
+ static uint8_t
+ ccdbg_hex_checksum(struct hex_record *record)
+ {
+       uint8_t checksum = 0;
+       int i;
+       checksum += record->length;
+       checksum += record->address >> 8;
+       checksum += record->address & 0xff;
+       checksum += record->type;
+       for (i = 0; i < record->length; i++)
+               checksum += record->data[i];
+       return -checksum;
+ }
+ static struct hex_record *
+ ccdbg_hex_read_record(struct hex_input *input)
+ {
+       struct hex_record *record = NULL;
+       enum hex_read_state state = read_marker;
+       char c;
+       int nhexbytes;
+       uint32_t hex;
+       uint32_t ndata;
+       uint8_t checksum;
+       while (state != read_done) {
+               c = getc(input->file);
+               if (c == EOF && state != read_white) {
+                       ccdbg_hex_error(input, "Unexpected EOF");
+                       goto bail;
+               }
+               if (c == ' ')
+                       continue;
+               if (c == '\n')
+                       input->line++;
+               switch (state) {
+               case read_marker:
+                       if (c != ':') {
+                               ccdbg_hex_error(input, "Missing ':'");
+                               goto bail;
+                       }
+                       state = read_length;
+                       nhexbytes = 2;
+                       hex = 0;
+                       break;
+               case read_length:
+               case read_address:
+               case read_type:
+               case read_data:
+               case read_checksum:
+                       if (!ishex(c)) {
+                               ccdbg_hex_error(input, "Non-hex char '%c'",
+                                               c);
+                               goto bail;
+                       }
+                       hex = hex << 4 | fromhex(c);
+                       --nhexbytes;
+                       if (nhexbytes != 0)
+                               break;
 -                      newhex = realloc(hex, 
++
+                       switch (state) {
+                       case read_length:
+                               record = ccdbg_hex_alloc(hex);
+                               if (!record) {
+                                       ccdbg_hex_error(input, "Out of memory");
+                                       goto bail;
+                               }
+                               state = read_address;
+                               nhexbytes = 4;
+                               break;
+                       case read_address:
+                               record->address = hex;
+                               state = read_type;
+                               nhexbytes = 2;
+                               break;
+                       case read_type:
+                               record->type = hex;
+                               state = read_data;
+                               nhexbytes = 2;
+                               ndata = 0;
+                               break;
+                       case read_data:
+                               record->data[ndata] = hex;
+                               ndata++;
+                               nhexbytes = 2;
+                               break;
+                       case read_checksum:
+                               record->checksum = hex;
+                               state = read_newline;
+                               break;
+                       default:
+                               break;
+                       }
+                       if (state == read_data)
+                               if (ndata == record->length) {
+                                       nhexbytes = 2;
+                                       state = read_checksum;
+                               }
+                       hex = 0;
+                       break;
+               case read_newline:
+                       if (c != '\n' && c != '\r') {
+                               ccdbg_hex_error(input, "Missing newline");
+                               goto bail;
+                       }
+                       state = read_white;
+                       break;
+               case read_white:
+                       if (!isspace(c)) {
+                               if (c == '\n')
+                                       input->line--;
+                               if (c != EOF)
+                                       ungetc(c, input->file);
+                               state = read_done;
+                       }
+                       break;
+               case read_done:
+                       break;
+               }
+       }
+       checksum = ccdbg_hex_checksum(record);
+       if (checksum != record->checksum) {
+               ccdbg_hex_error(input, "Invalid checksum (read 0x%02x computed 0x%02x)\n",
+                               record->checksum, checksum);
+               goto bail;
+       }
+       return record;
+ bail:
+       ccdbg_hex_free(record);
+       return NULL;
+ }
+ void
+ ccdbg_hex_file_free(struct hex_file *hex)
+ {
+       int     i;
+       if (!hex)
+               return;
+       for (i = 0; i < hex->nrecord; i++)
+               ccdbg_hex_free(hex->records[i]);
+       free(hex);
+ }
+ static int
+ ccdbg_hex_record_compar(const void *av, const void *bv)
+ {
+       const struct hex_record *a = *(struct hex_record **) av;
+       const struct hex_record *b = *(struct hex_record **) bv;
+       return (int) a->address - (int) b->address;
+ }
+ struct hex_file *
+ ccdbg_hex_file_read(FILE *file, char *name)
+ {
+       struct hex_input input;
+       struct hex_file *hex = NULL, *newhex;
+       struct hex_record *record;
+       int srecord = 1;
+       int done = 0;
+       hex = calloc(sizeof (struct hex_file) + sizeof (struct hex_record *), 1);
+       input.name = name;
+       input.line = 1;
+       input.file = file;
+       while (!done) {
+               record = ccdbg_hex_read_record(&input);
+               if (!record)
+                       goto bail;
+               if (hex->nrecord == srecord) {
+                       srecord *= 2;
++                      newhex = realloc(hex,
+                                        sizeof (struct hex_file) +
+                                        srecord * sizeof (struct hex_record *));
+                       if (!newhex)
+                               goto bail;
+                       hex = newhex;
+               }
+               hex->records[hex->nrecord++] = record;
+               if (record->type == HEX_RECORD_EOF)
+                       done = 1;
+       }
+       /*
+        * Sort them into increasing addresses, except for EOF
+        */
+       qsort(hex->records, hex->nrecord - 1, sizeof (struct hex_record *),
+             ccdbg_hex_record_compar);
+       return hex;
+ bail:
+       ccdbg_hex_file_free(hex);
+       return NULL;
+ }
+ struct hex_image *
+ ccdbg_hex_image_create(struct hex_file *hex)
+ {
+       struct hex_image *image;
+       struct hex_record *first, *last, *record;
+       int i;
+       uint32_t base, bound;
+       uint32_t offset;
+       int length;
+       first = hex->records[0];
+       last = hex->records[hex->nrecord - 2];  /* skip EOF */
+       base = (uint32_t) first->address;
+       bound = (uint32_t) last->address + (uint32_t) last->length;
+       length = bound - base;
+       image = calloc(sizeof(struct hex_image) + length, 1);
+       if (!image)
+               return NULL;
+       image->address = base;
+       image->length = length;
+       memset(image->data, 0xff, length);
+       for (i = 0; i < hex->nrecord - 1; i++) {
+               record = hex->records[i];
+               offset = record->address - base;
+               memcpy(image->data + offset, record->data, record->length);
+       }
+       return image;
+ }
+ void
+ ccdbg_hex_image_free(struct hex_image *image)
+ {
+       free(image);
+ }
+ int
+ ccdbg_hex_image_equal(struct hex_image *a, struct hex_image *b)
+ {
+       if (a->length != b->length)
+               return 0;
+       if (memcmp(a->data, b->data, a->length) != 0)
+               return 0;
+       return 1;
+ }
index 0000000,878c5f9..554ac63
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,179 +1,179 @@@
 -      
+ /*
+  * Copyright © 2008 Keith Packard <keithp@keithp.com>
+  *
+  * 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"
+ /*
+  * Read and write arbitrary memory through the debug port
+  */
+ static uint8_t        memory_init[] = {
+       3,      MOV_DPTR_data16,        0,      0,
+ #define HIGH_START    2
+ #define LOW_START     3
+       0,
+ };
+ static uint8_t write8[] = {
+       2,      MOV_A_data,     0,
+ #define DATA_BYTE     2
+       1,      MOVX_atDPTR_A,
+       1,      INC_DPTR,
+       0
+ };
+ static uint8_t read8[] = {
+       1,      MOVX_A_atDPTR,
+       1,      INC_DPTR,
+       0,
+ };
+ uint8_t
+ 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;
+       (void) ccdbg_execute(dbg, memory_init);
+       for (i = 0; i < nbytes; i++) {
+               write8[DATA_BYTE] = *bytes++;
+               ccdbg_execute(dbg, write8);
+               if ((i & 0xf) == 0xf) {
+                       ccdbg_debug(CC_DEBUG_MEMORY, ".");
+                       ccdbg_flush(CC_DEBUG_MEMORY);
+                       nl = 1;
+               }
+               if ((i & 0xff) == 0xff) {
+                       ccdbg_debug(CC_DEBUG_MEMORY, "\n");
+                       nl = 0;
+               }
+       }
+       ccdbg_state_restore(dbg, &state);
+       if (nl)
+               ccdbg_debug(CC_DEBUG_MEMORY, "\n");
+       return 0;
+ }
+ uint8_t
+ ccdbg_read_memory(struct ccdbg *dbg, uint16_t addr, uint8_t *bytes, int nbytes)
+ {
+       int i, nl = 0;
+       struct ccstate state;
+       if (ccdbg_rom_contains(dbg, addr, 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;
+       (void) ccdbg_execute(dbg, memory_init);
+       for (i = 0; i < nbytes; i++) {
+               *bytes++ = ccdbg_execute(dbg, read8);
+               if ((i & 0xf) == 0xf) {
+                       ccdbg_debug(CC_DEBUG_MEMORY, ".");
+                       ccdbg_flush(CC_DEBUG_MEMORY);
+                       nl = 1;
+               }
+               if ((i & 0xff) == 0xff) {
+                       ccdbg_debug(CC_DEBUG_MEMORY, "\n");
+                       nl = 0;
+               }
+       }
+       ccdbg_state_replace_xmem(dbg, &state, addr, bytes, nbytes);
+       ccdbg_state_restore(dbg, &state);
+       if (nl)
+               ccdbg_debug(CC_DEBUG_MEMORY, "\n");
+       return 0;
+ }
+ uint8_t
+ ccdbg_write_uint8(struct ccdbg *dbg, uint16_t addr, uint8_t byte)
+ {
+       return ccdbg_write_memory(dbg, addr, &byte, 1);
+ }
+ uint8_t
+ ccdbg_write_hex_image(struct ccdbg *dbg, struct hex_image *image, uint16_t offset)
+ {
+       ccdbg_write_memory(dbg, image->address + offset, image->data, image->length);
+       return 0;
+ }
+ struct hex_image *
+ ccdbg_read_hex_image(struct ccdbg *dbg, uint16_t address, uint16_t length)
+ {
+       struct hex_image *image;
 -      
++
+       image = calloc(sizeof(struct hex_image) + length, 1);
+       image->address = address;
+       image->length = length;
+       memset(image->data, 0xff, length);
+       ccdbg_read_memory(dbg, address, image->data, length);
+       return image;
+ }
+ static uint8_t sfr_read[] = {
+       2,      MOV_A_direct,           0,
+ #define SFR_READ_ADDR 2
+       0,
+ };
+ static uint8_t sfr_write[] = {
+       3,      MOV_direct_data,        0,      0,
+ #define SFR_WRITE_ADDR        2
+ #define SFR_WRITE_DATA        3
+       0,
+ };
+ uint8_t
+ ccdbg_read_sfr(struct ccdbg *dbg, uint8_t addr, uint8_t *bytes, int nbytes)
+ {
+       int     i;
+       struct ccstate state;
+       ccdbg_state_save(dbg, &state, CC_STATE_ACC);
+       for (i = 0; i < nbytes; i++) {
+               sfr_read[SFR_READ_ADDR] = addr + i;
+               *bytes++ = ccdbg_execute(dbg, sfr_read);
+       }
+       ccdbg_state_replace_sfr(dbg, &state, addr, bytes, nbytes);
+       ccdbg_state_restore(dbg, &state);
+       return 0;
+ }
+ uint8_t
+ ccdbg_write_sfr(struct ccdbg *dbg, uint8_t addr, uint8_t *bytes, int nbytes)
+ {
+       int     i;
++
+       for (i = 0; i < nbytes; i++) {
+               sfr_write[SFR_WRITE_ADDR] = addr + i;
+               sfr_write[SFR_WRITE_DATA] = *bytes++;
+               ccdbg_execute(dbg, sfr_write);
+       }
+       return 0;
+ }
diff --cc lib/ccdbg-rom.c
index 0000000,4559b4e..71bed22
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,63 +1,63 @@@
 -      
+ /*
+  * Copyright © 2008 Keith Packard <keithp@keithp.com>
+  *
+  * 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"
+ uint8_t
+ ccdbg_set_rom(struct ccdbg *dbg, struct hex_image *rom)
+ {
+       if (dbg->rom)
+               ccdbg_hex_image_free(dbg->rom);
+       dbg->rom = rom;
+       return 0;
+ }
+ uint8_t
+ ccdbg_rom_contains(struct ccdbg *dbg, uint16_t addr, int nbytes)
+ {
+       struct hex_image *rom = dbg->rom;
+       if (!rom)
+               return 0;
+       if (addr < rom->address || rom->address + rom->length < addr + nbytes)
+               return 0;
+       return 1;
+ }
+ uint8_t
+ ccdbg_rom_replace_xmem(struct ccdbg *dbg,
+                      uint16_t addr, uint8_t *bytes, int nbytes)
+ {
+       struct hex_image *rom = dbg->rom;
+       if (!rom)
+               return 0;
++
+       if (rom->address < addr + nbytes && addr < rom->address + rom->length) {
+               int     start, stop;
+               start = addr;
+               if (addr < rom->address)
+                       start = rom->address;
+               stop = addr + nbytes;
+               if (rom->address + rom->length < stop)
+                       stop = rom->address + rom->length;
+               memcpy(bytes + start - addr, rom->data + start - rom->address,
+                      stop - start);
+               return 1;
+       }
+       return 0;
+ }
diff --cc lib/ccdbg.h
index 0000000,fe0ea3a..4a2e3b9
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,341 +1,341 @@@
 -      
+ /*
+  * Copyright © 2008 Keith Packard <keithp@keithp.com>
+  *
+  * 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_H_
+ #define _CCDBG_H_
+ #include <stdint.h>
+ #include <stdlib.h>
+ #include <unistd.h>
+ #include <string.h>
+ #include <stdio.h>
+ #include <stdint.h>
+ #include <assert.h>
+ #include <fcntl.h>
+ #include <sys/types.h>
+ #include <sys/ioctl.h>
+ #include <sys/stat.h>
+ #include "ccdbg-debug.h"
+ #include "cc-bitbang.h"
+ #include "cc-usb.h"
+ /* 8051 instructions
+  */
+ #define NOP                   0x00
+ #define MOV_direct_data               0x75
+ #define LJMP                  0x02
+ #define MOV_Rn_data(n)                (0x78 | (n))
+ #define DJNZ_Rn_rel(n)                (0xd8 | (n))
+ #define MOV_A_direct          0xe5
+ #define MOV_direct1_direct2   0x85
+ #define MOV_direct_A          0xf5
+ #define MOV_DPTR_data16               0x90
+ #define MOV_A_data            0x74
+ #define MOVX_atDPTR_A         0xf0
+ #define MOVX_A_atDPTR         0xe0
+ #define INC_DPTR              0xa3
+ #define TRAP                  0xa5
+ #define SJMP                  0x80
+ #define JB                    0x20
+ /* 8051 special function registers
+  */
+ #define SFR_P0                        0x80
+ #define SFR_SP                        0x81
+ #define SFR_DPL0              0x82
+ #define SFR_DPH0              0x83
+ #define SFR_DPL1              0x84
+ #define SFR_DPH1              0x85
+ /* flash controller */
+ #define FWT                   0xAB
+ #define FADDRL                        0xAC
+ #define FADDRH                        0xAD
+ #define FCTL                  0xAE
+ # define FCTL_BUSY            0x80
+ # define FCTL_BUSY_BIT                7
+ # define FCTL_SWBSY           0x40
+ # define FCTL_SWBSY_BIT               6
+ # define FCTL_CONTRD          0x10
+ # define FCTL_WRITE           0x02
+ # define FCTL_ERASE           0x01
+ #define FWDATA                        0xAF
+ #define SLEEP                 0xBE
+ /* clock controller */
+ #define CLKCON                        0xC6
+ #define  CLKCON_OSC32K                0x80
+ #define  CLKCON_OSC           0x40
+ #define  CLKCON_TICKSPD               0x38
+ #define  CLKCON_CLKSPD                0x07
+ /* I/O pins */
+ #define P0                    0x80
+ #define P1                    0x90
+ #define P2                    0xA0
+ #define P0DIR                 0xFD
+ #define P1DIR                 0xFE
+ #define P2DIR                 0xFF
+ /* Bit-addressable accumulator */
+ #define ACC(bit)              (0xE0 | (bit))
+ /* Bit-addressable status word */
+ #define PSW(bit)              (0xD0 | (bit))
+ struct ccdbg {
+       struct cc_bitbang       *bb;
+       struct cc_usb           *usb;
+       struct hex_image        *rom;
+ };
+ /* Intel hex file format data
+  */
+ struct hex_record {
+       uint8_t length;
+       uint16_t address;
+       uint8_t type;
+       uint8_t checksum;
+       uint8_t data[0];
+ };
+ struct hex_file {
+       int                     nrecord;
+       struct hex_record       *records[0];
+ };
+ struct hex_image {
+       uint16_t        address;
+       uint16_t        length;
+       uint8_t         data[0];
+ };
+ #define CC_STATE_ACC  0x1
+ #define CC_STATE_PSW  0x2
+ #define CC_STATE_DP   0x4
+ #define CC_STATE_NSFR 5
+ struct ccstate {
+       uint16_t        mask;
+       uint8_t         acc;
+       uint8_t         sfr[CC_STATE_NSFR];
+ };
+ #define HEX_RECORD_NORMAL             0x00
+ #define HEX_RECORD_EOF                        0x01
+ #define HEX_RECORD_EXTENDED_ADDRESS   0x02
+ /* CC1111 debug port commands
+  */
+ #define CC_CHIP_ERASE         0x14
+ #define CC_WR_CONFIG          0x1d
+ #define CC_RD_CONFIG          0x24
+ # define CC_CONFIG_TIMERS_OFF         (1 << 3)
+ # define CC_CONFIG_DMA_PAUSE          (1 << 2)
+ # define CC_CONFIG_TIMER_SUSPEND      (1 << 1)
+ # define CC_SET_FLASH_INFO_PAGE               (1 << 0)
+ #define CC_GET_PC             0x28
+ #define CC_READ_STATUS                0x34
+ # define CC_STATUS_CHIP_ERASE_DONE    (1 << 7)
+ # define CC_STATUS_PCON_IDLE          (1 << 6)
+ # define CC_STATUS_CPU_HALTED         (1 << 5)
+ # define CC_STATUS_POWER_MODE_0               (1 << 4)
+ # define CC_STATUS_HALT_STATUS                (1 << 3)
+ # define CC_STATUS_DEBUG_LOCKED               (1 << 2)
+ # define CC_STATUS_OSCILLATOR_STABLE  (1 << 1)
+ # define CC_STATUS_STACK_OVERFLOW     (1 << 0)
+ #define CC_SET_HW_BRKPNT      0x3b
+ # define CC_HW_BRKPNT_N(n)    ((n) << 3)
+ # define CC_HW_BRKPNT_N_MASK  (0x3 << 3)
+ # define CC_HW_BRKPNT_ENABLE  (1 << 2)
+ #define CC_HALT                       0x44
+ #define CC_RESUME             0x4c
+ #define CC_DEBUG_INSTR(n)     (0x54|(n))
+ #define CC_STEP_INSTR         0x5c
+ #define CC_STEP_REPLACE(n)    (0x64|(n))
+ #define CC_GET_CHIP_ID                0x68
+ /* ccdbg-command.c */
+ void
+ ccdbg_debug_mode(struct ccdbg *dbg);
+ void
+ ccdbg_reset(struct ccdbg *dbg);
+ uint8_t
+ ccdbg_chip_erase(struct ccdbg *dbg);
+ uint8_t
+ ccdbg_wr_config(struct ccdbg *dbg, uint8_t config);
+ uint8_t
+ ccdbg_rd_config(struct ccdbg *dbg);
+ uint16_t
+ ccdbg_get_pc(struct ccdbg *dbg);
+ uint8_t
+ ccdbg_read_status(struct ccdbg *dbg);
+ uint8_t
+ ccdbg_set_hw_brkpnt(struct ccdbg *dbg, uint8_t number, uint8_t enable, uint16_t addr);
+ uint8_t
+ ccdbg_halt(struct ccdbg *dbg);
+ uint8_t
+ 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);
+ uint8_t
+ ccdbg_step_replace(struct ccdbg *dbg, uint8_t *instr, int nbytes);
+ uint16_t
+ ccdbg_get_chip_id(struct ccdbg *dbg);
+ uint8_t
+ ccdbg_execute(struct ccdbg *dbg, uint8_t *inst);
 -      
++
+ uint8_t
+ ccdbg_set_pc(struct ccdbg *dbg, uint16_t pc);
++
+ uint8_t
+ ccdbg_execute_hex_image(struct ccdbg *dbg, struct hex_image *image);
+ /* ccdbg-flash.c */
+ uint8_t
+ ccdbg_flash_hex_image(struct ccdbg *dbg, struct hex_image *image);
+ /* ccdbg-hex.c */
+ struct hex_file *
+ ccdbg_hex_file_read(FILE *file, char *name);
+ void
+ ccdbg_hex_file_free(struct hex_file *hex);
+ struct hex_image *
+ ccdbg_hex_image_create(struct hex_file *hex);
+ void
+ ccdbg_hex_image_free(struct hex_image *image);
+ int
+ ccdbg_hex_image_equal(struct hex_image *a, struct hex_image *b);
+ /* ccdbg-io.c */
+ struct ccdbg *
+ ccdbg_open(void);
+ void
+ ccdbg_close(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);
+ void
+ ccdbg_cmd_write_queue8(struct ccdbg *dbg, uint8_t cmd,
+                      uint8_t *data, int len, uint8_t *reply);
+ 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_bytes(struct ccdbg *dbg, uint8_t *bytes, int nbytes);
+ void
+ ccdbg_sync(struct ccdbg *dbg);
+ /* ccdbg-manual.c */
+ void
+ ccdbg_manual(struct ccdbg *dbg, FILE *input);
+ /* ccdbg-memory.c */
+ uint8_t
+ ccdbg_write_memory(struct ccdbg *dbg, uint16_t addr, uint8_t *bytes, int nbytes);
+ uint8_t
+ ccdbg_read_memory(struct ccdbg *dbg, uint16_t addr, uint8_t *bytes, int nbytes);
+ uint8_t
+ ccdbg_write_uint8(struct ccdbg *dbg, uint16_t addr, uint8_t byte);
+ uint8_t
+ ccdbg_write_hex_image(struct ccdbg *dbg, struct hex_image *image, uint16_t offset);
+ struct hex_image *
+ ccdbg_read_hex_image(struct ccdbg *dbg, uint16_t address, uint16_t length);
+ uint8_t
+ ccdbg_read_sfr(struct ccdbg *dbg, uint8_t addr, uint8_t *bytes, int nbytes);
+ uint8_t
+ ccdbg_write_sfr(struct ccdbg *dbg, uint8_t addr, uint8_t *bytes, int nbytes);
+ /* ccdbg-rom.c */
+ uint8_t
+ ccdbg_set_rom(struct ccdbg *dbg, struct hex_image *rom);
+ uint8_t
+ ccdbg_rom_contains(struct ccdbg *dbg, uint16_t addr, int nbytes);
+ uint8_t
+ ccdbg_rom_replace_xmem(struct ccdbg *dbg,
+                      uint16_t addrp, uint8_t *bytesp, int nbytes);
+ /* ccdbg-state.c */
+ uint8_t
+ ccdbg_state_save(struct ccdbg *dbg, struct ccstate *state, unsigned int mask);
+ uint8_t
+ ccdbg_state_restore(struct ccdbg *dbg, struct ccstate *state);
+ void
+ ccdbg_state_replace_xmem(struct ccdbg *dbg, struct ccstate *state,
+                        uint16_t addr, uint8_t *bytes, int nbytes);
+ void
+ ccdbg_state_replace_sfr(struct ccdbg *dbg, struct ccstate *state,
+                       uint8_t addr, uint8_t *bytes, int nbytes);
+ #endif /* _CCDBG_H_ */
index 0000000,1fe09aa..6539394
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,188 +1,188 @@@
 -      
+ /*
+  * Copyright © 2008 Keith Packard <keithp@keithp.com>
+  *
+  * 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 <stdio.h>
+ #include <errno.h>
+ #include <stdlib.h>
+ #include <unistd.h>
+ #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;
+       uint8_t                 value;
+       uint8_t                 set;
+ };
+ 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);
+       cp->ack = -1;
+       if (!cp->handle) {
+               libusb_exit(cp->ctx);
+               free(cp);
+               return NULL;
+       }
+       cp->value = 0;
+       cp->set = 0;
+       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;
+       int     ret;
+       if (cp->set) {
+               value = (cp->value & ~mask) | (value & mask);
+               mask = value ^ cp->value;
+       }
+       cp->set = 1;
+       cp->value = value;
+       gpio_set = ((uint16_t) value << 8) | mask;
+       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 = -1;
+ }
diff --cc lib/cp-usb.c
index 0000000,d227b78..530848d
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,157 +1,157 @@@
 -      
+ /*
+  * Copyright © 2008 Keith Packard <keithp@keithp.com>
+  *
+  * 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.
+  */
+ /*
+  * libusb interface to the GPIO pins on a CP2103.
+  *
+  * Various magic constants came from the cp210x driver published by silabs.
+  */
+ #include "cp-usb.h"
+ #include <stdio.h>
+ #include <errno.h>
+ #include <libusb.h>
+ struct cp_usb {
+       usb_dev_handle *usb_dev;
+       uint8_t gpio;
+ };
+ #define CP2101_UART   0x00
+ #define UART_ENABLE   0x0001
+ #define UART_DISABLE  0x0000
+ #define REQTYPE_HOST_TO_DEVICE  0x41
+ #define REQTYPE_DEVICE_TO_HOST  0xc1
+ static int
+ cp_usb_gpio_get(struct cp_usb *cp, uint8_t *gpio_get)
+ {
+       return usb_control_msg(cp->usb_dev,             /* dev */
+                              0xc0,                    /* request */
+                              0xff,                    /* requesttype */
+                              0x00c2,                  /* value */
+                              0,                       /* index */
+                              (char *) gpio_get,       /* bytes */
+                              1,                       /* size */
+                              300);                    /* timeout */
+ }
+ static int
+ cp_usb_gpio_set(struct cp_usb *cp, uint8_t mask, uint8_t value)
+ {
+       uint16_t gpio_set = ((uint16_t) value << 8) | mask;
+       return usb_control_msg(cp->usb_dev,             /* dev */
+                              0x40,                    /* request */
+                              0xff,                    /* requesttype */
+                              0x37e1,                  /* value */
+                              gpio_set,                /* index */
+                              NULL,                    /* bytes */
+                              0,                       /* size */
+                              300);                    /* timeout */
+ }
+ static int
+ cp_usb_uart_enable_disable(struct cp_usb *cp, uint16_t enable)
+ {
+       return usb_control_msg(cp->usb_dev,
+                              CP2101_UART,
+                              REQTYPE_HOST_TO_DEVICE,
+                              enable,
+                              0,
+                              NULL,
+                              0,
+                              300);
+ }
+ struct cp_usb *
+ cp_usb_open(void)
+ {
+       struct cp_usb *cp;
+       usb_dev_handle *dev_handle;
+       struct usb_device *dev = NULL;
+       struct usb_bus *bus, *busses;
+       int interface;
+       int ret;
+       uint8_t gpio;
 -      
++
+       usb_init();
+       usb_find_busses();
+       usb_find_devices();
++
+       busses = usb_get_busses();
+       for (bus = busses; bus; bus = bus->next) {
+               for (dev = bus->devices; dev; dev = dev->next) {
+                       if (dev->descriptor.idVendor == 0x10c4 &&
+                           dev->descriptor.idProduct == 0xea60)
+                               break;
+               }
+               if (dev)
+                       break;
+       }
+       if (!dev){
+               perror("No CP2103 found");
+               return NULL;
+       }
+       cp = calloc(sizeof(struct cp_usb), 1);
+       interface = 0;
+       dev_handle = usb_open(dev);
+       usb_detach_kernel_driver_np(dev_handle, interface);
+       usb_claim_interface(dev_handle, interface);
+       cp->usb_dev = dev_handle;
+       ret = cp_usb_uart_enable_disable(cp, UART_DISABLE);
+       cp->gpio = 0xf;
+       ret = cp_usb_gpio_set(cp, 0xf, cp->gpio);
+       ret = cp_usb_gpio_get(cp, &gpio);
+       return cp;
+ }
+ void
+ cp_usb_close(struct cp_usb *cp)
+ {
+       cp_usb_uart_enable_disable(cp, UART_DISABLE);
+       usb_close(cp->usb_dev);
+       free(cp);
+ }
+ void
+ cp_usb_write(struct cp_usb *cp, uint8_t mask, uint8_t value)
+ {
+       uint8_t new_gpio;
+       int ret;
+       new_gpio = (cp->gpio & ~mask) | (value & mask);
+       if (new_gpio != cp->gpio) {
+               ret = cp_usb_gpio_set(cp, new_gpio ^ cp->gpio, new_gpio);
+               if (ret < 0)
+                       perror("gpio_set");
+               cp->gpio = new_gpio;
+       }
+ }
+ uint8_t
+ cp_usb_read(struct cp_usb *cp)
+ {
+       int ret;
+       uint8_t gpio;
+       ret = cp_usb_gpio_get(cp, &gpio);
+       if (ret < 0)
+               perror("gpio_get");
+       return gpio;
+ }
diff --cc s51/commands
index 0000000,77a9849..aba65cd
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,61 +1,60 @@@
 -      run <start> <stop>      - set temporary bp at <stop> 
+ Listens on port 9756 for a command stream.
+ Dump commands:
+       di <start> <end>        - dump imem
+       ds <start> <end>        - dump sprs
+       dx <start> <end>        - dump xaddr
+       Returns a string of hex pairs, each preceded by a space,
+       with 8 pairs per line
+ Memory access commands:
+       set mem <prefix> <start> <end>
+       dump <prefix> <start> <end>
+       <prefix> is one of:
+               xram    - external ram or external stack
+               rom     - code space
+               iram    - internal ram or stack
+               sfr     - special function register
+       dump <addr>
+       set bit <addr>
+               bit addressable space
+ Set PC:
+       pc <addr>
+       Sets PC to specified address
+       pc
+       Returns current PC
+ Breakpoints
+       break <addr>
+       clear <addr>
+ Load a file
+       file "<filename>"
+ Execution control:
+       run <start>             - run starting at <start>
 -      
++      run <start> <stop>      - set temporary bp at <stop>
+       run                     - continue
+       next                    - step over calls(?)
+       step                    - step one instruction
 -      
++
+       reset                   - reset the simulator
+       res                     - synonym?
 -      
++
+ Error messages:
+       start with "Error:"
index 0000000,02ecddd..4f80306
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,655 +1,654 @@@
 -      
+ /*
+  * Copyright © 2008 Keith Packard <keithp@keithp.com>
+  *
+  * 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 "s51.h"
+ static uint16_t start_address;
+ static enum command_result
+ parse_int(char *value, int *result)
+ {
+       char *endptr;
+       *result = strtol(value, &endptr, 0);
+       if (endptr == value)
+               return command_syntax;
+       return command_success;
+ }
+ static enum command_result
+ parse_uint16(char *value, uint16_t *uint16)
+ {
+       int     v;
+       enum command_result result;
+       result = parse_int(value, &v);
+       if (result != command_success)
+               return command_error;
+       if (v < 0 || v > 0xffff)
+               return command_error;
+       *uint16 = v;
+       return command_success;
+ }
+ static enum command_result
+ parse_uint8(char *value, uint8_t *uint8)
+ {
+       int     v;
+       enum command_result result;
+       result = parse_int(value, &v);
+       if (result != command_success)
+               return command_error;
+       if (v < 0 || v > 0xff)
+               return command_error;
+       *uint8 = v;
+       return command_success;
+ }
+ enum command_result
+ command_quit (int argc, char **argv)
+ {
+       ccdbg_reset(s51_dbg);
+       exit(0);
+       return command_error;
+ }
+ static void
+ dump_bytes(uint8_t *memory, int length, uint16_t start, char *format)
+ {
+       int group, i;
 -      
++
+       for (group = 0; group < length; group += 8) {
+               s51_printf(format, start + group);
+               for (i = group; i < length && i < group + 8; i++)
+                       s51_printf("%02x ", memory[i]);
+               for (; i < group + 8; i++)
+                       s51_printf("   ");
+               for (i = group; i < length && i < group + 8; i++) {
+                       if (isascii(memory[i]) && isprint(memory[i]))
+                               s51_printf("%c", memory[i]);
+                       else
+                               s51_printf(".");
+               }
+               s51_printf("\n");
+       }
+ }
+ enum command_result
+ command_di (int argc, char **argv)
+ {
+       uint16_t start, end;
+       uint8_t memory[65536];
+       uint8_t status;
+       int length;
 -      
++
+       if (argc != 3)
+               return command_error;
+       if (parse_uint16(argv[1], &start) != command_success)
+               return command_error;
+       if (parse_uint16(argv[2], &end) != command_success)
+               return command_error;
+       length = (int) end - (int) start + 1;
+       status = ccdbg_read_memory(s51_dbg, start + 0xff00, memory, length);
+       dump_bytes(memory, length, start, "0x%02x ");
+       return command_success;
+ }
+ enum command_result
+ command_ds (int argc, char **argv)
+ {
+       uint8_t start, end;
+       uint8_t memory[0x100];
+       uint8_t status;
+       int length;
 -      
++
+       if (argc != 3)
+               return command_error;
+       if (parse_uint8(argv[1], &start) != command_success)
+               return command_error;
+       if (parse_uint8(argv[2], &end) != command_success)
+               return command_error;
+       length = (int) end - (int) start + 1;
+       status = ccdbg_read_sfr(s51_dbg, start, memory, length);
+       dump_bytes(memory, length, start, "0x%02x ");
+       return command_success;
+ }
+ enum command_result
+ command_dx (int argc, char **argv)
+ {
+       uint16_t start, end;
+       uint8_t memory[65536];
+       uint8_t status;
+       int length;
 -      
++
+       if (argc != 3)
+               return command_error;
+       if (parse_uint16(argv[1], &start) != command_success)
+               return command_error;
+       if (parse_uint16(argv[2], &end) != command_success)
+               return command_error;
+       length = (int) end - (int) start + 1;
+       status = ccdbg_read_memory(s51_dbg, start, memory, length);
+       dump_bytes(memory, length, start, "0x%04x ");
+       return command_success;
+ }
+ enum command_result
+ command_set (int argc, char **argv)
+ {
+       uint16_t address;
+       uint8_t *data;
+       int len = argc - 3;
+       int i;
+       enum command_result ret = command_success;
+       if (len < 0)
+               return command_error;
+       if (parse_uint16(argv[2], &address) != command_success)
+               return command_error;
+       if (len == 0)
+               return command_success;
+       data = malloc(len);
+       if (!data)
+               return command_error;
+       for (i = 0; i < len; i++)
+               if (parse_uint8(argv[i+3], &data[i]) != command_success)
+                       return command_error;
 -      
++
+       if (strcmp(argv[1], "xram") == 0) {
+               ccdbg_write_memory(s51_dbg, address, data, len);
+       } else if (strcmp(argv[1], "iram") == 0) {
+               ccdbg_write_memory(s51_dbg, address + 0xff00, data, len);
+       } else if (strcmp(argv[1], "sfr") == 0) {
+               ccdbg_write_sfr(s51_dbg, (uint8_t) address, data, len);
+       } else
+               ret = command_error;
+       free(data);
+       return ret;
+ }
+ enum command_result
+ command_dump (int argc, char **argv)
+ {
+       if (argv[1]) {
+               if (strcmp(argv[1], "rom") == 0 ||
+                   strcmp(argv[1], "xram") == 0)
+                       return command_dx(argc-1, argv+1);
+               if (strcmp(argv[1], "iram") == 0)
+                       return command_di(argc-1, argv+1);
+               if (strcmp(argv[1], "sfr") == 0)
+                       return command_ds(argc-1, argv+1);
+       }
+       return command_error;
+ }
+ enum command_result
+ command_file (int argc, char **argv)
+ {
+       struct hex_file *hex;
+       struct hex_image *image;
+       FILE *file;
 -      
++
+       if (argc != 2)
+               return command_error;
+       file = fopen (argv[1], "r");
+       if (!file)
+               return command_error;
+       hex = ccdbg_hex_file_read(file, argv[1]);
+       fclose(file);
+       if (!hex)
+               return command_error;
+       if (hex->nrecord == 0) {
+               ccdbg_hex_file_free(hex);
+               return command_error;
+       }
+       image = ccdbg_hex_image_create(hex);
+       ccdbg_hex_file_free(hex);
+       start_address = image->address;
+       ccdbg_set_rom(s51_dbg, image);
+       return command_success;
+ }
+ enum command_result
+ command_pc (int argc, char **argv)
+ {
+       uint16_t        pc;
+       if (argv[1]) {
+               enum command_result result;
+               result = parse_uint16(argv[1], &pc);
+               if (result != command_success)
+                       return result;
+               ccdbg_set_pc(s51_dbg, pc);
+       } else {
+               pc = ccdbg_get_pc(s51_dbg);
+               s51_printf("   0x%04x 00\n", pc);
+       }
+       return command_success;
+ }
+ struct cc_break {
+       int             enabled;
+       int             temporary;
+       uint16_t        address;
+ };
+ #define CC_NUM_BREAKPOINTS 4
+ static struct cc_break        breakpoints[CC_NUM_BREAKPOINTS];
+ static void
+ disable_breakpoint(int b)
+ {
+       uint8_t status;
 -      
++
+       status = ccdbg_set_hw_brkpnt(s51_dbg, b, 0, breakpoints[b].address);
+       if (status != 0x00 && status != 0xff)
+               s51_printf("disable_breakpoint status 0x%02x\n", status);
+ }
+ static void
+ enable_breakpoint(int b)
+ {
+       uint8_t status;
 -      
++
+       status = ccdbg_set_hw_brkpnt(s51_dbg, b, 1, breakpoints[b].address);
+       if (status != 0xff)
+               s51_printf("enable_breakpoint status 0x%02x\n", status);
+ }
+ static void
+ enable_breakpoints(void)
+ {
+       int b;
+       for (b = 0; b < CC_NUM_BREAKPOINTS; b++)
+               if (breakpoints[b].enabled)
+                       enable_breakpoint(b);
+ }
+ enum command_result
+ set_breakpoint(uint16_t address, int temporary)
+ {
+       int b;
+       uint8_t status;
+       for (b = 0; b < CC_NUM_BREAKPOINTS; b++) {
+               if (breakpoints[b].enabled == 0)
+                       break;
+               if (breakpoints[b].address == address)
+                       break;
+       }
+       if (b == CC_NUM_BREAKPOINTS) {
+               s51_printf("Error: too many breakpoints requested\n");
+               return command_success;
+       }
+       if (breakpoints[b].enabled == 0) {
+               breakpoints[b].address = address;
+               enable_breakpoint(b);
+       }
+       ++breakpoints[b].enabled;
+       s51_printf("Breakpoint %d at 0x%04x\n", b, address);
+       breakpoints[b].temporary += temporary;
+       return command_success;
+ }
+ enum command_result
+ clear_breakpoint(uint16_t address, int temporary)
+ {
+       int b;
+       uint8_t status;
+       for (b = 0; b < CC_NUM_BREAKPOINTS; b++) {
+               if (breakpoints[b].enabled != 0 &&
+                   ((breakpoints[b].temporary != 0) == (temporary != 0)) &&
+                   breakpoints[b].address == address)
+                       break;
+       }
+       if (b == CC_NUM_BREAKPOINTS) {
+               s51_printf("Error: no matching breakpoint found\n");
+               return command_success;
+       }
+       --breakpoints[b].enabled;
+       breakpoints[b].temporary -= temporary;
+       if (breakpoints[b].enabled == 0) {
+               disable_breakpoint(b);
+               breakpoints[b].address = -1;
+       }
+       return command_success;
+ }
+ int
+ find_breakpoint(uint16_t address)
+ {
+       int b;
+       for (b = 0; b < CC_NUM_BREAKPOINTS; b++)
+               if (breakpoints[b].enabled && breakpoints[b].address == address)
+                       break;
+       if (b == CC_NUM_BREAKPOINTS)
+               return -1;
+       return b;
+ }
+ enum command_result
+ command_break (int argc, char **argv)
+ {
+       int b;
+       uint16_t address;
+       enum command_result result;
+       if (argc == 1) {
+               for (b = 0; b < CC_NUM_BREAKPOINTS; b++)
+                       if (breakpoints[b].enabled)
+                               s51_printf("Breakpoint %d 0x%04x\n",
+                                       b, breakpoints[b].address);
+               return command_success;
+       }
+       if (argc != 2)
+               return command_error;
+       result = parse_uint16(argv[1], &address);
+       if (result != command_success)
+               return result;
+       return set_breakpoint(address, 0);
+ }
+ enum command_result
+ command_clear (int argc, char **argv)
+ {
+       int b;
+       uint16_t address;
+       enum command_result result;
+       if (argc != 2)
+               return command_error;
+       result = parse_uint16(argv[1], &address);
+       if (result != command_success)
+               return result;
+       return clear_breakpoint(address, 0);
+ }
+ void
+ cc_stopped(uint8_t status)
+ {
+       uint16_t pc;
+       int b;
+       int code;
+       char *reason;
+       pc = ccdbg_get_pc(s51_dbg);
+       if (status & CC_STATUS_CPU_HALTED) {
+               if ((status & CC_STATUS_HALT_STATUS) != 0) {
+                       pc = pc - 1;
+                       code = 104;
+                       reason = "Breakpoint";
+                       b = find_breakpoint(pc);
+                       if (b != -1 && breakpoints[b].temporary)
+                               clear_breakpoint(pc, 1);
+                       ccdbg_set_pc(s51_dbg, pc);
+               } else {
+                       code = 105;
+                       reason = "Interrupt";
+               }
+               s51_printf("Stop at 0x%04x: (%d) %s\n",
+                       pc, code, reason);
+       }
+ }
+ uint8_t
+ cc_step(uint16_t pc)
+ {
+       int b;
+       uint8_t status;
+       b = find_breakpoint(pc);
+       if (b != -1)
+               disable_breakpoint(b);
+       status = ccdbg_step_instr(s51_dbg);
+       if (b != -1)
+               enable_breakpoint(b);
+       return status;
+ }
+ enum command_result
+ command_run (int argc, char **argv)
+ {
+       uint16_t start, end;
+       enum command_result result;
+       uint16_t pc;
+       uint8_t status;
+       int b;
 -      
++
+       if (argv[1]) {
+               result = parse_uint16(argv[1], &start);
+               if (result != command_success)
+                       return result;
+               if (argv[2]) {
+                       result = parse_uint16(argv[2], &end);
+                       if (result != command_success)
+                               return result;
+               }
+               if (start_address && start == 0) {
+                       start = start_address;
+                       s51_printf("Starting at 0x%04x\n", start);
+               }
+               ccdbg_set_pc(s51_dbg, start);
+       }
+       else
+               start = ccdbg_get_pc(s51_dbg);
+       s51_printf("Resume at 0x%04x\n", start);
+       pc = start;
+       b = find_breakpoint(pc);
+       if (b != -1) {
+               cc_step(pc);
+               pc = ccdbg_get_pc(s51_dbg);
+               if (find_breakpoint(pc) != -1) {
+                       status = ccdbg_read_status(s51_dbg);
+                       cc_stopped(status);
+                       return command_success;
+               }
+       }
+       ccdbg_resume(s51_dbg);
+       result = cc_wait();
+       return result;
+ }
+ enum command_result
+ command_next (int argc, char **argv)
+ {
+       return command_step(argc, argv);
+ }
+ enum command_result
+ command_step (int argc, char **argv)
+ {
+       uint16_t pc;
+       uint8_t opcode;
+       uint8_t a;
+       a = cc_step(ccdbg_get_pc(s51_dbg));
+       s51_printf(" ACC= 0x%02x\n", a);
+       pc = ccdbg_get_pc(s51_dbg);
+       ccdbg_read_memory(s51_dbg, pc, &opcode, 1);
+       s51_printf(" ? 0x%04x %02x\n", pc, opcode);
+       return command_success;
+ }
+ enum command_result
+ command_load (int argc, char **argv)
+ {
+       char *filename = argv[1];
+       FILE *file;
+       struct hex_file *hex;
+       struct hex_image *image;
 -      
++
+       if (!filename)
+               return command_error;
+       file = fopen(filename, "r");
+       if (!file) {
+               perror(filename);
+               return command_error;
+       }
+       hex = ccdbg_hex_file_read(file, filename);
+       fclose(file);
+       if (!hex) {
+               return command_error;
+       }
+       image = ccdbg_hex_image_create(hex);
+       ccdbg_hex_file_free(hex);
+       if (!image) {
+               fprintf(stderr, "image create failed\n");
+               return command_error;
+       }
+       if (image->address >= 0xf000) {
+               printf("Loading %d bytes to RAM at 0x%04x\n",
+                      image->length, image->address);
+               ccdbg_write_hex_image(s51_dbg, image, 0);
+       } else {
+               fprintf(stderr, "Can only load to RAM\n");
+       }
+       ccdbg_hex_image_free(image);
+       return command_success;
+ }
+ enum command_result
+ command_halt (int argc, char **argv)
+ {
+       uint16_t        pc;
+       ccdbg_halt(s51_dbg);
+       pc = ccdbg_get_pc(s51_dbg);
+       s51_printf("Halted at 0x%04x\n", pc);
+       return command_success;
+ }
+ enum command_result
+ command_stop (int argc, char **argv)
+ {
+       return command_success;
+ }
+ enum command_result
+ command_reset (int argc, char **argv)
+ {
+       ccdbg_debug_mode(s51_dbg);
+       ccdbg_halt(s51_dbg);
+       enable_breakpoints();
+       return command_success;
+ }
+ enum command_result
+ command_status(int argc, char **argv)
+ {
+       uint8_t status;
+       status = ccdbg_read_status(s51_dbg);
+       if ((status & CC_STATUS_CHIP_ERASE_DONE) == 0)
+               s51_printf("\tChip erase in progress\n");
+       if (status & CC_STATUS_PCON_IDLE)
+               s51_printf("\tCPU is idle (clock gated)\n");
+       if (status & CC_STATUS_CPU_HALTED)
+               s51_printf("\tCPU halted\n");
+       else
+               s51_printf("\tCPU running\n");
+       if ((status & CC_STATUS_POWER_MODE_0) == 0)
+               s51_printf("\tPower Mode 1-3 selected\n");
+       if (status & CC_STATUS_HALT_STATUS)
+               s51_printf("\tHalted by software or hw breakpoint\n");
+       else
+               s51_printf("\tHalted by debug command\n");
+       if (status & CC_STATUS_DEBUG_LOCKED)
+               s51_printf("\tDebug interface is locked\n");
+       if ((status & CC_STATUS_OSCILLATOR_STABLE) == 0)
+               s51_printf("\tOscillators are not stable\n");
+       if (status & CC_STATUS_STACK_OVERFLOW)
+               s51_printf("\tStack overflow\n");
+       return command_success;
+ }
+ static enum command_result
+ info_breakpoints(int argc, char **argv)
+ {
+       int b;
+       uint16_t address;
+       enum command_result result;
+       if (argc == 1) {
+               s51_printf("Num Type       Disp Hit   Cnt   Address  What\n");
+               for (b = 0; b < CC_NUM_BREAKPOINTS; b++)
+                       if (breakpoints[b].enabled) {
+                               s51_printf("%-3d fetch      %s 1     1     0x%04x   uc::disass() unimplemented\n",
+                                          b,
+                                          breakpoints[b].temporary ? "del " : "keep",
+                                          breakpoints[b].address);
+                       }
+               return command_success;
+       }
 -      
++
+ }
+ static enum command_result
+ info_help(int argc, char **argv);
+ static struct command_function infos[] = {
+       { "breakpoints", "b", info_breakpoints, "[b]reakpoints",
+               "List current breakpoints\n" },
+       { "help",   "?",  info_help,    "help",
+               "Print this list\n" },
 -      
++
+       { NULL, NULL, NULL, NULL, NULL },
+ };
+ static enum command_result
+ info_help(int argc, char **argv)
+ {
+       return command_function_help(infos, argc, argv);
+ }
+ enum command_result
+ command_info(int argc, char **argv)
+ {
+       struct command_function *func;
 -                      
++
+       if (argc < 2)
+               return command_error;
+       func = command_string_to_function(infos, argv[1]);
+       if (!func)
+               return command_syntax;
+       return (*func->func)(argc-1, argv+1);
+ }
+ enum command_result
+ cc_wait(void)
+ {
+       for(;;) {
+               uint8_t status;
+               status = ccdbg_read_status(s51_dbg);
+               if (status & CC_STATUS_CPU_HALTED) {
+                       cc_stopped(status);
+                       return command_success;
+               }
+               if (s51_interrupted || s51_check_input()) {
 -
++
+                       ccdbg_halt(s51_dbg);
+                       status = ccdbg_read_status(s51_dbg);
+                       cc_stopped(status);
+                       return command_interrupt;
+               }
+       }
+ }
diff --cc s51/s51-main.c
index 0000000,46b97b0..4dbd4c6
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,240 +1,239 @@@
 -                      
+ /*
+  * Copyright © 2008 Keith Packard <keithp@keithp.com>
+  *
+  * 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 "s51.h"
+ #include <unistd.h>
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+ #include <signal.h>
+ #include <stdarg.h>
+ #include <poll.h>
+ static int s51_port = 0;
+ static char *cpu = "8051";
+ static double freq = 11059200;
+ char *s51_prompt = "> ";
+ struct ccdbg *s51_dbg;
+ int s51_interrupted = 0;
+ int s51_monitor = 0;
+ static FILE *s51_input;
+ static FILE *s51_output;
+ static void
+ usage(void)
+ {
+       fprintf(stderr, "You're doing it wrong.\n");
+       exit(1);
+ }
+ void s51_sigint()
+ {
+       s51_interrupted = 1;
+ }
+ int
+ main(int argc, char **argv)
+ {
+       int flags, opt;
+       char *endptr;
+       struct sigvec vec, ovec;
+       while ((opt = getopt(argc, argv, "PVvHhmt:X:c:r:Z:s:S:p:")) != -1) {
+               switch (opt) {
+               case 't':
+                       cpu = optarg;
+                       break;
+               case 'X':
+                       freq = strtod(optarg, &endptr);
+                       if (endptr == optarg)
+                               usage();
+                       if (endptr[0] != '\0') {
+                               if (!strcmp(endptr, "k"))
+                                       freq *= 1000;
+                               else if (!strcmp(endptr, "M") )
+                                       freq *= 1000000;
+                               else
+                                       usage ();
+                       }
+                       break;
+               case 'c':
+                       break;
+               case 'r':
+               case 'Z':
+                       s51_port = strtol(optarg, &endptr, 0);
+                       if (endptr == optarg || strlen(endptr) != 0)
+                               usage();
+                       break;
+               case 's':
+                       break;
+               case 'S':
+                       break;
+               case 'p':
+                       s51_prompt = optarg;
+                       break;
+               case 'P':
+                       s51_prompt = NULL;
+                       break;
+               case 'V':
+                       break;
+               case 'v':
+                       break;
+               case 'H':
+                       exit (0);
+                       break;
+               case 'h':
+                       usage ();
+                       break;
+               case 'm':
+                       s51_monitor = 1;
+                       break;
+               }
+       }
+       if (s51_port) {
+               int l, r, one = 1;
+               int s;
+               struct sockaddr_in in;
+               l = socket(AF_INET, SOCK_STREAM, 0);
+               if (l < 0) {
+                       perror ("socket");
+                       exit(1);
+               }
+               r = setsockopt(l, SOL_SOCKET, SO_REUSEADDR, &one, sizeof (int));
+               if (r) {
+                       perror("setsockopt");
+                       exit(1);
+               }
+               in.sin_family = AF_INET;
+               in.sin_port = htons(s51_port);
+               in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+               r = bind(l, (struct sockaddr *) &in, sizeof (in));
+               if (r) {
+                       perror("bind");
+                       exit(1);
+               }
+               r = listen(l, 5);
+               if (r) {
+                       perror("listen");
+                       exit(1);
+               }
+               for (;;) {
+                       struct sockaddr_in client_addr;
+                       socklen_t client_len = sizeof (struct sockaddr_in);
 -              return 1; 
++
+                       s = accept(l, (struct sockaddr *)
+                                  &client_addr, &client_len);
+                       if (s < 0) {
+                               perror("accept");
+                               exit(1);
+                       }
+                       s51_input = fdopen(s, "r");
+                       s51_output = fdopen(s, "w");
+                       if (!s51_input || !s51_output) {
+                               perror("fdopen");
+                               exit(1);
+                       }
+                       vec.sv_handler = SIG_IGN;
+                       vec.sv_mask = 0;
+                       vec.sv_flags = 0;
+                       sigvec(SIGINT, &vec, &ovec);
+                       command_read();
+                       sigvec(SIGINT, &ovec, NULL);
+                       fclose(s51_input);
+                       fclose(s51_output);
+               }
+       } else {
+               s51_input = stdin;
+               s51_output = stdout;
+               vec.sv_handler = s51_sigint;
+               vec.sv_mask = 0;
+               vec.sv_flags = 0;
+               sigvec(SIGINT, &vec, &ovec);
+               command_read();
+       }
+       exit(0);
+ }
+ void
+ s51_printf(char *format, ...)
+ {
+       va_list ap;
+       va_start(ap, format);
+       vfprintf(s51_output, format, ap);
+       if (s51_monitor)
+               vfprintf(stdout, format, ap);
+       va_end(ap);
+ }
+ void
+ s51_putc(int c)
+ {
+       putc(c, s51_output);
+ }
+ #include <readline/readline.h>
+ #include <readline/history.h>
+ int
+ s51_read_line(char *line, int len)
+ {
+       int ret;
+       if (s51_output == stdout && s51_input == stdin && s51_prompt) {
+               char *r;
+               r = readline(s51_prompt);
+               if (r == NULL)
+                       return 0;
+               strncpy (line, r, len);
+               line[len-1] = '\0';
+               add_history(r);
+               return 1;
+       } else {
+               if (s51_prompt)
+                       s51_printf("%s", s51_prompt);
+               else
+                       s51_putc('\0');
+               fflush(s51_output);
+               ret = fgets(line, len, s51_input) != NULL;
+               if (s51_monitor)
+                       printf("> %s", line);
+               fflush(stdout);
+       }
+       return ret;
+ }
+ int
+ s51_check_input(void)
+ {
+       struct pollfd   input;
+       int r;
+       int c;
+       input.fd = fileno(s51_input);
+       input.events = POLLIN;
+       r = poll(&input, 1, 0);
+       if (r > 0) {
+               char line[256];
+               (void) s51_read_line(line, sizeof (line));
 -
++              return 1;
+       }
+       return 0;
+ }
diff --cc s51/s51-parse.c
index 0000000,aba4548..170c979
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,242 +1,241 @@@
 -}    
+ /*
+  * Copyright © 2008 Keith Packard <keithp@keithp.com>
+  *
+  * 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 "s51.h"
+ static struct command_function functions[] = {
+       { "help",   "?",  command_help, "help",         "Print this list\n" },
+       { "quit",   "q",  command_quit, "[q]uit",       "Quit\n" },
+       { "di",     "di", command_di,   "di <start> <end>",
+               "Dump imem\n" },
+       { "ds",     "ds", command_ds,   "ds <start> <end>",
+               "Dump sprs\n" },
+       { "dx",     "dx", command_dx,   "dx <start> <end>",
+               "Dump xaddr\n" },
+       { "set",    "t",  command_set,  "se[t] mem <prefix> <address> <data> ...",
+               "Set mem {xram|rom|iram|sfr}\n"
+               "set bit <addr>\n" },
+       { "dump",   "d",  command_dump, "[d]ump <prefix> <start> <end>",
+               "Dump {xram|rom|iram|sfr} <start> <end>\n" },
+       { "file", "file", command_file, "file <filename>",
+               "Pretend to load executable from <filename>\n" },
+       { "pc",     "p",  command_pc, "[p]c [addr]",
+               "Get or set pc value\n" },
+       { "break",  "b",  command_break,"[b]reak <addr>",
+               "Set break point\n" },
+       { "clear",  "c",  command_clear,"[c]lear <addr>",
+               "Clear break point\n" },
+       { "run",    "r",  command_run, "[r]un [start] [stop]",
+               "Run with optional start and temp breakpoint addresses\n" },
+       { "go",     "g",  command_run, "[g]o [start] [stop]",
+               "Run with optional start and temp breakpoint addresses\n" },
+       { "next",   "n",  command_next, "[n]ext",
+               "Step over one instruction, past any call\n" },
+       { "step",   "s",  command_step, "[s]tep",
+               "Single step\n" },
+       { "load",   "l",  command_load, "[l]oad <file>",
+               "Load a hex file into memory or flash" },
+       { "halt",   "h",  command_halt, "[h]alt",
+               "Halt the processor\n" },
+       { "reset","res",command_reset,  "[res]et",
+               "Reset the CPU\n" },
+       { "status","status",command_status, "status",
+               "Display CC1111 debug status\n" },
+       { "info",   "i",  command_info, "[i]info",
+               "Get information\n" },
+       { "stop",  "stop", command_stop, "stop",
+               "Ignored\n" },
+       { NULL, NULL, NULL, NULL, NULL },
+ };
+ #ifndef FALSE
+ #define FALSE 0
+ #define TRUE 1
+ #endif
+ static int
+ string_to_int(char *s, int *v)
+ {
+       char *endptr;
+       if (isdigit(s[0]) || s[0] == '-' || s[0] == '+') {
+               *v = strtol(s, &endptr, 0);
+               if (endptr == s)
+                       return FALSE;
+       } else if (*s == '\'') {
+               s++;
+               if (*s == '\\') {
+                       s++;
+                       switch (*s) {
+                       case 'n':
+                               *v = '\n';
+                               break;
+                       case 't':
+                               *v = '\t';
+                               break;
+                       default:
+                               *v = (int) *s;
+                               break;
+                       }
+               } else
+                       *v = (int) *s;
+               s++;
+               if (*s != '\'')
+                       return FALSE;
+       }
+       else
+               return FALSE;
+     return TRUE;
+ }
+ struct command_function *
+ command_string_to_function(struct command_function *functions, char *name)
+ {
+       int i;
+       for (i = 0; functions[i].name; i++)
+               if (!strcmp(name, functions[i].name) ||
+                   !strcmp(name, functions[i].alias))
+                       return &functions[i];
+       return NULL;
 -    
++}
+ enum command_result
+ command_function_help(struct command_function *functions, int argc, char **argv)
+ {
+       int i;
+       struct command_function *func;
+       if (argc == 1) {
+               for (i = 0; functions[i].name; i++)
+                       s51_printf("%-10s%s\n", functions[i].name,
+                              functions[i].usage);
+       } else {
+               for (i = 1; i < argc; i++) {
+                       func = command_string_to_function(functions, argv[i]);
+                       if (!func) {
+                               s51_printf("%-10s unknown command\n", argv[i]);
+                               return command_syntax;
+                       }
+                       s51_printf("%-10s %s\n%s", func->name,
+                              func->usage, func->help);
+               }
+       }
+       return command_debug;
+ }
+ static int
+ command_split_into_words(char *line, char **argv)
+ {
+       char quotechar;
+       int argc;
+       argc = 0;
+       while (*line) {
+               while (isspace(*line))
+                       line++;
+               if (!*line)
+                       break;
+               if (*line == '"') {
+                       quotechar = *line++;
+                       *argv++ = line;
+                       argc++;
+                       while (*line && *line != quotechar)
+                               line++;
+                       if (*line)
+                               *line++ = '\0';
+               } else {
+                       *argv++ = line;
+                       argc++;
+                       while (*line && !isspace(*line))
+                               line++;
+                       if (*line)
+                               *line++ = '\0';
+               }
+       }
+       *argv = 0;
+       return argc;
+ }
+ enum command_result
+ command_help(int argc, char **argv)
+ {
+       return command_function_help(functions, argc, argv);
+ }
 -
++
+ void
+ command_syntax_error(int argc, char **argv)
+ {
+       s51_printf("Syntax error in:");
+       while (*argv)
+               s51_printf(" %s", *argv++);
+       s51_printf("\n");
+ }
+ void
+ command_read (void)
+ {
+       int argc;
+       char line[1024];
+       char *argv[20];
+       enum command_result result;
+       struct command_function *func;
+       s51_dbg = ccdbg_open ();
+       if (!s51_dbg) {
+               perror("ccdbg_open");
+               exit(1);
+       }
+       ccdbg_debug_mode(s51_dbg);
+       ccdbg_halt(s51_dbg);
+       s51_printf("Welcome to the non-simulated processor\n");
+       for (;;) {
+               if (s51_read_line (line, sizeof line) == 0)
+                       break;
+               s51_interrupted = 0;
+               argc = command_split_into_words(line, argv);
+               if (argc > 0) {
+                       func = command_string_to_function(functions, argv[0]);
+                       if (!func)
+                               command_syntax_error(argc, argv);
+                       else
+                       {
+                               result = (*func->func)(argc, argv);
+                               if (s51_interrupted)
+                                       result = command_interrupt;
+                               switch (result) {
+                               case command_syntax:
+                                       command_syntax_error(argc, argv);
+                                       break;
+                               case command_error:
+                                       s51_printf("Error\n");
+                                       break;
+                               case command_success:
+                                       break;
+                               case command_interrupt:
+                                       ccdbg_halt(s51_dbg);
+                                       s51_printf("Interrupted\n");
+                                       break;
+                               default:
+                                       break;
+                               }
+                       }
+               }
+       }
+       ccdbg_close(s51_dbg);
+       s51_printf("...\n");
+ }
diff --cc s51/s51.1
index 0000000,c283950..f2f59a5
mode 000000,100644..100644
--- /dev/null
+++ b/s51/s51.1
@@@ -1,0 -1,211 +1,211 @@@
 -.PP 
+ .\"
+ .\" Copyright © 2009 Keith Packard <keithp@keithp.com>
+ .\"
+ .\" 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.
+ .\"
+ .\"
+ .TH S51 1 "s51" ""
+ .SH NAME
+ s51 \- hex debugger for cc1111 processors
+ .SH SYNOPSIS
+ .B "s51"
+ [\-t \fIcpu-type\fP]
+ [\-X \fIfrequency\fP]
+ [\-c]
+ [\-r \fIlisten-port\fP]
+ [\-Z \fIlisten-port\fP]
+ [\-s]
+ [\-S]
+ [\-p \fIprompt\fP]
+ [\-V]
+ [\-v]
+ [\-H]
+ [\-h]
+ [\-m]
+ .SH DESCRIPTION
+ .I s51
+ connects to a cc1111 processor through a cp1203-based USB-to-serial
+ converter board, using the GPIO pins available on that chip. It provides an
+ interface compatible with the 8051 emulator of the same name (s51), but
+ communicating with the real chip instead of an emulation. Using a modified
+ version of the SDCC debugger (sdcdb), you can control program execution
+ on the target machine at source-level.
+ .SH OPTIONS
+ The command line options are designed to be compatible with the 8051
+ emulator so that it can be used with sdcdb. As such, they're all one letter
+ long.
+ .IP "\-t \fIcpu-type\fP"
+ The 8051 emulator can operate as one of several different chips. Oddly, the
+ real hardware cannot, so this option is ignored.
+ .IP "\-X \fIfrequency\fP"
+ Similarly, the emulator can pretend to run at an arbitrary frequency
+ which the real hardware cannot do. Ignored.
+ .IP "\-c"
+ .IP "\-s"
+ .IP "\-S"
+ .IP "\-v"
+ .IP "\-V"
+ All ignored.
+ .IP "\-r \fIlisten-port\fP, -Z \fIlisten-port\fP"
+ The emulator and sdcdb communicate through a network socket. This option
+ switches the debugger from communicating through stdin/stdout to listening
+ on a specific network port instead. Once a connection is made, the debugger
+ continues on, using that network port for command input and output. The
+ debugger uses port 9756, and attempts to connect before launching s51, so if
+ s51 is listening on this port before sdcdb is started, sdcdb will end up
+ talking to the existing s51 instance. That's often useful for debugging s51
+ itself.
+ .IP "\-p \fIprompt\fP"
+ This sets the command prompt to the specified string.
+ .IP "\-P"
+ This sets the command prompt to a single NUL character. This is for use by
+ sdcdb.
+ .IP "\-h"
+ This should print a usage message, but does nothing useful currently.
+ .IP "\-m"
+ This option is not present in the original 8051 emulator, and causes s51 to
+ dump all commands and replies that are received from and sent to sdcdb.
+ .SH COMMANDS
+ Once started, s51 connects to the cc1111 via the CP2103 using libusb2 and
+ then reads and executes commands, either from stdin, or the nework
+ connection to sdcdb.
+ .PP
+ Unlike the command line, s51 contains built-in help for each of these
+ commands, via the 'help' command. Most of the commands are available in a
+ long form and a single character short form. Below, the short form follows
+ the long form after a comma.
+ .IP "help, ? {command}"
+ Without arguments, prints a list of available commands. With an argument
+ prints more detail about the specific command
+ .IP "quit, q"
+ Terminates the application, without changing the state of the target
+ processor.
+ .IP "di [start] [end]"
+ Dumps imem (256 bytes of "internal" memory) from start to end (inclusive).
+ .IP "ds [start] [end]"
+ Dumps sprs from start to end (inclusive). Note that while most sprs are
+ visible in the global address space, some are not, so use this command
+ instead of "dx" to read them.
+ .IP "dx [start] [end]"
+ Dump external (global) memory from start to end (inclusive).
+ .IP "set, t <prefix> [start] {data ...}"
+ Store to the memory space specified by prefix where prefix is one of "xram",
+ "rom", "iram", or "sfr". Store bytes starting at start.
+ .IP "dump, d <prefix> [start] [end]"
+ Dump from the memory space specified by prefix, where prefix is one of
+ "xram", "rom", "iram" or "sfr". Dumps from start to end (inclusive).
+ .IP "file [filename]"
+ Specifies an intel-format hex file (ihx) that contains the contents of the
+ rom area loaded into the cc1111. This is used to respond to requests to dump
+ rom memory contents without getting them from the cc1111 (which is slow).
+ .IP "pc, p {address}"
+ If the address argument is given, this sets the program counter to the
+ specified value. Otherwise, the current program counter value is displayed.
+ .IP "break, b [address]"
+ Sets a breakpoint at the specified address. This uses the built-in hardware
+ breakpoint support in the cc1111. As a result, it supports no more than four
+ breakpoints at once. You must therefore use a modified version of sdcdb which
+ changes how program execution is controlled to work within this limit.
+ .IP "clear, c [address]"
+ Clear a breakpoint from the specified address.
+ .IP "run, r, go, g {start} {stop}"
+ Resumes execution of the program. If the start argument is present, then it
+ begins at that address, otherwise it continues running at the current pc. If
+ a stop argument is present, then a temporary breakpoint is set at that
+ address. This temporary breakpoint will be removed when execution hits it.
+ .IP "next, n"
+ Step one instruction. In the original s51 program this would ignore
+ subroutines, but as sdcdb doesn't require this functionality, it's not
+ available here.
+ .IP "step, s"
+ Step one instruction.
+ .IP "load, l [filename]"
+ This is not implemented, but it is supposed to load a hex file into flash.
+ Use the ccload program instead.
+ .IP "halt, h"
+ Halt the processor. This is the only command which can be sent while the
+ program is running. It is ignored at other times.
+ .IP "reset, res"
+ Reset the processor. This pulls the reset pin low and re-enables debug mode.
+ Check the cc1111 documentation to see precisely what this does.
+ .IP "status"
+ This dumps the cc1111 debug status register.
+ .IP "info, i breakpoints, b"
+ List the current breakpoints.
+ .IP "info, i help, ?"
+ List the things you can get info on.
+ .IP "stop"
+ This doesn't do anything and is present only to retain compatibility with
+ the original 8051 emulator.
+ .SH "BOARD BRINGUP DEBUGGING"
 -\'s51\' command itself should connect to the device without trouble. 
++.PP
+ While the original purpose for this program was to connect the source
+ debugger with the hardware, it can also be used as a low-level hex debugger
+ all on its own. In particular, all of the cc1111 peripherals can be
+ manipulated directly from the s51 command line.
+ .IP "Starting s51"
+ If the CP2103 is plugged in, and the CC1111 is connected correctly, the
++\'s51\' command itself should connect to the device without trouble.
+ Note that the CP2103 must have the GPIO pins configured correctly as well.
+ .IP
+ $ s51
+ .br
+ Welcome to the non-simulated processor
+ .br
+ > status
+ .br
+       CPU halted
+ .br
+       Halted by debug command
+ .br
+ >
+ .IP "Turning on LEDs"
+ Two of the cc1111 GPIO pins, P1_0 and P1_1 are capable of driving external
+ LEDs. To control these, set the Port 1 direction bits to make these output
+ pins and then change the Port 1 data to set them high or low:
+ .IP
+ > set sfr 0xfe 0x02   # set P1DIR to 0x2
+ .br
+ > set sfr 0x90 0x02   # set P1_1 to high
+ .br
+ > set sfr 0x90 0x00   # set P1_1 to low
+ .IP "Reading the A/D converters"
+ The six A/D converter inputs can each be connected to any of the P0 pins,
+ ground, the A/D voltage refernece, an internal temperature sensor or VDD/3.
+ To read one of these values, select an A/D converter to use then start the
+ conversion process. The cc1111 manual has the table for selecting the input
+ on page 144.
+ .IP
+ To configure one of the P0 pins for use by the A/D unit, we program the
+ ADCCFG register, setting the bits in that which match the pins desired:
+ .IP
+ > set sfr 0xf2 0x3f   # enable all 6 A/D inputs
+ .IP
+ To trigger a single conversion, we ask the A/D unit to perform an 'extra'
+ conversion, which means to do a single conversion not a whole sequence of
+ conversions. This is controlled by the ADCCON3 register at 0xB6:
+ .IP
+ > set sfr 0xb6 0xb2   # sample P0_2 using 12 bits of precision
+ .br
+ > ds 0xba 0xbb                # dump the ADC data low and high regs
+ .br
+ > set sfr 0xb6 0xbe   # sample internal temperature sensor
+ .br
+ > ds 0xba 0xbb                # dump the ADC data low and high regs
+ .SH "SEE ALSO"
+ sdcdb(1), ccload(1)
+ .SH AUTHOR
+ Keith Packard
index 0000000,eba5874..1f7b688
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,578 +1,578 @@@
 -      
+ /*
+  * Copyright © 2008 Keith Packard <keithp@keithp.com>
+  *
+  * 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 <stdint.h>
+ /*
+  * Test ADC in DMA mode
+  */
+ sfr at 0x80 P0;
+ sfr at 0x90 P1;
+ sfr at 0xA0 P2;
+ sfr at 0xC6 CLKCON;
+ sfr at 0xbe SLEEP;
+ # define SLEEP_USB_EN         (1 << 7)
+ # define SLEEP_XOSC_STB               (1 << 6)
+ sfr at 0xF1 PERCFG;
+ #define PERCFG_T1CFG_ALT_1    (0 << 6)
+ #define PERCFG_T1CFG_ALT_2    (1 << 6)
+ #define PERCFG_T3CFG_ALT_1    (0 << 5)
+ #define PERCFG_T3CFG_ALT_2    (1 << 5)
+ #define PERCFG_T4CFG_ALT_1    (0 << 4)
+ #define PERCFG_T4CFG_ALT_2    (1 << 4)
+ #define PERCFG_U1CFG_ALT_1    (0 << 1)
+ #define PERCFG_U1CFG_ALT_2    (1 << 1)
+ #define PERCFG_U0CFG_ALT_1    (0 << 0)
+ #define PERCFG_U0CFG_ALT_2    (1 << 0)
+ sfr at 0xF2 ADCCFG;
+ sfr at 0xF3 P0SEL;
+ sfr at 0xF4 P1SEL;
+ sfr at 0xF5 P2SEL;
+ sfr at 0xFD P0DIR;
+ sfr at 0xFE P1DIR;
+ sfr at 0xFF P2DIR;
+ sfr at 0x8F P0INP;
+ sfr at 0xF6 P1INP;
+ sfr at 0xF7 P2INP;
+ sfr at 0x89 P0IFG;
+ sfr at 0x8A P1IFG;
+ sfr at 0x8B P2IFG;
+ sbit at 0x90 P1_0;
+ sbit at 0x91 P1_1;
+ sbit at 0x92 P1_2;
+ sbit at 0x93 P1_3;
+ sbit at 0x94 P1_4;
+ sbit at 0x95 P1_5;
+ sbit at 0x96 P1_6;
+ sbit at 0x97 P1_7;
+ /*
+  * UART registers
+  */
+ sfr at 0x86 U0CSR;
+ sfr at 0xF8 U1CSR;
+ /*
+  * IRCON2
+  */
+ sfr at 0xE8 IRCON2;   /* CPU Interrupt Flag 5 */
+ sbit at 0xE8 USBIF;   /* USB interrupt flag (shared with Port2) */
+ sbit at 0xE8 P2IF;    /* Port2 interrupt flag (shared with USB) */
+ sbit at 0xE9 UTX0IF;  /* USART0 TX interrupt flag */
+ sbit at 0xEA UTX1IF;  /* USART1 TX interrupt flag (shared with I2S TX) */
+ sbit at 0xEA I2STXIF; /* I2S TX interrupt flag (shared with USART1 TX) */
+ sbit at 0xEB P1IF;    /* Port1 interrupt flag */
+ sbit at 0xEC WDTIF;   /* Watchdog timer interrupt flag */
+ # define UxCSR_MODE_UART              (1 << 7)
+ # define UxCSR_MODE_SPI                       (0 << 7)
+ # define UxCSR_RE                     (1 << 6)
+ # define UxCSR_SLAVE                  (1 << 5)
+ # define UxCSR_MASTER                 (0 << 5)
+ # define UxCSR_FE                     (1 << 4)
+ # define UxCSR_ERR                    (1 << 3)
+ # define UxCSR_RX_BYTE                        (1 << 2)
+ # define UxCSR_TX_BYTE                        (1 << 1)
+ # define UxCSR_ACTIVE                 (1 << 0)
+ sfr at 0xc4 U0UCR;
+ sfr at 0xfb U1UCR;
+ # define UxUCR_FLUSH                  (1 << 7)
+ # define UxUCR_FLOW_DISABLE           (0 << 6)
+ # define UxUCR_FLOW_ENABLE            (1 << 6)
+ # define UxUCR_D9_EVEN_PARITY         (0 << 5)
+ # define UxUCR_D9_ODD_PARITY          (1 << 5)
+ # define UxUCR_BIT9_8_BITS            (0 << 4)
+ # define UxUCR_BIT9_9_BITS            (1 << 4)
+ # define UxUCR_PARITY_DISABLE         (0 << 3)
+ # define UxUCR_PARITY_ENABLE          (1 << 3)
+ # define UxUCR_SPB_1_STOP_BIT         (0 << 2)
+ # define UxUCR_SPB_2_STOP_BITS                (1 << 2)
+ # define UxUCR_STOP_LOW                       (0 << 1)
+ # define UxUCR_STOP_HIGH              (1 << 1)
+ # define UxUCR_START_LOW              (0 << 0)
+ # define UxUCR_START_HIGH             (1 << 0)
+ sfr at 0xc5 U0GCR;
+ sfr at 0xfc U1GCR;
+ # define UxGCR_CPOL_NEGATIVE          (0 << 7)
+ # define UxGCR_CPOL_POSITIVE          (1 << 7)
+ # define UxGCR_CPHA_FIRST_EDGE                (0 << 6)
+ # define UxGCR_CPHA_SECOND_EDGE               (1 << 6)
+ # define UxGCR_ORDER_LSB              (0 << 5)
+ # define UxGCR_ORDER_MSB              (1 << 5)
+ # define UxGCR_BAUD_E_MASK            (0x1f)
+ # define UxGCR_BAUD_E_SHIFT           0
+ sfr at 0xc1 U0DBUF;
+ sfr at 0xf9 U1DBUF;
+ sfr at 0xc2 U0BAUD;
+ sfr at 0xfa U1BAUD;
+ #define DEBUG P1_1
+ # define DMA_LEN_HIGH_VLEN_MASK               (7 << 5)
+ # define DMA_LEN_HIGH_VLEN_LEN                (0 << 5)
+ # define DMA_LEN_HIGH_VLEN_PLUS_1     (1 << 5)
+ # define DMA_LEN_HIGH_VLEN            (2 << 5)
+ # define DMA_LEN_HIGH_VLEN_PLUS_2     (3 << 5)
+ # define DMA_LEN_HIGH_VLEN_PLUS_3     (4 << 5)
+ # define DMA_LEN_HIGH_MASK            (0x1f)
+ # define DMA_CFG0_WORDSIZE_8          (0 << 7)
+ # define DMA_CFG0_WORDSIZE_16         (1 << 7)
+ # define DMA_CFG0_TMODE_MASK          (3 << 5)
+ # define DMA_CFG0_TMODE_SINGLE                (0 << 5)
+ # define DMA_CFG0_TMODE_BLOCK         (1 << 5)
+ # define DMA_CFG0_TMODE_REPEATED_SINGLE       (2 << 5)
+ # define DMA_CFG0_TMODE_REPEATED_BLOCK        (3 << 5)
+ /*
+  * DMA triggers
+  */
+ # define DMA_CFG0_TRIGGER_NONE                0
+ # define DMA_CFG0_TRIGGER_PREV                1
+ # define DMA_CFG0_TRIGGER_T1_CH0      2
+ # define DMA_CFG0_TRIGGER_T1_CH1      3
+ # define DMA_CFG0_TRIGGER_T1_CH2      4
+ # define DMA_CFG0_TRIGGER_T2_OVFL     6
+ # define DMA_CFG0_TRIGGER_T3_CH0      7
+ # define DMA_CFG0_TRIGGER_T3_CH1      8
+ # define DMA_CFG0_TRIGGER_T4_CH0      9
+ # define DMA_CFG0_TRIGGER_T4_CH1      10
+ # define DMA_CFG0_TRIGGER_IOC_0               12
+ # define DMA_CFG0_TRIGGER_IOC_1               13
+ # define DMA_CFG0_TRIGGER_URX0                14
+ # define DMA_CFG0_TRIGGER_UTX0                15
+ # define DMA_CFG0_TRIGGER_URX1                16
+ # define DMA_CFG0_TRIGGER_UTX1                17
+ # define DMA_CFG0_TRIGGER_FLASH               18
+ # define DMA_CFG0_TRIGGER_RADIO               19
+ # define DMA_CFG0_TRIGGER_ADC_CHALL   20
+ # define DMA_CFG0_TRIGGER_ADC_CH0     21
+ # define DMA_CFG0_TRIGGER_ADC_CH1     22
+ # define DMA_CFG0_TRIGGER_ADC_CH2     23
+ # define DMA_CFG0_TRIGGER_ADC_CH3     24
+ # define DMA_CFG0_TRIGGER_ADC_CH4     25
+ # define DMA_CFG0_TRIGGER_ADC_CH5     26
+ # define DMA_CFG0_TRIGGER_ADC_CH6     27
+ # define DMA_CFG0_TRIGGER_I2SRX               27
+ # define DMA_CFG0_TRIGGER_ADC_CH7     28
+ # define DMA_CFG0_TRIGGER_I2STX               28
+ # define DMA_CFG0_TRIGGER_ENC_DW      29
+ # define DMA_CFG0_TRIGGER_DNC_UP      30
+ # define DMA_CFG1_SRCINC_MASK         (3 << 6)
+ # define DMA_CFG1_SRCINC_0            (0 << 6)
+ # define DMA_CFG1_SRCINC_1            (1 << 6)
+ # define DMA_CFG1_SRCINC_2            (2 << 6)
+ # define DMA_CFG1_SRCINC_MINUS_1      (3 << 6)
+ # define DMA_CFG1_DESTINC_MASK                (3 << 4)
+ # define DMA_CFG1_DESTINC_0           (0 << 4)
+ # define DMA_CFG1_DESTINC_1           (1 << 4)
+ # define DMA_CFG1_DESTINC_2           (2 << 4)
+ # define DMA_CFG1_DESTINC_MINUS_1     (3 << 4)
+ # define DMA_CFG1_IRQMASK             (1 << 3)
+ # define DMA_CFG1_M8                  (1 << 2)
+ # define DMA_CFG1_PRIORITY_MASK               (3 << 0)
+ # define DMA_CFG1_PRIORITY_LOW                (0 << 0)
+ # define DMA_CFG1_PRIORITY_NORMAL     (1 << 0)
+ # define DMA_CFG1_PRIORITY_HIGH               (2 << 0)
+ /*
+  * DMAARM - DMA Channel Arm
+  */
+ sfr at 0xD6 DMAARM;
+ # define DMAARM_ABORT                 (1 << 7)
+ # define DMAARM_DMAARM4                       (1 << 4)
+ # define DMAARM_DMAARM3                       (1 << 3)
+ # define DMAARM_DMAARM2                       (1 << 2)
+ # define DMAARM_DMAARM1                       (1 << 1)
+ # define DMAARM_DMAARM0                       (1 << 0)
+ /*
+  * DMAREQ - DMA Channel Start Request and Status
+  */
+ sfr at 0xD7 DMAREQ;
+ # define DMAREQ_DMAREQ4                       (1 << 4)
+ # define DMAREQ_DMAREQ3                       (1 << 3)
+ # define DMAREQ_DMAREQ2                       (1 << 2)
+ # define DMAREQ_DMAREQ1                       (1 << 1)
+ # define DMAREQ_DMAREQ0                       (1 << 0)
+ /*
+  * DMA configuration 0 address
+  */
+ sfr at 0xD5 DMA0CFGH;
+ sfr at 0xD4 DMA0CFGL;
+ /*
+  * DMA configuration 1-4 address
+  */
+ sfr at 0xD3 DMA1CFGH;
+ sfr at 0xD2 DMA1CFGL;
+ /*
+  * DMAIRQ - DMA Interrupt Flag
+  */
+ sfr at 0xD1 DMAIRQ;
+ # define DMAIRQ_DMAIF4                        (1 << 4)
+ # define DMAIRQ_DMAIF3                        (1 << 3)
+ # define DMAIRQ_DMAIF2                        (1 << 2)
+ # define DMAIRQ_DMAIF1                        (1 << 1)
+ # define DMAIRQ_DMAIF0                        (1 << 0)
+ struct cc_dma_channel {
+       uint8_t src_high;
+       uint8_t src_low;
+       uint8_t dst_high;
+       uint8_t dst_low;
+       uint8_t len_high;
+       uint8_t len_low;
+       uint8_t cfg0;
+       uint8_t cfg1;
+ };
+ /*
+  * ADC Data register, low and high
+  */
+ sfr at 0xBA ADCL;
+ sfr at 0xBB ADCH;
+ __xdata __at (0xDFBA) volatile uint16_t ADCXDATA;
+ /*
+  * ADC Control Register 1
+  */
+ sfr at 0xB4 ADCCON1;
+ # define ADCCON1_EOC          (1 << 7)        /* conversion complete */
+ # define ADCCON1_ST           (1 << 6)        /* start conversion */
+ # define ADCCON1_STSEL_MASK   (3 << 4)        /* start select */
+ # define ADCCON1_STSEL_EXTERNAL       (0 << 4)        /* P2_0 pin triggers */
+ # define ADCCON1_STSEL_FULLSPEED (1 << 4)     /* full speed, no waiting */
+ # define ADCCON1_STSEL_TIMER1 (2 << 4)        /* timer 1 channel 0 */
+ # define ADCCON1_STSEL_START  (3 << 4)        /* set start bit */
+ # define ADCCON1_RCTRL_MASK   (3 << 2)        /* random number control */
+ # define ADCCON1_RCTRL_COMPLETE       (0 << 2)        /* operation completed */
+ # define ADCCON1_RCTRL_CLOCK_LFSR (1 << 2)    /* Clock the LFSR once */
+ /*
+  * ADC Control Register 2
+  */
+ sfr at 0xB5 ADCCON2;
+ # define ADCCON2_SREF_MASK    (3 << 6)        /* reference voltage */
+ # define ADCCON2_SREF_1_25V   (0 << 6)        /* internal 1.25V */
+ # define ADCCON2_SREF_EXTERNAL        (1 << 6)        /* external on AIN7 cc1110 */
+ # define ADCCON2_SREF_VDD     (2 << 6)        /* VDD on the AVDD pin */
+ # define ADCCON2_SREF_EXTERNAL_DIFF (3 << 6)  /* external on AIN6-7 cc1110 */
+ # define ADCCON2_SDIV_MASK    (3 << 4)        /* decimation rate */
+ # define ADCCON2_SDIV_64      (0 << 4)        /* 7 bits */
+ # define ADCCON2_SDIV_128     (1 << 4)        /* 9 bits */
+ # define ADCCON2_SDIV_256     (2 << 4)        /* 10 bits */
+ # define ADCCON2_SDIV_512     (3 << 4)        /* 12 bits */
+ # define ADCCON2_SCH_MASK     (0xf << 0)      /* Sequence channel select */
+ # define ADCCON2_SCH_SHIFT    0
+ # define ADCCON2_SCH_AIN0     (0 << 0)
+ # define ADCCON2_SCH_AIN1     (1 << 0)
+ # define ADCCON2_SCH_AIN2     (2 << 0)
+ # define ADCCON2_SCH_AIN3     (3 << 0)
+ # define ADCCON2_SCH_AIN4     (4 << 0)
+ # define ADCCON2_SCH_AIN5     (5 << 0)
+ # define ADCCON2_SCH_AIN6     (6 << 0)
+ # define ADCCON2_SCH_AIN7     (7 << 0)
+ # define ADCCON2_SCH_AIN0_AIN1        (8 << 0)
+ # define ADCCON2_SCH_AIN2_AIN3        (9 << 0)
+ # define ADCCON2_SCH_AIN4_AIN5        (0xa << 0)
+ # define ADCCON2_SCH_AIN6_AIN7        (0xb << 0)
+ # define ADCCON2_SCH_GND      (0xc << 0)
+ # define ADCCON2_SCH_VREF     (0xd << 0)
+ # define ADCCON2_SCH_TEMP     (0xe << 0)
+ # define ADCCON2_SCH_VDD_3    (0xf << 0)
+ /*
+  * ADC Control Register 3
+  */
+ sfr at 0xB6 ADCCON3;
+ # define ADCCON3_EREF_MASK    (3 << 6)        /* extra conversion reference */
+ # define ADCCON3_EREF_1_25    (0 << 6)        /* internal 1.25V */
+ # define ADCCON3_EREF_EXTERNAL        (1 << 6)        /* external AIN7 cc1110 */
+ # define ADCCON3_EREF_VDD     (2 << 6)        /* VDD on the AVDD pin */
+ # define ADCCON3_EREF_EXTERNAL_DIFF (3 << 6)  /* external AIN6-7 cc1110 */
+ # define ADCCON2_EDIV_MASK    (3 << 4)        /* extral decimation */
+ # define ADCCON2_EDIV_64      (0 << 4)        /* 7 bits */
+ # define ADCCON2_EDIV_128     (1 << 4)        /* 9 bits */
+ # define ADCCON2_EDIV_256     (2 << 4)        /* 10 bits */
+ # define ADCCON2_EDIV_512     (3 << 4)        /* 12 bits */
+ # define ADCCON3_ECH_MASK     (0xf << 0)      /* Sequence channel select */
+ # define ADCCON3_ECH_SHIFT    0
+ # define ADCCON3_ECH_AIN0     (0 << 0)
+ # define ADCCON3_ECH_AIN1     (1 << 0)
+ # define ADCCON3_ECH_AIN2     (2 << 0)
+ # define ADCCON3_ECH_AIN3     (3 << 0)
+ # define ADCCON3_ECH_AIN4     (4 << 0)
+ # define ADCCON3_ECH_AIN5     (5 << 0)
+ # define ADCCON3_ECH_AIN6     (6 << 0)
+ # define ADCCON3_ECH_AIN7     (7 << 0)
+ # define ADCCON3_ECH_AIN0_AIN1        (8 << 0)
+ # define ADCCON3_ECH_AIN2_AIN3        (9 << 0)
+ # define ADCCON3_ECH_AIN4_AIN5        (0xa << 0)
+ # define ADCCON3_ECH_AIN6_AIN7        (0xb << 0)
+ # define ADCCON3_ECH_GND      (0xc << 0)
+ # define ADCCON3_ECH_VREF     (0xd << 0)
+ # define ADCCON3_ECH_TEMP     (0xe << 0)
+ # define ADCCON3_ECH_VDD_3    (0xf << 0)
+ sfr at 0xF2 ADCCFG;
+ #define nop() _asm nop _endasm;
+ void
+ delay (unsigned char n)
+ {
+       unsigned char i = 0;
+       unsigned char j = 0;
+       n++;
+       while (--n != 0)
+               while (--i != 0)
+                       while (--j != 0)
+                               nop();
+ }
+ void
+ debug_byte(uint8_t byte)
+ {
+       uint8_t s;
+       for (s = 0; s < 8; s++) {
+               DEBUG = byte & 1;
+               delay(5);
+               byte >>= 1;
+       }
+ }
+ struct cc_dma_channel __xdata dma_config;
+ #define ADC_LEN       6
+ /* The DMA engine writes to XDATA in MSB order */
+ struct dma_xdata16 {
+       uint8_t high;
+       uint8_t low;
+ };
+ struct dma_xdata16 adc_output[ADC_LEN];
+ #define DMA_XDATA16(a,n)      ((uint16_t) ((a)[n].high << 8) | (uint16_t) (a[n].low))
+ #define ADDRH(a)      (((uint16_t) (a)) >> 8)
+ #define ADDRL(a)      (((uint16_t) (a)))
+ void
+ adc_init(void)
+ {
+       dma_config.cfg0 = (DMA_CFG0_WORDSIZE_16 |
+                          DMA_CFG0_TMODE_REPEATED_SINGLE |
+                          DMA_CFG0_TRIGGER_ADC_CHALL);
+       dma_config.cfg1 = (DMA_CFG1_SRCINC_0 |
+                          DMA_CFG1_DESTINC_1 |
+                          DMA_CFG1_PRIORITY_NORMAL);
 -      
++
+       dma_config.src_high = ADDRH(&ADCXDATA);
+       dma_config.src_low = ADDRL(&ADCXDATA);
+       dma_config.dst_high = ADDRH(adc_output);
+       dma_config.dst_low = ADDRL(adc_output);
+       dma_config.len_high = 0;
+       dma_config.len_low = ADC_LEN;
+       DMA0CFGH = ADDRH(&dma_config);
+       DMA0CFGL = ADDRL(&dma_config);
+       ADCCFG = ((1 << 0) |    /* acceleration */
+                 (1 << 1) |    /* pressure */
+                 (1 << 2) |    /* temperature */
+                 (1 << 3) |    /* battery voltage */
+                 (1 << 4) |    /* drogue sense */
+                 (1 << 5));    /* main sense */
 -      
++
+       ADCCON1 = (ADCCON1_STSEL_START);        /* ST bit triggers */
+       ADCCON2 = (ADCCON2_SREF_VDD |           /* reference voltage is VDD */
+                  ADCCON2_SDIV_512 |           /* 12 bit ADC results */
+                  ADCCON2_SCH_AIN5);           /* sample all 6 inputs */
+ }
+ void
+ adc_run(void)
+ {
+       DMAIRQ &= ~1;
+       DMAARM |= 1;
+       ADCCON1 |= ADCCON1_ST;
+       while ((DMAIRQ & 1) == 0)
+               ;
+ }
+ /*
+  * This version uses the USART in UART mode
+  */
+ void
+ usart_init(void)
+ {
+       P1DIR |= (1 << 2);
+       /*
+        * Configure the peripheral pin choices
+        * for both of the serial ports
+        *
+        * Note that telemetrum will use U1CFG_ALT_2
+        * but that overlaps with SPI ALT_2, so until
+        * we can test that this works, we'll set this
+        * to ALT_1
+        */
+       PERCFG = (PERCFG_U1CFG_ALT_2 |
+                 PERCFG_U0CFG_ALT_1);
+       /*
+        * Make the UART pins controlled by the UART
+        * hardware
+        */
+       P1SEL |= ((1 << 6) | (1 << 7));
+       /*
+        * UART mode with the receiver enabled
+        */
+       U1CSR = (UxCSR_MODE_UART |
+                UxCSR_RE);
+       /*
+        * Pick a 38.4kbaud rate
+        */
+       U1BAUD = 163;
+       U1GCR = 10 << UxGCR_BAUD_E_SHIFT;       /* 38400 */
+ //    U1GCR = 3 << UxGCR_BAUD_E_SHIFT;        /* 300 */
+       /*
+        * Reasonable serial parameters
+        */
+       U1UCR = (UxUCR_FLUSH |
+                UxUCR_FLOW_DISABLE |
+                UxUCR_D9_ODD_PARITY |
+                UxUCR_BIT9_8_BITS |
+                UxUCR_PARITY_DISABLE |
+                UxUCR_SPB_2_STOP_BITS |
+                UxUCR_STOP_HIGH |
+                UxUCR_START_LOW);
+ }
+ void
+ usart_out_byte(uint8_t byte)
+ {
+       U1DBUF = byte;
+       while (!UTX1IF)
+               ;
+       UTX1IF = 0;
+ }
+ void
+ usart_out_string(uint8_t *string)
+ {
+       uint8_t b;
+       while (b = *string++)
+               usart_out_byte(b);
+ }
+ #define NUM_LEN 6
+ uint8_t __xdata       num_buffer[NUM_LEN];
+ uint8_t __xdata * __xdata num_ptr;
+ void
+ usart_out_number(uint16_t v)
+ {
+       num_ptr = num_buffer + NUM_LEN;
+       *--num_ptr = '\0';
+       do {
+               *--num_ptr = '0' + v % 10;
+               v /= 10;
+       } while (v);
+       while (num_ptr != num_buffer)
+               *--num_ptr = ' ';
+       usart_out_string(num_buffer);
+ }
+ #define ADC(n)        DMA_XDATA16(adc_output,n)
+ main ()
+ {
+       P1DIR = 3;
+       CLKCON = 0;
+       while (!(SLEEP & SLEEP_XOSC_STB))
+               ;
++
+       adc_init();
+       P1_0 = 1;
+       usart_init();
+       for (;;) {
+               adc_run();
+               usart_out_string("accel: ");
+               usart_out_number(ADC(0));
+               usart_out_string(" pres: ");
+               usart_out_number(ADC(1));
+               usart_out_string(" temp: ");
+               usart_out_number(ADC(2));
+               usart_out_string(" batt: ");
+               usart_out_number(ADC(3));
+               usart_out_string(" drogue: ");
+               usart_out_number(ADC(4));
+               usart_out_string(" main: ");
+               usart_out_number(ADC(5));
+               usart_out_string("\r\n");
+               delay(10);
+       }
+ }
index 0000000,bdc6c61..3a63a2c
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,470 +1,470 @@@
 -      
+ /*
+  * Copyright © 2008 Keith Packard <keithp@keithp.com>
+  *
+  * 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 <stdint.h>
+ /*
+  * Test ADC in DMA mode
+  */
+ sfr at 0x80 P0;
+ sfr at 0x90 P1;
+ sfr at 0xA0 P2;
+ sfr at 0xC6 CLKCON;
+ sfr at 0xbe SLEEP;
+ # define SLEEP_USB_EN         (1 << 7)
+ # define SLEEP_XOSC_STB               (1 << 6)
+ sfr at 0xF1 PERCFG;
+ #define PERCFG_T1CFG_ALT_1    (0 << 6)
+ #define PERCFG_T1CFG_ALT_2    (1 << 6)
+ #define PERCFG_T3CFG_ALT_1    (0 << 5)
+ #define PERCFG_T3CFG_ALT_2    (1 << 5)
+ #define PERCFG_T4CFG_ALT_1    (0 << 4)
+ #define PERCFG_T4CFG_ALT_2    (1 << 4)
+ #define PERCFG_U1CFG_ALT_1    (0 << 1)
+ #define PERCFG_U1CFG_ALT_2    (1 << 1)
+ #define PERCFG_U0CFG_ALT_1    (0 << 0)
+ #define PERCFG_U0CFG_ALT_2    (1 << 0)
+ sfr at 0xF2 ADCCFG;
+ sfr at 0xF3 P0SEL;
+ sfr at 0xF4 P1SEL;
+ sfr at 0xF5 P2SEL;
+ sfr at 0xFD P0DIR;
+ sfr at 0xFE P1DIR;
+ sfr at 0xFF P2DIR;
+ sfr at 0x8F P0INP;
+ sfr at 0xF6 P1INP;
+ sfr at 0xF7 P2INP;
+ sfr at 0x89 P0IFG;
+ sfr at 0x8A P1IFG;
+ sfr at 0x8B P2IFG;
+ sbit at 0x90 P1_0;
+ sbit at 0x91 P1_1;
+ sbit at 0x92 P1_2;
+ sbit at 0x93 P1_3;
+ sbit at 0x94 P1_4;
+ sbit at 0x95 P1_5;
+ sbit at 0x96 P1_6;
+ sbit at 0x97 P1_7;
+ /*
+  * UART registers
+  */
+ sfr at 0x86 U0CSR;
+ sfr at 0xF8 U1CSR;
+ /*
+  * IRCON2
+  */
+ sfr at 0xE8 IRCON2;   /* CPU Interrupt Flag 5 */
+ sbit at 0xE8 USBIF;   /* USB interrupt flag (shared with Port2) */
+ sbit at 0xE8 P2IF;    /* Port2 interrupt flag (shared with USB) */
+ sbit at 0xE9 UTX0IF;  /* USART0 TX interrupt flag */
+ sbit at 0xEA UTX1IF;  /* USART1 TX interrupt flag (shared with I2S TX) */
+ sbit at 0xEA I2STXIF; /* I2S TX interrupt flag (shared with USART1 TX) */
+ sbit at 0xEB P1IF;    /* Port1 interrupt flag */
+ sbit at 0xEC WDTIF;   /* Watchdog timer interrupt flag */
+ # define UxCSR_MODE_UART              (1 << 7)
+ # define UxCSR_MODE_SPI                       (0 << 7)
+ # define UxCSR_RE                     (1 << 6)
+ # define UxCSR_SLAVE                  (1 << 5)
+ # define UxCSR_MASTER                 (0 << 5)
+ # define UxCSR_FE                     (1 << 4)
+ # define UxCSR_ERR                    (1 << 3)
+ # define UxCSR_RX_BYTE                        (1 << 2)
+ # define UxCSR_TX_BYTE                        (1 << 1)
+ # define UxCSR_ACTIVE                 (1 << 0)
+ sfr at 0xc4 U0UCR;
+ sfr at 0xfb U1UCR;
+ # define UxUCR_FLUSH                  (1 << 7)
+ # define UxUCR_FLOW_DISABLE           (0 << 6)
+ # define UxUCR_FLOW_ENABLE            (1 << 6)
+ # define UxUCR_D9_EVEN_PARITY         (0 << 5)
+ # define UxUCR_D9_ODD_PARITY          (1 << 5)
+ # define UxUCR_BIT9_8_BITS            (0 << 4)
+ # define UxUCR_BIT9_9_BITS            (1 << 4)
+ # define UxUCR_PARITY_DISABLE         (0 << 3)
+ # define UxUCR_PARITY_ENABLE          (1 << 3)
+ # define UxUCR_SPB_1_STOP_BIT         (0 << 2)
+ # define UxUCR_SPB_2_STOP_BITS                (1 << 2)
+ # define UxUCR_STOP_LOW                       (0 << 1)
+ # define UxUCR_STOP_HIGH              (1 << 1)
+ # define UxUCR_START_LOW              (0 << 0)
+ # define UxUCR_START_HIGH             (1 << 0)
+ sfr at 0xc5 U0GCR;
+ sfr at 0xfc U1GCR;
+ # define UxGCR_CPOL_NEGATIVE          (0 << 7)
+ # define UxGCR_CPOL_POSITIVE          (1 << 7)
+ # define UxGCR_CPHA_FIRST_EDGE                (0 << 6)
+ # define UxGCR_CPHA_SECOND_EDGE               (1 << 6)
+ # define UxGCR_ORDER_LSB              (0 << 5)
+ # define UxGCR_ORDER_MSB              (1 << 5)
+ # define UxGCR_BAUD_E_MASK            (0x1f)
+ # define UxGCR_BAUD_E_SHIFT           0
+ sfr at 0xc1 U0DBUF;
+ sfr at 0xf9 U1DBUF;
+ sfr at 0xc2 U0BAUD;
+ sfr at 0xfa U1BAUD;
+ #define DEBUG P1_1
+ # define DMA_LEN_HIGH_VLEN_MASK               (7 << 5)
+ # define DMA_LEN_HIGH_VLEN_LEN                (0 << 5)
+ # define DMA_LEN_HIGH_VLEN_PLUS_1     (1 << 5)
+ # define DMA_LEN_HIGH_VLEN            (2 << 5)
+ # define DMA_LEN_HIGH_VLEN_PLUS_2     (3 << 5)
+ # define DMA_LEN_HIGH_VLEN_PLUS_3     (4 << 5)
+ # define DMA_LEN_HIGH_MASK            (0x1f)
+ # define DMA_CFG0_WORDSIZE_8          (0 << 7)
+ # define DMA_CFG0_WORDSIZE_16         (1 << 7)
+ # define DMA_CFG0_TMODE_MASK          (3 << 5)
+ # define DMA_CFG0_TMODE_SINGLE                (0 << 5)
+ # define DMA_CFG0_TMODE_BLOCK         (1 << 5)
+ # define DMA_CFG0_TMODE_REPEATED_SINGLE       (2 << 5)
+ # define DMA_CFG0_TMODE_REPEATED_BLOCK        (3 << 5)
+ /*
+  * DMA triggers
+  */
+ # define DMA_CFG0_TRIGGER_NONE                0
+ # define DMA_CFG0_TRIGGER_PREV                1
+ # define DMA_CFG0_TRIGGER_T1_CH0      2
+ # define DMA_CFG0_TRIGGER_T1_CH1      3
+ # define DMA_CFG0_TRIGGER_T1_CH2      4
+ # define DMA_CFG0_TRIGGER_T2_OVFL     6
+ # define DMA_CFG0_TRIGGER_T3_CH0      7
+ # define DMA_CFG0_TRIGGER_T3_CH1      8
+ # define DMA_CFG0_TRIGGER_T4_CH0      9
+ # define DMA_CFG0_TRIGGER_T4_CH1      10
+ # define DMA_CFG0_TRIGGER_IOC_0               12
+ # define DMA_CFG0_TRIGGER_IOC_1               13
+ # define DMA_CFG0_TRIGGER_URX0                14
+ # define DMA_CFG0_TRIGGER_UTX0                15
+ # define DMA_CFG0_TRIGGER_URX1                16
+ # define DMA_CFG0_TRIGGER_UTX1                17
+ # define DMA_CFG0_TRIGGER_FLASH               18
+ # define DMA_CFG0_TRIGGER_RADIO               19
+ # define DMA_CFG0_TRIGGER_ADC_CHALL   20
+ # define DMA_CFG0_TRIGGER_ADC_CH0     21
+ # define DMA_CFG0_TRIGGER_ADC_CH1     22
+ # define DMA_CFG0_TRIGGER_ADC_CH2     23
+ # define DMA_CFG0_TRIGGER_ADC_CH3     24
+ # define DMA_CFG0_TRIGGER_ADC_CH4     25
+ # define DMA_CFG0_TRIGGER_ADC_CH5     26
+ # define DMA_CFG0_TRIGGER_ADC_CH6     27
+ # define DMA_CFG0_TRIGGER_I2SRX               27
+ # define DMA_CFG0_TRIGGER_ADC_CH7     28
+ # define DMA_CFG0_TRIGGER_I2STX               28
+ # define DMA_CFG0_TRIGGER_ENC_DW      29
+ # define DMA_CFG0_TRIGGER_DNC_UP      30
+ # define DMA_CFG1_SRCINC_MASK         (3 << 6)
+ # define DMA_CFG1_SRCINC_0            (0 << 6)
+ # define DMA_CFG1_SRCINC_1            (1 << 6)
+ # define DMA_CFG1_SRCINC_2            (2 << 6)
+ # define DMA_CFG1_SRCINC_MINUS_1      (3 << 6)
+ # define DMA_CFG1_DESTINC_MASK                (3 << 4)
+ # define DMA_CFG1_DESTINC_0           (0 << 4)
+ # define DMA_CFG1_DESTINC_1           (1 << 4)
+ # define DMA_CFG1_DESTINC_2           (2 << 4)
+ # define DMA_CFG1_DESTINC_MINUS_1     (3 << 4)
+ # define DMA_CFG1_IRQMASK             (1 << 3)
+ # define DMA_CFG1_M8                  (1 << 2)
+ # define DMA_CFG1_PRIORITY_MASK               (3 << 0)
+ # define DMA_CFG1_PRIORITY_LOW                (0 << 0)
+ # define DMA_CFG1_PRIORITY_NORMAL     (1 << 0)
+ # define DMA_CFG1_PRIORITY_HIGH               (2 << 0)
+ /*
+  * DMAARM - DMA Channel Arm
+  */
+ sfr at 0xD6 DMAARM;
+ # define DMAARM_ABORT                 (1 << 7)
+ # define DMAARM_DMAARM4                       (1 << 4)
+ # define DMAARM_DMAARM3                       (1 << 3)
+ # define DMAARM_DMAARM2                       (1 << 2)
+ # define DMAARM_DMAARM1                       (1 << 1)
+ # define DMAARM_DMAARM0                       (1 << 0)
+ /*
+  * DMAREQ - DMA Channel Start Request and Status
+  */
+ sfr at 0xD7 DMAREQ;
+ # define DMAREQ_DMAREQ4                       (1 << 4)
+ # define DMAREQ_DMAREQ3                       (1 << 3)
+ # define DMAREQ_DMAREQ2                       (1 << 2)
+ # define DMAREQ_DMAREQ1                       (1 << 1)
+ # define DMAREQ_DMAREQ0                       (1 << 0)
+ /*
+  * DMA configuration 0 address
+  */
+ sfr at 0xD5 DMA0CFGH;
+ sfr at 0xD4 DMA0CFGL;
+ /*
+  * DMA configuration 1-4 address
+  */
+ sfr at 0xD3 DMA1CFGH;
+ sfr at 0xD2 DMA1CFGL;
+ /*
+  * DMAIRQ - DMA Interrupt Flag
+  */
+ sfr at 0xD1 DMAIRQ;
+ # define DMAIRQ_DMAIF4                        (1 << 4)
+ # define DMAIRQ_DMAIF3                        (1 << 3)
+ # define DMAIRQ_DMAIF2                        (1 << 2)
+ # define DMAIRQ_DMAIF1                        (1 << 1)
+ # define DMAIRQ_DMAIF0                        (1 << 0)
+ struct cc_dma_channel {
+       uint8_t src_high;
+       uint8_t src_low;
+       uint8_t dst_high;
+       uint8_t dst_low;
+       uint8_t len_high;
+       uint8_t len_low;
+       uint8_t cfg0;
+       uint8_t cfg1;
+ };
+ /*
+  * ADC Data register, low and high
+  */
+ sfr at 0xBA ADCL;
+ sfr at 0xBB ADCH;
+ __xdata __at (0xDFBA) volatile uint16_t ADCXDATA;
+ /*
+  * ADC Control Register 1
+  */
+ sfr at 0xB4 ADCCON1;
+ # define ADCCON1_EOC          (1 << 7)        /* conversion complete */
+ # define ADCCON1_ST           (1 << 6)        /* start conversion */
+ # define ADCCON1_STSEL_MASK   (3 << 4)        /* start select */
+ # define ADCCON1_STSEL_EXTERNAL       (0 << 4)        /* P2_0 pin triggers */
+ # define ADCCON1_STSEL_FULLSPEED (1 << 4)     /* full speed, no waiting */
+ # define ADCCON1_STSEL_TIMER1 (2 << 4)        /* timer 1 channel 0 */
+ # define ADCCON1_STSEL_START  (3 << 4)        /* set start bit */
+ # define ADCCON1_RCTRL_MASK   (3 << 2)        /* random number control */
+ # define ADCCON1_RCTRL_COMPLETE       (0 << 2)        /* operation completed */
+ # define ADCCON1_RCTRL_CLOCK_LFSR (1 << 2)    /* Clock the LFSR once */
+ /*
+  * ADC Control Register 2
+  */
+ sfr at 0xB5 ADCCON2;
+ # define ADCCON2_SREF_MASK    (3 << 6)        /* reference voltage */
+ # define ADCCON2_SREF_1_25V   (0 << 6)        /* internal 1.25V */
+ # define ADCCON2_SREF_EXTERNAL        (1 << 6)        /* external on AIN7 cc1110 */
+ # define ADCCON2_SREF_VDD     (2 << 6)        /* VDD on the AVDD pin */
+ # define ADCCON2_SREF_EXTERNAL_DIFF (3 << 6)  /* external on AIN6-7 cc1110 */
+ # define ADCCON2_SDIV_MASK    (3 << 4)        /* decimation rate */
+ # define ADCCON2_SDIV_64      (0 << 4)        /* 7 bits */
+ # define ADCCON2_SDIV_128     (1 << 4)        /* 9 bits */
+ # define ADCCON2_SDIV_256     (2 << 4)        /* 10 bits */
+ # define ADCCON2_SDIV_512     (3 << 4)        /* 12 bits */
+ # define ADCCON2_SCH_MASK     (0xf << 0)      /* Sequence channel select */
+ # define ADCCON2_SCH_SHIFT    0
+ # define ADCCON2_SCH_AIN0     (0 << 0)
+ # define ADCCON2_SCH_AIN1     (1 << 0)
+ # define ADCCON2_SCH_AIN2     (2 << 0)
+ # define ADCCON2_SCH_AIN3     (3 << 0)
+ # define ADCCON2_SCH_AIN4     (4 << 0)
+ # define ADCCON2_SCH_AIN5     (5 << 0)
+ # define ADCCON2_SCH_AIN6     (6 << 0)
+ # define ADCCON2_SCH_AIN7     (7 << 0)
+ # define ADCCON2_SCH_AIN0_AIN1        (8 << 0)
+ # define ADCCON2_SCH_AIN2_AIN3        (9 << 0)
+ # define ADCCON2_SCH_AIN4_AIN5        (0xa << 0)
+ # define ADCCON2_SCH_AIN6_AIN7        (0xb << 0)
+ # define ADCCON2_SCH_GND      (0xc << 0)
+ # define ADCCON2_SCH_VREF     (0xd << 0)
+ # define ADCCON2_SCH_TEMP     (0xe << 0)
+ # define ADCCON2_SCH_VDD_3    (0xf << 0)
+ /*
+  * ADC Control Register 3
+  */
+ sfr at 0xB6 ADCCON3;
+ # define ADCCON3_EREF_MASK    (3 << 6)        /* extra conversion reference */
+ # define ADCCON3_EREF_1_25    (0 << 6)        /* internal 1.25V */
+ # define ADCCON3_EREF_EXTERNAL        (1 << 6)        /* external AIN7 cc1110 */
+ # define ADCCON3_EREF_VDD     (2 << 6)        /* VDD on the AVDD pin */
+ # define ADCCON3_EREF_EXTERNAL_DIFF (3 << 6)  /* external AIN6-7 cc1110 */
+ # define ADCCON2_EDIV_MASK    (3 << 4)        /* extral decimation */
+ # define ADCCON2_EDIV_64      (0 << 4)        /* 7 bits */
+ # define ADCCON2_EDIV_128     (1 << 4)        /* 9 bits */
+ # define ADCCON2_EDIV_256     (2 << 4)        /* 10 bits */
+ # define ADCCON2_EDIV_512     (3 << 4)        /* 12 bits */
+ # define ADCCON3_ECH_MASK     (0xf << 0)      /* Sequence channel select */
+ # define ADCCON3_ECH_SHIFT    0
+ # define ADCCON3_ECH_AIN0     (0 << 0)
+ # define ADCCON3_ECH_AIN1     (1 << 0)
+ # define ADCCON3_ECH_AIN2     (2 << 0)
+ # define ADCCON3_ECH_AIN3     (3 << 0)
+ # define ADCCON3_ECH_AIN4     (4 << 0)
+ # define ADCCON3_ECH_AIN5     (5 << 0)
+ # define ADCCON3_ECH_AIN6     (6 << 0)
+ # define ADCCON3_ECH_AIN7     (7 << 0)
+ # define ADCCON3_ECH_AIN0_AIN1        (8 << 0)
+ # define ADCCON3_ECH_AIN2_AIN3        (9 << 0)
+ # define ADCCON3_ECH_AIN4_AIN5        (0xa << 0)
+ # define ADCCON3_ECH_AIN6_AIN7        (0xb << 0)
+ # define ADCCON3_ECH_GND      (0xc << 0)
+ # define ADCCON3_ECH_VREF     (0xd << 0)
+ # define ADCCON3_ECH_TEMP     (0xe << 0)
+ # define ADCCON3_ECH_VDD_3    (0xf << 0)
+ sfr at 0xF2 ADCCFG;
+ #define nop() _asm nop _endasm;
+ void
+ delay (unsigned char n)
+ {
+       unsigned char i = 0;
+       unsigned char j = 0;
+       n++;
+       while (--n != 0)
+               while (--i != 0)
+                       while (--j != 0)
+                               nop();
+ }
+ void
+ debug_byte(uint8_t byte)
+ {
+       uint8_t s;
+       for (s = 0; s < 8; s++) {
+               DEBUG = byte & 1;
+               delay(5);
+               byte >>= 1;
+       }
+ }
+ struct cc_dma_channel __xdata dma_config;
+ #define ADC_LEN       6
+ uint16_t __xdata adc_output[ADC_LEN];
+ #define ADDRH(a)      (((uint16_t) (a)) >> 8)
+ #define ADDRL(a)      (((uint16_t) (a)))
+ void
+ adc_init(void)
+ {
+       dma_config.cfg0 = (DMA_CFG0_WORDSIZE_16 |
+                          DMA_CFG0_TMODE_REPEATED_SINGLE |
+                          DMA_CFG0_TRIGGER_ADC_CHALL);
+       dma_config.cfg1 = (DMA_CFG1_SRCINC_0 |
+                          DMA_CFG1_DESTINC_1 |
+                          DMA_CFG1_PRIORITY_NORMAL);
 -      
++
+       dma_config.src_high = ADDRH(&ADCXDATA);
+       dma_config.src_low = ADDRL(&ADCXDATA);
+       dma_config.dst_high = ADDRH(adc_output);
+       dma_config.dst_low = ADDRL(adc_output);
+       dma_config.len_high = 0;
+       dma_config.len_low = ADC_LEN;
+       DMA0CFGH = ADDRH(&dma_config);
+       DMA0CFGL = ADDRL(&dma_config);
+       ADCCFG = ((1 << 0) |    /* acceleration */
+                 (1 << 1) |    /* pressure */
+                 (1 << 2) |    /* temperature */
+                 (1 << 3) |    /* battery voltage */
+                 (1 << 4) |    /* drogue sense */
+                 (1 << 5));    /* main sense */
 -      
++
+       ADCCON1 = (ADCCON1_STSEL_START);        /* ST bit triggers */
+       ADCCON2 = (ADCCON2_SREF_VDD |           /* reference voltage is VDD */
+                  ADCCON2_SDIV_512 |           /* 12 bit ADC results */
+                  ADCCON2_SCH_AIN5);           /* sample all 6 inputs */
+ }
+ void
+ adc_run(void)
+ {
+       DMAIRQ &= ~1;
+       DMAARM |= 1;
+       ADCCON1 |= ADCCON1_ST;
+       while ((DMAIRQ & 1) == 0)
+               ;
+ }
+ main ()
+ {
+       int i;
+       P1DIR |= 2;
+       CLKCON = 0;
+       while (!(SLEEP & SLEEP_XOSC_STB))
+               ;
+       while (P1 & 0x4)
+               ;
++
+       adc_init();
+       for (;;) {
+               adc_run();
+               for (i = 0; i < ADC_LEN; i++)
+                       debug_byte(adc_output[i]);
+       }
+ }
index 0000000,53b9549..b3fa875
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,204 +1,204 @@@
 - 
+ /*
+  * Copyright © 2008 Keith Packard <keithp@keithp.com>
+  *
+  * 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.
+  */
+ sfr at 0x80 P0;
+ sfr at 0x90 P1;
+ sfr at 0xA0 P2;
+ sfr at 0xC6 CLKCON;
+ sfr at 0xbe SLEEP;
+ # define SLEEP_USB_EN         (1 << 7)
+ # define SLEEP_XOSC_STB               (1 << 6)
+ sbit at 0x90 P1_0;
+ sbit at 0x91 P1_1;
+ sbit at 0x92 P1_2;
+ sbit at 0x93 P1_3;
+ sbit at 0x94 P1_4;
+ sbit at 0x95 P1_5;
+ sbit at 0x96 P1_6;
+ sbit at 0x97 P1_7;
+ sfr at 0xF1 PERCFG;
+ sfr at 0xF2 ADCCFG;
+ sfr at 0xF3 P0SEL;
+ sfr at 0xF4 P1SEL;
+ sfr at 0xF5 P2SEL;
+ #define P2SEL_PRI3P1_USART0           (0 << 6)
+ #define P2SEL_PRI3P1_USART1           (1 << 6)
+ #define P2SEL_PRI2P1_USART1           (0 << 5)
+ #define P2SEL_PRI2P1_TIMER3           (1 << 5)
+ #define P2SEL_PRI1P1_TIMER1           (0 << 4)
+ #define P2SEL_PRI1P1_TIMER4           (1 << 4)
+ #define P2SEL_PRI0P1_USART0           (0 << 3)
+ #define P2SEL_PRI0P1_TIMER1           (1 << 3)
+ #define P2SEL_SELP2_4_GPIO            (0 << 2)
+ #define P2SEL_SELP2_4_PERIPHERAL      (1 << 2)
+ #define P2SEL_SELP2_3_GPIO            (0 << 1)
+ #define P2SEL_SELP2_3_PERIPHERAL      (1 << 1)
+ #define P2SEL_SELP2_0_GPIO            (0 << 0)
+ #define P2SEL_SELP2_0_PERIPHERAL      (1 << 0)
+ sfr at 0xFD P0DIR;
+ sfr at 0xFE P1DIR;
+ sfr at 0xFF P2DIR;
+ sfr at 0x8F P0INP;
+ sfr at 0xF6 P1INP;
+ sfr at 0xF7 P2INP;
+ sfr at 0x89 P0IFG;
+ sfr at 0x8A P1IFG;
+ sfr at 0x8B P2IFG;
+ sfr at 0xF1 PERCFG;
+ #define PERCFG_T1CFG_ALT_1    (0 << 6)
+ #define PERCFG_T1CFG_ALT_2    (1 << 6)
+ #define PERCFG_T3CFG_ALT_1    (0 << 5)
+ #define PERCFG_T3CFG_ALT_2    (1 << 5)
+ #define PERCFG_T4CFG_ALT_1    (0 << 4)
+ #define PERCFG_T4CFG_ALT_2    (1 << 4)
+ #define PERCFG_U1CFG_ALT_1    (0 << 1)
+ #define PERCFG_U1CFG_ALT_2    (1 << 1)
+ #define PERCFG_U0CFG_ALT_1    (0 << 0)
+ #define PERCFG_U0CFG_ALT_2    (1 << 0)
+ /* Timer count */
+ sfr at 0xCA T3CNT;
+ sfr at 0xEA T4CNT;
+ /* Timer control */
 -      
++
+ sfr at 0xCB T3CTL;
+ sfr at 0xEB T4CTL;
+ #define TxCTL_DIV_1           (0 << 5)
+ #define TxCTL_DIV_2           (1 << 5)
+ #define TxCTL_DIV_4           (2 << 5)
+ #define TxCTL_DIV_8           (3 << 5)
+ #define TxCTL_DIV_16          (4 << 5)
+ #define TxCTL_DIV_32          (5 << 5)
+ #define TxCTL_DIV_64          (6 << 5)
+ #define TxCTL_DIV_128         (7 << 5)
+ #define TxCTL_START           (1 << 4)
+ #define TxCTL_OVFIM           (1 << 3)
+ #define TxCTL_CLR             (1 << 2)
+ #define TxCTL_MODE_FREE               (0 << 0)
+ #define TxCTL_MODE_DOWN               (1 << 0)
+ #define TxCTL_MODE_MODULO     (2 << 0)
+ #define TxCTL_MODE_UP_DOWN    (3 << 0)
+ /* Timer 4 channel 0 compare control */
+ sfr at 0xCC T3CCTL0;
+ sfr at 0xCE T3CCTL1;
+ sfr at 0xEC T4CCTL0;
+ sfr at 0xEE T4CCTL1;
+ #define TxCCTLy_IM                    (1 << 6)
+ #define TxCCTLy_CMP_SET                       (0 << 3)
+ #define TxCCTLy_CMP_CLEAR             (1 << 3)
+ #define TxCCTLy_CMP_TOGGLE            (2 << 3)
+ #define TxCCTLy_CMP_SET_UP_CLEAR_DOWN (3 << 3)
+ #define TxCCTLy_CMP_CLEAR_UP_SET_DOWN (4 << 3)
+ #define TxCCTLy_CMP_SET_CLEAR_FF      (5 << 3)
+ #define TxCCTLy_CMP_CLEAR_SET_00      (6 << 3)
+ #define TxCCTLy_CMP_MODE_ENABLE               (1 << 2)
+ /* Timer compare value */
+ sfr at 0xCD T3CC0;
+ sfr at 0xCF T3CC1;
+ sfr at 0xED T4CC0;
+ sfr at 0xEF T4CC1;
+ #define nop() _asm nop _endasm;
+ void
+ delay (unsigned char n)
+ {
+       unsigned char i = 0, j = 0;
+       n <<= 1;
+       while (--n != 0)
+               while (--j != 0)
+                       while (--i != 0)
+                               nop();
+ }
+ void
+ dit() {
+       T4CTL |= TxCTL_START;
+       delay(1);
+       T4CTL &= ~TxCTL_START;
+       delay(1);
+ }
+ void
+ dah () {
+       T4CTL |= TxCTL_START;
+       delay(3);
+       T4CTL &= ~TxCTL_START;
+       delay(1);
+ }
+ void
+ charspace () {
+       delay(2);
+ }
+ void
+ wordspace () {
+       delay(8);
+ }
+ #define _ dit();
+ #define ___ dah();
+ #define C charspace();
+ #define W wordspace();
+ main ()
+ {
+       CLKCON = 0;
+       while (!(SLEEP & SLEEP_XOSC_STB))
+               ;
+       /* Use timer 4 alternate config 2 */
+       PERCFG = PERCFG_T4CFG_ALT_2;
+       /* Use P2_4 for timer 4 output */
+       P2SEL = P2SEL_SELP2_0_PERIPHERAL;
+       T4CCTL0 = TxCCTLy_CMP_TOGGLE|TxCCTLy_CMP_MODE_ENABLE;
+       T4CC0 = 125;
+       T4CTL = TxCTL_DIV_32 | TxCTL_MODE_MODULO;
++
+       for (;;) {
+               ___ _ ___ _ C ___ ___ _ ___ W   /* cq */
+               ___ _ _ C _ W                   /* de */
+               ___ _ ___ C ___ _ _ C           /* kd */
+               ___ ___ _ _ _ C _ _ _ C         /* 7s */
+               ___ ___ _ ___ C ___ ___ _ W     /* qg */
+               if (T4CC0 == 94)
+                       T4CC0 = 125;
+               else
+                       T4CC0 = 94;
+       }
+ }
index 0000000,c35c39f..1762b65
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,361 +1,361 @@@
 -      
+ /*
+  * Copyright © 2008 Keith Packard <keithp@keithp.com>
+  *
+  * 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 <stdint.h>
+ /*
+  * Test DMA
+  */
+ sfr at 0x80 P0;
+ sfr at 0x90 P1;
+ sfr at 0xA0 P2;
+ sfr at 0xC6 CLKCON;
+ sfr at 0xbe SLEEP;
+ # define SLEEP_USB_EN         (1 << 7)
+ # define SLEEP_XOSC_STB               (1 << 6)
+ sfr at 0xF1 PERCFG;
+ #define PERCFG_T1CFG_ALT_1    (0 << 6)
+ #define PERCFG_T1CFG_ALT_2    (1 << 6)
+ #define PERCFG_T3CFG_ALT_1    (0 << 5)
+ #define PERCFG_T3CFG_ALT_2    (1 << 5)
+ #define PERCFG_T4CFG_ALT_1    (0 << 4)
+ #define PERCFG_T4CFG_ALT_2    (1 << 4)
+ #define PERCFG_U1CFG_ALT_1    (0 << 1)
+ #define PERCFG_U1CFG_ALT_2    (1 << 1)
+ #define PERCFG_U0CFG_ALT_1    (0 << 0)
+ #define PERCFG_U0CFG_ALT_2    (1 << 0)
+ sfr at 0xF2 ADCCFG;
+ sfr at 0xF3 P0SEL;
+ sfr at 0xF4 P1SEL;
+ sfr at 0xF5 P2SEL;
+ sfr at 0xFD P0DIR;
+ sfr at 0xFE P1DIR;
+ sfr at 0xFF P2DIR;
+ sfr at 0x8F P0INP;
+ sfr at 0xF6 P1INP;
+ sfr at 0xF7 P2INP;
+ sfr at 0x89 P0IFG;
+ sfr at 0x8A P1IFG;
+ sfr at 0x8B P2IFG;
+ sbit at 0x90 P1_0;
+ sbit at 0x91 P1_1;
+ sbit at 0x92 P1_2;
+ sbit at 0x93 P1_3;
+ sbit at 0x94 P1_4;
+ sbit at 0x95 P1_5;
+ sbit at 0x96 P1_6;
+ sbit at 0x97 P1_7;
+ /*
+  * UART registers
+  */
+ sfr at 0x86 U0CSR;
+ sfr at 0xF8 U1CSR;
+ /*
+  * IRCON2
+  */
+ sfr at 0xE8 IRCON2;   /* CPU Interrupt Flag 5 */
+ sbit at 0xE8 USBIF;   /* USB interrupt flag (shared with Port2) */
+ sbit at 0xE8 P2IF;    /* Port2 interrupt flag (shared with USB) */
+ sbit at 0xE9 UTX0IF;  /* USART0 TX interrupt flag */
+ sbit at 0xEA UTX1IF;  /* USART1 TX interrupt flag (shared with I2S TX) */
+ sbit at 0xEA I2STXIF; /* I2S TX interrupt flag (shared with USART1 TX) */
+ sbit at 0xEB P1IF;    /* Port1 interrupt flag */
+ sbit at 0xEC WDTIF;   /* Watchdog timer interrupt flag */
+ # define UxCSR_MODE_UART              (1 << 7)
+ # define UxCSR_MODE_SPI                       (0 << 7)
+ # define UxCSR_RE                     (1 << 6)
+ # define UxCSR_SLAVE                  (1 << 5)
+ # define UxCSR_MASTER                 (0 << 5)
+ # define UxCSR_FE                     (1 << 4)
+ # define UxCSR_ERR                    (1 << 3)
+ # define UxCSR_RX_BYTE                        (1 << 2)
+ # define UxCSR_TX_BYTE                        (1 << 1)
+ # define UxCSR_ACTIVE                 (1 << 0)
+ sfr at 0xc4 U0UCR;
+ sfr at 0xfb U1UCR;
+ # define UxUCR_FLUSH                  (1 << 7)
+ # define UxUCR_FLOW_DISABLE           (0 << 6)
+ # define UxUCR_FLOW_ENABLE            (1 << 6)
+ # define UxUCR_D9_EVEN_PARITY         (0 << 5)
+ # define UxUCR_D9_ODD_PARITY          (1 << 5)
+ # define UxUCR_BIT9_8_BITS            (0 << 4)
+ # define UxUCR_BIT9_9_BITS            (1 << 4)
+ # define UxUCR_PARITY_DISABLE         (0 << 3)
+ # define UxUCR_PARITY_ENABLE          (1 << 3)
+ # define UxUCR_SPB_1_STOP_BIT         (0 << 2)
+ # define UxUCR_SPB_2_STOP_BITS                (1 << 2)
+ # define UxUCR_STOP_LOW                       (0 << 1)
+ # define UxUCR_STOP_HIGH              (1 << 1)
+ # define UxUCR_START_LOW              (0 << 0)
+ # define UxUCR_START_HIGH             (1 << 0)
+ sfr at 0xc5 U0GCR;
+ sfr at 0xfc U1GCR;
+ # define UxGCR_CPOL_NEGATIVE          (0 << 7)
+ # define UxGCR_CPOL_POSITIVE          (1 << 7)
+ # define UxGCR_CPHA_FIRST_EDGE                (0 << 6)
+ # define UxGCR_CPHA_SECOND_EDGE               (1 << 6)
+ # define UxGCR_ORDER_LSB              (0 << 5)
+ # define UxGCR_ORDER_MSB              (1 << 5)
+ # define UxGCR_BAUD_E_MASK            (0x1f)
+ # define UxGCR_BAUD_E_SHIFT           0
+ sfr at 0xc1 U0DBUF;
+ sfr at 0xf9 U1DBUF;
+ sfr at 0xc2 U0BAUD;
+ sfr at 0xfa U1BAUD;
+ #define DEBUG P1_1
+ # define DMA_LEN_HIGH_VLEN_MASK               (7 << 5)
+ # define DMA_LEN_HIGH_VLEN_LEN                (0 << 5)
+ # define DMA_LEN_HIGH_VLEN_PLUS_1     (1 << 5)
+ # define DMA_LEN_HIGH_VLEN            (2 << 5)
+ # define DMA_LEN_HIGH_VLEN_PLUS_2     (3 << 5)
+ # define DMA_LEN_HIGH_VLEN_PLUS_3     (4 << 5)
+ # define DMA_LEN_HIGH_MASK            (0x1f)
+ # define DMA_CFG0_WORDSIZE_8          (0 << 7)
+ # define DMA_CFG0_WORDSIZE_16         (1 << 7)
+ # define DMA_CFG0_TMODE_MASK          (3 << 5)
+ # define DMA_CFG0_TMODE_SINGLE                (0 << 5)
+ # define DMA_CFG0_TMODE_BLOCK         (1 << 5)
+ # define DMA_CFG0_TMODE_REPEATED_SINGLE       (2 << 5)
+ # define DMA_CFG0_TMODE_REPEATED_BLOCK        (3 << 5)
+ /*
+  * DMA triggers
+  */
+ # define DMA_CFG0_TRIGGER_NONE                0
+ # define DMA_CFG0_TRIGGER_PREV                1
+ # define DMA_CFG0_TRIGGER_T1_CH0      2
+ # define DMA_CFG0_TRIGGER_T1_CH1      3
+ # define DMA_CFG0_TRIGGER_T1_CH2      4
+ # define DMA_CFG0_TRIGGER_T2_OVFL     6
+ # define DMA_CFG0_TRIGGER_T3_CH0      7
+ # define DMA_CFG0_TRIGGER_T3_CH1      8
+ # define DMA_CFG0_TRIGGER_T4_CH0      9
+ # define DMA_CFG0_TRIGGER_T4_CH1      10
+ # define DMA_CFG0_TRIGGER_IOC_0               12
+ # define DMA_CFG0_TRIGGER_IOC_1               13
+ # define DMA_CFG0_TRIGGER_URX0                14
+ # define DMA_CFG0_TRIGGER_UTX0                15
+ # define DMA_CFG0_TRIGGER_URX1                16
+ # define DMA_CFG0_TRIGGER_UTX1                17
+ # define DMA_CFG0_TRIGGER_FLASH               18
+ # define DMA_CFG0_TRIGGER_RADIO               19
+ # define DMA_CFG0_TRIGGER_ADC_CHALL   20
+ # define DMA_CFG0_TRIGGER_ADC_CH0     21
+ # define DMA_CFG0_TRIGGER_ADC_CH1     22
+ # define DMA_CFG0_TRIGGER_ADC_CH2     23
+ # define DMA_CFG0_TRIGGER_ADC_CH3     24
+ # define DMA_CFG0_TRIGGER_ADC_CH4     25
+ # define DMA_CFG0_TRIGGER_ADC_CH5     26
+ # define DMA_CFG0_TRIGGER_ADC_CH6     27
+ # define DMA_CFG0_TRIGGER_I2SRX               27
+ # define DMA_CFG0_TRIGGER_ADC_CH7     28
+ # define DMA_CFG0_TRIGGER_I2STX               28
+ # define DMA_CFG0_TRIGGER_ENC_DW      29
+ # define DMA_CFG0_TRIGGER_DNC_UP      30
+ # define DMA_CFG1_SRCINC_MASK         (3 << 6)
+ # define DMA_CFG1_SRCINC_0            (0 << 6)
+ # define DMA_CFG1_SRCINC_1            (1 << 6)
+ # define DMA_CFG1_SRCINC_2            (2 << 6)
+ # define DMA_CFG1_SRCINC_MINUS_1      (3 << 6)
+ # define DMA_CFG1_DESTINC_MASK                (3 << 4)
+ # define DMA_CFG1_DESTINC_0           (0 << 4)
+ # define DMA_CFG1_DESTINC_1           (1 << 4)
+ # define DMA_CFG1_DESTINC_2           (2 << 4)
+ # define DMA_CFG1_DESTINC_MINUS_1     (3 << 4)
+ # define DMA_CFG1_IRQMASK             (1 << 3)
+ # define DMA_CFG1_M8                  (1 << 2)
+ # define DMA_CFG1_PRIORITY_MASK               (3 << 0)
+ # define DMA_CFG1_PRIORITY_LOW                (0 << 0)
+ # define DMA_CFG1_PRIORITY_NORMAL     (1 << 0)
+ # define DMA_CFG1_PRIORITY_HIGH               (2 << 0)
+ /*
+  * DMAARM - DMA Channel Arm
+  */
+ sfr at 0xD6 DMAARM;
+ # define DMAARM_ABORT                 (1 << 7)
+ # define DMAARM_DMAARM4                       (1 << 4)
+ # define DMAARM_DMAARM3                       (1 << 3)
+ # define DMAARM_DMAARM2                       (1 << 2)
+ # define DMAARM_DMAARM1                       (1 << 1)
+ # define DMAARM_DMAARM0                       (1 << 0)
+ /*
+  * DMAREQ - DMA Channel Start Request and Status
+  */
+ sfr at 0xD7 DMAREQ;
+ # define DMAREQ_DMAREQ4                       (1 << 4)
+ # define DMAREQ_DMAREQ3                       (1 << 3)
+ # define DMAREQ_DMAREQ2                       (1 << 2)
+ # define DMAREQ_DMAREQ1                       (1 << 1)
+ # define DMAREQ_DMAREQ0                       (1 << 0)
+ /*
+  * DMA configuration 0 address
+  */
+ sfr at 0xD5 DMA0CFGH;
+ sfr at 0xD4 DMA0CFGL;
+ /*
+  * DMA configuration 1-4 address
+  */
+ sfr at 0xD3 DMA1CFGH;
+ sfr at 0xD2 DMA1CFGL;
+ /*
+  * DMAIRQ - DMA Interrupt Flag
+  */
+ sfr at 0xD1 DMAIRQ;
+ # define DMAIRQ_DMAIF4                        (1 << 4)
+ # define DMAIRQ_DMAIF3                        (1 << 3)
+ # define DMAIRQ_DMAIF2                        (1 << 2)
+ # define DMAIRQ_DMAIF1                        (1 << 1)
+ # define DMAIRQ_DMAIF0                        (1 << 0)
+ struct cc_dma_channel {
+       uint8_t src_high;
+       uint8_t src_low;
+       uint8_t dst_high;
+       uint8_t dst_low;
+       uint8_t len_high;
+       uint8_t len_low;
+       uint8_t cfg0;
+       uint8_t cfg1;
+ };
+ #define nop() _asm nop _endasm;
+ void
+ delay (unsigned char n)
+ {
+       unsigned char i = 0;
+       unsigned char j = 0;
+       n++;
+       while (--n != 0)
+               while (--i != 0)
+                       while (--j != 0)
+                               nop();
+ }
+ void
+ debug_byte(uint8_t byte)
+ {
+       uint8_t s;
+       for (s = 0; s < 8; s++) {
+               DEBUG = byte & 1;
+               delay(5);
+               byte >>= 1;
+       }
+ }
+ struct cc_dma_channel __xdata config;
+ #define DMA_LEN       8
+ uint8_t __xdata dma_input[DMA_LEN];
+ uint8_t __xdata dma_output[DMA_LEN];
+ #define ADDRH(a)      (((uint16_t) (a)) >> 8)
+ #define ADDRL(a)      (((uint16_t) (a)))
+ void
+ dma_init(void)
+ {
+       int i;
+       config.cfg0 = (DMA_CFG0_WORDSIZE_8 |
+                      DMA_CFG0_TMODE_BLOCK |
+                      DMA_CFG0_TRIGGER_NONE);
+       config.cfg1 = (DMA_CFG1_SRCINC_1 |
+                      DMA_CFG1_DESTINC_1 |
+                      DMA_CFG1_PRIORITY_NORMAL);
 -      
++
+       config.src_high = ADDRH(dma_input);
+       config.src_low = ADDRL(dma_input);
+       config.dst_high = ADDRH(dma_output);
+       config.dst_low = ADDRL(dma_output);
+       config.len_high = 0;
+       config.len_low = DMA_LEN;
+       DMA0CFGH = ADDRH(&config);
+       DMA0CFGL = ADDRL(&config);
+       for (i = 0; i < DMA_LEN; i++)
+               dma_input[i] = i + 1;
+ }
+ void
+ dma_run(void)
+ {
+       DMAREQ |= 1;
+       DMAARM |= 1;
+       while (DMAARM & 1)
+               ;
+ }
+ main ()
+ {
+       int i;
+       P1DIR |= 2;
+       CLKCON = 0;
+       while (!(SLEEP & SLEEP_XOSC_STB))
+               ;
++
+       dma_init();
+       dma_run();
+       for (;;) {
+               for (i = 0; i < DMA_LEN; i++)
+                       debug_byte(dma_output[i]);
+       }
+ }
diff --cc target/ee/ee.c
index 0000000,7cc4712..9ea22cd
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,407 +1,407 @@@
 -      
+ /*
+  * Copyright © 2008 Keith Packard <keithp@keithp.com>
+  *
+  * 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 <stdint.h>
+ /*
+  * Validate the SPI-connected EEPROM
+  */
+ sfr at 0x80 P0;
+ sfr at 0x90 P1;
+ sfr at 0xA0 P2;
+ sfr at 0xC6 CLKCON;
+ sfr at 0xbe SLEEP;
+ # define SLEEP_USB_EN         (1 << 7)
+ # define SLEEP_XOSC_STB               (1 << 6)
+ sfr at 0xF1 PERCFG;
+ #define PERCFG_T1CFG_ALT_1    (0 << 6)
+ #define PERCFG_T1CFG_ALT_2    (1 << 6)
+ #define PERCFG_T3CFG_ALT_1    (0 << 5)
+ #define PERCFG_T3CFG_ALT_2    (1 << 5)
+ #define PERCFG_T4CFG_ALT_1    (0 << 4)
+ #define PERCFG_T4CFG_ALT_2    (1 << 4)
+ #define PERCFG_U1CFG_ALT_1    (0 << 1)
+ #define PERCFG_U1CFG_ALT_2    (1 << 1)
+ #define PERCFG_U0CFG_ALT_1    (0 << 0)
+ #define PERCFG_U0CFG_ALT_2    (1 << 0)
+ sfr at 0xF2 ADCCFG;
+ sfr at 0xF3 P0SEL;
+ sfr at 0xF4 P1SEL;
+ sfr at 0xF5 P2SEL;
+ sfr at 0xFD P0DIR;
+ sfr at 0xFE P1DIR;
+ sfr at 0xFF P2DIR;
+ sfr at 0x8F P0INP;
+ sfr at 0xF6 P1INP;
+ sfr at 0xF7 P2INP;
+ sfr at 0x89 P0IFG;
+ sfr at 0x8A P1IFG;
+ sfr at 0x8B P2IFG;
+ sbit at 0x90 P1_0;
+ sbit at 0x91 P1_1;
+ sbit at 0x92 P1_2;
+ sbit at 0x93 P1_3;
+ sbit at 0x94 P1_4;
+ sbit at 0x95 P1_5;
+ sbit at 0x96 P1_6;
+ sbit at 0x97 P1_7;
+ /*
+  * UART registers
+  */
+ sfr at 0x86 U0CSR;
+ sfr at 0xF8 U1CSR;
+ # define UxCSR_MODE_UART              (1 << 7)
+ # define UxCSR_MODE_SPI                       (0 << 7)
+ # define UxCSR_RE                     (1 << 6)
+ # define UxCSR_SLAVE                  (1 << 5)
+ # define UxCSR_MASTER                 (0 << 5)
+ # define UxCSR_FE                     (1 << 4)
+ # define UxCSR_ERR                    (1 << 3)
+ # define UxCSR_RX_BYTE                        (1 << 2)
+ # define UxCSR_TX_BYTE                        (1 << 1)
+ # define UxCSR_ACTIVE                 (1 << 0)
+ sfr at 0xc4 U0UCR;
+ sfr at 0xfb U1UCR;
+ sfr at 0xc5 U0GCR;
+ sfr at 0xfc U1GCR;
+ # define UxGCR_CPOL_NEGATIVE          (0 << 7)
+ # define UxGCR_CPOL_POSITIVE          (1 << 7)
+ # define UxGCR_CPHA_FIRST_EDGE                (0 << 6)
+ # define UxGCR_CPHA_SECOND_EDGE               (1 << 6)
+ # define UxGCR_ORDER_LSB              (0 << 5)
+ # define UxGCR_ORDER_MSB              (1 << 5)
+ # define UxGCR_BAUD_E_MASK            (0x1f)
+ # define UxGCR_BAUD_E_SHIFT           0
+ sfr at 0xc1 U0DBUF;
+ sfr at 0xf9 U1DBUF;
+ sfr at 0xc2 U0BAUD;
+ sfr at 0xfa U1BAUD;
+ #define MOSI  P1_5
+ #define MISO  P1_4
+ #define SCK   P1_3
+ #define CS    P1_2
+ #define DEBUG P1_1
+ #define BITBANG       0
+ #define USART 1
+ #define nop() _asm nop _endasm;
+ void
+ delay (unsigned char n)
+ {
+       unsigned char i = 0;
+       unsigned char j = 0;
+       while (--n != 0)
+               while (--i != 0)
+                       while (--j != 0)
+                               nop();
+ }
+ #if BITBANG
+ /*
+  * This version directly manipulates the GPIOs to synthesize SPI
+  */
+ void
+ bitbang_cs(uint8_t b)
+ {
+       SCK = 0;
+       CS = b;
+       delay(1);
+ }
+ void
+ bitbang_out_bit(uint8_t b)
+ {
+       MOSI = b;
+       delay(1);
+       SCK = 1;
+       delay(1);
+       SCK = 0;
+ }
+ void
+ bitbang_out_byte(uint8_t byte)
+ {
+       uint8_t s;
+       for (s = 0; s < 8; s++) {
+               uint8_t b = (byte & 0x80) ? 1 : 0;
+               bitbang_out_bit(b);
+               byte <<= 1;
+       }
+ }
+ uint8_t
+ bitbang_in_bit(void)
+ {
+       uint8_t b;
 -      
++
+       delay(1);
+       SCK = 1;
+       delay(1);
+       b = MISO;
+       SCK = 0;
+       return b;
+ }
+ uint8_t
+ bitbang_in_byte(void)
+ {
+       uint8_t byte = 0;
+       uint8_t s;
+       uint8_t b;
+       for (s = 0; s < 8; s++) {
+               b = bitbang_in_bit();
+               byte = byte << 1;
+               byte |= b;
+       }
+       return byte;
+ }
+ void
+ bit_bang_init(void)
+ {
+       CS = 1;
+       SCK = 0;
+       P1DIR = ((1 << 5) |
+                (0 << 4) |
+                (1 << 3) |
+                (1 << 2) |
+                (1 << 1));
+ }
+ #define spi_init()    bitbang_init()
+ #define spi_out_byte(b)       bitbang_out_byte(b)
+ #define spi_in_byte() bitbang_in_byte()
+ #define spi_cs(b)     bitbang_cs(b)
+ #endif
+ #if USART
+ /*
+  * This version uses the USART in SPI mode
+  */
+ void
+ usart_init(void)
+ {
+       /*
+        * Configure our chip select line
+        */
+       CS = 1;
+       P1DIR |= (1 << 2);
+       /*
+        * Configure the peripheral pin choices
+        * for both of the serial ports
+        *
+        * Note that telemetrum will use U1CFG_ALT_2
+        * but that overlaps with SPI ALT_2, so until
+        * we can test that this works, we'll set this
+        * to ALT_1
+        */
+       PERCFG = (PERCFG_U1CFG_ALT_1 |
+                 PERCFG_U0CFG_ALT_2);
+       /*
+        * Make the SPI pins controlled by the SPI
+        * hardware
+        */
+       P1SEL |= ((1 << 5) | (1 << 4) | (1 << 3));
+       /*
+        * SPI in master mode
+        */
+       U0CSR = (UxCSR_MODE_SPI |
+                UxCSR_MASTER);
+       /*
+        * The cc1111 is limited to a 24/8 MHz SPI clock,
+        * while the 25LC1024 is limited to 20MHz. So,
+        * use the 3MHz clock (BAUD_E 17, BAUD_M 0)
+        */
+       U0BAUD = 0;
+       U0GCR = (UxGCR_CPOL_NEGATIVE |
+                UxGCR_CPHA_FIRST_EDGE |
+                UxGCR_ORDER_MSB |
+                (17 << UxGCR_BAUD_E_SHIFT));
+ }
+ void
+ usart_cs(uint8_t b)
+ {
+       CS = b;
+ }
+ uint8_t
+ usart_in_out(uint8_t byte)
+ {
+       U0DBUF = byte;
+       while ((U0CSR & UxCSR_TX_BYTE) == 0)
+               ;
+       U0CSR &= ~UxCSR_TX_BYTE;
+       return U0DBUF;
+ }
+ void
+ usart_out_byte(uint8_t byte)
+ {
+       (void) usart_in_out(byte);
+ }
+ uint8_t
+ usart_in_byte(void)
+ {
+       return usart_in_out(0xff);
+ }
+ #define spi_init()    usart_init()
+ #define spi_out_byte(b)       usart_out_byte(b)
+ #define spi_in_byte() usart_in_byte()
+ #define spi_cs(b)     usart_cs(b)
+ #endif
+ uint8_t
+ rdsr(void)
+ {
+       uint8_t status;
+       spi_cs(0);
+       spi_out_byte(0x05);
+       status = spi_in_byte();
+       spi_cs(1);
+       return status;
+ }
+ void
+ wrsr(uint8_t status)
+ {
+       spi_cs(0);
+       spi_out_byte(0x01);
+       spi_out_byte(status);
+       spi_cs(1);
+ }
 -      
++
+ void
+ wren(void)
+ {
+       spi_cs(0);
+       spi_out_byte(0x06);
+       spi_cs(1);
+ }
+ void
+ write(uint32_t addr, uint8_t *bytes, uint16_t len)
+ {
+       wren();
+       spi_cs(0);
+       spi_out_byte(0x02);
+       spi_out_byte(addr >> 16);
+       spi_out_byte(addr >> 8);
+       spi_out_byte(addr);
+       while (len-- > 0)
+               spi_out_byte(*bytes++);
+       spi_cs(1);
+       for (;;) {
+               uint8_t status = rdsr();
+               if ((status & (1 << 0)) == 0)
+                       break;
+       }
+ }
+ void
+ read(uint32_t addr, uint8_t *bytes, uint16_t len)
+ {
+       spi_cs(0);
+       spi_out_byte(0x03);
+       spi_out_byte(addr >> 16);
+       spi_out_byte(addr >> 8);
+       spi_out_byte(addr);
+       while (len-- > 0)
+               *bytes++ = spi_in_byte();
+       spi_cs(1);
+ }
+ void
+ debug_byte(uint8_t byte)
+ {
+       uint8_t s;
+       for (s = 0; s < 8; s++) {
+               DEBUG = byte & 1;
+               delay(5);
+               byte >>= 1;
+       }
+ }
+ #define STRING        "\360\252"
+ #define LENGTH        2
+ main ()
+ {
+       uint8_t status;
+       uint8_t buf[LENGTH];
+       int i;
+       P1DIR |= 2;
+       CLKCON = 0;
+       while (!(SLEEP & SLEEP_XOSC_STB))
+               ;
++
+       spi_init();
+       status = rdsr();
+       /*
+        * Turn off both block-protect bits
+        */
+       status &= ~((1 << 3) | (1 << 2));
+       /*
+        * Turn off write protect enable
+        */
+       status &= ~(1 << 7);
+       wrsr(status);
+       write(0x0, STRING, LENGTH);
+       for (;;) {
+               read(0x0, buf, LENGTH);
+               for (i = 0; i < LENGTH; i++)
+                       debug_byte(buf[i]);
+       }
+ }
diff --cc target/isr.c
index 0000000,43aedc2..ae4d04c
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,90 +1,89 @@@
 -
+ /*
+  * Copyright © 2008 Keith Packard <keithp@keithp.com>
+  *
+  * 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.
+  */
+ void rftxrx_isr (void) __interrupt(0) __using(1)
+ {
+ }
+ void adc_isr (void) __interrupt(1) __using(1)
+ {
+ }
+ void urx0_isr (void) __interrupt(2) __using(1)
+ {
+ }
+ void urx1_isr (void) __interrupt(3) __using(1)
+ {
+ }
+ void enc_isr (void) __interrupt(4) __using(1)
+ {
+ }
+ void st_isr (void) __interrupt(5) __using(1)
+ {
+ }
+ void usb_isr (void) __interrupt(6) __using(1)
+ {
+ }
+ void utx0_isr (void) __interrupt(7) __using(1)
+ {
+ }
+ void dma_isr (void) __interrupt(8) __using(1)
+ {
+ }
+ void t1_isr (void) __interrupt(9) __using(1)
+ {
+ }
+ void t2_isr (void) __interrupt(10) __using(1)
+ {
+ }
+ void t3_isr (void) __interrupt(11) __using(1)
+ {
+ }
+ void t4_isr (void) __interrupt(12) __using(1)
+ {
+ }
+ void p0int_isr (void) __interrupt(13) __using(1)
+ {
+ }
+ void utx1_isr (void) __interrupt(14) __using(1)
+ {
+ }
+ void p1int_isr (void) __interrupt(15) __using(1)
+ {
+ }
+ void rf_isr (void) __interrupt(16) __using(1)
+ {
+ }
+ void wdt_isr (void) __interrupt(17) __using(1)
+ {
+ }
index 0000000,c9b3d18..ea7c984
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,207 +1,207 @@@
 -      
+ /*
+  * Copyright © 2009 Keith Packard <keithp@keithp.com>
+  *
+  * 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; version 2 of the License.
+  *
+  * 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 "radio.h"
+ /* Values from SmartRF® Studio for:
+  *
+  * Deviation: 20.507812 kHz
+  * Datarate:  38.360596 kBaud
+  * Modulation:        GFSK
+  * RF Freq:   434.549927 MHz
+  * Channel:   99.975586 kHz
+  * Channel:   0
+  * RX filter: 93.75 kHz
+  */
+ /*
+  * For 434.550MHz, the frequency value is:
+  *
+  * 434.550e6 / (24e6 / 2**16) = 1186611.2
+  */
+ #define FREQ_CONTROL  1186611
+ /*
+  * For IF freq of 140.62kHz, the IF value is:
+  *
+  * 140.62e3 / (24e6 / 2**10) = 6
+  */
+ #define IF_FREQ_CONTROL       6
+ /*
+  * For channel bandwidth of 93.75 kHz, the CHANBW_E and CHANBW_M values are
+  *
+  * BW = 24e6 / (8 * (4 + M) * 2 ** E)
+  *
+  * So, M = 0 and E = 3
+  */
+ #define CHANBW_M      0
+ #define CHANBW_E      3
+ /*
+  * For a symbol rate of 38360kBaud, the DRATE_E and DRATE_M values are:
+  *
+  * R = (256 + M) * 2** E * 24e6 / 2**28
+  *
+  * So M is 163 and E is 10
+  */
+ #define DRATE_E               10
+ #define DRATE_M               163
+ /*
+  * For a channel deviation of 20.5kHz, the DEVIATION_E and DEVIATION_M values are:
+  *
+  * F = 24e6/2**17 * (8 + DEVIATION_M) * 2**DEVIATION_E
+  *
+  * So M is 6 and E is 3
+  */
+ #define DEVIATION_M   6
+ #define DEVIATION_E   3
+ #define PACKET_LEN    128
+ /* This are from the table for 433MHz */
+ #define RF_POWER_M30_DBM      0x12
+ #define RF_POWER_M20_DBM      0x0e
+ #define RF_POWER_M15_DBM      0x1d
+ #define RF_POWER_M10_DBM      0x34
+ #define RF_POWER_M5_DBM               0x2c
+ #define RF_POWER_0_DBM                0x60
+ #define RF_POWER_5_DBM                0x84
+ #define RF_POWER_7_DBM                0xc8
+ #define RF_POWER_10_DBM               0xc0
+ #define RF_POWER              RF_POWER_0_DBM
+ static __code uint8_t radio_setup[] = {
+       RF_PA_TABLE7_OFF,       RF_POWER,
+       RF_PA_TABLE6_OFF,       RF_POWER,
+       RF_PA_TABLE5_OFF,       RF_POWER,
+       RF_PA_TABLE4_OFF,       RF_POWER,
+       RF_PA_TABLE3_OFF,       RF_POWER,
+       RF_PA_TABLE2_OFF,       RF_POWER,
+       RF_PA_TABLE1_OFF,       RF_POWER,
+       RF_PA_TABLE0_OFF,       RF_POWER,
+       RF_FREQ2_OFF,           FREQ_CONTROL >> 16,
+       RF_FREQ1_OFF,           FREQ_CONTROL >> 8,
+       RF_FREQ0_OFF,           FREQ_CONTROL >> 0,
 -      
++
+       RF_FSCTRL1_OFF,         (IF_FREQ_CONTROL << RF_FSCTRL1_FREQ_IF_SHIFT),
+       RF_FSCTRL0_OFF,         (0 << RF_FSCTRL0_FREQOFF_SHIFT),
+       RF_MDMCFG4_OFF,         ((CHANBW_E << RF_MDMCFG4_CHANBW_E_SHIFT) |
+                                (CHANBW_M << RF_MDMCFG4_CHANBW_M_SHIFT) |
+                                (DRATE_E << RF_MDMCFG4_DRATE_E_SHIFT)),
+       RF_MDMCFG3_OFF,         (DRATE_M << RF_MDMCFG3_DRATE_M_SHIFT),
+       RF_MDMCFG2_OFF,         (RF_MDMCFG2_DEM_DCFILT_OFF |
+                                RF_MDMCFG2_MOD_FORMAT_GFSK |
+                                RF_MDMCFG2_SYNC_MODE_15_16_THRES),
+       RF_MDMCFG1_OFF,         (RF_MDMCFG1_FEC_EN |
+                                RF_MDMCFG1_NUM_PREAMBLE_4 |
+                                (2 << RF_MDMCFG1_CHANSPC_E_SHIFT)),
+       RF_MDMCFG0_OFF,         (17 << RF_MDMCFG0_CHANSPC_M_SHIFT),
+       RF_CHANNR_OFF,          0,
+       RF_DEVIATN_OFF,         ((DEVIATION_E << RF_DEVIATN_DEVIATION_E_SHIFT) |
+                                (DEVIATION_M << RF_DEVIATN_DEVIATION_M_SHIFT)),
+       /* SmartRF says set LODIV_BUF_CURRENT_TX to 0
+        * And, we're not using power ramping, so use PA_POWER 0
+        */
+       RF_FREND0_OFF,          ((1 << RF_FREND0_LODIV_BUF_CURRENT_TX_SHIFT) |
+                                (0 << RF_FREND0_PA_POWER_SHIFT)),
+       RF_FREND1_OFF,          ((1 << RF_FREND1_LNA_CURRENT_SHIFT) |
+                                (1 << RF_FREND1_LNA2MIX_CURRENT_SHIFT) |
+                                (1 << RF_FREND1_LODIV_BUF_CURRENT_RX_SHIFT) |
+                                (2 << RF_FREND1_MIX_CURRENT_SHIFT)),
+       RF_FSCAL3_OFF,          0xE9,
+       RF_FSCAL2_OFF,          0x0A,
+       RF_FSCAL1_OFF,          0x00,
+       RF_FSCAL0_OFF,          0x1F,
+       RF_TEST2_OFF,           0x88,
+       RF_TEST1_OFF,           0x31,
+       RF_TEST0_OFF,           0x09,
+       /* default sync values */
+       RF_SYNC1_OFF,           0xD3,
+       RF_SYNC0_OFF,           0x91,
++
+       /* max packet length */
+       RF_PKTLEN_OFF,          PACKET_LEN,
+       RF_PKTCTRL1_OFF,        ((1 << PKTCTRL1_PQT_SHIFT)|
+                                PKTCTRL1_APPEND_STATUS|
+                                PKTCTRL1_ADR_CHK_NONE),
+       RF_PKTCTRL0_OFF,        (RF_PKTCTRL0_WHITE_DATA|
+                                RF_PKTCTRL0_PKT_FORMAT_NORMAL|
+                                RF_PKTCTRL0_CRC_EN|
+                                RF_PKTCTRL0_LENGTH_CONFIG_FIXED),
+       RF_ADDR_OFF,            0x00,
+       RF_MCSM2_OFF,           (RF_MCSM2_RX_TIME_END_OF_PACKET),
+       RF_MCSM1_OFF,           (RF_MCSM1_CCA_MODE_RSSI_BELOW_UNLESS_RECEIVING|
+                                RF_MCSM1_RXOFF_MODE_IDLE|
+                                RF_MCSM1_TXOFF_MODE_IDLE),
+       RF_MCSM0_OFF,           (RF_MCSM0_FS_AUTOCAL_FROM_IDLE|
+                                RF_MCSM0_MAGIC_3|
+                                RF_MCSM0_CLOSE_IN_RX_18DB),
+       RF_FOCCFG_OFF,          (RF_FOCCFG_FOC_PRE_K_3K,
+                                RF_FOCCFG_FOC_POST_K_PRE_K,
+                                RF_FOCCFG_FOC_LIMIT_BW_OVER_4),
+       RF_BSCFG_OFF,           (RF_BSCFG_BS_PRE_K_2K|
+                                RF_BSCFG_BS_PRE_KP_3KP|
+                                RF_BSCFG_BS_POST_KI_PRE_KI|
+                                RF_BSCFG_BS_POST_KP_PRE_KP|
+                                RF_BSCFG_BS_LIMIT_0),
+       RF_AGCCTRL2_OFF,        0x43,
+       RF_AGCCTRL1_OFF,        0x40,
+       RF_AGCCTRL0_OFF,        0x91,
+       RF_IOCFG2_OFF,          0x00,
+       RF_IOCFG1_OFF,          0x00,
+       RF_IOCFG0_OFF,          0x00,
+ };
+ void
+ radio_init(void) {
+       uint8_t i;
+       for (i = 0; i < sizeof (radio_setup); i += 2)
+               RF[radio_setup[i]] = radio_setup[i+1];
+ }
+ #define nop() _asm nop _endasm;
+ void
+ delay (unsigned char n)
+ {
+       unsigned char i = 0;
+       n <<= 1;
+       while (--n != 0)
+               while (--i != 0)
+                       nop();
+ }
index 0000000,1f50d8a..c50c320
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,68 +1,68 @@@
 -              
+ /*
+  * Copyright © 2008 Keith Packard <keithp@keithp.com>
+  *
+  * 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 "radio.h"
+ main ()
+ {
+       static uint8_t  packet[PACKET_LEN + 2];
+       CLKCON = 0;
+       while (!(SLEEP & SLEEP_XOSC_STB))
+               ;
+       /* Set P2_0 to output */
+       P1 = 0;
+       P1DIR = 0x02;
+       radio_init ();
+       delay(100);
+       for (;;) {
+               uint8_t i;
+               RFST = RFST_SIDLE;
+               RFIF = 0;
+               delay(100);
+               RFST = RFST_SRX;
+ //            while (!(RFIF & RFIF_IM_CS));
+ //            P1 = 2;
+               for (i = 0; i < PACKET_LEN + 2; i++) {
+                       while (!RFTXRXIF)
+                               ;
+                       P1=2;
+                       RFTXRXIF = 0;
+                       packet[i] = RFD;
+               }
+               P1 = 0;
++
+               /* check packet contents */
+               for (i = 0; i < PACKET_LEN; i++)
+                       if (packet[i] != i)
+                               break;
+               /* get excited if the packet came through correctly */
+               if (i == PACKET_LEN &&
+                   packet[PACKET_LEN+1] & PKT_APPEND_STATUS_1_CRC_OK)
+               {
+                       for (i = 0; i < 5; i++){
+                               P1 = 2;
+                               delay(100);
+                               P1 = 0;
+                               delay(100);
+                       }
+               }
+               delay(100);
+       }
+ }
index 0000000,2939042..63f6c6d
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,270 +1,270 @@@
 -      
+ /*
+  * Copyright © 2008 Keith Packard <keithp@keithp.com>
+  *
+  * 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 <stdint.h>
+ /*
+  * Validate UART1
+  */
+ sfr at 0x80 P0;
+ sfr at 0x90 P1;
+ sfr at 0xA0 P2;
+ sfr at 0xC6 CLKCON;
+ sfr at 0xbe SLEEP;
+ # define SLEEP_USB_EN         (1 << 7)
+ # define SLEEP_XOSC_STB               (1 << 6)
+ sfr at 0xF1 PERCFG;
+ #define PERCFG_T1CFG_ALT_1    (0 << 6)
+ #define PERCFG_T1CFG_ALT_2    (1 << 6)
+ #define PERCFG_T3CFG_ALT_1    (0 << 5)
+ #define PERCFG_T3CFG_ALT_2    (1 << 5)
+ #define PERCFG_T4CFG_ALT_1    (0 << 4)
+ #define PERCFG_T4CFG_ALT_2    (1 << 4)
+ #define PERCFG_U1CFG_ALT_1    (0 << 1)
+ #define PERCFG_U1CFG_ALT_2    (1 << 1)
+ #define PERCFG_U0CFG_ALT_1    (0 << 0)
+ #define PERCFG_U0CFG_ALT_2    (1 << 0)
+ sfr at 0xF2 ADCCFG;
+ sfr at 0xF3 P0SEL;
+ sfr at 0xF4 P1SEL;
+ sfr at 0xF5 P2SEL;
+ sfr at 0xFD P0DIR;
+ sfr at 0xFE P1DIR;
+ sfr at 0xFF P2DIR;
+ sfr at 0x8F P0INP;
+ sfr at 0xF6 P1INP;
+ sfr at 0xF7 P2INP;
+ sfr at 0x89 P0IFG;
+ sfr at 0x8A P1IFG;
+ sfr at 0x8B P2IFG;
+ sbit at 0x90 P1_0;
+ sbit at 0x91 P1_1;
+ sbit at 0x92 P1_2;
+ sbit at 0x93 P1_3;
+ sbit at 0x94 P1_4;
+ sbit at 0x95 P1_5;
+ sbit at 0x96 P1_6;
+ sbit at 0x97 P1_7;
+ /*
+  * UART registers
+  */
+ sfr at 0x86 U0CSR;
+ sfr at 0xF8 U1CSR;
+ /*
+  * IRCON2
+  */
+ sfr at 0xE8 IRCON2;   /* CPU Interrupt Flag 5 */
+ sbit at 0xE8 USBIF;   /* USB interrupt flag (shared with Port2) */
+ sbit at 0xE8 P2IF;    /* Port2 interrupt flag (shared with USB) */
+ sbit at 0xE9 UTX0IF;  /* USART0 TX interrupt flag */
+ sbit at 0xEA UTX1IF;  /* USART1 TX interrupt flag (shared with I2S TX) */
+ sbit at 0xEA I2STXIF; /* I2S TX interrupt flag (shared with USART1 TX) */
+ sbit at 0xEB P1IF;    /* Port1 interrupt flag */
+ sbit at 0xEC WDTIF;   /* Watchdog timer interrupt flag */
+ # define UxCSR_MODE_UART              (1 << 7)
+ # define UxCSR_MODE_SPI                       (0 << 7)
+ # define UxCSR_RE                     (1 << 6)
+ # define UxCSR_SLAVE                  (1 << 5)
+ # define UxCSR_MASTER                 (0 << 5)
+ # define UxCSR_FE                     (1 << 4)
+ # define UxCSR_ERR                    (1 << 3)
+ # define UxCSR_RX_BYTE                        (1 << 2)
+ # define UxCSR_TX_BYTE                        (1 << 1)
+ # define UxCSR_ACTIVE                 (1 << 0)
+ sfr at 0xc4 U0UCR;
+ sfr at 0xfb U1UCR;
+ # define UxUCR_FLUSH                  (1 << 7)
+ # define UxUCR_FLOW_DISABLE           (0 << 6)
+ # define UxUCR_FLOW_ENABLE            (1 << 6)
+ # define UxUCR_D9_EVEN_PARITY         (0 << 5)
+ # define UxUCR_D9_ODD_PARITY          (1 << 5)
+ # define UxUCR_BIT9_8_BITS            (0 << 4)
+ # define UxUCR_BIT9_9_BITS            (1 << 4)
+ # define UxUCR_PARITY_DISABLE         (0 << 3)
+ # define UxUCR_PARITY_ENABLE          (1 << 3)
+ # define UxUCR_SPB_1_STOP_BIT         (0 << 2)
+ # define UxUCR_SPB_2_STOP_BITS                (1 << 2)
+ # define UxUCR_STOP_LOW                       (0 << 1)
+ # define UxUCR_STOP_HIGH              (1 << 1)
+ # define UxUCR_START_LOW              (0 << 0)
+ # define UxUCR_START_HIGH             (1 << 0)
+ sfr at 0xc5 U0GCR;
+ sfr at 0xfc U1GCR;
+ # define UxGCR_CPOL_NEGATIVE          (0 << 7)
+ # define UxGCR_CPOL_POSITIVE          (1 << 7)
+ # define UxGCR_CPHA_FIRST_EDGE                (0 << 6)
+ # define UxGCR_CPHA_SECOND_EDGE               (1 << 6)
+ # define UxGCR_ORDER_LSB              (0 << 5)
+ # define UxGCR_ORDER_MSB              (1 << 5)
+ # define UxGCR_BAUD_E_MASK            (0x1f)
+ # define UxGCR_BAUD_E_SHIFT           0
+ sfr at 0xc1 U0DBUF;
+ sfr at 0xf9 U1DBUF;
+ sfr at 0xc2 U0BAUD;
+ sfr at 0xfa U1BAUD;
+ #define MOSI  P1_5
+ #define MISO  P1_4
+ #define SCK   P1_3
+ #define CS    P1_2
+ #define DEBUG P1_1
+ #define USART 1
+ #define nop() _asm nop _endasm;
+ void
+ delay (unsigned char n)
+ {
+       unsigned char i = 0;
+       unsigned char j = 0;
+       n++;
+       while (--n != 0)
+               while (--i != 0)
+                       while (--j != 0)
+                               nop();
+ }
+ /*
+  * This version uses the USART in SPI mode
+  */
+ void
+ usart_init(void)
+ {
+       P1DIR |= (1 << 2);
+       /*
+        * Configure the peripheral pin choices
+        * for both of the serial ports
+        *
+        * Note that telemetrum will use U1CFG_ALT_2
+        * but that overlaps with SPI ALT_2, so until
+        * we can test that this works, we'll set this
+        * to ALT_1
+        */
+       PERCFG = (PERCFG_U1CFG_ALT_2 |
+                 PERCFG_U0CFG_ALT_1);
+       /*
+        * Make the UART pins controlled by the UART
+        * hardware
+        */
+       P1SEL |= ((1 << 6) | (1 << 7));
+       /*
+        * UART mode with the receiver enabled
+        */
+       U1CSR = (UxCSR_MODE_UART |
+                UxCSR_RE);
+       /*
+        * Pick a 38.4kbaud rate
+        */
+       U1BAUD = 163;
+       U1GCR = 10 << UxGCR_BAUD_E_SHIFT;       /* 38400 */
+ //    U1GCR = 3 << UxGCR_BAUD_E_SHIFT;        /* 300 */
+       /*
+        * Reasonable serial parameters
+        */
+       U1UCR = (UxUCR_FLUSH |
+                UxUCR_FLOW_DISABLE |
+                UxUCR_D9_ODD_PARITY |
+                UxUCR_BIT9_8_BITS |
+                UxUCR_PARITY_DISABLE |
+                UxUCR_SPB_2_STOP_BITS |
+                UxUCR_STOP_HIGH |
+                UxUCR_START_LOW);
+ }
+ void
+ usart_out_byte(uint8_t byte)
+ {
+       U1DBUF = byte;
+       while (!UTX1IF)
+               ;
+       UTX1IF = 0;
+ }
+ void
+ usart_out_string(uint8_t *string)
+ {
+       uint8_t b;
+       while (b = *string++)
+               usart_out_byte(b);
+ }
+ uint8_t
+ usart_in_byte(void)
+ {
+       uint8_t b;
+       while ((U1CSR & UxCSR_RX_BYTE) == 0)
+               ;
+       b = U1DBUF;
+       U1CSR &= ~UxCSR_RX_BYTE;
+       return b;
+ }
+ void
+ debug_byte(uint8_t byte)
+ {
+       uint8_t s;
+       for (s = 0; s < 8; s++) {
+               DEBUG = byte & 1;
+               delay(5);
+               byte >>= 1;
+       }
+ }
+ main ()
+ {
+       P1DIR |= 2;
+       CLKCON = 0;
+       while (!(SLEEP & SLEEP_XOSC_STB))
+               ;
 -      
++
+       usart_init();
+       for (;;) {
+               usart_out_string("hello world\r\n");
+               debug_byte(usart_in_byte());
+       }
++
+ }
index 0000000,7a531cc..76c95c2
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,294 +1,294 @@@
 -  
+ /*-------------------------------------------------------------------------
+    Register Declarations for the ChipCon CC1111 Processor Range
+    Copyright © 2008 Keith Packard <keithp@keithp.com>
 -  
++
+    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.
+    Adapted from the Cygnal C8051F12x config file which is:
 -sfr at 0xE1 RFST     ;  /*                                               */ 
 -sfr at 0xE2 T1CNTL   ;  /*                                               */ 
 -sfr at 0xE3 T1CNTH   ;  /*                                               */ 
 -sfr at 0xE4 T1CTL    ;  /*                                               */ 
 -sfr at 0xE5 T1CCTL0  ;  /*                                               */ 
 -sfr at 0xE6 T1CCTL1  ;  /*                                               */ 
 -sfr at 0xE7 T1CCTL2  ;  /*                                               */ 
 -sfr at 0xE8 IRCON2   ;  /*                                               */ 
 -sfr at 0xE9 RFIF     ;  /*                                               */ 
 -sfr at 0xEA T4CNT    ;  /*                                               */ 
 -sfr at 0xEB T4CTL    ;  /*                                               */ 
 -sfr at 0xEC T4CCTL0  ;  /*                                               */ 
 -sfr at 0xED T4CC0    ;  /*                                               */ 
 -sfr at 0xEE T4CCTL1  ;  /*                                               */ 
 -sfr at 0xEF T4CC1    ;  /*                                               */ 
 -sfr at 0xF0 B        ;  /*                                               */ 
 -sfr at 0xF1 PERCFG   ;  /*                                               */ 
 -sfr at 0xF2 ADCCFG   ;  /*                                               */ 
 -sfr at 0xF3 P0SEL    ;  /*                                               */ 
 -sfr at 0xF4 P1SEL    ;  /*                                               */ 
 -sfr at 0xF5 P2SEL    ;  /*                                               */ 
 -sfr at 0xF6 P1INP    ;  /*                                               */ 
 -sfr at 0xF7 P2INP    ;  /*                                               */ 
 -sfr at 0xF8 U1CSR    ;  /*                                               */ 
 -sfr at 0xF9 U1DBUF   ;  /*                                               */ 
 -sfr at 0xFA U1BAUD   ;  /*                                               */ 
 -sfr at 0xFB U1UCR    ;  /*                                               */ 
 -sfr at 0xFC U1GCR    ;  /*                                               */ 
 -sfr at 0xFD P0DIR    ;  /*                                               */ 
 -sfr at 0xFE P1DIR    ;  /*                                               */ 
 -sfr at 0xFF P2DIR    ;  /*                                               */ 
++
+    Copyright (C) 2003 - Maarten Brock, sourceforge.brock@dse.nl
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+    This library 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
+    Lesser General Public License for more details.
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ -------------------------------------------------------------------------*/
+ #ifndef _CC1111_H_
+ #define _CC1111_H_
+ /*  BYTE Registers  */
+ sfr at 0x80 P0       ;  /* PORT 0                                        */
+ sfr at 0x81 SP       ;  /* STACK POINTER                                 */
+ sfr at 0x82 DPL      ;  /* DATA POINTER - LOW BYTE                       */
+ sfr at 0x83 DPH      ;  /* DATA POINTER - HIGH BYTE                      */
+ sfr at 0x84 DPL1     ;  /* DATA POINTER 1 - LOW BYTE                     */
+ sfr at 0x85 DPH1     ;  /* DATA POINTER 1 - HIGH BYTE                    */
+ sfr at 0x86 U0CSR    ;  /* USART 0 Control and status                    */
+ sfr at 0x87 PCON     ;  /* POWER CONTROL                                 */
+ sfr at 0x88 TCON     ;  /* TIMER CONTROL                                 */
+ sfr at 0x89 P0IFG    ;  /* TIMER MODE                                    */
+ sfr at 0x8A P1IFG    ;  /* TIMER 0 - LOW BYTE                            */
+ sfr at 0x8B P2IFG    ;  /* TIMER 1 - LOW BYTE                            */
+ sfr at 0x8C PICTL    ;  /* TIMER 0 - HIGH BYTE                           */
+ sfr at 0x8D P1IEN    ;  /* TIMER 1 - HIGH BYTE                           */
+ sfr at 0x8F P0INP    ;  /* FLASH WRITE/ERASE CONTROL                     */
+ sfr at 0x90 P1       ;  /* PORT 1                                        */
+ sfr at 0x91 RFIM     ;  /* UART 0 STATUS                                 */
+ sfr at 0x92 DPS      ;  /* */
+ sfr at 0x93 MPAGE    ;  /* */
+ sfr at 0x94 _SFR94_  ;  /* */
+ sfr at 0x95 ENDIAN   ;  /* */
+ sfr at 0x96 _SFR96_  ;  /* */
+ sfr at 0x97 _SFR97_  ;  /* */
+ sfr at 0x98 S0CON    ;  /* UART 0 CONTROL                                */
+ sfr at 0x99 _SFR99_  ;  /* UART 0 BUFFER                                 */
+ sfr at 0x9A IEN2     ;  /* SPI 0 CONFIGURATION                           */
+ sfr at 0x9B S1CON    ;  /* SPI 0 DATA                                    */
+ sfr at 0x9C T2CT     ;  /* SPI 0 DATA                                    */
+ sfr at 0x9D T2PR     ;  /* SPI 0 CLOCK RATE CONTROL                      */
+ sfr at 0x9E T2CTL    ;  /* SPI 0 CLOCK RATE CONTROL                      */
+ sfr at 0x9F _SFR9F_  ;  /* SPI 0 CLOCK RATE CONTROL                      */
+ sfr at 0xA0 P2       ;  /* PORT 2                                        */
+ sfr at 0xA1 WORIRQ   ;  /* EMIF TIMING CONTROL                           */
+ sfr at 0xA2 WORCTRL  ;  /* EMIF CONTROL                                  */
+ sfr at 0xA3 WOREVT0  ;  /* EMIF CONFIGURATION                            */
+ sfr at 0xA4 WOREVT1  ;  /* EMIF CONFIGURATION                            */
+ sfr at 0xA5 WORTIME0 ;  /* EMIF CONFIGURATION                            */
+ sfr at 0xA6 WORTIME1 ;  /* EMIF CONFIGURATION                            */
+ sfr at 0xA7 _SFRA7_  ;  /* EMIF CONFIGURATION                            */
+ sfr at 0xA8 IEN0     ;  /* INTERRUPT ENABLE                              */
+ sfr at 0xA9 IP0      ;  /* UART 0 SLAVE ADDRESS                          */
+ sfr at 0xAA _SFRAA_  ;  /*                                               */
+ sfr at 0xAB FWT      ;  /*                                               */
+ sfr at 0xAC FADDRL   ;  /*                                               */
+ sfr at 0xAD FADDRH   ;  /*                                               */
+ sfr at 0xAE FCTL     ;  /*                                               */
+ sfr at 0xAF FWDATA   ;  /*                                               */
+ sfr at 0xB0 _SFRB0_  ;  /*                                               */
+ sfr at 0xB1 ENCDI    ;  /* FLASH BANK SELECT                             */
+ sfr at 0xB2 ENCDO    ;  /*                                               */
+ sfr at 0xB3 ENCCS    ;  /*                                               */
+ sfr at 0xB4 ADCCON1  ;  /*                                               */
+ sfr at 0xB5 ADCCON2  ;  /*                                               */
+ sfr at 0xB6 ADCCON3  ;  /*                                               */
+ sfr at 0xB8 IEN1     ;  /* INTERRUPT PRIORITY                            */
+ sfr at 0xB9 IP1      ;  /*                                               */
+ sfr at 0xBA ADCL     ;  /*                                               */
+ sfr at 0xBB ADCH     ;  /*                                               */
+ sfr at 0xBC RNDL     ;  /*                                               */
+ sfr at 0xBD RNDH     ;  /*                                               */
+ sfr at 0xBE SLEEP    ;  /*                                               */
+ sfr at 0xC0 IRCON    ;  /*                                               */
+ sfr at 0xC1 U0DBUF   ;  /*                                               */
+ sfr at 0xC2 U0BAUD   ;  /*                                               */
+ sfr at 0xC4 U0UCR    ;  /*                                               */
+ sfr at 0xC5 U0GCR    ;  /*                                               */
+ sfr at 0xC6 CLKCON   ;  /*                                               */
+ sfr at 0xC7 MEMCTR   ;  /*                                               */
+ sfr at 0xC9 WDCTL    ;  /*                                               */
+ sfr at 0xCA T3CNT    ;  /*                                               */
+ sfr at 0xCB T3CTL    ;  /*                                               */
+ sfr at 0xCC T3CCTL0  ;  /*                                               */
+ sfr at 0xCD T3CC0    ;  /*                                               */
+ sfr at 0xCE T3CCTL1  ;  /*                                               */
+ sfr at 0xCF T3CC1    ;  /*                                               */
+ sfr at 0xD0 PSW      ;  /*                                               */
+ sfr at 0xD1 DMAIRQ   ;  /*                                               */
+ sfr at 0xD2 DMA1CFGL ;  /*                                               */
+ sfr at 0xD3 DMA1CFGH ;  /*                                               */
+ sfr at 0xD4 DMA0CFGL ;  /*                                               */
+ sfr at 0xD5 DMA0CFGH ;  /*                                               */
+ sfr at 0xD6 DMAARM   ;  /*                                               */
+ sfr at 0xD7 DMAREQ   ;  /*                                               */
+ sfr at 0xD8 TIMIF    ;  /*                                               */
+ sfr at 0xD9 RFD      ;  /*                                               */
+ sfr at 0xDA T1CC0L   ;  /*                                               */
+ sfr at 0xDB T1CC0H   ;  /*                                               */
+ sfr at 0xDC T1CC1L   ;  /*                                               */
+ sfr at 0xDD T1CC1H   ;  /*                                               */
+ sfr at 0xDE T1CC2L   ;  /*                                               */
+ sfr at 0xDF T1CC2H   ;  /*                                               */
+ sfr at 0xE0 ACC      ;  /* ACCUMULATOR                                   */
++sfr at 0xE1 RFST     ;  /*                                               */
++sfr at 0xE2 T1CNTL   ;  /*                                               */
++sfr at 0xE3 T1CNTH   ;  /*                                               */
++sfr at 0xE4 T1CTL    ;  /*                                               */
++sfr at 0xE5 T1CCTL0  ;  /*                                               */
++sfr at 0xE6 T1CCTL1  ;  /*                                               */
++sfr at 0xE7 T1CCTL2  ;  /*                                               */
++sfr at 0xE8 IRCON2   ;  /*                                               */
++sfr at 0xE9 RFIF     ;  /*                                               */
++sfr at 0xEA T4CNT    ;  /*                                               */
++sfr at 0xEB T4CTL    ;  /*                                               */
++sfr at 0xEC T4CCTL0  ;  /*                                               */
++sfr at 0xED T4CC0    ;  /*                                               */
++sfr at 0xEE T4CCTL1  ;  /*                                               */
++sfr at 0xEF T4CC1    ;  /*                                               */
++sfr at 0xF0 B        ;  /*                                               */
++sfr at 0xF1 PERCFG   ;  /*                                               */
++sfr at 0xF2 ADCCFG   ;  /*                                               */
++sfr at 0xF3 P0SEL    ;  /*                                               */
++sfr at 0xF4 P1SEL    ;  /*                                               */
++sfr at 0xF5 P2SEL    ;  /*                                               */
++sfr at 0xF6 P1INP    ;  /*                                               */
++sfr at 0xF7 P2INP    ;  /*                                               */
++sfr at 0xF8 U1CSR    ;  /*                                               */
++sfr at 0xF9 U1DBUF   ;  /*                                               */
++sfr at 0xFA U1BAUD   ;  /*                                               */
++sfr at 0xFB U1UCR    ;  /*                                               */
++sfr at 0xFC U1GCR    ;  /*                                               */
++sfr at 0xFD P0DIR    ;  /*                                               */
++sfr at 0xFE P1DIR    ;  /*                                               */
++sfr at 0xFF P2DIR    ;  /*                                               */
+ /*  BIT Registers  */
+ /*  P0  0x80 */
+ sbit at 0x80 P0_0    ;
+ sbit at 0x81 P0_1    ;
+ sbit at 0x82 P0_2    ;
+ sbit at 0x83 P0_3    ;
+ sbit at 0x84 P0_4    ;
+ sbit at 0x85 P0_5    ;
+ sbit at 0x86 P0_6    ;
+ sbit at 0x87 P0_7    ;
+ /*  TCON  0x88 */
+ sbit at 0x89 RFTXRXIF;  /*                                               */
+ sbit at 0x8B URX0IF  ;  /*                                               */
+ sbit at 0x8D ADCIF   ;  /*                                               */
+ sbit at 0x8F URX1IF  ;  /*                                               */
+ sbit at 0x8F I2SRXIF ;  /*                                               */
+ /*  SCON0  0x98 */
+ sbit at 0x98 ENCIF_0 ;  /* UART 0 RX INTERRUPT FLAG                      */
+ sbit at 0x99 ENCIF_1 ;  /* UART 0 RX INTERRUPT FLAG                      */
+ /*  IEN0  0xA8 */
+ sbit at 0xA8 RFTXRXIE;  /* RF TX/RX done interrupt enable                */
+ sbit at 0xA9 ADCIE   ;  /* ADC interrupt enable                          */
+ sbit at 0xAA URX0IE  ;  /* USART0 RX interrupt enable                    */
+ sbit at 0xAB URX1IE  ;  /* USART1 RX interrupt enable                    */
+ sbit at 0xAB I2SRXIE ;  /* I2S RX interrupt enable                       */
+ sbit at 0xAC ENCIE   ;  /* AES interrupt enable                          */
+ sbit at 0xAD STIE    ;  /* Sleep Timer interrupt enable                  */
+ sbit at 0xAF EA      ;  /* GLOBAL INTERRUPT ENABLE                       */
+ /*  IEN1  0xB8 */
+ sbit at 0xB8 DMAIE   ;  /* DMA transfer interrupt enable                 */
+ sbit at 0xB9 T1IE    ;  /* Timer 1 interrupt enable                      */
+ sbit at 0xBA T2IE    ;  /* Timer 2 interrupt enable                      */
+ sbit at 0xBB T3IE    ;  /* Timer 3 interrupt enable                      */
+ sbit at 0xBC T4IE    ;  /* Timer 4 interrupt enable                      */
+ sbit at 0xBD P0IE    ;  /* Port 0 interrupt enable                       */
+ /* IRCON 0xC0 */
+ sbit at 0xC0 DMAIF   ;  /*                                             */
+ sbit at 0xC1 T1IF    ;  /*                                             */
+ sbit at 0xC2 T2IF    ;  /*                                             */
+ sbit at 0xC3 T3IF    ;  /*                                             */
+ sbit at 0xC4 T4IF    ;  /*                                             */
+ sbit at 0xC5 P0IF    ;  /*                                             */
+ sbit at 0xC7 STIF    ;  /*                                             */
+ /*  PSW  0xD0 */
+ sbit at 0xD0 P       ;  /* ACCUMULATOR PARITY FLAG                       */
+ sbit at 0xD1 F1      ;  /* USER FLAG 1                                   */
+ sbit at 0xD2 OV      ;  /* OVERFLOW FLAG                                 */
+ sbit at 0xD3 RS0     ;  /* REGISTER BANK SELECT 0                        */
+ sbit at 0xD4 RS1     ;  /* REGISTER BANK SELECT 1                        */
+ sbit at 0xD5 F0      ;  /* USER FLAG 0                                   */
+ sbit at 0xD6 AC      ;  /* AUXILIARY CARRY FLAG                          */
+ sbit at 0xD7 CY      ;  /* CARRY FLAG                                    */
+ /* TIMIF D8H */
+ sbit at 0xD8 T3OVFIF ;  /*                                               */
+ sbit at 0xD9 T3CH0IF ;  /*                                               */
+ sbit at 0xDA T3CH1IF ;  /*                                               */
+ sbit at 0xDB T4OVFIF ;  /*                                               */
+ sbit at 0xDC T4CH0IF ;  /*                                               */
+ sbit at 0xDD T4CH1IF ;  /*                                               */
+ sbit at 0xDE OVFIM   ;  /*                                               */
+ /* IRCON2  E8H */
+ sbit at 0xE8 P2IF    ;  /*                                                     */
+ sbit at 0xE8 USBIF   ;  /*                                                     */
+ sbit at 0xE9 UTX0IF  ;  /*                                                     */
+ sbit at 0xEA UTX1IF  ;  /*                                                     */
+ sbit at 0xEA I2STXIF ;  /*                                                     */
+ sbit at 0xEB P1IF    ;  /*                                                     */
+ sbit at 0xEC WDTIF   ;  /*                                                     */
+ /* U1CSR F8H */
+ sbit at 0xF8 U1_ACTIVE  ;  /*                                               */
+ sbit at 0xF9 U1_TX_BYTE ;  /*                                               */
+ sbit at 0xFA U1_RX_BYTE ;  /*                                               */
+ sbit at 0xFB U1_ERR     ;  /*                                               */
+ sbit at 0xFC U1_FE      ;  /*                                               */
+ sbit at 0xFD U1_SLAVE   ;  /*                                               */
+ sbit at 0xFE U1_RE      ;  /*                                               */
+ sbit at 0xFF U1_MODE    ;  /*                                               */
+ #define T1CTL_MODE_SUSPENDED  (0 << 0)
+ #define T1CTL_MODE_FREE               (1 << 0)
+ #define T1CTL_MODE_MODULO     (2 << 0)
+ #define T1CTL_MODE_UP_DOWN    (3 << 0)
+ #define T1CTL_MODE_MASK               (3 << 0)
+ #define T1CTL_DIV_1           (0 << 2)
+ #define T1CTL_DIV_8           (1 << 2)
+ #define T1CTL_DIV_32          (2 << 2)
+ #define T1CTL_DIV_128         (3 << 2)
+ #define T1CTL_DIV_MASK                (3 << 2)
+ #define T1CTL_OVFIF           (1 << 4)
+ #define T1CTL_CH0IF           (1 << 5)
+ #define T1CTL_CH1IF           (1 << 6)
+ #define T1CTL_CH2IF           (1 << 7)
+ #define T1CCTL_NO_CAPTURE     (0 << 0)
+ #define T1CCTL_CAPTURE_RISING (1 << 0)
+ #define T1CCTL_CAPTURE_FALLING        (2 << 0)
+ #define T1CCTL_CAPTURE_BOTH   (3 << 0)
+ #define T1CCTL_CAPTURE_MASK   (3 << 0)
+ #define T1CCTL_MODE_CAPTURE   (0 << 2)
+ #define T1CCTL_MODE_COMPARE   (1 << 2)
+ #define T1CTL_CMP_SET         (0 << 3)
+ #define T1CTL_CMP_CLEAR               (1 << 3)
+ #define T1CTL_CMP_TOGGLE      (2 << 3)
+ #define T1CTL_CMP_SET_CLEAR   (3 << 3)
+ #define T1CTL_CMP_CLEAR_SET   (4 << 3)
+ #define T1CTL_IM_DISABLED     (0 << 6)
+ #define T1CTL_IM_ENABLED      (1 << 6)
+ #define T1CTL_CPSEL_NORMAL    (0 << 7)
+ #define T1CTL_CPSEL_RF                (1 << 7)
+ #endif
index 0000000,fe25bfe..2b5ec02
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,11 +1,10 @@@
 -
+ #
+ # Debug mode - drive RESET_N low for two clock cycles
+ #
+ C D R
+ . D .
+ C D .
+ . D .
+ C D .
+ . D R
index 0000000,1d4ff03..3e67a2e
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,329 +1,328 @@@
 -
+ #
+ # Debug mode - drive RESET_N low for two clock cycles
+ #
+ C D R
+ . D .
+ C D .
+ . D .
+ C D .
+ . D R
+ #
+ # Halt 0x44
+ #
+ C . R 0
+ . . R
+ C D R 1
+ . D R
+ C . R 0
+ . . R
+ C . R 0
+ . . R
+ C . R 0
+ . . R
+ C D R 1
+ . D R
+ C . R 0
+ . . R
+ C . R 0
+ . . R
+ # status byte
+ C D R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ # Resume 0x4c
+ #
+ C . R 0
+ . . R
+ C D R 1
+ . D R
+ C . R 0
+ . . R
+ C . R 0
+ . . R
+ C D R 1
+ . D R
+ C D R 1
+ . D R
+ C . R 0
+ . . R
+ C . R 0
+ . . R
+ # status byte
+ C D R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ #
+ # READ_STATUS
+ #
+ C . R 0
+ . . R
+ C . R 0
+ . . R
+ C D R 1
+ . D R
+ C D R 1
+ . D R
+ C . R 0
+ . . R
+ C D R 1
+ . D R
+ C . R 0
+ . . R
+ C . R 0
+ . . R
+ #
+ # status
+ #
+ C D R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ #
+ # READ_STATUS
+ #
+ C . R 0
+ . . R
+ C . R 0
+ . . R
+ C D R 1
+ . D R
+ C D R 1
+ . D R
+ C . R 0
+ . . R
+ C D R 1
+ . D R
+ C . R 0
+ . . R
+ C . R 0
+ . . R
+ #
+ # status
+ #
+ C D R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ #
+ # READ_STATUS
+ #
+ C . R 0
+ . . R
+ C . R 0
+ . . R
+ C D R 1
+ . D R
+ C D R 1
+ . D R
+ C . R 0
+ . . R
+ C D R 1
+ . D R
+ C . R 0
+ . . R
+ C . R 0
+ . . R
+ #
+ # status
+ #
+ C D R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ #
+ # Halt 0x44
+ #
+ C . R 0
+ . . R
+ C D R 1
+ . D R
+ C . R 0
+ . . R
+ C . R 0
+ . . R
+ C . R 0
+ . . R
+ C D R 1
+ . D R
+ C . R 0
+ . . R
+ C . R 0
+ . . R
+ # status byte
+ C D R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ #
+ # READ_STATUS
+ #
+ C . R 0
+ . . R
+ C . R 0
+ . . R
+ C D R 1
+ . D R
+ C D R 1
+ . D R
+ C . R 0
+ . . R
+ C D R 1
+ . D R
+ C . R 0
+ . . R
+ C . R 0
+ . . R
+ #
+ # status
+ #
+ C D R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R
+ C - R
+ . - R