simio: added "simio" command and device/CPU interfaces.
This commit is contained in:
parent
115683c8bc
commit
5f40c55f4e
4
Makefile
4
Makefile
|
@ -16,7 +16,7 @@
|
||||||
# along with this program; if not, write to the Free Software
|
# along with this program; if not, write to the Free Software
|
||||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
CC ?= gcc
|
CC = gcc
|
||||||
INSTALL = /usr/bin/install
|
INSTALL = /usr/bin/install
|
||||||
PREFIX ?= /usr/local
|
PREFIX ?= /usr/local
|
||||||
LDFLAGS ?= -s
|
LDFLAGS ?= -s
|
||||||
|
@ -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 \
|
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 \
|
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 \
|
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
|
cmddb.o stdcmd.o prog.o flash_bsl.o list.o simio.o
|
||||||
$(CC) $(LDFLAGS) $(PORTS_LDFLAGS) -o $@ $^ -lusb $(READLINE_LIBS)
|
$(CC) $(LDFLAGS) $(PORTS_LDFLAGS) -o $@ $^ -lusb $(READLINE_LIBS)
|
||||||
|
|
||||||
.c.o:
|
.c.o:
|
||||||
|
|
20
cmddb.c
20
cmddb.c
|
@ -26,6 +26,7 @@
|
||||||
#include "rtools.h"
|
#include "rtools.h"
|
||||||
#include "sym.h"
|
#include "sym.h"
|
||||||
#include "stdcmd.h"
|
#include "stdcmd.h"
|
||||||
|
#include "simio.h"
|
||||||
|
|
||||||
const struct cmddb_record commands[] = {
|
const struct cmddb_record commands[] = {
|
||||||
{
|
{
|
||||||
|
@ -240,6 +241,25 @@ const struct cmddb_record commands[] = {
|
||||||
.help =
|
.help =
|
||||||
"exit\n"
|
"exit\n"
|
||||||
" Exit from MSPDebug.\n"
|
" Exit from MSPDebug.\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "simio",
|
||||||
|
.func = cmd_simio,
|
||||||
|
.help =
|
||||||
|
"simio add <class> <name> [args ...]\n"
|
||||||
|
" Add a new device to the IO simulator's bus.\n"
|
||||||
|
"simio del <name>\n"
|
||||||
|
" Delete a device from the bus.\n"
|
||||||
|
"simio devices\n"
|
||||||
|
" Show all devices attached to the bus.\n"
|
||||||
|
"simio classes\n"
|
||||||
|
" Show the types of devices which may be attached.\n"
|
||||||
|
"simio help <class>\n"
|
||||||
|
" Obtain more information about a device type.\n"
|
||||||
|
"simio config <name> <param> [args ...]\n"
|
||||||
|
" Change settings of an attached device.\n"
|
||||||
|
"simio info <name>\n"
|
||||||
|
" Print status information for an attached device.\n"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
/* 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 <stdlib.h>
|
||||||
|
#include "list.h"
|
||||||
|
|
||||||
|
void list_init(struct list_node *head)
|
||||||
|
{
|
||||||
|
head->next = head;
|
||||||
|
head->prev = head;
|
||||||
|
}
|
||||||
|
|
||||||
|
void list_insert(struct list_node *item, struct list_node *after)
|
||||||
|
{
|
||||||
|
item->next = after;
|
||||||
|
item->prev = after->prev;
|
||||||
|
|
||||||
|
after->prev->next = item;
|
||||||
|
after->prev = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
void list_remove(struct list_node *item)
|
||||||
|
{
|
||||||
|
item->next->prev = item->prev;
|
||||||
|
item->prev->next = item->next;
|
||||||
|
|
||||||
|
item->prev = NULL;
|
||||||
|
item->next = NULL;
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
/* 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 LIST_H_
|
||||||
|
#define LIST_H_
|
||||||
|
|
||||||
|
/* This is the list node definition. It's intended to be embedded within
|
||||||
|
* another data structure.
|
||||||
|
*
|
||||||
|
* All lists are circular and doubly-linked. So, to iterate over the
|
||||||
|
* members of a list, do something like this:
|
||||||
|
*
|
||||||
|
* struct list_node *n;
|
||||||
|
*
|
||||||
|
* for (n = list->next; n != list; n = n->next) {
|
||||||
|
* ...
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* An empty list must be created first with list_init(). This sets the
|
||||||
|
* next and prev pointers to the list head itself.
|
||||||
|
*/
|
||||||
|
struct list_node {
|
||||||
|
struct list_node *next;
|
||||||
|
struct list_node *prev;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Check to see if a list contains anything. */
|
||||||
|
#define LIST_EMPTY(h) ((h)->next == (h))
|
||||||
|
|
||||||
|
/* Create an empty list */
|
||||||
|
void list_init(struct list_node *head);
|
||||||
|
|
||||||
|
/* Add an item to a list. The item will appear before the item
|
||||||
|
* specified as after.
|
||||||
|
*/
|
||||||
|
void list_insert(struct list_node *item, struct list_node *after);
|
||||||
|
|
||||||
|
/* Remove a node from its containing list. */
|
||||||
|
void list_remove(struct list_node *item);
|
||||||
|
|
||||||
|
#endif
|
5
main.c
5
main.c
|
@ -38,6 +38,7 @@
|
||||||
#include "opdb.h"
|
#include "opdb.h"
|
||||||
#include "reader.h"
|
#include "reader.h"
|
||||||
#include "output.h"
|
#include "output.h"
|
||||||
|
#include "simio.h"
|
||||||
|
|
||||||
#include "sim.h"
|
#include "sim.h"
|
||||||
#include "bsl.h"
|
#include "bsl.h"
|
||||||
|
@ -511,6 +512,8 @@ int main(int argc, char **argv)
|
||||||
if (setup_driver(&args) < 0)
|
if (setup_driver(&args) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
simio_init();
|
||||||
|
|
||||||
if (!args.no_rc)
|
if (!args.no_rc)
|
||||||
process_rc_file();
|
process_rc_file();
|
||||||
|
|
||||||
|
@ -527,6 +530,8 @@ int main(int argc, char **argv)
|
||||||
reader_loop();
|
reader_loop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
simio_exit();
|
||||||
|
|
||||||
stab_destroy(stab_default);
|
stab_destroy(stab_default);
|
||||||
device_default->destroy(device_default);
|
device_default->destroy(device_default);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,384 @@
|
||||||
|
/* 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 <string.h>
|
||||||
|
|
||||||
|
#include "output.h"
|
||||||
|
#include "dis.h"
|
||||||
|
#include "simio.h"
|
||||||
|
#include "simio_cpu.h"
|
||||||
|
#include "simio_device.h"
|
||||||
|
|
||||||
|
static const struct simio_class *const class_db[] = {
|
||||||
|
/* FIXME: nothing here yet */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Simulator data. We keep a list of devices on the bus, and the special
|
||||||
|
* function registers.
|
||||||
|
*
|
||||||
|
* Currently, MCLK and SMCLK are tied together, and ACLK runs at a fixed
|
||||||
|
* ratio of 1:256 with MCLK. aclk_counter counts fractional cycles.
|
||||||
|
*/
|
||||||
|
static struct list_node device_list;
|
||||||
|
static uint8_t sfr_data[16];
|
||||||
|
static int aclk_counter;
|
||||||
|
|
||||||
|
static void destroy_device(struct simio_device *dev)
|
||||||
|
{
|
||||||
|
list_remove(&dev->node);
|
||||||
|
dev->type->destroy(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void simio_init(void)
|
||||||
|
{
|
||||||
|
list_init(&device_list);
|
||||||
|
simio_reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void simio_exit(void)
|
||||||
|
{
|
||||||
|
while (!LIST_EMPTY(&device_list))
|
||||||
|
destroy_device((struct simio_device *)&device_list.next);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct simio_class *find_class(const char *name)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_LEN(class_db); i++) {
|
||||||
|
const struct simio_class *t = class_db[i];
|
||||||
|
|
||||||
|
if (!strcasecmp(t->name, name))
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct simio_device *find_device(const char *name)
|
||||||
|
{
|
||||||
|
struct list_node *n;
|
||||||
|
|
||||||
|
for (n = device_list.next; n != &device_list; n = n->next) {
|
||||||
|
struct simio_device *dev = (struct simio_device *)n;
|
||||||
|
|
||||||
|
if (!strcasecmp(dev->name, name))
|
||||||
|
return dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmd_add(char **arg_text)
|
||||||
|
{
|
||||||
|
const char *name_text = get_arg(arg_text);
|
||||||
|
const char *type_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 "
|
||||||
|
"specified.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (find_device(name_text)) {
|
||||||
|
printc_err("simio add: device name is not unique: %s\n",
|
||||||
|
name_text);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = find_class(type_text);
|
||||||
|
if (!type) {
|
||||||
|
printc_err("simio add: unknown type.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev = type->create(arg_text);
|
||||||
|
if (!dev) {
|
||||||
|
printc_err("simio add: failed to create device.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_insert(&dev->node, &device_list);
|
||||||
|
strncpy(dev->name, name_text, sizeof(dev->name));
|
||||||
|
dev->name[sizeof(dev->name) - 1] = 0;
|
||||||
|
|
||||||
|
printc_dbg("Added new device \"%s\" of type \"%s\".\n",
|
||||||
|
dev->name, dev->type->name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmd_del(char **arg_text)
|
||||||
|
{
|
||||||
|
const char *name_text = get_arg(arg_text);
|
||||||
|
struct simio_device *dev;
|
||||||
|
|
||||||
|
if (!name_text) {
|
||||||
|
printc_err("simio del: device name must be specified.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev = find_device(name_text);
|
||||||
|
if (!dev) {
|
||||||
|
printc_err("simio del: no such device: %s\n", name_text);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy_device(dev);
|
||||||
|
printc_dbg("Destroyed device \"%s\".\n", name_text);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
int irq = dev->type->check_interrupt(dev);
|
||||||
|
|
||||||
|
printc(" %-10s (type %s", dev->name, dev->type->name);
|
||||||
|
if (irq < 0)
|
||||||
|
printc(")\n");
|
||||||
|
else
|
||||||
|
printc(", IRQ pending: %d)\n", irq);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmd_classes(char **arg_text)
|
||||||
|
{
|
||||||
|
struct vector v;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
vector_init(&v, sizeof(const char *));
|
||||||
|
for (i = 0; i < ARRAY_LEN(class_db); i++) {
|
||||||
|
if (vector_push(&v, &class_db[i]->name, 1) < 0) {
|
||||||
|
printc_err("simio classes: can't allocate memory\n");
|
||||||
|
vector_destroy(&v);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printc("Available device classes:\n");
|
||||||
|
namelist_print(&v);
|
||||||
|
vector_destroy(&v);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmd_help(char **arg_text)
|
||||||
|
{
|
||||||
|
const char *name = get_arg(arg_text);
|
||||||
|
const struct simio_class *type;
|
||||||
|
|
||||||
|
if (!name) {
|
||||||
|
printc_err("simio help: you must specify a device class\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = find_class(name);
|
||||||
|
if (!type) {
|
||||||
|
printc_err("simio help: unknown device class: %s\n", name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printc("\x1b[1mDEVICE CLASS: %s\x1b[0m\n%s\n", type->name, type->help);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmd_config(char **arg_text)
|
||||||
|
{
|
||||||
|
const char *name = get_arg(arg_text);
|
||||||
|
const char *param = get_arg(arg_text);
|
||||||
|
struct simio_device *dev;
|
||||||
|
|
||||||
|
if (!(name && param)) {
|
||||||
|
printc_err("simio config: you must specify a device name and "
|
||||||
|
"a parameter\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev = find_device(name);
|
||||||
|
if (!dev) {
|
||||||
|
printc_err("simio config: no such device: %s\n", name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dev->type->config(dev, param, arg_text);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmd_info(char **arg_text)
|
||||||
|
{
|
||||||
|
const char *name = get_arg(arg_text);
|
||||||
|
struct simio_device *dev;
|
||||||
|
|
||||||
|
if (!name) {
|
||||||
|
printc_err("simio info: you must specify a device name\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev = find_device(name);
|
||||||
|
if (!dev) {
|
||||||
|
printc_err("simio info: no such device: %s\n", name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dev->type->info(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmd_simio(char **arg_text)
|
||||||
|
{
|
||||||
|
const char *subcmd = get_arg(arg_text);
|
||||||
|
static const struct {
|
||||||
|
const char *name;
|
||||||
|
int (*func)(char **arg_text);
|
||||||
|
} cmd_table[] = {
|
||||||
|
{"add", cmd_add},
|
||||||
|
{"del", cmd_del},
|
||||||
|
{"devices", cmd_devices},
|
||||||
|
{"classes", cmd_classes},
|
||||||
|
{"help", cmd_help},
|
||||||
|
{"config", cmd_config},
|
||||||
|
{"info", cmd_info}
|
||||||
|
};
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!subcmd) {
|
||||||
|
printc_err("simio: a subcommand is required\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_LEN(cmd_table); i++)
|
||||||
|
if (!strcasecmp(cmd_table[i].name, subcmd))
|
||||||
|
return cmd_table[i].func(arg_text);
|
||||||
|
|
||||||
|
printc_err("simio: unknown subcommand: %s\n", subcmd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void simio_reset(void)
|
||||||
|
{
|
||||||
|
memset(sfr_data, 0, sizeof(sfr_data));
|
||||||
|
aclk_counter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define IO_REQUEST_FUNC(name, method, datatype) \
|
||||||
|
int name(address_t addr, datatype data) { \
|
||||||
|
struct list_node *n; \
|
||||||
|
int ret = 1; \
|
||||||
|
\
|
||||||
|
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->method) { \
|
||||||
|
int r = type->method(dev, addr, data); \
|
||||||
|
\
|
||||||
|
if (r < ret) \
|
||||||
|
ret = r; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
return ret; \
|
||||||
|
}
|
||||||
|
|
||||||
|
IO_REQUEST_FUNC(simio_write, write, uint16_t)
|
||||||
|
IO_REQUEST_FUNC(simio_read, read, uint16_t *)
|
||||||
|
IO_REQUEST_FUNC(simio_write_b, write_b, uint8_t)
|
||||||
|
IO_REQUEST_FUNC(simio_read_b, read_b, uint8_t *)
|
||||||
|
|
||||||
|
int simio_check_interrupt(void)
|
||||||
|
{
|
||||||
|
int irq = -1;
|
||||||
|
struct list_node *n;
|
||||||
|
|
||||||
|
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->check_interrupt) {
|
||||||
|
int i = type->check_interrupt(dev);
|
||||||
|
|
||||||
|
if (i > irq)
|
||||||
|
irq = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return irq;
|
||||||
|
}
|
||||||
|
|
||||||
|
void simio_ack_interrupt(void)
|
||||||
|
{
|
||||||
|
struct list_node *n;
|
||||||
|
|
||||||
|
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->ack_interrupt)
|
||||||
|
type->ack_interrupt(dev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void simio_step(uint16_t status_register, int cycles)
|
||||||
|
{
|
||||||
|
int clocks[3] = {0};
|
||||||
|
struct list_node *n;
|
||||||
|
|
||||||
|
aclk_counter += cycles;
|
||||||
|
|
||||||
|
clocks[SIMIO_MCLK] = cycles;
|
||||||
|
clocks[SIMIO_SMCLK] = cycles;
|
||||||
|
clocks[SIMIO_ACLK] = aclk_counter >> 8;
|
||||||
|
|
||||||
|
if (status_register & MSP430_SR_CPUOFF)
|
||||||
|
clocks[SIMIO_MCLK] = 0;
|
||||||
|
|
||||||
|
if (status_register & MSP430_SR_SCG1)
|
||||||
|
clocks[SIMIO_SMCLK] = 0;
|
||||||
|
|
||||||
|
if (status_register & MSP430_SR_OSCOFF)
|
||||||
|
clocks[SIMIO_ACLK] = 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->step)
|
||||||
|
type->step(dev, status_register, clocks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t simio_sfr_get(address_t which)
|
||||||
|
{
|
||||||
|
if (which < 0 || which > sizeof(sfr_data))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return sfr_data[which];
|
||||||
|
}
|
||||||
|
|
||||||
|
void simio_sfr_modify(address_t which, uint8_t mask, uint8_t bits)
|
||||||
|
{
|
||||||
|
if (which < 0 || which > sizeof(sfr_data))
|
||||||
|
return;
|
||||||
|
|
||||||
|
sfr_data[which] = (sfr_data[which] & ~mask) | bits;
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
/* 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_H_
|
||||||
|
#define SIMIO_H_
|
||||||
|
|
||||||
|
/* Initialize the IO simulator. */
|
||||||
|
void simio_init(void);
|
||||||
|
|
||||||
|
/* Clean up allocated resources. */
|
||||||
|
void simio_exit(void);
|
||||||
|
|
||||||
|
/* This file gives the prototype for the "simio" command function. */
|
||||||
|
int cmd_simio(char **arg_text);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,60 @@
|
||||||
|
/* 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_CPU_H_
|
||||||
|
#define SIMIO_CPU_H_
|
||||||
|
|
||||||
|
/* This file describes the interface between the CPU simulator and the IO
|
||||||
|
* simulator. It gives prototypes for functions which should be periodically
|
||||||
|
* called by the CPU simulator.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
/* This function should be called when the CPU is reset, to also reset
|
||||||
|
* the IO simulator.
|
||||||
|
*/
|
||||||
|
void simio_reset(void);
|
||||||
|
|
||||||
|
/* These functions should be called to perform programmed IO requests. A
|
||||||
|
* return value of 0 indicates success, 1 is an unhandled request, and -1
|
||||||
|
* is an error which should cause execution to stop.
|
||||||
|
*/
|
||||||
|
int simio_write(address_t addr, uint16_t data);
|
||||||
|
int simio_read(address_t addr, uint16_t *data);
|
||||||
|
int simio_write_b(address_t addr, uint8_t data);
|
||||||
|
int simio_read_b(address_t addr, uint8_t *data);
|
||||||
|
|
||||||
|
/* Check for an interrupt before executing an instruction. It returns -1 if
|
||||||
|
* no interrupt is pending, otherwise the number of the highest priority
|
||||||
|
* pending interrupt.
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* This should be called after executing an instruction to advance the system
|
||||||
|
* clocks.
|
||||||
|
*/
|
||||||
|
void simio_step(uint16_t status_register, int cycles);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,101 @@
|
||||||
|
/* 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_DEVICE_H_
|
||||||
|
#define SIMIO_DEVICE_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "util.h"
|
||||||
|
#include "list.h"
|
||||||
|
|
||||||
|
/* Each system clock has a unique index. After each instruction, step()
|
||||||
|
* is invoked on each device with an array of clock transition counts.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
SIMIO_MCLK = 0,
|
||||||
|
SIMIO_SMCLK,
|
||||||
|
SIMIO_ACLK
|
||||||
|
} simio_clock_t;
|
||||||
|
|
||||||
|
/* Access to special function registers is provided by these functions. The
|
||||||
|
* modify function does:
|
||||||
|
*
|
||||||
|
* SFR = (SFR & ~mask) | bits
|
||||||
|
*/
|
||||||
|
uint8_t simio_sfr_get(address_t which);
|
||||||
|
void simio_sfr_modify(address_t which, uint8_t mask, uint8_t bits);
|
||||||
|
|
||||||
|
struct simio_class;
|
||||||
|
|
||||||
|
/* Device base class.
|
||||||
|
*
|
||||||
|
* The node and name fields will be filled out by the IO simulator - they're
|
||||||
|
* used for keeping track of the device list. The node member MUST be the
|
||||||
|
* first in the struct.
|
||||||
|
*/
|
||||||
|
struct simio_device {
|
||||||
|
struct list_node node;
|
||||||
|
|
||||||
|
char name[64];
|
||||||
|
const struct simio_class *type;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct simio_class {
|
||||||
|
const char *name;
|
||||||
|
const char *help;
|
||||||
|
|
||||||
|
/* Instantiate a new device, with the given arguments. This may
|
||||||
|
* fail, in which case NULL should be returned.
|
||||||
|
*/
|
||||||
|
struct simio_device *(*create)(char **arg_text);
|
||||||
|
void (*destroy)(struct simio_device *dev);
|
||||||
|
|
||||||
|
/* These methods are invoked via the command interface to modify
|
||||||
|
* device data and show status.
|
||||||
|
*/
|
||||||
|
int (*config)(struct simio_device *dev, const char *param,
|
||||||
|
char **arg_text);
|
||||||
|
int (*info)(struct simio_device *dev);
|
||||||
|
|
||||||
|
/* Programmed IO functions return 1 to indicate an unhandled
|
||||||
|
* request. This scheme allows stacking.
|
||||||
|
*/
|
||||||
|
int (*write)(struct simio_device *dev,
|
||||||
|
address_t addr, uint16_t data);
|
||||||
|
int (*read)(struct simio_device *dev,
|
||||||
|
address_t addr, uint16_t *data);
|
||||||
|
int (*write_b)(struct simio_device *dev,
|
||||||
|
address_t addr, uint8_t data);
|
||||||
|
int (*read_b)(struct simio_device *dev,
|
||||||
|
address_t addr, uint8_t *data);
|
||||||
|
|
||||||
|
/* Check and acknowledge interrupts. Each device may produce
|
||||||
|
* a single interrupt request at any time.
|
||||||
|
*/
|
||||||
|
int (*check_interrupt)(struct simio_device *dev);
|
||||||
|
void (*ack_interrupt)(struct simio_device *dev);
|
||||||
|
|
||||||
|
/* Run the clocks for this device. The counters array has one
|
||||||
|
* array per clock, and gives the number of cycles elapsed since
|
||||||
|
* the last call to this method.
|
||||||
|
*/
|
||||||
|
void (*step)(struct simio_device *dev,
|
||||||
|
uint16_t status_register, const int *clocks);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue