
                               HOW GDOS WORKS
                               ==============
                            By: Mrten Lindstrm


 Most of you already know what GDOS  does  for a user or general application
 programmer. Essentially the following:

   - Allows the opening of VDI workstations onto other devices than screen.

   - Allows the loading of GEM  fonts  from  disk, for any workstation, also
     the ones on the screen.

   - Allows the use of Normalized  Device  Coordinates  (NDC) instead of the
     accustomed pixel-based Raster Coordinates (RC).

     (The above is what all GDOS  versions give. More advanced versions also
     give Bezier curve drawing  capability  and  outline  font handling, but
     this text is about the basic GDOS; I haven't yet got anything else).

 But anyone who wants to program  a  GDOS  driver, or a replacement for GDOS
 itself for that matter, might want  more  details  on the workings of GDOS,
 and this text is about  what  I  have  found  out  from disassembly of GDOS
 release 1.1.

 According to my investigations  GDOS  release  1.1  allows  a maximum of 16
 workstations - physical and/or virtual  -  by  all  processes in total. The
 workstations are managed through fixed parameter blocks (40 bytes/block) in
 the BSS segment of the GDOS.PRG.


 INITIALIZATION
 --------------
 The pointer to the VDI screen driver  in  ROM is fetched (through a TRAP #2
 with D0 set to -1) and stored.

 ASSIGN.SYS is loaded and interpreted.  Any  drive  and path for the drivers
 and fonts is stored. (Default: the  boot  drive and path.) The filename for
 each font given is stored, and for each device driver given filename plus:-
  - device number
  - flag for resident, permanent (=in ROM) or neither
  - number of fonts plus index (in ASSIGN.SYS) to the first.
 This data is copied down over  the  expended  ASCII  text and then the GDOS
 memory shrunk according to the data + TEXT  + DATA + BSS segments, + 2K for
 a buffer for input coordinate conversions (if NDC coordinates used).

 Any memory  resident  drivers  are  loaded  (into  memory  blocks allocated
 separately for each driver), one workstation  to each resident or permanent
 driver is assigned, and parameter blocks  for these workstations filled in.
 (For the workstations corresponding to permanent drivers, the screen driver
 address, got through TRAP #2 with -1  in  D0,  is entered as the pointer to
 the driver.)

 A message is written  on  the  screen,  with  CCONWS,  stating that GDOS is
 installed.

 Old trap #2 vector saved and the new one installed. Then GDOS is terminated
 with PTERMRES.

 If any fatal error occurred  during  the  above  procedure (file not found,
 illegal format of  the  ASSIGN.SYS  file)  GDOS  will  tell  about this and
 terminate with PTERM instead.

 THE NEW TRAP 2
 --------------
 Register D0 checked:

  If 115:  All registers saved on stack and the new VDI called.
  If  -1:  The pointer to the VDI screen driver loaded into D0. RTE ended.
  If  -2:  The address of the new VDI loaded into D0. Ended with RTE.
  Else  :  Old trap2 vector pushed on stack, then RTS executed.


 THE NEW VDI
 -----------
 Semaphore flag checked and set  and,  if  already  set,  a memory area with
 important data is saved  (making  the  VDI  one  time  re-entrant, though I
 cannot imagine why a cleanly written driver  would  want to make a VDI call
 of its own).

 The operation code (first word of  contrl  array)  checked to see what call
 has been made. All VDI calls  are  passed  on to the driver (as sub-routine
 calls 'JSR' with D1 pointing  to  the  VDI  parameter block), but GDOS also
 performs some processing of its  own,  which  is  different  for six of the
 calls:   V_OPNWK,   V_OPNVWK,   V_CLSWK,   V_CLSVWK,   VST_LOAD_FONTS   and
 VST_UNLOAD_FONTS.

 V_OPNWK: A workstation is found for  the requested device. If a workstation
 was already assigned (for a  permanent  or  resident  driver)  it is just a
 matter of finding this workstation  (parameter  block). Otherwise an unused
 workstation must be found and the  driver  loaded (and relocated). Then the
 driver is called (as a  sub-routine)  and  the  handle  given by the driver
 stored within the workstation parameter  block.  (This handle may of course
 be different from the one selected  by  GDOS;  only the GDOS handle will be
 visible to the calling application,  and  only the driver's own workstation
 handle is known to the driver; GDOS translates between them).

 Likewise the width and height of the workstation, returned by the driver in
 intout[0] and intout[1] will be stored  (to  be  used in any NDC coordinate
 transformations).  If  NDC  coordinates  are  used,  the  intout  array  is
 transformed (the return in D0  from  the  driver  will determine whether to
 reverse Y axis direction or  not;  0=reverse,  other=don't). Then the GDOS-
 selected VDI handle is written to contrl[6].


 V_OPNVWK: Similar to V_OPNWK but  first  the physical workstation is found,
 corresponding to the handle given with the call, and checked to see that it
 is OK and its driver is loaded. Then an unused workstation is found for the
 virtual one to be now opened and  the driver of the physical workstation is
 called.


 V_CLSWK and V_CLSVWK: In  both  cases  the  driver  is  called first (after
 translating the handle). Then fonts  will  be  unloaded. (If they have been
 loaded for this workstation but for no  other one corresponding to the same
 physical workstation, the memory blocks for fonts and character buffer will
 be freed). If V_CLSWK was  called,  the  memory  of any non-resident driver
 will likewise be freed, but V_CLSVWK merely  leads to a 'driver ready' flag
 being cleared.


 VST_LOAD_FONTS:  If  fonts  have  already   been   loaded  for  some  other
 workstation corresponding  to  the  same  physical  workstation,  then  the
 pointers  are  merely  copied  to  the   parameter  block  of  the  current
 workstation. Otherwise the  fonts  are  loaded,  converted  from  PC  to ST
 format, and sorted according to  font  ID  and  point  size (the sorting is
 performed merely by changing pointers in  the linked chain of font headers,
 not by physically moving any font headers  or  data). Any font with font ID
 and size both the same as for  another  already loaded font will be skipped
 and its memory freed. Finally a memory  buffer,  the size of which is based
 on the maximum character size in any font is allocated.

 A copy of the contrl array is made  within the GDOS BSS area, and at offset
 14 (contrl[7-8]) is written a pointer to the character buffer, at offset 18
 (contrl[9]) the length of this  buffer  and  at offset 20 (contrl[10-11]) a
 pointer to the first font header in the chain. Then the driver is called.


 VST_UNLOAD_FONTS: The fonts are  unloaded.  (If  they  have been loaded for
 this workstation but for no  other  one  corresponding to the same physical
 workstation, the memory  blocks  for  fonts  and  character  buffer will be
 freed.) Then the driver is called.

 Other VDI calls: GDOS VDI handle translated into driver internal handle. If
 NDC coordinates used then any elements  in  the  ptsin array are copied and
 transformed in a 2K buffer  reserved  by  GDOS  during  bootup (room for 1K
 words or 512 coordinate pairs).  Then  the  driver is called and afterwards
 any ptsout will be transformed if  NDC  coordinates are used (the return in
 D0 from the driver will determine  whether  to  reverse Y axis direction or
 not).

 In all cases the VDI will  end  by  clearing  its semaphore and restore any
 variables if needed (see start of VDI).


 The character buffer
 --------------------
 The size of the character buffer is calculated according to an unbelievably
 intricate formula, which I think is as follows:-

     (2 * MAX( MAX((2H+3)*bytes(2W+T),(2W+3)*bytes(2H+T)) ,
               MAX(2H*bytes(W),2W*bytes(H)) )
       +  MAX( bytes(2W+T)+3 , bytes(2H+T)+3 )
      )/2 evened down

 which reasonably should be possible to simplify to:-

     ( 2 * MAX((2H+3)*bytes(2W+T),(2W+3)*bytes(2H+T))
        +  MAX(     3+bytes(2W+T),     3+bytes(2H+T))
      )/2 evened down

 Where  bytes(x) is  (x+15)/16*2   -  i.e.  the  evened  up  number of bytes
 required to hold the given number of bits.

 H is the form height (got from word at offset 82 in font header)
 W is the sum of max character cell width + left offset + right offset
     (got from words at offset 52, 54 and 56 respectively)
 T is the 'thickening size' (from word at offset 58)

 This calculation is repeated for each  loaded  font and the maximum for all
 fonts used to  reserve  a  memory  block,  except  with  a  metafile driver
 (31-40).

 Basically this should result in a  buffer  with room for the single largest
 character in any font with its width and height doubled and with some extra
 margins too.



                       HOW A GDOS PRINTER DRIVER WORKS
                       ===============================

 This text describes what I have  found  out about the FX80.SYS driver, that
 came with GDOS release 1.1,  from  disassembling  it. I still haven't fully
 analysed the disassembly (in  particular  I  haven't  delved  much into the
 routines that do the actual  drawing)  but  think  I  can describe the main
 routines (in particular V_UPDWK at  the  heart  of  the driver) and how the
 driver deals with files and memory.

 The purpose of my investigations was to  give information on how to write a
 GDOS driver of our own, but I think that some of the findings might also be
 of use to people merely programming printer output for GDOS.



                                General notes
                                -------------

 The driver FX80.SYS (like  the  GDOS  program)  seems  to  be  written in a
 compiled language (presumably  C)  and  not  assembler,  which  can be seen
 (among other things) from  the  very  inefficient  way  that data are often
 handled. (On the other hand, the  size  is probably acceptably small anyway
 and speed no problem at all in a printer driver).

 The driver retains all registers except D0 which is always set =1.

 The main routine will in addition:
 (1) for some reason make its own copy of the ptsin array
 (2) clear contrl[2] and contrl[4] (the lengths  of the output arrays; later
     possibly to be changed by individual functions)
 (3) on any call other than V_UPDWK,  free any full-workstation bitmap image
     buffer allocated by a previous V_UPDWK (see below)
 (4) execute the specific routine called.


                            The GSX display list
                            --------------------

 The output commands (with the  exception  of V_ALPHA_TEXT) cause nothing to
 be printed at the time they are  called.  Instead they are stored in a "GSX
 display list", for  which  a  memory  buffer,  reserved  and cleared during
 V_OPNWK, is used.

 Should this memory buffer become filled  up, a file GSXPRN$$.SYS is created
 in the root of the disk that  happens  to  be  the current one at the time.
 Each time the memory GSX buffer is  filled  up, its contents are written to
 the end of the file  and  the  memory  pointer  reset  to  the start of the
 buffer.

 The attribute setting commands are also  written to this "display list" but
 in addition cause internal variables to  be  immediately set (so that these
 can be correctly inquired for instance).  A  flag is maintained that is set
 by calls of any output  functions,  but  not  by calls of attribute setting
 functions. (This flag is used  to  determine  whether  there is anything to
 print when V_CLSWK is called).

 The format of commands in the display list is one leading byte with the VDI
 function number, then possibly one or two further bytes with small integers
 (e.g. flags, sub-opcodes etc.) and  any  other  integers, plus all "points"
 (coordinates), stored  as  words  (but  not  necessarily  word  aligned). A
 function number = 0  marks the end of the display list.

 Note that once created, GSXPRN$$.SYS is  kept  open (by the FX80.SYS driver
 I've examined) until V_OPNWK,  when  it  is  closed  and  deleted. Calls of
 V_CLRWK and V_CLEAR_DISP_LIST will however trigger an FSEEK to file start.


 When V_UPDWK (or V_OUTPUT_WINDOW or V_CLSWK) is called, any contents of the
 GSX memory buffer are written to the  end  of the GSXPRN$$.SYS file if this
 file has been created. Then the  complete  GSX  display list will be worked
 through, one or more times depending on whether a large enough bitmap image
 buffer could be allocated to hold  the  complete workstation area. (If not,
 the image will be printed in  strips  and  the complete display list worked
 through for each strip. Since all VDI commands are required to be clipable,
 this doesn't add much complication).

 Before each strip, all settings  (drawing  attributes)  will be restored to
 the default situation (as  stored  after  V_OPNWK).  The GSX memory pointer
 will be reset to buffer start, and if  there is a file, its pointer is also
 reset to file start with an FSEEK  (after  which  the file is to be read in
 portions into the buffer).

 THE MEMORY GSX BUFFER is allocated  during  V_OPNWK  and its size set to 32
 kilobytes except if this would leave  less  than  32 kb free, in which case
 the size is the available size minus 32 kb, but never less than 1 kb.


                           The bitmap image buffer
                           -----------------------

 During V_OPNWK a default minimum  buffer  is  allocated (which the FX80.SYS
 driver makes large enough  to  hold  32  pixel  lines  of image data). This
 buffer is however never used if  a  larger  buffer  can be allocated at the
 time of V_UPDWK.

 When V_UPDWK (or V_OUTPUT_WINDOW  or  V_CLSWK)  is  called, a bitmap buffer
 large enough for the entire workstation  will be allocated, if possible, or
 else larger than the default  minimum  buffer  at  least. In case of severe
 memory shortage, no new buffer  will  be  allocated  and the default buffer
 used instead.

 Exception: If the number of intin's (in contrl[3]) is specified as =2, with
 the V_UPDWK call, then these two integers (intin[0] and intin[1]) are taken
 to form the address (long) of a bitmap  memory buffer, the size of which is
 automatically assumed to be large  enough  for  the entire workstation. (No
 extra  memory  buffer  will  then  be  allocated).  This  feature  can,  in
 combination with the feature mentioned  below,  be  used to send any custom
 bitmap image to the printer via a call of V_UPDWK.

 Before each strip is  drawn  and  printed,  the  bitmap  buffer is cleared,
 except if  contrl[1]  was  set  to  non-zero,  with  the  call  of V_UPDWK.
 (contrl[1] normally gives the number of  ptsin  but with V_UPDWK takes this
 special meaning).

 If a bitmap image buffer large  enough  for the entire workstation could be
 allocated, a special flag will be set  that prevents the buffer being freed
 at the end of the V_UPDWK  routine.  If  further  calls of V_UPDWK are made
 immediately after this, then a quick  routine  will  be used to simply send
 the existing ready-drawn bitmap image  to  the  printer. Any other VDI call
 than V_UPDWK will  cause  the  buffer  to  be  freed  (and  the  flag to be
 cleared).

                                 Form feeds
                                 ----------
 A form feed is sent by  V_FORM_ADVANCE,  V_CLRWK  and, if the previous call
 was a V_UPDWK or V_OUTPUT_WINDOW, at the beginning of a renewed V_UPDWK.
 No form feed is sent at the end of V_UPDWK /V_OUTPUT_WINDOW.


                                  Clipping
                                  --------
 During  the  printing  process,   the   clipping   rectangle  will  be  the
 intersection of the rectangle set with  VS_CLIP, the rectangle of the strip
 currently done, and if  V_OUTPUT_WINDOW  was  called  the rectangle of this
 window. From the point of the individual drawing routines, this won't be of
 any importance of course, since each drawing routine is required to be able
 to do clipped output, regardless of how the clipping rectangle came to be.


                                 Rectangles
                                 ----------
 A sub-routine exists, that can take  any two diagonally opposite points and
 convert them so that the first point becomes the upper left, and the second
 point becomes the lower right corner of the rectangle. This routine is used
 on each rectangle given with any VDI call to the driver.



                         Notes on special functions
                         --------------------------

 V_BIT_IMAGE
 -----------
 This function, outputting a IMG image file, basically works the same way as
 other output functions. (Represented by an  entry  in the display list, and
 eventually leading to output on the same bitmap as others).

 But V_BIT_IMAGE, as implemented in  FX80.SYS,  adds  a  bit to the file and
 memory handling. On  each  call  the  corresponding  IMG  file is instantly
 opened, some preliminary calculations are  performed and some memory blocks
 are allocated and filled with data concerning file and image. The IMG files
 seem to be kept  open  and  the  memory  block  allocated,  until a call of
 V_CLSWK, V_CLRWK or V_CLEAR_DISP_LIST.

 As much as 40 IMG  files  on  the  same  page  (workstation) are allowed by
 FX80.SYS, meaning 40 simultaneously opened  IMG  files and even more memory
 blocks (which TOS 1.x wouldn't be able to deal with, of course). Though you
 may very rarely want more  than  a  couple  of  images  on the same page, I
 personally don't see the point in  doing  things  the  way they are done in
 FX80.SYS. It would seem to me more straightforward to merely save the given
 IMG file specification somewhere (possibly in the display list itself), and
 perhaps check for the existence of the file, at the time of the V_BIT_IMAGE
 call, and to leave file opening and reading until the V_UPDWK call.

 The IMG file seems to be  unpacked  one  pixel  line  at  a time to save on
 memory.


 VRT_CPYFM
 ---------
 This is the only VDI raster function implemented in FX80.SYS. I.e. VR_TRNFM
 is NOT implemented. When working  on  a  general  SCREEN,  a 100% clean GEM
 program is required to use  VR_TRNFM  to  transform  a bitmap from standard
 format to device specific format  before  it  is  copied with VRT_CPYFM (or
 VRO_CPYFM) to screen. But  it  is  perhaps  logical  to  assume that device
 specific bitmap formats are applicable to screens only and that all bitmaps
 for other devices are always in the VDI standard format.

 (VRO_CPYFM is not  implemented  in  FX80.SYS  and  neither  is,  of course,
 V_GET_PIXEL, inquiring a pixel, since the  bitmap image isn't created until
 a V_UPDWK call).

 VRT_CPYFM itself  is  represented,  like  other  output  functions,  in the
 display list, where the  given  MFDBs  are  also  stored. The image bitmaps
 themselves are not stored,  but  merely  the  pointers  to  them (the first
 longword of each MFDB), which of course  means  that the image data must be
 kept unchanged until the call of V_UPDWK for them to come out right.


 V_CONTOURFILL
 -------------
 This function, performing a  flood  fill,  is  NOT implemented in FX80.SYS,
 despite the Atari Compendium stating  V_CONTOURFILL  to be supported by all
 printer  (and   screen   and   metafile)   drivers.   This   is,   however,
 understandable, considering  that  FX80.SYS  (and  probably  other  printer
 drivers) might construct the actual bitmap  image  a single strip at a time
 (which would make  the  spread  of  the  flood  fill  rather complicated to
 calculate  across  strip   boundaries).   My   guess   is   therefore  that
 V_CONTOURFILL is always implemented in  screen  (and metafile) drivers, but
 not normally in printer drivers.


 V_ALPHA_TEXT
 ------------
 This function sends  "alpha  text"  to  the  printer  (i.e. plain character
 output, using the printers built in  font  set).  It is NOT recorded in the
 display list, used by other output functions, but causes instant printing.

 A count of the pixel  lines,  that  have  already been actually printed, is
 maintained by the FX80.SYS driver.  It  is  zeroed  by V_OPNWK at each form
 feed, and updated when anything is actually sent to the printer, whether by
 V_UPDWK/V_OUTPUT_WINDOW or by  V_ALPHA_TEXT.  When  V_ALPHA_TEXT  is called
 this count is used to make sure that  the alpha text is printed on the next
 "text line" (pixel line evenly divisible  by  the pixel height of the alpha
 characters = 24 for the FX80.SYS driver).  If on an "odd" pixel line, micro
 line feeds will be  used  before  printing.  Unfortunately  this pixel line
 count does  not  seem  to  be  consulted  by  the  V_UPDWK /V_OUTPUT_WINDOW
 functions before they are printing.

 The style codes recognized  by  V_ALPHA_TEXT  seem  to  be  limited to bold
 (implemented  through  Epson   "double-strike"),   italics  and  underline.
 Furthermore, unrecognized escape sequences are  not ignored by the FX80.SYS
 driver, as they should be, but may cause rubbish to be printed.


                    Descriptions of the central functions
                    -------------------------------------

 V_OPNWK
 -------

    Set contrl[4]=45 and contrl[2]=6 (number of intout's and ptsout's)

    If there are any ptsin given with the V_OPNWK call, then take the first
     word pair of these to define XRES  and YRES. Otherwise set XRES=959 and
     YRES=1487 (XRES and YRES are the width and height of the workstation in
     pixels MINUS ONE.)

    Initialise various other variables (e.g. Width  of pixel = 212 microns,
     height of pixel  =  176  microns  -  for  a  9-pin  dot matrix printer,
     character lines per page = 66, Height of character in pixels = 24)

    Allocate default 1K buffer for  GSX  display list and default 32-pixel-
     line buffer for bit image. If this fails, clear contrl[2] and contrl[4]
     (number of ptsout's and intout's), set intout[0]=1 and exit.
     (NOTE: This, and I think other, drivers do NOT return a zero handle for
     error, so the GDOS program has, on return from the driver, to check for
     EITHER a zero handle, OR no output  (contrl[2] = contrl[4] = 0). Either
     of these signals an error  and  the  GDOS  program should return a zero
     handle to the calling program. This is of course what GDOS release 1.1.
     does).

    Copy data into intout and ptsout arrays

    Set drawing attributes (and  other  parameters). The drawing attributes
     given with  the  V_OPNWK  call  are  checked  against  boundaries  (and
     corrected if needed). Then save default settings, to be restored before
     each time the display list is to be interpreted during a V_UPDWK.

    Allocate and clear memory buffer for display list. (32 kilobytes except
     if this would leave less than 32 kb free, in which case the size is the
     available size minus 32 kb, but never less than 1 kb).

    "Open printer" as a file "PRN". (I.e.  the actual printing will be done
     by "writing" character output with FWRITE to this "file").


 V_UPDWK
 -------

    If a full-workstation bit-image buffer  is  already allocated and drawn
     by a previous V_UPDWK, then  make  a  form  feed, print this buffer and
     exit.

    If previous call was a V_UPDWK  or  V_OUTPUT_WINDOW  (and this one is a
     V_UPDWK) then make a form feed (send character 12 to the printer).

    Write contents of GSX memory  buffer  to  end of GSXPRN$$.SYS file, and
     reset pointers to start of file and start of memory buffer.

    Allocate (if not given  with  the  call*)  a  memory  buffer for bitmap
     image. If possible large enough  to  hold entire workstation. If buffer
     larger than default buffer cannot be allocated, then use this instead.
     (* If contrl[3]=2 then  interpret  intin[0-1]  (long)  as  address to a
     full-workstation buffer.)

    Do some operations related to any V_BIT_IMAGE calls in the display list
     (I haven't examined this in detail)

    Initialise,  according  to  buffer,  workstation  and  possibly  window
     dimensions, the "buffer Y1" and "buffer Y2" (clipping coordinates to be
     combined, during interpreting  of  the  display  list,  with the actual
     VS_CLIP clipping). If all there is  to  be drawn fits within the buffer
     in one go, then set a "buffer complete" flag.

    For each strip do:

      -  Restore GSXPRN$$.SYS file pointer  to  file  start (with FSEEK) and
         read first part of display list into memory buffer.

      -  If CONTRL[1] is zero, clear the bit-image buffer.

      -  If CONTRL[1] is zero,  AND  next  command  in  display list is also
         zero, then exit.

      -  Restore default settings (as set after V_OPNWK)

         (Here comes a piece of code which I believe could draw some sort of
         frame, perhaps around the drawing  area,  though as implemented all
         coordinates are zeroed.)

      -  Now draw each command in the display  list  (until a command = 0 is
         encountered).

      -  Print the bit-image buffer (exit on  error), update "buffer Y1" and
         "buffer Y2" (clipping coordinates) with  buffer  height and do next
         strip.

    If the "buffer complete" flag (see above)  is not set, then free buffer
     memory.

    Restore default settings (as set after V_OPNWK)

    Restore 6 line per inch (normal dot matrix setting)

    Clear the flag for anything in display list to draw (used by V_CLSWK to
     determine if to print before shutting down workstation).

    Return a zero in intout[0] (and set contrl[4]=1)


 V_OUTPUT_WINDOW
 ---------------
    Fix window rectangle given (so  that  1st  corner  = upper left and 2nd
     corner = lower right)

    Set  window  coordinates  (initialised  to  full  workstation)  to  the
     dimensions of the window given, and  set  a flag for window output (all
     these variables will be checked by the V_UPDWK routine).

    Run V_UPDWK as a sub-routine!

    Restore the window coordinates to full workstation dimensions and clear
     the window flag.


 V_CLSWK
 -------
    If any output functions  (not  counting  V_ALPHA_TEXT) have been called
     since last V_UPDWK, then run V_UPDWK  as  a sub-routine, and after this
     (if needed) free the bit image buffer allocated by V_UPDWK.
    Free the default buffers for GSX display list and bit image.
    Free any memory block allocated  for  IMG  files (by V_BIT_IMAGE calls)
     and close these IMG files.
    Close printer and any GSXPRN$$.SYS file and free GSX memory buffer.


 V_CLRWK ( = V_CLEAR_DISP_LIST + V_FORM_ADVANCE )
 -------
    Clear GSX memory buffer and  reset  pointers (including, with an FSEEK,
     the file pointer of any GSXPRN$$.SYS file written to).
    Free any memory block allocated  for  IMG  files (by V_BIT_IMAGE calls)
     and close these IMG files.
    Make a form feed (and clear the count of printed pixel lines).


 V_CLEAR_DISP_LIST
 -----------------
    Clear GSX memory buffer and  reset  pointers (including, with an FSEEK,
     the file pointer of any GSXPRN$$.SYS file written to).
    Free any memory block allocated  for  IMG  files (by V_BIT_IMAGE calls)
     and close these IMG files.


 V_FORM_ADVANCE
 --------------
    Make a form feed (and clear the count of printed pixel lines).

