Skip to content

Commit d98b8fe

Browse files
committed
fix(gpio): timer outputs not reflected in PIN register #102
fix #102
1 parent d58284e commit d98b8fe

File tree

2 files changed

+22
-8
lines changed

2 files changed

+22
-8
lines changed

src/peripherals/gpio.spec.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { CPU } from '../cpu/cpu';
2-
import { AVRIOPort, portBConfig, PinState, portDConfig } from './gpio';
2+
import { AVRIOPort, portBConfig, PinState, portDConfig, PinOverrideMode } from './gpio';
33

44
// CPU registers
55
const SREG = 95;
@@ -76,6 +76,18 @@ describe('GPIO', () => {
7676
expect(cpu.data[PINB]).toEqual(0x4); // PINB should return port value
7777
});
7878

79+
it('should update the PIN register on output compare (OCR) match (issue #102)', () => {
80+
const cpu = new CPU(new Uint16Array(1024));
81+
const port = new AVRIOPort(cpu, portBConfig);
82+
cpu.writeData(DDRB, 1 << 1);
83+
cpu.gpioTimerHooks[PORTB](1, PinOverrideMode.Set, PORTB);
84+
expect(port.pinState(1)).toBe(PinState.High);
85+
expect(cpu.data[PINB]).toBe(1 << 1);
86+
cpu.gpioTimerHooks[PORTB](1, PinOverrideMode.Clear, PORTB);
87+
expect(port.pinState(1)).toBe(PinState.Low);
88+
expect(cpu.data[PINB]).toBe(0);
89+
});
90+
7991
describe('removeListener', () => {
8092
it('should remove the given listener', () => {
8193
const cpu = new CPU(new Uint16Array(1024));

src/peripherals/gpio.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -213,15 +213,15 @@ export class AVRIOPort {
213213
cpu.writeHooks[portConfig.DDR] = (value: u8) => {
214214
const portValue = cpu.data[portConfig.PORT];
215215
cpu.data[portConfig.DDR] = value;
216-
this.updatePinRegister(portValue, value);
217216
this.writeGpio(portValue, value);
217+
this.updatePinRegister(value);
218218
return true;
219219
};
220220
cpu.writeHooks[portConfig.PORT] = (value: u8) => {
221221
const ddrMask = cpu.data[portConfig.DDR];
222222
cpu.data[portConfig.PORT] = value;
223-
this.updatePinRegister(value, ddrMask);
224223
this.writeGpio(value, ddrMask);
224+
this.updatePinRegister(ddrMask);
225225
return true;
226226
};
227227
cpu.writeHooks[portConfig.PIN] = (value: u8) => {
@@ -230,8 +230,8 @@ export class AVRIOPort {
230230
const ddrMask = cpu.data[portConfig.DDR];
231231
const portValue = oldPortValue ^ value;
232232
cpu.data[portConfig.PORT] = portValue;
233-
this.updatePinRegister(portValue, ddrMask);
234233
this.writeGpio(portValue, ddrMask);
234+
this.updatePinRegister(ddrMask);
235235
return true;
236236
};
237237
// The following hook is used by the timer compare output to override GPIO pins:
@@ -258,7 +258,9 @@ export class AVRIOPort {
258258
break;
259259
}
260260
}
261-
this.writeGpio(cpu.data[portConfig.PORT], cpu.data[portConfig.DDR]);
261+
const ddrMask = cpu.data[portConfig.DDR];
262+
this.writeGpio(cpu.data[portConfig.PORT], ddrMask);
263+
this.updatePinRegister(ddrMask);
262264
};
263265

264266
// External interrupts
@@ -355,11 +357,11 @@ export class AVRIOPort {
355357
if (value) {
356358
this.pinValue |= bitMask;
357359
}
358-
this.updatePinRegister(this.cpu.data[this.portConfig.PORT], this.cpu.data[this.portConfig.DDR]);
360+
this.updatePinRegister(this.cpu.data[this.portConfig.DDR]);
359361
}
360362

361-
private updatePinRegister(port: u8, ddr: u8) {
362-
const newPin = (this.pinValue & ~ddr) | (port & ddr);
363+
private updatePinRegister(ddr: u8) {
364+
const newPin = (this.pinValue & ~ddr) | (this.lastValue & ddr);
363365
this.cpu.data[this.portConfig.PIN] = newPin;
364366
if (this.lastPin !== newPin) {
365367
for (let index = 0; index < 8; index++) {

0 commit comments

Comments
 (0)