Skip to content

Commit 764b4b2

Browse files
committed
feat(timer): 3rd output compare (OCRnC) #96
1 parent 1cd1646 commit 764b4b2

File tree

2 files changed

+170
-13
lines changed

2 files changed

+170
-13
lines changed

src/peripherals/timer.spec.ts

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -925,6 +925,31 @@ describe('timer', () => {
925925
expect(cpu.cycles).toEqual(2);
926926
});
927927

928+
it('should set OCF1C flag when timer equals OCRC', () => {
929+
const cpu = new CPU(new Uint16Array(0x1000));
930+
const OCR1C = 0x8c;
931+
const OCR1CH = 0x8d;
932+
const OCF1C = 1 << 3;
933+
new AVRTimer(cpu, {
934+
...timer1Config,
935+
OCRC: OCR1C,
936+
OCFC: OCF1C,
937+
});
938+
cpu.writeData(TCNT1H, 0);
939+
cpu.writeData(TCNT1, 0x10);
940+
cpu.writeData(OCR1C, 0x11);
941+
cpu.writeData(OCR1CH, 0x11);
942+
cpu.writeData(TCCR1A, 0x0); // WGM: (Normal)
943+
cpu.writeData(TCCR1B, CS00); // Set prescaler to 1
944+
cpu.cycles = 1;
945+
cpu.tick();
946+
cpu.cycles = 2;
947+
cpu.tick();
948+
expect(cpu.data[TIFR1]).toEqual(OCF1C);
949+
expect(cpu.pc).toEqual(0);
950+
expect(cpu.cycles).toEqual(2);
951+
});
952+
928953
it('should generate an overflow interrupt if timer overflows and interrupts enabled', () => {
929954
const cpu = new CPU(new Uint16Array(0x1000));
930955
new AVRTimer(cpu, timer1Config);
@@ -1034,6 +1059,55 @@ describe('timer', () => {
10341059
expect(gpioCallback).toHaveBeenCalledWith(2, PinOverrideMode.Toggle);
10351060
});
10361061

1062+
it('should toggle OC1C on Compare Match', () => {
1063+
const OCR1C = 0x8c;
1064+
const OCR1CH = 0x8d;
1065+
const OCF1C = 1 << 3;
1066+
const { program, lines, instructionCount } = asmProgram(`
1067+
; Set waveform generation mode (WGM) to Normal, top 0xFFFF
1068+
LDI r16, 0x04 ; TCCR1A = (1 << COM1C0);
1069+
STS ${TCCR1A}, r16
1070+
LDI r16, 0x1 ; TCCR1B = (1 << CS00);
1071+
STS ${TCCR1B}, r16
1072+
LDI r16, 0x0 ; OCR1CH = 0x0;
1073+
STS ${OCR1CH}, r16
1074+
LDI r16, 0x4a ; OCR1C = 0x4a;
1075+
STS ${OCR1C}, r16
1076+
LDI r16, 0x0 ; TCNT1H = 0x0;
1077+
STS ${TCNT1H}, r16
1078+
LDI r16, 0x49 ; TCNT1 = 0x49;
1079+
STS ${TCNT1}, r16
1080+
1081+
NOP ; TCNT1 will be 0x49
1082+
NOP ; TCNT1 will be 0x4a
1083+
`);
1084+
1085+
const cpu = new CPU(program);
1086+
new AVRTimer(cpu, {
1087+
...timer1Config,
1088+
OCRC: OCR1C,
1089+
OCFC: OCF1C,
1090+
compPortC: portBConfig.PORT,
1091+
compPinC: 3,
1092+
});
1093+
1094+
// Listen to Port B's internal callback
1095+
const portB = new AVRIOPort(cpu, portBConfig);
1096+
const gpioCallback = jest.spyOn(portB, 'timerOverridePin');
1097+
1098+
const nopCount = lines.filter((line) => line.bytes == nopOpCode).length;
1099+
const runner = new TestProgramRunner(cpu);
1100+
runner.runInstructions(instructionCount - nopCount);
1101+
1102+
expect(cpu.readData(TCNT1)).toEqual(0x49);
1103+
expect(gpioCallback).toHaveBeenCalledWith(3, PinOverrideMode.Enable);
1104+
gpioCallback.mockClear();
1105+
1106+
runner.runInstructions(1);
1107+
expect(cpu.readData(TCNT1)).toEqual(0x4a);
1108+
expect(gpioCallback).toHaveBeenCalledWith(3, PinOverrideMode.Toggle);
1109+
});
1110+
10371111
it('should only update OCR1A when TCNT1=BOTTOM in PWM Phase/Frequency Correct mode (issue #76)', () => {
10381112
const { program, instructionCount } = asmProgram(`
10391113
LDI r16, 0x0 ; OCR1AH = 0x0;

0 commit comments

Comments
 (0)