diff options
Diffstat (limited to '')
| -rw-r--r-- | src/instruction.spec.ts | 152 | ||||
| -rw-r--r-- | src/instruction.ts | 416 |
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; |
