<--- Turn the page     (contents page)     Turn the page --->


Assembler




Have you ever go dumped back in to dos and the colors are not what they should be. On DOS user told me a little while ago that a program he was using SHELLed to DOS with the color attribute set to Black text on Black Background. A CLS would take of of this, however he was asking about programming it rather than calling the DOS CLS command.

DOS prints to the screen memory two bytes for each character. The first byte is the ascii char while the second byte is the color attribute. To easily change the color of the screen without modifying the existing text, simply modify this second byte.

The color is specified in AH with the background in the HI nibble and the text color in the LO nibble. Please note with the background color. If you set the HI nibble to a value with the HI bit set, the video card will take the LO 3 bits as the color and blink. To stop the blinking, you must call INT 10h, service 1003h, with BL cleared.

.model tiny
.code

       mov  di,00h     ; di = 0
       mov  cx,2000    ; cx = 2000
       mov  ax,0B800h  ; es = 0B800h
       mov  es,ax
loop1: mov  ax,es:[di] ; get the word
       mov  ah,07h     ; ah = 07h
       stosw           ; put it back
       loop loop1      ; loop cx times
       ret             ; exit
.end
That is all we have to do. It is fairly quick too. Keep reading to find out how to optimize this snippet of code for size and speed.

With assembler, it is very easy to optimize your code. First of all, if we look at the code above, we get the WORD of the character in memory rather than just the attribute byte. This takes time to get the word and set AH to the color attribute 2000 times. Also, if we rely on the initial registers at .COM file startup, we can do a few tricks to make our code smaller.



Look at the following:
.model tiny
.code

         xchg di,ax      ; di = 0, ax = 0FFFEh
         xchg cx,ax      ; cx = 0FFFEh, ax = 00FFh
         mov  bh,0B8h    ; bx = 0B800h
         mov  es,bx      ; es = bx
         mov  al,07h     ; al = 07h
loop1:   inc  di         ; di += 1
         stosb           ; put it
         loop loop1      ; cx -= 1
         ret             ; exit
.end

Let us assume the following values for each of the registers we use above.
AX and BX  = 0000h
CX         = 00FFh
DI         = FFFEh
ES         = CS
First of all we exchange DI and AX. This sets DI to zero, or offset 00h.

Next we exchange CX and AX. This sets CX to 0FFFEh, more than enough to change all 2000 bytes. (Don't need to worry about changing any of the memory past the 2000 bytes in segment 0B800h.)

Now we need to point ES to 0B800h. Since we can not MOV an immediate into a segment register, we must use a general purpose register. It is one byte smaller to set BH to 0B8h then BX to 0B800h. We will do this since BX = zero on start up.

Now set AL to the color attribute specified and start our loop.

INC DI to the second byte and store our value using STOSB which also increments DI to the first of the next character word.

The optimized code is 6 bytes smaller and considerably faster.

Please don't send me "flame" mail about how you can make it smaller and faster, or how I should use actual memory modification rather than STOSB on Pentiums. I did this optimize bit to show that it can be done easily without getting out that spec sheet on clock counts and processor types. ¥


<--- Turn the page     (contents page)     Turn the page --->

Page 9