--- /dev/null
+;-----------------------------------------------------------\r
+;\r
+; MXSM.ASM - Set/change mode functions\r
+; Copyright (c) 1993,1994 by Alessandro Scotti\r
+;\r
+;-----------------------------------------------------------\r
+WARN PRO\r
+INCLUDE MODEX.DEF\r
+\r
+PUBLIC mxChangeMode\r
+PUBLIC mxGetAspect\r
+PUBLIC mxGetScreenSize\r
+PUBLIC mxSetMode\r
+\r
+PUBLIC mx_ScreenWidth\r
+PUBLIC mx_ScreenHeight\r
+PUBLIC mx_BytesPerLine\r
+\r
+MX_TEXT SEGMENT USE16 PARA PUBLIC 'CODE'\r
+ ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING\r
+\r
+EXTRN mxSetSysClipRegion : FAR\r
+\r
+EXTRN mx_VideoSegment : WORD\r
+EXTRN mx_CodeSegment : WORD\r
+\r
+mx_ScreenWidth DW ? ; Current screen width\r
+mx_ScreenHeight DW ?\r
+mx_AspectX DW ? ; Aspect ratio for current mode\r
+mx_AspectY DW ?\r
+mx_BytesPerLine DW 0 ; Bytes per line\r
+\r
+;\r
+; Tables for setting video modes, sources:\r
+; - MODEX.ASM, Matt Pritchard\r
+; - Dr. Dobb's Journal, Michael Abrash\r
+; - Fractint VIDEO.ASM module\r
+;\r
+TBL_SingleLine LABEL WORD ; CRTC\r
+ DW 04009h ; Cell height: 1 scan line\r
+ DW 00014h ; Double word mode off\r
+ DW 0E317h ; Byte mode on\r
+ DW 0\r
+TBL_DoubleLine LABEL WORD ; CRTC\r
+ DW 04109h ; Cell height: 2 scan lines\r
+ DW 00014h\r
+ DW 0E317h\r
+ DW 0\r
+TBL_Width320 LABEL WORD ; CRTC\r
+ DW 05F00h ; Horizontal total\r
+ DW 04F01h ; Horizontal displayed\r
+ DW 05002h ; Start horizontal blanking\r
+ DW 08203h ; End horizontal blanking\r
+ DW 05404h ; Start horizontal sync\r
+ DW 08005h ; End horizontal sync\r
+ DW 02813h ; Row address\r
+ DW 0\r
+TBL_Width360 LABEL WORD ; CRTC\r
+ DW 06B00h ; Horizontal total\r
+ DW 05901h ; Horizontal displayed\r
+ DW 05A02h ; Start horizontal blanking\r
+ DW 08E03h ; End horizontal blanking\r
+ DW 05E04h ; Start horizontal sync\r
+ DW 08A05h ; End horizontal sync\r
+ DW 02D13h ; Row address\r
+ DW 0\r
+TBL_Height175 LABEL WORD ; CRTC\r
+ DW 0BF06h ; Vertical total\r
+ DW 01F07h ; Overflow\r
+ DW 08310h ; Start vertical sync\r
+ DW 08511h ; End vertical sync\r
+ DW 05D12h ; Vertical displayed\r
+ DW 06315h ; Start vertical blanking\r
+ DW 0BA16h ; End vertical blanking\r
+ DW 0\r
+TBL_Height200 LABEL WORD ; CRTC\r
+ DW 0BF06h ; Vertical total\r
+ DW 01F07h ; Overflow\r
+ DW 09C10h ; Start vertical sync\r
+ DW 08E11h ; End vertical sync\r
+ DW 08F12h ; Vertical displayed\r
+ DW 09615h ; Start vertical blanking\r
+ DW 0B916h ; End vertical blanking\r
+ DW 0\r
+TBL_Height240 LABEL WORD ; CRTC\r
+ DW 00D06h ; Vertical total\r
+ DW 03E07h ; Overflow\r
+ DW 0EA10h ; Start vertical sync\r
+ DW 08C11h ; End vertical sync\r
+ DW 0DF12h ; Vertical displayed\r
+ DW 0E715h ; Start vertical blanking\r
+ DW 00616h ; End vertical blanking\r
+ DW 0\r
+TBL_Tweak400x600:\r
+ DW 07400h\r
+ DW 06301h\r
+ DW 06402h\r
+ DW 09703h\r
+ DW 06804h\r
+ DW 09505h\r
+ DW 08606h\r
+ DW 0F007h\r
+ DW 06009h\r
+ DW 0310Fh\r
+ DW 05B10h\r
+ DW 08D11h\r
+ DW 05712h\r
+ DW 03213h\r
+ DW 00014h\r
+ DW 06015h\r
+ DW 08016h\r
+ DW 0E317h\r
+ DW 0\r
+\r
+TBL_320x200:\r
+ DB 63h ; 400 scan lines, 25 MHz clock\r
+ DW 6, 5 ; Aspect: 6/5 = 1.2:1\r
+ DW 320, 200 ; Size\r
+ DW TBL_Width320, TBL_Height200, TBL_DoubleLine, 0\r
+ DW 819 ; Max height\r
+TBL_320x240:\r
+ DB 0E3h ; 400 scan lines, 25 MHz clock\r
+ DW 1, 1 ; Aspect: 1/1 = 1:1\r
+ DW 320, 240 ; Size\r
+ DW TBL_Width320, TBL_Height240, TBL_DoubleLine, 0\r
+ DW 819 ; Max height\r
+TBL_320x400:\r
+ DB 63h ; 480 scan lines, 25 MHz clock\r
+ DW 6, 10 ; Aspect: 6/10 = 0.6:1\r
+ DW 320, 400 ; Size\r
+ DW TBL_Width320, TBL_Height200, TBL_SingleLine, 0\r
+ DW 819 ; Max height\r
+TBL_320x480:\r
+ DB 0E3h ; 480 scan lines, 25 MHz clock\r
+ DW 1, 2 ; Aspect: 1/2 = 0.5:1\r
+ DW 320, 480 ; Size\r
+ DW TBL_Width320, TBL_Height240, TBL_SingleLine, 0\r
+ DW 819 ; Max height\r
+TBL_360x200:\r
+ DB 067h ; 400 scan lines, 28 MHz clock\r
+ DW 27, 20 ; Aspect: 27/20 = 1.35:1\r
+ DW 360, 200 ; Size\r
+ DW TBL_Width360, TBL_Height200, TBL_DoubleLine, 0\r
+ DW 728 ; Max height\r
+TBL_360x240:\r
+ DB 0E7h ; 480 scan lines, 28 MHz clock\r
+ DW 9, 8 ; Aspect: 9/8 = 1.125:1\r
+ DW 360, 240 ; Size\r
+ DW TBL_Width360, TBL_Height240, TBL_DoubleLine, 0\r
+ DW 728 ; Max height\r
+TBL_360x400:\r
+ DB 067h ; 400 scan lines, 28 MHz clock\r
+ DW 27, 40 ; Aspect: 27/40 = 0.675:1\r
+ DW 360, 400 ; Size\r
+ DW TBL_Width360, TBL_Height200, TBL_SingleLine, 0\r
+ DW 728 ; Max height\r
+TBL_360x480:\r
+ DB 0E7h ; 480 scan lines, 28 MHz clock\r
+ DW 9, 16 ; Aspect: 9/16 = 0.5625:1\r
+ DW 360, 480 ; Size\r
+ DW TBL_Width360, TBL_Height240, TBL_SingleLine, 0\r
+ DW 728 ; Max height\r
+TBL_320x175:\r
+ DB 0A3h\r
+ DW 0, 0 ; Aspect:\r
+ DW 320, 175\r
+ DW TBL_Width320, TBL_Height175, TBL_DoubleLine, 0\r
+ DW 819\r
+TBL_320x350:\r
+ DB 0A3h\r
+ DW 0, 0 ; Aspect:\r
+ DW 320, 175\r
+ DW TBL_Width320, TBL_Height175, TBL_SingleLine, 0\r
+ DW 819\r
+TBL_360x175:\r
+ DB 0A7h\r
+ DW 0, 0 ; Aspect:\r
+ DW 360, 480 ; Size\r
+ DW TBL_Width360, TBL_Height175, TBL_DoubleLine, 0\r
+ DW 728 ; Max height\r
+TBL_360x350:\r
+ DB 0A7h\r
+ DW 0, 0 ; Aspect:\r
+ DW 360, 480 ; Size\r
+ DW TBL_Width360, TBL_Height175, TBL_SingleLine, 0\r
+ DW 728 ; Max height\r
+TBL_400x600:\r
+ DB 0E7h ; 28 MHz clock\r
+ DW 1, 2 ; Aspect: 1/2 = 0.5:1\r
+ DW 400, 600 ; Size\r
+ DW TBL_Tweak400x600, 0\r
+ DW 655 ; Max height\r
+\r
+TBL_Mode LABEL WORD\r
+ DW TBL_320x175\r
+ DW TBL_320x200\r
+ DW TBL_320x240\r
+ DW TBL_320x350\r
+ DW TBL_320x400\r
+ DW TBL_320x480\r
+ DW TBL_360x175\r
+ DW TBL_360x200\r
+ DW TBL_360x240\r
+ DW TBL_360x350\r
+ DW TBL_360x400\r
+ DW TBL_360x480\r
+ DW TBL_400x600\r
+\r
+MAXVMODE EQU ($-OFFSET TBL_Mode) / 2\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Enables 80x25 color text mode\r
+;\r
+subText PROC NEAR\r
+ ASSUME ds:MX_TEXT\r
+ mov ax, 0003h\r
+ int 10h ; Call BIOS set mode\r
+\r
+ mov [mx_ScreenHeight], 0\r
+ mov [mx_BytesPerLine], 0\r
+ ret\r
+subText ENDP\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Enables the selected graphics mode.\r
+;\r
+; Input:\r
+; Mode = mode to select (MX_???x???)\r
+; Output:\r
+; none\r
+;\r
+mxSetMode PROC FAR\r
+ ARG Mode:WORD = ARG_SIZE\r
+ ASSUME ds:NOTHING\r
+ .enter 0\r
+ .push ds, si, es, di\r
+\r
+; Set DS to code segment alias\r
+ mov ds, [mx_CodeSegment]\r
+ ASSUME ds:MX_TEXT\r
+\r
+ mov si, [Mode]\r
+ cmp si, MAXVMODE ; Is it a valid mode?\r
+ ja @@Exit ; No, exit\r
+ test si, si ; Text mode?\r
+ jnz @@Set ; No, handle it\r
+\r
+ call subText ; Back to text mode\r
+ jmp @@Exit ; Exit now\r
+\r
+; Set video mode\r
+@@Set:\r
+ dec si ; Skip text mode\r
+ shl si, 1\r
+ mov si, TBL_Mode[si]\r
+ cld\r
+\r
+; Use BIOS to set 320x200x256 linear mode\r
+ push si ; Save SI\r
+ mov ax, 0013h\r
+ int 10h ; Use BIOS to set 320x200 linear mode\r
+ pop si ; Restore SI\r
+\r
+ mov dx, TS\r
+ mov ax, 0604h\r
+ out dx, ax ; Disable chain-4 mode\r
+ mov ax, 0100h\r
+ out dx, ax ; Reset\r
+ mov dx, MISC\r
+ lodsb\r
+ out dx, al ; New timing/size\r
+ mov dx, TS\r
+ mov ax, 0300h\r
+ out dx, ax ; Restart sequencer\r
+\r
+; Unlock CRTC registers 0-7\r
+ mov dx, CRTC\r
+ mov al, 11h\r
+ out dx, al ; Vertical sync end register\r
+ inc dx\r
+ in al, dx\r
+ and al, 7Fh ; Clear write protect bit\r
+ out dx, al\r
+\r
+ lodsw ; Get X aspect\r
+ mov [mx_AspectX], ax\r
+ lodsw ; Get Y aspect\r
+ mov [mx_AspectY], ax\r
+ lodsw ; Get screen width\r
+ mov [mx_ScreenWidth], ax\r
+ shr ax, 1\r
+ shr ax, 1 ; Divide by four to get bytes per line\r
+ mov [mx_BytesPerLine], ax\r
+ lodsw ; Get screen height\r
+ mov [mx_ScreenHeight], ax\r
+\r
+; Set CRTC registers\r
+ mov bx, si\r
+ mov dx, CRTC\r
+@@TableLoop:\r
+ mov si, ds:[bx] ; DS:SI -> table of CRTC registers\r
+ inc bx\r
+ inc bx ; DS:BX -> offset of next table\r
+ test si, si ; Last table?\r
+ jz @@EndLoop ; Yes, exit loop\r
+@@Loop:\r
+ lodsw ; Get CRTC register index and value\r
+ test ax, ax ; End of table?\r
+ jz @@TableLoop ; Yes, go to next table\r
+ out dx, ax ; Set register AL to value AH\r
+ jmp @@Loop ; Get next register/value\r
+@@EndLoop:\r
+\r
+; Set virtual screen and system clip region\r
+ push [mx_ScreenWidth]\r
+ push WORD PTR ds:[bx]\r
+ call mxSetSysClipRegion\r
+\r
+; Clear video memory\r
+ mov dx, TS\r
+ mov ax, 0F02h\r
+ out dx, ax ; Enable all planes\r
+ mov es, [mx_VideoSegment]\r
+ xor di, di\r
+ mov cx, 8000h\r
+ xor ax, ax\r
+ rep stosw\r
+\r
+@@Done:\r
+; Lock CRTC registers 0-7 (some cards need this)\r
+ mov dx, CRTC\r
+ mov al, 11h\r
+ out dx, al ; Vertical sync end register\r
+ inc dx\r
+ in al, dx\r
+ or al, 80h ; Set write protect bit\r
+ out dx, al\r
+\r
+@@Exit:\r
+ xor ax, ax\r
+ mov ax, [mx_ScreenWidth]\r
+ .pop ds, si, es, di\r
+ .leave ARG_SIZE\r
+mxSetMode ENDP\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Changes from the current mode the selected graphics mode.\r
+;\r
+; Input:\r
+; Mode = mode to select (MX_???x???)\r
+; Output:\r
+; none\r
+; Notes:\r
+; this function assumes that mxSetMode and mxSetVirtualScreen\r
+; have been called first. View size is rearranged to match the\r
+; specified mode, but video memory is not cleared.\r
+; Differences from mxSetMode:\r
+; - video BIOS is not called to initialize graphics;\r
+; - row address register is not modified;\r
+; - video memory is not cleared;\r
+; - mx_BytesPerLine is not modified;\r
+; - system clip region is not modified.\r
+;\r
+mxChangeMode PROC FAR\r
+ ARG Mode:WORD = ARG_SIZE\r
+ ASSUME ds:NOTHING\r
+ .enter 0\r
+ .push ds, si, es, di\r
+\r
+; Set DS to code segment alias\r
+ mov ds, [mx_CodeSegment]\r
+ ASSUME ds:MX_TEXT\r
+\r
+ mov si, [Mode]\r
+ cmp si, MAXVMODE ; Is it a valid mode?\r
+ ja @@Exit ; No, exit\r
+ test si, si ; Text mode?\r
+ jz @@Exit ; Yes, exit\r
+\r
+ dec si ; Skip text mode\r
+ shl si, 1\r
+ mov si, TBL_Mode[si]\r
+ cld\r
+\r
+ mov dx, TS\r
+ mov ax, 0604h\r
+ out dx, ax ; Disable chain-4 mode\r
+ mov ax, 0100h\r
+ out dx, ax ; Reset\r
+ mov dx, MISC\r
+ lodsb\r
+ out dx, al ; New timing/size\r
+ mov dx, TS\r
+ mov ax, 0300h\r
+ out dx, ax ; Restart sequencer\r
+\r
+; Unlock CRTC registers 0-7\r
+ mov dx, CRTC\r
+ mov al, 11h\r
+ out dx, al ; Vertical sync end register\r
+ inc dx\r
+ in al, dx\r
+ and al, 7Fh ; Clear write protect bit\r
+ out dx, al\r
+\r
+ lodsw ; Get X aspect\r
+ mov [mx_AspectX], ax\r
+ lodsw ; Get Y aspect\r
+ mov [mx_AspectY], ax\r
+ lodsw ; Get screen width\r
+ mov [mx_ScreenWidth], ax\r
+ lodsw ; Get screen height\r
+ mov [mx_ScreenHeight], ax\r
+\r
+; Set CRTC registers\r
+ mov bx, si\r
+ mov dx, CRTC\r
+@@TableLoop:\r
+ mov si, ds:[bx] ; DS:SI -> table of CRTC registers\r
+ inc bx\r
+ inc bx ; DS:BX -> offset of next table\r
+ test si, si ; Last table?\r
+ jz @@EndLoop ; Yes, exit loop\r
+@@Loop:\r
+ lodsw ; Get CRTC register index and value\r
+ test ax, ax ; End of table?\r
+ jz @@TableLoop ; Yes, go to next table\r
+ cmp al, 13h ; Row address register?\r
+ je @@Loop ; Yes, ignore it\r
+ out dx, ax ; Set register AL to value AH\r
+ jmp @@Loop ; Get next register/value\r
+@@EndLoop:\r
+\r
+; Lock CRTC registers 0-7 (some cards need this)\r
+ mov dx, CRTC\r
+ mov al, 11h\r
+ out dx, al ; Vertical sync end register\r
+ inc dx\r
+ in al, dx\r
+ or al, 80h ; Set write protect bit\r
+ out dx, al\r
+\r
+@@Exit:\r
+ xor ax, ax\r
+ mov ax, [mx_ScreenWidth]\r
+ .pop ds, si, es, di\r
+ .leave ARG_SIZE\r
+mxChangeMode ENDP\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Returns the aspect ratio for the current mode.\r
+;\r
+; Input:\r
+; AspectX = pointer to aspect X\r
+; AspectY = pointer to aspect Y\r
+;\r
+; A rectangle of width AspectX and height AspectY looks like a square.\r
+;\r
+mxGetAspect PROC FAR\r
+ ARG AspectY:DWORD, \\r
+ AspectX:DWORD = ARG_SIZE\r
+ .enter 0\r
+ .push ds, si\r
+ ASSUME ds:NOTHING\r
+\r
+ lds si, [AspectX]\r
+ mov ax, [mx_AspectX]\r
+ mov ds:[si], ax\r
+ lds si, [AspectY]\r
+ mov ax, [mx_AspectY]\r
+ mov ds:[si], ax\r
+\r
+ .pop ds, si\r
+ .leave ARG_SIZE\r
+mxGetAspect ENDP\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Returns the current screen size.\r
+;\r
+; Input:\r
+; Width = pointer to screen width\r
+; Height = pointer to screen height\r
+;\r
+mxGetScreenSize PROC FAR\r
+ ARG SizeY:DWORD, \\r
+ SizeX:DWORD = ARG_SIZE\r
+ .enter 0\r
+ .push ds, si\r
+ ASSUME ds:NOTHING\r
+\r
+ lds si, [SizeX]\r
+ mov ax, [mx_ScreenWidth]\r
+ mov ds:[si], ax\r
+ lds si, [SizeY]\r
+ mov ax, [mx_ScreenHeight]\r
+ mov ds:[si], ax\r
+\r
+ .pop ds, si\r
+ .leave ARG_SIZE\r
+mxGetScreenSize ENDP\r
+\r
+MX_TEXT ENDS\r
+END\r