From 9025eb792861930e6af918d2727c4f5d97a69936 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 19 Dec 2008 21:11:45 -0800 Subject: Autotools. Signed-off-by: Keith Packard --- lib/Makefile.am | 14 +++ lib/cccp.c | 100 +++++++++++++++ lib/cccp.h | 41 ++++++ lib/ccdbg-command.c | 182 +++++++++++++++++++++++++++ lib/ccdbg-debug.c | 47 +++++++ lib/ccdbg-flash.c | 337 +++++++++++++++++++++++++++++++++++++++++++++++++ lib/ccdbg-hex.c | 330 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/ccdbg-io.c | 211 +++++++++++++++++++++++++++++++ lib/ccdbg-manual.c | 70 +++++++++++ lib/ccdbg-memory.c | 104 ++++++++++++++++ lib/ccdbg.h | 351 ++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/cp-usb.c | 140 +++++++++++++++++++++ 12 files changed, 1927 insertions(+) create mode 100644 lib/Makefile.am create mode 100644 lib/cccp.c create mode 100644 lib/cccp.h create mode 100644 lib/ccdbg-command.c create mode 100644 lib/ccdbg-debug.c create mode 100644 lib/ccdbg-flash.c create mode 100644 lib/ccdbg-hex.c create mode 100644 lib/ccdbg-io.c create mode 100644 lib/ccdbg-manual.c create mode 100644 lib/ccdbg-memory.c create mode 100644 lib/ccdbg.h create mode 100644 lib/cp-usb.c (limited to 'lib') diff --git a/lib/Makefile.am b/lib/Makefile.am new file mode 100644 index 00000000..a5e5932b --- /dev/null +++ b/lib/Makefile.am @@ -0,0 +1,14 @@ +noinst_LIBRARIES = libcc.a + +AM_CFLAGS=$(WARN_CFLAGS) + +libcc_a_SOURCES = \ + ccdbg-command.c \ + ccdbg-debug.c \ + ccdbg-flash.c \ + ccdbg.h \ + ccdbg-hex.c \ + ccdbg-io.c \ + ccdbg-manual.c \ + ccdbg-memory.c \ + cp-usb.c diff --git a/lib/cccp.c b/lib/cccp.c new file mode 100644 index 00000000..99a0d81f --- /dev/null +++ b/lib/cccp.c @@ -0,0 +1,100 @@ +/* + * 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" + +static void +say(char *name, uint8_t bits) +{ + printf("%s: ", name); + if (bits & CC_RESET_N) + printf ("R "); + else + printf (". "); + if (bits & CC_CLOCK) + printf ("C "); + else + printf (". "); + if (bits & CC_DATA) + printf ("D\n"); + else + printf (".\n"); +} + +static void +_cccp_write(struct ccdbg *dbg, uint8_t mask, uint8_t value) +{ + uint16_t set; + int ret; + + set = (mask) | (value << 8); + dbg->debug_data = (dbg->debug_data & ~mask) | (value & mask); + ret = ioctl(dbg->fd, CP2101_IOCTL_GPIOSET, &set); + if (ret < 0) + perror("CP2101_IOCTL_GPIOSET"); +} + +void +cccp_write(struct ccdbg *dbg, uint8_t mask, uint8_t value) +{ + _cccp_write(dbg, mask, value); +// say("w", dbg->debug_data); +} + +uint8_t +cccp_read_all(struct ccdbg *dbg) +{ + int ret; + uint8_t get; + ret = ioctl(dbg->fd, CP2101_IOCTL_GPIOGET, &get); + if (ret < 0) { + perror("CP2101_IOCTL_GPIOGET"); + get = 0; + } + return get; +} + +uint8_t +cccp_read(struct ccdbg *dbg, uint8_t mask) +{ + uint8_t pull_up; + uint8_t get; + + /* tri-state the bits of interest */ + pull_up = (~dbg->debug_data) & mask; + if (pull_up) + _cccp_write(dbg, pull_up, pull_up); + get = cccp_read_all(dbg); + say("\t\tr", get); + return get & mask; +} + +void +cccp_init(struct ccdbg *dbg) +{ + /* set all of the GPIOs to a known state */ + cccp_write(dbg, 0xf, 0xf); +} + +void +cccp_fini(struct ccdbg *dbg) +{ + /* set all of the GPIOs to a known state */ + cccp_write(dbg, 0xf, 0xf); + dbg->clock = 1; +} diff --git a/lib/cccp.h b/lib/cccp.h new file mode 100644 index 00000000..eecdbb49 --- /dev/null +++ b/lib/cccp.h @@ -0,0 +1,41 @@ +/* + * 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. + */ + +/* + * Interface for using a CP2103 to talk to a CC1111 + */ + +#ifndef _CCCP_H_ +#define _CCCP_H_ + +void +cccp_write(struct ccdbg *dbg, uint8_t mask, uint8_t value); + +uint8_t +cccp_read_all(struct ccdbg *dbg); + +uint8_t +cccp_read(struct ccdbg *dbg, uint8_t mask); + +void +cccp_init(struct ccdbg *dbg); + +void +cccp_fini(struct ccdbg *dbg); + +#endif /* _CCCP_H_ */ diff --git a/lib/ccdbg-command.c b/lib/ccdbg-command.c new file mode 100644 index 00000000..38c006cb --- /dev/null +++ b/lib/ccdbg-command.c @@ -0,0 +1,182 @@ +/* + * 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" + +void +ccdbg_debug_mode(struct ccdbg *dbg) +{ + /* force two rising clocks while holding RESET_N low */ + ccdbg_debug(CC_DEBUG_COMMAND, "#\n"); + ccdbg_debug(CC_DEBUG_COMMAND, "# Debug mode\n"); + ccdbg_debug(CC_DEBUG_COMMAND, "#\n"); + ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); + ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_DATA ); + ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); + ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_DATA ); + ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); + ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_DATA|CC_RESET_N); +} + +void +ccdbg_reset(struct ccdbg *dbg) +{ + ccdbg_debug(CC_DEBUG_COMMAND, "#\n"); + ccdbg_debug(CC_DEBUG_COMMAND, "# Reset\n"); + ccdbg_debug(CC_DEBUG_COMMAND, "#\n"); + ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); + ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); + ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); + ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); + ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); + ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); +} + +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) +{ + return ccdbg_cmd_write_read16(dbg, CC_GET_PC, NULL, 0); +} + +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); +} + +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]); + status = ccdbg_debug_instr(dbg, inst+1, len); + for (; i < 3; i++) + ccdbg_debug(CC_DEBUG_INSTRUCTIONS, " "); + ccdbg_debug(CC_DEBUG_INSTRUCTIONS, " -> %02x\n", status); + inst += len + 1; + } + 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); + printf ("pc starts at 0x%04x\n", pc); + status = ccdbg_resume(dbg); + printf ("resume status: 0x%02x\n", status); + return 0; +} + diff --git a/lib/ccdbg-debug.c b/lib/ccdbg-debug.c new file mode 100644 index 00000000..2e67bc8d --- /dev/null +++ b/lib/ccdbg-debug.c @@ -0,0 +1,47 @@ +/* + * 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 + +int +ccdbg_level = 0; + +void +ccdbg_add_debug(int level) +{ + ccdbg_level |= level; +} + +void +ccdbg_clear_debug(int level) +{ + ccdbg_level &= ~level; +} + +void +ccdbg_debug(int level, char *format, ...) +{ + va_list ap; + + if (ccdbg_level & level) { + va_start(ap, format); + vprintf(format, ap); + va_end(ap); + } +} diff --git a/lib/ccdbg-flash.c b/lib/ccdbg-flash.c new file mode 100644 index 00000000..aa2c5187 --- /dev/null +++ b/lib/ccdbg-flash.c @@ -0,0 +1,337 @@ +/* + * 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); + printf("erase status 0x%02x\n", status); + do { + status = ccdbg_execute(dbg, flash_read_control); + printf("fctl 0x%02x\n", status); + } while (status & FCTL_BUSY); + ccdbg_read_memory(dbg, addr, new, 0x10); + for (i = 0; i < 0x10; i++) + printf("0x%02x -> 0x%02x\n", old[i], new[i]); + status = ccdbg_execute(dbg, flash_control_clear); + printf("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]; + printf("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); + printf("waiting for write 0x%02x\n", status); + if ((status & CC_STATUS_CPU_HALTED) != 0) + break; + sleep (1); + } + status = ccdbg_execute(dbg, flash_control_clear); + printf("clear fctl 0x%02x\n", status); + ccdbg_read_memory(dbg, addr, check, 2); + for (i = 0; i < 2; i++) + printf("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); + printf ("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_word_addr; + uint16_t flash_words; + uint16_t ram_addr; + uint16_t pc; + uint8_t status; + uint16_t remain, this_time, start; + uint8_t verify[0x400]; + + 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; + printf("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); + + printf("Upload %d bytes at 0x%04x\n", this_time, ram_addr); + ccdbg_write_memory(dbg, ram_addr, image->data + start, this_time); + + printf("Verify %d bytes\n", image->length); + ccdbg_read_memory(dbg, ram_addr, verify, this_time); + if (memcmp (image->data + start, verify, this_time) != 0) { + fprintf(stderr, "image verify failed\n"); + return 1; + } + + flash_word_addr = (image->address + start) >> 1; + flash_len = this_time + (this_time & 1); + flash_words = flash_len >> 1; + + 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 >> 8); + ccdbg_write_uint8(dbg, flash_prog + FLASH_WORDS_LOW, flash_words & 0xff); + + ccdbg_set_pc(dbg, flash_prog); + pc = ccdbg_get_pc(dbg); + printf("Starting flash program at 0x%04x\n", pc); + status = ccdbg_resume(dbg); + printf("resume status is 0x%02x\n", status); + do { + status = ccdbg_read_status(dbg); + printf("chip status is 0x%02x\n", status); + sleep(1); + } while ((status & CC_STATUS_CPU_HALTED) == 0); + + remain -= this_time; + start += this_time; + } +#if 1 + printf("Downloading flash to check\n"); + struct hex_image *test_image; + test_image = ccdbg_read_hex_image(dbg, image->address, image->length); + if (!ccdbg_hex_image_equal(image, test_image)) { + int i; + fprintf(stderr, "Image not loaded\n"); + for (i = 0;i < 0x10; i++) + printf ("0x%02x : 0x%02x\n", image->data[i], test_image->data[i]); + return 1; + } + return 0; +#endif + return 0; +} diff --git a/lib/ccdbg-hex.c b/lib/ccdbg-hex.c new file mode 100644 index 00000000..86478da0 --- /dev/null +++ b/lib/ccdbg-hex.c @@ -0,0 +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, + 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 --git a/lib/ccdbg-io.c b/lib/ccdbg-io.c new file mode 100644 index 00000000..29476785 --- /dev/null +++ b/lib/ccdbg-io.c @@ -0,0 +1,211 @@ +/* + * 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 + +void +ccdbg_half_clock(struct ccdbg *dbg) +{ + struct timespec req, rem; + req.tv_sec = (CC_CLOCK_US / 2) / 1000000; + req.tv_nsec = ((CC_CLOCK_US / 2) % 1000000) * 1000; + nanosleep(&req, &rem); +} + +struct ccdbg * +ccdbg_open(void) +{ + struct ccdbg *dbg; + + dbg = calloc(sizeof (struct ccdbg), 1); + if (!dbg) { + perror("calloc"); + return NULL; + } + dbg->clock = 1; +#ifdef USE_KERNEL + dbg->fd = open("/dev/ttyUSB0", 2); + if (dbg->fd < 0) { + perror(file); + free(dbg); + return NULL; + } + cccp_init(dbg); + cccp_write(dbg, CC_CLOCK, CC_CLOCK); +#else + cp_usb_init(dbg); +#endif + dbg->clock = 1; + return dbg; +} + +void +ccdbg_close(struct ccdbg *dbg) +{ +#if USE_KERNEL + cccp_fini(dbg); + close (dbg->fd); +#else + cp_usb_fini(dbg); +#endif + free (dbg); +} + +int +ccdbg_write(struct ccdbg *dbg, uint8_t mask, uint8_t value) +{ +#if USE_KERNEL + return cccp_write(dbg, mask, value); +#else + cp_usb_write(dbg, mask, value); + return 0; +#endif +} + +uint8_t +ccdbg_read(struct ccdbg *dbg) +{ +#if USE_KERNEL + return cccp_read_all(dbg); +#else + return cp_usb_read(dbg); +#endif +} + +static char +is_bit(uint8_t get, uint8_t mask, char on, uint8_t bit) +{ + if (mask&bit) { + if (get&bit) + return on; + else + return '.'; + } else + return '-'; +} +void +ccdbg_print(char *format, uint8_t mask, uint8_t set) +{ + ccdbg_debug (CC_DEBUG_BITBANG, format, + is_bit(set, mask, 'C', CC_CLOCK), + is_bit(set, mask, 'D', CC_DATA), + is_bit(set, mask, 'R', CC_RESET_N)); +} + +void +ccdbg_send(struct ccdbg *dbg, uint8_t mask, uint8_t set) +{ + ccdbg_write(dbg, mask, set); + ccdbg_print("%c %c %c\n", mask, set); + ccdbg_half_clock(dbg); +} + +void +ccdbg_send_bit(struct ccdbg *dbg, uint8_t bit) +{ + if (bit) bit = CC_DATA; + ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|bit|CC_RESET_N); + ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, bit|CC_RESET_N); +} + +void +ccdbg_send_byte(struct ccdbg *dbg, uint8_t byte) +{ + int bit; + ccdbg_debug(CC_DEBUG_BITBANG, "#\n# Send Byte 0x%02x\n#\n", byte); + for (bit = 7; bit >= 0; bit--) { + ccdbg_send_bit(dbg, (byte >> bit) & 1); + if (bit == 3) + ccdbg_debug(CC_DEBUG_BITBANG, "\n"); + } +} + +void +ccdbg_send_bytes(struct ccdbg *dbg, uint8_t *bytes, int nbytes) +{ + while (nbytes--) + ccdbg_send_byte(dbg, *bytes++); +} + +uint8_t +ccdbg_recv_bit(struct ccdbg *dbg, int first) +{ + uint8_t mask = first ? CC_DATA : 0; + uint8_t read; + + ccdbg_send(dbg, CC_CLOCK|mask|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); + read = ccdbg_read(dbg); + ccdbg_send(dbg, CC_CLOCK| CC_RESET_N, CC_RESET_N); + return (read & CC_DATA) ? 1 : 0; +} + +uint8_t +ccdbg_recv_byte(struct ccdbg *dbg, int first) +{ + uint8_t byte = 0; + int bit; + + ccdbg_debug(CC_DEBUG_BITBANG, "#\n# Recv byte\n#\n"); + for (bit = 0; bit < 8; bit++) { + byte = byte << 1; + byte |= ccdbg_recv_bit(dbg, first); + if (bit == 3) + ccdbg_debug(CC_DEBUG_BITBANG, "\n"); + first = 0; + } + ccdbg_debug(CC_DEBUG_BITBANG, "#\n# Recv 0x%02x\n#\n", byte); + return byte; +} + +void +ccdbg_recv_bytes(struct ccdbg *dbg, uint8_t *bytes, int nbytes) +{ + int first = 1; + while (nbytes--) { + *bytes++ = ccdbg_recv_byte(dbg, first); + first = 0; + } +} + +void +ccdbg_cmd_write(struct ccdbg *dbg, uint8_t cmd, uint8_t *data, int len) +{ + int i; + ccdbg_send_byte(dbg, cmd); + for (i = 0; i < len; i++) + ccdbg_send_byte(dbg, data[i]); +} + +uint8_t +ccdbg_cmd_write_read8(struct ccdbg *dbg, uint8_t cmd, uint8_t *data, int len) +{ + uint8_t byte[1]; + ccdbg_cmd_write(dbg, cmd, data, len); + ccdbg_recv_bytes(dbg, byte, 1); + return byte[0]; +} + +uint16_t +ccdbg_cmd_write_read16(struct ccdbg *dbg, uint8_t cmd, uint8_t *data, int len) +{ + uint8_t byte[2]; + ccdbg_cmd_write(dbg, cmd, data, len); + ccdbg_recv_bytes(dbg, byte, 2); + return (byte[0] << 8) | byte[1]; +} diff --git a/lib/ccdbg-manual.c b/lib/ccdbg-manual.c new file mode 100644 index 00000000..b83dc450 --- /dev/null +++ b/lib/ccdbg-manual.c @@ -0,0 +1,70 @@ +/* + * Copyright © 2008 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ccdbg.h" + +/* + * Manual bit-banging to debug the low level protocol + */ + +static void +get_bit(char *line, int i, char on, uint8_t bit, uint8_t *bits, uint8_t *masks) +{ + if (line[i] == on) { + *bits |= bit; + *masks |= bit; + return; + } + if (line[i] == '.') { + *masks |= bit; + return; + } + if (line[i] == '-') { + return; + } + fprintf(stderr, "bad line %s\n", line); + exit (1); +} + +void +ccdbg_manual(struct ccdbg *dbg, FILE *input) +{ + char line[80]; + uint8_t set, mask; + + while (fgets(line, sizeof line, input)) { + if (line[0] == '#' || line[0] == '\n') { + printf ("%s", line); + continue; + } + set = 0; + mask = 0; + get_bit(line, 0, 'C', CC_CLOCK, &set, &mask); + get_bit(line, 2, 'D', CC_DATA, &set, &mask); + get_bit(line, 4, 'R', CC_RESET_N, &set, &mask); + if (mask != (CC_CLOCK|CC_DATA|CC_RESET_N)) { + uint8_t read; + read = ccdbg_read(dbg); + ccdbg_print("\t%c %c %c", CC_CLOCK|CC_DATA|CC_RESET_N, read); + if ((set & CC_CLOCK) == 0) + printf ("\t%d", (read&CC_DATA) ? 1 : 0); + printf ("\n"); + } + ccdbg_send(dbg, mask, set); + } +} diff --git a/lib/ccdbg-memory.c b/lib/ccdbg-memory.c new file mode 100644 index 00000000..105295db --- /dev/null +++ b/lib/ccdbg-memory.c @@ -0,0 +1,104 @@ +/* + * 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; + 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) { printf ("."); fflush(stdout); nl = 1; } + if ((i & 0xff) == 0xff) { printf ("\n"); nl = 0; } + } + if (nl) printf ("\n"); + return 0; +} + +uint8_t +ccdbg_read_memory(struct ccdbg *dbg, uint16_t addr, uint8_t *bytes, int nbytes) +{ + int i, nl = 0; + 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) { printf ("."); fflush(stdout); nl = 1; } + if ((i & 0xff) == 0xff) { printf ("\n"); nl = 0; } + } + if (nl) printf ("\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; +} diff --git a/lib/ccdbg.h b/lib/ccdbg.h new file mode 100644 index 00000000..b74d13ca --- /dev/null +++ b/lib/ccdbg.h @@ -0,0 +1,351 @@ +/* + * 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 +#undef USE_KERNEL +#ifdef USE_KERNEL +#include +#define CC_CLOCK CP2101_GPIO_MASK(0) +#define CC_DATA CP2101_GPIO_MASK(1) +#define CC_RESET_N CP2101_GPIO_MASK(2) +#else +#define CC_CLOCK 0x1 +#define CC_DATA 0x2 +#define CC_RESET_N 0x4 +#include +#endif + + +/* painfully slow for now */ +#define CC_CLOCK_US (50) + +#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_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 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 CLKCON 0xC6 +#define CLKCON_OSC32K 0x80 +#define CLKCON_OSC 0x40 +#define CLKCON_TICKSPD 0x38 +#define CLKCON_CLKSPD 0x07 + +#define P0 0x80 +#define P1 0x90 +#define P2 0xA0 +#define P0DIR 0xFD +#define P1DIR 0xFE +#define P2DIR 0xFF + +#define SLEEP 0xBE + +#define JB 0x20 + +#define ACC(bit) (0xE0 | (bit)) + +struct ccdbg { + usb_dev_handle *usb_dev; + uint8_t gpio; +#ifdef USE_KERNEL + int fd; +#endif + uint8_t debug_data; + int clock; +}; + +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 HEX_RECORD_NORMAL 0x00 +#define HEX_RECORD_EOF 0x01 +#define HEX_RECORD_EXTENDED_ADDRESS 0x02 + +#include "cccp.h" + +#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 + +#define CC_DEBUG_BITBANG 0x00000001 +#define CC_DEBUG_COMMAND 0x00000002 +#define CC_DEBUG_INSTRUCTIONS 0x00000004 + +/* 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); + +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-debug.c */ +void +ccdbg_debug(int level, char *format, ...); + +void +ccdbg_add_debug(int level); + +void +ccdbg_clear_debug(int level); + +/* 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 */ +void +ccdbg_half_clock(struct ccdbg *dbg); + +int +ccdbg_write(struct ccdbg *dbg, uint8_t mask, uint8_t value); + +uint8_t +ccdbg_read(struct ccdbg *dbg); + +struct ccdbg * +ccdbg_open(void); + +void +ccdbg_close(struct ccdbg *dbg); + +void +ccdbg_clock_1_0(struct ccdbg *dbg); + +void +ccdbg_clock_0_1(struct ccdbg *dbg); + +void +ccdbg_write_bit(struct ccdbg *dbg, uint8_t bit); + +void +ccdbg_write_byte(struct ccdbg *dbg, uint8_t byte); + +uint8_t +ccdbg_read_bit(struct ccdbg *dbg); + +uint8_t +ccdbg_read_byte(struct ccdbg *dbg); + +void +ccdbg_cmd_write(struct ccdbg *dbg, uint8_t cmd, uint8_t *data, int len); + +uint8_t +ccdbg_cmd_write_read8(struct ccdbg *dbg, uint8_t cmd, uint8_t *data, int len); + +uint16_t +ccdbg_cmd_write_read16(struct ccdbg *dbg, uint8_t cmd, uint8_t *data, int len); + +void +ccdbg_send(struct ccdbg *dbg, uint8_t mask, uint8_t set); + +void +ccdbg_send_bit(struct ccdbg *dbg, uint8_t bit); + +void +ccdbg_send_byte(struct ccdbg *dbg, uint8_t byte); + +void +ccdbg_send_bytes(struct ccdbg *dbg, uint8_t *bytes, int nbytes); + +uint8_t +ccdbg_recv_bit(struct ccdbg *dbg, int first); + +uint8_t +ccdbg_recv_byte(struct ccdbg *dbg, int first); + +void +ccdbg_recv_bytes(struct ccdbg *dbg, uint8_t *bytes, int nbytes); + +void +ccdbg_print(char *format, uint8_t mask, uint8_t set); + +/* 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); + +/* cp-usb.c */ +void +cp_usb_init(struct ccdbg *dbg); + +void +cp_usb_fini(struct ccdbg *dbg); + +void +cp_usb_write(struct ccdbg *dbg, uint8_t mask, uint8_t value); + +uint8_t +cp_usb_read(struct ccdbg *dbg); + +#endif /* _CCDBG_H_ */ diff --git a/lib/cp-usb.c b/lib/cp-usb.c new file mode 100644 index 00000000..61b684a2 --- /dev/null +++ b/lib/cp-usb.c @@ -0,0 +1,140 @@ +/* + * 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 + +#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 ccdbg *dbg, uint8_t *gpio_get) +{ + return usb_control_msg(dbg->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 ccdbg *dbg, uint8_t mask, uint8_t value) +{ + uint16_t gpio_set = ((uint16_t) value << 8) | mask; + + return usb_control_msg(dbg->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 ccdbg *dbg, uint16_t enable) +{ + return usb_control_msg(dbg->usb_dev, + CP2101_UART, + REQTYPE_HOST_TO_DEVICE, + enable, + 0, + NULL, + 0, + 300); +} + +void +cp_usb_init(struct ccdbg *dbg) +{ + 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"); + exit(1); + } + interface = 0; + dev_handle = usb_open(dev); + usb_detach_kernel_driver_np(dev_handle, interface); + usb_claim_interface(dev_handle, interface); + dbg->usb_dev = dev_handle; + ret = cp_usb_uart_enable_disable(dbg, UART_DISABLE); + dbg->gpio = 0xf; + ret = cp_usb_gpio_set(dbg, 0xf, dbg->gpio); + ret = cp_usb_gpio_get(dbg, &gpio); +} + +void +cp_usb_fini(struct ccdbg *dbg) +{ + cp_usb_uart_enable_disable(dbg, UART_DISABLE); + usb_close(dbg->usb_dev); +} + +void +cp_usb_write(struct ccdbg *dbg, uint8_t mask, uint8_t value) +{ + uint8_t new_gpio; + int ret; + + new_gpio = (dbg->gpio & ~mask) | (value & mask); + if (new_gpio != dbg->gpio) { + ret = cp_usb_gpio_set(dbg, new_gpio ^ dbg->gpio, new_gpio); + if (ret < 0) + perror("gpio_set"); + dbg->gpio = new_gpio; + } +} + +uint8_t +cp_usb_read(struct ccdbg *dbg) +{ + int ret; + uint8_t gpio; + + ret = cp_usb_gpio_get(dbg, &gpio); + if (ret < 0) + perror("gpio_set"); + return gpio; +} -- cgit v1.2.3 From f7d49868aeae80d515b12a7e339628f1296754a6 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 20 Dec 2008 23:30:06 -0800 Subject: Cleanup work; separating out the cp interface to be more abstract. Signed-off-by: Keith Packard --- lib/cccp.c | 12 +++++ lib/ccdbg-command.c | 4 +- lib/ccdbg-flash.c | 34 +++++++------- lib/ccdbg-io.c | 34 +++----------- lib/ccdbg.h | 131 +++++++++++++++++++++++----------------------------- lib/cp-usb.c | 70 +++++++++++++++++----------- 6 files changed, 137 insertions(+), 148 deletions(-) (limited to 'lib') diff --git a/lib/cccp.c b/lib/cccp.c index 99a0d81f..34e866e8 100644 --- a/lib/cccp.c +++ b/lib/cccp.c @@ -98,3 +98,15 @@ cccp_fini(struct ccdbg *dbg) cccp_write(dbg, 0xf, 0xf); dbg->clock = 1; } + +cccp_open() +{ + dbg->fd = open("/dev/ttyUSB0", 2); + if (dbg->fd < 0) { + perror(file); + free(dbg); + return NULL; + } + cccp_init(dbg); + cccp_write(dbg, CC_CLOCK, CC_CLOCK); +} diff --git a/lib/ccdbg-command.c b/lib/ccdbg-command.c index 38c006cb..30f5094d 100644 --- a/lib/ccdbg-command.c +++ b/lib/ccdbg-command.c @@ -174,9 +174,9 @@ ccdbg_execute_hex_image(struct ccdbg *dbg, struct hex_image *image) ccdbg_write_hex_image(dbg, image, 0); ccdbg_set_pc(dbg, image->address); pc = ccdbg_get_pc(dbg); - printf ("pc starts at 0x%04x\n", pc); + ccdbg_debug(CC_DEBUG_EXECUTE, "pc starts at 0x%04x\n", pc); status = ccdbg_resume(dbg); - printf ("resume status: 0x%02x\n", status); + ccdbg_debug(CC_DEBUG_EXECUTE, "resume status: 0x%02x\n", status); return 0; } diff --git a/lib/ccdbg-flash.c b/lib/ccdbg-flash.c index aa2c5187..f950dd1b 100644 --- a/lib/ccdbg-flash.c +++ b/lib/ccdbg-flash.c @@ -112,16 +112,16 @@ ccdbg_flash_erase_page(struct ccdbg *dbg, uint16_t addr) 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); - printf("erase status 0x%02x\n", status); + ccdbg_debug(CC_DEBUG_FLASH, "erase status 0x%02x\n", status); do { status = ccdbg_execute(dbg, flash_read_control); - printf("fctl 0x%02x\n", status); + 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++) - printf("0x%02x -> 0x%02x\n", old[i], new[i]); + ccdbg_debug(CC_DEBUG_FLASH, "0x%02x -> 0x%02x\n", old[i], new[i]); status = ccdbg_execute(dbg, flash_control_clear); - printf("clear fctl 0x%02x\n", status); + ccdbg_debug(CC_DEBUG_FLASH, "clear fctl 0x%02x\n", status); return 0; } #endif @@ -190,22 +190,22 @@ ccdbg_flash_write_word(struct ccdbg *dbg, uint16_t addr, uint8_t data[2]) flash_write[WRITE_PAGE_LOW] = page_addr & 0xff; flash_write[WRITE_BYTE_0] = data[0]; flash_write[WRITE_BYTE_1] = data[1]; - printf("upload flash write\n"); + 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); - printf("waiting for write 0x%02x\n", status); + 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); - printf("clear fctl 0x%02x\n", status); + ccdbg_debug(CC_DEBUG_FLASH, "clear fctl 0x%02x\n", status); ccdbg_read_memory(dbg, addr, check, 2); for (i = 0; i < 2; i++) - printf("0x%02x : 0x%02x\n", data[i], check[i]); + ccdbg_debug(CC_DEBUG_FLASH, "0x%02x : 0x%02x\n", data[i], check[i]); return 0; } #endif @@ -231,7 +231,7 @@ ccdbg_flash_lock(struct ccdbg *dbg, uint8_t lock) ccdbg_read_memory(dbg, 0, old, 1); ccdbg_flash_write_word(dbg, 0, bytes); ccdbg_read_memory(dbg, 0, new, 1); - printf ("flash lock 0x%02x -> 0x%02x\n", old[0], new[0]); + 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; } @@ -270,7 +270,7 @@ ccdbg_flash_hex_image(struct ccdbg *dbg, struct hex_image *image) fwt = 0x20; flash_page[FLASH_TIMING] = fwt; - printf("Upload %d flash program bytes to 0x%04x\n", + 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)); @@ -283,10 +283,10 @@ ccdbg_flash_hex_image(struct ccdbg *dbg, struct hex_image *image) offset = ram_addr - (image->address + start); - printf("Upload %d bytes at 0x%04x\n", this_time, ram_addr); + 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); - printf("Verify %d bytes\n", image->length); + ccdbg_debug(CC_DEBUG_FLASH, "Verify %d bytes\n", image->length); ccdbg_read_memory(dbg, ram_addr, verify, this_time); if (memcmp (image->data + start, verify, this_time) != 0) { fprintf(stderr, "image verify failed\n"); @@ -308,12 +308,12 @@ ccdbg_flash_hex_image(struct ccdbg *dbg, struct hex_image *image) ccdbg_set_pc(dbg, flash_prog); pc = ccdbg_get_pc(dbg); - printf("Starting flash program at 0x%04x\n", pc); + ccdbg_debug(CC_DEBUG_FLASH, "Starting flash program at 0x%04x\n", pc); status = ccdbg_resume(dbg); - printf("resume status is 0x%02x\n", status); + ccdbg_debug(CC_DEBUG_FLASH, "resume status is 0x%02x\n", status); do { status = ccdbg_read_status(dbg); - printf("chip status is 0x%02x\n", status); + ccdbg_debug(CC_DEBUG_FLASH, "chip status is 0x%02x\n", status); sleep(1); } while ((status & CC_STATUS_CPU_HALTED) == 0); @@ -321,14 +321,14 @@ ccdbg_flash_hex_image(struct ccdbg *dbg, struct hex_image *image) start += this_time; } #if 1 - printf("Downloading flash to check\n"); + ccdbg_debug(CC_DEBUG_FLASH, "Downloading flash to check\n"); struct hex_image *test_image; test_image = ccdbg_read_hex_image(dbg, image->address, image->length); if (!ccdbg_hex_image_equal(image, test_image)) { int i; fprintf(stderr, "Image not loaded\n"); for (i = 0;i < 0x10; i++) - printf ("0x%02x : 0x%02x\n", image->data[i], test_image->data[i]); + ccdbg_debug(CC_DEBUG_FLASH, "0x%02x : 0x%02x\n", image->data[i], test_image->data[i]); return 1; } return 0; diff --git a/lib/ccdbg-io.c b/lib/ccdbg-io.c index 29476785..6999dbec 100644 --- a/lib/ccdbg-io.c +++ b/lib/ccdbg-io.c @@ -38,54 +38,32 @@ ccdbg_open(void) perror("calloc"); return NULL; } - dbg->clock = 1; -#ifdef USE_KERNEL - dbg->fd = open("/dev/ttyUSB0", 2); - if (dbg->fd < 0) { - perror(file); - free(dbg); + dbg->cp = cp_usb_open (); + if (!dbg->cp) { + free (dbg); return NULL; } - cccp_init(dbg); - cccp_write(dbg, CC_CLOCK, CC_CLOCK); -#else - cp_usb_init(dbg); -#endif - dbg->clock = 1; return dbg; } void ccdbg_close(struct ccdbg *dbg) { -#if USE_KERNEL - cccp_fini(dbg); - close (dbg->fd); -#else - cp_usb_fini(dbg); -#endif + cp_usb_close(dbg->cp); free (dbg); } int ccdbg_write(struct ccdbg *dbg, uint8_t mask, uint8_t value) { -#if USE_KERNEL - return cccp_write(dbg, mask, value); -#else - cp_usb_write(dbg, mask, value); + cp_usb_write(dbg->cp, mask, value); return 0; -#endif } uint8_t ccdbg_read(struct ccdbg *dbg) { -#if USE_KERNEL - return cccp_read_all(dbg); -#else - return cp_usb_read(dbg); -#endif + return cp_usb_read(dbg->cp); } static char diff --git a/lib/ccdbg.h b/lib/ccdbg.h index b74d13ca..4d4a648d 100644 --- a/lib/ccdbg.h +++ b/lib/ccdbg.h @@ -30,23 +30,14 @@ #include #include #include -#undef USE_KERNEL -#ifdef USE_KERNEL -#include -#define CC_CLOCK CP2101_GPIO_MASK(0) -#define CC_DATA CP2101_GPIO_MASK(1) -#define CC_RESET_N CP2101_GPIO_MASK(2) -#else +#include "cp-usb.h" #define CC_CLOCK 0x1 #define CC_DATA 0x2 #define CC_RESET_N 0x4 -#include -#endif - - -/* painfully slow for now */ -#define CC_CLOCK_US (50) +#define CC_CLOCK_US (40) +/* 8051 instructions + */ #define MOV_direct_data 0x75 #define LJMP 0x02 #define MOV_Rn_data(n) (0x78 | (n)) @@ -54,56 +45,57 @@ #define MOV_A_direct 0xe5 #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 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 CLKCON 0xC6 -#define CLKCON_OSC32K 0x80 -#define CLKCON_OSC 0x40 -#define CLKCON_TICKSPD 0x38 -#define CLKCON_CLKSPD 0x07 - -#define P0 0x80 -#define P1 0x90 -#define P2 0xA0 -#define P0DIR 0xFD -#define P1DIR 0xFE -#define P2DIR 0xFF - -#define SLEEP 0xBE - -#define JB 0x20 - -#define ACC(bit) (0xE0 | (bit)) +#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 + */ + +/* 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)) struct ccdbg { - usb_dev_handle *usb_dev; - uint8_t gpio; -#ifdef USE_KERNEL - int fd; -#endif - uint8_t debug_data; - int clock; + struct cp_usb *cp; }; +/* Intel hex file format data + */ struct hex_record { uint8_t length; uint16_t address; @@ -127,8 +119,8 @@ struct hex_image { #define HEX_RECORD_EOF 0x01 #define HEX_RECORD_EXTENDED_ADDRESS 0x02 -#include "cccp.h" - +/* CC1111 debug port commands + */ #define CC_CHIP_ERASE 0x14 #define CC_WR_CONFIG 0x1d @@ -161,9 +153,13 @@ struct hex_image { #define CC_STEP_REPLACE(n) (0x64|(n)) #define CC_GET_CHIP_ID 0x68 +/* Debug levels + */ #define CC_DEBUG_BITBANG 0x00000001 #define CC_DEBUG_COMMAND 0x00000002 #define CC_DEBUG_INSTRUCTIONS 0x00000004 +#define CC_DEBUG_EXECUTE 0x00000008 +#define CC_DEBUG_FLASH 0x00000010 /* ccdbg-command.c */ void @@ -335,17 +331,4 @@ ccdbg_write_hex_image(struct ccdbg *dbg, struct hex_image *image, uint16_t offse struct hex_image * ccdbg_read_hex_image(struct ccdbg *dbg, uint16_t address, uint16_t length); -/* cp-usb.c */ -void -cp_usb_init(struct ccdbg *dbg); - -void -cp_usb_fini(struct ccdbg *dbg); - -void -cp_usb_write(struct ccdbg *dbg, uint8_t mask, uint8_t value); - -uint8_t -cp_usb_read(struct ccdbg *dbg); - #endif /* _CCDBG_H_ */ diff --git a/lib/cp-usb.c b/lib/cp-usb.c index 61b684a2..6ab9092c 100644 --- a/lib/cp-usb.c +++ b/lib/cp-usb.c @@ -16,8 +16,20 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#include "ccdbg.h" -#include +/* + * 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 + +struct cp_usb { + usb_dev_handle *usb_dev; + uint8_t gpio; +}; #define CP2101_UART 0x00 #define UART_ENABLE 0x0001 @@ -26,9 +38,9 @@ #define REQTYPE_DEVICE_TO_HOST 0xc1 static int -cp_usb_gpio_get(struct ccdbg *dbg, uint8_t *gpio_get) +cp_usb_gpio_get(struct cp_usb *cp, uint8_t *gpio_get) { - return usb_control_msg(dbg->usb_dev, /* dev */ + return usb_control_msg(cp->usb_dev, /* dev */ 0xc0, /* request */ 0xff, /* requesttype */ 0x00c2, /* value */ @@ -39,11 +51,11 @@ cp_usb_gpio_get(struct ccdbg *dbg, uint8_t *gpio_get) } static int -cp_usb_gpio_set(struct ccdbg *dbg, uint8_t mask, uint8_t value) +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(dbg->usb_dev, /* dev */ + return usb_control_msg(cp->usb_dev, /* dev */ 0x40, /* request */ 0xff, /* requesttype */ 0x37e1, /* value */ @@ -54,9 +66,9 @@ cp_usb_gpio_set(struct ccdbg *dbg, uint8_t mask, uint8_t value) } static int -cp_usb_uart_enable_disable(struct ccdbg *dbg, uint16_t enable) +cp_usb_uart_enable_disable(struct cp_usb *cp, uint16_t enable) { - return usb_control_msg(dbg->usb_dev, + return usb_control_msg(cp->usb_dev, CP2101_UART, REQTYPE_HOST_TO_DEVICE, enable, @@ -66,9 +78,10 @@ cp_usb_uart_enable_disable(struct ccdbg *dbg, uint16_t enable) 300); } -void -cp_usb_init(struct ccdbg *dbg) +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; @@ -92,49 +105,52 @@ cp_usb_init(struct ccdbg *dbg) } if (!dev){ perror("No CP2103 found"); - exit(1); + 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); - dbg->usb_dev = dev_handle; - ret = cp_usb_uart_enable_disable(dbg, UART_DISABLE); - dbg->gpio = 0xf; - ret = cp_usb_gpio_set(dbg, 0xf, dbg->gpio); - ret = cp_usb_gpio_get(dbg, &gpio); + 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_fini(struct ccdbg *dbg) +cp_usb_close(struct cp_usb *cp) { - cp_usb_uart_enable_disable(dbg, UART_DISABLE); - usb_close(dbg->usb_dev); + cp_usb_uart_enable_disable(cp, UART_DISABLE); + usb_close(cp->usb_dev); + free(cp); } void -cp_usb_write(struct ccdbg *dbg, uint8_t mask, uint8_t value) +cp_usb_write(struct cp_usb *cp, uint8_t mask, uint8_t value) { uint8_t new_gpio; int ret; - new_gpio = (dbg->gpio & ~mask) | (value & mask); - if (new_gpio != dbg->gpio) { - ret = cp_usb_gpio_set(dbg, new_gpio ^ dbg->gpio, new_gpio); + 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"); - dbg->gpio = new_gpio; + cp->gpio = new_gpio; } } uint8_t -cp_usb_read(struct ccdbg *dbg) +cp_usb_read(struct cp_usb *cp) { int ret; uint8_t gpio; - ret = cp_usb_gpio_get(dbg, &gpio); + ret = cp_usb_gpio_get(cp, &gpio); if (ret < 0) - perror("gpio_set"); + perror("gpio_get"); return gpio; } -- cgit v1.2.3 From e75918f3667a5c8ad294bec4acef6fe81682edf6 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 21 Dec 2008 23:33:35 -0800 Subject: Add preliminary version of s51, a UI clone of the 8051 emulator. sdcdb provides source-level debugging using the 8051 emulator, s51. By emulating that emulator a the UI level, we should be able to get source debugging right on our target platform. This is just the preliminary structure for the program with most commands not yet implemented. --- lib/cp-usb.h | 36 +++++++++ s51/Makefile.am | 10 +++ s51/commands | 61 ++++++++++++++ s51/s51-command.c | 171 ++++++++++++++++++++++++++++++++++++++++ s51/s51-main.c | 143 +++++++++++++++++++++++++++++++++ s51/s51-parse.c | 232 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ s51/s51.h | 78 ++++++++++++++++++ 7 files changed, 731 insertions(+) create mode 100644 lib/cp-usb.h create mode 100644 s51/Makefile.am create mode 100644 s51/commands create mode 100644 s51/s51-command.c create mode 100644 s51/s51-main.c create mode 100644 s51/s51-parse.c create mode 100644 s51/s51.h (limited to 'lib') diff --git a/lib/cp-usb.h b/lib/cp-usb.h new file mode 100644 index 00000000..3e5f25ff --- /dev/null +++ b/lib/cp-usb.h @@ -0,0 +1,36 @@ +/* + * Copyright © 2008 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _CP_USB_H_ +#define _CP_USB_H_ +#include + +struct cp_usb * +cp_usb_open(void); + +void +cp_usb_close(struct cp_usb *cp); + +void +cp_usb_write(struct cp_usb *cp, uint8_t mask, uint8_t value); + +uint8_t +cp_usb_read(struct cp_usb *cp); + + +#endif diff --git a/s51/Makefile.am b/s51/Makefile.am new file mode 100644 index 00000000..cfa183d4 --- /dev/null +++ b/s51/Makefile.am @@ -0,0 +1,10 @@ +bin_PROGRAMS=s51 + +AM_CFLAGS=-I$(top_srcdir)/lib +S51_LIBS=../lib/libcc.a + +s51_DEPENDENCIES = $(S51_LIBS) + +s51_LDADD=$(S51_LIBS) $(USB_LIBS) + +s51_SOURCES = s51-parse.c s51-command.c s51-main.c diff --git a/s51/commands b/s51/commands new file mode 100644 index 00000000..77a98493 --- /dev/null +++ b/s51/commands @@ -0,0 +1,61 @@ +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 - continue + next - step over calls(?) + step - step one instruction + + reset - reset the simulator + res - synonym? + +Error messages: + + start with "Error:" + diff --git a/s51/s51-command.c b/s51/s51-command.c new file mode 100644 index 00000000..8a5d4c08 --- /dev/null +++ b/s51/s51-command.c @@ -0,0 +1,171 @@ +/* + * 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 enum command_result +parse_int(char *value, int *result) +{ + char *endptr; + + *result = strtol(value, &endptr, 0); + if (endptr == value) + return command_syntax; + return command_proceed; +} + +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_proceed) + return command_error; + if (v < 0 || v > 0xffff) + return command_error; + *uint16 = v; + return command_proceed; +} + +enum command_result +command_quit (FILE *output, int argc, char **argv) +{ + exit(0); + return command_error; +} + +enum command_result +command_di (FILE *output, int argc, char **argv) +{ + return command_error; +} + +enum command_result +command_ds (FILE *output, int argc, char **argv) +{ + return command_error; +} + +enum command_result +command_dx (FILE *output, int argc, char **argv) +{ + return command_error; +} + +enum command_result +command_set (FILE *output, int argc, char **argv) +{ + return command_error; +} + +enum command_result +command_dump (FILE *output, int argc, char **argv) +{ + return command_error; +} + +enum command_result +command_pc (FILE *output, int argc, char **argv) +{ + uint16_t pc; + if (argv[1]) { + enum command_result result; + + result = parse_uint16(argv[1], &pc); + if (result != command_proceed) + return result; + ccdbg_set_pc(s51_dbg, pc); + } else { + pc = ccdbg_get_pc(s51_dbg); + printf (" 0x%04x\n", pc); + } + return command_proceed; +} + +enum command_result +command_break (FILE *output, int argc, char **argv) +{ + return command_error; +} + +enum command_result +command_clear (FILE *output, int argc, char **argv) +{ + return command_error; +} + +enum command_result +command_run (FILE *output, int argc, char **argv) +{ + uint16_t start, end; + enum command_result result; + + if (argv[1]) { + result = parse_uint16(argv[1], &start); + if (result != command_proceed) + return result; + if (argv[2]) { + result = parse_uint16(argv[2], &end); + if (result != command_proceed) + return result; + } + ccdbg_set_pc(s51_dbg, start); + } + else + start = ccdbg_get_pc(s51_dbg); + fprintf(output, "Resume at 0x%04x\n", start); + ccdbg_resume(s51_dbg); + return command_proceed; +} + +enum command_result +command_next (FILE *output, int argc, char **argv) +{ + return command_error; +} + +enum command_result +command_step (FILE *output, int argc, char **argv) +{ + return command_error; +} + +enum command_result +command_load (FILE *output, int argc, char **argv) +{ + return command_error; +} + +enum command_result +command_halt (FILE *output, int argc, char **argv) +{ + uint16_t pc; + ccdbg_halt(s51_dbg); + pc = ccdbg_get_pc(s51_dbg); + fprintf(output, "Halted at 0x%04x\n", pc); + return command_proceed; +} + +enum command_result +command_reset (FILE *output, int argc, char **argv) +{ + ccdbg_debug_mode(s51_dbg); + return command_proceed; +} diff --git a/s51/s51-main.c b/s51/s51-main.c new file mode 100644 index 00000000..e8bf2d7d --- /dev/null +++ b/s51/s51-main.c @@ -0,0 +1,143 @@ +/* + * 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 + +static int s51_port = 0; +static char *cpu = "8051"; +static double freq = 11059200; +char *s51_prompt = "> "; +struct ccdbg *s51_dbg; + +static void +usage(void) +{ + fprintf(stderr, "You're doing it wrong.\n"); + exit(1); +} + +int +main(int argc, char **argv) +{ + int flags, opt; + FILE *console_in = stdin; + FILE *console_out = stdout; + char *endptr; + + while ((opt = getopt(argc, argv, "PVvHht:X:c: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 '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; + } + } + 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); + } + 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 = setsockopt(l, SOL_SOCKET, SO_REUSEADDR, &one, sizeof (int)); + if (r) { + perror("setsockopt"); + 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); + FILE *client; + + s = accept(r, (struct sockaddr *) + &client_addr, &client_len); + if (s < 0) { + perror("accept"); + exit(1); + } + client = fdopen(s, "rw"); + if (!client) { + perror("fdopen"); + exit(1); + } + command_read(client, client); + fclose(client); + } + } else + command_read(console_in, console_out); + exit(0); +} diff --git a/s51/s51-parse.c b/s51/s51-parse.c new file mode 100644 index 00000000..ba0d611c --- /dev/null +++ b/s51/s51-parse.c @@ -0,0 +1,232 @@ +/* + * 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" + +struct command_function { + char *name; + char *alias; + enum command_result (*func)(FILE *output, int argc, char **argv); + char *usage; + char *help; +}; + +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" }, + { "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" }, + { "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" }, +}; + +#define NUM_FUNCTIONS (sizeof functions / sizeof functions[0]) + +#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; +} + +static struct command_function * +command_string_to_function(char *name) +{ + int i; + for (i = 0; i < NUM_FUNCTIONS; i++) + if (!strcmp(name, functions[i].name) || + !strcmp(name, functions[i].alias)) + return &functions[i]; + return NULL; +} + +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(FILE *output, int argc, char **argv) +{ + int i; + struct command_function *func; + + if (argc == 1) { + for (i = 0; i < NUM_FUNCTIONS; i++) + fprintf(output, "%-10s%s\n", functions[i].name, + functions[i].usage); + } else { + for (i = 1; i < argc; i++) { + func = command_string_to_function(argv[i]); + if (!func) { + fprintf(output, "%-10s unknown command\n", argv[i]); + return command_syntax; + } + fprintf(output, "%-10s %s\n%s", func->name, + func->usage, func->help); + } + } + return command_debug; +} + +static void +command_syntax_error(FILE *output, int argc, char **argv) +{ + fprintf(output, "Syntax error in:"); + while (*argv) + fprintf(output, " %s", *argv++); + fprintf(output, "\n"); +} + +void +command_read (FILE *input, FILE *output) +{ + 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); + fprintf(output, "Welcome to the non-simulated processor\n"); + for (;;) { + if (s51_prompt) + fprintf(output, "%s", s51_prompt); + else + putc('\0', output); + fflush(output); + if (!fgets (line, sizeof line, input)) + break; + argc = command_split_into_words(line, argv); + if (argc > 0) { + func = command_string_to_function(argv[0]); + if (!func) + command_syntax_error(output, argc, argv); + else + { + result = (*func->func)(output, argc, argv); + switch (result) { + case command_syntax: + command_syntax_error(output, argc, argv); + break; + case command_error: + fprintf(output, "Error\n"); + break; + case command_proceed: + break; + default: + break; + } + } + } + } + ccdbg_close(s51_dbg); + fprintf(output, "...\n"); +} + diff --git a/s51/s51.h b/s51/s51.h new file mode 100644 index 00000000..b916acb6 --- /dev/null +++ b/s51/s51.h @@ -0,0 +1,78 @@ +/* + * 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 + +extern char *s51_prompt; + +extern struct ccdbg *s51_dbg; + +enum command_result { + command_proceed, command_debug, command_syntax, command_error +}; + +enum command_result +command_quit (FILE *output, int argc, char **argv); + +enum command_result +command_help (FILE *output, int argc, char **argv); + +enum command_result +command_di (FILE *output, int argc, char **argv); + +enum command_result +command_ds (FILE *output, int argc, char **argv); + +enum command_result +command_dx (FILE *output, int argc, char **argv); + +enum command_result +command_set (FILE *output, int argc, char **argv); + +enum command_result +command_dump (FILE *output, int argc, char **argv); + +enum command_result +command_pc (FILE *output, int argc, char **argv); + +enum command_result +command_break (FILE *output, int argc, char **argv); + +enum command_result +command_clear (FILE *output, int argc, char **argv); + +enum command_result +command_run (FILE *output, int argc, char **argv); + +enum command_result +command_next (FILE *output, int argc, char **argv); + +enum command_result +command_step (FILE *output, int argc, char **argv); + +enum command_result +command_load (FILE *output, int argc, char **argv); + +enum command_result +command_halt (FILE *output, int argc, char **argv); + +enum command_result +command_reset (FILE *output, int argc, char **argv); + +void +command_read (FILE *input, FILE *output); -- cgit v1.2.3 From 55eba4fa08b022197106245d36a70f575a070b0a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 22 Dec 2008 19:10:27 -0800 Subject: Make read_memory debug output use ccdbg_debug. This makes it default to not being presented, which makes s51 much happier Signed-off-by: Keith Packard --- lib/ccdbg-debug.c | 6 ++++++ lib/ccdbg-io.c | 1 + lib/ccdbg-memory.c | 28 ++++++++++++++++++++++------ lib/ccdbg.h | 4 ++++ 4 files changed, 33 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/ccdbg-debug.c b/lib/ccdbg-debug.c index 2e67bc8d..8f6f9e11 100644 --- a/lib/ccdbg-debug.c +++ b/lib/ccdbg-debug.c @@ -45,3 +45,9 @@ ccdbg_debug(int level, char *format, ...) va_end(ap); } } + +void +ccdbg_flush(void) +{ + fflush(stdout); +} diff --git a/lib/ccdbg-io.c b/lib/ccdbg-io.c index 6999dbec..5ecea769 100644 --- a/lib/ccdbg-io.c +++ b/lib/ccdbg-io.c @@ -129,6 +129,7 @@ ccdbg_recv_bit(struct ccdbg *dbg, int first) ccdbg_send(dbg, CC_CLOCK|mask|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); read = ccdbg_read(dbg); + ccdbg_print("#\t%c %c %c\n", CC_DATA, read); ccdbg_send(dbg, CC_CLOCK| CC_RESET_N, CC_RESET_N); return (read & CC_DATA) ? 1 : 0; } diff --git a/lib/ccdbg-memory.c b/lib/ccdbg-memory.c index 105295db..3406a1b1 100644 --- a/lib/ccdbg-memory.c +++ b/lib/ccdbg-memory.c @@ -54,10 +54,18 @@ ccdbg_write_memory(struct ccdbg *dbg, uint16_t addr, uint8_t *bytes, int nbytes) for (i = 0; i < nbytes; i++) { write8[DATA_BYTE] = *bytes++; ccdbg_execute(dbg, write8); - if ((i & 0xf) == 0xf) { printf ("."); fflush(stdout); nl = 1; } - if ((i & 0xff) == 0xff) { printf ("\n"); nl = 0; } + if ((i & 0xf) == 0xf) { + ccdbg_debug(CC_DEBUG_MEMORY, "."); + ccdbg_flush(); + nl = 1; + } + if ((i & 0xff) == 0xff) { + ccdbg_debug(CC_DEBUG_MEMORY, "\n"); + nl = 0; + } } - if (nl) printf ("\n"); + if (nl) + ccdbg_debug(CC_DEBUG_MEMORY, "\n"); return 0; } @@ -70,10 +78,18 @@ ccdbg_read_memory(struct ccdbg *dbg, uint16_t addr, uint8_t *bytes, int nbytes) (void) ccdbg_execute(dbg, memory_init); for (i = 0; i < nbytes; i++) { *bytes++ = ccdbg_execute(dbg, read8); - if ((i & 0xf) == 0xf) { printf ("."); fflush(stdout); nl = 1; } - if ((i & 0xff) == 0xff) { printf ("\n"); nl = 0; } + if ((i & 0xf) == 0xf) { + ccdbg_debug(CC_DEBUG_MEMORY, "."); + ccdbg_flush(); + nl = 1; + } + if ((i & 0xff) == 0xff) { + ccdbg_debug(CC_DEBUG_MEMORY, "\n"); + nl = 0; + } } - if (nl) printf ("\n"); + if (nl) + ccdbg_debug(CC_DEBUG_MEMORY, "\n"); return 0; } diff --git a/lib/ccdbg.h b/lib/ccdbg.h index 4d4a648d..e0e58104 100644 --- a/lib/ccdbg.h +++ b/lib/ccdbg.h @@ -160,6 +160,7 @@ struct hex_image { #define CC_DEBUG_INSTRUCTIONS 0x00000004 #define CC_DEBUG_EXECUTE 0x00000008 #define CC_DEBUG_FLASH 0x00000010 +#define CC_DEBUG_MEMORY 0x00000020 /* ccdbg-command.c */ void @@ -223,6 +224,9 @@ ccdbg_add_debug(int level); void ccdbg_clear_debug(int level); +void +ccdbg_flush(void); + /* ccdbg-flash.c */ uint8_t ccdbg_flash_hex_image(struct ccdbg *dbg, struct hex_image *image); -- cgit v1.2.3 From 1264c3676e95427bba5d01e05c303d036a7f9eca Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 26 Dec 2008 23:05:04 -0800 Subject: Switch to libusb-1.0 and use async interface. The async libusb interface offers substantial performance benefits by not making each command wait for the reply. This makes talking over this interface almost reasonable. Signed-off-by: Keith Packard --- ccload/Makefile.am | 4 +- configure.ac | 4 ++ lib/Makefile.am | 5 +- lib/ccdbg-command.c | 2 + lib/ccdbg-debug.h | 44 +++++++++++++ lib/ccdbg-io.c | 70 ++++++++++++++++----- lib/ccdbg-manual.c | 2 +- lib/ccdbg.h | 48 ++++++-------- lib/cp-usb-async.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/cp-usb-async.h | 38 ++++++++++++ s51/Makefile.am | 4 +- 11 files changed, 344 insertions(+), 53 deletions(-) create mode 100644 lib/ccdbg-debug.h create mode 100644 lib/cp-usb-async.c create mode 100644 lib/cp-usb-async.h (limited to 'lib') diff --git a/ccload/Makefile.am b/ccload/Makefile.am index f54f4aaa..3a754b23 100644 --- a/ccload/Makefile.am +++ b/ccload/Makefile.am @@ -1,10 +1,10 @@ bin_PROGRAMS=ccload -AM_CFLAGS=-I$(top_srcdir)/lib +AM_CFLAGS=-I$(top_srcdir)/lib $(LIBUSB_CFLAGS) CCLOAD_LIBS=../lib/libcc.a ccload_DEPENDENCIES = $(CCLOAD_LIBS) -ccload_LDADD=$(CCLOAD_LIBS) $(USB_LIBS) +ccload_LDADD=$(CCLOAD_LIBS) $(LIBUSB_LIBS) ccload_SOURCES = ccload.c diff --git a/configure.ac b/configure.ac index a14c802b..3ae80522 100644 --- a/configure.ac +++ b/configure.ac @@ -30,7 +30,9 @@ AC_PROG_CC AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_RANLIB +PKG_PROG_PKG_CONFIG +CFLAGS="-g" WARN_CFLAGS="" if test "x$GCC" = "xyes"; then WARN_CFLAGS="-Wall -Wpointer-arith -Wstrict-prototypes \ @@ -57,6 +59,8 @@ fi AC_MSG_RESULT([$CC_FOR_BUILD]) AC_SUBST(CC_FOR_BUILD) +PKG_CHECK_MODULES([LIBUSB], [libusb-1.0]) + AC_MSG_CHECKING([for suffix of executable build tools]) if test $cross_compiling = yes; then cat >conftest.c <<\_______EOF diff --git a/lib/Makefile.am b/lib/Makefile.am index a5e5932b..16f5b921 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,6 +1,6 @@ noinst_LIBRARIES = libcc.a -AM_CFLAGS=$(WARN_CFLAGS) +AM_CFLAGS=$(WARN_CFLAGS) $(LIBUSB_CFLAGS) libcc_a_SOURCES = \ ccdbg-command.c \ @@ -11,4 +11,5 @@ libcc_a_SOURCES = \ ccdbg-io.c \ ccdbg-manual.c \ ccdbg-memory.c \ - cp-usb.c + cp-usb.c \ + cp-usb-async.c diff --git a/lib/ccdbg-command.c b/lib/ccdbg-command.c index 30f5094d..2b29fdee 100644 --- a/lib/ccdbg-command.c +++ b/lib/ccdbg-command.c @@ -31,6 +31,7 @@ ccdbg_debug_mode(struct ccdbg *dbg) ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_DATA ); ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_DATA|CC_RESET_N); + ccdbg_sync_io(dbg); } void @@ -45,6 +46,7 @@ ccdbg_reset(struct ccdbg *dbg) ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); + ccdbg_sync_io(dbg); } uint8_t diff --git a/lib/ccdbg-debug.h b/lib/ccdbg-debug.h new file mode 100644 index 00000000..a09148d3 --- /dev/null +++ b/lib/ccdbg-debug.h @@ -0,0 +1,44 @@ +/* + * Copyright © 2008 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _CCDBG_DEBUG_H_ +#define _CCDBG_DEBUG_H_ +/* Debug levels + */ +#define CC_DEBUG_BITBANG 0x00000001 +#define CC_DEBUG_COMMAND 0x00000002 +#define CC_DEBUG_INSTRUCTIONS 0x00000004 +#define CC_DEBUG_EXECUTE 0x00000008 +#define CC_DEBUG_FLASH 0x00000010 +#define CC_DEBUG_MEMORY 0x00000020 +#define CC_DEBUG_USB_ASYNC 0x00000040 + +/* ccdbg-debug.c */ +void +ccdbg_debug(int level, char *format, ...); + +void +ccdbg_add_debug(int level); + +void +ccdbg_clear_debug(int level); + +void +ccdbg_flush(void); + +#endif /* _CCDBG_DEBUG_H_ */ diff --git a/lib/ccdbg-io.c b/lib/ccdbg-io.c index 5ecea769..53ea7583 100644 --- a/lib/ccdbg-io.c +++ b/lib/ccdbg-io.c @@ -18,6 +18,11 @@ #include "ccdbg.h" #include +#ifdef CP_USB_ASYNC +#include "cp-usb-async.h" +#else +#include "cp-usb.h" +#endif void ccdbg_half_clock(struct ccdbg *dbg) @@ -38,32 +43,60 @@ ccdbg_open(void) perror("calloc"); return NULL; } +#ifdef CP_USB_ASYNC + dbg->cp_async = cp_usb_async_open(); + if (!dbg->cp_async) { + free (dbg); + return NULL; + } +#else dbg->cp = cp_usb_open (); if (!dbg->cp) { free (dbg); return NULL; } +#endif return dbg; } void ccdbg_close(struct ccdbg *dbg) { +#ifdef CP_USB_ASYNC + cp_usb_async_close(dbg->cp_async); +#else cp_usb_close(dbg->cp); +#endif free (dbg); } int ccdbg_write(struct ccdbg *dbg, uint8_t mask, uint8_t value) { +#ifdef CP_USB_ASYNC + cp_usb_async_write(dbg->cp_async, mask, value); +#else cp_usb_write(dbg->cp, mask, value); +#endif return 0; } -uint8_t -ccdbg_read(struct ccdbg *dbg) +void +ccdbg_read(struct ccdbg *dbg, uint8_t *valuep) +{ +#ifdef CP_USB_ASYNC + cp_usb_async_read(dbg->cp_async, valuep); +#else + *valuep = cp_usb_read(dbg->cp); +#endif +} + +void +ccdbg_sync_io(struct ccdbg *dbg) { - return cp_usb_read(dbg->cp); +#ifdef CP_USB_ASYNC + cp_usb_async_sync(dbg->cp_async); +#endif } static char @@ -112,6 +145,7 @@ ccdbg_send_byte(struct ccdbg *dbg, uint8_t byte) if (bit == 3) ccdbg_debug(CC_DEBUG_BITBANG, "\n"); } + ccdbg_sync_io(dbg); } void @@ -121,43 +155,47 @@ ccdbg_send_bytes(struct ccdbg *dbg, uint8_t *bytes, int nbytes) ccdbg_send_byte(dbg, *bytes++); } -uint8_t -ccdbg_recv_bit(struct ccdbg *dbg, int first) +void +ccdbg_recv_bit(struct ccdbg *dbg, int first, uint8_t *bit) { uint8_t mask = first ? CC_DATA : 0; - uint8_t read; ccdbg_send(dbg, CC_CLOCK|mask|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); - read = ccdbg_read(dbg); - ccdbg_print("#\t%c %c %c\n", CC_DATA, read); + ccdbg_read(dbg, bit); ccdbg_send(dbg, CC_CLOCK| CC_RESET_N, CC_RESET_N); - return (read & CC_DATA) ? 1 : 0; } -uint8_t -ccdbg_recv_byte(struct ccdbg *dbg, int first) +void +ccdbg_recv_byte(struct ccdbg *dbg, int first, uint8_t *bytep) { uint8_t byte = 0; + uint8_t bits[8]; int bit; ccdbg_debug(CC_DEBUG_BITBANG, "#\n# Recv byte\n#\n"); + for (bit = 0; bit < 8; bit++) { + ccdbg_recv_bit(dbg, first, &bits[bit]); + first = 0; + } + ccdbg_sync_io(dbg); for (bit = 0; bit < 8; bit++) { byte = byte << 1; - byte |= ccdbg_recv_bit(dbg, first); + byte |= (bits[bit] & CC_DATA) ? 1 : 0; + ccdbg_print("#\t%c %c %c\n", CC_DATA, bits[bit]); if (bit == 3) ccdbg_debug(CC_DEBUG_BITBANG, "\n"); - first = 0; } ccdbg_debug(CC_DEBUG_BITBANG, "#\n# Recv 0x%02x\n#\n", byte); - return byte; + *bytep = byte; } void ccdbg_recv_bytes(struct ccdbg *dbg, uint8_t *bytes, int nbytes) { + int i; int first = 1; - while (nbytes--) { - *bytes++ = ccdbg_recv_byte(dbg, first); + for (i = 0; i < nbytes; i++) { + ccdbg_recv_byte(dbg, first, &bytes[i]); first = 0; } } diff --git a/lib/ccdbg-manual.c b/lib/ccdbg-manual.c index b83dc450..b48f8bb1 100644 --- a/lib/ccdbg-manual.c +++ b/lib/ccdbg-manual.c @@ -59,7 +59,7 @@ ccdbg_manual(struct ccdbg *dbg, FILE *input) get_bit(line, 4, 'R', CC_RESET_N, &set, &mask); if (mask != (CC_CLOCK|CC_DATA|CC_RESET_N)) { uint8_t read; - read = ccdbg_read(dbg); + ccdbg_read(dbg, &read); ccdbg_print("\t%c %c %c", CC_CLOCK|CC_DATA|CC_RESET_N, read); if ((set & CC_CLOCK) == 0) printf ("\t%d", (read&CC_DATA) ? 1 : 0); diff --git a/lib/ccdbg.h b/lib/ccdbg.h index e0e58104..834092b2 100644 --- a/lib/ccdbg.h +++ b/lib/ccdbg.h @@ -30,11 +30,12 @@ #include #include #include -#include "cp-usb.h" +#include "ccdbg-debug.h" + #define CC_CLOCK 0x1 #define CC_DATA 0x2 #define CC_RESET_N 0x4 -#define CC_CLOCK_US (40) +#define CC_CLOCK_US (0) /* 8051 instructions */ @@ -90,8 +91,14 @@ /* Bit-addressable accumulator */ #define ACC(bit) (0xE0 | (bit)) +#define CP_USB_ASYNC + struct ccdbg { +#ifdef CP_USB_ASYNC + struct cp_usb_async *cp_async; +#else struct cp_usb *cp; +#endif }; /* Intel hex file format data @@ -153,15 +160,6 @@ struct hex_image { #define CC_STEP_REPLACE(n) (0x64|(n)) #define CC_GET_CHIP_ID 0x68 -/* Debug levels - */ -#define CC_DEBUG_BITBANG 0x00000001 -#define CC_DEBUG_COMMAND 0x00000002 -#define CC_DEBUG_INSTRUCTIONS 0x00000004 -#define CC_DEBUG_EXECUTE 0x00000008 -#define CC_DEBUG_FLASH 0x00000010 -#define CC_DEBUG_MEMORY 0x00000020 - /* ccdbg-command.c */ void ccdbg_debug_mode(struct ccdbg *dbg); @@ -214,19 +212,6 @@ ccdbg_set_pc(struct ccdbg *dbg, uint16_t pc); uint8_t ccdbg_execute_hex_image(struct ccdbg *dbg, struct hex_image *image); -/* ccdbg-debug.c */ -void -ccdbg_debug(int level, char *format, ...); - -void -ccdbg_add_debug(int level); - -void -ccdbg_clear_debug(int level); - -void -ccdbg_flush(void); - /* ccdbg-flash.c */ uint8_t ccdbg_flash_hex_image(struct ccdbg *dbg, struct hex_image *image); @@ -254,8 +239,8 @@ ccdbg_half_clock(struct ccdbg *dbg); int ccdbg_write(struct ccdbg *dbg, uint8_t mask, uint8_t value); -uint8_t -ccdbg_read(struct ccdbg *dbg); +void +ccdbg_read(struct ccdbg *dbg, uint8_t *valuep); struct ccdbg * ccdbg_open(void); @@ -302,15 +287,18 @@ ccdbg_send_byte(struct ccdbg *dbg, uint8_t byte); void ccdbg_send_bytes(struct ccdbg *dbg, uint8_t *bytes, int nbytes); -uint8_t -ccdbg_recv_bit(struct ccdbg *dbg, int first); +void +ccdbg_recv_bit(struct ccdbg *dbg, int first, uint8_t *bit); -uint8_t -ccdbg_recv_byte(struct ccdbg *dbg, int first); +void +ccdbg_recv_byte(struct ccdbg *dbg, int first, uint8_t *byte); void ccdbg_recv_bytes(struct ccdbg *dbg, uint8_t *bytes, int nbytes); +void +ccdbg_sync_io(struct ccdbg *dbg); + void ccdbg_print(char *format, uint8_t mask, uint8_t set); diff --git a/lib/cp-usb-async.c b/lib/cp-usb-async.c new file mode 100644 index 00000000..3f5f76ab --- /dev/null +++ b/lib/cp-usb-async.c @@ -0,0 +1,176 @@ +/* + * Copyright © 2008 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include +#include +#include +#include "cp-usb-async.h" +#include "ccdbg-debug.h" + +#define MAX_OUTSTANDING 256 +#define CP_TIMEOUT 1000 /* ms */ + +struct cp_usb_packet { + struct libusb_transfer *transfer; + enum { packet_read, packet_write } direction; + unsigned char data[9]; + uint8_t *valuep; +}; + +struct cp_usb_async { + libusb_context *ctx; + libusb_device_handle *handle; + struct cp_usb_packet packet[MAX_OUTSTANDING]; + int p, ack; +}; + +struct cp_usb_async * +cp_usb_async_open(void) +{ + struct cp_usb_async *cp; + int ret; + + cp = calloc(sizeof (struct cp_usb_async), 1); + if (!cp) + return NULL; + ret = libusb_init(&cp->ctx); + if (ret) { + free(cp); + return NULL; + } + cp->handle = libusb_open_device_with_vid_pid(cp->ctx, + 0x10c4, 0xea60); + if (!cp->handle) { + libusb_exit(cp->ctx); + free(cp); + return NULL; + } + return cp; +} + +void +cp_usb_async_close(struct cp_usb_async *cp) +{ + libusb_close(cp->handle); + libusb_exit(cp->ctx); + free(cp); +} + +static void +cp_usb_async_transfer_callback(struct libusb_transfer *transfer) +{ + struct cp_usb_async *cp = transfer->user_data; + int p; + + for (p = 0; p < cp->p; p++) + if (cp->packet[p].transfer == transfer) + break; + if (p == cp->p) { + fprintf(stderr, "unknown transfer\n"); + return; + } + switch (cp->packet[p].direction) { + case packet_read: + ccdbg_debug(CC_DEBUG_USB_ASYNC, "ack read %d 0x%02x\n", + p, cp->packet[p].data[8]); + *cp->packet[p].valuep = cp->packet[p].data[8]; + break; + case packet_write: + ccdbg_debug(CC_DEBUG_USB_ASYNC, "ack write %d\n", p); + break; + } + if (p > cp->ack) + cp->ack = p; +} + +void +cp_usb_async_write(struct cp_usb_async *cp, uint8_t mask, uint8_t value) +{ + int p; + uint16_t gpio_set = ((uint16_t) value << 8) | mask; + int ret; + + if (cp->p == MAX_OUTSTANDING) + cp_usb_async_sync(cp); + p = cp->p; + if (!cp->packet[p].transfer) + cp->packet[p].transfer = libusb_alloc_transfer(0); + cp->packet[p].direction = packet_write; + libusb_fill_control_setup(cp->packet[p].data, + 0x40, /* request */ + 0xff, /* request type */ + 0x37e1, /* value */ + gpio_set, /* index */ + 0); /* length */ + + libusb_fill_control_transfer(cp->packet[p].transfer, + cp->handle, + cp->packet[p].data, + cp_usb_async_transfer_callback, + cp, + CP_TIMEOUT); + ccdbg_debug(CC_DEBUG_USB_ASYNC, "Write packet %d 0x%x 0x%x\n", p, mask, value); + ret = libusb_submit_transfer(cp->packet[p].transfer); + if (ret) + fprintf(stderr, "libusb_submit_transfer failed %d\n", ret); + cp->p++; +} + +void +cp_usb_async_read(struct cp_usb_async *cp, uint8_t *valuep) +{ + int p; + int ret; + + if (cp->p == MAX_OUTSTANDING) + cp_usb_async_sync(cp); + p = cp->p; + if (!cp->packet[p].transfer) + cp->packet[p].transfer = libusb_alloc_transfer(0); + cp->packet[p].valuep = valuep; + cp->packet[p].direction = packet_read; + libusb_fill_control_setup(cp->packet[p].data, + 0xc0, /* request */ + 0xff, /* request type */ + 0x00c2, /* value */ + 0, /* index */ + 1); /* length */ + + libusb_fill_control_transfer(cp->packet[p].transfer, + cp->handle, + cp->packet[p].data, + cp_usb_async_transfer_callback, + cp, + CP_TIMEOUT); + ccdbg_debug(CC_DEBUG_USB_ASYNC, "Read packet %d\n", p); + ret = libusb_submit_transfer(cp->packet[p].transfer); + if (ret) + fprintf(stderr, "libusb_submit_transfer failed %d\n", ret); + cp->p++; +} + +void +cp_usb_async_sync(struct cp_usb_async *cp) +{ + while (cp->ack < cp->p - 1) { + libusb_handle_events(cp->ctx); + } + cp->p = 0; + cp->ack = 0; +} diff --git a/lib/cp-usb-async.h b/lib/cp-usb-async.h new file mode 100644 index 00000000..976a320e --- /dev/null +++ b/lib/cp-usb-async.h @@ -0,0 +1,38 @@ +/* + * Copyright © 2008 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _CP_USB_ASYNC_H_ +#define _CP_USB_ASYNC_H_ +#include + +struct cp_usb_async * +cp_usb_async_open(void); + +void +cp_usb_async_close(struct cp_usb_async *cp); + +void +cp_usb_async_write(struct cp_usb_async *cp, uint8_t mask, uint8_t value); + +void +cp_usb_async_read(struct cp_usb_async *cp, uint8_t *valuep); + +void +cp_usb_async_sync(struct cp_usb_async *cp); + +#endif diff --git a/s51/Makefile.am b/s51/Makefile.am index cfa183d4..fa6fc692 100644 --- a/s51/Makefile.am +++ b/s51/Makefile.am @@ -1,10 +1,10 @@ bin_PROGRAMS=s51 -AM_CFLAGS=-I$(top_srcdir)/lib +AM_CFLAGS=-I$(top_srcdir)/lib $(LIBUSB_CFLAGS) S51_LIBS=../lib/libcc.a s51_DEPENDENCIES = $(S51_LIBS) -s51_LDADD=$(S51_LIBS) $(USB_LIBS) +s51_LDADD=$(S51_LIBS) $(LIBUSB_LIBS) s51_SOURCES = s51-parse.c s51-command.c s51-main.c -- cgit v1.2.3 From 23aca1fcbc169184e32d4ec19f28dd4fd4cfda36 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 28 Dec 2008 00:09:30 -0800 Subject: Save/restore regs when reading/writing memory. Add SFR access. The DPL and ACC registers are used by the memory access code, so they need to be saved and restored. Stuff them up high in ram for now; this should probably be fixed to pull them back to the host instead. Special SFR access is required as not all SFRs are visible in the unified address space. Signed-off-by: Keith Packard --- lib/ccdbg-memory.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- lib/ccdbg.h | 14 +++++++++++ 2 files changed, 81 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/ccdbg-memory.c b/lib/ccdbg-memory.c index 3406a1b1..d74726fb 100644 --- a/lib/ccdbg-memory.c +++ b/lib/ccdbg-memory.c @@ -23,9 +23,14 @@ */ static uint8_t memory_init[] = { + 2, MOV_direct_A, 0x7f, + 3, MOV_direct1_direct2, 0x7e, SFR_DPL0, + 3, MOV_direct1_direct2, 0x7d, SFR_DPH0, + 3, MOV_direct1_direct2, 0x7c, SFR_DPL1, + 3, MOV_direct1_direct2, 0x7b, SFR_DPH1, 3, MOV_DPTR_data16, 0, 0, -#define HIGH_START 2 -#define LOW_START 3 +#define HIGH_START 21 +#define LOW_START 22 0, }; @@ -44,6 +49,15 @@ static uint8_t read8[] = { 0, }; +static uint8_t memory_fini[] = { + 2, MOV_A_direct, 0x7f, + 3, MOV_direct1_direct2, SFR_DPL0, 0x7e, + 3, MOV_direct1_direct2, SFR_DPH0, 0x7d, + 3, MOV_direct1_direct2, SFR_DPL1, 0x7c, + 3, MOV_direct1_direct2, SFR_DPH1, 0x7b, + 0, +}; + uint8_t ccdbg_write_memory(struct ccdbg *dbg, uint16_t addr, uint8_t *bytes, int nbytes) { @@ -64,6 +78,7 @@ ccdbg_write_memory(struct ccdbg *dbg, uint16_t addr, uint8_t *bytes, int nbytes) nl = 0; } } + (void) ccdbg_execute(dbg, memory_fini); if (nl) ccdbg_debug(CC_DEBUG_MEMORY, "\n"); return 0; @@ -88,6 +103,7 @@ ccdbg_read_memory(struct ccdbg *dbg, uint16_t addr, uint8_t *bytes, int nbytes) nl = 0; } } + (void) ccdbg_execute(dbg, memory_fini); if (nl) ccdbg_debug(CC_DEBUG_MEMORY, "\n"); return 0; @@ -118,3 +134,52 @@ ccdbg_read_hex_image(struct ccdbg *dbg, uint16_t address, uint16_t length) ccdbg_read_memory(dbg, address, image->data, length); return image; } + +static uint8_t sfr_init[] = { + 2, MOV_direct_A, 0x7f, + 0, +}; + +static uint8_t sfr_fini[] = { + 2, MOV_A_direct, 0x7f, + 0, +}; + +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; + (void) ccdbg_execute(dbg, sfr_init); + for (i = 0; i < nbytes; i++) { + sfr_read[SFR_READ_ADDR] = addr + i; + *bytes++ = ccdbg_execute(dbg, sfr_read); + } + (void) ccdbg_execute(dbg, sfr_fini); + 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 --git a/lib/ccdbg.h b/lib/ccdbg.h index 834092b2..203b5aeb 100644 --- a/lib/ccdbg.h +++ b/lib/ccdbg.h @@ -44,6 +44,7 @@ #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 @@ -57,6 +58,13 @@ /* 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 @@ -323,4 +331,10 @@ ccdbg_write_hex_image(struct ccdbg *dbg, struct hex_image *image, uint16_t offse 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); + #endif /* _CCDBG_H_ */ -- cgit v1.2.3 From ea366058aa467a8a7caf17e7014758f3741ea7f7 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 29 Dec 2008 12:35:11 -0800 Subject: Fix flashing less than a full page of data. Verify page at a time. The 8051 flashing code requires special help with counts with non-zero low byte. Also, instead of verifying the entire flash contents at the end, verify each page as it goes. Signed-off-by: Keith Packard --- ccload/ccload.c | 2 ++ lib/ccdbg-flash.c | 61 ++++++++++++++++++++++++++++++++------------------- target/blink/Makefile | 2 ++ 3 files changed, 42 insertions(+), 23 deletions(-) (limited to 'lib') diff --git a/ccload/ccload.c b/ccload/ccload.c index b4bb1443..3e220914 100644 --- a/ccload/ccload.c +++ b/ccload/ccload.c @@ -54,6 +54,8 @@ main (int argc, char **argv) if (!dbg) exit (1); + ccdbg_add_debug(CC_DEBUG_FLASH); + ccdbg_debug_mode(dbg); ccdbg_halt(dbg); if (image->address == 0xf000) { diff --git a/lib/ccdbg-flash.c b/lib/ccdbg-flash.c index f950dd1b..8b3390c7 100644 --- a/lib/ccdbg-flash.c +++ b/lib/ccdbg-flash.c @@ -244,13 +244,16 @@ ccdbg_flash_hex_image(struct ccdbg *dbg, struct hex_image *image) 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) { @@ -286,52 +289,64 @@ ccdbg_flash_hex_image(struct ccdbg *dbg, struct hex_image *image) 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); - ccdbg_debug(CC_DEBUG_FLASH, "Verify %d bytes\n", image->length); + 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, "image verify failed\n"); + fprintf(stderr, "ram verify failed\n"); return 1; } - flash_word_addr = (image->address + start) >> 1; + 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 >> 8); - ccdbg_write_uint8(dbg, flash_prog + FLASH_WORDS_LOW, flash_words & 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, "Starting flash program at 0x%04x\n", pc); + ccdbg_debug(CC_DEBUG_FLASH, "Flashing %d bytes at 0x%04x\n", + this_time, flash_addr); status = ccdbg_resume(dbg); - ccdbg_debug(CC_DEBUG_FLASH, "resume status is 0x%02x\n", status); - do { + for (times = 0; times < 10; times++) { status = ccdbg_read_status(dbg); ccdbg_debug(CC_DEBUG_FLASH, "chip status is 0x%02x\n", status); - sleep(1); - } while ((status & CC_STATUS_CPU_HALTED) == 0); + if ((status & CC_STATUS_CPU_HALTED) != 0) + break; + } + 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; } -#if 1 - ccdbg_debug(CC_DEBUG_FLASH, "Downloading flash to check\n"); - struct hex_image *test_image; - test_image = ccdbg_read_hex_image(dbg, image->address, image->length); - if (!ccdbg_hex_image_equal(image, test_image)) { - int i; - fprintf(stderr, "Image not loaded\n"); - for (i = 0;i < 0x10; i++) - ccdbg_debug(CC_DEBUG_FLASH, "0x%02x : 0x%02x\n", image->data[i], test_image->data[i]); - return 1; - } - return 0; -#endif return 0; } diff --git a/target/blink/Makefile b/target/blink/Makefile index 1f18f529..4c9b4102 100644 --- a/target/blink/Makefile +++ b/target/blink/Makefile @@ -42,3 +42,5 @@ blink-flash.ihx: blink-ram.ihx clean: rm -f $(ADB) $(ASM) $(LNK) $(LST) $(REL) $(RST) $(SYM) rm -f $(PROGS) $(PCDB) $(PLNK) $(PMAP) $(PMEM) $(PAOM) + +install: -- cgit v1.2.3 From 6c2a65c743a4ffae96ed27dbc38c1bf9242ed1df Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 30 Dec 2008 22:35:53 -0800 Subject: Save/restore registers to host during memory operations. Cache ROM data. Because the debug port uses instructions for most operations, the debug code will clobber registers used by the running program. Save and restore these to avoid corrupting application data. If the ROM file is known, use that to return data instead of fetching it from the target to improve performance. Signed-off-by: Keith Packard --- lib/Makefile.am | 2 + lib/ccdbg-debug.c | 5 ++- lib/ccdbg-debug.h | 2 +- lib/ccdbg-flash.c | 8 +++- lib/ccdbg-memory.c | 54 +++++++++------------- lib/ccdbg-rom.c | 63 ++++++++++++++++++++++++++ lib/ccdbg-state.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/ccdbg.h | 43 ++++++++++++++++++ s51/s51-command.c | 74 ++++++++++++++++++++++++++++--- s51/s51-parse.c | 71 +++++++++++++++-------------- s51/s51.h | 23 ++++++++++ 11 files changed, 396 insertions(+), 77 deletions(-) create mode 100644 lib/ccdbg-rom.c create mode 100644 lib/ccdbg-state.c (limited to 'lib') diff --git a/lib/Makefile.am b/lib/Makefile.am index 16f5b921..ba6f9725 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -11,5 +11,7 @@ libcc_a_SOURCES = \ ccdbg-io.c \ ccdbg-manual.c \ ccdbg-memory.c \ + ccdbg-rom.c \ + ccdbg-state.c \ cp-usb.c \ cp-usb-async.c diff --git a/lib/ccdbg-debug.c b/lib/ccdbg-debug.c index 8f6f9e11..847361c7 100644 --- a/lib/ccdbg-debug.c +++ b/lib/ccdbg-debug.c @@ -47,7 +47,8 @@ ccdbg_debug(int level, char *format, ...) } void -ccdbg_flush(void) +ccdbg_flush(int level) { - fflush(stdout); + if (ccdbg_level & level) + fflush(stdout); } diff --git a/lib/ccdbg-debug.h b/lib/ccdbg-debug.h index a09148d3..0b5b44c1 100644 --- a/lib/ccdbg-debug.h +++ b/lib/ccdbg-debug.h @@ -39,6 +39,6 @@ void ccdbg_clear_debug(int level); void -ccdbg_flush(void); +ccdbg_flush(int level); #endif /* _CCDBG_DEBUG_H_ */ diff --git a/lib/ccdbg-flash.c b/lib/ccdbg-flash.c index 8b3390c7..8a586a21 100644 --- a/lib/ccdbg-flash.c +++ b/lib/ccdbg-flash.c @@ -288,13 +288,14 @@ ccdbg_flash_hex_image(struct ccdbg *dbg, struct hex_image *image) 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; @@ -324,10 +325,13 @@ ccdbg_flash_hex_image(struct ccdbg *dbg, struct hex_image *image) status = ccdbg_resume(dbg); for (times = 0; times < 10; times++) { status = ccdbg_read_status(dbg); - ccdbg_debug(CC_DEBUG_FLASH, "chip status is 0x%02x\n", status); + 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; diff --git a/lib/ccdbg-memory.c b/lib/ccdbg-memory.c index d74726fb..20a24799 100644 --- a/lib/ccdbg-memory.c +++ b/lib/ccdbg-memory.c @@ -23,14 +23,9 @@ */ static uint8_t memory_init[] = { - 2, MOV_direct_A, 0x7f, - 3, MOV_direct1_direct2, 0x7e, SFR_DPL0, - 3, MOV_direct1_direct2, 0x7d, SFR_DPH0, - 3, MOV_direct1_direct2, 0x7c, SFR_DPL1, - 3, MOV_direct1_direct2, 0x7b, SFR_DPH1, 3, MOV_DPTR_data16, 0, 0, -#define HIGH_START 21 -#define LOW_START 22 +#define HIGH_START 2 +#define LOW_START 3 0, }; @@ -49,19 +44,13 @@ static uint8_t read8[] = { 0, }; -static uint8_t memory_fini[] = { - 2, MOV_A_direct, 0x7f, - 3, MOV_direct1_direct2, SFR_DPL0, 0x7e, - 3, MOV_direct1_direct2, SFR_DPH0, 0x7d, - 3, MOV_direct1_direct2, SFR_DPL1, 0x7c, - 3, MOV_direct1_direct2, SFR_DPH1, 0x7b, - 0, -}; - uint8_t ccdbg_write_memory(struct ccdbg *dbg, uint16_t addr, uint8_t *bytes, int nbytes) { int i, nl = 0; + struct ccstate state; + + 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); @@ -70,7 +59,7 @@ ccdbg_write_memory(struct ccdbg *dbg, uint16_t addr, uint8_t *bytes, int nbytes) ccdbg_execute(dbg, write8); if ((i & 0xf) == 0xf) { ccdbg_debug(CC_DEBUG_MEMORY, "."); - ccdbg_flush(); + ccdbg_flush(CC_DEBUG_MEMORY); nl = 1; } if ((i & 0xff) == 0xff) { @@ -78,7 +67,7 @@ ccdbg_write_memory(struct ccdbg *dbg, uint16_t addr, uint8_t *bytes, int nbytes) nl = 0; } } - (void) ccdbg_execute(dbg, memory_fini); + ccdbg_state_restore(dbg, &state); if (nl) ccdbg_debug(CC_DEBUG_MEMORY, "\n"); return 0; @@ -88,6 +77,13 @@ 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; + } + 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); @@ -95,7 +91,7 @@ ccdbg_read_memory(struct ccdbg *dbg, uint16_t addr, uint8_t *bytes, int nbytes) *bytes++ = ccdbg_execute(dbg, read8); if ((i & 0xf) == 0xf) { ccdbg_debug(CC_DEBUG_MEMORY, "."); - ccdbg_flush(); + ccdbg_flush(CC_DEBUG_MEMORY); nl = 1; } if ((i & 0xff) == 0xff) { @@ -103,7 +99,8 @@ ccdbg_read_memory(struct ccdbg *dbg, uint16_t addr, uint8_t *bytes, int nbytes) nl = 0; } } - (void) ccdbg_execute(dbg, memory_fini); + ccdbg_state_replace_xmem(dbg, &state, addr, bytes, nbytes); + ccdbg_state_restore(dbg, &state); if (nl) ccdbg_debug(CC_DEBUG_MEMORY, "\n"); return 0; @@ -135,16 +132,6 @@ ccdbg_read_hex_image(struct ccdbg *dbg, uint16_t address, uint16_t length) return image; } -static uint8_t sfr_init[] = { - 2, MOV_direct_A, 0x7f, - 0, -}; - -static uint8_t sfr_fini[] = { - 2, MOV_A_direct, 0x7f, - 0, -}; - static uint8_t sfr_read[] = { 2, MOV_A_direct, 0, #define SFR_READ_ADDR 2 @@ -162,12 +149,15 @@ uint8_t ccdbg_read_sfr(struct ccdbg *dbg, uint8_t addr, uint8_t *bytes, int nbytes) { int i; - (void) ccdbg_execute(dbg, sfr_init); + 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); } - (void) ccdbg_execute(dbg, sfr_fini); + ccdbg_state_replace_sfr(dbg, &state, addr, bytes, nbytes); + ccdbg_state_restore(dbg, &state); return 0; } diff --git a/lib/ccdbg-rom.c b/lib/ccdbg-rom.c new file mode 100644 index 00000000..4559b4e7 --- /dev/null +++ b/lib/ccdbg-rom.c @@ -0,0 +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 --git a/lib/ccdbg-state.c b/lib/ccdbg-state.c new file mode 100644 index 00000000..9aca8d2e --- /dev/null +++ b/lib/ccdbg-state.c @@ -0,0 +1,128 @@ +/* + * 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" + +static uint8_t save_acc[] = { + 1, NOP, + 0 +}; + +static uint8_t save_sfr[] = { + 2, MOV_A_direct, 0, +#define SAVE_SFR_ADDR 2 + 0, +}; + +struct sfr_state { + uint8_t address; + uint16_t mask; + char *name; +}; + +static struct sfr_state sfrs[CC_STATE_NSFR] = { + { SFR_DPL0, CC_STATE_DP, "dpl0" }, + { SFR_DPH0, CC_STATE_DP, "dph0" }, + { SFR_DPL1, CC_STATE_DP, "dpl1" }, + { SFR_DPH1, CC_STATE_DP, "dph1" }, + { PSW(0), CC_STATE_PSW, "psw" }, +}; + +uint8_t +ccdbg_state_save(struct ccdbg *dbg, struct ccstate *state, unsigned int mask) +{ + int i; + + mask |= CC_STATE_ACC; + if (mask & CC_STATE_ACC) + state->acc = ccdbg_execute(dbg, save_acc); + for (i = 0; i < CC_STATE_NSFR; i++) { + if (sfrs[i].mask & mask) { + save_sfr[SAVE_SFR_ADDR] = sfrs[i].address; + state->sfr[i] = ccdbg_execute(dbg, save_sfr); + } + } + state->mask = mask; + return 0; +} + +static uint8_t restore_sfr[] = { + 3, MOV_direct_data, 0, 0, +#define RESTORE_SFR_ADDR 2 +#define RESTORE_SFR_DATA 3 + 0 +}; + +static uint8_t restore_acc[] = { + 2, MOV_A_data, 0, +#define RESTORE_ACC_DATA 2 + 0 +}; + +uint8_t +ccdbg_state_restore(struct ccdbg *dbg, struct ccstate *state) +{ + int i; + for (i = CC_STATE_NSFR - 1; i >= 0; i--) { + if (sfrs[i].mask & state->mask) { + restore_sfr[RESTORE_SFR_ADDR] = sfrs[i].address; + restore_sfr[RESTORE_SFR_DATA] = state->sfr[i]; + ccdbg_execute(dbg, restore_sfr); + } + } + if (state->mask & CC_STATE_ACC) { + restore_acc[RESTORE_ACC_DATA] = state->acc; + ccdbg_execute(dbg, restore_acc); + } + state->mask = 0; + return 0; +} + +static void +ccdbg_state_replace(uint16_t sfr_addr, uint8_t sfr, char *name, + uint16_t addr, uint8_t *bytes, int nbytes) +{ + sfr_addr += 0xdf00; + + if (addr <= sfr_addr && sfr_addr < addr + nbytes) { + fprintf(stderr, "replacing %s at 0x%04x - read 0x%02x saved 0x%02x\n", + name, sfr_addr, bytes[sfr_addr - addr], sfr); + bytes[sfr_addr - addr] = sfr; + } +} + +void +ccdbg_state_replace_xmem(struct ccdbg *dbg, struct ccstate *state, + uint16_t addr, uint8_t *bytes, int nbytes) +{ + int i; + if (state->mask & CC_STATE_ACC) + ccdbg_state_replace(ACC(0), state->acc, "acc", + addr, bytes, nbytes); + for (i = 0; i < CC_STATE_NSFR; i++) + if (state->mask & sfrs[i].mask) + ccdbg_state_replace(sfrs[i].address, state->sfr[i], + sfrs[i].name, addr, bytes, nbytes); +} + +void +ccdbg_state_replace_sfr(struct ccdbg *dbg, struct ccstate *state, + uint8_t addr, uint8_t *bytes, int nbytes) +{ + ccdbg_state_replace_xmem(dbg, state, (uint16_t) addr + 0xdf00, bytes, nbytes); +} diff --git a/lib/ccdbg.h b/lib/ccdbg.h index 203b5aeb..241c4eec 100644 --- a/lib/ccdbg.h +++ b/lib/ccdbg.h @@ -39,6 +39,7 @@ /* 8051 instructions */ +#define NOP 0x00 #define MOV_direct_data 0x75 #define LJMP 0x02 #define MOV_Rn_data(n) (0x78 | (n)) @@ -99,6 +100,9 @@ /* Bit-addressable accumulator */ #define ACC(bit) (0xE0 | (bit)) +/* Bit-addressable status word */ +#define PSW(bit) (0xD0 | (bit)) + #define CP_USB_ASYNC struct ccdbg { @@ -107,6 +111,7 @@ struct ccdbg { #else struct cp_usb *cp; #endif + struct hex_image *rom; }; /* Intel hex file format data @@ -130,6 +135,18 @@ struct hex_image { 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 @@ -337,4 +354,30 @@ 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 --git a/s51/s51-command.c b/s51/s51-command.c index 25328f1e..63d142f4 100644 --- a/s51/s51-command.c +++ b/s51/s51-command.c @@ -69,12 +69,12 @@ command_quit (int argc, char **argv) } static void -dump_bytes(uint8_t *memory, int length, uint16_t start) +dump_bytes(uint8_t *memory, int length, uint16_t start, char *format) { int group, i; for (group = 0; group < length; group += 8) { - s51_printf("0x%04x ", start + group); + s51_printf(format, start + group); for (i = group; i < length && i < group + 8; i++) s51_printf("%02x ", memory[i]); for (; i < group + 8; i++) @@ -105,7 +105,7 @@ command_di (int argc, char **argv) return command_error; length = (int) end - (int) start + 1; status = ccdbg_read_memory(s51_dbg, start + 0xff00, memory, length); - dump_bytes(memory, length, start); + dump_bytes(memory, length, start, "0x%02x "); return command_success; } @@ -125,7 +125,7 @@ command_ds (int argc, char **argv) return command_error; length = (int) end - (int) start + 1; status = ccdbg_read_sfr(s51_dbg, start, memory, length); - dump_bytes(memory, length, start); + dump_bytes(memory, length, start, "0x%02x "); return command_success; } @@ -145,7 +145,7 @@ command_dx (int argc, char **argv) return command_error; length = (int) end - (int) start + 1; status = ccdbg_read_memory(s51_dbg, start, memory, length); - dump_bytes(memory, length, start); + dump_bytes(memory, length, start, "0x%04x "); return command_success; } @@ -174,6 +174,7 @@ enum command_result command_file (int argc, char **argv) { struct hex_file *hex; + struct hex_image *image; FILE *file; if (argc != 2) @@ -189,7 +190,10 @@ command_file (int argc, char **argv) ccdbg_hex_file_free(hex); return command_error; } - start_address = hex->records[0]->address; + image = ccdbg_hex_image_create(hex); + ccdbg_hex_file_free(hex); + start_address = image->address; + ccdbg_set_rom(s51_dbg, image); return command_success; } @@ -473,6 +477,12 @@ command_halt (int argc, char **argv) return command_success; } +enum command_result +command_stop (int argc, char **argv) +{ + return command_success; +} + enum command_result command_reset (int argc, char **argv) { @@ -511,6 +521,58 @@ command_status(int argc, char **argv) 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) { diff --git a/s51/s51-parse.c b/s51/s51-parse.c index d0bfb45b..749d7bd8 100644 --- a/s51/s51-parse.c +++ b/s51/s51-parse.c @@ -18,14 +18,6 @@ #include "s51.h" -struct command_function { - char *name; - char *alias; - enum command_result (*func)(int argc, char **argv); - char *usage; - char *help; -}; - static struct command_function functions[] = { { "help", "?", command_help, "help", "Print this list\n" }, { "quit", "q", command_quit, "[q]uit", "Quit\n" }, @@ -50,6 +42,8 @@ static struct command_function functions[] = { "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", @@ -62,10 +56,13 @@ static struct command_function functions[] = { "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 }, }; -#define NUM_FUNCTIONS (sizeof functions / sizeof functions[0]) - #ifndef FALSE #define FALSE 0 #define TRUE 1 @@ -106,17 +103,41 @@ string_to_int(char *s, int *v) return TRUE; } -static struct command_function * -command_string_to_function(char *name) +struct command_function * +command_string_to_function(struct command_function *functions, char *name) { int i; - for (i = 0; i < NUM_FUNCTIONS; 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) { @@ -153,28 +174,10 @@ command_split_into_words(char *line, char **argv) enum command_result command_help(int argc, char **argv) { - int i; - struct command_function *func; - - if (argc == 1) { - for (i = 0; i < NUM_FUNCTIONS; i++) - s51_printf("%-10s%s\n", functions[i].name, - functions[i].usage); - } else { - for (i = 1; i < argc; i++) { - func = command_string_to_function(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; + return command_function_help(functions, argc, argv); } -static void +void command_syntax_error(int argc, char **argv) { s51_printf("Syntax error in:"); @@ -206,7 +209,7 @@ command_read (void) s51_interrupted = 0; argc = command_split_into_words(line, argv); if (argc > 0) { - func = command_string_to_function(argv[0]); + func = command_string_to_function(functions, argv[0]); if (!func) command_syntax_error(argc, argv); else diff --git a/s51/s51.h b/s51/s51.h index eab61452..f4dcce66 100644 --- a/s51/s51.h +++ b/s51/s51.h @@ -27,12 +27,32 @@ enum command_result { command_success, command_debug, command_syntax, command_interrupt, command_error, }; +struct command_function { + char *name; + char *alias; + enum command_result (*func)(int argc, char **argv); + char *usage; + char *help; +}; + +struct command_function * +command_string_to_function(struct command_function *functions, char *name); + +enum command_result +command_function_help(struct command_function *functions, int argc, char **argv); + +void +command_syntax_error(int argc, char **argv); + enum command_result command_quit (int argc, char **argv); enum command_result command_help (int argc, char **argv); +enum command_result +command_stop (int argc, char **argv); + enum command_result command_di (int argc, char **argv); @@ -81,6 +101,9 @@ command_reset (int argc, char **argv); enum command_result command_status (int argc, char **argv); +enum command_result +command_info (int argc, char **argv); + enum command_result cc_wait(void); -- cgit v1.2.3 From 60940b4be23962db79b8e914ec943d0636dd68ad Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 5 Jan 2009 21:45:21 -0800 Subject: Expose ccdbg_set_clock API This allows applications to change the debug port clock rate on the fly. Signed-off-by: Keith Packard --- lib/ccdbg-io.c | 12 ++++++++++-- lib/ccdbg.h | 3 +++ 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/ccdbg-io.c b/lib/ccdbg-io.c index 53ea7583..e5e85e43 100644 --- a/lib/ccdbg-io.c +++ b/lib/ccdbg-io.c @@ -24,12 +24,20 @@ #include "cp-usb.h" #endif +static uint32_t cc_clock_us = CC_CLOCK_US; + +void +ccdbg_set_clock(uint32_t us) +{ + cc_clock_us = us; +} + void ccdbg_half_clock(struct ccdbg *dbg) { struct timespec req, rem; - req.tv_sec = (CC_CLOCK_US / 2) / 1000000; - req.tv_nsec = ((CC_CLOCK_US / 2) % 1000000) * 1000; + req.tv_sec = (cc_clock_us / 2) / 1000000; + req.tv_nsec = ((cc_clock_us / 2) % 1000000) * 1000; nanosleep(&req, &rem); } diff --git a/lib/ccdbg.h b/lib/ccdbg.h index 241c4eec..037d8ff5 100644 --- a/lib/ccdbg.h +++ b/lib/ccdbg.h @@ -258,6 +258,9 @@ int ccdbg_hex_image_equal(struct hex_image *a, struct hex_image *b); /* ccdbg-io.c */ +void +ccdbg_set_clock(uint32_t us); + void ccdbg_half_clock(struct ccdbg *dbg); -- cgit v1.2.3 From f7d91bd23b8214e09deae0aafb516331e934c49b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 1 Mar 2009 18:43:03 -0800 Subject: Sometimes the link breaks and the GET_PC command returns garbage --- lib/ccdbg-command.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/ccdbg-command.c b/lib/ccdbg-command.c index 2b29fdee..d99e8ff3 100644 --- a/lib/ccdbg-command.c +++ b/lib/ccdbg-command.c @@ -70,7 +70,14 @@ ccdbg_rd_config(struct ccdbg *dbg) uint16_t ccdbg_get_pc(struct ccdbg *dbg) { - return ccdbg_cmd_write_read16(dbg, CC_GET_PC, NULL, 0); + 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 -- cgit v1.2.3 From cc0495b7028f4b1189a00707d828a68534d1dea2 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 6 Mar 2009 22:52:35 -0800 Subject: Wait for a while when switching the RESET_N line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The cc1111 manual suggests placing a 2.7kΩ resister and 1nF capacitor on the RESET_N line to filter out noise. This increases the time necessary to reset the chip to several microseconds which is longer than the interval between two USB packets. Flush the USB packet queue and sleep for a while after changing the value on the RESET_N line to make sure the chip sees the state change. Signed-off-by: Keith Packard --- lib/ccdbg-command.c | 6 ++++-- lib/ccdbg-io.c | 12 ++++++++++++ lib/ccdbg.h | 9 +++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/ccdbg-command.c b/lib/ccdbg-command.c index d99e8ff3..74313bdf 100644 --- a/lib/ccdbg-command.c +++ b/lib/ccdbg-command.c @@ -27,11 +27,12 @@ ccdbg_debug_mode(struct ccdbg *dbg) ccdbg_debug(CC_DEBUG_COMMAND, "#\n"); ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_DATA ); + ccdbg_wait_reset(dbg); ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_DATA ); ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_DATA|CC_RESET_N); - ccdbg_sync_io(dbg); + ccdbg_wait_reset(dbg); } void @@ -42,11 +43,12 @@ ccdbg_reset(struct ccdbg *dbg) ccdbg_debug(CC_DEBUG_COMMAND, "#\n"); ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); + ccdbg_wait_reset(dbg); ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); - ccdbg_sync_io(dbg); + ccdbg_wait_reset(dbg); } uint8_t diff --git a/lib/ccdbg-io.c b/lib/ccdbg-io.c index e5e85e43..3606c57c 100644 --- a/lib/ccdbg-io.c +++ b/lib/ccdbg-io.c @@ -25,6 +25,7 @@ #endif static uint32_t cc_clock_us = CC_CLOCK_US; +static uint32_t cc_reset_us = CC_RESET_US; void ccdbg_set_clock(uint32_t us) @@ -41,6 +42,17 @@ ccdbg_half_clock(struct ccdbg *dbg) nanosleep(&req, &rem); } +void +ccdbg_wait_reset(struct ccdbg *dbg) +{ + struct timespec req, rem; + + ccdbg_sync_io(dbg); + req.tv_sec = (cc_reset_us) / 1000000; + req.tv_nsec = ((cc_reset_us) % 1000000) * 1000; + nanosleep(&req, &rem); +} + struct ccdbg * ccdbg_open(void) { diff --git a/lib/ccdbg.h b/lib/ccdbg.h index 037d8ff5..8bc9444a 100644 --- a/lib/ccdbg.h +++ b/lib/ccdbg.h @@ -37,6 +37,12 @@ #define CC_RESET_N 0x4 #define CC_CLOCK_US (0) +/* Telemetrum has a 10k pull-up to 3.3v, a 0.001uF cap to ground + * and a 2.7k resistor to the reset line. This takes about 6us + * to settle, so we'll wait longer than that after changing the reset line + */ +#define CC_RESET_US (12) + /* 8051 instructions */ #define NOP 0x00 @@ -264,6 +270,9 @@ ccdbg_set_clock(uint32_t us); void ccdbg_half_clock(struct ccdbg *dbg); +void +ccdbg_wait_reset(struct ccdbg *dbg); + int ccdbg_write(struct ccdbg *dbg, uint8_t mask, uint8_t value); -- cgit v1.2.3 From 5a338c8a7394d003355f96a8777b6fe83bb8493c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 7 Mar 2009 14:48:35 -0800 Subject: Flip debug pins around to match telemetrum --- lib/ccdbg.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/ccdbg.h b/lib/ccdbg.h index 8bc9444a..dbb2a907 100644 --- a/lib/ccdbg.h +++ b/lib/ccdbg.h @@ -32,10 +32,10 @@ #include #include "ccdbg-debug.h" -#define CC_CLOCK 0x1 +#define CC_CLOCK 0x4 #define CC_DATA 0x2 -#define CC_RESET_N 0x4 -#define CC_CLOCK_US (0) +#define CC_RESET_N 0x1 +#define CC_CLOCK_US (1000) /* Telemetrum has a 10k pull-up to 3.3v, a 0.001uF cap to ground * and a 2.7k resistor to the reset line. This takes about 6us -- cgit v1.2.3 From 77d754afc2d14aaa4413c13ebe3777ef385f62a9 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 7 Mar 2009 14:48:49 -0800 Subject: Sync after manual bit reading --- lib/ccdbg-manual.c | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/ccdbg-manual.c b/lib/ccdbg-manual.c index b48f8bb1..4bbf0879 100644 --- a/lib/ccdbg-manual.c +++ b/lib/ccdbg-manual.c @@ -60,6 +60,7 @@ ccdbg_manual(struct ccdbg *dbg, FILE *input) if (mask != (CC_CLOCK|CC_DATA|CC_RESET_N)) { uint8_t read; ccdbg_read(dbg, &read); + ccdbg_sync_io(dbg); ccdbg_print("\t%c %c %c", CC_CLOCK|CC_DATA|CC_RESET_N, read); if ((set & CC_CLOCK) == 0) printf ("\t%d", (read&CC_DATA) ? 1 : 0); -- cgit v1.2.3 From ade11f88754b4ab0386ebf86afc5257e59238f62 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 7 Mar 2009 21:04:38 -0800 Subject: Make manual bit flipping sync after every transaction --- lib/ccdbg-manual.c | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/ccdbg-manual.c b/lib/ccdbg-manual.c index 4bbf0879..df79d88d 100644 --- a/lib/ccdbg-manual.c +++ b/lib/ccdbg-manual.c @@ -67,5 +67,6 @@ ccdbg_manual(struct ccdbg *dbg, FILE *input) printf ("\n"); } ccdbg_send(dbg, mask, set); + ccdbg_sync_io(dbg); } } -- cgit v1.2.3 From c8fd04e154bcfd65ae1200980bd8163caabd7fe4 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 7 Mar 2009 21:05:06 -0800 Subject: The debug port only works if reset is higher than clock. weird --- lib/ccdbg.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/ccdbg.h b/lib/ccdbg.h index dbb2a907..f6e216c4 100644 --- a/lib/ccdbg.h +++ b/lib/ccdbg.h @@ -32,9 +32,9 @@ #include #include "ccdbg-debug.h" -#define CC_CLOCK 0x4 +#define CC_CLOCK 0x1 #define CC_DATA 0x2 -#define CC_RESET_N 0x1 +#define CC_RESET_N 0x4 #define CC_CLOCK_US (1000) /* Telemetrum has a 10k pull-up to 3.3v, a 0.001uF cap to ground -- cgit v1.2.3 From 9fd63972758d6d5572f7bcaadec9b1c0e974a2e8 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 7 Mar 2009 21:05:40 -0800 Subject: Only flip changing bits in async mode --- lib/cp-usb-async.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/cp-usb-async.c b/lib/cp-usb-async.c index 3f5f76ab..1fe09aad 100644 --- a/lib/cp-usb-async.c +++ b/lib/cp-usb-async.c @@ -38,6 +38,8 @@ struct cp_usb_async { libusb_device_handle *handle; struct cp_usb_packet packet[MAX_OUTSTANDING]; int p, ack; + uint8_t value; + uint8_t set; }; struct cp_usb_async * @@ -56,11 +58,14 @@ cp_usb_async_open(void) } 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; } @@ -103,9 +108,16 @@ void cp_usb_async_write(struct cp_usb_async *cp, uint8_t mask, uint8_t value) { int p; - uint16_t gpio_set = ((uint16_t) value << 8) | mask; + 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; @@ -172,5 +184,5 @@ cp_usb_async_sync(struct cp_usb_async *cp) libusb_handle_events(cp->ctx); } cp->p = 0; - cp->ack = 0; + cp->ack = -1; } -- cgit v1.2.3 From 04a316133af93b79bfbebb91f05eec1015ec2abc Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 15 Mar 2009 18:10:43 -0700 Subject: Bump debug speed back up --- lib/ccdbg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/ccdbg.h b/lib/ccdbg.h index f6e216c4..e0e12c8b 100644 --- a/lib/ccdbg.h +++ b/lib/ccdbg.h @@ -35,7 +35,7 @@ #define CC_CLOCK 0x1 #define CC_DATA 0x2 #define CC_RESET_N 0x4 -#define CC_CLOCK_US (1000) +#define CC_CLOCK_US (2) /* Telemetrum has a 10k pull-up to 3.3v, a 0.001uF cap to ground * and a 2.7k resistor to the reset line. This takes about 6us -- cgit v1.2.3 From 2d9b8a83a2d9f495199033e43f519d26f27938fe Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 6 Apr 2009 11:31:49 -0700 Subject: Add support for a serial-connected custom debug dongle This uses the cc1111 board as a custom debug dongle with faster methods for communicating with the debug target. --- lib/Makefile.am | 4 + lib/cc-bitbang.c | 270 +++++++++++++++++++++++++++++++++++++++ lib/cc-bitbang.h | 94 ++++++++++++++ lib/cc-usb.c | 355 ++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/cc-usb.h | 53 ++++++++ lib/ccdbg-command.c | 52 +++----- lib/ccdbg-debug.c | 9 ++ lib/ccdbg-io.c | 213 ++++++++----------------------- lib/ccdbg-manual.c | 15 ++- lib/ccdbg-memory.c | 4 + lib/ccdbg.h | 88 +++---------- lib/cp-usb.c | 1 + 12 files changed, 885 insertions(+), 273 deletions(-) create mode 100644 lib/cc-bitbang.c create mode 100644 lib/cc-bitbang.h create mode 100644 lib/cc-usb.c create mode 100644 lib/cc-usb.h (limited to 'lib') diff --git a/lib/Makefile.am b/lib/Makefile.am index ba6f9725..4d9ded3a 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -13,5 +13,9 @@ libcc_a_SOURCES = \ ccdbg-memory.c \ ccdbg-rom.c \ ccdbg-state.c \ + cc-usb.c \ + cc-usb.h \ + cc-bitbang.c \ + cc-bitbang.h \ cp-usb.c \ cp-usb-async.c diff --git a/lib/cc-bitbang.c b/lib/cc-bitbang.c new file mode 100644 index 00000000..a5d2d369 --- /dev/null +++ b/lib/cc-bitbang.c @@ -0,0 +1,270 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include +#include +#include "ccdbg-debug.h" +#include "cc-bitbang.h" + +#define CP_USB_ASYNC + +#ifdef CP_USB_ASYNC +#include "cp-usb-async.h" +#else +#include "cp-usb.h" +#endif + +struct cc_bitbang { +#ifdef CP_USB_ASYNC + struct cp_usb_async *cp_async; +#else + struct cp_usb *cp; +#endif +}; + +static uint32_t cc_clock_us = CC_CLOCK_US; +static uint32_t cc_reset_us = CC_RESET_US; + +void +cc_bitbang_set_clock(uint32_t us) +{ + cc_clock_us = us; +} + +void +cc_bitbang_half_clock(struct cc_bitbang *bb) +{ + struct timespec req, rem; + req.tv_sec = (cc_clock_us / 2) / 1000000; + req.tv_nsec = ((cc_clock_us / 2) % 1000000) * 1000; + nanosleep(&req, &rem); +} + +void +cc_bitbang_wait_reset(struct cc_bitbang *bb) +{ + struct timespec req, rem; + + cc_bitbang_sync(bb); + req.tv_sec = (cc_reset_us) / 1000000; + req.tv_nsec = ((cc_reset_us) % 1000000) * 1000; + nanosleep(&req, &rem); +} + +struct cc_bitbang * +cc_bitbang_open(void) +{ + struct cc_bitbang *bb; + + bb = calloc(sizeof (struct cc_bitbang), 1); + if (!bb) { + perror("calloc"); + return NULL; + } +#ifdef CP_USB_ASYNC + bb->cp_async = cp_usb_async_open(); + if (!bb->cp_async) { + free (bb); + return NULL; + } +#else + bb->cp = cp_usb_open (); + if (!bb->cp) { + free (bb); + return NULL; + } +#endif + return bb; +} + +void +cc_bitbang_close(struct cc_bitbang *bb) +{ +#ifdef CP_USB_ASYNC + cp_usb_async_close(bb->cp_async); +#else + cp_usb_close(bb->cp); +#endif + free (bb); +} + +void +cc_bitbang_debug_mode(struct cc_bitbang *bb) +{ + /* force two rising clocks while holding RESET_N low */ + ccdbg_debug(CC_DEBUG_COMMAND, "#\n"); + ccdbg_debug(CC_DEBUG_COMMAND, "# Debug mode\n"); + ccdbg_debug(CC_DEBUG_COMMAND, "#\n"); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_DATA ); + cc_bitbang_wait_reset(bb); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_DATA ); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_DATA|CC_RESET_N); + cc_bitbang_wait_reset(bb); +} + +void +cc_bitbang_reset(struct cc_bitbang *bb) +{ + ccdbg_debug(CC_DEBUG_COMMAND, "#\n"); + ccdbg_debug(CC_DEBUG_COMMAND, "# Reset\n"); + ccdbg_debug(CC_DEBUG_COMMAND, "#\n"); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); + cc_bitbang_wait_reset(bb); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); + cc_bitbang_wait_reset(bb); +} + +int +cc_bitbang_write(struct cc_bitbang *bb, uint8_t mask, uint8_t value) +{ +#ifdef CP_USB_ASYNC + cp_usb_async_write(bb->cp_async, mask, value); +#else + cp_usb_write(bb->cp, mask, value); +#endif + return 0; +} + +void +cc_bitbang_read(struct cc_bitbang *bb, uint8_t *valuep) +{ +#ifdef CP_USB_ASYNC + cp_usb_async_read(bb->cp_async, valuep); +#else + *valuep = cp_usb_read(bb->cp); +#endif +} + +void +cc_bitbang_sync(struct cc_bitbang *bb) +{ +#ifdef CP_USB_ASYNC + cp_usb_async_sync(bb->cp_async); +#endif +} + +static char +is_bit(uint8_t get, uint8_t mask, char on, uint8_t bit) +{ + if (mask&bit) { + if (get&bit) + return on; + else + return '.'; + } else + return '-'; +} + +void +cc_bitbang_print(char *format, uint8_t mask, uint8_t set) +{ + ccdbg_debug (CC_DEBUG_BITBANG, format, + is_bit(set, mask, 'C', CC_CLOCK), + is_bit(set, mask, 'D', CC_DATA), + is_bit(set, mask, 'R', CC_RESET_N)); +} + +void +cc_bitbang_send(struct cc_bitbang *bb, uint8_t mask, uint8_t set) +{ + cc_bitbang_write(bb, mask, set); + cc_bitbang_print("%c %c %c\n", mask, set); + cc_bitbang_half_clock(bb); +} + +void +cc_bitbang_send_bit(struct cc_bitbang *bb, uint8_t bit) +{ + if (bit) bit = CC_DATA; + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|bit|CC_RESET_N); + cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, bit|CC_RESET_N); +} + +void +cc_bitbang_send_byte(struct cc_bitbang *bb, uint8_t byte) +{ + int bit; + ccdbg_debug(CC_DEBUG_BITBANG, "#\n# Send Byte 0x%02x\n#\n", byte); + for (bit = 7; bit >= 0; bit--) { + cc_bitbang_send_bit(bb, (byte >> bit) & 1); + if (bit == 3) + ccdbg_debug(CC_DEBUG_BITBANG, "\n"); + } + cc_bitbang_sync(bb); +} + +void +cc_bitbang_send_bytes(struct cc_bitbang *bb, uint8_t *bytes, int nbytes) +{ + while (nbytes--) + cc_bitbang_send_byte(bb, *bytes++); +} + +void +cc_bitbang_recv_bit(struct cc_bitbang *bb, int first, uint8_t *bit) +{ + uint8_t mask = first ? CC_DATA : 0; + + cc_bitbang_send(bb, CC_CLOCK|mask|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); + cc_bitbang_read(bb, bit); + cc_bitbang_send(bb, CC_CLOCK| CC_RESET_N, CC_RESET_N); +} + +void +cc_bitbang_recv_byte(struct cc_bitbang *bb, int first, uint8_t *bytep) +{ + uint8_t byte = 0; + uint8_t bits[8]; + int bit; + + ccdbg_debug(CC_DEBUG_BITBANG, "#\n# Recv byte\n#\n"); + for (bit = 0; bit < 8; bit++) { + cc_bitbang_recv_bit(bb, first, &bits[bit]); + first = 0; + } + cc_bitbang_sync(bb); + for (bit = 0; bit < 8; bit++) { + byte = byte << 1; + byte |= (bits[bit] & CC_DATA) ? 1 : 0; + cc_bitbang_print("#\t%c %c %c\n", CC_DATA, bits[bit]); + if (bit == 3) + ccdbg_debug(CC_DEBUG_BITBANG, "\n"); + } + ccdbg_debug(CC_DEBUG_BITBANG, "#\n# Recv 0x%02x\n#\n", byte); + *bytep = byte; +} + +void +cc_bitbang_recv_bytes(struct cc_bitbang *bb, uint8_t *bytes, int nbytes) +{ + int i; + int first = 1; + for (i = 0; i < nbytes; i++) { + cc_bitbang_recv_byte(bb, first, &bytes[i]); + first = 0; + } +} + diff --git a/lib/cc-bitbang.h b/lib/cc-bitbang.h new file mode 100644 index 00000000..54b20e2c --- /dev/null +++ b/lib/cc-bitbang.h @@ -0,0 +1,94 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _CC_BITBANG_H_ +#define _CC_BITBANG_H_ + +#include + +#define CC_CLOCK 0x1 +#define CC_DATA 0x2 +#define CC_RESET_N 0x4 +#define CC_CLOCK_US (2) + +/* Telemetrum has a 10k pull-up to 3.3v, a 0.001uF cap to ground + * and a 2.7k resistor to the reset line. This takes about 6us + * to settle, so we'll wait longer than that after changing the reset line + */ +#define CC_RESET_US (12) + +struct cc_bitbang; + +void +cc_bitbang_set_clock(uint32_t us); + +void +cc_bitbang_half_clock(struct cc_bitbang *bb); + +void +cc_bitbang_wait_reset(struct cc_bitbang *bb); + +struct cc_bitbang * +cc_bitbang_open(void); + +void +cc_bitbang_close(struct cc_bitbang *bb); + +void +cc_bitbang_debug_mode(struct cc_bitbang *bb); + +void +cc_bitbang_reset(struct cc_bitbang *bb); + +int +cc_bitbang_write(struct cc_bitbang *bb, uint8_t mask, uint8_t value); + +void +cc_bitbang_read(struct cc_bitbang *bb, uint8_t *valuep); + +void +cc_bitbang_sync(struct cc_bitbang *bb); + +void +cc_bitbang_print(char *format, uint8_t mask, uint8_t set); + +void +cc_bitbang_print(char *format, uint8_t mask, uint8_t set); + +void +cc_bitbang_send(struct cc_bitbang *bb, uint8_t mask, uint8_t set); + +void +cc_bitbang_send_bit(struct cc_bitbang *bb, uint8_t bit); + +void +cc_bitbang_send_byte(struct cc_bitbang *bb, uint8_t byte); + +void +cc_bitbang_send_bytes(struct cc_bitbang *bb, uint8_t *bytes, int nbytes); + +void +cc_bitbang_recv_bit(struct cc_bitbang *bb, int first, uint8_t *bit); + +void +cc_bitbang_recv_byte(struct cc_bitbang *bb, int first, uint8_t *bytep); + +void +cc_bitbang_recv_bytes(struct cc_bitbang *bb, uint8_t *bytes, int nbytes); + +#endif /* _CC_BITBANG_H_ */ diff --git a/lib/cc-usb.c b/lib/cc-usb.c new file mode 100644 index 00000000..a85765af --- /dev/null +++ b/lib/cc-usb.c @@ -0,0 +1,355 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ccdbg-debug.h" +#include "cc-usb.h" + + +#define CC_NUM_READ 16 +#define CC_BUF 1024 +#define DEFAULT_TTY "/dev/ttyACM0" + +struct cc_read { + uint8_t *buf; + int len; +}; + +struct cc_usb { + int fd; + uint8_t in_buf[CC_BUF]; + int in_count; + uint8_t out_buf[CC_BUF]; + int out_count; + struct cc_read read_buf[CC_NUM_READ]; + int read_count; +}; + +#define NOT_HEX 0xff + +static uint8_t +cc_hex_nibble(uint8_t c) +{ + if ('0' <= c && c <= '9') + return c - '0'; + if ('a' <= c && c <= 'f') + return c - 'a' + 10; + if ('A' <= c && c <= 'F') + return c - 'A' + 10; + return NOT_HEX; +} + +/* + * Take raw input bytes, parse them as hex + * and write them to the waiting buffer + */ +static void +cc_handle_in(struct cc_usb *cc) +{ + uint8_t h, l; + int in_pos; + int read_pos; + + in_pos = 0; + read_pos = 0; + while (read_pos < cc->read_count && in_pos < cc->in_count) { + /* + * Skip to next hex character + */ + while (in_pos < cc->in_count && + cc_hex_nibble(cc->in_buf[in_pos]) == NOT_HEX) + in_pos++; + /* + * Make sure we have two characters left + */ + if (cc->in_count - in_pos < 2) + break; + /* + * Parse hex number + */ + h = cc_hex_nibble(cc->in_buf[in_pos]); + l = cc_hex_nibble(cc->in_buf[in_pos+1]); + if (h == NOT_HEX || l == NOT_HEX) { + fprintf(stderr, "hex read error\n"); + break; + } + in_pos += 2; + /* + * Store hex number + */ + *cc->read_buf[read_pos].buf++ = (h << 4) | l; + if (--cc->read_buf[read_pos].len <= 0) + read_pos++; + } + + /* Move remaining bytes to the start of the input buffer */ + if (in_pos) { + memmove(cc->in_buf, cc->in_buf + in_pos, + cc->in_count - in_pos); + cc->in_count -= in_pos; + } + + /* Move pending reads to the start of the array */ + if (read_pos) { + memmove(cc->read_buf, cc->read_buf + read_pos, + (cc->read_count - read_pos) * sizeof (cc->read_buf[0])); + cc->read_count -= read_pos; + } + + /* Once we're done reading, flush any pending input */ + if (cc->read_count == 0) + cc->in_count = 0; +} + +static void +cc_usb_dbg(int indent, uint8_t *bytes, int len) +{ + int eol = 1; + int i; + uint8_t c; + while (len--) { + c = *bytes++; + if (eol) { + for (i = 0; i < indent; i++) + ccdbg_debug(CC_DEBUG_BITBANG, " "); + eol = 0; + } + switch (c) { + case '\r': + ccdbg_debug(CC_DEBUG_BITBANG, "^M"); + break; + case '\n': + eol = 1; + default: + ccdbg_debug(CC_DEBUG_BITBANG, "%c", c); + } + } +} + +/* + * Flush pending writes, fill pending reads + */ +void +cc_usb_sync(struct cc_usb *cc) +{ + int ret; + struct pollfd fds; + int timeout; + + fds.fd = cc->fd; + for (;;) { + if (cc->read_count || cc->out_count) + timeout = -1; + else + timeout = 0; + fds.events = 0; + if (cc->in_count < CC_BUF) + fds.events |= POLLIN; + if (cc->out_count) + fds.events |= POLLOUT; + ret = poll(&fds, 1, timeout); + if (ret == 0) + break; + if (ret < 0) { + perror("poll"); + break; + } + if (fds.revents & POLLIN) { + ret = read(cc->fd, cc->in_buf + cc->in_count, + CC_BUF - cc->in_count); + if (ret > 0) { + cc_usb_dbg(24, cc->in_buf + cc->in_count, ret); + cc->in_count += ret; + cc_handle_in(cc); + } + } + if (fds.revents & POLLOUT) { + ret = write(cc->fd, cc->out_buf, + cc->out_count); + if (ret > 0) { + cc_usb_dbg(0, cc->out_buf, ret); + memmove(cc->out_buf, + cc->out_buf + ret, + cc->out_count - ret); + cc->out_count -= ret; + } + } + } +} + +static void +cc_usb_printf(struct cc_usb *cc, char *format, ...) +{ + char buf[1024], *b; + va_list ap; + int ret, this_time; + + /* sprintf to a local buffer */ + va_start(ap, format); + ret = vsnprintf(buf, sizeof(buf), format, ap); + va_end(ap); + if (ret > sizeof(buf)) { + fprintf(stderr, "printf overflow for format %s\n", + format); + } + + /* flush local buffer to the wire */ + b = buf; + while (ret > 0) { + this_time = ret; + if (this_time > CC_BUF - cc->out_count) + this_time = CC_BUF - cc->out_count; + memcpy(cc->out_buf + cc->out_count, b, this_time); + cc->out_count += this_time; + ret -= this_time; + while (cc->out_count >= CC_BUF) + cc_usb_sync(cc); + } +} + +int +cc_usb_send_bytes(struct cc_usb *cc, uint8_t *bytes, int len) +{ + int this_len; + int ret = len; + + while (len) { + this_len = len; + if (this_len > 8) + this_len = 8; + len -= this_len; + cc_usb_printf(cc, "P"); + while (this_len--) + cc_usb_printf (cc, " %02x", (*bytes++) & 0xff); + cc_usb_printf(cc, "\n"); + } + return ret; +} + +static void +cc_queue_read(struct cc_usb *cc, uint8_t *buf, int len) +{ + struct cc_read *read_buf; + while (cc->read_count >= CC_NUM_READ) + cc_usb_sync(cc); + read_buf = &cc->read_buf[cc->read_count++]; + read_buf->buf = buf; + read_buf->len = len; +} + +int +cc_usb_recv_bytes(struct cc_usb *cc, uint8_t *buf, int len) +{ + cc_queue_read(cc, buf, len); + cc_usb_printf(cc, "G %x\n", len); + return len; +} + +int +cc_usb_write_memory(struct cc_usb *cc, uint16_t addr, uint8_t *bytes, int len) +{ + cc_usb_printf(cc, "O %x %x\n", len, addr); + while (len--) + cc_usb_printf(cc, "%02x", *bytes++); + return 0; +} + +int +cc_usb_read_memory(struct cc_usb *cc, uint16_t addr, uint8_t *bytes, int len) +{ + int i; + cc_queue_read(cc, bytes, len); + cc_usb_printf(cc, "I %x %x\n", len, addr); + cc_usb_sync(cc); + for (i = 0; i < len; i++) { + if ((i & 15) == 0) { + if (i) + ccdbg_debug(CC_DEBUG_MEMORY, "\n"); + ccdbg_debug(CC_DEBUG_MEMORY, "\t%04x", addr + i); + } + ccdbg_debug(CC_DEBUG_MEMORY, " %02x", bytes[i]); + } + ccdbg_debug(CC_DEBUG_MEMORY, "\n"); + return 0; +} + +int +cc_usb_debug_mode(struct cc_usb *cc) +{ + cc_usb_sync(cc); + cc_usb_printf(cc, "D\n"); + return 1; +} + +int +cc_usb_reset(struct cc_usb *cc) +{ + cc_usb_sync(cc); + cc_usb_printf(cc, "R\n"); + return 1; +} + +static struct termios save_termios; + +struct cc_usb * +cc_usb_open(void) +{ + struct cc_usb *cc; + char *tty; + struct termios termios; + + tty = getenv("CCDBG_TTY"); + if (!tty) + tty = DEFAULT_TTY; + cc = calloc (sizeof (struct cc_usb), 1); + if (!cc) + return NULL; + cc->fd = open(tty, O_RDWR | O_NONBLOCK); + if (cc->fd < 0) { + perror(tty); + free (cc); + return NULL; + } + tcgetattr(cc->fd, &termios); + save_termios = termios; + cfmakeraw(&termios); + tcsetattr(cc->fd, TCSAFLUSH, &termios); + cc_usb_printf(cc, "E 0\n"); + cc_usb_sync(cc); + sleep(1); + cc_usb_sync(cc); + return cc; +} + +void +cc_usb_close(struct cc_usb *cc) +{ + tcsetattr(cc->fd, TCSAFLUSH, &save_termios); + close (cc->fd); + free (cc); +} + diff --git a/lib/cc-usb.h b/lib/cc-usb.h new file mode 100644 index 00000000..235e9918 --- /dev/null +++ b/lib/cc-usb.h @@ -0,0 +1,53 @@ +/* + * Copyright © 2009 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _CC_USB_H_ +#define _CC_USB_H_ + +#include + +struct cc_usb; + +struct cc_usb * +cc_usb_open(void); + +void +cc_usb_close(struct cc_usb *cc); + +int +cc_usb_send_bytes(struct cc_usb *cc, uint8_t *bytes, int len); + +int +cc_usb_recv_bytes(struct cc_usb *cc, uint8_t *bytes, int len); + +int +cc_usb_write_memory(struct cc_usb *cc, uint16_t addr, uint8_t *bytes, int len); + +int +cc_usb_read_memory(struct cc_usb *cc, uint16_t addr, uint8_t *bytes, int len); + +int +cc_usb_debug_mode(struct cc_usb *cc); + +int +cc_usb_reset(struct cc_usb *cc); + +void +cc_usb_sync(struct cc_usb *cc); + +#endif /* _CC_USB_H_ */ diff --git a/lib/ccdbg-command.c b/lib/ccdbg-command.c index 74313bdf..7d1ae067 100644 --- a/lib/ccdbg-command.c +++ b/lib/ccdbg-command.c @@ -18,39 +18,6 @@ #include "ccdbg.h" -void -ccdbg_debug_mode(struct ccdbg *dbg) -{ - /* force two rising clocks while holding RESET_N low */ - ccdbg_debug(CC_DEBUG_COMMAND, "#\n"); - ccdbg_debug(CC_DEBUG_COMMAND, "# Debug mode\n"); - ccdbg_debug(CC_DEBUG_COMMAND, "#\n"); - ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); - ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_DATA ); - ccdbg_wait_reset(dbg); - ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); - ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_DATA ); - ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); - ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_DATA|CC_RESET_N); - ccdbg_wait_reset(dbg); -} - -void -ccdbg_reset(struct ccdbg *dbg) -{ - ccdbg_debug(CC_DEBUG_COMMAND, "#\n"); - ccdbg_debug(CC_DEBUG_COMMAND, "# Reset\n"); - ccdbg_debug(CC_DEBUG_COMMAND, "#\n"); - ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); - ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); - ccdbg_wait_reset(dbg); - ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); - ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); - ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA ); - ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); - ccdbg_wait_reset(dbg); -} - uint8_t ccdbg_chip_erase(struct ccdbg *dbg) { @@ -117,6 +84,22 @@ ccdbg_debug_instr(struct ccdbg *dbg, uint8_t *instr, int nbytes) return ccdbg_cmd_write_read8(dbg, CC_DEBUG_INSTR(nbytes), instr, nbytes); } +void +ccdbg_debug_instr_discard(struct ccdbg *dbg, uint8_t *instr, int nbytes) +{ + static uint8_t discard; + ccdbg_cmd_write_queue8(dbg, CC_DEBUG_INSTR(nbytes), + instr, nbytes, &discard); +} + +void +ccdbg_debug_instr_queue(struct ccdbg *dbg, uint8_t *instr, int nbytes, + uint8_t *reply) +{ + return ccdbg_cmd_write_queue8(dbg, CC_DEBUG_INSTR(nbytes), + instr, nbytes, reply); +} + uint8_t ccdbg_step_instr(struct ccdbg *dbg) { @@ -148,12 +131,13 @@ ccdbg_execute(struct ccdbg *dbg, uint8_t *inst) ccdbg_debug(CC_DEBUG_INSTRUCTIONS, "\t%02x", inst[1]); for (i = 0; i < len - 1; i++) ccdbg_debug(CC_DEBUG_INSTRUCTIONS, " %02x", inst[i+2]); - status = ccdbg_debug_instr(dbg, inst+1, len); + ccdbg_debug_instr_queue(dbg, inst+1, len, &status); for (; i < 3; i++) ccdbg_debug(CC_DEBUG_INSTRUCTIONS, " "); ccdbg_debug(CC_DEBUG_INSTRUCTIONS, " -> %02x\n", status); inst += len + 1; } + ccdbg_sync(dbg); return status; } diff --git a/lib/ccdbg-debug.c b/lib/ccdbg-debug.c index 847361c7..6eb4e0c5 100644 --- a/lib/ccdbg-debug.c +++ b/lib/ccdbg-debug.c @@ -34,11 +34,20 @@ ccdbg_clear_debug(int level) ccdbg_level &= ~level; } +static int initialized; + void ccdbg_debug(int level, char *format, ...) { va_list ap; + if (!initialized) { + char *level; + initialized = 1; + level = getenv("CCDEBUG"); + if (level) + ccdbg_level |= strtoul(level, NULL, 0); + } if (ccdbg_level & level) { va_start(ap, format); vprintf(format, ap); diff --git a/lib/ccdbg-io.c b/lib/ccdbg-io.c index 3606c57c..acd44f10 100644 --- a/lib/ccdbg-io.c +++ b/lib/ccdbg-io.c @@ -18,41 +18,10 @@ #include "ccdbg.h" #include -#ifdef CP_USB_ASYNC -#include "cp-usb-async.h" -#else -#include "cp-usb.h" -#endif +#include "cc-usb.h" +#include "cc-bitbang.h" -static uint32_t cc_clock_us = CC_CLOCK_US; -static uint32_t cc_reset_us = CC_RESET_US; -void -ccdbg_set_clock(uint32_t us) -{ - cc_clock_us = us; -} - -void -ccdbg_half_clock(struct ccdbg *dbg) -{ - struct timespec req, rem; - req.tv_sec = (cc_clock_us / 2) / 1000000; - req.tv_nsec = ((cc_clock_us / 2) % 1000000) * 1000; - nanosleep(&req, &rem); -} - -void -ccdbg_wait_reset(struct ccdbg *dbg) -{ - struct timespec req, rem; - - ccdbg_sync_io(dbg); - req.tv_sec = (cc_reset_us) / 1000000; - req.tv_nsec = ((cc_reset_us) % 1000000) * 1000; - nanosleep(&req, &rem); -} - struct ccdbg * ccdbg_open(void) { @@ -63,170 +32,77 @@ ccdbg_open(void) perror("calloc"); return NULL; } -#ifdef CP_USB_ASYNC - dbg->cp_async = cp_usb_async_open(); - if (!dbg->cp_async) { - free (dbg); - return NULL; - } -#else - dbg->cp = cp_usb_open (); - if (!dbg->cp) { - free (dbg); - return NULL; + dbg->usb = cc_usb_open(); + if (!dbg->usb) { + dbg->bb = cc_bitbang_open(); + if (!dbg->bb) { + free(dbg); + return NULL; + } } -#endif return dbg; } void ccdbg_close(struct ccdbg *dbg) { -#ifdef CP_USB_ASYNC - cp_usb_async_close(dbg->cp_async); -#else - cp_usb_close(dbg->cp); -#endif + if (dbg->usb) + cc_usb_close(dbg->usb); + if (dbg->bb) + cc_bitbang_close(dbg->bb); free (dbg); } -int -ccdbg_write(struct ccdbg *dbg, uint8_t mask, uint8_t value) -{ -#ifdef CP_USB_ASYNC - cp_usb_async_write(dbg->cp_async, mask, value); -#else - cp_usb_write(dbg->cp, mask, value); -#endif - return 0; -} - -void -ccdbg_read(struct ccdbg *dbg, uint8_t *valuep) -{ -#ifdef CP_USB_ASYNC - cp_usb_async_read(dbg->cp_async, valuep); -#else - *valuep = cp_usb_read(dbg->cp); -#endif -} - -void -ccdbg_sync_io(struct ccdbg *dbg) -{ -#ifdef CP_USB_ASYNC - cp_usb_async_sync(dbg->cp_async); -#endif -} - -static char -is_bit(uint8_t get, uint8_t mask, char on, uint8_t bit) -{ - if (mask&bit) { - if (get&bit) - return on; - else - return '.'; - } else - return '-'; -} -void -ccdbg_print(char *format, uint8_t mask, uint8_t set) -{ - ccdbg_debug (CC_DEBUG_BITBANG, format, - is_bit(set, mask, 'C', CC_CLOCK), - is_bit(set, mask, 'D', CC_DATA), - is_bit(set, mask, 'R', CC_RESET_N)); -} - void -ccdbg_send(struct ccdbg *dbg, uint8_t mask, uint8_t set) +ccdbg_debug_mode(struct ccdbg *dbg) { - ccdbg_write(dbg, mask, set); - ccdbg_print("%c %c %c\n", mask, set); - ccdbg_half_clock(dbg); + if (dbg->usb) + cc_usb_debug_mode(dbg->usb); + else if (dbg->bb) + cc_bitbang_debug_mode(dbg->bb); } void -ccdbg_send_bit(struct ccdbg *dbg, uint8_t bit) +ccdbg_reset(struct ccdbg *dbg) { - if (bit) bit = CC_DATA; - ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|bit|CC_RESET_N); - ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, bit|CC_RESET_N); -} - -void -ccdbg_send_byte(struct ccdbg *dbg, uint8_t byte) -{ - int bit; - ccdbg_debug(CC_DEBUG_BITBANG, "#\n# Send Byte 0x%02x\n#\n", byte); - for (bit = 7; bit >= 0; bit--) { - ccdbg_send_bit(dbg, (byte >> bit) & 1); - if (bit == 3) - ccdbg_debug(CC_DEBUG_BITBANG, "\n"); - } - ccdbg_sync_io(dbg); + if (dbg->usb) + cc_usb_reset(dbg->usb); + else if (dbg->bb) + cc_bitbang_reset(dbg->bb); } void ccdbg_send_bytes(struct ccdbg *dbg, uint8_t *bytes, int nbytes) { - while (nbytes--) - ccdbg_send_byte(dbg, *bytes++); -} - -void -ccdbg_recv_bit(struct ccdbg *dbg, int first, uint8_t *bit) -{ - uint8_t mask = first ? CC_DATA : 0; - - ccdbg_send(dbg, CC_CLOCK|mask|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); - ccdbg_read(dbg, bit); - ccdbg_send(dbg, CC_CLOCK| CC_RESET_N, CC_RESET_N); + if (dbg->usb) + cc_usb_send_bytes(dbg->usb, bytes, nbytes); + else if (dbg->bb) + cc_bitbang_send_bytes(dbg->bb, bytes, nbytes); } void -ccdbg_recv_byte(struct ccdbg *dbg, int first, uint8_t *bytep) +ccdbg_recv_bytes(struct ccdbg *dbg, uint8_t *bytes, int nbytes) { - uint8_t byte = 0; - uint8_t bits[8]; - int bit; - - ccdbg_debug(CC_DEBUG_BITBANG, "#\n# Recv byte\n#\n"); - for (bit = 0; bit < 8; bit++) { - ccdbg_recv_bit(dbg, first, &bits[bit]); - first = 0; - } - ccdbg_sync_io(dbg); - for (bit = 0; bit < 8; bit++) { - byte = byte << 1; - byte |= (bits[bit] & CC_DATA) ? 1 : 0; - ccdbg_print("#\t%c %c %c\n", CC_DATA, bits[bit]); - if (bit == 3) - ccdbg_debug(CC_DEBUG_BITBANG, "\n"); - } - ccdbg_debug(CC_DEBUG_BITBANG, "#\n# Recv 0x%02x\n#\n", byte); - *bytep = byte; + if (dbg->usb) + cc_usb_recv_bytes(dbg->usb, bytes, nbytes); + else if (dbg->bb) + cc_bitbang_recv_bytes(dbg->bb, bytes, nbytes); } void -ccdbg_recv_bytes(struct ccdbg *dbg, uint8_t *bytes, int nbytes) +ccdbg_sync(struct ccdbg *dbg) { - int i; - int first = 1; - for (i = 0; i < nbytes; i++) { - ccdbg_recv_byte(dbg, first, &bytes[i]); - first = 0; - } + if (dbg->usb) + cc_usb_sync(dbg->usb); + else if (dbg->bb) + cc_bitbang_sync(dbg->bb); } void ccdbg_cmd_write(struct ccdbg *dbg, uint8_t cmd, uint8_t *data, int len) { - int i; - ccdbg_send_byte(dbg, cmd); - for (i = 0; i < len; i++) - ccdbg_send_byte(dbg, data[i]); + ccdbg_send_bytes(dbg, &cmd, 1); + ccdbg_send_bytes(dbg, data, len); } uint8_t @@ -235,6 +111,7 @@ ccdbg_cmd_write_read8(struct ccdbg *dbg, uint8_t cmd, uint8_t *data, int len) uint8_t byte[1]; ccdbg_cmd_write(dbg, cmd, data, len); ccdbg_recv_bytes(dbg, byte, 1); + ccdbg_sync(dbg); return byte[0]; } @@ -244,5 +121,15 @@ ccdbg_cmd_write_read16(struct ccdbg *dbg, uint8_t cmd, uint8_t *data, int len) uint8_t byte[2]; ccdbg_cmd_write(dbg, cmd, data, len); ccdbg_recv_bytes(dbg, byte, 2); + ccdbg_sync(dbg); return (byte[0] << 8) | byte[1]; } + +void +ccdbg_cmd_write_queue8(struct ccdbg *dbg, uint8_t cmd, + uint8_t *data, int len, + uint8_t *reply) +{ + ccdbg_cmd_write(dbg, cmd, data, len); + ccdbg_recv_bytes(dbg, reply, 1); +} diff --git a/lib/ccdbg-manual.c b/lib/ccdbg-manual.c index df79d88d..0e811b76 100644 --- a/lib/ccdbg-manual.c +++ b/lib/ccdbg-manual.c @@ -17,6 +17,7 @@ */ #include "ccdbg.h" +#include "cc-bitbang.h" /* * Manual bit-banging to debug the low level protocol @@ -47,6 +48,10 @@ ccdbg_manual(struct ccdbg *dbg, FILE *input) char line[80]; uint8_t set, mask; + if (dbg->bb == NULL) { + fprintf(stderr, "Must use bitbang API for manual mode\n"); + return; + } while (fgets(line, sizeof line, input)) { if (line[0] == '#' || line[0] == '\n') { printf ("%s", line); @@ -59,14 +64,14 @@ ccdbg_manual(struct ccdbg *dbg, FILE *input) get_bit(line, 4, 'R', CC_RESET_N, &set, &mask); if (mask != (CC_CLOCK|CC_DATA|CC_RESET_N)) { uint8_t read; - ccdbg_read(dbg, &read); - ccdbg_sync_io(dbg); - ccdbg_print("\t%c %c %c", CC_CLOCK|CC_DATA|CC_RESET_N, read); + cc_bitbang_read(dbg->bb, &read); + cc_bitbang_sync(dbg->bb); + cc_bitbang_print("\t%c %c %c", CC_CLOCK|CC_DATA|CC_RESET_N, read); if ((set & CC_CLOCK) == 0) printf ("\t%d", (read&CC_DATA) ? 1 : 0); printf ("\n"); } - ccdbg_send(dbg, mask, set); - ccdbg_sync_io(dbg); + cc_bitbang_send(dbg->bb, mask, set); + cc_bitbang_sync(dbg->bb); } } diff --git a/lib/ccdbg-memory.c b/lib/ccdbg-memory.c index 20a24799..878c5f97 100644 --- a/lib/ccdbg-memory.c +++ b/lib/ccdbg-memory.c @@ -50,6 +50,8 @@ ccdbg_write_memory(struct ccdbg *dbg, uint16_t addr, uint8_t *bytes, int nbytes) int i, nl = 0; struct ccstate state; + if (dbg->usb) + return cc_usb_write_memory(dbg->usb, addr, bytes, nbytes); ccdbg_state_save(dbg, &state, CC_STATE_ACC | CC_STATE_PSW | CC_STATE_DP); memory_init[HIGH_START] = addr >> 8; memory_init[LOW_START] = addr; @@ -83,6 +85,8 @@ ccdbg_read_memory(struct ccdbg *dbg, uint16_t addr, uint8_t *bytes, int nbytes) ccdbg_rom_replace_xmem(dbg, addr, bytes, nbytes); return 0; } + if (dbg->usb) + return cc_usb_read_memory(dbg->usb, addr, bytes, nbytes); ccdbg_state_save(dbg, &state, CC_STATE_ACC | CC_STATE_PSW | CC_STATE_DP); memory_init[HIGH_START] = addr >> 8; memory_init[LOW_START] = addr; diff --git a/lib/ccdbg.h b/lib/ccdbg.h index e0e12c8b..fe0ea3a0 100644 --- a/lib/ccdbg.h +++ b/lib/ccdbg.h @@ -31,17 +31,8 @@ #include #include #include "ccdbg-debug.h" - -#define CC_CLOCK 0x1 -#define CC_DATA 0x2 -#define CC_RESET_N 0x4 -#define CC_CLOCK_US (2) - -/* Telemetrum has a 10k pull-up to 3.3v, a 0.001uF cap to ground - * and a 2.7k resistor to the reset line. This takes about 6us - * to settle, so we'll wait longer than that after changing the reset line - */ -#define CC_RESET_US (12) +#include "cc-bitbang.h" +#include "cc-usb.h" /* 8051 instructions */ @@ -109,15 +100,10 @@ /* Bit-addressable status word */ #define PSW(bit) (0xD0 | (bit)) -#define CP_USB_ASYNC - struct ccdbg { -#ifdef CP_USB_ASYNC - struct cp_usb_async *cp_async; -#else - struct cp_usb *cp; -#endif - struct hex_image *rom; + struct cc_bitbang *bb; + struct cc_usb *usb; + struct hex_image *rom; }; /* Intel hex file format data @@ -225,6 +211,13 @@ ccdbg_resume(struct ccdbg *dbg); uint8_t ccdbg_debug_instr(struct ccdbg *dbg, uint8_t *instr, int nbytes); +void +ccdbg_debug_instr_discard(struct ccdbg *dbg, uint8_t *instr, int nbytes); + +void +ccdbg_debug_instr_queue(struct ccdbg *dbg, uint8_t *instr, int nbytes, + uint8_t *reply); + uint8_t ccdbg_step_instr(struct ccdbg *dbg); @@ -264,80 +257,33 @@ int ccdbg_hex_image_equal(struct hex_image *a, struct hex_image *b); /* ccdbg-io.c */ -void -ccdbg_set_clock(uint32_t us); - -void -ccdbg_half_clock(struct ccdbg *dbg); - -void -ccdbg_wait_reset(struct ccdbg *dbg); - -int -ccdbg_write(struct ccdbg *dbg, uint8_t mask, uint8_t value); - -void -ccdbg_read(struct ccdbg *dbg, uint8_t *valuep); - struct ccdbg * ccdbg_open(void); void ccdbg_close(struct ccdbg *dbg); -void -ccdbg_clock_1_0(struct ccdbg *dbg); - -void -ccdbg_clock_0_1(struct ccdbg *dbg); - -void -ccdbg_write_bit(struct ccdbg *dbg, uint8_t bit); - -void -ccdbg_write_byte(struct ccdbg *dbg, uint8_t byte); - -uint8_t -ccdbg_read_bit(struct ccdbg *dbg); - -uint8_t -ccdbg_read_byte(struct ccdbg *dbg); - void ccdbg_cmd_write(struct ccdbg *dbg, uint8_t cmd, uint8_t *data, int len); uint8_t ccdbg_cmd_write_read8(struct ccdbg *dbg, uint8_t cmd, uint8_t *data, int len); -uint16_t -ccdbg_cmd_write_read16(struct ccdbg *dbg, uint8_t cmd, uint8_t *data, int len); - void -ccdbg_send(struct ccdbg *dbg, uint8_t mask, uint8_t set); +ccdbg_cmd_write_queue8(struct ccdbg *dbg, uint8_t cmd, + uint8_t *data, int len, uint8_t *reply); -void -ccdbg_send_bit(struct ccdbg *dbg, uint8_t bit); - -void -ccdbg_send_byte(struct ccdbg *dbg, uint8_t byte); +uint16_t +ccdbg_cmd_write_read16(struct ccdbg *dbg, uint8_t cmd, uint8_t *data, int len); void ccdbg_send_bytes(struct ccdbg *dbg, uint8_t *bytes, int nbytes); -void -ccdbg_recv_bit(struct ccdbg *dbg, int first, uint8_t *bit); - -void -ccdbg_recv_byte(struct ccdbg *dbg, int first, uint8_t *byte); - void ccdbg_recv_bytes(struct ccdbg *dbg, uint8_t *bytes, int nbytes); void -ccdbg_sync_io(struct ccdbg *dbg); - -void -ccdbg_print(char *format, uint8_t mask, uint8_t set); +ccdbg_sync(struct ccdbg *dbg); /* ccdbg-manual.c */ diff --git a/lib/cp-usb.c b/lib/cp-usb.c index 6ab9092c..d227b78c 100644 --- a/lib/cp-usb.c +++ b/lib/cp-usb.c @@ -25,6 +25,7 @@ #include "cp-usb.h" #include #include +#include struct cp_usb { usb_dev_handle *usb_dev; -- cgit v1.2.3 From ee110425fb814780476d1d3d8a257af126f41763 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 6 Apr 2009 17:09:23 -0700 Subject: Bump buffer pointer as data is written to cc-usb --- lib/cc-usb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/cc-usb.c b/lib/cc-usb.c index a85765af..5da36fe9 100644 --- a/lib/cc-usb.c +++ b/lib/cc-usb.c @@ -226,6 +226,7 @@ cc_usb_printf(struct cc_usb *cc, char *format, ...) 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_BUF) cc_usb_sync(cc); } -- cgit v1.2.3 From 5221dc63cf3a059a32aca2bfa7828c215be814a1 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 12 Apr 2009 12:38:58 -0700 Subject: Add ccdump --- INSTALL | 106 ++++++++++++++++++++++++++++------------------------- Makefile.am | 2 +- ccdump/Makefile.am | 10 +++++ ccdump/ccdump.c | 52 ++++++++++++++++++++++++++ configure.ac | 1 + lib/cc-usb.c | 4 +- lib/cc-usb.h | 6 +++ 7 files changed, 129 insertions(+), 52 deletions(-) create mode 100644 ccdump/Makefile.am create mode 100644 ccdump/ccdump.c (limited to 'lib') diff --git a/INSTALL b/INSTALL index 54caf7c1..d3c5b40a 100644 --- a/INSTALL +++ b/INSTALL @@ -1,13 +1,19 @@ -Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software -Foundation, Inc. +Installation Instructions +************************* - This file is free documentation; the Free Software Foundation gives +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, +2006, 2007 Free Software Foundation, Inc. + +This file is free documentation; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. Basic Installation ================== - These are generic installation instructions. +Briefly, the shell commands `./configure; make; make install' should +configure, build, and install this package. The following +more-detailed instructions are generic; see the `README' file for +instructions specific to this package. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses @@ -20,9 +26,9 @@ debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves -the results of its tests to speed up reconfiguring. (Caching is +the results of its tests to speed up reconfiguring. Caching is disabled by default to prevent problems with accidental use of stale -cache files.) +cache files. If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail @@ -32,20 +38,17 @@ some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create -`configure' by a program called `autoconf'. You only need -`configure.ac' if you want to change it or regenerate `configure' using -a newer version of `autoconf'. +`configure' by a program called `autoconf'. You need `configure.ac' if +you want to change it or regenerate `configure' using a newer version +of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type - `./configure' to configure the package for your system. If you're - using `csh' on an old version of System V, you might need to type - `sh ./configure' instead to prevent `csh' from trying to execute - `configure' itself. + `./configure' to configure the package for your system. - Running `configure' takes awhile. While running, it prints some - messages telling which features it is checking for. + Running `configure' might take a while. While running, it prints + some messages telling which features it is checking for. 2. Type `make' to compile the package. @@ -64,54 +67,55 @@ The simplest way to compile this package is: all sorts of other programs in order to regenerate files that came with the distribution. + 6. Often, you can also type `make uninstall' to remove the installed + files again. + Compilers and Options ===================== - Some systems require unusual options for compilation or linking that -the `configure' script does not know about. Run `./configure --help' -for details on some of the pertinent environment variables. +Some systems require unusual options for compilation or linking that the +`configure' script does not know about. Run `./configure --help' for +details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: - ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + ./configure CC=c99 CFLAGS=-g LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== - You can compile the package for more than one kind of computer at the +You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their -own directory. To do this, you must use a version of `make' that -supports the `VPATH' variable, such as GNU `make'. `cd' to the +own directory. To do this, you can use GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. - If you have to use a `make' that does not support the `VPATH' -variable, you have to compile the package for one architecture at a -time in the source code directory. After you have installed the -package for one architecture, use `make distclean' before reconfiguring -for another architecture. + With a non-GNU `make', it is safer to compile the package for one +architecture at a time in the source code directory. After you have +installed the package for one architecture, use `make distclean' before +reconfiguring for another architecture. Installation Names ================== - By default, `make install' will install the package's files in -`/usr/local/bin', `/usr/local/man', etc. You can specify an -installation prefix other than `/usr/local' by giving `configure' the -option `--prefix=PATH'. +By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you -give `configure' the option `--exec-prefix=PATH', the package will use -PATH as the prefix for installing programs and libraries. -Documentation and other data files will still use the regular prefix. +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. In addition, if you use an unusual directory layout you can give -options like `--bindir=PATH' to specify different values for particular +options like `--bindir=DIR' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. @@ -122,7 +126,7 @@ option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= - Some packages pay attention to `--enable-FEATURE' options to +Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The @@ -137,11 +141,11 @@ you can use the `configure' options `--x-includes=DIR' and Specifying the System Type ========================== - There may be some features `configure' cannot figure out -automatically, but needs to determine by the type of machine the package -will run on. Usually, assuming the package is built to be run on the -_same_ architectures, `configure' can figure that out, but if it prints -a message saying it cannot guess the machine type, give it the +There may be some features `configure' cannot figure out automatically, +but needs to determine by the type of machine the package will run on. +Usually, assuming the package is built to be run on the _same_ +architectures, `configure' can figure that out, but if it prints a +message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: @@ -156,7 +160,7 @@ where SYSTEM can have one of these forms: need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should -use the `--target=TYPE' option to select the type of system they will +use the option `--target=TYPE' to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a @@ -167,9 +171,9 @@ eventually be run) with `--host=TYPE'. Sharing Defaults ================ - If you want to set default values for `configure' scripts to share, -you can create a site shell script called `config.site' that gives -default values for variables like `CC', `cache_file', and `prefix'. +If you want to set default values for `configure' scripts to share, you +can create a site shell script called `config.site' that gives default +values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. @@ -178,7 +182,7 @@ A warning: not all `configure' scripts look for a site script. Defining Variables ================== - Variables not defined in a site shell script can be set in the +Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set @@ -186,14 +190,18 @@ them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc -will cause the specified gcc to be used as the C compiler (unless it is +causes the specified `gcc' to be used as the C compiler (unless it is overridden in the site shell script). +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf bug. Until the bug is fixed you can use this workaround: + + CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash + `configure' Invocation ====================== - `configure' recognizes the following options to control how it -operates. +`configure' recognizes the following options to control how it operates. `--help' `-h' diff --git a/Makefile.am b/Makefile.am index 5341ab33..ee3d2924 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1 +1 @@ -SUBDIRS=lib ccload s51 ccmanual +SUBDIRS=lib ccload s51 ccmanual ccdump diff --git a/ccdump/Makefile.am b/ccdump/Makefile.am new file mode 100644 index 00000000..976383f7 --- /dev/null +++ b/ccdump/Makefile.am @@ -0,0 +1,10 @@ +bin_PROGRAMS=ccdump + +AM_CFLAGS=-I$(top_srcdir)/lib $(LIBUSB_CFLAGS) +CCLOAD_LIBS=../lib/libcc.a + +ccdump_DEPENDENCIES = $(CCLOAD_LIBS) + +ccdump_LDADD=$(CCLOAD_LIBS) $(LIBUSB_LIBS) + +ccdump_SOURCES = ccdump.c diff --git a/ccdump/ccdump.c b/ccdump/ccdump.c new file mode 100644 index 00000000..5a5ce11c --- /dev/null +++ b/ccdump/ccdump.c @@ -0,0 +1,52 @@ +/* + * 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 "cc-usb.h" + +#define NUM_BLOCK 512 + +int +main (int argc, char **argv) +{ + struct cc_usb *cc; + int block; + uint8_t bytes[32 * (2 + 8)]; + uint8_t *b; + int i, j; + uint32_t addr; + + cc = cc_usb_open(); + for (block = 0; block < NUM_BLOCK; block++) { + cc_queue_read(cc, bytes, sizeof (bytes)); + cc_usb_printf(cc, "e %x\n", block); + cc_usb_sync(cc); + for (i = 0; i < 32; i++) { + b = bytes + (i * 10); + addr = block * 256 + i * 8; + printf ("%06x", addr); + for (j = 0; j < 8; j++) { + printf (" %02x", b[j+2]); + } + printf ("\n"); + } + } + cc_usb_close(cc); + exit (0); +} diff --git a/configure.ac b/configure.ac index 516657ea..1d4720a6 100644 --- a/configure.ac +++ b/configure.ac @@ -98,4 +98,5 @@ lib/Makefile ccload/Makefile s51/Makefile ccmanual/Makefile +ccdump/Makefile ]) diff --git a/lib/cc-usb.c b/lib/cc-usb.c index 5da36fe9..09b06bb5 100644 --- a/lib/cc-usb.c +++ b/lib/cc-usb.c @@ -201,7 +201,7 @@ cc_usb_sync(struct cc_usb *cc) } } -static void +void cc_usb_printf(struct cc_usb *cc, char *format, ...) { char buf[1024], *b; @@ -251,7 +251,7 @@ cc_usb_send_bytes(struct cc_usb *cc, uint8_t *bytes, int len) return ret; } -static void +void cc_queue_read(struct cc_usb *cc, uint8_t *buf, int len) { struct cc_read *read_buf; diff --git a/lib/cc-usb.h b/lib/cc-usb.h index 235e9918..2adccb93 100644 --- a/lib/cc-usb.h +++ b/lib/cc-usb.h @@ -50,4 +50,10 @@ cc_usb_reset(struct cc_usb *cc); void cc_usb_sync(struct cc_usb *cc); +void +cc_queue_read(struct cc_usb *cc, uint8_t *buf, int len); + +void +cc_usb_printf(struct cc_usb *cc, char *format, ...); + #endif /* _CC_USB_H_ */ -- cgit v1.2.3 From 26095fc0511ee0d5213f038986032f7c59964cf0 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 17 Apr 2009 10:10:47 -0700 Subject: Run-time selection between cp2103 and cc1111 --- lib/cc-usb.c | 4 +--- lib/cc-usb.h | 2 +- lib/ccdbg-io.c | 6 ++++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/cc-usb.c b/lib/cc-usb.c index 09b06bb5..9df2e312 100644 --- a/lib/cc-usb.c +++ b/lib/cc-usb.c @@ -317,13 +317,11 @@ cc_usb_reset(struct cc_usb *cc) static struct termios save_termios; struct cc_usb * -cc_usb_open(void) +cc_usb_open(char *tty) { struct cc_usb *cc; - char *tty; struct termios termios; - tty = getenv("CCDBG_TTY"); if (!tty) tty = DEFAULT_TTY; cc = calloc (sizeof (struct cc_usb), 1); diff --git a/lib/cc-usb.h b/lib/cc-usb.h index 2adccb93..d7acfbd2 100644 --- a/lib/cc-usb.h +++ b/lib/cc-usb.h @@ -24,7 +24,7 @@ struct cc_usb; struct cc_usb * -cc_usb_open(void); +cc_usb_open(char *tty); void cc_usb_close(struct cc_usb *cc); diff --git a/lib/ccdbg-io.c b/lib/ccdbg-io.c index acd44f10..9c6693cd 100644 --- a/lib/ccdbg-io.c +++ b/lib/ccdbg-io.c @@ -21,18 +21,20 @@ #include "cc-usb.h" #include "cc-bitbang.h" - struct ccdbg * ccdbg_open(void) { struct ccdbg *dbg; + char *tty; dbg = calloc(sizeof (struct ccdbg), 1); if (!dbg) { perror("calloc"); return NULL; } - dbg->usb = cc_usb_open(); + tty = getenv("CCDBG_TTY"); + if (!tty || tty[0] == '/') + dbg->usb = cc_usb_open(tty); if (!dbg->usb) { dbg->bb = cc_bitbang_open(); if (!dbg->bb) { -- cgit v1.2.3 From 837c620f07b63efc171be3ac14c78bc99adf7592 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 22 Apr 2009 14:25:43 -0700 Subject: Shrink USB output buffers, work around USB packet errors --- lib/cc-usb.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) (limited to 'lib') diff --git a/lib/cc-usb.c b/lib/cc-usb.c index 9df2e312..2efe572e 100644 --- a/lib/cc-usb.c +++ b/lib/cc-usb.c @@ -31,7 +31,11 @@ #define CC_NUM_READ 16 -#define CC_BUF 1024 +/* + * 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 { @@ -41,9 +45,9 @@ struct cc_read { struct cc_usb { int fd; - uint8_t in_buf[CC_BUF]; + uint8_t in_buf[CC_IN_BUF]; int in_count; - uint8_t out_buf[CC_BUF]; + uint8_t out_buf[CC_OUT_BUF]; int out_count; struct cc_read read_buf[CC_NUM_READ]; int read_count; @@ -167,7 +171,7 @@ cc_usb_sync(struct cc_usb *cc) else timeout = 0; fds.events = 0; - if (cc->in_count < CC_BUF) + if (cc->in_count < CC_IN_BUF) fds.events |= POLLIN; if (cc->out_count) fds.events |= POLLOUT; @@ -180,12 +184,13 @@ cc_usb_sync(struct cc_usb *cc) } if (fds.revents & POLLIN) { ret = read(cc->fd, cc->in_buf + cc->in_count, - CC_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, @@ -196,7 +201,8 @@ cc_usb_sync(struct cc_usb *cc) cc->out_buf + ret, cc->out_count - ret); cc->out_count -= ret; - } + } else if (ret < 0) + perror("write"); } } } @@ -221,13 +227,13 @@ cc_usb_printf(struct cc_usb *cc, char *format, ...) b = buf; while (ret > 0) { this_time = ret; - if (this_time > CC_BUF - cc->out_count) - this_time = CC_BUF - cc->out_count; + 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_BUF) + while (cc->out_count >= CC_OUT_BUF) cc_usb_sync(cc); } } -- cgit v1.2.3