aboutsummaryrefslogtreecommitdiff
path: root/src/peripherals/spi.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/peripherals/spi.ts')
-rw-r--r--src/peripherals/spi.ts48
1 files changed, 28 insertions, 20 deletions
diff --git a/src/peripherals/spi.ts b/src/peripherals/spi.ts
index 0c03c3f..7dd5d43 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;
@@ -39,9 +38,18 @@ const bitsPerByte = 8;
export class AVRSPI {
public onTransfer: SPITransferCallback | null = null;
- private transmissionCompleteCycles = 0;
+ private transmissionActive = false;
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) => {
@@ -51,34 +59,34 @@ export class AVRSPI {
}
// Write collision
- if (this.transmissionCompleteCycles > this.cpu.cycles) {
+ if (this.transmissionActive) {
cpu.data[SPSR] |= SPSR_WCOL;
return true;
}
// 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;
+ 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) => {
+ 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;
- this.cpu.data[SPDR] = this.receivedByte;
- 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;
- }
- }
+ reset() {
+ this.transmissionActive = false;
+ this.receivedByte = 0;
}
get isMaster() {