Turbo Pascal 3

Discussions on programming older machines
Post Reply
Vorticon
Posts: 278
Joined: Fri Nov 27, 2009 6:25 am

Turbo Pascal 3

Post by Vorticon »

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

Retro
Posts: 5
Joined: Sat Jan 01, 2011 9:56 am
Location: New Zealand

Re: Turbo Pascal 3

Post by Retro »

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 11:14 am, edited 6 times in total.
Brutman
Site Admin
Posts: 1331
Joined: Sat Jun 21, 2008 5:03 pm
Contact:

Re: Turbo Pascal 3

Post by Brutman »

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.
deathshadow60
Posts: 62
Joined: Mon Jan 10, 2011 5:17 am
Location: Keene, NH
Contact:

Re: Turbo Pascal 3

Post by deathshadow60 »

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.
Vorticon
Posts: 278
Joined: Fri Nov 27, 2009 6:25 am

Re: Turbo Pascal 3

Post by Vorticon »

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].
deathshadow60
Posts: 62
Joined: Mon Jan 10, 2011 5:17 am
Location: Keene, NH
Contact:

Re: Turbo Pascal 3

Post by deathshadow60 »

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.
Vorticon
Posts: 278
Joined: Fri Nov 27, 2009 6:25 am

Re: Turbo Pascal 3

Post by Vorticon »

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.
deathshadow60
Posts: 62
Joined: Mon Jan 10, 2011 5:17 am
Location: Keene, NH
Contact:

Re: Turbo Pascal 3

Post by deathshadow60 »

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.
Post Reply