home *** CD-ROM | disk | FTP | other *** search
- { ProcParm Version 2.2A 86/05/27
-
- Author: Mike Babulic Compuserve ID: 72307,314 FIDO: 134/1
- 3827 Charleswood Dr. N.W.
- Calgary, Alberta,
- CANADA
- T2L 2C7
-
- One of the weaknesses of TURBO Pascal is that procedures and functions
- cannot be passed as parameters. The "ProcParm" files are meant to
- overcome this limitation.
-
- There are 6 files: 1) ProcParm.PAS - documentation with example program
- 2) ProcParm.INC - contains the call_ProcParm procedure
- 3) ProcParm.QK - Inline code to be used instead of
- the call_ProcParm procedure.
- Quicker execution, but larger programs.
- 4) ProcParm.BIN - the third (and best) alternative, an
- externally assembled binary file.
- - Fastest execution due to less stack
- manipulation.
- - Least code added to the program
- (12 bytes!).
- 5) ProcParm.P - this is the "glue" that you $Include
- in a program so it can use ProcParm.BIN.
- 6) ProcParm.ASM - the source code for ProcParm.BIN
-
- The call_ProcParm procedure
- ---------------------------
-
- When this procedure is called by a procedure or function, it will cause a
- "short" jump to the procedure whose offset is the last parameter (of the
- calling procedure). This is done by swapping the last parameter (a procedure
- pointer) and the return address of the calling routine on the stack.
-
- Using ProcParm, procedures can be passed as parameters to other procedures.
- This is accomplished by defining a dummy procedure (or function) with exactly
- the same arguments as the procedure to be passed EXCEPT that a final added
- parameter of type Integer is also defined. When the calling procedure calls
- the dummy procedure, it passes the offset of the procedure to be executed in
- this last parameter (most often by using the Ofs function).
-
- ProcParm will "return" to the routine specified by the last parameter of the
- dummy and THE STACK WILL LOOK EXACTLY THE SAME AS IF THE "returned to"
- PROCEDURE HAD BEEN CALLED BY THE PROCEDURE THAT CALLED THE DUMMY!
-
- ProcParm.QK -- the Inline code
- ------------------------------
-
- The ProcParm.QK file can be "included" in your dummy procedure instead of
- calling the ProcParm procedure. This will speed up a program because several
- fewer 8088 instructions will be executed to "jump" to the passed procedure.
- However, be aware that the cost of this speed is a larger program!
-
- The ProcPtr type will not be declared if you use ProcParm.QK, so use Integer
- instead.
-
- ProcParm.BIN and ProcParm.P
- -----------------------------
-
- The ProcParm.P file is "included" in your program to allow it to use the
- contents of ProcParm.BIN file. As in the previous two methods, a dummy
- procedure is created with the procedure to be "run" as the last parameter. This
- is where the similarity ends.
-
- As well as allowing you to call procedures and functions in the body of your
- TURBO program (NEAR calls), ProcParm.P also allows you to call (FAR) procedures
- and functions which lie OUTSIDE the body of the program. This program gives the
- example of a procedure stored in a typed constant (FarDummy). Admittedly it is
- a very simple procedure, just the 8086 instruction "RETF", but more complex
- procedures could be read into an array variable (or into the heap?) and be run
- just as easily.
-
- You can also make a FAR call with an offset. This is useful if you have set
- aside an area of storage for a group of procedures or functions. The method
- used is quite a bit slower than the standard FAR call. If speed is important
- you should save the address of each procedure in a variable, and use the
- regular FAR call. I have included a function to make life easier for you.
-
- }
-
- {-------------- The procedures to be passed as Parameters --------------}
-
- procedure first(a,b:integer);
- begin
- writeln(' FIRST ',a:3,b:3);
- end;
-
- procedure second(a,b:integer);
- begin
- writeln(' ',a:3,' SECOND',b:3);
- end;
-
- {-------------------- Use of the ProcParm procedure --------------------}
-
- {$i procparm.inc} { Include the call_ProcParm procedure's definition}
-
- procedure dummy(a,b:integer; p:integer {ProcPtr});
- begin
- call_ProcParm;
- end;
-
- procedure OneTwo(p:integer {ProcPtr});
- begin
- dummy(9,10,p);
- end;
-
- {----------------------- Use of ProcParm.QK -----------------------------}
-
- procedure fasterDummy(a,b:integer; p:Integer {ProcPtr});
- begin
- {$I procparm.qk}
- end;
-
- procedure QuickStep(p:integer {ProcPtr});
- begin
- FasterDummy(20,30,p);
- end;
-
- {-------------------- Use of the EXTERNAL procedure --------------------}
-
- {$i procparm.p} { Include the external procedure's definition}
-
- procedure ExternalDummy(a,b:integer; p:ProcPtr); external ProcParm[near];
-
- procedure Zoom(p:ProcPtr);
- begin
- ExternalDummy(49,50,p);
- end;
-
- {------------------------------- Timer -----------------------------------}
-
- TYPE TimeType = record
- case boolean of
- False: (ffss,mmhh: integer);
- True: (frac,sec,min,hour: byte)
- end;
-
- VAR
- REGS: record AX,BX,CX,DX,BP,SI,DI,DS,ES,FLAGS: integer end;
- oldTime, theTime: TimeType;
-
- procedure Timer;
- begin
- OldTime := TheTime;
- with REGS do begin
- AX := $2C00;
- MsDos(REGS);
- with TheTime do begin
- mmhh := CX;
- ffss := DX;
- end;
- end;
- end;
-
- function TimeInSec(t:TimeType):real;
- begin
- with t do TimeInSec := frac/100.0 + sec + 60*(min + 60*hour);
- end;
-
- function ElapsedTime: real;
- { returns elapsed time in seconds }
- begin
- ElapsedTime := TimeInSec(theTime)-TimeInSec(OldTime);
- end;
-
- {------------------------- Timing Procedures -----------------------------}
-
- procedure theDummy;
- begin
- end;
-
- Const farDummy: integer = $CBCB; { RETF ;RETurn Far }
-
- procedure Speed1(p:ProcPtr);
- begin
- call_ProcParm;
- end;
-
- procedure Speed2(p:ProcPtr);
- begin
- {$i ProcParm.QK}
- end;
-
- procedure Speed3(p:ProcPtr); EXTERNAL ProcParm[NEAR];
-
- procedure Speed4(p:FarProcPtr); EXTERNAL ProcParm[FAR];
-
- procedure Speed5;
- begin
- OffsetProc(ADDR(farDummy),1);
- end;
-
- {-------------------------- Run the Examples -----------------------------}
-
- const TimeLoop = MaxInt;
-
- var
- i: integer;
- s0,s1,s2,s3,s4,s5: real; { elapsed time from each timing loop }
-
- begin
-
- Writeln;
- Writeln('Using call_ProcParm Routine ....');
- OneTwo(Ofs(First));
- OneTwo(Ofs(Second));
-
- Writeln;
- Writeln('Using Inline Code Dummy ....');
- QuickStep(Ofs(First));
- QuickStep(Ofs(Second));
-
- Writeln;
- Writeln('Using External Code Dummy ....');
- Zoom(Ofs(First));
- Zoom(Ofs(Second));
-
- Writeln;
- Writeln('Now running speed test');
- Timer;
- for i := 1 to TimeLoop do theDummy;
- Timer;
- s0 := elapsedTime;
- Writeln(' Ordinary Call = ',elapsedTime:3:2,' seconds');
- Timer;
- for i := 1 to TimeLoop do Speed1(Ofs(theDummy));
- Timer;
- s1 := elapsedTime;
- Writeln(' call_ProcPtr = ',elapsedTime:3:2,' seconds');
- Timer;
- for i := 1 to TimeLoop do Speed2(Ofs(theDummy));
- Timer;
- s2 := elapsedTime;
- Writeln(' Inline code = ',elapsedTime:3:2,' seconds');
- Timer;
- for i := 1 to TimeLoop do Speed3(Ofs(theDummy));
- Timer;
- s3 := elapsedTime;
- Writeln(' External NEAR = ',elapsedTime:3:2,' seconds');
- Timer;
- for i := 1 to TimeLoop do Speed4(ADDR(farDummy));
- Timer;
- s4 := elapsedTime;
- Writeln(' External FAR = ',elapsedTime:3:2,' seconds');
- Timer;
- for i := 1 to TimeLoop do Speed5;
- Timer;
- s5 := elapsedTime;
- Writeln(' Offset FAR = ',elapsedTime:3:2,' seconds');
-
- writeln;
- writeln('Relative Speeds : Ordinary: call_.. : Inline : NEAR : FAR : FARofs :');
- writeln(' :',s0/s0:8:3,' :',s0/s1:8:3,' :',s0/s2:8:3,' :'
- ,s0/s3:8:3,' :',s0/s4:8:3,' :',s0/s5:8:3,' :');
- end.