# Wipforth Wipforth is a Forth implementation that runs in the WebAssembly virtual machine. The system is bootstrapped from source on page load: the only non-text file is the favicon :) I/O is done via memory-mapped peripherals, which are emulated in JavaScript. - For the Forth kernel, see [wipforth.ws](./wipforth.ws) - For the emulator, see [emu.js](./emu.js) - For the assembler, see [asm.js](./asm.js) - For the prelude (Forth code loaded right after the kernel boots), see [prelude.f](./prelude.f) - For a description of the peripherals, see the [Peripherals](#peripherals) section below. ## Building and Running Locally There's a [Guile](https://www.gnu.org/software/guile/) script in the repo you can use for this: ``` guile server.scm ``` You should then be able to open in a browser and use the system from there. However, since everything is bootstrapped on the client, you only *need* an appropriate HTTP server, so if you don't have Guile on your system you can use something else like Python's `http.server`. The only requirement is that it sets the cross-origin isolation headers required for `SharedMemoryBuffer` use: - `Cross-Origin-Opener-Policy: same-origin` - `Cross-Origin-Embedder-Policy: require-corp` You should **definitely not** use `server.scm` to serve the application on the open internet or anything like that; I just hacked it together for testing on localhost during development and it's probably hilariously insecure. ## End-to-End Tests There's a (fairly minimal at the moment) end-to-end test suite defined in [tests.scm](./tests.scm). To run it you'll need: - [Guile](https://www.gnu.org/software/guile/) again (no substitute this time, sorry) - [guile-json](https://github.com/aconchillo/guile-json) - Firefox I'm also pretty sure it won't work on a non-POSIX system, though I haven't tried it. Given that's all sorted, you should be able to run: ``` guile tests.scm ``` It will print a JUnit XML report to standard out. You can pretty-print it with `xmllint` if you have it installed: ``` guile tests.scm | xmllint --format - ``` ## Peripherals ### Terminal | Name | Address | Size / B | Access | |--------|---------|----------|--------------| | TXBUF | 00h | 32 | write | | RXBUF | 20h | 32 | read | | TXHEAD | 40h | 4 | atomic read | | TXTAIL | 44h | 4 | atomic write | | RXHEAD | 48h | 4 | atomic write | | RXTAIL | 4Ch | 4 | atomic read | For both sending (`TX`) and receiving (`RX`), there are three registers: `xBUF`, `xHEAD` and `xTAIL`: - `xBUF` registers are 32-byte FIFO ring buffers used for data - The `xHEAD` and `xTAIL` registers specify the start and end of data in the ring buffer, `xHEAD` being the offset of the first byte of data, and `xTAIL` being the offset of the first byte *after* the data. In order to be distinguishable from the empty state, the ring buffers must never be completely full -- there must always be *at least one* unoccupied byte between the tail and the head. ### System status | Name | Address | Size / B | Access | |----------|---------|----------|--------------| | SYSREADY | 50h | 1 | atomic write | The `SYSREADY` register is used to indicate when the system has booted up and is ready for user input.