From 1cf738536477d8e5b7002d9d6554b8bb56309b4d Mon Sep 17 00:00:00 2001 From: Daniel Beer Date: Thu, 10 Mar 2011 11:57:06 +1300 Subject: [PATCH] simio: implemented tracer peripheral. --- Makefile | 2 +- simio.c | 30 ++-- simio_cpu.h | 2 +- simio_device.h | 8 +- simio_tracer.c | 367 +++++++++++++++++++++++++++++++++++++++++++++++++ simio_tracer.h | 24 ++++ 6 files changed, 420 insertions(+), 13 deletions(-) create mode 100644 simio_tracer.c create mode 100644 simio_tracer.h diff --git a/Makefile b/Makefile index d5d1f8d..8c619e6 100644 --- a/Makefile +++ b/Makefile @@ -63,7 +63,7 @@ mspdebug: main.o fet.o rf2500.o dis.o uif.o olimex.o ihex.o elf32.o stab.o \ util.o bsl.o sim.o symmap.o gdb.o btree.o rtools.o sym.o devcmd.o \ reader.o vector.o output_util.o expr.o fet_error.o binfile.o \ fet_db.o usbutil.o titext.o srec.o device.o coff.o opdb.o output.o \ - cmddb.o stdcmd.o prog.o flash_bsl.o list.o simio.o + cmddb.o stdcmd.o prog.o flash_bsl.o list.o simio.o simio_tracer.o $(CC) $(LDFLAGS) $(PORTS_LDFLAGS) -o $@ $^ -lusb $(READLINE_LIBS) .c.o: diff --git a/simio.c b/simio.c index 872271f..a62f548 100644 --- a/simio.c +++ b/simio.c @@ -24,8 +24,10 @@ #include "simio_cpu.h" #include "simio_device.h" +#include "simio_tracer.h" + static const struct simio_class *const class_db[] = { - /* FIXME: nothing here yet */ + &simio_tracer }; /* Simulator data. We keep a list of devices on the bus, and the special @@ -53,7 +55,7 @@ void simio_init(void) void simio_exit(void) { while (!LIST_EMPTY(&device_list)) - destroy_device((struct simio_device *)&device_list.next); + destroy_device((struct simio_device *)device_list.next); } static const struct simio_class *find_class(const char *name) @@ -86,13 +88,13 @@ static struct simio_device *find_device(const char *name) static int cmd_add(char **arg_text) { - const char *name_text = get_arg(arg_text); const char *type_text = get_arg(arg_text); + const char *name_text = get_arg(arg_text); const struct simio_class *type; struct simio_device *dev; if (!(name_text && type_text)) { - printc_err("simio add: device name and class must be " + printc_err("simio add: device class and name must be " "specified.\n"); return -1; } @@ -150,7 +152,7 @@ static int cmd_devices(char **arg_text) struct list_node *n; for (n = device_list.next; n != &device_list; n = n->next) { - struct simio_device *dev = (struct simio_device *)&n; + struct simio_device *dev = (struct simio_device *)n; int irq = dev->type->check_interrupt(dev); printc(" %-10s (type %s", dev->name, dev->type->name); @@ -200,7 +202,7 @@ static int cmd_help(char **arg_text) return -1; } - printc("\x1b[1mDEVICE CLASS: %s\x1b[0m\n%s\n", type->name, type->help); + printc("\x1b[1mDEVICE CLASS: %s\x1b[0m\n\n%s\n", type->name, type->help); return 0; } @@ -276,8 +278,18 @@ int cmd_simio(char **arg_text) void simio_reset(void) { + struct list_node *n; + memset(sfr_data, 0, sizeof(sfr_data)); aclk_counter = 0; + + for (n = device_list.next; n != &device_list; n = n->next) { + struct simio_device *dev = (struct simio_device *)n; + const struct simio_class *type = dev->type; + + if (type->reset) + type->reset(dev); + } } #define IO_REQUEST_FUNC(name, method, datatype) \ @@ -325,7 +337,7 @@ int simio_check_interrupt(void) return irq; } -void simio_ack_interrupt(void) +void simio_ack_interrupt(int irq) { struct list_node *n; @@ -334,13 +346,13 @@ void simio_ack_interrupt(void) const struct simio_class *type = dev->type; if (type->ack_interrupt) - type->ack_interrupt(dev); + type->ack_interrupt(dev, irq); } } void simio_step(uint16_t status_register, int cycles) { - int clocks[3] = {0}; + int clocks[SIMIO_NUM_CLOCKS] = {0}; struct list_node *n; aclk_counter += cycles; diff --git a/simio_cpu.h b/simio_cpu.h index 0fd825c..099516f 100644 --- a/simio_cpu.h +++ b/simio_cpu.h @@ -50,7 +50,7 @@ int simio_check_interrupt(void); /* When the CPU begins to handle an interrupt, it needs to notify the IO * simulation. Some interrupt flags are cleared automatically when handled. */ -void simio_ack_interrupt(void); +void simio_ack_interrupt(int irq); /* This should be called after executing an instruction to advance the system * clocks. diff --git a/simio_device.h b/simio_device.h index 7b140a3..0a1e5e9 100644 --- a/simio_device.h +++ b/simio_device.h @@ -29,7 +29,8 @@ typedef enum { SIMIO_MCLK = 0, SIMIO_SMCLK, - SIMIO_ACLK + SIMIO_ACLK, + SIMIO_NUM_CLOCKS } simio_clock_t; /* Access to special function registers is provided by these functions. The @@ -72,6 +73,9 @@ struct simio_class { char **arg_text); int (*info)(struct simio_device *dev); + /* System reset hook. */ + void (*reset)(struct simio_device *dev); + /* Programmed IO functions return 1 to indicate an unhandled * request. This scheme allows stacking. */ @@ -88,7 +92,7 @@ struct simio_class { * a single interrupt request at any time. */ int (*check_interrupt)(struct simio_device *dev); - void (*ack_interrupt)(struct simio_device *dev); + void (*ack_interrupt)(struct simio_device *dev, int irq); /* Run the clocks for this device. The counters array has one * array per clock, and gives the number of cycles elapsed since diff --git a/simio_tracer.c b/simio_tracer.c new file mode 100644 index 0000000..eee7b2b --- /dev/null +++ b/simio_tracer.c @@ -0,0 +1,367 @@ +/* MSPDebug - debugging tool for MSP430 MCUs + * Copyright (C) 2009, 2010 Daniel Beer + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include "simio_device.h" +#include "simio_tracer.h" +#include "expr.h" +#include "output.h" + +#define DEFAULT_HISTORY 16 + +typedef enum { + EVENT_WRITE_16, + EVENT_READ_16, + EVENT_WRITE_8, + EVENT_READ_8, + EVENT_IRQ_HANDLE, + EVENT_RESET +} event_type_t; + +typedef unsigned long long counter_t; + +struct event { + counter_t when; + event_type_t what; + address_t addr; + uint16_t data; +}; + +struct tracer { + struct simio_device base; + + /* IO event history ring buffer. */ + struct event *history; + int size; + int head; + int tail; + + /* Clock and instruction counters. */ + counter_t cycles[SIMIO_NUM_CLOCKS]; + counter_t inscount; + + /* Outstanding interrupt request. */ + int irq_request; + + /* Verbose mode. */ + int verbose; +}; + +static void print_address(address_t addr) +{ + char name[64]; + address_t offset; + + printc("0x%04x", addr); + if (!stab_nearest(stab_default, addr, name, sizeof(name), &offset)) { + printc(" (%s", name); + if (offset) + printc("+0x%x", offset); + printc(")"); + } +} + +static void event_print(const struct event *e) +{ + printc(" %10lld: ", e->when); + + switch (e->what) { + case EVENT_WRITE_16: + printc("write.w "); + print_address(e->addr); + printc(" => 0x%04x\n", e->data); + break; + + case EVENT_READ_16: + printc("read.w "); + print_address(e->addr); + printc("\n"); + break; + + case EVENT_WRITE_8: + printc("write.b "); + print_address(e->addr); + printc(" => 0x%02x\n", e->data); + break; + + case EVENT_READ_8: + printc("read.b "); + print_address(e->addr); + printc("\n"); + break; + + case EVENT_IRQ_HANDLE: + printc("irq handle %d\n", e->addr); + break; + + case EVENT_RESET: + printc("system reset\n"); + break; + + default: + printc("unknown 0x%04x 0x%04x\n", e->addr, e->data); + break; + } +} + +static void event_rec(struct tracer *tr, event_type_t what, + address_t addr, uint16_t data) +{ + struct event *e = &tr->history[tr->head]; + + e->when = tr->cycles[SIMIO_MCLK]; + e->what = what; + e->addr = addr; + e->data = data; + + if (tr->verbose) + event_print(e); + + tr->head = (tr->head + 1) % tr->size; + if (tr->head == tr->tail) + tr->tail = (tr->tail + 1) % tr->size; +} + +static struct simio_device *tracer_create(char **arg_text) +{ + const char *size_text = get_arg(arg_text); + int size = DEFAULT_HISTORY; + struct event *history; + struct tracer *tr; + + if (size_text) { + address_t value; + + if (expr_eval(stab_default, size_text, &value) < 0) { + printc_err("tracer: can't parse history size: %s\n", + size_text); + return NULL; + } + + size = value; + if (size < 2) { + printc_err("tracer: invalid size: %d\n", size); + return NULL; + } + } + + history = malloc(sizeof(history[0]) * size); + if (!history) { + pr_error("tracer: couldn't allocate memory for history\n"); + return NULL; + } + + tr = malloc(sizeof(*tr)); + if (!tr) { + pr_error("tracer: couldn't allocate memory\n"); + return NULL; + } + + memset(tr, 0, sizeof(*tr)); + tr->base.type = &simio_tracer; + tr->history = history; + tr->size = size; + tr->irq_request = -1; + + return (struct simio_device *)tr; +} + +static void tracer_destroy(struct simio_device *dev) +{ + struct tracer *tr = (struct tracer *)dev; + + free(tr->history); + free(tr); +} + +static void tracer_reset(struct simio_device *dev) +{ + struct tracer *tr = (struct tracer *)dev; + + event_rec(tr, EVENT_RESET, 0, 0); +} + +static int tracer_config(struct simio_device *dev, + const char *param, char **arg_text) +{ + struct tracer *tr = (struct tracer *)dev; + + if (!strcasecmp(param, "verbose")) + tr->verbose = 1; + else if (!strcasecmp(param, "quiet")) + tr->verbose = 0; + else if (!strcasecmp(param, "untrigger")) + tr->irq_request = -1; + else if (!strcasecmp(param, "clear")) { + tr->head = 0; + tr->tail = 0; + } else if (!strcasecmp(param, "trigger")) { + const char *irq_text = get_arg(arg_text); + address_t value; + + if (!irq_text) { + printc_err("tracer: trigger: must specify an IRQ " + "number\n"); + return -1; + } + + if (expr_eval(stab_default, irq_text, &value) < 0) { + printc_err("tracer: trigger: can't parse IRQ " + "number: %s\n", irq_text); + return -1; + } + + if (value < 0 || value >= 16) { + printc_err("tracer: trigger: invalid IRQ: %d\n", + value); + return -1; + } + + tr->irq_request = value; + } else { + printc_err("tracer: unknown config parameter: %s\n", param); + return -1; + } + + return 0; +} + +static int tracer_info(struct simio_device *dev) +{ + struct tracer *tr = (struct tracer *)dev; + int i; + + printc("Instruction count: %lld\n", tr->inscount); + printc("MCLK: %lld\n", tr->cycles[SIMIO_MCLK]); + printc("SMCLK %lld\n", tr->cycles[SIMIO_SMCLK]); + printc("ACLK: %lld\n", tr->cycles[SIMIO_ACLK]); + + if (tr->irq_request >= 0) + printc("IRQ pending: %d\n", tr->irq_request); + else + printc("No IRQ is pending\n"); + + printc("\nIO event history (oldest first):\n"); + for (i = tr->tail; i != tr->head; i = (i + 1) % tr->size) + event_print(&tr->history[i]); + + return 0; +} + +static int tracer_write(struct simio_device *dev, + address_t addr, uint16_t data) +{ + struct tracer *tr = (struct tracer *)dev; + + event_rec(tr, EVENT_WRITE_16, addr, data); + return 1; +} + +static int tracer_read(struct simio_device *dev, + address_t addr, uint16_t *data) +{ + struct tracer *tr = (struct tracer *)dev; + + event_rec(tr, EVENT_READ_16, addr, 0); + return 1; +} + +static int tracer_write_b(struct simio_device *dev, + address_t addr, uint8_t data) +{ + struct tracer *tr = (struct tracer *)dev; + + event_rec(tr, EVENT_WRITE_8, addr, data); + return 1; +} + +static int tracer_read_b(struct simio_device *dev, + address_t addr, uint8_t *data) +{ + struct tracer *tr = (struct tracer *)dev; + + event_rec(tr, EVENT_READ_8, addr, 0); + return 1; +} + +static int tracer_check_interrupt(struct simio_device *dev) +{ + struct tracer *tr = (struct tracer *)dev; + + return tr->irq_request; +} + +static void tracer_ack_interrupt(struct simio_device *dev, int irq) +{ + struct tracer *tr = (struct tracer *)dev; + + if (tr->irq_request == irq) + tr->irq_request = -1; + + event_rec(tr, EVENT_IRQ_HANDLE, irq, 0); +} + +static void tracer_step(struct simio_device *dev, + uint16_t addr, const int *clocks) +{ + struct tracer *tr = (struct tracer *)dev; + int i; + + for (i = 0; i < SIMIO_NUM_CLOCKS; i++) + tr->cycles[i] += clocks[i]; + + tr->inscount++; +} + +const struct simio_class simio_tracer = { + .name = "tracer", + .help = +"A debug peripheral to implement IO tracing. This will keep a record of\n" +"IO activity which can be checked at any time. It can also be used to\n" +"manually trigger interrupts.\n" +"\n" +"Constructor arguments: [history-size]\n" +" If specified, enlarge the IO event history from its default size.\n" +"\n" +"Config arguments are:\n" +" verbose\n" +" Show IO events as they occur.\n" +" quiet\n" +" Only show IO events when requested (default).\n" +" trigger \n" +" Trigger an specific IRQ vector.\n" +" untrigger\n" +" Cancel an interrupt request.\n" +" clear\n" +" Clear the IO history and counter so far.\n", + + .create = tracer_create, + .destroy = tracer_destroy, + .reset = tracer_reset, + .config = tracer_config, + .info = tracer_info, + .write = tracer_write, + .read = tracer_read, + .write_b = tracer_write_b, + .read_b = tracer_read_b, + .check_interrupt = tracer_check_interrupt, + .ack_interrupt = tracer_ack_interrupt, + .step = tracer_step +}; diff --git a/simio_tracer.h b/simio_tracer.h new file mode 100644 index 0000000..6180080 --- /dev/null +++ b/simio_tracer.h @@ -0,0 +1,24 @@ +/* MSPDebug - debugging tool for MSP430 MCUs + * Copyright (C) 2009, 2010 Daniel Beer + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SIMIO_TRACER_H_ +#define SIMIO_TRACER_H_ + +extern const struct simio_class simio_tracer; + +#endif