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