@@ -10,6 +10,7 @@ import { u32, u16, u8, i16 } from '../types';
1010import { avrInterrupt } from './interrupt' ;
1111
1212const registerSpace = 0x100 ;
13+ const MAX_INTERRUPTS = 128 ; // Enough for ATMega2560
1314
1415export type CPUMemoryHook = ( value : u8 , oldValue : u8 , addr : u16 , mask : u8 ) => boolean | void ;
1516export interface CPUMemoryHooks {
@@ -46,7 +47,7 @@ export class CPU {
4647 readonly progBytes = new Uint8Array ( this . progMem . buffer ) ;
4748 readonly readHooks : CPUMemoryReadHooks = [ ] ;
4849 readonly writeHooks : CPUMemoryHooks = [ ] ;
49- private readonly pendingInterrupts : AVRInterruptConfig [ ] = [ ] ;
50+ private readonly pendingInterrupts : ( AVRInterruptConfig | null ) [ ] = new Array ( MAX_INTERRUPTS ) ;
5051 private nextClockEvent : AVRClockEventEntry | null = null ;
5152 private readonly clockEventPool : AVRClockEventEntry [ ] = [ ] ; // helps avoid garbage collection
5253
@@ -77,6 +78,7 @@ export class CPU {
7778 cycles = 0 ;
7879
7980 nextInterrupt : i16 = - 1 ;
81+ maxInterrupt : i16 = 0 ;
8082
8183 constructor ( public progMem : Uint16Array , private sramBytes = 8192 ) {
8284 this . reset ( ) ;
@@ -86,7 +88,7 @@ export class CPU {
8688 this . data . fill ( 0 ) ;
8789 this . SP = this . data . length - 1 ;
8890 this . pc = 0 ;
89- this . pendingInterrupts . splice ( 0 , this . pendingInterrupts . length ) ;
91+ this . pendingInterrupts . fill ( null ) ;
9092 this . nextInterrupt = - 1 ;
9193 this . nextClockEvent = null ;
9294 }
@@ -124,10 +126,6 @@ export class CPU {
124126 return this . SREG & 0x80 ? true : false ;
125127 }
126128
127- private updateNextInterrupt ( ) {
128- this . nextInterrupt = this . pendingInterrupts . findIndex ( ( item ) => ! ! item ) ;
129- }
130-
131129 setInterruptFlag ( interrupt : AVRInterruptConfig ) {
132130 const { flagRegister, flagMask, enableRegister, enableMask } = interrupt ;
133131 if ( interrupt . inverseFlag ) {
@@ -153,16 +151,34 @@ export class CPU {
153151 }
154152
155153 queueInterrupt ( interrupt : AVRInterruptConfig ) {
156- this . pendingInterrupts [ interrupt . address ] = interrupt ;
157- this . updateNextInterrupt ( ) ;
154+ const { address } = interrupt ;
155+ this . pendingInterrupts [ address ] = interrupt ;
156+ if ( this . nextInterrupt === - 1 || this . nextInterrupt > address ) {
157+ this . nextInterrupt = address ;
158+ }
159+ if ( address > this . maxInterrupt ) {
160+ this . maxInterrupt = address ;
161+ }
158162 }
159163
160164 clearInterrupt ( { address, flagRegister, flagMask } : AVRInterruptConfig , clearFlag = true ) {
161- delete this . pendingInterrupts [ address ] ;
162165 if ( clearFlag ) {
163166 this . data [ flagRegister ] &= ~ flagMask ;
164167 }
165- this . updateNextInterrupt ( ) ;
168+ const { pendingInterrupts, maxInterrupt } = this ;
169+ if ( ! pendingInterrupts [ address ] ) {
170+ return ;
171+ }
172+ pendingInterrupts [ address ] = null ;
173+ if ( this . nextInterrupt === address ) {
174+ this . nextInterrupt = - 1 ;
175+ for ( let i = address + 1 ; i <= maxInterrupt ; i ++ ) {
176+ if ( pendingInterrupts [ i ] ) {
177+ this . nextInterrupt = i ;
178+ break ;
179+ }
180+ }
181+ }
166182 }
167183
168184 clearInterruptByFlag ( interrupt : AVRInterruptConfig , registerValue : number ) {
@@ -241,7 +257,8 @@ export class CPU {
241257
242258 const { nextInterrupt } = this ;
243259 if ( this . interruptsEnabled && nextInterrupt >= 0 ) {
244- const interrupt = this . pendingInterrupts [ nextInterrupt ] ;
260+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
261+ const interrupt = this . pendingInterrupts [ nextInterrupt ] ! ;
245262 avrInterrupt ( this , interrupt . address ) ;
246263 if ( ! interrupt . constant ) {
247264 this . clearInterrupt ( interrupt ) ;
0 commit comments