Commit 934b0dfa91511da5c948196dd3a634b11647b991
authorMichel Pollet <michel.pollet@bp.renesas.com>
Wed, 19 Oct 2016 09:46:08 +0000 (10:46 +0100)
committerMichel Pollet <michel.pollet@bp.renesas.com>
Wed, 19 Oct 2016 10:03:56 +0000 (11:03 +0100)
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)

4 files changed:
simavr/sim/sim_avr.c
simavr/sim/sim_avr.h
simavr/sim/sim_cmds.c [new file with mode: 0644]
simavr/sim/sim_cmds.h [new file with mode: 0644]

index 88c60191ee0ccd912853ca7d7428e65a292023ed..8551e5c2804316b22fd606b42bbe4470ce2bff50 100644 (file)
@@ -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)
index fbd15d54e3c00fe718db626652a8a62bc47fb0df..00ad9b76952cf364a01d49110c808ecbfa607da3 100644 (file)
@@ -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 (file)
index 0000000..bb5f308
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+       sim_cmds.c
+
+       Copyright 2014 Florian Albrechtskirchinger <falbrechtskirchinger@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 <string.h>
+#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 (file)
index 0000000..aac75fc
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+       sim_cmds.h
+
+       Copyright 2014 Florian Albrechtskirchinger <falbrechtskirchinger@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/>.
+ */
+
+#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