+++ /dev/null
-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 <sx@htl-kaindorf.at>
-Description: megaavr microcontroller simulation
+++ /dev/null
-../doc/htl-simuc/readme
\ No newline at end of file
+++ /dev/null
-/*
- avr_mcu_section.h
-
- Copyright 2008-2013 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#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 <stdint.h>
-
-#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
+++ /dev/null
-/*\r
- avr_acomp.c\r
-\r
- Copyright 2017 Konstantin Begun\r
-\r
- This file is part of simavr.\r
-\r
- simavr is free software: you can redistribute it and/or modify\r
- it under the terms of the GNU General Public License as published by\r
- the Free Software Foundation, either version 3 of the License, or\r
- (at your option) any later version.\r
-\r
- simavr is distributed in the hope that it will be useful,\r
- but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- GNU General Public License for more details.\r
-\r
- You should have received a copy of the GNU General Public License\r
- along with simavr. If not, see <http://www.gnu.org/licenses/>.\r
- */\r
-\r
-#include <stdlib.h>\r
-#include "avr_acomp.h"\r
-#include "avr_timer.h"\r
-\r
-static uint8_t\r
-avr_acomp_get_state(\r
- struct avr_t * avr,\r
- avr_acomp_t *ac)\r
-{\r
- if (avr_regbit_get(avr, ac->disabled))\r
- return 0;\r
-\r
- // get positive voltage\r
- uint16_t positive_v;\r
-\r
- if (avr_regbit_get(avr, ac->acbg)) { // if bandgap\r
- positive_v = ACOMP_BANDGAP;\r
- } else {\r
- positive_v = ac->ain_values[0]; // AIN0\r
- }\r
-\r
- // get negative voltage\r
- uint16_t negative_v = 0;\r
-\r
- // multiplexer is enabled if acme is set and adc is off\r
- if (avr_regbit_get(avr, ac->acme) && !avr_regbit_get(avr, ac->aden)) {\r
- if (!avr_regbit_get(avr, ac->pradc)) {\r
- uint8_t adc_i = avr_regbit_get_array(avr, ac->mux, ARRAY_SIZE(ac->mux));\r
- if (adc_i < ac->mux_inputs && adc_i < ARRAY_SIZE(ac->adc_values)) {\r
- negative_v = ac->adc_values[adc_i];\r
- }\r
- }\r
-\r
- } else {\r
- negative_v = ac->ain_values[1]; // AIN1\r
- }\r
-\r
- return positive_v > negative_v;\r
-}\r
-\r
-static avr_cycle_count_t\r
-avr_acomp_sync_state(\r
- struct avr_t * avr,\r
- avr_cycle_count_t when,\r
- void * param)\r
-{\r
- avr_acomp_t * p = (avr_acomp_t *)param;\r
- if (!avr_regbit_get(avr, p->disabled)) {\r
-\r
- uint8_t cur_state = avr_regbit_get(avr, p->aco);\r
- uint8_t new_state = avr_acomp_get_state(avr, p);\r
-\r
- if (new_state != cur_state) {\r
- avr_regbit_setto(avr, p->aco, new_state); // set ACO\r
-\r
- uint8_t acis0 = avr_regbit_get(avr, p->acis[0]);\r
- uint8_t acis1 = avr_regbit_get(avr, p->acis[1]);\r
-\r
- if ((acis0 == 0 && acis1 == 0) || (acis1 == 1 && acis0 == new_state)) {\r
- avr_raise_interrupt(avr, &p->ac);\r
- }\r
-\r
- avr_raise_irq(p->io.irq + ACOMP_IRQ_OUT, new_state);\r
- }\r
-\r
- }\r
-\r
- return 0;\r
-}\r
-\r
-static inline void\r
-avr_schedule_sync_state(\r
- struct avr_t * avr,\r
- void *param)\r
-{\r
- avr_cycle_timer_register(avr, 1, avr_acomp_sync_state, param);\r
-}\r
-\r
-static void\r
-avr_acomp_write_acsr(\r
- struct avr_t * avr,\r
- avr_io_addr_t addr,\r
- uint8_t v,\r
- void * param)\r
-{\r
- avr_acomp_t * p = (avr_acomp_t *)param;\r
-\r
- avr_core_watch_write(avr, addr, v);\r
-\r
- if (avr_regbit_get(avr, p->acic) != (p->timer_irq ? 1:0)) {\r
- if (p->timer_irq) {\r
- avr_unconnect_irq(p->io.irq + ACOMP_IRQ_OUT, p->timer_irq);\r
- p->timer_irq = NULL;\r
- }\r
- else {\r
- avr_irq_t *irq = avr_io_getirq(avr, AVR_IOCTL_TIMER_GETIRQ(p->timer_name), TIMER_IRQ_IN_ICP);\r
- if (irq) {\r
- avr_connect_irq(p->io.irq + ACOMP_IRQ_OUT, irq);\r
- p->timer_irq = irq;\r
- }\r
- }\r
- }\r
-\r
- avr_schedule_sync_state(avr, param);\r
-}\r
-\r
-static void\r
-avr_acomp_dependencies_changed(\r
- struct avr_irq_t * irq,\r
- uint32_t value,\r
- void * param)\r
-{\r
- avr_acomp_t * p = (avr_acomp_t *)param;\r
- avr_schedule_sync_state(p->io.avr, param);\r
-}\r
-\r
-static void\r
-avr_acomp_irq_notify(\r
- struct avr_irq_t * irq,\r
- uint32_t value,\r
- void * param)\r
-{\r
- avr_acomp_t * p = (avr_acomp_t *)param;\r
-\r
- switch (irq->irq) {\r
- case ACOMP_IRQ_AIN0 ... ACOMP_IRQ_AIN1: {\r
- p->ain_values[irq->irq - ACOMP_IRQ_AIN0] = value;\r
- avr_schedule_sync_state(p->io.avr, param);\r
- } break;\r
- case ACOMP_IRQ_ADC0 ... ACOMP_IRQ_ADC15: {\r
- p->adc_values[irq->irq - ACOMP_IRQ_ADC0] = value;\r
- avr_schedule_sync_state(p->io.avr, param);\r
- } break;\r
- }\r
-}\r
-\r
-static void\r
-avr_acomp_register_dependencies(\r
- avr_acomp_t *p,\r
- avr_regbit_t rb)\r
-{\r
- if (rb.reg) {\r
- avr_irq_register_notify(\r
- avr_iomem_getirq(p->io.avr, rb.reg, NULL, rb.bit),\r
- avr_acomp_dependencies_changed,\r
- p);\r
- }\r
-}\r
-\r
-static void\r
-avr_acomp_reset(avr_io_t * port)\r
-{\r
- avr_acomp_t * p = (avr_acomp_t *)port;\r
-\r
- for (int i = 0; i < ACOMP_IRQ_COUNT; i++)\r
- avr_irq_register_notify(p->io.irq + i, avr_acomp_irq_notify, p);\r
-\r
- // register notification for changes of registers comparator does not own\r
- // avr_register_io_write is tempting instead, but it requires that the handler\r
- // updates the actual memory too. Given this is for the registers this module\r
- // does not own, it is tricky to know whether it should write to the actual memory.\r
- // E.g., if there is already a native handler for it then it will do the writing\r
- // (possibly even omitting some bits etc). IInterefering would probably be wrong.\r
- // On the other hand if there isn't a handler already, then this hadnler would have to,\r
- // as otherwise nobody will.\r
- // This write notification mechanism should probably need reviewing and fixing\r
- // For now using IRQ mechanism, as it is not intrusive\r
-\r
- avr_acomp_register_dependencies(p, p->pradc);\r
- avr_acomp_register_dependencies(p, p->aden);\r
- avr_acomp_register_dependencies(p, p->acme);\r
-\r
- // mux\r
- for (int i = 0; i < ARRAY_SIZE(p->mux); ++i) {\r
- avr_acomp_register_dependencies(p, p->mux[i]);\r
- }\r
-}\r
-\r
-static const char * irq_names[ACOMP_IRQ_COUNT] = {\r
- [ACOMP_IRQ_AIN0] = "16<ain0",\r
- [ACOMP_IRQ_AIN1] = "16<ain1",\r
- [ACOMP_IRQ_ADC0] = "16<adc0",\r
- [ACOMP_IRQ_ADC1] = "16<adc1",\r
- [ACOMP_IRQ_ADC2] = "16<adc2",\r
- [ACOMP_IRQ_ADC3] = "16<adc3",\r
- [ACOMP_IRQ_ADC4] = "16<adc4",\r
- [ACOMP_IRQ_ADC5] = "16<adc5",\r
- [ACOMP_IRQ_ADC6] = "16<adc6",\r
- [ACOMP_IRQ_ADC7] = "16<adc7",\r
- [ACOMP_IRQ_ADC8] = "16<adc0",\r
- [ACOMP_IRQ_ADC9] = "16<adc9",\r
- [ACOMP_IRQ_ADC10] = "16<adc10",\r
- [ACOMP_IRQ_ADC11] = "16<adc11",\r
- [ACOMP_IRQ_ADC12] = "16<adc12",\r
- [ACOMP_IRQ_ADC13] = "16<adc13",\r
- [ACOMP_IRQ_ADC14] = "16<adc14",\r
- [ACOMP_IRQ_ADC15] = "16<adc15",\r
- [ACOMP_IRQ_OUT] = ">out"\r
-};\r
-\r
-static avr_io_t _io = {\r
- .kind = "ac",\r
- .reset = avr_acomp_reset,\r
- .irq_names = irq_names,\r
-};\r
-\r
-void\r
-avr_acomp_init(\r
- avr_t * avr,\r
- avr_acomp_t * p)\r
-{\r
- p->io = _io;\r
-\r
- avr_register_io(avr, &p->io);\r
- avr_register_vector(avr, &p->ac);\r
- // allocate this module's IRQ\r
- avr_io_setirqs(&p->io, AVR_IOCTL_ACOMP_GETIRQ, ACOMP_IRQ_COUNT, NULL);\r
-\r
- avr_register_io_write(avr, p->r_acsr, avr_acomp_write_acsr, p);\r
-}\r
+++ /dev/null
-/*\r
- avr_acomp.h\r
-\r
- Copyright 2017 Konstantin Begun\r
-\r
- This file is part of simavr.\r
-\r
- simavr is free software: you can redistribute it and/or modify\r
- it under the terms of the GNU General Public License as published by\r
- the Free Software Foundation, either version 3 of the License, or\r
- (at your option) any later version.\r
-\r
- simavr is distributed in the hope that it will be useful,\r
- but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- GNU General Public License for more details.\r
-\r
- You should have received a copy of the GNU General Public License\r
- along with simavr. If not, see <http://www.gnu.org/licenses/>.\r
- */\r
-\r
-#ifndef __AVR_COMP_H___\r
-#define __AVR_COMP_H___\r
-\r
-#ifdef __cplusplus\r
-extern "C" {\r
-#endif\r
-\r
-#include "sim_avr.h"\r
-\r
-/*\r
- * simavr Analog Comparator allows external code to feed real voltages to the\r
- * simulator, and the simulator uses it's 'real' reference voltage\r
- * to set comparator output accordingly and trigger in interrupt, if set up this way\r
- *\r
- */\r
-\r
-enum {\r
- // input IRQ values. Values are /always/ volts * 1000 (millivolts)\r
- ACOMP_IRQ_AIN0 = 0, ACOMP_IRQ_AIN1,\r
- ACOMP_IRQ_ADC0, ACOMP_IRQ_ADC1, ACOMP_IRQ_ADC2, ACOMP_IRQ_ADC3,\r
- ACOMP_IRQ_ADC4, ACOMP_IRQ_ADC5, ACOMP_IRQ_ADC6, ACOMP_IRQ_ADC7,\r
- ACOMP_IRQ_ADC8, ACOMP_IRQ_ADC9, ACOMP_IRQ_ADC10, ACOMP_IRQ_ADC11,\r
- ACOMP_IRQ_ADC12, ACOMP_IRQ_ADC13, ACOMP_IRQ_ADC14, ACOMP_IRQ_ADC15,\r
- ACOMP_IRQ_OUT, // output has changed\r
- ACOMP_IRQ_COUNT\r
-};\r
-\r
-// Get the internal IRQ corresponding to the INT\r
-#define AVR_IOCTL_ACOMP_GETIRQ AVR_IOCTL_DEF('a','c','m','p')\r
-\r
-enum {\r
- ACOMP_BANDGAP = 1100\r
-};\r
-\r
-typedef struct avr_acomp_t {\r
- avr_io_t io;\r
-\r
- uint8_t mux_inputs; // number of inputs (not mux bits!) in multiplexer. Other bits in mux below would be expected to be zero\r
- avr_regbit_t mux[4];\r
- avr_regbit_t pradc; // ADC power reduction, this impacts on ability to use adc multiplexer\r
- avr_regbit_t aden; // ADC Enabled, this impacts on ability to use adc multiplexer\r
- avr_regbit_t acme; // AC multiplexed input enabled\r
-\r
- avr_io_addr_t r_acsr; // control & status register\r
- avr_regbit_t acis[2]; //\r
- avr_regbit_t acic; // input capture enable\r
- avr_regbit_t aco; // output\r
- avr_regbit_t acbg; // bandgap select\r
- avr_regbit_t disabled;\r
-\r
- char timer_name; // connected timer for incput capture triggering\r
-\r
- // use ACI and ACIE bits\r
- avr_int_vector_t ac;\r
-\r
- // runtime data\r
- uint16_t adc_values[16]; // current values on the ADCs inputs\r
- uint16_t ain_values[2]; // current values on AIN inputs\r
- avr_irq_t* timer_irq;\r
-} avr_acomp_t;\r
-\r
-void avr_acomp_init(avr_t * avr, avr_acomp_t * port);\r
-\r
-#ifdef __cplusplus\r
-};\r
-#endif\r
-\r
-#endif // __AVR_COMP_H___\r
+++ /dev/null
-/*
- avr_adc.c
-
- Copyright 2008, 2010 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#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] = "16<adc0",
- [ADC_IRQ_ADC1] = "16<adc1",
- [ADC_IRQ_ADC2] = "16<adc2",
- [ADC_IRQ_ADC3] = "16<adc3",
- [ADC_IRQ_ADC4] = "16<adc4",
- [ADC_IRQ_ADC5] = "16<adc5",
- [ADC_IRQ_ADC6] = "16<adc6",
- [ADC_IRQ_ADC7] = "16<adc7",
- [ADC_IRQ_ADC8] = "16<adc0",
- [ADC_IRQ_ADC9] = "16<adc9",
- [ADC_IRQ_ADC10] = "16<adc10",
- [ADC_IRQ_ADC11] = "16<adc11",
- [ADC_IRQ_ADC12] = "16<adc12",
- [ADC_IRQ_ADC13] = "16<adc13",
- [ADC_IRQ_ADC14] = "16<adc14",
- [ADC_IRQ_ADC15] = "16<adc15",
- [ADC_IRQ_TEMP] = "16<temp",
- [ADC_IRQ_IN_TRIGGER] = "<trigger_in",
- [ADC_IRQ_OUT_TRIGGER] = ">trigger_out",
-};
-
-static avr_io_t _io = {
- .kind = "adc",
- .reset = avr_adc_reset,
- .irq_names = irq_names,
-};
-
-void avr_adc_init(avr_t * avr, avr_adc_t * p)
-{
- p->io = _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);
-}
+++ /dev/null
-/*
- avr_adc.h
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#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___ */
+++ /dev/null
-/*
- avr_bitbang.c
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
- 2011 Stephan Veigl <veig@gmx.net>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __AVR_BITBANG_H__
-#define __AVR_BITBANG_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#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__*/
+++ /dev/null
-/*
- avr_bitbang.h
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
- 2011 Stephan Veigl <veig@gmx.net>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- @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
+++ /dev/null
-/*
- avr_eeprom.c
-
- IO module that simulates the AVR EEProm
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#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);
-}
-
+++ /dev/null
-/*
- avr_eeprom.h
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#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__ */
+++ /dev/null
-/*
- avr_extint.c
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#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] = "<int0",
- [EXTINT_IRQ_OUT_INT1] = "<int1",
- [EXTINT_IRQ_OUT_INT2] = "<int2",
- [EXTINT_IRQ_OUT_INT3] = "<int3",
- [EXTINT_IRQ_OUT_INT4] = "<int4",
- [EXTINT_IRQ_OUT_INT5] = "<int5",
- [EXTINT_IRQ_OUT_INT6] = "<int6",
- [EXTINT_IRQ_OUT_INT7] = "<int7",
-};
-
-static avr_io_t _io = {
- .kind = "extint",
- .reset = avr_extint_reset,
- .irq_names = irq_names,
-};
-
-void avr_extint_init(avr_t * avr, avr_extint_t * p)
-{
- p->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);
-}
-
+++ /dev/null
-/*
- avr_extint.h
-
- External Interrupt Handling (for INT0-3)
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
- Copyright 2014 Doug Szumski <d.s.szumski@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#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__*/
+++ /dev/null
-/*
- avr_flash.c
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#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);
-}
+++ /dev/null
-/*
- avr_flash.h
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#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___ */
+++ /dev/null
-/*
- avr_ioport.c
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#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);
- }
-}
+++ /dev/null
-/*
- avr_ioport.h
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#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__ */
+++ /dev/null
-/*
- avr_lin.h
-
- Copyright 2008, 2011 Michel Pollet <buserror@gmail.com>
- Copyright 2011 Markus Lampert <mlampert@telus.net>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#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);
-}
+++ /dev/null
-/*
- avr_lin.h
-
- Copyright 2008, 2011 Michel Pollet <buserror@gmail.com>
- Copyright 2011 Markus Lampert <mlampert@telus.net>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#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__ */
+++ /dev/null
-/*
- avr_spi.c
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
- Modified 2020 by VintagePC <https://github.com/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 <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#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] = "8<in",
- [SPI_IRQ_OUTPUT] = "8<out",
-};
-
-static avr_io_t _io = {
- .kind = "spi",
- .reset = avr_spi_reset,
- .irq_names = irq_names,
-};
-
-void avr_spi_init(avr_t * avr, avr_spi_t * p)
-{
- p->io = _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);
-}
+++ /dev/null
-/*
- avr_spi.h
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
- Modified 2020 by VintagePC <https://github.com/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 <http://www.gnu.org/licenses/>.
- */
-
-#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__*/
+++ /dev/null
-/*
- avr_timer.c
-
- Handles the 8 bits and 16 bits AVR timer.
- Handles
- + CDC
- + Fast PWM
-
- Copyright 2008-2012 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <math.h>
-
-#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] = "<icp",
- [TIMER_IRQ_OUT_COMP + 0] = ">compa",
- [TIMER_IRQ_OUT_COMP + 1] = ">compb",
- [TIMER_IRQ_OUT_COMP + 2] = ">compc",
-};
-
-static avr_io_t _io = {
- .kind = "timer",
- .irq_names = irq_names,
- .reset = avr_timer_reset,
- .ioctl = avr_timer_ioctl,
-};
-
-void
-avr_timer_init(
- avr_t * avr,
- avr_timer_t * p)
-{
- p->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;
- }
-}
+++ /dev/null
-/*
- avr_timer.h
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#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__*/
+++ /dev/null
-/*
- avr_twi.c
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#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] = "8<input",
- [TWI_IRQ_OUTPUT] = "32>output",
- [TWI_IRQ_STATUS] = "8>status",
-};
-
-static avr_io_t _io = {
- .kind = "twi",
- .reset = avr_twi_reset,
- .irq_names = irq_names,
-};
-
-void avr_twi_init(avr_t * avr, avr_twi_t * p)
-{
- p->io = _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;
-}
+++ /dev/null
-/*
- avr_twi.h
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#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__*/
+++ /dev/null
-/*
- 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 <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifdef NO_COLOR
- #define FONT_GREEN
- #define FONT_DEFAULT
-#else
- #define FONT_GREEN "\e[32m"
- #define FONT_DEFAULT "\e[0m"
-#endif
-
-#include <stdio.h>
-#include <unistd.h>
-#include <stdint.h>
-#include <stdlib.h>
-#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] = "8<in",
- [UART_IRQ_OUTPUT] = "8>out",
- [UART_IRQ_OUT_XON] = ">xon",
- [UART_IRQ_OUT_XOFF] = ">xoff",
-};
-
-static avr_io_t _io = {
- .kind = "uart",
- .reset = avr_uart_reset,
- .ioctl = avr_uart_ioctl,
- .irq_names = irq_names,
-};
-
-void
-avr_uart_init(
- avr_t * avr,
- avr_uart_t * p)
-{
- p->io = _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);
-}
-
+++ /dev/null
-/*
- avr_uart.h
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#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__*/
+++ /dev/null
-/* vim: set sts=4:sw=4:ts=4:noexpandtab
- avr_usb.c
-
- Copyright 2012 Torbjorn Tyridal <ttyridal@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/* 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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#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);
-}
-
+++ /dev/null
-/* vim: set sts=4:sw=4:ts=4:noexpandtab
- avr_usb.h
-
- Copyright 2012 Torbjorn Tyridal <ttyridal@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#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__*/
+++ /dev/null
-/*
- avr_watchdog.c
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#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;
-}
-
+++ /dev/null
-/*
- avr_watchdog.h
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#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___ */
+++ /dev/null
-/*
- fido_declare.h
- Copyright (C) 2003-2012 Michel Pollet <buserror@gmail.com>
-
- 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 <stdint.h>
-
-#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
+++ /dev/null
-/*
- run_avr.c
-
- Copyright 2008, 2010 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <libgen.h>
-#include <string.h>
-#include <signal.h>
-#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 [...] <firmware>\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 <freq>] Sets the frequency for an .hex firmware\n"
- " [--mcu|-m <device>] Sets the MCU type for an .hex firmware\n"
- " [--gdb|-g [<port>]] Listen for gdb connection on <port> "
- "(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 <vector>] Add traces for IRQ vector <vector>\n"
- " [--input|-i <file>] A VCD file to use as input signals\n"
- " [--output|-o <file>] A VCD file to save the traced signals\n"
- " [--add-trace|-at <name=kind@addr/mask>]\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"
- " <firmware> 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);
-}
+++ /dev/null
-/*
- sim_avr.c
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <sys/time.h>
-#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);
- }
-}
-
+++ /dev/null
-/*
- sim_avr.h
-
- Copyright 2008-2012 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#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 <stdarg.h>
-/*
- * 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__*/
-
+++ /dev/null
-/*
- sim_avr_types.h
-
- Copyright 2008-2012 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#ifndef __SIM_AVR_TYPES_H___
-#define __SIM_AVR_TYPES_H___
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stdint.h>
-#include <inttypes.h>
-
-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___ */
+++ /dev/null
-/*
- sim_cmds.c
-
- Copyright 2014 Florian Albrechtskirchinger <falbrechtskirchinger@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include <stdlib.h>
-#include <string.h>
-#include "sim_avr.h"
-#include "sim_cmds.h"
-#include "sim_vcd_file.h"
-#include "avr_uart.h"
-#include "avr/avr_mcu_section.h"
-
-#define LOG_PREFIX "CMDS: "
-
-static void
-_avr_cmd_io_write(
- avr_t * avr,
- avr_io_addr_t addr,
- uint8_t v,
- void * param)
-{
- avr_cmd_table_t * commands = &avr->commands;
- avr_cmd_t * command = commands->pending;
-
- AVR_LOG(avr, LOG_TRACE, LOG_PREFIX "%s: 0x%02x\n", __FUNCTION__, v);
-
- if (!command) {
- if (v > MAX_AVR_COMMANDS) {
- AVR_LOG(avr, LOG_ERROR, LOG_PREFIX
- "%s: code 0x%02x outside permissible range (>0x%02x)\n",
- __FUNCTION__, v, MAX_AVR_COMMANDS - 1);
- return;
- }
- command = &commands->table[v];
- }
- if (!command->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);
-}
+++ /dev/null
-/*
- sim_cmds.h
-
- Copyright 2014 Florian Albrechtskirchinger <falbrechtskirchinger@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#pragma once
-
-#include "sim_avr_types.h"
-
-#define MAX_AVR_COMMANDS 32
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef int (*avr_cmd_handler_t)(
- struct avr_t * avr,
- uint8_t v,
- void * param);
-
-typedef struct avr_cmd_t {
- avr_cmd_handler_t handler;
- void * param;
-} avr_cmd_t;
-
-typedef struct avr_cmd_table_t {
- avr_cmd_t table[MAX_AVR_COMMANDS];
- avr_cmd_t * pending; // Holds a reference to a pending multi-byte command
-} avr_cmd_table_t;
-
-// Called by avr_set_command_register()
-void
-avr_cmd_set_register(
- struct avr_t * avr,
- avr_io_addr_t addr);
-
-/*
- * Register a command distinguished by 'code'.
- *
- * When 'code' is written to the configured IO address, 'handler' is executed
- * with the value written, as well as 'param'.
- * 'handler' can return non-zero, to indicate, that this is a multi-byte command.
- * Subsequent writes are then dispatched to the same handler, until 0 is returned.
- */
-void
-avr_cmd_register(
- struct avr_t * avr,
- uint8_t code,
- avr_cmd_handler_t handler,
- void * param);
-
-void
-avr_cmd_unregister(
- struct avr_t * avr,
- uint8_t code);
-
-// Private functions
-
-// Called from avr_init() to initialize the avr_cmd_table_t and register builtin commands.
-void
-avr_cmd_init(
- struct avr_t * avr);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/*
- sim_core.c
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-#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;
-}
+++ /dev/null
-/*
- sim_core.h
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#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__*/
+++ /dev/null
-/*
- sim_cycle_timers.c
-
- Copyright 2008-2012 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#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);
-}
+++ /dev/null
-/*
- sim_cycle_timers.h
-
- Copyright 2008-2012 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * 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___ */
+++ /dev/null
-/*
- 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 <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <libelf.h>
-#include <gelf.h>
-
-#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;
-}
+++ /dev/null
-/*
- sim_elf.h
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#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__*/
+++ /dev/null
-/*
- sim_gdb.c
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "sim_network.h"
-#include <sys/time.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <pthread.h>
-#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 <base> <count>
- // 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<memory-map>\n"
- " <memory type='ram' start='0x800000' length='%#x'/>\n"
- " <memory type='flash' start='0' length='%#x'>\n"
- " <property name='blocksize'>0x80</property>\n"
- " </memory>\n"
- "</memory-map>",
- 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();
-}
+++ /dev/null
-/*
- sim_gdb.h
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#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
+++ /dev/null
-/*
- sim_hex.c
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#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
+++ /dev/null
-/*
- sim_hex.h
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#ifndef __SIM_HEX_H___
-#define __SIM_HEX_H___
-
-#include <stdint.h>
-#include <stddef.h>
-
-#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___ */
+++ /dev/null
-/*
- sim_interrupts.c
-
- Copyright 2008-2012 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <strings.h>
-#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);
- }
-}
-
+++ /dev/null
-/*
- sim_interrupts.h
-
- Copyright 2008-2012 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#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__ */
+++ /dev/null
-/*
- sim_io.c
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-#include <stdint.h>
-#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;
-}
+++ /dev/null
-/*
- sim_io.h
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#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__ */
+++ /dev/null
-/*
- sim_irq.c
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#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;
-}
+++ /dev/null
-/*
- sim_irq.h
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __SIM_IRQ_H__
-#define __SIM_IRQ_H__
-
-#include <stdint.h>
-
-#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__ */
+++ /dev/null
-/*
- sim_network.h
-
- Copyright 2012 Stephan Veigl <veigl@gmx.net>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __SIM_NETWORK_H__
-#define __SIM_NETWORK_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef __MINGW32__
-
-// Windows with MinGW
-
-#include <winsock2.h>
-#include <windows.h>
-#include <ws2tcpip.h>
-
-#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 <netinet/in.h>
-#include <netinet/tcp.h>
-#include <arpa/inet.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <poll.h>
-
-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__*/
+++ /dev/null
-/*
- sim_regbit.h
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#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__ */
+++ /dev/null
-/*
- sim_time.h
-
- Copyright 2008-2012 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#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___ */
+++ /dev/null
-/*
- sim_utils.c
-
- Implements a Value Change Dump file outout to generate
- traces & curves and display them in gtkwave.
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <string.h>
-#include <stdlib.h>
-
-#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;
-}
+++ /dev/null
-/*
- sim_utils.h
-
- Implements a Value Change Dump file outout to generate
- traces & curves and display them in gtkwave.
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __SIM_UTILS_H__
-#define __SIM_UTILS_H__
-
-#include <stdint.h>
-
-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__ */
+++ /dev/null
-/*
- 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 <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <inttypes.h>
-#include <ctype.h>
-#include <time.h>
-#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:
- * #<absolute timestamp>[\n][<value x/z/0/1><signal alias character>|
- * b[x/z/0/1]?<space><signal alias character|
- * r<real value><space><signal alias character]+
- * For example:
- * #1234 1' 0$
- * Or:
- * #1234
- * b1101x1 '
- * 0$
- *
- * This function tries to handle this transparently, and pushes the
- * signal/values into the FIFO for processing by the timer when
- * convenient.
- * NOTE: Add 'floating' support here. Also, FIX THE TIMING.
- */
-static avr_cycle_count_t
-avr_vcd_input_parse_line(
- avr_vcd_t * vcd,
- argv_p v )
-{
- uint64_t res = 0;
- int vi = 0;
-
- if (v->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 <four-character ioctl>[_<IRQ index>] */
- 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;
-}
-
-
+++ /dev/null
-/*
- 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 <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __SIM_VCD_FILE_H__
-#define __SIM_VCD_FILE_H__
-
-#include <stdio.h>
-#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__ */
+++ /dev/null
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-
-#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 <Enter> 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
+++ /dev/null
-#include "error.h"
-#include <stdarg.h>
-
-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;
-}
+++ /dev/null
-#ifndef ERROR_H
-#define ERROR_H
-
-#include <string>
-
-#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
+++ /dev/null
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <libgen.h>
-#include <errno.h>
-#include <stdarg.h>
-
-#include <stdexcept>
-#include <string>
-#include <iostream>
-#include <vector>
-
-#include <GL/glut.h>
-#include <pthread.h>
-#include <simavr/sim_avr.h>
-#include <simavr/sim_elf.h>
-#include <simavr/sim_gdb.h>
-
-#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<uint8_t> gdbFromUartBuffer;
-std::vector<uint8_t> 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 "?";
- }
- }
-}
+++ /dev/null
-#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
+++ /dev/null
-/*
- fido_declare.h
- Copyright (C) 2003-2012 Michel Pollet <buserror@gmail.com>
-
- 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 <stdint.h>
-
-#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
+++ /dev/null
-/*
- uart_pty.c
-
- Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <simavr/sim_network.h>
-#include <stdlib.h>
-#include <pthread.h>
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <signal.h>
-#ifdef __APPLE__
-#include <util.h>
-#elif defined (__FreeBSD__)
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <termios.h>
-#include <libutil.h>
-#else
-#include <pty.h>
-#endif
-
-#include "uart_pty.h"
-#include <simavr/avr_uart.h>
-#include <simavr/sim_time.h>
-#include <simavr/sim_hex.h>
-
-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] = "8<uart_pty.in",
- [IRQ_UART_PTY_BYTE_OUT] = "8>uart_pty.out",
-};
-
-void
-uart_pty_init(
- struct avr_t * avr,
- uart_pty_t * p)
-{
- memset(p, 0, sizeof(*p));
-
- p->avr = 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");
- }
-}
+++ /dev/null
-/*
- uart_pty.h
-
- Copyright 2012 Michel Pollet <buserror@gmail.com>
-
- This file is part of simavr.
-
- simavr is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- simavr is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#ifndef __UART_PTY_H___
-#define __UART_PTY_H___
-
-#include <pthread.h>
-#include <simavr/sim_irq.h>
-#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___ */
-
+++ /dev/null
-#ifndef SEMAPHORE_H
-#define SEMAPHORE_H
-
-#include <mutex>
-#include <condition_variable>
-
-class Semaphore {
- public:
- Semaphore (int count_ = 0) : count(count_) {
- }
-
- inline void notify () {
- std::unique_lock<std::mutex> lock(mtx);
- count++;
- //notify the waiting thread
- cv.notify_one();
- }
- inline void wait () {
- std::unique_lock<std::mutex> 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
+++ /dev/null
-#include "simavr.h"
-#include "../sim/error.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <limits.h>
-#include <sys/time.h>
-
-#include <iostream>
-#include <iomanip>
-#include <thread>
-
-#include <simavr/sim_gdb.h>
-#include <simavr/sim_irq.h>
-#include <simavr/sim_avr.h>
-#include <simavr/sim_core.h>
-#include <simavr/avr_uart.h>
-
-
-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;
- }
-
- }
- }
-}
-
+++ /dev/null
-#ifndef SIMAVR_H
-#define SIMAVR_H
-
-#include "semaphore.h"
-#include "parts/uart_pty.h"
-
-#include <simavr/sim_avr.h>
-#include <simavr/sim_elf.h>
-#include <simavr/sim_io.h>
-
-#include <string>
-#include <thread>
-#include <list>
-
-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<struct SimAvrEvent *> 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