Access to the Hardware: Low-Level Support

The DOS ROM-BIOS (Read Only Memory-Basic Input/Output System) provides an interface between programs and the operating system to perform various functions, including disk, file, printer, and screen I/O. For specific information on the ROM-BIOS, refer to the DOS Technical Reference Manual.

Visual Prolog provides six built-in predicates that give low-level access to the operating system, I/O ports, and hardware. These predicates are bios (2 versions), ptr_dword, memword, membyte, and port_byte.

This section describes each of these predicates in detail and provides some practical examples that demonstrate how to use them.

(1) bios/3 and bios/4

bios gives access to the PC's low-level BIOS (Basic I/O System) routines. For information about these routines, refer to your DOS Reference Manual. Note that the bios predicates only relate to DOS. Under UNIX, it's possible to access routines in shared libraries using the nlistnlist library call (see nlist(S)). However, the process is rather involved and won't be described here. See NLIST.PRO in the PROGRAMS directory for an example.

Information passes to and from the BIOS functions through the predefined compound object reg(...). The bios predicate takes the following forms:

    bios(InterruptNo, RegistersIn, RegistersOut)        /* (i,i,o) */
    bios(InterruptNo, RegistersIn, RegistersOut, OutFlags)
                    
                                                  /* (i,i,o,o) */

where RegistersIn and RegistersOut are data structures defined as follows:

    /* RegistersIn */
       reg(AXi, BXi, CXi, DXi, SIi, DIi, DSi, ESi)
                                                                   /* (i,i,i,i,i,i,i,i) */

    /* RegistersOut */
       reg(AXo, BXo, CXo, DXo, SIo, DIo, DSo, ESo)
                    
                                       /* (o,o,o,o,o,o,o,o) */

The bios predicates use the arguments

AXi, BXi, CXi, DXi, SIi, DIi, DSi, and ESi to represent the PC's hardware register values passed to the BIOS.

AXo, ... , ESo for those register values returned by the BIOS.

The flow pattern for bios/3 is (i,i,o); for bios/4 it's (i,i,o,o). When you make a call to the BIOS, each argument of RegistersIn must be instantiated (bound to a value), and each argument of RegistersOut must be free (not bound to a value).

The domain for the RegistersIn and RegistersOut compound objects (reg(AX, BX, ...)) is the reg domain, a predefined data structure created by Visual Prolog specifically for the bios predicate. Internally, Visual Prolog defines this data structure as

    DOMAINS
   
    reg = reg(integer, integer, integer, ..., integer)

The optional OutFlag argument in the bios/4 predicate is packed coding for the 8086 flag register (see Figure 15.1). OutFlag allows you to read the contents of the status flags after return from the interrupt. The flags are packed in an integer value as shown here:

Figure 15.1: Packing the 8086 Flag Register in an Integer

U

U

U

U

O

D

I

T

S

Z

U

A

U

P

U

C

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

 

Code

Flag

Flag's Purpose

U

Undefined; indeterminate value

Not used

O

Overflow flag 

Indicates arithmetic overflow

D

Direction flag

Controls left/right direction in repeated operations

I

Interrupt enable flag 

Enables interrupts (when set)

T

Trap flag

Generates a trap at end of each instruction (for trace)

S

Sign flag

Indicates negative result or comparison if set

Z

Zero flag

Indicates zero result or equal comparison

A

Auxiliary flag 

Need adjustment in BCD (Binary Coded Decimal) operations

P

Parity flag

Indicates even number of bits set

C

Carry flag 

Indicates arithmetic carry out bit

(2) ptr_dword

ptr_dword returns the internal address of StringVar, or creates the string ("the char pointer") StringVar based on the supplied address.

    ptr_dword(StringVar, Seg, Off)             /* (o,i,i), (i,o,o) */

When StringVar is bound, ptr_dword returns the internal segment and offset for the string. When Seg and Off are bound, ptr_dword binds StringVar to the string stored at that location. On 32-bit platforms the segment is ignored. ptr_dword has to a considerable extent been superseded by the cast function.

A string in Visual Prolog is a series of ASCII values terminated by a zero value. You can use the low-level routines in this chapter on abnormal strings (those that contain several zero bytes). However, you can't write abnormal strings out or assert them in the database.

(3) membyte, memword, memdword

Visual Prolog provides three predicates for looking at (peeking) and modifying (poking) specific elements in memory. membyte, memword and memdword access byte, word and dword sized locations respectively. All predicates have two formats:

    membyte(Segment, Offset, Byte)             /* (i,i,i), (i,i,o) */
    memword(Segment, Offset, Word)
           /* (i,i,i), (i,i,o) */
    memdword(Segment, Offset, DWord)
        /* (i,i,i), (i,i,o) */

and

    membyte(StringVar, Byte)                          /* (i,i), (i,o) */
    memword(StringVar, Word)
                        /* (i,i), (i,o) */
    memdword(StringVar, DWord)
                     /* (i,i), (i,o) */

The Segment is an ushort, the Offset is an unsigned, and Byte, Word and DWord are byte, word and dword respectively. Many of the bios calls require pointers to be passed as Segment:Offset pairs. membyte and memword also require pointers in this format. In realmode DOS, Memory locations are calculated as ((Segment  ) 16) + Offset).

The mem* predicates have to a large extent been superseded by the get*entry and set*entry predicates for the binary datatype.

(4) port_byte/2

The port_byte predicate allows you to read or write a byte to a specific I/O port. The DOS format for port_byte is

    port_byte(PortAddress, Byte)                  /* (i,i), (i,o) */

where PortAddress and Byte are defined as unsigneds. If you don't know what to use port_byte for, don't worry and don't think about using it. It's intended for access to (custom) hardware using ports for I/O.

Summary

These are the major points covered in this chapter:

1. Visual Prolog includes several predicates that

a. give access to the OS

b. perform bit-level logical and shifting operations

c. provide low-level support for manipulating the BIOS, memory, and other hardware elements

2. These are the predicates giving access to the OS:

a. system (execute external program)

b. time (get or set the system clock)

c. date (get or set the internal calendar)

d. envsymbol (look up an environment variable)

e. comline (read the command-line arguments)

f. syspath (return start-up directory and name of .EXE file)

g. osversion (returns operating system version number)

h. diskspace (returns disk space available)

3. These are the predicates that perform bit-level operations:

a. bitor (bit-wise OR)

b. bitand (bit-wise AND)

c. bitnot (bit-wise NOT)

d. bitxor (bit-wise XOR)

e. bitleft (bit-wise LEFT SHIFT)

f. bitright (bit-wise RIGHT SHIFT)

4. These are the predicates that provide low-level support for various hardware elements:

a. bios (accesses the PC's low-level BIOS routines)

b. ptr_dword (returns the internal address of its argument or places the argument at a specified memory location)

c. membyte (peeks or pokes a one-byte value)

d. memword (peeks or pokes a two-byte value)

e. memdword (peeks or pokes a four-byte value)

f. port_byte (reads or writes a byte to a specific I/O port)