*.s
simavr/simavr
simavr/run_avr
+*.a
--- /dev/null
+#
+# This makefile take each "at*" file, extracts it's part name
+# And compile it into an ELF binary.
+# It also disassemble it for debugging purposes.
+#
+# The code is compiled "optimized" to the max.
+#
+# The wierd "-Wl,--undefined=_mmcu,--section-start=.mmcu=0x910000"
+# is used to tell the linker not to discard the .mmcu section,
+# otherwise the --gc-sections will delete it.
+#
+# 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/>.
+
+%.hex: %.axf
+ @${AVR}objcopy -j .text -j .data -O ihex ${<} ${@}
+
+%.s: %.axf
+ @${AVR}objdump -j .text -j .data -j .bss -d ${<} > ${@}
+
+# --mcall-prologues
+%.axf: %.c
+ @echo CC ${<}
+ @part=${<} ; part=$${part/_*}; \
+ ${AVR}gcc -Wall -gdwarf-2 -Os -std=gnu99 \
+ -mmcu=$$part \
+ -DF_CPU=8000000 \
+ -fno-inline-small-functions \
+ -ffunction-sections -fdata-sections \
+ -Wl,--relax,--gc-sections \
+ -Wl,--undefined=_mmcu,--section-start=.mmcu=0x910000 \
+ -I../include \
+ ${<} -o ${@}
+ @${AVR}size ${@}|sed '1d'
cores = ${wildcard cores/*.c}
cores_o = ${patsubst cores/%.c, obj/%.o, ${cores}}
-sim = ${wildcard sim/*.c}
+sim = ${wildcard sim/sim_*.c} ${wildcard sim/avr_*.c}
sim_o = ${patsubst sim/%.c, obj/%.o, ${sim}}
VPATH = .
CFLAGS += ${patsubst %,-I%,${subst :, ,${IPATH}}}
LFLAGS = -L/opt/local/lib/
-LDFLAGS += -lelf -lpthread
+LDFLAGS += -lelf
-all: obj ${target}
+all: obj ${target} libsimavr.a
obj:
@mkdir -p obj
@gcc $(CFLAGS) \
$< -c -o $@
@echo CC $<
-
+
+libsimavr.a : ${cores_o}
+libsimavr.a : ${sim_o}
+ ar cru $@ $^
+ ranlib $@
+
${target} : ${cores_o}
${target} : ${sim_o}
+${target} : obj/${target}.o
@gcc $(CFLAGS) $(LFLAGS) \
${^} -o $@ \
$(LDFLAGS)
@echo LD $@
clean:
- rm -rf ${target} obj
+ rm -rf ${target} obj *.a
#include "avr_ioport.h"
#include "avr_uart.h"
#include "avr_timer8.h"
+#include "avr_spi.h"
#define _AVR_IO_H_
#define __ASSEMBLER__
avr_ioport_t porta, portb, portc, portd;
avr_uart_t uart0,uart1;
avr_timer8_t timer0,timer2;
+ avr_spi_t spi;
} mcu = {
.core = {
.mmcu = "atmega644",
.vector = TIMER2_COMPB_vect,
},
},
+ .spi = {
+ .disabled = AVR_IO_REGBIT(PRR,PRSPI),
+
+ .r_spdr = SPDR,
+ .r_spcr = SPCR,
+ .r_spsr = SPSR,
+
+ .spe = AVR_IO_REGBIT(SPCR, SPE),
+ .mstr = AVR_IO_REGBIT(SPCR, MSTR),
+
+ .spr = { AVR_IO_REGBIT(SPCR, SPR0), AVR_IO_REGBIT(SPCR, SPR1), AVR_IO_REGBIT(SPSR, SPI2X) },
+ .spi = {
+ .enable = AVR_IO_REGBIT(SPCR, SPIE),
+ .raised = AVR_IO_REGBIT(SPSR, SPIF),
+ .vector = SPI_STC_vect,
+ },
+ },
};
static avr_t * make()
avr_uart_init(avr, &mcu->uart1);
avr_timer8_init(avr, &mcu->timer0);
avr_timer8_init(avr, &mcu->timer2);
+ avr_spi_init(avr, &mcu->spi);
}
static void reset(struct avr_t * avr)
}
avr_kind_t tiny85 = {
+ .names = { "attiny85" },
.make = make
};
#include <string.h>
#include "avr_eeprom.h"
-static void avr_eeprom_run(avr_t * avr, avr_io_t * port)
+static void avr_eeprom_run(avr_io_t * port)
{
avr_eeprom_t * p = (avr_eeprom_t *)port;
+ avr_t * avr = p->io.avr;
//printf("%s\n", __FUNCTION__);
if (p->eempe_clear_timer) {
p->eempe_clear_timer--;
}
}
-static void avr_eeprom_write(struct avr_t * avr, uint8_t addr, uint8_t v, void * param)
+static void avr_eeprom_write(avr_t * avr, uint8_t addr, uint8_t v, void * param)
{
avr_eeprom_t * p = (avr_eeprom_t *)param;
uint8_t eempe = avr_regbit_get(avr, p->eempe);
avr_regbit_clear(avr, p->eere);
}
-static int avr_eeprom_ioctl(avr_t * avr, avr_io_t * port, uint32_t ctl, void * io_param)
+static int avr_eeprom_ioctl(struct avr_io_t * port, uint32_t ctl, void * io_param)
{
avr_eeprom_t * p = (avr_eeprom_t *)port;
int res = -1;
#include <stdio.h>
#include "avr_ioport.h"
-static void avr_ioport_run(avr_t * avr, avr_io_t * port)
-{
- //printf("%s\n", __FUNCTION__);
-}
-
static uint8_t avr_ioport_read(struct avr_t * avr, uint8_t addr, void * param)
{
avr_ioport_t * p = (avr_ioport_t *)param;
// raise the internal IRQ callbacks
for (int i = 0; i < 8; i++)
if (mask & (1 << i))
- avr_raise_irq(avr, p->io.irq + i, (v >> i) & 1);
- avr_raise_irq(avr, p->io.irq + IOPORT_IRQ_PIN_ALL, v);
+ avr_raise_irq(p->io.irq + i, (v >> i) & 1);
+ avr_raise_irq(p->io.irq + IOPORT_IRQ_PIN_ALL, v);
}
}
}
* AVR code, or any external piece of code that see fit to do it.
* Either way, this will raise pin change interrupts, if needed
*/
-void avr_ioport_irq_notify(avr_t * avr, struct avr_irq_t * irq, uint32_t value, void * param)
+void avr_ioport_irq_notify(struct avr_irq_t * irq, uint32_t value, void * param)
{
avr_ioport_t * p = (avr_ioport_t *)param;
+ avr_t * avr = p->io.avr;
if (p->r_pcint) {
uint8_t mask = 1 << irq->irq;
// set the real PIN bit. ddr doesn't matter here as it's masked when read.
}
}
-static void avr_ioport_reset(avr_t * avr, avr_io_t * port)
+static void avr_ioport_reset(avr_io_t * port)
{
avr_ioport_t * p = (avr_ioport_t *)port;
for (int i = 0; i < IOPORT_IRQ_PIN_ALL; i++)
- avr_irq_register_notify(avr, p->io.irq + i, avr_ioport_irq_notify, p);
+ avr_irq_register_notify(p->io.irq + i, avr_ioport_irq_notify, p);
}
static avr_io_t _io = {
.kind = "io",
- .run = avr_ioport_run,
.reset = avr_ioport_reset,
};
// allocate this module's IRQ
p->io.irq_count = IOPORT_IRQ_COUNT;
- p->io.irq = avr_alloc_irq(avr, 0, p->io.irq_count);
+ p->io.irq = avr_alloc_irq(0, p->io.irq_count);
p->io.irq_ioctl_get = AVR_IOCTL_IOPORT_GETIRQ(p->name);
avr_register_io(avr, &p->io);
#include <stdio.h>
#include "avr_spi.h"
-static void avr_spi_run(avr_t * avr, avr_io_t * port)
-{
-// printf("%s\n", __FUNCTION__);
-}
-
static uint8_t avr_spi_read(struct avr_t * avr, uint8_t addr, void * param)
{
avr_spi_t * p = (avr_spi_t *)param;
- uint8_t v = avr->data[addr];
+ uint8_t v = p->input_data_register;
+ p->input_data_register = 0;
// printf("** PIN%c = %02x\n", p->name, v);
return v;
}
if (addr == p->r_spdr) {
// printf("UDR%c(%02x) = %02x\n", p->name, addr, v);
avr_core_watch_write(avr, addr, v);
+
+ if (avr_regbit_get(avr, p->spe)) {
+ // in master mode, any byte is sent as it comes..
+ if (avr_regbit_get(avr, p->mstr)) {
+ avr_raise_irq(p->io.irq + SPI_IRQ_OUTPUT, v);
+ }
+ }
}
}
-static void avr_spi_irq_input(avr_t * avr, struct avr_irq_t * irq, uint32_t value, void * param)
+static void avr_spi_irq_input(struct avr_irq_t * irq, uint32_t value, void * param)
{
avr_spi_t * p = (avr_spi_t *)param;
+ avr_t * avr = p->io.avr;
// check to see fi receiver is enabled
if (!avr_regbit_get(avr, p->spe))
return;
// double buffer the input.. ?
+ p->input_data_register = value;
+ avr_raise_interrupt(avr, &p->spi);
+
+ // if in slave mode,
+ // 'output' the byte only when we received one...
+ if (!avr_regbit_get(avr, p->mstr)) {
+ avr_raise_irq(p->io.irq + SPI_IRQ_OUTPUT, avr->data[p->r_spdr]);
+ }
}
-void avr_spi_reset(avr_t * avr, struct avr_io_t *io)
+void avr_spi_reset(struct avr_io_t *io)
{
avr_spi_t * p = (avr_spi_t *)io;
- avr_irq_register_notify(avr, p->io.irq + SPI_IRQ_INPUT, avr_spi_irq_input, p);
+ avr_irq_register_notify(p->io.irq + SPI_IRQ_INPUT, avr_spi_irq_input, p);
}
static avr_io_t _io = {
.kind = "spi",
- .run = avr_spi_run,
.reset = avr_spi_reset,
};
// 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 = avr_alloc_irq(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_regbit_t spr[4]; // clock divider
avr_int_vector_t spi; // spi interrupt
+
+ uint8_t input_data_register;
} avr_spi_t;
void avr_spi_init(avr_t * avr, avr_spi_t * port);
#include <stdio.h>
#include "avr_timer8.h"
-static void avr_timer8_run(avr_t * avr, avr_io_t * port)
+static void avr_timer8_run(avr_io_t * port)
{
avr_timer8_t * p = (avr_timer8_t *)port;
- //printf("%s\n", __FUNCTION__);
+ avr_t * avr = p->io.avr;
if (p->compa_cycles) {
if (p->compa_next == 0) {
}
-static void avr_timer8_reset(avr_t * avr, avr_io_t * port)
+static void avr_timer8_reset(avr_io_t * port)
{
}
DEFINE_FIFO(uint8_t, uart_fifo, 128);
-static void avr_uart_run(avr_t * avr, avr_io_t * port)
+static void avr_uart_run(avr_io_t * port)
{
avr_uart_t * p = (avr_uart_t *)port;
+ avr_t * avr = p->io.avr;
if (p->input_cycle_timer) {
p->input_cycle_timer--;
if (p->input_cycle_timer == 0) {
}
// tell other modules we are "outputing" a byte
if (avr_regbit_get(avr, p->txen))
- avr_raise_irq(avr, p->io.irq + UART_IRQ_OUTPUT, v);
+ avr_raise_irq(p->io.irq + UART_IRQ_OUTPUT, v);
} else {
// get the bits before the write
uint8_t udre = avr_regbit_get(avr, p->udrc.raised);
}
}
-static void avr_uart_irq_input(avr_t * avr, struct avr_irq_t * irq, uint32_t value, void * param)
+static void avr_uart_irq_input(struct avr_irq_t * irq, uint32_t value, void * param)
{
avr_uart_t * p = (avr_uart_t *)param;
+ avr_t * avr = p->io.avr;
// check to see fi receiver is enabled
if (!avr_regbit_get(avr, p->rxen))
}
-void avr_uart_reset(avr_t * avr, struct avr_io_t *io)
+void avr_uart_reset(struct avr_io_t *io)
{
avr_uart_t * p = (avr_uart_t *)io;
+ avr_t * avr = p->io.avr;
avr_regbit_set(avr, p->udrc.raised);
- avr_irq_register_notify(avr, p->io.irq + UART_IRQ_INPUT, avr_uart_irq_input, p);
+ avr_irq_register_notify(p->io.irq + UART_IRQ_INPUT, avr_uart_irq_input, p);
p->input_cycle_timer = 0;
uart_fifo_reset(&p->input);
}
// allocate this module's IRQ
p->io.irq_count = UART_IRQ_COUNT;
- p->io.irq = avr_alloc_irq(avr, 0, p->io.irq_count);
+ p->io.irq = avr_alloc_irq(0, p->io.irq_count);
p->io.irq_ioctl_get = AVR_IOCTL_UART_GETIRQ(p->name);
avr_register_io_write(avr, p->r_udr, avr_uart_write, p);
#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)
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_load_firmware(avr, &f);
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 (src && dst) {
+ printf("%s:%s activating uart local echo IRQ src %p dst %p\n", __FILE__, __FUNCTION__, src, dst);
+ avr_connect_irq(src, dst);
+ }
}
-
+ // even if not setup at startup, activate gdb if crashing
+ avr->gdb_port = 1234;
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);
-
+ avr_run(avr);
}
avr_io_t * port = avr->io_port;
while (port) {
if (port->reset)
- port->reset(avr, port);
+ port->reset(port);
port = port->next;
}
}
+void avr_sadly_crashed(avr_t *avr, uint8_t signal)
+{
+ avr->state = cpu_Stopped;
+ if (avr->gdb_port) {
+ // enable gdb server, and wait
+ if (!avr->gdb)
+ avr_gdb_init(avr);
+ }
+ if (!avr->gdb)
+ exit(1); // no gdb ?
+}
void avr_loadcode(avr_t * avr, uint8_t * code, uint32_t size, uint32_t address)
{
int avr_run(avr_t * avr)
{
- avr_gdb_processor(avr);
+ avr_gdb_processor(avr, avr->state == cpu_Stopped);
- if (avr->state == cpu_Stopped) {
- usleep(500);
+ if (avr->state == cpu_Stopped)
return avr->state;
- }
+ // if we are stepping one insruction, we "run" for one..
int step = avr->state == cpu_Step;
if (step) {
avr->state = cpu_Running;
avr_io_t * port = avr->io_port;
while (port) {
if (port->run)
- port->run(avr, port);
+ port->run(port);
port = port->next;
}
printf("simavr: sleeping with interrupts off, quitting gracefuly\n");
exit(0);
}
- usleep(500);
+ if (avr->gdb) {
+ while (avr_gdb_processor(avr, 1))
+ ;
+ } else
+ usleep(500);
long sleep = (float)avr->frequency * (1.0f / 500.0f);
avr->cycle += sleep;
// avr->state = cpu_Running;
// reset before each new instructions. Allows meaningful traces
uint32_t touched[256 / 32]; // debug
- // placeholder
+ // gdb hooking structure. Only present when gdb server is active
struct avr_gdb_t * gdb;
+ // if non-zero, the gdb server will be started when the core
+ // crashed even if not activated at startup
+ // if zero, the simulator will just exit() in case of a crash
+ int gdb_port;
} avr_t;
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);
+// called when the core has detected a crash somehow.
+// this might activate gdb server
+void avr_sadly_crashed(avr_t *avr, uint8_t signal);
#include "sim_io.h"
#include "sim_regbit.h"
}\
printf("Stack Ptr %04x/%04x = %d \n", _avr_sp_get(avr), avr->ramend, avr->ramend - _avr_sp_get(avr));\
DUMP_STACK();\
- exit(1);\
+ avr_sadly_crashed(avr, 0);\
}
#endif /* SIM_CORE_H_ */
#include <gelf.h>
#include "sim_elf.h"
+#include "avr_eeprom.h"
+
+void avr_load_firmware(avr_t * avr, elf_firmware_t * firmware)
+{
+ avr->frequency = firmware->mmcu.f_cpu;
+ avr->codeline = firmware->codeline;
+ avr_loadcode(avr, firmware->flash, firmware->flashsize, 0);
+ avr->codeend = firmware->flashsize - firmware->datasize;
+ if (firmware->eeprom && firmware->eesize) {
+ avr_eeprom_desc_t d = { .ee = firmware->eeprom, .offset = 0, .size = firmware->eesize };
+ avr_ioctl(avr, AVR_IOCTL_EEPROM_SET, &d);
+ }
+}
int elf_read_firmware(const char * file, elf_firmware_t * firmware)
{
} 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(struct 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
#define ELF_SYMBOLS 1
#endif
-#if ELF_SYMBOLS
#include "sim_avr.h"
-#endif
typedef struct elf_firmware_t {
struct avr_mcu_t mmcu;
int elf_read_firmware(const char * file, elf_firmware_t * firmware);
+void avr_load_firmware(avr_t * avr, elf_firmware_t * firmware);
+
#endif /* ELF_H_ */
#include "sim_avr.h"
#include "avr_eeprom.h"
+#define DBG(w)
+
typedef struct avr_gdb_t {
avr_t * avr;
int listen; // listen socket
int s; // current gdb connection
-
- pthread_t thread;
-
- uint32_t query_len;
- char query[1024];
uint32_t watchmap;
struct {
*dst++ = *cmd++;
}
sprintf((char*)dst, "#%02x", check);
- printf("%s '%s'\n", __FUNCTION__, reply);
+ DBG(printf("%s '%s'\n", __FUNCTION__, reply);)
send(g->s, reply, dst - reply + 3, 0);
}
char cmd[64];
sprintf(cmd, "T%02x20:%02x;21:%02x%02x;22:%02x%02x%02x00;",
- signal, g->avr->data[R_SREG],
+ signal ? signal : 5, 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);
+ DBG(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
return -1;
}
-static void gdb_handle_command(avr_gdb_t * g)
+static int gdb_write_register(avr_gdb_t * g, int regi, uint8_t * src)
+{
+ switch (regi) {
+ case 0 ... 31:
+ g->avr->data[regi] = *src;
+ return 1;
+ case 32:
+ g->avr->data[R_SREG] = * src;
+ return 1;
+ case 33:
+ g->avr->data[R_SPL] = *src++;
+ g->avr->data[R_SPH] = *src++;
+ return 2;
+ case 34:
+ g->avr->pc = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
+ return 4;
+ }
+ return 1;
+}
+
+static int gdb_read_register(avr_gdb_t * g, int regi, char * rep)
+{
+ 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;
+ }
+ return strlen(rep);
+}
+
+static void gdb_handle_command(avr_gdb_t * g, char * cmd)
{
avr_t * avr = g->avr;
- char * cmd = g->query;
char rep[1024];
uint8_t command = *cmd++;
switch (command) {
case '?':
- gdb_send_reply(g, "S00");
+ gdb_send_quick_status(g, 0);
break;
- case 'p': {
+ case 'G': { // set all general purpose registers
+ // get their binary form
+ read_hex_string(cmd, (uint8_t*)rep, strlen(cmd));
+ uint8_t *src = (uint8_t*)rep;
+ for (int i = 0; i < 35; i++)
+ src += gdb_write_register(g, i, src);
+ gdb_send_reply(g, "OK");
+ } break;
+ case 'g': { // read all general purpose registers
+ char * dst = rep;
+ for (int i = 0; i < 35; i++)
+ dst += gdb_read_register(g, i, dst);
+ gdb_send_reply(g, rep);
+ } break;
+ case 'p': { // read register
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_read_register(g, regi, rep);
gdb_send_reply(g, rep);
} break;
- case 'm': {
+ case 'P': { // write register
+ unsigned int regi = 0;
+ char * val = strchr(cmd, '=');
+ if (!val)
+ break;
+ *val++ = 0;
+ sscanf(cmd, "%x", ®i);
+ read_hex_string(val, (uint8_t*)rep, strlen(val));
+ gdb_write_register(g, regi, (uint8_t*)rep);
+ gdb_send_reply(g, "OK");
+ } break;
+ case 'm': { // read memory
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)) {
+ } else if (addr >= 0x810000 && (addr - 0x810000) <= avr->e2end) {
avr_eeprom_desc_t ee = {.offset = (addr - 0x810000)};
avr_ioctl(avr, AVR_IOCTL_EEPROM_GET, &ee);
if (ee.ee)
else
gdb_send_reply(g, "E01");
} else {
+ printf("read memory error %08x, %08x (ramend %04x)\n", addr, len, avr->ramend+1);
gdb_send_reply(g, "E01");
break;
}
*dst = 0;
gdb_send_reply(g, rep);
} break;
- case 'M': {
+ case 'M': { // write memory
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");
} 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");
+ } else if (addr >= 0x810000 && (addr - 0x810000) <= avr->e2end) {
+ read_hex_string(start + 1, (uint8_t*)rep, strlen(start+1));
+ avr_eeprom_desc_t ee = {.offset = (addr - 0x810000), .size = len, .ee = (uint8_t*)rep };
+ avr_ioctl(avr, AVR_IOCTL_EEPROM_SET, &ee);
+ gdb_send_reply(g, "OK");
+ } else {
+ printf("write memory error %08x, %08x\n", addr, len);
+ gdb_send_reply(g, "E01");
+ }
} break;
- case 'c': {
+ case 'c': { // continue
avr->state = cpu_Running;
} break;
- case 's': {
+ case 's': { // step
avr->state = cpu_Step;
} break;
- case 'Z':
+ case 'Z': // set clear break/watchpoint
case 'z': {
uint32_t kind, addr, len;
sscanf(cmd, "%d,%x,%x", &kind, &addr, &len);
- printf("breakbpoint %d, %08x, %08x\n", kind, addr, len);
+// printf("breakbpoint %d, %08x, %08x\n", kind, addr, len);
switch (kind) {
case 0: // software breakpoint
case 1: // hardware breakpoint
} else
gdb_send_reply(g, "E01"); // out of flash address
break;
+ // TODO
case 2: // write watchpoint
case 3: // read watchpoint
case 4: // access watchpoint
}
}
-void avr_gdb_processor(avr_t * avr)
+static int gdb_network_handler(avr_gdb_t * g, int dosleep)
+{
+ fd_set read_set;
+ int max;
+ FD_ZERO(&read_set);
+
+ if (g->s != -1) {
+ FD_SET(g->s, &read_set);
+ max = g->s + 1;
+ } else {
+ FD_SET(g->listen, &read_set);
+ max = g->listen + 1;
+ }
+ struct timeval timo = { 0, dosleep ? 500 : 0 }; // short, but not too short interval
+ int ret = select(max, &read_set, NULL, NULL, &timo);
+
+ if (ret == 0)
+ return 0;
+
+ if (FD_ISSET(g->listen, &read_set)) {
+ g->s = accept(g->listen, NULL, NULL);
+
+ if (g->s == -1) {
+ perror("gdb_network_handler accept");
+ sleep(5);
+ return 1;
+ }
+ int i = 1;
+ setsockopt (g->s, IPPROTO_TCP, TCP_NODELAY, &i, sizeof (i));
+ g->avr->state = cpu_Stopped;
+ printf("%s connection opened\n", __FUNCTION__);
+ }
+
+ 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__);
+ close(g->s);
+ g->watchmap = 0; // clear breakpoints
+ g->avr->state = cpu_Running; // resume
+ g->s = -1;
+ return 1;
+ }
+ if (r == -1) {
+ perror("gdb_network_handler recv");
+ sleep(1);
+ return 1;
+ }
+ 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++;
+ // control C -- lets send the guy a nice status packet
+ if (*src == 3) {
+ src++;
+ g->avr->state = cpu_StepDone;
+ printf("GDB hit control-c\n");
+ }
+ if (*src == '$') {
+ // strip checksum
+ uint8_t * end = buffer + r - 1;
+ while (end > src && *end != '#')
+ *end-- = 0;
+ *end = 0;
+ src++;
+ DBG(printf("GDB command = '%s'\n", src);)
+
+ send(g->s, "+", 1, 0);
+
+ gdb_handle_command(g, (char*)src);
+ }
+ }
+ return 1;
+}
+
+int avr_gdb_processor(avr_t * avr, int sleep)
{
if (!avr || !avr->gdb)
- return;
+ return 0;
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);
+ DBG(printf("avr_gdb_processor hit breakpoint at %08x\n", avr->pc);)
gdb_send_quick_status(g, 0);
avr->state = cpu_Stopped;
}
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;
+ // this also sleeps for a bit
+ return gdb_network_handler(g, sleep);
}
struct sockaddr_in address = { 0 };
address.sin_family = AF_INET;
- address.sin_port = htons (1234);
+ address.sin_port = htons (avr->gdb_port);
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);
+ if (listen(g->listen, 1)) {
+ perror("listen");
+ return -1;
+ }
+ printf("avr_gdb_init listening on port %d\n", avr->gdb_port);
g->avr = avr;
+ g->s = -1;
avr->gdb = g;
-
- pthread_create(&g->thread, NULL, gdb_network_handler, g);
-
+
return 0;
}
int avr_gdb_init(avr_t * avr);
// call from the main AVR decoder thread
-void avr_gdb_processor(avr_t * avr);
+int avr_gdb_processor(avr_t * avr, int sleep);
#endif
avr->pending[v >> 5] &= ~(1 << (v & 0x1f));
if (!vector)
return;
- printf("%s cleared %d\n", __FUNCTION__, vector->vector);
+// printf("%s cleared %d\n", __FUNCTION__, vector->vector);
if (vector->raised.reg)
avr_regbit_clear(avr, vector->raised);
}
int res = -1;
while (port && res == -1) {
if (port->ioctl)
- res = port->ioctl(avr, port, ctl, io_param);
+ res = port->ioctl(port, ctl, io_param);
port = port->next;
}
return res;
void avr_register_io(avr_t *avr, avr_io_t * io)
{
io->next = avr->io_port;
+ io->avr = avr;
avr->io_port = io;
}
* Modules uses that as their first member in their own struct
*/
typedef struct avr_io_t {
- struct avr_io_t * next;
+ struct avr_io_t * next;
+ avr_t * avr; // avr we are attached to
const char * kind; // pretty name, for debug
uint32_t irq_ioctl_get; // used to get irqs from this module
int irq_count; // number of (optional) irqs
struct avr_irq_t * irq; // optional external IRQs
// called at every instruction
- void (*run)(avr_t * avr, struct avr_io_t *io);
+ void (*run)(struct avr_io_t *io);
// called at reset time
- void (*reset)(avr_t * avr, struct avr_io_t *io);
+ void (*reset)(struct avr_io_t *io);
// called externally. allow access to io modules and so on
- int (*ioctl)(avr_t * avr, struct avr_io_t *io, uint32_t ctl, void *io_param);
+ int (*ioctl)(struct avr_io_t *io, uint32_t ctl, void *io_param);
} avr_io_t;
/*
#include "sim_irq.h"
-void avr_init_irq(avr_t * avr, avr_irq_t * irq, uint32_t base, uint32_t count)
+void avr_init_irq(avr_irq_t * irq, uint32_t base, uint32_t count)
{
memset(irq, 0, sizeof(avr_irq_t) * count);
irq[i].irq = base + i;
}
-avr_irq_t * avr_alloc_irq(avr_t * avr, uint32_t base, uint32_t count)
+avr_irq_t * avr_alloc_irq(uint32_t base, uint32_t count)
{
avr_irq_t * irq = (avr_irq_t*)malloc(sizeof(avr_irq_t) * count);
- avr_init_irq(avr, irq, base, count);
+ avr_init_irq(irq, base, count);
return irq;
}
-void avr_irq_register_notify(avr_t * avr, avr_irq_t * irq, avr_irq_notify_t notify, void * param)
+void avr_irq_register_notify(avr_irq_t * irq, avr_irq_notify_t notify, void * param)
{
if (!irq || !notify)
return;
irq->hook = hook;
}
-void avr_raise_irq(avr_t * avr, avr_irq_t * irq, uint32_t value)
+void avr_raise_irq(avr_irq_t * irq, uint32_t value)
{
if (!irq || irq->value == value)
return ;
avr_irq_hook_t *hook = irq->hook;
while (hook) {
- if (hook->notify) {
+ if (hook->notify) {
+ // prevents reentrance / endless calling loops
if (hook->busy == 0) {
hook->busy++;
- hook->notify(avr, irq, value, hook->param);
+ hook->notify(irq, value, hook->param);
hook->busy--;
}
}
irq->value = value;
}
-static void _avr_irq_connect(avr_t * avr, avr_irq_t * irq, uint32_t value, void * param)
+static void _avr_irq_connect(avr_irq_t * irq, uint32_t value, void * param)
{
avr_irq_t * dst = (avr_irq_t*)param;
- avr_raise_irq(avr, dst, value);
+ avr_raise_irq(dst, value);
}
-void avr_connect_irq(avr_t * avr, avr_irq_t * src, avr_irq_t * dst)
+void avr_connect_irq(avr_irq_t * src, avr_irq_t * dst)
{
- avr_irq_register_notify(avr, src, _avr_irq_connect, dst);
+ avr_irq_register_notify(src, _avr_irq_connect, dst);
}
#ifndef __SIM_IRQ_H__
#define __SIM_IRQ_H__
-#include "sim_avr.h"
+#include <stdint.h>
/*
* Internal IRQ system
// internal structure for a hook, never seen by the notify procs
struct avr_irq_t;
-typedef void (*avr_irq_notify_t)(avr_t * avr, struct avr_irq_t * irq, uint32_t value, void * param);
+typedef void (*avr_irq_notify_t)(struct avr_irq_t * irq, uint32_t value, void * param);
typedef struct avr_irq_hook_t {
struct avr_irq_hook_t * next;
avr_irq_hook_t * hook;
} avr_irq_t;
-avr_irq_t * avr_alloc_irq(avr_t * avr, uint32_t base, uint32_t count);
-void avr_init_irq(avr_t * avr, avr_irq_t * irq, uint32_t base, uint32_t count);
-void avr_raise_irq(avr_t * avr, avr_irq_t * irq, uint32_t value);
+avr_irq_t * avr_alloc_irq(uint32_t base, uint32_t count);
+void avr_init_irq(avr_irq_t * irq, uint32_t base, uint32_t count);
+void avr_raise_irq(avr_irq_t * irq, uint32_t value);
// this connects a "source" IRQ to a "destination" IRQ
-void avr_connect_irq(avr_t * avr, avr_irq_t * src, avr_irq_t * dst);
-void avr_irq_register_notify(avr_t * avr, avr_irq_t * irq, avr_irq_notify_t notify, void * param);
+void avr_connect_irq(avr_irq_t * src, avr_irq_t * dst);
+void avr_irq_register_notify(avr_irq_t * irq, avr_irq_notify_t notify, void * param);
#endif /* __SIM_IRQ_H__ */
all : ${sources:.c=.axf} ${sources:.c=.hex} ${sources:.c=.s}
-%.hex: %.axf
- @${AVR}objcopy -j .text -j .data -O ihex ${<} ${@}
-
-%.s: %.axf
- @${AVR}objdump -j .text -j .data -j .bss -d ${<} > ${@}
-
-%.axf: %.c
- @echo CC ${<}
- @part=${<} ; part=$${part/_*}; \
- ${AVR}gcc -Wall -g -Os -std=gnu99 \
- -mmcu=$$part \
- -DF_CPU=8000000 \
- -mcall-prologues -fno-inline-small-functions \
- -ffunction-sections -fdata-sections \
- -Wl,--relax,--gc-sections \
- -Wl,--undefined=_mmcu,--section-start=.mmcu=0x910000 \
- -I../include \
- ${<} -o ${@}
- @${AVR}size ${@}|sed '1d'
+include ../Makefile.common
clean:
rm -f *.hex *.o *.axf *.s
--- /dev/null
+/*
+ * attiny85_crash_gdb.c
+ *
+ * Created on: 1 Dec 2009
+ * Author: jone
+ */
+
+#include <avr/sleep.h>
+#include "avr_mcu_section.h"
+
+AVR_MCU(F_CPU, "attiny85");
+
+int value = 0;
+
+int main()
+{
+
+ /*
+ * this is not much, but that crashed the core, and should activate
+ * the gdb server properly, so you can see it stopped, here
+ */
+ value++;
+
+ *((uint8_t*)0xdead) = 0x55;
+
+ // should never reach here !
+ value++;
+ sleep_mode();
+}