PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : LPT Port Interrupt


bionicle
09.11.2008, 21:00
Hallo,
Ich habe folgendes Problem:
Ich möchte den LPT-Port als Zähler Eingang für einen Motor-Encoder nutzen (eigentlich 3 Encoder) Diese liefern jeweils 5V Rechtecksignale mit 90° Phasenverschiebung (Kanal A+B). Ich habe einen bidirekionalen LPT und möchte 6 Inputs nutzen, 3 davon sollen jeweils einen Interrupt auslösen, so dass alle eingehenden Impulse gezählt werden können und parallel noch das normale Programm läuft. Die Impulse kommen mit max. 2 kHz.
Läst sich das unter Turbo Pascal unter DOS realisieren wenn ja wie ??
Ich beschäftige mich schon eine ganze Weile mit TP aber das überfordert mich.....


Xpyder
13.11.2008, 08:40
OK, dann anworte ich mal kurz.

Der IRQ für den LPT1 ist normalerweise IRQ7. IRQ7 löst INT15 aus, d.h. man muß ne ISR (Interrupt Service Routine) auf INT15 legen. Wenn kein Plan, wie das geht, kann ich's erklären.
(Anmerkung: Der IRQ für LPT2 ist IRQ5, der INT dazu entsprechend INT13.)

So. INT 13 und 15 werden auch noch von anderen Dingen benutzt. (Soundblaster benutzt beispielsweise meistens IRQ5 (früher 7). Aber weil der PC nur 16 Hardware-IRQs hat, (wobei IRQ2 die zweiten 8 kaskadiert..., ich erklär das jetzt mal nicht so ausführlich), werden IRQs oft von mehrerer Peripherie gleichzeitig benutzt. Deswegen klinkt man die ISR nicht einfach auf den entsprechenden INT ein, sondern klinkt sie zwischen der ISR, die da vorher war und den INT, also man baut eine ISR, die, wenn sie "negativ" ausgeführt wurde, zur ursprünglichen ISR springt. (Manchmal - z.B. bei Keyboard- oder Timer-Interrupt - will man auch, wenn sie "positiv" ausgeführt wurde, trotzdem noch die Originalroutine ausgeführt wird.)

Damit man unterscheiden kann, von welchem der Geräte der INT nun kam, kann man Bits der Ports abfragen, an denen diese Geräte hängen.

LPT1 benutzt normalerweise Port $378 (und die folgenden 2)
LPT2 benutzt normalerweise Port $278 (und die folgenden 2)
LPT3 benutzt normalerweise Port $3BC (und die folgenden 2)

Ja, bei anderweitiger Benutzung werden die folgenden 3 bis 7 benutzt, also wenn man z.B. den EPC- oder EPP- Mode nutzt - aber das würde jetzt zu weit führen und gehört nicht hierher.

Die Adressen für die LPTs stehen auch in den Word-Speicherstellen $0040:$0008 (LPT1) $0040:$000A (LPT2) und $0040:$000C (LPT3). Steht dort eine 0, so ist der entsprechende LPT nicht vorhanden. (Man kann die Anzahl vorhandener LPTs auch in 2 Bits im Word an Adresse $0040:$0010 ablesen...)

Anmerkung: Es ist immer besser, die Port-Adressen aus diesen Speicherstellen zu holen, anstatt sich einfach darauf zu verlassen, daß "es schon stimmen wird".

So. Um den IRQ für einen LPT zu aktivieren ist BIT 4 in Port-Adresse+2 zu löschen. (Also 0= IRQ an).


{Fuer LPT1 sieht das so aus}
LPT1addr:=memW[$0040:$0008]; {Wir gehen mal davon aus, dass es LPT1 gibt}
port[LPT1addr+2]:=port[LPT1addr+2]and $EF; {Bit 4 loeschen}


Immer, das ACK-Bit gelöscht ist, (das ist PIN 10 des LPT!), wird nun ein IRQ ausgelöst, im Falle von LPT1 also an IRQ7 - was dann die ISR an INT15 startet.

Immer, wenn ein IRQ ausgelöst wurde, ist in Port-Adresse+1 das BIT 2 gelöscht, d.h. man braucht nur dieses Bit testen, um zu sehen, ob der IRQ von diesem LPT kam:


{Fuer LPT1 sieht das so aus}
LPT1addr:=memW[$0040:$0008]; {Wir gehen mal davon aus, dass es LPT1 gibt}
if (port[LPT1addr+1]and $04)=0 then {Bit 2 testen}
begin
{Hier das Gewollte ausfuehren}
end;


Achja, das ACK-Bit selber ist in Bit 6, ebenfalls von Port-Adresse+1 zu finden (ist dann auch 0, wenn ein ACK grad erfolgt). Wie man das testet, dürfte ja nun nicht mehr schwer rauszukriegen sein.

Die ganze Zuordnung der Bits und Pins der Ports habe ich eigentlich schon in diesem Thread aufgeführt. Ich kann auch gerne mal einen 52 kByte großen Text schicken, den ich mal aus einer HTML-Seite in DOS-ASCII-Text (Codepage 437) gewandelt habe, sogar mit Tabellen in Rähmchengrafik. (Ja, hab mir mal 'n Tool dazu geschrieben. Wenn ich in Pascal programmiere, kann ich so 'n anderes Fenster offen haben, um so Texte drin zu haben und da immer hinschalten kann. Für HTML bräuchte man wieder 'n extra Tool/Viewer und Grafikmode. Sowas tät mich nerven... (Achja, ist natürlich englisch.)

Kann Dir also wahlweise das HTML oder den ASCII-Text schicken. Oder schau doch einfach mal auf http://www.beyondlogic.org nach. (Wie oft hab ich diese Seite eigentlich schon in diesem Forum hier empfohlen...? - Hab aufgehört zu zählen...)

OK, ich hoffe, das hilft erstmal ein wenig. Wenn noch Problem, wie man eine Pascal-Routine als ISR (Interrupt-Service-Routine) einklinkt - kein Problem, frag einfach.

Und Entschuldigung, daß ich jetzt erst geantwortet habe. War etwas anderweitig beschäftigt.

bionicle
15.11.2008, 21:09
Hallo Xpyder,

Danke für die Antwort. Ich denke, ich habe alles verstanden, und auch bei 'beyondlogig' gelesen. Es bleiben aber noch ne Menge Probleme:

1. Die Parallele Schnittstelle hat nur einen Interrupt-Pin, ich brauche aber 3 !
2. Der Interrupt wird entweder an der steigenden Flanke oder an der fallenden ausgelöst, ich brauche aber einen Interrupt bei jedem Pegelwechsel !

Beide Probleme könnte man mit einer externen Elektronik lösen, was aber aufwändig ist.

Eine Zweite Möglichkeit wäre 'Polling'. Ich schaue einfach mit einer Frequenz von ca. 10 kHz nach, ob sich was am Port getan hat. Ich denke dabei an einen Timer gesteuerten Interrupt, in der ISR steht dann die Abfrage des Ports.
Dazu gleich eine Frage: gibt es einen schnelleren Befehl als:
Portbyte:=Port[$378];
was ist mit:
Portbyte:=mem[$xxx:yyy]; den habe ich mal gelesen, aber in der Hilfe von TP 7 ist das nicht ordentlich erklärt.

Wie sollte ich Deiner Meinung nach weiter machen ????

Xpyder
15.11.2008, 22:46
Hallo Xpyder,

Danke für die Antwort. Ich denke, ich habe alles verstanden, und auch bei 'beyondlogig' gelesen. Es bleiben aber noch ne Menge Probleme:

1. Die Parallele Schnittstelle hat nur einen Interrupt-Pin, ich brauche aber 3 !
Ja, das ist Hardware und läßt sich halt softwaremäßig nicht ändern. Oder, wie der Assember-Coder sagt: "Was auch in Assembler nicht geht, muß man löten."
2. Der Interrupt wird entweder an der steigenden Flanke oder an der fallenden ausgelöst, ich brauche aber einen Interrupt bei jedem Pegelwechsel !
Ja, wie gesagt... Daran kann man erstmal nichts ändern...

Beide Probleme könnte man mit einer externen Elektronik lösen, was aber aufwändig ist.
So ist es...

Eine Zweite Möglichkeit wäre 'Polling'. Ich schaue einfach mit einer Frequenz von ca. 10 kHz nach, ob sich was am Port getan hat. Ich denke dabei an einen Timer gesteuerten Interrupt, in der ISR steht dann die Abfrage des Ports.
Ja. Der Timer-Interrupt ist IRQ1, der liegt auf INT9. (Gibt noch n anderen, den RealTimeInterrupt auf INT112 (70hex), aber der ist etwas "aufwendiger" zu aktivieren und der kann auch nur Zeitintervalle in 1/2 hoch n Sekunden (also 1, 1/2, 1/4, 1/8, 1/16, 1/32, 1/64 .... bis 1/32768 Sekunde).

Dazu gleich eine Frage: gibt es einen schnelleren Befehl als:
Portbyte:=Port[$378];
In Pascal nicht. Und Port[] ist nur ein "Pseudo-Array", also kein richtiges Array, das ist nur von Pascal so gemacht. Und - GANZ WICHTIG! - Ports sind etwas anderes als Speicher!
mem[], memW[] und memL[] greifen auf Speicher zu, also mem[x:y] ist das Byte an Segment x, Offset y.
Ports dagegen sind andere Dinge, halt Hardwareschnittstellen, die durchnumeriert sind.

was ist mit:
Portbyte:=mem[$xxx:yyy]; den habe ich mal gelesen, aber in der Hilfe von TP 7 ist das nicht ordentlich erklärt.
Ja, wie gesagt, damit kriegst Du den Inhalt von SPEICHERSTELLEN, aber nicht die Zustände vn Ports. Und Port[portadresse] wird meines Wissens in Pascal sowieso in die entsprechenden "IN" und "OUT" Befehle des Maschinencodes compiliert. Also es gibt da nichts "schnelleres". Und es ist so: Portzugriffe sind nur so schnell, wie die entsprechende Hardware. Der LPT kann (haben wir getestet - 'n Kumpel und ich) nur zwischen 500000 und 600000 Zugriffe bearbeiten (Lesen ODER Schreiben), hängt ein wenig von der Hardware ab, aber wir sind nie über 600000 gekommen - was aber für Deine Zwecke wohl ausreicht. (Für uns reichte es damals nicht, wir haben dann "getrickst"...)

Wie sollte ich Deiner Meinung nach weiter machen ????

Den Timer-Interrupt statt des LPT-Interrupts benutzen und den Port im Timer-Interrupt regelmäßig "von Hand" abfragen.
Man kann den Timer-Interrupt auf alle Teiler von 1193180 zwischen 1 bis 65536 stellen, der niedrigste Wert ist also ca. 18,2 mal pro Sekunde (das ist der Wert, auf den dieser Timer auch original eingestellt ist), der höchste Wert ist 1193180 mal pro Sekunde (liebe Pfennigfuchser: Ja, ich weiß, daß der wirkliche Wert vielleicht auch 1193181.81818181 oder sowas sein könnte....)
Achso: Zu hohe Frequenzen könnten evtl den Rechner abstürzen lassen. (Wenn nix mehr außer dem Interrupt ausgeführt wird, weil er dann zu oft den Interrupt aufruft, das Hauptprogramm gar keine Zeit mehr hat. Oder weil er grad im Interrupt ist und dann schon der nächste kommt. Dann würde quasi sofort, nachdem man das I-Flag (das Interrupts sperrt, solange man sich in einem befindet) wieder "an" ist, der nächste Interrupt erfolgen... usw... - also: Keine zu hohen Frequenzen benutzen - außer... Naja. also mit allem bis so ca. 50000 Hz kann eigentlich nichts passieren... Es liegt auch daran, wie lang die ISR ist (muß natürlich bei 50000 Hz in weniger als 1/50000 Sekunde ausgeführt sein, klar oder?)

Dadurch, daß man TEILER von dieser Zahl benutzt, wird man natürlich nur einen Näherungswert von der gewünschten Frequenz erhalten, also wenn man z.B. 400 Hz haben will, stellt man den Ticker auf 1193180 / 400, (wäre 2982,95) aber man kann nur ganze Zahlen (word) da einstellen, also mit 2982 erhielte man 400.12743 Hz und mit 2983 erhielte man 399.99329 Hz. Kann man halt testen, was näher an der gewünschten Frequenz liegt, aber ich denke mal, es ist eine ausreichende Genauigkeit.

Ich hab das mal vor ner Teile gemacht und benutze es jetzt nur noch. Es ist eine Subroutine, die ich in eine meiner Units eingebaut habe, die sich in den INT9 (IRQ1) einklinkt, die Frequenz ändert und eine Pascal-Procedure diese zuweist.

Aufgerufen wird sie mit:
InstallTimer(@MeineRoutine,1193180 div gewuenschteFrequenz,1);
(wichtig: das @)
(wichtig:1193180 div gewuenschteFrequenz muß einen Wert zwischen einschließlich 0 und 65535 ergeben! Wenn man die Original-Frequenz (diese 18.2 Hz) beibehalten will, schreibt man statt 1193180 div gewuenschteFrequenz einfach 0. (Das entspricht für den Ticker 65536.)

Beendet wird sie mit:
InstallTimer(nil,0,0);
Wobei nur die letzte 0 wichtig ist, die anderen Parameter können beim Beenden egal sein.

Achja: Ich hab da n bißchen Assembler benutzt. Kann man auch alles in Pascal machen, bei Wunsch schreib ich das noch um.

Also, hier den Code, den ich rauskopiert habe. Ohne Garantie erstmal. (aber bei mir funktionierts)
Achja: Die globale Variable DOSTIMERcall kann man TRUE oder FALSE setzen. Ist sie TRUE, dann wird die normale DOS-Timer-Routine weiterhin aufgerufen (mit den normalen 18.2 Hz), egal, ob da eine zusätzliche Routine mit anderer Frequenz zusätzlich drinhängt. Wenn man die auf FALSE setzt, wird NUR die eigene Routine aufgerufen und NICHT mehr die DOS-Timer-Routine. (Das bedeutet, daß die DOS-Uhr an 64:108 ($0040:$006C) nicht mehr weiterläuft. Weiß nicht, ob der DOS-Ticker noch was anderes macht, außer Uhr+Datum zu stellen. Laß es am besten auf TRUE.)
TIMERinstalled wird von der InstallTimer-Procedure auf TRUE oder FALSE gesetzt, je nachdem, ob die Routine grad installiert ist oder nicht. Das wird benutzt, um nicht 2mal "übereinander" zu installieren - oder zu de-installieren, wenn sie gar nicht installiert ist. Man kann also am Ende des Programms einfach schreiben: InstallTimer(nil,0,0) - damit wird die Routine auf jedenfall aus dem Timer-Int entfernt. Wenn sie nicht drin war, wird das ignoriert.

Und ja: Die Routine ist schon etwas älter. Sie tut ihren Dienst und deswegen laß ich die so. Heute würd ich die wahrscheinlich anders machen (und vielleicht auch in 100% Asm), aber sie ist ja nur dazu da, dieses Timer-Ding an- und auszuschalten.


const DOSTIMERcall:boolean=true;{Wenn TRUE, wird bei aktiviertem
Timer-Int der DOS-Timer trotzdem aufgerufen}
TIMERinstalled:boolean=false; {Ob Timer-Interrupt-Routine installiert}

realTIMERint,igTIMERproc:Procedure; {Werden gebraucht. Sichern den Pointer der alten und der neuen ISR.}


{---------------------------------------------------------------------------}
procedure igbiosTIMERINTPROC; INTERRUPT;
begin
asm push ax; mov al,20h; out 20h,al; pop ax;end;{Int Controller gleich hier rcksetzen?}
{ASM CLI END; {Ints sperren - deaktiviert}
ASM
STI
pusha {alle Register sichern }
push es
call [igTimerProc] {Routine aufrufen }
pop es {Register wiederherstellen }
popa
END;
{asm CLI end; {Ints sperren wegen Rekursion}
dec(igbiosCounter,igbiosTICKER); {muá alter Timer-Handler auf- }
if (igbiosCounter<igbiosTICKER) and DOSTIMERcall then {gerufen werden ? (18.2 Hz=$FFFF}
begin {Warteschritte des Timer-Chips) }
{igbiosCounter:=$FFFF;}{Es wird das WRAPping benutzt...}
asm
pushf {alte Routine aufrufen }
call [realTIMERint]
end;
end
else(*
asm {sonst nur Int-Controller zurcksetzen durch lesen/schreiben von port $20}
push ax; mov al,20h; out 20h,al; pop ax;
end*);
asm STI end; {Ints wieder erlauben }
end;
{---------------------------------------------------------------------------}
procedure SetTimer(value:word); assembler;
asm CLI; mov al,$34; out 43h,al; mov AX,value; out 40h, AL; xchg AH,AL; out 40h,AL; STI; end;
{---------------------------------------------------------------------------}
{Installiert den Timer-Interrupt, wenn MODE<>0,
oder deinstalliert ihn, wenn MODE=0
factor ist dabei der zu benutzende Zeitfaktor ausgehend von 1193180 pro sekunde}
{c:\bp\timerirq\test}
procedure InstallTimer(TIMERINTPROC:Pointer;factor:word;mode:byte);
var PR:procedure absolute TIMERINTPROC;
begin
case mode of
0 :begin {DeInstall}
igbiosTICKER:=$10000;if not TIMERinstalled then exit;
SetTimer(0);
SetIntVec($08,@realTIMERint);TIMERinstalled:=false;
end;
else begin {Install}
if TIMERinstalled then InstallTimer(nil,0,0);
igTIMERproc:=PR;igbiosTICKER:=factor; if igbiosTICKER=0 then igbiosTICKER:=$10000;
if mode=2 then begin ibGetIntVec($08,@realTIMERint);ibSetIntVec($08,@igbiosTIMERINTPROC);end
else begin GetIntVec($08,@realTIMERint);SetIntVec($08,@igbiosTIMERINTPROC);end;
SetTimer(factor);TIMERinstalled:=true;
end;
end;{case}
end;
{---------------------------------------------------------------------------}


Kannst Du so in Dein Programm einbauen. Ich hoffe, es verwirrt Dich nicht allzusehr.
So, und die Procedure, die Du TimerInstall (@MeineRoutine) übergeben mußt, muß "FAR" sein, d.h. entweder benutzt Du am Anfang Deines Programms den Schalter {$F+}, oder Du schreibst hinter den "Kopf" Deiner Procedure das Wort far;

Beispiel:

procedure MeinLustigerTicker; far;
begin
{Hier wird der LPT abgefragt, zig mal pro Sekunde}
end;


Anmerkungen zum Thema Windows:
Achja: Wichtig! Wenn man das Teil unter WINDOWS benutzen will, ist zu beachten: Man kann den Ticker nur auf maximal 1000 Hz stellen! Windows selbst ist mit 1000 Hz getaktet, wenn man niedrigere Frequenzen einstellt, funktioniert es, weil Windows das dann "runterrechnet" und selber weiter mit 1000 Hz läuft. Stellt man mehr als 1000 Hz ein, setzt Windows das auf 1000 Hz zurück.
Achtung! Bei Windows NT und Windows 2000 werden "komische" Werte draus. Wenn man da z.B. 100 Hz einstellen will, muß man mit dem Wert ca. 123 arbeiten, weil NT die eingestellte Frequenz da auf 83% abbremst. Keine Ahnung, was das soll. Mein Spiel "Xpyderz" hat dafür einen Workaround. (Testet zu Anfang die erreichte Frequenz mit Hilfe der Echtzeituhr (wo 1 Sekunde immer 1 Sekunde ist) und stellt den Wert entsprechend nach.)

Ich hoffe, das hilft Dir ein wenig. Vielleicht sollte ich dieses "Wie krieg ich einen Timer-Interrupt mit (fast) beliebiger Frequenz auf nem x86-PC hin" Ding mal als Tutorial auf meine Seite stellen...

Xpyder
15.11.2008, 22:59
Achja: Außerdem ist noch einzufügen:

const igbiosCOUNTER:word=$FFFF; igbiosTICKER:longint=$10000;

Ja, ich hab das halt aus der Unit rauskopiert und die Unit hat auch noch andere Funktionen, wie z.B. "direkte" Tastaturabfrage und Speaker auf Digitalmode setzen und so Dinge...

Falls der beim Compilieren noch meckert, weil noch woanders ne Variable oder Konstante fehlen sollte, sag Bescheid.

bionicle
17.11.2008, 18:00
Hallo,

Erst mal vielen Dank Xpyder, dass Du dir so viel Zeit für mein Problem genommen hast und Respekt für dein unfassendes Wissen !!!!!
Ich habe die 600000 Port Abfragen/sek. wiedergefunden, und das inclusive meiner ISR !! Also kann ich locker mit 60 KHz den Port abfragen und laste den alten Laptop nur zu ca 10% aus. Habe also noch 90 % für's Hauptprogramm. Es ist ja wirklich Wahnsinn was man aus einem alten 230 MHz Laptop unter DOS raus holen kann !! Ich bin also fast am Ziel aber ich kriege deinen Auszug aus der Unit nicht zum laufen:
Ich wollte daraus wieder eine Unit machen, aber beim compilieren meldet er:

Fehler 159: 286/287 - Anweisungen sind nicht zugelassen

Bei Mikrocontrollern (AT-Mega) kriege ich timergesteuerte Interrupts hin aber bei TP blicke ich einfach nicht durch !

Hast Du nicht irgenwas Idiotensicheres auf Lager ?? Wäre dir sehr dankbar

Danke in Voraus

Xpyder
19.11.2008, 00:03
Hallo,

Erst mal vielen Dank Xpyder, dass Du dir so viel Zeit für mein Problem genommen hast und Respekt für dein unfassendes Wissen !!!!!

Ach naja...

Ich habe die 600000 Port Abfragen/sek. wiedergefunden, und das inclusive meiner ISR !!
Äh... "wiedergefunden"?

Naja. Es ist so: Ich hab damals meine ganze Kiste total ausgelastet. Was bedeutet: Ich hab alle Interrupts abgeschaltet, so daß außer meinem Programm nix lief.
Mein Programm war eine kleine hundsgemeine Schleife, die nix anderes tat, außer den LPT abzufragen oder zu beschicken. Und fragte Tasten ab, aber direkt, ohne Keyboard-Interrupt.
Sinn und Zweck des Ganzen war: Zusammen mit einem Kumpel wollten wir was machen: Er lötet, ich code. Und zwar ein Teil, was hinten an den LPT angepappt wird und dann verbunden mit dem "Controller"-Eingang der PSX bzw PS2. (Hab keine.) Und der Grund, warum ich keine hab, ist, daß ich mit diesen schrecklichen Controlpads nicht zocken kann. Ich zocke mit Keyboard oder Digitaljoystick (nicht die analogen, die steuern sich zu schwammig). Und wollte dann mit dem PC über Tastatur so Ding bauen, mit dem man ne PSX/PS2 steuern kann. (Desweiteren wird über den selben Port auch die Memorycard der PSX/PS2 angesteuert, d.h. auf die Art könnte man die Festplatte des PC als simulierte Speicherkarte benutzen.)

EINZIGES Problem waren die max. 500000 bis 600000 Zugriffe. Die PSX/PS2 ist der "Master", das Pad der "Client", was bedeutet, daß die Konsole die Taktrate der Zugriffe bestimmt. Und die ist 1 MHz (1000000 "Pulse", also 500000 "halbe").Das ginge zwar theoretisch, aber es ist einfach zu knapp. Normalerweise braucht man mindestens das 3- bis 4- fache des Taktes, um den quasi ausreichend genau zu "samplen"...
Und die Schleifengeschwindigkeit war nicht das Problem (habn 486er), aber der Portzugriff riß das alles runter. Weil: Wenn aufn Port zugegriffen wird, "wartet" die CPU natürlich aufs Ergebnis. Und manche Ports sind halt langsam...


Ich bin also fast am Ziel aber ich kriege deinen Auszug aus der Unit nicht zum laufen:
Ich wollte daraus wieder eine Unit machen, aber beim compilieren meldet er:

Fehler 159: 286/287 - Anweisungen sind nicht zugelassen

Bei Mikrocontrollern (AT-Mega) kriege ich timergesteuerte Interrupts hin aber bei TP blicke ich einfach nicht durch !

Hast Du nicht irgenwas Idiotensicheres auf Lager ?? Wäre dir sehr dankbar

Danke in Voraus

Eigentlich ist das schon idiotensicher.
(Und, gut, daß mal einer den Fehler benennt und nicht einfach sagt "da is irgend'n Fehler" - auf die Art kann ich nämlich leichter rausfinden, wie ich helfen kann.)

Hast Du schon mal irgendwas von den sogenannten "Compilerschaltern" gehört?

Das sind so Dinge, die die Compilierung des Codes beeinflussen. Die stellt man normalerweise an den Anfang des Sourcecodes.

Ich setze vor jedes meiner Programme und vor jede Unit die folgenden Compiler-Schalter. Die kann man einzeln setzen, also z.B. {$A+}, oder eben durch Komma getrennt. Zu beachten: Sie sind in einem "Kommentar" zu setzen und das erste Zeichen nach dem { muß ein $ (Dollar) sein, damit der Compiler es als Compilerschalter erkennt und nicht als Kommentar benutzt.
Die im folgenden fett markierten Schalter {$G+} und {$N+} sind dazu da, um 80286er (statt nur 8086er) Code zu erzeugen.
{$A+,B-,D-,E-,F+,G+,I-,L-,N+,O-,P+,Q-,R-,S-,T-,V-,X+}
{$A+} Wechsel zwischen Byte- und Word Ausrichtung des Codes (hier: word)
{$B-} Auswertung boolescher Ausdrücke vollständig/unvollständig (hier unv.)
{$D-} Einfügen von Debug-Informationen (hier: keine)
{$E-} Laufzeitbibliothek für FPU. (hier: aus, weil FPU ja vorhanden)
{$F+} Far-Aufrufe von Procedures/Functions (hier: an)
{$G+} Erzeugen von 286er-Code ( mit G- wirds nur 8086), (hier: an)
{$I-} Fehlerprüfung von Ein/Ausgaben (hier: aus, kann man manuell prüfen)
{$L-} Einfügen von lokalen Symbolen/Namen etc in den Code (hier: aus)
{$N+} Benutzung des FPU für Gleitkomma! (hier: an)
{$O-} Übersetzung für Overlay-Code. Benutz ich nicht. Hab es aus.
{$P+} Offene String- und Array-Parameter! (Codet sich besser, also an.)
{$Q-} Bereichsüberlaufprüfung. Kostet nur Rechenzeit. Also weg damit!
{$R-} BereichsüberlaufprüfungsCode foür Array/Strings. Auch weg!
{$S-} Prüfen des Stacks vor Zugriffen. Kostet Zeit. Also weg!
{$T-} Typenprüfung bei Zeiger-Übergabe. Würde mich oft behindern, also weg!
{$V-} Strenge Prüfung von VAR-Strings... Nö! Ich nehm's eher locker.
{$X+} Erweiterte Sytax von Turbo/Borland-Pascal. Sehr nützlich, also an.
Ich persönlich schreibe also in ALLE meine Pascal-Sourcen als erstes diese Zeile hin, weil alle meine Programme normalerweise mit diesen Einstellungen arbeiten. Wenn ich da mal modifizieren will, kann ich das immer noch tun.
Also, mein Vorschlag, um sicher zu gehen: Mach es genauso, und es wird funktionieren. Möglicherweise enthält das Zeug irgendwelchen 286er/287er-Code.

{$A+,B-,D-,E-,F+,G+,I-,L-,N+,O-,P+,Q-,R-,S-,T-,V-,X+}

Achso: Pascal merkt an, daß einige der Schalter in Units nicht funktionieren. Das macht nichts! Kopier einfach trotzdem diese Zeile an alle Units und alle Programme. Die Schalter, die in Units nix bewirken, werden ignoriert und erzeugen keine Fehler beim Compilieren oder so.
Das Hauptprogramm sollte jedoch unbedingt diese Schalter haben. Denn die, die in Units "nicht funktionieren", werden nämlich von Hauptprogramm übernommen (gelten also für das gesamte Programm).
Noch was:
Es gibt auch einige dieser Optionen, die sich inmitten des Codes auch ändern können, um bestimmte Bereiche mit einer Einstellung zu compilieren und andere Bereiche mit einer anderen. Das sind aber nur EINIGE der Optionen.
Manche MÜSSEN am Programmanfang, spätestens nach dem "program" oder "unit" Befehl stehen, noch vor dem "uses" und noch vor den ersten "var", "const", "type", "procedure", "function" oder "begin" Anweisungen. Anmerkung: (nicht so wichtig...) Ich habe - ohne mich selbst loben zu wollen - vor einiger Zeit ein hypergeiles Debugging-Tool für Pascal-Sourcen geschrieben. Es arbeitet zwar nicht so perfekt, daß es mit absolut jeder eventuellen komischen Idee des Programmierers klar käme - aber schon so gut wie. Das Ding hat verschiedene Modi, in einem baut es sogar einen "Zweit-Source", den man dann compilieren kann und der dann Debugging-Befehle in den ganzen Source einbaut. Beim Laufen des Programms schreibt es diese dann in ein Logfile - darin steht, welche Procedures/Functions aufgerufen und beendet werden und auch, welche Parameter an eine Procedure/Function übergeben worden sind.
Achja: Wenn Du in Pascal auf einen Befehl gehst und Strg+F1 drückst, wird eine Hilfe zu diesem Befehl angezeigt... (Anklicken mit der rechten Maustaste funktioniert auch. Ich benutze halt selten mal die Maus.)
OK. Eigentlich schon wieder n viel zu langer Text. Entschuldige bitte.