****************************************************************************** * This information is intended for advanced programmers writing applications * or drivers to make use of the extended capabilities of the VGA Card. This * information is not needed for normal use of the VGA Card. Use of the * information contained here requires familiarity with assembly language * programming and the workings of the IBM *PC/AT* environments. ******************************************************************************* Extended Memory Mapping The memory map for IBM PCs and compatibles allots 128 Kbytes of the one Megabyte system total to video RAM. This area begins at A0000 and extends to BFFFF, but "standard" video modes only use: ADDRESS SIZE USED IN MODES A0000 64K D,E,F,10,11,12,13 B0000 32K 7 B0000 64K Hercules B8000 32K 0,1,2,3,4,5,6 If two video cards coexist, they must be set to modes using different VRAM areas. All of the modes listed above are designed to use no more than 64K of the video memory map - even modes D-12 conform to this limit by organizing their extra memory into "planes". Mode 13 is in a class by itself, it can provide 256 colors with a resolution of 320x200 pels. Each pel requires one byte of VRAM, so it takes 64,000 bytes to store a display screen. Using 128K at A0000, it would be possible to support 640x200 or 320x400 resolution; but these modes would not be able to coexist with secondary video cards. The PVGA chip is designed to provide 256 color modes with resolutions as high as 640x480 pels. Although this requires 310K of VRAM, a kind of bankswitching allows this mode to operate without violating the 64K limit at any time. (Note: the PVGA hardware supports the use of a 128K limit, but software always sets it for 64K in order to conform to the "standard".) Before giving examples of how to read and write extended VRAM, the necessary memory and I/O conventions will be described. In a 256 color mode the memory assigns one byte for each pel - in addition, the byte's offset from the beginning of the VRAM is a function of the X-Y coordinates of the pel's position on the display. By convention, the leftmost pel of the top scan line is assigned coordinates (0,0) - the X coordinates increase moving to the right and Y coordinates increase moving downward. The rightmost pel in the last scan line of a 640x480 display has the position (639,479). Letting WIDTH represent the number of pels in one horizontal scan line (usually 320 or 640), a given pel's relative location in memory is: OFFSET = (WIDTH*Y)+X The problem of extended VRAM control is the conversion of this OFFSET to an address that can be accessed by an 8088 MOV instruction. In mode 13, this is simple - the true address is equal to A0000+OFFSET. There is no problem because OFFSET is always less than 64K (since WIDTH=320, X@ and Y<200>). In extended modes, the video memory must be thought of in two distinct ways - the PVGA's point of view and the SYSTEM's. The PVGA addressing can be thought of as the correspondence between display coordinates and memory location given in the formula for OFFSET. It represents the "true" pel address. The SYSTEM addressing must be set up by the software prior to the memory access itself. This setup is carried out by writing to certain I/O registers in the PVGA. Note that this is not an unusual situation, a similar preparation is required to work with standard "planed" memory. Before describing the SYSTEM memory I/O registers in detail, a model of the relationship between PVGA and SYSTEM memory treatment will be presented. All memory addresses, unless stated otherwise, are hexadecimal. The PVGA can control up to one megabyte of video RAM, so the value calculated by OFFSET requires twenty bits or five hex digits. It is useful to split the five digit address into two parts - the two high order digits (HI_OFFSET) and the three low order digits (LO_OFFSET). For example, OFFSET=1E7A4 has 1E as a HI_OFFSET and 7A4 as its LO_OFFSET. Because SYSTEM video memory addresses begin at A0000 and cannot exceed AFFFF, a full five digit OFFSET will go out of range if A0000 is added (like for mode 13). To allow the necessary adjustment, the PVGA provides two offset registers - PR0A and PR0B. These registers can be used to map regions of the VRAM into the SYSTEM memory area. There are two options: 1. Use PR0A alone to access a 64K VRAM window. This window begins at A0000 in SYSTEM memory. 2. Use PR0A and PR0B to access two 32K VRAM windows. The PR0A window is mapped to A8000 and PR0B to A0000. Even though the windows are separate in SYSTEM memory, they can overlap in PVGA memory if the values written to PR0A and PR0B specify it. PR0A and PR0B both take one byte values. Assuming ADDRESS is a twenty bit number in the video range A0000-AFFFF, the correspondence between PVGA and SYSTEM addressing is given as follows: SYSTEM to PVGA is straightforward - OFFSET = (ADDRESS-A0000)+VALUE(PR0A)*1000H and OFFSET = (ADDRESS-A0000)+VALUE(PR0B)*1000H PVGA to SYSTEM is more ambiguous because the same OFFSET can be derived from different combinations of ADDRESS and VALUE(PR0A). The recommended settings are - ADDRESS = A8000+LO_OFFSET VALUE(PR0A) = HI_OFFSET-8h and ADDRESS = A0000+LO_OFFSET VALUE(PR0B) = HI_OFFSET Adherance to this recommendation maximizes the size of the PVGA memory blocks that can be modified without worrying about address wraparound in SYSTEM memory: e.g. take OFFSET=2FFFF Case 1: set DS:SI=A000:FFF and VALUE(PR0A)=2F Case 2: set DS:SI=A000:FFFF and VALUE(PR0A)=20 Both cases yield the correct OFFSET, but if SI is incremented, the case 1 OFFSET is 30000 and the case 2 OFFSET has wrapped back to 20000. Because LO_OFFSET has a maximum value of FFF (=4K-1), it is safe to operate with 60K (=64-4) blocks if PR0A alone is used, and 28K (=32-4) if PR0A and PR0B are both activated. A close check of the PVGA-SYSTEM conversion formulas should reveal that the PR0B variants aren't quite as symmetric as those for PR0A. In particular, to generate a SYSTEM address that accesses PVGA OFFSETs in the range 00000-07FFF, it is necessary to set PR0A to a value in the vicinity of (Total 4K units of VRAM used)-8 For example, 640x400 mode requires 256K of video memory which is equivalent to a maximum OFFSET of 40000. This value has a HI_OFFSET equal to 40 which also represents the "Total 4K units of VRAM used". So, by setting PR0A to 38 (=40-8) and accessing SYSTEM address A8000, software can modify OFFSET 00000. Although this technique allows PR0A to access any VRAM that PR0B can, the implementation might be clumsy since the "Total 4K units" varies according to the mode's resolution. An alternative is to check the value of HI_OFFSET-8 prior to setting PR0A or PR0B and making sure that PR0A receives a valid setting. In other words, if the source and destination OFFSETs are both less than 08000, use PR0A only; otherwise set up PR0B to handle the lower OFFSET and PR0A to access the higher OFFSET. For anyone familiar with the 8088 architecture, PR0A and PR0B can be thought of as being analogous to the segment registers DS and ES. Both are used to modify a sixteen bit address (e.g. [SI]) to a full twenty bit address required by the hardware. The principal difference is the granularity - incrementing a segment register by one advances the true address by one paragraph (=16 bytes), and incrementing PR0A or PR0B jumps the pointer into PVGA memory by 4K (=4096 bytes). The following diagram illustrates the PVGA-SYSTEM addressing relationship in PR0A-only and PR0A-PR0B operation. The numbers represent the beginning addresses of 4K memory blocks, so 02000 should be read as "the memory from 2000 to 2FFF inclusive": Example 1 Example 2 PR0A=12 PR0A=0E=16-8 PR0B inactive PR0B=00 PVGA SYSTEM WINDOW PVGA SYSTEM WINDOWS 00000 00000 A0000 (PR0B) 01000 01000 A1000 (PR0B) 02000 02000 A2000 (PR0B) 03000 03000 A3000 (PR0B) 04000 04000 A4000 (PR0B) 05000 05000 A5000 (PR0B) 06000 06000 A6000 (PR0B) 07000 07000 A7000 (PR0B) 08000 08000 09000 09000 0A000 0A000 0B000 0B000 0C000 0C000 0D000 0D000 0E000 0E000 0F000 0F000 10000 10000 11000 11000 12000 A0000 (PR0A) 12000 13000 A1000 (PR0A) 13000 14000 A2000 (PR0A) 14000 15000 A3000 (PR0A) 15000 16000 A4000 (PR0A) 16000 A8000 (PR0A) 17000 A5000 (PR0A) 17000 A9000 (PR0A) 18000 A6000 (PR0A) 18000 AA000 (PR0A) 19000 A7000 (PR0A) 19000 AB000 (PR0A) 1A000 A8000 (PR0A) 1A000 AC000 (PR0A) 1B000 A9000 (PR0A) 1B000 AD000 (PR0A) 1C000 AA000 (PR0A) 1C000 AE000 (PR0A) 1D000 AB000 (PR0A) 1D000 AF000 (PR0A) 1E000 AC000 (PR0A) 1E000 1F000 AD000 (PR0A) 1F000 20000 AE000 (PR0A) 20000 21000 AF000 (PR0A) 21000 22000 22000 23000 23000 . . . . . . Now that the operation of PR0A and PR0B has been made abundantly clear, their enabling and setting procedures will be outlined. Control is handled by a variety of I/O registers provided by the PVGA: PR0A, PR0B, PR1, PR2, PR3, PR4 and PR5. These registers are described in the PVGA User's Guide; of them, PR0A, PR0B, PR1 and PR5 are associated with extended memory control. (So is PR4, but it is set automatically whenever an extended memory mode has been activated and should be left alone thereafter.) These registers are implemented as additions to the Graphics Controller portion of the PVGA. Software communicates with the Graphics Controller through two eight-bit I/O ports - the Index Port at 3CE and the Data Port at 3CF. Both ports can be written to with a standard OUT instruction, an IN instruction returns the last value sent to the port. The Index Port is used to select a specific Graphics Controller register, the following indices are assigned within the PVGA: Index Name 0-8 Standard VGA Graphics Controller Registers 9 PR0A 0A PR0B 0B PR1 0C PR2 0D PR3 0E PR4 0F PR5 Since PR0A through PR5 are not standard VGA registers, the PVGA chip offers optional protection from accidental modification. The PR5 register handles this protection in the following manner: Example - writing the value 2E to PR0B MOV DX,3CE ; GRAPHICS CONTROLLER INDEX PORT ADDRESS MOV AL,0F ; PR5 INDEX VALUE MOV AH,5 ; THE VALUE 5 "UNLOCKS" PR0A TO PR4 OUT DX,AX ; UNLOCK MOV AL,0A ; PR0B INDEX VALUE MOV AH,2E ; DESIRED SETTING OUT DX,AX ; SET PR0B MOV AL,0F ; PR5 INDEX VALUE MOV AH,0 ; VALUES OTHER THAN 5 "LOCK" PR0A TO PR4 OUT DX,AX ; RELOCK It is not necessary to relock after setting a register, but this is a safe convention. PR5 values are recognized modulo 8 (e.g. A5 is equivalent to 05). PR0A is modified in the same way as PR0B. It is probably desirable to zero these registers upon completion of an extended memory access - this forces consistency between diferent applications. The following example shows how to enable PR0B by setting the 8 bit of PR1: Example - enabling and disabling PR0B MOV DX,3CE ; GRAPHICS CONTROLLER INDEX PORT ADDRESS MOV AL,0F ; PR5 INDEX VALUE MOV AH,5 ; THE VALUE 5 "UNLOCKS" PR0A TO PR4 OUT DX,AX ; UNLOCK MOV AL,0B ; PR1 INDEX VALUE OUT DX,AL ; SET INDEX ONLY INC DX ; GRAPHICS CONTROLLER DATA PORT ADDRESS IN AL,DX ; READ CURRENT CONTENTS OR AL,8 ; SET BIT TO ENABLE PR0B OUT DX,AL ; ENABLE PR0B --- ; INSERT CODE TO MODIFY MEMORY, ; LEAVING REGISTERS AND PORTS UNCHANGED AND AL,0F7 ; SET BIT TO DISABLE PR0B OUT DX,AL ; DISABLE PR0B DEC DX ; GRAPHICS CONTROLLER INDEX PORT ADDRESS MOV AL,0F ; PR5 INDEX VALUE MOV AH,0 ; VALUES OTHER THAN 5 "LOCK" PR0A TO PR4 OUT DX,AX ; RELOCK It is also possible to read and write PR0A and PR0B using the extended BIOS calls described in the document PROGRAM.TXT. When using these BIOS calls it is not necessary to unlock and lock the extended registers since this is performed automatically by the BIOS routines. Example - writing the value 2E to PROB using BIOS MOV AX,007F ; Extended function BIOS call MOV BH,0A ; Write to PR0B MOV BL,2E ; Value to write to PR0B INT 10 ; Video BIOS software interrupt Example - enabling and disabling PROB using BIOS MOV AX,007F ; Extended function BIOS call MOV BH,1B ; Read contents of PR1 INT 10 ; Video BIOS software interrupt OR BL,8 ; Set bit of PR1 to enable PR0B MOV BH,0B ; Write value to PR1 using BIOS call INT 10 ; Video BIOS software interrupt ___ ; Insert code to modify memory ; Leaving registers and ports unchanged AND BL,0F7 ; Set bit of PR1 to disable PR0B MOV BH,0B ; Write value to PR1 using BIOS call INT 10 ; Video BIOS software interrupt In summary, control through the PR0A and PR0B registers allows software to access any part of extended video memory without violating the PC and VGA memory map standards. There are two access options - PR0A is most useful for simple memory fills and for moving VRAM blocks that lie within 64K of each other. But if the lowest OFFSET of one block is more than 64K bytes from the highest OFFSET of the other, it is necessary to use both PR0A and PR0B. To avoid address wrapping or conflict with other software, the following conventions are recommended: 1. Upon completion of a task, make sure that: a. PR0A and PR0B are zeroed b. PR0B is disabled c. PR0A through PR4 are locked by setting PR5 2. When converting an OFFSET to its equivalent SYSTEM address, use the PR0A and PR0B registers to their greatest advantage by splitting OFFSET into HI_OFFSET and LO_OFFSET as described earlier. 3. Use 32K as a maximum memory block size for PR0A operations, and use 16K for PR0A-PR0B transfers. In conjunction with convention 2, this avoids any address wrap problems. Also, as multiples of 4K, these block sizes are convenient to deal with in loops. Sample program 1 Task: zero 256K of video memory starting at OFFSET 00000 Assuming: registers unlocked, PR0A enabled, PR0B disabled MOV AX,0A000 MOV ES,AX ; SET VIDEO RAM SEGMENT MOV DX,3CE ; GRAPHICS CONTROLLER INDEX PORT MOV BL,0 ; INITIAL VALUE FOR HI_OFFSET LOOP1: ; OUTER LOOP FILLS 32K BLOCKS MOV AL,9 ; INDEX FOR PR0A MOV AH,BL ; HI_OFFSET FOR CURRENT 32K OUT DX,AX ; SET IT CLD MOV DI,0 ; SET LO_OFFSET MOV AL,0 ; DATA VALUE MOV CX,8000H ; 32K BYTES REP STOSB ; FILL 32K WITH ZERO ADD BL,8 ; ADVANCE HI_OFFSET BY 32K CMP BL,40 ; TEST IF HI_OFFSET OF 256K JNZ LOOP1 Sample program 2 Task: Move the contents of a source VRAM block to a destination VRAM block. Assuming: registers unlocked PR0A enabled PR0B enabled pointer and size variables are in code segment 08000 = destination OFFSET source, destination blocks disjoint SIZE+either OFFSET = highest possible OFFSET DB SOURCE_HI ; HI_OFFSET FOR SOURCE BLOCK DW SOURCE_LO ; LO_OFFSET FOR SOURCE BLOCK DB DESTINATION_HI ; HI_OFFSET FOR DESTINATION DW DESTINATION_LO ; LO_OFFSET FOR DESTINATION DD SIZE ; BLOCK SIZE IN BYTES MOV AX,0A000 MOV DS,AX ; SET SOURCE VRAM SEGMENT MOV BL,CS:BYTE PTR SOURCE_HI MOV AX,0A800 MOV ES,AX ; SET DESTINATION VRAM SEGMENT MOV BH,CS:BYTE PTR DESTINATION_HI SUB BH,8 ; PR0A ADJUSTMENT OF HI_OFFSET MOV DX,3CE ; GRAPHICS CONTROLLER INDEX PORT LOOP1: ; OUTER LOOP MOVES 16K BLOCKS MOV CX,4000 ; DEFAULT BLOCK SIZE OF 16K CMP CS:WORD PTR SIZE+2,0 JNZ MORE ; SIZE>64K, CONTINUE CMP CX,CS:WORD PTR SIZE JBE MORE ; SIZE=16K, CONTINUE MOV CX,CS:WORD PTR SIZE ; SET COUNT=MIN(16K,SIZE) JCXZ EXIT ; SIZE=0, DONE MORE: MOV AL,0A ; INDEX FOR PR0B MOV AH,BL ; HI_OFFSET FOR SOURCE OUT DX,AX ; SET IT MOV AL,9 ; INDEX FOR PR0A MOV AH,BH ; HI_OFFSET FOR DESTINATION OUT DX,AX ; SET IT MOV SI,CS:WORD PTR SOURCE_LO ; SET LO_OFFSETS MOV DI,CS:WORD PTR DESTINATION_LO PUSH CX ; SAVE SUB-BLOCK SIZE CLD REP MOVSB ; TRANSFER BLOCK PORTION (16K MAX) ADD BL,4 ; ADVANCE SOURCE BY 16K ADD BH,4 ; ADVANCE DESTINATION BY 16K POP CX ; RECOVER SUB-BLOCK SIZE SUB CS:WORD PTR SIZE,CX ; SUBTRACT PART MOVED SBB CS:WORD PTR SIZE+2,0 ; BORROW FROM HI ORDER JMP SHORT LOOP1 EXIT: --- * Paradise and VGA Plus 16 are trademarks of Paradise Systems, Inc. IBM and AT are trademarks of International Business Machines Corp. (C) 1988 Paradise Systems, Inc. All rights reserved.