home *** CD-ROM | disk | FTP | other *** search
- (**** TPA&RTL Documentation and Demonstration ****
-
- TP&Asm Version 2.2 (Revision 1)
-
- This revision can be distinguished from the original Version 2.2 by
- the 2:21 time stamp and by the Version number shown in the copyright
- message. In most of the documentation, however, I will continue to
- refer to this revision as "Version 2.2".
-
- TP&Asm Version 2.21 contains a small but interesting upgrade to the
- TP&Asm program file which permits you to call any routine in the
- Turbo Pascal RunTime Library directly from your TP&Asm assembly code.
- (You do not need to purchase the RTL source license).
-
- To use this feature you must determine the System Unit internal hex
- code which designates the appropriate routine (more on this below),
- and declare a standard Pascal constant equal to $C0DE0000 plus this
- code. You may then specify the constant identifier as the target of
- any assembly Call (or JMP) statement, and TP&Asm will link in the
- designated RunTime Library routine.
-
- For example, the internal hex code for the RunTime Library "LMod"
- function is $0018. The following code fragment will compute
- L1 Mod L2 and leave the result in (Bx,Cx)
-
- CONST LMod = $C0DE0018;
- :
- Assembly
- Les Ax,L1
- Mov Dx,Es ;load L1 into (Dx,Ax)
- Les Cx,L2
- Mov Bx,Es ;load L2 into (Bx,Cx)
- Call LMod ;call RTL routine which leaves result in (Bx,Cx)
- :
-
-
- All valid internal hex codes are multiples of 4, and the following
- limits are enforced:
-
- VER40: $0004 to $0260
- VER50: $0004 to $0284
- VER55: $0004 to $0294
-
- I don't guarantee that all codes up to these maximum values are valid
- RTL routines, however I am fairly certain that codes beyond these are
- not valid.
-
- Please note:
- I have made no attempt to explain or even determine what all of the
- RunTime Library routines do nor how they should be called. I have
- left that to the user. In many cases the following technique can
- be applied to determine the internal code of a particular RunTime
- Library routine:
-
- 1) create a file which defines the entire range of RTL constants
- and makes one call to each, and which also contains a single
- Pascal line which will invoke the desired RTL routine:
-
- Program FindRTL;
- CONST
- RTL0004 = $C0DE0004;
- RTL0008 = $C0DE0008;
- : :
- RTL0294 = $C0DE0294; {- v5.5 Maximum -}
- VAR
- L1,L2,L3: LongInt;
- BEGIN
- L3 := L1 Mod L2; {- invoke RTL LMod function -}
- Assembly
- Call RTL0004
- Call RTL0008
- :
- Call RTL0294
- End; {Assembly}
- END.
-
- 2) compile and create a map file, eg: "tpa c FindRTL/gd". Then use
- EXAMINE.EXE (available in the archive TP-XMN) to examine the
- compiled file and save the output ("examine FindRTL >rtl.xmn").
-
- 3) Edit the examine output file, find the Far Call(s) associated
- with the Pascal statement, and locate the assembly Call(s) which
- reference the same location. The relevant parts of the example
- in (1) are shown below:
-
- VAR
- L1,L2,L3: LongInt;
- BEGIN
-
- 3FC1:0000 9A0000F83F CALL 3FF8:0000
- 3FC1:0005 55 PUSH BP
- 3FC1:0006 89E5 MOV BP,SP
- ----
- L3 := L1 Mod L2; {- invoke RTL LMod function -}
-
- 3FC1:0008 C4063E00 LES AX,[003E]
- 3FC1:000C 8CC2 MOV DX,ES
- 3FC1:000E C40E4200 LES CX,[0042]
- 3FC1:0012 8CC3 MOV BX,ES
- 3FC1:0014 9A9402F83F CALL 3FF8:0294 ** This is the RTL Call **
- 3FC1:0019 89C8 MOV AX,CX
- 3FC1:001B 89DA MOV DX,BX
- 3FC1:001D A34600 MOV [0046],AX
- 3FC1:0020 89164800 MOV [0048],DX
- ----
- :
- :
- ----
- Call RTL0018
-
- 3FC1:0040 9A9402F83F CALL 3FF8:0294 ** Matching Assembly Call **
- ----
- Call RTL001C
-
- 3FC1:0045 9A0203F83F CALL 3FF8:0302
- ----
- :
-
-
- It has been my observation that many of the RunTime Library routines
- have retained the same internal code for all versions (4.0 and above),
- however I am not certain that that will be true in all cases. In some
- cases, for example RtlGetMem and RtlFreeMem shown below, the internal
- code has remained the same but the calling conventions have changed.
-
- The example below is designed to provide a simple demonstration of
- the use of assembly language RTL calls. The RunTime Library FreeMem
- pocedure is used to implement a "ShrinkMem" capability. A typical
- use of ShrinkMem would be to read a data file into a large buffer on
- the heap, and then to reduce the allocated heap space to the amount
- actually required:
-
- GetMem(DataBuf,64000);
- Assign(DataFile,DataPath); Reset(DataFile,1);
- BlockRead(DataFile,DataBuf^,64000,BytesRead);
- ShrinkMem(DataBuf,64000,BytesRead);
-
- An additional example is provided by the UserRunError procedure,
- which demonstrates one of the relatively rare circumstances where
- it is useful to make an unconditional JMP to a procedure.
-
- Unlike the Version 5.x "RunError" procedure which flags the address
- of the RunError call itself, this procedure provides a more useful
- function by flagging the line which invoked the routine containing
- the UserRunError call. Thus,
-
- ShrinkMem(p1,21000,30000); {- RunTime Error 204 -}
-
- will generate a RunTime Error at this line itself, not at some
- obscure point within ShrinkMem where the error was detected. If
- ShrinkMem resides in a unit which was compiled without debug
- information ({$D-}), or for which source code is not available,
- UserRunError (but not v 5.x RunError) will still correctly report
- the address of the invalid ShrinkMem Call.
-
- ShrinkMem could have been written entirely in Pascal; the use of
- assembly language simply makes it smaller and faster. Note that
- it could not be written in inline or External assembly language,
- however - unless you have purchased the RTL license, recompiled
- the System unit with all of the routines "interfaced", and then
- recompiled all of your standard and user-defined units to recognize
- the recompiled System unit.
-
- I believe that UserRunError is an example of a procedure which
- could not be written either in Pascal or inline/External assembly
- (again, unless you have the RTL license and recompile all your
- units).
-
- This example file can be compiled with TP&Asm Version 2.21 running
- Turbo Pascal Version 4.0, 5.0, or 5.5.
-
- *****************************************************************)
-
- {$M $1000,51000,51000}
-
- CONST
- RtlRunError = $C0DE0008;
- RtlGetMem = $C0DE0088;
- RtlFreeMem = $C0DE008C;
-
- VAR
- p1,p2,p3: POINTER;
-
- {$F+} PROCEDURE RunError(ErrorNo: WORD); Forward; {$F-}
- {$F+} PROCEDURE UserRunError(ErrorNo: WORD); Forward; {$F-}
-
- Internal RTE
-
- RunError Proc Far ; (for version 4.0 users)
- Mov Bx,Sp
- Ss Mov Ax,[Bx+4] ;load ErrorNo into Ax
- Jmp RtlRunError ;Jmp to Runtime Library Routine
- RunError ENDP
-
- UserRunError Proc Far
- Pop Ax,Ax,Ax ;Clear Return Cs:Ip and load ErrorNo into Ax
- Mov Sp,Bp ;Proc/Function containing UserRunError
- Pop Bp ; Must have standard Proc/Function entry code
- Jmp RtlRunError ; (and must be FAR)
- UserRunError ENDP
-
- End
-
- {$F+} PROCEDURE ShrinkMem(PVar: POINTER; OldSize,NewSize: WORD); {$F-}
- {$S-} BEGIN {$S+}
- Assembly
- Les Ax,PVar ;set Dx:Ax
- Mov Dx,Es ; to PVar
- Add Ax,NewSize ;Point to "PVar+NewSize"
- Mov Bx,Ax ;Normalize
- And Ax,000Fh ; Pointer
- Shr Bx,4 ; before passing
- Add Dx,Bx ; to FreeMem
- Mov Bx,OldSize ;Compute
- Sub Bx,NewSize ; amount to free
-
- jA Valid
- Pas UserRunError(204);
- Valid:
-
- Pas {$IFDEF VER55} {- 5.5 uses pointer Value -}
- Push Dx,Ax,Bx ;Push parameters for FreeMem
- Pas {$ELSE} {- 4.0, 5.0 use pointer Address -}
- Mov W PVar,Ax
- Mov W PVar+2,Dx
- Lea Ax,PVar
- Push Ss,Ax,Bx ;Push parameters for FreeMem
- Pas {$ENDIF}
-
- Call RtlFreeMem ;Call RunTime Library Routine
- End {Assembly}
- END;
-
- PROCEDURE ShowMaxAvail;
- BEGIN WRITELN('Size of largest available block is ',MaxAvail); END;
-
- BEGIN {- Verify proper operation of ShrinkMem -}
-
- ShowMaxAvail;
- GetMem(p1,30000); {- Allocate -}
- GetMem(p2,10000); {- three -}
- GetMem(p3,10000); {- blocks -}
- ShowMaxAvail;
-
- {- First free the center block -}
- FreeMem(p2,10000); ShowMaxAvail; {- 10,000 -}
-
- {- Free some of 1st block, should merge with freed 2nd block -}
- ShrinkMem(p1,30000,21000); ShowMaxAvail; {- 19,000 -}
-
- {- Free remainder of 1st block, should merge again -}
- FreeMem(p1,21000); ShowMaxAvail; {- 40,000 -}
-
- Halt;
-
- {- The following line would generate a RunTime Error -}
- ShrinkMem(p1,21000,30000); {- RunTime Error 204 -}
-
- END.
-