I read a book about OS development and faced with a simple exercise: write a function that prints a hexadecimal value stored at a register. The program runs as a boot sector.
I would really appreciate suggestions and help for size optimization and functionality.
[BITS 16]
[ORG 0x7C00]
EntryPoint:
; Setup the stack:
xor AX, AX ; First of all set SS to 0x0000.
mov SS, AX ;
mov BP, 0x7BFF ; BIOS memory map description found on the Internet states that
; address space from 0x500 to 0x7BFF is guaranteed free for use.
mov SP, BP ; We will use it for our stack.
; Test of the PrintHex procedure:
mov BX, 0x2019 ; Load some number into BX.
call PrintHex ; Print it.
; Hang:
jmp $
;==============================================================================
; PROCEDURE PrintHex
;
; Description:
; Prints content of BX in form "0x0000" in teletype mode.
; Inputs:
; BX: number to print.
; Outputs:
; No.
;==============================================================================
PrintHex:
pusha
mov CX, BX ; Save the original number to CX.
mov SI, .alphabet ; Use SI as base for .alphabet array.
shr BX, 12 ; Get the first 4 bits of the original number (0x[1]234).
mov AL, [BX + SI] ; Use it as index in the array of hexadecimal digits. Thus get the appropriate character.
mov [.result + 2], AL ; Copy the character to the output array.
; In other words, these instuctions mean result[2] = alphabet[BX].
mov BX, CX ; Restore the original number.
shr BX, 8 ; Get the second 4 bits of the original number (0x1[2]34).
and BX, 0x0F ; We have to apply mask 0x0F to the value in order to get exactly 4 bits.
mov AL, [BX + SI] ; AL = alphabet[BX].
mov [.result + 3], AL ; result[3] = AL.
mov BX, CX ; Restore the original number.
shr BX, 4 ; Get the third 4 bits of the original number (0x12[3]4).
and BX, 0x0F ;
mov AL, [BX + SI] ; AL = alphabet[BX].
mov [.result + 4], AL ; result[4] = AL.
mov BX, CX ; Restore the original number.
and BX, 0x0F ; Get the last 4 bits of the original number (0x123[4]).
mov AL, [BX + SI] ; AL = alphabet[BX].
mov [.result + 5], AL ; result[5] = AL.
mov BX, .result ; Print the result.
call WriteString ;
popa
ret
.alphabet:
db '0123456789ABCDEF', 0x0
.result:
db '0x0000', 0x0
;==============================================================================
; PROCEDURE WriteString
;
; Description:
; Writes a null-terminated string to the screen using BIOS teletype mode text
; writing.
; Inputs:
; BX: address of the string.
; Outputs:
; No.
;==============================================================================
WriteString:
pusha
mov SI, 0 ; Use SI as index in the string.
.loop:
mov AL, [BX + SI] ; Move the current character at the string into AL.
cmp AL, 0x0 ; If the current character is null-terminator, then
je .break ; break the loop.
call WriteCharInTeletypeMode ; Otherwise print it.
inc SI ; Increment index and
jmp .loop ; jump to the beginning.
.break:
popa
ret
;==============================================================================
; PROCEDURE WriteCharInTeletypeMode
;
; Description:
; Writes a character in teletype mode using BIOS interrupts.
; Inputs:
; AL: character.
; Outputs:
; No.
;==============================================================================
WriteCharInTeletypeMode:
pusha
mov AH, 0xE ; Select BIOS function teletype mode text writing.
int 0x10
popa
ret
;==============================================================================
; Padding and the Bootloader Signature
;==============================================================================
times 510 - ($ - $$) db 0x0 ; Fill the rest of the file by zeroes.
db 0x55 ; The bootloader signature. Required by some BIOSes.
db 0xAA ;