Turbo Pascal 3

Discussions on programming older machines

Turbo Pascal 3

Postby Vorticon » Fri Jul 30, 2010 6:32 pm

I've been playing quite a bit with Turbo Pascal 3 programming lately, and it is really a very nice development system given its size. However, I keep bumping into certain "omissions" such as the lack of a Power or Tan function among other things. Since there is an ATN function, I'm not sure why the designers decided to drop Tan. A more pressing issue reared its head however when I wanted to poll the keyboard for input in a manner similar to INKEY$ in Basic, only to find out that there is no such thing! There is a function that lets you know when a key was pressed, but in order to capture the key code, one had to access the DOS BIOS interrupts through the intr() function. Needless to say that the manual was very terse on the issue and it turned out not quite accurate in its description of how to set up intr(). I turned to the Turbo Pascal 5 manual which luckily had a better intr() setup description, although it was not needed because TP 5 had a key polling function.
With that information and some hair pulling, I finally managed to put together a key polling procedure for TP3, and I thought I'll post it here in case anyone here needed something similar:

procedure GetKey(var Key,Ekey:byte);
(* Key will return the ASCII code *)
(* For extended keys like cursor keys, ALT etc..., Key will be 0 and Ekey will return the scan code *)
type Registers = record
case integer of
0:(AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags:integer);
1:(AL,AH,BL,BH,CL,CH,DL,DH:byte);
end;
var Res:Registers;
begin
Res.AH:=0;
intr(22,Res);
Key:=Res.AL;
Ekey:=Res.AH;
end;

Walid


Vorticon
 
Posts: 276
Joined: Fri Nov 27, 2009 7:25 am

Re: Turbo Pascal 3

Postby Retro » Thu Jan 06, 2011 6:26 pm

Or you could use inline machine code, which would be more efficient than intr()

Code: Select all
procedure GetKey (var Key, Ekey: Char);
begin
  inline
    ($31/$c0/              {  xor   ax,ax       }
     $cd/$16/              {  int   16h         }
     $c4/$be/Key/          {  les   di,Key[bp]  }
     $88/$05/              {  mov   [di],al     }
     $c4/$be/Ekey/         {  les   di,Ekey[bp] }
     $88/$25)              {  mov   [di],ah     }
end;
Last edited by Retro on Mon Jan 10, 2011 12:14 pm, edited 6 times in total.
Retro
 
Posts: 5
Joined: Sat Jan 01, 2011 10:56 am
Location: New Zealand

Re: Turbo Pascal 3

Postby Brutman » Thu Jan 06, 2011 8:32 pm

Thank you both for posting those! I used TP 3 extensively on the PCjr years ago, after BASIC but before I moved to C on bigger machines. I never dabbled with the ability to do interrupts, and I didn't know that inline assembly was even possible.
Brutman
Site Admin
 
Posts: 910
Joined: Sat Jun 21, 2008 5:03 pm

Re: Turbo Pascal 3

Postby deathshadow60 » Mon Jan 10, 2011 8:10 am

Wait, TP3 doesn't have READKEY? I thought it did! That's kind of wierd it would have keypressed and not readkey -- the two go hand-in-hand.

Oh, duh. That's right. You're supposed to use READ.

Code: Select all
var
   ch:char;
   
begin
   ch:=' ';
   repeat
      if keypressed then begin
         read(ch);
         write(ch);
      {
         you can do anything here and it will run
         uninterupted by the keyboard -- and it will
         run FASTER than inkey$ since we aren't checking
         for a value!
      }
   until ch=#27; /* escape key exits */
end.


Code: Select all
function inkeyString:string;
begin
   if keypressed then begin
      read(inkeyString);
   end else inkeyString:='';
end;


We have to use string on that because you can't have an empty char.
The only thing about Adobe web development products that can be considered professional grade tools are the people promoting their use.
deathshadow60
 
Posts: 62
Joined: Mon Jan 10, 2011 6:17 am
Location: Keene, NH

Re: Turbo Pascal 3

Postby Vorticon » Mon Jan 10, 2011 5:48 pm

Interesting! I never thought of using read because traditionally one needs to send a carriage return after inputing a value. I was not aware that read could retrieve the result of KeyPressed. Part of the issue here is that the TP3 manual states that following a call to KeyPressed, "the result is obtained by calling the operating system console status routine" with no mention of using the read standard function.
Thanks for the info :)

PS: you forgot the end; that matches the begin in the first code snippet, and the string declaration in TP3 requires a length i.e string[1].
Vorticon
 
Posts: 276
Joined: Fri Nov 27, 2009 7:25 am

Re: Turbo Pascal 3

Postby deathshadow60 » Mon Jan 10, 2011 6:43 pm

Vorticon wrote:Interesting! I never thought of using read because traditionally one needs to send a carriage return after inputing a value.

That's readLN. read just does whatever value size you pass.

Vorticon wrote:I was not aware that read could retrieve the result of KeyPressed. Part of the issue here is that the TP3 manual states that following a call to KeyPressed, "the result is obtained by calling the operating system console status routine" with no mention of using the read standard function.

Which the console is the default device for read. There are also functions you can use to override the console to trap for your own routines. (Including write!)

I actually do that in Free Pascal for my SDL code -- I trapped the console output so write and writeln default to sending to my own handler to output on the graphics display using my glKernedFont routine.

Vorticon wrote:PS: you forgot the end; that matches the begin in the first code snippet, and the string declaration in TP3 requires a length i.e string[1].


Doh, what I get for typing it into the forum untested. Good catch.
The only thing about Adobe web development products that can be considered professional grade tools are the people promoting their use.
deathshadow60
 
Posts: 62
Joined: Mon Jan 10, 2011 6:17 am
Location: Keene, NH

Re: Turbo Pascal 3

Postby Vorticon » Mon Jan 10, 2011 9:44 pm

deathshadow60 wrote:
Vorticon wrote:Interesting! I never thought of using read because traditionally one needs to send a carriage return after inputing a value.

That's readLN. read just does whatever value size you pass.


Not quite. What I meant was this:

Code: Select all
program test;
var  ch:char;
begin
  read(ch);
  writeln;
  write('Bingo!');
end.


You need a carriage return to proceed with the program unless you are using a read after KeyPressed, which I did not know.
Vorticon
 
Posts: 276
Joined: Fri Nov 27, 2009 7:25 am

Re: Turbo Pascal 3

Postby deathshadow60 » Fri Jan 14, 2011 7:59 am

Interesting, I always thought the purpose of READ vs. READLN was to not wait for the enter key -- quite unusual, but since it's likely just wrapping the BIOS calls who knows what the story is on that.

Oh, if you want to bypass the BIOS function since the overhead of an interrupt call can be quite large, especially with the Pascal variable mapping, you can read the bios data area directly. The keyboard buffer itself is stored in the BIOS data area at $0040:0000 along with all the pointer data.

I think this should work in Turbo 3, though only on x86 hardware.
Code: Select all
var
   keyBuffer_head:word absolute $0040:$001A;
   keyBuffer_tail:word absolute $0040:$001C;
   keyBuffer_start:word absolute $0040:$0080;
   keyBuffer_end:word absolute $0040:$0082;

function readkey:char;
begin
   repeat until not(keyBuffer_head=keyBuffer_tail);
   if (mem[$0040:keyBuffer_head] and $80)=$80 then begin
      mem[$0040:keyBuffer_head]:=mem[$0040:keyBuffer_head] or $7F;
      readkey:=#0;
   end else begin
      readKey:=chr(mem[$0040:keyBuffer_head]);
      inc(keyBuffer_head);
      if keyBuffer_head=keyBuffer_end then keyBuffer_head:=keyBuffer_start;
   end;
end;

function keywaiting:boolean;
begin
   keywaiting:=not(keyBuffer_head=keyBuffer_tail);
end;


Bypass the BIOS entirely, runs a lot faster -- and does not interfere with proper BIOS operation. The readkey function works just like it's turbo 4 and later counterpart... and I threw in 'keywaiting' which runs faster than the 'real' keypressed function, and is functionally identical. I actually use both of these routines under Turbo 7 (recoded in ASM) because I don't usually want/need the entire CRT unit.

Code: Select all
function readkey:char; assembler;
asm
   mov  dx,$0040
   mov  es,dx
@readKeyWait:
   mov  di,es:[$001A] {keybuffer_head}
   cmp  di,es:[$001C] {keybuffer_tail}
   je   @readKeyWait
   mov  al,es:[di]
   test al,$80
   jnz   @extendedKey
   add  di,2
   cmp  di,es:[$0082] {keyBuffer_end}
   jne  @bufferUpdate
   mov  di,es:[$0080] {keyBuffer_start}
   ret
@bufferUpdate:
   mov  es:[$001A],di {keyBuffer_head}
@extendedKey
   and  al,$7F
   mov  es:[di],al
   xor  al,al
end;

function keypressed:boolean; assembler;
asm
   xor  ax,ax
   mov  es,ax
   mov  bx,es:[$041A]  {keybuffer_head}
   cmp  bx,es:[$041C]  {keybuffer_tail}
   je   @retval
   not  ax
   @retval:
   { tp7 ASM exit values are in AL, which we set to zero at start! }
end;


Fun stuff.
The only thing about Adobe web development products that can be considered professional grade tools are the people promoting their use.
deathshadow60
 
Posts: 62
Joined: Mon Jan 10, 2011 6:17 am
Location: Keene, NH


Return to Programming

Who is online

Users browsing this forum: No registered users and 1 guest

cron