Chapter 7 Basic Input & Output

Fig-Forth v2 has a variety of input and output options, some of which are and are not compatible with other operating systems or specific platforms. Because Fig-Forth v2 was developed with the MS-DOS version 6 platform as its chief interface to the system hardware, it expects that advanced access to the system devices is possible by using their direct commands and individual port mappings. As such, the programmer should be aware of and include in their documentation all cases of possible conflicts from their program with these devices or other platforms. Extensive testing before release is strongly recommended for finished applications.

Fig-Forth v2 uses MS-DOS interrupt calls for character and block access to major devices, with others managed by internal drivers. For the purposes of redirected character input, Fig-Forth uses the DOS STDIN handle and interrupt call to access the system keyboard, and the DOS STDPRN handle for printer output. During these processes all control codes, sub-values and status functions are passed into and from Fig-Forth, thus allowing Forth to be used as a system wide filter of these values.

The Console or System Keyboard

The primary code that handles input is the (KEY) kernel function, which is deferred by Forth through the compiler and language under the symbol of KEY. This code begins its operation as a command line tail active process, emulating keystrokes from the DOS command line after Fig-Forth is started. When the command line is fully processed Fig-Forth falls to a character by character input from the system console, including those zero flags normally sent by Function and Alternate key combinations from the IBM keyboard. Control-C is intercepted and ignored by Fig-Forth and MS-DOS, producing an ASCII 3 as a result. Because of the manner in which BIOS manages the flags of Alternate and Function keys they are always returned as two characters, a zero followed by the ASCII representation of the scan code. Programs requiring these combined keystrokes should expect and interpret the zero flags before making other character tests, or use a definition similar to the one below;

        : 1KEY ( -- c ) KEY -DUP 0= IF KEY 128 + THEN ;

This will return a single keystroke of any type, adding 128 to any special key value found on input. (Ex: Key F1 is ASCII ";" or 59 + 128 which equals 187.) For those programs requiring keyboard activity detection, Fig-Forth v2 uses the ?TERMINAL word which is deferred to the kernel code of (KEY?). Unlike the (KEY) function which waits for a keystroke to be processed, (KEY?) returns a true flag if a keystroke is waiting to be processed, or a false flag is no input is present.

The use of (KEY) and (KEY?) within application programs is to be avoided unless direct, explicit commands from the system console or its redirected input is required. For all other cases, the use of KEY and ?TERMINAL is recommended to allow Fig-Forth to manage the redirection of these input functions as needed. An example of the exception to this rule would be a Modem active application in which Fig-Forth will accept commands from the serial port with the system console having an over-riding priority.

The Printer

As in keyboard access Fig-Forth v2 uses the DOS standard list device handle for any desired redirection, allowing the compatibility with capture programs and devices for this output. The more that is known about the system printer and its limitations the better the interface, for Forth will merely pass the signal codes on to the printer port. The sole form of filtering directed to the printer is the replacement of an ASCII Backspace (Control-H) for all "un-write" characters as described in the Font Printer section.

The primary control for the system printer is the PRINTER variable, which defines when characters are, or are not, sent to this device. When the PRINTER variable contains a true value all characters sent to the (EMIT) kernel function are routed to this output device before they are displayed upon the system console.

For direct access to both the printer and the screen simultaneously, Fig-Forth v2 has the (PRINT) word. This function will send any character other than an "un-write" directly to the primary system printer, without checking the status of the PRINTER variable.

The PC Hardware Ports

Though ordinarily beyond the scope of beginning programmers, Fig-Forth allows direct access to all system data ports using the words of PC@, PC!, P@ and P! respectively. These words are utilized in the manner of their memory access equivalents, prefixed with the letter P to indicate a port function. PC@ reads and PC! writes a single byte only, while P@ and P! send a full word to the function. Note however that in the manner of the hardware the P! function will send one byte to the specified port followed by a byte to the next port in line, while P@ will attempt to read two bytes from the addressed port and its successor. See the Intel CPU reference manual for details.

The Modem

The serial port in Fig-Forth is an alternate device supported by its own internal driver and a 1024 byte character ring buffer. Because this is a direct access driver Fig-Forth may or may not be compatible with other programs desiring to use the serial port in concert with or while Fig-Forth is running. The internal driver is not initialized or tested upon Fig-Forth start-up and no output words have been provided in the default vocabularies, because only the communications input interrupt is required within the kernel code.

The serial port interrupt is controlled via a complex data record located within the starting pages of Fig-Forth's main dictionary, the address of this record returned by the word MODEM-REC located in the MOUSE vocabulary. The values contained in the control record have the following definition;

<address> Pointer to last input received.
<+2> Pointer to next character to be removed.
<+4> Port address of the Status Register.
<+8> Port address of the Data Register.
<+10> Old Interrupt Vector Address. (DWORD)
<+14> The offset to the Kernel Service Routine.

Programs wishing to access the serial device must know the communications address of the desired port, the interrupt service routine number taken when the device generates an input request, and the values to be programmed into the port. After the values are properly computed the locations of MODEM-REC+4 and MODEM-REC+8 must be set to their proper entries, and the interrupt vector changed and saved as indicated.

Once all locations are properly programmed Fig-Forth v2 allows transparent input from the communications device through the words of (MKEY?) and (MKEY). These functions operate similar to their keyboard equivalents, with the exception that (MKEY) will return a zero if no character has been received. Thus applications should test the (MKEY?) flag for received character validity, then return the contents of (MKEY). The below shows a sample interface;

          0 VARIABLE MINT#  -- current interrupt values used

          : IRQ3 2092 MINT# ! ; -- set IRQ #3

          : IRQ4 4144 MINT# ! ; -- set IRQ #4

          : COMDAT MODEM-REC 6 + ; -- data location

          : COMSTAT MODEM-REC 4 + ; -- status location

          : COMS DUP COMDAT ! 5 + COMSTAT ! ; ( SET PORT ADR )

          : COM1 1016 COMS IRQ4 ; -- set com1 addresses

          : COM2 760 COMS IRQ3 ; -- set com2 addresses

          : INTE COMDAT @ 1+ ; ( INTE REGS )

          : LCMD COMSTAT @ 2- ; ( LINE CMD REGS )

          : CMD COMSTAT @ 1- ; ( CMD REGS )

          : SETDIV 115200. ROT M/ DROP 128 LCMD PC! COMDAT @ P! ; ( SET BAUD )

          : SETCOM ( N - ) SETDIV 7 LCMD PC! 11 CMD PC! ;

                   ( SETUP 8 BITS, BAUD, ETC. )

          : <MEMIT?> COMSTAT @ PC@ 32 AND ; ( OK TO SEND? )

          : <MEMIT> COMDAT @ PC! ; ( MODEM SEND )

          : MODEM-ON MINT# @ IF MINT# C@ 0 2L@ MODEM-REC 8 + 2! CS@

              MODEM-REC 12 + MINT# C@ 0 2L! ELSE ." NO INTERRUPT VECTOR!"

             ABORT THEN 33 PC@ MINT# 1+ C@ 255 XOR AND 33 PC! 1 INTE PC!

             32 32 PC! ;         ( SET VECTOR AND TURN ON PORT )

          : MODEM-OFF MINT# 1+ C@ 33 PC@ OR 33 PC! MODEM-REC 8 + 2@ MINT#

               C@ 0 2L! 0 MINT# ! 0 CMD PC! 0 INTE PC! ; ( MODEM OFF )

          : RAW BEGIN <MEMIT?> UNTIL DUP <MEMIT> ; -- can send?

          : LET'S-TALK BEGIN (MKEY?) IF (MKEY) EMIT THEN -- allow modem response

              ?TERMINAL IF KEY DUP -27 +UNDER OVER IF RAW ELSE DROP -- get key

               THEN ELSE 1 THEN 0= UNTIL ;  -- & transmit until Esc pressed

          COM1 2400 SETCOM MODEM-ON LET'S-TALK MODEM-OFF -- gab a little

Note that the programmer is responsible for setting both the serial chip settings and the programmable interrupt controller in the system hardware. (Though the method used here is outdated.)

As a final entry Fig-Forth v2 contains a constant located in the dictionary space at offset 6 decimal, in which a 6 @ will retrieve the Kernel offset to the 1024 byte ring buffer used by the serial device. This location is provided for those unusual cases where the character contents of the buffer must be reloaded by "backing up" the output pointer above and simulating characters received.

The Mouse

The mouse pointer in Fig-Forth is managed both by the standard OEM driver and a code segment inside the Forth Kernel, because of the wide range of video modes possible in Fig-Forth v2. These additional routines provide advanced cursor control and display, movement and button interface, and several words for controlling the mouse once the driver has been extended properly. Not all of these functions may be required by any single application program, but are located in the MOUSE vocabulary along with the Modem words. (The general thinking being both are commonly serial devices.)

Before using the mouse application programs should execute the MOK? word and test for a valid flag being returned, indicating that Fig-Forth was able to add its driver extension to the current system mouse handler. The additional code takes over the function of displaying the mouse cursor and reads both mouse position and button status on any interrupt call to the OEM driver. As such simple mouse calls can be performed without requiring the use of the DOS interrupts or other advanced functions, however the programmer should note that displaying the mouse cursor is a polled function in Fig-Forth and controlled by the following words;

MSHOW

Executing this word will cause the mouse cursor to appear on the screen, either in text or graphics mode using the default or current mouse cursor. In graphic modes any underlying image is internally buffered by the driver, however it is recognized that phasing errors can occur with this saved data. As such, programmers should utilize both the hide and show functions to preserve the screen contents.

MHIDE

This word turns off Fig-Forth's internal mouse display routine, though does not disconnect Fig-Forth's driver extension from the interrupt chain. (This is performed by MCLR.) Any saved image preserved by MSHOW is returned to the screen area where the mouse was last located, and the internal display routine is disabled.

MBUTTON

This is the basic system call for the Fig-Forth mouse function, which in addition to displaying and updating the mouse cursor for the current video mode also returns the status of the active mouse buttons. The button status word is a bit mapped function; the left button indicated in bit 0, the right button in bit 1, and any center button in bit 2. The programmer should be aware that no "click count" or button release testing is performed by this routine, so it is up to the application to make these checks. In addition, the mouse display function is a polled operation, such that application programs should call this function repeatedly while awaiting input. A sample of such code is displayed below, using the keyboard encoding concept defined under the console section of this chapter;

: 1KEY ( -- c ) BEGIN ?TERMINAL ( test keyboard for activity & get flag )
     MOUSE MBUTTON FORTH IF ( process mouse & get click if any )

( mouse activity call-back code goes here )

     THEN UNTIL ( Terminate test loop )
     KEY 0= IF KEY 128 + THEN ; ( get keyboard character )

MX and MY

These two words return the current X and Y position of the mouse cursor, whether or not it is currently displayed on the screen. These values are signed integers with the upper left corner of the screen being the origin and are offset by the values of the "hot spot" defined below for mouse cursors.

The next three words of mouse control are MSPEED, MSETX and MSETY, which control mouse movement speed and display limits of the cursor respectively. The double word system variable of MSPEED has an independent X and Y acceleration value, allowing for scaling of mouse movement in both possible directions with a single operation. However, the values saved in MSPEED interact with the values given to MSETX and MSETY, so application programs should set the speed variable first.

MSPEED

This double word variable controls the mouse movement multipliers, the address returned pointing to the X value followed by the Y value. Both values may be accessed as two single precision numbers or a single double word, in which case the X value is the upper word and the Y value is the lower word.

MSETX and MSETY

These words define the limits of the mouse cursor movement, starting with the lower value as the top of stack and up to the higher value as the second item. Note that both these values are multiplied by their MSPEED counterparts before use by the mouse routines, then are passed on to the system mouse driver. The flag values returned by these words are the error code from the DOS mouse driver if any.

MARROW and MHOUR

The next level of mouse control is that of the mouse cursor, of which four cursor types are provided. Because of the wide range of video modes in Fig-Forth two arrow images and two hour glass waiters are included in the default vocabulary. Both MARROW and MHOUR are constants which may be accessed by name or by ' (tick) and @ such that the mouse driver's display pointer may be changed or set to that image as required by the video mode. These images are 16 pixel by 16 line bit maps of 256 colors, preceded by two cursor "hot spot" pointers in two single precision values. A brief overview of the cursor structure is shown below;

addr

word

-1 ; Hot Spot offset for X
word -1 ; Hot Spot offset for Y
byte 16*16 dup ? ; the cursor image in pixel index values

Note that this structure is contained in the MOUSE vocabulary, however the values returned by MARROW and MHOUR are constant pointers to these images. For the purposes of clarification the following assembly language code defines this constant structure;

addr word offset (image structure) ; the large image
label $ ; first mouse image structure -- the small image

The definitions of "large image" and "small image" in this context refers to the apparent visual result produced by the mouse cursors on the standard graphical screen, as based upon the default OEM driver's image in Fig-Forth's various modes. For example, when the screen is in the MGR mode or BIOS mode 12 hex, (640x480x16 colors) the standard 16 pixel by 16 line arrow appears to occupy roughly a one-quarter inch square. In mode 13 hex (320x200x256 colors) this image appears 4 times larger, owing to the decreased resolution of the screen in pixel and line count. The "small" images saved in the vocabulary will correct for this condition, making the mouse appear as it does in the former mode 12.

MBUFFER

This word returns the address of the last saved mouse background image, which user programs may elect to restore to the video memory before calling the functions of MZERO or MCLR defined below. This area is exactly 256 bytes in size, or the 16 pixel by 16 line definition of the mouse cursors.

MCURSOR

This word sets the current mouse display in the graphical modes, having no effect upon the text based mouse. This function requires an address to the above mouse cursor structure, extracting the hot spot pointer values and cursor image from the memory buffer. Note that when the position routines are called the value returned will be offset by the hot spot locations, such that the values of 8 X and 8 Y will return a position report 8 pixels and 8 lines higher than the upper left corner of the displayed mouse image.

MZERO

This word resets the current mouse pointers inside the Fig-Forth kernel, in the event the mouse position gets out of phase with the system. This has the effect of forcing the mouse to the upper left corner of the screen, where it may be tracked from this position by the user.

MCLR

This final word attempts to reset the OEM mouse driver, removing Fig-Forth from the interrupt service. Though not all mouse drivers understand the purpose of this call user applications may attempt to use this call to share the mouse resource. MCLR is automatically executed as Fig-Forth v2 shuts down.

The Text Screen

Fig-Forth v2 implements the text screen as a fully adjustable window of character columns and text display lines, using a specialized internal driver to the video hardware. These windows are scrolled by the (CR) function without character buffering, and changing the display window size does not buffer the underlying text. Programming the window set is achieved through several system variables and the embedded routines, most of which are available to user applications. (See also the Advanced Input and Output video section for enhancements to the characteristics listed below.)

The parameters of the text display window are controlled by six system variables, VTOP, VLEFT, VWIDTH, VLENGTH, ATTR and CUR. Of these the first four variables describe the current window's physical parameters, in number of character rows or columns as is appropriate. The final two variables control the text display values and current location, as described below. Please note that changing any of these values may allow improper operation of the video text driver, so careful use is recommended.

VTOP

This variable defines the top most row to be used as the current text window, valid values being from 0 to 23.

VLEFT

This variable will set the left margin of the current text window, valid values being 0 to 78.

VLENGTH

This variable defines the length of the display in number of lines, range 25 to 1.

VWIDTH

This variable defines the width of the display window in columns, valid values being 80 to 1.

ATTR

This combined value controls the foreground and background colors of the text character to be displayed, and at times the character set to be used. The format of this variable in Text mode is such that bits 0-3 are the foreground color, bits 4-6 are the background color and bit 7 is the blink or intensity flag. In Graphics mode the variable holds the byte value of the color selected from the current palette, which will be used as the ink of the characters shown. Text mode also uses the byte located at ATTR-1 which should be zero for normal operation, because the value at this location is added to the display character. If the byte at ATTR-1 contains a 1 for example, the character of ASCII A (number 65) will be displayed as ASCII B (number 66). This byte has no effect in the Graphics mode, and is lost when that mode is engaged.

CUR

This variable is the text display cursor location, in bytes from the start of the video screen. Because each text character consists of two bytes (the character and its attributes) all values saved in this variable should be divisible by 2 when in text mode. (bit 0 equals zero.)

CLS

This function will blank the current text or graphics window, using the current background color in ATTR to fill the screen.

Finally, specific DOS interrupts may be called to select most any video text mode available by BIOS, which can change the limits of the above variables for specialized printing. Fig-Forth contains two versions of these basic calls and two system variables for the definition of the hardware being used, such words outlined below;

COLOR

This function sets up the video screen into an 80 column by 25 line text screen with CGA style interface. This mode allows 16 foreground colors and 8 background ones, with an alternate option of 8 ink colors and flashing or high intensity setting for displayed characters. (Implemented by the hardware used and the BIOS system calls.) This word also sets the values of VID and CRTC listed below, to the memory location of the video buffer and the controller access port. (0B800Hex and 3D4Hex.)

MONO

This function sets up the video screen into an 80 column by 25 line monographic text mode, utilizing the old standard IBM PC style of communication. As in the COLOR word this function sets the values of VID and CRTC listed below, to the location of the screen buffer and the controller access port. (0B000Hex and 3B4Hex.)

VID

This variable contains the current segment of the video screen memory buffer address, 0B000Hex for monographic text, 0B800Hex for color text, and 0A000Hex for graphical modes.

CRTC

This variable contains the current video controller access port value, 3B4Hex for monographic text modes and 3D4Hex for 16 color text and graphical modes.

TEXT

This function of the video interface is used to set the default text mode of the video screen, usually an 80 column by 25 line 16 color display. This function calls the IBM PC BIOS interrupt of 10 Hex, with a value of 3 as the operative parameter. As defined in Advanced Input and Output this word also sets the VMODE control byte, see chapter 8 for its description.

The System Speaker

Fig-Forth implements access to the system control speaker port using a single value to control this device. When the ASCII code of 7 or Bell character is sent to the standard text driver this device will generate a control beep, whose length can be defined by the VBELL system variable. Note that when the Font Printer described in chapter 8 is in operation this output call is not utilized, so this variable bears no meaning in that event.

Files

Files in Fig-Forth v2 are accessed through assigned MS-DOS handles from the time of opening and beyond, then mapped into the user space via 4 disk access buffers. Using MS-DOS handles presents a problem in that the DOS system allows reading or writing beyond the end of the physical file or drive, and in a typical installation DOS will only allow 20 files to be opened at any time, though by reusing handles and careful checks the programmer can work around these limitations. Once the file collection is selected Fig-Forth maps the file access into a block or array type of definition, using the functions as listed under Variables and Math to manipulate the file contents. (Chapter 2) These "file arrays" or records are placed into the upper portion of the user space, protected from all but the most serious errors or catastrophic events. Changes to a file must be marked explicitly though several words do this internally (Advanced Input and Output, File Streaming Words) and files must be closed to inform DOS of their new contents.

OPEN

The first Forth word for file access is the open operation, which takes a stack parameter and the next space delimited string to call DOS for the file handle. Because this is a space delimited string the file name must appear in 8 and 3 letter format for DOS files, including the period character between name and type extension;

          20 OPEN MYFILE.DAT

At the time of the open the file name is added to the end of the dictionary, converted to upper case and then assigned to the next file control block area of Fig-Forth. This is an explicit open command to MS-DOS, meaning the file requested must exist in the current directory or search path or an error will result. The integer parameter given in the command is the starting block address assigned to the file, meaning that the first 1024 bytes of the file above is read by saying 20 BLOCK. Files can be assigned any arbitrary starting value but should not overlap in their contents, or the data contained within them may become corrupted. For Fig-Forth v2 all disk access blocks are unsigned values, ranging between 1 and 65535. (Even though a zero offset is allowed Fig-Forth will not transfer any data for this specified block.)

OPEN-FILES

This function is used to open the current file collection after it has been constructed, as in saving the Forth environment and wishing to reconstruct it. This same process may be called after a CLOSE-FILES operation, to establish a new arrangement or collection of files required by the program. As with OPEN, all files must exist in the search path or an error will be generated.

CLOSE

This word is used to close any specific file in the current collection, starting with the first which is numbered as file zero. Note that files which are closed will generate disk errors if their access is attempted, so care must be employed.

CLOSE-FILES

This word will close all files open in the current arrangement, in preparation for using SAVE to create application executables. In this event the file system is left intact by the virtual machine, for subsequent use of OPEN-FILES.

RESET-FILES

This word closes all files and resets the file control system, removing all references to the current files. Note however that file names are not removed from the dictionary area, owing to potential compilation of definitions after their names.

DISK-ERROR

This system variable contains the error code sent by DOS in the event of a disk access error.

BYTES-MOVED

This system variable contains the number of bytes transferred during the last read or write operation, which is either the remaining length of the file or the size of the buffer. This value will be zero if at the physical end of a file or disk drive, which is not counted as an error by MS-DOS.

EMPTY-BUFFERS

This word will discard all data contained in the file access buffers, filling the area with nulls.

FLUSH

This word will force all changes contained in the disk buffers onto the disk drive, by writing out the contents of any update marked buffer to its respective file. If the buffer location is beyond the current limit of the file it will be extended to contain the new data, though the length value of the file won't be updated by DOS until the file is closed.

OFFSET

This variable is used to establish the current file of focus within a Fig-Forth application, adding its contents to any requested disk access granted. If the file MYFILE.DAT is open as shown above at block number 20, setting offset to 5 will mean the file now begins at block 15 for all subsequent access.

BLOCK and VBLOCK

Once a collection of files has been established these two words allow access to the files, by using a block number for BLOCK and a double word byte offset for VBLOCK. Each function will attempt to read 1024 bytes from the file accessed and place them into one of the four disk buffers, then will return the dictionary space address of the buffer filled. Once at this point the access memory words may be employed to manipulate the file contents. Which file provides the targeted data depends upon the opening arrangement and the current offset value, as in the following examples;

          1 OPEN EDIT.4TH 20 OPEN MYPROG.4TH 100 OPEN MYDATA

          20 BLOCK -- read start of MYPROG.4TH

          20 OFFSET ! -- change offset value

          -10 BLOCK -- get block #9 of EDIT.4TH

          100 BLOCK -- get block #20 of MYDATA

          0 OFFSET ! -- reset pointer

          100. VBLOCK -- read first screen of EDIT.4TH offset by 100 characters

.FILES

This word will list the files currently open in Fig-Forth, giving their file number, current block numbered offset, their names and the open lengths. If the file name was part of a forgotten word or vocabulary the name string in this listing will be changed to "unknown."

#FILES

This variable holds the count of files currently open, and the number that will be assigned to the next file after openning.

UPDATE

This word will mark the last accessed disk buffer as containing changed data, meaning a FLUSH operation or the next disk access for that buffer will write the data to the disk drive.

INDEX

This utility word will print the first line (or the title comment as defined under Using The Block Editor) of multiple screen blocks, to aid in locating portions of source text. The format of this command is <starting-number> <ending-number> INDEX.

LIST

Finally, this word will list the contents of any single screen block, as 16 lines of 64 characters. One should note that this operation prints ASCII control characters in their standard format, including carriage returns and line feeds.

Return to Contents.   Next Chapter.   Previous Chapter.