diff options
Diffstat (limited to '')
| -rw-r--r-- | src/instruction.spec.ts | 63 | ||||
| -rw-r--r-- | src/instruction.ts | 92 |
2 files changed, 140 insertions, 15 deletions
diff --git a/src/instruction.spec.ts b/src/instruction.spec.ts index 99c904d..d40ac3f 100644 --- a/src/instruction.spec.ts +++ b/src/instruction.spec.ts @@ -15,14 +15,75 @@ describe('avrInstruction', () => { } } + it('should execute `BCLR 2` instruction', () => { + loadProgram('a894'); + cpu.data[95] = 0xff; // SREG <- 0xff + avrInstruction(cpu); + expect(cpu.pc).toEqual(1); + expect(cpu.cycles).toEqual(1); + expect(cpu.data[95]).toEqual(0xfb); + }); + + it('should execute `BLD r4, 7` instruction', () => { + loadProgram('47f8'); + cpu.data[4] = 0x15; // r <- 0x15 + cpu.data[95] = 0x40; // SREG <- 0x40 + avrInstruction(cpu); + expect(cpu.pc).toEqual(1); + expect(cpu.cycles).toEqual(1); + expect(cpu.data[4]).toEqual(0x95); + expect(cpu.data[95]).toEqual(0x40); + }); + + it('should execute `BRBC 0, +8` instruction when SREG.C is clear', () => { + loadProgram('20f4'); + cpu.data[95] = 0x8; // SREG <- 0b00001000 (V) + avrInstruction(cpu); + expect(cpu.pc).toEqual(1 + 8 / 2); + expect(cpu.cycles).toEqual(2); + }); + + it('should execute `BRBC 0, +8` instruction when SREG.C is set', () => { + loadProgram('20f4'); + cpu.data[95] = 0x1; // SREG <- 0b00000001 (C) + avrInstruction(cpu); + expect(cpu.pc).toEqual(1); + expect(cpu.cycles).toEqual(1); + }); + + it('should execute `BRBS 3, 92` instruction when SREG.V is set', () => { + loadProgram('73f1'); + cpu.data[95] = 0x8; // SREG <- 0b00001000 (V) + avrInstruction(cpu); + expect(cpu.pc).toEqual(1 + 92 / 2); + expect(cpu.cycles).toEqual(2); + }); + + it('should execute `BRBS 3, -4` instruction when SREG.V is set', () => { + loadProgram('0000f3f3'); + cpu.data[95] = 0x8; // SREG <- 0b00001000 (V) + avrInstruction(cpu); + avrInstruction(cpu); + expect(cpu.pc).toEqual(0); + expect(cpu.cycles).toEqual(3); // 1 for NOP, 2 for BRBS + }); + + it('should execute `BRBS 3, -4` instruction when SREG.V is clear', () => { + loadProgram('f3f3'); + cpu.data[95] = 0x0; // SREG <- 0x0 + avrInstruction(cpu); + expect(cpu.pc).toEqual(1); + expect(cpu.cycles).toEqual(1); + }); + it('should execute `CALL` instruction', () => { loadProgram('0e945c00'); cpu.data[93] = 150; // SP <- 50 avrInstruction(cpu); expect(cpu.pc).toEqual(0x5c); + expect(cpu.cycles).toEqual(5); expect(cpu.data[150]).toEqual(2); // return addr expect(cpu.data[93]).toEqual(148); // SP should be decremented - expect(cpu.cycles).toEqual(5); }); it('should execute `CPC r27, r18` instruction', () => { diff --git a/src/instruction.ts b/src/instruction.ts index f520143..dbb23e7 100644 --- a/src/instruction.ts +++ b/src/instruction.ts @@ -13,52 +13,116 @@ export function avrInstruction(cpu: ICPU) { /* ADC, 0001 11rd dddd rrrr */ if ((opcode & 0xfc00) === 0x1c00) { - /* not implemented */ + const d = cpu.data[(opcode & 0x1f0) >> 4]; + 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); + cpu.data[95] = sreg; } /* ADD, 0000 11rd dddd rrrr */ if ((opcode & 0xfc00) === 0xc00) { - /* not implemented */ + 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); + cpu.data[95] = sreg; } /* ADIW, 1001 0110 KKdd KKKK */ if ((opcode & 0xff00) === 0x9600) { - /* not implemented */ + const addr = 2 * ((opcode & 0x30) >> 4) + 24; + 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); + cpu.data[95] = sreg; + cpu.cycles++; } /* AND, 0010 00rd dddd rrrr */ if ((opcode & 0xfc00) === 0x2000) { - /* 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]; + 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); + cpu.data[95] = sreg; } /* ANDI, 0111 KKKK dddd KKKK */ if ((opcode & 0xf000) === 0x7000) { - /* 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]; + 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); + cpu.data[95] = sreg; } /* ASR, 1001 010d dddd 0101 */ if ((opcode & 0xfe0f) === 0x9405) { - /* not implemented */ + 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); + cpu.data[95] = sreg; } /* BCLR, 1001 0100 1sss 1000 */ if ((opcode & 0xff8f) === 0x9488) { - /* not implemented */ + cpu.data[95] &= ~(1 << ((opcode & 0x70) >> 4)); } /* BLD, 1111 100d dddd 0bbb */ if ((opcode & 0xfe08) === 0xf800) { - /* not implemented */ + const b = opcode & 7; + const d = (opcode & 0x1f0) >> 4; + cpu.data[d] = (~(1 << b) & cpu.data[d]) | (((cpu.data[95] >> 6) & 1) << b); } - /* BRBS, 1111 00kk kkkk ksss */ - if ((opcode & 0xfc00) === 0xf000) { - /* not implemented */ + /* BRBC, 1111 01kk kkkk ksss */ + if ((opcode & 0xfc00) === 0xf400) { + if (!(cpu.data[95] & (1 << (opcode & 7)))) { + cpu.pc = cpu.pc + (((opcode & 0x1f8) >> 3) - (opcode & 0x200 ? 0x40 : 0)); + cpu.cycles++; + } } - /* BRCC, 1111 01kk kkkk k000 */ - if ((opcode & 0xfc00) === 0xf400) { - /* not implemented */ + /* BRBS, 1111 00kk kkkk ksss */ + if ((opcode & 0xfc00) === 0xf000) { + if (cpu.data[95] & (1 << (opcode & 7))) { + cpu.pc = cpu.pc + (((opcode & 0x1f8) >> 3) - (opcode & 0x200 ? 0x40 : 0)); + cpu.cycles++; + } } /* BSET, 1001 0100 0sss 1000 */ |
