|Dͻ
|D |5The Happy Hacker |D
|Dͼ

^C^1A VIDEO TUTORIAL -- Part 8
^CVideo BIOS RAM Variables

^Cby:  Joel Ellis Rea

   Some of you who are be a little familiar with machine language may have been
wondering how the BIOS can change bits in a port that it cannot read from.  To
set a bit to a "1" in a byte, the 8088 CPU must read the location or port, then
logically-OR its contents with a value consisting of the bit or bits to be set,
then write out the results.  Likewise, to reset a bit to a "0" in a byte, the
8088 CPU must read the location or port, then logically AND its contents with a
value consisting of the bit(s) to be reset, previously NOTted to invert the
value so that said bits are "0" while bits to remain unchanged are "1", then the
results are written back out.  But if the port is write-only, as is the case
with the Control port on the MDA ($03B8) and CGA ($03D8), and the Color/Palette
port on the CGA ($03D9), the required preliminary READ cannot occur.  A program
could write a whole NEW value to that port, but not just change particular bits
within the existing value.

   In a similar manner, how does the BIOS know what mode the video is currently
in?  It must know, since it treats most calls differently depending on the
current mode -- in fact, BIOS video function 0Fh returns the current video mode
as part of the information it returns.  It also returns the number of character
columns across the screen in the current mode -- how does it get THAT
information?  Not only that, but when you switch active video pages in text
modes, you will find that the cursor can be in a different position on each
page.  Since the 6845 CRTC chip has only one set of cursor-positioning
registers, just where do the other 3 or 7 come from?  And how does the BIOS
keep track of which is the current video page, anyway?

   It should be getting obvious that the Video BIOS has some "scratchpad" RAM
that it uses to store such information.  It obviously cannot store it within
itself, since the BIOS resides in ROM, and ROM (by definition) cannot be written
to.  Likewise, the video card ports and the 6845 CRTC registers are, for the
most part, write-only, so they cannot be read from.

   Sure enough, MS-DOS and other BIOS-compatible PC operating systems allocate a
small area of low-address RAM specifically for the BIOS.  The first 400h
locations of memory are taken up by a segment which holds the INTerrupt
vectors.  The next segment, which is given segment address 0040h (RAM address
00400h), is allocated to BIOS scratchpad usage.  We are interested in the VIDEO
BIOS RAM, which starts at offset 0049h in segment 0040h.  It breaks down as
follows:
 
  OFFSET       NAME                    SIZE    COMMENT
                                 
 
  0049h        CRT_MODE                Byte    Current BIOS video mode
  004Ah        CRT_COLS                Word    Number of character columns
  004Ch        CRT_LENS                Word    Length of video buffer in bytes
  004Eh        CRT_START               Word    Offset of current video page
  0050h        CURSOR_POSN             Word*8  Cursor (col,row) for 8 pages
  0060h        CURSOR_MODE             Word    Current cursor scan line mode
  0062h        ACTIVE_PAGE             Byte    Current page being addressed
  0063h        ADDR_6845               Word    I/O index port addr for CRTC
  0065h        CRTC_MODE_SET           Byte    Simulated Control value (03x8h)
  0066h        CRTC_Palette            Byte    Simulated Palette value (03D9h)
 
  A Turbo Pascal program could use Turbo Pascal's structured-data and ABSOLUTE
VARiables feature to set up a single RECORD structure as follows:
 
^1   VAR

^1     BIOS_Video_RAM:  RECORD  BEGIN
^1       CRT_MODE:       Byte;
^1       CRT_COLS:       INTEGER;
^1       CRT_LENS:       INTEGER;
^1       CRT_START:      INTEGER;
^1       CURSOR_POSN:    ARRAY [0..7] OF  RECORD  BEGIN  Column, Row:  Byte  END;
^1       CURSOR_MODE:    RECORD  BEGIN  First, Last:  Byte  END;
^1       ACTIVE_PAGE:    Byte;
^1       ADDR_6845:      INTEGER;
^1       CRTC_MODE_SET:  Byte;
^1       CRTC_Palette:   Byte
^1     END   { RECORD BIOS_Video_RAM }  ABSOLUTE $0040:$0049;
 
   In Microsoft BASIC, BASICA, GW-BASIC, QuickBASIC, etc., you have to settle
for direct POKEs and PEEKs after first executing a ^1DEF SEG = &h0040^0 statement.
  
   Most of these locations are of little use, since manipulating them would
have no effects that you couldn't do with the BIOS INT 10h calls, except that
such calls are virtually impossible under BASIC without having a short machine
language routine installed to do the call and return the results.  However, you
can use some of these locations to, in effect, "pull the wool over the BIOS's
eyes".
 
   As an example, the only difference between the 320x200 color and "B&W"
graphics modes and the 640x200 "B&W" graphics mode is the contents of the
CGA_Control (03D8h) port, and the interpretation of the CGA_Palette (03D9h)
port and the video buffer.  The 6845 CRTC is initialized the same for all three
modes.  The BIOS must distinguish between the modes so that it will know which
palettes are valid, whether to plot two bits or one bit per pixel, and whether
40 or 80 columns of text will fit on the screen.
 
  As it turns out, the video BIOS reads CRT_MODE (offset 0049h) to determine
whether to plot pixels single or double-wide.  It reads CRT_COLS (offset 004Ah)
to determine when to wrap the pseudo-text cursor to the next screen line when
plotting text on the graphics screen.  By changing these locations without
calling the BIOS video function 00h (Set Video Mode), you can fool the BIOS
into plotting wider, 40-column text on the 640x200 "B&W" graphics screen.  This
way you can have wide "headline" text and narrow "copy" text on the same
screen.  See the accompanying demo program for an example of this.
 
  Due to the "digital snow" problem on the IBM CGA and some compatibles, the
video BIOS "blanks" the screen on these boards briefly during a scroll or clear
(BIOS video functions 06h and 07h, "Initialize Window or Scroll Window Contents
Up/Down"), to prevent the simultaneous CPU/video access to the video buffer RAM
which triggers the "snow".  Because of this, it must reset bit 3 (value 08h),
the CGA_C_Video bit of the CGA_Control port at 03D8h, then set it back to a "1"
when done.  This means that it has to have a place to get the proper value to
use for the non-changed bits, since that port is write-only.  Thus the location
called "CRT_MODE_SET" at offset 0065h.  Because of this, however, any change
you make directly to the CGA_Control port, such as resetting the CGA_C_Blink
bit (bit 5, value 20h) to disable blinking text in exchange for a full 16
background colors in text mode, will be undone the next time BIOS video
function 06h or 07h is called to scroll or clear the screen.  The solution is
to also change those bits in the CRT_MODE_SET scratchpad RAM location, whose
intention is to "mirror" or "shadow" the contents of the CGA_Control port, so
that the changed bits will be put back into the CGA_Control port when the next
scroll or clear is done.   Once again, see the accompanying demo program for an
example of this.

  By using this technique, you can also have this effect work for both the CGA
and the MDA, by using only one POKE then making sure that the screen is either
cleared or scrolled by the BIOS afterwards.  Of course, the MDA cannot display
16 colors no way no how, but it CAN, if the MDA_C_Blink bit (bit 5, value 32)
is reset in the MDA_Control port (03B8h), display both bright and dim
backgrounds for reversed (inverse) text.  Because the BIOS handles the work for
both the MDA and the CGA, resetting the Blink bit in the CRT_MODE_SET BIOS
scratchpad RAM byte, then doing a BIOS video function 06h or 07h call, will set
the appropriate Control port automatically.

  This technique is used in one of our Happy Hacker programs this month, called 
"COLOR".  See the "about" file on "COLOR" for more details.  The enhancement 
which concerns us here is the ability to set a bright background color without 
blinking, which persists through screen scrolls and clears.  Now you know how 
this is done.

  You may have noticed throughout this series that mention of the Enhanced
Graphics Adapter (EGA) was kept to a minimum.  There were several reasons for
this, not the least of which was that I was just not familiar enough with it. 
The required technical documentation was not as available to me.  Fortunately,
this has changed, and starting next issue, we will be specializing in the EGA. 
We will re-cap the previous articles dealing with registers, ports, BIOS calls
and this current article on BIOS scratchpad RAM from an EGA standpoint.  Next
issue:  Introduction to the EGA.
