****************************************************************
* Z80-Assembler fr ATARI ST                                   *
* Copyright (c) Jens Mller, O-6501 Frankenau, Nr.66           *
* 15.08.1992                                                   *
*                                                              *
* Dieser Quelltext darf fr nichtkommerzielle Zwecke           *
* (Hobby, Lehre usw.) verwendet werden.                        *
*                                                              *
* Es ist nicht gestattet, das Copyright im Quelltext oder im   *
* ausfhrbaren Programm zu entfernen oder die  Urheberschaft   *
* anderwertig zu verschleiern oder zu ver„ndern.               *
*                                                              *
* Žnderungen zum Original sind entsprechend zu markieren.      *
****************************************************************

* entwickelt und assembliert mit DevpacST 2.08 von HiSoft

* Kommandozeile:  [-Option1] [-Option2] [-...] Dateiname

	output	.TTP

	include	"C:\TOSDEF.S"


BYTE_BUF_LEN	equ	256
MAX_CODE	equ	4		* max. Anz. Code-Bytes im Listing


*** Macros ************************************************

puts	macro	string
	move.l	\1,-(sp)
	call_gemdos Cconws
	addq.l	#6,sp
	endm

error	macro	number
	moveq.w	\1,d0
	bsr	out_err
	endm

warning	macro	text
	move.l	a0,-(sp)
	lea	\1(pc),a0
	bsr	out_wrn
	move.l	(sp)+,a0
	endm


*** Hauptprogramm *****************************************

	section	text

	move.l	4(sp),a6		* Basepage
	move.l	sp,a5
	lea	mystack(pc),sp
	sub.l	#$2000,a5		* 8k freigeben
	cmp.l	#buffer,a5
	bhi.s	buf_ok
	error	#2
	bra.w	prg_end
buf_ok	move.l	#buffer,source_ptr	* Zeiger auf Quelltext
	move.l	a5,end_ptr
	sub.l	a6,a5			* benutzte L„nge
	move.l	a5,-(sp)		* Speicher freigeben
	move.l	a6,-(sp)
	clr.w	-(sp)
	call_gemdos Mshrink
	lea	$C(sp),sp
	puts	#titel
	clr.w	line			* aktuelle Zeilennummer
	clr.w	err_ln			* Zeilennummer 1. Fehler
	move.l	a6,a0
	add.l	#$80,a0			* Zeiger auf Kommandozeile
	clr.l	d0
	move.b	(a0)+,d0		* L„nge Kommandozeile
	bne.s	chk_cmd
	move.l	a0,a5
	puts	#t_cmd
	subq.l	#1,a5
	move.b	#122,(a5)
	move.l	a5,-(sp)
	call_gemdos Cconrs
	addq.l	#6,sp
	puts	#t_cs2nl
	move.l	a5,a0
	addq.l	#1,a0
	clr.l	d0
	move.b	(a0)+,d0
chk_cmd	cmp.b	#124,d0
	bls.s	ldt_str
	move.b	#124,d0
ldt_str	move.b	#0,(a0,d0)		* Null-terminiert
	clr.b	A_flag
	clr.b	B_flag
	clr.b	C_flag
	clr.b	J_flag
	clr.b	L_flag
	clr.b	S_flag
next_op	bsr	atxt
	cmp.b	#'-',(a0)+
	bne.s	tstfile
	move.b	(a0)+,d0
	bsr	upcase
	cmp.b	#'A',d0
	bne.s	B_op
	move.b	#-1,A_flag
	bra.s	next_op
B_op	cmp.b	#'B',d0
	bne.s	C_op
	move.b	#-1,B_flag
	bra.s	next_op
C_op	cmp.b	#'C',d0
	bne.s	J_op
	move.b	#-1,C_flag
	bra.s	next_op
J_op	cmp.b	#'J',d0
	bne.s	L_op
	move.b	#-1,J_flag
	bra.s	next_op
L_op	cmp.b	#'L',d0
	bne.s	S_op
	move.b	#-1,L_flag
	bra.s	next_op
S_op	cmp.b	#'S',d0
	bne.s	wro_op
	move.b	#-1,S_flag
	bra.s	next_op
wro_op	error	#0
	puts	#t_crsnl
	bra.s	help
tstfile	subq.l	#1,a0
	move.l	a0,cmd_ptr
	tst.b	(a0)
	beq.s	help
	bsr	as_main
	bra.s	prg_end
help	puts	#t_help
prg_end	puts	#t_quit
	call_gemdos Crawcin
	addq.l	#2,sp
	puts	#t_crsnl
	move.w	err_ln,-(sp)		* Nummer der 1. fehlerhaften Zeile
	call_gemdos Pterm


	section	data

titel	dc.b	'Z80-Assembler Version 1.0 PD',13,10
	dc.b	'(c) Jens Mller - 15.08.1992',13,10,10,0
t_cmd	dc.b	'Kommandozeile: ',0
t_help	dc.b	'Format der Kommandozeile:',13,10
	dc.b	'  [-Option1] [-...] Dateiname',13,10,10
	dc.b	'Optionen:',13,10
	dc.b	'  -A   Pass 2 auch bei Fehler in Pass 1',13,10
	dc.b	'  -B   keine Bin„rdatei (*.BIN)',13,10
	dc.b	'  -C   Grož/klein unterscheiden',13,10
	dc.b	'  -J   nur absolute Sprnge',13,10
	dc.b	'  -L   Listing ausgeben (*.LST)',13,10
	dc.b	'  -S   Symboltabelle ausgeben (*.LST)',13,10,10
	dc.b	'UNDO   Abbruchtaste',13,10,10,0

t_quit	dc.b	13,10,'Taste drcken...',0
t_cs2nl	dc.b	13,10
t_crsnl	dc.b	13,10,0


	section	bss

A_flag	ds.b	1
B_flag	ds.b	1
C_flag	ds.b	1
J_flag	ds.b	1
L_flag	ds.b	1
S_flag	ds.b	1
	even
cmd_ptr	ds.l	1
line	ds.w	1
err_ln	ds.w	1
	

*** Fehlerausschrift und Warnungen ************************

	section	text

* Zeilennummer ausgeben
o_line	move.w	d0,-(sp)
	puts	#t_line
	move.w	line,d0
	bsr	outdez
	puts	#t_dp
	move.w	(sp)+,d0
	rts

* Warnung ausgeben
out_wrn	movem.l	d0-d2/a0-a2,-(sp)
	move.l	a0,-(sp)
	bsr	o_line
	puts	#t_warn
	call_gemdos Cconws
	addq.l	#6,sp
	movem.l	(sp)+,d0-d2/a0-a2
	rts

* d0.w Fehlernumer
out_err	movem.l	d0-d2/a0-a2,-(sp)
	clr.b	term_flag
	tst.w	line
	beq.s	o_er_st			* Systemfehler
	tst.w	err_ln
	bne.s	o_errln
	move.w	line,err_ln		* 1. fehlerhafte Zeile
o_errln	bsr.s	o_line
o_er_st	lea	err_tab(pc),a0
o_err1	tst.w	d0
	beq.s	o_err3
o_err2	tst.b	(a0)+
	bne.s	o_err2
	subq.w	#1,d0
	bra.s	o_err1
o_err3	puts	a0
	puts	#t_crsnl
	add.w	#1,num_err
	movem.l	(sp)+,d0-d2/a0-a2
	rts


	section	data

t_line	dc.b	'Zeile ',0
t_dp	dc.b	': ',0
t_warn	dc.b	'Warnung!  ',0
err_tab	dc.b	'Falsche Option',0				* 0
	dc.b	'Datei kann nicht ge”ffnet werden',0		* 1
	dc.b	'Zu wenig Speicher',0				* 2
	dc.b	'Datei kann nicht gelesen werden',0		* 3
	dc.b	'Unzul„ssige Marke',0				* 4
	dc.b	'Marke mehrfach definiert',0			* 5
	dc.b	'Konstante fehlerhaft',0			* 6
	dc.b	'Marke nicht gefunden',0			* 7
	dc.b	'šberflssiges Zeichen',0			* 8
	dc.b	'Marke + ORG nicht erlaubt',0			* 9
	dc.b	'EQU ohne Marke',0				* 10
	dc.b	'Fehlender Operand',0				* 11
	dc.b	'Falscher Operand',0				* 12
	dc.b	'Klammer erwartet',0				* 13
	dc.b	'Komma erwartet',0				* 14
	dc.b	'Operanden passen nicht zusammen',0		* 15
	dc.b	'Relative Sprungdistanz zu grož',0		* 16
	dc.b	'Unbekannte Mnemonik',0				* 17
	dc.b	'Offset zu grož',0				* 18
	dc.b	'Zu viele erzeugte Bytes',0			* 19
	dc.b	'Fehlendes String-Ende',0			* 20
	dc.b	'Ausgabe wrde Quelldatei l”schen',0		* 21
	dc.b	'Ausgabeatei kann nicht angelegt werden',0	* 22
	dc.b	'Datei kann nicht geschrieben werden',0		* 23
	dc.b	'Laufwerk voll',0				* 24
	dc.b	'Division durch Null',0				* 25


	section	bss

	even
num_err	ds.w	1


*** Assembler aufrufen ************************************

	section	text

as_main	move.l	a0,a6			* Dateiname
	clr.w	-(sp)			* Quelldatei ”ffnen
	move.l	a6,-(sp)
	call_gemdos Fopen
	addq.l	#8,sp
	tst.w	d0
	bpl.s	open_ok
	error	#1
	rts
open_ok	move.w	d0,f_handle
	move.w	#2,-(sp)		* Dateil„nge ermitteln
	move.w	f_handle,-(sp)
	clr.l	-(sp)
	call_gemdos Fseek
	lea	$A(sp),sp
	move.l	d0,d7
	add.l	source_ptr,d0
	move.l	d0,d1
	add.l	#$1000,d1		* min. 4k fr anderes
	cmp.l	end_ptr,d1
	bcs.s	len_ok
	bsr	f_close
	error	#2
	rts
len_ok	move.l	d0,symb_ptr
	clr.w	-(sp)			* Dateizeiger auf Anfang
	move.w	f_handle,-(sp)
	clr.l	-(sp)
	call_gemdos Fseek
	lea	$A(sp),sp
	move.l	source_ptr,-(sp)	* Quelldatei einlesen
	move.l	d7,-(sp)
	move.w	f_handle,-(sp)
	call_gemdos Fread
	lea	$C(sp),sp
	cmp.l	d7,d0
	beq.s	read_ok
	bsr	f_close
	error	#3
	rts
read_ok	move.l	symb_ptr,a0
	move.b	#$1A,(a0)+
	move.b	#$1A,(a0)+
	clr.b	(a0)			* Symboltabelle l”schen
	move.l	a0,symb_ptr
	bsr	pass1
	tst.b	A_flag
	bne.s	exe_ps2
	tst.w	num_err
	bne.s	o_numer
exe_ps2	bsr	pass2
o_numer	puts	#t_crsnl
	clr.l	d0
	move.w	num_err,d0
	bsr	outdez
	puts	#t_error
	move.w	line,d0
	sub.w	#1,d0
	bsr	outdez
	puts	#t_eass1
	move.w	byte_cnt,d0
	bsr	outdez
	puts	#t_eass2
	rts


	section	data

t_error	dc.b	' Fehler',13,10,0
t_eass1	dc.b	' Zeilen in ',0
t_eass2	dc.b	' Bytes assembliert.',13,10,0



	section	bss

lab_flag	ds.b	1
		even
source_ptr	ds.l	1
symb_ptr	ds.l	1
code_ptr	ds.l	1
end_ptr		ds.l	1
f_handle	ds.w	1


*** Pass 1 ************************************************

	section	text

pass1	move.l	symb_ptr,a0
	move.l	a0,code_ptr
	clr.b	(a0)
	move.w	#1,m_pass
	puts	#t_pass1
	clr.b	end_flag
	clr.w	prg_count		* pc des Z80
	clr.w	line
	move.l	source_ptr,a6
p1_loop	addq.w	#1,line
	tst.b	end_flag
	bne.s	p1_ret
	bsr	tst_brk
	cmp.b	#$1A,(a6)		* Textende?
	bne.s	tst_lab
p1_ret	rts
tst_lab	clr.b	lab_flag
	move.l	a6,a0
	bsr	esym
	cmp.l	a0,a6
	beq	p1_asm
	move.b	#-1,lab_flag		* Marke vorhanden
	cmp.b	#':',(a0)
	bne.s	lb_fnd1
	addq.l	#1,a0
lb_fnd1	cmp.b	#'0',(a6)		* beginnt Symbol mit Ziffer?
	bcs.s	lb_fnd2
	cmp.b	#'9',(a6)
	bhi.s	lb_fnd2
lab_err	error	#4			* ungltiges Symbol
	bra.w	p1asm1
lb_fnd2	bsr	atxt
	move.l	a0,a3			* Anfang Befehl
	bsr	etxt
	move.l	a0,a4			* hinter Befehl
	move.b	(a4),d7
	clr.b	(a4)
	move.l	a3,a0
	lea	t_EQU(pc),a1
	bsr	ustrcmp			* Test auf EQU
	move.b	d7,(a4)
	tst.w	d0
	bne.s	lab_pc
	move.l	a4,a0			* EQU-Wert berechnen
	move.w	#2,m_pass
	bsr	term
	move.w	#1,m_pass
	bsr	syntax
	bra.s	lb_entr
lab_pc	move.w	prg_count,d0		* kein EQU -> Marke = pc
lb_entr	move.l	a6,a0			* Symbol in Tabelle eintragen
	bsr	esym
	move.l	a0,a5
	move.b	(a5),d7
	clr.b	(a5)
	move.l	a6,a0			* a0: Zeiger auf Symbol
	move.l	a5,d1
	sub.l	a6,d1			* Symboll„nge in d1.l
	bsr	lab_entry		* Symdolwert in d0.w
	move.b	d7,(a5)
	move.l	a5,a6			* hinter Symbol
	cmp.b	#':',(a6)		* Doppelpunkt hinter Marke
	bne.s	p1_asm
	addq.l	#1,a6
p1_asm	move.l	a6,a0
p1asm1	bsr	assem
	move.w	d1,prg_count
p1_n_ln	move.l	a6,a0
	bsr	next_ln
	move.l	a0,a6
	bra.w	p1_loop


* Symbol alphabetisch geordnet in Tabelle eintragen
* d0.w  Symbolwert
* d1.w  Symboll„nge
* a0    Zeiger auf Symbol (null-terminiert)
* a5,a6,d7: unver„ndert
lab_entry
	move.l	symb_ptr,a4
	move.l	a0,a3
	move.w	d0,d6
l_e_lp	tst.b	(a4)
	beq.s	l_ent
	move.l	a3,a0			* Zeiger auf Symbol
	move.l	a4,a1
	bsr	strcmp
	tst.w	d0
	bmi.s	l_ent			* an dieser Stelle eintragen
	bne.s	l_nofnd			* String 1 > String 2
	error	#5
	rts
l_nofnd	tst.b	(a1)+			* Symbolende suchen
	bne.s	l_nofnd
	addq.l	#2,a1			* auf n„chsten Eintrag
	move.l	a1,a4
	bra.s	l_e_lp
l_ent	move.l	code_ptr,a0		* bisheriges Symboltabellenende
	move.l	a0,a1
	add.l	d1,a1
	addq.l	#3,a1			* neues Symboltabellenende
	cmp.l	end_ptr,a1		* noch Platz?
	bcs.s	l_m_ok
	error	#2			* kein Platz
	bra	prg_end
l_m_ok	move.l	a1,code_ptr		* neues Symboltabellenende
	clr.b	(a1)
l_entr1	cmp.l	a0,a4			* Tabellenrest nach hinten
	beq.s	l_entr2
	move.b	-(a0),-(a1)
	bra.s	l_entr1
l_entr2	subq.w	#1,d1			* Symboll„nge - 1
l_entr3	move.b	(a3)+,d0		* Symbol eintragen
	tst.b	C_flag
	bne.s	l_entr4
	bsr	upcase			* nur grož
l_entr4	move.b	d0,(a4)+
	dbf	d1,l_entr3
	clr.b	(a4)+
	move.b	d6,(a4)+		* Wert (2 Byte) im INTEL-Format
	lsr.w	#8,d6			* dahinter eintragen
	move.b	d6,(a4)+
	rts


	section	data

t_pass1	dc.b	'Pass 1',13,10,0


	section	bss

end_flag	ds.b	1
		even
prg_count	ds.w	1
m_pass		ds.w	1


*** Pass 2 ************************************************

	section	text

pass2	move.w	#2,m_pass
	puts	#t_pass2
	clr.b	end_flag
	clr.w	line
	add.l	#1,code_ptr		* Symboltabellenende (0-Byte) bergehen
	move.l	cmd_ptr,a0		* Name Ausgabedatei erzeugen
	lea	lst_path(pc),a1
	bsr	ustrcpy
	move.w	#'\',d0			* Dateinamenanfang suchen
	lea	lst_path,a0
	bsr	strrchr
	cmp.l	#0,a0
	bne.s	pass2_1
	lea	lst_path(pc),a0
pass2_1	move.l	a0,a2
	move.w	#'.',d0			* Extension suchen
	bsr	strrchr
	cmp.l	#0,a0
	beq.s	pass2_2
	clr.b	(a0)			* Extension abtrennen
pass2_2	lea	lst_path(pc),a0
	lea	bin_path(pc),a1
	bsr	strcpy
	move.b	L_flag,d0
	or.b	S_flag,d0
	beq.s	pass2_5			* kein Listing/Symboltabelle
	lea	t_lst(pc),a0
	lea	lst_path(pc),a1
	bsr	strcat
	move.l	cmd_ptr,a0
	lea	lst_path(pc),a1
	bsr	ustrcmp
	tst.w	d0
	bne.s	pass2_3
	clr.b	L_flag			* Flags fr Listing l”schen
	clr.b	S_flag			* wrde Quelldatei l”schen
	error	#21
	bra.s	pass2_5
pass2_3	clr.w	-(sp)			* Listing-Datei anlegen
	pea	lst_path
	call_gemdos Fcreate
	addq.l	#8,sp
	move.w	d0,f_handle
	tst.w	d0
	bpl.s	pass2_4
	clr.b	L_flag
	clr.b	S_flag
	error	#22
pass2_4	lea	f_titel(pc),a0		* Titel fr Listing-Datei schreiben
	move.l	#eoftitl-f_titel,d0
	bsr	f_write
pass2_5	clr.w	prg_count		* pc des Z80
	clr.w	byte_cnt		* Z„hler fr erzeugte Bytes
	move.l	code_ptr,code_index	* Zeiger auf aktuelle Codeposition
	move.l	source_ptr,a6
p2_loop	add.w	#1,line
	tst.b	end_flag
	bne.s	p2_ret
	bsr	tst_brk
	cmp.b	#$1A,(a6)		* Textende?
	bne	p2_mark
p2_ret	tst.b	S_flag
	beq.s	p2ret1
	bsr	foutnl			* Symboltabelle sichern
	tst.b	wr_err_flag
	bne.s	p2ret1
	move.l	symb_ptr(pc),a3
p2sa_sm	tst.b	(a3)
	beq.s	p2ret1
	move.l	a3,a4
p2sasm1	tst.b	(a4)+			* Symbolende suchen
	bne.s	p2sasm1
	move.b	1(a4),d0		* H-Byte
	lsl.w	#8,d0
	move.b	(a4),d0			* L-Byte
	bsr	fouthex			* Wert schreiben
	tst.b	wr_err_flag
	bne.s	p2ret1
	move.l	a4,d0
	sub.l	a3,d0
	subq.l	#1,d0			* Symboll„nge
	move.l	a3,a0
	bsr	f_write			* Symbolname schreiben
	tst.b	wr_err_flag
	bne.s	p2ret1
	bsr	foutnl			* neue Zeile
	tst.b	wr_err_flag
	bne.s	p2ret1
	addq.l	#2,a4
	move.l	a4,a3
	bra.s	p2sa_sm
p2ret1	move.b	L_flag,d0
	or.b	S_flag,d0
	beq.s	p2ret2
	bsr	f_close			* Listingdatei schliežen
p2ret2	tst.b	B_flag
	bne	p2ret3			* keine Bin„rdatei
	move.l	code_index,d0
	cmp.l	code_ptr,d0
	beq	p2ret3			* keine Bytes erzeugt
	lea	t_bin(pc),a0		* Name Bin„rdatei erzeugen
	lea	bin_path,a1
	bsr	strcat
	move.l	cmd_ptr,a0
	lea	bin_path(pc),a1
	bsr	ustrcmp
	tst.w	d0
	bne.s	p2sacod
	error	#21			* gleicher Name wie Quelltext
	bra.s	p2ret3
p2sacod	clr.w	-(sp)			* Bin„rdatei anlegen
	pea	bin_path
	call_gemdos Fcreate
	addq.l	#8,sp
	move.w	d0,f_handle
	tst.w	d0
	bpl.s	p2save
	error	#22
	bra.s	p2ret3
p2save	move.l	code_ptr,a0		* Bin„rdatei schreiben
	move.l	code_index,d0
	sub.l	a0,d0
	bsr	f_write
	bsr	f_close
p2ret3	rts
p2_mark	move.l	a6,boln			* Anfang Zeile
	clr.b	lab_flag
	move.l	a6,a0			* evtl. Marke bergehen
	bsr	esym
	cmp.l	a0,a6
	beq.s	p2mark1			* keine Marke
	move.b	#-1,lab_flag		* Marke vorhanden
	cmp.b	#':',(a0)
	bne.s	p2mark1
	addq.l	#1,a0
p2mark1	bsr	assem
	move.l	a0,a5			* -> erzeugte Bytes
	move.l	d0,d6			* Anzahl Bytes
	move.w	d1,d7
	add.w	d0,byte_cnt		* Z„hler erzeugte Bytes
	tst.b	B_flag
	bne.s	p2_list			* keine Bin„rdatei
	move.l	code_index,a1
	move.l	a1,d1
	add.l	d0,d1			* Anz. erzeugte Bytes
	cmp.l	end_ptr,d1		* noch Platz fr Code-Bytes?
	bcs.s	p2_code
	error	#2			* Zu wenig Speicher
	move.b	#-1,B_flag		* Bin„rdatei unterdrcken
	bra.s	p2_list
p2_code	tst.w	d0			* Code-Bytes ablegen
	beq.s	p2code1
	move.b	(a0)+,(a1)+
	subq.l	#1,d0
	bra.s	p2_code
p2code1	move.l	a1,code_index
p2_list	tst.b	L_flag
	beq	p2_next
	clr.l	d0
	move.b	defs_flag,d0
	or.b	d6,d0
	bne.s	p2_l_wa
	lea	filebuf(pc),a0
	moveq.w	#13,d0			* 14 * Space
p2_l_sp	move.b	#$20,(a0)+		* Adresss- und Code-Spalte
	dbf	d0,p2_l_sp			* bergehen
	bra.s	p2list4
p2_l_wa	move.w	prg_count,d0
	bsr	fouthex			* Adresse schreiben
	tst.b	wr_err_flag
	bne	p2_next
	lea	filebuf(pc),a0
	moveq.w	#MAX_CODE-1,d2		* max. 4 Bytes schreiben
p2list1	tst.w	d6			* noch Bytes zu schreiben?
	beq.s	p2list2
	move.b	(a5)+,d0
	bsr	htoa
	subq.w	#1,d6
	bra.s	p2list3
p2list2	move.b	#$20,(a0)+		* da keine Bytes mehr
	move.b	#$20,(a0)+
p2list3	dbf	d2,p2list1
p2list4	move.b	#$9,(a0)+
	move.w	line,d0
	bsr	uitoa
	move.b	#$9,(a0)+		* Puffer vorbereitet
	move.l	a0,d0
	lea	filebuf(pc),a0
	sub.l	a0,d0			* L„nge Puffer
	bsr	f_write
	tst.b	wr_err_flag
	bne	p2_next			* Fehler beim Schreiben
	move.l	boln,a0			* Anfang Quelltextzeile
	move.l	a0,a1
p2list5	move.b	(a1),d0			* Ende Quelltextzeile suchen
	beq.s	p2list6
	cmp.b	#$0A,d0
	beq.s	p2list6
	cmp.b	#$0D,d0
	beq.s	p2list6
	cmp.b	#$1A,d0
	beq.s	p2list6
	cmp.b	#$1E,d0
	beq.s	p2list6
	addq.l	#1,a1
	bra.s	p2list5
p2list6	move.l	a1,d0
	sub.l	a0,d0
	bsr	f_write			* Quelltextzeile schreiben
	tst.b	wr_err_flag
	bne.s	p2_next
	bsr	foutnl			* Zeilenende
	tst.b	wr_err_flag
	bne.s	p2_next
p2list7	tst.w	d6
	beq.s	p2_next
	add.w	#MAX_CODE,prg_count
	move.w	prg_count,d0
	bsr	fouthex
	lea	filebuf(pc),a0		* restliche erzeugte Bytes schreiben
	moveq.w	#MAX_CODE-1,d2
p2list8	tst.w	d6
	beq.s	p2list9
	move.b	(a5)+,d0
	bsr	htoa
	subq.w	#1,d6
	bra.s	p2lst10
p2list9	move.b	#$20,(a0)+
	move.b	#$20,(a0)+
p2lst10	dbf	d2,p2list8
	move.b	#$0D,(a0)+		* Zeilenende
	move.b	#$0A,(a0)+
	move.l	a0,d0
	lea	filebuf(pc),a0
	sub.l	a0,d0			* L„nge Puffer
	bsr	f_write
	tst.b	wr_err_flag
	beq.s	p2list7			* Fehler -> Ende, sonst nochmal
p2_next	move.w	d7,prg_count
p2_n_ln	move.l	a6,a0
	bsr	next_ln
	move.l	a0,a6
	bra.w	p2_loop


	section	data

t_pass2	dc.b	'Pass 2',13,10,0
t_lst	dc.b	'.LST',0
t_bin	dc.b	'.BIN',0
f_titel	dc.b	'Z80-Assembler fr ATARI ST - V1.0 PD',13,10
	dc.b	'Copyright (c) Jens Mller 15.08.1992',13,10,13,10
eoftitl					* Ende des Titels fr .LST-File


	section	bss

		even
byte_cnt	ds.w	1
boln		ds.l	1
code_index	ds.l	1
lst_path	ds.b	128
bin_path	ds.b	128


*** Mathematischer Ausdruck berechnen *********************

	section	text

* INPUT : a0   : Zeiger auf ASCII-Term
* OUTPUT: d0.w : Wert, a0: zeigt auf n„chstes Zeichen
term	move.b	#-1,term_flag		* berechneter Wert ist gltig
	bsr	atxt
	clr.l	d0
	cmp.b	#'+',(a0)+		* Vorzeichen
	beq.s	frst_c
	cmp.b	#'-',-(a0)
	beq.s	minus
frst_c	bsr.s	tm_mul			* erste Konstante
next_c	cmp.b	#'+',(a0)
	bne.s	tst_mi
	move.w	d0,-(sp)
	addq.l	#1,a0
	bsr.s	tm_mul
	add.w	(sp)+,d0
	bra.s	next_c
tst_mi	cmp.b	#'-',(a0)
	beq.s	minus
	rts
minus	addq.l	#1,a0
	move.w	d0,-(sp)
	bsr.s	tm_mul
	move.w	(sp)+,d1
	sub.w	d0,d1
	exg	d0,d1
	bra.s	next_c


* Berechnung eines multiplikativen Ausdrucks
tm_mul	bsr.s	tm_cnst
tm_mul1	cmp.b	#'*',(a0)
	bne.s	tm_mul2
	addq.l	#1,a0
	move.w	d0,-(sp)
	bsr.s	tm_cnst
	mulu	(sp)+,d0
	bra.s	tm_mul1
tm_mul2	cmp.b	#'/',(a0)
	bne.s	tm_mul4
	addq.l	#1,a0
	move.w	d0,-(sp)
	bsr.s	tm_cnst
	move.w	d0,d1
	clr.l	d0
	move.w	(sp)+,d0
	tst.w	d1
	bne.s	tm_mul3
	error	#25			* Division durch Null
	bra.s	tm_mul4
tm_mul3	divu	d1,d0
	bra.s	tm_mul1
tm_mul4	rts


* Berechnung einer Konstante, entweder Literal oder Symbol
* muž vorhanden sein
* a0: Zeiger auf Konstante
* d0: Wert
tm_cnst	move.b	(a0),d0
	cmp.w	#"'",d0
	beq.s	tm_cnt1
	cmp.w	#'"',d0
	bne.s	tm_cnt3
tm_cnt1	addq.l	#1,a0			* char-Zeichen
	cmp.b	1(a0),d0
	beq.s	tm_cnt2
	error	#20
	clr.l	d0
	rts
tm_cnt2	clr.l	d0
	move.b	(a0),d0
	addq.l	#2,a0
	rts
tm_cnt3	cmp.b	#'(',d0
	bne.s	cn_tstl
	bsr	fkt
	rts
cn_tstl	bsr	upcase
	cmp.b	#'L',d0
	bne.s	cn_tsth
	cmp.b	#'(',1(a0)
	beq.w	low
cn_tsth	cmp.b	#'H',d0
	cmp.b	#'(',1(a0)
	bne.s	cn_goon
	beq.w	high
cn_goon	clr.l	d0
	cmp.b	#'%',(a0)
	beq.s	inbin
	cmp.b	#'$',(a0)
	beq.s	inhex
	cmp.b	#'#',(a0)
	beq.s	inhex
	cmp.b	#'0',(a0)
	bcs.w	insym
	cmp.b	#'9',(a0)
	bhi.w	insym
	move.l	a0,-(sp)
	bsr.s	inhex1
	move.l	(sp)+,a1
	cmp.b	#'H',(a0)
	beq.s	o_hex
	cmp.b	#'h',(a0)
	beq.s	o_hex
	move.l	a1,a0			* Dezimalzahl
	clr.l	d0
indez	clr.w	d1
	move.b	(a0),d1
	sub.b	#'0',d1
	bcs.s	c_ret
	cmp.b	#9,d1
	bhi.s	c_ret
	mulu	#10,d0
	and.l	#$FFFF,d0
	add.w	d1,d0
	addq.l	#1,a0
	bra.s	indez
o_hex	addq.l	#1,a0			* war Hexzahl "XXXXH"
c_ret	rts
inbin	addq.l	#1,a0			* Bin„rzahl berechnen
	clr.w	d1
	move.b	(a0),d1
	sub.b	#'0',d1
	bcs.s	inbin1
	cmp.b	#1,d1
	bhi.s	inbin1
	lsl.w	#1,d0
	or.w	d1,d0
	bra.s	inbin
inbin1	cmp.b	#'%',-(a0)
	bne.s	bin_ret
	error	#6
bin_ret	addq.l	#1,a0
	rts
inhex	addq.l	#1,a0			* Hexzahl berechnen
inhex1	clr.w	d1
	move.b	(a0),d1
	exg	d0,d1
	bsr	upcase
	exg	d0,d1
	sub.b	#'0',d1
	bcs.s	inhex3
	cmp.b	#9,d1
	bls.s	inhex2
	sub.b	#7,d1
	bcs.s	inhex3
	cmp.b	#$F,d1
	bhi.s	inhex3
inhex2	lsl.w	#4,d0
	or.w	d1,d0
	bra.s	inhex
inhex3	cmp.b	#'$',-(a0)
	beq.s	inhex4
	cmp.b	#'#',(a0)
	bne.s	hex_ret
inhex4	error	#6
hex_ret	addq.l	#1,a0
	rts
* Marke (a0) in Symboltabelle suchen und Wert (d0.w) ausgeben
insym	movem.l	a1-a3/d7,-(sp)
	cmp.w	#2,m_pass
	beq.s	insym1
	bsr	esym
	clr.b	term_flag		* Wert ungltig
	clr.l	d0
	bra.s	isymret
insym1	move.l	a0,a2
	bsr	esym			* Symbolende
	move.l	a0,a3
	cmp.l	a2,a3			* echte Marke?
	bne.s	isym_ok
	error	#11
	clr.l	d0
	bra.s	i_sm_rt
isym_ok	move.b	(a3),d7
	clr.b	(a3)			* Symbol abtrennen
	move.l	symb_ptr,a1		* Symboltabellenanfang
i_sm_lp	tst.b	(a1)
	bne.s	insym2
	error	#7			* nicht gefunden
	clr.l	d0
	bra.s	i_sm_rt
insym2	move.l	a2,a0
	bsr	strcmp
	tst.w	d0
	beq.s	ism_fnd
nx_sym	tst.b	(a1)+			* n„chster Eintrag
	bne.s	nx_sym
	add.w	#2,a1			* Wert-Bytes bergehen
	bra.s	i_sm_lp
ism_fnd	clr.l	d0			* gefunden
	move.b	1(a1),d0		* H-Byte lesen (INTEL-Format)
	lsl.w	#8,d0
	move.b	(a1),d0			* L-Byte
i_sm_rt	move.b	d7,(a3)
	move.l	a3,a0
isymret	movem.l	(sp)+,a1-a3/d7
	rts

* Low- bzw. High-Byte eines 16-Bit-Ausdrucks errechnen
low	addq.l	#1,a0
	bsr.s	fkt
	and.w	#$FF,d0
	rts
high	addq.l	#1,a0
	bsr.s	fkt
	lsr.w	#8,d0
	rts

fkt	cmp.b	#'(',(a0)+
	bne.s	fkt_err
	bsr.w	term
	cmp.b	#')',(a0)+
	beq.s	fkt_ret
fkt_err	error	#13
	clr.l	d0
fkt_ret	rts


	section	bss

term_flag	ds.b	1


*** Befehl assemblieren ***********************************

	section	text

* Befehl (a0) assemblieren
* OUTPUT: a0: zeigt auf erzeugte Bytefolge
*         d0: Anzahl der Bytes
*         d1: neuer pc des Z80 (prg_count)
assem	movem.l	d2-d7/a1-a6,-(sp)
	clr.b	defs_flag
	bsr	atxt
	move.l	a0,a4
	bsr	esym
	move.l	a0,a5
	move.b	(a5),d7
	clr.b	(a5)
	lea	tab_i1(pc),a1
	lea	tab_jp1(pc),a3
lp_w_op	tst.b	(a1)
	beq.s	se_o_op			* kein Befehl mit m”glichen Operand
	move.l	a4,a0			* Befehl im Quelltext
	bsr	ustrcmp
	tst.w	d0
	beq.s	wop_fnd
nx_o_op	tst.b	(a1)+
	bne.s	nx_o_op
	addq.l	#4,a3			* n„chste Adresse
	bra.s	lp_w_op
wop_fnd	move.b	d7,(a5)
	move.l	a5,a0			* zeigt hinter Befehl
	move.l	(a3),a3			* Anfangsaddresse der Routine
	lea	byte_buf(pc),a1		* Puffer fr erzeugte Bytes
	jsr	(a3)			* Routine anspringen
	bra	asm_ret
se_o_op	lea	tab_i2(pc),a3		* Befehl ohne Operand suchen
lp_o_op	move.l	a4,a0			* Befehl im Quelltext
	tst.b	(a3)
	beq.s	pc_inst
	move.l	a3,a1
	bsr	ustrcmp
	tst.w	d0
	beq.s	ins_fnd
nx_ist	tst.b	(a1)+			* n„chster Befehl in Tabelle suchen
	bne.s	nx_ist
	clr.l	d0
	move.b	(a1)+,d0		* Code-Bytes
	add.l	d0,a1
	move.l	a1,a3
	bra.s	lp_o_op
ins_fnd	clr.l	d0			* Befehl gefunden
	move.b	(a1)+,d0		* wieviel Bytes?
	move.b	d7,(a5)
	bra	asm_ret
pc_inst	move.l	a4,a0			* Test auf DEFS,DS
	lea	t_DEFS(pc),a1
	bsr	ustrcmp			* DEFS?
	tst.w	d0
	beq.s	ds_fnd
	move.l	a4,a0
	lea	t_DS(pc),a1
	bsr	ustrcmp			* DS?
	tst.w	d0
	bne.s	asm_org
ds_fnd	bsr	op_num
	cmp.w	#25,d0
	beq.s	ds_opok
	error	#12
	bra.s	noinst1
ds_opok	add.w	prg_count,d1
	bsr	syntax
	clr.l	d0
	move.b	#-1,defs_flag
	move.b	d7,(a5)
	bra.s	asmret1
asm_org	move.l	a4,a0			* Test auf ORG
	lea	t_ORG(pc),a1
	bsr	ustrcmp
	tst.w	d0
	bne.s	no_inst
	tst.b	lab_flag
	beq.s	asmorg1
	error	#9			* Marke + ORG nicht erlaubt
asmorg1	move.w	m_pass,-(sp)
	move.w	#2,m_pass		* auch im ersten Pass ORG berechnen
	bsr	term
	move.w	(sp)+,m_pass
	move.l	d0,d1
	cmp.w	prg_count,d1
	bcc.s	asmorg3
	warning	orgwarn
asmorg3	bsr	syntax
	clr.l	d0
	move.b	d7,(a5)
	bra.s	asmret1
no_inst	move.l	a4,a0			* voller Syntaxcheck
noinst1	move.b	d7,(a5)
	bsr	syntax1
	tst.w	d0
	beq.s	noinst2
	error	#17			* unbekannte Mnemonik
noinst2	clr.l	d0			* keine erzeugten Bytes
	move.w	prg_count,d1		* pc unver„ndert
	bra.s	asmret1
asm_ret	bsr	syntax
	move.l	a1,a0
	move.w	prg_count,d1
	add.w	d0,d1			* neuer pc des Z80
asmret1	movem.l	(sp)+,d2-d7/a1-a6
	rts


	section	data

t_DEFS	dc.b	'DEFS',0
t_DS	dc.b	'DS',0
t_ORG	dc.b	'ORG',0
orgwarn	dc.b	'ORG im alten Adressbereich',13,10,0


	section	bss

defs_flag	ds.b	1


*** Auswertung der Befehle mit m”glichen Operanden ********

* INPUT : a0: zeigt auf das erste Byte hinter den Befehl
*         a1: zeigt auf nutzbaren Puffer fr erzeugte Bytes
* OUTPUT: d0: Anzahl der erzeugten Bytes
*         a0: zeigt hinter den ausgewerteten Teil
*         a1: zeigt auf erzeugte Bytefolge
* pc des Z80 wird NICHT aktualisiert! (nur bei DEFS, DS)

	section	text

op_err1	error	#12			* Falscher Operand
	bra.s	op_err4
op_err2	error	#15			* Op passen nicht zusammen
	bra.s	op_err4
op_err3	error	#14			* Komma erwartet
op_err4	bsr	etxt
	bra.s	no_byte

r_EQU	tst.b	lab_flag
	bne.s	equ1
	error	#10			* EQU ohne Marke
equ1	bsr	atxt			* nur fr Syntaxcheck
	bsr	etxt
no_byte	clr.l	d0
	move.l	d0,a1
	rts

r_END	move.b	#-1,end_flag
	bra.s	no_byte


r_LD	bsr	two_op
	moveq.l	#1,d0			* meisten LD-Befehle 1 Byte
	move.w	d2,d1			* und 8 Bit
	lsl.w	#3,d1			* Kennung 1.Op * 8
	cmp.w	#7,d2			* Kennung 1.Op
	bhi	ld_1_8			* 1.Op ab Kennung 8 auswerten
	cmp.w	#7,d4
	bhi.s	ld7_8			* 2.Op auf >=8 bei 1.Op bis 7
	add.w	#$40,d1			* Grundcodebyte
	add.w	d4,d1			* + Kennung 2.Op fr 8 Bit
	cmp.w	#$76,d1			* LD (HL),(HL) ist HALT
	beq.s	op_err2			* -> Fehler
	move.b	d1,(a1)
	rts				* d0 bereits 1
ld7_8	cmp.w	#9,d4
	bhi.s	ld7_12
	cmp.w	#7,d2
	bne.s	op_err2			* nur LD A,(BC,DE) erlaubt
	sub.w	#8,d4			* Kennung $00 und $01
	lsl.w	#4,d4			* $00 oder $10
	add.w	#$0A,d4
	move.b	d4,(a1)
	rts				* d0 bereits 1
ld7_12	cmp.w	#12,d4
	bcs	op_err2
	cmp.w	#15,d4
	bhi.s	ld7_16
	cmp.w	#6,d2			* IXH-IYL nicht dokumentiert
	beq	op_err2			* LD (HL),IXH -> Fehler
	move.w	d4,d0
	bsr	c_ixy
	add.w	#$44,d1
	and.w	#1,d4			* H gerade, L ungerade
	or.w	d4,d1
	move.b	d1,1(a1)
	moveq.l	#2,d0
	rts
ld7_16	cmp.w	#17,d4
	bhi.s	ld7_25
	cmp.w	#7,d2
	bne	op_err2
	move.b	#$ED,(a1)
	move.b	#$57,1(a1)		* LD A,I
	cmp.w	#16,d4
	beq	e_2byte
	move.b	#$5F,1(a1)		* LD A,R
	bra	e_2byte
ld7_25	cmp.w	#25,d4
	bcs	op_err2
	bhi.s	ld7_26
	add.w	#$06,d1			* LD r,n
	move.b	d1,(a1)
	move.w	d5,d0
	bsr	chkbyte
	move.b	d0,1(a1)
	moveq.l	#2,d0
	rts
ld7_26	cmp.w	#27,d4
	bhi.s	ld7_28
	cmp.w	#6,d2
	beq	op_err2			* LD (HL),(IX+d) -> Fehler
	move.w	d4,d0
	bsr	c_ixy
	add.w	#$46,d1
	move.b	d1,1(a1)
	move.w	d5,d0
	move.b	d0,2(a1)
	moveq.l	#3,d0
	rts
ld7_28	cmp.w	#7,d2
	bne	op_err2
	move.b	#$3A,(a1)
	move.b	d5,1(a1)
	lsr.w	#8,d5
	move.b	d5,2(a1)
	moveq.l	#3,d0
	rts
ld_1_8	cmp.w	#9,d2
	bhi.s	ld_1_12
	cmp.w	#7,d4
	bne	op_err2			* nur LD (BC,DE),A erlaubt
	sub.w	#8,d2			* 0,1
	lsl.w	#4,d2			* $00,$10
	add.w	#$02,d2
	move.b	d2,(a1)
	moveq.l	#1,d0
	rts
ld_1_12	cmp.w	#12,d2			* 1.Op = 12?
	bcs	op_err1
	cmp.w	#15,d2
	bhi.s	ld_1_16
	move.w	d2,d0
	bsr	c_ixy
	and.w	#1,d0			* 0: H, 1: L
	lsl.w	#3,d0
	cmp.w	#7,d4
	bhi.s	ld12_25			* 2.Op auf 25 bei 1.Op bis 12 testen
	cmp.w	#6,d4
	beq	op_err2			* LD IXH,(HL) -> Fehler
	add.w	#$60,d0
	add.w	d4,d0
	move.b	d0,1(a1)
	moveq.l	#2,d0
	rts
ld12_25	cmp.w	#25,d4
	bne	op_err2
	add.w	#$26,d0
	move.b	d0,1(a1)
	move.w	d5,d0
	bsr	chkbyte
	move.b	d0,2(a1)
	moveq.l	#3,d0
	rts
ld_1_16	cmp.w	#17,d2
	bhi.s	ld_1_18
	cmp.w	#7,d4
	bne	op_err2			* nur LD IR,A
	move.b	#$ED,(a1)
	move.b	#$47,1(a1)
	cmp.w	#16,d2
	beq.s	e_2byte
	move.b	#$4F,1(a1)
e_2byte	moveq.l	#2,d0
	rts
ld_1_18	cmp.w	#19,d2
	bhi.s	ld_1_20
	sub.w	#18,d2			* 0,1
	lsl.w	#4,d2			* $00,$10
	cmp.w	#25,d4
	bcs	op_err2
	bhi.s	ld18_28
	add.w	#$01,d2			* LD BCDE,nn
	move.b	d2,(a1)
	move.b	d5,1(a1)
	lsr.w	#8,d5
	move.b	d5,2(a1)
	moveq.l	#3,d0
	rts
ld18_28	cmp.w	#28,d4
	bne	op_err2
	move.b	#$ED,(a1)		* LD BCDE,(nn)
	add.w	#$4B,d2
	move.b	d2,1(a1)
	move.b	d5,2(a1)
	lsr.w	#8,d5
	move.b	d5,3(a1)
	moveq.l	#4,d0
	rts
ld_1_20	cmp.w	#20,d2
	bhi.s	ld_1_22
	cmp.w	#25,d4
	bcs	op_err2
	bhi.s	ld20_28
	move.b	#$21,(a1)		* LD HL,nn
	bra	wr_wd1
ld20_28	cmp.w	#28,d4
	bne	op_err2
	move.b	#$2A,(a1)		* LD HL,(nn)
	bra	wr_wd1
ld_1_22	cmp.w	#22,d2
	bcs	op_err1
	cmp.w	#23,d2
	bhi.s	ld_1_24
	move.w	d2,d0
	bsr	c_ixy
	cmp.w	#25,d4
	bcs	op_err2
	bhi.s	ld22_28
	move.b	#$21,1(a1)		* LD IXY,nn
	bra	wr_wd2
ld22_28	cmp.w	#28,d4
	bne	op_err2
	move.b	#$2A,1(a1)		* LD IXY,(nn)
	bra	wr_wd2
ld_1_24	cmp.w	#24,d2
	bhi.s	ld_1_26
	cmp.w	#20,d4
	bcs	op_err2
	bhi.s	ld24_22
	move.b	#$F9,(a1)		* LD SP,HL
	moveq.l	#1,d0
	rts
ld24_22	cmp.w	#22,d4
	bcs	op_err2
	cmp.w	#23,d4
	bhi.s	ld24_25
	move.w	d4,d0			* LD SP,IXY
	bsr	c_ixy
	move.b	#$F9,1(a1)
	moveq.l	#2,d0
	rts
ld24_25	cmp.w	#25,d4
	bcs	op_err2
	bhi.s	ld24_28
	move.b	#$31,(a1)		* LD SP,nn
wr_wd1	move.b	d5,1(a1)
	lsr.w	#8,d5
	move.b	d5,2(a1)
	moveq.l	#3,d0
	rts
ld24_28	cmp.w	#28,d4
	bne	op_err2
	move.b	#$ED,(a1)		* SP,(nn)
	move.b	#$7B,1(a1)
wr_wd2	move.b	d5,2(a1)
	lsr.w	#8,d5
	move.b	d5,3(a1)
	moveq.l	#4,d0
	rts
ld_1_26	cmp.w	#26,d2
	bcs	op_err1
	cmp.w	#27,d2
	bhi.s	ld_1_28
	move.w	d2,d0
	bsr	c_ixy
	cmp.w	#7,d4
	bhi.s	ld26_25
	cmp.w	#6,d4
	beq	op_err2			* LD (IXY+d),(HL) -> Fehler
	add.w	#$70,d4			* LD (IXY+d),r
	move.b	d4,1(a1)
	move.b	d3,2(a1)
	moveq.l	#3,d0
	rts
ld26_25	cmp.w	#25,d4
	bne	op_err2
	move.b	#$36,1(a1)		* LD (IXY+d),n
	move.b	d3,2(a1)
	move.w	d5,d0
	bsr	chkbyte
	move.b	d0,3(a1)
	moveq.l	#4,d0
	rts
ld_1_28	cmp.w	#28,d2
	bne	op_err1
	cmp.w	#7,d4
	bcs	op_err2
	bhi.s	ld28_18
	move.b	#$32,(a1)		* LD (nn),A
	bra.s	wr_wd11
ld28_18	cmp.w	#18,d4
	bcs	op_err2
	cmp.w	#19,d4
	bhi.s	ld28_20
	move.b	#$ED,(a1)		* LD (nn),BCDE
	sub.w	#18,d4			* 0,1
	lsl.w	#4,d4			* $00,$10
	add.w	#$43,d4
	move.b	d4,1(a1)
	bra.s	wr_wd12
ld28_20	cmp.w	#20,d4
	bhi.s	ld28_22
	move.b	#$22,(a1)		* LD (nn),HL
wr_wd11	move.b	d3,1(a1)
	lsr.w	#8,d3
	move.b	d3,2(a1)
	moveq.l	#3,d0
	rts
ld28_22	cmp.w	#22,d4
	bcs	op_err2
	cmp.w	#23,d4
	bhi.s	ld28_24
	move.w	d4,d0			* LD (nn),IXY
	bsr	c_ixy
	move.b	#$22,1(a1)
	bra.s	wr_wd12
ld28_24	cmp.w	#24,d4
	bne	op_err2
	move.b	#$ED,(a1)
	move.b	#$73,1(a1)
wr_wd12	move.b	d3,2(a1)
	lsr.w	#8,d3
	move.b	d3,3(a1)
	moveq.l	#4,d0
	rts


r_IM	bsr	op_num
	cmp.w	#25,d0
	bne	op_err1
	move.b	#$ED,(a1)
	tst.w	d1
	bne.s	im1
	move.b	#$46,1(a1)		* IM 0
	moveq.l	#2,d0
	rts
im1	cmp.w	#1,d1
	bne.s	im2
	move.b	#$56,1(a1)		* IM 1
	moveq.l	#2,d0
	rts
im2	cmp.w	#2,d1
	bne	op_err1
	move.b	#$5E,1(a1)		* IM 2
	moveq.l	#2,d0
	rts


r_DEFB	bsr	atxt
	move.l	a1,a2
	clr.l	d6
defb1	bsr.s	defstr
	cmp.l	#1,d5			* genau 1 Byte?
	bne.s	defb2
	subq.l	#3,a0
	subq.l	#1,a2
	subq.l	#1,d6
	bra.s	defb3
defb2	tst.l	d5
	bne.s	defb5
defb3	bsr	op_num
	cmp.w	#25,d0
	bne	op_err1
	cmp.w	#BYTE_BUF_LEN,d6
	bcs.s	defb4
	error	#19
	bra.s	defb6
defb4	move.w	d1,d0
	bsr	chkbyte
	move.b	d0,(a2)+
	addq.l	#1,d6
defb5	cmp.b	#',',(a0)+
	beq.s	defb1
	subq.l	#1,a0
defb6	move.l	d6,d0
	rts


r_DEFM	bsr	atxt
	move.l	a1,a2
	bsr.s	defstr
	move.l	d5,d0
	bne.s	defm1
	error	#11
defm1	rts


* Quelltextstring von (a0) nach (a2) kopieren
* OUTPUT: d5: Anzahl Bytes
*         d6:=d6+Anzahl Bytes 
defstr	clr.l	d5
	move.b	(a0),d0
	cmp.b	#'"',d0
	beq.s	defstr1
	cmp.b	#"'",d0
	bne.s	defstr5
defstr1	addq.l	#1,a0
defstr2	move.b	(a0)+,d1
	cmp.b	d1,d0
	beq.s	defstr5			* String-Ende
	cmp.b	#$20,d1
	bcc.s	defstr3			* kein String-Ende
	error	#20
defstr3	cmp.l	#BYTE_BUF_LEN,d5	* noch Platz im Puffer?
	bcs.s	defstr4
	error	#19
	bra.s	defstr5
defstr4	move.b	d1,(a2)+
	addq.l	#1,d5
	bra.s	defstr2
defstr5	add.l	d5,d6
	rts


r_DEFW	bsr	atxt
	move.l	a1,a2
	clr.l	d6
defw1	bsr	op_num
	cmp.w	#25,d0
	bne	op_err1
	cmp.w	#BYTE_BUF_LEN,d6
	bcs.s	defw2
	error	#19
	bra.s	defw3
defw2	move.b	d1,(a2)+
	lsr.w	#8,d1
	move.b	d1,(a2)+
	addq.l	#2,d6
	cmp.b	#',',(a0)+
	beq.s	defw1
	subq.l	#1,a0
defw3	move.l	d6,d0
	rts


r_RST	bsr	op_num
	cmp.w	#25,d0
	bne	op_err1
	move.w	d1,d0
	and.w	#$FFC7,d1
	bne	op_err1
	or.b	#$C7,d0
	move.b	d0,(a1)
	moveq.l	#1,d0
	rts


r_PUSH	move.w	#$C5,d2
	bra.s	pushpop
r_POP	move.w	#$C1,d2
pushpop	bsr	op_num
	moveq.l	#1,d3			* Anz. Bytes
	cmp.w	#18,d0
	beq.s	pp_code			* BC
	add.w	#$10,d2
	cmp.w	#19,d0
	beq.s	pp_code			* DE
	add.w	#$10,d2
	cmp.w	#20,d0
	beq.s	pp_code			* HL
	add.w	#$10,d2
	cmp.b	#21,d0
	beq.s	pp_code			* AF
	sub.w	#$10,d2			* IX, IY
	move.b	d2,1(a1)
	moveq.l	#2,d3
	move.w	#$DD,d2
	cmp.w	#22,d0			* IX
	beq.s	pp_code
	move.w	#$FD,d2
	cmp.w	#23,d0			* IY
	bne	op_err1
pp_code	move.b	d2,(a1)
	move.l	d3,d0
	rts


r_EX	move.l	a1,a4
	bsr	atxt
	move.l	a0,a2
	bsr	op_num			* beide Operanden abtrennen
	cmp.w	#10,d0
	beq.s	ex_2_op			* EX (SP),..
	cmp.w	#19,d0
	beq.s	ex_2_op			* EX DE,..
	cmp.w	#21,d0
	bne	op_err1			* EX AF,..
ex_2_op	cmp.b	#',',(a0)+
	bne	op_err3
	bsr	etxt
	move.l	a0,a3
	move.b	(a3),d7
	clr.b	(a3)
	lea	tab_ex(pc),a1
ex_lp	move.l	a2,a0
	tst.b	(a1)
	bne.s	se_ex
	move.b	d7,(a3)			* kein gltiger Operand
	move.l	a3,a0
	bra	op_err1
se_ex	bsr	ustrcmp
	tst.w	d0
	beq.s	ex_fnd
nx_ex	tst.b	(a1)+			* n„chster Eintrag
	bne.s	nx_ex
	clr.l	d0			* Code-Bytes bergehen
	move.b	(a1),d0
	addq.l	#1,d0
	add.l	d0,a1
	bra.s	ex_lp
ex_fnd	move.b	d7,(a3)
	clr.l	d0
	move.l	a3,a0
	move.b	(a1)+,d0
	rts


	section	data

* Tabelle fr EX-Befehle
tab_ex	dc.b	'(SP),HL',0,1,$E3
	dc.b	'(SP),IX',0,2,$DD,$E3
	dc.b	'(SP),IY',0,2,$FD,$E3
	dc.b	'DE,HL',0,1,$EB
	dc.b	"AF,AF'",0,1,$08


	section	text

r_JP	bsr	c_flags
	move.w	#$C2,d3
	cmp.w	#-1,d0
	bne.s	j_case
	bsr	op_num			* unbedingter Sprung
	cmp.w	#25,d0
	bne.s	jp1
	move.b	#$C3,(a1)		* JP nn
	bra.s	j_abs
jp1	cmp.w	#6,d0
	bne.s	jp2
	move.b	#$E9,(a1)		* JP (HL)
	moveq.l	#1,d0
	rts
jp2	tst.w	d1
	bne	op_err1			* Offset <> 0
	cmp.w	#26,d0
	bne.s	jp3
	move.b	#$DD,(a1)		* JP (IX)
	bra.s	jp4
jp3	cmp.w	#27,d0
	bne	op_err1
	move.b	#$FD,(a1)
jp4	move.b	#$E9,1(a1)
	moveq.l	#2,d0
	rts

r_CALL	bsr	c_flags
	move.w	#$C4,d3
	cmp.w	#-1,d0
	bne.s	j_case
	bsr	op_num			* unbedingter CALL
	cmp.w	#25,d0
	bne	op_err1
	move.b	#$CD,(a1)
	bra.s	j_abs
j_case	move.w	d0,d2			* Flags
	cmp.b	#',',(a0)+
	bne	op_err3
	bsr	op_num
	cmp.w	#25,d0
	bne	op_err1
	add.w	d2,d3			* Flags addieren
	move.b	d3,(a1)
j_abs	move.b	d1,1(a1)
	lsr.w	#8,d1
	move.b	d1,2(a1)
	moveq.l	#3,d0
	rts


r_RET	bsr	c_flags
	cmp.w	#-1,d0
	bne.s	r_case
	move.b	#$C9,(a1)
	bra.s	r_cas1
r_case	add.w	#$C0,d0
	move.b	d0,(a1)
r_cas1	moveq.l	#1,d0
	rts


r_JR	tst.b	J_flag
	bne.w	r_JP			* absoluter Sprung generieren
	bsr	c_flags
	move.b	#$18,(a1)
	cmp.w	#-1,d0
	beq.s	jmp_rel
	add.w	#$20,d0
	cmp.b	#$38,d0			* nur NZ,Z,NC,C
	bhi	op_err1
	move.b	d0,(a1)
	cmp.b	#',',(a0)+
	bne	op_err3
	bra.s	jmp_rel


r_DJNZ	tst.b	J_flag
	beq.s	djnz
	move.b	#$05,(a1)		* DEC B
	move.b	#$C2,1(a1)		* JP  NZ,..
	bsr	op_num
	cmp.w	#25,d0
	bne	op_err1
	move.b	d1,2(a1)
	lsr.w	#8,d1
	move.b	d1,3(a1)
	moveq.l	#4,d0
	rts
djnz	move.b	#$10,(a1)

* Relative Sprungdistanz ermitteln und in 1(a1) schreiben
* Bereichsprfung, d0 auf 2 oder 0 (Fehler) setzen
* nur in Pass 2

jmp_rel	bsr	op_num
	cmp.w	#2,m_pass
	bne.s	rang_ok			* im Pass 1
	sub.w	prg_count,d1		* Sprungdistanz
	subq.w	#2,d1			* erst ab n„chsten Befehl
	move.b	d1,1(a1)
	move.w	d1,d0			* Bereichsprfung
	and.w	#$FF80,d0
	beq.s	rang_ok			* Vorw„rtssprung
	or.w	#$7F,d1
	cmp.w	#-1,d1
	beq.s	rang_ok			* Rckw„rtssprung
	error	#16
	clr.l	d0
	rts
rang_ok	moveq.l	#2,d0
	rts


* Bedingungsflags auswerten
* OUTPUT: d0.w Code der Flags oder -1
c_flags	move.l	a1,-(sp)
	lea	tab_flg(pc),a1
	bsr	sea_pos
	cmp.w	#-1,d0
	beq.s	flg_ret
flg_fnd	lsl.l	#3,d0
flg_ret	move.l	(sp)+,a1
	rts

	section	data

tab_flg	dc.b	'NZ',0,'Z',0,'NC',0,'C',0
	dc.b	'PO',0,'PE',0,'P',0,'M',0
	dc.b	0


	section	text

r_ADD	bsr	two_op
	move.w	d4,d0
	move.w	d5,d1
	move.w	#$80,d6			* Grundcodebyte fr 8 Bit
	cmp.w	#7,d2
	beq	math8			* 8 Bit ADD
	cmp.w	#20,d2			* 16 Bit ADD
	bcs	op_err1
	bhi.s	addixy
	cmp.w	#18,d4			* ADD HL,..
	bcs	op_err2
	move.w	#$39,d0
	cmp.w	#24,d4
	beq.s	addhl			* ADD HL,SP
	cmp.w	#18,d4
	bcs	op_err2
	cmp.w	#20,d4
	bhi	op_err2
	sub.w	#18,d4			* ADD HL,BC/DE/HL
	lsl.w	#4,d4			* $00/$10/$20
	add.w	#$09,d4
	move.w	d4,d0
addhl	move.b	d0,(a1)
	moveq.l	#1,d0
	rts
addixy	cmp.w	#22,d2
	bcs	op_err1
	cmp.w	#23,d2
	bhi	op_err1
	move.w	d2,d0
	bsr	c_ixy
	cmp.w	#18,d4
	bcs	op_err2
	cmp.w	#19,d4
	bhi.s	addxy22
	sub.w	#18,d4			* ADD IXY,BC/DE
	lsl.w	#4,d4
	add.w	#$09,d4
	move.b	d4,1(a1)
	moveq.l	#2,d0
	rts
addxy22	cmp.w	d2,d4
	bne.s	addxy24
	move.b	#$29,1(a1)		* ADD IX,IX oder IY,IY
	moveq.l	#2,d0
	rts
addxy24	cmp.w	#24,d4
	bne	op_err2
	move.b	#$39,1(a1)
	moveq.l	#2,d0
	rts


r_ADC	bsr	two_op
	move.w	#$88,d6			* Grundcodebyte fr 8 Bit
	move.w	#$4A,d7			* Grundcodebyte fr 16 Bit
	bra.s	asbc16
r_SBC	bsr	two_op
	move.w	#$98,d6			* Grundcodebyte fr 8 Bit
	move.w	#$42,d7			* Grundcodebyte fr 16 Bit
asbc16	move.w	d4,d0
	move.w	d5,d1
	cmp.w	#7,d2
	beq.s	math8			* 8 Bit ADD
	cmp.w	#20,d2
	bne	op_err1
	move.b	#$ED,(a1)
	move.w	#$30,d0
	cmp.w	#24,d4
	beq.s	asbchl			* ADC/SBC HL,SP
	cmp.w	#18,d4			* 16 Bit ADD
	bcs	op_err2
	cmp.w	#20,d4
	bhi	op_err2
	sub.w	#18,d4
	lsl.w	#4,d4			* $00/$10/$20
	move.w	d4,d0
asbchl	add.w	d7,d0
	move.b	d0,1(a1)
	moveq.l	#2,d0
	rts


r_SUB	move.w	#$90,d6
	bra.s	math
r_AND	move.w	#$A0,d6
	bra.s	math
r_XOR	move.w	#$A8,d6
	bra.s	math
r_OR	move.w	#$B0,d6
	bra.s	math
r_CP	move.w	#$B8,d6
math	bsr	op_num
math8	cmp.w	#7,d0
	bhi.s	ma_12			* als n„chstes auf Kennung 12 testen
	add.w	d6,d0			* + Grundcodebyte
	move.b	d0,(a1)
	moveq.l	#1,d0
	rts
ma_12	cmp.w	#12,d0
	bcs	op_err1
	cmp.w	#15,d0
	bhi.s	ma_25
	bsr	c_ixy			* ADD-CP IXYHL
	and.w	#1,d0			* H gerade, L ungerade
	add.w	#4,d0			* B -> H
	add.w	d6,d0			* + Grundcodebyte
	move.b	d0,1(a1)
	moveq.l	#2,d0
	rts
ma_25	cmp.w	#25,d0
	bne.s	ma_26
	add.w	#$46,d6			* ADD-CP n
	move.b	d6,(a1)
	move.w	d1,d0
	bsr	chkbyte
	move.b	d0,1(a1)
	moveq.l	#2,d0
	rts
ma_26	cmp.w	#26,d0
	bcs	op_err1
	cmp.w	#27,d0
	bhi	op_err1
	bsr	c_ixy			* ADD-CP (IXY+d)
	add.w	#$06,d6			* B -> H
	move.b	d6,1(a1)
	move.b	d1,2(a1)
	moveq.l	#3,d0
	rts


r_INC	move.w	#$04,d6			* Grundcodebyte fr 8 Bit
	move.w	#$03,d7			* fr 16 Bit
	bra.s	incdec
r_DEC	move.w	#$05,d6			* fr 8 Bit
	move.w	#$0B,d7
incdec	bsr	op_num
	cmp.w	#7,d0
	bhi.s	icdc12
	lsl.w	#3,d0			* INC/DEC r
	add.w	d6,d0
	move.b	d0,(a1)
	moveq.l	#1,d0
	rts
icdc12	cmp.w	#12,d0
	bcs	op_err1
	cmp.w	#15,d0
	bhi.s	icdc18
	bsr	c_ixy			* INC/DEC IXYHL
	and.w	#1,d0			* H gerade, L ungerade
	lsl.w	#3,d0
	add.w	#$20,d0			* B -> H
	add.w	d6,d0			* Grundcodebyte
	move.b	d0,1(a1)
	moveq.l	#2,d0
	rts
icdc18	cmp.w	#18,d0
	bcs	op_err1
	cmp.w	#20,d0
	bhi.s	icdc22
	sub.w	#18,d0			* INC/DEC BC-HL
	lsl.w	#4,d0
	add.w	d7,d0
	move.b	d0,(a1)
	moveq.l	#1,d0
	rts
icdc22	cmp.w	#22,d0
	bcs	op_err1
	cmp.w	#23,d0
	bhi.s	icdc24
	bsr	c_ixy			* INC/DEC IXY
	add.w	#$20,d7
	move.b	d7,1(a1)
	moveq.l	#2,d0
	rts
icdc24	cmp.w	#24,d0
	bne.s	icdc26
	move.w	#$30,d0			* INC/DEC SP
	add.w	d7,d0
	move.b	d0,(a1)
	moveq.l	#1,d0
	rts
icdc26	cmp.w	#26,d0
	bcs	op_err1
	cmp.w	#27,d0
	bhi	op_err1
	bsr	c_ixy
	add.w	#$30,d6
	move.b	d6,1(a1)
	move.b	d1,2(a1)
	moveq.l	#3,d0
	rts


r_BIT	move.w	#$40,d6			* Grundcodebyte
	bra.s	od_bit
r_RES	move.w	#$80,d6
	bra.s	od_bit
r_SET	move.w	#$C0,d6
od_bit	bsr	two_op
	cmp.w	#25,d2			* 1. Op Direktwert
	bne	op_err2
	cmp.w	#7,d3			* Bitnummer
	bhi	op_err1			* gr”žer 7
	lsl.w	#3,d3			* Bitnummer * 8
	add.w	d3,d6			* Grundcodebyte
	move.w	d4,d0			* Registerkennung
	move.w	d5,d1			* Direktwert
	bra.s	bitrot


r_RLC	move.w	#$00,d6			* Grundcodebytes
	bra.s	ro_sh
r_RRC	move.w	#$08,d6
	bra.s	ro_sh
r_RL	move.w	#$10,d6
	bra.s	ro_sh
r_RR	move.w	#$18,d6
	bra.s	ro_sh
r_SLA	move.w	#$20,d6
	bra.s	ro_sh
r_SRA	move.w	#$28,d6
	bra.s	ro_sh
r_SLE	move.w	#$30,d6
	bra.s	ro_sh
r_SRL	move.w	#$38,d6
ro_sh	bsr	op_num
bitrot	cmp.w	#7,d0
	bhi.s	bt_ro2
bt_ro1	move.b	#$CB,(a1)		* OP einfaches Register
	add.w	d6,d0
	move.b	d0,1(a1)
	moveq.l	#2,d0
	rts
bt_ro2	move.b	#$CB,1(a1)
	cmp.w	#12,d0
	bcs	op_err1
	cmp.w	#15,d0
	bhi.s	bt_ro3
	bsr	c_ixy			* IXH-IYL
	add.w	#4,d6
	and.w	#1,d0
	or.w	d0,d6
	move.b	d6,2(a1)
	moveq.l	#3,d0
	rts
bt_ro3	cmp.w	#26,d0
	bcs	op_err1
	cmp.w	#27,d0
	bhi	op_err1
	bsr	c_ixy			* (IXY+d)
	move.b	d1,2(a1)
	add.w	#6,d6
	move.b	d6,3(a1)
	moveq.l	#4,d0
	rts


r_IN	bsr	two_op
	move.w	d2,d0			* Registerkenung
	move.w	#$40,d1			* Grundcodebyte
	cmp.w	#11,d4			* Tor (C)?
	beq.s	i_inout
	move.w	d5,d0			* E/A-Adresse
	move.w	d4,d1			* Adresskennung
	move.w	#$DB,d3			* Code IN A,(n)
	bra.s	a_inout
r_OUT	bsr	two_op
	move.w	d4,d0			* Registerkennung
	move.w	#$41,d1			* Grundcodebyte
	cmp.w	#11,d2			* Tor (C)?
	beq.s	i_inout
	move.w	d3,d0			* E/A-Adresse
	move.w	d2,d1			* Adresskennung
	move.w	d4,d2			* Registerkennung
	move.w	#$D3,d3			* Code OUT (n),A
a_inout	cmp.w	#7,d2
	bne	op_err2			* kein A-Register
	cmp.w	#28,d1
	bne	op_err2			* kein Direktwert
	move.b	d3,(a1)
	bsr	chkbyte
	bra.s	io_ret
i_inout	cmp.w	#6,d0			* ber (C)
	beq	op_err1			* (HL)
	cmp.w	#7,d0
	bhi	op_err1
	lsl.w	#3,d0			* mul 8
	add.w	d1,d0
	move.b	#$ED,(a1)
io_ret	move.b	d0,1(a1)
	moveq.l	#2,d0
	rts


* Unterscheidung von IX und IY
* (a1) $DD oder $FD schreiben
* Op-Kennung in d0
c_ixy	move.b	#$DD,(a1)
	cmp.w	#12,d0
	beq.s	ixy_ret			* IXH
	cmp.w	#13,d0
	beq.s	ixy_ret			* IXL
	cmp.w	#22,d0
	beq.s	ixy_ret			* IX
	cmp.w	#26,d0
	beq.s	ixy_ret			* (IX+d)
	move.b	#$FD,(a1)
ixy_ret	rts


* zwei Operanden (a0) auswerten
* OUTPUT: d2: Op1-Kennung
*         d3: Op1-Wert
*         d4: Op2-Kennung
*         d5: Op2-Wert
*         a0: hinter ausgewerteten Teil
two_op	bsr.s	op_num
	move.l	d0,d2
	move.l	d1,d3
	cmp.b	#',',(a0)+
	bne	op_err3
	bsr.s	op_num
	move.l	d0,d4
	move.l	d1,d5
	rts


* Im Quelltext (a0) n„chstes Operanden auswerten
* OUTPUT: a0: hinter ausgewerteten Teil im Quelltext
*         d0: Art des Operanden (Nummer)
*         d1: evtl. Direktwert
* Operandennummer: ab Null beginnend in der Reihenfolge
* B, C, D, E, H, L, (HL), A		* 0-7
* (BC), (DE), (SP), (C)			* 8-11
* IXH, IXL, IYH, IYL, I, R		* 12-17
* BC, DE, HL, AF, IX, IY, SP, nn	* 18-25
* (IX+d), (IY+d), (nn)			* 26-28

op_num	movem.l	d6/a1-a2,-(sp)
	lea	tab_reg(pc),a1
	bsr	sea_pos
	cmp.w	#-1,d0
	beq.s	reg_no
reg_fnd	clr.l	d1			* Registernummer
	bra.w	op_ret
reg_no	cmp.b	#'(',(a0)
	bne	direct
	addq.l	#1,a0			* auf IX und IY testen
	bsr	atxt
	move.l	a0,a2
	move.b	(a0),d0
	bsr	upcase
	cmp.b	#'I',d0
	bne.s	indirct
	addq.l	#1,a0
	move.b	(a0),d0
	move.l	a2,a0			* Anfang in der Klammer + 1
	bsr	upcase
	cmp.b	#'X',d0
	bne.s	reg_iy
	moveq.l	#26,d6
	bra.s	offset
reg_iy	cmp.b	#'Y',d0
	bne.s	indirct
	moveq.l	#27,d6
offset	addq.l	#2,a0
	move.b	(a0),d0
	cmp.b	#')',d0
	bne.s	offset1
	clr.l	d0			* (IX) oder (IY)
	bra.s	indrct1
offset1	cmp.b	#'+',d0
	beq.s	offset2
	cmp.b	#'-',d0
	beq.s	offset2
	move.l	a2,a0			* Anfang in der Klammer
	bra.s	indirct
offset2	bsr	term
	tst.b	term_flag
	beq.s	indrct1			* Wert ungltig
	move.w	d0,d1			* Bereichsprfung nur Pass 2
	and.w	#$FF80,d1
	beq.s	indrct1			* vorw„rts
	move.w	d0,d1
	or.w	#$7F,d1
	cmp.w	#-1,d1
	beq.s	indrct1			* rckw„rts
	error	#18
	bra.s	indrct1
indirct	bsr	term			* indirekter Wert
	moveq.l	#28,d6
indrct1	move.l	d0,d1
	move.l	d6,d0
	cmp.b	#')',(a0)+
	beq.s	op_ret
	error	#13			* schliežende Klammer fehlt
	bra.s	op_ret
direct	bsr	term
	move.l	d0,d1
	moveq.l	#25,d0
op_ret	movem.l	(sp)+,d6/a1-a2
	rts


* Position (mit Null beginnend) eines Strings in einer Tabelle suchen
* INPUT:  a0: zu suchender String, wird grož gewandelt
*         a1: Tabelle
* OUTPUT: d0: Nummer in Tabelle oder -1, wenn nicht gefunden
*         a0: zeigt hinter ausgewerteten Teil
sea_pos	movem.l	d1/d7/a1-a3,-(sp)
	bsr	atxt
	move.l	a0,a2			* String abtrennen
	bsr	etxt
	move.l	a0,a3
	move.b	(a3),d7
	clr.b	(a3)
	moveq.l	#-1,d1
pos_lp	addq.l	#1,d1
	move.l	a2,a0
	tst.b	(a1)
	beq.s	no_pos			* nicht gefunden
	bsr	ustrcmp
	tst.w	d0
	beq.s	pos_fnd
nx_pos	tst.b	(a1)+
	bne.s	nx_pos
	bra.s	pos_lp
no_pos	moveq.l	#-1,d0
	move.l	a2,a0
	bra.s	pos_ret
pos_fnd	move.l	a3,a0
	move.l	d1,d0
pos_ret	move.b	d7,(a3)
	movem.l	(sp)+,d1/d7/a1-a3
	rts


	section	data

* Tabelle aller Befehle mit m”glichen Operanden
tab_i1	dc.b	'LD',0
	dc.b	'PUSH',0
	dc.b	'POP',0
	dc.b	'EX',0
	dc.b	'JP',0
	dc.b	'CALL',0
	dc.b	'RET',0
	dc.b	'JR',0
	dc.b	'ADD',0
	dc.b	'ADC',0
	dc.b	'SUB',0
	dc.b	'SBC',0
	dc.b	'AND',0
	dc.b	'XOR',0
	dc.b	'OR',0
	dc.b	'CP',0
	dc.b	'INC',0
	dc.b	'DEC',0
	dc.b	'DJNZ',0
t_EQU	dc.b	'EQU',0
	dc.b	'BIT',0
	dc.b	'RES',0
	dc.b	'SET',0
	dc.b	'RLC',0
	dc.b	'RRC',0
	dc.b	'RL',0
	dc.b	'RR',0
	dc.b	'SLA',0
	dc.b	'SRA',0
	dc.b	'SLE',0
	dc.b	'SRL',0
	dc.b	'RST',0
	dc.b	'IN',0
	dc.b	'OUT',0
	dc.b	'IM',0
	dc.b	'DEFB',0,'DB',0
	dc.b	'DEFM',0,'DM',0
	dc.b	'DEFW',0,'DW',0
	dc.b	'DEFA',0,'DA',0
	dc.b	'END',0
	dc.b	0			* Tabellenende


* Tabelle der Adressen der Auswerteroutinen fr Befehle mit
* m”glichen Operanden, gleiche Reihenfolge wie bei tab_i1!
	even
tab_jp1	dc.l	r_LD
	dc.l	r_PUSH
	dc.l	r_POP
	dc.l	r_EX
	dc.l	r_JP
	dc.l	r_CALL
	dc.l	r_RET
	dc.l	r_JR
	dc.l	r_ADD
	dc.l	r_ADC
	dc.l	r_SUB
	dc.l	r_SBC
	dc.l	r_AND
	dc.l	r_XOR
	dc.l	r_OR
	dc.l	r_CP
	dc.l	r_INC
	dc.l	r_DEC
	dc.l	r_DJNZ
	dc.l	r_EQU
	dc.l	r_BIT
	dc.l	r_RES
	dc.l	r_SET
	dc.l	r_RLC
	dc.l	r_RRC
	dc.l	r_RL
	dc.l	r_RR
	dc.l	r_SLA
	dc.l	r_SRA
	dc.l	r_SLE
	dc.l	r_SRL
	dc.l	r_RST
	dc.l	r_IN
	dc.l	r_OUT
	dc.l	r_IM
	dc.l	r_DEFB,r_DEFB
	dc.l	r_DEFM,r_DEFM
	dc.l	r_DEFW,r_DEFW
	dc.l	r_DEFW,r_DEFW
	dc.l	r_END


* Tabelle aller Befehle ohne jeglichen Operanden
* Format:
* NAME, 1 Byte Null, Anz. Bytes, Code-Bytes
* Ende mit Null
tab_i2	dc.b	'EXX',0,1,$D9
	dc.b	'LDI',0,2,$ED,$A0
	dc.b	'LDIR',0,2,$ED,$B0
	dc.b	'LDD',0,2,$ED,$A8
	dc.b	'LDDR',0,2,$ED,$B8
	dc.b	'CPI',0,2,$ED,$A1
	dc.b	'CPIR',0,2,$ED,$B1
	dc.b	'CPD',0,2,$ED,$A9
	dc.b	'CPDR',0,2,$ED,$B9
	dc.b	'RETI',0,2,$ED,$4D
	dc.b	'RETN',0,2,$ED,$45
	dc.b	'NOP',0,1,$00
	dc.b	'HALT',0,1,$76
	dc.b	'CCF',0,1,$3F
	dc.b	'SCF',0,1,$37
	dc.b	'EI',0,1,$FB
	dc.b	'DI',0,1,$F3
	dc.b	'INF',0,2,$ED,$70
	dc.b	'INI',0,2,$ED,$A2
	dc.b	'INIR',0,2,$ED,$B2
	dc.b	'IND',0,2,$ED,$AA
	dc.b	'INDR',0,2,$ED,$BA
	dc.b	'OUTI',0,2,$ED,$A3
	dc.b	'OTIR',0,2,$ED,$B3
	dc.b	'OUTD',0,2,$ED,$AB
	dc.b	'OTDR',0,2,$ED,$BB
	dc.b	'DAA',0,1,$27
	dc.b	'CPL',0,1,$2F
	dc.b	'NEG',0,2,$ED,$44
	dc.b	'RRCA',0,1,$0F
	dc.b	'RLCA',0,1,$07
	dc.b	'RRA',0,1,$1F
	dc.b	'RLA',0,1,$17
	dc.b	'RLD',0,2,$ED,$6F
	dc.b	'RRD',0,2,$ED,$67
	dc.b	0			* Tabellenende


tab_reg	dc.b	'B',0,'C',0,'D',0,'E',0			* 0-3
	dc.b	'H',0,'L',0,'(HL)',0,'A',0		* 4-7
	dc.b	'(BC)',0,'(DE)',0,'(SP)',0,'(C)',0	* 8-11
	dc.b	'IXH',0,'IXL',0,'IYH',0,'IYL',0		* 12-15
	dc.b	'I',0,'R',0				* 16,17
	dc.b	'BC',0,'DE',0,'HL',0,'AF',0		* 18-21
	dc.b	'IX',0,'IY',0,'SP',0			* 22-24
	dc.b	0					* Tabellenende


	section	bss

byte_buf	ds.b	BYTE_BUF_LEN	* Puffer fr erzeugte Bytes


*** allgemeine Grundroutinen ******************************

	section	text

* Umwandlung Klein -> Grožbuchstabe in d0.b
upcase	cmp.b	#'a',d0
	bcs.s	upcase1
	cmp.b	#'z',d0
	bhi.s	upcase1
	sub.b	#$20,d0
upcase1	rts


* Vergleichen zweier Strings (a0, a1)
* String a0 wird in Grožbuchstaben umgewandelt
* OUTPUT: d0.l = 0, wenn gleich, sonst +1 oder -1
*         a0, a1: zeigt auf Unterschied bzw. hinter String (hinter Null)
ustrcmp	move.b	(a0),d0
	bsr.s	upcase
	cmp.b	(a1),d0
	beq.s	ustrcp1
	bhi.s	ustrcp2		* String 1 > String 2
	moveq.l	#-1,d0
	bra.s	ustrcp3		* String 1 < String 2
ustrcp1	clr.l	d0
	addq.l	#1,a1
	tst.b	(a0)+
	beq.s	ustrcp3		* String 1 = String 2
	bra.s	ustrcmp
ustrcp2	moveq.l	#1,d0
ustrcp3	rts


* Vergleichen zweier Strings (a0, a1)
* String a0 wird dann in in Grožbuchstaben umgewandelt,
* wenn die "-C" Option nicht angegeben wurde
* OUTPUT: d0.l = 0, wenn gleich, sonst +1 oder -1
*         a0, a1: zeigt auf Unterschied bzw. hinter String (hinter Null)
strcmp	move.b	(a0),d0
	tst.b	C_flag
	bne.s	strcmp1
	bsr.s	upcase
strcmp1	cmp.b	(a1),d0
	beq.s	strcmp2
	bhi.s	strcmp3
	moveq.l	#-1,d0
	bra.s	strcmp4
strcmp2	clr.l	d0
	addq.l	#1,a1
	tst.b	(a0)+
	beq.s	strcmp4
	bra.s	strcmp
strcmp3	moveq.l	#1,d0
strcmp4	rts


* String grož wandeln und kopieren
* von a0 nach a1
ustrcpy	move.b	(a0)+,d0
	bsr.s	upcase
	move.b	d0,(a1)+
	bne.s	ustrcpy
	rts


* String a0 an a1 anh„ngen
strcat	tst.b	(a1)+			* Ende String 2 suchen
	bne.s	strcat
	subq.l	#1,a1
strcpy	move.b	(a0)+,(a1)+
	bne.s	strcpy
	rts


* letztes Vorkommen eines Zeichens (d0.b) im String (a0) suchen
* OUTPUT: a0: Zeiger auf letztes Vorkommen bzw. Stringanfang
strrchr	move.l	a1,-(sp)
	move.l	a0,a1
srchr1	cmp.b	(a0),d0
	bne.s	srchr2
	move.l	a0,a1
srchr2	tst.b	(a0)+
	bne.s	srchr1
	move.l	a1,a0
	move.l	(sp)+,a1
	rts


* Zeiger a0 Leerzeichen und TABs bergehen
atxt	subq.l	#1,a0
atxt1	addq.l	#1,a0
	cmp.b	#$20,(a0)
	beq.s	atxt1
	cmp.b	#9,(a0)
	beq.s	atxt1
	rts


* Stringende suchen (0, 9, $0A, $0C, $0D, $1A, $1E, $20)
etxt	movem.l	d0/a1,-(sp)
etxt1	move.b	(a0),d0
	moveq.w	#8,d1
	lea	etxttab(pc),a1
etxt2	cmp.b	(a1)+,d0
	beq.s	etxt3
	dbf	d1,etxt2
	addq.l	#1,a0
	bra.s	etxt1
etxt3	movem.l	(sp)+,d0/a1
	rts

	section	data
etxttab	dc.b	0,9,$0A,$0C,$0D,$1A,$1E,$20,','


	section	text

* Symbolende suchen
esym	move.w	d0,-(sp)
esym1	move.b	(a0)+,d0
	cmp.b	#'_',d0
	beq.s	esym1
	bsr.w	upcase
	cmp.b	#'0',d0
	bcs.s	esym2
	cmp.b	#'9',d0
	bls.s	esym1
	cmp.b	#'A',d0
	bcs.s	esym2
	cmp.b	#'Z',d0
	bls.s	esym1
esym2	subq.l	#1,a0
	move.w	(sp)+,d0
	rts


* Ausgabe einer vorzeichenlosen Dezimalzahl in d0.w
outdez	move.w	#-1,d4
outdez1	and.l	#$FFFF,d0		* oberen 16Bit = 0
	addq.w	#1,d4			* Anzahl der Stellen-1
	divu	#10,d0
	swap	d0
	move.w	d0,-(sp)		* Rest -> Stack
	swap	d0
	tst.w	d0
	bne.s	outdez1
outdez2	move.w  (sp)+,d0
	add.w	#'0',d0
	move.w	d0,-(sp)
	call_gemdos Cconout
	addq.l	#4,sp
	dbf.w	d4,outdez2
	rts


* Test auf Abbruch (^C), ja -> exit
tst_brk	call_gemdos Cconis
	addq.l	#2,sp
	tst.w	d0
	beq.s	brk_end
	call_gemdos Crawcin
	addq.l	#2,sp
	cmp.l	#$610000,d0
	beq	prg_end
	cmp.b	#3,d0
	beq	prg_end
brk_end	rts


* n„chste Zeile suchen
next_ln	move.w	d0,-(sp)
nx_ln1	move.b	(a0)+,d0
	cmp.b	#$0A,d0
	beq.s	nx_ret
	cmp.b	#$1E,d0
	beq.s	nx_ret
	cmp.b	#$1A,d0
	bne.s	nx_ln1
	subq.l	#1,a0
nx_ret	move.w	(sp)+,d0
	rts


* Testet, ob in der Zeile (a0) noch etwas steht

syntax	move.l	d0,-(sp)
	bsr.s	syntax1
	tst.w	d0
	beq.s	sn_ret
	error	#8
sn_ret	move.l	(sp)+,d0
	rts

* Test Zeilenende, d0.w=0: ok, d0.w=-1: Fehler
syntax1	clr.l	d0
	bsr	atxt
	cmp.b	#$0A,(a0)		* Zeilenende
	beq.s	snret1
	cmp.b	#$0D,(a0)
	beq.s	snret1
	cmp.b	#$1E,(a0)
	beq.s	snret1
	cmp.b	#$1A,(a0)		* Textende
	beq.s	snret1
	cmp.b	#';',(a0)		* Kommentar
	beq.s	snret1
	moveq.l	#-1,d0
snret1	rts


* Testet, ob der Wert (d0.w) ein Byte ist
* wenn nein -> Warnung
chkbyte	movem.l	d0-d2/a0-a2,-(sp)
	tst.b	term_flag
	beq.s	chkbret			* Wert ungltig
	and.w	#$FF00,d0
	beq.s	chkbret
	warning	bigbyte
chkbret	movem.l	(sp)+,d0-d2/a0-a2
	rts


* d0.b als Hex-Zahl in Puffer (a0) schreiben
* a0 wird zwei mal inkrementiert
htoa	move.w	d0,-(sp)
	lsr.b	#4,d0
	bsr.s	htoa1
	move.w	(sp)+,d0
htoa1	and.w	#$F,d0
	add.w	#'0',d0
	cmp.w	#'9',d0
	bls.s	htoa2
	add.w	#7,d0
htoa2	move.b	d0,(a0)+
	rts


* d0.w als Dezimalzahl (immer 5 Stellen) in Puffer (a0) schreiben
* a0 wird inkrementiert
uitoa	moveq.w	#-1,d1
uitoa1	and.l	#$FFFF,d0
	divu	#10,d0
	swap	d0
	move.w	d0,-(sp)		* Rest
	addq.w	#1,d1
	swap	d0
	tst.w	d0
	bne.s	uitoa1
uitoa2	cmp.w	#4,d1			* Anzahl Stellen - 1
	bcc.s	uitoa3
	move.w	#0,-(sp)		* Format -> Leerzeichen
	addq.w	#1,d1
	bra.s	uitoa2
uitoa3	move.w	(sp)+,d0
	add.w	#'0',d0
	move.b	d0,(a0)+
	dbf	d1,uitoa3
	rts


* Wort als Hexzahl + 2 Leerzeichen in Datei schreiben
* INPUT: d0.w: Wert
fouthex	movem.l	d0-d2/a0-a2,-(sp)
	lea	filebuf(pc),a0
	move.l	a0,a1
	moveq.w	#3,d2
fohex1	rol.w	#4,d0			* HEX -> ASCII
	move.w	d0,d1
	and.w	#$F,d1
	add.w	#'0',d1
	cmp.w	#'9',d1
	bls.s	fohex2
	add.w	#7,d1
fohex2	move.b	d1,(a1)+
	dbf	d2,fohex1
	move.b	#$20,(a1)+
	move.b	#$20,(a1)+
	moveq.l	#6,d0
	bsr.s	f_write
	movem.l	(sp)+,d0-d2/a0-a2
	rts


* $0D $0A in Datei schreiben
foutnl	movem.l	d0-d2/a0-a2,-(sp)
	lea	filebuf(pc),a0
	move.l	a0,a1
	move.b	#$0D,(a1)+
	move.b	#$0A,(a1)+
	moveq.l	#2,d0
	bsr.s	f_write
	movem.l	(sp)+,d0-d2/a0-a2
	rts


* Datei schreiben
* INPUT  a0:   Zeiger auf Puffer
*        d0.l: Anzahl Bytes
f_write	move.l	d0,-(sp)
	move.l	a0,-(sp)
	move.l	d0,-(sp)
	move.w	f_handle,-(sp)
	call_gemdos Fwrite
	lea	$C(sp),sp
	cmp.l	(sp)+,d0
	beq.s	f_wr2
	move.b	#-1,wr_err_flag
	move.b	#-1,end_flag
	cmp.l	#-36,d0
	bne.s	f_wr1
	error	#23			* Zugriff verweigert
	bra.s	f_wr2
f_wr1	error	#24			* Laufwerk voll
f_wr2	rts


f_close	move.w	f_handle,-(sp)
	call_gemdos Fclose
	addq.l	#4,sp
	rts


	section	data

bigbyte	dc.b	'16-Bit statt 8-Bit Wert',13,10,0


*** Stack und Arbeitsspeicher *****************************

	section	bss

filebuf		ds.b	BYTE_BUF_LEN	* Hilfspuffer fr Ausgabedatei
wr_err_flag	ds.b	1		* Schreibfehler
	even
	ds.l	1000
mystack	ds.l	1
buffer	ds.l	1


*** Ende **************************************************

	END

***********************************************************
