From cb533ae28fd0e051e42bdeae43965ec6faf9ae1f Mon Sep 17 00:00:00 2001 From: Michel Pollet Date: Wed, 23 Dec 2009 22:17:46 +0000 Subject: [PATCH] core: Added a new ELF tag with AVR->simavr command path This new mode allow the AVR firmware to specify an (unused) AVR IO register as a "command path" to send commands back to simavr. It allows for example the firmware to start/stop the VCD trace dump, exactly where it should from the ooint of view of the firmware being ran. See atmega88_uart_echo.c for an example. Signed-off-by: Michel Pollet --- include/avr_mcu_section.h | 28 +++++++++++++++++++++++++++- simavr/sim/sim_avr.c | 33 +++++++++++++++++++++++++++++++++ simavr/sim/sim_avr.h | 3 +++ simavr/sim/sim_elf.c | 14 ++++++++++---- simavr/sim/sim_elf.h | 16 ++++++++++------ tests/atmega88_uart_echo.c | 6 +++++- 6 files changed, 88 insertions(+), 12 deletions(-) diff --git a/include/avr_mcu_section.h b/include/avr_mcu_section.h index eb36512..01118ca 100644 --- a/include/avr_mcu_section.h +++ b/include/avr_mcu_section.h @@ -48,11 +48,19 @@ enum { AVR_MMCU_TAG_HFUSE, AVR_MMCU_TAG_EFUSE, AVR_MMCU_TAG_SIGNATURE, + AVR_MMCU_TAG_SIMAVR_COMMAND, AVR_MMCU_TAG_VCD_FILENAME, AVR_MMCU_TAG_VCD_PERIOD, AVR_MMCU_TAG_VCD_TRACE, }; +enum { + SIMAVR_CMD_NONE = 0, + SIMAVR_CMD_VCD_START_TRACE, + SIMAVR_CMD_VCD_STOP_TRACE, + SIMAVR_CMD_UART_LOOPBACK, +}; + #if __AVR__ #define _MMCU_ __attribute__((section(".mmcu"))) @@ -68,6 +76,12 @@ struct avr_mmcu_string_t { char string[]; } __attribute__((__packed__)); +struct avr_mmcu_addr_t { + uint8_t tag; + uint8_t len; + void * what; +} __attribute__((__packed__)); + struct avr_mmcu_vcd_trace_t { uint8_t tag; uint8_t len; @@ -98,13 +112,25 @@ const uint8_t _##_tag _MMCU_ = { _tag, 1, _val } .len = sizeof(struct avr_mmcu_vcd_trace_t) - 2 + sizeof(_name),\ .name = _name -// specified the nane and wanted period (usec) for a VCD file +// specified the name and wanted period (usec) for a VCD file // thid is not mandatory, a default one will be created if // symbols are declared themselves #define AVR_MCU_VCD_FILE(_name, _period) \ AVR_MCU_STRING(AVR_MMCU_TAG_VCD_FILENAME, _name);\ AVR_MCU_LONG(AVR_MMCU_TAG_VCD_PERIOD, _period) +// It is possible to send "commands" to simavr from the +// firmware itself. For this to work you need to specify +// an IO register that is to be used for a write-only +// bridge. A favourite is one of the usual "GPIO register" +// that most (all ?) AVR have +#define AVR_MCU_SIMAVR_COMMAND(_register) \ + const struct avr_mmcu_addr_t _simavr_command_register _MMCU_ = {\ + .tag = AVR_MMCU_TAG_SIMAVR_COMMAND,\ + .len = sizeof(void *),\ + .what = (void*)_register, \ + } + /* * This the has to be used if you want to add other tags to the .mmcu section * the _mmcu symbol is used as an anchor to make sure it stays linked in. diff --git a/simavr/sim/sim_avr.c b/simavr/sim/sim_avr.c index 1af351e..1682c2e 100644 --- a/simavr/sim/sim_avr.c +++ b/simavr/sim/sim_avr.c @@ -26,7 +26,9 @@ #include "sim_avr.h" #include "sim_core.h" #include "sim_gdb.h" +#include "avr_uart.h" #include "sim_vcd_file.h" +#include "avr_mcu_section.h" int avr_init(avr_t * avr) @@ -73,6 +75,7 @@ void avr_reset(avr_t * avr) void avr_sadly_crashed(avr_t *avr, uint8_t signal) { + printf("%s\n", __FUNCTION__); avr->state = cpu_Stopped; if (avr->gdb_port) { // enable gdb server, and wait @@ -83,6 +86,36 @@ void avr_sadly_crashed(avr_t *avr, uint8_t signal) exit(1); // no gdb ? } +static void _avr_io_command_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) +{ + printf("%s %02x\n", __FUNCTION__, v); + switch (v) { + case SIMAVR_CMD_VCD_START_TRACE: + if (avr->vcd) + avr_vcd_start(avr->vcd); + break; + case SIMAVR_CMD_VCD_STOP_TRACE: + if (avr->vcd) + avr_vcd_stop(avr->vcd); + break; + case SIMAVR_CMD_UART_LOOPBACK: { + 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); + if (src && dst) { + printf("%s activating uart local echo IRQ src %p dst %p\n", __FUNCTION__, src, dst); + avr_connect_irq(src, dst); + } + } break; + + } +} + +void avr_set_command_register(avr_t * avr, avr_io_addr_t addr) +{ + if (addr) + avr_register_io_write(avr, addr, _avr_io_command_write, NULL); +} + void avr_loadcode(avr_t * avr, uint8_t * code, uint32_t size, uint32_t address) { memcpy(avr->flash + address, code, size); diff --git a/simavr/sim/sim_avr.h b/simavr/sim/sim_avr.h index e763f04..5a96a19 100644 --- a/simavr/sim/sim_avr.h +++ b/simavr/sim/sim_avr.h @@ -229,6 +229,9 @@ int avr_run(avr_t * avr); // finish any pending operations void avr_terminate(avr_t * avr); +// set an IO register to receive commands from the AVR firmware +// it's optional, and uses the ELF tags +void avr_set_command_register(avr_t * avr, avr_io_addr_t addr); // load code in the "flash" void avr_loadcode(avr_t * avr, uint8_t * code, uint32_t size, uint32_t address); diff --git a/simavr/sim/sim_elf.c b/simavr/sim/sim_elf.c index 92785e0..723cda9 100644 --- a/simavr/sim/sim_elf.c +++ b/simavr/sim/sim_elf.c @@ -42,13 +42,13 @@ void avr_load_firmware(avr_t * avr, elf_firmware_t * firmware) #if CONFIG_SIMAVR_TRACE avr->codeline = firmware->codeline; #endif - avr_loadcode(avr, firmware->flash, firmware->flashsize, 0); - avr->codeend = firmware->flashsize - firmware->datasize; + avr_loadcode(avr, firmware->flash, firmware->flashsize, firmware->flashbase); + avr->codeend = firmware->flashsize + firmware->flashbase - 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); } - + avr_set_command_register(avr, firmware->command_register_addr); if (firmware->tracecount == 0) return; avr->vcd = malloc(sizeof(*avr->vcd)); @@ -93,7 +93,10 @@ void avr_load_firmware(avr_t * avr, elf_firmware_t * firmware) } } } - avr_vcd_start(avr->vcd); + // if the firmware has specified a command register, do NOT start the trace here + // the firmware probably knows best when to start/stop it + if (!firmware->command_register_addr) + avr_vcd_start(avr->vcd); } static void elf_parse_mmcu_section(elf_firmware_t * firmware, uint8_t * src, uint32_t size) @@ -129,6 +132,9 @@ static void elf_parse_mmcu_section(elf_firmware_t * firmware, uint8_t * src, uin firmware->traceperiod = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24); } break; + case AVR_MMCU_TAG_SIMAVR_COMMAND: { + firmware->command_register_addr = src[0] | (src[1] << 8); + } break; } size -= next; src += next - 2; // already incremented diff --git a/simavr/sim/sim_elf.h b/simavr/sim/sim_elf.h index f12c8f7..172b1c5 100644 --- a/simavr/sim/sim_elf.h +++ b/simavr/sim/sim_elf.h @@ -43,13 +43,17 @@ typedef struct elf_firmware_t { char name[64]; } trace[32]; - uint8_t * flash; - uint32_t flashsize; - uint32_t datasize; - uint32_t bsssize; + // register to listen to for commands from the firmware + uint16_t command_register_addr; + + uint32_t flashbase; // base address + uint8_t * flash; + uint32_t flashsize; + uint32_t datasize; + uint32_t bsssize; // read the .eeprom section of the elf, too - uint8_t * eeprom; - uint32_t eesize; + uint8_t * eeprom; + uint32_t eesize; #if ELF_SYMBOLS avr_symbol_t ** codeline; diff --git a/tests/atmega88_uart_echo.c b/tests/atmega88_uart_echo.c index c2b4ba3..c904013 100644 --- a/tests/atmega88_uart_echo.c +++ b/tests/atmega88_uart_echo.c @@ -21,7 +21,8 @@ */ #include "avr_mcu_section.h" AVR_MCU(F_CPU, "atmega88"); - +// tell simavr to listen to commands written in this (unused) register +AVR_MCU_SIMAVR_COMMAND(&GPIOR0); static int uart_putchar(char c, FILE *stream) { if (c == '\n') @@ -49,6 +50,9 @@ ISR(USART_RX_vect) int main() { + // this tell simavr to put the UART in loopback mode + GPIOR0 = SIMAVR_CMD_UART_LOOPBACK; + stdout = &mystdout; // enable receiver -- 2.39.5