rp2040js 0.19.4 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/dist/cjs/clock/clock.d.ts +6 -8
  2. package/dist/cjs/clock/mock-clock.d.ts +2 -15
  3. package/dist/cjs/clock/mock-clock.js +4 -46
  4. package/dist/cjs/clock/simulation-clock.d.ts +26 -0
  5. package/dist/cjs/clock/simulation-clock.js +97 -0
  6. package/dist/cjs/cortex-m0-core.d.ts +1 -1
  7. package/dist/cjs/cortex-m0-core.js +39 -37
  8. package/dist/cjs/gdb/gdb-connection.d.ts +1 -1
  9. package/dist/cjs/gdb/gdb-connection.js +2 -2
  10. package/dist/cjs/gdb/gdb-server.d.ts +3 -3
  11. package/dist/cjs/gdb/gdb-server.js +12 -11
  12. package/dist/cjs/gdb/gdb-target.d.ts +7 -0
  13. package/dist/cjs/gdb/gdb-target.js +2 -0
  14. package/dist/cjs/gdb/gdb-tcp-server.d.ts +2 -2
  15. package/dist/cjs/gdb/gdb-tcp-server.js +2 -2
  16. package/dist/cjs/index.d.ts +4 -3
  17. package/dist/cjs/index.js +7 -5
  18. package/dist/cjs/peripherals/adc.d.ts +7 -2
  19. package/dist/cjs/peripherals/adc.js +12 -8
  20. package/dist/cjs/peripherals/dma.d.ts +1 -1
  21. package/dist/cjs/peripherals/dma.js +6 -15
  22. package/dist/cjs/peripherals/rtc.d.ts +1 -1
  23. package/dist/cjs/peripherals/rtc.js +3 -3
  24. package/dist/cjs/peripherals/timer.js +12 -17
  25. package/dist/cjs/peripherals/usb.d.ts +5 -0
  26. package/dist/cjs/peripherals/usb.js +62 -53
  27. package/dist/cjs/rp2040.d.ts +0 -5
  28. package/dist/cjs/rp2040.js +2 -27
  29. package/dist/cjs/simulator.d.ts +13 -0
  30. package/dist/cjs/simulator.js +45 -0
  31. package/dist/cjs/utils/timer32.d.ts +3 -3
  32. package/dist/cjs/utils/timer32.js +14 -16
  33. package/dist/esm/clock/clock.d.ts +6 -8
  34. package/dist/esm/clock/mock-clock.d.ts +2 -15
  35. package/dist/esm/clock/mock-clock.js +3 -44
  36. package/dist/esm/clock/simulation-clock.d.ts +26 -0
  37. package/dist/esm/clock/simulation-clock.js +92 -0
  38. package/dist/esm/cortex-m0-core.d.ts +1 -1
  39. package/dist/esm/cortex-m0-core.js +39 -37
  40. package/dist/esm/gdb/gdb-connection.d.ts +1 -1
  41. package/dist/esm/gdb/gdb-connection.js +2 -2
  42. package/dist/esm/gdb/gdb-server.d.ts +3 -3
  43. package/dist/esm/gdb/gdb-server.js +12 -11
  44. package/dist/esm/gdb/gdb-target.d.ts +7 -0
  45. package/dist/esm/gdb/gdb-target.js +1 -0
  46. package/dist/esm/gdb/gdb-tcp-server.d.ts +2 -2
  47. package/dist/esm/gdb/gdb-tcp-server.js +2 -2
  48. package/dist/esm/index.d.ts +4 -3
  49. package/dist/esm/index.js +2 -1
  50. package/dist/esm/peripherals/adc.d.ts +7 -2
  51. package/dist/esm/peripherals/adc.js +12 -8
  52. package/dist/esm/peripherals/dma.d.ts +1 -1
  53. package/dist/esm/peripherals/dma.js +6 -15
  54. package/dist/esm/peripherals/rtc.d.ts +1 -1
  55. package/dist/esm/peripherals/rtc.js +3 -3
  56. package/dist/esm/peripherals/timer.js +12 -17
  57. package/dist/esm/peripherals/usb.d.ts +5 -0
  58. package/dist/esm/peripherals/usb.js +62 -53
  59. package/dist/esm/rp2040.d.ts +0 -5
  60. package/dist/esm/rp2040.js +2 -27
  61. package/dist/esm/simulator.d.ts +13 -0
  62. package/dist/esm/simulator.js +41 -0
  63. package/dist/esm/utils/timer32.d.ts +3 -3
  64. package/dist/esm/utils/timer32.js +14 -16
  65. package/package.json +1 -1
  66. package/dist/cjs/clock/realtime-clock.d.ts +0 -23
  67. package/dist/cjs/clock/realtime-clock.js +0 -73
  68. package/dist/esm/clock/realtime-clock.d.ts +0 -23
  69. package/dist/esm/clock/realtime-clock.js +0 -68
@@ -43,10 +43,10 @@ export class RP2040RTC extends BasePeripheral {
43
43
  this.setup1 = 0;
44
44
  this.ctrl = 0;
45
45
  this.baseline = new Date(2021, 0, 1);
46
- this.baselineMicros = 0;
46
+ this.baselineNanos = 0;
47
47
  }
48
48
  readUint32(offset) {
49
- const date = new Date(this.baseline.getTime() + (this.rp2040.clock.micros - this.baselineMicros) / 1000);
49
+ const date = new Date(this.baseline.getTime() + (this.rp2040.clock.nanos - this.baselineNanos) / 1000000);
50
50
  switch (offset) {
51
51
  case RTC_SETUP0:
52
52
  return this.setup0;
@@ -96,7 +96,7 @@ export class RP2040RTC extends BasePeripheral {
96
96
  const min = (this.setup1 >> SETUP_1_MIN_SHIFT) & SETUP_1_MIN_MASK;
97
97
  const sec = (this.setup1 >> SETUP_1_SEC_SHIFT) & SETUP_1_SEC_MASK;
98
98
  this.baseline = new Date(year, month - 1, day, hour, min, sec);
99
- this.baselineMicros = this.rp2040.clock.micros;
99
+ this.baselineNanos = this.rp2040.clock.nanos;
100
100
  this.ctrl &= ~RTC_LOAD_BITS;
101
101
  }
102
102
  }
@@ -20,35 +20,34 @@ const ALARM_2 = 1 << 2;
20
20
  const ALARM_3 = 1 << 3;
21
21
  const timerInterrupts = [IRQ.TIMER_0, IRQ.TIMER_1, IRQ.TIMER_2, IRQ.TIMER_3];
22
22
  class RPTimerAlarm {
23
- constructor(name, bitValue) {
24
- this.name = name;
23
+ constructor(bitValue, clockAlarm) {
25
24
  this.bitValue = bitValue;
25
+ this.clockAlarm = clockAlarm;
26
26
  this.armed = false;
27
27
  this.targetMicros = 0;
28
- this.timer = null;
29
28
  }
30
29
  }
31
30
  export class RPTimer extends BasePeripheral {
32
31
  constructor(rp2040, name) {
33
32
  super(rp2040, name);
34
33
  this.latchedTimeHigh = 0;
35
- this.alarms = [
36
- new RPTimerAlarm('Alarm 0', ALARM_0),
37
- new RPTimerAlarm('Alarm 1', ALARM_1),
38
- new RPTimerAlarm('Alarm 2', ALARM_2),
39
- new RPTimerAlarm('Alarm 3', ALARM_3),
40
- ];
41
34
  this.intRaw = 0;
42
35
  this.intEnable = 0;
43
36
  this.intForce = 0;
44
37
  this.paused = false;
45
38
  this.clock = rp2040.clock;
39
+ this.alarms = [
40
+ new RPTimerAlarm(ALARM_0, this.clock.createAlarm(() => this.fireAlarm(0))),
41
+ new RPTimerAlarm(ALARM_1, this.clock.createAlarm(() => this.fireAlarm(1))),
42
+ new RPTimerAlarm(ALARM_2, this.clock.createAlarm(() => this.fireAlarm(2))),
43
+ new RPTimerAlarm(ALARM_3, this.clock.createAlarm(() => this.fireAlarm(3))),
44
+ ];
46
45
  }
47
46
  get intStatus() {
48
47
  return (this.intRaw & this.intEnable) | this.intForce;
49
48
  }
50
49
  readUint32(offset) {
51
- const time = this.clock.micros;
50
+ const time = this.clock.nanos / 1000;
52
51
  switch (offset) {
53
52
  case TIMEHR:
54
53
  return this.latchedTimeHigh;
@@ -93,11 +92,10 @@ export class RPTimer extends BasePeripheral {
93
92
  case ALARM3: {
94
93
  const alarmIndex = (offset - ALARM0) / 4;
95
94
  const alarm = this.alarms[alarmIndex];
96
- const delta = (value - this.clock.micros) >>> 0;
97
- this.disarmAlarm(alarm);
95
+ const deltaMicros = (value - this.clock.nanos / 1000) >>> 0;
98
96
  alarm.armed = true;
99
97
  alarm.targetMicros = value;
100
- alarm.timer = this.clock.createTimer(delta, () => this.fireAlarm(alarmIndex));
98
+ alarm.clockAlarm.schedule(deltaMicros * 1000);
101
99
  break;
102
100
  }
103
101
  case ARMED:
@@ -143,10 +141,7 @@ export class RPTimer extends BasePeripheral {
143
141
  }
144
142
  }
145
143
  disarmAlarm(alarm) {
146
- if (alarm.timer) {
147
- this.clock.deleteTimer(alarm.timer);
148
- alarm.timer = null;
149
- }
144
+ alarm.clockAlarm.cancel();
150
145
  alarm.armed = false;
151
146
  }
152
147
  }
@@ -1,3 +1,4 @@
1
+ import { RP2040 } from '../rp2040.js';
1
2
  import { BasePeripheral } from './peripheral.js';
2
3
  export declare class RPUSBController extends BasePeripheral {
3
4
  private mainCtrl;
@@ -6,6 +7,9 @@ export declare class RPUSBController extends BasePeripheral {
6
7
  private intForce;
7
8
  private sieStatus;
8
9
  private buffStatus;
10
+ private readonly endpointReadAlarms;
11
+ private readonly endpointWriteAlarms;
12
+ private readonly resetAlarm;
9
13
  onUSBEnabled?: () => void;
10
14
  onResetReceived?: () => void;
11
15
  onEndpointWrite?: (endpoint: number, buffer: Uint8Array) => void;
@@ -13,6 +17,7 @@ export declare class RPUSBController extends BasePeripheral {
13
17
  readDelayMicroseconds: number;
14
18
  writeDelayMicroseconds: number;
15
19
  get intStatus(): number;
20
+ constructor(rp2040: RP2040, name: string);
16
21
  readUint32(offset: number): number;
17
22
  writeUint32(offset: number, value: number): void;
18
23
  private readEndpointControlReg;
@@ -1,5 +1,6 @@
1
1
  import { IRQ } from '../irq.js';
2
2
  import { BasePeripheral } from './peripheral.js';
3
+ const ENDPOINT_COUNT = 16;
3
4
  // USB DPSRAM Registers
4
5
  const EP1_IN_CONTROL = 0x8;
5
6
  const EP0_IN_BUFFER_CONTROL = 0x80;
@@ -77,20 +78,52 @@ const SIE_WRITECLEAR_MASK = SIE_DATA_SEQ_ERROR |
77
78
  SIE_TRANS_COMPLETE |
78
79
  SIE_SETUP_REC |
79
80
  SIE_RESUME;
81
+ class USBEndpointAlarm {
82
+ constructor(alarm) {
83
+ this.alarm = alarm;
84
+ this.buffers = [];
85
+ }
86
+ schedule(buffer, delayNanos) {
87
+ this.buffers.push(buffer);
88
+ this.alarm.schedule(delayNanos);
89
+ }
90
+ }
80
91
  export class RPUSBController extends BasePeripheral {
81
- constructor() {
82
- super(...arguments);
92
+ get intStatus() {
93
+ return (this.intRaw & this.intEnable) | this.intForce;
94
+ }
95
+ constructor(rp2040, name) {
96
+ super(rp2040, name);
83
97
  this.mainCtrl = 0;
84
98
  this.intRaw = 0;
85
99
  this.intEnable = 0;
86
100
  this.intForce = 0;
87
101
  this.sieStatus = 0;
88
102
  this.buffStatus = 0;
89
- this.readDelayMicroseconds = 1;
90
- this.writeDelayMicroseconds = 1;
91
- }
92
- get intStatus() {
93
- return (this.intRaw & this.intEnable) | this.intForce;
103
+ this.readDelayMicroseconds = 10;
104
+ this.writeDelayMicroseconds = 10; // Determined empirically
105
+ const clock = rp2040.clock;
106
+ this.endpointReadAlarms = [];
107
+ this.endpointWriteAlarms = [];
108
+ for (let i = 0; i < ENDPOINT_COUNT; ++i) {
109
+ this.endpointReadAlarms.push(new USBEndpointAlarm(clock.createAlarm(() => {
110
+ const buffer = this.endpointReadAlarms[i].buffers.shift();
111
+ if (buffer) {
112
+ this.finishRead(i, buffer);
113
+ }
114
+ })));
115
+ this.endpointWriteAlarms.push(new USBEndpointAlarm(clock.createAlarm(() => {
116
+ var _a;
117
+ for (const buffer of this.endpointWriteAlarms[i].buffers) {
118
+ (_a = this.onEndpointWrite) === null || _a === void 0 ? void 0 : _a.call(this, i, buffer);
119
+ }
120
+ this.endpointWriteAlarms[i].buffers = [];
121
+ })));
122
+ }
123
+ this.resetAlarm = clock.createAlarm(() => {
124
+ this.sieStatus |= SIE_BUS_RESET;
125
+ this.sieStatusUpdated();
126
+ });
94
127
  }
95
128
  readUint32(offset) {
96
129
  switch (offset) {
@@ -164,7 +197,7 @@ export class RPUSBController extends BasePeripheral {
164
197
  return this.readEndpointControlReg(endpoint, out) & 0xffc0;
165
198
  }
166
199
  DPRAMUpdated(offset, value) {
167
- var _a, _b, _c, _d;
200
+ var _a, _b;
168
201
  if (value & USB_BUF_CTRL_AVAILABLE &&
169
202
  offset >= EP0_IN_BUFFER_CONTROL &&
170
203
  offset <= EP15_OUT_BUFFER_CONTROL) {
@@ -177,31 +210,6 @@ export class RPUSBController extends BasePeripheral {
177
210
  doubleBuffer = !!(control & USB_CTRL_DOUBLE_BUF);
178
211
  interrupt = !!(control & USB_CTRL_INTERRUPT_PER_TRANSFER);
179
212
  }
180
- const bufferLength = value & USB_BUF_CTRL_LEN_MASK;
181
- const bufferOffset = this.getEndpointBufferOffset(endpoint, bufferOut);
182
- this.debug(`Start USB transfer, endPoint=${endpoint}, direction=${bufferOut ? 'out' : 'in'} buffer=${bufferOffset.toString(16)} length=${bufferLength}`);
183
- value &= ~USB_BUF_CTRL_AVAILABLE;
184
- this.rp2040.usbDPRAMView.setUint32(offset, value, true);
185
- if (bufferOut) {
186
- (_a = this.onEndpointRead) === null || _a === void 0 ? void 0 : _a.call(this, endpoint, bufferLength);
187
- }
188
- else {
189
- value &= ~USB_BUF_CTRL_FULL;
190
- this.rp2040.usbDPRAMView.setUint32(offset, value, true);
191
- const buffer = this.rp2040.usbDPRAM.slice(bufferOffset, bufferOffset + bufferLength);
192
- if (interrupt || !doubleBuffer) {
193
- this.indicateBufferReady(endpoint, false);
194
- }
195
- if (this.writeDelayMicroseconds) {
196
- this.rp2040.clock.createTimer(this.writeDelayMicroseconds, () => {
197
- var _a;
198
- (_a = this.onEndpointWrite) === null || _a === void 0 ? void 0 : _a.call(this, endpoint, buffer);
199
- });
200
- }
201
- else {
202
- (_b = this.onEndpointWrite) === null || _b === void 0 ? void 0 : _b.call(this, endpoint, buffer);
203
- }
204
- }
205
213
  if (doubleBuffer && (value >> USB_BUF1_SHIFT) & USB_BUF_CTRL_AVAILABLE) {
206
214
  const bufferLength = (value >> USB_BUF1_SHIFT) & USB_BUF_CTRL_LEN_MASK;
207
215
  const bufferOffset = this.getEndpointBufferOffset(endpoint, bufferOut) + USB_BUF1_OFFSET;
@@ -209,35 +217,37 @@ export class RPUSBController extends BasePeripheral {
209
217
  value &= ~(USB_BUF_CTRL_AVAILABLE << USB_BUF1_SHIFT);
210
218
  this.rp2040.usbDPRAMView.setUint32(offset, value, true);
211
219
  if (bufferOut) {
212
- (_c = this.onEndpointRead) === null || _c === void 0 ? void 0 : _c.call(this, endpoint, bufferLength);
220
+ (_a = this.onEndpointRead) === null || _a === void 0 ? void 0 : _a.call(this, endpoint, bufferLength);
213
221
  }
214
222
  else {
215
223
  value &= ~(USB_BUF_CTRL_FULL << USB_BUF1_SHIFT);
216
224
  this.rp2040.usbDPRAMView.setUint32(offset, value, true);
217
225
  const buffer = this.rp2040.usbDPRAM.slice(bufferOffset, bufferOffset + bufferLength);
218
226
  this.indicateBufferReady(endpoint, false);
219
- if (this.writeDelayMicroseconds) {
220
- this.rp2040.clock.createTimer(this.writeDelayMicroseconds, () => {
221
- var _a;
222
- (_a = this.onEndpointWrite) === null || _a === void 0 ? void 0 : _a.call(this, endpoint, buffer);
223
- });
224
- }
225
- else {
226
- (_d = this.onEndpointWrite) === null || _d === void 0 ? void 0 : _d.call(this, endpoint, buffer);
227
- }
227
+ this.endpointWriteAlarms[endpoint].schedule(buffer, this.writeDelayMicroseconds * 1000);
228
228
  }
229
229
  }
230
+ const bufferLength = value & USB_BUF_CTRL_LEN_MASK;
231
+ const bufferOffset = this.getEndpointBufferOffset(endpoint, bufferOut);
232
+ this.debug(`Start USB transfer, endPoint=${endpoint}, direction=${bufferOut ? 'out' : 'in'} buffer=${bufferOffset.toString(16)} length=${bufferLength}`);
233
+ value &= ~USB_BUF_CTRL_AVAILABLE;
234
+ this.rp2040.usbDPRAMView.setUint32(offset, value, true);
235
+ if (bufferOut) {
236
+ (_b = this.onEndpointRead) === null || _b === void 0 ? void 0 : _b.call(this, endpoint, bufferLength);
237
+ }
238
+ else {
239
+ value &= ~USB_BUF_CTRL_FULL;
240
+ this.rp2040.usbDPRAMView.setUint32(offset, value, true);
241
+ const buffer = this.rp2040.usbDPRAM.slice(bufferOffset, bufferOffset + bufferLength);
242
+ if (interrupt || !doubleBuffer) {
243
+ this.indicateBufferReady(endpoint, false);
244
+ }
245
+ this.endpointWriteAlarms[endpoint].schedule(buffer, this.writeDelayMicroseconds * 1000);
246
+ }
230
247
  }
231
248
  }
232
249
  endpointReadDone(endpoint, buffer, delay = this.readDelayMicroseconds) {
233
- if (delay) {
234
- this.rp2040.clock.createTimer(delay, () => {
235
- this.finishRead(endpoint, buffer);
236
- });
237
- }
238
- else {
239
- this.finishRead(endpoint, buffer);
240
- }
250
+ this.endpointReadAlarms[endpoint].schedule(buffer, delay * 1000);
241
251
  }
242
252
  finishRead(endpoint, buffer) {
243
253
  const bufferOffset = this.getEndpointBufferOffset(endpoint, true);
@@ -256,8 +266,7 @@ export class RPUSBController extends BasePeripheral {
256
266
  this.rp2040.setInterrupt(IRQ.USBCTRL, !!intStatus);
257
267
  }
258
268
  resetDevice() {
259
- this.sieStatus |= SIE_BUS_RESET;
260
- this.sieStatusUpdated();
269
+ this.resetAlarm.schedule(10000000); // USB reset takes ~10ms
261
270
  }
262
271
  sendSetupPacket(setupPacket) {
263
272
  this.rp2040.usbDPRAM.set(setupPacket);
@@ -44,9 +44,7 @@ export declare class RP2040 {
44
44
  readonly pio: RPPIO[];
45
45
  readonly usbCtrl: RPUSBController;
46
46
  readonly spi: RPSPI[];
47
- private stopped;
48
47
  logger: Logger;
49
- private executeTimer;
50
48
  readonly peripherals: {
51
49
  [index: number]: Peripheral;
52
50
  };
@@ -66,7 +64,4 @@ export declare class RP2040 {
66
64
  setInterrupt(irq: number, value: boolean): void;
67
65
  updateIOInterrupt(): void;
68
66
  step(): void;
69
- execute(): void;
70
- stop(): void;
71
- get executing(): boolean;
72
67
  }
@@ -1,4 +1,4 @@
1
- import { RealtimeClock } from './clock/realtime-clock.js';
1
+ import { SimulationClock } from './clock/simulation-clock.js';
2
2
  import { CortexM0Core } from './cortex-m0-core.js';
3
3
  import { GPIOPin } from './gpio-pin.js';
4
4
  import { IRQ } from './irq.js';
@@ -37,7 +37,7 @@ const KB = 1024;
37
37
  const MB = 1024 * KB;
38
38
  const MHz = 1000000;
39
39
  export class RP2040 {
40
- constructor(clock = new RealtimeClock()) {
40
+ constructor(clock = new SimulationClock()) {
41
41
  this.clock = clock;
42
42
  this.bootrom = new Uint32Array(4 * KB);
43
43
  this.sram = new Uint8Array(264 * KB);
@@ -122,9 +122,7 @@ export class RP2040 {
122
122
  tx: DREQChannel.DREQ_SPI1_TX,
123
123
  }),
124
124
  ];
125
- this.stopped = true;
126
125
  this.logger = new ConsoleLogger(LogLevel.Debug, true);
127
- this.executeTimer = null;
128
126
  this.peripherals = {
129
127
  0x18000: new RPSSI(this, 'SSI'),
130
128
  0x40000: new RP2040SysInfo(this, 'SYSINFO_BASE'),
@@ -164,7 +162,6 @@ export class RP2040 {
164
162
  this.onBreak = (code) => {
165
163
  // TODO: raise HardFault exception
166
164
  // console.error('Breakpoint!', code);
167
- this.stopped = true;
168
165
  };
169
166
  this.reset();
170
167
  }
@@ -339,26 +336,4 @@ export class RP2040 {
339
336
  step() {
340
337
  this.core.executeInstruction();
341
338
  }
342
- execute() {
343
- this.clock.resume();
344
- this.executeTimer = null;
345
- this.stopped = false;
346
- for (let i = 0; i < 100000 && !this.stopped && !this.core.waiting; i++) {
347
- this.core.executeInstruction();
348
- }
349
- if (!this.stopped) {
350
- this.executeTimer = setTimeout(() => this.execute(), 0);
351
- }
352
- }
353
- stop() {
354
- this.stopped = true;
355
- if (this.executeTimer != null) {
356
- clearTimeout(this.executeTimer);
357
- this.executeTimer = null;
358
- }
359
- this.clock.pause();
360
- }
361
- get executing() {
362
- return !this.stopped;
363
- }
364
339
  }
@@ -0,0 +1,13 @@
1
+ import { SimulationClock } from './clock/simulation-clock.js';
2
+ import { IGDBTarget } from './gdb/gdb-target.js';
3
+ import { RP2040 } from './rp2040.js';
4
+ export declare class Simulator implements IGDBTarget {
5
+ readonly clock: SimulationClock;
6
+ executeTimer: ReturnType<typeof setTimeout> | null;
7
+ rp2040: RP2040;
8
+ stopped: boolean;
9
+ constructor(clock?: SimulationClock);
10
+ execute(): void;
11
+ stop(): void;
12
+ get executing(): boolean;
13
+ }
@@ -0,0 +1,41 @@
1
+ import { SimulationClock } from './clock/simulation-clock.js';
2
+ import { RP2040 } from './rp2040.js';
3
+ export class Simulator {
4
+ constructor(clock = new SimulationClock()) {
5
+ this.clock = clock;
6
+ this.executeTimer = null;
7
+ this.stopped = true;
8
+ this.rp2040 = new RP2040(clock);
9
+ this.rp2040.onBreak = () => this.stop();
10
+ }
11
+ execute() {
12
+ const { rp2040, clock } = this;
13
+ this.executeTimer = null;
14
+ this.stopped = false;
15
+ const cycleNanos = 1e9 / 125000000; // 125 MHz
16
+ for (let i = 0; i < 1000000 && !this.stopped; i++) {
17
+ if (rp2040.core.waiting) {
18
+ const { nanosToNextAlarm } = clock;
19
+ clock.tick(nanosToNextAlarm);
20
+ i += nanosToNextAlarm / cycleNanos;
21
+ }
22
+ else {
23
+ const cycles = rp2040.core.executeInstruction();
24
+ clock.tick(cycles * cycleNanos);
25
+ }
26
+ }
27
+ if (!this.stopped) {
28
+ this.executeTimer = setTimeout(() => this.execute(), 0);
29
+ }
30
+ }
31
+ stop() {
32
+ this.stopped = true;
33
+ if (this.executeTimer != null) {
34
+ clearTimeout(this.executeTimer);
35
+ this.executeTimer = null;
36
+ }
37
+ }
38
+ get executing() {
39
+ return !this.stopped;
40
+ }
41
+ }
@@ -8,7 +8,7 @@ export declare class Timer32 {
8
8
  readonly clock: IClock;
9
9
  private baseFreq;
10
10
  private baseValue;
11
- private baseMicros;
11
+ private baseNanos;
12
12
  private topValue;
13
13
  private prescalerValue;
14
14
  private timerMode;
@@ -32,7 +32,7 @@ export declare class Timer32 {
32
32
  set frequency(value: number);
33
33
  get prescaler(): number;
34
34
  set prescaler(value: number);
35
- toMicros(cycles: number): number;
35
+ toNanos(cycles: number): number;
36
36
  get enable(): boolean;
37
37
  set enable(value: boolean);
38
38
  get mode(): TimerMode;
@@ -44,7 +44,7 @@ export declare class Timer32PeriodicAlarm {
44
44
  readonly callback: () => void;
45
45
  private targetValue;
46
46
  private enabled;
47
- private clockTimer?;
47
+ private clockAlarm;
48
48
  constructor(timer: Timer32, callback: () => void);
49
49
  get enable(): boolean;
50
50
  set enable(value: boolean);
@@ -9,7 +9,7 @@ export class Timer32 {
9
9
  this.clock = clock;
10
10
  this.baseFreq = baseFreq;
11
11
  this.baseValue = 0;
12
- this.baseMicros = 0;
12
+ this.baseNanos = 0;
13
13
  this.topValue = 0xffffffff;
14
14
  this.prescalerValue = 1;
15
15
  this.timerMode = TimerMode.Increment;
@@ -17,13 +17,13 @@ export class Timer32 {
17
17
  this.listeners = [];
18
18
  }
19
19
  reset() {
20
- this.baseMicros = this.clock.micros;
20
+ this.baseNanos = this.clock.nanos;
21
21
  this.baseValue = 0;
22
22
  this.updated();
23
23
  }
24
24
  set(value, zigZagDown = false) {
25
25
  this.baseValue = zigZagDown ? this.topValue * 2 - value : value;
26
- this.baseMicros = this.clock.micros;
26
+ this.baseNanos = this.clock.nanos;
27
27
  this.updated();
28
28
  }
29
29
  /**
@@ -36,12 +36,12 @@ export class Timer32 {
36
36
  this.baseValue += delta;
37
37
  }
38
38
  get rawCounter() {
39
- const { baseFreq, prescalerValue, baseMicros, baseValue, enabled, timerMode } = this;
39
+ const { baseFreq, prescalerValue, baseNanos, baseValue, enabled, timerMode } = this;
40
40
  if (!baseFreq || !prescalerValue || !enabled) {
41
41
  return this.baseValue;
42
42
  }
43
43
  const zigzag = timerMode == TimerMode.ZigZag;
44
- const ticks = ((this.clock.micros - baseMicros) / 1e6) * (baseFreq / prescalerValue);
44
+ const ticks = ((this.clock.nanos - baseNanos) / 1e9) * (baseFreq / prescalerValue);
45
45
  const topModulo = zigzag ? this.topValue * 2 : this.topValue + 1;
46
46
  const delta = timerMode == TimerMode.Decrement ? topModulo - (ticks % topModulo) : ticks;
47
47
  let currentValue = Math.round(baseValue + delta);
@@ -70,7 +70,7 @@ export class Timer32 {
70
70
  }
71
71
  set frequency(value) {
72
72
  this.baseValue = this.counter;
73
- this.baseMicros = this.clock.micros;
73
+ this.baseNanos = this.clock.nanos;
74
74
  this.baseFreq = value;
75
75
  this.updated();
76
76
  }
@@ -79,14 +79,14 @@ export class Timer32 {
79
79
  }
80
80
  set prescaler(value) {
81
81
  this.baseValue = this.counter;
82
- this.baseMicros = this.clock.micros;
82
+ this.baseNanos = this.clock.nanos;
83
83
  this.enabled = this.prescalerValue !== 0;
84
84
  this.prescalerValue = value;
85
85
  this.updated();
86
86
  }
87
- toMicros(cycles) {
87
+ toNanos(cycles) {
88
88
  const { baseFreq, prescalerValue } = this;
89
- return (cycles * 1e6) / (baseFreq / prescalerValue);
89
+ return (cycles * 1e9) / (baseFreq / prescalerValue);
90
90
  }
91
91
  get enable() {
92
92
  return this.enabled;
@@ -94,7 +94,7 @@ export class Timer32 {
94
94
  set enable(value) {
95
95
  if (value !== this.enabled) {
96
96
  if (value) {
97
- this.baseMicros = this.clock.micros;
97
+ this.baseNanos = this.clock.nanos;
98
98
  }
99
99
  else {
100
100
  this.baseValue = this.counter;
@@ -137,6 +137,7 @@ export class Timer32PeriodicAlarm {
137
137
  this.schedule();
138
138
  }
139
139
  };
140
+ this.clockAlarm = this.timer.clock.createAlarm(this.handleAlarm);
140
141
  timer.listeners.push(this.update);
141
142
  }
142
143
  get enable() {
@@ -191,13 +192,10 @@ export class Timer32PeriodicAlarm {
191
192
  cycleDelta = top + 1 - cycleDelta;
192
193
  }
193
194
  const cyclesToAlarm = cycleDelta >>> 0;
194
- const microsToAlarm = timer.toMicros(cyclesToAlarm);
195
- this.clockTimer = this.timer.clock.createTimer(microsToAlarm, this.handleAlarm);
195
+ const nanosToAlarm = timer.toNanos(cyclesToAlarm);
196
+ this.clockAlarm.schedule(nanosToAlarm);
196
197
  }
197
198
  cancel() {
198
- if (this.clockTimer) {
199
- this.timer.clock.deleteTimer(this.clockTimer);
200
- this.clockTimer = undefined;
201
- }
199
+ this.clockAlarm.cancel();
202
200
  }
203
201
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rp2040js",
3
- "version": "0.19.4",
3
+ "version": "1.0.1",
4
4
  "description": "Raspberry Pi Pico (RP2040) Emulator",
5
5
  "repository": "https://github.com/wokwi/rp2040js",
6
6
  "keywords": [
@@ -1,23 +0,0 @@
1
- import { IClock, IClockTimer } from './clock.js';
2
- export declare class ClockTimer implements IClockTimer {
3
- private micros;
4
- private callback;
5
- private jsTimer;
6
- private timeLeft;
7
- constructor(micros: number, callback: () => void);
8
- schedule(currentMicros: number): void;
9
- unschedule(): void;
10
- pause(currentMicros: number): void;
11
- resume(currentMicros: number): void;
12
- }
13
- export declare class RealtimeClock implements IClock {
14
- baseTime: number;
15
- pauseTime: number;
16
- paused: boolean;
17
- timers: Set<ClockTimer>;
18
- pause(): void;
19
- resume(): void;
20
- createTimer(deltaMicros: number, callback: () => void): ClockTimer;
21
- deleteTimer(timer: ClockTimer): void;
22
- get micros(): number;
23
- }
@@ -1,73 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RealtimeClock = exports.ClockTimer = void 0;
4
- const time_js_1 = require("../utils/time.js");
5
- class ClockTimer {
6
- constructor(micros, callback) {
7
- this.micros = micros;
8
- this.callback = callback;
9
- this.jsTimer = null;
10
- this.timeLeft = this.micros;
11
- }
12
- schedule(currentMicros) {
13
- this.jsTimer = setTimeout(this.callback, (this.micros - currentMicros) / 1000);
14
- }
15
- unschedule() {
16
- if (this.jsTimer) {
17
- clearTimeout(this.jsTimer);
18
- this.jsTimer = null;
19
- }
20
- }
21
- pause(currentMicros) {
22
- this.timeLeft = this.micros - currentMicros;
23
- this.unschedule();
24
- }
25
- resume(currentMicros) {
26
- this.micros = currentMicros + this.timeLeft;
27
- this.schedule(currentMicros);
28
- }
29
- }
30
- exports.ClockTimer = ClockTimer;
31
- class RealtimeClock {
32
- constructor() {
33
- this.baseTime = 0;
34
- this.pauseTime = 0;
35
- this.paused = true;
36
- this.timers = new Set();
37
- }
38
- pause() {
39
- if (!this.paused) {
40
- for (const timer of this.timers) {
41
- timer.pause(this.micros);
42
- }
43
- this.pauseTime = this.micros;
44
- this.paused = true;
45
- }
46
- }
47
- resume() {
48
- if (this.paused) {
49
- this.baseTime = (0, time_js_1.getCurrentMicroseconds)() - this.pauseTime;
50
- this.paused = false;
51
- for (const timer of this.timers) {
52
- timer.resume(this.micros);
53
- }
54
- }
55
- }
56
- createTimer(deltaMicros, callback) {
57
- const timer = new ClockTimer(this.micros + deltaMicros, () => {
58
- this.timers.delete(timer);
59
- callback();
60
- });
61
- timer.schedule(this.micros);
62
- this.timers.add(timer);
63
- return timer;
64
- }
65
- deleteTimer(timer) {
66
- timer.unschedule();
67
- this.timers.delete(timer);
68
- }
69
- get micros() {
70
- return (0, time_js_1.getCurrentMicroseconds)() - this.baseTime;
71
- }
72
- }
73
- exports.RealtimeClock = RealtimeClock;
@@ -1,23 +0,0 @@
1
- import { IClock, IClockTimer } from './clock.js';
2
- export declare class ClockTimer implements IClockTimer {
3
- private micros;
4
- private callback;
5
- private jsTimer;
6
- private timeLeft;
7
- constructor(micros: number, callback: () => void);
8
- schedule(currentMicros: number): void;
9
- unschedule(): void;
10
- pause(currentMicros: number): void;
11
- resume(currentMicros: number): void;
12
- }
13
- export declare class RealtimeClock implements IClock {
14
- baseTime: number;
15
- pauseTime: number;
16
- paused: boolean;
17
- timers: Set<ClockTimer>;
18
- pause(): void;
19
- resume(): void;
20
- createTimer(deltaMicros: number, callback: () => void): ClockTimer;
21
- deleteTimer(timer: ClockTimer): void;
22
- get micros(): number;
23
- }