I am trying to learn the 8086 assembly language. So as exercise, I decided to write a hexdump program, that outputs the contents of files in a format similar to Linux hexdump.
I am developing under Concurrent CP/M 86 inside an emulator.
My version of hexdump reads a file name from command line and print the contents on the console. I don't have any experience with the assembly language, so I'm trying to find ways to improve. I still don't know how to structure code and name labels and variables.
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