diff options
| author | Keith Packard <keithp@keithp.com> | 2008-12-19 21:11:45 -0800 | 
|---|---|---|
| committer | Keith Packard <keithp@keithp.com> | 2008-12-19 21:11:45 -0800 | 
| commit | 9025eb792861930e6af918d2727c4f5d97a69936 (patch) | |
| tree | dcace71405af05c9673112c481beed81aae6ddb8 /lib | |
| parent | ab909db28307cfbf7ee8d692506bb79d7ffd627a (diff) | |
Autotools.
Signed-off-by: Keith Packard <keithp@keithp.com>
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/Makefile.am | 14 | ||||
| -rw-r--r-- | lib/cccp.c | 100 | ||||
| -rw-r--r-- | lib/cccp.h | 41 | ||||
| -rw-r--r-- | lib/ccdbg-command.c | 182 | ||||
| -rw-r--r-- | lib/ccdbg-debug.c | 47 | ||||
| -rw-r--r-- | lib/ccdbg-flash.c | 337 | ||||
| -rw-r--r-- | lib/ccdbg-hex.c | 330 | ||||
| -rw-r--r-- | lib/ccdbg-io.c | 211 | ||||
| -rw-r--r-- | lib/ccdbg-manual.c | 70 | ||||
| -rw-r--r-- | lib/ccdbg-memory.c | 104 | ||||
| -rw-r--r-- | lib/ccdbg.h | 351 | ||||
| -rw-r--r-- | lib/cp-usb.c | 140 | 
12 files changed, 1927 insertions, 0 deletions
| 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 <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ccdbg.h" + +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 <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +/* + * 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 <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ccdbg.h" + +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 <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ccdbg.h" +#include <stdarg.h> + +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 <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ccdbg.h" + +/* From SWRA124 section 3.1.6 */ + +static uint8_t flash_page[] = { + +	MOV_direct_data, P1DIR, 0x02, +	MOV_direct_data, P1,	0xFF, + +	MOV_direct_data, FADDRH, 0, +#define FLASH_ADDR_HIGH	8 + +	MOV_direct_data, FADDRL, 0, +#define FLASH_ADDR_LOW	11 + +	MOV_DPTR_data16, 0, 0, +#define RAM_ADDR_HIGH	13 +#define RAM_ADDR_LOW	14 + +	MOV_Rn_data(7), 0, +#define FLASH_WORDS_HIGH	16 +	 +	MOV_Rn_data(6), 0, +#define FLASH_WORDS_LOW		18 +	 +	MOV_direct_data, FWT, 0x20, +#define FLASH_TIMING		21 + +	MOV_direct_data, FCTL, FCTL_ERASE, +/* eraseWaitLoop: */ +		MOV_A_direct,		FCTL, +	JB, ACC(FCTL_BUSY_BIT), 0xfb, + +	MOV_direct_data, P1, 0xfd, + +	MOV_direct_data, FCTL, FCTL_WRITE, +/* writeLoop: */ +		MOV_Rn_data(5), 2, +/* writeWordLoop: */ +			MOVX_A_atDPTR, +			INC_DPTR, +			MOV_direct_A, FWDATA, +		DJNZ_Rn_rel(5), 0xfa,		/* writeWordLoop */ +/* writeWaitLoop: */ +			MOV_A_direct, FCTL, +		JB, ACC(FCTL_SWBSY_BIT), 0xfb,		/* writeWaitLoop */ +	DJNZ_Rn_rel(6), 0xf1,			/* writeLoop */ +	DJNZ_Rn_rel(7), 0xef,			/* writeLoop */ + +	MOV_direct_data, P1DIR, 0x00, +	MOV_direct_data, P1,	0xFF, +	TRAP, +}; + +#define FLASH_RAM	0xf000 + +#if 0 +static uint8_t	flash_erase_page[] = { +	3,	MOV_direct_data, FADDRH, 0, +#define ERASE_PAGE_HIGH	3 +	 +	3,	MOV_direct_data, FADDRL, 0, +#define ERASE_PAGE_LOW	7 + +	3,	MOV_direct_data, FWT, 0x2A, +	3,	MOV_direct_data, FCTL, FCTL_ERASE, +	0 +}; + +static uint8_t	flash_read_control[] = { +	2,	MOV_A_direct,	FCTL, +	0 +}; +#endif + +#if 0 +static uint8_t	flash_control_clear[] = { +	3,	MOV_direct_data,	FCTL, 0, +	2,	MOV_A_direct,		FCTL, +	0 +}; +#endif + +#if 0 +static uint8_t +ccdbg_flash_erase_page(struct ccdbg *dbg, uint16_t addr) +{ +	uint16_t	page_addr = addr >> 1; +	uint8_t		status; +	uint8_t		old[0x10], new[0x10]; +	int		i; +	 +	ccdbg_read_memory(dbg, addr, old, 0x10); +	flash_erase_page[ERASE_PAGE_HIGH] = page_addr >> 8; +	flash_erase_page[ERASE_PAGE_LOW] = page_addr & 0xff; +	status = ccdbg_execute(dbg, flash_erase_page); +	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 <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ccdbg.h" +#include <stdarg.h> +#include <ctype.h> + +struct hex_input { +	FILE	*file; +	int	line; +	char	*name; +}; + +enum hex_read_state { +	read_marker, +	read_length, +	read_address, +	read_type, +	read_data, +	read_checksum, +	read_newline, +	read_white, +	read_done, +}; + + +static void +ccdbg_hex_error(struct hex_input *input, char *format, ...) +{ +	va_list ap; + +	va_start(ap, format); +	fprintf(stderr, "Hex error %s:%d: ", input->name, input->line); +	vfprintf(stderr, format, ap); +	fprintf(stderr, "\n"); +	va_end(ap); +} + +static void +ccdbg_hex_free(struct hex_record *record) +{ +	if (!record) return; +	free(record); +} + +static struct hex_record * +ccdbg_hex_alloc(uint8_t length) +{ +	struct hex_record *record; + +	record = calloc(1, sizeof(struct hex_record) + length); +	record->length = length; +	return record; +} + +static int +ishex(char c) +{ +	return isdigit(c) || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F'); +} + +static int +fromhex(char c) +{ +	if (isdigit(c)) +		return c - '0'; +	if ('a' <= c && c <= 'f') +		return c - 'a' + 10; +	if ('A' <= c && c <= 'F') +		return c - 'A' + 10; +	abort(); +	return 0; +} + +static uint8_t +ccdbg_hex_checksum(struct hex_record *record) +{ +	uint8_t	checksum = 0; +	int i; + +	checksum += record->length; +	checksum += record->address >> 8; +	checksum += record->address & 0xff; +	checksum += record->type; +	for (i = 0; i < record->length; i++) +		checksum += record->data[i]; +	return -checksum; +} + +static struct hex_record * +ccdbg_hex_read_record(struct hex_input *input) +{ +	struct hex_record *record = NULL; +	enum hex_read_state state = read_marker; +	char c; +	int nhexbytes; +	uint32_t hex; +	uint32_t ndata; +	uint8_t checksum; + +	while (state != read_done) { +		c = getc(input->file); +		if (c == EOF && state != read_white) { +			ccdbg_hex_error(input, "Unexpected EOF"); +			goto bail; +		} +		if (c == ' ') +			continue; +		if (c == '\n') +			input->line++; +		switch (state) { +		case read_marker: +			if (c != ':') { +				ccdbg_hex_error(input, "Missing ':'"); +				goto bail; +			} +			state = read_length; +			nhexbytes = 2; +			hex = 0; +			break; +		case read_length: +		case read_address: +		case read_type: +		case read_data: +		case read_checksum: +			if (!ishex(c)) { +				ccdbg_hex_error(input, "Non-hex char '%c'", +						c); +				goto bail; +			} +			hex = hex << 4 | fromhex(c); +			--nhexbytes; +			if (nhexbytes != 0) +				break; +			 +			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 <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ccdbg.h" +#include <time.h> + +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 <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ccdbg.h" + +/* + * 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 <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ccdbg.h" + +/* + * Read and write arbitrary memory through the debug port + */ + +static uint8_t	memory_init[] = { +	3,	MOV_DPTR_data16,	0,	0, +#define HIGH_START	2 +#define LOW_START	3 +	0, +}; + + +static uint8_t write8[] = { +	2,	MOV_A_data,	0, +#define DATA_BYTE	2 +	1,	MOVX_atDPTR_A, +	1,	INC_DPTR, +	0 +}; + +static uint8_t read8[] = { +	1,	MOVX_A_atDPTR, +	1,	INC_DPTR, +	0, +}; + +uint8_t +ccdbg_write_memory(struct ccdbg *dbg, uint16_t addr, uint8_t *bytes, int nbytes) +{ +	int i, nl = 0; +	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 <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _CCDBG_H_ +#define _CCDBG_H_ + +#include <stdint.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdio.h> +#include <stdint.h> +#include <assert.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#undef USE_KERNEL +#ifdef USE_KERNEL +#include <cp2101.h> +#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 <usb.h> +#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 <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ccdbg.h" +#include <usb.h> + +#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; +} | 
