Code Gems Part 2
This text comes from IMPHOBIA Issue IX - February 1995
* Short Palette Loading *
The traditional method to fill the palette registers sounds somehow like
this (15 bytes+palette):
mov al,startcolor
mov dx,3c8h
out dx,al
inc dx
mov cx,colornum*3
mov si, offset rgbpalette
rep outsb
Here's the shorter way (13+1 bytes+palette):
mov dx,03c8h
mov si, offset startcolor
outsb
inc dx
mov cx,colornum*3
rep outsb
After startcolor come the RGB components.
And here's the general procedure:
setpal:
mov dx,3c8h
outsb
inc dx
lodsw
xchg cx,ax
rep outsb
ret
After startcolor (the byte at [SI]) is colornum*3 (the word at [SI+1]), then
the RGBs. SI is loaded by the caller.
* Feeding the VGA registers *
An usual VGA initializer routine:
mov dx,03xxh
mov ax,xx
out dx,ax
mov dl,xx
mov al,xx
out dx,al
...
But why not to collect the values into one array like this:
mov si,offset vgaregs
mov dx,03xxh
outsw
mov dl,xx
outsb
...
This may be combined, per chance with REP OUTs too. Make sure that CH won't
be loaded unnecessarily after REPs.
See:
mov cl,3
rep outsb
is longer than
outsb
outsb
outsb
but gives the same result.
* A nice tweaked mode operation *
Let's put a raw picture's line:
mov al,2
mov dx,3c4h
out dx,al
inc dx
mov al,11h
mov cx,linelength
onerow:
out dx,al
movsb
rol al,1
adc di,0ffffh
loop onerow
Actually this is a very slow way to do it, I wanted to show just its philosophy.
* XCHG instead MOV and PUSH/POP *
Note that
xchg reg,ax
takes only 1 byte and the TASM compiles XCHG ANYREG,AX even if we write XCHG AX,ANYREG.
And
xchg ax,ax
is nothing else but the good old NOP.( Protected mode freaks may think
XCHG EAX,EAX :-) Sometimes when there is a free register, double XCHG REG,AX
is better than PUSH/POP AX.
* Short Compare *
If a routine gives back the result in a register and its value is 0 on error
and 1 on success, the ordinary
or ax,ax
je error
can be replaced with the shorter
dec ax
jne error
For example, the XMS driver reports the errors this way. Is it fair that
testing if a register=0 is longer than testing if it is 1 or -1? :-(
* Tiny Little Instructions *
CBW/CWD/CDQ/CWDE are the short ways to clear/set AH/DX/EDX/upper word of EAX
when the MSB of AL/AX/EAX/AX is known in advance.
* Writing a two-digit number *
Let's suppose we want to write out a two-digit number in any numerical
system between [2..10]. Value comes in AL, the base of the numerical system is in AH.
WRITE2DIGIT macro
local zeros,convert
mov byte ptr aam_operand,ah
call convert
zeros db '00$'
convert:
aam_operand equ $+1
aam
xchg ah,al
add word ptr zeros,ax
mov ah,9
pop dx
int 21h
endm
See it from a debugger ;-) When we want to write decimal numbers
only, then unnecessary to rewrite the AAM's operand. The morals of the macro:
1. AAM has an operand, which is 0ah by default. It can be redefined.
2. Don't forget to purge the prefetch queue with a JMP or CALL when using self-modifying code near to IP.
3. See Ralph Brown's IntrList for more undocumented functions.
* Puzzle *
Remember? The solution is under 4 instructions...
* HLT *
HLT can be useful! It's very easy to make timings with it:
mov cx,18
hlt
loop $-1
This was an 1-second delay.
* Macro Fun *
Let me ask You one of my favourite questions! Which programming language
is this:
Writeln('Hello, world!');
Pascal...?
Not!
This is assembly.Here's the solution:
WRITELN macro _string
local _afterstring
call _afterstring
db _string,13,10,'$'
_afterstring:
mov ah,9
pop dx
int 21h
endm
This idea was taken from Silent's Planet Zzyqxhaycom BBS advert.
* Optimizing for coding time *
Look at this:
b equ byte ptr
w equ word ptr
o equ offset
...
With these abbrevations some typing time can be saved.
(Invented by TomCat.)
* Puzzle - The Solution *
imul eax,01010101h
(Now you can kill me.)
I would be very glad if the next issue would contain another part(s) of Code
Gems from other coders. If You want to contact me, here's my address:
Ervin / AbaddoN
Ervin Toth
HUNGARY
1126 Budapest
Kiss Janos str. 48/a
(+36)-1-201-9563
ervin@unicorn.sch.bme.hu