Code polishing, actual production ready version
This commit is contained in:
parent
2851e78e7e
commit
290f5bb6f8
|
@ -1,4 +1,10 @@
|
|||
|
||||
.ioboxes {
|
||||
background-color: #e0e0e0;
|
||||
border: 2px solid grey;
|
||||
}
|
||||
|
||||
|
||||
mark.goodcode {
|
||||
background-color: #deffff
|
||||
}
|
||||
|
|
36
index.html
36
index.html
|
@ -9,9 +9,11 @@
|
|||
</head>
|
||||
<body>
|
||||
<div class="centred">
|
||||
<h3>L'incredibile interprete di RJ</h3>
|
||||
<div style="text-align: center">
|
||||
<h3>L'incredibile interprete di RJ</h3>
|
||||
</div>
|
||||
|
||||
<div class="vertical centred">
|
||||
<div class="vertical">
|
||||
<div class="interpreter spaced horizontal">
|
||||
<div class="vertical">
|
||||
<div class="container">
|
||||
|
@ -33,13 +35,18 @@ HALT
|
|||
<div class="right-container vertical">
|
||||
<div class="inputcontainter">
|
||||
<h3>INPUT:</h3>
|
||||
<input type="text" id="inputqueue" value="" />
|
||||
<input
|
||||
type="text"
|
||||
id="inputqueue"
|
||||
pattern="[0-9| ]+"
|
||||
value="1 2 3"
|
||||
/>
|
||||
</div>
|
||||
<div class="outputcontainer">
|
||||
<h3>OUTPUT:</h3>
|
||||
<div class="outputbox">
|
||||
<p id="outputqueue"></p>
|
||||
</div>
|
||||
<div class="ioboxes outputbox">
|
||||
<p id="outputqueue"></p>
|
||||
</div>
|
||||
<!-- <input type="text" name="inputqueue" value="" /> -->
|
||||
</div>
|
||||
<h3>MEMORY:</h3>
|
||||
|
@ -69,7 +76,12 @@ HALT
|
|||
<td>0</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p id="errormessage"></p>
|
||||
<p id="messagebox"></p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3>currently loaded program:</h3>
|
||||
<div class="ioboxes" id="progbox"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -77,9 +89,17 @@ HALT
|
|||
<button id="load" type="button">Load</button>
|
||||
<button id="run" type="button">Run</button>
|
||||
<button id="run1" type="button">Run single step</button>
|
||||
<button id="reset" type="button">Reset memory</button>
|
||||
<button id="reset" type="button">Reset</button>
|
||||
<!-- <button id="run1" type="button">Reset </button> -->
|
||||
</div>
|
||||
<details>
|
||||
<summary>What is this??</summary>
|
||||
<p>This is a register architecture machine emulator. The full specification can be found <a href="https://git.dekedin.me/raphy/RAM-emu/src/branch/master/ISA.md">here</a>.</p>
|
||||
<h3>I found a bug. What do I do?</h3>
|
||||
<p>Contact info can be found on <a href="https://dekedin.me/about">this page.</a></p>
|
||||
<h3>This website looks very ugly!! I am a web developer and I think I can do better.</h3>
|
||||
<p>I'm VERY GLAD! contact me (link above) or open a pull request<a href="https://git.dekedin.me/raphy/RAM-emu">here</a>.</p>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
|
|
@ -72,12 +72,13 @@ impl Default for CPU {
|
|||
impl CPU {
|
||||
/// Exposes the state of the CPU:
|
||||
/// Returns a triplet of vectors, corresponding to:
|
||||
/// (entire memory, input queue, output queue)
|
||||
pub fn exposestate(&self) -> (Vec<u32>, Vec<u32>, Vec<u32>) {
|
||||
/// (entire memory, input queue, output queue, current_program)
|
||||
pub fn exposestate(&self) -> (Vec<u32>, Vec<u32>, Vec<u32>, Vec<Instruction>) {
|
||||
return (
|
||||
self.regmemory.clone(),
|
||||
self.input_filo.clone().into(),
|
||||
self.output_filo.clone().into(),
|
||||
self.program.clone(),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -250,7 +251,7 @@ impl CPU {
|
|||
if accval == 0 {
|
||||
self.writememory(pc, u - 1)?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JGTZ(u) => {
|
||||
|
@ -259,7 +260,7 @@ impl CPU {
|
|||
if accval > 0 {
|
||||
self.writememory(pc, u - 1)?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NON DOCUMENTED!
|
||||
|
@ -270,8 +271,13 @@ impl CPU {
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
HALT => {self.stopped = true; return Ok(())}
|
||||
HALT => {
|
||||
self.stopped = true;
|
||||
self.writememory(pc, pc_val + 1)?;
|
||||
return Ok(());
|
||||
} // manually increase pc, without checking.
|
||||
};
|
||||
|
||||
self.pc_increase()?;
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -281,7 +287,7 @@ impl CPU {
|
|||
pub fn exec(&mut self) -> Result<(), CpuError> {
|
||||
while !self.stopped {
|
||||
self.execone()?;
|
||||
self.steps+=1;
|
||||
self.steps += 1;
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::parser::{parse_line, parse_program, ParseError};
|
||||
use js_sys::Uint32Array;
|
||||
use js_sys::{Uint32Array, Array};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
use super::cpu::*;
|
||||
|
@ -33,31 +33,51 @@ impl WrapCpu {
|
|||
};
|
||||
}
|
||||
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
self.cpu = CPU::default();
|
||||
}
|
||||
|
||||
// view
|
||||
pub fn showmem(&self) -> Uint32Array {
|
||||
let (k, _, _) = self.cpu.exposestate();
|
||||
let (k, _, _, _) = self.cpu.exposestate();
|
||||
return Uint32Array::from(&k[..]);
|
||||
}
|
||||
|
||||
pub fn showinput(&self) -> Uint32Array {
|
||||
let (_, k, _) = self.cpu.exposestate();
|
||||
let (_, k, _, _) = self.cpu.exposestate();
|
||||
return Uint32Array::from(&k[..]);
|
||||
}
|
||||
|
||||
pub fn showoutput(&self) -> Uint32Array {
|
||||
let (_, _, k) = self.cpu.exposestate();
|
||||
let (_, _, k, _) = self.cpu.exposestate();
|
||||
return Uint32Array::from(&k[..]);
|
||||
}
|
||||
|
||||
|
||||
pub fn showprogram(&self) -> Array {
|
||||
let (_, _, _, k) = self.cpu.exposestate();
|
||||
let arr = Array::new_with_length(k.len() as u32);
|
||||
for i in 0..arr.length() {
|
||||
let s = JsValue::from_str(&format!("{:?}", k[i as usize]));
|
||||
arr.set(i, s);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
pub fn add_input(&mut self, x: u32) {
|
||||
self.cpu.add_input(x)
|
||||
}
|
||||
|
||||
pub fn one_step(&mut self) {
|
||||
match self.cpu.execone() {
|
||||
Ok(()) => {}
|
||||
Err(k) => cpuErrDispatch(k),
|
||||
};
|
||||
if !self.cpu.stopped {
|
||||
match self.cpu.execone() {
|
||||
Ok(()) => {}
|
||||
Err(k) => cpuErrDispatch(k),
|
||||
};
|
||||
} else {
|
||||
signalerror("The program reached halt. All good!", None);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ pub fn main() {
|
|||
|
||||
fn showmem(cpu: &CPU) {
|
||||
print!("Memory: ");
|
||||
let (k, _, _) = cpu.exposestate();
|
||||
let (k, _, _, _) = cpu.exposestate();
|
||||
for i in 0..k.len() - 1 {
|
||||
print!(" {} |", k[i])
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ fn showmem(cpu: &CPU) {
|
|||
|
||||
fn showinput(cpu: &CPU) {
|
||||
print!("Input: ");
|
||||
let (_, k, _) = cpu.exposestate();
|
||||
let (_, k, _, _) = cpu.exposestate();
|
||||
for i in 0..k.len() {
|
||||
print!(" {} ", k[i])
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ fn showinput(cpu: &CPU) {
|
|||
|
||||
fn showoutput(cpu: &CPU) {
|
||||
print!("Output: ");
|
||||
let (_, _, k) = cpu.exposestate();
|
||||
let (_, _, k, _) = cpu.exposestate();
|
||||
for i in 0..k.len() {
|
||||
print!(" {} ", k[i])
|
||||
}
|
||||
|
|
|
@ -82,22 +82,22 @@ pub fn parse_line(line: &str) -> Option<Instruction> {
|
|||
|
||||
// COULD BE BETTER!!!!!!!!!
|
||||
let patternspairs = [
|
||||
(FnWrap::new(|x| READ(x.parse().unwrap())), r"READ\s+(\d+)\s*#?.*"),
|
||||
(FnWrap::new(|x| WRITE(x.parse().unwrap())), r"WRITE\s+(\d+)\s*#?.*"),
|
||||
(FnWrap::new(|x| LOAD(x.parse().unwrap())), r"LOAD\s+(\d+)\s*#?.*"),
|
||||
(FnWrap::new(|x| READ(x.parse().unwrap())), r"^READ\s+(\d+)\s*(?:#.*)?$"),
|
||||
(FnWrap::new(|x| WRITE(x.parse().unwrap())), r"^WRITE\s+(\d+)\s*(?:#.*)?$"),
|
||||
(FnWrap::new(|x| LOAD(x.parse().unwrap())), r"^LOAD\s+(\d+)\s*(?:#.*)?$"),
|
||||
(
|
||||
FnWrap::new(|x| LOADI(x.parse().unwrap())),
|
||||
r"LOAD\s+=\s*(\d+)\s*#?.*",
|
||||
r"^LOAD\s+=\s*(\d+)\s*(?:#.*)?$",
|
||||
),
|
||||
(FnWrap::new(|x| STORE(x.parse().unwrap())), r"STORE\s+(\d+)\s*#?.*"),
|
||||
(FnWrap::new(|x| ADD(x.parse().unwrap())), r"ADD\s+(\d+)\s*#?.*"),
|
||||
(FnWrap::new(|x| ADDI(x.parse().unwrap())), r"ADD\s=\s*(\d+)\s*#?.*"),
|
||||
(FnWrap::new(|x| SUB(x.parse().unwrap())), r"SUB\s+(\d+)\s*#?.*"),
|
||||
(FnWrap::new(|x| SUBI(x.parse().unwrap())), r"SUB\s=\s*(\d+)\s*#?.*"),
|
||||
(FnWrap::new(|x| JUMP(x.parse().unwrap())), r"JUMP\s+(\d+)\s*#?.*"),
|
||||
(FnWrap::new(|x| JZERO(x.parse().unwrap())), r"JZERO\s+(\d+)\s*#?.*"),
|
||||
(FnWrap::new(|x| JGTZ(x.parse().unwrap())), r"JGTZ\s+(\d+)\s*#?.*"),
|
||||
(FnWrap::new(|_| HALT), r"HALT"),
|
||||
(FnWrap::new(|x| STORE(x.parse().unwrap())), r"^STORE\s+(\d+)\s*(?:#.*)?$"),
|
||||
(FnWrap::new(|x| ADD(x.parse().unwrap())), r"^ADD\s+(\d+)\s*(?:#.*)?$"),
|
||||
(FnWrap::new(|x| ADDI(x.parse().unwrap())), r"^ADD\s=\s*(\d+)\s*(?:#.*)?$"),
|
||||
(FnWrap::new(|x| SUB(x.parse().unwrap())), r"^SUB\s+(\d+)\s*(?:#.*)?$"),
|
||||
(FnWrap::new(|x| SUBI(x.parse().unwrap())), r"^SUB\s=\s*(\d+)\s*(?:#.*)?$"),
|
||||
(FnWrap::new(|x| JUMP(x.parse().unwrap())), r"^JUMP\s+(\d+)\s*(?:#.*)?$"),
|
||||
(FnWrap::new(|x| JZERO(x.parse().unwrap())), r"^JZERO\s+(\d+)\s*(?:#.*)?$"),
|
||||
(FnWrap::new(|x| JGTZ(x.parse().unwrap())), r"^JGTZ\s+(\d+)\s*(?:#.*)?$"),
|
||||
(FnWrap::new(|_| HALT), r"^HALT\s*(?:#.*)?$"),
|
||||
];
|
||||
|
||||
// Compile a set matching any of our patterns.
|
||||
|
|
|
@ -10,25 +10,26 @@ function $(x: string) {
|
|||
|
||||
// error signaling:
|
||||
|
||||
export function signalerror(msg: string, _l: number | null) {
|
||||
let errbox = $("errormessage");
|
||||
export function signalerror(msg: string, l: number | null) {
|
||||
let errbox = $("messagebox");
|
||||
if (errbox) {
|
||||
errbox.innerHTML = msg;
|
||||
}
|
||||
if (l) {
|
||||
highlightError(l, "progbox")
|
||||
}
|
||||
}
|
||||
|
||||
export function signalparseerr(x: number) {
|
||||
console.log("hey!", x);
|
||||
// $("#errormessage").val("Parser error at line " + x.toString() + "!");
|
||||
let errmsg = $("errormessage");
|
||||
let errmsg = $("messagebox");
|
||||
if (errmsg) {
|
||||
errmsg.innerHTML = "Parser error at line " + x.toString() + "!";
|
||||
}
|
||||
highlightError(x);
|
||||
highlightError(x, "highlighting");
|
||||
}
|
||||
|
||||
function highlightError(x: number) {
|
||||
let highlights = $("highlighting");
|
||||
function highlightError(x: number, box: string) {
|
||||
let highlights = $(box);
|
||||
let text = highlights?.innerHTML;
|
||||
if (text != null && highlights != null) {
|
||||
let lines = text.toString().split("\n");
|
||||
|
|
135
src/index.ts
135
src/index.ts
|
@ -10,6 +10,8 @@ let highlights = $("#highlighting");
|
|||
|
||||
textarea.on({
|
||||
input: handleInput,
|
||||
keyup: handleInput,
|
||||
onchange: handleInput,
|
||||
scroll: handleScroll,
|
||||
});
|
||||
|
||||
|
@ -17,7 +19,7 @@ handleInput(); // immediately calling this the first time to highlight the sampl
|
|||
|
||||
function handleInput() {
|
||||
var text = textarea.val();
|
||||
if (text) {
|
||||
if (text != undefined) {
|
||||
var highlightedText = applyHighlights(text.toString());
|
||||
highlights.html(highlightedText);
|
||||
}
|
||||
|
@ -25,22 +27,21 @@ function handleInput() {
|
|||
|
||||
function applyHighlights(text: string) {
|
||||
let res = text
|
||||
.replace(/(READ\s+\d+)/gi, '<mark class="goodcode">$1</mark>')
|
||||
.replace(/(WRITE\s+\d+)/gi, '<mark class="goodcode">$1</mark>')
|
||||
.replace(/(LOAD\s+\d+)/gi, '<mark class="goodcode">$1</mark>')
|
||||
.replace(/(LOAD\s+=\s*\d+)/gi, '<mark class="goodcode">$1</mark>')
|
||||
.replace(/(STORE\s+\d+)/gi, '<mark class="goodcode">$1</mark>')
|
||||
.replace(/(ADD\s+\d+)/gi, '<mark class="goodcode">$1</mark>')
|
||||
.replace(/(ADD\s=\s*\d+)/gi, '<mark class="goodcode">$1</mark>')
|
||||
.replace(/(SUB\s+\d+)/gi, '<mark class="goodcode">$1</mark>')
|
||||
.replace(/(SUB\s=\s*\d+)/gi, '<mark class="goodcode">$1</mark>')
|
||||
.replace(/(JUMP\s+\d+)/gi, '<mark class="goodcode">$1</mark>')
|
||||
.replace(/(JZERO\s+\d+)/gi, '<mark class="goodcode">$1</mark>')
|
||||
.replace(/(JGTZ\s+\d+)/gi, '<mark class="goodcode">$1</mark>')
|
||||
.replace(/(HALT)/gi, '<mark class="goodcode">$1</mark>')
|
||||
.replace(/(#.*\n?\$?)/gi, '<mark class="comment">$1</mark>');
|
||||
|
||||
return res;
|
||||
.replace(/^(READ\s+\d+)(\s*(#.*)?)?$/mg, '<mark class="goodcode">$1</mark>$2')
|
||||
.replace(/^(WRITE\s+\d+)(\s*(#.*)?)?$/mg, '<mark class="goodcode">$1</mark>$2')
|
||||
.replace(/^(LOAD\s+\d+)(\s*(#.*)?)?$/mg, '<mark class="goodcode">$1</mark>$2')
|
||||
.replace(/^(LOAD\s+=\s*\d+)(\s*(#.*)?)?$/mg, '<mark class="goodcode">$1</mark>$2')
|
||||
.replace(/^(STORE\s+\d+)(\s*(#.*)?)?$/mg, '<mark class="goodcode">$1</mark>$2')
|
||||
.replace(/^(ADD\s+\d+)(\s*(#.*)?)?$/mg, '<mark class="goodcode">$1</mark>$2')
|
||||
.replace(/^(ADD\s=\s*\d+)(\s*(#.*)?)?$/mg, '<mark class="goodcode">$1</mark>$2')
|
||||
.replace(/^(SUB\s+\d+)(\s*(#.*)?)?$/mg, '<mark class="goodcode">$1</mark>$2')
|
||||
.replace(/^(SUB\s=\s*\d+)(\s*(#.*)?)?$/mg, '<mark class="goodcode">$1</mark>$2')
|
||||
.replace(/^(JUMP\s+\d+)(\s*(#.*)?)?$/mg, '<mark class="goodcode">$1</mark>$2')
|
||||
.replace(/^(JZERO\s+\d+)(\s*(#.*)?)?$/mg, '<mark class="goodcode">$1</mark>$2')
|
||||
.replace(/^(JGTZ\s+\d+)(\s*(#.*)?)?$/mg, '<mark class="goodcode">$1</mark>$2')
|
||||
.replace(/^(HALT)(\s*(#.*)?)?$/mg, '<mark class="goodcode">$1</mark>$2')
|
||||
.replace(/(#.*\n?\$?)/mg, '<mark class="comment">$1</mark>$2');
|
||||
return res + "\n";
|
||||
}
|
||||
|
||||
function handleScroll() {
|
||||
|
@ -52,38 +53,78 @@ function handleScroll() {
|
|||
}
|
||||
}
|
||||
|
||||
// setting up input box:
|
||||
|
||||
$("#inputqueue").on({
|
||||
input: restrictNumeric,
|
||||
paste: restrictNumeric,
|
||||
})
|
||||
|
||||
|
||||
function restrictNumeric() {
|
||||
var text = $("#inputqueue").val();
|
||||
if (typeof(text) == 'string') {
|
||||
let newtext = text.replaceAll(/[^0-9 ]/g, '');
|
||||
$("#inputqueue").val(newtext)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// setting up buttons.
|
||||
|
||||
let load = $("#load");
|
||||
let run = $("#run");
|
||||
let run1 = $("#run1");
|
||||
|
||||
load.on({
|
||||
$("#load").on({
|
||||
click: function () {
|
||||
|
||||
$("#messagebox").html("Program loaded!");
|
||||
handleInput(); // immediately calling this the first time to highlight the sample code.
|
||||
cpu.reset();
|
||||
loadPrg();
|
||||
loadInput();
|
||||
writeMem();
|
||||
writeProgram();
|
||||
writeInput();
|
||||
writeOutput();
|
||||
highlightCurrent();
|
||||
},
|
||||
});
|
||||
|
||||
run.on({
|
||||
$("#run").on({
|
||||
click: function () {
|
||||
|
||||
$("#messagebox").html("Running the whole program!");
|
||||
cpu.run();
|
||||
writeMem();
|
||||
writeOutput();
|
||||
writeInput();
|
||||
highlightCurrent();
|
||||
},
|
||||
});
|
||||
|
||||
run1.on({
|
||||
$("#run1").on({
|
||||
click: function () {
|
||||
|
||||
$("#messagebox").html("Running a single step!");
|
||||
cpu.one_step();
|
||||
writeMem();
|
||||
writeOutput();
|
||||
writeInput();
|
||||
highlightCurrent();
|
||||
},
|
||||
});
|
||||
|
||||
$("#reset").on({
|
||||
click: function () {
|
||||
$("#messagebox").html("Resetting the whole machine!");
|
||||
cpu.reset();
|
||||
writeMem();
|
||||
writeInput();
|
||||
writeOutput();
|
||||
writeProgram();
|
||||
highlightCurrent();
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
function writeMem() {
|
||||
let mem = cpu.showmem();
|
||||
|
||||
|
@ -95,35 +136,41 @@ function writeMem() {
|
|||
}
|
||||
|
||||
function writeOutput() {
|
||||
let out = cpu.showoutput();
|
||||
// console.log(out);
|
||||
let out = cpu.showoutput().join(" ");
|
||||
|
||||
let outputbox = $("#outputqueue");
|
||||
|
||||
for (let index = 0; index < out.length; index++) {
|
||||
outputbox.html(outputbox.html() + " " + out[index].toString());
|
||||
}
|
||||
outputbox.html(out);
|
||||
}
|
||||
|
||||
function writeInput() {
|
||||
let input = cpu.showinput();
|
||||
let input = cpu.showinput().reverse().join(" ");
|
||||
|
||||
let inputbox = $("#inputqueue");
|
||||
|
||||
for (let index = 0; index < input.length; index++) {
|
||||
inputbox.val(inputbox.val() + " " + input[index].toString());
|
||||
}
|
||||
inputbox.val(input);
|
||||
}
|
||||
|
||||
|
||||
function writeProgram() {
|
||||
let prog = cpu.showprogram().join("<br>");
|
||||
|
||||
|
||||
let progbox = $("#progbox");
|
||||
progbox.html(prog);
|
||||
|
||||
// for (let index = 0; index < prog.length; index++) {
|
||||
// progbox.val(progbox.val() + " " + prog[index]);
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
function loadInput() {
|
||||
// let input = cpu.showinput();
|
||||
|
||||
let inputbox = $("#inputqueue");
|
||||
let inputboxtext = $("#inputqueue").val();
|
||||
if (typeof inputboxtext == "string") {
|
||||
// let inputqueue = inputboxtext.split(" ").filter(function (x) {
|
||||
// x != " ";
|
||||
let inputqueue = inputboxtext.split(" ");
|
||||
let inputqueue = inputboxtext.split(" ").reverse();
|
||||
|
||||
console.log(inputqueue);
|
||||
|
||||
|
@ -140,3 +187,17 @@ function loadPrg() {
|
|||
cpu.load_program(prg);
|
||||
}
|
||||
}
|
||||
|
||||
function highlightCurrent() {
|
||||
let current = cpu.showmem()[9];
|
||||
writeProgram();
|
||||
let progbox = $("#progbox");
|
||||
let text = progbox.html();
|
||||
if (progbox != null && text != null && current > 0) {
|
||||
let lines = text.toString().split("<br>");
|
||||
lines[current - 1] = '<mark class="goodcode">' + lines[current - 1] + '</mark>';
|
||||
var newtext = lines.join("<br>");
|
||||
progbox.html(newtext);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue