Commit 1cbc06407c5d63714195e3e62a7de66b87e702b5
authorMichel Pollet <buserror@gmail.com>
Sun, 4 Apr 2010 11:20:34 +0000 (12:20 +0100)
committerMichel Pollet <buserror@gmail.com>
Sun, 4 Apr 2010 11:20:34 +0000 (12:20 +0100)
Added RAMPZ as an optional IOREG for the core.
Factored the [E]I[JMP/CALL] into one blob.
Added the ELMP Instruction with RAMPZ support.

Signed-off-by: Michel Pollet <buserror@gmail.com>
2 files changed:
simavr/sim/sim_avr.h
simavr/sim/sim_core.c

index 9c2256d22a825dca95d9764d31164917f0b91b49..4af20be5f8554491815199bcc0c822373ae29c51 100644 (file)
@@ -78,6 +78,7 @@ typedef struct avr_t {
        uint8_t         vector_size;
        uint8_t         signature[3];
        uint8_t         fuse[4];
+       avr_io_addr_t   rampz;  // optional, only for ELPM/SPM on >64Kb cores
 
        // filled by the ELF data, this allow tracking of invalid jumps
        uint32_t                        codeend;
index 31c2ab35c94fb9c5b628e3461d11d3e9ad80396b..1ccae6b912bfb1e05a2d76f8cc25b6aceaf64a98 100644 (file)
@@ -819,22 +819,26 @@ uint16_t avr_run_one(avr_t * avr)
                                        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;
@@ -890,6 +894,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