rp2040js 0.14.5 → 0.14.9

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/README.md CHANGED
@@ -19,6 +19,7 @@ If you want to develop your own application using the Raspberry Pi Pico simulato
19
19
 
20
20
  ## Run the demo project
21
21
 
22
+ ### Native code
22
23
  You'd need to get `hello_uart.hex` by building it from the [pico-examples repo](https://github.com/raspberrypi/pico-examples/tree/master/uart/hello_uart), then copy it to the rp2040js root directory and run:
23
24
 
24
25
  ```
@@ -26,16 +27,37 @@ npm install
26
27
  npm start
27
28
  ```
28
29
 
29
- To run the micropython demo, first download [rp2-pico-20210902-v1.17.uf2](https://micropython.org/resources/firmware/rp2-pico-20210902-v1.17.uf2), place it in the rp2040js root directory, then run:
30
+ ### MicroPython code
31
+ To run the MicroPython demo, first download [rp2-pico-20210902-v1.17.uf2](https://micropython.org/resources/firmware/rp2-pico-20210902-v1.17.uf2), place it in the rp2040js root directory, then run:
30
32
 
31
33
  ```
32
34
  npm install
33
35
  npm run start:micropython
34
36
  ```
35
37
 
36
- and enjoy the MicroPython REPL! Quit the REPL with Ctrl+D.
38
+ and enjoy the MicroPython REPL! Quit the REPL with Ctrl+X.
37
39
 
38
- You can replace rp2-pico-20210902-v1.17.uf2 any recent MicroPython or CircuitPython release built for the RP2040.
40
+ You can replace rp2-pico-20210902-v1.17.uf2 with any recent MicroPython or CircuitPython release built for the RP2040.
41
+
42
+ With MicroPython – and probably also CircuitPython – you can use the filesystem on the Pico. This becomes useful as more than one script file is used in your code. Just put a [LittleFS](https://github.com/littlefs-project/littlefs) formatted filesystem image called `littlefs.img` into the rp2040js root directory, and your `main.py` will be automatically started from there.
43
+
44
+ A simple way to create a suitable LittleFS image containing your script files is outlined in [create_littlefs_image.py](https://github.com/tomods/GrinderController/blob/358ad3e0f795d8cc0bdf4f21bb35f806871d433f/tools/create_littlefs_image.py).
45
+ So, using [littlefs-python](https://pypi.org/project/littlefs-python/), you can do the following:
46
+ ```python
47
+ from littlefs import LittleFS
48
+ files = ['your.py', 'files.py', 'here.py', 'main.py']
49
+ output_image = 'output/littlefs.img' # symlinked/copied to rp2040js root directory
50
+ lfs = LittleFS(block_size=4096, block_count=352, prog_size=256)
51
+ for filename in files:
52
+ with open(filename, 'rb') as src_file, lfs.open(filename, 'w') as lfs_file:
53
+ lfs_file.write(src_file.read())
54
+ with open(output_image, 'wb') as fh:
55
+ fh.write(lfs.context.buffer)
56
+ ```
57
+
58
+ Other ways of creating LittleFS images can be found [here](https://github.com/wokwi/littlefs-wasm) or [here](https://github.com/littlefs-project/littlefs#related-projects).
59
+
60
+ Currently, the filesystem is not writeable, as the SSI peripheral required for flash writing is not implemented yet. If you're interested in hacking, see the discussion in https://github.com/wokwi/rp2040js/issues/88 for a workaround.
39
61
 
40
62
  ## Learn more
41
63
 
@@ -1,5 +1,6 @@
1
1
  import { RP2040 } from '../rp2040';
2
2
  import { FIFO } from '../utils/fifo';
3
+ import { DREQChannel } from './dma';
3
4
  import { BasePeripheral, Peripheral } from './peripheral';
4
5
  export declare class RPADC extends BasePeripheral implements Peripheral {
5
6
  readonly numChannels = 5;
@@ -25,6 +26,7 @@ export declare class RPADC extends BasePeripheral implements Peripheral {
25
26
  */
26
27
  onADCRead: (channel: number) => void;
27
28
  readonly fifo: FIFO;
29
+ readonly dreq = DREQChannel.DREQ_ADC;
28
30
  cs: number;
29
31
  fcs: number;
30
32
  clockDiv: number;
@@ -43,6 +45,7 @@ export declare class RPADC extends BasePeripheral implements Peripheral {
43
45
  constructor(rp2040: RP2040, name: string);
44
46
  checkInterrupts(): void;
45
47
  startADCRead(): void;
48
+ private updateDMA;
46
49
  completeADCRead(value: number, error: boolean): void;
47
50
  readUint32(offset: number): number;
48
51
  writeUint32(offset: number, value: number): void;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RPADC = void 0;
4
4
  const irq_1 = require("../irq");
5
5
  const fifo_1 = require("../utils/fifo");
6
+ const dma_1 = require("./dma");
6
7
  const peripheral_1 = require("./peripheral");
7
8
  const CS = 0x00; // ADC Control and Status
8
9
  const RESULT = 0x04; // Result of most recent ADC conversion
@@ -84,6 +85,7 @@ class RPADC extends peripheral_1.BasePeripheral {
84
85
  this.rp2040.clock.createTimer(this.sampleTime, () => this.completeADCRead(this.channelValues[channel], false));
85
86
  };
86
87
  this.fifo = new fifo_1.FIFO(4);
88
+ this.dreq = dma_1.DREQChannel.DREQ_ADC;
87
89
  // Registers
88
90
  this.cs = 0;
89
91
  this.fcs = 0;
@@ -127,6 +129,17 @@ class RPADC extends peripheral_1.BasePeripheral {
127
129
  this.busy = true;
128
130
  this.onADCRead(this.activeChannel);
129
131
  }
132
+ updateDMA() {
133
+ if (this.fcs & FCS_DREQ_EN) {
134
+ const thres = (this.fcs >> FCS_THRESH_SHIFT) & FCS_THRES_MASK;
135
+ if (this.fifo.itemCount >= thres) {
136
+ this.rp2040.dma.setDREQ(this.dreq);
137
+ }
138
+ else {
139
+ this.rp2040.dma.clearDREQ(this.dreq);
140
+ }
141
+ }
142
+ }
130
143
  completeADCRead(value, error) {
131
144
  this.busy = false;
132
145
  this.result = value;
@@ -150,6 +163,7 @@ class RPADC extends peripheral_1.BasePeripheral {
150
163
  value |= FIFO_ERR;
151
164
  }
152
165
  this.fifo.push(value);
166
+ this.updateDMA();
153
167
  this.checkInterrupts();
154
168
  }
155
169
  }
@@ -197,7 +211,9 @@ class RPADC extends peripheral_1.BasePeripheral {
197
211
  return 0;
198
212
  }
199
213
  else {
200
- return this.fifo.pull();
214
+ const value = this.fifo.pull();
215
+ this.updateDMA();
216
+ return value;
201
217
  }
202
218
  case DIV:
203
219
  return this.clockDiv;
@@ -35,7 +35,7 @@ export declare class RPI2C extends BasePeripheral implements Peripheral {
35
35
  intEnable: number;
36
36
  get intStatus(): number;
37
37
  get speed(): I2CSpeed;
38
- get masterBits(): 7 | 10;
38
+ get masterBits(): 10 | 7;
39
39
  constructor(rp2040: RP2040, name: string, irq: number);
40
40
  checkInterrupts(): void;
41
41
  protected clearInterrupts(mask: number): 0 | 1;
@@ -75,11 +75,11 @@ var WaitType;
75
75
  WaitType[WaitType["Out"] = 5] = "Out";
76
76
  })(WaitType = exports.WaitType || (exports.WaitType = {}));
77
77
  function bitReverse(x) {
78
- x = ((x & 0x55555555) << 1) | ((x & 0xaaaaaaaa) >> 1);
79
- x = ((x & 0x33333333) << 2) | ((x & 0xcccccccc) >> 2);
80
- x = ((x & 0x0f0f0f0f) << 4) | ((x & 0xf0f0f0f0) >> 4);
81
- x = ((x & 0x00ff00ff) << 8) | ((x & 0xff00ff00) >> 8);
82
- x = ((x & 0x0000ffff) << 16) | ((x & 0xffff0000) >> 16);
78
+ x = ((x & 0x55555555) << 1) | ((x & 0xaaaaaaaa) >>> 1);
79
+ x = ((x & 0x33333333) << 2) | ((x & 0xcccccccc) >>> 2);
80
+ x = ((x & 0x0f0f0f0f) << 4) | ((x & 0xf0f0f0f0) >>> 4);
81
+ x = ((x & 0x00ff00ff) << 8) | ((x & 0xff00ff00) >>> 8);
82
+ x = ((x & 0x0000ffff) << 16) | ((x & 0xffff0000) >>> 16);
83
83
  return x >>> 0;
84
84
  }
85
85
  function irqIndex(irq, machineIndex) {
@@ -1,5 +1,7 @@
1
1
  import { IClockTimer } from '../clock/clock';
2
2
  import { BasePeripheral, Peripheral } from './peripheral';
3
+ export declare const CPUID = 3328;
4
+ export declare const ICSR = 3332;
3
5
  export declare const VTOR = 3336;
4
6
  export declare const SHPR2 = 3356;
5
7
  export declare const SHPR3 = 3360;
@@ -1,8 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RPPPB = exports.SHPR3 = exports.SHPR2 = exports.VTOR = void 0;
3
+ exports.RPPPB = exports.SHPR3 = exports.SHPR2 = exports.VTOR = exports.ICSR = exports.CPUID = void 0;
4
4
  const irq_1 = require("../irq");
5
5
  const peripheral_1 = require("./peripheral");
6
+ exports.CPUID = 0xd00;
7
+ exports.ICSR = 0xd04;
6
8
  exports.VTOR = 0xd08;
7
9
  exports.SHPR2 = 0xd1c;
8
10
  exports.SHPR3 = 0xd20;
@@ -23,6 +25,18 @@ const NVIC_IPR4 = 0x410;
23
25
  const NVIC_IPR5 = 0x414;
24
26
  const NVIC_IPR6 = 0x418;
25
27
  const NVIC_IPR7 = 0x41c;
28
+ /** ICSR Bits */
29
+ const NMIPENDSET = 1 << 31;
30
+ const PENDSVSET = 1 << 28;
31
+ const PENDSVCLR = 1 << 27;
32
+ const PENDSTSET = 1 << 26;
33
+ const PENDSTCLR = 1 << 25;
34
+ const ISRPREEMPT = 1 << 23;
35
+ const ISRPENDING = 1 << 22;
36
+ const VECTPENDING_MASK = 0x1ff;
37
+ const VECTPENDING_SHIFT = 12;
38
+ const VECTACTIVE_MASK = 0x1ff;
39
+ const VECTACTIVE_SHIFT = 0;
26
40
  /** PPB stands for Private Periphral Bus.
27
41
  * These are peripherals that are part of the ARM Cortex Core, and there's one copy for each processor core.
28
42
  *
@@ -41,6 +55,21 @@ class RPPPB extends peripheral_1.BasePeripheral {
41
55
  readUint32(offset) {
42
56
  const { rp2040 } = this;
43
57
  switch (offset) {
58
+ case exports.CPUID:
59
+ return 0x410cc601; /* Verified against actual hardware */
60
+ case exports.ICSR: {
61
+ const pendingInterrupts = this.rp2040.pendingInterrupts ||
62
+ this.rp2040.pendingPendSV ||
63
+ this.rp2040.pendingSystick ||
64
+ this.rp2040.pendingSVCall;
65
+ const vectPending = this.rp2040.vectPending;
66
+ return ((this.rp2040.pendingNMI ? NMIPENDSET : 0) |
67
+ (this.rp2040.pendingPendSV ? PENDSVSET : 0) |
68
+ (this.rp2040.pendingSystick ? PENDSTSET : 0) |
69
+ (pendingInterrupts ? ISRPENDING : 0) |
70
+ (vectPending << VECTPENDING_SHIFT) |
71
+ ((this.rp2040.IPSR & VECTACTIVE_MASK) << VECTACTIVE_SHIFT));
72
+ }
44
73
  case exports.VTOR:
45
74
  return rp2040.VTOR;
46
75
  /* NVIC */
@@ -100,6 +129,26 @@ class RPPPB extends peripheral_1.BasePeripheral {
100
129
  const { rp2040 } = this;
101
130
  const hardwareInterruptMask = (1 << irq_1.MAX_HARDWARE_IRQ) - 1;
102
131
  switch (offset) {
132
+ case exports.ICSR:
133
+ if (value & NMIPENDSET) {
134
+ this.rp2040.pendingNMI = true;
135
+ rp2040.interruptsUpdated = true;
136
+ }
137
+ if (value & PENDSVSET) {
138
+ this.rp2040.pendingPendSV = true;
139
+ rp2040.interruptsUpdated = true;
140
+ }
141
+ if (value & PENDSVCLR) {
142
+ this.rp2040.pendingPendSV = false;
143
+ }
144
+ if (value & PENDSTSET) {
145
+ this.rp2040.pendingSystick = true;
146
+ rp2040.interruptsUpdated = true;
147
+ }
148
+ if (value & PENDSTCLR) {
149
+ this.rp2040.pendingSystick = false;
150
+ }
151
+ return;
103
152
  case exports.VTOR:
104
153
  rp2040.VTOR = value;
105
154
  return;
@@ -16,7 +16,7 @@ export declare class RPUART extends BasePeripheral implements Peripheral {
16
16
  /**
17
17
  * Number of bits per UART character
18
18
  */
19
- get wordLength(): 8 | 7 | 5 | 6 | undefined;
19
+ get wordLength(): 8 | 6 | 5 | 7 | undefined;
20
20
  get flags(): number;
21
21
  checkInterrupts(): void;
22
22
  feedByte(value: number): void;
@@ -74,6 +74,8 @@ export declare class RP2040 {
74
74
  pendingInterrupts: number;
75
75
  enabledInterrupts: number;
76
76
  interruptPriorities: number[];
77
+ pendingNMI: boolean;
78
+ pendingPendSV: boolean;
77
79
  pendingSVCall: boolean;
78
80
  pendingSystick: boolean;
79
81
  interruptsUpdated: boolean;
@@ -114,10 +116,12 @@ export declare class RP2040 {
114
116
  set SPmain(value: number);
115
117
  exceptionEntry(exceptionNumber: number): void;
116
118
  exceptionReturn(excReturn: number): void;
119
+ get pendSVPriority(): number;
117
120
  get svCallPriority(): number;
118
121
  get systickPriority(): number;
119
122
  get gpioValues(): number;
120
123
  exceptionPriority(n: number): number;
124
+ get vectPending(): number;
121
125
  setInterrupt(irq: number, value: boolean): void;
122
126
  checkForInterrupts(): boolean;
123
127
  updateIOInterrupt(): void;
@@ -162,6 +162,8 @@ class RP2040 {
162
162
  this.pendingInterrupts = 0;
163
163
  this.enabledInterrupts = 0;
164
164
  this.interruptPriorities = [0xffffffff, 0x0, 0x0, 0x0];
165
+ this.pendingNMI = false;
166
+ this.pendingPendSV = false;
165
167
  this.pendingSVCall = false;
166
168
  this.pendingSystick = false;
167
169
  this.interruptsUpdated = false;
@@ -542,6 +544,9 @@ class RP2040 {
542
544
  // if CurrentMode == Mode_Thread && SCR.SLEEPONEXIT == '1' then
543
545
  // SleepOnExit(); // IMPLEMENTATION DEFINED
544
546
  }
547
+ get pendSVPriority() {
548
+ return (this.SHPR3 >> 22) & 0x3;
549
+ }
545
550
  get svCallPriority() {
546
551
  return this.SHPR2 >>> 30;
547
552
  }
@@ -569,9 +574,9 @@ class RP2040 {
569
574
  case EXC_SVCALL:
570
575
  return this.svCallPriority;
571
576
  case EXC_PENDSV:
572
- return (this.readUint32(this.SHPR3) >> 22) & 0x3;
577
+ return this.pendSVPriority;
573
578
  case EXC_SYSTICK:
574
- return this.readUint32(this.SHPR3) >>> 30;
579
+ return this.systickPriority;
575
580
  default: {
576
581
  if (n < 16) {
577
582
  return LOWEST_PRIORITY;
@@ -586,6 +591,32 @@ class RP2040 {
586
591
  }
587
592
  }
588
593
  }
594
+ get vectPending() {
595
+ if (this.pendingNMI) {
596
+ return EXC_NMI;
597
+ }
598
+ const { svCallPriority, systickPriority, pendSVPriority, pendingInterrupts } = this;
599
+ for (let priority = 0; priority < LOWEST_PRIORITY; priority++) {
600
+ const levelInterrupts = pendingInterrupts & this.interruptPriorities[priority];
601
+ if (this.pendingSVCall && priority === svCallPriority) {
602
+ return EXC_SVCALL;
603
+ }
604
+ if (this.pendingPendSV && priority === pendSVPriority) {
605
+ return EXC_PENDSV;
606
+ }
607
+ if (this.pendingSystick && priority === systickPriority) {
608
+ return EXC_SYSTICK;
609
+ }
610
+ if (levelInterrupts) {
611
+ for (let interruptNumber = 0; interruptNumber < 32; interruptNumber++) {
612
+ if (levelInterrupts & (1 << interruptNumber)) {
613
+ return 16 + interruptNumber;
614
+ }
615
+ }
616
+ }
617
+ }
618
+ return 0;
619
+ }
589
620
  setInterrupt(irq, value) {
590
621
  const irqBit = 1 << irq;
591
622
  if (value && !(this.pendingInterrupts & irqBit)) {
@@ -611,7 +642,12 @@ class RP2040 {
611
642
  : LOWEST_PRIORITY
612
643
  : Math.min(this.exceptionPriority(this.IPSR), this.PM ? 0 : LOWEST_PRIORITY);
613
644
  const interruptSet = this.pendingInterrupts & this.enabledInterrupts;
614
- const { svCallPriority, systickPriority } = this;
645
+ const { svCallPriority, systickPriority, pendSVPriority } = this;
646
+ if (this.pendingNMI) {
647
+ this.pendingNMI = false;
648
+ this.exceptionEntry(EXC_NMI);
649
+ return true;
650
+ }
615
651
  for (let priority = 0; priority < currentPriority; priority++) {
616
652
  const levelInterrupts = interruptSet & this.interruptPriorities[priority];
617
653
  if (this.pendingSVCall && priority === svCallPriority) {
@@ -619,6 +655,11 @@ class RP2040 {
619
655
  this.exceptionEntry(EXC_SVCALL);
620
656
  return true;
621
657
  }
658
+ if (this.pendingPendSV && priority === pendSVPriority) {
659
+ this.pendingPendSV = false;
660
+ this.exceptionEntry(EXC_PENDSV);
661
+ return true;
662
+ }
622
663
  if (this.pendingSystick && priority === systickPriority) {
623
664
  this.pendingSystick = false;
624
665
  this.exceptionEntry(EXC_SYSTICK);
@@ -1 +1 @@
1
- {"type":"esm"}
1
+ {"type":"module"}
@@ -1,5 +1,6 @@
1
1
  import { RP2040 } from '../rp2040';
2
2
  import { FIFO } from '../utils/fifo';
3
+ import { DREQChannel } from './dma';
3
4
  import { BasePeripheral, Peripheral } from './peripheral';
4
5
  export declare class RPADC extends BasePeripheral implements Peripheral {
5
6
  readonly numChannels = 5;
@@ -25,6 +26,7 @@ export declare class RPADC extends BasePeripheral implements Peripheral {
25
26
  */
26
27
  onADCRead: (channel: number) => void;
27
28
  readonly fifo: FIFO;
29
+ readonly dreq = DREQChannel.DREQ_ADC;
28
30
  cs: number;
29
31
  fcs: number;
30
32
  clockDiv: number;
@@ -43,6 +45,7 @@ export declare class RPADC extends BasePeripheral implements Peripheral {
43
45
  constructor(rp2040: RP2040, name: string);
44
46
  checkInterrupts(): void;
45
47
  startADCRead(): void;
48
+ private updateDMA;
46
49
  completeADCRead(value: number, error: boolean): void;
47
50
  readUint32(offset: number): number;
48
51
  writeUint32(offset: number, value: number): void;
@@ -1,5 +1,6 @@
1
1
  import { IRQ } from '../irq';
2
2
  import { FIFO } from '../utils/fifo';
3
+ import { DREQChannel } from './dma';
3
4
  import { BasePeripheral } from './peripheral';
4
5
  const CS = 0x00; // ADC Control and Status
5
6
  const RESULT = 0x04; // Result of most recent ADC conversion
@@ -81,6 +82,7 @@ export class RPADC extends BasePeripheral {
81
82
  this.rp2040.clock.createTimer(this.sampleTime, () => this.completeADCRead(this.channelValues[channel], false));
82
83
  };
83
84
  this.fifo = new FIFO(4);
85
+ this.dreq = DREQChannel.DREQ_ADC;
84
86
  // Registers
85
87
  this.cs = 0;
86
88
  this.fcs = 0;
@@ -124,6 +126,17 @@ export class RPADC extends BasePeripheral {
124
126
  this.busy = true;
125
127
  this.onADCRead(this.activeChannel);
126
128
  }
129
+ updateDMA() {
130
+ if (this.fcs & FCS_DREQ_EN) {
131
+ const thres = (this.fcs >> FCS_THRESH_SHIFT) & FCS_THRES_MASK;
132
+ if (this.fifo.itemCount >= thres) {
133
+ this.rp2040.dma.setDREQ(this.dreq);
134
+ }
135
+ else {
136
+ this.rp2040.dma.clearDREQ(this.dreq);
137
+ }
138
+ }
139
+ }
127
140
  completeADCRead(value, error) {
128
141
  this.busy = false;
129
142
  this.result = value;
@@ -147,6 +160,7 @@ export class RPADC extends BasePeripheral {
147
160
  value |= FIFO_ERR;
148
161
  }
149
162
  this.fifo.push(value);
163
+ this.updateDMA();
150
164
  this.checkInterrupts();
151
165
  }
152
166
  }
@@ -194,7 +208,9 @@ export class RPADC extends BasePeripheral {
194
208
  return 0;
195
209
  }
196
210
  else {
197
- return this.fifo.pull();
211
+ const value = this.fifo.pull();
212
+ this.updateDMA();
213
+ return value;
198
214
  }
199
215
  case DIV:
200
216
  return this.clockDiv;
@@ -35,7 +35,7 @@ export declare class RPI2C extends BasePeripheral implements Peripheral {
35
35
  intEnable: number;
36
36
  get intStatus(): number;
37
37
  get speed(): I2CSpeed;
38
- get masterBits(): 7 | 10;
38
+ get masterBits(): 10 | 7;
39
39
  constructor(rp2040: RP2040, name: string, irq: number);
40
40
  checkInterrupts(): void;
41
41
  protected clearInterrupts(mask: number): 0 | 1;
@@ -72,11 +72,11 @@ export var WaitType;
72
72
  WaitType[WaitType["Out"] = 5] = "Out";
73
73
  })(WaitType || (WaitType = {}));
74
74
  function bitReverse(x) {
75
- x = ((x & 0x55555555) << 1) | ((x & 0xaaaaaaaa) >> 1);
76
- x = ((x & 0x33333333) << 2) | ((x & 0xcccccccc) >> 2);
77
- x = ((x & 0x0f0f0f0f) << 4) | ((x & 0xf0f0f0f0) >> 4);
78
- x = ((x & 0x00ff00ff) << 8) | ((x & 0xff00ff00) >> 8);
79
- x = ((x & 0x0000ffff) << 16) | ((x & 0xffff0000) >> 16);
75
+ x = ((x & 0x55555555) << 1) | ((x & 0xaaaaaaaa) >>> 1);
76
+ x = ((x & 0x33333333) << 2) | ((x & 0xcccccccc) >>> 2);
77
+ x = ((x & 0x0f0f0f0f) << 4) | ((x & 0xf0f0f0f0) >>> 4);
78
+ x = ((x & 0x00ff00ff) << 8) | ((x & 0xff00ff00) >>> 8);
79
+ x = ((x & 0x0000ffff) << 16) | ((x & 0xffff0000) >>> 16);
80
80
  return x >>> 0;
81
81
  }
82
82
  function irqIndex(irq, machineIndex) {
@@ -1,5 +1,7 @@
1
1
  import { IClockTimer } from '../clock/clock';
2
2
  import { BasePeripheral, Peripheral } from './peripheral';
3
+ export declare const CPUID = 3328;
4
+ export declare const ICSR = 3332;
3
5
  export declare const VTOR = 3336;
4
6
  export declare const SHPR2 = 3356;
5
7
  export declare const SHPR3 = 3360;
@@ -1,5 +1,7 @@
1
1
  import { MAX_HARDWARE_IRQ } from '../irq';
2
2
  import { BasePeripheral } from './peripheral';
3
+ export const CPUID = 0xd00;
4
+ export const ICSR = 0xd04;
3
5
  export const VTOR = 0xd08;
4
6
  export const SHPR2 = 0xd1c;
5
7
  export const SHPR3 = 0xd20;
@@ -20,6 +22,18 @@ const NVIC_IPR4 = 0x410;
20
22
  const NVIC_IPR5 = 0x414;
21
23
  const NVIC_IPR6 = 0x418;
22
24
  const NVIC_IPR7 = 0x41c;
25
+ /** ICSR Bits */
26
+ const NMIPENDSET = 1 << 31;
27
+ const PENDSVSET = 1 << 28;
28
+ const PENDSVCLR = 1 << 27;
29
+ const PENDSTSET = 1 << 26;
30
+ const PENDSTCLR = 1 << 25;
31
+ const ISRPREEMPT = 1 << 23;
32
+ const ISRPENDING = 1 << 22;
33
+ const VECTPENDING_MASK = 0x1ff;
34
+ const VECTPENDING_SHIFT = 12;
35
+ const VECTACTIVE_MASK = 0x1ff;
36
+ const VECTACTIVE_SHIFT = 0;
23
37
  /** PPB stands for Private Periphral Bus.
24
38
  * These are peripherals that are part of the ARM Cortex Core, and there's one copy for each processor core.
25
39
  *
@@ -38,6 +52,21 @@ export class RPPPB extends BasePeripheral {
38
52
  readUint32(offset) {
39
53
  const { rp2040 } = this;
40
54
  switch (offset) {
55
+ case CPUID:
56
+ return 0x410cc601; /* Verified against actual hardware */
57
+ case ICSR: {
58
+ const pendingInterrupts = this.rp2040.pendingInterrupts ||
59
+ this.rp2040.pendingPendSV ||
60
+ this.rp2040.pendingSystick ||
61
+ this.rp2040.pendingSVCall;
62
+ const vectPending = this.rp2040.vectPending;
63
+ return ((this.rp2040.pendingNMI ? NMIPENDSET : 0) |
64
+ (this.rp2040.pendingPendSV ? PENDSVSET : 0) |
65
+ (this.rp2040.pendingSystick ? PENDSTSET : 0) |
66
+ (pendingInterrupts ? ISRPENDING : 0) |
67
+ (vectPending << VECTPENDING_SHIFT) |
68
+ ((this.rp2040.IPSR & VECTACTIVE_MASK) << VECTACTIVE_SHIFT));
69
+ }
41
70
  case VTOR:
42
71
  return rp2040.VTOR;
43
72
  /* NVIC */
@@ -97,6 +126,26 @@ export class RPPPB extends BasePeripheral {
97
126
  const { rp2040 } = this;
98
127
  const hardwareInterruptMask = (1 << MAX_HARDWARE_IRQ) - 1;
99
128
  switch (offset) {
129
+ case ICSR:
130
+ if (value & NMIPENDSET) {
131
+ this.rp2040.pendingNMI = true;
132
+ rp2040.interruptsUpdated = true;
133
+ }
134
+ if (value & PENDSVSET) {
135
+ this.rp2040.pendingPendSV = true;
136
+ rp2040.interruptsUpdated = true;
137
+ }
138
+ if (value & PENDSVCLR) {
139
+ this.rp2040.pendingPendSV = false;
140
+ }
141
+ if (value & PENDSTSET) {
142
+ this.rp2040.pendingSystick = true;
143
+ rp2040.interruptsUpdated = true;
144
+ }
145
+ if (value & PENDSTCLR) {
146
+ this.rp2040.pendingSystick = false;
147
+ }
148
+ return;
100
149
  case VTOR:
101
150
  rp2040.VTOR = value;
102
151
  return;
@@ -16,7 +16,7 @@ export declare class RPUART extends BasePeripheral implements Peripheral {
16
16
  /**
17
17
  * Number of bits per UART character
18
18
  */
19
- get wordLength(): 8 | 7 | 5 | 6 | undefined;
19
+ get wordLength(): 8 | 6 | 5 | 7 | undefined;
20
20
  get flags(): number;
21
21
  checkInterrupts(): void;
22
22
  feedByte(value: number): void;
@@ -74,6 +74,8 @@ export declare class RP2040 {
74
74
  pendingInterrupts: number;
75
75
  enabledInterrupts: number;
76
76
  interruptPriorities: number[];
77
+ pendingNMI: boolean;
78
+ pendingPendSV: boolean;
77
79
  pendingSVCall: boolean;
78
80
  pendingSystick: boolean;
79
81
  interruptsUpdated: boolean;
@@ -114,10 +116,12 @@ export declare class RP2040 {
114
116
  set SPmain(value: number);
115
117
  exceptionEntry(exceptionNumber: number): void;
116
118
  exceptionReturn(excReturn: number): void;
119
+ get pendSVPriority(): number;
117
120
  get svCallPriority(): number;
118
121
  get systickPriority(): number;
119
122
  get gpioValues(): number;
120
123
  exceptionPriority(n: number): number;
124
+ get vectPending(): number;
121
125
  setInterrupt(irq: number, value: boolean): void;
122
126
  checkForInterrupts(): boolean;
123
127
  updateIOInterrupt(): void;
@@ -159,6 +159,8 @@ export class RP2040 {
159
159
  this.pendingInterrupts = 0;
160
160
  this.enabledInterrupts = 0;
161
161
  this.interruptPriorities = [0xffffffff, 0x0, 0x0, 0x0];
162
+ this.pendingNMI = false;
163
+ this.pendingPendSV = false;
162
164
  this.pendingSVCall = false;
163
165
  this.pendingSystick = false;
164
166
  this.interruptsUpdated = false;
@@ -539,6 +541,9 @@ export class RP2040 {
539
541
  // if CurrentMode == Mode_Thread && SCR.SLEEPONEXIT == '1' then
540
542
  // SleepOnExit(); // IMPLEMENTATION DEFINED
541
543
  }
544
+ get pendSVPriority() {
545
+ return (this.SHPR3 >> 22) & 0x3;
546
+ }
542
547
  get svCallPriority() {
543
548
  return this.SHPR2 >>> 30;
544
549
  }
@@ -566,9 +571,9 @@ export class RP2040 {
566
571
  case EXC_SVCALL:
567
572
  return this.svCallPriority;
568
573
  case EXC_PENDSV:
569
- return (this.readUint32(this.SHPR3) >> 22) & 0x3;
574
+ return this.pendSVPriority;
570
575
  case EXC_SYSTICK:
571
- return this.readUint32(this.SHPR3) >>> 30;
576
+ return this.systickPriority;
572
577
  default: {
573
578
  if (n < 16) {
574
579
  return LOWEST_PRIORITY;
@@ -583,6 +588,32 @@ export class RP2040 {
583
588
  }
584
589
  }
585
590
  }
591
+ get vectPending() {
592
+ if (this.pendingNMI) {
593
+ return EXC_NMI;
594
+ }
595
+ const { svCallPriority, systickPriority, pendSVPriority, pendingInterrupts } = this;
596
+ for (let priority = 0; priority < LOWEST_PRIORITY; priority++) {
597
+ const levelInterrupts = pendingInterrupts & this.interruptPriorities[priority];
598
+ if (this.pendingSVCall && priority === svCallPriority) {
599
+ return EXC_SVCALL;
600
+ }
601
+ if (this.pendingPendSV && priority === pendSVPriority) {
602
+ return EXC_PENDSV;
603
+ }
604
+ if (this.pendingSystick && priority === systickPriority) {
605
+ return EXC_SYSTICK;
606
+ }
607
+ if (levelInterrupts) {
608
+ for (let interruptNumber = 0; interruptNumber < 32; interruptNumber++) {
609
+ if (levelInterrupts & (1 << interruptNumber)) {
610
+ return 16 + interruptNumber;
611
+ }
612
+ }
613
+ }
614
+ }
615
+ return 0;
616
+ }
586
617
  setInterrupt(irq, value) {
587
618
  const irqBit = 1 << irq;
588
619
  if (value && !(this.pendingInterrupts & irqBit)) {
@@ -608,7 +639,12 @@ export class RP2040 {
608
639
  : LOWEST_PRIORITY
609
640
  : Math.min(this.exceptionPriority(this.IPSR), this.PM ? 0 : LOWEST_PRIORITY);
610
641
  const interruptSet = this.pendingInterrupts & this.enabledInterrupts;
611
- const { svCallPriority, systickPriority } = this;
642
+ const { svCallPriority, systickPriority, pendSVPriority } = this;
643
+ if (this.pendingNMI) {
644
+ this.pendingNMI = false;
645
+ this.exceptionEntry(EXC_NMI);
646
+ return true;
647
+ }
612
648
  for (let priority = 0; priority < currentPriority; priority++) {
613
649
  const levelInterrupts = interruptSet & this.interruptPriorities[priority];
614
650
  if (this.pendingSVCall && priority === svCallPriority) {
@@ -616,6 +652,11 @@ export class RP2040 {
616
652
  this.exceptionEntry(EXC_SVCALL);
617
653
  return true;
618
654
  }
655
+ if (this.pendingPendSV && priority === pendSVPriority) {
656
+ this.pendingPendSV = false;
657
+ this.exceptionEntry(EXC_PENDSV);
658
+ return true;
659
+ }
619
660
  if (this.pendingSystick && priority === systickPriority) {
620
661
  this.pendingSystick = false;
621
662
  this.exceptionEntry(EXC_SYSTICK);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rp2040js",
3
- "version": "0.14.5",
3
+ "version": "0.14.9",
4
4
  "description": "Raspberry Pi Pico (RP2040) Emulator",
5
5
  "repository": "https://github.com/wokwi/rp2040js",
6
6
  "keywords": [
@@ -54,10 +54,12 @@
54
54
  "uf2": "^1.0.0"
55
55
  },
56
56
  "lint-staged": {
57
- "**/*.{js,ts}": [
57
+ "**/*.ts": [
58
58
  "eslint --fix",
59
- "prettier --write",
60
- "git add"
59
+ "prettier --write"
60
+ ],
61
+ "**/*.js": [
62
+ "prettier --write"
61
63
  ]
62
64
  }
63
65
  }