#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";
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);
_avr_set_r(avr, d+1, avr->data[r+1]);
} break;
case 0x0200: { // MULS – Multiply Signed 0000 0010 dddd rrrr
- int8_t r = opcode & 0xf;
- int8_t d = (opcode >> 4) & 0xf;
+ 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_r(avr, 0, res);
uint8_t res = vr - k - avr->sreg[S_C];
STATE("sbci %s[%02x], 0x%02x = %02x\n", avr_regname(r), avr->data[r], k, res);
_avr_set_r(avr, r, res);
- avr->sreg[S_Z] = res == 0;
+ if (res)
+ avr->sreg[S_Z] = 0;
avr->sreg[S_N] = (res >> 7) & 1;
avr->sreg[S_C] = (k + avr->sreg[S_C]) > vr;
avr->sreg[S_S] = avr->sreg[S_N] ^ avr->sreg[S_V];
} 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
+ 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);
uint16_t z = avr->data[R_ZL] | (avr->data[R_ZH] << 8);
- STATE("ijmp Z[%04x]\n", z << 1);
+ 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_push16(avr, new_pc >> 1);
+ }
new_pc = z << 1;
cycle++;
TRACE_JUMP();
} break;
- case 0x9509: { // ICALL Indirect Call to Subroutine
- uint16_t z = avr->data[R_ZL] | (avr->data[R_ZH] << 8);
- STATE("icall Z[%04x]\n", z << 1);
- _avr_push16(avr, new_pc >> 1);
- new_pc = z << 1;
- cycle += 2;
- TRACE_JUMP();
- STACK_FRAME_PUSH();
- } break;
case 0x9518: // RETI
case 0x9508: { // RET
new_pc = _avr_pop16(avr) << 1;
}
cycle += 2;
} break;
+ case 0x9006:
+ 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);
+ 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?"+":"");
+ _avr_set_r(avr, r, avr->flash[z]);
+ if (op == 3) {
+ z++;
+ _avr_set_r(avr, avr->rampz, z >> 16);
+ _avr_set_r(avr, R_ZH, z >> 8);
+ _avr_set_r(avr, R_ZL, z);
+ }
+ cycle += 2;
+ } break;
case 0x900c:
case 0x900d:
case 0x900e: { // LD Load Indirect from Data using X 1001 000r rrrr 11oo
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);