home *** CD-ROM | disk | FTP | other *** search
- ;
- ; MODEX.ASM - A Complete Mode X Library
- ;
- ; By Matt Pritchard
- ; With considerable input from Michael Abrash
- ;
- ; The following information is donated to the public domain in
- ; the hopes that save other programmers much frustration.
- ;
- ; If you do use this code in a product, it would be nice if
- ; you include a line like 'Mode X routine by Matt Pritchard'
- ; in the credits. '
- ;
-
- .MODEL Medium, Basic
- .286
- PAGE 255, 132
-
- ; ==== MACROS ====
-
- OUT_16 MACRO Register, Value
- MOV DX, Register ; Select Register
- MOV AX, Value ; Get Out Value
- OUT DX, AX ; Set Register(s)
- ENDM
-
- OUT_8 MACRO Register, Value
- MOV DX, Register ; Select Register
- MOV AL, Value ; Get Out Value
- OUT DX, AL ; Set Register
- ENDM
-
- ; ==== General Constants ====
-
- False EQU 0
- True EQU -1
-
- b EQU BYTE PTR
- w EQU WORD PTR
- d EQU DWORD PTR
-
- ; ==== VGA Register Values ====
-
- VGA_Segment EQU 0A000H ; Vga Memory Segment
-
- ATTRIB_Ctrl EQU 03C0H ; VGA Attribute Controller
- GC_Index EQU 03CEH ; VGA Graphics Controller
- SC_Index EQU 03C4H ; VGA Sequencer Controller
- SC_Data EQU 03C5H ; VGA Sequencer Data Port
- CRTC_Index EQU 03D4H ; VGA CRT Controller
- CRTC_Data EQU 03D5H ; VGA CRT Controller Data
- MISC_OUTPUT EQU 03C2H ; VGA Misc Register
- INPUT_1 EQU 03DAH ; Input Status #1 Register
-
- DAC_WRITE_ADDR EQU 03C8H ; VGA DAC Write Addr Register
- DAC_READ_ADDR EQU 03C7H ; VGA DAC Read Addr Register
- PEL_DATA_REG EQU 03C9H ; VGA DAC/PEL data Register R/W
-
- MAP_MASK EQU 02 ; Map Register #
- READ_MAP EQU 04 ; Read Map Register #
- MAP_MASK_PLANE1 EQU 0102h ; Map Register + Plane 1
-
- START_DISP_HI EQU 0Ch ; CRTC Index: Display Start Addr Hi
- START_DISP_LO EQU 0Dh ; CRTC Index: Display Start Addr Lo
-
- PLANE_BITS EQU 03h ; Bits 0-1 of Xpos = Plane #
- ALL_PLANES EQU 0Fh ; All Bit Planes Selected
- ALL_PLANES_ON EQU 0F02h ; Map Register + All Bit Planes
- CHAIN4_OFF EQU 0604h ; Chain 4 mode Off
- ASYNC_RESET EQU 0100h ; (A)synchronous Reset
- SEQU_RESTART EQU 0300h ; Sequencer Restart
-
- ; Constants Specific for these routines
-
- NUM_MODES EQU 8 ; # of Mode X Variations
-
- ; Specific Mode Data Table format...
-
- M_MiscR EQU 0 ; Value of MISC_OUTPUT register
- M_Pages EQU 1 ; Maximum Possible # of pages
- M_XSize EQU 2 ; X Size Displayed on screen
- M_YSize EQU 4 ; Y Size Displayed on screen
- M_XMax EQU 6 ; Maximum Possible X Size
- M_YMax EQU 8 ; Maximum Possible Y Size
- M_CRTC EQU 10 ; Table of CRTC register values
-
- ; ==== DGROUP STORAGE NEEDED (36 BYTES) =====
-
- .DATA?
-
- SCREEN_WIDTH DW 0 ; Width of a line in Bytes
- SCREEN_WIDTHx4 DW 0 ; Width of a line in Pixels
- SCREEN_HEIGHT DW 0 ; Veritcal Height in Pixels
-
- LAST_PAGE DW 0 ; # of Display Pages
- PAGE_ADDR DW 0, 0, 0, 0 ; Offsets to start of each page
-
- PAGE_SIZE DW 0 ; Size of Page in Addr Bytes
-
- DISPLAY_PAGE DW 0 ; Page # currently displayed
- ACTIVE_PAGE DW 0 ; Page # currently active
-
- CURRENT_PAGE DW 0 ; Offset of current Page
- CURRENT_SEGMENT DW 0 ; Segment of VGA memory
-
- CURRENT_XOFFSET DW 0 ; Current Display X Offset
- CURRENT_YOFFSET DW 0 ; Current Display Y Offset
-
- CURRENT_MOFFSET DW 0 ; Current Start Offset
-
- MAX_XOFFSET DW 0 ; Current Display X Offset
- MAX_YOFFSET DW 0 ; Current Display Y Offset
-
- .CODE
-
- ; Data Tables, Put in Code Segement for Easy Access
- ; (Like when all the other Segment Registers are in
- ; use!!) and reduced DGROUP requirements...
-
- LEFT_CLIP_MASK DB 0FH, 0EH, 0CH, 08H
-
- RIGHT_CLIP_MASK DB 01H, 03H, 07H, 0FH
-
- MODE_TABLE:
- DW OFFSET MODE_320x200, OFFSET MODE_320x400
- DW OFFSET MODE_360x200, OFFSET MODE_360x400
- DW OFFSET MODE_320x240, OFFSET MODE_320x480
- DW OFFSET MODE_360x240, OFFSET MODE_360x480
-
- MODE_320x200: ; Data for 320 by 200 Pixels
-
- DB 063h ; 400 scan Lines & 25 Mhz Clock
- DB 4 ; Maximum of 4 Pages
- DW 320, 200 ; Displayed Pixels (X,Y)
- DW 1302, 816 ; Max Possible X and Y Sizes
-
- ;CRTC Setup Data....
-
- DW 00014H ; Dword Mode off
- DW 0E317H ; turn on Byte Mode
- DW 00000h ; End of CRTC Data for 320x200
-
- MODE_320x400: ; Data for 320 by 400 Pixels
-
- DB 063h ; 400 scan Lines & 25 Mhz Clock
- DB 2 ; Maximum of 2 Pages
- DW 320, 400 ; Displayed Pixels X,Y
- DW 648, 816 ; Max Possible X and Y Sizes
-
- ;CRTC Setup Data....
-
- DW 04009H ; Cell Heigth (1 Scan Line)
- DW 00014H ; Dword Mode off
- DW 0E317H ; turn on Byte Mode
- DW 00000h ; End of CRTC Data for 320x400
-
- MODE_360x240: ; Data for 360 by 240 Pixels
-
- DB 0E7h ; 480 scan Lines & 28 Mhz Clock
- DB 3 ; Maximum of 3 Pages
- DW 360, 240 ; Displayed Pixels X,Y
- DW 1092, 728 ; Max Possible X and Y Sizes
-
- ;CRTC Setup Data....
-
- DW 06B00H ; Horz total
- DW 05901H ; Horz Displayed
- DW 05A02H ; Start Horz Blanking
- DW 08E03H ; End Horz Blanking
- DW 05E04H ; Start H Sync
- DW 08A05H ; End H Sync
- DW 00D06H ; Vertical Total
- DW 03E07H ; Overflow
- DW 04109H ; Cell Heigth (2 Scan Lines)
- DW 0EA10H ; V Sync Start
- DW 0AC11H ; V Sync End/Prot Cr0 Cr7
- DW 0DF12H ; Vertical Displayed
- DW 00014H ; Dword Mode off
- DW 0E715H ; V Blank Start
- DW 00616H ; V Blank End
- DW 0E317H ; turn on Byte Mode
- DW 00000h ; End of CRTC Data for 360x240
-
- MODE_360x480: ; Data for 360 by 480 Pixels
-
- DB 0E7h ; 480 scan Lines & 28 Mhz Clock
- DB 1 ; Only 1 Page Possible
- DW 360, 480 ; Displayed Pixels X,Y
- DW 544, 728 ; Max Possible X and Y Sizes
-
- ;CRTC Setup Data....
-
- DW 06B00H ; Horz total
- DW 05901H ; Horz Displayed
- DW 05A02H ; Start Horz Blanking
- DW 08E03H ; End Horz Blanking
- DW 05E04H ; Start H Sync
- DW 08A05H ; End H Sync
- DW 00D06H ; Vertical Total
- DW 03E07H ; Overflow
- DW 04009H ; Cell Heigth (1 Scan Line)
- DW 0EA10H ; V Sync Start
- DW 0AC11H ; V Sync End/Prot Cr0 Cr7
- DW 0DF12H ; Vertical Displayed
- DW 00014H ; Dword Mode off
- DW 0E715H ; V Blank Start
- DW 00616H ; V Blank End
- DW 0E317H ; turn on Byte Mode
-
- DW 00000h ; End of CRTC Data for 360x480
-
- MODE_320x240: ; Data for 320 by 240 Pixels
-
- DB 0E3h ; 480 scan Lines & 25 Mhz Clock
- DB 3 ; Maximum of 3 Pages
- DW 320, 240 ; Displayed Pixels X,Y
- DW 1088, 818 ; Max Possible X and Y Sizes
-
- DW 00D06H ; Vertical Total
- DW 03E07H ; Overflow
- DW 04109H ; Cell Heigth (2 Scan Lines)
- DW 0EA10H ; V Sync Start
- DW 0AC11H ; V Sync End/Prot Cr0 Cr7
- DW 0DF12H ; Vertical Displayed
- DW 00014H ; Dword Mode off
- DW 0E715H ; V Blank Start
- DW 00616H ; V Blank End
- DW 0E317H ; turn on Byte Mode
-
- DW 00000h ; End of CRTC Data for 320x240
-
- MODE_320x480: ; Data for 320 by 480 Pixels
-
- DB 0E3h ; 480 scan Lines & 25 Mhz Clock
- DB 1 ; Only 1 Page Possible
- DW 320, 480 ; Displayed Pixels X,Y
- DW 540, 818 ; Max Possible X and Y Sizes
-
- DW 00D06H ; Vertical Total
- DW 03E07H ; Overflow
- DW 04009H ; Cell Heigth (1 Scan Line)
- DW 0EA10H ; V Sync Start
- DW 0AC11H ; V Sync End/Prot Cr0 Cr7
- DW 0DF12H ; Vertical Displayed
- DW 00014H ; Dword Mode off
- DW 0E715H ; V Blank Start
- DW 00616H ; V Blank End
- DW 0E317H ; turn on Byte Mode
-
- DW 00000h ; End of CRTC Data for 320x480
-
- MODE_360x200: ; Data for 360 by 200 Pixels
-
- DB 067h ; 400 scan Lines & 28 Mhz Clock
- DB 3 ; Maximum of 3 Pages
- DW 360, 200 ; Displayed Pixels (X,Y)
- DW 1302, 728 ; Max Possible X and Y Sizes
-
- ;CRTC Setup Data....
-
- DW 06B00H ; Horz total
- DW 05901H ; Horz Displayed
- DW 05A02H ; Start Horz Blanking
- DW 08E03H ; End Horz Blanking
- DW 05E04H ; Start H Sync
- DW 08A05H ; End H Sync
- DW 00014H ; Dword Mode off
- DW 0E317H ; turn on Byte Mode
- DW 00000h ; End of CRTC Data for 360x200
-
- MODE_360x400: ; Data for 360 by 400 Pixels
-
- DB 067h ; 400 scan Lines & 28 Mhz Clock
- DB 1 ; Maximum of 1 Pages
- DW 360, 400 ; Displayed Pixels X,Y
- DW 648, 816 ; Max Possible X and Y Sizes
-
- ;CRTC Setup Data....
-
- DW 06B00H ; Horz total
- DW 05901H ; Horz Displayed
- DW 05A02H ; Start Horz Blanking
- DW 08E03H ; End Horz Blanking
- DW 05E04H ; Start H Sync
- DW 08A05H ; End H Sync
- DW 04009H ; Cell Heigth (1 Scan Line)
- DW 00014H ; Dword Mode off
- DW 0E317H ; turn on Byte Mode
- DW 00000h ; End of CRTC Data for 360x400
-
-
- ; ===== ACTUAL ASSEMBLY CODE =====
-
- ;======================================================
- ;SET_VGA_MODEX%(ModeType%, MaxXPos%, MaxYpos%, Pages%)
- ;======================================================
- ;
- ; Sets Up the specified version of Mode X. Allows for
- ; the setup of multiple video pages, and a virtual
- ; screen which can be larger than the displayed screen
- ; (which can then be scrolled a pixel at a time)
- ;
- ; INPUT PARAMETERS:
- ;
- ; ModeType% - The Desired Version of 256 Color Mode X
- ;
- ; 0 = 320 x 200, 4 Pages max, 1.2:1 Aspect Ratio
- ; 1 = 320 x 400, 2 Pages max, 2.4:1 Aspect Ratio
- ; 2 = 360 x 200, 3 Pages max, 1.35:1 Aspect Ratio
- ; 3 = 360 x 400, 1 Page max, 2.7:1 Aspect Ratio
- ; 4 = 320 x 240, 3 Pages max, 1:1 Aspect Ratio
- ; 5 = 320 x 480, 1 Page max, 2:1 Aspect Ratio
- ; 6 = 360 x 240, 3 Pages max, 1.125:1 Aspect Ratio
- ; 7 = 360 x 480, 1 Page max, 2.25:1 Aspect Ratio
- ;
- ; MaxXpos = The Desired Virtual Screen Width
- ; MaxYpos = The Desired Virtual Screen Height
- ; Pages% = The Desired # of Video Pages
- ;
- ; RETURNS in AX: 0 (= Failure) or ffff (= Success)
- ;
-
- SVM_STACK STRUC
- DW ?,?,?,? ;DI,SI,DS,BP
- DD ? ;Caller
- SVM_Pages DW ?
- SVM_Ysize DW ?
- SVM_Xsize DW ?
- SVM_Mode DW ?
- SVM_STACK ENDS
-
- PUBLIC SET_VGA_MODEX
-
- SET_VGA_MODEX PROC FAR
-
- PUSH BP ; Preserve Important
- PUSH DS ; Register Values
- PUSH SI
- PUSH DI
-
- MOV BP,SP ; Set up Stack Frame
-
- ;Check Legality of Mode Request....
-
- MOV BX, [BP].SVM_Mode ; Get Requested Mode #
- CMP BX, NUM_MODES ; Is it 0..7?
- JAE SVM_BadModeSetup ; If Not, Error out
-
- SHL BX, 1 ; Scale BX
- MOV SI, w CS:MODE_TABLE[BX] ; CS:SI -> Mode Info
- PUSH SI ; Save for later use
-
- ;Check # of Requested Display Pages
-
- MOV CX, [Bp].SVM_Pages ; Get # of Requested Pages
- CMP CX, CS:[SI].M_Pages ; Check # Pages for mode
- JA SVM_BadModeSetup ; Report Error if too Many
- OR CX, CX ; # Pages = 0?
- JE SVM_BadModeSetup ; Report Error if 0
-
- ;Check Validity of X Size
-
- AND [BP].SVM_XSize, 0FFF8h ;X size Mod 8 Must = 0
-
- MOV AX, [BP].SVM_XSize ; Get Logical Screen Width
- CMP AX, CS:[SI].M_XSize ; Check against Displayed X
- JB SVM_BadModeSetup ; Report Error if too small
- CMP AX, CS:[SI].M_XMax ; Check against Max X
- JA SVM_BadModeSetup ; Report Error if too big
-
- ;Check Validity of Y Size
-
- MOV BX, [BP].SVM_YSize ; Get Logical Screen Height
- CMP BX, CS:[SI].M_YSize ; Check against Displayed Y
- JB SVM_BadModeSetup ; Report Error if too small
- CMP BX, CS:[SI].M_YMax ; Check against Max Y
- JA SVM_BadModeSetup ; Report Error if too big
-
- ;Enough memory to Fit it all?
-
- SHR AX, 2 ;# of Bytes:Line = XSize/4
- MUL BX ;# Bytes/Page = AX/4 * BX
- JO SVM_BadModeSetup ;Exit if Page Size > 256K
-
- MUL CX ;Total Mem = PageSize * Pages
- JNO SVM_Continue ;Exit if Total Size > 256K
-
- SVM_BadModeSetup:
-
- XOR AX, AX ; Return Value = False
- JMP SVM_Exit ; Normal Exit
-
- SVM_Continue:
-
- MOV AX, 13H ; Start with Mode 13H
- INT 10H ; Let BIOS Set Mode
-
- OUT_16 SC_INDEX, CHAIN4_OFF ; Disable Chain 4 Mode
- OUT_16 SC_INDEX, ASYNC_RESET ; (A)synchronous Reset
-
- MOV DX, MISC_OUTPUT ; VGA Misc Register
- MOV AL, CS:[SI].M_MiscR ; Get New Timing/Size Value
- OUT DX, AL ; Set VGA Misc Register
-
- OUT_16 SC_INDEX, SEQU_RESTART ; Restart Sequencer ...
-
- MOV DX, CRTC_INDEX ; Vga crtc Registers
- MOV AL, 11H ; Vert Retrace End Register
- OUT DX, AL ; Load Current Value
- INC DX ; Point to Data
- IN AL, DX ; Get Value, Bit 7 = Protect
- AND AL, 7FH ; Mask out Write Protect
- OUT DX, AL ; And send it back
-
- MOV DX, CRTC_INDEX ; Vga Crtc Registers
- ADD SI, M_CRTC ; SI -> CRTC Parameter Data
-
- SVM_Setup_CRTC:
-
- MOV AX, CS:[SI] ; Get CRTC Data from Table
- ADD SI, 2 ; Advance Pointer
- OR AX, AX ; At End of Data Table?
- JZ SVM_Set_Data ; If so, Exit Loop
-
- OUT DX, AX ; Reprogram VGA CRTC reg
- JMP SVM_Setup_CRTC ; Process Next Table Entry
-
- SVM_Set_Data:
-
- XOR AX, AX ; AX = 0
- MOV DISPLAY_PAGE, AX ; Display Page = 0
- MOV ACTIVE_PAGE, AX ; Active Page = 0
- MOV CURRENT_PAGE, AX ; Current Page (Offset) = 0
- MOV CURRENT_XOFFSET, AX ; Horz Scroll Index = 0
- MOV CURRENT_YOFFSET, AX ; Vert Scroll Index = 0
- MOV CURRENT_MOFFSET, AX ; Memory Scroll Index = 0
-
- MOV AX, VGA_SEGMENT ; Segment for VGA memory
- MOV CURRENT_SEGMENT, AX ; Save for Future LES's
-
- ;Set Logical Screen Width, X Scroll and Our Data
-
- POP SI ; Get Saved Ptr to Mode Info
- MOV AX, [Bp].SVM_Xsize ; Get Display Width
-
- MOV CX, AX ; CX = Logical Width
- SUB CX, CS:[SI].M_XSize ; CX = Max X Scroll Value
- MOV MAX_XOFFSET, CX ; Set Maximum X Scroll
-
- MOV SCREEN_WIDTHx4, AX ; Save Width in Pixels
- SHR AX, 2 ; Bytes = Pixels / 4
- MOV SCREEN_WIDTH, AX ; Save Width in Pixels
-
- SHR AX, 1 ; Offset Value = Bytes / 2
- MOV AH, 13h ; CRTC Offset Register Index
- XCHG AL, AH ; Switch format for OUT
- OUT DX, AX ; Set VGA CRTC Offset Reg
-
- ;Setup Data table, Y Scroll, Misc for Other Routines
-
- MOV AX, [Bp].SVM_Ysize ; Get Logical Screen Hieght
-
- MOV CX, AX ; CX = Logical Height
- SUB BX, CS:[SI].M_YSize ; CX = Max Y Scroll Value
- MOV MAX_YOFFSET, CX ; Set Maximum Y Scroll
-
- MOV SCREEN_HEIGHT, AX ; Save Hight in Pixels
- MUL SCREEN_WIDTH ; AX = Page Size in Bytes,
- MOV PAGE_SIZE, AX ; Save Page Size
-
- MOV CX, [Bp].SVM_Pages ; Get # of Pages
- MOV LAST_PAGE, CX ; Save # of Pages
-
- MOV BX, 0 ; Page # = 0
- MOV DX, BX ; Page 0 Offset = 0
-
- SVM_Set_Pages:
-
- MOV PAGE_ADDR[BX], DX ; Set Page #(BX) Offset
- ADD BX, 2 ; Page#++
- ADD DX, AX ; Compute Addr of Next Page
- LOOP SVM_Set_Pages ; Loop until Done
-
- ;Clear VGA Memory
-
- OUT_16 SC_INDEX, ALL_PLANES_ON ; Select All Planes
- LES DI, d CURRENT_PAGE ; Point to Start of VGA memory
-
- XOR AX, AX ; AX = 0
- CLD ; Block Xfer Forwards
- MOV CX, 8000H ; 32K * 4 * 2 = 256K
- REP STOSW ; Clear dat memory!
-
- MOV AX, True ; Return Success Code
-
- SVM_EXIT:
-
- POP DI ; Restore Saved Registers
- POP SI
- POP DS
- POP BP
-
- RET 8 ;We are Done.. Outa here
-
- SET_VGA_MODEX ENDP
-
-
- ;==================
- ;SET_MODEX% (Mode%)
- ;==================
- ;
- ; Quickie Mode Set - Sets Up Mode X to Default Configuration
- ;
- ; INPUT PARAMETERS:
- ;
- ; ModeType% - The Desired Version of 256 Color Mode X
- ;
- ; (0 to 7 - See Chart under SET_VGA_MODEX)
- ;
- ; RETURNS in AX: 0 (= Failure) or ffff (= Success)
- ;
-
- SM_STACK STRUC
- DW ? ;BP
- DD ? ;Caller
- SM_Mode DW ?
- SM_STACK ENDS
-
- PUBLIC SET_MODEX
-
- SET_MODEX PROC FAR
-
- PUSH BP ; Preserve Important
- MOV BP,SP ; Set up Stack Frame
-
- XOR AX, AX ; Assume Failure
- MOV BX, [BP].SM_Mode ; Get Desired Mode #
-
- CMP BX, NUM_MODES ; Is it 0..7?
- JAE @SX_Exit ; If Not, don't Bother
-
- PUSH BX ; Push Mode Parameter
-
- SHL BX, 1 ; Scale BX
- MOV SI, w CS:MODE_TABLE[BX] ;CS:SI -> Mode Info
-
- MOV AX, CS:[SI].M_XSize ; Get Default X Size
- PUSH AX ; Push X Size Parameter
-
- MOV AX, CS:[SI].M_Ysize ; Get Default Y size
- PUSH AX ; Push Y Size Parameter
-
- MOV AL, CS:[SI].M_Pages ; Get Default # of Pages
- MOV AH, 0 ; Hi Byte = 0
- PUSH AX ; Push # Pages
-
- CALL FAR PTR SET_VGA_MODEX ; Set up Mode X!
-
- @SX_Exit:
-
- POP BP ; Restore Register
- RET 2 ; We are Done.. Outa here
-
- SET_MODEX ENDP
-
-
- ;============================
- ;CLEAR_VGA_SCREEN (ColorNum%)
- ;============================
- ;
- ; Clears the currently active display page to
- ; all the color #ColorNum
- ;
-
- CVS_STACK STRUC
- DW ?,? ;DI, BP
- DD ? ;Caller
- CVS_COLOR DB ?,? ;Color to Set Screen to
- CVS_STACK ENDS
-
- PUBLIC CLEAR_VGA_SCREEN
-
- CLEAR_VGA_SCREEN PROC FAR
-
- PUSH BP ; Preserve Registers
- PUSH DI
-
- MOV BP, SP ; Set up Stack Frame
-
- OUT_16 SC_INDEX, ALL_PLANES_ON ; Select All Planes
- LES DI, d CURRENT_PAGE ; Point to Active VGA Page
-
- MOV AL, [BP].CVS_COLOR ; Get Color
- MOV AH, AL ; Copy for Word Write
- CLD ; Block fill Forwards
-
- MOV CX, PAGE_SIZE ; Get Size of Page
- SHR CX, 1 ; Divied by 2 for Words
- REP STOSW ; Block Fill VGA memory
-
- POP DI ; Restore Saved Registers
- POP BP
-
- RET 2 ;We are Done.. Outa here
-
- CLEAR_VGA_SCREEN ENDP
-
-
- ;===================================
- ;SET_POINT (Xpos%, Ypos%, ColorNum%)
- ;===================================
- ;
- ; Sets a single Pixel at (Xpos, Ypos) on the active
- ; Display Page to color #ColorNum
- ;
-
- SP_STACK STRUC
- DW ? ;BP
- DD ? ;Caller
- SETP_Color DB ?,?
- SETP_Ypos DW ?
- SETP_Xpos DW ?
- SP_STACK ENDS
-
- PUBLIC SET_POINT
-
- SET_POINT PROC FAR
-
- PUSH BP ; Preserve Registers
- MOV BP, SP ; Set up Stack Frame
-
- LES DI, d CURRENT_PAGE ; Point to Active VGA Page
-
- MOV AX, [BP].SETP_Ypos ; Get Line # of Pixel
- MUL SCREEN_WIDTH ; Get Offset to Start of Line
-
- MOV BX, [BP].SETP_Xpos ; Get Xpos
- MOV CX, BX
- SHR BX, 2 ; X offset (Bytes) = Xpos/4
- ADD BX, AX ; Offset = Width*Ypos + Xpos/4
-
- MOV AX, MAP_MASK_PLANE1 ; Map Mask & Plane Select Register
- AND CL, PLANE_BITS ; Get Plane Bits
- SHL AH, CL ; Get Plane Select Value
- MOV DX, SC_Index ; Setup to select plane
- OUT DX, AX ; Select Plane...
-
- MOV AL,[BP].SETP_Color ; Get Pixel Color
- MOV ES:[DI+BX], AL ; Draw Pixel
-
- POP BP ; Restore Saved Registers
- RET 6 ; Exit and Clean up Stack
-
- SET_POINT ENDP
-
-
- ;==========================
- ;READ_POINT% (Xpos%, Ypos%)
- ;==========================
- ;
- ; Returns the color of a pixel from the Active Display Page
- ;
- ; RETURNS: AX = Color of Pixel at (Xpos, Ypos)
- ;
-
- RP_STACK STRUC
- DW ? ;Bp
- DD ? ;Caller
- RP_Ypos DW ?
- RP_Xpos DW ?
- RP_STACK ENDS
-
- PUBLIC READ_POINT
-
- READ_POINT PROC FAR
-
- PUSH BP ; Preserve Registers
- MOV BP, SP ; Set up Stack Frame
-
- LES DI, d CURRENT_PAGE ; Point to Active VGA Page
-
- MOV AX, [Bp].RP_Ypos ; Get Line # of Pixel
- MUL SCREEN_WIDTH ; Get Offset to Start of Line
-
- MOV BX, [BP].RP_Xpos ; Get Xpos
- MOV CX, BX
- SHR BX, 2 ; X offset (Bytes) = Xpos/4
- ADD BX, AX ; Offset = Width*Ypos + Xpos/4
-
- MOV AL, READ_MAP ; GC Read Mask Register
- MOV AH, CL ; Get Xpos
- AND AH, PLANE_BITS ; & mask out Plane #
- MOV DX, GC_INDEX ; Setup to select Read Mask
- OUT DX, AX ; Select Read Plane...
-
- XOR AX, AX ; Clear Return Value
-
- MOV AL, ES:[DI+BX] ; Get Color of Pixel
-
- POP BP ; Restore Saved Registers
- RET 4 ; Exit and Clean up Stack
-
- READ_POINT ENDP
-
-
- ;======================================================
- ;FILL_BLOCK (Xpos1%, Ypos1%, Xpos2%, Ypos2%, ColorNum%)
- ;======================================================
- ;
- ; Fills a block on the current display Page from Point
- ; (Xpos1, Ypos1) to Point (Xpos2, Ypos2) in Color #ColorNum
- ;
-
- FB_STACK STRUC
- DW ?,?,?,? ; DS, DI, SI, BP
- DD ? ; Caller
- FB_Color DB ?,? ; Fill Color
- FB_Ypos2 DW ? ; Lower Right Pixel
- FB_Xpos2 DW ? ;
- FB_Ypos1 DW ? ; Upper Left Pixel
- FB_Xpos1 DW ? ;
- FB_STACK ENDS
-
- PUBLIC FILL_BLOCK
-
- FILL_BLOCK PROC FAR
-
- PUSH BP ; Save Registers
- PUSH SI
- PUSH DI
- PUSH DS
-
- MOV BP, SP ; Set up Stack Frame
-
- LES DI, d CURRENT_PAGE ; Point to Active VGA Page
- CLD ; Direction Flag = Forward
-
- OUT_8 SC_INDEX, MAP_MASK ; Set up for Plane Select
-
- ; Validate Pixel Coordinates
- ; If necessary, Swap so X1 <= X2, Y1 <= Y2
-
- MOV AX, [BP].FB_Ypos1 ; AX = Y1 is Y1< Y2?
- MOV BX, [BP].FB_Ypos2 ; BX = Y2
- CMP AX, BX
- JLE @FB_NOSWAP1
-
- MOV [BP].FB_Ypos1, BX ; Swap Y1 and Y2 and save Y1
- XCHG AX, BX ; on stack for future use
-
- @FB_NOSWAP1:
- SUB BX, AX ; Get Y width
- INC BX ; Add 1 to avoid 0 value
- MOV [BP].FB_Ypos2, BX ; Save in Ypos2
-
- MUL SCREEN_WIDTH ; Mul Y1 by Bytes per Line
- ADD DI, AX ; DI = Start of Line Y1
-
- MOV AX, [BP].FB_Xpos1 ; Check X1 <= X2
- MOV BX, [BP].FB_Xpos2 ;
- CMP AX, BX
- JLE @FB_NOSWAP2 ; Skip Ahead if Ok
-
- MOV [BP].FB_Xpos2, AX ; Swap X1 AND X2 and save X2
- XCHG AX, BX ; on stack for future use
-
- ; All our Input Values are in order, Now determine
- ; How many full "bands" 4 pixels wide (aligned) there
- ; are, and if there are partial bands (<4 pixels) on
- ; the left and right edges.
-
- @FB_NOSWAP2:
- MOV DX, AX ; DX = X1 (Pixel Position)
- SHR DX, 2 ; DX/4 = Bytes into Line
- ADD DI, DX ; DI = Addr of Upper-Left Corner
-
- MOV CX, BX ; CX = X2 (Pixel Position)
- SHR CX, 2 ; CX/4 = Bytes into Line
-
- CMP DX, CX ; Start and end in same band?
- JNE @FB_NORMAL ; if not, check for l & r edges
- JMP @FB_ONE_BAND_ONLY ; if so, then special processing
-
- @FB_NORMAL:
- SUB CX, DX ; CX = # bands -1
- MOV SI, AX ; SI = PLANE#(X1)
- AND SI, PLANE_BITS ; if Left edge is aligned then ..
- JZ @FB_LEFT_PLANE_FLUSH ; no special processing..
-
- ; Draw "Left Edge" vertical strip of 1-3 pixels...
-
- OUT_8 SC_Data, LEFT_CLIP_MASK[SI] ; Set Left Edge Plane Mask
-
- MOV SI, DI ; SI = Copy of Start Addr (UL)
-
- MOV DX, [BP].FB_Ypos2 ; Get # of Lines to draw
- MOV AL, [BP].FB_Color ; Get Fill Color
- MOV BX, SCREEN_WIDTH ; Get Vertical increment Value
-
- @FB_LEFT_LOOP:
- MOV ES:[SI], AL ; Fill in Left Edge Pixels
- ADD SI, BX ; Point to Next Line (Below)
- DEC DX ; Lines to go--
- JZ @FB_LEFT_CONT ; Exit loop if all Lines Drawn
-
- MOV ES:[SI], AL ; Fill in Left Edge Pixels
- ADD SI, BX ; Point to Next Line (Below)
- DEC DX ; Lines to go--
- JNZ @FB_LEFT_LOOP ; loop until left strip is drawn
-
- @FB_LEFT_CONT:
-
- INC DI ; Point to Middle (or Right) Block
- DEC CX ; Reset CX insted of JMP @FB_RIGHT
-
- @FB_LEFT_PLANE_FLUSH:
- INC CX ; Add in Left band to middle block
-
- ;DI = Addr of 1st middle Pixel (band) to fill
- ;CX = # of Bands to fill -1
-
- @FB_RIGHT:
- MOV SI, [BP].FB_Xpos2 ; Get Xpos2
- AND SI, PLANE_BITS ; Get Plane values
- CMP SI, 0003 ; Plane = 3?
- JE @FB_RIGHT_EDGE_FLUSH ; Hey, add to middle
-
- ; Draw "Right Edge" vertical strip of 1-3 pixels...
-
- OUT_8 SC_Data, RIGHT_CLIP_MASK[SI] ; Set Right Edge Plane Mask
-
- MOV SI, DI ; Get Addr of Left Edge
- ADD SI, CX ; Add Width-1 (Bands)
- DEC SI ; To point to top of Right Edge
-
- MOV DX, [BP].FB_Ypos2 ; Get # of Lines to draw
- MOV AL, [BP].FB_Color ; Get Fill Color
- MOV BX, SCREEN_WIDTH ; Get Vertical increment Value
-
- @FB_RIGHT_LOOP:
- MOV ES:[SI], AL ; Fill in Right Edge Pixels
- ADD SI, BX ; Point to Next Line (Below)
- DEC DX ; Lines to go--
- JZ @FB_RIGHT_CONT ; Exit loop if all Lines Drawn
-
- MOV ES:[SI], AL ; Fill in Right Edge Pixels
- ADD SI, BX ; Point to Next Line (Below)
- DEC DX ; Lines to go--
- JNZ @FB_RIGHT_LOOP ; loop until left strip is drawn
-
- @FB_RIGHT_CONT:
-
- DEC CX ; Minus 1 for Middle bands
- JCXZ @FB_EXIT ; Uh.. no Middle bands...
-
- @FB_RIGHT_EDGE_FLUSH:
-
- ;DI = Addr of Upper Left block to fill
- ;CX = # of Bands to fill in (width)
-
- OUT_8 SC_Data, 0FH ; Write to All Planes
-
- MOV DX, SCREEN_WIDTH ; DX = DI Incrament
- SUB DX, CX ; = Screen_Width-# Planes Filled
-
- MOV BX, CX ; BX = Quick Refill for CX
- MOV SI, [BP].FB_Ypos2 ; SI = # of Line to Fill
- MOV AL, [BP].FB_Color ; Get Fill Color
-
- @FB_MIDDLE_LOOP:
- REP STOSB ; Fill in entire line
-
- MOV CX, BX ; Recharge CX (Line Width)
- ADD DI, DX ; Point to start of Next Line
-
- DEC SI ; Lines to go--
- JNZ @FB_MIDDLE_LOOP ; Loop until all lines drawn
-
- JMP @FB_EXIT ; Outa here
-
- @FB_ONE_BAND_ONLY:
- MOV SI, AX ; Get Left CLip Mask, Save X1
- AND SI, PLANE_BITS ; Mask out Row #
- MOV AL, LEFT_CLIP_MASK[SI] ; Get Left Edge Mask
- MOV SI, BX ; Get Right Clip Mask, Save X2
- AND SI, PLANE_BITS ; Mask out Row #
- AND AL, RIGHT_CLIP_MASK[SI] ; Get Right Edge Mask byte
-
- MOV DX, SC_Data ; Plane Selection
- OUT DX, AL ; Clip For Left & Right Masks
-
- MOV CX, [BP].FB_Ypos2 ; Get # of Lines to draw
- MOV AL, [BP].FB_Color ; Get Fill Color
- MOV BX, SCREEN_WIDTH ; Get Vertical increment Value
-
- @FB_ONE_LOOP:
- MOV ES:[DI], AL ; Fill in Pixels
- ADD DI, BX ; Point to Next Line (Below)
- DEC CX ; Lines to go--
- JZ @FB_EXIT ; Exit loop if all Lines Drawn
-
- MOV ES:[DI], AL ; Fill in Pixels
- ADD DI, BX ; Point to Next Line (Below)
- DEC CX ; Lines to go--
- JNZ @FB_ONE_LOOP ; loop until left strip is drawn
-
- @FB_EXIT:
- POP DS
- POP DI
- POP SI
- POP BP ; Restore Registers
-
- RET 10 ; Exit and Clean up Stack
-
- FILL_BLOCK ENDP
-
-
- ;=====================================================
- ;DRAW_LINE (Xpos1%, Ypos1%, Xpos2%, Ypos2%, ColorNum%)
- ;=====================================================
- ;
- ; Draws a Line from (X1,Y1) to (X2,Y2) in Color #ColorNum
- ; in VGA Mode X
- ;
-
- DL_STACK STRUC
- DW ?,?,? ;DI, SI , BP
- DD ? ;Caller
- DL_ColorF DB ?,?
- DL_Ypos2 DW ?
- DL_Xpos2 DW ?
- DL_Ypos1 DW ?
- DL_Xpos1 DW ?
- DL_STACK ENDS
-
- PUBLIC DRAW_LINE
-
- DRAW_LINE PROC FAR
-
- PUSH BP ; Save Registers
- PUSH SI
- PUSH DI
-
- MOV BP, SP ; Set up Stack Frame
- CLD ; Direction Flag = Forward
-
- OUT_8 SC_INDEX, MAP_MASK ; Set up for Plane Select
-
- MOV CH, [BP].DL_ColorF ; Save Color in CH
-
- ;Check Line Type
-
- MOV SI, [BP].DL_Xpos1 ; AX = X1 is X1< X2?
- MOV DI, [BP].DL_Xpos2 ; DX = X2
- CMP SI, DI ; Is X1 < X2
- JE @DL_VLINE ; If X1=X2, Draw Vertical Line
- JL @DL_NOSWAP1 ; If X1 < X2, don't swap
-
- XCHG SI, DI ; X2 IS > X1, SO SWAP THEM
-
- @DL_NOSWAP1:
-
- ; SI = X1, DI = X2
-
- MOV AX, [BP].DL_Ypos1 ; AX = Y1 is Y1 <> Y2?
- CMP AX, [BP].DL_Ypos2 ; Y1 = Y2?
- JE @DL_HORZ ; If so, Draw a Horizontal Line
-
- JMP @DL_BREZHAM ; Diagonal line... go do it...
-
- ; This Code draws a Horizontal Line in Mode X where:
- ; SI = X1, DI = X2, and AX = Y1/Y2
-
- @DL_HORZ:
-
- MUL SCREEN_WIDTH ; Offset = Ypos * Screen_Width
- MOV DX, AX ; CX = Line offste into Page
-
- MOV AX, SI ; Get Left Edge CLip Mask, Save X1
- AND SI, PLANE_BITS ; Mask out Row #
- MOV BL, LEFT_CLIP_MASK[SI] ; Get Left Edge Mask
- MOV CX, DI ; Get Right Edge Clip Mask, Save X2
- AND DI, PLANE_BITS ; Mask out Row #
- MOV BH, RIGHT_CLIP_MASK[DI] ; Get Right Edge Mask byte
-
- SHR AX, 2 ; Get X1 Byte # (=X1/4)
- SHR CX, 2 ; Get X2 Byte # (=X2/4)
-
- LES DI, d CURRENT_PAGE ; Point to Active VGA Page
- ADD DI, DX ; Point to Start of Line
- ADD DI, AX ; Point to Pixel X1
-
- SUB CX, AX ; CX = # Of Bands (-1) to set
- JNZ @DL_LONGLN ; If longer than one segment, go ahead
-
- AND BL, BH ; otherwise, megre clip masks
-
- @DL_LONGLN:
-
- OUT_8 SC_Data, BL ; Set the Left Clip Mask
-
- MOV AL, [BP].DL_ColorF ; Get Line Color
- MOV BL, AL ; BL = Copy of Line Color
- STOSB ; Set Left (1-4) Pixels
-
- JCXZ @DL_EXIT ; Done if only one Line Segment
-
- DEC CX ; CX = # of Middle Segemnts
- JZ @DL_XRSEG ; If no middle segments....
-
- ;Draw Middle Segments
-
- MOV AL, ALL_PLANES ; Write to ALL Planes
- OUT DX, AL ; Select Planes
-
- MOV AL, BL ; Get Color from BL
- REP STOSB ; Draw Middle (4 Pixel) Segements
-
- @DL_XRSEG:
- MOV AL, BH ; Get Right Clip Mask
- OUT DX, AL ; Select Planes
-
- MOV AL, BL ; Get Color Value
- STOSB ; Draw Right (1-4) Pixels
-
- JMP SHORT @DL_EXIT ; We Are Done...
-
- ; This Code Draws A Vertical Line. On entry:
- ; CH = Line Color, SI & DI = X1
-
- @DL_VLINE:
-
- MOV AX, [BP].DL_Ypos1 ; AX = Y1
- MOV SI, [BP].DL_Ypos2 ; SI = Y2
- CMP AX, SI ; Is Y1 < Y2?
- JLE @DL_NOSWAP2 ; if so, Don't Swap them
-
- XCHG AX, SI ; Ok, NOW Y1 < Y2
-
- @DL_NOSWAP2:
-
- SUB SI, AX ; SI = Line Heigth (Y2-Y1+1)
- INC SI
-
- ; AX = Y1, DI = X1, Get offset into Page into AX
-
- MUL SCREEN_WIDTH ; Offset = Y1 (AX) * Screen Width
- MOV DX, DI ; Copy Xpos into DX
- SHR DI, 2 ; DI = Xpos/4
- ADD AX, DI ; DI = Xpos/4 + ScreenWidth * Y1
-
- LES DI, d CURRENT_PAGE ; Point to Active VGA Page
- ADD DI, AX ; Point to Pixel X1, Y1
-
- ;Select Plane
-
- MOV CL, DL ; CL = Save X1
- AND CL, PLANE_BITS ; Get X1 MOD 4 (Plane #)
- MOV AX, MAP_MASK_PLANE1 ; Code to set Plane #1
- SHL AH, CL ; Change to Correct Plane #
-
- MOV DX, SC_Index ; Set VGA Sequencer
- OUT DX, AX ; Select Plane!
-
- MOV AL, CH ; Get Saved Color
- MOV BX, SCREEN_WIDTH ; Get Offset to Advance Line By
-
- @DL_VLoop:
- MOV ES:[DI], AL ; Draw Single Pixel
- ADD DI, BX ; Point to Next Line
-
- DEC SI ; Lines to draw--
- JNZ @DL_VLoop ; Loop until Done
-
- @DL_EXIT:
-
- JMP @DL_EXIT2 ; Done!
-
- ; This code Draws a diagonal line in Mode X
-
- @DL_BREZHAM:
- LES DI, d CURRENT_PAGE ; Point to Active VGA Page
-
- MOV AX, [BP].DL_Ypos1 ; get y1 value
- MOV BX, [BP].DL_Ypos2 ; get y2 value
- MOV CX, [BP].DL_Xpos1 ; Get Starting Xpos
-
- CMP BX, AX ; Y2-Y1 is?
- JNC @DL_DeltaYOK ; if Y2>=Y1 then goto...
-
- XCHG BX, AX ; Swap em...
- MOV CX, [BP].DL_Xpos2 ; Get New Starting Xpos
-
- @DL_DeltaYOK:
- MUL SCREEN_WIDTH ; Offset = SCREEN_WIDTH * Y1
-
- ADD DI, AX ; DI -> Start of Line Y1 on Page
- MOV AX, CX ; AX = Xpos (X1)
- SHR AX, 2 ; /4 = Byte Offset into Line
- ADD DI, AX ; DI = Starting pos (X1,Y1)
-
- MOV AL, 11h ; Staring Mask
- AND CL, PLANE_BITS ; Get Plane #
- SHL AL, CL ; and shift into placE
- MOV AH, [BP].DL_ColorF ; Color in Hi Bytes
-
- PUSH AX ; Save Mask,Color...
-
- MOV DX, SC_Index
- MOV AH, AL ; Plane # in AH
- MOV AL, MAP_MASK ; Select Plane Register
- OUT DX, AX ; Select initial plane
-
- MOV AX, [BP].DL_Xpos1 ; get x1 value
- MOV BX, [BP].DL_Ypos1 ; get y1 value
- MOV CX, [BP].DL_Xpos2 ; get x2 value
- MOV DX, [BP].DL_Ypos2 ; get y2 value
-
- MOV BP, SCREEN_WIDTH ; Use BP for Line width to
- ; to avoid extra memory access
-
- SUB DX, BX ; figure delta_y
- JNC @DL_DeltaYOK2 ; jump if y2>=y1
-
- ADD BX, DX ; put y2 into y1
- NEG DX ; abs(Delta_y)
- XCHG AX, CX ; and exchange x1 and x2
-
- @DL_DeltaYOK2:
- MOV BX, 08000H ; seed for fraction accumulator
-
- SUB CX, AX ; figure delta_x
- JC @DL_DrawLeft ; if negitive, go left
-
- JMP @DL_DrawRight ; Draw Line that slopes right
-
- @DL_DrawLeft:
-
- NEG CX ; abs(Delta_X)
-
- CMP CX, DX ; is X < Delta_Y?
- JB @DL_SteepLeft ; yes, so go do steep line (Delta_Y iterations)
-
- ; Draw a Shallow line to the left in Mode X
-
- @DL_ShallowLeft:
- XOR AX, AX ; zero low word of Delta_y * 10000h
- SUB AX, DX ; DX:AX <- DX * 0FFFFh
- SBB DX, 0
- DIV CX ; divide by Delta_X
-
- MOV SI, BX ; Si = Acculmulator
- MOV BX, AX ; Bx = Addor
- POP AX ; Get Color, Bit mask
- MOV DX, SC_Data ; Sequence controller data register
- INC CX ; Inc Delta_X so we can unroll loop
-
- ; Loop (x2) to Draw Pixels, Move Left, and Maybe Down...
-
- @DL_SLLLoop:
- MOV ES:[DI], AH ; set first pixel, plane data set up
-
- DEC CX ; count down Delta_X
- JZ @DL_SLLExit ; Exit if done..
-
- ADD SI, BX ; add numerator to accumulator
- JNC @DL_SLLL2nc ; move down on carry
-
- ADD DI, BP ; Move Down one line...
-
- @DL_SLLL2nc:
- DEC DI ; Left one addr
- ROR AL, 1 ; Move Left one plane
- CMP AL, 87h ; Skipped around?, if AL <88 then Carry set
- ADC DI, 0 ; Adjust Address: DI = Di + Carry, ie. plane =
- OUT DX, AL ; Set up New Bit Plane mask
-
- MOV ES:[DI], AH ; set pixel
-
- ADD SI, BX ; add numerator to accumulator,
- JNC @DL_SLLL3nc ; move down on carry
-
- ADD DI, BP ; Move Down one line...
-
- @DL_SLLL3nc: ; Now move left a pixel...
- DEC DI ; Left one addr
- ROR AL, 1 ; Move Left one plane
- CMP AL, 87h ; Skipped around?, if AL <88 then Carry set
- ADC DI, 0 ; Adjust Address: DI = Di + Carry, ie. plane =
- OUT DX, AL ; Set up New Bit Plane mask
-
- DEC CX ; count down Delta_X
- JNZ @DL_SLLLoop ; loop till done
-
- @DL_SLLExit:
- JMP @DL_EXIT2 ; and exit
-
- ; Draw a steep line to the left in Mode X
-
- @DL_SteepLeft:
- XOR AX, AX ; zero low word of Delta_y * 10000h
- XCHG DX, CX ; Delta_Y switched with Delta_x
- DIV CX ; divide by Delta_Y
-
- MOV SI, BX ; Si = Acculmulator
- MOV BX, AX ; Bx = Addor
- POP AX ; Get Color, Bit mask
- MOV DX, SC_Data ; Sequence controller data register
- INC CX ; Inc Delta_Y so we can unroll loop
-
- ; Loop (x2) to Draw Pixels, Move Down, and Maybe left
-
- @DL_STLLoop:
-
- MOV ES:[DI], AH ; set first pixel
- DEC CX ; Count Down Delta_Y
- JZ @DL_STLExit ; Exit if done
-
- ADD SI, BX ; add numerator to accumulator
- JNC @DL_STLnc2 ; No carry, just move down!
-
- ; Move Left
-
- DEC DI ; Left one addr
- ROR AL, 1 ; Move Left one plane
- CMP AL, 87h ; Skipped around?, if AL <88 then Carry set
- ADC DI, 0 ; Adjust Address: DI = Di + Carry, ie. plane =
- OUT DX, AL ; Set up New Bit Plane mask
-
- @DL_STLnc2:
- ADD DI, BP ; advance to next line.
-
- MOV ES:[DI], AH ; set pixel
- ADD SI, BX ; add numerator to accumulator
- JNC @DL_STLnc3 ; No carry, just move down!
-
- ;Move Left
-
- DEC DI ; Left one addr
- ROR AL, 1 ; Move Left one plane
- CMP AL, 87h ; Skipped around?, if AL <88 then Carry set
- ADC DI, 0 ; Adjust Address: DI = Di + Carry, ie. plane =
- OUT DX, AL ; Set up New Bit Plane mask
-
- @DL_STLnc3:
- ADD DI, BP ; advance to next line.
-
- DEC CX ; count down Delta_Y
- JNZ @DL_STLLoop ; loop till done
-
- @DL_STLExit:
- JMP @DL_EXIT2 ; and exit
-
- ; Draw A line that goes to the Right...
-
- @DL_DrawRight:
- CMP CX, DX ; is X < Delta_Y?
- JB @DL_SteepRight ; yes, so go do steep line (Delta_Y iterations)
-
- ; Draw a Shallow line to the Right in Mode X
-
- @DL_ShallowRight:
- XOR AX, AX ; zero low word of Delta_y * 10000h
- SUB AX, DX ; DX:AX <- DX * 0FFFFh
- SBB DX, 0
- DIV CX ; divide by Delta_X
-
- MOV SI, BX ; Si = Acculmulator
- MOV BX, AX ; Bx = Addor
- POP AX ; Get Color, Bit mask
- MOV DX, SC_Data ; Sequence controller data register
- INC CX ; Inc Delta_X so we can unroll loop
-
- ; Loop (x2) to Draw Pixels, Move Right, and Maybe Down...
-
- @DL_SLRLoop:
- MOV ES:[DI], AH ; set first pixel, mask already set up
-
- DEC CX ; count down Delta_X
- JZ @DL_SLRExit ; Exit if done..
-
- ADD SI, BX ; add numerator to accumulator
- JNC @DL_SLR2nc ; don't move down if carry not set....
-
- ADD DI, BP ; Move Down one line...
-
- @DL_SLR2nc: ; Now move right a pixel...
- ROL AL, 1 ; Move Right one plane
- CMP AL, 12h ; Skipped around?, if AL >12 then Carry not set
- ADC DI, 0 ; Adjust Address: DI = Di + Carry, ie. plane =
- OUT DX, AL ; Set up New Bit Plane mask
-
- MOV ES:[DI], AH ; set pixel
- ADD SI, BX ; add numerator to accumulator
- JNC @DL_SLR3nc ; don't move down if carry not set....
-
- ADD DI, BP ; Move Down one line...
-
- @DL_SLR3nc:
- ROL AL, 1 ; Move Right one plane
- CMP AL, 12h ; Skipped around?, if AL >12 then Carry not set
- ADC DI, 0 ; Adjust Address: DI = Di + Carry, ie. plane =
- OUT DX, AL ; Set up New Bit Plane mask
-
- DEC CX ; count down Delta_X
- JNZ @DL_SLRLoop ; loop till done
-
- @DL_SLRExit:
- JMP @DL_EXIT2 ; and exit
-
- ; Draw a Shallow line to the Right in Mode X
-
- @DL_SteepRight:
- XOR AX, AX ; zero low word of Delta_y * 10000h
- XCHG DX, CX ; Delta_Y switched with Delta_x
- DIV CX ; divide by Delta_Y
-
- MOV SI, BX ; Si = Acculmulator
- MOV BX, AX ; Bx = Addor
- POP AX ; Get Color, Bit mask
- MOV DX, SC_Data ; Sequence controller data register
- INC CX ; Inc Delta_Y so we can unroll loop
-
- ; Loop (x2) to Draw Pixels, Move Down, and Maybe Right
-
- @STRLoop:
- MOV ES:[DI], AH ; set first pixel, mask already set up...
-
- DEC CX ; count down Delta_Y
- JZ @DL_EXIT2 ; Exit if Finished
-
- ADD SI, BX ; add numerator to accumulator
- JNC @STRnc2 ; if no carry then just go down...
-
- ROL AL, 1 ; Move Right one plane
- CMP AL, 12h ; Skipped around?, if AL >12 then Carry not set
- ADC DI, 0 ; Adjust Address: DI = Di + Carry, ie. plane =
- OUT DX, AL ; Set up New Bit Plane mask
-
- @STRnc2:
- ADD DI, BP ; advance to next line.
-
- MOV ES:[DI], AH ; set pixel
- ADD SI, BX ; add numerator to accumulator
- JNC @STRnc3 ; if no carry then just go down...
-
- ROL AL, 1 ; Move Right one plane
- CMP AL, 12h ; Skipped around?, if AL >12 then Carry not set
- ADC DI, 0 ; Adjust Address: DI = Di + Carry, ie. plane =
- OUT DX, AL ; Set up New Bit Plane mask
-
- @STRnc3:
- ADD DI, BP ; advance to next line.
-
- DEC CX ; count down Delta_Y
- JNZ @STRLoop ; loop till done
-
- @DL_EXIT2:
-
- POP DI
- POP SI
- POP BP ; Restore BP, SI, & DI
-
- RET 10 ; Exit and Clean up Stack
-
- DRAW_LINE ENDP
-
-
- ;=========================
- ;SET_ACTIVE_PAGE (PageNo%)
- ;=========================
- ;
- ;Sets the Video Page to be used for future drawing
- ;
-
- SAP_STACK STRUC
- DW ? ;BP
- DD ? ;Caller
- SAP_Page DW ? ;Page # for Drawing
- SAP_STACK ENDS
-
- PUBLIC SET_ACTIVE_PAGE
-
- SET_ACTIVE_PAGE PROC FAR
-
- PUSH BP ; Preserve Registers
- MOV BP, SP ; Set up Stack Frame
-
- MOV BX, [BP].SAP_Page ; Get Desired Page #
- CMP BX, LAST_PAGE ; Is Page # Valid?
- JAE @SAP_Exit ; IF Not, Do Nothing
-
- MOV ACTIVE_PAGE, BX ; Set Active Page #
-
- SHL BX, 1 ; Scale Page # to Word
- MOV AX, PAGE_ADDR[BX] ; Get offset to Page
-
- MOV CURRENT_PAGE, AX ; And set for future LES's
-
- @SAP_Exit:
- POP BP ; Restore Registers
-
- RET 2 ; We are Done.. Outa here
-
- SET_ACTIVE_PAGE ENDP
-
-
- ;================
- ;GET_ACTIVE_PAGE%
- ;================
- ;
- ; Returns the Video Page # currently used for Drawing
- ;
- ; RETURNS: AX = Current Video Page used for Drawing
- ;
-
- PUBLIC GET_ACTIVE_PAGE
-
- GET_ACTIVE_PAGE PROC FAR
-
- MOV AX, ACTIVE_PAGE ; Get Active Page #
-
- RET ; We are Done.. Outa here
-
- GET_ACTIVE_PAGE ENDP
-
-
- ;==========================
- ;SET_DISPLAY_PAGE (PageNo%)
- ;==========================
- ;
- ;Sets the Video Page to be displayed on the screen
- ;
-
-
- SDP_STACK STRUC
- DW ? ;BP
- DD ? ;Caller
- SDP_Page DW ? ;Page # to Display...
- SDP_STACK ENDS
-
- PUBLIC SET_DISPLAY_PAGE
-
- SET_DISPLAY_PAGE PROC FAR
-
- PUSH BP ; Preserve Registers
- MOV BP, SP ; Set up Stack Frame
-
- MOV BX, [BP].SDP_Page ; Get Desired Page #
- CMP BX, LAST_PAGE ; Is Page # Valid?
- JAE @SDP_Exit ; IF Not, Do Nothing
-
- MOV DISPLAY_PAGE, BX ; Set Display Page #
-
- SHL BX, 1 ; Scale Page # to Word
- MOV CX, PAGE_ADDR[BX] ; Get offset in memory to Page
-
- ADD CX, CURRENT_MOFFSET ; Adjust for any scrolling
-
- MOV DX, CRTC_Index ; We Change the VGA Sequencer
- MOV AL, START_DISP_LO ; Display Start Low Register
- MOV AH, CL ; Low 8 Bits of Start Addr
- OUT DX, AX ; Set Display Addr Low
-
- MOV AL, START_DISP_HI ; Display Start High Register
- MOV AH, CH ; High 8 Bits of Start Addr
- OUT DX, AX ; Set Display Addr High
-
- @SDP_Exit:
- POP BP ; Restore Registers
-
- RET 2 ; We are Done.. Outa here
-
- SET_DISPLAY_PAGE ENDP
-
-
- ;=================
- ;GET_DISPLAY_PAGE%
- ;=================
- ;
- ; Returns the Video Page # currently be displayed on the screen
- ;
- ; RETURNS: AX = Current Display Page
- ;
-
- PUBLIC GET_DISPLAY_PAGE
-
- GET_DISPLAY_PAGE PROC FAR
-
- MOV AX, DISPLAY_PAGE ; Get Display Page #
-
- RET ; We are Done.. Outa here
-
- GET_DISPLAY_PAGE ENDP
-
-
- ;=================================================
- ;SET_DAC_REGISTER (Register%, Red%, Green%, Blue%)
- ;=================================================
- ;
- ; Sets a single (RGB) Vga Palette Register
- ; to the specified Reg, Green & Blue Values
- ;
-
- SDR_STACK STRUC
- DW ? ; BP
- DD ? ; Caller
- SDR_Blue DB ?,? ; Blue Data Value
- SDR_Green DB ?,? ; Green Data Value
- SDR_Red DB ?,? ; Red Data Value
- SDR_Register DB ?,? ; Palette Register #
- SDR_STACK ENDS
-
- PUBLIC SET_DAC_REGISTER
-
- SET_DAC_REGISTER PROC FAR
-
- PUSH BP ; Save Bp
- MOV BP, SP ; Set up Stack Frame
-
- ; Select which DAC Register to modify
-
- OUT_8 DAC_WRITE_ADDR, [BP].SDR_Register
-
- MOV DX, PEL_DATA_REG ; Dac Data Register
-
- MOV AL, [Bp].SDR_Red ; Get Red Intensity
- OUT DX, AL ; Set it
-
- MOV AL, [Bp].SDR_Green ; Get Green Intensity
- OUT DX, AL ; Set it
-
- MOV AL, [Bp].SDR_Blue ; Get Blue Intensity
- OUT DX, AL ; Set it
-
- POP BP ; Restore Registers
- RET 8 ; Exit & Clean Up Stack
-
- SET_DAC_REGISTER ENDP
-
-
- ;====================================================
- ;GET_DAC_REGISTER (Register%, &Red%, &Green%, &Blue%)
- ;====================================================
- ;
- ; Gets the RGB Values of a single Vga Palette Register
- ;
- ; INPUT: Red%, Green% & Blue% are offsets into DGROUP
- ; that point to 16 bit integers that will hold
- ; the returned red, green, and blue values
- ;
-
- GDR_STACK STRUC
- DW ? ; BP
- DD ? ; Caller
- GDR_Blue DW ? ; Addr of Blue Data Value in DS
- GDR_Green DW ? ; Addr of Green Data Value in DS
- GDR_Red DW ? ; Addr of Red Data Value in DS
- GDR_Register DB ?,? ; Palette Register #
- GDR_STACK ENDS
-
- PUBLIC GET_DAC_REGISTER
-
- GET_DAC_REGISTER PROC FAR
-
- PUSH BP ; Save Bp
- MOV BP, SP ; Set up Stack Frame
-
- ; Select which DAC Register to read in
-
- OUT_8 DAC_READ_ADDR, [BP].GDR_Register
-
- MOV DX, PEL_DATA_REG ; Dac Data Register
- XOR AX, AX ; Clear AX
-
- IN AL, DX ; Read Red Value
- MOV BX, [Bp].GDR_Red ; Get Address of Red%
- MOV [BX], AX ; *Red% = AX
-
- IN AL, DX ; Read Green Value
- MOV BX, [Bp].GDR_Green ; Get Address of Green%
- MOV [BX], AX ; *Green% = AX
-
- IN AL, DX ; Read Blue Value
- MOV BX, [Bp].GDR_Blue ; Get Address of Blue%
- MOV [BX], AX ; *Blue% = AX
-
- POP BP ; Restore Registers
- RET 8 ; Exit & Clean Up Stack
-
- GET_DAC_REGISTER ENDP
-
-
- ;=========================
- ;SET_WINDOW (Xpos%, Ypos%)
- ;=========================
- ;
- ; Since a Logical Screen can be larger than the Physical
- ; Screen, Scrolling is possible. This routine sets the
- ; Upper Left Corner of the Screen to the specified Pixel.
- ;
- ; Xpos & Ypos = Coordinates of the Pixel to put in the
- ; upper left corner of the screen
- ;
-
- SW_STACK STRUC
- DW ? ;BP
- DD ? ;Caller
- SW_Ypos DW ?
- SW_Xpos DW ?
- SW_STACK ENDS
-
- PUBLIC SET_WINDOW
-
- SET_WINDOW PROC FAR
-
- PUSH BP ; Preserve Registers
- MOV BP, SP ; Set up Stack Frame
-
- ; Check if our Scroll Offsets are Valid
-
- MOV AX, [BP].SW_Ypos ; Get Desired Y Offset
- CMP AX, MAX_YOFFSET ; Is it Within Limitss?
- JA @SW_Exit ; if not, exit
-
- MOV BX, [BP].SW_Xpos ; Get Desired X Offset
- CMP BX, MAX_XOFFSET ; Is it Within Limitss?
- JA @SW_Exit ; if not, exit
-
- ; Compute proper Display start address to use
-
- MUL SCREEN_WIDTH ; AX = YOffset * Line Width
- MOV CX, BX ; CX = Copy of X Offset
- SHR BX, 2 ; BX / 4 = Bytes into Line
- ADD AX, BX ; AX = Offset of Upper Left Pixel
-
- MOV CURRENT_MOFFSET, AX ; Save Offset Info
-
- MOV BX, DISPLAY_PAGE ; Get Display Page #
- SHL BX, 1 ; Scale Page # to Word
- ADD AX, PAGE_ADDR[BX] ; Get offset in VGA to Page
- MOV BX, AX ; BX = Desired Display Start
-
- MOV DX, INPUT_1 ; Input Status #1 Register
-
- ; Wait for a Vertical Retrace to smooth out the scroll
-
- @SW_WAIT:
- IN AL, DX ; Get VGA stauts
- JMP $+2 ; Delay (why?)
- AND AL, 8 ; Bit 3 Gone Hi Yet?
- JZ @SW_WAIT ; If Not, wait for it
- CLI ; Don't Interrupt this!
-
- ; Set the Start Display Address to the New window
-
- MOV DX, CRTC_Index ; We Change the VGA Sequencer
- MOV AL, START_DISP_LO ; Display Start Low Register
- MOV AH, BL ; Low 8 Bits of Start Addr
- OUT DX, AX ; Set Display Addr Low
-
- MOV AL, START_DISP_HI ; Display Start High Register
- MOV AH, BH ; High 8 Bits of Start Addr
- OUT DX, AX ; Set Display Addr High
-
- ; Now Set the Horizontal Pixel Pan values
-
- MOV DX, INPUT_1 ; Input Status #1 Register
- IN AL, DX ; Reset Attrib Flip/Flop
-
- OUT_8 ATTRIB_Ctrl, 33h ; Select Pixel Pan Register
-
- MOV AL, CL ; Get Low Bits of X Offset
- AND AL, 03 ; Get # of Pixels to Pan (0-3)
- SHL AL, 1 ; Shift for 256 Color Mode
- OUT DX, AX ; Fine tune the display!
- STI ; Ok, Now you CAN interrupt
-
- @SW_Exit:
- POP BP ; Restore Saved Registers
- RET 4 ; Exit and Clean up Stack
-
- SET_WINDOW ENDP
-
- END
-