123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- "use strict";
- /**
- * @constructor
- * @param {Object=} wasm
- */
- function v86(bus, wasm)
- {
- /** @type {boolean} */
- this.running = false;
- /** @type {boolean} */
- this.stopped = false;
- /** @type {CPU} */
- this.cpu = new CPU(bus, wasm);
- this.bus = bus;
- bus.register("cpu-init", this.init, this);
- bus.register("cpu-run", this.run, this);
- bus.register("cpu-stop", this.stop, this);
- bus.register("cpu-restart", this.restart, this);
- this.register_tick();
- }
- v86.prototype.run = function()
- {
- this.stopped = false;
- if(!this.running)
- {
- this.bus.send("emulator-started");
- this.fast_next_tick();
- }
- };
- v86.prototype.do_tick = function()
- {
- if(this.stopped)
- {
- this.stopped = this.running = false;
- this.bus.send("emulator-stopped");
- return;
- }
- this.running = true;
- var dt = this.cpu.main_run();
- if(dt <= 0)
- {
- this.fast_next_tick();
- }
- else
- {
- this.next_tick(dt);
- }
- };
- v86.prototype.stop = function()
- {
- if(this.running)
- {
- this.stopped = true;
- }
- };
- v86.prototype.destroy = function()
- {
- this.unregister_tick();
- };
- v86.prototype.restart = function()
- {
- this.cpu.reset();
- this.cpu.load_bios();
- };
- v86.prototype.init = function(settings)
- {
- this.cpu.init(settings, this.bus);
- this.bus.send("emulator-ready");
- };
- if(typeof setImmediate !== "undefined")
- {
- /** @this {v86} */
- var fast_next_tick = function()
- {
- setImmediate(() => { this.do_tick(); });
- };
- /** @this {v86} */
- var register_tick = function() {};
- /** @this {v86} */
- var unregister_tick = function() {};
- }
- else if(typeof window !== "undefined" && typeof postMessage !== "undefined")
- {
- // setImmediate shim for the browser.
- // TODO: Make this deactivatable, for other applications
- // using postMessage
- /** @const */
- let MAGIC_POST_MESSAGE = 0xAA55;
- /** @this {v86} */
- fast_next_tick = function()
- {
- window.postMessage(MAGIC_POST_MESSAGE, "*");
- };
- let tick;
- /** @this {v86} */
- register_tick = function()
- {
- tick = e =>
- {
- if(e.source === window && e.data === MAGIC_POST_MESSAGE)
- {
- this.do_tick();
- }
- };
- window.addEventListener("message", tick, false);
- };
- /** @this {v86} */
- unregister_tick = function()
- {
- window.removeEventListener("message", tick);
- tick = null;
- };
- }
- else
- {
- /** @this {v86} */
- fast_next_tick = function()
- {
- setTimeout(() => { this.do_tick(); }, 0);
- };
- /** @this {v86} */
- register_tick = function() {};
- /** @this {v86} */
- unregister_tick = function() {};
- }
- v86.prototype.fast_next_tick = fast_next_tick;
- v86.prototype.register_tick = register_tick;
- v86.prototype.unregister_tick = unregister_tick;
- if(typeof document !== "undefined" && typeof document.hidden === "boolean")
- {
- /** @this {v86} */
- var next_tick = function(t)
- {
- if(t < 4 || document.hidden)
- {
- // Avoid sleeping for 1 second (happens if page is not
- // visible), it can break boot processes. Also don't try to
- // sleep for less than 4ms, since the value is clamped up
- this.fast_next_tick();
- }
- else
- {
- setTimeout(() => { this.do_tick(); }, t);
- }
- };
- }
- else
- {
- // In environments that aren't browsers, we might as well use setTimeout
- /** @this {v86} */
- next_tick = function(t)
- {
- setTimeout(() => { this.do_tick(); }, t);
- };
- }
- v86.prototype.next_tick = next_tick;
- v86.prototype.save_state = function()
- {
- // TODO: Should be implemented here, not on cpu
- return this.cpu.save_state();
- };
- v86.prototype.restore_state = function(state)
- {
- // TODO: Should be implemented here, not on cpu
- return this.cpu.restore_state(state);
- };
- if(typeof performance === "object" && performance.now)
- {
- v86.microtick = performance.now.bind(performance);
- }
- else if(typeof require === "function")
- {
- const { performance } = require("perf_hooks");
- v86.microtick = performance.now.bind(performance);
- }
- else if(typeof process === "object" && process.hrtime)
- {
- v86.microtick = function()
- {
- var t = process.hrtime();
- return t[0] * 1000 + t[1] / 1e6;
- };
- }
- else
- {
- v86.microtick = Date.now;
- }
|