108 lines
3.2 KiB
Markdown
108 lines
3.2 KiB
Markdown
# Wipforth
|
|
|
|
Wipforth is a simple Forth implementation that runs in the WebAssembly
|
|
virtual machine. It does I/O via memory-mapped peripherals, which are
|
|
emulated in JavaScript.
|
|
|
|
- For the Forth kernel, see [wipforth.wat](./wipforth.wat)
|
|
- For the JavaScript emulator, see [emu.js](./emu.js)
|
|
- For the Forth prelude, which is loaded at start-up, see
|
|
[prelude.f](./prelude.f)
|
|
- For a description of the peripherals, see the
|
|
[Peripherals](#peripherals) section below.
|
|
|
|
## Building and Running Locally
|
|
|
|
You'll need:
|
|
|
|
- [WABT](https://github.com/WebAssembly/wabt) (not for long >:D)
|
|
- [Guile](https://www.gnu.org/software/guile/) (or bring your own HTTP
|
|
server -- see note below)
|
|
|
|
To run, first compile the WebAssembly module:
|
|
|
|
```
|
|
wat2wasm --enable-threads wipforth.wat
|
|
```
|
|
|
|
Then run the development server:
|
|
|
|
```
|
|
guile server.scm
|
|
```
|
|
|
|
You should then be able to open <http://localhost:8080> in a browser
|
|
and use the system from there.
|
|
|
|
**NOTE**: The server is very simple and just serves the files with the
|
|
cross-origin isolation headers required for `SharedMemoryBuffer` use.
|
|
You could use any HTTP server that sets these headers.
|
|
|
|
You should **definitely not** use the development server to serve the
|
|
application on the open internet; 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:
|
|
|
|
```
|
|
guile tests.scm | xmllint --format -
|
|
```
|
|
|
|
Though, of course, this will require that you have `xmllint` on your
|
|
system.
|
|
|
|
## 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.
|