Skip to content

Commit

Permalink
Fix issue with OneRegTwoImm decoding and add Game of Life example o…
Browse files Browse the repository at this point in the history
…n the website. (#9)

* Render game of life.

* Perform multiple steps at once.

* QA.
  • Loading branch information
tomusdrw authored Dec 6, 2024
1 parent 280d9e6 commit f649402
Show file tree
Hide file tree
Showing 9 changed files with 233 additions and 65 deletions.
11 changes: 9 additions & 2 deletions assembly/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,17 @@ export function resetGenericWithMemory(
interpreter = int;
}

export function nextStep(): boolean {
export function nextStep(steps: number = 1): boolean {
if (interpreter !== null) {
const int = <Interpreter>interpreter;
return int.nextStep();
let isOk = true;
for (let i = 0; i < steps; i++) {
isOk = int.nextStep();
if (!isOk) {
return false;
}
}
return isOk;
}
return false;
}
Expand Down
11 changes: 7 additions & 4 deletions assembly/arguments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export enum Arguments {
/** How many numbers in `Args` is relevant for given `Arguments`. */
export const RELEVANT_ARGS = [<u8>0, 1, 2, 1, 2, 3, 3, 2, 3, 3, 4, 3];

@unmanaged
// @unmanaged
export class Args {
a: u32 = 0;
b: u32 = 0;
Expand Down Expand Up @@ -67,8 +67,11 @@ export const DECODERS: ArgsDecoder[] = [
},
//DECODERS[Arguments.OneRegTwoImm] =
(data: Uint8Array) => {
const result = twoImm(data.subarray(1));
return asArgs(nibbles(data[0]).low, result.a, result.b, result.c);
const first = nibbles(data[0]);
const split = first.hig + 1;
const immA = decodeI32(data.subarray(1, split));
const immB = decodeI32(data.subarray(split));
return asArgs(first.low, immA, immB, 0);
},
// DECODERS[Arguments.OneRegOneImmOneOff] =
(data: Uint8Array) => {
Expand Down Expand Up @@ -104,7 +107,7 @@ export const DECODERS: ArgsDecoder[] = [
},
];

@unmanaged
// @unmanaged
class Nibbles {
low: u8 = 0;
hig: u8 = 0;
Expand Down
2 changes: 1 addition & 1 deletion assembly/codec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export class Decoder {
}
}

@unmanaged
// @unmanaged
export class ValOffset<T> {
constructor(
public readonly value: T,
Expand Down
2 changes: 1 addition & 1 deletion assembly/instructions-outcome.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export enum Outcome {
Result = 3,
}

@unmanaged
// @unmanaged
export class OutcomeData {
outcome: Outcome = Outcome.Ok;
staticJump: i32 = 0;
Expand Down
4 changes: 2 additions & 2 deletions assembly/interpreter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ export class Interpreter {
}
}

@unmanaged
// @unmanaged
class BranchResult {
isOkay: boolean = false;
newPc: u32 = 0;
Expand All @@ -163,7 +163,7 @@ enum DjumpStatus {
PANIC = 2,
}

@unmanaged
// @unmanaged
class DjumpResult {
status: DjumpStatus = DjumpStatus.OK;
newPc: u32 = 0;
Expand Down
4 changes: 2 additions & 2 deletions assembly/memory.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Access, Arena, PAGE_SIZE, PAGE_SIZE_SHIFT, Page, PageIndex } from "./memory-page";

@unmanaged
// @unmanaged
export class MaybePageFault {
isFault: boolean = false;
fault: u32 = 0;
}

@unmanaged
// @unmanaged
export class Result {
ok: u32 = 0;
fault: MaybePageFault = new MaybePageFault();
Expand Down
156 changes: 156 additions & 0 deletions web/conway.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
<!DOCTYPE html>
<html lang="en">
<head>
<link type="text/css" rel="stylesheet" href="./styles.css" />
<style>
.hidden {
display: none;
}
</style>
<script type="module" defer>
import { resetGenericWithMemory, getPageDump, nextStep } from "./build/release.js";
const $out = document.querySelector('#output');
const $run = document.querySelector('#run');
const $stop = document.querySelector('#stop');
const $step = document.querySelector('#steps');

const steps = {
count: 0,
startTime: null,
lastTime: null,
};

let isRunning = true;
let lastMemory = null;
let lastRenderCount = 0;
let stepsAtOnce = parseInt($step.value);


setTimeout(() => {
pvmInit();
}, 0);

$step.addEventListener('change', () => {
stepsAtOnce = parseInt($step.value);
});

$run.addEventListener('click', () => {
$run.classList.add('hidden');
$stop.classList.remove('hidden');

isRunning = true;
steps.count = 0;
steps.startTime = performance.now();

pvmRun();
});

$stop.addEventListener('click', () => {
$stop.classList.add('hidden');
$run.classList.remove('hidden');
pvmStop();
});

function pvmInit() {
const registers = Array(13 * 4).fill(0);
const pageMap = new Uint8Array(
[...u32_le_bytes(0), ...u32_le_bytes(4096), 1]
);
const chunks = new Uint8Array();
resetGenericWithMemory(
CODE,
registers,
pageMap,
chunks,
10_000_000n
);
refreshCanvas();
}

function isSame(memA, memB) {
if (memA === null || memB === null) {
return false;
}

for (let i = 0; i < memA.length; i++) {
if (memA[i] !== memB[i]) {
return false;
}
}
return true;
}

function refreshCanvas() {
const CELLS = 64;
const memory = getPageDump(0).subarray(0, CELLS);
if (isSame(memory, lastMemory) && (steps.lastTime - steps.startTime < 250)) {
return;
}
lastMemory = memory;
lastRenderCount = steps.count;
const cells = Array.from(memory).map(x => (x === 0xff) ? '⬛' :'⬜');
const toPrint = [];
let i = 0;
while (i < CELLS) {
const row = cells.slice(i, i + 8);
toPrint.push(row.join(' '));
i += 8;
}

const timeMs = steps.lastTime - steps.startTime;
let perSec = timeMs === 0 ? 0 : 1000 * steps.count / timeMs;
perSec = Number.isNaN(perSec) ? 0.0 : perSec;
const stats = `Steps: ${steps.count.toString().padStart(10, ' ')} (${perSec.toFixed(1)} steps/sec)`;
$out.innerHTML = `${toPrint.join('\n')}\n${stats}`;
}

function pvmRun() {
if (!isRunning) {
return;
}
steps.count += stepsAtOnce;
steps.lastTime = performance.now();
isRunning = nextStep(stepsAtOnce);
if (!isRunning) {
$stop.click();
}
refreshCanvas();
setTimeout(pvmRun, 0);
}
function pvmStop() {
isRunning = false;
}

function u32_le_bytes(val) {
const out = new Uint8Array(4);
out[0] = val & 0xff;
out[1] = (val >> 8) & 0xff;
out[2] = (val >> 16) & 0xff;
out[3] = (val >> 24) & 0xff;
return out;
}

const CODE = [0,0,128,222,62,1,3,255,0,62,1,11,255,0,62,1,19,255,0,62,1,18,255,0,62,1,9,255,0,5,176,0,4,1,255,17,2,17,1,7,17,8,166,0,4,2,255,17,2,34,1,7,18,8,241,35,19,8,8,35,3,5,47,2,51,128,0,11,52,18,68,1,15,20,1,14,44,21,2,25,50,21,3,21,5,8,7,21,3,6,5,11,2,51,128,26,3,255,0,5,205,2,51,128,26,3,5,198,4,5,2,52,128,0,2,68,255,11,70,18,102,1,8,101,5,2,68,2,11,70,18,102,1,8,101,5,2,68,247,11,70,18,102,1,8,101,5,2,68,16,11,70,18,102,1,8,101,5,2,68,1,11,70,18,102,1,8,101,5,2,68,254,11,70,18,102,1,8,101,5,2,68,240,11,70,18,102,1,8,101,5,2,68,2,11,70,18,102,1,8,101,5,5,117,255,4,1,17,2,19,128,0,1,18,3,50,2,17,4,7,17,64,69,255,5,240,33,132,16,146,9,153,72,138,18,17,69,137,82,69,74,82,146,146,148,164,36,37,41,73,73,26,149,16];
</script>
</head>
<body>
<h3>Check out <a href="https://fluffylabs.dev">other fluffy stuff.</a></h3>
<h1>🍍 Anan-AS - Game Of Life</h1>
<p>Download:
<a href="./build/release.wasm">release.wasm</a>|<a href="./build/release.wat">wat</a>
or
<a href="./build/debug.wasm">debug.wasm</a>|<a href="./build/debug.wat">wat</a>
</p>
<p>
<a href="index.html">Home</a>
</p>
<pre id="output">
</pre>
<button id="run">▶️ Start</button>
<button id="stop" class="hidden">▶️ Stop</button>
<label>
Steps per refresh: <input type="number" min="1" max="1000" id="steps" value="30">
</label>
<a href="https://pvm.fluffylabs.dev">Looking for a better disassembler for PVM?</a>
</body>
</html>
57 changes: 4 additions & 53 deletions web/index.html
Original file line number Diff line number Diff line change
@@ -1,59 +1,7 @@
<!DOCTYPE html>
<html lang="en">
<head>
<style>
#root, html {
font-size: 18px;
font-family: monospace;
}
* {
font-size: 1rem;
}
h1 {
font-size: 2rem;
}
h3 {
font-size: 1.4rem;
text-align: right;
}
body {
width: 70vw;
max-width: 1024px;
margin: 2rem auto;
display: flex;
flex-direction: column;
gap: 1rem;
}
#file {
display: none;
}
button {
padding: 1rem;
cursor: pointer;
}
textarea {
padding: 1rem;
}
textarea.error {
border: 2px solid #e22;
}
pre {
border: 1px solid #ccc;
background: #ddd;
padding: 1rem;
}
#run {
background-color: #5c7;
}
.actions {
display: flex;
gap: 1rem;
flex-direction: row;
}
.actions > * {
flex: 1;
}
</style>
<link type="text/css" rel="stylesheet" href="./styles.css" />
<script type="module" defer>
import { disassemble, run, InputKind } from "./build/release.js";
const $upload = document.querySelector('#upload');
Expand Down Expand Up @@ -159,6 +107,9 @@ <h1>🍍 Anan-AS</h1>
or
<a href="./build/debug.wasm">debug.wasm</a>|<a href="./build/debug.wat">wat</a>
</p>
<p>
<a href="conway.html">Game of Life</a>
</p>
<label>
<input type="checkbox" id="spi"> JAM SPI
</label>
Expand Down
51 changes: 51 additions & 0 deletions web/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#root, html {
font-size: 18px;
font-family: monospace;
}
* {
font-size: 1rem;
}
h1 {
font-size: 2rem;
}
h3 {
font-size: 1.4rem;
text-align: right;
}
body {
width: 70vw;
max-width: 1024px;
margin: 2rem auto;
display: flex;
flex-direction: column;
gap: 1rem;
}
#file {
display: none;
}
button {
padding: 1rem;
cursor: pointer;
}
textarea {
padding: 1rem;
}
textarea.error {
border: 2px solid #e22;
}
pre {
border: 1px solid #ccc;
background: #ddd;
padding: 1rem;
}
#run {
background-color: #5c7;
}
.actions {
display: flex;
gap: 1rem;
flex-direction: row;
}
.actions > * {
flex: 1;
}

0 comments on commit f649402

Please sign in to comment.