Create initial emulator and hello world demo
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
*.wasm
|
||||||
108
LICENSE.md
Normal file
108
LICENSE.md
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
# Komorebi License
|
||||||
|
|
||||||
|
Version 2.0.0
|
||||||
|
|
||||||
|
## Acceptance
|
||||||
|
|
||||||
|
In order to get any license under these terms, you must agree
|
||||||
|
to them as both strict obligations and conditions to all
|
||||||
|
your licenses.
|
||||||
|
|
||||||
|
## Copyright License
|
||||||
|
|
||||||
|
The licensor grants you a copyright license for the software
|
||||||
|
to do everything you might do with the software that would
|
||||||
|
otherwise infringe the licensor's copyright in it for any
|
||||||
|
permitted purpose. However, you may only distribute the source
|
||||||
|
code of the software according to the [Distribution License](
|
||||||
|
#distribution-license), you may only make changes according
|
||||||
|
to the [Changes License](#changes-license), and you may not
|
||||||
|
otherwise distribute the software or new works based on the
|
||||||
|
software.
|
||||||
|
|
||||||
|
## Distribution License
|
||||||
|
|
||||||
|
The licensor grants you an additional copyright license to
|
||||||
|
distribute copies of the source code of the software. Your
|
||||||
|
license to distribute covers distributing the source code of
|
||||||
|
the software with changes permitted by the [Changes License](
|
||||||
|
#changes-license).
|
||||||
|
|
||||||
|
## Changes License
|
||||||
|
|
||||||
|
The licensor grants you an additional copyright license to
|
||||||
|
make changes for any permitted purpose.
|
||||||
|
|
||||||
|
## Patent License
|
||||||
|
|
||||||
|
The licensor grants you a patent license for the software that
|
||||||
|
covers patent claims the licensor can license, or becomes able
|
||||||
|
to license, that you would infringe by using the software.
|
||||||
|
|
||||||
|
## Personal Uses
|
||||||
|
|
||||||
|
Personal use for research, experiment, and testing for
|
||||||
|
the benefit of public knowledge, personal study, private
|
||||||
|
entertainment, hobby projects, amateur pursuits, or religious
|
||||||
|
observance, without any anticipated commercial application,
|
||||||
|
is use for a permitted purpose.
|
||||||
|
|
||||||
|
## Fair Use
|
||||||
|
|
||||||
|
You may have "fair use" rights for the software under the
|
||||||
|
law. These terms do not limit them.
|
||||||
|
|
||||||
|
## No Other Rights
|
||||||
|
|
||||||
|
These terms do not allow you to sublicense or transfer any of
|
||||||
|
your licenses to anyone else, or prevent the licensor from
|
||||||
|
granting licenses to anyone else. These terms do not imply
|
||||||
|
any other licenses.
|
||||||
|
|
||||||
|
## Patent Defense
|
||||||
|
|
||||||
|
If you make any written claim that the software infringes or
|
||||||
|
contributes to infringement of any patent, your patent license
|
||||||
|
for the software granted under these terms ends immediately. If
|
||||||
|
your company makes such a claim, your patent license ends
|
||||||
|
immediately for work on behalf of your company.
|
||||||
|
|
||||||
|
## Violations
|
||||||
|
|
||||||
|
The first time you are notified in writing that you have
|
||||||
|
violated any of these terms, or done anything with the software
|
||||||
|
not covered by your licenses, your licenses can nonetheless
|
||||||
|
continue if you come into full compliance with these terms,
|
||||||
|
and take practical steps to correct past violations, within
|
||||||
|
32 days of receiving notice. Otherwise, all your licenses
|
||||||
|
end immediately.
|
||||||
|
|
||||||
|
## No Liability
|
||||||
|
|
||||||
|
***As far as the law allows, the software comes as is, without
|
||||||
|
any warranty or condition, and the licensor will not be liable
|
||||||
|
to you for any damages arising out of these terms or the use
|
||||||
|
or nature of the software, under any kind of legal claim.***
|
||||||
|
|
||||||
|
## Definitions
|
||||||
|
|
||||||
|
The **licensor** is the individual or entity offering these
|
||||||
|
terms, and the **software** is the software the licensor makes
|
||||||
|
available under these terms.
|
||||||
|
|
||||||
|
**You** refers to the individual or entity agreeing to these
|
||||||
|
terms.
|
||||||
|
|
||||||
|
**Your company** is any legal entity, sole proprietorship,
|
||||||
|
or other kind of organization that you work for, plus all
|
||||||
|
organizations that have control over, are under the control of,
|
||||||
|
or are under common control with that organization. **Control**
|
||||||
|
means ownership of substantially all the assets of an entity,
|
||||||
|
or the power to direct its management and policies by vote,
|
||||||
|
contract, or otherwise. Control can be direct or indirect.
|
||||||
|
|
||||||
|
**Your licenses** are all the licenses granted to you for the
|
||||||
|
software under these terms.
|
||||||
|
|
||||||
|
**Use** means anything you do with the software requiring one
|
||||||
|
of your licenses.
|
||||||
49
README.md
Normal file
49
README.md
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
# Wipforth
|
||||||
|
|
||||||
|
## Building and Running
|
||||||
|
|
||||||
|
To run, first compile the WebAssembly module:
|
||||||
|
|
||||||
|
```
|
||||||
|
wat2wasm --enable-threads wipforth.wat
|
||||||
|
```
|
||||||
|
|
||||||
|
Then run the server:
|
||||||
|
|
||||||
|
```
|
||||||
|
python3 server.py
|
||||||
|
```
|
||||||
|
|
||||||
|
You should then be able to open <http://localhost:8080> in a browser
|
||||||
|
and use the system from there.
|
||||||
|
|
||||||
|
**NOTE**: The server is just a very simple instantiation of Python's
|
||||||
|
built-in `http.server` that sets the cross-origin headers required for
|
||||||
|
`SharedMemoryBuffer` use. You could use any HTTP server that sets
|
||||||
|
these headers.
|
||||||
|
|
||||||
|
## Peripherals
|
||||||
|
|
||||||
|
# Serial
|
||||||
|
|
||||||
|
| Name | Offset | Size / B | Access |
|
||||||
|
|--------|--------|----------|--------------|
|
||||||
|
| TXBUF | 0 | 32 | write |
|
||||||
|
| RXBUF | 32 | 32 | read |
|
||||||
|
| TXDATA | 64 | 1 | atomic write |
|
||||||
|
| TXHEAD | 65 | 1 | atomic read |
|
||||||
|
| TXTAIL | 66 | 1 | atomic write |
|
||||||
|
| RXDATA | 67 | 1 | atomic read |
|
||||||
|
| RXHEAD | 68 | 1 | atomic write |
|
||||||
|
| RXTAIL | 69 | 1 | atomic read |
|
||||||
|
|
||||||
|
For both sending (`TX`) and receiving (`RX`), there are four
|
||||||
|
registers: `xBUF`, `xDATA`, `xHEAD` and `xTAIL`:
|
||||||
|
|
||||||
|
- `xBUF` registers are 32-byte FIFO ring buffers used for data
|
||||||
|
- The `xDATA` registers indicate whether data is available (0 for
|
||||||
|
data, FFh for no data)
|
||||||
|
- The `xHEAD` and `xTAIL` registers specify the start and end of
|
||||||
|
data in the FIFO, `xHEAD` being the offset of the first byte of
|
||||||
|
data, and `xTAIL` being the offset of the first byte after the
|
||||||
|
data.
|
||||||
6
boot.js
Normal file
6
boot.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
self.onmessage = async (e) => {
|
||||||
|
const exports = { emu: { mem: e.data } };
|
||||||
|
const mod = await WebAssembly.instantiateStreaming(
|
||||||
|
fetch('wipforth.wasm'), exports)
|
||||||
|
mod.instance.exports.reset();
|
||||||
|
};
|
||||||
69
emu.js
Normal file
69
emu.js
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
const TXBUF = 0;
|
||||||
|
const RXBUF = 32;
|
||||||
|
const TXDATA = 64;
|
||||||
|
const TXHEAD = 65;
|
||||||
|
const TXTAIL = 66;
|
||||||
|
const RXDATA = 67;
|
||||||
|
const RXHEAD = 68;
|
||||||
|
const RXTAIL = 69;
|
||||||
|
|
||||||
|
const TXBUF_SIZE = 32;
|
||||||
|
const RXBUF_SIZE = 32;
|
||||||
|
const PERIPHS_SIZE = 70;
|
||||||
|
|
||||||
|
const POLL_INTERVAL_MS = 20;
|
||||||
|
|
||||||
|
class Emulator {
|
||||||
|
constructor() {
|
||||||
|
this.mem = new WebAssembly.Memory({
|
||||||
|
initial: 1,
|
||||||
|
maximum: 1,
|
||||||
|
shared: true
|
||||||
|
});
|
||||||
|
this.mem_u8 = new Uint8Array(this.mem.buffer);
|
||||||
|
for (let i = 0; i < PERIPHS_SIZE; ++i)
|
||||||
|
this.mem_u8[i] = 0;
|
||||||
|
|
||||||
|
this.decoder = new TextDecoder('utf-8');
|
||||||
|
|
||||||
|
this.output = document.getElementById('output');
|
||||||
|
this.input = document.getElementById('input');
|
||||||
|
|
||||||
|
this.timer = setInterval(() => this.poll(), POLL_INTERVAL_MS);
|
||||||
|
|
||||||
|
this.worker = new Worker('boot.js');
|
||||||
|
this.worker.postMessage(this.mem);
|
||||||
|
}
|
||||||
|
|
||||||
|
poll() {
|
||||||
|
const txdata = Atomics.load(this.mem_u8, TXDATA);
|
||||||
|
if (txdata !== 0)
|
||||||
|
this.handle_txdata();
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_txdata() {
|
||||||
|
const head = Atomics.load(this.mem_u8, TXHEAD);
|
||||||
|
const tail = Atomics.load(this.mem_u8, TXTAIL);
|
||||||
|
|
||||||
|
const data = [];
|
||||||
|
let i = head;
|
||||||
|
do {
|
||||||
|
data.push(this.mem_u8[TXBUF + i]);
|
||||||
|
i = (i + 1) % TXBUF_SIZE;
|
||||||
|
} while (i !== tail);
|
||||||
|
|
||||||
|
Atomics.store(this.mem_u8, TXHEAD, tail);
|
||||||
|
|
||||||
|
// More data could have been added -- only clear TXDATA if
|
||||||
|
// tail is unchanged.
|
||||||
|
if (tail === Atomics.load(this.mem_u8, TXTAIL))
|
||||||
|
Atomics.store(this.mem_u8, TXDATA, 0);
|
||||||
|
|
||||||
|
const str = this.decoder.decode(new Uint8Array(data));
|
||||||
|
this.output.innerText += str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('DOMContentLoaded', () => {
|
||||||
|
window.emu = new Emulator();
|
||||||
|
});
|
||||||
12
index.html
Normal file
12
index.html
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Wipforth</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="styles.css"/>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script type="text/javascript" src="emu.js"></script>
|
||||||
|
<div id="output"></div>
|
||||||
|
<input id="input" type="text" autofocus></input>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
16
server.py
Normal file
16
server.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
from http.server import HTTPServer, SimpleHTTPRequestHandler
|
||||||
|
import sys
|
||||||
|
|
||||||
|
class CORSRequestHandler(SimpleHTTPRequestHandler):
|
||||||
|
def end_headers(self):
|
||||||
|
self.send_header(
|
||||||
|
'Cross-Origin-Opener-Policy', 'same-origin')
|
||||||
|
self.send_header(
|
||||||
|
'Cross-Origin-Embedder-Policy', 'require-corp')
|
||||||
|
self.send_header(
|
||||||
|
'Cache-Control', 'no-store, no-cache, must-revalidate')
|
||||||
|
super().end_headers()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
server = HTTPServer(('localhost', 8080), CORSRequestHandler)
|
||||||
|
server.serve_forever()
|
||||||
17
styles.css
Normal file
17
styles.css
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
body {
|
||||||
|
line-height: 1.4em;
|
||||||
|
font-family: 'Courier 10 Pitch', monospace;
|
||||||
|
font-size: 12pt;
|
||||||
|
background-color: black;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
#output {
|
||||||
|
margin: 1.4em auto;
|
||||||
|
width: 80em;
|
||||||
|
height: 48em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#input {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
22
wipforth.wat
Normal file
22
wipforth.wat
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
(module
|
||||||
|
(import "emu" "mem" (memory 1 1 shared))
|
||||||
|
|
||||||
|
(func (export "reset")
|
||||||
|
;; Write message into TXBUF
|
||||||
|
(i32.store8 (i32.const 0x0) (i32.const 0x48)) ;; H
|
||||||
|
(i32.store8 (i32.const 0x1) (i32.const 0x65)) ;; e
|
||||||
|
(i32.store8 (i32.const 0x2) (i32.const 0x6c)) ;; l
|
||||||
|
(i32.store8 (i32.const 0x3) (i32.const 0x6c)) ;; l
|
||||||
|
(i32.store8 (i32.const 0x4) (i32.const 0x6f)) ;; o
|
||||||
|
(i32.store8 (i32.const 0x5) (i32.const 0x2c)) ;; ,
|
||||||
|
(i32.store8 (i32.const 0x6) (i32.const 0x20)) ;; <space>
|
||||||
|
(i32.store8 (i32.const 0x7) (i32.const 0x77)) ;; w
|
||||||
|
(i32.store8 (i32.const 0x8) (i32.const 0x6f)) ;; o
|
||||||
|
(i32.store8 (i32.const 0x9) (i32.const 0x72)) ;; r
|
||||||
|
(i32.store8 (i32.const 0xa) (i32.const 0x6c)) ;; l
|
||||||
|
(i32.store8 (i32.const 0xb) (i32.const 0x64)) ;; d
|
||||||
|
(i32.store8 (i32.const 0xc) (i32.const 0x21)) ;; !
|
||||||
|
|
||||||
|
;; Update TXTAIL and set TXDATA
|
||||||
|
(i32.atomic.store8 (i32.const 0x42) (i32.const 0xd))
|
||||||
|
(i32.atomic.store8 (i32.const 0x40) (i32.const 0xff))))
|
||||||
Reference in New Issue
Block a user