From 36c4134a26063248a2ef47f5ac8defe50d9476b1 Mon Sep 17 00:00:00 2001 From: Uri Shaked Date: Wed, 9 Dec 2020 00:51:13 +0200 Subject: refactor: central interrupt handling #38 --- src/peripherals/spi.ts | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) (limited to 'src/peripherals/spi.ts') diff --git a/src/peripherals/spi.ts b/src/peripherals/spi.ts index 0c03c3f..f67143f 100644 --- a/src/peripherals/spi.ts +++ b/src/peripherals/spi.ts @@ -1,6 +1,5 @@ -import { CPU } from '../cpu/cpu'; +import { AVRInterruptConfig, CPU } from '../cpu/cpu'; import { u8 } from '../types'; -import { avrInterrupt } from '../cpu/interrupt'; export interface SPIConfig { spiInterrupt: u8; @@ -42,6 +41,15 @@ export class AVRSPI { private transmissionCompleteCycles = 0; private receivedByte: u8 = 0; + // Interrupts + private SPI: AVRInterruptConfig = { + address: this.config.spiInterrupt, + flagRegister: this.config.SPSR, + flagMask: SPSR_SPIF, + enableRegister: this.config.SPCR, + enableMask: SPCR_SPIE, + }; + constructor(private cpu: CPU, private config: SPIConfig, private freqMHz: number) { const { SPCR, SPSR, SPDR } = config; cpu.writeHooks[SPDR] = (value: u8) => { @@ -57,28 +65,26 @@ export class AVRSPI { } // Clear write collision / interrupt flags - cpu.data[SPSR] &= ~SPSR_WCOL & ~SPSR_SPIF; + cpu.data[SPSR] &= ~SPSR_WCOL; + this.cpu.clearInterrupt(this.SPI); this.receivedByte = this.onTransfer?.(value) ?? 0; this.transmissionCompleteCycles = this.cpu.cycles + this.clockDivider * bitsPerByte; return true; }; + cpu.writeHooks[SPSR] = (value: u8) => { + this.cpu.data[SPSR] = value; + this.cpu.clearInterruptByFlag(this.SPI, value); + }; } tick() { if (this.transmissionCompleteCycles && this.cpu.cycles >= this.transmissionCompleteCycles) { - const { SPSR, SPDR } = this.config; - this.cpu.data[SPSR] |= SPSR_SPIF; + const { SPDR } = this.config; this.cpu.data[SPDR] = this.receivedByte; + this.cpu.setInterruptFlag(this.SPI); this.transmissionCompleteCycles = 0; } - if (this.cpu.interruptsEnabled) { - const { SPSR, SPCR, spiInterrupt } = this.config; - if (this.cpu.data[SPCR] & SPCR_SPIE && this.cpu.data[SPSR] & SPSR_SPIF) { - avrInterrupt(this.cpu, spiInterrupt); - this.cpu.data[SPSR] &= ~SPSR_SPIF; - } - } } get isMaster() { -- cgit v1.2.3 From 9c1288f18889ae3bd10869a9f6ebc53defa3024b Mon Sep 17 00:00:00 2001 From: Uri Shaked Date: Wed, 9 Dec 2020 15:46:53 +0200 Subject: perf!: centeral timekeeping This should improve performance, especially when running simulations with multiple peripherals. For instance, the demo project now runs at ~322%, up from ~185% in AVR8js 0.13.1. BREAKING CHANGE: `tick()` methods were removed from individual peripherals. You now need to call `cpu.tick()` instead. --- src/peripherals/spi.ts | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'src/peripherals/spi.ts') diff --git a/src/peripherals/spi.ts b/src/peripherals/spi.ts index f67143f..7dd5d43 100644 --- a/src/peripherals/spi.ts +++ b/src/peripherals/spi.ts @@ -38,7 +38,7 @@ const bitsPerByte = 8; export class AVRSPI { public onTransfer: SPITransferCallback | null = null; - private transmissionCompleteCycles = 0; + private transmissionActive = false; private receivedByte: u8 = 0; // Interrupts @@ -59,7 +59,7 @@ export class AVRSPI { } // Write collision - if (this.transmissionCompleteCycles > this.cpu.cycles) { + if (this.transmissionActive) { cpu.data[SPSR] |= SPSR_WCOL; return true; } @@ -69,7 +69,13 @@ export class AVRSPI { this.cpu.clearInterrupt(this.SPI); this.receivedByte = this.onTransfer?.(value) ?? 0; - this.transmissionCompleteCycles = this.cpu.cycles + this.clockDivider * bitsPerByte; + const cyclesToComplete = this.clockDivider * bitsPerByte; + this.transmissionActive = true; + this.cpu.addClockEvent(() => { + this.cpu.data[SPDR] = this.receivedByte; + this.cpu.setInterruptFlag(this.SPI); + this.transmissionActive = false; + }, cyclesToComplete); return true; }; cpu.writeHooks[SPSR] = (value: u8) => { @@ -78,13 +84,9 @@ export class AVRSPI { }; } - tick() { - if (this.transmissionCompleteCycles && this.cpu.cycles >= this.transmissionCompleteCycles) { - const { SPDR } = this.config; - this.cpu.data[SPDR] = this.receivedByte; - this.cpu.setInterruptFlag(this.SPI); - this.transmissionCompleteCycles = 0; - } + reset() { + this.transmissionActive = false; + this.receivedByte = 0; } get isMaster() { -- cgit v1.2.3