core: Fix MULS register
[simavr] / simavr / sim / sim_core.c
index ee95552..3550771 100644 (file)
@@ -26,6 +26,7 @@
 #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";
@@ -129,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) {
@@ -180,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);
                
@@ -300,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);
@@ -502,8 +517,8 @@ uint16_t avr_run_one(avr_t * avr)
                                                                        _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);
@@ -692,7 +707,8 @@ uint16_t avr_run_one(avr_t * avr)
                        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];
@@ -798,27 +814,32 @@ 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
+                               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;
@@ -874,6 +895,23 @@ uint16_t avr_run_one(avr_t * avr)
                                                        }
                                                        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
@@ -1195,15 +1233,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);