#include <ctype.h>
#include "sim_avr.h"
#include "sim_core.h"
+#include "avr_flash.h"
+#include "avr_watchdog.h"
// SREG bit names
const char * _sreg_bit_name = "cznvshti";
#define STATE(_f, args...) { \
if (avr->trace) {\
- if (avr->codeline[avr->pc>>1]) {\
+ if (avr->codeline && avr->codeline[avr->pc>>1]) {\
const char * symn = avr->codeline[avr->pc>>1]->symbol; \
int dont = 0 && dont_trace(symn);\
if (dont!=donttrace) { \
#define SREG()
#endif
+void avr_core_watch_write(avr_t *avr, uint16_t addr, uint8_t v)
+{
+ if (addr > avr->ramend) {
+ printf("*** Invalid write address PC=%04x SP=%04x O=%04x Address %04x=%02x out of ram\n",
+ avr->pc, _avr_sp_get(avr), avr->flash[avr->pc] | (avr->flash[avr->pc]<<8), addr, v);
+ CRASH();
+ }
+ if (addr < 32) {
+ printf("*** Invalid write address PC=%04x SP=%04x O=%04x Address %04x=%02x low registers\n",
+ avr->pc, _avr_sp_get(avr), avr->flash[avr->pc] | (avr->flash[avr->pc]<<8), addr, v);
+ CRASH();
+ }
+#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->stack_frame_index > 1 && addr > avr->stack_frame[avr->stack_frame_index-2].sp) {
+ printf("\e[31m%04x : munching stack SP %04x, A=%04x <= %02x\e[0m\n", avr->pc, _avr_sp_get(avr), addr, v);
+ }
+#endif
+ avr->data[addr] = v;
+}
+
+uint8_t avr_core_watch_read(avr_t *avr, uint16_t addr)
+{
+ if (addr > avr->ramend) {
+ printf("*** Invalid read address PC=%04x SP=%04x O=%04x Address %04x out of ram (%04x)\n",
+ avr->pc, _avr_sp_get(avr), avr->flash[avr->pc] | (avr->flash[avr->pc]<<8), addr, avr->ramend);
+ CRASH();
+ }
+ return avr->data[addr];
+}
+
/*
* Set a register (r < 256)
* if it's an IO regisrer (> 31) also (try to) call any callback that was
REG_TOUCH(avr, r);
if (r == R_SREG) {
- avr->data[r] = v;
+ avr->data[R_SREG] = v;
// unsplit the SREG
for (int i = 0; i < 8; i++)
- avr->sreg[i] = (avr->data[R_SREG] & (1 << i)) != 0;
+ avr->sreg[i] = (v & (1 << i)) != 0;
SREG();
}
if (r > 31) {
*/
static inline uint8_t _avr_get_ram(avr_t * avr, uint16_t addr)
{
- if (addr > 31 && addr < 256) {
+ if (addr == R_SREG) {
+ /*
+ * SREG is special it's reconstructed when read
+ * while the core itself uses the "shortcut" array
+ */
+ avr->data[R_SREG] = 0;
+ for (int i = 0; i < 8; i++)
+ if (avr->sreg[i] > 1) {
+ printf("** Invalid SREG!!\n");
+ CRASH();
+ } else if (avr->sreg[i])
+ avr->data[R_SREG] |= (1 << i);
+
+ } else if (addr > 31 && addr < 256) {
uint8_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);
#define get_r_d_10(o) \
const uint8_t r = ((o >> 5) & 0x10) | (o & 0xf); \
const uint8_t d = (o >> 4) & 0x1f;\
- const uint8_t vd = avr->data[d], vr =avr->data[r];
+ const uint8_t vd = avr->data[d], vr = avr->data[r];
#define get_k_r16(o) \
const uint8_t r = 16 + ((o >> 4) & 0xf); \
const uint8_t k = ((o & 0x0f00) >> 4) | (o & 0xf);
/****************************************************************************\
*
* Helper functions for calculating the status register bit values.
- * See the Atmel data sheet for the instuction set for more info.
+ * See the Atmel data sheet for the instruction set for more info.
*
\****************************************************************************/
*
* 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 becane apparent later on, so SOME instructions
+ * 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 wether the core it's
- * emulating is suposed to have the fancy instructions, like multiply and such.
+ * + It also doesn't check whether the core it's
+ * emulating is supposed to have the fancy instructions, like multiply and such.
*
* for now all instructions take "one" cycle, the cycle+=<extra> needs to be added.
*/
uint16_t avr_run_one(avr_t * avr)
{
+#if CONFIG_SIMAVR_TRACE
/*
- * this traces spurious reset or bad jump/opcodes and dumps the last 32 "jumps" to track it down
+ * this traces spurious reset or bad jumps
*/
if ((avr->pc == 0 && avr->cycle > 0) || avr->pc >= avr->codeend) {
avr->trace = 1;
STATE("RESET\n");
CRASH();
}
+ avr->touched[0] = avr->touched[1] = avr->touched[2] = 0;
+#endif
uint32_t opcode = (avr->flash[avr->pc + 1] << 8) | avr->flash[avr->pc];
uint32_t new_pc = avr->pc + 2; // future "default" pc
int cycle = 1;
-#if CONFIG_SIMAVR_TRACE
- avr->touched[0] = avr->touched[1] = avr->touched[2] = 0;
-#endif
-
switch (opcode & 0xf000) {
case 0x0000: {
switch (opcode) {
} break;
case 0x95a8: { // WDR
STATE("wdr\n");
+ avr_ioctl(avr, AVR_IOCTL_WATCHDOG_RESET, 0);
+ } break;
+ case 0x95e8: { // SPM
+ STATE("spm\n");
+ avr_ioctl(avr, AVR_IOCTL_FLASH_SPM, 0);
} break;
case 0x9409: { // IJMP Indirect jump
uint16_t z = avr->data[R_ZL] | (avr->data[R_ZH] << 8);
uint8_t r = (opcode >> 4) & 0x1f;
uint8_t A = ((((opcode >> 9) & 3) << 4) | ((opcode) & 0xf)) + 32;
STATE("out %s, %s[%02x]\n", avr_regname(A), avr_regname(r), avr->data[r]);
- // todo: store to IO register
_avr_set_ram(avr, A, avr->data[r]);
- // avr->data[A] = ;
} break;
case 0xb000: { // IN Rd,A 1011 0AAr rrrr AAAA
uint8_t r = (opcode >> 4) & 0x1f;
uint8_t A = ((((opcode >> 9) & 3) << 4) | ((opcode) & 0xf)) + 32;
STATE("in %s, %s[%02x]\n", avr_regname(r), avr_regname(A), avr->data[A]);
- // todo: get the IO register
_avr_set_r(avr, r, _avr_get_ram(avr, A));
} break;
default: _avr_invalid_opcode(avr);