Search code examples
assemblyemu8086cursor-positiondosbox

Character reading does not work in graphical mode


I want to read a character and its attribute with ah=8 int 10h interrupt.

It works on text mode, but not in graphical mode (16-color 640 x 480).

mov ax,0012h
int 10h       ;graphical mode
int 10h

mov ah,0Ah
mov al,'1'
mov cx,200    ;printing '1' 200 times
mov bx,0
int 10h

mov ah,2
mov dx,0      ;moving cursor to (0,0)
mov bx,0
int 10h

mov bh,0
mov ah,8      ;reading the character
int 10h

Code has to give AH=07h & AL=31h.

But this code always gives AH=07h & AL=00h.

So how can I use this method with graphical mode?


Solution

  • Problems in a nutshell

    • Writing a redundant int 10h
    • Requesting a replication count that is too big
    • Outputting black characters on a black background
    • Interpreting random register content

    Explanations

    ...Writing a redundant int 10h

    mov ax,0012h
    int 10h       ;graphical mode
    int 10h
    

    It's never a good idea to call an api function without explicitely specifying the function number. You might think that in this example the AX register still holds 0012h (since function 00h is documented to return nothing), but that's not necessarily always the case.
    I don't know why you wrote that second int 10h. Maybe you had removed some extra instructions and simply forgot to remove this one. Can happen...

    ...Requesting a replication count that is too big

    From my VGA Programmer's Guide for BIOS.WriteCharacterOnly 0Ah:

    In the graphics modes, the number of times to replicate the character, is limited to the number of remaining character positions to the right of the cursor position until the end of the line.

    Your program specifies a replication count of 200 which is much more than the available 80 columns on the screen. Requesting too much results in unpredictable behaviour.
    The screenshot for emu8086 from your previous question already shows this problem. Look very carefully at the upperleft corner of the picture.

    Below is what my computer [1] shows when I request a replication count of 81. After having displayed 80 characters normally, the function wraps to the left edge of the screen but also descends a single scanline (is 1 pixel)! Now you can see that the 8x16 character box in the upperleft corner of the screen no longer holds a bitpattern that BIOS function 08h can recognize as a valid ASCII character and consequently function 08h will return with AL=0.

            x=0    x=7
            |      |
           .........................................
    y=0 -  .                                        
           .                                        
           .           **      **      **      **   
           .   **     ***     ***     ***     ***   
           .  ***    ****    ****    ****    ****   
           . ****      **      **      **      **   
           .   **      **      **      **      **   
           .   **      **      **      **      **   
           .   **      **      **      **      **   
           .   **      **      **      **      **   
           .   **      **      **      **      **   
           .   **    ******  ******  ******  ****** 
           . ******                                 
           .                                        
           .                                        
    y=15 - .                                        
    

    See this comment by Michael Petch about possible implementation differences between BIOS'es. It's a wise programmer that makes sure his program runs fine on a wide variety of machines.

    ...Outputting black characters on a black background

    When you invoke BIOS function 0Ah WriteCharacterOnly, the 'Only' applies exclusively to the alphanumeric video modes. In the graphics modes the value in the BL register is used for the character color. Your program passes 0 (black) as the character color and BIOS will use that on a black background. That's another reason for not being able to read something from the screen.

    ...Interpreting random register content

    From my VGA Programmer's Guide for BIOS.ReadAttributeCharacterPair 08h:

    No attribute code is returned when the display is in one of the graphics modes.

    Your program is in a graphics mode (16-color 640x480). You should not interpret the value that is in the AH register. It is whatever happens to be in there, so treat it as garbage. On your computer this register held 7, on mine [1] it held 5.

    Try this instead

    You don't need to move the cursor to the topleft corner of the screen since the cursor position wasn't modified by function 0Ah.

    mov     ax, 0012h  ; BIOS.SetVideoMode 16-color 640x480
    int     10h
    mov     cx, 80     ; Replication count
    mov     bx, 000Eh  ; Display page 0, character color Yellow
    mov     ax, 0A31h  ; BIOS.WriteCharacter(Only)
    int     10h
    mov     bh, 0      ; Display page 0
    mov     ah, 08h    ; BIOS.Read(Attribute)Character(Pair)
    int     10h        ; -> AL=31h
    

    [1] Phoenix TrustedCore v1.23 VGA BIOS 1264