SandboXP

Форк
0
/
main.js 
228 строк · 4.8 Кб
1
"use strict";
2

3
/**
4
 * @constructor
5
 * @param {Object=} wasm
6
 */
7
function v86(bus, wasm)
8
{
9
    /** @type {boolean} */
10
    this.running = false;
11

12
    /** @type {boolean} */
13
    this.stopped = false;
14

15
    this.tick_counter = 0;
16
    this.worker = null;
17

18
    /** @type {CPU} */
19
    this.cpu = new CPU(bus, wasm, () => { this.idle && this.next_tick(0); });
20

21
    this.bus = bus;
22
    bus.register("cpu-init", this.init, this);
23
    bus.register("cpu-run", this.run, this);
24
    bus.register("cpu-stop", this.stop, this);
25
    bus.register("cpu-restart", this.restart, this);
26

27
    this.register_yield();
28
}
29

30
v86.prototype.run = function()
31
{
32
    this.stopped = false;
33

34
    if(!this.running)
35
    {
36
        this.running = true;
37
        this.bus.send("emulator-started");
38
    }
39

40
    this.next_tick(0);
41
};
42

43
v86.prototype.do_tick = function()
44
{
45
    if(this.stopped || !this.running)
46
    {
47
        this.stopped = this.running = false;
48
        this.bus.send("emulator-stopped");
49
        return;
50
    }
51

52
    this.idle = false;
53
    const t = this.cpu.main_run();
54

55
    this.next_tick(t);
56
};
57

58
v86.prototype.next_tick = function(t)
59
{
60
    const tick = ++this.tick_counter;
61
    this.idle = true;
62
    this.yield(t, tick);
63
};
64

65
v86.prototype.yield_callback = function(tick)
66
{
67
    if(tick === this.tick_counter)
68
    {
69
        this.do_tick();
70
    }
71
};
72

73
v86.prototype.stop = function()
74
{
75
    if(this.running)
76
    {
77
        this.stopped = true;
78
    }
79
};
80

81
v86.prototype.destroy = function()
82
{
83
    this.unregister_yield();
84
};
85

86
v86.prototype.restart = function()
87
{
88
    this.cpu.reset_cpu();
89
    this.cpu.load_bios();
90
};
91

92
v86.prototype.init = function(settings)
93
{
94
    this.cpu.init(settings, this.bus);
95
    this.bus.send("emulator-ready");
96
};
97

98
if(typeof process !== "undefined")
99
{
100
    v86.prototype.yield = function(t, tick)
101
    {
102
        if(t < 1)
103
        {
104
            global.setImmediate(tick => this.yield_callback(tick), tick);
105
        }
106
        else
107
        {
108
            setTimeout(tick => this.yield_callback(tick), t, tick);
109
        }
110
    };
111

112
    v86.prototype.register_yield = function() {};
113
    v86.prototype.unregister_yield = function() {};
114
}
115
else if(typeof Worker !== "undefined")
116
{
117
    // XXX: This has a slightly lower throughput compared to window.postMessage
118

119
    function the_worker()
120
    {
121
        globalThis.onmessage = function(e)
122
        {
123
            const t = e.data.t;
124
            if(t < 1) postMessage(e.data.tick);
125
            else setTimeout(() => postMessage(e.data.tick), t);
126
        };
127
    }
128

129
    v86.prototype.register_yield = function()
130
    {
131
        const url = URL.createObjectURL(new Blob(["(" + the_worker.toString() + ")()"], { type: "text/javascript" }));
132
        this.worker = new Worker(url);
133
        this.worker.onmessage = e => this.yield_callback(e.data);
134
        URL.revokeObjectURL(url);
135
    };
136

137
    v86.prototype.yield = function(t, tick)
138
    {
139
        this.worker.postMessage({ t, tick });
140
    };
141

142
    v86.prototype.unregister_yield = function()
143
    {
144
        this.worker.terminate();
145
        this.worker = null;
146
    };
147
}
148
//else if(typeof window !== "undefined" && typeof postMessage !== "undefined")
149
//{
150
//    // setImmediate shim for the browser.
151
//    // TODO: Make this deactivatable, for other applications
152
//    //       using postMessage
153
//
154
//    /** @const */
155
//    let MAGIC_POST_MESSAGE = 0xAA55;
156
//
157
//    v86.prototype.yield = function(t)
158
//    {
159
//        // XXX: Use t
160
//        window.postMessage(MAGIC_POST_MESSAGE, "*");
161
//    };
162
//
163
//    let tick;
164
//
165
//    v86.prototype.register_yield = function()
166
//    {
167
//        tick = e =>
168
//        {
169
//            if(e.source === window && e.data === MAGIC_POST_MESSAGE)
170
//            {
171
//                this.do_tick();
172
//            }
173
//        };
174
//
175
//        window.addEventListener("message", tick, false);
176
//    };
177
//
178
//    v86.prototype.unregister_yield = function()
179
//    {
180
//        window.removeEventListener("message", tick);
181
//        tick = null;
182
//    };
183
//}
184
else
185
{
186
    v86.prototype.yield = function(t)
187
    {
188
        setTimeout(() => { this.do_tick(); }, t);
189
    };
190

191
    v86.prototype.register_yield = function() {};
192
    v86.prototype.unregister_yield = function() {};
193
}
194

195
v86.prototype.save_state = function()
196
{
197
    // TODO: Should be implemented here, not on cpu
198
    return this.cpu.save_state();
199
};
200

201
v86.prototype.restore_state = function(state)
202
{
203
    // TODO: Should be implemented here, not on cpu
204
    return this.cpu.restore_state(state);
205
};
206

207

208
if(typeof performance === "object" && performance.now)
209
{
210
    v86.microtick = performance.now.bind(performance);
211
}
212
else if(typeof require === "function")
213
{
214
    const { performance } = require("perf_hooks");
215
    v86.microtick = performance.now.bind(performance);
216
}
217
else if(typeof process === "object" && process.hrtime)
218
{
219
    v86.microtick = function()
220
    {
221
        var t = process.hrtime();
222
        return t[0] * 1000 + t[1] / 1e6;
223
    };
224
}
225
else
226
{
227
    v86.microtick = Date.now;
228
}
229

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.