Compare commits

...

8 Commits

Author SHA1 Message Date
cdo 277c06b999 Add HEX and DECIMAL to prelude 2026-03-02 16:10:54 +00:00
cdo 33047a49e0 Add more information to the README 2026-03-02 16:10:54 +00:00
cdo f9447d22d1 Add favicon 2026-03-02 16:10:54 +00:00
cdo 8ed8bbad3e Set output rows based on window size 2026-03-02 16:10:54 +00:00
cdo 7f4d900688 Fix EMIT-DIGIT 2026-03-02 16:10:54 +00:00
cdo 54be0a8c0e Fix output width at 80 chars and remove trailing spaces 2026-03-02 16:10:54 +00:00
cdo 832ce55108 Implement basic scrolling in emu.js 2026-03-02 16:10:54 +00:00
cdo 259aa730f7 Add copyright and license message to the banner 2026-03-02 16:10:54 +00:00
6 changed files with 63 additions and 5 deletions
+11
View File
@@ -1,5 +1,16 @@
# 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
To run, first compile the WebAssembly module:
+41 -4
View File
@@ -13,7 +13,6 @@ const PERIPHS_SIZE = 69; // Nice
const POLL_INTERVAL_MS = 20;
const COLS = 80;
const ROWS = 36;
const TAB_WIDTH = 8;
const CURSOR_IDLE_TIME_MS = 1000;
@@ -36,8 +35,9 @@ class Emulator {
this.rx_queue = [];
this.timer = setInterval(() => this.poll(), POLL_INTERVAL_MS);
this.rows = this.max_rows();
this.grid = Array.from(
{ length: ROWS },
{ length: this.rows },
() => new Array(COLS).fill(' '));
this.cursor = { x: 0, y: 0 };
this.range = {
@@ -47,6 +47,7 @@ class Emulator {
this.idle_timer = null;
this.input_enable = false;
document.addEventListener('keydown', (e) => this.handle_keydown(e));
window.addEventListener('resize', () => this.handle_resize());
this.worker = new Worker('boot.js');
this.worker.postMessage(this.mem);
@@ -142,6 +143,8 @@ class Emulator {
this.cursor_move(1, 0);
} else if (e.key == 'Enter') {
this.cursor.y = this.range.end.y + 1;
while (this.cursor.y >= this.rows)
this.scroll();
this.cursor.x = 0;
this.submit_line();
Object.assign(this.range.start, this.cursor);
@@ -226,7 +229,7 @@ class Emulator {
next_cell(cell) {
if (cell.x < COLS - 1)
return { x: cell.x + 1, y: cell.y };
else if (cell.y < ROWS - 1)
else if (cell.y < this.rows - 1)
return { x: 0, y: cell.y + 1 };
else
return null;
@@ -239,6 +242,8 @@ class Emulator {
this.grid[cell.y][cell.x] = this.grid[prev.y][prev.x];
cell = prev;
}
if (this.next_cell(this.range.end) == null)
this.scroll();
this.range.end = this.next_cell(this.range.end);
}
@@ -262,7 +267,7 @@ class Emulator {
return '<span id="cursor">' + ec + '</span>';
else
return ec;
}).join('');
}).join('').trimEnd();
}).join('\n');
this.output.innerHTML = html;
}
@@ -283,6 +288,38 @@ class Emulator {
return c;
}
}
scroll() {
this.grid.shift()
this.grid.push(new Array(COLS).fill(' '));
this.cursor.y -= 1;
this.range.start.y -= 1;
this.range.end.y -= 1;
}
max_rows() {
const style = getComputedStyle(this.output);
const line_height = parseFloat(style.lineHeight);
const margin_top = parseFloat(style.marginTop);
const margin_bottom = parseFloat(style.marginBottom);
const viewport_height = window.innerHeight;
const output_height = viewport_height - margin_top - margin_bottom;
return Math.floor(output_height / line_height) - 1;
}
handle_resize() {
this.rows = this.max_rows();
while (this.grid.length < this.rows)
this.grid.push(new Array(COLS).fill(' '));
while (this.grid.length > this.rows) {
this.grid.shift()
this.cursor.y -= 1;
this.range.start.y -= 1;
this.range.end.y -= 1;
}
this.flush_output();
}
}
window.addEventListener('DOMContentLoaded', () => {
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 499 B

+1
View File
@@ -3,6 +3,7 @@
<head>
<title>Wipforth</title>
<link rel="stylesheet" type="text/css" href="styles.css"/>
<link rel="icon" type="image/png" href="favicon.png"/>
</head>
<body>
<script type="text/javascript" src="emu.js"></script>
+9 -1
View File
@@ -88,7 +88,7 @@
; IMMEDIATE
: EMIT-DIGIT
DUP 10 < IF CHAR 0 ELSE CHAR A THEN
DUP 10 < IF CHAR 0 ELSE 10 - CHAR A THEN
+ EMIT
;
@@ -165,6 +165,10 @@ CHAR . EMIT
: NIP SWAP DROP ;
: HEX 16 BASE ! ;
: DECIMAL 10 BASE ! ;
: '
WORD FIND DUP 0<> IF
>CFA
@@ -258,6 +262,10 @@ CHAR . EMIT
." /_/ " CR
CR
." Wipforth " VERSION-PRINT CR
." Copyright (c) Camden Dixie O'Brien" CR
CR
." Wipforth is freely available to use, modify and distribute for personal use" CR
." under the Komorebi license, version 2.0.0." CR
CR
;
+1
View File
@@ -14,6 +14,7 @@ body {
}
#output {
width: 80ch;
margin: 1.5em auto;
white-space: pre;
}