X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=simavr%2Fsim%2Fsim_core.c;h=5e7e2c8f86342a1e42a031f848d46efabf5f2165;hb=43c83e991c0705b7dc981ca760aa14fd3331604c;hp=6d95fb58383e13aa764a69aa86a87a5618b90ab7;hpb=b73f9b6094e2c9639fded52022ec60556ae8f8de;p=simavr diff --git a/simavr/sim/sim_core.c b/simavr/sim/sim_core.c index 6d95fb5..5e7e2c8 100644 --- a/simavr/sim/sim_core.c +++ b/simavr/sim/sim_core.c @@ -25,20 +25,13 @@ #include #include "sim_avr.h" #include "sim_core.h" +#include "sim_gdb.h" #include "avr_flash.h" #include "avr_watchdog.h" // SREG bit names const char * _sreg_bit_name = "cznvshti"; -#ifdef NO_COLOR - #define FONT_RED - #define FONT_DEFAULT -#else - #define FONT_RED "\e[31m" - #define FONT_DEFAULT "\e[0m" -#endif - /* * Handle "touching" registers, marking them changed. * This is used only for debugging purposes to be able to @@ -52,8 +45,8 @@ const char * _sreg_bit_name = "cznvshti"; #define REG_ISTOUCHED(a, r) ((a)->trace_data->touched[(r) >> 5] & (1 << ((r) & 0x1f))) /* - * This allows a "special case" to skip indtruction tracing when in these - * symbols. since printf() is useful to have, but generates a lot of cycles + * 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) { @@ -100,12 +93,12 @@ int donttrace = 0; 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_LOG(avr, LOG_ERROR, "CORE: *** 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 + 1] | (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_LOG(avr, LOG_ERROR, "CORE: *** 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 + 1] | (avr->flash[avr->pc]<<8), addr, v); CRASH(); } @@ -119,22 +112,32 @@ void avr_core_watch_write(avr_t *avr, uint16_t addr, uint8_t v) 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; } uint8_t avr_core_watch_read(avr_t *avr, uint16_t addr) { if (addr > avr->ramend) { - printf( FONT_RED "*** Invalid read address PC=%04x SP=%04x O=%04x Address %04x out of ram (%04x)\n" FONT_DEFAULT, + AVR_LOG(avr, LOG_ERROR, FONT_RED "CORE: *** Invalid read address PC=%04x SP=%04x O=%04x Address %04x out of ram (%04x)\n" FONT_DEFAULT, avr->pc, _avr_sp_get(avr), avr->flash[avr->pc + 1] | (avr->flash[avr->pc]<<8), addr, avr->ramend); CRASH(); } + + if (avr->gdb) { + avr_gdb_handle_watchpoints(avr, addr, AVR_GDB_WATCH_READ); + } + return avr->data[addr]; } /* * Set a register (r < 256) - * if it's an IO regisrer (> 31) also (try to) call any callback that was + * 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, uint8_t r, uint8_t v) @@ -144,8 +147,7 @@ static inline void _avr_set_r(avr_t * avr, uint8_t r, uint8_t v) if (r == R_SREG) { avr->data[R_SREG] = v; // unsplit the SREG - for (int i = 0; i < 8; i++) - avr->sreg[i] = (v & (1 << i)) != 0; + SET_SREG_FROM(avr, v); SREG(); } if (r > 31) { @@ -198,13 +200,7 @@ static inline uint8_t _avr_get_ram(avr_t * avr, uint16_t addr) * 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); + READ_SREG_INTO(avr, avr->data[R_SREG]); } else if (addr > 31 && addr < 256) { uint8_t io = AVR_DATA_TO_IO(addr); @@ -287,7 +283,7 @@ static void _avr_invalid_opcode(avr_t * avr) 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[avr->pc] | (avr->flash[avr->pc+1]<<8)); #else - printf( FONT_RED "*** %04x: Invalid Opcode SP=%04x O=%04x \n" FONT_DEFAULT, + 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[avr->pc] | (avr->flash[avr->pc+1]<<8)); #endif } @@ -451,7 +447,7 @@ static inline int _avr_is_instruction_32_bits(avr_t * avr, avr_flashaddr_t pc) * + It also doesn't check whether the core it's * emulating is supposed to have the fancy instructions, like multiply and such. * - * The nunber of cycles taken by instruction has been added, but might not be + * 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) @@ -816,7 +812,12 @@ avr_flashaddr_t avr_run_one(avr_t * avr) } else switch (opcode) { case 0x9588: { // SLEEP STATE("sleep\n"); - avr->state = cpu_Sleeping; + /* 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 STATE("break\n");