aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUri Shaked2020-11-14 11:16:04 +0200
committerUri Shaked2020-11-14 11:16:54 +0200
commit0e4e8def8d67b27e3bc07237cd413b322e297d82 (patch)
tree2165c153c721480ee9c16258c1a8ac7da2e393b1
parent0.11.5 (diff)
downloadavr8js-0e4e8def8d67b27e3bc07237cd413b322e297d82.tar.gz
avr8js-0e4e8def8d67b27e3bc07237cd413b322e297d82.tar.bz2
avr8js-0e4e8def8d67b27e3bc07237cd413b322e297d82.zip
feat: Support for simulating ATtinyx5 (e.g. ATtiny85) timers #64
close #64
Diffstat (limited to '')
-rw-r--r--src/peripherals/timer.spec.ts27
-rw-r--r--src/peripherals/timer.ts45
2 files changed, 60 insertions, 12 deletions
diff --git a/src/peripherals/timer.spec.ts b/src/peripherals/timer.spec.ts
index 7854bf9..2dc7d55 100644
--- a/src/peripherals/timer.spec.ts
+++ b/src/peripherals/timer.spec.ts
@@ -141,6 +141,33 @@ describe('timer', () => {
expect(cpu.cycles).toEqual(3);
});
+ it('should support overriding TIFR/TOV and TIMSK/TOIE bits (issue #64)', () => {
+ const cpu = new CPU(new Uint16Array(0x1000));
+ const timer = new AVRTimer(cpu, {
+ ...timer0Config,
+
+ // The following values correspond ATtiny85 config:
+ TOV: 2,
+ OCFA: 2,
+ OCFB: 8,
+ TOIE: 2,
+ OCIEA: 16,
+ OCIEB: 8,
+ });
+ cpu.writeData(TCNT0, 0xff);
+ cpu.writeData(TCCR0B, CS00); // Set prescaler to 1
+ timer.tick();
+ cpu.data[TIMSK0] = 2;
+ cpu.data[SREG] = 0x80; // SREG: I-------
+ cpu.cycles = 1;
+ timer.tick();
+ const tcnt = cpu.readData(TCNT0);
+ expect(tcnt).toEqual(2); // TCNT should be 2 (one tick above + 2 cycles for interrupt)
+ expect(cpu.data[TIFR0] & 2).toEqual(0);
+ expect(cpu.pc).toEqual(0x20);
+ expect(cpu.cycles).toEqual(3);
+ });
+
it('should not generate an overflow interrupt when global interrupts disabled', () => {
const cpu = new CPU(new Uint16Array(0x1000));
const timer = new AVRTimer(cpu, timer0Config);
diff --git a/src/peripherals/timer.ts b/src/peripherals/timer.ts
index 5c211ba..e347212 100644
--- a/src/peripherals/timer.ts
+++ b/src/peripherals/timer.ts
@@ -21,14 +21,6 @@ const timer01Dividers = {
7: 0, // TODO: External clock source on T0 pin. Clock on rising edge.
};
-const TOV = 1;
-const OCFA = 2;
-const OCFB = 4;
-
-const TOIE = 1;
-const OCIEA = 2;
-const OCIEB = 4;
-
type u8 = number;
type u16 = number;
@@ -45,6 +37,9 @@ interface TimerDividers {
export interface AVRTimerConfig {
bits: 8 | 16;
+ dividers: TimerDividers;
+
+ // Interrupt vectors
captureInterrupt: u8;
compAInterrupt: u8;
compBInterrupt: u8;
@@ -61,7 +56,15 @@ export interface AVRTimerConfig {
TCCRC: u8;
TIMSK: u8;
- dividers: TimerDividers;
+ // TIFR bits
+ TOV: u8;
+ OCFA: u8;
+ OCFB: u8;
+
+ // TIMSK bits
+ TOIE: u8;
+ OCIEA: u8;
+ OCIEB: u8;
// Output compare pins
compPortA: u16;
@@ -70,6 +73,19 @@ export interface AVRTimerConfig {
compPinB: u8;
}
+/** These are differnet for some devices (e.g. ATtiny85) */
+const defaultTimerBits = {
+ // TIFR bits
+ TOV: 1,
+ OCFA: 2,
+ OCFB: 4,
+
+ // TIMSK bits
+ TOIE: 1,
+ OCIEA: 2,
+ OCIEB: 4,
+};
+
export const timer0Config: AVRTimerConfig = {
bits: 8,
captureInterrupt: 0, // not available
@@ -90,6 +106,7 @@ export const timer0Config: AVRTimerConfig = {
compPinA: 6,
compPortB: portDConfig.PORT,
compPinB: 5,
+ ...defaultTimerBits,
};
export const timer1Config: AVRTimerConfig = {
@@ -112,6 +129,7 @@ export const timer1Config: AVRTimerConfig = {
compPinA: 1,
compPortB: portBConfig.PORT,
compPinB: 2,
+ ...defaultTimerBits,
};
export const timer2Config: AVRTimerConfig = {
@@ -143,6 +161,7 @@ export const timer2Config: AVRTimerConfig = {
compPinA: 3,
compPortB: portDConfig.PORT,
compPinB: 3,
+ ...defaultTimerBits,
};
/* All the following types and constants are related to WGM (Waveform Generation Mode) bits: */
@@ -365,12 +384,13 @@ export class AVRTimer {
this.timerUpdated();
}
if ((timerMode === TimerMode.Normal || timerMode === TimerMode.FastPWM) && val > newVal) {
- this.TIFR |= TOV;
+ this.TIFR |= this.config.TOV;
}
}
this.tcntUpdated = false;
if (this.cpu.interruptsEnabled && this.pendingInterrupt) {
const { TIFR, TIMSK } = this;
+ const { TOV, OCFA, OCFB, TOIE, OCIEA, OCIEB } = this.config;
if (TIFR & TOV && TIMSK & TOIE) {
avrInterrupt(this.cpu, this.config.ovfInterrupt);
this.TIFR &= ~TOV;
@@ -398,7 +418,7 @@ export class AVRTimer {
value--;
if (!value && !this.tcntUpdated) {
this.countingUp = true;
- this.TIFR |= TOV;
+ this.TIFR |= this.config.TOV;
}
}
delta--;
@@ -410,6 +430,7 @@ export class AVRTimer {
const value = this.tcnt;
if (this.ocrA && value === this.ocrA) {
+ const { TOV, OCFA } = this.config;
this.TIFR |= OCFA;
if (this.timerMode === TimerMode.CTC) {
// Clear Timer on Compare Match (CTC) Mode
@@ -421,7 +442,7 @@ export class AVRTimer {
}
}
if (this.ocrB && value === this.ocrB) {
- this.TIFR |= OCFB;
+ this.TIFR |= this.config.OCFB;
if (this.compB) {
this.updateCompPin(this.compB, 'B');
}
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.