Skip to content

Commit 6e38625

Browse files
authored
Fixed JS loading before the body on firefox
1 parent 0d36086 commit 6e38625

File tree

1 file changed

+62
-91
lines changed

1 file changed

+62
-91
lines changed

src/index.html

Lines changed: 62 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<meta name="viewport" content="width=device-width, initial-scale=1.0">
1414
<meta name="title" content="EXACT">
1515
<meta name="author" content="Fereydoun Memarzanjany">
16-
<meta name="description" content="Bare-metal Intel iAPX 86/10 Emulator Written In Pure WebAssembly.">
16+
<meta name="description" content="A Bare-Metal Intel 8086 Emulator Written In Raw WebAssembly.">
1717
<meta name="keywords" content="intel, 8086, iapx, emulator, webassembly, wasm, wat, wast, assembly, browser, cpu, cpu-emulator, 16bit, emulation, graphical, x86, 8086-emulator, 8086-architecture">
1818
<style>
1919
/*
@@ -38,6 +38,9 @@
3838
}
3939

4040

41+
/* I Avoid using external dependencies but this is required considering how web browsers *
42+
* either don't have the same built-in fonts or override and replace those with custom ones */
43+
@import url(//fonts.googleapis.com/css?family=Noto+Sans);
4144

4245
/*
4346
* Custom styles for elements
@@ -50,7 +53,7 @@
5053
}
5154

5255
code {
53-
font-family: lucida console !important; /* First impression is important, some browsers try to override the default font (monocode) for <code> tags */
56+
font-family: 'Noto Sans', monospace !important; /* First impression is important, some browsers try to override the default font (monocode) for <code> tags */
5457
}
5558

5659
p {
@@ -139,6 +142,7 @@ <h1><code>EXACT</code></h1>
139142
<select class="button" id="examples">
140143
<option selected disabled>Examples</option>
141144
<option value="checked_add">checked_add</option>
145+
<option value="jump">jump</option>
142146
<option value="memory">memory</option>
143147
<option value="rotate">rotate</option>
144148
<option value="stack">stack</option>
@@ -201,7 +205,7 @@ <h1><code>EXACT</code></h1>
201205
Source Available at <a href="https://github.com/Thraetaona/EXACT">GitHub</a>
202206
</body>
203207

204-
208+
205209
<script type="module" async>
206210
"use strict";
207211
(async () => {
@@ -216,9 +220,18 @@ <h1><code>EXACT</code></h1>
216220
// be used to create 'instances' of this emulator, each instance has its own isolated memory along with global variable scope.
217221
const module = await WebAssembly.compileStreaming(fetch('./8086.wasm'));
218222

223+
// The UI updater's handle, as ianonymous intervals can not be cleared.
219224
let updateUI;
220225

221-
document.getElementById('examples').addEventListener('change', async function(example) {
226+
document.getElementById('examples').addEventListener('change', e => { init(e, 1); }, false);
227+
document.getElementById('upload').addEventListener('change', e => { init(e, 0); }, false);
228+
229+
230+
// The front-end currently allows uploading a local (residing in the same directory as this file) or remote (from the users PC).
231+
// It would be much better if it also supported 'live' examples, such as embedding an assembler (like NASM) inside of the webpage
232+
// which allows users to write assembly code and see it's run-time results at the same time.
233+
async function init(uploaded, local) {
234+
222235
// Clears the UI updater (if any)
223236
clearInterval(updateUI)
224237

@@ -232,94 +245,17 @@ <h1><code>EXACT</code></h1>
232245
const byteBuffer = new Uint8Array(instance.exports.memory.buffer),
233246
wordBuffer = new Uint16Array(instance.exports.memory.buffer),
234247
registers = document.getElementsByClassName("register");
235-
236-
let file = await fetch('examples/' + example.target.value);
237-
let buffer = await file.arrayBuffer();
238248

239-
const opcodes = new DataView(buffer, 0, buffer.byteLength);
240-
241-
instance.exports.programLength.value = opcodes.byteLength;
242-
243-
for (let offset = 0; offset < instance.exports.programLength.value; offset++) {
244-
byteBuffer[offset + 40] = opcodes.getUint8(offset);
245-
}
249+
if (local) {
250+
const file = await fetch('examples/' + uploaded.target.value);
251+
const buffer = await file.arrayBuffer();
246252

247-
if (instance.exports.programLength.value > 0) {
248-
for (let offset = 0; offset < 3; offset++) {
249-
document.getElementById("control").children[offset].disabled = false;
250-
}
251-
}
253+
const opcodes = new DataView(buffer, 0, buffer.byteLength);
252254

253-
// Simply modifying programLength's value allows us to re-use this existing
254-
// variable rather than making separate 'halt' or 'continue' flag.
255-
document.getElementById('run').addEventListener('click', function() {
256255
instance.exports.programLength.value = opcodes.byteLength;
257-
instance.exports.run();
258-
}, false);
259-
document.getElementById('step').addEventListener('click', function() {
260-
const temp = instance.exports.IP.value + 1;
261-
instance.exports.programLength.value = (temp > opcodes.byteLength) ? opcodes.byteLength : temp;
262-
instance.exports.run();
263-
}, false);
264-
document.getElementById('stop').addEventListener('click', function() {
265-
instance.exports.programLength.value = instance.exports.IP.value;
266-
instance.exports.run();
267-
}, false);
268-
269-
updateUI = window.setInterval(async function() {
270-
for (let offset = 0; offset < 8; offset++) {
271-
// 16-Bit General-purpose and Index registers
272-
registers[offset].innerHTML = wordBuffer[offset];
273-
// 8-Bit register decodes
274-
registers[offset + 8].innerHTML = byteBuffer[offset];
275-
}
276-
277-
for (let offset = 8; offset < 12; offset++) {
278-
// Segment registers
279-
registers[offset + 8].innerHTML = wordBuffer[offset];
280-
}
281-
282-
// Flag registers do not follow a uniform order, hence the manual assignment.
283-
registers[20].innerHTML = byteBuffer[24];
284-
registers[21].innerHTML = byteBuffer[26];
285-
registers[22].innerHTML = byteBuffer[28];
286-
registers[23].innerHTML = byteBuffer[30];
287-
registers[24].innerHTML = byteBuffer[31];
288-
registers[25].innerHTML = byteBuffer[32];
289-
registers[26].innerHTML = byteBuffer[33];
290-
registers[27].innerHTML = byteBuffer[34];
291-
registers[28].innerHTML = byteBuffer[35];
292-
293-
// Program counter
294-
registers[29].innerHTML = instance.exports.IP.value;
295-
}, 15);
296-
}, false);
297-
298-
document.getElementById('upload').addEventListener('change', async function(uploaded) {
299-
300-
// Clears the UI updater (if any)
301-
clearInterval(updateUI)
302-
303-
// Each time a new file is uploaded, we will create an 'instance' of this emulator for it,
304-
// the instance will be dedicated to running the said program.
305-
const instance = await WebAssembly.instantiate(module, imports);
306-
307-
// Since the UI runs at 60 frames per second we should not be
308-
// allocating memory on the heap every time updateUI is run,
309-
// so we allocate it once in here, and simply pass it to the UI updater.
310-
const byteBuffer = new Uint8Array(instance.exports.memory.buffer),
311-
wordBuffer = new Uint16Array(instance.exports.memory.buffer),
312-
registers = document.getElementsByClassName("register");
313-
314-
let file = uploaded.target.files[0];
315-
let reader = new FileReader();
316-
317-
reader.onload = function() {
318-
let opcodes = new Uint8Array(reader.result);
319-
instance.exports.programLength.value = opcodes.length;
320256

321257
for (let offset = 0; offset < instance.exports.programLength.value; offset++) {
322-
byteBuffer[offset + 40] = opcodes[offset];
258+
byteBuffer[offset + 40] = opcodes.getUint8(offset);
323259
}
324260

325261
if (instance.exports.programLength.value > 0) {
@@ -331,21 +267,56 @@ <h1><code>EXACT</code></h1>
331267
// Simply modifying programLength's value allows us to re-use this existing
332268
// variable rather than making separate 'halt' or 'continue' flag.
333269
document.getElementById('run').addEventListener('click', function() {
334-
instance.exports.programLength.value = opcodes.length;
270+
instance.exports.programLength.value = opcodes.byteLength;
335271
instance.exports.run();
336272
}, false);
337273
document.getElementById('step').addEventListener('click', function() {
338274
const temp = instance.exports.IP.value + 1;
339-
instance.exports.programLength.value = (temp > opcodes.length) ? opcodes.length : temp;
275+
instance.exports.programLength.value = (temp > opcodes.byteLength) ? opcodes.byteLength : temp;
340276
instance.exports.run();
341277
}, false);
342278
document.getElementById('stop').addEventListener('click', function() {
343279
instance.exports.programLength.value = instance.exports.IP.value;
344280
instance.exports.run();
345281
}, false);
346282
}
347-
348-
reader.readAsArrayBuffer(file);
283+
else {
284+
const file = uploaded.target.files[0];
285+
const reader = new FileReader();
286+
287+
reader.onload = function() {
288+
let opcodes = new Uint8Array(reader.result);
289+
instance.exports.programLength.value = opcodes.length;
290+
291+
for (let offset = 0; offset < instance.exports.programLength.value; offset++) {
292+
byteBuffer[offset + 40] = opcodes[offset];
293+
}
294+
295+
if (instance.exports.programLength.value > 0) {
296+
for (let offset = 0; offset < 3; offset++) {
297+
document.getElementById("control").children[offset].disabled = false;
298+
}
299+
}
300+
301+
// Simply modifying programLength's value allows us to re-use this existing
302+
// variable rather than making separate 'halt' or 'continue' flag.
303+
document.getElementById('run').addEventListener('click', function() {
304+
instance.exports.programLength.value = opcodes.length;
305+
instance.exports.run();
306+
}, false);
307+
document.getElementById('step').addEventListener('click', function() {
308+
const temp = instance.exports.IP.value + 1;
309+
instance.exports.programLength.value = (temp > opcodes.length) ? opcodes.length : temp;
310+
instance.exports.run();
311+
}, false);
312+
document.getElementById('stop').addEventListener('click', function() {
313+
instance.exports.programLength.value = instance.exports.IP.value;
314+
instance.exports.run();
315+
}, false);
316+
}
317+
318+
reader.readAsArrayBuffer(file);
319+
}
349320

350321
updateUI = window.setInterval(async function() {
351322
for (let offset = 0; offset < 8; offset++) {
@@ -374,7 +345,7 @@ <h1><code>EXACT</code></h1>
374345
// Program counter
375346
registers[29].innerHTML = instance.exports.IP.value;
376347
}, 15);
377-
}, false);
348+
}
378349
})();
379350
</script>
380351
</html>

0 commit comments

Comments
 (0)