diff options
author | Keith Packard <keithp@keithp.com> | 2008-12-30 22:35:53 -0800 |
---|---|---|
committer | Keith Packard <keithp@keithp.com> | 2008-12-30 22:38:35 -0800 |
commit | 6c2a65c743a4ffae96ed27dbc38c1bf9242ed1df (patch) | |
tree | bea5fb122dfcc2edfcff0baca30dd1166a1d24af /lib | |
parent | ea366058aa467a8a7caf17e7014758f3741ea7f7 (diff) |
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 <keithp@keithp.com>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Makefile.am | 2 | ||||
-rw-r--r-- | lib/ccdbg-debug.c | 5 | ||||
-rw-r--r-- | lib/ccdbg-debug.h | 2 | ||||
-rw-r--r-- | lib/ccdbg-flash.c | 8 | ||||
-rw-r--r-- | lib/ccdbg-memory.c | 54 | ||||
-rw-r--r-- | lib/ccdbg-rom.c | 63 | ||||
-rw-r--r-- | lib/ccdbg-state.c | 128 | ||||
-rw-r--r-- | lib/ccdbg.h | 43 |
8 files changed, 268 insertions, 37 deletions
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 <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ccdbg.h" + +uint8_t +ccdbg_set_rom(struct ccdbg *dbg, struct hex_image *rom) +{ + if (dbg->rom) + ccdbg_hex_image_free(dbg->rom); + dbg->rom = rom; + return 0; +} + +uint8_t +ccdbg_rom_contains(struct ccdbg *dbg, uint16_t addr, int nbytes) +{ + struct hex_image *rom = dbg->rom; + if (!rom) + return 0; + if (addr < rom->address || rom->address + rom->length < addr + nbytes) + return 0; + return 1; +} + +uint8_t +ccdbg_rom_replace_xmem(struct ccdbg *dbg, + uint16_t addr, uint8_t *bytes, int nbytes) +{ + struct hex_image *rom = dbg->rom; + if (!rom) + return 0; + + if (rom->address < addr + nbytes && addr < rom->address + rom->length) { + int start, stop; + + start = addr; + if (addr < rom->address) + start = rom->address; + stop = addr + nbytes; + if (rom->address + rom->length < stop) + stop = rom->address + rom->length; + memcpy(bytes + start - addr, rom->data + start - rom->address, + stop - start); + return 1; + } + return 0; +} diff --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 <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 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_ */ |