Initial Commit - Copy from Altus Metrum AltOS

This commit is contained in:
2024-06-25 19:03:04 +02:00
commit 13fc49c923
2048 changed files with 1206748 additions and 0 deletions

1
ao-tools/ao-dbg/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
s51

View File

@@ -0,0 +1,12 @@
bin_PROGRAMS=ao-dbg
AM_CFLAGS=$(WARN_CFLAGS) -I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
AO_DBG_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
man_MANS = ao-dbg.1
ao_dbg_DEPENDENCIES = $(AO_DBG_LIBS)
ao_dbg_LDADD=$(AO_DBG_LIBS) $(LIBUSB_LIBS) $(LIBREADLINE)
ao_dbg_SOURCES = ao-dbg-parse.c ao-dbg-command.c ao-dbg-main.c

View File

@@ -0,0 +1,652 @@
/*
* 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 "ao-dbg.h"
static uint16_t start_address;
static enum command_result
parse_int(char *value, int *result)
{
char *endptr;
*result = strtol(value, &endptr, 0);
if (endptr == value)
return command_syntax;
return command_success;
}
static enum command_result
parse_uint16(char *value, uint16_t *uint16)
{
int v;
enum command_result result;
result = parse_int(value, &v);
if (result != command_success)
return command_error;
if (v < 0 || v > 0xffff)
return command_error;
*uint16 = v;
return command_success;
}
static enum command_result
parse_uint8(char *value, uint8_t *uint8)
{
int v;
enum command_result result;
result = parse_int(value, &v);
if (result != command_success)
return command_error;
if (v < 0 || v > 0xff)
return command_error;
*uint8 = v;
return command_success;
}
enum command_result
command_quit (int argc, char **argv)
{
ccdbg_reset(s51_dbg);
exit(0);
return command_error;
}
static void
dump_bytes(uint8_t *memory, int length, uint16_t start, char *format)
{
int group, i;
for (group = 0; group < length; group += 8) {
s51_printf(format, start + group);
for (i = group; i < length && i < group + 8; i++)
s51_printf("%02x ", memory[i]);
for (; i < group + 8; i++)
s51_printf(" ");
for (i = group; i < length && i < group + 8; i++) {
if (isascii(memory[i]) && isprint(memory[i]))
s51_printf("%c", memory[i]);
else
s51_printf(".");
}
s51_printf("\n");
}
}
enum command_result
command_di (int argc, char **argv)
{
uint16_t start, end;
uint8_t memory[65536];
uint8_t status;
int length;
if (argc != 3)
return command_error;
if (parse_uint16(argv[1], &start) != command_success)
return command_error;
if (parse_uint16(argv[2], &end) != command_success)
return command_error;
length = (int) end - (int) start + 1;
status = ccdbg_read_memory(s51_dbg, start + 0xff00, memory, length);
(void) status;
dump_bytes(memory, length, start, "0x%02x ");
return command_success;
}
enum command_result
command_ds (int argc, char **argv)
{
uint8_t start, end;
uint8_t memory[0x100];
uint8_t status;
int length;
if (argc != 3)
return command_error;
if (parse_uint8(argv[1], &start) != command_success)
return command_error;
if (parse_uint8(argv[2], &end) != command_success)
return command_error;
length = (int) end - (int) start + 1;
status = ccdbg_read_sfr(s51_dbg, start, memory, length);
(void) status;
dump_bytes(memory, length, start, "0x%02x ");
return command_success;
}
enum command_result
command_dx (int argc, char **argv)
{
uint16_t start, end;
uint8_t memory[65536];
uint8_t status;
int length;
if (argc != 3)
return command_error;
if (parse_uint16(argv[1], &start) != command_success)
return command_error;
if (parse_uint16(argv[2], &end) != command_success)
return command_error;
length = (int) end - (int) start + 1;
status = ccdbg_read_memory(s51_dbg, start, memory, length);
(void) status;
dump_bytes(memory, length, start, "0x%04x ");
return command_success;
}
enum command_result
command_set (int argc, char **argv)
{
uint16_t address;
uint8_t *data;
int len = argc - 3;
int i;
enum command_result ret = command_success;
if (len < 0)
return command_error;
if (parse_uint16(argv[2], &address) != command_success)
return command_error;
if (len == 0)
return command_success;
data = malloc(len);
if (!data)
return command_error;
for (i = 0; i < len; i++)
if (parse_uint8(argv[i+3], &data[i]) != command_success)
return command_error;
if (strcmp(argv[1], "xram") == 0) {
ccdbg_write_memory(s51_dbg, address, data, len);
} else if (strcmp(argv[1], "iram") == 0) {
ccdbg_write_memory(s51_dbg, address + 0xff00, data, len);
} else if (strcmp(argv[1], "sfr") == 0) {
ccdbg_write_sfr(s51_dbg, (uint8_t) address, data, len);
} else
ret = command_error;
free(data);
return ret;
}
enum command_result
command_dump (int argc, char **argv)
{
if (argv[1]) {
if (strcmp(argv[1], "rom") == 0 ||
strcmp(argv[1], "xram") == 0)
return command_dx(argc-1, argv+1);
if (strcmp(argv[1], "iram") == 0)
return command_di(argc-1, argv+1);
if (strcmp(argv[1], "sfr") == 0)
return command_ds(argc-1, argv+1);
}
return command_error;
}
enum command_result
command_file (int argc, char **argv)
{
struct ao_hex_file *hex;
struct ao_hex_image *image;
FILE *file;
if (argc != 2)
return command_error;
file = fopen (argv[1], "r");
if (!file)
return command_error;
hex = ao_hex_file_read(file, argv[1]);
fclose(file);
if (!hex)
return command_error;
if (hex->nrecord == 0) {
ao_hex_file_free(hex);
return command_error;
}
image = ao_hex_image_create(hex);
ao_hex_file_free(hex);
start_address = image->address;
ccdbg_set_rom(s51_dbg, image);
return command_success;
}
enum command_result
command_pc (int argc, char **argv)
{
uint16_t pc;
if (argv[1]) {
enum command_result result;
result = parse_uint16(argv[1], &pc);
if (result != command_success)
return result;
ccdbg_set_pc(s51_dbg, pc);
} else {
pc = ccdbg_get_pc(s51_dbg);
s51_printf(" 0x%04x 00\n", pc);
}
return command_success;
}
struct cc_break {
int enabled;
int temporary;
uint16_t address;
};
#define CC_NUM_BREAKPOINTS 4
static struct cc_break breakpoints[CC_NUM_BREAKPOINTS];
static void
disable_breakpoint(int b)
{
uint8_t status;
status = ccdbg_set_hw_brkpnt(s51_dbg, b, 0, breakpoints[b].address);
if (status != 0x00 && status != 0xff)
s51_printf("disable_breakpoint status 0x%02x\n", status);
}
static void
enable_breakpoint(int b)
{
uint8_t status;
status = ccdbg_set_hw_brkpnt(s51_dbg, b, 1, breakpoints[b].address);
if (status != 0xff)
s51_printf("enable_breakpoint status 0x%02x\n", status);
}
static void
enable_breakpoints(void)
{
int b;
for (b = 0; b < CC_NUM_BREAKPOINTS; b++)
if (breakpoints[b].enabled)
enable_breakpoint(b);
}
static enum command_result
set_breakpoint(uint16_t address, int temporary)
{
int b;
for (b = 0; b < CC_NUM_BREAKPOINTS; b++) {
if (breakpoints[b].enabled == 0)
break;
if (breakpoints[b].address == address)
break;
}
if (b == CC_NUM_BREAKPOINTS) {
s51_printf("Error: too many breakpoints requested\n");
return command_success;
}
if (breakpoints[b].enabled == 0) {
breakpoints[b].address = address;
enable_breakpoint(b);
}
++breakpoints[b].enabled;
s51_printf("Breakpoint %d at 0x%04x\n", b, address);
breakpoints[b].temporary += temporary;
return command_success;
}
static enum command_result
clear_breakpoint(uint16_t address, int temporary)
{
int b;
for (b = 0; b < CC_NUM_BREAKPOINTS; b++) {
if (breakpoints[b].enabled != 0 &&
((breakpoints[b].temporary != 0) == (temporary != 0)) &&
breakpoints[b].address == address)
break;
}
if (b == CC_NUM_BREAKPOINTS) {
s51_printf("Error: no matching breakpoint found\n");
return command_success;
}
--breakpoints[b].enabled;
breakpoints[b].temporary -= temporary;
if (breakpoints[b].enabled == 0) {
disable_breakpoint(b);
breakpoints[b].address = -1;
}
return command_success;
}
static int
find_breakpoint(uint16_t address)
{
int b;
for (b = 0; b < CC_NUM_BREAKPOINTS; b++)
if (breakpoints[b].enabled && breakpoints[b].address == address)
break;
if (b == CC_NUM_BREAKPOINTS)
return -1;
return b;
}
enum command_result
command_break (int argc, char **argv)
{
int b;
uint16_t address;
enum command_result result;
if (argc == 1) {
for (b = 0; b < CC_NUM_BREAKPOINTS; b++)
if (breakpoints[b].enabled)
s51_printf("Breakpoint %d 0x%04x\n",
b, breakpoints[b].address);
return command_success;
}
if (argc != 2)
return command_error;
result = parse_uint16(argv[1], &address);
if (result != command_success)
return result;
return set_breakpoint(address, 0);
}
enum command_result
command_clear (int argc, char **argv)
{
uint16_t address;
enum command_result result;
if (argc != 2)
return command_error;
result = parse_uint16(argv[1], &address);
if (result != command_success)
return result;
return clear_breakpoint(address, 0);
}
static void
cc_stopped(uint8_t status)
{
uint16_t pc;
int b;
int code;
char *reason;
pc = ccdbg_get_pc(s51_dbg);
if (status & CC_STATUS_CPU_HALTED) {
if ((status & CC_STATUS_HALT_STATUS) != 0) {
pc = pc - 1;
code = 104;
reason = "Breakpoint";
b = find_breakpoint(pc);
if (b != -1 && breakpoints[b].temporary)
clear_breakpoint(pc, 1);
ccdbg_set_pc(s51_dbg, pc);
} else {
code = 105;
reason = "Interrupt";
}
s51_printf("Stop at 0x%04x: (%d) %s\n",
pc, code, reason);
}
}
static uint8_t
cc_step(uint16_t pc)
{
int b;
uint8_t status;
b = find_breakpoint(pc);
if (b != -1)
disable_breakpoint(b);
status = ccdbg_step_instr(s51_dbg);
if (b != -1)
enable_breakpoint(b);
return status;
}
enum command_result
command_run (int argc, char **argv)
{
uint16_t start, end;
enum command_result result;
uint16_t pc;
uint8_t status;
int b;
if (argv[1]) {
result = parse_uint16(argv[1], &start);
if (result != command_success)
return result;
if (argv[2]) {
result = parse_uint16(argv[2], &end);
if (result != command_success)
return result;
}
if (start_address && start == 0) {
start = start_address;
s51_printf("Starting at 0x%04x\n", start);
}
ccdbg_set_pc(s51_dbg, start);
}
else
start = ccdbg_get_pc(s51_dbg);
s51_printf("Resume at 0x%04x\n", start);
pc = start;
b = find_breakpoint(pc);
if (b != -1) {
cc_step(pc);
pc = ccdbg_get_pc(s51_dbg);
if (find_breakpoint(pc) != -1) {
status = ccdbg_read_status(s51_dbg);
cc_stopped(status);
return command_success;
}
}
ccdbg_resume(s51_dbg);
result = cc_wait();
return result;
}
enum command_result
command_next (int argc, char **argv)
{
return command_step(argc, argv);
}
enum command_result
command_step (int argc, char **argv)
{
uint16_t pc;
uint8_t opcode;
uint8_t a;
a = cc_step(ccdbg_get_pc(s51_dbg));
s51_printf(" ACC= 0x%02x\n", a);
pc = ccdbg_get_pc(s51_dbg);
ccdbg_read_memory(s51_dbg, pc, &opcode, 1);
s51_printf(" ? 0x%04x %02x\n", pc, opcode);
return command_success;
}
enum command_result
command_load (int argc, char **argv)
{
char *filename = argv[1];
FILE *file;
struct ao_hex_file *hex;
struct ao_hex_image *image;
if (!filename)
return command_error;
file = fopen(filename, "r");
if (!file) {
perror(filename);
return command_error;
}
hex = ao_hex_file_read(file, filename);
fclose(file);
if (!hex) {
return command_error;
}
image = ao_hex_image_create(hex);
ao_hex_file_free(hex);
if (!image) {
fprintf(stderr, "image create failed\n");
return command_error;
}
if (image->address >= 0xf000) {
printf("Loading %d bytes to RAM at 0x%04x\n",
image->length, image->address);
ccdbg_write_hex_image(s51_dbg, image, 0);
} else {
fprintf(stderr, "Can only load to RAM\n");
}
ao_hex_image_free(image);
return command_success;
}
enum command_result
command_halt (int argc, char **argv)
{
uint16_t pc;
ccdbg_halt(s51_dbg);
pc = ccdbg_get_pc(s51_dbg);
s51_printf("Halted at 0x%04x\n", pc);
return command_success;
}
enum command_result
command_stop (int argc, char **argv)
{
return command_success;
}
enum command_result
command_reset (int argc, char **argv)
{
ccdbg_debug_mode(s51_dbg);
ccdbg_halt(s51_dbg);
enable_breakpoints();
return command_success;
}
enum command_result
command_status(int argc, char **argv)
{
uint8_t status;
status = ccdbg_read_status(s51_dbg);
if ((status & CC_STATUS_CHIP_ERASE_DONE) == 0)
s51_printf("\tChip erase in progress\n");
if (status & CC_STATUS_PCON_IDLE)
s51_printf("\tCPU is idle (clock gated)\n");
if (status & CC_STATUS_CPU_HALTED)
s51_printf("\tCPU halted\n");
else
s51_printf("\tCPU running\n");
if ((status & CC_STATUS_POWER_MODE_0) == 0)
s51_printf("\tPower Mode 1-3 selected\n");
if (status & CC_STATUS_HALT_STATUS)
s51_printf("\tHalted by software or hw breakpoint\n");
else
s51_printf("\tHalted by debug command\n");
if (status & CC_STATUS_DEBUG_LOCKED)
s51_printf("\tDebug interface is locked\n");
if ((status & CC_STATUS_OSCILLATOR_STABLE) == 0)
s51_printf("\tOscillators are not stable\n");
if (status & CC_STATUS_STACK_OVERFLOW)
s51_printf("\tStack overflow\n");
return command_success;
}
static enum command_result
info_breakpoints(int argc, char **argv)
{
int b;
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;
}
return command_syntax;
}
static enum command_result
info_help(int argc, char **argv);
static struct command_function infos[] = {
{ "breakpoints", "b", info_breakpoints, "[b]reakpoints",
"List current breakpoints\n" },
{ "help", "?", info_help, "help",
"Print this list\n" },
{ NULL, NULL, NULL, NULL, NULL },
};
static enum command_result
info_help(int argc, char **argv)
{
return command_function_help(infos, argc, argv);
}
enum command_result
command_info(int argc, char **argv)
{
struct command_function *func;
if (argc < 2)
return command_error;
func = command_string_to_function(infos, argv[1]);
if (!func)
return command_syntax;
return (*func->func)(argc-1, argv+1);
}
enum command_result
cc_wait(void)
{
for(;;) {
uint8_t status;
status = ccdbg_read_status(s51_dbg);
if (status & CC_STATUS_CPU_HALTED) {
cc_stopped(status);
return command_success;
}
if (s51_interrupted || s51_check_input()) {
ccdbg_halt(s51_dbg);
status = ccdbg_read_status(s51_dbg);
cc_stopped(status);
return command_interrupt;
}
}
}

View File

@@ -0,0 +1,256 @@
/*
* 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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "ao-dbg.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdarg.h>
#include <poll.h>
#include <getopt.h>
static int s51_port = 0;
static char *cpu = "8051";
static double freq = 11059200;
char *s51_prompt = "> ";
struct ccdbg *s51_dbg;
int s51_interrupted = 0;
int s51_monitor = 0;
char *s51_tty = NULL;
char *s51_device = NULL;
static FILE *s51_input;
static FILE *s51_output;
static void
usage(void)
{
fprintf(stderr, "You're doing it wrong.\n");
exit(1);
}
static void
s51_sigint(int signum)
{
s51_interrupted = 1;
}
static const struct option options[] = {
{ .name = "tty", .has_arg = 1, .val = 'T' },
{ .name = "device", .has_arg = 1, .val = 'D' },
{ 0, 0, 0, 0 },
};
int
main(int argc, char **argv)
{
int opt;
char *endptr;
while ((opt = getopt_long(argc, argv, "PVvHhmt:X:c:r:Z:s:S:p:T:", options, NULL)) != -1) {
switch (opt) {
case 't':
cpu = optarg;
break;
case 'X':
freq = strtod(optarg, &endptr);
if (endptr == optarg)
usage();
if (endptr[0] != '\0') {
if (!strcmp(endptr, "k"))
freq *= 1000;
else if (!strcmp(endptr, "M") )
freq *= 1000000;
else
usage ();
}
break;
case 'c':
break;
case 'r':
case 'Z':
s51_port = strtol(optarg, &endptr, 0);
if (endptr == optarg || strlen(endptr) != 0)
usage();
break;
case 's':
break;
case 'S':
break;
case 'p':
s51_prompt = optarg;
break;
case 'P':
s51_prompt = NULL;
break;
case 'V':
break;
case 'v':
break;
case 'H':
exit (0);
break;
case 'h':
usage ();
break;
case 'm':
s51_monitor = 1;
break;
case 'T':
s51_tty = optarg;
break;
case 'D':
s51_device = optarg;
break;
}
}
if (s51_port) {
int l, r, one = 1;
int s;
struct sockaddr_in in;
l = socket(AF_INET, SOCK_STREAM, 0);
if (l < 0) {
perror ("socket");
exit(1);
}
r = setsockopt(l, SOL_SOCKET, SO_REUSEADDR, &one, sizeof (int));
if (r) {
perror("setsockopt");
exit(1);
}
in.sin_family = AF_INET;
in.sin_port = htons(s51_port);
in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
r = bind(l, (struct sockaddr *) &in, sizeof (in));
if (r) {
perror("bind");
exit(1);
}
r = listen(l, 5);
if (r) {
perror("listen");
exit(1);
}
for (;;) {
struct sockaddr_in client_addr;
socklen_t client_len = sizeof (struct sockaddr_in);
s = accept(l, (struct sockaddr *)
&client_addr, &client_len);
if (s < 0) {
perror("accept");
exit(1);
}
s51_input = fdopen(s, "r");
s51_output = fdopen(s, "w");
if (!s51_input || !s51_output) {
perror("fdopen");
exit(1);
}
signal(SIGINT, SIG_IGN);
command_read();
signal(SIGINT, SIG_DFL);
fclose(s51_input);
fclose(s51_output);
}
} else {
s51_input = stdin;
s51_output = stdout;
signal(SIGINT, s51_sigint);
command_read();
}
exit(0);
}
void
s51_printf(char *format, ...)
{
va_list ap;
va_start(ap, format);
vfprintf(s51_output, format, ap);
if (s51_monitor)
vfprintf(stdout, format, ap);
va_end(ap);
}
void
s51_putc(int c)
{
putc(c, s51_output);
}
#if HAVE_LIBREADLINE
#include <readline/readline.h>
#include <readline/history.h>
#endif
int
s51_read_line(char *line, int len)
{
int ret;
#if HAVE_LIBREADLINE
if (s51_output == stdout && s51_input == stdin && s51_prompt) {
char *r;
r = readline(s51_prompt);
if (r == NULL)
return 0;
strncpy (line, r, len);
line[len-1] = '\0';
add_history(r);
return 1;
} else
#endif
{
if (s51_prompt)
s51_printf("%s", s51_prompt);
else
s51_putc('\0');
fflush(s51_output);
ret = fgets(line, len, s51_input) != NULL;
if (s51_monitor)
printf("> %s", line);
fflush(stdout);
}
return ret;
}
int
s51_check_input(void)
{
struct pollfd input;
int r;
input.fd = fileno(s51_input);
input.events = POLLIN;
r = poll(&input, 1, 0);
if (r > 0) {
char line[256];
(void) s51_read_line(line, sizeof (line));
return 1;
}
return 0;
}

View File

@@ -0,0 +1,209 @@
/*
* 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 "ao-dbg.h"
static struct command_function functions[] = {
{ "help", "?", command_help, "help", "Print this list\n" },
{ "quit", "q", command_quit, "[q]uit", "Quit\n" },
{ "di", "di", command_di, "di <start> <end>",
"Dump imem\n" },
{ "ds", "ds", command_ds, "ds <start> <end>",
"Dump sprs\n" },
{ "dx", "dx", command_dx, "dx <start> <end>",
"Dump xaddr\n" },
{ "set", "t", command_set, "se[t] mem <prefix> <address> <data> ...",
"Set mem {xram|rom|iram|sfr}\n"
"set bit <addr>\n" },
{ "dump", "d", command_dump, "[d]ump <prefix> <start> <end>",
"Dump {xram|rom|iram|sfr} <start> <end>\n" },
{ "file", "file", command_file, "file <filename>",
"Pretend to load executable from <filename>\n" },
{ "pc", "p", command_pc, "[p]c [addr]",
"Get or set pc value\n" },
{ "break", "b", command_break,"[b]reak <addr>",
"Set break point\n" },
{ "clear", "c", command_clear,"[c]lear <addr>",
"Clear break point\n" },
{ "run", "r", command_run, "[r]un [start] [stop]",
"Run with optional start and temp breakpoint addresses\n" },
{ "go", "g", command_run, "[g]o [start] [stop]",
"Run with optional start and temp breakpoint addresses\n" },
{ "next", "n", command_next, "[n]ext",
"Step over one instruction, past any call\n" },
{ "step", "s", command_step, "[s]tep",
"Single step\n" },
{ "load", "l", command_load, "[l]oad <file>",
"Load a hex file into memory or flash" },
{ "halt", "h", command_halt, "[h]alt",
"Halt the processor\n" },
{ "reset","res",command_reset, "[res]et",
"Reset the CPU\n" },
{ "status","status",command_status, "status",
"Display CC1111 debug status\n" },
{ "info", "i", command_info, "[i]info",
"Get information\n" },
{ "stop", "stop", command_stop, "stop",
"Ignored\n" },
{ NULL, NULL, NULL, NULL, NULL },
};
#ifndef FALSE
#define FALSE 0
#define TRUE 1
#endif
struct command_function *
command_string_to_function(struct command_function *functions, char *name)
{
int i;
for (i = 0; functions[i].name; i++)
if (!strcmp(name, functions[i].name) ||
!strcmp(name, functions[i].alias))
return &functions[i];
return NULL;
}
enum command_result
command_function_help(struct command_function *functions, int argc, char **argv)
{
int i;
struct command_function *func;
if (argc == 1) {
for (i = 0; functions[i].name; i++)
s51_printf("%-10s%s\n", functions[i].name,
functions[i].usage);
} else {
for (i = 1; i < argc; i++) {
func = command_string_to_function(functions, argv[i]);
if (!func) {
s51_printf("%-10s unknown command\n", argv[i]);
return command_syntax;
}
s51_printf("%-10s %s\n%s", func->name,
func->usage, func->help);
}
}
return command_debug;
}
static int
command_split_into_words(char *line, char **argv)
{
char quotechar;
int argc;
argc = 0;
while (*line) {
while (isspace(*line))
line++;
if (!*line)
break;
if (*line == '"') {
quotechar = *line++;
*argv++ = line;
argc++;
while (*line && *line != quotechar)
line++;
if (*line)
*line++ = '\0';
} else {
*argv++ = line;
argc++;
while (*line && !isspace(*line))
line++;
if (*line)
*line++ = '\0';
}
}
*argv = 0;
return argc;
}
enum command_result
command_help(int argc, char **argv)
{
return command_function_help(functions, argc, argv);
}
void
command_syntax_error(int argc, char **argv)
{
s51_printf("Syntax error in:");
while (*argv)
s51_printf(" %s", *argv++);
s51_printf("\n");
}
void
command_read (void)
{
int argc;
char line[1024];
char *argv[20];
enum command_result result;
struct command_function *func;
if (!s51_tty) {
if (!s51_device)
s51_device = getenv("AO_DBG_DEVICE");
s51_tty = cc_usbdevs_find_by_arg(s51_device, "TeleDongle");
}
s51_dbg = ccdbg_open (s51_tty);
if (!s51_dbg)
exit(1);
ccdbg_debug_mode(s51_dbg);
ccdbg_halt(s51_dbg);
s51_printf("Welcome to the non-simulated processor\n");
for (;;) {
if (s51_read_line (line, sizeof line) == 0)
break;
s51_interrupted = 0;
argc = command_split_into_words(line, argv);
if (argc > 0) {
func = command_string_to_function(functions, argv[0]);
if (!func)
command_syntax_error(argc, argv);
else
{
result = (*func->func)(argc, argv);
if (s51_interrupted)
result = command_interrupt;
switch (result) {
case command_syntax:
command_syntax_error(argc, argv);
break;
case command_error:
s51_printf("Error\n");
break;
case command_success:
break;
case command_interrupt:
ccdbg_halt(s51_dbg);
s51_printf("Interrupted\n");
break;
default:
break;
}
}
}
}
ccdbg_close(s51_dbg);
s51_printf("...\n");
}

235
ao-tools/ao-dbg/ao-dbg.1 Normal file
View File

@@ -0,0 +1,235 @@
.\"
.\" 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; either version 2 of the License, or
.\" (at your option) any later version.
.\"
.\" This program is distributed in the hope that it will be useful, but
.\" WITHOUT ANY WARRANTY; without even the implied warranty of
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
.\" General Public License for more details.
.\"
.\" You should have received a copy of the GNU General Public License along
.\" with this program; if not, write to the Free Software Foundation, Inc.,
.\" 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
.\"
.\"
.TH AO-DBG 1 "ao-dbg" ""
.SH NAME
ao-dbg \- hex debugger for cc1111 processors
.SH SYNOPSIS
.B "ao-dbg"
[\-t \fIcpu-type\fP]
[\-X \fIfrequency\fP]
[\-c]
[\-r \fIlisten-port\fP]
[\-Z \fIlisten-port\fP]
[\-s]
[\-S]
[\-p \fIprompt\fP]
[\-V]
[\-v]
[\-H]
[\-h]
[\-m]
[\-T \fItty-device\fP]
[\--tty \fItty-device\fP]
[\-D \fIaltos-device\fP]
[\--device \fIaltos-device\fP]
.SH DESCRIPTION
.I ao-dbg
connects to a cc1111 processor through either a suitable cc1111 board
or a cp2103 usb to serial converter board, using the GPIO pins
available on that chip. It provides an interface compatible with the
8051 emulator from sdcc called s51, but communicating with the real
chip instead of an emulation. Using a modified version of the SDCC
debugger (sdcdb), you can control program execution on the target
machine at source-level.
.SH OPTIONS
The command line options are designed to be compatible with the 8051
emulator so that it can be used with sdcdb. As such, they're all one letter
long.
.IP "\-t \fIcpu-type\fP"
The 8051 emulator can operate as one of several different chips. Oddly, the
real hardware cannot, so this option is ignored.
.IP "\-X \fIfrequency\fP"
Similarly, the emulator can pretend to run at an arbitrary frequency
which the real hardware cannot do. Ignored.
.IP "\-c"
.IP "\-s"
.IP "\-S"
.IP "\-v"
.IP "\-V"
All ignored.
.IP "\-r \fIlisten-port\fP, -Z \fIlisten-port\fP"
The emulator and sdcdb communicate through a network socket. This option
switches the debugger from communicating through stdin/stdout to listening
on a specific network port instead. Once a connection is made, the debugger
continues on, using that network port for command input and output. The
debugger uses port 9756, and attempts to connect before launching ao-dbg, so if
ao-dbg is listening on this port before sdcdb is started, sdcdb will end up
talking to the existing ao-dbg instance. That's often useful for debugging ao-dbg
itself.
.IP "\-p \fIprompt\fP"
This sets the command prompt to the specified string.
.IP "\-P"
This sets the command prompt to a single NUL character. This is for use by
sdcdb.
.IP "\-h"
This should print a usage message, but does nothing useful currently.
.IP "\-m"
This option is not present in the original 8051 emulator, and causes ao-dbg to
dump all commands and replies that are received from and sent to sdcdb.
.TP
\-T tty-device | --tty tty-device
This selects which tty device the debugger uses to communicate with
the target device. The special name 'BITBANG' directs ao-dbg to use
the cp2103 connection, otherwise this should be a usb serial port
connected to a suitable cc1111 debug node.
.TP
\-D AltOS-device | --device AltOS-device
Search for a connected device. This requires an argument of one of the
following forms:
.IP
TeleMetrum:2
.br
TeleMetrum
.br
2
.IP
Leaving out the product name will cause the tool to select a suitable
product, leaving out the serial number will cause the tool to match
one of the available devices.
.SH COMMANDS
Once started, ao-dbg connects to the cc1111 and then reads and
executes commands, either from stdin, or the network connection to
sdcdb.
.PP
Unlike the command line, ao-dbg contains built-in help for each of these
commands, via the 'help' command. Most of the commands are available in a
long form and a single character short form. Below, the short form follows
the long form after a comma.
.IP "help, ? {command}"
Without arguments, prints a list of available commands. With an argument
prints more detail about the specific command
.IP "quit, q"
Terminates the application, without changing the state of the target
processor.
.IP "di [start] [end]"
Dumps imem (256 bytes of "internal" memory) from start to end (inclusive).
.IP "ds [start] [end]"
Dumps sprs from start to end (inclusive). Note that while most sprs are
visible in the global address space, some are not, so use this command
instead of "dx" to read them.
.IP "dx [start] [end]"
Dump external (global) memory from start to end (inclusive).
.IP "set, t <prefix> [start] {data ...}"
Store to the memory space specified by prefix where prefix is one of "xram",
"rom", "iram", or "sfr". Store bytes starting at start.
.IP "dump, d <prefix> [start] [end]"
Dump from the memory space specified by prefix, where prefix is one of
"xram", "rom", "iram" or "sfr". Dumps from start to end (inclusive).
.IP "file [filename]"
Specifies an intel-format hex file (ihx) that contains the contents of the
rom area loaded into the cc1111. This is used to respond to requests to dump
rom memory contents without getting them from the cc1111 (which is slow).
.IP "pc, p {address}"
If the address argument is given, this sets the program counter to the
specified value. Otherwise, the current program counter value is displayed.
.IP "break, b [address]"
Sets a breakpoint at the specified address. This uses the built-in hardware
breakpoint support in the cc1111. As a result, it supports no more than four
breakpoints at once. You must therefore use a modified version of sdcdb which
changes how program execution is controlled to work within this limit.
.IP "clear, c [address]"
Clear a breakpoint from the specified address.
.IP "run, r, go, g {start} {stop}"
Resumes execution of the program. If the start argument is present, then it
begins at that address, otherwise it continues running at the current pc. If
a stop argument is present, then a temporary breakpoint is set at that
address. This temporary breakpoint will be removed when execution hits it.
.IP "next, n"
Step one instruction. In the original s51 program this would ignore
subroutines, but as sdcdb doesn't require this functionality, it's not
available here.
.IP "step, s"
Step one instruction.
.IP "load, l [filename]"
This is not implemented, but it is supposed to load a hex file into flash.
Use the ccload program instead.
.IP "halt, h"
Halt the processor. This is the only command which can be sent while the
program is running. It is ignored at other times.
.IP "reset, res"
Reset the processor. This pulls the reset pin low and re-enables debug mode.
Check the cc1111 documentation to see precisely what this does.
.IP "status"
This dumps the cc1111 debug status register.
.IP "info, i breakpoints, b"
List the current breakpoints.
.IP "info, i help, ?"
List the things you can get info on.
.IP "stop"
This doesn't do anything and is present only to retain compatibility with
the original 8051 emulator.
.SH "BOARD BRINGUP DEBUGGING"
.PP
While the original purpose for this program was to connect the source
debugger with the hardware, it can also be used as a low-level hex debugger
all on its own. In particular, all of the cc1111 peripherals can be
manipulated directly from the ao-dbg command line.
.IP "Starting ao-dbg"
First ensure that the target cc1111 device and intermediate cp2103 or
cc111 board are all hooked up correctly.
.IP
$ ao-dbg
.br
Welcome to the non-simulated processor
.br
> status
.br
CPU halted
.br
Halted by debug command
.br
>
.IP "Turning on LEDs"
Two of the cc1111 GPIO pins, P1_0 and P1_1 are capable of driving external
LEDs. To control these, set the Port 1 direction bits to make these output
pins and then change the Port 1 data to set them high or low:
.IP
> set sfr 0xfe 0x02 # set P1DIR to 0x2
.br
> set sfr 0x90 0x02 # set P1_1 to high
.br
> set sfr 0x90 0x00 # set P1_1 to low
.IP "Reading the A/D converters"
The six A/D converter inputs can each be connected to any of the P0 pins,
ground, the A/D voltage reference, an internal temperature sensor or VDD/3.
To read one of these values, select an A/D converter to use then start the
conversion process. The cc1111 manual has the table for selecting the input
on page 144.
.IP
To configure one of the P0 pins for use by the A/D unit, we program the
ADCCFG register, setting the bits in that which match the pins desired:
.IP
> set sfr 0xf2 0x3f # enable all 6 A/D inputs
.IP
To trigger a single conversion, we ask the A/D unit to perform an 'extra'
conversion, which means to do a single conversion not a whole sequence of
conversions. This is controlled by the ADCCON3 register at 0xB6:
.IP
> set sfr 0xb6 0xb2 # sample P0_2 using 12 bits of precision
.br
> ds 0xba 0xbb # dump the ADC data low and high regs
.br
> set sfr 0xb6 0xbe # sample internal temperature sensor
.br
> ds 0xba 0xbb # dump the ADC data low and high regs
.SH "SEE ALSO"
sdcdb(1), ccload(1)
.SH AUTHOR
Keith Packard

127
ao-tools/ao-dbg/ao-dbg.h Normal file
View File

@@ -0,0 +1,127 @@
/*
* 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 <cc.h>
#include <ctype.h>
extern char *s51_prompt;
extern struct ccdbg *s51_dbg;
extern int s51_interrupted;
extern int s51_monitor;
extern char *s51_tty;
extern char *s51_device;
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);
enum command_result
command_ds (int argc, char **argv);
enum command_result
command_dx (int argc, char **argv);
enum command_result
command_set (int argc, char **argv);
enum command_result
command_dump (int argc, char **argv);
enum command_result
command_file (int argc, char **argv);
enum command_result
command_pc (int argc, char **argv);
enum command_result
command_break (int argc, char **argv);
enum command_result
command_clear (int argc, char **argv);
enum command_result
command_run (int argc, char **argv);
enum command_result
command_next (int argc, char **argv);
enum command_result
command_step (int argc, char **argv);
enum command_result
command_load (int argc, char **argv);
enum command_result
command_halt (int argc, char **argv);
enum command_result
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);
void
command_read (void);
void
s51_printf(char *format, ...);
void
s51_putc(int c);
int
s51_check_input(void);
int
s51_read_line(char *line, int len);

60
ao-tools/ao-dbg/commands Normal file
View File

@@ -0,0 +1,60 @@
Listens on port 9756 for a command stream.
Dump commands:
di <start> <end> - dump imem
ds <start> <end> - dump sprs
dx <start> <end> - dump xaddr
Returns a string of hex pairs, each preceded by a space,
with 8 pairs per line
Memory access commands:
set mem <prefix> <start> <end>
dump <prefix> <start> <end>
<prefix> is one of:
xram - external ram or external stack
rom - code space
iram - internal ram or stack
sfr - special function register
dump <addr>
set bit <addr>
bit addressable space
Set PC:
pc <addr>
Sets PC to specified address
pc
Returns current PC
Breakpoints
break <addr>
clear <addr>
Load a file
file "<filename>"
Execution control:
run <start> - run starting at <start>
run <start> <stop> - set temporary bp at <stop>
run - continue
next - step over calls(?)
step - step one instruction
reset - reset the simulator
res - synonym?
Error messages:
start with "Error:"