SandboXP

Форк
0
/
io.js 
461 строка · 12.5 Кб
1
"use strict";
2

3
/**
4
 * The ISA IO bus
5
 * Devices register their ports here
6
 *
7
 * @constructor
8
 * @param {CPU} cpu
9
 */
10
function IO(cpu)
11
{
12
    /** @const */
13
    this.ports = [];
14

15
    /** @const @type {CPU} */
16
    this.cpu = cpu;
17

18
    for(var i = 0; i < 0x10000; i++)
19
    {
20
        this.ports[i] = this.create_empty_entry();
21
    }
22

23
    var memory_size = cpu.memory_size[0];
24

25
    for(var i = 0; (i << MMAP_BLOCK_BITS) < memory_size; i++)
26
    {
27
        // avoid sparse arrays
28
        cpu.memory_map_read8[i] = cpu.memory_map_write8[i] = undefined;
29
        cpu.memory_map_read32[i] = cpu.memory_map_write32[i] = undefined;
30
    }
31

32
    this.mmap_register(memory_size, 0x100000000 - memory_size,
33
        function(addr) {
34
            // read outside of the memory size
35
            dbg_log("Read from unmapped memory space, addr=" + h(addr >>> 0, 8), LOG_IO);
36
            return 0xFF;
37
        },
38
        function(addr, value) {
39
            // write outside of the memory size
40
            dbg_log("Write to unmapped memory space, addr=" + h(addr >>> 0, 8) + " value=" + h(value, 2), LOG_IO);
41
        },
42
        function(addr) {
43
            dbg_log("Read from unmapped memory space, addr=" + h(addr >>> 0, 8), LOG_IO);
44
            return -1;
45
        },
46
        function(addr, value) {
47
            dbg_log("Write to unmapped memory space, addr=" + h(addr >>> 0, 8) + " value=" + h(value >>> 0, 8), LOG_IO);
48
        }
49
    );
50
}
51

52
IO.prototype.create_empty_entry = function()
53
{
54
    return {
55
        read8: this.empty_port_read8,
56
        read16: this.empty_port_read16,
57
        read32: this.empty_port_read32,
58

59
        write8: this.empty_port_write,
60
        write16: this.empty_port_write,
61
        write32: this.empty_port_write,
62

63
        device: undefined,
64
    };
65
};
66

67
IO.prototype.empty_port_read8 = function()
68
{
69
    return 0xFF;
70
};
71

72
IO.prototype.empty_port_read16 = function()
73
{
74
    return 0xFFFF;
75
};
76

77
IO.prototype.empty_port_read32 = function()
78
{
79
    return -1;
80
};
81

82
IO.prototype.empty_port_write = function(x)
83
{
84
};
85

86

87
/**
88
 * @param {number} port_addr
89
 * @param {Object} device
90
 * @param {function():number=} r8
91
 * @param {function():number=} r16
92
 * @param {function():number=} r32
93
 */
94
IO.prototype.register_read = function(port_addr, device, r8, r16, r32)
95
{
96
    dbg_assert(typeof port_addr === "number");
97
    dbg_assert(typeof device === "object");
98
    dbg_assert(!r8 || typeof r8 === "function");
99
    dbg_assert(!r16 || typeof r16 === "function");
100
    dbg_assert(!r32 || typeof r32 === "function");
101
    dbg_assert(r8 || r16 || r32);
102

103
    if(DEBUG)
104
    {
105
        var fail = function(n) {
106
            dbg_assert(false, "Overlapped read" + n + " " + h(port_addr, 4) + " (" + device.name + ")");
107
            return -1 >>> (32 - n) | 0;
108
        };
109
        if(!r8) r8 = fail.bind(this, 8);
110
        if(!r16) r16 = fail.bind(this, 16);
111
        if(!r32) r32 = fail.bind(this, 32);
112
    }
113

114
    if(r8) this.ports[port_addr].read8 = r8;
115
    if(r16) this.ports[port_addr].read16 = r16;
116
    if(r32) this.ports[port_addr].read32 = r32;
117
    this.ports[port_addr].device = device;
118
};
119

120
/**
121
 * @param {number} port_addr
122
 * @param {Object} device
123
 * @param {function(number)=} w8
124
 * @param {function(number)=} w16
125
 * @param {function(number)=} w32
126
 */
127
IO.prototype.register_write = function(port_addr, device, w8, w16, w32)
128
{
129
    dbg_assert(typeof port_addr === "number");
130
    dbg_assert(typeof device === "object");
131
    dbg_assert(!w8 || typeof w8 === "function");
132
    dbg_assert(!w16 || typeof w16 === "function");
133
    dbg_assert(!w32 || typeof w32 === "function");
134
    dbg_assert(w8 || w16 || w32);
135

136
    if(DEBUG)
137
    {
138
        var fail = function(n) {
139
            dbg_assert(false, "Overlapped write" + n + " " + h(port_addr) + " (" + device.name + ")");
140
        };
141
        if(!w8) w8 = fail.bind(this, 8);
142
        if(!w16) w16 = fail.bind(this, 16);
143
        if(!w32) w32 = fail.bind(this, 32);
144
    }
145

146
    if(w8) this.ports[port_addr].write8 = w8;
147
    if(w16) this.ports[port_addr].write16 = w16;
148
    if(w32) this.ports[port_addr].write32 = w32;
149
    this.ports[port_addr].device = device;
150
};
151

152
/**
153
 * > Any two consecutive 8-bit ports can be treated as a 16-bit port;
154
 * > and four consecutive 8-bit ports can be treated as a 32-bit port
155
 * > http://css.csail.mit.edu/6.858/2012/readings/i386/s08_01.htm
156
 *
157
 * This info is not correct for all ports, but handled by the following functions
158
 *
159
 * Register the write of 2 or 4 consecutive 8-bit ports, 1 or 2 16-bit
160
 * ports and 0 or 1 32-bit ports
161
 *
162
 * @param {number} port_addr
163
 * @param {!Object} device
164
 * @param {function():number} r8_1
165
 * @param {function():number} r8_2
166
 * @param {function():number=} r8_3
167
 * @param {function():number=} r8_4
168
 */
169
IO.prototype.register_read_consecutive = function(port_addr, device, r8_1, r8_2, r8_3, r8_4)
170
{
171
    dbg_assert(arguments.length === 4 || arguments.length === 6);
172

173
    function r16_1()
174
    {
175
        return r8_1.call(this) |
176
                r8_2.call(this) << 8;
177
    }
178
    function r16_2()
179
    {
180
        return r8_3.call(this) |
181
                r8_4.call(this) << 8;
182
    }
183
    function r32()
184
    {
185
        return r8_1.call(this) |
186
                r8_2.call(this) << 8 |
187
                r8_3.call(this) << 16 |
188
                r8_4.call(this) << 24;
189
    }
190

191
    if(r8_3 && r8_4)
192
    {
193
        this.register_read(port_addr, device, r8_1, r16_1, r32);
194
        this.register_read(port_addr + 1, device, r8_2);
195
        this.register_read(port_addr + 2, device, r8_3, r16_2);
196
        this.register_read(port_addr + 3, device, r8_4);
197
    }
198
    else
199
    {
200
        this.register_read(port_addr, device, r8_1, r16_1);
201
        this.register_read(port_addr + 1, device, r8_2);
202
    }
203
};
204

205
/**
206
 * @param {number} port_addr
207
 * @param {!Object} device
208
 * @param {function(number)} w8_1
209
 * @param {function(number)} w8_2
210
 * @param {function(number)=} w8_3
211
 * @param {function(number)=} w8_4
212
 */
213
IO.prototype.register_write_consecutive = function(port_addr, device, w8_1, w8_2, w8_3, w8_4)
214
{
215
    dbg_assert(arguments.length === 4 || arguments.length === 6);
216

217
    function w16_1(data)
218
    {
219
        w8_1.call(this, data & 0xFF);
220
        w8_2.call(this, data >> 8 & 0xFF);
221
    }
222
    function w16_2(data)
223
    {
224
        w8_3.call(this, data & 0xFF);
225
        w8_4.call(this, data >> 8 & 0xFF);
226
    }
227
    function w32(data)
228
    {
229
        w8_1.call(this, data & 0xFF);
230
        w8_2.call(this, data >> 8 & 0xFF);
231
        w8_3.call(this, data >> 16 & 0xFF);
232
        w8_4.call(this, data >>> 24);
233
    }
234

235
    if(w8_3 && w8_4)
236
    {
237
        this.register_write(port_addr,     device, w8_1, w16_1, w32);
238
        this.register_write(port_addr + 1, device, w8_2);
239
        this.register_write(port_addr + 2, device, w8_3, w16_2);
240
        this.register_write(port_addr + 3, device, w8_4);
241
    }
242
    else
243
    {
244
        this.register_write(port_addr,     device, w8_1, w16_1);
245
        this.register_write(port_addr + 1, device, w8_2);
246
    }
247
};
248

249
IO.prototype.mmap_read32_shim = function(addr)
250
{
251
    var aligned_addr = addr >>> MMAP_BLOCK_BITS;
252
    var fn = this.cpu.memory_map_read8[aligned_addr];
253

254
    return fn(addr) | fn(addr + 1) << 8 |
255
            fn(addr + 2) << 16 | fn(addr + 3) << 24;
256
};
257

258
IO.prototype.mmap_write32_shim = function(addr, value)
259
{
260
    var aligned_addr = addr >>> MMAP_BLOCK_BITS;
261
    var fn = this.cpu.memory_map_write8[aligned_addr];
262

263
    fn(addr, value & 0xFF);
264
    fn(addr + 1, value >> 8 & 0xFF);
265
    fn(addr + 2, value >> 16 & 0xFF);
266
    fn(addr + 3, value >>> 24);
267
};
268

269
/**
270
 * @param {number} addr
271
 * @param {number} size
272
 * @param {*} read_func8
273
 * @param {*} write_func8
274
 * @param {*=} read_func32
275
 * @param {*=} write_func32
276
 */
277
IO.prototype.mmap_register = function(addr, size, read_func8, write_func8, read_func32, write_func32)
278
{
279
    dbg_log("mmap_register addr=" + h(addr >>> 0, 8) + " size=" + h(size, 8), LOG_IO);
280

281
    dbg_assert((addr & MMAP_BLOCK_SIZE - 1) === 0);
282
    dbg_assert(size && (size & MMAP_BLOCK_SIZE - 1) === 0);
283

284
    if(!read_func32)
285
        read_func32 = this.mmap_read32_shim.bind(this);
286

287
    if(!write_func32)
288
        write_func32 = this.mmap_write32_shim.bind(this);
289

290
    var aligned_addr = addr >>> MMAP_BLOCK_BITS;
291

292
    for(; size > 0; aligned_addr++)
293
    {
294
        this.cpu.memory_map_read8[aligned_addr] = read_func8;
295
        this.cpu.memory_map_write8[aligned_addr] = write_func8;
296
        this.cpu.memory_map_read32[aligned_addr] = read_func32;
297
        this.cpu.memory_map_write32[aligned_addr] = write_func32;
298

299
        size -= MMAP_BLOCK_SIZE;
300
    }
301
};
302

303

304
IO.prototype.port_write8 = function(port_addr, data)
305
{
306
    var entry = this.ports[port_addr];
307

308
    if(entry.write8 === this.empty_port_write || LOG_ALL_IO)
309
    {
310
        dbg_log(
311
            "write8 port #" + h(port_addr, 4) + " <- " + h(data, 2) + this.get_port_description(port_addr),
312
            LOG_IO
313
        );
314
    }
315
    return entry.write8.call(entry.device, data);
316
};
317

318
IO.prototype.port_write16 = function(port_addr, data)
319
{
320
    var entry = this.ports[port_addr];
321

322
    if(entry.write16 === this.empty_port_write || LOG_ALL_IO)
323
    {
324
        dbg_log(
325
            "write16 port #" + h(port_addr, 4) + " <- " + h(data, 4) + this.get_port_description(port_addr),
326
            LOG_IO
327
        );
328
    }
329
    return entry.write16.call(entry.device, data);
330
};
331

332
IO.prototype.port_write32 = function(port_addr, data)
333
{
334
    var entry = this.ports[port_addr];
335

336
    if(entry.write32 === this.empty_port_write || LOG_ALL_IO)
337
    {
338
        dbg_log(
339
            "write32 port #" + h(port_addr, 4) + " <- " + h(data >>> 0, 8) + this.get_port_description(port_addr),
340
            LOG_IO
341
        );
342
    }
343
    return entry.write32.call(entry.device, data);
344
};
345

346
IO.prototype.port_read8 = function(port_addr)
347
{
348
    var entry = this.ports[port_addr];
349

350
    if(entry.read8 === this.empty_port_read8 || LOG_ALL_IO)
351
    {
352
        dbg_log(
353
            "read8 port  #" + h(port_addr, 4) + this.get_port_description(port_addr),
354
            LOG_IO
355
        );
356
    }
357
    var value = entry.read8.call(entry.device);
358
    dbg_assert(value < 0x100, "8 bit port returned large value: " + h(port_addr));
359
    return value;
360
};
361

362
IO.prototype.port_read16 = function(port_addr)
363
{
364
    var entry = this.ports[port_addr];
365

366
    if(entry.read16 === this.empty_port_read16 || LOG_ALL_IO)
367
    {
368
        dbg_log(
369
            "read16 port  #" + h(port_addr, 4) + this.get_port_description(port_addr),
370
            LOG_IO
371
        );
372
    }
373
    var value = entry.read16.call(entry.device);
374
    dbg_assert(value < 0x10000 && value >= 0, "16 bit port returned large value: " + h(port_addr));
375
    return value;
376
};
377

378
IO.prototype.port_read32 = function(port_addr)
379
{
380
    var entry = this.ports[port_addr];
381

382
    if(entry.read32 === this.empty_port_read32 || LOG_ALL_IO)
383
    {
384
        dbg_log(
385
            "read32 port  #" + h(port_addr, 4) + this.get_port_description(port_addr),
386
            LOG_IO
387
        );
388
    }
389
    var value = entry.read32.call(entry.device);
390
    dbg_assert((value | 0) === value);
391
    return value;
392
};
393

394
// via seabios ioport.h
395
var debug_port_list = {
396
    0x0004: "PORT_DMA_ADDR_2",
397
    0x0005: "PORT_DMA_CNT_2",
398
    0x000a: "PORT_DMA1_MASK_REG",
399
    0x000b: "PORT_DMA1_MODE_REG",
400
    0x000c: "PORT_DMA1_CLEAR_FF_REG",
401
    0x000d: "PORT_DMA1_MASTER_CLEAR",
402
    0x0020: "PORT_PIC1_CMD",
403
    0x0021: "PORT_PIC1_DATA",
404
    0x0040: "PORT_PIT_COUNTER0",
405
    0x0041: "PORT_PIT_COUNTER1",
406
    0x0042: "PORT_PIT_COUNTER2",
407
    0x0043: "PORT_PIT_MODE",
408
    0x0060: "PORT_PS2_DATA",
409
    0x0061: "PORT_PS2_CTRLB",
410
    0x0064: "PORT_PS2_STATUS",
411
    0x0070: "PORT_CMOS_INDEX",
412
    0x0071: "PORT_CMOS_DATA",
413
    0x0080: "PORT_DIAG",
414
    0x0081: "PORT_DMA_PAGE_2",
415
    0x0092: "PORT_A20",
416
    0x00a0: "PORT_PIC2_CMD",
417
    0x00a1: "PORT_PIC2_DATA",
418
    0x00b2: "PORT_SMI_CMD",
419
    0x00b3: "PORT_SMI_STATUS",
420
    0x00d4: "PORT_DMA2_MASK_REG",
421
    0x00d6: "PORT_DMA2_MODE_REG",
422
    0x00da: "PORT_DMA2_MASTER_CLEAR",
423
    0x00f0: "PORT_MATH_CLEAR",
424
    0x0170: "PORT_ATA2_CMD_BASE",
425
    0x01f0: "PORT_ATA1_CMD_BASE",
426
    0x0278: "PORT_LPT2",
427
    0x02e8: "PORT_SERIAL4",
428
    0x02f8: "PORT_SERIAL2",
429
    0x0374: "PORT_ATA2_CTRL_BASE",
430
    0x0378: "PORT_LPT1",
431
    0x03e8: "PORT_SERIAL3",
432
    //0x03f4: "PORT_ATA1_CTRL_BASE",
433
    0x03f0: "PORT_FD_BASE",
434
    0x03f2: "PORT_FD_DOR",
435
    0x03f4: "PORT_FD_STATUS",
436
    0x03f5: "PORT_FD_DATA",
437
    0x03f6: "PORT_HD_DATA",
438
    0x03f7: "PORT_FD_DIR",
439
    0x03f8: "PORT_SERIAL1",
440
    0x0cf8: "PORT_PCI_CMD",
441
    0x0cf9: "PORT_PCI_REBOOT",
442
    0x0cfc: "PORT_PCI_DATA",
443
    0x0402: "PORT_BIOS_DEBUG",
444
    0x0510: "PORT_QEMU_CFG_CTL",
445
    0x0511: "PORT_QEMU_CFG_DATA",
446
    0xb000: "PORT_ACPI_PM_BASE",
447
    0xb100: "PORT_SMB_BASE",
448
    0x8900: "PORT_BIOS_APM"
449
};
450

451
IO.prototype.get_port_description = function(addr)
452
{
453
    if(debug_port_list[addr])
454
    {
455
        return "  (" + debug_port_list[addr] + ")";
456
    }
457
    else
458
    {
459
        return "";
460
    }
461
};
462

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

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

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

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