@@ -61,6 +61,7 @@ export type AVRClockEventCallback = () => void;
6161interface AVRClockEventEntry {
6262 cycles : number ;
6363 callback : AVRClockEventCallback ;
64+ next : AVRClockEventEntry | null ;
6465}
6566
6667export class CPU implements ICPU {
@@ -71,7 +72,8 @@ export class CPU implements ICPU {
7172 readonly readHooks : CPUMemoryReadHooks = [ ] ;
7273 readonly writeHooks : CPUMemoryHooks = [ ] ;
7374 private readonly pendingInterrupts : AVRInterruptConfig [ ] = [ ] ;
74- private readonly clockEvents : AVRClockEventEntry [ ] = [ ] ;
75+ private nextClockEvent : AVRClockEventEntry | null = null ;
76+ private readonly clockEventPool : AVRClockEventEntry [ ] = [ ] ; // helps avoid garbage collection
7577 readonly pc22Bits = this . progBytes . length > 0x20000 ;
7678
7779 // This lets the Timer Compare output override GPIO pins:
@@ -80,7 +82,6 @@ export class CPU implements ICPU {
8082 pc : u32 = 0 ;
8183 cycles : u32 = 0 ;
8284 nextInterrupt : i16 = - 1 ;
83- private nextClockEvent : u32 = 0 ;
8485
8586 constructor ( public progMem : Uint16Array , private sramBytes = 8192 ) {
8687 this . reset ( ) ;
@@ -175,22 +176,25 @@ export class CPU implements ICPU {
175176 }
176177
177178 addClockEvent ( callback : AVRClockEventCallback , cycles : number ) {
178- const entry = { cycles : this . cycles + Math . max ( 1 , cycles ) , callback } ;
179- // Add the new entry while keeping the array sorted
180- const { clockEvents } = this ;
181- if ( ! clockEvents . length || clockEvents [ clockEvents . length - 1 ] . cycles <= entry . cycles ) {
182- clockEvents . push ( entry ) ;
183- } else if ( clockEvents [ 0 ] . cycles >= entry . cycles ) {
184- clockEvents . unshift ( entry ) ;
179+ const { clockEventPool } = this ;
180+ cycles = this . cycles + Math . max ( 1 , cycles ) ;
181+ const maybeEntry = clockEventPool . pop ( ) ;
182+ const entry : AVRClockEventEntry = maybeEntry ?? { cycles, callback, next : null } ;
183+ entry . cycles = cycles ;
184+ entry . callback = callback ;
185+ let { nextClockEvent : clockEvent } = this ;
186+ let lastItem = null ;
187+ while ( clockEvent && clockEvent . cycles < cycles ) {
188+ lastItem = clockEvent ;
189+ clockEvent = clockEvent . next ;
190+ }
191+ if ( lastItem ) {
192+ lastItem . next = entry ;
193+ entry . next = clockEvent ;
185194 } else {
186- for ( let i = 1 ; i < clockEvents . length ; i ++ ) {
187- if ( clockEvents [ i ] . cycles >= entry . cycles ) {
188- clockEvents . splice ( i , 0 , entry ) ;
189- break ;
190- }
191- }
195+ this . nextClockEvent = entry ;
196+ entry . next = clockEvent ;
192197 }
193- this . nextClockEvent = this . clockEvents [ 0 ] . cycles ;
194198 return callback ;
195199 }
196200
@@ -203,20 +207,38 @@ export class CPU implements ICPU {
203207 }
204208
205209 clearClockEvent ( callback : AVRClockEventCallback ) {
206- const index = this . clockEvents . findIndex ( ( item ) => item . callback === callback ) ;
207- if ( index >= 0 ) {
208- this . clockEvents . splice ( index , 1 ) ;
209- this . nextClockEvent = this . clockEvents [ 0 ] ?. cycles ?? 0 ;
210- return true ;
210+ let { nextClockEvent : clockEvent } = this ;
211+ if ( ! clockEvent ) {
212+ return false ;
213+ }
214+ const { clockEventPool } = this ;
215+ let lastItem = null ;
216+ while ( clockEvent ) {
217+ if ( clockEvent . callback === callback ) {
218+ if ( lastItem ) {
219+ lastItem . next = clockEvent . next ;
220+ } else {
221+ this . nextClockEvent = clockEvent . next ;
222+ }
223+ if ( clockEventPool . length < 10 ) {
224+ clockEventPool . push ( clockEvent ) ;
225+ }
226+ return true ;
227+ }
228+ lastItem = clockEvent ;
229+ clockEvent = clockEvent . next ;
211230 }
212231 return false ;
213232 }
214233
215234 tick ( ) {
216- const { nextClockEvent, clockEvents } = this ;
217- if ( nextClockEvent && nextClockEvent <= this . cycles ) {
218- clockEvents . shift ( ) ?. callback ( ) ;
219- this . nextClockEvent = clockEvents [ 0 ] ?. cycles ?? 0 ;
235+ const { nextClockEvent } = this ;
236+ if ( nextClockEvent && nextClockEvent . cycles <= this . cycles ) {
237+ nextClockEvent . callback ( ) ;
238+ this . nextClockEvent = nextClockEvent . next ;
239+ if ( this . clockEventPool . length < 10 ) {
240+ this . clockEventPool . push ( nextClockEvent ) ;
241+ }
220242 }
221243
222244 const { nextInterrupt } = this ;
0 commit comments