Skip to content

Commit

Permalink
Add the public directory to host the emulator by Firebase
Browse files Browse the repository at this point in the history
  • Loading branch information
d0iasm committed Dec 21, 2019
1 parent a55cc5a commit c952eba
Show file tree
Hide file tree
Showing 8 changed files with 316 additions and 7 deletions.
4 changes: 3 additions & 1 deletion .gitignore
@@ -1,8 +1,10 @@
.DS_Store
.firebase
.firebaserc
/target
**/*.rs.bk
Cargo.lock
pkg/
wasm-pack.log
www/node_modules
www/dist
**/node_modules
13 changes: 7 additions & 6 deletions README.md
Expand Up @@ -2,6 +2,8 @@
[![Build Status](https://travis-ci.com/d0iasm/rvemu.svg?branch=master)](https://travis-ci.com/d0iasm/rvemu)
RISC-V online emulator with WebAssembly generated by Rust. The instruction sets in this emulator complies "The RISC-V Instruction Set Manual Volume I: Unprivileged ISA Document Version 20190608-Base-Ratified".

https://riscvemu.web.app/

Supports the following RISC-V ISA features:
- RV32I (v2.1): supports 37/40 instructions (except FENCE, ECALL, and EBREAK)
- RV64I (v2.1): supports 12/12 instructions (SLLI, SRLI, and SRAI are included in RV32I)
Expand All @@ -17,18 +19,17 @@ Supports the following RISC-V ISA features:
The `wasm-pack build` command generates a pkg directory and makes Rust source code into `.wasm` binary. It also generates the JavaScript API for using our Rust-generated WebAssembly. The toolchain's supported target is `wasm32-unknown-unknown`.
You need to execute this command whenever you change your Rust code.
```
$ wasm-pack build --out-dir www/pkg
$ wasm-pack build --out-dir www/pkg --target web
```

Use `npm init wasm-app www` just once to generate a www directory for a web page. Also, need `npm install` in a www directory at the first time and whenever you change a dependency in package.json.
This command installs dependencies in the `node_modules` directory. Need `npm install --save` in the `public` directory at the first time and whenever you change dependencies in package.json.
```
$ npm init wasm-app www // at a root directory
$ npm install // at ./www directory
$ npm install --save // at the public directory
```

You can see a web page via http://localhost:8080/ that reflects changes when we rus the wasm-pack build command.
You can see the website via http://localhost:8000. `npm start` is the alias of `python3 -m http.server` so you need Python3 in your environment.
```
$ npm start
$ npm start // at the public directory
```

## Test
Expand Down
9 changes: 9 additions & 0 deletions firebase.json
@@ -0,0 +1,9 @@
{
"hosting": {
"public": "public",
"ignore": [
"firebase.json",
"**/.*"
]
}
}
33 changes: 33 additions & 0 deletions public/404.html
@@ -0,0 +1,33 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Page Not Found</title>

<style media="screen">
body { background: #ECEFF1; color: rgba(0,0,0,0.87); font-family: Roboto, Helvetica, Arial, sans-serif; margin: 0; padding: 0; }
#message { background: white; max-width: 360px; margin: 100px auto 16px; padding: 32px 24px 16px; border-radius: 3px; }
#message h3 { color: #888; font-weight: normal; font-size: 16px; margin: 16px 0 12px; }
#message h2 { color: #ffa100; font-weight: bold; font-size: 16px; margin: 0 0 8px; }
#message h1 { font-size: 22px; font-weight: 300; color: rgba(0,0,0,0.6); margin: 0 0 16px;}
#message p { line-height: 140%; margin: 16px 0 24px; font-size: 14px; }
#message a { display: block; text-align: center; background: #039be5; text-transform: uppercase; text-decoration: none; color: white; padding: 16px; border-radius: 4px; }
#message, #message a { box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); }
#load { color: rgba(0,0,0,0.4); text-align: center; font-size: 13px; }
@media (max-width: 600px) {
body, #message { margin-top: 0; background: white; box-shadow: none; }
body { border-top: 16px solid #ffa100; }
}
</style>
</head>
<body>
<div id="message">
<h2>404</h2>
<h1>Page Not Found</h1>
<p>The specified file was not found on this website. Please check the URL for mistakes and try again.</p>
<h3>Why am I seeing this?</h3>
<p>This page was generated by the Firebase Command-Line Interface. To modify it, edit the <code>404.html</code> file in your project's configured <code>public</code> directory.</p>
</div>
</body>
</html>
31 changes: 31 additions & 0 deletions public/index.html
@@ -0,0 +1,31 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>RISC-V Emulator</title>
<link rel="stylesheet" type="text/css" href="./node_modules/xterm/css/xterm.css" />
<style>
html, body {
margin: 0;
padding: 0;
}
#terminal {
background-color: black;
color: white;
height: 100vh;
width: 100vw;
}
.hide {
display: none;
}
</style>
<script src="./node_modules/xterm/lib/xterm.js"></script>
<script src="./node_modules/xterm-addon-fit/lib/xterm-addon-fit.js"></script>
</head>
<body>
<input id="file" class="hide" type="file" multiple/>
<div id="buffer" class="hide"></div>
<div id="terminal"></div>
<script src="./index.js" type="module"></script>
</body>
</html>
181 changes: 181 additions & 0 deletions public/index.js
@@ -0,0 +1,181 @@
import init, { Emulator } from "./pkg/rvemu.js";

const fileIn = document.getElementById("file");
const buffer = document.getElementById("buffer");

const termContainer = document.getElementById("terminal");
const term = new Terminal({cursorBlink: true});

console.log(Terminal);
console.log(FitAddon.FitAddon);

const fitAddon = new FitAddon.FitAddon();
const newLine = "\r\n$ ";
const deleteLine = "\x1b[2K\r";

const fileReader = new FileReader();
let files = [];
let execute_once = false;

async function initialize() {
// Load the wasm file.
await init();

term.loadAddon(fitAddon);
term.open(termContainer);
fitAddon.fit();

runTerminal();

buffer.addEventListener('DOMSubtreeModified', (e) => {
if (e.target.childNodes.length <= 0) {
term.write("$ ");
return;
}
const firstChild = e.target.childNodes[0];
term.write(deleteLine);
term.writeln(firstChild.innerText);
e.target.removeChild(firstChild);
});

fileReader.onloadend = e => {
const emu = Emulator.new();
const bin = new Uint8Array(fileReader.result);
emu.set_binary(bin);
emu.execute();
};

fileIn.onchange = e => {
let names = "";
for (let i=0; i<file.files.length; i++) {
names += file.files[i].name;
if (i < file.files.length-1) {
names += ", ";
}
}
files.push.apply(files, file.files);
term.write(deleteLine);
term.write("uploaded " + names);
prompt();
};
}

function prompt() {
term.write(newLine);
}

function help() {
term.writeln("Supports the following commands:");
term.writeln(" upload open local files for an execution on the emulator");
term.writeln(" ls list files you uploaded");
term.writeln(" run [file] execute a file");
term.write(" help print all commands you can use");
}

function upload() {
fileIn.click();
}

function run(filename) {
for (let i=0; i<files.length; i++) {
if (filename == files[i].name) {
fileReader.readAsArrayBuffer(files[i]);
return;
}
}
term.write("\r\n" + filename + ": No such file");
}

function ls() {
let names = "";
for (let i=0; i<files.length; i++) {
names += files[i].name;
if (i < files.length-1) {
names += ", ";
}
}
term.write("\r\n" + names);
}

function command(input) {
const com = input.split(" ");
switch (com[0]) {
case "":
break;
case "upload":
upload();
break;
case "ls":
ls();
break;
case "run":
if (com[1] == undefined) {
term.writeln("");
help();
break;
}
term.writeln("\r\nstart to execute " + com[1]);
run(com[1]);
break;
default:
term.writeln("");
help();
}
}

function runTerminal() {
if (term._initialized) {
return;
}

term._initialized = true;

term.prompt = () => {
term.write('\r\n$ ');
};

term.writeln("Welcome to RISC-V emulator");
help();
term.writeln("");
prompt();

let input = "";
let cursor = 0;
term.onKey(e => {
const printable = !e.domEvent.altKey && !e.domEvent.altGraphKey && !e.domEvent.ctrlKey && !e.domEvent.metaKey;

if (e.domEvent.keyCode === 13) { // Enter key
command(input);
input = "";
cursor = 0;
prompt();
} else if (e.domEvent.keyCode === 8) { // Backspace key
// Do not delete the prompt
if (term._core.buffer.x > 2) {
input = input.substr(0, cursor-1) + input.substr(cursor);
if (cursor > input.length) {
cursor--;
}
term.write(deleteLine);
term.write("$ ");
term.write(input);
}
} else if (e.domEvent.keyCode === 37) { // Arrow left
if (cursor > 0) {
cursor--;
}
term.write(e.key);
} else if (e.domEvent.keyCode === 39) { // Arrow right
if (cursor < input.length) {
cursor++;
}
term.write(e.key);
} else if (printable) {
cursor++;
input = input.substr(0, cursor) + e.key + input.substr(cursor);
term.write(e.key);
}
});
}

initialize();
21 changes: 21 additions & 0 deletions public/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 31 additions & 0 deletions public/package.json
@@ -0,0 +1,31 @@
{
"name": "rvemu",
"version": "0.1.0",
"description": "RISC-V emulator on a browser with WebAssembly generated by Rust",
"main": "index.js",
"scripts": {
"deploy": "firebase deploy",
"start": "python3 -m http.server"
},
"repository": {
"type": "git",
"url": "git+https://github.com/d0iasm/rvemu.git"
},
"keywords": [
"webassembly",
"wasm",
"rust",
"webpack"
],
"author": "Asami Doi <d0iasm.pub@gmail.com>",
"license": "MIT",
"bugs": {
"url": "https://github.com/d0iasm/rvemu/issues"
},
"homepage": "https://github.com/d0iasm/rvemu",
"dependencies": {
"rvemu": "file:./pkg",
"xterm": "^4.3.0",
"xterm-addon-fit": "^0.3.0"
}
}

0 comments on commit c952eba

Please sign in to comment.