aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorUri Shaked2019-11-20 00:00:25 +0200
committerUri Shaked2019-11-20 00:00:25 +0200
commitb742b267b822e95af19717c1e5125dc2bd4fd5cf (patch)
tree42762ae5b84ceac665ed94afb75854f90290057a /src
parentfeat: CALL, INC, RET, RETI, ROR instructions (diff)
downloadavr8js-b742b267b822e95af19717c1e5125dc2bd4fd5cf.tar.gz
avr8js-b742b267b822e95af19717c1e5125dc2bd4fd5cf.tar.bz2
avr8js-b742b267b822e95af19717c1e5125dc2bd4fd5cf.zip
feat: more instructions
implement ADC, ADD, ADIW, AND, ANDI, ASR, BCLR, BLD, BRBC, BRBS, test some of them
Diffstat (limited to 'src')
-rw-r--r--src/instruction.spec.ts63
-rw-r--r--src/instruction.ts92
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 */