This repository has been archived by the owner on Dec 24, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 92
/
ram.js
604 lines (574 loc) · 24.1 KB
/
ram.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
/**
* @fileoverview Implements the PCx86 RAM component
* @author <a href="mailto:[email protected]">Jeff Parsons</a>
* @copyright © 2012-2020 Jeff Parsons
*
* This file is part of PCjs, a computer emulation software project at <https://www.pcjs.org>.
*
* PCjs is free software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* PCjs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCjs. If not,
* see <http://www.gnu.org/licenses/gpl.html>.
*
* You are required to include the above copyright notice in every modified copy of this work
* and to display that copyright notice when the software starts running; see COPYRIGHT in
* <https://www.pcjs.org/modules/shared/lib/defines.js>.
*
* Some PCjs files also attempt to load external resource files, such as character-image files,
* ROM files, and disk image files. Those external resource files are not considered part of PCjs
* for purposes of the GNU General Public License, and the author does not claim any copyright
* as to their contents.
*/
"use strict";
if (typeof module !== "undefined") {
var Str = require("../../shared/lib/strlib");
var Web = require("../../shared/lib/weblib");
var Component = require("../../shared/lib/component");
var State = require("../../shared/lib/state");
var PCx86 = require("./defines");
var ChipSet = require("./chipset");
var MemoryX86 = require("./memory");
var ROMx86 = require("./rom");
var Controller = require("./bus").Controller;
}
/**
* class RAMx86
* @unrestricted (allows the class to define properties, both dot and named, outside of the constructor)
*/
class RAMx86 extends Component {
/**
* RAMx86(parmsRAM)
*
* The RAMx86 component expects the following (parmsRAM) properties:
*
* addr: starting physical address of RAM (default is 0)
* size: amount of RAM, in bytes (default is 0, which means defer to motherboard switch settings)
* test: true (default) means don't interfere with any BIOS memory tests, false means "fake a warm boot"
*
* The 'test' parm can also be overridden by the machine-specific 'testRAM' parm.
*
* NOTE: We make a note of the specified size, but no memory is initially allocated for the RAM until the
* Computer component calls powerUp().
*
* @this {RAMx86}
* @param {Object} parmsRAM
*/
constructor(parmsRAM)
{
super("RAMx86", parmsRAM);
this.addrRAM = parmsRAM['addr'];
this.sizeRAM = parmsRAM['size'];
this.fTestRAM = parmsRAM['test'];
this.fInstalled = (!!this.sizeRAM); // 0 is the default value for 'size' when none is specified
this.fAllocated = false;
}
/**
* initBus(cmp, bus, cpu, dbg)
*
* @this {RAMx86}
* @param {Computer} cmp
* @param {BusX86} bus
* @param {CPUx86} cpu
* @param {DebuggerX86} dbg
*/
initBus(cmp, bus, cpu, dbg)
{
this.bus = bus;
this.cpu = cpu;
this.dbg = dbg;
this.chipset = cmp.getMachineComponent("ChipSet");
this.fTestRAM = cmp.getMachineBoolean('testRAM', this.fTestRAM);
this.setReady();
}
/**
* powerUp(data, fRepower)
*
* @this {RAMx86}
* @param {Object|null} data
* @param {boolean} [fRepower]
* @return {boolean} true if successful, false if failure
*/
powerUp(data, fRepower)
{
if (!fRepower) {
/*
* The Computer powers up the CPU last, at which point CPUx86 state is restored,
* which includes the Bus state, and since we use the Bus to allocate all our memory,
* memory contents are already restored for us, so we don't need the usual restore
* logic. We just need to call reset(), to allocate memory for the RAM.
*
* The only exception is when there's a custom Memory controller (eg, CompaqController).
*/
this.reset();
if (data && this.controller) {
if (!this.restore(data)) return false;
}
}
return true;
}
/**
* powerDown(fSave, fShutdown)
*
* @this {RAMx86}
* @param {boolean} [fSave]
* @param {boolean} [fShutdown]
* @return {Object|boolean} component state if fSave; otherwise, true if successful, false if failure
*/
powerDown(fSave, fShutdown)
{
/*
* The Computer powers down the CPU first, at which point CPUx86 state is saved,
* which includes the Bus state, and since we use the Bus component to allocate all
* our memory, memory contents are already saved for us, so we don't need the usual
* save logic.
*
* The only exception is when there's a custom Memory controller (eg, CompaqController).
*/
return (fSave && this.controller)? this.save() : true;
}
/**
* reset()
*
* NOTE: When we were initialized, we were given an amount of INSTALLED memory (see sizeRAM above).
* The ChipSet component, on the other hand, tells us how much SPECIFIED memory there is -- which,
* like a real PC, may not match the amount of installed memory (due to either user error or perhaps
* an attempt to prevent some portion of the installed memory from being used).
*
* However, since we're a virtual machine, we can defer allocation of RAM until we're able to query the
* ChipSet component, and then allocate an amount of memory that matches the SPECIFIED memory, making
* it easy to reconfigure the machine on the fly and prevent mismatches.
*
* But, we do that ONLY for the RAM instance configured with an addrRAM of 0x0000, and ONLY if that RAM
* object was not given a specific size (see fInstalled). If there are other RAM objects in the system,
* they must necessarily specify a non-conflicting, non-zero start address, in which case their sizeRAM
* value will never be affected by the ChipSet settings.
*
* @this {RAMx86}
*/
reset()
{
if (!this.addrRAM && !this.fInstalled && this.chipset) {
let baseRAM = this.chipset.getDIPMemorySize() * 1024;
if (this.sizeRAM && baseRAM != this.sizeRAM) {
this.bus.removeMemory(this.addrRAM, this.sizeRAM);
this.fAllocated = false;
}
this.sizeRAM = baseRAM;
}
if (!this.fAllocated && this.sizeRAM) {
if (this.bus.addMemory(this.addrRAM, this.sizeRAM, MemoryX86.TYPE.RAM)) {
this.fAllocated = true;
/*
* NOTE: I'm specifying MAXDEBUG for status() messages because I'm not yet sure I want these
* messages buried in the app, since they're seen only when a Control Panel is active. Another
* and perhaps better alternative is to add "comment" attributes to the XML configuration file
* for these components, which the Computer component will display as it "powers up" components.
*/
if (MAXDEBUG && !this.addrRAM && this.fInstalled) this.status("specified size overrides SW1");
/*
* Memory with an ID of "ramCPQ" is reserved for built-in memory located just below the 16Mb
* boundary on COMPAQ DeskPro 386 machines.
*
* Technically, that memory is part of the first 1Mb of memory that also provides up to 640Kb
* of conventional memory (ie, memory below 1Mb).
*
* However, PCx86 doesn't support individual memory allocations that (a) are discontiguous
* or (b) dynamically change location. Components must simulate those features by performing
* a separate allocation for each starting address, and removing/adding memory allocations
* whenever their starting address changes.
*
* Therefore, a DeskPro 386's first 1Mb of physical memory is allocated by PCx86 in two pieces,
* and the second piece must have an ID of "ramCPQ", triggering the additional allocation of
* COMPAQ-specific memory-mapped registers.
*
* See CompaqController for more details.
*/
if (DESKPRO386) {
if (this.idComponent == "ramCPQ") {
this.controller = new CompaqController(this);
this.bus.addMemory(CompaqController.ADDR, 4, MemoryX86.TYPE.CTRL, this.controller);
}
}
}
}
if (this.fAllocated) {
if (!this.addrRAM && !this.fTestRAM) {
/*
* HACK: Set the word at 40:72 in the ROM BIOS Data Area (RBDA) to 0x1234 to bypass the ROM BIOS
* memory storage tests. See rom.js for all RBDA definitions.
*/
if (MAXDEBUG) this.status("ROM BIOS memory test has been disabled");
this.bus.setShortDirect(ROMx86.BIOS.RESET_FLAG.ADDR, ROMx86.BIOS.RESET_FLAG.WARMBOOT);
}
/*
* Don't add the "ramCPQ" memory to the CMOS total, because addCMOSMemory() will add it to the extended
* memory total, which will just confuse the COMPAQ BIOS.
*/
if (!DESKPRO386 || this.idComponent != "ramCPQ") {
if (this.chipset) this.chipset.addCMOSMemory(this.addrRAM, this.sizeRAM);
}
} else {
Component.error("No RAM allocated");
}
}
/**
* save()
*
* This implements save support for the RAM component.
*
* @this {RAMx86}
* @return {Object}
*/
save()
{
let state = new State(this);
if (this.controller) state.set(0, this.controller.save());
return state.data();
}
/**
* restore(data)
*
* This implements restore support for the RAM component.
*
* @this {RAMx86}
* @param {Object} data
* @return {boolean} true if successful, false if failure
*/
restore(data)
{
if (this.controller) return this.controller.restore(data[0]);
return true;
}
/**
* RAM.init()
*
* This function operates on every HTML element of class "ram", extracting the
* JSON-encoded parameters for the RAM constructor from the element's "data-value"
* attribute, invoking the constructor to create a RAM component, and then binding
* any associated HTML controls to the new component.
*/
static init()
{
let aeRAM = Component.getElementsByClass(document, PCx86.APPCLASS, "ram");
for (let iRAM = 0; iRAM < aeRAM.length; iRAM++) {
let eRAM = aeRAM[iRAM];
let parmsRAM = Component.getComponentParms(eRAM);
let ram = new RAMx86(parmsRAM);
Component.bindComponentControls(ram, eRAM, PCx86.APPCLASS);
}
}
}
/**
* class CompaqController
* @unrestricted (allows the class to define properties, both dot and named, outside of the constructor)
*/
class CompaqController extends Controller {
/**
* CompaqController(ram)
*
* DeskPro 386 machines came with a minimum of 1Mb of RAM, which could be configured (via jumpers)
* for 256Kb, 512Kb or 640Kb of conventional memory, starting at address 0x00000000, with the
* remainder (768Kb, 512Kb, or 384Kb) accessible only at an address just below 0x01000000. In PCx86,
* this second chunk of RAM must be separately allocated, with an ID of "ramCPQ".
*
* The typical configuration was 640Kb of conventional memory, leaving 384Kb accessible at 0x00FA0000.
* Presumably, the other configurations (256Kb and 512Kb) would leave 768Kb and 512Kb accessible at
* 0x00F40000 and 0x00F80000, respectively.
*
* The DeskPro 386 also contained two memory-mapped registers at 0x80C00000. The first is a write-only
* mapping register that provides the ability to map the 128Kb at 0x00FE0000 to 0x000E0000, replacing
* any ROMs in the range 0x000E0000-0x000FFFFF, and optionally write-protecting that 128Kb; internally,
* this register corresponds to wMappings.
*
* The second register is a read-only diagnostics register that indicates jumper configuration and
* parity errors; internally, this register corresponds to wSettings.
*
* To emulate the memory-mapped registers at 0x80C00000, the RAM component allocates a block at that
* address using this custom controller once it sees an allocation for "ramCPQ".
*
* Later, when the addressability of "ramCPQ" memory is altered, we record the blocks in all the
* memory slots spanning 0x000E0000-0x000FFFFF, and then update those slots with the blocks from
* 0x00FE0000-0x00FFFFFF. Note that only the top 128Kb of "ramCPQ" addressability is affected; the
* rest of that memory, ranging anywhere from 256Kb to 640Kb, remains addressable at its original
* location. COMPAQ's CEMM and VDISK utilities were generally the only software able to access that
* remaining memory (what COMPAQ refers to as "Compaq Built-in Memory").
*
* @this {CompaqController}
* @param {RAMx86} ram
*/
constructor(ram)
{
super();
this.ram = ram;
this.wMappings = CompaqController.MAPPINGS.DEFAULT;
/*
* TODO: wSettings needs to reflect the actual amount of configured memory....
*/
this.wSettings = CompaqController.SETTINGS.DEFAULT;
this.wRAMSetup = CompaqController.RAMSETUP.DEFAULT;
this.aBlocksDst = null;
}
/**
* save()
*
* This implements save support for the CompaqController component.
*
* @this {CompaqController}
* @return {Array}
*/
save()
{
return [this.wMappings, this.wRAMSetup];
}
/**
* restore(data)
*
* This implements restore support for the CompaqController component.
*
* @this {CompaqController}
* @param {Object} data
* @return {boolean} true if successful, false if failure
*/
restore(data)
{
this.setByte(0, data[0] & 0xff);
this.setByte(2, data[1] & 0xff);
return true;
}
/**
* getByte(off)
*
* @this {CompaqController}
* @param {number} off
* @return {number}
*/
getByte(off)
{
/*
* Offsets 0-3 correspond to reads from 0x80C00000-0x80C00003; anything outside that range
* returns our standard non-responsive value of 0xff.
*/
let b = 0xff;
if (off < 0x02) {
b = (off & 0x1)? (this.wSettings >> 8) : (this.wSettings & 0xff);
}
else if (off < 0x4) {
b = (off & 0x1)? (this.wRAMSetup >> 8) : (this.wRAMSetup & 0xff);
}
return b;
}
/**
* setByte(off, b)
*
* @this {CompaqController}
* @param {number} off (relative to 0x80C00000)
* @param {number} b
*/
setByte(off, b)
{
if (!off) {
/*
* This is a write to 0x80C00000
*/
if (b != (this.wMappings & 0xff)) {
let bus = this.ram.bus;
if (!(b & CompaqController.MAPPINGS.UNMAPPED)) {
if (!this.aBlocksDst) {
this.aBlocksDst = bus.getMemoryBlocks(CompaqController.MAP_DST, CompaqController.MAP_SIZE);
}
/*
* You might think that the next three lines could ALSO be moved to the preceding IF,
* but it's possible for the write-protection feature to be enabled/disabled separately
* from the mapping feature. We could avoid executing this code as well by checking the
* current read-write state, but this is an infrequent operation, so there's no point.
*/
let aBlocks = bus.getMemoryBlocks(CompaqController.MAP_SRC, CompaqController.MAP_SIZE);
let type = (b & CompaqController.MAPPINGS.READWRITE)? MemoryX86.TYPE.RAM : MemoryX86.TYPE.ROM;
bus.setMemoryBlocks(CompaqController.MAP_DST, CompaqController.MAP_SIZE, aBlocks, type);
}
else {
if (this.aBlocksDst) {
bus.setMemoryBlocks(CompaqController.MAP_DST, CompaqController.MAP_SIZE, this.aBlocksDst);
this.aBlocksDst = null;
}
}
this.wMappings = (this.wMappings & ~0xff) | b;
}
}
else if (off == 0x2) {
/*
* This is a write to 0x80C00002
*/
this.wRAMSetup = (this.wRAMSetup & ~0xff) | b;
}
}
/**
* getMemoryAccess()
*
* @this {CompaqController}
* @return {Array.<function()>}
*/
getMemoryAccess()
{
return CompaqController.ACCESS;
}
/**
* getMemoryBuffer(addr)
*
* @this {CompaqController}
* @param {number} addr
* @return {Array} containing the buffer (and an offset within that buffer)
*/
getMemoryBuffer(addr)
{
return CompaqController.BUFFER;
}
/**
* readByte(off, addr)
*
* NOTE: Even though we asked bus.addMemory() for only 4 bytes, corresponding to the 4 memory-mapped register
* locations we must manage, we're at the mercy of the Bus component's physical block allocation granularity,
* which, on 80386-based machines, is fixed at 4K (the same as the 80386 page size, to simplify emulation of paging).
*
* So we must allow for requests outside that 4-byte range.
*
* @this {MemoryX86}
* @param {number} off (relative to 0x80C00000)
* @param {number} [addr]
* @return {number}
*/
static readByte(off, addr)
{
let b = this.controller.getByte(off);
if (DEBUG) {
this.controller.ram.printMessage("CompaqController.readByte(" + Str.toHexWord(off) + ") returned " + Str.toHexByte(b), 0, true);
}
return b;
}
/**
* writeByte(off, b, addr)
*
* NOTE: Even though we asked bus.addMemory() for only 4 bytes, corresponding to the 4 memory-mapped register
* locations we must manage, we're at the mercy of the Bus component's physical memory allocation granularity,
* which, on 80386-based machines, is fixed at 4K (the same as the 80386 page size, to simplify emulation of paging).
*
* So we must allow for requests outside that 4-byte range.
*
* @this {MemoryX86}
* @param {number} off (relative to 0x80C00000)
* @param {number} b
* @param {number} [addr]
*/
static writeByte(off, b, addr)
{
this.controller.setByte(off, b);
/*
* All bits in 0x80C00001 and 0x80C00003 are reserved, so we can simply ignore those writes.
*/
if (DEBUG) {
this.controller.ram.printMessage("CompaqController.writeByte(" + Str.toHexWord(off) + "," + Str.toHexByte(b) + ")", 0, true);
}
}
}
CompaqController.ADDR = 0x80C00000|0;
CompaqController.MAP_SRC = 0x00FE0000;
CompaqController.MAP_DST = 0x000E0000;
CompaqController.MAP_SIZE = 0x00020000;
/*
* Bit definitions for the 16-bit write-only memory-mapping register (wMappings)
*
* NOTE: Although COMPAQ says the memory at %FE0000 is "relocated", it actually remains addressable
* at %FE0000; it simply becomes addressable at %0E0000 as well, displacing any ROMs that used to be
* addressable at %0E0000 through %0FFFFF.
*/
CompaqController.MAPPINGS = {
UNMAPPED: 0x0001, // is this bit is CLEAR, the last 128Kb (at 0x00FE0000) is mapped to 0x000E0000
READWRITE: 0x0002, // if this bit is CLEAR, the last 128Kb (at 0x00FE0000) is read-only (ie, write-protected)
RESERVED: 0xFFFC, // the remaining 6 bits are reserved and should always be SET
DEFAULT: 0xFFFF // our default settings (no mapping, no write-protection)
};
/*
* Bit definitions for the 16-bit read-only settings/diagnostics register (wSettings)
*
* SW1-7 and SW1-8 are mapped to bits 5 and 4 of wSettings, respectively, as follows:
*
* SW1-7 SW1-8 Bit5 Bit4 Amount (of base memory provided by the COMPAQ 32-bit memory board)
* ----- ----- ---- ---- ------
* ON ON 0 0 640Kb
* ON OFF 0 1 Invalid
* OFF ON 1 0 512Kb
* OFF OFF 1 1 256Kb
*
* Other SW1 switches include:
*
* SW1-1: ON enables fail-safe timer
* SW1-2: ON indicates 80387 coprocessor installed
* SW1-3: ON sets memory from 0xC00000 to 0xFFFFFF (between 12 and 16 megabytes) non-cacheable
* SW1-4: ON selects AUTO system speed (OFF selects HIGH system speed)
* SW1-5: RESERVED (however, the system can read its state; see below)
* SW1-6: COMPAQ Dual-Mode Monitor or Color Monitor (OFF selects Monochrome monitor other than COMPAQ)
*
* While SW1-7 and SW1-8 are connected to this memory-mapped register, other SW1 DIP switches are accessible
* through the 8042 Keyboard Controller's KBC.INPORT register, as follows:
*
* SW1-1: TODO: Determine
* SW1-2: ChipSet.KC8042.INPORT.COMPAQ_NO80387 clear if ON, set (0x04) if OFF
* SW1-3: TODO: Determine
* SW1-4: ChipSet.KC8042.INPORT.COMPAQ_HISPEED clear if ON, set (0x10) if OFF
* SW1-5: ChipSet.KC8042.INPORT.COMPAQ_DIP5OFF clear if ON, set (0x20) if OFF
* SW1-6: ChipSet.KC8042.INPORT.COMPAQ_NONDUAL clear if ON, set (0x40) if OFF
*/
CompaqController.SETTINGS = {
B0_PARITY: 0x0001, // parity OK in byte 0
B1_PARITY: 0x0002, // parity OK in byte 1
B2_PARITY: 0x0004, // parity OK in byte 2
B3_PARITY: 0x0008, // parity OK in byte 3
BASE_640KB: 0x0000, // SW1-7,8: ON ON Bits 5,4: 00
BASE_ERROR: 0x0010, // SW1-7,8: ON OFF Bits 5,4: 01
BASE_512KB: 0x0020, // SW1-7,8: OFF ON Bits 5,4: 10
BASE_256KB: 0x0030, // SW1-7,8: OFF OFF Bits 5,4: 11
/*
* TODO: The DeskPro 386/25 TechRef says bit 6 (0x40) is always set,
* but setting it results in memory configuration errors; review.
*/
ADDED_1MB: 0x0040,
/*
* TODO: The DeskPro 386/25 TechRef says bit 7 (0x80) is always clear; review.
*/
PIGGYBACK: 0x0080,
SYS_4MB: 0x0100, // 4Mb on system board
SYS_1MB: 0x0200, // 1Mb on system board
SYS_NONE: 0x0300, // no memory on system board
MODA_4MB: 0x0400, // 4Mb on module A board
MODA_1MB: 0x0800, // 1Mb on module A board
MODA_NONE: 0x0C00, // no memory on module A board
MODB_4MB: 0x1000, // 4Mb on module B board
MODB_1MB: 0x2000, // 1Mb on module B board
MODB_NONE: 0x3000, // no memory on module B board
MODC_4MB: 0x4000, // 4Mb on module C board
MODC_1MB: 0x8000, // 1Mb on module C board
MODC_NONE: 0xC000, // no memory on module C board
/*
* NOTE: It doesn't seem to matter to the ROM whether I set any of bits 8-15 or not....
*/
DEFAULT: 0x0A0F // our default settings (ie, parity OK, 640Kb base memory, 1Mb system memory, 1Mb module A memory)
};
CompaqController.RAMSETUP = {
SETUP: 0x000F,
CACHE: 0x0040,
RESERVED: 0xFFB0,
DEFAULT: 0x0002 // our default settings (ie, 2Mb, cache disabled)
};
CompaqController.BUFFER = [null, 0];
CompaqController.ACCESS = [CompaqController.readByte, null, null, CompaqController.writeByte, null, null];
/*
* Initialize all the RAM modules on the page.
*/
Web.onInit(RAMx86.init);
if (typeof module !== "undefined") module.exports = RAMx86;