diff options
| author | Keith Packard <keithp@keithp.com> | 2009-06-04 10:41:34 -0700 | 
|---|---|---|
| committer | Keith Packard <keithp@keithp.com> | 2009-06-04 10:41:34 -0700 | 
| commit | 210dbaa23cdacf3a6f2d6e23493e96ee2ac9bca7 (patch) | |
| tree | 42dbabd0caa7186c898da746014341d3ff31a201 /src/ao_dbg.c | |
| parent | 8cce307bb3156584ba17ae5a787f645dfee5fb94 (diff) | |
Use autotools, move altos to src subdir
Signed-off-by: Keith Packard <keithp@keithp.com>
Diffstat (limited to 'src/ao_dbg.c')
| -rw-r--r-- | src/ao_dbg.c | 367 | 
1 files changed, 367 insertions, 0 deletions
| diff --git a/src/ao_dbg.c b/src/ao_dbg.c new file mode 100644 index 00000000..c8dc6ddc --- /dev/null +++ b/src/ao_dbg.c @@ -0,0 +1,367 @@ +/* + * Copyright © 2009 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" + +#define DBG_CLOCK	(1 << 3) +#define DBG_DATA	(1 << 4) +#define DBG_RESET_N	(1 << 5) + +#define DBG_CLOCK_PIN	(P0_3) +#define DBG_DATA_PIN	(P0_4) +#define DBG_RESET_N_PIN	(P0_5) + +static void +ao_dbg_send_bits(uint8_t msk, uint8_t val) +{ +	P0 = (P0 & ~msk) | (val & msk); +	_asm +		nop +		nop +	_endasm; +} + +void +ao_dbg_send_byte(uint8_t byte) +{ +	__xdata uint8_t	b, d; + +	P0 |= DBG_DATA; +	P0DIR |= DBG_DATA; +	for (b = 0; b < 8; b++) { +		d = 0; +		if (byte & 0x80) +			d = DBG_DATA; +		byte <<= 1; +		ao_dbg_send_bits(DBG_CLOCK|DBG_DATA, DBG_CLOCK|d); +		ao_dbg_send_bits(DBG_CLOCK|DBG_DATA,     0    |d); +	} +	P0DIR &= ~DBG_DATA; +} + +uint8_t +ao_dbg_recv_byte(void) +{ +	__xdata uint8_t	byte, b; + +	byte = 0; +	for (b = 0; b < 8; b++) { +		byte = byte << 1; +		ao_dbg_send_bits(DBG_CLOCK, DBG_CLOCK); +		if (DBG_DATA_PIN) +			byte |= 1; +		ao_dbg_send_bits(DBG_CLOCK, 0); +	} +	return byte; +} + +/* 8051 instructions + */ +#define NOP			0x00 +#define MOV_direct_data		0x75 +#define LJMP			0x02 +#define MOV_Rn_data(n)		(0x78 | (n)) +#define DJNZ_Rn_rel(n)		(0xd8 | (n)) +#define MOV_A_direct		0xe5 +#define MOV_direct1_direct2	0x85 +#define MOV_direct_A		0xf5 +#define MOV_DPTR_data16		0x90 +#define MOV_A_data		0x74 +#define MOVX_atDPTR_A		0xf0 +#define MOVX_A_atDPTR		0xe0 +#define INC_DPTR		0xa3 +#define TRAP			0xa5 +#define SJMP			0x80 +#define JB			0x20 + +#define DEBUG_INSTR(l)		(0x54 | (l)) + +#define SFR_PSW			0xD0 +#define SFR_DPL0		0x82 +#define SFR_DPH0		0x83 +#define SFR_DPL1		0x84 +#define SFR_DPH1		0x85 + +__xdata uint8_t	save_acc; +__xdata uint8_t save_psw; +__xdata uint8_t save_dpl0; +__xdata uint8_t save_dph0; +__xdata uint8_t save_dpl1; +__xdata uint8_t save_dph1; + +static uint8_t +ao_dbg_inst1(uint8_t a) __reentrant +{ +	ao_dbg_send_byte(DEBUG_INSTR(1)); +	ao_dbg_send_byte(a); +	return ao_dbg_recv_byte(); +} + +static uint8_t +ao_dbg_inst2(uint8_t a, uint8_t b) __reentrant +{ +	ao_dbg_send_byte(DEBUG_INSTR(2)); +	ao_dbg_send_byte(a); +	ao_dbg_send_byte(b); +	return ao_dbg_recv_byte(); +} + +static uint8_t +ao_dbg_inst3(uint8_t a, uint8_t b, uint8_t c) __reentrant +{ +	ao_dbg_send_byte(DEBUG_INSTR(3)); +	ao_dbg_send_byte(a); +	ao_dbg_send_byte(b); +	ao_dbg_send_byte(c); +	return ao_dbg_recv_byte(); +} + +void +ao_dbg_start_transfer(uint16_t addr) +{ +	save_acc  = ao_dbg_inst1(NOP); +	save_psw  = ao_dbg_inst2(MOV_A_direct, SFR_PSW); +	save_dpl0 = ao_dbg_inst2(MOV_A_direct, SFR_DPL0); +	save_dph0 = ao_dbg_inst2(MOV_A_direct, SFR_DPH0); +	save_dpl1 = ao_dbg_inst2(MOV_A_direct, SFR_DPL1); +	save_dph1 = ao_dbg_inst2(MOV_A_direct, SFR_DPH1); +	ao_dbg_inst3(MOV_DPTR_data16, addr >> 8, addr); +} + +void +ao_dbg_end_transfer(void) +{ +	ao_dbg_inst3(MOV_direct_data, SFR_DPL0, save_dpl0); +	ao_dbg_inst3(MOV_direct_data, SFR_DPH0, save_dph0); +	ao_dbg_inst3(MOV_direct_data, SFR_DPL1, save_dpl1); +	ao_dbg_inst3(MOV_direct_data, SFR_DPH1, save_dph1); +	ao_dbg_inst3(MOV_direct_data, SFR_PSW, save_psw); +	ao_dbg_inst2(MOV_A_data, save_acc); +} + +void +ao_dbg_write_byte(uint8_t byte) +{ +	ao_dbg_inst2(MOV_A_data, byte); +	ao_dbg_inst1(MOVX_atDPTR_A); +	ao_dbg_inst1(INC_DPTR); +} + +uint8_t +ao_dbg_read_byte(void) +{ +	ao_dbg_inst1(MOVX_A_atDPTR); +	return ao_dbg_inst1(INC_DPTR); +} + +static void +ao_dbg_set_pins(void) +{ +	/* Disable peripheral use of P0 */ +	ADCCFG = 0; +	P0SEL = 0; + + +	/* make P0_4 tri-state */ +	P0INP = DBG_DATA; +	P2INP &= ~(P2INP_PDUP0_PULL_DOWN); + +	/* Raise RESET_N and CLOCK */ +	P0 = DBG_RESET_N | DBG_CLOCK; + +	/* RESET_N and CLOCK are outputs now */ +	P0DIR = DBG_RESET_N | DBG_CLOCK; +} + +static void +ao_dbg_long_delay(void) +{ +	uint8_t	n; + +	for (n = 0; n < 20; n++) +		_asm nop _endasm; +} + +void +ao_dbg_debug_mode(void) +{ +	ao_dbg_set_pins(); +	ao_dbg_long_delay(); +	ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N); +	ao_dbg_long_delay(); +	ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N,     0    |DBG_DATA|    0    ); +	ao_dbg_long_delay(); +	ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|    0    ); +	ao_dbg_long_delay(); +	ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N,     0    |DBG_DATA|    0    ); +	ao_dbg_long_delay(); +	ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|    0    ); +	ao_dbg_long_delay(); +	ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N,     0    |DBG_DATA|DBG_RESET_N); +	ao_dbg_long_delay(); +} + +void +ao_dbg_reset(void) +{ +	ao_dbg_set_pins(); +	ao_dbg_long_delay(); +	ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N); +	ao_dbg_long_delay(); +	ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|    0    ); +	ao_dbg_long_delay(); +	ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|    0    ); +	ao_dbg_long_delay(); +	ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|    0    ); +	ao_dbg_long_delay(); +	ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|    0    ); +	ao_dbg_long_delay(); +	ao_dbg_send_bits(DBG_CLOCK|DBG_DATA|DBG_RESET_N, DBG_CLOCK|DBG_DATA|DBG_RESET_N); +	ao_dbg_long_delay(); +} + +static void +debug_enable(void) +{ +	ao_dbg_debug_mode(); +} + +static void +debug_reset(void) +{ +	ao_dbg_reset(); +} + +static void +debug_put(void) +{ +	for (;;) { +		ao_cmd_white (); +		if (ao_cmd_lex_c == '\n') +			break; +		ao_cmd_hex(); +		if (ao_cmd_status != ao_cmd_success) +			break; +		ao_dbg_send_byte(ao_cmd_lex_i); +	} +} + +static void +debug_get(void) +{ +	__xdata uint16_t count; +	__xdata uint16_t i; +	__xdata uint8_t byte; +	ao_cmd_hex(); +	if (ao_cmd_status != ao_cmd_success) +		return; +	count = ao_cmd_lex_i; +	if (count > 256) { +		ao_cmd_status = ao_cmd_syntax_error; +		return; +	} +	for (i = 0; i < count; i++) { +		if (i && (i & 7) == 0) +			putchar('\n'); +		byte = ao_dbg_recv_byte(); +		ao_cmd_put8(byte); +		putchar(' '); +	} +	putchar('\n'); +} + +static uint8_t +getnibble(void) +{ +	__xdata char	c; + +	c = getchar(); +	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); +	ao_cmd_status = ao_cmd_lex_error; +	return 0; +} + +static void +debug_input(void) +{ +	__xdata uint16_t count; +	__xdata uint16_t addr; +	__xdata uint8_t b; +	__xdata uint8_t	i; + +	ao_cmd_hex(); +	count = ao_cmd_lex_i; +	ao_cmd_hex(); +	addr = ao_cmd_lex_i; +	if (ao_cmd_status != ao_cmd_success) +		return; +	ao_dbg_start_transfer(addr); +	i = 0; +	while (count--) { +		if (!(i++ & 7)) +			putchar('\n'); +		b = ao_dbg_read_byte(); +		ao_cmd_put8(b); +	} +	ao_dbg_end_transfer(); +	putchar('\n'); +} + +static void +debug_output(void) +{ +	__xdata uint16_t count; +	__xdata uint16_t addr; +	__xdata uint8_t b; + +	ao_cmd_hex(); +	count = ao_cmd_lex_i; +	ao_cmd_hex(); +	addr = ao_cmd_lex_i; +	if (ao_cmd_status != ao_cmd_success) +		return; +	ao_dbg_start_transfer(addr); +	while (count--) { +		b = getnibble() << 4; +		b |= getnibble(); +		if (ao_cmd_status != ao_cmd_success) +			return; +		ao_dbg_write_byte(b); +	} +	ao_dbg_end_transfer(); +} + +__code struct ao_cmds ao_dbg_cmds[7] = { +	{ 'D',	debug_enable,	"D                                  Enable debug mode" }, +	{ 'G',	debug_get,	"G <count>                          Get data from debug port" }, +	{ 'I',	debug_input,	"I <count> <addr>                   Input <count> bytes to target at <addr>" }, +	{ 'O',	debug_output,	"O <count> <addr>                   Output <count> bytes to target at <addr>" }, +	{ 'P',	debug_put,	"P <byte> ...                       Put data to debug port" }, +	{ 'R',	debug_reset,	"R                                  Reset target" }, +	{ 0, debug_reset,	0 }, +}; + +void +ao_dbg_init(void) +{ +	ao_cmd_register(&ao_dbg_cmds[0]); +} | 
