aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorUri Shaked2020-12-20 16:28:06 +0200
committerUri Shaked2020-12-20 16:30:23 +0200
commitf32994d68ce708cbc4e24f5de655c8cf0ffb52ef (patch)
tree15d7abb5ea7806434b2ce662c38ee5e2167f5ff3 /src
parent0.14.3 (diff)
downloadavr8js-f32994d68ce708cbc4e24f5de655c8cf0ffb52ef.tar.gz
avr8js-f32994d68ce708cbc4e24f5de655c8cf0ffb52ef.tar.bz2
avr8js-f32994d68ce708cbc4e24f5de655c8cf0ffb52ef.zip
fix(timer): TOV flag does not update correctly #75
fix #75
Diffstat (limited to 'src')
-rw-r--r--src/peripherals/timer.spec.ts38
-rw-r--r--src/peripherals/timer.ts38
2 files changed, 56 insertions, 20 deletions
diff --git a/src/peripherals/timer.spec.ts b/src/peripherals/timer.spec.ts
index 11c0264..583e759 100644
--- a/src/peripherals/timer.spec.ts
+++ b/src/peripherals/timer.spec.ts
@@ -239,7 +239,7 @@ describe('timer', () => {
expect(cpu.cycles).toEqual(2);
});
- it('should clear the timer in CTC mode if it equals to OCRA', () => {
+ it('should reset the counter in CTC mode if it equals to OCRA', () => {
const cpu = new CPU(new Uint16Array(0x1000));
new AVRTimer(cpu, timer0Config);
cpu.writeData(TCNT0, 0x10);
@@ -248,12 +248,44 @@ describe('timer', () => {
cpu.writeData(TCCR0B, CS00); // Set prescaler to 1
cpu.cycles = 1;
cpu.tick();
- cpu.cycles = 2;
+ cpu.cycles = 3;
cpu.tick();
const tcnt = cpu.readData(TCNT0);
expect(tcnt).toEqual(0);
expect(cpu.pc).toEqual(0);
- expect(cpu.cycles).toEqual(2);
+ expect(cpu.cycles).toEqual(3);
+ });
+
+ it('should not set the TOV bit when TOP < MAX in CTC mode (issue #75)', () => {
+ const cpu = new CPU(new Uint16Array(0x1000));
+ new AVRTimer(cpu, timer0Config);
+ cpu.writeData(TCNT0, 0x1e);
+ cpu.writeData(OCR0A, 0x1f);
+ cpu.writeData(TCCR0A, WGM01); // WGM: CTC
+ cpu.writeData(TCCR0B, CS00); // Set prescaler to 1
+ cpu.cycles = 1;
+ cpu.tick();
+ cpu.cycles = 2;
+ cpu.tick();
+ const tcnt = cpu.readData(TCNT0);
+ expect(tcnt).toEqual(0x1f);
+ expect(cpu.data[TIFR0]).toEqual(OCF0A); // TOV0 clear
+ });
+
+ it('should set the TOV bit when TOP == MAX in CTC mode (issue #75)', () => {
+ const cpu = new CPU(new Uint16Array(0x1000));
+ new AVRTimer(cpu, timer0Config);
+ cpu.writeData(TCNT0, 0xfe);
+ cpu.writeData(OCR0A, 0xff);
+ cpu.writeData(TCCR0A, WGM01); // WGM: CTC
+ cpu.writeData(TCCR0B, CS00); // Set prescaler to 1
+ cpu.cycles = 1;
+ cpu.tick();
+ cpu.cycles = 2;
+ cpu.tick();
+ const tcnt = cpu.readData(TCNT0);
+ expect(tcnt).toEqual(0xff);
+ expect(cpu.data[TIFR0]).toEqual(OCF0A | TOV0);
});
it('should set OCF0B flag when timer equals OCRB', () => {
diff --git a/src/peripherals/timer.ts b/src/peripherals/timer.ts
index 0f4d837..f10a49b 100644
--- a/src/peripherals/timer.ts
+++ b/src/peripherals/timer.ts
@@ -238,12 +238,14 @@ function compToOverride(comp: CompBitsValue) {
}
export class AVRTimer {
+ private readonly MAX = this.config.bits === 16 ? 0xffff : 0xff;
private lastCycle = 0;
private ocrA: u16 = 0;
private nextOcrA: u16 = 0;
private ocrB: u16 = 0;
private nextOcrB: u16 = 0;
private ocrUpdateMode = OCRUpdateMode.Immediate;
+ private tovUpdateMode = TOVUpdateMode.Max;
private icr: u16 = 0; // only for 16-bit timers
private timerMode: TimerMode;
private topValue: TimerTopValue;
@@ -403,10 +405,11 @@ export class AVRTimer {
private updateWGMConfig() {
const wgmModes = this.config.bits === 16 ? wgmModes16Bit : wgmModes8Bit;
- const [timerMode, topValue, ocrUpdateMode] = wgmModes[this.WGM];
+ const [timerMode, topValue, ocrUpdateMode, tovUpdateMode] = wgmModes[this.WGM];
this.timerMode = timerMode;
this.topValue = topValue;
this.ocrUpdateMode = ocrUpdateMode;
+ this.tovUpdateMode = tovUpdateMode;
}
count = (reschedule = true) => {
@@ -417,28 +420,34 @@ export class AVRTimer {
const counterDelta = Math.floor(delta / divider);
this.lastCycle += counterDelta * divider;
const val = this.tcnt;
- const { timerMode } = this;
+ const { timerMode, TOP } = this;
const phasePwm =
timerMode === TimerMode.PWMPhaseCorrect || timerMode === TimerMode.PWMPhaseFrequencyCorrect;
- const limit = this.TOP + 1;
const newVal = phasePwm
? this.phasePwmCount(val, counterDelta)
- : (val + counterDelta) % limit;
- const overflow = val + counterDelta >= limit;
+ : (val + counterDelta) % (TOP + 1);
+ const overflow = val + counterDelta > TOP;
// A CPU write overrides (has priority over) all counter clear or count operations.
if (!this.tcntUpdated) {
this.tcnt = newVal;
this.timerUpdated();
}
- if (!phasePwm && this.ocrUpdateMode == OCRUpdateMode.Bottom && overflow) {
- // OCRUpdateMode.Top only occurs in Phase Correct modes, handled by phasePwmCount()
- this.ocrA = this.nextOcrA;
- this.ocrB = this.nextOcrB;
- }
+ if (!phasePwm) {
+ if (this.ocrUpdateMode == OCRUpdateMode.Bottom && overflow) {
+ // OCRUpdateMode.Top only occurs in Phase Correct modes, handled by phasePwmCount()
+ this.ocrA = this.nextOcrA;
+ this.ocrB = this.nextOcrB;
+ }
- if ((timerMode === TimerMode.Normal || timerMode === TimerMode.FastPWM) && val > newVal) {
- cpu.setInterruptFlag(this.OVF);
+ // OCRUpdateMode.Bottom only occurs in Phase Correct modes, handled by phasePwmCount().
+ // Thus we only handle TOVUpdateMode.Top or TOVUpdateMode.Max here.
+ if (
+ (newVal === TOP || overflow) &&
+ (this.tovUpdateMode == TOVUpdateMode.Top || TOP === this.MAX)
+ ) {
+ cpu.setInterruptFlag(this.OVF);
+ }
}
}
if (this.tcntUpdated) {
@@ -492,11 +501,6 @@ export class AVRTimer {
if (this.ocrA && value === this.ocrA) {
this.cpu.setInterruptFlag(this.OCFA);
- if (this.timerMode === TimerMode.CTC) {
- // Clear Timer on Compare Match (CTC) Mode
- this.tcnt = 0;
- this.cpu.setInterruptFlag(this.OVF);
- }
if (this.compA) {
this.updateCompPin(this.compA, 'A');
}