home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Turbo Toolbox
/
Turbo_Toolbox.iso
/
1988
/
02
/
mmr
/
ed.
next >
Wrap
Text File
|
1994-04-10
|
19KB
|
352 lines
(*---------------------------------------------------------------------------*)
(* MAKEMAP.INC (v2.0) *)
(* Anfertigung eines Belegungsplanes des PC-Hauptspeichers (MS-DOS/Turbo) *)
(* (c) 1987 Karsten Gieselmann & PASCAL International *)
(*---------------------------------------------------------------------------*)
Type ProgName = String[8]; (* "reiner" Programmname (o. Pfad u. Ext.) *)
Entry = ^ProgEntry; (* Eintrag fuer ein Programm *)
ProgEntry = Record
Segment :Integer; (* Lade-Segment *)
Name :ProgName; (* Name des Programms *)
Segs :Integer; (* Anzahl der Segmente *)
Paragraphs :Integer; (* belegter Speicher *)
Last, (* Zeiger auf letzten Eintrag *)
Next :Entry; (* Zeiger auf naechsten Eintrag *)
End;
Var FreeBlocks :Integer; (* Groesse der nicht belegten Bloecke in Paragr. *)
(* Vergleichsfunktion "a < b" fuer CARDINAL-Zahlen (0..$FFFF): *)
Function Lower (a,b :Integer) :Boolean;
Begin
Inline ($31/$C0/ (* XOR AX,AX ; *)
$8B/$5E/$06/ (* MOV BX,[BP+06] ;a holen *)
$3B/$5E/$04/ (* CMP BX,[BP+04] ;Vergleich: a < b ? *)
$73/$01/ (* JNC *+1 ;nein: dann Abbruch *)
$40/ (* INC AX ;sonst Bedingung erfuellt *)
$88/$46/$08) (* MOV [BP+08],AL ;Ergebnis auf Stapel *)
End;
(* Diese Prozedur erstellt eine nach Segmenten geordnete Liste aller im
Speicher befindlichen residenten Programme. Der durch unbenutzte Bloecke
freie Speicher wird in der globalen Variablen "FreeBlocks" mitgezaehlt
(Angabe in Paragraphen). Der Uebergabe-Parameter "FirstProgPtr" enthaelt
einen Zeiger auf den ersten Listeneintrag. *)
Procedure MakeMemoryMap (Var FirstProgPtr :Entry);
Type MCB_Ptr = ^MCB_Type;
MCB_Type = Record (* Aufbau eines Memory Control Blocks *)
ID :Char;
PSPSeg, Diff :Integer;
End;
Var MCB :MCB_Type;
CurrentMCB :MCB_Ptr;
FirstProg, ProgPtr :Entry; (* Listenkopf und Arbeitszeiger *)
(* liefert einen Zeiger auf den ersten Memory Control Block: *)
Function First_MCB :MCB_Ptr;
Var Regs :Record AX,BX,CX,DX,BP,DI,SI,DS,ES,Flags :Integer End;
Begin
Regs.AX := $5200; MsDos (Regs); (* undokumentierte Funktion 52h *)
With Regs do First_MCB := Ptr (MemW[ES:BX-2], 0);
End;
(* durchsucht die nach Segmenten aufsteigend sortierte Programm-Liste
und liefert die Einfuege-Position. Befindet sich bereits ein Eintrag
in der Liste, bei welchem das Segment mit "PSPSeg" uebereinstimmt, so
wird ein Zeiger auf diesen Eintrag uebergeben: *)
Procedure GetProgPos (PSPSeg :Integer; Var ProgPtr :Entry);
Begin
ProgPtr := FirstProg;
While (ProgPtr^.Next <> Nil) and Lower (ProgPtr^.Segment, PSPSeg) do
ProgPtr := ProgPtr^.Next;
If ProgPtr <> FirstProg then
If Lower (PSPSeg, ProgPtr^.Segment) then ProgPtr := ProgPtr^.Last
End;
(* erzeugt ein neues Listenelement und fuegt es hinter "ProgPtr" ein: *)
Procedure InsertNewProg (Var ProgPtr :Entry);
Var NewProg :Entry;
Begin
New (NewProg); NewProg^.Next := ProgPtr^.Next;
NewProg^.Last := ProgPtr; ProgPtr^.Next := NewProg;
If NewProg^.Next <> Nil then NewProg^.Next^.Last := NewProg;
ProgPtr := NewProg
End;
(* holt das Environment-Segment aus dem PSP (Offset 2Ch) und schaut
dort nach dem vom DOS (erst ab Version 3.0!) abgelegten Dateinamen.
Bei erfolgreicher Suche werden Pfad und Extension abgeschnitten und
der reine Programmname uebergeben: *)
Function GetProgName (PSPSeg :Integer) :ProgName;
Var Name :String[255];
EnvSeg,EnvOfs :Integer; (* Segment, Offset des Environments *)
p :Byte;
Begin
EnvSeg := MemW [MCB.PSPSeg:$2C]; EnvOfs := 0; Name := '';
While (MemW[EnvSeg:EnvOfs] <> $0000) do (* bis Ende des Env.-Strings *)
EnvOfs := succ (EnvOfs);
If MemW[EnvSeg:EnvOfs+2] = $0001 then begin (* Datein. ist eingetragen *)
EnvOfs := EnvOfs + 4; (* EnvOfs auf Dateinamen *)
While Mem[EnvSeg:EnvOfs] <> $00 do begin (* bis zum Ende des Namens *)
Name := Name + chr(Mem[EnvSeg:EnvOfs]); EnvOfs := succ (EnvOfs)
End;
Repeat (* Pfadnamen abspalten *)
p := Pos ('\', Name); Delete (Name, 1, p);
until p = 0;
End;
p := pred (Pos('.',Name));
GetProgName := Copy (Name,1,p); (* Extension abspalten *)
End;
Begin (* MakeMemoryMap *)
New (FirstProg); (* Programm-Liste anlegen *)
FirstProg^.Next := Nil; FirstProg^.Last := Nil; FreeBlocks := 0;
CurrentMCB := First_MCB; (* Zeiger auf ersten MCB holen *)
Repeat
MCB := CurrentMCB^;
With MCB do (* belegt und nicht vom DOS benutzt: *)
If Lower ($0070,PSPSeg) then begin
GetProgPos (PSPSeg, ProgPtr);
If (ProgPtr <> FirstProg) and (ProgPtr^.Segment = PSPSeg) then
With ProgPtr^ do Begin
Segs := succ (Segs); Paragraphs := Paragraphs + Diff;
If Name <> 'DOS' THEN Name := GetProgName (PSPSeg);
End
else begin (* neuen Eintrag erzeugen *)
InsertNewProg (ProgPtr);
With ProgPtr^ do Begin
Segment := PSPSeg; Segs := 1; Paragraphs := Diff;
If ProgPtr = FirstProg^.Next then (* Eintrag ist DOS! *)
Name := 'DOS'
else Name := '???'
End
End;
End
else
If PSPSeg = $0000 then (* unbenutzer Speicherblock *)
FreeBlocks := FreeBlocks + Diff;
CurrentMCB := Ptr(Seg(CurrentMCB^)+succ(MCB.Diff),0); (* naechster MCB *)
until MCB.ID = 'Z';
FirstProgPtr := FirstProg^.Next
End;
(*---------------------------------------------------------------------------*)
(* MAKEMAP.INC (v2.0) *)
(*---------------------------------------------------------------------------*)
(* MAKEMARK.PAS (v1.0) *)
(* Erzeugen der superkurzen MARKer-Datei MARK.COM (MS-DOS/Turbo) *)
(* (c) 1987 Karsten Gieselmann & PASCAL International *)
(*---------------------------------------------------------------------------*)
Program MakeMark (Output, ComFile);
Const Code :Array [0..22] of Byte =
($FA, (* CLI ;Interrupts verbieten *)
$0E, (* PUSH CS ;Codesegment... *)
$07, (* POP ES ;...nach ES laden *)
$33,$C0, (* XOR AX,AX ;AX loeschen... *)
$8E,$D8, (* MOV DS,AX ;...als Segment nach DS... *)
$89,$C6, (* MOV SI,AX ;...und als Offset nach SI *)
$BF,$17,$01, (* MOV DI,0117 ;Beginn der IntVec-Tabelle *)
$B9,$00,$02, (* MOV CX,0200 ;Laenge der Tabelle *)
$F3, (* REPZ ;Kopieren bis Tabellenende *)
$A5, (* MOVSW ; *)
$FB, (* STI ;Interrupts zulassen *)
$BA,$17,$05, (* MOV DX,0517 ;22 Code-, 1024 Datenbytes *)
$CD,$27); (* INT 27 ;...resident machen *)
ComFileName = 'MARK.COM';
Var ComFile :File of Byte;
Count :Integer;
Begin
Assign (ComFile, ComFileName); ReWrite (ComFile);
For Count := 0 to pred(SizeOf(Code)) do Write (ComFile, Code[Count]);
Close (ComFile);
WriteLn; Writeln ('COM-File ', ComFileName, ' generiert!'); Writeln;
End.
Θ│+ÉÉ═½Copyright (C) 1985 BORLAND Inc ΘV v2 Default display modeP ppO.è'
Σ∙tC.èPΦ╣X■╠u≤°├║ ╟ n .╞ö ╛p & 4& t·&╟╕&îL√δ(*---------------------------------------------------------------------------*)
(* MAP.PAS *)
(* Ausgabe einer Belegungstabelle des PC-Hauptspeichers (MS-DOS/Turbo) *)
(* (c) 1987 Karsten Gieselmann & PASCAL International *)
(*---------------------------------------------------------------------------*)
PROGRAM Map (Output);
(* {$P512} *) (* fuer DOS-Ein/Ausgabeumleitung Klammern entfernen! *)
{$I MAKEMAP.INC} (* einbinden der die Liste liefernden Routine *)
Const LastIntr = $7F; (* Test auf Anzapfen bis zu diesem Vektor *)
Type StringType = String[4]; (* Typ fuer die Dez-Hex-Transformation *)
Var IntrCount, (* Zahl der angezapften Interrupts für ein Programm *)
i :Byte;
FreeMemory :Real; (* Groesse des verbleibenden RAM-Speichers in Bytes *)
ProgPtr :Entry;
IntrSegment,
NextSegment :Integer;
Hooked :Boolean;
(* wandelt ein Dezimalbyte in den entsprechenden Hexadezimalwert: *)
Function HexByte (b :Byte) :StringType;
Const HexDigit :Array [0..15] of Char = '0123456789ABCDEF';
Begin HexByte := HexDigit[b shr 4] + HexDigit[b and $0F] End;
(* wandelt ein Dezimalwort in den entsprechenden Hexadezimalwert: *)
Function HexWord (w :Integer) :StringType;
Begin HexWord := HexByte (w shr 8) + HexByte (w and $FF) End;
(* rechnet in Paragraphen gegebene Speichergroesse in Bytes um: *)
Function ByteSize (Paragraphs :Integer) :Real;
Begin
If Paragraphs < 0 then ByteSize := (Paragraphs + 65536.0) * 16.0
else ByteSize := Paragraphs * 16.0
End;
Begin (* Map *)
MakeMemoryMap (ProgPtr); LowVideo;
WriteLn; Write ('MAP v2.0 - Speicherbelegungstabelle');
WriteLn (' (c) 1987 K.Gieselmann & PASCAL Int.');
WriteLn;
Write (' Adresse Programm Seg Bytes ');
Write (' Interrupt-Vektoren'^M^J);
Write ('───────── ──────── ─── ────── ');
Write ('──────────────────────────────────────────');
While ProgPtr <> Nil do Begin
With ProgPtr^ do
If ProgPtr^.Next <> Nil then Begin
Write (HexWord(Segment), ':0000 ');
Write (Name, '':8-Length(Name));
Write (Segs:6, ByteSize(Paragraphs):9:0, ' ');
IntrCount := 1; NextSegment := Next^.Segment;
If Name <> 'DOS' then (* das DOS zapft keine Vektoren an! *)
For i:=$00 to LastIntr do Begin
IntrSegment := MemW[0:i*4+2] + MemW[0:i*4] shr 4;
If not Lower (IntrSegment, Segment) then
If not Lower (NextSegment, IntrSegment) then Begin
If IntrCount mod 12 = 0 then Write ('':36);
Write (HexByte(i):4); IntrCount := succ (IntrCount)
End
End;
If IntrCount mod 12 <> 0 then WriteLn
End
else begin (* letzter Eintrag ist laufendes Progamm! *)
FreeMemory := ByteSize (Paragraphs + FreeBlocks);
WriteLn (^J'Freier RAM-Speicher:', FreeMemory:15:0);
WriteLn (^J'Nächste Ladeadresse: ', HexWord(Segment))
End;
ProgPtr := ProgPtr^.Next
End;
WriteLn
End.
·3└Ä╪ë╞┐╣ ≤Ñ√║═'Θ│+ÉÉ═½Copyright (C) 1985 BORLAND Inc ΘV v2 Default display modeP ppO.è'
Σ∙tC.èPΦ╣X■╠u≤°├╗ ╟ n .╞ö ╛p & 4& t·&╟╕&îL√δ(*---------------------------------------------------------------------------*)
(* RELEASE.PAS (v2.0) *)
(* Freigeben eines mit MARK gekennzeichneten Speicherbereichs (MS-DOS/Turbo) *)
(* (c) 1987 Karsten Gieselmann & PASCAL International *)
(*---------------------------------------------------------------------------*)
PROGRAM ReleaseProgram (Output);
{$I MAKEMAP.INC} (* einbinden der die Liste liefernden Routine *)
Var Seg :Integer; (* Segment des letzten MARK-Aufrufs *)
FirstProg, LastProg :Entry;
(* sucht in der Programm-Liste den letzten MARK-Eintrag; wird dieser ge-
funden, so enthaelt "Segment" das Segment dieses Eintrags, anderenfalls
ist die Uebergabe-Variable gleich Null: *)
Procedure FindMarker (Var Segment :Integer);
Var ProgPtr :Entry;
Function DVersion :Integer; (* DOS-Version ermitteln *)
Var Regs :Record
AX,BX,CX,DX,BP,DI,SI,DS,ES,Flags :Integer
End;
Begin
Regs.AX := $3000; MsDos (Regs); (* Funktion 30h *)
DVersion := Lo (Regs.AX) (* "Hauptversionsnummer" *)
End; (* "Hi (Regs.AX)" ergibt Unterversionsnummer *)
Function MarkFound :Boolean;
Const MarkName = 'MARK'; (* Name des MARK-Programms *)
MarkCode : Array [0..22] of Byte =
($FA,$0E,$07,$33,$C0,$8E,$D8,$89,$C6,$BF,$17,$01,
$B9,$00,$02,$F3,$A5,$FB,$BA,$17,$05,$CD,$27);
Var found :Boolean; i :Integer;
Begin
If DVersion >= 3 then found := (ProgPtr^.Name = MarkName)
else begin (* DOS-Version kleiner 3.0 *)
found := true;
For i := 0 to 22 do
found := found and (Mem[ProgPtr^.Segment:$100+i] = MarkCode[i]);
End;
MarkFound := found
End;
Begin (* FindMarker *)
ProgPtr := LastProg;
While not MarkFound and (ProgPtr <> FirstProg) do ProgPtr := ProgPtr^.Last;
If ProgPtr <> FirstProg then Segment := ProgPtr^.Segment
else Segment := $0000 (* MARK nicht gefunden! *)
End;
(* kopiert die von MARK gesicherte Interrupt-Vektor-Tabelle wieder an ih-
ren ursprünglichen Platz am Speicheranfang bei Adresse $0000:$0000 *)
Procedure RestoreIntVecTable (Seg :Integer);
Begin
Inline ($FA/ (* CLI ;Interrupts verbieten *)
$06/ (* PUSH ES ;Extrasegment sichern *)
$1E/ (* PUSH DS ;Datensegment sichern *)
$8B/$86/Seg/ (* MOV AX,Segm ;MARK-Segment holen... *)
$8E/$D8/ (* MOV DS,AX ;...und nach DS laden *)
$BE/$17/$01/ (* MOV SI,0117 ;Beginn der IntVec-Tabelle *)
$31/$C0/ (* XOR AX,AX ;AX loeschen, ... *)
$8E/$C0/ (* MOV ES,AX ;...als Segment nach ES... *)
$89/$C7/ (* MOV DI,AX ;...und als Offset nach DI *)
$B9/$00/$02/ (* MOV CX,0200 ;Laenge der IntVec-Tabelle *)
$F3/ (* REPZ ;Kopieren bis Tabellenende *)
$A5/ (* MOVSW ; *)
$1F/ (* POP DS ;Datensegment wiederholen *)
$07/ (* POP ES ;Extrasegment wiederholen *)
$FB) (* STI ;Interrupts zulassen *)
End;
(* liefert einen Zeiger auf den letzten Eintrag der Programm-Liste: *)
Procedure GetPtr (Var LastProg :Entry);
Var ProgPtr :Entry;
Begin
ProgPtr := FirstProg;
While ProgPtr^.Next^.Next <> Nil do ProgPtr := ProgPtr^.Next;
LastProg := ProgPtr
End;
(* gibt den durch "ProgPtr" bezeichneten Speicherbereich wieder frei: *)
Procedure Release (ProgPtr :Entry);
VAR error: Boolean;
(* gibt das vom DOS allokierte Segment "Segment" wieder frei: *)
(* (PASCAL 4/87, 'Externe Kommandos in Turbo Pascal', S.72 ff) *)
Function MFree (Block_Segment :Integer) :Integer;
Var Regs :Record
AX,BX,CX,DX,BP,DI,SI,DS,ES,Flags :Integer
End;
Begin (* DOS-Funktion "Free Allocated Memory" *)
Regs.ES := Block_Segment; Regs.AX := $4900; MsDos (Regs);
If odd (Regs.Flags) then MFree := Lo (Regs.AX) Else MFree := 0;
End;
Begin (* Release *)
error := false; Write ('Freigabe von ',ProgPtr^.Name);
If ProgPtr^.Segs = 2 then (* Environment freigeben *)
error := MFree (MemW[ProgPtr^.Segment:$2C]) <> 0;
error := error or (MFree (ProgPtr^.Segment) <> 0);
If error THEN Write (' Achtung: Fehler bei Freigabe');
Writeln;
End;
Begin (* Release_Prog *)
Lowvideo; WriteLn; Write ('RELEASE v2.0');
Writeln (' (c) 1987 Karsten Gieselmann & PASCAL Int.'); Writeln;
MakeMemoryMap (FirstProg); (* Zeiger auf 1. Programm holen *)
GetPtr (LastProg); (* Zeiger auf letztes Programm holen *)
FindMarker (Seg);
If Seg <> 0 then begin (* ist MARK ueberhaupt vorhanden? *)
RestoreIntVecTable (Seg); (* Interrupt-Vektoren wieder auf alten Stand *)
Repeat
Release (LastProg); (* Speicher freigeben *)
LastProg := LastProg^.Last; (* naechstes Programm *)
until Lower (LastProg^.Segment, Seg) (* bis MARK-Segment freigegeben *)
End
else WriteLn ('Fehler: kein MARK gefunden!')
End.