Spinning planes demo animation (vejat2)

From: laura fairhead (laura_fairhead_at_INVALID.com)
Date: 10/15/03


Date: Wed, 15 Oct 2003 18:44:24 +0000

Hi ppl,

This has been optimised to run on a 486/100, and is as fast as I can get it so
far - it's still missing frames but I think it looks ok.

The code is a total mess I know (most of it is old and is going to be killed
off soon :) but it was either that or only post a binary which I think is not
really good or progressive for this grp.

If anyone has trouble with the display not working please tell me because
I've heard of problems with my tweaked VGA mode, in fact I'll post another
thread about that soon in case anyone else has ideas.

To assemble (minimal MASM) delete everything after ';;' and replace the
remaining ';' with newlines. I've put a bat file underneath with the
actual executeable in it in case you don't have MASM (maybe it will assemble
with TASM i dunno' )

byefornow,
l

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
OPTION SCOPED
OPTION SEGMENT:USE16
.486

osdx EQU 0Ch
stksiz EQU 0400h

phi0k EQU 012400000h
phi0 EQU 022400000h
phi0d EQU 001C00000h

phi1 EQU 01CC00000h
phi1d EQU 002400000h

scal0 EQU 07D1F0000h
scal0phi EQU 000110000h

cseg SEGMENT BYTE

ASSUME NOTHING
ORG 0100h

kode PROC NEAR

CLD
MOV AH,04Ah;MOV BX,OFFSET endof+0Fh;SHR BX,4;INT 021h;JC errmem
MOV SP,OFFSET stk+stksiz
CALL NEAR PTR osc1is;JC errmem

CALL NEAR PTR m324
MOV EAX,040404h;MOV BL,0;CALL NEAR PTR spal
CALL NEAR PTR spalr

;;
;;theta osc
;;f/mod all freq=phi0k, out of phase phi0+i*phi0d
MOV CX,4
MOV BX,OFFSET osd
MOV EDX,phi0
lopk6:
MOV DI,OFFSET ws
MOV SI,DI
MOV EAX,EDX;STOSD
ADD EDX,phi0d
MOV EAX,phi0k;STOSD
MOV EAX,028000000h;STOSD
MOV EAX,02C000000h;STOSD
MOV DI,BX
CALL NEAR PTR osc1i
MOV BX,DI
LOOP lopk6

MOV CX,4
lopk3:
MOV DI,OFFSET ws
MOV SI,DI
XOR EAX,EAX;STOSD
XOR EAX,EAX;STOSD
XOR EAX,EAX;STOSD
DEC EAX;STOSD
MOV DI,BX
CALL NEAR PTR osc1i
MOV BX,DI
LOOP lopk3

;;
;;4* scale osc
MOV EDX,phi1
MOV CX,4
lopk0:
MOV DI,OFFSET ws
MOV SI,DI
XOR EAX,EAX;STOSD
MOV EAX,EDX;STOSD
ADD EDX,phi1d
MOV EAX,scal0;STOSD
ADD EAX,scal0phi;STOSD
MOV DI,BX
CALL NEAR PTR osc1i
MOV BX,DI
LOOP lopk0

mlop:
;;
;;set plcdat
;;

;;f/mod theta osc
MOV SI,OFFSET osd
MOV CX,4
lopk5:
CALL NEAR PTR osc1uu
MOV [SI-020h+020h*4+8],EAX
LOOP lopk5

;;theta osc, set plcdat
MOV DI,OFFSET plcdat
MOV CX,4
lopk4:
CALL NEAR PTR osc1uu
MOV [DI+4],EAX
ADD DI,010h
LOOP lopk4

MOV DI,OFFSET plcdat
MOV CX,4
lopk1:
CALL NEAR PTR osc1uu
STOSD
ADD DI,4
XOR EAX,EAX;STOSD
STOSD
LOOP lopk1

;;
;;get vector data->plddat
MOV SI,OFFSET plcdat
MOV DI,OFFSET plddat
MOV CX,4
lopk2:
PUSH CX;CALL NEAR PTR prjv;POP CX
LOOP lopk2

CALL NEAR PTR vsy
;;
;;do project
MOV BX,WORD PTR DS:[scrseg]
MOV SI,OFFSET plddat
CALL NEAR PTR prj4

;;
;;user
MOV AH,0Bh;INT 021h;CMP AL,0;JZ mlop
MOV AH,7;INT 021h
CMP AL,01Bh;JZ SHORT don0
JMP mlop

don0:
MOV AX,2;INT 010h

terminat:
MOV AL,0
terminat0:
MOV AH,04Ch;INT 021h

erripa:
MOV SI,OFFSET terripa;MOV AL,2;JMP SHORT err
errmem:
MOV SI,OFFSET terrmem;MOV AL,1
err:
PUSH SI
MOV SI,OFFSET terr;CALL NEAR PTR pstr
POP SI;CALL NEAR PTR pstrcr
JMP terminat

terr:
DB "ERROR: ",0
terrmem:
DB "memory allocation failure",0
terripa:
DB "invalid parameter format",0

kode ENDP

spalr PROC NEAR

;;
;; my new palette
;;
;; miss out zero cause we want the screen (border)
;; this is a continuous problem really - with the border frame
;; colour zero is slightly out in the main palette but we
;; can't avoid to using it in the algorithm because then scaling
;; would have to be 1 to 255 which is out of phase with everything else
;; (and would take ages to get it right)
;;
;; OTOH I think this is a pretty good palette without going overboard
;; on the maths to find something ultra-smooth (and use the last 4 colour)
;; well there are other things to do now like cleaning up the sine generator
;; maybe getting rid of those sines altogether dunno'
;;
MOV BL,0;XOR EAX,EAX
lop1:
MOV EDX,EAX
MOV EAX,EDX;ADD EAX,010000h
CMP BL,0;JZ SHORT ko0;CALL NEAR PTR spal
ko0:
INC BL
MOV EAX,EDX;ADD EAX,000100h
CALL NEAR PTR spal
INC BL
MOV EAX,EDX;ADD EAX,000001h
CALL NEAR PTR spal
INC BL
MOV EAX,EDX;ADD EAX,000101h
CALL NEAR PTR spal
INC BL
LEA EAX,WORD PTR DS:[EDX+010101h]
CMP BL,0FCh;JNZ lop1
MOV EAX,03F3F3Fh;CALL NEAR PTR spal;INC BL
MOV EAX,03F3F3Fh;CALL NEAR PTR spal;INC BL
MOV EAX,03F3F3Fh;CALL NEAR PTR spal;INC BL
MOV EAX,03F3F3Fh;CALL NEAR PTR spal;INC BL
RET

;;
;; old palette
;; why don@t I delete it? Hmmmm...
;;
ENTER 0Ch,0

MOV WORD PTR [BP-2],00400h
MOV WORD PTR [BP-4],00400h
MOV WORD PTR [BP-6],00400h
MOV WORD PTR [BP-8],(03000h-00400h)/0100h
MOV WORD PTR [BP-0Ah],(02780h-0400h)/0100h
MOV WORD PTR [BP-0Ch],(03F00h-0400h)/0100h
MOV CX,0100h
MOV DI,OFFSET padat
CALL NEAR PTR rgad

MOV SI,OFFSET padat+3
MOV AX,1;MOV CX,0FFh;CALL NEAR PTR spalb

LEAVE
RET

rgad:
MOV AX,[BP-2];ADD AX,[BP-8];MOV [BP-2],AX
MOV AL,AH;STOSB
MOV AX,[BP-4];ADD AX,[BP-0Ah];MOV [BP-4],AX
MOV AL,AH;STOSB
MOV AX,[BP-6];ADD AX,[BP-0Ch];MOV [BP-6],AX
MOV AL,AH;STOSB
LOOP rgad
RET

spalr ENDP

;;------------------------------------- MODULES ----------------------

;;
;;prjv- calculate plane vectors and projection origin
;;
;;entry: SI=plane data
;;
;; +0 dw scale
;; +4 dw theta
;; +8 dw origx
;; +C dw origy
;;
;; DI=store vector data
;;
;;exit: data stored
;;
;; +0 dw origx
;; +4 dw origy
;; +8 2dw vx
;; +10 2dw vy
;; (+18)
;;
;; DI updated (DI+=018h)
;; SI updated (SI+=010h)
;;

prjv PROC NEAR

PUSH EDI

MOV AX,WORD PTR [SI+6]
CALL NEAR PTR stax
MOV EBP,EAX ;;ESI=st(theta)

MOV AX,WORD PTR [SI+6]
ADD AH,040h
CALL NEAR PTR stax ;;EAX=st(theta+pi/2)

;;
;;calculate vectors
                            ;;EAX=st(theta)
SAR EAX,7
MOV ECX,EAX;NEG ECX ;;ECX=-st
MOV EDI,0AAAAAAAh
IMUL EDI;SHL EDX,4
MOV EBX,EDX ;;EBX=2/3st
MOV EAX,EBP ;;EAX=st(theta+pi/2)
SAR EAX,7
MOV EBP,EAX
IMUL EDI;SHL EDX,4
MOV EDI,EDX

;;
;;EDI=vy(y) EBX=vy(x) ECX=vx(y) EBP=vx(x)

MOV EAX,DWORD PTR [SI+0]
IMUL EDI;MOV EDI,EDX;SHL EDI,4
MOV EAX,DWORD PTR [SI+0]
IMUL EBX;MOV EBX,EDX;SHL EBX,4
MOV EAX,DWORD PTR [SI+0]
IMUL ECX;MOV ECX,EDX;SHL ECX,4
MOV EAX,DWORD PTR [SI+0]
IMUL EBP;MOV EBP,EDX;SHL EBP,4

;;get centre central
MOV EAX,ECX;ADD EAX,EDI
MOV EDX,-080h;IMUL EDX;ADD EAX,020000000h
ADD EAX,DWORD PTR [SI+8]
XCHG EDI,DWORD PTR [ESP]
STOSD ;;origx

MOV EAX,EBP;ADD EAX,EBX
MOV EDX,-080h;IMUL EDX;ADD EAX,020000000h
ADD EAX,DWORD PTR [SI+0Ch]
STOSD ;;origy

XCHG EBP,EAX;STOSD
XCHG ECX,EAX;STOSD
XCHG EBX,EAX;STOSD
MOV EAX,DWORD PTR [ESP]
STOSD

ADD SI,010h

POP EAX
RET

prjv ENDP

;;
;;get sine EAX

steax PROC NEAR

SHR EAX,010h
stax::
XCHG BX,AX
ADD BX,BX
SBB ECX,ECX
ADD BX,BX
SBB AX,AX
AND AL,0FCh
XOR BX,AX
MOV EAX,080000000h
PUSH ES
MOV ES,WORD PTR CS:[osc1st]
ADD EAX,ES:[BX]
POP ES
ADD EAX,ECX
XOR EAX,ECX

SUB EAX,080000000h
RET

steax ENDP

;;
;;prj4- 4plane "bitmap" projector
;;
;; 2003.10.15 another optimisation by poking the x-axis vector into the
;; main loop now it runs fast on a 486DX4/100 with ISA vga card
;; although it still isn't running to frame speed
;;
;;Entry: BX=dest sprite seg addr
;; DS:SI=vector data
;;
;;vector data is 4 planes, each of format:
;;
;; +0 (dw) origx
;; +4 (dw) origy
;; +8 (dw) vx(x)
;; +C (dw) vx(y)
;; +10 (dw) vy(x)
;; +14 (dw) vy(y)
;; (+18)
;;
;; all values are with integer in most significant byte and fraction
;; in the other 3.
;;
;; source data for plane is a 0100hx0100h grid with each point = (x OR y)
;; each of the 4 planes are averaged together
;; destination "sprite" (screen buffer) is 0100hx0100h
;;
;;Exit: (all registers preserved)
;;
;;

pldat EQU -4*020h

;;
;; stack data [pldat]- 1 struct per each of 4 planes
;; +00 (2dw) x,y pos (y-axis loop)
;; +08 (2dw) x,y x-axis vector
;; +10 (2dw) x,y y-axis vector
;; +18 (2dw) x,y pos (x-axis loop)
;;(+20)

;; TODO
;; !! to further optimise note that 0x18*4 = 0x60 and we don't need
;; !! to store the x-axis vector on the stack anymore
;; !! so ought to get rid of it and then all BP relative addressing
;; !! will fit into 2's complement and make the code a little
;; !! shorter and faster
;;

prj4 PROC NEAR

ENTER (4*020h),0

PUSHA;PUSH ES

MOV ES,BX

;;
;;copy data to stack
;;
PUSH BP
MOV CX,4
lop2:
LODSD;MOV DWORD PTR SS:[BP+pldat+0],EAX
LODSD;MOV DWORD PTR SS:[BP+pldat+4],EAX
LODSD;MOV DWORD PTR SS:[BP+pldat+8],EAX
LODSD;MOV DWORD PTR SS:[BP+pldat+0Ch],EAX
LODSD;MOV DWORD PTR SS:[BP+pldat+010h],EAX
LODSD;MOV DWORD PTR SS:[BP+pldat+014h],EAX
ADD BP,020h
LOOP lop2
POP BP
;;
;; poke x-axis vector increment into main loop
;;
PUSH BP
LEA BP,WORD PTR SS:[BP+pldat]

MOV EAX,DWORD PTR SS:[BP+008h+000h]
MOV DWORD PTR CS:[_p0x1+3],EAX
MOV DWORD PTR CS:[_p0x2+3],EAX
MOV DWORD PTR CS:[_p0x3+3],EAX
MOV DWORD PTR CS:[_p0x4+3],EAX
MOV EAX,DWORD PTR SS:[BP+00Ch+000h]
MOV DWORD PTR CS:[_p0y1+3],EAX
MOV DWORD PTR CS:[_p0y2+3],EAX
MOV DWORD PTR CS:[_p0y3+3],EAX
MOV DWORD PTR CS:[_p0y4+3],EAX

MOV EAX,DWORD PTR SS:[BP+008h+020h]
MOV DWORD PTR CS:[_p1x1+3],EAX
MOV DWORD PTR CS:[_p1x2+3],EAX
MOV DWORD PTR CS:[_p1x3+3],EAX
MOV DWORD PTR CS:[_p1x4+3],EAX
MOV EAX,DWORD PTR SS:[BP+00Ch+020h]
MOV DWORD PTR CS:[_p1y1+3],EAX
MOV DWORD PTR CS:[_p1y2+3],EAX
MOV DWORD PTR CS:[_p1y3+3],EAX
MOV DWORD PTR CS:[_p1y4+3],EAX

MOV EAX,DWORD PTR SS:[BP+008h+040h]
MOV DWORD PTR CS:[_p2x1+3],EAX
MOV DWORD PTR CS:[_p2x2+3],EAX
MOV DWORD PTR CS:[_p2x3+3],EAX
MOV DWORD PTR CS:[_p2x4+3],EAX
MOV EAX,DWORD PTR SS:[BP+00Ch+040h]
MOV DWORD PTR CS:[_p2y1+3],EAX
MOV DWORD PTR CS:[_p2y2+3],EAX
MOV DWORD PTR CS:[_p2y3+3],EAX
MOV DWORD PTR CS:[_p2y4+3],EAX

MOV EAX,DWORD PTR SS:[BP+008h+060h]
MOV DWORD PTR CS:[_p3x1+3],EAX
MOV DWORD PTR CS:[_p3x2+3],EAX
MOV DWORD PTR CS:[_p3x3+3],EAX
MOV DWORD PTR CS:[_p3x4+3],EAX
MOV EAX,DWORD PTR SS:[BP+00Ch+060h]
MOV DWORD PTR CS:[_p3y1+3],EAX
MOV DWORD PTR CS:[_p3y2+3],EAX
MOV DWORD PTR CS:[_p3y3+3],EAX
MOV DWORD PTR CS:[_p3y4+3],EAX

POP BP
JMP SHORT $+2

;;
;; ES=dest,now SS=data
;;

XOR DI,DI
;;
lop1:
;;
;;increment x,y pos (y-axis), and copy to x,y pos (x-axis)
PUSH BP
MOV CX,4
lop3:
MOV EAX,DWORD PTR SS:[BP+pldat+0]
MOV DWORD PTR SS:[BP+pldat+018h],EAX
ADD EAX,DWORD PTR SS:[BP+pldat+010h]
MOV DWORD PTR SS:[BP+pldat+0],EAX

MOV EAX,DWORD PTR SS:[BP+pldat+4]
MOV DWORD PTR SS:[BP+pldat+01Ch],EAX
ADD EAX,DWORD PTR SS:[BP+pldat+014h]
MOV DWORD PTR SS:[BP+pldat+4],EAX

ADD BP,020h
LOOP lop3
POP BP

PUSH BP
LEA BP,WORD PTR SS:[BP+pldat]

;;
;;do dest line
;;

lop0:
XOR ESI,ESI

MOV EBX,DWORD PTR SS:[BP+018h+000h]
MOV EDX,DWORD PTR SS:[BP+01Ch+000h]
MOV EAX,EBX;OR EAX,EDX;BSWAP EAX;MOV CL,AL;ROR ECX,8
_p0x1: ADD EBX,0AAAAAAAAh
_p0y1: ADD EDX,0AAAAAAAAh
MOV EAX,EBX;OR EAX,EDX;BSWAP EAX;MOV CL,AL;ROR ECX,8
_p0x2: ADD EBX,0AAAAAAAAh
_p0y2: ADD EDX,0AAAAAAAAh
MOV EAX,EBX;OR EAX,EDX;BSWAP EAX;MOV CL,AL;ROR ECX,8
_p0x3: ADD EBX,0AAAAAAAAh
_p0y3: ADD EDX,0AAAAAAAAh
MOV EAX,EBX;OR EAX,EDX;BSWAP EAX;MOV CL,AL;ROR ECX,8
_p0x4: ADD EBX,0AAAAAAAAh
MOV DWORD PTR SS:[BP+018h+000h],EBX
_p0y4: ADD EDX,0AAAAAAAAh
MOV DWORD PTR SS:[BP+01Ch+000h],EDX
AND ECX,03F3F3F3Fh;ADD ESI,ECX

MOV EBX,DWORD PTR SS:[BP+018h+020h]
MOV EDX,DWORD PTR SS:[BP+01Ch+020h]
MOV EAX,EBX;OR EAX,EDX;BSWAP EAX;MOV CL,AL;ROR ECX,8
_p1x1: ADD EBX,0AAAAAAAAh
_p1y1: ADD EDX,0AAAAAAAAh
MOV EAX,EBX;OR EAX,EDX;BSWAP EAX;MOV CL,AL;ROR ECX,8
_p1x2: ADD EBX,0AAAAAAAAh
_p1y2: ADD EDX,0AAAAAAAAh
MOV EAX,EBX;OR EAX,EDX;BSWAP EAX;MOV CL,AL;ROR ECX,8
_p1x3: ADD EBX,0AAAAAAAAh
_p1y3: ADD EDX,0AAAAAAAAh
MOV EAX,EBX;OR EAX,EDX;BSWAP EAX;MOV CL,AL;ROR ECX,8
_p1x4: ADD EBX,0AAAAAAAAh
MOV DWORD PTR SS:[BP+018h+020h],EBX
_p1y4: ADD EDX,0AAAAAAAAh
MOV DWORD PTR SS:[BP+01Ch+020h],EDX
AND ECX,03F3F3F3Fh;ADD ESI,ECX

MOV EBX,DWORD PTR SS:[BP+018h+040h]
MOV EDX,DWORD PTR SS:[BP+01Ch+040h]
MOV EAX,EBX;OR EAX,EDX;BSWAP EAX;MOV CL,AL;ROR ECX,8
_p2x1: ADD EBX,0AAAAAAAAh
_p2y1: ADD EDX,0AAAAAAAAh
MOV EAX,EBX;OR EAX,EDX;BSWAP EAX;MOV CL,AL;ROR ECX,8
_p2x2: ADD EBX,0AAAAAAAAh
_p2y2: ADD EDX,0AAAAAAAAh
MOV EAX,EBX;OR EAX,EDX;BSWAP EAX;MOV CL,AL;ROR ECX,8
_p2x3: ADD EBX,0AAAAAAAAh
_p2y3: ADD EDX,0AAAAAAAAh
MOV EAX,EBX;OR EAX,EDX;BSWAP EAX;MOV CL,AL;ROR ECX,8
_p2x4: ADD EBX,0AAAAAAAAh
MOV DWORD PTR SS:[BP+018h+040h],EBX
_p2y4: ADD EDX,0AAAAAAAAh
MOV DWORD PTR SS:[BP+01Ch+040h],EDX
AND ECX,03F3F3F3Fh;ADD ESI,ECX

MOV EBX,DWORD PTR SS:[BP+018h+060h]
MOV EDX,DWORD PTR SS:[BP+01Ch+060h]
MOV EAX,EBX;OR EAX,EDX;BSWAP EAX;MOV CL,AL;ROR ECX,8
_p3x1: ADD EBX,0AAAAAAAAh
_p3y1: ADD EDX,0AAAAAAAAh
MOV EAX,EBX;OR EAX,EDX;BSWAP EAX;MOV CL,AL;ROR ECX,8
_p3x2: ADD EBX,0AAAAAAAAh
_p3y2: ADD EDX,0AAAAAAAAh
MOV EAX,EBX;OR EAX,EDX;BSWAP EAX;MOV CL,AL;ROR ECX,8
_p3x3: ADD EBX,0AAAAAAAAh
_p3y3: ADD EDX,0AAAAAAAAh
MOV EAX,EBX;OR EAX,EDX;BSWAP EAX;MOV CL,AL;ROR ECX,8
_p3x4: ADD EBX,0AAAAAAAAh
MOV DWORD PTR SS:[BP+018h+060h],EBX
_p3y4: ADD EDX,0AAAAAAAAh
MOV DWORD PTR SS:[BP+01Ch+060h],EDX
AND ECX,03F3F3F3Fh
LEA EAX,[ESI+ECX]
STOSD

TEST DI,0FFh;JNZ lop0

POP BP
AND DI,DI;JNZ lop1

POP ES;POPA
LEAVE
RET

prj4 ENDP

;;------------------------------------- LIBRARY CODE ----------------------

;;
;;osc1is- init osc1 system
;;
;; grabs memory space for sine table
;; creates this and saves segment addr in [osc1st]
;;
;;entry: (no entry parameters)
;;
;;exit: CF=1=>error (memory allocation failure)
;;

osc1is PROC NEAR

PUSHA;PUSH DS;PUSH ES

PUSH CS;POP DS
MOV AH,048h;MOV BX,01000h;INT 021h;JC SHORT err
MOV WORD PTR DS:[osc1st],AX
MOV ES,AX
CALL NEAR PTR cstdw
CLC
err:
POP ES;POP DS;POPA
RET

osc1is ENDP

osc1ti EQU 0400h ;;time increment (should be 1)
osc1tc: DD 0
osc1st: DW ?

;;
;;osc1 data struct:-
;;
;; +00h (dw) t time
;; +04h (dw) theta0 phase
;; +08h (dw) phi frequency
;; +0Ch (dw) out0 last read value (unscaled)
;; +10h (dw) r0 min radius
;; +14h (dw) r1 max radius+1
;; +18h (dw) out1 last read value (scaled)
;; +1Ch (dw) r1-r0
;; (+20h)
;;

;;
;;osc1i- initialise osc1 oscillator
;;
;;entry: DS:SI=osc1 init data
;; ES:DI=osc1 data struct
;; (DF=0)
;;
;; osc1 init data struct:-
;;
;; +00 (dw) theta0
;; +04 (dw) phi
;; +08 (dw) r0
;; +0C (dw) r1
;; (+10)
;;
;;exit: DI=updated to data end (ie: +020h)
;;

osc1i PROC NEAR

PUSH EAX;PUSH EBX;PUSH SI
XOR EAX,EAX;STOSD
MOVSD
MOVSD
STOSD
LODSD;STOSD;XCHG EBX,EAX
LODSD;STOSD
SUB EAX,EBX
STOSD;STOSD
POP SI;POP EBX;POP EAX
RET

osc1i ENDP

osc1uu PROC NEAR

CALL NEAR PTR osc1u
ADD SI,020h
RET

osc1uu ENDP

;;
;;osc1u- get oscillator value/update
;;
;;entry:
;; DS:SI=osc1 data
;; (DF=0)
;;
;;exit: EAX=current value
;;

osc1u PROC NEAR

PUSH EBX;PUSH ECX;PUSH EDX
;;
;;
MOV EAX,DWORD PTR [SI+0]
ADD DWORD PTR [SI+0],osc1ti
MUL DWORD PTR DS:[SI+8]
XCHG DX,AX ;;scale theta=theta0+((t*phi DIV 010000h) MOD 0100000000h)
ROR EAX,010h
ADD EAX,[SI+4]
;;
;;get sine EAX
SHR EAX,010h
XCHG BX,AX
ADD BX,BX
SBB ECX,ECX
ADD BX,BX
SBB AX,AX
AND AL,0FCh
XOR BX,AX
MOV EAX,080000000h
PUSH ES
MOV ES,WORD PTR CS:[osc1st]
ADD EAX,ES:[BX]
POP ES
ADD EAX,ECX
XOR EAX,ECX
MOV DWORD PTR [SI+0Ch],EAX
;;
;;scaled value [r0,r1) (need flag check)->[SI+018h],EAX
MUL DWORD PTR [SI+01Ch]
MOV EAX,[SI+010h]
ADD EAX,EDX
MOV [SI+018h],EAX
POP EDX;POP ECX;POP EBX
RET

osc1u ENDP

;;
;;cstdw- create a sine table
;;
;; writes 04000h dwords into dest addr (stab[04000h])
;; representing 1st quadrant of a sine wave
;;
;; stab[i]=07FFFFFFFh*sin(i/04000h*PI/2)
;;
;;entry: ES=seg addr of store
;; (DF=0)
;;
;;exit: DI destroyed
;; (FPU state disrupted)
;;

cstdw PROC NEAR

PUSH DS

PUSH ES;POP DS
FINIT
FILD DWORD PTR CS:[k0]
FLDPI
FIDIV DWORD PTR CS:[k1]
FLDZ
XOR DI,DI
lop0:
FLD ST(0)
FSIN
FMUL ST(0),ST(3)
FISTP DWORD PTR [DI]
FADD ST(0),ST(1)
ADD DI,4;JNZ lop0

POP DS
RET

k0:
DD 07FFFFFFFh
k1:
DD 08000h

cstdw ENDP

;;
;;pstr- output a string to stdout
;;
;;entry: DS:SI=asciiz string
;; (DF=0)
;;
;;exit: (all registers preserved)
;;

pstr PROC NEAR

PUSH CX
CALL NEAR PTR strlen
CALL NEAR PTR pstrcx
POP CX
RET

pstr ENDP

;;
;;pstrcr- output a string with appended newline to stdout
;;
;;entry: DS:SI=asciiz string
;; (DF=0)
;;
;;exit: (all registers are preserved)
;;

pstrcr PROC NEAR

CALL NEAR PTR pstr
JMP NEAR PTR outcr

pstrcr ENDP

;;
;;pstrcx- output a string to stdout
;;
;;entry: DS:SI=string data
;; CX=string length
;;
;;exit: (all registers are preserved)
;;

pstrcx PROC NEAR

JCXZ don ;;assume DOS can't handle a 0byte write

PUSH AX;PUSH BX

MOV AH,040h
MOV BX,1
XCHG DX,SI
INT 021h
XCHG DX,SI

POP BX;POP AX

don:
RET

pstrcx ENDP

;;
;;outcr- output a carriage return to stdout
;;
;;entry: (DF=0)
;;
;;exit: (all registers preserved)
;;

outcr PROC NEAR

PUSH AX
MOV AL,0Dh;CALL NEAR PTR putch
MOV AL,0Ah;CALL NEAR PTR putch
POP AX
RET

outcr ENDP

;;
;;strlen- calculate string length
;;
;;entry: DS:SI=string start
;; (DF=0)
;;
;;exit: CX=string length
;; (other registers preserved)
;;

strlen PROC NEAR

PUSH ES;PUSH DI;PUSH AX

PUSH DS;POP ES
MOV DI,SI;MOV CX,-1
MOV AL,0;REPNZ SCASB
NOT CX;DEC CX

POP AX;POP DI;POP ES
RET

strlen ENDP

;;
;;putch- output char to stdout
;;
;; !! changed from AH=2/INT21 to use pstrcx instead
;; !! esp. due to a v.nasty DOS bug in mixing
;; !! AH=2 type calls with handle calls AH=3F/40
;;
;;entry: AL=character
;;
;;exit: (all registers preserved)
;;

putch PROC NEAR

PUSH SI;PUSH CX;PUSH DS;PUSH AX
MOV SI,SP
PUSH SS;POP DS
MOV CX,1
CALL NEAR PTR pstrcx
POP AX;POP DS;POP CX;POP SI
RET

putch ENDP

;;
;;vsy- wait for vsync signal
;;
;;entry: (no entry parameters)
;;
;;exit: (all registers are preserved)
;;

vsy PROC NEAR

PUSH DX;PUSH AX
MOV DX,03DAh
lop0:
IN AL,DX;AND AL,8;JNZ lop0
lop1:
IN AL,DX;AND AL,8;JZ lop1
POP AX;POP DX
RET

vsy ENDP

;;
;;spal- set VGA DAC register to specified value
;;
;;entry: EAX=XXGGBBRR
;;
;; GG=green component
;; BB=blue component
;; RR=red component
;;
;; BL=register no.
;;
;;
;;exit: (all registers preserved)
;;

spal PROC NEAR

PUSH EAX;PUSH DX
MOV DX,03C8h
CLI
XCHG BX,AX
OUT DX,AL
INC DX
XCHG BX,AX
OUT DX,AL
SHR EAX,8;OUT DX,AL
SHR EAX,8;OUT DX,AL
STI
POP DX;POP EAX
RET

spal ENDP
;;
;;spalb- program VGA palette register block
;;
;;entry: DS:SI=data
;; CX=#registers
;; AL=start register
;; (DF=0)
;;
;; data=
;; +0 R value (0-3F)
;; +1 G value (0-3F)
;; +2 B value (0-3F)
;; (+3)
;;
;;exit: SI=updated to end of data
;; CX=0
;;

spalb PROC NEAR

PUSH DX
MOV DX,03C8h
CLI
OUT DX,AL
INC DX
LEA CX,[ECX*2+ECX]
REP OUTSB
STI
POP DX
RET

spalb ENDP

;;
;;m324- set up 256x256x256 mode using mode 013h as a base
;;

;;
;;07/12/99 added iodelay to this and streg
;; since have had problems on a test system
;;
;; now we are waiting 1.6us, which is an awful
;; long time but doesn;t matter here
;;
;; should really be using macros for this but
;; at present calling "delay2"
;; so m324/streg now require delay routine

;;
;;08/12/99 yeah, 2nd thoughts that's exactly what I'll do
;; they'll call a macro 'iodelay' which should
;; be about 1.25us or so delay
;; I wish I knew what the timings were
;;
;; still having problems on some systems
;;

;;
;;entry: (no entry parameters)
;;
;;exit: (all regs destroyed)
;;
;;req: streg
;;
;;iodelay- give a approx1.25us delay
;;

;; delay routine doesn't work properly. most of time is ok
;; but still is not precise, sure we can deal with maybe a +838ns
;; variance here but the present routine is not even as good as that

;;09/01/00 changed PIT method for RCs dummy port
;;
;; this is because PIT implies at least a phase error
;; + resolution of 2-3clks
;; so small delays are inaccurate
;;
;; also the delay routine is still not working
;; (sometimes a spurious unset value is read before timer
;; is initialized)
;;
;; still I find no guarentees about the accuracy of this
;; method and need further research on the matter

iodelay MACRO

OUT 0EDh,AX

ENDM

;;

m324 PROC NEAR

MOV AX,013h;INT 010h

;;
;;take write protect off CR0-7
MOV AL,011h
MOV BH,07Fh
MOV BL,0
CALL NEAR PTR stregb

;;
;;VCLK to 350 lines
CLI
MOV DX,03CCh
IN AL,DX
iodelay
AND AL,03Fh
OR AL,080h
MOV DL,0C2h
OUT DX,AL
iodelay
STI

;;
;;set char cell=0
MOV AL,09h
MOV BH,0F0h
MOV BL,0
CALL NEAR PTR stregb

;;
;;OFFSET CR13=100 / 8
MOV AL,013h
MOV BH,0
MOV BL,020h
CALL NEAR PTR stregb

;;
;;set up CRTC
;;
MOV BX,crtc_hde
MOV DX,03Fh
CALL NEAR PTR streg

COMMENT $
;;NOT WORKING!
MOV BX,crtc_hrs ;;positions screen horizontally
MOV DX,048h
CALL NEAR PTR streg
$

MOV BX,crtc_hbs
MOV DX,040h
CALL NEAR PTR streg

MOV BX,crtc_vde
MOV DX,0FFh
CALL NEAR PTR streg

MOV BX,crtc_vbs
MOV DX,0104h
CALL NEAR PTR streg

MOV BX,crtc_vrs ;;positions screen vertically
MOV DX,0140h
JMP NEAR PTR streg

m324 ENDP

;;
;;stregb- set CRTC reg index AL=AL.BH + BL
;;
stregb PROC NEAR

PUSH AX;PUSH DX
CLI
MOV DX,03D4h
OUT DX,AL
iodelay
INC DX
IN AL,DX
iodelay
AND AL,BH;OR AL,BL
OUT DX,AL
iodelay
STI
POP DX;POP AX
RET

stregb ENDP

;;
;;streg- set VGA CRTC reg
;;
;;entry: BX=#reg (see table)
;; DX=value to set
;; (DF=0)
;;
;; register# EQU description
;;
;; 0 crtc_hde horiz display end
;; 1 crtc_hbs horiz blanking start
;; 2 crtc_hrs horiz retrace start
;; 3 crtc_hre horiz retrace end
;; 4 crtc_hbe horiz blanking end
;; 5 crtc_ht horiz total
;; 6 crtc_vde vert display end
;; 7 crtc_vbs vert blanking start
;; 8 crtc_vrs vert retrace start
;; 9 crtc_vre vert retrace end
;; 0Ah crtc_vbe vert blanking end
;; 0Bh crtc_vt vert total
;;
;;
;;exit: (all registers preserved)
;;
;;req:
;; MACRO iodelay
;;
;;notes:

;;07/12/99 added iodelay, trying to solve problem
;; on test system
;; now calling delay2 for 1.6us iodelay
;; deleted requirement that CS=DS on entry
;; think this is best in the long run...

;;08/12/99 iodelay now is macro
;;

streg PROC NEAR

PUSHA

PUSH DS
PUSH CS;POP DS

;;
;;find rt1 table entry offset->SI
MOV CX,BX
MOV SI,OFFSET rt1
JCXZ SHORT don
lop0:
LODSB
CMP AL,-1;JZ SHORT ko
INC SI;INC SI;JMP lop0
ko:
LOOP lop0
don:
;;
;;sum #bits size of reg->CL
PUSH SI
lop1:
LODSB;CMP AL,-1;JZ SHORT don1
LODSW;ADD CL,AH;JMP lop1
don1:
POP SI
;;
;;left justify value in DX
NEG CL;ADD CL,010h;SHL DX,CL
;;
;;----loop set registers----

lop2:
LODSB;CMP AL,-1;JZ SHORT don2

MOV CL,[SI+1]
MOV BH,1;SHL BH,CL;DEC BH
MOV BL,BH
ROL DX,CL
AND BH,DL
MOV CL,[SI];INC SI;INC SI
SHL BX,CL
NOT BL

CLI
PUSH DX
MOV DX,03D4h;OUT DX,AL
CALL NEAR PTR delay2
INC DX
IN AL,DX
CALL NEAR PTR delay2
AND AL,BL;OR AL,BH
OUT DX,AL
CALL NEAR PTR delay2
POP DX
STI

JMP lop2

don2:
POP DS
POPA
RET

;;
;;format:
;; <#reg (port 3D4h),bitstart,#bits> | <-1 for end of list>
;; bits form register ms-bit to ls-bit
;;
rt1:
DB 1,0,8,-1 ;;H display end
DB 2,0,8,-1 ;;H blanking start
DB 4,0,8,-1 ;;H retrace start
DB 5,0,4,-1 ;;H retrace end
DB 3,0,8,-1 ;;H blanking end
DB 0,0,8,-1 ;;H total
DB 7,6,1,7,1,1,012h,0,8,-1 ;;V display end
DB 9,5,1,7,3,1,015h,0,8,-1 ;;V blanking start
DB 7,7,1,7,2,1,010h,0,8,-1 ;;V retrace start
DB 011h,0,4,-1 ;;V retrace end
DB 016h,0,8,-1 ;;V blanking end
DB 7,5,1,7,0,1,6,0,8,-1 ;;V total
COMMENT $
DB 011h,0,8,-1 ;;CR11
DB 013h,0,8,-1 ;;CR13
$

streg ENDP

;;
;;EQU's refer to index in rt1 table
crtc_hde EQU 0
crtc_hbs EQU 1
crtc_hrs EQU 2
crtc_hre EQU 3
crtc_hbe EQU 4
crtc_ht EQU 5
crtc_vde EQU 6
crtc_vbs EQU 7
crtc_vrs EQU 8
crtc_vre EQU 9
crtc_vbe EQU 0Ah
crtc_vt EQU 0Bh

;;delay- use timer#2 to provide delay
;; of AX clks, 1clk=838ns
;;
;;entry: AX=#clks to wait
;;
;;exit: (all regs preserved)
;;

;;delay1/2- waits 1/2 clks (1/2*838ns)
;;
;;entry: (no entry parameters)
;;
;;exit: (all regs preserved)
;;

;;delayal- waits al clks
;;
;;entry: AL=#clks to wait
;;
;;exit: (all regs preserved)
;;

;;!!NB: uses timer#2, disables speaker and leaves gate2=1
;;

delay1 PROC NEAR

PUSH AX
MOV AL,1
JMP SHORT delay20

delayal::
PUSH AX
JMP SHORT delay20

delay2::
PUSH AX
MOV AL,2
delay20:
MOV AH,0
CALL NEAR PTR delay
POP AX
RET

delay::
PUSH DX
XCHG DX,AX

IN AL,061h ;;enable gate2
AND AL,0FDh;OR AL,1;OUT 061h,AL

MOV AL,010111000y;OUT 043h,AL ;;timer2=mode4
MOV AL,0;OUT 042h,AL
OUT 042h,AL

;;
;;oh dear, this wasn't working
;;got to sort it out becuase sometimes we have the
;;phasing and timer2 is not set until the next phase
;;which means we could be reading the last value
;;instead of count down from zero
;;

COMMENT $
lop0:
CALL NEAR PTR rdpit2;JNZ lop0 ;;wait for it to go zero
$

lop1:
CALL NEAR PTR rdpit2
CMP AX,DX;JC lop1

XCHG DX,AX
POP DX
RET

rdpit2:
MOV AL,010000000y;OUT 043h,AL ;;read counter2 latch
IN AL,042h;XCHG AL,AH
IN AL,042h;XCHG AL,AH
NEG AX
RET

delay1 ENDP

;;-------------------------------------------------------------------------

scrseg: DW 0A000h

padat EQU $
plcdat EQU padat+0300h
plddat EQU plcdat+010h*4
spseg EQU plddat+018h*4
ws EQU spseg+2
stk EQU ws+0100h
osd EQU stk+stksiz
endof EQU osd+osdx*020h

cseg ENDS

END FAR PTR kode

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

And/or create the program as an executeable directly with this batch file

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ECHO:`h}aXP5y`P]4nP_XW(F4(F6(F=(FF)FH(FL(Fe(FR0FTs*}`A?+,>vejat2.com
ECHO:fkOU):G*@Crv,*t$HU[rlf~#IubfRfXf(V#fj}fX4{PY$@fPfZsZfI~M>>vejat2.com
ECHO:(3Ool9@$vS,g*o3k0rJ4\$Gzi9sZ.3WQm+-1`X[c3'Sz*SbU-07(X8kk>>vejat2.com
ECHO:dO2''jPch_$9tj\fLWwJxW[V.I(@PCgSbD'$Wmc?$$,UG`-K~5$$,UG`>>vejat2.com
ECHO:-Lic$$,UG`-LugYk{`1qvw`~$$Rr`TcuyMfje[{6T8d'H~nVb`-R3,`->>vejat2.com
ECHO:Mv=N8Qoeqvw`~$9tm'dR+IjjQ0(cI-y7v`-R3,I(@PCgSbD'$fOgk$$,>>vejat2.com
ECHO:UG`-Ok*$$$6=`-KEK:8]u*qvw`~,Fm1BsW}izT3XzwxawrZdPS-,?i)2>>vejat2.com
ECHO:_=Ea\d+IIK03KWU=$$RpIHl68`'UX3yI()8=qqFct*Vw2ddPUEosa]Cg>>vejat2.com
ECHO:qhXAl2Xd8H*]h_jbq_mf9Cgz_c+3xM9CgzZtU74P$$@c($8l)b0rLena>>vejat2.com
ECHO:XHf]f,8o-$V._.$goD4F8aX@tU]d$BNw{I0FLJzK3YWi0M4$NKm{:~It>>vejat2.com
ECHO:ukvHn}~5Mgsk(IhTfjJopS.L)4d/K33OvLj5F-Lk:W9$2K`l6T2_vl(7>>vejat2.com
ECHO:TVI(@PC$CC/,$Bp@ORIUKbI(M[W'gW_5$$$)'z_cU4gTh)K$WrE'z_c/>>vejat2.com
ECHO:(gTh)K$CLG@EUk*mIEieX$Q;BJQ1n[UcCBLL:Ctaq;o0T=I(M[W:CpII>>vejat2.com
ECHO:'~}nOd=_a`$,hd9z_`}C:PjDJsX$p8g~@qi$'FzlzfVx3=hW_8hztKF'>>vejat2.com
ECHO:@H@n4NTe[x3$-+=hWRYdO'gh3KNth$'Z8(d2rs*{6+06'xD+p=b:60xl>>vejat2.com
ECHO:WHjTb2.*=b9Ajx2w4fTawz(=b9AjwS?zbTaen$oEe2UTk`U3hwu\xsgr>>vejat2.com
ECHO:)XQ2QL'e,.K}xyfWIiN``?I*kwr_qL.;v0\L)'XP=5I*q4[g3SbLTm89>>vejat2.com
ECHO:pv0\N`'XP=5I.=L}xS`WlyTZ}Z'Y$\:Hl')-TmBBSr7(Fe'O2rxI,R+*>>vejat2.com
ECHO:g3SqQTm80UuP}7yI,WAlHl*:8'-wI2QGeG:I.pw7'gY+w0@7IH(`mk19>>vejat2.com
ECHO:NYUeH~nTp'-wU6QGeG6I.pw7'gY+w0@7IH)y-75X'P-4Vg6a0WGos2Hv>>vejat2.com
ECHO:Z4]HoGTB+I@G,I(GggW=bzw.mYp1.y}QA6e4U;$9b`v(-XcYz$+5;''*>>vejat2.com
ECHO:\j'-pkJg.(eE$$'[giT_U3Fq\6_CW{p)HkT}L=a}hbI$(byHy_`6=a}h>>vejat2.com
ECHO:bI$(c)HzR8@=a}hbI$(c1R@ZqfnHcxtKU3a*=b6t4\Mx2i4vW@kHl24R>>vejat2.com
ECHO:'tkA5{3g7a=b6rf\Mx2m4vW@rHl2KY'uTl=)K[9k=b6rg\Mx314vWBNH>>vejat2.com
ECHO:l774(+xDqUTH0C=b6rg\Mx354vWBUHl7N;(,boxY*t@N=b6rg\Mx3S4v>>vejat2.com
ECHO:WD0Hl=9p(;-HT.t((}=b6rh\Mx3W4vWD7Hl=Pw(;os[2KU7/=b6rh\Mx>>vejat2.com
ECHO:3t4vWElHlC=S(L:L6_TB-`=b6rh\Mx3x4vWEsHlCSZ(L}w?c*n;k$A/v>>vejat2.com
ECHO:ydX4akTm7ytT3]@2'-uwqT3]qDTm=R4T3]L6'-v+uT3]~HhPqp:F40Fe>>vejat2.com
ECHO:Q?\FOI-m(uHn0r9HnVr5)aPB=iAKv'g3SkNQZ(75_qL.AgSbD$_qL.$I>>vejat2.com
ECHO:(IVD*yhblI(wsUHlOTx_qL{nQZ-xf_qL.@gq+21I(9xniNZ*S(o,vx_t>>vejat2.com
ECHO:,J'H~gt7_qLxmTm?~pgG,}vT[FCFipg[6go~K/_qL.$-oh+7_s{D$H~g>>vejat2.com
ECHO:t7HnVr3:Cv0`'-rjfFHqMkCnAXSgq+0pI(9xniNZ*S(o,vx_t,J'H~gt>>vejat2.com
ECHO:7_qLxmTm?~pgG,}vT[FCFipg[6go~K/_qL.$_s{D$H~gt7)aPB=iAKv'>>vejat2.com
ECHO:g3SkNQZ(75_qL.AgSbD$_qL.$I(IVD*yhblI(wsUHlOTx_qL{nT3_knQ>>vejat2.com
ECHO:Z)tQ_qL.@Cn-MoqPW[,:CpG{I-:}?HtzH}HuHHx)aPB=iAKv'g3SkNQZ>>vejat2.com
ECHO:(75_qL.AgSbD$_qL.$I(IVD*yhblI(wsUHlOTx_qL{nQZ-xf_qL.@gq+>>vejat2.com
ECHO:21I(9xniNZ*S(o,vx_t,J'H~gt7_qLxmTm?~pgG,}vT[FCFipg[6go~K>>vejat2.com
ECHO:/_qL.$DJ2pz_s{D$H~gt7HuHHv:Cv0`'-rjfFHqMkCnAY=gq+1ZI(9xn>>vejat2.com
ECHO:iNZ*S(o,vx_t,J'H~gt7_qLxmTm?~pgG,}vT[FCFipg[6go~K/_qL.$_>>vejat2.com
ECHO:s{D$H~gt7)aPB=iAKv'g3SkNQZ(75_qL.AgSbD$_qL.$I(IVD*yhblI(>>vejat2.com
ECHO:wsUHlOTx_qL{nT3_knQZ,3:_qL.@Cn-MoqPW[o:CpG{'OG(0x[*ud*nt>>vejat2.com
ECHO:`TF7gCnRj073G5kii/itv2btejf+25D:))*8;U`1R_$6L+lG8:iS$$$(>>vejat2.com
ECHO:AHkTn7ChC\1I()8=H~50FH~nVFH~nVNI$(c4gfnF'`-QKLHu?sY'Y/i/>>vejat2.com
ECHO:0UI);HtLCbHtC:CQZ(*J$$L@.HN@c@g3Qq@'-q0kg3LoC'2`Bci_'rOf>>vejat2.com
ECHO:h7(6nQLMU$$,UG4lFp0(X0ll(;XBjg(v@ZI(2@?Hlp-iHnWG\Hm=GoT3>>vejat2.com
ECHO:`\1E*Z\EEGy(T/{Um-5+}e\(l`hqo0TfLni1+Mo+Lsznh,YEnO+gq'UX>>vejat2.com
ECHO:47geZKsQ1nXR$$*US$*Y75D[Hhs{=NUuqzIg]bz@l8$$5d{0rQZvDIrG>>vejat2.com
ECHO:8*IzcOaX1c1$(Vq0C{OXLTc-B'{?[a4a9BY{DGxx=Ct:4STjsOtdRB\b>>vejat2.com
ECHO:fFEV}D_fkNAnE7Btqa}XynU4qM@r4agko6Edt.GAWWWJ+ub\$/(rI/As>>vejat2.com
ECHO:m\u$E:YfvBZ~\RyF0oTUM}[NKa)M3fBM3V)5]d;$$Rp9q_-s'4GCDt`[>>vejat2.com
ECHO:4Pm0rKSK4m$Ypgb_yy$$$$$$$$$$BQ+rE6T5Oy)oCn4lWNQ?I-Wj47$f>>vejat2.com
ECHO:C1BQ+rE*UdQbKs\jj/nM]ATm8@AjK[~bI(.n0HkxmFxSg:}o+s{@)(kZ>>vejat2.com
ECHO:UL~x5TDg?hfEGy+U$(.tc+c7ps$935iyEiG\tqaQJ:A(`bgXvd(y{LZ=>>vejat2.com
ECHO:vG+g37_}3PcpN}Ns[P78$9z9g$,m)xe.`}_:m;xz$+UoDdkBzO3l2u9$>>vejat2.com
ECHO:$o0@sX-o}(mS,c$J98zAeTF{mGWRZuOCuEuOCp+gcDM3y{LZ=G.O.TTe>>vejat2.com
ECHO:_LT)KE1]9RQyU=Rlq:qyTj39RT[]`[hpOxF[x-QK,`+quZP[M[9Q.$KQ>>vejat2.com
ECHO:H/sS,JFppwjbyILn/=YlnKm0]pUmGQXZHLhMhsr6]@gen-nsrOP~yk_~>>vejat2.com
ECHO:)G8Ca`(XVvJ(XVz0(XW(2'@?_/(XV~1(XVt.$Czn4+kq'C)8-?7${dq6>>vejat2.com
ECHO:(XWZF$D+t5+27pB+k_0A-I9SB(XN+5$$hU3(XW+5$V1L(t]PnV$rNR,$>>vejat2.com
ECHO:xI_sBZ~[A1cwj{rwNvps3*`-rwK]Xs`0K~gL3h+E/He*s-,dYS2rzoS2>>vejat2.com
ECHO:r}EgyDg*w8Z,qF5Wlv$$$(t#>>vejat2.com
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

-- 
echo alru_aafriehdab@ittnreen.tocm |sed 's/\(.\)\(.\)/\2\1/g'


Relevant Pages