;-----------------------------------------------------------------
; Angepasst für ELZET80 CPU/IEC Baugruppe
; Franz Lange
; 17.11.2020
;-----------------------------------------------------------------
; 25.11.2020, 21:30h - Testroutinen ohne Stack
; 29.11.2020, 22:55h - Memory Adress Test FC00-FFFF
; 30.11.2020, 10:50h - Neue Kommandos, Input, Output, Clear Memory
; 01.12.2020, 13:35h - SIO-Programming, Memory-Test
; 02.12.2020, 10:20h - HEX -> ASCII
; 03.12.2020; 21:10h - Debug Minimon
; 04.12.2020; 21:50h - Basis-Adresse ist F000H, nicht E000 wie im Schaltplan
; 07.12.2020; 17:35h - Check ELZET80 FDC
; 08.12.2020; 17:35h - Check Memory on ELZET80 FDC
; 09.12.2020; 11:00h - Erweiterung Minimon-Kommandos
; 10.12.2020; 23:25h - Memory-Test-Kommando
; 11.12.2020; 10:20h - LOW Memory + EPROM
;-----------------------------------------------------------------
; Link
: https://archive.org/stream/ct8312/ct8312_djvu.txt
;
; c’t 1983, Heft 12 
;
; MINIMON 
;
; Kurzes Monitorprogramm für Z80-Rechner 
;
; Andreas Burgwitz 
; Dieses kleine Maschinenprogramm bietet die wichtigsten Funktionen, 
; die ein Monitorprogramm haben sollte. MINI- MON belegt nur 605 Bytes, 
; umfaßt aber fünf wesentliche Befehle. Da das Programm nur die Betriebssystemroutinen 
; Tastaturabfrage und Bildschirmausgabe verwendet, dürfte es sich leicht für verschiedene 
; Z80-Rechner anpassen lassen. 
;
; Bei der Programmierung in Maschinensprache benötigt man ein Hilfsprogramm, das es er- 
; laubt, Daten in einzelne Speicherzellen zu schreiben und wieder herauszulesen. MINI- 
; MON bietet diese Möglichkeiten. Als Befehle stehen zur Verfügung: 
;
; MODIFY (M) 
;
; Sichten und Ändern des Inhalts einer Speicherzelle 
;
; ## TABULATE (T) ## umbenannt in DISPLAY (D)
;
; Auflistung der Hex-Werte eines Speicherbereichs 
;
; JUMP (J) 
;
; Sprung zu angegebener Adresse 
;
; ASCII (A) 
;
; Auflistung der ASCII- Werte eines Speicherbereichs 
;
; BREAKPOINT (B) 
;
; Setzen und Löschen eines Haltepunktes 
; Das Monitorprogramm, im folgenden kurz Monitor genannt, benutzt zwei Routinen des 
; Rechnerbetriebssystems. Diese Routinen dienen zur Ausgabe eines Zeichens auf den Bild- 
; schirm sowie zur Abfrage der Tastatur. Da aber beide Programme grundsätzlich in jedem 
; Rechner vorhanden sind, dürfte die Anpassung des Programms an den verwendeten 
; Computer keine Probleme bereiten. Nähere Hinweise zur Anpassung und Modifikation 
; des Programms stehen unter dem Abschnitt ‘Modifikationen’. Das Programm ist modu- 
; lar aufgebaut. Diese Struktur erlaubt eine Erweiterung, um beliebige Befehle sowie die Ver- 
; wendung von Unterprogrammen des Monitors durch andere Programme. 
;
; Neue Kommandos:
;
; INPUT (I) 
; I (I/O-Adresse)
;
; OUTPUT (O) 
; O (I/O-Adresse) (Datum)
;
; MEMORY PAGE (P) 
; P (PAGE) {0 - F}
;
; CLEAR MEMORY (C) 
; C (Anfangsadresse) (Endadresse)
;
; TESTE MEMORY (T) 
; T (Anfangsadresse) (Endadresse)
;
; Die Struktur des Programms 
;
; Der Monitor besteht im wesentlichen aus zwei großen Blöcken. Der eine Block ent- 
; hält mehrere Module, die zum Teil von anderen Programmen als Unterprogramme verwendet 
; werden können. Der andere Block enthält die Befehlsroutinen. Diese enden alle mit "RETURN", 
; so daß sie ebenfalls von anderen Programmen auf gerufen werden können. 
; 
; Nach dem Start des Monitors erfolgt die Initialisierung. Dabei wird zuerst der Stack defi- 
; niert. Danach löscht die CPU einen Speicherbereich, der als Buffer für die Tastatureingabe 
; dient. Der Computer meldet sich dann mit dem Zeichen ‘ # ’ und fragt anschließend die Ta- 
; statur mittels des Unterprogramms KBIN ab. Dieses Programm wartet solange auf Zei- 
; chen von der Tastatur, bis der Benutzer ein Carriage Return eingibt. Alle zuvor eingegebe- 
; nen Zeichen stehen in dem BUFF genannten Speicherbereich. Wird diese Routine von 
; einem anderen Programm aufgerufen, kann als Einsprung KBIN 1 gewählt werden, da 
; dann der Anfang des Buffers durch den Inhalt des Registers HL bestimmt ist. Nach der Ein- 
; gabe eines Befehls durchsucht das Programmodul EXEC eine Befehlstabelle, wobei nur das 
; erste eingegebene Zeichen mit denen in der Tabelle verglichen wird. Die Tabelle enthält den 
; Befehlsbuchstaben, gefolgt von der Einsprungsadresse der Befehlsroutine. Ergibt der Ver- 
; gleich des eingegebenen Zeichens mit denen in der Tabelle keine Gleichheit, findet EXEC 
; das Endzeichen der Tabelle (FF Hex). Das bewirkt, daß die CPU zu der Eingabeschleife zu- 
; rückspringt. Ist das eingegebene Zeichen identisch mit einem der Tabelle, legt das Programm 
; JEXE die Rücksprungadresse des Monitors auf den Stack und verzweigt zu der Befehls- 
; routine. Die weiteren Programmodule dienen der ASCII-HEX-Wandlung (AHEX) und 
; dem Gewinnen der Befehlsargumente (GETA). Das Programm PRHEX druckt den Akkuinhalt in hexadezimaler 
; Form — eine Funktion, die man in verschiedenen Programmen häufig braucht. 
;
; DAS ARBEITEN MIT DEM MONITOR
;
; Der Befehl MODIFY dient dem Sichten und Verändern des In-
; halts einer Speicherzelle. Die Eingabe des Befehls erfolgt in der Form: 
;
; M (Adresse) 
;
; Angezeigt werden die Speicheradressen sowie der Inhalt dieser Zelle. Der Cursor steht hinter 
; dem Datum. Man kann jetzt entweder ein neues Byte eingeben, was sofort in der angezeig- 
; ten Speicherzelle abgelegt wird, oder durch Drücken der CR- Taste zur nächsten Speicherzel- 
; le weitergehen, wobei der Speicherinhalt nicht verändert wird. Zu dem Monitor kann 
; man durch Eingabe eines ',' und Drücken der CR-Taste zurückkehren. 
;
; Der Befehl ## TABULATE ## DISPLAY bewirkt die Anzeige eines Speicherbereichs in hexadezimaler 
; Form (Hexdump). Die Form dieses Befehls ist: 
;
; ( T Startadresse Endadresse) - alt 
; 
; D (Startadresse) (Endadresse) - neu
;
;
; Angezeigt wird am Anfang jeder Zeile die jeweilige Speicheradresse, danach folgen (acht) sechzehn 
; Datenbytes. Die Anzeige kann jederzeit durch Drücken der Leertaste angehalten und wie- 
; der fortgesetzt werden. Ist die Anzeige nicht gestoppt, kann man auch hier vor Erreichen 
; der eingegebenen Endadresse durch die Eingabe von ',' zum Monitor zurückkehren. 
; 
; Das gleiche Format wie (TABULATE) DISPLAY verwendet der Befehl ASCII, wobei anstelle der 
; hexadezimalen Darstellung der Speicherinhalt in ASCII-Zeichen angezeigt wird. Zeichen 
; die nicht gedruckt werden können, werden durch ein Leerzeichen ersetzt. 
; 
; Der Befehl JUMP setzt den Programmcounter auf die angegebene Adresse, was den 
; Sprung zu einem dort beginnenden Programm bedeutet. 
; Die Form des Befehls ist: 

; J (Startadresse des Programms) 
; Der Monitor bietet die Möglichkeit einen Software - BREAKPOINT zu setzen. 
; Die Form ist dabei: 
;
; B (Breakadresse) 
;
; Die Adresse, auf die der Breakpoint gesetzt werden soll, muß immer das erste Byte eines 
; Maschinenbefehls sein. Dieser Befehl wird durch eine drei Byte lange Sequenz ‘Call BREAK’ 
; ersetzt. Der ursprünglich an dieser Stelle stehende Befehl wird in einem Buffer des Moni- 
; tors gesichert. 
; Durch die Eingabe von: 
; B Taste CR drücken werden die drei Byte ‘Call BREAK’ wieder gegen die alten 
; Daten ausgetauscht. Wird beim Lauf des Programms die Break-Sequenz erreicht, über- 
; nimmt der Monitor die Werte der Z80-Register und zeigt sie in der Form 
; Register Wert 1 (Wert 2) an. Wert 1 steht für den Inhalt des Registers (Anzeige Hexade- 
; zimal). Wert 2 zeigt den Inhalt der Speicherzelle an, die durch das Register adressiert sein 
; könnte. Auch diese Daten werden in hexadezimaler Form dargestellt. Nach der Anzeige 
; aller Register wartet der Monitor auf die Eingabe weiterer Befehle. 
;
; Das Monitorprogramm akzeptiert die Befehlseingabe auch dann, wenn zwischen dem Be- 
; fehlsbuchstaben und dem ersten Argument kein Leerzeichen steht. Zwischen zwei Ar- 
; gumenten ist das Leerzeichen jedoch unabdingbar. 
;
; Modifikationen 
;
; Der Monitor wurde für einen TRS-80 geschrieben, verwendet aber keine schwierig adaptier-
; baren Routinen des Betriebssystems.  
; Soll das Programm auf anderen Computertypen laufen, müssen folgende System- 
; definitionen beachtet werden: 
;
;	1: KBDM, Eine einmalige Abfrage der Tastatur. 
; 	Das Zeichen steht im Akku. 
; 	Wurde keine Taste gedrückt, ist der Akku ‘ 0 ’. 
;
;	2: KBD Abfrage der Tastatur, bis ein Zeichen eingegeben wird, 
;	sonst wie KBDM. Diese Routine muß nicht dem Betriebssystem entnommen werden
;	man kann sie unter Verwendung von KBDM selbst schreiben. 
;
;	3: CRT Ausgabe des Akkuinhalts auf den Bildschirm 
;	unter Berücksichtigung der Steuerzeichen. 
;
; Das Zeichen CON bewirkt beim TRS-80, daß der Cursor ‘eingeschaltet’, das heißt sicht- 
; bar ist. Dieses Zeichen wird nur einmal bei der Initialisierung des Monitors ausgegeben. 
;
; Der Speicherbereich, in dem der Monitor liegt, kann unabhängig von dem Bereich des 
; Buffers verändert werden. Das Programm läßt sich aber nicht frei im Speicher verschieben.
;
; Das Programmlisting 
;
;--------------------------------------------------
; MINI-MONITOR FUER Z80
; 	VON 
; A. BURGWITZ 
;--------------------------------------------------
; Angepasst a TASM
;----------------------------------------------------------------------
#define	EQU	.equ		; for TASM
#define	DB	.byte		; for TASM
#define	DW	.word		; for TASM
#define	DS	.block		; for TASM
#define	ORG	.ORG		; for TASM
#define	END	.end		; for TASM
#define	PAGE	.page		; for TASM
#define	TITLE	.title		; for TASM
;----------------------------------------------------------------------
; Angepasst an ELZET 80 CPU/IEC und ELZET80 FDC-3 mit 2 x 64K DRAM
;
; Nur mit ELZET 80 CPU/IEC mit integriertem 2K SRAM
; liegt der Monitor im Adressbereich F000 - F7FF
;----------------------------------------------------------------------
#define	CPUIEC	1		; Zielhardware = ELZET80-IEC-CPU
#define	INTRAM	1		; IEC-CPU uses internal RAM AT F000H
#define	FDC_03	1		; ELZET80-IEC-CPU + FDC3 mit 128 MB RAM
;----------------------------------------------------------------------
; 
; S Y S T E M D E F I N I T I O N E N 
; 
;----------------------------------------------------------------------
;		NUR TRS-80
;		für ELZET80 nicht relevant
;
; KBDM	EQU	002BH		; EINMALIGE TASTATURABFRAGE 
; KBD	EQU	0049H		; TASTATURABFRAGE BIS EINGABE 
; CRT	EQU	0033H		; ZEICHEN IN AKKU AUF SCHIRM GEBEN 
;----------------------------------------------------------------------
;		ELZET80 CPU/IEC CPU-Baugruppe
SIOA_DAT	EQU	04H		; SIO/2-A - Data Register
SIOB_DAT	EQU	05H		; SIO/2-B - Data Register
SIOA_CTL	EQU	06H		; SIO/2-A - Control Register
SIOB_CTL	EQU	07H		; SIO/2-B - Control Register
;----------------------------------------------------------------------
;
SIO_CH_RST	EQU	18H		; Z80 SIO Channel RESET
SIO_WR0		EQU	00H		; Z80 SIO Write Register 0
SIO_WR1		EQU	01H		; Z80 SIO Write Register 1
SIO_WR3		EQU	03H		; Z80 SIO Write Register 3
SIO_WR4		EQU	04H		; Z80 SIO Write Register 4
SIO_WR5		EQU	05H		; Z80 SIO Write Register 5
SIO_RXA		EQU	00000001B	; RX Character Available
SIO_TXE		EQU	00000100B	; SIO Transmit Buffer Empty
;	
;----------------------------------------------------------------------
;		ELZET80 CPU/IEC CPU-Baugruppe
PIO_PAD		EQU	00H		; PIO PORT A DATEN
PIO_PBD		EQU	01H		; PIO PORT B DATEN
PIO_PAC		EQU	02H		; PIO PORT A, Control
PIO_PBC		EQU	03H		; PIO PORT B, Control
;
DRAM_ST		EQU	1000H		; DRAM Start Adresse (ext.)
;----------------------------------------------------------------------
;		ELZET80 FDC3 Floppy Controller
;		ELZET80 FDC3 Floppy Controller - PIO
FD3BAS		EQU	60H		; FDC3 I/O Basis-Adresse
FD3PAD		EQU	FD3BAS + 0CH	; FDC3 PIO Data A
FD3PBD		EQU	FD3BAS + 0DH	; FDC3 PIO Data B
FD3PAC		EQU	FD3BAS + 0EH	; FDC3 PIO Control A
FD3PBC		EQU	FD3BAS + 0FH	; FDC3 PIO Control B
;
F3PIOM3		EQU	11001111B	; PIO MODE 3
F3PAIOC		EQU	00100000B	; PORT A I/O Control Word
F3PBIOC		EQU	10000000B	; PORT B I/O Control Word
F3PAINT		EQU	00010111B	; PORT A Interrupt Control Word
					; DI, OR,LOW, MASK follows
F3PBINT		EQU	00010111B	; PORT B Interrupt Control Word
					; DI, OR,LOW, MASK follows
F3PAMSK		EQU	11111111B	; PORT A Interrupt MASK Word
					; Mask all interrupts
F3PBMSK		EQU	11111111B	; PORT B Interrupt MASK Word
					; Mask all interrupts
;
; F3PA7 = Output, FM/MFM (Density)
; F3PA6 = Output, SIDE-SEL
; F3PA5 = Input, Two Sided, 8" Interface
; F3PA4 = Output, MINI, Umschaltung 8" 5-1/4"
; F3PA3 = Output, Drive Select 3
; F3PA2 = Output, Drive Select 2
; F3PA1 = Output, Drive Select 1
; F3PA0 = Output, Drive Select 0

; PORT-B-7 = Input, Disk Change
; PORT-B-6 = Motor-ON-3
; PORT-B-5 = Motor-ON-2
; PORT-B-4 = Motor-ON-1
; PORT-B-3 = Output A19
; PORT-B-2 = Output A18
; PORT-B-1 = Output A17
; PORT-B-0 = Output A16
;
;		ELZET80 FDC3 Floppy Controller - DMA
;
;		ELZET80 FDC3 Floppy Controller - FDC-1793
F1793CMD	EQU	FD3BAS + 08H	; FDC-1793 Command Register
F1793TRK	EQU	FD3BAS + 09H	; FDC-1793 Track Register
F1793SEC	EQU	FD3BAS + 0AH	; FDC-1793 Sector Register
F1793DAT	EQU	FD3BAS + 0BH	; FDC-1793 Data Register
F1793STA	EQU	FD3BAS + 08H	; FDC-1793 Status Register
;----------------------------------------------------------------------
;
; STEUERZEICHEN UND TOP OF STACK 
; 
CON	EQU	0EH		; CURSOR ON BEI TRS-80 
CR	EQU	0DH 		; CARRIAGE RETURN 
LF	EQU	0AH 		; LINEFEED
BS	EQU	0BH		; BACKSPACE 
#ifdef	INTRAM
; TOS	EQU	0F3FFH		; TOP OF STACK, CPU-IEC internal RAM, Standard
TOS	EQU	0F7FFH		; TOP OF STACK, CPU-IEC internal RAM, Debug
#else
TOS	EQU	0FFFFH		; TOP OF STACK 
#endif
;
;--------------------------------------------------
ORG 0000H 				; RESET-ENTRY 
;--------------------------------------------------
RESET	DI				;
	JR	HW_INIT			; INIT I/O
;--------------------------------------------------
					; INIT SIO/2 (A und B)
HW_INIT	LD	A,SIO_CH_RST		; SIO - Channel RESET
        OUT	(SIOB_CTL),A		; SIO/2-B-Control-Port
        OUT	(SIOA_CTL),A		; SIO/2-A-Control-Port
        LD	A,SIO_WR4		; Address WR4
        OUT	(SIOB_CTL),A		; SIO/2-B-Control-Port
        OUT	(SIOA_CTL),A		; SIO/2-A-Control-Port
        LD	A,044H			; 0x44, 0100 0100b - > 
					; X16 Clock Mode, 
					; 1 Stop-Bits, Even/Odd-Parity = 0
					; Parity-Enable = 0
        OUT	(SIOB_CTL),A		; SIO/2-B-Control-Port
        OUT	(SIOA_CTL),A		; SIO/2-A-Control-Port
        LD	A,SIO_WR3		; WR3
        OUT	(SIOB_CTL),A		; SIO/2-B-Control-Port
        OUT	(SIOA_CTL),A		; SIO/2-A-Control-Port
        LD	A,0C1H			; 0xC1, 0100 0001b ->
					; RX = 8 Bits/Char, Autoenables = 0
					; Bit(4:1) = 0, RX-Enable = 1 
        OUT	(SIOB_CTL),A		; SIO/2-B-Control-Port
        OUT	(SIOA_CTL),A		; SIO/2-A-Control-Port
        LD	A,SIO_WR5		; WR5			
        OUT	(SIOB_CTL),A		; SIO/2-B-Control-Port
        OUT	(SIOA_CTL),A		; SIO/2-A-Control-Port
        LD	A,068H			; 0x68, 0110 1000b ->
					; DTR = 0, TX = 8Bits/Char, Send-Break = 0
					; TX-Enable = 1, RTS = 0, Bit2 und Bit0 = 0
        OUT	(SIOB_CTL),A		; SIO/2-B-Control-Port
        OUT	(SIOA_CTL),A		; SIO/2-A-Control-Port
        LD	A,SIO_WR1		; WR1
        OUT	(SIOB_CTL),A		; SIO/2-B-Control-Port
        OUT	(SIOA_CTL),A		; SIO/2-A-Control-Port
        LD	A,00H			; WR1 = 00
        OUT	(SIOB_CTL),A		; SIO/2-B-Control-Port
        OUT	(SIOA_CTL),A		; SIO/2-A-Control-Port
        LD	A,SIO_WR0		; WR0
        OUT	(SIOB_CTL),A		; SIO/2-B-Control-Port
        OUT	(SIOA_CTL),A		; SIO/2-A-Control-Port
					; INIT Z80-PIO
	JP	TST_HW			; Teste Hardware
; Adresse 42H
M0042	DB	"MINIMON EI V 0.1"	; Monitormeldung
M0052	DB	0DH,0AH			; neue Zeile
M0054	DB	00H			; Endezeichen
RAM_OK1	DB	"OK",0DH,0AH,00H	;
RAM_BD1	DB	"BAD",0DH,0AH,00H	;
M0060	DB	13H,13H,12H,20H,21H	; Version 13, 13.12.20, 21:15
M0065	DB	15H			;
;
ORG	0066H				; NMI Entry
	LD	HL,LD_OK		; MINIMON im RAM?
	LD	A,055H			; 55H im RAM ?  
	CP	(HL)			;
	JR	NZ,NMSTP		; NEIN, EPROM, Halt on NMI
	INC	HL			;
	LD	A,0AAH			; 0AAH im RAM ?  
	CP	(HL)			;
	JR	NZ,NMSTP		; NEIN, EPROM, Halt on NMI
	LD	HL,NMTXT		; MINIMON im RAM > "NMI AT: "
	CALL	PRTXT			; ausgeben
	POP	HL			; PC
	CALL	PRHL			; ausgeben
	CALL	CRLF			; neue Zeile
	LD	HL,0000H		; -> setze auf RESET Enty fort
	PUSH	HL			;
	LD	HL,BREAK		; zunaechst Register-Ausgabe
	PUSH	HL			; wie bei Breakpoint
	RETN				; Return from NMI
NMSTP	LD	DE,NMTX1		; MINIMON im EPROM, "NMI"
	LD	HL,NMHLT		; Return Adresse
	JP	TXTO_S0			; ausgeben (CALL)
NMHLT	HALT				; HALT
	JP	RESET			; START NEW
;--------------------------------------------------
NMTXT	DB	0DH,0AH,"NMI AT: "	;
	DB	00H			;
NMTX1	DB	"NMI ",00H		; TEXT when there is no RAM
;--------------------------------------------------
#ifdef	INTRAM
RAM_ST1	DB	0DH,0AH,"Testing RAM at"	; IEC-CPU, External RAM
	DB	" F000H - F3FFH : ",00H			
#else
RAM_ST1	DB	0DH,0AH,"Testing RAM at"	; IEC-CPU, Internal RAM
	DB	" FC00H - FCFFH : ",00H
#endif
;
FDC3_FI	DB	0DH,0AH,"FIND FDC-3 - ",00H
FDC3_NP	DB	"NOT "
FDC3_PR	DB	"PRESENT",0DH,0AH,00H
FDC3_RT	DB	"TESTING RAM ON FDC-3 - ",00H
;
MOV_RAM	DB	0DH,0AH
	DB	"MOVE CODE TO RAM ",00H
;
TST_HW	LD	SP,0100H		; Stack vorlaeufig auf 0100H
	LD	C,'#'			; Erstes Zeichen
	LD	HL,RAMT00		; Return Adresse -> HL
	JP	CHO_S0			; auf Serial 0 ausgeben
RAMT00	LD	DE,RAM_ST1		; Adresse String -> DE
	LD	HL,MRETB		; Return-Adresse -> HL
	JP	TXTO_S0			; Text ausgeben
					; Teste zunächst zwei RAM-Zellen
MRETB	LD	HL,TSTRAM		; Adresse RAM (Buffer-Bereich)
	LD	B,055H			; Testpattern 055H
MRETL	LD	(HL),B			; Testpattern -> RAM
	NOP				; warte
	NOP				; warte
	LD	A,(HL)			; Lese Testpattern
	CP	B			; OK ?
	JR	NZ,RT0_FE1		; NEIN, "<" ausgeben
	LD	A,B			;
	CPL				; invertiere Testpattern
	LD	B,A			;
	INC	HL			; zweiter TP auf der nächsten Adresse
	AND	80H			; zweiter Testpattern OK?
	JR	NZ,MRETL		; nein Teste mit invertiertem Pattern
	LD	C,'>'			; OK, ">" ausgeben 
	LD	HL,MRETC		; Return-Adresse
	JP	CHO_S0			; auf Serial 0 ausgeben
MRETC	LD	HL,STAMON		; Anfangsadresse CODE im RAM
MRETF	LD	D,H			; Adresspointer -> DE
	LD	E,L			;
	LD	(HL),D			; High Byte Adresspointer -> RAM
	INC	HL			;
	LD	(HL),E			; Low Byte Adresspointer -> RAM
	INC	HL			;
	LD	A,L			;
	OR	A			; 256 Bytes geschrieben
	JR	NZ,MRETD		; nein
	NOP				; hier Punkt ausgeben
	EX	DE,HL			; save Memory-Adresse -> DE
	LD	HL,RETPKT		; Return-Adresse -> HL
	LD	C,'.'			; Punkt
	JP	CHO_S0			; ausgeben
RETPKT	EX	DE,HL			; Memory-Adresse -> HL	
MRETD	LD	A,H			; incremented past 1 KByte
	AND	03H			; begrenze Vergleich auf 1K
	OR	L			;
	JR	NZ,MRETF		; nein -> nächster Adresspattern -> RAM
					;
	LD	HL,STAMON		; Ja, überprüfe ab erster Code Adresse
MRETE	LD	D,H			; Adresspointer -> DE
	LD	E,L			;
	LD	A,D			;
	LD	B,D			; Expected Value -> B
	LD	A,(HL)			; High Byte
	CP	D			; correct ?
	JR	NZ,RT1_FE1		; nein -> Fehler
	INC	HL			;
	LD	A,E			;
	LD	B,E			; Expected Value -> B
	LD	A,(HL)			; LOW Byte
	CP	E			; correct ?
	JR	NZ,RT1_FE1		; nein -> Fehler
	INC	HL			;
	LD	A,L			; 256 Bytes gelesen ?
	OR	A			;
	JR	NZ,MRETG		; nein
	NOP				; hier + ausgeben
	EX	DE,HL			; Memory-Adresse -> DE
	LD	HL,RETHAS		; Return-Adresse -> HL
	LD	C,'+'			; Pluszeichen
	JP	CHO_S0			; ausgeben
RETHAS	EX	DE,HL			; Memory-Adresse -> HL
MRETG	LD	A,H			; incremented past 1K ?
	AND	03H			; begrenze auf 1K
	OR	L			;
	JR	Z,RT1_OK1		; ja, FC00 - FFFF is OK
	JR	MRETE			; nein, nächstes Wort	 	
					; FC00 - FFFF erfolgreich getestet
RT1_OK1	LD	DE,RAM_OK1		; Adresse String -> DE
	LD	HL,RT1_END		; Return-Adresse -> HL
	JP	TXTO_S0			; Text ausgeben (CALL DIRECT)
RT1_END	JR	RAMT02			; BASIS-RAM OK, weitere RAM Tests
;--------------------------------------------------
;					; Fehler erste RAM-Adresse
; IN	HL = RAM-Adresse
;	B = Write Data
;	A = Read Data
RT0_FE1	EX	DE,HL			; RAM-Adresse -> DE
	LD	IY,RT0_HLT		; Return Adresse -> IY
	JP	RAM_FEH			; Fehleradresse, Write Date
RT0_HLT	HALT				; und Read Data ausgeben 
	JR	RT0_HLT			; und HALT
;
;--------------------------------------------------
;					; RAM-Fehler
;					; STANDARD RAM   FC00 - FFFF
;					; CPU-IEC RAM at F000 - F3FF
; IN	HL = RAM-Adresse
;	B = Write Data
;	A = Read Data
RT1_FE1	EX	DE,HL			; RAM-Adresse -> DE
	LD	IY,RT1_FE2		; IY = Return-Adr., Fehleradresse,
	JP	RAM_FEH			; Write Data und Read Data ausgeben
RT1_FE2	LD	DE,RAM_BD1		; Adresse String -> DE
	LD	HL,RT1_HLT		; Return-Adresse -> HL
	JP	TXTO_S0			; Test ausgeben
RT1_HLT	HALT				; STOP
	JP	RESET			;
;
;--------------------------------------------------
;	RAM Test 2 X 64K auf ELZET80 FDC-3
;	Finde FDC-3
RAMT02	LD	DE,FDC3_FI		; Adr String -> DE, Finde FDC-3
	LD	HL,RT1_FDF		; Return-Adresse -> HL
	JP	TXTO_S0			; Test ausgeben (DIRECT CALL)
;
;	1. Initialisiere FDC-3 - PIO
;
RT1_FDF	LD	C,FD3PAC		; Initialisiere FDC-3 PIO-Port A
	LD	A,F3PIOM3		; MODE 3
	OUT	(C),A			;
	LD	A,F3PAIOC		; I/O Control Word
	OUT	(C),A			;
	LD	A,F3PAINT		; Interrupt Control Word
	OUT	(C),A			;
	LD	A,F3PAMSK		; Interrupt Mask
	OUT	(C),A			;
	LD	C,FD3PAD		;
	LD	A,0DFH			; FDC3-PIO-PORT A, Initial Value
	OUT	(C),A			;
					;
	LD	C,FD3PBC		; Initialisiere FDC-3 PIO-Port B
	LD	A,F3PIOM3		; MODE 3
	OUT	(C),A			;
	LD	A,F3PBIOC		; I/O Control Word
	OUT	(C),A			;
	LD	A,F3PBINT		; Interrupt Control Word
	OUT	(C),A			;
	LD	A,F3PBMSK		; Interrupt Mask
	OUT	(C),A			;
	LD	C,FD3PBD		;
	LD	A,70H			; FDC3-PIO-PORT B, Initial Value
	OUT	(C),A			; A19 - A16 = 0000
;
;	2. Check if PIO Port B, Bit 3:0 is writable
;	
	IN	A,(C)			; Read PIO Port B
	AND	0F0H			; Clear Bit 3:0 (A19:A16)
	OR	09H			; Test Pattern XXXX 1001B
	OUT	(C),A			; A19 - A16 = 9
	NOP				;	
	IN	A,(C)			; Read PIO Port B
	LD	B,A			; save in B
	AND	0FH			; Bit 3:0 only (A19:A16)
	CP	09H			; Port B Bit 3:0 = 9?
	JR	NZ,FD3NOP		; NEIN, FDC-3 not Present
	LD	A,B			; 
	AND	0F0H			; Clear Bit 3:0 (A19:A16)
	OR	06H			; Test Pattern XXXX 0110B
	OUT	(C),A			; A19 - A16 = 8
	NOP				;	
	IN	A,(C)			; Read PIO Port B
	AND	0FH			; Bit 3:0 only (A19:A16)
	CP	06H			; Port B Bit 3:0 = 6?
	JR	NZ,FD3NOP		; NEIN, FDC-3 not Present
FD3_PRE	LD	A,70H			; FDC3-PIO-PORT B, Initial Value
	OUT	(C),A			; A19 - A16 = 0000
	LD	DE,FDC3_PR		; JA, Adr String -> DE, FDC3 PRESENT
	LD	HL,RT2_FDF		; Return-Adresse -> HL	
	JP	TXTO_S0			; Test ausgeben (DIRECT CALL)
;
;	3. Test FDC-3 DRAM Bank 0 from 1000H to START MINIMON
;
RT2_FDF	LD	DE,FDC3_RT		; Text Message, RAM Test FDC-3
	LD	HL,RT2_RAT		; Return-Adresse -> HL
	JP	TXTO_S0			; Test ausgeben (DIRECT CALL)
RT2_RAT	NOP				; RAM Test FDC-3
	LD	HL,DRAM_ST		; Start-Adresse DRAM
	LD	DE,MFC00-1		; Endadresse freies DRAM
	LD	B,55H			; Testpattern -> B
RT2_RBT	LD	A,B			; Testpattern -> A
	LD	(HL),A			; Testpattern -> DRAM
	NOP				;
	LD	A,(HL)			; Testpattern OK?
	CP	B			;
	JR	NZ,RT2_F01		; NEIN -> Fehler
	INC	HL			; nächste Adresse
	LD	A,L			; Endadresse DRAM erreicht?
	OR	A			; 256 Bytes Grenze?
	JR	NZ,RT2_NBG		; nein
	LD	SP,HL			; DRAM-Adressse in SP sichern
	LD	HL,RT2_PLU		; Return-Adresse -> HL
	LD	C,'+'			; Pluszeichen
	JP	CHO_S0			; ausgeben (DIRECT CALL)
RT2_PLU	LD	HL,0000H		; restauriere DRAM-Adresse
	ADD	HL,SP			;
RT2_NBG	LD	A,L			;
	CP	E			; Endadresse DRAM erreicht?	
	JR	NZ,RT2_RBT		; nein, teste nächstes Byte
	LD	A,H			; Endadresse DRAM erreicht?
	CP	D			;
	JR	NZ,RT2_RBT		; nein, teste nächstes Byte
	LD	DE,RAM_OK1		; JA, RAM ist OK
	LD	HL,RT2_RCT		; Return-Adresse -> HL
	JP	TXTO_S0			; Test ausgeben (DIRECT CALL)
RT2_RCT	JR	RT3_FDF			; Move Code to RAM
;
FD3NOP	LD	A,70H			; FDC3-PIO-PORT B, Initial Value
	OUT	(C),A			; A19 - A16 = 0000
	LD	DE,FDC3_NP		; Adr String -> DE, FDC3 NOT PRESENT
	LD	HL,RT3_FDF		; Return-Adresse -> HL
	JP	TXTO_S0			; Test ausgeben (DIRECT CALL)
RT3_FDF	JP	MVTORAM			; RAM OK, Monitor -> Zieldresse im RAM
;
;--------------------------------------------------
;					; RAM-Fehler
;					; DRAM on FDC3
;					; BANK 0, ADR: 1000H - EFFFH
; IN	HL = RAM-Adresse
;	B = Write Data
;	A = Read Data
RT2_F01	EX	DE,HL			; RAM-Adresse -> DE
	LD	IY,RT2_FE2		; IY = Return-Adr.
	JP	RAM_FEH			; Fehleradr., Write Data und Read Data ausgeben	
RT2_FE2	LD	DE,RAM_BD1		; RAM Fehler
	LD	HL,RT2_FE3		; Return-Adresse -> HL
	JP	TXTO_S0			; Test ausgeben (DIRECT CALL)
RT2_FE3	NOP				; Fehler
	JP	MVTORAM			;
;--------------------------------------------------
;	Unterprogramme ohne Stack
;--------------------------------------------------
;	CHO_S0 gibt ASII-Character auf die serielle Schnittstelle 0 aus
;	C = ASCII Character
;	HL = Return Addresse
;	REGISTER: C, HL
CHO_S0	EX	AF,AF'			; Save A in A'
CHO_W0	LD	A,SIO_WR0		;	
	OUT	(SIOA_CTL),A		; Address Register RR0
	IN	A,(SIOA_CTL)		; Read RR0
	AND	SIO_TXE			; TX Empty ?
	JR	Z,CHO_W0		; NO, wait
	LD	A,C			; Output Character
	OUT	(SIOA_DAT),A		;
	EX	AF,AF'			; Restore A	
	JP	(HL)			; Return
;--------------------------------------------------
;	TXTO_S0 gibt NULL-terminierten ASII-String auf die
;	serielle Schnittstelle 0 aus
;	DE = Adresse ASCII String
;	HL = Return Addresse
;	REGISTER: A, C, DE, HL		;
TXTO_S0	LD	A,(DE)			; Lade ASCCI Character
	OR	A			; Endezeichen 00 erreicht?
	JR	Z,TXTO_E		; ja, STOP
	LD	C,A			; ASCII-Character -> C
	LD	SP,HL			; Original Return-Adresse -> IX
	LD	IX,0000H		;
	ADD	IX,SP			;
	LD	HL,TXTO_S1		; Neue Return-Adresse -> HL
	JP	CHO_S0			; Character ausgeben, (CALL) 
TXTO_S1	LD	SP,IX			;
	LD	HL,0000H		;
	ADD	HL,SP			; Return-Adresse -> HL
	LD	SP,0100H		; Stackpointer auf Anfangswert	
	INC	DE			; naechster Character
	JR	TXTO_S0			; 	
TXTO_E	JP	(HL)			; Return
;--------------------------------------------------
;	HXTOSP gibt SPACE auf Serial 0 aus, wandelt HEX-Datum in A in ASCII
;	und gibt auf Serial 0 aus
; IN	A = HEX-Datum
;	IX = Return Adresse
; CHG	REGISTER: A, B, C, HL, DE
HXTOSP	LD	C,' '			; Space -> C
	LD	HL,HXTOS0		; neue Return Adresse -> HL
	JP	CHO_S0			; SPACE -> Serial 0, (CALL DIRECT)				; 
;	weiter zum folgenden HXTOS0
;--------------------------------------------------
;	HXTOS0 wandelt HEX-Datum in A in ASCII und gibt auf Serial 0 aus
; IN	A = HEX-Datum
;	IX = Return Addresse
; CHG	REGISTER: A, B, C, HL, SP
HXTOS0	EX	DE,HL			; Sichere DE		
	LD	SP,HL			; in SP
	LD	HL,HXTOSA		; Return Aresse - > HL
	JP	HXTOAS			; konvertiere -> ASCII in DE, (CALL DIRECT)
HXTOSA	LD	C,D			; High Nibble ASCII -> C
	LD	HL,HXTOSB		; Return Adressse -> HL
	JP	CHO_S0			; High Nibble ASCII -> Serial 0, (CALL DIRECT)
HXTOSB	LD	C,E			; Low Nibble ASCII -> C
	LD	HL,HXTOSC		; Return Adressse -> HL
	JP	CHO_S0			; High Nibble ASCII -> Serial 0, (CALL DIRECT)
HXTOSC	LD	HL,0000H		; Urspruengliche Return Adresse
	ADD	HL,SP			; RESTORE
	EX	DE,HL			; DE
	JP	(IX)			; Return
;--------------------------------------------------
;	HXTOAS wandelt HEX-Datum in A in ASCII in D und E
; IN	A = HEX-Datum
;	HL = Return Addresse
; OUT	DE = ASCII-Character
; CHG	REGISTER: A, C, HL, DE
HXTOAS	LD	C,A			; Sichere HEX-Wert in C
	AND	0FH			; LOW HEX Nibble
	CP	0AH			;
	SBC	A,69H			;
	DAA				;
	LD	E,A			; Low ASCII Nibble -> E
	LD	A,C			; High HEX Nibble
	RRA				;
	RRA				;
	RRA				;
	RRA				; -> Bit 3:0
	AND	0FH			;
	CP	0AH			;
	SBC	A,69H			;
	DAA				;
	LD	D,A			; High ASCII Nibble -> D
	JP	(HL)			; Return
;--------------------------------------------------
;		Fehler RAM-Adresse
;		Gebe Fehleradresse, Write Data und Read Data 
;		auf serielle Schnittstelle	
; IN	IY = Return-Adresse
;	DE = RAM-Adresse
;	B = Write Data
;	A = Read Data
; REGS	AF, AF', BC, DE, HL, IX, IY
;###### LD	DE,1234H		; ###### DEBUG
RAM_FEH	LD	I,A			; Read Data -> I
	LD	C,'<'			; FEHLER, "<" ausgeben
	LD	HL,RT0_FE2		; Return-Adresse
	JP	CHO_S0			; auf Serial 0 ausgeben
RT0_FE2	LD	A,D			; High Byte Adresse -> A	
	LD	IX,RT0_FE3		; Return-Adresse -> IX
	JP	HXTOSP			; SPACE + HI-Byte ADR. -> Serial 0
RT0_FE3	LD	A,E			; Low Byte Adresse -> A	
	LD	IX,RT0_FE4		; Return-Adresse -> IX
	JP	HXTOS0			; LO-Byte ADR. -> Serial 0
RT0_FE4	LD	A,B			; Write Data -> A
	LD	IX,RT0_FE5		; Return-Adresse -> IX
	JP	HXTOSP			; SPACE + WRITE-Data -> Serial 0
RT0_FE5	LD	A,I			; READ-Data -> A
	LD	IX,RT0_FE6		; Return-Adresse -> IX
	JP	HXTOSP			; SPACE + READ-Data -> Serial 	
RT0_FE6	LD	C,' '			; Space ausgeben
	LD	HL,RT0_FE7		; Return-Adresse -> HL
	JP	CHO_S0			; Space ausgeben
RT0_FE7	JP	(IY)			; RETURN
;--------------------------------------------------
MVTORAM	LD	DE,MOV_RAM		; Text "Move Code to RAM " ausgeben
	LD	HL,MVTRRET		; Return Adresse -> HL
	JP	TXTO_S0			; Text ausgeben (CALL DIRECT)
MVTRRET	LD	DE,STAMON		; Ziel-Adresse -> DE
	LD	HL,ENDLOW		; Start-Adresse - HL
	LD	BC,MO_END-STAMON		; Länge
	LDIR				; umkopieren
	NOP				; Check code im RAM
	LD	HL,ENDLOW		; EPROM-Start ADR. -> HL
	LD	IX,STAMON		; RAM Start-Adresse -> IX
	LD	BC,MO_END-STAMON	; Länge -> BC
MVNCHK	LD	A,(HL)			; EPROM DATUM -> A
	CP	(IX+0)			; GLEICH EPROM DATUM ?
	JR	NZ,MV_FAIL		; NEIN -> Fehler
	INC	HL			; EPROM-Adresse +1
	INC	IX			; RAM-Adresse +1
	DJNZ	MVNCHK			; Teste nächstes Byte
;					; IMAGE im RAM ist OK
	LD	DE,RAM_OK1		; "OK" ausgeben
	LD	HL,MVOKRET		; Return Adresse -> HL
	JP	TXTO_S0			; Text ausgeben (CALL DIRECT)
MVOKRET	LD	HL,LD_OK		; Set Flag, Loaded to RAM
	LD	(HL),055H		;
	INC	HL			;
	LD	(HL),0AAH		;
	JP	STAMON			; Setze auf Zieladresse im RAM fort
;
MV_FAIL	JP	RT1_FE1			; Wie Fehler im RAM Test 1	
;
ENDLOW	DS	0			;
;
;--------------------------------------------------
#IFDEF	INTRAM
ORG	0F000H			; ELZET80 IEC-CPU, Internal RAM
#ELSE
ORG	0FC00H 			; STANDARD-CPU, BEREICH DER BUFFER 
#ENDIF
;--------------------------------------------------
;
MFC00	DS	0		; Startaddresse RAM 
;	 
;--------------------------------------------------
; ORG	0FC30H			; STARTADR.DES MONITORS
;-------------------------------------------------- 
				;
				; STACK DEFINIEREN  
STAMON	LD	SP,TOS		; 
;--------------------------------------------------  
;	Monitormeldung ausgeben
	LD	HL,M0042	; Adresse Monitormeldung
	CALL	PRTXT		; Monitor-Meldung ausgeben
				; INITIALISIEREN DES MONITORBUFFERS
				;
	LD	HL,BUFF		; 
	LD	B,10H		; BUFFER MIT '0' FUELLEN 
INIT	XOR	A		; 
	LD (HL),A		; 
	INC HL			; 
	DJNZ INIT		;
;-------------------------------------------------- 
				; CURSOR EINSCHALTEN (BEI TRS-80) 
				; 
;	LD A,CON		; 
;	CALL CRT		; 
; 
;--------------------------------------------------
; 
; DRUCKT '-', LIEST ZEILE VOM KBD IN BUFF 
; 
KBDL	CALL	CRLF		; neue Zeile
	LD	A,'-'		; Aufforderungszeichen -> CRT
	CALL	CRT		; ausgeben
	CALL	PSP		; Space -> CRT
	CALL	KBIN		; Warte auf Befehl, mit CR abgeschlossen
	PUSH	HL		; save BUFF-Pointer
	LD	HL,BUFF		; konvertiere ASCII -> Upper Case
KBDL1	LD	A,(HL)		;
	CP	CR		; CR = Endezeichen
	JR	Z,KBDLE		; JA -> Ende Konvertierung
	CP	'a'		; kleiner 'a' ?
	JR	C,KBDNC		; -> do not change
	CP	'{'		; größer 'z' ?
	JR	NC,KBDNC	; -> do not change
	AND	01011111B	; Convert to Upper Case
	LD	(HL),A		; save in Buffer
KBDNC	INC	HL		; nächstes ASCII-Zeichen
	JR	KBDL1		; Continue
KBDLE	POP	HL		; Restauriere Buff-Pointer				
;--------------------------------------------------
				; SUCHT TABA NACH BEFEHL DURCH  
				; WENN GEFUNDEN SPRUNG JEXE
;
EXEC	LD	HL,TABA		; Anfangsadresse Befehlstabelle
	XOR	A		; ??
EXECl	LD	A,(BUFF)	;
	CP	CR		;
	JR	Z,KBDL		; NUR CR -> warte weiter auf Befehl
	CP	(HL)		; Gültiger Befehl ? 
	JR	Z,JEXE 		; Ja, weiter dekodieren
	LD	A,0FFH		; Endezeichen
	CP	(HL)		; der Befehls-Tabelle?
	JR	Z,KBDL		; ja, warte weiter auf Befehl
	INC	HL		; HL+3
	INC	HL		; nächstes Element der Tabelle
	INC	HL		; 
	JR	EXECl		; 
; 
;-------------------------------------------------- 
				; SPRINGT ZU BEFEHLS ROUTINE 
;  
JEXE	PUSH	HL		; Sichere BUFF-Zeiger
	CALL	GETA		; Lese ARG1 und ARG2 
	POP	HL		; Restauriere BUFF-Zeiger 
	INC	HL		; Nächstes Element in BUFF 
	LD	E,(HL)		; -> DE
	INC	HL		;  
	LD	D,(HL)		; 
	LD	HL,KBDL		; Return-Adresse Hauptschleife 
	PUSH	HL		; -> Stack 
	PUSH	DE		; Adresse Monitor-Befehl -> Stack 
	RET			; ausführen
;--------------------------------------------------
TABA	DB	'M'		;  
	DW	MODIFY		; Modify Memory 
	DB	'D'		; 
	DW	DISPM		; Display Memory (BIN)
	DB	'J'		; 
	DW	JUMP		; Goto Address
	DB	'B'		; 
	DW	BREP0		; Set/RESET Breakpoint 
	DB	'A'		;  
	DW	ASCII		; Display Memory (ASCII)
	DB	'I'		;  
	DW	INPU		; Input
	DB	'O'		;  
	DW	OUTP		; Output
	DB	'C'		;  
	DW	CLEARM		; Clear Memory
	DB	'P'		;  
	DW	PAGEM		; Memory Page
	DB	'T'		;  
	DW	TESTM		; Memory Test
	DB	0FFH		; Endezeichen
;--------------------------------------------------
; UNTERPROG. LIEST (DE) U. WANDELT ASCII IN HEX  
; ERGEBNIS STEHT IN AHEXB+1 
AHEX	XOR	A		; AHEXB = 00
	LD	HL,AHEXB	;  
	LD	(HL),A		;  
	INC	HL		; 
	LD	(HL), A		; AHEXB+1 = 00  
	INC	HL		;  
	LD	(HL),A		; AHEXB+2 = 00
AHEXl	DEC	HL		; Zeige auf AHEXB 
	DEC	HL		; 
	LD	A,(DE)		; ASCII -> A
	SUB	30H		; ASCII-Kontroll-Zeichen ?
	RET	M		; JA -> UNGUELTIG 
	CP	0AH		; ASCII 0 - 9 ?
	JR	C,AHEX2		; GUELTIG, 0-9 
	SUB	07H		; 
	CP	0AH		;  
	RET	M		; UNGUELTIG 
	CP	10H		;  
	RET	P		; UNGUELTIG 
AHEX2	INC	DE		;  
	INC	(HL)		;  
	INC	HL		; 
	RLD			; 
	INC	HL		; 
	RLD			;  
	JR	AHEXl		; 
; RLD
; zyklische Verschiebung nach links zwischen dem Akkumulator und dem Inhalt des durch HL 
; adressiertem Speicherplatzes (m). 
; Die unteren 4 Bit von m werden in die oberen 4 Bitstellen übertragen und diese ihrerseits
; in die unteren 4 Bits des Akkumulators. 
; Die unteren 4 Bits des Akkumulators werden in die unteren 4 Bitstellen
; von m transportiert. Die oberen 4 Bits des Akkumulators bleiben unverändert.
;--------------------------------------------------
; UNTERPROG. LIEST AUS EINGEG. ZEILE DIE 
; ARGUMENTE ARG1 UND ARG2 
;
GETA	LD	DE,BUFF+1	; 
	CALL	TESP		; Suche Space
	CALL	AHEX		; Wandle ASCII in HEX
	PUSH	DE		; Sichere BUFF-Zeiger 
	LD	HL,AHEXB+1	; Ergebnix in AHEXB+1 und AHEXB+2
	LD	E,(HL)		; Ergebnis -> DE  
	INC	HL		;  
	LD	D,(HL)		;  
	LD	(ARG1),DE	; Ergebnis -> ARG1
	POP	DE		; Restauriere BUFF-Zeiger
	CALL	TESP		; Suche Space
	CALL	AHEX		; Wandle ASCII in HEX
	LD	HL,AHEXB+1	; Ergebnix in AHEXB+1 und AHEXB+2 
	LD	E,(HL)		; Ergebnis -> DE 
	INC	HL		;  
	LD	D,(HL)		;
	LD	(ARG2),DE	; Ergebnis -> ARG2 
	RET			; 
;--------------------------------------------------
; UNTERPROG. SETZT DE UEBER SPACE
; Suche SPACE 
TESP	XOR	A		;  
	LD	A,(DE)		;
	CP	' '		; 
	RET	NZ		; 
	INC	DE		; 
	JR	TESP		; 
;--------------------------------------------------
; UNTERPROG. DRUCKT AKKUINHALT IN HEX 
;
PRHEX	PUSH	AF		; 
	RRA			; 
	RRA			;  
	RRA			;  
	RRA			; 
	CALL	PRHEX1		;  
	POP	AF		; 
PRHEX1	AND	0FH		;  
	ADD	A,30H		; 
	CP	':'		;  
	JR	C,JCRT		; 
	ADD	A,07H		; 
JCRT	JP	CRT		; RETURN UEBER RET IN CRT ROUTINE
;--------------------------------------------------
;				; UNTERPROG. DRUCKT CR/LF
CRLF	LD	A,CR		;
	CALL	CRT		; CR -> CRT
	LD	A,LF		;
	JR	JCRT		; LF -> CRT
;--------------------------------------------------
;				; UNTERPROG. DRUCKT CR
CRET	LD	A,CR		;
	JR	JCRT		;
;--------------------------------------------------
				; UNTERPROG. DRUCKT SPACE
PSP	LD	A,' '		;
	JR	JCRT		;
;--------------------------------------------------
				; UNTERPROG. DRUCKT ADRESSE IN HL
PRHL	PUSH	DE		; Save DE, BC
	PUSH	BC		;
	LD	A,H		; Drucke Hex-Byte in H
	CALL	PRHEX		;
	LD	A,L		;
	CALL	PRHEX		; Drucke Hex-Byte in L
	POP	BC		; Restore DE, BC
	POP	DE		;
	RET			;
;--------------------------------------------------
				; UNTERPROG. DRUCKT Zeichen in BC
REGS	LD	A,B		; Register-Namen ausgeben
	CALL	CRT		;
	LD	A,C		;
	CALL	CRT		;
	JR	PSP		; Space ausgeben und RET
;--------------------------------------------------
				; UNTERPROG. DRUCKT ADRESSE IN HL und (HL)
PR	CALL	PRHL		; HL als HEX -> Konsole
	CALL	PSP		;
	LD	A,'('		;
	CALL	CRT		;
	LD	A,(HL)		; Adressierte Zelle -> Konsole
	CALL	PRHEX		;
	LD	A,')'		;
	CALL	CRT		;
	CALL	PSP		; Space
	JR	CRLF		; CR + LF -> Konsole
;--------------------------------------------------
				; UNTERPROG. DRUCKT NULL terminierten ASCII-String
				; HL = Pointer auf String
PRTXT	LD	A,(HL)		; Lade ASCII Zeichen
	OR	A		; NULL ?
	RET	Z		; JA, Ende
	CALL	CRT		; ausgeben
	INC	HL		; nächstes Zeichen
	JR	PRTXT		;
;--------------------------------------------------
				; UNTERPROG. KBD ABFRAGE, HL ZEIGT AUF BUFFER
KBIN	LD	HL,BUFF		;
KBIN1	XOR	A		;
	CALL	KBD		; Hole Zeichen
	CALL	CRT		; ECHO to CRT
	LD	(HL),A		; Zeichen -> Buffer
	LD	A,L		;  
	CP	0FH		; Ende Buffer erreicht?
	JR	Z,KBIN3		; JA -> ENDE
	LD	A,(HL)		; Zeichen -> A
	INC	HL		; erhöhe Zeiger
	CP	BS		; Backspace ?
	JR	NZ,KBIN2	; nein
	DEC	HL		; Backspace ->
	LD	(HL),' '	; Buffer wieder loeschen
	DEC	HL		;
	LD	(HL),' '	;
	JR	KBIN1		; Warte auf naechstes Zeichen
KBIN2	CP	CR		; CR ?
	RET	Z		; JA -> Ende Eingabe	
	JR	KBIN1		; NEIN -> warte auf naechstes Zeichen
KBIN3	LD	A,CR		;	
	LD	(HL),A		; ENDE Buffer, mit CR abschliessen
	JR	KBIN2		; Ende Eingabe
;--------------------------------------------------
				; BEFEHLSROUTINEN
;
;--------------------------------------------------
				; SPRINGT ZU EINGEG. ADR.
; IN	HL = Zieladresse
;
JUMP	LD	HL,ARG1		;
	LD	E,(HL)		;
	INC	HL		;
	LD	D,(HL)		;
	PUSH	DE		;
	RET			;
;--------------------------------------------------
				; HEXDUMP VON ADR1 - ADR2
				; im Original = TABU
DISPM	LD	HL,(ARG1)	; HL = Anfangsadresse
	LD	DE,(ARG2)	; DE = Endadresse
	CALL	CRLF		; Neue Zeile
TABU1	CALL	PRHL		; Adresse ausgeben
	LD	A,':'		; ':' ausgeben
	CALL	CRT		;		
	LD	B,16		; 16 Bytes pro Zeile
TABU2	CALL	PSP		; Space -> CRT
	LD	A,(HL)		;
	CALL	PRHEX		; Gebe Datum aus
	CALL	CPHLDE		; Endadresse erreicht ? 	
	RET	NC		; JA -> Return
	INC	HL		; adressiere nächste Speicherzelle
	XOR	A		;
	CALL	KBDM		; Check Keyboard
	CP	' '		; Space eingegeben?
	JR	Z,TAWAIT	; JA -> anhalten bis nächstes SPACE
	CP	','		; Komma eingegeben ?
	RET	Z		; JA -> ENDE
TABU3	DJNZ	TABU2		; nächstes Datum ausgeben
	CALL	CRLF		; NEIN -> naechste Zeile
	JR	TABU1		; und weiter
TAWAIT	XOR	A		; Warte auf SPACE
	CALL	KBDM		;
	CP	' '		; SPACE = weiter anzeigen
	JR	Z,TABU3		;
	JR	TAWAIT		;
;--------------------------------------------------
				; AENDERT SPEICHERINHALT
MODIFY	LD	HL,(ARG1)	; Lade Adresse
MOD1	CALL	CRLF		; neue Zeile
	CALL	PRHL		; Adresse -> Console
	CALL	PSP		; Space -> Console
	LD	A,(HL)		;
	CALL	PRHEX		; Datum -> Console
	CALL	PSP		; Space -> Console
	PUSH	HL		;
	CALL	KBIN		;
	POP	HL		;
	XOR	A		;
	LD	DE,BUFF		;
	LD	A,(DE)		;
	CP	CR		;
	JR	NZ,MOD2		;
	INC	HL		;
	JR	MOD1		;
MOD2	CP	','		; Ende der Eingabe ?
	RET	Z		; JA -> Return
	PUSH	HL		; Save Adresse
	CALL	AHEX		; wandle in HEX
	INC	HL		; 
	LD	A,(HL)		; Restore Adresse
	POP	HL		;
	LD	(HL),A		; neues Datum -> Adresse
	INC	HL		; nächste Adresse
	JR	MOD1		;
;--------------------------------------------------
				; SETZT (ARG1) "CALL BREAK"
BREP0	XOR	A		;
	LD	A,(BUFF+1)	;
	CP	CR		;
	JR	Z,BREP01	;
	LD	BC,04H		;
	LD	DE,BREBU	;
	LD	HL,(ARG1)	;
	LDIR			;
	LD	HL,(ARG1)	;
	LD	(BREAD),HL	;
	LD	(HL),0CDH	;
	INC	HL		;
	LD	DE,BREAK	;
	LD	(HL),E		;
	INC	HL		;
	LD	(HL),D		;
	RET			;
BREP01	LD	BC,04H		;
	LD	DE,(BREAD)	;
	LD	HL,BREBU	;
	LDIR			;
	RET			;
;--------------------------------------------------
				; RETTET U. DRUCKT REGISTER, WIRD
				; NACH BREAK ANGESPRUNGEN
BREAK	PUSH	HL		;
	PUSH	DE		;
	PUSH	BC		;
	PUSH	AF		;
	CALL	CRLF		; neue Zeile
	POP	HL		; AF -> HL
	LD	B,'A'		;
	LD	C,'F'		;
	CALL	REGS		; Registernamen ausgeben
	CALL	PR		; Register-Inhalt und adressiertes
	POP	HL		; Byte ausgeben
	LD	B,'B'		;
	LD	C,'C'		;
	CALL	REGS		;
	CALL	PR		;
	POP	HL		;
	LD	B,'D'		;
	LD	C,'E'		;
	CALL	REGS		;
	CALL	PR		;
	POP	HL		;
	LD	B,'H'		;
	LD	C,'L'		;
	CALL	REGS		;
	CALL	PR		; ADRESSE IN HL und (HL) -> Console
	POP	HL		;
	LD	B,'P'		;
	LD	C,'C'		;
	CALL	REGS		;
	CALL	PR		; ADRESSE IN HL und (HL) -> Console
	LD	HL,0000H	;
	ADD	HL,SP		; SP -> HL
	LD	B,'S'		;
	LD	C,'P'		;
	CALL	REGS		;
	CALL	PR		;
	RET			;
;--------------------------------------------------
				; ASCII-PRINT VON ADR1 - ADR2
ASCII	LD	HL,(ARG1)	;
	LD	DE,(ARG2)	; Endadresse -> DE
	CALL	CRLF		; neue Zeile
ASCII1	CALL	PRHL		;
	LD	B,16		; 16 Werte pro Zeile
ASCII2	CALL	PSP		;
;--------------------------------------------------
	XOR	A		;
	LD	A,(HL)		;
	SBC	A,20H		; TEST OB KLEINER SPACE
	LD	A,20H		;
	JR	C,ASCII5	;
;--------------------------------------------------
	LD	A,(HL)		;
	SBC	A,7AH		; TEST OB GROESSER Z
	JR	C,ASCII4	;
	LD	A,20H		;
	JR	ASCII5		;
;--------------------------------------------------
ASCII4	LD	A,(HL)		;
ASCII5	CALL	CRT		;
	CALL	CPHLDE		; Endadresse erreicht ?
	RET	NC		; JA -> Ende
	INC	HL		; NEIN -> nächste Adresse
	XOR	A		;
	CALL	KBDM		; Tastatur-Eingabe
	CP	' '		; Space ?
	JR	Z,ASWAIT	; JA -> anhalten
	CP	','		; Komma ?
	RET	Z		; JA -> Ende
ASCII6	DJNZ	ASCII2		;
;	PUSH	HL		;
;	OR	A		;
;	LD	DE,(ARG2)	;
;	SBC	HL,DE		;
;	POP	HL		;
;	RET	NC		;
	CALL	CRLF		; neue Zeile
	JR	ASCII1		;
;--------------------------------------------------
ASWAIT	XOR	A		;
	CALL	KBDM		; Tastatur-Eingabe
	CP	' '		; Space ?
	JR	Z,ASCII6	;
	JR	ASWAIT		;
;--------------------------------------------------
;	Im Original nicht enthaltene Kommandos
;--------------------------------------------------
;
; INPUT: (I) (I/O-Adresse)
;
INPU	LD	HL,(ARG1)	; Input from I/O-Device, neu
	CALL	CRLF		; neue Zeile
	LD	A,H		; 8-Bit I/O-Adresse, H = 00 ?
	OR	A		;
	JR	NZ,PARM_F	; nein -> Fehler
	LD	A,L		; I/O-Adresse -> A
	CALL	PRHEX		; I/O-Adresse ausgeben
	CALL	PSP		; Space
	LD	A,'='		; '=' ausgeben
	CALL	CRT		;
	CALL	PSP		; Space
	LD	C,L		; I/O-Adresse -> C
	IN	A,(C)		; Lese -> A
	CALL	PRHEX		; gebe aus
	RET			;
PARM_F	CALL	CRLF		; neue Zeile
	LD	A,'?'		; Parameter Fehler
	JP	CRT		; ausgeben und RETURN (in CRT)
;--------------------------------------------------
;
; OUTPUT: (O) (I/O-Adresse) (Datum)
;
OUTP	LD	HL,(ARG1)	; Output to I/O-Device, neu
	CALL	CRLF		; Neue Zeile
	LD	A,H		; H = 00 ?
	OR	A		; I/O-Adresse = 8 Bit ?
	JR	NZ,PARM_F	; nein -> Fehler
	LD	C,L		; OK, I/O-Adresse -> C
	LD	HL,(ARG2)	; I/O-Wert -> HL
	LD	A,H		; H = 00 ?
	OR	A		; I/O-Wert = 8 Bit ?
	JR	NZ,PARM_F	; nein -> Fehler
	LD	A,L		; OK, I/O-Wert -> A
	OUT	(C),A		; ausgeben
	RET			;
;--------------------------------------------------
;
; Clear Memory: (C) (Anfangsadresse) (Endadresse)
;
CLEARM	LD	DE,(ARG1)	; Clear Memory, Anfangsadresse
	CALL	CRET		; CR ausgeben
	LD	HL,(ARG2)	; Endadresse
	OR	A		; Lösche Carry
	SBC	HL,DE		; Länge -> BC
	LD	B,H		;
	LD	C,L		;
	LD	HL,(ARG1)	; Anfangsadresse -> HL
	LD	(HL),00H	; = 00
;	PUSH	HL		; ### SAVE HL
;	CALL	PSP		; Gebe SPACE aus
;	CALL	PRHL		; ### Anfangsadresse ausgeben
;	POP	HL		; ### RESTORE HL		; 
	LD	D,H		; Zieladresse = HL + 1
	LD	E,L		;
	INC	DE		;
	LDIR			; Clear Memory
	RET			;
;--------------------------------------------------
;
; Memory Page: (P) (Page) {0 - F}
;
PAGEM	LD	HL,(ARG1)	; Page
	CALL	CRLF		; Neue Zeile
	LD	A,H		; H = 00 ?
	OR	A		; Page Nr. > 256 ?
	JR	NZ,PARM_F	; JA -> Fehler
	LD	A,L		; Page Nr. > 16 ?
	CP	10H		;
	JR	NC,PARM_F	; JA -> Fehler
	LD	C,FD3PBD	; FDC3, PIO-B Datenregister
	IN	A,(C)		; Lese PIO-B, Bit 3:0, A19:A16
	AND	0F0H		; Clear A19:A16
	OR	L		; Set A19:A16
	OUT	(C),A		; -> FDC-3 PIO Port B
	RET			;
;--------------------------------------------------
;
; Test Memory: (T) (Anfangsadresse) (Endadresse)
;
TESTM	CALL	CRLF		; neue Zeile
	LD	DE,(ARG1)	; Test Memory, Anfangsadresse
;	LD	HL,0FFFH	; Anfangsadresse > 1000H ?
;	OR	A		; Lösche Carry
;	SBC	HL,DE		; Anfangsadresse < 1000H?
;	JP	NC,PARM_F	; Ja -> Parameter Fehler
	LD	HL,(ARG2)	; Endadresse
	EX	DE,HL		; -> DE
	LD	HL,MFC00-1	; unterhalb Monitor-Bereich?
	OR	A		; Lösche Carry
	SBC	HL,DE		; Endadresse <  Monitor-Adresse ?
	JP	C,PARM_F	; Ja -> Parameter Fehler
	LD	HL,(ARG2)	; Endadresse -> HL
	LD	DE,(ARG1)	; Anfangsadresse -> DE
	OR	A		; Lösche Carry
	SBC	HL,DE		; Anfangsadresse < Endadresse ?
	JP	C,PARM_F	; Nein -> Parameter Fehler
;
;	Adresstest
;	schreibe Testpattern
	LD	HL,(ARG1)	; Anfangsadresse -> HL
	LD	DE,(ARG2)	; Endadresse -> DE
TMADL1	LD	A,H		; Schreibe High Byte Adressse
	LD	(HL),A		;
	LD	A,L		;
	INC	HL		; Schreibe Low Byte Adresse
	LD	(HL),A		;
	INC	HL		; nächstes Adresspaar
	AND	0FEH		; 256 Byte Grenze
	JR	NZ,TMADC1	; nein, weiter
	PUSH	AF		; save
	LD	A,'.'		; '.' ausgeben
	CALL	CRT		; -> Console
	POP	AF		; restore
TMADC1	CALL	CPHLDE		; Anfangsadresse < Endadresse
	JR	C,TMADL1	; JA, nächstes Adresspaar
;	Adresspattern initialisiert
;	Prüfe Testpattern
	LD	HL,(ARG1)	; Anfangsadresse -> HL
	LD	DE,(ARG2)	; Endadresse -> DE
TMADL2	LD	B,(HL)		; Lade High Byte Adresse -> B
	INC	HL		; Lade LOW Byte
	LD	C,(HL)		; Adresse -> C
	DEC	HL		;
	LD	A,B		; High Byte Adresse 	
	CP	H		; OK ?
	JR	NZ,TMADF1	; nein, Fehler HIGH Byte
	LD	A,C		; Low Byte Adresse 
	CP	L		; OK ?
	JR	NZ,TMADF2	; nein, Fehler LOW-Byte
	LD	A,C		; low Byte Adresse -> A
	AND	0FEH		; 256 Byte Grenze
	JR	NZ,TMADC2	; nein, weiter
	PUSH	AF		; save
	LD	A,'+'		; '+' ausgeben
	CALL	CRT		; -> Console
	POP	AF		; restore
TMADC2	INC	HL		; nächstes Adresspaar?
	INC	HL		;
	CALL	CPHLDE		; Anfangsadresse < Endadresse
	JR	C,TMADL2	; JA, nächstes Adresspaar		;
;
 	RET			; Test OK, Return
;
TMADF1	LD	B,H		; Fehler HIGH-Byte, exp. Data -> B
	JR	TMADF3		; Adresse und Daten ausgeben
TMADF2	LD	B,L		; Fehler LOW-Byte, exp. Data -> B
TMADF3	LD	C,A		; Read Data -> C
	CALL	CRLF		; neue Zeile
	CALL	PRHL		; Adresse ausgeben
	LD	HL,TMWTEX	; W = 
	CALL	PRTXT		; ausgeben
	LD	A,B		; Expected Data
	CALL	PRHEX		; ausgeben
	LD	HL,TMRTEX	; R = 
	CALL	PRTXT		; ausgeben
	LD	A,C		; Read Data
	CALL	PRHEX		; ausgeben
	RET			; Return
;
TMWTEX	DB	" W=",00H	;
TMRTEX	DB	" R=",00H	;
;--------------------------------------------------
;	Im Original nicht enthaltene Unterprogramme
;--------------------------------------------------
;	CPHLDE
; IN	HL = Start-Adresse
; IN	DE = Endadresse
; OUT	C = 1 -> Anfangsadresse < Endadresse
; OUT	C = 0 -> Anfangsadresse >= Endadresse
;	REGISTER: A
CPHLDE	PUSH	HL			; Save HL
	SBC	HL,DE			; Anfangsadresse - Endadresse
	POP	HL			; Restore HL
	RET	
;--------------------------------------------------
;	CRT gibt ASII-Character in A auf die serielle Schnittstelle 0 aus
;	A = ASCII Character
;	REGISTER: A
CRT	PUSH	BC			;
	LD	C,A			; rette Zeichen in C
CRT1	LD	A,SIO_WR0		;	
	OUT	(SIOA_CTL),A		; Address Register RR0
	IN	A,(SIOA_CTL)		; Read RR0
	AND	SIO_TXE			; TX Empty ?
	JR	Z,CRT1			; NO, wait
	LD	A,C			; Output Character
	OUT	(SIOA_DAT),A		;
	POP	BC			;
	RET				; Return
;--------------------------------------------------
; KBDM	Eine einmalige Abfrage der Tastatur. 
; 	Das Zeichen steht im Akku. 
; 	Wurde keine Taste gedrückt, ist der Akku ‘ 0 ’.
; IN	-
; OUT	A = 00 -> kein Zeichen, A <> 0 -> Eingabezeichen
;	Z = 1 -> kein Zeichen
;	Z = 0 -> Zeichen in A
;	Register: A
KBDM	LD	A,SIO_WR0		;	
	OUT	(SIOA_CTL),A		; Address Register RR0
	IN	A,(SIOA_CTL)		; Read RR0
	AND	SIO_RXA			; RX Character available ?
	RET	Z			; NEIN, Return mit Akku = 00 und Z = 1
	IN	A,(SIOA_DAT)		; Ja, Character einlesen
	OR	A			; Z = 0
	RET				;			
;--------------------------------------------------
;	KBD liest ASII-Character von der seriellen Schnittstelle 0
; IN	-
; OUT	A = ASCII Character
KBD	Call	KBDM			; Character available ?
	OR	A			;
	JR	Z,KBD			; nein, warten
	IN	A,(SIOA_DAT)		; Ja, Character einlesen
	RET				; und RETURN
;--------------------------------------------------
MO_END	DB	0FFH		; 
;--------------------------------------------------
;	RAM Speicherzellen
BUFF	DS	16		; reserve 16 Bytes 
AHEXB	DS	3		; reserve 3 Bytes 
ARG1	DS	2		; reserve 2 Bytes
ARG2	DS	2		; reserve 2 Bytes
BREAD	DS	2		; reserve 2 Bytes
BREBU	DS	3		; reserve 3 Bytes
LD_OK	DS	2		; Flag, Monitor loaded to RAM
TSTRAM	DS	2		; 1st. Memory TEST Loc.
;
END 



