Übungen

Archiv Sommersemester 2000

Übung 1 (11.04.2001) RZ2/3

Entwickle zunächst eine allgemein verwendbare Toolbox (Datentransfer via geeignet zu definierender Register) zum sowie anschließend ein EXE-Programm - unter Benutzung der gerade entwickelten Toolbox - zum Berechnen und Ausgeben der absoluten Häufigkeit der einzelnen Buchstaben (ohne Unterscheidung zwischen Klein- und Großbuchstaben) über die Standardausgabe in einer zuvor über die Standardeingabe eingelesenen Zeichenkette. Es entstehen zwei Quellcode-Dateien mit je einem Code-Segment. Für das Aufrufen der Routinen in der Toolbox kommen neben dem CALL-Befehl die beiden Assembler-Anweisungen EXTRN und PUBLIC zum Einsatz.

Das nachfolgende Dialogbeispiel möge die Aufgabenstellung verdeutlichen :

Moin Moin - Assembler ist eine schön bittige Programmiersprache

A  3
B  2
C  2
D  0
E  7
F  0
G  2
H  2
I  7
J  0
K  0
L  1
M  5
N  4
O  3
P  2
Q  0
R  5
S  5
T  3
U  0
V  0
W  0
X  0
Y  0
Z  0

Übung 2 (25.04.2001) RZ2/3

Quasi als Gegenstück zu der in der vorherigen Übung entwickelten Routine zur dezimalen Ausgabe einer vorzeichenbehafteten 16-Bit ganzen Zahl, soll in dieser Übung eine Routine zur dezimalen Eingabe (d.h. Einlesen via Standardeingabe) einer ebenfalls vorzeichenbehafteten 16-Bit ganzen Zahl entwickelt werden. Auch diese Routine wird Bestandteil der in der vorherigen Übung begonnenen Toolbox. Die Toolbox enthält kein eigenes Datensegment. Zwischenergebnisse der Routine werden in den Prozessorregistern bzw. auf dem Stack abgelegt; das Ergebnis soll via DX-Register bereitgestellt werden.

Zum Testen dient ein zu entwickelndes Hauptprogramm, welches beliebig viele Integer-Werte über die Standardeingabe einliest (Abbruchkriterium sei die Zahl -32768), und anschließend den größten und kleinsten Wert, sowie den Mittelwert in der Form ganzzahliges Ergebnis und (ganzzahligen) Rest ausgibt.

Tips für die Toolbox-Routine : Jedes via DOS-Funktion 8 (MOV AH,8 INT 21h) ohne Echo eingelesenes Zeichen wird entweder sofort verarbeitet (gültiges Zeichen laut Syntaxdiagramm) oder ignoriert (ungültiges Zeichen laut Syntaxdiagramm). Zur Verarbeitung gehört auch das Echo gültiger Zeichen über die Standardausgabe. Das Eingabeende erfolgt durch Drücken der RETURN-Taste. Eventuell entstehende Zahlenüberläufe wie z.B. 32768 dürfen ignoriert werden.

Intermezzo (02.05.2000) HS4

Übersetze die nachfolgenden Assembler-Programmausschnitte (Ziel: COM-Dateien) in Maschinencode :
      MOV  DL,43h         ; Offsetadresse 100
      MOV  DL,21h
      MOV  DX,4321h
      MOV  OPA,DX
      MOV  DX,OPA
      MOV  TABL[SI],DX
      MOV  DX,TABL[SI]
      MOV  OPA,4321h
      MOV  TABL[SI],4321h
      INT  20h

      CALL UP             ; Offsetadresse 300
      ...
UP    PROC                ; Offsetadresse 400
      ...
UP    ENDP

UP    PROC                ; Offsetadresse 200
      ...
UP    ENDP
      ...
      CALL UP             ; Offsetadresse 300

      JE   MARKE          ; Offsetadresse 200
      ...
MARKE:...                 ; Offsetadresse 230

MARKE:...                 ; Offsetadresse 1D0
      ...
      JE   MARKE          ; Offsetadresse 200
In allen zugrundeliegenden Assembler-Programmen stehen ab der Offsetadresse 150 jeweils folgende Daten :
OPA  DW ?
OPB  DB ?
OPC  DW ?
TABL DW 10 DUP (?)
Hinweis : Alle Offsetadressen sind in hexadezimaler Form angegeben.

Übung 3 (09.05.2001) RZ2/3

Entwickle ein EXE-Programm zur Multiplikation zweier maximal 9x9 großer Matrizen. Das Einlesen der tatsächlichen Dimensionen der nicht unbedingt quadratischen Matrizen erfolgt wie das Einlesen der Matrizenelemente (vorzeichenbehaftete 16-Bit ganze Zahlen) über die Standardeingabe. Das berechnete Matrizenprodukt wird über die Standardausgabe ausgegeben. Bei der Dialoggestaltung ist für die einzelnen Ein- und Ausgaben auf eine übersichtliche Textwüste (z.B. aussagekräftige Eingabeaufforderungen) zu achten. Zahlenbereichsüberläufe dürfen wie bereits in der vorherigen Übung erneut weitgehend ignoriert werden. Auch die in den beiden vorherigen Übungen entwickelte Toolbox wird wieder gute Dienste leisten.

Übung 4 (30.05.2001) RZ2/3

Übersetze das nachfolgende Pascal-Programm möglichst bedeutungstreu in ein 8086-Assembler-Programm (EXE-Format). Gemäß den Konventionen von Turbo-Pascal erfolgt die Parameterübergabe (Wert- und Referenzaufruf) über den Stack; ein Integer-Funktionswert wird über das AX-Register zurückgegeben. Zur Ein- und Ausgabe der Integer-Zahlen kommt erneut die in den Übungen 1 und 2 entwickelte Toolbox zum Einsatz.
Program Aufgabe4;

Function Multiply(X,Y:Integer):Integer;

Begin
  If Y = 1 Then Multiply := X
           Else Multiply := Multiply(X,Y-1) + X
End;

Procedure Divide(X,Y:Integer;Var Q,R:Integer);

Begin
  If X >= Y Then Begin
    Divide(X-Y,Y,Q,R);
    Q := Q+1
  End Else Begin
    Q := 0;
    R := X
  End
End;

Var hX, hY, hQ, hR : Integer;

Begin
  {$I-}
  Repeat
    Write('1. Operand : '); ReadLn(hX)
  Until (IoResult = 0) And (hX > 0);
  Repeat
    Write('2. Operand : '); ReadLn(hY)
  Until (IoResult = 0) And (hY > 0);
  {$I+}
  WriteLn(hX,' * ',hY,' = ',Multiply(hX,hY));
  Divide(hX,hY,hQ,hR);
  WriteLn(hX,' / ',hY,' = ',hQ,' Rest ',hR)
End.

Übung 5 (13.06.2001) RZ2/3
(Idee und Realisation : Benno Haupt)

Diesmal steht ein kleines Grafik Programm zur Aufgabe. Wir wollen die sogenannten Shade Bobs nachprogrammieren. Dies sind Grafik Objekte ähnlich der Sprites, also so ne Art bewegliche Bitmaps, die jedoch auf Schatteneffekte basieren. Vorgelegt bekommt ihr ein kleines Pascal Programm, wodrin drei externe Prozeduren deklariert sind, welche noch von Euch zu ergänzen sind. Der Ablauf des Programmes selber gestaltet sich insofern, als das zuerst in den Grafik Modus geschaltet wird, worauf eine spezielle Farb Palette aufgebaut wird. Dann wollen wir zwei Schlangen animieren, wobei deren Bewegungen durch eine "Rahmen Prozedur" gesteuert werden.

Eure Aufgabe besteht darin, das Setzen und Löschen der "Bitmap" bzw. Matrix eines Shadebobs zu übernehmen, sowie deren Koordination.
Da wir uns im Grafikmodus befinden, ist die Ausgabe vollkommen uns überlassen und wir haben leider keinerlei Unterstützung von Seitens DOS oder ähnlichem. Der Grafik Modus hat eine Bildschirmseite beginnend ab dem Segment 0A000h und der Offset Adresse 0h. Hier findet Ihr eine Einteilung von 320 Pixel pro Zeile auf insgesamt 200 Zeilen. D. H. möchte man in der linken oberen Ecke einen Punkt setzen, so sind es hier die Koordinaten 0,0, was bedeutet das man das Offset genauso auf null zu setzen hat (0*320+0), um dorthin ein Byte als Farb Wert zu "moven". Möchte man an der Koordinate 0,2 einen Punkt ausgeben, so beträgt das Offset 1*320+0. Für die rechte untere Ecke wäre es 199*320+319!
So ergibt sich, daß ein Shadebob an dem Offset aus seinen Koordinaten seiner X-Länge nach ausgegeben wird, in einer Schleife, dimensioniert der Y-Größe nach, Zeile für Zeile, wobei das neue Offset nach jeder Zeile um 320-XLänge aufaddiert werden muß.
Das Aussehen eines solchen Shade Bobs ist auch schon vorgegeben. Dazu wurde die Konstante BobMatrix erstellt. Hieraus ist jeweils immer ein Punkt zu entnehmen, um diesen auf den Grafik Bildschirm aufzuaddieren!
Um einen Bob zu löschen, muß man diesen dann nämlich ganz einfach nur wieder subtrahieren, nach den Wertigkeiten vorgegeben in der Matrix!
Das zweite Problem in dieser Aufgabenstellung ist das Errechnen der Koordinaten, welches ich auch euch überlassen möchte. Dazu habe ich einen Rekord aufgebaut, der folgende Form angenommen hat:
type  BobMover  = record
                    positionx   : word;
                    positiony   : word;
                    lastx       : word;
                    lasty       : word;
                    firstspeedx : integer;
                    firstspeedy : integer;
                    lastspeedx  : integer;
                    lastspeedy  : integer;
                    bobscount   : byte;
                  end;
Interessant ist es hier, daß wir uns in einem Rahmen bewegen, den ich auf die Koordinaten 2/2 und 290/170 festlegen möchte. Wir haben also eine Startkoordinate, vorgegeben in positionx und positiony. Wir haben eine Bewegungsgeschwindigkeit firstspeedx und firstspeedy, die zur Bewegung immer auf die Koordinaten aufaddiert werden müssen. Sollten wir nun im Verlauf auf einen Rand stoßen, so ist die Bewegungsgeschwindigkeit einfach umzudrehen (z.B. durch Multiplikation mit -1). So denn haben wir noch den Punkt bobscount, schließlich wollen wir zwei Schlangen darstellen, die sich in der Anzahl der Bobs jeweils aus der Konstante MaxBobs ergeben. Fangen wir mit der Darstellung an, so geben wir erst den ersten, dann den zweiten Bob aus und so weiter, wobei sich die Abstände der einzelnen Bobs jeweils aus der Geschwindigkeit ergeben, d. h. der erste Bob erscheint an positionx+0*firstspeedx und positiony+0*firstspeedy, der zweite analog an positionx+1*firstspeedx und positiony+1*firstspeedy. Achtet auch beim Aufbau darauf, daß wir uns dem Bildschirmrand nähern könnten. Da unsere Schlange aber auch ein Ende haben soll, müssen wir irgendwann anfangen, die Bobs auch wieder zu löschen! Dazu haben wir einmal den Punkt bobscount, wo eben halt alle vorhandenen mitgezählt werden. Wir haben auch lastx, lasty, lastspeedx und lastspeedy, womit wir den gleichen Spaß wie mit dem Kopf der Schlange (also dem führendem Bob) noch einmal machen müssen, sprich Koordinaten und Bewegungsgeschwindigkeit errechnen und auf den Rahmen achten.

So, damit ihr denn dann auch gleich loslegen könnt, hier der festgelegte Pascal Anteil. Die fertige EXE-Datei (auf Basis 100% Pascal ohne Debuginformationen) könnt Ihr hier herunterladen. Viel Spaß und Erfolg wünscht Euch Euer Assembler Team...
{$X+}
program Shadebobs;

uses  crt;

const BobMatrix : array[0..27,0..27] of byte = (
                  (0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0),
                  (0,0,0,0,0,0,0,0,1,1,1,2,2,7,7,2,2,1,1,1,0,0,0,0,0,0,0,0),
                  (0,0,0,0,0,0,1,1,2,2,2,1,2,7,7,2,1,2,2,2,1,1,0,0,0,0,0,0),
                  (0,0,0,0,0,1,2,2,1,1,1,1,2,7,7,2,1,1,1,1,2,2,1,0,0,0,0,0),
                  (0,0,0,0,1,2,1,1,1,1,1,2,7,7,7,7,2,1,1,1,1,1,2,1,0,0,0,0),
                  (0,0,0,1,2,1,1,1,1,1,1,2,7,7,7,7,2,1,1,1,1,1,1,2,1,0,0,0),
                  (0,0,1,2,1,1,1,1,1,1,1,2,7,7,7,7,2,1,1,1,1,1,1,1,2,1,0,0),
                  (0,0,1,2,1,1,1,1,1,1,2,7,7,8,8,7,7,2,1,1,1,1,1,1,2,1,0,0),
                  (0,1,2,1,1,1,1,1,1,1,2,7,7,8,8,7,7,2,1,1,1,1,1,1,1,2,1,0),
                  (0,1,2,1,1,1,1,1,1,2,7,7,8,8,8,8,7,7,2,1,1,1,1,1,1,2,1,0),
                  (0,1,2,1,1,1,1,2,2,7,7,8,8,9,9,8,8,7,7,2,2,1,1,1,1,2,1,0),
                  (1,2,1,1,2,2,2,7,7,7,8,8,9,9,9,9,8,8,7,7,7,2,2,2,1,1,2,1),
                  (1,2,2,2,7,7,7,7,7,8,8,9,9,9,9,9,9,8,8,7,7,7,7,7,2,2,2,1),
                  (1,7,7,7,7,7,7,8,8,8,9,9,9,9,9,9,9,9,8,8,8,7,7,7,7,7,7,1),
                  (1,7,7,7,7,7,7,8,8,8,9,9,9,9,9,9,9,9,8,8,8,7,7,7,7,7,7,1),
                  (1,2,2,2,7,7,7,7,7,8,8,9,9,9,9,9,9,8,8,7,7,7,7,7,2,2,2,1),
                  (1,2,1,1,2,2,2,7,7,7,8,8,9,9,9,9,8,8,7,7,7,2,2,2,1,1,2,1),
                  (0,1,2,1,1,1,1,2,2,7,7,8,8,9,9,8,8,7,7,2,2,1,1,1,1,2,1,0),
                  (0,1,2,1,1,1,1,1,1,2,7,7,8,8,8,8,7,7,2,1,1,1,1,1,1,2,1,0),
                  (0,1,2,1,1,1,1,1,1,1,2,7,7,8,8,7,7,2,1,1,1,1,1,1,1,2,1,0),
                  (0,0,1,2,1,1,1,1,1,1,2,7,7,8,8,7,7,2,1,1,1,1,1,1,2,1,0,0),
                  (0,0,1,2,1,1,1,1,1,1,1,2,7,7,7,7,2,1,1,1,1,1,1,1,2,1,0,0),
                  (0,0,0,1,2,1,1,1,1,1,1,2,7,7,7,7,2,1,1,1,1,1,1,2,1,0,0,0),
                  (0,0,0,0,1,2,1,1,1,1,1,2,7,7,7,7,2,1,1,1,1,1,2,1,0,0,0,0),
                  (0,0,0,0,0,1,2,2,1,1,1,1,2,7,7,2,1,1,1,1,2,2,1,0,0,0,0,0),
                  (0,0,0,0,0,0,1,1,2,2,2,1,2,7,7,2,1,2,2,2,1,1,0,0,0,0,0,0),
                  (0,0,0,0,0,0,0,0,1,1,1,2,2,7,7,2,2,1,1,1,0,0,0,0,0,0,0,0),
                  (0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0));

const MaxBobs :   byte = 64;

type  BobMover  = record
                    positionx   : word;
                    positiony   : word;
                    lastx       : word;
                    lasty       : word;
                    firstspeedx : integer;
                    firstspeedy : integer;
                    lastspeedx  : integer;
                    lastspeedy  : integer;
                    bobscount   : byte;
                  end;

var BobSnake1,
    BobSnake2 : BobMover;

{$L SBASM}

procedure Grafik_Modus; assembler;
asm
  mov  ax,13h
  int  10h
end;

procedure Text_Modus; assembler;
asm
  mov  ax,03h
  int  10h
end;

procedure Neue_Palette; assembler;
asm
  mov  dx,3c8h
  xor  al,al
  out  dx,al
  inc  dx
  mov  cx,256
  xor  ah,ah

@loop1:
  xor  al,al
  out  dx,al
  mov  al,ah
  out  dx,al
  xor  al,al
  out  dx,al
  cmp  ah,63
  jae  @loop2
  inc  ah

@loop2:
  loop @loop1
end;

procedure Bob_setzen(x,y:word;matrix:pointer); external;

procedure Bob_loeschen(x,y:word;matrix:pointer); external;

procedure Bob_berechnen(bobrecord:pointer); external;

procedure Bob_bewegen;
begin

  bobsnake1.positionx:=10;
  bobsnake1.positiony:=10;
  bobsnake1.lastx:=10;
  bobsnake1.lasty:=10;
  bobsnake1.firstspeedx:=2;
  bobsnake1.firstspeedy:=-2;
  bobsnake1.lastspeedx:=2;
  bobsnake1.lastspeedy:=-2;
  bobsnake1.bobscount:=1;

  bobsnake2.positionx:=250;
  bobsnake2.positiony:=160;
  bobsnake2.lastx:=250;
  bobsnake2.lasty:=160;
  bobsnake2.firstspeedx:=-1;
  bobsnake2.firstspeedy:=2;
  bobsnake2.lastspeedx:=-1;
  bobsnake2.lastspeedy:=2;
  bobsnake2.bobscount:=1;

  repeat

    bob_setzen(bobsnake1.positionx,bobsnake1.positiony,@bobmatrix);
    bob_setzen(bobsnake2.positionx,bobsnake2.positiony,@bobmatrix);

    bob_berechnen(@bobsnake1);
    bob_berechnen(@bobsnake2);

    if bobsnake1.bobscount >= maxbobs then bob_loeschen(bobsnake1.lastx,
                                                   bobsnake1.lasty,
                                                   @bobmatrix);

    if bobsnake2.bobscount >= maxbobs then bob_loeschen(bobsnake2.lastx,
                                                   bobsnake2.lasty,
                                                   @bobmatrix);

  until keypressed;

  while keypressed do readkey

end;


begin

  Grafik_Modus;

  Neue_palette;

  Bob_bewegen;

  Text_Modus;

end.