Lsungsverfahren zur numerischen Lsung linearer Gleichungssysteme

TGM_98 : LINGL.*, GAUSS.SBR, GAUSS.SYS

Ronald Hasenberger / cand.ing. TU-Wien

1. Allgemeines

Bei dem hier vorliegenden Text behandle ich zunchst mglichst kurz (und dadurch auch sehr ungenau) die Theorie der Lsung linearer Gleichungssysteme, um mich anschlieend auf konkrete Lsungsverfahren, insbesondere das Gausche Eliminationsverfahren zu konzentrieren.

1.1. Notation

In diesem Text werden Matrizen durch Unterstreichen des jeweiligen Symbols gekennzeichnet z.B.:

     A = Matrix A

Die Unterscheidung zwischen eindimensionalen Matrizen (Vektoren) und zweidimensionalen Matrizen (Matrizen im eigentlichen Sinn) erfolgt dadurch, da Vektoren durch Kleinbuchstaben bezeichnet werden.

Z.B.:
     v = Vektor v
Soll auf einzelne Elemente der Matrix hingewiesen werden, erfolgt das in Indexschreibweise mit Kleinbuchstaben z.B.:

                                       
          a11  a12  a13    ...     a1n 
          a21  a22  a23    ...     a2n 
     A =  a31  a32  a33    ...     a3n 
           :    :    :              :  
          am1  am2  am3    ...     amn 
                                       

Die hier vorgestellte Matrix ist eine m x n Matrix mit m Zeilen und n Spalten.

Eine derartige Matrix kann man sich nun wieder aufgespalten in ihre Zeilen und Spalten vorstellen, wobei hierdurch m Zeilen- und n Spaltenvektoren definiert werden. Als Spaltenvektor wird im folgenden ein Vektor bezeichnet, der nur aus einer einzigen Spalte (m x 1 Matrix) besteht z.B.:

             
          s1 
          s2 
     s =  s3 
           : 
          sm 
             

Als Zeilenvektor wird im folgenden ein Vektor bezeichnet, der nur aus einer einzigen Zeile (1 x n Matrix) besteht z.B.:

                                 
     z =  z1  z2   z3   ...   zn 
                                 

Ein lineares Gleichungssystem lt sich formal als die Matrizenmultiplikation einer Koeffizientenmatrix A mit einem Spaltenvektor x, welche als Ergebnis wieder einen Spaltenvektor b ergibt, darstellen:

     A * x = b

ausfhrlich:

     a11 x1 + a12 x2 + a13 x3 + ... + a1n xn = b1
     a21 x1 + a22 x2 + a23 x3 + ... + a2n xn = b2
     a31 x1 + a32 x2 + a33 x3 + ... + a3n xn = b3
       :        :        :              :       :
     am1 x1 + am2 x2 + am3 x3 + ... + amn xn = bm

Das hierdurch erklrte System ist durchaus auch fr nicht quadratische Koeffizientenmatrizen erklrt, wobei dann aber fr die Lsbarkeit bzw. eindeutige Lsbarkeit bestimmte Voraussetzungen getroffen werden mssen, auf die ich hier nicht nher eingehen mchte (Nheres siehe (1)). Im folgenden werde ich mich ausschlielich auf quadratische Koeffizientenmatrizen (d.h. m = n) beziehen.

1.2 Lsbarkeit von linearen Gleichungssystemen

Damit ein derartiges Gleichungssystem eindeutig lsbar ist (was uns letztlich fr diesen Bereich hauptschlich interessiert), mssen einige Voraussetzungen betreffend die Koeffizientenmatrix festgehalten werden.

1.2.1 Lineare Abhngigkeit von Vektoren

Sind a1, a2, a3, ..., an beliebige Vektoren, so wird die mit beliebigen Zahlen 1, 2, 3, n gebildete Summe 

     1 a1 + 2 a2 + 3 a3 + ... + n an

eine Linearkombination der Vektoren ak genannt. Diese Linearkombination wird im n-dimensionalen Raum durch einen Polygonzug reprsentiert.

Man kann sich nun fragen, ob es durch geeignete Wahl der Konstanten k mglich ist, einen geschlossenen Polygonzug zu erzeugen d.h.:

     1 a1 + 2 a2 + 3 a3 + ... + n an = 0

Dies ist offensichtlich mglich, indem alle k zu Null gesetzt werden, wobei dann aber auch der Polygonzug (zu einem Punkt) entartet.

Ist es aber auch fr k mglich, die nicht alle gleich Null sind, so spricht man von linearer Abhngigkeit zwischen den Vektoren ak. In diesem Fall lt sich zumindest einer der Vektoren durch eine Linearkombination der restlichen Vektoren darstellen.
Z.B. sind die Vektoren

                                 
           1         4         7 
     a1 =  2 ; a2 =  5 ; a3 =  8 
           3         6         9 
                                 

linear abhngig, weil die Linearkombination

     1 a1 + 2 a2 + 3 a3 + ... + n an 

fr 1 = 1, 2 = -2 und 3 = 1 den Nullvektor ergibt, womit die Bedingung fr lineare Abhngigkeit erfllt ist.

Lineare Abhngigkeit ist immer dann gegeben, wenn eine Zeile (oder auch eine Spalte) der Koeffizientematrix ein Vielfaches einer anderen Zeile (Spalte) ist.

Die lineare Unabhngigkeit der Koeffizientenmatrix ist dann gegeben, wenn die Determinante der Koeffizientenmatrix ungleich Null ist.

1.2.2 Lsbarkeit von linearen Gleichungssystemen

Kehren wir nun wieder zurck zur Lsbarkeit von linearen Gleichungssystemen.

Es lt sich hier zeigen, da ein lineares Gleichungssystem nur dann eindeutig lsbar ist, wenn alle (n) Spalten- und Zeilenvektoren der Koeffizientenmatrix A linear unabhngig sind. Im Fall der Nichterfllung dieser Bedingung ist das Gleichungssystem entweder nur nicht eindeutig lsbar (d.h. das Ergebnis ist wiederum ein geforderter Zusammenhang zwischen verschiedenen Variablen) oder nicht lsbar. Dies hngt hauptschlich von der rechten Seite, dem Ergebnisvektor b ab.

2. Lsungsverfahren bei linearen Gleichungssystemen

2.1. Cramer'sche Regel

Die Cramer'sche Regel fhrt die Lsung eines linearen Gleichungssystemes auf die Berechnung von Determinanten zurck:

                 a11 ... a1 i-1   b1   a1 i+1 ... a1n 
            1    a21 ... a2 i-1   b2   a2 i+1 ... a2n 
     xi =    :         :      :      :        :  
          Det A   :         :      :      :        :  
                 an1 ... an i-1   bn   an i+1 ... ann 

Hierbei wird zur Berechnung der i-ten Variable jeweils die i-te Spalte der Koeffizientenmatrix durch die linke Seite ersetzt, und die Determinante der so erhaltenen Matrix durch die Determinante der ursprnglichen Koeffizientenmatrix dividiert.

Aus dieser Form ist auch (numerisch) leicht ersichtlich, da die Determinante der Koeffizientenmatrix nicht Null sein darf, da hier sonst eine Division durch Null erfolgen wrde.

Aufgrund des sehr hohen Aufwands der Berechnung von Determinanten, und der Notwendigkeit der Berechnung von n + 1 Determinanten fr die Lsung eines Gleichungssystems mit n Variablen wird dieses Verfahren selten angewendet, und wird hier auch nicht weiter behandelt.

2.2 Gausches Eliminationsverfahren

Das Gausche Eliminationsverfahren beruht darauf, da ein Gleichungssystem (nebenbei: wie auch die Determinante einer Matrix) seinen Wert nicht ndert, wenn zu (von) einer Zeile ein Vielfaches einer anderen Zeile addiert (subtrahiert) wird.

Dies wird beim Gauschen Eliminationsverfahren dazu bentzt der Reihe nach die einzelnen Variablen zu eliminieren, indem man eine Gleichung als Hauptgleichung bentzt, und zu jeder der restlichen Gleichungen ein geeignetes Vielfaches dieser Gleichung addiert, soda in diesen eine Variable nicht mehr vorkommt.

Wir betrachten hierzu das ursprngliche System,

     a11 x1 + a12 x2 + a13 x3 + ... + a1n xn = b1
     a21 x1 + a22 x2 + a23 x3 + ... + a2n xn = b2
       :        :        :              :      :
     an1 x1 + an2 x2 + an3 x3 + ... + ann xn = bn

welches sich nach dem ersten Schritt der Transformation mit der ersten Gleichung als Hauptgleichung zu

     a11 x1 + a12 x2 + a13 x3 + ... + a1n xn = b1
              a22'x2 + a23'x3 + ... + a2n'xn = b2'
                :        :              :      :
              an2'xn + an3'xn + ... + ann'xn = bn'
ergibt.

Diese Transformation ist in dieser Form nur fr a11 <> 0 mglich, was aber keine ernsthafte Beschrnkung darstellt, da durch Vertauschen zweier Zeilen, wodurch der Wert des Gleichungssystems ebenfalls nicht gendert wird, sicher eine Situation hergestellt werden kann, in der a11' <> 0 gilt; die Faktoren ergeben sich hierbei zu:

     - a21 / a11 fr die 2. Gleichung
     - a31 / a11 fr die 3. Gleichung
     - an1 / a11 fr die n-te Gleichung

Das selbe Verfahren kann man nun (fr a22' <> 0) mit der 2. Gleichung als Hauptgleichung zur Elimination der Variablen x2 aus den Gleichungen 3 bis n verwenden.

Durch weitere Anwendung dieses Verfahrens kann man auf diese Art, wenn das System berhaupt eindeutig lsbar ist, das Gleichungssystem in die Form

     r11 x1 + r12 x2 + r13 x3 + ... + r1n xn = c1
              r22 x2 + r23 x3 + ... + r2n xn = c2
                         :              :      :
                                      rnn xn = cn

berfhren, aus dem man durch Lsen der letzten Gleichung xn (= cn / rnn), mit dem Einsetzen von xn in die n-1 - te Gleichung xn-1 und so weiter bis x1 erhalten kann.

Ist die berfhrung des Gleichungssystems in die obengenannte Form nicht mglich, so ist das Gleichungssystem nicht eindeutig lsbar, d.h. singulr. Dieser Fall soll aus den weiteren Betrachtungen ausgeklammert werden, da dessen Behandlung einen wesentlich hheren Aufwand erfordern wrde.

Man erhlt dadurch ein neues, dem ursprnglichen Gleichungssystem aber quivalentes Gleichungssystem, fr welches ich folgende Notation bentzen mchte:

     R * x = c

Dieses Verfahren ist gleichwertig mit der Multiplikation der Koeffizientenmatrix A sowie der rechten Seite b mit einer unteren Dreiecksmatrix L von links (beachte: die Matrizenmultiplikation ist nicht kommutativ!). Die untere Dreiecksmatrix (eine Matrix, bei der smtliche Elemente oberhalb der Hauptdiagonale gleich Null sind) ergibt sich dabei aus der Multiplikation mehrerer (n) unterer Dreiecksmatrizen:

     L = Ln * ... * L2 * L1

Die Matrizen Lm haben dabei in der Hauptdiagonale nur Einsen stehen. Die Elemente unterhalb der Hauptdiagonale sind alle gleich Null, auer jenen in der m-ten Spalte, wo die Koeffizienten der Elimination

     - am+1m / amm
     - am+2m / amm
     - an  m / amm

stehen.

Dadurch ergibt sich z.B. die Matrix L1 zu:

                                  
                1      0  0 ... 0 
           -a21 / a11  1  0 ... 0  
           -a31 / a11  0  1 ... 0 
     L1 =  -a41 / a11  0  0 ... 0 
                :      :  :     : 
                :      :  :     : 
           -an1 / a11  0  0 ... 1 
                                  

Die Matrizen R und c ergeben sich hierbei durch:

     R = L * A
     c = L * b

Diese Darstellung ist deshalb sehr gnstig, weil sie die Berechnung eines Gleichungssystems fr eine neue rechte Seite ermglicht, ohne da dafr die gesamte Elimination nochmals durchgefhrt werden mu. Ich werde spter darauf noch zurckkommen.

3. Numerik des Gauschen Eliminationsverfahrens

Das Gausche Eliminationsverfahren, dessen Grundlagen im bisherigen Text bereits behandelt wurden ist grundstzlich sehr einfach zu programmieren. Man findet dabei fr eine einfache Version durchaus mit der Anwendung des bis jetzt Gesagten sein Auslangen.

Fr hhere Ansprche kann man das Verfahren aber noch verbessern.
Zunchst besteht hier die Mglichkeit die Genauigkeit des Verfahrens zu erhhen:

3.1 Pivotisierung des Gleichungssystems

Hierzu mchte ich zunchst kurz auf die Zahlendarstellung im Computer eingehen.

Bei modernen Programmiersprachen wird in der Regel zwischen Integer (= ganzzahligen) und Real (= gebrochenen) Zahlen unterschieden. 

Die Speicherung von Integerzahlen fhrt in der Regel kaum zu Problemen, da man sich hierbei auf einen Zahlenbereich beschrnkt, der durch die verwendete Wortlnge exakt beschrieben werden kann.

Z.B. Integer = 16 Bit Worte ==> 
     Zahlenbereich: -2^(n-1) = -32768 <= Z <= 32767 = 2^(n-1) - 1) 

Hierbei wird jede mgliche Zahl des Zahlenbereiches durch genau eine Bitkombination beschrieben, wodurch keine Fehler auftreten knnen. 

Anders ist die Situation bei Realzahlen: Hier mu ein Dezimalbruch dargestellt werden, der im Extremfall nie endet (z.B. , 1/3, ...). Derartige Zahlen knnen nicht exakt dargestellt werden, soda man zur Verarbeitung im Computer nur die ersten n Stellen des Dezimalbruches verwendet (n ist gleich der Anzahl der gltigen Stellen). Um trotzdem groe und kleine Zahlen darstellen zu knnen verwendet man hier eine Darstellung mit Mantisse und Exponent. Die Mantisse sind die eigentlichen Stellen der Zahl, der Stellenwert der gesamten Zahl ergibt sich durch Multiplikation mit 10^Exponent. 

z.B.: Mantisse = 0,1234; Exponent = 2: Zahl = 0,1234 * 10^2 = 12,34

Eine Addition wird dabei so durchgefhrt, da die beiden Zahlen zunchst durch Verschieben der Stellen der kleineren Zahl auf den Exponenten der greren Zahl gebracht und anschlieend addiert werden. Hierbei kann es aber vorkommen, da die eine Zahl soweit verschoben werden mu, da keine gltige Stelle mehr fr die Addition verfgbar ist, soda das Ergebnis so aussieht, als wenn Null addiert worden wre.

z.B.:
a) Addition von 0,1234 * 10^0 + 0,5678 * 10^2 in einem Computer mit 5 gltigen Stellen; die fhrende Null wird hierbei nicht mitgezhlt:

1. Schritt: Auf gleichen Exponenten bringen:

Hierbei werden beide Zahlen auf den Exponenten der greren Zahl gebracht.

 ==> 0,12340 * 10^0 -> 0,00123 * 10^2
     0,56780 * 10^2 -> 0,5678  * 10^2

Hierbei ging bereits die letzte gltige Ziffer des ersten Summanden verloren.

2. Schritt: Ziffernweise Addition

 ==> 0,00123 * 10^2
   + 0,56780 * 10^2
     
     0,56903 * 10^2

b) Addition von 0,1234 * 10^0 + 0,5678 * 10^8 in einem Computer mit 5 gltigen Stellen; die fhrende Null wird hierbei nicht mitgezhlt:

1. Schritt: Auf gleichen Exponenten bringen:

Hierbei werden beide Zahlen auf den Exponenten der greren Zahl gebracht.

 ==> 0,1234 * 10^0 -> 0,00000 * 10^8
     0,5678 * 10^8 -> 0,56780 * 10^8

Hierbei ging die gesamte Information des ersten Summanden veloren.

2. Schritt: Ziffernweise Addition

Dieser Schritt ist in diesem Fall eine Addition von 0 zu 0,5678*10^8

Wie bereits in der Theorie erlutert, wird beim Gauschen Eliminationsverfahren das Aij/Aii - fache einer Zeile (mit i: Nummer der zu eliminierenden Variablen, j: Nummer der Zeile, in der eliminiert werden soll) von der j - ten Zeile abgezogen. Wird dieser Faktor sehr gro, so "berdeckt" die Hauptgleichung die anderen Gleichungen. Im diesem Fall wird die Gleichung, in der eliminiert werden soll fr den Rechner mit seiner begrenzten Darstellungsmglichkeit nur mehr ein Vielfaches der Hauptgleichung sein, was die eindeutige Lsung des Gleichungssystems verhindern wrde.

Dieser Faktor wird nun (betragsmig) genau dann sehr gro, wenn Aii betragsmig sehr klein wird. 

Dies ist auch die Mglichkeit zu einer Abhilfe: Wenn als Aii das (betragsmig) grte aller Aij mit j von i bis Anzahl der Gleichungen gewhlt wird, werden die Faktoren klein gehalten (betragsmig kleiner oder gleich 1).

Die Elimination der Variablen wird daher so ablaufen, da man vor der Elimination einer Variablen das betragsmig grte Element der Koeffizientenmatrix in der Spalte der betrachteten Variablen unter und auf der Hauptdiagonale sucht, diese Gleichung zur Hauptgleichung erklrt, und mit Hilfe dieser Gleichung die Variable in den anderen Gleichungen eliminiert.

Fr die Verarbeitung im Rechner, bei der man die zu eliminierenden Variablen in der Regel in Form einer Schleife von 1 bis Anzahl der Variablen eliminieren wird, ergibt sich daher die Notwendigkeit, das Gleichungssystem umzustellen.

Hier besteht die berlegungsmig einfachste Mglichkeit die i-te Zeile mit der Zeile, in der das betragsmig grte Element gefunden worden ist, auszutauschen, indem die entsprechenden Elemente der Koeffizientenmatrix A und des Spaltenvektors b kopiert werden. Aufgrund der hohen Anzahl von Zuordnungsvorgngen ist diese Methode aber relativ langsam.

Eine zweite Mglichkeit ist die Verwendung eines Steuervektors.

3.1.1 Pivotisierung mittels Steuervektor

Hierbei bedient man sich folgender Struktur:

  s1  ->    a11  a12  ....  a1n    b1
  s2  ->    a21  a22  ....  a2n    b2
  :          :    :          :     :
  sn  ->    an1  an2  ....  ann    bn

Man definiert einen Steuervektor s, der ebensoviele Zeilen hat wie die Koeffizientenmatrix A. Bei der Adressierung der Zeilen der Koeffizientenmatrix A sowie des Spaltenvektors b adressiert man nun die zeilen nicht direkt, sondern ber den Steuervektor:

z.B. A(.s(.i.),j.), wenn man die das j-te Element der i-ten Zeile        adressieren will; ebenso beim Spaltenvektor b:
     b(.s(.i.).), wenn man die i-te Zeile des Spaltenvektors b        adressieren will.

Vor Beginn der Elimination ist dafr zu sorgen, da das i-te Element des Steuervektors den Wert i enthlt, wodurch gewhrleistet ist, da wirklich die erste Zeile adressiert wird, wenn A(.s(.1.),j.) adressiert wird.

Wenn nun aber im Zuge einer Pivotsuche die gewnschte Hauptgleichung z.B. die 5. Gleichung statt der 3. ist, so reicht ein Vertauschen von s(.5.) mit s(.3.) um den Zeilentausch durchzufhren. Es darf trotzdem nicht direkt, wie in diesem Beispiel naheliegend zu sein scheint 

   s(.5.) := 3 und 
   s(.3.) := 5 

durchgefhrt werden, da es ja mglich ist, da durch eine frhere Vertauschung s(.5.) gar nicht mehr 5 enthlt (desgleichen mit s(.3.))!

3.2 Verbesserung des Ergebnisses

Jener Ergebnisvektor x, den man nach der Durchfhrung des Gauschen Eliminationsverfahrens und anschlieender Berechnung der einzelnen Koordinaten erhlt ist zwangslufig nicht genau.

Es besteht jetzt die Mglichkeit, durch Einsetzen des Ergebnisvektors x in die ursprngliche (!!!!) Gleichung einen Fehler fr die linke Seite zu bestimmen.

  diff = b - A * xe

xe: errechneter Ergebnisvektor

Diese Differenz ist nun aber noch kein Ma fr den Fehler der Ergebnisvektors. Aufgrund der Distributivittseigenschaften der Matrizenmultiplikation gilt aber:

  A * x - A * xe = b - A * xe = diff

woraus folgt:

  A * (x - xe) = diff oder

  A * Delta_x = diff

x:       exakter Ergebnisvektor
Delta_x: Fehler, um den der errechnete Ergebnisvektor zu klein ist.

Daraus folgt nun aber, da durch Lsung des Gleichungssystems

  A * Delta_x = diff

eine (wiederum nicht exakte) Lsung fr den Fehler berechnet werden kann, der bei der Lsung des Gleichungssystems begangen wurde.

Indem dieser Fehler zur ursprnglichen Lsung addiert wird, erhlt man eine genauere Lsung des ursprnglichen Systems. Diese Iterationen sind aber nur in einem beschrnkten Ausma sinnvoll, da ja die Genauigkeit auch durch die Faktoren, mit denen die Elimination durchgefhrt wurde beeinflut wird, deren Genauigkeit aber durch diese Methode nicht gesteigert werden kann.

Zur Berechnung des Fehlervektors Delta_x gibt es nun die einfache, aber aufwendige, Mglichkeit die gesamte Elimination nochmals durchzufhren.

Schneller ist es, wenn man unter Ausntzung einiger Eigenschaften der Elimination die Berechnung fr eine neue linke Seite einfacher durchfhrt. Der Schlssel hierzu liegt in der Mglichkeit, die Elimination als Multiplikation sowohl der Koeffizientenmatrix A als auch des Spaltenvektors b mit einer unteren Dreiecksmatrix L von links zu interpretieren:

  R = L * A = Ln * ... * L2 * L1 * A
  c = L * b = Ln * ... * L2 * L1 * b

wodurch sich das Gleichungssystem, wie bei der Theorie bereits erlutert als

  R * x = c

darstellt.

Die Matrix R haben wir hierbei bereits einmal berechnet, es ist dies eine obere Dreiecksmatrix, die sich bei der Elimination von A ergibt.

Dadurch reicht es, die Matrizenmultiplikation von L mit b und anschlieend die Berechnung der xi aus dem reduziertzen System durchzufhren.

Dieses Matrizenmultiplikation kann mit der Kenntnis aller Lm ebenso gut wie mit der Kenntnis der unteren Dreiecksmatrix L durchgefhrt werden. Wenn mann alle Matrizen Lm in einem Feld speichert ergibt sich eine untere Dreiecksmatrix:

                                                 
            1           0           0      ... 0 
       -a21 / a11       1           0      ... 0  
       -a31 / a11  -a32'/ a21'      1      ... 0 
       -a41 / a11  -a42'/ a21' -a43"/ a31" ... 0 
            :           :           :          : 
            :           :           :          : 
       -an1 / a11  -an2'/ a21' -an3"/ a31" ... 1 
                                                 

Die "interessanten" Bereiche (jene, in denen eine nicht von vornherein bekannte Information steht) dieser Matrix sind angenehmerweise genau jene, die bei der reduzierten Koeffizientenmatrix Null werden, soda jene Speicherpltze der Koeffizientenmatrix, die zu Null werden, zur Speicherung eben jener Teile dieser Matrix verwendet werden knnen.

In etwas weniger mathematischer Form kann man auch sagen, da man die Quotienten, mit denen man eine Variable aus einer Gleichung eliminiert hat, am Platz des Koeffizienten fr diese Variable in der entsprechenden Gleichung abspeichert, da der Koeffizient nach der Elimination Null wird, was aufgrund der Struktur des Lsungsverfahrens bekannt ist.

Hierdurch ergibt sich nach Durchfhrung der gesamten Reduktion mit Speicherung der Quotienten folgender Zustand der Matrix:

                                                 
             a11      a12       a13    ... a1n   
          a21 /a11    a22'      a23'   ... a2n'  
     A'=  a31 /a11 a32'/a2'     a33"   ... a3n"  
              :        :         :     ...  :    
          an1 /a11 an2'/a22' an3"/a33" ... ann"' 
                                                 

Bei der Berechnung der cn wird nun sinnvollerweise wieder das Feld fr die bn doppelt verwendet, wodurch sich als eine Mglichkeit zur Berechnung der cn folgende Methode ergibt, wobei nicht mehr zwischen bn und cn unterschieden wird, da nur ein Array vorhanden ist.

  Ŀ
   I := 1 to Dim - 1                            
   Ĵ
    J := I + 1 to Dim                          
    Ĵ
     b (.J.) := b (.J.) - A (.J,I.) * b (.I.) 
  

4. Weitere Anwendungen des Gauschen Eliminationsverfahrens

4.1 Berechnung von Determinanten

Fr die Berechnung von Determinanten mit Hilfe von Computern ist der wesentlichste Satz jener, da bei einer oberen oder unteren Dreiecksmatrix der Wert der Determinante gleich dem Produkt der Elemente der Hauptdiagonale ist.

Das Gausche Eliminationsverfahren ist nun ein Verfahren, welches eine Matrix in eine obere Dreiecksmatrix umwandelt, soda (im wesentlichen) nur mehr die Elemente der Hauptdiagonale miteinander multipliziert werden mssen.

Das Vorzeichen der Determinante ist nach dieser Manahme aber noch nicht unbedingt korrekt, da eine Determinante bei einer Vertauschung von Zeilen oder Spalten ihr Vorzeichen wechselt, das heit, es ist notwendig das Produkt der Elemente der Hauptdiagonale mit (-1)^Anzahl der Vertauschungen zu multiplizieren.

4.2 Inversion von Matrizen

Matrizeninversion kann am einfachsten durchgefhrt werden, indem man n Gleichungssysteme in n Variablen lst:

  A * X = E

X ist hierbei eine n x n Matrix, die Inverse zu A. Die linke Seite ist in diesem Fall ebenfalls eine Matrix, die Einheitsmatrix, bei der alle Elemente auer den Elementen der Hauptdiagonale 0 sind; letztere sind 1.

                        
        1   0   0 ... 0 
        0   1   0 ... 0 
   E =  0   0   1 ... 0 
        :   :   :     : 
        0   0   0 ... 1 
                        

Diese Gleichungssysteme kann man auf 2 Arten relativ effizient lsen:

Die erste Mglichkeit wre die spaltenweise Bestimmung der Inversen X indem in ein Gleichungssystem

  A * x = b

der Reihe nach als rechte Seite die Spalten der Einheitsmatrix eingesetzt werden. Die m-te Spalte der Inversen ist hierbei die Lsung des obigen Gleichungssystems mit der m-ten Spalte der Einheitsmatrix (alle Elemente gleich 0; nur das m-te gleich 1) als rechter Seite. Hierbei mte nur einmal das gesamte Eliminationsverfahren abgearbeitet werden, danach knnte man das Verfahren zur Berechnung eines Gleichungssystems mit genderter rechter Seite verwenden.

Dieses Verfahren bietet sich insbesondere an, wenn man auf ein vorhandenes System von Unterprogrammen zur Durchfhrung des Gauschen Eliminationsverfahrens zurckgreifen kann.

Die zweite Mglichkeit ist wahrscheinlich etwas schneller, bentigt aber doch einige spezielle Unterroutinen:

Hierbei wird das gesamte System

  A * X = E

betrachtet. Multipliziert man dieses System von links mit einer unteren Dreiecksmatrix L vom selben Aufbau wie beim Gauschen Eliminationsverfahren, so erhlt man folgendes System

  R * X = L,

wobei die Matrix R die in eine obere Dreiecksmatrix umgerechnete Koeffizientenmatrix ist. Hierbei kann man die Spalten der Inversen X erhalten, indem man die Rckrechnung (!) des Gauschen Eliminationsverfahrens fr ein Gleichungssystem durchfhrt, dessen rechte Seite die entsprechende Spalte der unteren Dreiecksmatrix L ist. Die Dreiecksmatrix L mte hierbei aber explizit berechnet werden.

5. Hinweise zur Programmierung

Es empfiehlt sich bei der Programmierung eines derartigen Programmes, eine Routine zu schreiben, die einem die Gestalt des aktuellen Gleichungssystems zeigt.

Im Falle der Verwendung der Version mit Steuervektor bedeutet dies, da sowohl die Information vorhanden sein sollte, welche Zeile des ursprnglichen Systems eine ausgedruckte Zeile ist, als auch welche Zeile des aktuellen Systems sie darstellt, oder, was die selbe Information beinhaltet, wo die Quotienten enden und die eigentliche Koeffizientenmatrix beginnt.

Bei der Durchfhrung des Eliminationsverfahrens ist weiter darauf zu achten, da eine Division durch Null verhindert (abgefangen) wird, wobei die Abfrage besser nicht auf Null erfolgen sollte, sondern eine, vom Problem abhngige Schwelle gesetzt werden sollte, unter der angenommen wird, da dieses Element in Wirklichkeit (bei unendlich genauer Rechnung) Null wre. In diesem Fall ist das Gleichungssystem nicht eindeutig lsbar.

6. Quellennachweis

(1) H.J. Dirschmid; Mathematische Grundlagen der Elektrotechnik
         2. Auflage 1987; 
         Verlag Vieweg

(2) Mathematik A2 fr Elektrotechnik
         Vorlesung 101.695 Sommersemester 1987/88 Prof. Dirschmid
         Technische Universitt Wien

(3) Programmiertechnik fr Elektrotechniker
         Vorlesung 356.895 Wintesemester 1988/89 Prof. Barth
         Technische Universitt Wien

GAUSS.SYS

(* Dieses File definiert alle ntigen Typen fr das Programm Gauss *)

Const MaxN = 20;       (* Maximalanzahl der Gleichungen und Variablen *)
      Minimum = 1E-30; (* Grenze fr die Erkennung einer singulren   *)
                       (* Matrix                                      *)

Type Koeff = Array (.1..MaxN, 1..MaxN.) of Real;
                       (* Typ fr die Speicherung der Koeffizienten   *)
     Spalte = Array (.1..MaxN.) of Real;
                       (* Typ zur Speicherung der rechten Seite und   *)
                       (* des Ergebnisvektors                         *)
     ISpalte = Array (.1..MaxN.) of Integer;
                       (* Typ zur Speicherung des Steuervektors       *)


GAUSS.SBR

(* Dieses Unterprogrammpaket berechnet ein lineares Gleichungssystem
   der Form

   Ax = B,

   A ... Matrix n x n (n: Dimension des Systems)
   B ... Ergebnisvektor (Matrix n x 1)
   x ... Variablenvektor (Matrix n x 1)                               *)

Procedure Gauss_Druck (DA: Koeff; DB:Spalte; DSteuer: ISpalte; DDimension: Integer);

(* Procedure zum Drucken eines gestaffelten Systems, wobei zwischen den
   Quotienten und der eigentlichen Matrix ein  gezeichnet wird               *)

Var I, J:          Integer;  (* Zhlervariablen *)
    Dummy:         Char;     (* Dummy Zeichen zum Warten auf die Fortsetzung *)

Begin (* Gauss_Druck *)
      Writeln;
      Writeln;
      For I := 1 to DDimension do
          Begin For J := 1 to DDimension do
                Begin If DSteuer (.I.) = J then Write (' ')
                                           else Write ('  ');
                      Write (DA (.I,J.):7:1);
                End;         
                (* Schreiben der Quotienten und der gestaffelten Matrix *)
                Writeln (' = ',DB (.I.):7:1);
                (* Schreiben des entsprechenden Elements, rechte Seite *)
          End;
      Writeln;
      Writeln ('Weiter mit Return');
      Read (Dummy);          
      (* nach dem Einlesen Fortsetzung des Programms *)
End;  (* Gauss_Druck *)

Procedure Gauss_Init (Var ISteuer: ISpalte; IDimension: Integer);

(* Initialisierung des Steuervektors *)

Var I:             Integer;  (* Zhlervariable *)

Begin (* Gauss_init *)
      For I := 1 to IDimension do
          ISteuer (.I.) := I;
End;  (* Gauss_Init *)

Procedure Gauss_neue_Rechte (LA:Koeff; Var LB: Spalte; LSteuer: ISpalte; LDimension: Integer);

(* Diese Procedure berechnet die zur gestaffelten Matrix passende 
   rechte Seite aus der ursprnglichen rechten Seite des Systems
*)

Var I, J:          Integer;  (* Zhlervariablen *)

Begin (* Gauss_neue_Rechte *)
      For I := 1 to LDimension - 1 do
          For J := I + 1 to LDimension do
              LB (.LSteuer (.J.).) := 
                 LB (.LSteuer (.J.).) - LA (.LSteuer (.J.),I.) 
                 * LB (.LSteuer (.I.).);
End;  (* Gauss_neue_Rechte *)

Procedure Gauss_Elim (Var GA:Koeff; Var GB: Spalte; Var GSteuer: ISpalte; GDimension: Integer; Var Nicht_Singulaer: Boolean);

(* Diese Procedure rechnet die Koeffizientenmatrix GA um in die
   gestaffelte Koeffizientematrix, wobei der Steuervektor verndert
   wird, und in den zu 0 gemachten Koeffizienten der Quotient Q
   gespeichert wird                                                   *)

Var I, J:           Integer; (* Zhlervariablen *)
    Max_Betrag:     Real;    (* maximaler Betrag, *)
                             (* der von Abs_Max gefunden wurde *)

Function Abs_Max (GAA: Koeff; Var GASteuer: ISpalte; GADimension: Integer; GAZeile: Integer): Real;

(* Diese Function bestimmt das betragsmig grte Element 
   der Koeffizientenmatrix GAA in der Spalte GAZeile unter der 
   Hauptiagonale unter Beachtung des Steuervektors GASteuer, 
   und tauscht die Zeile, in der das betragsmig grte Element 
   gefunden wurde durch Vernderung des Steuervektors in die
   Zeile GAZeile. Der Rckgabewert von Abs_Max ist 
   der grte gefundene Betrag *)

Var I:             Integer;   (* Zhlervariable                    *)
    Hilf:          Integer;   (* Hilfsvariable zum Zeilentausch    *)
    Max:           Real;      (* grtes bisher gefundenes Element *)
    Max_Zeile:     Integer;   (* Zeile, in der Max gefunden wurde  *)

Begin (* Abs_Max *)
      Max := ABS (GAA (.GASteuer (.GAZeile.),GAZeile.));
      Max_Zeile := GAZeile;
      For I := GAZeile + 1 to GADimension do
          If ABS (GAA (.GASteuer (.I.),GAZeile.)) > Max then
             Begin Max := ABS (GAA (.GASteuer (.I.),GAZeile.));
                   Max_Zeile := I;
             End;  (* Suche Zeile mit absolut grtem Element *)
      If Max_Zeile <> GAZeile then           (* vertausche die Zeilen *)
                                             (* GAZeile und Max_Zeile *)
         Begin Hilf := GASteuer (.GAZeile.);
               GASteuer (.GAZeile.) := GASteuer (.Max_Zeile.);
               GASteuer (.Max_Zeile.) := Hilf;
         End;
      Abs_Max := Max;
End;  (* Abs_Max *)


Procedure Gauss_Single (Var GSA: Koeff; GSSteuer: ISpalte; GSDimension: Integer; GSZeile: Integer);

(* Diese Procedure macht einen Schritt einer Gau-Transformation, d.h. sie
   transformiert die Koeffizientenamtrix derart, da in der Spalte GSZeile
   unter der Hauptdiagonale nur mehr Nullen stehen wrden.
   Tatschlich werden in jene Elemente aber die bei der Berechnung ver-
   wendeten Quotienten geschrieben
 *)

Var I, J:           Integer; (* Zhlervariablen *)
    Q:              Real;    (* Quotient        *)

Begin (* Gauss_Single *)
      For I := GSZeile + 1 to GSDimension do
                            (* I zhlt die Zeilen *)
          Begin Q := GSA (.GSSteuer (.I.),GSZeile.) / 
                     GSA (.GSSteuer (.GSZeile.),GSZeile.);
                GSA (.GSSteuer (.I.),GSZeile.) := Q;
                (* Koeffizientenmatrix wird gleichzeitig 
                   zum Speichern der Quotienten verwendet *)
                For J := GSZeile + 1 to GSDimension do
                (* J zhlt die Spalten bei der Umrechnung einer Zeile 
                   in die gestaffelte Form *)
                    GSA (.GSSteuer (.I.),J.) := 
                        GSA (.GSSteuer (.I.),J.) - 
                        Q * GSA (.GSSteuer (.GSZeile.),J.);
          End;
End;  (* Gauss_Single *)

Begin (* Gauss_Elim *)
      Nicht_Singulaer := true;
      For I := 1 to GDimension do
          If Nicht_Singulaer then
             Begin Max_Betrag := Abs_Max (GA,GSteuer, GDimension, I);
               (* suche abolut grtes Element in der Spalte I 
                  unterhalb der Hauptdiagonale *)
               (* und tausche die dazugehrige Zeile in die Zeile I *)
                   If not (Max_Betrag < Minimum) then
                          Gauss_Single (GA,GSteuer, GDimension, I)
                            (* fhre einen Schritt der Transformation aus
                             *)
                      else Nicht_Singulaer := false;
             End;
      Gauss_neue_Rechte (GA, GB, GSteuer, GDimension);
End;  (* Gauss_Elim *)


Procedure Gauss_Rueck (RA: Koeff; RB: Spalte; RSteuer: ISpalte; RDimension: Integer; Var OK: Boolean; Var RX: Spalte);

(* Diese Procedure erledigt die Rckrechnung von einer gestaffelten Matrix
    mit passender linker Seite auf den Variablenvektor x *)

Var I, J:          Integer;
    Hilf:          Real;  (* Hilfsvariable zum Berechnen des Divisors *)

Begin (* Gauss_Rueck *)
      OK := true;
      For I := RDimension downto 1 do
          (* I zhlt die Zeilen = Elemente des Ergebnisvektors *)
          Begin Hilf := RB (.RSteuer (.I.).);
                For J := RDimension  downto I + 1 do
                    (* J zhlt die Spalten bei der 
                       Rcktransformation eines Elements 
                       des Ergebnisvektors *)
                    Hilf := Hilf - RX (.J.) * RA (.RSteuer (.I.),J.);
                If (Abs (RA (.RSteuer (.I.),I.)) > Minimum) then 
                   RX (.I.) := Hilf / RA (.RSteuer (.I.),I.)
                             (* Verhinderung einer Division durch 0 *)
                else OK := false;
          End;
End;  (* Gauss_Rueck *)

Procedure Gauss_Defekt (RkA: Koeff; RkB: Spalte; RkSteuer: ISpalte; RkDimension: Integer; RkX: Spalte; Var RkD: Spalte);

(* Gauss_Defekt berechnet die Differenz zwischen dem Vektor B 
   der Angabe und dem Vektor B, der bei einem Einsetzen 
   des berechneten Variablenvektors in die ursprngliche Matrix A
   entstehen wrde *)

Var I, J:          Integer;  (* Zhlervariablen *)

Begin (* Gauss_Defekt *)
      For I := 1 to RkDimension do
          Begin RkD (.I.) := RkB (.I.);
                For J := 1 to RkDimension do 
                  RkD (.I.) := RkD (.I.) - RkA (.I,J.) * RkX (.J.);
          End;
End;  (* Gauss_Defekt *)


LINGL.PAS

Program Lingl;               (* Lsen eines linearen Gleichungssystems *)

(*$I GAUSS.SYS *)            (* Definition der Typen fr Gauss         *)

Var Koeffmat:      Koeff;    (* Koeffizientenmatrix fr Gauss          *)
    Rechte:        Spalte;   (* rechte Seite fr Gauss                 *)
    Koeffmat2:     Koeff;    (* original Koeffizientenmatrix 
                                fr Defektberechnung *)
    Rechte2:       Spalte;   (* original rechte Seite 
                                fr Defektberechnung *)
    Steuer:        ISpalte;  (* Steuervektor                           *)
    Dim:           Integer;  (* Dimension des Gleichungssystems        *)
    X:             Spalte;   (* Ergebnisvektor des Gleichungssystems   *)
    Differenz:     Spalte;   (* Defekt des Gleichungssystems           *)
    DeltaX:        Spalte;   (* Fehler des Ergebnisvektors             *)
    OK:            Boolean;  (* Hilfsvariable, die anzeigt, 
                                ob die letzten Operationen
                                ordnungsgem abliefen                 *)
    I:             Integer;  (* Zhlervariable zum allgemeinen Gebrauch*)
    Dummy:         Char;     (* Dummychar zum Bremsen des Programms    *)

(*$I GAUSS.SBR *)            (* Prozeduren und Funktionen fr Gauss    *)

Procedure Eingabe (Var Matrix: Koeff;Var LSpalte: Spalte; Var Nbr: Integer; Var EingabeOK: Boolean);

(* Procedure zum Einlesen des Gleichungssystemes

   Die Eingabe kann wahlweise von einem Textfile oder der Tastatur erfolgen.

   Das Textfile mu dabei alle Informationene beinhalten, die sonst vom Benutzer
   abgefragt wrden:

   o) Dimension des Gleichungssystems
   o) Koeffizientenmatrix
   o) rechte Seite

   Aufbau des Textfiles:

   Dimension
   a11   a12    b1
   a21   a22    b2                                                           *)

Var Eing_File:     Text;     (* File, von dem gelesen werden kann       *)
    Eing_Filenam:  String (.11.);
                             (* Name des Eingabefiles                   *)
    I, J:          Integer;  (* Zhlervariablen                         *)
    Eing_Quelle:   Char;     (* Single Char fr div. Abfragen           *)
    E_File:        Boolean;  (* true, wenn vom File gelesen werden soll *)

Begin (* Eingabe *)
      EingabeOK := true;
      Write ('Eingabe von File oder von Tastatur (F/T): ');
      Readln (Eing_Quelle);
      If (Eing_Quelle in (.'F','f'.)) then E_File := true
                                      else E_File := false;
      If E_File then Begin Repeat 
                           Write ('Eingabefilename:             ');
                                  Readln (Eing_Filenam);
                                  Writeln;
                                  Assign (Eing_File, Eing_Filenam);
                                  (*$I-*) Reset (Eing_File);(*$I+*)
                           Until (IOResult = 0);
                           Readln (Eing_File,Dim);
                           If Dim > MaxN then 
                           Begin 
                             Writeln ('Dimension des Gleichungssystems 
                                       zu gro');
                             EingabeOK := false;
                             Delay (10000);
                           End;
                     End
                else Begin Repeat Write 
                                    ('Dimension des Gleichungssystems:');
                                  Readln (Nbr);
                                  Writeln;
                           Until Nbr <= MaxN;
                     End;
      For I := 1 to Dim do
          Begin For J := 1 to Dim do 
                 If E_File then Read (Eing_File,Matrix (.I,J.))
                 else Begin Write ('A [',I:1,',',J:1,'] = ');
                Readln (Matrix (.I,J.));
          End;
                If E_File then Readln (Eing_File, LSpalte (.I.))
                          else Begin Write ('B [',I:1,'] = ');
                                     Readln (LSpalte (.I.));
                                     Writeln;
                               End;
          End;
      If E_File then Close (Eing_File);
End;  (* Eingabe *)

Begin (* Lingl *)
      ClrScr;
      Eingabe (Koeffmat, Rechte, Dim, OK);
      ClrScr;
      If OK then
         Begin Koeffmat2 := Koeffmat;
               Rechte2 := Rechte;
               (* sichern der ursprnglichen Daten fr sptere *)
               (* Verwendung                                   *)
               Gauss_Init (Steuer,Dim);
               Writeln ('Eingegebenes Gleichungssystem');
               Gauss_Druck (Koeffmat, Rechte, Steuer, Dim);
               Writeln;
               (* Ausgabe der ursprnglichen Matrix                *)
               Gauss_Elim  (Koeffmat, Rechte, Steuer, Dim, OK);
               (* berechnen eines ersten Ergebnisses               *)
               If OK then    
               (* nur, wenn Elimination ordnungsgem              *)
                  Begin 
                    Writeln ('Gleichungssystem nach der Elimination:');
                    Gauss_Druck (Koeffmat, Rechte, Steuer, Dim);
                    (* Rcktransformation des Systems          *)
                    Gauss_Rueck 
                      (Koeffmat, Rechte, Steuer, Dim, OK, X);
                    Writeln;
                    Writeln 
                    ('Ergebnis unmittelbar nach Gleichungslsung');
                    Writeln;
                    Writeln ('Ergebnisvektor:');
                    Writeln;
                    For I := 1 to Dim do 
                      Writeln ('X',I:1,' = ',X (.I.));
                    (* Berechnung des Defekts mit ursprnglicher *)
                    (* Koeffizientenmatrix                       *)
                    Gauss_Defekt 
                      (Koeffmat2, Rechte2, Steuer, Dim, X, Differenz);
                    (* Ausgabe des Defekts                       *)
                    Writeln;
                    Writeln ('Defekt:');
                    Writeln;
                    For I := 1 to Dim do 
                      Writeln ('Defekt',I:1,' = ',Differenz (.I.));
                    (* Aufbau eines neuen Gleichungssystems mit Fehlern *)
                    (* als rechter Seite und Berechnung desselben       *)
                    (* Elimination nicht mehr ntig, da sich die        *)
                    (* Koeffizientenmatrix nicht gendert hat           *)
                    Gauss_neue_Rechte (Koeffmat, Differenz, Steuer, Dim);
                    (* Ruecktransformation -> DeltaX                    *)
                    Gauss_Rueck 
                      (Koeffmat, Differenz, Steuer, Dim, OK, DeltaX);
                    Writeln;
                    Writeln ('Fehler des Ergebnisvektors:');
                    Writeln;
                    For I := 1 to Dim do 
                    Begin 
                       Writeln ('DeltaX',I:1,' = ',DeltaX (.I.));
                       X(.I.) := X(.I.) + DeltaX (.I.);
                    End;
                    Writeln;
                    Writeln;
                    Writeln ('Weiter mit Return');
                    Read (Dummy);
                    Writeln ('Ergebnis nach 1 Iteration:');
                    Writeln;
                    For I := 1 to Dim do Writeln ('X',I:1,' = ',X (.I.));
                    Gauss_Defekt 
                       (Koeffmat2, Rechte2, Steuer, Dim, X, Differenz);
                    Writeln;
                    Writeln ('Defekt:');
                    Writeln;
                    For I := 1 to Dim do 
                      Writeln ('Defekt',I:1,' = ',Differenz (.I.));
                    Gauss_neue_Rechte (Koeffmat, Differenz, Steuer, Dim);
                    Gauss_Rueck 
                       (Koeffmat, Differenz, Steuer, Dim, OK, DeltaX);
                    Writeln;
                    Writeln ('Fehler des Ergebnisvektors');
                    Writeln;
                    For I := 1 to Dim do 
                       Writeln ('DeltaX',I:1,' = ',DeltaX (.I.));
                    Writeln;
                    Writeln ('Weiter mit Return');
                    Read (Dummy);
                  End
               else Begin Writeln;
                          Writeln ('Fehler: singulre Matrix');
                          Writeln;
                          Writeln ('Berechnung abgebrochen');
                    End;
         End;
End.  (* Lingl *)
MSDOS-Treiber fr fremde Diskettenformate
(Beantwortung einer Anfrage in den vorletzten PC-NEWS)

TGM_98 : UNIDRV.ASM, UNIDRV.SYS

Thomas Kopelent / BOKU

Dieser Treiber ist an und fr sich als Universaltreiber konzipiert, der verschiedene DOS-Formate, die vom Standardformat abweichen, als auch das ATARI ST-Format fr einen PC/AT zur Verfgung stellen. Er ist der Zeitschrift c't 11/1987 p.216 ff. entnommen. An dieser Stelle findet sich auch ein ausfhrlicher Artikel ber die Problematik des Lesens von Fremdformaten. Wenn Ihr BIOS 3,5" Laufwerke nicht standardmig untersttzt, so mssen Sie folgende Zeile in Ihr CONFIG.SYS aufnehmen:

    device=driver.sys /D:1 /F:2

wobei der Parameter D: das physikalische Laufwerk angibt.

Der Treiber UNIDRV.SYS wird zum Bearbeiten von ATARI ST-Disketten wie folgt eingebunden:

    device=unidrv.sys 80 1 2

Die Bedeutung der Parameter:
erster (80) : Anzahl der Tracks auf diesem Medium
zweiter (1) : Physikalisches Laufwerk (mu ggf. mit /D:x bereinstimmen)
dritter (2) : Dieser Parameter ist nur zum Bearbeiten von 
              ATARI ST-Disketten erforderlich. 
              '1' bedeutet einseitige Diskette, '2' zweiseitig.

Nach einem Re-Boot meldet sich der Treiber am Bildschirm (am Besten ist es, ein eventuell in AUTOEXEC.BAT enthaltenes 'CLS' zu entfernen). Er gibt selbstttig an, als welches logische Laufwerk er ATARI ST-Disketten ansprechen kann (Es handelt sich immer um den nchsten freien Laufwerksbuchstaben).
Sollen sowohl ein- als auch zweiseitige ATARI ST-Disketten bearbeitet werden, so sollte der Treiber zweimal (!!) ins CONFIG.SYS eingetragen werden; einmal mit '1' und einmal mit '2' als dritten Parameter. Sie erhalten dann zwei logische Laufwerke fr die verschiedenen Formate (ACHTUNG: nicht durcheinanderbringen !).

Nach erfolgreicher Installation lt sich das Funktionieren des Treibers am Einfachsten mit dir x: (x steht fr das neue logische Laufwerk) berprfen.

Viel Glck !
Thomas Kopelent

;****************************************************************
;*                                                              *
;*         Universeller PC-/MSDOS-Diskettentreiber              *
;*                                                              *
;* Programmname         : unidrv.asm                            *
;* Ersteller        : Martin Ernst                              *
;* Erweitert        : Peter Khlermann                          *
;* Erstellungsdatum : 11.03.86                                  *
;* letzte nderung am    : 16.08.87                             *
;* letzter Test am  : 02.09.87                                  *
;* Versionsnummer   : 3.0                                       *
;* Revisionsnummer  : 6.0                                       *
;*                                                              *
;****************************************************************

          page      72,132
          title     PC-/MSDOS-Universal-Treiber

 
false     equ  0
true equ  not false
v20  equ  false     ; fr Rechner mit 8088/86 od. 80286
;v20 equ  true      ; fr Rechner mit V20/30

lengt     equ  13h

.186
ausgabe   macro     message
          mov  dx, offset message
          mov  ah, 9
          int  21h
          endm
     
     
; diese Definition ist der Einsprung in die Monitorfunktion des c't 86

monitoreprom        segment   at 0f000h
                    org  0e000h
monitor             label     far
monitoreprom        ends


code           segment   para public
assume         cs:code,ds:code,es:code,ss:code

;=========================================================================

dskdev:   dw   -1,-1
          dw   0000100000000000b   ; Bit 11 vom Attributwort gesetzt
          dw   strategy
          dw   dskint
drvmax    db   1

ptrsav    dd   0    ; hier wird der Zeiger auf die Anorderungs-
                    ; kopfzeile gesichert
          db   3 dup (?)
     
;-------------------------------------------------------------------------

dsktbl:   dw   dskinit        ; "Init Device-Treiber"
          dw   mediac         ; "Check Media Type"
          dw   getbpb         ; "Get BIOS Parameter Block de
                              ; selektierten "Media Type"
          dw   cmderr         ; "I/O-Control Input (nicht implementiert)
          dw   dskred         ; "Read Data"
          dw   busexit        ; "Non Destruczive Read Data" (n.i.)
          dw   exit           ; "Input Status"
          dw   exit           ; "Input Flush Buffer"
          dw   dskwrt         ; "Write Data"
          dw   dskwrv         ; "Write Data" mit Verify-Funktion
          dw   exit           ; "Output Status"
          dw   exit           ; "Output Flush Buffer"
          dw   exit           ; "I/O-Control Output"
          dw   exit           ; "open"
          dw   exit           ; "close"
          dw   exit           ; "Removable Media" --> gleich nach "exit",
                              ; kein "busy", da Diskette

;-------------------------------------------------------------------------

iodat     struc
cmdlen    db   ?         ; Lnge der Tabelle
unit      db   ?         ; Einheiten-Code
cmd       db   ?         ; Befehls-Code
status    dw   ?         ; Status der Operation
          db   8 dup (?)
media     db   ?         ; Media Deskriptor Byte
trans     dd   ?         ; Transfer Adresse
count     dw   ?         ; Anzahl der Blcke oder charakter
                         ; die bertragen werden sollen
start     dw   ?         ; erster Block, der transferiert werden soll
drive     db   ?         ; zugeordnete Drive-Bezeichnung
iodat     ends

;-------------------------------------------------------------------------

bpbs struc
          db   13 dup (?)
bpb1      db   ?         ; Struktur fr die Rcklieferung von Werten
bpb2      dw   ?         ; ber die Anforderungskopfzeile
          dw   ?
bpb3      dw   ?
          dw   ?
bpbs ends

;-------------------------------------------------------------------------

dbp  struc
secsize   dw   ?         ; Sektorgre (512 bytes)
alloc     db   ?         ; Anzahl Sektoren pro Cluster
ressec    dw   ?         ; Anzahl reservierter Sektoeren
fats      db   ?         ; Anzahl der FATs
maxdir    dw   ?         ; Anzahl der Directory-Eintrge
sectors   dw   ?         ; Gesamtanzahl der Sektoren
mediaid   db   ?         ; Media Descriptor Byte
fatsec    dw   ?         ; Anzahl der Sektoren pro FAT
sectrk    dw   ?         ; Anzahl der Sektoren pro Track
                         ; (nicht Zylinder!)
koepfe    dw   ?         ; Anzahl der Kpfe (bzw. Seiten bei Floppy)
hidden    dw   0         ; versteckte (hidden) Sektoeren
dbp  ends


; IBM PS/2, 720 KByte, 80 Spuren
ibmps     dbp  <512,2,1,2,112,1440,0f9h,3,9,2>

; Philips YES
philips   dbp  <512,2,1,2,176,1440,0feh,3,9,2>

; DEC Rainbow (MS-PCDOS), 80 Spuren
decrain   dbp  <512,1,20,2,96,800,0fah,3,10,1>

; ct86, 80 Spuren, einseitig
ddrive2   dbp  <512,1,1,2,112,720,0fch,4,9,1>

; ct86, 80 Spuren, doppelseitig
ddrive1   dbp  <512,2,1,2,224,1440,0fdh,4,9,2>

; Atari ST (default: Doppelseitig, 80 Spuren)
atari     dbp  <512,2,1,2,112,1440,0f7h,5,9,2>

inittab1: dw   ibmps.secsize

;=========================================================================

stratp    proc far
; Registerbelegung beim Aufruf:
; bx = Offset der Anforderungszeile
; es = Segment der Anforderungszeile

strategy:
     mov  word ptr cs:[ptrsav],bx       ; Adresse der Zeile wird
     mov  word ptr cs:[ptrsav+2],es     ; gesichert
     ret
stratp    endp

;=========================================================================

diskint   proc far
dskint:
     if   v20
     pusha
     else
     push ax
     push cx
     push dx
     push di
     push bp
     push bx             ; erst alle Register rettesn
     push si
     endif
     push ds
     push es
     mov  si,offset dsktbl; Tabelle der Befehle
     lds  bx,cs:[ptrsav] ; in BX der Offset der Anforderungskopfzeile
     mov  al,[bx.unit]   ; AL: welche Einheit
     mov  ah,[bx.media]  ; Media Descriptor Byte
     mov  cx,[bx.count]  ; Anzahl Bytes oder Blcke
     mov  dx,[bx.start]  ; Startadresse des ersten Bytes od. Blocks
     xchg di,ax          ; AX sichern, da nun die Adresse der Befehls-
     mov  al,[bx.cmd]    ; routine berechnet wird. Dazu mu der
     xor  ah,ah          ; Befehlscode zweimal auf die Startadresse
     add  si,ax          ; der Tabelle (Wert in SI) addiert werden.
     add  si,ax
     cmp  al,18          ; Funktion grer als 18
     ja   cmderr         ; ja --> Fehler
     xchg ax,di          ; altes AX zurck
     les  di,[bx.trans]  ; DI enthlt nun den Offset, ES das
                         ; Segment der Transferadresse
     push cs             ; Datensegment gleich dem Code-Segment
     pop  ds
     jmp  word ptr [si]  ; und ab zur Befehlsroutine
     
;-------------------------------------------------------------------------

busexit:mov    ah,00000011b   ; wenn das entsprechende Device "busy" ist,
        jmp    short exit1    ; dann hierher und weiter zum gemeinsamen
                              ; Ausgang
                         
; Fehlercodes :
;          0 = schreibgeschtzt
;          1 = unbekannte Einheit
;          2 = Laufwerk nicht bereit
;          3 = unekannter Befehl in der Anforderungskopfzeile
;          4 = CRC-Fehler
;          5 = falsche Laufwerksanforderungszeilenlnge
;          6 = Seek-Fehler
;          7 = unbekanntes Media deskriptor Byte
;          8 = Sektor nicht gefunden
;          9 = Drucker hat kein Papier mehr
;         10 = Fehler beim Schreiben
;         11 = Fehler beim Lesen
;         12 = allgemeiner Fehler

cmderr:   mov  al,3           ; unbekannter Befehl --> Sprung hierher

errexit:  mov  ah,10000001b   ; Bits fr "fertig" und "Fehler" setzen
          stc
          jmp  short exit1    ; und weg
     
exit:     mov  ah,00000001b
exit1:    lds  bx,cs:[ptrsav]
          mov  [bx.status],ax ; in der Anforderungskopfzeile den
                              ; Status melden

set_double:
          cmp  atflg,1        ; ist es ein AT?
          jnz  ok2            ; nein, dann weg ohne Double Stepping an
          mov  bx,40h
          mov  es,bx
          mov  bx,90h
          add  bl,drivesel
          mov  dl,es:[bx]
          and  dl,0f0h        ; sonst das Double-Stepping aktivieren
          cmp  dl,50h         ; da wir es fr 720 KByte Disketten in HD-
          jne  ok2            ; Laufwerk abgeschaltet hatten
          mov  dl,61h
          mov  es:[bx],dl
ok2:
          pop  es
          pop  ds
     if   v20
          popa
     else
          pop  si
          pop  bx
          pop  bp
          pop  di
          pop  dx
          pop  cx             ; alle Register zurck vom BIOS-Stack
          pop  ax
     endif
          ret                 ; zurck zum DOS
diskint   endp

;=========================================================================

localer   proc near

dskwrv:
          mov  verify,1       ; wenn Verify ON
dskwrt:
          call setup          ; berprfen, ob angeforderte Sektoren
          jc   is_error       ; auerhalb der Grenzen der Diskette
          call diskwrt        ; wenn ok, dann Sektoren schreiben
          jc   is_error       ; bei SChreibfehler weg
          cmp  verify,0       ; ohne Verify sofort zum Ausgang, sonst
          jz   exit
          
          mov  verify,0       ; Kontroll-Lesen
          lds  bx,cs:[ptrsav] ; dazu die bentigten Parameter wieder
          mov  al,[bx.unit]   ; holen
          mov  ah,[bx.media]  
          mov  cx,[bx.count]  
          mov  dx,[bx.start]
          les  di,[bx.trans]
          push cs
          pop  ds
          
dskred:
          call setup          ; genauso wie beim Schreiben
          jc   is_error
          call diskrd
          jnc  exit
          
is_error:
          call derror         ; Fehlercode des INT 13 in den des Treibers
          jmp  short errexit  ; wandeln und Fehler-Ausgang benutzen
          
;------------------------------------------------------------------ -----

getbpb:
          mov  ah,al          ; bei PCDOS wird es schon ber Pointer
                              ; in DI geliefert
          mov  al,es:[di]     ; Media Byte holen, Unit Code jetzt in AH
          push ax
          push bx
          xchg ah,al
          call getpara        ; den richtigen DPB ermitteln
          mov  si,bx
          pop  bx
          pop  ax
          
getbp4:

get_bp5:  lds  bx,[ptrsav]    ; und beide Werte in der
          mov  [bx.bpb1],al   ; Anforderungszeile sichern
          mov  [bx.bpb3],si
          mov  [bx.bpb3+2],cs
          xor  al,al          ; kein Fehler
          jmp  exit           ; weg
          
;-------------------------------------------------------------------------

mediac:   xor  di,di          ; 1: not changed, 0: don't know, -1: changed
     
          mov  al,ibmifcflg   ; wenn keine IFC-Karte, 
                              ; dann nicht berprfen
          or   al,al
          jz   media1
          cmp  al,1           ; die alte FDC braucht auch kein Media Check
          jz   media1
          inc  di
          mov  al,24h         ; nur bei IFC ber callf monitor
          call romcall        ; auf "motor aus" testen
          or   al,al
          jz   mediaexit
     
media1:   xor  di,di          ; sonst eine Null, da nicht bekannt

mediaexit:
          lds  bx,[ptrsav]    ; in Anforderungszeile den Status sichern
          mov  word ptr [bx].trans,di
          mov  al,0           ; kein Fehler
          jmp  exit
     
;-------------------------------------------------------------------------

setup:    xor  si,si

          call getpara        ; hole den zum Media-Byte gehrenden DBP
          
          xchg bx,di          ; nach DI mit dem pointer
          mov  al,byte ptr [di].koepfe
          mov  ah,byte ptr [di].sectrk
          imul ah             ; Anzahl der Sektoren pro Spur
          mov  [maxsec],al    ; fr spter (berlauf in nchsten Track)
          push si
          mov  si,cx          ; CX = Anzahl zu lesende Sektoren
          add  si,dx          ; DX = Startsektor
          cmp  si,word ptr [di].sectors
          pop  si             ; grer als die gesamte Diskette
          jbe  inrange        ; Sektoren hat? Nein --> Fehler = 8
          mov  al,8           ; --> Sektor nicht gefunden
          stc
          ret
     
inrange:
          mov  [seccnt],cx    ; Anzahl zu lesende Sektoren sichern
          add  dx,si
          mov  si,bx          ; BX enthlt Offset Transferadresse
          and  bx,0fh         ; der Offset soll so klein wie mglich sein
          mov  [dmaadr],bx    ; darum wird entsprechend das Segment
          mov  ax,dx          ; in DX erhht
          xor  dx,dx
          mov  bl,[maxsec]    ; Nummer des logischen Sektors wird durch 
          xor  bh,bh          ; Maximalzahl Sektoren pro Track geteilt
          div  bx             ; das ergibt den relativen Sektor
          inc  dl             ; innerhalb des Tracks
          mov  [cursec],dl
          mov  [curtrk],ax    ; und als Quotient den Track-Wert
          mov  cl,4
          clc
          shr  si,cl          ; hier jetzt die Segmentvergrerung
          mov  cx,es
          add  cx,si
          mov  [dmasegment],cx     ; Segmentadresse sichern fr spter
     
driveeq:
          mov  cx,[curtrk]    ; sicher ist sicher
          clc                 ; kein Fehler
dirf:     ret

;-------------------------------------------------------------------------

getpara:
          mov  bx,offset ibmps     ; erster dbp-Eintrag
loopac:   cmp  ah,[bx].mediaid     ; ist es der richtige DBP ?
          jz   sfou      ; ja dann weg
          add  bx,lengt  ; sonst nchsten versuchen
          cmp  bx,offset atari+lengt    ; falls es nicht der letzte war
          jnz  loopac
     
sfou1:    mov  bx,offset atari     ; keiner stimmt, dann nehmen wir atari
sfou:     ret

;-------------------------------------------------------------------------

diskrd:   
          call reset_double   ; double stepping eventuell abschalten
rdlp:     call preset         ; Werte fr Track, Sektor, Kopf, Anzahl der
          cmp  ibmifcflg,2    ; sEKTOREN NUR BEI ifc-Karte mit uebercallf
          jnz  ueberintles    ; sonst den INT 13 benutzen
          mov  al,16h         ; Code des Callf-Monitors fr Lesen
          call uebercallf
          jmp  short rdlp2
     
ueberintles:
          mov  ah,2           ; Lesefunktionsnummer des INT 13H
          int  13h
rdlp2:    jc   errorr         ; in AH steht error-Code

          dec  [seccnt]       ; nchsten Sektor
          jnz  rdlp
          clc                 ; kein Fehler
          ret
     
errorr:   stc                 ; bei Fehler hierher
          ret
     
diskwrt:
          call reset_double
wrloop:   call preset         ; wie rdlp, nur eben schreiben
          cmp  ibmifcflg,2
          jnz  ueberintsch
          mov  al,18h
          call uebercallf
          jmp  short wrlp2
     
ueberintsch:
          mov  ah,3
          int  13h
     
wrlp2:    jc   errorr
          dec  [seccnt]
          jnz  wrloop
          clc
          ret
     
     
; Double Stepping fr die Bearbeitung normaler 80-Spur-Disketten mit 720
; KByte Kapazitt in Multifunktionslaufwerken nur in Ats abschalten.

reset_double:
          cmp  atflg,1        ; auf AT
          jz   ok1            ; nein, dann weg
          ret
     
ok1:      mov  bx,40h         ; sonst bei Adresse 40:90 oder 91
          mov  es,bx
          mov  bx,90h
          add  bl,drivesel
          and  byte ptr es:[bx],0dfh    ; maskiert das doublestep-Bit aus
          ret
     
preset:   mov  bx,[dmaadr]    ; fr den INT 13h mssen die Register belegt
                              ; werden
          mov  es,[dmasegment]     ; Segment laden
          mov  al,[cursec]
          cmp  al,[maxsec]
          jbe  gotsec1        ; zu lesender Sektor im nchsten Track ?
          inc  [curtrk]       ; ja, dann eben track erhhen
          mov  al,1           ; relativer Sektor wird 1
          mov  [cursec],al
          mov  cl,al
          xor  dh,dh          ; Kopf iost dann logischerweise 0
          jmp  short wegvon
     
gotsec1:  push bx             ; kein berlauf
          mov  bx,word ptr [di].sectrk
          mov  [secpertrak],bl; dann den Kopf berechnen, indem man
          xor  dh,dh          ; solange sectrk abzieht, bis es richtig ist
loopinc:cmp    al,bl
          jbe  nohead
          inc  dh             ; Kopf immer um eins erhhen (damit knnen
          sub  al,bl          ; wir auch Harddisks bedienen)
          jmp  short loopinc
     
nohead:   mov  cl,al          ; richtiger Sektor und richtiger Kopf
          pop  bx             ; DMA-Adresse wieder vom Stack
     
; ist es eine Diskette vom DEC Rainbow ?

     mov  ax,offset decrain   ; bei den Floppy-Disks mssen wir noch
     cmp  ax,di               ; berprfen, ob es sich eventuell um eine
     jnz  nodec               ; DEC-Rainbow-Diskette handelt (findet man 
                              ; anhand des BPB heraus)
                    
; erst prfen, ob Track 0 oder 1, denn da hat der DEC keinen Skew
; (diese Angabe im BIOS-Listing des DEC-Rainbow erwies sich leider als
; falsch, trotzdem bleibt der Code drin, falls nochmal eine nderung
; zumachen ist)

;    xor  ax,ax
;    cmp  ax,[curtrk]
;    jb   nodec
     
; jetzt Skew fr DEC Rainbow ndern

istdec:   xor  ch,ch
          push si             ; aus der Tabelle die richtige Sektornummer
          mov  si,cx
          mov  cl,scewtable[si]    ; holen
          pop  si
     
wegvon:
nodec:    mov  ax,word ptr [di].secsize
          add  [dmaadr],ax
          inc  [cursec]       ; schon den nchsten Sektor einstellen
          mov  ax,[curtrk]
          mov  ch,al
          and  ah,03h         ; und in CL (Sektor) zustzlich die beiden
          ror  ah,1           ; oberen Bits als Track benutzen
          ror  ah,1
          or   cl,ah          ; oberes Byte der Track-Nummer
          mov  dl,[drivesel]
          mov  al,1
          ret
     
;-------------------------------------------------------------------------

derror:   lds  bx,cs:[ptrsav] 
          mov  [bx.count],0
          push cs             ; Fehlermeldung des INT 13h in Meldung
          pop  ds             ; fr DOS umsetzen
          cmp  ibmifcflg,0    ; nur beim PC oder AT kann der Flopy-
          jnz  no_pc          ; Controller zurckgesetzt werden
          push ax
          xor  ax,ax          ; Reset auf Controller
          cwd
          int  13h
          pop  ax
no_pc:
          test ah,80h         ; Zeitberschreitung (time out)
          jz   de1
          mov  al,2
          ret
     
de1:      test ah,40h         ; Spur nicht gefunden (Seek-Error)
          jz   de2
          mov  al,6
          ret
     
de2:      test ah,3           ; schreibgeschtzt
          jz   de3
          xor  al,al
          ret
     
de3:      test ah,10h         ; CRC-Error
          jz   de4
          mov  al,4
          ret
     
de4:      test ah,2           ; Sektor nicht gefunden
          jz   de5
          mov  al,8
          ret
     
de5:      test ah,4           ; Bad Adress Mark
          jz   de6
          mov  al,8
          ret
     
de6:      or   ah,ah          ; berhaupt ein Fehgler aufgetreten ?
          jz   dee
          mov  al,12          ; dann ist es ein allgemeiner Fehler
     
dee: ret


; Skewtable fr den DEC-Rainbow

scewtable      db   0,1,3,5,7,9,2,4,6,8,10

verify         db   0

drivesel       db   0
cursec         db   0
curtrk         dw   0
dmaadr         dw   0
dmasegment     dw   0

maxsec         db   0    ; Anzahl Sektoren pro Zylinder

seccnt         dw   0
secpertrak     db   0

atflg          db   0    ; 0 = PC/c't86, 1 = AT

ibmifcflg db   0    ; 0 = PC/AT , 1 = c't86-FDC, 2 = c't86-IFC

; ab hier transienter Code, wenn PC oder AT

uebercallf:
          push ax        ; INT 13h - Aufruf in einem Callf-Monitor
          push cx        ; umsetzen
          push dx
          push bx
          mov  cx,es
          mov  al,14h    ; Setze Segment
          call romcall
          pop  cx
          mov  al,0ch    ; Setze Offset
          call romcall
          pop  ax
          push      ax
          inc  al
          mov  ah,[secpertrak]
          mov  cx,ax
          mov  al,10h    ; setze Laufwerk
     
ifc_or:
          or   cl,al     ; fr HD (AT)-Format
          call romcall   ; mit IFC-Karte auf c't86
          pop  dx
          mov  cl,dh
          mov  ch,0
          mov  al,[secpertrak]
          mov  ah,0      ; Kopf gibt es nicht, nur relativen Sektor
          mul  cl        ; innerhalb einer Spur, daher mit Kopfnummer
          pop  cx        ; multiplizieren
          push cx
          mov  ch,0
          add  cx,ax
          mov  al,12h    ; setze Sektor
          call romcall
          pop  cx
          mov  cl,ch
          mov  ch,0
          mov  al,0eh    ; setze Spur
          call romcall
          pop  ax        ; lesen oder schreiben
          call romcall
          mov  ah,al
          or   al,al
          jz   noerr
          stc
          ret
noerr:    clc
     ret
     
; callf-Monitoraufruf

romcall:  push bx
          push di
          call monitor
          pop  di
          pop  bx
          ret
     
; ab hier transienter Code, wenn c't86

dskinit:  mov  es,dx
          mov  bx,cx          ; es:bx zeigt auf die Zeile im Config.sys
          push bx
          push es
          mov  ax,0f000h
          mov  es,ax
          mov  bx,0fffeh ; erst mal schauen ob es ein PC oder ein
          mov  al,es:[bx]; c't86 ist, denn beim c't knnen wir mit
                         ; callf-Monitor und ifc arbeiten
          cmp  al,06h    ; die letzte Version des c't86 Monitors
          ja   istibmpc  ; wird hoffentlich nur 6 sein
istct86:  mov  al,22h
          call romcall   ; ist eine ifc-Karte vorhanden ?
          test al,20h    ; wenn ja, dann auf jeden fall ber callf
          jnz  mitifckarte
          mov  ibmifcflg,1    ; sonst nur alte fdc-Karte
          jmp  short weiterinit
     
istibmpc:
          mov  ibmifcflg,0
          cmp  al,0fch        ; ist es ein IBM PC/AT ??
          jnz  weiterinit
          mov  atflg,1        ; AT !!!
          jmp  short weiterinit
     
mitifckarte:
          mov  ibmifcflg,2    ; IBMIFCFLG auf entsprechenden Wert setzen
weiterinit:
          pop  es
          pop  bx
          ausgabe   startmes  ; signon Message ausgeben
          call scan_for_para  ; Treibernamen bergehen
          mov  al,es:[bx]     ; sind parameter angegeben ?
          or   al,al
          jnz  node           ; wenn ja, dann die Werte analysieren
          jmp  default_init   ; sonst voreingestellte Werte benutzen
     
node:     mov  al,es:[bx]
          inc  bx             ; auf erstes Zeichen nach Treibernamen
          cmp  al,'4'         ; 40 oder 80 Track
          jz   track40
          cmp  al,'8'
          jz   track80
          jmp  errordata
     
track40:  mov  al,es:[bx]
          cmp  al,'0'         ; die Null von 40 oder 80 berprfen
          jz   ok11
          jmp  errordata
     
ok11:     mov  tr4080,0  ; Bei 40 Spuren braucht das Doublestepping
          mov  atflg,0        ; nicht abgeschaltet werden
          mov  dx,offset viertrack
          jmp  short driveermit; text ausgeben
     
track80:  mov  al,es:[bx]
          cmp  al,'0'
          jz   ok22
          jmp  errordata ; keine 0 dann Fehler
     
ok22:     mov  tr4080,1
          ausgabe achttrack
     
driveermit:
          inc  bx
          inc  bx
          mov  al,es:[bx]     ; physikalisches Laufwerk ermitteln
          cmp  al,'0'         ; mu zwischen 0 und 3 liegen
          jl   errordata
          cmp  al,'3'
          jg   errordata
          sub  al,'0'
store:    mov  drivesel,al
          cmp  al,1      ; nur bei 0 und 1 kann man das Double-Stepping
          jle  hdlauf    ; ausschalten, sonst nicht
          mov  atflg,0
hdlauf:
          add  al,'A'    ; fr die Textausgabe umwandeln
          mov  physic,al
          cmp  tr4080,1
          jnz  move_them ; bei 40 Spur-Formaten mssen wir DBPs
          inc  bx        ; bertragen
          inc  bx
          mov  al,es:[bx]; bei 80 Spuren erst im dritten Parameter
                         ; nachsehen, welcher zu bertragen ist
          and  al,0dfh   ; Uppercase wandeln
          cmp  al,'A'
          jz   atlauf    ; als normales HD-Laufwerk im c't86 benutzen
          cmp  al,'I'
          jz   ibmpsin   ; als IBMPC 720KByte-Format (PS/2)
          cmp  al,'S'
          jz   siemin    ; mit Siemens PCD-Format
          cmp  al,'T'
          jz   nixin     ; mit Nixdorf PWS-Format
          cmp  al,'O'
          jz   olliin    ; mit Olivetti M24-Format
          cmp  al,'N'
          jnz  ibmpsin1  ; und wenn's keiner war,
                         ; dann ist's IBM PS/2
nixin:    mov  dx,offset nixtext
          mov  si,offset nixdorf
          jmp  short move_bpb ; Text ausgeben DBP bertragen
     
errordata:
          ausgabe fehlertxt
default_init:
          mov  tr4080,0  ; bei Fehler oder ohne Parameter ist es 40
          mov  drivesel,1; Spuren auf Laufwerk B:
          mov  physic,'B'
          mov  dx,offset deftxt
          jmp  short move_bpb
     
atlauf:
          mov  dx,offset at_text
          mov  si,offset hd
          jmp  short move_bpb
     
siemin:
          mov  dx,offset siemtext
          mov  si,offset siemens
          jmp  short move_bpb
     
olliin:   mov  dx,offset ollitext
          mov  si,offset olivet
          jmp  short move_bpb ; Text ausgeben und DPB bertragen
          
ibmpsin1:
          dec  bx
          dec  bx
ibmpsin:
          mov  dx,offset ibmpstext
move_them:
          mov  si,offset ibmps
move_bpb:
          mov  ah,9
          int  21h
          push es
          push ds
          pop  es
          mov  di,offset ibmps
          cmp  si,offset hd   ; bei den 80 Spur-Formaten mu nur ein DBP
          jnz  normal         ; bertragen werden, bei den HD-Formaten
          mov  cx,lengt * 3   ; sind es aber drei
          jmp  short move
     
normal:
          mov  word ptr ds:ifc_or,9090h ; nop nop
          cmp  tr4080,0
          mov  cx,lengt
          jnz  move                ; falls 80 track, 
                                   ; sonst berschreibe die
          mov  si,offset lsdriv1   ; ersten zwei 80 track bpb 
                                   ; mit 40 track bpb
          add  cx,cx               ; 2 BPBs zu kopieren
move:     cld
          rep  movsb
          pop  es
          cmp  tr4080,0  ; bei 40 Spur Format gibt es keien vierten
          jz   no_atari  ; Parameter fr Atari
          call scan_for_para
          mov  al,es:[bx]     ; Atari-Parameter '1' oder '2' (-seitig)
          cmp  al,'1'         ; nur 1 wird ausgewertet, sonst DS
          mov  atariflg,al
          mov  dx,offset atarissmes
          mov  si,offset atariss
          jz   atari1
          mov  dx,offset ataridsmes
          mov  si,offset atari
atari1:   mov  di,offset atari
          push es
          push ds
          pop  es
          mov  cx,lengt  ; Atari-Format bertragen und
          rep  movsb
          pop  es
          mov  ah,9      ; Text ausgeben
          int  21h
     
no_atari:
          mov  ah,30h
          int  21h       ; get Version
          lds  bx,[ptrsav]
          cmp  al,3      ; wird erst ab Version 3.x untersttzt
          push ds
          jb   below_3x
          mov  dl,[bx.drive]  ; sonst kann das logische Laufwerk nicht
          add  dl,'A'         ; ermittelt werden
          mov  byte ptr cs:laufwerk,dl
          push      cs
          pop  ds
          ausgabe   logical
below_3x:
          mov  ax,offset dskinit
          cmp  ibmifcflg,0    ; bei PC ode AT ab Dskinit transienter Code
          pop  ds
          jnz  here_end  ; im c't86 erst ab uebercallf
          mov  ax,offset uebercallf
here_end:
          mov  word ptr [bx+0eh],ax
          mov  word ptr [bx+10h],cs     ; gib 'end of driver' an's DOS
          push      cs
          pop  ds
          mov  al,drvmax ; Anzahl Untereinheiten des Treibers
          xor  ah,ah
          mov  si,offset inittab1  ; Standard-DBP einstellen
          jmp  get_bp5
     
scan_for_para:
          push ds
          push es
          pop  ds
          mov  si,bx
s1:       lodsb
          cmp  al,' '         ; berspringe voraneilende Leerzeichen
          jz   s1
s2:       lodsb
          cmp  al,0
          jz   s3
          cmp  al,' '         ; berspringe den Treibernamen
          jnz  s2
s3:       lodsb
          cmp  al,' '         ; berspringe nachfolgende Leerzeichen
          jz   s3
          dec  si
          mov  bx,si
          pop  ds
          ret
     
; HD-Laufwerk
hd        dbp  <512,1,1,2,224,2400,0f9h,7,15,2>
          dbp  <512,2,1,2,224,2720,0fdh,7,17,2>
          dbp  <1024,2,1,2,224,1440,0feh,7,9,2>
     
; IBMPC40Track, 9 Sektoern, doppelseitig
lsdriv1   dbp  <512,2,1,2,112,720,0fdh,2,9,2>

; IBMPC 40 Track 9 Sektoren einseitg
lsdriv2   dbp  <512,1,1,2,64,360,0fch,2,9,1>

; Olivetti M24
olivet    dbp  <512,2,1,2,144,1440,0f9h,3,9,2>

; Siemens PC-D
siemens   dbp  <512,4,1,2,144,1440,0f9h,2,9,2>

; Nixdorf PWS oder Softec
nixdorf   dbp  <512,2,1,2,144,1600,0f9h,3,10,2>

; Atari ST doppelseitig (80 Spur 3,5 Zoll)
atarids   dbp  <512,2,1,2,112,1440,0f7h,5,9,2>

; Atari ST einseitig (80 Spur 3,5 Zoll)
atariss   dbp  <512,2,1,2,112,720,0f7h,5,9,1>

atariflg  db   0
tr4080    db   0    ; 40 oder 80 Track

deftxt    db   'Default-Werte: ',0dh,0ah
          db   '40-Track-Drive B:',0dh,0ah,'$'
fehlertxt db   'Fehler in Parameterfeld',0dh,0ah,'$'

viertrack db   '40-Track-Drive eingestellt',0dh,0ah,'$'
achttrack db   '80-Track-Drive eingestellt',0dh,0ah
          db   'Bei Media-Byte F9h: ','$'
          
ollitext  db   'Olivetti M24',0dh,0ah,'$'
siemtext  db   'Siemens PC-D',0dh,0ah,'$'
nixtext        db   'Nixdorf/Softec',0dh,0ah,'$'
ibmpstext db   'IBM 80-Spur',0dh,0ah,'$'
at_text        db   'AT-Laufwerk',0dh,0ah,'$'

startmes  db   0dh,0ah,"Universeller c't-Disk-Treiber"
          db   'V 3.6 (16.08.87)',0dh,0ah,'$'
          
logical   db   'auf physik. Laufwerk '
physic    db   ' '
          db   ': als Laufwerk '
laufwerk  db   'd'
          db   ': installiert',0ah,0dh,'$'
          
ataridsmes     db   'Bei Media-Byte F7h: Atari ST doppelseitig',0dh,0ah,'$'
atarissmes     db   'Bei Media-Byte F7h: Atari ST einseitig',0dh,0ah,'$'

localer   endp
code ends

     if1
     %out end of pass 1
     endif
     
     if2
     %out end of pass 2
     endif
     
     end
PROLOAD
TGM_98 : PROLOAD.ASM, PROLOAD.EXE
Scharl, Schchle / TGM-5AN

1. Aufgabe

Proload dient dazu, andere speicherresistente Programme, wie Treiber fr Netzwerk, Drucker, Maus, usw. oder andere Utilities an einer beliebigen Speicherposition zu installieren. Die zu installierenden Programme und die Speicherposition sind frei whlbar. 

2. Funktion

Proload sttzt sich auf die Verwaltung des Speicherplatzes von MSDOS und ntzt deren Organisation. Um die Arbeitsweise dieses Programms zu verstehen, mchte ich eine kurze Einfhrung in die Speicherorganisation von MSDOS geben. 

2.1 Speicherverwaltung von MSDOS

Damit das Betriebssystem feststellen kann, an welcher Position ein Programm im Speicher installiert werden kann, wird der Speicher in mehrere einzelne Blcke unterteilt. Diese Blcke nennt man Memory Control Blcke (MCB). Am Beginn jedes MCBs befindet sich Information ber die Position des nchsten Blocks und ber die Lnge des zur Verfgung gehaltenen Blockbereichs. Die einzelnen MCBs stehen hintereinander im Speicher und kennzeichnen die Platzreservierung fr bereits installierte Programme. Um das Ende der Blockkette zu kennzeichnen, befindet sich an erster Position des letzten Blocks ein "Z". Die dazwischenliegenden Blcke werden mit "M" bezeichnet.

























Die Organisation dieser Blcke kann aus Bild 5 entnommen werden. 

Wird nun ein neues Programm geladen und ausgefhrt, so sucht das Betriebssystem zuerst die Kette der einzelnen Blcke ab. 
Wird der Block mit dem "Z" gefunden, so kann aus dem Eintrag der Lnge ( Offset 3 ) die nchste freie Speicheradresse ermittelt werden. An dieser Position wird das Programm von DOS installiert und ausgefhrt. 

2.2 Arbeitsweise des Programms Proload

Proload ntzt diese Organisation bzw. die Blockaufteilung aus. Nach der Abfrage von Programmnamen, Programmadresse und Programmlnge wird als erstes die Entfernung der eingegebenen Programmadresse und der momentanen Programmadresse ( von Proload ) ermittelt. 

Danach wird von der momentanen Adresse bis zur Adresse des zu installierenden Programmes ein Block markiert. Der Block enthlt an erster Position ein "Z" und ist somit fr DOS der letzte in der Kette befindliche Block. Weiters wird die Blocklnge und weitere fr DOS notwendige Daten in den Blockhead geschrieben. Danach erfolgt ein Interrupt 21 ( 4B ), und das zu installierende Programm wird ber DOS gestartet. 

Das Betriebssystem findet nun an letzter Stelle der Kette den soeben selbst generierten Block und ladet das Programm an das Ende dieses Blocks, welches nun der eingegebenen Speicheradresse entspricht. Nach dem Verlassen des installierten Programms wird der Block wieder gelscht und der Block davor durch ein "Z" am Beginn als Schluglied gekennzeichnet. 
Proload wird anschlieend beendet, ohne da das speicherresistent installierte Programm zerstrt wird.

Die genaue Arbeitsweise kann aus dem beiliegenden Listing entnommen werden.

TITLE    ProLoad.COM  11-25-88       [11-26-88]

.RADIX   16
;
;INITIAL VALUES :  CS:IP     0000:0100
;                  SS:SP     0000:FFFF
Start    SEGMENT
         ASSUME    DS:Start,SS:Start,CS:Start,ES:Start

         ORG       100H

Seg0     EQU       $-100h
ParBlock EQU       $+240h
RegSave  EQU       $+280h
ProLen   EQU       $+1EFFh
ProAdr   EQU       $-9100h

Begin:   jmp       NamInp

ErrMes:  DB        0a,'Falscher Pfad oder Dateiname !!$'
Header1: DB        '***************************************'
         DB        '***   Programm  Loading  Software   ***'
         DB        '***************************************'
         DB        0a
         DB        'Dieses  Programm installiert Ihnen  ein'
         DB        'Speicher Resistentes  Programm an einer'
         DB        'von  Ihnen gewnschten  Speicheradresse'
         DB        0a
         DB        'Programmname    : $'
Header2: DB        0a,'Speicheradresse : $'
Header3: DB        0a,'Programmlnge   : $'
MemLeng: DB        05,00,00,00,00,00,00
MemAdr:  DB        05,00,00,00,00,00,00
ProNam:  DB        20
         DB        1f dup (?)

;********************************************************************
;*       Ausgabe der Meldetexte und Abfrage des Programmnamens,     *
;*       der Programmlnge und der Speicherposition                 *
;********************************************************************
NamInp:  mov       ah,09                    ;Ausgabe der Startmeldung
         mov       dx,offset Header1        ;und Aufforderung
         int       21                       ;zur
         mov       ax,offset ProNam
         mov       dx,ax                    ;Eingabe der Progammnamens
         mov       ah,0a
         int       21
         mov       bx,offset ProNam+1       ;Rcksetzen des eingegebenen
         mov       al,[bx]                  ;ENTER ( D0h )
         mov       ah,00                    ;auf 00h
         mov       bx,offset ProNam+2
         adc       bx,ax
         mov       ax,0000
         mov       [bx],ax
AdrInp:  mov       ah,09                    ;Aufforderung
         mov       dx,offset Header2
         int       21                       ;zur
         mov       ax,offset MemAdr
         mov       dx,ax                    ;Eingabe der Adresse
         mov       ah,0a
         int       21
LengInp: mov       ah,09                    ;Aufforderung
         mov       dx,offset Header3
         int       21                       ;zur
         mov       ax,offset MemLeng
         mov       dx,ax                    ;Eingabe der Progr.
         mov       ah,0a                    ;Lnge
         int       21
         jmp       Main


;********************************************************************
;*       Verschieben der Memory Control Blcke und installieren     *
;*       des Programms                                              *
;********************************************************************

Main:    mov       bx,offset MemLeng+1      ;Text Programmlnge
         call      ASCtoWrd                 ;in Word umwandeln
         mov       dx,bx                    ;Programmlnge nach dx
         mov       bx,offset MemAdr+1       ;Text Adresse
         call      ASCtoWrd                 ;in Word umwandeln
         MOV       AX,CS                    ;Code Segment um 1
         DEC       AX                       ;verkleinern un ins
         MOV       DS,AX                    ;Datensegment bertrag.
         MOV       BYTE PTR DS:Seg0,4Dh     ;Markieren eines MCB
         PUSH      DS:Seg0+3                ;ENDE durch "M"
         mov       cx,bx                    ;Errechnen der Lnge bis
         SUB       CX,AX                    ;gewnschter Progr. Beginn
         SUB       CX,1                     ;und in MCB Pos 3 schreiben
         MOV       DS:Seg0+3,CX
         mov       ax,bx
         MOV       DS,AX
         MOV       BYTE PTR DS:Seg0,5A      ;Markieren des bisherigen
         MOV       WORD PTR DS:Seg0+1,0     ;MCB ENDE als ANFANG durch
         MOV       WORD PTR DS:Seg0+3,dx    ;austauschen des "M" durch
         MOV       AX,CS                    ;"Z"
         MOV       DS,AX                    ;zurcksetzen des Datensegm.
         MOV       RegSave+2,SS             ;Sichern der Register
         MOV       RegSave+4,DX
         MOV       RegSave+6,DS
         MOV       RegSave+8,BX
         MOV       RegSave+0Ah,ES
         MOV       RegSave,SP
         MOV       AX,CS
         MOV       WORD PTR ParBlock,0     ;festhalten des alten
         MOV       WORD PTR ParBlock+2,80  ;Parameter Block
         MOV       ParBlock+4,AX
         MOV       WORD PTR ParBlock+6,5C
         MOV       ParBlock+8,AX
         MOV       WORD PTR ParBlock+0Ah,6C
         MOV       ParBlock+0Ch,AX
         MOV       AX,CS
         MOV       DS,AX
         MOV       ES,AX
         MOV       DX,OFFSET ProNam+2       ;Laden und ausfhren
         MOV       BX,OFFSET ParBlock       ;des Programms
         MOV       AX,4B00
         INT       21
         jc        Error                    ;Sprung bei Fehler
Close:   MOV       SP,RegSave
         MOV       SS,RegSave+2             ;rckhohlen der Register
         MOV       DX,RegSave+4
         MOV       DS,RegSave+6
         MOV       BX,RegSave+8
         MOV       ES,RegSave+0Ah
         MOV       AX,CS
         DEC       AX
         MOV       DS,AX
         MOV       BYTE PTR DS:Seg0,5A      ;Rcksetzen des MCB
         POP       DS:Seg0+3
         INT       20                       ;Programmbergabe an DOS
Error:   mov       ah,09                    ;Ausgeben des Error Textes
         mov       dx,offset ErrMes
         int       21
         jmp       Close

;********************************************************************
;*       Wandelt den Hexcode von ASCII Zeichen in die jeweiligen    *
;*       um und macht somit aus vier folgenden Bytes ein Word       *
;********************************************************************
;*       Eing:  BX =  Adresse des Hexcodes - 1                      *
;*       Ausg:  BX =  Word mit ASCII Zeichen                        *
;********************************************************************

ASCtoWrd PROC NEAR
         push      dx                  ;Register sichern
         push      cx
         mov       cx,04               ;Schleifenzhler
Loop1:   adc       bx,1
         mov       ax,[bx]
         cmp       al,01000000b        ;Testen ob Ziffer oder
         js        Number              ;Buchstabe
Alpha:   adc       ax,09h              ;Hex Code L-Byte = ASCII
         and       ax,00001111b        ;lschen des H-Byte
         push      ax                  ;Ablegen auf Stack
         loop      Loop1
         jmp       SPtoWord
Number:  sub       ax,30h              ;Hex Code L-Byte = ASCII
         and       ax,00001111b        ;Lschen des  H-Byte
         push      ax                  ;Ablegen auf Stack
         loop      Loop1
SPtoWord:mov       dx,03               ;Schleifenzhler
         mov       cl,0                ;Positionsregister
         pop       bx                  ;erstes Byte vom Stack holen
Loop2:   adc       cl,4
         pop       si                  ;nchstes Byte vom Stack
         shl       si,cl               ;um 4 Bit nach links schieben
         or        bx,si               ;mit Rest verknpfen
         sub       dx,1                ;Schleifenzhler um 1 kleiner
         jnz       Loop2
         pop       cx                  ;zurckholen der Registen
         pop       dx
         ret
ASCtoWrd ENDP

Start    ENDS

END      Begin


BIOS-EPROM im AT verndern

TGM_88 : SPLIT.*, 386_1.*, XLIT.*, LF.TBL

Franz FIALA / TGM

Dieser Beitrag richtet sich an alle, die sich an hardwarenahe Arbeiten am BIOS heranwagen wollen oder mssen. Die dazu notwendigen, eher 'handwerklichen' Fertigkeiten sind hier beschrieben. 

Als Beispiel dient eine sehr hufige Ttigkeit beim AT-BIOS: das Erweitern der Festplattentabelle. Wenn Sie ein solches Vorhaben realisieren wollen, bentigen Sie ein EPROM-Programmiergert, sowie ein EPROM-Lschgert (oder eine Hhensonne, die man zwecks Schonung der Haut ohnehin nicht zum Brunen verwenden sollte) und einige leere EPROMS (27128 oder 27256, je nach AT-Type). 

Sie bentigen das Programm DEBUG des Betriebssystems und das fr diesen Zweck geschriebene Programm SPLIT. Da nur sehr einfache Vorhaben auf Anhieb funktionieren, wurde auch die Mglichkeit vorbereitet, alle diese Arbeiten auch automatisch ausfhren zu knnen. 

Das AT-BIOS

Das AT-BIOS schreibt wichtige Festplattenparameter (Kopfzahl, Spurenzahl u.a.) in eine Tabelle im BIOS (genaueres siehe PC-NEWS 1/87 S.53, Schlatte, AT-BIOS konfigurieren). Je nach BIOS gibt es etwa 30-50 eingetragene Festplattentypen. Mit ziemlicher Sicherheit ist Ihre neu angeschaffte Festplatte nicht dabei. Dafr bieten sich zwei Lsungen an: Entweder man verwendet eines der handelsblichen (und bei vielen Festplatten gleich mitgelieferten) Festplatten-Utilities, wie SPEEDSTORE o.. oder die hier beschriebene etwas 'sportlichere' Methode der Vernderung der entsprechenden BIOS-Tabelle selbst. Die erwhnten Utilities haben den Nachteil, da bei einer Aufteilung der Festplatte in mehrere Partitionen man einen besonderen Treiber in der Datei CONFIG.SYS geladen haben mu, der ca. 10k Speicherplatz beansprucht. 

Das Verndern der BIOS-Inhalte im XT ist einfach, da die Verarbeitungseinheit (Wortbreite) des XT und die Speicherbreite der EPROMs mit 8 bit gleich ist. Der AT, mit seinem 16 bit breiten Adressbus hat aber die Inhalte aller geraden und ungeraden Adressen in zwei verschiedenen EPROMs abgelegt. Daher mu bei der Anfertigung der beiden EPROMs eine Trennung des Codes in gerade und ungerade Adressen vorgenommen werden. 

Speicheraufteilung auf gerade (even) und ungerade (odd) Adressen

Bei den PCs erfolgt die Zhlung der Adressen byteweise, auch dann, wenn, wie beim AT, in 16-bit und beim 386-AT in 32-bit-Wortbreite auf den Speicher zugegriffen wird. 


BIOS-EPROM         Memory             BIOS-EPROM
lower Byte         <  8 bit  >        higher Byte
even                                  odd
                   ͸
                       F    Ŀ
                   Ĵ       
            Ĵ    E           
                  ͵       
                      D    Ŀ
                  Ĵ      
            Ĵ    C          
                 ͵      
                     B    Ŀ
                 Ĵ     
            Ĵ    A         
                ͵     
                    9    Ŀ
                Ĵ    
            Ĵ    8        
Ŀ    ͵    Ŀ
    E    ٳ       7    Ŀ    F    
Ĵ     Ĵ    Ĵ
    C    ٳĴ    6       Ĵ    D    
Ĵ     ͵     Ĵ
    A    ٳ      5    ĿĴ    B    
Ĵ      Ĵ     Ĵ
    8    ٳĴ    4      Ĵ    9    
Ĵ      ͵      Ĵ
    6    ٳ     3    ĿĴ    7    
Ĵ       Ĵ      Ĵ
    4    ڴ    2     Ĵ    5    
Ĵ       ͵       Ĵ
    2    ٳ    1    ÿĴ    3    
Ĵ        Ĵ       Ĵ
    0    Ĵ    0    Ĵ    1    
        ;        

Dasselbe noch einmal in Zahlen:

            - - - - A   D   R   E   S   S   E - - - -
            -----------------------------------------
            real   segment:   relativ  EPROM lo  EPROM hi
                   offset     zu F8000 even      odd
-----------------------------------------------------
BIOS-Anfang F8000  F000:8000  0000     0000      ----
            F8001  F000:8001  0001     ----      0000
            F8002  F000:8002  0002     0001      ----
            F8003  F000:8003  0003     ----      0001
.....
.....
BIOS-Ende   FFFFE  F000:FFFE  7FFE     3FFF      ----
            FFFFF  F000:FFFF  7FFF     ----      3FFF

Verallgemeinert man dieses Prinzip fr den AT-386, dann sollte man wegen des 32-Bit-breiten Datenbusses 4 EPROMs vorfinden. Hier hat man wahrscheinlich Platinenflche sparen mssen, denn in diesem Adressbereich greift auch der 386er 16-bit-weise zu, es bleibt also bei dieser Aufteilung. (Neuerdings gibt es auch 386er, die das BIOS in 4 EPROMS aufteilen.) 

Speichern des BIOS-Code in eine Datei

Zunchst ist es erforderlich, den BIOS-Code in einer Datei festzuhalten. Dazu bentigt man das Programm DEBUG des Betriebssystems. 

C:\>DEBUG                Aufruf des DEBUGgers
-mf000:8000 ffff 100     Verschieben des BIOS-Bereichs
                         auf die Aresse 100h
-n386_.08                der Name '386_' wurde gewhlt, da das BIOS
                         eines AT-386 disassembliert werden sollte
                         das Suffix 08 deutet auf die 8-bit-Bus-
                         Version hin
-rcx                     die Lnge des zu speichernden
                         Bereichs wird in den Registern
                         CX (offset) und BX (segment)
                         festgelegt
cx 0000
:8000
-rbx
bx 0000                  dient nur zur Kontrolle, da BX=0
:0
-w                       schreibt die Datei 386_.08 
                         auf die Diskette
Schreiben von 8000 Byte
-q
C:\>

Modifikation des BIOS (Patch)

Jetzt ist es erforderlich die gewnschte nderung anzubringen. Dazu fertigt man zunchst eine Kopie des Original-BIOS an (386_1.08) und ldt diese in den DEBUGger. Die hier folgenden Schritte sind nur beispielhaft angegeben. 

Zunchst wird die Kopie des BIOS im DEBUGger modifiziert. Danach mu diese Datei wieder auf zwei Teile aufgespaltet werden. Dazu wurde das Hilfsprogramm SPLIT geschrieben. (Beschreibung siehe spter)

C:\>DEBUG 386_1.08       Laden des BIOS
-exxxx                   nderung der gewnschten Speicherzellen
  ...                    dabei mu beachtet werden, da bei allen
  ...                    Adressen 100h addiert werden mu, 
  ...                    da der DEBUGger die Datei auf den Offset 
                         100h ldt
-e80ff                   jedenfalls sollte aber das hchste Byte
xx:00                    im BIOS auf Null gesetzt werden,
                         damit die sptere Prfsummenbildung
                         einfacher wird
-w                       mit nderungen zurckspeichern
Schreiben von 8000 Byte
-q
C:\>SPLIT 2 386_1        Das Programm SPLIT teilt 386_1.08 in
                         zwei Dateien 386_1.160 und 386_1.161 auf
                         und liefert etwa folgende Meldung:

    BINRDATEIEN fr 8/16-Bit Bus SPLITEN/KOMBINIEREN
    =================================================
        386_.08 =     386_.160 +        386_.161      : Dateinamen
    32768(8000) =16384(  4000) + 16384(    4000)      : Byteanzahl
     3840( f32) = 3970(   fb4) + 4294967166(ffffff7e) : Prfsummen

Die Zahlen sind dezimal (hexadezimal) angegeben.

Das Programm nimmt an, da die aufzuspaltende Datei die Extension '08' hat und spaltet die Datei in zwei halb so groe Dateien mit den Endungen '160' und '161' auf. Die Endungen 08 und 16 sind die Busbreite. Zustzlich zu der Anzahl der verarbeiteten Bytes sind auch noch die Prfsummen angegeben. Der Rechner verweigert nach der Modifikation bei falscher Prfsumme den Dienst. Die Prfsumme wird im letzten Byte des BIOS (f000:ffff) gespeichert. 

Man mu nochmals in den DEBUGger einsteigen und an der hchsten Stelle die Zahl (hier) 32h eintragen (32h ist die niederwertige Stelle der Prfsumme des BIOS im o.a. Beispiel). 

Es stellte sich bei den Versuchen bald heraus, da es bei der ersten nderung nicht blieb, es folgte eine zweite und... es war vorteilhafter den ganzen Vorgang zu automatisieren. 

Automatische nderung des BIOS
------------------------------

Eine nicht sehr hufig bentzte, aber manchmal sehr praktische, Mglichkeit automatischer Eingaben aus einer Datei, statt von der Konsole ist der Operator '<' (=Umlenkung der Eingabe von Datei oder Gert) auf Betriebssystemebene. Man kann so den gesamten Dialog mit dem DEBUGger in einer Datei in aller Ruhe fehlerfrei vorformulieren und kleine nderungen in dieser Datei editieren. 

Ein Beispiel fr eine solche Debugger-Sitzung finden Sie in der Datei 386_1.TXT: 

d100
d6500
e65e0
00 22 05 07 00 00 ff ff 00 00 00 00 00 22 05 11
e6670
00 00 04 06 00 00 ff ff 00 00 00 00 00 00 04 11
e6780
00 32 01 02 00 00 ff ff 00 00 00 00 00 31 01 11
e6790
00 00 04 05 00 00 ff ff 00 00 00 00 00 00 04 11
e67a0
00
e70cb
12
e80ff
00
w
q

Die beiden ersten Zeilen zeigen nur ein Detail aus dem Speicher, sozusagen als Quittung, da die richtige Datei geladen wurde. Danach beginnt der eigentliche Patch: es werden drei Bereichen mit je 16 Bytes (die Festplatten-Parameter) beginnend bei 6670, 6780 und 6790 gendert. Der Patch auf 67a0 dient als Abschluzeichen, der bei 70cb war ein Versuch das BIOS zum Lesen von Disketten mit 18 Sektoren zu bewegen (was allerdings nicht gelang). Zum Abschlu wird 0 auf die hchste Speicherzelle geschrieben. 

Jetzt sollte man eigentlich nur mehr das Umlenkkommando anwenden mssen?

DEBUG 386_1 < 386_1.TXT

Leider nein! Diese Umlenkung vertrgt die in der Textdatei enthaltenen Zeichenkombinationen Wagenrcklauf-Zeilenvorschub CR-LF nicht. Es mu daher zuerst das Zeichen Zeilenvorschub LF=0ah aus der Datei entfernt werden. Mit dem Editor geht das gar nicht; dazu braucht man ein Utility. Ich verwendete das sehr universelle Public-Domain-Programm XLIT. XLIT substituiert jedes gewnschte Zeichen durch ein anderes oder auch durch nichts. Dazu bentzt es eine Tafel, in der diese Entsprechungen eingetragen sind (Nheres siehe in der Dokumentation XLIT.DOC). In diesem Fall enthlt diese Tabelle nur eine Eintragung. Die Tabelle erhlt Namen LF.TBL (da sie das Zeichen LF eliminiert) und enthlt nur eine Zeile:

h0a

Das zugehrige Kommando, welches die Substitution vornimmt:

XLIT < 386_1.TXT > 386_1.PAT LF.TBL

Die neue Datei 386_1.PAT enthlt jetzt nur mehr Zeilen, die mit CR statt mit CR-LF abgeschlossen sind. 

Nach diesen kleinen Hrden haben wir es geschafft: Wir haben einen einfachen Mechanismus, mit dem das ndern der ERPOM-Inhalte problemlos mglich ist. Die zugehrige BAT.Datei heit 386_1.BAT und enthlt:

    xlit < 386_1.txt > 386_1.pat lf.tbl
    copy 386_.08 386_1.08
    debug 386_1.08 < 386_1.pat
    split -2 386_1

Das Patchen des BIOS erfolgt durch Editieren der Datei 386_1.txt. und Aufruf der obigen Prozedur. Die Prfsumme ist im allgemeinen ungleich Null. Die Differenz wird ausgerechnet und mittels Editor in der Datei 386_1.txt eingetragen (Bis jetzt stand an dieser Stelle der Wert Null). Und danach die BAT-Datei nocheinmal aufgerufen. Die Prfsumme ist jetzt 0, wenn richtig gerechnet wurde. 

Das Programm SPLIT (Compiliert mit ZORTECH-C-Compiler Vers. 3.0)


/* split.c */

#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>

#define BUF_S 2048    /* Die Datei wird in 4k-Portionen bearbeitet */
#define BUF_0 BUF_S/2 

FILE *fs,*f0,*f1;
char BufferS [BUF_S];
char Buffer0 [BUF_0];
char Buffer1 [BUF_0];


char DateiS [50]; /* Dateiname ohne Pfadangabe */
char Datei0 [50]; /* Dateiname ohne Pfadangabe */
char Datei1 [50]; /* Dateiname ohne Pfadangabe */



void Namenbildung (char *Name)
{
  int i;
  
  if (Name[0]==0)
  {
    printf ("Kein Dateiname angegeben\n");
    exit (0);
  }
  if (strlen(Name)>8)
  {
    printf ("Dateiname zu lang\n");
    exit (0);
  }
  for (i=0;i<strlen(Name);i++)
    if (!( isalnum (Name[i]) || (Name[i]=='_') || (Name[i]=='-')))
    {
      printf ("%c ist nicht erlaubt\n",Name[i]);
      exit (0);
    }
  strcpy (DateiS,Name);
  strcpy (Datei0,Name);
  strcpy (Datei1,Name);
  strcat (DateiS,".08");
  strcat (Datei0,".160");
  strcat (Datei1,".161");
}



void spalt ()
{
  unsigned gelesen,gelesen0,gelesen1,i;
  unsigned long anzahl,anzahl0,anzahl1;
  unsigned long summe,summe0,summe1;
  
  fs=fopen (DateiS,"rb");
  if (fs==0) 
  {
    printf ("Datei %s nicht gefunden \n",DateiS);
    exit (0);
  }

  f0=fopen (Datei0,"wb");
  if (f0==0) 
  {
    printf ("Datei %s kann nicht erffnet werden \n",Datei0);
    exit (0);
  }
  
  f1=fopen (Datei1,"wb");
  if (f1==0) 
  {
    printf ("Datei %s kann nicht erffnet werden \n",Datei1);
    exit (0);
  }

  anzahl=0;anzahl0=0;anzahl1=0;
  summe=0;summe0=0;summe1=0;
  while ((gelesen=(unsigned)fread (BufferS,1,BUF_S,fs))!=0) /* Jeweils 1 k wird aus der Datei gelesen */
  {
    i=0;
    while (i<gelesen)
    {
      Buffer0[i/2]=BufferS[i];
      summe0=summe0+(unsigned long)BufferS[i];
      summe=summe+(unsigned long)BufferS[i];
      i++;
      Buffer1[i/2]=BufferS[i];
      summe1=summe1+(unsigned long)BufferS[i];
      summe=summe+(unsigned long)BufferS[i];
      i++;
    }
    gelesen0=(gelesen/2)+(((gelesen%2)==0)?0:1); 
    gelesen1=(gelesen/2); 
    anzahl=anzahl+(unsigned long)gelesen;
    anzahl0=anzahl0+(unsigned long)gelesen0;
    anzahl1=anzahl1+(unsigned long)gelesen1;
    fwrite (Buffer0,1,gelesen0,f0); 
    fwrite (Buffer1,1,gelesen1,f1); 
  }
  printf ("%17s = %17s + %17s : Dateinamen \n",DateiS,Datei0,Datei1);
  printf ("%7lu(%8lx) = %7lu(%8lx) + %7lu(%8lx) : Byteanzahl dez(hex)\n",
          anzahl,anzahl,anzahl0,anzahl0,anzahl1,anzahl1);
  printf ("%7lu(%8lx) = %7lu(%8lx) + %7lu(%8lx) : Prfsummen dez(hex)\n",
          summe,summe,summe0,summe0,summe1,summe1);

  if (fs) fclose (fs);
  if (f0) fclose (f0);
  if (f1) fclose (f1);
}




void kombi ()
{
  unsigned gelesen0,gelesen1,i;
  unsigned long anzahl,anzahl0,anzahl1;
  unsigned long summe,summe0,summe1;
  
  f0=fopen (Datei0,"rb");
  if (f0==0) 
  {
    printf ("Datei %s nicht gefunden \n",Datei0);
    exit (0);
  }

  f1=fopen (Datei1,"rb");
  if (f1==0) 
  {
    printf ("Datei %s nicht gefunden \n",Datei1);
    exit (0);
  }

  fs=fopen (DateiS,"wb");
  if (fs==0) 
  {
    printf ("Datei %s kann nicht erffnet werden \n",Datei0);
    exit (0);
  }
  
  
  anzahl=0;anzahl0=0;anzahl1=0;
  summe=0;summe0=0;summe1=0;
  while ((gelesen0=(unsigned)fread (Buffer0,1,BUF_0,f0))!=0)
  {
    gelesen1=fread (Buffer1,1,BUF_0,f1);
    
    if ( abs ((gelesen0-gelesen1)<2) )
    {
      i=0;
      while (i<gelesen0)
      {
        BufferS[2*i]=Buffer0[i];
        summe=summe+(unsigned long)Buffer0[i];
        summe0=summe0+(unsigned long)Buffer0[i];
        if (i<gelesen1) 
        {
          BufferS[2*i+1]=Buffer1[i];
          summe=summe+(unsigned long)Buffer1[i];
          summe1=summe1+(unsigned long)Buffer1[i];
        }
        i++;
      }
      fwrite (BufferS,1,gelesen0+gelesen1,fs); 
      anzahl=anzahl+(unsigned long)gelesen0+(unsigned long)gelesen1;
      anzahl0=anzahl0+(unsigned long)gelesen0;
      anzahl1=anzahl1+(unsigned long)gelesen1;
    }
    else
    {
      printf ("Dateien %s und %s sind verschieden lang!\n",Datei0,Datei1);
      exit (0);
    }
  }
  printf ("%15s + %15s = %15s : Dateinamen\n",Datei0,Datei1,DateiS);
  printf ("%7lu(%6lx) + %7lu(%6lx) = %7lu(%6lx) : Byteanzahl dez(hex)\n",
          anzahl0,anzahl0,anzahl1,anzahl1,anzahl,anzahl);
  printf ("%7lu(%6lx) + %7lu(%6lx) = %7lu(%6lx) : Prfsummen dez(hex)\n",
          summe0,summe0,summe1,summe1,summe,summe);

  if (fs) fclose (fs);
  if (f0) fclose (f0);
  if (f1) fclose (f1);
}

void Hilfe ()
{
  printf ("\nAufspaltung einer Datei 'name.08' in zwei Dateien, \n");
  printf ("mit den geraden Adressen 'name.160' \n");
  printf ("und ungeraden Adressen 'name.161' \n");
  printf ("'ERPOM -2 name'  : name.08 -> name.160 + name.161\n");
  printf ("\nVereinigung zweier Dateien \n");
  printf ("'name.160' mit den geraden Adressen und \n");
  printf ("'name.161' mit den ungeraden Adressen zu \n");
  printf ("einer Datei 'name.08' \n");
  printf ("'ERPOM -1 name'  : name.160 + name.161 -> name.08\n");
}


void main (int argc,char *argv[])
{
  printf ("\nBINRDATEIEN fr 8/16-Bit Bus SPLITEN/KOMBINIEREN\n");
  printf ("=================================================\n");
  
  switch (argc)
  {
    case 1:
      printf ("Zuwenig Argumente\n");
      goto Fehler;
    case 2:
      if ( (argv[1][0]=='-') && (toupper (argv[1][1])=='H') )
      {
        Hilfe ();
        break;
      }
      else
      {
        printf ("Falsche Option %s, zuwenig Argumente\n");
        goto Fehler;
      }
    case 3:
      if (argv[1][0]=='-') /* Option angegeben */
      switch (toupper (argv[1][1]))
      {
        case 'H': Hilfe ();
                  break;
        case '1': Namenbildung (argv[2]);
                  kombi ();
                  break;
        case '2': Namenbildung (argv[2]);
                  spalt ();
                  break;
        default:  printf ("Falsche Option \n");
                  goto Fehler;
      }
      break;
    default:
      printf ("Zuviele Argumente\n");
    Fehler:
      printf ("EPROM -{h12} name     -h..Hilfe, -1 kombi, -2 spalt\n");
      break;;
  }
}

Ein drittes Laufwerk an der Multi-I/O-Platine.

Mag.Peter Schneeweis / HTBLA f. Mode u. Bekleidung

Ich habe einen XT und war krzlich vor die Aufgabe gestellt,
Daten von einem 3 1/2 Zoll Laufwerk (720 kb) zu bernehmen.
Nachdem ich mir die Multi-I/O-Platine etwas nher angesehen
hatte, ergab sich eine verblffend einfache Lsung.

Im 8-D-Typ-Register 74SL173, bezeichnet als U12 sind alle
Motor-On-Leitungen und die Drive-Select fr alle vier Drives
anliegend. Weiters sind 3 Nand-Glieder mit offenem Collektor am
Chip U2 vorhanden. Damit ist das Problem schon gelst; ein
kleiner sechspoliger Stecker ud einige Drhte und fertig.

Der Anschlu 16 des U12 ist mit den Anschlssen 1,2 und 4 des U2
zu verbinden. Weiters ist der Anschlu 5 von U12 mit dem Anschlu
5 von U2 zu verbinden. Die Anschlsse 3 und 6 von U2 sind jeweils
mit Wiederstnden von 150 bis 320 Ohm an +5V zu legen.(offener
Collektor). Anschlu 3 von U2 ist mit Anschlu 1 des Steckers zu
verbinden, Anschlu 6 von U2 mit Anschlu 5 des Steckers. Die
Steckeranschlsse 2,4 und 6 sind an Masse zu legen, der Anschlu
3 bleibt offen. Damit sind die nderungen an der Platine fertig.

Am Verbindungskabel zu den Diskettendrives ist ein dritter
Stecker zu montieren, wobei die Leitungen 11 bis 16 zu entfernen
sind so durch das neue Verbindungskabel von dem 6-poligen Stecker
zu ersetzen sind, da  der Steckeranschlu 16 mit Leitung 1, 15
mit 2 usw. bis 11 mit 6 zusammenkommen.

Nun ist noch ein Treiber fr dieses Laufwerk zu Installieren. Da
ich mit MS-DOS 3.3 arbeite habe ich folgenden Befehl in die Datei
CONFIG.SYS aufgenommen.

device=driver.sys /D:2/T:80/F:3

Da ich eine Festplatte "C:" habe, hat das dritte Laufwerk die Bezeichnung D:

Falls Sie Fragen haben: mein Name ist Peter Schneeweis, mein Telefon 96-39-38.

8-4-2-1

TGM_98 : REIHE421.BAS

Dipl.-Ing. R.Neubauer / TGM

Bezug:  Wissenschaftliche Nachrichten Nr.79 - Jnner 1989, Seite 23 u. 24

Perfektion und Information im Mathematikunterricht 1.


"Der Lehrer lt sich eine kleine natrliche Zahl N = a1 nennen und die weiteren Glieder einer Folge nach der Vorschrift

      a(n+1) = a(n) / 2  fr gerades a(n) bzw.
      a(n+1) = a(n)*3 + 1  fr ungerades a(n)

berechnen. Fr z.B. N = 5 ergibt sich die Folge

      5, 16, 8, 4, 2, 1, 4, 2, 1, .....

fr N = 11

      11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1, .....



Obwohl das Einmnden in die Periodizitt 4, 2, 1 bisher immer eintrat, ist die Frage nach der Allgemeingltigkeit des Ergebnisses noch offen. 

Der Vorschlag, die Schler mgen doch nach Ausnahmen suchen, wird sicher schon in den untersten Klassen zur Eigenttigkeit anspornen und dabei das Rechnen festigen."

Soweit aus o.a. Zeitschrift zitiert !

Das kleine BASIC - Programm REIHE421.BAS kann die Rechenarbeit ganz erheblich erleichtern:

      50  INPUT A
      70  IF A MOD 2=0 THEN PRINT A;
      100 IF A MOD 2=0 THEN A=A/2
      150 PRINT A;
      200 IF A=0 THEN 450
      210 IF A=1 THEN 450
      230 IF A MOD 2=0 THEN 100
      250 A=A*3+1:PRINT A;
      270 IF A=1 THEN 450 ELSE 100
      450 PRINT
      500 INPUT A
      600 IF A=0 THEN END ELSE 70

Interessant sind die etwas lngeren Ausgaben bei den Eingaben 27, 31,41, 47, 54, 55, 62, 63, 71, 73, 82, 83, 91, 94, 97, 103, 107, 108, 109, 110, 111, 124 u.125 u.s.w., aber auch die krzeren Ausgaben bei Eingabe anderer Werte, welche wirklich alle mit der Periodizitt 4, 2, 1 endigen. Beendet wird der Programmlauf durch Eingabe von 0 .

Erfahrungen mit Symphony 1.1

G. Silberbauer / TGM

Symphony ist ein universell verwendbares Programmpaket zur Textverarbeitung, Tabellenkalkulation, als Datenbank, als Grafikpaket und fr Kommunikation, alles unter einer Benutzeroberflche. 

Wenn Sie an Ihre Textverarbeitung hohe Anforderungen stellen und viele Schriftarten wnschen oder eine deutsche Rechtschreibhilfe etc., dann vergessen Sie Symphony - es gibt viel bessere Nur-Textverarbeitungs-Programme! Doch fr normale Briefe oder Formbriefe zusammen mit der immer bereiten Datenbank und gemischt mit Tabellenkalkulation (z.B. Rechnungswesen, Mahnwesen etc.) kommt man ganz gut mit Symphony aus.

Meine berlegung war ursprnglich die, da es einfacher sein mte, ein einziges Programm gut zu lernen als verschiedene fr verschiedene Zwecke. Das glaube ich auch jetzt noch. Leider gibt es bei uns noch sehr wenige Symphony-User, soda man leichter jemanden findet, der einem bei dBase 3+ hilft oder bei Word als bei Symphony. So mu man sich vieles selbst erarbeiten mit Hilfe von Bchern und dem Tutor.

Leider gibt es auch keine Kollegen, die wirklich verschiedene Programmpakete gleich gut beherrschen und objektiv zwischen den Paketen vergleichen knnen. So kann ich nur von eigenen Erfahrungen und von Bemerkungen anderer Kollegen zu meinen Problemen berichten.

Eine der Hauptstrken von Symphony ist die ausgereifte Tabellenkalkulation. Damit ist es einfach, komplexere Tabellen anzulegen, die sich selbst berechnen. Ich habe z.B. eine selbstgemachte "Umgebung", bestehend aus mehreren Fenstern, zur Berechnung von allem, was ich am 10. jedes Monats fr das Finanzamt brauche: Lohnkonten wegen Lohnsteuer und Dienstgeberbeitrag, Rechnungsbersicht wegen Mehrwertsteuer, Vorsteuern von Kassa und Banken, berstundenabrechnungen etc. Das luft auf dem Turbo-XT mit 640 k, jedoch lade ich dieses File ca. 40 Sek. von der Harddisk - die Berechnung dauert eben. hnliche groe Files habe ich als Kundenkartei (Datenbank) und als Rechnungsverzeichnis. 

Die Datenbank arbeitet anders als in dBase: es wird immer die ganze Datenbank in den Rechner geladen. Da gibt es Grenzen mit 640 k, doch wenn einmal geladen ist (auch das dauert ber 30 Sek. bei einer ausfhrlicheren 1200-Personen-Datenbank), geht alles schneller als in dBase. Man kann auch viel programmieren und hat dazu mchtige Befehle, kann Makros schreiben, automatisch ablaufen lassen beim Laden des Files oder mit Kurzbezeichnungen aufrufen oder mit einem Makro-Manager berall verwenden etc. - man kann immer noch dazulernen. 

HiSoft '89

Vielleicht kann Ihnen diese Sonderausgabe des TREND-PROFIL-EXTRA von Gergely & Gschl helfen, einen berblick ber die Leistungsfhigkeit von Software geben. 

Aus dem Inhalt:

Die zehn Gebote fr PC-Anwender, Der Computermarkt gestern, heute, morgen, Kampf der Betriebssysteme, Buchhaltung, Glossar, Firmenverzeichnis

getestet und verglichen wurden:

TEXTVERARBEITUNG: Comfotex, Enable, Euroscript, Framework II und III, GEM 1st Word Plus, PC Text 4, Writing Assistant, Lotus Manuscript, Microsoft Word, Microsoft Works, Multimate Advantage, Open Access II, Pharao, Q-One, Star Writer, Symphony, Tex-Ass Window Plus, Windows Write, Word Perfect, Wordstar 2000, Wordstar 4.0 Extra

DATENBANK: dBase III+, Enable, Excel, F&A, Foxbase plus, Framework II und III, GBase, Lotus 1-2-3, Microsoft Works, Open Access II, Paradox, Pharao, Rapid File, RBase, Symphony

TABELLENKALKULATION: Enable, Excel, Framework II und III, Lotus 1-2-3, Microsoft Works, Multiplan, Open Access II, Pharao, Quattro, Star Planer, SuperCalc 4, Symphony

INTEGRIERTE PROGRAMME: Enable, Excel, Framework II und III, Microsoft Works, Open Access II, Symphony

GRAFIK: Chart Master, GEM Graph, GEM Presentation Team, Graph Plus, Harvard Graphics, Microsoft Chart, Perspective, VCN Concorde

ZEICHENPROGRAMME: Freelance Plus, GEM Draw Plus, Windows Draw

MALPROGRAMME: GEM Paint, PC Paintbrush, Windows Paint

DESKTOP PUBLISHING: Byline,  First Publisher, GEM Desktop Publisher, Page Maker Ventura Publisher

UTILITIES: DS Backup+ und DS Recover, Floppy Driver, Norton Commander, Norton Utilities, PC+Softlock und PC+Master, PC-Tools, PKarc, Safe-Guard, Sideways, Star Manager, Turbo Backup, Word for Word.
 
Programm SYSTEST

TGM_98 : SYSTEST.EXE, ILTEST.EXE, LESEN.EXE

Zitate aus den Hilfe-Menus:

"Das Programm ermglicht Ihnen den Test Ihrer Systemkomponenten. Folgende Tests sind mglich: Prozessor Festplatte Bildschirm Setup Information Vergleich. Whlen Sie die Komponente aus dem Hauptmen durch Eintippen ihres ersten Buchstabens (P, F, B) oder benutzen Sie die Pfeiltasten und
die Return-Taste. "

"Wenn Sie Ihre Resultate in eine Datei speichern wollen, starten Sie das Programm einfach mit: SYSTEST <Laufwerk:><Dateiname>."

"Die Option Vergleich (V) erlaubt es Ihnen, Ihr Gert mit verschiedenen Standards zu vergleichen: Dem 'klassischen' IBM PC/XT und den drei neuen IBM-PS/2-Systemen. Whlen Sie in diesem Submen Ihr Vergleichssystem mit den Pfeiltasten aus und drcken Sie <Return>. Standardeinstellung ist: IBM PC/XT."

Ein Beispiel fr die Ausgaben von SYSTEST bei einem portablen AT mit Hercules-Monitor und 40MB Festplatte:

Prozessor

    Prozessortyp              Intel 80286
    Datenbus                  16 Bit
    Taktfrequenz              12.05 MHz
    Datendurchsatz            3820497 BPS
    RAM Wait States           1

    Leistungsindex verglichen mit  IBM PC/XT

    Benchmark 1                      4.773 Sekunden
    Leistungsindex 1                 7.025
    Benchmark 2                      4.953 Sekunden
    Leistungsindex 2                 4.005

Festplatte

    Bytes pro Sektor          512      FAT Sektoren              064
    Sektoren/Speicherblock    004      Directory-Eintrge        512
    Sektoren/Spur             017      Verborgene Sektoren       017
    Lese/Schreibkpfe         005      Reservierte Sektoren      001
    Zylinder                  976      Spuren                    4880
    FAT Kopien                002      Plattenkapazitt (MB)     42.5

    Spur zu Spur Zugriffszeit            5.12 Millisekunden
    Durchschnittliche Zugriffszeit      25.00 Millisekunden
    Maximale Zugriffszeit               40.00 Millisekunden

    Interleave-Faktor                    2

    Datendurchsatz bester Fall           253592 Bytes / Sekunde
    Datendurchsatz schlechtester Fall     94873 Bytes / Sekunde

    Leistungsindex verglichen mit   IBM PC/XT          3.057

Bildschirm

    Video RAM Datendurchsatz        144073 Bytes/Sekunde
    ROM BIOS Video Datendurchsatz     4060 Bytes/Sekunde
    DOS Video Datendurchsatz          2375 Bytes/Sekunde
    Video RAM Wait States                5


    Leistungsindex verglichen mit  IBM PC/XT

    Video RAM Ausgabe           3.305
    BIOS Video Ausgabe          2.719
    DOS Video Ausgabe           4.264

Setup

    Gertetyp                           IBM AT oder kompatibel
    DOS Version                         3.30

    Gegenwrtige Installation

    Bildschirmtyp                       MONOCHROM
    Game Adaptor                        NICHT INSTALLIERT
    Math. Koprozessor                   NICHT INSTALLIERT
    Systemspeicher                      640 KB
    Parallele Schnittstellen            1
    Serielle Schnittstellen             1
    Festplatten-Laufwerke               1
    RAM-Erweiterung                     384 KB
    Festplattentyp Nr.                  15
    Diskettenlaufwerke                  1
    High-Density-Laufwerke              0
    Low-Density-Laufwerke               1

VIREN in Nippon

Ing. Alois Lippert

Abschrift aus der Sonderbeilage der Sddeutschen Zeitung Nr.260 vom Dienstag 10.November 1988 - bersetzter Artikel aus der japanischen Zeitung ASAHI SHIMBUN. Publiziert zwischen September-Oktober 1988.

    "COMPUTER-VIREN" aufgetaucht
    Zum ersten Mal ins landesinnere Netz eingedrungen

Laut Meldung vom 13.September ist ein "Computer-Virus", der sich von Computer zu Computer bertrgt und dort  gespeicherte Daten lscht oder verndert, in das grte Computer-Netz des Landes, PC-VAN, das vom NEC (Nippon Electric Company) betrieben wird, eingedrungen.Da dieser Virus das Kennwort des Benutzers, in dessen Computer er eingedrungen ist, stiehlt und da man davon ausgeht, da schon etwa zehn Personen Schaden erlitten haben, ist man im PC-VAN-Bro dazu bergegangen, die ca. 45 000 Mitglieder ber das Netz zu warnen.Whrend in Europa und den USA dieser neue "Virus" um sich greift und man sich vergeblich bemht, ihn auszurotten, ist sein Eindringen in ein japanisches Benutzer-Netz eine Premiere. 

Der sogenannte "Computer-Virus" ist eigentlich eine Art Programm.
Es hat diesen Namen erhalten, da es sich in die Computer anderer Leute einschleicht und vermehrt.Es ist jetzt zwei Wochen her, da das Eindringen des Virus in das PC-VAN-Netz bemerkt wurde.Ein Mitglied hat eine merkwrdige Nachricht auf einer "Angebots-Tafel" des Netzes entdeckt und die Dienststelle benachrichtigt.Die darauf erfolgte Untersuchung ergab, da es sich hier um eine neue bsartige Sorte handelte, welche die Kennwrter anderer stiehlt. Mit einem gestohlenen Kennwort ist es mglich, innerhalb des Netzes die Rolle des Besitzers zu bernehmen, zum Beispiel
eigene Bentzergebhren auf ihn zu bertragen oder unter seinem Namen Einkufe zu ttigen (on-line shopping).

Der Virus sei, so die Dienststelle, in einem Programm eingebaut, das der Tter per elektronischer Post an das Opfer geschickt habe.Wenn das Opfer ein solches Programm benutzt, schleicht sich der Virus in die Basis-Software ein.Wenn sich das Opfer dann mit dem PC-VAN-Host-Computer in Verbindung setzt, zeigt sich der Virus in seiner wirklichen Gestalt. Er verschlsselt das Kennwort des Opfers und schreibt es in die "Angebots-Tafel" des PC-VAN-Netzes.Spter sieht sich der Tter dann die Tafel an und kommt so an das Kennwort. So sieht der komplizierte Mechanismus aus.

Der Tter, der den Virus geschickt hat, scheint schon von Anfang an gestohlene Benutzer-Nummern(user-ID) und Kennwrten benutzt zu haben; er konnte noch nicht bestimmt werden. Aus diesem Grunde hat das PC-VAN-Bro am 12.September damit begonnen, die Mitglieder davon in Kenntnis zu setzen, da der Virus in die Tafel des Netzes eingedrungen ist und sie zu warnen. Gleichzeitig wurde, um die Ausweitung des Schadens festzustellen, zur Mitarbeit an einer Untersuchung aufgefordert. 

Was ist zu tun, um Schaden durch den Virus zu verhindern? Keine verdchtigen Programme benutzen, die per elektronischer Post kommen. 

Mitglieder haben bereits einen "Impfstoff" entwickelt, mit dessen Hilfe es mglich ist, festzustellen, ob der eigene Computer vom Virus infiziert ist oder nicht, und den das PC-VAN-Bro bereits ber das Netz verteilt.Auerdem heit es, da auch bei einer "Infektion" nichts passiere, wenn man die Basis-Software in ihre ursprngliche Lage bringt und das Kennwort ndert.

Auf der Hannover CeBit 1989
...mit Bercksichtigung des Themas Taiwan

Dipl.Ing.A.Zandomeneghi

Da es mir heuer mglich war, die 1036 km nach Hannover zur Messe zu bewltigen, mchte ich einige fr Clubkollegen interessante Neuigkeiten zusammenfassen:

Was das Thema "Taiwan" betrifft, kann man hier sozusagen eine "Konsolidierungsphase" von v.a. greren Firmen beobachten. Wie ich aus Gesprchen mit einigen Firmenvertretern erfahren habe, wird es in Hinkunft nicht mehr mglich sein, bei Firmen direkt in Taiwan zu bestellen, die schon in sterreich eine Vertretung haben. Dies gilt z.B. fr "Qtronix" (Muse, Bildschirme), von der ich in einem vergangenen Artikel berichtet habe. Die Vertretung wird in Hinkunft laut einem "offiziellen" Blatt der Firma in sterreich von "Herlango" bernommen. Fr viele Clubmitglieder wohl keine sehr positive Nachricht! Ich werde aber in Hinkunft auf kleinere taiwanesische Firmen ohne Vertretung hierzulande ausweichen.

Als Anlaufstelle fr Fragen kann ich das "CETRA" (C_hina E_xternal T_rade D_evelopment C_ouncil) empfehlen, das auch auf der CeBit vertreten war. Die Aufgabe dieser Institution ist es, eine Art Standort- und Industriewerbung fr das Land zu machen. Ein Exemplar der wirklich informativen Broschre "Microcomputers in Taiwan, ROC 1989" wurde mir von einer freundlichen Chinesin am CETRA-Stand berlassen (Danke Frulein Wu !), nachdem ich einen Fragebogen betreffend einen Vergleich der Fernost-Computerlnder Taiwan, Japan, Hongkong und Singapur beantwortet hatte. Das Heft umfat etwa 100 Seiten und enthlt eine komplette Aufstellung aller taiwanesischen Hersteller, aufgeschlsselt nach der Angebotspalette; Firmenprofile (Grndung der Firma, Anzahl der Beschftigten etc.) sowie eine Beschreibung der angebotenen Hardware! Ich werde mein Exemplar dem Verein zum Zweck des Kopierens zur Verfgung stellen. 

Da ich in den vergangenen Monaten von mehreren Clubmitgliedern in Bezug auf die neueste Preissituation in Taiwan, speziell betreffend 386er-Boards, angeschrieben worden bin, hier einige allgemeine Informationen; man kann die angebotenen 386 Board m.E. in vier Kategorien einteilen (Stand Mrz '89):

            Taktfrequenz                  Preis (ungefhr)

   ) 386 mit 16 MHz                           850 US$
   ) 386 mit 20 MHz                          1000 US$
   ) 386 mit 25 MHz                          1450 US$
   ) 386 mit 25 MHz mit Cache-Speicher       1700 US$

In allen genannten Preisen sind 1MB Speicherbausteine enthalten. Dazu mssen noch 20 % Mehrwertssteuer sowie die Transportkosten gerechnet werden. Die Musterpreise beziehen sich auf Angebote der Firma "Digicom", doch ist die Preissituation bei anderen taiwanesischen Firmen, schon aufgrund der Konkurrenzsituation hnlich. Durch die angespannte Lage auf dem Markt fr Speicherbausteine ist aber der Preis fr RAMs in Taiwan auch nicht viel niedriger als hierzulande.

Bleibt nur noch anzumerken, da es ganz und gar unmglich war, das riesige Angebot auf der Hannover Messe an einem Tag zu inspizieren, obwohl ich 8 Stunden unterwegs war. Doch kann man die bekannten Anbieter (Microsoft, IBM etc.) auch auf der Wiener "Ifabo" besuchen. Ich kann aus eigener Erfahrung sagen, da in sterreich auf den Messen v.a. Stnde mit Anbietern aus Fernost sowie aus bersee fast gnzlich fehlen, wobei in Hannover allein die USA und Kanada auf der CeBit fast eine ganze Halle(!) fr sich in Anspruch nahmen. Falls Clubmitglieder Interesse an diesen Adressen haben, mgen sie sich mit mir in Verbindung setzen. 


FRAGEN
Frage:
Kennt jemand ein Grafikprogramm, das einen STAR-LC-10 Color-Drucker untersttzt? Kennt oder hat jemand DELUXE PAINT II PC?
Antworten an Mag. Walter Neidhart, Karlsdorf 15, 9851 LIESERBRCKE

Frage:
Suche das Programm STEN von Side&Soundstudio in der speziellen Fassung fr Linkshnder. (Lern- und Trainingsprogramm fr Steno-Schrift). Antworten erbeten an: Hans Schattauer, Magdalenenstrae 25/7, 1060 Wien

Anfrage des RENIETS-VERLAG, Obkirchergasse 36, 1190 Wien, 32 72 74, Herr Anton Burger, Bitte bei Rckantwort Korrespondenzzeichen Bu/896.19 angeben!

Gesucht werden Spezialisten fr die mathematische Textverarbeitung TEX, die in der Lage wren, reprofhige Bltter von ca. 150 handgeschriebenen A4-Seiten zu erstellen. Diese Vorlagen sind ein Lsungsheft fr den Mathematikunterricht und enthalten mathematische Formeln. Die genauen Konditionen dieses Auftrags und die gesamte Auftragsabwicklung sind mit dem Verlag abzusprechen. 
TEX-Liebhaber bitte melden.
TGM-Disketten
TGM_98 : NEWS 2/98, Texte und Programme

N        TXT   136704  12.05.89  19.50  / Texte
STANDARD TBS     1024  12.05.89  19.51 /

GAUSS    SBR     8303  25.03.89   7.42    / Lineares 
GAUSS    SYS      780  25.03.89   7.43   /  Gleichungssystem
LINGL    DOC      830  10.05.89   0.21  /
LINGL    PAS     8762  25.03.89   7.54 /

SPLIT    C       6347  17.04.89  21.43         /
SPLIT    EXE    13828  17.04.89  21.44        /
386_1    BAT      100  22.04.89  14.49       /
386_1    PAT      258  22.04.89  15.03      /EPROMs im AT
386_1    TXT      276  22.04.89  15.03     / verndern
LF       TBL        5  18.04.89   9.14    /
XLIT     COM     1780  24.02.85  17.01   /
XLIT     DOC     7572  26.02.85   9.27  /
XLIT     TBL       13  15.02.88  12.07 /

REIHE421 BAS      262  12.05.89  19.52 / 8-4-2-1

UNIDRV   ASM    28780  27.12.88  14.57  / Fremdformate
UNIDRV   SYS     2005  27.12.88  15.00 /  im XT

PROLOAD  COM      937   6.02.89  16.50  / PROLOAD
PROLOAD  ASM     8031   6.02.89  16.48 /

ILTEST   EXE    22635  26.02.87  12.07   / Programm SYSTEST
LESEN    EXE    13450   1.08.87  13.00  /
SYSTEST  EXE    46809   1.08.87  13.00 /


TGM_99 : EPSON-Druckertreiber-1

Vor allem Treiber fr die Drucker LQ-850 und LQ-1050 aber auch fr andere 9- und 24-Nadel-Drucker. 

EPSON    BAT       53  28.04.88  11.45
HILFE             490  30.06.88  13.40
READ     ME       828  28.04.88  15.08
ES           <DIR>      9.05.89  22.47
MM           <DIR>      9.05.89  22.47
PCTEXT       <DIR>      9.05.89  22.47
TWIN         <DIR>      9.05.89  22.47
WORD4        <DIR>      9.05.89  22.47
WP           <DIR>      9.05.89  22.47
WS           <DIR>      9.05.89  22.47

TGM_100 : EPSON-Druckertreiber-2

EPSON    BAT       53  28.04.88  11.45
HILFE             490  30.06.88  13.40
READ     ME       829  28.04.88  15.14
ACAD         <DIR>      9.05.89  22.48
CHART        <DIR>      9.05.89  22.48
FW           <DIR>      9.05.89  22.48
GEM          <DIR>      9.05.89  22.48
LOTUS        <DIR>      9.05.89  22.49
OA           <DIR>      9.05.89  22.49
WIN          <DIR>      9.05.89  22.49


TGM_101 : EPSON-Hardcopy

Ein residentes Bildschirmdruckprogramm fr 9- oder 24-Nadel-Drucker mit und ohne Farbe, hnlich GRAPHICS.COM des Betriebsystems, aber fr CGA, HGA, MGA und EGA-Karte. 

24       DOK    98532  29.10.87  15.49
9        DOK    98283  29.10.87  16.14
COPYFEST BAT      403   9.11.87  10.48
INSTALL  EXE    39200   9.11.87  11.24
LIESMICH BAT     1247  24.03.88  19.15
PRTINS   BAT      178  29.03.89  13.36
PRTSC24H EXE    24827  15.10.87   1.10
PRTSC24L EXE    24715   9.11.87   8.52
PRTSC9   EXE    25415  15.10.87   1.10

