Skip to content

Commit 78377f7

Browse files
committed
fix(timer): keeps counting even when stopped #41
1 parent b0bfe88 commit 78377f7

File tree

2 files changed

+51
-36
lines changed

2 files changed

+51
-36
lines changed

src/peripherals/timer.spec.ts

Lines changed: 49 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ import { AVRTimer, timer0Config, timer1Config, timer2Config } from './timer';
66
// CPU registers
77
const R1 = 1;
88
const R17 = 17;
9+
const R18 = 18;
10+
const R19 = 19;
11+
const R20 = 20;
12+
const R21 = 21;
13+
const R22 = 22;
914
const SREG = 95;
1015

1116
// Port Registers
@@ -168,10 +173,10 @@ describe('timer', () => {
168173
const cpu = new CPU(new Uint16Array(0x1000));
169174
const timer = new AVRTimer(cpu, timer0Config);
170175
cpu.writeData(TCNT0, 0x10);
171-
timer.tick();
172176
cpu.writeData(OCR0A, 0x11);
173177
cpu.writeData(TCCR0A, 0x0); // WGM: Normal
174178
cpu.writeData(TCCR0B, CS00); // Set prescaler to 1
179+
timer.tick();
175180
cpu.cycles = 1;
176181
timer.tick();
177182
expect(cpu.data[TIFR0]).toEqual(OCF0A);
@@ -183,10 +188,10 @@ describe('timer', () => {
183188
const cpu = new CPU(new Uint16Array(0x1000));
184189
const timer = new AVRTimer(cpu, timer0Config);
185190
cpu.writeData(TCNT0, 0x10);
186-
timer.tick();
187191
cpu.writeData(OCR0A, 0x11);
188192
cpu.writeData(TCCR0A, WGM01); // WGM: CTC
189193
cpu.writeData(TCCR0B, CS00); // Set prescaler to 1
194+
timer.tick();
190195
cpu.cycles = 1;
191196
timer.tick();
192197
const tcnt = cpu.readData(TCNT0);
@@ -199,10 +204,10 @@ describe('timer', () => {
199204
const cpu = new CPU(new Uint16Array(0x1000));
200205
const timer = new AVRTimer(cpu, timer0Config);
201206
cpu.writeData(TCNT0, 0x10);
202-
timer.tick();
203207
cpu.writeData(OCR0B, 0x11);
204208
cpu.writeData(TCCR0A, 0x0); // WGM: (Normal)
205209
cpu.writeData(TCCR0B, CS00); // Set prescaler to 1
210+
timer.tick();
206211
cpu.cycles = 1;
207212
timer.tick();
208213
expect(cpu.data[TIFR0]).toEqual(OCF0B);
@@ -214,11 +219,11 @@ describe('timer', () => {
214219
const cpu = new CPU(new Uint16Array(0x1000));
215220
const timer = new AVRTimer(cpu, timer0Config);
216221
cpu.writeData(TCNT0, 0x20);
217-
timer.tick();
218222
cpu.writeData(OCR0A, 0x21);
219223
cpu.writeData(TCCR0B, CS00); // Set prescaler to 1
220224
cpu.writeData(TIMSK0, OCIE0A);
221225
cpu.writeData(95, 0x80); // SREG: I-------
226+
timer.tick();
222227
cpu.cycles = 1;
223228
timer.tick();
224229
const tcnt = cpu.readData(TCNT0);
@@ -232,11 +237,11 @@ describe('timer', () => {
232237
const cpu = new CPU(new Uint16Array(0x1000));
233238
const timer = new AVRTimer(cpu, timer0Config);
234239
cpu.writeData(TCNT0, 0x20);
235-
timer.tick();
236240
cpu.writeData(OCR0A, 0x21);
237241
cpu.writeData(TCCR0B, CS00); // Set prescaler to 1
238242
cpu.writeData(TIMSK0, 0);
239243
cpu.writeData(95, 0x80); // SREG: I-------
244+
timer.tick();
240245
cpu.cycles = 1;
241246
timer.tick();
242247
const tcnt = cpu.readData(TCNT0);
@@ -249,11 +254,11 @@ describe('timer', () => {
249254
const cpu = new CPU(new Uint16Array(0x1000));
250255
const timer = new AVRTimer(cpu, timer0Config);
251256
cpu.writeData(TCNT0, 0x20);
252-
timer.tick();
253257
cpu.writeData(OCR0B, 0x21);
254258
cpu.writeData(TCCR0B, CS00); // Set prescaler to 1
255259
cpu.writeData(TIMSK0, OCIE0B);
256260
cpu.writeData(95, 0x80); // SREG: I-------
261+
timer.tick();
257262
cpu.cycles = 1;
258263
timer.tick();
259264
const tcnt = cpu.readData(TCNT0);
@@ -311,9 +316,27 @@ describe('timer', () => {
311316
expect(cpu.data[R1]).toEqual(2);
312317
});
313318

319+
it('should not start counting before the prescaler is first set (issue #41)', () => {
320+
const { program, instructionCount } = asmProgram(`
321+
NOP
322+
NOP
323+
NOP
324+
NOP
325+
LDI r16, 0x1 ; TCCR2B = 1 << CS20;
326+
STS 0xb1, r16 ; Should start counting after this line
327+
NOP
328+
LDS r17, 0xb2 ; TCNT should equal 2 at this point
329+
`);
330+
const cpu = new CPU(program);
331+
const timer = new AVRTimer(cpu, timer2Config);
332+
const runner = new TestProgramRunner(cpu, timer);
333+
runner.runInstructions(instructionCount);
334+
expect(cpu.readData(R17)).toEqual(2);
335+
});
336+
314337
describe('Phase-correct PWM mode', () => {
315338
it('should count up to TOP, down to 0, and then set TOV flag', () => {
316-
const { program, lines, instructionCount } = asmProgram(`
339+
const { program, instructionCount } = asmProgram(`
317340
; Set waveform generation mode (WGM) to PWM, Phase Correct, top OCR0A
318341
LDI r16, 0x1 ; TCCR0A = 1 << WGM00;
319342
OUT 0x24, r16
@@ -323,36 +346,26 @@ describe('timer', () => {
323346
OUT 0x27, r16
324347
LDI r16, 0x2 ; TCNT0 = 0x2;
325348
OUT 0x26, r16
326-
327-
NOP ; TCNT0 will be 3
328-
NOP ; TCNT0 will be 2
329-
NOP ; TCNT0 will be 1
330-
NOP ; TCNT0 will be 0
331-
NOP ; TCNT0 will be 1 (end of test)
349+
350+
IN r17, 0x26 ; TCNT0 will be 2
351+
IN r18, 0x26 ; TCNT0 will be 3
352+
IN r19, 0x26 ; TCNT0 will be 2
353+
IN r20, 0x26 ; TCNT0 will be 1
354+
IN r21, 0x26 ; TCNT0 will be 0
355+
IN r22, 0x26 ; TCNT0 will be 1 (end of test)
332356
`);
333-
const nopCount = lines.filter((line) => line.bytes == nopOpCode).length;
334357
const cpu = new CPU(program);
335358
const timer = new AVRTimer(cpu, timer0Config);
336359
const runner = new TestProgramRunner(cpu, timer);
337-
runner.runInstructions(instructionCount - nopCount);
338-
expect(cpu.readData(TCNT0)).toEqual(2);
339-
340-
runner.runInstructions(1);
341-
expect(cpu.readData(TCNT0)).toEqual(3);
342-
343-
runner.runInstructions(1);
344-
expect(cpu.readData(TCNT0)).toEqual(2);
345-
346-
runner.runInstructions(1);
347-
expect(cpu.readData(TCNT0)).toEqual(1);
348-
expect(cpu.data[TIFR0] & TOV0).toEqual(0);
349-
350-
runner.runInstructions(1);
351-
expect(cpu.readData(TCNT0)).toEqual(0);
360+
runner.runInstructions(instructionCount);
361+
362+
expect(cpu.readData(R17)).toEqual(2);
363+
expect(cpu.readData(R18)).toEqual(3);
364+
expect(cpu.readData(R19)).toEqual(2);
365+
expect(cpu.readData(R20)).toEqual(1);
366+
expect(cpu.readData(R21)).toEqual(0);
367+
expect(cpu.readData(R22)).toEqual(1);
352368
expect(cpu.data[TIFR0] & TOV0).toEqual(TOV0);
353-
354-
runner.runInstructions(1);
355-
expect(cpu.readData(TCNT0)).toEqual(1);
356369
});
357370

358371
it('should clear OC0A when TCNT0=OCR0A and counting up', () => {
@@ -408,12 +421,12 @@ describe('timer', () => {
408421
const timer = new AVRTimer(cpu, timer1Config);
409422
cpu.writeData(TCNT1H, 0x22); // TCNT1 <- 0x2233
410423
cpu.writeData(TCNT1, 0x33); // ...
411-
timer.tick();
412424
const timerLow = cpu.readData(TCNT1);
413425
const timerHigh = cpu.readData(TCNT1H);
414426
expect((timerHigh << 8) | timerLow).toEqual(0x2233);
415427
cpu.writeData(TCCR1A, 0x0); // WGM: Normal
416428
cpu.writeData(TCCR1B, CS10); // Set prescaler to 1
429+
timer.tick();
417430
cpu.cycles = 1;
418431
timer.tick();
419432
cpu.readData(TCNT1);
@@ -425,11 +438,11 @@ describe('timer', () => {
425438
const timer = new AVRTimer(cpu, timer1Config);
426439
cpu.writeData(TCNT1H, 0x10); // TCNT1 <- 0x10ee
427440
cpu.writeData(TCNT1, 0xee); // ...
428-
timer.tick();
429441
cpu.writeData(OCR1AH, 0x10); // OCR1 <- 0x10ef
430442
cpu.writeData(OCR1A, 0xef); // ...
431443
cpu.writeData(TCCR1A, 0x0); // WGM: Normal
432444
cpu.writeData(TCCR1B, CS10); // Set prescaler to 1
445+
timer.tick();
433446
cpu.cycles = 1;
434447
timer.tick();
435448
expect(cpu.data[TIFR1]).toEqual(OCF1A); // TIFR1 should have OCF1A bit on
@@ -442,11 +455,11 @@ describe('timer', () => {
442455
const timer = new AVRTimer(cpu, timer1Config);
443456
cpu.writeData(TCNT1H, 0x3); // TCNT1 <- 0x3ff
444457
cpu.writeData(TCNT1, 0xff); // ...
445-
timer.tick();
446458
cpu.writeData(TCCR1A, 0x3); // TCCR1A <- WGM10 | WGM11 (Fast PWM, 10-bit)
447459
cpu.writeData(TCCR1B, 0x9); // TCCR1B <- WGM12 | CS10
448460
cpu.data[0x6f] = 0x1; // TIMSK1: TOIE1
449461
cpu.data[SREG] = 0x80; // SREG: I-------
462+
timer.tick();
450463
cpu.cycles = 1;
451464
timer.tick();
452465
cpu.readData(TCNT1); // Refresh TCNT1
@@ -461,10 +474,10 @@ describe('timer', () => {
461474
const timer = new AVRTimer(cpu, timer1Config);
462475
cpu.writeData(TCNT1H, 0x50); // TCNT1 <- 0x500f
463476
cpu.writeData(TCNT1, 0x0f); // ...
464-
timer.tick();
465477
cpu.writeData(ICR1H, 0x50); // ICR1 <- 0x5010
466478
cpu.writeData(ICR1, 0x10); // ...
467479
cpu.writeData(TCCR1B, WGM13 | WGM12 | CS10); // Set prescaler to 1, WGM: CTC
480+
timer.tick();
468481
cpu.cycles = 2; // 2 cycles should increment timer twice, beyond ICR1
469482
timer.tick();
470483
cpu.readData(TCNT1); // Refresh TCNT1

src/peripherals/timer.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ export class AVRTimer {
247247

248248
this.cpu.writeHooks[config.TCNT] = (value: u8) => {
249249
this.tcnt = (this.highByteTemp << 8) | value;
250+
this.countingUp = true;
250251
this.tcntUpdated = true;
251252
this.timerUpdated();
252253
};
@@ -281,6 +282,7 @@ export class AVRTimer {
281282
};
282283
cpu.writeHooks[config.TCCRB] = (value) => {
283284
this.cpu.data[config.TCCRB] = value;
285+
this.tcntUpdated = true;
284286
this.updateWGMConfig();
285287
return true;
286288
};

0 commit comments

Comments
 (0)