8086 Assembler (MS-DOS) vs Turbo C:
HD - hexadezimale Dateianzeige (Zweite Version)

Hinweis: Ein praktisch funktionsgleiches 32-bit-Programm ist im Abschnitt über den MASM32-SDK beschrieben. Das 32-bit-Programm ist auch in Windows-Versionen ab Windows 7 verwendbar. Das auf dieser Seite für MS-DOS beschriebene 16-bit-Programm lässt sich ab Windows 7 nicht mehr verwenden.
Zwar funktioniert die auf der vorigen Seite beschriebene erste Version des Programmes zur Anzeige eines Hexadezimaldumps - aber sie schreit förmlich nach einer Verbesserung: Pro Ausgabezeile wird etwa 60-mal der MS-DOS-Interrupt mit Funktion 40h aufgerufen. Dadurch wird die Ausführungsgeschwindigkeit deutlich abgebremst!

Die auf dieser Seite gezeigte zweite Version des Hexadezimaldumpprogrammes vermeidet fast alle Aufrufe des MS-DOS-Interrupts mit Funktion 40h. Das wird erreicht, indem die ermittelten Ausgabeteile nicht sofort zur Anzeige geschickt werden, sondern sie werden in den vorbereiteten Druckpuffer (dz im Programmlisting) gestellt. Erst wenn eine Zeile fertig zusammengestellt ist, wird einmalig der MS-DOS-Interrupt mit Funktion 40h aufgerufen.

Die Formatierung des Druckpuffers dz erfolgt dadurch, dass die Vorgabezeile lz in ihren Bereich kopiert wird. Die Vorgabezeile enthält bereits alle in der Ausgabezeile vorhandenen Spaces, alle Punkte, den Doppelpunkt und das Pipe-Symbol.

Das ausführbare Programm ist mit 1000 Bytes etwa 120 Bytes länger als auf der vorigen Seite beschriebene Programm. Es läuft jedoch spürbar schneller ab.


.MODEL SMALL
.386
;======================================
;Hexadezimaldump
;Eingabedatei ueber Standardeingabe,
;Ausgabe/Anzeige ueber Standardausgabe
;======================================
;
false   equ     0
true    equ     not false

dump$   equ     false   ;fuer mdump, rdump
prompt$ equ     false   ;fuer enter, inkjn
intasc$ equ     false   ;fuer int2asc, asc2int
string$ equ     false   ;fuer fill, cmpstr, lenstr, instrg, movstr, ucaseg, lcaseg

pipe    equ     0b3h    ;Pipe-Zeichen (senkrechter Strich)

.STACK  256
.DATA
        include MAC32.mac
;Arbeitsfelder
address dd      0       ;adresse
text    db      0       ;zu verarbeitendes zeichen
cnt     db      0       ;zeilenzaehler

lz      db      '........: ',50 dup (spc),pipe,spc,16 dup ('.'),cr,lf
llz     equ     $ - lz
dz      db      llz-18 dup (spc)
asc     db      18 dup (spc)    ;zeichenausgabebereich + cr lf
dzpos   dw      0               ;positionszeiler druckpuffer
asccnt  dw      0               ;zeichenzaehler fuer ausgabebereich
;in MAC32.mac sind definiert:
;wcrlf   db     cr,lf,'$'       ;ausgabestring zeilenvorschub
;wcolon  db     ':'             ;ausgabestring : ggf mit spaces
;wspc    db     spc,spc         ;ausgabestring spaces

.CODE
_start: mov     ax,@DATA        ;Initialisieren des Datensegment-Registers
        mov     ds,ax
        mov     es,ax           ;auch ES auf datenseqment zeigen lassen
        jmp     around

;print message following call prmsg and ending with 0
prmsg:  pop     si
        push    ds      ;sichern ds
        push    cs
        pop     ds      ;ds zeigt nun auf das Codesegment
        call    printa
        pop     ds      ;nach Ausgabe ds wieder herstellen
        push    si      ;returnadr.
        ret

;druckt die mit ds:si adressierte zeichenkette
;die zeichenkette darf keine steuerzeichen ausser cr und attribute enthalten
;sie endet mit 0h
printa:
        push    ax
        cld

printa5:
        lodsb           ;zeichen
printa_b9:
        or      al,al   ;ob fertig ?
        jz      printa7 ;ja
        call    printchr
        jmp     printa5

printa7:
        pop     ax
        ret

;======
if1                     ;macros nur im 1.durchlauf
prstr   macro   texte    ;;print string
        call    prmsg
        dbz     <texte>
        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
endif                   ;if1

;ausgabe zeichen in al nach standardausgabe
printchr:
        cmp     al,cr   ;cr?
        je      $print_crlf

        push    bx
        push    cx
        push    dx
        mov     dl,al
        int21   2
        pop     dx
        pop     cx
        pop     bx
        ret

$print_crlf:
        push    bx
        push    cx              ;Ausgabe crlf nach handle 1
        push    dx
        mov     dl,cr
        int21   2
        mov     dl,lf
        int21   2
        pop     dx
        pop     cx
        pop     bx
        ret
;einspeichern einer 8bit-ziffer als 2 byte ascii (hexadezimal)
;in den mit bx adressierten puffer
;die ziffer wird in al uebergeben
byte_hex:
        push    ax
        shr     al,1
        shr     al,1
        shr     al,1
        shr     al,1
        call    byte_hex1
        pop     ax

byte_hex1:
        and     al,0fh
        daa
        add     al,0f0h
        adc     al,40h

;einspeichern zeichen in al in den mit bx adressierten puffer
printchr1:
        mov     bx,dzpos
        mov     [bx],al
        inc     bx
        mov     dzpos,bx
        ret

;unterprogramm zur 4-stelligen adressausgabe (8 hexadezimalziffern)
pa00:   lea     bx,dz           ;anfangsadresse druckzeile
        mov     dzpos,bx
        mov     bx,offset address + 3
        mov     cx,4            ;adresse vierstellig hexa
pa10:   push    cx              ;ausgeben (rueckwaerts)
        mov     al,[bx]
        dec     bx
        push    bx              ;upro byte_hex zerstoeert bx
        call    byte_hex
        pop     bx
        pop     cx
        loop    pa10
        ret

around:
;hauptprogramm
        cld                     ;richtung aufwaerts
        push    ds
        pop     es              ;es zeigt nun auf das datensegment
ha00:   lea     si,lz           ;"leerzeile" initialisiert
        lea     di,dz           ;"druckzeile"
        mov     cx,llz
        rep movsb
        call    pa00            ;adressanzeige
        inc     dzpos           ;ueber esc spc hinweg
        inc     dzpos

        mov     cx,16           ;16 Bytes ergeben eine Zeile

ha01:   push    cx              ;sichern Schleifenzaehler
        mov     bx,0            ;Handle console (eingabe)
        mov     cx,1            ;1 Zeichen lesen
        mov     dx,offset text
        int21   3fh
        or      ah,al           ;ax ist 0 wenn EOF
        jz      fertig

        mov     al,text
        call    byte_hex        ;Zeichen hexadezimal in den druckpuffer
        inc     dzpos           ;ueber spc hinweg
        pop     cx
        push    cx
        cmp     cx,9
        jne     ha05

        inc     dzpos           ;doppelter Abstand nach 8 zeichen
ha05:   mov     al,text

        cmp     al,00h          ;00, cr, lf, tab werden als
        je      ha12            ;punkt angezeigt. der punkt
                                ;steht bereits im druckpuffer
        cmp     al,cr
        je      ha12

        cmp     al,lf
        je      ha12

        cmp     al,tab
        je      ha12

ha10:   lea     bx,asc
        add     bx,asccnt       ;ascii-zeichen zum
        mov     [bx],al         ;ausgabebereich
ha12:   inc     asccnt
        pop     cx              ;Schleifenzaehler
        loop    ha01

;neue Zeile:
        fwrit   1,dz,llz        ;zeile anzeigen
        lea     si,lz           ;"leerzeile" initialisiert
        lea     di,dz           ;"druckzeile"
        mov     cx,llz
        rep movsb

        mov     asccnt,0        ;zeichenzaehler loeschen
        add     address,10h
        mov     ah,cnt
        inc     ah
        mov     cnt,ah
        test    ah,07h
        jnz     ha00            ;keine leerzeile zusaetzlich
        print_crlf              ;eine leerzeile zusaetzlich
        jmp     ha00

fertig:
        fwrit   1,dz,llz        ;zeile anzeigen
        MOV     AX,4C00h        ;EXIT
        INT21
        END     _start
Letztes Upload: 29.11.2021 um 15:28:49 • Impressum und Datenschutzerklärung