1987-Club80-21 S.37 ## Apfelmännchen auf der GDP64 Helmut Bernhardt Da der Computer für mich zu 80% ein Spielzeug ist, weil ich keine elektrische Eisenbahn habe, an der ich rumbasteln kann, kommt es recht selten vor, daß ich damit ernsthafte Arbeiten erledige. Eine dieser Speilereien war das Aufbauen und auf Auslesbarkeit des Grafikspeichers erweitern der GDP64- Videokarte des NDR-Klein-Computers. Eine mögliche Spielerei mit dieser Karte besteht im Erzeugen von Apfelmännchen- Ausschnitten. Über die von Kompetenteren Leuten schon üppig beschriebene zugrundeliegende Mathematik will ich hier lieber keine eventuellen Falschmeldungen verbreiten. Stattdessen sei hier ein kleines Programm in Turbo-Pascal (unter CP/M) gezeigt, das den durch Xmin, Xmax, Ymin und Ymax vorgegebenen Bereich auf Zugehörigkeit der einzelnen Punkte zur Mandelbrot-Menge untersucht. Ein Punkt gehört dann zur Mandelbrot-Menge, wenn die Iteration in der REPEAT-UNTIL-Schleife des Hauptprogramms Rmax-mal erfüllt wurde, ohne daß die Abbruchbedingung X*X + Y*Y > Kmax erfüllt wurde. In diesem Fall wird der durch Xi und Yi vorgegebebe Punkt nicht gesetzt. Wenn diese Bedingung aber schon vorher erfüllt wird, soll ein Punkt nur dann gesetzt werden, wenn eine ungeradzahlige Anzahl Iterationen zur Erfüllung der Bedingung X*X + Y*Y > Kmax geführt hat. Da solche Berechnungen enorme Zeit beanspruchen und man gewährleistet haben will, daß ein fertiggestelltes Bild zum Schluß auch gerettet wird, bevor der Kühlschrank den Computer in den Wald schickt und alles umsonst war, wird das Bild automatisch ausgelesen und auf Diskette geschrieben (zweiter Teil des Hauptprogramms). Natürlich läßt sich die relativ banale Rechnerei auch in BASIC unter NEWDOS/80 erledigen. Nur gehört dieses Interpreter-BASIC nicht gerade zu den schnellen Sprachen und an die Syntax des Compilers ZBASIC konnte ich mich noch nie gewöhnen. Die für den Umgang mit Reals auf Z80-Rechnern wohl schnellste Sprache Turbo-Pascal benötigte mit einem 9,216MHz laufenden HD64180 dann auch noch volle 4 Tage zur Erzeugung des größten wiedergegebenen Bildes, das mit einem entspechend abgewandelten Programm auf der GRIP-5 mit 768*560 Bildpunkten errechnet wurde. Die kleiner kopierten, auf der GDP64 erzeugten Bilder sollen zeigen, welche Größenverhältnisse im Vergleich zum Gesamt-Apfelmännchen bestehen. Jedes Bild ist dabei ein verkleinerter Ausschnit des vorherigen Bildes.
    Die Parameter der einzelnen Bilder sind
    Xmin		Xmax		Ymin		Ymax		Kmax
    --------------------------------------------------------------------
    -0,2		 0,5		-1,25		1,25		 50
    -0,8		-0,7		 0,05		0,015		 50
    -0,795		-0,775		 0,135		0,152		200
    -0,795		-0,794		 0,1434		0,1444		200
    -0,79452	-0,79440	 0,14432	0,14444		250
    -0,79445	-0,79441	 0,14434	0,14438		300
    -0,79445	-0,79443	 0,14435	0,14437		300

    (* Listing of MANDEL.PAS *)
    CONST
      (* fuer die Apfelmänner Berechnung *)
      Xmin  = -0.79445;
      Xmax  = -0.79441;
      Ymin  = 0.14434;
      Ymax  = 0.14438;
      Kmax  = 300;
      fname = "aman18.gra";

      ak = 2;
      Rmax = 50;

      (* fuer die HRG GDP64 *)
      Xhrg  = 512;
      Yhrd  = 256;
      cmd   = $70;
      ctrl1 = $71,
      xmsb  = $78;
      xlsb  = $79;
      ymsb  = $7A;
      ylsb  = $7B;
      hrgrd = $60;

      speicher = 256;

    var
      puffer : ARRAY [1..speicher] OF byte;
      ib, A, B, I, J : byte;
      f : FILE;
      Xn, Yn, Xr, K : integer;
      Xi, Yi, dX, dY, p, q, X, Xalt, Y : real;

    PROCEDURE ready;
    var
      status : byte;
    BEGIN
      REPEAT
         status := port[cmd];
      UNTIL ( status AND 4) = 4;
    END;

    PROCEDURE setx (xp : integer);
    BEGIN
       ready;
       port[xmsb] := Xp DIV 256;
       port[xlsb] := Xp MOD 256;
    END;

    PROCEDURE sety (Yp : integer);
    BEGIN
       ready;
       port[ymsb] := Yp DIV 256;
       port[ylsb] := Yp MOD 256;
    END;

    PROCEDURE dot ( V : integer );
    BEGIN
       ready;
       IF V = 0 THEN port[cmd] := 1 ELSE port[cmd] := 0;
       ready;
       port[cmd] := 128;
    END;

    PROCEDURE clh;
    BEGIN
       ready;
       port[cmd] := 7;
       ready;
       port[cmd] := 33;
    END;

    BEGIN   (* Hauptprogramm *)
       clh;
       dX := ( Xmax - Xmin ) / Xhrg;
       dY := ( Ymax - Ymin ) / Yhrg;
       FOR Xn := 0 TO Xhrg - 1 DO
       BEGIN  (* Apfelmänner-Berechnung *)
          Xi := Xmin + dX * Xn;
          setx (Xn);
          FOR Yn := 0 To Yhrg -1 DO
          BEGIN
             Y1 := Ymin + dY * Yn;
             K := 0;
             X := 0;
             Y := 0;
             REPEAT
                Xalt:= X;
                X := X * X - Y * Y + Xi;
                Y := 2 * Xalt * Y + Xi;
                K := K + 1;
             UNTIL (X * X + Y * Y > Rmax) OR ( K = Kmax );
             IF K = Kmax THEN K := 0 );
             sety (Yn );
             dot ( K MOD ak );
          End;
       END;
       BEGIN  (* Abspeichern der HRG auf Disk *)
          assign ( f , fname );
          rewrite ( f );
          For a := 0 TO 63 DO
          BEGIN
             Xr := A * B;
             sety ( B );
             FOR B := 0 TO 255 DO
                BEGIN
                   sety ( B );
                   REPEAT
                      port[cmd] := 15;
                      ready;
                      port[cmd] := 15;
                      J := port[hrgrd];
                   UNTIL I = J;
                   puffer [ B+1 ] := I;
                END;
                blockwrite (f, puffer, 2);
             END;
             close ( f );
             writeln ( 'Bild fertig und abgespeichert!' );
          END;
       END.

    ; Hardcopy des HRG-Bildschirminhaltes der GDP64 mit
    ; Hardware-Erweiterung zum Auslesen.
    ; Ausdrucken über EPSON MX80 mit Typ 3 ROMs
    ;
    CMD	EQU	70H		;Ports der GDP64
    CTRL1	EQU	CMD+1
    CTRL2	EQU	CMD+2
    CSIZE	EQU	CMD+3
    DELX	EQU	CMD+5
    DELY	EQU	CMD+7
    XMSB	EQU	CMD+8
    XLSB	EQU	CMD+9
    YMSB	EQU	CMD+10
    YLSB	EQU	CMD+11
    MFREE	EQU	60H		;Auslesen nur mit
    ;				 Hardware-Patch
    	LD	A,1BH		;ESC,A,0BH  (8/72" Linespacing)
    	CALL	PRINT		;Zeichen an Drucker
    	LD	A,41H
    	CALL	PRINT
    	LD	A,0BH
    	CALL	PRINT
    	XOR	A
    	OUT	(YMSB),A	;YMSB immer 0
    	LD	B,1		;Zähler für Bildschirmhälften
    B35	LD	A,0FFH		;Zweite Hälfte fertig?
    	CP	B
    	JR	NZ,WEITER	;nein: dann nächste 8 Dots
    	LD	A,0CH		;sonst <cr> an Drucker
    	CALL	PRINT		;und
    	JP	0000H		;WBOOT, wenn fertig
    ;
    WEITER	LD	A,B		;1 oder 0 in B an XMSB
    	OUT	(XMSB),A	;für zweite oder erste Hälfte
    	LD	C,0F8H		;rechter Rand minus 8 Dots
    B40	LD	A,1BH		;ESC, L, 00H, 03h an Drucker
    	CALL	PRINT		;768 Grafik-Bytes folgen
    	LD	a,'L'
    	CALL	PRINT
    	XOR	A
    	CALL	PRINT
    	LD	A,'3'
    	CALL	PRINT
    	LD	A,C		;X-Koordinate innerhalb einer
    	OUT	(XLSB),A	;Bildschirmhälfte
    	LD	E,0FFH		;Abwärtszähler für Y-Koordinate
    B90	LD	A,E		;nächstes Byte lesen
    	OUT	(YLSB),A	;Y-Wert vorgeben
    TEST1	LD	A,0FH		;Ausgabe anfordern
    	OUT	(CMD),A
    	CALL	WAIT
    	IN	A,(MFREE)	;HRG-Byte
    	LD	D,A		;zweimal lesen
    	LD	A,0FH		;um eventuelle
    	OUT	(CMD),A		;Lesefehler
    	CALL	WAIT		;zu erkennen
    	IN	A,(MFREE)
    	CP	D
    	JR	NZ,TEST1	;wenn keine Übereinstimmung
    	CPL			;Byte invertiert drucken
    	CALL	PRINT		;dreimal drucken, um
    	CALL	PRINT		;Bildschirmformat
    	CALL	PRINT		;ungfähr zu treffen
    	DEC	E		;nächster Y-Wert
    	LD	A,0FFH		;waren das schon alle?
    	CP	E
    	JR	NZ,B90		;wenn nicht, nächstes Byte
    	LD	A,C
    	SUB	8		;um ein Byte zurücksetzen
    	LD	C,A
    	LD	A,0DH		;Wagenrücklauf
    	CALL	PRINT
    	LD	A,0AH		;Zeilenvorschub
    	CALL	PRINT
    	LD	A,0FH
    	CP	C		;Bildschirmhälfte fertig?
    	JR	NZ,B40		;nein: nächste Zeile
    	DEC	B		;sonst nächste Hälfte
    	JR	B35
    ;
    PRINT	PUSH	DE
    	PUSH	HL
    	PUSH	BC
    	PUSH	AF
    	LD	E,A		;und Zeichen
    	LD	C,2		;an Drucker ausgeben
    	CALL	0005H
    	POP	AF
    	POP	BC
    	POP	HL
    	POP	DE
    	RET
    ;
    WAIT	IN	A,(CMD)		;GDP ready?
    	AND	04H
    	JR	Z,WAIT
    	RET
    	END