Files
wipforth/README.md
2026-03-18 14:57:19 +00:00

103 lines
3.3 KiB
Markdown

# 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 <http://localhost:8080> 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.