aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUri Shaked2019-11-20 22:49:18 +0200
committerUri Shaked2019-11-20 22:49:18 +0200
commite5b02ca111b5fd6fc1ff40afb0f9074c9ff26320 (patch)
tree00ce82f5ffaf420cd5861c6710489ccb323a723d
parentfeat: implement most instructions (diff)
downloadavr8js-e5b02ca111b5fd6fc1ff40afb0f9074c9ff26320.tar.gz
avr8js-e5b02ca111b5fd6fc1ff40afb0f9074c9ff26320.tar.bz2
avr8js-e5b02ca111b5fd6fc1ff40afb0f9074c9ff26320.zip
fix: SREG issues in ADC, CPC, SBC, SBCI
also added regression test cases
-rw-r--r--src/instruction.spec.ts47
-rw-r--r--src/instruction.ts15
2 files changed, 52 insertions, 10 deletions
diff --git a/src/instruction.spec.ts b/src/instruction.spec.ts
index ccf8676..58cb33a 100644
--- a/src/instruction.spec.ts
+++ b/src/instruction.spec.ts
@@ -15,6 +15,30 @@ describe('avrInstruction', () => {
}
}
+ it('should execute `ADC r0, r1` instruction when carry is on', () => {
+ loadProgram('011c');
+ cpu.data[0] = 10; // r0 <- 10
+ cpu.data[1] = 20; // r1 <- 20
+ cpu.data[95] = 0b00000001; // SREG <- -------C
+ avrInstruction(cpu);
+ expect(cpu.pc).toEqual(1);
+ expect(cpu.cycles).toEqual(1);
+ expect(cpu.data[0]).toEqual(31);
+ expect(cpu.data[95]).toEqual(0); // SREG: --------
+ });
+
+ it('should execute `ADC r0, r1` instruction when carry is on and the result overflows', () => {
+ loadProgram('011c');
+ cpu.data[0] = 10; // r0 <- 10
+ cpu.data[1] = 245; // r1 <- 20
+ cpu.data[95] = 0b00000001; // SREG <- -------C
+ avrInstruction(cpu);
+ expect(cpu.pc).toEqual(1);
+ expect(cpu.cycles).toEqual(1);
+ expect(cpu.data[0]).toEqual(0);
+ expect(cpu.data[95]).toEqual(0b00100011); // SREG: --H---ZC
+ });
+
it('should execute `BCLR 2` instruction', () => {
loadProgram('a894');
cpu.data[95] = 0xff; // SREG <- 0xff
@@ -102,7 +126,18 @@ describe('avrInstruction', () => {
avrInstruction(cpu);
expect(cpu.pc).toEqual(1);
expect(cpu.cycles).toEqual(1);
- expect(cpu.data[95]).toEqual(0); // SREG 00000000
+ expect(cpu.data[95]).toEqual(0); // SREG clear
+ });
+
+ it('should execute `CPC r24, r1` instruction and set', () => {
+ loadProgram('8105');
+ cpu.data[1] = 0; // r1 <- 0
+ cpu.data[24] = 0; // r24 <- 0
+ cpu.data[95] = 0b10000001; // SREG: I-------C
+ avrInstruction(cpu);
+ expect(cpu.pc).toEqual(1);
+ expect(cpu.cycles).toEqual(1);
+ expect(cpu.data[95]).toEqual(0b10110101); // SREG: I-HS-N-C
});
it('should execute `CPI r26, 0x9` instruction', () => {
@@ -598,6 +633,16 @@ describe('avrInstruction', () => {
expect(cpu.data[95]).toEqual(0b00011001); // SREG: SVI
});
+ it('should execute `SBCI r23, 3`', () => {
+ loadProgram('7340');
+ cpu.data[23] = 3; // r23 <- 3
+ cpu.data[95] = 0b10000001; // SREG <- I------C
+ avrInstruction(cpu);
+ expect(cpu.pc).toEqual(1);
+ expect(cpu.cycles).toEqual(1);
+ expect(cpu.data[95]).toEqual(0b10110101); // SREG: I-HS-N-C
+ });
+
it('should execute `SBI 0x0c, 5`', () => {
loadProgram('659a');
cpu.data[0x2c] = 0b00001111;
diff --git a/src/instruction.ts b/src/instruction.ts
index 30d30cc..a72218e 100644
--- a/src/instruction.ts
+++ b/src/instruction.ts
@@ -29,14 +29,15 @@ export function avrInstruction(cpu: ICPU) {
if ((opcode & 0xfc00) === 0x1c00) {
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;
+ const sum = d + r + (cpu.data[95] & 1);
+ const R = sum & 255;
cpu.data[(opcode & 0x1f0) >> 4] = R;
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 |= sum & 256 ? 1 : 0;
sreg |= 1 & ((d & r) | (r & ~R) | (~R & d)) ? 0x20 : 0;
cpu.data[95] = sreg;
}
@@ -202,12 +203,10 @@ 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 &= 0xc0;
- sreg |= 0 === r && (sreg >> 1) & 1 ? 2 : 0;
+ sreg = (sreg & 0xc0) | (!r && (sreg >> 1) & 1 ? 2 : 0) | (arg2 + (sreg & 1) > arg1 ? 1 : 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;
}
@@ -650,11 +649,10 @@ export function avrInstruction(cpu: ICPU) {
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 = (sreg & 0xc0) | (!R && (sreg >> 1) & 1 ? 2 : 0) | (val2 + (sreg & 1) > val1 ? 1 : 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;
}
@@ -666,11 +664,10 @@ export function avrInstruction(cpu: ICPU) {
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 = (sreg & 0xc0) | (!R && (sreg >> 1) & 1 ? 2 : 0) | (val2 + (sreg & 1) > val1 ? 1 : 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;
}