From 934b0dfa91511da5c948196dd3a634b11647b991 Mon Sep 17 00:00:00 2001 From: Michel Pollet Date: Wed, 19 Oct 2016 10:46:08 +0100 Subject: [PATCH] cmds: rewrite command handling and move to separate file Move AVR command handling code to separate file and add support for multi-byte, as well as user-defined, commands. (cherry picked from commit c627c3720a6dcb1f8f7a3068510f11e3fbee0ce4) --- simavr/sim/sim_avr.c | 29 +------ simavr/sim/sim_avr.h | 3 + simavr/sim/sim_cmds.c | 187 ++++++++++++++++++++++++++++++++++++++++++ simavr/sim/sim_cmds.h | 82 ++++++++++++++++++ 4 files changed, 274 insertions(+), 27 deletions(-) create mode 100644 simavr/sim/sim_cmds.c create mode 100644 simavr/sim/sim_cmds.h diff --git a/simavr/sim/sim_avr.c b/simavr/sim/sim_avr.c index 88c6019..8551e5c 100644 --- a/simavr/sim/sim_avr.c +++ b/simavr/sim/sim_avr.c @@ -82,6 +82,7 @@ int avr_init(avr_t * avr) // cpu is in limbo before init is finished. avr->state = cpu_Limbo; avr->frequency = 1000000; // can be overridden via avr_mcu_section + avr_cmd_init(avr); avr_interrupt_init(avr); if (avr->custom.init) avr->custom.init(avr, avr->custom.data); @@ -159,35 +160,9 @@ void avr_sadly_crashed(avr_t *avr, uint8_t signal) avr->state = cpu_Crashed; } -static void _avr_io_command_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) -{ - AVR_LOG(avr, LOG_TRACE, "%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) { - AVR_LOG(avr, LOG_TRACE, "%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); + avr_cmd_set_register(avr, addr); } static void _avr_io_console_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) diff --git a/simavr/sim/sim_avr.h b/simavr/sim/sim_avr.h index fbd15d5..00ad9b7 100644 --- a/simavr/sim/sim_avr.h +++ b/simavr/sim/sim_avr.h @@ -28,6 +28,7 @@ extern "C" { #include "sim_irq.h" #include "sim_interrupts.h" +#include "sim_cmds.h" #include "sim_cycle_timers.h" typedef uint32_t avr_flashaddr_t; @@ -290,6 +291,8 @@ typedef struct avr_t { // queue of io modules struct avr_io_t *io_port; + // Builtin and user-defined commands + avr_cmd_table_t commands; // cycle timers tracking & delivery avr_cycle_timer_pool_t cycle_timers; // interrupt vectors and delivery fifo diff --git a/simavr/sim/sim_cmds.c b/simavr/sim/sim_cmds.c new file mode 100644 index 0000000..bb5f308 --- /dev/null +++ b/simavr/sim/sim_cmds.c @@ -0,0 +1,187 @@ +/* + sim_cmds.c + + Copyright 2014 Florian Albrechtskirchinger + + 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 . + */ + + +#include +#include +#include "sim_avr.h" +#include "sim_cmds.h" +#include "sim_vcd_file.h" +#include "avr_uart.h" +#include "avr/avr_mcu_section.h" + +#define LOG_PREFIX "CMDS: " + +static void +_avr_cmd_io_write( + avr_t * avr, + avr_io_addr_t addr, + uint8_t v, + void * param) +{ + avr_cmd_table_t * commands = &avr->commands; + avr_cmd_t * command = commands->pending; + + AVR_LOG(avr, LOG_TRACE, LOG_PREFIX "%s: 0x%02x\n", __FUNCTION__, v); + + if (!command) { + if (v > MAX_AVR_COMMANDS) { + AVR_LOG(avr, LOG_ERROR, LOG_PREFIX + "%s: code 0x%02x outside permissible range (>0x%02x)\n", + __FUNCTION__, v, MAX_AVR_COMMANDS - 1); + return; + } + command = &commands->table[v]; + } + + if (command) { + if (command->handler(avr, v, command->param)) + commands->pending = command; + else + commands->pending = NULL; + } else + AVR_LOG(avr, LOG_TRACE, LOG_PREFIX "%s: unknown command 0x%02x\n", + __FUNCTION__, v); +} + +void +avr_cmd_set_register( + avr_t * avr, + avr_io_addr_t addr) +{ + if (addr) + avr_register_io_write(avr, addr, &_avr_cmd_io_write, NULL); +} + +void +avr_cmd_register( + avr_t * avr, + uint8_t code, + avr_cmd_handler_t handler, + void * param) +{ + avr_cmd_table_t * commands = &avr->commands; + avr_cmd_t * command; + + if (!handler) + return; + + if (code > MAX_AVR_COMMANDS) { + AVR_LOG(avr, LOG_ERROR, LOG_PREFIX + "%s: code 0x%02x outside permissible range (>0x%02x)\n", + __FUNCTION__, code, MAX_AVR_COMMANDS - 1); + return; + } + + command = &commands->table[code]; + if (command->handler) { + AVR_LOG(avr, LOG_ERROR, LOG_PREFIX + "%s: code 0x%02x is already registered\n", + __FUNCTION__, code); + return; + } + + command->handler = handler; + command->param = param; +} + +void +avr_cmd_unregister( + avr_t * avr, + uint8_t code) +{ + avr_cmd_table_t * commands = &avr->commands; + avr_cmd_t * command; + + if (code > MAX_AVR_COMMANDS) { + AVR_LOG(avr, LOG_ERROR, LOG_PREFIX + "%s: code 0x%02x outside permissible range (>0x%02x)\n", + __FUNCTION__, code, MAX_AVR_COMMANDS - 1); + return; + } + + command = &commands->table[code]; + if (command->handler) { + if(command->param) + free(command->param); + + command->handler = NULL; + command->param = NULL; + } else + AVR_LOG(avr, LOG_ERROR, LOG_PREFIX + "%s: no command registered for code 0x%02x\n", + __FUNCTION__, code); +} + +static int +_simavr_cmd_vcd_start_trace( + avr_t * avr, + uint8_t v, + void * param) +{ + if (avr->vcd) + avr_vcd_start(avr->vcd); + + return 0; +} + +static int +_simavr_cmd_vcd_stop_trace( + avr_t * avr, + uint8_t v, + void * param) +{ + if (avr->vcd) + avr_vcd_stop(avr->vcd); + + return 0; +} + +static int +_simavr_cmd_uart_loopback( + avr_t * avr, + uint8_t v, + void * param) +{ + 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) { + AVR_LOG(avr, LOG_TRACE, LOG_PREFIX + "%s: activating uart local echo; IRQ src %p dst %p\n", + __FUNCTION__, src, dst); + avr_connect_irq(src, dst); + } + + return 0; +} + +void +avr_cmd_init( + avr_t * avr) +{ + memset(&avr->commands, 0, sizeof(avr->commands)); + + // Register builtin commands + avr_cmd_register(avr, SIMAVR_CMD_VCD_START_TRACE, &_simavr_cmd_vcd_start_trace, NULL); + avr_cmd_register(avr, SIMAVR_CMD_VCD_STOP_TRACE, &_simavr_cmd_vcd_stop_trace, NULL); + avr_cmd_register(avr, SIMAVR_CMD_UART_LOOPBACK, &_simavr_cmd_uart_loopback, NULL); +} diff --git a/simavr/sim/sim_cmds.h b/simavr/sim/sim_cmds.h new file mode 100644 index 0000000..aac75fc --- /dev/null +++ b/simavr/sim/sim_cmds.h @@ -0,0 +1,82 @@ +/* + sim_cmds.h + + Copyright 2014 Florian Albrechtskirchinger + + 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 . + */ + +#pragma once + +#include "sim_avr_types.h" + +#define MAX_AVR_COMMANDS 32 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int (*avr_cmd_handler_t)( + struct avr_t * avr, + uint8_t v, + void * param); + +typedef struct avr_cmd_t { + avr_cmd_handler_t handler; + void * param; +} avr_cmd_t; + +typedef struct avr_cmd_table_t { + avr_cmd_t table[MAX_AVR_COMMANDS]; + avr_cmd_t * pending; // Holds a reference to a pending multi-byte command +} avr_cmd_table_t; + +// Called by avr_set_command_register() +void +avr_cmd_set_register( + struct avr_t * avr, + avr_io_addr_t addr); + +/* + * Register a command distinguished by 'code'. + * + * When 'code' is written to the configured IO address, 'handler' is executed + * with the value written, as well as 'param'. + * 'handler' can return non-zero, to indicate, that this is a multi-byte command. + * Subsequent writes are then dispatched to the same handler, until 0 is returned. + */ +void +avr_cmd_register( + struct avr_t * avr, + uint8_t code, + avr_cmd_handler_t handler, + void * param); + +void +avr_cmd_unregister( + struct avr_t * avr, + uint8_t code); + +// Private functions + +// Called from avr_init() to initialize the avr_cmd_table_t and register builtin commands. +void +avr_cmd_init( + struct avr_t * avr); + +#ifdef __cplusplus +} +#endif -- 2.39.5