From 46b57676df609623515f691b0af46192ecc74615 Mon Sep 17 00:00:00 2001 From: Manfred Steiner Date: Sun, 27 Nov 2022 16:24:15 +0100 Subject: [PATCH] simuc option board, debian packet creation --- README.md | 33 +- examples/Makefile | 2 + examples/simuc/.gitignore | 4 + examples/simuc/.vscode/launch.json | 21 + examples/simuc/.vscode/settings.json | 87 + examples/simuc/.vscode/tasks.json | 26 + examples/simuc/Makefile | 111 ++ examples/simuc/README.md | 64 + .../htl-simuc_version_arch/DEBIAN/control | 10 + .../dpkg/htl-simuc_version_arch/usr/bin/simuc | 1 + .../usr/share/doc/htl-simuc/copyright | 43 + .../usr/share/doc/htl-simuc/readme | 5 + .../usr/share/htl-simuc/readme | 1 + .../simavr/sim/avr/avr_mcu_section.h | 332 ++++ .../share/htl-simuc/simavr/sim/avr_acomp.c | 241 +++ .../share/htl-simuc/simavr/sim/avr_acomp.h | 89 + .../usr/share/htl-simuc/simavr/sim/avr_adc.c | 427 +++++ .../usr/share/htl-simuc/simavr/sim/avr_adc.h | 193 +++ .../share/htl-simuc/simavr/sim/avr_bitbang.c | 248 +++ .../share/htl-simuc/simavr/sim/avr_bitbang.h | 117 ++ .../share/htl-simuc/simavr/sim/avr_eeprom.c | 148 ++ .../share/htl-simuc/simavr/sim/avr_eeprom.h | 131 ++ .../share/htl-simuc/simavr/sim/avr_extint.c | 228 +++ .../share/htl-simuc/simavr/sim/avr_extint.h | 129 ++ .../share/htl-simuc/simavr/sim/avr_flash.c | 145 ++ .../share/htl-simuc/simavr/sim/avr_flash.h | 92 ++ .../share/htl-simuc/simavr/sim/avr_ioport.c | 340 ++++ .../share/htl-simuc/simavr/sim/avr_ioport.h | 148 ++ .../usr/share/htl-simuc/simavr/sim/avr_lin.c | 106 ++ .../usr/share/htl-simuc/simavr/sim/avr_lin.h | 55 + .../usr/share/htl-simuc/simavr/sim/avr_spi.c | 119 ++ .../usr/share/htl-simuc/simavr/sim/avr_spi.h | 107 ++ .../share/htl-simuc/simavr/sim/avr_timer.c | 985 +++++++++++ .../share/htl-simuc/simavr/sim/avr_timer.h | 176 ++ .../usr/share/htl-simuc/simavr/sim/avr_twi.c | 521 ++++++ .../usr/share/htl-simuc/simavr/sim/avr_twi.h | 116 ++ .../usr/share/htl-simuc/simavr/sim/avr_uart.c | 546 ++++++ .../usr/share/htl-simuc/simavr/sim/avr_uart.h | 229 +++ .../usr/share/htl-simuc/simavr/sim/avr_usb.c | 801 +++++++++ .../usr/share/htl-simuc/simavr/sim/avr_usb.h | 74 + .../share/htl-simuc/simavr/sim/avr_watchdog.c | 231 +++ .../share/htl-simuc/simavr/sim/avr_watchdog.h | 96 ++ .../share/htl-simuc/simavr/sim/fifo_declare.h | 189 +++ .../usr/share/htl-simuc/simavr/sim/run_avr.c | 287 ++++ .../usr/share/htl-simuc/simavr/sim/sim_avr.c | 453 +++++ .../usr/share/htl-simuc/simavr/sim/sim_avr.h | 517 ++++++ .../htl-simuc/simavr/sim/sim_avr_types.h | 57 + .../usr/share/htl-simuc/simavr/sim/sim_cmds.c | 193 +++ .../usr/share/htl-simuc/simavr/sim/sim_cmds.h | 82 + .../usr/share/htl-simuc/simavr/sim/sim_core.c | 1457 +++++++++++++++++ .../usr/share/htl-simuc/simavr/sim/sim_core.h | 142 ++ .../htl-simuc/simavr/sim/sim_cycle_timers.c | 249 +++ .../htl-simuc/simavr/sim/sim_cycle_timers.h | 121 ++ .../usr/share/htl-simuc/simavr/sim/sim_elf.c | 499 ++++++ .../usr/share/htl-simuc/simavr/sim/sim_elf.h | 103 ++ .../usr/share/htl-simuc/simavr/sim/sim_gdb.c | 1026 ++++++++++++ .../usr/share/htl-simuc/simavr/sim/sim_gdb.h | 55 + .../usr/share/htl-simuc/simavr/sim/sim_hex.c | 287 ++++ .../usr/share/htl-simuc/simavr/sim/sim_hex.h | 90 + .../htl-simuc/simavr/sim/sim_interrupts.c | 296 ++++ .../htl-simuc/simavr/sim/sim_interrupts.h | 134 ++ .../usr/share/htl-simuc/simavr/sim/sim_io.c | 298 ++++ .../usr/share/htl-simuc/simavr/sim/sim_io.h | 132 ++ .../usr/share/htl-simuc/simavr/sim/sim_irq.c | 294 ++++ .../usr/share/htl-simuc/simavr/sim/sim_irq.h | 150 ++ .../share/htl-simuc/simavr/sim/sim_network.h | 89 + .../share/htl-simuc/simavr/sim/sim_regbit.h | 199 +++ .../usr/share/htl-simuc/simavr/sim/sim_time.h | 64 + .../share/htl-simuc/simavr/sim/sim_utils.c | 68 + .../share/htl-simuc/simavr/sim/sim_utils.h | 51 + .../share/htl-simuc/simavr/sim/sim_vcd_file.c | 630 +++++++ .../share/htl-simuc/simavr/sim/sim_vcd_file.h | 131 ++ .../usr/share/htl-simuc/simuc/simuc | Bin 0 -> 1820968 bytes .../usr/share/htl-simuc/simuc/src/main.cpp | 190 +++ .../share/htl-simuc/simuc/src/sim/error.cpp | 18 + .../usr/share/htl-simuc/simuc/src/sim/error.h | 11 + .../usr/share/htl-simuc/simuc/src/sim/sim.cpp | 282 ++++ .../usr/share/htl-simuc/simuc/src/sim/sim.h | 43 + .../simuc/src/simavr/parts/fifo_declare.h | 189 +++ .../simuc/src/simavr/parts/uart_pty.c | 371 +++++ .../simuc/src/simavr/parts/uart_pty.h | 90 + .../htl-simuc/simuc/src/simavr/semaphore.h | 32 + .../htl-simuc/simuc/src/simavr/simavr.cpp | 749 +++++++++ .../share/htl-simuc/simuc/src/simavr/simavr.h | 132 ++ examples/simuc/sim/vcd/.gitkeep | 0 examples/simuc/src/main.cpp | 190 +++ examples/simuc/src/sim/error.cpp | 18 + examples/simuc/src/sim/error.h | 11 + examples/simuc/src/sim/sim.cpp | 282 ++++ examples/simuc/src/sim/sim.h | 43 + .../simuc/src/simavr/parts/fifo_declare.h | 189 +++ examples/simuc/src/simavr/parts/uart_pty.c | 371 +++++ examples/simuc/src/simavr/parts/uart_pty.h | 90 + examples/simuc/src/simavr/semaphore.h | 32 + examples/simuc/src/simavr/simavr.cpp | 749 +++++++++ examples/simuc/src/simavr/simavr.h | 132 ++ 96 files changed, 20127 insertions(+), 8 deletions(-) create mode 100644 examples/simuc/.gitignore create mode 100644 examples/simuc/.vscode/launch.json create mode 100644 examples/simuc/.vscode/settings.json create mode 100644 examples/simuc/.vscode/tasks.json create mode 100644 examples/simuc/Makefile create mode 100644 examples/simuc/README.md create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/DEBIAN/control create mode 120000 examples/simuc/dpkg/htl-simuc_version_arch/usr/bin/simuc create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/doc/htl-simuc/copyright create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/doc/htl-simuc/readme create mode 120000 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/readme create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr/avr_mcu_section.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_acomp.c create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_acomp.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_adc.c create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_adc.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_bitbang.c create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_bitbang.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_eeprom.c create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_eeprom.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_extint.c create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_extint.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_flash.c create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_flash.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_ioport.c create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_ioport.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_lin.c create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_lin.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_spi.c create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_spi.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_timer.c create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_timer.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_twi.c create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_twi.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_uart.c create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_uart.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_usb.c create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_usb.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_watchdog.c create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_watchdog.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/fifo_declare.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/run_avr.c create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_avr.c create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_avr.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_avr_types.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_cmds.c create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_cmds.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_core.c create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_core.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_cycle_timers.c create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_cycle_timers.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_elf.c create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_elf.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_gdb.c create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_gdb.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_hex.c create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_hex.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_interrupts.c create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_interrupts.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_io.c create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_io.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_irq.c create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_irq.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_network.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_regbit.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_time.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_utils.c create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_utils.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_vcd_file.c create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_vcd_file.h create mode 100755 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/simuc create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/main.cpp create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/sim/error.cpp create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/sim/error.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/sim/sim.cpp create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/sim/sim.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/simavr/parts/fifo_declare.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/simavr/parts/uart_pty.c create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/simavr/parts/uart_pty.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/simavr/semaphore.h create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/simavr/simavr.cpp create mode 100644 examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/simavr/simavr.h create mode 100644 examples/simuc/sim/vcd/.gitkeep create mode 100644 examples/simuc/src/main.cpp create mode 100644 examples/simuc/src/sim/error.cpp create mode 100644 examples/simuc/src/sim/error.h create mode 100644 examples/simuc/src/sim/sim.cpp create mode 100644 examples/simuc/src/sim/sim.h create mode 100644 examples/simuc/src/simavr/parts/fifo_declare.h create mode 100644 examples/simuc/src/simavr/parts/uart_pty.c create mode 100644 examples/simuc/src/simavr/parts/uart_pty.h create mode 100644 examples/simuc/src/simavr/semaphore.h create mode 100644 examples/simuc/src/simavr/simavr.cpp create mode 100644 examples/simuc/src/simavr/simavr.h diff --git a/README.md b/README.md index 606e9f9..450d4db 100644 --- a/README.md +++ b/README.md @@ -2,29 +2,46 @@ This repository is mirrored from [https://github.com/buserror/simavr.git](https://github.com/buserror/simavr.git), commit 7003af0 (Mon Jul 18 10:29:17 2022) -Original `README.md`: see [README-simavr.md](README-simavr.md) +* **simuc**: see [examples/](examples/simuc/README.md) +* Original `README.md`: see [README-simavr.md](README-simavr.md) -## build +------------------------------------------ + +## Build simavr library on Debian- or Ubuntu-systems ### Prepare system ```sh $ sudo apt install gcc make gcc-avr avr-libc $ sudo apt install libelf-dev $ sudo apt install freeglut3 freeglut3-dev +$ sudo apt install libncurses3 ``` -### make simavr libs +### Clone repository + +```sh +user@host:~ $ git clone https://git.htl-mechatronik.at/public/sx/simavr.git +user@host:~ $ cd simavr +user@host:~/simavr $ +``` -Make sure your shell working directory is simavr +### Make libaries and example executables ```sh -$ cd simavr -$ make +user@host:~/simavr $ make ``` Result is available in: -* static lib: `obj-x86_64-linux-gnu/libsimavr.a` -* shared lib: `obj-x86_64-linux-gnu/libsimavr.so` + +* static lib: `obj-.../libsimavr.a` +* shared lib: `obj-.../libsimavr.so` + +The ... is a placeholder for the *architecture*, which is the result of `gcc -dumpmachine` and depends on system architecture: +* i386: `obj-i686-linux-gnu` +* amd64: `obj-x86_64-linux-gnu` +* arm64: `obj-aarch64-linux-gnu` +* ... + Project examples available in folder `examples` diff --git a/examples/Makefile b/examples/Makefile index 65cc893..7fe92ee 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -9,9 +9,11 @@ endif all: for bi in ${boards}; do $(MAKE) -C $$bi; done + $(MAKE) -C simuc clean: for bi in ${boards}; do $(MAKE) -C $$bi clean; done + $(MAKE) -C simuc clean # # The USB example is not made by default, as it downloads stuff diff --git a/examples/simuc/.gitignore b/examples/simuc/.gitignore new file mode 100644 index 0000000..d1ad022 --- /dev/null +++ b/examples/simuc/.gitignore @@ -0,0 +1,4 @@ +dist/** +build/** +dpkg/**/*.deb +**/*.vcd diff --git a/examples/simuc/.vscode/launch.json b/examples/simuc/.vscode/launch.json new file mode 100644 index 0000000..64e527c --- /dev/null +++ b/examples/simuc/.vscode/launch.json @@ -0,0 +1,21 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Launch", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/dist/simuc", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "preLaunchTask": "build" + } + ] +} diff --git a/examples/simuc/.vscode/settings.json b/examples/simuc/.vscode/settings.json new file mode 100644 index 0000000..189a435 --- /dev/null +++ b/examples/simuc/.vscode/settings.json @@ -0,0 +1,87 @@ +{ + "files.associations": { + "cstdio": "cpp", + "array": "cpp", + "atomic": "cpp", + "bit": "cpp", + "*.tcc": "cpp", + "cctype": "cpp", + "chrono": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "compare": "cpp", + "concepts": "cpp", + "condition_variable": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdlib": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "list": "cpp", + "map": "cpp", + "string": "cpp", + "unordered_map": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "random": "cpp", + "ratio": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "future": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "mutex": "cpp", + "new": "cpp", + "numbers": "cpp", + "ostream": "cpp", + "semaphore": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "stop_token": "cpp", + "streambuf": "cpp", + "thread": "cpp", + "cinttypes": "cpp", + "typeinfo": "cpp", + "variant": "cpp" + }, + "cSpell.words": [ + "aref", + "atmega", + "avcc", + "avrsim", + "ddrb", + "eeprom", + "eesize", + "evws", + "ioend", + "lfcrlf", + "lockbits", + "megaavr", + "millis", + "mmcu", + "picocom", + "PORTB", + "ramend", + "simavr", + "simuc", + "slavename", + "SRAM", + "sreg" + ] +} \ No newline at end of file diff --git a/examples/simuc/.vscode/tasks.json b/examples/simuc/.vscode/tasks.json new file mode 100644 index 0000000..4e8bd30 --- /dev/null +++ b/examples/simuc/.vscode/tasks.json @@ -0,0 +1,26 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "type": "shell", + "command": "make", + "args": [], + "problemMatcher": [ "$gcc" ], + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "label": "clean", + "type": "shell", + "command": "make", + "args": [ + "clean" + ] + } + ] +} diff --git a/examples/simuc/Makefile b/examples/simuc/Makefile new file mode 100644 index 0000000..456d1d5 --- /dev/null +++ b/examples/simuc/Makefile @@ -0,0 +1,111 @@ +$(shell mkdir -p dist >/dev/null) +$(shell mkdir -p build >/dev/null) + +PRJ="simuc" +$(PRJ): dist/simuc + +start2: $(PRJ) + LD_LIBRARY_PATH=$(pwd);dist/simuc + +start: $(PRJ) + dist/simuc + +CFLAGS = -Os -Wall +#X_CFLAGS = -O0 -g -Wall +X_CFLAGS = -Os -g -Wall + + +dist/simuc: build/main.o build/sim.o build/simavr.o build/error.o build/uart_pty.o + #g++ -o $@ -g -Wall -gdwarf-2 $^ -Wl,-rpath,$(CURDIR) -L$(CURDIR) -lsimavr -lpthread -lutil + g++ -o $@ -g -Wall -gdwarf-2 $^ ../../simavr/obj-$(shell gcc -dumpmachine)/libsimavr.a -lelf -lpthread -lutil + + +#dist/libsim.so: build/sim.o build/simavr.o build/error.o build/uart_pty.o +# gcc -o $@ $(CFLAGS) -shared $^ + +build/sim.o: src/sim/sim.cpp src/sim/sim.h src/sim/error.h src/simavr/simavr.h + gcc -o $@ $(CFLAGS) -fPIC -c $< + +build/simavr.o: src/simavr/simavr.cpp src/simavr/simavr.h src/sim/error.h + gcc -o $@ $(CFLAGS) -fPIC -c $< + +build/error.o: src/sim/error.cpp src/sim/error.h + gcc -o $@ $(CFLAGS) -fPIC -c $< + +build/uart_pty.o: src/simavr/parts/uart_pty.c src/simavr/parts/uart_pty.h src/simavr/parts/fifo_declare.h + gcc -o $@ $(CFLAGS) -Wno-unused-result -fPIC -c $< + +build/main.o: src/main.cpp src/sim/sim.h src/simavr/simavr.h + g++ -o $@ $(X_CFLAGS) -c $< + + +# ############################################ +# Debian Packet for htl-simuc_version_arch.deb +# ############################################ + +ARCH := $(shell arch) +ifeq ($(ARCH), x86_64) + DEBARCH="amd64" + OBJARCH="" +endif +ifeq ($(ARCH), x86_32) + DEBARCH="i386" +endif +ifeq ($(ARCH), aarch64) + DEBARCH="arm64" +endif + +DEBVERSION := 0.0.1~1 +DEBNAME := dpkg/htl-simuc_version_arch +DEBSRC := dpkg/htl-simuc_version_arch + +DEB := $(DEBNAME:%version=%$(DEBVERSION),%arch=%$(DEBARCH).deb) + +deb: dpkg $(DEBSRC)/DEBIAN/control $(DEBSRC)/usr/share/doc/htl-simuc/readme + @dpkg-deb --root-owner-group --build $(DEBSRC) ${DEB} + +.PHONY: $(DEBSRC)/DEBIAN/control $(DEBSRC)/usr/share/doc/htl-simuc/readme + +$(DEBSRC)/DEBIAN/control: + echo "Package: htl-simuc" > $@ + echo "Version:" ${DEBVERSION} >> $@ + @echo "Section: devel" >> $@ + echo "Architecture:" $(DEBARCH) >> $@ + @echo "Depends: libelf1" >> $@ + @echo "Recommends: gcc-avr, avr-libc, gdb-avr, binutils-avr, avrdude" >> $@ + echo "Installed-Size:" $(shell du -s $(DEBSRC) | cut -f1) >> $@ + @echo "Priority: optional" >> $@ + @echo "Maintainer: Manfred Steiner " >> $@ + @echo "Description: megaavr microcontroller simulation" >> $@ + @chmod 644 $@ + +$(DEBSRC)/usr/share/doc/htl-simuc/readme: + @echo "created: $(shell date)" > $@ + @echo "https://git.htl-mechatronik.at/public/?p=sx/simavr.git;a=home" >> $@ + @echo >> $@ + @echo "$ git clone https://git.htl-mechatronik.at/public/sx/simavr.git" >> $@ + @echo "$ git checkout $(shell git rev-parse HEAD)" >> $@ + @chmod 644 $@ + +dpkg: $(PRJ) + @test -d $(DEBSRC)/usr/share/htl-simuc || mkdir -m 755 $(DEBSRC)/usr/share/htl-simuc + @test -d $(DEBSRC)/usr/share/htl-simuc/simuc || mkdir -m 755 $(DEBSRC)/usr/share/htl-simuc/simuc + rsync -a --delete dist/simuc $(DEBSRC)/usr/share/htl-simuc/simuc + @test -d $(DEBSRC)/usr/share/htl-simuc/simuc/src || mkdir -m 755 $(DEBSRC)/usr/share/htl-simuc/simuc/src + rsync -a --delete src/ $(DEBSRC)/usr/share/htl-simuc/simuc/src/ + @test -d $(DEBSRC)/usr/share/htl-simuc/simavr || mkdir -m 755 $(DEBSRC)/usr/share/htl-simuc/simavr + @test -d $(DEBSRC)/usr/share/htl-simuc/simavr/sim || mkdir -m 755 $(DEBSRC)/usr/share/htl-simuc/simavr/sim + rsync -a --delete ../../simavr/sim/ $(DEBSRC)/usr/share/htl-simuc/simavr/sim/ + @find $(DEBSRC) -type d -exec chmod 755 {} \; + @find $(DEBSRC)/usr/share/htl-simuc/ -type f -exec chmod 644 {} \; + @chmod 755 $(DEBSRC)/usr/share/htl-simuc/simuc/simuc + @touch $(DEBSRC) + +# ##################################################################### + +clean: + -@rm -r dist + -@rm -r build + -@find dpkg -name "*.deb" -delete + -@rm -rf $(DEBSRC)/usr/share/htl-simuc + -@rm -f $(DEBSRC)/DEBIAN/control diff --git a/examples/simuc/README.md b/examples/simuc/README.md new file mode 100644 index 0000000..5dee7f8 --- /dev/null +++ b/examples/simuc/README.md @@ -0,0 +1,64 @@ +# simuc + +**simuc** is used to simulate a megaAvr microcontroller. + +If the cpu is stopped by command or `avr-gdb`, some information is printed on standard output: +* Number of cycles and elapsed time +* Status Flags +* General Purpose registers r0..r31 +* address registers X, Y and Z +* Stack pointer SP and stack content + +Commands available via standard input (keyboard): +* *Enter* print current cycles and elapsed time +* `interrupt`: stop cpu +* `continue`: continue cpu run +* `stack`: print complete stack content on standard output + +Microcontrollers UART interface(s) is/are connected to local devices and can be used with terminal programs (like `picocom`). + +After start of `simuc` the program waits for an keyboard action to start simulation. So you are able to connect with avr-gdb before the simulation is executing some machine code. + +1) start `simuc` with proper options and arguments +2) start new shell and execute `avr-gdb` +3) inside (gdb) connect to simuc with the gdb shell command `target remote :1234` +4) load symbols with gdb command `file ...` +5) optionally set source directory with `directory ...` +6) press enter in the shell of simuc +7) now debug avr program step by step with gdb commands `stepi`, `step`, `nexti`, `next` or continue execution with `continue` + +------------------------------------------------------------- + +## Build simavr + +### Prepare system +```sh +$ sudo apt install gcc make gcc-avr avr-libc +$ sudo apt install libelf-dev +$ sudo apt install freeglut3 freeglut3-dev +$ sudo apt install libncurses3 +``` + +### Clone repository + +```sh +user@host:~ $ git clone https://git.htl-mechatronik.at/public/sx/simavr.git +user@host:~ $ cd simavr/examples/simuc +user@host:~/simavr/examples/simuc $ +``` + +### Make simuc executable + +```sh +user@host:~/simavr/examples/simuc $ make +``` + +Executable `simuc` available in folder `dist` + +### Make debian packet `htl-simuc` + +```sh +user@host:~/simavr/examples/simuc $ make deb +``` + +Debian packet available in folder `dpkg` diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/DEBIAN/control b/examples/simuc/dpkg/htl-simuc_version_arch/DEBIAN/control new file mode 100644 index 0000000..6b155e4 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/DEBIAN/control @@ -0,0 +1,10 @@ +Package: htl-simuc +Version: 0.0.1~1 +Section: devel +Architecture: amd64 +Depends: libelf1 +Recommends: gcc-avr, avr-libc, gdb-avr, binutils-avr, avrdude +Installed-Size: 4328 +Priority: optional +Maintainer: Manfred Steiner +Description: megaavr microcontroller simulation diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/bin/simuc b/examples/simuc/dpkg/htl-simuc_version_arch/usr/bin/simuc new file mode 120000 index 0000000..c184c52 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/bin/simuc @@ -0,0 +1 @@ +../share/htl-simuc/simuc/simuc \ No newline at end of file diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/doc/htl-simuc/copyright b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/doc/htl-simuc/copyright new file mode 100644 index 0000000..5cf1991 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/doc/htl-simuc/copyright @@ -0,0 +1,43 @@ +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: htl-simuc + +Files: * +Copyright: 2022 Manfred Steiner +License: GPL-3+ + +License: GPL-3+ + This program 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. + . + This program 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 this program. If not, see . + . + On Debian systems, the complete text of the GNU General Public + License version 3 can be found in "/usr/share/common-licenses/GPL-3". + +License: LGPL-3+ + This library is free software: you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + . + This library 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 + Lesser General Public License for more details. + . + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see + . + . + On Debian systems, the complete text of the GNU Lesser General + Public License version 3 can be found in + "/usr/share/common-licenses/LGPL-3". + diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/doc/htl-simuc/readme b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/doc/htl-simuc/readme new file mode 100644 index 0000000..06453d5 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/doc/htl-simuc/readme @@ -0,0 +1,5 @@ +created: So 27 Nov 2022 16:21:49 CET +https://git.htl-mechatronik.at/public/?p=sx/simavr.git;a=home + +git clone https://git.htl-mechatronik.at/public/sx/simavr.git +git checkout 0a12726a5335284495e557078a73381dc5fc8599 diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/readme b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/readme new file mode 120000 index 0000000..bf9863d --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/readme @@ -0,0 +1 @@ +../doc/htl-simuc/readme \ No newline at end of file diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr/avr_mcu_section.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr/avr_mcu_section.h new file mode 100644 index 0000000..3deae7b --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr/avr_mcu_section.h @@ -0,0 +1,332 @@ +/* + avr_mcu_section.h + + Copyright 2008-2013 Michel Pollet + + 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 . + */ + +#ifndef __AVR_MCU_SECTION_H__ +#define __AVR_MCU_SECTION_H__ + +/* + * This header is used to pass "parameters" to the programmer or the simulator, + * it tags the ELF file with a section that contains parameters about the physical + * AVR this was compiled for, including the speed, model, and signature bytes. + * + * A programmer software can read this and verify fuses values for example, and a + * simulator can instantiate the proper "model" of AVR, the speed and so on without + * command line parameters. + * + * Example of use: + * + * #include "avr_mcu_section.h" + * AVR_MCU(F_CPU, "atmega88"); + * + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + AVR_MMCU_TAG = 0, + AVR_MMCU_TAG_NAME, + AVR_MMCU_TAG_FREQUENCY, + AVR_MMCU_TAG_VCC, + AVR_MMCU_TAG_AVCC, + AVR_MMCU_TAG_AREF, + AVR_MMCU_TAG_LFUSE, + AVR_MMCU_TAG_HFUSE, + AVR_MMCU_TAG_EFUSE, + AVR_MMCU_TAG_SIGNATURE, + AVR_MMCU_TAG_SIMAVR_COMMAND, + AVR_MMCU_TAG_SIMAVR_CONSOLE, + AVR_MMCU_TAG_VCD_FILENAME, + AVR_MMCU_TAG_VCD_PERIOD, + AVR_MMCU_TAG_VCD_TRACE, + AVR_MMCU_TAG_VCD_PORTPIN, + AVR_MMCU_TAG_VCD_IRQ, + AVR_MMCU_TAG_PORT_EXTERNAL_PULL, +}; + +enum { + SIMAVR_CMD_NONE = 0, + SIMAVR_CMD_VCD_START_TRACE, + SIMAVR_CMD_VCD_STOP_TRACE, + SIMAVR_CMD_UART_LOOPBACK, +}; + +#if __AVR__ +/* + * WARNING. Due to newer GCC being stupid, they introduced a bug that + * prevents us introducing variable length strings in the declaration + * of structs. Worked for a million years, and no longer. + * So the new method declares the string as fixed size, and the parser + * is forced to skip the zeroes in padding. Dumbo. + */ +#define _MMCU_ __attribute__((section(".mmcu"))) __attribute__((used)) +struct avr_mmcu_long_t { + uint8_t tag; + uint8_t len; + uint32_t val; +} __attribute__((__packed__)); + +struct avr_mmcu_string_t { + uint8_t tag; + uint8_t len; + char string[64]; +} __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; + uint8_t mask; + void * what; + char name[32]; +} __attribute__((__packed__)); + +#define AVR_MCU_STRING(_tag, _str) \ + const struct avr_mmcu_string_t _##_tag _MMCU_ = {\ + .tag = _tag,\ + .len = sizeof(struct avr_mmcu_string_t) - 2,\ + .string = _str,\ + } +/* + * This trick allows concatenation of tokens. We need a macro redirection + * for it to work. + * The goal is to make unique variable names (they don't matter anyway) + */ +#define DO_CONCAT2(_a, _b) _a##_b +#define DO_CONCAT(_a, _b) DO_CONCAT2(_a,_b) + +#define AVR_MCU_LONG(_tag, _val) \ + const struct avr_mmcu_long_t DO_CONCAT(DO_CONCAT(_, _tag), __LINE__) _MMCU_ = {\ + .tag = _tag,\ + .len = sizeof(struct avr_mmcu_long_t) - 2,\ + .val = _val,\ + } + +#define AVR_MCU_BYTE(_tag, _val) \ + const uint8_t _##_tag _MMCU_ = { _tag, 1, _val } + +/*! + * This Macro allows you to specify traces for the VCD file output + * engine. This specifies a default header, and let you fill in the + * relevant bits. + * Example: + * const struct avr_mmcu_vcd_trace_t _mytrace[] _MMCU_ = { + * { AVR_MCU_VCD_SYMBOL("UDR0"), .what = (void*)&UDR0, }, + * { AVR_MCU_VCD_SYMBOL("UDRE0"), .mask = (1 << UDRE0), .what = (void*)&UCSR0A, }, + * }; + * This structure will automatically tell simavr to add a VCD trace + * for the UART register, and the UDRE0 bit, so you can trace exactly + * the timing of the changed using gtkwave. + */ +#define AVR_MCU_VCD_SYMBOL(_name) \ + .tag = AVR_MMCU_TAG_VCD_TRACE, \ + .len = sizeof(struct avr_mmcu_vcd_trace_t) - 2,\ + .name = _name + +/*! + * Specifies the name and wanted period (in usec) for a VCD file + * this is not mandatory for the VCD output to work, if this tag + * is not used, a VCD file will still be created with default values + */ +#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. + * See definition of SIMAVR_CMD_* to see what commands can + * be used from your firmware. + */ +#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, \ + } +/*! + * Similar to AVR_MCU_SIMAVR_COMMAND, The CONSOLE allows the AVR code + * to declare a register (typically a GPIO register, but any unused + * register can work...) that will allow printing on the host's console + * without using a UART to do debug. + */ +#define AVR_MCU_SIMAVR_CONSOLE(_register) \ + const struct avr_mmcu_addr_t _simavr_console_register _MMCU_ = {\ + .tag = AVR_MMCU_TAG_SIMAVR_CONSOLE,\ + .len = sizeof(void *),\ + .what = (void*)_register, \ + } +/*! + * Allows the firmware to hint simavr as to wether there are external + * pullups/down on PORT pins. It helps if the firmware uses "open drain" + * pins by toggling the DDR pins to switch between an output state and + * a "default" state. + * The value passed here will be output on the PORT IRQ when the DDR + * pin is set to input again + */ +#define AVR_MCU_EXTERNAL_PORT_PULL(_port, _mask, _val) \ + AVR_MCU_LONG(AVR_MMCU_TAG_PORT_EXTERNAL_PULL, \ + (((unsigned long)((_port)&0xff) << 16) | \ + ((unsigned long)((_mask)&0xff) << 8) | \ + ((_val)&0xff))); +/*! + * Add this port/pin to the VCD file. The syntax uses the name of the + * port as a character, and not a pointer to a register. + * AVR_MCU_VCD_PORT_PIN('B', 5); + */ +#define AVR_MCU_VCD_PORT_PIN(_port, _pin, _name) \ + const struct avr_mmcu_vcd_trace_t DO_CONCAT(DO_CONCAT(_, _tag), __LINE__) _MMCU_ = {\ + .tag = AVR_MMCU_TAG_VCD_PORTPIN, \ + .len = sizeof(struct avr_mmcu_vcd_trace_t) - 2,\ + .mask = _port, \ + .what = (void*)_pin, \ + .name = _name, \ + } + +/*! + * These allows you to add a trace showing how long an IRQ vector is pending, + * and also how long it is running. You can specify the IRQ as a vector name + * straight from the firmware file, and it will be named properly in the trace + */ + +#define AVR_MCU_VCD_IRQ_TRACE(_vect_number, __what, _trace_name) \ + const struct avr_mmcu_vcd_trace_t DO_CONCAT(DO_CONCAT(_, _tag), __LINE__) _MMCU_ = {\ + .tag = AVR_MMCU_TAG_VCD_IRQ, \ + .len = sizeof(struct avr_mmcu_vcd_trace_t) - 2,\ + .mask = _vect_number, \ + .what = (void*)__what, \ + .name = _trace_name, \ + }; +#define AVR_MCU_VCD_IRQ(_irq_name) \ + AVR_MCU_VCD_IRQ_TRACE(_irq_name##_vect_num, 1, #_irq_name) +#define AVR_MCU_VCD_IRQ_PENDING(_irq_name) \ + AVR_MCU_VCD_IRQ_TRACE(_irq_name##_vect_num, 0, #_irq_name "_pend") +#define AVR_MCU_VCD_ALL_IRQ() \ + AVR_MCU_VCD_IRQ_TRACE(0xff, 1, "IRQ") +#define AVR_MCU_VCD_ALL_IRQ_PENDING() \ + AVR_MCU_VCD_IRQ_TRACE(0xff, 0, "IRQ_PENDING") + +/*! + * This tag allows you to specify the voltages used by your board + * It is optional in most cases, but you will need it if you use + * ADC module's IRQs. Not specifying it in this case might lead + * to a divide-by-zero crash. + * The units are Volts*1000 (millivolts) + */ +#define AVR_MCU_VOLTAGES(_vcc, _avcc, _aref) \ + AVR_MCU_LONG(AVR_MMCU_TAG_VCC, (_vcc));\ + AVR_MCU_LONG(AVR_MMCU_TAG_AVCC, (_avcc));\ + AVR_MCU_LONG(AVR_MMCU_TAG_AREF, (_aref)); + +/*! + * 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. + */ +#define AVR_MCU(_speed, _name) \ + AVR_MCU_STRING(AVR_MMCU_TAG_NAME, _name);\ + AVR_MCU_LONG(AVR_MMCU_TAG_FREQUENCY, _speed);\ + const uint8_t _mmcu[2] _MMCU_ = { AVR_MMCU_TAG, 0 } + +/* + * The following MAP macros where copied from + * https://github.com/swansontec/map-macro/blob/master/map.h + * + * The license header for that file is reproduced below: + * + * Copyright (C) 2012 William Swanson + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the names of the authors or + * their institutions shall not be used in advertising or otherwise to + * promote the sale, use or other dealings in this Software without + * prior written authorization from the authors. + */ + +#define _EVAL0(...) __VA_ARGS__ +#define _EVAL1(...) _EVAL0 (_EVAL0 (_EVAL0 (__VA_ARGS__))) +#define _EVAL2(...) _EVAL1 (_EVAL1 (_EVAL1 (__VA_ARGS__))) +#define _EVAL3(...) _EVAL2 (_EVAL2 (_EVAL2 (__VA_ARGS__))) +#define _EVAL4(...) _EVAL3 (_EVAL3 (_EVAL3 (__VA_ARGS__))) +#define _EVAL(...) _EVAL4 (_EVAL4 (_EVAL4 (__VA_ARGS__))) + +#define _MAP_END(...) +#define _MAP_OUT + +#define _MAP_GET_END() 0, _MAP_END +#define _MAP_NEXT0(test, next, ...) next _MAP_OUT +#define _MAP_NEXT1(test, next) _MAP_NEXT0 (test, next, 0) +#define _MAP_NEXT(test, next) _MAP_NEXT1 (_MAP_GET_END test, next) + +#define _MAP0(f, x, peek, ...) f(x) _MAP_NEXT (peek, _MAP1) (f, peek, __VA_ARGS__) +#define _MAP1(f, x, peek, ...) f(x) _MAP_NEXT (peek, _MAP0) (f, peek, __VA_ARGS__) +#define _MAP(f, ...) _EVAL (-MAP1 (f, __VA_ARGS__, (), 0)) + +/* End of original MAP macros. */ + +// Define MAP macros with one additional argument +#define _MAP0_1(f, a, x, peek, ...) f(a, x) _MAP_NEXT (peek, _MAP1_1) (f, a, peek, __VA_ARGS__) +#define _MAP1_1(f, a, x, peek, ...) f(a, x) _MAP_NEXT (peek, _MAP0_1) (f, a, peek, __VA_ARGS__) +#define _MAP_1(f, a, ...) _EVAL (_MAP1_1 (f, a, __VA_ARGS__, (), 0)) + +#define _SEND_SIMAVR_CMD_BYTE(reg, b) reg = b; + +// A helper macro for sending multi-byte commands +#define SEND_SIMAVR_CMD(reg, ...) \ + do { \ + _MAP_1(_SEND_SIMAVR_CMD_BYTE, reg, __VA_ARGS__) \ + } while(0) + +#endif /* __AVR__ */ + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_acomp.c b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_acomp.c new file mode 100644 index 0000000..f3e14e1 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_acomp.c @@ -0,0 +1,241 @@ +/* + avr_acomp.c + + Copyright 2017 Konstantin Begun + + 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 "avr_acomp.h" +#include "avr_timer.h" + +static uint8_t +avr_acomp_get_state( + struct avr_t * avr, + avr_acomp_t *ac) +{ + if (avr_regbit_get(avr, ac->disabled)) + return 0; + + // get positive voltage + uint16_t positive_v; + + if (avr_regbit_get(avr, ac->acbg)) { // if bandgap + positive_v = ACOMP_BANDGAP; + } else { + positive_v = ac->ain_values[0]; // AIN0 + } + + // get negative voltage + uint16_t negative_v = 0; + + // multiplexer is enabled if acme is set and adc is off + if (avr_regbit_get(avr, ac->acme) && !avr_regbit_get(avr, ac->aden)) { + if (!avr_regbit_get(avr, ac->pradc)) { + uint8_t adc_i = avr_regbit_get_array(avr, ac->mux, ARRAY_SIZE(ac->mux)); + if (adc_i < ac->mux_inputs && adc_i < ARRAY_SIZE(ac->adc_values)) { + negative_v = ac->adc_values[adc_i]; + } + } + + } else { + negative_v = ac->ain_values[1]; // AIN1 + } + + return positive_v > negative_v; +} + +static avr_cycle_count_t +avr_acomp_sync_state( + struct avr_t * avr, + avr_cycle_count_t when, + void * param) +{ + avr_acomp_t * p = (avr_acomp_t *)param; + if (!avr_regbit_get(avr, p->disabled)) { + + uint8_t cur_state = avr_regbit_get(avr, p->aco); + uint8_t new_state = avr_acomp_get_state(avr, p); + + if (new_state != cur_state) { + avr_regbit_setto(avr, p->aco, new_state); // set ACO + + uint8_t acis0 = avr_regbit_get(avr, p->acis[0]); + uint8_t acis1 = avr_regbit_get(avr, p->acis[1]); + + if ((acis0 == 0 && acis1 == 0) || (acis1 == 1 && acis0 == new_state)) { + avr_raise_interrupt(avr, &p->ac); + } + + avr_raise_irq(p->io.irq + ACOMP_IRQ_OUT, new_state); + } + + } + + return 0; +} + +static inline void +avr_schedule_sync_state( + struct avr_t * avr, + void *param) +{ + avr_cycle_timer_register(avr, 1, avr_acomp_sync_state, param); +} + +static void +avr_acomp_write_acsr( + struct avr_t * avr, + avr_io_addr_t addr, + uint8_t v, + void * param) +{ + avr_acomp_t * p = (avr_acomp_t *)param; + + avr_core_watch_write(avr, addr, v); + + if (avr_regbit_get(avr, p->acic) != (p->timer_irq ? 1:0)) { + if (p->timer_irq) { + avr_unconnect_irq(p->io.irq + ACOMP_IRQ_OUT, p->timer_irq); + p->timer_irq = NULL; + } + else { + avr_irq_t *irq = avr_io_getirq(avr, AVR_IOCTL_TIMER_GETIRQ(p->timer_name), TIMER_IRQ_IN_ICP); + if (irq) { + avr_connect_irq(p->io.irq + ACOMP_IRQ_OUT, irq); + p->timer_irq = irq; + } + } + } + + avr_schedule_sync_state(avr, param); +} + +static void +avr_acomp_dependencies_changed( + struct avr_irq_t * irq, + uint32_t value, + void * param) +{ + avr_acomp_t * p = (avr_acomp_t *)param; + avr_schedule_sync_state(p->io.avr, param); +} + +static void +avr_acomp_irq_notify( + struct avr_irq_t * irq, + uint32_t value, + void * param) +{ + avr_acomp_t * p = (avr_acomp_t *)param; + + switch (irq->irq) { + case ACOMP_IRQ_AIN0 ... ACOMP_IRQ_AIN1: { + p->ain_values[irq->irq - ACOMP_IRQ_AIN0] = value; + avr_schedule_sync_state(p->io.avr, param); + } break; + case ACOMP_IRQ_ADC0 ... ACOMP_IRQ_ADC15: { + p->adc_values[irq->irq - ACOMP_IRQ_ADC0] = value; + avr_schedule_sync_state(p->io.avr, param); + } break; + } +} + +static void +avr_acomp_register_dependencies( + avr_acomp_t *p, + avr_regbit_t rb) +{ + if (rb.reg) { + avr_irq_register_notify( + avr_iomem_getirq(p->io.avr, rb.reg, NULL, rb.bit), + avr_acomp_dependencies_changed, + p); + } +} + +static void +avr_acomp_reset(avr_io_t * port) +{ + avr_acomp_t * p = (avr_acomp_t *)port; + + for (int i = 0; i < ACOMP_IRQ_COUNT; i++) + avr_irq_register_notify(p->io.irq + i, avr_acomp_irq_notify, p); + + // register notification for changes of registers comparator does not own + // avr_register_io_write is tempting instead, but it requires that the handler + // updates the actual memory too. Given this is for the registers this module + // does not own, it is tricky to know whether it should write to the actual memory. + // E.g., if there is already a native handler for it then it will do the writing + // (possibly even omitting some bits etc). IInterefering would probably be wrong. + // On the other hand if there isn't a handler already, then this hadnler would have to, + // as otherwise nobody will. + // This write notification mechanism should probably need reviewing and fixing + // For now using IRQ mechanism, as it is not intrusive + + avr_acomp_register_dependencies(p, p->pradc); + avr_acomp_register_dependencies(p, p->aden); + avr_acomp_register_dependencies(p, p->acme); + + // mux + for (int i = 0; i < ARRAY_SIZE(p->mux); ++i) { + avr_acomp_register_dependencies(p, p->mux[i]); + } +} + +static const char * irq_names[ACOMP_IRQ_COUNT] = { + [ACOMP_IRQ_AIN0] = "16io = _io; + + avr_register_io(avr, &p->io); + avr_register_vector(avr, &p->ac); + // allocate this module's IRQ + avr_io_setirqs(&p->io, AVR_IOCTL_ACOMP_GETIRQ, ACOMP_IRQ_COUNT, NULL); + + avr_register_io_write(avr, p->r_acsr, avr_acomp_write_acsr, p); +} diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_acomp.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_acomp.h new file mode 100644 index 0000000..caa3c4e --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_acomp.h @@ -0,0 +1,89 @@ +/* + avr_acomp.h + + Copyright 2017 Konstantin Begun + + 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 . + */ + +#ifndef __AVR_COMP_H___ +#define __AVR_COMP_H___ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "sim_avr.h" + +/* + * simavr Analog Comparator allows external code to feed real voltages to the + * simulator, and the simulator uses it's 'real' reference voltage + * to set comparator output accordingly and trigger in interrupt, if set up this way + * + */ + +enum { + // input IRQ values. Values are /always/ volts * 1000 (millivolts) + ACOMP_IRQ_AIN0 = 0, ACOMP_IRQ_AIN1, + ACOMP_IRQ_ADC0, ACOMP_IRQ_ADC1, ACOMP_IRQ_ADC2, ACOMP_IRQ_ADC3, + ACOMP_IRQ_ADC4, ACOMP_IRQ_ADC5, ACOMP_IRQ_ADC6, ACOMP_IRQ_ADC7, + ACOMP_IRQ_ADC8, ACOMP_IRQ_ADC9, ACOMP_IRQ_ADC10, ACOMP_IRQ_ADC11, + ACOMP_IRQ_ADC12, ACOMP_IRQ_ADC13, ACOMP_IRQ_ADC14, ACOMP_IRQ_ADC15, + ACOMP_IRQ_OUT, // output has changed + ACOMP_IRQ_COUNT +}; + +// Get the internal IRQ corresponding to the INT +#define AVR_IOCTL_ACOMP_GETIRQ AVR_IOCTL_DEF('a','c','m','p') + +enum { + ACOMP_BANDGAP = 1100 +}; + +typedef struct avr_acomp_t { + avr_io_t io; + + uint8_t mux_inputs; // number of inputs (not mux bits!) in multiplexer. Other bits in mux below would be expected to be zero + avr_regbit_t mux[4]; + avr_regbit_t pradc; // ADC power reduction, this impacts on ability to use adc multiplexer + avr_regbit_t aden; // ADC Enabled, this impacts on ability to use adc multiplexer + avr_regbit_t acme; // AC multiplexed input enabled + + avr_io_addr_t r_acsr; // control & status register + avr_regbit_t acis[2]; // + avr_regbit_t acic; // input capture enable + avr_regbit_t aco; // output + avr_regbit_t acbg; // bandgap select + avr_regbit_t disabled; + + char timer_name; // connected timer for incput capture triggering + + // use ACI and ACIE bits + avr_int_vector_t ac; + + // runtime data + uint16_t adc_values[16]; // current values on the ADCs inputs + uint16_t ain_values[2]; // current values on AIN inputs + avr_irq_t* timer_irq; +} avr_acomp_t; + +void avr_acomp_init(avr_t * avr, avr_acomp_t * port); + +#ifdef __cplusplus +}; +#endif + +#endif // __AVR_COMP_H___ diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_adc.c b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_adc.c new file mode 100644 index 0000000..6adf1f2 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_adc.c @@ -0,0 +1,427 @@ +/* + avr_adc.c + + Copyright 2008, 2010 Michel Pollet + + 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 +#include "sim_time.h" +#include "avr_adc.h" + +static avr_cycle_count_t +avr_adc_int_raise( + struct avr_t * avr, avr_cycle_count_t when, void * param) +{ + avr_adc_t * p = (avr_adc_t *)param; + if (avr_regbit_get(avr, p->aden)) { + // if the interrupts are not used, still raised the UDRE and TXC flag + avr_raise_interrupt(avr, &p->adc); + avr_regbit_clear(avr, p->adsc); + if( p->adts_mode == avr_adts_free_running ) + avr_raise_irq(p->io.irq + ADC_IRQ_IN_TRIGGER, 1); + if (!p->read_status) { + /* Update I/O registers. */ + + avr->data[p->r_adcl] = p->result & 0xff; + avr->data[p->r_adch] = p->result >> 8; + } + } + return 0; +} + +static avr_cycle_count_t +avr_adc_convert(struct avr_t * avr, avr_cycle_count_t when, void * param) +{ + avr_adc_t *p = (avr_adc_t *)param; + + p->first = 0; // Converter initialised + + /* Ask the calling program for inputs. */ + + avr_adc_mux_t mux = p->muxmode[p->current_muxi]; + union { + avr_adc_mux_t mux; + uint32_t v; + } e = { .mux = mux }; + avr_raise_irq(p->io.irq + ADC_IRQ_OUT_TRIGGER, e.v); + + // optional shift left/right + uint8_t shift = p->current_extras.adjust ? 6 : 0; // shift LEFT + + int32_t reg = 0, clipped = 0; + switch (mux.kind) { + case ADC_MUX_SINGLE: + reg = p->adc_values[mux.src]; + break; + case ADC_MUX_DIFF: + if (mux.gain == 0) + mux.gain = 1; + reg = ((uint32_t)p->adc_values[mux.src] * mux.gain) - + ((uint32_t)p->adc_values[mux.diff] * mux.gain); + break; + case ADC_MUX_TEMP: + reg = p->temp; // assumed to be already calibrated somehow + break; + case ADC_MUX_REF: + reg = mux.src; // reference voltage + break; + case ADC_MUX_VCC4: + if ( !avr->vcc) { + AVR_LOG(avr, LOG_WARNING, "ADC: missing VCC analog voltage\n"); + } else + reg = avr->vcc / 4; + break; + } + + int32_t vref = 3300; + uint16_t ref = p->ref_values[p->current_refi]; + + switch (ref) { + case ADC_VREF_VCC: + if (!avr->vcc) + AVR_LOG(avr, LOG_WARNING, "ADC: missing VCC analog voltage\n"); + else + vref = avr->vcc; + break; + case ADC_VREF_AREF: + if (!avr->aref) + AVR_LOG(avr, LOG_WARNING, "ADC: missing AREF analog voltage\n"); + else + vref = avr->aref; + break; + case ADC_VREF_AVCC: + if (!avr->avcc) + AVR_LOG(avr, LOG_WARNING, "ADC: missing AVCC analog voltage\n"); + else + vref = avr->avcc; + break; + default: + vref = ref; + } +// printf("ADCL %d:%3d:%3d read %4d vref %d:%d=%d\n", +// mux.kind, mux.diff, mux.src, +// reg, refi, ref, vref); + + if (mux.kind == ADC_MUX_DIFF) { + if (p->current_extras.negate) + reg = -reg; + if (p->current_extras.bipolar) { + reg = (reg * (int32_t)0x1ff) / vref; // scale to 9 bits + if (reg > (int32_t)0x1ff) { + clipped = 0x1ff; + } else if (reg < -(int32_t)0x1ff) { + clipped = 0x200; + } + } else { + reg = (reg * (int32_t)0x3ff) / vref; // scale to 10 bit + if (reg < 0 || reg > (int32_t)0x3ff) + clipped = 0x1ff; + } + } else { + reg = (reg * (int32_t)0x3ff) / vref; // scale to 10 bits + if (reg < 0 || reg > (int32_t)0x3ff) + clipped = 0x3ff; + } +// printf("ADC to 9/10 bits 0x%x %d\n", reg, reg); + if (clipped) { + AVR_LOG(avr, LOG_WARNING, + "ADC: channel %d clipped %u/%u VREF %d\n", + p->current_muxi, reg, clipped, vref); + reg = clipped; + } + reg &= 0x3ff; + reg <<= shift; +// printf("ADC to 9/10 bits %x shifted %d\n", reg, shift); + p->result = reg; + + /* Schedule the interrupt in 11 ADC cycles. */ + + avr_cycle_timer_register(avr, p->current_prescale * 11, + avr_adc_int_raise, p); + return 0; +} + +/* + * From Datasheet: + * "When ADCL is read, the ADC Data Register is not updated until ADCH is read. + * Consequently, if the result is left adjusted and no more than 8-bit + * precision is required, it is sufficient to read ADCH. + * Otherwise, ADCL must be read first, then ADCH." + */ + +static uint8_t +avr_adc_read_l( + struct avr_t * avr, avr_io_addr_t addr, void * param) +{ + avr_adc_t * p = (avr_adc_t *)param; + + p->read_status = 1; // Set the update interlock. + return avr_core_watch_read(avr, addr); +} + +static uint8_t +avr_adc_read_h( + struct avr_t * avr, avr_io_addr_t addr, void * param) +{ + avr_adc_t * p = (avr_adc_t *)param; + + p->read_status = 0; // Clear the update interlock. + return avr_core_watch_read(avr, addr); +} + +static void +avr_adc_configure_trigger( + struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) +{ + avr_adc_t * p = (avr_adc_t *)param; + + uint8_t adate = avr_regbit_get(avr, p->adate); + uint8_t old_adts = p->adts_mode; + + static char * auto_trigger_names[] = { + "none", + "free_running", + "analog_comparator_0", + "analog_comparator_1", + "analog_comparator_2", + "analog_comparator_3", + "external_interrupt_0", + "timer_0_compare_match_a", + "timer_0_compare_match_b", + "timer_0_overflow", + "timer_1_compare_match_b", + "timer_1_overflow", + "timer_1_capture_event", + "pin_change_interrupt", + "psc_module_0_sync_signal", + "psc_module_1_sync_signal", + "psc_module_2_sync_signal", + }; + + if( adate ) { + uint8_t adts = avr_regbit_get_array(avr, p->adts, ARRAY_SIZE(p->adts)); + p->adts_mode = p->adts_op[adts]; + + switch(p->adts_mode) { + case avr_adts_free_running: { + // do nothing at free running mode + } break; + // TODO: implement the other auto trigger modes + default: { + AVR_LOG(avr, LOG_WARNING, + "ADC: unimplemented auto trigger mode: %s\n", + auto_trigger_names[p->adts_mode]); + p->adts_mode = avr_adts_none; + } break; + } + } else { + // TODO: remove previously configured auto triggers + p->adts_mode = avr_adts_none; + } + + if( old_adts != p->adts_mode ) + AVR_LOG(avr, LOG_TRACE, "ADC: auto trigger configured: %s\n", + auto_trigger_names[p->adts_mode]); +} + +static void +avr_adc_write_adcsra( + struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) +{ + + avr_adc_t * p = (avr_adc_t *)param; + uint8_t adsc = avr_regbit_get(avr, p->adsc); + uint8_t aden = avr_regbit_get(avr, p->aden); + uint8_t new_aden; + + if (p->adc.raised.reg == addr) { + uint8_t mask; + + mask = 1 << p->adc.raised.bit; + if (mask & v) { + // Clear interrupt flag on bit set. + + avr_clear_interrupt(avr, &p->adc); + v &= ~mask; + } else { + v |= (mask & avr->data[p->adsc.reg]); + } + } + + avr->data[p->adsc.reg] = v; + new_aden = avr_regbit_get(avr, p->aden); + + // can't write zero to adsc + if (adsc && !avr_regbit_get(avr, p->adsc)) { + avr_regbit_set(avr, p->adsc); + v = avr->data[p->adsc.reg]; + } + if (!aden && new_aden) { + // first conversion + p->first = 1; + AVR_LOG(avr, LOG_TRACE, "ADC: Start AREF %d AVCC %d\n", avr->aref, avr->avcc); + } + if (aden && !avr_regbit_get(avr, p->aden)) { + // stop ADC + + avr_cycle_timer_cancel(avr, avr_adc_convert, p); + avr_cycle_timer_cancel(avr, avr_adc_int_raise, p); + avr_regbit_clear(avr, p->adsc); + v = avr->data[p->adsc.reg]; // Peter Ross pross@xvid.org + } + if (new_aden && !adsc && avr_regbit_get(avr, p->adsc)) { + // start one! + + /* Copy mux, prescaler and ADSRB settings, as they may change + * before conversion. + */ + + p->current_muxi = avr_regbit_get_array(avr, p->mux, + ARRAY_SIZE(p->mux)); + p->current_refi = avr_regbit_get_array(avr, p->ref, + ARRAY_SIZE(p->ref)); + + // clock prescaler are just a bit shift.. and 0 means 1 + + uint32_t div = avr_regbit_get_array(avr, p->adps, + ARRAY_SIZE(p->adps)); + if (!div) div++; + + if (p->first) + AVR_LOG(avr, LOG_TRACE, "ADC: starting at %uKHz\n", + (avr->frequency >> div) / 13 / 100); + div = (1 << div); + div *= (p->first ? 14 : 2); // first conversion is longer + p->current_prescale = div; + avr_cycle_timer_register(avr, div, avr_adc_convert, p); + p->current_extras.bipolar = + p->bin.reg && avr_regbit_get(avr, p->bin); + p->current_extras.negate = + p->ipr.reg && avr_regbit_get(avr, p->ipr); + p->current_extras.adjust = avr_regbit_get(avr, p->adlar); + } + avr_core_watch_write(avr, addr, v); + avr_adc_configure_trigger(avr, addr, v, param); +} + +static void +avr_adc_write_adcsrb( + struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) +{ + avr_core_watch_write(avr, addr, v); + avr_adc_configure_trigger(avr, addr, v, param); +} + +static void +avr_adc_irq_notify( + struct avr_irq_t * irq, uint32_t value, void * param) +{ + avr_adc_t * p = (avr_adc_t *)param; + avr_t * avr = p->io.avr; + + switch (irq->irq) { + case ADC_IRQ_ADC0 ... ADC_IRQ_ADC15: { + p->adc_values[irq->irq] = value; + } break; + case ADC_IRQ_TEMP: { + p->temp = value; + } break; + case ADC_IRQ_IN_TRIGGER: { + if (avr_regbit_get(avr, p->adate)) { + // start a conversion only if it's not running + // otherwise ignore the trigger + if(!avr_regbit_get(avr, p->adsc) ) { + uint8_t addr = p->adsc.reg; + if (addr) { + uint8_t val = avr->data[addr] | (1 << p->adsc.bit); + if (p->adc.raised.reg == addr) { + uint8_t mask; + + mask = 1 << p->adc.raised.bit; + val &= ~mask; + } + + // write ADSC to ADCSRA + + avr_adc_write_adcsra(avr, addr, val, param); + } + } + } + } + break; + } +} + +static void avr_adc_reset(avr_io_t * port) +{ + avr_adc_t * p = (avr_adc_t *)port; + + // stop ADC + avr_cycle_timer_cancel(p->io.avr, avr_adc_int_raise, p); + avr_regbit_clear(p->io.avr, p->adsc); + + for (int i = 0; i < ADC_IRQ_COUNT; i++) + avr_irq_register_notify(p->io.irq + i, avr_adc_irq_notify, p); +} + +static const char * irq_names[ADC_IRQ_COUNT] = { + [ADC_IRQ_ADC0] = "16io = _io; + + avr_register_io(avr, &p->io); + avr_register_vector(avr, &p->adc); + // allocate this module's IRQ + avr_io_setirqs(&p->io, AVR_IOCTL_ADC_GETIRQ, ADC_IRQ_COUNT, NULL); + + avr_register_io_write(avr, p->r_adcsra, avr_adc_write_adcsra, p); + // some ADCs don't have ADCSRB (atmega8/16/32) + if (p->r_adcsrb) + avr_register_io_write(avr, p->r_adcsrb, avr_adc_write_adcsrb, p); + avr_register_io_read(avr, p->r_adcl, avr_adc_read_l, p); + avr_register_io_read(avr, p->r_adch, avr_adc_read_h, p); +} diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_adc.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_adc.h new file mode 100644 index 0000000..c9dbfa0 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_adc.h @@ -0,0 +1,193 @@ +/* + avr_adc.h + + Copyright 2008, 2009 Michel Pollet + + 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 . + */ + +#ifndef __AVR_ADC_H___ +#define __AVR_ADC_H___ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "sim_avr.h" + +/* + * simavr ADC allows external code to feed real voltages to the + * simulator, and the simulator uses it's 'real' reference voltage + * to do the right thing and return the 'proper' 10 bits ADC value + * to the AVR firmware. + * + * To send values to the ADC, register your code to wait for the + * ADC_IRQ_OUT_TRIGGER irq, and at that point send any of the + * ADC_IRQ_ADC* with Millivolts as value. + * + * External trigger is not done yet. + */ + +enum { + // input IRQ values. Values are /always/ volts * 1000 (millivolts) + ADC_IRQ_ADC0 = 0, ADC_IRQ_ADC1, ADC_IRQ_ADC2, ADC_IRQ_ADC3, + ADC_IRQ_ADC4, ADC_IRQ_ADC5, ADC_IRQ_ADC6, ADC_IRQ_ADC7, + ADC_IRQ_ADC8, ADC_IRQ_ADC9, ADC_IRQ_ADC10, ADC_IRQ_ADC11, + ADC_IRQ_ADC12, ADC_IRQ_ADC13, ADC_IRQ_ADC14, ADC_IRQ_ADC15, + ADC_IRQ_TEMP, // see the datasheet + ADC_IRQ_IN_TRIGGER, + ADC_IRQ_OUT_TRIGGER, // sends a avr_adc_mux_t + ADC_IRQ_COUNT +}; + +// Get the internal IRQ corresponding to the INT +#define AVR_IOCTL_ADC_GETIRQ AVR_IOCTL_DEF('a','d','c','0') + +/* + * Definition of a ADC mux mode. + */ +enum { + ADC_MUX_NONE = 0, // Nothing. return 0 + ADC_MUX_NOISE, // Nothing. return something random + ADC_MUX_SINGLE, // Normal ADC pin reading + ADC_MUX_DIFF, // differential channels (src-diff) + ADC_MUX_TEMP, // internal temp sensor + ADC_MUX_REF, // reference voltage (in src * 100) + ADC_MUX_VCC4, // VCC/4 +}; +typedef struct avr_adc_mux_t { + unsigned long kind : 3, gain : 8, diff : 8, src : 13; +} avr_adc_mux_t; + +enum { + ADC_VREF_AREF = 0, // default mode + ADC_VREF_VCC, + ADC_VREF_AVCC, + ADC_VREF_V110 = 1100, + ADC_VREF_V256 = 2560, +}; + +// ADC trigger sources +typedef enum { + avr_adts_none = 0, + avr_adts_free_running, + avr_adts_analog_comparator_0, + avr_adts_analog_comparator_1, + avr_adts_analog_comparator_2, + avr_adts_analog_comparator_3, + avr_adts_external_interrupt_0, + avr_adts_timer_0_compare_match_a, + avr_adts_timer_0_compare_match_b, + avr_adts_timer_0_overflow, + avr_adts_timer_1_compare_match_b, + avr_adts_timer_1_overflow, + avr_adts_timer_1_capture_event, + avr_adts_pin_change_interrupt, + avr_adts_psc_module_0_sync_signal, + avr_adts_psc_module_1_sync_signal, + avr_adts_psc_module_2_sync_signal, +} avr_adts_type; + +typedef struct avr_adc_t { + avr_io_t io; + + uint8_t r_admux; + // if the last bit exists in the mux, we are an extended ADC + avr_regbit_t mux[6]; + avr_regbit_t ref[3]; // reference voltages bits + uint16_t ref_values[8]; // ADC_VREF_* + + avr_regbit_t adlar; // left/right adjustment bit + + uint8_t r_adcsra; // ADC Control and Status Register A + avr_regbit_t aden; // ADC Enabled + avr_regbit_t adsc; // ADC Start Conversion + avr_regbit_t adate; // ADC Auto Trigger Enable + + avr_regbit_t adps[3]; // Prescaler bits. Note that it's a frequency bit shift + + uint8_t r_adcl, r_adch; // Data Registers + + uint8_t r_adcsrb; // ADC Control and Status Register B + avr_regbit_t adts[4]; // Timing Source + avr_adts_type adts_op[16]; // ADTS type + uint8_t adts_mode; // the extracted ADTS mode + avr_regbit_t bin; // Bipolar Input Mode (tinyx5 have it) + avr_regbit_t ipr; // Input Polarity Reversal (tinyx5 have it) + + // use ADIF and ADIE bits + avr_int_vector_t adc; + + avr_adc_mux_t muxmode[64]; // maximum 6 bits of mux modes + + /* + * runtime bits + */ + + uint16_t adc_values[16]; // current values on the ADCs + uint16_t temp; // temp sensor reading + uint8_t first; + uint8_t read_status; // marked one when adcl is read + + /* Conversion parameters saved at start (ADSC is set). */ + + uint8_t current_muxi; + uint8_t current_refi; + uint8_t current_prescale; + struct { + unsigned int bipolar : 1; // BIN bit. + unsigned int negate : 1; // IPR bit. + unsigned int adjust : 1; // ADLAR bit. + } current_extras; + + /* Buffered conversion result. */ + + uint16_t result; +} avr_adc_t; + +void avr_adc_init(avr_t * avr, avr_adc_t * port); + + +/* + * Helper macros for the Cores definition of muxes + */ +#define AVR_ADC_SINGLE(_chan) { \ + .kind = ADC_MUX_SINGLE, \ + .src = (_chan), \ + } +#define AVR_ADC_DIFF(_a,_b,_g) { \ + .kind = ADC_MUX_DIFF, \ + .src = (_a), \ + .diff = (_b), \ + .gain = (_g), \ + } +#define AVR_ADC_REF(_t) { \ + .kind = ADC_MUX_REF, \ + .src = (_t), \ + } +#define AVR_ADC_TEMP() { \ + .kind = ADC_MUX_TEMP, \ + } + +#define AVR_ADC_VCC4() { \ + .kind = ADC_MUX_VCC4, \ + } + +#ifdef __cplusplus +}; +#endif + +#endif /* __AVR_ADC_H___ */ diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_bitbang.c b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_bitbang.c new file mode 100644 index 0000000..e34aab2 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_bitbang.c @@ -0,0 +1,248 @@ +/* + avr_bitbang.c + + Copyright 2008, 2009 Michel Pollet + 2011 Stephan Veigl + + 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 . + */ + +#ifndef __AVR_BITBANG_H__ +#define __AVR_BITBANG_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include "avr_bitbang.h" + +#include "sim_regbit.h" +#include "sim_core.h" +#include "avr_ioport.h" + +///@todo refactor SPI to bitbang + +#define BITBANG_MASK 0xFFFFFFFFUL + +/** + * read (sample) data from input pin + * + * @param p internal bitbang structure + */ +static void avr_bitbang_read_bit(avr_bitbang_t *p) +{ + avr_ioport_state_t iostate; + uint8_t bit = 0; + + if ( !p->enabled ) + return; + + // read from HW pin + if ( p->p_in.port ) { + avr_ioctl(p->avr, AVR_IOCTL_IOPORT_GETSTATE( p->p_in.port ), &iostate); + bit = ( iostate.pin >> p->p_in.pin ) & 1; + + if ( p->data_order ) { + // data order: shift right + p->data = (p->data >> 1) | ( bit << (p->buffer_size-1)); + } else { + // data order: shift left + p->data = (p->data << 1) | bit; + } + + } + + // module callback + if ( p->callback_bit_read ) { + p->callback_bit_read(bit, p->callback_param); + } + + // data sanitary + p->data = p->data & ~(BITBANG_MASK << p->buffer_size); +} + +/** + * write data to output pin + * + * @param p bitbang structure + */ +static void avr_bitbang_write_bit(avr_bitbang_t *p) +{ + uint8_t bit = 0; + + if ( !p->enabled ) + return; + + if ( p->data_order ) { + // data order: shift right + bit = p->data & 1; + } else { + // data order: shift left + bit = (p->data >> (p->buffer_size-1)) & 1; + } + + // output to HW pin + if ( p->p_out.port ) { + avr_raise_irq(avr_io_getirq(p->avr, AVR_IOCTL_IOPORT_GETIRQ( p->p_out.port ), p->p_out.pin), bit); + } + + // module callback + if ( p->callback_bit_write ) { + p->callback_bit_write(bit, p->callback_param); + } +} + + +/** + * process clock edges (both: positive and negative edges) + * + * @param p bitbang structure + * + */ +static void avr_bitbang_clk_edge(avr_bitbang_t *p) +{ + uint8_t phase = (p->clk_count & 1) ^ p->clk_phase; + uint8_t clk = (p->clk_count & 1) ^ p->clk_pol; + + if ( !p->enabled ) + return; + + // increase clock + p->clk_count++; + clk ^= 1; + phase ^= 1; + + // generate clock output on HW pin + if ( p->clk_generate && p->p_clk.port ) { + avr_raise_irq(avr_io_getirq(p->avr, AVR_IOCTL_IOPORT_GETIRQ( p->p_clk.port ), p->p_clk.pin), clk); + } + + if ( phase ) { + // read data in + avr_bitbang_read_bit(p); + + } else { + // write data out + avr_bitbang_write_bit(p); + } + + if ( p->clk_count >= (p->buffer_size*2) ) { + // transfer finished + if ( p->callback_transfer_finished ) { + p->data = p->callback_transfer_finished(p->data, p->callback_param); + } + p->clk_count = 0; + } +} + +static avr_cycle_count_t avr_bitbang_clk_timer(struct avr_t * avr, avr_cycle_count_t when, void * param) +{ + avr_bitbang_t * p = (avr_bitbang_t *)param; + + avr_bitbang_clk_edge(p); + + if ( p->enabled ) + return when + p->clk_cycles/2; + else + return 0; +} + +static void avr_bitbang_clk_hook(struct avr_irq_t * irq, uint32_t value, void * param) +{ + avr_bitbang_t * p = (avr_bitbang_t *)param; + uint8_t clk = (p->clk_count & 1) ^ p->clk_pol; + + // no clock change + if ( clk == value ) + return; + + avr_bitbang_clk_edge(p); +} + +/** + * reset bitbang sub-module + * + * @param avr avr attached to + * @param p bitbang structure + */ +void avr_bitbang_reset(avr_t *avr, avr_bitbang_t * p) +{ + p->avr = avr; + p->enabled = 0; + p->clk_count = 0; + p->data = 0; + + if ( p->buffer_size < 1 || p->buffer_size > 32 ) { + AVR_LOG(avr, LOG_ERROR, + "Error: bitbang buffer size should be between 1 and 32. set value: %d\n", p->buffer_size); + abort(); + } + +} + +/** + * start bitbang transfer + * + * buffers should be written / cleared in advanced + * timers and interrupts are connected + * + * @param p bitbang structure + */ +void avr_bitbang_start(avr_bitbang_t * p) +{ + p->enabled = 1; + p->clk_count = 0; + + if ( p->clk_phase == 0 ) { + // write first bit + avr_bitbang_write_bit(p); + } + + if ( p->clk_generate ) { + // master mode, generate clock -> set timer + avr_cycle_timer_register(p->avr, (p->clk_cycles/2), avr_bitbang_clk_timer, p); + } else { + // slave mode -> attach clock function to clock pin + ///@todo test + avr_irq_register_notify( avr_io_getirq(p->avr, AVR_IOCTL_IOPORT_GETIRQ( p->p_clk.port ), p->p_clk.pin), avr_bitbang_clk_hook, p); + } + +} + + +/** + * stop bitbang transfer + * + * timers and interrupts are disabled + * + * @param p bitbang structure + */ +void avr_bitbang_stop(avr_bitbang_t * p) +{ + + p->enabled = 0; + avr_cycle_timer_cancel(p->avr, avr_bitbang_clk_timer, p); + avr_irq_unregister_notify( avr_io_getirq(p->avr, AVR_IOCTL_IOPORT_GETIRQ( p->p_clk.port ), p->p_clk.pin), avr_bitbang_clk_hook, p); +} + +#ifdef __cplusplus +}; +#endif + +#endif /*__AVR_BITBANG_H__*/ diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_bitbang.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_bitbang.h new file mode 100644 index 0000000..3d8832f --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_bitbang.h @@ -0,0 +1,117 @@ +/* + avr_bitbang.h + + Copyright 2008, 2009 Michel Pollet + 2011 Stephan Veigl + + 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 . + */ + +/** + @defgroup avr_bitbang Generic BitBang Module + @{ + + Generic BitBang Module of simavr AVR simulator. + + @par Features / Implementation Status + - easy buffer access with push() / pop() functions + - one input and one output pin (can be the same HW pin for I2C) + + @todo + - one input and one output pin (can be the same HW pin for I2C) + - one clock pin which can be configured as input or output + when the clock is output, the clock signal is generated with a + configured frequency (master / slave mode) + - 2x 32-bit buffers (input / output) (allows start, stop bits for UART, etc.) + - on each read / write a callback is executed to notify the master module + +*/ + + +#ifndef AVR_BITBANG_H_ +#define AVR_BITBANG_H_ + +#include "sim_avr.h" +#include "avr_ioport.h" + + + + +/// SPI Module initialization and state structure +typedef struct avr_bitbang_t { + avr_t * avr; ///< avr we are attached to + + uint8_t enabled; ///< bit-bang enabled flag + uint8_t clk_generate; ///< generate clock and write to clock pin (if available) -> master / slave mode + uint8_t clk_pol; ///< clock polarity, base (inactive) value of clock + uint8_t clk_phase; ///< clock phase / data sampling edge + /// - 0: data are sampled at first clock edge + /// - 1: data are sampled at second clock edge + uint32_t clk_cycles; ///< cycles per clock period - must be multiple of 2! (used if clk_generate is enabled) + uint8_t data_order; ///< data order / shift + /// - 0: shift left + /// - 1: shift right + + uint8_t buffer_size; ///< size of buffer in bits (1...32) + + void *callback_param; /// anonymous parameter for callback functions + void (*callback_bit_read)(uint8_t bit, void *param); ///< callback function to notify about bit read + void (*callback_bit_write)(uint8_t bit, void *param); ///< callback function to notify about bit write + uint32_t (*callback_transfer_finished)(uint32_t data, void *param); ///< callback function to notify about a complete transfer + /// (read received data and write new output data) + + avr_iopin_t p_clk; ///< clock pin (optional) + avr_iopin_t p_in; ///< data in pin + avr_iopin_t p_out; ///< data out pin + +// private data + uint32_t data; ///< data buffer + /// - latest received bit the is lowest / most right one, bit number: 0 + /// - next bit to be written is the highest one, bit number: (buffer_size-1) + int8_t clk_count; ///< internal clock edge count +} avr_bitbang_t; + +/** + * reset bitbang sub-module + * + * @param avr avr attached to + * @param p bitbang structure + */ +void avr_bitbang_reset(avr_t *avr, avr_bitbang_t * p); + +/** + * start bitbang transfer + * + * buffers should be written / cleared in advanced + * timers and interrupts are connected + * + * @param p bitbang structure + */ +void avr_bitbang_start(avr_bitbang_t * p); + + +/** + * stop bitbang transfer + * + * timers and interrupts are disabled + * + * @param p bitbang structure + */ +void avr_bitbang_stop(avr_bitbang_t * p); + + +#endif /* AVR_BITBANG_H_ */ +/// @} end of avr_bitbang group diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_eeprom.c b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_eeprom.c new file mode 100644 index 0000000..c348f3f --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_eeprom.c @@ -0,0 +1,148 @@ +/* + avr_eeprom.c + + IO module that simulates the AVR EEProm + + Copyright 2008, 2009 Michel Pollet + + 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 +#include "avr_eeprom.h" + +static avr_cycle_count_t avr_eempe_clear(struct avr_t * avr, avr_cycle_count_t when, void * param) +{ + avr_eeprom_t * p = (avr_eeprom_t *)param; + avr_regbit_clear(p->io.avr, p->eempe); + return 0; +} + +static avr_cycle_count_t avr_eei_raise(struct avr_t * avr, avr_cycle_count_t when, void * param) +{ + avr_eeprom_t * p = (avr_eeprom_t *)param; + avr_raise_interrupt(p->io.avr, &p->ready); + return 0; +} + +static void avr_eeprom_write(avr_t * avr, avr_io_addr_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_core_watch_write(avr, addr, v); + + if (!eempe && avr_regbit_get(avr, p->eempe)) { + avr_cycle_timer_register(avr, 4, avr_eempe_clear, p); + } + + uint16_t ee_addr; + if (p->r_eearh) + ee_addr = avr->data[p->r_eearl] | (avr->data[p->r_eearh] << 8); + else + ee_addr = avr->data[p->r_eearl]; + if (((eempe && avr_regbit_get(avr, p->eepe)) || avr_regbit_get(avr, p->eere)) && + ee_addr >= p->size) { + AVR_LOG(avr, LOG_ERROR, "EEPROM: *** %s address out of bounds: %04x > %04x," + " wrapping to %04x (PC=%04x)\n", + eempe ? "Write" : "Read", + ee_addr, p->size-1, ee_addr & (p->size-1), + avr->pc); + ee_addr = ee_addr & (p->size-1); + } + if (eempe && avr_regbit_get(avr, p->eepe)) { // write operation + // printf("eeprom write %04x <- %02x\n", addr, avr->data[p->r_eedr]); + p->eeprom[ee_addr] = avr->data[p->r_eedr]; + // Automatically clears that bit (?) + avr_regbit_clear(avr, p->eempe); + + avr_cycle_timer_register_usec(avr, 3400, avr_eei_raise, p); // 3.4ms here + } + if (avr_regbit_get(avr, p->eere)) { // read operation + avr->data[p->r_eedr] = p->eeprom[ee_addr]; + // printf("eeprom read %04x : %02x\n", addr, p->eeprom[addr]); + } + + // autocleared + avr_regbit_clear(avr, p->eepe); + avr_regbit_clear(avr, p->eere); +} + +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; + + switch(ctl) { + case AVR_IOCTL_EEPROM_SET: { + avr_eeprom_desc_t * desc = (avr_eeprom_desc_t*)io_param; + if (!desc || !desc->size || !desc->ee || (desc->offset + desc->size) > p->size) { + AVR_LOG(port->avr, LOG_WARNING, "EEPROM: %s: AVR_IOCTL_EEPROM_SET Invalid argument\n", + __FUNCTION__); + return -2; + } + memcpy(p->eeprom + desc->offset, desc->ee, desc->size); + AVR_LOG(port->avr, LOG_TRACE, "EEPROM: %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) { + AVR_LOG(port->avr, LOG_WARNING, "EEPROM: %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; +} + +static void avr_eeprom_dealloc(struct avr_io_t * port) +{ + avr_eeprom_t * p = (avr_eeprom_t *)port; + if (p->eeprom) + free(p->eeprom); + p->eeprom = NULL; +} + +static avr_io_t _io = { + .kind = "eeprom", + .ioctl = avr_eeprom_ioctl, + .dealloc = avr_eeprom_dealloc, +}; + +void avr_eeprom_init(avr_t * avr, avr_eeprom_t * p) +{ + p->io = _io; +// printf("%s init (%d bytes) EEL/H:%02x/%02x EED=%02x EEC=%02x\n", +// __FUNCTION__, p->size, p->r_eearl, p->r_eearh, p->r_eedr, p->r_eecr); + + p->eeprom = malloc(p->size); + memset(p->eeprom, 0xff, p->size); + + avr_register_io(avr, &p->io); + avr_register_vector(avr, &p->ready); + + avr_register_io_write(avr, p->r_eecr, avr_eeprom_write, p); +} + diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_eeprom.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_eeprom.h new file mode 100644 index 0000000..9ad1c5a --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_eeprom.h @@ -0,0 +1,131 @@ +/* + avr_eeprom.h + + Copyright 2008, 2009 Michel Pollet + + 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 . + */ + +#ifndef __AVR_EEPROM_H__ +#define __AVR_EEPROM_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "sim_avr.h" + +typedef struct avr_eeprom_t { + avr_io_t io; + + uint8_t * eeprom; // actual bytes + uint16_t size; // size for this MCU + + uint8_t r_eearh; + uint8_t r_eearl; + uint8_t r_eedr; + + // eepm -- eeprom write mode + uint8_t r_eecr; // shortcut, assumes these bits fit in that register + avr_regbit_t eepm[4]; + avr_regbit_t eempe; // eeprom master program enable + avr_regbit_t eepe; // eeprom program enable + avr_regbit_t eere; // eeprom read enable + + avr_int_vector_t ready; // EERIE vector +} avr_eeprom_t; + +void avr_eeprom_init(avr_t * avr, avr_eeprom_t * port); + +typedef struct avr_eeprom_desc_t { + uint8_t * ee; + uint16_t offset; + uint32_t size; +} avr_eeprom_desc_t; + +#define AVR_IOCTL_EEPROM_GET AVR_IOCTL_DEF('e','e','g','p') +#define AVR_IOCTL_EEPROM_SET AVR_IOCTL_DEF('e','e','s','p') + + +/* + * the eeprom block seems to be very similar across AVRs, + * so here is a macro to declare a "typical" one in a core. + */ + +#define AVR_EEPROM_DECLARE(_vector) \ + .eeprom = {\ + .size = E2END+1,\ + .r_eearh = EEARH,\ + .r_eearl = EEARL,\ + .r_eedr = EEDR,\ + .r_eecr = EECR,\ + .eepm = { AVR_IO_REGBIT(EECR, EEPM0), AVR_IO_REGBIT(EECR, EEPM1) },\ + .eempe = AVR_IO_REGBIT(EECR, EEMPE),\ + .eepe = AVR_IO_REGBIT(EECR, EEPE),\ + .eere = AVR_IO_REGBIT(EECR, EERE),\ + .ready = {\ + .enable = AVR_IO_REGBIT(EECR, EERIE),\ + .vector = _vector,\ + },\ + } + +/* + * no EEPM registers in atmega128 + */ +#define AVR_EEPROM_DECLARE_NOEEPM(_vector) \ + .eeprom = {\ + .size = E2END+1,\ + .r_eearh = EEARH,\ + .r_eearl = EEARL,\ + .r_eedr = EEDR,\ + .r_eecr = EECR,\ + .eepm = { }, \ + .eempe = AVR_IO_REGBIT(EECR, EEMWE),\ + .eepe = AVR_IO_REGBIT(EECR, EEWE),\ + .eere = AVR_IO_REGBIT(EECR, EERE),\ + .ready = {\ + .enable = AVR_IO_REGBIT(EECR, EERIE),\ + .vector = _vector,\ + },\ + } + + +/* + * macro definition without a high address bit register, + * which is not implemented in some tiny AVRs. + */ + +#define AVR_EEPROM_DECLARE_8BIT(_vector) \ + .eeprom = {\ + .size = E2END+1,\ + .r_eearl = EEAR,\ + .r_eedr = EEDR,\ + .r_eecr = EECR,\ + .eepm = { AVR_IO_REGBIT(EECR, EEPM0), AVR_IO_REGBIT(EECR, EEPM1) },\ + .eempe = AVR_IO_REGBIT(EECR, EEMPE),\ + .eepe = AVR_IO_REGBIT(EECR, EEPE),\ + .eere = AVR_IO_REGBIT(EECR, EERE),\ + .ready = {\ + .enable = AVR_IO_REGBIT(EECR, EERIE),\ + .vector = _vector,\ + },\ + } + +#ifdef __cplusplus +}; +#endif + +#endif /* __AVR_EEPROM_H__ */ diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_extint.c b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_extint.c new file mode 100644 index 0000000..6f85660 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_extint.c @@ -0,0 +1,228 @@ +/* + avr_extint.c + + Copyright 2008, 2009 Michel Pollet + + 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 +#include "avr_extint.h" +#include "avr_ioport.h" + +typedef struct avr_extint_poll_context_t { + uint32_t eint_no; // index of particular interrupt source we are monitoring + avr_extint_t *extint; +} avr_extint_poll_context_t; + +static avr_cycle_count_t avr_extint_poll_level_trig( + struct avr_t * avr, + avr_cycle_count_t when, + void * param) +{ + avr_extint_poll_context_t *poll = (avr_extint_poll_context_t *)param; + avr_extint_t * p = poll->extint; + + /* Check for change of interrupt mode. */ + + if (avr_regbit_get_array(avr, p->eint[poll->eint_no].isc, 2)) + goto terminate_poll; + + uint8_t port = p->eint[poll->eint_no].port_ioctl & 0xFF; + avr_ioport_state_t iostate; + if (avr_ioctl(avr, AVR_IOCTL_IOPORT_GETSTATE( port ), &iostate) < 0) + goto terminate_poll; + uint8_t bit = ( iostate.pin >> p->eint[poll->eint_no].port_pin ) & 1; + if (bit) + goto terminate_poll; // Only poll while pin level remains low + + if (avr->sreg[S_I]) { + uint8_t raised = avr_regbit_get(avr, p->eint[poll->eint_no].vector.raised) || p->eint[poll->eint_no].vector.pending; + if (!raised) + avr_raise_interrupt(avr, &p->eint[poll->eint_no].vector); + } + + return when+1; + +terminate_poll: + free(poll); + return 0; +} + +static avr_extint_t * avr_extint_get(avr_t * avr) +{ + if (!avr) + return NULL; + avr_io_t * periferal = avr->io_port; + while (periferal) { + if (!strcmp(periferal->kind, "extint")) { + return (avr_extint_t *)periferal; + } + periferal = periferal->next; + } + return NULL; +} + +static inline uint8_t avr_extint_exists(avr_extint_t *extint, int8_t extint_no) +{ + return (extint_no < EXTINT_COUNT) && (extint->eint[extint_no].port_ioctl); +} + +/** + * @brief avr_extint_is_strict_lvl_trig + * @param avr + * @param extint_no: an ext interrupt number, e.g. 0 or 1 (corresponds to INT0 or INT1) + * @return -1 if irrelevant extint_no given, strict + * level triggering flag otherwise. + */ +int avr_extint_is_strict_lvl_trig(avr_t * avr, uint8_t extint_no) +{ + avr_extint_t *p = avr_extint_get(avr); + if (!p || !avr_extint_exists(p, extint_no)) + return -1; + if (!p->eint[extint_no].isc[1].reg) + return -1; // this is edge-only triggered interrupt + return p->eint[extint_no].strict_lvl_trig; +} + +/** + * @brief avr_extint_set_strict_lvl_trig + * @param avr + * @param extint_no: an ext interrupt number, e.g. 0 or 1 (corresponds to INT0 or INT1) + * @param strict: new value for level triggering flag + */ +void avr_extint_set_strict_lvl_trig(avr_t * avr, uint8_t extint_no, uint8_t strict) +{ + avr_extint_t *p = avr_extint_get(avr); + if (!p || !avr_extint_exists(p, extint_no)) + return; + if (!p->eint[extint_no].isc[1].reg) + return; // this is edge-only triggered interrupt + p->eint[extint_no].strict_lvl_trig = strict; +} + +static void avr_extint_irq_notify(struct avr_irq_t * irq, uint32_t value, void * param) +{ + avr_extint_t * p = (avr_extint_t *)param; + avr_t * avr = p->io.avr; + + int up = !irq->value && value; + int down = irq->value && !value; + + // ?? uint8_t isc_bits = p->eint[irq->irq + 1].isc->reg ? 2 : 1; + uint8_t isc_bits = p->eint[irq->irq].isc[1].reg ? 2 : 1; + uint8_t mode = avr_regbit_get_array(avr, p->eint[irq->irq].isc, isc_bits); + + // Asynchronous interrupts, eg int2 in m16, m32 etc. support only down/up + if (isc_bits == 1) + mode +=2; + + switch (mode) { + case 0: // Level triggered (low level) interrupt + { + /** + Datasheet excerpt: + >When the external interrupt is enabled and is configured as level triggered (only INT0/INT1), + >the interrupt will trigger as long as the pin is held low. + Thus we have to query the pin value continiously while it's held low and try to trigger the interrupt. + This can be expensive, so avr_extint_set_strict_lvl_trig function provisioned to allow the user + to turn this feature off. In this case bahaviour will be similar to the falling edge interrupt. + */ + if (!value) { + if (avr->sreg[S_I]) { + uint8_t raised = avr_regbit_get(avr, p->eint[irq->irq].vector.raised) || p->eint[irq->irq].vector.pending; + if (!raised) + avr_raise_interrupt(avr, &p->eint[irq->irq].vector); + } + if (p->eint[irq->irq].strict_lvl_trig) { + avr_extint_poll_context_t *poll = malloc(sizeof(avr_extint_poll_context_t)); + if (poll) { + poll->eint_no = irq->irq; + poll->extint = p; + avr_cycle_timer_register(avr, 1, avr_extint_poll_level_trig, poll); + } + } + } + } + break; + case 1: // Toggle-triggered interrupt + if (up || down) + avr_raise_interrupt(avr, &p->eint[irq->irq].vector); + break; + case 2: // Falling edge triggered + if (down) + avr_raise_interrupt(avr, &p->eint[irq->irq].vector); + break; + case 3: // Rising edge trigggerd + if (up) + avr_raise_interrupt(avr, &p->eint[irq->irq].vector); + break; + } +} + +static void avr_extint_reset(avr_io_t * port) +{ + avr_extint_t * p = (avr_extint_t *)port; + + for (int i = 0; i < EXTINT_COUNT; i++) { + if (p->eint[i].port_ioctl) { + avr_irq_register_notify(p->io.irq + i, avr_extint_irq_notify, p); + + if (p->eint[i].isc[1].reg) // level triggering available + p->eint[i].strict_lvl_trig = 1; // turn on repetitive level triggering by default + avr_irq_t * irq = avr_io_getirq(p->io.avr, + p->eint[i].port_ioctl, p->eint[i].port_pin); + + avr_connect_irq(irq, p->io.irq + i); + } + } +} + +static const char * irq_names[EXTINT_COUNT] = { + [EXTINT_IRQ_OUT_INT0] = "io = _io; + + avr_register_io(avr, &p->io); + for (int i = 0; i < EXTINT_COUNT; i++) { + if (!p->eint[i].port_ioctl) + break; + avr_register_vector(avr, &p->eint[i].vector); + } + // allocate this module's IRQ + + avr_io_setirqs(&p->io, AVR_IOCTL_EXTINT_GETIRQ(), EXTINT_COUNT, NULL); +} + diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_extint.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_extint.h new file mode 100644 index 0000000..62aa154 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_extint.h @@ -0,0 +1,129 @@ +/* + avr_extint.h + + External Interrupt Handling (for INT0-3) + + Copyright 2008, 2009 Michel Pollet + Copyright 2014 Doug Szumski + + 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 . + */ + +#ifndef __AVR_EXTINT_H__ +#define __AVR_EXTINT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "sim_avr.h" + + +enum { + EXTINT_IRQ_OUT_INT0 = 0, + EXTINT_IRQ_OUT_INT1, EXTINT_IRQ_OUT_INT2, EXTINT_IRQ_OUT_INT3, + EXTINT_IRQ_OUT_INT4, EXTINT_IRQ_OUT_INT5, EXTINT_IRQ_OUT_INT6, + EXTINT_IRQ_OUT_INT7, + EXTINT_COUNT +}; + +// Get the internal IRQ corresponding to the INT +#define AVR_IOCTL_EXTINT_GETIRQ() AVR_IOCTL_DEF('i','n','t',' ') + +/* + * This module is just a "relay" for the pin change IRQ in the IO port + * module. We hook up to their IRQ and raise out interrupt vectors as needed + * + * "isc" is handled, apart from the "level" mode that doesn't make sense here (?) + */ +typedef struct avr_extint_t { + avr_io_t io; + + struct { + avr_regbit_t isc[2]; // interrupt sense control bits + avr_int_vector_t vector; // interrupt vector + + uint32_t port_ioctl; // ioctl to use to get port + uint8_t port_pin; // pin number in said port + uint8_t strict_lvl_trig;// enforces a repetitive interrupt triggering while the pin is held low + } eint[EXTINT_COUNT]; + +} avr_extint_t; + +void avr_extint_init(avr_t * avr, avr_extint_t * p); +int avr_extint_is_strict_lvl_trig(avr_t * avr, uint8_t extint_no); +void avr_extint_set_strict_lvl_trig(avr_t * avr, uint8_t extint_no, uint8_t strict); + + +// Declares a typical INT into a avr_extint_t in a core. +// this is a shortcut since INT declarations are pretty standard. +// The Tinies as well as the atmega1280 are slightly different. +// See sim_tinyx5.h and sim_mega1280.h +#define AVR_EXTINT_DECLARE(_index, _portname, _portpin) \ + .eint[_index] = { \ + .port_ioctl = AVR_IOCTL_IOPORT_GETIRQ(_portname), \ + .port_pin = _portpin, \ + .isc = { AVR_IO_REGBIT(EICRA, ISC##_index##0), AVR_IO_REGBIT(EICRA, ISC##_index##1) },\ + .vector = { \ + .enable = AVR_IO_REGBIT(EIMSK, INT##_index), \ + .raised = AVR_IO_REGBIT(EIFR, INTF##_index), \ + .vector = INT##_index##_vect, \ + },\ + } + +// Asynchronous External Interrupt, for example INT2 on the m16 and m32 +// Uses only 1 interrupt sense control bit +#define AVR_ASYNC_EXTINT_DECLARE(_index, _portname, _portpin) \ + .eint[_index] = { \ + .port_ioctl = AVR_IOCTL_IOPORT_GETIRQ(_portname), \ + .port_pin = _portpin, \ + .isc = { AVR_IO_REGBIT(MCUCSR, ISC##_index) },\ + .vector = { \ + .enable = AVR_IO_REGBIT(GICR, INT##_index), \ + .raised = AVR_IO_REGBIT(GIFR, INTF##_index), \ + .vector = INT##_index##_vect, \ + },\ + } + +#define AVR_EXTINT_MEGA_DECLARE(_index, _portname, _portpin, _EICR) \ + .eint[_index] = { \ + .port_ioctl = AVR_IOCTL_IOPORT_GETIRQ(_portname), \ + .port_pin = _portpin, \ + .isc = { AVR_IO_REGBIT(EICR##_EICR, ISC##_index##0), AVR_IO_REGBIT(EICR##_EICR, ISC##_index##1) },\ + .vector = { \ + .enable = AVR_IO_REGBIT(EIMSK, INT##_index), \ + .raised = AVR_IO_REGBIT(EIFR, INTF##_index), \ + .vector = INT##_index##_vect, \ + },\ + } + +#define AVR_EXTINT_TINY_DECLARE(_index, _portname, _portpin, _IFR) \ + .eint[_index] = { \ + .port_ioctl = AVR_IOCTL_IOPORT_GETIRQ(_portname), \ + .port_pin = _portpin, \ + .isc = { AVR_IO_REGBIT(MCUCR, ISC##_index##0), AVR_IO_REGBIT(MCUCR, ISC##_index##1) }, \ + .vector = { \ + .enable = AVR_IO_REGBIT(GIMSK, INT##_index), \ + .raised = AVR_IO_REGBIT(_IFR, INTF##_index), \ + .vector = INT##_index##_vect, \ + }, \ + } + +#ifdef __cplusplus +}; +#endif + +#endif /*__AVR_EXTINT_H__*/ diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_flash.c b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_flash.c new file mode 100644 index 0000000..cc1fd96 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_flash.c @@ -0,0 +1,145 @@ +/* + avr_flash.c + + Copyright 2008, 2009 Michel Pollet + + 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 +#include "avr_flash.h" + +static avr_cycle_count_t avr_progen_clear(struct avr_t * avr, avr_cycle_count_t when, void * param) +{ + avr_flash_t * p = (avr_flash_t *)param; + avr_regbit_clear(p->io.avr, p->selfprgen); + AVR_LOG(avr, LOG_WARNING, "FLASH: avr_progen_clear - SPM not received, clearing PRGEN bit\n"); + return 0; +} + + +static void avr_flash_write(avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) +{ + avr_flash_t * p = (avr_flash_t *)param; + + avr_core_watch_write(avr, addr, v); + +// printf("** avr_flash_write %02x\n", v); + + if (avr_regbit_get(avr, p->selfprgen)) + avr_cycle_timer_register(avr, 4, avr_progen_clear, p); // 4 cycles is very little! +} + +static void avr_flash_clear_temppage(avr_flash_t *p) +{ + for (int i = 0; i < p->spm_pagesize / 2; i++) { + p->tmppage[i] = 0xff; + p->tmppage_used[i] = 0; + } +} + +static int avr_flash_ioctl(struct avr_io_t * port, uint32_t ctl, void * io_param) +{ + if (ctl != AVR_IOCTL_FLASH_SPM) + return -1; + + avr_flash_t * p = (avr_flash_t *)port; + avr_t * avr = p->io.avr; + + avr_flashaddr_t z = avr->data[R_ZL] | (avr->data[R_ZH] << 8); + if (avr->rampz) + z |= avr->data[avr->rampz] << 16; + uint16_t r01 = avr->data[0] | (avr->data[1] << 8); + +// printf("AVR_IOCTL_FLASH_SPM %02x Z:%04x R01:%04x\n", avr->data[p->r_spm], z,r01); + if (avr_regbit_get(avr, p->selfprgen)) { + avr_cycle_timer_cancel(avr, avr_progen_clear, p); + + if (avr_regbit_get(avr, p->pgers)) { + z &= ~1; + AVR_LOG(avr, LOG_TRACE, "FLASH: Erasing page %04x (%d)\n", (z / p->spm_pagesize), p->spm_pagesize); + for (int i = 0; i < p->spm_pagesize; i++) + avr->flash[z++] = 0xff; + } else if (avr_regbit_get(avr, p->pgwrt)) { + z &= ~(p->spm_pagesize - 1); + AVR_LOG(avr, LOG_TRACE, "FLASH: Writing page %04x (%d)\n", (z / p->spm_pagesize), p->spm_pagesize); + for (int i = 0; i < p->spm_pagesize / 2; i++) { + avr->flash[z++] = p->tmppage[i]; + avr->flash[z++] = p->tmppage[i] >> 8; + } + avr_flash_clear_temppage(p); + } else if (avr_regbit_get(avr, p->blbset)) { + AVR_LOG(avr, LOG_TRACE, "FLASH: Setting lock bits (ignored)\n"); + } else if (p->flags & AVR_SELFPROG_HAVE_RWW && avr_regbit_get(avr, p->rwwsre)) { + avr_flash_clear_temppage(p); + } else { + AVR_LOG(avr, LOG_TRACE, "FLASH: Writing temppage %08x (%04x)\n", z, r01); + z >>= 1; + if (!p->tmppage_used[z % (p->spm_pagesize / 2)]) { + p->tmppage[z % (p->spm_pagesize / 2)] = r01; + p->tmppage_used[z % (p->spm_pagesize / 2)] = 1; + } + } + } + avr_regbit_clear(avr, p->selfprgen); + return 0; +} + +static void +avr_flash_reset(avr_io_t * port) +{ + avr_flash_t * p = (avr_flash_t *) port; + + avr_flash_clear_temppage(p); +} + +static void +avr_flash_dealloc(struct avr_io_t * port) +{ + avr_flash_t * p = (avr_flash_t *) port; + + if (p->tmppage) + free(p->tmppage); + + if (p->tmppage_used) + free(p->tmppage_used); +} + +static avr_io_t _io = { + .kind = "flash", + .ioctl = avr_flash_ioctl, + .reset = avr_flash_reset, + .dealloc = avr_flash_dealloc, +}; + +void avr_flash_init(avr_t * avr, avr_flash_t * p) +{ + p->io = _io; +// printf("%s init SPM %04x\n", __FUNCTION__, p->r_spm); + + if (!p->tmppage) + p->tmppage = malloc(p->spm_pagesize); + + if (!p->tmppage_used) + p->tmppage_used = malloc(p->spm_pagesize / 2); + + avr_register_io(avr, &p->io); + avr_register_vector(avr, &p->flash); + + avr_register_io_write(avr, p->r_spm, avr_flash_write, p); +} diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_flash.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_flash.h new file mode 100644 index 0000000..07747fc --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_flash.h @@ -0,0 +1,92 @@ +/* + avr_flash.h + + Copyright 2008, 2009 Michel Pollet + + 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 . + */ + + +#ifndef __AVR_FLASH_H___ +#define __AVR_FLASH_H___ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "sim_avr.h" + +/* + * Handles self-programming subsystem if the core + * supports it. + */ +typedef struct avr_flash_t { + avr_io_t io; + + uint16_t flags; + uint16_t *tmppage; + uint8_t *tmppage_used; + uint16_t spm_pagesize; + uint8_t r_spm; + avr_regbit_t selfprgen; + avr_regbit_t pgers; // page erase + avr_regbit_t pgwrt; // page write + avr_regbit_t blbset; // lock bit set + avr_regbit_t rwwsre; // read while write section read enable + avr_regbit_t rwwsb; // read while write section busy + + avr_int_vector_t flash; // Interrupt vector +} avr_flash_t; + +/* Set if the flash supports a Read While Write section */ +#define AVR_SELFPROG_HAVE_RWW (1 << 0) + +void avr_flash_init(avr_t * avr, avr_flash_t * p); + + +#define AVR_IOCTL_FLASH_SPM AVR_IOCTL_DEF('f','s','p','m') + +#define AVR_SELFPROG_DECLARE_INTERNAL(_spmr, _spen, _vector) \ + .r_spm = _spmr,\ + .spm_pagesize = SPM_PAGESIZE,\ + .selfprgen = AVR_IO_REGBIT(_spmr, _spen),\ + .pgers = AVR_IO_REGBIT(_spmr, PGERS),\ + .pgwrt = AVR_IO_REGBIT(_spmr, PGWRT),\ + .blbset = AVR_IO_REGBIT(_spmr, BLBSET),\ + .flash = {\ + .enable = AVR_IO_REGBIT(_spmr, SPMIE),\ + .vector = _vector,\ + }\ + +#define AVR_SELFPROG_DECLARE_NORWW(_spmr, _spen, _vector) \ + .selfprog = {\ + .flags = 0,\ + AVR_SELFPROG_DECLARE_INTERNAL(_spmr, _spen, _vector),\ + } + +#define AVR_SELFPROG_DECLARE(_spmr, _spen, _vector) \ + .selfprog = {\ + .flags = AVR_SELFPROG_HAVE_RWW,\ + AVR_SELFPROG_DECLARE_INTERNAL(_spmr, _spen, _vector),\ + .rwwsre = AVR_IO_REGBIT(_spmr, RWWSRE),\ + .rwwsb = AVR_IO_REGBIT(_spmr, RWWSB),\ + } + +#ifdef __cplusplus +}; +#endif + +#endif /* __AVR_FLASH_H___ */ diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_ioport.c b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_ioport.c new file mode 100644 index 0000000..91cf106 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_ioport.c @@ -0,0 +1,340 @@ +/* + avr_ioport.c + + Copyright 2008, 2009 Michel Pollet + + 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 "avr_ioport.h" + +#define D(_w) + +static void +avr_ioport_flag_write( + struct avr_t * avr, + avr_io_addr_t addr, + uint8_t v, + void * param) +{ + avr_ioport_t * p = (avr_ioport_t *)param; + + // Clear interrupt if 1 is written to flag. + + if (avr_regbit_from_value(avr, p->pcint.raised, v)) + avr_clear_interrupt(avr, &p->pcint); +} + +static uint8_t +avr_ioport_read( + struct avr_t * avr, + avr_io_addr_t addr, + void * param) +{ + avr_ioport_t * p = (avr_ioport_t *)param; + uint8_t ddr = avr->data[p->r_ddr]; + uint8_t v = (avr->data[p->r_pin] & ~ddr) | (avr->data[p->r_port] & ddr); + avr->data[addr] = v; + avr_raise_irq(p->io.irq + IOPORT_IRQ_REG_PIN, v); + D(if (avr->data[addr] != v) printf("** PIN%c(%02x) = %02x\r\n", p->name, addr, v);) + + // made to trigger potential watchpoints + v = avr_core_watch_read(avr, addr); + return v; +} + +static void +avr_ioport_update_irqs( + avr_ioport_t * p) +{ + avr_t * avr = p->io.avr; + uint8_t ddr = avr->data[p->r_ddr]; + // Set the PORT value if the pin is marked as output + // otherwise, if there is an 'external' pullup, set it + // otherwise, if the PORT pin was 1 to indicate an + // internal pullup, set that. + for (int i = 0; i < 8; i++) { + if (ddr & (1 << i)) + avr_raise_irq(p->io.irq + i, (avr->data[p->r_port] >> i) & 1); + else if (p->external.pull_mask & (1 << i)) + avr_raise_irq(p->io.irq + i, (p->external.pull_value >> i) & 1); + else if ((avr->data[p->r_port] >> i) & 1) + avr_raise_irq(p->io.irq + i, 1); + } + uint8_t pin = (avr->data[p->r_pin] & ~ddr) | (avr->data[p->r_port] & ddr); + pin = (pin & ~p->external.pull_mask) | p->external.pull_value; + avr_raise_irq(p->io.irq + IOPORT_IRQ_PIN_ALL, pin); + + // if IRQs are registered on the PORT register (for example, VCD dumps) send + // those as well + avr_io_addr_t port_io = AVR_DATA_TO_IO(p->r_port); + if (avr->io[port_io].irq) { + avr_raise_irq(avr->io[port_io].irq + AVR_IOMEM_IRQ_ALL, avr->data[p->r_port]); + for (int i = 0; i < 8; i++) + avr_raise_irq(avr->io[port_io].irq + i, (avr->data[p->r_port] >> i) & 1); + } +} + +static void +avr_ioport_write( + struct avr_t * avr, + avr_io_addr_t addr, + uint8_t v, + void * param) +{ + avr_ioport_t * p = (avr_ioport_t *)param; + + D(if (avr->data[addr] != v) printf("** PORT%c(%02x) = %02x\r\n", p->name, addr, v);) + avr_core_watch_write(avr, addr, v); + avr_raise_irq(p->io.irq + IOPORT_IRQ_REG_PORT, v); + avr_ioport_update_irqs(p); +} + +/* + * This is a reasonably new behaviour for the io-ports. Writing 1's to the PIN register + * toggles the PORT equivalent bit (regardless of direction + */ +static void +avr_ioport_pin_write( + struct avr_t * avr, + avr_io_addr_t addr, + uint8_t v, + void * param) +{ + avr_ioport_t * p = (avr_ioport_t *)param; + + avr_ioport_write(avr, p->r_port, avr->data[p->r_port] ^ v, param); +} + +/* + * This is a the callback for the DDR register. There is nothing much to do here, apart + * from triggering an IRQ in case any 'client' code is interested in the information, + * and restoring all PIN bits marked as output to PORT values. + */ +static void +avr_ioport_ddr_write( + struct avr_t * avr, + avr_io_addr_t addr, + uint8_t v, + void * param) +{ + avr_ioport_t * p = (avr_ioport_t *)param; + + D(if (avr->data[addr] != v) printf("** DDR%c(%02x) = %02x\r\n", p->name, addr, v);) + avr_raise_irq(p->io.irq + IOPORT_IRQ_DIRECTION_ALL, v); + avr_core_watch_write(avr, addr, v); + avr_ioport_update_irqs(p); +} + +/* + * this is our "main" pin change callback, it can be triggered by either the + * 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( + struct avr_irq_t * irq, + uint32_t value, + void * param) +{ + avr_ioport_t * p = (avr_ioport_t *)param; + avr_t * avr = p->io.avr; + + int output = value & AVR_IOPORT_OUTPUT; + value &= 0xff; + uint8_t mask = 1 << irq->irq; + uint8_t ddr = avr->data[p->r_ddr]; + + if (output) { + if ((mask & ddr) == 0) + return; // TODO: stop further processing of IRQ. + + // If the IRQ was marked as Output, also do the IO write. + + avr_ioport_write(avr, + p->r_port, + (avr->data[p->r_port] & ~mask) | + (value ? mask : 0), + p); + } else { + // Set the real PIN bit. Ignore DDR as it's masked when read. + + avr_core_watch_write(avr, p->r_pin, + (avr->data[p->r_pin] & ~mask) | + (value ? mask : 0)); + + /* BUG: If DDR bit is set here, there should be no + * interrupt. But a spurious IRQ call by the user + * is indistinguishable from an internal one + * caused by writing the output port register and + * that should cause an interrupt. Doh! + */ + } + + if (p->r_pcint) { + // Ignore lingering copy of AVR_IOPORT_OUTPUT, or + // differing non-zero values. + + if (!value == !(irq->value & 0xff)) + return; + + // if the pcint bit is on, try to raise it + + int raisedata = avr->data[p->r_pcint]; + uint8_t uiRegMask = p->mask; + int8_t iShift = p->shift; + + if (uiRegMask) // If mask is 0, do nothing (backwards compat) + raisedata &= uiRegMask; // Mask off + + if (iShift>0) // Shift data if necessary for alignment. + raisedata <<= iShift; + else if (iShift<0) + raisedata >>= -iShift; + + int raise = raisedata & mask; + if (raise) + avr_raise_interrupt(avr, &p->pcint); + } +} + +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(p->io.irq + i, avr_ioport_irq_notify, p); +} + +static int +avr_ioport_ioctl( + struct avr_io_t * port, + uint32_t ctl, + void * io_param) +{ + avr_ioport_t * p = (avr_ioport_t *)port; + avr_t * avr = p->io.avr; + int res = -1; + + // all IOCTls require some sort of valid parameter, bail if not + if (!io_param) + return -1; + + switch(ctl) { + case AVR_IOCTL_IOPORT_GETIRQ_REGBIT: { + avr_ioport_getirq_t * r = (avr_ioport_getirq_t*)io_param; + + if (r->bit.reg == p->r_port || r->bit.reg == p->r_pin || r->bit.reg == p->r_ddr) { + // it's us ! check the special case when the "all pins" irq is requested + int o = 0; + if (r->bit.mask == 0xff) + r->irq[o++] = &p->io.irq[IOPORT_IRQ_PIN_ALL]; + else { + // otherwise fill up the ones needed + for (int bi = 0; bi < 8; bi++) + if (r->bit.mask & (1 << bi)) + r->irq[o++] = &p->io.irq[r->bit.bit + bi]; + } + if (o < 8) + r->irq[o] = NULL; + return o; + } + } break; + default: { + /* + * Return the port state if the IOCTL matches us. + */ + if (ctl == AVR_IOCTL_IOPORT_GETSTATE(p->name)) { + avr_ioport_state_t state = { + .name = p->name, + .port = avr->data[p->r_port], + .ddr = avr->data[p->r_ddr], + .pin = avr->data[p->r_pin], + }; + if (io_param) + *((avr_ioport_state_t*)io_param) = state; + res = 0; + } + /* + * Set the default IRQ values when pin is set as input + */ + if (ctl == AVR_IOCTL_IOPORT_SET_EXTERNAL(p->name)) { + avr_ioport_external_t * m = (avr_ioport_external_t*)io_param; + p->external.pull_mask = m->mask; + p->external.pull_value = m->value; + res = 0; + } + } + } + + return res; +} + +static const char * irq_names[IOPORT_IRQ_COUNT] = { + [IOPORT_IRQ_PIN0] = "=pin0", + [IOPORT_IRQ_PIN1] = "=pin1", + [IOPORT_IRQ_PIN2] = "=pin2", + [IOPORT_IRQ_PIN3] = "=pin3", + [IOPORT_IRQ_PIN4] = "=pin4", + [IOPORT_IRQ_PIN5] = "=pin5", + [IOPORT_IRQ_PIN6] = "=pin6", + [IOPORT_IRQ_PIN7] = "=pin7", + [IOPORT_IRQ_PIN_ALL] = "8>all", + [IOPORT_IRQ_DIRECTION_ALL] = "8>ddr", + [IOPORT_IRQ_REG_PORT] = "8>port", + [IOPORT_IRQ_REG_PIN] = "8>pin", +}; + +static avr_io_t _io = { + .kind = "port", + .reset = avr_ioport_reset, + .ioctl = avr_ioport_ioctl, + .irq_names = irq_names, +}; + +void avr_ioport_init(avr_t * avr, avr_ioport_t * p) +{ + if (!p->r_port) { + printf("skipping PORT%c for core %s\n", p->name, avr->mmcu); + return; + } + p->io = _io; +// printf("%s PIN%c 0x%02x DDR%c 0x%02x PORT%c 0x%02x\n", __FUNCTION__, +// p->name, p->r_pin, +// p->name, p->r_ddr, +// p->name, p->r_port); + + avr_register_io(avr, &p->io); + avr_register_vector(avr, &p->pcint); + // allocate this module's IRQ + avr_io_setirqs(&p->io, AVR_IOCTL_IOPORT_GETIRQ(p->name), IOPORT_IRQ_COUNT, NULL); + + for (int i = 0; i < IOPORT_IRQ_REG_PIN; i++) { + p->io.irq[i].flags |= IRQ_FLAG_FILTERED; + if (i < IOPORT_IRQ_PIN_ALL) + p->io.irq[i].flags &= ~IRQ_FLAG_INIT; + } + avr_register_io_write(avr, p->r_port, avr_ioport_write, p); + avr_register_io_read(avr, p->r_pin, avr_ioport_read, p); + avr_register_io_write(avr, p->r_pin, avr_ioport_pin_write, p); + avr_register_io_write(avr, p->r_ddr, avr_ioport_ddr_write, p); + if (p->pcint.raised.reg) { + avr_register_io_write(avr, p->pcint.raised.reg, + avr_ioport_flag_write, p); + } +} diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_ioport.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_ioport.h new file mode 100644 index 0000000..024b695 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_ioport.h @@ -0,0 +1,148 @@ +/* + avr_ioport.h + + Copyright 2008, 2009 Michel Pollet + + 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 . + */ + +#ifndef __AVR_IOPORT_H__ +#define __AVR_IOPORT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "sim_avr.h" + +enum { + IOPORT_IRQ_PIN0 = 0, + IOPORT_IRQ_PIN1,IOPORT_IRQ_PIN2,IOPORT_IRQ_PIN3,IOPORT_IRQ_PIN4, + IOPORT_IRQ_PIN5,IOPORT_IRQ_PIN6,IOPORT_IRQ_PIN7, + IOPORT_IRQ_PIN_ALL, + IOPORT_IRQ_DIRECTION_ALL, + IOPORT_IRQ_REG_PORT, + IOPORT_IRQ_REG_PIN, + IOPORT_IRQ_COUNT +}; + +#define AVR_IOPORT_OUTPUT 0x100 + +// add port name (uppercase) to get the real IRQ +#define AVR_IOCTL_IOPORT_GETIRQ(_name) AVR_IOCTL_DEF('i','o','g',(_name)) + + +// this ioctl takes a avr_regbit_t, compares the register address +// to PORT/PIN/DDR and return the corresponding IRQ(s) if it matches +typedef struct avr_ioport_getirq_t { + avr_regbit_t bit; // bit wanted + avr_irq_t * irq[8]; // result, terminated by NULL if < 8 +} avr_ioport_getirq_t; + +#define AVR_IOCTL_IOPORT_GETIRQ_REGBIT AVR_IOCTL_DEF('i','o','g','r') + +/* + * ioctl used to get a port state. + * + * for (int i = 'A'; i <= 'F'; i++) { + * avr_ioport_state_t state; + * if (avr_ioctl(AVR_IOCTL_IOPORT_GETSTATE(i), &state) == 0) + * printf("PORT%c %02x DDR %02x PIN %02x\n", + * state.name, state.port, state.ddr, state.pin); + * } + */ +typedef struct avr_ioport_state_t { + unsigned long name : 7, + port : 8, ddr : 8, pin : 8; +} avr_ioport_state_t; + +// add port name (uppercase) to get the port state +#define AVR_IOCTL_IOPORT_GETSTATE(_name) AVR_IOCTL_DEF('i','o','s',(_name)) + +/* + * ioctl used to set default port state when set as input. + * + */ +typedef struct avr_ioport_external_t { + unsigned long name : 7, + mask : 8, value : 8; +} avr_ioport_external_t; + +// add port name (uppercase) to set default input pin IRQ values +#define AVR_IOCTL_IOPORT_SET_EXTERNAL(_name) AVR_IOCTL_DEF('i','o','p',(_name)) + +/** + * pin structure + */ +typedef struct avr_iopin_t { + uint16_t port : 8; ///< port e.g. 'B' + uint16_t pin : 8; ///< pin number +} avr_iopin_t; +#define AVR_IOPIN(_port, _pin) { .port = _port, .pin = _pin } + +/* + * Definition for an IO port + */ +typedef struct avr_ioport_t { + avr_io_t io; + char name; + avr_io_addr_t r_port; + avr_io_addr_t r_ddr; + avr_io_addr_t r_pin; + + avr_int_vector_t pcint; // PCINT vector + avr_io_addr_t r_pcint; // pcint 8 pins mask + + // Mask and shift for PCINTs. This is needed for chips like the 2560 + // where PCINT do not align with IRQs. + + uint8_t mask; + int8_t shift; + + // This represent the default IRQ value when + // the port is set as input. + // If the mask is not set, no output value is sent + // on the output IRQ. If the mask is set, the specified + // value is sent. + struct { + uint8_t pull_mask, pull_value; + } external; +} avr_ioport_t; + +void avr_ioport_init(avr_t * avr, avr_ioport_t * port); + +#define AVR_IOPORT_DECLARE(_lname, _cname, _uname) \ + .port ## _lname = { \ + .name = _cname, .r_port = PORT ## _uname, .r_ddr = DDR ## _uname, .r_pin = PIN ## _uname, \ + } + +#define AVR_IOPORT_DECLARE_PC(_lname, _cname, _uname, _pcnum) \ + .port ## _lname = { \ + .name = _cname, .r_port = PORT ## _uname, \ + .r_ddr = DDR ## _uname, .r_pin = PIN ## _uname, \ + .pcint = { \ + .enable = AVR_IO_REGBIT(PCICR, PCIE ## _pcnum), \ + .raised = AVR_IO_REGBIT(PCIFR, PCIF ## _pcnum), \ + .vector = PCINT ## _pcnum ## _vect, \ + }, \ + .r_pcint = PCMSK ## _pcnum, \ + } + +#ifdef __cplusplus +}; +#endif + +#endif /* __AVR_IOPORT_H__ */ diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_lin.c b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_lin.c new file mode 100644 index 0000000..001b34c --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_lin.c @@ -0,0 +1,106 @@ +/* + avr_lin.h + + Copyright 2008, 2011 Michel Pollet + Copyright 2011 Markus Lampert + + 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 "avr_lin.h" +#include "sim_time.h" + + +static void +avr_lin_baud_write( + struct avr_t *avr, + avr_io_addr_t addr, + uint8_t v, + void *param) +{ + avr_lin_t *p = (avr_lin_t*) param; + + if (p->r_linbtr != p->ldisr.reg || p->r_linbtr != p->lbt.reg) { // sanity check + AVR_LOG(avr, LOG_ERROR, "LIN: LDISR and LBT[x] register different!\n"); + return; + } + + AVR_LOG(avr, LOG_TRACE, "LIN: addr[%04x] = %02x\n", addr, v); + if (addr == p->ldisr.reg) { + if (avr_regbit_get(avr, p->lena)) { + AVR_LOG(avr, LOG_WARNING, "LIN: LENA bit set on changing LBTR\n"); + return; + } + if ((v >> p->ldisr.bit) & p->ldisr.mask) { + uint8_t lbt = (v >> p->lbt.bit) & p->lbt.mask; + uint8_t ov = v; + v = (1 << p->ldisr.bit) | (lbt << p->lbt.bit); + AVR_LOG(avr, LOG_TRACE, "LIN: v=%02x -> LBT = %02x -> LINBT = %02x\n", ov, lbt, v); + } else { + v = 0x20; + } + } + avr_core_watch_write(avr, addr, v); // actually set the value + + uint32_t lbt = avr_regbit_get(avr, p->lbt); // Min value CANNOT be zero + uint32_t lbrr = (avr->data[p->r_linbrrh] << 8) | avr->data[p->r_linbrrl]; + AVR_LOG(avr, LOG_TRACE, "LIN: UART LBT/LBRR to %04x/%04x\n", lbt, lbrr); + // there is no division by zero case here, lbt is >= 8 + //uint32_t baud = avr->frequency / (lbt * (lbrr + 1)); + uint32_t word_size = 1 /*start*/+ 8 /*data bits*/+ 1 /*parity*/+ 1 /*stop*/; + int cycles_per_bit = lbt * (lbrr + 1); + double baud = ((double)avr->frequency) / cycles_per_bit; // can be less than 1 + p->uart.cycles_per_byte = cycles_per_bit * word_size; + + AVR_LOG(avr, LOG_TRACE, "LIN: UART configured to %04x/%04x = %.4f bps, 8 data 1 stop\n", lbt, + lbrr, baud); + + //p->uart.cycles_per_byte = 1000000 / (baud / word_size); + AVR_LOG(avr, LOG_TRACE, "LIN: Roughly %d usec per byte\n", + avr_cycles_to_usec(avr, p->uart.cycles_per_byte)); +} + +static void +avr_lin_reset( + avr_io_t *port) +{ + avr_lin_t *p = (avr_lin_t*) port; + avr_t * avr = p->io.avr; + + AVR_LOG(avr, LOG_TRACE, "LIN: UART: reset\n"); + + p->uart.io.reset(&p->uart.io); + avr->data[p->r_linbtr] = 0x20; +} + +static avr_io_t _io = { + .kind = "lin", + .reset = avr_lin_reset, +}; + +void +avr_lin_init( + avr_t *avr, + avr_lin_t *p) +{ + // init uart part + avr_uart_init(avr, &p->uart); + + p->io = _io; + avr_register_io_write(avr, p->r_linbtr, avr_lin_baud_write, p); + avr_register_io_write(avr, p->r_linbrrl, avr_lin_baud_write, p); +} diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_lin.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_lin.h new file mode 100644 index 0000000..b1ecadf --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_lin.h @@ -0,0 +1,55 @@ +/* + avr_lin.h + + Copyright 2008, 2011 Michel Pollet + Copyright 2011 Markus Lampert + + 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 . + */ + +#ifndef __AVR_LIN_H__ +#define __AVR_LIN_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "sim_avr.h" +#include "avr_uart.h" + +typedef struct avr_lin_t { + avr_io_t io; + + avr_io_addr_t r_linbtr; + avr_io_addr_t r_linbrrh, r_linbrrl; + + avr_regbit_t lena; + avr_regbit_t ldisr; + avr_regbit_t lbt; + + avr_uart_t uart; // used when LIN controller is setup as a UART +} avr_lin_t; + +void +avr_lin_init( + avr_t *avr, + avr_lin_t *port); + +#ifdef __cplusplus +}; +#endif + +#endif /* __AVR_LIN_H__ */ diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_spi.c b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_spi.c new file mode 100644 index 0000000..bb602ac --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_spi.c @@ -0,0 +1,119 @@ +/* + avr_spi.c + + Copyright 2008, 2009 Michel Pollet + Modified 2020 by VintagePC to support clock divisors + + 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 "avr_spi.h" + +static avr_cycle_count_t avr_spi_raise(struct avr_t * avr, avr_cycle_count_t when, void * param) +{ + avr_spi_t * p = (avr_spi_t *)param; + + 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_interrupt(avr, &p->spi); + avr_raise_irq(p->io.irq + SPI_IRQ_OUTPUT, avr->data[p->r_spdr]); + } + } + return 0; +} + +static uint8_t avr_spi_read(struct avr_t * avr, avr_io_addr_t addr, void * param) +{ + avr_spi_t * p = (avr_spi_t *)param; + uint8_t v = p->input_data_register; + p->input_data_register = 0; + avr_regbit_clear(avr, p->spi.raised); +// printf("avr_spi_read = %02x\n", v); + return v; +} + +static void avr_spi_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) +{ + + static const uint8_t _avr_spi_clkdiv[4] = {4,16,64,128}; + avr_spi_t * p = (avr_spi_t *)param; + + if (addr == p->r_spdr) { + /* Clear the SPIF bit. See ATmega164/324/644 manual, Section 18.5.2. */ + avr_regbit_clear(avr, p->spi.raised); + + avr_core_watch_write(avr, addr, v); + uint16_t clock_shift = _avr_spi_clkdiv[avr->data[p->r_spcr]&0b11]; + // If master && 2X, double rate (half divisor) + if (avr_regbit_get(avr, p->mstr) && avr_regbit_get(avr, p->spr[2])) + clock_shift>>=1; + + // We can wait directly in clockshifts, it is a divisor, so /4 means 4 avr cycles to clock out one bit. + avr_cycle_timer_register(avr, clock_shift<<3, avr_spi_raise, p); // *8 since 8 clocks to a byte. + } +} + +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 if 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(struct avr_io_t *io) +{ + avr_spi_t * p = (avr_spi_t *)io; + avr_irq_register_notify(p->io.irq + SPI_IRQ_INPUT, avr_spi_irq_input, p); +} + +static const char * irq_names[SPI_IRQ_COUNT] = { + [SPI_IRQ_INPUT] = "8io = _io; + + avr_register_io(avr, &p->io); + avr_register_vector(avr, &p->spi); + // allocate this module's IRQ + avr_io_setirqs(&p->io, AVR_IOCTL_SPI_GETIRQ(p->name), SPI_IRQ_COUNT, NULL); + + avr_register_io_write(avr, p->r_spdr, avr_spi_write, p); + avr_register_io_read(avr, p->r_spdr, avr_spi_read, p); +} diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_spi.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_spi.h new file mode 100644 index 0000000..c676adb --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_spi.h @@ -0,0 +1,107 @@ +/* + avr_spi.h + + Copyright 2008, 2009 Michel Pollet + Modified 2020 by VintagePC to support clock divisors + + 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 . + */ + +#ifndef __AVR_SPI_H__ +#define __AVR_SPI_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#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; + char name; + avr_regbit_t disabled; // bit in the PRR + + avr_io_addr_t r_spdr; // data register + avr_io_addr_t r_spcr; // control register + avr_io_addr_t r_spsr; // status register + + avr_regbit_t spe; // spi enable + avr_regbit_t mstr; // master/slave + 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); + +#define AVR_SPIX_DECLARE(_name, _prr, _prspi) \ + .spi = { \ + .name = '0' + _name,\ + .disabled = AVR_IO_REGBIT(_prr, _prspi), \ + \ + .r_spdr = SPDR ## _name, \ + .r_spcr = SPCR ## _name, \ + .r_spsr = SPSR ## _name, \ + \ + .spe = AVR_IO_REGBIT(SPCR ## _name, SPE ## _name), \ + .mstr = AVR_IO_REGBIT(SPCR ## _name, MSTR ## _name), \ + \ + .spr = { AVR_IO_REGBIT(SPCR ## _name, SPR0 ## _name), \ + AVR_IO_REGBIT(SPCR ## _name, SPR1 ## _name), \ + AVR_IO_REGBIT(SPSR ## _name, SPI2X ## _name) }, \ + .spi = { \ + .enable = AVR_IO_REGBIT(SPCR ## _name, SPIE ## _name), \ + .raised = AVR_IO_REGBIT(SPSR ## _name, SPIF ## _name), \ + .vector = SPI_STC_vect, \ + }, \ + } + + +#define AVR_SPI_DECLARE(_prr, _prspi) \ + .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, \ + }, \ + } + +#ifdef __cplusplus +}; +#endif + +#endif /*__AVR_SPI_H__*/ diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_timer.c b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_timer.c new file mode 100644 index 0000000..39a46bd --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_timer.c @@ -0,0 +1,985 @@ +/* + avr_timer.c + + Handles the 8 bits and 16 bits AVR timer. + Handles + + CDC + + Fast PWM + + Copyright 2008-2012 Michel Pollet + + 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 "avr_timer.h" +#include "avr_ioport.h" +#include "sim_time.h" + +/* + * The timers are /always/ 16 bits here, if the higher byte register + * is specified it's just added. + */ +static uint16_t +_timer_get_ocr( + avr_timer_t * p, + int compi) +{ + return p->io.avr->data[p->comp[compi].r_ocr] | + (p->comp[compi].r_ocrh ? + (p->io.avr->data[p->comp[compi].r_ocrh] << 8) : 0); +} + +static uint16_t +_timer_get_comp_ocr( + struct avr_t * avr, + avr_timer_comp_p comp) +{ + int ocrh = comp->r_ocrh; + return avr->data[comp->r_ocr] | + (ocrh ? (avr->data[ocrh] << 8) : 0); +} + +static uint16_t +_timer_get_tcnt( + avr_timer_t * p) +{ + return p->io.avr->data[p->r_tcnt] | + (p->r_tcnth ? (p->io.avr->data[p->r_tcnth] << 8) : 0); +} + +static uint16_t +_timer_get_icr( + avr_timer_t * p) +{ + return p->io.avr->data[p->r_icr] | + (p->r_tcnth ? (p->io.avr->data[p->r_icrh] << 8) : 0); +} +static avr_cycle_count_t +avr_timer_comp( + avr_timer_t *p, + avr_cycle_count_t when, + uint8_t comp, + uint8_t raise_interrupt) +{ + avr_t * avr = p->io.avr; + if (raise_interrupt) { + avr_raise_interrupt(avr, &p->comp[comp].interrupt); + } + + // check output compare mode and set/clear pins + uint8_t mode = avr_regbit_get(avr, p->comp[comp].com); + avr_irq_t * irq = &p->io.irq[TIMER_IRQ_OUT_COMP + comp]; + + uint32_t flags = 0; + if (p->comp[comp].com_pin.reg) // we got a physical pin + flags |= AVR_IOPORT_OUTPUT; + AVR_LOG(avr, LOG_TRACE, "Timer comp: irq %p, mode %d @%d\n", irq, mode, when); + switch (mode) { + case avr_timer_com_normal: // Normal mode OCnA disconnected + break; + case avr_timer_com_toggle: // Toggle OCnA on compare match + if (p->comp[comp].com_pin.reg) // we got a physical pin + avr_raise_irq(irq, + flags | + (avr_regbit_get(avr, p->comp[comp].com_pin) ? 0 : 1)); + else // no pin, toggle the IRQ anyway + avr_raise_irq(irq, + p->io.irq[TIMER_IRQ_OUT_COMP + comp].value ? 0 : 1); + break; + case avr_timer_com_clear: + avr_raise_irq(irq, flags | 0); + break; + case avr_timer_com_set: + avr_raise_irq(irq, flags | 1); + break; + } + + return p->tov_cycles ? 0 : + p->comp[comp].comp_cycles ? + when + p->comp[comp].comp_cycles : 0; +} + +static void +avr_timer_comp_on_tov( + avr_timer_t *p, + avr_cycle_count_t when, + uint8_t comp) +{ + avr_t * avr = p->io.avr; + + // check output compare mode and set/clear pins + uint8_t mode = avr_regbit_get(avr, p->comp[comp].com); + avr_irq_t * irq = &p->io.irq[TIMER_IRQ_OUT_COMP + comp]; + + // only PWM modes have special behaviour on overflow + if((p->wgm_op_mode_kind != avr_timer_wgm_pwm) && + (p->wgm_op_mode_kind != avr_timer_wgm_fast_pwm)) + return; + + switch (mode) { + case avr_timer_com_normal: // Normal mode + break; + case avr_timer_com_toggle: // toggle on compare match => on tov do nothing + break; + case avr_timer_com_clear: // clear on compare match => set on tov + avr_raise_irq(irq, 1); + break; + case avr_timer_com_set: // set on compare match => clear on tov + avr_raise_irq(irq, 0); + break; + } +} + +static avr_cycle_count_t +avr_timer_compa( + struct avr_t * avr, + avr_cycle_count_t when, + void * param) +{ + return avr_timer_comp((avr_timer_t*)param, when, AVR_TIMER_COMPA, 1); +} + +static avr_cycle_count_t +avr_timer_compb( + struct avr_t * avr, + avr_cycle_count_t when, + void * param) +{ + return avr_timer_comp((avr_timer_t*)param, when, AVR_TIMER_COMPB, 1); +} + +static avr_cycle_count_t +avr_timer_compc( + struct avr_t * avr, + avr_cycle_count_t when, + void * param) +{ + return avr_timer_comp((avr_timer_t*)param, when, AVR_TIMER_COMPC, 1); +} + +static void +avr_timer_irq_ext_clock( + struct avr_irq_t * irq, + uint32_t value, + void * param) +{ + avr_timer_t * p = (avr_timer_t *)param; + avr_t * avr = p->io.avr; + + if ((p->ext_clock_flags & AVR_TIMER_EXTCLK_FLAG_VIRT) || !p->tov_top) + return; // we are clocked internally (actually should never come here) + + int bing = 0; + if (p->ext_clock_flags & AVR_TIMER_EXTCLK_FLAG_EDGE) { // clock on rising edge + if (!irq->value && value) + bing++; + } else { // clock on falling edge + if (irq->value && !value) + bing++; + } + if (!bing) + return; + + //AVR_LOG(avr, LOG_TRACE, "%s Timer%c tick, tcnt=%i\n", __func__, p->name, p->tov_base); + + p->ext_clock_flags |= AVR_TIMER_EXTCLK_FLAG_STARTED; + + static const avr_cycle_timer_t dispatch[AVR_TIMER_COMP_COUNT] = + { avr_timer_compa, avr_timer_compb, avr_timer_compc }; + + int overflow = 0; + /** + * + * Datasheet excerpt (Compare Match Output Unit): + * "The 16-bit comparator continuously compares TCNT1 with the Output Compare Regis- + ter (OCR1x). If TCNT equals OCR1x the comparator signals a match. A match will set + the Output Compare Flag (OCF1x) at the next timer clock cycle. If enabled (OCIE1x = + 1), the Output Compare Flag generates an output compare interrupt." + Thus, comparators should go before incementing the counter to use counter value + from the previous cycle. + */ + for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++) { + if (p->wgm_op_mode_kind != avr_timer_wgm_ctc) { + if ((p->mode.top == avr_timer_wgm_reg_ocra) && (compi == 0)) + continue; // ocra used to define TOP + } + if (p->comp[compi].comp_cycles && (p->tov_base == p->comp[compi].comp_cycles)) { + dispatch[compi](avr, avr->cycle, param); + if (p->wgm_op_mode_kind == avr_timer_wgm_ctc) + p->tov_base = 0; + } + } + + switch (p->wgm_op_mode_kind) { + case avr_timer_wgm_fc_pwm: // in the avr_timer_write_ocr comment "OCR is not used here" - why? + case avr_timer_wgm_pwm: + if ((p->ext_clock_flags & AVR_TIMER_EXTCLK_FLAG_REVDIR) != 0) { + --p->tov_base; + if (p->tov_base == 0) { + // overflow occured + p->ext_clock_flags &= ~AVR_TIMER_EXTCLK_FLAG_REVDIR; // restore forward count direction + overflow = 1; + } + } + else { + if (++p->tov_base >= p->tov_top) { + p->ext_clock_flags |= AVR_TIMER_EXTCLK_FLAG_REVDIR; // prepare to count down + } + } + break; + case avr_timer_wgm_fast_pwm: + if (++p->tov_base == p->tov_top) { + overflow = 1; + if (p->mode.top == avr_timer_wgm_reg_icr) + avr_raise_interrupt(avr, &p->icr); + else if (p->mode.top == avr_timer_wgm_reg_ocra) + avr_raise_interrupt(avr, &p->comp[0].interrupt); + } + else if (p->tov_base > p->tov_top) { + p->tov_base = 0; + } + break; + case avr_timer_wgm_ctc: + { + int max = (1 << p->wgm_op[0].size)-1; + if (++p->tov_base > max) { + // overflow occured + p->tov_base = 0; + overflow = 1; + } + } + break; + default: + if (++p->tov_base > p->tov_top) { + // overflow occured + p->tov_base = 0; + overflow = 1; + } + break; + } + + if (overflow) { + for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++) { + if (p->comp[compi].comp_cycles) { + if (p->mode.top == avr_timer_wgm_reg_ocra && compi == 0) + continue; + avr_timer_comp_on_tov(p, 0, compi); + } + } + avr_raise_interrupt(avr, &p->overflow); + } + +} + +// timer overflow +static avr_cycle_count_t +avr_timer_tov( + struct avr_t * avr, + avr_cycle_count_t when, + void * param) +{ + avr_timer_t * p = (avr_timer_t *)param; + int start = p->tov_base == 0; + + avr_cycle_count_t next = when; + if (((p->ext_clock_flags & (AVR_TIMER_EXTCLK_FLAG_AS2 | AVR_TIMER_EXTCLK_FLAG_TN)) != 0) + && (p->tov_cycles_fract != 0.0f)) { + p->phase_accumulator += p->tov_cycles_fract; + if (p->phase_accumulator >= 1.0f) { + ++next; + p->phase_accumulator -= 1.0f; + } else if (p->phase_accumulator <= -1.0f) { + --next; + p->phase_accumulator += 1.0f; + } + } + + if (!start) + avr_raise_interrupt(avr, &p->overflow); + p->tov_base = when; + + static const avr_cycle_timer_t dispatch[AVR_TIMER_COMP_COUNT] = + { avr_timer_compa, avr_timer_compb, avr_timer_compc }; + + for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++) { + if (p->comp[compi].comp_cycles) { + if (p->comp[compi].comp_cycles < p->tov_cycles && p->comp[compi].comp_cycles >= (avr->cycle - when)) { + avr_timer_comp_on_tov(p, when, compi); + avr_cycle_timer_register(avr, + p->comp[compi].comp_cycles - (avr->cycle - next), + dispatch[compi], p); + } else if (p->tov_cycles == p->comp[compi].comp_cycles && !start) + dispatch[compi](avr, when, param); + } + } + + return next + p->tov_cycles; +} + +static uint16_t +_avr_timer_get_current_tcnt( + avr_timer_t * p) +{ + avr_t * avr = p->io.avr; + if (!(p->ext_clock_flags & (AVR_TIMER_EXTCLK_FLAG_TN | AVR_TIMER_EXTCLK_FLAG_AS2)) || + (p->ext_clock_flags & AVR_TIMER_EXTCLK_FLAG_VIRT) + ) { + if (p->tov_cycles) { + uint64_t when = avr->cycle - p->tov_base; + + return (when * (((uint32_t)p->tov_top)+1)) / p->tov_cycles; + } + } + else { + if (p->tov_top) + return p->tov_base; + } + return 0; +} + +static uint8_t +avr_timer_tcnt_read( + struct avr_t * avr, + avr_io_addr_t addr, + void * param) +{ + avr_timer_t * p = (avr_timer_t *)param; + // made to trigger potential watchpoints + + uint16_t tcnt = _avr_timer_get_current_tcnt(p); + + avr->data[p->r_tcnt] = tcnt; + if (p->r_tcnth) + avr->data[p->r_tcnth] = tcnt >> 8; + + return avr_core_watch_read(avr, addr); +} + +static inline void +avr_timer_cancel_all_cycle_timers( + struct avr_t * avr, + avr_timer_t *timer, + const uint8_t clear_timers) +{ + if(clear_timers) { + for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++) + timer->comp[compi].comp_cycles = 0; + timer->tov_cycles = 0; + } + + + avr_cycle_timer_cancel(avr, avr_timer_tov, timer); + avr_cycle_timer_cancel(avr, avr_timer_compa, timer); + avr_cycle_timer_cancel(avr, avr_timer_compb, timer); + avr_cycle_timer_cancel(avr, avr_timer_compc, timer); +} + +static void +avr_timer_tcnt_write( + struct avr_t * avr, + avr_io_addr_t addr, + uint8_t v, + void * param) +{ + avr_timer_t * p = (avr_timer_t *)param; + avr_core_watch_write(avr, addr, v); + uint16_t tcnt = _timer_get_tcnt(p); + + if (!p->tov_top) + return; + + if (tcnt >= p->tov_top) + tcnt = 0; + + if (!(p->ext_clock_flags & (AVR_TIMER_EXTCLK_FLAG_TN | AVR_TIMER_EXTCLK_FLAG_AS2)) || + (p->ext_clock_flags & AVR_TIMER_EXTCLK_FLAG_VIRT) + ) { + // internal or virtual clock + + // this involves some magicking + // cancel the current timers, recalculate the "base" we should be at, reset the + // timer base as it should, and re-schedule the timers using that base. + + avr_timer_cancel_all_cycle_timers(avr, p, 0); + + uint64_t cycles = (tcnt * p->tov_cycles) / p->tov_top; + + // printf("%s-%c %d/%d -- cycles %d/%d\n", __FUNCTION__, p->name, tcnt, p->tov_top, (uint32_t)cycles, (uint32_t)p->tov_cycles); + + // this reset the timers bases to the new base + if (p->tov_cycles > 1) { + avr_cycle_timer_register(avr, p->tov_cycles - cycles, avr_timer_tov, p); + p->tov_base = 0; + avr_timer_tov(avr, avr->cycle - cycles, p); + } + + // tcnt = ((avr->cycle - p->tov_base) * p->tov_top) / p->tov_cycles; + // printf("%s-%c new tnt derive to %d\n", __FUNCTION__, p->name, tcnt); + } + else { + // clocked externally + p->tov_base = tcnt; + } +} + +static void +avr_timer_configure( + avr_timer_t * p, + uint32_t prescaler, + uint32_t top, + uint8_t reset) +{ + p->tov_top = top; + + avr_t * avr = p->io.avr; + float resulting_clock = 0.0f; // used only for trace + float tov_cycles_exact = 0; + + uint8_t as2 = p->ext_clock_flags & AVR_TIMER_EXTCLK_FLAG_AS2; + uint8_t use_ext_clock = as2 || (p->ext_clock_flags & AVR_TIMER_EXTCLK_FLAG_TN); + uint8_t virt_ext_clock = use_ext_clock && (p->ext_clock_flags & AVR_TIMER_EXTCLK_FLAG_VIRT); + + if (!use_ext_clock) { + if (prescaler != 0) + resulting_clock = (float)avr->frequency / prescaler; + p->tov_cycles = prescaler * (top+1); + p->tov_cycles_fract = 0.0f; + tov_cycles_exact = p->tov_cycles; + } else { + if (!virt_ext_clock) { + p->tov_cycles = 0; + p->tov_cycles_fract = 0.0f; + } else { + if (prescaler != 0) + resulting_clock = p->ext_clock / prescaler; + tov_cycles_exact = (float)avr->frequency / p->ext_clock * prescaler * (top+1); + // p->tov_cycles = round(tov_cycles_exact); -- don't want libm! + p->tov_cycles = tov_cycles_exact + .5f; // Round to integer + p->tov_cycles_fract = tov_cycles_exact - p->tov_cycles; + } + } + + if (p->trace) { + if (!use_ext_clock || virt_ext_clock) { + // clocked internally + AVR_LOG(avr, LOG_TRACE, "TIMER: %s-%c TOP %.2fHz = %d cycles = %dusec\n", // TOP there means Timer Overflows Persec ? + __FUNCTION__, p->name, ((float)avr->frequency / tov_cycles_exact), + (int)p->tov_cycles, (int)avr_cycles_to_usec(avr, p->tov_cycles)); + } else { + // clocked externally from the Tn pin + AVR_LOG(avr, LOG_TRACE, "TIMER: %s-%c use ext clock, TOP=%d\n", + __FUNCTION__, p->name, (int)p->tov_top + ); + } + } + + for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++) { + if (!p->comp[compi].r_ocr) + continue; + uint32_t ocr = _timer_get_ocr(p, compi); + //uint32_t comp_cycles = clock * (ocr + 1); + uint32_t comp_cycles; + if (virt_ext_clock) + comp_cycles = (uint32_t)((float)avr->frequency / p->ext_clock * prescaler * (ocr+1)); + else + comp_cycles = prescaler * (ocr + 1); + + p->comp[compi].comp_cycles = 0; + + if (p->trace & (avr_timer_trace_compa << compi)) { + if (!use_ext_clock || virt_ext_clock) { + printf("%s-%c clock %f top %d OCR%c %d\n", __FUNCTION__, p->name, + resulting_clock, top, 'A'+compi, ocr); + } else { + AVR_LOG(avr, LOG_TRACE, "%s timer%c clock via ext pin, TOP=%d OCR%c=%d\n", + __FUNCTION__, p->name, top, 'A'+compi, ocr); + } + } + if (ocr <= top) { + p->comp[compi].comp_cycles = comp_cycles; + + if (p->trace & (avr_timer_trace_compa << compi)) printf( + "TIMER: %s-%c %c %.2fHz = %d cycles\n", + __FUNCTION__, p->name, + 'A'+compi, resulting_clock / (ocr+1), + (int)comp_cycles); + } + } + + if (!use_ext_clock || virt_ext_clock) { + if (p->tov_cycles > 1) { + if (reset) { + avr_cycle_timer_register(avr, p->tov_cycles, avr_timer_tov, p); + // calling it once, with when == 0 tells it to arm the A/B/C timers if needed + p->tov_base = 0; + avr_timer_tov(avr, avr->cycle, p); + p->phase_accumulator = 0.0f; + } else { + uint64_t orig_tov_base = p->tov_base; + avr_cycle_timer_register(avr, p->tov_cycles - (avr->cycle - orig_tov_base), avr_timer_tov, p); + // calling it once, with when == 0 tells it to arm the A/B/C timers if needed + p->tov_base = 0; + avr_timer_tov(avr, orig_tov_base, p); + } + } + } else { + if (reset) + p->tov_base = 0; + } + + if (reset) { + avr_ioport_getirq_t req = { + .bit = p->ext_clock_pin + }; + if (avr_ioctl(p->io.avr, AVR_IOCTL_IOPORT_GETIRQ_REGBIT, &req) > 0) { + // got an IRQ for the Tn input clock pin + if (use_ext_clock && !virt_ext_clock) { + if (p->trace) + AVR_LOG(p->io.avr, LOG_TRACE, "%s: timer%c connecting T%c pin IRQ %d\n", __FUNCTION__, p->name, p->name, req.irq[0]->irq); + avr_irq_register_notify(req.irq[0], avr_timer_irq_ext_clock, p); + } else { + if (p->trace) + AVR_LOG(p->io.avr, LOG_TRACE, "%s: timer%c disconnecting T%c pin IRQ %d\n", __FUNCTION__, p->name, p->name, req.irq[0]->irq); + avr_irq_unregister_notify(req.irq[0], avr_timer_irq_ext_clock, p); + } + } + } + +} + +static void +avr_timer_reconfigure( + avr_timer_t * p, uint8_t reset) +{ + avr_t * avr = p->io.avr; + + // cancel everything + avr_timer_cancel_all_cycle_timers(avr, p, 1); + + switch (p->wgm_op_mode_kind) { + case avr_timer_wgm_normal: + avr_timer_configure(p, p->cs_div_value, p->wgm_op_mode_size, reset); + break; + case avr_timer_wgm_fc_pwm: + avr_timer_configure(p, p->cs_div_value, p->wgm_op_mode_size, reset); + break; + case avr_timer_wgm_ctc: { + avr_timer_configure(p, p->cs_div_value, _timer_get_ocr(p, AVR_TIMER_COMPA), reset); + } break; + case avr_timer_wgm_pwm: { + uint16_t top = (p->mode.top == avr_timer_wgm_reg_ocra) ? + _timer_get_ocr(p, AVR_TIMER_COMPA) : _timer_get_icr(p); + avr_timer_configure(p, p->cs_div_value, top, reset); + } break; + case avr_timer_wgm_fast_pwm: { + uint16_t top = + (p->mode.top == avr_timer_wgm_reg_icr) ? _timer_get_icr(p) : + p->wgm_op_mode_size; + avr_timer_configure(p, p->cs_div_value, top, reset); + } break; + case avr_timer_wgm_none: + avr_timer_configure(p, p->cs_div_value, p->wgm_op_mode_size, reset); + break; + default: { + uint8_t mode = avr_regbit_get_array(avr, p->wgm, ARRAY_SIZE(p->wgm)); + AVR_LOG(avr, LOG_WARNING, "TIMER: %s-%c unsupported timer mode wgm=%d (%d)\n", + __FUNCTION__, p->name, mode, p->mode.kind); + } + } +} + +static void +avr_timer_write_ocr( + struct avr_t * avr, + avr_io_addr_t addr, + uint8_t v, + void * param) +{ + avr_timer_comp_p comp = (avr_timer_comp_p)param; + avr_timer_t *timer = comp->timer; + uint16_t oldv; + + /* check to see if the OCR values actually changed */ + oldv = _timer_get_comp_ocr(avr, comp); + avr_core_watch_write(avr, addr, v); + + switch (timer->wgm_op_mode_kind) { + case avr_timer_wgm_normal: + avr_timer_reconfigure(timer, 0); + break; + case avr_timer_wgm_fc_pwm: // OCR is not used here + avr_timer_reconfigure(timer, 0); + break; + case avr_timer_wgm_ctc: + avr_timer_reconfigure(timer, 0); + break; + case avr_timer_wgm_pwm: + if (timer->mode.top != avr_timer_wgm_reg_ocra) { + avr_raise_irq(timer->io.irq + TIMER_IRQ_OUT_PWM0, _timer_get_ocr(timer, AVR_TIMER_COMPA)); + } else { + avr_timer_reconfigure(timer, 0); // if OCRA is the top, reconfigure needed + } + avr_raise_irq(timer->io.irq + TIMER_IRQ_OUT_PWM1, _timer_get_ocr(timer, AVR_TIMER_COMPB)); + if (sizeof(timer->comp)>2) + avr_raise_irq(timer->io.irq + TIMER_IRQ_OUT_PWM2, _timer_get_ocr(timer, AVR_TIMER_COMPC)); + break; + case avr_timer_wgm_fast_pwm: + if (oldv != _timer_get_comp_ocr(avr, comp)) + avr_timer_reconfigure(timer, 0); + avr_raise_irq(timer->io.irq + TIMER_IRQ_OUT_PWM0, + _timer_get_ocr(timer, AVR_TIMER_COMPA)); + avr_raise_irq(timer->io.irq + TIMER_IRQ_OUT_PWM1, + _timer_get_ocr(timer, AVR_TIMER_COMPB)); + if (sizeof(timer->comp)>2) + avr_raise_irq(timer->io.irq + TIMER_IRQ_OUT_PWM2, + _timer_get_ocr(timer, AVR_TIMER_COMPC)); + break; + default: + AVR_LOG(avr, LOG_WARNING, "TIMER: %s-%c mode %d UNSUPPORTED\n", + __FUNCTION__, timer->name, timer->mode.kind); + avr_timer_reconfigure(timer, 0); + break; + } +} + +static void +avr_timer_write( + struct avr_t * avr, + avr_io_addr_t addr, + uint8_t v, + void * param) +{ + avr_timer_t * p = (avr_timer_t *)param; + + uint8_t as2 = avr_regbit_get(avr, p->as2); + uint8_t cs = avr_regbit_get_array(avr, p->cs, ARRAY_SIZE(p->cs)); + uint8_t mode = avr_regbit_get_array(avr, p->wgm, ARRAY_SIZE(p->wgm)); + + avr_core_watch_write(avr, addr, v); + + uint8_t new_as2 = avr_regbit_get(avr, p->as2); + uint8_t new_cs = avr_regbit_get_array(avr, p->cs, ARRAY_SIZE(p->cs)); + uint8_t new_mode = avr_regbit_get_array(avr, p->wgm, ARRAY_SIZE(p->wgm)); + + // only reconfigure the timer if "relevant" bits have changed + // this prevent the timer reset when changing the edge detector + // or other minor bits + if (new_cs != cs || new_mode != mode || new_as2 != as2) { + /* cs */ + if (new_cs == 0) { + p->cs_div_value = 0; // reset prescaler + // cancel everything + avr_timer_cancel_all_cycle_timers(avr, p, 1); + + AVR_LOG(avr, LOG_TRACE, "TIMER: %s-%c clock turned off\n", + __func__, p->name); + return; + } + + p->ext_clock_flags &= ~(AVR_TIMER_EXTCLK_FLAG_TN | AVR_TIMER_EXTCLK_FLAG_EDGE + | AVR_TIMER_EXTCLK_FLAG_AS2 | AVR_TIMER_EXTCLK_FLAG_STARTED); + if (p->ext_clock_pin.reg + && (p->cs_div[new_cs] == AVR_TIMER_EXTCLK_CHOOSE)) { + // Special case: external clock source chosen, prescale divider irrelevant. + p->cs_div_value = 1; + p->ext_clock_flags |= AVR_TIMER_EXTCLK_FLAG_TN | (new_cs & AVR_TIMER_EXTCLK_FLAG_EDGE); + } else { + p->cs_div_value = 1 << p->cs_div[new_cs]; + if (new_as2) { + //p->cs_div_value = (uint32_t)((uint64_t)avr->frequency * (1 << p->cs_div[new_cs]) / 32768); + p->ext_clock_flags |= AVR_TIMER_EXTCLK_FLAG_AS2 | AVR_TIMER_EXTCLK_FLAG_EDGE; + } + } + + /* mode */ + p->mode = p->wgm_op[new_mode]; + p->wgm_op_mode_kind = p->mode.kind; + p->wgm_op_mode_size = (1 << p->mode.size) - 1; + + avr_timer_reconfigure(p, 1); + } +} + +/* + * write to the "force output compare" bits + */ +static void avr_timer_write_foc(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) +{ + avr_timer_t * p = (avr_timer_t *)param; + + /* These are strobe writes, so just decode them, don't store them */ + + for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++) { + if ((addr == p->comp[compi].foc.reg) && + (v & (1 << p->comp[compi].foc.bit))) { + avr_timer_comp(p, avr->cycle, compi, 0); + } + } +} + +/* + * write to the TIFR register. Watch for code that writes "1" to clear + * pending interrupts. + */ +static void +avr_timer_write_pending( + struct avr_t * avr, + avr_io_addr_t addr, + uint8_t v, + void * param) +{ + avr_timer_t * p = (avr_timer_t *)param; + + // All bits in this register are assumed to be write-1-to-clear. + + if (addr == p->overflow.raised.reg && + avr_regbit_from_value(avr, p->overflow.raised, v)) { + avr_clear_interrupt(avr, &p->overflow); + } + if (addr == p->icr.raised.reg && + avr_regbit_from_value(avr, p->icr.raised, v)) { + avr_clear_interrupt(avr, &p->icr); + } + + for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++) { + if (addr == p->comp[compi].interrupt.raised.reg && + avr_regbit_from_value(avr, p->comp[compi].interrupt.raised, + v)) { + avr_clear_interrupt(avr, &p->comp[compi].interrupt); + } + } +} + +static void +avr_timer_irq_icp( + struct avr_irq_t * irq, + uint32_t value, + void * param) +{ + avr_timer_t * p = (avr_timer_t *)param; + avr_t * avr = p->io.avr; + + // input capture disabled when ICR is used as top + if (p->mode.top == avr_timer_wgm_reg_icr) + return; + int bing = 0; + if (avr_regbit_get(avr, p->ices)) { // rising edge + if (!irq->value && value) + bing++; + } else { // default, falling edge + if (irq->value && !value) + bing++; + } + if (!bing) + return; + // get current TCNT, copy it to ICR, and raise interrupt + uint16_t tcnt = _avr_timer_get_current_tcnt(p); + avr->data[p->r_icr] = tcnt; + if (p->r_icrh) + avr->data[p->r_icrh] = tcnt >> 8; + avr_raise_interrupt(avr, &p->icr); +} + +static int +avr_timer_ioctl( + avr_io_t * port, + uint32_t ctl, + void * io_param) +{ + avr_timer_t * p = (avr_timer_t *)port; + int res = -1; + + if (ctl == AVR_IOCTL_TIMER_SET_TRACE(p->name)) { + /* Allow setting individual trace flags */ + p->trace = *((uint32_t*)io_param); + res = 0; + } else if (ctl == AVR_IOCTL_TIMER_SET_FREQCLK(p->name)) { + float new_freq = *((float*)io_param); + if (new_freq >= 0.0f) { + if (p->as2.reg) { + if (new_freq <= port->avr->frequency/4) { + p->ext_clock = new_freq; + res = 0; + } + } else if (p->ext_clock_pin.reg) { + if (new_freq <= port->avr->frequency/2) { + p->ext_clock = new_freq; + res = 0; + } + } + } + } else if (ctl == AVR_IOCTL_TIMER_SET_VIRTCLK(p->name)) { + uint8_t new_val = *((uint8_t*)io_param); + if (!new_val) { + avr_ioport_getirq_t req_timer_clock_pin = { + .bit = p->ext_clock_pin + }; + if (avr_ioctl(p->io.avr, AVR_IOCTL_IOPORT_GETIRQ_REGBIT, &req_timer_clock_pin) > 0) { + p->ext_clock_flags &= ~AVR_TIMER_EXTCLK_FLAG_VIRT; + res = 0; + } + } else { + p->ext_clock_flags |= AVR_TIMER_EXTCLK_FLAG_VIRT; + res = 0; + } + } + if (res >= 0) + avr_timer_reconfigure(p, 0); // virtual clock: attempt to follow frequency change preserving the phase + return res; +} + +static void +avr_timer_reset( + avr_io_t * port) +{ + avr_timer_t * p = (avr_timer_t *)port; + avr_timer_cancel_all_cycle_timers(p->io.avr, p, 0); + + // check to see if the comparators have a pin output. If they do, + // (try) to get the ioport corresponding IRQ and connect them + // they will automagically be triggered when the comparator raises + // it's own IRQ + for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++) { + p->comp[compi].comp_cycles = 0; + + avr_ioport_getirq_t req = { + .bit = p->comp[compi].com_pin + }; + if (avr_ioctl(port->avr, AVR_IOCTL_IOPORT_GETIRQ_REGBIT, &req) > 0) { + // cool, got an IRQ + //printf("%s-%c COMP%c Connecting PIN IRQ %d\n", + // __func__, p->name, 'A'+compi, req.irq[0]->irq); + avr_connect_irq(&port->irq[TIMER_IRQ_OUT_COMP + compi], req.irq[0]); + } + } + + avr_irq_register_notify(port->irq + TIMER_IRQ_IN_ICP, avr_timer_irq_icp, p); + + avr_ioport_getirq_t req = { + .bit = p->icp + }; + if (avr_ioctl(port->avr, AVR_IOCTL_IOPORT_GETIRQ_REGBIT, &req) > 0) { + // cool, got an IRQ for the input capture pin + //printf("%s-%c ICP Connecting PIN IRQ %d\n", __func__, p->name, req.irq[0]->irq); + avr_connect_irq(req.irq[0], port->irq + TIMER_IRQ_IN_ICP); + } + p->ext_clock_flags &= ~(AVR_TIMER_EXTCLK_FLAG_STARTED | AVR_TIMER_EXTCLK_FLAG_TN | + AVR_TIMER_EXTCLK_FLAG_AS2 | AVR_TIMER_EXTCLK_FLAG_REVDIR); + +} + +static const char * irq_names[TIMER_IRQ_COUNT] = { + [TIMER_IRQ_OUT_PWM0] = "8>pwm0", + [TIMER_IRQ_OUT_PWM1] = "8>pwm1", + [TIMER_IRQ_OUT_PWM2] = "8>pwm2", + [TIMER_IRQ_IN_ICP] = "io = _io; + + avr_register_io(avr, &p->io); + avr_register_vector(avr, &p->overflow); + avr_register_vector(avr, &p->icr); + + // allocate this module's IRQ + avr_io_setirqs(&p->io, AVR_IOCTL_TIMER_GETIRQ(p->name), TIMER_IRQ_COUNT, NULL); + + // marking IRQs as "filtered" means they don't propagate if the + // new value raised is the same as the last one.. in the case of the + // pwm value it makes sense not to bother. + p->io.irq[TIMER_IRQ_OUT_PWM0].flags |= IRQ_FLAG_FILTERED; + p->io.irq[TIMER_IRQ_OUT_PWM1].flags |= IRQ_FLAG_FILTERED; + p->io.irq[TIMER_IRQ_OUT_PWM2].flags |= IRQ_FLAG_FILTERED; + + if (p->wgm[0].reg) // these are not present on older AVRs + avr_register_io_write(avr, p->wgm[0].reg, avr_timer_write, p); + if (p->wgm[1].reg && + (p->wgm[1].reg != p->wgm[0].reg)) + avr_register_io_write(avr, p->wgm[1].reg, avr_timer_write, p); + if (p->wgm[2].reg && + (p->wgm[2].reg != p->wgm[0].reg) && + (p->wgm[2].reg != p->wgm[1].reg)) + avr_register_io_write(avr, p->wgm[2].reg, avr_timer_write, p); + if (p->wgm[3].reg && + (p->wgm[3].reg != p->wgm[0].reg) && + (p->wgm[3].reg != p->wgm[1].reg) && + (p->wgm[3].reg != p->wgm[2].reg)) + avr_register_io_write(avr, p->wgm[3].reg, avr_timer_write, p); + + avr_register_io_write(avr, p->cs[0].reg, avr_timer_write, p); + if (p->cs[1].reg && + (p->cs[1].reg != p->cs[0].reg)) + avr_register_io_write(avr, p->cs[1].reg, avr_timer_write, p); + if (p->cs[2].reg && + (p->cs[2].reg != p->cs[0].reg) && (p->cs[2].reg != p->cs[1].reg)) + avr_register_io_write(avr, p->cs[2].reg, avr_timer_write, p); + if (p->cs[3].reg && + (p->cs[3].reg != p->cs[0].reg) && + (p->cs[3].reg != p->cs[1].reg) && + (p->cs[3].reg != p->cs[2].reg)) + avr_register_io_write(avr, p->cs[3].reg, avr_timer_write, p); + + if (p->as2.reg) // as2 signifies timer/counter 2... therefore must check for register. + avr_register_io_write(avr, p->as2.reg, avr_timer_write, p); + + // this assumes all the "pending" interrupt bits are in the same + // register. Might not be true on all devices ? + avr_register_io_write(avr, p->overflow.raised.reg, avr_timer_write_pending, p); + + /* + * Even if the timer is 16 bits, we don't care to have watches on the + * high bytes because the datasheet says that the low address is always + * the trigger. + */ + for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++) { + p->comp[compi].timer = p; + + avr_register_vector(avr, &p->comp[compi].interrupt); + + if (p->comp[compi].r_ocr) // not all timers have all comparators + avr_register_io_write(avr, p->comp[compi].r_ocr, avr_timer_write_ocr, &p->comp[compi]); + if (p->comp[compi].foc.reg) + avr_register_io_write(avr, p->comp[compi].foc.reg, avr_timer_write_foc, p); + } + avr_register_io_write(avr, p->r_tcnt, avr_timer_tcnt_write, p); + avr_register_io_read(avr, p->r_tcnt, avr_timer_tcnt_read, p); + + if (p->as2.reg) { + p->ext_clock_flags = AVR_TIMER_EXTCLK_FLAG_VIRT; + p->ext_clock = 32768.0f; + } else { + p->ext_clock_flags = 0; + p->ext_clock = 0.0f; + } +} diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_timer.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_timer.h new file mode 100644 index 0000000..837936c --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_timer.h @@ -0,0 +1,176 @@ +/* + avr_timer.h + + Copyright 2008, 2009 Michel Pollet + + 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 . + */ + +#ifndef __AVR_TIMER_H__ +#define __AVR_TIMER_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "sim_avr.h" + +enum { + AVR_TIMER_COMPA = 0, + AVR_TIMER_COMPB, + AVR_TIMER_COMPC, + + AVR_TIMER_COMP_COUNT +}; + +enum { + TIMER_IRQ_OUT_PWM0 = 0, + TIMER_IRQ_OUT_PWM1, + TIMER_IRQ_OUT_PWM2, + TIMER_IRQ_IN_ICP, // input capture + TIMER_IRQ_OUT_COMP, // comparator pins output IRQ + + TIMER_IRQ_COUNT = TIMER_IRQ_OUT_COMP + AVR_TIMER_COMP_COUNT +}; + +// Get the internal IRQ corresponding to the INT +#define AVR_IOCTL_TIMER_GETIRQ(_name) AVR_IOCTL_DEF('t','m','r',(_name)) + +// add timer number/name (character) to set tracing flags +#define AVR_IOCTL_TIMER_SET_TRACE(_number) AVR_IOCTL_DEF('t','m','t',(_number)) +// enforce using virtual clock generator when external clock is chosen by firmware +#define AVR_IOCTL_TIMER_SET_VIRTCLK(_number) AVR_IOCTL_DEF('t','m','v',(_number)) +// set frequency of the virtual clock generator +#define AVR_IOCTL_TIMER_SET_FREQCLK(_number) AVR_IOCTL_DEF('t','m','f',(_number)) + +// Waveform generation modes +enum { + avr_timer_wgm_none = 0, // invalid mode + avr_timer_wgm_normal, + avr_timer_wgm_ctc, + avr_timer_wgm_pwm, + avr_timer_wgm_fast_pwm, + avr_timer_wgm_fc_pwm, +}; + +// Compare output modes +enum { + avr_timer_com_normal = 0,// Normal mode, OCnx disconnected + avr_timer_com_toggle, // Toggle OCnx on compare match + avr_timer_com_clear, // clear OCnx on compare match + avr_timer_com_set, // set OCnx on compare match + +}; + +enum { + avr_timer_wgm_reg_constant = 0, + avr_timer_wgm_reg_ocra, + avr_timer_wgm_reg_icr, +}; + +typedef struct avr_timer_wgm_t { + uint32_t top: 8, bottom: 8, size : 8, kind : 8; +} avr_timer_wgm_t; + +#define AVR_TIMER_EXTCLK_CHOOSE 0x80 // marker value for cs_div specifying ext clock selection +#define AVR_TIMER_EXTCLK_FLAG_TN 0x80 // Tn external clock chosen +#define AVR_TIMER_EXTCLK_FLAG_STARTED 0x40 // peripheral started +#define AVR_TIMER_EXTCLK_FLAG_REVDIR 0x20 // reverse counting (decrement) +#define AVR_TIMER_EXTCLK_FLAG_AS2 0x10 // asynchronous external clock chosen +#define AVR_TIMER_EXTCLK_FLAG_VIRT 0x08 // don't use the input pin, generate clock internally +#define AVR_TIMER_EXTCLK_FLAG_EDGE 0x01 // use the rising edge + +#define AVR_TIMER_WGM_NORMAL8() { .kind = avr_timer_wgm_normal, .size=8 } +#define AVR_TIMER_WGM_NORMAL16() { .kind = avr_timer_wgm_normal, .size=16 } +#define AVR_TIMER_WGM_CTC() { .kind = avr_timer_wgm_ctc, .top = avr_timer_wgm_reg_ocra } +#define AVR_TIMER_WGM_ICCTC() { .kind = avr_timer_wgm_ctc, .top = avr_timer_wgm_reg_icr } +#define AVR_TIMER_WGM_FASTPWM8() { .kind = avr_timer_wgm_fast_pwm, .size=8 } +#define AVR_TIMER_WGM_FASTPWM9() { .kind = avr_timer_wgm_fast_pwm, .size=9 } +#define AVR_TIMER_WGM_FASTPWM10() { .kind = avr_timer_wgm_fast_pwm, .size=10 } +#define AVR_TIMER_WGM_FCPWM8() { .kind = avr_timer_wgm_fc_pwm, .size=8 } +#define AVR_TIMER_WGM_FCPWM9() { .kind = avr_timer_wgm_fc_pwm, .size=9 } +#define AVR_TIMER_WGM_FCPWM10() { .kind = avr_timer_wgm_fc_pwm, .size=10 } +#define AVR_TIMER_WGM_OCPWM() { .kind = avr_timer_wgm_pwm, .top = avr_timer_wgm_reg_ocra } +#define AVR_TIMER_WGM_ICPWM() { .kind = avr_timer_wgm_pwm, .top = avr_timer_wgm_reg_icr } +#define AVR_TIMER_WGM_ICFASTPWM() { .kind = avr_timer_wgm_fast_pwm, .top = avr_timer_wgm_reg_icr } + +typedef struct avr_timer_comp_t { + avr_int_vector_t interrupt; // interrupt vector + struct avr_timer_t *timer; // parent timer + avr_io_addr_t r_ocr; // comparator register low byte + avr_io_addr_t r_ocrh; // comparator register hi byte + avr_regbit_t com; // comparator output mode registers + avr_regbit_t com_pin; // where comparator output is connected + uint64_t comp_cycles; + avr_regbit_t foc; // "force compare match" strobe +} avr_timer_comp_t, *avr_timer_comp_p; + +enum { + avr_timer_trace_ocr = (1 << 0), + avr_timer_trace_tcnt = (1 << 1), + + avr_timer_trace_compa = (1 << 8), + avr_timer_trace_compb = (1 << 9), + avr_timer_trace_compc = (1 << 10), +}; + +typedef struct avr_timer_t { + avr_io_t io; + char name; + uint32_t trace; // debug trace + + avr_regbit_t disabled; // bit in the PRR + + avr_io_addr_t r_tcnt, r_icr; + avr_io_addr_t r_tcnth, r_icrh; + + avr_regbit_t wgm[4]; + avr_timer_wgm_t wgm_op[16]; + avr_timer_wgm_t mode; + int wgm_op_mode_kind; + uint32_t wgm_op_mode_size; + + avr_regbit_t as2; // asynchronous clock 32khz + avr_regbit_t cs[4]; // specify control register bits choosing clock sourcre + uint8_t cs_div[16]; // translate control register value to clock prescaler (orders of 2 exponent) + uint32_t cs_div_value; + + avr_regbit_t ext_clock_pin; // external clock input pin, to link IRQs + uint8_t ext_clock_flags; // holds AVR_TIMER_EXTCLK_FLAG_ON, AVR_TIMER_EXTCLK_FLAG_EDGE and other ext. clock mode flags + float ext_clock; // external clock frequency, e.g. 32768Hz + + avr_regbit_t icp; // input capture pin, to link IRQs + avr_regbit_t ices; // input capture edge select + + avr_timer_comp_t comp[AVR_TIMER_COMP_COUNT]; + + avr_int_vector_t overflow; // overflow + avr_int_vector_t icr; // input capture + + uint64_t tov_cycles; // number of cycles from zero to overflow + float tov_cycles_fract; // fractional part for external clock with non int ratio to F_CPU + float phase_accumulator; + uint64_t tov_base; // MCU cycle when the last overflow occured; when clocked externally holds external clock count + uint16_t tov_top; // current top value to calculate tnct +} avr_timer_t; + +void avr_timer_init(avr_t * avr, avr_timer_t * port); + +#ifdef __cplusplus +}; +#endif + +#endif /*__AVR_TIMER_H__*/ diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_twi.c b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_twi.c new file mode 100644 index 0000000..521c03c --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_twi.c @@ -0,0 +1,521 @@ +/* + avr_twi.c + + Copyright 2008, 2009 Michel Pollet + + 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 "avr_twi.h" + +/* + * This block respectfully nicked straight out from the Atmel sample + * code for AVR315. Typos and all. + * There is no copyright notice on the original file. + */ +/**************************************************************************** + TWI State codes +****************************************************************************/ +// General TWI Master status codes +#define TWI_START 0x08 // START has been transmitted +#define TWI_REP_START 0x10 // Repeated START has been transmitted +#define TWI_ARB_LOST 0x38 // Arbitration lost + +// TWI Master Transmitter status codes +#define TWI_MTX_ADR_ACK 0x18 // SLA+W has been transmitted and ACK received +#define TWI_MTX_ADR_NACK 0x20 // SLA+W has been transmitted and NACK received +#define TWI_MTX_DATA_ACK 0x28 // Data byte has been transmitted and ACK received +#define TWI_MTX_DATA_NACK 0x30 // Data byte has been transmitted and NACK received + +// TWI Master Receiver status codes +#define TWI_MRX_ADR_ACK 0x40 // SLA+R has been transmitted and ACK received +#define TWI_MRX_ADR_NACK 0x48 // SLA+R has been transmitted and NACK received +#define TWI_MRX_DATA_ACK 0x50 // Data byte has been received and ACK transmitted +#define TWI_MRX_DATA_NACK 0x58 // Data byte has been received and NACK transmitted + +// TWI Slave Transmitter status codes +#define TWI_STX_ADR_ACK 0xA8 // Own SLA+R has been received; ACK has been returned +#define TWI_STX_ADR_ACK_M_ARB_LOST 0xB0 // Arbitration lost in SLA+R/W as Master; own SLA+R has been received; ACK has been returned +#define TWI_STX_DATA_ACK 0xB8 // Data byte in TWDR has been transmitted; ACK has been received +#define TWI_STX_DATA_NACK 0xC0 // Data byte in TWDR has been transmitted; NOT ACK has been received +#define TWI_STX_DATA_ACK_LAST_BYTE 0xC8 // Last data byte in TWDR has been transmitted (TWEA = �0�); ACK has been received + +// TWI Slave Receiver status codes +#define TWI_SRX_ADR_ACK 0x60 // Own SLA+W has been received ACK has been returned +#define TWI_SRX_ADR_ACK_M_ARB_LOST 0x68 // Arbitration lost in SLA+R/W as Master; own SLA+W has been received; ACK has been returned +#define TWI_SRX_GEN_ACK 0x70 // General call address has been received; ACK has been returned +#define TWI_SRX_GEN_ACK_M_ARB_LOST 0x78 // Arbitration lost in SLA+R/W as Master; General call address has been received; ACK has been returned +#define TWI_SRX_ADR_DATA_ACK 0x80 // Previously addressed with own SLA+W; data has been received; ACK has been returned +#define TWI_SRX_ADR_DATA_NACK 0x88 // Previously addressed with own SLA+W; data has been received; NOT ACK has been returned +#define TWI_SRX_GEN_DATA_ACK 0x90 // Previously addressed with general call; data has been received; ACK has been returned +#define TWI_SRX_GEN_DATA_NACK 0x98 // Previously addressed with general call; data has been received; NOT ACK has been returned +#define TWI_SRX_STOP_RESTART 0xA0 // A STOP condition or repeated START condition has been received while still addressed as Slave + +// TWI Miscellaneous status codes +#define TWI_NO_STATE 0xF8 // No relevant state information available; TWINT = �0� +#define TWI_BUS_ERROR 0x00 // Bus error due to an illegal START or STOP condition + +#define AVR_TWI_DEBUG 1 + +static inline void +_avr_twi_status_set( + avr_twi_t * p, + uint8_t v, + int interrupt) +{ + avr_regbit_setto_raw(p->io.avr, p->twsr, v); +#if AVR_TWI_DEBUG + AVR_TRACE(p->io.avr, "%s %02x\n", __func__, v); +#endif + avr_raise_irq(p->io.irq + TWI_IRQ_STATUS, v); + if (interrupt) + avr_raise_interrupt(p->io.avr, &p->twi); +} + +static __attribute__ ((unused)) inline uint8_t +_avr_twi_status_get( + avr_twi_t * p) +{ + return avr_regbit_get_raw(p->io.avr, p->twsr); +} + +static avr_cycle_count_t +avr_twi_set_state_timer( + struct avr_t * avr, + avr_cycle_count_t when, + void * param) +{ + avr_twi_t * p = (avr_twi_t *)param; + _avr_twi_status_set(p, p->next_twstate, 1); + p->next_twstate = 0; + return 0; +} + +// Quick exponent helper for integer values > 0. +static uint32_t _avr_twi_quick_exp(uint8_t base, uint8_t exp) +{ + uint32_t result = 1; + for (uint8_t i=exp; i>0; i--) + result *= base; + return result; +} + +/* + * This is supposed to trigger a timer whose duration is a multiple + * of 'twi' clock cycles, which should be derived from the prescaler + * (100khz, 400khz etc). + * Right now it cheats and uses one twi cycle == one usec. + */ + +static void +_avr_twi_delay_state( + avr_twi_t * p, + int twi_cycles, + uint8_t state) +{ + p->next_twstate = state; + uint8_t prescale = avr_regbit_get(p->io.avr, p->twps); + uint16_t bitrate = p->io.avr->data[p->r_twbr]; + uint32_t clockdiv = 16u+((bitrate<<1u)*_avr_twi_quick_exp(4,prescale)); + //One TWI cycle is "clockdiv" AVR Cycles. So we can wait in these directly. + // printf("Waiting %d cycles\n",clockdiv*twi_cycles); + avr_cycle_timer_register( + p->io.avr, twi_cycles*clockdiv, avr_twi_set_state_timer, p); +} + +static void +avr_twi_write( + struct avr_t * avr, + avr_io_addr_t addr, + uint8_t v, + void * param) +{ + avr_twi_t * p = (avr_twi_t *)param; + + uint8_t twen = avr_regbit_get(avr, p->twen); + uint8_t twsta = avr_regbit_get(avr, p->twsta); + uint8_t twsto = avr_regbit_get(avr, p->twsto); + uint8_t twint = avr_regbit_get(avr, p->twi.raised); + + avr_core_watch_write(avr, addr, v); +#if AVR_TWI_DEBUG + AVR_TRACE(avr, "%s %02x START:%d STOP:%d ACK:%d INT:%d TWSR:%02x (state %02x)\n", + __func__, v, + avr_regbit_get(avr, p->twsta), + avr_regbit_get(avr, p->twsto), + avr_regbit_get(avr, p->twea), + avr_regbit_get(avr, p->twi.raised), + avr_regbit_get_raw(p->io.avr, p->twsr), p->state); +#endif + if (twen != avr_regbit_get(avr, p->twen)) { + twen = !twen; + if (!twen) { // if we were running, now now are not + avr_regbit_clear(avr, p->twea); + avr_regbit_clear(avr, p->twsta); + avr_regbit_clear(avr, p->twsto); + avr_clear_interrupt(avr, &p->twi); + avr_core_watch_write(avr, p->r_twdr, 0xff); + _avr_twi_status_set(p, TWI_NO_STATE, 0); + p->state = 0; + p->peer_addr = 0; + } + AVR_TRACE(avr, "TWEN: %d\n", twen); + if (avr->data[p->r_twar]) { + AVR_TRACE(avr, "TWEN Slave: %02x&%02x\n", avr->data[p->r_twar] >> 1, avr->data[p->r_twamr] >> 1); + p->state |= TWI_COND_SLAVE; + } + } + if (!twen) + return; + + uint8_t cleared = avr_regbit_get(avr, p->twi.raised); + + /*int cleared = */ + avr_clear_interrupt_if(avr, &p->twi, twint); +// AVR_TRACE(avr, "cleared %d\n", cleared); + + if (!twsto && avr_regbit_get(avr, p->twsto)) { + // generate a stop condition +#if AVR_TWI_DEBUG + AVR_TRACE(avr, "<<<<< I2C stop\n"); +#endif + if (p->state) { // doing stuff + if (p->state & TWI_COND_START) { + avr_raise_irq(p->io.irq + TWI_IRQ_OUTPUT, + avr_twi_irq_msg(TWI_COND_STOP, p->peer_addr, 1)); + } + } + /* clear stop condition regardless of status */ + avr_regbit_clear(avr, p->twsto); + _avr_twi_status_set(p, TWI_NO_STATE, 0); + p->state = 0; + } + if (!twsta && avr_regbit_get(avr, p->twsta)) { +#if AVR_TWI_DEBUG + AVR_TRACE(avr, ">>>>> I2C %sstart\n", p->state & TWI_COND_START ? "RE" : ""); +#endif + // generate a start condition + if (p->state & TWI_COND_START) + _avr_twi_delay_state(p, 0, TWI_REP_START); + else + _avr_twi_delay_state(p, 0, TWI_START); + p->peer_addr = 0; + p->state = TWI_COND_START; + } + + int data = cleared && + !avr_regbit_get(avr, p->twsta) && + !avr_regbit_get(avr, p->twsto); + + if (!data) + return; + + int do_read = p->peer_addr & 1; + int do_ack = avr_regbit_get(avr, p->twea) != 0; + + if (p->state & TWI_COND_SLAVE) { + // writing or reading a byte + if (p->state & TWI_COND_ADDR) { +#if AVR_TWI_DEBUG + if (do_read) + AVR_TRACE(avr, "I2C slave READ byte\n"); + else + AVR_TRACE(avr, "I2C slave WRITE byte\n"); +#endif + if (do_read) { + if (p->state & TWI_COND_WRITE) { + avr_raise_irq(p->io.irq + TWI_IRQ_OUTPUT, + avr_twi_irq_msg(TWI_COND_READ | TWI_COND_ACK, p->peer_addr, avr->data[p->r_twdr])); + } +#if AVR_TWI_DEBUG + else + AVR_TRACE(avr, "I2C latch is not ready, do nothing\n"); +#endif + } else { + avr_raise_irq(p->io.irq + TWI_IRQ_OUTPUT, + avr_twi_irq_msg(TWI_COND_ACK, p->peer_addr, 0)); + } + avr_raise_irq(p->io.irq + TWI_IRQ_OUTPUT, + avr_twi_irq_msg(TWI_COND_ADDR + (do_ack ? TWI_COND_ACK : 0), p->peer_addr, avr->data[p->r_twdr])); + } else { // address, acknowledge it + p->state |= TWI_COND_ADDR; + avr_raise_irq(p->io.irq + TWI_IRQ_OUTPUT, + avr_twi_irq_msg( + TWI_COND_ADDR | + (do_ack ? TWI_COND_ACK : 0) | + (p->state & TWI_COND_WRITE ? TWI_COND_READ : 0), + p->peer_addr, avr->data[p->r_twdr])); + } + } else { + + // writing or reading a byte + if (p->state & TWI_COND_ADDR) { +#if AVR_TWI_DEBUG + if (do_read) + AVR_TRACE(avr, "I2C READ byte from %02x\n", p->peer_addr); + else + AVR_TRACE(avr, "I2C WRITE byte %02x to %02x\n", avr->data[p->r_twdr], p->peer_addr); +#endif + // a normal data byte + uint8_t msgv = do_read ? TWI_COND_READ : TWI_COND_WRITE; + + if (do_ack) + msgv |= TWI_COND_ACK; + + p->state &= ~TWI_COND_ACK; // clear ACK bit + + AVR_TRACE(avr, "state %02x want %02x\n", p->state, msgv); + // if the latch is ready... as set by writing/reading the TWDR + if (p->state & msgv) { + + // we send an IRQ and we /expect/ a slave to reply + // immediately via an IRQ to set the COND_ACK bit + // otherwise it's assumed it's been nacked... + avr_raise_irq(p->io.irq + TWI_IRQ_OUTPUT, + avr_twi_irq_msg(msgv, p->peer_addr, avr->data[p->r_twdr])); + + if (do_read) { // read ? + _avr_twi_delay_state(p, 9, + msgv & TWI_COND_ACK ? + TWI_MRX_DATA_ACK : TWI_MRX_DATA_NACK); + } else { + _avr_twi_delay_state(p, 9, + p->state & TWI_COND_ACK ? + TWI_MTX_DATA_ACK : TWI_MTX_DATA_NACK); + } + } +#if AVR_TWI_DEBUG + else + AVR_TRACE(avr, "I2C latch is not ready, do nothing\n"); +#endif + } else if (p->state) { +#if AVR_TWI_DEBUG + AVR_TRACE(avr, "I2C Master address %02x\n", avr->data[p->r_twdr]); +#endif + // send the address + p->state |= TWI_COND_ADDR; + p->peer_addr = avr->data[p->r_twdr]; + p->state &= ~TWI_COND_ACK; // clear ACK bit + + // we send an IRQ and we /expect/ a slave to reply + // immediately via an IRQ tp set the COND_ACK bit + // otherwise it's assumed it's been nacked... + avr_raise_irq(p->io.irq + TWI_IRQ_OUTPUT, + avr_twi_irq_msg(TWI_COND_START, p->peer_addr, 0)); + + if (p->peer_addr & 1) { // read ? + p->state |= TWI_COND_READ; // always allow read to start with + _avr_twi_delay_state(p, 9, + p->state & TWI_COND_ACK ? + TWI_MRX_ADR_ACK : TWI_MRX_ADR_NACK); + } else { + if(p->state & TWI_COND_ADDR){ + _avr_twi_delay_state(p, 0, + p->state & TWI_COND_ACK ? + TWI_MTX_ADR_ACK : TWI_MTX_ADR_NACK); + }else{ + _avr_twi_delay_state(p, 9, + p->state & TWI_COND_ACK ? + TWI_MTX_DATA_ACK : TWI_MTX_DATA_NACK); + } + } + } + p->state &= ~TWI_COND_WRITE; + } +} + +/* + * Write data to the latch, tell the system we have something + * to send next + */ +static void +avr_twi_write_data( + struct avr_t * avr, + avr_io_addr_t addr, + uint8_t v, + void * param) +{ + avr_twi_t * p = (avr_twi_t *)param; + + avr_core_watch_write(avr, addr, v); + // tell system we have something in the write latch + p->state |= TWI_COND_WRITE; +} + +/* + * Read data from the latch, tell the system can receive a new byte + */ +static uint8_t +avr_twi_read_data( + struct avr_t * avr, + avr_io_addr_t addr, + void * param) +{ + avr_twi_t * p = (avr_twi_t *)param; + + // tell system we can receive another byte + p->state |= TWI_COND_READ; + return avr->data[p->r_twdr]; +} + +/* + * prevent code from rewriting out status bits, since we actually use them! + */ +static void +avr_twi_write_status( + struct avr_t * avr, + avr_io_addr_t addr, + uint8_t v, + void * param) +{ + avr_twi_t * p = (avr_twi_t *)param; + uint8_t sr = avr_regbit_get(avr, p->twsr); + uint8_t c = avr_regbit_get(avr, p->twps); + + avr_core_watch_write(avr, addr, v); + avr_regbit_setto(avr, p->twsr, sr); // force restore + + if (c != avr_regbit_get(avr, p->twps)) { + // prescaler bits changed... + } +} + +static void +avr_twi_irq_input( + struct avr_irq_t * irq, + uint32_t value, + void * param) +{ + avr_twi_t * p = (avr_twi_t *)param; + avr_t * avr = p->io.avr; + + // check to see if we are enabled + if (!avr_regbit_get(avr, p->twen)) + return; + avr_twi_msg_irq_t msg; + msg.u.v = value; + + AVR_TRACE(avr, "%s %08x\n", __func__, value); + + // receiving an attempt at waking a slave + if (msg.u.twi.msg & TWI_COND_START) { + p->state = 0; + p->peer_addr = 0; + if (msg.u.twi.msg & TWI_COND_ADDR) { + uint8_t mask = ~avr->data[p->r_twamr] >> 1; + AVR_TRACE(avr, "I2C slave start %2x (want %02x&%02x)\n", + msg.u.twi.addr, avr->data[p->r_twar] >> 1, mask); + p->peer_addr = msg.u.twi.addr & mask; + if (p->peer_addr == ((avr->data[p->r_twar] >> 1) & mask)) { + // address match, we're talking + p->state = TWI_COND_SLAVE; + // INVERSE logic here + if (!(msg.u.twi.msg & TWI_COND_WRITE)) + p->peer_addr |= 1; + _avr_twi_delay_state(p, 9, + msg.u.twi.msg & TWI_COND_WRITE ? + TWI_SRX_ADR_ACK : TWI_STX_ADR_ACK ); + } + } else { + // "general call" address + AVR_TRACE(avr, "I2C slave start without address?\n"); + if (avr->data[p->r_twar] & 1) { + // TODO + } + } + } + if (msg.u.twi.msg & TWI_COND_STOP) { + _avr_twi_delay_state(p, 9, + msg.u.twi.msg & TWI_COND_WRITE ? + TWI_SRX_ADR_ACK : TWI_STX_ADR_ACK ); + } + // receiving an acknowledge bit + if (msg.u.twi.msg & TWI_COND_ACK) { +#if AVR_TWI_DEBUG + AVR_TRACE(avr, "I2C received ACK:%d\n", msg.u.twi.data & 1); +#endif + if (msg.u.twi.data & 1) + p->state |= TWI_COND_ACK; + else + p->state &= ~TWI_COND_ACK; + } + if (p->state & TWI_COND_SLAVE) { + if (msg.u.twi.msg & TWI_COND_WRITE) { + avr->data[p->r_twdr] = msg.u.twi.data; + _avr_twi_delay_state(p, 9, TWI_SRX_ADR_DATA_ACK ); + } + } else { + // receive a data byte from a slave + if (msg.u.twi.msg & TWI_COND_READ) { +#if AVR_TWI_DEBUG + AVR_TRACE(avr, "I2C received %02x\n", msg.u.twi.data); +#endif + avr->data[p->r_twdr] = msg.u.twi.data; + } + } +} + +void avr_twi_reset(struct avr_io_t *io) +{ + avr_twi_t * p = (avr_twi_t *)io; + avr_irq_register_notify(p->io.irq + TWI_IRQ_INPUT, avr_twi_irq_input, p); + p->state = p->peer_addr = 0; + avr_regbit_setto_raw(p->io.avr, p->twsr, TWI_NO_STATE); +} + +static const char * irq_names[TWI_IRQ_COUNT] = { + [TWI_IRQ_INPUT] = "8io = _io; + avr_register_io(avr, &p->io); + avr_register_vector(avr, &p->twi); + + //printf("%s TWI%c init\n", __FUNCTION__, p->name); + + // allocate this module's IRQ + avr_io_setirqs(&p->io, AVR_IOCTL_TWI_GETIRQ(p->name), TWI_IRQ_COUNT, NULL); + + avr_register_io_write(avr, p->twen.reg, avr_twi_write, p); + avr_register_io_write(avr, p->r_twdr, avr_twi_write_data, p); + avr_register_io_read(avr, p->r_twdr, avr_twi_read_data, p); + avr_register_io_write(avr, p->twsr.reg, avr_twi_write_status, p); +} + +uint32_t +avr_twi_irq_msg( + uint8_t msg, + uint8_t addr, + uint8_t data) +{ + avr_twi_msg_irq_t _msg = { + .u.twi.msg = msg, + .u.twi.addr = addr, + .u.twi.data = data, + }; + return _msg.u.v; +} diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_twi.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_twi.h new file mode 100644 index 0000000..8b37ba3 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_twi.h @@ -0,0 +1,116 @@ +/* + avr_twi.h + + Copyright 2008, 2009 Michel Pollet + + 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 . + */ + +#ifndef __AVR_TWI_H__ +#define __AVR_TWI_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "sim_avr.h" + +//#include "sim_twi.h" + +enum { + TWI_IRQ_INPUT = 0, + TWI_IRQ_OUTPUT, + TWI_IRQ_STATUS, + TWI_IRQ_COUNT +}; + +enum { + TWI_COND_START = (1 << 0), + TWI_COND_STOP = (1 << 1), + TWI_COND_ADDR = (1 << 2), + TWI_COND_ACK = (1 << 3), + TWI_COND_WRITE = (1 << 4), + TWI_COND_READ = (1 << 5), + // internal state, do not use in irq messages + TWI_COND_SLAVE = (1 << 6), +}; + +typedef struct avr_twi_msg_t { + uint32_t unused : 8, + msg : 8, + addr : 8, + data : 8; +} avr_twi_msg_t; + +typedef struct avr_twi_msg_irq_t { + union { + uint32_t v; + avr_twi_msg_t twi; + } u; +} avr_twi_msg_irq_t; + +// add port number to get the real IRQ +#define AVR_IOCTL_TWI_GETIRQ(_name) AVR_IOCTL_DEF('t','w','i',(_name)) + +typedef struct avr_twi_t { + avr_io_t io; + char name; + + avr_regbit_t disabled; // bit in the PRR + + avr_io_addr_t r_twbr; // bit rate register + avr_io_addr_t r_twcr; // control register + avr_io_addr_t r_twsr; // status register + avr_io_addr_t r_twar; // address register (slave) + avr_io_addr_t r_twamr; // address mask register + avr_io_addr_t r_twdr; // data register + + avr_regbit_t twen; // twi enable bit + avr_regbit_t twea; // enable acknowledge bit + avr_regbit_t twsta; // start condition + avr_regbit_t twsto; // stop condition + avr_regbit_t twwc; // write collision + + avr_regbit_t twsr; // status registers, (5 bits) + avr_regbit_t twps; // prescaler bits (2 bits) + + avr_int_vector_t twi; // twi interrupt + + uint8_t state; + uint8_t peer_addr; + uint8_t next_twstate; +} avr_twi_t; + +void +avr_twi_init( + avr_t * avr, + avr_twi_t * port); + +/* + * Create a message value for twi including the 'msg' bitfield, + * 'addr' and data. This value is what is sent as the IRQ value + */ +uint32_t +avr_twi_irq_msg( + uint8_t msg, + uint8_t addr, + uint8_t data); + +#ifdef __cplusplus +}; +#endif + +#endif /*__AVR_TWI_H__*/ diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_uart.c b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_uart.c new file mode 100644 index 0000000..25b6fe6 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_uart.c @@ -0,0 +1,546 @@ +/* + avr_uart.c + + Handles UART access + Right now just handle "write" to the serial port at any speed + and printf to the console when '\n' is written. + + Copyright 2008, 2009 Michel Pollet + + 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 . + */ + +#ifdef NO_COLOR + #define FONT_GREEN + #define FONT_DEFAULT +#else + #define FONT_GREEN "\e[32m" + #define FONT_DEFAULT "\e[0m" +#endif + +#include +#include +#include +#include +#include "avr_uart.h" +#include "sim_hex.h" +#include "sim_time.h" +#include "sim_gdb.h" + +//#define TRACE(_w) _w +#ifndef TRACE +#define TRACE(_w) +#endif + +DEFINE_FIFO(uint16_t, uart_fifo); + +static inline void +avr_uart_clear_interrupt( + avr_t * avr, + avr_int_vector_t * vector) +{ + if (!vector->vector) + return; + // clear the interrupt flag even it's 'sticky' + if (avr_regbit_get(avr, vector->raised)) + avr_clear_interrupt_if(avr, vector, 0); + if (avr_regbit_get(avr, vector->raised)) + avr_regbit_clear(avr, vector->raised); +} + +static avr_cycle_count_t +avr_uart_txc_raise( + struct avr_t * avr, + avr_cycle_count_t when, + void * param) +{ + avr_uart_t * p = (avr_uart_t *)param; + if (p->tx_cnt) { + // Even if the interrupt is disabled, still raise the TXC flag + if (p->tx_cnt == 1) + avr_raise_interrupt(avr, &p->txc); + p->tx_cnt--; + } + if (p->udrc.vector) {// UDRE is disabled in the LIN mode + if (p->tx_cnt) { + if (avr_regbit_get(avr, p->udrc.raised)) { + avr_uart_clear_interrupt(avr, &p->udrc); + } + } else { + if (avr_regbit_get(avr, p->txen)) { + // Even if the interrupt is disabled, still raise the UDRE flag + avr_raise_interrupt(avr, &p->udrc); + if (!avr_regbit_get(avr, p->udrc.enable)) { + return 0; //polling mode: stop TX pump + } else // udrc (alias udre) should be rased repeatedly while output buffer is empty + return when + p->cycles_per_byte; + } else + return 0; // transfer disabled: stop TX pump + } + } + if (p->tx_cnt) + return when + p->cycles_per_byte; + return 0; // stop TX pump +} + +static avr_cycle_count_t +avr_uart_rxc_raise( + struct avr_t * avr, + avr_cycle_count_t when, + void * param) +{ + avr_uart_t * p = (avr_uart_t *)param; + if (avr_regbit_get(avr, p->rxen)) { + // rxc should be rased continiosly untill input buffer is empty + if (!uart_fifo_isempty(&p->input)) { + if (!avr_regbit_get(avr, p->rxc.raised)) { + p->rxc_raise_time = when; + p->rx_cnt = 0; + } + avr_raise_interrupt(avr, &p->rxc); + return when + p->cycles_per_byte; + } + } + return 0; +} + +static uint8_t +avr_uart_status_read( + struct avr_t * avr, + avr_io_addr_t addr, + void * param) +{ + avr_uart_t * p = (avr_uart_t *)param; + + if (addr == p->fe.reg) { + if (!uart_fifo_isempty(&p->input)) { + uint16_t d = uart_fifo_read_at(&p->input, 0); + + uint8_t st = avr->data[addr]; + + st &= ~(p->fe.mask << p->fe.bit); + if (d & UART_INPUT_FE) { + st |= p->fe.mask << p->fe.bit; + } + + avr->data[addr] = st; + } + } + + uint8_t v = avr_core_watch_read(avr, addr); + + if (addr == p->rxc.raised.reg) { + //static uint8_t old = 0xff; if (v != old) printf("UCSRA read %02x\n", v); old = v; + // + // if RX is enabled, and there is nothing to read, and + // the AVR core is reading this register, it's probably + // to poll the RXC TXC flag and spinloop + // so here we introduce a usleep to make it a bit lighter + // on CPU and let data arrive + // + uint8_t ri = !avr_regbit_get(avr, p->rxen) || !avr_regbit_get(avr, p->rxc.raised); + uint8_t ti = !avr_regbit_get(avr, p->txen) || !avr_regbit_get(avr, p->txc.raised); + + if (p->flags & AVR_UART_FLAG_POLL_SLEEP) { + + if (ri && ti) + usleep(1); + } + // if reception is idle and the fifo is empty, tell whomever there is room + if (avr_regbit_get(avr, p->rxen) && uart_fifo_isempty(&p->input)) { + avr_raise_irq(p->io.irq + UART_IRQ_OUT_XOFF, 0); + avr_raise_irq(p->io.irq + UART_IRQ_OUT_XON, 1); + } + } + + return v; +} + +static uint8_t +avr_uart_read( + struct avr_t * avr, + avr_io_addr_t addr, + void * param) +{ + avr_uart_t * p = (avr_uart_t *)param; + uint8_t v = 0; + + if (!avr_regbit_get(avr, p->rxen) || + !avr_regbit_get(avr, p->rxc.raised) // rxc flag not raised - nothing to read! + ) { + AVR_LOG(avr, LOG_TRACE, "UART%c: attempt to read empty rx buffer\n", p->name); + avr->data[addr] = 0; + // made to trigger potential watchpoints + avr_core_watch_read(avr, addr); + //return 0; + goto avr_uart_read_check; + } + if (!uart_fifo_isempty(&p->input)) { // probably redundant check + v = (uint8_t)uart_fifo_read(&p->input) & 0xFF; + p->rx_cnt++; + if ((p->rx_cnt > 1) && // UART actually has 2-character rx buffer + ((avr->cycle-p->rxc_raise_time)/p->rx_cnt < p->cycles_per_byte)) { + // prevent the firmware from reading input characters with non-realistic high speed + avr_uart_clear_interrupt(avr, &p->rxc); + p->rx_cnt = 0; + } + } else { + AVR_LOG(avr, LOG_TRACE, "UART%c: BUG: rxc raised with empty rx buffer\n", p->name); + } + +// TRACE(printf("UART read %02x %s\n", v, uart_fifo_isempty(&p->input) ? "EMPTY!" : "");) + avr->data[addr] = v; + // made to trigger potential watchpoints + v = avr_core_watch_read(avr, addr); + +avr_uart_read_check: + if (uart_fifo_isempty(&p->input)) { + avr_cycle_timer_cancel(avr, avr_uart_rxc_raise, p); + avr_uart_clear_interrupt(avr, &p->rxc); + avr_raise_irq(p->io.irq + UART_IRQ_OUT_XOFF, 0); + avr_raise_irq(p->io.irq + UART_IRQ_OUT_XON, 1); + } + if (!uart_fifo_isfull(&p->input)) { + avr_regbit_clear(avr, p->dor); + } + + return v; +} + +static void +avr_uart_baud_write( + struct avr_t * avr, + avr_io_addr_t addr, + uint8_t v, + void * param) +{ + avr_uart_t * p = (avr_uart_t *)param; + avr_core_watch_write(avr, addr, v); + uint32_t val = avr_regbit_get(avr,p->ubrrl) | (avr_regbit_get(avr,p->ubrrh) << 8); + + const int databits[] = { 5,6,7,8, /* 'reserved', assume 8 */8,8,8, 9 }; + int db = databits[avr_regbit_get(avr, p->ucsz) | (avr_regbit_get(avr, p->ucsz2) << 2)]; + int sb = 1 + avr_regbit_get(avr, p->usbs); + int word_size = 1 /* start */ + db /* data bits */ + 1 /* parity */ + sb /* stops */; + int cycles_per_bit = (val+1)*8; + if (!avr_regbit_get(avr, p->u2x)) + cycles_per_bit *= 2; + double baud = ((double)avr->frequency) / cycles_per_bit; // can be less than 1 + p->cycles_per_byte = cycles_per_bit * word_size; + + AVR_LOG(avr, LOG_TRACE, "UART: %c configured to %04x = %.4f bps (x%d), %d data %d stop\n", + p->name, val, baud, avr_regbit_get(avr, p->u2x)?2:1, db, sb); + AVR_LOG(avr, LOG_TRACE, "UART: Roughly %d usec per byte\n", + avr_cycles_to_usec(avr, p->cycles_per_byte)); +} + +static void +avr_uart_udr_write( + struct avr_t * avr, + avr_io_addr_t addr, + uint8_t v, + void * param) +{ + avr_uart_t * p = (avr_uart_t *)param; + + // The byte to be sent should NOT be written there, + // the value written could never be read back. + //avr_core_watch_write(avr, addr, v); + if (avr->gdb) { + avr_gdb_handle_watchpoints(avr, addr, AVR_GDB_WATCH_WRITE); + } + + //avr_cycle_timer_cancel(avr, avr_uart_txc_raise, p); // synchronize tx pump + if (p->udrc.vector && avr_regbit_get(avr, p->udrc.raised)) { + avr_uart_clear_interrupt(avr, &p->udrc); + } + + if (p->flags & AVR_UART_FLAG_STDIO) { + const int maxsize = 256; + if (!p->stdio_out) + p->stdio_out = malloc(maxsize); + p->stdio_out[p->stdio_len++] = v < ' ' ? '.' : v; + p->stdio_out[p->stdio_len] = 0; + if (v == '\n' || p->stdio_len == maxsize) { + p->stdio_len = 0; + AVR_LOG(avr, LOG_OUTPUT, + FONT_GREEN "%s\n" FONT_DEFAULT, p->stdio_out); + } + } + TRACE(printf("UDR%c(%02x) = %02x\n", p->name, addr, v);) + // tell other modules we are "outputting" a byte + if (avr_regbit_get(avr, p->txen)) { + avr_raise_irq(p->io.irq + UART_IRQ_OUTPUT, v); + p->tx_cnt++; + if (p->tx_cnt > 2) // AVR actually has 1-character UART tx buffer, plus shift register + AVR_LOG(avr, LOG_TRACE, + "UART%c: tx buffer overflow %d\n", + p->name, (int)p->tx_cnt); + if (avr_cycle_timer_status(avr, avr_uart_txc_raise, p) == 0) + avr_cycle_timer_register(avr, p->cycles_per_byte, + avr_uart_txc_raise, p); // start the tx pump + } +} + + +static void +avr_uart_write( + struct avr_t * avr, + avr_io_addr_t addr, + uint8_t v, + void * param) +{ + avr_uart_t * p = (avr_uart_t *)param; + + uint8_t masked_v = v; + uint8_t clear_txc = 0; + uint8_t clear_rxc = 0; + + // exclude these locations from direct write: + if (p->udrc.raised.reg == addr) { + masked_v &= ~(p->udrc.raised.mask << p->udrc.raised.bit); + masked_v |= avr_regbit_get_raw(avr, p->udrc.raised); + } + if (p->txc.raised.reg == addr) { + uint8_t mask = p->txc.raised.mask << p->txc.raised.bit; + masked_v &= ~(mask); + masked_v |= avr_regbit_get_raw(avr, p->txc.raised); + // it can be cleared by writing a one to its bit location + if (v & mask) + clear_txc = 1; + } + if (p->rxc.raised.reg == addr) { + uint8_t mask = p->rxc.raised.mask << p->rxc.raised.bit; + masked_v &= ~(mask); + masked_v |= avr_regbit_get_raw(avr, p->rxc.raised); + if (!p->udrc.vector) { + // In the LIN mode it can be cleared by writing a one to its bit location + if (v & mask) + clear_rxc = 1; + } + } + // mainly to prevent application to confuse itself + // by writing something there and reading it back: + if (p->fe.reg == addr) { + masked_v &= ~(p->fe.mask << p->fe.bit); + masked_v |= avr_regbit_get_raw(avr, p->fe); + } + if (p->dor.reg == addr) { + masked_v &= ~(p->dor.mask << p->dor.bit); + //masked_v |= avr_regbit_get_raw(avr, p->dor); + } + if (p->upe.reg == addr) { + masked_v &= ~(p->upe.mask << p->upe.bit); + masked_v |= avr_regbit_get_raw(avr, p->upe); + } + if (p->rxb8.reg == addr) { + masked_v &= ~(p->rxb8.mask << p->rxb8.bit); + masked_v |= avr_regbit_get_raw(avr, p->rxb8); + } + + uint8_t txen = avr_regbit_get(avr, p->txen); + uint8_t rxen = avr_regbit_get(avr, p->rxen); + uint8_t udrce = avr_regbit_get(avr, p->udrc.enable); + // Now write whatever bits could be writen directly. + // It is necessary anyway, to trigger potential watchpoints. + avr_core_watch_write(avr, addr, masked_v); + uint8_t new_txen = avr_regbit_get(avr, p->txen); + uint8_t new_rxen = avr_regbit_get(avr, p->rxen); + uint8_t new_udrce = avr_regbit_get(avr, p->udrc.enable); + if (p->udrc.vector && (!udrce && new_udrce) && new_txen) { + // If enabling the UDRC (alias is UDRE) interrupt, raise it immediately if FIFO is empty. + // If the FIFO is not empty (clear timer is flying) we don't + // need to raise the interrupt, it will happen when the timer + // is fired. + if (avr_cycle_timer_status(avr, avr_uart_txc_raise, p) == 0) + avr_raise_interrupt(avr, &p->udrc); + } + if (clear_txc) + avr_uart_clear_interrupt(avr, &p->txc); + if (clear_rxc) + avr_uart_clear_interrupt(avr, &p->rxc); + + ///TODO: handle the RxD & TxD pins function override + + if (new_rxen != rxen) { + if (new_rxen) { + if (uart_fifo_isempty(&p->input)) { + // if reception is enabled and the fifo is empty, tell whomever there is room + avr_raise_irq(p->io.irq + UART_IRQ_OUT_XOFF, 0); + avr_raise_irq(p->io.irq + UART_IRQ_OUT_XON, 1); + } + } else { + avr_raise_irq(p->io.irq + UART_IRQ_OUT_XOFF, 1); + avr_cycle_timer_cancel(avr, avr_uart_rxc_raise, p); + // flush the Receive Buffer + uart_fifo_reset(&p->input); + // clear the rxc interrupt flag + avr_uart_clear_interrupt(avr, &p->rxc); + } + } + if (new_txen != txen) { + if (p->udrc.vector && !new_txen) { + avr_uart_clear_interrupt(avr, &p->udrc); + } else { + avr_regbit_set(avr, p->udrc.raised); + } + } +} + +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 if receiver is enabled + if (!avr_regbit_get(avr, p->rxen)) + return; + + // reserved/not implemented: + //avr_regbit_clear(avr, p->fe); + //avr_regbit_clear(avr, p->upe); + //avr_regbit_clear(avr, p->rxb8); + + if (uart_fifo_isempty(&p->input) && + (avr_cycle_timer_status(avr, avr_uart_rxc_raise, p) == 0) + ) { + avr_cycle_timer_register(avr, p->cycles_per_byte, avr_uart_rxc_raise, p); // start the rx pump + p->rx_cnt = 0; + avr_regbit_clear(avr, p->dor); + } else if (uart_fifo_isfull(&p->input)) { + avr_regbit_setto(avr, p->dor, 1); + } + if (!avr_regbit_get(avr, p->dor)) { // otherwise newly received character must be rejected + uart_fifo_write(&p->input, value); // add to fifo + } else { + AVR_LOG(avr, LOG_ERROR, "UART%c: %s: RX buffer overrun, lost char=%c=0x%02X\n", p->name, __func__, + (char)value, (uint8_t)value ); + } + + TRACE(printf("UART IRQ in %02x (%d/%d) %s\n", value, p->input.read, p->input.write, uart_fifo_isfull(&p->input) ? "FULL!!" : "");) + + if (uart_fifo_isfull(&p->input)) + avr_raise_irq(p->io.irq + UART_IRQ_OUT_XOFF, 1); +} + + +void +avr_uart_reset( + struct avr_io_t *io) +{ + avr_uart_t * p = (avr_uart_t *)io; + avr_t * avr = p->io.avr; + if (p->udrc.vector) { + avr_regbit_set(avr, p->udrc.raised); + avr_regbit_clear(avr, p->dor); + } + avr_uart_clear_interrupt(avr, &p->txc); + avr_uart_clear_interrupt(avr, &p->rxc); + avr_irq_register_notify(p->io.irq + UART_IRQ_INPUT, avr_uart_irq_input, p); + avr_cycle_timer_cancel(avr, avr_uart_rxc_raise, p); + avr_cycle_timer_cancel(avr, avr_uart_txc_raise, p); + uart_fifo_reset(&p->input); + p->tx_cnt = 0; + + avr_regbit_set(avr, p->ucsz); + avr_regbit_clear(avr, p->ucsz2); + + // DEBUG allow printf without fiddling with enabling the uart + avr_regbit_set(avr, p->txen); + p->cycles_per_byte = avr_usec_to_cycles(avr, 100); +} + +static int +avr_uart_ioctl( + struct avr_io_t * port, + uint32_t ctl, + void * io_param) +{ + avr_uart_t * p = (avr_uart_t *)port; + int res = -1; + + if (!io_param) + return res; + + if (ctl == AVR_IOCTL_UART_SET_FLAGS(p->name)) { + p->flags = *(uint32_t*)io_param; + res = 0; + } + if (ctl == AVR_IOCTL_UART_GET_FLAGS(p->name)) { + *(uint32_t*)io_param = p->flags; + res = 0; + } + + return res; +} + +static const char * irq_names[UART_IRQ_COUNT] = { + [UART_IRQ_INPUT] = "8io = _io; + +// printf("%s UART%c UDR=%02x\n", __FUNCTION__, p->name, p->r_udr); + + p->flags = AVR_UART_FLAG_POLL_SLEEP|AVR_UART_FLAG_STDIO; + + avr_register_io(avr, &p->io); + avr_register_vector(avr, &p->rxc); + avr_register_vector(avr, &p->txc); + avr_register_vector(avr, &p->udrc); + + // allocate this module's IRQ + avr_io_setirqs(&p->io, AVR_IOCTL_UART_GETIRQ(p->name), UART_IRQ_COUNT, NULL); + // Only call callbacks when the value change... + p->io.irq[UART_IRQ_OUT_XOFF].flags |= IRQ_FLAG_FILTERED; + + avr_register_io_write(avr, p->r_udr, avr_uart_udr_write, p); + avr_register_io_read(avr, p->r_udr, avr_uart_read, p); + + // status bits + // monitor code that reads the rxc flag, and delay it a bit + avr_register_io_read(avr, p->rxc.raised.reg, avr_uart_status_read, p); + if (p->fe.reg != p->rxc.raised.reg) + avr_register_io_read(avr, p->fe.reg, avr_uart_status_read, p); + + if (p->udrc.vector) + avr_register_io_write(avr, p->udrc.enable.reg, avr_uart_write, p); + if (p->r_ucsra) + avr_register_io_write(avr, p->r_ucsra, avr_uart_write, p); + if (p->ubrrl.reg) + avr_register_io_write(avr, p->ubrrl.reg, avr_uart_baud_write, p); + avr_register_io_write(avr, p->rxen.reg, avr_uart_write, p); +} + diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_uart.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_uart.h new file mode 100644 index 0000000..107359e --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_uart.h @@ -0,0 +1,229 @@ +/* + avr_uart.h + + Copyright 2008, 2009 Michel Pollet + + 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 . + */ + +#ifndef __AVR_UART_H__ +#define __AVR_UART_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "sim_avr.h" + +#include "fifo_declare.h" + +DECLARE_FIFO(uint16_t, uart_fifo, 64); + +/* + * The method of "connecting" the the UART from external code is to use 4 IRQS. + * The easy one is UART->YOU, where you will be called with the byte every time + * the AVR firmware sends one. Do whatever you like with it. + * + * The slightly more tricky one is the INPUT part. Since the AVR is quite a bit + * slower than your code most likely, there is a way for the AVR UART to tell + * you to "pause" sending it bytes when its own input buffer is full. + * So, the UART will send XON to you when its fifo is empty, XON means you can + * send as many bytes as you have until XOFF is sent. Note that these are two + * IRQs because you /will/ be called with XOFF when sending a byte in INPUT... + * So it's a reentrant process. + * + * When XOFF has been called, do not send any new bytes, they would be dropped. + * Instead wait for XON again and continue. + * See examples/parts/uart_udp.c for a full implementation + * + * Pseudo code: + * + * volatile int off = 0; + * void irq_xon() + * { + * off = 0; + * while (!off && bytes_left) + * avr_raise_irq(UART_IRQ_INPUT, a_byte); + * } + * void irq_xoff() + * { + * off = 1; + * } + * + */ +enum { + UART_IRQ_INPUT = 0, + UART_IRQ_OUTPUT, + UART_IRQ_OUT_XON, // signaled (continuously) when input fifo is not full + UART_IRQ_OUT_XOFF, // signaled when input fifo IS full + UART_IRQ_COUNT +}; + +enum { + UART_INPUT_FE = 0x8000 // framing error +}; + +// add port number to get the real IRQ +#define AVR_IOCTL_UART_GETIRQ(_name) AVR_IOCTL_DEF('u','a','r',(_name)) + +enum { + // the uart code monitors for firmware that poll on + // reception registers, and can do an atomic usleep() + // if it's detected, this helps regulating CPU + AVR_UART_FLAG_POOL_SLEEP = (1 << 0), + AVR_UART_FLAG_POLL_SLEEP = (1 << 0), // to replace pool_sleep + AVR_UART_FLAG_STDIO = (1 << 1), // print lines on the console +}; + +typedef struct avr_uart_t { + avr_io_t io; + char name; + avr_regbit_t disabled; // bit in the PRR + + avr_io_addr_t r_udr; + avr_io_addr_t r_ucsra; + avr_io_addr_t r_ucsrb; + avr_io_addr_t r_ucsrc; + + avr_regbit_t rxen; // receive enabled + avr_regbit_t txen; // transmit enable + avr_regbit_t u2x; // double UART speed + avr_regbit_t usbs; // stop bits + avr_regbit_t ucsz; // data bits + avr_regbit_t ucsz2; // data bits, continued + + // read-only bits (just to mask it out) + avr_regbit_t fe; // frame error bit + avr_regbit_t dor; // data overrun bit + avr_regbit_t upe; // parity error bit + avr_regbit_t rxb8; // receive data bit 8 + + avr_regbit_t ubrrl; + avr_regbit_t ubrrh; + + avr_int_vector_t rxc; + avr_int_vector_t txc; + avr_int_vector_t udrc; + + uart_fifo_t input; + uint8_t tx_cnt; // number of unsent characters in the output buffer + uint32_t rx_cnt; // number of characters read by app since rxc_raise_time + + uint32_t flags; + avr_cycle_count_t cycles_per_byte; + avr_cycle_count_t rxc_raise_time; // the cpu cycle when rxc flag was raised last time + + uint8_t * stdio_out; + int stdio_len; // current size in the stdio output +} avr_uart_t; + +/* takes a uint32_t* as parameter */ +#define AVR_IOCTL_UART_SET_FLAGS(_name) AVR_IOCTL_DEF('u','a','s',(_name)) +#define AVR_IOCTL_UART_GET_FLAGS(_name) AVR_IOCTL_DEF('u','a','g',(_name)) + +void avr_uart_init(avr_t * avr, avr_uart_t * port); + +#define AVR_UARTX_DECLARE(_name, _prr, _prusart) \ + .uart ## _name = { \ + .name = '0' + _name, \ + .disabled = AVR_IO_REGBIT(_prr, _prusart), \ + \ + .r_udr = UDR ## _name, \ + \ + .fe = AVR_IO_REGBIT(UCSR ## _name ## A, FE ## _name), \ + .dor = AVR_IO_REGBIT(UCSR ## _name ## A, DOR ## _name), \ + .upe = AVR_IO_REGBIT(UCSR ## _name ## A, UPE ## _name), \ + .u2x = AVR_IO_REGBIT(UCSR ## _name ## A, U2X ## _name), \ + .txen = AVR_IO_REGBIT(UCSR ## _name ## B, TXEN ## _name), \ + .rxen = AVR_IO_REGBIT(UCSR ## _name ## B, RXEN ## _name), \ + .rxb8 = AVR_IO_REGBIT(UCSR ## _name ## B, RXB8 ## _name), \ + .usbs = AVR_IO_REGBIT(UCSR ## _name ## C, USBS ## _name), \ + .ucsz = AVR_IO_REGBITS(UCSR ## _name ## C, UCSZ ## _name ## 0, 0x3), \ + .ucsz2 = AVR_IO_REGBIT(UCSR ## _name ## B, UCSZ ## _name ## 2), \ + .ubrrl = AVR_IO_REGBITS(UBRR ## _name ## L, 0,0xFF), \ + .ubrrh = AVR_IO_REGBITS(UBRR ## _name ## H, 0,0xF), \ + \ + .r_ucsra = UCSR ## _name ## A, \ + .r_ucsrb = UCSR ## _name ## B, \ + .r_ucsrc = UCSR ## _name ## C, \ + \ + .rxc = { \ + .enable = AVR_IO_REGBIT(UCSR ## _name ## B, RXCIE ## _name), \ + .raised = AVR_IO_REGBIT(UCSR ## _name ## A, RXC ## _name), \ + .vector = USART ## _name ## _RX_vect, \ + .raise_sticky = 1, \ + }, \ + .txc = { \ + .enable = AVR_IO_REGBIT(UCSR ## _name ## B, TXCIE ## _name), \ + .raised = AVR_IO_REGBIT(UCSR ## _name ## A, TXC ## _name), \ + .vector = USART ## _name ## _TX_vect, \ + }, \ + .udrc = { \ + .enable = AVR_IO_REGBIT(UCSR ## _name ## B, UDRIE ## _name), \ + .raised = AVR_IO_REGBIT(UCSR ## _name ## A, UDRE ## _name), \ + .vector = USART ## _name ## _UDRE_vect, \ + .raise_sticky = 1, \ + }, \ + } + +// This macro is for older single-interface devices where variable names are bit divergent +#define AVR_UART_DECLARE(_prr, _prusart, _upe_name, _rname_ix, _intr_c) \ + .uart = { \ + .name = '0', \ + .disabled = AVR_IO_REGBIT(_prr, _prusart), \ + .r_udr = UDR ## _rname_ix, \ + \ + .fe = AVR_IO_REGBIT(UCSR ## _rname_ix ## A, FE ## _rname_ix), \ + .dor = AVR_IO_REGBIT(UCSR ## _rname_ix ## A, DOR ## _rname_ix), \ + .upe = AVR_IO_REGBIT(UCSR ## _rname_ix ## A, _upe_name ## _rname_ix), \ + .u2x = AVR_IO_REGBIT(UCSR ## _rname_ix ## A, U2X ## _rname_ix), \ + .txen = AVR_IO_REGBIT(UCSR ## _rname_ix ## B, TXEN ## _rname_ix), \ + .rxen = AVR_IO_REGBIT(UCSR ## _rname_ix ## B, RXEN ## _rname_ix), \ + .rxb8 = AVR_IO_REGBIT(UCSR ## _rname_ix ## B, RXB8 ## _rname_ix), \ + .usbs = AVR_IO_REGBIT(UCSR ## _rname_ix ## C, USBS ## _rname_ix), \ + .ucsz = AVR_IO_REGBITS(UCSR ## _rname_ix ## C, UCSZ ## _rname_ix ## 0, 0x3), \ + .ucsz2 = AVR_IO_REGBIT(UCSR ## _rname_ix ## B, UCSZ ## _rname_ix ## 2), \ + .ubrrl = AVR_IO_REGBITS(UBRR ## _rname_ix ## L, 0,0xFF), \ + .ubrrh = AVR_IO_REGBITS(UBRR ## _rname_ix ## H, 0,0xF), \ + \ + .r_ucsra = UCSR ## _rname_ix ## A, \ + .r_ucsrb = UCSR ## _rname_ix ## B, \ + .r_ucsrc = UCSR ## _rname_ix ## C, \ + \ + .rxc = { \ + .enable = AVR_IO_REGBIT(UCSR ## _rname_ix ## B, RXCIE ## _rname_ix), \ + .raised = AVR_IO_REGBIT(UCSR ## _rname_ix ## A, RXC ## _rname_ix), \ + .vector = USART_RX ## _intr_c ## _vect, \ + .raise_sticky = 1, \ + }, \ + .txc = { \ + .enable = AVR_IO_REGBIT(UCSR ## _rname_ix ## B, TXCIE ## _rname_ix), \ + .raised = AVR_IO_REGBIT(UCSR ## _rname_ix ## A, TXC ## _rname_ix), \ + .vector = USART_TX ## _intr_c ## _vect, \ + }, \ + .udrc = { \ + .enable = AVR_IO_REGBIT(UCSR ## _rname_ix ## B, UDRIE ## _rname_ix), \ + .raised = AVR_IO_REGBIT(UCSR ## _rname_ix ## A, UDRE ## _rname_ix), \ + .vector = USART_UDRE_vect, \ + .raise_sticky = 1, \ + }, \ + } + +#ifdef __cplusplus +}; +#endif + +#endif /*__AVR_UART_H__*/ diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_usb.c b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_usb.c new file mode 100644 index 0000000..4acbcfd --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_usb.c @@ -0,0 +1,801 @@ +/* vim: set sts=4:sw=4:ts=4:noexpandtab + avr_usb.c + + Copyright 2012 Torbjorn Tyridal + + 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 . + */ + +/* TODO correct reset values */ +/* TODO generate sofi every 1ms (when connected) */ +/* TODO otg support? */ +/* TODO drop bitfields? */ +/* TODO thread safe ioctls */ +/* TODO dual-bank endpoint buffers */ +/* TODO actually pay attention to endpoint memory allocation ? buggy endpoint configuration doesn't matter in the simulator now. */ + +#include +#include +#include +#include +#include "avr_usb.h" + +enum usb_regs +{ + usbcon = 0, + udcon = 8, + udint = 9, + udien = 10, + udaddr = 11, + udfnuml = 12, + udfnumh = 13, + udmfn = 14, +// _res=15, + ueintx = 16, + uenum = 17, + uerst = 18, + ueconx = 19, + uecfg0x = 20, + uecfg1x = 21, + uesta0x = 22, + uesta1x = 23, + ueienx = 24, + uedatx = 25, + uebclx = 26, +// _res2=27, + ueint = 28, + otgtcon = 29, +}; + +union _ueintx { + struct { + uint8_t txini :1; + uint8_t stalledi :1; + uint8_t rxouti :1; + uint8_t rxstpi :1; + uint8_t nakouti :1; + uint8_t rwal :1; + uint8_t nakini :1; + uint8_t fifocon :1; + }; + uint8_t v; +}; + +struct _epstate { + union _ueintx ueintx; + uint8_t dummy1; + uint8_t dummy2; + union { + struct { + uint8_t epen :1; + uint8_t res :2; + uint8_t rstdt :1; + uint8_t stallrqc :1; + uint8_t stallrq :1; + }; + uint8_t v; + } ueconx; + union { + struct { + uint8_t epdir :1; + uint8_t res :5; + uint8_t eptype :2; + }; + uint8_t v; + } uecfg0x; + union { + struct { + uint8_t res :1; + uint8_t alloc :1; + uint8_t epbk1 :2; + uint8_t epsize :3; + uint8_t res2 :1; + }; + uint8_t v; + } uecfg1x; + union { + struct { + uint8_t nbusybk :2; + uint8_t dtseq :2; + uint8_t res :1; + uint8_t underfi :1; + uint8_t overfi :1; + uint8_t cfgok :1; + }; + uint8_t v; + } uesta0x; + union { + struct { + uint8_t curbk :2; + uint8_t ctrldir :1; + uint8_t res :5; + }; + uint8_t v; + } uesta1x; + union { + struct { + uint8_t txine :1; + uint8_t stallede :1; + uint8_t rxoute :1; + uint8_t rxstpe :1; + uint8_t nakoute :1; + uint8_t res :1; + uint8_t nakine :1; + uint8_t flerre :1; + }; + uint8_t v; + } ueienx; + + struct { + uint8_t bytes[64]; + uint8_t tail; + } bank[2]; + uint8_t current_bank; + int setup_is_read; +}; + +struct usb_internal_state { + struct _epstate ep_state[5]; + avr_int_vector_t com_vect; + avr_int_vector_t gen_vect; +}; + +const uint8_t num_endpoints = 5;//sizeof (struct usb_internal_state.ep_state) / sizeof (struct usb_internal_state.ep_state[0]); + +static uint8_t +current_ep_to_cpu( + avr_usb_t * p) +{ + return p->io.avr->data[p->r_usbcon + uenum]; +} + +static struct _epstate * +get_epstate( + avr_usb_t * p, + uint8_t ep) +{ + assert(ep < num_endpoints); + return &p->state->ep_state[ep]; +} + + +enum epints { + txini = 0, + stalledi = 1, + rxouti = 2, + rxstpi = 3, + nakouti = 4, + nakini = 6, + overfi = 10, + underfi = 11, +}; + +static void +raise_ep_interrupt( + struct avr_t * avr, + avr_usb_t * p, + uint8_t ep, + enum epints irq) +{ + struct _epstate * epstate = get_epstate(p, ep); + assert(ep < num_endpoints); + avr->data[p->r_usbcon + ueint] |= 1 << ep; + switch (irq) { + case txini: + case stalledi: + case rxouti: + case nakouti: + case nakini: + epstate->ueintx.v |= 1 << irq; + if (epstate->ueienx.v & (1 << irq)) + avr_raise_interrupt(avr, &p->state->com_vect); + break; + case rxstpi: + epstate->ueintx.v |= 1 << irq; + if (epstate->ueienx.v & (1 << irq)) + avr_raise_interrupt(avr, &p->state->com_vect); + break; + case overfi: + epstate->uesta0x.overfi = 1; + if (epstate->ueienx.flerre) + avr_raise_interrupt(avr, &p->state->com_vect); + break; + case underfi: + epstate->uesta0x.underfi = 1; + if (epstate->ueienx.flerre) + avr_raise_interrupt(avr, &p->state->com_vect); + break; + default: + assert(0); + } +} + +enum usbints { + suspi = 0, sofi = 2, eorsti = 3, wakeupi = 4, eorsmi = 5, uprsmi = 6 +}; +static void +raise_usb_interrupt( + avr_usb_t * p, + enum usbints irq) +{ + uint8_t * Rudien = &p->io.avr->data[p->r_usbcon + udien]; + uint8_t * Rudint = &p->io.avr->data[p->r_usbcon + udint]; + + switch (irq) { + case uprsmi: + case eorsmi: + case wakeupi: + case eorsti: + case sofi: + case suspi: + *Rudint |= 1 << irq; + if (*Rudien & (1 << irq)) + avr_raise_interrupt(p->io.avr, &p->state->gen_vect); + break; + default: + assert(0); + } + +} + +static void +reset_endpoints( + struct avr_t * avr, + avr_usb_t * p) +{ + memset(&p->state->ep_state[1], 0, + sizeof p->state->ep_state - sizeof p->state->ep_state[0]); +} + +static int +ep_fifo_empty( + struct _epstate * epstate) +{ + return epstate->bank[epstate->current_bank].tail == 0; +} + +static int +ep_fifo_full( + struct _epstate * epstate) +{ + return epstate->bank[epstate->current_bank].tail >= + (8 << epstate->uecfg1x.epsize); +} + +static uint8_t +ep_fifo_size( + struct _epstate * epstate) +{ + assert(epstate->ueconx.epen); + return (8 << epstate->uecfg1x.epsize); +} + +static uint8_t +ep_fifo_count( + struct _epstate * epstate) +{ + return epstate->bank[epstate->current_bank].tail; +} + +static int +ep_fifo_cpu_readbyte( + struct _epstate * epstate) +{ + uint8_t i, j; + uint8_t v = epstate->bank[epstate->current_bank].bytes[0]; + + if (!epstate->ueconx.epen) { + printf("WARNING! Adding bytes to non configured endpoint\n"); + return -1; + } + + if (ep_fifo_empty(epstate)) + return -2; + + for (i = 0, j = ep_fifo_count(epstate) - 1; i < j; i++) + epstate->bank[epstate->current_bank].bytes[i] = + epstate->bank[epstate->current_bank].bytes[i + 1]; + epstate->bank[epstate->current_bank].tail--; + return v; +} + +static int +ep_fifo_cpu_writebyte( + struct _epstate * epstate, + uint8_t v) +{ + if (!epstate->ueconx.epen) { + printf("WARNING! Adding bytes to non configured endpoint\n"); + return -1; + } + if (ep_fifo_full(epstate)) + return -2; + + epstate->bank[epstate->current_bank].bytes[epstate->bank[epstate->current_bank].tail++] = v; + return 0; +} + +static int +ep_fifo_usb_read( + struct _epstate * epstate, + uint8_t * buf) +{ + if (!epstate->ueconx.epen) { + printf("WARNING! Reading from non configured endpoint\n"); + return -1; + } + if (epstate->ueintx.txini) { + return AVR_IOCTL_USB_NAK; + } + if (epstate->ueintx.fifocon && epstate->uecfg0x.eptype != 0) { + return AVR_IOCTL_USB_NAK; + } + + int ret = epstate->bank[epstate->current_bank].tail; + memcpy(buf, epstate->bank[epstate->current_bank].bytes, + epstate->bank[epstate->current_bank].tail); + epstate->bank[epstate->current_bank].tail = 0; + return ret; +} + +static int +ep_fifo_usb_write( + struct _epstate * epstate, + uint8_t * buf, + uint8_t len) +{ + if (!epstate->ueconx.epen) { + printf("WARNING! Adding bytes to non configured endpoint\n"); + return -1; + } + + if (epstate->ueintx.rxouti) { + return AVR_IOCTL_USB_NAK; + } + if (epstate->ueintx.fifocon && epstate->uecfg0x.eptype != 0) { + return AVR_IOCTL_USB_NAK; + } + + if (len > ep_fifo_size(epstate)) { + printf("EP OVERFI\n"); + len = sizeof epstate->bank[epstate->current_bank].bytes; + } + memcpy(epstate->bank[epstate->current_bank].bytes, buf, len); + epstate->bank[epstate->current_bank].tail = len; + + return 0; +} + +static uint8_t +avr_usb_ep_read_bytecount( + struct avr_t * avr, + avr_io_addr_t addr, + void * param) +{ + avr_usb_t * p = (avr_usb_t *) param; + return ep_fifo_count(get_epstate(p, current_ep_to_cpu(p))); +} + +static void +avr_usb_udaddr_write( + struct avr_t * avr, + avr_io_addr_t addr, + uint8_t v, + void * param) +{ + if (v & 0x80) + AVR_LOG(avr, LOG_TRACE, "USB: Activate address %d\n", v & 0x7f); + avr_core_watch_write(avr, addr, v); +} + +static void +avr_usb_udcon_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) +{ + avr_usb_t * p = (avr_usb_t *)param; + + if(avr->data[addr]&1 && !(v&1)) + avr_raise_irq(p->io.irq + USB_IRQ_ATTACH, !(v&1)); + avr_core_watch_write(avr, addr, v); +} + +static void +avr_usb_uenum_write( + struct avr_t * avr, + avr_io_addr_t addr, + uint8_t v, + void * param) +{ + assert(v < num_endpoints); + avr_core_watch_write(avr, addr, v); +} + +static uint8_t +avr_usb_ep_read_ueintx( + struct avr_t * avr, + avr_io_addr_t addr, + void * param) +{ + avr_usb_t * p = (avr_usb_t *) param; + uint8_t ep = current_ep_to_cpu(p); + + if (p->state->ep_state[ep].uecfg0x.epdir) + p->state->ep_state[ep].ueintx.rwal = !ep_fifo_full(get_epstate(p, ep)); + else + p->state->ep_state[ep].ueintx.rwal = !ep_fifo_empty(get_epstate(p, ep)); + + return p->state->ep_state[ep].ueintx.v; +} + +static void +avr_usb_ep_write_ueintx( + struct avr_t * avr, + avr_io_addr_t addr, + uint8_t v, + void * param) +{ + avr_usb_t * p = (avr_usb_t *) param; + uint8_t ep = current_ep_to_cpu(p); + + union _ueintx * newstate = (union _ueintx*) &v; + union _ueintx * curstate = &p->state->ep_state[ep].ueintx; + + if (curstate->rxouti & !newstate->rxouti) + curstate->rxouti = 0; + if (curstate->txini & !newstate->txini) + curstate->txini = 0; + if (curstate->rxstpi & !newstate->rxstpi) { + curstate->txini = 1; + curstate->rxouti = 0; + curstate->rxstpi = 0; + } + if (curstate->fifocon & !newstate->fifocon) + curstate->fifocon = 0; + if (curstate->nakini & !newstate->nakini) + curstate->nakini = 0; + if (curstate->nakouti & !newstate->nakouti) + curstate->nakouti = 0; + if (curstate->stalledi & !newstate->stalledi) + curstate->stalledi = 0; + if (curstate->rwal & !newstate->rwal) + AVR_LOG(avr, LOG_WARNING, "USB: Pointless change of ueintx.rwal\n"); + + if ((curstate->v & 0xdf) == 0) + avr->data[p->r_usbcon + ueint] &= 0xff ^ (1 << ep); // mark ep0 interrupt +} + +static uint8_t +avr_usb_ep_read( + struct avr_t * avr, + avr_io_addr_t addr, + void * param) +{ + avr_usb_t * p = (avr_usb_t *) param; + uint8_t laddr = addr - p->r_usbcon; + uint8_t v; + struct _epstate * epstate = get_epstate(p, current_ep_to_cpu(p)); + + switch(laddr) { + case ueconx: v = epstate->ueconx.v; break; + case uecfg0x: v = epstate->uecfg0x.v; break; + case uecfg1x: v = epstate->uecfg1x.v; break; + case uesta0x: v = epstate->uesta0x.v; break; + case uesta1x: v = epstate->uesta1x.v; break; + case ueienx: v = epstate->ueienx.v; break; + default:assert(0); + } + return v; +} + +static void +avr_usb_ep_write( + struct avr_t * avr, + avr_io_addr_t addr, + uint8_t v, + void * param) +{ + avr_usb_t * p = (avr_usb_t *) param; + struct _epstate * epstate = get_epstate(p, current_ep_to_cpu(p)); + uint8_t laddr = addr - p->r_usbcon; + + switch (laddr) { + case ueconx: + if (v & 1 << 4) + epstate->ueconx.stallrq = 0; + if (v & 1 << 5) + epstate->ueconx.stallrq = 1; + epstate->ueconx.epen = (v & 1) != 0; + break; + case uecfg0x: + epstate->uecfg0x.v = v; + epstate->uesta0x.cfgok = 0; + break; + case uecfg1x: + epstate->uecfg1x.v = v; + epstate->uesta0x.cfgok = epstate->uecfg1x.alloc; + if (epstate->uecfg0x.eptype == 0) + epstate->ueintx.txini = 1; + else if (epstate->uecfg0x.epdir) { + epstate->ueintx.txini = 1; + epstate->ueintx.rwal = 1; + epstate->ueintx.fifocon = 1; + } else + epstate->ueintx.rxouti = 0; + avr_core_watch_write(avr, p->r_usbcon + uesta0x, + epstate->uesta0x.v); + break; + case uesta0x: + v = (epstate->uesta0x.v & 0x9f) + (v & (0x60 & epstate->uesta0x.v)); + epstate->uesta0x.v = v; + break; + case ueienx: + epstate->ueienx.v = v; + break; + default: + assert(0); + } +} + +static uint8_t +avr_usb_ep_read_data( + struct avr_t * avr, + avr_io_addr_t addr, + void * param) +{ + avr_usb_t * p = (avr_usb_t *) param; + int ret = ep_fifo_cpu_readbyte(get_epstate(p, current_ep_to_cpu(p))); + + if (ret < 0) { + if (ret == -2) + raise_ep_interrupt(avr, p, current_ep_to_cpu(p), underfi); + return 0; + } else + return (uint8_t) ret; +} + +static void +avr_usb_ep_write_data( + struct avr_t * avr, + avr_io_addr_t addr, + uint8_t v, + void * param) +{ + avr_usb_t * p = (avr_usb_t *) param; + int ret = ep_fifo_cpu_writebyte(get_epstate(p, current_ep_to_cpu(p)), v); + if (ret == 0) + return; + + if (ret == -2) + raise_ep_interrupt(avr, p, current_ep_to_cpu(p), overfi); +} + +static void +avr_usb_pll_write( + struct avr_t * avr, + avr_io_addr_t addr, + uint8_t v, + void * param) +{ + v |= (v >> 1) & 1; + avr_core_watch_write(avr, addr, v); +} + + +avr_cycle_count_t +sof_generator( + struct avr_t * avr, + avr_cycle_count_t when, + void * param) +{ + avr_usb_t * p = (avr_usb_t *) param; + //stop sof generation if detached + if (avr->data[p->r_usbcon + udcon] & 1) + return 0; + else { + raise_usb_interrupt(p, sofi); + return when; + } +} + +static int +avr_usb_ioctl( + struct avr_io_t * io, + uint32_t ctl, + void * io_param) +{ + avr_usb_t * p = (avr_usb_t *) io; + struct avr_io_usb * d = (struct avr_io_usb*) io_param; + struct _epstate * epstate = 0; + int ret; + uint8_t ep; + + switch (ctl) { + case AVR_IOCTL_USB_READ: + ep = d->pipe & 0x7f; + epstate = get_epstate(p, ep); + + if (epstate->ueconx.stallrq) { + raise_ep_interrupt(io->avr, p, 0, stalledi); + return AVR_IOCTL_USB_STALL; + } + if (ep && !epstate->uecfg0x.epdir) + AVR_LOG(io->avr, LOG_WARNING, "USB: Reading from IN endpoint from host??\n"); + + ret = ep_fifo_usb_read(epstate, d->buf); + if (ret < 0) { + // is this correct? It makes the cdc example work. + // Linux stops polling the data ep if we send naks,but + // according to usb spec nak'ing should be ok. + if (epstate->uecfg0x.eptype == 2) { + d->sz = 0; + return 0; + } else + return ret; + } + d->sz = ret; + ret = 0; + epstate->ueintx.fifocon = 1; + raise_ep_interrupt(io->avr, p, ep, txini); + return ret; + case AVR_IOCTL_USB_WRITE: + ep = d->pipe & 0x7f; + epstate = get_epstate(p, ep); + + if (ep && epstate->uecfg0x.epdir) + AVR_LOG(io->avr, LOG_WARNING, "USB: Writing to IN endpoint from host??\n"); + + if (epstate->ueconx.stallrq) { + raise_ep_interrupt(io->avr, p, 0, stalledi); + return AVR_IOCTL_USB_STALL; + } + + ret = ep_fifo_usb_write(epstate, d->buf, d->sz); + if (ret < 0) + return ret; + + epstate->ueintx.fifocon = 1; + raise_ep_interrupt(io->avr, p, ep, rxouti); + return 0; + case AVR_IOCTL_USB_SETUP: + ep = d->pipe & 0x7f; + epstate = get_epstate(p, ep); + + epstate->ueconx.stallrq = 0; + // teensy actually depends on this (fails to ack rxouti on usb + // control read status stage) even if the datasheet clearly states + // that one should do so. + epstate->ueintx.rxouti = 0; + + ret = ep_fifo_usb_write(epstate, d->buf, d->sz); + if (ret < 0) + return ret; + raise_ep_interrupt(io->avr, p, ep, rxstpi); + + return 0; + case AVR_IOCTL_USB_RESET: + AVR_LOG(io->avr, LOG_TRACE, "USB: __USB_RESET__\n"); + reset_endpoints(io->avr, p); + raise_usb_interrupt(p, eorsti); + if (0) + avr_cycle_timer_register_usec(io->avr, 1000, sof_generator, p); + return 0; + default: + return -1; + } +} + +void +avr_usb_reset( + struct avr_io_t *io) +{ + avr_usb_t * p = (avr_usb_t *) io; + uint8_t i; + + memset(p->state->ep_state, 0, sizeof p->state->ep_state); + + for (i = 0; i < otgtcon; i++) + p->io.avr->data[p->r_usbcon + i] = 0; + + p->io.avr->data[p->r_usbcon] = 0x20; + p->io.avr->data[p->r_usbcon + udcon] = 1; + + AVR_LOG(io->avr, LOG_TRACE, "USB: %s\n", __FUNCTION__); +} + +static const char * irq_names[USB_IRQ_COUNT] = { + [USB_IRQ_ATTACH] = ">attach", +}; + +static void +avr_usb_dealloc( + struct avr_io_t * port) +{ + avr_usb_t * p = (avr_usb_t *) port; + free(p->state); +} + +static avr_io_t _io = { + .kind = "usb", + .reset = avr_usb_reset, + .irq_names = irq_names, + .ioctl = avr_usb_ioctl, + .dealloc = avr_usb_dealloc, +}; + +static void +register_io_ep_readwrite( + avr_t * avr, + avr_usb_t * p, + uint8_t laddr) +{ + avr_register_io_write(avr, p->r_usbcon + laddr, avr_usb_ep_write, p); + avr_register_io_read(avr, p->r_usbcon + laddr, avr_usb_ep_read, p); +} + +static void +register_vectors( + avr_t * avr, + avr_usb_t * p) +{ + // usb interrupts are multiplexed into just two vectors. + // we therefore need fake bits for enable & raise + + // use usbe as fake enable bit + p->state->com_vect.enable = (avr_regbit_t)AVR_IO_REGBIT(p->r_usbcon, 7); + p->state->gen_vect.enable = (avr_regbit_t)AVR_IO_REGBIT(p->r_usbcon, 7); + +// // use reserved/unused bits in usbsta as fake raised bits +// p->state->com_vect.raised = (avr_regbit_t)AVR_IO_REGBIT(p->r_usbcon+1,7); +// p->state->gen_vect.raised = (avr_regbit_t)AVR_IO_REGBIT(p->r_usbcon+1,6); + + p->state->com_vect.vector = p->usb_com_vect; + p->state->gen_vect.vector = p->usb_gen_vect; + + avr_register_vector(avr, &p->state->com_vect); + avr_register_vector(avr, &p->state->gen_vect); +} + +void avr_usb_init(avr_t * avr, avr_usb_t * p) +{ + p->io = _io; + + p->state = calloc(1, sizeof *p->state); + + avr_register_io(avr, &p->io); + register_vectors(avr, p); + // allocate this module's IRQ + avr_io_setirqs(&p->io, AVR_IOCTL_USB_GETIRQ(), USB_IRQ_COUNT, NULL); + + avr_register_io_write(avr, p->r_usbcon + udaddr, avr_usb_udaddr_write, p); + avr_register_io_write(avr, p->r_usbcon + udcon, avr_usb_udcon_write, p); + avr_register_io_write(avr, p->r_usbcon + uenum, avr_usb_uenum_write, p); + + avr_register_io_read(avr, p->r_usbcon + uedatx, avr_usb_ep_read_data, p); + avr_register_io_write(avr, p->r_usbcon + uedatx, avr_usb_ep_write_data, p); + avr_register_io_read(avr, p->r_usbcon + uebclx, avr_usb_ep_read_bytecount, p); //ro + + avr_register_io_read(avr, p->r_usbcon + ueintx, avr_usb_ep_read_ueintx, p); + avr_register_io_write(avr, p->r_usbcon + ueintx, avr_usb_ep_write_ueintx, p); + + register_io_ep_readwrite(avr, p, ueconx); + register_io_ep_readwrite(avr, p, uecfg0x); + register_io_ep_readwrite(avr, p, uecfg1x); + register_io_ep_readwrite(avr, p, uesta0x); + register_io_ep_readwrite(avr, p, uesta1x); + register_io_ep_readwrite(avr, p, ueienx); + + avr_register_io_write(avr, p->r_pllcsr, avr_usb_pll_write, p); +} + diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_usb.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_usb.h new file mode 100644 index 0000000..17e5c0d --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_usb.h @@ -0,0 +1,74 @@ +/* vim: set sts=4:sw=4:ts=4:noexpandtab + avr_usb.h + + Copyright 2012 Torbjorn Tyridal + + 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 . + */ + +#ifndef __AVR_USB_H__ +#define __AVR_USB_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "sim_avr.h" + +enum { + USB_IRQ_ATTACH = 0, + USB_IRQ_COUNT +}; + +// add port number to get the real IRQ +#define AVR_IOCTL_USB_WRITE AVR_IOCTL_DEF('u','s','b','w') +#define AVR_IOCTL_USB_READ AVR_IOCTL_DEF('u','s','b','r') +#define AVR_IOCTL_USB_SETUP AVR_IOCTL_DEF('u','s','b','s') +#define AVR_IOCTL_USB_RESET AVR_IOCTL_DEF('u','s','b','R') +#define AVR_IOCTL_USB_VBUS AVR_IOCTL_DEF('u','s','b','V') +#define AVR_IOCTL_USB_GETIRQ() AVR_IOCTL_DEF('u','s','b',' ') + +struct avr_io_usb { + uint8_t pipe; //[in] + uint32_t sz; //[in/out] + uint8_t * buf; //[in/out] +}; +#define AVR_IOCTL_USB_NAK -2 +#define AVR_IOCTL_USB_STALL -3 +#define AVR_IOCTL_USB_OK 0 + +typedef struct avr_usb_t { + avr_io_t io; + char name; + avr_regbit_t disabled; // bit in the PRR + avr_regbit_t usbrf; // bit in the MCUSR + avr_io_addr_t r_usbcon; // every usb reg is an offset of this. + avr_io_addr_t r_pllcsr; + + + uint8_t usb_com_vect; + uint8_t usb_gen_vect; + + struct usb_internal_state * state; +} avr_usb_t; + +void avr_usb_init(avr_t * avr, avr_usb_t * port); + +#ifdef __cplusplus +}; +#endif + +#endif /*__AVR_USB_H__*/ diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_watchdog.c b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_watchdog.c new file mode 100644 index 0000000..b7a5d01 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_watchdog.c @@ -0,0 +1,231 @@ +/* + avr_watchdog.c + + Copyright 2008, 2009 Michel Pollet + + 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 "avr_watchdog.h" + +static void avr_watchdog_run_callback_software_reset(avr_t * avr) +{ + avr_reset(avr); +} + +static avr_cycle_count_t avr_watchdog_timer( + struct avr_t * avr, avr_cycle_count_t when, void * param) +{ + avr_watchdog_t * p = (avr_watchdog_t *)param; + + if (avr_regbit_get(avr, p->watchdog.enable)) { + AVR_LOG(avr, LOG_TRACE, "WATCHDOG: timer fired.\n"); + avr_raise_interrupt(avr, &p->watchdog); + return when + p->cycle_count; + } else if (avr_regbit_get(avr, p->wde)) { + AVR_LOG(avr, LOG_TRACE, + "WATCHDOG: timer fired without interrupt. Resetting\n"); + + p->reset_context.avr_run = avr->run; + p->reset_context.wdrf = 1; + + /* Ideally we would perform a reset here via 'avr_reset' + * However, returning after reset would result in an unconsistent state. + * It seems our best (and cleanest) solution is to set a temporary call + * back which can safely perform the reset for us... During reset, + * the previous callback can be restored and safely resume. + */ + avr->run = avr_watchdog_run_callback_software_reset; + } + + return 0; +} + +static avr_cycle_count_t avr_wdce_clear( + struct avr_t * avr, avr_cycle_count_t when, void * param) +{ + avr_watchdog_t * p = (avr_watchdog_t *)param; + avr_regbit_clear(p->io.avr, p->wdce); + return 0; +} + +static void avr_watchdog_set_cycle_count_and_timer( + avr_t * avr, + avr_watchdog_t * p, + uint8_t was_enabled, + int8_t old_wdp) +{ + // If nothing else, always ensure we have a valid cycle count... + uint8_t wdp = avr_regbit_get_array(avr, p->wdp, 4); + + p->cycle_count = 2048 << wdp; + p->cycle_count = (p->cycle_count * avr->frequency) / 128000; + + uint8_t wde = avr_regbit_get(avr, p->wde); + uint8_t wdie = avr_regbit_get(avr, p->watchdog.enable); + + uint8_t enable_changed = (was_enabled != (wde || wdie)); + + uint8_t wdp_changed = ((old_wdp >= 0) ? (wdp != old_wdp) : 0); + + if (!enable_changed && !wdp_changed) + return; + + static char *message[2][2] = { + { 0, "reset" }, { "enabled", "enabled and set" } }; + + if (wde || wdie) { + AVR_LOG(avr, LOG_TRACE, + "WATCHDOG: %s to %d cycles @ 128kz (* %d) = %d CPU cycles.\n", + message[enable_changed][wdp_changed], 2048 << wdp, + 1 << wdp, (int)p->cycle_count); + + avr_cycle_timer_register(avr, p->cycle_count, avr_watchdog_timer, p); + } else if (enable_changed) { + AVR_LOG(avr, LOG_TRACE, "WATCHDOG: disabled\n"); + avr_cycle_timer_cancel(avr, avr_watchdog_timer, p); + } +} + +static void avr_watchdog_write( + avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) +{ + avr_watchdog_t * p = (avr_watchdog_t *)param; + + uint8_t old_wde = avr_regbit_get(avr, p->wde); + uint8_t old_wdie = avr_regbit_get(avr, p->watchdog.enable); + uint8_t old_wdce = avr_regbit_get(avr, p->wdce); + + uint8_t was_enabled = (old_wde || old_wdie); + + uint8_t old_v = avr->data[addr]; // allow gdb to see write... + avr_core_watch_write(avr, addr, v); + + if (old_wdce) { + uint8_t old_wdp = avr_regbit_get_array(avr, p->wdp, 4); + + // wdrf (watchdog reset flag) must be cleared before wde can be cleared. + if (avr_regbit_get(avr, p->wdrf)) + avr_regbit_set(avr, p->wde); + + avr_watchdog_set_cycle_count_and_timer(avr, p, was_enabled, old_wdp); + } else { + /* easier to change only what we need rather than check and reset + * locked/read-only bits. + */ + avr->data[addr] = old_v; + + uint8_t wdce_v = avr_regbit_from_value(avr, p->wdce, v); + uint8_t wde_v = avr_regbit_from_value(avr, p->wde, v); + + if (wdce_v && wde_v) { + avr_regbit_set(avr, p->wdce); + + avr_cycle_timer_register(avr, 4, avr_wdce_clear, p); + } else { + if (wde_v) // wde can be set but not cleared + avr_regbit_set(avr, p->wde); + + avr_regbit_setto_raw(avr, p->watchdog.enable, v); + + avr_watchdog_set_cycle_count_and_timer(avr, p, was_enabled, -1); + } + } +} + +/* + * called by the core when a WTD instruction is found + */ +static int avr_watchdog_ioctl( + struct avr_io_t * port, uint32_t ctl, void * io_param) +{ + avr_watchdog_t * p = (avr_watchdog_t *)port; + int res = -1; + + if (ctl == AVR_IOCTL_WATCHDOG_RESET) { + if (avr_regbit_get(p->io.avr, p->wde) || + avr_regbit_get(p->io.avr, p->watchdog.enable)) + avr_cycle_timer_register(p->io.avr, p->cycle_count, + avr_watchdog_timer, p); + res = 0; + } + + return res; +} + +static void avr_watchdog_irq_notify( + struct avr_irq_t * irq, + uint32_t value, + void * param) +{ + avr_watchdog_t * p = (avr_watchdog_t *)param; + avr_t * avr = p->io.avr; + + /* interrupt handling calls this twice... + * first when raised (during queuing), value = 1 + * again when cleared (after servicing), value = 0 + */ + + if (!value && avr_regbit_get(avr, p->watchdog.raised) && avr_regbit_get(avr, p->wde)) { + avr_regbit_clear(avr, p->watchdog.enable); + } +} + +static void avr_watchdog_reset(avr_io_t * port) +{ + avr_watchdog_t * p = (avr_watchdog_t *)port; + avr_t * avr = p->io.avr; + + if (p->reset_context.wdrf) { + p->reset_context.wdrf = 0; + /* + * if watchdog reset kicked, then watchdog gets restarted at + * fastest interval + */ + avr->run = p->reset_context.avr_run; + + avr_regbit_set(avr, p->wde); + avr_regbit_set(avr, p->wdrf); + avr_regbit_set_array_from_value(avr, p->wdp, 4, 0); + + avr_watchdog_set_cycle_count_and_timer(avr, p, 0, 0); + } + /* TODO could now use the two pending/running IRQs to do the same + * as before */ + avr_irq_register_notify(p->watchdog.irq, avr_watchdog_irq_notify, p); +} + +static avr_io_t _io = { + .kind = "watchdog", + .reset = avr_watchdog_reset, + .ioctl = avr_watchdog_ioctl, +}; + +void avr_watchdog_init(avr_t * avr, avr_watchdog_t * p) +{ + p->io = _io; + + avr_register_io(avr, &p->io); + avr_register_vector(avr, &p->watchdog); + + avr_register_io_write(avr, p->wdce.reg, avr_watchdog_write, p); + + p->reset_context.wdrf = 0; +} + diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_watchdog.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_watchdog.h new file mode 100644 index 0000000..da86371 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/avr_watchdog.h @@ -0,0 +1,96 @@ +/* + avr_watchdog.h + + Copyright 2008, 2009 Michel Pollet + + 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 . + */ + + +#ifndef __AVR_WATCHDOG_H___ +#define __AVR_WATCHDOG_H___ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "sim_avr.h" + +typedef struct avr_watchdog_t { + avr_io_t io; + + avr_regbit_t wdrf; // watchdog reset flag (in MCU Status Register) + + avr_regbit_t wdce; // watchdog change enable + avr_regbit_t wde; // watchdog enabled + avr_regbit_t wdp[4]; // watchdog Timer Prescaler + + avr_int_vector_t watchdog; // watchdog interrupt + + avr_cycle_count_t cycle_count; + + struct { + uint8_t wdrf; // saved watchdog reset flag + avr_run_t avr_run; // restored during reset + } reset_context; +} avr_watchdog_t; + +/* takes no parameter */ +#define AVR_IOCTL_WATCHDOG_RESET AVR_IOCTL_DEF('w','d','t','r') + +void avr_watchdog_init(avr_t * avr, avr_watchdog_t * p); + + +/* + * This helps declare a watchdog block into a core. + * No guarantee it will work with all, but it works + * with the one we have right now + */ +#define AVR_WATCHDOG_DECLARE(_WDSR, _vec) \ + .watchdog = {\ + .wdrf = AVR_IO_REGBIT(MCUSR, WDRF),\ + .wdce = AVR_IO_REGBIT(_WDSR, WDCE),\ + .wde = AVR_IO_REGBIT(_WDSR, WDE),\ + .wdp = { AVR_IO_REGBIT(_WDSR, WDP0),AVR_IO_REGBIT(_WDSR, WDP1),\ + AVR_IO_REGBIT(_WDSR, WDP2),AVR_IO_REGBIT(_WDSR, WDP3) },\ + .watchdog = {\ + .enable = AVR_IO_REGBIT(_WDSR, WDIE),\ + .raised = AVR_IO_REGBIT(_WDSR, WDIF),\ + .vector = _vec,\ + },\ + } + +/* no WDP3, WDIE, WDIF in atmega128 */ +/* MCUSR is called MCUCSR in atmega128 */ +#define AVR_WATCHDOG_DECLARE_128(_WDSR, _vec) \ + .watchdog = {\ + .wdrf = AVR_IO_REGBIT(MCUCSR, WDRF),\ + .wdce = AVR_IO_REGBIT(_WDSR, WDCE),\ + .wde = AVR_IO_REGBIT(_WDSR, WDE),\ + .wdp = { AVR_IO_REGBIT(_WDSR, WDP0),AVR_IO_REGBIT(_WDSR, WDP1),\ + AVR_IO_REGBIT(_WDSR, WDP2) },\ + .watchdog = {\ + .enable = AVR_IO_REGBIT(_WDSR, 6),\ + .raised = AVR_IO_REGBIT(_WDSR, 7),\ + .vector = _vec,\ + },\ + } + +#ifdef __cplusplus +}; +#endif + +#endif /* __AVR_WATCHDOG_H___ */ diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/fifo_declare.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/fifo_declare.h new file mode 100644 index 0000000..8a3b2fb --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/fifo_declare.h @@ -0,0 +1,189 @@ +/* + fido_declare.h + Copyright (C) 2003-2012 Michel Pollet + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* + * FIFO helpers, aka circular buffers + * + * these macros define accessories for FIFOs of any name, type and + * any (power of two) size + */ + +#ifndef __FIFO_DECLARE__ +#define __FIFO_DECLARE__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + doing a : + DECLARE_FIFO(uint8_t, myfifo, 128); + + will declare : + enum : myfifo_overflow_f + type : myfifo_t + functions: + // write a byte into the fifo, return 1 if there was room, 0 if there wasn't + int myfifo_write(myfifo_t *c, uint8_t b); + // reads a byte from the fifo, return 0 if empty. Use myfifo_isempty() to check beforehand + uint8_t myfifo_read(myfifo_t *c); + int myfifo_isfull(myfifo_t *c); + int myfifo_isempty(myfifo_t *c); + // returns number of items to read now + uint16_t myfifo_get_read_size(myfifo_t *c); + // read item at offset o from read cursor, no cursor advance + uint8_t myfifo_read_at(myfifo_t *c, uint16_t o); + // write b at offset o compared to current write cursor, no cursor advance + void myfifo_write_at(myfifo_t *c, uint16_t o, uint8_t b); + + In your .c you need to 'implement' the fifo: + DEFINE_FIFO(uint8_t, myfifo) + + To use the fifo, you must declare at least one : + myfifo_t fifo = FIFO_NULL; + + while (!myfifo_isfull(&fifo)) + myfifo_write(&fifo, 0xaa); + .... + while (!myfifo_isempty(&fifo)) + b = myfifo_read(&fifo); + */ + +#include + +#if __AVR__ +#define FIFO_CURSOR_TYPE uint8_t +#define FIFO_BOOL_TYPE char +#define FIFO_INLINE +#define FIFO_SYNC +#endif + +#ifndef FIFO_CURSOR_TYPE +#define FIFO_CURSOR_TYPE uint16_t +#endif +#ifndef FIFO_BOOL_TYPE +#define FIFO_BOOL_TYPE int +#endif +#ifndef FIFO_INLINE +#define FIFO_INLINE inline +#endif + +/* We should not need volatile */ +#ifndef FIFO_VOLATILE +#define FIFO_VOLATILE +#endif +#ifndef FIFO_SYNC +#define FIFO_SYNC __sync_synchronize() +#endif + +#ifndef FIFO_ZERO_INIT +#define FIFO_ZERO_INIT {0} +#endif +#define FIFO_NULL { FIFO_ZERO_INIT, 0, 0, 0 } + +/* New compilers don't like unused static functions. However, + * we do like 'static inlines' for these small accessors, + * so we mark them as 'unused'. It stops it complaining */ +#ifdef __GNUC__ +#define FIFO_DECL static __attribute__ ((unused)) +#else +#define FIFO_DECL static +#endif + +#define DECLARE_FIFO(__type, __name, __size) \ +enum { __name##_overflow_f = (1 << 0) }; \ +enum { __name##_fifo_size = (__size) }; \ +typedef struct __name##_t { \ + __type buffer[__name##_fifo_size]; \ + FIFO_VOLATILE FIFO_CURSOR_TYPE read; \ + FIFO_VOLATILE FIFO_CURSOR_TYPE write; \ + FIFO_VOLATILE uint8_t flags; \ +} __name##_t + +#define DEFINE_FIFO(__type, __name) \ +FIFO_DECL FIFO_INLINE FIFO_BOOL_TYPE __name##_write(__name##_t * c, __type b)\ +{\ + FIFO_CURSOR_TYPE now = c->write;\ + FIFO_CURSOR_TYPE next = (now + 1) & (__name##_fifo_size-1);\ + if (c->read != next) { \ + c->buffer[now] = b;\ + FIFO_SYNC; \ + c->write = next;\ + return 1;\ + }\ + return 0;\ +}\ +FIFO_DECL FIFO_INLINE FIFO_BOOL_TYPE __name##_isfull(__name##_t *c)\ +{\ + FIFO_CURSOR_TYPE next = (c->write + 1) & (__name##_fifo_size-1);\ + return c->read == next;\ +}\ +FIFO_DECL FIFO_INLINE FIFO_BOOL_TYPE __name##_isempty(__name##_t * c)\ +{\ + return c->read == c->write;\ +}\ +FIFO_DECL FIFO_INLINE __type __name##_read(__name##_t * c)\ +{\ + __type res = FIFO_ZERO_INIT; \ + FIFO_CURSOR_TYPE read = c->read;\ + if (read == c->write)\ + return res;\ + res = c->buffer[read];\ + FIFO_SYNC; \ + c->read = (read + 1) & (__name##_fifo_size-1);\ + return res;\ +}\ +FIFO_DECL FIFO_INLINE FIFO_CURSOR_TYPE __name##_get_read_size(__name##_t *c)\ +{\ + return ((c->write + __name##_fifo_size) - c->read) & (__name##_fifo_size-1);\ +}\ +FIFO_DECL FIFO_INLINE FIFO_CURSOR_TYPE __name##_get_write_size(__name##_t *c)\ +{\ + return (__name##_fifo_size-1) - __name##_get_read_size(c);\ +}\ +FIFO_DECL FIFO_INLINE void __name##_read_offset(__name##_t *c, FIFO_CURSOR_TYPE o)\ +{\ + FIFO_SYNC; \ + c->read = (c->read + o) & (__name##_fifo_size-1);\ +}\ +FIFO_DECL FIFO_INLINE __type __name##_read_at(__name##_t *c, FIFO_CURSOR_TYPE o)\ +{\ + return c->buffer[(c->read + o) & (__name##_fifo_size-1)];\ +}\ +FIFO_DECL FIFO_INLINE void __name##_write_at(__name##_t *c, FIFO_CURSOR_TYPE o, __type b)\ +{\ + c->buffer[(c->write + o) & (__name##_fifo_size-1)] = b;\ +}\ +FIFO_DECL FIFO_INLINE void __name##_write_offset(__name##_t *c, FIFO_CURSOR_TYPE o)\ +{\ + FIFO_SYNC; \ + c->write = (c->write + o) & (__name##_fifo_size-1);\ +}\ +FIFO_DECL FIFO_INLINE void __name##_reset(__name##_t *c)\ +{\ + FIFO_SYNC; \ + c->read = c->write = c->flags = 0;\ +}\ +struct __name##_t + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/run_avr.c b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/run_avr.c new file mode 100644 index 0000000..dfa6fce --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/run_avr.c @@ -0,0 +1,287 @@ +/* + run_avr.c + + Copyright 2008, 2010 Michel Pollet + + 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 +#include +#include +#include "sim_avr.h" +#include "sim_elf.h" +#include "sim_core.h" +#include "sim_gdb.h" +#include "sim_hex.h" +#include "sim_vcd_file.h" + +#include "sim_core_decl.h" + +static void +display_usage( + const char * app) +{ + printf("Usage: %s [...] \n", app); + printf( + " [--help|-h|-?] Display this usage message and exit\n" + " [--list-cores] List all supported AVR cores and exit\n" + " [-v] Raise verbosity level\n" + " (can be passed more than once)\n" + " [--freq|-f ] Sets the frequency for an .hex firmware\n" + " [--mcu|-m ] Sets the MCU type for an .hex firmware\n" + " [--gdb|-g []] Listen for gdb connection on " + "(default 1234)\n" +#ifdef CONFIG_SIMAVR_TRACE + " [--trace, -t] Run full scale decoder trace\n" +#else + " [--trace, -t] Run full scale decoder trace (Off)\n" +#endif //CONFIG_SIMAVR_TRACE + " [-ti ] Add traces for IRQ vector \n" + " [--input|-i ] A VCD file to use as input signals\n" + " [--output|-o ] A VCD file to save the traced signals\n" + " [--add-trace|-at ]\n" + " Add signal to be included in VCD output\n" + " [-ff <.hex file>] Load next .hex file as flash\n" + " [-ee <.hex file>] Load next .hex file as eeprom\n" + " A .hex or an ELF file. ELF files are\n" + " preferred, and can include " + "debugging syms\n"); + exit(1); +} + +static void +list_cores() +{ + printf( "Supported AVR cores:\n"); + for (int i = 0; avr_kind[i]; i++) { + printf(" "); + for (int ti = 0; ti < 4 && avr_kind[i]->names[ti]; ti++) + printf("%s ", avr_kind[i]->names[ti]); + printf("\n"); + } + exit(1); +} + +static avr_t * avr = NULL; + +static void +sig_int( + int sign) +{ + printf("signal caught, simavr terminating\n"); + if (avr) + avr_terminate(avr); + exit(0); +} + +int +main( + int argc, + char *argv[]) +{ +#ifdef CONFIG_SIMAVR_TRACE + int trace = 0; +#endif //CONFIG_SIMAVR_TRACE + elf_firmware_t f = {{0}}; + uint32_t f_cpu = 0; + int gdb = 0; + int log = 1; + int port = 1234; + char name[24] = ""; + uint32_t loadBase = AVR_SEGMENT_OFFSET_FLASH; + int trace_vectors[8] = {0}; + int trace_vectors_count = 0; + const char *vcd_input = NULL; + + if (argc == 1) + display_usage(basename(argv[0])); + + for (int pi = 1; pi < argc; pi++) { + if (!strcmp(argv[pi], "--list-cores")) { + list_cores(); + } else if (!strcmp(argv[pi], "-h") || !strcmp(argv[pi], "--help")) { + display_usage(basename(argv[0])); + } else if (!strcmp(argv[pi], "-m") || !strcmp(argv[pi], "--mcu")) { + if (pi < argc-1) { + snprintf(name, sizeof(name), "%s", argv[++pi]); + strcpy(f.mmcu, name); + } else { + display_usage(basename(argv[0])); + } + } else if (!strcmp(argv[pi], "-f") || !strcmp(argv[pi], "--freq")) { + if (pi < argc-1) { + f_cpu = atoi(argv[++pi]); + f.frequency = f_cpu; + } else { + display_usage(basename(argv[0])); + } + } else if (!strcmp(argv[pi], "-i") || !strcmp(argv[pi], "--input")) { + if (pi < argc-1) + vcd_input = argv[++pi]; + else + display_usage(basename(argv[0])); + } else if (!strcmp(argv[pi], "-o") || + !strcmp(argv[pi], "--output")) { + if (pi + 1 >= argc) { + fprintf(stderr, "%s: missing mandatory argument for %s.\n", argv[0], argv[pi]); + exit(1); + } + snprintf(f.tracename, sizeof(f.tracename), "%s", argv[++pi]); + } else if (!strcmp(argv[pi], "-t") || + !strcmp(argv[pi], "--trace")) { +#ifdef CONFIG_SIMAVR_TRACE + trace++; +#else + fprintf(stderr, + "%s: tracing option '%s' requires " + "compilation option CONFIG_SIMAVR_TRACE.\n", + argv[0], argv[pi]); +#endif //CONFIG_SIMAVR_TRACE + } else if (!strcmp(argv[pi], "-at") || + !strcmp(argv[pi], "--add-trace")) { + if (pi + 1 >= argc) { + fprintf(stderr, "%s: missing mandatory argument for %s.\n", argv[0], argv[pi]); + exit(1); + } + ++pi; + struct { + char kind[64]; + uint8_t mask; + uint16_t addr; + char name[64]; + } trace; + const int n_args = sscanf( + argv[pi], + "%63[^=]=%63[^@]@0x%hx/0x%hhx", + &trace.name[0], + &trace.kind[0], + &trace.addr, + &trace.mask + ); + if (n_args != 4) { + --pi; + fprintf(stderr, "%s: format for %s is name=kind@addr/mask.\n", argv[0], argv[pi]); + exit(1); + } + + /****/ if (!strcmp(trace.kind, "portpin")) { + f.trace[f.tracecount].kind = AVR_MMCU_TAG_VCD_PORTPIN; + } else if (!strcmp(trace.kind, "irq")) { + f.trace[f.tracecount].kind = AVR_MMCU_TAG_VCD_IRQ; + } else if (!strcmp(trace.kind, "trace")) { + f.trace[f.tracecount].kind = AVR_MMCU_TAG_VCD_TRACE; + } else { + fprintf( + stderr, + "%s: unknown trace kind '%s', not one of 'portpin', 'irq', or 'trace'.\n", + argv[0], + trace.kind + ); + exit(1); + } + f.trace[f.tracecount].mask = trace.mask; + f.trace[f.tracecount].addr = trace.addr; + strncpy(f.trace[f.tracecount].name, trace.name, sizeof(f.trace[f.tracecount].name)); + + printf( + "Adding %s trace on address 0x%04x, mask 0x%02x ('%s')\n", + f.trace[f.tracecount].kind == AVR_MMCU_TAG_VCD_PORTPIN ? "portpin" + : f.trace[f.tracecount].kind == AVR_MMCU_TAG_VCD_IRQ ? "irq" + : f.trace[f.tracecount].kind == AVR_MMCU_TAG_VCD_TRACE ? "trace" + : "unknown", + f.trace[f.tracecount].addr, + f.trace[f.tracecount].mask, + f.trace[f.tracecount].name + ); + + ++f.tracecount; + } else if (!strcmp(argv[pi], "-ti")) { + if (pi < argc-1) + trace_vectors[trace_vectors_count++] = atoi(argv[++pi]); + } else if (!strcmp(argv[pi], "-g") || + !strcmp(argv[pi], "--gdb")) { + gdb++; + if (pi < (argc-2) && argv[pi+1][0] != '-' ) + port = atoi(argv[++pi]); + } else if (!strcmp(argv[pi], "-v")) { + log++; + } else if (!strcmp(argv[pi], "-ee")) { + loadBase = AVR_SEGMENT_OFFSET_EEPROM; + } else if (!strcmp(argv[pi], "-ff")) { + loadBase = AVR_SEGMENT_OFFSET_FLASH; + } else if (argv[pi][0] != '-') { + sim_setup_firmware(argv[pi], loadBase, &f, argv[0]); + } + } + + // Frequency and MCU type were set early so they can be checked when + // loading a hex file. Set them again because they can also be set + // in an ELF firmware file. + + if (strlen(name)) + strcpy(f.mmcu, name); + if (f_cpu) + f.frequency = f_cpu; + + avr = avr_make_mcu_by_name(f.mmcu); + if (!avr) { + fprintf(stderr, "%s: AVR '%s' not known\n", argv[0], f.mmcu); + exit(1); + } + avr_init(avr); + avr->log = (log > LOG_TRACE ? LOG_TRACE : log); +#ifdef CONFIG_SIMAVR_TRACE + avr->trace = trace; +#endif //CONFIG_SIMAVR_TRACE + + avr_load_firmware(avr, &f); + if (f.flashbase) { + printf("Attempted to load a bootloader at %04x\n", f.flashbase); + avr->pc = f.flashbase; + } + for (int ti = 0; ti < trace_vectors_count; ti++) { + for (int vi = 0; vi < avr->interrupts.vector_count; vi++) + if (avr->interrupts.vector[vi]->vector == trace_vectors[ti]) + avr->interrupts.vector[vi]->trace = 1; + } + if (vcd_input) { + static avr_vcd_t input; + if (avr_vcd_init_input(avr, vcd_input, &input)) { + fprintf(stderr, "%s: Warning: VCD input file %s failed\n", argv[0], vcd_input); + } + } + + // even if not setup at startup, activate gdb if crashing + avr->gdb_port = port; + if (gdb) { + avr->state = cpu_Stopped; + avr_gdb_init(avr); + } + + signal(SIGINT, sig_int); + signal(SIGTERM, sig_int); + + for (;;) { + int state = avr_run(avr); + if (state == cpu_Done || state == cpu_Crashed) + break; + } + + avr_terminate(avr); +} diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_avr.c b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_avr.c new file mode 100644 index 0000000..24cb244 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_avr.c @@ -0,0 +1,453 @@ +/* + sim_avr.c + + Copyright 2008, 2009 Michel Pollet + + 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 +#include +#include +#include +#include +#include "sim_avr.h" +#include "sim_core.h" +#include "sim_time.h" +#include "sim_gdb.h" +#include "avr_uart.h" +#include "sim_vcd_file.h" +#include "avr/avr_mcu_section.h" + +#define AVR_KIND_DECL +#include "sim_core_decl.h" + +static void +std_logger( + avr_t * avr, + const int level, + const char * format, + va_list ap); +static avr_logger_p _avr_global_logger = std_logger; + +void +avr_global_logger( + struct avr_t* avr, + const int level, + const char * format, + ... ) +{ + va_list args; + va_start(args, format); + if (_avr_global_logger) + _avr_global_logger(avr, level, format, args); + va_end(args); +} + +void +avr_global_logger_set( + avr_logger_p logger) +{ + _avr_global_logger = logger ? logger : std_logger; +} + +avr_logger_p +avr_global_logger_get(void) +{ + return _avr_global_logger; +} + +uint64_t +avr_get_time_stamp( + avr_t * avr ) +{ + uint64_t stamp; +#ifndef CLOCK_MONOTONIC_RAW + /* CLOCK_MONOTONIC_RAW isn't portable, here is the POSIX alternative. + * Only downside is that it will drift if the system clock changes */ + struct timeval tv; + gettimeofday(&tv, NULL); + stamp = (((uint64_t)tv.tv_sec) * 1E9) + (tv.tv_usec * 1000); +#else + struct timespec tp; + clock_gettime(CLOCK_MONOTONIC_RAW, &tp); + stamp = (tp.tv_sec * 1E9) + tp.tv_nsec; +#endif + if (!avr->time_base) + avr->time_base = stamp; + return stamp - avr->time_base; +} + +int +avr_init( + avr_t * avr) +{ + avr->flash = malloc(avr->flashend + 4); + memset(avr->flash, 0xff, avr->flashend + 1); + *((uint16_t*)&avr->flash[avr->flashend + 1]) = AVR_OVERFLOW_OPCODE; + avr->codeend = avr->flashend; + avr->data = malloc(avr->ramend + 1); + memset(avr->data, 0, avr->ramend + 1); +#ifdef CONFIG_SIMAVR_TRACE + avr->trace_data = calloc(1, sizeof(struct avr_trace_data_t)); +#endif + + AVR_LOG(avr, LOG_TRACE, "%s init\n", avr->mmcu); + + // 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); + if (avr->init) + avr->init(avr); + // set default (non gdb) fast callbacks + avr->run = avr_callback_run_raw; + avr->sleep = avr_callback_sleep_raw; + // number of address bytes to push/pull on/off the stack + avr->address_size = avr->eind ? 3 : 2; + avr->log = 1; + avr_reset(avr); + avr_regbit_set(avr, avr->reset_flags.porf); // by default set to power-on reset + return 0; +} + +void +avr_terminate( + avr_t * avr) +{ + if (avr->custom.deinit) + avr->custom.deinit(avr, avr->custom.data); + if (avr->gdb) { + avr_deinit_gdb(avr); + avr->gdb = NULL; + } + if (avr->vcd) { + avr_vcd_close(avr->vcd); + avr->vcd = NULL; + } + avr_deallocate_ios(avr); + + if (avr->flash) free(avr->flash); + if (avr->data) free(avr->data); + if (avr->io_console_buffer.buf) { + avr->io_console_buffer.len = 0; + avr->io_console_buffer.size = 0; + free(avr->io_console_buffer.buf); + avr->io_console_buffer.buf = NULL; + } + avr->flash = avr->data = NULL; +} + +void +avr_reset( + avr_t * avr) +{ + AVR_LOG(avr, LOG_TRACE, "%s reset\n", avr->mmcu); + + avr->state = cpu_Running; + for(int i = 0x20; i <= avr->ioend; i++) + avr->data[i] = 0; + _avr_sp_set(avr, avr->ramend); + avr->pc = avr->reset_pc; // Likely to be zero + for (int i = 0; i < 8; i++) + avr->sreg[i] = 0; + avr_interrupt_reset(avr); + avr_cycle_timer_reset(avr); + if (avr->reset) + avr->reset(avr); + avr_io_t * port = avr->io_port; + while (port) { + if (port->reset) + port->reset(port); + port = port->next; + } + avr->cycle = 0; // Prevent crash +} + +void +avr_sadly_crashed( + avr_t *avr, + uint8_t signal) +{ + AVR_LOG(avr, LOG_ERROR, "%s\n", __FUNCTION__); + avr->state = cpu_Stopped; + if (avr->gdb_port) { + // enable gdb server, and wait + if (!avr->gdb) + avr_gdb_init(avr); + } + if (!avr->gdb) + avr->state = cpu_Crashed; +} + +void +avr_set_command_register( + avr_t * avr, + avr_io_addr_t addr) +{ + 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) +{ + if (v == '\r' && avr->io_console_buffer.buf) { + avr->io_console_buffer.buf[avr->io_console_buffer.len] = 0; + AVR_LOG(avr, LOG_OUTPUT, "O:" "%s" "" "\n", + avr->io_console_buffer.buf); + avr->io_console_buffer.len = 0; + return; + } + if (avr->io_console_buffer.len + 1 >= avr->io_console_buffer.size) { + avr->io_console_buffer.size += 128; + avr->io_console_buffer.buf = (char*)realloc( + avr->io_console_buffer.buf, + avr->io_console_buffer.size); + } + if (v >= ' ') + avr->io_console_buffer.buf[avr->io_console_buffer.len++] = v; +} + +void +avr_set_console_register( + avr_t * avr, + avr_io_addr_t addr) +{ + if (addr) + avr_register_io_write(avr, addr, _avr_io_console_write, NULL); +} + +void +avr_loadcode( + avr_t * avr, + uint8_t * code, + uint32_t size, + avr_flashaddr_t address) +{ + if ((address + size) > avr->flashend+1) { + AVR_LOG(avr, LOG_ERROR, "avr_loadcode(): Attempted to load code of size %d but flash size is only %d.\n", + size, avr->flashend + 1); + abort(); + } + memcpy(avr->flash + address, code, size); +} + +/** + * Accumulates sleep requests (and returns a sleep time of 0) until + * a minimum count of requested sleep microseconds are reached + * (low amounts cannot be handled accurately). + */ +uint32_t +avr_pending_sleep_usec( + avr_t * avr, + avr_cycle_count_t howLong) +{ + avr->sleep_usec += avr_cycles_to_usec(avr, howLong); + uint32_t usec = avr->sleep_usec; + if (usec > 200) { + avr->sleep_usec = 0; + return usec; + } + return 0; +} + +void +avr_callback_sleep_gdb( + avr_t * avr, + avr_cycle_count_t howLong) +{ + uint32_t usec = avr_pending_sleep_usec(avr, howLong); + while (avr_gdb_processor(avr, usec)) + ; +} + +void +avr_callback_run_gdb( + avr_t * avr) +{ + avr_gdb_processor(avr, avr->state == cpu_Stopped ? 50000 : 0); + + if (avr->state == cpu_Stopped) + return ; + + // if we are stepping one instruction, we "run" for one.. + int step = avr->state == cpu_Step; + if (step) + avr->state = cpu_Running; + + avr_flashaddr_t new_pc = avr->pc; + + if (avr->state == cpu_Running) { + new_pc = avr_run_one(avr); +#if CONFIG_SIMAVR_TRACE + avr_dump_state(avr); +#endif + } + + // run the cycle timers, get the suggested sleep time + // until the next timer is due + avr_cycle_count_t sleep = avr_cycle_timer_process(avr); + + avr->pc = new_pc; + + if (avr->state == cpu_Sleeping) { + if (!avr->sreg[S_I]) { + if (avr->log) + AVR_LOG(avr, LOG_TRACE, "simavr: sleeping with interrupts off, quitting gracefully\n"); + avr->state = cpu_Done; + return; + } + /* + * try to sleep for as long as we can (?) + */ + avr->sleep(avr, sleep); + avr->cycle += 1 + sleep; + } + // Interrupt servicing might change the PC too, during 'sleep' + if (avr->state == cpu_Running || avr->state == cpu_Sleeping) + avr_service_interrupts(avr); + + // if we were stepping, use this state to inform remote gdb + if (step) + avr->state = cpu_StepDone; +} + +/* +To avoid simulated time and wall clock time to diverge over time +this function tries to keep them in sync (roughly) by sleeping +for the time required to match the expected sleep deadline +in wall clock time. +*/ +void +avr_callback_sleep_raw( + avr_t *avr, + avr_cycle_count_t how_long) +{ + /* figure out how long we should wait to match the sleep deadline */ + uint64_t deadline_ns = avr_cycles_to_nsec(avr, avr->cycle + how_long); + uint64_t runtime_ns = avr_get_time_stamp(avr); + if (runtime_ns >= deadline_ns) + return; + uint64_t sleep_us = (deadline_ns - runtime_ns) / 1000; + usleep(sleep_us); + return; +} + +void +avr_callback_run_raw( + avr_t * avr) +{ + avr_flashaddr_t new_pc = avr->pc; + + if (avr->state == cpu_Running) { + new_pc = avr_run_one(avr); +#if CONFIG_SIMAVR_TRACE + avr_dump_state(avr); +#endif + } + + // run the cycle timers, get the suggested sleep time + // until the next timer is due + avr_cycle_count_t sleep = avr_cycle_timer_process(avr); + + avr->pc = new_pc; + + if (avr->state == cpu_Sleeping) { + if (!avr->sreg[S_I]) { + if (avr->log) + AVR_LOG(avr, LOG_TRACE, "simavr: sleeping with interrupts off, quitting gracefully\n"); + avr->state = cpu_Done; + return; + } + /* + * try to sleep for as long as we can (?) + */ + avr->sleep(avr, sleep); + avr->cycle += 1 + sleep; + } + // Interrupt servicing might change the PC too, during 'sleep' + if (avr->state == cpu_Running || avr->state == cpu_Sleeping) { + /* Note: checking interrupt_state here is completely superfluous, however + as interrupt_state tells us all we really need to know, here + a simple check here may be cheaper than a call not needed. */ + if (avr->interrupt_state) + avr_service_interrupts(avr); + } +} + + +int +avr_run( + avr_t * avr) +{ + avr->run(avr); + return avr->state; +} + +avr_t * +avr_core_allocate( + const avr_t * core, + uint32_t coreLen) +{ + uint8_t * b = malloc(coreLen); + memcpy(b, core, coreLen); + return (avr_t *)b; +} + +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) { + AVR_LOG(((avr_t*)0), LOG_ERROR, "%s: AVR '%s' not known\n", __FUNCTION__, name); + return NULL; + } + + avr_t * avr = maker->make(); + AVR_LOG(avr, LOG_TRACE, "Starting %s - flashend %04x ramend %04x e2end %04x\n", + avr->mmcu, avr->flashend, avr->ramend, avr->e2end); + return avr; +} + +static void +std_logger( + avr_t * avr, + const int level, + const char * format, + va_list ap) +{ + if (!avr || avr->log >= level) { + vfprintf((level < LOG_ERROR) ? stdout : stderr, format, ap); + } +} + diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_avr.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_avr.h new file mode 100644 index 0000000..e9a97cd --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_avr.h @@ -0,0 +1,517 @@ +/* + sim_avr.h + + Copyright 2008-2012 Michel Pollet + + 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 . + */ + +#ifndef __SIM_AVR_H__ +#define __SIM_AVR_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __has_attribute + #define __has_attribute(x) 0 +#endif + +#if __has_attribute(fallthrough) + #define FALLTHROUGH __attribute__((fallthrough)); +#else + #define FALLTHROUGH +#endif + +#include "sim_irq.h" +#include "sim_interrupts.h" +#include "sim_cmds.h" +#include "sim_cycle_timers.h" + +typedef uint32_t avr_flashaddr_t; + +struct avr_t; +typedef uint8_t (*avr_io_read_t)( + struct avr_t * avr, + avr_io_addr_t addr, + void * param); +typedef void (*avr_io_write_t)( + struct avr_t * avr, + avr_io_addr_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 registers, on normal AVRs + MAX_IOs = 280, // Bigger AVRs need more than 256-32 (mega1280) +}; + +#define AVR_DATA_TO_IO(v) ((v) - 32) +#define AVR_IO_TO_DATA(v) ((v) + 32) + +/** + * Logging macros and associated log levels. + * The current log level is kept in avr->log. + */ +enum { + LOG_NONE = 0, + LOG_OUTPUT, + LOG_ERROR, + LOG_WARNING, + LOG_TRACE, + LOG_DEBUG, +}; + + +#ifndef AVR_LOG +#define AVR_LOG(avr, level, ...) \ + do { \ + avr_global_logger(avr, level, __VA_ARGS__); \ + } while(0) +#endif +#define AVR_TRACE(avr, ... ) \ + AVR_LOG(avr, LOG_TRACE, __VA_ARGS__) + +/* + * Core states. + */ +enum { + cpu_Limbo = 0, // before initialization is finished + cpu_Stopped, // all is stopped, timers included + + cpu_Running, // we're free running + + cpu_Sleeping, // we're now sleeping until an interrupt + + cpu_Step, // run ONE instruction, then... + cpu_StepDone, // tell gdb it's all OK, and give it registers + cpu_Done, // avr software stopped gracefully + cpu_Crashed, // avr software crashed (watchdog fired) +}; + +// this is only ever used if CONFIG_SIMAVR_TRACE is defined +struct avr_trace_data_t { + 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 which registers gets touched by instructions + // reset before each new instructions. Allows meaningful traces + uint32_t touched[256 / 32]; // debug +}; + +typedef void (*avr_run_t)( + struct avr_t * avr); + +#define AVR_FUSE_LOW 0 +#define AVR_FUSE_HIGH 1 +#define AVR_FUSE_EXT 2 + +#define REG_NAME_COUNT (256 + 32) // Size of reg_names table. + +/* + * 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 ioend; + uint16_t ramend; + uint32_t flashend; + uint32_t e2end; + uint8_t vector_size; + uint8_t signature[3]; + uint8_t fuse[6]; + uint8_t lockbits; + avr_io_addr_t rampz; // optional, only for ELPM/SPM on >64Kb cores + avr_io_addr_t eind; // optional, only for EIJMP/EICALL on >64Kb cores + uint8_t address_size; // 2, or 3 for cores >128KB in flash + struct { + avr_regbit_t porf; + avr_regbit_t extrf; + avr_regbit_t borf; + avr_regbit_t wdrf; + } reset_flags; + + // 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 + // mostly used by the ADC for now + uint32_t vcc,avcc,aref; // (optional) voltages in millivolts + + // cycles gets incremented when sleeping and when running; it corresponds + // not only to "cycles that runs" but also "cycles that might have run" + // like, sleeping. + avr_cycle_count_t cycle; // current cycle + + // these next two allow the core to freely run between cycle timers and also allows + // for a maximum run cycle limit... run_cycle_count is set during cycle timer processing. + avr_cycle_count_t run_cycle_count; // cycles to run before next timer + avr_cycle_count_t run_cycle_limit; // maximum run cycle interval limit + + /** + * Sleep requests are accumulated in sleep_usec until the minimum sleep value + * is reached, at which point sleep_usec is cleared and the sleep request + * is passed on to the operating system. + */ + uint32_t sleep_usec; + uint64_t time_base; // for avr_get_time_stamp() + + // called at init time + void (*init)(struct avr_t * avr); + // called at reset time + void (*reset)(struct avr_t * avr); + + struct { + // called at init time (for special purposes like using a + // memory mapped file as flash see: simduino) + void (*init)(struct avr_t * avr, void * data); + // called at termination time ( to clean special initializations) + void (*deinit)(struct avr_t * avr, void * data); + // value passed to init() and deinit() + void *data; + } custom; + + /*! + * Default AVR core run function. + * Two modes are available, a "raw" run that goes as fast as + * it can, and a "gdb" mode that also watchouts for gdb events + * and is a little bit slower. + */ + avr_run_t run; + + /*! + * Sleep default behaviour. + * In "raw" mode, it calls usleep, in gdb mode, it waits + * for howLong for gdb command on it's sockets. + */ + void (*sleep)(struct avr_t * avr, avr_cycle_count_t howLong); + + /*! + * Every IRQs will be stored in this pool. It is not + * mandatory (yet) but will allow listing IRQs and their connections + */ + avr_irq_pool_t irq_pool; + + // Mirror of the SREG register, to facilitate the access to bits + // in the opcode decoder. + // This array is re-synthesized back/forth when SREG changes + uint8_t sreg[8]; + + /* Interrupt state: + 00: idle (no wait, no pending interrupts) or disabled + <0: wait till zero + >0: interrupt pending */ + int8_t interrupt_state; // interrupt state + + /* + * ** current PC ** + * Note that the PC is representing /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 and <<1 in the decoder to handle jumps. + * It CAN be a little confusing, so concentrate, young grasshopper. + */ + avr_flashaddr_t pc; + /* + * Reset PC, this is the value used to jump to at reset time, this + * allow support for bootloaders + */ + avr_flashaddr_t reset_pc; + + /* + * callback when specific IO registers are read/written. + * There is one drawback here, there is in way of knowing what is the + * "beginning of useful sram" on a core, so there is no way to deduce + * what is the maximum IO register for a core, and thus, we can't + * allocate this table dynamically. + * If you wanted to emulate the BIG AVRs, and XMegas, this would need + * work. + */ + struct { + struct avr_irq_t * irq; // optional, used only if asked for with avr_iomem_getirq() + struct { + void * param; + avr_io_read_t c; + } r; + struct { + void * param; + avr_io_write_t c; + } w; + } io[MAX_IOs]; + + /* + * This block allows sharing of the IO write/read on addresses between + * multiple callbacks. In 99% of case it's not needed, however on the tiny* + * (tiny85 at last) some registers have bits that are used by different + * IO modules. + * If this case is detected, a special "dispatch" callback is installed that + * will handle this particular case, without impacting the performance of the + * other, normal cases... + */ + int io_shared_io_count; + struct { + int used; + struct { + void * param; + void * c; + } io[4]; + } io_shared_io[4]; + + // 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; + + // 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 + avr_int_table_t interrupts; + + // DEBUG ONLY -- value ignored if CONFIG_SIMAVR_TRACE = 0 + uint8_t trace : 1, + log : 4; // log level, default to 1 + + // Only used if CONFIG_SIMAVR_TRACE is defined + struct avr_trace_data_t *trace_data; + + // VALUE CHANGE DUMP file (waveforms) + // this is the VCD file that gets allocated if the + // firmware that is loaded explicitly asks for a trace + // to be generated, and allocates it's own symbols + // using AVR_MMCU_TAG_VCD_TRACE (see avr_mcu_section.h) + struct avr_vcd_t * vcd; + + // 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; + + // buffer for console debugging output from register + struct { + char * buf; + uint32_t size; + uint32_t len; + } io_console_buffer; +} 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)(void); +} avr_kind_t; + +// a symbol loaded from the .elf file +typedef struct avr_symbol_t { + uint32_t addr; + uint32_t size; + const char symbol[0]; +} 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); +// Used by the cores, allocated a mutable avr_t from the const global +avr_t * +avr_core_allocate( + const avr_t * core, + uint32_t coreLen); + +// 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); +// 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); + +// specify the "console register" -- output sent to this register +// is printed on the simulator console, without using a UART +void +avr_set_console_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, + avr_flashaddr_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); + +// called when the core has detected a crash somehow. +// this might activate gdb server +void +avr_sadly_crashed( + avr_t *avr, + uint8_t signal); + +/* + * Logs a message using the current logger + */ +void +avr_global_logger( + struct avr_t* avr, + const int level, + const char * format, + ... ); + +#ifndef AVR_CORE +#include +/* + * Type for custom logging functions + */ +typedef void (*avr_logger_p)(struct avr_t* avr, const int level, const char * format, va_list ap); + +/* Sets a global logging function in place of the default */ +void +avr_global_logger_set( + avr_logger_p logger); +/* Gets the current global logger function */ +avr_logger_p +avr_global_logger_get(void); +#endif + +/* + * These are callbacks for the two 'main' behaviour in simavr + */ +void avr_callback_sleep_gdb(avr_t * avr, avr_cycle_count_t howLong); +void avr_callback_run_gdb(avr_t * avr); +void avr_callback_sleep_raw(avr_t * avr, avr_cycle_count_t howLong); +void avr_callback_run_raw(avr_t * avr); + +/** + * Accumulates sleep requests (and returns a sleep time of 0) until + * a minimum count of requested sleep microseconds are reached + * (low amounts cannot be handled accurately). + * This function is an utility function for the sleep callbacks + */ +uint32_t +avr_pending_sleep_usec( + avr_t * avr, + avr_cycle_count_t howLong); +/* Return the number of 'real time' spent since sim started, in uS */ +uint64_t +avr_get_time_stamp( + avr_t * avr ); + +#ifdef __cplusplus +}; +#endif + +#include "sim_io.h" +#include "sim_regbit.h" + +#ifdef __GNUC__ + +# ifndef likely +# define likely(x) __builtin_expect(!!(x), 1) +# endif + +# ifndef unlikely +# define unlikely(x) __builtin_expect(!!(x), 0) +# endif + +#else /* ! __GNUC__ */ + +# ifndef likely +# define likely(x) x +# endif + +# ifndef unlikely +# define unlikely(x) x +# endif + +#endif /* __GNUC__ */ + +#endif /*__SIM_AVR_H__*/ + diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_avr_types.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_avr_types.h new file mode 100644 index 0000000..b15bafc --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_avr_types.h @@ -0,0 +1,57 @@ +/* + sim_avr_types.h + + Copyright 2008-2012 Michel Pollet + + 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 . + */ + + +#ifndef __SIM_AVR_TYPES_H___ +#define __SIM_AVR_TYPES_H___ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +typedef uint64_t avr_cycle_count_t; +typedef uint16_t avr_io_addr_t; + +/* + * this 'structure' is a packed representation of an IO register 'bit' + * (or consecutive bits). This allows a way to set/get/clear them. + * gcc is happy passing these as register value, so you don't need to + * use a pointer when passing them along to functions. + * + * 9 bits ought to be enough, as it's the maximum I've seen (atmega2560) + */ +typedef struct avr_regbit_t { + uint32_t reg : 9, bit : 3, mask : 8; +} avr_regbit_t; + +// printf() conversion specifier for avr_cycle_count_t +#define PRI_avr_cycle_count PRIu64 + +struct avr_t; + +#ifdef __cplusplus +}; +#endif + +#endif /* __SIM_AVR_TYPES_H___ */ diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_cmds.c b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_cmds.c new file mode 100644 index 0000000..587f259 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_cmds.c @@ -0,0 +1,193 @@ +/* + 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->handler) { + AVR_LOG(avr, LOG_ERROR, LOG_PREFIX + "%s: code 0x%02x has no handler (wrong MMCU config)\n", + __FUNCTION__, v); + return; + } + + 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/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_cmds.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_cmds.h new file mode 100644 index 0000000..aac75fc --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/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 diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_core.c b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_core.c new file mode 100644 index 0000000..ab8015c --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_core.c @@ -0,0 +1,1457 @@ +/* + sim_core.c + + Copyright 2008, 2009 Michel Pollet + + 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 +#include +#include "sim_avr.h" +#include "sim_core.h" +#include "sim_gdb.h" +#include "avr_flash.h" +#include "avr_watchdog.h" + +// SREG bit names +const char * _sreg_bit_name = "cznvshti"; + +/* + * Handle "touching" registers, marking them changed. + * This is used only for debugging purposes to be able to + * print the effects of each instructions on registers + */ +#if CONFIG_SIMAVR_TRACE + +#define T(w) w + +#define REG_TOUCH(a, r) (a)->trace_data->touched[(r) >> 5] |= (1 << ((r) & 0x1f)) +#define REG_ISTOUCHED(a, r) ((a)->trace_data->touched[(r) >> 5] & (1 << ((r) & 0x1f))) + +/* + * This allows a "special case" to skip instruction tracing when in these + * symbols since printf() is useful to have, but generates a lot of cycles. + */ +int dont_trace(const char * name) +{ + return ( + !strcmp(name, "uart_putchar") || + !strcmp(name, "fputc") || + !strcmp(name, "printf") || + !strcmp(name, "vfprintf") || + !strcmp(name, "__ultoa_invert") || + !strcmp(name, "__prologue_saves__") || + !strcmp(name, "__epilogue_restores__")); +} + +int donttrace = 0; + +#define STATE(_f, args...) { \ + if (avr->trace) {\ + if (avr->trace_data->codeline && avr->trace_data->codeline[avr->pc>>1]) {\ + const char * symn = avr->trace_data->codeline[avr->pc>>1]->symbol; \ + int dont = 0 && dont_trace(symn);\ + if (dont!=donttrace) { \ + donttrace = dont;\ + DUMP_REG();\ + }\ + if (donttrace==0)\ + printf("%04x: %-25s " _f, avr->pc, symn, ## args);\ + } else \ + printf("%s: %04x: " _f, __FUNCTION__, avr->pc, ## args);\ + }\ + } +#define SREG() if (avr->trace && donttrace == 0) {\ + printf("%04x: \t\t\t\t\t\t\t\t\tSREG = ", avr->pc); \ + for (int _sbi = 0; _sbi < 8; _sbi++)\ + printf("%c", avr->sreg[_sbi] ? toupper(_sreg_bit_name[_sbi]) : '.');\ + printf("\n");\ +} + +void crash(avr_t* avr) +{ + DUMP_REG(); + printf("*** CYCLE %" PRI_avr_cycle_count "PC %04x\n", avr->cycle, avr->pc); + + for (int i = OLD_PC_SIZE-1; i > 0; i--) { + int pci = (avr->trace_data->old_pci + i) & 0xf; + printf(FONT_RED "*** %04x: %-25s RESET -%d; sp %04x\n" FONT_DEFAULT, + avr->trace_data->old[pci].pc, avr->trace_data->codeline ? avr->trace_data->codeline[avr->trace_data->old[pci].pc>>1]->symbol : "unknown", OLD_PC_SIZE-i, avr->trace_data->old[pci].sp); + } + + printf("Stack Ptr %04x/%04x = %d \n", _avr_sp_get(avr), avr->ramend, avr->ramend - _avr_sp_get(avr)); + DUMP_STACK(); + + avr_sadly_crashed(avr, 0); +} +#else +#define T(w) +#define REG_TOUCH(a, r) +#define STATE(_f, args...) +#define SREG() + +void crash(avr_t* avr) +{ + avr_sadly_crashed(avr, 0); + +} +#endif + +static inline uint16_t +_avr_flash_read16le( + avr_t * avr, + avr_flashaddr_t addr) +{ + return(avr->flash[addr] | (avr->flash[addr + 1] << 8)); +} + +static inline void _call_register_irqs(avr_t * avr, uint16_t addr) +{ + if (addr > 31 && addr < 31 + MAX_IOs) { + avr_io_addr_t io = AVR_DATA_TO_IO(addr); + + if (avr->io[io].irq) { + uint8_t v = avr->data[addr]; + avr_raise_irq(avr->io[io].irq + AVR_IOMEM_IRQ_ALL, v); + for (int i = 0; i < 8; i++) + avr_raise_irq(avr->io[io].irq + i, (v >> i) & 1); + } + } +} + +void avr_core_watch_write(avr_t *avr, uint16_t addr, uint8_t v) +{ + if (addr > avr->ramend) { + AVR_LOG(avr, LOG_WARNING, + "CORE: *** Wrapping write address " + "PC=%04x SP=%04x O=%04x v=%02x Address %04x %% %04x --> %04x\n", + avr->pc, _avr_sp_get(avr), _avr_flash_read16le(avr, avr->pc), v, addr, (avr->ramend + 1), addr % (avr->ramend + 1)); + addr = addr % (avr->ramend + 1); + } + if (addr < 32) { + AVR_LOG(avr, LOG_ERROR, FONT_RED + "CORE: *** Invalid write address PC=%04x SP=%04x O=%04x Address %04x=%02x low registers\n" + FONT_DEFAULT, + avr->pc, _avr_sp_get(avr), _avr_flash_read16le(avr, avr->pc), addr, v); + crash(avr); + } +#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->trace_data->stack_frame_index > 1 && addr > avr->trace_data->stack_frame[avr->trace_data->stack_frame_index-2].sp) { + printf( FONT_RED "%04x : munching stack " + "SP %04x, A=%04x <= %02x\n" FONT_DEFAULT, + avr->pc, _avr_sp_get(avr), addr, v); + } +#endif + + if (avr->gdb) { + avr_gdb_handle_watchpoints(avr, addr, AVR_GDB_WATCH_WRITE); + } + + avr->data[addr] = v; + _call_register_irqs(avr, addr); +} + +uint8_t avr_core_watch_read(avr_t *avr, uint16_t addr) +{ + if (addr > avr->ramend) { + AVR_LOG(avr, LOG_WARNING, + "CORE: *** Wrapping read address " + "PC=%04x SP=%04x O=%04x Address %04x %% %04x --> %04x\n" + FONT_DEFAULT, + avr->pc, _avr_sp_get(avr), _avr_flash_read16le(avr, avr->pc), + addr, (avr->ramend + 1), addr % (avr->ramend + 1)); + addr = addr % (avr->ramend + 1); + } + + if (avr->gdb) { + avr_gdb_handle_watchpoints(avr, addr, AVR_GDB_WATCH_READ); + } + +// _call_register_irqs(avr, addr); + return avr->data[addr]; +} + +/* + * Set a register (r < 256) + * if it's an IO register (> 31) also (try to) call any callback that was + * registered to track changes to that register. + */ +static inline void _avr_set_r(avr_t * avr, uint16_t r, uint8_t v) +{ + REG_TOUCH(avr, r); + + if (r == R_SREG) { + avr->data[R_SREG] = v; + // unsplit the SREG + SET_SREG_FROM(avr, v); + SREG(); + } + if (r > 31) { + avr_io_addr_t io = AVR_DATA_TO_IO(r); + if (avr->io[io].w.c) { + avr->io[io].w.c(avr, r, v, avr->io[io].w.param); + } else { + avr->data[r] = v; + if (avr->io[io].irq) { + avr_raise_irq(avr->io[io].irq + AVR_IOMEM_IRQ_ALL, v); + for (int i = 0; i < 8; i++) + avr_raise_irq(avr->io[io].irq + i, (v >> i) & 1); + } + } + } else + avr->data[r] = v; +} + +static inline void +_avr_set_r16le( + avr_t * avr, + uint16_t r, + uint16_t v) +{ + _avr_set_r(avr, r, v); + _avr_set_r(avr, r + 1, v >> 8); +} + +static inline void +_avr_set_r16le_hl( + avr_t * avr, + uint16_t r, + uint16_t v) +{ + _avr_set_r(avr, r + 1, v >> 8); + _avr_set_r(avr, r , v); +} + +/* + * Stack pointer access + */ +inline uint16_t _avr_sp_get(avr_t * avr) +{ + return avr->data[R_SPL] | (avr->data[R_SPH] << 8); +} + +inline void _avr_sp_set(avr_t * avr, uint16_t sp) +{ + _avr_set_r16le(avr, R_SPL, sp); +} + +/* + * Set any address to a value; split between registers and SRAM + */ +static inline void _avr_set_ram(avr_t * avr, uint16_t addr, uint8_t v) +{ + if (addr <= avr->ioend) + _avr_set_r(avr, addr, v); + else + avr_core_watch_write(avr, addr, v); +} + +/* + * Get a value from SRAM. + */ +static inline uint8_t _avr_get_ram(avr_t * avr, uint16_t addr) +{ + if (addr == R_SREG) { + /* + * SREG is special it's reconstructed when read + * while the core itself uses the "shortcut" array + */ + READ_SREG_INTO(avr, avr->data[R_SREG]); + + } else if (addr > 31 && addr < 31 + MAX_IOs) { + avr_io_addr_t io = AVR_DATA_TO_IO(addr); + + if (avr->io[io].r.c) + avr->data[addr] = avr->io[io].r.c(avr, addr, avr->io[io].r.param); +#if 0 + if (avr->io[io].irq) { + uint8_t v = avr->data[addr]; + avr_raise_irq(avr->io[io].irq + AVR_IOMEM_IRQ_ALL, v); + for (int i = 0; i < 8; i++) + avr_raise_irq(avr->io[io].irq + i, (v >> i) & 1); + } +#endif + } + return avr_core_watch_read(avr, addr); +} + +/* + * Stack push accessors. + */ +static inline void _avr_push8(avr_t * avr, uint16_t v) +{ + uint16_t sp = _avr_sp_get(avr); + _avr_set_ram(avr, sp, v); + _avr_sp_set(avr, sp-1); +} + +static inline uint8_t _avr_pop8(avr_t * avr) +{ + uint16_t sp = _avr_sp_get(avr) + 1; + uint8_t res = _avr_get_ram(avr, sp); + _avr_sp_set(avr, sp); + return res; +} + +int _avr_push_addr(avr_t * avr, avr_flashaddr_t addr) +{ + uint16_t sp = _avr_sp_get(avr); + addr >>= 1; + for (int i = 0; i < avr->address_size; i++, addr >>= 8, sp--) { + _avr_set_ram(avr, sp, addr); + } + _avr_sp_set(avr, sp); + return avr->address_size; +} + +avr_flashaddr_t _avr_pop_addr(avr_t * avr) +{ + uint16_t sp = _avr_sp_get(avr) + 1; + avr_flashaddr_t res = 0; + for (int i = 0; i < avr->address_size; i++, sp++) { + res = (res << 8) | _avr_get_ram(avr, sp); + } + res <<= 1; + _avr_sp_set(avr, sp -1); + return res; +} + +/* + * "Pretty" register names + */ +const char * reg_names[REG_NAME_COUNT] = { + [R_XH] = "XH", [R_XL] = "XL", + [R_YH] = "YH", [R_YL] = "YL", + [R_ZH] = "ZH", [R_ZL] = "ZL", + [R_SPH] = "SPH", [R_SPL] = "SPL", + [R_SREG] = "SREG", +}; + + +const char * avr_regname(unsigned int reg) +{ + if (!reg_names[reg]) { + char tt[16]; + if (reg < 32) + sprintf(tt, "r%d", reg); + else + sprintf(tt, "io:%02x", reg); + reg_names[reg] = strdup(tt); + } + return reg_names[reg]; +} + +/* + * Called when an invalid opcode is decoded + */ +static void _avr_invalid_opcode(avr_t * avr) +{ +#if CONFIG_SIMAVR_TRACE + printf( FONT_RED "*** %04x: %-25s Invalid Opcode SP=%04x O=%04x \n" FONT_DEFAULT, + avr->pc, avr->trace_data->codeline[avr->pc>>1]->symbol, _avr_sp_get(avr), _avr_flash_read16le(avr, avr->pc)); +#else + AVR_LOG(avr, LOG_ERROR, FONT_RED "CORE: *** %04x: Invalid Opcode SP=%04x O=%04x \n" FONT_DEFAULT, + avr->pc, _avr_sp_get(avr), _avr_flash_read16le(avr, avr->pc)); +#endif +} + +#if CONFIG_SIMAVR_TRACE +/* + * Dump changed registers when tracing + */ +void avr_dump_state(avr_t * avr) +{ + if (!avr->trace || donttrace) + return; + + int doit = 0; + + for (int r = 0; r < 3 && !doit; r++) + if (avr->trace_data->touched[r]) + doit = 1; + if (!doit) + return; + printf(" ->> "); + const int r16[] = { R_SPL, R_XL, R_YL, R_ZL }; + for (int i = 0; i < 4; i++) + if (REG_ISTOUCHED(avr, r16[i]) || REG_ISTOUCHED(avr, r16[i]+1)) { + REG_TOUCH(avr, r16[i]); + REG_TOUCH(avr, r16[i]+1); + } + + for (int i = 0; i < 3*32; i++) + if (REG_ISTOUCHED(avr, i)) { + printf("%s=%02x ", avr_regname(i), avr->data[i]); + } + printf("\n"); +} +#endif + +#define get_d5(o) \ + const uint8_t d = (o >> 4) & 0x1f; + +#define get_vd5(o) \ + get_d5(o) \ + const uint8_t vd = avr->data[d]; + +#define get_r5(o) \ + const uint8_t r = ((o >> 5) & 0x10) | (o & 0xf); + +#define get_d5_a6(o) \ + get_d5(o); \ + const uint8_t A = ((((o >> 9) & 3) << 4) | ((o) & 0xf)) + 32; + +#define get_vd5_s3(o) \ + get_vd5(o); \ + const uint8_t s = o & 7; + +#define get_vd5_s3_mask(o) \ + get_vd5_s3(o); \ + const uint8_t mask = 1 << s; + +#define get_vd5_vr5(o) \ + get_r5(o); \ + get_d5(o); \ + const uint8_t vd = avr->data[d], vr = avr->data[r]; + +#define get_d5_vr5(o) \ + get_d5(o); \ + get_r5(o); \ + const uint8_t vr = avr->data[r]; + +#define get_h4_k8(o) \ + const uint8_t h = 16 + ((o >> 4) & 0xf); \ + const uint8_t k = ((o & 0x0f00) >> 4) | (o & 0xf); + +#define get_vh4_k8(o) \ + get_h4_k8(o) \ + const uint8_t vh = avr->data[h]; + +#define get_d5_q6(o) \ + get_d5(o) \ + const uint8_t q = ((o & 0x2000) >> 8) | ((o & 0x0c00) >> 7) | (o & 0x7); + +#define get_io5(o) \ + const uint8_t io = ((o >> 3) & 0x1f) + 32; + +#define get_io5_b3(o) \ + get_io5(o); \ + const uint8_t b = o & 0x7; + +#define get_io5_b3mask(o) \ + get_io5(o); \ + const uint8_t mask = 1 << (o & 0x7); + +// const int16_t o = ((int16_t)(op << 4)) >> 3; // CLANG BUG! +#define get_o12(op) \ + const int16_t o = ((int16_t)((op << 4) & 0xffff)) >> 3; + +#define get_vp2_k6(o) \ + const uint8_t p = 24 + ((o >> 3) & 0x6); \ + const uint8_t k = ((o & 0x00c0) >> 2) | (o & 0xf); \ + const uint16_t vp = avr->data[p] | (avr->data[p + 1] << 8); + +#define get_sreg_bit(o) \ + const uint8_t b = (o >> 4) & 7; + +/* + * Add a "jump" address to the jump trace buffer + */ +#if CONFIG_SIMAVR_TRACE +#define TRACE_JUMP()\ + avr->trace_data->old[avr->trace_data->old_pci].pc = avr->pc;\ + avr->trace_data->old[avr->trace_data->old_pci].sp = _avr_sp_get(avr);\ + avr->trace_data->old_pci = (avr->trace_data->old_pci + 1) & (OLD_PC_SIZE-1);\ + +#if AVR_STACK_WATCH +#define STACK_FRAME_PUSH()\ + avr->trace_data->stack_frame[avr->trace_data->stack_frame_index].pc = avr->pc;\ + avr->trace_data->stack_frame[avr->trace_data->stack_frame_index].sp = _avr_sp_get(avr);\ + avr->trace_data->stack_frame_index++; +#define STACK_FRAME_POP()\ + if (avr->trace_data->stack_frame_index > 0) \ + avr->trace_data->stack_frame_index--; +#else +#define STACK_FRAME_PUSH() +#define STACK_FRAME_POP() +#endif +#else /* CONFIG_SIMAVR_TRACE */ + +#define TRACE_JUMP() +#define STACK_FRAME_PUSH() +#define STACK_FRAME_POP() + +#endif + +/****************************************************************************\ + * + * Helper functions for calculating the status register bit values. + * See the Atmel data sheet for the instruction set for more info. + * +\****************************************************************************/ + +static void +_avr_flags_zns (struct avr_t * avr, uint8_t res) +{ + avr->sreg[S_Z] = res == 0; + avr->sreg[S_N] = (res >> 7) & 1; + avr->sreg[S_S] = avr->sreg[S_N] ^ avr->sreg[S_V]; +} + +static void +_avr_flags_zns16 (struct avr_t * avr, uint16_t res) +{ + avr->sreg[S_Z] = res == 0; + avr->sreg[S_N] = (res >> 15) & 1; + avr->sreg[S_S] = avr->sreg[S_N] ^ avr->sreg[S_V]; +} + +static void +_avr_flags_add_zns (struct avr_t * avr, uint8_t res, uint8_t rd, uint8_t rr) +{ + /* carry & half carry */ + uint8_t add_carry = (rd & rr) | (rr & ~res) | (~res & rd); + avr->sreg[S_H] = (add_carry >> 3) & 1; + avr->sreg[S_C] = (add_carry >> 7) & 1; + + /* overflow */ + avr->sreg[S_V] = (((rd & rr & ~res) | (~rd & ~rr & res)) >> 7) & 1; + + /* zns */ + _avr_flags_zns(avr, res); +} + + +static void +_avr_flags_sub_zns (struct avr_t * avr, uint8_t res, uint8_t rd, uint8_t rr) +{ + /* carry & half carry */ + uint8_t sub_carry = (~rd & rr) | (rr & res) | (res & ~rd); + avr->sreg[S_H] = (sub_carry >> 3) & 1; + avr->sreg[S_C] = (sub_carry >> 7) & 1; + + /* overflow */ + avr->sreg[S_V] = (((rd & ~rr & ~res) | (~rd & rr & res)) >> 7) & 1; + + /* zns */ + _avr_flags_zns(avr, res); +} + +static void +_avr_flags_Rzns (struct avr_t * avr, uint8_t res) +{ + if (res) + avr->sreg[S_Z] = 0; + avr->sreg[S_N] = (res >> 7) & 1; + avr->sreg[S_S] = avr->sreg[S_N] ^ avr->sreg[S_V]; +} + +static void +_avr_flags_sub_Rzns (struct avr_t * avr, uint8_t res, uint8_t rd, uint8_t rr) +{ + /* carry & half carry */ + uint8_t sub_carry = (~rd & rr) | (rr & res) | (res & ~rd); + avr->sreg[S_H] = (sub_carry >> 3) & 1; + avr->sreg[S_C] = (sub_carry >> 7) & 1; + + /* overflow */ + avr->sreg[S_V] = (((rd & ~rr & ~res) | (~rd & rr & res)) >> 7) & 1; + + _avr_flags_Rzns(avr, res); +} + +static void +_avr_flags_zcvs (struct avr_t * avr, uint8_t res, uint8_t vr) +{ + avr->sreg[S_Z] = res == 0; + avr->sreg[S_C] = vr & 1; + avr->sreg[S_V] = avr->sreg[S_N] ^ avr->sreg[S_C]; + avr->sreg[S_S] = avr->sreg[S_N] ^ avr->sreg[S_V]; +} + +static void +_avr_flags_zcnvs (struct avr_t * avr, uint8_t res, uint8_t vr) +{ + avr->sreg[S_Z] = res == 0; + avr->sreg[S_C] = vr & 1; + avr->sreg[S_N] = res >> 7; + avr->sreg[S_V] = avr->sreg[S_N] ^ avr->sreg[S_C]; + avr->sreg[S_S] = avr->sreg[S_N] ^ avr->sreg[S_V]; +} + +static void +_avr_flags_znv0s (struct avr_t * avr, uint8_t res) +{ + avr->sreg[S_V] = 0; + _avr_flags_zns(avr, res); +} + +static inline int _avr_is_instruction_32_bits(avr_t * avr, avr_flashaddr_t pc) +{ + uint16_t o = _avr_flash_read16le(avr, pc) & 0xfe0f; + return o == 0x9200 || // STS ! Store Direct to Data Space + o == 0x9000 || // LDS Load Direct from Data Space + o == 0x940c || // JMP Long Jump + o == 0x940d || // JMP Long Jump + o == 0x940e || // CALL Long Call to sub + o == 0x940f; // CALL Long Call to sub +} + +/* + * Main opcode decoder + * + * The decoder was written by following the datasheet in no particular order. + * As I went along, I noticed "bit patterns" that could be used to factor opcodes + * However, a lot of these only became apparent later on, so SOME instructions + * (skip of bit set etc) are compact, and some could use some refactoring (the ALU + * ones scream to be factored). + * I assume that the decoder could easily be 2/3 of it's current size. + * + * + It lacks the "extended" XMega jumps. + * + It also doesn't check whether the core it's + * emulating is supposed to have the fancy instructions, like multiply and such. + * + * The number of cycles taken by instruction has been added, but might not be + * entirely accurate. + */ +avr_flashaddr_t avr_run_one(avr_t * avr) +{ +run_one_again: +#if CONFIG_SIMAVR_TRACE + /* + * this traces spurious reset or bad jumps + */ + if ((avr->pc == 0 && avr->cycle > 0) || avr->pc >= avr->codeend || _avr_sp_get(avr) > avr->ramend) { +// avr->trace = 1; + STATE("RESET\n"); + crash(avr); + } + avr->trace_data->touched[0] = avr->trace_data->touched[1] = avr->trace_data->touched[2] = 0; +#endif + + /* Ensure we don't crash simavr due to a bad instruction reading past + * the end of the flash. + */ + if (unlikely(avr->pc >= avr->flashend)) { + STATE("CRASH\n"); + crash(avr); + return 0; + } + + uint32_t opcode = _avr_flash_read16le(avr, avr->pc); + avr_flashaddr_t new_pc = avr->pc + 2; // future "default" pc + int cycle = 1; + + switch (opcode & 0xf000) { + case 0x0000: { + switch (opcode) { + case 0x0000: { // NOP + STATE("nop\n"); + } break; + default: { + switch (opcode & 0xfc00) { + case 0x0400: { // CPC -- Compare with carry -- 0000 01rd dddd rrrr + get_vd5_vr5(opcode); + uint8_t res = vd - vr - avr->sreg[S_C]; + STATE("cpc %s[%02x], %s[%02x] = %02x\n", avr_regname(d), vd, avr_regname(r), vr, res); + _avr_flags_sub_Rzns(avr, res, vd, vr); + SREG(); + } break; + case 0x0c00: { // ADD -- Add without carry -- 0000 11rd dddd rrrr + get_vd5_vr5(opcode); + uint8_t res = vd + vr; + if (r == d) { + STATE("lsl %s[%02x] = %02x\n", avr_regname(d), vd, res & 0xff); + } else { + STATE("add %s[%02x], %s[%02x] = %02x\n", avr_regname(d), vd, avr_regname(r), vr, res); + } + _avr_set_r(avr, d, res); + _avr_flags_add_zns(avr, res, vd, vr); + SREG(); + } break; + case 0x0800: { // SBC -- Subtract with carry -- 0000 10rd dddd rrrr + get_vd5_vr5(opcode); + uint8_t res = vd - vr - avr->sreg[S_C]; + STATE("sbc %s[%02x], %s[%02x] = %02x\n", avr_regname(d), avr->data[d], avr_regname(r), avr->data[r], res); + _avr_set_r(avr, d, res); + _avr_flags_sub_Rzns(avr, res, vd, vr); + SREG(); + } break; + default: + switch (opcode & 0xff00) { + case 0x0100: { // MOVW -- Copy Register Word -- 0000 0001 dddd rrrr + uint8_t d = ((opcode >> 4) & 0xf) << 1; + uint8_t r = ((opcode) & 0xf) << 1; + STATE("movw %s:%s, %s:%s[%02x%02x]\n", avr_regname(d), avr_regname(d+1), avr_regname(r), avr_regname(r+1), avr->data[r+1], avr->data[r]); + uint16_t vr = avr->data[r] | (avr->data[r + 1] << 8); + _avr_set_r16le(avr, d, vr); + } break; + case 0x0200: { // MULS -- Multiply Signed -- 0000 0010 dddd rrrr + int8_t r = 16 + (opcode & 0xf); + int8_t d = 16 + ((opcode >> 4) & 0xf); + int16_t res = ((int8_t)avr->data[r]) * ((int8_t)avr->data[d]); + STATE("muls %s[%d], %s[%02x] = %d\n", avr_regname(d), ((int8_t)avr->data[d]), avr_regname(r), ((int8_t)avr->data[r]), res); + _avr_set_r16le(avr, 0, res); + avr->sreg[S_C] = (res >> 15) & 1; + avr->sreg[S_Z] = res == 0; + cycle++; + SREG(); + } break; + case 0x0300: { // MUL -- Multiply -- 0000 0011 fddd frrr + int8_t r = 16 + (opcode & 0x7); + int8_t d = 16 + ((opcode >> 4) & 0x7); + int16_t res = 0; + uint8_t c = 0; + T(const char * name = "";) + switch (opcode & 0x88) { + case 0x00: // MULSU -- Multiply Signed Unsigned -- 0000 0011 0ddd 0rrr + res = ((uint8_t)avr->data[r]) * ((int8_t)avr->data[d]); + c = (res >> 15) & 1; + T(name = "mulsu";) + break; + case 0x08: // FMUL -- Fractional Multiply Unsigned -- 0000 0011 0ddd 1rrr + res = ((uint8_t)avr->data[r]) * ((uint8_t)avr->data[d]); + c = (res >> 15) & 1; + res <<= 1; + T(name = "fmul";) + break; + case 0x80: // FMULS -- Multiply Signed -- 0000 0011 1ddd 0rrr + res = ((int8_t)avr->data[r]) * ((int8_t)avr->data[d]); + c = (res >> 15) & 1; + res <<= 1; + T(name = "fmuls";) + break; + case 0x88: // FMULSU -- Multiply Signed Unsigned -- 0000 0011 1ddd 1rrr + res = ((uint8_t)avr->data[r]) * ((int8_t)avr->data[d]); + c = (res >> 15) & 1; + res <<= 1; + T(name = "fmulsu";) + break; + } + cycle++; + STATE("%s %s[%d], %s[%02x] = %d\n", name, avr_regname(d), ((int8_t)avr->data[d]), avr_regname(r), ((int8_t)avr->data[r]), res); + _avr_set_r16le(avr, 0, res); + avr->sreg[S_C] = c; + avr->sreg[S_Z] = res == 0; + SREG(); + } break; + default: _avr_invalid_opcode(avr); + } + } + } + } + } break; + + case 0x1000: { + switch (opcode & 0xfc00) { + case 0x1800: { // SUB -- Subtract without carry -- 0001 10rd dddd rrrr + get_vd5_vr5(opcode); + uint8_t res = vd - vr; + STATE("sub %s[%02x], %s[%02x] = %02x\n", avr_regname(d), vd, avr_regname(r), vr, res); + _avr_set_r(avr, d, res); + _avr_flags_sub_zns(avr, res, vd, vr); + SREG(); + } break; + case 0x1000: { // CPSE -- Compare, skip if equal -- 0001 00rd dddd rrrr + get_vd5_vr5(opcode); + uint16_t res = vd == vr; + STATE("cpse %s[%02x], %s[%02x]\t; Will%s skip\n", avr_regname(d), avr->data[d], avr_regname(r), avr->data[r], res ? "":" not"); + if (res) { + if (_avr_is_instruction_32_bits(avr, new_pc)) { + new_pc += 4; cycle += 2; + } else { + new_pc += 2; cycle++; + } + } + } break; + case 0x1400: { // CP -- Compare -- 0001 01rd dddd rrrr + get_vd5_vr5(opcode); + uint8_t res = vd - vr; + STATE("cp %s[%02x], %s[%02x] = %02x\n", avr_regname(d), vd, avr_regname(r), vr, res); + _avr_flags_sub_zns(avr, res, vd, vr); + SREG(); + } break; + case 0x1c00: { // ADD -- Add with carry -- 0001 11rd dddd rrrr + get_vd5_vr5(opcode); + uint8_t res = vd + vr + avr->sreg[S_C]; + if (r == d) { + STATE("rol %s[%02x] = %02x\n", avr_regname(d), avr->data[d], res); + } else { + STATE("addc %s[%02x], %s[%02x] = %02x\n", avr_regname(d), avr->data[d], avr_regname(r), avr->data[r], res); + } + _avr_set_r(avr, d, res); + _avr_flags_add_zns(avr, res, vd, vr); + SREG(); + } break; + default: _avr_invalid_opcode(avr); + } + } break; + + case 0x2000: { + switch (opcode & 0xfc00) { + case 0x2000: { // AND -- Logical AND -- 0010 00rd dddd rrrr + get_vd5_vr5(opcode); + uint8_t res = vd & vr; + if (r == d) { + STATE("tst %s[%02x]\n", avr_regname(d), avr->data[d]); + } else { + STATE("and %s[%02x], %s[%02x] = %02x\n", avr_regname(d), vd, avr_regname(r), vr, res); + } + _avr_set_r(avr, d, res); + _avr_flags_znv0s(avr, res); + SREG(); + } break; + case 0x2400: { // EOR -- Logical Exclusive OR -- 0010 01rd dddd rrrr + get_vd5_vr5(opcode); + uint8_t res = vd ^ vr; + if (r==d) { + STATE("clr %s[%02x]\n", avr_regname(d), avr->data[d]); + } else { + STATE("eor %s[%02x], %s[%02x] = %02x\n", avr_regname(d), vd, avr_regname(r), vr, res); + } + _avr_set_r(avr, d, res); + _avr_flags_znv0s(avr, res); + SREG(); + } break; + case 0x2800: { // OR -- Logical OR -- 0010 10rd dddd rrrr + get_vd5_vr5(opcode); + uint8_t res = vd | vr; + STATE("or %s[%02x], %s[%02x] = %02x\n", avr_regname(d), vd, avr_regname(r), vr, res); + _avr_set_r(avr, d, res); + _avr_flags_znv0s(avr, res); + SREG(); + } break; + case 0x2c00: { // MOV -- 0010 11rd dddd rrrr + get_d5_vr5(opcode); + uint8_t res = vr; + STATE("mov %s, %s[%02x] = %02x\n", avr_regname(d), avr_regname(r), vr, res); + _avr_set_r(avr, d, res); + } break; + default: _avr_invalid_opcode(avr); + } + } break; + + case 0x3000: { // CPI -- Compare Immediate -- 0011 kkkk hhhh kkkk + get_vh4_k8(opcode); + uint8_t res = vh - k; + STATE("cpi %s[%02x], 0x%02x\n", avr_regname(h), vh, k); + _avr_flags_sub_zns(avr, res, vh, k); + SREG(); + } break; + + case 0x4000: { // SBCI -- Subtract Immediate With Carry -- 0100 kkkk hhhh kkkk + get_vh4_k8(opcode); + uint8_t res = vh - k - avr->sreg[S_C]; + STATE("sbci %s[%02x], 0x%02x = %02x\n", avr_regname(h), vh, k, res); + _avr_set_r(avr, h, res); + _avr_flags_sub_Rzns(avr, res, vh, k); + SREG(); + } break; + + case 0x5000: { // SUBI -- Subtract Immediate -- 0101 kkkk hhhh kkkk + get_vh4_k8(opcode); + uint8_t res = vh - k; + STATE("subi %s[%02x], 0x%02x = %02x\n", avr_regname(h), vh, k, res); + _avr_set_r(avr, h, res); + _avr_flags_sub_zns(avr, res, vh, k); + SREG(); + } break; + + case 0x6000: { // ORI aka SBR -- Logical OR with Immediate -- 0110 kkkk hhhh kkkk + get_vh4_k8(opcode); + uint8_t res = vh | k; + STATE("ori %s[%02x], 0x%02x\n", avr_regname(h), vh, k); + _avr_set_r(avr, h, res); + _avr_flags_znv0s(avr, res); + SREG(); + } break; + + case 0x7000: { // ANDI -- Logical AND with Immediate -- 0111 kkkk hhhh kkkk + get_vh4_k8(opcode); + uint8_t res = vh & k; + STATE("andi %s[%02x], 0x%02x\n", avr_regname(h), vh, k); + _avr_set_r(avr, h, res); + _avr_flags_znv0s(avr, res); + SREG(); + } break; + + case 0xa000: + case 0x8000: { + /* + * Load (LDD/STD) store instructions + * + * 10q0 qqsd dddd yqqq + * s = 0 = load, 1 = store + * y = 16 bits register index, 1 = Y, 0 = X + * q = 6 bit displacement + */ + switch (opcode & 0xd008) { + case 0xa000: + case 0x8000: { // LD (LDD) -- Load Indirect using Z -- 10q0 qqsd dddd yqqq + uint16_t v = avr->data[R_ZL] | (avr->data[R_ZH] << 8); + get_d5_q6(opcode); + if (opcode & 0x0200) { + STATE("st (Z+%d[%04x]), %s[%02x]\n", q, v+q, avr_regname(d), avr->data[d]); + _avr_set_ram(avr, v+q, avr->data[d]); + } else { + STATE("ld %s, (Z+%d[%04x])=[%02x]\n", avr_regname(d), q, v+q, avr->data[v+q]); + _avr_set_r(avr, d, _avr_get_ram(avr, v+q)); + } + cycle += 1; // 2 cycles, 3 for tinyavr + } break; + case 0xa008: + case 0x8008: { // LD (LDD) -- Load Indirect using Y -- 10q0 qqsd dddd yqqq + uint16_t v = avr->data[R_YL] | (avr->data[R_YH] << 8); + get_d5_q6(opcode); + if (opcode & 0x0200) { + STATE("st (Y+%d[%04x]), %s[%02x]\n", q, v+q, avr_regname(d), avr->data[d]); + _avr_set_ram(avr, v+q, avr->data[d]); + } else { + STATE("ld %s, (Y+%d[%04x])=[%02x]\n", avr_regname(d), q, v+q, avr->data[d+q]); + _avr_set_r(avr, d, _avr_get_ram(avr, v+q)); + } + cycle += 1; // 2 cycles, 3 for tinyavr + } break; + default: _avr_invalid_opcode(avr); + } + } break; + + case 0x9000: { + /* this is an annoying special case, but at least these lines handle all the SREG set/clear opcodes */ + if ((opcode & 0xff0f) == 0x9408) { + get_sreg_bit(opcode); + STATE("%s%c\n", opcode & 0x0080 ? "cl" : "se", _sreg_bit_name[b]); + avr_sreg_set(avr, b, (opcode & 0x0080) == 0); + SREG(); + } else switch (opcode) { + case 0x9588: { // SLEEP -- 1001 0101 1000 1000 + STATE("sleep\n"); + /* Don't sleep if there are interrupts about to be serviced. + * Without this check, it was possible to incorrectly enter a state + * in which the cpu was sleeping and interrupts were disabled. For more + * details, see the commit message. */ + if (!avr_has_pending_interrupts(avr) || !avr->sreg[S_I]) + avr->state = cpu_Sleeping; + } break; + case 0x9598: { // BREAK -- 1001 0101 1001 1000 + STATE("break\n"); + if (avr->gdb) { + // if gdb is on, break here. + avr->state = cpu_Stopped; + avr_gdb_handle_break(avr); + } + } break; + case 0x95a8: { // WDR -- Watchdog Reset -- 1001 0101 1010 1000 + STATE("wdr\n"); + avr_ioctl(avr, AVR_IOCTL_WATCHDOG_RESET, 0); + } break; + case 0x95e8: { // SPM -- Store Program Memory -- 1001 0101 1110 1000 + STATE("spm\n"); + avr_ioctl(avr, AVR_IOCTL_FLASH_SPM, 0); + } break; + case 0x9409: // IJMP -- Indirect jump -- 1001 0100 0000 1001 + case 0x9419: // EIJMP -- Indirect jump -- 1001 0100 0001 1001 bit 4 is "indirect" + case 0x9509: // ICALL -- Indirect Call to Subroutine -- 1001 0101 0000 1001 + case 0x9519: { // EICALL -- Indirect Call to Subroutine -- 1001 0101 0001 1001 bit 8 is "push pc" + int e = opcode & 0x10; + int p = opcode & 0x100; + if (e && !avr->eind) + _avr_invalid_opcode(avr); + uint32_t z = avr->data[R_ZL] | (avr->data[R_ZH] << 8); + if (e) + z |= avr->data[avr->eind] << 16; + STATE("%si%s Z[%04x]\n", e?"e":"", p?"call":"jmp", z << 1); + if (p) + cycle += _avr_push_addr(avr, new_pc) - 1; + new_pc = z << 1; + cycle++; + TRACE_JUMP(); + } break; + case 0x9518: // RETI -- Return from Interrupt -- 1001 0101 0001 1000 + avr_sreg_set(avr, S_I, 1); + avr_interrupt_reti(avr); + FALLTHROUGH + case 0x9508: { // RET -- Return -- 1001 0101 0000 1000 + new_pc = _avr_pop_addr(avr); + cycle += 1 + avr->address_size; + STATE("ret%s\n", opcode & 0x10 ? "i" : ""); + TRACE_JUMP(); + STACK_FRAME_POP(); + } break; + case 0x95c8: { // LPM -- Load Program Memory R0 <- (Z) -- 1001 0101 1100 1000 + uint16_t z = avr->data[R_ZL] | (avr->data[R_ZH] << 8); + STATE("lpm %s, (Z[%04x])\n", avr_regname(0), z); + cycle += 2; // 3 cycles + _avr_set_r(avr, 0, avr->flash[z]); + } break; + case 0x95d8: { // ELPM -- Load Program Memory R0 <- (Z) -- 1001 0101 1101 1000 + if (!avr->rampz) + _avr_invalid_opcode(avr); + uint32_t z = avr->data[R_ZL] | (avr->data[R_ZH] << 8) | (avr->data[avr->rampz] << 16); + STATE("elpm %s, (Z[%02x:%04x])\n", avr_regname(0), z >> 16, z & 0xffff); + _avr_set_r(avr, 0, avr->flash[z]); + cycle += 2; // 3 cycles + } break; + default: { + switch (opcode & 0xfe0f) { + case 0x9000: { // LDS -- Load Direct from Data Space, 32 bits -- 1001 0000 0000 0000 + get_d5(opcode); + uint16_t x = _avr_flash_read16le(avr, new_pc); + new_pc += 2; + STATE("lds %s[%02x], 0x%04x\n", avr_regname(d), avr->data[d], x); + _avr_set_r(avr, d, _avr_get_ram(avr, x)); + cycle++; // 2 cycles + } break; + case 0x9005: + case 0x9004: { // LPM -- Load Program Memory -- 1001 000d dddd 01oo + get_d5(opcode); + uint16_t z = avr->data[R_ZL] | (avr->data[R_ZH] << 8); + int op = opcode & 1; + STATE("lpm %s, (Z[%04x]%s)\n", avr_regname(d), z, op ? "+" : ""); + _avr_set_r(avr, d, avr->flash[z]); + if (op) { + z++; + _avr_set_r16le_hl(avr, R_ZL, z); + } + cycle += 2; // 3 cycles + } break; + case 0x9006: + case 0x9007: { // ELPM -- Extended Load Program Memory -- 1001 000d dddd 01oo + if (!avr->rampz) + _avr_invalid_opcode(avr); + uint32_t z = avr->data[R_ZL] | (avr->data[R_ZH] << 8) | (avr->data[avr->rampz] << 16); + get_d5(opcode); + int op = opcode & 1; + STATE("elpm %s, (Z[%02x:%04x]%s)\n", avr_regname(d), z >> 16, z & 0xffff, op ? "+" : ""); + _avr_set_r(avr, d, avr->flash[z]); + if (op) { + z++; + _avr_set_r(avr, avr->rampz, z >> 16); + _avr_set_r16le_hl(avr, R_ZL, z); + } + cycle += 2; // 3 cycles + } break; + /* + * Load store instructions + * + * 1001 00sr rrrr iioo + * s = 0 = load, 1 = store + * ii = 16 bits register index, 11 = X, 10 = Y, 00 = Z + * oo = 1) post increment, 2) pre-decrement + */ + case 0x900c: + case 0x900d: + case 0x900e: { // LD -- Load Indirect from Data using X -- 1001 000d dddd 11oo + int op = opcode & 3; + get_d5(opcode); + uint16_t x = (avr->data[R_XH] << 8) | avr->data[R_XL]; + STATE("ld %s, %sX[%04x]%s\n", avr_regname(d), op == 2 ? "--" : "", x, op == 1 ? "++" : ""); + cycle++; // 2 cycles (1 for tinyavr, except with inc/dec 2) + if (op == 2) x--; + uint8_t vd = _avr_get_ram(avr, x); + if (op == 1) x++; + _avr_set_r16le_hl(avr, R_XL, x); + _avr_set_r(avr, d, vd); + } break; + case 0x920c: + case 0x920d: + case 0x920e: { // ST -- Store Indirect Data Space X -- 1001 001d dddd 11oo + int op = opcode & 3; + get_vd5(opcode); + uint16_t x = (avr->data[R_XH] << 8) | avr->data[R_XL]; + STATE("st %sX[%04x]%s, %s[%02x] \n", op == 2 ? "--" : "", x, op == 1 ? "++" : "", avr_regname(d), vd); + cycle++; // 2 cycles, except tinyavr + if (op == 2) x--; + _avr_set_ram(avr, x, vd); + if (op == 1) x++; + _avr_set_r16le_hl(avr, R_XL, x); + } break; + case 0x9009: + case 0x900a: { // LD -- Load Indirect from Data using Y -- 1001 000d dddd 10oo + int op = opcode & 3; + get_d5(opcode); + uint16_t y = (avr->data[R_YH] << 8) | avr->data[R_YL]; + STATE("ld %s, %sY[%04x]%s\n", avr_regname(d), op == 2 ? "--" : "", y, op == 1 ? "++" : ""); + cycle++; // 2 cycles, except tinyavr + if (op == 2) y--; + uint8_t vd = _avr_get_ram(avr, y); + if (op == 1) y++; + _avr_set_r16le_hl(avr, R_YL, y); + _avr_set_r(avr, d, vd); + } break; + case 0x9209: + case 0x920a: { // ST -- Store Indirect Data Space Y -- 1001 001d dddd 10oo + int op = opcode & 3; + get_vd5(opcode); + uint16_t y = (avr->data[R_YH] << 8) | avr->data[R_YL]; + STATE("st %sY[%04x]%s, %s[%02x]\n", op == 2 ? "--" : "", y, op == 1 ? "++" : "", avr_regname(d), vd); + cycle++; + if (op == 2) y--; + _avr_set_ram(avr, y, vd); + if (op == 1) y++; + _avr_set_r16le_hl(avr, R_YL, y); + } break; + case 0x9200: { // STS -- Store Direct to Data Space, 32 bits -- 1001 0010 0000 0000 + get_vd5(opcode); + uint16_t x = _avr_flash_read16le(avr, new_pc); + new_pc += 2; + STATE("sts 0x%04x, %s[%02x]\n", x, avr_regname(d), vd); + cycle++; + _avr_set_ram(avr, x, vd); + } break; + case 0x9001: + case 0x9002: { // LD -- Load Indirect from Data using Z -- 1001 000d dddd 00oo + int op = opcode & 3; + get_d5(opcode); + uint16_t z = (avr->data[R_ZH] << 8) | avr->data[R_ZL]; + STATE("ld %s, %sZ[%04x]%s\n", avr_regname(d), op == 2 ? "--" : "", z, op == 1 ? "++" : ""); + cycle++;; // 2 cycles, except tinyavr + if (op == 2) z--; + uint8_t vd = _avr_get_ram(avr, z); + if (op == 1) z++; + _avr_set_r16le_hl(avr, R_ZL, z); + _avr_set_r(avr, d, vd); + } break; + case 0x9201: + case 0x9202: { // ST -- Store Indirect Data Space Z -- 1001 001d dddd 00oo + int op = opcode & 3; + get_vd5(opcode); + uint16_t z = (avr->data[R_ZH] << 8) | avr->data[R_ZL]; + STATE("st %sZ[%04x]%s, %s[%02x] \n", op == 2 ? "--" : "", z, op == 1 ? "++" : "", avr_regname(d), vd); + cycle++; // 2 cycles, except tinyavr + if (op == 2) z--; + _avr_set_ram(avr, z, vd); + if (op == 1) z++; + _avr_set_r16le_hl(avr, R_ZL, z); + } break; + case 0x900f: { // POP -- 1001 000d dddd 1111 + get_d5(opcode); + _avr_set_r(avr, d, _avr_pop8(avr)); + T(uint16_t sp = _avr_sp_get(avr);) + STATE("pop %s (@%04x)[%02x]\n", avr_regname(d), sp, avr->data[sp]); + cycle++; + } break; + case 0x920f: { // PUSH -- 1001 001d dddd 1111 + get_vd5(opcode); + _avr_push8(avr, vd); + T(uint16_t sp = _avr_sp_get(avr);) + STATE("push %s[%02x] (@%04x)\n", avr_regname(d), vd, sp); + cycle++; + } break; + case 0x9400: { // COM -- One's Complement -- 1001 010d dddd 0000 + get_vd5(opcode); + uint8_t res = 0xff - vd; + STATE("com %s[%02x] = %02x\n", avr_regname(d), vd, res); + _avr_set_r(avr, d, res); + _avr_flags_znv0s(avr, res); + avr->sreg[S_C] = 1; + SREG(); + } break; + case 0x9401: { // NEG -- Two's Complement -- 1001 010d dddd 0001 + get_vd5(opcode); + uint8_t res = 0x00 - vd; + STATE("neg %s[%02x] = %02x\n", avr_regname(d), vd, res); + _avr_set_r(avr, d, res); + avr->sreg[S_H] = ((res >> 3) | (vd >> 3)) & 1; + avr->sreg[S_V] = res == 0x80; + avr->sreg[S_C] = res != 0; + _avr_flags_zns(avr, res); + SREG(); + } break; + case 0x9402: { // SWAP -- Swap Nibbles -- 1001 010d dddd 0010 + get_vd5(opcode); + uint8_t res = (vd >> 4) | (vd << 4) ; + STATE("swap %s[%02x] = %02x\n", avr_regname(d), vd, res); + _avr_set_r(avr, d, res); + } break; + case 0x9403: { // INC -- Increment -- 1001 010d dddd 0011 + get_vd5(opcode); + uint8_t res = vd + 1; + STATE("inc %s[%02x] = %02x\n", avr_regname(d), vd, res); + _avr_set_r(avr, d, res); + avr->sreg[S_V] = res == 0x80; + _avr_flags_zns(avr, res); + SREG(); + } break; + case 0x9405: { // ASR -- Arithmetic Shift Right -- 1001 010d dddd 0101 + get_vd5(opcode); + uint8_t res = (vd >> 1) | (vd & 0x80); + STATE("asr %s[%02x]\n", avr_regname(d), vd); + _avr_set_r(avr, d, res); + _avr_flags_zcnvs(avr, res, vd); + SREG(); + } break; + case 0x9406: { // LSR -- Logical Shift Right -- 1001 010d dddd 0110 + get_vd5(opcode); + uint8_t res = vd >> 1; + STATE("lsr %s[%02x]\n", avr_regname(d), vd); + _avr_set_r(avr, d, res); + avr->sreg[S_N] = 0; + _avr_flags_zcvs(avr, res, vd); + SREG(); + } break; + case 0x9407: { // ROR -- Rotate Right -- 1001 010d dddd 0111 + get_vd5(opcode); + uint8_t res = (avr->sreg[S_C] ? 0x80 : 0) | vd >> 1; + STATE("ror %s[%02x]\n", avr_regname(d), vd); + _avr_set_r(avr, d, res); + _avr_flags_zcnvs(avr, res, vd); + SREG(); + } break; + case 0x940a: { // DEC -- Decrement -- 1001 010d dddd 1010 + get_vd5(opcode); + uint8_t res = vd - 1; + STATE("dec %s[%02x] = %02x\n", avr_regname(d), vd, res); + _avr_set_r(avr, d, res); + avr->sreg[S_V] = res == 0x7f; + _avr_flags_zns(avr, res); + SREG(); + } break; + case 0x940c: + case 0x940d: { // JMP -- Long Call to sub, 32 bits -- 1001 010a aaaa 110a + avr_flashaddr_t a = ((opcode & 0x01f0) >> 3) | (opcode & 1); + uint16_t x = _avr_flash_read16le(avr, new_pc); + a = (a << 16) | x; + STATE("jmp 0x%06x\n", a); + new_pc = a << 1; + cycle += 2; + TRACE_JUMP(); + } break; + case 0x940e: + case 0x940f: { // CALL -- Long Call to sub, 32 bits -- 1001 010a aaaa 111a + avr_flashaddr_t a = ((opcode & 0x01f0) >> 3) | (opcode & 1); + uint16_t x = _avr_flash_read16le(avr, new_pc); + a = (a << 16) | x; + STATE("call 0x%06x\n", a); + new_pc += 2; + cycle += 1 + _avr_push_addr(avr, new_pc); + new_pc = a << 1; + TRACE_JUMP(); + STACK_FRAME_PUSH(); + } break; + + default: { + switch (opcode & 0xff00) { + case 0x9600: { // ADIW -- Add Immediate to Word -- 1001 0110 KKpp KKKK + get_vp2_k6(opcode); + uint16_t res = vp + k; + STATE("adiw %s:%s[%04x], 0x%02x\n", avr_regname(p), avr_regname(p + 1), vp, k); + _avr_set_r16le_hl(avr, p, res); + avr->sreg[S_V] = ((~vp & res) >> 15) & 1; + avr->sreg[S_C] = ((~res & vp) >> 15) & 1; + _avr_flags_zns16(avr, res); + SREG(); + cycle++; + } break; + case 0x9700: { // SBIW -- Subtract Immediate from Word -- 1001 0111 KKpp KKKK + get_vp2_k6(opcode); + uint16_t res = vp - k; + STATE("sbiw %s:%s[%04x], 0x%02x\n", avr_regname(p), avr_regname(p + 1), vp, k); + _avr_set_r16le_hl(avr, p, res); + avr->sreg[S_V] = ((vp & ~res) >> 15) & 1; + avr->sreg[S_C] = ((res & ~vp) >> 15) & 1; + _avr_flags_zns16(avr, res); + SREG(); + cycle++; + } break; + case 0x9800: { // CBI -- Clear Bit in I/O Register -- 1001 1000 AAAA Abbb + get_io5_b3mask(opcode); + uint8_t res = _avr_get_ram(avr, io) & ~mask; + STATE("cbi %s[%04x], 0x%02x = %02x\n", avr_regname(io), avr->data[io], mask, res); + _avr_set_ram(avr, io, res); + cycle++; + } break; + case 0x9900: { // SBIC -- Skip if Bit in I/O Register is Cleared -- 1001 1001 AAAA Abbb + get_io5_b3mask(opcode); + uint8_t res = _avr_get_ram(avr, io) & mask; + STATE("sbic %s[%04x], 0x%02x\t; Will%s branch\n", avr_regname(io), avr->data[io], mask, !res?"":" not"); + if (!res) { + if (_avr_is_instruction_32_bits(avr, new_pc)) { + new_pc += 4; cycle += 2; + } else { + new_pc += 2; cycle++; + } + } + } break; + case 0x9a00: { // SBI -- Set Bit in I/O Register -- 1001 1010 AAAA Abbb + get_io5_b3mask(opcode); + uint8_t res = _avr_get_ram(avr, io) | mask; + STATE("sbi %s[%04x], 0x%02x = %02x\n", avr_regname(io), avr->data[io], mask, res); + _avr_set_ram(avr, io, res); + cycle++; + } break; + case 0x9b00: { // SBIS -- Skip if Bit in I/O Register is Set -- 1001 1011 AAAA Abbb + get_io5_b3mask(opcode); + uint8_t res = _avr_get_ram(avr, io) & mask; + STATE("sbis %s[%04x], 0x%02x\t; Will%s branch\n", avr_regname(io), avr->data[io], mask, res?"":" not"); + if (res) { + if (_avr_is_instruction_32_bits(avr, new_pc)) { + new_pc += 4; cycle += 2; + } else { + new_pc += 2; cycle++; + } + } + } break; + default: + switch (opcode & 0xfc00) { + case 0x9c00: { // MUL -- Multiply Unsigned -- 1001 11rd dddd rrrr + get_vd5_vr5(opcode); + uint16_t res = vd * vr; + STATE("mul %s[%02x], %s[%02x] = %04x\n", avr_regname(d), vd, avr_regname(r), vr, res); + cycle++; + _avr_set_r16le(avr, 0, res); + avr->sreg[S_Z] = res == 0; + avr->sreg[S_C] = (res >> 15) & 1; + SREG(); + } break; + default: _avr_invalid_opcode(avr); + } + } + } break; + } + } break; + } + } break; + + case 0xb000: { + switch (opcode & 0xf800) { + case 0xb800: { // OUT A,Rr -- 1011 1AAd dddd AAAA + get_d5_a6(opcode); + STATE("out %s, %s[%02x]\n", avr_regname(A), avr_regname(d), avr->data[d]); + _avr_set_ram(avr, A, avr->data[d]); + } break; + case 0xb000: { // IN Rd,A -- 1011 0AAd dddd AAAA + get_d5_a6(opcode); + STATE("in %s, %s[%02x]\n", avr_regname(d), avr_regname(A), avr->data[A]); + _avr_set_r(avr, d, _avr_get_ram(avr, A)); + } break; + default: _avr_invalid_opcode(avr); + } + } break; + + case 0xc000: { // RJMP -- 1100 kkkk kkkk kkkk + get_o12(opcode); + STATE("rjmp .%d [%04x]\n", o >> 1, new_pc + o); + new_pc = (new_pc + o) % (avr->flashend+1); + cycle++; + TRACE_JUMP(); + } break; + + case 0xd000: { // RCALL -- 1101 kkkk kkkk kkkk + get_o12(opcode); + STATE("rcall .%d [%04x]\n", o >> 1, new_pc + o); + cycle += _avr_push_addr(avr, new_pc); + new_pc = (new_pc + o) % (avr->flashend+1); + // 'rcall .1' is used as a cheap "push 16 bits of room on the stack" + if (o != 0) { + TRACE_JUMP(); + STACK_FRAME_PUSH(); + } + } break; + + case 0xe000: { // LDI Rd, K aka SER (LDI r, 0xff) -- 1110 kkkk dddd kkkk + get_h4_k8(opcode); + STATE("ldi %s, 0x%02x\n", avr_regname(h), k); + _avr_set_r(avr, h, k); + } break; + + case 0xf000: { + switch (opcode & 0xfe00) { + case 0xf100: { /* simavr special opcodes */ + if (opcode == 0xf1f1) { // AVR_OVERFLOW_OPCODE + printf("FLASH overflow, soft reset\n"); + new_pc = 0; + TRACE_JUMP(); + } + } break; + case 0xf000: + case 0xf200: + case 0xf400: + case 0xf600: { // BRXC/BRXS -- All the SREG branches -- 1111 0Boo oooo osss + int16_t o = ((int16_t)(opcode << 6)) >> 9; // offset + uint8_t s = opcode & 7; + int set = (opcode & 0x0400) == 0; // this bit means BRXC otherwise BRXS + int branch = (avr->sreg[s] && set) || (!avr->sreg[s] && !set); + const char *names[2][8] = { + { "brcc", "brne", "brpl", "brvc", NULL, "brhc", "brtc", "brid"}, + { "brcs", "breq", "brmi", "brvs", NULL, "brhs", "brts", "brie"}, + }; + if (names[set][s]) { + STATE("%s .%d [%04x]\t; Will%s branch\n", names[set][s], o, new_pc + (o << 1), branch ? "":" not"); + } else { + STATE("%s%c .%d [%04x]\t; Will%s branch\n", set ? "brbs" : "brbc", _sreg_bit_name[s], o, new_pc + (o << 1), branch ? "":" not"); + } + if (branch) { + cycle++; // 2 cycles if taken, 1 otherwise + new_pc = new_pc + (o << 1); + } + } break; + case 0xf800: + case 0xf900: { // BLD -- Bit Store from T into a Bit in Register -- 1111 100d dddd 0bbb + get_vd5_s3_mask(opcode); + uint8_t v = (vd & ~mask) | (avr->sreg[S_T] ? mask : 0); + STATE("bld %s[%02x], 0x%02x = %02x\n", avr_regname(d), vd, mask, v); + _avr_set_r(avr, d, v); + } break; + case 0xfa00: + case 0xfb00:{ // BST -- Bit Store into T from bit in Register -- 1111 101d dddd 0bbb + get_vd5_s3(opcode) + STATE("bst %s[%02x], 0x%02x\n", avr_regname(d), vd, 1 << s); + avr->sreg[S_T] = (vd >> s) & 1; + SREG(); + } break; + case 0xfc00: + case 0xfe00: { // SBRS/SBRC -- Skip if Bit in Register is Set/Clear -- 1111 11sd dddd 0bbb + get_vd5_s3_mask(opcode) + int set = (opcode & 0x0200) != 0; + int branch = ((vd & mask) && set) || (!(vd & mask) && !set); + STATE("%s %s[%02x], 0x%02x\t; Will%s branch\n", set ? "sbrs" : "sbrc", avr_regname(d), vd, mask, branch ? "":" not"); + if (branch) { + if (_avr_is_instruction_32_bits(avr, new_pc)) { + new_pc += 4; cycle += 2; + } else { + new_pc += 2; cycle++; + } + } + } break; + default: _avr_invalid_opcode(avr); + } + } break; + + default: _avr_invalid_opcode(avr); + + } + avr->cycle += cycle; + + if ((avr->state == cpu_Running) && + (avr->run_cycle_count > cycle) && + (avr->interrupt_state == 0)) + { + avr->run_cycle_count -= cycle; + avr->pc = new_pc; + goto run_one_again; + } + + return new_pc; +} diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_core.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_core.h new file mode 100644 index 0000000..874651e --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_core.h @@ -0,0 +1,142 @@ +/* + sim_core.h + + Copyright 2008, 2009 Michel Pollet + + 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 . + */ + +#ifndef __SIM_CORE_H__ +#define __SIM_CORE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef NO_COLOR + #define FONT_GREEN + #define FONT_RED + #define FONT_DEFAULT +#else + #define FONT_GREEN "\e[32m" + #define FONT_RED "\e[31m" + #define FONT_DEFAULT "\e[0m" +#endif + +/* + * Instruction decoder, run ONE instruction + */ +avr_flashaddr_t avr_run_one(avr_t * avr); + +/* + * These are for internal access to the stack (for interrupts) + */ +uint16_t _avr_sp_get(avr_t * avr); +void _avr_sp_set(avr_t * avr, uint16_t sp); +int _avr_push_addr(avr_t * avr, avr_flashaddr_t addr); + +#if CONFIG_SIMAVR_TRACE + +/* + * Get a "pretty" register name + */ +const char * avr_regname(unsigned int reg); + +/* + * DEBUG bits follow + * These will disappear when gdb arrives + */ +void avr_dump_state(avr_t * avr); + +#define DUMP_REG() { \ + for (int i = 0; i < 32; i++) printf("%s=%02x%c", avr_regname(i), avr->data[i],i==15?'\n':' ');\ + printf("\n");\ + uint16_t y = avr->data[R_YL] | (avr->data[R_YH]<<8);\ + for (int i = 0; i < 20; i++) printf("Y+%02d=%02x ", i, avr->data[y+i]);\ + printf("\n");\ + } + + +#if AVR_STACK_WATCH +#define DUMP_STACK() \ + for (int i = avr->trace_data->stack_frame_index; i; i--) {\ + int pci = i-1;\ + printf(FONT_RED "*** %04x: %-25s sp %04x\n" FONT_DEFAULT,\ + avr->trace_data->stack_frame[pci].pc, \ + avr->trace_data->codeline ? avr->trace_data->codeline[avr->trace_data->stack_frame[pci].pc>>1]->symbol : "unknown", \ + avr->trace_data->stack_frame[pci].sp);\ + } +#else +#define DUMP_STACK() +#endif + +#else /* CONFIG_SIMAVR_TRACE */ + +#define DUMP_STACK() +#define DUMP_REG(); + +#endif + +/** + * Reconstructs the SREG value from avr->sreg into dst. + */ +#define READ_SREG_INTO(avr, dst) { \ + dst = 0; \ + for (int i = 0; i < 8; i++) \ + if (avr->sreg[i] > 1) { \ + printf("** Invalid SREG!!\n"); \ + } else if (avr->sreg[i]) \ + dst |= (1 << i); \ + } + +static inline void avr_sreg_set(avr_t * avr, uint8_t flag, uint8_t ival) +{ + /* + * clear interrupt_state if disabling interrupts. + * set wait if enabling interrupts. + * no change if interrupt flag does not change. + */ + + if (flag == S_I) { + if (ival) { + if (!avr->sreg[S_I]) + avr->interrupt_state = -1; + } else + avr->interrupt_state = 0; + } + + avr->sreg[flag] = ival; +} + +/** + * Splits the SREG value from src into the avr->sreg array. + */ +#define SET_SREG_FROM(avr, src) { \ + for (int i = 0; i < 8; i++) \ + avr_sreg_set(avr, i, (src & (1 << i)) != 0); \ + } + +/* + * Opcode is sitting at the end of the flash to catch PC overflows. + * Apparently it's used by some code to simulate soft reset? + */ +#define AVR_OVERFLOW_OPCODE 0xf1f1 + +#ifdef __cplusplus +}; +#endif + +#endif /*__SIM_CORE_H__*/ diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_cycle_timers.c b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_cycle_timers.c new file mode 100644 index 0000000..93cf265 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_cycle_timers.c @@ -0,0 +1,249 @@ +/* + sim_cycle_timers.c + + Copyright 2008-2012 Michel Pollet + + 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 +#include "sim_avr.h" +#include "sim_time.h" +#include "sim_cycle_timers.h" + +#define QUEUE(__q, __e) { \ + (__e)->next = (__q); \ + (__q) = __e; \ + } +#define DETACH(__q, __l, __e) { \ + if (__l) \ + (__l)->next = (__e)->next; \ + else \ + (__q) = (__e)->next; \ + } +#define INSERT(__q, __l, __e) { \ + if (__l) { \ + (__e)->next = (__l)->next; \ + (__l)->next = (__e); \ + } else { \ + (__e)->next = (__q); \ + (__q) = (__e); \ + } \ + } + +#define DEFAULT_SLEEP_CYCLES 1000 + +void +avr_cycle_timer_reset( + struct avr_t * avr) +{ + avr_cycle_timer_pool_t * pool = &avr->cycle_timers; + memset(pool, 0, sizeof(*pool)); + // queue all slots into the free queue + for (int i = 0; i < MAX_CYCLE_TIMERS; i++) { + avr_cycle_timer_slot_p t = &pool->timer_slots[i]; + QUEUE(pool->timer_free, t); + } + avr->run_cycle_count = 1; + avr->run_cycle_limit = 1; +} + +static avr_cycle_count_t +avr_cycle_timer_return_sleep_run_cycles_limited( + avr_t *avr, + avr_cycle_count_t sleep_cycle_count) +{ + // run_cycle_count is bound to run_cycle_limit but NOT less than 1 cycle... + // this is not an error!.. unless you like deadlock. + avr_cycle_count_t run_cycle_count = ((avr->run_cycle_limit >= sleep_cycle_count) ? + sleep_cycle_count : avr->run_cycle_limit); + avr->run_cycle_count = run_cycle_count ? run_cycle_count : 1; + + // sleep cycles are returned unbounded thus preserving original behavior. + return(sleep_cycle_count); +} + +static void +avr_cycle_timer_reset_sleep_run_cycles_limited( + avr_t *avr) +{ + avr_cycle_timer_pool_t * pool = &avr->cycle_timers; + avr_cycle_count_t sleep_cycle_count = DEFAULT_SLEEP_CYCLES; + + if(pool->timer) { + if(pool->timer->when > avr->cycle) { + sleep_cycle_count = pool->timer->when - avr->cycle; + } else { + sleep_cycle_count = 0; + } + } + + avr_cycle_timer_return_sleep_run_cycles_limited(avr, sleep_cycle_count); +} + +// no sanity checks checking here, on purpose +static void +avr_cycle_timer_insert( + avr_t * avr, + avr_cycle_count_t when, + avr_cycle_timer_t timer, + void * param) +{ + avr_cycle_timer_pool_t * pool = &avr->cycle_timers; + + when += avr->cycle; + + avr_cycle_timer_slot_p t = pool->timer_free; + + if (!t) { + AVR_LOG(avr, LOG_ERROR, "CYCLE: %s: ran out of timers (%d)!\n", __func__, MAX_CYCLE_TIMERS); + return; + } + // detach head + pool->timer_free = t->next; + t->next = NULL; + t->timer = timer; + t->param = param; + t->when = when; + + // find its place in the list + avr_cycle_timer_slot_p loop = pool->timer, last = NULL; + while (loop) { + if (loop->when > when) + break; + last = loop; + loop = loop->next; + } + INSERT(pool->timer, last, t); +} + +void +avr_cycle_timer_register( + avr_t * avr, + avr_cycle_count_t when, + avr_cycle_timer_t timer, + void * param) +{ + avr_cycle_timer_pool_t * pool = &avr->cycle_timers; + + // remove it if it was already scheduled + avr_cycle_timer_cancel(avr, timer, param); + + if (!pool->timer_free) { + AVR_LOG(avr, LOG_ERROR, "CYCLE: %s: pool is full (%d)!\n", __func__, MAX_CYCLE_TIMERS); + return; + } + avr_cycle_timer_insert(avr, when, timer, param); + avr_cycle_timer_reset_sleep_run_cycles_limited(avr); +} + +void +avr_cycle_timer_register_usec( + avr_t * avr, + uint32_t when, + avr_cycle_timer_t timer, + void * param) +{ + avr_cycle_timer_register(avr, avr_usec_to_cycles(avr, when), timer, param); +} + +void +avr_cycle_timer_cancel( + avr_t * avr, + avr_cycle_timer_t timer, + void * param) +{ + avr_cycle_timer_pool_t * pool = &avr->cycle_timers; + + // find its place in the list + avr_cycle_timer_slot_p t = pool->timer, last = NULL; + while (t) { + if (t->timer == timer && t->param == param) { + DETACH(pool->timer, last, t); + QUEUE(pool->timer_free, t); + break; + } + last = t; + t = t->next; + } + avr_cycle_timer_reset_sleep_run_cycles_limited(avr); +} + +/* + * Check to see if a timer is present, if so, return the number (+1) of + * cycles left for it to fire, and if not present, return zero + */ +avr_cycle_count_t +avr_cycle_timer_status( + avr_t * avr, + avr_cycle_timer_t timer, + void * param) +{ + avr_cycle_timer_pool_t * pool = &avr->cycle_timers; + + // find its place in the list + avr_cycle_timer_slot_p t = pool->timer; + while (t) { + if (t->timer == timer && t->param == param) { + return 1 + (t->when - avr->cycle); + } + t = t->next; + } + return 0; +} + +/* + * run through all the timers, call the ones that needs it, + * clear the ones that wants it, and calculate the next + * potential cycle we could sleep for... + */ +avr_cycle_count_t +avr_cycle_timer_process( + avr_t * avr) +{ + avr_cycle_timer_pool_t * pool = &avr->cycle_timers; + + if (pool->timer) do { + avr_cycle_timer_slot_p t = pool->timer; + avr_cycle_count_t when = t->when; + + if (when > avr->cycle) + return avr_cycle_timer_return_sleep_run_cycles_limited(avr, when - avr->cycle); + + // detach from active timers + pool->timer = t->next; + t->next = NULL; + do { + avr_cycle_count_t w = t->timer(avr, when, t->param); + // make sure the return value is either zero, or greater + // than the last one to prevent infinite loop here + when = w > when ? w : 0; + } while (when && when <= avr->cycle); + + if (when) // reschedule then + avr_cycle_timer_insert(avr, when - avr->cycle, t->timer, t->param); + + // requeue this one into the free ones + QUEUE(pool->timer_free, t); + } while (pool->timer); + + // original behavior was to return 1000 cycles when no timers were present... + // run_cycles are bound to at least one cycle but no more than requested limit... + // value passed here is returned unbounded, thus preserving original behavior. + return avr_cycle_timer_return_sleep_run_cycles_limited(avr, DEFAULT_SLEEP_CYCLES); +} diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_cycle_timers.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_cycle_timers.h new file mode 100644 index 0000000..a4dfdf7 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_cycle_timers.h @@ -0,0 +1,121 @@ +/* + sim_cycle_timers.h + + Copyright 2008-2012 Michel Pollet + + 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 . + */ + +/* + * cycle timers are callbacks that will be called when "when" cycle is reached + * these timers are one shots, then get cleared if the timer function returns zero, + * they get reset if the callback function returns a new cycle number + * + * the implementation maintains a list of 'pending' timers, sorted by when they + * should run, it allows very quick comparison with the next timer to run, and + * quick removal of then from the pile once dispatched. + */ +#ifndef __SIM_CYCLE_TIMERS_H___ +#define __SIM_CYCLE_TIMERS_H___ + +#include "sim_avr_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_CYCLE_TIMERS 64 + +typedef avr_cycle_count_t (*avr_cycle_timer_t)( + struct avr_t * avr, + avr_cycle_count_t when, + void * param); + +/* + * Each timer instance contains the absolute cycle number they + * are hoping to run at, a function pointer to call and a parameter + * + * it will NEVER be the exact cycle specified, as each instruction is + * not divisible and might take 2 or more cycles anyway. + * + * However if there was a LOT of cycle lag, the timer migth be called + * repeteadly until it 'caches up'. + */ +typedef struct avr_cycle_timer_slot_t { + struct avr_cycle_timer_slot_t *next; + avr_cycle_count_t when; + avr_cycle_timer_t timer; + void * param; +} avr_cycle_timer_slot_t, *avr_cycle_timer_slot_p; + +/* + * Timer pool contains a pool of timer slots available, they all + * start queued into the 'free' qeueue, are migrated to the + * 'active' queue when needed and are re-queued to the free one + * when done + */ +typedef struct avr_cycle_timer_pool_t { + avr_cycle_timer_slot_t timer_slots[MAX_CYCLE_TIMERS]; + avr_cycle_timer_slot_p timer_free; + avr_cycle_timer_slot_p timer; +} avr_cycle_timer_pool_t, *avr_cycle_timer_pool_p; + + +// register for calling 'timer' in 'when' cycles +void +avr_cycle_timer_register( + struct avr_t * avr, + avr_cycle_count_t when, + avr_cycle_timer_t timer, + void * param); +// register a timer to call in 'when' usec +void +avr_cycle_timer_register_usec( + struct avr_t * avr, + uint32_t when, + avr_cycle_timer_t timer, + void * param); +// cancel a previously set timer +void +avr_cycle_timer_cancel( + struct avr_t * avr, + avr_cycle_timer_t timer, + void * param); +/* + * Check to see if a timer is present, if so, return the number (+1) of + * cycles left for it to fire, and if not present, return zero + */ +avr_cycle_count_t +avr_cycle_timer_status( + struct avr_t * avr, + avr_cycle_timer_t timer, + void * param); + +// +// Private, called from the core +// +avr_cycle_count_t +avr_cycle_timer_process( + struct avr_t * avr); +void +avr_cycle_timer_reset( + struct avr_t * avr); + +#ifdef __cplusplus +}; +#endif + +#endif /* __SIM_CYCLE_TIMERS_H___ */ diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_elf.c b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_elf.c new file mode 100644 index 0000000..df69b81 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_elf.c @@ -0,0 +1,499 @@ +/* + sim_elf.c + + Loads a .elf file, extract the code, the data, the eeprom and + the "mcu" specification section, also load usable code symbols + to be able to print meaningful trace information. + + Copyright 2008, 2009 Michel Pollet + + 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 +#include +#include +#include +#include +#include + +#include "sim_elf.h" +#include "sim_vcd_file.h" +#include "avr_eeprom.h" +#include "avr_ioport.h" + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +void +avr_load_firmware( + avr_t * avr, + elf_firmware_t * firmware) +{ + if (firmware->frequency) + avr->frequency = firmware->frequency; + if (firmware->vcc) + avr->vcc = firmware->vcc; + if (firmware->avcc) + avr->avcc = firmware->avcc; + if (firmware->aref) + avr->aref = firmware->aref; +#if CONFIG_SIMAVR_TRACE && ELF_SYMBOLS + int scount = firmware->flashsize >> 1; + avr->trace_data->codeline = malloc(scount * sizeof(avr_symbol_t*)); + memset(avr->trace_data->codeline, 0, scount * sizeof(avr_symbol_t*)); + + for (int i = 0; i < firmware->symbolcount; i++) + if (firmware->symbol[i]->addr < firmware->flashsize) // code address + avr->trace_data->codeline[firmware->symbol[i]->addr >> 1] = + firmware->symbol[i]; + // "spread" the pointers for known symbols forward + avr_symbol_t * last = NULL; + for (int i = 0; i < scount; i++) { + if (!avr->trace_data->codeline[i]) + avr->trace_data->codeline[i] = last; + else + last = avr->trace_data->codeline[i]; + } +#endif + + 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); + } + if (firmware->fuse) + memcpy(avr->fuse, firmware->fuse, firmware->fusesize); + if (firmware->lockbits) + avr->lockbits = firmware->lockbits[0]; + // load the default pull up/down values for ports + for (int i = 0; i < 8 && firmware->external_state[i].port; i++) { + avr_ioport_external_t e = { + .name = firmware->external_state[i].port, + .mask = firmware->external_state[i].mask, + .value = firmware->external_state[i].value, + }; + avr_ioctl(avr, AVR_IOCTL_IOPORT_SET_EXTERNAL(e.name), &e); + } + avr_set_command_register(avr, firmware->command_register_addr); + avr_set_console_register(avr, firmware->console_register_addr); + + // rest is initialization of the VCD file + if (firmware->tracecount == 0) + return; + avr->vcd = malloc(sizeof(*avr->vcd)); + memset(avr->vcd, 0, sizeof(*avr->vcd)); + avr_vcd_init(avr, + firmware->tracename[0] ? firmware->tracename: "gtkwave_trace.vcd", + avr->vcd, + firmware->traceperiod >= 1000 ? firmware->traceperiod : 1000); + + AVR_LOG(avr, LOG_TRACE, "Creating VCD trace file '%s'\n", + avr->vcd->filename); + + for (int ti = 0; ti < firmware->tracecount; ti++) { + if (firmware->trace[ti].kind == AVR_MMCU_TAG_VCD_PORTPIN) { + avr_irq_t * irq = avr_io_getirq(avr, + AVR_IOCTL_IOPORT_GETIRQ(firmware->trace[ti].mask), + firmware->trace[ti].addr); + if (irq) { + char name[16]; + sprintf(name, "%c%d", firmware->trace[ti].mask, + firmware->trace[ti].addr); + avr_vcd_add_signal(avr->vcd, irq, 1, + firmware->trace[ti].name[0] ? + firmware->trace[ti].name : name); + } + } else if (firmware->trace[ti].kind == AVR_MMCU_TAG_VCD_IRQ) { + avr_irq_t * bit = avr_get_interrupt_irq(avr, firmware->trace[ti].mask); + if (bit && firmware->trace[ti].addr < AVR_INT_IRQ_COUNT) + avr_vcd_add_signal(avr->vcd, + &bit[firmware->trace[ti].addr], + firmware->trace[ti].mask == 0xff ? 8 : 1, + firmware->trace[ti].name); + } else if (firmware->trace[ti].mask == 0xff || + firmware->trace[ti].mask == 0) { + // easy one + avr_irq_t * all = avr_iomem_getirq(avr, + firmware->trace[ti].addr, + firmware->trace[ti].name, + AVR_IOMEM_IRQ_ALL); + if (!all) { + AVR_LOG(avr, LOG_ERROR, + "ELF: %s: unable to attach trace to address %04x\n", + __FUNCTION__, firmware->trace[ti].addr); + } else { + avr_vcd_add_signal(avr->vcd, all, 8, + firmware->trace[ti].name); + } + } else { + int count = __builtin_popcount(firmware->trace[ti].mask); + // for (int bi = 0; bi < 8; bi++) + // if (firmware->trace[ti].mask & (1 << bi)) + // count++; + for (int bi = 0; bi < 8; bi++) + if (firmware->trace[ti].mask & (1 << bi)) { + avr_irq_t * bit = avr_iomem_getirq(avr, + firmware->trace[ti].addr, + firmware->trace[ti].name, + bi); + if (!bit) { + AVR_LOG(avr, LOG_ERROR, + "ELF: %s: unable to attach trace to address %04x\n", + __FUNCTION__, firmware->trace[ti].addr); + break; + } + + if (count == 1) { + avr_vcd_add_signal(avr->vcd, + bit, 1, firmware->trace[ti].name); + break; + } + char comp[128]; + sprintf(comp, "%s.%d", firmware->trace[ti].name, bi); + avr_vcd_add_signal(avr->vcd, bit, 1, comp); + } + } + } + // 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) +{ +// hdump(".mmcu", src, size); + while (size) { + uint8_t tag = *src++; + uint8_t ts = *src++; + int next = size > 2 + ts ? 2 + ts : size; + // printf("elf_parse_mmcu_section %2d, size %2d / remains %3d\n", + // tag, ts, size); + switch (tag) { + case AVR_MMCU_TAG_FREQUENCY: + firmware->frequency = + src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24); + break; + case AVR_MMCU_TAG_NAME: + strcpy(firmware->mmcu, (char*)src); + break; + case AVR_MMCU_TAG_VCC: + firmware->vcc = + src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24); + break; + case AVR_MMCU_TAG_AVCC: + firmware->avcc = + src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24); + break; + case AVR_MMCU_TAG_AREF: + firmware->aref = + src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24); + break; + case AVR_MMCU_TAG_PORT_EXTERNAL_PULL: { + for (int i = 0; i < 8; i++) + if (!firmware->external_state[i].port) { + firmware->external_state[i].port = src[2]; + firmware->external_state[i].mask = src[1]; + firmware->external_state[i].value = src[0]; +#if 0 + AVR_LOG(NULL, LOG_DEBUG, + "AVR_MMCU_TAG_PORT_EXTERNAL_PULL[%d] %c:%02x:%02x\n", + i, firmware->external_state[i].port, + firmware->external_state[i].mask, + firmware->external_state[i].value); +#endif + break; + } + } break; + case AVR_MMCU_TAG_VCD_PORTPIN: + case AVR_MMCU_TAG_VCD_IRQ: + case AVR_MMCU_TAG_VCD_TRACE: { + uint8_t mask = src[0]; + uint16_t addr = src[1] | (src[2] << 8); + char * name = (char*)src + 3; + +#if 0 + AVR_LOG(NULL, LOG_DEBUG, + "VCD_TRACE %d %04x:%02x - %s\n", tag, + addr, mask, name); +#endif + firmware->trace[firmware->tracecount].kind = tag; + firmware->trace[firmware->tracecount].mask = mask; + firmware->trace[firmware->tracecount].addr = addr; + strncpy(firmware->trace[firmware->tracecount].name, name, + sizeof(firmware->trace[firmware->tracecount].name)); + firmware->tracecount++; + } break; + case AVR_MMCU_TAG_VCD_FILENAME: { + strcpy(firmware->tracename, (char*)src); + } break; + case AVR_MMCU_TAG_VCD_PERIOD: { + 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; + case AVR_MMCU_TAG_SIMAVR_CONSOLE: { + firmware->console_register_addr = src[0] | (src[1] << 8); + } break; + } + size -= next; + src += next - 2; // already incremented + } +} + +static int +elf_copy_segment(int fd, Elf32_Phdr *php, uint8_t **dest) +{ + int rv; + + if (*dest == NULL) + *dest = malloc(php->p_filesz); + if (!*dest) + return -1; + + lseek(fd, php->p_offset, SEEK_SET); + rv = read(fd, *dest, php->p_filesz); + if (rv != php->p_filesz) { + AVR_LOG(NULL, LOG_ERROR, + "Got %d when reading %d bytes for %x at offset %d " + "from ELF file\n", + rv, php->p_filesz, php->p_vaddr, php->p_offset); + return -1; + } + AVR_LOG(NULL, LOG_DEBUG, "Loaded %d bytes at %x\n", + php->p_filesz, php->p_vaddr); + return 0; +} + +static int +elf_handle_segment(int fd, Elf32_Phdr *php, uint8_t **dest, const char *name) +{ + if (*dest) { + AVR_LOG(NULL, LOG_ERROR, + "Unexpected extra %s data: %d bytes at %x.\n", + name, php->p_filesz, php->p_vaddr); + return -1; + } else { + elf_copy_segment(fd, php, dest); + return 0; + } +} + +/* The structure *firmware must be pre-initialised to zero, then optionally + * tracing and VCD information may be added. + */ + +int +elf_read_firmware( + const char * file, + elf_firmware_t * firmware) +{ + Elf32_Ehdr elf_header; /* ELF header */ + Elf *elf = NULL; /* Our Elf pointer for libelf */ + Elf32_Phdr *php; /* Program header. */ + Elf_Scn *scn = NULL; /* Section Descriptor */ + size_t ph_count; /* Program Header entry count. */ + int fd, i; /* File Descriptor */ + + if ((fd = open(file, O_RDONLY | O_BINARY)) == -1 || + (read(fd, &elf_header, sizeof(elf_header))) < sizeof(elf_header)) { + AVR_LOG(NULL, LOG_ERROR, "could not read %s\n", file); + perror(file); + close(fd); + return -1; + } + +#if ELF_SYMBOLS + firmware->symbolcount = 0; + firmware->symbol = NULL; +#endif + + /* this is actually mandatory !! otherwise elf_begin() fails */ + if (elf_version(EV_CURRENT) == EV_NONE) { + /* library out of date - recover from error */ + return -1; + } + // Iterate through section headers again this time well stop when we find symbols + elf = elf_begin(fd, ELF_C_READ, NULL); + //printf("Loading elf %s : %p\n", file, elf); + + if (!elf) + return -1; + if (elf_kind(elf) != ELF_K_ELF) { + AVR_LOG(NULL, LOG_ERROR, "Unexpected ELF file type\n"); + return -1; + } + + /* Scan the Program Header Table. */ + + if (elf_getphdrnum(elf, &ph_count) != 0 || ph_count == 0 || + (php = elf32_getphdr(elf)) == NULL) { + AVR_LOG(NULL, LOG_ERROR, "No ELF Program Headers\n"); + return -1; + } + + for (i = 0; i < (int)ph_count; ++i, ++php) { +#if 0 + printf("Header %d type %d addr %x/%x size %d/%d flags %x\n", + i, php->p_type, php->p_vaddr, php->p_paddr, + php->p_filesz, php->p_memsz, php->p_flags); +#endif + if (php->p_type != PT_LOAD || php->p_filesz == 0) + continue; + if (php->p_vaddr < 0x800000) { + /* Explicit flash section. Load it. */ + + if (elf_handle_segment(fd, php, &firmware->flash, "Flash")) + continue; + firmware->flashsize = php->p_filesz; + firmware->flashbase = php->p_vaddr; + } else if (php->p_vaddr < 0x810000) { + /* Data space. If there are initialised variables, treat + * them as extra initialised flash. The C startup function + * understands that and will copy them to RAM. + */ + + if (firmware->flash) { + uint8_t *where; + + firmware->flash = realloc(firmware->flash, + firmware->flashsize + php->p_filesz); + if (!firmware->flash) + return -1; + where = firmware->flash + firmware->flashsize; + elf_copy_segment(fd, php, &where); + firmware->flashsize += php->p_filesz; + } else { + /* If this ever happens, add a second pass. */ + + AVR_LOG(NULL, LOG_ERROR, + "Initialialised data but no flash (%d bytes at %x)!\n", + php->p_filesz, php->p_vaddr); + return -1; + } + } else if (php->p_vaddr < 0x820000) { + /* EEPROM. */ + + if (elf_handle_segment(fd, php, &firmware->eeprom, "EEPROM")) + continue; + firmware->eesize = php->p_filesz; + } else if (php->p_vaddr < 0x830000) { + /* Fuses. */ + + if (elf_handle_segment(fd, php, &firmware->fuse, "Fuses")) + continue; + firmware->fusesize = php->p_filesz; + } else if (php->p_vaddr < 0x840000) { + /* Lock bits. */ + + elf_handle_segment(fd, php, &firmware->lockbits, "Lock bits"); + } + } + + /* Scan the section table for .mmcu magic and symbols. */ + + while ((scn = elf_nextscn(elf, scn)) != NULL) { + GElf_Shdr shdr; /* Section Header */ + gelf_getshdr(scn, &shdr); + char * name = elf_strptr(elf, elf_header.e_shstrndx, shdr.sh_name); + // printf("Walking elf section '%s'\n", name); + + if (!strcmp(name, ".mmcu")) { + Elf_Data *s = elf_getdata(scn, NULL); + + elf_parse_mmcu_section(firmware, s->d_buf, s->d_size); + if (shdr.sh_addr < 0x860000) + AVR_LOG(NULL, LOG_WARNING, + "Warning: ELF .mmcu section at %x may be loaded.\n", + shdr.sh_addr); + // printf("%s: size %ld\n", __FUNCTION__, s->d_size); + // avr->frequency = f_cpu; + } + +#if ELF_SYMBOLS + // When we find a section header marked SHT_SYMTAB stop and get symbols + if (shdr.sh_type == SHT_SYMTAB) { + // edata points to our symbol table + Elf_Data *edata = elf_getdata(scn, NULL); + + // how many symbols are there? this number comes from the size of + // the section divided by the entry size + int symbol_count = shdr.sh_size / shdr.sh_entsize; + + // loop through to grab all symbols + for (int i = 0; i < symbol_count; i++) { + GElf_Sym sym; /* Symbol */ + // libelf grabs the symbol data using gelf_getsym() + gelf_getsym(edata, i, &sym); + + // print out the value and size + if (ELF32_ST_BIND(sym.st_info) == STB_GLOBAL || + ELF32_ST_TYPE(sym.st_info) == STT_FUNC || + ELF32_ST_TYPE(sym.st_info) == STT_OBJECT) { + const char * name = elf_strptr(elf, shdr.sh_link, sym.st_name); + + // if its a bootloader, this symbol will be the entry point we need + if (!strcmp(name, "__vectors")) + firmware->flashbase = sym.st_value; + avr_symbol_t * s = malloc(sizeof(avr_symbol_t) + strlen(name) + 1); + strcpy((char*)s->symbol, name); + s->addr = sym.st_value; + s->size = sym.st_size; + if (!(firmware->symbolcount % 8)) + firmware->symbol = realloc( + firmware->symbol, + (firmware->symbolcount + 8) * sizeof(firmware->symbol[0])); + + // insert new element, keep the array sorted + int insert = -1; + for (int si = 0; si < firmware->symbolcount && insert == -1; si++) + if (firmware->symbol[si]->addr >= s->addr) + insert = si; + if (insert == -1) + insert = firmware->symbolcount; + else + memmove(firmware->symbol + insert + 1, + firmware->symbol + insert, + (firmware->symbolcount - insert) * sizeof(firmware->symbol[0])); + firmware->symbol[insert] = s; + firmware->symbolcount++; + } + } + } +#endif // ELF_SYMBOLS + } + elf_end(elf); + close(fd); + return 0; +} diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_elf.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_elf.h new file mode 100644 index 0000000..37d61d7 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_elf.h @@ -0,0 +1,103 @@ +/* + sim_elf.h + + Copyright 2008, 2009 Michel Pollet + + 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 . + */ + +#ifndef __SIM_ELF_H__ +#define __SIM_ELF_H__ + +#include "avr/avr_mcu_section.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef ELF_SYMBOLS +#define ELF_SYMBOLS 1 +#endif + +/* these are the addresses the gnu linker uses to + * "fake" a non-Harvard addressing space for the AVR + */ +#define AVR_SEGMENT_OFFSET_FLASH 0 +#define AVR_SEGMENT_OFFSET_EEPROM 0x00810000 + +#include "sim_avr.h" + +typedef struct elf_firmware_t { + char mmcu[64]; + uint32_t frequency; + uint32_t vcc,avcc,aref; + + char tracename[128]; // trace filename + uint32_t traceperiod; + int tracecount; + struct { + uint8_t kind; + uint8_t mask; + uint16_t addr; + char name[64]; + } trace[32]; + + struct { + char port; + uint8_t mask, value; + } external_state[8]; + + // register to listen to for commands from the firmware + uint16_t command_register_addr; + uint16_t console_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 * fuse; + uint32_t fusesize; + uint8_t * lockbits; + +#if ELF_SYMBOLS + avr_symbol_t ** symbol; + uint32_t symbolcount; +#endif +} elf_firmware_t ; + +/* The structure *firmware must be pre-initialised to zero, then optionally + * with tracing and VCD information. + */ + +int +elf_read_firmware( + const char * file, + elf_firmware_t * firmware); + +void +avr_load_firmware( + avr_t * avr, + elf_firmware_t * firmware); + +#ifdef __cplusplus +}; +#endif + +#endif /*__SIM_ELF_H__*/ diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_gdb.c b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_gdb.c new file mode 100644 index 0000000..cd2196e --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_gdb.c @@ -0,0 +1,1026 @@ +/* + sim_gdb.c + + Copyright 2008, 2009 Michel Pollet + + 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 "sim_network.h" +#include +#include +#include +#include +#include +#include +#include +#include "sim_avr.h" +#include "sim_core.h" // for SET_SREG_FROM, READ_SREG_INTO +#include "sim_hex.h" +#include "avr_eeprom.h" +#include "sim_gdb.h" + +// For debug printfs: "#define DBG(w) w" +#define DBG(w) + +#define WATCH_LIMIT (32) + +typedef struct { + uint32_t len; /**< How many points are taken (points[0] .. points[len - 1]). */ + struct { + uint32_t addr; /**< Which address is watched. */ + uint32_t size; /**< How large is the watched segment. */ + uint32_t kind; /**< Bitmask of enum avr_gdb_watch_type values. */ + } points[WATCH_LIMIT]; +} avr_gdb_watchpoints_t; + +/* How many AVR instructions to execute before looking for gdb input. */ + +#define GDB_BURST 256 + +typedef struct avr_gdb_t { + avr_t * avr; + int burst_count; // Current instruction burst size + int listen; // listen socket + int s; // current gdb connection + + avr_gdb_watchpoints_t breakpoints; + avr_gdb_watchpoints_t watchpoints; + + // These are used by gdb's "info io_registers" command. + + uint16_t ior_base; + uint8_t ior_count, mad; +} avr_gdb_t; + + +/** + * Returns the index of the watchpoint if found, -1 otherwise. + */ +static int +gdb_watch_find( + const avr_gdb_watchpoints_t * w, + uint32_t addr ) +{ + for (int i = 0; i < w->len; i++) { + if (w->points[i].addr > addr) { + return -1; + } else if (w->points[i].addr == addr) { + return i; + } + } + return -1; +} + +/** + * Contrary to gdb_watch_find, this actually checks the address against + * a watched memory _range_. + */ +static int +gdb_watch_find_range( + const avr_gdb_watchpoints_t * w, + uint32_t addr ) +{ + for (int i = 0; i < w->len; i++) { + if (w->points[i].addr > addr) { + return -1; + } else if (w->points[i].addr <= addr && + addr < w->points[i].addr + w->points[i].size) { + return i; + } + } + return -1; +} + +/** + * Returns -1 on error, 0 otherwise. + */ +static int +gdb_watch_add_or_update( + avr_gdb_watchpoints_t * w, + enum avr_gdb_watch_type kind, + uint32_t addr, + uint32_t size ) +{ + if (kind == AVR_GDB_WATCH_ACCESS) + kind |= AVR_GDB_WATCH_WRITE | AVR_GDB_WATCH_READ; + + /* If the watchpoint exists, update it. */ + int i = gdb_watch_find(w, addr); + if (i != -1) { + w->points[i].size = size; + w->points[i].kind |= kind; + return 0; + } + + /* Otherwise add it. */ + if (w->len == WATCH_LIMIT) { + return -1; + } + + /* Find the insertion point. */ + for (i = 0; i < w->len; i++) { + if (w->points[i].addr > addr) { + break; + } + } + + w->len++; + + /* Make space for new element, moving old ones from the end. */ + for (int j = w->len; j > i; j--) { + w->points[j] = w->points[j - 1]; + } + + /* Insert it. */ + w->points[i].kind = kind; + w->points[i].addr = addr; + w->points[i].size = size; + + return 0; +} + +/** + * Returns -1 on error or if the specified point does not exist, 0 otherwise. + */ +static int +gdb_watch_rm( + avr_gdb_watchpoints_t * w, + enum avr_gdb_watch_type kind, + uint32_t addr ) +{ + int i = gdb_watch_find(w, addr); + if (i == -1) { + return -1; + } + + w->points[i].kind &= ~kind; + if (w->points[i].kind) { + return 0; + } + + for (i = i + 1; i < w->len; i++) { + w->points[i - 1] = w->points[i]; + } + + w->len--; + + return 0; +} + +static void +gdb_watch_clear( + avr_gdb_watchpoints_t * w ) +{ + w->len = 0; +} + +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); + DBG(printf("%s '%s'\n", __FUNCTION__, reply);) + send(g->s, reply, dst - reply + 3, 0); +} + +static void +gdb_send_stop_status( + avr_gdb_t * g, + uint8_t signal, + const char * reason, + uint32_t * pp ) +{ + avr_t * avr; + uint8_t sreg; + int n; + char cmd[64]; + + avr = g->avr; + READ_SREG_INTO(avr, sreg); + + n = sprintf(cmd, "T%02x20:%02x;21:%02x%02x;22:%02x%02x%02x00;", + signal, sreg, + avr->data[R_SPL], avr->data[R_SPH], + avr->pc & 0xff, (avr->pc >> 8) & 0xff, + (avr->pc >> 16) & 0xff); + if (reason) { + if (pp) + sprintf(cmd + n, "%s:%x;", reason, *pp); + else + sprintf(cmd + n, "%s:;", reason); + } + gdb_send_reply(g, cmd); +} + +static void +gdb_send_quick_status( + avr_gdb_t * g, + uint8_t signal ) +{ + gdb_send_stop_status(g, signal, NULL, NULL); +} + +static int +gdb_change_breakpoint( + avr_gdb_watchpoints_t * w, + int set, + enum avr_gdb_watch_type kind, + uint32_t addr, + uint32_t size ) +{ + DBG(printf("%s kind %d addr %08x len %d\n", set ? "Set" : "Clear", + kind, addr, size);) + + if (set) { + return gdb_watch_add_or_update(w, kind, addr, size); + } else { + return gdb_watch_rm(w, kind, addr); + } + return -1; +} + +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; + SET_SREG_FROM(g->avr, *src); + return 1; + case 33: + g->avr->data[R_SPL] = src[0]; + g->avr->data[R_SPH] = src[1]; + 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: { + uint8_t sreg; + READ_SREG_INTO(g->avr, sreg); + sprintf(rep, "%02x", 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 int tohex(const char *in, char *out, unsigned int len) +{ + int n = 0; + + while (*in && n + 2 < len) + n += sprintf(out + n, "%02x", (uint8_t)*in++); + return n; +} + +/* Send a message to the user. Gdb must be expecting a reply, otherwise this + * is ignored. + */ + +static void message(avr_gdb_t * g, const char *m) +{ + char buff[256]; + + buff[0] = 'O'; + tohex(m, buff + 1, sizeof buff - 1); + gdb_send_reply(g, buff); +} + +static int +handle_monitor(avr_t * avr, avr_gdb_t * g, char * cmd) +{ + char *ip, *op; + unsigned int c1, c2; + char dehex[128]; + + if (*cmd++ != ',') + return 1; // Bad format + for (op = dehex; op < dehex + (sizeof dehex - 1); ++op) { + if (!*cmd) + break; + if (sscanf(cmd, "%1x%1x", &c1, &c2) != 2) + return 2; // Bad format + *op = (c1 << 4) + c2; + cmd += 2; + } + *op = '\0'; + if (*cmd) + return 3; // Too long + ip = dehex; + while (*ip) { + while (*ip == ' ' || *ip == '\t') + ++ip; + + if (strncmp(ip, "reset", 5) == 0) { + avr_reset(avr); + avr->state = cpu_Stopped; + ip += 5; + } else if (strncmp(ip, "halt", 4) == 0) { + avr->state = cpu_Stopped; + ip += 4; + } else if (strncmp(ip, "ior", 3) == 0) { + unsigned int base; + int n, m, count; + + // Format is "ior + // or just "ior" to reset. + + ip += 3; + m = sscanf(ip, "%x %i%n", &base, &count, &n); + if (m <= 0) { + // Reset values. + + g->ior_base = g->ior_count = 0; + n = 0; + } else if (m != 2) { + return 1; + } else { + if (count <= 0 || base + count + 32 > REG_NAME_COUNT || + base + count + 32 > avr->ioend) { + return 4; // bad value + } + g->ior_base = base; + g->ior_count = count; + } + ip += n; + DBG( + } else if (strncmp(ip, "say ", 4) == 0) { + // Put a message in the debug output. + printf("Say: %s\n", ip + 4); + ip += strlen(ip); + ) + } else { + tohex("Monitor subcommands are: ior halt reset" DBG(" say") "\n", + dehex, sizeof dehex); + gdb_send_reply(g, dehex); + return -1; + } + } + return 0; +} + +static void +handle_io_registers(avr_t * avr, avr_gdb_t * g, char * cmd) +{ + extern const char *avr_regname(unsigned int); // sim_core.c + char * params; + char * reply; + unsigned int addr, count; + char buff[1024]; + + if (g->mad) { + /* For this command, gdb employs a streaming protocol, + * with the command being repeated until the stub sends + * an empy packet as terminator. That makes no sense, + * as the requests are sized to ensure the reply will + * fit in a single packet. + */ + + reply = ""; + g->mad = 0; + } else { + params = cmd + 11; + if (sscanf(params, ":%x,%x", &addr, &count) == 2) { + int i; + + // Send names and values. + addr += 32; + if (addr + count > avr->ioend) + count = avr->ioend + 1 - addr; + reply = buff; + for (i = 0; i < count; ++i) { + const char *name; + + name = avr_regname(addr + i); + reply += sprintf(reply, "%s,%x;", + name, avr->data[addr + i]); + if (reply > buff + sizeof buff - 20) + break; + } + } else { + // Send register count. + + count = g->ior_count ? g->ior_count : + avr->ioend > REG_NAME_COUNT ? + REG_NAME_COUNT - 32 : avr->ioend - 32; + sprintf(buff, "%x", count); + } + reply = buff; + g->mad = 1; + } + gdb_send_reply(g, reply); +} + +static void +handle_v(avr_t * avr, avr_gdb_t * g, char * cmd, int length) +{ + uint32_t addr; + uint8_t *src = NULL; + int len, err = -1; + + if (strncmp(cmd, "FlashErase", 10) == 0) { + + sscanf(cmd, "%*[^:]:%x,%x", &addr, &len); + if (addr < avr->flashend) { + src = avr->flash + addr; + if (addr + len > avr->flashend) + len = avr->flashend - addr; + memset(src, 0xff, len); + DBG(printf("FlashErase: %x,%x\n", addr, len);) //Remove + } else { + err = 1; + } + } else if (strncmp(cmd, "FlashWrite", 10) == 0) { + if (sscanf(cmd, "%*[^:]:%x:%n", &addr, &len) != 1) { + err = 2; + } else { + if (len >= length) { + err = 99; + } else if (addr < avr->flashend) { + int escaped; + char *end; + uint8_t *limit; + + end = cmd + length - 1; // Ignore final '#'. + cmd += len; + src = avr->flash + addr; + limit = avr->flash + avr->flashend; + for (escaped = 0; cmd < end && src < limit; ++cmd) { + if (escaped) { + *src++ = *cmd ^ 0x20; + escaped = 0; + } else if (*cmd == '}') { + escaped = 1; + } else { + *src++ = *cmd; + } + } + DBG(printf("FlashWrite %x, %ld bytes\n", addr, + (src - avr->flash) - addr);) + addr = src - avr->flash; // Address of end. + if (addr > avr->codeend) // Checked by sim_core.c + avr->codeend = addr; + if (cmd != end) { + DBG(printf("FlashWrite %ld bytes left!\n", end - cmd)); + } + } else { + err = 1; + } + } + } else if (strncmp(cmd, "FlashDone", 9) == 0) { + DBG(printf("FlashDone\n");) //Remove + } else { + gdb_send_reply(g, ""); + return; + } + + if (err < 0) { + gdb_send_reply(g, "OK"); + } else { + char b[32]; + + sprintf(b, "E %.2d", err); + gdb_send_reply(g, b); + } +} + +static void +gdb_handle_command( + avr_gdb_t * g, + char * cmd, + int length) +{ + avr_t * avr = g->avr; + char rep[1024]; + uint8_t command = *cmd++; + switch (command) { + case 'q': + if (strncmp(cmd, "Supported", 9) == 0) { + /* If GDB asked what features we support, report back + * the features we support, which is just memory layout + * information and stop reasons for now. + */ + gdb_send_reply(g, "qXfer:memory-map:read+;swbreak+;hwbreak+"); + break; + } else if (strncmp(cmd, "Attached", 8) == 0) { + /* Respond that we are attached to an existing process.. + * ourselves! + */ + gdb_send_reply(g, "1"); + break; + // Rmoving the following 3 lines fixes #150 issue: + // } else if (strncmp(cmd, "Offsets", 7) == 0) { + // gdb_send_reply(g, "Text=0;Data=800000;Bss=800000"); + // break; + } else if (strncmp(cmd, "Xfer:memory-map:read", 20) == 0) { + snprintf(rep, sizeof(rep), + "l\n" + " \n" + " \n" + " 0x80\n" + " \n" + "", + g->avr->ramend + 1, g->avr->flashend + 1); + + gdb_send_reply(g, rep); + break; + } else if (strncmp(cmd, "RegisterInfo", 12) == 0) { + // Send back the information we have on this register (if any). + long n = strtol(cmd + 12, NULL, 16); + if (n < 32) { + // General purpose (8-bit) registers. + snprintf(rep, sizeof(rep), "name:r%ld;bitsize:8;offset:0;encoding:uint;format:hex;set:General Purpose Registers;gcc:%ld;dwarf:%ld;", n, n, n); + gdb_send_reply(g, rep); + break; + } else if (n == 32) { + // SREG (flags) register. + snprintf(rep, sizeof(rep), "name:sreg;bitsize:8;offset:0;encoding:uint;format:binary;set:General Purpose Registers;gcc:32;dwarf:32;"); + gdb_send_reply(g, rep); + break; + } else if (n == 33) { + // SP register (SPH and SPL combined). + snprintf(rep, sizeof(rep), "name:sp;bitsize:16;offset:0;encoding:uint;format:hex;set:General Purpose Registers;gcc:33;dwarf:33;generic:sp;"); + gdb_send_reply(g, rep); + break; + } else if (n == 34) { + // PC register + snprintf(rep, sizeof(rep), "name:pc;bitsize:32;offset:0;encoding:uint;format:hex;set:General Purpose Registers;gcc:34;dwarf:34;generic:pc;"); + gdb_send_reply(g, rep); + break; + } else { + // Register not available. + // By sending back nothing, the debugger knows it has read + // all available registers. + } + } else if (strncmp(cmd, "Rcmd", 4) == 0) { // monitor command + int err = handle_monitor(avr, g, cmd + 4); + if (err > 0) { + snprintf(rep, sizeof rep, + "E%02x", err); + gdb_send_reply(g, rep); + } else if (err == 0) { + gdb_send_reply(g, "OK"); + } + break; + } else if (strncmp(cmd, "Ravr.io_reg", 11) == 0) { + handle_io_registers(avr, g, cmd); + break; + } + gdb_send_reply(g, ""); + break; + case '?': + gdb_send_quick_status(g, 0); + break; + 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); + gdb_read_register(g, regi, rep); + gdb_send_reply(g, rep); + } break; + 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 + avr_flashaddr_t addr; + uint32_t len; + sscanf(cmd, "%x,%x", &addr, &len); + uint8_t * src = NULL; + /* GDB seems to also use 0x1800000 for sram ?!?! */ + addr &= 0xffffff; + if (addr < avr->flashend) { + src = avr->flash + addr; + } else if (addr >= 0x800000 && (addr - 0x800000) <= avr->ramend) { + src = avr->data + addr - 0x800000; + } else if (addr == (0x800000 + avr->ramend + 1) && len == 2) { + // Allow GDB to read a value just after end of stack. + // This is necessary to make instruction stepping work when stack is empty + AVR_LOG(avr, LOG_TRACE, + "GDB: read just past end of stack %08x, %08x; returning zero\n", addr, len); + gdb_send_reply(g, "0000"); + break; + } 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) + src = ee.ee; + else { + gdb_send_reply(g, "E01"); + break; + } + } else { + AVR_LOG(avr, LOG_ERROR, + "GDB: read memory error %08x, %08x (ramend %04x)\n", + addr, len, avr->ramend+1); + 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': { // write memory + uint32_t addr, len; + sscanf(cmd, "%x,%x", &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 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 { + AVR_LOG(avr, LOG_ERROR, "GDB: write memory error %08x, %08x\n", addr, len); + gdb_send_reply(g, "E01"); + } + } break; + case 'c': { // continue + avr->state = cpu_Running; + } break; + case 's': { // step + avr->state = cpu_Step; + } break; + case 'r': { // deprecated, suggested for AVRStudio compatibility + avr_reset(avr); + avr->state = cpu_Stopped; + } break; + case 'Z': // set clear break/watchpoint + case 'z': { + uint32_t kind, addr, len; + int set = (command == 'Z'); + sscanf(cmd, "%d,%x,%x", &kind, &addr, &len); +// printf("breakpoint %d, %08x, %08x\n", kind, addr, len); + switch (kind) { + case 0: // software breakpoint + case 1: // hardware breakpoint + if (addr > avr->flashend || + gdb_change_breakpoint(&g->breakpoints, set, 1 << kind, addr, len) == -1) { + gdb_send_reply(g, "E01"); + break; + } + + gdb_send_reply(g, "OK"); + break; + case 2: // write watchpoint + case 3: // read watchpoint + case 4: // access watchpoint + /* Mask out the offset applied to SRAM addresses. */ + addr &= ~0x800000; + if (addr > avr->ramend || + gdb_change_breakpoint(&g->watchpoints, set, 1 << kind, addr, len) == -1) { + gdb_send_reply(g, "E01"); + break; + } + + gdb_send_reply(g, "OK"); + break; + default: + gdb_send_reply(g, ""); + break; + } + } break; + case 'D': // detach +#ifdef DETACHABLE + if (avr->state = cpu_Stopped) + avr->state = cpu_Running; + gdb_send_reply(g, "OK"); + close(g->s); + g->s = -1; + break; +#endif + case 'k': // kill + avr->state = cpu_Done; + gdb_send_reply(g, "OK"); + break; + case 'v': + handle_v(avr, g, cmd, length); + break; + default: + gdb_send_reply(g, ""); + break; + } +} + +static int +gdb_network_handler( + avr_gdb_t * g, + uint32_t dosleep ) +{ + fd_set read_set; + int max; + FD_ZERO(&read_set); + + g->burst_count = 0; // Reset burst count + 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 = { dosleep / 1000000, dosleep % 1000000 }; + 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; + DBG(printf("%s connection opened\n", __FUNCTION__);) + } + + if (g->s != -1 && FD_ISSET(g->s, &read_set)) { + uint8_t buffer[1024]; + + ssize_t r = recv(g->s, buffer, sizeof(buffer)-1, 0); + + if (r == 0) { + DBG(printf("%s connection closed\n", __FUNCTION__);) + close(g->s); + gdb_watch_clear(&g->breakpoints); + gdb_watch_clear(&g->watchpoints); + 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; + + uint8_t * src = buffer; + while (*src == '+' || *src == '-') + src++; + DBG( + if (!strncmp("$vFlashWrite", (char *)src, 12)) { + printf("%s: received Flashwrite command %ld bytes\n", + __FUNCTION__, r); + } else { + printf("%s: received command %ld bytes\n'%s'\n", + __FUNCTION__, r, buffer); + }) + // hdump("gdb", buffer, r); + // control C -- lets send the guy a nice status packet + if (*src == 3) { + src++; + gdb_send_quick_status(g, 2); // SIGINT + g->avr->state = cpu_Stopped; + printf("GDB hit control-c\n"); + } else if (*src == '$') { + // strip checksum + uint8_t * end = buffer + r - 1; + while (end > src && *end != '#') + *end-- = 0; + *end = 0; + src++; + DBG( + if (strncmp("vFlashWrite", (char *)src, 11)) + printf("GDB command = '%s'\n", src);) + send(g->s, "+", 1, 0); + if (end > src) + gdb_handle_command(g, (char*)src, end - src); + } + } + return 1; +} + +/* Called on a hardware break instruction. */ +void avr_gdb_handle_break(avr_t *avr) +{ + avr_gdb_t *g = avr->gdb; + + message(g, "Simavr executed 'break' instruction.\n"); + //gdb_send_stop_status(g, 5, "swbreak", NULL); Correct but ignored! + gdb_send_quick_status(g, 5); +} + +/** + * If an applicable watchpoint exists for addr, stop the cpu and send a status report. + * type is one of AVR_GDB_WATCH_READ, AVR_GDB_WATCH_WRITE depending on the type of access. + */ +void +avr_gdb_handle_watchpoints( + avr_t * avr, + uint16_t addr, + enum avr_gdb_watch_type type ) +{ + avr_gdb_t *g = avr->gdb; + uint32_t false_addr; + + int i = gdb_watch_find_range(&g->watchpoints, addr); + if (i == -1) { + return; + } + + int kind = g->watchpoints.points[i].kind; + DBG(printf("Addr %04x found watchpoint %d size %d type %x wanted %x\n", + addr, i, g->watchpoints.points[i].size, kind, type);) + if (kind & type) { + /* Send gdb reply (see GDB user manual appendix E.3). */ + + const char * what; + + what = (kind & AVR_GDB_WATCH_ACCESS) ? "awatch" : + (kind & AVR_GDB_WATCH_WRITE) ? "watch" : "rwatch"; + false_addr = addr + 0x800000; + gdb_send_stop_status(g, 5, what, &false_addr); + avr->state = cpu_Stopped; + } +} + +int +avr_gdb_processor( + avr_t * avr, + int sleep ) +{ + if (!avr || !avr->gdb) + return 0; + avr_gdb_t * g = avr->gdb; + + if (avr->state == cpu_Running && + gdb_watch_find(&g->breakpoints, avr->pc) != -1) { + DBG(printf("avr_gdb_processor hit breakpoint at %08x\n", avr->pc);) + gdb_send_stop_status(g, 5, "hwbreak", NULL); + avr->state = cpu_Stopped; + } else if (avr->state == cpu_StepDone) { + gdb_send_quick_status(g, 0); + avr->state = cpu_Stopped; + } else { + /* Look for gdb input every GDB_BURST instructions. */ + + if (sleep == 0 && g->burst_count++ < GDB_BURST) + return 0; + } + return gdb_network_handler(g, sleep); +} + + +int +avr_gdb_init( + avr_t * avr ) +{ + if (avr->gdb) + return 0; // GDB server already is active + + avr_gdb_t * g = malloc(sizeof(avr_gdb_t)); + memset(g, 0, sizeof(avr_gdb_t)); + + avr->gdb = NULL; + + if ( network_init() ) { + AVR_LOG(avr, LOG_ERROR, "GDB: Can't initialize network"); + goto error; + } + + if ((g->listen = socket(PF_INET, SOCK_STREAM, 0)) < 0) { + AVR_LOG(avr, LOG_ERROR, "GDB: Can't create socket: %s", strerror(errno)); + goto error; + } + + int optval = 1; + setsockopt(g->listen, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); + + struct sockaddr_in address = { 0 }; + address.sin_family = AF_INET; + address.sin_port = htons (avr->gdb_port); + + if (bind(g->listen, (struct sockaddr *) &address, sizeof(address))) { + AVR_LOG(avr, LOG_ERROR, "GDB: Can not bind socket: %s", strerror(errno)); + goto error; + } + if (listen(g->listen, 1)) { + perror("listen"); + goto error; + } + printf("avr_gdb_init listening on port %d\n", avr->gdb_port); + g->avr = avr; + g->s = -1; + avr->gdb = g; + // change default run behaviour to use the slightly slower versions + avr->run = avr_callback_run_gdb; + avr->sleep = avr_callback_sleep_gdb; + + return 0; + +error: + if (g->listen >= 0) + close(g->listen); + free(g); + + return -1; +} + +void +avr_deinit_gdb( + avr_t * avr ) +{ + if (!avr->gdb) + return; + avr->run = avr_callback_run_raw; // restore normal callbacks + avr->sleep = avr_callback_sleep_raw; + if (avr->gdb->listen != -1) + close(avr->gdb->listen); + avr->gdb->listen = -1; + if (avr->gdb->s != -1) + close(avr->gdb->s); + avr->gdb->s = -1; + free(avr->gdb); + avr->gdb = NULL; + + network_release(); +} diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_gdb.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_gdb.h new file mode 100644 index 0000000..2936df7 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_gdb.h @@ -0,0 +1,55 @@ +/* + sim_gdb.h + + Copyright 2008, 2009 Michel Pollet + + 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 . + */ + +#ifndef __SIM_GDB_H__ +#define __SIM_GDB_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Watchpoint types. + See GDB User Manual, Appendix E.2 */ +enum avr_gdb_watch_type { + AVR_GDB_BREAK_SOFT = 1 << 0, + AVR_GDB_BREAK_HARD = 1 << 1, + + AVR_GDB_WATCH_WRITE = 1 << 2, + AVR_GDB_WATCH_READ = 1 << 3, + AVR_GDB_WATCH_ACCESS = 1 << 4 +}; + +int avr_gdb_init(avr_t * avr); + +void avr_deinit_gdb(avr_t * avr); + +// call from the main AVR decoder thread +int avr_gdb_processor(avr_t * avr, int sleep); + +// Called from sim_core.c +void avr_gdb_handle_watchpoints(avr_t * g, uint16_t addr, enum avr_gdb_watch_type type); +void avr_gdb_handle_break(avr_t *); + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_hex.c b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_hex.c new file mode 100644 index 0000000..fea67c4 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_hex.c @@ -0,0 +1,287 @@ +/* + sim_hex.c + + Copyright 2008, 2009 Michel Pollet + + 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 +#include "sim_hex.h" +#include "sim_elf.h" + +// friendly hex dump +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"); +} + + // 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; + maxlen--; + } + ls++; + } + + return dst - buffer; +} + +void +free_ihex_chunks( + ihex_chunk_p chunks) +{ + if (!chunks) + return; + for (int i = 0; chunks[i].size; i++) + if (chunks[i].data) + free(chunks[i].data); +} + +int +read_ihex_chunks( + const char * fname, + ihex_chunk_p * chunks ) +{ + if (!fname || !chunks) + return -1; + FILE * f = fopen(fname, "r"); + if (!f) { + perror(fname); + return -1; + } + uint32_t segment = 0; // segment address + int chunk = 0, max_chunks = 0; + *chunks = NULL; + + while (!feof(f)) { + char line[128]; + if (!fgets(line, sizeof(line)-1, f)) + continue; + if (line[0] != ':') { + fprintf(stderr, "AVR: '%s' invalid ihex format (%.4s)\n", fname, line); + break; + } + uint8_t bline[64]; + + int len = read_hex_string(line + 1, bline, sizeof(bline)); + if (len <= 0) + continue; + + uint8_t chk = 0; + { // calculate checksum + uint8_t * src = bline; + int tlen = len-1; + while (tlen--) + chk += *src++; + chk = 0x100 - chk; + } + if (chk != bline[len-1]) { + fprintf(stderr, "%s: %s, invalid checksum %02x/%02x\n", __FUNCTION__, fname, chk, bline[len-1]); + break; + } + uint32_t addr = 0; + switch (bline[3]) { + case 0: // normal data + addr = segment | (bline[1] << 8) | bline[2]; + break; + case 1: // end of file - reset segment + segment = 0; + continue; + case 2: // extended address 2 bytes + segment = ((bline[4] << 8) | bline[5]) << 4; + continue; + case 4: + segment = ((bline[4] << 8) | bline[5]) << 16; + continue; + default: + fprintf(stderr, "%s: %s, unsupported check type %02x\n", __FUNCTION__, fname, bline[3]); + continue; + } + if (chunk < max_chunks && addr != ((*chunks)[chunk].baseaddr + (*chunks)[chunk].size)) { + if ((*chunks)[chunk].size) + chunk++; + } + if (chunk >= max_chunks) { + max_chunks++; + /* Here we allocate and zero an extra chunk, to act as terminator */ + *chunks = realloc(*chunks, (1 + max_chunks) * sizeof(ihex_chunk_t)); + memset(*chunks + chunk, 0, + (1 + (max_chunks - chunk)) * sizeof(ihex_chunk_t)); + (*chunks)[chunk].baseaddr = addr; + } + (*chunks)[chunk].data = realloc((*chunks)[chunk].data, + (*chunks)[chunk].size + bline[0]); + memcpy((*chunks)[chunk].data + (*chunks)[chunk].size, + bline + 4, bline[0]); + (*chunks)[chunk].size += bline[0]; + } + fclose(f); + return max_chunks; +} + + +uint8_t * +read_ihex_file( + const char * fname, uint32_t * dsize, uint32_t * start) +{ + ihex_chunk_p chunks = NULL; + int count = read_ihex_chunks(fname, &chunks); + uint8_t * res = NULL; + + if (count > 0) { + *dsize = chunks[0].size; + *start = chunks[0].baseaddr; + res = chunks[0].data; + chunks[0].data = NULL; + } + if (count > 1) { + fprintf(stderr, "AVR: '%s' ihex contains more chunks than loaded (%d)\n", + fname, count); + } + free_ihex_chunks(chunks); + return res; +} + +/* Load a firmware file, ELF or HEX format, from filename, based at + * loadBase, returning the data in *fp ready for loading into + * the simulated MCU. Progname is the current program name for error messages. + * + * Included here as it mostly specific to HEX files. + */ + +void +sim_setup_firmware(const char * filename, uint32_t loadBase, + elf_firmware_t * fp, const char * progname) +{ + char * suffix = strrchr(filename, '.'); + + if (suffix && !strcasecmp(suffix, ".hex")) { + if (!(fp->mmcu[0] && fp->frequency > 0)) { + printf("MCU type and frequency are not set " + "when loading .hex file\n"); + } + ihex_chunk_p chunk = NULL; + int cnt = read_ihex_chunks(filename, &chunk); + if (cnt <= 0) { + fprintf(stderr, + "%s: Unable to load IHEX file %s\n", progname, filename); + exit(1); + } + printf("Loaded %d section(s) of ihex\n", cnt); + + for (int ci = 0; ci < cnt; ci++) { + if (chunk[ci].baseaddr < (1*1024*1024)) { + if (fp->flash) { + printf("Ignoring chunk %d, " + "possible flash redefinition %08x, %d\n", + ci, chunk[ci].baseaddr, chunk[ci].size); + free(chunk[ci].data); + chunk[ci].data = NULL; + continue; + } + fp->flash = chunk[ci].data; + fp->flashsize = chunk[ci].size; + fp->flashbase = chunk[ci].baseaddr; + printf("Load HEX flash %08x, %d at %08x\n", + fp->flashbase, fp->flashsize, fp->flashbase); + } else if (chunk[ci].baseaddr >= AVR_SEGMENT_OFFSET_EEPROM || + (chunk[ci].baseaddr + loadBase) >= + AVR_SEGMENT_OFFSET_EEPROM) { + // eeprom! + + if (fp->eeprom) { + + // Converting ELF with .mmcu section will do this. + + printf("Ignoring chunk %d, " + "possible eeprom redefinition %08x, %d\n", + ci, chunk[ci].baseaddr, chunk[ci].size); + free(chunk[ci].data); + chunk[ci].data = NULL; + continue; + } + fp->eeprom = chunk[ci].data; + fp->eesize = chunk[ci].size; + printf("Load HEX eeprom %08x, %d\n", + chunk[ci].baseaddr, fp->eesize); + } + } + free(chunk); + } else { + if (elf_read_firmware(filename, fp) == -1) { + fprintf(stderr, "%s: Unable to load firmware from file %s\n", + progname, filename); + exit(1); + } + } +} + +#ifdef IHEX_TEST +// gcc -std=gnu99 -Isimavr/sim simavr/sim/sim_hex.c -o sim_hex -DIHEX_TEST -Dtest_main=main +int test_main(int argc, char * argv[]) +{ + struct ihex_chunk_t chunk[4]; + + for (int fi = 1; fi < argc; fi++) { + int c = read_ihex_chunks(argv[fi], chunk, 4); + if (c == -1) { + perror(argv[fi]); + continue; + } + for (int ci = 0; ci < c; ci++) { + char n[96]; + sprintf(n, "%s[%d] = %08x", argv[fi], ci, chunk[ci].baseaddr); + hdump(n, chunk[ci].data, chunk[ci].size); + } + } +} +#endif diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_hex.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_hex.h new file mode 100644 index 0000000..e3a1d1f --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_hex.h @@ -0,0 +1,90 @@ +/* + sim_hex.h + + Copyright 2008, 2009 Michel Pollet + + 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 . + */ + + +#ifndef __SIM_HEX_H___ +#define __SIM_HEX_H___ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// Load a firmware file, ELF or HEX format, ready for use. + +struct elf_firmware_t; // Predeclaration ... + +void +sim_setup_firmware( + const char * filename, // Firmware file + uint32_t loadBase, // Base of load region + struct elf_firmware_t * fp, // Data returned here + const char * progname); // For error messages. + +// parses a hex text string 'src' of at max 'maxlen' characters, decodes it into 'buffer' +int +read_hex_string( + const char * src, + uint8_t * buffer, + int maxlen); + +// a .hex file chunk (base address + size) +typedef struct ihex_chunk_t { + uint32_t baseaddr; // offset it started at in the .hex file + uint8_t * data; // read data + uint32_t size; // read data size +} ihex_chunk_t, *ihex_chunk_p; + +/* + * Read a .hex file, detects the various different chunks in it from their starting + * addresses and allocate an array of ihex_chunk_t returned in 'chunks'. + * Returns the number of chunks found, or -1 if an error occurs. + */ +int +read_ihex_chunks( + const char * fname, + ihex_chunk_p * chunks ); +/* Frees previously allocated chunks */ +void +free_ihex_chunks( + ihex_chunk_p chunks); + +// reads IHEX file 'fname', puts it's decoded size in *'dsize' and returns +// a newly allocated buffer with the binary data (or NULL, if error) +uint8_t * +read_ihex_file( + const char * fname, + uint32_t * dsize, + uint32_t * start); + +// hex dump from pointer 'b' for 'l' bytes with string prefix 'w' +void +hdump( + const char *w, + uint8_t *b, size_t l); + +#ifdef __cplusplus +}; +#endif + +#endif /* __SIM_HEX_H___ */ diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_interrupts.c b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_interrupts.c new file mode 100644 index 0000000..9e3ed9c --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_interrupts.c @@ -0,0 +1,296 @@ +/* + sim_interrupts.c + + Copyright 2008-2012 Michel Pollet + + 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 +#include +#include "sim_interrupts.h" +#include "sim_avr.h" +#include "sim_core.h" + +DEFINE_FIFO(avr_int_vector_p, avr_int_pending); + +void +avr_interrupt_init( + avr_t * avr ) +{ + avr_int_table_p table = &avr->interrupts; + memset(table, 0, sizeof(*table)); + + static const char *names[] = { ">avr.int.pending", ">avr.int.running" }; + avr_init_irq(&avr->irq_pool, table->irq, + 0, // base number + AVR_INT_IRQ_COUNT, names); +} + +void +avr_interrupt_reset( + avr_t * avr ) +{ + avr_int_table_p table = &avr->interrupts; + + table->running_ptr = 0; + avr_int_pending_reset(&table->pending); + avr->interrupt_state = 0; + for (int i = 0; i < table->vector_count; i++) + table->vector[i]->pending = 0; +} + +void +avr_register_vector( + avr_t *avr, + avr_int_vector_t * vector) +{ + if (!vector->vector) + return; + + avr_int_table_p table = &avr->interrupts; + + char name0[48], name1[48]; + sprintf(name0, ">avr.int.%02x.pending", vector->vector); + sprintf(name1, ">avr.int.%02x.running", vector->vector); + const char *names[2] = { name0, name1 }; + avr_init_irq(&avr->irq_pool, vector->irq, + vector->vector * 256, // base number + AVR_INT_IRQ_COUNT, names); + table->vector[table->vector_count++] = vector; + if (vector->trace) + printf("IRQ%d registered (enabled %04x:%d)\n", + vector->vector, vector->enable.reg, vector->enable.bit); + + if (!vector->enable.reg) + AVR_LOG(avr, LOG_WARNING, "IRQ%d No 'enable' bit !\n", + vector->vector); +} + +int +avr_has_pending_interrupts( + avr_t * avr) +{ + avr_int_table_p table = &avr->interrupts; + return !avr_int_pending_isempty(&table->pending); +} + +int +avr_is_interrupt_pending( + avr_t * avr, + avr_int_vector_t * vector) +{ + return vector->pending; +} + +int +avr_is_interrupt_enabled( + avr_t * avr, + avr_int_vector_t * vector) +{ + return avr_regbit_get(avr, vector->enable); +} + +int +avr_raise_interrupt( + avr_t * avr, + avr_int_vector_t * vector) +{ + if (!vector || !vector->vector) + return 0; + + if (vector->trace) + printf("IRQ%d raising (enabled %d)\n", + vector->vector, avr_regbit_get(avr, vector->enable)); + + // always mark the 'raised' flag to one, even if the interrupt is disabled + // this allow "polling" for the "raised" flag, like for non-interrupt + // driven UART and so so. These flags are often "write one to clear" + if (vector->raised.reg) + avr_regbit_set(avr, vector->raised); + + if (vector->pending) { + if (vector->trace) + printf("IRQ%d:I=%d already raised (enabled %d) (cycle %lld pc 0x%x)\n", + vector->vector, !!avr->sreg[S_I], avr_regbit_get(avr, vector->enable), + (long long int)avr->cycle, avr->pc); + + return 0; + } + + avr_raise_irq(vector->irq + AVR_INT_IRQ_PENDING, 1); + avr_raise_irq(avr->interrupts.irq + AVR_INT_IRQ_PENDING, vector->vector); + + // If the interrupt is enabled, attempt to wake the core + if (avr_regbit_get(avr, vector->enable)) { + // Mark the interrupt as pending + vector->pending = 1; + + avr_int_table_p table = &avr->interrupts; + + avr_int_pending_write(&table->pending, vector); + + if (avr->sreg[S_I] && avr->interrupt_state == 0) + avr->interrupt_state = 1; + if (avr->state == cpu_Sleeping) { + if (vector->trace) + printf("IRQ%d Waking CPU due to interrupt\n", + vector->vector); + avr->state = cpu_Running; // in case we were sleeping + } + } + // return 'raised' even if it was already pending + return 1; +} + +void +avr_clear_interrupt( + avr_t * avr, + avr_int_vector_t * vector) +{ + if (!vector) + return; + if (vector->trace) + printf("IRQ%d cleared\n", vector->vector); + vector->pending = 0; + + avr_raise_irq(vector->irq + AVR_INT_IRQ_PENDING, 0); + avr_raise_irq_float(avr->interrupts.irq + AVR_INT_IRQ_PENDING, + avr_has_pending_interrupts(avr) ? + avr_int_pending_read_at( + &avr->interrupts.pending, 0)->vector : 0, + avr_has_pending_interrupts(avr)); + + if (vector->raised.reg && !vector->raise_sticky) + avr_regbit_clear(avr, vector->raised); +} + +int +avr_clear_interrupt_if( + avr_t * avr, + avr_int_vector_t * vector, + uint8_t old) +{ + avr_raise_irq(avr->interrupts.irq + AVR_INT_IRQ_PENDING, + avr_has_pending_interrupts(avr)); + if (avr_regbit_get(avr, vector->raised)) { + avr_clear_interrupt(avr, vector); + return 1; + } + avr_regbit_setto(avr, vector->raised, old); + return 0; +} + +avr_irq_t * +avr_get_interrupt_irq( + avr_t * avr, + uint8_t v) +{ + avr_int_table_p table = &avr->interrupts; + if (v == AVR_INT_ANY) + return table->irq; + for (int i = 0; i < table->vector_count; i++) + if (table->vector[i]->vector == v) + return table->vector[i]->irq; + return NULL; +} + +/* this is called upon RETI. */ +void +avr_interrupt_reti( + struct avr_t * avr) +{ + avr_int_table_p table = &avr->interrupts; + if (table->running_ptr) { + avr_int_vector_t * vector = table->running[--table->running_ptr]; + avr_raise_irq(vector->irq + AVR_INT_IRQ_RUNNING, 0); + } + avr_raise_irq(table->irq + AVR_INT_IRQ_RUNNING, + table->running_ptr > 0 ? + table->running[table->running_ptr-1]->vector : 0); +} + +/* + * check whether interrupts are pending. If so, check if the interrupt "latency" is reached, + * and if so triggers the handlers and jump to the vector. + */ +void +avr_service_interrupts( + avr_t * avr) +{ + if (!avr->sreg[S_I] || !avr->interrupt_state) + return; + + if (avr->interrupt_state < 0) { + avr->interrupt_state++; + if (avr->interrupt_state == 0) + avr->interrupt_state = avr_has_pending_interrupts(avr); + return; + } + + avr_int_table_p table = &avr->interrupts; + + // how many are pending... + int cnt = avr_int_pending_get_read_size(&table->pending); + // locate the highest priority one + int min = 0xff; + int mini = 0; + for (int ii = 0; ii < cnt; ii++) { + avr_int_vector_t * v = avr_int_pending_read_at(&table->pending, ii); + if (v->vector < min) { + min = v->vector; + mini = ii; + } + } + avr_int_vector_t * vector = avr_int_pending_read_at(&table->pending, mini); + + // it's possible that the vector being serviced is not at the front of the fifo, because we process interrupts based + // on vector priority rather than position in the fifo. if this is the case, we need to manually swap the vector + // being serviced with the vector at the front of the fifo so that the vector at the front of the fifo can be + // serviced in a following iteration. + avr_int_vector_p fifo_front = avr_int_pending_read(&table->pending); + if (fifo_front->vector != vector->vector) { + // the read into fifo_front above has incremented pending.read, so now mini points 1 beyond the desired + // destination for the swap. + table->pending.buffer[(table->pending.read + mini - 1) % avr_int_pending_fifo_size] = fifo_front; + } + + // if that single interrupt is masked, ignore it and continue + // could also have been disabled, or cleared + if (!avr_regbit_get(avr, vector->enable) || !vector->pending) { + vector->pending = 0; + avr->interrupt_state = avr_has_pending_interrupts(avr); + } else { + if (vector->trace) + printf("IRQ%d calling\n", vector->vector); + _avr_push_addr(avr, avr->pc); + avr_sreg_set(avr, S_I, 0); + avr->pc = vector->vector * avr->vector_size; + + avr_raise_irq(vector->irq + AVR_INT_IRQ_RUNNING, 1); + avr_raise_irq(table->irq + AVR_INT_IRQ_RUNNING, vector->vector); + if (table->running_ptr == ARRAY_SIZE(table->running)) { + AVR_LOG(avr, LOG_ERROR, "%s run out of nested stack!", __func__); + } else { + table->running[table->running_ptr++] = vector; + } + avr_clear_interrupt(avr, vector); + } +} + diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_interrupts.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_interrupts.h new file mode 100644 index 0000000..bebf614 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_interrupts.h @@ -0,0 +1,134 @@ +/* + sim_interrupts.h + + Copyright 2008-2012 Michel Pollet + + 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 . + */ + +#ifndef __SIM_INTERRUPTS_H__ +#define __SIM_INTERRUPTS_H__ + +#include "sim_avr_types.h" +#include "sim_irq.h" +#include "fifo_declare.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + AVR_INT_IRQ_PENDING = 0, + AVR_INT_IRQ_RUNNING, + AVR_INT_IRQ_COUNT, + AVR_INT_ANY = 0xff, // for avr_get_interrupt_irq() +}; +// interrupt vector for the IO modules +typedef struct avr_int_vector_t { + uint8_t vector; // vector number, zero (reset) is reserved + avr_regbit_t enable; // IO register index for the "interrupt enable" flag for this vector + avr_regbit_t raised; // IO register index for the register where the "raised" flag is (optional) + + uint8_t mask; // Mask for PCINTs. this is needed for chips like the 2560 where PCINT do not align with IRQs + int8_t shift; // PCINT8 = E0, PCINT9-15 are on J0-J6. Shift shifts down (<0) or up (>0) for alignment with IRQ#. + + // 'pending' IRQ, and 'running' status as signaled here + avr_irq_t irq[AVR_INT_IRQ_COUNT]; + uint8_t pending : 1, // 1 while scheduled in the fifo + trace : 1, // only for debug of a vector + raise_sticky : 1; // 1 if the interrupt flag (= the raised regbit) is not cleared + // by the hardware when executing the interrupt routine (see TWINT) +} avr_int_vector_t, *avr_int_vector_p; + +// Size needs to be >= max number of vectors, and a power of two +DECLARE_FIFO(avr_int_vector_p, avr_int_pending, 64); + +// interrupt vectors, and their enable/clear registers +typedef struct avr_int_table_t { + avr_int_vector_t * vector[64]; + uint8_t vector_count; + avr_int_pending_t pending; + uint8_t running_ptr; + avr_int_vector_t *running[64]; // stack of nested interrupts + // global status for pending + running in interrupt context + avr_irq_t irq[AVR_INT_IRQ_COUNT]; +} avr_int_table_t, *avr_int_table_p; + +/* + * Interrupt Helper Functions + */ +// register an interrupt vector. It's only needed if you want to use the "r_raised" flags +void +avr_register_vector( + struct avr_t *avr, + avr_int_vector_t * vector); +// raise an interrupt (if enabled). The interrupt is latched and will be called later +// return non-zero if the interrupt was raised and is now pending +int +avr_raise_interrupt( + struct avr_t * avr, + avr_int_vector_t * vector); +// return non-zero if the AVR core has any pending interrupts +int +avr_has_pending_interrupts( + struct avr_t * avr); +// return nonzero if a specific interrupt vector is pending +int +avr_is_interrupt_pending( + struct avr_t * avr, + avr_int_vector_t * vector); +// clear the "pending" status of an interrupt +void +avr_clear_interrupt( + struct avr_t * avr, + avr_int_vector_t * vector); +// called by the core at each cycle to check whether an interrupt is pending +void +avr_service_interrupts( + struct avr_t * avr); +// called by the core when RETI opcode is ran +void +avr_interrupt_reti( + struct avr_t * avr); +// clear the interrupt (inc pending) if "raised" flag is 1 +int +avr_clear_interrupt_if( + struct avr_t * avr, + avr_int_vector_t * vector, + uint8_t old); + +// return the IRQ that is raised when the vector is enabled and called/cleared +// this allows tracing of pending interrupts +avr_irq_t * +avr_get_interrupt_irq( + struct avr_t * avr, + uint8_t v); + +// Initializes the interrupt table +void +avr_interrupt_init( + struct avr_t * avr ); + +// reset the interrupt table and the fifo +void +avr_interrupt_reset( + struct avr_t * avr ); + +#ifdef __cplusplus +}; +#endif + +#endif /* __SIM_INTERRUPTS_H__ */ diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_io.c b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_io.c new file mode 100644 index 0000000..548f030 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_io.c @@ -0,0 +1,298 @@ +/* + sim_io.c + + Copyright 2008, 2009 Michel Pollet + + 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 +#include +#include +#include "sim_io.h" + +int +avr_ioctl( + avr_t *avr, + uint32_t ctl, + void * io_param) +{ + avr_io_t * port = avr->io_port; + int res = -1; + while (port && res == -1) { + if (port->ioctl) + 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; +} + +void +avr_register_io_read( + avr_t *avr, + avr_io_addr_t addr, + avr_io_read_t readp, + void * param) +{ + avr_io_addr_t a = AVR_DATA_TO_IO(addr); + if (avr->io[a].r.param || avr->io[a].r.c) { + if (avr->io[a].r.param != param || avr->io[a].r.c != readp) { + AVR_LOG(avr, LOG_ERROR, + "IO: %s(): Already registered, refusing to override.\n", + __func__); + AVR_LOG(avr, LOG_ERROR, + "IO: %s(%04x : %p/%p): %p/%p\n", + __func__, a, + avr->io[a].r.c, avr->io[a].r.param, readp, param); + abort(); + } + } + avr->io[a].r.param = param; + avr->io[a].r.c = readp; +} + +static void +_avr_io_mux_write( + avr_t * avr, + avr_io_addr_t addr, + uint8_t v, + void * param) +{ + int io = (intptr_t)param; + for (int i = 0; i < avr->io_shared_io[io].used; i++) { + avr_io_write_t c = avr->io_shared_io[io].io[i].c; + if (c) + c(avr, addr, v, avr->io_shared_io[io].io[i].param); + } +} + +void +avr_register_io_write( + avr_t *avr, + avr_io_addr_t addr, + avr_io_write_t writep, + void * param) +{ + avr_io_addr_t a = AVR_DATA_TO_IO(addr); + + if (a >= MAX_IOs) { + AVR_LOG(avr, LOG_ERROR, + "IO: %s(): IO address 0x%04x out of range (max 0x%04x).\n", + __func__, a, MAX_IOs); + abort(); + } + /* + * Verifying that some other piece of code is not installed to watch write + * on this address. If there is, this code installs a "dispatcher" callback + * instead to handle multiple clients, otherwise, it continues as usual + */ + if (avr->io[a].w.param || avr->io[a].w.c) { + if (avr->io[a].w.param != param || avr->io[a].w.c != writep) { + // if the muxer not already installed, allocate a new slot + if (avr->io[a].w.c != _avr_io_mux_write) { + int no = avr->io_shared_io_count++; + if (avr->io_shared_io_count > ARRAY_SIZE(avr->io_shared_io)) { + AVR_LOG(avr, LOG_ERROR, + "IO: %s(): Too many shared IO registers.\n", __func__); + abort(); + } + AVR_LOG(avr, LOG_TRACE, + "IO: %s(%04x): Installing muxer on register.\n", + __func__, addr); + avr->io_shared_io[no].used = 1; + avr->io_shared_io[no].io[0].param = avr->io[a].w.param; + avr->io_shared_io[no].io[0].c = avr->io[a].w.c; + avr->io[a].w.param = (void*)(intptr_t)no; + avr->io[a].w.c = _avr_io_mux_write; + } + int no = (intptr_t)avr->io[a].w.param; + int d = avr->io_shared_io[no].used++; + if (avr->io_shared_io[no].used > ARRAY_SIZE(avr->io_shared_io[0].io)) { + AVR_LOG(avr, LOG_ERROR, + "IO: %s(): Too many callbacks on %04x.\n", + __func__, addr); + abort(); + } + avr->io_shared_io[no].io[d].param = param; + avr->io_shared_io[no].io[d].c = writep; + return; + } + } + + avr->io[a].w.param = param; + avr->io[a].w.c = writep; +} + +avr_irq_t * +avr_io_getirq( + avr_t * avr, + uint32_t ctl, + int index) +{ + avr_io_t * port = avr->io_port; + while (port) { + if (port->irq && port->irq_ioctl_get == ctl && port->irq_count > index) + return port->irq + index; + port = port->next; + } + return NULL; +} + +avr_irq_t * +avr_iomem_getirq( + avr_t * avr, + avr_io_addr_t addr, + const char * name, + int index) +{ + if (index > 8) + return NULL; + avr_io_addr_t a = AVR_DATA_TO_IO(addr); + if (avr->io[a].irq == NULL) { + /* + * Prepare an array of names for the io IRQs. Ideally we'd love to have + * a proper name for these, but it's not possible at this time. + */ + char names[9 * 20]; + char * d = names; + const char * namep[9]; + for (int ni = 0; ni < 9; ni++) { + if (ni < 8) + sprintf(d, "=avr.io.%04x.%d", addr, ni); + else + sprintf(d, "8=avr.io.%04x.all", addr); + namep[ni] = d; + d += strlen(d) + 1; + } + avr->io[a].irq = avr_alloc_irq(&avr->irq_pool, 0, 9, namep); + // mark the pin ones as filtered, so they only are raised when changing + for (int i = 0; i < 8; i++) + avr->io[a].irq[i].flags |= IRQ_FLAG_FILTERED; + } + // if given a name, replace the default one... + if (name) { + int l = strlen(name); + char n[l + 10]; + sprintf(n, "avr.io.%s", name); + free((void*)avr->io[a].irq[index].name); + avr->io[a].irq[index].name = strdup(n); + } + return avr->io[a].irq + index; +} + +avr_irq_t * +avr_io_setirqs( + avr_io_t * io, + uint32_t ctl, + int count, + avr_irq_t * irqs ) +{ + // allocate this module's IRQ + io->irq_count = count; + + if (!irqs) { + const char ** irq_names = NULL; + + if (io->irq_names) { + irq_names = malloc(count * sizeof(char*)); + memset(irq_names, 0, count * sizeof(char*)); + char buf[64]; + for (int i = 0; i < count; i++) { + /* + * this bit takes the io module 'kind' ("port") + * the IRQ name ("=0") and the last character of the ioctl ('p','o','r','A') + * to create a full name "=porta.0" + */ + char * dst = buf; + // copy the 'flags' of the name out + const char * kind = io->irq_names[i]; + while (isdigit(*kind)) + *dst++ = *kind++; + while (!isalpha(*kind)) + *dst++ = *kind++; + // add avr name +// strcpy(dst, io->avr->mmcu); + strcpy(dst, "avr"); + dst += strlen(dst); + *dst ++ = '.'; + // add module 'kind' + strcpy(dst, io->kind); + dst += strlen(dst); + // add port name, if any + if ((ctl & 0xff) > ' ') + *dst ++ = tolower(ctl & 0xff); + *dst ++ = '.'; + // add the rest of the irq name + strcpy(dst, kind); + dst += strlen(dst); + *dst = 0; + +// printf("%s\n", buf); + irq_names[i] = strdup(buf); + } + } + irqs = avr_alloc_irq(&io->avr->irq_pool, 0, + count, irq_names); + if (irq_names) { + for (int i = 0; i < count; i++) + free((char*)irq_names[i]); + free((char*)irq_names); + } + } + + io->irq = irqs; + io->irq_ioctl_get = ctl; + return io->irq; +} + +static void +avr_deallocate_io( + avr_io_t * io) +{ + if (io->dealloc) + io->dealloc(io); + avr_free_irq(io->irq, io->irq_count); + io->irq_count = 0; + io->irq_ioctl_get = 0; + io->avr = NULL; + io->next = NULL; +} + +void +avr_deallocate_ios( + avr_t * avr) +{ + avr_io_t * port = avr->io_port; + while (port) { + avr_io_t * next = port->next; + avr_deallocate_io(port); + port = next; + } + avr->io_port = NULL; +} diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_io.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_io.h new file mode 100644 index 0000000..cfd2fdb --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_io.h @@ -0,0 +1,132 @@ +/* + sim_io.h + + Copyright 2008, 2009 Michel Pollet + + 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 . + */ + +#ifndef __SIM_IO_H__ +#define __SIM_IO_H__ + +#include "sim_avr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * used by the ioports to implement their own features + * see avr_eeprom.* for an example, and avr_ioctl(). + */ +#define AVR_IOCTL_DEF(_a,_b,_c,_d) \ + (((_a) << 24)|((_b) << 16)|((_c) << 8)|((_d))) + +/* + * IO module base struct + * Modules uses that as their first member in their own struct + */ +typedef struct avr_io_t { + struct avr_io_t * next; + avr_t * avr; // avr we are attached to + const char * kind; // pretty name, for debug + + const char ** irq_names; // IRQ names + + 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 reset time + void (*reset)(struct avr_io_t *io); + // called externally. allow access to io modules and so on + int (*ioctl)(struct avr_io_t *io, uint32_t ctl, void *io_param); + + // optional, a function to free up allocated system resources + void (*dealloc)(struct avr_io_t *io); +} avr_io_t; + +/* + * IO modules helper functions + */ + +// registers an IO module, so it's run(), reset() etc are called +// this is called by the AVR core init functions, you /could/ register an external +// one after instantiation, for whatever purpose... +void +avr_register_io( + avr_t *avr, + avr_io_t * io); +// Sets an IO module "official" IRQs and the ioctl used to get to them. if 'irqs' is NULL, +// 'count' will be allocated +avr_irq_t * +avr_io_setirqs( + avr_io_t * io, + uint32_t ctl, + int count, + avr_irq_t * irqs ); + +// register a callback for when IO register "addr" is read +void +avr_register_io_read( + avr_t *avr, + avr_io_addr_t addr, + avr_io_read_t read, + void * param); +// register a callback for when the IO register is written. callback has to set the memory itself +void +avr_register_io_write( + avr_t *avr, + avr_io_addr_t addr, + avr_io_write_t write, + void * param); +// call every IO modules until one responds to this +int +avr_ioctl( + avr_t *avr, + uint32_t ctl, + void * io_param); +// get the specific irq for a module, check AVR_IOCTL_IOPORT_GETIRQ for example +struct avr_irq_t * +avr_io_getirq( + avr_t * avr, + uint32_t ctl, + int index); + +// get the IRQ for an absolute IO address +// this allows any code to hook an IRQ in any io address, for example +// tracing changes of values into a register +// Note that the values do not "magically" change, they change only +// when the AVR code attempt to read and write at that address +// +// the "index" is a bit number, or ALL bits if index == 8 +#define AVR_IOMEM_IRQ_ALL 8 +avr_irq_t * +avr_iomem_getirq( + avr_t * avr, + avr_io_addr_t addr, + const char * name /* Optional, if NULL, "ioXXXX" will be used */ , + int index); + +// Terminates all IOs and remove from them from the io chain +void +avr_deallocate_ios( + avr_t *avr); + +#ifdef __cplusplus +}; +#endif + +#endif /* __SIM_IO_H__ */ diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_irq.c b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_irq.c new file mode 100644 index 0000000..6d175cf --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_irq.c @@ -0,0 +1,294 @@ +/* + sim_irq.c + + Copyright 2008, 2009 Michel Pollet + + 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 +#include "sim_irq.h" + +// internal structure for a hook, never seen by the notify procs +typedef struct avr_irq_hook_t { + struct avr_irq_hook_t * next; + int busy; // prevent reentrance of callbacks + + struct avr_irq_t * chain; // raise the IRQ on this too - optional if "notify" is on + avr_irq_notify_t notify; // called when IRQ is raised - optional if "chain" is on + void * param; // "notify" parameter +} avr_irq_hook_t; + +static void +_avr_irq_pool_add( + avr_irq_pool_t * pool, + avr_irq_t * irq) +{ + int insert = 0; + /* lookup a slot */ + for (; insert < pool->count && pool->irq[insert]; insert++) + ; + if (insert == pool->count) { + if ((pool->count & 0xf) == 0) { + pool->irq = (avr_irq_t**)realloc(pool->irq, + (pool->count + 16) * sizeof(avr_irq_t *)); + } + pool->count++; + } + pool->irq[insert] = irq; + irq->pool = pool; +} + +static void +_avr_irq_pool_remove( + avr_irq_pool_t * pool, + avr_irq_t * irq) +{ + for (int i = 0; i < pool->count; i++) + if (pool->irq[i] == irq) { + pool->irq[i] = 0; + return; + } +} + +void +avr_init_irq( + avr_irq_pool_t * pool, + avr_irq_t * irq, + uint32_t base, + uint32_t count, + const char ** names /* optional */) +{ + memset(irq, 0, sizeof(avr_irq_t) * count); + + for (int i = 0; i < count; i++) { + irq[i].irq = base + i; + irq[i].flags = IRQ_FLAG_INIT; + if (pool) + _avr_irq_pool_add(pool, &irq[i]); + if (names && names[i]) + irq[i].name = strdup(names[i]); + else { + printf("WARNING %s() with NULL name for irq %d.\n", __func__, irq[i].irq); + } + } +} + +avr_irq_t * +avr_alloc_irq( + avr_irq_pool_t * pool, + uint32_t base, + uint32_t count, + const char ** names /* optional */) +{ + avr_irq_t * irq = (avr_irq_t*)malloc(sizeof(avr_irq_t) * count); + avr_init_irq(pool, irq, base, count, names); + for (int i = 0; i < count; i++) + irq[i].flags |= IRQ_FLAG_ALLOC; + return irq; +} + +static avr_irq_hook_t * +_avr_alloc_irq_hook( + avr_irq_t * irq) +{ + avr_irq_hook_t *hook = malloc(sizeof(avr_irq_hook_t)); + memset(hook, 0, sizeof(avr_irq_hook_t)); + hook->next = irq->hook; + irq->hook = hook; + return hook; +} + +void +avr_free_irq( + avr_irq_t * irq, + uint32_t count) +{ + if (!irq || !count) + return; + for (int i = 0; i < count; i++) { + avr_irq_t * iq = irq + i; + if (iq->pool) + _avr_irq_pool_remove(iq->pool, iq); + if (iq->name) + free((char*)iq->name); + iq->name = NULL; + // purge hooks + avr_irq_hook_t *hook = iq->hook; + while (hook) { + avr_irq_hook_t * next = hook->next; + free(hook); + hook = next; + } + iq->hook = NULL; + } + // if that irq list was allocated by us, free it + if (irq->flags & IRQ_FLAG_ALLOC) + free(irq); +} + +void +avr_irq_register_notify( + avr_irq_t * irq, + avr_irq_notify_t notify, + void * param) +{ + if (!irq || !notify) + return; + + avr_irq_hook_t *hook = irq->hook; + while (hook) { + if (hook->notify == notify && hook->param == param) + return; // already there + hook = hook->next; + } + hook = _avr_alloc_irq_hook(irq); + hook->notify = notify; + hook->param = param; +} + +void +avr_irq_unregister_notify( + avr_irq_t * irq, + avr_irq_notify_t notify, + void * param) +{ + avr_irq_hook_t *hook, *prev; + if (!irq || !notify) + return; + + hook = irq->hook; + prev = NULL; + while (hook) { + if (hook->notify == notify && hook->param == param) { + if ( prev ) + prev->next = hook->next; + else + irq->hook = hook->next; + free(hook); + return; + } + prev = hook; + hook = hook->next; + } +} + +void +avr_raise_irq_float( + avr_irq_t * irq, + uint32_t value, + int floating) +{ + if (!irq) + return ; + uint32_t output = (irq->flags & IRQ_FLAG_NOT) ? !value : value; + // if value is the same but it's the first time, raise it anyway + if (irq->value == output && + (irq->flags & IRQ_FLAG_FILTERED) && !(irq->flags & IRQ_FLAG_INIT)) + return; + irq->flags &= ~(IRQ_FLAG_INIT | IRQ_FLAG_FLOATING); + if (floating) + irq->flags |= IRQ_FLAG_FLOATING; + avr_irq_hook_t *hook = irq->hook; + while (hook) { + avr_irq_hook_t * next = hook->next; + // prevents reentrance / endless calling loops + if (hook->busy == 0) { + hook->busy++; + if (hook->notify) + hook->notify(irq, output, hook->param); + if (hook->chain) + avr_raise_irq_float(hook->chain, output, floating); + hook->busy--; + } + hook = next; + } + // the value is set after the callbacks are called, so the callbacks + // can themselves compare for old/new values between their parameter + // they are passed (new value) and the previous irq->value + irq->value = output; +} + +void +avr_raise_irq( + avr_irq_t * irq, + uint32_t value) +{ + avr_raise_irq_float(irq, value, !!(irq->flags & IRQ_FLAG_FLOATING)); +} + +void +avr_connect_irq( + avr_irq_t * src, + avr_irq_t * dst) +{ + if (!src || !dst || src == dst) { + fprintf(stderr, "error: %s invalid irq %p/%p", __FUNCTION__, src, dst); + return; + } + avr_irq_hook_t *hook = src->hook; + while (hook) { + if (hook->chain == dst) + return; // already there + hook = hook->next; + } + hook = _avr_alloc_irq_hook(src); + hook->chain = dst; +} + +void +avr_unconnect_irq( + avr_irq_t * src, + avr_irq_t * dst) +{ + avr_irq_hook_t *hook, *prev; + + if (!src || !dst || src == dst) { + fprintf(stderr, "error: %s invalid irq %p/%p", __FUNCTION__, src, dst); + return; + } + hook = src->hook; + prev = NULL; + while (hook) { + if (hook->chain == dst) { + if ( prev ) + prev->next = hook->next; + else + src->hook = hook->next; + free(hook); + return; + } + prev = hook; + hook = hook->next; + } +} + +uint8_t +avr_irq_get_flags( + avr_irq_t * irq ) +{ + return irq->flags; +} + +void +avr_irq_set_flags( + avr_irq_t * irq, + uint8_t flags ) +{ + irq->flags = flags; +} diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_irq.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_irq.h new file mode 100644 index 0000000..b96fd47 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_irq.h @@ -0,0 +1,150 @@ +/* + sim_irq.h + + Copyright 2008, 2009 Michel Pollet + + 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 . + */ + +#ifndef __SIM_IRQ_H__ +#define __SIM_IRQ_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Internal IRQ system + * + * This subsystem allows any piece of code to "register" a hook to be called when an IRQ is + * raised. The IRQ definition is up to the module defining it, for example a IOPORT pin change + * might be an IRQ in which case any piece of code can be notified when a pin has changed state + * + * The notify hooks are chained, and duplicates are filtered out so you can't register a + * notify hook twice on one particular IRQ + * + * IRQ calling order is not defined, so don't rely on it. + * + * IRQ hook needs to be registered in reset() handlers, ie after all modules init() bits + * have been called, to prevent race condition of the initialization order. + */ +struct avr_irq_t; + +typedef void (*avr_irq_notify_t)( + struct avr_irq_t * irq, + uint32_t value, + void * param); + + +enum { + IRQ_FLAG_NOT = (1 << 0), //!< change polarity of the IRQ + IRQ_FLAG_FILTERED = (1 << 1), //!< do not "notify" if "value" is the same as previous raise + IRQ_FLAG_ALLOC = (1 << 2), //!< this irq structure was malloced via avr_alloc_irq + IRQ_FLAG_INIT = (1 << 3), //!< this irq hasn't been used yet + IRQ_FLAG_FLOATING = (1 << 4), //!< this 'pin'/signal is floating + IRQ_FLAG_USER = (1 << 5), //!< Can be used by irq users +}; + +/* + * IRQ Pool structure + */ +typedef struct avr_irq_pool_t { + int count; //!< number of irqs living in the pool + struct avr_irq_t ** irq; //!< irqs belonging in this pool +} avr_irq_pool_t; + +/*! + * Public IRQ structure + */ +typedef struct avr_irq_t { + struct avr_irq_pool_t * pool; + const char * name; + uint32_t irq; //!< any value the user needs + uint32_t value; //!< current value + uint8_t flags; //!< IRQ_* flags + struct avr_irq_hook_t * hook; //!< list of hooks to be notified +} avr_irq_t; + +//! allocates 'count' IRQs, initializes their "irq" starting from 'base' and increment +avr_irq_t * +avr_alloc_irq( + avr_irq_pool_t * pool, + uint32_t base, + uint32_t count, + const char ** names /* optional */); +void +avr_free_irq( + avr_irq_t * irq, + uint32_t count); + +//! init 'count' IRQs, initializes their "irq" starting from 'base' and increment +void +avr_init_irq( + avr_irq_pool_t * pool, + avr_irq_t * irq, + uint32_t base, + uint32_t count, + const char ** names /* optional */); +//! Returns the current IRQ flags +uint8_t +avr_irq_get_flags( + avr_irq_t * irq ); +//! Sets this irq's flags +void +avr_irq_set_flags( + avr_irq_t * irq, + uint8_t flags ); +//! 'raise' an IRQ. Ie call their 'hooks', and raise any chained IRQs, and set the new 'value' +void +avr_raise_irq( + avr_irq_t * irq, + uint32_t value); +//! Same as avr_raise_irq(), but also allow setting the float status +void +avr_raise_irq_float( + avr_irq_t * irq, + uint32_t value, + int floating); +//! this connects a "source" IRQ to a "destination" IRQ +void +avr_connect_irq( + avr_irq_t * src, + avr_irq_t * dst); +void +avr_unconnect_irq( + avr_irq_t * src, + avr_irq_t * dst); + +//! register a notification 'hook' for 'irq' -- 'param' is anything that your want passed back as argument +void +avr_irq_register_notify( + avr_irq_t * irq, + avr_irq_notify_t notify, + void * param); + +void +avr_irq_unregister_notify( + avr_irq_t * irq, + avr_irq_notify_t notify, + void * param); + +#ifdef __cplusplus +}; +#endif + +#endif /* __SIM_IRQ_H__ */ diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_network.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_network.h new file mode 100644 index 0000000..da4600a --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_network.h @@ -0,0 +1,89 @@ +/* + sim_network.h + + Copyright 2012 Stephan Veigl + + 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 . + */ + +#ifndef __SIM_NETWORK_H__ +#define __SIM_NETWORK_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __MINGW32__ + +// Windows with MinGW + +#include +#include +#include + +#define send(sockfd, buf, len, flags) \ + (ssize_t)send( (sockfd), (const char *)(buf), (len), (flags)) +#define setsockopt(sockfd, level, optname, optval, optlen) \ + setsockopt( (sockfd), (level), (optname), (void *)(optval), (optlen)) +#define recv(sockfd, buf, len, flags) \ + (ssize_t)recv( (sockfd), (char *)(buf), (len), (flags)) +#define sleep(x) Sleep((x)*1000) + +static inline int network_init(void) +{ + // Windows requires WinSock to be init before use + WSADATA wsaData; + if ( WSAStartup( MAKEWORD( 2, 2 ), &wsaData ) ) + return -1; + + return 0; +} + +static inline void network_release(void) +{ + // close WinSock + WSACleanup(); +} + +#else + +// native Linux + +#include +#include +#include +#include +#include +#include + +static inline int network_init(void) +{ + // nothing to do + return 0; +} + +static inline void network_release(void) +{ + // nothing to do +} + +#endif + +#ifdef __cplusplus +}; +#endif + +#endif /*__SIM_NETWORK_H__*/ diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_regbit.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_regbit.h new file mode 100644 index 0000000..862f490 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_regbit.h @@ -0,0 +1,199 @@ +/* + sim_regbit.h + + Copyright 2008, 2009 Michel Pollet + + 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 . + */ + +#ifndef __SIM_REGBIT_H__ +#define __SIM_REGBIT_H__ + +#include "sim_avr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ARRAY_SIZE(_aa) (sizeof(_aa) / sizeof((_aa)[0])) + + +/* + * These accessors are inlined and are used to perform the operations on + * avr_regbit_t definitions. This is the "official" way to access bits into registers + * The small footprint costs brings much better versatility for functions/bits that are + * not always defined in the same place on real AVR cores + */ +/* + * set/get/clear io register bits in one operation + */ +static inline uint8_t +avr_regbit_set( + avr_t * avr, + avr_regbit_t rb) +{ + uint16_t a = rb.reg; + uint8_t m; + + if (!a) + return 0; + m = (uint8_t)(rb.mask << rb.bit); + avr_core_watch_write(avr, a, (uint8_t)(avr->data[a] | m)); + return (uint8_t)((avr->data[a] >> rb.bit) & rb.mask); +} + +static inline uint8_t +avr_regbit_setto( + avr_t * avr, + avr_regbit_t rb, + uint8_t v) +{ + uint16_t a = rb.reg; + uint8_t m; + + if (!a) + return 0; + m = (uint8_t)(rb.mask << rb.bit); + avr_core_watch_write(avr, a, + (uint8_t)((avr->data[a] & ~(m)) | + ((v << rb.bit) & m))); + return (uint8_t)((avr->data[a] >> rb.bit) & rb.mask); +} + +/* + * Set the 'raw' bits, if 'v' is the unshifted value of the bits + */ +static inline uint8_t +avr_regbit_setto_raw( + avr_t * avr, + avr_regbit_t rb, + uint8_t v) +{ + uint16_t a = rb.reg; + uint8_t m; + + if (!a) + return 0; + m = (uint8_t)(rb.mask << rb.bit); + avr_core_watch_write(avr, a, + (uint8_t)((avr->data[a] & ~(m)) | ((v) & m))); + return (uint8_t)((avr->data[a]) & (rb.mask << rb.bit)); +} + +static inline uint8_t +avr_regbit_get( + avr_t * avr, + avr_regbit_t rb) +{ + uint16_t a = rb.reg; + if (!a) + return 0; + //uint8_t m = rb.mask << rb.bit; + return (uint8_t)((avr->data[a] >> rb.bit) & rb.mask); +} + +/* + * Using regbit from value eliminates some of the + * set to test then clear register operations. + * makes cheking register bits before setting easier. + */ +static inline uint8_t +avr_regbit_from_value( + avr_t * avr __attribute__((unused)), + avr_regbit_t rb, + uint8_t value) +{ + uint16_t a = rb.reg; + if (!a) + return 0; + return (uint8_t)((value >> rb.bit) & rb.mask); +} + +/* + * Return the bit(s) 'in position' instead of zero based + */ +static inline uint8_t +avr_regbit_get_raw( + avr_t * avr, + avr_regbit_t rb) +{ + uint16_t a = rb.reg; + if (!a) + return 0; + //uint8_t m = rb.mask << rb.bit; + return (uint8_t)((avr->data[a]) & (rb.mask << rb.bit)); +} + +static inline uint8_t +avr_regbit_clear( + avr_t * avr, + avr_regbit_t rb) +{ + uint16_t a = rb.reg; + if (!a) + return 0; + uint8_t m = (uint8_t)(rb.mask << rb.bit); + avr_core_watch_write(avr, a, (uint8_t)(avr->data[a] & ~m)); + return avr->data[a]; +} + + +/* + * This reads the bits for an array of avr_regbit_t, make up a "byte" with them. + * This allows reading bits like CS0, CS1, CS2 etc even if they are not in the same + * physical IO register. + */ +static inline uint8_t +avr_regbit_get_array( + avr_t * avr, + avr_regbit_t *rb, + int count) +{ + uint8_t res = 0; + int i; + + for (i = 0; i < count; i++, rb++) if (rb->reg) { + uint16_t a = rb->reg; + res |= (uint8_t)(((avr->data[a] >> rb->bit) & rb->mask) << i); + } + return res; +} + +/* + * Does the reverse of avr_regbit_get_array + */ +static inline void +avr_regbit_set_array_from_value( + avr_t * avr, + avr_regbit_t * rb, + uint8_t count, + uint8_t value) +{ + int i; + for (i = 0; i < count; i++, rb++) if (rb->reg) { + uint8_t rbv = (value >> (count - i)) & 1; + avr_regbit_setto(avr, *rb, rbv); + } +} + +#define AVR_IO_REGBIT(_io, _bit) { . reg = (_io), .bit = (_bit), .mask = 1 } +#define AVR_IO_REGBITS(_io, _bit, _mask) { . reg = (_io), .bit = (_bit), .mask = (_mask) } + +#ifdef __cplusplus +}; +#endif + +#endif /* __SIM_REGBIT_H__ */ diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_time.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_time.h new file mode 100644 index 0000000..4b81f43 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_time.h @@ -0,0 +1,64 @@ +/* + sim_time.h + + Copyright 2008-2012 Michel Pollet + + 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 . + */ + + +#ifndef __SIM_TIME_H___ +#define __SIM_TIME_H___ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "sim_avr.h" + +// converts a number of usec to a number of machine cycles, at current speed +static inline avr_cycle_count_t +avr_usec_to_cycles(struct avr_t * avr, uint32_t usec) +{ + return avr->frequency * (avr_cycle_count_t)usec / 1000000; +} + +// converts back a number of cycles to usecs (for usleep) +static inline uint32_t +avr_cycles_to_usec(struct avr_t * avr, avr_cycle_count_t cycles) +{ + return 1000000L * cycles / avr->frequency; +} + +// converts back a number of cycles to nsecs +static inline uint64_t +avr_cycles_to_nsec(struct avr_t * avr, avr_cycle_count_t cycles) +{ + return (uint64_t)1E6 * (uint64_t)cycles / (avr->frequency/1000); +} + +// converts a number of hz (to megahertz etc) to a number of cycle +static inline avr_cycle_count_t +avr_hz_to_cycles(avr_t * avr, uint32_t hz) +{ + return avr->frequency / hz; +} + +#ifdef __cplusplus +}; +#endif + +#endif /* __SIM_TIME_H___ */ diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_utils.c b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_utils.c new file mode 100644 index 0000000..eeb4986 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_utils.c @@ -0,0 +1,68 @@ +/* + sim_utils.c + + Implements a Value Change Dump file outout to generate + traces & curves and display them in gtkwave. + + Copyright 2008, 2009 Michel Pollet + + 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_utils.h" + +static argv_p +argv_realloc( + argv_p argv, + uint32_t size ) +{ + argv = realloc(argv, + sizeof(argv_t) + (size * sizeof(argv->argv[0]))); + argv->size = size; + return argv; +} + +argv_p +argv_parse( + argv_p argv, + char * line ) +{ + if (!argv) + argv = argv_realloc(argv, 8); + argv->argc = 0; + + /* strip end of lines and trailing spaces */ + char *d = line + strlen(line); + while ((d - line) > 0 && *(--d) <= ' ') + *d = 0; + /* stop spaces + tabs */ + char *s = line; + while (*s && *s <= ' ') + s++; + argv->line = s; + char * a = NULL; + do { + if (argv->argc == argv->size) + argv = argv_realloc(argv, argv->size + 8); + if ((a = strsep(&s, " \t")) != NULL) + argv->argv[argv->argc++] = a; + } while (a); + argv->argv[argv->argc] = NULL; + return argv; +} diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_utils.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_utils.h new file mode 100644 index 0000000..44cb2c5 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_utils.h @@ -0,0 +1,51 @@ +/* + sim_utils.h + + Implements a Value Change Dump file outout to generate + traces & curves and display them in gtkwave. + + Copyright 2008, 2009 Michel Pollet + + 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 . + */ + +#ifndef __SIM_UTILS_H__ +#define __SIM_UTILS_H__ + +#include + +typedef struct argv_t { + uint32_t size, argc; + char * line; + char * argv[]; +} argv_t, *argv_p; + +/* + * Allocate a argv_t structure, split 'line' into words (destructively) + * and fills up argc, and argv fields with pointers to the individual + * words. The line is stripped of any \r\n as well + * You can pass an already allocated argv_t for it to be reused (and + * grown to fit). + * + * You are still responsible, as the caller, to (free) the resulting + * pointer, and the 'line' text, if appropriate, no duplication is made + */ +argv_p +argv_parse( + argv_p argv, + char * line ); + +#endif /* __SIM_UTILS_H__ */ diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_vcd_file.c b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_vcd_file.c new file mode 100644 index 0000000..16e4d25 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_vcd_file.c @@ -0,0 +1,630 @@ +/* + sim_vcd_file.c + + Implements a Value Change Dump file outout to generate + traces & curves and display them in gtkwave. + + Copyright 2008, 2009 Michel Pollet + + 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 +#include +#include +#include +#include "sim_vcd_file.h" +#include "sim_avr.h" +#include "sim_time.h" +#include "sim_utils.h" +#include "sim_core_config.h" + +DEFINE_FIFO(avr_vcd_log_t, avr_vcd_fifo); + +#define strdupa(__s) strcpy(alloca(strlen(__s)+1), __s) + +static void +_avr_vcd_notify( + struct avr_irq_t * irq, + uint32_t value, + void * param); + +int +avr_vcd_init( + struct avr_t * avr, + const char * filename, + avr_vcd_t * vcd, + uint32_t period) +{ + memset(vcd, 0, sizeof(avr_vcd_t)); + vcd->avr = avr; + vcd->filename = strdup(filename); + vcd->period = avr_usec_to_cycles(vcd->avr, period); + return 0; +} + +/* + * Parse a VCD 'timing' line. The lines are assumed to be: + * #[\n][| + * b[x/z/0/1]?argc == 0) + return res; + + if (v->argv[0][0] == '#') { + res = atoll(v->argv[0] + 1) * vcd->vcd_to_ns; + vcd->start = vcd->period; + vcd->period = res; + vi++; + } + for (int i = vi; i < v->argc; i++) { + char * a = v->argv[i]; + uint32_t val = 0; + int floating = 0; + char name = 0; + int sigindex; + + if (*a == 'b' || *a == 'B') { // Binary string + a++; + while (*a) { + if (*a == 'x' || *a == 'z') { + val <<= 1; + floating |= (floating << 1) | 1; + } else if (*a == '0' || *a == '1') { + val = (val << 1) | (*a - '0'); + floating <<= 1; + } else { + name = *a; + break; + } + a++; + } + } else if (*a == '0' || *a == '1' || *a == 'x' || *a == 'z') { + if (*a == 'x' || *a == 'z') + floating = 1; + else + val = *a++ - '0'; + if (*a && *a > ' ') + name = *a; + } else if (*a == 'r' || *a == 'R') { + val = (uint32_t)strtod(++a, NULL); + } + + if (!name && (i < v->argc - 1)) { + const char *n = v->argv[i+1]; + if (strlen(n) == 1) { + // we've got a name, it was not attached + name = *n; + i++; // skip that one + } + } + sigindex = -1; + if (name) { + for (int si = 0; + si < vcd->signal_count && + sigindex == -1; si++) { + if (vcd->signal[si].alias == name) + sigindex = si; + } + } + if (sigindex == -1) { + printf("Signal name '%c' value %x not found\n", + name? name : '?', val); + continue; + } + avr_vcd_log_t e = { + .when = vcd->period, + .sigindex = sigindex, + .floating = !!floating, + .value = val, + }; + // printf("%10u %d\n", e.when, e.value); + avr_vcd_fifo_write(&vcd->log, e); + } + return res; +} + +/* + * Read some signals from the file and fill the FIFO with it, we read + * a completely arbitrary amount of stuff to fill the FIFO reasonably well + */ +static int +avr_vcd_input_read( + avr_vcd_t * vcd ) +{ + char line[1024]; + + while (fgets(line, sizeof(line), vcd->input)) { + // printf("%s", line); + if (!line[0]) // technically can't happen, but make sure next line works + continue; + vcd->input_line = argv_parse(vcd->input_line, line); + avr_vcd_input_parse_line(vcd, vcd->input_line); + /* stop once the fifo is full enough */ + if (avr_vcd_fifo_get_read_size(&vcd->log) >= 128) + break; + } + return avr_vcd_fifo_isempty(&vcd->log); +} + +/* + * This is called when we need to change the state of one or more IRQ, + * so look in the FIFO to know 'our' stamp time, read as much as we can + * that is still on that same timestamp. + * When when the FIFO content has too far in the future, re-schedule the + * timer for that time and shoot off. + * Also try to top up the FIFO with new read stuff when it's drained + */ +static avr_cycle_count_t +_avr_vcd_input_timer( + struct avr_t * avr, + avr_cycle_count_t when, + void * param) +{ + avr_cycle_count_t next; + avr_vcd_t * vcd = param; + +again: + // get some more if needed + if (avr_vcd_fifo_get_read_size(&vcd->log) < (vcd->signal_count * 16)) + avr_vcd_input_read(vcd); + + if (avr_vcd_fifo_isempty(&vcd->log)) { + printf("%s DONE but why are we here?\n", __func__); + return 0; + } + + avr_vcd_log_t log = avr_vcd_fifo_read_at(&vcd->log, 0); + uint64_t stamp = log.when; + while (!avr_vcd_fifo_isempty(&vcd->log)) { + log = avr_vcd_fifo_read_at(&vcd->log, 0); + if (log.when != stamp) // leave those in the FIFO + break; + // we already have it + avr_vcd_fifo_read_offset(&vcd->log, 1); + avr_vcd_signal_p signal = &vcd->signal[log.sigindex]; + avr_raise_irq_float(&signal->irq, log.value, log.floating); + } + + if (avr_vcd_fifo_isempty(&vcd->log)) { + AVR_LOG(vcd->avr, LOG_TRACE, + "%s Finished reading, ending simavr\n", + vcd->filename); + avr->state = cpu_Done; + return 0; + } + log = avr_vcd_fifo_read_at(&vcd->log, 0); + + next = (log.when * avr->frequency) / (1000*1000*1000); + if (next <= when) + goto again; + return next; +} + +int +avr_vcd_init_input( + struct avr_t * avr, + const char * filename, // filename to read + avr_vcd_t * vcd ) // vcd struct to initialize +{ + memset(vcd, 0, sizeof(avr_vcd_t)); + vcd->avr = avr; + vcd->filename = strdup(filename); + + vcd->input = fopen(vcd->filename, "r"); + if (!vcd->input) { + perror(filename); + return -1; + } + char line[1024]; + argv_p v = NULL; + + while (fgets(line, sizeof(line), vcd->input)) { + if (!line[0]) // technically can't happen, but make sure next line works + continue; + v = argv_parse(v, line); + + // we are done reading headers, got our first timestamp + if (v->line[0] == '#') { + uint64_t when; + + vcd->start = 0; + avr_vcd_input_parse_line(vcd, v); + when = (vcd->period * vcd->avr->frequency) / + (1000*1000*1000); + avr_cycle_timer_register(vcd->avr, when, + _avr_vcd_input_timer, vcd); + break; + } + // ignore multiline stuff + if (v->line[0] != '$') + continue; + + const char * end = !strcmp(v->argv[v->argc - 1], "$end") ? + v->argv[v->argc - 1] : NULL; + const char *keyword = v->argv[0]; + + if (keyword == end) + keyword = NULL; + if (!keyword) + continue; + + if (!strcmp(keyword, "$timescale")) { + // sim_vcd header allows only integer factors of ns: 1ns, 2us, 3ms, 10s, ... + uint64_t cnt = 0; + char *si = v->argv[1]; + + vcd->vcd_to_ns = 1; + while (si && *si && isdigit(*si)) + cnt = (cnt * 10) + (*si++ - '0'); + while (si && *si == ' ') + si++; + if (si && !*si) + si = v->argv[2]; + if (!strcmp(si, "ns")) { + // no calculation here + vcd->vcd_to_ns = cnt; + } else if (!strcmp(si, "us")) { + cnt*=1000; + vcd->vcd_to_ns = cnt; + } else if (!strcmp(si, "ms")) { + cnt*=1000*1000; + vcd->vcd_to_ns = cnt; + } else if (!strcmp(si, "s")) { + cnt*=1000*1000*1000; + vcd->vcd_to_ns = cnt; + } + // printf("cnt %dus; unit %s\n", (int)cnt, si); + } else if (!strcmp(keyword, "$var")) { + const char *name = v->argv[4]; + + vcd->signal[vcd->signal_count].alias = v->argv[3][0]; + vcd->signal[vcd->signal_count].size = atoi(v->argv[2]); + strncpy(vcd->signal[vcd->signal_count].name, name, + sizeof(vcd->signal[0].name)); + + vcd->signal_count++; + } + } + // reuse this one + vcd->input_line = v; + + for (int i = 0; i < vcd->signal_count; i++) { + AVR_LOG(vcd->avr, LOG_TRACE, "%s %2d '%c' %s : size %d\n", + __func__, i, + vcd->signal[i].alias, vcd->signal[i].name, + vcd->signal[i].size); + /* format is [_] */ + if (strlen(vcd->signal[i].name) >= 4) { + char *dup = strdupa(vcd->signal[i].name); + char *ioctl = strsep(&dup, "_"); + int index = 0; + if (dup) + index = atoi(dup); + if (strlen(ioctl) == 4) { + uint32_t ioc = AVR_IOCTL_DEF( + ioctl[0], ioctl[1], ioctl[2], ioctl[3]); + avr_irq_t * irq = avr_io_getirq(vcd->avr, ioc, index); + if (irq) { + vcd->signal[i].irq.flags = IRQ_FLAG_INIT; + avr_connect_irq(&vcd->signal[i].irq, irq); + } else { + AVR_LOG(vcd->avr, LOG_WARNING, + "%s IRQ was not found\n", + vcd->signal[i].name); + } + continue; + } + AVR_LOG(vcd->avr, LOG_WARNING, + "%s is an invalid IRQ format\n", + vcd->signal[i].name); + } + } + return 0; +} + +void +avr_vcd_close( + avr_vcd_t * vcd) +{ + avr_vcd_stop(vcd); + + /* dispose of any link and hooks */ + for (int i = 0; i < vcd->signal_count; i++) { + avr_vcd_signal_t * s = &vcd->signal[i]; + + avr_free_irq(&s->irq, 1); + } + + if (vcd->filename) { + free(vcd->filename); + vcd->filename = NULL; + } +} + +static char * +_avr_vcd_get_float_signal_text( + avr_vcd_signal_t * s, + char * out) +{ + char * dst = out; + + if (s->size > 1) + *dst++ = 'b'; + + for (int i = s->size; i > 0; i--) + *dst++ = 'x'; + if (s->size > 1) + *dst++ = ' '; + *dst++ = s->alias; + *dst = 0; + return out; +} + +static char * +_avr_vcd_get_signal_text( + avr_vcd_signal_t * s, + char * out, + uint32_t value) +{ + char * dst = out; + + if (s->size > 1) + *dst++ = 'b'; + + for (int i = s->size; i > 0; i--) + *dst++ = value & (1 << (i-1)) ? '1' : '0'; + if (s->size > 1) + *dst++ = ' '; + *dst++ = s->alias; + *dst = 0; + return out; +} + +/* Write queued output to the VCD file. */ + +static void +avr_vcd_flush_log( + avr_vcd_t * vcd) +{ +#if AVR_VCD_MAX_SIGNALS > 32 + uint64_t seen = 0; +#else + uint32_t seen = 0; +#endif + uint64_t oldbase = 0; // make sure it's different + char out[48]; + + if (avr_vcd_fifo_isempty(&vcd->log) || !vcd->output) + return; + + while (!avr_vcd_fifo_isempty(&vcd->log)) { + avr_vcd_log_t l = avr_vcd_fifo_read(&vcd->log); + // 10ns base -- 100MHz should be enough + uint64_t base = avr_cycles_to_nsec(vcd->avr, l.when - vcd->start) / 10; + + /* + * if that trace was seen in this nsec already, we fudge the + * base time to make sure the new value is offset by one nsec, + * to make sure we get at least a small pulse on the waveform. + * + * This is a bit of a fudge, but it is the only way to represent + * very short "pulses" that are still visible on the waveform. + */ + if (base == oldbase && + (seen & (1 << l.sigindex))) + base++; // this forces a new timestamp + + if (base > oldbase || !seen) { + seen = 0; + fprintf(vcd->output, "#%" PRIu64 "\n", base); + oldbase = base; + } + // mark this trace as seen for this timestamp + seen |= (1 << l.sigindex); + fprintf(vcd->output, "%s\n", + l.floating ? + _avr_vcd_get_float_signal_text( + &vcd->signal[l.sigindex], + out) : + _avr_vcd_get_signal_text( + &vcd->signal[l.sigindex], + out, l.value)); + } +} + +/* Cycle timer for writing queued output. */ + +static avr_cycle_count_t +_avr_vcd_timer( + struct avr_t * avr, + avr_cycle_count_t when, + void * param) +{ + avr_vcd_t * vcd = param; + avr_vcd_flush_log(vcd); + return when + vcd->period; +} + +/* Called for an IRQ that is being recorded. */ + +static void +_avr_vcd_notify( + struct avr_irq_t * irq, + uint32_t value, + void * param) +{ + avr_vcd_t * vcd = (avr_vcd_t *)param; + + if (!vcd->output) { + AVR_LOG(vcd->avr, LOG_WARNING, + "%s: no output\n", + __FUNCTION__); + return; + } + + avr_vcd_signal_t * s = (avr_vcd_signal_t*)irq; + avr_vcd_log_t l = { + .sigindex = s->irq.irq, + .when = vcd->avr->cycle, + .value = value, + .floating = !!(avr_irq_get_flags(irq) & IRQ_FLAG_FLOATING), + }; + if (avr_vcd_fifo_isfull(&vcd->log)) { + AVR_LOG(vcd->avr, LOG_WARNING, + "%s FIFO Overload, flushing!\n", + __func__); + /* Decrease period by a quarter, for next time */ + vcd->period -= vcd->period >> 2; + avr_vcd_flush_log(vcd); + } + avr_vcd_fifo_write(&vcd->log, l); +} + +/* Register an IRQ whose value is to be logged. */ + +int +avr_vcd_add_signal( + avr_vcd_t * vcd, + avr_irq_t * signal_irq, + int signal_bit_size, + const char * name ) +{ + if (vcd->signal_count == AVR_VCD_MAX_SIGNALS) { + AVR_LOG(vcd->avr, LOG_ERROR, + " %s: unable add signal '%s'\n", + __FUNCTION__, name); + return -1; + } + int index = vcd->signal_count++; + avr_vcd_signal_t * s = &vcd->signal[index]; + strncpy(s->name, name, sizeof(s->name)); + s->size = signal_bit_size; + s->alias = ' ' + vcd->signal_count ; + + /* manufacture a nice IRQ name */ + int l = strlen(name); + char iname[10 + l + 1]; + if (signal_bit_size > 1) + sprintf(iname, "%d>vcd.%s", signal_bit_size, name); + else + sprintf(iname, ">vcd.%s", name); + + const char * names[1] = { iname }; + avr_init_irq(&vcd->avr->irq_pool, &s->irq, index, 1, names); + avr_irq_register_notify(&s->irq, _avr_vcd_notify, vcd); + + avr_connect_irq(signal_irq, &s->irq); + return 0; +} + +/* Open the VCD output file and write header. Does nothing for input. */ + +int +avr_vcd_start( + avr_vcd_t * vcd) +{ + time_t now; + + vcd->start = vcd->avr->cycle; + avr_vcd_fifo_reset(&vcd->log); + + if (vcd->input) { + /* + * nothing to do here, the first cycle timer will take care + * if it. + */ + return 0; + } + if (vcd->output) + avr_vcd_stop(vcd); + vcd->output = fopen(vcd->filename, "w"); + if (vcd->output == NULL) { + perror(vcd->filename); + return -1; + } + + time(&now); + fprintf(vcd->output, "$date %s$end\n", ctime(&now)); + fprintf(vcd->output, + "$version Simavr " CONFIG_SIMAVR_VERSION " $end\n"); + fprintf(vcd->output, "$timescale 10ns $end\n"); // 10ns base, aka 100MHz + fprintf(vcd->output, "$scope module logic $end\n"); + + for (int i = 0; i < vcd->signal_count; i++) { + fprintf(vcd->output, "$var wire %d %c %s $end\n", + vcd->signal[i].size, vcd->signal[i].alias, vcd->signal[i].name); + } + + fprintf(vcd->output, "$upscope $end\n"); + fprintf(vcd->output, "$enddefinitions $end\n"); + + fprintf(vcd->output, "$dumpvars\n"); + for (int i = 0; i < vcd->signal_count; i++) { + avr_vcd_signal_t * s = &vcd->signal[i]; + char out[48]; + fprintf(vcd->output, "%s\n", + _avr_vcd_get_float_signal_text(s, out)); + } + fprintf(vcd->output, "$end\n"); + avr_cycle_timer_register(vcd->avr, vcd->period, _avr_vcd_timer, vcd); + return 0; +} + +int +avr_vcd_stop( + avr_vcd_t * vcd) +{ + avr_cycle_timer_cancel(vcd->avr, _avr_vcd_timer, vcd); + avr_cycle_timer_cancel(vcd->avr, _avr_vcd_input_timer, vcd); + + avr_vcd_flush_log(vcd); + + if (vcd->input_line) + free(vcd->input_line); + vcd->input_line = NULL; + if (vcd->input) + fclose(vcd->input); + vcd->input = NULL; + if (vcd->output) + fclose(vcd->output); + vcd->output = NULL; + return 0; +} + + diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_vcd_file.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_vcd_file.h new file mode 100644 index 0000000..2dd6219 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simavr/sim/sim_vcd_file.h @@ -0,0 +1,131 @@ +/* + sim_vcd_file.c + + Implements a Value Change Dump file outout to generate + traces & curves and display them in gtkwave. + + Copyright 2008, 2009 Michel Pollet + + 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 . + */ + +#ifndef __SIM_VCD_FILE_H__ +#define __SIM_VCD_FILE_H__ + +#include +#include "sim_irq.h" +#include "fifo_declare.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Value Change dump module for simavr. + * + * This structure registers IRQ change hooks to various "source" IRQs + * and dumps their values (if changed) at certain intervals into the VCD + * file. + * + * It can also do the reverse, load a VCD file generated by for example + * sigrock signal analyzer, and 'replay' digital input with the proper + * timing. + * + * TODO: Add support for 'looping' a VCD input. + */ + +#define AVR_VCD_MAX_SIGNALS 64 + +typedef struct avr_vcd_signal_t { + /* + * For VCD output this is the IRQ we receive new values from. + * For VCD input, this is the IRQ we broadcast the values to + */ + avr_irq_t irq; + char alias; // vcd one character alias + uint8_t size; // in bits + char name[32]; // full human name +} avr_vcd_signal_t, *avr_vcd_signal_p; + +typedef struct avr_vcd_log_t { + uint64_t when; // Cycles for output, + // nS for input. + uint64_t sigindex : 8, // index in signal table + floating : 1, + value : 32; +} avr_vcd_log_t, *avr_vcd_log_p; + +DECLARE_FIFO(avr_vcd_log_t, avr_vcd_fifo, 256); + +struct argv_t; + +typedef struct avr_vcd_t { + struct avr_t * avr; // AVR we are attaching timers to.. + + char * filename; // .vcd filename + /* can be input OR output, not both */ + FILE * output; + FILE * input; + struct argv_t * input_line; + + int signal_count; + avr_vcd_signal_t signal[AVR_VCD_MAX_SIGNALS]; + + uint64_t start; + uint64_t period; // for output cycles + uint64_t vcd_to_ns; // for input unit mapping + + avr_vcd_fifo_t log; +} avr_vcd_t; + +// initializes a new VCD trace file, and returns zero if all is well +int +avr_vcd_init( + struct avr_t * avr, + const char * filename, // filename to write + avr_vcd_t * vcd, // vcd struct to initialize + uint32_t period ); // file flushing period is in usec +int +avr_vcd_init_input( + struct avr_t * avr, + const char * filename, // filename to read + avr_vcd_t * vcd ); // vcd struct to initialize +void +avr_vcd_close( + avr_vcd_t * vcd ); + +// Add a trace signal to the vcd file. Must be called before avr_vcd_start() +int +avr_vcd_add_signal( + avr_vcd_t * vcd, + avr_irq_t * signal_irq, + int signal_bit_size, + const char * name ); + +// Starts recording the signal value into the file +int +avr_vcd_start( + avr_vcd_t * vcd); +// stops recording signal values into the file +int +avr_vcd_stop( + avr_vcd_t * vcd); + +#ifdef __cplusplus +}; +#endif + +#endif /* __SIM_VCD_FILE_H__ */ diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/simuc b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/simuc new file mode 100755 index 0000000000000000000000000000000000000000..966bd1f1fef2c8ad96d4c10ce19072af1de44a61 GIT binary patch literal 1820968 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

jYLP-V2|xnd#%O<5*YpS7*-s!qtp{%h zJGDQ`4K5{pTGEj+ewo0H<4~ayM(yX~A3vLG_Hb>2#6n;Ctrfaa$ONaI9{Wc0#|MNc zE5<%3BpTZ2$R8};=*}wwJ=FPGCGCxx%UK{L@Z*QG>nox!O{qiRdRF!#>j_7qst2^+ z%lM3%%InQ3GxYRW*BM34pNc*6G3j}mWe}k=CJ~*W?cyeExN&{BT%)TfcEqTXd%!@J zIp!T45}tzF*D=w>nl@s8rn6Ml7OLi))Ow^S_Lk0r1;HJXdFsMKh|uF<`KZ-p6@s-M zF-<83p2fC>zAfji>M%@@fv#&4q?0@f$}Gm1h>_t@%=9z{W>h`TGf^90!4kWjRjviT ziVTpQL963NMEV1iTH6s7=IRaosD!Bf2NVHW0a;4mB;b*=>3~QeBQOHgwq%QC@r8Xb zpDJuC34C*yCULEp%`*A(k`t2kRTIKKuD91yIE8=8f2Ge`IX*X-wf3zacc$BjeL+hk z89m;=Zp1`(aw0&naA2+A;UnWv>8uRo#Vecho6;HKN*mU8#0ozjuR6C*p-D;-IO} zI9t=NOIm@ZTa=~;{5b&A^Knczp^M$5o^=*<=JhbsR6n7Ig*Y6_aO8bO{Pzma_XeW< z3JB6xh|o^NsU6E-1!3WYuD zP>94^TJf1`y@+l(3#$TIVEu^r34VGIqjD^RCsjPrOWqijCeS{FP0BxDwy-gJrTo$k z>*0V^`(ijSaKfC{eR90G z%k_qV7v39H^VU7@f2|lv%w}(dY^M>jt7b^r(Sthz^}9K8s6?j5eb?V_)Yg`>fNH4W z34$l;s}UOpekeSe68aBGyk*Ku7=qn_{Br5VsQLa}+BJV9t$%d`&I~S~dRpIdTDkom zjo*o91hv$u4QntbEnN&#sKs8ngJCHZ$B6xj>PbBXRVZh0{H<1%9R5eV5xbllz7Dpi zO%xgY(>Sl}JJsM_om2Ps>wxM{p`((n^e0UC7*dLTWq-2ge0+aJ(x3QB(n!qZ-})G~ zTsf?FPT=AqK90%CVZ;gmYwD6P7>n8-HDZz%2D+0`imcJ`Hc6RM=jh@Tcd1gJGyWUp z9i|U67N&2+yz;lU8P*AJ)7%jrnq-hdC#KTXopB_}yzvJ`caI+N-g;Af8zE9sS z2}Hy{zAGe8{F2h|tT#4Oikeb|$Bqt-zm(KL9;;bl~-<~~6Drv*8u*K?md`~Y5?mL4^5vsa2;1!|qS~iPv zPC-l6Ea7+ZOyu7|0NvUaZ;)$YWLMStF%Bztl2zTQ)jdC#IytAwH4uGe+2wQ}!m{mH zpUF4tpCiS){ZfIFn4uyxy88=+GfM2P@J3KDroOlYsg&mv%D8GN-VrMhO*133KoqNT zzM_Q~u@89{ocB<{LLPAOH!-_DPKU{_$kDTmHD~a;(Q`p?UQ9g`r9`RV9^=G`~n@P(r(`}e1!nE8p{9l*XUZ0ji>Jnc1v6ryqVUTB}ldARKl%3HNe>@`=)`$a3`} ziMWs%YF%9@Um|P;9`X-7p0JR`X{-mMP6eaZRu4H5Y`TG@iao)u_FrkfBdJYgNj1XX zHJ%B{a_}Uz!o*s+E1NE!#?s7*(f%yn9FO*c#IcsiE8#P*$m&>kEs+GMdim|1yjrV| z-e3aP0WamensAeA^|sZ~!0#w^th`BP=SJEXH4n&Y$X-ty5W)#%#BQRmC^yx=sF1h% zK`DTE<+T)R;1gb?#QcLYb2x~6q+^H?%i+lh4UMBzhmbW8Mfn}e0bQpFMFYN6wI)+{ zP%~rSI~uLyOT66$@AJeNj|9x`xaz*U3>d1k3ZZX4G+ za|)3$&{49A#Sl#?s@qe&*SX>~M7Wb0unhP1%Y<>5bC{p`;A}m8`RLZl+7q;5#8xQA zr=;PmfY(y-A6n0`3RJ6V*!F6*=Gs0~`oVQ@m0-NfJ$UK{{^AWLu6=Z}B?F)R%AgNto+MY(-N>U~c?52>eI z9FePJUUAaK5K{ssT3fvG*qVQ3>xbue9{cWpNJm$y0WDj)I5U1N-R3L}fCIKy}({qpUlD7!ALT~ z*I-IcNV~eB=pOF5LEmxpCx7+Sg8s@qWD@|V)wZWB37ze-&gG2GS6G)0sK5@YyP1Ig zJC;b{OF!mKnmiIv zz*$$n&K9d0x4n`AS{|CkD?#sMem3nttUtId|J4dPm7R@29&~BA>+H<2*$wvRY=tHD zU9aS8R$fW-U`^! z+~Jt*%irjazmxqc%+sa6s@K>&8-I2tCyVUe>>nxjT!&f}9XTxCxtt5NPW(R4(?oNZ z^*>`3KK*-A!(Ff1OA%5ElkVqDyg^&t;E??|za9UTxK~p|^ot3i9HrYP5Aei6H^Cyu zU#AJ}A{;wlrBpZk)ur5du6Xo~T?#|t%2ebjdZTK=Fsd?H^rR5)vYs35G;ZjU{H2yH zH)`s2qwHQ7keoqQ-OxiRQXnx#0Yov)bWen8MPz~1PxUx}C2<@o@2a&p5pV=cjwiFz z*s;}Z=tk`y>p{gBj?$cj*B(2r&o5TvIuYSB>=Tabfv+6b$`g+3o~_4>>spHGe4}R1 zo|pCGHX4-oaU2%&O_l75e;(J5IP}ltlCl0Zd=IFb#d2R%U#~3U@fol1olMDF?iI@h z7R`^VIl!WC7O?(wDM*aEE%Oy)*mt4+E$bq`3!UGhNy_hhe(Q)!omLqsB@vg)=Z39s zpkgXZBpDt#3JW_@EecQumKX`KtnuTddbg~NH?sL^O<)+>-k=i-JX;{ObX=u1f|sh& zGXBQY8@24B$Z}dm4#?o(6=Ow4*mVh|U7HYKokb);_%c<0vWTads`&`bYrot=^=d}4 zfn+=4bwy&i8nuGJK2bKFyfM(54nljdpmaaQv)1UfYdZpWlC@BL^mCQ_)+|#{e^QUPAWzWW)rXd>CTgb8nML^TO*1A0ZDW~f_3*QYJ@wen|yB-5isD-0^ zY-=C+b7xokv#$Om_5u#L@<5y$Q&3N`D0rGnO?kmXM}eI%<1}dqW>eaXjLZ=#GR0reB(UwXJm1L z{jMwqoIO+eQQjoGl+mV{ql$lU%O^LXupx<%5+N}JFP%Fcna?yfLY1FoNUUY$DWaTl zRW-Yy}X|Ak#Dw@m2^9DuXZ|&R*6_c( z-2N6>MW7#SHFmB#uIhnV-5WABYPcu$=#!a7)qYu(_~$sJVs*Fm>9{JB$j0}1hC0+! zZTi>QARU5zOoOpzoqB;K5j9n{`au1TUZfk$%EsU7eVdCsmUE7E5{5M^P6WIxaU6;) z&E>N+L#;PKJHr~)YX1@gS+^rsB0>_)$j=@@+y`oZ496z%D4F46R3Bovr+KOecGPEt zUWMZOcUHuwW_7l2aOWFHTsCP2o{7IQ-StI`&G)?gwI_qV0&jDgCqB@e+W!lxebK&V zt-|Z}A5rbX>!|h^)t;wlS9?suw`>M+h~H!h*Z-Dg*t9uJF-m*rL?CHRyuKR(X?RZn zDaV7elVL;-6Y_guLj7PKJ2C@_QGGhD%=CsX8JD?YDN^-bnLLO71NFOlm3p@XyoZgN zJNpDliP>{Q7Ox!0e?0b}@ss-Y0+|OjM;kR8G}Jl+^&bPZ&VYAcgnAx=5agU){SFA7 z)Q?`UID;IG*-h0M8_TR=OpnQ>z ziZ@7`$^480lX!E4?3HU|a~F^ObaJ}=RCf2`uj-3ih~X|ZuP*nswq2FwKl$|Nk-o+n z@#U0~uVp$57H__WQ@@kQeBmSYMNOTq1zs^FD#?^ey-ofsFtaGjc%pgv*@7m{`3VYb zl@dWOw><=V<@qAFWqEFUKVaTkE~Nsi8->f*CBp?B{IZm~JS|27y^10$vpg$X(%Pec z>DTErl9km_l$8~JT9p7ZzGT4bg-XDT52h*1sJa+D8hu@7msN+eR?+u#uCZ_uD4UZV zcBV3&ibj<&$QL;bxaw(T(mXiY&E?mSfH=q`u1-wtDH-B_tMS7UxR-jZQg0pJ8tN{~ z_H~T!;SG^Ud`2+#UTA5g-5WZuG;U2yjN1xNlJejb;IaaVP;Ug-oxQV3#uV`Gu}+>P zH=87{`mCh;hvOceD}xl*0?Rmls7kd#<<}uzmwj7D-mwhXeC+ z{^Tw|!29auT{|^hQoVQYZtLXlopsFb9>@G932G8gq<+t1eyhaqKnD!Lik#}uDNsYATA_jk`i-2YLlX~RIdk#m6xZmL|^}?{n_lUN2!U@J}=%lsJ>&Ulz-CaFC z9ZsqP#y|_auO8o%#o(8aAjH3{Cnq_35l@16axY(^ z@)Y51z#gG$|K(*Rhos$T(@)jB^86=h&*wv8Schw-unsDbT4MC-$!Zpy+*7XR3H zSDoV%)ns0azq%}l_!^iECSCTAGMG&OX5jMM7y8fwBxAQS!ktpdebKCIU!cN0H4pQV$Z#)&>u8@Q`GE5BVCHe&a~ z{fspi(a`G7$?C~&^?kW~uWIBwusV-`Elz3N%`sA;(B3F_c%ir?tGqNZs)bbUq;@a3 z7?4aY=+V)TXH@-$5;*eu`AGalZl72uy`Vk?%!!=Ge3_S&%`AA5F#o}-$}*xO z=~XnD$N3~81{eM1Mb%@U2fR&0IyKU;Cq5<9AKx7r z5J7jbhOtIO#Ywh_inXgdS13sRM3(V5Nc{u&DM;N^K55?P;J9E==A^{99H5g!UU`)x z8z^N0rK;yC?LH&Dya2BU!2BA6HEO1idA^d3r7kOoRmPRI7y2Uo3L@m8V8<8h?b8=1 z=CSUVU?51#y?D|&jI8h3lNYY4PHu708&vB4L~g}3Nfp=%{#rEBl5*}*dYC5B%*CLT zf5#~4$Li?a@?exqjg)3&bClYj(Wm|pOvW2xu(T?WO*}n@1-9NSP>|&8Uy>ex;n~D2 za--ti(VcfIy+H;MoVSUQmO}&-C`MyK1OpCXJRm}(yvGL+K2N#Pu|YrFV&xNwjkBqm zy#LHcz$EDdU!Y@;iswH8m;@e|2jXK<$VY-`cYqO?#On_P zerdmmIJf>qCuwk8H_5SmFnqk^HnoQ%2Gic>roG?sOWEufnz7rElIG>{v1VxG7x9qy z3;Rae)+7;atBW@%tu%5ZVpPc{-Iii;9biP*=krSe6u@$@8}_CywTP4sI^7$|%0M^C z2w(9$ZFSim8AxqtBnooK+i7>wqtx&o}zK*N1GT2%&!{v^e zWSvRstM;ehW2;I5Vgz23K1jOhvZwPWje{xvi#;=bDjOos@H+h7EN`ek_Y0@z<(h!Z z{LE30Bc|&3_RrU!xx@758HIeF;MnYjp9!kQCb<{J2Z?hox1L37mPF;{SjGMV zQd8_PfB07@Q0+W9;EKF<=IWgu&)%-=hWPYMbNXWES9AQz#R_gSstFE(?_FPgO6F!I_k|MC#o}8>Xe_Tj(SsZqB^($ zI;`O*s-xaqNF9I@Do}USC2{5aJ?h-GsPgt6ilmecW&a4hayw~g{tBb&XW*QhsRO<4 zTAwMYI%{*HJIkq*T11(@z3YjjJ}kcpwZwT#yxwF|JIKlKt4mER<(j}P#HI($=fxOT;E|9- zBGd!Rba?u?lAA@>I9=9XrC-Sz?8bcu%2cs%CSwL_%bd7Ug4Y8}STcNAAgH^WEL$vR z=k!ML7Z2KYoL(vYoHPuj+M%4y^;Y`1Adoqpi{2*SH@aQUwX1GrJ3^Xm-Ra1ZWQ=N* zCLP>L6F+Oo-yYv4tDTrWbs8Jv$b`aj{GLPoupH2 zNJ~dq&jAqM^Kv}KoK^(Z?#CZdLh{%$cH*XTnc@poSB$=4eXw7KTuEy@)$FTp??=dM zA07Nkh0=m+3+qUCL&`r{Pw0zXMxf9YUTh|$NB1OWg}vnwe=?)hJjy^?d4eo6^WywX1+6kQ%Ph4 zl4$;+=$-QgIw=`FMqUvb^Mt=4>Rm8#XTeHlK>EMY`*n4;CbCAP^vzOY#RKM=HmWqP zQ8kU)6=gw9l6r@%>Umx&P8!fyS}7?srv?*?3+A^Ebm=v^F*7i>Jyc}WeoK`KeS(GP zH4#*ea{nh894L{Z1}9%z5`8!Q5dt6E9O(#j6gTGvCoz~x3xX2w7D%>u zTx(9$@=DrLmqQ6%)?9O~d0p9mtmCIn+8mA85Mirv$9|0Om6Y=Aun0NntB_b-+}y!y z{bmWRhszuvhahD7CjJ*<0jWLQi(8MV0LDp6r~-EgE96a;4H>GOoc;3U@AZqTebOYq zxvCVO;a>g|Di9m<@6v^ej3IKOcA8|4H;i@uf&tFan+8@(ajMM0awuYtq?g!Y&HqEE zBug-2f8cc>F-_Fb!VYzxwc_;WB@^h?(T^9t^Hub}DV_e&n**x;xz4@_gAO7o%xM9d z>2~FxQT4R42B#JbU>EQ;&~pgp2m?%6WcJnKOVaxVGIZ;YzbBr~$tF>AXMr)kdfZ3> zi#d(!gTtjsnWm1+$9^Vw8h_VZRfduD4nr%0`YC=b;3CY2+eOGWCADHq> z+L!-<3PO>*PcR50_Bd~X?s>XK0tpnu?IYZqu(TFy2&2-&Cl}ftNv(Mi&Wkx}10{LT zxbg$#*Wr$@Y%Gr?y~=RRX<$rAQj1^+4GM-M^l)PDhQ97Xvz9~6+=s9SzUuFjiT<<~ z3~07~NYtQUkfz6z#fTc96agEXO4(b2Vl|VNIMZ;&hYJ62Qw5P=Maa*fd9|-&6-le9 zrf_abeuI)S4X^RivK~D(QnY8(HucFFAUFzWzWgnuH-wS`$f}E=A)A=eG=3@k%F#|_ za|hnjbL(eb4ihfzxmthrkL%CeAMoiUP&{KD-;cesw-7zR)d@Cp_?l2}lJ~!(nWY?f zc6M5`&y*wOinj?*9WwGr8ig3$y>0vVnoHF#S8j)^77{1I(O0Hx!+#AAkTSy2@mt~MvVCO(z(m$=Us5Y z1@cq=RW1nS>4!sk6JB)l(&2fP;pGd4=PkH(MP=bIj}#g)qVl$z=gGI^KlNb2;OvXwi}dc`Fu$7UnHqFn4jD{FISM?mja7%c>>+^tH=HPFa+apHI zJ+^#$ao-8bFJDm6ZGhd%PcFIAZC~KEVCCE;%N8%t>!p|20pQ%wk_9)-{nmwJmNAAD zAPO%Uss8a0IE-9*F~9QWUa&MA(%^U7(2MM>v0Groh=mIlFY`Ef;c?!2QeAlj7o6XP z7kLy;BwvqO<|&yx`I^a>Fo9d=E?zX>!6XnhFI>5R5lQQLp{0413zx3o5%BEOhu#Ds z_*k}dd5DkXTs-G2R*&cL5E%1UKrJ6Y@Yt?2V(0ybzMSzbSyWlM=;oVTG=fy}gjD{` zFg=TIUIcb7y_so%MGGn`^S=B4vG+dkRUKvi|J-|XAs2@Oe_+?3E#r3Rwc7Ax(di^^(uw<^1f zyZvdu`>ifNMYqlUzMq+M?!8HFD73j)x^rGRdCqxe=9!t#JoC&mbIzU9yh+zZ6iYRB zw1->Udzuw`)_51O4FHWD8#XkwH%$ulyX_89gHS=KsNkH?+Kw*K&TtRx_NJMpV(K<} z!fow6ZEdQ&xv669T20#3T-Dvu6K?9**q(K3Xf3@OY#SRu7qB;lB=@fH5Fs6%i36I$ z#io>5Q>G-6+0fKfdQWqEc!*%Mw}#GLjYUW(KkdqOO=~9iNbg&?G*mEoa!93J$zPOP zv8*OEc}_@8nR1)(y2CyE+fe5!U0&yH=)}7|NWI+qQN|*}ZA%w(tgBkjc{P z8t&Vd|FLRsC-(S%rZ z(Y1tFu4(9QZLI4KccHv9XVxvLL+!ZhX$*%%RYFn=EiVGmyRR$x2>bGuC=|p z8BI0EmTgmtXt`w+sHA5@XKA~P4oz;Rp*77~sSwE6(G?p%T;yO1fDi{i2B&z{i_^&s zJ>llwP;*yTN7qoPr{AuevQ&mQ4J=BQ+n2NoWj5V9l$05Hs##YF&Ek}xj93YB-%0;fM;%Q&JZo1J9WCkcW|1$M0*fR8#XjYD}2Ev&C4Dt zi)qs&iyG~uB+7w~616~W9Su#*Luywpw#KnP1A0;JjHyG0%uo$r)Pl?63@M?`=JqDc zfV9p)`+HHnZ|aO}wXFTFc7_yH?Tjs|oGPel>Cyb}=#;v1#}F08^kS4KFL#D&+|-C& zW<(Fo4rMlVhcdILHf=EEyI(i7y<0`c8fPH7xSCAMR)YQODkEtfGcF=R4Qs_cG$syr z#SFPav<_Z+wC!CJV{~As1lX6hwRO_{>)e!5=q@uH=wW?`q|@`1>%25}_GmxZ^;)8C zwK!OKtok1BqX%oTX(%&sJBoErSKWq&yPE6p!s^y+s%!7pbwtW+<{3kjCnr1CxJKI5 z7Y}ZBChm@tYEo$J?93j#pTCtp`9 zPZe9F$1QDu^_bP%q$-xCsfzjY(^Q&(D$+Y~s2alf&r-HfM|%igym~&aZDw~`h?}m= z?A)f={OeWRhiaW#ghDH$SF55mBLcmr@vcx-b)~~(u7ML!T~)Ni$pa5xOCxTPnRtcD zOG`rKGeb(sg#RV_*w)va0JZoZkJ zX!FgK$&^u!nL`wI#?)-Jv7t3QzoW~z&#%j*<Oel+T-VAZ zc;V9Oy8OC@?e}!t)!enPIy^1h!_0W$q9xO-TQ?Nl(>4E|drB*-r`DC~LzRlhDZM~d zFI-ZzysBe^wi;|AxM=^w5- zmOzYLXu^aEatmPs8*b=~&JRG=%nKSxzM`mVDbWT97Y2d7^ym$t$zXAu zWxkH&InfDVD0j}doX|LxUm$+0lx9k6yUL#vy<=`~oOlql_#-EVsi8t&?=UytEV#z zSZmi#3fivgVj5%mnq3IDJb)H?0wBVa=e8p&@HyR|g<3SyH?V7qNY9 z>pC~NiluL847c9XpfQrh2joW9=9(K@I%b6yR^1W8hK4d38oJT-PPh1R>Ep`}_^wsy zYF@|eyt%8nNvDbBNBLZLH5NxNc*IGH=HtMn>WpI5HEw9C(>mJL(b2g^mQ~Cl?V-ck zU7>Eu{^5y3m8x?Ew06|#IlGhmhC8R`Y$&d%DxGP%H+nNOguT&ASrwhS$czA5pDGMV zyW!644Q}qSq$|1_I!%wzO9FVcdc~-+*rXaDP4T7G7x(c8&*3BnMN29(b& znOSytjXdIoo9q}a=<257x?igvVvIugO{%qHrgnX5 z%T;ZeT3N1EmZ??cYE_x4t}N$-5?M9g+kQ`XOSo12U*0qLG|%GYyq@bisGQ0-@$S=Mj5b&Tl}aq&7k zI@-kH5%U=zMXR1xXPI8rX&L<&dWbPF+--GNZx`S`U|cu0G`H&|2{G1UY&V6Q$&o=c zvscDZthr1p2+%w3x( z;w=bV%Zp2#%If7u87dh#8&U4e?kW7|c|%)M)Z?O}Y0SB!wRfS^)44Pr`RI~XI?pP~ z=zC~Jnwl?_RHdbrRTWFreAaxsDJg#2n$~c)()Chxb!OqO+ihE+yZKf7(ZBDD)SuvY zADo4p*_^_UKSS`+IbSC3^PKsFyJrjcu1wJ<8J?qaS9Oc-zbJHO?<{IOlYb0xhUr|$ zO?I|og}1J~IlQr>>#jO?=xS(eZ0-yv4C-obyhkl4nHOro{gO5Iu8y|JjcTH*?&%ai z3|AJf0afFoc5QRl%ni*OI=VJZ-q6rFQ*4&1axC1!_O%_Vicv#l=JfKXw3nk=8hDJ; z%E}~KklC8qu1a;GtEl1>MhAKd)tMxy&QZ*8Gkf_nEmFz^q*-N7xbrlQ4LiC3vCEjOvIjSb<(7S&)#%f>Yn`Yx&P0GF|wc5V(!FN+3h zZCcZcgA*4>&j>fSI}KGMb;-@v#&uS1j;6wzm75#AHqA0ir&!WK2a|^pJ!_m%TR*7a zaSlvD%5@DL`FAHmeB!KbQ;UhSoa#(;^`@;L);e?2Le8C5`q|@g(8kNejs=AA*}eJt z8P@nvTXXxmaLerRnYZ+gzim(&-Roni`bQ^rsDS5v_*dagAz9RzJ$?-i&t2k7j>pBy z&n~#l4Hwb3nbOTkbFV~;WXC&6JF_dZt!b9@G*ZvZpJj~U%qpt-%d3lFQZr>nDrCt$8NcF$VZ*f>)pHu212t-f;d=|<-+I3Jq7 zp=;9xWHmL{$%zY7pYG0RE;-YOr8-lmx_L~UwN5JD+BlP3oO*ROM)RW#!vWvaJU73* zXny3POb^i>%laNX+0F+3iN`M!3B3%HnVsJ|3AZZ0cNQug?$N_T=-%e84m~#M?x)im zjW7={bbOO4lodCfh`QM(U*nApk#H_|MJbKlrM|N$!6P{n(FV{Hbx*5?AsUr%6T_^DtYkLM=Tl%uO4|%Nr3i z#uPeV+z9TB^jY1vO8d7GXvX(YS!r#Ed8=M?HTqy?FTDS_oOM1u+ii86e@P~u5Ph3m zrsPRJ{7#3=<$1FkORu7I_wYy$BYT_tGwtoh>uK+HN3D=qago;?bZi|lE?>z{hPwuI zg4H)3Yc{s97}p&NGiW-FiuMB~p-lO-B&LG+X71|}@-S4^c*JSbzMYKOqCkR>cHJDq zEah7kb=~yDd!eACT^VszoMYj-_6~XSXv%_nG>NqkXXa`gFlKfP zAb$f^4m8`pI}#iXm(NfXx@klp&aREJBjdGM;{Xz!ps zJVly#iu)XRm`e!Bk}0Qo5zLY#aj#E;G2N1hF1L|LYDI|5l~Sr6NW=i69S)e z%L*Uhn* zyyO;3&~z)Sht8uNJY4qZ0Jermlf3S7# z>Jj-@NdM9+L(YR+#ztqMVG@RWZI5}0qa)OD4@*ugrkI&REZxG2=%m$M$v2ZNXQ5?7 zL$9-ndn-v}>1sMUm=v^c;>nLRK?pf+*4-u#jgKjxOwU=pT8Q;FO%&SD)60qsUBFE= zuv}63EWfnL%7$K86hX0K=w$!^=)5hn6Y-j+so7fhI#500GO@_-$3U9Q_HbRN;3>L? z;Omy8Zory{#2FYa`YwD~yu&Uw66=Ti(pFJZsDq^B zuKXU{B)u3}N02b%4#_`0RPM!yxKXQH*R|tBi5q4NJu5P35-z)#x3#>=Wo!)j&nKNc z!vJ}0>v(NVKP6?oP{v%{c}gmlmg;%q#+FU`MVyVzAs(zY&rM?<)7E1aJegB6FYlDM zrbO(*`4yoGluV2x54GBQx?50cy75@#tFbcg?xro9)!2I)m`w0IGna8)1|_cL-8{X1 znWpL_jD8W?s8{czrH3o)Y3)$}C5{ zGS!PqNY?u|fhBM9aE0Zt)r%@BDV`Z}pWe%R zp$({Z$2#}b(y0H_FJ6(n5Sln*|9C?S)bSc|9NU}Qq)Rrowd&{FnLW2<_Jo#826`@` zi{&-Ec3C{Z$8D~29U6lT z1IUKXhOP$IFY4$x8rXOqJ!lY*jys6QJ6G~t4t~rPL7-V!&2}X6s)Q`t)HMvjUlZkv zW3rZ&c88HOK!6)Dr*3e>hE67?&2`Q4>ZRgg0?w&C9f}o8VU_EQxvtBulNYdEYZ(`i zGgLrszW{VqR92q9sRF0H$w|#|ujLt|S$UL})ei*g7FHD3l=HY%)+6hxOKWg}%(D{S zlIjr!aunq?)5*jDWuyIR=;$)Dt7hlVcfo7t>pZJ*B7Svc)q>KcGO1vF z*rb>BND1kb*VRoWj7#r?%ev(G!mFFj^IBOe(`(D2ECylbpfWX)V}Kk{8Yi#(UM8jD z4)YGJUaaoE3sa+uSy5GkD{D-x|Wq>)Yo|oy{&v+Rh2v{kpi=LU>^BtykqfV_O)M3$!1F4+R&O#RwMGwgOMDj zgdOG?u1;Uo(X*~aKP#7a@f+o_vwl{Rrc%-iw{&;5@_vE5R!|^4-5fRYM2hCx(8&_8 z`1+l^*d8OQz#4z!A6Pl)N)cTUigRG8DiBVBpCB7fF9RE+-&uFB3S{vkv4=+Bn zPYTsk@JQ8(&IQ=iEL>8m-?S33@;4=SZP~q2NyaXjYdRy4*rBLkGrN!m5j{h)cC)p- z_;|cV?o2fjM%5MSmp{czPyk&R!BLvBUwoLlZW<1^cBaAm$BSDG(v>jKZd|uP(2%Eq zCec9o24-2aY?c+xwFB{T8)(_m>SdLc^t#fLs36l^DwU6t%UQ;`g)_^!|7}+!aznQ{ z^PwtiuEikfB05jYWA{;gbR-)R3&&o$9zk4;Sh!v+t?Ov)GUKE4>Wv$+4aqS?jAmn} znxn^eL)IA57!$c=F1xmUhkGbA3EAX9B_- zO%IpZ(A3;HW^xO}BBsZz6~s!X>%bfqa~_qgtFD!DU_5#4M+Q|VL*~)ua3Bp;*I?to zor{V}p{5!5If&-gtf;Qi&!hMmM6^zlk>t}Rj+V@gqi?HC;>|_5lL@%VN$bM*uO089~HKxk{_wL=syZXJJEGy>w0<1UOHip^l|B z>4!G75}w&;{HLl~mLO!DF>6;n7{ay=o>MTabj{8*FU988n)9|XQKAB}yb+R{ zO`)z{N0JM>a^ufiwtxY#w~@CD^s1eHJu5*XH-6Zaq{}33tL_85c9Oe+@mjyZA@Ad$ zH8M!d>FvNl?8OE-__;*z)$i>L0C-t7k2Nbh@QN_uyu7LXSy`3uX@=K3g@>VSQVD0> zX^gxPBUakHh(N7z{^Q$*b%;)p=H{#AisLE4%JX5Ez!y%237f(yI9j6)RJ>X~eqMOlefSm|MVac{bF! zgtS z@wK{&G}_j@N@#-l5dvIoBl^iTkMjL1ifW3>N-EHKGoG^Muixf~@frN}&zxAXG{1Lp zsrCcKOz7wEO&xq*iX)aVPM}^06>AqQ+>}t2IGy5Cn=TkjC!P-;o$I!Q3PUVG-F0s$ zi4L6?Ui;3z$Y{bdZlZk9Jm{gf zDfJ8JNoe7_`Xc9`?+x+(%G;It5VQn(U@Y~7{%{;y=|Xp8@!rbSN@Y!;e$eM8@;(c6 z+@!upYKBsM&_d|^$-ILM&7ML$=x*p?;b)T%v+`7}baV;$K#!He z2j7}9%1^o4pq3^b4Ue}Eo>zIQSBUPt+%qoLo2PJ;d)Xd(0y zOTim@Yeiq=81%YI@PjUfjvcMkXQ1WKpR|SV?_qfkM_dw4<_d`d$gL@}Y;IC!lAbXP_Bts4uhx zn*L7YLdQaD8o?cU3fcrM;hpqe=ppD%=vdw(-vgW7aX89p8z+xho;_4IP^y7nNK1Yy6sbx3tF?Ecdl-seGb4E`Zwe! z^vjeB+H??ohaUS1;bSTH*9eF1|1NlCQjVwLLz|9KAEDnvKcIQvryk?T7djSt_BeVg z_q^}51De6tS@uI~en`CW;PVgY5j4y*_?^&G(0$Mnp3fhG?%}!p%g{s6lq|{v9Su$4 znf@eb-cP{+n(?!~$Pwrv=vldcp88|Awn4L?hj=Gp8#Ir17EVC-LsKRo4>}sU{{?Ur z`U~m-JqtYpZTeU25N{bBV^gnsXxeh)nZ&6tGz|LBXfKui9Ueh%FaJpq+( zr)Ny&9-0NM`TxiVdIq`$dKS6|n(}M(1bXTv`VBPvf52}F^8PRQLGyk`|A6lKZ}i|c z;z7%xC1;TXJ@iNVDRj^O(0`zLub|&@56#L(UIcpy-3HwO-4ERhZQ@f~MaBQyib+i5BfS_0jc5{WcH_dt80hoC#5XZ(!!(6i8^&QHbF<_k{&u1x*u8qJqE3To`SYO&q6mt4_(1}uJECUgbzId%}Ar1&^+iX&=P3+ zROCa)LbnAdCv-n_HS`!X3_Szg2~8OliR_1tg&u*{Tp5YH0BwSvmHQy_^03f%)e08M!t<%DKHPeb#dXQ8K{8Pg~SGz*&YcIpq^4_ysC z1`SI%bSLyIbRRT>4U`T+4?#~sPeEUjaA?YO!ZTg38oG_mn?~gm z9~y!lgYqayWv~nGPUs=%VdyD#=6xBOl1aU9r<~AAXwyX67rJc{a)q+@-3!qD(6i8E z(Da$qlQn(zFHkkC^>2ojOhq2_4D`lX)FUqvsfC_mPpg-pP5Icon$_ZT!Jq6tZ%_sp+ zXc&4DdIy>JuL*^#o!Aqf$o5wg&u+KFGtUz zrH!%GFGHpodz)sT8?)q5sfRZQvyLcT>*!$b;rX z4?)YJHDTHp8it;b@E-jB1(XMx1+BRUeSns1#GXK#pgW-{ThXsF!l5B(#x~?Z&upiB za{mGFhK3)a9t$bQ!{`BY+lOcmXvs&IV?fV-ly+ML-k+kMLc^b?9MG|!LH=UWK||29 z&^&0#e(DF^58Vkp1l=5>0Ddqn<^%43F>na(1XzMljL7P z`M-%BfsXw<^cI?-%;CAWN_l$IJvWRRnY!C!_%{+Xn*FxNNtBY2=|ULV73PWkU|)^w zPK5^3=LbhGx+<_Sb&Hz&j+qmtj=foeMeb_OmX}|RgrM#r{4i%H{4J8+IfTEH^AYlU zT6m?wbnlbFR4IcTo_j0HbqPm4e*ez`>IS!*K&H#I@sF=YewPA{SEGdUgXtgiE(nf( z*jE}1?Mj&!%-ZQM3TAH~Q54MII&wkqq{sJMN-!T*Q7~&>Ff=bXdR{PnUXb!g{W7S3 z<+)cQs0$BFgX!Cm6&2CvuMy@2AAuEAq;N z>07D*{d#UL?HA!@htL&LL@JPs=6nbUndrr_{42m|hAH5`LqXdDRf%qX{n{ z{1b#@?sOftdN&G$=!{bGO?oeN9xq{9cD)Xp#BG?cAYuEXVMW2w+kMo1Yf4El+xy{Q z2nP7kB89}^BigEqd@?C-%8DW_Z6vqqF4f1}%MYHC z?%&;X=u9l#YhqB2j6WgcR*~_vD}(NPfig-cM|O%*zaP~Xd6jF^&uE8-eRQHh{j4Nd z={=pOmr0-KMb3dM`y%fWIUJ%FJK=2|(HD7E7+Pog>&4+Xy^#1vh=1eA3yVLN_%9K^ z=ufXkeioHqCVE#!pL^2Px7CD&iMI>6p8&6v?=bjMmJf=)4XS5}u_p(;zDGU5!`}J9 zqu$lfvLKwpo}ua<_OqEj^ZDzf92{c%cECFeFH;zlsFvO$IPHV)ozWM$S@;|h_Yk~v zcsf0{;|}6VpF07+m$vz$L|mwCz&`18Quh}L8v)*HBuv{Iur;=7nQL!EKRbz6NW9si zBO^`SdY`XX10e2z-aBghio_28NE4>&m*NAxY;E-#4M<@v!a z9^Xsev|v6)V1QvR4Ioc!eLDG!V$Ej^{V2uPuWhugFBMx~Dl!+Cw(0aO^9&(UrJRAjyyF| zsYkEvi~N_v`D}51Z?hr;*24u@l8L_IE=t^_dflU)z1!))8k5 z@vj}t99H6g%H+RG;_sAkZhOiiI{62%y;vgG_G-PYMen{rx&@?@Bb)Pt}A&PSRaFf}wSy)1q@nprJhGJYJ`Jng=j!l{`dXH8{ zeVl_H-+zxBLh+F&y1yEklcw;yP$}Evu1u}_FJf2|%OkN*AP3({W~CNKfg&Iie(=Kp^+GLdW34y!~RbbTffHjDiKQt~Pu zoR_u@+7Hxrdr@$=&v&Ocac7qL+z8fP=+_j&nP zrTBV|*JRSYK)QF6?!P1*+T_@AMi-|ah_m(6{=GoPiVT$h>U`EGC7srF{1ZJ^G`K^B z9#it~1O~k7p-pnW#OQL$KeRHk1Wr9UX5FPua zC;)m_*55fV4J=GFqS8*}ahyCdXR^k~wUl|QcPYbqqxQk2d@mAyKjF)wWf-96S}#ha z3{}CCUf%>y@Of`T@U-_%Xb~LmcM@hUI#F^ZcCvtVPRW}?^t2Y<33yKmV{!1b$NL2C zcu_!XRG6^N+5FZ>!i+5ud}+_kG^Uw16bHPe(VK;V4wo-B0^Ep_IPVb zr%8n8JTI__Ytss40q;C+%5;;6x@uj11vxvA^A3^2A$3U)GG~MbT>1#{U!J?{hWAC` zXl%<-oDLeA$;EH_q*gyeAr`jruMKFjdlcv=F|U@b5&!Wp-zLlWl~lLVo}5 zgl+etA6tD3X~4gA>zzf|0pcAd-tE|{f%W!fdE9=W%kw;OPZae<8XcKiy_+b{yucbV zm3p2d{Kk2)dJ1n8lcUk_#z-0t;f3Jk!7CERx?sBS^5AvCnVG?9Q?|D@t$(Ln5Li5jLpGvkN0HZ5?ATo0HcPZU zlrp_QSPNmdac%Hoyx8ueldjNZk_oTqQwo*pB;HS)c=7&TiHw(GCn|&ajln`XDIKMR z(x7eB(2P;@1A4Asj-1qzzR15havmlT;~ed{Gi9labI92`qSsU40$R>HX>7{bUH zaf>lzS(U-i!r2*L`|Cj#yh-r35H3fEvjE+&*UMGK)4^0} zpL*h?%LbrQYq9cWDAPbIzYhN3r5Wsul<6RO)GX?Y zhz*mYh4UD^N_hHv(b&Uy{|f2b{S2&IM|i(6K=I}Uyo+S;FI=wks~QyiJ}Dn6Use>X zyd#*cbv&C1&VHVawnZ_$_LFzap^AEkU1!4Od;?FrK6FX@Z?E!U>~-T0<7`9Tqf7fDKaY;V zG5>YY8eOHYN8EtHim)gkvg8^0q&xZ|)1tBxjpy3WqlJBoMHcE$v2ksqMJ*0wBP-<^ z`d2m2MY)a}SBlMgR3RRXbPlr~wFt$N{PRh(mo&#SO&Vu?K+hTR;GOkG$ET_EU7a}p zqJZGNP4eH=7x@g=atQBHct_wps5ypr0ABvR&NvKT%5fClDR|FFJl#h0`CX!qJDE?> zMvJiBjzUJOJs;;RtK2oP3tf9O>RSAk`<(FtaZ-*DyfD0CkDoxQV{>2RF|I{Fopjo7VN?(|ma;4g&=VcBi}4?_s)N}} zv_3VF>>x7EAmblWxS_u1S(m}D_V`vMR-&SS?uS6?IY1!k##ynWPj6BKm&h+^Xh7p_UDv2<76E{Boz%7cB8 zKO#zwY|az#UVO;$3pKu|tdaTQ&>p4HT z&*SY3KH*swJm^^vJnUh)%TpRW?kQ(M{SFDNPKW`BI{lx#T6VF=k(1XTJ565L>8;ok zCgxFXEen(f^VbIpmuPE%tTxWW$lCdEUt~Q#j=^$K|2c*B=k@$*VQ|aay`N23wD|$w z_fms9-d+~m{r2V1BBEA7o4Bub?v3tdT~B_zBk`YPXZl%9)VE=t;@HA+7682uGl_>4 zZxTxbA(FKrBma{;?-v=`S3~u^O~#L&7f>~@cN0h6!T2AEQz3mM)`ss(dpbCJ{xdl7 zCuD-U-d

~iE^>`}p5tV(O_bnuEY|Sp2cRTA|+Ao$`iMGc3!t{8-M&3C(LfQ@e$0yyd zG&U@7Y-i0!&v`4oxWEaAI^EazBkS}RoOw2~#V#L)H|dLgkp`~i(BnV69q@|#w=sPw zy6$z*!)VrT*$Zz^It8crA5ZR9+^T1!T2O8IL z{XmZuUOYr+fS4C(N7I+l2TJG@M3wRB6lp8}rZ4glNlPa28d3i2VztRUJCCzbqGWE0VZduiv#Z?Q6a2C!fObhAO&X*;Ph9VJ;r>ulnb6Y zA&V|7s(SAu`vnwNx^OuiNpyc3GXDC7S0gN6@nFm>zRJ98FZ?Xts|pLBf__l+&spz_ z`50Qi@dLdHS4RYoGsvk&&U!~qyiM`m5yi4Z){o-xxbY_1fpl~;eMnnp!`lz<=fWX! zVjI3ZSjco+ysdaczJSMaWlMsUrNP?y!TPFTAtLHIw;?n8tJu7#9ntl~fbNp@(fDV# z;>*1waW^gtU`Z2pBGK;`$>YS=oOwL=lQ>_2mwJfz_oVH#ug#inrL5^XOS-e7OS!sF zPkI;j;2V9BJ0!kt4?R}K)=KqQsoP@_L!!5w^1vG4bCv|MNG|X8tv>9`^N`ighpKZG z$Jp8Z#N9{S8Bu)nv+c!#k6!nUJwuTt^v4szfKiuzCGQaKdD59n>h?pH<1cETo*5Zq z@FH#0qC>Fh=aWLLvyt|P$dNwzu;` zyGYN$3W!_w9p2aQkgx6!y5BOfaQbbmKS;m5R`MO(A8_wTz5`h&j`l_VPqYpL`c}-J zE5X(DJtNNv;SK0qcv0ZS`8@L4p6-jRl(MnrGssSvHs99YLY3*}t`~LK?%$cR%lEL? z`#}FFh#Sk9&tg*BG2Th#+Sm?vp1xjpUS1W^V^KZvwh^yI;(?L#tY7-9wpro(zW?r`PioU#x|Ai95J53nkeUpf8g)gKa^`Tu6ZAlPARr2g9^&tjI|Or&^ECsXJ*1i_X>&IMBJZByJ;Ob zZ@YPG5;j|zo(Jzl*0~=tuatZ_q#x{qcNQMgTz$xxdJpFJ8_|@bcj$ zk|XsU#RIIee~hJprTr6mKf5vkzW{!10)7qr`T=|?XB+$$_xCE&jTKWhMA%9Jr4JmJTeGYj6NxVTcz0(klG zmNI6$a`16Cy8HQh&fG_X0mnGouhhLe1e*}K*0KSy#6#RPlV`Ak>!S;%& z(CvAa@XmjV)sH0FCXAxuq+- zfiC+Q!n0q9l||&7gEt9Yyqr>z154*Czi&95 zfPW+W7ZdRF;J-Y8FZxgp{~Y{XBG}-!)otGv!rFcjtAoVf46g;=dt>p#Zv00HI}sOO za5w<(_yFEfc*o$yx8o^zC*eICldJViZVNci629e^eUT;7KlGT)m=%2oPWzmNz5qR@ z-^9L5Tnjzc=1pXs=CpZ_#f*=O#OE_})4Onzc&CPiOqt$k{c9qA<-g*KhyV_$OE0{= z@TA@3$mf*bi#!2ufsdQS<;wPT;rKA8jy3#ZR()caGAGyHv~sBi8t=4F6&q_==_hE-z(+MhqpP7R|Bsc-VS*4 zobt!72gRQAN7p?1g0)M6_3sYWvi{VATQK`IyW?H9&%H8aQniqov|^tHqG>vcP!2jnyx{e&f6&qJ5=Bj{k3-UJ8t5#A^}x#2Y_?8|^2>=JK(%UuT`Q(sx}7fH3tL z;NC9Oe$pXi9sMouJxLuoq&<(rJMlYy(?>T-`#=Tl1e)^*5TAz2b`()bm(>&rHCGHav7pxy< z>BXG~(_q{EW)8h|;KX4!(K|_-_s71-tf;>n(}P$aan>v=y+2A=okamzOC9`*R7Jr1 ze8L1vd19D9c(z1&#O|bIWB>oevnHo)`@fHjJzNN|&a9qRr+1*$=#r!@B(400Y#-Ng z>vX2yNc+3*oJ7}_ikM>=JG_~+kCIl8SF9%tn)@?Z^xofpawMsLKvvRc<@adkNdIxk zn|A2Grfud{tmtO3P{M;yQ*5!fXGvH8DrUOs=Qt+&&Z*j2-oA1?n~%` zp3^(;=TQAcJVJBqyzV&#Xyc=F|~nJj(Czj&nVr&$olTG2&XoO*vj7em=j~`>yYvb}PLhD=hn*M{Y#_<5@@=15Qq~nl0kHTw$S0@bZbLe?EYlq%q{rU)v znnloy#M?_e8UN$TrpN5HuEioqWM)jo&m`{RXk2YeiQ5&eM?GN$#Cx82^-jO}pu86w z|BkrEZoaJXi=FxjT@%YNz@#q@+?%k=@|2~JJob^tsSy$V{%HR;*6S&bspWw#4ZcXb z9SZ}C^)jx!`GTauu587Yhd9%V>9ouY^OyWBKhVkID6s&i^y;vIp?a!7G4wwG&Tl`KalX2j1Pnqs)Ww(CyEAef`?H zM6U&wk#;9(DB_BH-_BpA#4!2LkrIq|0k*wVwuI)|*i{B}2gBsbdbpT`e5 z>hb-XhX?(Od8)A%TEv5Y?^l3?mrDjf!Vsk-Y7J2<-KalI*xHK&-d*Ygjdtf6=Ddr;8@%HHq!-rryr%-es90^S#bS?lz}cu@;uFBrRJ zCf7^SSCErBCKCB})XyAp>_Z29A4Qs`F>PiXruV|`IsQ+=g(M*sJ1K(c)yAYFj&E&BT`>+ z0Yu(Q$U8SK5*e4mjqand`s(M2x{o@(XQA&qiR)|T!J^{@Ga3ITus<8uatN;y-Whm* zsX6BPp8OuWeqto@p{UOr%QyDkmoqOcg_!LH1qX4qH0kTz~36pH~?f-KxUr*&cYwyH|5=uR?B6A zj|PdMm$9ah@G#+Dbi(7FeLw0>F(qCL@m?X`ZzP^BLv%d&jyoO*e!Gcx?6yecCW*(f znR7q9lkoOQp>(?q=&LbXB|p#lA5XA$X|R4?u%#&2SrY7(-&L)EzaepZ@+wq^%r+6i z0|``##xcIK`>xSgoTiug{re&*5QmI!`S2$38~7u_;3u*28(HU>|AV>%qQ<39KcoAr z{I32earN^l%D+q2Ci<_p)cbzt3AQW=c2-HL>v?k4&xpMzAnkYnIc0Ou-~M9&?YKQf zKTDxM$QWRB-_$`K2-TAIMbZ}V8~v*OY5V)z-zKr?OOz5VSd5cT4=!xh=lMi1siBFn^%=)O$X)Bct3DRkEHQp|I%PU4138OI!(Gic629ej_=5D;IB(g3R$ z{W$U-qV(yb$UDUz0blQ5FO7-zrRgxfD@0!W$cX7(4vUcoEi^zm^SSgn)MqijiFa&H zKim2nD#H>A$Y9*~)t6&vWq_)uEajvIzH&jE>XaE9PYmtnogvM><*_0^1RIk;mGCyg5al3(xakmjzc}y+qoqcSp=RhoqICs4#h0 zpbKmSd6#grScY`-o||AK`)O=>PbBg+u9f$1G!}wK0sO2w_JI)ovS9jVNF}@)cs&Wm z*a2f5b3)%~bS}ZdXNgoO!6;Z7@J13Q(CfN4lK)A`zmYvhq)gzw)4PhQlm)sOuf&GF zO!ywciyZsotX=8fXy`c)Kke};UoeZGPeogUbb`aAdHA1e*@uE_<>hUL)#ms4CGacP zMa**`ohSCsT^p43aC8oJUJ&T!nq*v;1=hLN!|3=9WQ=NwMBjH1eD}gjh4+}`$021n z2yYL(8euqVhN5T3;lBX?XC7`a0Xr!lWuRVLQ+yM}E|}$ziopE10#yXFc>ca#n^x?I zDVxS=bTRXT^{gw1Jn9s0r*V1pZ(>lDEHYp)GbWU2p=u(!?2EGdu1I9QgK^^bd>wzM z(yXaq_6K;<*y#Pn5MraSRngYahb@(M}5wd z!R1yHr_+s-<UwPCMo(wMEZ{n2eI7OamWoy3b_k7*s|B&DJ6VKmzx%o(n z|53m1Ybh06pZ5EIIYRxx@BiTl^~8t_uK#Os2fL4|&zbBLZ6F z@ogT@y>)(m@4eptsS#?2ha^vW{LhW>9rO5)jbOs$|4)zSpx6J?5x#GE{U=BG{>khA zh1c_8pa0)R_&(|Lzc9jg#OMFfNYBeY|0^SW|Ksz&IKubw6#pkvJikrxe{H1i70Ni$ z_n3boah~)0Py0PvQvL5wReMsM(zSg^@LuSd)97cbf_DE-pV}$K_>RYa$me^`CcWGLm{+ycESE}?=ujh|mf1g+F^0_JTuOE?ekam^-QLk#2M%^lD4|)9G_WCHz7refod;F)o zoltA&(|^FD&0^&7$)1}(>G7ZNqIdppdDZu&wEyY3_2*vCt6u+K z_|zj#F0{Wc-+qthQO_Db*Bks>0_q`&{}h-6d?!5q&jx(I_V`bZ^6c~azZdX*$?N}0 z!1t`T9?nB4{$B-rA5HOpW0db$ivO1Z-@obWzZl{FZNRr{g#S0hACX4re~<9L8u0av z@c$v;+dHxc&XcMBzamwtf9ojUzokCyf%QLWcBN#CI^M79cS{>g z^GvMu@A6XHSERN?`Mk&fNw4qQ9{*v`7sm5mKfk|u$?4ViXX$i%J)Rw&TtYYhKJ}#x z&%reRC$9E=E6xA0t9}2J=7;lf9C3uf7G0>1toOXRsN4; z_#VB=|3HTC8&?VE`&aqDoZ&y6{#7qGzrWi5KUe!sX88Xx!}pVG{Qq*T`o%T==dM++ zT;tz=o!WKn?3b<$JaV1?qt~ggT}K(DKA!uilk(iJc6?B`@wIaZ_@YPJhJO58ulk9H zM%DdrrKe(*|A7>A=VhPKyU)_oQ+(g@_f>GX^c8@$4G2zMj zzk9QGi&VWsla-H^YZ0&rSOhEr76FTZMZh9p5wHkY1S|p;0gHe|z#?D~un1TLECLn* zi-1MIB481)2v`Ix0u}*_fJML}U=gqgSOhEr76FTZMZh9p5wHkY1S|p;0gHe|z#?D~ zun1TLECLn*i-1MIB481)2v`Ix0&flk3YD5OyMR6LMsvO+R;B_rX)Aa;r)=QHA=}^; zT&piHi+?qgwTLl9`K@Z4s~tTnqy9*zIzLnyzHGk~^_+tKw|=#mKqPxO{eCSdZ*DX;sd3 z1-7jM+g2SNcT%{4%FY2g9eznM#4N3Lk8siZy(^g@~%ir##?yIUJ%KD=BO3Wm4WZ3#QV^ z#-nrN2jDgizv&iy4cWswi|{NbJPW&%C49%PVjD)4g-&MSi@g<(@l+}iK2q25alV*G zmG`q(JNGBq zfGxHOTMcSeLtm+(ugKi*jUL(eYga?IuzjPVY(x?y1bS4 zUz6=Z?EY&Pub?IDzb1QXEMuR8W$bex*LSjq$SP;Qm5Y~nVJRfvi{4=A!bICx7Jv&xUy>4)t8!Gf zlC6^NWNV>SN#0&4^L&MQ9bws|k^P@0sflWWx~lQa&vn^(!cQ4`p&YGT~pR z96@-Oa{tHG`LxL*4A(q}B6J4_VEnXaqIZkxho3C7zs3odYx%;3lg|}4q zkMw?ZZ6wH;BwKlH2iQ)|xuS_j8`fxO1>DIVBde0U&xqY$akyL1%CiW( zaRl7`72mj|KaYgB%KnOf9`xRLuGu1jvBd7LXt1>VE531^I-dlsZ%%|NhuZxWV~8#1 z((bPq!{cJF?EZ=uiS8|%82H&)Xb&eYLj;tACZ&Nq!h0yf(nf(<{JNqnNNE#c* zB481)2v`Ix0u}*_fJML}U=gqgSOhEr76FTZMZh9p5wHkY1S|p;0gHe|z#?D~un1TL zECLn*i-1MIB481)2v`Ix0u}*_fJML}U=gqgSOhEr76FTZMZh9p5wHkY1S|p;0gHe| zz#?D~un1TLE@K2dYR>Eer3yxKz9UwT0)EF{!0*`$_+7gkZ{sW&hTpYoVVB^a{06^> zIu!|}4n@?Zh&mNHb>vnRu@_;{O_!iBNzB6Tub4z|t!RtDWrBdazv9)D_fBlyswCU$ zvBQkZTV;Pmh8T4xFBUNq-`!tv9R7pdUvV&oc7Mgem|P6U?yq<;XkB>R%XNRn zfi*03_FLSyCO9xi-*@gX`ywU`Ou)SH-DdyBF%F&L(0LAB?$GrPeXm15?9eYc^l68l za_CDAebu2?zsKa0<i#K5{^=pgfBI8zto+}rKY#fvKX2skc4*<}E-t@wxki4dDKY+?2aUY+0~aUP z#p}+7^Oyhh*Dg+O=-W`HB;rxB z$7{+>AM>3%XZCl!(}_Ra`@8PD%i!DT&;iA=w-y15fJML}U=gqgSOhEr76FTZMZh9p z5wHkY1S|p;0gHe|z#?D~un1TLECLn*i-1MIB481)2v`Ix0u}*_fJML}U=gqgSOhEr z76FTZMZh9p5wHkY1S|p;0gHe|z#?D~un1TLECLn*i-1MIBJfs2Abnm@;asKWvLD^t zxcyz{vhUVhHbI@so^Nuefo#q+Mro?e04~ zFy3(8m#ph(6lmpzY@c}Tue$5z_3l{WNoJ)1Jfe#^-`BwwjxE4tE( zuE=f~v#EEo_jHzgrH<=q)Ae90`#;U5?y}!>GLKU7l{&5m*Y(s>_Jf-Z-tl`}CnJB! zSL(Q)`mHCwk&-W%7dZAO8F`9K$ye&Qo_yBRzOsMiY-mA}?SkYhbsVmvNZqW)sL*hU zyX11_sZ2Fi-J-4_=N5E+7H2Y#yM|eKF(c%7HEx)tUOI6lYNDE;ZoPCF4s%YWYKof7 zF1%^TZNXm7O7eKrrbpc2tHgYjqq5a)!zb_(OIo1v)KrywiE|yk?8=na7vc^t*KJr)ZO-@Q(_g>!%1i_VQKgdoL?> zJ?WpqXF8fBzsc-Ur_>FS55C&bB>ROjO?--fN97_3hg+W{h`uaD%6`es_;^25$JMjy zIrS`h^(=aI9G!X&`W*W9EIM`^{&C@R{VZW8(6=9;Z(~XSEV_0)$@(T9-LvT0@g(b; ze3#%^bnUp+H;@?q19ei(=+95pN%bT3WA!8S>PP6+Nq9eo{+I|qLdQ5CRyL|Bp-C`q}4Z&82&@_r5PQX?#cG#cyc{C43Ih3 zDV5EKW^$pqM98^@d-&PH=Q@Y5yx(4>ru~+5q|bR5e9mMX?)Z~0`Mi^SIFotIkbD@t zvtW5 zVs0u)Q;Ge1D;}GvR6IVLsq1FyDmZPX@|&Y}-K)w|^fH2mVKX@0%a!1GFY)e`d%+c) z?*+%+P4}t$xWAA4`?!}wCIPZ$EbEH0#wTl9GB1<4jXZa_m_xedy_E6ZB)5y%%~{GV zE1*KDl%^(Qud}x3)lY&XJlhG+*R)#ySE|}cUo4g9C>~+tRi_(y)#*lF@wMi@_*!!x zFws;X)m#KpO?V*H4G(E~fz&LAn*0N)CjWqmt^(;!dMCetlV2d+NuO@g`&IqTB1qPp zt~BzhD~-J3<>tP4xw#LN znfQS+6F*R9!UJV)c)gY%C^Pv7%1r)&GLwIx(n(+Gq<8WQIQa!Co%EF^y%zQ+_?I15 zhWXBQNxD)c^ruqv-W;iVUd=z$G_{|phbNCoF6t;neyPZJ`YR$vq^51z5-((8)E>lh zm13Ay?WCQ?c`1$sWKvR~ROS%n5s2EU$Fyi&l3Oa#u9AHG6zt&TaNt_0cG`Oyr#&tl z0r3gsXhOlZsqO0h>Mzw6Fx-OPKLGE6(Gr@j`=wmT5$m5<&_~ny^-~F_^YW+v`4aWp z2ax}O$dBss`TONW%J2YVvK(*Y>>%y*OVlrSs1K+u(l3YT2U3g<>M=c97b#`(jtA94 zY76}`)4^k4PE0LS2kkap48|omcB)-!OWx3SOJM1sy{9L+UyAq++GzR^?Q{vC7}hLu z*gY!}xUn7%) z(l51rx)eFSwesLIE~=CEo*^B_9v6(j)VP>?)JN4v)W_6rFx-vaKSIBJBnji?BglV5 zX(nIkE`AE%PCPC6$coXW28LPBR^V~{^7%Y z_n3NI?Pk23GK8JDS;|9M^M@$!aF=JV`h?n@M|p-Ar*4t*(BAn;?w7LMcsFIpAEF$? zUGHSe15$l7)6VIx~RwP(YhpvG>oh-sxPU1^h>WiP)=}6g4ad6 z-F}Jso>ND0e&XegG?+MWl zLQGV~po?R4`w#E@at!jvh%i6j_xmU@RVV*9Dj1j5bKg6=goW^R!7v6 z>YM7@>Rajv^*us8kI;rksMry7_{raU)RWnYcY3*}&PS3|&q0f14ruR5{C&-oWPe|C z_Xe}1SMSg_a~s;SSp+Ns76FTZMZh9p5wHkY1S|p;0gHe|z#?D~un1TLECLn*i-1MI zB481)2v`Ix0u}*_fJML}U=gqgSOhEr76FTZMZh9p5wHkY1S|p;0gHe|z#?D~un1TL zECLn*i-1MIB481)2v`Ix0u}*_z%U?SzprV(uQ?2Alxz|9`g8fL$* z*&kK=ea-%OTs`y!!U^L>%ZO@Qzs@ z>Sg0(4%u(Dp1RdvMs?B!AMo$b@qH05WoQMeUXt;e(d@z&SW0l!z?@-c}?idGwP^%N_|&7 z#W?X4bvO#|yU_3Ea!;Eag@07|Tt7wFv6rt>-+NgpX|AX61&$`kACP`2hrs$2e#gi9duEMD80;g)$h$&>FxG@(mBRL9k`>N)i+*U!?p$I+?hpwFRi z&!SYv;U5=1*Uu7m0)6`d`XsB5X0GeR@Q4FAbyz~O^gd~ zrtd>!rkipN{4eZw#_4ICm*R+i9|9YY=y)5vudr8$CdSJrLDp--y(-EnDIvWybZpiTJD!IDYGuMCu@HdR%yXy5YXwp+2Ct6eu-u z2!A#x<)I$aqjeeX67-knejh@)bS< z_g{6c4}#%A^!_W+F(Oqz#)WzLM;tE7|QnneKm*V&unH-dUImEm< zjqpzT^B&d(=nON7TpEZmxHu z_m9voAJKL>o$fb$IC>bOa(9z9{}S~}_xli;L-d0& zQXcA&AFa#9pnvgkA5)L3-So@MA?(D(OH6Kxn-PCEZJ8g}p2^7ZU6K!alK&PNF9o9u z`98$e#4AS^mRu(KAoX&OCdzzR9Z^rJZ>n#rZ>b~np(FIOBedZW?9LJF&y&CRs3)_P zl4d=E4joBSJqJ1cZXpNIEwS%Iq{n?9!h7yqA2B29PA7g1Wv#(R)lesSXXA|?*&Uc* zIb3S)?0<`ZMZh9p5wHkY1S|p;0gHe|z#?D~un1TLECLn*i-1MIB481)2v`Ix0u}*_ zfJML}U=gqgSOhEr76FTZMZh9p5wHkY1S|p;0gHe|z#?D~un1TLECLn*i-1MIB481) z2v`Ix0u}*_fJML}U=et$B9K0J&g_E0m6QGGWiR{!XCDXoNqfOC{H}d)PRZdozn&i~ z+|#1>6_>raWq)hgBf5pX2U?u{K4kxjmL%;tFt{*poFjV;6jA;np|n*I^(vxX@kbGL zE4qy86km4tdOdYpPu-+lS8`qJ=%pJz+*H2PATrm3<$AD{4dGUje=TP+56M^RxSlp$ z&n6hM`P@p%P&=Sahr0}tuhelpy0RW!k^M1NQtw*MWFGGKFjmo?tH4(F&0k5~YdMp7 zlu}=*<0^1nMIB|o`<38bD;tj_@sNC_j;pBOD)N$j>Q{n!tz&ounqJ z3GDtifpKU8AnaDY_ptkArMOfR7&C_2xAKiv#NC%m z+?@%GRmt9uQub4uz&JeA{J#cQ^y)G6>Twk56VOkf zZ;#Q~kHddl_*_3m*vHYgN6|NNPafmn<4N*UTzv~kKIq%yN%q5J-@?bxx5ty@XS($v zoBx%E__gEFxAExEcrhZ*F%JDHM8C4Q&mugF@GQc!XooD?Jd1GARr$V1mc&CJ--^e0 zDix2TxcIoH+nvubocb_~5=dMwU`UCB3;s_DPg z^xx{Jo%H!fj7*L8`SVGVeevZRyURH*#c>CjROhqbZ<71}rKroFBM+Kde;0YVT-f7+ z5pcgRA_>a*^3M{rKvjTY1$w`fKD1QpqwJR+JGfyOdHvrPS&ICnB0ttI2Yp{8*BOH) z*Idf5)VY`MNXYlDmtUfOvPdmf6$L}@!!6%Ck#BG>?`OxP)X6!@)IwE}PkG|-iO)%3 zxgUJx8*7*1=vA9kMIPme`c?gNmG7^}cgmMX+q!@FaNWuG5?0{DEl<+CW4OwBp>lHL zB9=JUrL=izKRp}1@lvuVMQ2Lsm!;9R8vGrD+#%XozAqx*onJmgxKo8;BgIl)=?9l6 zzhNu*n?#T}K`YRwVe=5>NKURv zmP$XlO-)u)$YwGPJDE103~w@RI|VAo+c+oFKc-x!<3^_ntGiVfwdhu1bREdo=8#b`y!wBoI4kxgvtB9$iYrCW!d6T zGP8$8z#?D~un1TLECLn*i-1MIB481)2v`Ix0u}*_fJML}U=gqgSOhEr76FTZMZh9p z5wHkY1S|p;0gHe|z#?D~un1TLECLn*i-1MIB481)2v`Ix0u}*_fJML}U=gqgSOhEr z76FTZMZh9p5wHlnl@UmvS5!Dxsk!|Aes0`e3Um2w{#^DQnCt92AV0&Odx`eE7!J7m zZTJ;0(6d7CvnG4v$-Yjq_m%9&C40%pA^VTYK0uetA>S9Nr~LIoX{&nbRZqR@owk(y z#_FkC{bf|AMA)}dw^r&V?K+!l_q#WV;tmJT{k}*mShj+#>^nM}{N28U0=G9u)e?^>gOCT(_M-ZS74k=Dnx!w7&EV`F4e7G zR^3?VyYZaq!o8PaUq;iq@vQ5@{VutW>u!X72j>mEaz-i9{p!Y=)#cK<<>*3*&RaLu z&xkivkLpz?RWHU>FUD05#?(pJlNfKk7-K!S z-y`>N-HWi-Fy3Crcw2__y%=jfE{``6dGEzo>v4I!$uR)E7;8NoZy*tWC;KYVE*3pT z(Lij&m}-K*72~H3eH%o05dI*-g9s0zAA)ip;WAdG`$hXbi19cXT{{{T&PQ}K9c|Bc zG`>AF&%CN8sqcIX(Rpk|TH)A=c&*|WuHe`Tj&~hsQ*H3K!QTeIIC)o;_cqzv%RXE7 zjIwVLtz~&H9*GlO%U0C2)#ZM<@XohrTq6A-?|pP*N1!mQ=uPIj8uO_d^Qlj>JGx#s z=9>IeF(Nk{z3yn|n8|rF`%t%Hd=lX{qmb${rE)^+Q~y%2G^l-8cZ$v0(?2x+zAebI zx>Tu4u?|iIC+9Zp!+0vjhi>=;obxT3Fu?9r_d^Z(0o4J99T@iqaqpmh9>rI$`ylc^ zDEWuR@<1K^@N@sdl>tkr-F$}olp}vjZ^YRB$T69hdVNYn ziIb}gIlrp~{k>Ku4&AT`gr9HmsQMI6(EYSJ1crw&?hj*L9(Lh*c^LU0mi+tX<$&{` zR);+gM7#g6@dwbd+mW_3LG$u)^@KWvdAT~YM)gO#Sn7jzl!n^UKRn*P&*0qILwH`U zjNPuKIrdKm*=INLwh^wP#UEk@osk_@@vAF z+KyA&wxO^ZjQ<++c?~$$VC-)*JY^WvV18_i@}8B5dXA=y=T)aVp$7Chgg|A>g~8?Me(>|7>pD9^X(-*-IU zqCby#`*^-ZY@+Q5=J^)U8S#9J=xi9`9sx*hh8)kg2%!jF@O+C9iu1bQ`4;DeO`mxs zDS5ud;QV;L#o%0=yFA~*ArW6&6qemH=9=eQ^g-eI7JV$v=ZfcBoDVgnc)mq!Zam*2 zHXojE5u49wLV3Q$_&eX?xO2XRI+t{=LaB2&ZX#*nqv_817EXWf#916WaSq8&oY}E6 z4rk2-?y}Fd2p-`177k-t5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq z5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH* znA8Nk8`f9i@7gP}@tN1x(hB??dj<2xcAZ%QzM}ore21!2b!bx^ z+E#}))}c*xXnWm7cBSUS)GbUv1>;nNXbm)?{*7YMu12)05$$R;eJOgYjc8lr1ZvY@ zXvX4v3(*>F2Fqr!mFse_EyKr6C+AG~P(U;Kv>AOU*X5`~89r{h4Jg;qR&}!+=1l^l zA+TO8QHxbTiEjHItat0o^Jz4B#!7ojtibaK+n{pPGPP7CBkdlnCF@*XPvU((M3u@@ zxoWvek@{mzTIce*blZ6_j+MkYUnEuPk9B<=K5n`@XkD}Nq2Q)FVN-Ee!w|TL9ljX-_d3ERdL1; z%5JulgXd&d*xof17>5g|J#oltLS`Z7Lo{J5y`g$kuR5uEaovl~?ZKEj340Rbtrvr; z2lspAKCXKa_8P|9>lkm+{k<4#JuZ(o$-Wnb^|(CV7Dzc5YdsuqAQ68Tc|L@c(1d4v zD>}FheH(;72!9Y`EQqldL_Y-OKEh?JijH;=<1mQvI2m0#8kMN?A>zqTx}z2S(&}=* zIPWlCB_m1R+b~$PwF~xQ?`Zq;j4d>_RNGqptyHZ^UnLtIxT+L8zuHVYzuHVYzp5*u99g3hU8$Iv*m(jHgI4a(f@v&|-WN;X>y_U=0||O~=iBSkH^`Nrc;i zLaH(4a_niDh$2T-hIG?DbXswg{v1{2lQ^;L3B(P3K7=1jXc|80$@uLUj}bq%{%QE6 z4|oMYpnlBY%ZIq~6J0-d5PftI9diqC$8m4t=s z0GGa;^C1eN>}NBiK4?cts4Xs4#AN%hdPH?#UKUJ{c_}*d`_bPeF3-y;QV#m4BuYQI z+bi+Uy~t$QgmM3jxgO8wL!_aOEtr#Q6ErWK^C1eNyf>#yeK052CTLzhhw_feyfo{S z>9TQaEa8JWxz^=*Ic@>4VkAHUlZwD_&WD(Z7T4gJu`SATV>|oLA|72 zRGoOXb>ex`i9Jsz_Jf^xcRcZ~N1Z5CO143rSlc^YYUhAWe-vcRM6eZaAao=^0wh2JBtQZrKmsH{0wh2JBtQZrKmsH{0wh2JBtQZrKmsH{ z0wh2JBtQZrKmsH{0wh2JBtQZrKmsH{0wh2JBtQZrKmsH{0wh2JBtQZrKmsH{0wh2J zlb^sa&xa6Mw~2H<#8BrZi0tEJI5#1hIzYz|=U~Wr9~0>uj0^32h{?b3u!STrastlz z3L?rl5zmKk&Q}oqnTdElgmb=vKHmcRJrnJG2uKT!>U;%}2Ta8I3L^WLi1QUhPm1R& z0D?)rQd zj^`d8dwqKMk-GNq%VSZ#&Rg$3eB8;I6pr4#JX^;??>=0AU)pw$*+*!db?gTct#_Ye z_8?Lhara=)G9H~ip8);mw%)z$yQp{HHv%w62b?p}7dr6j8`$q2M?W3M{`PoiZ26K? zQvHHvCzBE3ESU?S5n@S#zgNvN`1oXHXg3^`2^^1>fMjLH-@9DE$0(m2)f#G z>`EeawVx`|TMKo)x<2U~&Y?etg)V8~qrS6er5|0?&o;W*jcxMQPe%eIKmsH{0wh2J zBtQZrKmsH{0wh2JBtQZrKmsH{0wh2JBtQZrKmsH{0wh2JBtQZrKmsH{0wh2JBtQZr zKmsH{0wh2JBtQZrKmsH{0wh2JBtQZrKmsH%=?Qo%t|%`X*vc|!a+E=vqYRo2;zSRs zY=US_NPVOI)%;Mp(jrANk#wa+Cwx6b5!Q=EU#&-WVG3gS^6qftS(iTj9K}kEx1}0sWqx_wAqYVdR=ooOIE4^ zm9HvQKAxTVSl`=h zcm_n%=ZqIX(G$$avn5>rFkX2}K2Ce$ndd~xOLXCKG2U`9hH}I9Wy>*sf*4Vhwo`=53L%-)CT(mL~r1B&l#^YpkxoA{4pIo%nak=1-8=7ZYhbyEFm+-TteiV(>?M&5oKPRzNL=b}i;_ZD^hJrTEi3I>OVG+QUEm zmcEvAAR3Ui9-lrhB7rdVm%dXnEWVMc)0=jZp6IY zh=NPq-LfCNZ@1W14cNPq-LfCNZ@1W14c zNPq-LfCNZ@1W14cNPq-LfCNZ@1W14cNPq-LfCNZ@1W14cNPq-LfCNZ@1W14cNPq-L zfCNZ@1W14cNPq+qN5H#bePzYK;wqpaPyu~}3Zsv(08uLXX_*X6GoJ2(c^d1Nx7oQ)QmaNjKLv#DCKCk z+nWDXDA&z)G4IJmV1vq0%b;IrSYA~k>VI3D>;Ia1L%ohXdoTfB!#e%i z8BubJpDQ$3y=80<#%Iq6=9mnJlZf9tf;8t-dtDCd*6Z^8IiI>Q&F~4dBWgRwN;~?o z9i7^aaosMHQ|@Cg(jMBMYaOnT{&zd}My-g`ittv%YZX88X+=J*$mgyDZK@6aHu&4% zZ$rMaSC&1U>>*`eC7D_Hhz7psdCM6`GHj(JnN^}?7EK3xKEhg&XRE0zyskJ~eN5^k zJ5aGwL$P+jL+O8eRi%l)#n_;>Bh_gG2c0k)51lE$CJli?(~>5P@lEEs8bhxd^QlkM zG`gNC=GurKOoQl|4$%LWGZF@KGI#f(ZpHW{!fi$&)nzz01AGQ^K&AGfuEkO6J6M|0 z+>_Z|T?+lm1hs!Ob(OTDL%9!-iUkziun9Q&-%VKl?^XA!`_u!f0}MOR?*}m!59-H4 zeD%K%BL9Pue`qWZ)a92mN*pI==N!Z{S)4pu_akjdg2v^8>LJx3^Dzs>NJ=GI`(x-GP?b+`3@aP(_E=N6wk=TqnKpiEl$xaaIy(XKtGu2t9R z3hYGvcA}m;(FXbLe6;S&o%S!&UB-?!Kc*)E5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq z5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH* zAOR8}0TLhq5+DH*80Q2sH)#FZ3jD2oMVOXAq<*dZx&1`auZ^bbsyub74u7j(hriXY z!{6%H;cxZp(Dpi`w~>c-P9$B|p>%phKV&lK^g8;r(yxiquSHQI{aVoxON4%{=;lfr z9sODnfl7pat&}Tmbo6UQ-z*XOwNkFMaWCfNUd&0+M=QsCEW^i5w-Mz^8~0)j*o!ql zbnVKq{*{HTfo_y9*(($99*0Vbo6)QlwHEJarAdZdovOG z$G2+L&-gWSlUkz+)y474Fu^%(R+p+vR8fLUjbCwFl-J|&#JN-BSG^%~+NzR0Ngkgk zapV6FBJ>qEca`#cQavdi(QliG`q?$g@}zsxqP||m4U|h66(Zjz>@#0gU8-BXth%ue z>&E`C3-?}zeHl}`8+*bo-0zb6xb8;Scg{>xubfe8F4A{n&(!78zRA%Q7JcMy?A5wl z-WSStw;NwwF711r_Mn&x(uv;aO?bC?L-nX$byD?WT=imHi7xy}*pnDD$6K+KgRyqX z&%~?hbvmzVGaQXc@UiFpp&RWplYh~il4V%CvVKE<7pHh#hPpd;< zcnIVEFy`f9Js!{d{H#Hrmxq!6VaY!Cd}`-FL3E|&VB9i^eR*x_z{e@1;)9m2d^9kEV)!tjxo!`o5U(un%HRi7u- z=hUG~QJ;wY#3zh@sniGkUF!0@l%E@KN13G&^>C}*Zs!Z6+TDbH{(}0F`l9-Cbp#BL zVB9~2zJ1DtdHEFbe@gNXjpc#!(i`@>u7%C(Q)b-dqqcV-?PUp?mtR(2QAaQ@z4D?I z=AJh5vHz&r@xMP)I@;$q$Z z@qJz{M*fQ>fB6wdyMgo43WebeXNha}ZSsF+-HADQd4lF;o@a$8P>wo8%*!Qa-6)j$ zU`}41pm~|^Dewd?LwzFV71`AdiRMrA2Gf?Xk`q0-CTMY;@A+^d7nz9j z;Y1cJ5$D5+%pT8&0|b|xysw0x4y2T07(cO&ls-bV46J@^*N#HR# zKPlSz6oWAv%X`vI`_O5{QTlT%>o%Utmi?=^q0dk9A?|sdpOh0e?+UO^C8@%%e+b8{0Q)Th>>x- zb!5?pjLq{QhD6ja0?&u&ha>JDo(~asr2R7F`4IhZD4q||pGUlXJRc%9(RKufpP$hV zz4dmZrOfjojBqy?d6kSLvG$9iSJ{xfDq!yC8Cz&cu^4sB--w6-s{CGZu#xQBV>`}z?A)<9C&xeRcW_b5` zKE&`iMaJU!5RpXs`yW&fsg5$7$H4O;`hyv!kLN=S6I4XBBID=z5D{RE_gUCuGB4%e z!$BO+hZqD(*e#w95e9>oBtQZao&e8>Q0m0H9(4jQ+vDYYh~mM|hnRNutPHnvp)t1; zKLhQ=OWaPJv$iwJ8Hu6D!?&cbcA?J$xs3JH(^36KB@kN^pg011!)36KB@ zkN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg z011!)36KB@kN^pg011!)36Q`>cmE8_5X?TJDqe}mr$NybL8_}lzO{B3?C z{x-kS=wONLV_*#;p3*eEzX%2BEKdue^qs`%JzansF|aSOgYXA2u!89HAo?LF_Yp4IwsRyL<1mQvI2m0#8Wqk*^zI!O zsdukbO=vi^gHtOa3ddIPY8Ah51;~XEWq?vT9r+kz{?RyKo5hCwya8I^qBXS#&|3=B*%vWTQ;!p4B2+yP-%6!W}qT28$KHds~oIb!l{+@A#DzpPbOuY9GFe<$`Y51ctA7-UZDC;UN0xAm-J<&{!U1USgeaT#m#y^Fp4j`;oRJLG#kl zyU&Rz?;f*Xm*@O`w4)@{7N^$k*oW04ssr;fC!)N2qO2S4)MEI#PDRxH=)V$|=cVks z_G8SHgpHfw*K+*DEHYJ^D0=s@|82n>SsO7=+#>7f-RFe%4*g4#_oNogk+l)?q<^gV z`JO{o$K-h#r9Sa1DLy&LyGje@%rg89ei^hi%8Xuv=nIrh5UmMmO|-w7?-)W?TI4$>lCHGq zgs+Dv!g{gjtM%x!_0otiw;oyw>s``I2rI_b%WKfKYtT07*K5(9-T1iasz0#5Swy9- z0n2N^R<5rF!`&`(lyXIQZl`IVTwe(Ve zs#smBE*UD?xDBsXMbPyv9Jlows$#n4c$TcxI^dNmAJ5KwtnUSQwp7Aa7Qv4-UvxS} zTdM%q`3PG9{p`v!N{PN)KAr&uEbP8R$PLXiE%7O`i`wOa({fx1$K__Pv>Y6l1K4tKT$W=Zx@1t4T8_Fd zce!75t5MeZ>SvF%`N`^t3`y!|j}+V_i(eSlo~y&I`(N7n+5PXGzpoaPsuuINHndI- z)afmii8qLog`ojy>+wm1yAFlamMT>mwq7No+{sdg=qfj$FYBZ9=VWPTyxZaEXG^{{ zP`2NuHmeQwLYbJA(kR&|xyQKnQ;l>Myi#~Q$?K0)(#i@H+nz&cTsp!Pc) z&ew`gZv*>FHLN%}S78;#=IRMLJ_Bl(TCA3!6-(7F ztlhiN&RtkrccHDjuvRR7*P|8}DkbNo?LwP(xztX#e(zbY)~U(&eNLTA z57YmC;Oy_tp(5whwWc~d!E`6a(@wCLf0G-nYy7aig)206wD~bT36KB@kN^pg011!) z36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@ zkN^pg011!)36KB@kN^pg011!)36KB@kia-6khEcaWrb1|&-?3NV@7XJi zK7z;vRK(%$+7m^ip8!%=p+o6^i)`RT)BkQn-!-Cd8qrsc=(9%jU8Cts(Y0uV7DS^< zdJkb}UA=5Z+nUif>DO{xJG%646)HO1l6Ny$HiNAQWR;_Q(ZqMtNx9O-X7p(@`cU-0 z%TWi><9E|Jdgsj;E6o@yqT^AHcDt?l@93So*|zbR_g?hxUi7c%qm_es89r{hjTl#= zxi!(<29=|hLE}br%JyI#Sci|B?v^-bUIoS9T&-Li=Zq7SUA5NDUXh^E;$O^0s6efP z`u9Y2o3#4+#S^vqTGRR_%-J_okLpz?RWH`TUOZ=d@LW9!d$I_AJnMRJzen!lx)))u zL4W=AGfK@x%X{&B>Tzj5)^OVRsm$9QYU z7-~0rs3!PZF@D<6w?Tvl;SVA_i0~l#At?6|E?TS7{i4$z#CV*Ht{sgE=hKe1wxg|W z;Lwi7w}&YDpiQ;G-v)mh{B6ir_O+6W>_cSV zBhPTjP_%&MJ!K?r0V1~|&sLZFMYkGdIr{5TS8VL6ZEN*6w4#-a zM5U_CCafyO_B;7RwRW^nc?07413F*JpJ%LHzU8;e9}r*1>Z^Zbc(Q6-B2h$dQk+*+ z8oR~Vpt1GFHX6G}+bWM;VQ1Z`HGFCfpIXDG7U#H#t2OnnHTAFc+x4$C^{?^-B$}%7 z*zK$G*x^+kJAGA}2~RWOX(l|)gr}JB6ce6e!c$Cmh6&Fw;Ta}8!wyH$W8&;uDAj~{ zwaL_=I#a1?%%?t0+30$*m}~OtI3hQQo@~nS)MS;Kjgt1EZpHW{!fi$&)n!WMgx072 zrDADN`>^g5|S-hx=%fzI>4|4 zB;cmF>?O;>j#nlLCHTfmgQW8=tSh~qJwxQi<^$mexxl) z(7b$5J)}BhUSiz}clVfiD%IGJc9ewL5*{o5*AJ^lR0rl|j^W{ya8HEaxj)ucuF zm$*DHCHwv8qmqbz8te9-Z~4xNYBymHKB_*Y9#fxIhtSAF7;uMi@30H=@-Xs0Ecu7V za_o62XF44=<1T=P-j1}TG9eP+9#>DOLztIxw$xy5F>csuS()L_0gthn;9xC)S@6&|g1Mh;zx% zhEBA()1`Jg?_KdmCHtP6Q0JX!)7v=H#EP;12rs*~Pe0vz4u=|wYPxsfCz2igbSG}y z_0tbv*98}BwXIVQEeVhS36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!) z36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36Q`f zCE(dGEd6vy08A+T^qr`1EM0Mtv6~FK;?YKBrK(eP&}pcHMnxU;9O|S4!<^`lP9&Z9 zvCvN!?ZmOrPam=HU0A>Jk_09*0Y^Vw=Ey|WPZyn=Jy@I9xvZacYn%szqn|GNs(bKU zS%;6C?zT8*4hbXG1m>@*F4e7GR^8Ay>c+FN3-?}zeYpsJw5bdCyW~EuyAk#s=y$(z zMk!pXZs-VgxvYOASi7OY)D=bVEM8bT*f1%Pl>pc(vc{eEcXNT%TIX8;O3m z=$u|?`rX1v+(7;An$U0>seZTQCrVnfr<1+^X!W~AFL*5UyS)mVdN{9EoD&-`ep~-J zQolO{Ovf7fD^fpu=oE}G841X9Qry_DQJoozPcf;euz0l7L@XKRSzWUvFau{5{J7Qjjjk_Fl zuA|>A=QE6nez$DY!Y$WYX`(Yom5ecpf}s zu8)D^F^t3Gq2FHPcizP}FyD?N|KpN>Xl(hCQ&M9o>zj(f$o{tlY1iVD2=^=sIaUT8 z`w)x%rOJC!3)-r6YC(Um#fNTW1csyEE$2*3 zRQ>KI{1!D_{chPlCsM!r_CEdW%ySUWK8J-TY2l~R&Yl$|ZTZ+P-ul^ryX0*jznvHz zZMzhHlK=^j011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@ zkN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg00~T50{-FYXN%r) z#RSoskiN42dVY{z^9VEuuBZl;JHB7%v3Yt0ii&3MkP9orwC`j{djSpN4kTMAOf%Qh6#@ zE!P^f6H!0g(f=0xuszt%taEu!b7!0ZIz$buT)%2W!_!*po%@V^HXOxm{buaY2dR*3< zm+X5{SdZDqyM#k6kaDmu>j~2fjb~XS)w_;o+2bKE>dnXQg?0po>+!c^&b4FiiHp>m zhuXZzlxlZAdh<@&cvz|8M9`bBHI1!RG7^=l60v=4ZGUa1Enr!jX+y8dvi((Aw%@X& zDa&tPSbjU)@;l)HouB2;Gq%v!Qrp_mm6d7IoANAEo|PFe@$B@}yVp3z{LAje@uxR0 zTGoR(xjhzo^U?HkMZa_(_726eK}~?$f-%8^m zbEHF!lQS3`y?L!)jL`Pbbd>$9oJ%nldh^lF$#8?gX!4YEG7_OT zuXX>?M_2 zWIiN70%J{JIOjmfd6*Z%IS{f9O5`~Z(fa=WLC%NpF8tKJXV3l~N!&XhqNUCLKU^x? zZ5yqAyiWooKmsH{0wh2JBtQZrKmsH{0wh2JBtQZrKmsH{0wh2JBtQZrKmsH{0wh2J zBtQZrKmsH{0wh2JBtQZrKmsH{0wh2JBtQZrKmsH{0wh2JBtQZrKmsH%NeGzpAtGB- z0iCuA=;2fteL2xZok-_H40UdT$lOeZa}%Pf0}OEvhR6<0q;oKw^C3jnyBuS(%#2HT zU2)YoFF~Y1n=ucXp(7`1o#mJhW%#)1oO2qS^C3i+DpBV{h-Q5=CPp&`hv-k0qupir zxaq3E+0Fc!_v9kroUb6mG7;xP?2R)%=X`}ZQh%%^Zl4cvOPuTPoUb6Vnu$0c;?_9V zf1_HhR;iULQT4wq&h>u{O8u`RPtoFk4eRu4XXFH-__;!p)mz5OIRHH)c-D%%?@7e( z9YLD&sl6@-b(6CQ=q4_Kc2s@1diRKW-g@_Km@l$dmOY*9A!T1BnTd|1Xs?P6u4ui= zuodxNnN=bTEPJBCoSY*!5%li8s!~_qt3(l7+7{GyfatNl8~qC$bi!ynqNilYL?lpX zDlNL&o6L1JCPy{a+l{jM($246Kk4);d_o2 zp|J3~_S_u{z59X?i~jXNQ^rK^e)R--9_sS|0I66&(G8nGNbepS*w}jaeOdO+Pxtih z^TOtVXuCUl_gdE+V>01-_fggft-p`3k|^PQ)Z%mXuzEywlq!`sLFT1C4*+wr#N~M@ z`>y?yNbg=o%W(92Mb|cw`n`wy^lOvOErMdLECvfdnSSXHHwIWY3ne=N#$7(X`*H)@JRR;}~CJ`n7VM2>n{o%^k7u6Y54s0v7@SN559)NFwxW0ux*De&Lvz#gAVBgmjw)cx?Sx$T6ndd~xOLXtU z^;xCvP1u*UV*IqBZ-ej$;SXY91<~n2^g~eYBV4rVMCUq)aTvsSoQ$p=jSA<}jv8)n0jRpSzgN}bwa0-L1K3QfD3Ft5gweywO@4(3F6aZL1UvGxq+L<@T# z)}3Or_6!y$p7%tZy1G=U0`%8Ja9EnvK73KXc4WO3(yzsH@_hAc@eK6gSs4160e*Qb z%2&VpPR$OYpAO(}O>%y4&)*+*zSU9=<7`n5SB zc6P1qiL!2l*Lf_iwZ1R<&u#r$IXhr7>DLyS&T2xxK4Y$rf#WfZ!{ebnZT$4!zkzlB zIPyO(`G>}qFF7UEA3Eb9*7%V#99oceEk22G&!UiHWlH6QSoAMd-jiC;j z?>S_6OrDof>J#tsMw_3Ux6y+BUW*Ui$OsHaS6cM+6R9gbvKGXS-Gpb`^Qu#wP%o&L z)QhSUbEp&RP$$-iPVAREF~(24>rp2Pl|Hwr6Jw||^j;l1?~#T^zHk1u(a*kKT_3KW zoqG1H(O`NZauUV*1M#a5MGX(*VmwJ*Pw0E zuh*hIyYX?;iH^01N?ik%*MO~DUkir2UFJyrY&UzAc~5i#8&s)Ut4bzpGpbavx>Q{< zVe4P5ilFOTIAQCrYmR5hN>!lpRi(VJP+Y{2+u=bbP8R z$PLXi*@3B$HefC|EyoSvxZKQ<<$$#u9G8RRvK%KDcdY33E=OILyWB6j)hNrWWF(1| z5h2zt*sB7@FC$6r7aCit?MT0p)e)T$^|MDxZgR!9N0Hs8tD`o})&q?iJi>rl4DDLX z-`dbRIZ&s!$mRJq!YVWRc@hvk&<6B(Jw9~9C*bI3ONtsO+iz2w)ebP+fqAnX&!g>n zeq{Fh`3oLAM*P@{rQwr4U`vKT{g}bmp!(U{k^gqdKi0g&^Vo5v65l+N<*bSZ)Tur} z^LDGcO6@39sucAd%!zJr131-(?K1|87q5F;)Rk&SDe4nq7q6V%$wzh>4XA6q%k`E0 zMFYl6eb~5hr$vd$wJ5BZYID62b6{h?aTZ-aJ1qIIE;k_GjhJT}G0r!J`pTCyT>Wej z&u_rqxjwYN9#*mE9jOW_H_ANd$K$-SyWkSaqTPV;RBzVR3l6|&8jN{zv09~8Bacuc%!gry~yIgALfXzi5+c*|ky&Ka1{+T+5&BNWOgm>X#>+J7D``bPJ@4^my z3)f}rShSsGk^l*i011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!) z36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg00|_HK!>vR zzssN#P!^`e5~=?!dUq2^|2vv4_IlGs(J7!V_Q=QC2BV8T@{~+L0wmxTf%R&gx?EkR zh1{;iTD}_}H(j{iRXoaZbiGBF>RPPPyThJE@yI_ikIKj!qx6ezTDXp_WEX(Wj_A`a zg%*#9s>ag!6&>aaP3JckV^nl}!*zZ|^`<6FL`dR<>-;W9{Qf$>OVv_vUJ5OzrA7x$ z@(@8o(H<1NKhc^LeJ9cG7S6+QON~B~=x|R2onK1^Aly-7Ei?a*8f#_R0Y{CsvW?$Z zD;p3cy|GrnPI%N<%Lq^(HP$LL;l^5}#&4{Z7qIg))+)@i{l;3Qg|^>VM{hV;HHwIp za)!WB9SePzZSptPDlIkXZEG2QB6K?EU*~MOMN)G~65c8=vq}3N)w-9qp zmh2I^;pqIX3zgkJYpolLy4B;82)7G`1k0l9cgnhw2)#_Ft=CC?Fm%?rq~GS06E7=k zZUe>>b$&-i)Y173U>?+{YUuoK92Yvj>+EGxH%7)_xX$lN%t<*%BN5Kg`CW&-)nHDZ z`zx^@kn=kd;T)acbuRB)t&J*<=M?N;G?>KU1OhE!}6L9nqMb|D7`iRAGZjk7?h3g~cLf5Dg+B1Xc zBTCVE(2U6w-9)2vC3-#=nm(d%5a;M4iWZ`ykEm5+(p9?XC&oh`QS^XB>u|VE^bwb$ zY)LmB^bxI0Tgd3Bu>LofM=#OQ9dvXE?a)3QLdQ>gVG$?{Ywp$NdMk$7 zR_L51Rv$5}A~7zt9wF9=`Y@fg7|}-^bR}}wD*A}_^c#?$*8js=Uyn~B+!hqFwG{P9 zkPh8w+a&8v1L~S6JUwp(=iD@<&f(g-@Dr(S>mwE#eZ($fbtU*k0wh2J zBtQZrKmsH{0wh2JBtQZrKmsH{0wh2JBtQZrKmsH{0wh2JBtQZrKmsH{0wh2JBtQZr zKmsH{0wh2JBtQZrKmsH{0wh2JBtQZrKmsH{0wh2JBrtgicq*`EHkWW{Tq6 zAV=R(bb=D0?^qe<`iq=ixW1!gAHcJ7Fnz~7JX^!{9YxDY^m;EeeMixA6#Yg=-%*%3 z`i^ofPU6Hv-%)hoM2k&0566kVqd3uo91r@AUKNn)V1DNrTWD;lwpN6mqh;p*QDd!4 zJHk<8t!(2rc7R@Fz)pD7SS!!?jkOAm-&o5CTOBpl$_wav9W~Y}wCjD;SgX{o|50Nd z-APA>Qub%!LVA_iraWV<(o#FzSW7E$N_@LrmNM~;wfy!*_NcLz--H`$Wg5S+R(8P7 z-&iZ#)ZbVu+tlA!E8En^SSw)S8*Am6_{Lg=Ccd${urc_uYh@RFwJG1xc}uLmV@F4L z^VdbuOVqk;3DgVRg-QiQ-w|u}U{32zBCI}2_+V*9bMHDN7G1k_W_=n>UWrJn^)E5? z>hYl)J^@GHF@SkcqpH<5wNdQ=!yOp=+i`EZUam5=46>6eJlOvEv2>>4lkO~`POt=O zF*|(u5LdQZ{oHoszg_YVjb&eoKRsez>T>O5G6uIBJx4h|VI|TQ;FAcqRb8caU|y~> z^Ftu+sVw01W14cNPq-LfCNZ@1W14cNPq-LfCNZ@1W14cNPq-L zfCNZ@1W14cNPq-LfCNZ@1W14cNPq-LfCNZ@1W14cNPq-LfCNZ@1W14cNPq-LfCNZ@ z1W14cNMQUB7^c3X=r>FzeMixGqQ2wEhavSHN6w5XNWg6Zjy|FY_#{Ffu{h2R5;3B1 zeZ*X77*#@hW-xt3DLPyqQT(FkbD`-YO1s55`iP>1C~7e^fT>ku(p9?XC&oh`QS^XB z>u|VE^bwb$Y)LmB^bxI0Tgd3Bu>Lp~qsBVAgN_cN9jep-5iKWx_JSZ# z7}m`$`J`soro9T^j+_}&kbv6+)~j{ua&?)~`iNM| zce|`JQxxY0Ir@&G6O;&j$I3X@Uu5*c^&KVq0G^$L={x4(*&43zC|XXU*L$JqJBps8 z=r=n0j>62*ca&>!5+@$|j-m@ET5Q63I8O8(#fc{5c+hwBs(@4n^E=PjLSsv{wTzCV zqvvRu`G3?{E7Oi})L1Lq_>CQ)7a6b<9yQj=Gk#;OLgP2qGQw6zjkWRux?V?(wF>Qe zA2rr0wd;S>SVwo#(V=v7CqsIb*`_>Wt*JP;u~ufn)t@*#*D$2T`Rlbt4;Zi z&Rb&j9XmS0o4+oKUZU1*!+S}h^a6LGQbEyo#F{;r(|VH$)JeNe>Vu)P&a6*^)oDE4 z)B2Z~diD6w4WEFc?-;;5s8Q8wo7$*$fZ+~|{q4B7T`yOe{q!A0nhuJ@SUS`2Nq3ge zP@xEv?V)`65LdQZ{oHoszg_YVjdfp&KRsez>T>O5G6uIBJx4h|VI|TQ;FAcqRb8ca zU|y~>pNO*>pPw@x{kqv{ibkyJDItW011!)36KB@kN^pg011!)36KB@kN^pg011!) z36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@kN^pg011!)36KB@ zkN^pg011!)35*{C!_;>a{f5b;?cY$eA$(3Ajzb(MJ>kpG4>*7RR|k zB1ROhkC+P$qe^Jc45p7LMThGnieL16E;M~aX}35>A5pXrMJ=WVFtut-x=I)Q#CYf< ziXMl38Q zcNOYWBlStpx-=BFZ9_zm=Y9kFxjsSqkwa8x%!1b%eZ+I>ocCOXQs*$Ek`_LC&)KuT zN1e`v>a`Q=|4yu9JHcyb9M<|nMi;S>`iLRMydVJ*AOR8}0TLhq5+DH*AOR8}0TLhq z5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH* zAOR8}0TLhq5+DH*Ac09uz`J36CH}6x0=fhhVOj_k_&fFr{5^Yx(KVS52o-VoyY@t} zj3#{1q3To}+EjpEjcp zMK`4!btuEfO(*3_8=Em!nlV;H|Dzo3c3Trw%9S?mMSt!EThRk5N88Krann_yT+!6q z3$A<7PSJlY2k)}5HPDUnrM<#-FWR>kWl0^%!Mscs9v7XID{b71a`vKsMgFZEw#?;q zLCTdj#>;I`Ick|&szkqM55~+om)C(?;#F~zPnF73xlk+=ow7X`@9SJ%Pi~EK{i{`h z%2zAmoNMB;6Wy$vFlOFRJ*rooRK1voy_o+!=!cWACyU_6n$Uy$J#rt{y$E~l%ry1- z8KveReJ|!rk4y8$(OaA=}9$ZZg-^7=P6m zQyVe9Y-j7V;kl1Tu)iNN+>^)Sh}=fxzftlJ?HPP2{`8KH@JtG#jNh4vv=3>E@kxZ+ zj6$l*lq!fa&ZP9?udEmUv z(d9}mO65p=GcTsWzaME!5;QL#R1c{R%*&i8<;if{k9L%V+9EY}&poUjQ5~3A`vIv$K)L8dbaOw}s*(w^UJVNcm~B@zN;E2KF#c;WCu(r722i&dp7Q9d!82@I zl;_y6${B-5djE+!??ivSt*%s4L?Cz!To7gU({n|Af?yp)-K35(oJ8X_7`7gbK{ZEQ z1g@?@6qM|& zZNL29EY2Bz&hl1j!p&n*|BfN?e*1@W`^6qJyJbhm{)l;g$!{Oxerdu@wN#p^m@^HX z@?>8X?wn0{-c@$L*tJxu%cOT6OU`c{@}4N}ZL{fj?mxKLzHj9BRWQf)%kLTDobsJz z&58Hl=j`@@yT0`YDn6X{Po-+2dv1g1`H=6Q| z4H#Q!Y^AY5V;hZaF}B0lL&hF4_L#9<#-1|vw6SN5RZXURV*|z(8e3^>(AY*}Ta4{6 z_K>khj6G&-m$9deJ#Fk6W7SQjd}9N~78+Y=Y|z+7V_S^vF!qqKM~ppYY?ra8j6H4a z8DrJWrhH=q#uge|X>8EgMq^uy?J)L`u}6$OW^9+Sr;I&q>=|R#2Tb|K28=B(AY*}Ta4{6_K>khjJ0ze z`)_}6@bwMru6DA_+E@MSI%k7d-^elcSa<*Mz_oV1r?0bZF*3}hgxE%KRQJEGq=Z1f83;h(b!ib@~gZvcKWwW{GS;6PDJ{~A<{op zG(`Uok^VOk5fI=aB7J3#U}mX zDCy4(k-j2Iy&Zm;AC6uBEkmTQ93p+KNq?QOH%H{x@kg=Czum-di%93x|Hu&O?~jts zN#8X@`okvuXN>(qM1H4-NdMO+{x>7iIpwRnVz7Y`w9K#_ln;#n`)y?J)L1V-FeY zq<`G_j~M$EW1lhhMPt8X?CZup?fmo`-e*6T?l$%jV;#Od*W2N582bZb z|K8Zs#{R-eRm1?v($O>DNCu_N&HTX8t{K zb5+&lfxK&O_|U!&ekibJ&FV{57p_|KA?;oBk)op2g_o`{w-x@c5@jl@OG!Im7xrya zX6_yK#jlghjR><6ey^HeWd0>gIX|iXiSuuIgU0`2gA>2j77y2OtEIp^OPBjVfr@pEjn?fSQr+wm_q@fVo>h=Nzy^?T{#PWoe;?DQXr zQl1^Z=`Wr5g+V)hZ*oM%jMt9;^B0`>YL^}V=E#4e?HB)_e&fV%F|RV|O|6omYt1@n8Lv6W@7dh#mh2&pGj(SA^K{&%EWtFEptJU>orb%XNw;@e%W>>zO$u|9e?YsPJCwzA3Ofd4?FP#X3Jk3 zlh2pG;>2$>|4+nk2doVC4ST*f_JrcM+8HOu%zx86PW+ZOJK{Sr^MA{i?5scLmE-d< z;~!h-#8>7O;kB6YPnA0HPYo;nnX8@n&MQQ0{%3D-;ybSlvE%>xUMK!(^NJ9={xd%B z#CKi^V&^~ac_+T}3J^Q~tT&zb&XzxR{EPmt6W`h5$Bv)nOELXhXkG~(i`idanD4|t zW#Zo#Gk(&gPJHLc=>LitKm9$S`1jc3b6d>uT)5MTf9y}}h~G{bya0Q?6y4#(?|9gb z{~z|hAP-1n$N#U#L-C)m<2T04f9f+%{L`Pe<2S^Nf9pvne&v_!_&qWA8)g5;iJ$pZ zJAQZSfU4^ocKy{KocO1owc}UB++QA;nQF#^^S>m1D`x!Md?)^C?1aQ+EzxGcmtCKK zxY>!Xerm^8GX_M}H|+Q&p9sbOH#`1q&i{iJk<5<&S3h*(w@kHn^Xq3uL^NJI{;gB} zroCMOJN`dK*&oiq&OTXr^k%f;H^^kM^FQnVZA1Y{&*6XDOL}vTY|PXBsb9i|yRsO! zvVBVStc$*dFTHtP^dj!cRnnqgpcmzZ!@sD-TxH^aV%XRw{T(6z=qFhgvIHfbcE7!9z6Ou2R_4ji9=aSFmGk+o1 zS6~JvubU+cL()&BtSvL7_@r-0O|P`e{b$@req2{8>1+6(t&^Xauj5=T@t?G>cSt@* z=IQ<1?x{V$=T5*8lxeBLQTg6Qb5dp{%MeXcizQ?1!_^W&=2J-) zlBLY{{U6-Uz8Y{cQ`0l|A>8)_vQC|1=_j90{{BC8>NH8{S4rPP!%{PR^8aBZtw-+u zNOsjQc9tF5L z7uUob58kAz~oFQXn_MNz~rW{3l{A0M% z{a+|oYfhoAhvh0g;JXafPtQ!MMYQy!q-ljP{-l4gZ~hV{cQ5KX#q!Mhk&F@dd)kn&|0AF8f%5NMOLx4 zms)RXTWtMQ+Y;+n+OD;JtL${js*|tcSEMvmVp-3acDTn|E4;^$LpiPFruS z*Y`JA+qA8+8nmspnRDJ+pH7XZns|1 zHfUX`;2kZVcnr^r6qsL?af?oZPs>!b%VB5)*owIZ9T5-M(bH^ zH(76JyV?4=wmYnu+6JxP!RCJx(`EXmsW+m3HeJ7~NKJolQr70_|1f1y3+|{b|4V|e zn=-2vzM{Vq&xfYWQY+fgbJI(v=9i&&W>ieQ5)<&sD{$?fvD;b)kMABtopIe%d4Q;` z5;Eg`nWebyL_XieXIfx7{@-{Ve96CH+%?MIaQzqoKXU@rCGTJh{_{X6dcXXyS_ zzefQxZk&1xa7YHzu*%HFXIc)jRCA@UTW&#=T-;kF_oXQN{%v0Z>I&T3>fHC_hXPyX zqo1!szz0HsA3!#C$`8JUzyk=lHxziWq`dUkh;s0=s7f)spF!XkLlJb=I>LQF!Qv+o zUPR!lp$IyMxgE&nPuJt-+xYyW6F5yT<8wcY+41rJg<0`i1jxR?1}Ax`n*Rj28K2Fp zL5pRsc;+H}k;Ks?wtX6f&N!BujG)UA-*agwNX`BjaC&F#%zO{-;i7t;+}K_uDT4mb zfw?r@BR5sx=!0e)}7iOwmz=y zC#+$XRJ?Y`&p|~+b6BJ zwf&ssn#0|k6L$W`vvP!ZNFr_pzT+zpK1G5D;a-{;GOkXR=&2! ztWDZJW8JLnv(^LJK4(3x?bofBwEc$lwzl82exvR4Rt8>ayt7VNmumZhwN={}t-acI zS`TaclJytb{*CoRZNFum(YD)~o+atOZLQMwJJvRBU$ORS`>OSEZNF>%wYELhtJ?Nj z?`V6{O2uDMcxU~sm851H^xrKUsZT#y=h%+ z>^5!RvTiZ!g=~)PloWFzRZ&$T&L%G zGIY8Xo(!EX-;*Kfyt9j~X>-MvSl8gMSG=>=S}kI;?zX<7ZHM(!ZSS|L@Jp^Y>mjRA z+dsA1wEd`cSlf?Tf3EGvt(UYtZ2eN(N3A6M6^u9QQ`UTKpRm?y`x&cN+s|5eYWq3s zQEiV{U)T1iC87e}tS?$W)b>l(JKFxafwmv9{%T2MK$AR{9-zq{OApYj z9?R~?w=KH^|IxBL@aLA@asOo59ruo9cjzxI>A?3iHGf!T{m}Og%98ZbM$ZiAOI@9X zXJ~5D9car%YyAI+`x#H7hAQJHct&|L{#hROYPKY*y%~2dDqbLQyej_{R5zp4vT$=} z#^u@nf#xfJCVbZ<{TZ@ckZr#U-GgWg=GyN+PoN45=GpH&vfo@V-+s^eE?6wgw%?al z;EBC(?yMJ)Tap)q7tXWai@t$87tXieg?@!Niwd&k2fd^hkk6u(a~H_q^vo(WUe7uP`cUidd*;@q4i{~nOE6ZZqDGar-d_aOhp=`)_f^=#RN?fT$ts&q-J zUtS)3m*d8gH1n$SPsn*my7nabk|o5_9>4Er$a~2Y?U~|B1+*nowI|buAGXz!4DFfa z6Wy*Q_RCwg@9)r-C7C+pBHs#h#**pU6YwQTv{_SxN}lg`Qt0eyvN11Ivt@gj{SA=K zTx$7ckLdd(!k1=Fk?Jeo-=JTX&Ypb&9>1F3yIrYeTQX&fnK}h&mhG7KO=KfmNsqKt zf2q{xk#bq>G`Vw^1j(23OG&BkR3NBE2Yph4=l^Lg2W`mXF(?Yk*Ap=HbN^i26aQfFZ^ z;n82>Q-0ar*8LiD#V^|zzidYftVSqU&`N#bSXbYSYDmSa}2lSqc3zi6H6AN zlr@N-`>vgX?1wyZ*N%|#Ul@D2Q+&Ev{~}@f%Pt~U5`O?K%B}J02(o$7=}gs*fK*sr&!fVX`ySVJcPB|MGsLG08sBuAa`< zuu7H&Jno(HdvvO>l3k?T6Ly4@ebP;{e0mVb*3u)R!3LJ{d8vDq-3worFg;3iKZ;lR z%khe2aS-7W+54eyjau#%PRW&3Jt zM@q>C?Ywe3E7^?M5$p^OqM5mW>z#6!X|8O3!@^Tqv2f(wZ}*05h&?i|ZO*#aQ||(_yj^x08iB)?S5Dza->;rX$HNU1y+De~)bQeyUT*p1rR`JqA_k z5y|^DU0K=7_Z4fxdnNtTI+^V8Bh#mRQ22k_W_U^>XomVqSJ0k5!YuW>7(lsQx`Oh0 z&{vd7`4JYZ+*XfXsi$D8ZHLK~^2>sg(j{r{_GBExSde##un4LDPZIzAbcrXg7hzS@ z8KnG1!oTL3{%hnW?;U+<&H8dq2HG>8c_oM-FC>u>Qg1~-?gP5!@}d$}g0xYk9Frbj zY)^T4gVEDQrQCt>mFu%_%L|R2ubweFUFx#}FIQ(LFFKL=re24d=auQ(@&Ys<+``J4 z*Q{^Li;*3!S6#baPsx}OLoYz z?d}URfcSt%%UL;u62SMf$#sC*=zJ=Vs-bj_J9={<+!jTZ<>% ziYxSQ!kNC0pt>unwI|#6AgZupqxJ-RUyuwoX-}R{e$rd9S$hh7mq-R%w5QbfHh`_T zQhO?W_eq+q+Ox%1C7!GF@B2aDX7SW$&wG6G?`kWyYtPlbpGek0?Wy(MF43;mo}IpX zBzk`E$UATz((_c-bz@AP(>jTy4$ zm^7QT2mjpg1mfgxPX4-`X1nhQ3YXU?JI#)nGEPjIp!OimQ;3uQp5$L4O>R9pGrtgz z1Eld^jIRc%nf!v_k=F+OrBdcdDZA|r)ouxsFXg`;-@CJ_F$wdp$FF0sdI1PUNNoV; z{G0Vkd|2+vW<;fa5MTMt`Y|CtMVPxEm%F#>g;jo-u zBO7zwW`X))?^OA1#h%$Kr(-{r|Em22n3pM@9*_Lg;<-awm-?!-<-?k_{P1E|SALIG zscWPu$2D5{Ev7HX&N=mqQrOq^BTIgxi40HakizEJ&5<8(bOe=}hinTT(p8tAa_pzI zEPRI2o9O+59l8wpMWAm-q*6X5mA%2YP=>1fN)YzOpZcVP-M&mluKaLd3VTxqZLePU zQK^S96|86U;FaH%?7J!1$ikXs6Ox~q%lZo?`3=fM z{xB$89($6>Pg3UgVvIHGtbO|*oZB9`QhxcxE9Hww=S}h0c=3~yeIeuCxpHHNeGq}_nya=Wj; z-up|WUYaVidgZj4xc(W!Gk%N&Dx)5A!;^6dy2G3CI&?Bq`|Wtd99o`RsIDq)AuyeteihxhC{aR2yU&sXr7c9 zxTxhuwQ|8!`S-$Q7k&6fcou3;p6_N%?3IhOXQl5eXy3|!_7tk6$Y0M9J@Kb2U^D+?d;~mVZ8NQ_mPW_hf zf3F@$cfxNEcHMzOafW)|4M=}|Cz8u!>k)|}7i#{4=&MzW=Kl({Et!sH%>Sx{NjvQb zDZPlb`qTEW0^gP}dzLN&aO*zrjISZfpUZ7o*FE}5k5<17yT%?YrmN;oo&PYp_u`zX z|AUBrsa46w4S1QJu@p%JjmqkgN%c+7lyAXGgi9nyO4465RB9KXuYOWDaC^Tnm0Af7 z-s^SHUI_|o_WS<>`FZB*ArSe0-Fu!aMIG0!208t2c6fu4AEwpXw~^)|Y0gggHsP~O zP|dqY`sM!<_8xFj7Rmc~_xsMwPM+BuSat`N%r3CxB`iynoDmce7IuMEauN)H*{|t9 zJx)(VOlOW~ju=pkV2)?NGkbzLp8lVwy5HGZ?(YAa&!^t4s;;iCj&HwjRlnOM-XlTqw$-LA-eqkk24A5e+;ZQ1dPblka10SMbxy!*KhN-`t`zynG9hr@_k? za@QJxsc3D#p02Ag(so-z+16Jhn_tgxPGqXH2`|}SvZ)hLvE=6&qOWC&hTN0AbA`#U ztq%45YJ@`W|Jh`!JqelyWeBC(OQ9im`yoQhGK5BYLN^>D^mK;MF-FLkA94?*Z90%4 z^rx0WKct0{wmoV1oh^m_ofaCLA@pWTp;#~5)ycCngnn-+l#>>^E<>mSgCpJUA-51;Ttq>=YDjS4LPG=0)8!>=SE#~NUx9;3jHWmEyI$%0JH1` zJKfoQ8<4{`N@$vu{R{Y92C#AscmU=OYE(CO7>zEF@^`1p_b{%D{M}OcnOFX$D4PL* zp%<-mvb&TMa{oxzCfCcq9_8h}W(8N1_#}f+YC&6!+d+-%)Lo_QRAWXvTM4Z^%rm1Y zu>$havJb$7`)EcFE1foDcG`@=?5F8zZIvisI$S!uFL81||ei2f3#!^|<5#dpm0`)i)76yl1cx zLwlh`+V4YD{R2R#yUp8jWES^88h(B~CFI7^#MF@MvxMy|FT0~W%U{pOLvrqdD^0p`#fzG(A0+7 zrX8xSv86UI-BBLqX^Ta&Ds4@D+7gkgJZ*EKX%4j=cc`{twdrl!r(U|FJj~OUjC}2BqZ45zwVisXwgD}* zdFhVwFi%@{WJr~5w=<#XbZYz4q1ujbsm)7wl!tlRaw6w>+8Bg&3AJ5%sJ81{YV*<^ z1TYls?PuuIz^eVMIa;Ucav^KfddFhVAdm2>`Y2>{wu=6`?2-U*p4$XW-I!>P0O0rq#BklgHUS4s>ao;Q^z)L5J_l) zH>dpuJn#&~KD+&+VRQf>)^0~z(J&yjx@qa!1*zG~SFCATzHIdzmRiM9sk>-LK`K?h zuD)qW{rn}3DJz4Jme{}@H7We6s^%}RU)7N6)~y>!{#L_s!|a5VwN1;GSEg34U4>dS zt~+jZH39@;bvtS)Syi=q!?Fd$(m!D|E~#I!y0Ibk*j>Y`)-)|`OdZ#>W^rm&WBrm8 zNg7tYqdW6dRV`h*U~OjUQoL=yhQ@VG3mQ{vHmqnwmOeXrnJf!eHLhISxNN}&FCQ(o zS(?+DmZe4?k8Hzt3^mzSEb!z>7KQPfiJ=XUFm8$QyeC--`6GmC4A~P)Ps7OnxGq6eJ(U9JlLu2?a3!@Bj z!f}uPI0XJLNEDePA-*}-A7*uGH54;&Y){~0frO64g%HM^#BbcV2r>lJpMZCG1Q#Nz z1J8{R^L604k!`?&9e8epSW*?4b0gz}9ZCBdSk8i?KE!!4CHP_?l^2;qB}EyBNA;SHIDAGI)5v~y;rFj}6JV1y} zx&U|8@IWDYXr6`$4-%rkeh>P?gN3NmJPi@96JoUHX^8MpAtviM*3$4WA!g~<@5FRa7uh2XV5gsGN8qL!X;jxhvs<2-3G(>np4qJY+=4puV z!~{F*6nzoRnH1z!=v2+q5aB6_ULelWJPi>(B320nTQpBYgl88HM#{ySry;^e74zi6 zPR-L0;W=W?b(*Ik!bgWVa&FT+4H2Fjz8=KAnx`Sc^Tf7Ynx`Sc^Mm7|z@CPPWEF2f zK@+Jn+%=x!X$XHF2tU~&b{DO(1KS@3p5kc;e}7^;4dEXKOazbe1amR3fOjM#unae> z=$5$P`(RRZtKb-L3`6u?fk6|?%IC3t3C)Wad{$hB(v&SY+0in;yfrD*a$pgTZzPufX@!3=zj5V!Vsj?@; zLP$yKpP)Q@q7ZrdA`I~CNwKdXR-`BQ0x`LS$0brK(GIIlGJ9C^29SC_1hR(*WFi=K zBMO)hRDK>$@liN?q)R*eyrgCq0^7wT+L%4XrMpb+S%6b@cUuPZ6!z;n8OVKcYsKo4iOpe@6$=4vIKj@AeoujO{(j6h3+eJ$E>1U89 zx2q6A%`$VVL@cWJj0e#zvK4t^(g?ZLF)B-T|9BEME=HN#y&5~JUIA*>Zui@vy0;LH zt3uDf*pHDzMuJv8nv~nurQN=a&KSvFcRG637Id+!}opnEGuj z!xmT3mD7b_b1Emg{O~m8I8pX81Zk4bQK4_3eF;}7uB1bhk6Mw;f=Vuc&c%V;LD_Gy z1Zkzg`NUOpDjGJo*3{C8vdXzb@~8*i4*ti`+&W21`l71_gBqI0Y(>5rj=tRC(o(qZ zggytCU`zM2J$x)ScZ9nheBY%oCoh%A!VL6Baq0X$N^cLul?!X(ZUYMk48bh<9a*>3 z=3kL~4YNbjXOMrTjC+`muFStW#x@D+8_*N^*ThML^%7*t|C>yLsNMzR^RKnj;{^=S z{Oe>!wQKUm8ZWOUHy_jM*W$#DtrgSxln}ukrOR4P^ z5o@Oz3zC1Q??~JeI_WQ&a*q_+Umt<7oPS@K6&i8S{4wF-v#C$jN_Fh)^DNdeR{Mn* zC*umu7xDQohQ`9S^}2?{%R+3{&(P|B__iVCtk|lx%T)eH(OM8YbpXRE|I3huRoCe= zsqLHWTcPbXeHSbDVv^&Y`pWV86+nvH2r(Smx}mZ?u}SWcebM zKT`W-$~+2A&UdKaXx)mQ<9W3M)-7mIlO&pUaqWOb4fEAheG2+;MQzR}7;`hV+|$Iha=&=Uzl%UQ?^=OE|A_pCRpI_Pi<=TTkVC5JR(|OY3^z z{)M=7=6Klz#LO&GW@aUB#HdLX)Fk;}q+emS0d0sYeG1y4V4#erpuV6Fh(UQXkdl-t z6bzOs6e&N|`lzO$))o9L!Aq&7WCyx587vr;EI@bYUKpvR>sb&Sf&x(2l>$@(*{t+GDAwKVG;Tw7;_F=ETI{J559m7{CtWJNh*vc5v<+<|@a zxzw0DLH?vbElSSnh7^^x1(nrVF9CP53W2*>6_E91RRH(f42^*knBfVuk;>BOL!Gq| zLQYl=ig2^aQFC9`AIy-IhxQ6&odAB8>JdEYQsj$arsi*qvN=_3^$L~0DaxhOr%Kjg zMD@@(L-szz^aZdze{FFdRs6yQ-ywszm41V(bMWQL5cCtQaEEx>=%3=W+}~qEmr(#z7*l6i8tVnEDT4!5)^{W^wi(R4AblfJtj zh#9#%ktuw6Bynle1s5|seuI!p{VsXR ze1cm%pt5gde+bXz8e#X1Bf#`=loSqh**UVb7q`(TgP-*vY^zg=OVPHI zi+U#?2T!`as3y+syV8wp%>iLPesKL=yFU?0og8SGMN;ww}t zSu`Y>hgOnXXi=SXfa+8QPSG$Sf_0s~N8v@o1KgA8(Vh6HRy0DW)EMQXlA@9BUMLic ziw@Jhk$d16T$ENN|3rboB)G@36h0kT+&mqC;0msi@^oM+Cn-+{pg47KIw?dGIU1zv z{!l(@MKViDm7-hx+kl1GEVp@5c!uD}E;`EP@Ch8KpAVkq#i!P^c89y9pw z*kYC>4gM@;at(e3WeNmGq;y|OFr(GJkUlQhqVnA+xU;`}*QJCJpGQGU*@ z+=ICJlywOdlP%3s+Zl!A|4r+@9!pAbIeYO04l8qy*Q1#xEuMP?^yW>_N2WPlUSpe; znl@WWwlr6lTOgP!G<|p;*>u0T#FYOspcRD>aOO!L-^28JrhkuQ_e)~37|(hWLiz!% z^|ufi!rSeGns(QXN5Vro#>KlXAJu+XCpmV8)UQyFm~S{7(FP5wuht?z?^y`q_pz?a+DN-x{Ri)z2B-lx&vjDN=tLX3TapTd7R|Q{`-%UbE2-f0f4TVNK|6ZP(kw7&Pq;U_f1}vx#@djfF26+uaD;x0^lMM9_TO z+;zU%p`+YXHGx_LnEifxcpypu~mh^DH;|V4f~P%IY3?$R?cJ08;X(G zpVa{J_|{`BK6is5a0+OCW+k%Es^n7lB+Oxn>u^}X|AZ-ni{g8R?_Q;6sIt~J;pen4 zn*v4__pvElALGj`;SG^>Y%x2KuCqe~^|~1oYL=e7+Z1+mx?W-I0;OI@n1TN!Y<&#S zt{)oWNS)6*yaW0TK%U0%n4=@ydi((TEAl#^VU9MuLTmx?B{!A#B;@K1kK4iyfTJqf zWB+E0*A8Zto}-IDMCM>EQjUPgOhB+Fh+}{(2B^phHp2@QO3`zSMw7;wbBj&jZAMit z#b7Ac2cI^zO7YHupWa?nYAcsAoyLR4s{nZ)!N5*h-c{cP`d0GTk(H(+e+7MjJa%M1 z(~$$8R#ykW=?gR85hkpmWS?;|sO<`0&R1sE;TWmibUd;s&_28{dytHfya-l7f75f1qv@-KfcB0pJk(aF` zH`Q?zY$R3W8_T~E{0!2{i{I2{-mq?#=e3c4KE`lqUsUq++jblA zN6a6zNwTeNlQX1E`k)@&0cFoy$s4U=+_59?SzZ>_wa1(J#lKoUclnXHwUiG5pJoV^ zTRtBeihE=d<1+|#*jy|Q_20w3$+j9b+8C?1^ZqIQH(zX>4m&3TM%>gMLBCd7cY=81 zcGN2PGT1ATz7!CA3dAWuHj{V&#Q8wZ1;kIbIhS>0H%xbee|X!p`qhvdXGfj(5Dano z>CKJ8~|-S;)~;$C}9Pc_%&u>Dw)#&c)2^9j>RH<&*dX%k?n^xg#NJ%0CypM@ED09hu< zZma`XZ2=8yRwz9)hYw@U*2$5lttvjl4S^E04|j&sk*12r?luK%?ufsQeKC0SD9s1@ zEjAa5ke}XOIs#K*$O_Acq~)^-3wZprF3F5Fu%Hh>m7a)UdqAm3PkE!s z*Y4v01$^@BB@ccLAm@?A2f*I){KqJ~wSa|#k45%=;me@T-MVvQ*-ch|KG?YFkf(~D zwoIv2pRriZ+#YOIZWp@oHt+VR;9aM%+Y}}Z;Qm(iITH1AJ9B@+fotSCXUKK7a<^mO z=&$4*i8Dv!{8h4$cUv`I`MV|PD;Qm`dPMl_IeMw87Kfqgdl9PRtJ#LKxIHN3)0nSD zlP>h5t$=gl7QTRn0De7i)i(~Kd?l30>)_=n(HB!L%seIf0~BKNl-NAKLV%8Z(@OaqUdS*^=k!*55-*gG+?`%659EvZsP6sWkm<#k+%e9tgj#8RYqxFM)gt7{1@;y8zmUq9)uU zaTmaC5y#3^daA1O*|9>Q|0aMU`$;FDBl@ui&j$44%i7}ri|M8mhi4R{jFEV|Fk^a1 zBwi&(5+m^r{r4*SF-s&I&V8|P0MsW;R9>}-YRereEcyO%!o(LPOuSse#LFd2jGcUo z+1EZF&k!n+@hxUwhr-!pWrWT7I+e}`OG4#*T?(3r-xqL@8xWip7v(qLi{GmwW&srIHe*lr=2*BuI%;${HRR3f0P}8&SXn1oI8X zABj@R8tKvwx#TlS$$f`Ov@vUn*eg*=!8SS7aTR2=5ePPma)QebPg9N)WV8{|SR|s2 z0-r(OWGIkvWTTCc{0rDQCfX=8DEncSz-Xh;;C$jL$Y`Tbt!W=8$ohqbk?| zC`#we!Y>!r!Y_|E@-6Bd6Kxc^B6)uR7GH@e5V=yuFU-eE61h6YHZjpgk!#{4Otewt zZ!(xov{B?*JIonv6uC}Dwuv^1Tp#-bbIC*-MQ(^CuomOEFfW`jUtccAuPs58%1^tVWN#9PYPk8jc~r4c}%oXj4q&HGb zv{B^WGDr4AOteu!FeBQC#J-4$HX4B(Z$xdh(NHwU#g$PTZ8QT(J1e6$+K3N|yQ-o# z+KAMis;G@N;)Bt?s;G@N;s=Z0sEXQXqc944zkAe18@-I-b+BJAPR|IUjbwr{+Nd{u zun|NX$&_KVQS>{Ea6}vZ0p0UzJDF&szu^wFxVDptHo6VOirVNW7;}g=qV4Nzqc+;; z1q>iW8zm*$DBM1|pF@?=M&S;5@4*HWZ4~Yp;<&caM&V8_M|6&fHVSu17NH^%Z4~Yr zC9Y%+hAZQpNMK%5D{=4sKw6@W!c{I`9!j)Pv`g!eka5T2Qp)kN0En4cq|D4pO0-e5 zCV34K#bF;E(1y5il|~23crwvO(Ls4NNHNhy(ZN!MBIQ!8L>onG4bEtzXl*IAH{KcNcjSbU)h3>Cyr1W$SjvSEz)$i^tmQei~xL^ega1o>3XI*b%Ve5?sZ zF`Fc6C$hG97;qJ4)J|lxZ#;-#kWo94lY>LqIy%UxoygV*59%Olr;kMKM4EJx8NIk2 zDa?!8kp}VNcKFDLd+%Woc3EtI)uApsW&)Jv>=xR_?L;n0a$Rsw!li_(m$ag4lf0FS zg2e4aZp-F9*u?EbZWqGD?L_Vn!o=-F{w_pRwJCb_TjpilPUMZSi}_*Vb|P;HVd8co z@5pFMsuBvAzB4O7GZ!#!rwbCixE)D~NZd|aR4WJx#O;jtBoMdbNg!^AqX80(+t~n# zh>hFfu0%y7ZYKzKFd}g~ETstQ5Vv!wrw(yDo;vg*QK)0w&cl?jaXaiZ=$5!0@-c>4 z8rK79VHZjfx5FDu#K!Hs!YtBxh}&Uz1S2+XheT8bI3#%!5(Sv{q{}_puS&QcH&1Bg zGEIcIxY~XVuvNIC_T^p@aXSIli_54r%ca(&#O=hoB)Ou>G7#&UPh5rhY!|DH@q?cx zZYNeHH(e9A6YHMy4pL0qPOMsPUnz;(iS?AbTszq;#d_tly-nOstWSs^)H88Av3|iY zw!$WECpJJ*>Xds7%62)ca!lM#d|Z-iuvilxFJZVQZYMr5!ge%qJMqcUZ}602;&$Rw zgfMYC@u@lghFi_V?Zl^xX(nzbJ|ow`2E9j+aXayua+mCp7i8Q{e3nrC^MZ`qi60?U zU0z4tGvc$ezl1`>?YMjim(REz_eNm-xJ`*5aEB*G+`GUDybl98AN#WluACnj;ggGCR7$k%_ACnj?M4g7KtI(ShI@LVYdoLl zV_ZHzyJX7)9IcW$1}2}X^LakTeSsLy$GC3*6G0AH5zJLCyEZBDPx0Q#8VoR*KJl73 zpB|LNKg9=x`Fv>NpW*{$D{kVS;)B9JA;rc&#Rt1TQk%p-#fK!%hBk?Rir2|NR;?KS z6dxu;u&x#3pW?#<+$HMKtr-6lA0d<%{}dnTj)aaJ6YCT|O!M=5@@!&p^K1e_o=uYS zY+@-VDbFULxZEJtDL`{LgQVs*)(Oemz{+Q=llv2}0Gl8O(^I5utP{=&amvYUI(ztN zq=r^uUx&jLn87;q0zG@7TX1zl^dtI=WX^~sl-vXk4w&PrLk@B|p#hXsZFk{Md_AYr z$&mB&qFff;mfv}cpU9L;(9}P)AmxuwXGoxu@M|NPE=#ov1>~SP_1>;QaoxGRI z&9{a4S8q?DcO}m8KIV#`Azi@0>!EGB71oU?K|kR98M@;yA)yKqT>-g};q`~LGL-T12t@5m766MeI|@vYs~LcHkd3~`9! zh0+YF?j@e49xY^5yBxIiHEdNcVWTM;wLcuAS!(|`)_yT8=jU%@>(sRzfE;BP0P^Vf zx-QIiyb0uWfUc`oEl@YGPoDtwFgXpY*QguGc^}kUfYuChSqKQZY9x0s`|CCA1}!Z=VVCz^xvg=;Ps-F;t&~#V$!;7{J~^?Hw8a5akB*sQ8^K; zBlwY@L4UI`Dx?Gsq!*AbP5DIh3<;49P1){m|AQ@*Q@*mt zUQ;yt?<-V|BiM}geb(bBJ?CXcpXo`eXk13F<{Y~+``XKaxy+~C!22kNhDcZDAn*?O z;ALn8j5d84h*}8%m>OZdi&XHq>qpUr4WtaIeumOdvATs%A$tM!+_Flwa4C{F76^MSW;XCi{l5~ivdzxJ1K4@$fW>` zu=ec#vw&}=2%DmVw8S+auK>u9=p-$|@S8iyV#{=vmg$bU(HS5ubTx_%x%0dg;iTt` zK^z6&p#ct^#rHOk1!p5tXK~`zZL_)JP?pZYl*(^1^i4LY-tuS$S2A;`cxFIv059i* z2yrNCYbOgWg6@{NTMW(r%xwm#>2_9Bx;4*V7 z6p6)j!~pNcmKnx7NS*EP&E(*xx5tNrJr->`3=p3LVgrz+B={Eh4j?y>SOnr9KwbrO zTMZ(JnWg~Uc+_SnkQ%^n7P8Y8l15T23O`Jf4`8V%z68>L28iNYfiOT%%6|&Tqa2 zrKCS(pIthD&hj%FSth{NWkva^nLjH$ISZ;{%Cp#{vK!$O?)Z zA4rT*6Yzmd0xPx|rTIFR{E5lN9}??`ts?v(hcj8>*#rI%7^-5{AHu$#8BB0rKI%bS zpq0*#&Sb=Ppfor?8i=0))&62}aCCl`g2o$?;GiA#10|kK{{uX zk>L!9WjI3;Ly*|fIz#>n+|Lu+@P)htT=^N>3SS7z2&Swrq%BgCer|)|3n7u`=i7Do zLRfNc`^v4$9F!6-YxR5$bJR!v0&@Af-Aq7uJj9K6b z@gqxjc1@^FfB`L0Ijn&m7K0l9Z!&^ck z=x34emQXC}=W%U#OSm4yqzT|Hp|a!<<1Glb!0|y`wXzNrHYN@aS_cX# z$7y99D73=osJtv>I2j;T3{f#^g&r2vCG9{t0Lrw|;C$k$m35#{3resK6zT~&t*iru zX-Quz>p)?)BHt0#fx?!8110Yda0#~b1luFVV&OnJ5B%7rFb58lQmg_Ao{Q?$2L%oQ z5|Rtc2=RehB^YpAd0ZO~6n+Cg-_PUPaG?AEqR7wV+Hjyytjy2j+Hj!!3?k*{acwwI zNVN6yxHcRp6l>?_acwwImSZ*Pel)994ppY2h z=W%T~P)LmS^SCw~C?v-FJHjY9Q2qsCvY*Gb;XolV%g^K5aG;Qw=jU;4I8c~pu|LLY zzYyb8T;Z2DnJ?nsisD6upU1V~Kq0Z&&*R!~pxg-Jtdw=2Oarmg&v;ijPzs`W#_;pF zHXJDQj^5_yacwwIS|MeZpU1V~K;g96!w>D^xb{fA1ADH*9@i$ZuhckDx+2FLt*rxv z&2e#MYwJK6gruF7t*rxPJXKe`P_EojE4wN})r#GrvA2S(2DZ01@ zg}vXswRNEQFn|vBJJNHYu$wd;D6>5W3OPPHP+D6D3jeLsyxP&mfpP%E;@Z*1f$}qm z6}7Fc1BJG)uWfA|D0iWI;6UkU9Vj_4$#4B9NtmGg+@ZmL!eJd$F^a)|!U5eS?LQgK zOgya({|Rv=QxN`>StKy6sg<})ta6ng9b6G-9K-cAl{ z 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

64a~B|f3ug% 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 z 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 z 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

~>Twnl3BNk+v&O`xx6;c+W85~ucC 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

mgphFZrlU>t7#VNXc@ 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 HTl4<`JTJDT literal 0 HcmV?d00001 diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/main.cpp b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/main.cpp new file mode 100644 index 0000000..0af4178 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/main.cpp @@ -0,0 +1,190 @@ +#include +#include +#include + +#include "sim/sim.h" +#include "simavr/simavr.h" + +void printHelp () { + printf("simuc V1.0.0 (%s,%s)\n", __DATE__, __TIME__); + printf("usage: simuc [options] elf-file\n\n"); + printf(" available options:\n"); + printf(" --board ... set board (arduino, sure, evws1)\n"); + printf(" --sync sync elapsed µC-time with real time\n\n"); + printf(" --mmcu ... set target device type\n"); + printf(" --frequency ... set target frequency in Hz\n"); + printf(" --pc ... set start program counter (default is 0)\n"); + printf(" --vcc ... set voltage VCC in Volt\n"); + printf(" --avcc ... set voltage AVCC in Volt\n"); + printf(" --aref ... set voltage AREF in Volt\n\n"); + printf(" example:\n"); + printf(" simuc --mmcu atmega328p --frequency 16000000 --pc 0x7000 a.out\n\n"); + printf(" simuc --board arduino a.out\n\n"); +} + +int main (int argc, char **argv) { + struct StartParameters params = { + filename: NULL, + gdbPort: -1, + frequency: -1, + mmcu: NULL, + board: BoardUnknown, + vcc: -1, + avcc: -1, + aref: -1 + }; + + if (argc <= 1) { + printHelp(); + return 1; + } + + for (int i = 1; i < argc; i++) { + if (argv[i][0] == '-') { + if (strcmp(argv[i], "--help") == 0) { + printHelp(); + return 0; + } else if (strcmp(argv[i], "--board") == 0 && argc >= (i + 1)) { + i++; + if (strcmp("arduino", argv[i]) == 0) { + params.board = BoardNano; + params.mmcu = "atmega328p"; + params.frequency = 16000000; + params.vcc = 5000; + params.avcc = 5000; + params.aref = 2500; + } else if (strcmp("sure", argv[i]) == 0) { + params.board = BoardSure; + params.mmcu = "atmega16"; + params.frequency = 12000000; + params.vcc = 5000; + params.avcc = 5000; + params.aref = 2500; + } else if (strcmp("evws1", argv[i]) == 0) { + params.board = BoardEWS1; + params.mmcu = "atmega324p"; + params.frequency = 20000000; + params.vcc = 5000; + params.avcc = 5000; + params.aref = 2500; + } else { + fprintf(stderr, "ERROR: invalid board %s, use --help to show usage\n\n", argv[i]); + return 1; + } + + } else if (strcmp(argv[i], "--mmcu") == 0) { + params.mmcu = argv[++i]; + } else if (strcmp(argv[i], "--port") == 0) { + sscanf(argv[++i], "%d", ¶ms.gdbPort); + } else if (strcmp(argv[i], "--frequency") == 0) { + sscanf(argv[++i], "%" PRIu64, ¶ms.frequency); + } else if (strcmp(argv[i], "--pc") == 0) { + i++; + if (argv[i][0] == '0' && argv[i][1] == 'x') { + sscanf(&argv[i][2], "%x", ¶ms.pc); + } else { + sscanf(argv[++i], "%d", ¶ms.pc); + } + } else if (strcmp(argv[i], "--vcc") == 0) { + sscanf(argv[++i], "%d", ¶ms.vcc); + } else if (strcmp(argv[i], "--avcc") == 0) { + sscanf(argv[++i], "%d", ¶ms.avcc); + } else if (strcmp(argv[i], "--aref") == 0) { + sscanf(argv[++i], "%d", ¶ms.aref); + } else { + fprintf(stderr, "ERROR: invalid option %s, use --help to show usage\n\n", argv[i]); + return 1; + } + continue; + } + params.filename = argv[i]; + break; + } + + if (params.filename == NULL) { + printf("ERROR: missing target elf file, use --help to show usage\n\n"); + return 1; + } + + init(¶ms); + if (errno == 1) { + return 1; + } + printf("init done - press key to start\n"); + getchar(); + start(); + + // int cnt = 0; + char *line = NULL; + size_t size = 0; + while (1) { + // struct SimAvrEvent ev = waitForEvent(); + // printf("%10.03lf: event %s (%d) received \r", ev.cycle / 20E6, eventText((EnumSimEvent)ev.event), ev.event); + // fflush(stdout); + // if (++cnt == 10000) { + // stop(); + // shutdown(); + // break; + // } + + if (getline(&line, &size, stdin) > 0) { + const char *commands[] = { "interrupt", "continue", "stack" }; + try { + int foundIndex = -1; + int foundCnt = 0; + size_t length = strlen(line) - 1; + if (length > 0 && size >= (length + 1)) { + line[length] = 0; + for (long unsigned int i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) { + const char *cmd = commands[i]; + size_t max = strlen(cmd); + bool ok = true; + for (size_t j = 0; j < length; j++) { + if (j >= max || line[j] != cmd[j]) { + ok = false; + break; + } + } + if (ok) { + foundCnt++; + foundIndex = i; + } + } + } + // printf("foundCnt=%d foundIndex=%d command=%s\n", foundCnt, foundIndex, foundIndex >= 0 ? commands[foundIndex] : ""); + if (foundCnt == 1 || length == 0) { + setCommand((EnumSimAvrCommand)(foundCnt > 0 ? foundIndex + 2 : 1), NULL); + while (1) { + struct SimAvrEvent ev = waitForEvent(); + if (ev.event == EventCommandExecuted) { + break; + } + } + + } else { + printf("invalid command, valid commands are for status and:"); + for (long unsigned int i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) { + printf(" %s", commands[i]); + } + printf("\n"); + continue; + } + + } catch (std::exception& e) { + printf("ERROR\n"); + } + + } + + } + while (1) { + struct SimAvrEvent ev = waitForEvent(); + printf("event %s (%d) received\n", eventText((EnumSimEvent)ev.event), ev.event); + if (ev.event == EventShutdown) { + break; + } + } + + usleep(10000); + return 0; +} \ No newline at end of file diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/sim/error.cpp b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/sim/error.cpp new file mode 100644 index 0000000..f59ddbd --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/sim/error.cpp @@ -0,0 +1,18 @@ +#include "error.h" +#include + +std::string error (const char *location, const char *format, ...) { + va_list args; + va_start (args, format); + int length = std::vsnprintf (NULL, 0, format, args); + va_end (args); + + va_start (args, format); + char* str = new char[length + 1]; // one more character for null terminator + std::vsnprintf (str, length + 1, format, args); + std::string rv = "Error at " + std::string(location) + " -> " + str; + delete[] str; + va_end (args); + + return rv; +} diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/sim/error.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/sim/error.h new file mode 100644 index 0000000..80d5682 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/sim/error.h @@ -0,0 +1,11 @@ +#ifndef ERROR_H +#define ERROR_H + +#include + +#define STRINGIFY(x) #x +#define TOSTRING(x) STRINGIFY(x) +#define AT __FILE__ ":" TOSTRING(__LINE__) +std::string error (const char *location, const char *format, ...); + +#endif // ERROR_H diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/sim/sim.cpp b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/sim/sim.cpp new file mode 100644 index 0000000..32a23b6 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/sim/sim.cpp @@ -0,0 +1,282 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "sim.h" +#include "error.h" + + + +// https://github.com/java-native-access/jna/blob/master/www/CallbacksAndClosures.md#callbacks-function-pointers-and-closures + + +int SIGUSR1 = 30; + +// avr_t * avr = NULL; +SimAvr simavr; +std::string lastErrorMessage; + +static int fdStdOut = -1, fdStdErr = -1; +// static fpos_t posStdOut, posStdErr; + +void switchStdOut (const char * filename) { + fflush(stdout); + // fgetpos(stdout, &posStdOut); + if (filename == NULL) { + int fd = open("/dev/null", O_WRONLY); + fdStdOut = dup2(fd, fileno(stdout)); + } else { + fdStdOut = dup(fileno(stdout)); + } +} + +void switchStdErr (const char * filename) { + fflush(stderr); + // fgetpos(stderr, &posStdErr); + if (filename == NULL) { + int fd = open("/dev/null", O_WRONLY); + fdStdErr = dup2(fd, fileno(stderr)); + } else { + fdStdErr = dup(fileno(stderr)); + } +} + +void revertStdErrOut () { + if (fdStdOut >= 0) { + fflush(stdout); + dup2(fdStdOut, fileno(stdout)); + close(fdStdOut); + fdStdOut = -1; + clearerr(stdout); + // fsetpos(stdout, &posStdOut); + } + if (fdStdErr >= 0) { + fflush(stderr); + dup2(fdStdErr, fileno(stderr)); + close(fdStdErr); + fdStdErr = -1; + clearerr(stderr); + // fsetpos(stderr, &posStdErr); + } +} + +const char * lastError () { + return lastErrorMessage.c_str(); +} + + +// static void handleWritePortB (struct avr_t * avr, __attribute__((unused)) avr_io_addr_t addr, uint8_t v, SimAvr *simavr) { +// static int value = 0; +// if (value != v) { +// value = v; +// if (simavr != NULL) { +// if ((value << PORTB0) != 0) { +// simavr->addEvent(EventLedOn); +// } else { +// simavr->addEvent(EventLedOff); +// } +// } +// } +// } + +std::vector gdbFromUartBuffer; +std::vector gdbToUartBuffer; + +__attribute__((unused)) static void fromGdbUart (uint8_t b) { + static int cnt = 0; + if (b == '$') { + cnt = 1; + } else if (cnt > 0 && b == '#') { + cnt = -1; + } else if (cnt < 0) { + cnt--; + } + gdbFromUartBuffer.push_back(b); + + if (cnt <= -3 || (cnt == 0 && b == '+')) { + printf("\n\rgdb-uart OUT -> "); + for (uint8_t c : gdbFromUartBuffer) { + putchar(c); + } + printf("\n\r"); + gdbFromUartBuffer.clear(); + } +} + +__attribute__((unused)) static void toGdbUart (uint8_t b) { + static int cnt = 0; + if (b == '$') { + cnt = 1; + } else if (cnt > 0 && b == '#') { + cnt = -1; + } else if (cnt < 0) { + cnt--; + } + gdbToUartBuffer.push_back(b); + + if (cnt <= -3 || (cnt == 0 && b == '+')) { + printf("\n\rgdb-uart IN <-- "); + for (uint8_t c : gdbToUartBuffer) { + putchar(c); + } + printf("\n\r"); + gdbToUartBuffer.clear(); + } + +} + +void init (struct StartParameters *param) { + try { + // switchStdOut(NULL); + // switchStdErr(NULL); + // std::cout.rdbuf(0); + // std::cerr.rdbuf(0); + const char *filename = param->filename != NULL + ? param->filename + // : "../gdb-stub-sm_atmega324p/sim/dist/gdb-stub-sm_atmega324p.axf"; + : "../gdb-stub-sm_atmega324p/sim/dist/gdb-stub-sm_atmega324p.axf"; + printf("firmware file \"%s\"\n", filename); + simavr.load(param); + if (strcmp(simavr.getTargetDeviceName(), "atmega324p") != 0) { + std::logic_error(error(AT, "invalid target device %s", simavr.getTargetDeviceName())); + } + + simavr.setUartDumpEnabled(false); + // simavr.registerIoWrite(PORTB, handleWritePortB); + simavr.setUartPtyEnabled(0, true); + int uartCnt = 1; + if (strcmp(simavr.getTargetDeviceName(), "atmega324p") == 0) { + simavr.setUartPtyEnabled(1, true); + simavr.setUartPtyHook(1, fromGdbUart, toGdbUart); + uartCnt = 2; + } + // printf("uart0 -> picocom --imap lfcrlf -b 115200 %s\n", simavr.getUartPtyDeviceName(0)); + // printf("uart1 -> picocom --imap lfcrlf -b 115200 %s\n", simavr.getUartPtyDeviceName(1)); + + printf("device %s\n", simavr.getTargetDeviceName()); + printf("frequency %.2lfMHz\n", simavr.getTargetFrequency() / 1E6); + + for (int i = 0; i < uartCnt; i++) { + char s[128]; + snprintf(s, 128, "/tmp/sim-megaavr-%s-uart%1d", simavr.getTargetDeviceName(), i); + FILE *f = fopen(s, "w"); + if (f == NULL) { + std::logic_error(error(AT, "cannot write file %s", s)); + } + printf("uart%1d -> picocom %s (see file %s)\n", i, simavr.getUartPtyDeviceName(i), s); + fprintf(f, "%s\n", simavr.getUartPtyDeviceName(i)); + fclose(f); + } + + } catch (std::exception& e) { + lastErrorMessage = "init() fails, caused by " + std::string(e.what()); + std::cerr << lastErrorMessage << "\n"; + errno = 1; + } +} + +void shutdown () { + try { + simavr.shutdown(); + } catch (std::exception& e) { + lastErrorMessage = "shutdown() fails, caused by " + std::string(e.what()); + std::cerr << lastErrorMessage << "\n"; + errno = 1; + } +} + +void start () { + try { + simavr.start(); + + } catch (std::exception& e) { + lastErrorMessage = "start() fails, caused by " + std::string(e.what()); + std::cerr << lastErrorMessage << "\n"; + errno = 1; + } +} + +void stop () { + try { + simavr.stop(); + + } catch (std::exception& e) { + lastErrorMessage = "stop() fails, caused by " + std::string(e.what()); + std::cerr << lastErrorMessage << "\n"; + errno = 1; + } +} + +void setCommand (EnumSimAvrCommand cmd, void *param) { + try { + simavr.setCommand(cmd, param); + + } catch (std::exception& e) { + lastErrorMessage = "setCommand(..) fails, caused by " + std::string(e.what()); + std::cerr << lastErrorMessage << "\n"; + errno = 1; + throw e; + } + +} + +void addEvent (EnumSimEvent event) { + try { + simavr.addEvent(event); + + } catch (std::exception& e) { + lastErrorMessage = "addEvent(..) fails, caused by " + std::string(e.what()); + std::cerr << lastErrorMessage << "\n"; + errno = 1; + } +} + +void setTimeSync (bool sync) { + try { + simavr.setTimeSync(sync); + + } catch (std::exception& e) { + lastErrorMessage = "setTimeSync() fails, caused by " + std::string(e.what()); + std::cerr << lastErrorMessage << "\n"; + errno = 1; + } +} + +struct SimAvrStatus getStatus () { + return simavr.getStatus();; +} + +struct SimAvrEvent waitForEvent () { + return simavr.waitForEvent(); +} + +const char *eventText (EnumSimEvent event) { + const char *rv = simavr.eventText((EnumSimAvrEvent)event); + if (rv != NULL) { + return rv; + } else { + switch (event) { + case EventLedOff: return "LedOff"; + case EventLedOn: return "LedOn"; + default: return "?"; + } + } +} diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/sim/sim.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/sim/sim.h new file mode 100644 index 0000000..d980f26 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/sim/sim.h @@ -0,0 +1,43 @@ +#ifndef SIM_H +#define SIM_H + +#include "../simavr/simavr.h" + +// #define _AVR_IO_H_ +// #define _SFR_IO8(reg) (0x20 + reg) +// #include "iom324p.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + EventInterrupt = 1, + EventLedOff = 10, + EventLedOn = 11 +} EnumSimEvent; + + + +extern void init (struct StartParameters *param); +extern void shutdown (); +extern const char * lastError (); +extern void start (); +extern void stop (); +extern void setCommand (EnumSimAvrCommand cmd, void *param); +extern void addEvent (EnumSimEvent event); +extern void setTimeSync (bool sync); +extern struct SimAvrStatus getStatus (); +extern struct SimAvrEvent waitForEvent (); +extern const char *eventText (EnumSimEvent event); + +typedef void (*NotificationListener)(char *, int); +void callbackTrigger(const NotificationListener l); +void getDeviceRandomStatus(char *answer, int sizeOfChars); +int randNum( int min, int max); + +#ifdef __cplusplus +} +#endif + +#endif // SIM_H diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/simavr/parts/fifo_declare.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/simavr/parts/fifo_declare.h new file mode 100644 index 0000000..8a3b2fb --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/simavr/parts/fifo_declare.h @@ -0,0 +1,189 @@ +/* + fido_declare.h + Copyright (C) 2003-2012 Michel Pollet + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* + * FIFO helpers, aka circular buffers + * + * these macros define accessories for FIFOs of any name, type and + * any (power of two) size + */ + +#ifndef __FIFO_DECLARE__ +#define __FIFO_DECLARE__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + doing a : + DECLARE_FIFO(uint8_t, myfifo, 128); + + will declare : + enum : myfifo_overflow_f + type : myfifo_t + functions: + // write a byte into the fifo, return 1 if there was room, 0 if there wasn't + int myfifo_write(myfifo_t *c, uint8_t b); + // reads a byte from the fifo, return 0 if empty. Use myfifo_isempty() to check beforehand + uint8_t myfifo_read(myfifo_t *c); + int myfifo_isfull(myfifo_t *c); + int myfifo_isempty(myfifo_t *c); + // returns number of items to read now + uint16_t myfifo_get_read_size(myfifo_t *c); + // read item at offset o from read cursor, no cursor advance + uint8_t myfifo_read_at(myfifo_t *c, uint16_t o); + // write b at offset o compared to current write cursor, no cursor advance + void myfifo_write_at(myfifo_t *c, uint16_t o, uint8_t b); + + In your .c you need to 'implement' the fifo: + DEFINE_FIFO(uint8_t, myfifo) + + To use the fifo, you must declare at least one : + myfifo_t fifo = FIFO_NULL; + + while (!myfifo_isfull(&fifo)) + myfifo_write(&fifo, 0xaa); + .... + while (!myfifo_isempty(&fifo)) + b = myfifo_read(&fifo); + */ + +#include + +#if __AVR__ +#define FIFO_CURSOR_TYPE uint8_t +#define FIFO_BOOL_TYPE char +#define FIFO_INLINE +#define FIFO_SYNC +#endif + +#ifndef FIFO_CURSOR_TYPE +#define FIFO_CURSOR_TYPE uint16_t +#endif +#ifndef FIFO_BOOL_TYPE +#define FIFO_BOOL_TYPE int +#endif +#ifndef FIFO_INLINE +#define FIFO_INLINE inline +#endif + +/* We should not need volatile */ +#ifndef FIFO_VOLATILE +#define FIFO_VOLATILE +#endif +#ifndef FIFO_SYNC +#define FIFO_SYNC __sync_synchronize() +#endif + +#ifndef FIFO_ZERO_INIT +#define FIFO_ZERO_INIT {0} +#endif +#define FIFO_NULL { FIFO_ZERO_INIT, 0, 0, 0 } + +/* New compilers don't like unused static functions. However, + * we do like 'static inlines' for these small accessors, + * so we mark them as 'unused'. It stops it complaining */ +#ifdef __GNUC__ +#define FIFO_DECL static __attribute__ ((unused)) +#else +#define FIFO_DECL static +#endif + +#define DECLARE_FIFO(__type, __name, __size) \ +enum { __name##_overflow_f = (1 << 0) }; \ +enum { __name##_fifo_size = (__size) }; \ +typedef struct __name##_t { \ + __type buffer[__name##_fifo_size]; \ + FIFO_VOLATILE FIFO_CURSOR_TYPE read; \ + FIFO_VOLATILE FIFO_CURSOR_TYPE write; \ + FIFO_VOLATILE uint8_t flags; \ +} __name##_t + +#define DEFINE_FIFO(__type, __name) \ +FIFO_DECL FIFO_INLINE FIFO_BOOL_TYPE __name##_write(__name##_t * c, __type b)\ +{\ + FIFO_CURSOR_TYPE now = c->write;\ + FIFO_CURSOR_TYPE next = (now + 1) & (__name##_fifo_size-1);\ + if (c->read != next) { \ + c->buffer[now] = b;\ + FIFO_SYNC; \ + c->write = next;\ + return 1;\ + }\ + return 0;\ +}\ +FIFO_DECL FIFO_INLINE FIFO_BOOL_TYPE __name##_isfull(__name##_t *c)\ +{\ + FIFO_CURSOR_TYPE next = (c->write + 1) & (__name##_fifo_size-1);\ + return c->read == next;\ +}\ +FIFO_DECL FIFO_INLINE FIFO_BOOL_TYPE __name##_isempty(__name##_t * c)\ +{\ + return c->read == c->write;\ +}\ +FIFO_DECL FIFO_INLINE __type __name##_read(__name##_t * c)\ +{\ + __type res = FIFO_ZERO_INIT; \ + FIFO_CURSOR_TYPE read = c->read;\ + if (read == c->write)\ + return res;\ + res = c->buffer[read];\ + FIFO_SYNC; \ + c->read = (read + 1) & (__name##_fifo_size-1);\ + return res;\ +}\ +FIFO_DECL FIFO_INLINE FIFO_CURSOR_TYPE __name##_get_read_size(__name##_t *c)\ +{\ + return ((c->write + __name##_fifo_size) - c->read) & (__name##_fifo_size-1);\ +}\ +FIFO_DECL FIFO_INLINE FIFO_CURSOR_TYPE __name##_get_write_size(__name##_t *c)\ +{\ + return (__name##_fifo_size-1) - __name##_get_read_size(c);\ +}\ +FIFO_DECL FIFO_INLINE void __name##_read_offset(__name##_t *c, FIFO_CURSOR_TYPE o)\ +{\ + FIFO_SYNC; \ + c->read = (c->read + o) & (__name##_fifo_size-1);\ +}\ +FIFO_DECL FIFO_INLINE __type __name##_read_at(__name##_t *c, FIFO_CURSOR_TYPE o)\ +{\ + return c->buffer[(c->read + o) & (__name##_fifo_size-1)];\ +}\ +FIFO_DECL FIFO_INLINE void __name##_write_at(__name##_t *c, FIFO_CURSOR_TYPE o, __type b)\ +{\ + c->buffer[(c->write + o) & (__name##_fifo_size-1)] = b;\ +}\ +FIFO_DECL FIFO_INLINE void __name##_write_offset(__name##_t *c, FIFO_CURSOR_TYPE o)\ +{\ + FIFO_SYNC; \ + c->write = (c->write + o) & (__name##_fifo_size-1);\ +}\ +FIFO_DECL FIFO_INLINE void __name##_reset(__name##_t *c)\ +{\ + FIFO_SYNC; \ + c->read = c->write = c->flags = 0;\ +}\ +struct __name##_t + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/simavr/parts/uart_pty.c b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/simavr/parts/uart_pty.c new file mode 100644 index 0000000..a283fef --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/simavr/parts/uart_pty.c @@ -0,0 +1,371 @@ +/* + uart_pty.c + + Copyright 2008, 2009 Michel Pollet + + 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 +#include +#include +#include +#include +#include +#ifdef __APPLE__ +#include +#elif defined (__FreeBSD__) +#include +#include +#include +#include +#else +#include +#endif + +#include "uart_pty.h" +#include +#include +#include + +DEFINE_FIFO(uint8_t,uart_pty_fifo); + +//#define TRACE(_w) _w +#ifndef TRACE +#define TRACE(_w) +#endif + +TRACE(static const char * +uart_pty_toPrintableChar( + uint32_t value) +{ + static char rv[2] = ""; + if (value >= ' ' && value <= 126) { + rv[0] = (char)value; + rv[1] = 0; + } else if (value == '\n') { + return "\\n"; + } else if (value == '\r') { + return "\\r"; + } else { + rv[0] = 0; + } + return rv; +}) + + +/* + * called when a byte is send via the uart on the AVR + */ +static void +uart_pty_in_hook( + struct avr_irq_t * irq, + uint32_t value, + void * param) +{ + uart_pty_t * p = (uart_pty_t*)param; + TRACE(printf("uart_pty_in_hook %02x %s\n", value, uart_pty_toPrintableChar(value));) + if (p->port[0].crlf && value == '\n') { + uart_pty_fifo_write(&p->port[0].in, '\r'); + } + uart_pty_fifo_write(&p->pty.in, value); + if (p->port[0].hook_from_uart != NULL) { + p->port[0].hook_from_uart(value); + } else if (p->hook_from_uart != NULL) { + p->hook_from_uart(value); + } + + if (p->tap.s) { + if (p->tap.crlf && value == '\n') + uart_pty_fifo_write(&p->tap.in, '\r'); + uart_pty_fifo_write(&p->tap.in, value); + } +} + +// try to empty our fifo, the uart_pty_xoff_hook() will be called when +// other side is full +static void +uart_pty_flush_incoming( + uart_pty_t * p) +{ + while (p->xon && !uart_pty_fifo_isempty(&p->pty.out)) { + TRACE(int r = p->pty.out.read;) + uint8_t byte = uart_pty_fifo_read(&p->pty.out); + TRACE(printf("uart_pty_flush_incoming send r %03d:%02x\n", r, byte);) + avr_raise_irq(p->irq + IRQ_UART_PTY_BYTE_OUT, byte); + + if (p->tap.s) { + if (p->tap.crlf && byte == '\n') + uart_pty_fifo_write(&p->tap.in, '\r'); + uart_pty_fifo_write(&p->tap.in, byte); + } + } + if (p->tap.s) { + while (p->xon && !uart_pty_fifo_isempty(&p->tap.out)) { + uint8_t byte = uart_pty_fifo_read(&p->tap.out); + if (p->tap.crlf && byte == '\r') { + uart_pty_fifo_write(&p->tap.in, '\n'); + } + if (byte == '\n') + continue; + uart_pty_fifo_write(&p->tap.in, byte); + avr_raise_irq(p->irq + IRQ_UART_PTY_BYTE_OUT, byte); + } + } +} + +avr_cycle_count_t +uart_pty_flush_timer( + struct avr_t * avr, + avr_cycle_count_t when, + void * param) +{ + uart_pty_t * p = (uart_pty_t*)param; + + uart_pty_flush_incoming(p); + /* always return a cycle NUMBER not a cycle count */ + return p->xon ? when + avr_hz_to_cycles(p->avr, 1000) : 0; +} + +/* + * Called when the uart has room in it's input buffer. This is called repeateadly + * if necessary, while the xoff is called only when the uart fifo is FULL + */ +static void +uart_pty_xon_hook( + struct avr_irq_t * irq, + uint32_t value, + void * param) +{ + uart_pty_t * p = (uart_pty_t*)param; + TRACE(if (!p->xon) printf("uart_pty_xon_hook\n");) + p->xon = 1; + + uart_pty_flush_incoming(p); + + // if the buffer is not flushed, try to do it later + if (p->xon) + avr_cycle_timer_register(p->avr, avr_hz_to_cycles(p->avr, 1000), + uart_pty_flush_timer, param); +} + +/* + * Called when the uart ran out of room in it's input buffer + */ +static void +uart_pty_xoff_hook( + struct avr_irq_t * irq, + uint32_t value, + void * param) +{ + uart_pty_t * p = (uart_pty_t*)param; + TRACE(if (p->xon) printf("uart_pty_xoff_hook\n");) + p->xon = 0; + avr_cycle_timer_cancel(p->avr, uart_pty_flush_timer, param); +} + +static void * +uart_pty_thread( + void * param) +{ + uart_pty_t * p = (uart_pty_t*)param; + + while (1) { + fd_set read_set, write_set; + int max = 0; + FD_ZERO(&read_set); + FD_ZERO(&write_set); + + for (int ti = 0; ti < 2; ti++) if (p->port[ti].s) { + // read more only if buffer was flushed + if (p->port[ti].buffer_len == p->port[ti].buffer_done) { + FD_SET(p->port[ti].s, &read_set); + max = p->port[ti].s > max ? p->port[ti].s : max; + } + if (!uart_pty_fifo_isempty(&p->port[ti].in)) { + FD_SET(p->port[ti].s, &write_set); + max = p->port[ti].s > max ? p->port[ti].s : max; + } + } + + // short, but not too short interval + struct timeval timo = { 0, 500 }; + int ret = select(max+1, &read_set, &write_set, NULL, &timo); + + if (ret < 0) + break; + + for (int ti = 0; ti < 2; ti++) if (p->port[ti].s) { + if (FD_ISSET(p->port[ti].s, &read_set)) { + ssize_t r = read(p->port[ti].s, p->port[ti].buffer, + sizeof(p->port[ti].buffer)-1); + p->port[ti].buffer_len = r; + p->port[ti].buffer_done = 0; + TRACE(if (!p->port[ti].tap) + hdump("pty recv", p->port[ti].buffer, r);) + } + if (p->port[ti].buffer_done < p->port[ti].buffer_len) { + // write them in fifo + while (p->port[ti].buffer_done < p->port[ti].buffer_len && + !uart_pty_fifo_isfull(&p->port[ti].out)) { + int index = p->port[ti].buffer_done++; + TRACE(int wi = p->port[ti].out.write;) + uart_pty_fifo_write(&p->port[ti].out, + p->port[ti].buffer[index]); + TRACE(printf("w %3d:%02x (%d/%d) %s\n", + wi, p->port[ti].buffer[index], + p->port[ti].out.read, + p->port[ti].out.write, + p->xon ? "XON" : "XOFF");) + if (p->port[ti].hook_to_uart != NULL) { + p->port[ti].hook_to_uart(p->port[ti].buffer[index]); + } else if (p->hook_to_uart != NULL) { + p->hook_to_uart(p->port[ti].buffer[index]); + } + } + } + if (FD_ISSET(p->port[ti].s, &write_set)) { + uint8_t buffer[512]; + // write them in fifo + uint8_t * dst = buffer; + while (!uart_pty_fifo_isempty(&p->port[ti].in) && + (dst - buffer) < sizeof(buffer)) { + *dst = uart_pty_fifo_read(&p->port[ti].in); + dst++; + } + size_t len = dst - buffer; + TRACE(size_t r =) write(p->port[ti].s, buffer, len); + TRACE(if (!p->port[ti].tap) hdump("pty send", buffer, r);) + } + } + /* DO NOT call this, this create a concurency issue with the + * FIFO that can't be solved cleanly with a memory barrier + uart_pty_flush_incoming(p); + */ + } + return NULL; +} + +static const char * irq_names[IRQ_UART_PTY_COUNT] = { + [IRQ_UART_PTY_BYTE_IN] = "8avr = avr; + p->irq = avr_alloc_irq(&avr->irq_pool, 0, IRQ_UART_PTY_COUNT, irq_names); + avr_irq_register_notify(p->irq + IRQ_UART_PTY_BYTE_IN, uart_pty_in_hook, p); + + const int hastap = (getenv("SIMAVR_UART_TAP") && atoi(getenv("SIMAVR_UART_TAP"))) || + (getenv("SIMAVR_UART_XTERM") && atoi(getenv("SIMAVR_UART_XTERM"))); + p->hastap = hastap; + p->hook_from_uart = NULL; + p->hook_to_uart = NULL; + + for (int ti = 0; ti < 1 + hastap; ti++) { + int m, s; + + if (openpty(&m, &s, p->port[ti].slavename, NULL, NULL) < 0) { + fprintf(stderr, "%s: Can't create pty: %s", __FUNCTION__, strerror(errno)); + return; + } + struct termios tio; + tcgetattr(m, &tio); + cfmakeraw(&tio); + tio.c_cflag &= ~(ECHO | ECHONL); // no input echo + // tio.c_oflag |= (OPOST | ONLCR); // LF -> CRLF + tcsetattr(m, TCSANOW, &tio); + p->port[ti].s = m; + p->port[ti].tap = ti != 0; + // p->port[ti].crlf = ti != 0; + p->port[ti].crlf = 1; + p->port[ti].hook_from_uart = NULL; + p->port[ti].hook_to_uart = NULL; + if (ti > 0) { + printf("uart_pty_init %s on port *** %s ***\n", + ti == 0 ? "bridge" : "tap", p->port[ti].slavename); + } + } + + pthread_create(&p->thread, NULL, uart_pty_thread, p); + +} + +void +uart_pty_stop( + uart_pty_t * p) +{ + puts(__func__); + pthread_kill(p->thread, SIGINT); + for (int ti = 0; ti < 2; ti++) + if (p->port[ti].s) + close(p->port[ti].s); + void * ret; + pthread_join(p->thread, &ret); +} + +void +uart_pty_connect( + uart_pty_t * p, + char uart) +{ + // disable the stdio dump, as we are sending binary there + uint32_t f = 0; + avr_ioctl(p->avr, AVR_IOCTL_UART_GET_FLAGS(uart), &f); + f &= ~AVR_UART_FLAG_STDIO; + avr_ioctl(p->avr, AVR_IOCTL_UART_SET_FLAGS(uart), &f); + + avr_irq_t * src = avr_io_getirq(p->avr, AVR_IOCTL_UART_GETIRQ(uart), UART_IRQ_OUTPUT); + avr_irq_t * dst = avr_io_getirq(p->avr, AVR_IOCTL_UART_GETIRQ(uart), UART_IRQ_INPUT); + avr_irq_t * xon = avr_io_getirq(p->avr, AVR_IOCTL_UART_GETIRQ(uart), UART_IRQ_OUT_XON); + avr_irq_t * xoff = avr_io_getirq(p->avr, AVR_IOCTL_UART_GETIRQ(uart), UART_IRQ_OUT_XOFF); + + if (src && dst) { + avr_connect_irq(src, p->irq + IRQ_UART_PTY_BYTE_IN); + avr_connect_irq(p->irq + IRQ_UART_PTY_BYTE_OUT, dst); + } + if (xon) + avr_irq_register_notify(xon, uart_pty_xon_hook, p); + if (xoff) + avr_irq_register_notify(xoff, uart_pty_xoff_hook, p); + + for (int ti = 0; ti < 1+(p->hastap?1:0); ti++) if (p->port[ti].s) { + char link[128]; + snprintf(link, sizeof(link), "/tmp/simavr-uart%c%s", uart, ti == 1 ? "-tap" : ""); + unlink(link); + if (symlink(p->port[ti].slavename, link) != 0) { + fprintf(stderr, "WARN %s: Can't create %s: %s", __func__, link, strerror(errno)); + } else { + // printf("%s: %s now points to %s\n", __func__, link, p->port[ti].slavename); + } + } + if (getenv("SIMAVR_UART_XTERM") && atoi(getenv("SIMAVR_UART_XTERM"))) { + char cmd[256]; + sprintf(cmd, "xterm -e picocom -b 115200 %s >/dev/null 2>&1 &", + p->tap.slavename); + system(cmd); + } else { + // printf("note: export SIMAVR_UART_XTERM=1 and install picocom to get a terminal\n"); + } +} diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/simavr/parts/uart_pty.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/simavr/parts/uart_pty.h new file mode 100644 index 0000000..482de7d --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/simavr/parts/uart_pty.h @@ -0,0 +1,90 @@ +/* + uart_pty.h + + Copyright 2012 Michel Pollet + + 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 . + */ + + +#ifndef __UART_PTY_H___ +#define __UART_PTY_H___ + +#include +#include +#include "fifo_declare.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + IRQ_UART_PTY_BYTE_IN = 0, + IRQ_UART_PTY_BYTE_OUT, + IRQ_UART_PTY_COUNT +}; + +DECLARE_FIFO(uint8_t,uart_pty_fifo, 512); + +typedef struct uart_pty_port_t { + unsigned int tap : 1, crlf : 1; + int s; // socket we chat on + char slavename[64]; + uart_pty_fifo_t in; + uart_pty_fifo_t out; + uint8_t buffer[512]; + size_t buffer_len, buffer_done; + void (*hook_from_uart)(uint8_t); + void (*hook_to_uart)(uint8_t); +} uart_pty_port_t, *uart_pty_port_p; + +typedef struct uart_pty_t { + avr_irq_t * irq; // irq list + struct avr_t *avr; // keep it around so we can pause it + + pthread_t thread; + int xon; + int hastap; + + union { + struct { + uart_pty_port_t pty; + uart_pty_port_t tap; + }; + uart_pty_port_t port[2]; + }; + void (*hook_from_uart)(uint8_t); + void (*hook_to_uart)(uint8_t); +} uart_pty_t; + +void +uart_pty_init( + struct avr_t * avr, + uart_pty_t * b); +void +uart_pty_stop(uart_pty_t * p); + +void +uart_pty_connect( + uart_pty_t * p, + char uart); + +#ifdef __cplusplus +} +#endif + +#endif /* __UART_PTY_H___ */ + diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/simavr/semaphore.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/simavr/semaphore.h new file mode 100644 index 0000000..289a45d --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/simavr/semaphore.h @@ -0,0 +1,32 @@ +#ifndef SEMAPHORE_H +#define SEMAPHORE_H + +#include +#include + +class Semaphore { + public: + Semaphore (int count_ = 0) : count(count_) { + } + + inline void notify () { + std::unique_lock lock(mtx); + count++; + //notify the waiting thread + cv.notify_one(); + } + inline void wait () { + std::unique_lock lock(mtx); + while(count == 0) { + //wait on the mutex until notify is called + cv.wait(lock); + } + count--; + } + private: + std::mutex mtx; + std::condition_variable cv; + int count; +}; + +#endif // SEMAPHORE_H diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/simavr/simavr.cpp b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/simavr/simavr.cpp new file mode 100644 index 0000000..ba63390 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/simavr/simavr.cpp @@ -0,0 +1,749 @@ +#include "simavr.h" +#include "../sim/error.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + + +SimAvr::SimAvr () { + memset(&status, 0, sizeof(status)); +} + +SimAvr::~SimAvr () { + if (firmware != NULL) { + free(firmware); + firmware = NULL; + } + if (avr != NULL) { + free(avr); + avr = NULL; + } +} + +void SimAvr::shutdown () { + // if (pthread_mutex_lock(&lock)) { + // throw std::logic_error(error(AT, "shutdown() fails caused by mutex error")); + // } + // cancelThread = true; + // isShutdown = true; + // pthread_mutex_unlock(&lock); + addEvent(EventShutdown); +} + + +void SimAvr::load (struct StartParameters *params) { + if (pthread_mutex_lock(&lock)) { + throw std::logic_error(error(AT, "load() fails caused by mutex error")); + } + try { + if (isShutdown) { + throw std::logic_error(error(AT, "cannot load after simavr shutdown")); + } + if (firmware != NULL) { + throw std::logic_error(error(AT, "firmware already loaded")); + } + + startParameters = params; + firmware = (elf_firmware_t *) malloc(sizeof(elf_firmware_t)); + std::string filename = std::string(params->filename); + if (firmware == NULL || elf_read_firmware(filename.c_str(), firmware) != 0) { + throw std::logic_error(error(AT, "elf_read_firmware() from %s fails", filename.c_str())); + } + if (params->mmcu != NULL) { + strncpy(firmware->mmcu, params->mmcu, sizeof(firmware->mmcu)); + } + if (params->frequency > 0) { + firmware->frequency = (uint32_t)params->frequency; + } + if (params->vcc > 0) { + firmware->vcc = (uint32_t)params->vcc; + } + if (params->avcc > 0) { + firmware->avcc = (uint32_t)params->avcc; + } + if (params->aref > 0) { + firmware->aref = (uint32_t)params->aref; + } + + // strncpy(firmware->mmcu, "atmega324p", sizeof(firmware->mmcu)); + // firmware->frequency = 20000000L; + if (firmware->frequency == 0) { + firmware->frequency = 8000000L; + } + if (firmware->vcc == 0) { + firmware->vcc = 5000; + } + if (firmware->avcc == 0) { + firmware->avcc = 5000; + } + if (firmware->aref == 0) { + firmware->aref = 2500; + } + if (firmware->mmcu[0] == 0) { + throw std::logic_error(error(AT, "missing cpu type, use --mmcu ... to set mmcu manually)", firmware->mmcu)); + } + + avr = avr_make_mcu_by_name(firmware->mmcu); + if (!avr) { + throw std::logic_error(error(AT, "avr_make_mcu_by_name() fails (mmcu=%s)", firmware->mmcu)); + } + if (params->gdbPort > 0) { + avr->gdb_port = params->gdbPort; + } else { + avr->gdb_port = 1234; + } + printf("init with port=%d, mmcu=%s, f=%u, vcc=%d, avcc=%d, aref=%d, pc=0x%04x\n", + avr->gdb_port, firmware->mmcu, firmware->frequency, firmware->vcc, firmware->avcc, firmware->aref, params->pc < 0 ? 0 : params->pc); + status.freqHz = firmware->frequency; + + if (avr_init(avr) != 0) { + throw std::logic_error(error(AT, "avr_init() fails")); + } + + + firmware->eeprom = (uint8_t *)malloc(1024); + for (int i = 0; i < 1024; i++) { + firmware->eeprom[i] = 0xff; + } + firmware->eeprom[0] = 0xf0; + firmware->eesize = 1024; + + avr_load_firmware(avr, firmware); + status.state = StateLoaded; + + avr->fuse[AVR_FUSE_LOW] = 0xe7; + avr->fuse[AVR_FUSE_HIGH] = 0xd8; + avr->fuse[AVR_FUSE_EXT] = 0xff; + avr->lockbits = 0xff; + + avr->gdb_port = 1234; + avr_gdb_init(avr); + if (params->pc >= 0) { + avr->pc = params->pc; + } + + pthread_mutex_unlock(&lock); + + } catch (std::exception& e) { + status.state = StateError; + pthread_mutex_unlock(&lock); + throw; + } + addEvent(EventLoad); +} + +// enabled/disable character output on stdout in case of avr uart write +void SimAvr::setUartDumpEnabled (bool enabled) { + if (avr == NULL) { + throw std::logic_error(error(AT, "setUartDumpEnabled() fails because no avr available")); + } + uint32_t f = 0; + avr_ioctl(avr, AVR_IOCTL_UART_GET_FLAGS('0'), &f); + f = enabled ? f | AVR_UART_FLAG_STDIO : f & ~AVR_UART_FLAG_STDIO; + avr_ioctl(avr, AVR_IOCTL_UART_SET_FLAGS('0'), &f); + avr_ioctl(avr, AVR_IOCTL_UART_GET_FLAGS('1'), &f); + f = enabled ? f | AVR_UART_FLAG_STDIO : f & ~AVR_UART_FLAG_STDIO; + avr_ioctl(avr, AVR_IOCTL_UART_SET_FLAGS('1'), &f); +} + +void SimAvr::registerIoWrite (avr_io_addr_t addr, avrsim_io_write_callback_t callback) { + avr_register_io_write(avr, addr, (avr_io_write_t)callback, this); +} + +void SimAvr::setUartPtyEnabled (int uart, bool enable) { + if (pthread_mutex_lock(&lock)) { + throw std::logic_error(error(AT, "start() fails caused by mutex error")); + } + uart_pty_t *p = NULL; + try { + if (uart < 0 || uart > 1) { + throw std::logic_error(error(AT, "setUartPtyEnabled() fails (invalid uart %d)", uart)); + } + if (enable && uartPty[uart] != NULL) { + throw std::logic_error(error(AT, "enableUartPty() fails (uart %d already enabled)", uart)); + } + if (!enable && uartPty[uart] == NULL) { + throw std::logic_error(error(AT, "enableUartPty() fails (uart %d not enabled)", uart)); + } + if (avr == NULL) { + throw std::logic_error(error(AT, "enableUartPty() fails (avr not ready)")); + } + if (enable) { + p = (uart_pty_t *)malloc(sizeof(uart_pty_t)); + if (p == NULL) { + throw std::logic_error(error(AT, "enableUartPty() fails (malloc fails)")); + } + memset(p, 0, sizeof(uart_pty_t)); + // setenv("SIMAVR_UART_TAP", "1", 1); + uart_pty_init(avr, p); + uart_pty_connect(p, uart + '0'); + uartPty[uart] = p; + } else { + uart_pty_stop(uartPty[uart]); + free(uartPty[uart]); + uartPty[uart] = NULL; + } + pthread_mutex_unlock(&lock); + + } catch (std::exception& e) { + if (p != NULL) { + free(p); + } + status.state = StateError; + pthread_mutex_unlock(&lock); + throw; + } +} + +void SimAvr::setUartPtyHook (int uart, void (*fromUart)(uint8_t), void (*toUart)(uint8_t)) { + if (pthread_mutex_lock(&lock)) { + throw std::logic_error(error(AT, "setUartPtyHook() fails caused by mutex error")); + } + try { + if (uart < 0 || uart > 1) { + throw std::logic_error(error(AT, "setUartPtyHook() fails (invalid uart %d)", uart)); + } + if (uartPty[uart] == NULL) { + throw std::logic_error(error(AT, "setUartPtyHook() fails (uart %d not enabled)", uart)); + } + uartPty[uart]->hook_from_uart = fromUart; + uartPty[uart]->hook_to_uart = toUart; + pthread_mutex_unlock(&lock); + + } catch (std::exception& e) { + status.state = StateError; + pthread_mutex_unlock(&lock); + throw; + } +} + +const char *SimAvr::getUartPtyDeviceName (int uart) { + if (pthread_mutex_lock(&lock)) { + throw std::logic_error(error(AT, "start() fails caused by mutex error")); + } + try { + if (uart < 0 || uart > 1) { + throw std::logic_error(error(AT, "getUartPtyDeviceName() fails (invalid uart %d)", uart)); + } + uart_pty_t *p = uartPty[uart]; + pthread_mutex_unlock(&lock); + return p == NULL ? NULL : p->port[0].slavename; + + } catch (std::exception& e) { + status.state = StateError; + pthread_mutex_unlock(&lock); + throw; + } +} + +const char *SimAvr::getTargetDeviceName () { + if (pthread_mutex_lock(&lock)) { + throw std::logic_error(error(AT, "start() fails caused by mutex error")); + } + try { + if (firmware == NULL) { + throw std::logic_error(error(AT, "getTargetDeviceName() fails (no firmware loaded)")); + } + pthread_mutex_unlock(&lock); + return firmware->mmcu; + + } catch (std::exception& e) { + status.state = StateError; + pthread_mutex_unlock(&lock); + throw; + } +} + +uint32_t SimAvr::getTargetFrequency () { + if (pthread_mutex_lock(&lock)) { + throw std::logic_error(error(AT, "start() fails caused by mutex error")); + } + try { + if (firmware == NULL) { + throw std::logic_error(error(AT, "getTargetDeviceName() fails (no firmware loaded)")); + } + pthread_mutex_unlock(&lock); + return firmware->frequency; + + } catch (std::exception& e) { + status.state = StateError; + pthread_mutex_unlock(&lock); + throw; + } +} + +void SimAvr::start () { + if (pthread_mutex_lock(&lock)) { + throw std::logic_error(error(AT, "start() fails caused by mutex error")); + } + try { + if (isShutdown) { + throw std::logic_error("start() not allowed after shutdown"); + } + if (avrRunThread != NULL) { + throw std::logic_error("simavr already started"); + } + if (avr == NULL) { + throw std::logic_error("avr not ready (check if load done)"); + } + syncTime[0] = !syncTime[1]; + avrRunThread = new std::thread(&SimAvr::avrRun, this); + pthread_mutex_unlock(&lock); + + } catch (std::exception& e) { + status.state = StateError; + pthread_mutex_unlock(&lock); + throw; + } + addEvent(EventStart); +} + + +void SimAvr::stop () { + if (pthread_mutex_lock(&lock)) { + throw std::logic_error(error(AT, "stop() fails caused by mutex error")); + } + try { + if (avrRunThread == NULL) { + throw std::logic_error("simavr not started"); + } + cancelThread = true; + pthread_mutex_unlock(&lock); + + } catch (std::exception& e) { + status.state = StateError; + pthread_mutex_unlock(&lock); + throw; + } + addEvent(EventStop); +} + +void SimAvr::setCommand (EnumSimAvrCommand cmd, void *param) { + if (command != ReadyForNewCommand) { + throw std::logic_error("another command pending"); + } + command = cmd; +} + +void SimAvr::addEvent (int event) { + struct timeval tp; + gettimeofday(&tp, NULL); + SimAvrEvent *p = (SimAvrEvent *)malloc(sizeof(SimAvrEvent)); + if (p != NULL) { + p->epochMillis = tp.tv_sec * 1000 + (long)tp.tv_usec / 1000; + p->event = event; + if (pthread_mutex_lock(&lock)) { + throw std::logic_error(error(AT, "addEvent() fails caused by mutex error")); + } + try { + p->cycle = avr->cycle; + if (!isShutdown) { + events.push_back(p); + eventCount.notify(); + } + pthread_mutex_unlock(&lock); + } catch (std::exception& e) { + status.state = StateError; + pthread_mutex_unlock(&lock); + throw; + } + } +} + + +void SimAvr::setTimeSync (bool sync) { + if (pthread_mutex_lock(&lock)) { + throw std::logic_error(error(AT, "setTimeSync() fails caused by mutex error")); + } + try { + syncTime[1] = sync; + pthread_mutex_unlock(&lock); + } catch (std::exception& e) { + status.state = StateError; + pthread_mutex_unlock(&lock); + throw; + } +} + + +struct SimAvrEvent SimAvr::waitForEvent () { + eventCount.wait(); + + if (pthread_mutex_lock(&lock)) { + throw std::logic_error(error(AT, "waitForEvent() fails caused by mutex error")); + } + try { + struct SimAvrEvent rv = { epochMillis: 0, event: EventUnknown }; + struct SimAvrEvent *p = NULL; + if (events.size() > 0) { + p = events.front(); + rv = *p; + if (p->event != EventShutdown) { + events.pop_front(); + free(p); + } + if (p->event == EventShutdown) { + cancelThread = true; + isShutdown = true; + } + } + pthread_mutex_unlock(&lock); + return rv; + + } catch (std::exception& e) { + status.state = StateError; + pthread_mutex_unlock(&lock); + throw; + } +} + +const char *SimAvr::eventText (EnumSimAvrEvent event) { + switch (event) { + case EventUnknown: return "Unknown"; + case EventShutdown: return "Shutdown"; + case EventLoad: return "Load"; + case EventStart: return "Start"; + case EventStop: return "Stop"; + default: return NULL; + } +} + +struct SimAvrStatus SimAvr::getStatus () { + if (pthread_mutex_lock(&lock)) { + throw std::logic_error(error(AT, "getStatus() fails caused by mutex error")); + } + struct SimAvrStatus rv = status; + pthread_mutex_unlock(&lock); + return rv; +} + +void SimAvr::printCyclesAndElapsedTime () { + uint64_t time = avr->cycle * 1000000000L / avr->frequency; + uint16_t nanos = time % 1000; time = time / 1000; + uint16_t micros = time % 1000; time = time / 1000; + uint16_t millis = time % 1000; time = time / 1000; + uint16_t seconds = time % 1000; time = time / 1000; + printf("cycle %" PRIu64 " = %ds %03dms %03dµs %03dns", avr->cycle, seconds, millis, micros, nanos); +} + +void SimAvr::avrRun () { + long cnt = 0; + int lastAvrState = -1; + _avr_sp_set(avr, 0); + while (1) { + try { + if (avr->state != lastAvrState) { + switch (avr->state) { + case cpu_Stopped: { + printf("\ncpu stopped at 0x%04x on ", avr->pc); + printCyclesAndElapsedTime(); + char sfr[9]; + sfr[7] = avr->sreg[0] ? 'C' : '-'; + sfr[6] = avr->sreg[1] ? 'Z' : '-'; + sfr[5] = avr->sreg[2] ? 'N' : '-'; + sfr[4] = avr->sreg[3] ? 'V' : '-'; + sfr[3] = avr->sreg[4] ? 'S' : '-'; + sfr[2] = avr->sreg[5] ? 'H' : '-'; + sfr[1] = avr->sreg[6] ? 'T' : '-'; + sfr[0] = avr->sreg[7] ? 'I' : '-'; + sfr[8] = 0; + printf(" SFR: %s\n ", sfr); + uint16_t x = 0, y = 0, z = 0; + for (int i = 0; i < 32; i++) { + uint8_t b = avr->data[i]; + printf(" r%02d=%02x", i, b); + switch (i) { + case 0x0f: printf("\n "); break; + case 0x1a: x = (x & 0xff00) | b; break; + case 0x1b: x = (x & 0x00ff) | (b << 8); break; + case 0x1c: y = (y & 0xff00) | b; break; + case 0x1d: y = (y & 0x00ff) | (b << 8); break; + case 0x1e: z = (z & 0xff00) | b; break; + case 0x1f: z = (z & 0x00ff) | (b << 8); break; + } + } + printf("\n X=0x%04x Y=0x%04x Z=0x%04x\n", x, y, z); + + uint16_t sp = _avr_sp_get(avr); + printf(" Stack (SP=0x%04x)", sp); + int printHeader = 1; + for (int i = 0; i < 16; i++) { + uint16_t addr = sp + 1 + i; + if (addr <= avr->ioend) { continue; } + if (addr > avr->ramend) { break; } + if (printHeader) { + printf(" -> SRAM 0x%04x:", addr); + printHeader = 0; + } + uint8_t b = avr_core_watch_read(avr, addr); + printf(" %02x", b); + + } + printf(printHeader ? "\n" : "\n"); + + printf(" Arduino LED L: "); + printf((avr->data[0x24] & 0x20) && (avr->data[0x25] & 0x20) ? "ON\n" : "OFF\n"); + + printf("\n"); + break; + } + case cpu_Sleeping: printf("cpu enter sleep mode at cycle %" PRIu64 "\n", avr->cycle); break; + case cpu_Running: printf("cpu starts running at cycle %" PRIu64 "\n", avr->cycle); break; + case cpu_Step: printf("cpu step\n"); break; + case cpu_StepDone: printf("cpu step done\n"); break; + case cpu_Done: printf("cpu done\n"); break; + case cpu_Crashed: printf("cpu crashed\n"); break; + default: printf("cpu enter unknown mode at cycle %" PRIu64 "\n", avr->cycle); break; + } + lastAvrState = avr->state; + } + + if (startParameters != NULL) { + switch (startParameters->board) { + case BoardNano: { + static int8_t ledL = -1; // pin floating + uint8_t ddrb = avr->data[0x24]; + uint8_t portb = avr->data[0x25]; + int8_t nextLedL = -1; + if (ddrb & 0x20) { + nextLedL = portb & 0x20 ? 1 : 0; + } + if (nextLedL != ledL) { + ledL = nextLedL; + printCyclesAndElapsedTime(); + printf(": LED L = %c\n", ledL ? 'X' : '.'); + } + break; + } + case BoardSure: { + static int8_t led[4] = { -1, -1, -1, -1 }; // pin floating + uint8_t ddra = avr->data[0x3a]; + uint8_t porta = avr->data[0x3b]; + int change = 0; + for (int i = 0; i < 4; i++) { + int8_t nextLed = -1; + if (ddra & (1 << i)) { + nextLed = porta & (1 << i) ? 0 : 1; + } + if (nextLed != led[i]) { + change = 1; + led[i] = nextLed; + } + } + if (change) { + printCyclesAndElapsedTime(); printf(": "); + printf(" LED PA[3210] ="); + for (int i = 3; i >= 0; i--) { + printf(" %c", led[i] ? 'X' : '.'); + } + printf("\n"); + } + break; + } + case BoardEWS1: { + static int8_t led = -1; // pin floating + uint8_t ddrb = avr->data[0x24]; + uint8_t portb = avr->data[0x25]; + int8_t nextLed = -1; + if (ddrb & 0x01) { + nextLed = portb & 0x01 ? 1 : 0; + } + if (nextLed != led) { + led = nextLed; + printCyclesAndElapsedTime(); + printf(": LED1 (PB0) = %c\n", led ? 'X' : '.'); + } + break; + } + default: break; + } + } + + if (cnt <= 0) { + // usleep(10000); + if (pthread_mutex_lock(&lock)) { + throw std::logic_error(error(AT, "avrRun() fails caused by mutex error (1)")); + } + try { + status.cycle = avr->cycle; + status.state = StateRunning; + status.running = true; + switch (avr->state) { + case cpu_Done: status.state = StateDone; break; + case cpu_Running: status.state = StateRunning; break; + case cpu_Crashed: status.state = StateCrashed; break; + default: status.state = StateOthers; break; + } + if (cancelThread) { + cnt = -1; + cancelThread = false; + } else { + if (syncTime[0] != syncTime[1]) { + syncTime[0] = syncTime[1]; + if (syncTime[0]) { + cyclesOnSyncStart = avr->cycle; + struct timeval tp; + gettimeofday(&tp, NULL); + timeMicrosOnSyncStart = tp.tv_usec + (uint64_t)tp.tv_sec * 1000000L; + } else { + cyclesOnSyncStart = -1; + timeMicrosOnSyncStart = 0; + } + } + if (syncTime[0]) { + uint64_t ucMicros = (uint64_t)(status.cycle - cyclesOnSyncStart) * 1000000L / status.freqHz ; + struct timeval tp; + gettimeofday(&tp, NULL); + const uint64_t timeMicros = tp.tv_usec + (uint64_t)tp.tv_sec * 1000000L - timeMicrosOnSyncStart; + + if (ucMicros > 3000000) { + ucMicros++; + } + + int64_t dt = ucMicros - timeMicros; + if (dt > 0) { + int us = dt > INT_MAX ? INT_MAX : (int)dt; + if (us > 1000) { + timeval ts; + ts.tv_sec = 0; + ts.tv_usec = us; + select(0, 0, 0, 0, &ts); + } + } + } + } + if (avr->state == cpu_Done) { + cnt = -1; + } else if (avr->state == cpu_Crashed) { + throw std::logic_error(error(AT, "avr state is cpu_Crashed")); + } + pthread_mutex_unlock(&lock); + + } catch (std::exception& e) { + status.state = StateError; + pthread_mutex_unlock(&lock); + throw; + } + } + + if (avr->state == cpu_Stopped) { + timeval ts; + ts.tv_sec = 0; + ts.tv_usec = 1000; + select(0, 0, 0, 0, &ts); + } + + if (cnt < 0) { + cyclesOnSyncStart = -1; + timeMicrosOnSyncStart = 0; + if (pthread_mutex_lock(&lock)) { + throw std::logic_error(error(AT, "avrRun() fails caused by mutex error (2)")); + } + try { + if (avrRunThread != NULL) { + avrRunThread->detach(); + delete avrRunThread; + avrRunThread = NULL; + } + pthread_mutex_unlock(&lock); + return; + } catch (std::exception& e) { + pthread_mutex_unlock(&lock); + status.state = StateError; + throw; + } + + } else if (++cnt >= 100000) { + cnt = 0; + } + + if (command != ReadyForNewCommand) { + switch (command) { + case CommandStatus: { + printCyclesAndElapsedTime(); + printf("\n"); + break; + } + case CommandInterrupt: { + if (avr->state == cpu_Running) { + avr->state = cpu_Stopped; + } + break; + } + case CommandContinue: { + if (avr->state == cpu_Stopped) { + avr->state = cpu_Running; + } + break; + } + case CommandStack: { + uint16_t sp = _avr_sp_get(avr); + printf("Stack: SP=0x%04x:\n", sp); + for (uint16_t addr = ((sp + 1) / 16) * 16; addr <= avr->ramend; addr++) { + if (addr % 16 == 0) { + printf(" 0x%04x:", addr); + } + if (addr % 4 == 0) { + printf(" "); + } + if (addr <= sp) { + printf(" "); + } else { + uint8_t b = avr_core_watch_read(avr, addr); + printf(" %02x", b); + } + if (addr % 16 == 15) { + printf("\n"); + } + } + printf("\n"); + break; + } + + default: break; + } + command = ReadyForNewCommand; + addEvent(EventCommandExecuted); + } + + avr_run(avr); + + } catch (std::exception& e) { + status.state = StateError; + cyclesOnSyncStart = -1; + timeMicrosOnSyncStart = 0; + if (pthread_mutex_lock(&lock)) { + throw std::logic_error(error(AT, "avrRun() fails caused by mutex error (2)")); + } + try { + if (avrRunThread != NULL) { + avrRunThread->detach(); + delete avrRunThread; + avrRunThread = NULL; + } + pthread_mutex_unlock(&lock); + throw; + } catch (std::exception& e) { + pthread_mutex_unlock(&lock); + status.state = StateError; + throw; + } + + } + } +} + diff --git a/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/simavr/simavr.h b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/simavr/simavr.h new file mode 100644 index 0000000..e1455b7 --- /dev/null +++ b/examples/simuc/dpkg/htl-simuc_version_arch/usr/share/htl-simuc/simuc/src/simavr/simavr.h @@ -0,0 +1,132 @@ +#ifndef SIMAVR_H +#define SIMAVR_H + +#include "semaphore.h" +#include "parts/uart_pty.h" + +#include +#include +#include + +#include +#include +#include + +typedef enum { + BoardUnknown = 0, + BoardNano, + BoardSure, + BoardEWS1 +} EnumStartParameterBoard; + + +struct StartParameters { + char *filename; + int gdbPort; + int64_t frequency; + const char *mmcu; + EnumStartParameterBoard board; + int32_t pc; + int32_t vcc; + int32_t avcc; + int32_t aref; +}; + +enum SimAvrState { + StateInit = 0, + StateError = 1, + StateLoaded = 10, + StateRunning = 11, + StateDone = 12, + StateCrashed = 20, + StateOthers = 99, + StateUnknown = 100 +}; + +typedef enum { + EventUnknown = 0, + EventShutdown = -1, + EventLoad = -2, + EventStart = -3, + EventStop = -4, + EventCommandExecuted = -5 +} EnumSimAvrEvent; + +typedef enum { + ReadyForNewCommand = 0, + CommandStatus, + CommandInterrupt, + CommandContinue, + CommandStack +} EnumSimAvrCommand; + +struct SimAvrStatus { + long long freqHz; + long long cycle; + enum SimAvrState state; + bool running; +}; + +struct SimAvrEvent { + long long epochMillis; + long long cycle; + int event; +}; + + +class SimAvr; +typedef void (*avrsim_io_write_callback_t)(avr_t *avr, avr_io_addr_t addr, uint8_t value, SimAvr *simavr); + +class SimAvr { + +public: + SimAvr (); + ~SimAvr (); + + struct SimAvrStatus getStatus (); + struct SimAvrEvent waitForEvent (); + const char *eventText (EnumSimAvrEvent event); + +public: + void load (struct StartParameters *params); + void shutdown (); + void start (); + void stop (); + void addEvent (int event); + void setUartDumpEnabled (bool enabled); + void setUartPtyEnabled (int uart, bool enabled); + void setUartPtyHook (int uart, void (*fromUart)(uint8_t), void (*toUart)(uint8_t)); + void registerIoWrite (avr_io_addr_t addr, avrsim_io_write_callback_t callback); + + const char *getTargetDeviceName (); + uint32_t getTargetFrequency (); + const char *getUartPtyDeviceName (int uart); + + void avrRun (); + void setLed (bool on); + void setTimeSync (bool sync); + void setCommand (EnumSimAvrCommand cmd, void *param); + +private: + elf_firmware_t *firmware = NULL; + avr_t *avr = NULL;; + StartParameters *startParameters = NULL;; + pthread_mutex_t lock; + std::list events; + EnumSimAvrCommand command; + struct SimAvrStatus status; + bool cancelThread = false; + bool isShutdown = false; + bool syncTime[2] = { false, true }; + std::thread *avrRunThread = NULL; + long cyclesOnSyncStart = -1; + uint64_t timeMicrosOnSyncStart = 0; + Semaphore eventCount; + uart_pty_t *uartPty[2] = { NULL, NULL }; + void printCyclesAndElapsedTime (); +}; + + + + +#endif // SIMAVR_H \ No newline at end of file diff --git a/examples/simuc/sim/vcd/.gitkeep b/examples/simuc/sim/vcd/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/examples/simuc/src/main.cpp b/examples/simuc/src/main.cpp new file mode 100644 index 0000000..0af4178 --- /dev/null +++ b/examples/simuc/src/main.cpp @@ -0,0 +1,190 @@ +#include +#include +#include + +#include "sim/sim.h" +#include "simavr/simavr.h" + +void printHelp () { + printf("simuc V1.0.0 (%s,%s)\n", __DATE__, __TIME__); + printf("usage: simuc [options] elf-file\n\n"); + printf(" available options:\n"); + printf(" --board ... set board (arduino, sure, evws1)\n"); + printf(" --sync sync elapsed µC-time with real time\n\n"); + printf(" --mmcu ... set target device type\n"); + printf(" --frequency ... set target frequency in Hz\n"); + printf(" --pc ... set start program counter (default is 0)\n"); + printf(" --vcc ... set voltage VCC in Volt\n"); + printf(" --avcc ... set voltage AVCC in Volt\n"); + printf(" --aref ... set voltage AREF in Volt\n\n"); + printf(" example:\n"); + printf(" simuc --mmcu atmega328p --frequency 16000000 --pc 0x7000 a.out\n\n"); + printf(" simuc --board arduino a.out\n\n"); +} + +int main (int argc, char **argv) { + struct StartParameters params = { + filename: NULL, + gdbPort: -1, + frequency: -1, + mmcu: NULL, + board: BoardUnknown, + vcc: -1, + avcc: -1, + aref: -1 + }; + + if (argc <= 1) { + printHelp(); + return 1; + } + + for (int i = 1; i < argc; i++) { + if (argv[i][0] == '-') { + if (strcmp(argv[i], "--help") == 0) { + printHelp(); + return 0; + } else if (strcmp(argv[i], "--board") == 0 && argc >= (i + 1)) { + i++; + if (strcmp("arduino", argv[i]) == 0) { + params.board = BoardNano; + params.mmcu = "atmega328p"; + params.frequency = 16000000; + params.vcc = 5000; + params.avcc = 5000; + params.aref = 2500; + } else if (strcmp("sure", argv[i]) == 0) { + params.board = BoardSure; + params.mmcu = "atmega16"; + params.frequency = 12000000; + params.vcc = 5000; + params.avcc = 5000; + params.aref = 2500; + } else if (strcmp("evws1", argv[i]) == 0) { + params.board = BoardEWS1; + params.mmcu = "atmega324p"; + params.frequency = 20000000; + params.vcc = 5000; + params.avcc = 5000; + params.aref = 2500; + } else { + fprintf(stderr, "ERROR: invalid board %s, use --help to show usage\n\n", argv[i]); + return 1; + } + + } else if (strcmp(argv[i], "--mmcu") == 0) { + params.mmcu = argv[++i]; + } else if (strcmp(argv[i], "--port") == 0) { + sscanf(argv[++i], "%d", ¶ms.gdbPort); + } else if (strcmp(argv[i], "--frequency") == 0) { + sscanf(argv[++i], "%" PRIu64, ¶ms.frequency); + } else if (strcmp(argv[i], "--pc") == 0) { + i++; + if (argv[i][0] == '0' && argv[i][1] == 'x') { + sscanf(&argv[i][2], "%x", ¶ms.pc); + } else { + sscanf(argv[++i], "%d", ¶ms.pc); + } + } else if (strcmp(argv[i], "--vcc") == 0) { + sscanf(argv[++i], "%d", ¶ms.vcc); + } else if (strcmp(argv[i], "--avcc") == 0) { + sscanf(argv[++i], "%d", ¶ms.avcc); + } else if (strcmp(argv[i], "--aref") == 0) { + sscanf(argv[++i], "%d", ¶ms.aref); + } else { + fprintf(stderr, "ERROR: invalid option %s, use --help to show usage\n\n", argv[i]); + return 1; + } + continue; + } + params.filename = argv[i]; + break; + } + + if (params.filename == NULL) { + printf("ERROR: missing target elf file, use --help to show usage\n\n"); + return 1; + } + + init(¶ms); + if (errno == 1) { + return 1; + } + printf("init done - press key to start\n"); + getchar(); + start(); + + // int cnt = 0; + char *line = NULL; + size_t size = 0; + while (1) { + // struct SimAvrEvent ev = waitForEvent(); + // printf("%10.03lf: event %s (%d) received \r", ev.cycle / 20E6, eventText((EnumSimEvent)ev.event), ev.event); + // fflush(stdout); + // if (++cnt == 10000) { + // stop(); + // shutdown(); + // break; + // } + + if (getline(&line, &size, stdin) > 0) { + const char *commands[] = { "interrupt", "continue", "stack" }; + try { + int foundIndex = -1; + int foundCnt = 0; + size_t length = strlen(line) - 1; + if (length > 0 && size >= (length + 1)) { + line[length] = 0; + for (long unsigned int i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) { + const char *cmd = commands[i]; + size_t max = strlen(cmd); + bool ok = true; + for (size_t j = 0; j < length; j++) { + if (j >= max || line[j] != cmd[j]) { + ok = false; + break; + } + } + if (ok) { + foundCnt++; + foundIndex = i; + } + } + } + // printf("foundCnt=%d foundIndex=%d command=%s\n", foundCnt, foundIndex, foundIndex >= 0 ? commands[foundIndex] : ""); + if (foundCnt == 1 || length == 0) { + setCommand((EnumSimAvrCommand)(foundCnt > 0 ? foundIndex + 2 : 1), NULL); + while (1) { + struct SimAvrEvent ev = waitForEvent(); + if (ev.event == EventCommandExecuted) { + break; + } + } + + } else { + printf("invalid command, valid commands are for status and:"); + for (long unsigned int i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) { + printf(" %s", commands[i]); + } + printf("\n"); + continue; + } + + } catch (std::exception& e) { + printf("ERROR\n"); + } + + } + + } + while (1) { + struct SimAvrEvent ev = waitForEvent(); + printf("event %s (%d) received\n", eventText((EnumSimEvent)ev.event), ev.event); + if (ev.event == EventShutdown) { + break; + } + } + + usleep(10000); + return 0; +} \ No newline at end of file diff --git a/examples/simuc/src/sim/error.cpp b/examples/simuc/src/sim/error.cpp new file mode 100644 index 0000000..f59ddbd --- /dev/null +++ b/examples/simuc/src/sim/error.cpp @@ -0,0 +1,18 @@ +#include "error.h" +#include + +std::string error (const char *location, const char *format, ...) { + va_list args; + va_start (args, format); + int length = std::vsnprintf (NULL, 0, format, args); + va_end (args); + + va_start (args, format); + char* str = new char[length + 1]; // one more character for null terminator + std::vsnprintf (str, length + 1, format, args); + std::string rv = "Error at " + std::string(location) + " -> " + str; + delete[] str; + va_end (args); + + return rv; +} diff --git a/examples/simuc/src/sim/error.h b/examples/simuc/src/sim/error.h new file mode 100644 index 0000000..80d5682 --- /dev/null +++ b/examples/simuc/src/sim/error.h @@ -0,0 +1,11 @@ +#ifndef ERROR_H +#define ERROR_H + +#include + +#define STRINGIFY(x) #x +#define TOSTRING(x) STRINGIFY(x) +#define AT __FILE__ ":" TOSTRING(__LINE__) +std::string error (const char *location, const char *format, ...); + +#endif // ERROR_H diff --git a/examples/simuc/src/sim/sim.cpp b/examples/simuc/src/sim/sim.cpp new file mode 100644 index 0000000..32a23b6 --- /dev/null +++ b/examples/simuc/src/sim/sim.cpp @@ -0,0 +1,282 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "sim.h" +#include "error.h" + + + +// https://github.com/java-native-access/jna/blob/master/www/CallbacksAndClosures.md#callbacks-function-pointers-and-closures + + +int SIGUSR1 = 30; + +// avr_t * avr = NULL; +SimAvr simavr; +std::string lastErrorMessage; + +static int fdStdOut = -1, fdStdErr = -1; +// static fpos_t posStdOut, posStdErr; + +void switchStdOut (const char * filename) { + fflush(stdout); + // fgetpos(stdout, &posStdOut); + if (filename == NULL) { + int fd = open("/dev/null", O_WRONLY); + fdStdOut = dup2(fd, fileno(stdout)); + } else { + fdStdOut = dup(fileno(stdout)); + } +} + +void switchStdErr (const char * filename) { + fflush(stderr); + // fgetpos(stderr, &posStdErr); + if (filename == NULL) { + int fd = open("/dev/null", O_WRONLY); + fdStdErr = dup2(fd, fileno(stderr)); + } else { + fdStdErr = dup(fileno(stderr)); + } +} + +void revertStdErrOut () { + if (fdStdOut >= 0) { + fflush(stdout); + dup2(fdStdOut, fileno(stdout)); + close(fdStdOut); + fdStdOut = -1; + clearerr(stdout); + // fsetpos(stdout, &posStdOut); + } + if (fdStdErr >= 0) { + fflush(stderr); + dup2(fdStdErr, fileno(stderr)); + close(fdStdErr); + fdStdErr = -1; + clearerr(stderr); + // fsetpos(stderr, &posStdErr); + } +} + +const char * lastError () { + return lastErrorMessage.c_str(); +} + + +// static void handleWritePortB (struct avr_t * avr, __attribute__((unused)) avr_io_addr_t addr, uint8_t v, SimAvr *simavr) { +// static int value = 0; +// if (value != v) { +// value = v; +// if (simavr != NULL) { +// if ((value << PORTB0) != 0) { +// simavr->addEvent(EventLedOn); +// } else { +// simavr->addEvent(EventLedOff); +// } +// } +// } +// } + +std::vector gdbFromUartBuffer; +std::vector gdbToUartBuffer; + +__attribute__((unused)) static void fromGdbUart (uint8_t b) { + static int cnt = 0; + if (b == '$') { + cnt = 1; + } else if (cnt > 0 && b == '#') { + cnt = -1; + } else if (cnt < 0) { + cnt--; + } + gdbFromUartBuffer.push_back(b); + + if (cnt <= -3 || (cnt == 0 && b == '+')) { + printf("\n\rgdb-uart OUT -> "); + for (uint8_t c : gdbFromUartBuffer) { + putchar(c); + } + printf("\n\r"); + gdbFromUartBuffer.clear(); + } +} + +__attribute__((unused)) static void toGdbUart (uint8_t b) { + static int cnt = 0; + if (b == '$') { + cnt = 1; + } else if (cnt > 0 && b == '#') { + cnt = -1; + } else if (cnt < 0) { + cnt--; + } + gdbToUartBuffer.push_back(b); + + if (cnt <= -3 || (cnt == 0 && b == '+')) { + printf("\n\rgdb-uart IN <-- "); + for (uint8_t c : gdbToUartBuffer) { + putchar(c); + } + printf("\n\r"); + gdbToUartBuffer.clear(); + } + +} + +void init (struct StartParameters *param) { + try { + // switchStdOut(NULL); + // switchStdErr(NULL); + // std::cout.rdbuf(0); + // std::cerr.rdbuf(0); + const char *filename = param->filename != NULL + ? param->filename + // : "../gdb-stub-sm_atmega324p/sim/dist/gdb-stub-sm_atmega324p.axf"; + : "../gdb-stub-sm_atmega324p/sim/dist/gdb-stub-sm_atmega324p.axf"; + printf("firmware file \"%s\"\n", filename); + simavr.load(param); + if (strcmp(simavr.getTargetDeviceName(), "atmega324p") != 0) { + std::logic_error(error(AT, "invalid target device %s", simavr.getTargetDeviceName())); + } + + simavr.setUartDumpEnabled(false); + // simavr.registerIoWrite(PORTB, handleWritePortB); + simavr.setUartPtyEnabled(0, true); + int uartCnt = 1; + if (strcmp(simavr.getTargetDeviceName(), "atmega324p") == 0) { + simavr.setUartPtyEnabled(1, true); + simavr.setUartPtyHook(1, fromGdbUart, toGdbUart); + uartCnt = 2; + } + // printf("uart0 -> picocom --imap lfcrlf -b 115200 %s\n", simavr.getUartPtyDeviceName(0)); + // printf("uart1 -> picocom --imap lfcrlf -b 115200 %s\n", simavr.getUartPtyDeviceName(1)); + + printf("device %s\n", simavr.getTargetDeviceName()); + printf("frequency %.2lfMHz\n", simavr.getTargetFrequency() / 1E6); + + for (int i = 0; i < uartCnt; i++) { + char s[128]; + snprintf(s, 128, "/tmp/sim-megaavr-%s-uart%1d", simavr.getTargetDeviceName(), i); + FILE *f = fopen(s, "w"); + if (f == NULL) { + std::logic_error(error(AT, "cannot write file %s", s)); + } + printf("uart%1d -> picocom %s (see file %s)\n", i, simavr.getUartPtyDeviceName(i), s); + fprintf(f, "%s\n", simavr.getUartPtyDeviceName(i)); + fclose(f); + } + + } catch (std::exception& e) { + lastErrorMessage = "init() fails, caused by " + std::string(e.what()); + std::cerr << lastErrorMessage << "\n"; + errno = 1; + } +} + +void shutdown () { + try { + simavr.shutdown(); + } catch (std::exception& e) { + lastErrorMessage = "shutdown() fails, caused by " + std::string(e.what()); + std::cerr << lastErrorMessage << "\n"; + errno = 1; + } +} + +void start () { + try { + simavr.start(); + + } catch (std::exception& e) { + lastErrorMessage = "start() fails, caused by " + std::string(e.what()); + std::cerr << lastErrorMessage << "\n"; + errno = 1; + } +} + +void stop () { + try { + simavr.stop(); + + } catch (std::exception& e) { + lastErrorMessage = "stop() fails, caused by " + std::string(e.what()); + std::cerr << lastErrorMessage << "\n"; + errno = 1; + } +} + +void setCommand (EnumSimAvrCommand cmd, void *param) { + try { + simavr.setCommand(cmd, param); + + } catch (std::exception& e) { + lastErrorMessage = "setCommand(..) fails, caused by " + std::string(e.what()); + std::cerr << lastErrorMessage << "\n"; + errno = 1; + throw e; + } + +} + +void addEvent (EnumSimEvent event) { + try { + simavr.addEvent(event); + + } catch (std::exception& e) { + lastErrorMessage = "addEvent(..) fails, caused by " + std::string(e.what()); + std::cerr << lastErrorMessage << "\n"; + errno = 1; + } +} + +void setTimeSync (bool sync) { + try { + simavr.setTimeSync(sync); + + } catch (std::exception& e) { + lastErrorMessage = "setTimeSync() fails, caused by " + std::string(e.what()); + std::cerr << lastErrorMessage << "\n"; + errno = 1; + } +} + +struct SimAvrStatus getStatus () { + return simavr.getStatus();; +} + +struct SimAvrEvent waitForEvent () { + return simavr.waitForEvent(); +} + +const char *eventText (EnumSimEvent event) { + const char *rv = simavr.eventText((EnumSimAvrEvent)event); + if (rv != NULL) { + return rv; + } else { + switch (event) { + case EventLedOff: return "LedOff"; + case EventLedOn: return "LedOn"; + default: return "?"; + } + } +} diff --git a/examples/simuc/src/sim/sim.h b/examples/simuc/src/sim/sim.h new file mode 100644 index 0000000..d980f26 --- /dev/null +++ b/examples/simuc/src/sim/sim.h @@ -0,0 +1,43 @@ +#ifndef SIM_H +#define SIM_H + +#include "../simavr/simavr.h" + +// #define _AVR_IO_H_ +// #define _SFR_IO8(reg) (0x20 + reg) +// #include "iom324p.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + EventInterrupt = 1, + EventLedOff = 10, + EventLedOn = 11 +} EnumSimEvent; + + + +extern void init (struct StartParameters *param); +extern void shutdown (); +extern const char * lastError (); +extern void start (); +extern void stop (); +extern void setCommand (EnumSimAvrCommand cmd, void *param); +extern void addEvent (EnumSimEvent event); +extern void setTimeSync (bool sync); +extern struct SimAvrStatus getStatus (); +extern struct SimAvrEvent waitForEvent (); +extern const char *eventText (EnumSimEvent event); + +typedef void (*NotificationListener)(char *, int); +void callbackTrigger(const NotificationListener l); +void getDeviceRandomStatus(char *answer, int sizeOfChars); +int randNum( int min, int max); + +#ifdef __cplusplus +} +#endif + +#endif // SIM_H diff --git a/examples/simuc/src/simavr/parts/fifo_declare.h b/examples/simuc/src/simavr/parts/fifo_declare.h new file mode 100644 index 0000000..8a3b2fb --- /dev/null +++ b/examples/simuc/src/simavr/parts/fifo_declare.h @@ -0,0 +1,189 @@ +/* + fido_declare.h + Copyright (C) 2003-2012 Michel Pollet + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* + * FIFO helpers, aka circular buffers + * + * these macros define accessories for FIFOs of any name, type and + * any (power of two) size + */ + +#ifndef __FIFO_DECLARE__ +#define __FIFO_DECLARE__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + doing a : + DECLARE_FIFO(uint8_t, myfifo, 128); + + will declare : + enum : myfifo_overflow_f + type : myfifo_t + functions: + // write a byte into the fifo, return 1 if there was room, 0 if there wasn't + int myfifo_write(myfifo_t *c, uint8_t b); + // reads a byte from the fifo, return 0 if empty. Use myfifo_isempty() to check beforehand + uint8_t myfifo_read(myfifo_t *c); + int myfifo_isfull(myfifo_t *c); + int myfifo_isempty(myfifo_t *c); + // returns number of items to read now + uint16_t myfifo_get_read_size(myfifo_t *c); + // read item at offset o from read cursor, no cursor advance + uint8_t myfifo_read_at(myfifo_t *c, uint16_t o); + // write b at offset o compared to current write cursor, no cursor advance + void myfifo_write_at(myfifo_t *c, uint16_t o, uint8_t b); + + In your .c you need to 'implement' the fifo: + DEFINE_FIFO(uint8_t, myfifo) + + To use the fifo, you must declare at least one : + myfifo_t fifo = FIFO_NULL; + + while (!myfifo_isfull(&fifo)) + myfifo_write(&fifo, 0xaa); + .... + while (!myfifo_isempty(&fifo)) + b = myfifo_read(&fifo); + */ + +#include + +#if __AVR__ +#define FIFO_CURSOR_TYPE uint8_t +#define FIFO_BOOL_TYPE char +#define FIFO_INLINE +#define FIFO_SYNC +#endif + +#ifndef FIFO_CURSOR_TYPE +#define FIFO_CURSOR_TYPE uint16_t +#endif +#ifndef FIFO_BOOL_TYPE +#define FIFO_BOOL_TYPE int +#endif +#ifndef FIFO_INLINE +#define FIFO_INLINE inline +#endif + +/* We should not need volatile */ +#ifndef FIFO_VOLATILE +#define FIFO_VOLATILE +#endif +#ifndef FIFO_SYNC +#define FIFO_SYNC __sync_synchronize() +#endif + +#ifndef FIFO_ZERO_INIT +#define FIFO_ZERO_INIT {0} +#endif +#define FIFO_NULL { FIFO_ZERO_INIT, 0, 0, 0 } + +/* New compilers don't like unused static functions. However, + * we do like 'static inlines' for these small accessors, + * so we mark them as 'unused'. It stops it complaining */ +#ifdef __GNUC__ +#define FIFO_DECL static __attribute__ ((unused)) +#else +#define FIFO_DECL static +#endif + +#define DECLARE_FIFO(__type, __name, __size) \ +enum { __name##_overflow_f = (1 << 0) }; \ +enum { __name##_fifo_size = (__size) }; \ +typedef struct __name##_t { \ + __type buffer[__name##_fifo_size]; \ + FIFO_VOLATILE FIFO_CURSOR_TYPE read; \ + FIFO_VOLATILE FIFO_CURSOR_TYPE write; \ + FIFO_VOLATILE uint8_t flags; \ +} __name##_t + +#define DEFINE_FIFO(__type, __name) \ +FIFO_DECL FIFO_INLINE FIFO_BOOL_TYPE __name##_write(__name##_t * c, __type b)\ +{\ + FIFO_CURSOR_TYPE now = c->write;\ + FIFO_CURSOR_TYPE next = (now + 1) & (__name##_fifo_size-1);\ + if (c->read != next) { \ + c->buffer[now] = b;\ + FIFO_SYNC; \ + c->write = next;\ + return 1;\ + }\ + return 0;\ +}\ +FIFO_DECL FIFO_INLINE FIFO_BOOL_TYPE __name##_isfull(__name##_t *c)\ +{\ + FIFO_CURSOR_TYPE next = (c->write + 1) & (__name##_fifo_size-1);\ + return c->read == next;\ +}\ +FIFO_DECL FIFO_INLINE FIFO_BOOL_TYPE __name##_isempty(__name##_t * c)\ +{\ + return c->read == c->write;\ +}\ +FIFO_DECL FIFO_INLINE __type __name##_read(__name##_t * c)\ +{\ + __type res = FIFO_ZERO_INIT; \ + FIFO_CURSOR_TYPE read = c->read;\ + if (read == c->write)\ + return res;\ + res = c->buffer[read];\ + FIFO_SYNC; \ + c->read = (read + 1) & (__name##_fifo_size-1);\ + return res;\ +}\ +FIFO_DECL FIFO_INLINE FIFO_CURSOR_TYPE __name##_get_read_size(__name##_t *c)\ +{\ + return ((c->write + __name##_fifo_size) - c->read) & (__name##_fifo_size-1);\ +}\ +FIFO_DECL FIFO_INLINE FIFO_CURSOR_TYPE __name##_get_write_size(__name##_t *c)\ +{\ + return (__name##_fifo_size-1) - __name##_get_read_size(c);\ +}\ +FIFO_DECL FIFO_INLINE void __name##_read_offset(__name##_t *c, FIFO_CURSOR_TYPE o)\ +{\ + FIFO_SYNC; \ + c->read = (c->read + o) & (__name##_fifo_size-1);\ +}\ +FIFO_DECL FIFO_INLINE __type __name##_read_at(__name##_t *c, FIFO_CURSOR_TYPE o)\ +{\ + return c->buffer[(c->read + o) & (__name##_fifo_size-1)];\ +}\ +FIFO_DECL FIFO_INLINE void __name##_write_at(__name##_t *c, FIFO_CURSOR_TYPE o, __type b)\ +{\ + c->buffer[(c->write + o) & (__name##_fifo_size-1)] = b;\ +}\ +FIFO_DECL FIFO_INLINE void __name##_write_offset(__name##_t *c, FIFO_CURSOR_TYPE o)\ +{\ + FIFO_SYNC; \ + c->write = (c->write + o) & (__name##_fifo_size-1);\ +}\ +FIFO_DECL FIFO_INLINE void __name##_reset(__name##_t *c)\ +{\ + FIFO_SYNC; \ + c->read = c->write = c->flags = 0;\ +}\ +struct __name##_t + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/examples/simuc/src/simavr/parts/uart_pty.c b/examples/simuc/src/simavr/parts/uart_pty.c new file mode 100644 index 0000000..a283fef --- /dev/null +++ b/examples/simuc/src/simavr/parts/uart_pty.c @@ -0,0 +1,371 @@ +/* + uart_pty.c + + Copyright 2008, 2009 Michel Pollet + + 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 +#include +#include +#include +#include +#include +#ifdef __APPLE__ +#include +#elif defined (__FreeBSD__) +#include +#include +#include +#include +#else +#include +#endif + +#include "uart_pty.h" +#include +#include +#include + +DEFINE_FIFO(uint8_t,uart_pty_fifo); + +//#define TRACE(_w) _w +#ifndef TRACE +#define TRACE(_w) +#endif + +TRACE(static const char * +uart_pty_toPrintableChar( + uint32_t value) +{ + static char rv[2] = ""; + if (value >= ' ' && value <= 126) { + rv[0] = (char)value; + rv[1] = 0; + } else if (value == '\n') { + return "\\n"; + } else if (value == '\r') { + return "\\r"; + } else { + rv[0] = 0; + } + return rv; +}) + + +/* + * called when a byte is send via the uart on the AVR + */ +static void +uart_pty_in_hook( + struct avr_irq_t * irq, + uint32_t value, + void * param) +{ + uart_pty_t * p = (uart_pty_t*)param; + TRACE(printf("uart_pty_in_hook %02x %s\n", value, uart_pty_toPrintableChar(value));) + if (p->port[0].crlf && value == '\n') { + uart_pty_fifo_write(&p->port[0].in, '\r'); + } + uart_pty_fifo_write(&p->pty.in, value); + if (p->port[0].hook_from_uart != NULL) { + p->port[0].hook_from_uart(value); + } else if (p->hook_from_uart != NULL) { + p->hook_from_uart(value); + } + + if (p->tap.s) { + if (p->tap.crlf && value == '\n') + uart_pty_fifo_write(&p->tap.in, '\r'); + uart_pty_fifo_write(&p->tap.in, value); + } +} + +// try to empty our fifo, the uart_pty_xoff_hook() will be called when +// other side is full +static void +uart_pty_flush_incoming( + uart_pty_t * p) +{ + while (p->xon && !uart_pty_fifo_isempty(&p->pty.out)) { + TRACE(int r = p->pty.out.read;) + uint8_t byte = uart_pty_fifo_read(&p->pty.out); + TRACE(printf("uart_pty_flush_incoming send r %03d:%02x\n", r, byte);) + avr_raise_irq(p->irq + IRQ_UART_PTY_BYTE_OUT, byte); + + if (p->tap.s) { + if (p->tap.crlf && byte == '\n') + uart_pty_fifo_write(&p->tap.in, '\r'); + uart_pty_fifo_write(&p->tap.in, byte); + } + } + if (p->tap.s) { + while (p->xon && !uart_pty_fifo_isempty(&p->tap.out)) { + uint8_t byte = uart_pty_fifo_read(&p->tap.out); + if (p->tap.crlf && byte == '\r') { + uart_pty_fifo_write(&p->tap.in, '\n'); + } + if (byte == '\n') + continue; + uart_pty_fifo_write(&p->tap.in, byte); + avr_raise_irq(p->irq + IRQ_UART_PTY_BYTE_OUT, byte); + } + } +} + +avr_cycle_count_t +uart_pty_flush_timer( + struct avr_t * avr, + avr_cycle_count_t when, + void * param) +{ + uart_pty_t * p = (uart_pty_t*)param; + + uart_pty_flush_incoming(p); + /* always return a cycle NUMBER not a cycle count */ + return p->xon ? when + avr_hz_to_cycles(p->avr, 1000) : 0; +} + +/* + * Called when the uart has room in it's input buffer. This is called repeateadly + * if necessary, while the xoff is called only when the uart fifo is FULL + */ +static void +uart_pty_xon_hook( + struct avr_irq_t * irq, + uint32_t value, + void * param) +{ + uart_pty_t * p = (uart_pty_t*)param; + TRACE(if (!p->xon) printf("uart_pty_xon_hook\n");) + p->xon = 1; + + uart_pty_flush_incoming(p); + + // if the buffer is not flushed, try to do it later + if (p->xon) + avr_cycle_timer_register(p->avr, avr_hz_to_cycles(p->avr, 1000), + uart_pty_flush_timer, param); +} + +/* + * Called when the uart ran out of room in it's input buffer + */ +static void +uart_pty_xoff_hook( + struct avr_irq_t * irq, + uint32_t value, + void * param) +{ + uart_pty_t * p = (uart_pty_t*)param; + TRACE(if (p->xon) printf("uart_pty_xoff_hook\n");) + p->xon = 0; + avr_cycle_timer_cancel(p->avr, uart_pty_flush_timer, param); +} + +static void * +uart_pty_thread( + void * param) +{ + uart_pty_t * p = (uart_pty_t*)param; + + while (1) { + fd_set read_set, write_set; + int max = 0; + FD_ZERO(&read_set); + FD_ZERO(&write_set); + + for (int ti = 0; ti < 2; ti++) if (p->port[ti].s) { + // read more only if buffer was flushed + if (p->port[ti].buffer_len == p->port[ti].buffer_done) { + FD_SET(p->port[ti].s, &read_set); + max = p->port[ti].s > max ? p->port[ti].s : max; + } + if (!uart_pty_fifo_isempty(&p->port[ti].in)) { + FD_SET(p->port[ti].s, &write_set); + max = p->port[ti].s > max ? p->port[ti].s : max; + } + } + + // short, but not too short interval + struct timeval timo = { 0, 500 }; + int ret = select(max+1, &read_set, &write_set, NULL, &timo); + + if (ret < 0) + break; + + for (int ti = 0; ti < 2; ti++) if (p->port[ti].s) { + if (FD_ISSET(p->port[ti].s, &read_set)) { + ssize_t r = read(p->port[ti].s, p->port[ti].buffer, + sizeof(p->port[ti].buffer)-1); + p->port[ti].buffer_len = r; + p->port[ti].buffer_done = 0; + TRACE(if (!p->port[ti].tap) + hdump("pty recv", p->port[ti].buffer, r);) + } + if (p->port[ti].buffer_done < p->port[ti].buffer_len) { + // write them in fifo + while (p->port[ti].buffer_done < p->port[ti].buffer_len && + !uart_pty_fifo_isfull(&p->port[ti].out)) { + int index = p->port[ti].buffer_done++; + TRACE(int wi = p->port[ti].out.write;) + uart_pty_fifo_write(&p->port[ti].out, + p->port[ti].buffer[index]); + TRACE(printf("w %3d:%02x (%d/%d) %s\n", + wi, p->port[ti].buffer[index], + p->port[ti].out.read, + p->port[ti].out.write, + p->xon ? "XON" : "XOFF");) + if (p->port[ti].hook_to_uart != NULL) { + p->port[ti].hook_to_uart(p->port[ti].buffer[index]); + } else if (p->hook_to_uart != NULL) { + p->hook_to_uart(p->port[ti].buffer[index]); + } + } + } + if (FD_ISSET(p->port[ti].s, &write_set)) { + uint8_t buffer[512]; + // write them in fifo + uint8_t * dst = buffer; + while (!uart_pty_fifo_isempty(&p->port[ti].in) && + (dst - buffer) < sizeof(buffer)) { + *dst = uart_pty_fifo_read(&p->port[ti].in); + dst++; + } + size_t len = dst - buffer; + TRACE(size_t r =) write(p->port[ti].s, buffer, len); + TRACE(if (!p->port[ti].tap) hdump("pty send", buffer, r);) + } + } + /* DO NOT call this, this create a concurency issue with the + * FIFO that can't be solved cleanly with a memory barrier + uart_pty_flush_incoming(p); + */ + } + return NULL; +} + +static const char * irq_names[IRQ_UART_PTY_COUNT] = { + [IRQ_UART_PTY_BYTE_IN] = "8avr = avr; + p->irq = avr_alloc_irq(&avr->irq_pool, 0, IRQ_UART_PTY_COUNT, irq_names); + avr_irq_register_notify(p->irq + IRQ_UART_PTY_BYTE_IN, uart_pty_in_hook, p); + + const int hastap = (getenv("SIMAVR_UART_TAP") && atoi(getenv("SIMAVR_UART_TAP"))) || + (getenv("SIMAVR_UART_XTERM") && atoi(getenv("SIMAVR_UART_XTERM"))); + p->hastap = hastap; + p->hook_from_uart = NULL; + p->hook_to_uart = NULL; + + for (int ti = 0; ti < 1 + hastap; ti++) { + int m, s; + + if (openpty(&m, &s, p->port[ti].slavename, NULL, NULL) < 0) { + fprintf(stderr, "%s: Can't create pty: %s", __FUNCTION__, strerror(errno)); + return; + } + struct termios tio; + tcgetattr(m, &tio); + cfmakeraw(&tio); + tio.c_cflag &= ~(ECHO | ECHONL); // no input echo + // tio.c_oflag |= (OPOST | ONLCR); // LF -> CRLF + tcsetattr(m, TCSANOW, &tio); + p->port[ti].s = m; + p->port[ti].tap = ti != 0; + // p->port[ti].crlf = ti != 0; + p->port[ti].crlf = 1; + p->port[ti].hook_from_uart = NULL; + p->port[ti].hook_to_uart = NULL; + if (ti > 0) { + printf("uart_pty_init %s on port *** %s ***\n", + ti == 0 ? "bridge" : "tap", p->port[ti].slavename); + } + } + + pthread_create(&p->thread, NULL, uart_pty_thread, p); + +} + +void +uart_pty_stop( + uart_pty_t * p) +{ + puts(__func__); + pthread_kill(p->thread, SIGINT); + for (int ti = 0; ti < 2; ti++) + if (p->port[ti].s) + close(p->port[ti].s); + void * ret; + pthread_join(p->thread, &ret); +} + +void +uart_pty_connect( + uart_pty_t * p, + char uart) +{ + // disable the stdio dump, as we are sending binary there + uint32_t f = 0; + avr_ioctl(p->avr, AVR_IOCTL_UART_GET_FLAGS(uart), &f); + f &= ~AVR_UART_FLAG_STDIO; + avr_ioctl(p->avr, AVR_IOCTL_UART_SET_FLAGS(uart), &f); + + avr_irq_t * src = avr_io_getirq(p->avr, AVR_IOCTL_UART_GETIRQ(uart), UART_IRQ_OUTPUT); + avr_irq_t * dst = avr_io_getirq(p->avr, AVR_IOCTL_UART_GETIRQ(uart), UART_IRQ_INPUT); + avr_irq_t * xon = avr_io_getirq(p->avr, AVR_IOCTL_UART_GETIRQ(uart), UART_IRQ_OUT_XON); + avr_irq_t * xoff = avr_io_getirq(p->avr, AVR_IOCTL_UART_GETIRQ(uart), UART_IRQ_OUT_XOFF); + + if (src && dst) { + avr_connect_irq(src, p->irq + IRQ_UART_PTY_BYTE_IN); + avr_connect_irq(p->irq + IRQ_UART_PTY_BYTE_OUT, dst); + } + if (xon) + avr_irq_register_notify(xon, uart_pty_xon_hook, p); + if (xoff) + avr_irq_register_notify(xoff, uart_pty_xoff_hook, p); + + for (int ti = 0; ti < 1+(p->hastap?1:0); ti++) if (p->port[ti].s) { + char link[128]; + snprintf(link, sizeof(link), "/tmp/simavr-uart%c%s", uart, ti == 1 ? "-tap" : ""); + unlink(link); + if (symlink(p->port[ti].slavename, link) != 0) { + fprintf(stderr, "WARN %s: Can't create %s: %s", __func__, link, strerror(errno)); + } else { + // printf("%s: %s now points to %s\n", __func__, link, p->port[ti].slavename); + } + } + if (getenv("SIMAVR_UART_XTERM") && atoi(getenv("SIMAVR_UART_XTERM"))) { + char cmd[256]; + sprintf(cmd, "xterm -e picocom -b 115200 %s >/dev/null 2>&1 &", + p->tap.slavename); + system(cmd); + } else { + // printf("note: export SIMAVR_UART_XTERM=1 and install picocom to get a terminal\n"); + } +} diff --git a/examples/simuc/src/simavr/parts/uart_pty.h b/examples/simuc/src/simavr/parts/uart_pty.h new file mode 100644 index 0000000..482de7d --- /dev/null +++ b/examples/simuc/src/simavr/parts/uart_pty.h @@ -0,0 +1,90 @@ +/* + uart_pty.h + + Copyright 2012 Michel Pollet + + 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 . + */ + + +#ifndef __UART_PTY_H___ +#define __UART_PTY_H___ + +#include +#include +#include "fifo_declare.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + IRQ_UART_PTY_BYTE_IN = 0, + IRQ_UART_PTY_BYTE_OUT, + IRQ_UART_PTY_COUNT +}; + +DECLARE_FIFO(uint8_t,uart_pty_fifo, 512); + +typedef struct uart_pty_port_t { + unsigned int tap : 1, crlf : 1; + int s; // socket we chat on + char slavename[64]; + uart_pty_fifo_t in; + uart_pty_fifo_t out; + uint8_t buffer[512]; + size_t buffer_len, buffer_done; + void (*hook_from_uart)(uint8_t); + void (*hook_to_uart)(uint8_t); +} uart_pty_port_t, *uart_pty_port_p; + +typedef struct uart_pty_t { + avr_irq_t * irq; // irq list + struct avr_t *avr; // keep it around so we can pause it + + pthread_t thread; + int xon; + int hastap; + + union { + struct { + uart_pty_port_t pty; + uart_pty_port_t tap; + }; + uart_pty_port_t port[2]; + }; + void (*hook_from_uart)(uint8_t); + void (*hook_to_uart)(uint8_t); +} uart_pty_t; + +void +uart_pty_init( + struct avr_t * avr, + uart_pty_t * b); +void +uart_pty_stop(uart_pty_t * p); + +void +uart_pty_connect( + uart_pty_t * p, + char uart); + +#ifdef __cplusplus +} +#endif + +#endif /* __UART_PTY_H___ */ + diff --git a/examples/simuc/src/simavr/semaphore.h b/examples/simuc/src/simavr/semaphore.h new file mode 100644 index 0000000..289a45d --- /dev/null +++ b/examples/simuc/src/simavr/semaphore.h @@ -0,0 +1,32 @@ +#ifndef SEMAPHORE_H +#define SEMAPHORE_H + +#include +#include + +class Semaphore { + public: + Semaphore (int count_ = 0) : count(count_) { + } + + inline void notify () { + std::unique_lock lock(mtx); + count++; + //notify the waiting thread + cv.notify_one(); + } + inline void wait () { + std::unique_lock lock(mtx); + while(count == 0) { + //wait on the mutex until notify is called + cv.wait(lock); + } + count--; + } + private: + std::mutex mtx; + std::condition_variable cv; + int count; +}; + +#endif // SEMAPHORE_H diff --git a/examples/simuc/src/simavr/simavr.cpp b/examples/simuc/src/simavr/simavr.cpp new file mode 100644 index 0000000..ba63390 --- /dev/null +++ b/examples/simuc/src/simavr/simavr.cpp @@ -0,0 +1,749 @@ +#include "simavr.h" +#include "../sim/error.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + + +SimAvr::SimAvr () { + memset(&status, 0, sizeof(status)); +} + +SimAvr::~SimAvr () { + if (firmware != NULL) { + free(firmware); + firmware = NULL; + } + if (avr != NULL) { + free(avr); + avr = NULL; + } +} + +void SimAvr::shutdown () { + // if (pthread_mutex_lock(&lock)) { + // throw std::logic_error(error(AT, "shutdown() fails caused by mutex error")); + // } + // cancelThread = true; + // isShutdown = true; + // pthread_mutex_unlock(&lock); + addEvent(EventShutdown); +} + + +void SimAvr::load (struct StartParameters *params) { + if (pthread_mutex_lock(&lock)) { + throw std::logic_error(error(AT, "load() fails caused by mutex error")); + } + try { + if (isShutdown) { + throw std::logic_error(error(AT, "cannot load after simavr shutdown")); + } + if (firmware != NULL) { + throw std::logic_error(error(AT, "firmware already loaded")); + } + + startParameters = params; + firmware = (elf_firmware_t *) malloc(sizeof(elf_firmware_t)); + std::string filename = std::string(params->filename); + if (firmware == NULL || elf_read_firmware(filename.c_str(), firmware) != 0) { + throw std::logic_error(error(AT, "elf_read_firmware() from %s fails", filename.c_str())); + } + if (params->mmcu != NULL) { + strncpy(firmware->mmcu, params->mmcu, sizeof(firmware->mmcu)); + } + if (params->frequency > 0) { + firmware->frequency = (uint32_t)params->frequency; + } + if (params->vcc > 0) { + firmware->vcc = (uint32_t)params->vcc; + } + if (params->avcc > 0) { + firmware->avcc = (uint32_t)params->avcc; + } + if (params->aref > 0) { + firmware->aref = (uint32_t)params->aref; + } + + // strncpy(firmware->mmcu, "atmega324p", sizeof(firmware->mmcu)); + // firmware->frequency = 20000000L; + if (firmware->frequency == 0) { + firmware->frequency = 8000000L; + } + if (firmware->vcc == 0) { + firmware->vcc = 5000; + } + if (firmware->avcc == 0) { + firmware->avcc = 5000; + } + if (firmware->aref == 0) { + firmware->aref = 2500; + } + if (firmware->mmcu[0] == 0) { + throw std::logic_error(error(AT, "missing cpu type, use --mmcu ... to set mmcu manually)", firmware->mmcu)); + } + + avr = avr_make_mcu_by_name(firmware->mmcu); + if (!avr) { + throw std::logic_error(error(AT, "avr_make_mcu_by_name() fails (mmcu=%s)", firmware->mmcu)); + } + if (params->gdbPort > 0) { + avr->gdb_port = params->gdbPort; + } else { + avr->gdb_port = 1234; + } + printf("init with port=%d, mmcu=%s, f=%u, vcc=%d, avcc=%d, aref=%d, pc=0x%04x\n", + avr->gdb_port, firmware->mmcu, firmware->frequency, firmware->vcc, firmware->avcc, firmware->aref, params->pc < 0 ? 0 : params->pc); + status.freqHz = firmware->frequency; + + if (avr_init(avr) != 0) { + throw std::logic_error(error(AT, "avr_init() fails")); + } + + + firmware->eeprom = (uint8_t *)malloc(1024); + for (int i = 0; i < 1024; i++) { + firmware->eeprom[i] = 0xff; + } + firmware->eeprom[0] = 0xf0; + firmware->eesize = 1024; + + avr_load_firmware(avr, firmware); + status.state = StateLoaded; + + avr->fuse[AVR_FUSE_LOW] = 0xe7; + avr->fuse[AVR_FUSE_HIGH] = 0xd8; + avr->fuse[AVR_FUSE_EXT] = 0xff; + avr->lockbits = 0xff; + + avr->gdb_port = 1234; + avr_gdb_init(avr); + if (params->pc >= 0) { + avr->pc = params->pc; + } + + pthread_mutex_unlock(&lock); + + } catch (std::exception& e) { + status.state = StateError; + pthread_mutex_unlock(&lock); + throw; + } + addEvent(EventLoad); +} + +// enabled/disable character output on stdout in case of avr uart write +void SimAvr::setUartDumpEnabled (bool enabled) { + if (avr == NULL) { + throw std::logic_error(error(AT, "setUartDumpEnabled() fails because no avr available")); + } + uint32_t f = 0; + avr_ioctl(avr, AVR_IOCTL_UART_GET_FLAGS('0'), &f); + f = enabled ? f | AVR_UART_FLAG_STDIO : f & ~AVR_UART_FLAG_STDIO; + avr_ioctl(avr, AVR_IOCTL_UART_SET_FLAGS('0'), &f); + avr_ioctl(avr, AVR_IOCTL_UART_GET_FLAGS('1'), &f); + f = enabled ? f | AVR_UART_FLAG_STDIO : f & ~AVR_UART_FLAG_STDIO; + avr_ioctl(avr, AVR_IOCTL_UART_SET_FLAGS('1'), &f); +} + +void SimAvr::registerIoWrite (avr_io_addr_t addr, avrsim_io_write_callback_t callback) { + avr_register_io_write(avr, addr, (avr_io_write_t)callback, this); +} + +void SimAvr::setUartPtyEnabled (int uart, bool enable) { + if (pthread_mutex_lock(&lock)) { + throw std::logic_error(error(AT, "start() fails caused by mutex error")); + } + uart_pty_t *p = NULL; + try { + if (uart < 0 || uart > 1) { + throw std::logic_error(error(AT, "setUartPtyEnabled() fails (invalid uart %d)", uart)); + } + if (enable && uartPty[uart] != NULL) { + throw std::logic_error(error(AT, "enableUartPty() fails (uart %d already enabled)", uart)); + } + if (!enable && uartPty[uart] == NULL) { + throw std::logic_error(error(AT, "enableUartPty() fails (uart %d not enabled)", uart)); + } + if (avr == NULL) { + throw std::logic_error(error(AT, "enableUartPty() fails (avr not ready)")); + } + if (enable) { + p = (uart_pty_t *)malloc(sizeof(uart_pty_t)); + if (p == NULL) { + throw std::logic_error(error(AT, "enableUartPty() fails (malloc fails)")); + } + memset(p, 0, sizeof(uart_pty_t)); + // setenv("SIMAVR_UART_TAP", "1", 1); + uart_pty_init(avr, p); + uart_pty_connect(p, uart + '0'); + uartPty[uart] = p; + } else { + uart_pty_stop(uartPty[uart]); + free(uartPty[uart]); + uartPty[uart] = NULL; + } + pthread_mutex_unlock(&lock); + + } catch (std::exception& e) { + if (p != NULL) { + free(p); + } + status.state = StateError; + pthread_mutex_unlock(&lock); + throw; + } +} + +void SimAvr::setUartPtyHook (int uart, void (*fromUart)(uint8_t), void (*toUart)(uint8_t)) { + if (pthread_mutex_lock(&lock)) { + throw std::logic_error(error(AT, "setUartPtyHook() fails caused by mutex error")); + } + try { + if (uart < 0 || uart > 1) { + throw std::logic_error(error(AT, "setUartPtyHook() fails (invalid uart %d)", uart)); + } + if (uartPty[uart] == NULL) { + throw std::logic_error(error(AT, "setUartPtyHook() fails (uart %d not enabled)", uart)); + } + uartPty[uart]->hook_from_uart = fromUart; + uartPty[uart]->hook_to_uart = toUart; + pthread_mutex_unlock(&lock); + + } catch (std::exception& e) { + status.state = StateError; + pthread_mutex_unlock(&lock); + throw; + } +} + +const char *SimAvr::getUartPtyDeviceName (int uart) { + if (pthread_mutex_lock(&lock)) { + throw std::logic_error(error(AT, "start() fails caused by mutex error")); + } + try { + if (uart < 0 || uart > 1) { + throw std::logic_error(error(AT, "getUartPtyDeviceName() fails (invalid uart %d)", uart)); + } + uart_pty_t *p = uartPty[uart]; + pthread_mutex_unlock(&lock); + return p == NULL ? NULL : p->port[0].slavename; + + } catch (std::exception& e) { + status.state = StateError; + pthread_mutex_unlock(&lock); + throw; + } +} + +const char *SimAvr::getTargetDeviceName () { + if (pthread_mutex_lock(&lock)) { + throw std::logic_error(error(AT, "start() fails caused by mutex error")); + } + try { + if (firmware == NULL) { + throw std::logic_error(error(AT, "getTargetDeviceName() fails (no firmware loaded)")); + } + pthread_mutex_unlock(&lock); + return firmware->mmcu; + + } catch (std::exception& e) { + status.state = StateError; + pthread_mutex_unlock(&lock); + throw; + } +} + +uint32_t SimAvr::getTargetFrequency () { + if (pthread_mutex_lock(&lock)) { + throw std::logic_error(error(AT, "start() fails caused by mutex error")); + } + try { + if (firmware == NULL) { + throw std::logic_error(error(AT, "getTargetDeviceName() fails (no firmware loaded)")); + } + pthread_mutex_unlock(&lock); + return firmware->frequency; + + } catch (std::exception& e) { + status.state = StateError; + pthread_mutex_unlock(&lock); + throw; + } +} + +void SimAvr::start () { + if (pthread_mutex_lock(&lock)) { + throw std::logic_error(error(AT, "start() fails caused by mutex error")); + } + try { + if (isShutdown) { + throw std::logic_error("start() not allowed after shutdown"); + } + if (avrRunThread != NULL) { + throw std::logic_error("simavr already started"); + } + if (avr == NULL) { + throw std::logic_error("avr not ready (check if load done)"); + } + syncTime[0] = !syncTime[1]; + avrRunThread = new std::thread(&SimAvr::avrRun, this); + pthread_mutex_unlock(&lock); + + } catch (std::exception& e) { + status.state = StateError; + pthread_mutex_unlock(&lock); + throw; + } + addEvent(EventStart); +} + + +void SimAvr::stop () { + if (pthread_mutex_lock(&lock)) { + throw std::logic_error(error(AT, "stop() fails caused by mutex error")); + } + try { + if (avrRunThread == NULL) { + throw std::logic_error("simavr not started"); + } + cancelThread = true; + pthread_mutex_unlock(&lock); + + } catch (std::exception& e) { + status.state = StateError; + pthread_mutex_unlock(&lock); + throw; + } + addEvent(EventStop); +} + +void SimAvr::setCommand (EnumSimAvrCommand cmd, void *param) { + if (command != ReadyForNewCommand) { + throw std::logic_error("another command pending"); + } + command = cmd; +} + +void SimAvr::addEvent (int event) { + struct timeval tp; + gettimeofday(&tp, NULL); + SimAvrEvent *p = (SimAvrEvent *)malloc(sizeof(SimAvrEvent)); + if (p != NULL) { + p->epochMillis = tp.tv_sec * 1000 + (long)tp.tv_usec / 1000; + p->event = event; + if (pthread_mutex_lock(&lock)) { + throw std::logic_error(error(AT, "addEvent() fails caused by mutex error")); + } + try { + p->cycle = avr->cycle; + if (!isShutdown) { + events.push_back(p); + eventCount.notify(); + } + pthread_mutex_unlock(&lock); + } catch (std::exception& e) { + status.state = StateError; + pthread_mutex_unlock(&lock); + throw; + } + } +} + + +void SimAvr::setTimeSync (bool sync) { + if (pthread_mutex_lock(&lock)) { + throw std::logic_error(error(AT, "setTimeSync() fails caused by mutex error")); + } + try { + syncTime[1] = sync; + pthread_mutex_unlock(&lock); + } catch (std::exception& e) { + status.state = StateError; + pthread_mutex_unlock(&lock); + throw; + } +} + + +struct SimAvrEvent SimAvr::waitForEvent () { + eventCount.wait(); + + if (pthread_mutex_lock(&lock)) { + throw std::logic_error(error(AT, "waitForEvent() fails caused by mutex error")); + } + try { + struct SimAvrEvent rv = { epochMillis: 0, event: EventUnknown }; + struct SimAvrEvent *p = NULL; + if (events.size() > 0) { + p = events.front(); + rv = *p; + if (p->event != EventShutdown) { + events.pop_front(); + free(p); + } + if (p->event == EventShutdown) { + cancelThread = true; + isShutdown = true; + } + } + pthread_mutex_unlock(&lock); + return rv; + + } catch (std::exception& e) { + status.state = StateError; + pthread_mutex_unlock(&lock); + throw; + } +} + +const char *SimAvr::eventText (EnumSimAvrEvent event) { + switch (event) { + case EventUnknown: return "Unknown"; + case EventShutdown: return "Shutdown"; + case EventLoad: return "Load"; + case EventStart: return "Start"; + case EventStop: return "Stop"; + default: return NULL; + } +} + +struct SimAvrStatus SimAvr::getStatus () { + if (pthread_mutex_lock(&lock)) { + throw std::logic_error(error(AT, "getStatus() fails caused by mutex error")); + } + struct SimAvrStatus rv = status; + pthread_mutex_unlock(&lock); + return rv; +} + +void SimAvr::printCyclesAndElapsedTime () { + uint64_t time = avr->cycle * 1000000000L / avr->frequency; + uint16_t nanos = time % 1000; time = time / 1000; + uint16_t micros = time % 1000; time = time / 1000; + uint16_t millis = time % 1000; time = time / 1000; + uint16_t seconds = time % 1000; time = time / 1000; + printf("cycle %" PRIu64 " = %ds %03dms %03dµs %03dns", avr->cycle, seconds, millis, micros, nanos); +} + +void SimAvr::avrRun () { + long cnt = 0; + int lastAvrState = -1; + _avr_sp_set(avr, 0); + while (1) { + try { + if (avr->state != lastAvrState) { + switch (avr->state) { + case cpu_Stopped: { + printf("\ncpu stopped at 0x%04x on ", avr->pc); + printCyclesAndElapsedTime(); + char sfr[9]; + sfr[7] = avr->sreg[0] ? 'C' : '-'; + sfr[6] = avr->sreg[1] ? 'Z' : '-'; + sfr[5] = avr->sreg[2] ? 'N' : '-'; + sfr[4] = avr->sreg[3] ? 'V' : '-'; + sfr[3] = avr->sreg[4] ? 'S' : '-'; + sfr[2] = avr->sreg[5] ? 'H' : '-'; + sfr[1] = avr->sreg[6] ? 'T' : '-'; + sfr[0] = avr->sreg[7] ? 'I' : '-'; + sfr[8] = 0; + printf(" SFR: %s\n ", sfr); + uint16_t x = 0, y = 0, z = 0; + for (int i = 0; i < 32; i++) { + uint8_t b = avr->data[i]; + printf(" r%02d=%02x", i, b); + switch (i) { + case 0x0f: printf("\n "); break; + case 0x1a: x = (x & 0xff00) | b; break; + case 0x1b: x = (x & 0x00ff) | (b << 8); break; + case 0x1c: y = (y & 0xff00) | b; break; + case 0x1d: y = (y & 0x00ff) | (b << 8); break; + case 0x1e: z = (z & 0xff00) | b; break; + case 0x1f: z = (z & 0x00ff) | (b << 8); break; + } + } + printf("\n X=0x%04x Y=0x%04x Z=0x%04x\n", x, y, z); + + uint16_t sp = _avr_sp_get(avr); + printf(" Stack (SP=0x%04x)", sp); + int printHeader = 1; + for (int i = 0; i < 16; i++) { + uint16_t addr = sp + 1 + i; + if (addr <= avr->ioend) { continue; } + if (addr > avr->ramend) { break; } + if (printHeader) { + printf(" -> SRAM 0x%04x:", addr); + printHeader = 0; + } + uint8_t b = avr_core_watch_read(avr, addr); + printf(" %02x", b); + + } + printf(printHeader ? "\n" : "\n"); + + printf(" Arduino LED L: "); + printf((avr->data[0x24] & 0x20) && (avr->data[0x25] & 0x20) ? "ON\n" : "OFF\n"); + + printf("\n"); + break; + } + case cpu_Sleeping: printf("cpu enter sleep mode at cycle %" PRIu64 "\n", avr->cycle); break; + case cpu_Running: printf("cpu starts running at cycle %" PRIu64 "\n", avr->cycle); break; + case cpu_Step: printf("cpu step\n"); break; + case cpu_StepDone: printf("cpu step done\n"); break; + case cpu_Done: printf("cpu done\n"); break; + case cpu_Crashed: printf("cpu crashed\n"); break; + default: printf("cpu enter unknown mode at cycle %" PRIu64 "\n", avr->cycle); break; + } + lastAvrState = avr->state; + } + + if (startParameters != NULL) { + switch (startParameters->board) { + case BoardNano: { + static int8_t ledL = -1; // pin floating + uint8_t ddrb = avr->data[0x24]; + uint8_t portb = avr->data[0x25]; + int8_t nextLedL = -1; + if (ddrb & 0x20) { + nextLedL = portb & 0x20 ? 1 : 0; + } + if (nextLedL != ledL) { + ledL = nextLedL; + printCyclesAndElapsedTime(); + printf(": LED L = %c\n", ledL ? 'X' : '.'); + } + break; + } + case BoardSure: { + static int8_t led[4] = { -1, -1, -1, -1 }; // pin floating + uint8_t ddra = avr->data[0x3a]; + uint8_t porta = avr->data[0x3b]; + int change = 0; + for (int i = 0; i < 4; i++) { + int8_t nextLed = -1; + if (ddra & (1 << i)) { + nextLed = porta & (1 << i) ? 0 : 1; + } + if (nextLed != led[i]) { + change = 1; + led[i] = nextLed; + } + } + if (change) { + printCyclesAndElapsedTime(); printf(": "); + printf(" LED PA[3210] ="); + for (int i = 3; i >= 0; i--) { + printf(" %c", led[i] ? 'X' : '.'); + } + printf("\n"); + } + break; + } + case BoardEWS1: { + static int8_t led = -1; // pin floating + uint8_t ddrb = avr->data[0x24]; + uint8_t portb = avr->data[0x25]; + int8_t nextLed = -1; + if (ddrb & 0x01) { + nextLed = portb & 0x01 ? 1 : 0; + } + if (nextLed != led) { + led = nextLed; + printCyclesAndElapsedTime(); + printf(": LED1 (PB0) = %c\n", led ? 'X' : '.'); + } + break; + } + default: break; + } + } + + if (cnt <= 0) { + // usleep(10000); + if (pthread_mutex_lock(&lock)) { + throw std::logic_error(error(AT, "avrRun() fails caused by mutex error (1)")); + } + try { + status.cycle = avr->cycle; + status.state = StateRunning; + status.running = true; + switch (avr->state) { + case cpu_Done: status.state = StateDone; break; + case cpu_Running: status.state = StateRunning; break; + case cpu_Crashed: status.state = StateCrashed; break; + default: status.state = StateOthers; break; + } + if (cancelThread) { + cnt = -1; + cancelThread = false; + } else { + if (syncTime[0] != syncTime[1]) { + syncTime[0] = syncTime[1]; + if (syncTime[0]) { + cyclesOnSyncStart = avr->cycle; + struct timeval tp; + gettimeofday(&tp, NULL); + timeMicrosOnSyncStart = tp.tv_usec + (uint64_t)tp.tv_sec * 1000000L; + } else { + cyclesOnSyncStart = -1; + timeMicrosOnSyncStart = 0; + } + } + if (syncTime[0]) { + uint64_t ucMicros = (uint64_t)(status.cycle - cyclesOnSyncStart) * 1000000L / status.freqHz ; + struct timeval tp; + gettimeofday(&tp, NULL); + const uint64_t timeMicros = tp.tv_usec + (uint64_t)tp.tv_sec * 1000000L - timeMicrosOnSyncStart; + + if (ucMicros > 3000000) { + ucMicros++; + } + + int64_t dt = ucMicros - timeMicros; + if (dt > 0) { + int us = dt > INT_MAX ? INT_MAX : (int)dt; + if (us > 1000) { + timeval ts; + ts.tv_sec = 0; + ts.tv_usec = us; + select(0, 0, 0, 0, &ts); + } + } + } + } + if (avr->state == cpu_Done) { + cnt = -1; + } else if (avr->state == cpu_Crashed) { + throw std::logic_error(error(AT, "avr state is cpu_Crashed")); + } + pthread_mutex_unlock(&lock); + + } catch (std::exception& e) { + status.state = StateError; + pthread_mutex_unlock(&lock); + throw; + } + } + + if (avr->state == cpu_Stopped) { + timeval ts; + ts.tv_sec = 0; + ts.tv_usec = 1000; + select(0, 0, 0, 0, &ts); + } + + if (cnt < 0) { + cyclesOnSyncStart = -1; + timeMicrosOnSyncStart = 0; + if (pthread_mutex_lock(&lock)) { + throw std::logic_error(error(AT, "avrRun() fails caused by mutex error (2)")); + } + try { + if (avrRunThread != NULL) { + avrRunThread->detach(); + delete avrRunThread; + avrRunThread = NULL; + } + pthread_mutex_unlock(&lock); + return; + } catch (std::exception& e) { + pthread_mutex_unlock(&lock); + status.state = StateError; + throw; + } + + } else if (++cnt >= 100000) { + cnt = 0; + } + + if (command != ReadyForNewCommand) { + switch (command) { + case CommandStatus: { + printCyclesAndElapsedTime(); + printf("\n"); + break; + } + case CommandInterrupt: { + if (avr->state == cpu_Running) { + avr->state = cpu_Stopped; + } + break; + } + case CommandContinue: { + if (avr->state == cpu_Stopped) { + avr->state = cpu_Running; + } + break; + } + case CommandStack: { + uint16_t sp = _avr_sp_get(avr); + printf("Stack: SP=0x%04x:\n", sp); + for (uint16_t addr = ((sp + 1) / 16) * 16; addr <= avr->ramend; addr++) { + if (addr % 16 == 0) { + printf(" 0x%04x:", addr); + } + if (addr % 4 == 0) { + printf(" "); + } + if (addr <= sp) { + printf(" "); + } else { + uint8_t b = avr_core_watch_read(avr, addr); + printf(" %02x", b); + } + if (addr % 16 == 15) { + printf("\n"); + } + } + printf("\n"); + break; + } + + default: break; + } + command = ReadyForNewCommand; + addEvent(EventCommandExecuted); + } + + avr_run(avr); + + } catch (std::exception& e) { + status.state = StateError; + cyclesOnSyncStart = -1; + timeMicrosOnSyncStart = 0; + if (pthread_mutex_lock(&lock)) { + throw std::logic_error(error(AT, "avrRun() fails caused by mutex error (2)")); + } + try { + if (avrRunThread != NULL) { + avrRunThread->detach(); + delete avrRunThread; + avrRunThread = NULL; + } + pthread_mutex_unlock(&lock); + throw; + } catch (std::exception& e) { + pthread_mutex_unlock(&lock); + status.state = StateError; + throw; + } + + } + } +} + diff --git a/examples/simuc/src/simavr/simavr.h b/examples/simuc/src/simavr/simavr.h new file mode 100644 index 0000000..e1455b7 --- /dev/null +++ b/examples/simuc/src/simavr/simavr.h @@ -0,0 +1,132 @@ +#ifndef SIMAVR_H +#define SIMAVR_H + +#include "semaphore.h" +#include "parts/uart_pty.h" + +#include +#include +#include + +#include +#include +#include + +typedef enum { + BoardUnknown = 0, + BoardNano, + BoardSure, + BoardEWS1 +} EnumStartParameterBoard; + + +struct StartParameters { + char *filename; + int gdbPort; + int64_t frequency; + const char *mmcu; + EnumStartParameterBoard board; + int32_t pc; + int32_t vcc; + int32_t avcc; + int32_t aref; +}; + +enum SimAvrState { + StateInit = 0, + StateError = 1, + StateLoaded = 10, + StateRunning = 11, + StateDone = 12, + StateCrashed = 20, + StateOthers = 99, + StateUnknown = 100 +}; + +typedef enum { + EventUnknown = 0, + EventShutdown = -1, + EventLoad = -2, + EventStart = -3, + EventStop = -4, + EventCommandExecuted = -5 +} EnumSimAvrEvent; + +typedef enum { + ReadyForNewCommand = 0, + CommandStatus, + CommandInterrupt, + CommandContinue, + CommandStack +} EnumSimAvrCommand; + +struct SimAvrStatus { + long long freqHz; + long long cycle; + enum SimAvrState state; + bool running; +}; + +struct SimAvrEvent { + long long epochMillis; + long long cycle; + int event; +}; + + +class SimAvr; +typedef void (*avrsim_io_write_callback_t)(avr_t *avr, avr_io_addr_t addr, uint8_t value, SimAvr *simavr); + +class SimAvr { + +public: + SimAvr (); + ~SimAvr (); + + struct SimAvrStatus getStatus (); + struct SimAvrEvent waitForEvent (); + const char *eventText (EnumSimAvrEvent event); + +public: + void load (struct StartParameters *params); + void shutdown (); + void start (); + void stop (); + void addEvent (int event); + void setUartDumpEnabled (bool enabled); + void setUartPtyEnabled (int uart, bool enabled); + void setUartPtyHook (int uart, void (*fromUart)(uint8_t), void (*toUart)(uint8_t)); + void registerIoWrite (avr_io_addr_t addr, avrsim_io_write_callback_t callback); + + const char *getTargetDeviceName (); + uint32_t getTargetFrequency (); + const char *getUartPtyDeviceName (int uart); + + void avrRun (); + void setLed (bool on); + void setTimeSync (bool sync); + void setCommand (EnumSimAvrCommand cmd, void *param); + +private: + elf_firmware_t *firmware = NULL; + avr_t *avr = NULL;; + StartParameters *startParameters = NULL;; + pthread_mutex_t lock; + std::list events; + EnumSimAvrCommand command; + struct SimAvrStatus status; + bool cancelThread = false; + bool isShutdown = false; + bool syncTime[2] = { false, true }; + std::thread *avrRunThread = NULL; + long cyclesOnSyncStart = -1; + uint64_t timeMicrosOnSyncStart = 0; + Semaphore eventCount; + uart_pty_t *uartPty[2] = { NULL, NULL }; + void printCyclesAndElapsedTime (); +}; + + + + +#endif // SIMAVR_H \ No newline at end of file -- 2.39.5