masm
COMMENT ` (haftmann#software) +++FREEWARE+++
MIT HILFE DIESER DATEI KANN MAN GANZ EINFACH UND SCHNELL KRZESTE
ASSEMBLER-PROGRAMME SCHREIBEN! Folgende Zeilen gengen frs erste:
include prolog.asm
[DEBUG] ;Debug-Header fr Pseudo-COM's
ret ;1 Byte; DIESES PROGRAMM LUFT !!!
endc
Assemblieren mit TASM /zl name[.asm] ;Wozu gibt's den Norton Commander?
Linken mit TLINK /t name[.obj] ;Am besten diese Jobs auf ".ASM" legen!
Ausprobieren mit NAME[.COM] ;fertig!!!
Beschreibung der Funktionen der PROLOG.ASM:
(<>: Pflichtparameter, [] freie Parameter)
PROLOG.ASM schaltet auf folgende Standards:
<IDEAL, MODEL tiny, %TRUNC, %CONDS, %NOMACS, %NOSYMS, CODESEG>
nl NewLine, Abk. fr 0dh,0ah
ParaRes Gleichung fr residente Paragrafen
by Abk. fr "byte"
wo Abk. fr "word"
ofs Abk. fr "offset"
len Abk. fr "length"
ResizeM [x1] Komplettes Programmstck zum Verndern der Speicherblockgre.
Erfordert die Marke ResEnd bei Angabe ohne Parameter oder der Speicher
wird ab <x1> freigegeben.
PRINT <^str> Programmstck zur Ausgabe eines $-terminierten Strings per
DOS-Funktion.
JN <cc>,<label> Ersetzt fehlenden Jump Near Conditional der 80x86-CPU
bzw. die %JUMPS-Anweisung. Erzegt den 5-Byte-Ersatzcode. Zugelassene
Bedingungen sind z.Z. nur: "z","nz","c","nc" (Klein!!)
JR <label> Erzeugt Short-Sprung (Abk. fr JMP SHORT label)
CALLF [seg:ofs] erzeugt ohne Parameter den Code 9Ah fr Call Far.
Mit Parametern anschlieend die Bytes
JMPF [seg:ofs] siehe CALLF
EX <x1>,<x2> Austausch von Registern oder Speicherzellen.
Speziell fr den Austausch der Segmentregister ES und DS
LD <x1>,<x2> Laden via Push und Pop, spez. fr Segregs!
XLD <x1>,<x2>,[x3]..[x8] Kettenladebefehl von rechts nach links
DOS [x1],[x2] DOS-Funktionsaufruf; x1=AH, x2=AL. Wenn x1 bzw.
x2 fehlt, wird nur 1 8-Bit-Register geladen. Sind beide angegeben,
wird AX geladen. Fehlen beide, dann nur Aufruf des Int21
Ist x1100h wird AX mit dem Wert von x1 geladen und x2 ignoriert!
VID Dasselbe fr Int10
KBD Dasselbe fr Int16
INTR Master-Makro fr DOS, VID, KBD mit vorangestellter IntNo (ein Mu!)
ALIGNV <ausr>,[fllb] Erzeugt ein Alignment in angegebener Ausrichtung,
Fllbyte defaultmig "?".
SDS ) <dest>,<reg> Fllt das Doppelwort "dest" mit DS:reg auf. Gegen-
SES ) funktion zu LDS, LES, LSS
SSS )
SCS )
LSSx <reg>,<src> Fehlender LoadSS des 8086
DPS <string> Definiert PASCAL-String mit fhrendem Lngen-Byte.
DCL <string> Definiert DOS-Kommandozeilenstring, wie DPS, jedoch
mit abschlieendem 0Dh
DXS <xorbyte>,<char-chain> Definiert gescrambelte Zeichenkette. (Zeichen-
kette in spitzen Klammern ohne '' angeben!! Keine CRLF's u..)
DCD <val> Definiert "val" als numerische Zeichenkette im Speicher.
(zur Ausgabe der [festen] Programmgre o..) Keine Vorwrtsreferenzen
bitte!
DVT Definiere 1 Programmverteilertabellen-Eintrag: 1 Byte und 1 Word
DZ Definiere nullterminierten String, notfalls nur eine Null
DEBUG Debug-Code kopiert PSP an den COM-Anfang und korrigiert Segmentregs.
Im Turbo Debugger den CALL-Befehl mit F8 bergehen!
ENDC Komfortable END-Anweisung. Mit Beachtung einer evtl. Einbindung
des Makros DEBUG
_OCHR Komplett-Routine zur Zeichenausgabe (Zeichen in AL, VR:-)
Ansprungmarke: OCHR
_AXHX Komplett-Routine zur Zeichen- und Hexzahlausgabe, folgende Marken:
AXHX: AX hex ausgeben
AHEX: AL hex ausgeben
AHEX1: AL-Low-Nibble hex ausgeben
OCHR: AL ASCII ausgeben
Alle folgenden Prozeduren definieren 1 gleichnamiges Label ohne "_"
_ALDEZ Sternis geniale DOS-Uhrzeitkonvertierung, nur fr AL=0..99!
_AXDEZ AX dezimal ausgeben 1..5 Zeichen
_UPCASE Upcase-Routine AL->AL
_TOUP Komfort-Upcase mit Umlauten, zieht _UPCASE nach sich
_TOLOW Lowcase-Rountine AL->AL
_ANUM Wandelt ASCII in AL in numerischen Wert <36 um, bei Fehler AL>=36
_INW 1 Word ab [SI] einlesen, BL=Zahlenbasis. Zieht _ANUM nach sich
PA: AX: Zahl, CY=1: Fehler: Gar keine Ziffern oder Zahl zu gro
SI zeigt auf erste Nicht-Ziffer
_INW2 1 Word ab [SI] einlesen, Zahlenbasis mit Prfixen # (dez) und $ (hex)
berschreibbar; PA: s. _INW, dazu BL=Neue Basis. Zieht INW nach sich!
_INW3 wie INW2, jedoch dezimale Vorgabe und C-mige Prfixe dazu.
Zieht _INW2 nach sich!
_CHKWS Check AL auf WhiteSpace 0,9,0a,0d,20 PA: Z=1 A ist Whitespace
_CRLF Na was wohl? Aber ohne Register einzusauen! Bentigt _OCHR!
_CASE CASE-Anweisung via Tabelle! Wandelt Byte zu Wort wie UPV
_UPV Unterprogrammverteiler [si]=Optionsbuchstabe, di=Tabelle, s.a. DVT
_IS286 Programm testet ob mindestens 80286; CY=0 wenn ja
_IS386 Programm testet ob 80386; CY=0 wenn ja; schliet _IS286 ein
PSPOrg eine Marke am PSP-Anfang
COMentry hier geht das COM-Programm los!
(Assembler-Programm also mit END COMentry beenden!)
Sollte ausnahmsweise eine .EXE gewnscht werden, empfiehlt sich der
Befehl ORG 0 direkt nach der Include-Anweisung. Dann ist aber ein *anderer*
Eintrittspunkt zu whlen!
`
IDEAL
%NOINCL
MODEL tiny
%TRUNC ;Begrnzen von Strings im Object-Code
%CONDS ;Auch nicht bersetzte IF's listen
%NOMACS ;Keine Makros expandieren (Papier sparen)
%NOSYMS ;Keine "Symboltabelle" bitte!
NOMULTERRS ;Nie mehrere Fehler pro Quellzeile bitte!
nl equ <13,10> ;Zeilenende
ParaRes equ <(ResEnd-PSPOrg+15)/16>
;Residente Paragrafen eines .COM-Programms
by equ <byte>
wo equ <word>
ofs equ <offset>
len equ <length>
macro ResizeM r1
ifb <r1>
mov bx,ParaRes
else
mov bx,(r1-PSPOrg+15) / 16
endif
DOS 4ah
endm
macro PRINT str ;handhabbares Ausgabekommando
mov dx,offset str
mov ah,9
int 21h
endm
macro JN cc,lab ;Jump Near conditional
ifidn <cc>,<c>
jnc $+5
jmp lab
elseifidn <cc>,<nc>
jc $+5
jmp lab
elseifidn <cc>,<z>
jnz $+5
jmp lab
elseifidn <cc>,<nz>
jz $+5
jmp lab
else
err <Unknown condition code>
endif
endm
macro JR lab
jmp short lab ;KC-like
endm
macro SEGOFS r1 ;Internes Makro!
ifnb <r1>
@cxxf1 instr <r1>,<:>
if @cxxf1 lt 2
err <Wrong colon>
endif
@cxxf2 substr <r1>,1,@cxxf1-1
@cxxf3 substr <r1>,@cxxf1+1
dw @cxxf3,@cxxf2
endif
endm
macro CALLF r1 ;r1 Seg:Ofs
db 9ah
segofs <r1>
endm
macro JMPF r1 ;r1: Seg:Ofs
db 0eah
segofs <r1>
endm
macro EX r1,r2 ;zum Vertauschen von Segmentregistern
errifb <r1> <Operand expected>
errifb <r2> <Operand expected>
push r1 r2
pop r1 r2
endm
macro LD r1,r2 ;zum Laden von Segmentregistern
errifb <r1> <Operand expected>
errifb <r2> <Operand expected>
push r2
pop r1
endm
macro XLD r1,r2,r3,r4,r5,r6,r7,r8
ifnb <r8>
mov r7,r8
endif
ifnb <r7>
mov r6,r7
endif
ifnb <r6>
mov r5,r6
endif
ifnb <r5>
mov r4,r5
endif
ifnb <r4>
mov r3,r4
endif
ifnb <r3>
mov r2,r3
endif
mov r1,r2
endm
macro DOS r1,r2
INTR 21h,<r1>,<r2>
endm
macro VID r1,r2
INTR 10h,<r1>,<r2>
endm
macro KBD r1,r2
INTR 16h,<r1>,<r2>
endm
macro LoadAX r1,r2
ifb <r2>
ifnb <r1>
if r1 ge 256
mov ax,r1
else
mov ah,r1
endif
endif
else
ifb <r1>
mov al,r2
else
mov ax,r1*256+r2
endif
endif
endm
macro INTR intno,r1,r2 ;r1=ah, r2=al
LoadAX r1,r2
int intno
endm
;Alignment with Value
macro ALIGNV w1,w2
local w3
ife w1 GT 0
err <False Operand>
endif
; errife (w1 GT 0) <False Operand>
w3 = w1- (($-PSPOrg) MOD w1)
if w3 NE w1
ifnb <w2> ;;Existiert w2?
db w3 dup (w2)
else ;;wenn nicht
db w3 dup (?)
endif
endif
endm
macro SDS dest,reg ;Store DS:reg into dest
mov [wo LOW dest],reg
mov [wo HIGH dest],ds
endm
macro SES dest,reg ;Store ES:reg into dest
mov [wo LOW dest],reg
mov [wo HIGH dest],es
endm
macro SSS dest,reg ;Store SS:reg into dest
mov [wo LOW dest],reg
mov [wo HIGH dest],ss
endm
macro SCS dest,reg ;Store CS:reg into dest
mov [wo LOW dest],reg
mov [wo HIGH dest],ss
endm
macro LSSx reg,src ;Load SS:reg from src
mov reg,[wo LOW src]
mov ss,[wo HIGH src]
endm
;; Aufrufen mit DPS <'Hallo!',13,10>
macro dps w1
local dpsa,dpse
;;Define Pascal String (with length byte)
db LOW (dpse-dpsa)
dpsa: db w1
dpse:
endm
macro dcl w1 ;;Definiere Kommandozeilen-String
dps <w1>
db 13
endm
macro dxs x1,w1 ;Define Xored String
irpc c,<w1>
db '&c' xor x1
endm
endm
;;Note that x MUST BE a value, create it using %-Operator
macro dcd x ;Define Constant String Of A Decimal Word
local deno
deno = 10000
rept 5
if (x/deno GT 0) OR (deno EQ 1)
db ((x/deno) MOD 10)+'0'
endif
deno = deno/10
endm
endm
macro DVT c,w ;;Definiere Verteilertabelleneintrag
db c
dw ofs w
endm
macro DZ str ;;Definiere nullterminierten String
ifnb <str>
db str
endif
db 0
endm
macro entr w1 ;wie ENTER beim 286
if @CPU and 2
enter w1,0
else
push bp
mov bp,sp
ifnb <w1>
sub sp,w1 ;;lokale Variablen
endif
endif
endm
macro leav ;wie LEAVE beim 286
if @CPU and 2
leave
else
mov sp,bp
pop bp
endif
endm
macro _ochr ;Zeichenausgabe aus AL
ochr: push ax dx
mov dl,al
DOS 2
pop dx ax
ret
endm
macro _axhx ;Hexzahlausgabe, VR: AX,F
axhx: xchg al,ah
call ahex
xchg al,ah
ahex: push ax cx ;Werte erhalten
mov cl,4 ;oberes Nibble auf Bit 3...0
shr al,cl ; schieben
pop cx
call ahex1
pop ax
ahex1: and al,0fh
add al,90h ;Hex -> ASCII
daa
adc al,40h
daa
_ochr
endm
macro _ALDEZ ;AL zu Dezimal-String in AX wandeln
aldez:
xor ah,ah
aam ;dividiert AL durch 10
xchg al,ah ;AH=Rest, Low-Teil, AL=High-Teil
add ax,'00' ;fertig zum Einpoken
ret
endm
macro _AXDEZ ;AX dezimal ausgeben
proc axdez
push ax cx dx
xor cx,cx ;Vornullunterdrckung
mov bx,10000
call @@1 ;hinterlt in ax den Rest!
mov bx,1000
call @@1
mov bx,100
call @@1
mov bx,10
call @@1
add al,'0'
call ochr
pop dx cx ax
ret
@@1: ;Ziffernausgabe, ax=Zahl, bx=Teiler, cx=Vornull-Flag
xor dx,dx ;High-Teil=0
div bx ;ax:=ax/bx, Rest dx (bx Dezimalzahl?!)
push dx
or cx,ax ;Evtl. Ziffer anmelden
or cx,cx ;Immer noch Vornull?
jz @@3 ;Ziffer
add al,'0'
call ochr
@@3: pop ax ;Rest
ret
endp
endm
macro _UPCASE
proc UpCase
cmp al,'a'
jb @@1
cmp al,'z'
ja @@1
and al,not 20h
@@1: ret
endp
endm
macro _TOUP ;Komfort-Upcase mit lnderspezifischer Umsetzung (?)
proc ToUp
cmp al,80h
jc @@e
entr 20h
push bx cx dx ds ss
pop ds
lea dx,bp-20h
push ax ;Zeichencode
DOS 3800h
pop ax
jc @@e1
call [dword bp-20h+12h]
@@e1: pop ds dx cx bx
leav
@@e: endp
_UPCASE
endm
macro _TOLOW
proc ToLow
cmp al,'A'
jb UpCas1
cmp al,'Z'
ja UpCas1
or al,20h
@@1 ret
endp
endm
macro _ANUM ;stellt fest, ob AL eine "Ziffer" ist
;Zulssig: 0..9, A..Z, a..z
proc Anum ;gemopst von CAOS NT
;A numerisch wandeln
;PE: A-ASCII-Code
;PA: A: Zahl, die A reprsentierte
;A>=36 wenn nicht im zulssigen Bereich
;VR: AF
SUB al,30H
jc @@e
CMP al,10
jc @@e
SUB al,11H
AND al,not 20h
ADD al,10
@@e: RET
endp
endm
macro _INW ;Liest Word ein PE: BL: Zahlenbasis
;PA: CY=1: Gar keine Ziffern zum Einlesen oder Zahl zu gro
;SI zeigt aufs erste falsche Zeichen
;(Auswertung desselben ist Sache des Hauptprogramms!)
proc InW
push bx cx dx
xor cx,cx
mov bh,ch ;Null
mov al,[si]
call Anum
cmp al,bl
cmc
jc @@e ;;Fehler
@@1: mov ah,0
xchg ax,cx ;;bisherige Zahl nach AX, neue nach CX
mul bx ;;DXAX=BX*AX
add dx,-1
jc @@e ;;Fehler: Zahl zu gro
add cx,ax ;;Zur neuen Ziffer bl*bisherige dazu
jc @@e
inc si
mov al,[si]
call Anum
cmp al,bl
jc @@1 ;;wenn Ziffer klein genug
@@e: xchg ax,cx
pop dx cx bx
ret
endp
_ANUM
endm
macro _INW3 ;;C-mige Zahlenauswertung dazu,
;;Dezimalvorgabe! VR:BL
InW3: mov bl,10 ;;Immer dezimal!
cmp [by si],'0'
jnz inw3e
mov bl,8
inc si
cmp [by si],'x'
jnz inw3e
cmp [by si],'X'
jnz inw3e
mov bl,16
inc si
_INW2
endm
macro _INW2 ;wie oben, jedoch Prfixauswertung wie folgt:
;BL: Default-Basis (meist 10 oder 16)
;am Anfang #: Immer dezimal
; $: Immer hex
InW2: cmp [by si],'#'
jnz inw2b
mov bl,10
jr inw2a
inw2b: cmp [by si],'$'
jnz inw2e
mov bl,16
inw2a: inc si
inw2e: _INW
endm
macro _CHKWS
proc ChkWs ;Check for WhiteSpace, Z=1: Es ist welcher
or al,al
jz @@e
cmp al,9
jz @@e
cmp al,' '
jz @@e
cmp al,13
jz @@e
cmp al,10
@@e: ret
endp
endm
macro _CRLF
crlf: push ax
mov al,13
call ochr
mov al,10
call ochr
pop ax
ret
endm
macro _CASE ;fhrt Case-Anveisung via Tabelle durch
proc case ;PE: DI: Tabelle, AL: Zeichen (Byte); CY=1: Zeichen nicht
;enthalten; dann zeigt DI auf ELSE-Zweig
;Endekennung der Tabelle: Null-Byte! (leichte Einschrnkung)
@@r: cmp [by es:di],1
jc @@3
scasb
jz @@2 ;CY=0!
scasw ;Nchstes Wort bergehen
jr @@r
@@3: inc di
@@2: ret
endp
endm
macro _UPV ;zieht nicht mehr _CASE nach sich!
; _CASE
proc upv ;Unterprogrammverteiler nach Tabelle ES:DI
;Holt sich ein Zeichen ab [si] und fhrt Programm nach
;Tabelle aus
cld
lodsb
call UpCase
call Case ;nach DI
jc @@2
jmp [wo es:di] ;UP rufen; CY bedeutet Abbruchs-Erzwingung,
;z.B. Fehler oder Hilfeseite, AX=Code!
;AX=0: Nur Abbruch, keine zentrale Fehlermeldung
;AX=1: Fehler in Kommandozeile, SI zeigt auf
;unpassendes Zeichen
@@2: mov ax,1
dec si ;Pointer zurck
ret
endp
endm
macro _IS286 ;Is at least 80286?
push sp ;;continue with: jc WrongProcessor
pop ax
cmp ax,sp ;;ax less sp?
endm
macro _IS386
local isn286
_IS286 ;Is at least 80386?
jc isn286
mov ax,7000h
push ax
popf
pushf
pop ax
and ax,7000h
sub ax,1 ;Z->CY
isn286:
endm
macro DEBUG ;Debug-Hilfe, kopiert PSP vornan
local deb01,deb02
org 0
int 20h ;das Original hier
deb01: push cs
pop es
mov si,ofs deb02
mov di,si
mov cx,COMentry-deb02
cld
rep movsb
push cs
pop ds
mov sp,cx ;Null
push cx ;Return zum Int20
jmp si
deb02:
org 0fdh
DEBentry:
call deb01
endm
macro ENDC str ;;komfortable End-Anweisung
local ende1 ;;Wenn str=debug dann eingebaute Debug-Utility
ifb <str>
ifdef DEBentry
ende1 = DEBentry
else
ende1 = COMentry
endif
else
ende1 = str
endif
end ende1 ;;Diese Konstruktion vermeidet Warnings
endm
CODESEG
PSPOrg: ;eine Marke Wert 0 aber verschieblich weil im Codesegment definiert
org 100h
COMentry:
; ENDC ;Semikolon nur zu Testzwecken entfernen!
Vorgefundene Kodierung: UTF-8 | 0
|