Alt Key routine

A small example to show how to call an assembly routine in Turbo Pascal. (assembly code included)

This file is distributed to show how to call and assembler routine and send parameters w/TP. It calls the assembly routine to see if the Alt-key was pressed. The assembly routine returns a boolean expression.
(0 - False, non 0 - True)

When you call an assembler routine through TP, you must tell the TPC that there will be a standard external function call. It is the same as if you had a sub or a function in TP code, except for the external command.

Example  (TP6.0 code):

    program GetAltKey;

    uses Crt;

    var Prsd : string[25];

    {$L pas2asm.OBJ}  { link in the Assembly .OBJ module }

    function AltKey(P:word): boolean; external;

    begin
      Prsd := 'The alt key was pressed.$';
      repeat
      until AltKey(Ofs(Prsd));
    end.

First, declare the variable Prsd as a string with a length of 25.

The next line tells the compiler to link the assembly files object code with the pascal code. The $L for link, then the name of the .obj file. make sure to put them in comment brackets {}.

Next we declare the function:
function AltKey(P:word): boolean; external;
AltKey is the name of the function.
(P:Word) is the parameter that we are going to send w/ len of WORD
boolean is the type of function. (true or false)
external tells the compiler that we have written this
procedure/function in a different file. (external can
still point at a external pascal procedure/function).

Next we assign the string to the contents we want.
Note: TP will only assign the length amount you declared in the
declare variable above. If you need a longer string, increase
the value of the declare variable above.
Note: Notice the $ at the end of our string. The assembly routine uses
an interrupt call that uses the $ for an end-of-string descriptor. If
you don't put this at the end of the string, the interrupt will keep
printing chars until it hits a $ in memory.

Next we have the program loop until the function call returns a true boolean
expression. Each time the current execution line gets to the until line,
it will call the AltKey function and return a new boolean expression.

Notice we sent the offset of the string each time it loops. I could have
just allowed TP to print a message, but then I couldn't show how to send a
string parameter.
TP6.0 assigns strings with a single byte descriptor at the front. This
unsigned byte has the string length. So each string can be up to 255
chars in length.


The below code has comments for each line. I will explain some of the major parts any way.

The DOSSEG directive is used because I have had errors if it is not there. It tells DOS to use standard DOS segment addressing.

The MODEL large, pascal directive says to use large model memory and make the code pascal compatible.

The 286 directive says to use 16 bit processes. No 32 bit stuff needed here.

The STACK directive says use this amount for the stack. If there is no amount after the directive, then use the default stack size (1k).

The DATA directive says to put the following data in the data segment.

The CODE directive says to put the following code in the code segment.

PUBLIC says to make the procedure public to external sources.

AltKey PROC near pascal uses bp dx, P:word

AltKey is the proc. name
PROC says start here with this proc.
near means near addressing
pascal means code to pascal compatible
uses means save these registers (save all used registers including bp)
P is a parameter as type word

When saving registers, always save the bp (base pointer) register. TP
uses the bp register when accessing memory. If you don't save it, TP most
likely will lock up.

Next, save the registers that you want saved on return to TP. Don't save the ax (accumulative) register when using a function call. If you do this then the return code will not be correct (see below for more info.). Also, don't save the dx (data) register if using a long integer function.

Vars that where strings in TP are declared as a WORD in assembly. When you send the parameter as a string, the WORD that gets sent is the offset of the strings' descriptor. The string itself is not sent. That is why a WORD is to be used to tell where the string is located in memory. (see next for TPs' string descriptors)

TP saves strings in memory with a single unsigned byte descriptor at the first of the string. This byte is the length of the string. So strings in TP can be up to, but not more than 255 chars in length.

The return code is put into the ax register and then a ret command is executed. When the program is back at the TP code, it takes the function as the RC. If the function you defined is an integer, then the ax register is the RC only. If you declare the function as a long integer then both the ax and dx registers are used. dx as the high order word and ax as the low order word.

We return a boolean expression, so we need only to use the ax register.

DOSSEG
.MODEL large, pascal
.286
.STACK
.CODE

Even                             ; align on even byte (word)
          PUBLIC    AltKey
AltKey    PROC near pascal uses bp dx, P:word ; Save registers

          mov   ah,02h           ; get shift status
          int   16h              ; call interrupt
          mov   ah,al            ; save al in ah
          or    al,00001000b     ; set bit number 3
          cmp   al,ah            ; compare al and ah
          je    alttrue          ;
          xor   ax,ax            ; false flag
          jmp   short AltDone    ; Done
alttrue:  mov   dx,[P]           ; print 'pressed' message
          inc   dx               ; skip passed string descriptor
          mov   ah,09h           ; print string function w/$ as EOS
          int   21h              ;
          mov   ax,0FFFFh        ; true flag
Altdone:  ret                    ; R2TP
Altkey    endp                   ; end of procedure
          end