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/usart.ts | 47 ++++++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 17 deletions(-) (limited to 'src/peripherals/usart.ts') diff --git a/src/peripherals/usart.ts b/src/peripherals/usart.ts index a2037a9..c1441ad 100644 --- a/src/peripherals/usart.ts +++ b/src/peripherals/usart.ts @@ -6,8 +6,7 @@ * Copyright (C) 2019, 2020, Uri Shaked */ -import { CPU } from '../cpu/cpu'; -import { avrInterrupt } from '../cpu/interrupt'; +import { AVRInterruptConfig, CPU } from '../cpu/cpu'; import { u8 } from '../types'; export interface USARTConfig { @@ -72,14 +71,38 @@ export class AVRUSART { private lineBuffer = ''; + // Interrupts + private UDRE: AVRInterruptConfig = { + address: this.config.dataRegisterEmptyInterrupt, + flagRegister: this.config.UCSRA, + flagMask: UCSRA_UDRE, + enableRegister: this.config.UCSRB, + enableMask: UCSRB_UDRIE, + }; + private TXC: AVRInterruptConfig = { + address: this.config.txCompleteInterrupt, + flagRegister: this.config.UCSRA, + flagMask: UCSRA_TXC, + enableRegister: this.config.UCSRB, + enableMask: UCSRB_TXCIE, + }; + private txCompleteCycles = 0; constructor(private cpu: CPU, private config: USARTConfig, private freqMHz: number) { this.reset(); + this.cpu.writeHooks[config.UCSRA] = (value) => { + cpu.data[config.UCSRA] = value; + cpu.clearInterruptByFlag(this.UDRE, value); + cpu.clearInterruptByFlag(this.TXC, value); + return true; + }; this.cpu.writeHooks[config.UCSRB] = (value, oldValue) => { + cpu.updateInterruptEnable(this.UDRE, value); + cpu.updateInterruptEnable(this.TXC, value); if (value & UCSRB_TXEN && !(oldValue & UCSRB_TXEN)) { // Enabling the transmission - mark UDR as empty - this.cpu.data[config.UCSRA] |= UCSRA_UDRE; + cpu.setInterruptFlag(this.UDRE); } }; this.cpu.writeHooks[config.UDR] = (value) => { @@ -97,7 +120,8 @@ export class AVRUSART { } const symbolsPerChar = 1 + this.bitsPerChar + this.stopBits + (this.parityEnabled ? 1 : 0); this.txCompleteCycles = this.cpu.cycles + (this.UBRR * this.multiplier + 1) * symbolsPerChar; - this.cpu.data[config.UCSRA] &= ~(UCSRA_TXC | UCSRA_UDRE); + this.cpu.clearInterrupt(this.TXC); + this.cpu.clearInterrupt(this.UDRE); }; } @@ -110,21 +134,10 @@ export class AVRUSART { tick() { const { txCompleteCycles, cpu } = this; if (txCompleteCycles && cpu.cycles >= txCompleteCycles) { - this.cpu.data[this.config.UCSRA] |= UCSRA_UDRE | UCSRA_TXC; + cpu.setInterruptFlag(this.UDRE); + cpu.setInterruptFlag(this.TXC); this.txCompleteCycles = 0; } - if (cpu.interruptsEnabled) { - const ucsra = cpu.data[this.config.UCSRA]; - const ucsrb = cpu.data[this.config.UCSRB]; - if (ucsra & UCSRA_UDRE && ucsrb & UCSRB_UDRIE) { - avrInterrupt(cpu, this.config.dataRegisterEmptyInterrupt); - cpu.data[this.config.UCSRA] &= ~UCSRA_UDRE; - } - if (ucsra & UCSRA_TXC && ucsrb & UCSRB_TXCIE) { - avrInterrupt(cpu, this.config.txCompleteInterrupt); - cpu.data[this.config.UCSRA] &= ~UCSRA_TXC; - } - } } private get UBRR() { -- 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/usart.ts | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) (limited to 'src/peripherals/usart.ts') diff --git a/src/peripherals/usart.ts b/src/peripherals/usart.ts index c1441ad..c7dcbd4 100644 --- a/src/peripherals/usart.ts +++ b/src/peripherals/usart.ts @@ -87,8 +87,6 @@ export class AVRUSART { enableMask: UCSRB_TXCIE, }; - private txCompleteCycles = 0; - constructor(private cpu: CPU, private config: USARTConfig, private freqMHz: number) { this.reset(); this.cpu.writeHooks[config.UCSRA] = (value) => { @@ -119,7 +117,11 @@ export class AVRUSART { } } const symbolsPerChar = 1 + this.bitsPerChar + this.stopBits + (this.parityEnabled ? 1 : 0); - this.txCompleteCycles = this.cpu.cycles + (this.UBRR * this.multiplier + 1) * symbolsPerChar; + const cyclesToComplete = (this.UBRR * this.multiplier + 1) * symbolsPerChar; + this.cpu.addClockEvent(() => { + cpu.setInterruptFlag(this.UDRE); + cpu.setInterruptFlag(this.TXC); + }, cyclesToComplete); this.cpu.clearInterrupt(this.TXC); this.cpu.clearInterrupt(this.UDRE); }; @@ -131,15 +133,6 @@ export class AVRUSART { this.cpu.data[this.config.UCSRC] = UCSRC_UCSZ1 | UCSRC_UCSZ0; // default: 8 bits per byte } - tick() { - const { txCompleteCycles, cpu } = this; - if (txCompleteCycles && cpu.cycles >= txCompleteCycles) { - cpu.setInterruptFlag(this.UDRE); - cpu.setInterruptFlag(this.TXC); - this.txCompleteCycles = 0; - } - } - private get UBRR() { return (this.cpu.data[this.config.UBRRH] << 8) | this.cpu.data[this.config.UBRRL]; } -- cgit v1.2.3