rp2040js 1.1.1 → 1.2.0

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
@@ -1,3 +1,5 @@
1
+ ![](../../actions/workflows/ci-test.yml/badge.svg) ![](../../actions/workflows/ci-micropython.yml/badge.svg) ![](../../actions/workflows/ci-pico-sdk.yml/badge.svg)
2
+
1
3
  # rp2040js
2
4
 
3
5
  Raspberry Pi Pico Emulator for the [Wokwi Simulation Platform](https://wokwi.com). It blinks, runs Arduino code, and even the MicroPython REPL!
@@ -58,7 +60,7 @@ A GDB server on port 3333 can be enabled by specifying the `--gdb` flag:
58
60
  npm run start:micropython -- --gdb
59
61
  ```
60
62
 
61
- For using the MicroPython demo code in tests, the `--expect-text` can come handy: it will look for the given text in the serial output and exit with code 0 if found, or 1 if not found. You can find an example in [the MicroPython CI test](./github/workflows/ci-micropython.yml).
63
+ For using the MicroPython demo code in tests, the `--expect-text` can come handy: it will look for the given text in the serial output and exit with code 0 if found, or 1 if not found. You can find an example in [the MicroPython CI test](./.github/workflows/ci-micropython.yml).
62
64
 
63
65
  #### Filesystem support
64
66
 
@@ -0,0 +1,13 @@
1
+ import { BasePeripheral, Peripheral } from './peripheral.js';
2
+ export declare class RPXOSC extends BasePeripheral implements Peripheral {
3
+ private ctrl;
4
+ private status;
5
+ private dormant;
6
+ private startup;
7
+ private count;
8
+ private enabled;
9
+ private stable;
10
+ private isDormant;
11
+ readUint32(offset: number): number;
12
+ writeUint32(offset: number, value: number): void;
13
+ }
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RPXOSC = void 0;
4
+ const peripheral_js_1 = require("./peripheral.js");
5
+ // XOSC register offsets
6
+ const XOSC_CTRL = 0x00;
7
+ const XOSC_STATUS = 0x04;
8
+ const XOSC_DORMANT = 0x08;
9
+ const XOSC_STARTUP = 0x0c;
10
+ const XOSC_COUNT = 0x1c;
11
+ // CTRL register bits
12
+ const CTRL_ENABLE_LSB = 12;
13
+ const CTRL_ENABLE_BITS = 0x00fff000;
14
+ const CTRL_FREQ_RANGE_BITS = 0x00000fff;
15
+ // CTRL ENABLE values
16
+ const CTRL_ENABLE_DISABLE = 0xd1e;
17
+ const CTRL_ENABLE_ENABLE = 0xfab;
18
+ // STATUS register bits
19
+ const STATUS_STABLE = 0x80000000; // bit 31
20
+ const STATUS_BADWRITE = 0x01000000; // bit 24
21
+ const STATUS_ENABLED = 0x00001000; // bit 12
22
+ const STATUS_FREQ_RANGE_BITS = 0x00000003;
23
+ // DORMANT register values
24
+ const DORMANT_VALUE = 0x636f6d61; // "coma" in ASCII
25
+ const WAKE_VALUE = 0x77616b65; // "wake" in ASCII
26
+ // STARTUP register bits
27
+ const STARTUP_X4 = 0x00100000; // bit 20
28
+ const STARTUP_DELAY_BITS = 0x00003fff;
29
+ class RPXOSC extends peripheral_js_1.BasePeripheral {
30
+ constructor() {
31
+ super(...arguments);
32
+ this.ctrl = 0;
33
+ this.status = 0;
34
+ this.dormant = 0;
35
+ this.startup = 0;
36
+ this.count = 0;
37
+ this.enabled = false;
38
+ this.stable = false;
39
+ this.isDormant = false;
40
+ }
41
+ readUint32(offset) {
42
+ switch (offset) {
43
+ case XOSC_CTRL:
44
+ return this.ctrl;
45
+ case XOSC_STATUS: {
46
+ let status = this.status;
47
+ if (this.stable) {
48
+ status |= STATUS_STABLE;
49
+ }
50
+ if (this.enabled) {
51
+ status |= STATUS_ENABLED;
52
+ }
53
+ return status;
54
+ }
55
+ case XOSC_DORMANT:
56
+ return this.dormant;
57
+ case XOSC_STARTUP:
58
+ return this.startup;
59
+ case XOSC_COUNT:
60
+ return this.count;
61
+ }
62
+ return super.readUint32(offset);
63
+ }
64
+ writeUint32(offset, value) {
65
+ switch (offset) {
66
+ case XOSC_CTRL: {
67
+ this.ctrl = value;
68
+ const enableValue = (value & CTRL_ENABLE_BITS) >>> CTRL_ENABLE_LSB;
69
+ const freqRange = value & CTRL_FREQ_RANGE_BITS;
70
+ void freqRange; // Currently unused, but could be logged or validated
71
+ if (enableValue === CTRL_ENABLE_ENABLE) {
72
+ if (!this.isDormant) {
73
+ this.enabled = true;
74
+ // For simplicity, become stable immediately
75
+ // In real hardware, this would take time based on STARTUP register
76
+ this.stable = true;
77
+ }
78
+ }
79
+ else if (enableValue === CTRL_ENABLE_DISABLE) {
80
+ this.enabled = false;
81
+ this.stable = false;
82
+ }
83
+ else if (enableValue !== 0) {
84
+ // Invalid write to ENABLE field
85
+ this.status |= STATUS_BADWRITE;
86
+ this.warn(`Invalid ENABLE value written: 0x${enableValue.toString(16)}`);
87
+ }
88
+ break;
89
+ }
90
+ case XOSC_STATUS:
91
+ // Clear BADWRITE bit if written as 1 (write-1-to-clear)
92
+ if (value & STATUS_BADWRITE) {
93
+ this.status &= ~STATUS_BADWRITE;
94
+ }
95
+ break;
96
+ case XOSC_DORMANT:
97
+ if (value === DORMANT_VALUE) {
98
+ this.isDormant = true;
99
+ this.stable = false;
100
+ }
101
+ else if (value === WAKE_VALUE) {
102
+ this.isDormant = false;
103
+ if (this.enabled) {
104
+ this.stable = true;
105
+ }
106
+ }
107
+ this.dormant = value;
108
+ break;
109
+ case XOSC_STARTUP:
110
+ this.startup = value & (STARTUP_X4 | STARTUP_DELAY_BITS);
111
+ break;
112
+ case XOSC_COUNT:
113
+ // Writing to COUNT starts the countdown
114
+ this.count = value & 0xff;
115
+ // For simplicity, we don't actually implement the countdown
116
+ // In real hardware, this would decrement at the XOSC frequency
117
+ break;
118
+ default:
119
+ super.writeUint32(offset, value);
120
+ }
121
+ }
122
+ }
123
+ exports.RPXOSC = RPXOSC;
@@ -27,6 +27,7 @@ const timer_js_1 = require("./peripherals/timer.js");
27
27
  const uart_js_1 = require("./peripherals/uart.js");
28
28
  const usb_js_1 = require("./peripherals/usb.js");
29
29
  const watchdog_js_1 = require("./peripherals/watchdog.js");
30
+ const xosc_js_1 = require("./peripherals/xosc.js");
30
31
  const sio_js_1 = require("./sio.js");
31
32
  const logging_js_1 = require("./utils/logging.js");
32
33
  exports.FLASH_START_ADDRESS = 0x10000000;
@@ -137,7 +138,7 @@ class RP2040 {
137
138
  0x40018: new peripheral_js_1.UnimplementedPeripheral(this, 'IO_QSPI_BASE'),
138
139
  0x4001c: new pads_js_1.RPPADS(this, 'PADS_BANK0_BASE', 'bank0'),
139
140
  0x40020: new pads_js_1.RPPADS(this, 'PADS_QSPI_BASE', 'qspi'),
140
- 0x40024: new peripheral_js_1.UnimplementedPeripheral(this, 'XOSC_BASE'),
141
+ 0x40024: new xosc_js_1.RPXOSC(this, 'XOSC_BASE'),
141
142
  0x40028: new peripheral_js_1.UnimplementedPeripheral(this, 'PLL_SYS_BASE'),
142
143
  0x4002c: new peripheral_js_1.UnimplementedPeripheral(this, 'PLL_USB_BASE'),
143
144
  0x40030: new busctrl_js_1.RPBUSCTRL(this, 'BUSCTRL_BASE'),
@@ -0,0 +1,13 @@
1
+ import { BasePeripheral, Peripheral } from './peripheral.js';
2
+ export declare class RPXOSC extends BasePeripheral implements Peripheral {
3
+ private ctrl;
4
+ private status;
5
+ private dormant;
6
+ private startup;
7
+ private count;
8
+ private enabled;
9
+ private stable;
10
+ private isDormant;
11
+ readUint32(offset: number): number;
12
+ writeUint32(offset: number, value: number): void;
13
+ }
@@ -0,0 +1,119 @@
1
+ import { BasePeripheral } from './peripheral.js';
2
+ // XOSC register offsets
3
+ const XOSC_CTRL = 0x00;
4
+ const XOSC_STATUS = 0x04;
5
+ const XOSC_DORMANT = 0x08;
6
+ const XOSC_STARTUP = 0x0c;
7
+ const XOSC_COUNT = 0x1c;
8
+ // CTRL register bits
9
+ const CTRL_ENABLE_LSB = 12;
10
+ const CTRL_ENABLE_BITS = 0x00fff000;
11
+ const CTRL_FREQ_RANGE_BITS = 0x00000fff;
12
+ // CTRL ENABLE values
13
+ const CTRL_ENABLE_DISABLE = 0xd1e;
14
+ const CTRL_ENABLE_ENABLE = 0xfab;
15
+ // STATUS register bits
16
+ const STATUS_STABLE = 0x80000000; // bit 31
17
+ const STATUS_BADWRITE = 0x01000000; // bit 24
18
+ const STATUS_ENABLED = 0x00001000; // bit 12
19
+ const STATUS_FREQ_RANGE_BITS = 0x00000003;
20
+ // DORMANT register values
21
+ const DORMANT_VALUE = 0x636f6d61; // "coma" in ASCII
22
+ const WAKE_VALUE = 0x77616b65; // "wake" in ASCII
23
+ // STARTUP register bits
24
+ const STARTUP_X4 = 0x00100000; // bit 20
25
+ const STARTUP_DELAY_BITS = 0x00003fff;
26
+ export class RPXOSC extends BasePeripheral {
27
+ constructor() {
28
+ super(...arguments);
29
+ this.ctrl = 0;
30
+ this.status = 0;
31
+ this.dormant = 0;
32
+ this.startup = 0;
33
+ this.count = 0;
34
+ this.enabled = false;
35
+ this.stable = false;
36
+ this.isDormant = false;
37
+ }
38
+ readUint32(offset) {
39
+ switch (offset) {
40
+ case XOSC_CTRL:
41
+ return this.ctrl;
42
+ case XOSC_STATUS: {
43
+ let status = this.status;
44
+ if (this.stable) {
45
+ status |= STATUS_STABLE;
46
+ }
47
+ if (this.enabled) {
48
+ status |= STATUS_ENABLED;
49
+ }
50
+ return status;
51
+ }
52
+ case XOSC_DORMANT:
53
+ return this.dormant;
54
+ case XOSC_STARTUP:
55
+ return this.startup;
56
+ case XOSC_COUNT:
57
+ return this.count;
58
+ }
59
+ return super.readUint32(offset);
60
+ }
61
+ writeUint32(offset, value) {
62
+ switch (offset) {
63
+ case XOSC_CTRL: {
64
+ this.ctrl = value;
65
+ const enableValue = (value & CTRL_ENABLE_BITS) >>> CTRL_ENABLE_LSB;
66
+ const freqRange = value & CTRL_FREQ_RANGE_BITS;
67
+ void freqRange; // Currently unused, but could be logged or validated
68
+ if (enableValue === CTRL_ENABLE_ENABLE) {
69
+ if (!this.isDormant) {
70
+ this.enabled = true;
71
+ // For simplicity, become stable immediately
72
+ // In real hardware, this would take time based on STARTUP register
73
+ this.stable = true;
74
+ }
75
+ }
76
+ else if (enableValue === CTRL_ENABLE_DISABLE) {
77
+ this.enabled = false;
78
+ this.stable = false;
79
+ }
80
+ else if (enableValue !== 0) {
81
+ // Invalid write to ENABLE field
82
+ this.status |= STATUS_BADWRITE;
83
+ this.warn(`Invalid ENABLE value written: 0x${enableValue.toString(16)}`);
84
+ }
85
+ break;
86
+ }
87
+ case XOSC_STATUS:
88
+ // Clear BADWRITE bit if written as 1 (write-1-to-clear)
89
+ if (value & STATUS_BADWRITE) {
90
+ this.status &= ~STATUS_BADWRITE;
91
+ }
92
+ break;
93
+ case XOSC_DORMANT:
94
+ if (value === DORMANT_VALUE) {
95
+ this.isDormant = true;
96
+ this.stable = false;
97
+ }
98
+ else if (value === WAKE_VALUE) {
99
+ this.isDormant = false;
100
+ if (this.enabled) {
101
+ this.stable = true;
102
+ }
103
+ }
104
+ this.dormant = value;
105
+ break;
106
+ case XOSC_STARTUP:
107
+ this.startup = value & (STARTUP_X4 | STARTUP_DELAY_BITS);
108
+ break;
109
+ case XOSC_COUNT:
110
+ // Writing to COUNT starts the countdown
111
+ this.count = value & 0xff;
112
+ // For simplicity, we don't actually implement the countdown
113
+ // In real hardware, this would decrement at the XOSC frequency
114
+ break;
115
+ default:
116
+ super.writeUint32(offset, value);
117
+ }
118
+ }
119
+ }
@@ -24,6 +24,7 @@ import { RPTimer } from './peripherals/timer.js';
24
24
  import { RPUART } from './peripherals/uart.js';
25
25
  import { RPUSBController } from './peripherals/usb.js';
26
26
  import { RPWatchdog } from './peripherals/watchdog.js';
27
+ import { RPXOSC } from './peripherals/xosc.js';
27
28
  import { RPSIO } from './sio.js';
28
29
  import { ConsoleLogger, LogLevel } from './utils/logging.js';
29
30
  export const FLASH_START_ADDRESS = 0x10000000;
@@ -134,7 +135,7 @@ export class RP2040 {
134
135
  0x40018: new UnimplementedPeripheral(this, 'IO_QSPI_BASE'),
135
136
  0x4001c: new RPPADS(this, 'PADS_BANK0_BASE', 'bank0'),
136
137
  0x40020: new RPPADS(this, 'PADS_QSPI_BASE', 'qspi'),
137
- 0x40024: new UnimplementedPeripheral(this, 'XOSC_BASE'),
138
+ 0x40024: new RPXOSC(this, 'XOSC_BASE'),
138
139
  0x40028: new UnimplementedPeripheral(this, 'PLL_SYS_BASE'),
139
140
  0x4002c: new UnimplementedPeripheral(this, 'PLL_USB_BASE'),
140
141
  0x40030: new RPBUSCTRL(this, 'BUSCTRL_BASE'),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rp2040js",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "Raspberry Pi Pico (RP2040) Emulator",
5
5
  "repository": "https://github.com/wokwi/rp2040js",
6
6
  "keywords": [