diff options
| author | Uri Shaked | 2019-11-20 19:31:28 +0200 |
|---|---|---|
| committer | Uri Shaked | 2019-11-20 19:31:28 +0200 |
| commit | 8b9e52c7f6759e3907c425d2fbc2028ba7b41209 (patch) | |
| tree | e9864e096dfd46de3ecb246297f4a426a8c655a3 /src | |
| parent | feat: LAC, LAS, LAT, LDS instructions + tests (diff) | |
| download | avr8js-8b9e52c7f6759e3907c425d2fbc2028ba7b41209.tar.gz avr8js-8b9e52c7f6759e3907c425d2fbc2028ba7b41209.tar.bz2 avr8js-8b9e52c7f6759e3907c425d2fbc2028ba7b41209.zip | |
feat: LPM, LSR, MOV, MOVW, MUL, MULS, MULSU, NEG
+ tests
Diffstat (limited to 'src')
| -rw-r--r-- | src/instruction.spec.ts | 153 | ||||
| -rw-r--r-- | src/instruction.ts | 61 |
2 files changed, 195 insertions, 19 deletions
diff --git a/src/instruction.spec.ts b/src/instruction.spec.ts index d37b67a..9ab4a75 100644 --- a/src/instruction.spec.ts +++ b/src/instruction.spec.ts @@ -37,7 +37,7 @@ describe('avrInstruction', () => { it('should execute `BRBC 0, +8` instruction when SREG.C is clear', () => { loadProgram('20f4'); - cpu.data[95] = 0x8; // SREG <- 0b00001000 (V) + cpu.data[95] = 0b00001000; // SREG: V avrInstruction(cpu); expect(cpu.pc).toEqual(1 + 8 / 2); expect(cpu.cycles).toEqual(2); @@ -45,7 +45,7 @@ describe('avrInstruction', () => { it('should execute `BRBC 0, +8` instruction when SREG.C is set', () => { loadProgram('20f4'); - cpu.data[95] = 0x1; // SREG <- 0b00000001 (C) + cpu.data[95] = 0b00000001; // SREG: C avrInstruction(cpu); expect(cpu.pc).toEqual(1); expect(cpu.cycles).toEqual(1); @@ -53,7 +53,7 @@ describe('avrInstruction', () => { it('should execute `BRBS 3, 92` instruction when SREG.V is set', () => { loadProgram('73f1'); - cpu.data[95] = 0x8; // SREG <- 0b00001000 (V) + cpu.data[95] = 0b00001000; // SREG: V avrInstruction(cpu); expect(cpu.pc).toEqual(1 + 92 / 2); expect(cpu.cycles).toEqual(2); @@ -61,7 +61,7 @@ describe('avrInstruction', () => { it('should execute `BRBS 3, -4` instruction when SREG.V is set', () => { loadProgram('0000f3f3'); - cpu.data[95] = 0x8; // SREG <- 0b00001000 (V) + cpu.data[95] = 0b00001000; // SREG: V avrInstruction(cpu); avrInstruction(cpu); expect(cpu.pc).toEqual(0); @@ -102,7 +102,7 @@ describe('avrInstruction', () => { avrInstruction(cpu); expect(cpu.pc).toEqual(1); expect(cpu.cycles).toEqual(1); - expect(cpu.data[95]).toEqual(53); // SREG 00110101 - HSNC + expect(cpu.data[95]).toEqual(0b00110101); // SREG: HSNC }); it('should execute `INC r5` instruction', () => { @@ -112,7 +112,7 @@ describe('avrInstruction', () => { 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 + expect(cpu.data[95]).toEqual(0b00001100); // SREG: NV }); it('should execute `INC r5` instruction when r5 == 0xff', () => { @@ -122,7 +122,7 @@ describe('avrInstruction', () => { expect(cpu.data[5]).toEqual(0); expect(cpu.pc).toEqual(1); expect(cpu.cycles).toEqual(1); - expect(cpu.data[95]).toEqual(2); // SREG 00000010 - Z + expect(cpu.data[95]).toEqual(0b00000010); // SREG: Z }); it('should execute `JMP 0xb8` instruction', () => { @@ -309,6 +309,141 @@ describe('avrInstruction', () => { expect(cpu.data[30]).toEqual(0x80); // verify that Z was unchanged }); + it('should execute `LPM` instruction', () => { + loadProgram('c895'); + cpu.progMem[0x40] = 0xa0; + cpu.data[30] = 0x80; // Z <- 0x80 + avrInstruction(cpu); + expect(cpu.pc).toEqual(1); + expect(cpu.cycles).toEqual(3); + expect(cpu.data[0]).toEqual(0xa0); + expect(cpu.data[30]).toEqual(0x80); // verify that Z was unchanged + }); + + it('should execute `LPM r2` instruction', () => { + loadProgram('2490'); + cpu.progMem[0x40] = 0xa0; + cpu.data[30] = 0x80; // Z <- 0x80 + avrInstruction(cpu); + expect(cpu.pc).toEqual(1); + expect(cpu.cycles).toEqual(3); + expect(cpu.data[2]).toEqual(0xa0); + expect(cpu.data[30]).toEqual(0x80); // verify that Z was unchanged + }); + + it('should execute `LPM r1, Z+` instruction', () => { + loadProgram('1590'); + cpu.progMem[0x40] = 0xa0; + cpu.data[30] = 0x80; // Z <- 0x80 + avrInstruction(cpu); + expect(cpu.pc).toEqual(1); + expect(cpu.cycles).toEqual(3); + expect(cpu.data[1]).toEqual(0xa0); + expect(cpu.data[30]).toEqual(0x81); // verify that Z was incremented + }); + + it('should execute `LSR r7` instruction', () => { + loadProgram('7694'); + cpu.data[7] = 0x45; // r7 <- 0x45 + avrInstruction(cpu); + expect(cpu.pc).toEqual(1); + expect(cpu.cycles).toEqual(1); + expect(cpu.data[7]).toEqual(0x22); + expect(cpu.data[95]).toEqual(0b00011001); // SREG SVC + }); + + it('should execute `MOV r7, r8` instruction', () => { + loadProgram('782c'); + cpu.data[8] = 0x45; // r7 <- 0x45 + avrInstruction(cpu); + expect(cpu.pc).toEqual(1); + expect(cpu.cycles).toEqual(1); + expect(cpu.data[7]).toEqual(0x45); + }); + + it('should execute `MOVW r26, r22` instruction', () => { + loadProgram('db01'); + cpu.data[22] = 0x45; // r22 <- 0x45 + cpu.data[23] = 0x9a; // r23 <- 0x9a + avrInstruction(cpu); + expect(cpu.pc).toEqual(1); + expect(cpu.cycles).toEqual(1); + expect(cpu.data[26]).toEqual(0x45); + expect(cpu.data[27]).toEqual(0x9a); + }); + + it('should execute `MUL r5, r6` instruction', () => { + loadProgram('569c'); + cpu.data[5] = 100; // r5 <- 55 + cpu.data[6] = 5; // r6 <- 5 + avrInstruction(cpu); + expect(cpu.pc).toEqual(1); + expect(cpu.cycles).toEqual(2); + expect(cpu.dataView.getUint16(0, true)).toEqual(500); + expect(cpu.data[95]).toEqual(0b0); // SREG: 0 + }); + + it('should execute `MUL r5, r6` instruction and update carry flag when numbers are big', () => { + loadProgram('569c'); + cpu.data[5] = 200; // r5 <- 200 + cpu.data[6] = 200; // r6 <- 200 + avrInstruction(cpu); + expect(cpu.pc).toEqual(1); + expect(cpu.cycles).toEqual(2); + expect(cpu.dataView.getUint16(0, true)).toEqual(40000); + expect(cpu.data[95]).toEqual(0b00000001); // SREG: C + }); + + it('should execute `MUL r0, r1` and update the zero flag', () => { + loadProgram('569c'); + cpu.data[0] = 0; // r0 <- 0 + cpu.data[1] = 9; // r1 <- 9 + avrInstruction(cpu); + expect(cpu.pc).toEqual(1); + expect(cpu.cycles).toEqual(2); + expect(cpu.dataView.getUint16(0, true)).toEqual(0); + expect(cpu.data[95]).toEqual(0b00000010); // SREG: Z + }); + + it('should execute `MULS r18, r19` instruction', () => { + loadProgram('2302'); + cpu.data[18] = -5; // r18 <- -5 + cpu.data[19] = 100; // r19 <- 100 + avrInstruction(cpu); + expect(cpu.pc).toEqual(1); + expect(cpu.cycles).toEqual(2); + expect(cpu.dataView.getInt16(0, true)).toEqual(-500); + expect(cpu.data[95]).toEqual(0b00000001); // SREG: C + }); + + it('should execute `MULSU r16, r17` instruction', () => { + loadProgram('0103'); + cpu.data[16] = -5; // r16 <- -5 + cpu.data[17] = 200; // r17 <- 200 + avrInstruction(cpu); + expect(cpu.pc).toEqual(1); + expect(cpu.cycles).toEqual(2); + expect(cpu.dataView.getInt16(0, true)).toEqual(-1000); + expect(cpu.data[95]).toEqual(0b00000001); // SREG: C + }); + + it('should execute `NEG r20` instruction', () => { + loadProgram('4195'); + cpu.data[20] = 0x56; // r20 <- 0x56 + avrInstruction(cpu); + expect(cpu.pc).toEqual(1); + expect(cpu.cycles).toEqual(1); + expect(cpu.data[20]).toEqual(0xaa); + expect(cpu.data[95]).toEqual(0b00010101); // SREG: NC + }); + + it('should execute `NOP` instruction', () => { + loadProgram('0000'); + avrInstruction(cpu); + expect(cpu.pc).toEqual(1); + expect(cpu.cycles).toEqual(1); + }); + it('should execute `OUT 0x3f, r1` instruction', () => { loadProgram('1fbe'); cpu.data[1] = 0x5a; // r1 <- 0x5a @@ -336,7 +471,7 @@ describe('avrInstruction', () => { 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 + expect(cpu.data[95]).toEqual(0b10000000); // SREG: I }); it('should execute `RJMP 2` instruction', () => { @@ -353,7 +488,7 @@ describe('avrInstruction', () => { 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 + expect(cpu.data[95]).toEqual(0b00011001); // SREG: SVI }); it('should execute `ST X, r1` instruction', () => { diff --git a/src/instruction.ts b/src/instruction.ts index fe64f10..697892b 100644 --- a/src/instruction.ts +++ b/src/instruction.ts @@ -384,52 +384,93 @@ export function avrInstruction(cpu: ICPU) { /* LPM, 1001 0101 1100 1000 */ if (opcode === 0x95c8) { - /* not implemented */ + cpu.data[0] = cpu.progBytes[cpu.dataView.getUint16(30, true)]; + cpu.cycles += 2; } /* LPM, 1001 000d dddd 0100 */ if ((opcode & 0xfe0f) === 0x9004) { - /* not implemented */ + cpu.data[(opcode & 0x1f0) >> 4] = cpu.progBytes[cpu.dataView.getUint16(30, true)]; + cpu.cycles += 2; } /* LPM, 1001 000d dddd 0101 */ if ((opcode & 0xfe0f) === 0x9005) { - /* not implemented */ + const i = cpu.dataView.getUint16(30, true); + cpu.data[(opcode & 0x1f0) >> 4] = cpu.progBytes[i]; + cpu.dataView.setUint16(30, i + 1, true); + cpu.cycles += 2; } /* LSR, 1001 010d dddd 0110 */ if ((opcode & 0xfe0f) === 0x9406) { - /* not implemented */ + const value = cpu.data[(opcode & 0x1f0) >> 4]; + const R = value >>> 1; + cpu.data[(opcode & 0x1f0) >> 4] = R; + let sreg = cpu.data[95]; + sreg = (sreg & 0xfd) | (R ? 0 : 2); + sreg &= 0xfb; + sreg = (sreg & 0xfe) | (value & 1); + 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; } /* MOV, 0010 11rd dddd rrrr */ if ((opcode & 0xfc00) === 0x2c00) { - /* not implemented */ + cpu.data[(opcode & 0x1f0) >> 4] = cpu.data[(opcode & 0xf) | ((opcode & 0x200) >> 5)]; } /* MOVW, 0000 0001 dddd rrrr */ if ((opcode & 0xff00) === 0x100) { - /* not implemented */ + const r2 = 2 * (opcode & 0xf); + const d2 = 2 * ((opcode & 0xf0) >> 4); + cpu.data[d2] = cpu.data[r2]; + cpu.data[d2 + 1] = cpu.data[r2 + 1]; } /* MUL, 1001 11rd dddd rrrr */ if ((opcode & 0xfc00) === 0x9c00) { - /* not implemented */ + const R = cpu.data[(opcode & 0x1f0) >> 4] * cpu.data[(opcode & 0xf) | ((opcode & 0x200) >> 5)]; + cpu.dataView.setUint16(0, R, true); + cpu.data[95] = (cpu.data[95] & 0xfd) | (0xffff & R ? 0 : 2); + cpu.data[95] = (cpu.data[95] & 0xfe) | (0x8000 & R ? 1 : 0); + cpu.cycles++; } /* MULS, 0000 0010 dddd rrrr */ if ((opcode & 0xff00) === 0x200) { - /* not implemented */ + const R = + cpu.dataView.getInt8(((opcode & 0xf0) >> 4) + 16) * cpu.dataView.getInt8((opcode & 0xf) + 16); + cpu.dataView.setInt16(0, R, true); + cpu.data[95] = (cpu.data[95] & 0xfd) | (0xffff & R ? 0 : 2); + cpu.data[95] = (cpu.data[95] & 0xfe) | (0x8000 & R ? 1 : 0); + cpu.cycles++; } /* MULSU, 0000 0011 0ddd 0rrr */ if ((opcode & 0xff88) === 0x300) { - /* not implemented */ + const R = cpu.dataView.getInt8(((opcode & 0x70) >> 4) + 16) * cpu.data[(opcode & 7) + 16]; + cpu.dataView.setInt16(0, R, true); + cpu.data[95] = (cpu.data[95] & 0xfd) | (0xffff & R ? 0 : 2); + cpu.data[95] = (cpu.data[95] & 0xfe) | (0x8000 & R ? 1 : 0); + cpu.cycles++; } /* NEG, 1001 010d dddd 0001 */ if ((opcode & 0xfe0f) === 0x9401) { - /* not implemented */ + const d = (opcode & 0x1f0) >> 4; + const value = cpu.data[d]; + const R = 0 - value; + cpu.data[d] = R; + let sreg = cpu.data[95]; + sreg = (sreg & 0xfd) | (R ? 0 : 2); + sreg = (sreg & 0xfb) | (128 & R ? 4 : 0); + sreg = (sreg & 0xf7) | (128 === R ? 8 : 0); + sreg = (sreg & 0xef) | (((sreg >> 2) & 1) ^ ((sreg >> 3) & 1) ? 0x10 : 0); + sreg = (sreg & 0xfe) | (R ? 1 : 0); + sreg = (sreg & 0xdf) | (1 & (R | value) ? 0x20 : 0); + cpu.data[95] = sreg; } /* NOP, 0000 0000 0000 0000 */ |
