X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=simavr%2Fsim%2Fsim_core.c;h=31c2ab35c94fb9c5b628e3461d11d3e9ad80396b;hb=2f67001d;hp=197b71991635877d516e136753ebe28bd44f6f19;hpb=eab7a03e7ab811e50497f1316f6dac1b622d007f;p=simavr diff --git a/simavr/sim/sim_core.c b/simavr/sim/sim_core.c index 197b719..31c2ab3 100644 --- a/simavr/sim/sim_core.c +++ b/simavr/sim/sim_core.c @@ -25,6 +25,8 @@ #include #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"; @@ -58,7 +60,7 @@ int donttrace = 0; #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) { \ @@ -83,6 +85,41 @@ int donttrace = 0; #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 @@ -93,10 +130,10 @@ static inline void _avr_set_r(avr_t * avr, uint8_t r, uint8_t v) 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) { @@ -144,8 +181,22 @@ static inline void _avr_set_ram(avr_t * avr, uint16_t addr, uint8_t v) */ 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); @@ -264,7 +315,7 @@ void avr_dump_state(avr_t * avr) #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); @@ -301,7 +352,7 @@ void avr_dump_state(avr_t * avr) /****************************************************************************\ * * 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. * \****************************************************************************/ @@ -375,36 +426,35 @@ static inline int _avr_is_instruction_32_bits(avr_t * avr, uint32_t pc) * * 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+= 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) { @@ -763,6 +813,11 @@ uint16_t avr_run_one(avr_t * avr) } 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); @@ -1156,15 +1211,12 @@ uint16_t avr_run_one(avr_t * avr) 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);