*.hex
*.s
simavr/simavr
+simavr/run_avr
F
"./simavr/sim/sim_io.h"
T
-2 "simavr.c"
+2 "sim_avr.c"
F
-"./simavr/sim/simavr.c"
+"./simavr/sim/sim_avr.c"
T
-2 "simavr.h"
+2 "sim_avr.h"
F
-"./simavr/sim/simavr.h"
+"./simavr/sim/sim_avr.h"
T
2 "fifo_declare.h"
F
"./simavr/sim/fifo_declare.h"
+T
+2 "run_avr.c"
+F
+"./simavr/sim/run_avr.c"
F
T
1 "tests"
2 "atmega88_example.c"
F
"./tests/atmega88_example.c"
+T
+2 "atmega48_disabled_timer.c"
+F
+"./tests/atmega48_disabled_timer.c"
+T
+2 "atmega88_uart_echo.c"
+F
+"./tests/atmega88_uart_echo.c"
F
T
1 "cores"
# You should have received a copy of the GNU General Public License
# along with simavr. If not, see <http://www.gnu.org/licenses/>.
-target = simavr
+target = run_avr
ifeq (${shell uname}, Darwin)
AVR_ROOT := "/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/avr-4/"
CFLAGS += ${patsubst %,-I%,${subst :, ,${IPATH}}}
LFLAGS = -L/opt/local/lib/
-LDFLAGS += -lelf
+LDFLAGS += -lelf -lpthread
all: obj ${target}
along with simavr. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "simavr.h"
+#include "sim_avr.h"
#define SIM_VECTOR_SIZE 4
#define SIM_MMCU "atmega168"
along with simavr. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "simavr.h"
+#include "sim_avr.h"
#define SIM_VECTOR_SIZE 2
#define SIM_MMCU "atmega48"
*/
#include </usr/include/stdio.h>
-#include "simavr.h"
+#include "sim_avr.h"
#include "sim_core_declare.h"
#include "avr_eeprom.h"
#include "avr_ioport.h"
along with simavr. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "simavr.h"
+#include "sim_avr.h"
#define SIM_VECTOR_SIZE 2
#define SIM_MMCU "atmega88"
along with simavr. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
-#include "simavr.h"
+#include "sim_avr.h"
#include "sim_megax8.h"
.spi = {
.disabled = AVR_IO_REGBIT(PRR,PRSPI),
+
+ .r_spdr = SPDR,
+ .r_spcr = SPCR,
+ .r_spsr = SPSR,
+
.spe = AVR_IO_REGBIT(SPCR, SPE),
- .dord = AVR_IO_REGBIT(SPCR, DORD),
.mstr = AVR_IO_REGBIT(SPCR, MSTR),
- .cpol = AVR_IO_REGBIT(SPCR, CPOL),
- .cpha = AVR_IO_REGBIT(SPCR, CPHA),
.spr = { AVR_IO_REGBIT(SPCR, SPR0), AVR_IO_REGBIT(SPCR, SPR1), AVR_IO_REGBIT(SPSR, SPI2X) },
.spi = {
*/
#include </usr/include/stdio.h>
-#include "simavr.h"
+#include "sim_avr.h"
#include "sim_core_declare.h"
#include "avr_eeprom.h"
#include "avr_ioport.h"
printf("%s: AVR_IOCTL_EEPROM_SET Loaded %d at offset %d\n",
__FUNCTION__, desc->size, desc->offset);
} break;
+ case AVR_IOCTL_EEPROM_GET: {
+ avr_eeprom_desc_t * desc = (avr_eeprom_desc_t*)io_param;
+ if (!desc || (desc->offset + desc->size) >= p->size) {
+ printf("%s: AVR_IOCTL_EEPROM_GET Invalid argument\n",
+ __FUNCTION__);
+ return -2;
+ }
+ if (desc->ee)
+ memcpy(desc->ee, p->eeprom + desc->offset, desc->size);
+ else // allow to get access to the read data, for gdb support
+ desc->ee = p->eeprom + desc->offset;
+ } break;
}
return res;
#ifndef __AVR_EEPROM_H__
#define __AVR_EEPROM_H__
-#include "simavr.h"
+#include "sim_avr.h"
typedef struct avr_eeprom_t {
avr_io_t io;
#ifndef __AVR_IOPORT_H__
#define __AVR_IOPORT_H__
-#include "simavr.h"
+#include "sim_avr.h"
enum {
IOPORT_IRQ_PIN0 = 0,
// printf("%s\n", __FUNCTION__);
}
-#if 0
static uint8_t avr_spi_read(struct avr_t * avr, uint8_t addr, void * param)
{
avr_spi_t * p = (avr_spi_t *)param;
{
avr_spi_t * p = (avr_spi_t *)param;
- if (addr == p->r_udr) {
+ if (addr == p->r_spdr) {
// printf("UDR%c(%02x) = %02x\n", p->name, addr, v);
avr_core_watch_write(avr, addr, v);
- avr_regbit_set(avr, p->udre);
-
- static char buf[128];
- static int l = 0;
- buf[l++] = v <= ' ' ? '.' : v;
- buf[l] = 0;
- if (v == '\n' || l == 127) {
- l = 0;
- printf("\e[32m%s\e[0m\n", buf);
- }
}
}
-#endif
+
+static void avr_spi_irq_input(avr_t * avr, struct avr_irq_t * irq, uint32_t value, void * param)
+{
+ avr_spi_t * p = (avr_spi_t *)param;
+
+ // check to see fi receiver is enabled
+ if (!avr_regbit_get(avr, p->spe))
+ return;
+
+ // double buffer the input.. ?
+}
void avr_spi_reset(avr_t * avr, struct avr_io_t *io)
{
-// avr_spi_t * p = (avr_spi_t *)io;
-// avr_regbit_set(avr, p->udre);
+ avr_spi_t * p = (avr_spi_t *)io;
+ avr_irq_register_notify(avr, p->io.irq + SPI_IRQ_INPUT, avr_spi_irq_input, p);
}
static avr_io_t _io = {
printf("%s SPI%c init\n", __FUNCTION__, p->name);
-// avr_register_io_write(avr, p->r_udr, avr_spi_write, p);
-// avr_register_io_read(avr, p->r_udr, avr_spi_read, p);
+ // allocate this module's IRQ
+ p->io.irq_count = SPI_IRQ_COUNT;
+ p->io.irq = avr_alloc_irq(avr, 0, p->io.irq_count);
+ p->io.irq_ioctl_get = AVR_IOCTL_SPI_GETIRQ(p->name);
+
+ avr_register_io_write(avr, p->r_spdr, avr_spi_write, p);
+ avr_register_io_read(avr, p->r_spdr, avr_spi_read, p);
}
#ifndef AVR_SPI_H_
#define AVR_SPI_H_
-#include "simavr.h"
+#include "sim_avr.h"
+
+enum {
+ SPI_IRQ_INPUT = 0,
+ SPI_IRQ_OUTPUT,
+ SPI_IRQ_COUNT
+};
+
+// add port number to get the real IRQ
+#define AVR_IOCTL_SPI_GETIRQ(_name) AVR_IOCTL_DEF('s','p','i',(_name))
typedef struct avr_spi_t {
avr_io_t io;
uint8_t r_spdr; // data register
uint8_t r_spcr; // control register
+ uint8_t r_spsr; // status register
avr_regbit_t spe; // spi enable
- avr_regbit_t dord; // data order
avr_regbit_t mstr; // master/slave
- avr_regbit_t cpol; // clock polarity
- avr_regbit_t cpha; // phase
avr_regbit_t spr[4]; // clock divider
avr_int_vector_t spi; // spi interrupt
#ifndef AVR_TIMER8_H_
#define AVR_TIMER8_H_
-#include "simavr.h"
+#include "sim_avr.h"
typedef struct avr_timer8_t {
avr_io_t io;
}
}
-void avr_uart_irq_input(avr_t * avr, struct avr_irq_t * irq, uint32_t value, void * param)
+static void avr_uart_irq_input(avr_t * avr, struct avr_irq_t * irq, uint32_t value, void * param)
{
avr_uart_t * p = (avr_uart_t *)param;
#ifndef AVR_UART_H_
#define AVR_UART_H_
-#include "simavr.h"
+#include "sim_avr.h"
#include "fifo_declare.h"
--- /dev/null
+/*
+ run_avr.c
+
+ Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
+
+ This file is part of simavr.
+
+ simavr 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 3 of the License, or
+ (at your option) any later version.
+
+ simavr 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 simavr. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <string.h>
+#include "sim_avr.h"
+#include "sim_elf.h"
+#include "sim_core.h"
+#include "sim_gdb.h"
+#include "avr_eeprom.h"
+#include "avr_uart.h"
+
+void hdump(const char *w, uint8_t *b, size_t l)
+{
+ uint32_t i;
+ if (l < 16) {
+ printf("%s: ",w);
+ for (i = 0; i < l; i++) printf("%02x",b[i]);
+ } else {
+ printf("%s:\n",w);
+ for (i = 0; i < l; i++) {
+ if (!(i & 0x1f)) printf(" ");
+ printf("%02x",b[i]);
+ if ((i & 0x1f) == 0x1f) {
+ printf(" ");
+ printf("\n");
+ }
+ }
+ }
+ printf("\n");
+}
+
+
+void display_usage()
+{
+ printf("usage: simavr [-t] [-g] [-m <device>] [-f <frequency>] firmware\n");
+ printf(" -t: run full scale decoder trace\n");
+ printf(" -g: listen for gdb connection on port 1234\n");
+ exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+ elf_firmware_t f;
+ long f_cpu = 0;
+ int trace = 0;
+ int gdb = 0;
+ char name[16] = "";
+ int option_count;
+ int option_index = 0;
+
+ struct option long_options[] = {
+ {"help", no_argument, 0, 'h'},
+ {"mcu", required_argument, 0, 'm'},
+ {"freq", required_argument, 0, 'f'},
+ {"trace", no_argument, 0, 't'},
+ {"gdb", no_argument, 0, 'g'},
+ {0, 0, 0, 0}
+ };
+
+ if (argc == 1)
+ display_usage();
+
+ while ((option_count = getopt_long(argc, argv, "tghm:f:", long_options, &option_index)) != -1) {
+ switch (option_count) {
+ case 'h':
+ display_usage();
+ break;
+ case 'm':
+ strcpy(name, optarg);
+ break;
+ case 'f':
+ f_cpu = atoi(optarg);
+ break;
+ case 't':
+ trace++;
+ break;
+ case 'g':
+ gdb++;
+ break;
+ }
+ }
+
+ elf_read_firmware(argv[argc-1], &f);
+
+ if (strlen(name))
+ strcpy(f.mmcu.name, name);
+ if (f_cpu)
+ f.mmcu.f_cpu = f_cpu;
+
+ printf("firmware %s f=%d mmcu=%s\n", argv[argc-1], (int)f.mmcu.f_cpu, f.mmcu.name);
+
+ avr_t * avr = avr_make_mcu_by_name(f.mmcu.name);
+ if (!avr) {
+ fprintf(stderr, "%s: AVR '%s' now known\n", argv[0], f.mmcu.name);
+ exit(1);
+ }
+ avr_init(avr);
+ avr->frequency = f.mmcu.f_cpu;
+ avr->codeline = f.codeline;
+ avr_loadcode(avr, f.flash, f.flashsize, 0);
+ avr->codeend = f.flashsize - f.datasize;
+ if (f.eeprom && f.eesize) {
+ avr_eeprom_desc_t d = { .ee = f.eeprom, .offset = 0, .size = f.eesize };
+ avr_ioctl(avr, AVR_IOCTL_EEPROM_SET, &d);
+ }
+ avr->trace = trace;
+
+ // try to enable "local echo" on the first uart, for testing purposes
+ {
+ avr_irq_t * src = avr_io_getirq(avr, AVR_IOCTL_UART_GETIRQ('0'), UART_IRQ_OUTPUT);
+ avr_irq_t * dst = avr_io_getirq(avr, AVR_IOCTL_UART_GETIRQ('0'), UART_IRQ_INPUT);
+ printf("%s:%s activating uart local echo IRQ src %p dst %p\n", __FILE__, __FUNCTION__, src, dst);
+ if (src && dst)
+ avr_connect_irq(avr, src, dst);
+ }
+
+ if (gdb) {
+ avr->state = cpu_Stopped;
+ avr_gdb_init(avr);
+ }
+
+// for (long long i = 0; i < 8000000*10; i++)
+// for (long long i = 0; i < 80000; i++)
+ for (;;)
+ avr_run(avr);
+
+}
--- /dev/null
+/*
+ sim_avr.c
+
+ Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
+
+ This file is part of simavr.
+
+ simavr 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 3 of the License, or
+ (at your option) any later version.
+
+ simavr 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 simavr. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "sim_avr.h"
+#include "sim_core.h"
+#include "sim_gdb.h"
+
+
+int avr_init(avr_t * avr)
+{
+ avr->flash = malloc(avr->flashend + 1);
+ memset(avr->flash, 0xff, avr->flashend + 1);
+ avr->data = malloc(avr->ramend + 1);
+ memset(avr->data, 0, avr->ramend + 1);
+
+ // cpu is in limbo before init is finished.
+ avr->state = cpu_Limbo;
+ avr->frequency = 1000000; // can be overriden via avr_mcu_section
+ if (avr->init)
+ avr->init(avr);
+ avr->state = cpu_Running;
+ avr_reset(avr);
+ return 0;
+}
+
+void avr_reset(avr_t * avr)
+{
+ memset(avr->data, 0x0, avr->ramend + 1);
+ _avr_sp_set(avr, avr->ramend);
+ avr->pc = 0;
+ for (int i = 0; i < 8; i++)
+ avr->sreg[i] = 0;
+ if (avr->reset)
+ avr->reset(avr);
+
+ avr_io_t * port = avr->io_port;
+ while (port) {
+ if (port->reset)
+ port->reset(avr, port);
+ port = port->next;
+ }
+}
+
+
+void avr_loadcode(avr_t * avr, uint8_t * code, uint32_t size, uint32_t address)
+{
+ memcpy(avr->flash + address, code, size);
+}
+
+void avr_core_watch_write(avr_t *avr, uint16_t addr, uint8_t v)
+{
+ if (addr > avr->ramend) {
+ printf("*** Invalid write address PC=%04x SP=%04x O=%04x Address %04x=%02x out of ram\n",
+ avr->pc, _avr_sp_get(avr), avr->flash[avr->pc] | (avr->flash[avr->pc]<<8), addr, v);
+ CRASH();
+ }
+ if (addr < 32) {
+ printf("*** Invalid write address PC=%04x SP=%04x O=%04x Address %04x=%02x low registers\n",
+ avr->pc, _avr_sp_get(avr), avr->flash[avr->pc] | (avr->flash[avr->pc]<<8), addr, v);
+ CRASH();
+ }
+#if AVR_STACK_WATCH
+ /*
+ * this checks that the current "function" is not doctoring the stack frame that is located
+ * higher on the stack than it should be. It's a sign of code that has overrun it's stack
+ * frame and is munching on it's own return address.
+ */
+ if (avr->stack_frame_index > 1 && addr > avr->stack_frame[avr->stack_frame_index-2].sp) {
+ printf("\e[31m%04x : munching stack SP %04x, A=%04x <= %02x\e[0m\n", avr->pc, _avr_sp_get(avr), addr, v);
+ }
+#endif
+ avr->data[addr] = v;
+}
+
+uint8_t avr_core_watch_read(avr_t *avr, uint16_t addr)
+{
+ if (addr > avr->ramend) {
+ printf("*** Invalid read address PC=%04x SP=%04x O=%04x Address %04x out of ram (%04x)\n",
+ avr->pc, _avr_sp_get(avr), avr->flash[avr->pc] | (avr->flash[avr->pc]<<8), addr, avr->ramend);
+ CRASH();
+ }
+ return avr->data[addr];
+}
+
+
+int avr_run(avr_t * avr)
+{
+ avr_gdb_processor(avr);
+
+ if (avr->state == cpu_Stopped) {
+ usleep(500);
+ return avr->state;
+ }
+
+ int step = avr->state == cpu_Step;
+ if (step) {
+ avr->state = cpu_Running;
+ }
+
+ uint16_t new_pc = avr->pc;
+
+ if (avr->state == cpu_Running) {
+ new_pc = avr_run_one(avr);
+ avr_dump_state(avr);
+ } else
+ avr->cycle ++;
+
+ // re-synth the SREG
+ //SREG();
+ // if we just re-enabled the interrupts...
+ if (avr->sreg[S_I] && !(avr->data[R_SREG] & (1 << S_I))) {
+ // printf("*** %s: Renabling interrupts\n", __FUNCTION__);
+ avr->pending_wait++;
+ }
+ avr_io_t * port = avr->io_port;
+ while (port) {
+ if (port->run)
+ port->run(avr, port);
+ port = port->next;
+ }
+
+ avr->pc = new_pc;
+
+ if (avr->state == cpu_Sleeping) {
+ if (!avr->sreg[S_I]) {
+ printf("simavr: sleeping with interrupts off, quitting gracefuly\n");
+ exit(0);
+ }
+ usleep(500);
+ long sleep = (float)avr->frequency * (1.0f / 500.0f);
+ avr->cycle += sleep;
+ // avr->state = cpu_Running;
+ }
+ // Interrupt servicing might change the PC too
+ if (avr->state == cpu_Running || avr->state == cpu_Sleeping) {
+ avr_service_interrupts(avr);
+
+ avr->data[R_SREG] = 0;
+ for (int i = 0; i < 8; i++)
+ if (avr->sreg[i] > 1) {
+ printf("** Invalid SREG!!\n");
+ CRASH();
+ } else if (avr->sreg[i])
+ avr->data[R_SREG] |= (1 << i);
+ }
+
+ if (step) {
+ avr->state = cpu_StepDone;
+ }
+
+ return avr->state;
+}
+
+
+extern avr_kind_t tiny85;
+extern avr_kind_t mega48,mega88,mega168;
+extern avr_kind_t mega644;
+
+avr_kind_t * avr_kind[] = {
+ &tiny85,
+ &mega48,
+ &mega88,
+ &mega168,
+ &mega644,
+ NULL
+};
+
+avr_t * avr_make_mcu_by_name(const char *name)
+{
+ avr_kind_t * maker = NULL;
+ for (int i = 0; avr_kind[i] && !maker; i++) {
+ for (int j = 0; avr_kind[i]->names[j]; j++)
+ if (!strcmp(avr_kind[i]->names[j], name)) {
+ maker = avr_kind[i];
+ break;
+ }
+ }
+ if (!maker) {
+ fprintf(stderr, "%s: AVR '%s' now known\n", __FUNCTION__, name);
+ return NULL;
+ }
+
+ avr_t * avr = maker->make();
+ printf("Starting %s - flashend %04x ramend %04x e2end %04x\n", avr->mmcu, avr->flashend, avr->ramend, avr->e2end);
+ return avr;
+}
+
--- /dev/null
+/*
+ sim_avr.h
+
+ Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
+
+ This file is part of simavr.
+
+ simavr 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 3 of the License, or
+ (at your option) any later version.
+
+ simavr 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 simavr. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __SIM_AVR_H__
+#define __SIM_AVR_H__
+
+#include <stdint.h>
+
+struct avr_t;
+typedef uint8_t (*avr_io_read_t)(struct avr_t * avr, uint8_t addr, void * param);
+typedef void (*avr_io_write_t)(struct avr_t * avr, uint8_t addr, uint8_t v, void * param);
+
+enum {
+ // SREG bit indexes
+ S_C = 0,S_Z,S_N,S_V,S_S,S_H,S_T,S_I,
+
+ // 16 bits register pairs
+ R_XL = 0x1a, R_XH,R_YL,R_YH,R_ZL,R_ZH,
+ // stack pointer
+ R_SPL = 32+0x3d, R_SPH,
+ // real SREG
+ R_SREG = 32+0x3f,
+
+ // maximum number of IO regisrer, on normal AVRs
+ MAX_IOs = 256 - 32, // minus 32 GP registers
+};
+
+#define AVR_DATA_TO_IO(v) ((v) - 32)
+#define AVR_IO_TO_DATA(v) ((v) + 32)
+
+/*
+ * Core states. This will need populating with debug states for gdb
+ */
+enum {
+ cpu_Limbo = 0, // before initialization is finished
+ cpu_Stopped,
+ cpu_Running,
+ cpu_Sleeping,
+
+ cpu_Step,
+ cpu_StepDone,
+};
+
+/*
+ * Main AVR instance. Some of these fields are set by the AVR "Core" definition files
+ * the rest is runtime data (as little as possible)
+ */
+typedef struct avr_t {
+ const char * mmcu; // name of the AVR
+ // these are filled by sim_core_declare from constants in /usr/lib/avr/include/avr/io*.h
+ uint16_t ramend;
+ uint32_t flashend;
+ uint32_t e2end;
+ uint8_t vector_size;
+ uint8_t signature[3];
+ uint8_t fuse[4];
+
+ // filled by the ELF data, this allow tracking of invalid jumps
+ uint32_t codeend;
+
+ int state; // stopped, running, sleeping
+ uint32_t frequency; // frequency we are running at
+ uint64_t cycle; // current cycle
+
+ // called at init time
+ void (*init)(struct avr_t * avr);
+ // called at reset time
+ void (*reset)(struct avr_t * avr);
+
+ // Mirror of the SREG register, to facilitate the access to bits
+ // in the opcode decoder.
+ // This array is re-synthetized back/forth when SREG changes
+ uint8_t sreg[8];
+
+ /*
+ * ** current PC **
+ * Note that the PC is reoresenting /bytes/ while the AVR value is
+ * assumed to be "words". This is in line with what GDB does...
+ * this is why you will see >>1 ane <<1 in the decoder to handle jumps
+ */
+ uint32_t pc;
+
+ /*
+ * callback when specific IO registers are read/written
+ */
+ struct {
+ void * param;
+ avr_io_read_t r;
+ } ior[MAX_IOs];
+ struct {
+ void * param;
+ avr_io_write_t w;
+ } iow[MAX_IOs];
+
+ // flash memory (initialized to 0xff, and code loaded into it)
+ uint8_t * flash;
+ // this is the general purpose registers, IO registers, and SRAM
+ uint8_t * data;
+
+ // queue of io modules
+ struct avr_io_t *io_port;
+
+ // interrupt vectors, and their enable/clear registers
+ struct avr_int_vector_t * vector[64];
+ uint8_t pending_wait; // number of cycles to wait for pending
+ uint32_t pending[2]; // pending interrupts
+
+ // DEBUG ONLY
+ int trace;
+ struct avr_symbol_t ** codeline;
+
+ /* DEBUG ONLY
+ * this keeps track of "jumps" ie, call,jmp,ret,reti and so on
+ * allows dumping of a meaningful data even if the stack is
+ * munched and so on
+ */
+ #define OLD_PC_SIZE 32
+ struct {
+ uint32_t pc;
+ uint16_t sp;
+ } old[OLD_PC_SIZE]; // catches reset..
+ int old_pci;
+
+#if AVR_STACK_WATCH
+ #define STACK_FRAME_SIZE 32
+ // this records the call/ret pairs, to try to catch
+ // code that munches the stack -under- their own frame
+ struct {
+ uint32_t pc;
+ uint16_t sp;
+ } stack_frame[STACK_FRAME_SIZE];
+ int stack_frame_index;
+#endif
+
+ // DEBUG ONLY
+ // keeps track of wich registers gets touched by instructions
+ // reset before each new instructions. Allows meaningful traces
+ uint32_t touched[256 / 32]; // debug
+
+ // placeholder
+ struct avr_gdb_t * gdb;
+} avr_t;
+
+
+// this is a static constructor for each of the AVR devices
+typedef struct avr_kind_t {
+ const char * names[4]; // name aliases
+ avr_t * (*make)();
+} avr_kind_t;
+
+// a symbol loaded from the .elf file
+typedef struct avr_symbol_t {
+ const char * symbol;
+ uint32_t addr;
+} avr_symbol_t;
+
+// locate the maker for mcu "name" and allocates a new avr instance
+avr_t * avr_make_mcu_by_name(const char *name);
+// initializes a new AVR instance. Will call the IO registers init(), and then reset()
+int avr_init(avr_t * avr);
+// resets the AVR, and the IO modules
+void avr_reset(avr_t * avr);
+// run one cycle of the AVR, sleep if necessary
+int avr_run(avr_t * avr);
+
+// load code in the "flash"
+void avr_loadcode(avr_t * avr, uint8_t * code, uint32_t size, uint32_t address);
+
+
+/*
+ * these are accessors for avr->data but allows watchpoints to be set for gdb
+ * IO modules use that to set values to registers, and the AVR core decoder uses
+ * that to register "public" read by instructions.
+ */
+void avr_core_watch_write(avr_t *avr, uint16_t addr, uint8_t v);
+uint8_t avr_core_watch_read(avr_t *avr, uint16_t addr);
+
+
+#include "sim_io.h"
+#include "sim_regbit.h"
+#include "sim_interrupts.h"
+#include "sim_irq.h"
+
+#endif /*__SIM_AVR_H__*/
+
#include <stdio.h>
#include <string.h>
#include <ctype.h>
-#include "simavr.h"
+#include "sim_avr.h"
#include "sim_core.h"
// SREG bit names
} break;
case 0x9598: { // BREAK
STATE("break\n");
+ if (avr->gdb)
+ avr->state = cpu_StepDone;
} break;
case 0x95a8: { // WDR
STATE("wdr\n");
} else if (!strcmp(name, ".mmcu")) {
Elf_Data *s = elf_getdata(scn, NULL);
firmware->mmcu = *((struct avr_mcu_t*)s->d_buf);
- // printf("%s: avr_mcu_t size %ld / read %ld\n", __FUNCTION__, sizeof(avr_mcu_t), s->d_size);
+ printf("%s: avr_mcu_t size %ld / read %ld\n", __FUNCTION__, sizeof(struct avr_mcu_t), s->d_size);
// avr->frequency = f_cpu;
}
#if ELF_SYMBOLS
#endif
#if ELF_SYMBOLS
-#include "simavr.h"
+#include "sim_avr.h"
#endif
typedef struct elf_firmware_t {
/*
sim_gdb.c
- Placeholder!
-
Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
This file is part of simavr.
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <sys/socket.h>
+#include <sys/time.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <poll.h>
-#include "simavr.h"
+#include <pthread.h>
+#include "sim_avr.h"
+#include "avr_eeprom.h"
typedef struct avr_gdb_t {
avr_t * avr;
- int sock;
+ int listen; // listen socket
+ int s; // current gdb connection
+
+ pthread_t thread;
+
+ uint32_t query_len;
+ char query[1024];
+
+ uint32_t watchmap;
+ struct {
+ uint32_t pc;
+ uint32_t len;
+ int kind;
+ } watch[32];
} avr_gdb_t;
+ // decode line text hex to binary
+int read_hex_string(const char * src, uint8_t * buffer, int maxlen)
+{
+ uint8_t * dst = buffer;
+ int ls = 0;
+ uint8_t b = 0;
+ while (*src && maxlen--) {
+ char c = *src++;
+ switch (c) {
+ case 'a' ... 'f': b = (b << 4) | (c - 'a' + 0xa); break;
+ case 'A' ... 'F': b = (b << 4) | (c - 'A' + 0xa); break;
+ case '0' ... '9': b = (b << 4) | (c - '0'); break;
+ default:
+ if (c > ' ') {
+ fprintf(stderr, "%s: huh '%c' (%s)\n", __FUNCTION__, c, src);
+ return -1;
+ }
+ continue;
+ }
+ if (ls & 1) {
+ *dst++ = b; b = 0;
+ }
+ ls++;
+ }
+
+ return dst - buffer;
+}
+
+static void gdb_send_reply(avr_gdb_t * g, char * cmd)
+{
+ uint8_t reply[1024];
+ uint8_t * dst = reply;
+ uint8_t check = 0;
+ *dst++ = '$';
+ while (*cmd) {
+ check += *cmd;
+ *dst++ = *cmd++;
+ }
+ sprintf((char*)dst, "#%02x", check);
+ printf("%s '%s'\n", __FUNCTION__, reply);
+ send(g->s, reply, dst - reply + 3, 0);
+}
+
+static void gdb_send_quick_status(avr_gdb_t * g, uint8_t signal)
+{
+ char cmd[64];
+
+ sprintf(cmd, "T%02x20:%02x;21:%02x%02x;22:%02x%02x%02x00;",
+ signal, g->avr->data[R_SREG],
+ g->avr->data[R_SPL], g->avr->data[R_SPH],
+ g->avr->pc & 0xff, (g->avr->pc>>8)&0xff, (g->avr->pc>>16)&0xff);
+ gdb_send_reply(g, cmd);
+}
+
+static int gdb_change_breakpoint(avr_gdb_t * g, int set, int kind, uint32_t addr, uint32_t len)
+{
+ printf("set %d kind %d addr %08x len %d (map %08x)\n", set, kind, addr, len, g->watchmap);
+ if (set) {
+ if (g->watchmap == 0xffffffff)
+ return -1; // map full
+
+ // check to see if it exists
+ for (int i = 0; i < 32; i++)
+ if ((g->watchmap & (1 << i)) && g->watch[i].pc == addr) {
+ g->watch[i].len = len;
+ return 0;
+ }
+ for (int i = 0; i < 32; i++)
+ if (!(g->watchmap & (1 << i))) {
+ g->watchmap |= (1 << i);
+ g->watch[i].len = len;
+ g->watch[i].pc = addr;
+ g->watch[i].kind = kind;
+ return 0;
+ }
+ } else {
+ for (int i = 0; i < 32; i++)
+ if ((g->watchmap & (1 << i)) && g->watch[i].pc == addr) {
+ g->watchmap &= ~(1 << i);
+ g->watch[i].len = 0;
+ g->watch[i].pc = 0;
+ g->watch[i].kind = 0;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static void gdb_handle_command(avr_gdb_t * g)
+{
+ avr_t * avr = g->avr;
+ char * cmd = g->query;
+ char rep[1024];
+ uint8_t command = *cmd++;
+ switch (command) {
+ case '?':
+ gdb_send_reply(g, "S00");
+ break;
+ case 'p': {
+ unsigned int regi = 0;
+ sscanf(cmd, "%x", ®i);
+ switch (regi) {
+ case 0 ... 31:
+ sprintf(rep, "%02x", g->avr->data[regi]);
+ break;
+ case 32:
+ sprintf(rep, "%02x", g->avr->data[R_SREG]);
+ break;
+ case 33:
+ sprintf(rep, "%02x%02x", g->avr->data[R_SPL], g->avr->data[R_SPH]);
+ break;
+ case 34:
+ sprintf(rep, "%02x%02x%02x00",
+ g->avr->pc & 0xff, (g->avr->pc>>8)&0xff, (g->avr->pc>>16)&0xff);
+ break;
+ }
+ gdb_send_reply(g, rep);
+ } break;
+ case 'm': {
+ uint32_t addr, len;
+ sscanf(cmd, "%x,%x", &addr, &len);
+ printf("read memory %08x, %08x\n", addr, len);
+ uint8_t * src = NULL;
+ if (addr < 0xffff) {
+ src = avr->flash + addr;
+ } else if (addr >= 0x800000 && (addr - 0x800000) <= avr->ramend) {
+ src = avr->data + addr - 0x800000;
+ } else if (addr >= 0x810000 && (addr - 0x810000) <= (16*1024)) {
+ avr_eeprom_desc_t ee = {.offset = (addr - 0x810000)};
+ avr_ioctl(avr, AVR_IOCTL_EEPROM_GET, &ee);
+ if (ee.ee)
+ src = ee.ee;
+ else
+ gdb_send_reply(g, "E01");
+ } else {
+ gdb_send_reply(g, "E01");
+ break;
+ }
+ char * dst = rep;
+ while (len--) {
+ sprintf(dst, "%02x", *src++);
+ dst += 2;
+ }
+ *dst = 0;
+ gdb_send_reply(g, rep);
+ } break;
+ case 'M': {
+ uint32_t addr, len;
+ sscanf(cmd, "%x,%x", &addr, &len);
+ printf("write memory %08x, %08x\n", addr, len);
+ char * start = strchr(cmd, ':');
+ if (!start) {
+ gdb_send_reply(g, "E01");
+ break;
+ }
+ if (addr < 0xffff) {
+ read_hex_string(start + 1, avr->flash + addr, strlen(start+1));
+ gdb_send_reply(g, "OK");
+ } else if (addr >= 0x800000 && (addr - 0x800000) <= avr->ramend) {
+ read_hex_string(start + 1, avr->data + addr - 0x800000, strlen(start+1));
+ gdb_send_reply(g, "OK");
+ } else
+ gdb_send_reply(g, "E01");
+ } break;
+ case 'c': {
+ avr->state = cpu_Running;
+ } break;
+ case 's': {
+ avr->state = cpu_Step;
+ } break;
+ case 'Z':
+ case 'z': {
+ uint32_t kind, addr, len;
+ sscanf(cmd, "%d,%x,%x", &kind, &addr, &len);
+ printf("breakbpoint %d, %08x, %08x\n", kind, addr, len);
+ switch (kind) {
+ case 0: // software breakpoint
+ case 1: // hardware breakpoint
+ if (addr <= avr->flashend) {
+ if (gdb_change_breakpoint(g, command == 'Z', kind, addr, len))
+ gdb_send_reply(g, "E01");
+ else
+ gdb_send_reply(g, "OK");
+ } else
+ gdb_send_reply(g, "E01"); // out of flash address
+ break;
+ case 2: // write watchpoint
+ case 3: // read watchpoint
+ case 4: // access watchpoint
+ default:
+ gdb_send_reply(g, "");
+ }
+ } break;
+ default:
+ gdb_send_reply(g, "");
+ }
+}
+
+void avr_gdb_processor(avr_t * avr)
+{
+ if (!avr || !avr->gdb)
+ return;
+ avr_gdb_t * g = avr->gdb;
+
+ if (g->watchmap && avr->state == cpu_Running) {
+ for (int i = 0; i < 32; i++)
+ if ((g->watchmap & (1 << i)) && g->watch[i].pc == avr->pc) {
+ printf("avr_gdb_processor hit breakpoint at %08x\n", avr->pc);
+ gdb_send_quick_status(g, 0);
+ avr->state = cpu_Stopped;
+ }
+ }
+ if (avr->state == cpu_StepDone) {
+ gdb_send_quick_status(g, 0);
+ avr->state = cpu_Stopped;
+ }
+ if (avr->gdb->query_len) {
+ g->query_len = 0;
+
+ // printf("avr_gdb_handle_query got a query '%s'\n", g->query);
+ gdb_handle_command(g);
+ }
+}
+
+
+static void * gdb_network_handler(void * param)
+{
+ avr_gdb_t * g = (avr_gdb_t*)param;
+
+ do {
+ if (listen(g->listen, 1)) {
+ perror("gdb_network_handler listen");
+ sleep(5);
+ continue;
+ }
+
+ struct sockaddr_in address = { 0 };
+ socklen_t ad_len = sizeof(address);
+
+ g->s = accept(g->listen, (struct sockaddr*)&address, &ad_len);
+
+ if (g->s == -1) {
+ perror("gdb_network_handler accept");
+ sleep(5);
+ continue;
+ }
+ // should make that thread safe...
+ g->avr->state = cpu_Stopped;
+
+ do {
+ fd_set read_set;
+ FD_ZERO(&read_set);
+ FD_SET(g->s, &read_set);
+
+ struct timeval timo = { 1, 0000 }; // short, but not too short interval
+ /*int ret =*/ select(g->s + 1, &read_set, NULL, NULL, &timo);
+
+ if (FD_ISSET(g->s, &read_set)) {
+ uint8_t buffer[1024];
+
+ ssize_t r = recv(g->s, buffer, sizeof(buffer)-1, 0);
+
+ if (r == 0) {
+ printf("%s connection closed\n", __FUNCTION__);
+ break;
+ }
+ if (r == -1) {
+ perror("gdb_network_handler recv");
+ break;
+ }
+ buffer[r] = 0;
+ // printf("%s: received %d bytes\n'%s'\n", __FUNCTION__, r, buffer);
+ // hdump("gdb", buffer, r);
+
+ uint8_t * src = buffer;
+ while (*src == '+' || *src == '-')
+ src++;
+ if (*src == 3) {
+ src++;
+ g->query[0] = 3;
+ g->query_len = 1; // pass it on ?
+ }
+ if (*src == '$') {
+ // strip checksum
+ uint8_t * end = buffer + r - 1;
+ while (end > src && *end != '#')
+ *end-- = 0;
+ *end = 0;
+ src++;
+ printf("GDB command = '%s'\n", src);
+
+ send(g->s, "+", 1, 0);
+
+ strcpy(g->query, (char*)src);
+ g->query_len = strlen((char*)src);
+ }
+ }
+ } while(1);
+
+ close(g->s);
+
+ } while(1);
+
+ return NULL;
+}
+
+
int avr_gdb_init(avr_t * avr)
{
avr_gdb_t * g = malloc(sizeof(avr_gdb_t));
avr->gdb = NULL;
- if ((g->sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
+ if ((g->listen = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
fprintf(stderr, "Can't create socket: %s", strerror(errno));
return -1;
}
int i = 1;
- setsockopt(g->sock, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
+ setsockopt(g->listen, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
struct sockaddr_in address = { 0 };
address.sin_family = AF_INET;
address.sin_port = htons (1234);
- if (bind(g->sock, (struct sockaddr *) &address, sizeof(address))) {
+ if (bind(g->listen, (struct sockaddr *) &address, sizeof(address))) {
fprintf(stderr, "Can not bind socket: %s", strerror(errno));
return -1;
}
+ printf("avr_gdb_init listening on port %d\n", 1234);
+ g->avr = avr;
avr->gdb = g;
+
+ pthread_create(&g->thread, NULL, gdb_network_handler, g);
+
return 0;
}
#ifndef __SIM_GDB_H__
#define __SIM_GDB_H__
+int avr_gdb_init(avr_t * avr);
+
+// call from the main AVR decoder thread
+void avr_gdb_processor(avr_t * avr);
+
#endif
#ifndef __SIM_INTERUPTS_H__
#define __SIM_INTERUPTS_H__
-#include "simavr.h"
+#include "sim_avr.h"
// interrupt vector for the IO modules
typedef struct avr_int_vector_t {
#ifndef __SIM_IO_H__
#define __SIM_IO_H__
-#include "simavr.h"
+#include "sim_avr.h"
/*
* used by the ioports to implement their own features
#ifndef __SIM_IRQ_H__
#define __SIM_IRQ_H__
-#include "simavr.h"
+#include "sim_avr.h"
/*
* Internal IRQ system
#ifndef __SIM_REGBIT_H__
#define __SIM_REGBIT_H__
-#include "simavr.h"
+#include "sim_avr.h"
#define ARRAY_SIZE(_aa) (sizeof(_aa) / sizeof((_aa)[0]))
+++ /dev/null
-/*
- simavr.c
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr 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 3 of the License, or
- (at your option) any later version.
-
- simavr 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 simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-#include <getopt.h>
-#include "simavr.h"
-#include "sim_elf.h"
-
-#include "sim_core.h"
-#include "avr_eeprom.h"
-#include "avr_uart.h"
-
-void hdump(const char *w, uint8_t *b, size_t l)
-{
- uint32_t i;
- if (l < 16) {
- printf("%s: ",w);
- for (i = 0; i < l; i++) printf("%02x",b[i]);
- } else {
- printf("%s:\n",w);
- for (i = 0; i < l; i++) {
- if (!(i & 0x1f)) printf(" ");
- printf("%02x",b[i]);
- if ((i & 0x1f) == 0x1f) {
- printf(" ");
- printf("\n");
- }
- }
- }
- printf("\n");
-}
-
-
-
-int avr_init(avr_t * avr)
-{
- avr->flash = malloc(avr->flashend + 1);
- memset(avr->flash, 0xff, avr->flashend + 1);
- avr->data = malloc(avr->ramend + 1);
- memset(avr->data, 0, avr->ramend + 1);
-
- // cpu is in limbo before init is finished.
- avr->state = cpu_Limbo;
- avr->frequency = 1000000; // can be overriden via avr_mcu_section
- if (avr->init)
- avr->init(avr);
- avr->state = cpu_Running;
- avr_reset(avr);
- return 0;
-}
-
-void avr_reset(avr_t * avr)
-{
- memset(avr->data, 0x0, avr->ramend + 1);
- _avr_sp_set(avr, avr->ramend);
- avr->pc = 0;
- for (int i = 0; i < 8; i++)
- avr->sreg[i] = 0;
- if (avr->reset)
- avr->reset(avr);
-
- avr_io_t * port = avr->io_port;
- while (port) {
- if (port->reset)
- port->reset(avr, port);
- port = port->next;
- }
-
-}
-
-
-void avr_loadcode(avr_t * avr, uint8_t * code, uint32_t size, uint32_t address)
-{
- memcpy(avr->flash + address, code, size);
-}
-
-void avr_core_watch_write(avr_t *avr, uint16_t addr, uint8_t v)
-{
- if (addr > avr->ramend) {
- printf("*** Invalid write address PC=%04x SP=%04x O=%04x Address %04x=%02x out of ram\n",
- avr->pc, _avr_sp_get(avr), avr->flash[avr->pc] | (avr->flash[avr->pc]<<8), addr, v);
- CRASH();
- }
- if (addr < 32) {
- printf("*** Invalid write address PC=%04x SP=%04x O=%04x Address %04x=%02x low registers\n",
- avr->pc, _avr_sp_get(avr), avr->flash[avr->pc] | (avr->flash[avr->pc]<<8), addr, v);
- CRASH();
- }
-#if AVR_STACK_WATCH
- /*
- * this checks that the current "function" is not doctoring the stack frame that is located
- * higher on the stack than it should be. It's a sign of code that has overrun it's stack
- * frame and is munching on it's own return address.
- */
- if (avr->stack_frame_index > 1 && addr > avr->stack_frame[avr->stack_frame_index-2].sp) {
- printf("\e[31m%04x : munching stack SP %04x, A=%04x <= %02x\e[0m\n", avr->pc, _avr_sp_get(avr), addr, v);
- }
-#endif
- avr->data[addr] = v;
-}
-
-uint8_t avr_core_watch_read(avr_t *avr, uint16_t addr)
-{
- if (addr > avr->ramend) {
- printf("*** Invalid read address PC=%04x SP=%04x O=%04x Address %04x out of ram (%04x)\n",
- avr->pc, _avr_sp_get(avr), avr->flash[avr->pc] | (avr->flash[avr->pc]<<8), addr, avr->ramend);
- CRASH();
- }
- return avr->data[addr];
-}
-
-
-int avr_run(avr_t * avr)
-{
- if (avr->state == cpu_Stopped)
- return avr->state;
-
- uint16_t new_pc = avr->pc;
-
- if (avr->state == cpu_Running) {
- new_pc = avr_run_one(avr);
- avr_dump_state(avr);
- } else
- avr->cycle ++;
-
- // re-synth the SREG
- //SREG();
- // if we just re-enabled the interrupts...
- if (avr->sreg[S_I] && !(avr->data[R_SREG] & (1 << S_I))) {
- // printf("*** %s: Renabling interrupts\n", __FUNCTION__);
- avr->pending_wait++;
- }
- avr_io_t * port = avr->io_port;
- while (port) {
- if (port->run)
- port->run(avr, port);
- port = port->next;
- }
-
- avr->pc = new_pc;
-
- if (avr->state == cpu_Sleeping) {
- if (!avr->sreg[S_I]) {
- printf("simavr: sleeping with interrupts off, quitting gracefuly\n");
- exit(0);
- }
- usleep(500);
- long sleep = (float)avr->frequency * (1.0f / 500.0f);
- avr->cycle += sleep;
- // avr->state = cpu_Running;
- }
- // Interrupt servicing might change the PC too
- if (avr->state == cpu_Running || avr->state == cpu_Sleeping) {
- avr_service_interrupts(avr);
-
- avr->data[R_SREG] = 0;
- for (int i = 0; i < 8; i++)
- if (avr->sreg[i] > 1) {
- printf("** Invalid SREG!!\n");
- CRASH();
- } else if (avr->sreg[i])
- avr->data[R_SREG] |= (1 << i);
- }
- return avr->state;
-}
-
-extern avr_kind_t tiny85;
-extern avr_kind_t mega48,mega88,mega168;
-extern avr_kind_t mega644;
-
-avr_kind_t * avr_kind[] = {
- &tiny85,
- &mega48,
- &mega88,
- &mega168,
- &mega644,
- NULL
-};
-
-void display_usage()
-{
- printf("usage: simavr [-t] [-m <device>] [-f <frequency>] firmware\n");
- printf(" -t: run full scale decoder trace\n");
- exit(1);
-}
-
-int main(int argc, char *argv[])
-{
- elf_firmware_t f;
- long f_cpu = 0;
- int trace = 0;
- char name[16] = "";
- int option_count;
- int option_index = 0;
-
- struct option long_options[] = {
- {"help", no_argument, 0, 'h'},
- {"mcu", required_argument, 0, 'm'},
- {"freq", required_argument, 0, 'f'},
- {"trace", no_argument, 0, 't'},
- {0, 0, 0, 0}
- };
-
- if (argc == 1)
- display_usage();
-
- while ((option_count = getopt_long(argc, argv, "thm:f:", long_options, &option_index)) != -1) {
- switch (option_count) {
- case 'h':
- display_usage();
- break;
- case 'm':
- strcpy(name, optarg);
- break;
- case 'f':
- f_cpu = atoi(optarg);
- break;
- case 't':
- trace++;
- break;
- }
- }
-
- elf_read_firmware(argv[argc-1], &f);
-
- if (strlen(name))
- strcpy(f.mmcu.name, name);
- if (f_cpu)
- f.mmcu.f_cpu = f_cpu;
-
- printf("firmware %s f=%d mmcu=%s\n", argv[argc-1], f.mmcu.f_cpu, f.mmcu.name);
-
- avr_kind_t * maker = NULL;
- for (int i = 0; avr_kind[i] && !maker; i++) {
- for (int j = 0; avr_kind[i]->names[j]; j++)
- if (!strcmp(avr_kind[i]->names[j], f.mmcu.name)) {
- maker = avr_kind[i];
- break;
- }
- }
- if (!maker) {
- fprintf(stderr, "%s: AVR '%s' now known\n", argv[0], f.mmcu.name);
- exit(1);
- }
-
- avr_t * avr = maker->make();
- printf("Starting %s - flashend %04x ramend %04x e2end %04x\n", avr->mmcu, avr->flashend, avr->ramend, avr->e2end);
- avr_init(avr);
- avr->frequency = f.mmcu.f_cpu;
- avr->codeline = f.codeline;
- avr_loadcode(avr, f.flash, f.flashsize, 0);
- avr->codeend = f.flashsize - f.datasize;
- if (f.eeprom && f.eesize) {
- avr_eeprom_desc_t d = { .ee = f.eeprom, .offset = 0, .size = f.eesize };
- avr_ioctl(avr, AVR_IOCTL_EEPROM_SET, &d);
- }
- avr->trace = trace;
-
- // try to enable "local echo" on the first uart, for testing purposes
- {
- avr_irq_t * src = avr_io_getirq(avr, AVR_IOCTL_UART_GETIRQ('0'), UART_IRQ_OUTPUT);
- avr_irq_t * dst = avr_io_getirq(avr, AVR_IOCTL_UART_GETIRQ('0'), UART_IRQ_INPUT);
- printf("%s:%s activating uart local echo IRQ src %p dst %p\n", __FILE__, __FUNCTION__, src, dst);
- if (src && dst)
- avr_connect_irq(avr, src, dst);
- }
-
- for (long long i = 0; i < 8000000*10; i++)
-// for (long long i = 0; i < 80000; i++)
- avr_run(avr);
-
-}
+++ /dev/null
-/*
- simavr.h
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr 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 3 of the License, or
- (at your option) any later version.
-
- simavr 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 simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __SIMAVR_H__
-#define __SIMAVR_H__
-
-#include <stdint.h>
-
-struct avr_t;
-typedef uint8_t (*avr_io_read_t)(struct avr_t * avr, uint8_t addr, void * param);
-typedef void (*avr_io_write_t)(struct avr_t * avr, uint8_t addr, uint8_t v, void * param);
-
-enum {
- // SREG bit indexes
- S_C = 0,S_Z,S_N,S_V,S_S,S_H,S_T,S_I,
-
- // 16 bits register pairs
- R_XL = 0x1a, R_XH,R_YL,R_YH,R_ZL,R_ZH,
- // stack pointer
- R_SPL = 32+0x3d, R_SPH,
- // real SREG
- R_SREG = 32+0x3f,
-
- // maximum number of IO regisrer, on normal AVRs
- MAX_IOs = 256 - 32, // minus 32 GP registers
-};
-
-#define AVR_DATA_TO_IO(v) ((v) - 32)
-#define AVR_IO_TO_DATA(v) ((v) + 32)
-
-/*
- * Core states. This will need populating with debug states for gdb
- */
-enum {
- cpu_Limbo = 0, // before initialization is finished
- cpu_Stopped,
- cpu_Running,
- cpu_Sleeping,
-};
-
-/*
- * Main AVR instance. Some of these fields are set by the AVR "Core" definition files
- * the rest is runtime data (as little as possible)
- */
-typedef struct avr_t {
- const char * mmcu; // name of the AVR
- // these are filled by sim_core_declare from constants in /usr/lib/avr/include/avr/io*.h
- uint16_t ramend;
- uint32_t flashend;
- uint32_t e2end;
- uint8_t vector_size;
- uint8_t signature[3];
- uint8_t fuse[4];
-
- // filled by the ELF data, this allow tracking of invalid jumps
- uint32_t codeend;
-
- int state; // stopped, running, sleeping
- uint32_t frequency; // frequency we are running at
- uint64_t cycle; // current cycle
-
- // called at init time
- void (*init)(struct avr_t * avr);
- // called at reset time
- void (*reset)(struct avr_t * avr);
-
- // Mirror of the SREG register, to facilitate the access to bits
- // in the opcode decoder.
- // This array is re-synthetized back/forth when SREG changes
- uint8_t sreg[8];
-
- /*
- * ** current PC **
- * Note that the PC is reoresenting /bytes/ while the AVR value is
- * assumed to be "words". This is in line with what GDB does...
- * this is why you will see >>1 ane <<1 in the decoder to handle jumps
- */
- uint32_t pc;
-
- /*
- * callback when specific IO registers are read/written
- */
- struct {
- void * param;
- avr_io_read_t r;
- } ior[MAX_IOs];
- struct {
- void * param;
- avr_io_write_t w;
- } iow[MAX_IOs];
-
- // flash memory (initialized to 0xff, and code loaded into it)
- uint8_t * flash;
- // this is the general purpose registers, IO registers, and SRAM
- uint8_t * data;
-
- // queue of io modules
- struct avr_io_t *io_port;
-
- // interrupt vectors, and their enable/clear registers
- struct avr_int_vector_t * vector[64];
- uint8_t pending_wait; // number of cycles to wait for pending
- uint32_t pending[2]; // pending interrupts
-
- // DEBUG ONLY
- int trace;
- struct avr_symbol_t ** codeline;
-
- /* DEBUG ONLY
- * this keeps track of "jumps" ie, call,jmp,ret,reti and so on
- * allows dumping of a meaningful data even if the stack is
- * munched and so on
- */
- #define OLD_PC_SIZE 32
- struct {
- uint32_t pc;
- uint16_t sp;
- } old[OLD_PC_SIZE]; // catches reset..
- int old_pci;
-
-#if AVR_STACK_WATCH
- #define STACK_FRAME_SIZE 32
- // this records the call/ret pairs, to try to catch
- // code that munches the stack -under- their own frame
- struct {
- uint32_t pc;
- uint16_t sp;
- } stack_frame[STACK_FRAME_SIZE];
- int stack_frame_index;
-#endif
-
- // DEBUG ONLY
- // keeps track of wich registers gets touched by instructions
- // reset before each new instructions. Allows meaningful traces
- uint32_t touched[256 / 32]; // debug
-
- // placeholder
- struct avr_gdb_t * gdb;
-} avr_t;
-
-
-// this is a static constructor for each of the AVR devices
-typedef struct avr_kind_t {
- const char * names[4]; // name aliases
- avr_t * (*make)();
-} avr_kind_t;
-
-// a symbol loaded from the .elf file
-typedef struct avr_symbol_t {
- const char * symbol;
- uint32_t addr;
-} avr_symbol_t;
-
-
-// initializes a new AVR instance. Will call the IO registers init(), and then reset()
-int avr_init(avr_t * avr);
-// resets the AVR, and the IO modules
-void avr_reset(avr_t * avr);
-
-// load code in the "flash"
-void avr_loadcode(avr_t * avr, uint8_t * code, uint32_t size, uint32_t address);
-
-
-/*
- * these are accessors for avr->data but allows watchpoints to be set for gdb
- * IO modules use that to set values to registers, and the AVR core decoder uses
- * that to register "public" read by instructions.
- */
-void avr_core_watch_write(avr_t *avr, uint16_t addr, uint8_t v);
-uint8_t avr_core_watch_read(avr_t *avr, uint16_t addr);
-
-
-#include "sim_io.h"
-#include "sim_regbit.h"
-#include "sim_interrupts.h"
-#include "sim_irq.h"
-
-#endif /*__SIMAVR_H__*/
-
#include <avr/io.h>
#include <avr/interrupt.h>
+#include <avr/sleep.h>
#include "avr_mcu_section.h"
AVR_MCU(F_CPU, "atmega48");
// here the interupts are enabled, but the interupt
// vector should not be called
while(1)
- ;
+ sleep_mode();
}