TURBO PASCAL Run Time ErrorNach dem Motto "Keine Software ist fehlerfrei" besitzt auch CP/M-80 TURBO Pascal 3.0 einige Bugs, die leider nicht als Features durchgehen können. Neben einigen Publikationen zu diesem Thema habe ich einen bisher nirgends beschriebenen Fehler gefunden, der schon recht kurios ist.Aufgetreten ist dieser Fehler bei mir, als ich versuchte, den freien Speicher nicht als negative Zahl, wie von der Funktion memavail geliefert, wenn viel Speicher frei ist, sondern als positive Zahl zu erhalten. Der Trick ist die folgende Anweisung:
if memavail<0 then mfree:=65536.0+memavail
else mfree:=memavail;
Hierbei ist die Variable mfree vom Typ real. Die Korrektur mit der Konstanten
65536.0 erfolgt bei negativer integer Zahl, also im Breich $8000..$FFFF.
Hierbei ist $FFFF -1, also steht in mfree 65535, was ja richtig ist.
Nun zum Fehler: Bei einem einzigen Wert von memavail hängt sich der Rechner auf! Dieser Wert ist $8000. Ich habe mir mal den Code angeschaut und im Compiler bei Adresse $1008 die Funktion gefunden, die eine integer in eine real Zahl wandelt und für den Hänger verantwortlich ist. Diese Funktion sieht wie folgt aus:
;
; Adresse $1008
;
int2real:
ld a,h ; Test ob integer=0
or l
jp z,int.0 ; Wenn ja, real Resultat Null setzen
bit 7,h ; Test ob integer<0
ex af,af' ; Vorzeichen merken
call absNEG ; Integer absolut (nur positiv)
ld a,90h ; Startexponent laden
i2r.loop:
add hl,hl ; Integer solange links schieben
dec a
bit 7,h ; Bis das hoechste Bit gesetzt ist
jr z,i2r.loop
ld b,h ; Resultat holen
ld c,l
ld de,0
ld h,d
ld l,a
ex af,af' ; Altes Vorzeichen holen
ret nZ ; War negativ
res 7,b ; Real positiv machen
ret
Die Routine, die ich "int.0" genannt habe, findet sich in Adresse $07b2
des Compilers:
;
; Adresse $0b72
;
int.0:
xor a
ld l,a ; Real Resultat auf Null setzen
ld b,a
ld c,a
ld d,a
ld e,a
ld h,a
ret
Diese Routine sieht problemlos aus. Was ist nun mit der von mir genannten
Routine "absNEG" ?
;
; Adresse $0780
;
absNEG:
bit 7,h ; Test Vorzeichen
ret z ; Ende bei $0000..$7FFF
ld a,h ; Negative Zahl bilden
cpl ; als $8000..$FFFF -> $8000..$0001
ld h,a
ld a,l
cpl
ld l,a
inc hl
ret
Hier fällt auf, daß ausgerechnet die Zahl, bei der der Rechner hängt, sowohl
negativ als auch positiv identisch ist. Und hier liegt das Problem. In der
Routine "int2real" wird HL links geschoben und dann getestet, ob das Bit 7
vom Register H gesetzt ist. Falls nicht, wird weitergeschoben.
Schiebt man den Wert $8000 links, dann erhält man $0000 ! Jetzt kann man lange schieben, bis man das Bit 7 findet, es ist kein Bit mehr da ! Klar, daß der Rechner hängt. Will man dieses Problem beseitigen, so bleibt nur ein Patch, der erst das Bit prüft und dann schiebt. Leider reicht der vorhandene Platz der Routine nicht aus, so daß ein freien Platz gesucht werden muß. Die gepatchte Routine könnte wie folgt aussehen:
;
; Adresse $1008
;
int2real:
ld a,h
or l
jp z,int.0
bit 7,h
ex af,af'
;
; #### PATCH ####
;
call i2r.patch
i2r.loop:
bit 7,h ; Bit testen
jr nz,i2r.ex ; Ende wenn gesetzt
add hl,hl ; Nun schieben
dec a
jr i2r.loop
i2r.ex:
;
; #### PATCH ENDE ####
;
ld b,h
ld c,l
ld de,0
ld h,d
ld l,a
ex af,af'
ret nz
res 7,b
ret
Es fehlt genau ein Byte !! den Patch habe ich bei mir in Aresse $0106 des Compilers
gepackt, dort steht nur ein Copyright Hinweis:
;
; Adresse $0106
;
i2r.patch:
call absNEG
ld a,90h
ret
Für alle, die diesen Patch einfahren wollen, hier die Anweisungen für SID:
x>SID TURBO.COM # SID aufrufen, TURBO.COM laden CP/M 3 SID - Version 3.0 NEXT MSZE PC END 7980 7980 0100 D1FF #S106 # Angabe für Änderung 0106 6F CD # Werte ändern 0107 70 80 0108 79 07 0109 72 3E 010A 69 90 010B 67 C9 0108 68 . # Änderung fertig #S1011 # Zweiter Teil 1011 80 06 1012 07 01 1013 3E CB 1014 90 7C 1015 29 20 1016 3D 04 1017 CB 29 1018 7C 3D 1019 28 18 101A FA F8 101B 44 . # Ende #WTURBOP.COM # Neue Datei TURBOP.COM schreiben 00F1h record(s) written. #^C # Ende x> Um das Tipseln im SID überflüssig zu machen, hier eine SUBMIT Datei, die das automatisch macht. Abgedruckt in Klubzeitung Nr. 55 - März 1999. Autor: Werner Cirsovius |