Программа 8086 шестнадцатеричного представления ассамблее


Я пытаюсь выучить язык 8086 ассамблеи. Так как тренировки, я решил написать программу, вывести, который выводит содержимое файлов в формате, аналогичном вывести Линукс.

Я занимаюсь разработкой под одновременным СР/М-86 внутри эмулятора.

Моя версия шестнадцатеричного представления считывает имя файла из командной строки и печатать содержимое на консоль. У меня нет никакого опыта с ассемблером, поэтому я пытаюсь найти способы, чтобы улучшить. Я до сих пор не знаю, как структурировать код и название метки и переменные.

ccpmint equ 224
p_termcpm equ 0
c_read equ 1
c_write equ 2
c_writestr equ 9
f_open equ 15
f_close equ 16
f_read equ 20
f_dmaoff equ 26

cseg

start:

    ; copy filename to fcb
    mov cx, 0
    mov di, offset fcb
    mov si, 05ch
fcbloop:
    cmp cx, 16
    jz  fcbend
    mov dl, [si]
    mov [di], dl
    inc si
    inc di
    inc cx
    jmp fcbloop
fcbend:

    ; set current dma to dma in dseg
    mov cl, f_dmaoff
    mov dx, offset dma
    call ccpm

    ; open the file
    mov cl, f_open
    mov dx, offset fcb
    call ccpm
    cmp al, 0
    jnz error

    ; read the file
    mov readcnt, 0
read_loop:
    mov cl, f_read
    mov dx, offset fcb
    call ccpm
    cmp al, 0
    jnz read_end

    mov ax, readcnt
    inc ax
    mov readcnt, ax
    mov cl, c_writestr
    mov dx, offset crlf
    call ccpm
    call print_dma
    mov cl, c_read
    call ccpm
    jmp read_loop
read_end:
    cmp al, 01h
    jnz error

    ; close the file
    mov cl, f_close
    mov dx, offset fcb
    call ccpm
    cmp al, 0
    jnz error

terminate:
    ; terminate the program
    mov cl, p_termcpm
    mov dx, 0
    call ccpm

error:
    ; error handling
    mov tmp, ax
    mov cl, c_writestr
    mov dx, offset errmsg
    int ccpmint
    mov al, last_cl
    call print_byte
    mov cl, c_writestr
    mov dx, offset erral
    int ccpmint
    mov ax, tmp
    call print_byte
    mov cl, c_writestr
    mov dx, offset errah
    int ccpmint
    mov ax, tmp
    mov al, ah
    call print_byte
    mov cl, c_writestr
    mov dx, offset crlf
    int ccpmint
    jmp terminate

print_dma:
    ; fill lines of 16 bytes and prints each line
    mov cx, 0
    mov si, offset dma
    mov di, offset buf
pdmaloop:
    mov ax, [si]
    mov [di], ax
    inc cx
    inc si
    inc di
    mov ax, 0fh
    and ax, cx
    jnz pdmaloop
    call print_line
    cmp cx, 128
    jz pdmaend
    mov di, offset buf
    jmp pdma_loop
pdmaend:
    ret


print_line:
    ; prints a single dma line: address, bytes, chars
    ; address = readcnt*128 + cx
    push cx
    mov dx, cx
    mov ax, readcnt
    mov cl, 7
    shl ax, cl
    add ax, dx
    call print_word
    mov cl, c_write
    mov dl, 32
    call ccpm

    ; print bytes
    mov di, offset buf
    mov cx, 0
plbloop:
    mov tmp, cx
    mov al, [di]
    call print_byte
    mov cl, c_write
    mov dl, 32
    call ccpm
    mov cx, tmp
    inc cx
    inc di
    cmp cx, 16
    jnz plbloop

    ; print chars
    mov di, offset buf
    mov cx, 0
plcloop:
    mov tmp, cx
    mov al, [di]
    cmp al, 32
    jb plcpdot
    cmp al, 126
    jbe plcpchr
plcpdot:
    mov al, '.'
plcpchr:
    mov cl, c_write
    mov dl, al
    call ccpm
    mov cx, tmp
    inc di
    inc cx
    cmp cx, 16
    jb plcloop

    ; write crlf and return
    mov cl, c_writestr
    mov dx, offset crlf
    call ccpm
    pop cx
    ret

print_word:
    ; prints a word: the highest byte, then the lowest
    push ax
    mov al, ah
    call print_byte
    pop ax
    call print_byte
    ret

print_byte:
    ; prints the two characters of a byte in al
    push ax
    and al, 0f0h
    mov cl, 4
    shr al, cl
    call print_nibble
    pop ax
    and al, 0fh
    call print_nibble
    ret

print_nibble:
    ; prints a single hexadecimal digit
    cmp al, 9
    jg pnib_af
    add al, '0'
    jmp pnib_w
pnib_af:
    add al, 'A'-10
pnib_w:
    mov cl, c_write
    mov dl, al
    int ccpmint
    ret

ccpm:
    mov last_cl, cl
    int ccpmint
    ret

dseg
org 100h

errmsg  db  'error: function=$'
erral   db  ', al=$'
errah   db  ', ah=$'
crlf    db  10,13,'$'
fcb rs  33
dma rs  180
buf rs  16
tmp rw  1
readcnt rw  1
last_cl db  0
end

Это, как он составлен: enter image description here

И вот как это выглядит при выполнении: enter image description here enter image description here



243
10
задан 26 марта 2018 в 12:03 Источник Поделиться
Комментарии
1 ответ

Я не знакома с одновременным СР/М-86, но я знаю, что мои 8086.

...
dseg
org 100h
...

Я нашел это замечательно, чтобы увидеть org 100h директива до сих пор в вашей программе. Я ожидал этого почти на первой линии источника!


Я до сих пор не знаю, как структурировать код и название метки и переменные.

Кроме моего замечания о ORG это на самом деле довольно хороший.
Вы использовали описательные имена, и есть хороший заказ подпрограмм.



mov dx, 0

Каждый раз, когда вы очистите реестр (любой регистр общего назначения!), вы можете сделать это более эффективно XOR ную регистра с самим собой.

xor dx, dx    ;Will set DX=0



   ; copy filename to fcb
mov cx, 0
mov di, offset fcb
mov si, 05ch
fcbloop:
cmp cx, 16
jz fcbend
mov dl, [si]
mov [di], dl
inc si
inc di
inc cx
jmp fcbloop
fcbend:

Та часть, где вы копируете имя файла может быть значительно улучшена с помощью movs строки примитивной инструкции. Вы загружаете нужную сумму в CX а затем повторять (rep) операции. Направлении флаг (ДФ) снят заранее, чтобы заставить процессор обновления SI и DI регистрирует перемещение в памяти.

; copy filename to fcb
mov cx, 16
mov di, offset fcb
mov si, 05ch
cld
rep movsb



mov ax, readcnt
inc ax
mov readcnt, ax

Приращение переменной readcnt может быть сделано в одной инструкции:

inc readcnt



print_dma:
; fill lines of 16 bytes and prints each line
mov cx, 0
mov si, offset dma
mov di, offset buf
pdmaloop:
mov ax, [si]
mov [di], ax
inc cx
inc si
inc di
mov ax, 0fh
and ax, cx
jnz pdmaloop
call print_line
cmp cx, 128
jz pdmaend
mov di, offset buf
jmp pdma_loop
pdmaend:
ret

Эта процедура должна обработать байт (вы поднимаете адресов по 1), но вы читать и писать слова!
Тест, чтобы увидеть, если были обработаны 16 байт-это слишком сложно. Все что нужно-это испытание CX С 15.

print_dma:
; fill lines of 16 bytes and prints each line
xor cx, cx
mov si, offset dma
pdmaloop_:
mov di, offset buf
pdmaloop:
movsb
inc cx
test cx, 15
jnz pdmaloop
call print_line
cmp cx, 128
jne pdma_loop_
ret

Видишь, как я сократил количество инструкций, вводя дополнительную этикетку на верхней части и больше не нуждается в этикетке на дне?



print_word:
; prints a word: the highest byte, then the lowest
push ax
mov al, ah
call print_byte
pop ax
call print_byte
ret
print_byte:

А call прямо над ret можно смело заменить jmp.
Но поскольку цель вытекает сразу, можно просто не писать jmp.

print_word:
; prints a word: the highest byte, then the lowest
push ax
mov al, ah
call print_byte
pop ax
print_byte:



    call print_nibble
pop ax
and al, 0fh
call print_nibble
ret
print_nibble:

Аналогичным образом этот фрагмент приобретает следующий вид:

    call print_nibble
pop ax
and al, 0fh
print_nibble:



    cmp al, 9
jg pnib_af
add al, '0'
jmp pnib_w
pnib_af:
add al, 'A'-10
pnib_w:

Более простой способ преобразования следующим образом. Он использует меньше ярлыки что хорошо для удобочитаемости. Он использует меньше скачков, что хорошо для скорости.

    cmp al, 10
jb pnib_
add al, 7 ;7 is ('A' - 10) - '0'
pnib_:
add al, '0'

6
ответ дан 26 марта 2018 в 02:03 Источник Поделиться