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
@@ -1,10 +1,10 @@
1
1
  /// <reference types="node" />
2
2
  import { Socket } from 'net';
3
3
  import { GDBServer } from './gdb-server.js';
4
- import { RP2040 } from '../rp2040.js';
4
+ import { IGDBTarget } from './gdb-target.js';
5
5
  export declare class GDBTCPServer extends GDBServer {
6
6
  readonly port: number;
7
7
  private socketServer;
8
- constructor(rp2040: RP2040, port?: number);
8
+ constructor(target: IGDBTarget, port?: number);
9
9
  handleConnection(socket: Socket): void;
10
10
  }
@@ -5,8 +5,8 @@ const net_1 = require("net");
5
5
  const gdb_connection_js_1 = require("./gdb-connection.js");
6
6
  const gdb_server_js_1 = require("./gdb-server.js");
7
7
  class GDBTCPServer extends gdb_server_js_1.GDBServer {
8
- constructor(rp2040, port = 3333) {
9
- super(rp2040);
8
+ constructor(target, port = 3333) {
9
+ super(target);
10
10
  this.port = port;
11
11
  this.socketServer = (0, net_1.createServer)();
12
12
  this.socketServer.listen(port);
@@ -1,11 +1,12 @@
1
1
  export { GDBConnection } from './gdb/gdb-connection.js';
2
2
  export { GDBServer } from './gdb/gdb-server.js';
3
3
  export { GPIOPin, GPIOPinState } from './gpio-pin.js';
4
+ export { I2CMode, I2CSpeed, RPI2C } from './peripherals/i2c.js';
4
5
  export { BasePeripheral, type Peripheral } from './peripherals/peripheral.js';
5
- export { RPI2C, I2CSpeed, I2CMode } from './peripherals/i2c.js';
6
6
  export { RPUSBController } from './peripherals/usb.js';
7
7
  export { RP2040 } from './rp2040.js';
8
+ export { Simulator } from './simulator.js';
8
9
  export { USBCDC } from './usb/cdc.js';
9
- export { DataDirection, DescriptorType, type ISetupPacketParams, SetupRecipient, SetupRequest, SetupType, } from './usb/interfaces.js';
10
+ export { DataDirection, DescriptorType, SetupRecipient, SetupRequest, SetupType, type ISetupPacketParams, } from './usb/interfaces.js';
10
11
  export { createSetupPacket, getDescriptorPacket, setDeviceAddressPacket, setDeviceConfigurationPacket, } from './usb/setup.js';
11
- export { ConsoleLogger, type Logger, LogLevel } from './utils/logging.js';
12
+ export { ConsoleLogger, LogLevel, type Logger } from './utils/logging.js';
package/dist/cjs/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.LogLevel = exports.ConsoleLogger = exports.setDeviceConfigurationPacket = exports.setDeviceAddressPacket = exports.getDescriptorPacket = exports.createSetupPacket = exports.SetupType = exports.SetupRequest = exports.SetupRecipient = exports.DescriptorType = exports.DataDirection = exports.USBCDC = exports.RP2040 = exports.RPUSBController = exports.I2CMode = exports.I2CSpeed = exports.RPI2C = exports.BasePeripheral = exports.GPIOPinState = exports.GPIOPin = exports.GDBServer = exports.GDBConnection = void 0;
3
+ exports.LogLevel = exports.ConsoleLogger = exports.setDeviceConfigurationPacket = exports.setDeviceAddressPacket = exports.getDescriptorPacket = exports.createSetupPacket = exports.SetupType = exports.SetupRequest = exports.SetupRecipient = exports.DescriptorType = exports.DataDirection = exports.USBCDC = exports.Simulator = exports.RP2040 = exports.RPUSBController = exports.BasePeripheral = exports.RPI2C = exports.I2CSpeed = exports.I2CMode = exports.GPIOPinState = exports.GPIOPin = exports.GDBServer = exports.GDBConnection = void 0;
4
4
  var gdb_connection_js_1 = require("./gdb/gdb-connection.js");
5
5
  Object.defineProperty(exports, "GDBConnection", { enumerable: true, get: function () { return gdb_connection_js_1.GDBConnection; } });
6
6
  var gdb_server_js_1 = require("./gdb/gdb-server.js");
@@ -8,16 +8,18 @@ Object.defineProperty(exports, "GDBServer", { enumerable: true, get: function ()
8
8
  var gpio_pin_js_1 = require("./gpio-pin.js");
9
9
  Object.defineProperty(exports, "GPIOPin", { enumerable: true, get: function () { return gpio_pin_js_1.GPIOPin; } });
10
10
  Object.defineProperty(exports, "GPIOPinState", { enumerable: true, get: function () { return gpio_pin_js_1.GPIOPinState; } });
11
- var peripheral_js_1 = require("./peripherals/peripheral.js");
12
- Object.defineProperty(exports, "BasePeripheral", { enumerable: true, get: function () { return peripheral_js_1.BasePeripheral; } });
13
11
  var i2c_js_1 = require("./peripherals/i2c.js");
14
- Object.defineProperty(exports, "RPI2C", { enumerable: true, get: function () { return i2c_js_1.RPI2C; } });
15
- Object.defineProperty(exports, "I2CSpeed", { enumerable: true, get: function () { return i2c_js_1.I2CSpeed; } });
16
12
  Object.defineProperty(exports, "I2CMode", { enumerable: true, get: function () { return i2c_js_1.I2CMode; } });
13
+ Object.defineProperty(exports, "I2CSpeed", { enumerable: true, get: function () { return i2c_js_1.I2CSpeed; } });
14
+ Object.defineProperty(exports, "RPI2C", { enumerable: true, get: function () { return i2c_js_1.RPI2C; } });
15
+ var peripheral_js_1 = require("./peripherals/peripheral.js");
16
+ Object.defineProperty(exports, "BasePeripheral", { enumerable: true, get: function () { return peripheral_js_1.BasePeripheral; } });
17
17
  var usb_js_1 = require("./peripherals/usb.js");
18
18
  Object.defineProperty(exports, "RPUSBController", { enumerable: true, get: function () { return usb_js_1.RPUSBController; } });
19
19
  var rp2040_js_1 = require("./rp2040.js");
20
20
  Object.defineProperty(exports, "RP2040", { enumerable: true, get: function () { return rp2040_js_1.RP2040; } });
21
+ var simulator_js_1 = require("./simulator.js");
22
+ Object.defineProperty(exports, "Simulator", { enumerable: true, get: function () { return simulator_js_1.Simulator; } });
21
23
  var cdc_js_1 = require("./usb/cdc.js");
22
24
  Object.defineProperty(exports, "USBCDC", { enumerable: true, get: function () { return cdc_js_1.USBCDC; } });
23
25
  var interfaces_js_1 = require("./usb/interfaces.js");
@@ -19,10 +19,10 @@ export declare class RPADC extends BasePeripheral implements Peripheral {
19
19
  * Invoked whenever the emulated code performs an ADC read.
20
20
  *
21
21
  * The default implementation reads the result from the `channelValues` array, and then calls
22
- * completeADCRead() after `sampleTime` milliseconds.
22
+ * completeADCRead() after `sampleTime` microseconds.
23
23
  *
24
24
  * If you override the default implementation, make sure to call `completeADCRead()` after
25
- * `sampleTime` milliseconds (or else the ADC read will never complete).
25
+ * `sampleTime` microseconds (or else the ADC read will never complete).
26
26
  */
27
27
  onADCRead: (channel: number) => void;
28
28
  readonly fifo: FIFO;
@@ -35,6 +35,11 @@ export declare class RPADC extends BasePeripheral implements Peripheral {
35
35
  result: number;
36
36
  busy: boolean;
37
37
  err: boolean;
38
+ currentChannel: number;
39
+ /** Used to simulate ADC sample time */
40
+ sampleAlarm: import("../clock/clock.js").IAlarm;
41
+ /** For scheduling multi-shot ADC capture */
42
+ multiShotAlarm: import("../clock/clock.js").IAlarm;
38
43
  get temperatueEnable(): number;
39
44
  get enabled(): number;
40
45
  get divider(): number;
@@ -100,14 +100,15 @@ class RPADC extends peripheral_js_1.BasePeripheral {
100
100
  * Invoked whenever the emulated code performs an ADC read.
101
101
  *
102
102
  * The default implementation reads the result from the `channelValues` array, and then calls
103
- * completeADCRead() after `sampleTime` milliseconds.
103
+ * completeADCRead() after `sampleTime` microseconds.
104
104
  *
105
105
  * If you override the default implementation, make sure to call `completeADCRead()` after
106
- * `sampleTime` milliseconds (or else the ADC read will never complete).
106
+ * `sampleTime` microseconds (or else the ADC read will never complete).
107
107
  */
108
108
  this.onADCRead = (channel) => {
109
109
  // Default implementation
110
- this.rp2040.clock.createTimer(this.sampleTime, () => this.completeADCRead(this.channelValues[channel], false));
110
+ this.currentChannel = channel;
111
+ this.sampleAlarm.schedule(this.sampleTime * 1000);
111
112
  };
112
113
  this.fifo = new fifo_js_1.FIFO(4);
113
114
  this.dreq = dma_js_1.DREQChannel.DREQ_ADC;
@@ -121,6 +122,13 @@ class RPADC extends peripheral_js_1.BasePeripheral {
121
122
  // Status
122
123
  this.busy = false;
123
124
  this.err = false;
125
+ this.currentChannel = 0;
126
+ this.sampleAlarm = this.rp2040.clock.createAlarm(() => this.completeADCRead(this.channelValues[this.currentChannel], false));
127
+ this.multiShotAlarm = this.rp2040.clock.createAlarm(() => {
128
+ if (this.cs & CS_START_MANY) {
129
+ this.startADCRead();
130
+ }
131
+ });
124
132
  }
125
133
  checkInterrupts() {
126
134
  this.rp2040.setInterrupt(irq_js_1.IRQ.ADC_FIFO, !!this.intStatus);
@@ -183,11 +191,7 @@ class RPADC extends peripheral_js_1.BasePeripheral {
183
191
  if (this.divider > sampleTicks) {
184
192
  // clock runs at 48MHz, subtract 2uS
185
193
  const micros = (this.divider - sampleTicks) / clockMHZ;
186
- this.rp2040.clock.createTimer(micros, () => {
187
- if (this.cs & CS_START_MANY) {
188
- this.startADCRead();
189
- }
190
- });
194
+ this.multiShotAlarm.schedule(micros * 1000);
191
195
  }
192
196
  else {
193
197
  this.startADCRead();
@@ -65,7 +65,7 @@ export declare class RPDMAChannel {
65
65
  private chainTo;
66
66
  private ringMask;
67
67
  private transferFn;
68
- private transferTimer;
68
+ private transferAlarm;
69
69
  constructor(dma: RPDMA, rp2040: RP2040, index: number);
70
70
  start(): void;
71
71
  get treq(): number;
@@ -133,7 +133,6 @@ class RPDMAChannel {
133
133
  this.chainTo = 0;
134
134
  this.ringMask = 0;
135
135
  this.transferFn = () => 0;
136
- this.transferTimer = null;
137
136
  this.transfer8 = () => {
138
137
  const { rp2040 } = this;
139
138
  rp2040.writeUint8(this.writeAddr, rp2040.readUint8(this.readAddr));
@@ -162,7 +161,6 @@ class RPDMAChannel {
162
161
  this.transfer = () => {
163
162
  var _a;
164
163
  const { ctrl, dataSize, ringMask } = this;
165
- this.transferTimer = null;
166
164
  this.transferFn();
167
165
  if (ctrl & INCR_READ) {
168
166
  if (ringMask && !(ctrl & RING_SEL)) {
@@ -195,6 +193,7 @@ class RPDMAChannel {
195
193
  }
196
194
  }
197
195
  };
196
+ this.transferAlarm = rp2040.clock.createAlarm(this.transfer);
198
197
  this.reset();
199
198
  }
200
199
  start() {
@@ -214,26 +213,19 @@ class RPDMAChannel {
214
213
  return this.ctrl & EN && this.ctrl & BUSY;
215
214
  }
216
215
  scheduleTransfer() {
217
- if (this.transferTimer) {
218
- // Already scheduled; do nothing.
219
- return;
220
- }
221
216
  if (this.dma.dreq[this.treqValue] || this.treqValue === TREQ.Permanent) {
222
- this.transferTimer = this.rp2040.clock.createTimer(0, this.transfer);
217
+ this.transferAlarm.schedule(0);
223
218
  }
224
219
  else {
225
220
  const delay = this.dma.getTimer(this.treqValue);
226
221
  if (delay) {
227
- this.transferTimer = this.rp2040.clock.createTimer(delay, this.transfer);
222
+ this.transferAlarm.schedule(delay * 1000);
228
223
  }
229
224
  }
230
225
  }
231
226
  abort() {
232
227
  this.ctrl &= ~BUSY;
233
- if (this.transferTimer) {
234
- this.rp2040.clock.deleteTimer(this.transferTimer);
235
- this.transferTimer = null;
236
- }
228
+ this.transferAlarm.cancel();
237
229
  }
238
230
  readUint32(offset) {
239
231
  switch (offset) {
@@ -311,9 +303,8 @@ class RPDMAChannel {
311
303
  if (this.ctrl & EN && this.ctrl & BUSY) {
312
304
  this.scheduleTransfer();
313
305
  }
314
- if (!(this.ctrl & EN) && this.transferTimer) {
315
- this.rp2040.clock.deleteTimer(this.transferTimer);
316
- this.transferTimer = null;
306
+ if (!(this.ctrl & EN)) {
307
+ this.transferAlarm.cancel();
317
308
  }
318
309
  break;
319
310
  }
@@ -4,7 +4,7 @@ export declare class RP2040RTC extends BasePeripheral implements Peripheral {
4
4
  setup1: number;
5
5
  ctrl: number;
6
6
  baseline: Date;
7
- baselineMicros: number;
7
+ baselineNanos: number;
8
8
  readUint32(offset: number): number;
9
9
  writeUint32(offset: number, value: number): void;
10
10
  }
@@ -46,10 +46,10 @@ class RP2040RTC extends peripheral_js_1.BasePeripheral {
46
46
  this.setup1 = 0;
47
47
  this.ctrl = 0;
48
48
  this.baseline = new Date(2021, 0, 1);
49
- this.baselineMicros = 0;
49
+ this.baselineNanos = 0;
50
50
  }
51
51
  readUint32(offset) {
52
- const date = new Date(this.baseline.getTime() + (this.rp2040.clock.micros - this.baselineMicros) / 1000);
52
+ const date = new Date(this.baseline.getTime() + (this.rp2040.clock.nanos - this.baselineNanos) / 1000000);
53
53
  switch (offset) {
54
54
  case RTC_SETUP0:
55
55
  return this.setup0;
@@ -99,7 +99,7 @@ class RP2040RTC extends peripheral_js_1.BasePeripheral {
99
99
  const min = (this.setup1 >> SETUP_1_MIN_SHIFT) & SETUP_1_MIN_MASK;
100
100
  const sec = (this.setup1 >> SETUP_1_SEC_SHIFT) & SETUP_1_SEC_MASK;
101
101
  this.baseline = new Date(year, month - 1, day, hour, min, sec);
102
- this.baselineMicros = this.rp2040.clock.micros;
102
+ this.baselineNanos = this.rp2040.clock.nanos;
103
103
  this.ctrl &= ~RTC_LOAD_BITS;
104
104
  }
105
105
  }
@@ -23,35 +23,34 @@ const ALARM_2 = 1 << 2;
23
23
  const ALARM_3 = 1 << 3;
24
24
  const timerInterrupts = [irq_js_1.IRQ.TIMER_0, irq_js_1.IRQ.TIMER_1, irq_js_1.IRQ.TIMER_2, irq_js_1.IRQ.TIMER_3];
25
25
  class RPTimerAlarm {
26
- constructor(name, bitValue) {
27
- this.name = name;
26
+ constructor(bitValue, clockAlarm) {
28
27
  this.bitValue = bitValue;
28
+ this.clockAlarm = clockAlarm;
29
29
  this.armed = false;
30
30
  this.targetMicros = 0;
31
- this.timer = null;
32
31
  }
33
32
  }
34
33
  class RPTimer extends peripheral_js_1.BasePeripheral {
35
34
  constructor(rp2040, name) {
36
35
  super(rp2040, name);
37
36
  this.latchedTimeHigh = 0;
38
- this.alarms = [
39
- new RPTimerAlarm('Alarm 0', ALARM_0),
40
- new RPTimerAlarm('Alarm 1', ALARM_1),
41
- new RPTimerAlarm('Alarm 2', ALARM_2),
42
- new RPTimerAlarm('Alarm 3', ALARM_3),
43
- ];
44
37
  this.intRaw = 0;
45
38
  this.intEnable = 0;
46
39
  this.intForce = 0;
47
40
  this.paused = false;
48
41
  this.clock = rp2040.clock;
42
+ this.alarms = [
43
+ new RPTimerAlarm(ALARM_0, this.clock.createAlarm(() => this.fireAlarm(0))),
44
+ new RPTimerAlarm(ALARM_1, this.clock.createAlarm(() => this.fireAlarm(1))),
45
+ new RPTimerAlarm(ALARM_2, this.clock.createAlarm(() => this.fireAlarm(2))),
46
+ new RPTimerAlarm(ALARM_3, this.clock.createAlarm(() => this.fireAlarm(3))),
47
+ ];
49
48
  }
50
49
  get intStatus() {
51
50
  return (this.intRaw & this.intEnable) | this.intForce;
52
51
  }
53
52
  readUint32(offset) {
54
- const time = this.clock.micros;
53
+ const time = this.clock.nanos / 1000;
55
54
  switch (offset) {
56
55
  case TIMEHR:
57
56
  return this.latchedTimeHigh;
@@ -96,11 +95,10 @@ class RPTimer extends peripheral_js_1.BasePeripheral {
96
95
  case ALARM3: {
97
96
  const alarmIndex = (offset - ALARM0) / 4;
98
97
  const alarm = this.alarms[alarmIndex];
99
- const delta = (value - this.clock.micros) >>> 0;
100
- this.disarmAlarm(alarm);
98
+ const deltaMicros = (value - this.clock.nanos / 1000) >>> 0;
101
99
  alarm.armed = true;
102
100
  alarm.targetMicros = value;
103
- alarm.timer = this.clock.createTimer(delta, () => this.fireAlarm(alarmIndex));
101
+ alarm.clockAlarm.schedule(deltaMicros * 1000);
104
102
  break;
105
103
  }
106
104
  case ARMED:
@@ -146,10 +144,7 @@ class RPTimer extends peripheral_js_1.BasePeripheral {
146
144
  }
147
145
  }
148
146
  disarmAlarm(alarm) {
149
- if (alarm.timer) {
150
- this.clock.deleteTimer(alarm.timer);
151
- alarm.timer = null;
152
- }
147
+ alarm.clockAlarm.cancel();
153
148
  alarm.armed = false;
154
149
  }
155
150
  }
@@ -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;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RPUSBController = void 0;
4
4
  const irq_js_1 = require("../irq.js");
5
5
  const peripheral_js_1 = require("./peripheral.js");
6
+ const ENDPOINT_COUNT = 16;
6
7
  // USB DPSRAM Registers
7
8
  const EP1_IN_CONTROL = 0x8;
8
9
  const EP0_IN_BUFFER_CONTROL = 0x80;
@@ -80,20 +81,52 @@ const SIE_WRITECLEAR_MASK = SIE_DATA_SEQ_ERROR |
80
81
  SIE_TRANS_COMPLETE |
81
82
  SIE_SETUP_REC |
82
83
  SIE_RESUME;
84
+ class USBEndpointAlarm {
85
+ constructor(alarm) {
86
+ this.alarm = alarm;
87
+ this.buffers = [];
88
+ }
89
+ schedule(buffer, delayNanos) {
90
+ this.buffers.push(buffer);
91
+ this.alarm.schedule(delayNanos);
92
+ }
93
+ }
83
94
  class RPUSBController extends peripheral_js_1.BasePeripheral {
84
- constructor() {
85
- super(...arguments);
95
+ get intStatus() {
96
+ return (this.intRaw & this.intEnable) | this.intForce;
97
+ }
98
+ constructor(rp2040, name) {
99
+ super(rp2040, name);
86
100
  this.mainCtrl = 0;
87
101
  this.intRaw = 0;
88
102
  this.intEnable = 0;
89
103
  this.intForce = 0;
90
104
  this.sieStatus = 0;
91
105
  this.buffStatus = 0;
92
- this.readDelayMicroseconds = 1;
93
- this.writeDelayMicroseconds = 1;
94
- }
95
- get intStatus() {
96
- return (this.intRaw & this.intEnable) | this.intForce;
106
+ this.readDelayMicroseconds = 10;
107
+ this.writeDelayMicroseconds = 10; // Determined empirically
108
+ const clock = rp2040.clock;
109
+ this.endpointReadAlarms = [];
110
+ this.endpointWriteAlarms = [];
111
+ for (let i = 0; i < ENDPOINT_COUNT; ++i) {
112
+ this.endpointReadAlarms.push(new USBEndpointAlarm(clock.createAlarm(() => {
113
+ const buffer = this.endpointReadAlarms[i].buffers.shift();
114
+ if (buffer) {
115
+ this.finishRead(i, buffer);
116
+ }
117
+ })));
118
+ this.endpointWriteAlarms.push(new USBEndpointAlarm(clock.createAlarm(() => {
119
+ var _a;
120
+ for (const buffer of this.endpointWriteAlarms[i].buffers) {
121
+ (_a = this.onEndpointWrite) === null || _a === void 0 ? void 0 : _a.call(this, i, buffer);
122
+ }
123
+ this.endpointWriteAlarms[i].buffers = [];
124
+ })));
125
+ }
126
+ this.resetAlarm = clock.createAlarm(() => {
127
+ this.sieStatus |= SIE_BUS_RESET;
128
+ this.sieStatusUpdated();
129
+ });
97
130
  }
98
131
  readUint32(offset) {
99
132
  switch (offset) {
@@ -167,7 +200,7 @@ class RPUSBController extends peripheral_js_1.BasePeripheral {
167
200
  return this.readEndpointControlReg(endpoint, out) & 0xffc0;
168
201
  }
169
202
  DPRAMUpdated(offset, value) {
170
- var _a, _b, _c, _d;
203
+ var _a, _b;
171
204
  if (value & USB_BUF_CTRL_AVAILABLE &&
172
205
  offset >= EP0_IN_BUFFER_CONTROL &&
173
206
  offset <= EP15_OUT_BUFFER_CONTROL) {
@@ -180,31 +213,6 @@ class RPUSBController extends peripheral_js_1.BasePeripheral {
180
213
  doubleBuffer = !!(control & USB_CTRL_DOUBLE_BUF);
181
214
  interrupt = !!(control & USB_CTRL_INTERRUPT_PER_TRANSFER);
182
215
  }
183
- const bufferLength = value & USB_BUF_CTRL_LEN_MASK;
184
- const bufferOffset = this.getEndpointBufferOffset(endpoint, bufferOut);
185
- this.debug(`Start USB transfer, endPoint=${endpoint}, direction=${bufferOut ? 'out' : 'in'} buffer=${bufferOffset.toString(16)} length=${bufferLength}`);
186
- value &= ~USB_BUF_CTRL_AVAILABLE;
187
- this.rp2040.usbDPRAMView.setUint32(offset, value, true);
188
- if (bufferOut) {
189
- (_a = this.onEndpointRead) === null || _a === void 0 ? void 0 : _a.call(this, endpoint, bufferLength);
190
- }
191
- else {
192
- value &= ~USB_BUF_CTRL_FULL;
193
- this.rp2040.usbDPRAMView.setUint32(offset, value, true);
194
- const buffer = this.rp2040.usbDPRAM.slice(bufferOffset, bufferOffset + bufferLength);
195
- if (interrupt || !doubleBuffer) {
196
- this.indicateBufferReady(endpoint, false);
197
- }
198
- if (this.writeDelayMicroseconds) {
199
- this.rp2040.clock.createTimer(this.writeDelayMicroseconds, () => {
200
- var _a;
201
- (_a = this.onEndpointWrite) === null || _a === void 0 ? void 0 : _a.call(this, endpoint, buffer);
202
- });
203
- }
204
- else {
205
- (_b = this.onEndpointWrite) === null || _b === void 0 ? void 0 : _b.call(this, endpoint, buffer);
206
- }
207
- }
208
216
  if (doubleBuffer && (value >> USB_BUF1_SHIFT) & USB_BUF_CTRL_AVAILABLE) {
209
217
  const bufferLength = (value >> USB_BUF1_SHIFT) & USB_BUF_CTRL_LEN_MASK;
210
218
  const bufferOffset = this.getEndpointBufferOffset(endpoint, bufferOut) + USB_BUF1_OFFSET;
@@ -212,35 +220,37 @@ class RPUSBController extends peripheral_js_1.BasePeripheral {
212
220
  value &= ~(USB_BUF_CTRL_AVAILABLE << USB_BUF1_SHIFT);
213
221
  this.rp2040.usbDPRAMView.setUint32(offset, value, true);
214
222
  if (bufferOut) {
215
- (_c = this.onEndpointRead) === null || _c === void 0 ? void 0 : _c.call(this, endpoint, bufferLength);
223
+ (_a = this.onEndpointRead) === null || _a === void 0 ? void 0 : _a.call(this, endpoint, bufferLength);
216
224
  }
217
225
  else {
218
226
  value &= ~(USB_BUF_CTRL_FULL << USB_BUF1_SHIFT);
219
227
  this.rp2040.usbDPRAMView.setUint32(offset, value, true);
220
228
  const buffer = this.rp2040.usbDPRAM.slice(bufferOffset, bufferOffset + bufferLength);
221
229
  this.indicateBufferReady(endpoint, false);
222
- if (this.writeDelayMicroseconds) {
223
- this.rp2040.clock.createTimer(this.writeDelayMicroseconds, () => {
224
- var _a;
225
- (_a = this.onEndpointWrite) === null || _a === void 0 ? void 0 : _a.call(this, endpoint, buffer);
226
- });
227
- }
228
- else {
229
- (_d = this.onEndpointWrite) === null || _d === void 0 ? void 0 : _d.call(this, endpoint, buffer);
230
- }
230
+ this.endpointWriteAlarms[endpoint].schedule(buffer, this.writeDelayMicroseconds * 1000);
231
231
  }
232
232
  }
233
+ const bufferLength = value & USB_BUF_CTRL_LEN_MASK;
234
+ const bufferOffset = this.getEndpointBufferOffset(endpoint, bufferOut);
235
+ this.debug(`Start USB transfer, endPoint=${endpoint}, direction=${bufferOut ? 'out' : 'in'} buffer=${bufferOffset.toString(16)} length=${bufferLength}`);
236
+ value &= ~USB_BUF_CTRL_AVAILABLE;
237
+ this.rp2040.usbDPRAMView.setUint32(offset, value, true);
238
+ if (bufferOut) {
239
+ (_b = this.onEndpointRead) === null || _b === void 0 ? void 0 : _b.call(this, endpoint, bufferLength);
240
+ }
241
+ else {
242
+ value &= ~USB_BUF_CTRL_FULL;
243
+ this.rp2040.usbDPRAMView.setUint32(offset, value, true);
244
+ const buffer = this.rp2040.usbDPRAM.slice(bufferOffset, bufferOffset + bufferLength);
245
+ if (interrupt || !doubleBuffer) {
246
+ this.indicateBufferReady(endpoint, false);
247
+ }
248
+ this.endpointWriteAlarms[endpoint].schedule(buffer, this.writeDelayMicroseconds * 1000);
249
+ }
233
250
  }
234
251
  }
235
252
  endpointReadDone(endpoint, buffer, delay = this.readDelayMicroseconds) {
236
- if (delay) {
237
- this.rp2040.clock.createTimer(delay, () => {
238
- this.finishRead(endpoint, buffer);
239
- });
240
- }
241
- else {
242
- this.finishRead(endpoint, buffer);
243
- }
253
+ this.endpointReadAlarms[endpoint].schedule(buffer, delay * 1000);
244
254
  }
245
255
  finishRead(endpoint, buffer) {
246
256
  const bufferOffset = this.getEndpointBufferOffset(endpoint, true);
@@ -259,8 +269,7 @@ class RPUSBController extends peripheral_js_1.BasePeripheral {
259
269
  this.rp2040.setInterrupt(irq_js_1.IRQ.USBCTRL, !!intStatus);
260
270
  }
261
271
  resetDevice() {
262
- this.sieStatus |= SIE_BUS_RESET;
263
- this.sieStatusUpdated();
272
+ this.resetAlarm.schedule(10000000); // USB reset takes ~10ms
264
273
  }
265
274
  sendSetupPacket(setupPacket) {
266
275
  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,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RP2040 = exports.SIO_START_ADDRESS = exports.DPRAM_START_ADDRESS = exports.APB_START_ADDRESS = exports.RAM_START_ADDRESS = exports.FLASH_END_ADDRESS = exports.FLASH_START_ADDRESS = void 0;
4
- const realtime_clock_js_1 = require("./clock/realtime-clock.js");
4
+ const simulation_clock_js_1 = require("./clock/simulation-clock.js");
5
5
  const cortex_m0_core_js_1 = require("./cortex-m0-core.js");
6
6
  const gpio_pin_js_1 = require("./gpio-pin.js");
7
7
  const irq_js_1 = require("./irq.js");
@@ -40,7 +40,7 @@ const KB = 1024;
40
40
  const MB = 1024 * KB;
41
41
  const MHz = 1000000;
42
42
  class RP2040 {
43
- constructor(clock = new realtime_clock_js_1.RealtimeClock()) {
43
+ constructor(clock = new simulation_clock_js_1.SimulationClock()) {
44
44
  this.clock = clock;
45
45
  this.bootrom = new Uint32Array(4 * KB);
46
46
  this.sram = new Uint8Array(264 * KB);
@@ -125,9 +125,7 @@ class RP2040 {
125
125
  tx: dma_js_1.DREQChannel.DREQ_SPI1_TX,
126
126
  }),
127
127
  ];
128
- this.stopped = true;
129
128
  this.logger = new logging_js_1.ConsoleLogger(logging_js_1.LogLevel.Debug, true);
130
- this.executeTimer = null;
131
129
  this.peripherals = {
132
130
  0x18000: new ssi_js_1.RPSSI(this, 'SSI'),
133
131
  0x40000: new sysinfo_js_1.RP2040SysInfo(this, 'SYSINFO_BASE'),
@@ -167,7 +165,6 @@ class RP2040 {
167
165
  this.onBreak = (code) => {
168
166
  // TODO: raise HardFault exception
169
167
  // console.error('Breakpoint!', code);
170
- this.stopped = true;
171
168
  };
172
169
  this.reset();
173
170
  }
@@ -342,27 +339,5 @@ class RP2040 {
342
339
  step() {
343
340
  this.core.executeInstruction();
344
341
  }
345
- execute() {
346
- this.clock.resume();
347
- this.executeTimer = null;
348
- this.stopped = false;
349
- for (let i = 0; i < 100000 && !this.stopped && !this.core.waiting; i++) {
350
- this.core.executeInstruction();
351
- }
352
- if (!this.stopped) {
353
- this.executeTimer = setTimeout(() => this.execute(), 0);
354
- }
355
- }
356
- stop() {
357
- this.stopped = true;
358
- if (this.executeTimer != null) {
359
- clearTimeout(this.executeTimer);
360
- this.executeTimer = null;
361
- }
362
- this.clock.pause();
363
- }
364
- get executing() {
365
- return !this.stopped;
366
- }
367
342
  }
368
343
  exports.RP2040 = RP2040;
@@ -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
+ }