From: Keith Packard Date: Thu, 4 Jun 2009 18:13:15 +0000 (-0700) Subject: Merge ccdbg and altos sources into one giant repository X-Git-Tag: 0.5~58 X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=commitdiff_plain;h=17d2432a8b9c15963cd3b821f025ad33972ef477 Merge ccdbg and altos sources into one giant repository Keeping these separate isn't making things any easier. Signed-off-by: Keith Packard --- 17d2432a8b9c15963cd3b821f025ad33972ef477 diff --cc .gitignore index 190ba2fd,93d05b7f..71b0a614 --- a/.gitignore +++ b/.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 index c9fd2c0c,d3c5b40a..200806c5 --- a/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 index e5c0c1e8,86f2fad5..b0d059ea --- a/Makefile.am +++ b/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 00000000,a36ad375..b84a88a6 mode 000000,100644..100644 --- a/aoload/aoload.c +++ b/aoload/aoload.c @@@ -1,0 -1,231 +1,231 @@@ + /* + * Copyright © 2008 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + + #include + #include + #include + #include "ccdbg.h" + + #define AO_USB_DESC_STRING 3 + + void + usage(char *program) + { + fprintf(stderr, "usage: %s \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); + } diff --cc aoview/Makefile.am index 9f67ac40,00000000..be3fbacf mode 100644,000000..100644 --- a/aoview/Makefile.am +++ b/aoview/Makefile.am @@@ -1,28 -1,0 +1,28 @@@ +VERSION=$(shell git describe) - AM_CFLAGS=$(AOVIEW_CFLAGS) -I$(top_srcdir)/src -DAOVIEW_VERSION=\"$(VERSION)\" ++AM_CFLAGS=$(GNOME_CFLAGS) -I$(top_srcdir)/src -DAOVIEW_VERSION=\"$(VERSION)\" + +bin_PROGRAMS=aoview + - aoview_LDADD=$(AOVIEW_LIBS) ++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 00000000,3e220914..5f7708fd mode 000000,100644..100644 --- a/ccload/ccload.c +++ b/ccload/ccload.c @@@ -1,0 -1,80 +1,80 @@@ + /* + * Copyright © 2008 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + + #include "ccdbg.h" + + 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 \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); + } diff --cc ccmanual/ccmanual.c index 00000000,402d9b13..7090c9a3 mode 000000,100644..100644 --- a/ccmanual/ccmanual.c +++ b/ccmanual/ccmanual.c @@@ -1,0 -1,33 +1,33 @@@ + /* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + + #include "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 index 0419489a,6c8963c4..99511a6e --- a/configure.ac +++ b/configure.ac @@@ -1,6 -1,6 +1,6 @@@ -dnl -dnl Copyright © 2008 Keith Packard -dnl +dnl - dnl Copyright © 2008 Keith Packard ++dnl Copyright © 2008,2009 Keith Packard +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 ]) diff --cc lib/cc-bitbang.c index 00000000,a5d2d369..1d3ba476 mode 000000,100644..100644 --- a/lib/cc-bitbang.c +++ b/lib/cc-bitbang.c @@@ -1,0 -1,270 +1,269 @@@ + /* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + + #include + #include + #include + #include "ccdbg-debug.h" + #include "cc-bitbang.h" + + #define CP_USB_ASYNC + + #ifdef CP_USB_ASYNC + #include "cp-usb-async.h" + #else + #include "cp-usb.h" + #endif + + struct cc_bitbang { + #ifdef CP_USB_ASYNC + struct cp_usb_async *cp_async; + #else + struct cp_usb *cp; + #endif + }; + + static uint32_t cc_clock_us = CC_CLOCK_US; + static uint32_t cc_reset_us = CC_RESET_US; + + void + cc_bitbang_set_clock(uint32_t us) + { + cc_clock_us = us; + } + + void + cc_bitbang_half_clock(struct cc_bitbang *bb) + { + struct timespec req, rem; + req.tv_sec = (cc_clock_us / 2) / 1000000; + req.tv_nsec = ((cc_clock_us / 2) % 1000000) * 1000; + nanosleep(&req, &rem); + } + + void + cc_bitbang_wait_reset(struct cc_bitbang *bb) + { + struct timespec req, rem; - ++ + cc_bitbang_sync(bb); + req.tv_sec = (cc_reset_us) / 1000000; + req.tv_nsec = ((cc_reset_us) % 1000000) * 1000; + nanosleep(&req, &rem); + } - ++ + struct cc_bitbang * + cc_bitbang_open(void) + { + struct cc_bitbang *bb; + + bb = calloc(sizeof (struct cc_bitbang), 1); + if (!bb) { + perror("calloc"); + return NULL; + } + #ifdef CP_USB_ASYNC + bb->cp_async = cp_usb_async_open(); + if (!bb->cp_async) { + free (bb); + return NULL; + } + #else + bb->cp = cp_usb_open (); + if (!bb->cp) { + free (bb); + return NULL; + } + #endif + return bb; + } + + void + cc_bitbang_close(struct cc_bitbang *bb) + { + #ifdef CP_USB_ASYNC + cp_usb_async_close(bb->cp_async); + #else + cp_usb_close(bb->cp); + #endif + free (bb); + } + + void + cc_bitbang_debug_mode(struct cc_bitbang *bb) + { + /* force two rising clocks while holding RESET_N low */ + ccdbg_debug(CC_DEBUG_COMMAND, "#\n"); + ccdbg_debug(CC_DEBUG_COMMAND, "# Debug mode\n"); + ccdbg_debug(CC_DEBUG_COMMAND, "#\n"); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_DATA ); + cc_bitbang_wait_reset(bb); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_DATA ); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_DATA|CC_RESET_N); + cc_bitbang_wait_reset(bb); + } + + void + cc_bitbang_reset(struct cc_bitbang *bb) + { + ccdbg_debug(CC_DEBUG_COMMAND, "#\n"); + ccdbg_debug(CC_DEBUG_COMMAND, "# Reset\n"); + ccdbg_debug(CC_DEBUG_COMMAND, "#\n"); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); + cc_bitbang_wait_reset(bb); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); + cc_bitbang_wait_reset(bb); + } + + int + cc_bitbang_write(struct cc_bitbang *bb, uint8_t mask, uint8_t value) + { + #ifdef CP_USB_ASYNC + cp_usb_async_write(bb->cp_async, mask, value); + #else + cp_usb_write(bb->cp, mask, value); + #endif + return 0; + } + + void + cc_bitbang_read(struct cc_bitbang *bb, uint8_t *valuep) + { + #ifdef CP_USB_ASYNC + cp_usb_async_read(bb->cp_async, valuep); + #else + *valuep = cp_usb_read(bb->cp); + #endif + } + + void + cc_bitbang_sync(struct cc_bitbang *bb) + { + #ifdef CP_USB_ASYNC + cp_usb_async_sync(bb->cp_async); + #endif + } + + static char + is_bit(uint8_t get, uint8_t mask, char on, uint8_t bit) + { + if (mask&bit) { + if (get&bit) + return on; + else + return '.'; + } else + return '-'; + } + + void + cc_bitbang_print(char *format, uint8_t mask, uint8_t set) + { + ccdbg_debug (CC_DEBUG_BITBANG, format, + is_bit(set, mask, 'C', CC_CLOCK), + is_bit(set, mask, 'D', CC_DATA), + is_bit(set, mask, 'R', CC_RESET_N)); + } + + void + cc_bitbang_send(struct cc_bitbang *bb, uint8_t mask, uint8_t set) + { + cc_bitbang_write(bb, mask, set); + cc_bitbang_print("%c %c %c\n", mask, set); + cc_bitbang_half_clock(bb); + } + + void + cc_bitbang_send_bit(struct cc_bitbang *bb, uint8_t bit) + { + if (bit) bit = CC_DATA; + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|bit|CC_RESET_N); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, bit|CC_RESET_N); + } + + void + cc_bitbang_send_byte(struct cc_bitbang *bb, uint8_t byte) + { + int bit; + ccdbg_debug(CC_DEBUG_BITBANG, "#\n# Send Byte 0x%02x\n#\n", byte); + for (bit = 7; bit >= 0; bit--) { + cc_bitbang_send_bit(bb, (byte >> bit) & 1); + if (bit == 3) + ccdbg_debug(CC_DEBUG_BITBANG, "\n"); + } + cc_bitbang_sync(bb); + } + + void + cc_bitbang_send_bytes(struct cc_bitbang *bb, uint8_t *bytes, int nbytes) + { + while (nbytes--) + cc_bitbang_send_byte(bb, *bytes++); + } + + void + cc_bitbang_recv_bit(struct cc_bitbang *bb, int first, uint8_t *bit) + { + uint8_t mask = first ? CC_DATA : 0; + + cc_bitbang_send(bb, CC_CLOCK|mask|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); + cc_bitbang_read(bb, bit); + cc_bitbang_send(bb, CC_CLOCK| CC_RESET_N, CC_RESET_N); + } + + void + cc_bitbang_recv_byte(struct cc_bitbang *bb, int first, uint8_t *bytep) + { + uint8_t byte = 0; + uint8_t bits[8]; + int bit; + + ccdbg_debug(CC_DEBUG_BITBANG, "#\n# Recv byte\n#\n"); + for (bit = 0; bit < 8; bit++) { + cc_bitbang_recv_bit(bb, first, &bits[bit]); + first = 0; + } + cc_bitbang_sync(bb); + for (bit = 0; bit < 8; bit++) { + byte = byte << 1; + byte |= (bits[bit] & CC_DATA) ? 1 : 0; + cc_bitbang_print("#\t%c %c %c\n", CC_DATA, bits[bit]); + if (bit == 3) + ccdbg_debug(CC_DEBUG_BITBANG, "\n"); + } + ccdbg_debug(CC_DEBUG_BITBANG, "#\n# Recv 0x%02x\n#\n", byte); + *bytep = byte; + } + + void + cc_bitbang_recv_bytes(struct cc_bitbang *bb, uint8_t *bytes, int nbytes) + { + int i; + int first = 1; + for (i = 0; i < nbytes; i++) { + cc_bitbang_recv_byte(bb, first, &bytes[i]); + first = 0; + } + } - diff --cc lib/cc-usb.c index 00000000,2efe572e..dc764c24 mode 000000,100644..100644 --- a/lib/cc-usb.c +++ b/lib/cc-usb.c @@@ -1,0 -1,360 +1,359 @@@ + /* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include "ccdbg-debug.h" + #include "cc-usb.h" + + + #define CC_NUM_READ 16 + /* + * 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; - ++ + 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 && ++ 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); + } - diff --cc lib/ccdbg-command.c index 00000000,7d1ae067..a1002879 mode 000000,100644..100644 --- a/lib/ccdbg-command.c +++ b/lib/ccdbg-command.c @@@ -1,0 -1,177 +1,176 @@@ + /* + * Copyright © 2008 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + + #include "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; + } - diff --cc lib/ccdbg-flash.c index 00000000,8a586a21..3e672985 mode 000000,100644..100644 --- a/lib/ccdbg-flash.c +++ b/lib/ccdbg-flash.c @@@ -1,0 -1,356 +1,356 @@@ + /* + * Copyright © 2008 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + + #include "ccdbg.h" + + /* 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 00000000,86478da0..dfea9156 mode 000000,100644..100644 --- a/lib/ccdbg-hex.c +++ b/lib/ccdbg-hex.c @@@ -1,0 -1,330 +1,330 @@@ + /* + * Copyright © 2008 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + + #include "ccdbg.h" + #include + #include + + 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; - ++ + 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, ++ 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; + } diff --cc lib/ccdbg-memory.c index 00000000,878c5f97..554ac637 mode 000000,100644..100644 --- a/lib/ccdbg-memory.c +++ b/lib/ccdbg-memory.c @@@ -1,0 -1,179 +1,179 @@@ + /* + * Copyright © 2008 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + + #include "ccdbg.h" + + /* + * 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 00000000,4559b4e7..71bed220 mode 000000,100644..100644 --- a/lib/ccdbg-rom.c +++ b/lib/ccdbg-rom.c @@@ -1,0 -1,63 +1,63 @@@ + /* + * Copyright © 2008 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + + #include "ccdbg.h" + + 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 00000000,fe0ea3a0..4a2e3b9f mode 000000,100644..100644 --- a/lib/ccdbg.h +++ b/lib/ccdbg.h @@@ -1,0 -1,341 +1,341 @@@ + /* + * Copyright © 2008 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + + #ifndef _CCDBG_H_ + #define _CCDBG_H_ + + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #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_ */ diff --cc lib/cp-usb-async.c index 00000000,1fe09aad..6539394b mode 000000,100644..100644 --- a/lib/cp-usb-async.c +++ b/lib/cp-usb-async.c @@@ -1,0 -1,188 +1,188 @@@ + /* + * Copyright © 2008 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + + #include + #include + #include + #include + #include "cp-usb-async.h" + #include "ccdbg-debug.h" + + #define MAX_OUTSTANDING 256 + #define CP_TIMEOUT 1000 /* ms */ + + struct cp_usb_packet { + struct libusb_transfer *transfer; + enum { packet_read, packet_write } direction; + unsigned char data[9]; + uint8_t *valuep; + }; + + struct cp_usb_async { + libusb_context *ctx; + libusb_device_handle *handle; + struct cp_usb_packet packet[MAX_OUTSTANDING]; + int p, ack; + 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 00000000,d227b78c..530848db mode 000000,100644..100644 --- a/lib/cp-usb.c +++ b/lib/cp-usb.c @@@ -1,0 -1,157 +1,157 @@@ + /* + * Copyright © 2008 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + + /* + * 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 + #include + #include + + 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 00000000,77a98493..aba65cd0 mode 000000,100644..100644 --- a/s51/commands +++ b/s51/commands @@@ -1,0 -1,61 +1,60 @@@ + Listens on port 9756 for a command stream. + + Dump commands: + di - dump imem + ds - dump sprs + dx - dump xaddr + + Returns a string of hex pairs, each preceded by a space, + with 8 pairs per line + + Memory access commands: + set mem + dump + + is one of: + + xram - external ram or external stack + rom - code space + iram - internal ram or stack + sfr - special function register + + + dump + set bit + + bit addressable space + + Set PC: + + pc + + Sets PC to specified address + + pc + + Returns current PC + + Breakpoints + + break + clear + + Load a file + + file "" + + Execution control: + + run - run starting at - run - set temporary bp at ++ run - set temporary bp at + run - continue + next - step over calls(?) + step - step one instruction - ++ + reset - reset the simulator + res - synonym? - ++ + Error messages: + + start with "Error:" - diff --cc s51/s51-command.c index 00000000,02ecdddd..4f803060 mode 000000,100644..100644 --- a/s51/s51-command.c +++ b/s51/s51-command.c @@@ -1,0 -1,655 +1,654 @@@ + /* + * Copyright © 2008 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + + #include "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 00000000,46b97b0c..4dbd4c60 mode 000000,100644..100644 --- a/s51/s51-main.c +++ b/s51/s51-main.c @@@ -1,0 -1,240 +1,239 @@@ + /* + * Copyright © 2008 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + + #include "s51.h" + #include + #include + #include + #include + #include + #include + #include + + 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); - ++ + 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 + #include + + 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 1; + } + return 0; + } - diff --cc s51/s51-parse.c index 00000000,aba45485..170c979d mode 000000,100644..100644 --- a/s51/s51-parse.c +++ b/s51/s51-parse.c @@@ -1,0 -1,242 +1,241 @@@ + /* + * Copyright © 2008 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + + #include "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 ", + "Dump imem\n" }, + { "ds", "ds", command_ds, "ds ", + "Dump sprs\n" }, + { "dx", "dx", command_dx, "dx ", + "Dump xaddr\n" }, + { "set", "t", command_set, "se[t] mem
...", + "Set mem {xram|rom|iram|sfr}\n" + "set bit \n" }, + { "dump", "d", command_dump, "[d]ump ", + "Dump {xram|rom|iram|sfr} \n" }, + { "file", "file", command_file, "file ", + "Pretend to load executable from \n" }, + { "pc", "p", command_pc, "[p]c [addr]", + "Get or set pc value\n" }, + { "break", "b", command_break,"[b]reak ", + "Set break point\n" }, + { "clear", "c", command_clear,"[c]lear ", + "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 ", + "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 00000000,c283950e..f2f59a52 mode 000000,100644..100644 --- a/s51/s51.1 +++ b/s51/s51.1 @@@ -1,0 -1,211 +1,211 @@@ + .\" + .\" Copyright © 2009 Keith Packard + .\" + .\" This program is free software; you can redistribute it and/or modify + .\" it under the terms of the GNU General Public License as published by + .\" the Free Software Foundation; either version 2 of the License, or + .\" (at your option) any later version. + .\" + .\" This program is distributed in the hope that it will be useful, but + .\" WITHOUT ANY WARRANTY; without even the implied warranty of + .\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + .\" General Public License for more details. + .\" + .\" You should have received a copy of the GNU General Public License along + .\" with this program; if not, write to the Free Software Foundation, Inc., + .\" 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + .\" + .\" + .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 [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 [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" -.PP ++.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. ++\'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 diff --cc target/adc-serial/adc_serial.c index 00000000,eba58744..1f7b6880 mode 000000,100644..100644 --- a/target/adc-serial/adc_serial.c +++ b/target/adc-serial/adc_serial.c @@@ -1,0 -1,578 +1,578 @@@ + /* + * Copyright © 2008 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + + #include + + /* + * 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); + } + } diff --cc target/adc/adc.c index 00000000,bdc6c614..3a63a2c6 mode 000000,100644..100644 --- a/target/adc/adc.c +++ b/target/adc/adc.c @@@ -1,0 -1,470 +1,470 @@@ + /* + * Copyright © 2008 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + + #include + + /* + * 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]); + } + } diff --cc target/beep-timer/beep_timer.c index 00000000,53b95495..b3fa8754 mode 000000,100644..100644 --- a/target/beep-timer/beep_timer.c +++ b/target/beep-timer/beep_timer.c @@@ -1,0 -1,204 +1,204 @@@ + /* + * Copyright © 2008 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + + 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; + } + } diff --cc target/dma/dma.c index 00000000,c35c39f6..1762b658 mode 000000,100644..100644 --- a/target/dma/dma.c +++ b/target/dma/dma.c @@@ -1,0 -1,361 +1,361 @@@ + /* + * Copyright © 2008 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + + #include + + /* + * 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 00000000,7cc47120..9ea22cdc mode 000000,100644..100644 --- a/target/ee/ee.c +++ b/target/ee/ee.c @@@ -1,0 -1,407 +1,407 @@@ + /* + * Copyright © 2008 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + + #include + + /* + * 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 00000000,43aedc29..ae4d04c5 mode 000000,100644..100644 --- a/target/isr.c +++ b/target/isr.c @@@ -1,0 -1,90 +1,89 @@@ + /* + * Copyright © 2008 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + + 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) + { + } - diff --cc target/radio/init.c index 00000000,c9b3d186..ea7c984c mode 000000,100644..100644 --- a/target/radio/init.c +++ b/target/radio/init.c @@@ -1,0 -1,207 +1,207 @@@ + /* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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(); + } diff --cc target/radio/recv.c index 00000000,1f50d8a9..c50c3205 mode 000000,100644..100644 --- a/target/radio/recv.c +++ b/target/radio/recv.c @@@ -1,0 -1,68 +1,68 @@@ + /* + * Copyright © 2008 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + + #include "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); + } + } diff --cc target/serial/serial.c index 00000000,29390426..63f6c6de mode 000000,100644..100644 --- a/target/serial/serial.c +++ b/target/serial/serial.c @@@ -1,0 -1,270 +1,270 @@@ + /* + * Copyright © 2008 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + + #include + + /* + * 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()); + } - ++ + } diff --cc target/timer/cc1111.h index 00000000,7a531cc0..76c95c27 mode 000000,100644..100644 --- a/target/timer/cc1111.h +++ b/target/timer/cc1111.h @@@ -1,0 -1,294 +1,294 @@@ + /*------------------------------------------------------------------------- + Register Declarations for the ChipCon CC1111 Processor Range + + Copyright © 2008 Keith Packard - ++ + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. - ++ + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. - ++ + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + + Adapted from the Cygnal C8051F12x config file which is: - ++ + 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 ; /* */ ++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 diff --cc tests/debug_mode index 00000000,fe25bfef..2b5ec020 mode 000000,100644..100644 --- a/tests/debug_mode +++ b/tests/debug_mode @@@ -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 - diff --cc tests/get_status index 00000000,1d4ff03d..3e67a2e0 mode 000000,100644..100644 --- a/tests/get_status +++ b/tests/get_status @@@ -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 -