Skip to content

Commit a7132e3

Browse files
committed
fix(eeprom): EEPROM interrupt not firing #110
fix #110
1 parent cd0cb03 commit a7132e3

File tree

3 files changed

+35
-5
lines changed

3 files changed

+35
-5
lines changed

src/cpu/cpu.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,10 @@ export class CPU {
141141
}
142142

143143
updateInterruptEnable(interrupt: AVRInterruptConfig, registerValue: u8) {
144-
const { enableMask, flagRegister, flagMask } = interrupt;
144+
const { enableMask, flagRegister, flagMask, inverseFlag } = interrupt;
145145
if (registerValue & enableMask) {
146-
if (this.data[flagRegister] & flagMask) {
146+
const bitSet = this.data[flagRegister] & flagMask;
147+
if (inverseFlag ? !bitSet : bitSet) {
147148
this.queueInterrupt(interrupt);
148149
}
149150
} else {

src/peripherals/eeprom.spec.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,30 @@ describe('EEPROM', () => {
9999
cpu.writeData(EEDR, 0x55);
100100
cpu.writeData(EEARL, 15);
101101
cpu.writeData(EEARH, 0);
102-
cpu.writeData(EECR, EEMPE | EERIE);
102+
cpu.writeData(EECR, EEMPE);
103+
cpu.data[SREG] = 0x80; // SREG: I-------
104+
cpu.writeData(EECR, EEPE | EERIE);
105+
cpu.cycles += 1000;
106+
cpu.tick();
107+
// At this point, write shouldn't be complete yet
108+
expect(cpu.data[EECR] & EEPE).toEqual(EEPE);
109+
expect(cpu.pc).toEqual(0);
110+
cpu.cycles += 10000000;
111+
// And now, 10 million cycles later, it should.
112+
cpu.tick();
113+
expect(eepromBackend.memory[15]).toEqual(0x55);
114+
expect(cpu.data[EECR] & EEPE).toEqual(0);
115+
expect(cpu.pc).toEqual(0x2c); // EEPROM Ready interrupt
116+
});
117+
118+
it('should clear the fire an interrupt when there is a pending interrupt and the interrupt flag is enabled (issue #110)', () => {
119+
const cpu = new CPU(new Uint16Array(0x1000));
120+
const eepromBackend = new EEPROMMemoryBackend(1024);
121+
new AVREEPROM(cpu, eepromBackend);
122+
cpu.writeData(EEDR, 0x55);
123+
cpu.writeData(EEARL, 15);
124+
cpu.writeData(EEARH, 0);
125+
cpu.writeData(EECR, EEMPE);
103126
cpu.data[SREG] = 0x80; // SREG: I-------
104127
cpu.writeData(EECR, EEPE);
105128
cpu.cycles += 1000;
@@ -112,6 +135,8 @@ describe('EEPROM', () => {
112135
cpu.tick();
113136
expect(eepromBackend.memory[15]).toEqual(0x55);
114137
expect(cpu.data[EECR] & EEPE).toEqual(0);
138+
cpu.writeData(EECR, EERIE);
139+
cpu.tick();
115140
expect(cpu.pc).toEqual(0x2c); // EEPROM Ready interrupt
116141
});
117142

src/peripherals/eeprom.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ const EEMPE = 1 << 2;
5858
const EERIE = 1 << 3;
5959
const EEPM0 = 1 << 4;
6060
const EEPM1 = 1 << 5;
61+
const EECR_WRITE_MASK = EEPE | EEMPE | EERIE | EEPM0 | EEPM1;
6162

6263
export class AVREEPROM {
6364
/**
@@ -91,6 +92,9 @@ export class AVREEPROM {
9192

9293
const addr = (this.cpu.data[EEARH] << 8) | this.cpu.data[EEARL];
9394

95+
this.cpu.data[EECR] = (this.cpu.data[EECR] & ~EECR_WRITE_MASK) | (eecr & EECR_WRITE_MASK);
96+
this.cpu.updateInterruptEnable(this.EER, eecr);
97+
9498
if (eecr & EERE) {
9599
this.cpu.clearInterrupt(this.EER);
96100
}
@@ -116,6 +120,7 @@ export class AVREEPROM {
116120
if (eecr & EEPE) {
117121
// If EEMPE is zero, setting EEPE will have no effect.
118122
if (this.cpu.cycles >= this.writeEnabledCycles) {
123+
this.cpu.data[EECR] &= ~EEPE;
119124
return true;
120125
}
121126
// Check for write-in-progress
@@ -147,10 +152,9 @@ export class AVREEPROM {
147152
// When EEPE has been set, the CPU is halted for two cycles before the
148153
// next instruction is executed.
149154
this.cpu.cycles += 2;
150-
return true;
151155
}
152156

153-
return false;
157+
return true;
154158
};
155159
}
156160
}

0 commit comments

Comments
 (0)