Files
wipforth/README.md
2026-03-18 15:04:32 +00:00

104 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, basically any
HTTP server will do as long as it sets the appropriate response
headers for `SharedMemoryBuffer` use:
- `Cross-Origin-Opener-Policy: same-origin`
- `Cross-Origin-Embedder-Policy: require-corp`
So, if you don't have Guile on your system you can use something else
like Python's `http.server`.
**NOTE**: 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.