Das nachfolgende Dialogbeispiel möge die Aufgabenstellung verdeutlichen :
Moin Moin - Assembler ist eine schön bittige Programmiersprache A 6 B 4 C 4 D 0 E 13 F 0 G 4 H 4 I 13 J 0 K 0 L 2 M 9 N 8 O 6 P 4 Q 0 R 9 S 9 T 6 U 0 V 0 W 0 X 0 Y 0 Z 0
Bitte beachtet die folgenden Randbedingungen :
Das Unterprogramm zur Matrizenaddition soll in ein Hauptprogramm folgenden Ablaufs eingebettet werden :
Type Dimension = (Zeile,Spalte); Matrix = Array [1..10,1..10] Of Integer; Var Dims : Array[1..3,Dimension] Of Word; Mats : Array[1..3] Of Matrix; Function ReadKey:Char; Assembler; Asm mov ah,8 int 21h End; Function IntRead:Integer; Var Result:Integer; Signed:Boolean; Digit:Char; First:Boolean; Begin Result := 0; Signed := False; First := True; Repeat Digit := ReadKey; If (Digit='-') And First Then Begin Signed := True; First := False; Write(Digit) End; If (Digit>='0') And (Digit<='9') Then Begin First := False; Result := Result*10+(Ord(Digit)-Ord('0')); Write(Digit) End Until Digit=#13; If Signed Then Result := -1*Result; IntRead := Result End; Procedure MatRead(DimX,DimY:Word;Var Mat:Matrix); Var X,Y:Integer; Begin For Y := 1 to DimY Do For X := 1 To DimX Do Begin Write('[',Y,',',X,'] = '); Mat[X,Y] := IntRead; WriteLn End End; Procedure MatWrite(DimX,DimY:Word; Var Mat:Matrix); Var X,Y:Integer; Begin For Y := 1 To DimY Do Begin For X := 1 to DimX Do Write(Mat[X,Y]:8); WriteLn End End; Function MatMult(DimAx,DimAy,DimBx,DimBy:Word; Var DimCx,DimCy:Word; Var MatA,MatB,MatC:Matrix):Boolean; Var I,X,Y:Word; Skalar:Integer; Begin If DimAx = DimBy Then Begin MatMult := True; DimCx := DimBx; DimCy := DimAy; For X := 1 To DimCx Do For Y := 1 To DimCy Do Begin Skalar := 0; For I := 1 To DimAx Do Skalar := Skalar+MatA[I,Y]*MatB[X,I]; MatC[X,Y] := Skalar End End Else MatMult := False End; Begin WriteLn('MATRIZENMULTIPLIKATION'); Repeat Write('Zeilenanzahl 1.Matrix : '); Dims[1,Zeile] := IntRead; WriteLn Until Dims[1,Zeile] In [1..10]; Repeat Write('Spaltenanzahl 1.Matrix & Zeilenanzahl 2.Matrix : '); Dims[1,Spalte] := IntRead; Dims[2,Zeile] := Dims[1,Spalte]; WriteLn Until Dims[1,Spalte] In [1..10]; Repeat Write('Spaltenanzahl 2. Matrix : '); Dims[2,Spalte] := IntRead; WriteLn Until Dims[2,Spalte] In [1..10]; WriteLn('1.Matrix :'); MatRead(Dims[1,Spalte],Dims[1,Zeile],Mats[1]); WriteLn('2.Matrix :'); MatRead(Dims[2,Spalte],Dims[2,Zeile],Mats[2]); If MatMult(Dims[1,Spalte],Dims[1,Zeile], Dims[2,Spalte],Dims[2,Zeile], Dims[3,Spalte],Dims[3,Zeile], Mats[1],Mats[2],Mats[3]) Then Begin WriteLn('Ergebnismatrix :'); MatWrite(Dims[3,Spalte],Dims[3,Zeile],Mats[3]) End Else WriteLn('Unexpected Severe Error') End.
In dieser Übung geht es darum, eine Verknüpfung zwischen Assembler und einer Hochsprache zu finden. Wir möchten Euch bitten, in Assembler eine kleine Bibliothek zu schreiben, aus welcher wir von Pascal aus eine Routine zum Berechnen von "Plasma" Bildschirmen aufrufen können.
Diesen "Plasma Bildschirm" werden wir im Grafik Modus verwalten. Dazu müssen wir zuerst uns einmal Gedanken machen, wie der Grafik Modus organisiert ist. Wir liefern Euch zu der zu entwickelnden Bibliothek ein Pascal Rahmen Programm, wo der Grafik Modus schon initialisiert wird (genauere Informationen kann man aus der Ralf Brown Interrupt Liste beziehen, siehe dort unter INT 10h). Der Grafik Bildschirm ist im Arbeitsspeicher an der Segmentadresse $0A000 organisiert, umfaßt dort genau 64KB und ist linear aufgebaut. Linear heißt in diesem Fall, daß direkt nach einer Grafik Zeile die nächste darauf folgt. Ich habe mich für eine Auflösung von 320*200 Pixeln zu 256 Farben entschlossen, mit anderen Worten, die erste Zeile fängt mit dem Offset $0000 an, die zweite folgt hier auf $0140 u.s.w., ein Pixel bzw. Punkt auf dem Bildschirm entspricht genau einem Byte Wert.
Der Plasma Bildschirm setzt auf eine Sinus Tabelle auf, welche ich im Pascal Programm als ein Array hinterlegt habe, welches eine Dimension von 360 Einträgen hat. Zuerst möchte ich auf die Schnittstelle eingehen, diese ist Euch freigestellt, nur folgende Informationen müssen übermittelt werden, einmal Zugriff auf die Sinus Tabelle, einmal die X- sowie Y-Auflösung des angewählten Grafik Modus und zuletzt eine Referenz auf eine Word Variable, die uns als Laufvariable für die Bewegung dienen wird. Implementiert die Schnittstelle im Pascal Programm und benennt die Routine plasma_calc, so wie sie im Hauptprogramm aufgerufen wird.
Der Plasma Algorithmus für die Bibliothek verfolgt folgendes Schema: Zuerst nehmen wir uns die Laufvariable vor, erhöhen diese um einen. Daraufhin überprüfen wir Sie, da sie als eine Art Index für die Sinustabelle herangezogen werden soll, ob sie die Dimension der Tabelle nicht sprengt! Dann definieren wir uns zwei Schleifen, eine Äußere, die im Bereich der vertikalen (Y) Auflösung rückwärts durchläuft, eine zweite, die den Bereich vom letzten Bildpunkt zum ersten auf der horizontalen durchläuft. Innerhalb der äußeren Schleife nehmen wir uns nun ein Byte aus der Sinus Tabelle, durch den vertikalen Schleifenzähler indiziert und merken uns dieses Byte. Achtet an dieser Stelle auf das Offset innerhalb dem Grafik Speicher, da hier das Offset immer auf einen Zeilenanfang gesetzt sein sollte. Darauf folgt die zweite innere Schleife. Auch hier holen wir uns ein Byte aus der Sinus Tabelle, indiziert durch den inneren Schleifenzähler. Dieses Byte halten wir auch fest. Nun nehmen wir uns den Wert des inneren Schleifenzählers, auf diesen Wert addieren wir den Counter, achten wiederum, ob das Resultat als Index für die Sinus Tabelle noch gültig ist, verändern aber nicht den Schleifenzähler selber! Auf das zuvor von der inneren Schleife gemerkte Byte addieren wir jetzt ein weiteres aus der Sinus Tabelle auf, indiziert durch den gerade zuvor errechneten Wert. Auf diese Summe kommt noch einmal der Wert aus der äußeren Schleife aufaddiert, so daß wir diesen Wert zu aller letzt noch einmal durch 4 teilen müssen. Das daraus resultierende Ergebnis wird nun in den Grafik Bildschirm geschrieben, die Ausgabe der Grafik Bildpunkte erfolgt von der linken oberen Ecke linksbündig, Zeile für Zeile.
Program Test_Plasma; {$G+} uses crt; Const Sin_Tab : Array[0..359] of byte = ( 128,130,132,134,136,139,141,143, 145,147,150,152,154,156,158,160, 163,165,167,169,171,173,175,177, 179,181,183,185,187,189,191,193, 195,197,199,200,202,204,206,207, 209,211,212,214,216,217,219,220, 222,223,225,226,228,229,230,232, 233,234,235,236,237,239,240,241, 242,243,244,244,245,246,247,248, 248,249,250,250,251,251,252,252, 253,253,253,254,254,254,254,254, 254,254,255,254,254,254,254,254, 254,254,253,253,253,252,252,251, 251,250,250,249,248,248,247,246, 245,244,244,243,242,241,240,239, 237,236,235,234,233,232,230,229, 228,226,225,223,222,220,219,217, 216,214,212,211,209,207,206,204, 202,200,199,197,195,193,191,189, 187,185,183,181,179,177,175,173, 171,169,167,165,163,160,158,156, 154,152,150,147,145,143,141,139, 136,134,132,130,128,125,123,121, 119,116,114,112,110,108,105,103, 101,099,097,095,092,090,088,086, 084,082,080,078,076,074,072,070, 068,066,064,062,060,058,056,055, 053,051,049,048,046,044,043,041, 039,038,036,035,033,032,030,029, 027,026,025,023,022,021,020,019, 018,016,015,014,013,012,011,011, 010,009,008,007,007,006,005,005, 004,004,003,003,002,002,002,001, 001,001,001,001,001,001,001,001, 001,001,001,001,001,001,002,002, 002,003,003,004,004,005,005,006, 007,007,008,009,010,011,011,012, 013,014,015,016,018,019,020,021, 022,023,025,026,027,029,030,032, 033,035,036,038,039,041,043,044, 046,048,049,051,053,055,056,058, 060,062,064,066,068,070,072,074, 076,078,080,082,084,086,088,090, 092,095,097,099,101,103,105,108, 110,112,114,116,119,121,123,125); { Deklaration & Einbindung der zu entwickelnden Prozedur } var oldmode:integer; counter:word; begin oldmode:=lastmode; counter:=0; asm mov ax,13h int 10h end; repeat plasma_calc(@sin_tab,counter,320,200); until keypressed; textmode(oldmode); readln; end.