diff options
Diffstat (limited to 'src/peripherals/timer.spec.ts')
| -rw-r--r-- | src/peripherals/timer.spec.ts | 158 |
1 files changed, 144 insertions, 14 deletions
diff --git a/src/peripherals/timer.spec.ts b/src/peripherals/timer.spec.ts index 8733f73..f4b0c69 100644 --- a/src/peripherals/timer.spec.ts +++ b/src/peripherals/timer.spec.ts @@ -2,6 +2,7 @@ import { CPU } from '../cpu/cpu'; import { avrInstruction } from '../cpu/instruction'; import { assemble } from '../utils/assembler'; import { AVRTimer, timer0Config, timer1Config, timer2Config } from './timer'; +import { PinOverrideMode } from './gpio'; describe('timer', () => { let cpu: CPU; @@ -57,20 +58,6 @@ describe('timer', () => { expect(cpu.data[0x35]).toEqual(1); // TOV bit in TIFR }); - it('should set TOV if timer overflows in PWM Phase Correct mode', () => { - const timer = new AVRTimer(cpu, timer0Config); - cpu.writeData(0x46, 0xff); // TCNT0 <- 0xff - timer.tick(); - cpu.writeData(0x47, 0x7f); // OCRA <- 0x7f - cpu.writeData(0x44, 0x1); // WGM0 <- 1 (PWM, Phase Correct) - cpu.data[0x45] = 0x1; // TCCR0B.CS <- 1 - cpu.cycles = 1; - timer.tick(); - const tcnt = cpu.readData(0x46); - expect(tcnt).toEqual(0); // TCNT should be 0 - expect(cpu.data[0x35]).toEqual(1); // TOV bit in TIFR - }); - it('should set TOV if timer overflows in FAST PWM mode', () => { const timer = new AVRTimer(cpu, timer0Config); cpu.writeData(0x46, 0xff); // TCNT0 <- 0xff @@ -273,6 +260,108 @@ describe('timer', () => { expect(cpu.data[1]).toEqual(2); // r1 should equal 2 }); + describe('Phase-correct PWM mode', () => { + it('should count up to TOP, down to 0, and then set TOV flag', () => { + const program = [ + // Set waveform generation mode (WGM) to PWM, Phase Correct, top OCR0A + 'LDI r16, 0x1', // TCCR0A = 1 << WGM00; + 'OUT 0x24, r16', + 'LDI r16, 0x9', // TCCR0B = (1 << WGM02) | (1 << CS00); + 'OUT 0x25, r16', + 'LDI r16, 0x3', // OCR0A = 0x3; + 'OUT 0x27, r16', + 'LDI r16, 0x2', // TCNT0 = 0x2; + 'OUT 0x26, r16', + ]; + const nops = [ + 'NOP', // TCNT0 will be 3 + 'NOP', // TCNT0 will be 2 + 'NOP', // TCNT0 will be 1 + 'NOP', // TCNT0 will be 0 + 'NOP', // TCNT0 will be 1 (end of test) + ]; + loadProgram(...program, ...nops); + const timer = new AVRTimer(cpu, timer0Config); + + for (let i = 0; i < program.length; i++) { + avrInstruction(cpu); + timer.tick(); + } + expect(cpu.readData(0x46)).toEqual(2); // TCNT should be 2 + + avrInstruction(cpu); + timer.tick(); + expect(cpu.readData(0x46)).toEqual(3); // TCNT should be 3 + + avrInstruction(cpu); + timer.tick(); + expect(cpu.readData(0x46)).toEqual(2); // TCNT should be 2 + + avrInstruction(cpu); + timer.tick(); + expect(cpu.readData(0x46)).toEqual(1); // TCNT should be 1 + expect(cpu.data[0x35] & 0x1).toEqual(0); // TIFR should have TOV bit clear + + avrInstruction(cpu); + timer.tick(); + expect(cpu.readData(0x46)).toEqual(0); // TCNT should be 0 + expect(cpu.data[0x35] & 0x1).toEqual(1); // TIFR should have TOV bit set + + avrInstruction(cpu); + timer.tick(); + expect(cpu.readData(0x46)).toEqual(1); // TCNT should be 1 + }); + + it('should clear OC0A when TCNT0=OCR0A and counting up', () => { + const program = [ + // Set waveform generation mode (WGM) to PWM, Phase Correct + 'LDI r16, 0x81', // TCCR0A = (1 << COM0A1) || (1 << WGM01); + 'OUT 0x24, r16', + 'LDI r16, 0x1', // TCCR0B = (1 << CS00); + 'OUT 0x25, r16', + 'LDI r16, 0xfe', // OCR0A = 0xfe; + 'OUT 0x27, r16', + 'LDI r16, 0xfd', // TCNT0 = 0xfd; + 'OUT 0x26, r16', + ]; + const nops = [ + 'NOP', // TCNT0 will be 0xfe + 'NOP', // TCNT0 will be 0xff + 'NOP', // TCNT0 will be 0xfe again (end of test) + ]; + loadProgram(...program, ...nops); + const timer = new AVRTimer(cpu, timer0Config); + + // Listen to Port D's internal callback + const gpioCallback = jest.fn(); + cpu.gpioTimerHooks[0x2b] = gpioCallback; + + for (let i = 0; i < program.length; i++) { + avrInstruction(cpu); + timer.tick(); + } + expect(cpu.readData(0x46)).toEqual(0xfd); // TCNT0 should be 0xfd + expect(gpioCallback).toHaveBeenCalledWith(6, PinOverrideMode.Enable, 0x2b); + gpioCallback.mockClear(); + + avrInstruction(cpu); + timer.tick(); + expect(cpu.readData(0x46)).toEqual(0xfe); // TCNT should be 0xfe + expect(gpioCallback).toHaveBeenCalledWith(6, PinOverrideMode.Clear, 0x2b); + gpioCallback.mockClear(); + + avrInstruction(cpu); + timer.tick(); + expect(cpu.readData(0x46)).toEqual(0xff); // TCNT should be 0xff + expect(gpioCallback).not.toHaveBeenCalled(); + + avrInstruction(cpu); + timer.tick(); + expect(cpu.readData(0x46)).toEqual(0xfe); // TCNT should be 0xfe + expect(gpioCallback).toHaveBeenCalledWith(6, PinOverrideMode.Set, 0x2b); + }); + }); + describe('16 bit timers', () => { it('should increment 16-bit TCNT by 1', () => { const timer = new AVRTimer(cpu, timer1Config); @@ -365,5 +454,46 @@ describe('timer', () => { const timerLow = cpu.readData(0x84); expect((timerHigh << 8) | timerLow).toEqual(0xff00); }); + + it('should toggle OC1B on Compare Match', () => { + const program = [ + // Set waveform generation mode (WGM) to Normal, top 0xFFFF + 'LDI r16, 0x10', // TCCR1A = (1 << COM1B0); + 'STS 0x80, r16', + 'LDI r16, 0x1', // TCCR1B = (1 << CS00); + 'STS 0x81, r16', + 'LDI r16, 0x0', // OCR1BH = 0x0; + 'STS 0x8B, r16', + 'LDI r16, 0x4a', // OCR1BL = 0x4a; + 'STS 0x8A, r16', + 'LDI r16, 0x0', // TCNT1H = 0x0; + 'STS 0x85, r16', + 'LDI r16, 0x49', // TCNT1L = 0x49; + 'STS 0x84, r16', + ]; + const nops = [ + 'NOP', // TCNT1 will be 0x49 + 'NOP', // TCNT1 will be 0x4a + ]; + loadProgram(...program, ...nops); + const timer = new AVRTimer(cpu, timer1Config); + + // Listen to Port B's internal callback + const gpioCallback = jest.fn(); + cpu.gpioTimerHooks[0x25] = gpioCallback; + + for (let i = 0; i < program.length; i++) { + avrInstruction(cpu); + timer.tick(); + } + expect(cpu.readData(0x84)).toEqual(0x49); // TCNT1 should be 0x49 + expect(gpioCallback).toHaveBeenCalledWith(2, PinOverrideMode.Enable, 0x25); + gpioCallback.mockClear(); + + avrInstruction(cpu); + timer.tick(); + expect(cpu.readData(0x84)).toEqual(0x4a); // TCNT1 should be 0x4a + expect(gpioCallback).toHaveBeenCalledWith(2, PinOverrideMode.Toggle, 0x25); + }); }); }); |
