diff options
Diffstat (limited to '')
| -rw-r--r-- | src/instruction.spec.ts | 79 | ||||
| -rw-r--r-- | src/instruction.ts | 41 |
2 files changed, 106 insertions, 14 deletions
diff --git a/src/instruction.spec.ts b/src/instruction.spec.ts index 29c9a49..99c904d 100644 --- a/src/instruction.spec.ts +++ b/src/instruction.spec.ts @@ -15,6 +15,16 @@ describe('avrInstruction', () => { } } + it('should execute `CALL` instruction', () => { + loadProgram('0e945c00'); + cpu.data[93] = 150; // SP <- 50 + avrInstruction(cpu); + expect(cpu.pc).toEqual(0x5c); + expect(cpu.data[150]).toEqual(2); // return addr + expect(cpu.data[93]).toEqual(148); // SP should be decremented + expect(cpu.cycles).toEqual(5); + }); + it('should execute `CPC r27, r18` instruction', () => { loadProgram('b207'); cpu.data[18] = 0x1; @@ -34,20 +44,31 @@ describe('avrInstruction', () => { expect(cpu.data[95]).toEqual(53); // SREG 00110101 - HSNC }); - it('should execute `JMP 0xb8` instruction', () => { - loadProgram('0c945c00'); + it('should execute `INC r5` instruction', () => { + loadProgram('5394'); + cpu.data[5] = 0x7f; avrInstruction(cpu); - expect(cpu.pc).toEqual(0x5c); - expect(cpu.cycles).toEqual(3); + expect(cpu.data[5]).toEqual(0x80); + expect(cpu.pc).toEqual(1); + expect(cpu.cycles).toEqual(1); + expect(cpu.data[95]).toEqual(0x0c); // SREG 00001100 NV }); - it('should execute `OUT 0x3f, r1` instruction', () => { - loadProgram('1fbe'); - cpu.data[1] = 0x5a; // r1 <- 0x5a + it('should execute `INC r5` instruction when r5 == 0xff', () => { + loadProgram('5394'); + cpu.data[5] = 0xff; avrInstruction(cpu); - expect(cpu.pc).toEqual(0x1); + expect(cpu.data[5]).toEqual(0); + expect(cpu.pc).toEqual(1); expect(cpu.cycles).toEqual(1); - expect(cpu.data[0x5f]).toEqual(0x5a); + expect(cpu.data[95]).toEqual(2); // SREG 00000010 - Z + }); + + it('should execute `JMP 0xb8` instruction', () => { + loadProgram('0c945c00'); + avrInstruction(cpu); + expect(cpu.pc).toEqual(0x5c); + expect(cpu.cycles).toEqual(3); }); it('should execute `LDI r28, 0xff` instruction', () => { @@ -179,6 +200,36 @@ describe('avrInstruction', () => { expect(cpu.data[30]).toEqual(0x80); // verify that Z was unchanged }); + it('should execute `OUT 0x3f, r1` instruction', () => { + loadProgram('1fbe'); + cpu.data[1] = 0x5a; // r1 <- 0x5a + avrInstruction(cpu); + expect(cpu.pc).toEqual(0x1); + expect(cpu.cycles).toEqual(1); + expect(cpu.data[0x5f]).toEqual(0x5a); + }); + + it('should execute `RET` instruction', () => { + loadProgram('0895'); + cpu.data[93] = 0x90; // SP <- 0x90 + cpu.data[0x92] = 16; + avrInstruction(cpu); + expect(cpu.pc).toEqual(16); + expect(cpu.cycles).toEqual(5); + expect(cpu.data[93]).toEqual(0x92); // SP should increment + }); + + it('should execute `RETI` instruction', () => { + loadProgram('1895'); + cpu.data[93] = 0xc0; // SP <- 0xc0 + cpu.data[0xc2] = 200; + avrInstruction(cpu); + expect(cpu.pc).toEqual(200); + expect(cpu.cycles).toEqual(5); + expect(cpu.data[93]).toEqual(0xc2); // SP should increment + expect(cpu.data[95]).toEqual(0x80); // SREG 10000000 I + }); + it('should execute `RJMP 2` instruction', () => { loadProgram('01c0'); avrInstruction(cpu); @@ -186,6 +237,16 @@ describe('avrInstruction', () => { expect(cpu.cycles).toEqual(2); }); + it('should execute `ROR r0` instruction', () => { + loadProgram('0794'); + cpu.data[0] = 0x11; // r0 <- 0x11 + avrInstruction(cpu); + expect(cpu.pc).toEqual(1); + expect(cpu.cycles).toEqual(1); + expect(cpu.data[0]).toEqual(0x08); // r0 should be right-shifted + expect(cpu.data[95]).toEqual(0x19); // SREG 00011001 SVI + }); + it('should execute `ST X, r1` instruction', () => { loadProgram('1c92'); cpu.data[1] = 0x5a; // r1 <- 0x5a diff --git a/src/instruction.ts b/src/instruction.ts index a0d7492..f520143 100644 --- a/src/instruction.ts +++ b/src/instruction.ts @@ -73,7 +73,14 @@ export function avrInstruction(cpu: ICPU) { /* CALL, 1001 010k kkkk 111k kkkk kkkk kkkk kkkk */ if ((opcode & 0xfe0e) === 0x940e) { - /* not implemented */ + const k = cpu.progMem[cpu.pc + 1] | ((opcode & 1) << 16) | ((opcode & 0x1f0) << 13); + const ret = cpu.pc + 2; + const sp = cpu.dataView.getUint16(93, true); + cpu.data[sp] = 255 & ret; + cpu.data[sp - 1] = (ret >> 8) & 255; + cpu.dataView.setUint16(93, sp - 2, true); + cpu.pc = k - 1; + cpu.cycles += 4; } /* CBI, 1001 1000 AAAA Abbb */ @@ -168,7 +175,15 @@ export function avrInstruction(cpu: ICPU) { /* INC, 1001 010d dddd 0011 */ if ((opcode & 0xfe0f) === 0x9403) { - /* not implemented */ + const d = cpu.data[(opcode & 0x1f0) >> 4]; + const r = (d + 1) & 255; + cpu.data[(opcode & 0x1f0) >> 4] = r; + let sreg = cpu.data[95]; + sreg = (sreg & 0xfd) | (0 === r ? 2 : 0); + sreg = (sreg & 0xfb) | (0 !== (128 & r) ? 4 : 0); + sreg = (sreg & 0xf7) | (127 === d ? 8 : 0); + sreg = (sreg & 0xef) | (((sreg >> 2) & 1) ^ ((sreg >> 3) & 1) ? 0x10 : 0); + cpu.data[95] = sreg; } /* JMP, 1001 010k kkkk 110k kkkk kkkk kkkk kkkk */ @@ -376,12 +391,19 @@ export function avrInstruction(cpu: ICPU) { /* RET, 1001 0101 0000 1000 */ if (opcode === 0x9508) { - /* not implemented */ + const i = cpu.dataView.getUint16(93, true) + 2; + cpu.dataView.setUint16(93, i, true); + cpu.pc = (cpu.data[i - 1] << 8) + cpu.data[i] - 1; + cpu.cycles += 4; } /* RETI, 1001 0101 0001 1000 */ if (opcode === 0x9518) { - /* not implemented */ + const i = cpu.dataView.getUint16(93, true) + 2; + cpu.dataView.setUint16(93, i, true); + cpu.pc = (cpu.data[i - 1] << 8) + cpu.data[i] - 1; + cpu.cycles += 4; + cpu.data[95] |= 0x80; // Enable interrupts } /* RJMP, 1100 kkkk kkkk kkkk */ @@ -392,7 +414,16 @@ export function avrInstruction(cpu: ICPU) { /* ROR, 1001 010d dddd 0111 */ if ((opcode & 0xfe0f) === 0x9407) { - /* not implemented */ + const d = cpu.data[(opcode & 0x1f0) >> 4]; + const r = (d >>> 1) | ((cpu.data[95] & 1) << 7); + cpu.data[(opcode & 0x1f0) >> 4] = r; + let sreg = cpu.data[95]; + sreg = (sreg & 0xfd) | (0 === r ? 2 : 0); + sreg = (sreg & 0xfb) | (0 !== (128 & r) ? 4 : 0); + sreg = (sreg & 0xfe) | (1 & d ? 1 : 0); + sreg = (sreg & 0xf7) | (((sreg >> 2) & 1) ^ (sreg & 1) ? 8 : 0); + sreg = (sreg & 0xef) | (((sreg >> 2) & 1) ^ ((sreg >> 3) & 1) ? 0x10 : 0); + cpu.data[95] = sreg; } /* SBC, 0000 10rd dddd rrrr */ |
