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.
- package/dist/cjs/clock/clock.d.ts +6 -8
- package/dist/cjs/clock/mock-clock.d.ts +2 -15
- package/dist/cjs/clock/mock-clock.js +4 -46
- package/dist/cjs/clock/simulation-clock.d.ts +26 -0
- package/dist/cjs/clock/simulation-clock.js +97 -0
- package/dist/cjs/cortex-m0-core.d.ts +1 -1
- package/dist/cjs/cortex-m0-core.js +39 -37
- package/dist/cjs/gdb/gdb-connection.d.ts +1 -1
- package/dist/cjs/gdb/gdb-connection.js +2 -2
- package/dist/cjs/gdb/gdb-server.d.ts +3 -3
- package/dist/cjs/gdb/gdb-server.js +12 -11
- package/dist/cjs/gdb/gdb-target.d.ts +7 -0
- package/dist/cjs/gdb/gdb-target.js +2 -0
- package/dist/cjs/gdb/gdb-tcp-server.d.ts +2 -2
- package/dist/cjs/gdb/gdb-tcp-server.js +2 -2
- package/dist/cjs/index.d.ts +4 -3
- package/dist/cjs/index.js +7 -5
- package/dist/cjs/peripherals/adc.d.ts +7 -2
- package/dist/cjs/peripherals/adc.js +12 -8
- package/dist/cjs/peripherals/dma.d.ts +1 -1
- package/dist/cjs/peripherals/dma.js +6 -15
- package/dist/cjs/peripherals/rtc.d.ts +1 -1
- package/dist/cjs/peripherals/rtc.js +3 -3
- package/dist/cjs/peripherals/timer.js +12 -17
- package/dist/cjs/peripherals/usb.d.ts +5 -0
- package/dist/cjs/peripherals/usb.js +62 -53
- package/dist/cjs/rp2040.d.ts +0 -5
- package/dist/cjs/rp2040.js +2 -27
- package/dist/cjs/simulator.d.ts +13 -0
- package/dist/cjs/simulator.js +45 -0
- package/dist/cjs/utils/timer32.d.ts +3 -3
- package/dist/cjs/utils/timer32.js +14 -16
- package/dist/esm/clock/clock.d.ts +6 -8
- package/dist/esm/clock/mock-clock.d.ts +2 -15
- package/dist/esm/clock/mock-clock.js +3 -44
- package/dist/esm/clock/simulation-clock.d.ts +26 -0
- package/dist/esm/clock/simulation-clock.js +92 -0
- package/dist/esm/cortex-m0-core.d.ts +1 -1
- package/dist/esm/cortex-m0-core.js +39 -37
- package/dist/esm/gdb/gdb-connection.d.ts +1 -1
- package/dist/esm/gdb/gdb-connection.js +2 -2
- package/dist/esm/gdb/gdb-server.d.ts +3 -3
- package/dist/esm/gdb/gdb-server.js +12 -11
- package/dist/esm/gdb/gdb-target.d.ts +7 -0
- package/dist/esm/gdb/gdb-target.js +1 -0
- package/dist/esm/gdb/gdb-tcp-server.d.ts +2 -2
- package/dist/esm/gdb/gdb-tcp-server.js +2 -2
- package/dist/esm/index.d.ts +4 -3
- package/dist/esm/index.js +2 -1
- package/dist/esm/peripherals/adc.d.ts +7 -2
- package/dist/esm/peripherals/adc.js +12 -8
- package/dist/esm/peripherals/dma.d.ts +1 -1
- package/dist/esm/peripherals/dma.js +6 -15
- package/dist/esm/peripherals/rtc.d.ts +1 -1
- package/dist/esm/peripherals/rtc.js +3 -3
- package/dist/esm/peripherals/timer.js +12 -17
- package/dist/esm/peripherals/usb.d.ts +5 -0
- package/dist/esm/peripherals/usb.js +62 -53
- package/dist/esm/rp2040.d.ts +0 -5
- package/dist/esm/rp2040.js +2 -27
- package/dist/esm/simulator.d.ts +13 -0
- package/dist/esm/simulator.js +41 -0
- package/dist/esm/utils/timer32.d.ts +3 -3
- package/dist/esm/utils/timer32.js +14 -16
- package/package.json +1 -1
- package/dist/cjs/clock/realtime-clock.d.ts +0 -23
- package/dist/cjs/clock/realtime-clock.js +0 -73
- package/dist/esm/clock/realtime-clock.d.ts +0 -23
- 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.
|
|
46
|
+
this.baselineNanos = 0;
|
|
47
47
|
}
|
|
48
48
|
readUint32(offset) {
|
|
49
|
-
const date = new Date(this.baseline.getTime() + (this.rp2040.clock.
|
|
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.
|
|
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(
|
|
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.
|
|
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
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
82
|
-
|
|
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 =
|
|
90
|
-
this.writeDelayMicroseconds =
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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
|
|
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
|
-
(
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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);
|
package/dist/esm/rp2040.d.ts
CHANGED
|
@@ -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
|
}
|
package/dist/esm/rp2040.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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,
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
87
|
+
toNanos(cycles) {
|
|
88
88
|
const { baseFreq, prescalerValue } = this;
|
|
89
|
-
return (cycles *
|
|
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.
|
|
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
|
|
195
|
-
this.
|
|
195
|
+
const nanosToAlarm = timer.toNanos(cyclesToAlarm);
|
|
196
|
+
this.clockAlarm.schedule(nanosToAlarm);
|
|
196
197
|
}
|
|
197
198
|
cancel() {
|
|
198
|
-
|
|
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,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
|
-
}
|