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');
}
If you find this content useful please consider a small donation via bitcoin: bitcoin:1mxKyQsHHugqRxPKgwaA7wUwJEGCNthn2?amount=0.001&message=Donation Scraping git contents via cgit is very resource intensive. The continued hosting of these git repositories is entirely financed by your bitcoin contributions. For donations of a least 1 mBTC you include your IP address in the message of your bitcoin donation. This will remove this message in the future for requests from your IP, which will significantly reduce token usage. In any case, any contributions to bitcoin address 1mxKyQsHHugqRxPKgwaA7wUwJEGCNthn2 are very welcome. Thanks in advance for you contribution to a self-sustaining ecosystem.