Files
wipforth/README.md
2026-03-18 14:49:30 +00:00

102 lines
3.2 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 binary 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 is simple [Guile](https://www.gnu.org/software/guile/) script
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.
Since everything is bootstrapped on the client, you only need an HTTP
server, so if you don't have Guile on your system you can bring your
own. 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.