@@ -256,6 +239,8 @@
+
+
@@ -265,13 +250,13 @@
+
+
-
-
@@ -345,3 +330,6 @@
+
+
+
diff --git a/docs/filesystem.md b/docs/filesystem.md
index 7549365a..d247a013 100644
--- a/docs/filesystem.md
+++ b/docs/filesystem.md
@@ -1,7 +1,34 @@
-A 9p filesystem is supported by v86, using a virtio transport. Using
-it, files can be exchanged with the guest OS, see `create_file` and `read_file`
-in [`starter.js`](https://github.com/copy/v86/blob/master/src/browser/starter.js).
-It can be enabled by passing the following options to `V86`:
+A 9p filesystem is supported by v86, using a virtio transport. There are several
+ways it can be set up.
+
+### Guest mount
+
+In all cases, the filesystem is mounted in the guest system using the `9p`
+filesystem type and the `host9p` device tag. Typically you want to be specific
+with the version and transport options:
+
+```sh
+mount -t 9p -o trans=virtio,version=9p2000.L host9p /mnt/9p/
+```
+
+Here are kernel arguments you can use to boot directly off the 9p filesystem:
+
+```
+rw root=host9p rootfstype=9p rootflags=trans=virtio,version=9p2000.L
+```
+
+The `aname` option can be used to pick the directory from 9p to mount. The `rw`
+argument makes this a read-write root filesystem.
+
+
+### JSON/HTTP Filesystem
+
+This is the standard way to setup the 9p filesystem. It loads files over
+HTTP on-demand into an in-memory filesystem in JS. This allows files to be
+exchanged with the guest OS. See `create_file` and `read_file` in
+[`starter.js`](https://github.com/copy/v86/blob/master/src/browser/starter.js).
+
+This mode is enabled by passing the following options to `V86`:
```javascript
filesystem: {
@@ -11,15 +38,60 @@ filesystem: {
```
Here, `basefs` is a json file created using
-[fs2json](https://github.com/copy/fs2json). The base url is the prefix of a url
-from which the files are available. For instance, if the 9p filesystem has a
-file `/bin/sh`, that file must be accessible from
-`http://localhost/9p/base/bin/sh`. If `basefs` and `baseurl` are omitted, an
-empty 9p filesystem is created.
+[fs2json.py](tools/fs2json.py) and the `baseurl` directory is created using
+[copy-to-sha256.py](tools/copy-to-sha256.py).
-The `mount_tag` of the 9p device is `host9p`. In order to mount it in the
-guest, use:
+If `basefs` and `baseurl` are omitted, an empty 9p filesystem is created. Unless
+you configure one of the alternative modes.
-```sh
-mount -t 9p host9p /mnt/9p/
+
+### Function Handler
+
+You can handle 9p messages directly in JavaScript yourself by providing a
+function as `handle9p` under `filesystem`:
+
+```javascript
+filesystem: {
+ handle9p: async (reqBuf, reply) => {
+ // reqBuf is a Uint8Array of the entire request frame.
+ // you can parse these bytes using a library or reading the 9p spec.
+ // once you formulate a response, you send the reply frame as a
+ // Uint8Array by passing it to reply: reply(respBuf)
+ }
+}
```
+
+This allows you to implement a 9p server or custom proxy in JS. However, this
+filesystem will not be cached (unless cached in the guest OS), functions like
+`create_file` and `read_file` will not be available, and you will be responsible
+for keeping its state in sync with any machine save states.
+
+
+### WebSocket Proxy
+
+You can also back the 9p virtio filesystem with a 9p server over WebSocket by
+providing a WS proxy URL:
+
+```javascript
+filesystem: {
+ proxy_url: "ws://localhost:8080/"
+}
+```
+
+Simlar to using `handle9p`, this filesystem will not be available in JS and
+will need to be re-mounted after restoring state.
+
+The WS proxy just needs to hand off messages with a connection to a normal 9p
+server. Each binary WebSocket message is the full buffer of a request or a
+reply.
+
+To implement, request message bytes can just be sent directly to the 9p
+connection, but the 9p reply stream needs to be buffered into a single binary
+WebSocket message. The proxy must at least parse the first 4 bytes to get the
+message size and use it to buffer a full message before sending over WebSocket.
+
+The [wanix](https://github.com/tractordev/wanix) CLI has a `serve` command that
+not only serves a directory over HTTP, but also over 9P via WebSocket. You can
+see how it [implements a proxy][1] in Go.
+
+[1]: https://github.com/tractordev/wanix/blob/main/cmd/wanix/serve.go#L117-L177
diff --git a/docs/networking.md b/docs/networking.md
index 0bb0a7ba..ca6067b1 100644
--- a/docs/networking.md
+++ b/docs/networking.md
@@ -62,6 +62,7 @@ Backends `fetch` and `wisp` support a couple of special settings in `config.net_
| **dns_method** | str | DNS method to use, either `static` or `doh`. `static`: use built-in DNS server, `doh`: use [DNS-over-HTTPS](https://en.wikipedia.org/wiki/DNS_over_HTTPS) (DoH). Defaults to `static` for `fetch` and to `doh` for `wisp` backend. |
| **doh_server** | str | Host name or IP address (and optional port number) of the DoH server if `dns_method` is `doh`. The value is expanded to the URL `https://DOH_SERVER/dns-query`. Default: `cloudflare-dns.com`. |
| **cors_proxy** | str | CORS proxy server URL, do not use a proxy if undefined. Default: undefined (`fetch` backend only). |
+| **mtu** | int | The MTU used for the virtual network. Increasing it can improve performance. This only works if the NIC type is `virtio`. Default: `1500` |
#### Example `net_device` settings
@@ -128,6 +129,7 @@ Since this backend (including its proxy server) only forwards unmodified etherne
* **[go-websockproxy](https://github.com/gdm85/go-websockproxy)** -- one TAP device for all clients, written in Go, without integraded DHCP but with integrated TLS support
* **[node-relay](https://github.com/krishenriksen/node-relay)** -- like websockproxy but written for NodeJS (dnsmasq/no TLS), see [New websocket ethernet switch built using Node.js #777](https://github.com/copy/v86/discussions/777)
* **[wsnic](https://github.com/chschnell/wsnic)** -- uses a single bridge and one TAP device per client, integrates dnsmasq for DHCP/DNS and stunnel for TLS
+* **[RootlessRelay](https://github.com/obegron/rootlessRelay)** -- uses its own network stack that doesn't require TUN/TAP devices, has a built-in reverse proxy and admin interface, see [RootlessRelay #1442](https://github.com/copy/v86/discussions/1442)
[See here](https://github.com/copy/v86/discussions/1199#discussioncomment-12026845) for a benchmark comparing the download performance of these proxy servers.
@@ -162,6 +164,8 @@ Starting with PR [#1233](https://github.com/copy/v86/pull/1233), the TCP guest l
v86 guests are isolated from each other when using the `fetch` backend.
+v86 guests have HTTP access to the host's `localhost` using the URL `http://.external` (e.g. `1234.external` -> `localhost:1234`).
+
**CORS proxy server**
* **[cors-anywhere](https://github.com/Rob--W/cors-anywhere)** -- NodeJS
diff --git a/docs/windows-9x.md b/docs/windows-9x.md
index 118e7961..d72f080e 100644
--- a/docs/windows-9x.md
+++ b/docs/windows-9x.md
@@ -6,13 +6,13 @@ Recommended versions:
-------------
-1. Create a disk image (up to 2 GB):
+1. Create a disk image (up to 2 GB):
```sh
qemu-img create -f raw hdd.img M
```
2. Run QEMU with the following settings:
```sh
-qemu-system-i386 -m 128 -M pc,acpi=off -hda hdd.img
+qemu-system-i386 -m 128 -M pc,acpi=off -drive file=hdd.img,format=raw
```
- add `-cdrom /path/to/installCD.iso`, if you use a CD version.
- add `-fda /path/to/boot_floppy.img -boot a`, if you use a floppy version or your install CD is non-bootable.
@@ -23,16 +23,46 @@ qemu-system-i386 -m 128 -M pc,acpi=off -hda hdd.img
4. To change floppy disk, press *Ctrl+Alt+2* to switch to the QEMU Monitor, run `change floppy0 /path/to/new_floppy_image` and press *Ctrl+Alt+1* to switch to VGA.
5. Follow the installation guide on the screen.
-6. (optionally) If "Windows protection" errors appears on startup, apply [FIX95CPU](http://lonecrusader.x10host.com/fix95cpu.html) or [patcher9x](https://github.com/JHRobotics/patcher9x#installation).
> [!TIP]
> For transfer files from host to guest, use [genisoimage](https://wiki.debian.org/genisoimage) ([UltraISO](https://www.ultraiso.com/) and [PowerISO](https://www.poweriso.com/) for Windows and Mac) for creating CD-ISO image or [dosfstools](https://github.com/dosfstools/dosfstools) ([WinImage](https://www.winimage.com/download.htm) for Windows) for creating floppy disk images, then mount the created image to QEMU.
+## Troubleshooting
+
+### "Windows protection" errors during startup
+
+Apply [FIX95CPU](http://lonecrusader.x10host.com/fix95cpu.html) or [patcher9x](https://github.com/JHRobotics/patcher9x#installation).
+
+### "VFBACKUP could no load VFD.VXD" on startup (Windows 95)
+
+**Workaround #1**:
+*Source: [#1185](https://github.com/copy/v86/issues/1185)*
+
+1. Mount the installation CD (or `Disk 3` for the RTM version on floppy disks).
+2. Open the "MS-DOS prompt" and run:
+
+For the CD version:
+```bat
+extract /a /l C:\Windows\System :\WIN95\WIN95_02.CAB vfd.vxd
+```
+
+For the floppy version:
+```bat
+extract /a /l C:\Windows\System :\WIN95_03.CAB vfd.vxd
+```
+
+**Workaround #2**:
+*Source: [#289](https://github.com/copy/v86/issues/289)*
+
+1. Open the Start menu, click on "Run" and run `sysedit`.
+2. Find `C:\AUTOEXEC.BAT` and add `smartdrv` to the top of the file.
+3. Press File -> Save.
+
## Floppy disk support
Currently, the floppy drive in v86 works only with MS-DOS compatibility mode.
-To check this: open the Start menu, click on "Control Panel" and "System", select "Performance" tab.
+To check this: open the Start menu, click on "Control Panel" and "System", select "Performance" tab.
If it says *"Drive A is using MS-DOS compatibility mode file system"*, the floppy drive should work properly in v86. If not, try this solution:
1. Click on "Device Manager" in "System Properties".
@@ -41,10 +71,12 @@ If it says *"Drive A is using MS-DOS compatibility mode file system"*, the flopp
## Enabling True Color (32 bpp)
-The default VGA display driver only supports 640x480x8 video mode, to fix this, install **Universal VBE9x Video Display Driver**.
+The default VGA display driver only supports 640x480x4 video mode, to fix this, you can install **Universal VBE9x Video Display Driver** or **VMDisp9x**.
+
+### Universal VBE9x Video Display Driver
> [!WARNING]
-> After installing, DOS Mode (and other programs and games that require it) may not work properly.
+> After installing, DOS Mode (and other programs and games that require it) may not work properly.
> This is a problem in VBE9x, not v86, see [#110](https://github.com/copy/v86/issues/110).
> Also, this driver doesn't support DirectX, DirectDraw and OpenGL.
@@ -56,6 +88,19 @@ The default VGA display driver only supports 640x480x8 video mode, to fix this,
6. Select "VBE Miniport" adapter, press "OK" and "Next".
7. After installing, restart Windows.
+### VMDisp9x (Windows 95)
+
+> [!WARNING]
+> This driver can run DOS Mode with some graphical glitches. However, DirectX and/or DirectDraw may not work properly with this driver.
+> Also, this driver doesn't support OpenGL.
+
+1. Download `vmdisp9x-<...>-driver-2d.img` from https://github.com/JHRobotics/vmdisp9x/releases.
+2. Mount as floppy image, right-click on the Desktop, click on "Properties".
+3. Click "Advanced" > "Adapter" > "Change".
+4. Press "Have Disk...", click "Browse" and go to the floppy.
+5. Select "VESA ISA" adapter and press "OK".
+6. After installing, restart Windows.
+
## CPU idling on Windows 95
See about [installing AmnHLT](cpu-idling.md#windows-9x-using-amnhlt).
@@ -64,43 +109,43 @@ See about [installing AmnHLT](cpu-idling.md#windows-9x-using-amnhlt).
1. Open the Start menu, click on "Control Panel" and "Add New Hardware".
2. Press "Next", select "No" and select next options:
-```
-Hardware type: Network adapters
-Manufacturers: Novell
-Models: NE2000 Compatible
-```
+| Option | Value |
+|:--------------|:------------------|
+| Hardware type | Network adapters |
+| Manufacturers | Novell |
+| Models | NE2000 Compatible |
3. Press "Next" and restart Windows.
4. After restarting, right-click on "My computer", select "Propeties".
5. Open "Device Manager" tab, select "NE2000 Compatible" (in "Network adapters") and press "Properties"
6. Open "Resources", change values by selecting the properties and click on "Change Setting":
-```
-Interrupt Request: 10
-Input/Output Range: 0300 - 031F
-```
+| Option | Value |
+|:-------------------|:------------|
+| Interrupt Request | 10 |
+| Input/Output Range | 0300 - 031F |
7. In "Control Panel", open "Network", click on "Add", choose "Protocol" and select the following options:
-```
-Manufacturers: Microsoft
-Network Protocols: TCP/IP
-```
+| Option | Value |
+|:------------------|:----------|
+| Manufacturers | Microsoft |
+| Network Protocols | TCP/IP |
8. (optionally) Set "Primary Network Logon" to `Windows Logon`.
## Enabling sound manually
> [!NOTE]
-> If you don't have an install CD, use the Sound Blaster 16 driver from https://www.claunia.com/qemu/drivers/index.html.
+> If you don't have an install CD, use the Sound Blaster 16 driver from https://web.archive.org/web/20210814023225/https://www.claunia.com/qemu/drivers/index.html (unpack `sbw9xup.exe` as a zip archive).
1. Open "Start" menu, click on "Control Panel" and "Add New Hardware".
2. Press "Next", select "No" and select the following options:
-```
-Hardware type: Sound, video and game cotrollers
-Manufacturers: Creative Labs
-Models: Creative Labs Sound Blaster 16 or AWE-32
-```
+| Option | Value |
+|:--------------|:-----------------------------------------|
+| Hardware type | Sound, video and game cotrollers |
+| Manufacturers | Creative Labs |
+| Models | Creative Labs Sound Blaster 16 or AWE-32 |
3. Restart Windows.
diff --git a/docs/windows-nt.md b/docs/windows-nt.md
index e3474880..c0f21920 100644
--- a/docs/windows-nt.md
+++ b/docs/windows-nt.md
@@ -17,14 +17,14 @@
3. Run QEMU with the following settings for installation:
```sh
-qemu-system-i386 -m 64 -hda hdd.img -cpu pentium -M pc,acpi=off -cdrom InstallCD.iso
+qemu-system-i386 -m 64 -drive file=hdd.img,format=raw -cpu pentium -M pc,acpi=off -cdrom InstallCD.iso
```
4. Run `xcopy /v :\I386\ C:\install\` in a VM to copy all files, disable the CD-ROM driver.
-5. Run QEMU with the following settings:
+5. Run QEMU with the following settings:
```sh
-qemu-system-i386 -m 64 -hda hdd.img -cpu pentium -M pc,acpi=off
+qemu-system-i386 -m 64 -drive file=hdd.img,format=raw -cpu pentium -M pc,acpi=off
```
6. Run `C:\install\winnt /F /C` in a VM.
@@ -33,7 +33,7 @@ qemu-system-i386 -m 64 -hda hdd.img -cpu pentium -M pc,acpi=off
## Windows NT 3.51
-### Installing
+### Installing
> [!NOTE]
> In newer versions of QEMU, the Windows Setup may not work, you can use an older version of QEMU, PCem, 86Box or PCBox instead.
@@ -64,10 +64,10 @@ Recommended version: Windows NT 4.0 SP1
### Installing using QEMU
-1. Run QEMU with the following settings for installation:
+1. Run QEMU with the following settings for installation:
```sh
-qemu-system-i386 -m 64 -hda hdd.img -cdrom InstallCD.iso -cpu pentium -M pc,acpi=off
+qemu-system-i386 -m 64 -drive file=hdd.img,format=raw -cdrom InstallCD.iso -cpu pentium -M pc,acpi=off
```
2. On setup startup, press F5 and select "Standard PC".
@@ -90,10 +90,10 @@ var emulator = new V86({
### Installing using QEMU
-1. Run QEMU with the following settings for installation:
+1. Run QEMU with the following settings for installation:
```sh
-qemu-system-i386 -m 512 -hda hdd.img -cdrom InstallCD.iso
+qemu-system-i386 -m 512 -drive file=hdd.img,format=raw -cdrom InstallCD.iso
```
Optional:
@@ -107,7 +107,7 @@ After installation, change the computer type to "Standard PC" as described [here
1. Open Start menu, right-click on "My Computer", select "Manage"
2. Open Device Manager, open Computer, right-click on "ACPI Uniprocessor PC"
3. Select "Update Driver..." > "No, not this time"
-4. Select "Install from a list or specific location (Advanced)" > Next > "Don't search. I will choose the driver to install."
+4. Select "Install from a list or specific location (Advanced)" > Next > "Don't search. I will choose the driver to install."
5. Choose "Standard PC", press Next > Finish.
6. Restart the VM, follow multiple "Found New Hardware Wizard" dialogs with default options.
@@ -145,10 +145,10 @@ Models: Sound Blaster 16 or AWE32 or compatible (WDM)
### Installing using QEMU
-1. Run QEMU with the following settings for installation:
+1. Run QEMU with the following settings for installation:
```sh
-qemu-system-i386 -m 1024 -hda hdd.img -cdrom InstallCD.iso
+qemu-system-i386 -m 1024 -drive file=hdd.img,format=raw -cdrom InstallCD.iso
```
Optionally add `-accel kvm` (for Linux host), `-accel whpx` (for Windows host) or `-accel hvf` (for MacOS host) to use hypervisor acceleration.
diff --git a/eslint.config.mjs b/eslint.config.mjs
index 7f21000a..a2691db3 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -1,5 +1,54 @@
export default [
{
+ "languageOptions": {
+ "globals": {
+ "process": "readonly",
+ "window": "writable",
+ "navigator": "writable",
+ "location": "writable",
+ "document": "readonly",
+ "console": "readonly",
+ "crypto": "readonly",
+ "alert": "readonly",
+ "performance": "readonly",
+ "URL": "readonly",
+ "WebAssembly": "readonly",
+
+ "setTimeout": "readonly",
+ "setInterval": "readonly",
+ "clearTimeout": "readonly",
+ "clearInterval": "readonly",
+ "requestAnimationFrame": "readonly",
+ "cancelAnimationFrame": "readonly",
+
+ "Buffer": "readonly",
+ "FileReader": "readonly",
+ "TextEncoder": "readonly",
+ "TextDecoder": "readonly",
+ "fetch": "readonly",
+ "Headers": "readonly",
+ "Response": "readonly",
+ "WebSocket": "readonly",
+ "Blob": "readonly",
+ "File": "readonly",
+ "XMLHttpRequest": "readonly",
+ "URLSearchParams": "readonly",
+ "ImageData": "readonly",
+ "Image": "readonly",
+ "OffscreenCanvas": "readonly",
+ "BroadcastChannel": "readonly",
+
+ "AudioContext": "readonly",
+ "AudioWorkletProcessor": "readonly",
+ "webkitAudioContext": "readonly",
+ "AudioWorkletNode": "readonly",
+ "Worker": "readonly",
+ "postMessage": "readonly",
+ "importScripts": "readonly",
+
+ "DEBUG": "writable"
+ }
+ },
rules: {
"eol-last": "error",
//"no-extra-parens": "error",
@@ -69,7 +118,7 @@ export default [
"no-shadow-restricted-names": "error",
"no-sparse-arrays": "error",
"no-this-before-super": "error",
- //"no-undef": "error",
+ "no-undef": "error",
"no-unexpected-multiline": "error",
//"no-unreachable": "error",
"no-unsafe-finally": "error",
@@ -84,7 +133,8 @@ export default [
"no-with": "error",
"require-yield": "error",
"use-isnan": "error",
- "valid-typeof": "error"
+ "valid-typeof": "error",
+ "strict": "error"
}
}
];
diff --git a/examples/lang.html b/examples/lang.html
index 8404901f..e60a0aae 100644
--- a/examples/lang.html
+++ b/examples/lang.html
@@ -26,7 +26,7 @@ window.onload = function()
url: "../bios/vgabios.bin",
},
initial_state: {
- url: "../images/arch_state.bin.zst",
+ url: "../images/arch_state-v2.bin.zst",
},
filesystem: {
baseurl: "../images/arch/",
diff --git a/examples/nodejs.js b/examples/nodejs.js
index c2ec8246..2d0ee4c9 100755
--- a/examples/nodejs.js
+++ b/examples/nodejs.js
@@ -1,16 +1,11 @@
#!/usr/bin/env node
-"use strict";
-var fs = require("fs");
-var V86 = require("../build/libv86.js").V86;
+import path from "node:path";
+import fs from "node:fs";
+import url from "node:url";
+import { V86 } from "../build/libv86.mjs";
-function readfile(path)
-{
- return new Uint8Array(fs.readFileSync(path)).buffer;
-}
-
-var bios = readfile(__dirname + "/../bios/seabios.bin");
-var linux = readfile(__dirname + "/../images/linux4.iso");
+const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
process.stdin.setRawMode(true);
process.stdin.resume();
@@ -19,9 +14,14 @@ process.stdin.setEncoding("utf8");
console.log("Now booting, please stand by ...");
var emulator = new V86({
- bios: { buffer: bios },
- cdrom: { buffer: linux },
+ bios: { url: __dirname + "/../bios/seabios.bin" },
+ vga_bios: { url: __dirname + "/../bios/vgabios.bin" },
+ cdrom: { url: __dirname + "/../images/linux4.iso" },
autostart: true,
+ net_device: {
+ type: "virtio",
+ relay_url: "fetch",
+ },
});
emulator.add_listener("serial0-output-byte", function(byte)
diff --git a/examples/nodejs_state.js b/examples/nodejs_state.js
index 229f2c14..a11ca4fe 100755
--- a/examples/nodejs_state.js
+++ b/examples/nodejs_state.js
@@ -1,19 +1,13 @@
#!/usr/bin/env node
-"use strict";
-var fs = require("fs");
-var V86 = require("../build/libv86.js").V86;
+import fs from "node:fs";
+import url from "node:url";
+import { V86 } from "../build/libv86.mjs";
-function readfile(path)
-{
- return new Uint8Array(fs.readFileSync(path)).buffer;
-}
+const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
console.log("Use F2 to save the state and F3 to restore.");
-var bios = readfile(__dirname + "/../bios/seabios.bin");
-var linux = readfile(__dirname + "/../images/linux4.iso");
-
process.stdin.setRawMode(true);
process.stdin.resume();
process.stdin.setEncoding("utf8");
@@ -21,8 +15,8 @@ process.stdin.setEncoding("utf8");
console.log("Now booting, please stand by ...");
var emulator = new V86({
- bios: { buffer: bios },
- cdrom: { buffer: linux },
+ bios: { url: __dirname + "/../bios/seabios.bin" },
+ cdrom: { url: __dirname + "/../images/linux4.iso" },
autostart: true,
});
diff --git a/examples/worker.js b/examples/worker.js
index 90760064..b438d49e 100644
--- a/examples/worker.js
+++ b/examples/worker.js
@@ -1,5 +1,7 @@
importScripts("../build/libv86.js");
+/* global V86 */
+
var emulator = new V86({
wasm_path: "../build/v86.wasm",
memory_size: 32 * 1024 * 1024,
diff --git a/gen/generate_analyzer.js b/gen/generate_analyzer.js
index de31a8c3..5fb95388 100755
--- a/gen/generate_analyzer.js
+++ b/gen/generate_analyzer.js
@@ -1,16 +1,19 @@
#!/usr/bin/env node
-"use strict";
-const assert = require("assert").strict;
-const fs = require("fs");
-const path = require("path");
-const x86_table = require("./x86_table");
-const rust_ast = require("./rust_ast");
-const { hex, mkdirpSync, get_switch_value, get_switch_exist, finalize_table_rust } = require("./util");
+import assert from "node:assert/strict";
+import fs from "node:fs";
+import path from "node:path";
+import url from "node:url";
+
+import x86_table from "./x86_table.js";
+import * as rust_ast from "./rust_ast.js";
+import { hex, get_switch_value, get_switch_exist, finalize_table_rust } from "./util.js";
+
+const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
const OUT_DIR = path.join(__dirname, "..", "src/rust/gen/");
-mkdirpSync(OUT_DIR);
+fs.mkdirSync(OUT_DIR, { recursive: true });
const table_arg = get_switch_value("--table");
const gen_all = get_switch_exist("--all");
diff --git a/gen/generate_interpreter.js b/gen/generate_interpreter.js
index 8c09eddf..0aa89fae 100755
--- a/gen/generate_interpreter.js
+++ b/gen/generate_interpreter.js
@@ -1,16 +1,19 @@
#!/usr/bin/env node
-"use strict";
-const assert = require("assert").strict;
-const fs = require("fs");
-const path = require("path");
-const x86_table = require("./x86_table");
-const rust_ast = require("./rust_ast");
-const { hex, mkdirpSync, get_switch_value, get_switch_exist, finalize_table_rust } = require("./util");
+import assert from "node:assert/strict";
+import fs from "node:fs";
+import path from "node:path";
+import url from "node:url";
+
+import x86_table from "./x86_table.js";
+import * as rust_ast from "./rust_ast.js";
+import { hex, get_switch_value, get_switch_exist, finalize_table_rust } from "./util.js";
+
+const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
const OUT_DIR = path.join(__dirname, "..", "src/rust/gen/");
-mkdirpSync(OUT_DIR);
+fs.mkdirSync(OUT_DIR, { recursive: true });
const table_arg = get_switch_value("--table");
const gen_all = get_switch_exist("--all");
@@ -210,8 +213,9 @@ function gen_instruction_body_after_prefix(encodings, size)
}),
default_case: {
+ varname: "x",
body: [
- `if DEBUG { panic!("Bad instruction at {:x}", *instruction_pointer); }`,
+ `dbg_log!("#ud ${encoding.opcode.toString(16).toUpperCase()}/{} at {:x}", x, *instruction_pointer);`,
"trigger_ud();",
],
}
@@ -410,7 +414,7 @@ function gen_table()
"use crate::cpu::cpu::{after_block_boundary, modrm_resolve};",
"use crate::cpu::cpu::{read_imm8, read_imm8s, read_imm16, read_imm32s, read_moffs};",
- "use crate::cpu::cpu::{task_switch_test, trigger_ud, DEBUG};",
+ "use crate::cpu::cpu::{task_switch_test, trigger_ud};",
"use crate::cpu::instructions;",
"use crate::cpu::global_pointers::{instruction_pointer, prefixes};",
"use crate::prefix;",
@@ -475,7 +479,6 @@ function gen_table()
"use crate::cpu::cpu::{after_block_boundary, modrm_resolve};",
"use crate::cpu::cpu::{read_imm8, read_imm16, read_imm32s};",
"use crate::cpu::cpu::{task_switch_test, task_switch_test_mmx, trigger_ud};",
- "use crate::cpu::cpu::DEBUG;",
"use crate::cpu::instructions_0f;",
"use crate::cpu::global_pointers::{instruction_pointer, prefixes};",
"use crate::prefix;",
diff --git a/gen/generate_jit.js b/gen/generate_jit.js
index 104f0598..33f15882 100755
--- a/gen/generate_jit.js
+++ b/gen/generate_jit.js
@@ -1,16 +1,19 @@
#!/usr/bin/env node
-"use strict";
-const assert = require("assert").strict;
-const fs = require("fs");
-const path = require("path");
-const x86_table = require("./x86_table");
-const rust_ast = require("./rust_ast");
-const { hex, mkdirpSync, get_switch_value, get_switch_exist, finalize_table_rust } = require("./util");
+import assert from "node:assert/strict";
+import fs from "node:fs";
+import path from "node:path";
+import url from "node:url";
+
+import x86_table from "./x86_table.js";
+import * as rust_ast from "./rust_ast.js";
+import { hex, get_switch_value, get_switch_exist, finalize_table_rust } from "./util.js";
+
+const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
const OUT_DIR = path.join(__dirname, "..", "src/rust/gen/");
-mkdirpSync(OUT_DIR);
+fs.mkdirSync(OUT_DIR, { recursive: true });
const table_arg = get_switch_value("--table");
const gen_all = get_switch_exist("--all");
diff --git a/gen/rust_ast.js b/gen/rust_ast.js
index fb4f2e98..60d7c285 100644
--- a/gen/rust_ast.js
+++ b/gen/rust_ast.js
@@ -1,13 +1,11 @@
-"use strict";
-
-const assert = require("assert").strict;
+import assert from "node:assert/strict";
function indent(lines, how_much)
{
return lines.map(line => " ".repeat(how_much) + line);
}
-function print_syntax_tree(statements)
+export function print_syntax_tree(statements)
{
let code = [];
@@ -34,7 +32,8 @@ function print_syntax_tree(statements)
if(statement.default_case)
{
- cases.push(`_ => {`);
+ const varname = statement.default_case.varname || "_";
+ cases.push(`${varname} => {`);
cases.push.apply(cases, indent(print_syntax_tree(statement.default_case.body), 4));
cases.push(`}`);
}
@@ -77,7 +76,3 @@ function print_syntax_tree(statements)
return code;
}
-
-module.exports = {
- print_syntax_tree,
-};
diff --git a/gen/util.js b/gen/util.js
index 9325428c..c33ca963 100644
--- a/gen/util.js
+++ b/gen/util.js
@@ -1,14 +1,10 @@
-"use strict";
-
-const assert = require("assert");
-const fs = require("fs");
-const path = require("path");
-const process = require("process");
-const child_process = require("child_process");
+import fs from "node:fs";
+import path from "node:path";
+import process from "node:process";
const CYAN_FMT = "\x1b[36m%s\x1b[0m";
-function hex(n, pad)
+export function hex(n, pad)
{
pad = pad || 0;
let s = n.toString(16).toUpperCase();
@@ -16,12 +12,7 @@ function hex(n, pad)
return s;
}
-function mkdirpSync(dir)
-{
- fs.mkdirSync(dir, { recursive: true });
-}
-
-function get_switch_value(arg_switch)
+export function get_switch_value(arg_switch)
{
const argv = process.argv;
const switch_i = argv.indexOf(arg_switch);
@@ -33,22 +24,14 @@ function get_switch_value(arg_switch)
return null;
}
-function get_switch_exist(arg_switch)
+export function get_switch_exist(arg_switch)
{
return process.argv.includes(arg_switch);
}
-function finalize_table_rust(out_dir, name, contents)
+export function finalize_table_rust(out_dir, name, contents)
{
const file_path = path.join(out_dir, name);
fs.writeFileSync(file_path, contents);
console.log(CYAN_FMT, `[+] Wrote table ${name}.`);
}
-
-module.exports = {
- hex,
- mkdirpSync,
- get_switch_value,
- get_switch_exist,
- finalize_table_rust,
-};
diff --git a/gen/x86_table.js b/gen/x86_table.js
index e6663a0c..bd6039cf 100644
--- a/gen/x86_table.js
+++ b/gen/x86_table.js
@@ -1,7 +1,3 @@
-"use strict";
-
-const { hex } = require("./util");
-
// http://ref.x86asm.net/coder32.html
const zf = 1 << 6;
@@ -875,4 +871,5 @@ encodings.sort((e1, e2) => {
return o1 - o2 || e1.fixed_g - e2.fixed_g;
});
-module.exports = Object.freeze(encodings.map(entry => Object.freeze(entry)));
+const result = Object.freeze(encodings.map(entry => Object.freeze(entry)));
+export default result;
diff --git a/index.html b/index.html
index f4d01f3a..9b2bbfc7 100644
--- a/index.html
+++ b/index.html
@@ -2,10 +2,13 @@
v86
-
+
-
+
+
+
+