@@ -61,6 +61,7 @@ export type AVRClockEventCallback = () => void;
61
61
interface AVRClockEventEntry {
62
62
cycles : number ;
63
63
callback : AVRClockEventCallback ;
64
+ next : AVRClockEventEntry | null ;
64
65
}
65
66
66
67
export class CPU implements ICPU {
@@ -71,7 +72,8 @@ export class CPU implements ICPU {
71
72
readonly readHooks : CPUMemoryReadHooks = [ ] ;
72
73
readonly writeHooks : CPUMemoryHooks = [ ] ;
73
74
private readonly pendingInterrupts : AVRInterruptConfig [ ] = [ ] ;
74
- private readonly clockEvents : AVRClockEventEntry [ ] = [ ] ;
75
+ private nextClockEvent : AVRClockEventEntry | null = null ;
76
+ private readonly clockEventPool : AVRClockEventEntry [ ] = [ ] ; // helps avoid garbage collection
75
77
readonly pc22Bits = this . progBytes . length > 0x20000 ;
76
78
77
79
// This lets the Timer Compare output override GPIO pins:
@@ -80,7 +82,6 @@ export class CPU implements ICPU {
80
82
pc : u32 = 0 ;
81
83
cycles : u32 = 0 ;
82
84
nextInterrupt : i16 = - 1 ;
83
- private nextClockEvent : u32 = 0 ;
84
85
85
86
constructor ( public progMem : Uint16Array , private sramBytes = 8192 ) {
86
87
this . reset ( ) ;
@@ -175,22 +176,25 @@ export class CPU implements ICPU {
175
176
}
176
177
177
178
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 ;
185
194
} 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 ;
192
197
}
193
- this . nextClockEvent = this . clockEvents [ 0 ] . cycles ;
194
198
return callback ;
195
199
}
196
200
@@ -203,20 +207,38 @@ export class CPU implements ICPU {
203
207
}
204
208
205
209
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 ;
211
230
}
212
231
return false ;
213
232
}
214
233
215
234
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
+ }
220
242
}
221
243
222
244
const { nextInterrupt } = this ;
0 commit comments