aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUri Shaked2019-11-20 19:31:28 +0200
committerUri Shaked2019-11-20 19:31:28 +0200
commit8b9e52c7f6759e3907c425d2fbc2028ba7b41209 (patch)
treee9864e096dfd46de3ecb246297f4a426a8c655a3
parentfeat: LAC, LAS, LAT, LDS instructions + tests (diff)
downloadavr8js-8b9e52c7f6759e3907c425d2fbc2028ba7b41209.tar.gz
avr8js-8b9e52c7f6759e3907c425d2fbc2028ba7b41209.tar.bz2
avr8js-8b9e52c7f6759e3907c425d2fbc2028ba7b41209.zip
feat: LPM, LSR, MOV, MOVW, MUL, MULS, MULSU, NEG
+ tests
Diffstat (limited to '')
-rw-r--r--src/instruction.spec.ts153
-rw-r--r--src/instruction.ts61
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 */