Finally, some progress with the IBM VGA ROM
This commit is contained in:
parent
dbb77f31b6
commit
f7e93fbeb3
6 changed files with 574 additions and 88 deletions
227
blog/2015/06/01/README.md
Normal file
227
blog/2015/06/01/README.md
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
Debugging the IBM VGA ROM
|
||||
---
|
||||
|
||||
The IBM VGA ("Video Graphics Array") standard was introduced as part of the IBM PS/2 line of computers;
|
||||
it was not a feature you could purchase or install in older PC, XT or AT-compatible machines. In fact, full VGA
|
||||
support was not even available in all PS/2 models. Of the first four PS/2 models -- the 8086-based Model 30, the
|
||||
80286-based Model 50 and Model 60, and the 80386-based Model 80 -- VGA support was available only in the three
|
||||
higher-end models. The Model 30 came with MCGA ("Multicolor Graphics Array") video hardware that supported a subset
|
||||
of VGA modes (eg, 640x480 2-color and 320x200 256-color graphics).
|
||||
|
||||
It wasn't until October 1987 that IBM finally introduced an 8-bit ISA card that brought VGA capability to older PCs.
|
||||
The card was called the **IBM PS/2 Display Adapter**. However, I think the name is a bit confusing, since the card
|
||||
could only be used in PC, XT, and AT-compatible systems. I'll refer to it here simply as the IBM VGA.
|
||||
|
||||
The VGA ROM used here is assumed to have come from an original IBM VGA. It's unknown if IBM ever made any
|
||||
revisions to the VGA ROM. With the introduction of the PS/2 family and the VGA, IBM decided to no longer publish
|
||||
the source code for its ROMs, so I've created some assemblable source code from the IBM VGA ROM
|
||||
[here](/devices/pc/video/ibm/vga/ibm-vga.nasm).
|
||||
|
||||
I've finally started debugging a machine configuration that uses the IBM VGA ROM. Since the VGA and the 80386 are
|
||||
contemporaries, I'm using an [80386 machine configuration](/devices/pc/machine/compaq/deskpro386/vga/2048kb/machine.xml).
|
||||
However, I don't expect the IBM VGA ROM to require any 80386 support or PS/2-specific features.
|
||||
|
||||
The first problem I ran into was here:
|
||||
|
||||
;
|
||||
; Initialize the ROM BIOS Video Mode Options byte @40:0087 (default to color and 256Kb of RAM)
|
||||
;
|
||||
mov byte [0x487],0x60 ; 0000008D
|
||||
;
|
||||
; The x100 subroutine alternately enables port 0x3B? and 0x3D? decoding, verifying that there is
|
||||
; no response on opposing ports 0x3D? and 0x3B?, respectively; otherwise, it assumes that another
|
||||
; video card must exist and attempts to select co-existing settings for the VGA. For example, if
|
||||
; there is an unexpected response on the color ports, the VGA ROM will default to mono operation.
|
||||
;
|
||||
call x100 ; 00000092
|
||||
|
||||
The Video component installs I/O port handlers for all possible I/O ranges; when a range isn't being used, the
|
||||
associated I/O operations are redirected to a dummy Card, so that the active Card isn't affected. Here,
|
||||
however, that was insufficient. If the VGA is the only installed video card, the VGA ROM expects *NO RESPONSE*
|
||||
on inactive CRTC ports. So I've changed the CRTC I/O handlers to check the Card's fActive flag. This seems
|
||||
like a safe and logical change, but we'll still have to check for backward-compatibility issues with older ROMs.
|
||||
|
||||
The VGA ROM programs the card for the first time here:
|
||||
|
||||
EAX=00000000 EBX=00001642 ECX=00000004 EDX=00004AE8
|
||||
ESP=000000EA EBP=FFFF00F0 ESI=00006000 EDI=000003D4
|
||||
SS=0030 DS=0000 ES=C000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0
|
||||
C000:00CB E85910 CALL 1127 ;cycles=5
|
||||
videoVGA.outPort(0x03C4,SEQ.INDX,0x00) @C000:112F
|
||||
videoVGA.outPort(0x03C5,SEQ.RESET,0x01) @C000:112F
|
||||
videoVGA.outPort(0x03C4,SEQ.INDX,0x01) @C000:1204
|
||||
videoVGA.outPort(0x03C5,SEQ.CLK,0x29) @C000:1204
|
||||
videoVGA.outPort(0x03C4,SEQ.INDX,0x02) @C000:1204
|
||||
videoVGA.outPort(0x03C5,SEQ.MAPMASK,0x0F) @C000:1204
|
||||
videoVGA.outPort(0x03C4,SEQ.INDX,0x03) @C000:1204
|
||||
videoVGA.outPort(0x03C5,SEQ.CHARMAP,0x00) @C000:1204
|
||||
videoVGA.outPort(0x03C4,SEQ.INDX,0x04) @C000:1204
|
||||
videoVGA.outPort(0x03C5,SEQ.MODE,0x06) @C000:1204
|
||||
videoVGA.outPort(0x03C2,MISC,0x63) @C000:1143
|
||||
videoVGA.outPort(0x03C4,SEQ.INDX,0x00) @C000:1149
|
||||
videoVGA.outPort(0x03C5,SEQ.RESET,0x03) @C000:1149
|
||||
videoVGA.outPort(0x03D4,CRTC.INDX,0x11) @C000:1151
|
||||
videoVGA.outPort(0x03D5,CRTC.VERT_RETRACE_END,0x00) @C000:1151
|
||||
videoVGA.outPort(0x03D4,CRTC.INDX,0x00) @C000:1204
|
||||
videoVGA.outPort(0x03D5,CRTC.HORZ_TOTAL,0x5F) @C000:1204
|
||||
videoVGA.outPort(0x03D4,CRTC.INDX,0x01) @C000:1204
|
||||
videoVGA.outPort(0x03D5,CRTC.HORZ_DISP_END,0x4F) @C000:1204
|
||||
videoVGA.outPort(0x03D4,CRTC.INDX,0x02) @C000:1204
|
||||
videoVGA.outPort(0x03D5,CRTC.HORZ_BLANK_START,0x50) @C000:1204
|
||||
videoVGA.outPort(0x03D4,CRTC.INDX,0x03) @C000:1204
|
||||
videoVGA.outPort(0x03D5,CRTC.HORZ_BLANK_END,0x82) @C000:1204
|
||||
videoVGA.outPort(0x03D4,CRTC.INDX,0x04) @C000:1204
|
||||
videoVGA.outPort(0x03D5,CRTC.HORZ_RETRACE_START,0x55) @C000:1204
|
||||
videoVGA.outPort(0x03D4,CRTC.INDX,0x05) @C000:1204
|
||||
videoVGA.outPort(0x03D5,CRTC.HORZ_RETRACE_END,0x81) @C000:1204
|
||||
videoVGA.outPort(0x03D4,CRTC.INDX,0x06) @C000:1204
|
||||
videoVGA.outPort(0x03D5,CRTC.VERT_TOTAL,0xBF) @C000:1204
|
||||
videoVGA.outPort(0x03D4,CRTC.INDX,0x07) @C000:1204
|
||||
videoVGA.outPort(0x03D5,CRTC.CRTC_OVERFLOW,0x1F) @C000:1204
|
||||
videoVGA.outPort(0x03D4,CRTC.INDX,0x08) @C000:1204
|
||||
videoVGA.outPort(0x03D5,CRTC.PRESET_ROW_SCAN,0x00) @C000:1204
|
||||
videoVGA.outPort(0x03D4,CRTC.INDX,0x09) @C000:1204
|
||||
videoVGA.outPort(0x03D5,CRTC.MAX_SCAN_LINE,0x40) @C000:1204
|
||||
removeCursor(): removed from 0,0
|
||||
videoVGA.outPort(0x03D4,CRTC.INDX,0x0A) @C000:1204
|
||||
videoVGA.outPort(0x03D5,CRTC.CURSOR_START,0x00) @C000:1204
|
||||
checkCursor(): cursor moved from -1 to 0
|
||||
videoVGA.outPort(0x03D4,CRTC.INDX,0x0B) @C000:1204
|
||||
videoVGA.outPort(0x03D5,CRTC.CURSOR_END,0x00) @C000:1204
|
||||
videoVGA.outPort(0x03D4,CRTC.INDX,0x0C) @C000:1204
|
||||
videoVGA.outPort(0x03D5,CRTC.START_ADDR_HI,0x00) @C000:1204
|
||||
videoVGA.outPort(0x03D4,CRTC.INDX,0x0D) @C000:1204
|
||||
videoVGA.outPort(0x03D5,CRTC.START_ADDR_LO,0x00) @C000:1204
|
||||
videoVGA.outPort(0x03D4,CRTC.INDX,0x0E) @C000:1204
|
||||
videoVGA.outPort(0x03D5,CRTC.CURSOR_ADDR_HI,0x00) @C000:1204
|
||||
videoVGA.outPort(0x03D4,CRTC.INDX,0x0F) @C000:1204
|
||||
videoVGA.outPort(0x03D5,CRTC.CURSOR_ADDR_LO,0x00) @C000:1204
|
||||
videoVGA.outPort(0x03D4,CRTC.INDX,0x10) @C000:1204
|
||||
videoVGA.outPort(0x03D5,CRTC.VERT_RETRACE_START,0x9C) @C000:1204
|
||||
videoVGA.outPort(0x03D4,CRTC.INDX,0x11) @C000:1204
|
||||
videoVGA.outPort(0x03D5,CRTC.VERT_RETRACE_END,0x8E) @C000:1204
|
||||
videoVGA.outPort(0x03D4,CRTC.INDX,0x12) @C000:1204
|
||||
videoVGA.outPort(0x03D5,CRTC.VERT_DISP_END,0x8F) @C000:1204
|
||||
videoVGA.outPort(0x03D4,CRTC.INDX,0x13) @C000:1204
|
||||
videoVGA.outPort(0x03D5,CRTC.OFFSET,0x28) @C000:1204
|
||||
videoVGA.outPort(0x03D4,CRTC.INDX,0x14) @C000:1204
|
||||
videoVGA.outPort(0x03D5,CRTC.UNDERLINE,0x1F) @C000:1204
|
||||
videoVGA.outPort(0x03D4,CRTC.INDX,0x15) @C000:1204
|
||||
videoVGA.outPort(0x03D5,CRTC.VERT_BLANK_START,0x96) @C000:1204
|
||||
videoVGA.outPort(0x03D4,CRTC.INDX,0x16) @C000:1204
|
||||
videoVGA.outPort(0x03D5,CRTC.VERT_BLANK_END,0xB9) @C000:1204
|
||||
videoVGA.outPort(0x03D4,CRTC.INDX,0x17) @C000:1204
|
||||
videoVGA.outPort(0x03D5,CRTC.MODE_CTRL,0xE3) @C000:1204
|
||||
videoVGA.outPort(0x03D4,CRTC.INDX,0x18) @C000:1204
|
||||
videoVGA.outPort(0x03D5,CRTC.LINE_COMPARE,0xFF) @C000:1204
|
||||
videoVGA.inPort(0x03DA,STATUS1): 0x00 @C000:1167
|
||||
videoVGA.outPort(0x03C0,ATC.INDX,0x10) @C000:116C
|
||||
videoVGA.outPort(0x03C0,ATC.MODE,0x01) @C000:1171
|
||||
videoVGA.outPort(0x03C0,ATC.INDX,0x12) @C000:1174
|
||||
videoVGA.outPort(0x03C0,ATC.PLANES,0x0F) @C000:1179
|
||||
videoVGA.outPort(0x03C0,ATC.INDX,0x13) @C000:117C
|
||||
videoVGA.outPort(0x03C0,ATC.HORZPAN,0x00) @C000:1181
|
||||
videoVGA.outPort(0x03CE,GRC.INDX,0x00) @C000:1204
|
||||
videoVGA.outPort(0x03CF,GRC.SRESET,0x00) @C000:1204
|
||||
videoVGA.outPort(0x03CE,GRC.INDX,0x01) @C000:1204
|
||||
videoVGA.outPort(0x03CF,GRC.ESRESET,0x00) @C000:1204
|
||||
videoVGA.outPort(0x03CE,GRC.INDX,0x02) @C000:1204
|
||||
videoVGA.outPort(0x03CF,GRC.COLRCMP,0x0F) @C000:1204
|
||||
videoVGA.outPort(0x03CE,GRC.INDX,0x03) @C000:1204
|
||||
videoVGA.outPort(0x03CF,GRC.DATAROT,0x00) @C000:1204
|
||||
videoVGA.outPort(0x03CE,GRC.INDX,0x04) @C000:1204
|
||||
videoVGA.outPort(0x03CF,GRC.READMAP,0x00) @C000:1204
|
||||
videoVGA.outPort(0x03CE,GRC.INDX,0x05) @C000:1204
|
||||
videoVGA.outPort(0x03CF,GRC.MODE,0x08) @C000:1204
|
||||
setAccess(0x0210)
|
||||
videoVGA.outPort(0x03CE,GRC.INDX,0x06) @C000:1204
|
||||
videoVGA.outPort(0x03CF,GRC.MISC,0x05) @C000:1204
|
||||
setMode(0x0010)
|
||||
setMode(16): removing 0x00008000 bytes from 0x000B8000
|
||||
setMode(16): adding 0x00010000 bytes to 0x000A0000
|
||||
videoVGA.outPort(0x03CE,GRC.INDX,0x07) @C000:1204
|
||||
videoVGA.outPort(0x03CF,GRC.COLRDC,0x0F) @C000:1204
|
||||
videoVGA.outPort(0x03CE,GRC.INDX,0x08) @C000:1204
|
||||
videoVGA.outPort(0x03CF,GRC.BITMASK,0xFF) @C000:1204
|
||||
|
||||
EAX=0000FF09 EBX=00001642 ECX=00000000 EDX=000003DA
|
||||
ESP=000000EA EBP=FFFF00F0 ESI=00006000 EDI=000003D4
|
||||
SS=0030 DS=0000 ES=C000 FS=0000 GS=0304 PS=00000246 V0 D0 I1 T0 S0 Z1 A0 P1 C0
|
||||
C000:00CE 32C0 XOR AL,AL ;cycles=1031
|
||||
|
||||
Now that the card was programmed for the first time, I used the `d video` Debugger command to dump the video
|
||||
card's state:
|
||||
|
||||
BIOSMODE: 0x10
|
||||
CRTC[0x00]: HORZ_TOTAL 0x5F
|
||||
CRTC[0x01]: HORZ_DISP_END 0x4F
|
||||
CRTC[0x02]: HORZ_BLANK_START 0x50
|
||||
CRTC[0x03]: HORZ_BLANK_END 0x82
|
||||
CRTC[0x04]: HORZ_RETRACE_START 0x55
|
||||
CRTC[0x05]: HORZ_RETRACE_END 0x81
|
||||
CRTC[0x06]: VERT_TOTAL 0xBF
|
||||
CRTC[0x07]: CRTC_OVERFLOW 0x1F
|
||||
CRTC[0x08]: PRESET_ROW_SCAN 0x00
|
||||
CRTC[0x09]: MAX_SCAN_LINE 0x40
|
||||
CRTC[0x0A]: CURSOR_START 0x00
|
||||
CRTC[0x0B]: CURSOR_END 0x00
|
||||
CRTC[0x0C]: START_ADDR_HI 0x00
|
||||
CRTC[0x0D]: START_ADDR_LO 0x00
|
||||
CRTC[0x0E]: CURSOR_ADDR_HI 0x00
|
||||
CRTC[0x0F]: CURSOR_ADDR_LO 0x00
|
||||
CRTC[0x10]: VERT_RETRACE_START 0x9C
|
||||
CRTC[0x11]: VERT_RETRACE_END 0x8E
|
||||
CRTC[0x12]: VERT_DISP_END 0x8F
|
||||
CRTC[0x13]: OFFSET 0x28
|
||||
CRTC[0x14]: UNDERLINE 0x1F
|
||||
CRTC[0x15]: VERT_BLANK_START 0x96
|
||||
CRTC[0x16]: VERT_BLANK_END 0xB9
|
||||
CRTC[0x17]: MODE_CTRL 0xE3
|
||||
CRTC[0x18]: LINE_COMPARE 0xFF*
|
||||
STATUS1: 0x00
|
||||
ATCDATA: false
|
||||
ATC[0x00]: PAL00 0x??
|
||||
ATC[0x01]: PAL01 0x??
|
||||
ATC[0x02]: PAL02 0x??
|
||||
ATC[0x03]: PAL03 0x??
|
||||
ATC[0x04]: PAL04 0x??
|
||||
ATC[0x05]: PAL05 0x??
|
||||
ATC[0x06]: PAL06 0x??
|
||||
ATC[0x07]: PAL07 0x??
|
||||
ATC[0x08]: PAL08 0x??
|
||||
ATC[0x09]: PAL09 0x??
|
||||
ATC[0x0A]: PAL0A 0x??
|
||||
ATC[0x0B]: PAL0B 0x??
|
||||
ATC[0x0C]: PAL0C 0x??
|
||||
ATC[0x0D]: PAL0D 0x??
|
||||
ATC[0x0E]: PAL0E 0x??
|
||||
ATC[0x0F]: PAL0F 0x??
|
||||
ATC[0x10]: MODE 0x01
|
||||
ATC[0x11]: OVRSCAN 0x??
|
||||
ATC[0x12]: PLANES 0x0F
|
||||
ATC[0x13]: HORZPAN 0x00*
|
||||
GRC[0x00]: SRESET 0x00
|
||||
GRC[0x01]: ESRESET 0x00
|
||||
GRC[0x02]: COLRCMP 0x0F
|
||||
GRC[0x03]: DATAROT 0x00
|
||||
GRC[0x04]: READMAP 0x00
|
||||
GRC[0x05]: MODE 0x08
|
||||
GRC[0x06]: MISC 0x05
|
||||
GRC[0x07]: COLRDC 0x0F
|
||||
GRC[0x08]: BITMASK 0xFF*
|
||||
SEQ[0x00]: RESET 0x03*
|
||||
SEQ[0x01]: CLK 0x29
|
||||
SEQ[0x02]: MAPMASK 0x0F
|
||||
SEQ[0x03]: CHARMAP 0x00
|
||||
SEQ[0x04]: MODE 0x06
|
||||
FEAT: 0x00
|
||||
MISC: 0x63
|
||||
STATUS0: 0x00
|
||||
LATCHES: 0x00
|
||||
ACCESS: 0x0210
|
||||
Use 'dump video buffer' to dump video memory
|
||||
|
||||
If you've noticed that none of the ATC palette registers were programmed, well, that's apparently by design.
|
||||
|
||||
*[@jeffpar](http://twitter.com/jeffpar)*
|
||||
*June 1, 2015*
|
||||
|
|
@ -4805,6 +4805,11 @@ xa9e9: cs rep movsw ; 0000A9E9 F32EA5 '...'
|
|||
mov al,0x3b ; 0000A9F9 B03B '.;'
|
||||
out 0x84,al ; 0000A9FB E684 '..'
|
||||
call xc259 ; 0000A9FD E85918 '.Y.'
|
||||
;
|
||||
; Set bit 2 (reserved?) and bit 4 (memory size?) of ROM BIOS Video Mode Options byte @40:0087.
|
||||
; It would appear that Compaq had a different conception of this byte; however, in the case of an
|
||||
; adapter like the IBM VGA, it doesn't matter, since the IBM VGA ROM will rewrite this byte anyway.
|
||||
;
|
||||
or byte [0x87],0x14 ; 0000AA00 800E870014 '.....'
|
||||
mov al,0x8e ; 0000AA05 B08E '..'
|
||||
call xb544 ; 0000AA07 E83A0B '.:.'
|
||||
|
|
|
|||
|
|
@ -24,8 +24,31 @@
|
|||
mov [0x10e],cs ; 00000083 8C0E0E01 '....'
|
||||
sti ; 00000087 FB '.'
|
||||
mov byte [0x489],0x11 ; 00000088 C606890411 '.....'
|
||||
mov byte [0x487],0x60 ; 0000008D C606870460 '....`'
|
||||
call x100 ; 00000092 E86B00 '.k.'
|
||||
|
||||
;
|
||||
; Initialize the ROM BIOS Video Mode Options byte @40:0087 (default to color and 256Kb of RAM)
|
||||
;
|
||||
mov byte [0x487],0x60 ; 0000008D
|
||||
;
|
||||
; The x100 subroutine alternately enables port 0x3B? and 0x3D? decoding, verifying that there is
|
||||
; no response on opposing ports 0x3D? and 0x3B?, respectively; otherwise, it assumes that another
|
||||
; video card must exist and attempts to select co-existing settings for the VGA. For example, if
|
||||
; there is an unexpected response on the color ports, the VGA ROM will default to mono operation.
|
||||
;
|
||||
call x100 ; 00000092
|
||||
;
|
||||
; From the "IBM Personal System/2 Model 50 and 60 Technical Reference: I/O Controllers, Video Subsystem", p.4-29:
|
||||
;
|
||||
; When in setup mode (I/O address hex 0094, bit 5 equals 0), the VGA responds to a single option select byte
|
||||
; at I/O address hex 0102 and treats the LSB (bit 0) of that byte as the VGA sleep bit. When the LSB equals 0,
|
||||
; the VGA does not respond to commands, addresses, or data, on the data bus. When the LSB equals 1, the VGA
|
||||
; responds. If the VGA was set up and is generating video output when the LSB is set to 0, the output is still
|
||||
; generated.
|
||||
;
|
||||
; The VGA responds only to address hex 0102 when in the setup mode. No other addresses are valid at that time.
|
||||
; Conversely, the VGA ignores address hex 0102 when in the enabled mode (I/O address hex 0094, bit 5 equals 1),
|
||||
; and decodes normal I/O and memory addresses.
|
||||
;
|
||||
cli ; 00000095 FA '.'
|
||||
mov dx,0x46e8 ; 00000096 BAE846 '..F'
|
||||
mov ax,0x16 ; 00000099 B81600 '...'
|
||||
|
|
@ -42,14 +65,35 @@
|
|||
sti ; 000000B1 FB '.'
|
||||
push cs ; 000000B2 0E '.'
|
||||
pop es ; 000000B3 07 '.'
|
||||
|
||||
;
|
||||
; Default to mono settings
|
||||
;
|
||||
mov di,0x3b4 ; 000000B4 BFB403 '...'
|
||||
mov bx,0x1602 ; 000000B7 BB0216 '...'
|
||||
|
||||
;
|
||||
; Test bit 1 of ROM BIOS Video Mode Options byte @40:0087 (set if mono, clear if color)
|
||||
;
|
||||
test byte [0x487],0x2 ; 000000BA F606870402 '.....'
|
||||
jnz xc7 ; 000000BF 7506 'u.'
|
||||
|
||||
;
|
||||
; Choose color settings
|
||||
;
|
||||
mov di,0x3d4 ; 000000C1 BFD403 '...'
|
||||
mov bx,0x1642 ; 000000C4 BB4216 '.B.'
|
||||
|
||||
;
|
||||
; Set the CRTC base port address (0x3B4 for mono, 0x3D4 for color)
|
||||
;
|
||||
xc7: mov [0x463],di ; 000000C7 893E6304 '.>c.'
|
||||
|
||||
;
|
||||
; Program the card for a default mode
|
||||
;
|
||||
call x1127 ; 000000CB E85910 '.Y.'
|
||||
|
||||
xor al,al ; 000000CE 32C0 '2.'
|
||||
out dx,al ; 000000D0 EE '.'
|
||||
call x547 ; 000000D1 E87304 '.s.'
|
||||
|
|
@ -2105,7 +2149,19 @@ x1122: mov dx,0x3c8 ; 00001122 BAC803 '...'
|
|||
out dx,al ; 00001125 EE '.'
|
||||
x1126: ret ; 00001126 C3 '.'
|
||||
|
||||
x1127: mov dx,0x3c4 ; 00001127 BAC403 '...'
|
||||
;
|
||||
; Programs the card using data from [BX]; CRTC port address is in DI (0x3B4 or 0x3D4).
|
||||
;
|
||||
; Writes 0x01 to SEQ register 0x00 (SEQ.RESET).
|
||||
; Writes values starting at [BX+0x05] to SEQ registers 0x01-0x04.
|
||||
; Writes [BX+0x09] to Miscellaneous Output register (MISC).
|
||||
; Writes 0x03 to SEQ register 0x00 (SEQ.RESET).
|
||||
; Writes 0x00 to CRTC register 0x11 (CRTC.VERT_RETRACE_END).
|
||||
; Writes values starting at [BX+0x0A] to CRTC registers 0x00-0x18.
|
||||
; Writes values starting at [BX+0x33] to ATC registers 0x10, 0x12 and 0x13
|
||||
; Writes values starting at [BX+0x37] to GRC registers 0x00-0x08.
|
||||
;
|
||||
x1127: mov dx,0x3c4 ; (DX) == SEQ port address (0x3C4)
|
||||
mov ax,0x100 ; 0000112A B80001 '...'
|
||||
pushf ; 0000112D 9C '.'
|
||||
cli ; 0000112E FA '.'
|
||||
|
|
@ -2116,14 +2172,14 @@ x1127: mov dx,0x3c4 ; 00001127 BAC403 '...'
|
|||
mov al,0x1 ; 00001137 B001 '..'
|
||||
call x1201 ; 00001139 E8C500 '...'
|
||||
pop bx ; 0000113C 5B '['
|
||||
mov dl,0xc2 ; 0000113D B2C2 '..'
|
||||
mov dl,0xc2 ; (DX) == MISC port address (0x3C2)
|
||||
mov al,[es:bx+0x9] ; 0000113F 268A4709 '&.G.'
|
||||
out dx,al ; 00001143 EE '.'
|
||||
mov dl,0xc4 ; 00001144 B2C4 '..'
|
||||
mov dl,0xc4 ; (DX) == SEQ port address (0x3C4)
|
||||
mov ax,0x300 ; 00001146 B80003 '...'
|
||||
out dx,ax ; 00001149 EF '.'
|
||||
popf ; 0000114A 9D '.'
|
||||
mov dx,di ; 0000114B 8BD7 '..'
|
||||
mov dx,di ; (DX) == CRTC port address (0x3B4 or 0x3D4)
|
||||
mov al,0x11 ; 0000114D B011 '..'
|
||||
xor ah,ah ; 0000114F 32E4 '2.'
|
||||
out dx,ax ; 00001151 EF '.'
|
||||
|
|
@ -2134,12 +2190,12 @@ x1127: mov dx,0x3c4 ; 00001127 BAC403 '...'
|
|||
call x1201 ; 0000115B E8A300 '...'
|
||||
pop bx ; 0000115E 5B '['
|
||||
mov dx,di ; 0000115F 8BD7 '..'
|
||||
add dl,0x6 ; 00001161 80C206 '...'
|
||||
add dl,0x6 ; (DX) == STATUS1 port address (0x3BA or 0x3DA)
|
||||
push dx ; 00001164 52 'R'
|
||||
pushf ; 00001165 9C '.'
|
||||
cli ; 00001166 FA '.'
|
||||
in al,dx ; 00001167 EC '.'
|
||||
mov dl,0xc0 ; 00001168 B2C0 '..'
|
||||
mov dl,0xc0 ; (DX) == ATC port address (0x3C0)
|
||||
mov al,0x10 ; 0000116A B010 '..'
|
||||
out dx,al ; 0000116C EE '.'
|
||||
mov al,[es:bx+0x33] ; 0000116D 268A4733 '&.G3'
|
||||
|
|
@ -2154,7 +2210,7 @@ x1127: mov dx,0x3c4 ; 00001127 BAC403 '...'
|
|||
out dx,al ; 00001181 EE '.'
|
||||
popf ; 00001182 9D '.'
|
||||
push bx ; 00001183 53 'S'
|
||||
mov dl,0xce ; 00001184 B2CE '..'
|
||||
mov dl,0xce ; (DX) == GRC port address (0x3CE)
|
||||
add bx,byte +0x37 ; 00001186 83C337 '..7'
|
||||
mov cx,0x9 ; 00001189 B90900 '...'
|
||||
xor al,al ; 0000118C 32C0 '2.'
|
||||
|
|
|
|||
|
|
@ -1375,7 +1375,8 @@ Bus.prototype.checkPortInputNotify = function(port, addrLIP)
|
|||
}
|
||||
if (aNotify !== undefined) {
|
||||
if (aNotify[1]) {
|
||||
bIn = aNotify[1].call(aNotify[0], port, addrLIP);
|
||||
var b = aNotify[1].call(aNotify[0], port, addrLIP);
|
||||
if (b !== undefined) bIn = b;
|
||||
}
|
||||
if (DEBUGGER && this.dbg && this.fPortInputBreakAll != aNotify[2]) {
|
||||
this.dbg.checkPortInput(port, bIn);
|
||||
|
|
|
|||
|
|
@ -462,6 +462,42 @@ Video.CARD = {
|
|||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Supported Modes
|
||||
*
|
||||
* Although this component is designed to be a video hardware emulation, not a BIOS simulation, we DO
|
||||
* look for changes to the hardware state that correspond to standard BIOS mode settings, so our internal
|
||||
* mode setting will normally match the current BIOS mode setting; however, this a debugging convenience,
|
||||
* not an attempt to monitor or emulate the BIOS.
|
||||
*
|
||||
* We do have some BIOS awareness (eg, when loading ROM-based fonts, and some special code to ensure all
|
||||
* the BIOS diagnostics pass), but for the most part, we treat the BIOS like any other application code.
|
||||
*
|
||||
* As we expand support to include more programmable cards like the EGA, it becomes quite easy for the card
|
||||
* to enter a "mode" that has no BIOS counterpart (eg, non-standard combinations of frame buffer address,
|
||||
* memory access modes, fonts, display regions, etc). Our hardware emulation routines will cope with those
|
||||
* situations as best they can (and when they don't, it should be considered a bug if some application is
|
||||
* broken as a result), but realistically, our hardware emulation is never likely to be 100% accurate.
|
||||
*/
|
||||
Video.MODE = {
|
||||
CGA_40X25_BW: 0,
|
||||
CGA_40X25: 1,
|
||||
CGA_80X25_BW: 2,
|
||||
CGA_80X25: 3,
|
||||
CGA_320X200: 4,
|
||||
CGA_320X200_BW: 5,
|
||||
CGA_640X200: 6,
|
||||
MDA_80X25: 7,
|
||||
EGA_320X200: 0x0D, // mapped at A000:0000
|
||||
EGA_640X200: 0x0E, // mapped at A000:0000
|
||||
EGA_640X350_MONO: 0x0F, // mapped at A000:0000, monochrome
|
||||
EGA_640X350: 0x10, // mapped at A000:0000, color
|
||||
VGA_640X480_MONO: 0x11, // mapped at A000:0000, monochrome
|
||||
VGA_640X480: 0x12, // mapped at A000:0000, color
|
||||
VGA_320X200: 0x13, // mapped at A000:0000, color
|
||||
UNKNOWN: 0xFF
|
||||
};
|
||||
|
||||
/*
|
||||
* Supported Monitors
|
||||
*
|
||||
|
|
@ -604,42 +640,6 @@ Video.aEGAMonitorSwitches = {
|
|||
0x05: [ChipSet.MONITOR.MONO, ChipSet.MONITOR.COLOR, false] // "0101"
|
||||
};
|
||||
|
||||
/*
|
||||
* Supported Modes
|
||||
*
|
||||
* Although this component is designed to be a video hardware emulation, not a BIOS simulation, we DO
|
||||
* look for changes to the hardware state that correspond to standard BIOS mode settings, so our internal
|
||||
* mode setting will normally match the current BIOS mode setting; however, this a debugging convenience,
|
||||
* not an attempt to monitor or emulate the BIOS.
|
||||
*
|
||||
* We do have some BIOS awareness (eg, when loading ROM-based fonts, and some special code to ensure all
|
||||
* the BIOS diagnostics pass), but for the most part, we treat the BIOS like any other application code.
|
||||
*
|
||||
* As we expand support to include more programmable cards like the EGA, it becomes quite easy for the card
|
||||
* to enter a "mode" that has no BIOS counterpart (eg, non-standard combinations of frame buffer address,
|
||||
* memory access modes, fonts, display regions, etc). Our hardware emulation routines will cope with those
|
||||
* situations as best they can (and when they don't, it should be considered a bug if some application is
|
||||
* broken as a result), but realistically, our hardware emulation is never likely to be 100% accurate.
|
||||
*/
|
||||
Video.MODE = {
|
||||
CGA_40X25_BW: 0,
|
||||
CGA_40X25: 1,
|
||||
CGA_80X25_BW: 2,
|
||||
CGA_80X25: 3,
|
||||
CGA_320X200: 4,
|
||||
CGA_320X200_BW: 5,
|
||||
CGA_640X200: 6,
|
||||
MDA_80X25: 7,
|
||||
EGA_320X200: 0x0D, // mapped at A000:0000
|
||||
EGA_640X200: 0x0E, // mapped at A000:0000
|
||||
EGA_640X350_MONO: 0x0F, // mapped at A000:0000, monochrome
|
||||
EGA_640X350: 0x10, // mapped at A000:0000, color
|
||||
VGA_640X480_MONO: 0x11, // mapped at A000:0000, monochrome
|
||||
VGA_640X480: 0x12, // mapped at A000:0000, color
|
||||
VGA_320X200: 0x13, // mapped at A000:0000, color
|
||||
UNKNOWN: 0xFF
|
||||
};
|
||||
|
||||
/**
|
||||
* @class Font
|
||||
* @property {number} cxCell
|
||||
|
|
@ -1121,7 +1121,7 @@ Card.CRTC = {
|
|||
HR: 0x80 // Hardware Reset
|
||||
},
|
||||
LINE_COMPARE: 0x18,
|
||||
TOTAL_REGS: 0x19 // total CRT registers on EGA
|
||||
TOTAL_REGS: 0x19 // total CRT registers on EGA/VGA
|
||||
},
|
||||
ADDR_HI_MASK: 0x3F
|
||||
};
|
||||
|
|
@ -1134,7 +1134,7 @@ if (DEBUGGER) {
|
|||
|
||||
Card.CRTC.EGA_REGS = ["HORZ_TOTAL","HORZ_DISP_END","HORZ_BLANK_START","HORZ_BLANK_END","HORZ_RETRACE_START","HORZ_RETRACE_END",
|
||||
"VERT_TOTAL","CRTC_OVERFLOW","PRESET_ROW_SCAN","MAX_SCAN_LINE","CURSOR_START","CURSOR_END",
|
||||
"START_ADDR_HI","START_ADDR_LO","CURSOR_ADDR_HI","CURSOR_ADDR_LO","LIGHT_PEN_HI","LIGHT_PEN_LO",
|
||||
"START_ADDR_HI","START_ADDR_LO","CURSOR_ADDR_HI","CURSOR_ADDR_LO","VERT_RETRACE_START","VERT_RETRACE_END",
|
||||
"VERT_DISP_END","OFFSET","UNDERLINE","VERT_BLANK_START","VERT_BLANK_END","MODE_CTRL","LINE_COMPARE"];
|
||||
}
|
||||
|
||||
|
|
@ -1352,7 +1352,8 @@ if (DEBUGGER) Card.SEQ.REGS = ["RESET","CLK","MAPMASK","CHARMAP","MODE"];
|
|||
*/
|
||||
Card.DAC = {
|
||||
MASK: {
|
||||
PORT: 0x3C6 // initialized to 0xFF and should not be changed
|
||||
PORT: 0x3C6, // initialized to 0xFF and should not be changed
|
||||
DEFAULT: 0xFF
|
||||
},
|
||||
STATE: {
|
||||
PORT: 0x3C7,
|
||||
|
|
@ -1365,15 +1366,16 @@ Card.DAC = {
|
|||
},
|
||||
DATA: {
|
||||
PORT: 0x3C9
|
||||
}
|
||||
},
|
||||
TOTAL_REGS: 0x100
|
||||
};
|
||||
|
||||
/*
|
||||
* EGA/VGA Graphics Controller Registers (regGRCIndx and regGRCData)
|
||||
*/
|
||||
Card.GRC = {
|
||||
POS1_PORT: 0x3CC,
|
||||
POS2_PORT: 0x3CA,
|
||||
POS1_PORT: 0x3CC, // EGA only, write-only
|
||||
POS2_PORT: 0x3CA, // EGA only, write-only
|
||||
INDX: {
|
||||
PORT: 0x3CE,
|
||||
MASK: 0x0F
|
||||
|
|
@ -1903,7 +1905,13 @@ Card.prototype.initEGA = function(data, nMonitorType)
|
|||
/*21*/ 0xffffffff|0,
|
||||
/*22*/ 0,
|
||||
/*23*/ 0,
|
||||
/*24*/ 0
|
||||
/*24*/ 0,
|
||||
/*25*/ Card.VGA_ENABLE.ENABLED,
|
||||
/*26*/ Card.DAC.MASK.DEFAULT,
|
||||
/*27*/ 0,
|
||||
/*28*/ 0,
|
||||
/*29*/ Card.DAC.STATE.MODE_WRITE,
|
||||
/*30*/ new Array(Card.DAC.TOTAL_REGS)
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -1969,7 +1977,15 @@ Card.prototype.initEGA = function(data, nMonitorType)
|
|||
this.nSetMapBits = data[22];
|
||||
this.nColorCompare = data[23];
|
||||
this.nColorDontCare = data[24];
|
||||
this.regVGAEnable = data[25];
|
||||
|
||||
if (this.nCard == Video.CARD.VGA) {
|
||||
this.regVGAEnable = data[25];
|
||||
this.regDACMask = data[26];
|
||||
this.regDACAddr = data[27];
|
||||
this.regDACShift = data[28];
|
||||
this.regDACState = data[29];
|
||||
this.regDACData = data[30];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -2030,7 +2046,15 @@ Card.prototype.saveEGA = function()
|
|||
data[22] = this.nSetMapBits;
|
||||
data[23] = this.nColorCompare;
|
||||
data[24] = this.nColorDontCare;
|
||||
data[25] = this.regVGAEnable;
|
||||
|
||||
if (this.nCard == Video.CARD.VGA) {
|
||||
data[25] = this.regVGAEnable;
|
||||
data[26] = this.regDACMask;
|
||||
data[27] = this.regDACAddr;
|
||||
data[28] = this.regDACShift;
|
||||
data[29] = this.regDACState;
|
||||
data[30] = this.regDACData;
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
||||
|
|
@ -4016,7 +4040,16 @@ Video.prototype.checkMode = function(fForce)
|
|||
// we've already defaulted to 0x0F or 0x10, so determine if it's 0x0D or 0x0E (ie, a 200-row mode)
|
||||
// and then which one (ie, 320 wide or 640 wide).
|
||||
//
|
||||
if (nCRTCVertTotal < 350) nMode = (fSEQDotClock? Video.MODE.EGA_320X200 : Video.MODE.EGA_640X200);
|
||||
if (nCRTCVertTotal > 480) {
|
||||
nMode = Video.MODE.VGA_640X480;
|
||||
}
|
||||
else if (nCRTCVertTotal < 350) {
|
||||
nMode = (fSEQDotClock? Video.MODE.EGA_320X200 : Video.MODE.EGA_640X200);
|
||||
}
|
||||
if (DEBUG && this.messageEnabled()) {
|
||||
this.printMessage("checkMode(): nCRTCVertTotal=" + nCRTCVertTotal + ", mode=" + str.toHexByte(nMode));
|
||||
this.cpu.stopCPU();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4074,7 +4107,7 @@ Video.prototype.setMode = function(nMode, fForce)
|
|||
if (nMode != null && (nMode != this.nMode || fForce)) {
|
||||
|
||||
if (DEBUG && this.messageEnabled()) {
|
||||
this.printMessage("setMode(" + str.toHexWord(nMode) + (fForce? ",force" : "") + ")");
|
||||
this.printMessage("setMode(" + str.toHexByte(nMode) + (fForce? ",force" : "") + ")");
|
||||
}
|
||||
|
||||
this.cUpdates = 0; // count updateScreen() calls as a means of driving blink updates
|
||||
|
|
@ -4100,7 +4133,7 @@ Video.prototype.setMode = function(nMode, fForce)
|
|||
if (this.addrBuffer) {
|
||||
|
||||
if (DEBUG && this.messageEnabled()) {
|
||||
this.printMessage("setMode(" + nMode + "): removing " + str.toHexLong(this.sizeBuffer) + " bytes from " + str.toHexLong(this.addrBuffer));
|
||||
this.printMessage("setMode(" + str.toHexByte(nMode) + "): removing " + str.toHexLong(this.sizeBuffer) + " bytes from " + str.toHexLong(this.addrBuffer));
|
||||
}
|
||||
|
||||
if (!this.bus.removeMemory(this.addrBuffer, this.sizeBuffer)) {
|
||||
|
|
@ -4119,7 +4152,7 @@ Video.prototype.setMode = function(nMode, fForce)
|
|||
this.sizeBuffer = card.sizeBuffer;
|
||||
|
||||
if (DEBUG && this.messageEnabled()) {
|
||||
this.printMessage("setMode(" + nMode + "): adding " + str.toHexLong(this.sizeBuffer) + " bytes to " + str.toHexLong(this.addrBuffer));
|
||||
this.printMessage("setMode(" + str.toHexByte(nMode) + "): adding " + str.toHexLong(this.sizeBuffer) + " bytes to " + str.toHexLong(this.addrBuffer));
|
||||
}
|
||||
|
||||
var controller = (card === this.cardEGA? card : null);
|
||||
|
|
@ -4692,11 +4725,11 @@ Video.prototype.updateScreenGraphicsEGA = function(addrScreen, addrScreenLimit)
|
|||
* @this {Video}
|
||||
* @param {number} port (0x3B4)
|
||||
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
|
||||
* @return {number}
|
||||
* @return {number|undefined}
|
||||
*/
|
||||
Video.prototype.inMDAIndx = function(port, addrFrom)
|
||||
{
|
||||
return this.inCRTCIndx(this.cardMono, addrFrom);
|
||||
return this.inCRTCIndx(this.cardMono, port, addrFrom);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -4709,7 +4742,7 @@ Video.prototype.inMDAIndx = function(port, addrFrom)
|
|||
*/
|
||||
Video.prototype.outMDAIndx = function(port, bOut, addrFrom)
|
||||
{
|
||||
this.outCRTCIndx(this.cardMono, bOut, addrFrom);
|
||||
this.outCRTCIndx(this.cardMono, port, bOut, addrFrom);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -4722,7 +4755,7 @@ Video.prototype.outMDAIndx = function(port, bOut, addrFrom)
|
|||
*/
|
||||
Video.prototype.inMDAData = function(port, addrFrom)
|
||||
{
|
||||
return this.inCRTCData(this.cardMono, addrFrom);
|
||||
return this.inCRTCData(this.cardMono, port, addrFrom);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -4735,7 +4768,7 @@ Video.prototype.inMDAData = function(port, addrFrom)
|
|||
*/
|
||||
Video.prototype.outMDAData = function(port, bOut, addrFrom)
|
||||
{
|
||||
this.outCRTCData(this.cardMono, bOut, addrFrom);
|
||||
this.outCRTCData(this.cardMono, port, bOut, addrFrom);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -4982,6 +5015,138 @@ Video.prototype.outSEQData = function(port, bOut, addrFrom)
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* inDACMask(port, addrFrom)
|
||||
*
|
||||
* @this {Video}
|
||||
* @param {number} port (0x3C6)
|
||||
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
|
||||
* @return {number}
|
||||
*/
|
||||
Video.prototype.inDACMask = function(port, addrFrom)
|
||||
{
|
||||
var b = this.cardEGA.regDACMask;
|
||||
if (this.messageEnabled()) {
|
||||
this.printMessageIO(Card.DAC.MASK.PORT, null, addrFrom, "DAC.MASK", b);
|
||||
}
|
||||
return b;
|
||||
};
|
||||
|
||||
/**
|
||||
* outDACMask(port, bOut, addrFrom)
|
||||
*
|
||||
* @this {Video}
|
||||
* @param {number} port (0x3C6)
|
||||
* @param {number} bOut
|
||||
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
|
||||
*/
|
||||
Video.prototype.outDACMask = function(port, bOut, addrFrom)
|
||||
{
|
||||
if (Video.TRAPALL || this.cardEGA.regDACMask !== bOut) {
|
||||
if (this.messageEnabled()) {
|
||||
this.printMessageIO(Card.DAC.MASK.PORT, bOut, addrFrom, "DAC.MASK");
|
||||
}
|
||||
this.cardEGA.regDACMask = bOut;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* inDACState(port, addrFrom)
|
||||
*
|
||||
* @this {Video}
|
||||
* @param {number} port (0x3C7)
|
||||
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
|
||||
* @return {number}
|
||||
*/
|
||||
Video.prototype.inDACState = function(port, addrFrom)
|
||||
{
|
||||
var b = this.cardEGA.regDACState;
|
||||
if (this.messageEnabled()) {
|
||||
this.printMessageIO(Card.DAC.STATE.PORT, null, addrFrom, "DAC.STATE", b);
|
||||
}
|
||||
return b;
|
||||
};
|
||||
|
||||
/**
|
||||
* outDACRead(port, bOut, addrFrom)
|
||||
*
|
||||
* @this {Video}
|
||||
* @param {number} port (0x3C7)
|
||||
* @param {number} bOut
|
||||
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
|
||||
*/
|
||||
Video.prototype.outDACRead = function(port, bOut, addrFrom)
|
||||
{
|
||||
if (this.messageEnabled()) {
|
||||
this.printMessageIO(Card.DAC.ADDR.PORT_READ, bOut, addrFrom, "DAC.READ");
|
||||
}
|
||||
this.cardEGA.regDACAddr = bOut;
|
||||
this.cardEGA.regDACState = Card.DAC.STATE.MODE_READ;
|
||||
this.cardEGA.regDACShift = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* outDACWrite(port, bOut, addrFrom)
|
||||
*
|
||||
* @this {Video}
|
||||
* @param {number} port (0x3C8)
|
||||
* @param {number} bOut
|
||||
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
|
||||
*/
|
||||
Video.prototype.outDACWrite = function(port, bOut, addrFrom)
|
||||
{
|
||||
if (this.messageEnabled()) {
|
||||
this.printMessageIO(Card.DAC.ADDR.PORT_WRITE, bOut, addrFrom, "DAC.WRITE");
|
||||
}
|
||||
this.cardEGA.regDACAddr = bOut;
|
||||
this.cardEGA.regDACState = Card.DAC.STATE.MODE_WRITE;
|
||||
this.cardEGA.regDACShift = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* inDACData(port, addrFrom)
|
||||
*
|
||||
* @this {Video}
|
||||
* @param {number} port (0x3C9)
|
||||
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
|
||||
* @return {number}
|
||||
*/
|
||||
Video.prototype.inDACData = function(port, addrFrom)
|
||||
{
|
||||
var b = (this.cardEGA.regDACData[this.cardEGA.regDACAddr] >> this.cardEGA.regDACShift) & 0x3f;
|
||||
if (this.messageEnabled()) {
|
||||
this.printMessageIO(Card.DAC.DATA.PORT, null, addrFrom, "DAC.DATA[" + str.toHexByte(this.cardEGA.regDACAddr) + "][" + str.toHexByte(this.cardEGA.regDACShift) + "]", b);
|
||||
}
|
||||
this.cardEGA.regDACShift += 6;
|
||||
if (this.cardEGA.regDACShift > 12) {
|
||||
this.cardEGA.regDACShift = 0;
|
||||
this.cardEGA.regDACAddr = (this.cardEGA.regDACAddr + 1) & (Card.DAC.TOTAL_REGS-1);
|
||||
}
|
||||
return b;
|
||||
};
|
||||
|
||||
/**
|
||||
* outDACData(port, bOut, addrFrom)
|
||||
*
|
||||
* @this {Video}
|
||||
* @param {number} port (0x3C9)
|
||||
* @param {number} bOut
|
||||
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
|
||||
*/
|
||||
Video.prototype.outDACData = function(port, bOut, addrFrom)
|
||||
{
|
||||
var dw = this.cardEGA.regDACData[this.cardEGA.regDACAddr];
|
||||
if (this.messageEnabled()) {
|
||||
this.printMessageIO(Card.DAC.DATA.PORT, bOut, addrFrom, "DAC.DATA[" + str.toHexByte(this.cardEGA.regDACAddr) + "][" + str.toHexByte(this.cardEGA.regDACShift) + "]");
|
||||
}
|
||||
this.cardEGA.regDACData[this.cardEGA.regDACAddr] = (dw & ~(0x3f << this.cardEGA.regDACShift)) | ((bOut & 0x3f) << this.cardEGA.regDACShift);
|
||||
this.cardEGA.regDACShift += 6;
|
||||
if (this.cardEGA.regDACShift > 12) {
|
||||
this.cardEGA.regDACShift = 0;
|
||||
this.cardEGA.regDACAddr = (this.cardEGA.regDACAddr + 1) & (Card.DAC.TOTAL_REGS-1);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* inVGAFeat(port, addrFrom)
|
||||
*
|
||||
|
|
@ -5154,11 +5319,11 @@ Video.prototype.outGRCData = function(port, bOut, addrFrom)
|
|||
* @this {Video}
|
||||
* @param {number} port (0x3D4)
|
||||
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
|
||||
* @return {number}
|
||||
* @return {number|undefined}
|
||||
*/
|
||||
Video.prototype.inCGAIndx = function(port, addrFrom)
|
||||
{
|
||||
return this.inCRTCIndx(this.cardColor, addrFrom);
|
||||
return this.inCRTCIndx(this.cardColor, port, addrFrom);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -5171,7 +5336,7 @@ Video.prototype.inCGAIndx = function(port, addrFrom)
|
|||
*/
|
||||
Video.prototype.outCGAIndx = function(port, bOut, addrFrom)
|
||||
{
|
||||
this.outCRTCIndx(this.cardColor, bOut, addrFrom);
|
||||
this.outCRTCIndx(this.cardColor, port, bOut, addrFrom);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -5184,7 +5349,7 @@ Video.prototype.outCGAIndx = function(port, bOut, addrFrom)
|
|||
*/
|
||||
Video.prototype.inCGAData = function(port, addrFrom)
|
||||
{
|
||||
return this.inCRTCData(this.cardColor, addrFrom);
|
||||
return this.inCRTCData(this.cardColor, port, addrFrom);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -5197,7 +5362,7 @@ Video.prototype.inCGAData = function(port, addrFrom)
|
|||
*/
|
||||
Video.prototype.outCGAData = function(port, bOut, addrFrom)
|
||||
{
|
||||
this.outCRTCData(this.cardColor, bOut, addrFrom);
|
||||
this.outCRTCData(this.cardColor, port, bOut, addrFrom);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -5238,7 +5403,7 @@ Video.prototype.inCGAColor = function(port, addrFrom)
|
|||
{
|
||||
var b = this.cardColor.regColor;
|
||||
if (this.messageEnabled()) {
|
||||
this.printMessageIO(this.cardColor.port + 5, null, addrFrom, this.cardColor.type + ".COLOR", b);
|
||||
this.printMessageIO(port /* this.cardColor.port + 5 */, null, addrFrom, this.cardColor.type + ".COLOR", b);
|
||||
}
|
||||
return b;
|
||||
};
|
||||
|
|
@ -5254,7 +5419,7 @@ Video.prototype.inCGAColor = function(port, addrFrom)
|
|||
Video.prototype.outCGAColor = function(port, bOut, addrFrom)
|
||||
{
|
||||
if (this.messageEnabled()) {
|
||||
this.printMessageIO(this.cardColor.port + 5, bOut, addrFrom, this.cardColor.type + ".COLOR");
|
||||
this.printMessageIO(port /* this.cardColor.port + 5 */, bOut, addrFrom, this.cardColor.type + ".COLOR");
|
||||
}
|
||||
if (this.cardColor.regColor !== bOut) {
|
||||
this.cardColor.regColor = bOut;
|
||||
|
|
@ -5280,67 +5445,92 @@ Video.prototype.inCGAStatus = function(port, addrFrom)
|
|||
};
|
||||
|
||||
/**
|
||||
* inCRTCIndx(card, addrFrom)
|
||||
* inCRTCIndx(card, port, addrFrom)
|
||||
*
|
||||
* @this {Video}
|
||||
* @param {Object} card
|
||||
* @param {number} port
|
||||
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
|
||||
* @return {number}
|
||||
* @return {number|undefined}
|
||||
*/
|
||||
Video.prototype.inCRTCIndx = function(card, addrFrom)
|
||||
Video.prototype.inCRTCIndx = function(card, port, addrFrom)
|
||||
{
|
||||
var b = card.regCRTIndx;
|
||||
this.printMessageIO(card.port, null, addrFrom, "CRTC.INDX", b);
|
||||
var b;
|
||||
/*
|
||||
* The IBM VGA ROM makes some hardware determinations based on how the CRTC controller responds when
|
||||
* the IO_SELECT bit in the Miscellaneous Output Register is cleared; normally, that would mean ports
|
||||
* 0x3B? are decoded and ports 0x3D? are ignored. We didn't used to bother ignoring them, but the
|
||||
* VGA ROM's logic requires it, so now we also check fActive. However, we ignore only CTRC reads;
|
||||
* we retain any writes in case that information proves useful later.
|
||||
*
|
||||
* Note that returning an undefined value now signals the Bus component to return whatever default value
|
||||
* it prefers (normally 0xff).
|
||||
*/
|
||||
if (card.fActive) b = card.regCRTIndx;
|
||||
this.printMessageIO(port, null, addrFrom, "CRTC.INDX", b);
|
||||
return b;
|
||||
};
|
||||
|
||||
/**
|
||||
* outCRTCIndx(card, bOut, addrFrom)
|
||||
* outCRTCIndx(card, port, bOut, addrFrom)
|
||||
*
|
||||
* @this {Video}
|
||||
* @param {Object} card
|
||||
* @param {number} port
|
||||
* @param {number} bOut
|
||||
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
|
||||
*/
|
||||
Video.prototype.outCRTCIndx = function(card, bOut, addrFrom)
|
||||
Video.prototype.outCRTCIndx = function(card, port, bOut, addrFrom)
|
||||
{
|
||||
card.regCRTPrev = card.regCRTIndx;
|
||||
card.regCRTIndx = bOut & Card.CGA.CRTC.INDX.MASK;
|
||||
this.printMessageIO(card.port, bOut, addrFrom, "CRTC.INDX");
|
||||
this.printMessageIO(port /* card.port */, bOut, addrFrom, "CRTC.INDX");
|
||||
};
|
||||
|
||||
/**
|
||||
* inCRTCData(card, addrFrom)
|
||||
* inCRTCData(card, port, addrFrom)
|
||||
*
|
||||
* @this {Video}
|
||||
* @param {Object} card
|
||||
* @param {number} port
|
||||
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
|
||||
* @return {number|undefined}
|
||||
*/
|
||||
Video.prototype.inCRTCData = function(card, addrFrom)
|
||||
Video.prototype.inCRTCData = function(card, port, addrFrom)
|
||||
{
|
||||
var b;
|
||||
if (card.regCRTIndx < card.nCRTCRegs) b = card.regCRTData[card.regCRTIndx];
|
||||
/*
|
||||
* The IBM VGA ROM makes some hardware determinations based on how the CRTC controller responds when
|
||||
* the IO_SELECT bit in the Miscellaneous Output Register is cleared; normally, that would mean ports
|
||||
* 0x3B? are decoded and ports 0x3D? are ignored. We didn't used to bother ignoring them, but the
|
||||
* VGA ROM's logic requires it, so now we also check fActive. However, we ignore only CTRC reads;
|
||||
* we retain any writes in case that information proves useful later.
|
||||
*
|
||||
* Note that returning an undefined value now signals the Bus component to return whatever default value
|
||||
* it prefers (normally 0xff).
|
||||
*/
|
||||
if (card.fActive && card.regCRTIndx < card.nCRTCRegs) b = card.regCRTData[card.regCRTIndx];
|
||||
if (this.messageEnabled()) {
|
||||
this.printMessageIO(card.port + 1, null, addrFrom, "CRTC." + card.asCRTCRegs[card.regCRTIndx], b);
|
||||
this.printMessageIO(port /* card.port + 1 */, null, addrFrom, "CRTC." + card.asCRTCRegs[card.regCRTIndx], b);
|
||||
}
|
||||
return b;
|
||||
};
|
||||
|
||||
/**
|
||||
* outCRTCData(card, bOut, addrFrom)
|
||||
* outCRTCData(card, port, bOut, addrFrom)
|
||||
*
|
||||
* @this {Video}
|
||||
* @param {Object} card
|
||||
* @param {number} port
|
||||
* @param {number} bOut
|
||||
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
|
||||
*/
|
||||
Video.prototype.outCRTCData = function(card, bOut, addrFrom)
|
||||
Video.prototype.outCRTCData = function(card, port, bOut, addrFrom)
|
||||
{
|
||||
if (card.regCRTIndx < card.nCRTCRegs) {
|
||||
if (Video.TRAPALL || card.regCRTData[card.regCRTIndx] !== bOut) {
|
||||
if (this.messageEnabled()) {
|
||||
this.printMessageIO(card.port + 1, bOut, addrFrom, "CRTC." + card.asCRTCRegs[card.regCRTIndx]);
|
||||
this.printMessageIO(port /* card.port + 1 */, bOut, addrFrom, "CRTC." + card.asCRTCRegs[card.regCRTIndx]);
|
||||
}
|
||||
card.regCRTData[card.regCRTIndx] = bOut;
|
||||
}
|
||||
|
|
@ -5571,12 +5761,19 @@ Video.aEGAPortOutput = {
|
|||
|
||||
Video.aVGAPortInput = {
|
||||
0x3C3: Video.prototype.inVGAEnable,
|
||||
0x3C6: Video.prototype.inDACMask,
|
||||
0x3C7: Video.prototype.inDACState,
|
||||
0x3C9: Video.prototype.inDACData,
|
||||
0x3CA: Video.prototype.inVGAFeat,
|
||||
0x3CC: Video.prototype.inVGAMisc
|
||||
};
|
||||
|
||||
Video.aVGAPortOutput = {
|
||||
0x3C3: Video.prototype.outVGAEnable
|
||||
0x3C3: Video.prototype.outVGAEnable,
|
||||
0x3C6: Video.prototype.outDACMask,
|
||||
0x3C7: Video.prototype.outDACRead,
|
||||
0x3C8: Video.prototype.outDACWrite,
|
||||
0x3C9: Video.prototype.outDACData
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2114,7 +2114,7 @@ X86CPU.prototype.rewindIP = function(dec)
|
|||
X86CPU.prototype.getSP = function()
|
||||
{
|
||||
if (I386) {
|
||||
this.assert(!((this.regLSP - this.segSS.base) & ~this.segSS.addrMask));
|
||||
// assert(!((this.regLSP - this.segSS.base) & ~this.segSS.addrMask));
|
||||
return (this.regESP & ~this.segSS.addrMask) | (this.regLSP - this.segSS.base);
|
||||
}
|
||||
return (this.regLSP - this.segSS.base)|0;
|
||||
|
|
|
|||
Loading…
Reference in a new issue