pico-emu 1.0.2
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/LICENSE +22 -0
- package/README.md +95 -0
- package/adc_rv32.uf2 +0 -0
- package/adc_test.uf2 +0 -0
- package/adc_test_pico2.uf2 +0 -0
- package/ble_adv.uf2 +0 -0
- package/ble_adv_pico2.uf2 +0 -0
- package/cli.js +247 -0
- package/clocks_rv32.uf2 +0 -0
- package/clocks_test.uf2 +0 -0
- package/clocks_test_pico2.uf2 +0 -0
- package/dma_rv32.uf2 +0 -0
- package/dma_test.uf2 +0 -0
- package/dma_test_pico2.uf2 +0 -0
- package/dualcore_rv32.uf2 +0 -0
- package/eth_dhcp.uf2 +0 -0
- package/eth_dhcp6300.uf2 +0 -0
- package/eth_dhcp6300_pico2.uf2 +0 -0
- package/eth_dhcp6300_rv32.uf2 +0 -0
- package/eth_dhcp_pico2.uf2 +0 -0
- package/eth_dhcp_rv32.uf2 +0 -0
- package/eth_http.uf2 +0 -0
- package/eth_http6300.uf2 +0 -0
- package/eth_http6300_pico2.uf2 +0 -0
- package/eth_http6300_rv32.uf2 +0 -0
- package/eth_http_pico2.uf2 +0 -0
- package/eth_http_rv32.uf2 +0 -0
- package/ethdhcp6300_arduino.uf2 +0 -0
- package/ethdhcp6300_arduino_pico2.uf2 +0 -0
- package/examples/adc_rv32.uf2 +0 -0
- package/examples/adc_test.uf2 +0 -0
- package/examples/adc_test_pico2.uf2 +0 -0
- package/examples/ble_adv.uf2 +0 -0
- package/examples/ble_adv_pico2.uf2 +0 -0
- package/examples/clocks_rv32.uf2 +0 -0
- package/examples/clocks_test.uf2 +0 -0
- package/examples/clocks_test_pico2.uf2 +0 -0
- package/examples/dma_rv32.uf2 +0 -0
- package/examples/dma_test.uf2 +0 -0
- package/examples/dma_test_pico2.uf2 +0 -0
- package/examples/dualcore_rv32.uf2 +0 -0
- package/examples/eth_dhcp.uf2 +0 -0
- package/examples/eth_dhcp6300.uf2 +0 -0
- package/examples/eth_dhcp6300_pico2.uf2 +0 -0
- package/examples/eth_dhcp6300_rv32.uf2 +0 -0
- package/examples/eth_dhcp_pico2.uf2 +0 -0
- package/examples/eth_dhcp_rv32.uf2 +0 -0
- package/examples/eth_http.uf2 +0 -0
- package/examples/eth_http6300.uf2 +0 -0
- package/examples/eth_http6300_pico2.uf2 +0 -0
- package/examples/eth_http6300_rv32.uf2 +0 -0
- package/examples/eth_http_pico2.uf2 +0 -0
- package/examples/eth_http_rv32.uf2 +0 -0
- package/examples/fp_test.uf2 +0 -0
- package/examples/fp_test_pico2.uf2 +0 -0
- package/examples/gpio_rv32.uf2 +0 -0
- package/examples/gpio_test.uf2 +0 -0
- package/examples/gpio_test_pico2.uf2 +0 -0
- package/examples/hello_rv32.uf2 +0 -0
- package/examples/hello_usb.uf2 +0 -0
- package/examples/hello_world.uf2 +0 -0
- package/examples/hello_world_pico2.uf2 +0 -0
- package/examples/i2c_rv32.uf2 +0 -0
- package/examples/i2c_test.uf2 +0 -0
- package/examples/i2c_test_pico2.uf2 +0 -0
- package/examples/interrupt_rv32.uf2 +0 -0
- package/examples/interrupt_test.uf2 +0 -0
- package/examples/interrupt_test_pico2.uf2 +0 -0
- package/examples/littleos.uf2 +0 -0
- package/examples/littleos_pico2.uf2 +0 -0
- package/examples/littleos_pico2_riscv.uf2 +0 -0
- package/examples/micropython_rp2040.uf2 +0 -0
- package/examples/micropython_rp2350.uf2 +0 -0
- package/examples/name_prompt.uf2 +0 -0
- package/examples/name_prompt_pico2.uf2 +0 -0
- package/examples/name_prompt_rv32.uf2 +0 -0
- package/examples/pio_rv32.uf2 +0 -0
- package/examples/pio_test.uf2 +0 -0
- package/examples/pio_test_pico2.uf2 +0 -0
- package/examples/psm_rv32.uf2 +0 -0
- package/examples/psm_test.uf2 +0 -0
- package/examples/psm_test_pico2.uf2 +0 -0
- package/examples/pwm_rv32.uf2 +0 -0
- package/examples/pwm_test.uf2 +0 -0
- package/examples/pwm_test_pico2.uf2 +0 -0
- package/examples/rtc_rv32.uf2 +0 -0
- package/examples/rtc_test.uf2 +0 -0
- package/examples/rtc_test_pico2.uf2 +0 -0
- package/examples/spi_rv32.uf2 +0 -0
- package/examples/spi_test.uf2 +0 -0
- package/examples/spi_test_pico2.uf2 +0 -0
- package/examples/timer_rv32.uf2 +0 -0
- package/examples/timer_test.uf2 +0 -0
- package/examples/timer_test_pico2.uf2 +0 -0
- package/examples/uart_echo.uf2 +0 -0
- package/examples/uart_echo_pico2.uf2 +0 -0
- package/examples/uart_echo_rv32.uf2 +0 -0
- package/examples/usb_rv32.uf2 +0 -0
- package/examples/usb_test.uf2 +0 -0
- package/examples/usb_test_pico2.uf2 +0 -0
- package/examples/wifi_ble_adv_rv32.uf2 +0 -0
- package/examples/wifi_ble_gatt_rv32.uf2 +0 -0
- package/examples/wifi_join_rv32.uf2 +0 -0
- package/examples/wifi_ping.uf2 +0 -0
- package/examples/wifi_ping6_rv32.uf2 +0 -0
- package/examples/wifi_ping_pico2.uf2 +0 -0
- package/examples/wifi_ping_rv32.uf2 +0 -0
- package/examples/wifi_rv32.uf2 +0 -0
- package/examples/wifi_scan.uf2 +0 -0
- package/examples/wifi_scan_pico2.uf2 +0 -0
- package/examples/wifi_scan_rv32.uf2 +0 -0
- package/examples/wifi_webserver.uf2 +0 -0
- package/examples/wifi_webserver_pico2.uf2 +0 -0
- package/examples/wifi_webserver_rv32.uf2 +0 -0
- package/examples/ws2812_rv32.uf2 +0 -0
- package/examples/ws2812_test.uf2 +0 -0
- package/examples/ws2812_test_pico2.uf2 +0 -0
- package/fp_test.uf2 +0 -0
- package/fp_test_pico2.uf2 +0 -0
- package/gpio_rv32.uf2 +0 -0
- package/gpio_test.uf2 +0 -0
- package/gpio_test_pico2.uf2 +0 -0
- package/hello_rv32.uf2 +0 -0
- package/hello_usb.uf2 +0 -0
- package/hello_world.uf2 +0 -0
- package/hello_world_pico2.uf2 +0 -0
- package/i2c_rv32.uf2 +0 -0
- package/i2c_test.uf2 +0 -0
- package/i2c_test_pico2.uf2 +0 -0
- package/index.html +1055 -0
- package/interrupt_rv32.uf2 +0 -0
- package/interrupt_test.uf2 +0 -0
- package/interrupt_test_pico2.uf2 +0 -0
- package/littleos.uf2 +0 -0
- package/littleos_pico2.uf2 +0 -0
- package/littleos_pico2_riscv.uf2 +0 -0
- package/micropython_rp2040.uf2 +0 -0
- package/micropython_rp2350.uf2 +0 -0
- package/name_prompt.uf2 +0 -0
- package/name_prompt_pico2.uf2 +0 -0
- package/name_prompt_rv32.uf2 +0 -0
- package/package.json +27 -0
- package/picoemu.wasm.js +2 -0
- package/picoemu.wasm.threads.js +2 -0
- package/picoemu.wasm.threads.wasm +0 -0
- package/picoemu.wasm.wasm +0 -0
- package/picoemu_worker.js +81 -0
- package/pio_rv32.uf2 +0 -0
- package/pio_test.uf2 +0 -0
- package/pio_test_pico2.uf2 +0 -0
- package/psm_rv32.uf2 +0 -0
- package/psm_test.uf2 +0 -0
- package/psm_test_pico2.uf2 +0 -0
- package/pwm_rv32.uf2 +0 -0
- package/pwm_test.uf2 +0 -0
- package/pwm_test_pico2.uf2 +0 -0
- package/rtc_rv32.uf2 +0 -0
- package/rtc_test.uf2 +0 -0
- package/rtc_test_pico2.uf2 +0 -0
- package/spi_rv32.uf2 +0 -0
- package/spi_test.uf2 +0 -0
- package/spi_test_pico2.uf2 +0 -0
- package/timer_rv32.uf2 +0 -0
- package/timer_test.uf2 +0 -0
- package/timer_test_pico2.uf2 +0 -0
- package/uart_echo.uf2 +0 -0
- package/uart_echo_pico2.uf2 +0 -0
- package/uart_echo_rv32.uf2 +0 -0
- package/usb_rv32.uf2 +0 -0
- package/usb_test.uf2 +0 -0
- package/usb_test_pico2.uf2 +0 -0
- package/wifi_ble_adv_rv32.uf2 +0 -0
- package/wifi_ble_gatt_rv32.uf2 +0 -0
- package/wifi_join_rv32.uf2 +0 -0
- package/wifi_ping.uf2 +0 -0
- package/wifi_ping6_rv32.uf2 +0 -0
- package/wifi_ping_pico2.uf2 +0 -0
- package/wifi_ping_rv32.uf2 +0 -0
- package/wifi_rv32.uf2 +0 -0
- package/wifi_scan.uf2 +0 -0
- package/wifi_scan_pico2.uf2 +0 -0
- package/wifi_scan_rv32.uf2 +0 -0
- package/wifi_webserver.uf2 +0 -0
- package/wifi_webserver_pico2.uf2 +0 -0
- package/wifi_webserver_rv32.uf2 +0 -0
- package/ws2812_rv32.uf2 +0 -0
- package/ws2812_test.uf2 +0 -0
- package/ws2812_test_pico2.uf2 +0 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 danish9661
|
|
4
|
+
Copyright (c) 2025 Night-Traders-Dev
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# picoemu
|
|
2
|
+
|
|
3
|
+
RP2040 / RP2350 (Cortex-M0+, Cortex-M33, RISC-V Hazard3) emulator that runs
|
|
4
|
+
in Node or the browser via WebAssembly. Boots real UF2 firmware —
|
|
5
|
+
littleOS, MicroPython, and 40+ bare-metal peripheral demos included.
|
|
6
|
+
|
|
7
|
+
Credit: emulation core is a WASM port of
|
|
8
|
+
[Night-Traders-Dev/Bramble](https://github.com/Night-Traders-Dev/Bramble)
|
|
9
|
+
(MIT); WASM build, browser UI and packaging by
|
|
10
|
+
[danish9661/pico-emulator](https://github.com/danish9661/pico-emulator).
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
npm i pico-emu
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## CLI — `npx pico-emu firmware.uf2`
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
npx pico-emu hello_world.uf2 # arch auto-detected from UF2
|
|
22
|
+
npx pico-emu ./web/uart_echo_rv32.uf2 # type a line, Enter submits
|
|
23
|
+
npx pico-emu fw.uf2 --arch rv32 --clock 125 --steps 2000000 --timeout 30 --cores 2
|
|
24
|
+
npx pico-emu wifi_fw.uf2 --gateway ws://localhost:5099/api/network-gateway --room lab
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Type into the terminal to send UART bytes (Ctrl-C quits); firmware output
|
|
28
|
+
streams to stdout. `--arch` accepts `auto` (default, UF2 family ID),
|
|
29
|
+
`m0`, `m33`, `rv32`.
|
|
30
|
+
|
|
31
|
+
## JS API
|
|
32
|
+
|
|
33
|
+
```js
|
|
34
|
+
import createEmu from 'pico-emu';
|
|
35
|
+
import fs from 'fs';
|
|
36
|
+
|
|
37
|
+
const mod = await createEmu({ print: () => {}, printErr: () => {} });
|
|
38
|
+
mod._picoemu_init(1); // 0=M0+ 1=RV32 2=M33
|
|
39
|
+
mod._picoemu_set_clock(125); // MHz
|
|
40
|
+
const uf2 = new Uint8Array(fs.readFileSync('hello_rv32.uf2'));
|
|
41
|
+
const ptr = mod._malloc(uf2.length);
|
|
42
|
+
mod.HEAPU8.set(uf2, ptr);
|
|
43
|
+
mod._picoemu_load_uf2(ptr, uf2.length);
|
|
44
|
+
mod._free(ptr);
|
|
45
|
+
mod._picoemu_reset();
|
|
46
|
+
mod._picoemu_step(200000); // run N instructions
|
|
47
|
+
|
|
48
|
+
let ch, out = '';
|
|
49
|
+
while ((ch = mod._picoemu_read_uart(0)) !== -1) out += String.fromCharCode(ch);
|
|
50
|
+
console.log(out); // Hello from Pico-emu RV32!
|
|
51
|
+
mod._picoemu_write_uart(65); // send 'A' to firmware
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
More entry points: `_picoemu_load_elf`, `_picoemu_get_gpio` /
|
|
55
|
+
`_picoemu_set_gpio`, `_picoemu_mem_read32` / `_picoemu_mem_write32`,
|
|
56
|
+
`_picoemu_set_cores`, `_picoemu_is_halted`. Full reference with every
|
|
57
|
+
export: [docs/PICOEMU.md](https://github.com/danish9661/pico-emulator/blob/main/docs/PICOEMU.md).
|
|
58
|
+
|
|
59
|
+
## Browser
|
|
60
|
+
|
|
61
|
+
`index.html` is a ready-made UI (serial monitor, GPIO viewer, three demo
|
|
62
|
+
dropdowns: RP2040 / M33 / RV32). Serve the package dir and open it, or copy
|
|
63
|
+
`picoemu.wasm.*` + `index.html` into your app.
|
|
64
|
+
|
|
65
|
+
## Firmware in this package
|
|
66
|
+
|
|
67
|
+
Top level: one UF2 per demo (`*_test.uf2` RP2040, `*_pico2.uf2` M33,
|
|
68
|
+
`*_rv32.uf2` RV32) plus `littleos*.uf2` and `micropython*.uf2`.
|
|
69
|
+
`examples/` mirrors the same set for the UI dropdowns.
|
|
70
|
+
|
|
71
|
+
Networking extras: `eth_dhcp{,_pico2,_rv32}.uf2` + `eth_http{,_pico2,_rv32}.uf2`
|
|
72
|
+
(W5500 DHCP + HTTP client, pico-eth on SPI0 — pick the board in the UI,
|
|
73
|
+
then bridge to the Go gateway for a real lease; offline sweep asserts
|
|
74
|
+
`ETH MACRAW-OK`), `eth_dhcp6300{,_pico2,_rv32}.uf2` +
|
|
75
|
+
`eth_http6300{,_pico2,_rv32}.uf2` (W6300 DHCP + HTTP client, pico-w6300 on
|
|
76
|
+
SPI0 QSPI-single — same gateway, same markers) +
|
|
77
|
+
`ethdhcp6300_arduino{,_pico2}.uf2` (real Arduino `W6300lwIP` DHCP, PIO-QSPI
|
|
78
|
+
driver runs unmodified; offline sweep asserts `ETH-BEGIN-OK`),
|
|
79
|
+
`ble_adv{,_pico2}.uf2` (BLE advertise M0+/M33 over the
|
|
80
|
+
CYW43 BT bus — sweep-locked `ARM BLE LISTEN` with `-wifi`, no peer),
|
|
81
|
+
`wifi_scan` / `wifi_ping` / `wifi_webserver` + `_pico2` / `_rv32`
|
|
82
|
+
(Arduino-CLI WiFi builds).
|
|
83
|
+
|
|
84
|
+
W6300 feature surface (dual IPv4/IPv6 TCP/IP offload, all modeled):
|
|
85
|
+
socket modes TCP4/UDP4/IPRAW4/MACRAW + TCP6/UDP6/IPRAW6 + dual-stack
|
|
86
|
+
TCPD/UDPD; commands OPEN/LISTEN/CONNECT/CONNECT6/DISCON/CLOSE/SEND/
|
|
87
|
+
SEND_MAC/SEND_KEEP/RECV/SEND6; IPv6 net registers (LLAR/GUAR/SUB6R/GA6R,
|
|
88
|
+
SLDIP6R, UIP6R/UPORT6R); masked interrupt chain (Sn_IMR/SIMR/SLIMR/IMR +
|
|
89
|
+
IEN gate); RTR/RCR retry engine with TIMEOUT; Sn_KPALVTR auto-keepalive;
|
|
90
|
+
NETMR Wake-on-LAN magic-packet detect; Sn_TTLR/Sn_TOSR/Sn_MSSR socket
|
|
91
|
+
options; live host sockets for IPv4 + IPv6 (loopback-verified).
|
|
92
|
+
|
|
93
|
+
## License
|
|
94
|
+
|
|
95
|
+
MIT — see LICENSE (upstream © 2025 Night-Traders-Dev).
|
package/adc_rv32.uf2
ADDED
|
Binary file
|
package/adc_test.uf2
ADDED
|
Binary file
|
|
Binary file
|
package/ble_adv.uf2
ADDED
|
Binary file
|
|
Binary file
|
package/cli.js
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// pico-emu — run RP2040/RP2350 (M0+/M33/RV32) UF2 firmware in Node.
|
|
3
|
+
// Usage: pico-emu <firmware.uf2> [--arch auto|m0|m33|rv32] [--clock 125]
|
|
4
|
+
// [--steps 2000000] [--timeout 30] [--cores 2] [--wifi]
|
|
5
|
+
// [--gateway ws://localhost:5090/api/network-gateway] [--room myroom]
|
|
6
|
+
// [--ble-hci ws://localhost:5090/api/ble-gateway]
|
|
7
|
+
// [--board pico-eth|pico-eth2|pico-w6300|pico-w6300-2] [--board-spi 0|1] [--board-live|--board6300-live]
|
|
8
|
+
// [--net-w5500 ws://localhost:8765/w5500] (live W5500/W6300 proxy pump)
|
|
9
|
+
import fs from 'fs';
|
|
10
|
+
import path from 'path';
|
|
11
|
+
import { fileURLToPath } from 'url';
|
|
12
|
+
|
|
13
|
+
const HERE = path.dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
const mod = await (await import(path.join(HERE, 'picoemu.wasm.js'))).default({
|
|
15
|
+
print: () => {}, printErr: () => {},
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const args = process.argv.slice(2);
|
|
19
|
+
const opt = (name, def) => {
|
|
20
|
+
const i = args.indexOf(name);
|
|
21
|
+
return i >= 0 && i + 1 < args.length ? args[i + 1] : def;
|
|
22
|
+
};
|
|
23
|
+
const file = args.find((a) => !a.startsWith('--'));
|
|
24
|
+
if (!file) {
|
|
25
|
+
console.error('Usage: pico-emu <firmware.uf2> [--arch auto|m0|m33|rv32] [--clock 125] [--steps 2000000] [--timeout 30] [--cores 2] [--wifi] [--gateway URL] [--room ID] [--ble-hci URL] [--board pico-eth|pico-eth2|pico-w6300|pico-w6300-2] [--board-spi 0|1] [--board-live|--board6300-live] [--net-w5500 URL]');
|
|
26
|
+
process.exit(2);
|
|
27
|
+
}
|
|
28
|
+
const u8 = new Uint8Array(fs.readFileSync(file));
|
|
29
|
+
// UF2 family ID lives at offset 28 of block 0
|
|
30
|
+
const FAM = { 0xe48bff56: 0, 0xe48bff59: 2, 0xe48bff5a: 1 };
|
|
31
|
+
let arch = { auto: -1, m0: 0, rv32: 1, m33: 2 }[opt('--arch', 'auto')] ?? -1;
|
|
32
|
+
if (arch < 0) {
|
|
33
|
+
const fam = u8.length >= 32
|
|
34
|
+
? (u8[28] | (u8[29] << 8) | (u8[30] << 16) | (u8[31] << 24)) >>> 0
|
|
35
|
+
: 0;
|
|
36
|
+
arch = FAM[fam] ?? 0;
|
|
37
|
+
}
|
|
38
|
+
const clock = parseInt(opt('--clock', '125'), 10);
|
|
39
|
+
const budget = parseInt(opt('--steps', '2000000'), 10);
|
|
40
|
+
const timeoutS = parseFloat(opt('--timeout', '30'));
|
|
41
|
+
const cores = parseInt(opt('--cores', '2'), 10);
|
|
42
|
+
|
|
43
|
+
mod._picoemu_init(arch);
|
|
44
|
+
mod._picoemu_set_clock(clock);
|
|
45
|
+
try { mod._picoemu_set_cores(cores); } catch { /* older builds */ }
|
|
46
|
+
const ptr = mod._malloc(u8.length);
|
|
47
|
+
mod.HEAPU8.set(u8, ptr);
|
|
48
|
+
const ok = mod._picoemu_load_uf2(ptr, u8.length);
|
|
49
|
+
mod._free(ptr);
|
|
50
|
+
if (!ok) { console.error('picoemu: UF2 load failed'); process.exit(1); }
|
|
51
|
+
mod._picoemu_reset();
|
|
52
|
+
|
|
53
|
+
// Optional CYW43 WiFi (--wifi enables the model; with --gateway the
|
|
54
|
+
// fake DHCP/DNS server is disabled like native -nodhcp).
|
|
55
|
+
{
|
|
56
|
+
const wantWifi = args.includes('--wifi') || opt('--gateway', '') !== '' || opt('--ble-hci', '') !== '';
|
|
57
|
+
if (wantWifi) {
|
|
58
|
+
const nodhcp = opt('--gateway', '') !== '' ? 1 : 0;
|
|
59
|
+
try { mod._picoemu_wifi_enable(nodhcp); } catch {}
|
|
60
|
+
}
|
|
61
|
+
try { if (opt('--ble-hci', '') !== '') mod._picoemu_bt_hci_enable(1); } catch {}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// pico-eth/pico-eth2 (W5500) and pico-w6300/pico-w6300-2 (W6300) boards:
|
|
65
|
+
// separate SPI boards, off by default. --board-live mirrors SEND to the
|
|
66
|
+
// WS proxy like -net-live. Pico2 wiring is identical; only the SoC differs.
|
|
67
|
+
// W6300 rides QSPI-single on the same PL022 path (CSn=16/RSTn=22/INTn=15).
|
|
68
|
+
{
|
|
69
|
+
const board = opt('--board', '');
|
|
70
|
+
const is6300 = board === 'pico-w6300' || board === 'pico-w6300-2';
|
|
71
|
+
if (board) {
|
|
72
|
+
if (board !== 'pico-eth' && board !== 'pico-eth2' && !is6300) { console.error(`picoemu: unknown board '${board}' (use pico-eth|pico-eth2|pico-w6300|pico-w6300-2)`); process.exit(2); }
|
|
73
|
+
let spi = parseInt(opt('--board-spi', '0'), 10);
|
|
74
|
+
if (!(spi === 0 || spi === 1)) { console.error('picoemu: --board-spi must be 0 or 1'); process.exit(2); }
|
|
75
|
+
const live = (args.includes('--board-live') || args.includes('--board6300-live')) ? 1 : 0;
|
|
76
|
+
try {
|
|
77
|
+
if (is6300) mod._picoemu_board_eth6300(1, live, spi);
|
|
78
|
+
else mod._picoemu_board_eth(1, live, spi);
|
|
79
|
+
} catch {}
|
|
80
|
+
// The proxy protocol is chip-agnostic (same CONNECT/LISTEN/CLOSE/SEND
|
|
81
|
+
// framing), so both boards share the /w5500 path; route RX by board.
|
|
82
|
+
try { opt._isW6300 = is6300 ? 1 : 0; } catch {}
|
|
83
|
+
if (live && !opt('--net-w5500', '') && !(opt('--net-url', '') || opt('--net', ''))) {
|
|
84
|
+
try { opt._autoW5500 = 'ws://localhost:8765/w5500'; } catch {}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (process.stdin.isTTY) process.stdin.setRawMode(true);
|
|
90
|
+
process.stdin.resume();
|
|
91
|
+
process.stdin.on('data', (d) => {
|
|
92
|
+
for (const b of d) {
|
|
93
|
+
if (b === 3) process.exit(0); // Ctrl-C
|
|
94
|
+
mod._picoemu_write_uart(b);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const tick = () => new Promise((r) => setImmediate(r));
|
|
99
|
+
const t0 = Date.now();
|
|
100
|
+
let done = 0;
|
|
101
|
+
const CHUNK = 100000;
|
|
102
|
+
|
|
103
|
+
// Optional network gateway (raw ETH frames, OpenHW-gateway protocol).
|
|
104
|
+
let gw = null;
|
|
105
|
+
{
|
|
106
|
+
let url = opt('--gateway', '');
|
|
107
|
+
const room = opt('--room', '');
|
|
108
|
+
if (url) {
|
|
109
|
+
if (room) url += (url.includes('?') ? '&' : '?') + 'sessionId=' + encodeURIComponent(room);
|
|
110
|
+
gw = new WebSocket(url);
|
|
111
|
+
gw.binaryType = 'arraybuffer';
|
|
112
|
+
gw.onopen = () => { try { mod._picoemu_eth_set_uplink(1); } catch {} };
|
|
113
|
+
gw.onclose = () => { try { mod._picoemu_eth_set_uplink(0); } catch {} };
|
|
114
|
+
gw.onmessage = (e) => {
|
|
115
|
+
const arr = e.data instanceof ArrayBuffer ? new Uint8Array(e.data) : new Uint8Array(0);
|
|
116
|
+
if (arr.length < 14 || arr.length > 1522) return;
|
|
117
|
+
const p = mod._malloc(arr.length);
|
|
118
|
+
mod.HEAPU8.set(arr, p);
|
|
119
|
+
try { mod._picoemu_eth_push_rx(p, arr.length); } catch {}
|
|
120
|
+
mod._free(p);
|
|
121
|
+
};
|
|
122
|
+
gw.onerror = (e) => console.error('picoemu: gateway error ' + url + (e && e.message ? ' (' + e.message + ')' : ''));
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// Optional live-W5500 proxy socket (shared net_proxy /w5500 path; the proxy
|
|
126
|
+
// dials real TCP/UDP. NOT the OpenHW gateway: W5500 frames are socket-level
|
|
127
|
+
// CONNECT/LISTEN/CLOSE/SEND, not raw ETH).
|
|
128
|
+
// Auto-uses the Net socket when it targets /w5500, else --net-w5500 URL.
|
|
129
|
+
let w5500ws = null;
|
|
130
|
+
{
|
|
131
|
+
let url = opt('--net-w5500', '') || (opt._autoW5500 || '');
|
|
132
|
+
if (!url) {
|
|
133
|
+
const netUrl = opt('--net-url', '') || opt('--net', '');
|
|
134
|
+
if (netUrl && /\/w5500/.test(netUrl)) url = netUrl;
|
|
135
|
+
}
|
|
136
|
+
if (url) {
|
|
137
|
+
w5500ws = new WebSocket(url);
|
|
138
|
+
w5500ws.binaryType = 'arraybuffer';
|
|
139
|
+
w5500ws.onmessage = (e) => {
|
|
140
|
+
const arr = e.data instanceof ArrayBuffer ? new Uint8Array(e.data)
|
|
141
|
+
: typeof e.data === 'string' ? new TextEncoder().encode(e.data) : new Uint8Array(0);
|
|
142
|
+
if (!arr.length) return;
|
|
143
|
+
// Route to the W6300 when a pico-w6300 board is selected (same
|
|
144
|
+
// 8-socket model and proxy framing; chip-agnostic proxy).
|
|
145
|
+
const is6300 = (() => { try { return opt._isW6300 ? 1 : 0; } catch { return 0; } })();
|
|
146
|
+
const pushRx = (sock, p, len) => {
|
|
147
|
+
try {
|
|
148
|
+
if (is6300) mod._picoemu_w6300_push_rx(sock, p, len);
|
|
149
|
+
else mod._picoemu_w5500_push_rx(sock, p, len);
|
|
150
|
+
} catch {}
|
|
151
|
+
};
|
|
152
|
+
const pushStatus = (sock, code) => {
|
|
153
|
+
try {
|
|
154
|
+
if (is6300) mod._picoemu_w6300_push_status(sock, code);
|
|
155
|
+
else mod._picoemu_w5500_push_status(sock, code);
|
|
156
|
+
} catch {}
|
|
157
|
+
};
|
|
158
|
+
if (arr[0] === 0x53 && arr.length >= 4) {
|
|
159
|
+
pushStatus(arr[1], arr[3]);
|
|
160
|
+
} else if (arr[0] < 8 && arr.length >= 3) {
|
|
161
|
+
const ln = arr[1] | (arr[2] << 8);
|
|
162
|
+
const payload = arr.slice(3, 3 + ln);
|
|
163
|
+
const p = mod._malloc(payload.length);
|
|
164
|
+
mod.HEAPU8.set(payload, p);
|
|
165
|
+
pushRx(arr[0], p, payload.length);
|
|
166
|
+
mod._free(p);
|
|
167
|
+
} else if (arr[0] === 0x57 && arr.length >= 4) {
|
|
168
|
+
const sock = arr[1], ln = arr[2] | (arr[3] << 8);
|
|
169
|
+
const payload = arr.slice(4, 4 + ln);
|
|
170
|
+
const p = mod._malloc(payload.length);
|
|
171
|
+
mod.HEAPU8.set(payload, p);
|
|
172
|
+
pushRx(sock, p, payload.length);
|
|
173
|
+
mod._free(p);
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
w5500ws.onerror = (e) => console.error('picoemu: net-w5500 error ' + url + (e && e.message ? ' (' + e.message + ')' : ''));
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
// Optional BLE HCI uplink (raw H4 packets, Bumble/gateway ble-gateway protocol).
|
|
180
|
+
let blehci = null;
|
|
181
|
+
{
|
|
182
|
+
const url = opt('--ble-hci', '');
|
|
183
|
+
if (url) {
|
|
184
|
+
blehci = new WebSocket(url);
|
|
185
|
+
blehci.binaryType = 'arraybuffer';
|
|
186
|
+
blehci.onmessage = (e) => {
|
|
187
|
+
const arr = e.data instanceof ArrayBuffer ? new Uint8Array(e.data) : new Uint8Array(0);
|
|
188
|
+
if (arr.length < 2 || arr.length > 1088) return;
|
|
189
|
+
const p = mod._malloc(arr.length);
|
|
190
|
+
mod.HEAPU8.set(arr, p);
|
|
191
|
+
try { mod._picoemu_bt_hci_push_rx(p, arr.length); } catch {}
|
|
192
|
+
mod._free(p);
|
|
193
|
+
};
|
|
194
|
+
blehci.onerror = (e) => console.error('picoemu: ble-hci error ' + url + (e && e.message ? ' (' + e.message + ')' : ''));
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
process.stdout.write('');
|
|
198
|
+
while (done < budget && (Date.now() - t0) / 1000 < timeoutS) {
|
|
199
|
+
mod._picoemu_step(Math.min(CHUNK, budget - done));
|
|
200
|
+
done += CHUNK;
|
|
201
|
+
await tick(); // let stdin/stdio/events fire
|
|
202
|
+
if (gw && gw.readyState === 1) {
|
|
203
|
+
for (let i = 0; i < 16; i++) {
|
|
204
|
+
const p = mod._malloc(2048);
|
|
205
|
+
let got = -1;
|
|
206
|
+
try { got = mod._picoemu_eth_pop_tx(p, 2048); } catch { mod._free(p); break; }
|
|
207
|
+
if (got <= 0) { mod._free(p); break; }
|
|
208
|
+
try { gw.send(mod.HEAPU8.slice(p, p + got)); } catch {}
|
|
209
|
+
mod._free(p);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if (blehci && blehci.readyState === 1) {
|
|
213
|
+
for (let i = 0; i < 16; i++) {
|
|
214
|
+
const p = mod._malloc(2048);
|
|
215
|
+
let got = -1;
|
|
216
|
+
try { got = mod._picoemu_bt_hci_pop_tx(p, 2048); } catch { mod._free(p); break; }
|
|
217
|
+
if (got <= 0) { mod._free(p); break; }
|
|
218
|
+
try { blehci.send(mod.HEAPU8.slice(p, p + got)); } catch {}
|
|
219
|
+
mod._free(p);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
// W5500/W6300 proxy pump (Node): forward queued CONNECT/LISTEN/CLOSE/SEND
|
|
223
|
+
// to the --net-w5500 proxy socket. Same shared net_proxy as the browser
|
|
224
|
+
// Net panel; NOT the OpenHW gateway (socket-level TCP/UDP, not ETH).
|
|
225
|
+
// Both chips queue identical framing; pump each queue in turn.
|
|
226
|
+
if (w5500ws && w5500ws.readyState === 1) {
|
|
227
|
+
const pumpOne = (lenFn, popFn) => {
|
|
228
|
+
let budget = 0;
|
|
229
|
+
try { budget = mod[lenFn](); } catch { budget = 0; }
|
|
230
|
+
if (budget > 0) {
|
|
231
|
+
const n = Math.min(budget, 8192);
|
|
232
|
+
const p = mod._malloc(n);
|
|
233
|
+
let got = 0;
|
|
234
|
+
try { got = mod[popFn](p, n); } catch { got = 0; }
|
|
235
|
+
if (got > 0) { try { w5500ws.send(mod.HEAPU8.slice(p, p + got)); } catch {} }
|
|
236
|
+
mod._free(p);
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
try { pumpOne('_picoemu_w5500_tx_len', '_picoemu_w5500_pop_tx'); } catch {}
|
|
240
|
+
try { pumpOne('_picoemu_w6300_tx_len', '_picoemu_w6300_pop_tx'); } catch {}
|
|
241
|
+
}
|
|
242
|
+
let s = '', ch, n = 0;
|
|
243
|
+
while ((ch = mod._picoemu_read_uart(0)) !== -1 && n++ < 65536) s += String.fromCharCode(ch);
|
|
244
|
+
if (s) process.stdout.write(s);
|
|
245
|
+
try { if (mod._picoemu_is_halted()) break; } catch { /* ignore */ }
|
|
246
|
+
}
|
|
247
|
+
process.exit(0);
|
package/clocks_rv32.uf2
ADDED
|
Binary file
|
package/clocks_test.uf2
ADDED
|
Binary file
|
|
Binary file
|
package/dma_rv32.uf2
ADDED
|
Binary file
|
package/dma_test.uf2
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/eth_dhcp.uf2
ADDED
|
Binary file
|
package/eth_dhcp6300.uf2
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/eth_http.uf2
ADDED
|
Binary file
|
package/eth_http6300.uf2
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|