rp2040js 0.14.8 → 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,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;
@@ -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,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;
@@ -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.8",
3
+ "version": "0.14.9",
4
4
  "description": "Raspberry Pi Pico (RP2040) Emulator",
5
5
  "repository": "https://github.com/wokwi/rp2040js",
6
6
  "keywords": [