aboutsummaryrefslogtreecommitdiff
path: root/src/cpu
diff options
context:
space:
mode:
authorUri Shaked2020-04-28 17:49:48 +0300
committerUri Shaked2020-04-28 17:54:08 +0300
commitb8c08a146f458e285543e04a35ed37c265ec7ec7 (patch)
treec152ff8c7c962be9d4c8d08fedcecf82f6a52e6b /src/cpu
parentchore: release 0.8.1 (diff)
downloadavr8js-b8c08a146f458e285543e04a35ed37c265ec7ec7.tar.gz
avr8js-b8c08a146f458e285543e04a35ed37c265ec7ec7.tar.bz2
avr8js-b8c08a146f458e285543e04a35ed37c265ec7ec7.zip
fix(instruction): LD, ST instructions should take 2 clock cycles
close #39
Diffstat (limited to 'src/cpu')
-rw-r--r--src/cpu/instruction.spec.ts28
-rw-r--r--src/cpu/instruction.ts25
2 files changed, 33 insertions, 20 deletions
diff --git a/src/cpu/instruction.spec.ts b/src/cpu/instruction.spec.ts
index 5ad160d..2312f6c 100644
--- a/src/cpu/instruction.spec.ts
+++ b/src/cpu/instruction.spec.ts
@@ -395,7 +395,7 @@ describe('avrInstruction', () => {
cpu.data[26] = 0xc0; // X <- 0xc0
avrInstruction(cpu);
expect(cpu.pc).toEqual(1);
- expect(cpu.cycles).toEqual(1);
+ expect(cpu.cycles).toEqual(2);
expect(cpu.data[1]).toEqual(0x15);
expect(cpu.data[26]).toEqual(0xc0); // verify that X was unchanged
});
@@ -417,7 +417,7 @@ describe('avrInstruction', () => {
cpu.data[26] = 0x99; // X <- 0x99
avrInstruction(cpu);
expect(cpu.pc).toEqual(1);
- expect(cpu.cycles).toEqual(3);
+ expect(cpu.cycles).toEqual(2);
expect(cpu.data[1]).toEqual(0x22);
expect(cpu.data[26]).toEqual(0x98); // verify that X was decremented
});
@@ -428,7 +428,7 @@ describe('avrInstruction', () => {
cpu.data[28] = 0xc0; // Y <- 0xc0
avrInstruction(cpu);
expect(cpu.pc).toEqual(1);
- expect(cpu.cycles).toEqual(1);
+ expect(cpu.cycles).toEqual(2);
expect(cpu.data[8]).toEqual(0x15);
expect(cpu.data[28]).toEqual(0xc0); // verify that Y was unchanged
});
@@ -450,7 +450,7 @@ describe('avrInstruction', () => {
cpu.data[28] = 0x99; // Y <- 0x99
avrInstruction(cpu);
expect(cpu.pc).toEqual(1);
- expect(cpu.cycles).toEqual(3);
+ expect(cpu.cycles).toEqual(2);
expect(cpu.data[0]).toEqual(0x22);
expect(cpu.data[28]).toEqual(0x98); // verify that Y was decremented
});
@@ -461,7 +461,7 @@ describe('avrInstruction', () => {
cpu.data[28] = 0x80; // Y <- 0x80
avrInstruction(cpu);
expect(cpu.pc).toEqual(1);
- expect(cpu.cycles).toEqual(3);
+ expect(cpu.cycles).toEqual(2);
expect(cpu.data[4]).toEqual(0x33);
expect(cpu.data[28]).toEqual(0x80); // verify that Y was unchanged
});
@@ -472,7 +472,7 @@ describe('avrInstruction', () => {
cpu.data[30] = 0xcc; // Z <- 0xcc
avrInstruction(cpu);
expect(cpu.pc).toEqual(1);
- expect(cpu.cycles).toEqual(1);
+ expect(cpu.cycles).toEqual(2);
expect(cpu.data[5]).toEqual(0xf5);
expect(cpu.data[30]).toEqual(0xcc); // verify that Z was unchanged
});
@@ -494,7 +494,7 @@ describe('avrInstruction', () => {
cpu.data[30] = 0x9f; // Z <- 0x9f
avrInstruction(cpu);
expect(cpu.pc).toEqual(1);
- expect(cpu.cycles).toEqual(3);
+ expect(cpu.cycles).toEqual(2);
expect(cpu.data[0]).toEqual(0x66);
expect(cpu.data[30]).toEqual(0x9e); // verify that Y was decremented
});
@@ -505,7 +505,7 @@ describe('avrInstruction', () => {
cpu.data[30] = 0x80; // Z <- 0x80
avrInstruction(cpu);
expect(cpu.pc).toEqual(1);
- expect(cpu.cycles).toEqual(3);
+ expect(cpu.cycles).toEqual(2);
expect(cpu.data[15]).toEqual(0x33);
expect(cpu.data[30]).toEqual(0x80); // verify that Z was unchanged
});
@@ -839,7 +839,7 @@ describe('avrInstruction', () => {
cpu.data[26] = 0x9a; // X <- 0x9a
avrInstruction(cpu);
expect(cpu.pc).toEqual(1);
- expect(cpu.cycles).toEqual(1);
+ expect(cpu.cycles).toEqual(2);
expect(cpu.data[0x9a]).toEqual(0x5a);
expect(cpu.data[26]).toEqual(0x9a); // verify that X was unchanged
});
@@ -850,7 +850,7 @@ describe('avrInstruction', () => {
cpu.data[26] = 0x9a; // X <- 0x9a
avrInstruction(cpu);
expect(cpu.pc).toEqual(1);
- expect(cpu.cycles).toEqual(1);
+ expect(cpu.cycles).toEqual(2);
expect(cpu.data[0x9a]).toEqual(0x5a);
expect(cpu.data[26]).toEqual(0x9b); // verify that X was incremented
});
@@ -872,7 +872,7 @@ describe('avrInstruction', () => {
cpu.data[28] = 0x9a; // Y <- 0x9a
avrInstruction(cpu);
expect(cpu.pc).toEqual(1);
- expect(cpu.cycles).toEqual(1);
+ expect(cpu.cycles).toEqual(2);
expect(cpu.data[0x9a]).toEqual(0x5b);
expect(cpu.data[28]).toEqual(0x9a); // verify that Y was unchanged
});
@@ -883,7 +883,7 @@ describe('avrInstruction', () => {
cpu.data[28] = 0x9a; // Y <- 0x9a
avrInstruction(cpu);
expect(cpu.pc).toEqual(1);
- expect(cpu.cycles).toEqual(1);
+ expect(cpu.cycles).toEqual(2);
expect(cpu.data[0x9a]).toEqual(0x5a);
expect(cpu.data[28]).toEqual(0x9b); // verify that Y was incremented
});
@@ -916,7 +916,7 @@ describe('avrInstruction', () => {
cpu.data[30] = 0x40; // Z <- 0x40
avrInstruction(cpu);
expect(cpu.pc).toEqual(1);
- expect(cpu.cycles).toEqual(1);
+ expect(cpu.cycles).toEqual(2);
expect(cpu.data[0x40]).toEqual(0xdf);
expect(cpu.data[30]).toEqual(0x40); // verify that Z was unchanged
});
@@ -927,7 +927,7 @@ describe('avrInstruction', () => {
cpu.dataView.setUint16(30, 0x155, true); // Z <- 0x155
avrInstruction(cpu);
expect(cpu.pc).toEqual(1);
- expect(cpu.cycles).toEqual(1);
+ expect(cpu.cycles).toEqual(2);
expect(cpu.data[0x155]).toEqual(0x55);
expect(cpu.dataView.getUint16(30, true)).toEqual(0x156); // verify that Z was incremented
});
diff --git a/src/cpu/instruction.ts b/src/cpu/instruction.ts
index 40ff71f..223a320 100644
--- a/src/cpu/instruction.ts
+++ b/src/cpu/instruction.ts
@@ -1,9 +1,13 @@
/**
* AVR-8 Instruction Simulation
* Part of AVR8js
+ *
* Reference: http://ww1.microchip.com/downloads/en/devicedoc/atmel-0856-avr-instruction-set-manual.pdf
*
- * Copyright (C) 2019, Uri Shaked
+ * Instruction timing is currently based on ATmega328p (see the Instruction Set Summary at the end of
+ * the datasheet)
+ *
+ * Copyright (C) 2019, 2020 Uri Shaked
*/
import { ICPU } from './cpu';
@@ -350,6 +354,7 @@ export function avrInstruction(cpu: ICPU) {
} else if ((opcode & 0xfe0f) === 0x900c) {
/* LDX, 1001 000d dddd 1100 */
cpu.data[(opcode & 0x1f0) >> 4] = cpu.readData(cpu.dataView.getUint16(26, true));
+ cpu.cycles++;
} else if ((opcode & 0xfe0f) === 0x900d) {
/* LDX(INC), 1001 000d dddd 1101 */
const x = cpu.dataView.getUint16(26, true);
@@ -361,10 +366,11 @@ export function avrInstruction(cpu: ICPU) {
const x = cpu.dataView.getUint16(26, true) - 1;
cpu.dataView.setUint16(26, x, true);
cpu.data[(opcode & 0x1f0) >> 4] = cpu.readData(x);
- cpu.cycles += 2;
+ cpu.cycles++;
} else if ((opcode & 0xfe0f) === 0x8008) {
/* LDY, 1000 000d dddd 1000 */
cpu.data[(opcode & 0x1f0) >> 4] = cpu.readData(cpu.dataView.getUint16(28, true));
+ cpu.cycles++;
} else if ((opcode & 0xfe0f) === 0x9009) {
/* LDY(INC), 1001 000d dddd 1001 */
const y = cpu.dataView.getUint16(28, true);
@@ -376,7 +382,7 @@ export function avrInstruction(cpu: ICPU) {
const y = cpu.dataView.getUint16(28, true) - 1;
cpu.dataView.setUint16(28, y, true);
cpu.data[(opcode & 0x1f0) >> 4] = cpu.readData(y);
- cpu.cycles += 2;
+ cpu.cycles++;
} else if (
(opcode & 0xd208) === 0x8008 &&
(opcode & 7) | ((opcode & 0xc00) >> 7) | ((opcode & 0x2000) >> 8)
@@ -386,10 +392,11 @@ export function avrInstruction(cpu: ICPU) {
cpu.dataView.getUint16(28, true) +
((opcode & 7) | ((opcode & 0xc00) >> 7) | ((opcode & 0x2000) >> 8))
);
- cpu.cycles += 2;
+ cpu.cycles++;
} else if ((opcode & 0xfe0f) === 0x8000) {
/* LDZ, 1000 000d dddd 0000 */
cpu.data[(opcode & 0x1f0) >> 4] = cpu.readData(cpu.dataView.getUint16(30, true));
+ cpu.cycles++;
} else if ((opcode & 0xfe0f) === 0x9001) {
/* LDZ(INC), 1001 000d dddd 0001 */
const z = cpu.dataView.getUint16(30, true);
@@ -401,7 +408,7 @@ export function avrInstruction(cpu: ICPU) {
const z = cpu.dataView.getUint16(30, true) - 1;
cpu.dataView.setUint16(30, z, true);
cpu.data[(opcode & 0x1f0) >> 4] = cpu.readData(z);
- cpu.cycles += 2;
+ cpu.cycles++;
} else if (
(opcode & 0xd208) === 0x8000 &&
(opcode & 7) | ((opcode & 0xc00) >> 7) | ((opcode & 0x2000) >> 8)
@@ -411,7 +418,7 @@ export function avrInstruction(cpu: ICPU) {
cpu.dataView.getUint16(30, true) +
((opcode & 7) | ((opcode & 0xc00) >> 7) | ((opcode & 0x2000) >> 8))
);
- cpu.cycles += 2;
+ cpu.cycles++;
} else if (opcode === 0x95c8) {
/* LPM, 1001 0101 1100 1000 */
cpu.data[0] = cpu.progBytes[cpu.dataView.getUint16(30, true)];
@@ -666,11 +673,13 @@ export function avrInstruction(cpu: ICPU) {
} else if ((opcode & 0xfe0f) === 0x920c) {
/* STX, 1001 001r rrrr 1100 */
cpu.writeData(cpu.dataView.getUint16(26, true), cpu.data[(opcode & 0x1f0) >> 4]);
+ cpu.cycles++;
} else if ((opcode & 0xfe0f) === 0x920d) {
/* STX(INC), 1001 001r rrrr 1101 */
const x = cpu.dataView.getUint16(26, true);
cpu.writeData(x, cpu.data[(opcode & 0x1f0) >> 4]);
cpu.dataView.setUint16(26, x + 1, true);
+ cpu.cycles++;
} else if ((opcode & 0xfe0f) === 0x920e) {
/* STX(DEC), 1001 001r rrrr 1110 */
const i = cpu.data[(opcode & 0x1f0) >> 4];
@@ -681,12 +690,14 @@ export function avrInstruction(cpu: ICPU) {
} else if ((opcode & 0xfe0f) === 0x8208) {
/* STY, 1000 001r rrrr 1000 */
cpu.writeData(cpu.dataView.getUint16(28, true), cpu.data[(opcode & 0x1f0) >> 4]);
+ cpu.cycles++;
} else if ((opcode & 0xfe0f) === 0x9209) {
/* STY(INC), 1001 001r rrrr 1001 */
const i = cpu.data[(opcode & 0x1f0) >> 4];
const y = cpu.dataView.getUint16(28, true);
cpu.writeData(y, i);
cpu.dataView.setUint16(28, y + 1, true);
+ cpu.cycles++;
} else if ((opcode & 0xfe0f) === 0x920a) {
/* STY(DEC), 1001 001r rrrr 1010 */
const i = cpu.data[(opcode & 0x1f0) >> 4];
@@ -708,11 +719,13 @@ export function avrInstruction(cpu: ICPU) {
} else if ((opcode & 0xfe0f) === 0x8200) {
/* STZ, 1000 001r rrrr 0000 */
cpu.writeData(cpu.dataView.getUint16(30, true), cpu.data[(opcode & 0x1f0) >> 4]);
+ cpu.cycles++;
} else if ((opcode & 0xfe0f) === 0x9201) {
/* STZ(INC), 1001 001r rrrr 0001 */
const z = cpu.dataView.getUint16(30, true);
cpu.writeData(z, cpu.data[(opcode & 0x1f0) >> 4]);
cpu.dataView.setUint16(30, z + 1, true);
+ cpu.cycles++;
} else if ((opcode & 0xfe0f) === 0x9202) {
/* STZ(DEC), 1001 001r rrrr 0010 */
const i = cpu.data[(opcode & 0x1f0) >> 4];