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