aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/instruction.spec.ts152
-rw-r--r--src/instruction.ts416
2 files changed, 455 insertions, 113 deletions
diff --git a/src/instruction.spec.ts b/src/instruction.spec.ts
index 9ab4a75..ccf8676 100644
--- a/src/instruction.spec.ts
+++ b/src/instruction.spec.ts
@@ -76,6 +76,15 @@ describe('avrInstruction', () => {
expect(cpu.cycles).toEqual(1);
});
+ it('should execute `CBI 0x0c, 5`', () => {
+ loadProgram('6598');
+ cpu.data[0x2c] = 0b11111111;
+ avrInstruction(cpu);
+ expect(cpu.pc).toEqual(1);
+ expect(cpu.cycles).toEqual(1);
+ expect(cpu.data[0x2c]).toEqual(0b11011111);
+ });
+
it('should execute `CALL` instruction', () => {
loadProgram('0e945c00');
cpu.data[93] = 150; // SP <- 50
@@ -105,6 +114,61 @@ describe('avrInstruction', () => {
expect(cpu.data[95]).toEqual(0b00110101); // SREG: HSNC
});
+ it('should execute `CPSE r2, r3` when r2 != r3', () => {
+ loadProgram('2310');
+ cpu.data[2] = 10; // r2 <- 10
+ cpu.data[3] = 11; // r3 <- 11
+ avrInstruction(cpu);
+ expect(cpu.pc).toEqual(1);
+ expect(cpu.cycles).toEqual(1);
+ });
+
+ it('should execute `CPSE r2, r3` when r2 == r3', () => {
+ loadProgram('23101c92');
+ cpu.data[2] = 10; // r2 <- 10
+ cpu.data[3] = 10; // r3 <- 10
+ avrInstruction(cpu);
+ expect(cpu.pc).toEqual(2);
+ expect(cpu.cycles).toEqual(2);
+ });
+
+ it('should execute `CPSE r2, r3` when r2 == r3 and followed by 2-word instruction', () => {
+ loadProgram('23100e945c00');
+ cpu.data[2] = 10; // r2 <- 10
+ cpu.data[3] = 10; // r3 <- 10
+ avrInstruction(cpu);
+ expect(cpu.pc).toEqual(3);
+ expect(cpu.cycles).toEqual(3);
+ });
+
+ it('should execute `ICALL` instruction', () => {
+ loadProgram('0995');
+ cpu.data[93] = 0x80;
+ cpu.dataView.setUint16(30, 0x2020, true); // Z <- 0x2020
+ avrInstruction(cpu);
+ expect(cpu.cycles).toEqual(3);
+ expect(cpu.pc).toEqual(0x2020);
+ expect(cpu.data[0x80]).toEqual(1); // Return address
+ expect(cpu.data[93]).toEqual(0x7e);
+ });
+
+ it('should execute `IJMP` instruction', () => {
+ loadProgram('0994');
+ cpu.dataView.setUint16(30, 0x1040, true); // Z <- 0x1040
+ avrInstruction(cpu);
+ expect(cpu.cycles).toEqual(2);
+ expect(cpu.pc).toEqual(0x1040);
+ });
+
+ it('should execute `IN r5, 0xb` instruction', () => {
+ loadProgram('5bb0');
+ cpu.data[0x2b] = 0xaf;
+ avrInstruction(cpu);
+ expect(cpu.cycles).toEqual(1);
+ expect(cpu.pc).toEqual(1);
+ expect(cpu.data[5]).toEqual(0xaf);
+ });
+
it('should execute `INC r5` instruction', () => {
loadProgram('5394');
cpu.data[5] = 0x7f;
@@ -453,6 +517,49 @@ describe('avrInstruction', () => {
expect(cpu.data[0x5f]).toEqual(0x5a);
});
+ it('should execute `POP r26` instruction', () => {
+ loadProgram('af91');
+ cpu.data[93] = 0xff; // SP <- 0xff
+ cpu.data[0x100] = 0x1a;
+ avrInstruction(cpu);
+ expect(cpu.pc).toEqual(0x1);
+ expect(cpu.cycles).toEqual(2);
+ expect(cpu.data[26]).toEqual(0x1a);
+ expect(cpu.dataView.getUint16(93, true)).toEqual(0x100); // SP
+ });
+
+ it('should execute `PUSH r11` instruction', () => {
+ loadProgram('bf92');
+ cpu.data[11] = 0x2a;
+ cpu.data[93] = 0xff; // SP <- 0xff
+ avrInstruction(cpu);
+ expect(cpu.pc).toEqual(0x1);
+ expect(cpu.cycles).toEqual(2);
+ expect(cpu.data[0xff]).toEqual(0x2a);
+ expect(cpu.dataView.getUint16(93, true)).toEqual(0xfe); // SP
+ });
+
+ it('should execute `RCALL .+6` instruction', () => {
+ loadProgram('03d0');
+ cpu.data[93] = 0x80; // SP <- 0x80
+ avrInstruction(cpu);
+ expect(cpu.pc).toEqual(4);
+ expect(cpu.cycles).toEqual(4);
+ expect(cpu.dataView.getUint16(0x80, true)).toEqual(1); // RET address
+ expect(cpu.data[93]).toEqual(0x7e); // SP
+ });
+
+ it('should execute `RCALL .-4` instruction', () => {
+ loadProgram('0000fedf');
+ cpu.data[93] = 0x80; // SP <- 0x80
+ avrInstruction(cpu);
+ avrInstruction(cpu);
+ expect(cpu.pc).toEqual(0);
+ expect(cpu.cycles).toEqual(5); // 1 for NOP, 4 for RCALL
+ expect(cpu.dataView.getUint16(0x80, true)).toEqual(2); // RET address
+ expect(cpu.data[93]).toEqual(0x7e); // SP
+ });
+
it('should execute `RET` instruction', () => {
loadProgram('0895');
cpu.data[93] = 0x90; // SP <- 0x90
@@ -491,6 +598,39 @@ describe('avrInstruction', () => {
expect(cpu.data[95]).toEqual(0b00011001); // SREG: SVI
});
+ it('should execute `SBI 0x0c, 5`', () => {
+ loadProgram('659a');
+ cpu.data[0x2c] = 0b00001111;
+ avrInstruction(cpu);
+ expect(cpu.pc).toEqual(1);
+ expect(cpu.cycles).toEqual(2);
+ expect(cpu.data[0x2c]).toEqual(0b00101111);
+ });
+
+ it('should execute `SBIS 0x0c, 5` when bit is clear', () => {
+ loadProgram('659b1c92');
+ cpu.data[0x2c] = 0b00001111;
+ avrInstruction(cpu);
+ expect(cpu.pc).toEqual(1);
+ expect(cpu.cycles).toEqual(1);
+ });
+
+ it('should execute `SBIS 0x0c, 5` when bit is set', () => {
+ loadProgram('659b1c92');
+ cpu.data[0x2c] = 0b00101111;
+ avrInstruction(cpu);
+ expect(cpu.pc).toEqual(2);
+ expect(cpu.cycles).toEqual(2);
+ });
+
+ it('should execute `SBIS 0x0c, 5` when bit is set and followed by 2-word instruction', () => {
+ loadProgram('659b0e945c00');
+ cpu.data[0x2c] = 0b00101111;
+ avrInstruction(cpu);
+ expect(cpu.pc).toEqual(3);
+ expect(cpu.cycles).toEqual(3);
+ });
+
it('should execute `ST X, r1` instruction', () => {
loadProgram('1c92');
cpu.data[1] = 0x5a; // r1 <- 0x5a
@@ -611,4 +751,16 @@ describe('avrInstruction', () => {
expect(cpu.data[0x51]).toEqual(0xcc);
expect(cpu.data[30]).toEqual(0x50); // verify that Z was unchanged
});
+
+ it('should execute `XCH r21` instruction', () => {
+ loadProgram('5493');
+ cpu.data[21] = 0xa1; // r21 <- 0xa1
+ cpu.data[30] = 0x50; // Z <- 0x50
+ cpu.data[0x50] = 0xb9;
+ avrInstruction(cpu);
+ expect(cpu.pc).toEqual(1);
+ expect(cpu.cycles).toEqual(1);
+ expect(cpu.data[21]).toEqual(0xb9); // r21
+ expect(cpu.data[0x50]).toEqual(0xa1);
+ });
});
diff --git a/src/instruction.ts b/src/instruction.ts
index 697892b..30d30cc 100644
--- a/src/instruction.ts
+++ b/src/instruction.ts
@@ -7,6 +7,20 @@
*/
import { ICPU } from './cpu';
+import { u16 } from './types';
+
+function isTwoWordInstruction(opcode: u16) {
+ return (
+ /* LDS */
+ (opcode & 0xfe0f) === 0x9000 ||
+ /* STS */
+ (opcode & 0xfe0f) === 0x9200 ||
+ /* CALL */
+ (opcode & 0xfe0e) === 0x940e ||
+ /* JMP */
+ (opcode & 0xfe0e) === 0x940c
+ );
+}
export function avrInstruction(cpu: ICPU) {
const opcode = cpu.progMem[cpu.pc];
@@ -17,13 +31,13 @@ export function avrInstruction(cpu: ICPU) {
const r = cpu.data[(opcode & 0xf) | ((opcode & 0x200) >> 5)];
const R = (d + r + (cpu.data[95] & 1)) & 255;
cpu.data[(opcode & 0x1f0) >> 4] = R;
- let sreg = cpu.data[95];
- sreg = (sreg & 0xfd) | (R ? 0 : 2);
- sreg = (sreg & 0xfb) | (128 & R ? 4 : 0);
- sreg = (sreg & 0xf7) | ((R ^ r) & (d ^ R) & 128 ? 8 : 0);
- sreg = (sreg & 0xef) | (((sreg >> 2) & 1) ^ ((sreg >> 3) & 1) ? 0x10 : 0);
- sreg = (sreg & 0xfe) | ((d + r + (sreg & 1)) & 256 ? 1 : 0);
- sreg = (sreg & 0xdf) | (1 & ((d & r) | (r & ~R) | (~R & d)) ? 0x20 : 0);
+ let sreg = cpu.data[95] & 0xc0;
+ sreg |= R ? 0 : 2;
+ sreg |= 128 & R ? 4 : 0;
+ sreg |= (R ^ r) & (d ^ R) & 128 ? 8 : 0;
+ sreg |= ((sreg >> 2) & 1) ^ ((sreg >> 3) & 1) ? 0x10 : 0;
+ sreg |= (d + r + (sreg & 1)) & 256 ? 1 : 0;
+ sreg |= 1 & ((d & r) | (r & ~R) | (~R & d)) ? 0x20 : 0;
cpu.data[95] = sreg;
}
@@ -32,14 +46,14 @@ export function avrInstruction(cpu: ICPU) {
const d = cpu.data[(opcode & 0x1f0) >> 4];
const r = cpu.data[(opcode & 0xf) | ((opcode & 0x200) >> 5)];
const R = (d + r) & 255;
- let sreg = cpu.data[95];
cpu.data[(opcode & 0x1f0) >> 4] = R;
- sreg = (sreg & 0xfd) | (R ? 0 : 2);
- sreg = (sreg & 0xfb) | (128 & R ? 4 : 0);
- sreg = (sreg & 0xf7) | ((R ^ r) & (R ^ d) & 128 ? 8 : 0);
- sreg = (sreg & 0xef) | (((sreg >> 2) & 1) ^ ((sreg >> 3) & 1) ? 0x10 : 0);
- sreg = (sreg & 0xfe) | ((d + r) & 256 ? 1 : 0);
- sreg = (sreg & 0xdf) | (1 & ((d & r) | (r & ~R) | (~R & d)) ? 0x20 : 0);
+ let sreg = cpu.data[95] & 0xc0;
+ sreg |= R ? 0 : 2;
+ sreg |= 128 & R ? 4 : 0;
+ sreg |= (R ^ r) & (R ^ d) & 128 ? 8 : 0;
+ sreg |= ((sreg >> 2) & 1) ^ ((sreg >> 3) & 1) ? 0x10 : 0;
+ sreg |= (d + r) & 256 ? 1 : 0;
+ sreg |= 1 & ((d & r) | (r & ~R) | (~R & d)) ? 0x20 : 0;
cpu.data[95] = sreg;
}
@@ -49,12 +63,12 @@ export function avrInstruction(cpu: ICPU) {
const value = cpu.dataView.getUint16(addr, true);
const R = (value + ((opcode & 0xf) | ((opcode & 0xc0) >> 2))) & 0xffff;
cpu.dataView.setUint16(addr, R, true);
- let sreg = cpu.data[95];
- sreg = (sreg & 0xfd) | (R ? 0 : 2);
- sreg = (sreg & 0xfb) | (0x8000 & R ? 4 : 0);
- sreg = (sreg & 0xf7) | (~value & R & 0x8000 ? 8 : 0);
- sreg = (sreg & 0xef) | (((sreg >> 2) & 1) ^ ((sreg >> 3) & 1) ? 0x10 : 0);
- sreg = (sreg & 0xfe) | (~R & value & 0x8000 ? 1 : 0);
+ let sreg = cpu.data[95] & 0xe0;
+ sreg |= R ? 0 : 2;
+ sreg |= 0x8000 & R ? 4 : 0;
+ sreg |= ~value & R & 0x8000 ? 8 : 0;
+ sreg |= ((sreg >> 2) & 1) ^ ((sreg >> 3) & 1) ? 0x10 : 0;
+ sreg |= ~R & value & 0x8000 ? 1 : 0;
cpu.data[95] = sreg;
cpu.cycles++;
}
@@ -63,11 +77,10 @@ export function avrInstruction(cpu: ICPU) {
if ((opcode & 0xfc00) === 0x2000) {
const R = cpu.data[(opcode & 0x1f0) >> 4] & cpu.data[(opcode & 0xf) | ((opcode & 0x200) >> 5)];
cpu.data[(opcode & 0x1f0) >> 4] = R;
- let sreg = cpu.data[95];
- sreg = (sreg & 0xfd) | (R ? 0 : 2);
- sreg = (sreg & 0xfb) | (128 & R ? 4 : 0);
- sreg &= 0xf7;
- sreg = (sreg & 0xef) | (((sreg >> 2) & 1) ^ ((sreg >> 3) & 1) ? 0x10 : 0);
+ let sreg = cpu.data[95] & 0xe1;
+ sreg |= R ? 0 : 2;
+ sreg |= 128 & R ? 4 : 0;
+ sreg |= ((sreg >> 2) & 1) ^ ((sreg >> 3) & 1) ? 0x10 : 0;
cpu.data[95] = sreg;
}
@@ -75,11 +88,10 @@ export function avrInstruction(cpu: ICPU) {
if ((opcode & 0xf000) === 0x7000) {
const R = cpu.data[((opcode & 0xf0) >> 4) + 16] & ((opcode & 0xf) | ((opcode & 0xf00) >> 4));
cpu.data[((opcode & 0xf0) >> 4) + 16] = R;
- let sreg = cpu.data[95];
- sreg = (sreg & 0xfd) | (R ? 0 : 2);
- sreg = (sreg & 0xfb) | (128 & R ? 4 : 0);
- sreg &= 0xf7;
- sreg = (sreg & 0xef) | (((sreg >> 2) & 1) ^ ((sreg >> 3) & 1) ? 0x10 : 0);
+ let sreg = cpu.data[95] & 0xe1;
+ sreg |= R ? 0 : 2;
+ sreg |= 128 & R ? 4 : 0;
+ sreg |= ((sreg >> 2) & 1) ^ ((sreg >> 3) & 1) ? 0x10 : 0;
cpu.data[95] = sreg;
}
@@ -87,13 +99,13 @@ export function avrInstruction(cpu: ICPU) {
if ((opcode & 0xfe0f) === 0x9405) {
const value = cpu.data[(opcode & 0x1f0) >> 4];
const R = (value >>> 1) | (128 & value);
- let sreg = cpu.data[95];
cpu.data[(opcode & 0x1f0) >> 4] = R;
- sreg = (sreg & 0xfd) | (R ? 0 : 2);
- sreg = (sreg & 0xfb) | (128 & R ? 4 : 0);
- 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);
+ let sreg = cpu.data[95] & 0xe0;
+ sreg |= R ? 0 : 2;
+ sreg |= 128 & R ? 4 : 0;
+ sreg |= value & 1;
+ sreg |= ((sreg >> 2) & 1) ^ (sreg & 1) ? 8 : 0;
+ sreg |= ((sreg >> 2) & 1) ^ ((sreg >> 3) & 1) ? 0x10 : 0;
cpu.data[95] = sreg;
}
@@ -127,12 +139,14 @@ export function avrInstruction(cpu: ICPU) {
/* BSET, 1001 0100 0sss 1000 */
if ((opcode & 0xff8f) === 0x9408) {
- /* not implemented */
+ cpu.data[95] |= 1 << ((opcode & 0x70) >> 4);
}
/* BST, 1111 101d dddd 0bbb */
if ((opcode & 0xfe08) === 0xfa00) {
- /* not implemented */
+ const d = cpu.data[(opcode & 0x1f0) >> 4];
+ const b = opcode & 7;
+ cpu.data[95] = (cpu.data[95] & 0xbf) | ((d >> b) & 1 ? 0x40 : 0);
}
/* CALL, 1001 010k kkkk 111k kkkk kkkk kkkk kkkk */
@@ -149,17 +163,37 @@ export function avrInstruction(cpu: ICPU) {
/* CBI, 1001 1000 AAAA Abbb */
if ((opcode & 0xff00) === 0x9800) {
- /* not implemented */
+ const A = opcode & 0xf8;
+ const b = opcode & 7;
+ const R = cpu.readData((A >> 3) + 32);
+ cpu.writeData((A >> 3) + 32, R & ~(1 << b));
}
/* COM, 1001 010d dddd 0000 */
if ((opcode & 0xfe0f) === 0x9400) {
- /* not implemented */
+ const d = (opcode & 0x1f0) >> 4;
+ const R = 255 - cpu.data[d];
+ cpu.data[d] = R;
+ let sreg = (cpu.data[95] & 0xe1) | 1;
+ sreg |= R ? 0 : 2;
+ sreg |= 128 & R ? 4 : 0;
+ sreg |= ((sreg >> 2) & 1) ^ ((sreg >> 3) & 1) ? 0x10 : 0;
+ cpu.data[95] = sreg;
}
/* CP, 0001 01rd dddd rrrr */
if ((opcode & 0xfc00) === 0x1400) {
- /* not implemented */
+ const val1 = cpu.data[(opcode & 0x1f0) >> 4];
+ const val2 = cpu.data[(opcode & 0xf) | ((opcode & 0x200) >> 5)];
+ const R = val1 - val2;
+ let sreg = cpu.data[95] & 0xc0;
+ sreg |= R ? 0 : 2;
+ sreg |= 128 & R ? 4 : 0;
+ sreg |= 0 !== ((val1 ^ val2) & (val1 ^ R) & 128) ? 8 : 0;
+ sreg |= ((sreg >> 2) & 1) ^ ((sreg >> 3) & 1) ? 0x10 : 0;
+ sreg |= val2 > val1 ? 1 : 0;
+ sreg |= 1 & ((~val1 & val2) | (val2 & R) | (R & ~val1)) ? 0x20 : 0;
+ cpu.data[95] = sreg;
}
/* CPC, 0000 01rd dddd rrrr */
@@ -168,12 +202,13 @@ export function avrInstruction(cpu: ICPU) {
const arg2 = cpu.data[(opcode & 0xf) | ((opcode & 0x200) >> 5)];
let sreg = cpu.data[95];
const r = arg1 - arg2 - (sreg & 1);
- sreg = (sreg & 0xfd) | (0 === r && (sreg >> 1) & 1 ? 2 : 0);
- sreg = (sreg & 0xfb) | (128 & r ? 4 : 0);
- sreg = (sreg & 0xf7) | ((arg1 ^ arg2) & (arg1 ^ r) & 128 ? 8 : 0);
- sreg = (sreg & 0xef) | (((sreg >> 2) & 1) ^ ((sreg >> 3) & 1) ? 0x10 : 0);
- sreg = (sreg & 0xfe) | (arg2 + (sreg & 1) > arg1 ? 1 : 0);
- sreg = (sreg & 0xdf) | (1 & ((~arg1 & arg2) | (arg2 & r) | (r & ~arg1)) ? 0x20 : 0);
+ sreg &= 0xc0;
+ sreg |= 0 === r && (sreg >> 1) & 1 ? 2 : 0;
+ sreg |= 128 & r ? 4 : 0;
+ sreg |= (arg1 ^ arg2) & (arg1 ^ r) & 128 ? 8 : 0;
+ sreg |= ((sreg >> 2) & 1) ^ ((sreg >> 3) & 1) ? 0x10 : 0;
+ sreg |= arg2 + (sreg & 1) > arg1 ? 1 : 0;
+ sreg |= 1 & ((~arg1 & arg2) | (arg2 & r) | (r & ~arg1)) ? 0x20 : 0;
cpu.data[95] = sreg;
}
@@ -182,59 +217,101 @@ export function avrInstruction(cpu: ICPU) {
const arg1 = cpu.data[((opcode & 0xf0) >> 4) + 16];
const arg2 = (opcode & 0xf) | ((opcode & 0xf00) >> 4);
const r = arg1 - arg2;
- let sreg = cpu.data[95];
- sreg = (sreg & 0xfd) | (0 === r ? 2 : 0);
- sreg = (sreg & 0xfb) | (128 & r ? 4 : 0);
- sreg = (sreg & 0xf7) | ((arg1 ^ arg2) & (arg1 ^ r) & 128 ? 8 : 0);
- sreg = (sreg & 0xef) | (((sreg >> 2) & 1) ^ ((sreg >> 3) & 1) ? 0x10 : 0);
- sreg = (sreg & 0xfe) | (arg2 > arg1 ? 1 : 0);
- sreg = (sreg & 0xdf) | (1 & ((~arg1 & arg2) | (arg2 & r) | (r & ~arg1)) ? 0x20 : 0);
+ let sreg = cpu.data[95] & 0xc0;
+ sreg |= r ? 0 : 2;
+ sreg |= 128 & r ? 4 : 0;
+ sreg |= (arg1 ^ arg2) & (arg1 ^ r) & 128 ? 8 : 0;
+ sreg |= ((sreg >> 2) & 1) ^ ((sreg >> 3) & 1) ? 0x10 : 0;
+ sreg |= arg2 > arg1 ? 1 : 0;
+ sreg |= 1 & ((~arg1 & arg2) | (arg2 & r) | (r & ~arg1)) ? 0x20 : 0;
cpu.data[95] = sreg;
}
/* CPSE, 0001 00rd dddd rrrr */
if ((opcode & 0xfc00) === 0x1000) {
- /* not implemented */
+ if (cpu.data[(opcode & 0x1f0) >> 4] === cpu.data[(opcode & 0xf) | ((opcode & 0x200) >> 5)]) {
+ const nextOpcode = cpu.progMem[cpu.pc + 1];
+ const skipSize = isTwoWordInstruction(nextOpcode) ? 2 : 1;
+ cpu.pc += skipSize;
+ cpu.cycles += skipSize;
+ }
}
/* DEC, 1001 010d dddd 1010 */
if ((opcode & 0xfe0f) === 0x940a) {
- /* not implemented */
+ const value = cpu.data[(opcode & 0x1f0) >> 4];
+ const R = value - 1;
+ cpu.data[(opcode & 0x1f0) >> 4] = R;
+ let sreg = cpu.data[95] & 0xe1;
+ sreg |= R ? 0 : 2;
+ sreg |= 128 & R ? 4 : 0;
+ sreg |= 128 === value ? 8 : 0;
+ sreg |= ((sreg >> 2) & 1) ^ ((sreg >> 3) & 1) ? 0x10 : 0;
+ cpu.data[95] = sreg;
}
/* EOR, 0010 01rd dddd rrrr */
if ((opcode & 0xfc00) === 0x2400) {
- /* not implemented */
+ const R = cpu.data[(opcode & 0x1f0) >> 4] ^ cpu.data[(opcode & 0xf) | ((opcode & 0x200) >> 5)];
+ cpu.data[(opcode & 0x1f0) >> 4] = R;
+ let sreg = cpu.data[95] & 0xe1;
+ sreg |= R ? 0 : 2;
+ sreg |= 128 & R ? 4 : 0;
+ sreg |= ((sreg >> 2) & 1) ^ ((sreg >> 3) & 1) ? 0x10 : 0;
+ cpu.data[95] = sreg;
}
/* FMUL, 0000 0011 0ddd 1rrr */
if ((opcode & 0xff88) === 0x308) {
- /* not implemented */
+ const v1 = cpu.data[((opcode & 0x70) >> 4) + 16];
+ const v2 = cpu.data[(opcode & 7) + 16];
+ const R = (v1 * v2) << 1;
+ cpu.dataView.setUint16(0, R, true);
+ cpu.data[95] = (cpu.data[95] & 0xfc) | (0xffff & R ? 0 : 2) | ((v1 * v2) & 0x8000 ? 1 : 0);
+ cpu.cycles++;
}
/* FMULS, 0000 0011 1ddd 0rrr */
if ((opcode & 0xff88) === 0x380) {
- /* not implemented */
+ const v1 = cpu.dataView.getInt8(((opcode & 0x70) >> 4) + 16);
+ const v2 = cpu.dataView.getInt8((opcode & 7) + 16);
+ const R = (v1 * v2) << 1;
+ cpu.dataView.setInt16(0, R, true);
+ cpu.data[95] = (cpu.data[95] & 0xfc) | (0xffff & R ? 0 : 2) | ((v1 * v2) & 0x8000 ? 1 : 0);
+ cpu.cycles++;
}
/* FMULSU, 0000 0011 1ddd 1rrr */
if ((opcode & 0xff88) === 0x388) {
- /* not implemented */
+ const v1 = cpu.dataView.getInt8(((opcode & 0x70) >> 4) + 16);
+ const v2 = cpu.data[(opcode & 7) + 16];
+ const R = (v1 * v2) << 1;
+ cpu.dataView.setInt16(0, R, true);
+ cpu.data[95] = (cpu.data[95] & 0xfc) | (0xffff & R ? 2 : 0) | ((v1 * v2) & 0x8000 ? 1 : 0);
+ cpu.cycles++;
}
/* ICALL, 1001 0101 0000 1001 */
if (opcode === 0x9509) {
- /* not implemented */
+ const retAddr = cpu.pc + 1;
+ const sp = cpu.dataView.getUint16(93, true);
+ cpu.data[sp] = retAddr & 255;
+ cpu.data[sp - 1] = (retAddr >> 8) & 255;
+ cpu.dataView.setUint16(93, sp - 2, true);
+ cpu.pc = cpu.dataView.getUint16(30, true) - 1;
+ cpu.cycles += 2;
}
/* IJMP, 1001 0100 0000 1001 */
if (opcode === 0x9409) {
- /* not implemented */
+ cpu.pc = cpu.dataView.getUint16(30, true) - 1;
+ cpu.cycles++;
}
/* IN, 1011 0AAd dddd AAAA */
if ((opcode & 0xf800) === 0xb000) {
- /* not implemented */
+ const i = cpu.readData(((opcode & 0xf) | ((opcode & 0x600) >> 5)) + 32);
+ cpu.data[(opcode & 0x1f0) >> 4] = i;
}
/* INC, 1001 010d dddd 0011 */
@@ -242,11 +319,11 @@ export function avrInstruction(cpu: ICPU) {
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);
+ let sreg = cpu.data[95] & 0xe1;
+ sreg |= r ? 0 : 2;
+ sreg |= 128 & r ? 4 : 0;
+ sreg |= 127 === d ? 8 : 0;
+ sreg |= ((sreg >> 2) & 1) ^ ((sreg >> 3) & 1) ? 0x10 : 0;
cpu.data[95] = sreg;
}
@@ -407,12 +484,11 @@ export function avrInstruction(cpu: ICPU) {
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);
+ let sreg = cpu.data[95] & 0xe0;
+ sreg |= R ? 0 : 2;
+ sreg |= value & 1;
+ sreg |= ((sreg >> 2) & 1) ^ (sreg & 1) ? 8 : 0;
+ sreg |= ((sreg >> 2) & 1) ^ ((sreg >> 3) & 1) ? 0x10 : 0;
cpu.data[95] = sreg;
}
@@ -433,8 +509,7 @@ export function avrInstruction(cpu: ICPU) {
if ((opcode & 0xfc00) === 0x9c00) {
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.data[95] = (cpu.data[95] & 0xfc) | (0xffff & R ? 0 : 2) | (0x8000 & R ? 1 : 0);
cpu.cycles++;
}
@@ -443,8 +518,7 @@ export function avrInstruction(cpu: ICPU) {
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.data[95] = (cpu.data[95] & 0xfc) | (0xffff & R ? 0 : 2) | (0x8000 & R ? 1 : 0);
cpu.cycles++;
}
@@ -452,8 +526,7 @@ export function avrInstruction(cpu: ICPU) {
if ((opcode & 0xff88) === 0x300) {
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.data[95] = (cpu.data[95] & 0xfc) | (0xffff & R ? 0 : 2) | (0x8000 & R ? 1 : 0);
cpu.cycles++;
}
@@ -463,13 +536,13 @@ export function avrInstruction(cpu: ICPU) {
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);
+ let sreg = cpu.data[95] & 0xc0;
+ sreg |= R ? 0 : 2;
+ sreg |= 128 & R ? 4 : 0;
+ sreg |= 128 === R ? 8 : 0;
+ sreg |= ((sreg >> 2) & 1) ^ ((sreg >> 3) & 1) ? 0x10 : 0;
+ sreg |= R ? 1 : 0;
+ sreg |= 1 & (R | value) ? 0x20 : 0;
cpu.data[95] = sreg;
}
@@ -480,12 +553,24 @@ export function avrInstruction(cpu: ICPU) {
/* OR, 0010 10rd dddd rrrr */
if ((opcode & 0xfc00) === 0x2800) {
- /* not implemented */
+ const R = cpu.data[(opcode & 0x1f0) >> 4] | cpu.data[(opcode & 0xf) | ((opcode & 0x200) >> 5)];
+ cpu.data[(opcode & 0x1f0) >> 4] = R;
+ let sreg = cpu.data[95] & 0xe1;
+ sreg |= R ? 0 : 2;
+ sreg |= 128 & R ? 4 : 0;
+ sreg |= ((sreg >> 2) & 1) ^ ((sreg >> 3) & 1) ? 0x10 : 0;
+ cpu.data[95] = sreg;
}
/* SBR, 0110 KKKK dddd KKKK */
if ((opcode & 0xf000) === 0x6000) {
- /* not implemented */
+ const R = cpu.data[((opcode & 0xf0) >> 4) + 16] | ((opcode & 0xf) | ((opcode & 0xf00) >> 4));
+ cpu.data[((opcode & 0xf0) >> 4) + 16] = R;
+ let sreg = cpu.data[95] & 0xe1;
+ sreg |= R ? 0 : 2;
+ sreg |= 128 & R ? 4 : 0;
+ sreg |= ((sreg >> 2) & 1) ^ ((sreg >> 3) & 1) ? 0x10 : 0;
+ cpu.data[95] = sreg;
}
/* OUT, 1011 1AAr rrrr AAAA */
@@ -495,17 +580,30 @@ export function avrInstruction(cpu: ICPU) {
/* POP, 1001 000d dddd 1111 */
if ((opcode & 0xfe0f) === 0x900f) {
- /* not implemented */
+ const value = cpu.dataView.getUint16(93, true) + 1;
+ cpu.dataView.setUint16(93, value, true);
+ cpu.data[(opcode & 0x1f0) >> 4] = cpu.data[value];
+ cpu.cycles++;
}
/* PUSH, 1001 001d dddd 1111 */
if ((opcode & 0xfe0f) === 0x920f) {
- /* not implemented */
+ const value = cpu.dataView.getUint16(93, true);
+ cpu.data[value] = cpu.data[(opcode & 0x1f0) >> 4];
+ cpu.dataView.setUint16(93, value - 1, true);
+ cpu.cycles++;
}
/* RCALL, 1101 kkkk kkkk kkkk */
if ((opcode & 0xf000) === 0xd000) {
- /* not implemented */
+ const k = (opcode & 0x7ff) - (opcode & 0x800 ? 0x800 : 0);
+ const retAddr = cpu.pc + 1;
+ const sp = cpu.dataView.getUint16(93, true);
+ cpu.data[sp] = 255 & retAddr;
+ cpu.data[sp - 1] = (retAddr >> 8) & 255;
+ cpu.dataView.setUint16(93, sp - 2, true);
+ cpu.pc += k;
+ cpu.cycles += 3;
}
/* RET, 1001 0101 0000 1000 */
@@ -536,53 +634,112 @@ export function avrInstruction(cpu: ICPU) {
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);
+ let sreg = cpu.data[95] & 0xe0;
+ sreg |= r ? 0 : 2;
+ sreg |= 128 & r ? 4 : 0;
+ sreg |= 1 & d ? 1 : 0;
+ sreg |= ((sreg >> 2) & 1) ^ (sreg & 1) ? 8 : 0;
+ sreg |= ((sreg >> 2) & 1) ^ ((sreg >> 3) & 1) ? 0x10 : 0;
cpu.data[95] = sreg;
}
/* SBC, 0000 10rd dddd rrrr */
if ((opcode & 0xfc00) === 0x800) {
- /* not implemented */
+ const val1 = cpu.data[(opcode & 0x1f0) >> 4];
+ const val2 = cpu.data[(opcode & 0xf) | ((opcode & 0x200) >> 5)];
+ let sreg = cpu.data[95];
+ const R = val1 - val2 - (sreg & 1);
+ cpu.data[(opcode & 0x1f0) >> 4] = R;
+ sreg = (sreg & 0xc0) | (0 === R && (sreg >> 1) & 1 ? 2 : 0);
+ sreg |= 128 & R ? 4 : 0;
+ sreg |= (val1 ^ val2) & (val1 ^ R) & 128 ? 8 : 0;
+ sreg |= ((sreg >> 2) & 1) ^ ((sreg >> 3) & 1) ? 0x10 : 0;
+ sreg |= val2 + (sreg & 1) > val1 ? 1 : 0;
+ sreg |= 1 & ((~val1 & val2) | (val2 & R) | (R & ~val1)) ? 0x20 : 0;
+ cpu.data[95] = sreg;
}
- /* SBCI */
+ /* SBCI, 0100 KKKK dddd KKKK */
if ((opcode & 0xf000) === 0x4000) {
- /* not implemented */
+ const val1 = cpu.data[((opcode & 0xf0) >> 4) + 16];
+ const val2 = (opcode & 0xf) | ((opcode & 0xf00) >> 4);
+ let sreg = cpu.data[95];
+ const R = val1 - val2 - (sreg & 1);
+ cpu.data[((opcode & 0xf0) >> 4) + 16] = R;
+ sreg = (sreg & 0xc0) | (0 === R && (sreg >> 1) & 1 ? 2 : 0);
+ sreg |= 128 & R ? 4 : 0;
+ sreg |= (val1 ^ val2) & (val1 ^ R) & 128 ? 8 : 0;
+ sreg |= ((sreg >> 2) & 1) ^ ((sreg >> 3) & 1) ? 0x10 : 0;
+ sreg |= val2 + (sreg & 1) > val1 ? 1 : 0;
+ sreg |= 1 & ((~val1 & val2) | (val2 & R) | (R & ~val1)) ? 0x20 : 0;
+ cpu.data[95] = sreg;
}
- /* SBI, 0100 KKKK dddd KKKK */
+ /* SBI, 1001 1010 AAAA Abbb */
if ((opcode & 0xff00) === 0x9a00) {
- /* not implemented */
+ const target = ((opcode & 0xf8) >> 3) + 32;
+ cpu.writeData(target, cpu.readData(target) | (1 << (opcode & 7)));
+ cpu.cycles++;
}
/* SBIC, 1001 1001 AAAA Abbb */
if ((opcode & 0xff00) === 0x9900) {
- /* not implemented */
+ const value = cpu.readData(((opcode & 0xf8) >> 3) + 32);
+ if (!(value & (1 << (opcode & 7)))) {
+ const nextOpcode = cpu.progMem[cpu.pc + 1];
+ const skipSize = isTwoWordInstruction(nextOpcode) ? 2 : 1;
+ cpu.cycles += skipSize;
+ cpu.pc += skipSize;
+ }
}
/* SBIS, 1001 1011 AAAA Abbb */
if ((opcode & 0xff00) === 0x9b00) {
- /* not implemented */
+ const value = cpu.readData(((opcode & 0xf8) >> 3) + 32);
+ if (value & (1 << (opcode & 7))) {
+ const nextOpcode = cpu.progMem[cpu.pc + 1];
+ const skipSize = isTwoWordInstruction(nextOpcode) ? 2 : 1;
+ cpu.cycles += skipSize;
+ cpu.pc += skipSize;
+ }
}
/* SBIW, 1001 0111 KKdd KKKK */
if ((opcode & 0xff00) === 0x9700) {
- /* not implemented */
+ const i = 2 * ((opcode & 0x30) >> 4) + 24;
+ const a = cpu.dataView.getUint16(i, true);
+ const l = (opcode & 0xf) | ((opcode & 0xc0) >> 2);
+ const R = a - l;
+ cpu.dataView.setUint16(i, R, true);
+ let sreg = cpu.data[95] & 0xc0;
+ sreg |= R ? 0 : 2;
+ sreg |= 0x8000 & R ? 4 : 0;
+ sreg |= a & ~R & 0x8000 ? 8 : 0;
+ sreg |= ((sreg >> 2) & 1) ^ ((sreg >> 3) & 1) ? 0x10 : 0;
+ sreg |= l > a ? 1 : 0;
+ sreg |= 1 & ((~a & l) | (l & R) | (R & ~a)) ? 0x20 : 0;
+ cpu.data[95] = sreg;
+ cpu.cycles++;
}
/* SBRC, 1111 110r rrrr 0bbb */
if ((opcode & 0xfe08) === 0xfc00) {
- /* not implemented */
+ if (!(cpu.data[(opcode & 0x1f0) >> 4] & (1 << (opcode & 7)))) {
+ const nextOpcode = cpu.progMem[cpu.pc + 1];
+ const skipSize = isTwoWordInstruction(nextOpcode) ? 2 : 1;
+ cpu.cycles += skipSize;
+ cpu.pc += skipSize;
+ }
}
/* SBRS, 1111 111r rrrr 0bbb */
if ((opcode & 0xfe08) === 0xfe00) {
- /* not implemented */
+ if (cpu.data[(opcode & 0x1f0) >> 4] & (1 << (opcode & 7))) {
+ const nextOpcode = cpu.progMem[cpu.pc + 1];
+ const skipSize = isTwoWordInstruction(nextOpcode) ? 2 : 1;
+ cpu.cycles += skipSize;
+ cpu.pc += skipSize;
+ }
}
/* SLEEP, 1001 0101 1000 1000 */
@@ -602,7 +759,11 @@ export function avrInstruction(cpu: ICPU) {
/* STS, 1001 001d dddd 0000 kkkk kkkk kkkk kkkk */
if ((opcode & 0xfe0f) === 0x9200) {
- /* not implemented */
+ const value = cpu.data[(opcode & 0x1f0) >> 4];
+ const addr = cpu.progMem[cpu.pc + 1];
+ cpu.writeData(addr, value);
+ cpu.pc++;
+ cpu.cycles++;
}
/* STX, 1001 001r rrrr 1100 */
@@ -697,17 +858,42 @@ export function avrInstruction(cpu: ICPU) {
/* SUB, 0001 10rd dddd rrrr */
if ((opcode & 0xfc00) === 0x1800) {
- /* not implemented */
+ const val1 = cpu.data[(opcode & 0x1f0) >> 4];
+ const val2 = cpu.data[(opcode & 0xf) | ((opcode & 0x200) >> 5)];
+ const R = val1 - val2;
+
+ cpu.data[(opcode & 0x1f0) >> 4] = R;
+ let sreg = cpu.data[95] & 0xc0;
+ sreg |= R ? 0 : 2;
+ sreg |= 128 & R ? 4 : 0;
+ sreg |= (val1 ^ val2) & (val1 ^ R) & 128 ? 8 : 0;
+ sreg |= ((sreg >> 2) & 1) ^ ((sreg >> 3) & 1) ? 0x10 : 0;
+ sreg |= val2 > val1 ? 1 : 0;
+ sreg |= 1 & ((~val1 & val2) | (val2 & R) | (R & ~val1)) ? 0x20 : 0;
+ cpu.data[95] = sreg;
}
/* SUBI, 0101 KKKK dddd KKKK */
if ((opcode & 0xf000) === 0x5000) {
- /* not implemented */
+ const val1 = cpu.data[((opcode & 0xf0) >> 4) + 16];
+ const val2 = (opcode & 0xf) | ((opcode & 0xf00) >> 4);
+ const R = val1 - val2;
+ cpu.data[((opcode & 0xf0) >> 4) + 16] = R;
+ let sreg = cpu.data[95] & 0xc0;
+ sreg |= R ? 0 : 2;
+ sreg |= 128 & R ? 4 : 0;
+ sreg |= (val1 ^ val2) & (val1 ^ R) & 128 ? 8 : 0;
+ sreg |= ((sreg >> 2) & 1) ^ ((sreg >> 3) & 1) ? 0x10 : 0;
+ sreg |= val2 > val1 ? 1 : 0;
+ sreg |= 1 & ((~val1 & val2) | (val2 & R) | (R & ~val1)) ? 0x20 : 0;
+ cpu.data[95] = sreg;
}
/* SWAP, 1001 010d dddd 0010 */
if ((opcode & 0xfe0f) === 0x9402) {
- /* not implemented */
+ const d = (opcode & 0x1f0) >> 4;
+ const i = cpu.data[d];
+ cpu.data[d] = ((15 & i) << 4) | ((240 & i) >>> 4);
}
/* WDR, 1001 0101 1010 1000 */
@@ -717,7 +903,11 @@ export function avrInstruction(cpu: ICPU) {
/* XCH, 1001 001r rrrr 0100 */
if ((opcode & 0xfe0f) === 0x9204) {
- /* not implemented */
+ const r = (opcode & 0x1f0) >> 4;
+ const val1 = cpu.data[r];
+ const val2 = cpu.data[cpu.dataView.getUint16(30, true)];
+ cpu.data[cpu.dataView.getUint16(30, true)] = val1;
+ cpu.data[r] = val2;
}
cpu.pc = (cpu.pc + 1) % cpu.progMem.length;
If you find this content useful please consider a small donation via bitcoin: bitcoin:1mxKyQsHHugqRxPKgwaA7wUwJEGCNthn2?amount=0.001&message=Donation Scraping git contents via cgit is very resource intensive. The continued hosting of these git repositories is entirely financed by your bitcoin contributions. For donations of a least 1 mBTC you include your IP address in the message of your bitcoin donation. This will remove this message in the future for requests from your IP, which will significantly reduce token usage. In any case, any contributions to bitcoin address 1mxKyQsHHugqRxPKgwaA7wUwJEGCNthn2 are very welcome. Thanks in advance for you contribution to a self-sustaining ecosystem.