... und dazu etwas Software

Arnulf Sopp

Wie nützlich ein Umbau am Computer ist, zeigt sich natürlich erst, wenn er etwas zu tun bekommt. Das folgende Programm ist nur ein Beispiel, was man mit dem Versechzehnfacher anfangen kann. Jedes andere Maschinenprogramm, sogar BASIC-, Pascal- oder sonstige höhere Programmtexte können dort untergebracht werden (1,2), natürlich auch Datenbytes für Tabellen und dergleichen. Damit ist das leidige Himem-Thema von Tisch; nahezu jede popelige BASIC-Verschönerung (eingerückte Zeilennummern und ähnlich überflüssiges) drängelt sich dort oben und verschleißt den Platz für wirklich Wichtiges.

Dieses Programm ist ein Treiber für die HRG 1b von RB-Elektronik. Er lädt selbsttätig BASIC/CMD und arbeitet anschließend im Hintergrund mit BASIC zusammen. Sein Ladebereich geht von 3000-32E4. Dahinter sind noch ein paar Bytes als Datenpuffer reserviert. Um beim Laden des Treibers nicht den DOS-Fehler "Ladeversuch auf ROM-Speicherplatz" serviert zu bekommen, muß dort natürlich RAM vorhanden sein. Der User gibt deshalb zuvor auf den Port F0 die Nummer eines Steckplatzes auf dem Versechzehnfacher aus, wo ein statisches RAM sitzt. Unter H-DOS geht das mit OUT F0,xx (7). Ansonsten kann man zunächst BASIC starten und dann OUT 240,xx anschließend CMD"S=HRG" eingeben (sofern man dieses Programm unter dem Namen HRG/CMD auf Disk stehen hat).

A propos H-DOS: Da der Befehl CMD > (mehr darüber weiter unten) das Parallel-RAM auf der CPU-Platine benutzt, müssen Besitzer des EG 64 MBA mit diesem DOS zuvor INI.N eingeben. Damit werden zwar die interessantesten Features von H-DOS disabled, aber noch immer hat der User alle G-DOS-Möglichkeiten und noch ein bißchen mehr. Auf allen Maschinen, mit denen Banking nicht möglich ist, funktioniert dieser Befehl ganz einfach nicht, ohne aber Schaden anzurichten oder zu einem Fehler zu führen.

Der Treiber stellt eine Reihe von Kommandos an die HRG zur Verfügung. Sie alle beginnen mit CMD (1). Um dem Interpreter anzuzeigen, daß es sich nicht um das gewohnte CMD handelt, folgt unmittelbar darauf nicht eine Variable oder ein Ausdruck zwischen Gänsefüßchen, sondern ein zweites BASIC-Token:

CMD +		: HRG einschalten
CMD -		: HRG ausschalten
CMD CLS		: HRG-Speicher löschen
CMD SET		: einen HRG-Punkt setzen
CMD RESET	: einen HRG-Punkt löschen
CMD POINT	: testen, ob ein HRG-Punkt gesetzt ist
CMD <		: HRG invertieren (weiß <-> schwarz)
CMD LPRINT	: HRG-Inhalt auf Drucker ausgeben (Hardcopy)
CMD ASC		: ASCII-Bildschirm in Hex anzeigen, bis neue Taste gedrückt
CMD >		: Bildschirm gegen Pufferinhalt austauschen
CMD LINE	: noch nicht programmiert, ergibt aber keinen Fehler

Nach der üblichen BASIC-Syntax können CMD und das zweite Token direkt oder durch Blank getrennt hintereinander stehen. Diese Befehle können im Direktmodus und als Bestandteil eines Programms eingegeben werden.

Die drei erstgenannten HRG-Befehle bedürfen keiner näheren Erläuterung. CMD SET, CMD RESET und CMD POINT haben eine ganz ähnliche Syntax wie die gewohnten Befehle zur Ansteuerung der Genie-Pixelgraphik. Im Argument sind im Unterschied dazu jedoch Koordinaten im Bereich 0-383 für X und 0-191 für Y zulässig, entsprechend der feineren HRG-Matrix. Die Koordinaten können wie in Level 2 oder Disk-BASIC auch durch Variable dargestellt werden.

CMD < macht aus jedem Punkt im HRG-Speicher sein Komplement. Gesetzte Punkte werden dunkel, nicht gesetzte werden eingeschaltet. Es entsteht eine negative Darstellung. Der normale ASCII-Bildschirm bleibt hiervon unberührt.

Bei einem Bildschirmausdruck der HRG mit CMD LPRINT wird der Drucker zunächst in den Einschaltzustand versetzt (Reset aller Druckparameter). Danach wird der linke Rand auf die 9. Stelle gesetzt, um das Bild zu zentrieren. Der Zeilenabstand wird mit 6/72" so eingestellt, daß die Druckzeilen lückenlos untereinander stehen. Nach getaner Arbeit werden diese Steuercodes alle wieder gelöscht; der Drucker ist wieder im Einschaltzustand. Diese Codes gelten für den Star Gemini-10X. Für andere Printer müssen sie entsprechend geändert werden. Von den vergleichbaren Epson-Typen ist mir bekannt, daß für die Randeinstellung lediglich in ESC M 09 aus dem "M" ein "1" gemacht zu werden braucht. Die übrigen Codes sind identisch.

Der Befehl CMD ASC ist für vielerlei Verwendungen interessant. Mit ihm hat der Programmierer sozusagen immer eine ASCII-Tabelle auf dem Bildschirm. Die ASCII-Zeichen werden als zweistellige Hexzahlen dargestellt (4). So werden gleiche Zeichen mit verschiedenen Codes unterscheidbar, um nur eine Anwendung zu nennen: Die beiden Blanks mit den Codes 32 und 128 sowie die Graphikblocks 128-191 und 192-255 sind als Hexzahlen eindeutig zu identifizieren. Bei der Ausführung von CMD ASC werden die 32er Blanks übrigens nicht mit umgewandelt, sondern als Leerzeichen belassen, um den Bildschirm übersichtlich zu halten.

Dabei wird der normale ASCII-Bildschirm natürlich gelöscht, sonst würde er stören. Der Treiber rettet ihn in den HRG-Speicher, so daß -er nach dem Druck auf irgendeine Taste wieder restauriert werden kann. Ein besonderer Puffer im RAM ist dafür nicht erforderlich.

Nach diesem Schema geht auch der Befehl CMD > vor. Zunächst wird der Bildschirm in die HRG gerettet. Von ihr sind nämlich nur 6 Bits pro Byte sichtbar, die beiden höchstwertigen Bits sind unbenutzt und können den Bildschirm aufnehmen. Dabei wird der sichtbare Inhalt des HRG-Speichers nicht beeinträchtigt. Alle Graphiken bleiben also erhalten. Im weiteren Verlauf der Ausführung dieses Befehls wird nun der Inhalt der HRG, also Graphik und ASCII, in einen Puffer gerettet, und der Inhalt dieses Puffers geht dafür in die HRG.

Die beiden höchstwertigen Bits des neuen HRG-Inhalts werden in den ASCII-Bildschirm übertragen. Es ist demnach ein Austausch Bildschirm gegen Puffer. In diesem Treiber liegt der Puffer im Adreßbereich ab 0000. Das ist natürlich nur mit dem EG 64 MBA oder einem anderen Banker realisierbar.

Entsprechende Änderungen, um stattdessen das gute alte Himem dafür zu benutzen, sind kein Problem.

Der Befehl CMD LINE soll eines fernen Tages, wenn der Autor mal wieder Lust hat, an dem Treiber weiterzuarbeiten, Linien, Rechtecke usw. ziehen. Der Leser möge mir nachsehen, daß die Computerei mein Hobby ist, bei dem ich gnadenlos dem Lustprinzip folge (6).

An diesem fernen Tage werden wohl noch ein paar andere Modifikationen folgen, die es ermöglichen. den HRG-Treiber fest in ein EPROM zu brennen. Das ist mit dieser Version nicht möglich, denn das Programm vollzieht Schreibzugriffe in seinem eigenen Adreßraum. Dazu gehören z. B. die Datenpuffer an seinem Ende, aber auch variable Sprungdistanzen mitten im Programm (Selbstmodifikation). Der Vorteil dieser Variante ist freilich, daß der Treiber mit den Bedürfnissen jederzeit mitwachsen kann. Immerhin sind noch eineinviertel kB frei!

Auf die Programmlogik möchte ich an dieser Stelle nicht eingehen. Die siebeneinhalb Seiten Listing wären halbwegs erschöpfend wohl nicht mit weniger als 15 Seiten Test erklärbar. Insbesondere diejenigen Features, die kein anderer mir bekannter HRG-Treiber zur Verfügung stellt, würden einige Seiten füllen: Z. B. die Umwandlung des ASCII-Bildschirms in die Hexdarstellung und das Puffern desselben im HRG-Speicher. Der Maschinensprache-Freak mag sich dabei amüsieren, sich in dem sehr ausführlich kommentierten Listing selber zurechtzufinden.

Zu diesem Thema sind an gleicher Stelle auch bereits ein paar Beiträge erschienen, die die Arbeit deutlich erleichtern werden (5 u.a.).

Nur einige wenige Kommentare, ohne die sich sogar der Autor kaum noch im Programm zurechtfindet, sollen angefügt sein: In BASIC/CMD steht nach dem Laden (also noch vor dem Ansprung!) an 67DD der CMD-Vektor (JP 57FF). Er wird durch JP cmd (3074) ersetzt. Andere Treiber benutzen kein bereits vorhandenes Token und verlangsamen damit den ganzen Computer: es muß bei jeder Eingabe geprüft werden, ob ein vorangestelltes Doppelkreuz o. dergl. ein Syntaxfehler oder die Einleitung eines HRG-Befehls ist. An der Stelle 64F3 wird HL als Zeiger auf das BASIC-Helle geladen. Mit der Änderung des LSB von 5C auf 5E werden die beiden ersten Codes, die den Bildschirm löschen, übergangen. So bleibt die oberste Titelzeile erhalten, die beim Label hello steht.

Beim späteren Programmablauf wird der Treiber nur dann angesprungen, wenn das CMD-Token angetroffen wurde. Nun prüft er, was folgt. In Disk-BASIC ist es immer ein Anführungszeichen oder ein Variablenname. Diese Zeichen liegen im Bereich bis 7F. Der Vergleich mit 80 beim Label cmd gibt deshalb Aufschluß, ob zur Ansteuerung der HRG ein weiteres Token folgt. Falls nein, geht es in der alten CMD-Routine weiter, falls ja, kommt der Treiber jetzt so richtig in Fahrt.

Anwender, die mit EDTASM/CMD oder ASM/CMD arbeiten. müssen auf die für diese Assembler zulässige Syntax achten; Labels dürfen höchstens 6 Zeichen lang sein, Kleinbuchstaben sind nur in den Kommentaren erlaubt, DB, DW und DM müssen als DEFB, DEFW und DEFM ausgeschrieben werden.

Bei diesen Statements dürfen auch nicht mehrere Argumente in derselben Zeile stehen, schon gar nicht DEFM und DEFB gemischt. Je eine eigene Zeile muß dafür eingerichtet werden.

Dieser HRG-Treiber ist, wie gesagt, lediglich eine Demonstration dafür, was mit Helmut Bernhardts Versechzehnfacher so alles anzufangen ist. Die Platine funktioniert selbstverständlich ohne HRG, auch ohne DOS ebenso gut wie mit. Vielleicht fällt einem von euch für eins der nächsten Infos eine sinnvolle Verwendung für Level 2 ein?

Literatur:

1) "PUT TO - ein neuer BASIC-Befehl", 4/1984
2) "Bank Selection mit dem Genie I", 5/1985
3) "Neuer DOS-Befehl: OUT port#,xx,yy,...", 11/1984
4) "VIDHEX - Hexanzeige des Bildschirms mit der HRG", 9/1985
5) "Die HRG 1b programmieren", 11/1984
       (alle von A. Sopp im Club-Info des Genie/TRS80-User-Club Bremerhaven, Ausgabe jeweils angegeben).
6) R. Goscinny, M. Uderzo: "Asterix und der Kupferkessel", Dargaud S. A. 1969


		00001 	;
		00002 	;
		00003	; BASIC-Treiber für die HRG 1b von RB-Elektronik
		00004	;
		00005	; Demo-Programm zum Speicher-Versechzehnfacher
		00006	; im Adreßraum 3000-370F von Helmut Bernhardt
		00007	;
		00008	;	(C)	Arnulf Sopp
		00009	;
		00010 	;
		00011	
3000		00012		ORG	3000h		;im Sonder-ROM-Bereich
		00013	
		00014	;DOS-Eingabepuffer retten
3000	11E432	00015	finit	LD	DE,cmdbuf	;Puffer für Aufrufbefehl
3003	014800	00016		LD	BC,0048h	;ca. Lng. DOS-Eing.-puff.
3006	E5	00017		PUSH	HL		;Aufrufbefehl retten,
3007	D5	00018		PUSH	DE		;weil 4419 den Puffer-
3008	C5	00019		PUSH	BC		;Inhalt verändert
3009	EDB0	00020		LDIR			;zwischenspeichern
		00021
		00022	;Initialisierungen in BASIC/CMD
3008	212C30	00023		LD	HL,command	;BASIC-Ladekommando
300E	CD1944	00024		CALL	4419h		;BASIC/CMD laden
3011	217430	00025		LD	HL,cmd		;neuer CMD-Vektor
3014	22DD67	00026		LD	(67ddh),HL	;in BASIC/CMD laden
3017	3E5E	00027		LD	A,5eh		;LSB des BASIC-Logo
3019	32F464	00028		LD	(64f4h),A	;CLS verhindern
301C	213830	00029		LD	HL,hello	;HRG-Logo
301F	CD6744	00030		CALL	4467h		;anzeigen
3022	C1	00031		POP	BC		;Länge Eingabepuffer
3023	E1	00032		POP	HL		;Aufrufbefehl
3024	D1	00033		POP	DE		;Adresse Eingabepuffer
3025	D5	00034		PUSH	DE		;brauchen wir gleich
3026	EDBO	00035		LDIR			;Befehl restaurieren
3028	E1	00036		POP	HL		;Befehlserweit. oder CR
3029	C3BE66	00037		JP	66beh		;BASIC-Kaltstart
		00038	
		00039	;DOS-Befehl, um BASIC in den Speicher zu laden
302C	6C	00040	command	DM	'load,basic/cmd',0dh
		00041
		00042	;neue 1. Zeile des BASIC-Hello
3038	1C	00043	hello	DM	1ch,1fh,'H R G	1 b - Utility von	'
3056	54	00044		DM	'The HACKTORY Arnulf Sopp für',Oah,0dh
		00045	
		00046	;BASIC-Erweiterung für HR-Graphikbefehle
3074	FE80	00047	cmd	CP	80h		;Graphik-CMD-Befehl?
3076	DAFF57	00048		JP	C,57ffh		;norm. weiter,	falls nein
		00049	
		00050	;Es ist ein HRG-Befehl. Erkennen und ausführen:
3079	FED4	00051		CP	0d4h		;Bildschirm austauschen?
307B	2029	00052		JR	NZ,CLS		;falls nein
		00053
		00054	;CMD >:	Bildschirm gegen Pufferinhalt austauschen
307D	E5	00055		PUSH	HL		;Befehlszeiger
307E	CD5332	00056		CALL	vidsav		;Bildschirm retten
3081	F3	00057		DI			;bloß keine Störungen!
3082	3E08	00058		LD	A,8		;RD RAM 0000-2FFF
3084	D3DF	00059		OUT	(0dfh),A	;auf Banking-Port ausg.
3086	3C	00060		INC	A		;WR RAM 0000-2FFF
3087	D3DF	00061		OUT	(0dfh),A	;dto.
3089	65	00062		LD	H,L		;HL <- 0000, Pufferadr.
308A	55	00063		LD	D,L		;DE <- 00xx, HRG-Adresse
3088	50	00064		LD	E,L		;DE <- 0000
308C	0E30	00065			LD	C,30h	;Konst. HRG-MSB
308E	CD4B32	00066	swaplop CALL	HRGadr		;HRG-Stelle adressieren
3091	DB04	00067		IN	A,(4)		;HRG-Byte laden
3093	46	00068		LD	B,(HL)		;Pufferbyte holen
3094	77	00069		LD	(HL),A		;HRG-Byte puffern
3095	78	00070		LD	A.B		;Pufferbyte
3096	0305	00071		OUT	(5),A		;auf HRG ausgeben
3098	23	00072		INC	HL		;Pufferzeiger erhöhen
3099	7A	00073		LD	A,D		;überprüfen, ob
309A	89	00074		CP	C		;HkG-Bereich überschr.?
3098	38F1	00075		JR	C.swaplop	;falls nein
309D	DBDF	00076		IN	A,(0dfh)	;Banks rücksetzen
309F	FBI	00077		EI			;INTs wieder zulassen
30A0	CD5532	00078		CALL	savrest		;Bildsch. restaurieren
30A3	E1	00079		POP	HL		;Befehlszeiger
30A4	1831	00080		JR	exit1		;fertig
		00081		
		00082	;CMD CLS: HRG-Speicher löschen	
30A6	FE84	00083 	CLS	CP	84h		;CLS?
30A8	2004	00084		JR	NZ,INV		;falls nein
30AA	1E00	00085 	clear	LD	E,0		;Flag für HRG-CLS
30AC	1806	00086		JR	clsinv		;dort weiter
		00087		
		00088 	;CMD <: HRG invertieren (positiv -> negativ)
30AE	FED6	00089 	INV	CP	Od6h		;invertieren?
3080	2027	00090		JR	NZ,LINE		;falls nein
3082	1EFF	00091		LD	E,0ffh		;Flag für Inversion
3084	010330	00092 	clsinv	LD	BC,3003h	;8 = MSB 12kB, C = Port 3
3087	C5	00093 	msloop	PUSH	BC		;retten
30B8	05	00094		DEC			;B um 1 zu hoch
30B9	ED41	00095		OUT	(C),B		;MSB HRG-Adresse
3088	0600	00096		LD	B,0		;B <- 0 für HRG-LSB
30BD	0D	00097		DEC	C		;Port 2 für LSB
308E	ED41	00098 	lsloop	OUT	(C),B		;LSB HRG-Adresse
3000	DB04	00099		IN	A,(4)		;HRG-Byte holen
30C2	F5	00100		PUSH	AF		;retten
30C3	E6C0	00101		AND	0c0h		;obere Bits isolieren
3005	57	00102		LD	D,A		;und retten
3006	F1	00103		POP	AF		;HRG-Byte
3007	2F	00104		CPL			;invertieren
3008	E63F	00105		AND	3fh		;obere Bits ausmaskieren
30CA	CB7B	00106		BIT	7,E		;CLS oder INV?
30CC	2001	00107		JR	NZ,outa		;falls INV
30CE	AF	00108		XOR	A		;sonst löschen
30CF	82	00109 	outa	OR	D		;obere Bits hinzufügen
3000	0305	00110		OUT	(5),A		;Blank od. Kompl. ausgeb.
3002	10EA	00111		DJNZ	lsloop		;LSB: 00, FF, FE ... 01
3004	C1	00112		POF	BC		;MSB und Port für MSB
3005	10E0	00113		DJNZ	msloop		;MSB-1:	2F ... 00
		00114
		00115 	;Rückkehr für mehrere Unterprogramme	
3007	23	00116 	exit1	INC	HL		;Befehlszeiger nachst.
3008	C9	00117		RET			;erledigt
		00118		
		00119 	;CMD LINE:	(bisher nicht programmiert)
3009	FE9C	00120 	LINE	CP	9ch		;LINE?
3008	28FA	00121		JR	Z,exit1		;vorl. nicht implement.
		00122
		00123 	;CMD 4:	HRG-Speicher in den Bildschirm einblenden
3000	FECD	00124		CP	Ocdh		;HRG einschalten?
30DF	2004	00125		JR	NZ,HRGoff	;falls nein
30E1	0301	00126		OUT	(1),A		;einschalten
30E3	18F2	00127		JR	exit1		;fertig
		00128
		00129 	;CMD -	HRG-Speicher aus dem Bildschirm ausblenden
30E5	FECE	00130 	HRGoff	CP	Oceh		;HRG ausschalten?
30E7	2004	00131		JR	NZ,LPRINT	;falls nein
30E9	0300	00132		OUT	(0),A		;ausschalten
30EB	18EA	00133	JR	exit1			;fertig	
30ED	FEAF	00134	
30EF	2066	00135 ;CMD LPRINT: Hardcopy des HRG-Speichers	
		00136 LPRINT	CP	0afh		;LPRINT (Hardcopy)?
		00137		JR	NZ,ASC		;falls nein
		00138	
		00139 ;LPRINT;	Drucker initial.: Reset, 6/72" Zeilenabstand
30F1	E5	00140		PUSH	HL		;Befehlszeiger	retten
30F2	210632	00141		LD	HL,prestor+1	;Druckerinitialisierung
30F5	0609	00142		LD	B,9		;mit 9 Codes
30F7	CDFC31	00143		CALL	lprint		;Ausgabe auf Drucker
		00144	
		00145 ;HRG-Zeiger laden, 16 (Doppel-)Zeilen vorbereiten
30FA	50	00146		LD	D,B		;DE <- 00xx
30FB	58	00147		LD	E,B		;DE <- 0000, Start HRG
30FC	010610	00148		LD	BC,1006h	;16 Zeilen, Konst. 6
		00149	
		00150 ;1 Doppelzeile zu je 6 Dotzeilen drucken
30FF	C5	00151 scrnlop	PUSH	BC		;Zähler retten
3100	D5	00152		PUSH	DE		;dto. HRG-Zeiger
3101	0602	00153		LD	B,2		;2 Halbzeilen/Zeile
3103	C5	00154 linelop PUSH	BC		;wird verändert
3104	D5	00155		PUSH	DE		;dto. HRG-Zeiger
3105	21DF32	00156		LD	HL,lninit	;Druckerinit. für 1 Zeile
310B	0605	00157		LD	B,5		;mit 5 Codes
310A	CDFC31	00158		CALL	lprint		;Ausgabe
3100	21E432	00159		LD	HL,buffer	;Puffer für Druckercodes
3110	0640	00160		LD	B,40h		;64 Bytes/Zeile
		00161	
		00162 ;1 Halbzeile drucken	
3112	C5	00163 hlinlop	PUSH	BC		;Zähler retten
3113	D5	00164		PUSH	DE		;dto.	HRG-Zeiger
3114	78	00165		LD	A,E		;LSB des HRG-Zeigers
3115	D302	00166		OUT	(2),A		;auf HRG ausgeben
3117	41	00167		LD	B,C		;6 Bytes senkrecht
		00168	
		00169 :1 Byte drucken	
3118	C5	00170 bytelop	PUSH	BC		;wird verändert
3119	7A	00171		LD	A,D		;MSB des HRG-Zeigers
311A	0303	00172		OUT	(3),A		;auf HRG ausgeben
311C	DB04	00173		IN	A,(4)		;Dotzeile aus HRG
311E	41	00174		LD	B,C		;6 Dots/Stelle
311F	E5	00175		PUSH	HL		;retten
		00176	
		00177 ;6mal 1 Bit errechnen	
3120	0F	00178 bitlop	RRCA			;Cy <- HRG-Bit
3121	CB16	00179		RL	(HL)		;nächstes Pufferbit <- Cy
3123	CBB6	00180		RES	6,(HL)		;nur untere Bits
3125	23	00181		INC	HL		;nächstes Pufferbyte
3126	10F8	00182		DJNZ	bitlop		;bis 6 Dots gepuffert
		00183	
		00184 ;6 Bits fertig - 6 Bytes vervollständigen	
3128	14	00185		INC	D		;MSB auf nächste Dotzeile
3129	14	00186		INC	D		;= um 1 kB erhöhen)
312A	14	00187		INC	D	
3120	14	00188		INC	D	
312C	E1	00189		POP	HL		;Pufferzeiger
312D	C1	00190		POP	BC		;Zähler
312E	10E8	00191		DJNZ	bytelop		;bis 1 Stelle im Puffer
		00192	
		00193 ;6 Bytes ausdrucken und weiter mit Halbzeile	
3130	E5	00194		PUSH	HL		;wird verändert
3131	41	00195		LD	B,0		;6 Dotspalten
3132	CDFC31	00196		CALL	lprint		;ausgeben
3135	E1	00197		POP	HL		;Pufferzeiger
3136	D1	00198		POP	DE		;alter HRG-Zeiger