I\'m using the 10h interrupt with AH as 0Eh to output \"Hello World!\" The text is ouputted but its not colored. I\'m running it on qemu-system-x86_64, assembling with NASM,
I was able to print with color by using the 09 for the 10h interrupt, instead of 0E. You do, however, have to change the cursor position after each character to use this method. Here is the working code.
BITS 16
start:
mov ax, 07C0h ; Set up 4K stack space after this bootloader
add ax, 288 ; (4096 + 512) / 16 bytes per paragraph
mov ss, ax
mov sp, 4096
mov ax, 07C0h ; Set data segment to where we're loaded
mov ds, ax
mov si, text_string ; Put string position into SI
call print_string ; Call our string-printing routine
jmp $ ; Jump here - infinite loop!
text_string db 'Hello World!', 0
print_string: ; Routine: output string in SI to screen
.repeat:
mov ah, 09h ; int 10h 'print char' function
mov bh, 0x00
mov bl, 0x03
mov cx, 01h
lodsb ; Get character from string
cmp al, 0
je .done ; If char is zero, end of string
int 10h ; Otherwise, print it
mov bh, 00h
mov ah, 03h
int 10h
mov ah, 02h
mov bh, 00h
inc dl
int 10h
jmp .repeat
.done:
ret
times 510-($-$$) db 0 ; Pad remainder of boot sector with 0s
dw 0xAA55 ; The standard PC boot signature
;make to use mov ah,0eh
bits 16
org 0x7c00
jmp basla
; clear screen with colour you want
basla:
;pencere boyutu 80x25 karakter
mov ah,06h
mov al,00h
mov bh,0ach ; ah zemin rengi,ch karakter rengi
mov cx,00h ;silmeye pencerenin sol ustunden basla
mov dx,184fh ;18h(24.satir) ve 4fh(79.sutun)a kadar sil.
int 10h
;then print your program
mov di,isim ;dizinin ilk adresini di kutuk yazmacina ata
call yazbas ; alt program cagriliyor
mov di,isim2 ;ikinci dizinin adresi ataniyor
call yazbas ;ayni alt program cagriliyor
jmp $ ;sonsuz dongu
yazbas:
mov ah,0eh
mov al,[di]
int 10h
inc di
or al,al
jz bitti
jmp yazbas
bitti:
ret
isim db "attila oguz",0
isim2 db "isletim duzenegine giris",0
times 510-($-$$) db 0
dw 0xaa55
For to change the cursor position:
text_string db 'Hello World!', 0
text_len = ($-text_string)-1
mov ah,3
xor bh,bh
int 10h
add dh,text_len
cmp dh,79
jb short P1
sub dh,79
inc dl
P1: mov ah,2
int 10h
RBIL->inter61a.zip->INTERRUP.A
--------V-1002-------------------------------
INT 10 - VIDEO - SET CURSOR POSITION
AH = 02h
BH = page number
0-3 in modes 2&3
0-7 in modes 0&1
0 in graphics modes
DH = row (00h is top)
DL = column (00h is left)
Return: nothing
SeeAlso: AH=03h,AH=05h,INT 60/DI=030Bh,MEM 0040h:0050h
--------V-1003-------------------------------
INT 10 - VIDEO - GET CURSOR POSITION AND SIZE
AH = 03h
BH = page number
0-3 in modes 2&3
0-7 in modes 0&1
0 in graphics modes
Return: AX = 0000h (Phoenix BIOS)
CH = start scan line
CL = end scan line
DH = row (00h is top)
DL = column (00h is left)
Notes: a separate cursor is maintained for each of up to 8 display pages
many ROM BIOSes incorrectly return the default size for a color display
(start 06h, end 07h) when a monochrome display is attached
With PhysTechSoft's PTS ROM-DOS the BH value is ignored on entry.
SeeAlso: AH=01h,AH=02h,AH=12h/BL=34h,MEM 0040h:0050h,MEM 0040h:0060h
I like it more to write directly into the segmentaddress of 0B800h.
mov ah,3 ; calculating the target offset address from the cursor position
xor bh,bh
int 10h
xor cx,cx
add dl,dl ; column
mov cl,dl
xor ax,ax
mov al,dh ; row
mov bx,160
mul bx
add ax,cx
mov di,ax
mov ax,0B800h
mov es,ax
mov si,text_string
mov cx,text_len
mov ah,3 ; color
cld
RP: lodsb ; get byte from DS:SI
stosw ; store word in ES:DI
loop RP
Not tested, but i hope no mistakes slept in.
I think a better idea than the one marked as accepted is to use function 13h of interrupt 10h. This function is supposed to send entire strings to the screen, along with attributes (colors). There are four modes of operation for this function, specified in the AL
register.
AL=00h: Assign all characters the attribute in
BL
; do not update the cursor position.
AL=01h: Assign all characters the attribute inBL
; update the cursor position.
AL=02h: Use attributes in string; do not update the cursor position.
AL=03h: Use attributes in string; update the cursor position.
So you can either use the same attribute (colors) for the entire string by specifying the attribute in BL
for modes 00h
or 01h
, or intermingle the attributes in the string itself to print each character with a different attribute.
The only drawback I see with this approach is that you have to know the length of the string upfront (to put it into CX
), since this function doesn't work with null-terminated strings.
But, on the other hand, storing a one-byte length of the string preceding its characters instead of the null character after its characters could have some benefits: You don't need to traverse the entire string to know its length; and a one-byte length won't take any more place than the null terminator. Even a two-byte length is not much a waste. You can load a two-byte length directly into CX
. You can do the same with a one-byte length, too, but make sure to clear out the CH
afterwards.
Having the ability attribute each character of the string alone also could be useful sometimes.
Other registers are as usual:
BH
is the page number.
DX
is where to start the string on the screen: DH:DL = Y:X
ES:BP
points to the first character of the string in memory.
If you use the teletype modes (01h
or 03h
), ASCII control characters are properly interpreted instead of being printed as symbols. They also update the cursor position to the end of the string.
To make it work continuously, you can use the function AH=03h
to get the cursor position. It is made so that it loads the cursor position to the DH:DL
, so it can be used afterwards directly in the subsequent call to AH=13h
to print the string from that position. Here's how I do it:
# Get cursor position.
getcur: mov $0x03, %ah # Get cursor position into DH:DL = Y:X.
int $0x10 # Video BIOS interrupt.
ret # Return to the caller.
# Print string with attributes.
# `putsa` expects attributes in `BL`.
# `puts` uses the default attributes (silver on black).
# Both expect a pointer to the string in `ES:SI`.
# The string should start with a 2-byte length information.
puts: mov $0x07, %bl # Default attribute: silver on black.
putsa: call getcur # Get cursor position into DH:DL.
mov (%si), %cx # Length of the string into `CX`.
mov %si, %bp # Prepare the pointer:
add $2, %bp # Skip the 2-byte length word.
mov $0, %bh # Use page #0.
mov $0x1301, %ax # Print string and update cursor.
int $0x10 # Video BIOS interrupt.
ret # Return to the caller.
Calling (assuming the ES
is properly set):
# Print a string with attributes.
lea msgHello, %si # String to print (after 2-byte length)
mov $0x0C, %bl # Attributes: light red on black.
call putsa
# Print it one more time with different attributes.
# Note we don't have to set the pointer: it's already set.
mov $0x0C, %bl # Attributes: yellow on black.
call putsa
The data section:
msgHello: .word 13 # Length of the string.
.ascii "Hello, World!" # The string itself.
Oh, and service is available only for XTs dated 01/19/1986 and later, ATs, EGAs, and PC Convertibles. But I guess it won't pose any problem, unless you're dealing with a serious piece of old junk ;-J