;matthaei, 16.10.89,2.3.93,17.6.94,31.3.96
;makrosammlung
.286c
;Einzelne Teile werden nur bei der
;Festlegung xxx EQU TRUE im Rahmenprogramm mit aufgenommen
; xxx kann sein:
; DUMP$ fuer mdump, rdump
; ENTER$ fuer ENTER, INKJN
; INTASC$ fuer INT2ASC, ASC2INT
; STRING$ fuer CMPSTR, LENSTR, INSTR, MOVSTR, UCASEG, LCASEG
;FALSE EQU 0 ;FALSE und TRUE ist im
;TRUE EQU NOT FALSE ;Rahmenprogramm definiert
w equ word ptr
b equ byte ptr
bs equ 8
tab equ 9
spc equ ' '
cr equ 0dh
lf equ 0ah
esc equ 1bh
eof equ 1ah ;end of file
;kbd_int equ 9 ;tastaturinterrupt
kbd_int equ 16h ;tastaturinterrupt
timer_int equ 1ah ;Echtzeituhr
user_int equ 1ch ;wird vom timer aufgerufen
dos equ 21h
video equ 10h ;bildschirmausgabe
break_int equ 23h ;reaktion auf break
fcb equ 005ch
lparm equ 0080h ;parameterlaenge
resflag equ 0072h ;reset flag
;======
;sucht den Anfang des Parameters, der beim Programmaufruf in der
;Kommandozeile mitgegeben wurde.
;Vorbereitung:
; mov si,lparm ;Parameterlaenge nach cx
; xor ch,ch
; mov cl,[si]
getparm macro gefunden
local getparm1,getparm99
getparm1:
inc si ;;Adresszeiger
cmp b [si],spc ;;igno leading spaces
ifb <gefunden>
jne getparm99
else
jne gefunden
endif
cmp b [si],cr ;;cr ist absolutes Parameterende
je getparm99
loop getparm1
getparm99: ;;si zeigt auf 1.Zeichen Parameter oder cr
endm
if1 ;macros nur im 1.Durchlauf
int21 macro intnr
ifnb <intnr&ht;
ldreg ah,intnr
endif
int dos
endm
jmps macro to ;;kurzer sprung
jmp short to
endm
jmpc macro to ;;langer sprung bei gesetztem carry
local weiter
jnc weiter
jmp to
weiter:
endm
ret_far macro
db 0cbh
endm
ret_near macro
db 0c3h
endm
pushreg macro liste
irp reg,<liste>
push reg
endm
endm
popreg macro liste
irp reg,<liste>
pop reg
endm
endm
dbl macro text ;;definiert eine zeile
ifb <text>
db cr
else
db text,cr
endif
endm
dbz macro text ;;definiert einen string mit 0 am Ende
ifb <text>
db 0
else
db text,0
endif
endm
SETINT MACRO DXA,INTN ;;dxa = dx address intn = int #
LEA DX,DXA ;;Get execution address
MOV AL,INTN ;:Interrupt level
int21 25h ;;Set interrupt vector request
ENDM
GETINT MACRO INTN ;:Intn = int #
MOV AL,INTN ;;Interrupt level
int21 35h ;;get Interrupt vector request ES:BX
ENDM
;=====
;bios macros (rs232 and video)
;ldreg is an "inner" macro to specify a register or a literal value as the
;parameter to the macro. it loads the specified register with the source, but
;no code will be generated if the two parameters are the same.
ldreg macro destreg,source
ifdif <destreg>,<source>
mov destreg,source
endif
endm
;tstnset will compare the value of two fields, if they are equal the
;third parameter will be or'd into al.
tstnset macro src1,src2,orval
ifidn <src1>,<src2>
or al,orval
endif
endm
;irs232 will generate a call to bios to initialize the rs232 port
;it allows the fields to be specified that initialize the port
irs232 macro baudrate,parity,stopbits,datalen,linenum
ldreg dx,linenum
sub ax,ax
tstnset baudrate,150,00100000b
tstnset baudrate,300,01000000b
tstnset baudrate,600,01100000b
tstnset baudrate,1200,10000000b
tstnset baudrate,2400,10100000b
tstnset baudrate,4800,11000000b
tstnset baudrate,9600,11100000b
;; tstnset parity,none,00000000b
tstnset parity,odd,00001000b
tstnset parity,even,00011000b
;; tstnset stopbits,1,00000000b
tstnset stopbits,2,00000100b
tstnset datalen,7,00000010b
tstnset datalen,8,00000011b
int 14h
endm
;sendchr sends a character over the rs232 line.
sendchr macro char,linenum
ldreg dx,linenum
ldreg al,char
mov ah,1
int 14h
endm
;recvchr receives a character from the rs232 line.
recvchr macro linenum
ldreg dx,linenum
mov ah,2
int 14h
endm
;comstat gets the status of the rs232 line.
comstat macro linenum
ldreg dx,linenum
mov ah,3
int 14h
endm
;======
;loescht den Bildschirm (allerdings bei Text immer 25-zeilig)
ClrCRT macro ;;init Screen
GetVid ;;al=Video Modus
xor ah,ah
int video
endm
;GetVID Rueckgabewerte: al=Videomodus, ah=Anzahl Zeichen / Zeile, bh=Seite
GetVid macro ;;get Video Mode
mov ah,0fh
int video
endm
;setcurtype will set the cursor type.
setcurtype macro start,end
ldreg ch,start
ldreg cl,end
mov ah,1
int video
endm
;setcurpos will set the cursor position. Row und Col sind 0-basierend
setcurpos macro row,col,crtpage
ldreg dh,row
ldreg dl,col
ifb <crtpage>
sub bh,bh
else
ldreg bh,crtpage
endif
mov ah,2 ;;bios function select
int video ;;invoke bios cursor positioning
endm
;setcurcol setzt den Cursor in der aktuellen Zeile auf die angegebene Position
;siehe weiter unten im Codeteil
;getcurpos return: dh=Zeile, dl=Spalte, ch=Anfangszeile-, cl=Endzeile-Cursor
getcurpos macro crtpage
ldreg bh,crtpage
mov ah,3
int video
endm
;scroll will scroll the page up or down
scroll macro direction,lines,ulcrow,ulccol,lrcrow,lrccol,attr
ldreg al,lines
ldreg ch,ulcrow
ldreg cl,ulccol
ldreg dh,lrcrow
ldreg dl,lrccol
ldreg bh,attr
ifidn <direction>,<up>
mov ah,6
endif
ifidn <direction>,<down>
mov ah,7
endif
int video
endm
;======
print_str macro string ;;zeichenkette ueber ansi.sys zum bildschirm
ifdif <dx>,<string>
mov dx,offset string ;;address of string ending with $
endif
int21 9
endm
get_str macro string ;;Zeichenkette von Tastatur holen
ifdif <dx>,<string>
mov dx,offset string ;;address Zielbereich
endif
int21 0ah
endm
;Eingaben von Ganzzahlen und Strings nach buffer (z.B.LPARM)
;Die maximale Eingabelaenge wird in bl mitgegeben
inkstr macro prompt,length,buffer ;;Stringeingabe mit Prompt
prstr <prompt>
mov di,offset buffer
mov bl,length
inc bl ;;Pufferlaenge=Eingabelaenge+1
mov [di],bl ;;Eingabe ohne Prompt
get_str buffer
endm
;zu keyread und keyget:
;for extended ascii codes two doscalls will be required, the first will return
;00 in al the second will return the extended code in al
keyread macro ;;eingabe eines zeichens mit anzeige
int21 1
endm
keyget macro ;;eingabe eines zeichens ohne anzeige
int21 8
endm
;handle-dateibehandlung
;======
fopen macro fname,acode ;;open file
ifdif <dx>,<fname>
mov dx,offset fname ;;address of file name
endif
ldreg al,acode ;;access code 0=read, 1=write, 2=read and write
int21 3dh ;;returns fhandle in ax
endm
fcrat macro fname,attrb ;;create a file (eine alte Datei
ifdif <dx>,<fname> ;;gleichen Namens wird dabei geloescht)
mov dx,offset fname ;;address of file name
endif
ldreg cx,attrb ;;attribute
int21 3ch ;;returns fhandle in ax
endm
fwrit macro fhand,wbuff,count ;;write to file
ldreg bx,fhand ;;handle
ldreg cx,count ;;attribute
ifdif <dx>,<wbuff>
mov dx,offset wbuff ;;address of write buffer
endif
int21 40h
endm
fclose macro fhand ;;close file
ldreg bx,fhand ;;handle
int21 3eh
endm
fread macro fhand,rbuff,count ;;read from file
ldreg bx,fhand ;;handle
ldreg cx,count ;;get this many byte(s)
ifdif <dx>,<rbuff>
mov dx,offset rbuff ;;address of read buffer
endif
int21 3fh
endm
endif ;if1
;farbattribute (fuer int video mit bh=0)
;(linkes nibble: hintergrund, rechtes nibble: vordergrund)
;bit 7 bestimmt blinken (1=ein, 0=aus)
;bit 3 bestimmt Intensitaet (1=hell, 0=normal)
n_blck equ 0 ;schwarz
n_blue equ 1 ;blau
n_grn equ 2 ;gruen
n_zyan equ 3 ;zyan
n_red equ 4 ;rot
n_viol equ 5 ;violett
n_brwn equ 6 ;braun
n_white equ 7 ;weiá
n_grey equ 8 ;grau
n_lblue equ 9 ;hellblau
n_lgrn equ 0ah ;hellgrn
n_lzyan equ 0bh ;hellzyan
n_lred equ 0ch ;hellrot
n_lviol equ 0dh ;hellviolett
n_yell equ 0eh ;gelb
n_lwhite equ 0fh ;hellweiá
;attribute (monochrom- und farbkarte mit schwarzem hintergrund))
ma_blinken equ 87h
ma_normal equ 7
ma_hell equ 0fh
ma_invers equ 70h
;attribute (nur farbkarte mit blauem hintergrund)
a_blinken equ 16d*n_lblue+n_white
a_invers equ 16d*n_white+n_blue
a_hell equ 16d*n_blue+n_yell
a_normal equ 16d*n_blue+n_white
if1 ;macros nur im 1.Durchlauf
;attribut-steuerzeichen fuer Farbkarte
a_nm macro ;;normal
db esc,a_normal
endm
a_he macro ;;hell
db esc,a_hell
endm
a_re macro ;;reverse
db esc,a_invers
endm
a_bl macro ;;blinken
db esc,a_blinken
endm
endif ;if1
code segment
assume cs:code, ds:code, es:code
;------ beginn der codeerzeugung ------
org 100h
start: jmp anfang
;======
;unterprogrammsammlung
;======
;print message following call prmsg and ending with 0
prmsg: mov w prmsg2,si
pop si
call printa
push si ;returnadr.
mov si,0 ;mod
prmsg2 equ $-2
ret
;druckt die mit si adressierte zeichenkette
;die zeichenkette darf keine steuerzeichen außer cr und attribute enthalten
;sie endet mit 0h
printa:
push ax
cld
printa5:
lodsb ;zeichen
cmp al,esc ;hiernach soll attribut folgen
jne printa_b9
lodsb ;attribut
mov b attr,al
jmps printa5 ;und string weiter einlesen
printa_b9:
or al,al ;ob fertig ?
jz printa7 ;ja
call printchr
jmps printa5
printa7:
pop ax
ret
;======
if1 ;macros nur im 1.Durchlauf
prstr macro text ;;print string
call prmsg
dbz <text>
endm
;======
print_crlf macro
call $print_crlf ;;ausgabe cr lf
endm ;;zum bildschirm
print_chr macro char ;;1 zeichen zum
ifnb <char>
ldreg al,char ;;bildschirm
endif
call printchr
endm
;======
;setcurcol setzt den Cursor in der aktuellen Zeile auf die angegebene Position
setcurcol macro col
ldreg cl,col
call $setcurcol
endm
endif ;if1
$setcurcol:
push cx ;col (Spalte)
GetVid ;get Video Page
push bx
getcurpos bh ;get Cursor position
pop bx
pop cx
mov dl,cl ;col
setcurpos dh,cl,bh ;set Cursor position
ret
<a name="FILL"></a>
;======
;Stringbehandlung
;FILL: der ueber DI adressierte Speicher wird auf den in AL mitgegebenen Wert
;gesetzt. Mit cld wird eine aufsteigende Fuellrichtung erzwungen.
;======
if1
FILL macro nach,byte,laenge
ifdif <di>,<nach>
mov di,offset nach
endif
ldreg cx,laenge
cld
ldreg al,<b byte>
rep stosb
endm
;SCANS THE STRING 'FLD' FOR THE BYTE 'DATA'
;FOR A LENGTH OF 'LNG'. IF A MATCH IS FOUND BRANCH IS TAKEN TO 'FND'
SCANBYTE MACRO FLD,DATA,LNG,FND
LOCAL AGAIN
ifdif <di>,<fld>
mov di,offset FLD
endif
ldreg AL, <b DATA> ;;GET BYTE TO FIND
ldreg CX,LNG ;;SET LENGTH
AGAIN SCASB
JZ FND ;;BRANCH IF FOUND
LOOP AGAIN ;;KEEP GOING
ENDM
;COPY FROM ADDR TO TO ADDR FOR LNG
COPY MACRO FROM,TO,LNG
ifdif <si>,<from>
mov si,offset FROM
endif
ifdif <di>,<to>
mov di,offset TO
endif
ldreg CX,LNG ;;SET LENGTH
REP MOVSB ;;COPY THE DATA
ENDM
endif ;if1
IF STRING$
;======
;Stringbehandlung.
;Ein String wird durch eine hex.0 am Ende gekennzeichet.
;Er kann max. 0ffffh Bytes lang sein
;======
;Vergleich der durch DI u.SI adressierten Strings.
;Laenge in CX
;return: Zero-Flag set if =, Reset if <>
; Carry/Borrow set if Bereich [SI]<[di]
; di and si: adresse der beiden ersten ungleichen bytes falls <>
;======
;Register: siehe COMP
CMPSTR: mov al,[SI]
OR al,al
jz F39 ;Ende 1.String
cmp al,[DI]
jnz f40
INC SI
inc di
jmps CMPSTR
F39: cmp al,[DI]
f40: RET ;Fertig, moeglicherweise gleich
LENSTR: XOR al,al ;Laenge des ueber DI adressierten Strings nach CX
xor cx,cx
F41: cmp al,[DI]
jz f40 ;Ende gefunden
INC CX
inc di
jmps F41
;======
;sucht im String [DI] den kuerzeren String [SI]. Bei Return:
;AX=relative Startadr. im String [DI], (1.Byte=1)
;Zero-Flag gesetzt wenn nicht gefunden
;======
INSTR: PUSH DI
push si
CALL LENSTR ;Laenge STRING [DI] NACH dx
mov dx,cx
mov di,si
CALL LENSTR ;Laenge STRING [SI] NACH CX
pop si
POP DI
or cl,ch
jz f48 ;NO MATCH, IF [SI] EMPTY
mov ax,dx ;no match, if string[SI] lonther than string [DI]
SUB ax,cx
jnb F42
XOR ax,ax ;no match
RET
F42: INC ax ;WURZEL SUCHEN
mov CX,ax ;LETZTE VERGL. STELLE IN DI
mov dx,1 ;1.STELLE DI
mov al,[SI]
F43: cmp al,[DI]
JZ F45 ;MATCH 1.STELLE
F44: INC dx ;ERHOEHEN POS.
inc di
loop F43 ;WEITER SUCHEN
XOR ax,ax ;KEIN MATCH
RET
F45: PUSH SI ;VERGL. REST DES STRINGS
INC SI
PUSH DI
push ax
CALL F47
pop ax
POP DI
POP SI
jnz F44 ;NO MATCH
F46: XOR ax,ax
ADD ax,dx ;POS.NACH A
RET ;MIT UNGESETZTER ZEROFLAG
F47: mov al,[SI] ;WIE CMPSTR, ABER Laenge KANN UNGLEICH SEIN
INC SI
OR al,al
jz f48 ;GLEICH
inc di
cmp al,[DI]
JZ F47
f48: RET ;UNGLEICH
;======
;MOVSTR String [SI] nach String [DI]
;======
MOVSTR: mov al,[SI] ;String [SI]->[DI]
INC SI
mov [DI],al
INC DI
OR al,al ;Stringende ?
JNZ MOVSTR
RET ;Stringende
;======
;Bei den Codewandlungen wird der String mit SI adressiert.
;Codwandlung String in Upper Case
;======
UCASEG: mov dx,6120h ;DH = 'a', DL = conversion factor
$convupper:
mov al,[si]
or al,al
jz $updone
cmp al,dh
jb $lu
cmp al,'z'
ja $lu
sub al,dl
mov [si],al
jmps $luraus
$lu: cmp al,'ä'
jne $luoe
mov [si],byte ptr 'Ä'
jmps $luraus
$luoe: cmp al,'ö'
jne $luue
mov [si],byte ptr 'Ö'
jmps $luraus
$luue: cmp al,'ü'
jne $luraus
mov [si],byte ptr 'Ü'
$luraus:
inc si
jmps $convupper
$updone:
ret
;======
;Codwandlung String in Lower Case
;======
LCASEG: mov dx,4120h ;DH = 'A', DL = conversion factor
$convlower:
mov al,[si]
or al,al
jz $lodone
cmp al,dh
jb $ul
cmp al,'Z'
ja $ul
add al,dl
mov [si],al
jmps $ulraus
$ul: cmp al,'Ä'
jne $uloe
mov [si],byte ptr 'ä'
jmps $ulraus
$uloe: cmp al,'Ö'
jne $ulue
mov [si],byte ptr 'ö'
jmps $ulraus
$ulue: cmp al,'Ü'
jne $ulraus
mov [si],byte ptr 'ü'
$ulraus:
inc si
jmps $convlower
$lodone:
ret
ENDIF
;======
if ENTER$
;Eingabe der Fortsetzungsaufforderung
ENTER: prstr '->'
keyread
ret
;eingabe j/n im dialog
;bei return: 3 wenn ctrl c, sonst J oder N
INKJN: prstr ' (J/N)gt;'
keyread
cmp al,3 ;ctrl c ?
jne $inkjn4
ret
$inkjn4:
and al,5fh ;wandlung in
cmp al,'Y' ;Groáschrift
jne $inkjn5
mov al,'J'
$inkjn5:
cmp al,'J'
jne $inkjn6
ret
$inkjn6:
cmp al,'N'
jne inkjn ;nicht jny, also neueingabe!
ret
ENDIF
;======
if INTASC$
;======
;Konvertierungen Speicherbereich mit ASCII-Zahl aus/nach DX:AX mit Binaerzahl;
;alle Zahlen im positiven Bereich
;======
;Erzeugt eine Binaerzahl in DX:AX aus einer Dezimalzahl im mit SI adressierten
;Speicherbereich. Der Speicherbereich muss mit einer Dezimalzahl beginnen,
;Space wird als Ziffer 0 gewertet.
asc2int:
xor dx,dx ;Ziel (Akku) loeschen
xor ax,ax
asc2int5:
push dx
push ax
mov bl,[si]
CMP bl,cr ;War es ein Return ?
JE asc2int98 ;Ja, dann Eingabe beendet
or bl,bl ;war es hexa 0 ?
jz asc2int98 ;ja, dann Eingabe beenden
pop ax ;Zielakku *10
pop dx
sal ax,1 ;*2
adc dx,dx
push dx
push ax
sal ax,1 ;*4
adc dx,dx
sal ax,1 ;*8
adc dx,dx
pop bx ;*10
add ax,bx
pop bx
adc dx,bx
mov bl,[si] ;+neue Ziffer
cmp bl,spc
jnz asc2int7 ;space wird als 0 gewertet
mov bl,'0'
asc2int7:
SUB bl,48 ;Zahl = ASCII - 48
jb asc2int99 ;fertig, wenn nicht numerisch
cmp bl,10d
jnb asc2int99
inc si
mov bh,0
add ax,bx
adc dx,0
jmps asc2int5
asc2int98:
pop ax
pop dx
asc2int99:
RET ;Zahl in DX:AX
;======
int2asc:
XCHG BP,DX ;erzeugt aus Binaerzahl in DX:AX Dezimalzahl
MOV BX,0AH ;und baut sie rueckwaerts ab DI im Speicher auf
MOV CL,30H ;'0'
;Verfahren: Division mit 10d, Rest -> Speicher
int2asc2:
or bp,bp
JZ int2asc4
XCHG BP,AX
XOR DX,DX
DIV BX
XCHG BP,AX
DIV BX
OR DL,CL
MOV [DI],DL
DEC DI
jmps int2asc2
int2asc4:
XOR DX,DX ;kurze Zahl (DX war 0)
DIV BX
OR DL,CL
MOV [DI],DL
DEC DI
or ax,ax
JNZ int2asc4
ret
ENDIF
;======
if1 ;macros nur im 1.Durchlauf
if DUMP$
;Testhilfe: Minidump, Aufruf mit: bx=Adresse, cl=Anzahl Bytes
mdump macro adresse,anzahl
local mdump11,mdump22,mdump33,mdump44,mdump99
ldreg <bx>,<adresse>
ldreg <cl>,anzahl
mdump11: ;;Ausgabe Adresse
call mdump44
mdump22: ;;Ausgabe Wert
mov al,bl
and al,0fh ;;Ausgabe neue Zeile?
jnz mdump33 ;;nein
call mdump44 ;;ja
mdump33: ;;Ausgabe HEXA Byte
push cx
print_chr spc
mov al,[bx]
INC bx
CALL hex_out
pop cx
dec cl
jnz mdump22
print_crlf
jmps mdump99
mdump44: ;;Ausgabe neue zeile mit Adresse
push cx
print_crlf
mov al,bh
CALL hex_out
mov al,bl
CALL hex_out
print_chr ':'
pop cx
ret
mdump99:
endm
;Testhilfe: Registerdump, Aufruf ohne Parameter
rdump macro
local rdump10,rdump11,rdump50,rdump99
pushreg <ss,es,ds,cs>
pusha
prstr <cr,'di= si= bp= sp= bx= dx= cx= ax= cs= ds= es= ss=',cr>
rdump10:
mov cl,12d ;;Anzahl anzuzeigender Register im Datenteil
rdump11 equ $-1 ;;des Befehls
pop ax
call rdump50
dec b rdump11
jnz rdump10
print_crlf
jmps rdump99
rdump50:
xchg al,ah
push ax
call hex_out
pop ax
xchg al,ah
call hex_out
print_chr spc
ret
rdump99:
endm
endif ;DUMP$
endif ;if1
;======
;ausgabe 8 bit zahl (in al) in hexa
hex_out: push ax
shr al,1
shr al,1
shr al,1
shr al,1
call conv
pop ax
conv: and al,0fh
daa
add al,0f0h
adc al,40h
;Ausgabe Zeichen in al zum Bildschirm
printchr:
cmp al,cr ;cr?
je printchr8
cmp al,tab
je printtab
printchr1:
push cx
push bx
mov cx,1 ;1 zeichen
mov ah,9
xor bh,bh
mov bl,a_normal ;attribut wird modifiziert
attr equ $-1
int video ;zeichenausgabe
mov ah,3 ;cursorposition ermitteln
int video
inc dl ;x-position um 1 erhoehen
mov ah,2
int video
pop bx
pop cx
ret
$print_crlf:
mov al,cr
printchr8: ;ausgabe crlf
mov ah,0eh ;funktion tty-ausgabe
int video
mov ax,0e00h+lf
int video
ret
printtab: ;Spaces bis Tabulator
mov al,spc
call printchr1
mov ah,3 ;cursorposition ermitteln
int video
and dl,7
cmp dl,0
jnz printtab
ret
;programmbeendungen
ret0: xor al,al ;ausgang fuer fehlerfrei
jmps raus
ret1: mov al,1
jmps raus
ret3: mov al,3
;programmende
raus:
int21 4ch
;programmanfang
anfang:
mov ah,8 ;attribut lesen
xor bx,bx
int video
mov b attr,ah
|