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 91
/
Copy pathchipset.js
5999 lines (5663 loc) · 250 KB
/
chipset.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
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/**
* @fileoverview Implements the PCjs ChipSet component.
* @author <a href="mailto:[email protected]">Jeff Parsons</a>
* @version 1.0
* Created 2012-Sep-14
*
* Copyright © 2012-2016 Jeff Parsons <[email protected]>
*
* This file is part of PCjs, which is part of the JavaScript Machines Project (aka JSMachines)
* at <http://jsmachines.net/> and <http://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 source code file of every
* copy or modified version of this work, and to display that copyright notice on every screen
* that loads or runs any version of this software (see Computer.COPYRIGHT).
*
* 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 the
* PCjs program for purposes of the GNU General Public License, and the author does not claim
* any copyright as to their contents.
*/
"use strict";
if (NODE) {
var str = require("../../shared/lib/strlib");
var usr = require("../../shared/lib/usrlib");
var web = require("../../shared/lib/weblib");
var Component = require("../../shared/lib/component");
var Interrupts = require("./interrupts");
var Messages = require("./messages");
var State = require("./state");
var X86 = require("./x86");
}
/**
* ChipSet(parmsChipSet)
*
* The ChipSet component has the following component-specific (parmsChipSet) properties:
*
* model: eg, "5150", "5160", "5170", "deskpro386" (should be a member of ChipSet.MODELS)
* sw1: 8-character binary string representing the SW1 DIP switches (SW1[1-8]); see Switches Overview
* sw2: 8-character binary string representing the SW2 DIP switches (SW2[1-8]) (MODEL_5150 only)
* sound: true to enable (experimental) sound support (default); false to disable
* scaleTimers: true to divide timer cycle counts by the CPU's cycle multiplier (default is false)
* floppies: array of floppy drive sizes in Kb (default is "[360, 360]" if no sw1 value provided)
* monitor: none|tv|color|mono|ega|vga (if no sw1 value provided, default is "ega" for 5170, "mono" otherwise)
* rtcDate: optional RTC date/time (in GMT) to use on reset; use the ISO 8601 format; eg: "2014-10-01T08:00:00"
*
* As support for IBM-compatible machines grows, we should refrain from adding new model strings (eg, "att6300")
* and corresponding model checks, and instead add more ChipSet configuration properties, such as:
*
* pit1port: 0x48 to enable PIT1 at base port 0x48 (as used by COMPAQ_DESKPRO386); default to undefined
* kbdchip: 8041 to select 8041 emulation (eg, for ATT_6300); default to 8255 for MODEL_5150/MODEL_5160, 8042 for MODEL_5170
*
* @constructor
* @extends Component
* @param {Object} parmsChipSet
*/
function ChipSet(parmsChipSet)
{
Component.call(this, "ChipSet", parmsChipSet, ChipSet, Messages.CHIPSET);
var model = parmsChipSet['model'];
/*
* this.model is a numeric version of the 'model' string; when comparing this.model to standard IBM
* model numbers, you should generally compare (this.model|0) to the target value, which truncates it.
*/
if (model && !ChipSet.MODELS[model]) {
Component.notice("Unrecognized ChipSet model: " + model);
}
this.model = ChipSet.MODELS[model] || ChipSet.MODEL_5150_OTHER;
var bSwitches;
this.aDIPSwitches = [];
/*
* SW1 describes the number of floppy drives, the amount of base memory, the primary monitor type,
* and (on the MODEL_5160) whether or not a coprocessor is installed. If no SW1 settings are provided,
* we look for individual 'floppies' and 'monitor' settings and build a default SW1 value.
*
* The defaults below select max memory, monochrome monitor (EGA monitor for MODEL_5170), and two floppies.
* Don't get too excited about "max memory" either: on a MODEL_5150, the max was 64Kb, and on a MODEL_5160,
* the max was 256Kb. However, the RAM component is free to install as much base memory as it likes,
* overriding the SW1 memory setting.
*
* Given that the ROM BIOS is hard-coded to load boot sectors @0000:7C00, the minimum amount of system RAM
* required to boot is therefore 32Kb. Whether that's actually enough to run any or all versions of PC-DOS is
* a separate question. FYI, with only 16Kb, the ROM BIOS will still try to boot, and fail miserably.
*/
bSwitches = this.parseDIPSwitches(parmsChipSet[ChipSet.CONTROLS.SW1]);
this.aDIPSwitches[0] = [bSwitches, bSwitches];
if (bSwitches == null) {
this.aFloppyDrives = [360, 360];
var aFloppyDrives = parmsChipSet['floppies'];
if (aFloppyDrives && aFloppyDrives.length) this.aFloppyDrives = aFloppyDrives;
this.setDIPSwitches(ChipSet.SWITCH_TYPE.FLOPNUM, this.aFloppyDrives.length);
var sMonitor = parmsChipSet['monitor'] || (this.model < ChipSet.MODEL_5170? "mono" : "ega");
this.setDIPSwitches(ChipSet.SWITCH_TYPE.MONITOR, sMonitor);
}
/*
* SW2 describes the number of 32Kb blocks of I/O expansion RAM that's present in the system. The MODEL_5150
* ROM BIOS only checked/supported the first four switches, so the maximum amount of additional RAM specifiable
* was 15 * 32Kb, or 480Kb. So with a 16Kb-64Kb motherboard, the MODEL_5150 ROM BIOS could support a grand
* total of 544Kb. With the 64Kb-256Kb motherboard revision, a 5150 could use the first FIVE SW2 switches,
* allowing for a grand total as high as 640Kb.
*
* For MODEL_5160 (PC XT) and up, memory expansion cards had their own switches, and the motherboard
* SW2 switches for I/O expansion RAM were eliminated. Instead, the ROM BIOS scans the entire address space
* (up to 0xA0000) looking for additional memory. As a result, the only mechanism we provide for adding RAM
* (above the maximum of 256Kb supported on the motherboard) is the "size" parameter of the RAM component.
*
* NOTE: If you use the "size" parameter, you will not be able to dynamically alter the memory configuration;
* the RAM component will ignore any changes to SW1.
*/
bSwitches = this.parseDIPSwitches(parmsChipSet[ChipSet.CONTROLS.SW2]);
this.aDIPSwitches[1] = [bSwitches, bSwitches];
this.sCellClass = PCJSCLASS + "-bitCell";
this.cDMACs = this.cPICs = 1;
if (this.model >= ChipSet.MODEL_5170) {
this.cDMACs = this.cPICs = 2;
}
this.fScaleTimers = parmsChipSet['scaleTimers'] || false;
this.sRTCDate = parmsChipSet['rtcDate'];
/*
* Here, I'm finally getting around to trying the Web Audio API. Fortunately, based on what little I know about
* sound generation, using the API to make the same noises as the IBM PC speaker seems straightforward.
*
* To start, we create an audio context, unless the 'sound' parameter has been explicitly set to false.
*
* From:
*
* http://developer.apple.com/library/safari/#documentation/AudioVideo/Conceptual/Using_HTML5_Audio_Video/PlayingandSynthesizingSounds/PlayingandSynthesizingSounds.html
*
* "Similar to how HTML5 canvas requires a context on which lines and curves are drawn, Web Audio requires an audio context
* on which sounds are played and manipulated. This context will be the parent object of further audio objects to come....
* Your audio context is typically created when your page initializes and should be long-lived. You can play multiple sounds
* coming from multiple sources within the same context, so it is unnecessary to create more than one audio context per page."
*/
this.fSpeaker = false;
if (parmsChipSet['sound']) {
this.classAudio = this.contextAudio = null;
if (window) {
this.classAudio = window['AudioContext'] || window['webkitAudioContext'];
}
if (this.classAudio) {
this.contextAudio = new this.classAudio();
} else {
if (DEBUG) this.log("AudioContext not available");
}
}
/*
* I used to defer ChipSet's reset() to powerUp(), which then gave us the option of doing either
* reset() OR restore(), instead of both. However, on MODEL_5170 machines, the initial CMOS data
* needs to be created earlier, so that when other components are initializing their state (eg, when
* HDC calls setCMOSDriveType() or RAM calls addCMOSMemory()), the CMOS will be ready to take their calls.
*/
this.reset(true);
this.setReady();
}
Component.subclass(ChipSet);
/*
* Ports Overview
* --------------
*
* This module provides support for many of the following components (except where a separate component is noted).
* This list is taken from p.1-8 ("System Unit") of the IBM 5160 (PC XT) Technical Reference Manual (as revised
* April 1983), only because I didn't see a similar listing in the original 5150 Technical Reference.
*
* Port(s) Description
* ------- -----------
* 000-00F DMA Chip 8237A-5 [see below]
* 020-021 Interrupt 8259A [see below]
* 040-043 Timer 8253-5 [see below]
* 060-063 PPI 8255A-5 [see below]
* 080-083 DMA Page Registers [see below]
* 0Ax [1] NMI Mask Register [see below]
* 0Cx Reserved
* 0Ex Reserved
* 200-20F Game Control
* 210-217 Expansion Unit
* 220-24F Reserved
* 278-27F Reserved
* 2F0-2F7 Reserved
* 2F8-2FF Asynchronous Communications (Secondary) [see the SerialPort component]
* 300-31F Prototype Card
* 320-32F Hard Drive Controller (XTC) [see the HDC component]
* 378-37F Printer
* 380-38C [2] SDLC Communications
* 380-389 [2] Binary Synchronous Communications (Secondary)
* 3A0-3A9 Binary Synchronous Communications (Primary)
* 3B0-3BF IBM Monochrome Display/Printer [see the Video component]
* 3C0-3CF Reserved
* 3D0-3DF Color/Graphics (Motorola 6845) [see the Video component]
* 3EO-3E7 Reserved
* 3FO-3F7 Floppy Drive Controller [see the FDC component]
* 3F8-3FF Asynchronous Communications (Primary) [see the SerialPort component]
*
* [1] At power-on time, NMI is masked off, perhaps because models 5150 and 5160 also tie coprocessor
* (FPU) interrupts to NMI. Suppressing NMI by default seems odd, because that would also suppress memory
* parity errors. TODO: Determine whether "power-on time" refers to the initial power-on state of the
* NMI Mask Register or the state that the BIOS "POST" (Power-On Self-Test) sets.
*
* [2] These devices cannot be used together since their port addresses overlap.
*
* MODEL_5170 Description
* ---------- -----------
* 070 [3] CMOS Address ChipSet.CMOS.ADDR.PORT
* 071 CMOS Data ChipSet.CMOS.DATA.PORT
* 0F0 FPU Coprocessor Clear Busy (output 0x00)
* 0F1 FPU Coprocessor Reset (output 0x00)
* 1F0-1F7 Hard Drive Controller (ATC) [see the HDC component]
*
* [3] Port 0x70 doubles as the NMI Mask Register: output a CMOS address with bit 7 clear to enable NMI
* or with bit 7 set to disable NMI (apparently the inverse of the older NMI Mask Register at port 0xA0).
* Also, apparently unlike previous models, the MODEL_5170 POST leaves NMI enabled. And fortunately, the
* FPU coprocessor interrupt line is no longer tied to NMI (it uses IRQ 13).
*/
/*
* Supported model numbers
*
* In general, when comparing this.model to "base" model numbers (ie, non-REV numbers), you should use
* (this.model|0), which truncates the current model number.
*
* Note that there were two 5150 motherboard revisions: the "REV A" 16Kb-64Kb motherboard and the
* "REV B" 64Kb-256Kb motherboard. There may have been a manufacturing correlation between motherboard
* revisions ("REV A" and "REV B") and the ROM BIOS revisions shown below, but in general, we can't assume
* any correlation, because newer ROMs could be installed with either motherboard.
*
* I do know that, for "REV A" motherboards, the Apr 1984 5150 TechRef says that "To expand the memory
* of your system beyond 544K requires your IBM Personal Computer System Unit to have a BIOS ROM module
* dated 10/27/82 or later." Which suggests that SW2[5] was not used until the REV3 5150 ROM BIOS.
*
* For now, we treat all our MODEL_5150 systems as 16Kb-64Kb motherboards; if you want a 64Kb-256Kb motherboard,
* then step up to a MODEL_5160 system. We use a multiplier of 16 for 5150 LOWMEM values, and a multiplier
* of 64 for 5160 LOWMEM values.
*/
ChipSet.MODEL_5150 = 5150; // used in reference to the 1st 5150 ROM BIOS, dated Apr 24, 1981
ChipSet.MODEL_5150_REV2 = 5150.2; // used in reference to the 2nd 5150 ROM BIOS, dated Oct 19, 1981
ChipSet.MODEL_5150_REV3 = 5150.3; // used in reference to the 3rd 5150 ROM BIOS, dated Oct 27, 1982
ChipSet.MODEL_5150_OTHER = 5150.9;
ChipSet.MODEL_5160 = 5160; // used in reference to the 1st 5160 ROM BIOS, dated Nov 08, 1982
ChipSet.MODEL_5160_REV2 = 5160.2; // used in reference to the 1st 5160 ROM BIOS, dated Jan 10, 1986
ChipSet.MODEL_5160_REV3 = 5160.3; // used in reference to the 1st 5160 ROM BIOS, dated May 09, 1986
ChipSet.MODEL_5160_OTHER = 5160.9;
ChipSet.MODEL_5170 = 5170; // used in reference to the 1st 5170 ROM BIOS, dated Jan 10, 1984
ChipSet.MODEL_5170_REV2 = 5170.2; // used in reference to the 2nd 5170 ROM BIOS, dated Jun 10, 1985
ChipSet.MODEL_5170_REV3 = 5170.3; // used in reference to the 3rd 5170 ROM BIOS, dated Nov 15, 1985
ChipSet.MODEL_5170_OTHER = 5170.9;
/*
* Assorted non-IBM models (we don't put "IBM" in the IBM models, but non-IBM models should include the company name).
*/
ChipSet.MODEL_CDP_MPC1600 = 5150.101; // Columbia Data Products MPC 1600 ("Copyright Columbia Data Products 1983, ROM/BIOS Ver 4.34")
ChipSet.MODEL_COMPAQ_PORTABLE = 5150.102; // COMPAQ Portable (COMPAQ's first PC)
ChipSet.MODEL_ATT_6300 = 5160.101; // AT&T Personal Computer 6300/Olivetti M24 ("COPYRIGHT (C) OLIVETTI 1984","04/03/86",v1.43)
ChipSet.MODEL_ZENITH_Z150 = 5160.150; // Zenith Data Systems Z-150 ("08/11/88 (C)ZDS CORP")
ChipSet.MODEL_COMPAQ_DESKPRO386 = 5180; // COMPAQ DeskPro 386 (COMPAQ's first 80386-based PC); should be > MODEL_5170
/*
* Last but not least, a complete list of supported model strings, and corresponding internal model numbers.
*/
ChipSet.MODELS = {
"5150": ChipSet.MODEL_5150,
"5160": ChipSet.MODEL_5160,
"5170": ChipSet.MODEL_5170,
"att6300": ChipSet.MODEL_ATT_6300,
"mpc1600": ChipSet.MODEL_CDP_MPC1600,
"z150": ChipSet.MODEL_ZENITH_Z150,
"compaq": ChipSet.MODEL_COMPAQ_PORTABLE,
"other": ChipSet.MODEL_5150_OTHER
};
if (DESKPRO386) {
ChipSet.MODELS["deskpro386"] = ChipSet.MODEL_COMPAQ_DESKPRO386;
}
ChipSet.CONTROLS = {
SW1: "sw1",
SW2: "sw2",
SWDESC: "swdesc"
};
/*
* Values returned by ChipSet.getDIPVideoMonitor()
*/
ChipSet.MONITOR = {
NONE: 0,
TV: 1, // Composite monitor (lower resolution; no support)
COLOR: 2, // Color Display (5153)
MONO: 3, // Monochrome Display (5151)
EGACOLOR: 4, // Enhanced Color Display (5154) in High-Res Mode
EGAEMULATION: 6, // Enhanced Color Display (5154) in Emulation Mode
VGACOLOR: 7 // VGA Color Display
};
/*
* 8237A DMA Controller (DMAC) I/O ports
*
* MODEL_5150 and up uses DMA channel 0 for memory refresh cycles and channel 2 for the FDC.
*
* MODEL_5160 and up uses DMA channel 3 for HDC transfers (XTC only).
*
* DMA0 refers to the original DMA controller found on all models, and DMA1 refers to the additional
* controller found on MODEL_5170 and up; channel 4 on DMA1 is used to "cascade" channels 0-3 from DMA0,
* so only channels 5-7 are available on DMA1.
*
* For FDC DMA notes, refer to http://wiki.osdev.org/ISA_DMA
* For general DMA notes, refer to http://www.freebsd.org/doc/en/books/developers-handbook/dma.html
*
* TODO: Determine why the MODEL_5150 ROM BIOS sets the DMA channel 1 page register (port 0x83) to zero.
*/
ChipSet.DMA0 = {
INDEX: 0,
PORT: {
CH0_ADDR: 0x00, // OUT: starting address IN: current address
CH0_COUNT: 0x01, // OUT: starting word count IN: remaining word count
CH1_ADDR: 0x02, // OUT: starting address IN: current address
CH1_COUNT: 0x03, // OUT: starting word count IN: remaining word count
CH2_ADDR: 0x04, // OUT: starting address IN: current address
CH2_COUNT: 0x05, // OUT: starting word count IN: remaining word count
CH3_ADDR: 0x06, // OUT: starting address IN: current address
CH3_COUNT: 0x07, // OUT: starting word count IN: remaining word count
CMD_STATUS: 0x08, // OUT: command register IN: status register
REQUEST: 0x09,
MASK: 0x0A,
MODE: 0x0B,
RESET_FF: 0x0C, // reset flip-flop
MASTER_CLEAR: 0x0D, // OUT: master clear IN: temporary register
MASK_CLEAR: 0x0E, // TODO: Provide handlers
MASK_ALL: 0x0F, // TODO: Provide handlers
CH2_PAGE: 0x81, // OUT: DMA channel 2 page register
CH3_PAGE: 0x82, // OUT: DMA channel 3 page register
CH1_PAGE: 0x83, // OUT: DMA channel 1 page register
CH0_PAGE: 0x87 // OUT: DMA channel 0 page register (unusable; See "The Inside Out" book, p.246)
}
};
ChipSet.DMA1 = {
INDEX: 1,
PORT: {
CH6_PAGE: 0x89, // OUT: DMA channel 6 page register (MODEL_5170)
CH7_PAGE: 0x8A, // OUT: DMA channel 7 page register (MODEL_5170)
CH5_PAGE: 0x8B, // OUT: DMA channel 5 page register (MODEL_5170)
CH4_PAGE: 0x8F, // OUT: DMA channel 4 page register (MODEL_5170; unusable; aka "Refresh" page register?)
CH4_ADDR: 0xC0, // OUT: starting address IN: current address
CH4_COUNT: 0xC2, // OUT: starting word count IN: remaining word count
CH5_ADDR: 0xC4, // OUT: starting address IN: current address
CH5_COUNT: 0xC6, // OUT: starting word count IN: remaining word count
CH6_ADDR: 0xC8, // OUT: starting address IN: current address
CH6_COUNT: 0xCA, // OUT: starting word count IN: remaining word count
CH7_ADDR: 0xCC, // OUT: starting address IN: current address
CH7_COUNT: 0xCE, // OUT: starting word count IN: remaining word count
CMD_STATUS: 0xD0, // OUT: command register IN: status register
REQUEST: 0xD2,
MASK: 0xD4,
MODE: 0xD6,
RESET_FF: 0xD8, // reset flip-flop
MASTER_CLEAR: 0xDA, // master clear
MASK_CLEAR: 0xDC, // TODO: Provide handlers
MASK_ALL: 0xDE // TODO: Provide handlers
}
};
ChipSet.DMA_CMD = {
M2M_ENABLE: 0x01,
CH0HOLD_ENABLE: 0x02,
CTRL_DISABLE: 0x04,
COMP_TIMING: 0x08,
ROT_PRIORITY: 0x10,
EXT_WRITE_SEL: 0x20,
DREQ_ACTIVE_LO: 0x40,
DACK_ACTIVE_HI: 0x80
};
ChipSet.DMA_STATUS = {
CH0_TC: 0x01, // Channel 0 has reached Terminal Count (TC)
CH1_TC: 0x02, // Channel 1 has reached Terminal Count (TC)
CH2_TC: 0x04, // Channel 2 has reached Terminal Count (TC)
CH3_TC: 0x08, // Channel 3 has reached Terminal Count (TC)
ALL_TC: 0x0f, // all TC bits are cleared whenever DMA_STATUS is read
CH0_REQ: 0x10, // Channel 0 DMA requested
CH1_REQ: 0x20, // Channel 1 DMA requested
CH2_REQ: 0x40, // Channel 2 DMA requested
CH3_REQ: 0x80 // Channel 3 DMA requested
};
ChipSet.DMA_MASK = {
CHANNEL: 0x03,
CHANNEL_SET: 0x04
};
ChipSet.DMA_MODE = {
CHANNEL: 0x03, // bits 0-1 select 1 of 4 possible channels
TYPE: 0x0C, // bits 2-3 select 1 of 3 valid (4 possible) transfer types
TYPE_VERIFY: 0x00, // pseudo transfer (generates addresses, responds to EOP, but nothing is moved)
TYPE_WRITE: 0x04, // write to memory (move data FROM an I/O device; eg, reading a sector from a disk)
TYPE_READ: 0x08, // read from memory (move data TO an I/O device; eg, writing a sector to a disk)
AUTOINIT: 0x10,
DECREMENT: 0x20, // clear for INCREMENT
MODE: 0xC0, // bits 6-7 select 1 of 4 possible transfer modes
MODE_DEMAND: 0x00,
MODE_SINGLE: 0x40,
MODE_BLOCK: 0x80,
MODE_CASCADE: 0xC0
};
ChipSet.DMA_REFRESH = 0x00; // DMA channel assigned to memory refresh
ChipSet.DMA_FDC = 0x02; // DMA channel assigned to the Floppy Drive Controller (FDC)
ChipSet.DMA_HDC = 0x03; // DMA channel assigned to the Hard Drive Controller (HDC; XTC only)
/*
* 8259A Programmable Interrupt Controller (PIC) I/O ports
*
* Internal registers:
*
* ICW1 Initialization Command Word 1 (sent to port ChipSet.PIC_LO)
* ICW2 Initialization Command Word 2 (sent to port ChipSet.PIC_HI)
* ICW3 Initialization Command Word 3 (sent to port ChipSet.PIC_HI)
* ICW4 Initialization Command Word 4 (sent to port ChipSet.PIC_HI)
* IMR Interrupt Mask Register
* IRR Interrupt Request Register
* ISR Interrupt Service Register
* IRLow (IR having lowest priority; IR+1 will have highest priority; default is 7)
*
* Note that ICW2 effectively contains the starting IDT vector number (ie, for IRQ 0),
* which must be multiplied by 4 to calculate the vector offset, since every vector is 4 bytes long.
*
* Also, since the low 3 bits of ICW2 are ignored in 8086/8088 mode (ie, they are effectively
* treated as zeros), this means that the starting IDT vector can only be a multiple of 8.
*
* So, if ICW2 is set to 0x08, the starting vector number (ie, for IRQ 0) will be 0x08, and the
* 4-byte address for the corresponding ISR will be located at offset 0x20 in the real-mode IDT.
*
* ICW4 is typically set to 0x09, indicating 8086 mode, non-automatic EOI, buffered/slave mode.
*
* TODO: Determine why the original ROM BIOS chose buffered/slave over buffered/master.
* Did it simply not matter in pre-AT systems with only one PIC, or am I misreading something?
*
* TODO: Consider support for level-triggered PIC interrupts, even though the original IBM PCs
* (up through MODEL_5170) used only edge-triggered interrupts.
*/
ChipSet.PIC0 = { // all models: the "master" PIC
INDEX: 0,
PORT_LO: 0x20,
PORT_HI: 0x21
};
ChipSet.PIC1 = { // MODEL_5170 and up: the "slave" PIC
INDEX: 1,
PORT_LO: 0xA0,
PORT_HI: 0xA1
};
ChipSet.PIC_LO = { // ChipSet.PIC1.PORT_LO or ChipSet.PIC2.PORT_LO
ICW1: 0x10, // set means ICW1
ICW1_ICW4: 0x01, // ICW4 needed (otherwise ICW4 must be sent)
ICW1_SNGL: 0x02, // single PIC (and therefore no ICW3; otherwise there is another "cascaded" PIC)
ICW1_ADI: 0x04, // call address interval is 4 (otherwise 8; presumably ignored in 8086/8088 mode)
ICW1_LTIM: 0x08, // level-triggered interrupt mode (otherwise edge-triggered mode, which is what PCs use)
OCW2: 0x00, // bit 3 (PIC_LO.OCW3) and bit 4 (ChipSet.PIC_LO.ICW1) are clear in an OCW2 command byte
OCW2_IR_LVL: 0x07,
OCW2_OP_MASK: 0xE0, // of the following valid OCW2 operations, the first 4 are EOI commands (all have ChipSet.PIC_LO.OCW2_EOI set)
OCW2_EOI: 0x20, // non-specific EOI (end-of-interrupt)
OCW2_EOI_SPEC: 0x60, // specific EOI
OCW2_EOI_ROT: 0xA0, // rotate on non-specific EOI
OCW2_EOI_ROTSPEC: 0xE0, // rotate on specific EOI
OCW2_SET_ROTAUTO: 0x80, // set rotate in automatic EOI mode
OCW2_CLR_ROTAUTO: 0x00, // clear rotate in automatic EOI mode
OCW2_SET_PRI: 0xC0, // bits 0-2 specify the lowest priority interrupt
OCW3: 0x08, // bit 3 (PIC_LO.OCW3) is set and bit 4 (PIC_LO.ICW1) clear in an OCW3 command byte (bit 7 should be clear, too)
OCW3_READ_IRR: 0x02, // read IRR register
OCW3_READ_ISR: 0x03, // read ISR register
OCW3_READ_CMD: 0x03,
OCW3_POLL_CMD: 0x04, // poll
OCW3_SMM_RESET: 0x40, // special mask mode: reset
OCW3_SMM_SET: 0x60, // special mask mode: set
OCW3_SMM_CMD: 0x60
};
ChipSet.PIC_HI = { // ChipSet.PIC1.PORT_HI or ChipSet.PIC2.PORT_HI
ICW2_VECTOR: 0xF8, // starting vector number (bits 0-2 are effectively treated as zeros in 8086/8088 mode)
ICW4_8086: 0x01,
ICW4_AUTO_EOI: 0x02,
ICW4_MASTER: 0x04,
ICW4_BUFFERED: 0x08,
ICW4_FULLY_NESTED: 0x10,
OCW1_IMR: 0xFF
};
/*
* The priorities of IRQs 0-7 are normally high to low, unless the master PIC has been reprogrammed.
* Also, if a slave PIC is present, the priorities of IRQs 8-15 fall between the priorities of IRQs 1 and 3.
*
* As the MODEL_5170 TechRef states:
*
* "Interrupt requests are prioritized, with IRQ9 through IRQ12 and IRQ14 through IRQ15 having the
* highest priority (IRQ9 is the highest) and IRQ3 through IRQ7 having the lowest priority (IRQ7 is
* the lowest).
*
* Interrupt 13 (IRQ.FPU) is used on the system board and is not available on the I/O channel.
* Interrupt 8 (IRQ.RTC) is used for the real-time clock."
*
* This priority scheme is a byproduct of IRQ8 through IRQ15 (slave PIC interrupts) being tied to IRQ2 of
* the master PIC. As a result, the two other system board interrupts, IRQ0 and IRQ1, continue to have the
* highest priority, by default.
*/
ChipSet.IRQ = {
TIMER0: 0x00,
KBD: 0x01,
SLAVE: 0x02, // MODEL_5170
COM2: 0x03,
COM1: 0x04,
XTC: 0x05, // MODEL_5160 uses IRQ 5 for HDC (XTC version)
LPT2: 0x05, // MODEL_5170 uses IRQ 5 for LPT2
FDC: 0x06,
LPT1: 0x07,
RTC: 0x08, // MODEL_5170
IRQ2: 0x09, // MODEL_5170
FPU: 0x0D, // MODEL_5170
ATC: 0x0E // MODEL_5170 uses IRQ 14 for HDC (ATC version)
};
/*
* 8253 Programmable Interval Timer (PIT) I/O ports
*
* Although technically, a PIT provides 3 "counters" rather than 3 "timers", we have
* adopted IBM's TechRef nomenclature, which refers to the PIT's counters as TIMER0,
* TIMER1, and TIMER2. For machines with a second PIT (eg, the DeskPro 386), we refer
* to those additional counters as TIMER3, TIMER4, and TIMER5.
*
* In addition, if there's a need to refer to a specific PIT, use PIT0 for the first PIT
* and PIT1 for the second. This mirrors how we refer to multiple DMA controllers
* (eg, DMA0 and DMA1) and multiple PICs (eg, PIC0 and PIC1).
*
* This differs from COMPAQ's nomenclature, which used "Timer 1" to refer to the first
* PIT, and "Timer 2" for the second PIT, and then referred to "Counter 0", "Counter 1",
* and "Counter 2" within each PIT.
*/
ChipSet.PIT0 = {
PORT: 0x40,
INDEX: 0,
TIMER0: 0, // used for time-of-day (prior to MODEL_5170)
TIMER1: 1, // used for memory refresh
TIMER2: 2 // used for speaker tone generation
};
ChipSet.PIT1 = {
PORT: 0x48, // MODEL_COMPAQ_DESKPRO386 only
INDEX: 1,
TIMER3: 0, // used for fail-safe clock
TIMER4: 1, // N/A
TIMER5: 2 // used for refresher request extend/speed control
};
ChipSet.PIT_CTRL = {
PORT1: 0x43, // write-only control register (use the Read-Back command to get status)
PORT2: 0x4B, // write-only control register (use the Read-Back command to get status)
BCD: 0x01,
MODE: 0x0E,
MODE0: 0x00, // interrupt on Terminal Count (TC)
MODE1: 0x02, // programmable one-shot
MODE2: 0x04, // rate generator
MODE3: 0x06, // square wave generator
MODE4: 0x08, // software-triggered strobe
MODE5: 0x0A, // hardware-triggered strobe
RW: 0x30,
RW_LATCH: 0x00,
RW_LSB: 0x10,
RW_MSB: 0x20,
RW_BOTH: 0x30,
SC: 0xC0,
SC_CTR0: 0x00,
SC_CTR1: 0x40,
SC_CTR2: 0x80,
SC_BACK: 0xC0,
SC_SHIFT: 6,
RB_CTR0: 0x02,
RB_CTR1: 0x04,
RB_CTR2: 0x08,
RB_STATUS: 0x10, // if this bit is CLEAR, then latch the current status of the selected counter(s)
RB_COUNTS: 0x20, // if this bit is CLEAR, then latch the current count(s) of the selected counter(s)
RB_NULL: 0x40, // bit set in Read-Back status byte if the counter has not been "fully loaded" yet
RB_OUT: 0x80 // bit set in Read-Back status byte if fOUT is true
};
ChipSet.TIMER_TICKS_PER_SEC = 1193181;
/*
* 8255A Programmable Peripheral Interface (PPI) I/O ports, for Cassette/Speaker/Keyboard/SW1/etc
*
* Normally, 0x99 is written to PPI_CTRL.PORT, indicating that PPI_A.PORT and PPI_C.PORT are INPUT ports
* and PPI_B.PORT is an OUTPUT port.
*
* However, the MODEL_5160 ROM BIOS initially writes 0x89 instead, making PPI_A.PORT an OUTPUT port.
* I'm guessing that's just part of some "diagnostic mode", because all it writes to PPI_A.PORT are a series
* of "checkpoint" values (ie, 0x01, 0x02, and 0x03) before updating PPI_CTRL.PORT with the usual 0x99.
*/
ChipSet.PPI_A = { // this.bPPIA (port 0x60)
PORT: 0x60 // INPUT: keyboard scan code (PPI_B.CLEAR_KBD must be clear)
};
ChipSet.PPI_B = { // this.bPPIB (port 0x61)
PORT: 0x61, // OUTPUT (although it has to be treated as INPUT, too; the keyboard interrupt handler reads it, OR's PPI_B.CLEAR_KBD, writes it, and then rewrites the original read value)
CLK_TIMER2: 0x01, // ALL: set to enable clock to TIMER2
SPK_TIMER2: 0x02, // ALL: set to connect output of TIMER2 to speaker (MODEL_5150: clear for cassette)
ENABLE_SW2: 0x04, // MODEL_5150: set to enable SW2[1-4] through PPI_C.PORT, clear to enable SW2[5]; MODEL_5160: unused (there is no SW2 switch block on the MODEL_5160 motherboard)
CASS_MOTOR_OFF: 0x08, // MODEL_5150: cassette motor off
ENABLE_SW_HI: 0x08, // MODEL_5160: clear to read SW1[1-4], set to read SW1[5-8]
DISABLE_RW_MEM: 0x10, // ALL: clear to enable RAM parity check, set to disable
DISABLE_IO_CHK: 0x20, // ALL: clear to enable I/O channel check, set to disable
CLK_KBD: 0x40, // ALL: clear to force keyboard clock low
CLEAR_KBD: 0x80 // ALL: clear to enable keyboard scan codes (MODEL_5150: set to enable SW1 through PPI_A.PORT)
};
ChipSet.PPI_C = { // this.bPPIC (port 0x62)
PORT: 0x62, // INPUT (see below)
SW: 0x0F, // MODEL_5150: SW2[1-4] or SW2[5], depending on whether PPI_B.ENABLE_SW2 is set or clear; MODEL_5160: SW1[1-4] or SW1[5-8], depending on whether PPI_B.ENABLE_SW_HI is clear or set
CASS_DATA_IN: 0x10,
TIMER2_OUT: 0x20,
IO_CHANNEL_CHK: 0x40, // used by NMI handler to detect I/O channel errors
RW_PARITY_CHK: 0x80 // used by NMI handler to detect R/W memory parity errors
};
ChipSet.PPI_CTRL = { // this.bPPICtrl (port 0x63)
PORT: 0x63, // OUTPUT: initialized to 0x99, defining PPI_A and PPI_C as INPUT and PPI_B as OUTPUT
A_IN: 0x10,
B_IN: 0x02,
C_IN_LO: 0x01,
C_IN_HI: 0x08,
B_MODE: 0x04,
A_MODE: 0x60
};
/*
* Switches Overview
* -----------------
*
* The conventions used for the sw1 and sw2 strings are that the left-most character represents DIP switch [1],
* the right-most character represents DIP switch [8], and "1" means the DIP switch is ON and "0" means it is OFF.
*
* Internally, we convert the above strings into binary values that the 8255A PPI returns, where DIP switch [1]
* is bit 0 and DIP switch [8] is bit 7, and 0 indicates the switch is ON and 1 indicates it is OFF.
*
* For reference, here's how the SW1 and SW2 switches correspond to the internal 8255A PPI bit values:
*
* SW1[1] (bit 0) "0xxxxxxx" (1): IPL, "1xxxxxxx" (0): No IPL
* SW1[2] (bit 1) reserved on the 5150; OFF (1) if FPU installed in a 5160
* SW1[3,4] (bits 3-2) "xx11xxxx" (00): 16Kb, "xx01xxxx" (10): 32Kb, "xx10xxxx" (01): 48Kb, "xx00xxxx" (11): 64Kb
* SW1[5,6] (bits 5-4) "xxxx11xx" (00): none, "xxxx01xx" (10): tv, "xxxx10xx" (01): color, "xxxx00xx" (11): mono
* SW1[7,8] (bits 7-6) "xxxxxx11" (00): 1 FD, "xxxxxx01" (10): 2 FD, "xxxxxx10" (01): 3 FD, "xxxxxx00" (11): 4 FD
*
* Note: FD refers to floppy drive, and IPL refers to an "Initial Program Load" floppy drive.
*
* SW2[1-5] (bits 4-0) "NNNxxxxx": number of 32Kb blocks of I/O expansion RAM present
*
* For example, sw1="01110011" indicates that all SW1 DIP switches are ON, except for SW1[1], SW1[5] and SW1[6],
* which are OFF. Internally, the order of these bits must reversed (to 11001110) and then inverted (to 00110001)
* to yield the value that the 8255A PPI returns. Reading the final value right-to-left, 00110001 indicates an
* IPL floppy drive, 1X of RAM (where X is 16Kb on a MODEL_5150 and 64Kb on a MODEL_5160), MDA, and 1 floppy drive.
*
* WARNING: It is possible to set SW1 to indicate more memory than the RAM component has been configured to provide.
* This is a configuration error which will cause the machine to crash after reporting a "201" error code (memory
* test failure), which is presumably what a real machine would do if it was similarly misconfigured. Surprisingly,
* the BIOS forges ahead, setting SP to the top of the memory range indicated by SW1 (via INT 0x12), but the lack of
* a valid stack causes the system to crash after the next IRET. The BIOS should have either halted or modified
* the actual memory size to match the results of the memory test.
*
* MODEL 5150 Switches
* -------------------
*
* PPI_SW bits are exposed via port PPI_A.
*
* MODEL 5160 Switches
* ------------------------
*
* PPI_SW bits 0-3 are exposed via PPI_C.SW if PPI_B.ENABLE_SW_HI is clear; bits 4-7 if PPI_B.ENABLE_SW_HI is set.
*
* AT&T 6300 Switches
* ------------------
*
* Based on ATT_PC_6300_Service_Manual.pdf, there are two 8-switch blocks, DIPSW-0 and DIPSW-1, where:
*
* DIPSW-0[1-4] Total RAM
* DIPSW-0[5] - ON if 8087 not installed, OFF if installed
* DIPSW-0[6] - ON if 8250 ACE serial interface present, OFF if Z-8530 SCC interface present
* DIPSW-0[7] - Not used
* DIPSW-0[8] - Type of EPROM chip for ROM 1.21 or lower, or presence of RAM in bank 1 for ROM 1.43 or higher
*
* and:
*
* DIPSW-1[1] - Floppy Type (ON for 48TPI, OFF for 96TPI)
* DIPSW-1[2] - Floppy Speed (ON for slow startup, OFF for fast startup)
* DIPSW-1[3] - HDU ROM (ON for indigenous, OFF for external)
* DIPSW-1[4] - Not used (ROM 1.21 or lower) or Scroll Speed (ROM 1.43 or higher: ON for fast, OFF for slow)
* DIPSW-1[5-6] - Display Type (11=EGA or none, 01=color 40x25, 10=color 80x25, 00=monochrome 80x25)
* DIPSW-1[7-8] - Number of Floppy Drives (11=one, 01=two, 10=three, 00=four)
*
* For AT&T 6300 ROM 1.43 and up, DIPSW-0 supports the following RAM combinations:
*
* 0111xxx1: 128Kb on motherboard
* 1011xxx0: 256Kb on motherboard
* 1101xxx0: 256Kb on motherboard, 256Kb on expansion board (512Kb total)
* 1110xxx1: 512Kb on motherboard
* 0101xxx0: 256Kb on motherboard, 384Kb on expansion board (640Kb total)
* 0100xxx0: 640Kb on motherboard (128Kb bank 0, 512Kb bank 1)
* 0110xxx0: 640Kb on motherboard (512Kb bank 0, 128Kb bank 1)
*
* Inspection of the AT&T 6300 Plus ROM BIOS reveals that DIPSW-0[1-8] are obtained from bits 0-7
* of port 0x66 ("sys_conf_a") and DIPSW-1[1-8] are obtained from bits 0-7 of port 0x67 ("sys_conf_b").
*/
ChipSet.PPI_SW = {
FDRIVE: {
IPL: 0x01, // MODEL_5150: IPL ("Initial Program Load") floppy drive attached; MODEL_5160: "Loop on POST"
ONE: 0x00, // 1 floppy drive attached (or 0 drives if PPI_SW.FDRIVE_IPL is not set -- MODEL_5150 only)
TWO: 0x40, // 2 floppy drives attached
THREE: 0x80, // 3 floppy drives attached
FOUR: 0xC0, // 4 floppy drives attached
MASK: 0xC0,
SHIFT: 6
},
FPU: 0x02, // MODEL_5150: reserved; MODEL_5160: FPU coprocessor installed
MEMORY: { // MODEL_5150: "X" is 16Kb; MODEL_5160: "X" is 64Kb
X1: 0x00, // 16Kb or 64Kb
X2: 0x04, // 32Kb or 128Kb
X3: 0x08, // 48Kb or 192Kb
X4: 0x0C, // 64Kb or 256Kb
MASK: 0x0C,
SHIFT: 2
},
MONITOR: {
TV: 0x10,
COLOR: 0x20,
MONO: 0x30,
MASK: 0x30,
SHIFT: 4
}
};
/*
* Some models have completely different DIP switch implementations from the MODEL_5150, which, being
* the first IBM PC, was the model that we, um, modeled our DIP switch support on. So, to support other
* implementations, we now get and set DIP switch values according to SWITCH_TYPE, and rely on the
* tables that follow to define which DIP switch(es) correspond to each SWITCH_TYPE.
*
* Not every model needs its own tables. The getDIPSwitches() and setDIPSwitches() functions look first
* for an *exact* model match, then a "truncated" model match, and failing that, they fall back to the
* MODEL_5150 switch definitions.
*/
ChipSet.SWITCH_TYPE = {
FLOPNUM: 1,
FLOPTYPE: 2,
FPU: 3,
MONITOR: 4,
LOWMEM: 5,
EXPMEM: 6
};
ChipSet.DIPSW = {};
ChipSet.DIPSW[ChipSet.MODEL_5150] = [{},{}];
ChipSet.DIPSW[ChipSet.MODEL_5150][0][ChipSet.SWITCH_TYPE.FLOPNUM] = {
MASK: 0xC0,
VALUES: {
1: 0x00,
2: 0x40,
3: 0x80,
4: 0xC0
},
LABEL: "Number of Floppy Drives"
};
/*
* NOTE: Both the Aug 1981 and the Apr 1984 IBM 5150 Technical Reference Manuals list SW1[2] as "RESERVED",
* but the Aug 1981 edition (p. 2-28) also says SW1[2] "MUST BE ON (RESERVED FOR CO-PROCESSOR)". Contemporary
* articles discussing 8087 support in early PCs all indicate that switch SW1[2] must OFF if a coprocessor
* is installed, and the 1984 5150 Guide to Operations (p. 5-34) confirms it.
*
* The Aug 1981 5150 TechRef makes no further mention of coprocessor support, whereas the Apr 1984 5150 TechRef
* discusses it in a fair bit of detail, including the fact that 8087 exceptions generate an NMI, despite Intel's
* warning in their iAPX 86,88 User's Manual, p. S-27, that "[t]he 8087 should not be tied to the CPU's NMI
* (non-maskable interrupt) line.")
*/
ChipSet.DIPSW[ChipSet.MODEL_5150][0][ChipSet.SWITCH_TYPE.FPU] = {
MASK: 0x02,
VALUES: {
0: 0x00, // 0 means an FPU is NOT installed
1: 0x02 // 1 means an FPU is installed
},
LABEL: "Coprocessor"
};
ChipSet.DIPSW[ChipSet.MODEL_5150][0][ChipSet.SWITCH_TYPE.MONITOR] = {
MASK: 0x30,
VALUES: {
0: 0x00,
1: 0x10,
2: 0x20,
3: 0x30,
"none": 0x00,
"tv": 0x10, // aka composite
"color":0x20,
"cga": 0x20, // alias for color
"mda": 0x30, // alias for mono
"mono": 0x30,
"ega": 0x00,
"vga": 0x00
},
LABEL: "Monitor Type"
};
ChipSet.DIPSW[ChipSet.MODEL_5150][0][ChipSet.SWITCH_TYPE.LOWMEM] = {
MASK: 0x0C,
VALUES: {
16: 0x00,
32: 0x04,
48: 0x08,
64: 0x0C
},
LABEL: "Base Memory (16Kb Increments)"
};
ChipSet.DIPSW[ChipSet.MODEL_5150][1][ChipSet.SWITCH_TYPE.EXPMEM] = {
MASK: 0x1F, // technically, this mask should be 0x0F for ROM revisions prior to 5150_REV3, and 0x1F on 5150_REV3
VALUES: {
0: 0x00,
32: 0x01,
64: 0x02,
96: 0x03,
128: 0x04,
160: 0x05,
192: 0x06,
224: 0x07,
256: 0x08,
288: 0x09,
320: 0x0A,
352: 0x0B,
384: 0x0C,
416: 0x0D,
448: 0x0E,
480: 0x0F,
512: 0x10,
544: 0x11,
576: 0x12
/*
* Obviously, more bit combinations are possible here (up to 0x1F), but assuming a minimum of 64Kb already on
* the motherboard, any amount of expansion memory above 576Kb would break the 640Kb barrier. Yes, if you used
* only MDA or CGA video cards, you could go as high as 704Kb in a real system. But in our happy little world,
* this is where we stop.
*
* TODO: A value larger than 0x12 usually comes from a misconfigured machine (ie, it forgot to leave SW2[5] ON).
* To compensate, when getDIPMemorySize() gets null back from its EXPMEM request, perhaps it should try truncating
* the DIP switch value. However, that would introduce a machine-specific hack into a function that's supposed
* be machine-independent now.
*/
},
LABEL: "Expansion Memory (32Kb Increments)"
};
ChipSet.DIPSW[ChipSet.MODEL_5160] = [{},{}];
ChipSet.DIPSW[ChipSet.MODEL_5160][0][ChipSet.SWITCH_TYPE.FLOPNUM] = ChipSet.DIPSW[ChipSet.MODEL_5150][0][ChipSet.SWITCH_TYPE.FLOPNUM];
ChipSet.DIPSW[ChipSet.MODEL_5160][0][ChipSet.SWITCH_TYPE.FPU] = ChipSet.DIPSW[ChipSet.MODEL_5150][0][ChipSet.SWITCH_TYPE.FPU];
ChipSet.DIPSW[ChipSet.MODEL_5160][0][ChipSet.SWITCH_TYPE.MONITOR] = ChipSet.DIPSW[ChipSet.MODEL_5150][0][ChipSet.SWITCH_TYPE.MONITOR];
ChipSet.DIPSW[ChipSet.MODEL_5160][0][ChipSet.SWITCH_TYPE.LOWMEM] = {
MASK: 0x0C,
VALUES: {
64: 0x00,
128: 0x04,
192: 0x08,
256: 0x0C
},
LABEL: "Base Memory (64Kb Increments)"
};
ChipSet.DIPSW[ChipSet.MODEL_5160][1][ChipSet.SWITCH_TYPE.EXPMEM] = ChipSet.DIPSW[ChipSet.MODEL_5150][1][ChipSet.SWITCH_TYPE.EXPMEM];
ChipSet.DIPSW[ChipSet.MODEL_ATT_6300] = [{},{}];
ChipSet.DIPSW[ChipSet.MODEL_ATT_6300][0][ChipSet.SWITCH_TYPE.LOWMEM] = {
MASK: 0x8F,
VALUES: {
128: 0x01, // "0111xxx1"
256: 0x82, // "1011xxx0"
512: 0x08, // "1110xxx1"
640: 0x8D // "0100xxx0"
},
LABEL: "Base Memory (128Kb Increments)"
};
ChipSet.DIPSW[ChipSet.MODEL_ATT_6300][0][ChipSet.SWITCH_TYPE.FPU] = {
MASK: 0x10,
VALUES: {
0: 0x00,
1: 0x10
},
LABEL: "Coprocessor"
};
ChipSet.DIPSW[ChipSet.MODEL_ATT_6300][1][ChipSet.SWITCH_TYPE.FLOPTYPE] = {
MASK: 0x01,
VALUES: {
0: 0x00,
1: 0x01
},
LABEL: "Floppy Type"
};
ChipSet.DIPSW[ChipSet.MODEL_ATT_6300][1][ChipSet.SWITCH_TYPE.FLOPNUM] = ChipSet.DIPSW[ChipSet.MODEL_5150][0][ChipSet.SWITCH_TYPE.FLOPNUM];
ChipSet.DIPSW[ChipSet.MODEL_ATT_6300][1][ChipSet.SWITCH_TYPE.MONITOR] = ChipSet.DIPSW[ChipSet.MODEL_5150][0][ChipSet.SWITCH_TYPE.MONITOR];
/*
* 8041 Keyboard Controller I/O ports (MODEL_ATT_6300)
*
* The AT&T 6300 uses an 8041 for its Keyboard Controller, which has the following ports:
*
* Port Description
* ---- -----------
* 0x60 Keyboard Scan Code (input)
* 0x61 Keyboard Control Port (output)
* 0x64 Keyboard Status Port (input)
*
* And the Keyboard Control Port (0x61) has the following bit definitions:
*
* 0x01 Speaker gate to 8253 (counter 2)
* 0x02 Speaker data
* 0x0C Not used
* 0x10 RAM Parity (NMI) Enable
* 0x20 I/O Channel (NMI) Enable
* 0x40 Keyboard Clock Reset
* 0x80 Reset Interrupt Pending
*/
/*
* 8042 Keyboard Controller I/O ports (MODEL_5170)
*
* On the MODEL_5170, port 0x60 is designated KC8042.DATA rather than PPI_A, although the BIOS also refers to it
* as "PORT_A: 8042 KEYBOARD SCAN/DIAG OUTPUTS"). This is the 8042's output buffer and should be read only when
* KC8042.STATUS.OUTBUFF_FULL is set.
*
* Similarly, port 0x61 is designated KC8042.RWREG rather than PPI_B; the BIOS also refers to it as "PORT_B: 8042
* READ WRITE REGISTER", but it is not otherwise discussed in the MODEL_5170 TechRef's 8042 documentation.
*
* There are brief references to bits 0 and 1 (KC8042.RWREG.CLK_TIMER2 and KC8042.RWREG.SPK_TIMER2), and the BIOS sets
* bits 2-7 to "DISABLE PARITY CHECKERS" (principally KC8042.RWREG.DISABLE_NMI, which are bits 2 and 3); why the BIOS
* also sets bits 4-7 (or if those bits are even settable) is unclear, since it uses 11111100b rather than defined
* constants.
*
* The bottom line: on a MODEL_5170, port 0x61 is still used for speaker control and parity checking, so we use
* the same register (bPPIB) but install different I/O handlers. It's also bi-directional: at one point, the BIOS
* reads KC8042.RWREG.REFRESH_BIT (bit 4) to verify that it's alternating.
*
* PPI_C and PPI_CTRL don't seem to be documented or used by the MODEL_5170 BIOS, so I'm assuming they're obsolete.
*
* NOTE: For more information on the 8042 Controller, including information on undocumented commands, refer to the
* documents in /devices/pc/keyboard, as well as the following websites:
*
* http://halicery.com/8042/8042_INTERN_TXT.htm
* http://www.os2museum.com/wp/ibm-pcat-8042-keyboard-controller-commands/
*/
ChipSet.KC8042 = {
DATA: { // this.b8042OutBuff (PPI_A on previous models, still referred to as "PORT A" by the MODEL_5170 BIOS)
PORT: 0x60,
CMD: { // this.b8042CmdData (KC8042.DATA.CMD "data bytes" written to port 0x60, after writing a KC8042.CMD byte to port 0x64)
INT_ENABLE: 0x01, // generate an interrupt when the controller places data in the output buffer
SYS_FLAG: 0x04, // this value is propagated to ChipSet.KC8042.STATUS.SYS_FLAG
NO_INHIBIT: 0x08, // disable inhibit function
NO_CLOCK: 0x10, // disable keyboard by driving "clock" line low
PC_MODE: 0x20,
PC_COMPAT: 0x40 // generate IBM PC-compatible scan codes
},
SELF_TEST: { // result of ChipSet.KC8042.CMD.SELF_TEST command (0xAA)
OK: 0x55
},
INTF_TEST: { // result of ChipSet.KC8042.CMD.INTF_TEST command (0xAB)
OK: 0x00, // no error
CLOCK_LO: 0x01, // keyboard clock line stuck low
CLOCK_HI: 0x02, // keyboard clock line stuck high
DATA_LO: 0x03, // keyboard data line stuck low
DATA_HI: 0x04 // keyboard data line stuck high
}
},
INPORT: { // this.b8042InPort