The interrupt ah=0Eh
int 10h
displays a character on the screen, it has several parameters including BH, which is supposed to indicate the page number, except that after several tests I realized that BH is absolutely useless. Even if I change the page number the character will still display on the active page no matter what.
Ralf Brown's interrupt list says
"IBM PC ROMs dated 1981/4/24 and 1981/10/19 require that BH be the same as the current active page"
And a page on the internet puts this : https://www.ic.unicamp.br/~celio/mc404-2004/service_interrupts#int10h_0Eh
This functions displays a character on the screen, advancing the cursor and scrolling the screen as necessary. The printing is always done to current active page.
I have to trust which source, I use virtual box without operating system, and I use a bootloader program.
I specify that I do not understand this information
IBM PC ROMs dated 1981/4/24 and 1981/10/19 require that BH be the same as the current active page
Knowing that I use virtual box, I do not think that virtual box uses ROMs from IMG PCs dating from 1981?
Service ah = 0x0E
, int 0x10
only prints on active page. You can change active page using service ah = 0x05
, al = page number
, int 0x10
.
BH isn't supposed to be an input to this BIOS function. Ralf Brown's interrupt list only shows it as part of documenting the bug in the two early IBM-PC BIOS versions it mentions (1981/4/24 and 1981/10/19) where BH needs to hold the active page number. Otherwise it's not an input at all.
I looked at the code of BIOS 1981-04-24, 1981-10-19 and 1982-10-27 and the service ah = 0x0E
(write_tty) in the first two BIOSes starts like this:
WRITE_TTY PROC NEAR PUSH AX ; SAVE REGISTERS PUSH AX ; SAVE CHAR TO WRITE MOV AH,3 INT 10H ; READ THE CURRENT CURSOR POSITION POP AX ; RECOVER CHAR . . . ;------ WRITE THE CHAR TO THE SCREEN MOV BH,ACTIVE_PAGE ; GET THE CURRENT ACTIVE PAGE MOV AH,10 ; WRITE CHAR ONLY MOV CX,1 ; ONLY ONE CHAR INT 10H
There is service ah = 0x03
(read_cursor) at the beginning which needs bh = page number
to calculate offset to cursor position on active page, this value is returned in DX and stored here:
CURSOR_POSN DW 8 DUP(?) ; CURSOR FOR EACH OF UP TO 8 PAGES
And later we have instruction mov bh,active_page
. For example we want to write to page 0, we calculate cursor position on page 0, but active_page = 1 so we have mismatch. So maybe that's why RBIL page talk about it, BH should be same as active_page.
IBM PC ROMs dated 1981/4/24 and 1981/10/19 require that BH be the same as the current active page
In last BIOS 1982-10-27, line MOV BH,ACTIVE_PAGE
changed position
WRITE_TTY PROC NEAR PUSH AX ; SAVE REGISTERS PUSH AX ; SAVE CHAR TO WRITE MOV AH,3 MOV BH,ACTIVE_PAGE ; GET THE CURRENT ACTIVE PAGE INT 10H ; READ THE CURRENT CURSOR POSITION POP AX ; RECOVER CHAR
BH is same as active_page. So program calculates position for correct page.
Here's an example of using it in a BIOS MBR bootloader. This works well in QEMU:
[org 0x7C00]
section .text
global main
main:
mov ax,0
mov ds,ax
mov ss,ax
mov sp,0x7C00
mov ax,0x0003
int 0x10
mov ah, 0x0E
mov si, msg1
Msg_1:
lodsb
or al,al
jz WaitKeyPress1
int 0x10
jmp Msg_1
WaitKeyPress1:
mov ah,0x00
int 0x16
mov ah,0x05
mov al,0x01
int 0x10
mov ah,0x0E
mov si,msg2
Msg_2:
lodsb
or al,al
jz WaitKeyPress2
int 0x10
jmp Msg_2
WaitKeyPress2:
mov ah,0x00
int 0x16
mov ah,0x05
mov al,0x00
int 0x10
Done:
jmp Done
msg1 db "This message is printed on page 0."
db 13,10,"Press any key to change page to 1...",0
msg2 db "And this message is printed on page 1."
db 13,10,"Press any key to go back to page 0.",0
times 510 - ($ - $$) db 0
dw 0xAA55
This works from the command line, as a DOS .COM:
[org 100h]
section .data
msg1 db "This message is printed on page 0."
db 13,10,"Press any key to change page to 1...",0
msg2 db "And this message is printed on page 1."
db 13,10,"Press any key to go back to page 0.",0
section .text
global main
main:
mov ax,0x0003
int 0x10
mov ah, 0x0E
mov si, msg1
Msg_1:
lodsb
or al,al
jz WaitKeyPress1
int 0x10
jmp Msg_1
WaitKeyPress1:
mov ah,0x08
int 0x21
mov ah,0x05
mov al,0x01
int 0x10
mov ah,0x0E
mov si,msg2
Msg_2:
lodsb
or al,al
jz WaitKeyPress2
int 0x10
jmp Msg_2
WaitKeyPress2:
mov ah,0x08
int 0x21
mov ah,0x05
mov al,0x00
int 0x10
Done:
mov ax,4C00h
int 21h