// 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
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();
}
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 (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) {
* 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);
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
}
} 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");
int p = opcode & 0x100;
if (e && !avr->eind)
_avr_invalid_opcode(avr);
- uint16_t z = avr->data[R_ZL] | (avr->data[R_ZH] << 8);
+ 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);
case 0x9007: { // ELPM Extended Load Program Memory 1001 000d dddd 01oo
if (!avr->rampz)
_avr_invalid_opcode(avr);
- uint16_t z = avr->data[R_ZL] | (avr->data[R_ZH] << 8) | (avr->data[avr->rampz] << 16);
+ uint32_t z = avr->data[R_ZL] | (avr->data[R_ZH] << 8) | (avr->data[avr->rampz] << 16);
uint8_t r = (opcode >> 4) & 0x1f;
int op = opcode & 3;
STATE("elpm %s, (Z[%02x:%04x]%s)\n", avr_regname(r), z >> 16, z&0xffff, opcode?"+":"");