From ca96ec1ab43979e75c8a551e2aaddda8ad4b9e06 Mon Sep 17 00:00:00 2001 From: Uri Shaked Date: Thu, 21 Nov 2019 17:09:40 +0200 Subject: feat: initial timer implementation 8-bit timers basic functionality + tests: 1. basic counting + prescaler 2. timer overflow 3. timer overflow interrupt --- src/timer.spec.ts | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 src/timer.spec.ts (limited to 'src/timer.spec.ts') diff --git a/src/timer.spec.ts b/src/timer.spec.ts new file mode 100644 index 0000000..b7d96a9 --- /dev/null +++ b/src/timer.spec.ts @@ -0,0 +1,84 @@ +import { CPU } from './cpu'; +import { AVRTimer, timer0Config } from './timer'; + +describe('timer', () => { + let cpu: CPU; + + beforeEach(() => { + cpu = new CPU(new Uint16Array(0x1000)); + }); + + it('should update timer every tick when prescaler is 1', () => { + const timer = new AVRTimer(cpu, timer0Config); + cpu.data[0x45] = 0x1; // TCCR0B.CS <- 1 + cpu.cycles = 1; + timer.tick(); + expect(cpu.data[0x46]).toEqual(1); // TCNT should be 1 + }); + + it('should update timer every 64 ticks when prescaler is 3', () => { + const timer = new AVRTimer(cpu, timer0Config); + cpu.data[0x45] = 0x3; // TCCR0B.CS <- 3 + cpu.cycles = 64; + timer.tick(); + expect(cpu.data[0x46]).toEqual(1); // TCNT should be 1 + }); + + it('should not update timer if it has been disabled', () => { + const timer = new AVRTimer(cpu, timer0Config); + cpu.data[0x45] = 0; // TCCR0B.CS <- 0 + cpu.cycles = 100000; + timer.tick(); + expect(cpu.data[0x46]).toEqual(0); // TCNT should stay 0 + }); + + it('should set TOV if timer overflows', () => { + const timer = new AVRTimer(cpu, timer0Config); + cpu.data[0x46] = 0xff; // TCNT0 <- 0xff + cpu.data[0x45] = 0x1; // TCCR0B.CS <- 1 + cpu.cycles = 1; + timer.tick(); + expect(cpu.data[0x46]).toEqual(0); // TCNT should be 0 + expect(cpu.data[0x35]).toEqual(1); // TOV bit in TIFR + }); + + it('should generate an overflow interrupt if timer overflows and interrupts enabled', () => { + const timer = new AVRTimer(cpu, timer0Config); + cpu.data[0x46] = 0xff; // TCNT0 <- 0xff + cpu.data[0x45] = 0x1; // TCCR0B.CS <- 1 + cpu.data[0x6e] = 0x1; // TIMSK0: TOIE0 + cpu.data[95] = 0x80; // SREG: I------- + cpu.cycles = 1; + timer.tick(); + expect(cpu.data[0x46]).toEqual(0); // TCNT should be 0 + expect(cpu.data[0x35]).toEqual(0); // TOV bit in TIFR should be clear + expect(cpu.pc).toEqual(0x20); + expect(cpu.cycles).toEqual(3); + }); + + it('should not generate an overflow interrupt when global interrupts disabled', () => { + const timer = new AVRTimer(cpu, timer0Config); + cpu.data[0x46] = 0xff; // TCNT0 <- 0xff + cpu.data[0x45] = 0x1; // TCCR0B.CS <- 1 + cpu.data[0x6e] = 0x1; // TIMSK0: TOIE0 + cpu.data[95] = 0x0; // SREG: -------- + cpu.cycles = 1; + timer.tick(); + expect(cpu.data[0x35]).toEqual(1); // TOV bit in TIFR should be set + expect(cpu.pc).toEqual(0); + expect(cpu.cycles).toEqual(1); + }); + + it('should not generate an overflow interrupt when TOIE0 is clear', () => { + const timer = new AVRTimer(cpu, timer0Config); + cpu.data[0x46] = 0xff; // TCNT0 <- 0xff + cpu.data[0x45] = 0x1; // TCCR0B.CS <- 1 + cpu.data[0x6e] = 0; // TIMSK0: clear + cpu.data[95] = 0x80; // SREG: I------- + cpu.cycles = 1; + timer.tick(); + expect(cpu.data[0x35]).toEqual(1); // TOV bit in TIFR should be set + expect(cpu.pc).toEqual(0); + expect(cpu.cycles).toEqual(1); + }); +}); -- cgit v1.2.3