More output in text modes

I am going to cover some more ways of outputting text in text modes. This first program is an example of how to move the cursor to display a string of text where you want it to go.
Listing 12: TEXT1.ASM

.model tiny 
.code
org 100h
start:

mov dh,12 			; cursor col 
mov dl,32 			; cursor row
mov ah,02h 			; move cursor to the right place
xor bh,bh 			; video page 0
int 10h 			; call bios service

mov dx,OFFSET Text		; DS:DX points to message
mov ah,9 			; function 9 - display string
int 21h 			; all dos service

mov ax,4C00h  			; exit to dos
int 21h

Text DB "This is some text$" 

end start
This next example demonstrates how to write to the screen using the file function 40h of interrupt 21h.
Listing 13: TEXT2.ASM

.model small
.stack
.code

mov ax,@data 		; set up ds as the segment for data
mov ds,ax 		

mov ah,40h 		; function 40h - write file
mov bx,1 		; handle = 1 (screen)
mov cx,17 		; length of string
mov dx,OFFSET Text 	; DS:DX points to string
int 21h 		; call DOS service

mov ax,4C00h 		; terminate program
int 21h

.data

Text DB "This is some text"

end
The next program shows how to set up and call function 13h of interrupt 10h - write string. This has the advantages of being able to write a string anywhere on the screen in a specified colour but it is hard to set up.
Listing 14: TEXT3.ASM

.model small
.stack
.code

mov ax,@data 		; set up ds as the segment for data
mov es,ax 		; put this in es

mov bp,OFFSET Text 	; ES:BP points to message
mov ah,13h 		; function 13 - write string
mov al,01h 		; attrib in bl,move cursor
xor bh,bh 		; video page 0
mov bl,5 		; attribute - magenta
mov cx,17 		; length of string
mov dh,5 		; row to put string
mov dl,5 		; column to put string
int 10h 		; call BIOS service

mov ax,4C00h 		; return to DOS
int 21h

.data

Text DB "This is some text"

end
The next program demonstrates how to write to the screen using rep stosw to put the writing in video memory.
Listing 15: TEXT4.ASM

.model small
.stack
.code

mov ax,0B800h 	; segment of video buffer
mov es,ax 	; put this into es
xor di,di 	; clear di, ES:DI points to video memory
mov ah,4 	; attribute - red
mov al,"G" 	; character to put there
mov cx,4000 	; amount of times to put it there 
cld 		; direction - forwards
rep stosw 	; output character at ES:[DI]

mov ax,4C00h 	; return to DOS
int 21h

end
The next program demonstrates how to write a string to video memory.
Listing 15: DIRECTWR.ASM

; write a string direct to video memory 

.model small
.stack
.code

mov ax,@data
mov ds,ax

mov ax,0B800h 		; segment of video buffer
mov es,ax 		; put this into es
mov ah,3 		; attribute - cyan
mov cx,17 		; length of string to print
mov si,OFFSET Text 	; DX:SI points to string
xor di,di

Wr_Char:

lodsb 			; put next character into al 
mov es:[di],al 		; output character to video memory
inc di 			; move along to next column
mov es:[di],ah 		; output attribute to video memory
inc di

loop Wr_Char 		; loop until done

mov ax,4C00h 		; return to DOS
int 21h

.data

Text DB "This is some text" 

end
It is left as an exercise to the reader to modify it so that only one write is made to video memory.

Mode 13h

Mode 13h is only available on VGA, MCGA cards and above. The reason that I am talking about this card is that it is very easy to use for graphics because of how the memory is arranged.

First check that mode 13h is possible

It would be polite to tell the user if their computer cannot support mode 13h instead of just crashing it computer without warning. This is how it is done.
Listing 16: CHECK13.ASM

.model small
.stack
.data

NoSupport db "Mode 13h is not supported on this computer."
	  db ,"You need either a MCGA or VGA video" 
	  db ,"card/monitor.$"

Supported db "Mode 13h is supported on this computer.$"

.code

mov ax,@data 		; set up DS to point to data segment
mov ds,ax 		; use ax 

call Check_Mode_13h 	; check if mode 13h is possible

jc Error 		; if cf=1 there is an error

mov ah,9 		; function 9 - display string
mov dx,OFFSET Supported ; DS:DX points to message
int 21h 		; call DOS service

jmp To_DOS 		; exit to DOS

Error:
mov ah,9 		; function 9 - display string
mov dx,OFFSET NoSupport ; DS:DX points to message
int 21h 		; call DOS service

To_DOS:
mov ax,4C00h 		; exit to DOS 
int 21h

Check_Mode_13h PROC 	; Returns: CF = 1 Mode 13h not possible

mov ax,1A00h 		; Request video info for VGA
int 10h 		; Get Display Combination Code
cmp al,1Ah 		; Is VGA or MCGA present?
je Mode_13h_OK 		; mode 13h is supported
stc 			; mode 13h isn't supported CF=1

Mode_13h_OK:

ret 
Check_Mode_13h ENDP

end 
Just use this to check if mode 13h is supported at the beginning of your program to make sure that you can go into that mode.

Setting the Video Mode

It is very simple to set the mode. This is how it is done.
mov ax,13h 	; set mode 13h
int 10h 	; call BIOS service
Once we are in mode 13h and have finished what we are doing we need to we need to set it to the video mode that it was in previously.

This is done in two stages. Firstly we need to save the video mode and then reset it to that mode.

VideoMode db ?
.
.
mov ah,0Fh 	 ; function 0Fh - get current mode
int 10h 	 ; Bios video service call
mov VideoMode,al ; save current mode

; program code here

mov al,VideoMode ; set previous video mode
xor ah,ah 	 ; clear ah - set mode
int 10h 	 ; call bios service

mov ax,4C00h 	 ; exit to dos
int 21h 	 ; call dos function
Now that we can get into mode 13h lets do something. Firstly lets put some pixels on the screen.

Function 0Ch: Write Graphics Pixel

This makes a colour dot on the screen at the specified graphics coordinates.

INPUT:

AH = 0Ch
AL = Color of the dot
CX = Screen column (x coordinate)
DX = Screen row (y coordinate)

OUTPUT:

Nothing except pixel on screen.

Note: This function performs exclusive OR (XOR) with the new colour value and the current context of the pixel of bit 7 of AL is set.

This program demonstrates how to plot pixels. It should plot four red pixels into the middle of the screen.

Listing 17: PIXINT.ASM

; example of plotting pixels in mode 13 using bios services - 
; INT 10h

.model tiny
.code
org 100h
start:

mov ax,13 	; mode = 13h 
int 10h 	; call bios service

mov ah,0Ch 	; function 0Ch
mov al,4 	; color 4 - red
mov cx,160 	; x position = 160
mov dx,100 	; y position = 100
int 10h 	; call BIOS service

inc dx 		; plot pixel downwards
int 10h 	; call BIOS service
inc cx 		; plot pixel to right
int 10h 	; call BIOS service
dec dx 		; plot pixel up
int 10h 	; call BIOS service

xor ax,ax 	; function 00h - get a key
int 16h 	; call BIOS service

mov ax,3 	; mode = 3
int 10h 	; call BIOS service

mov ax,4C00h 	; exit to DOS
int 21h

end start

Some Optimizations

This method isn't too fast and we could make it a lot faster. How? By writing direct to video memory. This is done quite easily.

The VGA segment is 0A000h. To work out where each pixel goes you use this simple formula to get the offset.

Offset = X + ( Y * 320 )

All we do is to put a number at this location and there is now a pixel on the screen. The number is what colour it is. There are two instructions that we can use to put a pixel on the screen, firstly we could use stosb to put the value in AL to ES:DI or we can use a new form of the MOV instruction like this:

mov es:[di], color
Which should we use? When we are going to write pixels to the screen we need to do so as fast as it is possible.
Instruction 	   Pentium  486   386   286   86

STOSB 	              3      5     4     3    11
MOV AL to SEG:OFF     1      1     4     3    10
If you use the MOV method you may need to increment DI (which STOSB does).

If we had a program which used sprites which need to be continuously draw, erased and then redraw you will have problems with flicker. To avoid this you can use a 'double buffer'. This is another part of memory which you write to and then copy all the information onto thescreen.

Return to Table of Contents