From 4fd84e1460463b4095bf4632dabfafb849a3489e Mon Sep 17 00:00:00 2001 From: sparky4 Date: Fri, 28 Nov 2014 13:28:14 -0600 Subject: [PATCH] new file: 16/PCGPE10.tar.7z deleted: 16/PCGPE10/3DROTATE.DOC deleted: 16/PCGPE10/3DSHADE.DOC deleted: 16/PCGPE10/ADLIB.TXT deleted: 16/PCGPE10/ANSI.TXT deleted: 16/PCGPE10/ASM0.TXT deleted: 16/PCGPE10/ASM1.TXT deleted: 16/PCGPE10/ASM2.TXT deleted: 16/PCGPE10/ASM3.TXT deleted: 16/PCGPE10/ASMINTRO.TXT deleted: 16/PCGPE10/ATI.TXT deleted: 16/PCGPE10/BLASTERS.EXE deleted: "16/PCGPE10/BL\346\213\205TER" deleted: 16/PCGPE10/BMP.TXT deleted: 16/PCGPE10/BRES.TXT deleted: 16/PCGPE10/BSP.TXT deleted: 16/PCGPE10/CAT.TXT deleted: 16/PCGPE10/CMF.TXT deleted: 16/PCGPE10/CONIC.CC deleted: 16/PCGPE10/COPPER.PAS deleted: 16/PCGPE10/CPUTYPE.TXT deleted: 16/PCGPE10/DMA_VLA.TXT deleted: 16/PCGPE10/DOOM.TXT deleted: 16/PCGPE10/DPMI16BI.OVL deleted: 16/PCGPE10/DPMIINST.EXE deleted: 16/PCGPE10/DPMILOAD.EXE deleted: 16/PCGPE10/DPMIUSER.DOC deleted: 16/PCGPE10/FDTM.TXT deleted: 16/PCGPE10/FIRE.TXT deleted: 16/PCGPE10/FLI.FOR deleted: 16/PCGPE10/FTPSITES.TXT deleted: 16/PCGPE10/GAMEBLST.TXT deleted: 16/PCGPE10/GAMEPAD.TXT deleted: 16/PCGPE10/GENOA.TXT deleted: 16/PCGPE10/GIF.TXT deleted: 16/PCGPE10/GMOUSE.DOC deleted: 16/PCGPE10/GUS.TXT deleted: 16/PCGPE10/GUSFAQ.TXT deleted: 16/PCGPE10/IFF.DOC deleted: 16/PCGPE10/INTEL.DOC deleted: 16/PCGPE10/JOYSTICK.TXT deleted: 16/PCGPE10/KEYBOARD.TXT deleted: 16/PCGPE10/LIMEMS41.DOC deleted: 16/PCGPE10/MIDI.TXT deleted: 16/PCGPE10/MODEX.TXT deleted: 16/PCGPE10/MODFORM.TXT deleted: 16/PCGPE10/MOUSE.TXT deleted: 16/PCGPE10/PALLETTE.COL deleted: 16/PCGPE10/PARADISE.TXT deleted: 16/PCGPE10/PCGPE.EXE deleted: 16/PCGPE10/PCX.TXT deleted: 16/PCGPE10/PERSPECT.TXT deleted: 16/PCGPE10/PIT.TXT deleted: 16/PCGPE10/README.TXT deleted: 16/PCGPE10/RTM.EXE deleted: 16/PCGPE10/RTMRES.EXE deleted: 16/PCGPE10/SBDSP.TXT deleted: 16/PCGPE10/SBPRO.TXT deleted: 16/PCGPE10/SCROLL.TXT deleted: 16/PCGPE10/SOFTROCK.FNT deleted: 16/PCGPE10/SPEAKER.TXT deleted: 16/PCGPE10/STARS.TXT deleted: 16/PCGPE10/SVGINTRO.TXT deleted: 16/PCGPE10/TEXTURE.TXT deleted: 16/PCGPE10/TIMER.ASM deleted: 16/PCGPE10/TRIDENT.TXT deleted: 16/PCGPE10/TSENG.TXT deleted: 16/PCGPE10/TUT1.TXT deleted: 16/PCGPE10/TUT10.TXT deleted: 16/PCGPE10/TUT2.TXT deleted: 16/PCGPE10/TUT3.TXT deleted: 16/PCGPE10/TUT4.TXT deleted: 16/PCGPE10/TUT5.TXT deleted: 16/PCGPE10/TUT6.TXT deleted: 16/PCGPE10/TUT7.TXT deleted: 16/PCGPE10/TUT8.TXT deleted: 16/PCGPE10/TUT9.TXT deleted: 16/PCGPE10/UT.TXT deleted: 16/PCGPE10/VESASP12.TXT deleted: 16/PCGPE10/VGABIOS.TXT deleted: 16/PCGPE10/VGAREGS.TXT deleted: 16/PCGPE10/VIDEO7.TXT deleted: 16/PCGPE10/VOC.TXT deleted: 16/PCGPE10/WAV.TXT deleted: 16/PCGPE10/WORMIE.PAS deleted: 16/PCGPE10/XMS30.TXT deleted: 16/PCGPE10/XTENDED.TXT deleted: 16/PCGPE10/suround.txt --- 16/PCGPE10.tar.7z | Bin 0 -> 558680 bytes 16/PCGPE10/3DROTATE.DOC | 484 -- 16/PCGPE10/3DSHADE.DOC | 311 -- 16/PCGPE10/ADLIB.TXT | 479 -- 16/PCGPE10/ANSI.TXT | 326 -- 16/PCGPE10/ASM0.TXT | 193 - 16/PCGPE10/ASM1.TXT | 131 - 16/PCGPE10/ASM2.TXT | 245 - 16/PCGPE10/ASM3.TXT | 526 -- 16/PCGPE10/ASMINTRO.TXT | 626 --- 16/PCGPE10/ATI.TXT | 158 - 16/PCGPE10/BLASTERS.EXE | Bin 8379 -> 0 bytes 16/PCGPE10/BL担TER | 34 - 16/PCGPE10/BMP.TXT | 1034 ---- 16/PCGPE10/BRES.TXT | 399 -- 16/PCGPE10/BSP.TXT | 149 - 16/PCGPE10/CAT.TXT | 163 - 16/PCGPE10/CMF.TXT | 159 - 16/PCGPE10/CONIC.CC | 356 -- 16/PCGPE10/COPPER.PAS | 361 -- 16/PCGPE10/CPUTYPE.TXT | 245 - 16/PCGPE10/DMA_VLA.TXT | 506 -- 16/PCGPE10/DOOM.TXT | 505 -- 16/PCGPE10/DPMI16BI.OVL | Bin 63504 -> 0 bytes 16/PCGPE10/DPMIINST.EXE | Bin 36724 -> 0 bytes 16/PCGPE10/DPMILOAD.EXE | Bin 22324 -> 0 bytes 16/PCGPE10/DPMIUSER.DOC | 245 - 16/PCGPE10/FDTM.TXT | 178 - 16/PCGPE10/FIRE.TXT | 100 - 16/PCGPE10/FLI.FOR | 244 - 16/PCGPE10/FTPSITES.TXT | 198 - 16/PCGPE10/GAMEBLST.TXT | 275 - 16/PCGPE10/GAMEPAD.TXT | 117 - 16/PCGPE10/GENOA.TXT | 134 - 16/PCGPE10/GIF.TXT | 1321 ----- 16/PCGPE10/GMOUSE.DOC | 1501 ------ 16/PCGPE10/GUS.TXT | 1403 ----- 16/PCGPE10/GUSFAQ.TXT | 1455 ----- 16/PCGPE10/IFF.DOC | 1424 ----- 16/PCGPE10/INTEL.DOC | 2807 ---------- 16/PCGPE10/JOYSTICK.TXT | 255 - 16/PCGPE10/KEYBOARD.TXT | 243 - 16/PCGPE10/LIMEMS41.DOC | 13224 ---------------------------------------------- 16/PCGPE10/MIDI.TXT | 5939 --------------------- 16/PCGPE10/MODEX.TXT | 720 --- 16/PCGPE10/MODFORM.TXT | 523 -- 16/PCGPE10/MOUSE.TXT | 295 -- 16/PCGPE10/PALLETTE.COL | Bin 768 -> 0 bytes 16/PCGPE10/PARADISE.TXT | 237 - 16/PCGPE10/PCGPE.EXE | Bin 144842 -> 0 bytes 16/PCGPE10/PCX.TXT | 586 -- 16/PCGPE10/PERSPECT.TXT | 149 - 16/PCGPE10/PIT.TXT | 297 -- 16/PCGPE10/README.TXT | 293 - 16/PCGPE10/RTM.EXE | Bin 85998 -> 0 bytes 16/PCGPE10/RTMRES.EXE | Bin 7936 -> 0 bytes 16/PCGPE10/SBDSP.TXT | 442 -- 16/PCGPE10/SBPRO.TXT | 267 - 16/PCGPE10/SCROLL.TXT | 302 -- 16/PCGPE10/SOFTROCK.FNT | Bin 15872 -> 0 bytes 16/PCGPE10/SPEAKER.TXT | 302 -- 16/PCGPE10/STARS.TXT | 710 --- 16/PCGPE10/SVGINTRO.TXT | 473 -- 16/PCGPE10/TEXTURE.TXT | 1566 ------ 16/PCGPE10/TIMER.ASM | 129 - 16/PCGPE10/TRIDENT.TXT | 129 - 16/PCGPE10/TSENG.TXT | 139 - 16/PCGPE10/TUT1.TXT | 369 -- 16/PCGPE10/TUT10.TXT | 514 -- 16/PCGPE10/TUT2.TXT | 616 --- 16/PCGPE10/TUT3.TXT | 624 --- 16/PCGPE10/TUT4.TXT | 408 -- 16/PCGPE10/TUT5.TXT | 410 -- 16/PCGPE10/TUT6.TXT | 434 -- 16/PCGPE10/TUT7.TXT | 1195 ----- 16/PCGPE10/TUT8.TXT | 792 --- 16/PCGPE10/TUT9.TXT | 823 --- 16/PCGPE10/UT.TXT | 195 - 16/PCGPE10/VESASP12.TXT | 1134 ---- 16/PCGPE10/VGABIOS.TXT | 707 --- 16/PCGPE10/VGAREGS.TXT | 806 --- 16/PCGPE10/VIDEO7.TXT | 197 - 16/PCGPE10/VOC.TXT | 72 - 16/PCGPE10/WAV.TXT | 112 - 16/PCGPE10/WORMIE.PAS | 307 -- 16/PCGPE10/XMS30.TXT | 1079 ---- 16/PCGPE10/XTENDED.TXT | 136 - 16/PCGPE10/suround.txt | 76 - 88 files changed, 57018 deletions(-) create mode 100644 16/PCGPE10.tar.7z delete mode 100644 16/PCGPE10/3DROTATE.DOC delete mode 100644 16/PCGPE10/3DSHADE.DOC delete mode 100644 16/PCGPE10/ADLIB.TXT delete mode 100644 16/PCGPE10/ANSI.TXT delete mode 100644 16/PCGPE10/ASM0.TXT delete mode 100644 16/PCGPE10/ASM1.TXT delete mode 100644 16/PCGPE10/ASM2.TXT delete mode 100644 16/PCGPE10/ASM3.TXT delete mode 100644 16/PCGPE10/ASMINTRO.TXT delete mode 100644 16/PCGPE10/ATI.TXT delete mode 100644 16/PCGPE10/BLASTERS.EXE delete mode 100644 16/PCGPE10/BL担TER delete mode 100644 16/PCGPE10/BMP.TXT delete mode 100644 16/PCGPE10/BRES.TXT delete mode 100644 16/PCGPE10/BSP.TXT delete mode 100644 16/PCGPE10/CAT.TXT delete mode 100644 16/PCGPE10/CMF.TXT delete mode 100644 16/PCGPE10/CONIC.CC delete mode 100644 16/PCGPE10/COPPER.PAS delete mode 100644 16/PCGPE10/CPUTYPE.TXT delete mode 100644 16/PCGPE10/DMA_VLA.TXT delete mode 100644 16/PCGPE10/DOOM.TXT delete mode 100644 16/PCGPE10/DPMI16BI.OVL delete mode 100644 16/PCGPE10/DPMIINST.EXE delete mode 100644 16/PCGPE10/DPMILOAD.EXE delete mode 100644 16/PCGPE10/DPMIUSER.DOC delete mode 100644 16/PCGPE10/FDTM.TXT delete mode 100644 16/PCGPE10/FIRE.TXT delete mode 100644 16/PCGPE10/FLI.FOR delete mode 100644 16/PCGPE10/FTPSITES.TXT delete mode 100644 16/PCGPE10/GAMEBLST.TXT delete mode 100644 16/PCGPE10/GAMEPAD.TXT delete mode 100644 16/PCGPE10/GENOA.TXT delete mode 100644 16/PCGPE10/GIF.TXT delete mode 100644 16/PCGPE10/GMOUSE.DOC delete mode 100644 16/PCGPE10/GUS.TXT delete mode 100644 16/PCGPE10/GUSFAQ.TXT delete mode 100644 16/PCGPE10/IFF.DOC delete mode 100644 16/PCGPE10/INTEL.DOC delete mode 100644 16/PCGPE10/JOYSTICK.TXT delete mode 100644 16/PCGPE10/KEYBOARD.TXT delete mode 100644 16/PCGPE10/LIMEMS41.DOC delete mode 100644 16/PCGPE10/MIDI.TXT delete mode 100644 16/PCGPE10/MODEX.TXT delete mode 100644 16/PCGPE10/MODFORM.TXT delete mode 100644 16/PCGPE10/MOUSE.TXT delete mode 100644 16/PCGPE10/PALLETTE.COL delete mode 100644 16/PCGPE10/PARADISE.TXT delete mode 100644 16/PCGPE10/PCGPE.EXE delete mode 100644 16/PCGPE10/PCX.TXT delete mode 100644 16/PCGPE10/PERSPECT.TXT delete mode 100644 16/PCGPE10/PIT.TXT delete mode 100644 16/PCGPE10/README.TXT delete mode 100644 16/PCGPE10/RTM.EXE delete mode 100644 16/PCGPE10/RTMRES.EXE delete mode 100644 16/PCGPE10/SBDSP.TXT delete mode 100644 16/PCGPE10/SBPRO.TXT delete mode 100644 16/PCGPE10/SCROLL.TXT delete mode 100644 16/PCGPE10/SOFTROCK.FNT delete mode 100644 16/PCGPE10/SPEAKER.TXT delete mode 100644 16/PCGPE10/STARS.TXT delete mode 100644 16/PCGPE10/SVGINTRO.TXT delete mode 100644 16/PCGPE10/TEXTURE.TXT delete mode 100644 16/PCGPE10/TIMER.ASM delete mode 100644 16/PCGPE10/TRIDENT.TXT delete mode 100644 16/PCGPE10/TSENG.TXT delete mode 100644 16/PCGPE10/TUT1.TXT delete mode 100644 16/PCGPE10/TUT10.TXT delete mode 100644 16/PCGPE10/TUT2.TXT delete mode 100644 16/PCGPE10/TUT3.TXT delete mode 100644 16/PCGPE10/TUT4.TXT delete mode 100644 16/PCGPE10/TUT5.TXT delete mode 100644 16/PCGPE10/TUT6.TXT delete mode 100644 16/PCGPE10/TUT7.TXT delete mode 100644 16/PCGPE10/TUT8.TXT delete mode 100644 16/PCGPE10/TUT9.TXT delete mode 100644 16/PCGPE10/UT.TXT delete mode 100644 16/PCGPE10/VESASP12.TXT delete mode 100644 16/PCGPE10/VGABIOS.TXT delete mode 100644 16/PCGPE10/VGAREGS.TXT delete mode 100644 16/PCGPE10/VIDEO7.TXT delete mode 100644 16/PCGPE10/VOC.TXT delete mode 100644 16/PCGPE10/WAV.TXT delete mode 100644 16/PCGPE10/WORMIE.PAS delete mode 100644 16/PCGPE10/XMS30.TXT delete mode 100644 16/PCGPE10/XTENDED.TXT delete mode 100644 16/PCGPE10/suround.txt diff --git a/16/PCGPE10.tar.7z b/16/PCGPE10.tar.7z new file mode 100644 index 0000000000000000000000000000000000000000..6311cef4afd10c1d221a1840a38430747457df62 GIT binary patch literal 558680 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

5rl5DgG5MuI7d^f${n%f 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 XwbY5w8JR+dHSVmhO2z_AHV|? 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

(>1@m02c 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 z%0A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

{*AxZ?5pCm?;+Stc@DFKdi7#~)$_F>)oZN)p~} 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

UXOUwr*{9w=LFaUMkg*Y=+3{~v&ChTa2IjBNA@ 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%0Dgacs@II1}^NoCWWdGxWBs}RK%B6$4 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�>iZ~NU~x8;c`!i8iQ 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 \ | (0,0,0) - Y Y \| - - - To relate the two systems you can use these equations. - - X = p(siní)(cosé) é = arctan (X/Y) - Y = p(siní)(siné) í = arccos (Z/p) - Z = p(cosí) p = û(X^2 + Y^2 + Z^2) - - If these don't seem right, do a couple of example problems for yourself, -it should make since after a bit of trig. - - -Matrix Notation -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - Lets say I can define Xt and Yt with the equations: - -Xt = aX + bY Where a,b,c,d are coeffiencets -Yt = cX + dY - - The matrix notation for this system of equations would be: - Ú ¿ -(Xt,Yt) = (X,Y)³a c³ - ³ ³ And we solve for this with these steps - ³b d³ - À Ù - - Ú ¿ - Xt = (X,Y)³a .³ = aX + bY - ³ ³ We move across the coordinates left to right - ³b .³ and multiply them by the coeffients in the - À Ù matrix, top to bottom - Ú ¿ - Yt = (X,Y)³. c³ = cX + dY - ³ ³ For Y, the second number, we use the second - ³. d³ column of the matrix - À Ù - - We can also multiply matricies in this fashion - Ú ¿ Ú ¿ - T = T1*T2 Where T1 = ³a c³ and T2 = ³e g³ - ³ ³ ³ ³ - ³b d³ ³f h³ - À Ù À Ù - -Ú ¿Ú ¿ Ú ¿ -³a c³³e g³ ³(ae + cf) (ag + ch)³ rows -> columns | -³ ³³ ³ = ³ ³ v -³b d³³f h³ ³(be + df) (bg + dh)³ -À ÙÀ Ù À Ù - - This product is dependent on position, so that means that - T1*T2 *DOES NOT* equal T2*T1 - - In English, the process above went like this, we move left to right in -the first matrix, T1, and top to bottom in the second, T2. AE + CF is our -first position. - - The numbers in the first row are multiplied by the numbers in the -first column. 1st * 1st + 2nd * 2nd is our first value for the new matrix. -Then you repeat the process for the next column of the second matrix. - - After that, you move down to the next row of the first matrix, and -multiply it by the 1st column of the second matrix. You then do the same -for the next column of the second matrix. This process is repeated until -you've done all of the rows and columns. - -If this is your introduction to matricies, don't feel bad if you're a bit -confused. They are a different mode of thinking about equations. The -operations above give the same results as if you were to do the long hand -algebra to solve them. It may seem a bit more difficult for these examples, -but when you get to systems of equations with many variables, this way is -MUCH faster to compute. Trust me, especially when you make your program do -it. - - -So, now you have the basic math.... - - - One important point for these matricies below. I will use a homogeneous -coordinate system, (X/r, Y/r, Z/r, r) Now I'll use r=1, so nothing will -really be different in my calculations, but you need to understand the -purpose. - - This form is very convienent for the translations and rotation -equations we will need to do because it allows for scaling of our points with -respect to a center point. - - Consider a point (2,2,2) in an object centered at (1,1,1). If we were -to scale the X direction by 3,(the X length to the center is 3 times what it -was) the point we want would be (4,2,2). Our new X = 3*(OldX-CenterX). -Without the added factor of the homogeneous system, calculations assume all -objects are centered at the origin, so our point would have turned out to be -(6,2,2), NOT the one we wanted. So that's why we are going to do it that way. - - - - ROTATIONS AND TRANSFORMATIONS -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - -Translation -ÄÄÄÄÄÄÄÄÄÄÄ - We will start with translation from the origin. Most objects are not -at (0,0,0,1), so we'll call their center (Tx,Ty,Tz,1). - -Ú ¿ -³ 1 0 0 0³ = T1 -³ ³ -³ 0 1 0 0³ This physically moves the object, so it is centered -³ ³ at the origin for our calcuations, eliminating the -³ 0 0 1 0³ need for a -Tx for each X, the matrix will factor it -³ ³ in when we multiply it by the others -³-Tx -Ty -Tz 1³ -À Ù But, we need sphereical coordinates... - -Ú ¿ -³ 1 0 0 0 ³ -³ ³ = T1 -³ 0 1 0 0 ³ -³ ³ -³ 0 0 1 0 ³ -³ ³ -³-p(cosé)(siní) -p(siné)(siní) -p(cosí) 1 ³ -À Ù - - -XY Clockwise Rotation -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - This will be our first rotation, about the Z-Axis - -Ú ¿ -³ siné cosé 0 0 ³ -³ ³ = T2 -³-cosé siné 0 0 ³ -³ ³ -³ 0 0 1 0 ³ -³ ³ -³ 0 0 0 1 ³ -À Ù - - -YZ Counter-Clockwise Rotation -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - Now we rotate about the X axis -Ú ¿ -³ 1 0 0 0 ³ -³ ³ = T3 -³ 0 -cosí -siní 0 ³ -³ ³ -³ 0 siní -cosí 0 ³ -³ ³ -³ 0 0 0 1 ³ -À Ù - - Notice that with two rotations that we can get any position in 3D space. - -Left Hand Correction -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - This will flip the X coordinates. Think about when you -look into the mirror, your left hand looks like your right. -These rotations do the same thing, so by flipping the X, it -will make your X move right when you increase it's value. - -Ú ¿ -³ -1 0 0 0 ³ -³ ³ = T4 -³ 0 1 0 0 ³ -³ ³ -³ 0 0 1 0 ³ -³ ³ -³ 0 0 0 1 ³ -À Ù - - -The Final Viewing Matrix -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - This is the net transformation matrix for our viewing perspective - -The math for this one is really messy, and I would need to go over even -more matrix stuff to get it reduced, so I will ask you to trust my -calculations - -V = T1*T2*T3*T4 - -Ú ¿ -³ -siné -(cosé)(cosí) -(cosé)(siní) 0 ³ -³ ³ = V -³ cosé -(siné)(cosí) -(siné)(siní) 0 ³ -³ ³ -³ 0 siní -cosí 0 ³ -³ ³ -³ 0 0 p 1 ³ -À Ù - - -Lets say our original (X,Y,Z,1) were just that, and the point after the -rotation is (Xv,Yv,Zv,1) - -(Xv,Yv,Zv,1) = (X,Y,Z,1) * V - - -Xv = -Xsiné + Ycosé - -Yv = -X(cosé)(cosí) - Y(siné)(cosí) + Zsiní - -Zv = -X(cosé)(siní) - Y(siné)(siní) - Zcosí + p - - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - - Some people have had trouble concepts of this implimentation, so I have -another way of setting up the equations. This works off of the straight -X,Y, and Z coordinates too, but uses another angle. - - -We will define the following variables - -Xan = Rotation about the X-Axis -Yan = Rotation about the Y-Axis -Zan = Rotation about the Z-Axis - - -Rotation about the Y Axis -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - -Ú ¿ -³ cos(Yan) 0 sin(Yan) ³ -³ ³ -³ 0 1 0 ³ -³ ³ -³ -sin(Yan) 0 cos(Yan) ³ -À Ù - - -Rotation about the Z Axis -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - -Ú ¿ -³ 1 0 0 ³ -³ ³ -³ 0 cos(Zan) -sin(Zan) ³ -³ ³ -³ 0 sin(Zan) cos(Zan) ³ -À Ù - - -Rotation about the X Axis -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - -Ú ¿ -³ cos(Xan) -sin(Xan) 0 ³ -³ ³ -³ sin(Xan) cos(Xan) 0 ³ -³ ³ -³ 0 0 1 ³ -À Ù - - -For simplification, lets call sin(Yan) = s1, cos(Xan) = c3, - sin(Zan) = s2, etc - -Final Rotation Matrix -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - -Ú ¿ -³ c1c3 + s1s2s3 -c1s3 + c3s1s2 c2s1 ³ -³ ³ -³ c2s3 c2c3 -s2 ³ -³ ³ -³ -c3s1 + c1s2s3 s1s3 + c1c3s2 c1c2 ³ -À Ù - - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - -Xv = x(s1s2s3 + c1c3) + y(c2s3) + z(c1s2s3 - c3s1) - -Yv = x(c3s1s2 - c1s3) + y(c2c3) + z(c1c3s2 + s1s3) - -Zv = x(c1s2s3 - c3s1) + y(-s2) + z(c1c2) - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - -Where Xv,Yv, and Zv are the final rotated points and the little x,y,z are -the original points. - - - - - - Normal Vectors - The Secret To Shading and Plane Elimination -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - - So, now you have the rotation equations... But, how do we make it fast? -Well, one of the best optimizations you can impliment is plane elimination. -It boils down to not displaying the planes that won't be seen. With that -said, here comes more math.... - - BE A MAN, KNOW YOUR NORMALS - - A 'normal' vector is perpendicular to a plane. Imagine the face of a -clock as a plane. Take your right hand and point your thumb toward yourself -and the other end toward the clock. Now curl your fingers in the -counter-clockwise direction. Your thumb is pointing in the direction of the -normal vector. This is called 'The Right Hand Rule' and it is the basis for -figuring the facing of planes. - - A plane can be determined with three points, try it. That's the minimum -you need, so that's what we will base our process on. Now if we have a line -segment, we could move it to the origin, maintaining it's direction and -lenght by subtracting the (X,Y,Z) of one of the points from both ends. This -is our definition of a vector. A line segment, starting at the origin and -extending in the direction (X,Y,Z). - - Here will be our plane, built from the three points below. - -(X1,Y1,Z1) V = (X1-X2, Y1-Y2, Z1-Z2) -(X2,Y2,Z2) W = (X1-X3, Y1-Y3, Z1-Z3) -(X3,Y3,Z3) - - So, we have our three points that define a plane. From these points we -create two vectors V and W. Now if you where to use the right hand rule with -these vectors, pointing your fingers in the direction of V and curling them -toward the direction of W, you would have the direction of the Normal vector. -This vector is perpendicular to both vectors, and since we have defined the -plane by these vectors, the normal is perpendicular to the plane as well. - -The process of finding the normal vector is called the 'Cross Product' and -it is of this form: - - Ú ¿ -V*W =³ i k j ³ - ³ ³ - ³ X1-X2 Y1-Y2 Z1-Z2 ³ - ³ ³ - ³ X1-X3 Y1-Y3 Z1-Z3 ³ - À Ù - - i = (Y1-Y2)(Z1-Z3) - (Z1-Z2)(Y1-Y3) - --k = (Z1-Z2)(X1-X3) - (X1-X2)(Z1-Z3) - - j = (X1-X2)(Y1-Y3) - (Y1-Y2)(X1-X3) - -The Normal to the plane is (i,-k,j) - - -NOTE: V*W *DOESN'T* equal W*V, it will be pointing in the negative direction - To prove that to yourself, lets go back to how I explained it before - We pointed in the direction of V and curled our fingers toward W, the - normal vector in the direction of your thumb. Try it in the - direction of W, toward V. It should be in the opposite direction. - Your normal, still perpendicular to both vectors, but it is negative. - If you use in your program, you will have the planes appearing when - they shouldn't and dissapearing when they are coming into view. - - So, now that we have a way to determin the direction of the plane, -how do we hide the plane? If the angle between the view point and the -normal is greater than 90 degrees, don't show it. One quick way that I -always use is to place the view point on an axis. I tipically set the -Z axis to come out of the screen, Y up and X across. Set the view point -to be at a positive point on the Z and then, if that normal vector has Z -greater than zero, I display it, otherwise I skip to the next one. - - This also has an application in shading. If you define a light scource, -just like the view point, you find the angle the normal and the light form. -Since you don't usually just want two colors, our 90 degree trick won't work -for you, but by finding this angle, and dividing all of the possible angles -by the number of colors you will allow in the shading, that color can be -assigned to the plane and, presto-chango, it looks like you know what your -doing... - - As you do your rotations, just rotate the coordinates of the normal and -that will keep everything updated. - - -Tips To Speed-Up Your Routines -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - -Pre-Calculate as many values as possible - The main limitation you will have is the speed of your math, using - precalculated values like Normals, Sin/Cos charts, and distance from the - origin are all good candidates. - -If you can get away with using a math-coprocessor, well... - This will greatly increase the speed of your routine. Unfortunately, - not everyone has one. - -Only figure values once - If you multiply (Siné)(Cosé) and will use that same value later, by all - means, keep it and use it then instead of doing the multiplication again. - -Another thing to keep in mind - The order of rotations *DOES* make a difference. Try it out and you'll - understand. Also, when you start to use these routines, you'll find - yourself making arrays of points and plane structures. - - -Counter-Clockwise points - Be sure to list your points for the planes in counter-clockwise order. - If you don't, not all of your planes will display correctly when you - start hiding planes. - -And as always, be clever - Just watch out, because when you have clever ideas you can lose a foot. - My brother once had a clever idea to cut his toe nails with an axe and - he lost his foot. - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - -Books to look for... -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - Any math book, the topics I covered will be found in: - - Normal Vectors - Analytic Geometry - Matrix Operations - Linear Algebra - Sines and Cosines - Trigonometry - - The Art of Graphics, by Jim McGregor and Alan Watt - 1986 Addison-Wesley Publishers - - - -Read the VLA.NFO file to find out how to contact us. diff --git a/16/PCGPE10/3DSHADE.DOC b/16/PCGPE10/3DSHADE.DOC deleted file mode 100644 index 2a456778..00000000 --- a/16/PCGPE10/3DSHADE.DOC +++ /dev/null @@ -1,311 +0,0 @@ - - ÖÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´% VLA Proudly Presents %ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ· - º º - ÓÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄĽ - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - Three Dimensional Shading In Computer Graphics - ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - By Lithium /VLA - - - - Hopefully you have read the companion document 3DROTATE.DOC, as this one -will build apon the concepts presented in my attempt to teach some of the -math need to make 3D graphics a reality. This file will cover such important -topics as the Dot Product and how routines are best constructed for real-time -3D rotations and planar shading. - - - - - Our Friend, The Dot Product - - The Dot Product is a neat relation that will allow you to quickly find -the angle between any two vectors. It's easiest to explain graphicly, so -I will exercise my extended-ASCII keys. - - -Two Vectors A & B - -A (Xa, Ya, Za) ³A³ = û( (Xa)ý + (Ya)ý + (Za)ý ) - -B (Xb, Yb, Zb) ³B³ = û( (Xb)ý + (Yb)ý + (Zb)ý ) - - -Where Xa, and the others coorispond to some value on their respective Axis's - - - ¿A - / - / - / - / - \ é <-- Angle Theta between vector A and B - \ - \ - \ - ÙB - - - Cos(é) = Xa * Xb + Ya * Yb + Za * Zb - ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - ³A³*³B³ - - - -Example: - -A (1,2,3) ³A³ = û( 1ý + 2ý + 3ý) = û(14) = 3.7417 - -B (4,5,6) ³b³ = û( 4ý + 5ý + 6ý) = û(77) = 8.7750 - - - Cos(é) = 1 * 4 + 2 * 5 + 3 * 6 = 4 + 10 + 18 = 32 = 0.9746 - ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄ - (3.7417)*(8.7750) 32.8334 32.8334 - - - ArcCos (.9746) = 12.9ø - - - So, your wondering how this revolutionizes you code, huh? Well, remember -our other friend, the Normal vector? You use Normal vectors that define -the directions of everything in our 3D world. Let's say that vector A was -the Normal vector from my plane, and B is a vector that shows the direction -that the light in my scene is pointing. If I do the Dot Product of them, -you will get the angle between them, if that angle is >= 90ø and <= 270ø -then no light falls on the visible surface and it doesn't need to be -displayed. - - -Also notice, the way the values of the Cosine orient themselves - - - - 90ø Cos 000ø = 1 - Cos 090ø = 0 - ³ Cos 180ø = -1 - Negative ³ Positive Cos 270ø = 0 - ³ - ³ -180ø ÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄ 0ø An angle between a light and a plane that - ³ is less than 90ø or greater than 270ø will - ³ be visible, so you can check if the Cos(é) - Negative ³ Positive is greater than 0 to see if it is visible. - ³ - ³ - - 270ø - - - How Do You Implement The Code? Easy As ã. - -Examples in ASM structures - -We will define our points like this - - STRUC XYZs - Xpos dd ? - Ypos dd ? - Zpos dd ? - Dist dd ? - ENDS XYZs ;size is 16 bytes - - -The X,Y,Zpos define a point in 3D space, Dist is the distance from the origin - -Dist = û( Xý + Yý + Zý ) - -Precalculate these values and have them handy in your data area - - -Our planes should look something like this - - STRUC PlaneSt - NumPts db ? ;3 or 4 - NormIndex dw ? - PtsIndex dw ? - dw ? - dw ? - dw ? - ENDS PlaneSt - -The number of points that in the plane depends on the number your fill -routines can handle you must have at least 3 and more than 6 is not suggested - - -Then we set up our data like this - -MaxPoints = 100 -MaxPlanes = 100 - -PointList XYZs MaxPoints DUP() -PlaneList PlaneSt MaxPlanes DUP() -NormalList XYZs <0,0,0, 10000h> , MaxPlanes DUP() - - Non-ASM User Note: - - I set up points in a structure that had an X,Y,Z and Distance - value. I set up a plane structure that had the number of points - the index number of the normal vector for that plane and the index - numbers for the points in the plane. - - The next lines set up arrays of these points in PointList, and - the number of points was defined as MaxPoints. An array of planes - was created as PlaneList with MaxPlanes as the total number of - plane structures in the array. NormalList is an array of the vectors - that are normal to the planes, one is set up initally (I'll explain - that next) and then one for each possible plane is allocated. - - -You'll notice that I defined the first Normal and then created space for -the rest of the possible normals. I'll call this first normal, the -Zero Normal. It will have special properties for planes that don't shade -and are never hidden. - - - - Well, before I start telling all the tricks to the writting code, let me -make sure a couple of points are clear. - -- In the 3DROTATE.DOC I said that you could set your view point on the - Z-Axis and then figure out if planes were visible by the post-rotation - Normal vectors, if their Z was > 0 then display, if not, don't - That is an easy way to set up the data, and I didn't feel like going - into the Dot Product at the time, so I generalized. So, what if you - don't view your plane from the Z-Axis, the answer is you use the... - - Dot Product! - - that's right. The angle will be used now to figure wheither or not to - display the plane. - -- I have been mentioning lights and view points as vectors that I can - use with the Normal vector from my plane. To work correctly, these - vectors for the lights and view should point in the direction that you - are looking or the direction that the light is pointing, *NOT* a vector - drawn from the origin to the viewer position or light position. - -- True Normal vectors only state a direction, and should therefore have - a unit distance of 1. This will have the advantage of simplifying the - math involved to figure you values. Also, for God's sake, pre-compute - your normal, don't do this everytime. Just rotate them when you do your - points and that will update their direction. - - If the Normal's have a length of 1 then ³A³*³B³ = 1 * 1 = 1 - - So: - Cos(é) = Xa * Xb + Ya * Yb + Za * Zb - ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - ³A³*³B³ - - Is Reduced To: - - Cos(é) = Xa * Xb + Ya * Yb + Za * Zb - - - We eliminated a multiply and a divide! Pat yourself on the back. - -- You ASM users might be wondering why I defined my Zero Normal as: - <0,0,0,10000h> How does 10000h = a length of 1 ? - - Well, this is a trick you can do in ASM, instead of using floating point - values that will be slow on computers without math co-processors, we can - use a double word to hold our value. The high word holds the integer - value, and the low word is our decimal. You do all of your computations - with the whole register, but only pull the high word when you go to - display the point. So, with that under consideration, 10000h = 1.00000 - Not bad for integers. - - -- How does the Zero Normal work? Since the X,Y,and Z are all 0, the - Cos(é) = 0, so if you always display when Cos(é) = 0, then that plane - will always be seen. - - - So, Beyond The Babble... How To Set Up Your Code - - -Define Data Points, Normals, and Planes - Pre-Calculate as many values as possible - - Rotate Points and Normals - - Determin Visible Planes With Dot Product - (Save this value if you want to shade) - - Sort Visible Planes Back to Front - - (Determin Shade From Dot Product) - - Clip Plane to fit scene - - Draw to the screen - - Change Angles - - Goto Rotation - - - - A quick way to figure out which color to shade your plane if you are - using the double word values like I described before is to take the - Dot Product result, it will lie between 10000h - 0h if you would like - say 16 shades over the angles, then take that value and shr ,12 that will - give you a value from 0h - 10h (0-16, or 17 colors) if you make 10h into - 0fh, add that offset to a gradient in your palette, then you will have - the color to fill your polygon with. - - Note also that the Cosine function is weighted toward the extremes. - If you want a smooth palette change as the angles change, your palette - should weight the gradient accordingly. - - - A useful little relation for depth sorting is to be able to find the - center of a triangle. - - E The center C = (D + E + F)/3 - ^ - / \ Divide each cooridinate by (Xd + Xe + Xf)/3 = Xc - / C \ and do the same for the Y's and Z's if you - / \ choose to sort with this method. Then rotate - DÄÄÄÄÄÄÄÄÄF that point and use it to depth sort the planes - - -Phong and Goraud Shading - - Recently, someone asked me about the practiblity of real-time phong and -goraud shading. The technique is common to ray-tracers and requires a great -deal of calculation when working with individual rays cast from each pixel, -but when only using this for each plane, it is possible. This type of shading -involves taking into account the reduced luminousity of light as distance -increases. For each light, you define a falloff value. This value should be -the distance a which the light will be at full intensity. Then at 2*FallOff -you will have 1/2 intensity, 3*FallOff will yeild 1/3 and so on. To implement -this type of shading, you will need to determin the distance from the light -to the center of the plane. If distance < FallOff, then use the normal -intensity. If it is greater, divide the FallOff value by the distance. This -will give you a scalar value that you can multiple by the shading color that -the plane should have. Use that offset and it will be darker since it is -further away from the light source. - However, to determin the distance form the light to each plane, you must -use a Square Root function, these are inherently slow unless you don't care -about accuracy. Also, it would be difficult to notice the use of this -technique unless you have a relatively small FallOff value and your objects -move about in the low intesity boundries. - - - - -Well, that's all that I feel like doing tonight, and besides, Star Trek is on! -So, see VLA.NFO for information about contacting myself or any of the other -members of VLA. - - Happy Coding! - - diff --git a/16/PCGPE10/ADLIB.TXT b/16/PCGPE10/ADLIB.TXT deleted file mode 100644 index 6904c753..00000000 --- a/16/PCGPE10/ADLIB.TXT +++ /dev/null @@ -1,479 +0,0 @@ - - Programming the AdLib/Sound Blaster - FM Music Chips - Version 2.0 (24 Feb 1992) - - Copyright (c) 1991, 1992 by Jeffrey S. Lee - - jlee@smylex.uucp - - - - Warranty and Copyright Policy - - This document is provided on an "as-is" basis, and its author makes - no warranty or representation, express or implied, with respect to - its quality performance or fitness for a particular purpose. In no - event will the author of this document be liable for direct, indirect, - special, incidental, or consequential damages arising out of the use - or inability to use the information contained within. Use of this - document is at your own risk. - - This file may be used and copied freely so long as the applicable - copyright notices are retained, and no modifications are made to the - text of the document. No money shall be charged for its distribution - beyond reasonable shipping, handling and duplication costs, nor shall - proprietary changes be made to this document so that it cannot be - distributed freely. This document may not be included in published - material or commercial packages without the written consent of its - author. - - - - Overview - - Two of the most popular sound cards for the IBM-PC, the AdLib and the - Sound Blaster, suffer from a real dearth of clear documentation for - programmers. AdLib Inc. and Creative Labs, Inc. both sell developers' - kits for their sound cards, but these are expensive, and (in the case - of the Sound Blaster developers' kit) can be extremely cryptic. - - This document is intended to provide programmers with a FREE source - of information about the programming of these sound cards. - - The information contained in this document is a combination of - information found in the Sound Blaster Software Developer's Kit, and - that learned by painful experience. Some of the information may not - be valid for AdLib cards; if this is so, I apologize in advance. - - Please note that numbers will be given in hexadecimal, unless otherwise - indicated. If a number is written out longhand (sixteen instead of 16) - it is in decimal. - - | Changes from Version 1 of the file will be indicated by the use of change - | bars in the left-hand margin. - - - - Chapter One - Sound Card I/O - - The sound card is programmed by sending data to its internal registers - via its two I/O ports: - - 0388 (hex) - Address/Status port (R/W) - 0389 (hex) - Data port (W/O) - - | The Sound Blaster Pro is capable of stereo FM music, which is accessed - | in exactly the same manner. Ports 0220 and 0221 (hex) are the address/ - | data ports for the left speaker, and ports 0222 and 0223 (hex) are the - | ports for the right speaker. Ports 0388 and 0389 (hex) will cause both - | speakers to output sound. - - The sound card possesses an array of two hundred forty-four registers; - to write to a particular register, send the register number (01-F5) to - the address port, and the desired value to the data port. - - After writing to the register port, you must wait twelve cycles before - sending the data; after writing the data, eighty-four cycles must elapse - before any other sound card operation may be performed. - - | The AdLib manual gives the wait times in microseconds: three point three - | (3.3) microseconds for the address, and twenty-three (23) microseconds - | for the data. - | - | The most accurate method of producing the delay is to read the register - | port six times after writing to the register port, and read the register - | port thirty-five times after writing to the data port. - - The sound card registers are write-only. - - The address port also functions as a sound card status byte. To - retrieve the sound card's status, simply read port 388. The status - byte has the following structure: - - 7 6 5 4 3 2 1 0 - +------+------+------+------+------+------+------+------+ - | both | tmr | tmr | unused | - | tmrs | 1 | 2 | | - +------+------+------+------+------+------+------+------+ - - Bit 7 - set if either timer has expired. - 6 - set if timer 1 has expired. - 5 - set if timer 2 has expired. - - - - Chapter Two - The Registers - -The following table shows the function of each register in the sound -card. Registers will be explained in detail after the table. Registers -not listed are unused. - - Address Function - ------- ---------------------------------------------------- - 01 Test LSI / Enable waveform control - 02 Timer 1 data - 03 Timer 2 data - 04 Timer control flags - 08 Speech synthesis mode / Keyboard split note select - 20..35 Amp Mod / Vibrato / EG type / Key Scaling / Multiple - 40..55 Key scaling level / Operator output level - 60..75 Attack Rate / Decay Rate - 80..95 Sustain Level / Release Rate - A0..A8 Frequency (low 8 bits) - B0..B8 Key On / Octave / Frequency (high 2 bits) - BD AM depth / Vibrato depth / Rhythm control - C0..C8 Feedback strength / Connection type - E0..F5 Wave Select - -The groupings of twenty-two registers (20-35, 40-55, etc.) have an odd -order due to the use of two operators for each FM voice. The following -table shows the offsets within each group of registers for each operator. - - - Channel 1 2 3 4 5 6 7 8 9 - Operator 1 00 01 02 08 09 0A 10 11 12 - Operator 2 03 04 05 0B 0C 0D 13 14 15 - -Thus, the addresses of the attack/decay bytes for channel 3 are 62 for -the first operator, and 65 for the second. (The address of the second -operator is always the address of the first operator plus three). - -To further illustrate the relationship, the addresses needed to control -channel 5 are: - - 29 - Operator 1 AM/VIB/EG/KSR/Multiplier - 2C - Operator 2 AM/VIB/EG/KSR/Multiplier - 49 - Operator 1 KSL/Output Level - 4C - Operator 2 KSL/Output Level - 69 - Operator 1 Attack/Decay - 6C - Operator 2 Attack/Decay - 89 - Operator 1 Sustain/Release - 8C - Operator 2 Sustain/Release - A4 - Frequency (low 8 bits) - B4 - Key On/Octave/Frequency (high 2 bits) - C4 - Feedback/Connection Type - E9 - Operator 1 Waveform - EC - Operator 2 Waveform - - - - Explanations of Registers - -Byte 01 - This byte is normally used to test the LSI device. All bits - should normally be zero. Bit 5, if enabled, allows the FM - chips to control the waveform of each operator. - - 7 6 5 4 3 2 1 0 - +-----+-----+-----+-----+-----+-----+-----+-----+ - | unused | WS | unused | - +-----+-----+-----+-----+-----+-----+-----+-----+ - - -Byte 02 - Timer 1 Data. If Timer 1 is enabled, the value in this - register will be incremented until it overflows. Upon - overflow, the sound card will signal a TIMER interrupt - (INT 08) and set bits 7 and 6 in its status byte. The - value for this timer is incremented every eighty (80) - microseconds. - - -Byte 03 - Timer 2 Data. If Timer 2 is enabled, the value in this - register will be incremented until it overflows. Upon - overflow, the sound card will signal a TIMER interrupt - (INT 08) and set bits 7 and 5 in its status byte. The - value for this timer is incremented every three hundred - twenty (320) microseconds. - - -Byte 04 - Timer Control Byte - - 7 6 5 4 3 2 1 0 - +-----+-----+-----+-----+-----+-----+-----+-----+ - | IRQ | T1 | T2 | unused | T2 | T1 | - | RST | MSK | MSK | | CTL | CTL | - +-----+-----+-----+-----+-----+-----+-----+-----+ - - bit 7 - Resets the flags for timers 1 & 2. If set, - all other bits are ignored. - bit 6 - Masks Timer 1. If set, bit 0 is ignored. - bit 5 - Masks Timer 2. If set, bit 1 is ignored. - bit 1 - When clear, Timer 2 does not operate. - When set, the value from byte 03 is loaded into - Timer 2, and incrementation begins. - bit 0 - When clear, Timer 1 does not operate. - When set, the value from byte 02 is loaded into - Timer 1, and incrementation begins. - - -Byte 08 - CSM Mode / Keyboard Split. - - 7 6 5 4 3 2 1 0 - +-----+-----+-----+-----+-----+-----+-----+-----+ - | CSM | Key | unused | - | sel | Spl | | - +-----+-----+-----+-----+-----+-----+-----+-----+ - - bit 7 - When set, selects composite sine-wave speech synthesis - mode (all KEY-ON bits must be clear). When clear, - selects FM music mode. - - bit 6 - Selects the keyboard split point (in conjunction with - the F-Number data). The documentation in the Sound - Blaster manual is utterly incomprehensible on this; - I can't reproduce it without violating their copyright. - - -Bytes 20-35 - Amplitude Modulation / Vibrato / Envelope Generator Type / - Keyboard Scaling Rate / Modulator Frequency Multiple - - 7 6 5 4 3 2 1 0 - +-----+-----+-----+-----+-----+-----+-----+-----+ - | Amp | Vib | EG | KSR | Modulator Frequency | - | Mod | | Typ | | Multiple | - +-----+-----+-----+-----+-----+-----+-----+-----+ - - bit 7 - Apply amplitude modulation when set; AM depth is - controlled by the AM-Depth flag in address BD. - bit 6 - Apply vibrato when set; vibrato depth is controlled - by the Vib-Depth flag in address BD. - bit 5 - When set, the sustain level of the voice is maintained - until released; when clear, the sound begins to decay - immediately after hitting the SUSTAIN phase. - bit 4 - Keyboard scaling rate. This is another incomprehensible - bit in the Sound Blaster manual. From experience, if - this bit is set, the sound's envelope is foreshortened as - it rises in pitch. - bits 3-0 - These bits indicate which harmonic the operator will - produce sound (or modulation) in relation to the voice's - specified frequency: - - 0 - one octave below - 1 - at the voice's specified frequency - 2 - one octave above - 3 - an octave and a fifth above - 4 - two octaves above - 5 - two octaves and a major third above - 6 - two octaves and a fifth above - 7 - two octaves and a minor seventh above - 8 - three octaves above - 9 - three octaves and a major second above - A - three octaves and a major third above - B - " " " " " " " - C - three octaves and a fifth above - D - " " " " " " - E - three octaves and a major seventh above - F - " " " " " " " - - -Bytes 40-55 - Level Key Scaling / Total Level - - 7 6 5 4 3 2 1 0 - +-----+-----+-----+-----+-----+-----+-----+-----+ - | Scaling | Total Level | - | Level | 24 12 6 3 1.5 .75 | <-- dB - +-----+-----+-----+-----+-----+-----+-----+-----+ - - bits 7-6 - causes output levels to decrease as the frequency - rises: - - 00 - no change - 10 - 1.5 dB/8ve - 01 - 3 dB/8ve - 11 - 6 dB/8ve - - bits 5-0 - controls the total output level of the operator. - all bits CLEAR is loudest; all bits SET is the - softest. Don't ask me why. - - -Bytes 60-75 - Attack Rate / Decay Rate - - 7 6 5 4 3 2 1 0 - +-----+-----+-----+-----+-----+-----+-----+-----+ - | Attack | Decay | - | Rate | Rate | - +-----+-----+-----+-----+-----+-----+-----+-----+ - - bits 7-4 - Attack rate. 0 is the slowest, F is the fastest. - bits 3-0 - Decay rate. 0 is the slowest, F is the fastest. - - -Bytes 80-95 - Sustain Level / Release Rate - - 7 6 5 4 3 2 1 0 - +-----+-----+-----+-----+-----+-----+-----+-----+ - | Sustain Level | Release | - | 24 12 6 3 | Rate | - +-----+-----+-----+-----+-----+-----+-----+-----+ - - bits 7-4 - Sustain Level. 0 is the loudest, F is the softest. - bits 3-0 - Release Rate. 0 is the slowest, F is the fastest. - - -Bytes A0-B8 - Octave / F-Number / Key-On - - 7 6 5 4 3 2 1 0 - +-----+-----+-----+-----+-----+-----+-----+-----+ - | F-Number (least significant byte) | (A0-A8) - | | - +-----+-----+-----+-----+-----+-----+-----+-----+ - - 7 6 5 4 3 2 1 0 - +-----+-----+-----+-----+-----+-----+-----+-----+ - | Unused | Key | Octave | F-Number | (B0-B8) - | | On | | most sig. | - +-----+-----+-----+-----+-----+-----+-----+-----+ - - bit 5 - Channel is voiced when set, silent when clear. - bits 4-2 - Octave (0-7). 0 is lowest, 7 is highest. - bits 1-0 - Most significant bits of F-number. - - In octave 4, the F-number values for the chromatic scale and their - corresponding frequencies would be: - - F Number Frequency Note - 16B 277.2 C# - 181 293.7 D - 198 311.1 D# - 1B0 329.6 E - 1CA 349.2 F - 1E5 370.0 F# - 202 392.0 G - 220 415.3 G# - 241 440.0 A - 263 466.2 A# - 287 493.9 B - 2AE 523.3 C - - -Bytes C0-C8 - Feedback / Algorithm - - 7 6 5 4 3 2 1 0 - +-----+-----+-----+-----+-----+-----+-----+-----+ - | unused | Feedback | Alg | - | | | | - +-----+-----+-----+-----+-----+-----+-----+-----+ - - bits 3-1 - Feedback strength. If all three bits are set to - zero, no feedback is present. With values 1-7, - operator 1 will send a portion of its output back - into itself. 1 is the least amount of feedback, - 7 is the most. - bit 0 - If set to 0, operator 1 modulates operator 2. In this - case, operator 2 is the only one producing sound. - If set to 1, both operators produce sound directly. - Complex sounds are more easily created if the algorithm - is set to 0. - - -Byte BD - Amplitude Modulation Depth / Vibrato Depth / Rhythm - - 7 6 5 4 3 2 1 0 - +-----+-----+-----+-----+-----+-----+-----+-----+ - | AM | Vib | Rhy | BD | SD | TOM | Top | HH | - | Dep | Dep | Ena | | | | Cym | | - +-----+-----+-----+-----+-----+-----+-----+-----+ - - bit 7 - Set: AM depth is 4.8dB - Clear: AM depth is 1 dB - bit 6 - Set: Vibrato depth is 14 cent - Clear: Vibrato depth is 7 cent - bit 5 - Set: Rhythm enabled (6 melodic voices) - Clear: Rhythm disabled (9 melodic voices) - bit 4 - Bass drum on/off - bit 3 - Snare drum on/off - bit 2 - Tom tom on/off - bit 1 - Cymbal on/off - bit 0 - Hi Hat on/off - - Note: KEY-ON registers for channels 06, 07, and 08 must be OFF - in order to use the rhythm section. Other parameters - such as attack/decay/sustain/release must also be set - appropriately. - - -Bytes E0-F5 - Waveform Select - - 7 6 5 4 3 2 1 0 - +-----+-----+-----+-----+-----+-----+-----+-----+ - | unused | Waveform | - | | Select | - +-----+-----+-----+-----+-----+-----+-----+-----+ - - bits 1-0 - When bit 5 of address 01 is set, the output waveform - will be distorted according to the waveform indicated - by these two bits. I'll try to diagram them here, - but this medium is fairly restrictive. - - ___ ___ ___ ___ _ _ - / \ / \ / \ / \ / | / | - /_____\_______ /_____\_____ /_____\/_____\ /__|___/__|___ - \ / - \___/ - - 00 01 10 11 - - - - | Detecting a Sound Card - | - | According to the AdLib manual, the 'official' method of checking for a - | sound card is as follows: - | - | 1) Reset both timers by writing 60h to register 4. - | 2) Enable the interrupts by writing 80h to register 4. NOTE: this - | must be a separate step from number 1. - | 3) Read the status register (port 388h). Store the result. - | 4) Write FFh to register 2 (Timer 1). - | 5) Start timer 1 by writing 21h to register 4. - | 6) Delay for at least 80 microseconds. - | 7) Read the status register (port 388h). Store the result. - | 8) Reset both timers and interrupts (see steps 1 and 2). - | 9) Test the stored results of steps 3 and 7 by ANDing them - | with E0h. The result of step 3 should be 00h, and the - | result of step 7 should be C0h. If both are correct, an - | AdLib-compatible board is installed in the computer. - | - | - | Making a Sound - | - | Many people have asked me, upon reading this document, what the proper - | register values should be to make a simple sound. Well, here they are. - | - | First, clear out all of the registers by setting all of them to zero. - | This is the quick-and-dirty method of resetting the sound card, but it - | works. Note that if you wish to use different waveforms, you must then - | turn on bit 5 of register 1. (This reset need be done only once, at the - | start of the program, and optionally when the program exits, just to - | make sure that your program doesn't leave any notes on when it exits.) - | - | Now, set the following registers to the indicated value: - | - | REGISTER VALUE DESCRIPTION - | 20 01 Set the modulator's multiple to 1 - | 40 10 Set the modulator's level to about 40 dB - | 60 F0 Modulator attack: quick; decay: long - | 80 77 Modulator sustain: medium; release: medium - | A0 98 Set voice frequency's LSB (it'll be a D#) - | 23 01 Set the carrier's multiple to 1 - | 43 00 Set the carrier to maximum volume (about 47 dB) - | 63 F0 Carrier attack: quick; decay: long - | 83 77 Carrier sustain: medium; release: medium - | B0 31 Turn the voice on; set the octave and freq MSB - | - | To turn the voice off, set register B0h to 11h (or, in fact, any value - | which leaves bit 5 clear). It's generally preferable, of course, to - | induce a delay before doing so. - | - | - | Acknowledgements - | - | Thanks are due to the following people: - | - | Ezra M. Dreisbach (ed10+@andrew.cmu.edu), for providing the information - | about the recommended port write delay from the AdLib manual, and the - | 'official' method of detecting an AdLib-compatible sound card. - | - | Nathan Isaac Laredo (gt7080a@prism.gatech.edu), for providing the - | port numbers for stereo sound on the Sound Blaster Pro. diff --git a/16/PCGPE10/ANSI.TXT b/16/PCGPE10/ANSI.TXT deleted file mode 100644 index fa894b6f..00000000 --- a/16/PCGPE10/ANSI.TXT +++ /dev/null @@ -1,326 +0,0 @@ -ÛÛÛÛÛÛ Û Û Û ÝßÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛßßßßßßßßßÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÝÝÞ ÛÛ Û ÛÛÜßÛÛÛ -ßßßÜÜÜÜÜÜÜÜÛÛÛÛÛÛÛÛÛÛÛßßßÜÜÜÜÛÛÛÛÛÜÜÜÜ -ßßÛÛÛÛÛ -ÛÛÛÛÛÛ ÛÛÛß Û ÛÛÛÜßÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛßßÜÛÛÛÛßßÜÛÛÛÛÛÛÛÞÛÛÜÜßÛÛÛÛÜ -ßÛÛÛ -ÛÛÛÛÛÛ  Û Û ÛÛ ÛÛÛÛÛÜßÛÛÛÛ -ßßßßßÜÜÜÛÛÛÛÛÛ ÛÛÛßßßßÞßÝßÛÛÛÛÛÛÛÛÛÛ -ÛÛ -ÛÛÛÛÛÛ ÛÛÛ Û ÛÛ ÛÛÛÛÛÛÛÜßÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛ ÛßÜÜÛÛÛÛÜÛÜÛÜÜ ÛßÜÛÛÛ -ÛÝÞÛ -ÛÛÛÛÛÛ Û ßÜÜÜÜß  -Û ÛÛÛÛÛÛÛÛÛÜßÛÛÛÛÛÛÛÛÛÛÛÛÝÝÞÝ -ÞÛßÜÜÜÜßßÜÜÜÜßÜ ÝÛÛÛÛÛ Û -ÛÛÛÛÛÛ ÛÛ ßßÜÜÜÜÛÛÛÛÛ Û - ÜßÛÛÛÛÛÛÛÛÛÛÛ ÜÛ ÛÛ -ÛÛÛÛÞÞÛÛÛÛ ÛÜÞÛÛÛÛ Û -ÛÛÛÛÛÛ  ÛÛß ßÜÜÜÛÛÛÛÛÛÛÛßÜ -Û ÛÛ ÜßÛÛßßßßÛÛÛ - ÛÝÞÞÛßÛÛÝÛÛßÛÛÛ ÛÛ -ÞÞÛÛÝÞÛ -ÛÛÛÛÛÛ ÛÛ ÝÞÞÛÛÛÛÛÛÛÛÛÛÛÜ -Û ÛÛÛÛ ÜßÛÛÛÛÜÛÛ - ÛÛÜßßßÜÜÜßß -ÛÛÛßÜÛ ÝÛÛÛ ÛÛ -ÛÛÛÛÝÝÞÛ Û ÝÞÞÛÛÛ -ÛÛÛÛÛÛÛÛÛß  ÜßÛÛÛÛÛ  -ÛÛÛÛ ÛÛÛÛÛÜÜÜÜÜÛÛÛ ÛÛ ÛÛÛ -ÛÛÛÛÝÝÞ Û ÛÛÛÛÛÛÛÛÛÛÛ ÛÛ - ÜßÛÛÛÝÝÞÛÛÛÛÜßßßÛÛÛß - ßÛÛÛÜ ÛÛÛÛ -ÛÛÛÛÝÝÞÛÛÛÛ ÛÜßß -ÜÜÜßÛÛÛ  Û   - ÜßÛÛ ÛÛÛ ßßßß ÜÛßßÜÛÛß -ßÛÛÛÛ -ÛÛÛÛÝÝÞÛÛ ßÜß ÜÜÜß -ÜßÛ  Üßß -ÜÜßÛÛÜÜÜÜÜÜÜÜÛÛßßÜÛÛÛÜÜßÛ -ÛÛÛÛÝÝÞÛ Ûß Ü   -Û Û  ßÜÜÛÛÛÛÛÜÜ -ßßßßßßßßÜÜÛÛÛÛÛÛÛÛÛÜ -ÜßßÛÛ ÛÛÛ ÜÜ -ÛÛÛÛ ßÜÛÛÛÛÛÛÛÛÜÜßßßßßÛß -ÜÜÜÜÜÜßÛÛÛÛÛÛ -ÛÛÛÛÝÝÞÛÛ Û   - ÛÛÛÛÛÛÛÛÛÛÛÛÛßÜÛÛ ÛÛÛÛÛÛÛÛÝÞÛ -ÛÛÛ -ÛÛÛÛÝÝÞÛÛ ÛÛ ÛÛ - ÜßÛÛÛÛÛÛÛÛÛÛÛÝÞÛÛÝÞÛÛÛÛÛÛÛÛÛ -ßÛÛÛ -ÛÛÛÛÝÝÞ ÛÛ Û Û   - ÜÜßßßßßÛÛÛÛÛ ÛÛÛ ÛÛÛÛÛÛÛÛÝÞ -ÛÜßÛ -ÛÛÛÛÝÝÞÛÛÛ Û ÛÛ   - ÛÛÜÜÜÜÜÜÜ Û ßßßßßß Ü -ÛÛÛÛÜ -ÛÛÛÛÝÝÞ Û Û ßÜ  - ÛÛÛÛÛÛÛÛÛ ÛÛ ÛÛÛÛÛÛ ÛÛÛÛÛÛ -ÛÜÜßÝÝÞÛ ÛÛ ÜÜß -Ü ÝÞÛÛÛÛÛÛÛÛÛ ÝÛ ÛÛÛÛÛÛÝÞÛÛÛÛ -Û -ÛÛÛÛÛ ÛÛÛ ÛÝÞÛÜÜß -Ü ÛÛÛÛÛÛÛÛÛÛ ÛÛ ÛÛÛÛÛÛÛ ÛÛÛÛÛ -ÛÛÛÛÝÞÛ ÛÛ ÛÛÛÜß -Ü ÜßÛÛÛÛÛÛÛÛ ÝÛ ÛÛÛÛÛÛÛÝÞ -ÛÛÛÛ -ÛÛÛÛ Û ÛÝÞÛÛÛÜÜ -ÛÜ ÝÞÛÛÜÜÜßßßßÛ ÛÛ ÛÛÛÛÛÛß -ÜßÜÜßß -ÛÛÛ ÛÛ ÜÜÜÜÜÜÜÜÜ ÛÛÝÞÛÛÛÛÜÜ -ßÜ ÝÞÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜßßÜ -ÜÛÛÛ ßÛÛ -ßßÜÛßßßÜÜÜÜÜÜÜÜÜßßßßßßßßßÛÛÛÛÛÜßÛÛÛ -ÛÜÜßÜ ÝÞÛÛÛÛÛÛÛÛÛÛÛßÛÛÛÛÛÛÛÛÛÛ -ÛÝßÜß -ÜßÜÜÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÛÛÛÛÛÛÛÜÜß -Ü ßÜÜÜÜÜÜÜÜÜßßßÜÜÜÜÜÜÜÜÜÜßßßÜ -ÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜßÜ  - ßÜÜÛÛÛÛÛÛÛßÜÛÛÛÜßßÛÛÛÛÛßÜÛÛÛÜ -ßÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜßÜ  -ÜßßÛÛÛÛÛÛÝÞÛÛÛÛÛ ÛÛÛÛÛÝÞÛÛÛÛÛ Û -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛßßßßÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜßÜ -ÛÛÛÜßßßÛÛÛ ÛÛÛßßÜßßßÛÛÛ ÛÛÛßßÜÛÛ -ÛÛßßßßßÜÜÜÜÜÜÜÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜßßßÛÛÛÛÛÛÛÛÛÜÜß -ÜÛÛÛÛÛÜÜÜÜÜÜÜÛÛÛÛÛÛÜÜÜÜÜÜÜÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÛÛÛÛÛÛÛÛÛÛÜÜß -ÜÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜß -ÜÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜßßßßÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜß -ÜÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛßßßßßÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜß -Ü ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜß -ÜÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛßÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜ -ÜßÜÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜ -ÜßÜÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛßßÛÛÛÛÛÛßßßßßßßßßßÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÜÜßÜÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛßßßÛÜÜÜÜÜÜßßÛÛÛÛÛÛÛÛÜÜÜÜÜÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜßÜÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÝÝÞÝÞÛÛÛÛÛ ÛÝÞ -ÛÛÛÛßßÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛßÛÛÛÛÛÜÜß -ÜÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛ ÛÛ ÛÛÛÝÝÞÛÝÞ -ÛÛßßÜÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛßßßßßßÜÜÜÜÜÜÛÛÛÛÛÛÛ -ÛÜÜßÜÛÛÛÛÛÛÛ -ÛÛÛÜÜÜÜßßßßÛ ÛÛÝÞÛÝÝÞÛÛÝÞ -ßßÜÛÛÝÞÛÛÛßßÜßÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜßÜÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÝÝÞÛÛÛÜßÝÞÛÛÛÛÜ ÛÛÛÛ Û -ÛßßÜÛÝÞÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÜÜßÜÛÛÛ -ÛÛÛßßÜßßÛÛÝÝÞÛÛÛÛÛÜÛÛÛÛÛÛÛÛÛÛÛÜß -ßÜÛÛÝÜßßÜßÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÜÜßÜÛÛ -ÛÛÛÝÝÞÛÛÜÜß ÛÛÛÛÛßßßßßßßßßßßßßßÛÛÛÛÝ Üßß ß -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛßßßÜÛÛÛÛÜÜßÜ -ÛßßÛÜÜßÛÛÛÛÜÛßßÜÜÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜßß -ÜÜßßßÜÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛßßßÜÜÜÜÜÜÛÛÛÛÛÛÛÛÛÛÜÜ -Û ßÜßß ÛÛÛßÜÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÝÜÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÜßßÜßßß Û ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÜßßÜÛÛÛÜÞÛÛÛÛÛÛÛÛÛÛÛÛÛßßßßßÛÛßßßßßÛÛÛÝÞÛÛßß -ßßßßÜÜÜÜÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÜÝÞÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÝÞÞÛÜÝÞÝÞ -ÞÛÜÝÞÛÛÝÞÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛ -ÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÛÛÜÜÜÜÜÛÛÛÝÞÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÝÝÞÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛßÜÜÜßÛÛÛÛÛÛÛ ÛÛÛÛÛ -ßßÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÜÜßÛÛÛßÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÝÞÛÛÛÛÛÛÝÞÛÛÛÛÛÛ -ÜÜÜÜÜßßßßßßßßßßÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÜÜÜÜ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛßßÜÛÛÛÛÛÛÛÝÞÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÜÜßÛÛÛÛÛÛÛÛÛßÛÛÛÛÛÛÛÛÛÛÛÛÛßÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÜßßßßßßßßÛÛÜÜßÛÛÛÛÛÛÛÛÜÜßßßßßßßßßÜÜÛÛÛß ÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÜÛßßß ÜßßßÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛßßß -ÜÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛßßÜÜÛÛÛÛÛÛÛ ÜÜßßßßßßßßßÜÜÜ ÛÜßÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛßÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛßßÜÛÛÛÛÛÛÛÛÛÛÛÜÜßßß ÛÛ ßßßÜÜÛßßÜÜÜÜÜßßÜ -ÜßßÛßßÛÛÛÛÛÛÛßßßßßßÜÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÝÝÞÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ ÝÛ ÛÛßßßÜÛÛÛÛÛÛÛÛÛÜß -ßÛÜßÛÜÜßÜÜÜÜÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÝÝÞÛÛÛÛÛÛÛÛÛÛÛÜßßßßß ßÜÜÜÜÛßÜÛÛÛÛÛÛÛÛÛÛÛÛ Û -Û ÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÝÝÞÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛ Û -ÛÝÞÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛßÛÛÛÛ -ÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜßÛÛÛÛÛÛÛÛÛÛÛßÜ -ÜÛ ÛÛÛÛÛ ÛÛÛÛÛÛÛÛßßßßßßßÜÜÜÛÛÛÛÛ -ÛÛÛÛÛÛÛÜÜßÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜßßÛÛÛÛßßßÜ -ÜßßÜÛÛÛÛÛÝÞÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÜÜÜßßÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛßÜÜÛÛÜ ÜÜÛÛÛÜÜÛÛÜÜ -ßßßÜÜÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛ ÛÜÜÜÜÜÜÜßßßßßßß ÜÜÜÛÛÛÛÛÛÝÞÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛ ÝÛ ÛÛÛÛÛÛÛÛÛÝÞÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛ ÛÛ ÛÛÛÛÛÛÛÛÛÝÞÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛßßßÜÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÝÝÞÛÛÛÛÛÛÛÛÛÛÛÛ ÝÛ ÛÛÛÛÛÛÛÛÛÛ ÛÛÛÛ -ßßßßßÜÜÜÜÜÜÜÜÜÜÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ßßÜÜÜÜÜÜÜÛÛÜÜßßßÛÛÛÛÛÛÛÛÛ ÛÛ ÛÛÛÛÛÛÛßßÜÛ ÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛÜ ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ ÛÛÛÝÞÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛßÜÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜßßÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ßßßßßßßÜÜÜÜßßÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÜÜßÜÜÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜßÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛßÛÛÛÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÝÝÞÛÛÛÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÝÞÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÝÝÞÛÛÛÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛ ÛÛÛÛßßßßßßßÛÛÛÛ ÛÛÛßßßßßßßßÛÛÛÝÞÛÛÛßßßßßßßßßßß -ßÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÝÝÞÛßÜÜÜÛÛÛÛÝÞÜÜÜßÝÞÝÜÜÜ -ÛÛÛÛÝÞÜÜßÛ ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜßßßÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛ ÜÜÛÛÛÛÛÛÛÛ ÛÛÛÛÜ ÛÛÛÛÛÛÛÛÛ ÛÛÛÜ ÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÝÝÞÞÛÛÛÛÛÛÛÛÛÝÞÛÛÛÛÝÞÞÛÛÛÛÛÛÛÝ -ÞÛÛÛÝÞÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÜÜßßßÛÛÛÛÛÛÛ ÛÛÛßßÜßßß -ÛÛÛÛÛÛ ÛÛßßÜÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛ -ßÜÜÜÜÜÜÜÜÜ ÜÜÜÜßÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ßßßßßßßßÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -Þ²Û²±°°±²ÛßÛÜÜß°ßÜÛÛÛÛ -ßßßßßßÜÜÜÜÜÜÜÛÛÛßßÜÛ±±° ±²Üß -ÛÛÛÛÛÛÛÛÛÛÜÜÜÜÜßßßßßßßÛÛÛÛÛÛÛ -ÜßÛ²±°°ßßÜßÛÛÛÛÜßÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÜÜßÛ²±°°ßÜÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÝÝÞÛ²±°ÝÞÜÜßÛÛÛÛÝÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ -ÜÜÜÜÜÜÜÜÞÛ²°ÝÜÜÜÜÜÜÜÜÜÜÜÜÜÜßÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛ -ÛÛ Û²±°°ßßÜÜÛÛÛÝÜÜÜÜ -ÜÜÜÜÜÜÜÜÜßßßßßßßßßßßß Û²°ß -²²±±°° °°±±²²Û ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛ Û²±°°ÜÛ ÜßÛÛßÜÛÛÛÜÜÜÜ -ÜÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ Û²°ÛÜÜÜÜÜÜÜÜß -ßßßßÜÛÛßßßßÜÜÜÛÛÛÛÛÛÛÛ -ÛÛ ²Û²±°±²ßÛßß ÜÜÜÜÜßßÛßßÜ -ÜÜÜßßÛßßÜÜÜÜßßÛÛ Û²° -ÜÜÜßßÛÛßßßßßßßßßÛÛÛÛÛÛÛÛÛßßßßÛÛÛ -ÛÛ ÛÛ²±°ßß Ü± ÛÛÛ -Û²±°Ü Û²²²±°°ÜÜßÛ²²±°° -ÜÜ Û²°²²±°°ÜÜß²±° °±² -ÛÜÜÜÜÜÜÜÜ ²±° ÜßÛ -ÛÛ ²Û²±°Û Û± ßßßßÛ -²±° Û±ßß²±° °Üßßß² -±° °Üß°±ßß²±° °Üß -²ÜÜÜÜ ÜÜÜÜÜÜܲ±° °° -Û -ÛÛ ÛÛ²±°Û Û± ÛÛÛÛ Û -²±°ÝÞ±ß ß²±°Û Ü -ÜÜß²±°Û ±ß²±°Û Û -²±°Û°Üß±ÜßÛßÜ  - °±Û -ÝÝÞÛÛ²±°ÝÞÞ²±°ÝÞÛÛÝ -ÝÞ²±° ²ßßßßßÞ²±° -ÝÞÛÝÝÞ²±°Ý ²ßßß -ßßÞ²±°Ý ß²±°°ÝÞ ÛÛÜÛ -  °±Û -ßܲ۲±°°±Ü ²±° ÜßÛ -ßÜÛ²±° ÜßÜßÛÛÛ Û²±° -ÛÛÛ Û²±°ÜßÛÛÛ Û -²±°Ü²±°°°ÝÞÜßÛÛßßÜ - °±Üß -ßÛÛ²±°°±²Ûßܲ±° ßÜßÛ²±°  -±²ßÜßÜÛÜÜß²±ßÜÛÛÛÜ -ß²±ßÜßßÜÛÛÜÜß²±ßÜ -²±°°ßßܲ°ßÜÜÜß - °±²Ûß -ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÛÛÜÜÜÜÜÜÜÜÛÜÛÛÛÛÛ -ÜÜÜÛÛÛÛÛÛÜÜÜÜÜÛÛÛÛÛÛÛÜÜÜ -ÜÜÜÜÜÜÛÜÜÜÜÛÛÛÛÜÜÜÜÜÜÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÜÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ßßßßßßßßßßßßßßßßÛÛÛÛÛÛÛÛÛÛÛßßßßÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛßßßÜÜÜÜÜÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜÛÛÛ -ÜÜÜÜßßÛÛÛÛÛÛÛßßßÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛßß±±±±±±±ß -ßÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÜÛÛÛß°°°°°ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛݲ²²²²²²²²²² -ÛÛÛÛÛÛÜÜÜßßßßßÛÛÛßßßÛÛÛÛÛÛÛÛÛÛ -Û -ÛÛÛÛÛÛÛÛÛÝ°°°°°°ÞÞÛÛÛÛÛÛßßßßÛÛÛÛÛÛÛÛÜÛÛÛ -ÛÛÛÛÛÛÛÛÛßßßßßÛÛÛÛÛÛÛÛÛÛÝÛÛÛß -ßßÛÛÛÛÛÛÛÛ -ÛÛÛÛÛÛÛÛß°±±±±±±±ßßßÛÛÛÛÛÛÛÛÜÜÛÛÛÛÛÛÛÛ -ÛÛÛ²²²²±±±±±°°°° ßßÛÛÛÛÛÛß²²Û -ÛÛ²ÞÞÛÛÛÛÛÛÛ -ÛÛÛß±±±±±²²²²²²ÛÛÛÛÛÛÜßßÛÛÛÛÛÛÛÛÛÛÛÝ -°°°°°°ÛÛÛÛÛÛ°°°±±±±±²ßßßß -²²ÛÛÛÛ²²²² ÛÛÛÛÛÛÛ -ÛÛÝ°±±±±±²²²²²²ÛÛÛ ÜÜÜÜÛÛÛÛÛÛÛÛÛÛÛÜ -ÜÜÜÜÜÜÜÜÜÜÜÜ ²ÛÛ±±±±°°°°  -ÜßßßÛÛÛ -ßß°°°±±±±²²²²²²ÛÛ²ßßßßßßÛÛÛß -ßÛÛ²±±±±°°°° °°°°± -ßß -°°°°°±±±±²²²²²²²²± Phantasm ù 2O6 --232-5912 Û²±±±±±°°°° - °°°°±±± -°°°°°°°±±±±±±²²²±± SysOp: Sat -anic Animal Slasher  ²±°±±±°°°°  - °°°°±±±± -°°°±±±±±±²²²²²²±±° CoSysOp: D -esolation ù NUP: NEWBIE   -±° ±±±±°°°° °°°°±±± -°°°±±±±±±²²²²²²±°° USR 14.4k DS  -ù 375 Megs Online  ± ±±±±° -°°° °°°°±±± -°°°°±±±±±²²²²²²°Û° CCi/C -TF Nets ù H/P/C/V/A Support -  °±±±±°°°° °°°°±±± -°°°°°±±±±²²²²²²°°± Software: Tel -egard 2.7  °±±±±°°°° °°°°±±±± -°°°°°±±±±²²²²²²°±²ÜÜ°±Û±±± -Ü°°°° °°°°±±± -°°°°°±±±±²²²²²²±²Ûßßßßßßßßßßßßßß -ßßßßßßßßßßßßß ²ÛÛ±Ü -ß±°°°° °°°°±±± -°°°±±±±±±²²²²²²²ÛÛÛÛÛÛÛ²²²²²²±±±±±±±±±°°°°°°  -°°°±±²ÛÛ±ßÜÜÜÜÜÜÜ °°° -°±±± -°°°°°±±±±²²²²²²ÛÛÛÛÛÛÛ²²²²²±±±±°°°° °°°°±±±±²²²²ÛÛÛÛ -²²ß²ß±ß± -°°°°ÛÛÛ °°°°±±±± -°°°°°±±±±²²²²²²ÛÛÛÛÛÛÛ²²²²²±±±±°°°° °°°°±±±±²²²²ÛÛÛ -ÛÜß²²Û±±ßÜ°°°  -°°°°±±±± -°°°°°±±±±²²²²²²ÛÛÛÛÛÛÛ²²²²²±±±±°°°° °°°°±±±±²²²²ÛÛÛÛ -²²²²Û±±±°°°° °°°°±±±± -°°°±±±±±±²²²²²²ÛÛÛÛÛÛÛÛ²²²²²±±±±°°°° °°°°±±±±²²²²ÛÛÛÛ -²²²ß±±±±°°°° °°°°±±± -°°°°°±±±±²²²²²²ÛÛÛÛÛÛÛ²²²²±±±±±°°°° °°°°±±±±²²²²ÛÛÛÛ -²²²²±±±±°°°° °°°°±±±± -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -ÄÄÄÄÄÄÄÄ - i C E P R O D U C T I O N S (tm) Ä N A  -P A L M [ i C E ] Ä o2/o -1/93 -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -ÄÄÄÄÄÄÄÄÄÄ diff --git a/16/PCGPE10/ASM0.TXT b/16/PCGPE10/ASM0.TXT deleted file mode 100644 index 14996d75..00000000 --- a/16/PCGPE10/ASM0.TXT +++ /dev/null @@ -1,193 +0,0 @@ -Text for ASM #0 - - Hello there, this is Draeden typing this wonderful document. This is -an explanation of the basic assembler frame. This document assumes that you -know what hexdecimal is and somewhat how it works, that you have a copy of -TASM and TLINK, that you know what AX is, and how it relates to AL and AH, -and you know the commands: - - MOV xx,xx - JMP xxxx -and INT xx - - I'm also making the rash assumption that you want to learn ASSEMBLER. :) -To assemble ASM0.ASM into an executable do the following: - - TASM ASM0 - TLINK ASM0 - - Now you can exececute this wonderful program. Go ahead. Try it. In -case you are having problems figuring out how to execute this, just type: - - ASM0 (followed by the enter key) - - No, you did nothing wrong. This code (ASM0.ASM) does nothing. All it -does is return control to DOS. It is the basic frame for an assembler -program. All of the programs that I write use this frame. If you want to -know what each part does, read on. If you already know, just go read -ASM1.TXT. - - The number followed by the colon means that this is from ASM0.ASM and -tells which line it is from. - -1: DOSSEG - - DOSSEG Sorts the segment using DOS standard, which is: - - 1) 'code' segments (in alphabetical order) - 2) 'data' segments (in alphabetical order) - 3) 'stack' segments (again, in alphabetical order) - - Although it may not seem clear what this does, don't worry about it. Just -have it as the first line in your assembler programs, until you understand it. - -2: .MODEL SMALL - -MODEL ONLY needs to be used if you use the simplified segments, which I -strongly recommend. - -In a nutshell, .MODEL Selects the MODEL to use. This is used so that this -code can be linked with C, PASCAL, ADA, BASIC, other ASSEMBLER program, and -other languages with ease. It also tells the compiler how to treat your -code and data segments. - -NEAR means that the data/code can be reached using a 16bit pointer (offset) -FAR means that a SEGMENT:OFFSET pair must be used to access all the data/code - -Possible MODELS are: - - TINY: Code and Data must fit in same 64k segment. - Both Code and Data are NEAR. - - SMALL: Code & Data have seperate segment, but must be each less than 64k - Both Code and Data are NEAR. - For most applications, this will suffice. - - MEDIUM: Code may be larger than 64k, but Data has to be less than 64k - Code is FAR, Data is NEAR. - - COMPACT: Code is less than 64k, but Data may be greater than 64k - Code is NEAR, Data is FAR. - - LARGE: Both Code & Data can be greather than 64k. Both are FAR, but a - single array cannot be greater than 64k. Note that max array size - means nothing if you are just writing in assembler. This only - matters when you link to C or another high level language. - - HUGE: Same as LARGE, but arrays can be greater than 64k. - What that means is that the array index is a far pointer, instead - of a NEAR one. - LARGE and HUGE are identicle to the assembler programmer. - -3: .STACK 200h - - Tells the compiler to set up a 200h byte stack upon execution of the -program. NOTE: the size you choose for the stack does not change the size -of the file on disk. You can see what I mean by changing the 200h to, say, -400h and then recompiling. The file sizes are identicle. - - This could be replaced with: - -: MyStack SEGMENT PARA PUBLIC STACK 'STACK' -: db 200h dup (0) -: MyStack ENDS - - BUT, doing it this way makes your executable 512 bytes bigger. If you -were to double to 400h, the executable would be another 512 bytes bigger. -I think it's pretty obvious why the simplified version is preferred. - -4: .DATA - - Simplified, unnamed 'data' segment. This is where those simplified -segments become very handy. If you were to write out the segment declaration -the regular way, you'd have to write something like this: - -: MyData SEGMENT PARA PUBLIC 'DATA' -: -: ... ;your data goes here... -: -: MyData ENDS - -Where 'MyData' is the name of the segment, public means that its, well, -public, and PARA is the alignment of the start of the segment. 'DATA' -specifies the type of the segment. Instead of PARA, WORD or BYTE could -have been used. (PARA = segment will start on an adress that is a multiple -of 16, WORD = even addresses, BYTE = where ever it lands.) - -5: .CODE - - Pretty much the same story as above, but this is for the code segment. -Could be replaced with: - - - IN MASM MODE - -: MyCode SEGMENT PARA PUBLIC 'CODE' -: ... -: MyCode ENDS - - - IN IDEAL MODE - -: SEGMENT MyCode PARA PUBLIC 'CODE' -: ... -: ENDS MyCode ;the 'MyCode' is optional in IDEAL mode - -6: START: - - This is just a label. Labels just provide a way of refencing memory -easily. Like I could say "JMP START" which would jump to the label START and -execute the code immediatly after it. Or I could say MOV AX,[Start], which -would grab the WORD that was immediatly after the label START. - -7: mov ax,4c00h -8: int 21h - - This bit of code calls DOS function # 4ch, which returns control to DOS -and sends back the error level code that is in AL (which is zero). -Note that for all int 21h DOS functions, AH contains the function number. - -THIS MUST BE AT THE END OF THE CODE! If it isn't, the code will continue to -run... right out of the end of your program and will execute whatever code -is there! The program will crash with out it! - -9: END START - -This tells the compiler that we are all done with our program and that it can -stop compiling, now. And it tells the compiler to put the entry point at -the label START. This means that DOS is effectivly starting your program by -executing this: - -: JMP START - - As you would probably guess, if you just put `END' instead of `END START' -and you compiled and linked the program, when you went to execute the code, -the computer will probably freeze because it does not know where to start -execution. - - Ok, now that you know what the frame is/does, lets actually make the -program do something. Lets be wild and crazy, and PRINT A MESSAGE! - - - CONTINUED IN ASM1.TXT - - -ÚÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ ASM0.ASM ³ -ÀÄÄÄÄÄÄÄÄÄÄÙ - - DOSSEG - .MODEL SMALL - .STACK 200h - .DATA - .CODE - -START: - -; -; Your code goes here... -; - - mov ax,4c00h - int 21h -END START - -; THIS CODE DOES ABSOLUTLY NOTHING EXCEPT RETURN CONTROL TO DOS! - - diff --git a/16/PCGPE10/ASM1.TXT b/16/PCGPE10/ASM1.TXT deleted file mode 100644 index a9c2a592..00000000 --- a/16/PCGPE10/ASM1.TXT +++ /dev/null @@ -1,131 +0,0 @@ -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - ASM1.ASM - print a string -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - Well, here's the classic example for the first program in just about -every language. It prints a message to the screen by using a DOS function. -More specifically, it uses function 9 of interrupt 21h. Here's the mock -specification for the function: - -þ- -|IN: ah = 9 ;ah tells INT 21h which function you want -| DS:DX = FAR pointer to the string to be printed. -| ;the string must terminate with a dollar sign ($) -| -|OUT: Prints the string to the screen -þ- - - Other than that function, there's nothing new that can't easily be -figured out. The directive SEG, as you might have guessed, returns the -segment that the specified label is in. OFFSET returns the offset from -the begining of the segment to the specified label. Together, you can -form a FAR pointer to a specified label. - - Another thing you might wonder about is why I put the SEG Message into -AX and THEN Put it in DS. - - The answer is: You have to. An immediate value cannot be put into a -segment register, but a register or an indexed value can. For instance: - -These are legal: - -: mov DS,AX -: mov DS,[TheSegment] - -But these are not: - -: mov DS,50 -: mov DS,0a000h - - One last piece of info: in the lines: - -:Message db "This was printed using function 9 " -: db "of the DOS interrupt 21h.$" - - The DB is just a data type. Its the same as a CHAR in C, which is 1 byte - in length. - - Other common data types are: - - DW same as an INT in C - 2 bytes - DD same as a double int or long int or a FAR pointer - 4 bytes - - - Well, that's pretty much it for this short section... Try playing around -with the 'print' function... Ya learn best by playing with it. - - -One last side note: - I COULD have put the message in the CODE segment instead, by doing this: - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - DOSSEG - .MODEL SMALL - .STACK 200h - .CODE - -Message db "Hey look! I'm in the code segment!$" - -START: - mov ax,cs ;since CS already points to the same segment as Message, - mov ds,ax ;I don't have to explicitly load the segment that message - ;is in.. - - mov dx,offset Message - mov ah,9 - int 21h - - mov ax,4c00h ;Returns control to DOS - int 21h ;MUST be here! Program will crash without it! - -END START - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - The advantage to having all your data in the CODE segment is that DS and -ES can be pointing anywhere and you can still access your data via a segment -override! - - Example: - say I'm in the middle of copying one section of the screen memory to - another and I need to access the variable "NumLines" I'd do it like this: - -ÄÄÄÄÄÄÄÄ - - mov ax,[CS:NumLines] ;this is in IDEAL mode - ^^^ -ÄÄÄÄÄÄÄÄ Code Segment override - - Pretty flexable, eh? - - -ÚÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ ASM1.ASM ³ -ÀÄÄÄÄÄÄÄÄÄÄÙ - - DOSSEG - .MODEL SMALL - .STACK 200h - .DATA - -Message db "This was printed using function 9 " - db "of the DOS interrupt 21h.$" - - .CODE - -START: - mov ax,seg Message ;moves the SEGMENT that `Message' is in into AX - mov ds,ax ;moves ax into ds (ds=ax) - ;you cannot do this -> mov ds,seg Message - - mov dx,offset Message ;move the OFFSET of `Message' into DX - mov ah,9 ;Function 9 of DOS interupt 21h prints a string that - int 21h ;terminates with a "$". It requires a FAR pointer to - ;what is to be printed in DS:DX - - mov ax,4c00h ;Returns control to DOS - int 21h ;MUST be here! Program will crash without it! - -END START - diff --git a/16/PCGPE10/ASM2.TXT b/16/PCGPE10/ASM2.TXT deleted file mode 100644 index b5e124ba..00000000 --- a/16/PCGPE10/ASM2.TXT +++ /dev/null @@ -1,245 +0,0 @@ -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - ASM2.TXT - intro to keyboard and flow control -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - Alright. This bit of code introduces control flow, keyboard input, and - a way to easily print out one character. - -ÄÄÄÄÄÄÄÄ - First off, lets examine the easiest one: printing a character. - - It's like this: you put the character to print in DL, put 2 in AH and - call interrupt 21h. Damn easy. - -ÄÄÄÄÄÄÄÄ - Ok, lets look at the next easiest one: keyboard input. - - There are quite a few functions related to INT 16h (the keyboard - interrupt.) They are: - -FUNCTION# ---------- - - 0h -Gets a key from the keyboard buffer. If there isn't one, it waits - until there is. - Returns the SCAN code in ah, and the ASCII translation in AL - - 1h -Checks to see if a key is ready to grab. Sets the zero flag if a - key is ready to grab. Grab it with Fn# 0 - This also returns the same info about the key as Fn#0, but does - not remove it from the buffer. - - 2h -Returns the shift flags in al. They are: - bit 7 - Insert active - bit 6 - Caps lock active - bit 5 - Num Lock active - bit 4 - Scroll lock active - bit 3 - Alt pressed - bit 2 - Ctrl pressed - bit 1 - Left shift pressed - bit 0 - right shift pressed - - 3h -You can set the Typematic Rate and delay with this function - registers must be set as follows - AL = 5 - BH = Delay value (0-3: 250,500,750,1000 millisec) - BL = Typematic rate (0-1fh) 1fh = slowest (2 chars per sec) - 0 =fastest (30 chars per second) - - 4h -Key Click control - not important - - 5h -STUFF the keyboard - input: - CH = scan code - CL = ascii code - - output: - al = 0 no error - al = 1 keyboard buffer is full - - 10h -Same as #0, but its for the extended keyboard. Checks all the keys. - - 11h -Same as #1, but for the extended keyboard. - - 12h -Same as #2, but AH contains additional shift flags: - bit 7 - Sys req pressed - bit 6 - Caps lock active - bit 5 - Num Lock active - bit 4 - Scroll lock active - bit 3 - Right Alt active - bit 2 - Right Ctrl active - bit 1 - Left Alt active - bit 0 - Right Alt active - Al is EXACTLY the same as in Fn#2 - - -WHERE AH= the function number when you call INT 16h - -ÄÄÄÄÄÄÄÄ - That's neat-o, eh? Now on to flow controll via CMP and Jcc... - -CMP: -ÄÄÄ - CMP is the same as SUB, but it does NOT alter any registers, only the - flags. This is used in conjunction with Jcc. - -Jcc: -ÄÄÄ - Ok, Jcc is not a real instruction, it means 'jump if conditionis met.' - - I'll break this into 3 sections, comparing signed numbers, comparing - unsigned numbers, and misc. - - Note that a number being 'unsigned' or 'signed' only depends on how you - treat it. That's why there are different Jcc for each... - - If you treat it as a signed number, the highest bit denotes whether it's - negative or not. - - Prove to yourself that 0FFFFh is actually -1 by adding 1 to 0FFFFh. You - should get a big zero: 00000h. (Remember that the number is ONLY 16 bits - and the carry dissapears..) - -UNSIGNED: -ÄÄÄÄÄÄÄÄ - JA -jumps if the first number was above the second number - JAE -same as above, but will also jump if they are equal - - JB -jumps if the first number was below the second - JBE -duh... - - JNA -jumps if the first number was NOT above... (same as JBE) - JNAE-jumps if the first number was NOT above or the same as.. - (same as JB) - JNB -jumps if the first number was NOT below... (same as JAE) - JNBE-jumps if the first number was NOT below or the same as.. - (same as JA) - JZ -jumps if the two numbers were equal (zero flag = 1) - JE -same as JZ, just a different name - - JNZ -pretty obvious, I hope... - JNE -same as above... - -SIGNED: -ÄÄÄÄÄÄ - JG -jumps if the first number was > the second number - JGE -same as above, but will also jump if they are equal - - JL -jumps if the first number was < the second - JLE -duh... - - JNG -jumps if the first number was NOT >... (same as JLE) - JNGE-jumps if the first number was NOT >=.. (same as JL) - - JNL -jumps if the first number was NOT <... (same as JGE) - JNLE-jumps if the first number was NOT <=... (same as JG) - - JZ, JE, JNZ, JNE - Same as for Unsigned - -MISC: -ÄÄÄÄ - JC -jumps if the carry flag is set - JNC -Go figgure... - - Here's the rest of them... I've never had to use these, though... - - JO -jump if overflow flag is set - JNO -... - - JP -jump is parity flag is set - JNP -... - JPE -jump if parity even (same as JP) - JPO -jump if parity odd (same as JNP) - - JS -jumps if sign flag is set - JNS -... - - -Here's the flags really quickly: -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -bit# 8 7 6 5 4 3 2 1 0 - ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -symbol: O D I T S Z A P C - - O = OverFlow flag - D = Direction flag * - I = Interrupt flag - T = Trap flag - S = Sign flag - Z = Zero flag * - A = Auxiliary flag - C = Carry flag * - -The * denotes the ones that you should know. - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - -That's it for now... Until next time... - -Draeden\VLA - - -ÚÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ ASM2.ASM ³ -ÀÄÄÄÄÄÄÄÄÄÄÙ - -; ASM2.ASM -; Prints messages get keyboard input and has control flow - - DOSSEG - .MODEL SMALL - .STACK 200h - .DATA - -Prompt db 13,10,"Do you want to be prompted again? (Y/N) $" -NoMessage db 13,10,"Ok, then I won't prompt you anymore.$" -YesMessage db 13,10,"Here comes another prompt!$" -UnKnownKey db 13,10,"Please hit either Y or N.$" - - .CODE - -START: - mov ax,@DATA ;moves the segment of data into ax - mov ds,ax - -MainLoop: - mov ah,9 - mov dx,offset Prompt - int 21h ;print a message - - mov ah,0 - int 16h ;get a key, returned in AX - ;AL is the ASCII part - ;AH is the SCAN CODE - push ax - mov dl,al - mov ah,2 - int 21h ;print character in dl - pop ax - - cmp al,"Y" ;was the character a 'Y'? - jne NotYes ;nope it was Not Equal - - mov ah,9 - mov dx,offset YesMessage - int 21h - jmp MainLoop - -NotYes: - cmp al,"N" ;was the character a 'N' - je ByeBye ;Yes, it was Equal - - mov dx,offset UnknownKey - mov ah,9 - int 21h - jmp MainLoop - -ByeBye: - mov dx,offset NoMessage - mov ah,9 - int 21h - - mov ax,4c00h ;Returns control to DOS - int 21h ;MUST be here! Program will crash without it! - -END START diff --git a/16/PCGPE10/ASM3.TXT b/16/PCGPE10/ASM3.TXT deleted file mode 100644 index ed5bb648..00000000 --- a/16/PCGPE10/ASM3.TXT +++ /dev/null @@ -1,526 +0,0 @@ - - - ASMVLA01 - File I/O - 04/14/93 - - - Lately we have been quite busy with school, so this second issue is a -little behind schedule. But that's life... This little issue will quickly -show off the DOS file functions: read, write, open, close, create & others. -They are all pretty much the same, so there isn't a whole lot to go over. -But, as a bonus, I'm going to throw in a bit about how to do a subroutine. -Let's do the subroutine stuff first. - -`Procedures' as they are called, are declared like this: - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - -PROC TheProcedure - - ... ;do whatever.. - - ret ;MUST have a RET statement! -ENDP TheProcedure - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - In the procedure, you can do basically anything you want, just at the -end of it, you say ret. You can also specify how to call the PROC by putting -a NEAR or FAR after the procedure name. This tells the compiler whether -to change segment AND offset, or just offset when the procedure is called. -Note that if you don't specify, it compiles into whatever the default is for -the current .MODEL (small = near, large = far) - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - -PROC TheProc NEAR - - ... - - ret ;this compiles to `retn' (return near- pops offset off -ENDP TheProc ; stack only) - - OR - -PROC TheProc FAR - - ... - - ret ;compiles to `retf' pops both offset & segment off stack -ENDP TheProc ; pops offset first - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - That's basically all there is to that. Note that if you REALLY wanted to -be tricky, you could do a far jump by doing this: - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - push seg TheProc - push offset TheProc - retf -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - This would "return" you to the beginning of the procedure "TheProc"... -This code is just to illustrate a point. If you actually did something like -this and compiled and executed it, it would bomb. Know why? What happens -when it hits the `ret' in the PROC? Well it pops off the offset and puts -it in IP and then pops the segment and puts it in CS. Who knows what was -on the stack... will return to an unknown address and probably crash. (It -DEFINATELY will not continue executing your code.) - - Of course, the only stack operations are PUSH and POP. All they do is -push or pop off the stack a word sized or a Dword sized piece of data. NEVER -under ANY circumstance try to push a byte sized piece of data! The results -are unpredictable. Well, not really, but just don't do it, ok? - - There are also two commands that'll save you some time and code space: - -PUSHA and POPA (push all and Pop all) - - PUSHA pushes the general registers in this order: - -AX, CX, DX, BX, SP, BP, SI, DI - - POPA pops the general registers in this order: - -DI, SI, BP, (sp), BX, DX, CX, AX - - SP is different because popa does NOT restore the value of SP. It merely -pops it off and throws it away. - - For the 386+, pushad and popad push and pop all extended registers in -the same order. You don't need to memorize the order, because you don't -need to know the order until you go and get tricky. (hint: the location of -AX on the stack is [sp + 14] - useful if you want to change what AX returns, -but you did a pusha cause you wanted to save all the registers (except AX) -Then you'd do a popa, and AX= whatever value you put in there. - - ÄÄÄÄ - - Alright, now a slightly different topic: memory management - - Ok, this isn't true by-the-book memory management, but you need to know -one thing: Upon execution of a program, DOS gives it ALL memory up to the -address A000:0000. This happens to be the beginning of the VGA buffer... -Another thing you must know is that, if you used DOSSEG at the top of your -file, the segment is the last piece of your program. The size of the segment -is derived from the little command `STACK 200h' or whatever the value was -that you put up there. The 200h is the number of bytes in the stack. To get -the number of paragraphs, you'd divide by 16. Here's an example of how I can -get a pointer to the first valid available segment that I can use for data: - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - mov ax,ss ;grab the stack segment - add ax,200h/16 ;add the size of the stack 200h/16 = 20h - - ;AX now contains the value of the first available segment the you can - ; use. -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - This is very nice, because you can just plop your data right there -and you have a 64k buffer you can use for anything you want. - - Ok, say you want to find out how much memory is available to use. This -would be done like this: (no suprises, I hope.) - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - mov ax,ss ;grab the stack segment - add ax,200h/16 ;add the size of the stack 200h/16 = 20h - mov bx,0A000h ;upper limit of the free memory - sub bx,ax ;bx= # of paragraphs available -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - Pretty darn simple. That's enough of the overhead that you must know -to understand the included ANSI viewer (asm3.asm) - - Now to the FILE I/O stuff... - - Files can be opened, read from, written to, created, and closed. To open -a file, all you need to do is give the DOS interrupt a name & path. All -references to that file are done through what's known as a file handle. A -file handle is simply a 16bit integer that DOS uses to identify the file. -It's used more or less like an index into chart of pointers that point to -a big structure that holds all the info about the file- like current position -in the file, file type, etc.. all the data needed to maintain a file. -The `FILES= 20' thing in your autoexec simply tells DOS how much memory to -grab for those structures. ( Files=20 grabs enough room for 20 open files. ) - - ANYway, here's each of the important function calls and a rundown on what -they do and how to work them. - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -FILE OPEN: Function 3Dh - - IN: - ah= 3Dh - al= open mode - - bits 7-3: Stuff that doesn't matter to us - bits 2-0: Access code - 000 read only access - 001 write only access - 010 read and write access - - DS:DX= pointer to the ASCIIZ filename - ASCIIZ means that its an ASCII string with a Zero on the end. - - Returns: - CF=1 error occured - AX= error code- don't worry about what they are, if the carry - is set, you didn't open the file. - - CF=0 no error - AX= File Handle ;you need to keep this- it's your only way to - ; reference your file! - - ÄÄÄÄ EXAMPLE ÄÄÄÄ - - [...] ;header stuff - - .CODE ;this stuff is used for all the examples - - FileName db "TextFile.TXT",0 - FileHandle dw 0 - Buffer db 300 dup (0) - BytesRead dw 0 - FileSize dd 0 - - [...] ;more stuff - - mov ax,3d00h ; open file for read only - mov ax,cs - mov ds,ax ;we use CS, cause it's pointing to the CODE segment - ; and our file name is in the code segment - mov dx,offset FileName - int 21h - jc FileError_Open - - mov [FileHandle],ax - - [...] ;etc... - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -FILE CLOSE: Function 3Eh - - IN: - AH= 3Eh - BX= File Handle - - RETURN: - CF=1 error occured, but who cares? - - ÄÄÄÄ EXAMPLE ÄÄÄÄ - - mov bx,[FileHandle] - mov ah,3eh - int 21h - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -FILE READ: Function 3Fh - - IN: - AH= 3Fh - BX= File Handle - CX= Number of bytes to read - DS:DX= where to put data that is read from the file (in memory) - - RETURN: - AX= number of bytes actually read- if 0, then you tried to read from - the end of the file. - - ÄÄÄÄ EXAMPLE ÄÄÄÄ - - mov bx,[FileHandle] - mov ax,cs - mov ds,ax - mov dx,offset buffer - mov ah,3Fh - mov cx,300 - int 21h - - mov [BytesRead],ax - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -FILE WRITE: Function 40h - - IN: - AH= 40h - BX= File Handle - CX= Number of bytes to write - DS:DX= where to read data from (in memory) to put on disk - - RETURN: - AX= number of bytes actually written- if not equal to the number of bytes - that you wanted to write, you have an error. - - ÄÄÄÄ EXAMPLE ÄÄÄÄ - - mov bx,[FileHandle] - mov ax,cs - mov ds,ax - mov dx,offset buffer - mov ah,40h - mov cx,[BytesRead] - int 21h - - cmp cx,ax - jne FileError_Write - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -FILE CREATE: Function 3Ch - - IN: - ah= 3Ch - cl= file attribute - - bit 0: read-only - bit 1: hidden - bit 2: system - bit 3: volume label - bit 4: sub directory - bit 5: Archive - bit 6&7: reserved - - DS:DX= pointer to the ASCIIZ filename - ASCIIZ means that its an ASCII string with a Zero on the end. - - Returns: - CF=1 error occured - AX= error code- don't worry about what they are, if CF - is set, you didn't create the file. - - CF=0 no error - AX= File Handle ;you need to keep this- it's your only way to - ; reference your file! - ÄÄÄÄ EXAMPLE ÄÄÄÄ - - mov ah,3ch - mov ax,cs - mov ds,ax ;we use CS, cause it's pointing to the CODE segment - ; and our file name is in the code segment - mov dx,offset FileName - mov cx,0 ;no attributes - int 21h - jc FileError_Create - - mov [FileHandle],ax - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -FILE DELETE: Function 41h - - IN: - ah= 41h - DS:DX= pointer to the ASCIIZ filename - - Returns: - CF=1 error occured - AX= error code- 2= file not found, 3= path not found - 5= access denied - - CF=0 no error - - ÄÄÄÄ EXAMPLE ÄÄÄÄ - - mov ah,41h ;kill the sucker - mov ax,cs - mov ds,ax - mov dx,offset FileName - int 21h - jc FileError_Delete - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -FILE MOVE POINTER: Function 42h - - IN: - ah= 42h - BX= File Handle - CX:DX= 32 bit pointer to location in file to move to - AL= 0 offset from beginning of file - = 1 offset from curent position - = 2 offset from the end of the file - - Returns: - CF=1 error occured - AX= error code- no move occured - - CF=0 no error - DX:AX 32 bit pointer to indicate current location in file - - ÄÄÄÄ EXAMPLE ÄÄÄÄ - - mov ah,42h ;find out the size of the file - mov bx,[FileHandle] - xor cx,cx - xor dx,dx - mov al,2 - int 21h - - mov [word low FileSize],ax - mov [word high FileSize],dx ;load data into filesize - - (or in MASM mode, - - mov word ptr [FileSize],ax - mov word ptr [FileSize+2],dx - - need I say why I like Ideal mode? ) - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -FILE CHANGE MODE: Function 43h - - IN: - ah= 43h - DS:DX= pointer to the ASCIIZ filename - al= 0 - returns file attributes in CX - al= 1 - sets file attributes to what's in CX - - Returns: - CF=1 error occured - AX= error code- 2= file not found, 3= path not found. - 5= access denied - - CF=0 no error - - ÄÄÄÄ EXAMPLE ÄÄÄÄ Lets erase a hidden file in your root directory... - - FileName db "C:\msdos.sys",0 - - [...] - - mov ah,43h ;change attribute to that of a normal file - mov ax,cs - mov ds,ax - mov dx,offset FileName - mov al,1 ;set to whats in CX - mov cx,0 ;attribute = 0 - int 21h - - mov ah,41h ;Nuke it with the delete command - int 21h - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - Well, that's all for now. I hope this info is enough for you to do some -SERIOUS damage... :) I just don't want to see any 'bombs' running around -erasing the hidden files in the root directory, ok? - - Anyway, go take a look at asm3.asm- it's a SIMPLE ansi/text displayer. -It just opens the file, reads it all into a "buffer" that was "allocated" -immediatly after the stack & reads in the entire file (if it's < 64k) and -prints out the file character by character via DOS's print char (fn# 2). -Very simple and very slow. You'd need a better print routine to go faster... -The quickest display programs would decode the ANSI on its own... But that's -kinda a chore... Oh, well. Enjoy. - - Draeden/VLA - - - Suggested projects: - - 1) Write a program that will try to open a file, but if it does not - find it, the program creates the file and fills it with a simple - text message. - - 2) Write a program that will input your keystrokes and write them - directly to a text file. - - 3) The write & read routines actually can be used for a file or device. - Try to figure out what the FileHandle for the text screen is by - writing to the device with various file handles. This same channel, - when read from, takes it's data from the keyboard. Try to read data - from the keyboard. Maybe read like 20 characters... CTRL-Z is the - end of file marker. - - 4) Try to use a file as `virtual memory'- open it for read/write access - and write stuff to it and then read it back again after moving the - cursor position. - - - -ÚÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ ASM3.ASM ³ -ÀÄÄÄÄÄÄÄÄÄÄÙ - -; VERY, VERY simple ANSI/text viewer -; -; Coded by Draeden [VLA] -; - - DOSSEG - .MODEL SMALL - .STACK 200h - .CODE - Ideal - -;===- Data -=== - -BufferSeg dw 0 - -ErrMsgOpen db "Error opening `" -FileName db "ANSI.TXT",0,8,"'$" ;8 is a delete character - ;0 is required for filename - ;(displays a space) -FileLength dw 0 - -;===- Subroutines -=== - -PROC DisplayFile NEAR - push ds - - mov ax,cs - mov ds,ax - mov ax,3d00h ;open file (ah=3dh) - mov dx,offset FileName - int 21h - jc OpenError - mov bx,ax ;move the file handle into bx - - mov ds,[BufferSeg] - mov dx,0 ;load to [BufferSeg]:0000 - mov ah,3fh - mov cx,0FFFFh ;try to read an entire segments worth - int 21h - - mov [cs:FileLength],ax - - mov ah,3eh - int 21h ;close the file - - cld - mov si,0 - mov cx,[cs:FileLength] -PrintLoop: - mov ah,2 - lodsb - mov dl,al - int 21h ;print a character - - dec cx - jne PrintLoop - - pop ds - ret - -OpenError: - mov ah,9 - mov dx,offset ErrMsgOpen - int 21h - - pop ds - ret -ENDP DisplayFile - -;===- Main Program -=== - -START: - mov ax,cs - mov ds,ax - mov bx,ss - add bx,200h/10h ;get past the end of the file - mov [BufferSeg],bx ;store the buffer segment - - call DisplayFile - - mov ax,4c00h - int 21h -END START - diff --git a/16/PCGPE10/ASMINTRO.TXT b/16/PCGPE10/ASMINTRO.TXT deleted file mode 100644 index d12429ed..00000000 --- a/16/PCGPE10/ASMINTRO.TXT +++ /dev/null @@ -1,626 +0,0 @@ - - ÖÄÄÄÄÄÄÄÄÄÄ´% VLA Presents: Intro to Assembler %ÃÄÄÄÄÄÄÄÄÄÄ· - º º - ÓÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄĽ - - - - ¯ Dedicated To Those Who Wish To Begin Exploring The Art Of Assembler. ® - - - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ  VLA Members Are  ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - (© Draeden - Main Coder ª) - (© The Priest - Coder/ Artist ª) - (© Lithium - Coder/Ideas/Ray Tracing ª) - (© The Kabal - Coder/Ideas/Artwork ª) - (© Desolation - Artwork/Ideas ª) - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ The Finn - Mods/Sounds ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - - ÖÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ͵ Contact Us On These Boards ÆÍÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ· - º º - ³ % Phantasm BBS .................................. (206) 232-5912 ³ - ³ * The Deep ...................................... (305) 888-7724 ³ - ³ * Dark Tanget Systems ........................... (206) 722-7357 ³ - ³ * Metro Holografix .............................. (619) 277-9016 ³ - ³ ³ - º % - World Head Quarters * - Distribution Site º - ÓÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄĽ - - Or Via Internet Mail For The Group: tkabal@carson.u.washington.edu - - Or to reach the other members: - - - draeden@u.washington.edu - - - - lithium@u.washington.edu - - - - desolation@u.washington.edu- - - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - VLA 3/93 Introduction to ASSEMBLER -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - -Here's something to help those of you who were having trouble understanding -the instructional programs we released. Dreaden made these files for the -Kabal and myself when we were just learning. These files go over some of -the basic concepts of assembler. Bonus of bonuses. These files also have -programs imbedded in them. Most of them have a ton of comments so even -the beginning programmers should be able to figure them out. - -If you'd like to learn more, post a message on Phantasm. We need to know -where you're interests are before we can make more files to bring out the -little programmers that are hiding inside all of us. - - Lithium/VLA - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - First thing ya need to know is a little jargon so you can talk about -the basic data structures with your friends and neighbors. They are (in -order of increasing size) BIT, NIBBLE, BYTE, WORD, DWORD, FWORD, PWORD and -QWORD, PARA, KiloByte, MegaByte. The ones that you'll need to memorize are -BYTE, WORD, DWORD, KiloByte, and MegaByte. The others aren't used all that -much, and you wont need to know them to get started. Here's a little -graphical representation of a few of those data structures: - -(The zeros in between the || is a graphical representation of the number of -bits in that data structure.) - -ÄÄÄÄÄÄ -1 BIT : |0| - - The simplest piece of data that exists. Its either a 1 or a zero. - Put a string of them together and you have a BASE-2 number system. - Meaning that instead of each 'decimal' place being worth 10, its only - worth 2. For instance: 00000001 = 1; 00000010 = 2; 00000011 = 3, etc.. - -ÄÄÄÄÄÄ -1 NIBBLE: |0000| -4 BITs - - The NIBBLE is half a BYTE or four BITS. Note that it has a maximum value - of 15 (1111 = 15). Not by coincidence, HEXADECIMAL, a base 16 number - system (computers are based on this number system) also has a maximum - value of 15, which is represented by the letter 'F'. The 'digits' in - HEXADECIMAL are (in increasing order): - - "0123456789ABCDEF" - - The standard notation for HEXADECIMAL is a zero followed by the number - in HEX followed by a lowercase "h" For instance: "0FFh" = 255 DECIMAL. - -ÄÄÄÄÄÄ -1 BYTE |00000000| -2 NIBBLEs ÀÄ AL ÄÙ -8 BITs - - The BYTE is the standard chunk of information. If you asked how much - memory a machine had, you'd get a response stating the number of BYTEs it - had. (Usually preceded by a 'Mega' prefix). The BYTE is 8 BITs or - 2 NIBBLEs. A BYTE has a maximum value of 0FFh (= 255 DECIMAL). Notice - that because a BYTE is just 2 NIBBLES, the HEXADECIMAL representation is - simply two HEX digits in a row (ie. 013h, 020h, 0AEh, etc..) - - The BYTE is also that size of the 'BYTE sized' registers - AL, AH, BL, BH, - CL, CH, DL, DH. - -ÄÄÄÄÄÄ -1 WORD |0000000000000000| -2 BYTEs ÀÄ AH ÄÙÀÄ AL ÄÙ -4 NIBBLEs ÀÄÄÄÄÄ AX ÄÄÄÄÄÙ -16 BITs - - The WORD is just two BYTEs that are stuck together. A word has a maximum - value of 0FFFFh (= 65,535). Since a WORD is 4 NIBBLEs, it is represented - by 4 HEX digits. This is the size of the 16bit registers on the 80x86 - chips. The registers are: AX, BX, CX, DX, DI, SI, BP, SP, CS, DS, ES, SS, - and IP. Note that you cannot directly change the contents of IP or CS in - any way. They can only be changed by JMP, CALL, or RET. - -ÄÄÄÄÄÄ -1 DWORD -2 WORDs |00000000000000000000000000000000| -4 BYTEs ³ ÀÄ AH ÄÙÀÄ AL ÄÙ -8 NIBBLEs ³ ÀÄÄÄÄÄ AX ÄÄÄÄÄÙ -32 BITs ÀÄÄÄÄÄÄÄÄÄÄÄÄ EAX ÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - A DWORD (or "DOUBLE WORD") is just two WORDs, hence the name DOUBLE-WORD. - This can have a maximum value of 0FFFFFFFFh (8 NIBBLEs, 8 'F's) which - equals 4,294,967,295. Damn large. This is also the size or the 386's - 32bit registers: EAX, EBX, ECX, EDX, EDI, ESI, EBP, ESP, EIP. The 'E ' - denotes that they are EXTENDED registers. The lower 16bits is where the - normal 16bit register of the same name is located. (See diagram.) - -ÄÄÄÄÄÄ -1 KILOBYTE |-lots of zeros (8192 of 'em)-| -256 DWORDs -512 WORDs -1024 BYTEs -2048 NIBBLEs -8192 BITs - - We've all heard the term KILOBYTE byte, before, so I'll just point out - that a KILOBYTE, despite its name, is -NOT- 1000 BYTEs. It is actually - 1024 bytes. - -ÄÄÄÄÄÄ - 1 MEGABYTE |-even more zeros (8,388,608 of 'em)-| - 1,024 KILOBYTEs - 262,144 DWORDs - 524,288 WORDs - 1,048,576 BYTEs - 2,097,152 NIBBLEs - 8,388,608 BITs - - Just like the KILOBYTE, the MEGABYTE is -NOT- 1 million bytes. It is - actually 1024*1024 BYTEs, or 1,048,578 BYTEs - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - Now that we know what the different data types are, we will investigate - an annoying little aspect of the 80x86 processors. I'm talking about - nothing other than SEGMENTS & OFFSETS! - - -SEGMENTS & OFFSETS: -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - Pay close attention, because this topic is (I believe) the single most - difficult (or annoying, once you understand it) aspect of ASSEMBLER. - -An OverView: - - The original designers of the 8088, way back when dinasaurs ruled the - planet, decided that no one would ever possibly need more than one MEG - (short for MEGABYTE :) of memory. So they built the machine so that it - couldn't access above 1 MEG. To access the whole MEG, 20 BITs are needed. - Problem was that the registers only had 16 bits, and if the used two - registers, that would be 32 bits, which was way too much (they thought.) - So they came up with a rather brilliant (blah) way to do their addressing- - they would use two registers. They decided that they would not be 32bits, - but the two registers would create 20 bit addressing. And thus Segments - and OFfsets were born. And now the confusing specifics. - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - -OFFSET = SEGMENT*16 -SEGMENT = OFFSET /16 ;note that the lower 4 bits are lost - - -SEGMENT * 16 |0010010000010000----| range (0 to 65535) * 16 - + -OFFSET |----0100100000100010| range (0 to 65535) - = -20 bit address |00101000100100100010| range 0 to 1048575 (1 MEG) - ÀÄÄÄÄÄ DS ÄÄÄÄÄÙ - ÀÄÄÄÄÄ SI ÄÄÄÄÄÙ - ÀÄ OverlapÄÙ - - This shows how DS:SI is used to construct a 20 bit address. - -Segment registers are: CS, DS, ES, SS. On the 386+ there are also FS & GS - -Offset registers are: BX, DI, SI, BP, SP, IP. In 386+ protected mode, ANY - general register (not a segment register) can be used as an Offset - register. (Except IP, which you can't access.) - - CS:IP => Points to the currently executing code. - SS:SP => Points to the current stack position. - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - If you'll notice, the value in the SEGMENT register is multiplied by - 16 (or shifted left 4 bits) and then added to the OFFSET register. - Together they create a 20 bit address. Also Note that there are MANY - combinations of the SEGMENT and OFFSET registers that will produce the - same address. The standard notation for a SEGment/OFFset pair is: - -ÄÄÄÄ -SEGMENT:OFFSET or A000:0000 ( which is, of course in HEX ) - - Where SEGMENT = 0A000h and OFFSET = 00000h. (This happens to be the - address of the upper left pixel on a 320x200x256 screen.) -ÄÄÄÄ - - You may be wondering what would happen if you were to have a segment - value of 0FFFFh and an offset value of 0FFFFh. - - Take notice: 0FFFFh * 16 (or 0FFFF0h ) + 0FFFFh = 1,114,095, which is - definately larger than 1 MEG (which is 1,048,576.) - - This means that you can actually access MORE than 1 meg of memory! - Well, to actually use that extra bit of memory, you would have to enable - something called the A20 line, which just enables the 21st bit for - addressing. This little extra bit of memory is usually called - "HIGH MEMORY" and is used when you load something into high memory or - say DOS = HIGH in your AUTOEXEC.BAT file. (HIMEM.SYS actually puts it up - there..) You don't need to know that last bit, but hey, knowledge is - good, right? - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - THE REGISTERS: -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - I've mentioned AX, AL, and AH before, and you're probably wondering what - exactly they are. Well, I'm gonna go through one by one and explain - what each register is and what it's most common uses are. Here goes: - -ÄÄÄÄ -AX (AH/AL): - AX is a 16 bit register which, as metioned before, is merely two bytes - attached together. Well, for AX, BX, CX, & DX you can independantly - access each part of the 16 bit register through the 8bit (or byte sized) - registers. For AX, they are AL and AH, which are the Low and High parts - of AX, respectivly. It should be noted that any change to AL or AH, - will change AX. Similairly any changes to AX may or may not change AL and - AH. For instance: - -ÄÄÄÄÄÄÄÄ -Let's suppose that AX = 00000h (AH and AL both = 0, too) - - mov AX,0 - mov AL,0 - mov AH,0 - -Now we set AL = 0FFh. - - mov AL,0FFh - -:AX => 000FFh ;I'm just showing ya what's in the registers -:AL => 0FFh -:AH => 000h - -Now we increase AX by one: - - INC AX - -:AX => 00100h (= 256.. 255+1= 256) -:AL => 000h (Notice that the change to AX changed AL and AH) -:AH => 001h - -Now we set AH = 0ABh (=171) - - mov AH,0ABh - -:AX => 0AB00h -:AL => 000h -:AH => 0ABh - -Notice that the first example was just redundant... -We could've set AX = 0 by just doing - - mov ax,0 - -:AX => 00000h -:AL => 000h -:AH => 000h - -I think ya got the idea... -ÄÄÄÄÄÄÄÄ - - SPECIAL USES OF AX: - Used as the destination of an IN (in port) - ex: IN AL,DX - IN AX,DX - - Source for the output for an OUT - ex: OUT DX,AL - OUT DX,AX - - Destination for LODS (grabs byte/word from [DS:SI] and INCreses SI) - ex: lodsb (same as: mov al,[ds:si] ; inc si ) - lodsw (same as: mov ax,[ds:si] ; inc si ; inc si ) - - Source for STOS (puts AX/AL into [ES:DI] and INCreses DI) - ex: stosb (same as: mov [es:di],al ; inc di ) - stosw (same as: mov [es:di],ax ; inc di ; inc di ) - - Used for MUL, IMUL, DIV, IDIV -ÄÄÄÄ -BX (BH/BL): same as AX (BH/BL) - - SPECIAL USES: - As mentioned before, BX can be used as an OFFSET register. - ex: mov ax,[ds:bx] (grabs the WORD at the address created by - DS and BX) - -CX (CH/CL): Same as AX - - SPECIAL USES: - Used in REP prefix to repeat an instruction CX number of times - ex: mov cx,10 - mov ax,0 - rep stosb ;this would write 10 zeros to [ES:DI] and increase - ;DI by 10. - Used in LOOP - ex: mov cx,100 - THELABEL: - - ;do something that would print out 'HI' - - loop THELABEL ;this would print out 'HI' 100 times - ;the loop is the same as: dec cx - jne THELABAL - -DX (DH/DL): Same as above - SPECIAL USES: - USED in word sized MUL, DIV, IMUL, IDIV as DEST for high word - or remainder - - ex: mov bx,10 - mov ax,5 - mul bx ;this multiplies BX by AX and puts the result - ;in DX:AX - - ex: (continue from above) - div bx ;this divides DX:AX by BX and put the result in AX and - ;the remainder (in this case zero) in DX - - Used as address holder for IN's, and OUT's (see ax's examples) - -INDEX REGISTERS: - - DI: Used as destination address holder for stos, movs (see ax's examples) - Also can be used as an OFFSET register - - SI: Used as source address holder for lods, movs (see ax's examples) - Also can be used as OFFSET register - - Example of MOVS: - movsb ;moves whats at [DS:SI] into [ES:DI] and increases - movsw ; DI and SI by one for movsb and 2 for movsw - - NOTE: Up to here we have assumed that the DIRECTION flag was cleared. - If the direction flag was set, the DI & SI would be DECREASED - instead of INCREASED. - ex: cld ;clears direction flag - std ;sets direction flag - -STACK RELATED INDEX REGISTERS: - BP: Base Pointer. Can be used to access the stack. Default segment is - SS. Can be used to access data in other segments throught the use - of a SEGMENT OVERRIDE. - - ex: mov al,[ES:BP] ;moves a byte from segment ES, offset BP - Segment overrides are used to specify WHICH of the 4 (or 6 on the - 386) segment registers to use. - - SP: Stack Pointer. Does just that. Segment overrides don't work on this - guy. Points to the current position in the stack. Don't alter unless - you REALLY know what you are doing. - -SEGMENT REGISTERS: - DS: Data segment- all data read are from the segment pointed to be this - segment register unless a segment overide is used. - Used as source segment for movs, lods - This segment also can be thought of as the "Default Segment" because - if no segment override is present, DS is assumed to be the segmnet - you want to grab the data from. - - ES: Extra Segment- this segment is used as the destination segment - for movs, stos - Can be used as just another segment... You need to specify [ES:°°] - to use this segment. - - FS: (386+) No particular reason for it's name... I mean, we have CS, DS, - and ES, why not make the next one FS? :) Just another segment.. - - GS: (386+) Same as FS - - -OTHERS THAT YOU SHOULDN'T OR CAN'T CHANGE: - CS: Segment that points to the next instruction- can't change directly - IP: Offset pointer to the next instruction- can't even access - The only was to change CS or IP would be through a JMP, CALL, or RET - - SS: Stack segment- don't mess with it unless you know what you're - doing. Changing this will probably crash the computer. This is the - segment that the STACK resides in. - -ÄÄÄÄÄÄÄÄ -Heck, as long as I've mentioned it, lets look at the STACK: - - The STACK is an area of memory that has the properties of a STACK of - plates- the last one you put on is the first one take off. The only - difference is that the stack of plates is on the roof. (Ok, so that - can't really happen... unless gravity was shut down...) Meaning that - as you put another plate (or piece of data) on the stack, the STACK grows - DOWNWARD. Meaning that the stack pointer is DECREASED after each PUSH, - and INCREASED after each POP. - - _____ Top of the allocated memory in the stack segment (SS) - þ - þ - þ - þ ® SP (the stack pointer points to the most recently pushed byte) - - Truthfully, you don't need to know much more than a stack is Last In, - First Out (LIFO). - - WRONG ex: push cx ;this swaps the contents of CX and AX - push ax ;of course, if you wanted to do this quicker, you'd - ... - pop cx ;just say XCHG cx,ax - pop ax ; but thats not my point. - - RIGHT ex: push cx ;this correctly restores AX & CX - push ax - ... - pop ax - pop cx - -ÄÄÄÄÄÄÄÄÄÄÄÄ - -Now I'll do a quick run through on the assembler instructions that you MUST -know: - -ÄÄÄÄ -MOV: - - Examples of different addressing modes: - - MOV ax,5 ;moves and IMMEDIATE value into ax (think 'AX = 5') - MOV bx,cx ;moves a register into another register - MOV cx,[SI] ;moves [DS:SI] into cx (the Default Segment is Used) - MOV [DI+5],ax ;moves ax into [DS:DI+5] - MOV [ES:DI+BX+34],al ;same as above, but has a more complicated - ;OFFSET (=DI+BX+34) and a SEGMENT OVERRIDE - MOV ax,[546] ;moves whats at [DS:546] into AX - - Note that the last example would be totally different if the brackets - were left out. It would mean that an IMMEDIATE value of 546 is put into - AX, instead of what's at offset 546 in the Default Segment. - -ANOTHER STANDARD NOTATION TO KNOW: - Whenever you see brackets [] around something, it means that it refers to - what is AT that offset. For instance, say you had this situation: - -ÄÄÄÄÄÄÄÄÄÄÄÄ -MyData dw 55 - ... - mov ax,MyData -ÄÄÄÄÄÄÄÄÄÄÄÄ - - What is that supposed to mean? Is MyData an Immediate Value? This is - confusing and for our purposes WRONG. The 'Correct' way to do this would - be: - -ÄÄÄÄÄÄÄÄÄÄÄÄ -MyData dw 55 - ... - mov ax,[MyData] -ÄÄÄÄÄÄÄÄÄÄÄÄ - - This is clearly moving what is AT the address of MyData, which would be - 55, and not moving the OFFSET of MyData itself. But what if you - actually wanted the OFFSET? Well, you must specify directly. - -ÄÄÄÄÄÄÄÄÄÄÄÄ -MyData dw 55 - ... - mov ax,OFFSET MyData -ÄÄÄÄÄÄÄÄÄÄÄÄ - - Similiarly, if you wanted the SEGMENT that MyData was in, you'd do this: - -ÄÄÄÄÄÄÄÄÄÄÄÄ -MyData dw 55 - ... - mov ax,SEG MyData -ÄÄÄÄÄÄÄÄÄÄÄÄ - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -INT: - Examples: - INT 21h ;calls DOS standard interrupt # 21h - INT 10h ;the Video BIOS interrupt.. - - INT is used to call a subroutine that performs some function that you'd - rather not write yourself. For instance, you would use a DOS interrupt - to OPEN a file. You would similiarly use the Video BIOS interrupt to - set the screen mode, move the cursor, or to do any other function that - would be difficult to program. - - Which subroutine the interrupt preforms is USUALLY specified by AH. - For instance, if you wanted to print a message to the screen you'd - use INT 21h, subfunction 9 by doing this: - -ÄÄÄÄÄÄÄÄÄÄÄÄ - mov ah,9 - int 21h -ÄÄÄÄÄÄÄÄÄÄÄÄ - - Yes, it's that easy. Of course, for that function to do anything, you - need to specify WHAT to print. That function requires that you have - DS:DX be a FAR pointer that points to the string to display. This string - must terminate with a dollar sign. Here's an example: - -ÄÄÄÄÄÄÄÄÄÄÄÄ -MyMessage db "This is a message!$" - ... - mov dx,OFFSET MyMessage - mov ax,SEG MyMessage - mov ds,ax - mov ah,9 - int 21h - ... -ÄÄÄÄÄÄÄÄÄÄÄÄ - - The DB, like the DW (and DD) merely declares the type of a piece of data. - - DB => Declare Byte (I think of it as 'Data Byte') - DW => Declare Word - DD => Declare Dword - - Also, you may have noticed that I first put the segment value into AX - and then put it into DS. I did that because the 80x86 does NOT allow - you to put an immediate value into a segment register. You can, however, - pop stuff into a Segment register or mov an indexed value into the - segment register. A few examples: - -ÄÄÄÄÄÄÄÄÄÄÄÄ - LEGAL: - mov ax,SEG MyMessage - mov ds,ax - - push SEG Message - pop ds - - mov ds,[SegOfMyMessage] - ;where [SegOfMyMessage] has already been loaded with - ; the SEGMENT that MyMessage resides in - ILLEGAL: - mov ds,10 - mov ds,SEG MyMessage -ÄÄÄÄÄÄÄÄÄÄÄÄ - -Well, that's about it for what you need to know to get started... - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - And now the FRAME for an ASSEMBLER program. -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - -The Basic Frame for an Assembler program using Turbo Assembler simplified - directives is: - -;===========- - - DOSSEG ;This arranges the segments in order according DOS standards - ;CODE, DATA, STACK - .MODEL SMALL ;dont worry about this yet - .STACK 200h ;tells the compiler to put in a 200h byte stack - .CODE ;starts code segment - - ASSUME CS:@CODE, DS:@CODE - -START: ;generally a good name to use as an entry point - - mov ax,4c00h - int 21h - -END START - -;===========- By the way, a semicolon means the start of a comment. - - If you were to enter this program and TASM & TLINK it, it would execute - perfectly. It will do absolutly nothing, but it will do it well. - - What it does: - Upon execution, it will jump to START. move 4c00h into AX, - and call the DOS interrupt, which exits back to DOS. - - Outout seen: NONE -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - -That's nice, eh? If you've understood the majority of what was presented -in this document, you are ready to start programming! - -See ASM0.TXT and ASM0.ASM to continue this wonderful assembler stuff... - - -Written By Draeden/VLA - diff --git a/16/PCGPE10/ATI.TXT b/16/PCGPE10/ATI.TXT deleted file mode 100644 index 6fd299a8..00000000 --- a/16/PCGPE10/ATI.TXT +++ /dev/null @@ -1,158 +0,0 @@ - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Programming the ATI Technologies SVGA Chip ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - Written for the PC-GPE by Mark Feldman - e-mail address : u914097@student.canberra.edu.au - myndale@cairo.anu.edu.au - - Please read the file SVGINTRO.TXT - (Graphics/SVGA/Intro PC-GPE menu option) - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ THIS FILE MAY NOT BE DISTRIBUTED ³ - ³ SEPARATE TO THE ENTIRE PC-GPE COLLECTION. ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Disclaimer ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ - -I assume no responsibility whatsoever for any effect that this file, the -information contained therein or the use thereof has on you, your sanity, -computer, spouse, children, pets or anything else related to you or your -existance. No warranty is provided nor implied with this information. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Locating the Extended Register Set ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The ATI extended register set is based on the vga's index register scheme, -ie you write the value of the register you want to modify to Index Register -Port and write the actual data to the Data Port (the Data Port is one port -number higher than the Index Register Port). The value of the Index Register -for the ATI extended register set is stored in a word in BIOS ROM at -C000:0010. Apparently ATI want to change the value of this register in -future so they recommend you obtain it by reading the value at this memory -address. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Identifying the ATI Chip ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The ATI chip can be identified by checking the string in memory locations -C000:0031-003A for the following characters : 761295520 - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Identifying which ATI Chip ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The first version of the ATI chip is the 18800. The second version is the -28800, which from a programming perspective is identical to the 18800-2. -The 18800 can be identified by it's lack of support for display mode -55h. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Determining the ATI Chip Revision Number ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The ATI chip revision number is stored at BIOS location C000:0043. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ ATI Graphics Display Modes ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Mode Resolution Colors Chip ³ - ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ - ³ 53h 800x600 16 18800 ³ - ³ 54h 800x600 16 18800 ³ - ³ 55h 1024x768 16 (planar) 18800-1 ³ - ³ 61h 640x400 256 18800 ³ - ³ 62h 640x480 256 18800 ³ - ³ 63h 800x600 256 18800 ³ - ³ 65h 1024x768 256 (packed) 18800 ³ - ³ 67h 1024x768 4 ? ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ ATI Display Memory ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -In the following examples the EXT variable is the extended register index -value obtained from reading the word at C000:0010. - -The ATI supports both single and duel bank memory mapping. It supports 64K -byte pages, each of these can be mapped into the host address space. - - - -Single or duel bank mode is selected by the E2B bit in register BE - - Index : BEh at port EXT - Read/Write at port EXT + 1 - ÚÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄ¿ - ³ 7 ³ 6 ³ 5 ³ 4 ³ 3 ³ 2 ³ 1 ³ 0 ³ - ÀÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÙ - ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄ E2B 0 = Single Bank Mode - 1 = Duel Bank Mode - -Selecting a bank to write to in single bank mode is done by writing the bank -number to the Bank Select Register : - - Index : B2h - ÚÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄ¿ - ³ 7 ³ 6 ³ 5 ³ 4 ³ 3 ³ 2 ³ 1 ³ 0 ³ - ÀÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÙ - ÀÄÄÄÄÄÂÄÄÄÄÄÙ - Bank number - -The following procedure will select a bank in single bank mode : - -Port[EXT] := $B2; -Port[EXT + 1] := (Port[EXT + 1] And $E1) Or (bank_number shl 1); - -where bank_number = 0 - 15. Each bank is 64K long and has a 64K -granularity. - -Duel Bank Mode is only supported on the 18800-1 and 28800 chips. You can -map one bank to A000:0000-FFFF for read operations and another to the -same address space for write operations. - - Index : B2h - ÚÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄ¿ - ³ 7 ³ 6 ³ 5 ³ 4 ³ 3 ³ 2 ³ 1 ³ 0 ³ - ÀÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÙ - ÀÄÄÄÂÄÄÄÙ ÀÄÄÄÂÄÄÄÙ - Read Write - Bank Bank - Number Number - -The following code will set the write bank number: - -Port[EXT] := $B2; -Port[EXT + 1] := (Port[EXT + 1] And $F0) Or (write_bank_number shl 1); - -The following code will set the read bank number: - -Port[EXT] := $B2; -Port[EXT + 1] := (Port[EXT + 1] And $0F) Or (read_bank_number shl 5); - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ ATI IsModeAvailable BIOS Call ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Int 10h -Inputs : - AH = 12h Extended VGA Control - BX = 5506h Get Mode Information - BP = FFFF Set up for Return Argument - AL = Mode Number Mode number you want to test - -Returns: -BP = FFFFh Mode not supported - Anything else : mode is supported, BP = offset into CRTC table for mode - diff --git a/16/PCGPE10/BLASTERS.EXE b/16/PCGPE10/BLASTERS.EXE deleted file mode 100644 index 0552d3c9e0f2b172c71a9f2f04ed4abdeaf870ce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8379 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 W$X^t=*W2jA*98Mb9&iytLjD_#M}kiP diff --git a/16/PCGPE10/BL担TER b/16/PCGPE10/BL担TER deleted file mode 100644 index 152f4e2c..00000000 --- a/16/PCGPE10/BL担TER +++ /dev/null @@ -1,34 +0,0 @@ - ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - ÖÄ· · · ÖÄÄ· · - ÇÄзºÖÄ·ÖÄ·ÇÄ ÖÄ·ÒÄ·ÓÄÄ·ÖÄ·· ·ÒÄ·ÖĶ - º ººÖĶÓÄ·º ÇĽº ºº ºº ºº ºº º - ÓÄĽÐÓÄÐÓĽÓĽÓĽРÓÄĽÓĽÓÄÐÐ ÐÓĽ - ÖÄ· ÖÄ· ÖÄÄ· - ÇÄзÇÄзÓÄÄ· - º ºº º º - SysOp: Mikel ÓÄĽÓÄĽÓÄĽþ Phone/Fax: + 34-58-293583 - ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ - Sound Blaster Connection 14:4500/200 & 201 HUB Granada (Spain) - Creativity Demo Net 94:620/200 & 201 HUB Granada (Spain) - SoundNet Espa¤a 34:1000/10 & 34:1000/100 RC (Spain) - SkyNEt 94:345/200&94:345/201 HUB Granada (Spain) - FidoNet Organization 2:345/805 - Authorized Product Support Node for - A d v a n c e d - ÜÜÜÜ ÜÜÜÜÜ ÜÜÜÜ ÜÜ ÜÜ Ü ÜÜÜÜÜ - Þ ÜÜ Þ Ý ÞÛ ÛÝ ÞÛ ÛÝ Û ÞÜÜÜÜÜ - Þ Ý ÞßßÛß ÞÛ ÛÝ ÞÛ ÛÝ Û Ý - ßßßß ß ß ß ß ßßßß ß ßßßßß - Advanced Gravis Computer Technology Ltd. - *IGUANA WorLd HeadQuarTers_ - - THE LORDS OF THE BITS World HeadQuarters - Distribution Site VangeliSTeam - Distribution Site RESET-TVC. - =-= DUST HQ Spain =-= Xography HQ Spain =-= Infiny HQ Spain =-= - /// Hemoroids HQ Spain \\\ - Software: FrontDoor 2.02 - Remote Access 2.01 - Hardware: 386/33 64Kb /\ 1 Gb On-Line /\ Modem ZyXEL 19k2 - CD-ROM Philips Electronics /-> 375 ms. - - \ No newline at end of file diff --git a/16/PCGPE10/BMP.TXT b/16/PCGPE10/BMP.TXT deleted file mode 100644 index 91240917..00000000 --- a/16/PCGPE10/BMP.TXT +++ /dev/null @@ -1,1034 +0,0 @@ -Graphics File Formats - -This topic describes the graphics-file formats used by the Microsoft Windows -operating system. Graphics files include bitmap files, icon-resource files, -and cursor-resource files. - -Bitmap-File Formats - -Windows bitmap files are stored in a device-independent bitmap (DIB) format -that allows Windows to display the bitmap on any type of display device. The -term "device independent" means that the bitmap specifies pixel color in a -form independent of the method used by a display to represent color. The -default filename extension of a Windows DIB file is .BMP. - -Bitmap-File Structures - -Each bitmap file contains a bitmap-file header, a bitmap-information header, -a color table, and an array of bytes that defines the bitmap bits. The file -has the following form: - -BITMAPFILEHEADER bmfh; -BITMAPINFOHEADER bmih; -RGBQUAD aColors[]; -BYTE aBitmapBits[]; - -The bitmap-file header contains information about the type, size, and layout -of a device-independent bitmap file. The header is defined as a -BITMAPFILEHEADER structure. - -The bitmap-information header, defined as a BITMAPINFOHEADER structure, -specifies the dimensions, compression type, and color format for the bitmap. - -The color table, defined as an array of RGBQUAD structures, contains as many -elements as there are colors in the bitmap. The color table is not present -for bitmaps with 24 color bits because each pixel is represented by 24-bit -red-green-blue (RGB) values in the actual bitmap data area. The colors in the -table should appear in order of importance. This helps a display driver -render a bitmap on a device that cannot display as many colors as there are -in the bitmap. If the DIB is in Windows version 3.0 or later format, the -driver can use the biClrImportant member of the BITMAPINFOHEADER structure to -determine which colors are important. - -The BITMAPINFO structure can be used to represent a combined -bitmap-information header and color table. The bitmap bits, immediately -following the color table, consist of an array of BYTE values representing -consecutive rows, or "scan lines," of the bitmap. Each scan line consists of -consecutive bytes representing the pixels in the scan line, in left-to-right -order. The number of bytes representing a scan line depends on the color -format and the width, in pixels, of the bitmap. If necessary, a scan line -must be zero-padded to end on a 32-bit boundary. However, segment boundaries -can appear anywhere in the bitmap. The scan lines in the bitmap are stored -from bottom up. This means that the first byte in the array represents the -pixels in the lower-left corner of the bitmap and the last byte represents -the pixels in the upper-right corner. - -The biBitCount member of the BITMAPINFOHEADER structure determines the number -of bits that define each pixel and the maximum number of colors in the -bitmap. These members can have any of the following values: - -Value Meaning - -1 Bitmap is monochrome and the color table contains two entries. Each -bit in the bitmap array represents a pixel. If the bit is clear, the pixel is -displayed with the color of the first entry in the color table. If the bit is -set, the pixel has the color of the second entry in the table. - -4 Bitmap has a maximum of 16 colors. Each pixel in the bitmap is -represented by a 4-bit index into the color table. For example, if the first -byte in the bitmap is 0x1F, the byte represents two pixels. The first pixel -contains the color in the second table entry, and the second pixel contains -the color in the sixteenth table entry. - -8 Bitmap has a maximum of 256 colors. Each pixel in the bitmap is -represented by a 1-byte index into the color table. For example, if the first -byte in the bitmap is 0x1F, the first pixel has the color of the -thirty-second table entry. - -24 Bitmap has a maximum of 2^24 colors. The bmiColors (or bmciColors) -member is NULL, and each 3-byte sequence in the bitmap array represents the -relative intensities of red, green, and blue, respectively, for a pixel. - -The biClrUsed member of the BITMAPINFOHEADER structure specifies the number -of color indexes in the color table actually used by the bitmap. If the -biClrUsed member is set to zero, the bitmap uses the maximum number of colors -corresponding to the value of the biBitCount member. An alternative form of -bitmap file uses the BITMAPCOREINFO, BITMAPCOREHEADER, and RGBTRIPLE -structures. - -Bitmap Compression - -Windows versions 3.0 and later support run-length encoded (RLE) formats for -compressing bitmaps that use 4 bits per pixel and 8 bits per pixel. -Compression reduces the disk and memory storage required for a bitmap. - -Compression of 8-Bits-per-Pixel Bitmaps - -When the biCompression member of the BITMAPINFOHEADER structure is set to -BI_RLE8, the DIB is compressed using a run-length encoded format for a -256-color bitmap. This format uses two modes: encoded mode and absolute mode. -Both modes can occur anywhere throughout a single bitmap. - -Encoded Mode - -A unit of information in encoded mode consists of two bytes. The first byte -specifies the number of consecutive pixels to be drawn using the color index -contained in the second byte. The first byte of the pair can be set to zero -to indicate an escape that denotes the end of a line, the end of the bitmap, -or a delta. The interpretation of the escape depends on the value of the -second byte of the pair, which must be in the range 0x00 through 0x02. -Following are the meanings of the escape values that can be used in the -second byte: - -Second byte Meaning - -0 End of line. -1 End of bitmap. -2 Delta. The two bytes following the escape contain unsigned values -indicating the horizontal and vertical offsets of the next pixel from the -current position. - -Absolute Mode - -Absolute mode is signaled by the first byte in the pair being set to zero and -the second byte to a value between 0x03 and 0xFF. The second byte represents -the number of bytes that follow, each of which contains the color index of a -single pixel. Each run must be aligned on a word boundary. Following is an -example of an 8-bit RLE bitmap (the two-digit hexadecimal values in the -second column represent a color index for a single pixel): - -Compressed data Expanded data - -03 04 04 04 04 -05 06 06 06 06 06 06 -00 03 45 56 67 00 45 56 67 -02 78 78 78 -00 02 05 01 Move 5 right and 1 down -02 78 78 78 -00 00 End of line -09 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E -00 01 End of RLE bitmap - -Compression of 4-Bits-per-Pixel Bitmaps - -When the biCompression member of the BITMAPINFOHEADER structure is set to -BI_RLE4, the DIB is compressed using a run-length encoded format for a -16-color bitmap. This format uses two modes: encoded mode and absolute mode. - -Encoded Mode - -A unit of information in encoded mode consists of two bytes. The first byte -of the pair contains the number of pixels to be drawn using the color indexes -in the second byte. - -The second byte contains two color indexes, one in its high-order nibble -(that is, its low-order 4 bits) and one in its low-order nibble. - -The first pixel is drawn using the color specified by the high-order nibble, -the second is drawn using the color in the low-order nibble, the third is -drawn with the color in the high-order nibble, and so on, until all the -pixels specified by the first byte have been drawn. - -The first byte of the pair can be set to zero to indicate an escape that -denotes the end of a line, the end of the bitmap, or a delta. The -interpretation of the escape depends on the value of the second byte of the -pair. In encoded mode, the second byte has a value in the range 0x00 through -0x02. The meaning of these values is the same as for a DIB with 8 bits per -pixel. - -Absolute Mode - -In absolute mode, the first byte contains zero, the second byte contains the -number of color indexes that follow, and subsequent bytes contain color -indexes in their high- and low-order nibbles, one color index for each pixel. -Each run must be aligned on a word boundary. - -Following is an example of a 4-bit RLE bitmap (the one-digit hexadecimal -values in the second column represent a color index for a single pixel): - -Compressed data Expanded data - -03 04 0 4 0 -05 06 0 6 0 6 0 -00 06 45 56 67 00 4 5 5 6 6 7 -04 78 7 8 7 8 -00 02 05 01 Move 5 right and 1 down -04 78 7 8 7 8 -00 00 End of line -09 1E 1 E 1 E 1 E 1 E 1 -00 01 End of RLE bitmap - -Bitmap Example - -The following example is a text dump of a 16-color bitmap (4 bits per pixel): - -Win3DIBFile - BitmapFileHeader - Type 19778 - Size 3118 - Reserved1 0 - Reserved2 0 - OffsetBits 118 - BitmapInfoHeader - Size 40 - Width 80 - Height 75 - Planes 1 - BitCount 4 - Compression 0 - SizeImage 3000 - - XPelsPerMeter 0 - YPelsPerMeter 0 - ColorsUsed 16 - ColorsImportant 16 - Win3ColorTable - Blue Green Red Unused -[00000000] 84 252 84 0 -[00000001] 252 252 84 0 -[00000002] 84 84 252 0 -[00000003] 252 84 252 0 -[00000004] 84 252 252 0 -[00000005] 252 252 252 0 -[00000006] 0 0 0 0 -[00000007] 168 0 0 0 -[00000008] 0 168 0 0 -[00000009] 168 168 0 0 -[0000000A] 0 0 168 0 -[0000000B] 168 0 168 0 -[0000000C] 0 168 168 0 -[0000000D] 168 168 168 0 -[0000000E] 84 84 84 0 -[0000000F] 252 84 84 0 - Image - . - . Bitmap data - . - -Icon-Resource File Format - -An icon-resource file contains image data for icons used by Windows -applications. The file consists of an icon directory identifying the number -and types of icon images in the file, plus one or more icon images. The -default filename extension for an icon-resource file is .ICO. - -Icon Directory - -Each icon-resource file starts with an icon directory. The icon directory, -defined as an ICONDIR structure, specifies the number of icons in the -resource and the dimensions and color format of each icon image. The ICONDIR -structure has the following form: - - - -typedef struct ICONDIR { - WORD idReserved; - WORD idType; - WORD idCount; - ICONDIRENTRY idEntries[1]; -} ICONHEADER; - -Following are the members in the ICONDIR structure: - -idReserved Reserved; must be zero. -idType Specifies the resource type. This member is set to 1. -idCount Specifies the number of entries in the directory. -idEntries Specifies an array of ICONDIRENTRY structures containing -information about individual icons. The idCount member specifies the number -of structures in the array. - -The ICONDIRENTRY structure specifies the dimensions and color format for an -icon. The structure has the following form: - - - -struct IconDirectoryEntry { - BYTE bWidth; - BYTE bHeight; - BYTE bColorCount; - BYTE bReserved; - WORD wPlanes; - WORD wBitCount; - DWORD dwBytesInRes; - DWORD dwImageOffset; -}; - -Following are the members in the ICONDIRENTRY structure: - -bWidth Specifies the width of the icon, in pixels. Acceptable values -are 16, 32, and 64. - -bHeight Specifies the height of the icon, in pixels. Acceptable -values are 16, 32, and 64. - -bColorCount Specifies the number of colors in the icon. Acceptable values -are 2, 8, and 16. - -bReserved Reserved; must be zero. -wPlanes Specifies the number of color planes in the icon bitmap. -wBitCount Specifies the number of bits in the icon bitmap. -dwBytesInRes Specifies the size of the resource, in bytes. -dwImageOffset Specifies the offset, in bytes, from the beginning of the -file to the icon image. - -Icon Image - -Each icon-resource file contains one icon image for each image identified in -the icon directory. An icon image consists of an icon-image header, a color -table, an XOR mask, and an AND mask. The icon image has the following form: - - - -BITMAPINFOHEADER icHeader; -RGBQUAD icColors[]; -BYTE icXOR[]; -BYTE icAND[]; - -The icon-image header, defined as a BITMAPINFOHEADER structure, specifies the -dimensions and color format of the icon bitmap. Only the biSize through -biBitCount members and the biSizeImage member are used. All other members -(such as biCompression and biClrImportant) must be set to zero. - -The color table, defined as an array of RGBQUAD structures, specifies the -colors used in the XOR mask. As with the color table in a bitmap file, the -biBitCount member in the icon-image header determines the number of elements -in the array. For more information about the color table, see Section 1.1, -"Bitmap-File Formats." - -The XOR mask, immediately following the color table, is an array of BYTE -values representing consecutive rows of a bitmap. The bitmap defines the -basic shape and color of the icon image. As with the bitmap bits in a bitmap -file, the bitmap data in an icon-resource file is organized in scan lines, -with each byte representing one or more pixels, as defined by the color -format. For more information about these bitmap bits, see Section 1.1, -"Bitmap-File Formats." - -The AND mask, immediately following the XOR mask, is an array of BYTE values, -representing a monochrome bitmap with the same width and height as the XOR -mask. The array is organized in scan lines, with each byte representing 8 -pixels. - -When Windows draws an icon, it uses the AND and XOR masks to combine the icon -image with the pixels already on the display surface. Windows first applies -the AND mask by using a bitwise AND operation; this preserves or removes -existing pixel color. Windows then applies the XOR mask by using a bitwise -XOR operation. This sets the final color for each pixel. - -The following illustration shows the XOR and AND masks that create a -monochrome icon (measuring 8 pixels by 8 pixels) in the form of an uppercase -K: - -Windows Icon Selection - -Windows detects the resolution of the current display and matches it against -the width and height specified for each version of the icon image. If Windows -determines that there is an exact match between an icon image and the current -device, it uses the matching image. Otherwise, it selects the closest match -and stretches the image to the proper size. - -If an icon-resource file contains more than one image for a particular -resolution, Windows uses the icon image that most closely matches the color -capabilities of the current display. If no image matches the device -capabilities exactly, Windows selects the image that has the greatest number -of colors without exceeding the number of display colors. If all images -exceed the color capabilities of the current display, Windows uses the icon -image with the least number of colors. - - - -Cursor-Resource File Format - -A cursor-resource file contains image data for cursors used by Windows -applications. The file consists of a cursor directory identifying the number -and types of cursor images in the file, plus one or more cursor images. The -default filename extension for a cursor-resource file is .CUR. - -Cursor Directory - -Each cursor-resource file starts with a cursor directory. The cursor -directory, defined as a CURSORDIR structure, specifies the number of cursors -in the file and the dimensions and color format of each cursor image. The -CURSORDIR structure has the following form: - - -typedef struct _CURSORDIR { - WORD cdReserved; - WORD cdType; - WORD cdCount; - CURSORDIRENTRY cdEntries[]; -} CURSORDIR; - -Following are the members in the CURSORDIR structure: - -cdReserved Reserved; must be zero. -cdType Specifies the resource type. This member must be set to 2. -cdCount Specifies the number of cursors in the file. -cdEntries Specifies an array of CURSORDIRENTRY structures containing -information about individual cursors. The cdCount member specifies the number -of structures in the array. - -A CURSORDIRENTRY structure specifies the dimensions and color format of a -cursor image. The structure has the following form: - - - -typedef struct _CURSORDIRENTRY { - BYTE bWidth; - BYTE bHeight; - BYTE bColorCount; - BYTE bReserved; - WORD wXHotspot; - WORD wYHotspot; - DWORD lBytesInRes; - DWORD dwImageOffset; -} CURSORDIRENTRY; - -Following are the members in the CURSORDIRENTRY structure: - -bWidth Specifies the width of the cursor, in pixels. -bHeight Specifies the height of the cursor, in pixels. -bColorCount Reserved; must be zero. -bReserved Reserved; must be zero. -wXHotspot Specifies the x-coordinate, in pixels, of the hot spot. -wYHotspot Specifies the y-coordinate, in pixels, of the hot spot. -lBytesInRes Specifies the size of the resource, in bytes. -dwImageOffset Specifies the offset, in bytes, from the start of the file to -the cursor image. - -Cursor Image - -Each cursor-resource file contains one cursor image for each image identified -in the cursor directory. A cursor image consists of a cursor-image header, a -color table, an XOR mask, and an AND mask. The cursor image has the following -form: - - - -BITMAPINFOHEADER crHeader; -RGBQUAD crColors[]; -BYTE crXOR[]; -BYTE crAND[]; - -The cursor hot spot is a single pixel in the cursor bitmap that Windows uses -to track the cursor. The crXHotspot and crYHotspot members specify the x- and -y-coordinates of the cursor hot spot. These coordinates are 16-bit integers. - -The cursor-image header, defined as a BITMAPINFOHEADER structure, specifies -the dimensions and color format of the cursor bitmap. Only the biSize through -biBitCount members and the biSizeImage member are used. The biHeight member -specifies the combined height of the XOR and AND masks for the cursor. This -value is twice the height of the XOR mask. The biPlanes and biBitCount -members must be 1. All other members (such as biCompression and -biClrImportant) must be set to zero. - -The color table, defined as an array of RGBQUAD structures, specifies the -colors used in the XOR mask. For a cursor image, the table contains exactly -two structures, since the biBitCount member in the cursor-image header is -always 1. - -The XOR mask, immediately following the color table, is an array of BYTE -values representing consecutive rows of a bitmap. The bitmap defines the -basic shape and color of the cursor image. As with the bitmap bits in a -bitmap file, the bitmap data in a cursor-resource file is organized in scan -lines, with each byte representing one or more pixels, as defined by the -color format. For more information about these bitmap bits, see Section 1.1, -"Bitmap-File Formats." - -The AND mask, immediately following the XOR mask, is an array of BYTE values -representing a monochrome bitmap with the same width and height as the XOR -mask. The array is organized in scan lines, with each byte representing 8 -pixels. - -When Windows draws a cursor, it uses the AND and XOR masks to combine the -cursor image with the pixels already on the display surface. Windows first -applies the AND mask by using a bitwise AND operation; this preserves or -removes existing pixel color. Window then applies the XOR mask by using a -bitwise XOR operation. This sets the final color for each pixel. - -The following illustration shows the XOR and the AND masks that create a -cursor (measuring 8 pixels by 8 pixels) in the form of an arrow: - -Following are the bit-mask values necessary to produce black, white, -inverted, and transparent results: - -Pixel result AND maskXOR mask - -Black 0 0 -White 0 1 -Transparent 1 0 -Inverted1 1 - -Windows Cursor Selection - -If a cursor-resource file contains more than one cursor image, Windows -determines the best match for a particular display by examining the width and -height of the cursor images. - - -============================================================================== - - -BITMAPFILEHEADER (3.0) - - - -typedef struct tagBITMAPFILEHEADER { /* bmfh */ - UINT bfType; - DWORD bfSize; - UINT bfReserved1; - UINT bfReserved2; - DWORD bfOffBits; -} BITMAPFILEHEADER; - -The BITMAPFILEHEADER structure contains information about the type, size, and -layout of a device-independent bitmap (DIB) file. - -Member Description - -bfType Specifies the type of file. This member must be BM. -bfSize Specifies the size of the file, in bytes. -bfReserved1 Reserved; must be set to zero. -bfReserved2 Reserved; must be set to zero. -bfOffBits Specifies the byte offset from the BITMAPFILEHEADER structure -to the actual bitmap data in the file. - -Comments - -A BITMAPINFO or BITMAPCOREINFO structure immediately follows the -BITMAPFILEHEADER structure in the DIB file. - -See Also - -BITMAPCOREINFO, BITMAPINFO - - -============================================================================== -BITMAPINFO (3.0) - - - -typedef struct tagBITMAPINFO { /* bmi */ - BITMAPINFOHEADER bmiHeader; - RGBQUAD bmiColors[1]; -} BITMAPINFO; - -The BITMAPINFO structure fully defines the dimensions and color information -for a Windows 3.0 or later device-independent bitmap (DIB). - -Member Description - -bmiHeader Specifies a BITMAPINFOHEADER structure that contains -information about the dimensions and color format of a DIB. - -bmiColors Specifies an array of RGBQUAD structures that define the -colors in the bitmap. - -Comments - -A Windows 3.0 or later DIB consists of two distinct parts: a BITMAPINFO -structure, which describes the dimensions and colors of the bitmap, and an -array of bytes defining the pixels of the bitmap. The bits in the array are -packed together, but each scan line must be zero-padded to end on a LONG -boundary. Segment boundaries, however, can appear anywhere in the bitmap. The -origin of the bitmap is the lower-left corner. - -The biBitCount member of the BITMAPINFOHEADER structure determines the number -of bits which define each pixel and the maximum number of colors in the -bitmap. This member may be set to any of the following values: - -Value Meaning - -1 The bitmap is monochrome, and the bmciColors member must contain two -entries. Each bit in the bitmap array represents a pixel. If the bit is -clear, the pixel is displayed with the color of the first entry in the -bmciColors table. If the bit is set, the pixel has the color of the second -entry in the table. - -4 The bitmap has a maximum of 16 colors, and the bmciColors member -contains 16 entries. Each pixel in the bitmap is represented by a four-bit -index into the color table. - -For example, if the first byte in the bitmap is 0x1F, the byte represents two -pixels. The first pixel contains the color in the second table entry, and the -second pixel contains the color in the sixteenth table entry. - -8 The bitmap has a maximum of 256 colors, and the bmciColors member -contains 256 entries. In this case, each byte in the array represents a -single pixel. - -24 The bitmap has a maximum of 2^24 colors. The bmciColors member is -NULL, and each 3-byte sequence in the bitmap array represents the relative -intensities of red, green, and blue, respectively, of a pixel. - -The biClrUsed member of the BITMAPINFOHEADER structure specifies the number -of color indexes in the color table actually used by the bitmap. If the -biClrUsed member is set to zero, the bitmap uses the maximum number of colors -corresponding to the value of the biBitCount member. - -The colors in the bmiColors table should appear in order of importance. -Alternatively, for functions that use DIBs, the bmiColors member can be an -array of 16-bit unsigned integers that specify an index into the currently -realized logical palette instead of explicit RGB values. In this case, an -application using the bitmap must call DIB functions with the wUsage -parameter set to DIB_PAL_COLORS. - -Note: The bmiColors member should not contain palette indexes if the bitmap -is to be stored in a file or transferred to another application. Unless the -application uses the bitmap exclusively and under its complete control, the -bitmap color table should contain explicit RGB values. - -See Also - -BITMAPINFOHEADER, RGBQUAD - -============================================================================== -BITMAPINFOHEADER (3.0) - - - -typedef struct tagBITMAPINFOHEADER { /* bmih */ - DWORD biSize; - LONG biWidth; - LONG biHeight; - WORD biPlanes; - WORD biBitCount; - DWORD biCompression; - DWORD biSizeImage; - LONG biXPelsPerMeter; - LONG biYPelsPerMeter; - DWORD biClrUsed; - DWORD biClrImportant; -} BITMAPINFOHEADER; - -The BITMAPINFOHEADER structure contains information about the dimensions and -color format of a Windows 3.0 or later device-independent bitmap (DIB). - -Member Description - -biSize Specifies the number of bytes required by the -BITMAPINFOHEADER structure. - -biWidth Specifies the width of the bitmap, in pixels. -biHeightSpecifies the height of the bitmap, in pixels. - -biPlanesSpecifies the number of planes for the target device. This -member must be set to 1. - -biBitCount Specifies the number of bits per pixel. This value must be 1, -4, 8, or 24. - -biCompression Specifies the type of compression for a compressed bitmap. It -can be one of the following values: - -Value Meaning - -BI_RGB Specifies that the bitmap is not compressed. - -BI_RLE8 Specifies a run-length encoded format for bitmaps with 8 bits -per pixel. The compression format is a 2-byte format consisting of a count -byte followed by a byte containing a color index. For more information, see -the following Comments section. - -BI_RLE4 Specifies a run-length encoded format for bitmaps with 4 bits -per pixel. The compression format is a 2-byte format consisting of a count -byte followed by two word-length color indexes. For more information, see -the following Comments section. - -biSizeImage Specifies the size, in bytes, of the image. It is valid to -set this member to zero if the bitmap is in the BI_RGB format. - -biXPelsPerMeter Specifies the horizontal resolution, in pixels per meter, of -the target device for the bitmap. An application can use this value to select -a bitmap from a resource group that best matches the characteristics of the -current device. - -biYPelsPerMeter Specifies the vertical resolution, in pixels per meter, of -the target device for the bitmap. - -biClrUsed Specifies the number of color indexes in the color table -actually used by the bitmap. If this value is zero, the bitmap uses the -maximum number of colors corresponding to the value of the biBitCount member. -For more information on the maximum sizes of the color table, see the -description of the BITMAPINFO structure earlier in this topic. - -If the biClrUsed member is nonzero, it specifies the actual number of colors -that the graphics engine or device driver will access if the biBitCount -member is less than 24. If biBitCount is set to 24, biClrUsed specifies the -size of the reference color table used to optimize performance of Windows -color palettes. If the bitmap is a packed bitmap (that is, a bitmap in which -the bitmap array immediately follows the BITMAPINFO header and which is -referenced by a single pointer), the biClrUsed member must be set to zero or -to the actual size of the color table. - -biClrImportant Specifies the number of color indexes that are considered -important for displaying the bitmap. If this value is zero, all colors are -important. - -Comments - -The BITMAPINFO structure combines the BITMAPINFOHEADER structure and a color -table to provide a complete definition of the dimensions and colors of a -Windows 3.0 or later DIB. For more information about specifying a Windows 3.0 -DIB, see the description of the BITMAPINFO structure. - -An application should use the information stored in the biSize member to -locate the color table in a BITMAPINFO structure as follows: - -pColor = ((LPSTR) pBitmapInfo + (WORD) (pBitmapInfo->bmiHeader.biSize)) - -Windows supports formats for compressing bitmaps that define their colors -with 8 bits per pixel and with 4 bits per pixel. Compression reduces the disk -and memory storage required for the bitmap. The following paragraphs describe -these formats. - -BI_RLE8 - -When the biCompression member is set to BI_RLE8, the bitmap is compressed -using a run-length encoding format for an 8-bit bitmap. This format may be -compressed in either of two modes: encoded and absolute. Both modes can occur -anywhere throughout a single bitmap. - -Encoded mode consists of two bytes: the first byte specifies the number of -consecutive pixels to be drawn using the color index contained in the second -byte. In addition, the first byte of the pair can be set to zero to indicate -an escape that denotes an end of line, end of bitmap, or a delta. The -interpretation of the escape depends on the value of the second byte of the -pair. The following list shows the meaning of the second byte: - -Value Meaning - -0 End of line. -1 End of bitmap. -2 Delta. The two bytes following the escape contain unsigned values -indicating the horizontal and vertical offset of the next pixel from the -current position. - -Absolute mode is signaled by the first byte set to zero and the second byte -set to a value between 0x03 and 0xFF. In absolute mode, the second byte -represents the number of bytes that follow, each of which contains the color -index of a single pixel. When the second byte is set to 2 or less, the escape -has the same meaning as in encoded mode. In absolute mode, each run must be -aligned on a word boundary. The following example shows the hexadecimal -values of an 8-bit compressed bitmap: - - - -03 04 05 06 00 03 45 56 67 00 02 78 00 02 05 01 -02 78 00 00 09 1E 00 01 - -This bitmap would expand as follows (two-digit values represent a color index -for a single pixel): - - - -04 04 04 -06 06 06 06 06 -45 56 67 -78 78 -move current position 5 right and 1 down -78 78 -end of line -1E 1E 1E 1E 1E 1E 1E 1E 1E -end of RLE bitmap - -BI_RLE4 - -When the biCompression member is set to BI_RLE4, the bitmap is compressed -using a run-length encoding (RLE) format for a 4-bit bitmap, which also uses -encoded and absolute modes. In encoded mode, the first byte of the pair -contains the number of pixels to be drawn using the color indexes in the -second byte. The second byte contains two color indexes, one in its -high-order nibble (that is, its low-order four bits) and one in its low-order -nibble. The first of the pixels is drawn using the color specified by the -high-order nibble, the second is drawn using the color in the low-order -nibble, the third is drawn with the color in the high-order nibble, and so -on, until all the pixels specified by the first byte have been drawn. In -absolute mode, the first byte contains zero, the second byte contains the -number of color indexes that follow, and subsequent bytes contain color -indexes in their high- and low-order nibbles, one color index for each pixel. -In absolute mode, each run must be aligned on a word boundary. The -end-of-line, end-of-bitmap, and delta escapes also apply to BI_RLE4. - -The following example shows the hexadecimal values of a 4-bit compressed -bitmap: - - - -03 04 05 06 00 06 45 56 67 00 04 78 00 02 05 01 -04 78 00 00 09 1E 00 01 - -This bitmap would expand as follows (single-digit values represent a color -index for a single pixel): - - - -0 4 0 -0 6 0 6 0 -4 5 5 6 6 7 -7 8 7 8 -move current position 5 right and 1 down -7 8 7 8 -end of line -1 E 1 E 1 E 1 E 1 -end of RLE bitmap - -See Also - -BITMAPINFO - -============================================================================== -RGBQUAD (3.0) - - - -typedef struct tagRGBQUAD { /* rgbq */ - BYTE rgbBlue; - BYTE rgbGreen; - BYTE rgbRed; - BYTE rgbReserved; -} RGBQUAD; - -The RGBQUAD structure describes a color consisting of relative intensities of -red, green, and blue. The bmiColors member of the BITMAPINFO structure -consists of an array of RGBQUAD structures. - -Member Description - -rgbBlue Specifies the intensity of blue in the color. -rgbGreenSpecifies the intensity of green in the color. -rgbRed Specifies the intensity of red in the color. -rgbReserved Not used; must be set to zero. - -See Also - -BITMAPINFO - -============================================================================== -RGB (2.x) - -COLORREF RGB(cRed, cGreen, cBlue) - -BYTE cRed; /* red component of color */ -BYTE cGreen; /* green component of color */ -BYTE cBlue; /* blue component of color */ - - -The RGB macro selects an RGB color based on the parameters supplied and the -color capabilities of the output device. - -Parameter Description - -cRed Specifies the intensity of the red color field. -cGreen Specifies the intensity of the green color field. -cBlue Specifies the intensity of the blue color field. - -Returns - -The return value specifies the resultant RGB color. - -Comments - -The intensity for each argument can range from 0 through 255. If all three -intensities are specified as zero, the result is black. If all three -intensities are specified as 255, the result is white. - -Comments - -The RGB macro is defined in WINDOWS.H as follows: - - - -#define RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)(g)<<8))| \ - (((DWORD)(BYTE)(b))<<16))) - -See Also - -GetBValue, GetGValue, GetRValue, PALETTEINDEX, PALETTERGB - -============================================================================== -BITMAPCOREINFO (3.0) - - - -typedef struct tagBITMAPCOREINFO { /* bmci */ - BITMAPCOREHEADER bmciHeader; - RGBTRIPLE bmciColors[1]; -} BITMAPCOREINFO; - -The BITMAPCOREINFO structure fully defines the dimensions and color -information for a device-independent bitmap (DIB). Windows applications -should use the BITMAPINFO structure instead of BITMAPCOREINFO whenever -possible. - -Member Description - -bmciHeader Specifies a BITMAPCOREHEADER structure that contains -information about the dimensions and color format of a DIB. - -bmciColors Specifies an array of RGBTRIPLE structures that define the -colors in the bitmap. - -Comments - -The BITMAPCOREINFO structure describes the dimensions and colors of a bitmap. -It is followed immediately in memory by an array of bytes which define the -pixels of the bitmap. The bits in the array are packed together, but each -scan line must be zero-padded to end on a LONG boundary. Segment boundaries, -however, can appear anywhere in the bitmap. The origin of the bitmap is the -lower-left corner. - -The bcBitCount member of the BITMAPCOREHEADER structure determines the number -of bits that define each pixel and the maximum number of colors in the -bitmap. This member may be set to any of the following values: - -Value Meaning - -1 The bitmap is monochrome, and the bmciColors member must contain two -entries. Each bit in the bitmap array represents a pixel. If the bit is -clear, the pixel is displayed with the color of the first entry in the -bmciColors table. If the bit is set, the pixel has the color of the second -entry in the table. - -4 The bitmap has a maximum of 16 colors, and the bmciColors member -contains 16 entries. Each pixel in the bitmap is represented by a four-bit -index into the color table. - -For example, if the first byte in the bitmap is 0x1F, the byte represents two -pixels. The first pixel contains the color in the second table entry, and the -second pixel contains the color in the sixteenth table entry. - -8 The bitmap has a maximum of 256 colors, and the bmciColors member -contains 256 entries. In this case, each byte in the array represents a -single pixel. - -24 The bitmap has a maximum of 2^24 colors. The bmciColors member is -NULL, and each 3-byte sequence in the bitmap array represents the relative -intensities of red, green, and blue, respectively, of a pixel. - -The colors in the bmciColors table should appear in order of importance. -Alternatively, for functions that use DIBs, the bmciColors member can be an -array of 16-bit unsigned integers that specify an index into the currently -realized logical palette instead of explicit RGB values. In this case, an -application using the bitmap must call DIB functions with the wUsage -parameter set to DIB_PAL_COLORS. - -Note: The bmciColors member should not contain palette indexes if the -bitmap is to be stored in a file or transferred to another application. -Unless the application uses the bitmap exclusively and under its complete -control, the bitmap color table should contain explicit RGB values. - -See Also - -BITMAPINFO, BITMAPCOREHEADER, RGBTRIPLE - - -============================================================================== -BITMAPCOREHEADER (3.0) - - - -typedef struct tagBITMAPCOREHEADER { /* bmch */ - DWORD bcSize; - short bcWidth; - short bcHeight; - WORD bcPlanes; - WORD bcBitCount; -} BITMAPCOREHEADER; - -The BITMAPCOREHEADER structure contains information about the dimensions and -color format of a device-independent bitmap (DIB). Windows applications -should use the BITMAPINFOHEADER structure instead of BITMAPCOREHEADER -whenever possible. - -Member Description - -bcSize Specifies the number of bytes required by the -BITMAPCOREHEADER structure. - -bcWidth Specifies the width of the bitmap, in pixels. -bcHeightSpecifies the height of the bitmap, in pixels. - -bcPlanesSpecifies the number of planes for the target device. This -member must be set to 1. - -bcBitCount Specifies the number of bits per pixel. This value must be 1, -4, 8, or 24. - -Comments - -The BITMAPCOREINFO structure combines the BITMAPCOREHEADER structure and a -color table to provide a complete definition of the dimensions and colors of -a DIB. See the description of the BITMAPCOREINFO structure for more -information about specifying a DIB. - -An application should use the information stored in the bcSize member to -locate the color table in a BITMAPCOREINFO structure with a method such as -the following: - - - -lpColor = ((LPSTR) pBitmapCoreInfo + (UINT) (pBitmapCoreInfo->bcSize)) - -See Also - -BITMAPCOREINFO, BITMAPINFOHEADER, BITMAPINFOHEADER - -============================================================================= -RGBTRIPLE (3.0) - - - -typedef struct tagRGBTRIPLE { /* rgbt */ - BYTE rgbtBlue; - BYTE rgbtGreen; - BYTE rgbtRed; -} RGBTRIPLE; - -The RGBTRIPLE structure describes a color consisting of relative intensities -of red, green, and blue. The bmciColors member of the BITMAPCOREINFO -structure consists of an array of RGBTRIPLE structures. Windows applications -should use the BITMAPINFO structure instead of BITMAPCOREINFO whenever -possible. The BITMAPINFO structure uses an RGBQUAD structure instead of the -RGBTRIPLE structure. - -Member Description - -rgbtBlueSpecifies the intensity of blue in the color. -rgbtGreen Specifies the intensity of green in the color. -rgbtRed Specifies the intensity of red in the color. - -See Also - -BITMAPCOREINFO, BITMAPINFO, RGBQUAD - -============================================================================== diff --git a/16/PCGPE10/BRES.TXT b/16/PCGPE10/BRES.TXT deleted file mode 100644 index 3e08092c..00000000 --- a/16/PCGPE10/BRES.TXT +++ /dev/null @@ -1,399 +0,0 @@ - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Bresenham's Line and Circle Algorithms ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - Written for the PC-GPE by Mark Feldman - e-mail address : u914097@student.canberra.edu.au - myndale@cairo.anu.edu.au - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ THIS FILE MAY NOT BE DISTRIBUTED ³ - ³ SEPARATE TO THE ENTIRE PC-GPE COLLECTION. ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Disclaimer ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ - -I assume no responsibility whatsoever for any effect that this file, the -information contained therein or the use thereof has on you, your sanity, -computer, spouse, children, pets or anything else related to you or your -existance. No warranty is provided nor implied with this information. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Introduction ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Bresenham is a pretty smart cookie (note the use of the word "is", last I -heard he was still working for IBM). This file contains the algorithms he -developped for drawing lines and circles on a pixelated display system -such as the VGA. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Line Algorithm ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The basic algorithm works for lines which look like this: - - - o------- ¿ - p1 -------- ³ deltay - ------- p2 ³ - -------o Ù - - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - deltax - -where p1 = (x1,y1), - p2 = (x2, y2), - x and y are both increasing from p1 to p2, - deltax = x2 - x1, - deltay = y2 - y1 and - deltax >= deltay. - -All other types of lines can be derived from this type. I'll get to this -bit later. - -First you need to perform the following intialisation: - -x = x1 -y = y1 -d = (2 * deltay) - deltax - -x is the current x location, you will add 1 to this variable after every -pixel you draw until all pixels have been drawn. -y is the current y location. The decision variable is used to determine -when to add 1 to this value. d is the decision variable which will be used -to keep a track of what to do. - -Now you loop across the screen from x1 to x2 and for each loop perform the -following operations for each pixel : - -PutPixel(x, y); { Draw a pixel at the current point } -if d < 0 then - d := d + (2 * deltay) -else - begin - d := d + 2 * (deltay - deltax); - y := y + 1; - end; -x := x + 1; - -It's that simple! - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Speeding Up The Line Algorithm ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -There are several useful techniques for speeding up Bresenhams line -algorithm. - -For starters, notice that all multiplications are by 2. This can be -performed with a simple shift left instruction (Shl in Pascal, << in C). - -Next notice that the values you add to the decision variable do not change -throughout the loop, so they can be precalculated beforehand. - -One property of lines is that they are symetrical about their mid-points, -and we can use this property to speed up the algorithm. Store two x and y -values, (xa, ya) and (xb, yb). Have each pair start on either end of the -line. For each pass through the loop you draw the pixel at both points, add -1 to xa and subtract one from xb. When d >= 0 add 1 to ya and subtract one -from yb. You then only need to loop until xa = xb. - -It's also obvious that if the decision variable becomes the same value -it was when it was initialised, then the rest of the line is just -copies of the line you have already drawn up to that point. You might be -able to speed the algorithm up by keeping an array of how y has been -modified and then use this array if the line starts repeating itself. If -you are using the Intel registers to store all values then you probably -wouldn't get much of a speed increase (in fact it could slow it down), but -it would probably be useful for thing like linear texture mapping (discussed -below). I've never actually tried implementing this technique, and I would -like to hear the results if anyone does. - -Above all remember that these optimisations will only significantly speed -up the line drawing algorithm if the whole thing is done in assembly. A -profile of the example program at the end of this file showed that 40% of -CPU time was spent in the slow PutPixel routine I was using, the loop -mechanics and testing the sign of the decision variable. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Other Uses for the Line Algorithm ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -A line can be represented by the equation y = mx + c, where -m = deltay / deltax. Note that this is a version of the standard linear -equation ax + bx + c = 0. There are many algorithms which use this equation. - -One good use for the bresenham line algorithm is for quickly drawing filled -concave polygons (eg triangles). You can set up an array of minimum and -maximum x values for every horizontal line on the screen. You then use -bresenham's algorithm to loop along each of the polygon's sides, find where -it's x value is on every line and adjust the min and max values accordingly. -When you've done it for every line you simply loop down the screen drawing -horizontal lines between the min and max values for each line. - -Another area is in linear texture mapping (see the PC-GPE article on texture -mapping). This method involves taking a string of bitmap pixels and -stretching them out (or squashing them in) to a line of pixels on the screen. -Typically you would draw a vertical line down the screen and use Bresenhams -to calculate which bitmap pixel should be drawn at each screen pixel. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Circle Algorithm ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Circles have the property of being highly symetrical, which is handy -when it comes to drawing them on a display screen. - - |y (This diagram is supposed to be a circle, try viewing - | it in 50 line mode). - \ ..... / - . | . We know that there are 360 degrees in a circle. First we - . \ | / . see that a circle is symetrical about the x axis, so - . \|/ . only the first 180 degrees need to be calculated. Next ---.---+---.-- we see that it's also symetrical about the y axis, so now - . /|\ . x we only need to calculate the first 90 degrees. Finally - . / | \ . we see that the circle is also symetrical about the 45 - . | . degree diagonal axis, so we only need to calculate the - / ..... \ first 45 degrees. - | - | - -Bresenhams circle algorithm calculates the locations of the pixels in the -first 45 degrees. It assumes that the circle is centered on the origin. So -for every pixel (x,y) it calculates we draw a pixel in each of the 8 octants -of the circle : - -PutPixel(CenterX + X, Center Y + Y) -PutPixel(CenterX + X, Center Y - Y) -PutPixel(CenterX - X, Center Y + Y) -PutPixel(CenterX - X, Center Y - Y) -PutPixel(CenterX + Y, Center Y + X) -PutPixel(CenterX + Y, Center Y - X) -PutPixel(CenterX - Y, Center Y + X) -PutPixel(CenterX - Y, Center Y - X) - -So let's get into the actual algorithm. Given a radius for the circle -we perform this initialisation: - -d := 3 - (2 * RADIUS) -x := 0 -y := RADIUS - -Now for each pixel we do the following operations: - -Draw the 8 circle pixels -if d < 0 then - d := d + (4 * x) + 6 -else - begin - d := d + 4 * (x - y) + 10 - y := y - 1; - end; - -And we keep doing this until x = y. Note that the values added to the -decision variable in this algorithm (x and y) are constantly changing, so -we cannot precalculate them. The muliplications however are by 4, and we -can accomplish this by shifting left twice. - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ A Pascal General Line Procedure ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The basic bresenham line algorithm can be modified to handle all types of -lines. In this section assume that deltax = abs(x2 - x1) and -deltay = abs(y2 - y1). - -First let's take lines where deltax >= deltay. Now if x1 > x2 then you will -need to subtract 1 from x for every pass through the loop. Similarly if y1 > -y2 then you will be also need to subtract 1 from y for every pass through the -loop where d < 0. - -Lines where deltax < deltay can be handled the same way, you just swap all -the deltax's and deltay's around. - -The fastest method of handling all cases is to write a custom routine for -each of the 8 line types: - -1) x1 <= x2, y1 <= y2, deltax >= deltay -2) x1 <= x2, y1 <= y2, deltax < deltay -3) x1 <= x2, y1 > y2, deltax >= deltay -4) x1 <= x2, y1 > y2, deltax < deltay -5) x1 > x2, y1 <= y2, deltax >= deltay -6) x1 > x2, y1 <= y2, deltax < deltay -7) x1 > x2, y1 > y2, deltax >= deltay -8) x1 > x2, y1 > y2, deltax < deltay - -This will give you the fastest results, but will also make your code 8 -times larger! Alternatively you can declare a few extra variables and -use a common inner loop for all lines: - -numpixels = number of pixels to draw - = deltax if deltax >= deltay or - = deltay if deltax < deltay -dinc1 = the amount to add to d when d < 0 -dinc2 = the amount to add to d when d >= 0 -xinc1 = the amount to add to x when d < 0 -xinc2 = the amount to add to x when d >= 0 -yinc1 = the amount to add to y when d < 0 -yinc2 = the amount to add to y when d >= 0 - -The following is a simple example program which uses this technique: - - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - -{ - -BRESLINE.PAS - A general line drawing procedure. - By Mark Feldman - -This is a very simple implementation of bresenhams' line algorithm with -no optimisations. It can draw about 6000 random lines a second in mode 13h -on my 486SX33 with sloooooow Paradise Extended VGA. - -} - -procedure Line(x1, y1, x2, y2 : integer; color : byte); -var i, deltax, deltay, numpixels, - d, dinc1, dinc2, - x, xinc1, xinc2, - y, yinc1, yinc2 : integer; -begin - - { Calculate deltax and deltay for initialisation } - deltax := abs(x2 - x1); - deltay := abs(y2 - y1); - - { Initialize all vars based on which is the independent variable } - if deltax >= deltay then - begin - - { x is independent variable } - numpixels := deltax + 1; - d := (2 * deltay) - deltax; - dinc1 := deltay Shl 1; - dinc2 := (deltay - deltax) shl 1; - xinc1 := 1; - xinc2 := 1; - yinc1 := 0; - yinc2 := 1; - end - else - begin - - { y is independent variable } - numpixels := deltay + 1; - d := (2 * deltax) - deltay; - dinc1 := deltax Shl 1; - dinc2 := (deltax - deltay) shl 1; - xinc1 := 0; - xinc2 := 1; - yinc1 := 1; - yinc2 := 1; - end; - - { Make sure x and y move in the right directions } - if x1 > x2 then - begin - xinc1 := - xinc1; - xinc2 := - xinc2; - end; - if y1 > y2 then - begin - yinc1 := - yinc1; - yinc2 := - yinc2; - end; - - { Start drawing at } - x := x1; - y := y1; - - { Draw the pixels } - for i := 1 to numpixels do - begin - PutPixel(x, y, color); - if d < 0 then - begin - d := d + dinc1; - x := x + xinc1; - y := y + yinc1; - end - else - begin - d := d + dinc2; - x := x + xinc2; - y := y + yinc2; - end; - end; -end; - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - - - - - -Note that if you are writing a line routine for mode 13h (for example) you -can speed it up by converting the inner loop to assembly and including -mode 13h specific code. This portion of the above routine works the same but -the values are stored in a single variable (screen) which holds the -memory address of the current pixel, screeninc1 and screeninc2 are the -update values for screen. - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - -var screen : word; - screeninc1, screeninc2 : integer; - . - . - . - { Start drawing at } - screen := word(y1) * 320 + x1; - screeninc1 := yinc1 * 320 + xinc1; - screeninc2 := yinc2 * 320 + xinc2; - - { Draw the pixels } - asm - - { Use as many registers as are available } - push $A000 - pop es - mov di, screen - mov dx, d - mov al, color - mov cx, numpixels - mov bx, dinc1 - - @bres1: - - { Draw the current pixel and compare the decision variable to 0 } - mov es:[di], al - cmp dx, 0 - jnl @bres2 - - { D < 0 } - add dx, bx { bx = dinc1 } - add di, screeninc1 - jmp @bres3 - - @bres2: - - { D >= 0 } - add dx, dinc2 - add di, screeninc2 - - @bres3: - - loop @bres1 - end; - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - diff --git a/16/PCGPE10/BSP.TXT b/16/PCGPE10/BSP.TXT deleted file mode 100644 index 03649563..00000000 --- a/16/PCGPE10/BSP.TXT +++ /dev/null @@ -1,149 +0,0 @@ - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ A Simple Explanation of BSP Trees ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - Written for the PC-GPE by Mark Feldman - e-mail address : u914097@student.canberra.edu.au - myndale@cairo.anu.edu.au - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ THIS FILE MAY NOT BE DISTRIBUTED ³ - ³ SEPARATE TO THE ENTIRE PC-GPE COLLECTION. ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Disclaimer ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ - -I assume no responsibility whatsoever for any effect that this file, the -information contained therein or the use thereof has on you, your sanity, -computer, spouse, children, pets or anything else related to you or your -existance. No warranty is provided nor implied with this information. - -ÚÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ BSP Trees ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÙ - -Binary Space Partition trees are handy for drawing 3D scenes where the -positions of objects are fixed and the user's viewing coordinate changes -(flight simulators being a classic example). - -BSP's are an extention of the "Painter's Algorithm". The painter's algorithm -works by drawing all the polygons (or texture maps) in a scene in back-to- -front order, so that polygon's in the background are drawn first, and -polygons in the foreground are drawn over them. The "classic" painter's -algorithm does have a few problems however: -1) polygon's will not be drawn correctly if they pass through any other -polygon -2) it's difficult and computationally expensive calculating the order that -the polygons should be drawn in for each frame -3) the algorithm cannot handle cases of cyclic overlap such as the -following : - ___ ___ - | | | | - __| |_____|___|___ - | | | | - |__| |_____________| - | | | | - __|___|_____| |___ - | | | | - |____________| |___| - | | | | - |___| |___| - -In this case it doesn't matter which order you draw the polygon's it still -won't look right! - -BSP's help solve all these problems. - -Ok, so let's get down to business. BSP's work by building an ordered tree of -all the objects in a scene. Let's imagine we live in a 2D world and we have -a scene like this: - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ ³ - ³ ³ - ³ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ³ - ³ line 1 ³ - ³ \ ³ - ³ \ ³ - ³ \ line 2 ³ - ³ \ ³ - ³ \ ³ - ³ ÄÄÄÄÄÄÄÄ \ ³ - ³ line 3 \ ³ - ³ ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - ^ - viewpoint (assume the viewpoint is the - origin for this example) - - -Now if we were to draw this scene using the painters algorithm we would -draw line 1 first, then line 2, finally line 3. Using BSP's we can figure -out the order beforehand and create a tree. First we note that any -arbitrary point can be on either of it's 2 sides or on the line (which -can be regarded as being on either of the sides). When we build our tree, we -take a line and put all the lines on one side of it to the left and all the -nodes on the other side on the right. So for the above example could wind up -with the following tree: - - 1 - / - 2 - / - 3 - -Alternatively, we could also wind up with this tree: - - 2 - / \ - 3 1 - -Notice that line 2 is the head node, line 3 is on the same side of line 2 -as the origin is and line 1 is on the opposite side. - -Now, I hear you say "but hang on a tic, what if line 3 is the head node? What -side of it is line 2 on?". Yes boys and girls, there had to be a catch -somewhere and this is it. What you have to do here is split line 2 into -*TWO* lines so that each portion falls nice and neatly onto either side of -line 3, so you get a tree like this: - - 3 - / \ - 2a 2b - \ - 1 - -The lines 2a and 2b are portions of the original line 2. If you draw *BOTH* -of them on the screen it will look as though you've drawn the entire original -line. - -You don't have to worry about balancing a BSP tree, since you have to -traverse every node in it every time you draw the scene anyway. The trick -is to figure out how to organise the tree so that you get the *least* number -of polygon splits. I tackled this by looking at each polygon yet to be -inserted into the tree, calculating how many splits it will cause if it -is inserted next and selecting the one which will cause the fewest. This -is a very slow way of going about things, O(N^2) I think, but for most games -you only need to sort the tree once when you are developping the game and not -during the game itself. - -Extending these concepts to 3D is pretty straight-forward. Let's say that -polygon 1 is at the top of the BSP tree and we want to insert polygon 2. If -all the points in polygon 2 fall on one side or the other of polygon 1 then -you insert it into polygon 2's left or right node. If some points fall on -one side and the rest fall on the other, then you have to figure out the line -of intersection formed by the planes that each polygon lies in and split -polygon 2 along this line. Each of these 2 new polygons will then fall on -either side of polygon 1. - - -To draw the objects in a BSP tree you start at the top node and figure out -which side of the object your view coordinate is on. You then traverse the -node for the *other* side, draw the current object, then traverse the node -for the side the view coordinate is on. - - diff --git a/16/PCGPE10/CAT.TXT b/16/PCGPE10/CAT.TXT deleted file mode 100644 index b2bbf55e..00000000 --- a/16/PCGPE10/CAT.TXT +++ /dev/null @@ -1,163 +0,0 @@ - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Programming the Chips And Technologies SVGA Chip ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - Written for the PC-GPE by Mark Feldman - e-mail address : u914097@student.canberra.edu.au - myndale@cairo.anu.edu.au - - Please read the file SVGINTRO.TXT - (Graphics/SVGA/Intro PC-GPE menu option) - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ THIS FILE MAY NOT BE DISTRIBUTED ³ - ³ SEPARATE TO THE ENTIRE PC-GPE COLLECTION. ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Disclaimer ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ - -I assume no responsibility whatsoever for any effect that this file, the -information contained therein or the use thereof has on you, your sanity, -computer, spouse, children, pets or anything else related to you or your -existance. No warranty is provided nor implied with this information. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Setup mode ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ - -To modify some of the CAT's internal SVGA registers the card must be placed -into setup mode. This is done by writing the value 1Eh to port 46E8h. To -exit setup mode write the value 0Eh to port 46E8h. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Enabling Extensions ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The CAT's extended registers are normally locked and must be enabled before -you attempt to modify them. To enable them, you must enter setup mode, -write the value 80h to port 103h and exit setup mode. To disable them -you must enter setup mode, write the value 00h to port 103h and exit -setup mode. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Identifying the CAT Chip ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Detecting the presence of a CAT chip can be done by entering setup mode, -checking that the value returned from reading port 104h is A5h and then -exiting setup mode. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Identifying which CAT Chip and Revision Number ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The CAT chip type and revision number can be determined by enabling -extensions, reading the value of register 0 and disabling extensions. -The top 4 bits (4-7) are the chip id and the lower 4 are the version -number. - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Chip ID Chip ³ - ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ - ³ 1 82c451 or 82c452 ³ - ³ 2 82c455 ³ - ³ 3 82c453 ³ - ³ 5 82c456 ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -The 82c451 and 82c452 can be distinguished by attempting to modify -register 3Ah (Graphics Cursor Color 1, make sure you set it back to what it -was). If the register exists the chip is an 82c452. - -Alternatively the chip ID can be determined using the Get Controller -Information BIOS call (see below). - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ CAT Graphics Display Modes ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Mode Resolution Colors Chip ³ - ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ - ³ 25h 640x480 16 451/452/453 ³ - ³ 6Ah 800x600 16 451/452/453 ³ - ³ 70h 800x600 16 451/452/453 ³ - ³ 71h 960x720 16 452 ³ - ³ 72h 1024x768 16 452/453 ³ - ³ 78h 640x400 256 451/452/453 ³ - ³ 79h 640x480 256 452/453 ³ - ³ 7Ah 768x576 256 452 ³ - ³ 7Ch 800x600 256 453 ³ - ³ 7Eh 1024x768 256 453 ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ The CAT Display Memory ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The following registers can only be modified while the extended registers -are enabled (See Enabling Extensions above). - -The 451, 455 and 456 are always in single-paging mode and have 4 64K -banks. To switch to a bank you must first enable access to extended memory -with the following procedure: - -Port[$3D6] := $0B; -Port[$3D6] := Port[$3D6] and $FD; - -Selecting a bank can be done with the following procedure: - -Port[$3D6] := $0B; -Port[$3D7] := bank_number; - -where bank_number = 0 - 3. Each bank is 64K long and has a 86K granularity. - -The 452 and 453 banks have a 16K granularity, so if you want 64K granularity -you must multiply the bank number by 4 before writing it to the registers : - -Port[$3D6] := $10; -Port[$3D7] := bank_number Shl 2; { = bank_numer * 4 } - -The 452 and 453 allow duel paging. The 64K host address space is split in -two, one low area A000:0000-7FFFh and a high area A000:8000-FFFFh. This -mode can be enabled with the following procedure: - -Port[$3D6] := $10; -Port[$3D6] := Port[$3D6] or 2; - -In this mode each bank also has a granularity of 16K. The lower bank is -selected with the same procedure for setting the bank in single-paging -mode. The upper bank is selected with the following call: - -Port[$3D6] := $11; -Port[$3D7] := bank_number Shl 2; { = bank_numer * 4 } - -None of the CAT chips allow you to select one bank for reading and -another for writing. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ CAT Get Controller Information BIOS Call ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Int 10h -Inputs : - AH = 5Fh Extended VGA Control - AL = 00h Get Controller Information - -Returns: -AL = 5Fh Extended VGA control function supported -BL = Chip type bits 7-4 contain the chip type number - 0 = 82c451 - 1 = 82c452 - 2 = 82c455 - ? = 82c453 - bits 3-0 contain the revision number -BH = Memory Size Video memory size - 0 = 256k - 1 = 512k - 2 = 1M diff --git a/16/PCGPE10/CMF.TXT b/16/PCGPE10/CMF.TXT deleted file mode 100644 index 2e095be0..00000000 --- a/16/PCGPE10/CMF.TXT +++ /dev/null @@ -1,159 +0,0 @@ - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Creative Labs File Formats (SBI/CMF/IBK) ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - Written for the PC-GPE by Mark Feldman - e-mail address : u914097@student.canberra.edu.au - myndale@cairo.anu.edu.au - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ THIS FILE MAY NOT BE DISTRIBUTED ³ - ³ SEPARATE TO THE ENTIRE PC-GPE COLLECTION. ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Disclaimer ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ - -I assume no responsibility whatsoever for any effect that this file, the -information contained therein or the use thereof has on you, your sanity, -computer, spouse, children, pets or anything else related to you or your -existance. No warranty is provided nor implied with this information. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Sound Blaster Instrument File Format (SBI) ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The SBI format contains the register values for the FM chip to synthesize -an instrument. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ -³ Offset Description ³ -ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ -³ 00h-03h Contains id characters "SBI" followed by byte 1Ah ³ -³ 04h-23h Instrument name, NULL terminated string ³ -³ 24h Modulator Sound Characteristic (Mult, KSR, EG, VIB, AM) ³ -³ 25h Carrier Sound Characteristic ³ -³ 26h Modulator Scaling/Output Level ³ -³ 27h Carrier Scaling/Output Level ³ -³ 28h Modulator Attack/Delay ³ -³ 29h Carrier Attack/Delay ³ -³ 2Ah Modulator Sustain/Release ³ -³ 2Bh Carrier Sustain/Release ³ -³ 2Ch Modulator Wave Seelct ³ -³ 2Dh Carrier Wave Select ³ -³ 2Eh Feedback/Connection ³ -³ 2Fh-33h Reserved ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Creative Music File Format (CMF) ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The CMF file format consists of 3 blocks: the header block, the instrument -block and the music block. - - -The CMF Header Block -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ -³ Offset Description ³ -ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ -³ 00h-03h Contains id characters "CTMF" ³ -³ 04h-05h CMF Format Version MSB = major version, lsb = minor version ³ -³ 06h-07h File offset of the instrument block ³ -³ 08h-09h File offset of the music block ³ -³ 0Ah-0Bh Clock ticks per quarter note (one beat) default = 120 ³ -³ 0Ch-0Dh Clock ticks per second ³ -³ 0Eh-0Fh File offset of the music title (0 = none) ³ -³ 10h-11h File offset of the composer name (0 = none) ³ -³ 12h-13h File offset of the remarks (0 = none) ³ -³ 14h-23h Channel-In-Use Table ³ -³ 24h-25h Number of instruments used ³ -³ 26h-27h Basic Tempo ³ -³ 28h-? Title, composer and remarks stored here ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -The CMF Instrument Block -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - -The instrument block contains one 16 byte data structure for each instrument -in the piece. Each record is of the same format as bytes 24h-33h in the -SBI file format. - - -The CMF Music Block -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - -The music block adheres to the standard MIDI file format, and can have from -1 to 16 instruments. The PC-GPE file MIDI.TXT contains more information -on this file format. - -The music block consists of an alternating seqence of time and MIDI event -records: - -ÚÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÂÄ -³dTime³MIDI Event³dTime³MIDI Event³dTime³MIDI Event³ ........ -ÀÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÁÄ - -dTime (delta Time) is the amount of time before the following MIDI event. -MIDI Event is any MIDI channel message (see MIDI.TXT). - - -The CMF file format defines the following MIDI Control Change events: - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ -³ Control ³ -³ Number Control Data ³ -ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ -³ 66h 1-127, used as markers in the music ³ -³ 67h 0 - melody mode, 1 = rhythm mode ³ -³ 68h 0-127, changes the pitch of all following notes upward ³ -³ by the given number of 1/128 semitones ³ -³ 69h 0-127, changes the pitch of all following notes downward ³ -³ by the given number of 1/128 semitones ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -In rhythm mode, the last five channels are allocated for the percussion -instruments: - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Channel Instrument ³ - ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ - ³ 12h Bass Drum ³ - ³ 13h Snare Drum ³ - ³ 14h Tom-Tom ³ - ³ 15h Top Cymbal ³ - ³ 16h High-hat Cymbal ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Sound Blaster Instrument Bank File Format (IBK) ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -A bank file is a group of up to 128 instruments. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ -³ Offset Description ³ -ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ -³ 00h-03h Contains id characters "IBK" followed by byte 1Ah ³ -³ 04h-803h Parameters for 128 instruments, 16 bytes for each instrument ³ -³ in the same format as bytes 24h-33h in the SBI format ³ -³ 804h-C83h Instrument names for 128 instruments, 9 bytes for each ³ -³ instrument, each name must be null terminated ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ References ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Title : Sound Blaster - The Official Book -Authors : Richard Heimlich, David M. Golden, Ivan Luk, Peter M. Ridge -Publishers : Osborne/McGraw Hill -ISBN : 0-07-881907-5 diff --git a/16/PCGPE10/CONIC.CC b/16/PCGPE10/CONIC.CC deleted file mode 100644 index 9e1b9c3f..00000000 --- a/16/PCGPE10/CONIC.CC +++ /dev/null @@ -1,356 +0,0 @@ - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ A General Conics Sections Scan Line Algorithm ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -The following code is the complete algorithm for the general conic -drawer as mentioned in Foley/VanDam. It is included here with the -permission of Andrew W. Fitzgibbon, who derived the remaining code -sections not included in the book. - - -// -// CONIC 2D Bresenham-like conic drawer. -// CONIC(Sx,Sy, Ex,Ey, A,B,C,D,E,F) draws the conic specified -// by A x^2 + B x y + C y^2 + D x + E y + F = 0, between the -// start point (Sx, Sy) and endpoint (Ex,Ey). - -// Author: Andrew W. Fitzgibbon (andrewfg@ed.ac.uk), -// Machine Vision Unit, -// Dept. of Artificial Intelligence, -// Edinburgh University, -// -// Date: 31-Mar-94 - -#include -#include -#include - -static int DIAGx[] = {999, 1, 1, -1, -1, -1, -1, 1, 1}; -static int DIAGy[] = {999, 1, 1, 1, 1, -1, -1, -1, -1}; -static int SIDEx[] = {999, 1, 0, 0, -1, -1, 0, 0, 1}; -static int SIDEy[] = {999, 0, 1, 1, 0, 0, -1, -1, 0}; -static int BSIGNS[] = {99, 1, 1, -1, -1, 1, 1, -1, -1}; - -int debugging = 1; - -struct ConicPlotter { - virtual void plot(int x, int y); -}; - -struct DebugPlotter : public ConicPlotter { - int xs; - int ys; - int xe; - int ye; - int A; - int B; - int C; - int D; - int E; - int F; - - int octant; - int d; - - void plot(int x, int y); -}; - -void DebugPlotter::plot(int x, int y) -{ - printf("%3d %3d\n",x,y); - - if (debugging) { - // Translate start point to origin... - float tF = A*xs*xs + B*xs*ys + C*ys*ys + D*xs + E*ys + F; - float tD = D + 2 * A * xs + B * ys; - float tE = E + B * xs + 2 * C * ys; - - float tx = x - xs + ((float)DIAGx[octant] + SIDEx[octant])/2; - float ty = y - ys + ((float)DIAGy[octant] + SIDEy[octant])/2; - // Calculate F - - float td = 4*(A*tx*tx + B*tx*ty + C*ty*ty + tD*tx + tE*ty + tF); - - fprintf(stderr,"O%d ", octant); - if (d<0) - fprintf(stderr," Inside "); - else - fprintf(stderr,"Outside "); - float err = td - d; - fprintf(stderr,"Real(%5.1f,%5.1f) = %8.2f Recurred = %8.2f err = %g\n", - tx, ty, td/4, d/4.0f, err); - if (fabs(err) > 1e-14) - abort(); - } - -} - -inline int odd(int n) -{ - return n&1; -} - -inline int abs(int a) -{ - if (a > 0) - return a; - else - return -a; -} - -int getoctant(int gx, int gy) -{ - // Use gradient to identify octant. - int upper = abs(gx)>abs(gy); - if (gx>=0) // Right-pointing - if (gy>=0) // Up - return 4 - upper; - else // Down - return 1 + upper; - else // Left - if (gy>0) // Up - return 5 + upper; - else // Down - return 8 - upper; -} - -int conic(int xs, int ys, int xe, int ye, - int A, int B, int C, int D, int E, int F, - ConicPlotter * plotterdata) -{ - A *= 4; - B *= 4; - C *= 4; - D *= 4; - E *= 4; - F *= 4; - - // Translate start point to origin... - F = A*xs*xs + B*xs*ys + C*ys*ys + D*xs + E*ys + F; - D = D + 2 * A * xs + B * ys; - E = E + B * xs + 2 * C * ys; - - // Work out starting octant - int octant = getoctant(D,E); - - int dxS = SIDEx[octant]; - int dyS = SIDEy[octant]; - int dxD = DIAGx[octant]; - int dyD = DIAGy[octant]; - - int bsign = BSIGNS[octant]; - int d,u,v; - switch (octant) { - case 1: - d = A + B/2 + C/4 + D + E/2 + F; - u = A + B/2 + D; - v = u + E; - break; - case 2: - d = A/4 + B/2 + C + D/2 + E + F; - u = B/2 + C + E; - v = u + D; - break; - case 3: - d = A/4 - B/2 + C - D/2 + E + F; - u = -B/2 + C + E; - v = u - D; - break; - case 4: - d = A - B/2 + C/4 - D + E/2 + F; - u = A - B/2 - D; - v = u + E; - break; - case 5: - d = A + B/2 + C/4 - D - E/2 + F; - u = A + B/2 - D; - v = u - E; - break; - case 6: - d = A/4 + B/2 + C - D/2 - E + F; - u = B/2 + C - E; - v = u - D; - break; - case 7: - d = A/4 - B/2 + C + D/2 - E + F; - u = -B/2 + C - E; - v = u + D; - break; - case 8: - d = A - B/2 + C/4 + D - E/2 + F; - u = A - B/2 + D; - v = u - E; - break; - default: - fprintf(stderr,"FUNNY OCTANT\n"); - abort(); - } - - int k1sign = dyS*dyD; - int k1 = 2 * (A + k1sign * (C - A)); - int Bsign = dxD*dyD; - int k2 = k1 + Bsign * B; - int k3 = 2 * (A + C + Bsign * B); - - // Work out gradient at endpoint - int gxe = xe - xs; - int gye = ye - ys; - int gx = 2*A*gxe + B*gye + D; - int gy = B*gxe + 2*C*gye + E; - - int octantcount = getoctant(gx,gy) - octant; - if (octantcount <= 0) - octantcount = octantcount + 8; - fprintf(stderr,"octantcount = %d\n", octantcount); - - int x = xs; - int y = ys; - - while (octantcount > 0) { - if (debugging) - fprintf(stderr,"-- %d -------------------------\n", octant); - - if (odd(octant)) { - while (2*v <= k2) { - // Plot this point - ((DebugPlotter*)plotterdata)->octant = octant; - ((DebugPlotter*)plotterdata)->d = d; - plotterdata->plot(x,y); - - // Are we inside or outside? - if (d < 0) { // Inside - x = x + dxS; - y = y + dyS; - u = u + k1; - v = v + k2; - d = d + u; - } - else { // outside - x = x + dxD; - y = y + dyD; - u = u + k2; - v = v + k3; - d = d + v; - } - } - - d = d - u + v/2 - k2/2 + 3*k3/8; - // error (^) in Foley and van Dam p 959, "2nd ed, revised 5th printing" - u = -u + v - k2/2 + k3/2; - v = v - k2 + k3/2; - k1 = k1 - 2*k2 + k3; - k2 = k3 - k2; - int tmp = dxS; dxS = -dyS; dyS = tmp; - } - else { // Octant is even - while (2*u < k2) { - // Plot this point - ((DebugPlotter*)plotterdata)->octant = octant; - ((DebugPlotter*)plotterdata)->d = d; - plotterdata->plot(x,y); - - // Are we inside or outside? - if (d > 0) { // Outside - x = x + dxS; - y = y + dyS; - u = u + k1; - v = v + k2; - d = d + u; - } - else { // Inside - x = x + dxD; - y = y + dyD; - u = u + k2; - v = v + k3; - d = d + v; - } - } - int tmpdk = k1 - k2; - d = d + u - v + tmpdk; - v = 2*u - v + tmpdk; - u = u + tmpdk; - k3 = k3 + 4*tmpdk; - k2 = k1 + tmpdk; - - int tmp = dxD; dxD = -dyD; dyD = tmp; - } - - octant = (octant&7)+1; - octantcount--; - } - - // Draw final octant until we reach the endpoint - if (debugging) - fprintf(stderr,"-- %d (final) -----------------\n", octant); - - if (odd(octant)) { - while (2*v <= k2 && x != xe && y != ye) { - // Plot this point - ((DebugPlotter*)plotterdata)->octant = octant; - ((DebugPlotter*)plotterdata)->d = d; - plotterdata->plot(x,y); - - // Are we inside or outside? - if (d < 0) { // Inside - x = x + dxS; - y = y + dyS; - u = u + k1; - v = v + k2; - d = d + u; - } - else { // outside - x = x + dxD; - y = y + dyD; - u = u + k2; - v = v + k3; - d = d + v; - } - } - } - else { // Octant is even - while ((2*u < k2) && (x != xe) && (y != ye)) { - // Plot this point - ((DebugPlotter*)plotterdata)->octant = octant; - ((DebugPlotter*)plotterdata)->d = d; - plotterdata->plot(x,y); - - // Are we inside or outside? - if (d > 0) { // Outside - x = x + dxS; - y = y + dyS; - u = u + k1; - v = v + k2; - d = d + u; - } - else { // Inside - x = x + dxD; - y = y + dyD; - u = u + k2; - v = v + k3; - d = d + v; - } - } - } - - - - return 1; -} - -main(int argc, char ** argv) -{ - DebugPlotter db; - db.xs = -7; - db.ys = -19; - db.xe = -8; - db.ye = -8; - db.A = 1424; - db.B = -964; - db.C = 276; - db.D = 0; - db.E = 0; - db.F = -40000; - conic(db.xs,db.ys,db.xe,db.ye,db.A,db.B,db.C,db.D,db.E,db.F, &db); -} diff --git a/16/PCGPE10/COPPER.PAS b/16/PCGPE10/COPPER.PAS deleted file mode 100644 index 1d791118..00000000 --- a/16/PCGPE10/COPPER.PAS +++ /dev/null @@ -1,361 +0,0 @@ -{$X+} -Program Copper; -Uses Crt; - - - -Type - ColType = Record - R, - G, - B : Byte; - End; - - PalType = Array[0..255] of ColType; - - BarType = Record - Col : Array[1..20] of ColType; - Pos : Array[1..20] of Byte; - UP : Array[1..20] of Boolean; - End; - - - -Var - Pal1 : PalType; - Bars : Array[1..40] Of BarType; - NumBars, NumLines : Byte; - - -Procedure Pal(Col, R, G, B : Byte); -Begin - Asm - mov dx, 3c8h - mov al, [Col] - out dx, al - inc dx - mov al, [R] - out dx, al - mov al, [G] - out dx, al - mov al, [B] - out dx, al - End; -End; - -Procedure GetPal(Col : Byte; Var R, G, B : Byte); -Var - Rt,Gt,Bt : Byte; -Begin - Asm - mov dx, 3c7h - mov al, [Col] - out dx, al - inc dx - inc dx - in al, dx - mov [Rt],al - in al, dx - mov [Gt],al - in al, dx - mov [Bt],al - End; - R := Rt; - G := Gt; - B := Bt; -End; - - - -Procedure WaitRetrace; Assembler; -Asm - mov dx,3DAh -@@1: - in al,dx - and al,08h - jnz @@1 -@@2: - in al,dx - and al,08h - jz @@2 -End; - - -Procedure SetPal(Var Palet : PalType); Assembler; -Asm - call WaitRetrace - push ds - lds si, Palet - mov dx, 3c8h - mov al, 0 - out dx, al - inc dx - mov cx, 768 - rep outsb - pop ds -End; - - -Procedure FadeOut(NoBars, BarSize : Byte); -Var - F, L : Integer; - PalFade : PalType; - -Begin - For F := 1 to NoBars do - For L := 1 to BarSize do - Begin - If Bars[F].Col[L].R > 0 Then Dec(Bars[F].Col[L].R); - If Bars[F].Col[L].G > 0 Then Dec(Bars[F].Col[L].G); - If Bars[F].Col[L].B > 0 Then Dec(Bars[F].Col[L].B); - End; -End; - - - -Procedure SetMcga; -Begin - Asm - mov ax, 0013h - int 10h - End; -End; - -Procedure SetText; -Begin - Asm - mov ax, 0003h - int 10h - End; -End; - - - -Procedure DrawCopper(NoLines, StartCol, YStart : Byte); -Var - Loop : Word; -Begin - For Loop := YStart to YStart + NoLines do - Begin - FillChar(Mem[$a000:Loop*320],320,StartCol+Loop-YStart); - End; -End; - - -Procedure SetCopperPal(NoBars, BarSize, YStart, ColStart, Space : Byte); -Var - Loop : Byte; - Loop2 : Word; - IncR : Byte; - RGB : Byte; - HalfBar : Byte; - -Begin - FillChar(Bars, SizeOf (Bars),0); - HalfBar := BarSize Div 2; - IncR := 63 Div HalfBar; - RGB := 0; - For Loop := 1 to NoBars do - Begin - For Loop2 := 1 to HalfBar do - Begin - If RGB = 0 Then - Bars[Loop].Col[Loop2].R := Loop2 * IncR; - If RGB = 1 Then - Bars[Loop].Col[Loop2].G := Loop2 * IncR; - If RGB = 2 Then - Bars[Loop].Col[Loop2].B := Loop2 * IncR; - - Bars[Loop].Pos[Loop2] := YStart + (Loop-1) * (BarSize+Space) + Loop2 -1 + ColStart; - Bars[Loop].UP[Loop2] := True - End; - - For Loop2 := HalfBar + 1 to BarSize do - Begin - If RGB = 0 Then - Bars[Loop].Col[Loop2].R := (BarSize - Loop2) * IncR; - If RGB = 1 Then - Bars[Loop].Col[Loop2].G := (BarSize - Loop2) * IncR; - If RGB = 2 Then - Bars[Loop].Col[Loop2].B := (BarSize - Loop2) * IncR; - - Bars[Loop].Pos[Loop2] := YStart + (Loop-1) * (BarSize+Space) + Loop2 -1 + ColStart; - Bars[Loop].UP[Loop2] := True - End; - - RGB := (RGB + 1) Mod 3; - End; - -End; - - - - -Procedure RotatePal(NoBars, BarSize, YStart, StartCol, NumLines : Byte; - Up : Boolean); - -Var - TPal : PalType; - TCol : ColType; - Loop, - Loop2 : Byte; - -Begin - FillChar(TPal, 768, 0); - For Loop := 1 to NoBars do - Begin - For Loop2 := 1 to BarSize do - Begin - TPal[Bars[Loop].Pos[Loop2]] := Bars[Loop].Col[Loop2]; - If Up Then - Begin - If Bars[Loop].Pos[Loop2] = StartCol Then - Bars[Loop].UP[Loop2] := False; - If Bars[Loop].Pos[Loop2] = NumLines Then - Bars[Loop].UP[Loop2] := True; - - If Bars[Loop].UP[Loop2] Then - Dec(Bars[Loop].Pos[Loop2]) - Else - Inc(Bars[Loop].Pos[Loop2]); - - End; - End; - - End; - SetPal(TPal); - -End; - - -Procedure SetUP(NumLines, NumBars, BarSize, YStart, ColStart, Space : Byte); -Begin - SetMcga; - DrawCopper(NumLines,ColStart,YStart); - SetCopperPal(NumBars, BarSize, YStart, ColStart, Space); -End; - - -Procedure DoItAll; -Var - NumLines, - NumBars, - BarSize, - YStart, - ColStart, - Space : Byte; - Loop : Byte; - -Begin - NumLines := 200; - NumBars := 10; - BarSize := 10; - YStart := 0; - ColStart := 1; - Space := 5; - SetUP(NumLines, NumBars, BarSize, YStart, ColStart, Space); - Repeat - RotatePal(NumBars, BarSize,YStart, ColStart, NumLines, True); - If KeyPressed Then - Begin - For Loop := 0 to 63 do - Begin - RotatePal(NumBars, BarSize,YStart, ColStart, NumLines, True); - FadeOut(NumBars, BarSize); - End; - Exit; - End; - Until False; -End; - - - -Procedure Creds; -Var - R, G, B : Byte; - R1, G1, B1 : Byte; - Loop : Byte; - -Begin - SetText; - While KeyPressed do ReadKey; - - Asm - mov ah, 1 - mov ch, 1 - mov cl, 0 - int 10h - End; - - GetPal(7,R,G,B); - Pal(7,0,0,0); - WriteLn('Copper Bars Trainer...'); - WriteLn; - WriteLn('By EzE of Asphyxia.'); - WriteLn; - WriteLn('Contact Us on ...'); - WriteLn; - WriteLn; - WriteLn('the Asphyxia BBS (031) - 7655312'); - WriteLn; - WriteLn('Email : eze@'); - WriteLn(' asphyxia@'); - WriteLn(' edwards@'); - WriteLn(' bailey@'); - WriteLn(' mcphail@'); - WriteLn(' beastie.cs.und.ac.za'); - WriteLn; - WriteLn('or peter.edwards@datavert.co.za'); - WriteLn; - WriteLn('Write me snail-mail at...'); - WriteLn('P.O. Box 2313'); - WriteLn('Hillcrest'); - WriteLn('Natal'); - WriteLn('3650'); - R1 := 0; - G1 := 0; - B1 := 0; - For Loop := 0 to 63 do - Begin - WaitRetrace; - WaitRetrace; - Pal(7, R1, G1, B1); - If R1 < R Then Inc(R1); - If G1 < G Then Inc(G1); - If B1 < B Then Inc(B1); - End; - Asm - mov ah, 1 - mov ch, 1 - mov cl, 0 - int 10h - End; - -End; - - -Procedure Fadecurs; -Var - Loop : Byte; - R, G, B : Byte; -Begin - GetPal(7, R, G, B); - For Loop := 0 to 63 do - Begin - WaitRetrace; - WaitRetrace; - Pal(7, R, G, B); - If R > 0 Then Dec(R); - If G > 0 Then Dec(G); - If B > 0 Then Dec(B); - End; -End; - - -Begin - TextAttr := $07; - While KeyPressed do ReadKey; - FadeCurs; - DoItAll; - Creds; -End. \ No newline at end of file diff --git a/16/PCGPE10/CPUTYPE.TXT b/16/PCGPE10/CPUTYPE.TXT deleted file mode 100644 index d8cc7b34..00000000 --- a/16/PCGPE10/CPUTYPE.TXT +++ /dev/null @@ -1,245 +0,0 @@ - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Testing the Intel CPU Type ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - Written for the PC-GPE by Mark Feldman - e-mail address : u914097@student.canberra.edu.au - myndale@cairo.anu.edu.au - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ THIS FILE MAY NOT BE DISTRIBUTED ³ - ³ SEPERATE TO THE ENTIRE PC-GPE COLLECTION. ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Disclaimer ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ - -I assume no responsibility whatsoever for any effect that this file, the -information contained therein or the use thereof has on you, your sanity, -computer, spouse, children, pets or anything else related to you or your -existance. No warranty is provided nor implied with this information. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Introduction ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Believe it or not there are people in the world who still own 8088s! Heck I -only just upgraded my 286 to a 486SUX33 a couple of months ago. - -As we all know, 286's and below just don't make the cut anymore, and even -386's are becoming a thing of the past. Personally I think a program should -politely tell someone they are a phleb rather than unceremoniously hanging -their machine for them. - -This text file will show one mothed of detecting the CPU type. Unfortunately -I don't have a Pentium op code list so it'll only detect up to a 486. - -Most of the information in this file came from a well documented assembly -program available on various ftp sites called 80486.asm, written by Robert -Collins. I tried calling Robert for permission to use his original file, but -he appears to have moved house. - -ÚÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Method ³ -ÀÄÄÄÄÄÄÄÄÙ - -80186 chips and higher generate an interrupt 6 when they come across an -instruction they don't support, this provides us with a real simple method -of determining the cpu type (coupled with the trap interrupt it would -conceivably also allow us to write a Pentium emulator for the 80286, but -that's another story). We simply have to try execting a 486 command, if it -causes an interrupt 6 then we know the machine is a 386 or lower. - -The op codes used in the program below all modify the dx register. - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Op Code Machine Language Bytes Supported by ³ - ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ - ³ shl dx, 5 C1 E2 05 80186 and higher ³ - ³ smsw dx 0F 01 E2 80286 and higher ³ - ³ mov edx, cr0 0F 20 C2 80386 and higher ³ - ³ xadd dx, dx 0F C1 D2 80486 and higher ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -When an interrupt 6 is generated you have to modify the value of the IP -register which was pushed onto the stack when the interrupt occurred, -otherwise the CPU will go back to it after the interrupt and keep trying -to execute it. Each of the instructions in the table above are 3 bytes long -so our interrupt handler can simply add 3 to the IP value on the stack. - -Identifying an 8088 chip is even simpler. If you push the SP register onto -the stack the 8088 increments the SP value before it pushes it, the other -chips all increment it afterwards. So to test for the presence of an 8088 -push SP onto the stack and pop it off into another variable, say AX. If AX -and SP are not equal then the chip is an 8088. - -Keep in mind that you *MUST* check for the presence of an 8088 before -doing anything else. Attempting to execute an invalid op code on an 8088 -will cause it to hang. Each of the functions in the unit below check for -an 8088 first to prevent this happening. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ A Pascal Unit to Test the CPU Type ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The following pascal unit contains some functions your program can use to -make sure it's running on the right kind of machine. If your program will -only work on a 386 and higher (for example) then put this unit first in your -Uses clause and modify the unit's initialization code to terminate the -program if the wrong CPU type is detected. The unit's current initialization -simply test the CPU type and store it in the 'cpu' variable. - -{ - - CPUTYPE - A Pascal Unit to Test the CPU Type - By Mark Feldman u914097@student.canberra.edu - myndale@cairo.anu.edu.au - - Based on an original assembly program by Robert Collins. - - -} - - -Unit CPUTYPE; - - -Interface - -const CPU_8088 = 0; - CPU_80186 = 1; - CPU_80286 = 2; - CPU_80386 = 3; - CPU_80486 = 4; - CPU_UNKNOWN = -1; - -{ The cpu variable is initialised to the cpu type } -var cpu : integer; - -{ Isa8088 returns true only if cpu is an 8088 or 8086 } -function Isa8088 : boolean; - -{ Isa80186 returns true if cpu is an 80186 or higher } -function Isa80186 : boolean; - -{ Isa80286 returns true if cpu is an 80286 or higher } -function Isa80286 : boolean; - -{ Isa80386 returns true if cpu is an 80386 or higher } -function Isa80386 : boolean; - -{ Isa80486 returns true if cpu is an 80486 or higher } -function Isa80486 : boolean; - - - - -Implementation - -Uses Dos; - -var OldIntr6Handler : procedure; - valid_op_code : boolean; - -procedure Intr6Handler; -interrupt; -begin - valid_op_code := false; - - { Stoopid TP7 won't let me modify IP directly } - asm - add word ptr ss:[bp + 18], 3 - end; -end; - -function Isa8088 : boolean; -var sp1, sp2 : word; -begin - asm - mov sp1, sp - push sp - pop sp2 - end; - if sp1 <> sp2 then - Isa8088 := true - else - Isa8088 := false; -end; - -function Isa80186 : boolean; -begin - if Isa8088 then - Isa80186 := false - else - begin - valid_op_code := true; - GetIntVec(6, @OldIntr6Handler); - SetIntVec(6, Addr(Intr6Handler)); - inline($C1/$E2/$05); { shl dx, 5 } - SetIntVec(6, @OldIntr6Handler); - Isa80186 := valid_op_code; - end; -end; - -function Isa80286 : boolean; -begin - if Isa8088 then - Isa80286 := false - else - begin - valid_op_code := true; - GetIntVec(6, @OldIntr6Handler); - SetIntVec(6, Addr(Intr6Handler)); - inline($0F/$01/$E2); { smsw dx } - SetIntVec(6, @OldIntr6Handler); - Isa80286 := valid_op_code; - end; -end; - -function Isa80386 : boolean; -begin - if Isa8088 then - Isa80386 := false - else - begin - valid_op_code := true; - GetIntVec(6, @OldIntr6Handler); - SetIntVec(6, Addr(Intr6Handler)); - inline($0F/$20/$C2); { mov edx, cr0 } - SetIntVec(6, @OldIntr6Handler); - Isa80386 := valid_op_code; - end; -end; - -function Isa80486 : boolean; -begin - if Isa8088 then - Isa80486 := false - else - begin - valid_op_code := true; - GetIntVec(6, @OldIntr6Handler); - SetIntVec(6, Addr(Intr6Handler)); - inline($0F/$C1/$D2); { xadd dx, dx } - SetIntVec(6, @OldIntr6Handler); - Isa80486 := valid_op_code; - end; -end; - - -begin - if Isa8088 then - cpu := CPU_8088 - else if Isa80486 then - cpu := CPU_80486 - else if Isa80386 then - cpu := CPU_80386 - else if Isa80286 then - cpu := CPU_80286 - else if Isa80186 then - cpu := CPU_80186 - else - cpu := CPU_UNKNOWN; -end. diff --git a/16/PCGPE10/DMA_VLA.TXT b/16/PCGPE10/DMA_VLA.TXT deleted file mode 100644 index fba17757..00000000 --- a/16/PCGPE10/DMA_VLA.TXT +++ /dev/null @@ -1,506 +0,0 @@ - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - INTRO TO DMA by Draeden of VLA -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - - DMA means Direct Memory Access. You probably already know where and -why you use it, so I'll skip right down to the dirty stuff. This all -should speak for it's self, so... Enjoy. - - Draeden /VLA - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - To do a DMA transfer, you need to know a few things: - - 1) Address of the memory to access - - 2) Length of data to read/write - - This can all be put into a structure: - -STRUC DMAInfo - Page db ? - Offset dw ? - Length dw ? -ENDS - - Page is the highest 4 bits of the absolute 20 bit address of the memory -location. Note that DMA transfers CANNOT cross 64k page boundries. - - The Length is actually LENGTH-1; sending in a 0 will move 1 byte, -sending a 0FFFFh will move 64k. - - ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - ; IN: DX:AX = segment/offset address of memory area - ; - ;OUT: DH = Page (0-F) (DL is destroyed) - ; AX = Offset - ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -PROC MakePage - push bx - - mov bl,dh - shr bl,4 ;isolate upper 4 bits of segment - - shl dx,4 ;make segment into ABS address - add ax,dx ;add the offset and put it in AX - adc bl,0 ;complete the addition - - mov dh,bl ;put the PAGE where it goes - - pop bx ; DH:AX is now the PAGE:OFFSET address - ret -ENDP - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - Programming DMA channels 0 thru 3 -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - There are 3 ports that are DMA channel specific: - - 1) The Page register - 2) The DMA count (length) register - 3) The memory address (offset register) - - They are as follows: - -DMACH PAGE ADDRESS LENGTH - - 0 87h 0 1 - - 1 83h 2 3 - - 2 81h 4 5 - - 3 82h 6 7 - - - And now some general registers: - - DMA Mask Register: 0Ah -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - bit 7 - 3 = 0 Reserved - - bit 2 = 0 clear mask - = 1 set mask - - bits 1 - 0 = 00 Select channel 0 - = 01 select channel 1 - = 10 select channel 2 - = 11 select channel 3 - - USE: You must set the mask of the channel before you - can reprogram it. - - DMA Mode Register: 0Bh -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - bit 7 - 6 = 00 Demand mode - = 01 Signal mode - = 10 Block mode - = 11 Cascade mode - - bit 5 - 4 = 0 Reserved - - bit 3 - 2 = 00 Verify operation - = 01 Write operation - = 10 Read operation - = 11 Reserved - - bits 1 - 0 = 00 Select channel 0 - = 01 select channel 1 - = 10 select channel 2 - = 11 select channel 3 - - USE: Tell the DMAC what to do. Common modes are: - - 48h (Read operation, Signal mode) - Used to read data from host memory and send to whomever - polls it. - - 44h (Write operation, Signal mode) - Used to write data taken from a device to memory. - -DMA clear byte ptr: 0Ch -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - USE: Send a zero to reset the internal ptrs - - - - WHAT TO DO: -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - 1) Set the Mask bit for the channel - - mov al,4 - add al,[DMA_Channel] - out 0ah,al - - 2) Clear Byte Ptr - - sub al,al - out 0Ch,al - - 3) Set the DMA transfer mode - - mov al,48h ;MODE output (read) - add al,[DMA_Channel] - out 0Bh,al - - 4) Set the memory ADDRESS and LENGTH - - ; AX = offset - ; CX = Length - ;[DMA_Base] = port # of memory address - - mov dx,[DMA_Base] - out dx,al ;send lower byte address - mov al,ah - out dx,al ;send high byte address - - inc dl ;point to Count port - mov al,cl - out dx,al ;send low byte length - mov al,ch - out dx,al ;send high byte length - - 5) Set the DMA page - - ; AL = Page - - mov dx,[Dma_Page] - out dx,al ; write the Page - - 6) Clear DMA mask bit - - mov al,[byte DMA_Channel] - out 0Ah,al ; port 0Ah, DMA-1 mask reg bit - - 7) Program the other device that is going to use the DMA output/input - - - ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - ; This routine programs the DMAC for channels 0-3 - ; - ; IN: [DMA_Channel], [DMAbaseAdd], [DMApageReg] must be setup - ; [DAMBaseAdd] = Memory Address port - ; - ; dh = mode - ; ax = address - ; cx = length - ; dl = page - ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -PROC Prog_DMA03 NEAR - push bx - mov bx,ax - - mov al,4 - add al,[DMA_Channel] - out 0Ah,al ; mask reg bit - - sub al,al - out 0Ch,al ; clr byte ptr - - mov al,dh - add al,[DMA_Channel] - out 0Bh,al ; set mode reg - - push dx - - mov dx,[DMAbaseAdd] - mov al,bl - out dx,al ; set base address low - mov al,bh - out dx,al ; set base address high - - inc dx ;point to length - mov al,cl - out dx,al ; set length low - mov al,ch - out dx,al ; set length high - - pop dx - - mov al,dl - mov dx,[DmaPageReg] - out dx,al ; set DMA page reg - - mov al,[DMA_Channel] - out 0Ah,al ; unmask (activate) dma channel - pop bx - ret -ENDP - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - Programming DMA channels 4 thru 7 -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - Again, there are 3 ports that are DMA channel specific: - - 1) The Page register - 2) The DMA count (length) register - 3) The memory address (offset register - - They are as follows: - -DMACH PAGE ADDRESS LENGTH - - 4 8Fh C0h C2h - - 5 8Bh C4h C6h - - 6 89h C8h CAh - - 7 8Ah CCh CEh - - - And now some general registers: - - DMA Mask Register: 0D4h -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - bit 7 - 3 = 0 Reserved - - bit 2 = 0 clear mask - = 1 set mask - - bits 1 - 0 = 00 Select channel 4 - = 01 select channel 5 - = 10 select channel 6 - = 11 select channel 7 - - USE: You must set the mask of the channel before you - can reprogram it. - - DMA Mode Register: 0D6h -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - bit 7 - 6 = 00 Demand mode - = 01 Signal mode - = 10 Block mode - = 11 Cascade mode - - bit 5 - 4 = 0 Reserved - - bit 3 - 2 = 00 Verify operation - = 01 Write operation - = 10 Read operation - = 11 Reserved - - bits 1 - 0 = 00 Select channel 4 - = 01 select channel 5 - = 10 select channel 6 - = 11 select channel 7 - - USE: Tell the DMAC what to do. Common modes are: - - 48h (Read operation, Signal mode) - Used to read data from host memory and send to whomever - polls it. - - 44h (Write operation, Signal mode) - Used to write data taken from a device to memory. - -DMA clear byte ptr: 0D8h -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - USE: Send a zero to reset the internal ptrs - - - WHAT TO DO: (exactly the same thing, just different io PORTs) -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - 1) Set the Mask bit for the channel - - mov al,[DMA_Channel] ;because the DMA's are 4-7, bit #3 - out 0D4h,al ; is already set - - 2) Clear Byte Ptr - - sub al,al - out 0D8h,al - - 3) Set the DMA transfer mode - - mov al,[DMA_Channel] - sub al,4 - or al,48h ;MODE output (read) - out 0D6h,al - - 4) Set the memory ADDRESS and LENGTH - - ; AX = offset - ; CX = Length - ;[DMA_Base] = port # of memory address - - mov dx,[DMA_Base] - out dx,al ;send lower byte address - mov al,ah - out dx,al ;send high byte address - - add dl,2 ;point to Count port (seperated by 2) - mov al,cl - out dx,al ;send low byte length - mov al,ch - out dx,al ;send high byte length - - 5) Set the DMA page - - ; AL = Page - - mov dx,[Dma_Page] - out dx,al ; write the Page - - 6) Clear DMA mask bit - - mov al,[byte DMA_Channel] - and al,00000011b - out 0d4h,al ; port 0Ah, DMA-1 mask reg bit - - 7) Program the other device that is going to use the DMA output/input - - - ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - ; This routine programs the DMAC for channels 4-7 - ; - ; IN: [DMA_Channel], [DMAbaseAdd], [DMApageReg] must be setup - ; [DAMBaseAdd] = Memory Address port - ; - ; dh = mode - ; ax = address - ; cx = length - ; dl = page - ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -PROC Prog_DMA47 NEAR - push bx - mov bx,ax - - mov al,[DMA_Channel] - out 0D4h,al ; mask reg bit - - sub al,al - out 0D8h,al ; clr byte ptr - - mov al,[DMA_Channel] - sub al,4 - add al,dh - out 0D6h,al ; set mode reg - - push dx - - mov dx,[DMAbaseAdd] - mov al,bl - out dx,al ; set base address low - mov al,bh - out dx,al ; set base address high - - add dl,2 ;point to length - mov al,cl - out dx,al ; set length low - mov al,ch - out dx,al ; set length high - - pop dx - - mov al,dl - mov dx,[DmaPageReg] - out dx,al ; set DMA page reg - - mov al,[DMA_Channel] - and al,00000011b - out 0D4h,al ; unmask (activate) dma channel - pop bx - ret -ENDP - - ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - ; This routine programs the DMAC for channels 0-7 - ; - ; IN: [DMA_Channel], [DMAbaseAdd], [DMApageReg] must be setup - ; [DAMBaseAdd] = Memory Address port - ; - ; dh = mode - ; ax = address - ; cx = length - ; dl = page - ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -PROC Prog_DMA NEAR - push bx - mov bx,ax - - cmp [DMA_Channel],4 - jb @@DoDMA03 - - mov al,[DMA_Channel] - out 0D4h,al ; mask reg bit - - sub al,al - out 0D8h,al ; clr byte ptr - - mov al,[DMA_Channel] - sub al,4 - add al,dh - out 0D6h,al ; set mode reg - - push dx - - mov dx,[DMAbaseAdd] - mov al,bl - out dx,al ; set base address low - mov al,bh - out dx,al ; set base address high - - add dl,2 ;point to length - mov al,cl - out dx,al ; set length low - mov al,ch - out dx,al ; set length high - - pop dx - - mov al,dl - mov dx,[DmaPageReg] - out dx,al ; set DMA page reg - - mov al,[DMA_Channel] - and al,00000011b - out 0D4h,al ; unmask (activate) dma channel - pop bx - ret - -@@DoDMA03: - mov al,4 - add al,[DMA_Channel] - out 0Ah,al ; mask reg bit - - sub al,al - out 0Ch,al ; clr byte ptr - - mov al,dh - add al,[DMA_Channel] - out 0Bh,al ; set mode reg - - push dx - - mov dx,[DMAbaseAdd] - mov al,bl - out dx,al ; set base address low - mov al,bh - out dx,al ; set base address high - - inc dx ;point to length - mov al,cl - out dx,al ; set length low - mov al,ch - out dx,al ; set length high - - pop dx - - mov al,dl - mov dx,[DmaPageReg] - out dx,al ; set DMA page reg - - mov al,[DMA_Channel] - out 0Ah,al ; unmask (activate) dma channel - pop bx - ret -ENDP diff --git a/16/PCGPE10/DOOM.TXT b/16/PCGPE10/DOOM.TXT deleted file mode 100644 index 3e2f25fa..00000000 --- a/16/PCGPE10/DOOM.TXT +++ /dev/null @@ -1,505 +0,0 @@ - -****************************************************************************** -* 'Doom' 3D Engine techniques * -****************************************************************************** -By Brian 'Neuromancer' Marshall -(Email: brianm@vissci.demon.co.uk) - - This document is submitted subject to certain conditions: - -1. This Document is not in any way related to Id Software, and is - not meant to be representive of their techniques : it is based - upon my own investigations of a realtime 3d engine that produces - a screen display similar to 'Doom' by Id software. - -2. I take no responsibility for any damange to data or computer equipment - caused by attempts to implement these algorithms. - -3. Although I have made every attempt to ensure that this document is error - free i take no responsability for any errors it may contain. - -4. Anyone is free to use this information as they wish, however I would - appreciate being credited if the information has been useful. - -5. I take no responsability for the spelling or grammar. - (My written english is none too good...so I won't take offence - at any corrections: I am a programmer not a writer...) - - Right now that that little lot is out of the way I will start this -document proper.... - -1: Definition of Terms -====================== - - Throughout this document I will be making use of many graphical terms -using my understanding of them as they apply to this algorithm. I will -explain all the terms below. Feel free to skip this part.... - -Texture: - A texture for the purpose of this is a square image. - -U and V: - U and V are the equivelants of x and y but are in texture space. -ie They are the the two axies of the two dimensional texture. - -Screen: - For my purposes 'screen' is the window we wish to fill: it doesn't -have to be the whole screen. - -Affine Mapping: - A affine mapping is a texture map where the texture is sampled -in a linear fashion in both U and V. - -Biquadratic Mapping: - A biquadratic mapping is a mapping where the texture is sampled -along a curve in both U and V that approximates the perspective transform. -This gives almost proper forshortening. - - -Projective Mapping: - A projective mapping is a mapping where a changing homogenous -coordinated is added to the texture coordinateds to give (U,V,W) and -a division is performed at every pixel. This is the mathematically and -visual correct for of texture mapping for the square to quadrilateral -mappings we are using. - (As an aside it is possible to do a projective mapping without -the divide (or 3 multiplies) but that is totally unrelated to the matter -in hand...) - -Ray Casting: - Ray Casting in this context is back-firing 'rays' along a two -dinesional map. The rays do however follow heights... more on that later - -Sprite: - A Sprite is a bitmap that is either a monster or an object. To -put it another way it is anything that is not made out of wall or -floor sectins. - -Sprite Scaling: - By this I mean scaling a bitmap in either x or y or both. - -Right... Now thats over with onto the foundation: - -2: Two Dimensional Ray Casting Techniques -=========================================== - - In order to make this accessible to anyone I will start by -explaining 2d raycasting as used in Wolfenstein 3d style games. - - 2.1: Wolfenstien 3D Style Techniques... - ======================================= - - Wolfenstein 3d was a game that rocked the world (well me anyway!). - It used a technique where you fire a ray accross a 2d grid based map to - find all its walls and objects. The walls were then drawn vertically - using sprite scaling techniques to simulate texture mapping. - - The tracing accross the map looked something like this; - - - ============================================= - = = = = = = /= = = = = = - = = = = = = / = = = = = = - = = = = = =/ = = = = = = - ====================/======================== - = = = = = /= = = = = = = - = = = = = / = = = = = = = - = = = = =/ = = = = = = = - ================/============================ - = = = = /# = = = = = = = - = = = = / # = = = = = = = - = = = =/ # = = = = = = = - ============/===#########==================== - = = = /= = = # = = = = = - = = = / = = = # = = = = = - = = =/ = = = # = = = = = - ========/===============#==================== - = = /= = = = # = = = = = - = = P = = = = # = = = = = - = = \= = = = # = = = = = - ========\===============#==================== - = = =\ = = = # = = = = = - = = = \ = = = # = = = = = - = = = \= = = # = = = = = - ============\=======#####==================== - = = = =\ = # = = = = = = - = = = = \ = # = = = = = = - = = = = \= # = = = = = = - ================\===#======================== - = = = = =\ # = = = = = = - = = = = = \ # = = = = = = - = = = = = \# = = = = = = - ============================================= - - (#'s are walls, = is the grid....) - - This is just a case of firing a ray for each vertical - line on the screen. This ray is traced accross the map to - see where it crosses a grid boundry. Where it crosses a - boundry you cjeck to see if there is a wall there we see how - far away it it and draw a scaled vertical line from the texture - on screen. The line we draw is selected from the texture by - seeing where the line has intersected on the side of the square it - hit. - This is repeated with a ray for each vertical line on the - screen that we wish to display. - This is a very quick explaination of how it works missing - out how the sprites are handled. If you want a more detailed - explaination then I suggest getting acksrc.zip from - ftp.funet.fi in /pub/msdos/games/programming - - This is someone's source for a Wolfenstien engine written - in Borland C and Assembly language on the Pc. - Its is not the fastest or best but has good documentation - and solves similiar sprite probelms, distance probelms and has - some much better explaination of the tracing technique tahn I have - put here. I recommend to everyone interested taht you get a copy - and have a thorough play around with it. - (Even if you don't have a Pc: Everything but the drawing and video - mode setting is done in 'C' so it should not be too hard to port - ....) - - - 2.2 Ray Casting in the Doom Environment - ======================================= - - When you look at a screen from Doom you see floors, steps - walls and lots of other trappings. - You look out of windows and accross courtyards and you - say WOW! what a great 3d game!! - Then you fire your gun a baddie who's in line with you but - above you and bang! he's a corpse. - Then you climb up to the level where the corpse is and look - out the window to where you were and you say Gosh! a 3d game!! - - Hmmm.... - - Stop gawping at the graphics for a minute and look at the map - screen. Nice line vectors. But isn't the map a bit simple??? - Notice how depite colours showing you that there are different - heights. Then notice that despite the fact that there is NEVER a - place where you can exist on two different levels. Smelling a little - 2d yet??? - Look where there are bridges (or sort of bridges) : managed to - see under them yet?? - - The whole point to this is that Doom is a 2D games just like - its ancestor Wolfenstein but it has rather more advanced raycasting - which does a very nice job of fooling the player into thinking its a - 3d game that shifting loads of polygons and back-culling, depth - sorting etc... - - Right the explaination of how you turn a 2d map into the 3d - doom screen is complex so if you are having difficulty try reading - it a few times and if all else fails mail me.... - - - 2.3 What is actually done! - ========================== - - Right to start with the raycasting is started in the same - way as Wolfenstien. That is find out where the player is in the 2d - map and get a ray setup for the first vertical line on the screen. - - Now we have an extra stage from the Wolfenstein I described - whcih involves a data srtucture that we will use later to actually - draw the screen. - - In this data structure we start the ray off as at the bottom - of the screen. This is shown in the diagram below; - - ================================= - = = - = = - = = - = = - = = - = = - = = - = = - = = - = = - = = - = = - = = - = = - = = - = = - =* = - ================================= - - - Where the '=' show the boundry of the screen and '*' is the virtual - position of the ray. - - Note: the Data structure is really two structures: - One which is a set of list for each vertical 'scanline' and - One which is a corresponding list for horizontal scanlines. - - Now we start tracing the ray. We skip accross the 2d map until - we hit something interesting. By something interesting I mean something - that is an actual wall or florr section edge. - Right we have hit the edge of either a floor or wall section. - We have several things to do know. These are; - - If it was a wall we hit: - - 1: Find out how 'high' of screen this section of wall should be - due to the distance it is accross the 2d map. - 2: Find out at what 'virtual height' it is: This is so that we can see - where in the vertical scanline in comes for testing where to insert - it and for clipping it. - 3: Test in our structure to see if you draw it or not. - (This is done so that you can look through windows : how this works - will become apparent later.) - 4: If any of the wall segment is visible then we find out where along - the texture we have hit it and write into the structure the area of - the screen it takes up as well as the texture, the point where we - have hit the texture and the size it should be on screen. (This is - so that we can draw it correctly even if the whole span is not on - screen. - - - If it was a floor section that we hit: - - 1: Find out where on the vertical line we are working the floor section - that the ray has hit is. (We know the height of the the floor in the - virtual map (2d) and we know the height of the player and the distance - of the floor square from the player so it is easy). - As a side effect of this we now know the U,V value where the ray has - hit the floor square. - - 2: Trace Accross the floor square till we hit the far edge of the floor - square : we then workout where this is on the vertical scanline using - the same technique as above. We now know the vertical span of the - floor section, and where on the span it is. - - 3: We check to see if the span is visible on the vertical span. - If it is or part of it is used then we mark that part of the vertical - scanline as used. - We also have to make use of the horizontal buffer I mentioned. We - insert into this in 2 places. The first is the x coordinate of where - we hit the floor square into the y line where we where on the screen. - Phew got that bit?? We also insert here the U,V value which we knew - from the tracing. (I told you we'd need it later....) - - - As you can see there's a little more to hiting a floor segment than -a wall segment. Also note that a you exit a floor segment you may also hit -a wall segment. - - Tracing the individual ray is continued until we hit a special kind -of wall. This wall is marked as a wall that connects to the ceiling. -This is one place to stop tracing this ray. However we can stop tracing early -if we have found enough to fill the whole vertical scanline then we can stop -whenevr we have done this. - - Next come a trick. I said we were tracing along a 2d map. Well I -lied a bit. There are (In my implementation at least..) TWO 2d maps. One is -basically from the floor along including all the 'floor' walls and everything -up to and including the walls that join onto the ceiling. The other map -is basically the ceiling (with anything coming down from the ceiling on it -if you are doing this: this makes life a little more complex as I'll explain -below..) - Now when we have traced along the bottom map and hit a wall that -connects to the ceiling then we go back and trace along the ceiling from -the start to fill in the gaps. There is a problem with this however. -The problem is when you have things like a monolith or something else built -out of walls jutting down from the ceiling. you have to decide whether to -draw it or draw whatever was already in the scanline structure. This means -either storing extra information in the buffer ie z coordinates or tracing -along both the ceiling and floor at the same time.... for most people I would -suggest just not having anything jutting down from the ceiling. - Also you could trace backwards instead of starting a new ray. This -would be fasterfor many cases as you wouldn't be tracing through lots -of floor squares that aren't on screen. By tracing backwards you can keep -going up the vertical scanline and you know that you are on the screen. As -soon as something goes off the top of the screen you can handle that and then -stop tracing. - - Phew. has everyone got that??? - - Now we just go back and fire rays up the rest of the vertical -scanlines. Easy!!??? - - At the end of this lot we have the necessary data in the two buffers -to go back and draw the screen background. -(There is one more thing done while tracing but I'll explain that later...) - - - Oh... one other thing... you have may want to change the raycasting -a bit to subdivide the map... it helps with speed. - And don't forget the added complexity that walls aren't all at -90 degrees to each other... - -3: Drawing the walls and Why it works!! -======================================= - - If you are familiar with Wolfenstein then please still read this -as it is esential background to understanding the floor routine. - - - As all of you probably know the walls are drawn by scaling the line -of the texture to the correct size for the screen. The information in the -vertical buffer makes this easy. What you probably don't know is why this -creates texture mapping that is good enough to fool us. - - The wall function is a Affine texture mapping. (well almost) -Now affine texture mappings look abysmal unless you do quite a lot of -subdivision (The amount needed varies according to the angle the projected -square is at.). So why does the Doom technique work?? - - Well when we traced the rays we found out exactly where along the -side of the square we hit we were in relation to the width of the texture. -This means that the top and bottom pixels of the scaled wall piece are -calculated correctly. This means that we have effecively subdivided the -texture along vertical scanlines and as the effective subdidvisons are -calculated exactly with proper forshortening as a result of the tracing. -So the ray casting has made the texture mapping easy for us. - (We have enough subdivision by this scanline effect as the wall -only rotates about one axis and we have proper foreshortening.) - - This knowlege helps us understand how to do the floors and why -that works. - - We can now draw all the wall segments by just looking at the buffer -and drawing the parts marked as walls.(Skiping where we put in the bits used -by the floor/ceiling bits: we draw them later.) - -4: Drawing the Floor/Ceiling and why it works! -=============================================== - - If you have grasped why the walls work then you have just about -won for the floors. - We have the information needed to draw the floors from the horizontal -buffer. - All we have to do is look at the horizontal spans in the buffer -and draw them in all. - Each of these spans has 2 end coordinates for which we have -exact texture coorinates. This tells us which line across the texture -we have to step along to do an Affine or linear mapping. - This is shown below; - - - ================================= - = = - = = - = = - = = U1,V1 (exit) - = ** - = *** = - = *** = - = *** = - = *** = - = *** = - = *** = - = *** = - = ** = - = ** = - = ** = - = ** = - U0,V0 ** = -(entry) = = - = = - = = - = = - = = - = = - = = - ================================= - -(apologies for the wonky line: it should be straight!!) - - Now...as the end coordinates are correct and the axis along -which forshortening takes place is not involved (this is a fudge) -we can step linearly along this line across the texture to approximate -the mapping. (This is far easier than a proper texture map). - This is effectivly a wall lying on its side which works as the -texture coordinates at the ends of the span have been calculated correctly. -This is a benefit of the raycasting we used to find everything. - Easy huh?? - - -5: Sprites -========== - - The Sprites are really quite easy to do. The basic technique is the -same as used in Wolfenstein 3d. - This is done as follows: - -When you enter a 'square' on the floor map you test to see if there are -any sprites in the square. If there are you flag that sprite as visible -and add it to a list of visible sprites. - -When you have finished tracing and drawing the walls and floor you -depth sort the sprites and draw them from the back to the front. (painters -algorithm). The only complication in drawing them is that you have to check -buffer that has the walls in, in order to clip the sprites correctly. - - (If you're interested in Doom you can occasionally see large -explosions (ie BFG) slip partially behind a wall segment.) - - On possibly faster way of handling the sprites would be to mark -them like wall segments as you find them in the buffer. The only (ONLY!) -complication to this approach is that sprites can have holes in them. By -this I mean things like the gap between an arm and a leg which should be -the background colour. - - -6: Lighting and Depth Cueing -============================ - - Lighting and Depth Cueing fits nicely in with the way that we have -prepared the screen ready for drawing. - All we have to do is see how far away we are when we found either -the floor or wall section and set the light level according to the distance. - The other thing that is applied is a light level. This is taken from -the map at the edges where you have hit something. As the map is 2D it is -easy to manage lighting, flickering etc. - For things like pools of light on the floor all you have to do -is subdivide that patch of floor so that you can set the bit under the -skylight to a lighter colour. Its also very easy to frig this for the -lighting goggles. - - -7: Controlling the Baddies -========================== - - - This is pretty easy: all you have to think about is moving and -reacting on a 2d map. the only complications are things like the monsters -looking through windows and seeing a player but this all degenerates into -a simple 2d problem. Things like deciding whether the player has been hit or -has he/she hit a monster is just another case of firing a ray. (Or do it -another way...) - - -8: Where next??? -================ - - Thats all folks... hopefully a useful and intersting insight into -my Doom engine works. - As to the question where next... well I already have some enhancements -to my Doom enigine and others are in the works... - -Some of what you may eventually see are: - - Proper lighting (I have done this already...its easier than you - think) - Non-Vertical walls (i.e. Aliens style corridors...) - Orgranic Walls (i.e. Curved like the Aliens nest...) - Fractal Landscapes (This one is still very much a theory but how - about being able to go outside and walk up and down - hills etc??) - - If there are bits people are really shaky about I may post a new -version of this... but I cannot get into implimentation issues as all -implementation work is under copyright... - - By the way if anyone out there implements this I'd love to here -how you get on... - - Anyone got any comments or any other interesting algorithms??? - -Brian 'Neuromancer' Marshall 'When do graphics not look like graphics? -( Email: brianm@vissci.demon.co.uk ) :when we get it RIGHT.' diff --git a/16/PCGPE10/DPMI16BI.OVL b/16/PCGPE10/DPMI16BI.OVL deleted file mode 100644 index 61e5742a08e19cfb606777dfb1153cacea1ce1c7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63504 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 cable ->|<---- MIDI IN port +5V - 270 | - +5V DIN DIN +--\/\/\/-+ - | 220 +-+ +-------+ +-+ 220 +--------+ | - |\ +-\/\/\/--|4|-|-------|-|4|--\/\/\/--| OPTO |-+-+- UART RXD - UART | \ | | | | | | |ISOLATOR| | - TXD ---| \---\/\/\/--|5|-|-------|-|5|----------| |-+ | - | / 220 | | +-------+ | | +--------+ | | - | / +--|2|-+ +-|2| 6N138 GND| - |/ 7407 | +-+ +-+ | - GND | - | - +-------------------------------------------+ - | - | +5V DIN - | | 220 +-+ - | |\ +-\/\/\/--|4| - | | \ | | - +--| \---\/\/\/--|5| MIDI THRU - | / 220 | | - | / +--|2| - |/ 7407 | +-+ - GND - - Note that when the UART TXD is high, no current flows through -the resistors and optoisolator's LED, causing the optoisolator's -phototransistor to remain off, allowing the UART RXD to be pulled high -by the 270 ohm resistor. When the UART TXD is low, current flows -through the resistors and optoisolator's LED, turning on -optoisolator's phototransistor, grounding the UART RXD. The voltage -drop across the optoisolator's LED is typically 1.5 volts, leaving 3.5 -volts to be dropped across (3 times 220) 660 ohms, which allows about -5 ma to flow. - - The reason a current loop is used is that it allows an ground -isolated interconnection. Note that the ground from the MIDI OUT -port's device is not connected to the ground of the MIDI IN port's -device. This prevents ground loops in systems where appropriate -attention has not been paid to grounding issues, such as the case of -typical musicians in a typical club! - -Gravis Ultrasound Circuit -========================= - -15 pin D connector - 220R -pin-1 +5v ----+--------------------------/\/\/\---------------\ - | \ 4 - | Gnd--2 MIDI OUT - | |\ |\ 220R / 5 -pin-12 tr >---|------| o-----| o----------/\/\/\--------------/ - | 13|/ 12 11|/ 10 - | 220R - +---------------------------/\/\/\-------------\ - | \ 4 -pin-15 rx <---|--------------------+ Gnd--2 MIDI THRU - | |\ |\ | 220R / 5 - | +--| o-----| o---+-------/\/\/\------------/ - | | 1|/ 2 3|/ 4 - | | - | +------+ - | 270R | 220R - +--/\/\/\--+ +------+----------/\/\/\--------\ - |B |C |A | \ 4 - +-|----------|----|-+ | MIDI IN - | 8 6 2 | ----- / 5 - | | / \ IN914 or IN4148 +-/ - | 6N138 | --- | - | | | | - | 5 3 | | | - +------------|----|-+ | | - | |K | | -pin-5 Gnd --------------+ +------+----------------------+ - - Inverters are 74LS04. (This is a 14-pin IC containing 6 -inverters. Connect pin 14 to +5V, pin 7 to GND) - - Leave pin 2 of the MIDI IN unconnected (Don't connect to ground). - -Some hints for testing your circuit -=================================== - - 1] Check *all* connections (use a continuity tester, and tick -them off on a printout of the circuit). - - 2] Check them again ;-) - - 3] Make sure you have the latest (GUS0012.zip) windows midi -driver, and make sure it is installed properly. - - 4] Make sure your midi sequencer package is set up to use the -Ultrasound Midi In/Out ports. (As opposed to the Ultrasound Synth) - - 5] If you still have no joy, - - a] Just connect the +5V and GND to your midi circuit, - (leave the d-connector pins 12 and 15 unconnected), and then - connect pin 13 of the 7404 to +5V check you have (about) +5V - appearing on pin 10. This checks midi out. - - b] Connect pin 4 of the midi-in DIN socket via 2 extra - 220R resistors to +5V. Check pin 4 of the 7404. It should be - low (about 0V). Then connect pin 4 of the midi-in DIN socket - to 0V. Pin 4 of the 7404 should go high. This checks midi in. - - c] Reconnect the d-type pins 12 and 15, and connect a - midi cable between midi-out on the circuit and and midi-in on - your synth. Set up your sequencer to use the Ultrasound MIDI - port as an output, and ensure that one of the tracks is set to - use this port. Check your synth is expecting MIDI data on the - same channel as sequencer is transmitting. Start sequencer - playing. Check that midi data is being transmitted at pin 12 - of the d-type (look at it with an oscilloscope, if possible). - -Note -==== - - Standard disclaimers apply - use this information at your own -risk, and if your fry your card/PC/synth/toaster, then you have my -sympathy, but not much else ;-) - - If you're not happy about messing with circuits and soldering -irons and wires and stuff, then you may wish to wait for the midi -connector box from Gravis to become available. - - I notice that in the older FAQs, there is a description (from -Dustin Caldwell ) of the solder side pinout for a -15-pin D-type connector. This looks wrong to me. I have a 15-pin male -d-type in from of me, and it looks like this from the solder side -(i.e. the side you attach the wires to, rather than the side with the -pins that plugs into the card): - - Gnd +5V - 8 7 6 5 4 3 2 1 - +-----/-------------------------------\-----+ - | \ o o o o o o o o / | - | ( ) \ / ( ) | - | \ o o o o o o o / | - +--------\-------------------------/--------+ - 15 14 13 12 11 10 9 - Rx Tx - - It is easy to get the pins confused on these connectors - the -female version seen from the solder side of course has everything the -other way around (pin 1 is on the left hand side). - - Hope this helps (or at least doesn't add to the confusion :-). -All reasonable quality D-type connectors have pin numbers marked -against the pins anyway. - ----------------------------------------------------------------------- - -13] What exactly is GUS 3D? - - First and foremost: YES, this is SOFTWARE. You will NOT need -to upgrade your GUS to be able to do the GUS-3D stuff. - -Written By: dionf@ERE.UMontreal.CA (Francois Dion) - - There are several systems that are in use to get 3D sounds on -recordings and some have been around since the 50s. Now i wont go into -the "how it works" of the more recent ones, but i think this will -clear up some confusion. The first part is a "hands-on" experiment, -the second is informations, including the address and phone of the -owner of the technology that is used with the Gravis Ultrasound. - - Let's get back to the early days of stereo. One record company -(i cant seem to remember) was pushing it, while another (again, blank. -anyone?) competed. Interestingly enough, technological development -was put on stereo, and not on the first 3D system which was called -"binaural recording" and it simply consisted of two microphones placed -like the ears. You can try it this way: - - Go to a hat store and buy an extruded foam mannequin head. -You'll then need two microphones. Condenser will do, but you will need -to power them if you want to use them with the GUS, since it take a -dynamic microphone because it does not supply phantom power like some -mixer with XLR plugs. I will post a circuit later for Radio-shack -condenser mike unit (a small element that cost about 2$) if there is -some interest. If you dont want to mess with that, go with a cardiod -dynamic element. Note that sensitive enough cardiod will cost you a -lot, so think about that. You cut holes in the ears of the head, to -insert the microphone units (dont forget to make the wires of the -elements go inside the head and out the rear (or wherever). Use glue -to fill the crack around the mic. Also, the more the ears look like -real ears, the better it will work. If you trim the foam, dont forget -to use an hairdryer to soften it (it will be more uniform). That's it. -Try recording sounds, and you'll be surprised. I was! I did the -experiment with a polystyrene head on which i incrusted two PZM -microphones. - - Now that you understand how 3D recording is nothing like -stereo recording, we'll see what is accesible presently. - - First, the gadget we just built in the previous section exist -commercially, and is called "Mikey" and is made by Spherical Sound. -It's the only system commercialised where the microphones are placed -in a head. - - Another system is made by Virtual Audio and claims to enhance -stereo depth, but is not labeled 3D audio. I dont have much more info -on it, but from the description it looks like the same thing as the -"mikey". - - Two other systems use less restraining microphones situation -and can also be used on any signal because a DSP simulate a 3D signal -from parameters entered on the machine. QSound (no hyphen) was -developped in Quebec, and the inventor sold the concept to another -company (Archer it seems). It is not that good even with electrostatic -headphones, and is pretty bad if you are listening to it thru speakers -and you are not in the sweet spot. And for trivia: Madonna, Sting, -Wilson Phillips and Paula Abdul to name a few have used the QSound on -their latest recordings. Another trivia: The Q logo is very very close -to Hydro-Quebec logo... QSound cost around 18K$ and is not midi -controllable. - - The other variant with a DSP is Roland RSS (Roland Sound -Space). It is a bit better (depending on how it is used) than QSound -with headphones, but suffers the same faith as QSound when you are -listening with speakers. Just move a bit from the sweet spot, and -suddenly what was in front left is now back left. RSS was used on -Suzanne Cianni _Hotel Luna_ album. RSS cost around 40K$ and is midi -controllable. - - Another system on which i have zero information is called -Audio Cybernetics. - - The last technology is called Focal Point 3D Audio. It was -developped by Bo Gehring and first used on the Macintosh computers -with a modified Audiomedia (Digidesign). It cost around 1400$ in this -configuration. But, Gravis saw that (Focal Point is from Seattle) and -it is the system that we will be getting. At a much better price. The -system produce the sounds with these parameters: direction, elevation -and distance. I am pretty sure that Gravis will have to develop a -SYSEX command set. We already need it badly, but with 3D, i will shoot -myself if i cant control it thru sysex. - - By the way, here's how to get in touch with Focal Point 3D -Audio, if you're interested. - - Focal Point(tm) 3D audio - 1402 Pine av., #127 - Niagara Falls, NY 14301 - Voice/fax: 1-416-963-9188 - - Ok, you have read the 3D thing, and you cant wait. You want -big sound. The only possibility for now is surround. Now surround cost -a lot of money, and it will not be useable anymore once you get the 3D -driver. Wrong. - - Now, i hope you have an amplifier, cause if you dont, you -can't use this little hack to get surrounding sound. WARNING: i am not -responsible for any damage resulting from the use or misuse or -anything else related to this circuit. Check that your - posts are -connected to ground and not the +. If it's the case reverse the -connections to the amplifier. - - It works surprisingly well considering the cost. Have fun! - - | Amplifier | - | + - - + | You connect the front speakers as usual (dont mixup - /| | | |\ the polarities!) _ - | |_| |_| | FLS: Front left speaker (/_\) - | /_\ /_\ | FRS: Front right speaker - | FLS FRS | R: variable pot 50 ohm. 10 watts or more (depends on - |_ _| the amplifier) - > | | < - ><'R R'>< RLS: Rear left speaker (use a much smaller speaker - > < for rear than front. 8 ohm also.) - | RLS RRS | RRS: Rear right speaker (") - | _ _ | - | \_/ \_/ | the 2 - on front speakers are connected to the - |_/ \_._/ \_| ground of the amplifier internally, so you dont - + -|- + have to connect them. - |_ - > | - ><'R - > Here, you do need to connect the 2 - thru R to the - _|_ amplifier ground. - - AMP GND - - Put the 3 potentiometer in a box so that you have the control -in one place, and use enough wire so you can move with it. You'll have -to experiment so that the R going to ground is a little higher than -the other 2 and once that adjusment made, the other two must be -adjusted so that the rear speakers are just adding a touch of depth -(if you turn them off, you notice that the surround is gone). Also, if -you have A-B speaker selection, plug the rear speakers on the + of B -instead of A, you will then be able to switch them off easily. Of -course, when you will use the 3D audio, it will affect the signal, so -it's better to unplug the rear section. But for your video, tape, CD -and regular GUS, you will still find it cool. - ----------------------------------------------------------------------- - -14] What are *.PAT *.VOC *.WAV *.SND *.MOD *.669, and *.MID files, and - how do I use them? - -Written by: Matthew E. Bernold - - These are all different types of sound files. - - *.PAT files are GUS instrument files, or PATCH files. These -files are what your GUS uses to recreate the various instruments it is -capable of playing. Your .PAT files should be in your /ULTRASND/MIDI -and /ULTRASND/SBOS directories. - - *.VOC and *.WAV files are basic digital sound files with -headers. The *.VOC files are used on the soundblaster, and the *.WAV -files are used by Microsoft Windows. Players capable of using these -formats can read information on sampling rate, 8 or 16 bit, and -mono/stereo from the header of these files. *.WAV files can be played -in MS Windows by many programs. *.VOC files can be converted to *.WAV -by many different programs, including SOX which is available via FTP. -The latest version (7.0) has been ported to PC clones and can be found -on the GUS FTP sites. - - *.SND files are raw sound files with no header information. -This is the format currently used by the GUS. This means that you -have to tell the player program about the sample, because the -information on how to play it is NOT in the file, like with the *.VOC -or *.WAV files. You can play these files using PLAYFILE which came -with the GUS. - - *.MOD files are 4-voice 15 or 31 instrument music files which -originated on the Amiga. They use 8-bit, 16kHz samples to produce the -instruments, and note information to play the songs. *.MOD files are -similar to MIDI files, but they are a bit more flexible because you -can use any sample as an instrument (including voices and sound -effects) instead of relying on the MIDI synth's own built in -instruments. You can play these files using GUSMOD which can be found -on epas. - - *.669 files are 8-voice music files. I don't know much about -them, so maybe Tran (author of the GUS 669 player) can fill in this -area. You can play these files using P669GU0 which can be found on -epas. - - *.MID files are MIDI files. You can play these files with -PLAYMIDI that came with the Ultrasound package, or with MediaPlayer in -MS Windows. You might have to create a *.cfg file for the MIDI file -if it was originally created for a synth that does not conform to the -GM Midi standard. - ----------------------------------------------------------------------- - -15] What exactly is Wavetable Synthesis? - -Written By: dionf@ERE.UMontreal.CA (Francois Dion) - - It is easier to find the Holy Grail than to find a text -describing precisely what synthesis method the GUS uses, so it's time -i take a shot at it. For this text i have searched thru ftp archives -troughout the world, have asked info from Ensoniq, Roland, -TurtleBeach, Advanced Gravis, Forte Creative Labs and i also took into -account the numerous comments, praise and flames i received to model -the text. Since this text is a result of a collective internet and -industry wisdom, flames will go the way of /dev/nul. And please, read -the text carefully, because i have received some comments from people -who were thinking i wrote something when in fact i wrote the opposite -(particularly from non anglophones). - - You probably have heard about the GUS beeing a wavetable -soundcard. I have received some comments that the GUS is not such a -thing, but since the industry uses this term (i.e. CL waveblaster, -GUS, TB multisound etc...), i am not in a position to create confusion -by renaming the technology. Wavetable explains perfectly what it is. -A table containing a waveform. - - The GUS uses the third generation of wavetable synthesis, so -before i start explaining it, i'll talk about the first two -generations first. - - The first generation of wavetable synthesis was actually a -_digitally_ controlled _analog_ oscillator(s) where parameters -controlling the waveform were kept in memory. The curtis based synths -and some others are directly derived from this concept. - - The second generation of wavetable synthesis uses a digital -oscillator, with the waveform held in memory in it's basic form (one -period usually). Parameters to alter the oscillator behaviour are -also in memory. I use the general term "memory" instead of RAM, -because in some case it's actually ROM, FlashROM, PROM, EPROM, -switches, buffers etc... The Ensoniq chip found in the Macintosh Plus -is an example (8 bit, 4 oscillators, 4096 byte wavetable). - - The third generation of wavetable synthesis which can be found -in two flavors (RAM or ROM) is based on the second generation, but -uses bigger wavetables to hold the waveform (either in single period -or multi period format) including this time the attack and release. In -this section, i will focus only on the GUS implementation, which -basically encompass all other implementations. Basically, what you -have are 32 oscillators which can do the exact same thing, and be -programmed separately and/or simultaneously. What the hardware can do -without the operating system is not too important here since we are -looking at what the GUS _can_presently_do_ (with modifications to the -OS, the GUS could do pretty much any synthesis method one can dream -up), not what it would have done if the OS wasn't available. Of -course, more processing done in hardware means more CPU cycles left -for other things. - - So in the GUS, you have some RAM (up to 1Mb) that holds 1, 2, -3, etc, wavetables which consist of a sampled (or soft-synthesised) -waveform, some parameters and optionally a sampled attack and release. -The GF1 chip (an asic based on the Ensoniq DOC-II chip) will then -playback a waveform when triggered based on some parameters it is -given, and on others it will fetch from the wavetable. I dont know if -all parameters can be fetched from RAM by the GF1, nor if the GF1 can -fetch some instructions from RAM, but by using the current OS built in -the windows drivers or in the DOS library, this is what the GUS -_can_presently_use_ to synthesise music: - - - sampled or envelopped attack in 8/16 bit, signed/unsigned - format * - - sampled waveform (anything! a period, or a several seconds - sample) * - - sampled or envelopped release * - -with: - - velocity (volume) * - - panning (balance) * - - precise frequency playback rates (with frequency based - antialiasing and oversampling) * - - mixing of all the channels * - -Up to here, it's sample playback. But there is more: - - - full vibrato (FM, depth, rate, sweep) - - full tremolo (AM, depth, rate, sweep) - - LFO (Low Frequency Oscillator) * - - forward, reverse, dual direction looping or no looping * - - the loop points can be anywhere (for sampled attack and release) * - |-------|-------------|--------------| - Start Start loop End loop End - - 6 point envelope - - tuning * - - fractional endpoint * - - combination of oscillators (up to 4 if the GF1 - implementation is the same as Ensoniq) * - - previous waveform usage * - -And more recently: - - 3D (focal point 3D positioning) - - ( "*" indicates that the operation is done in hardware. Some -others may be done in hardware but i have not done any tests or found -any technical information to confirm it. I also base 1 item on the DOC -II capability, which should be implemented in the GF1.) - - Also, reverb, flanger, phasing etc... could be easily -implemente within the drivers. Presently it can be done with a little -work on the patches and/or midi timestamp (i have succesfully made -flanger and phasing). Another thing that could be implemented is -dynamic patch loading since the card supports it (i have done it). You -can even get a distorted sound (ideal for guitars, vox, analog synths) -by simply changing the 2's complement flag (work best with -soft-synthesised patches). - - Last, it is far better to have a RAM wavetable synth than a -ROM one, since you can upload your samples. Even sound canvas owners -(and other synths too) complain that their ROM based GS synth lacks -interesting drum and bass sounds, cannot play sound effects, and is -not usable for dance and techno. Also you can have more space for -each samples, because you always have only the samples you need in -memory, so you can have better sampling rates and better waveforms. - ----------------------------------------------------------------------- - -16] Is there a GUS device driver for Linux/BSD386/*IX? - - There is a group of people working on device drivers and C -libraries for Linux, BSD386, 386bsd, Minix, SysVR3/386, and whatever -other PC/UNIX flavors there are out there. - - I know there is at least a beta driver out for Linux. If -anyone out there has more information on this, please mail it to -me. I had some information from Hannu Solvanen (Forgive my spelling) -but I lost it. If you're reading this, Hannu, please mail me that -info on your driver again. - ----------------------------------------------------------------------- - -17] How do I get the GUS to work with OS/2? - - As of now, there is no OS/2 specific device driver for the -GUS. According to Gravis, they are working directly with IBM to get -OS/2 drivers for the GUS written. A specific release date has not -been announced. - - There are a few simple tricks to get the GUS to work with OS/2 -to a small degree right now: - -Written by: Thomas Wong - - As it is right now, what you'll have to do is use a 8 bit DMA -channel in your setup of the GUS to make it work under a DOS window -under OS/2. If you have already installed/setup your GUS card, just -go into the c:\autoexec.bat file under OS/2 and manually change the -number in the environment variable. So, for example, use DMA channel -#1. By doing this, you can now use playmidi, 669 player, gusmod... a -number of GUS programs. But you still can't run playfile or SBOS (it -may crash). In other words, you can use a play a list of midi, 669, -mod...etc files in a DOS window, but can't play games. Gravis did say -they will come out with an OS/2 driver but no date is set. - ----------------------------------------------------------------------- - -18] How do I go about programming the GUS? - - Gravis and Forte have released a very detailed SDK for the -GUS. It includes source code, libraries, documentation, etc., etc, -and it's available on the FTP sites (see question #6). - - Also, there are two UltraDox files written by Phat Tran up for -FTP as well. Read them carefully, learn to love them. - - (If you want to use the GUS with another OS besides MSDOS, -read questions #21 and #23.) - ----------------------------------------------------------------------- - -19] What are the pinouts for the CD Audio IN on the GUS? - -Written by: - - About two days ago I posted requested some info on the 4-pin -CD audio pin on the GUS. I never got a reply but I got the info by -downloading volume 1 of the digest. - - The pin info was: - - left ground ground right - - I've tried this pin assignment and it seems to work. The -articles in the digest pointed out that they weren't certain of the -left-right assignment but the two pins in the middle are definitely -the grounds. - ----------------------------------------------------------------------- - -20] I'm having trouble with... GENERAL TROUBLESHOOTING TIPS - -Written by: john.smith@gravis.com (John Smith) - - It looks like a lot of the problems are incorrect -installations. - - Make sure that you put ALL the correct files in the -/ultrasnd/sbos directory and remove any old ones. Sbosdrv.exe, -Loadsbos.exe and Sboslib.sbs MUST all be from the same release -revision. They are NOT mixable. A lot of the problems you are seeing -could happen if the wrong driver is used with the new loader and patch -library. To make sure you are using the correct files, delete ALL -files from /ultrasnd/sbos. Then unzip the new release into the sbos -directory. Then COPY sbosdrv.exe up to the /ultrasnd directory. Then -COPY loadsbos.exe up to the /ultrasnd directory also. Now pick either -sboslo.bat or sboshi.bat up to /ultrasnd/sbos.bat. These two batch -files assume you are using emm386. If you are using another memory -manager (like qemm, 386max etc), use the appropriate command to load -it into high memory. (NOTE: If you installed your software in some -other directory, substitute it in place of /ultrasnd). ] Not all of -the tips below apply to all programs. This is just a brief summary of -some of the things we had to do to get some games running properly. - - 1) Make sure the BLASTER environment string tracks our -ULTRASND string. Many games look at BLASTER to set up their stuff. -SBOS needs ULTRASND. If they are not the same, the game will be -looking one place and SBOS will using another. This is another reason -NOT to have an SB and GUS in the same system. Presumably, the SB would -want BLASTER set up for it and any game looking at it would not work -with SBOS. BLASTER is set up like this: - - BLASTER=A220 I5 D1 T1 - | | | | - | | | - Type of SB (1 = regular SB) - | | ----- DMA channel (MUST be 1) - | -------- IRQ used. (same as GUS midi irq) - ------------- I/O base address - - This variable is set up by the GUS setup program. It should -never need to be modified unless you modify ULTRASND by hand. - - For example, wolf3d looks at BLASTER to get its parameters. -Sound will NOT function if the IRQs are different, but it will detect -an Adlib. - - 2) Make sure that SBOS is up and running BEFORE you install -your game. Some games configure themselves during their installation -procedure. If SBOS is not running, it will assume there is no sound -board present. - - 3) Some games have a separate setup/configuration section. -Make sure you run this after you install the game OR change the -ULTRASND variable. They are usually called setup, install or config. -Look around for it. Some games also save the last configuration to use -the next time the game is run. This means that if it didn't detect the -card (because SBOS wasn't loaded), it will save that info and will -start up the NEXT time with sound disabled. You will have to manually -turn sound back on somehow. See your games manual. For example, -Wolf-3d will do this. - - 4) Some games need all available RAM to run. Since SBOS -currently takes approximately 19K, it may not have enough to run. Some -games will shut off some of the sounds if RAM is short. Check your -manual. It may also be necessary to load SBOS high to reclaim some of -the RAM. - - 5) If you have poor performance with SBOS loaded, see if you -have an expanded memory manager running. (qemm, 386max, emm386 etc) -There is a SEVERE performance penalty to be paid if you run with -these. Its a byproduct of your machine running in protected mode. -Usually, only games that use direct I/O (mod players for example) are -seriously effected by this. If you must have SBOS loaded high, then -you will have to live with this. It is possible to disable the virtual -DMA if you are using qemm. (NOVDS) Doing so should speed things up a -bit. - -Comments on above paragraph by mike@batpad.org (Mike Batchelor) -] -] This paragraph contains some errors, from where I sit. -] You may disagree, but I offer my perspective anyway: -] -] 1. Virtual 8086 mode entails no more than a 5% -] performance penalty over real mode. It does not matter which -] memory manager you use, the degradation is dependent on the -] CPU and the motherboard. In any case, the penalty is hardly -] what you might call SEVERE. -] -] 2. QEMM's NOVDS parameter has NOTHING to do with -] virtualization of the standard DMA channels. There is no -] switch to disable this feature of QEMM, DMA would not fuction -] in V86 mode if the memory manager does not virtualize it. -] They all do this, they all MUST do this. NOVDS tells QEMM not -] to support the Virtual DMA Specification, which has to do with -] virtualizing non-standard DMA used by bus-mastering adapters -] (usually SCSI host adapters, but can be network cards, etc.). -] The VDS spec is a means by which these non-standard DMA -] operations may be virtualized in V86 mode. QEMM normally -] virtualizes the DMA channels handled by the motherboard's DMA -] controller. So-called bus-mastering disk controllers do DMA -] on their own, without help from the DMA controller, so the -] normal way of virtualizing DMA will not work. VDS is the -] solution for this. Adding NOVDS to the QEMM line will disable -] support for ASPI4DOS.SYS, USPI24.SYS and other VDS-supporting -] SCSI host adapter drivers. This will prevent the user from -] loading anything into mapped memory in the first megabyte -] (High RAM) from the SCSI hard disk. -] -] The usual way to improve DMA performance is to -] increase QEMM's DMA buffer. The default on ISA systems is -] 12K, and 64K on MCA systems. It can be increased to 128K max. -] DMA=nnn specifies how large the length of a single DMA -] transfer can be, in nnn Kb. QEMM should prompt you to -] increase the DMA buffer if a program attempts to exceed the -] capacity of the current buffer. I have found that 64K is -] plenty for all programs I have used with the GUS. - - 6) It is possible for an application to detect the Adlib side -of the GUS without SBOS being loaded. It depends on the method it uses -to detect it. Obviously if that happens, the application will think it -has an Adlib, but nothing is going to work. - - 7) Many games need to detect (and use) extended/expanded RAM -before some sounds will be activated (usually digitized stuff) Refer -to your manual for these kind of problems. An SB will not operate -properly under these conditions either. For example, Falcon III will -not play digitized sounds until EMS is set up properly. SBOS has -nothing to do with this problem. - - 8) Some games hard code their I/O address and/or irq -selections. Refer to your manual. You will have to make the GUS' -selections match these. I believe some Sierra games do this. Wing -Commander requires a base port of address of 220 for digital speech to -work. - - 9) Unless you are POSITIVE that a particular game needs an -option, (-o1 -o2 etc) DON'T specify one, 99% of the games do NOT need -one. You may screw up the driver by specifying one that you don't -need. You should unload and reload the driver before specifying an -option. Since it is possible to use more than one option, you may be -telling it conflicting things if you don't unload it. - - 10) There are several new features in SBOS that you should be -aware of: - - a) SBOS reloads its patches before an application - runs. This should eliminate having to reload it between - running windows or a native GUS application (GUSMOD Star Con - II, playmidi etc) and a game that uses SBOS. - - b) You can change the vector that it uses for - communicating between sbosdrv.exe and loadsbos.exe. The - option is -Cxx, where xx is the new software vector to use. - This is specified to sbosdrv. Currently, only 1 application - is known to need this. Netroom uses the default vector (7E) - so sbosdrv thinks it is already loaded. If you are using - netroom, you MUST change the vector #. Netroom is the only - application that we know of that has this problem. There may - be others. We don't know of ANY games that do. - - c) You can tell SBOS to leave line-in enabled by - specifying a -L when SBOS is loaded. This can be useful if you - want to monitor some other audio output source thru the GUS. - - 11) The volume up and down keys (defaults are [ and ]) do not -work in all games. Any game that takes over the keyboard vectors will -disable this feature. You must use the -V option when loading sbos to -alter the volume for these games. This option works like this: -vxx -where xx ranges from 0 to 31 (31 being max volume) Note: in SOME -versions prior to 1.4B2, hitting the volume keys would hang your -system. This has been fixed. - - 12) Some games grab all possible SB irqs (2,5 and 7) when they -initialize to find what IRQ the SB is on. If they do this with SBOS -and SBOS happens to have the UltraSound IRQ on one of the SB irqs, it -will not let SBOS get its irq. Make sure that you set the UltraSound -irq to one of the upper ones (11,12 or 15). Jill of the Jungle is an -example of a game that exhibits this problem. - - 13) Now for some simple things to look for. - - a) Is board seated properly? - b) Is DRAM in sockets correctly (bent pins etc)? - c) Are stereo/speakers hooked up properly? - d) Are you connected to the right outputs on GUS? - (Some Ultrasound boxes are labeled wrong ...) - - TOP OF ULTRASOUND - ================= - - Amplified Out - Line Out - - Joystick/Midi 15 pin connector - - Microphone In - Line In - - BOTTOM OF ULTRASOUND - ==================== - - e) Do you have enough environment space for ULTRASND - and BLASTER variables? - f) Did you set the volume too low? - g) Is \ultrasnd in your path? - h) Could you have gotten a bad download of new SBOS? - - 14) Several people have complained about sbos loading VERY -slowly. Is your joystick or MIDI plugged in? Try unplugging it. As -of now, we haven't been able to reproduce this problem. It may be -related to installing the software incorrectly or a DMA conflict. - - 15) If your joystick doesn't operate properly in a game, look -for these things. - - a) Has it been calibrated (see manual) - b) Do you have 2 games ports in your system? (GUS and - another game port). If so, one MUST be disabled. - c) DO you have a line like the following in your autoexec - - joycomp 20 - - where 20 is the compensation factor determined thru - the calibration utility, ultrajoy. - - 16) There are several things people have noticed that seem to -effect SBOS that need to be investigated. None of these have been -verified, but you should be aware of them and you might try -eliminating them as possible sources of your problem. - - a) Loading SBOS hi can cause some FM stuff to sound - 'weird'. - b) Using 'Stealth' mode on QEMM seems to have a - detrimental effect. - c) Change sbos.bat file to use loadhi instead of lh if - using QEMM. - d) Stacker seems to cause some people problems. It - works OK for others. - e) Order that TSR's are loaded may have an effect. Try - loading SBOS first, last etc. - f) When using XWing make sure that you have at least - 896K of EMS (not XMS) and 563K of conventional. If - you are having problems with slowdowns try turning - off the music. - - 17) The only other thing we can think of is a hardware problem -on your card. The diagnostics in the new setup program should be able -to isolate it. - - Granted, we are a bit biased, but we believe that you should -get SUPERB sound out of your GUS. If you are getting less than -satisfactory results, there can only be a few explanations. - - a) in windows, make sure its in 'high fidelity' mode. - b) Incorrect software installation. - c) Incorrect hardware installation (IRQ,DMA etc) - (probably) - 4) Bad hardware.(PC or GUS) - ----------------------------------------------------------------------- - -21] I can't seem to fit the new disks onto a floppy. - - First of all, the files need to go on to a HD 3.5" disk. - - Next, some of the disks were zip'ed a second time to include a -small README file (in other words, the .zip file you downloaded -contains two files: a README file, and another .zip file). This would -have been a good idea, except the .zip file got bigger; too big for a -HD 3.5" disk. So, you'll need to unzip the file, read the README, and -copy the new .zip file to a floppy. - ----------------------------------------------------------------------- - -22] Why shouldn't I use the comp.sys.ibm.pc.soundcard.GUS newgroup? - - c.s.i.p.s.GUS wasn't created legally; ie: there was no formal -call for discussion, voting, etc., etc. As such, many sites refuse to -carry the group. Posts there get to few readers. - - If anyone wants to take the time and energy to go through the -steps needed to get a new group created the correct way, I'm sure all -the GUSers would be more than happy to move there. - - (USENET tip for newbies: Don't create a new group for every -new topic that comes along. Find the group that your topic fits best -in, and use that. If you don't like all the other posts in the group, -learn the magic incantations that go along with killfiles in your -newsreader.) - ----------------------------------------------------------------------- - -23] What are "Miles Drivers", and how do I use them? - -Written by: Matthew E. Bernold - - Miles drivers (also known as MIDPAK/DIGIPAK) are a set of -drivers that software companies to easily support many soundcards. -The game is programmed to use these drivers, and then any soundcard -with an appropriate driver will automatically be supported. The Miles -drivers for the GUS can be found on the Epas archive site. The -current version of these drivers is v.97beta (filename GUSAIL97.ZIP) - - There are three driver files and one TSR in the GUS Miles -Drivers. The drivers are GF1MIDI.ADV, GF1DIGI.ADV, GF166.COM and the -TSR is ULTRAMID.EXE In order to use these drivers, you need to copy -them over existing sound drivers for another card. These drivers -should have easily recognizable names like: - - (List taken from Monopoly Deluxe) - - SBDIG.ADV Sound Blaster Digital - SBFM.ADV Sound Blaster FM Music - SBPDIG.ADV Sound Blaster Pro Digital - SBP1FM.ADV Sound Blaster Pro v1 Music - SBP2FM.ADV Sound Blaster Pro v2 Music (OPL3) - MT32MPU.ADV Roland MT32 Music - PCSPKR.ADV PC Speaker driver - - The above names are typical, but they may change. - - To get the game to work, you should do the following (This -example assumes that your Ultrasound directory is c:\ultrasnd and that -your miles drivers are in c:\ultrasnd\miles and your game is in the -directory c:\game): - - 1) Change into your Game's directory - -C:\>CD GAME - - NOTE: Any of the below steps MAY not be necessary, depending -on what your application uses. If the app uses only Digital sound, -and no MIDI music, for example, you will not have to do step 3. - - 2) Copy GF1DIGI.ADV over a Digital driver. I would suggest -choosing the one that is most functional. Choose the SBPro driver -over the SB one and you MIGHT get stereo (depending on what the game -does) and choose the PAS-16 driver (if one is present) and you MIGHT -get 16-bit sound if the game uses it. We'll choose the SBPro driver. - -C:\GAME>COPY C:\ULTRASND\MILES\GF1DIGI.ADV SBPDIG.ADV - - 3) Copy GF1MIDI.ADV over a Music driver. Here, I would -suggest that you try different ones and see which sounds best. -Sometimes the program plays a different version of the music depending -on your card. For Terminator 2029, I found that the MT32 setting -sounds better, but the SCC-1 setting sounds more like the movie music, -even though it isn't as clear and nice sounding. For this example, -we'll try the MT32 driver. - -C:\GAME>COPY C:\ULTRASND\MILES\GF1MIDI.ADV MT32MPU.ADV - - 4) Copy GF166.COM over the .COM file for the card you selected -above. This should be fairly simple. If you chose 2 different cards -as we did in this example, then copy the GF166.COM over the .COM file -for BOTH cards (just to be safe) - -C:\GAME>COPY C:\ULTRASND\MILES\GF166.COM SBLASTER.COM - - (For this game [Monopoly Deluxe] there doesn't seem to be a -.COM file for the Roland MT32, so I didn't copy over it here) - - 5) This step is MANDITORY. Run the game's SETUP utility and -choose the cards you chose above. In this example, we chose SBPro for -Digital, and MT32 for Music. If the SETUP utility does NOT allow you -to choose two different cards, you must redo steps 2-4 patching only -ONE card's drivers. Most programs now allow you to choose 2 cards, -however. - - 6) Run ULTRAMID.EXE. This needs to be done before you run any -games that use the Miles Drivers. There should be instructions on -different command line options for ULTRAMID in the readme file that -comes with the archive. Realize that ULTRAMID takes around 50k right -now, so you may have to load it high to get enough conventional memory -to run your game. - - That's it! Your game SHOULD now have full GUS support. If it -doesn't, here are a few hints on how to possibly fix things: - - 1) Try copying the GUS's *.ADV drivers over ALL the *.ADV -drivers in the game's directory. According to the README file, a good -indication of what a driver is is that if the driver is <10k then it -is a Digital driver, and should be replaced with GUSDIGI.ADV, if -larger, then it is a MIDI driver, and should be replaced with -GUSMIDI.ADV. The name should also give you a clue as to what to -replace it with. - - a) MIDI drivers: MT32, SCC1, ADLIB (Usually), Anything - with 'FM' like SBFM or SBP2FM - - b) Digital drivers: SBDIG, SBPDIG, PASDIG, PCSPKR. - Usually these drivers will have 'DIG' in them, but not - necessarily. - - 2) Try copying the GF166.COM file over ALL the .COM files in -the directory. BE CAREFUL WHEN YOU DO THIS! Some games have .COM -files other than the music drivers that should NOT be copied over. -Most of the time, the .COM files you are looking for will be small, -and will usually have a recognizable name, although this is not always -the case. - - 3) Some games on the list in the readme file from the archive -may use the Miles drivers, but NOT have *.ADV files anywhere. From -what I understand, the Miles drivers will have the word "Miles" -embedded in them somewhere near the beginning. Look through some of -the smaller files in the directory with an editor and see if you can -find the word "Miles" somewhere. Some games rename the Miles drivers -to *.DRV. - - Good luck, and happy GUSing. - ----------------------------------------------------------------------- - - diff --git a/16/PCGPE10/IFF.DOC b/16/PCGPE10/IFF.DOC deleted file mode 100644 index a0857049..00000000 --- a/16/PCGPE10/IFF.DOC +++ /dev/null @@ -1,1424 +0,0 @@ - - -"EA IFF 85" Standard for Interchange Format Files - -Document Date: January 14, 1985 -From: Jerry Morrison, Electronic Arts -Status of Standard: Released and in use - -1. Introduction - -Standards are Good for Software Developers - -As home computer hardware evolves to better and better media machines, -the demand increases for higher quality, more detailed data. Data -development gets more expensive, requires more expertise and better -tools, and has to be shared across projects. Think about several ports -of a product on one CD-ROM with 500M Bytes of common data! - -Development tools need standard interchange file formats. Imagine -scanning in images of "player" shapes, moving them to a paint program -for editing, then incorporating them into a game. Or writing a theme -song with a Macintosh score editor and incorporating it into an Amiga -game. The data must at times be transformed, clipped, filled out, -and moved across machine kinds. Media projects will depend on data -transfer from graphic, music, sound effect, animation, and script -tools. - -Standards are Good for Software Users - -Customers should be able to move their own data between independently -developed software products. And they should be able to buy data libraries -usable across many such products. The types of data objects to exchange -are open-ended and include plain and formatted text, raster and structured -graphics, fonts, music, sound effects, musical instrument descriptions, -and animation. - -The problem with expedient file formats typically memory dumps is -that they're too provincial. By designing data for one particular -use (e.g. a screen snapshot), they preclude future expansion (would -you like a full page picture? a multi-page document?). In neglecting -the possibility that other programs might read their data, they fail -to save contextual information (how many bit planes? what resolution?). -Ignoring that other programs might create such files, they're intolerant -of extra data (texture palette for a picture editor), missing data -(no color map), or minor variations (smaller image). In practice, -a filed representation should rarely mirror an in-memory representation. -The former should be designed for longevity; the latter to optimize -the manipulations of a particular program. The same filed data will -be read into different memory formats by different programs. - -The IFF philosophy: "A little behind-the-scenes conversion when programs -read and write files is far better than NxM explicit conversion utilities -for highly specialized formats." - -So we need some standardization for data interchange among development -tools and products. The more developers that adopt a standard, the -better for all of us and our customers. - -Here is "EA IFF 1985" - -Here is our offering: Electronic Arts' IFF standard for Interchange -File Format. The full name is "EA IFF 1985". Alternatives and justifications -are included for certain choices. Public domain subroutine packages -and utility programs are available to make it easy to write and use -IFF-compatible programs. - -Part 1 introduces the standard. Part 2 presents its requirements and -background. Parts 3, 4, and 5 define the primitive data types, FORMs, -and LISTs, respectively, and how to define new high level types. Part -6 specifies the top level file structure. Appendix A is included for -quick reference and Appendix B names the committee responsible for -this standard. - -References - -American National Standard Additional Control Codes for Use with ASCII, -ANSI standard 3.64-1979 for an 8-bit character set. See also ISO standard -2022 and ISO/DIS standard 6429.2. - -Amiga[tm] is a trademark of Commodore-Amiga, Inc. - -C, A Reference Manual, Samuel P. Harbison and Guy L. Steele Jr., Tartan -Laboratories. Prentice-Hall, Englewood Cliffs, NJ, 1984. - -Compiler Construction, An Advanced Course, edited by F. L. Bauer and -J. Eickel (Springer-Verlag, 1976). This book is one of many sources -for information on recursive descent parsing. - -DIF Technical Specification (c)1981 by Software Arts, Inc. DIF[tm] is -the format for spreadsheet data interchange developed by Software -Arts, Inc. -DIF[tm] is a trademark of Software Arts, Inc. - -Electronic Arts[tm] is a trademark of Electronic Arts. - -"FTXT" IFF Formatted Text, from Electronic Arts. IFF supplement document -for a text format. - -Inside Macintosh (c) 1982, 1983, 1984, 1985 Apple Computer, Inc., a -programmer's reference manual. -Apple(R) is a trademark of Apple Computer, Inc. -Macintosh[tm] is a trademark licensed to Apple Computer, Inc. - -"ILBM" IFF Interleaved Bitmap, from Electronic Arts. IFF supplement -document for a raster image format. - -M68000 16/32-Bit Microprocessor Programmer's Reference Manual(c) 1984, -1982, 1980, 1979 by Motorola, Inc. - -PostScript Language Manual (c) 1984 Adobe Systems Incorporated. -PostScript[tm] is a trademark of Adobe Systems, Inc. -Times and Helvetica(R) are trademarks of Allied Corporation. - -InterScript: A Proposal for a Standard for the Interchange of Editable -Documents (c)1984 Xerox Corporation. -Introduction to InterScript (c) 1985 Xerox Corporation. - - - -2. Background for Designers - -Part 2 is about the background, requirements, and goals for the standard. -It's geared for people who want to design new types of IFF objects. -People just interested in using the standard may wish to skip this -part. - -What Do We Need? - -A standard should be long on prescription and short on overhead. It -should give lots of rules for designing programs and data files for -synergy. But neither the programs nor the files should cost too much -more than the expedient variety. While we're looking to a future with -CD-ROMs and perpendicular recording, the standard must work well on -floppy disks. - -For program portability, simplicity, and efficiency, formats should -be designed with more than one implementation style in mind. (In practice, -pure stream I/O is adequate although random access makes it easier -to write files.) It ought to be possible to read one of many objects -in a file without scanning all the preceding data. Some programs need -to read and play out their data in real time, so we need good compromises -between generality and efficiency. - -As much as we need standards, they can't hold up product schedules. -So we also need a kind of decentralized extensibility where any software -developer can define and refine new object types without some "standards -authority" in the loop. Developers must be able to extend existing -formats in a forward- and backward-compatible way. A central repository -for design information and example programs can help us take full -advantage of the standard. - -For convenience, data formats should heed the restrictions of various -processors and environments. E.g. word-alignment greatly helps 68000 -access at insignificant cost to 8088 programs. - -Other goals include the ability to share common elements over a list -of objects and the ability to construct composite objects containing -other data objects with structural information like directories. - -And finally, "Simple things should be simple and complex things should -be possible." Alan Kay. - -Think Ahead - -Let's think ahead and build programs that read and write files for -each other and for programs yet to be designed. Build data formats -to last for future computers so long as the overhead is acceptable. -This extends the usefulness and life of today's programs and data. - -To maximize interconnectivity, the standard file structure and the -specific object formats must all be general and extensible. Think -ahead when designing an object. It should serve many purposes and -allow many programs to store and read back all the information they -need; even squeeze in custom data. Then a programmer can store the -available data and is encouraged to include fixed contextual details. -Recipient programs can read the needed parts, skip unrecognized stuff, -default missing data, and use the stored context to help transform -the data as needed. - -Scope - -IFF addresses these needs by defining a standard file structure, some -initial data object types, ways to define new types, and rules for -accessing these files. We can accomplish a great deal by writing programs -according to this standard, but don't expect direct compatibility -with existing software. We'll need conversion programs to bridge the -gap from the old world. - -IFF is geared for computers that readily process information in 8-bit -bytes. It assumes a "physical layer" of data storage and transmission -that reliably maintains "files" as strings of 8-bit bytes. The standard -treats a "file" as a container of data bytes and is independent of -how to find a file and whether it has a byte count. - -This standard does not by itself implement a clipboard for cutting -and pasting data between programs. A clipboard needs software to mediate -access, to maintain a "contents version number" so programs can detect -updates, and to manage the data in "virtual memory". - -Data Abstraction - -The basic problem is how to represent information in a way that's -program-independent, compiler- independent, machine-independent, and -device-independent. - -The computer science approach is "data abstraction", also known as -"objects", "actors", and "abstract data types". A data abstraction -has a "concrete representation" (its storage format), an "abstract -representation" (its capabilities and uses), and access procedures -that isolate all the calling software from the concrete representation. -Only the access procedures touch the data storage. Hiding mutable -details behind an interface is called "information hiding". What data -abstraction does is abstract from details of implementing the object, -namely the selected storage representation and algorithms for manipulating -it. - -The power of this approach is modularity. By adjusting the access -procedures we can extend and restructure the data without impacting -the interface or its callers. Conversely, we can extend and restructure -the interface and callers without making existing data obsolete. It's -great for interchange! - -But we seem to need the opposite: fixed file formats for all programs -to access. Actually, we could file data abstractions ("filed objects") -by storing the data and access procedures together. We'd have to encode -the access procedures in a standard machine-independent programming -language la PostScript. Even still, the interface can't evolve freely -since we can't update all copies of the access procedures. So we'll -have to design our abstract representations for limited evolution -and occasional revolution (conversion). - -In any case, today's microcomputers can't practically store data abstractions. -They can do the next best thing: store arbitrary types of data in -"data chunks", each with a type identifier and a length count. The -type identifier is a reference by name to the access procedures (any -local implementation). The length count enables storage-level object -operations like "copy" and "skip to next" independent of object type. - -Chunk writing is straightforward. Chunk reading requires a trivial -parser to scan each chunk and dispatch to the proper access/conversion -procedure. Reading chunks nested inside other chunks requires recursion, -but no lookahead or backup. - -That's the main idea of IFF. There are, of course, a few other detailsI - -Previous Work - -Where our needs are similar, we borrow from existing standards. - -Our basic need to move data between independently developed programs -is similar to that addressed by the Apple Macintosh desk scrap or -"clipboard" [Inside Macintosh chapter "Scrap Manager"]. The Scrap -Manager works closely with the Resource Manager, a handy filer and -swapper for data objects (text strings, dialog window templates, pictures, -fontsI) including types yet to be designed [Inside Macintosh chapter -"Resource Manager"]. The Resource Manager is a kin to Smalltalk's -object swapper. - -We will probably write a Macintosh desk accessory that converts IFF -files to and from the Macintosh clipboard for quick and easy interchange -with programs like MacPaint and Resource Mover. - -Macintosh uses a simple and elegant scheme of 4-character "identifiers" -to identify resource types, clipboard format types, file types, and -file creator programs. Alternatives are unique ID numbers assigned -by a central authority or by hierarchical authorities, unique ID numbers -generated by algorithm, other fixed length character strings, and -variable length strings. Character string identifiers double as readable -signposts in data files and programs. The choice of 4 characters is -a good tradeoff between storage space, fetch/compare/store time, and -name space size. We'll honor Apple's designers by adopting this scheme. - -"PICT" is a good example of a standard structured graphics format -(including raster images) and its many uses [Inside Macintosh chapter -"QuickDraw"]. Macintosh provides QuickDraw routines in ROM to create, -manipulate, and display PICTs. Any application can create a PICT by -simply asking QuickDraw to record a sequence of drawing commands. -Since it's just as easy to ask QuickDraw to render a PICT to a screen -or a printer, it's very effective to pass them between programs, say -from an illustrator to a word processor. An important feature is the -ability to store "comments" in a PICT which QuickDraw will ignore. -Actually, it passes them to your optional custom "comment handler". - -PostScript, Adobe's print file standard, is a more general way to -represent any print image (which is a specification for putting marks -on paper) [PostScript Language Manual]. In fact, PostScript is a full-fledged -programming language. To interpret a PostScript program is to render -a document on a raster output device. The language is defined in layers: -a lexical layer of identifiers, constants, and operators; a layer -of reverse polish semantics including scope rules and a way to define -new subroutines; and a printing-specific layer of built-in identifiers -and operators for rendering graphic images. It is clearly a powerful -(Turing equivalent) image definition language. PICT and a subset of -PostScript are candidates for structured graphics standards. - -A PostScript document can be printed on any raster output device (including -a display) but cannot generally be edited. That's because the original -flexibility and constraints have been discarded. Besides, a PostScript -program may use arbitrary computation to supply parameters like placement -and size to each operator. A QuickDraw PICT, in comparison, is a more -restricted format of graphic primitives parameterized by constants. -So a PICT can be edited at the level of the primitives, e.g. move -or thicken a line. It cannot be edited at the higher level of, say, -the bar chart data which generated the picture. - -PostScript has another limitation: Not all kinds of data amount to -marks on paper. A musical instrument description is one example. PostScript -is just not geared for such uses. - -"DIF" is another example of data being stored in a general format -usable by future programs [DIF Technical Specification]. DIF is a -format for spreadsheet data interchange. DIF and PostScript are both -expressed in plain ASCII text files. This is very handy for printing, -debugging, experimenting, and transmitting across modems. It can have -substantial cost in compaction and read/write work, depending on use. -We won't store IFF files this way but we could define an ASCII alternate -representation with a converter program. - -InterScript is Xerox' standard for interchange of editable documents -[Introduction to InterScript]. It approaches a harder problem: How -to represent editable word processor documents that may contain formatted -text, pictures, cross-references like figure numbers, and even highly -specialized objects like mathematical equations? InterScript aims -to define one standard representation for each kind of information. -Each InterScript-compatible editor is supposed to preserve the objects -it doesn't understand and even maintain nested cross-references. So -a simple word processor would let you edit the text of a fancy document -without discarding the equations or disrupting the equation numbers. - -Our task is similarly to store high level information and preserve -as much content as practical while moving it between programs. But -we need to span a larger universe of data types and cannot expect -to centrally define them all. Fortunately, we don't need to make programs -preserve information that they don't understand. And for better or -worse, we don't have to tackle general-purpose cross-references yet. - - - -3. Primitive Data Types - -Atomic components such as integers and characters that are interpretable -directly by the CPU are specified in one format for all processors. -We chose a format that's most convenient for the Motorola MC68000 -processor [M68000 16/32-Bit Microprocessor Programmer's Reference -Manual]. - -N.B.: Part 3 dictates the format for "primitive" data types where and -only where used in the overall file structure and standard kinds of -chunks (Cf. Chunks). The number of such occurrences will be small -enough that the costs of conversion, storage, and management of processor- -specific files would far exceed the costs of conversion during I/O by "foreign" -programs. A particular data chunk may be specified with a different -format for its internal primitive types or with processor- or environment- -speci fic variants if necessary to optimize local usage. Since that hurts -data interchange, it's not recommended. (Cf. Designing New Data Sections, -in Part 4.) - -Alignment - -All data objects larger than a byte are aligned on even byte addresses -relative to the start of the file. This may require padding. Pad bytes -are to be written as zeros, but don't count on that when reading. - -This means that every odd-length "chunk" (see below) must be padded -so that the next one will fall on an even boundary. Also, designers -of structures to be stored in chunks should include pad fields where -needed to align every field larger than a byte. Zeros should be stored -in all the pad bytes. - -Justification: Even-alignment causes a little extra work for files -that are used only on certain processors but allows 68000 programs -to construct and scan the data in memory and do block I/O. You just -add an occasional pad field to data structures that you're going to -block read/write or else stream read/write an extra byte. And the -same source code works on all processors. Unspecified alignment, on -the other hand, would force 68000 programs to (dis)assemble word and -long-word data one byte at a time. Pretty cumbersome in a high level -language. And if you don't conditionally compile that out for other -processors, you won't gain anything. - -Numbers - -Numeric types supported are two's complement binary integers in the -format used by the MC68000 processor high byte first, high word first the -reverse of 8088 and 6502 format. They could potentially include signed -and unsigned 8, 16, and 32 bit integers but the standard only uses -the following: - -UBYTE 8 bits unsigned -WORD 16 bits signed -UWORD 16 bits unsigned -LONG 32 bits signed - -The actual type definitions depend on the CPU and the compiler. In -this document, we'll express data type definitions in the C programming -language. [See C, A Reference Manual.] In 68000 Lattice C: - -typedef unsigned char UBYTE; /* 8 bits unsigned */ -typedef short WORD; /* 16 bits signed */ -typedef unsigned short UWORD; /* 16 bits unsigned */ -typedef long LONG; /* 32 bits signed */ - -Characters - -The following character set is assumed wherever characters are used, -e.g. in text strings, IDs, and TEXT chunks (see below). - -Characters are encoded in 8-bit ASCII. Characters in the range NUL -(hex 0) through DEL (hex 7F) are well defined by the 7-bit ASCII standard. -IFF uses the graphic group RJS (SP, hex 20) through R~S (hex 7E). - -Most of the control character group hex 01 through hex 1F have no -standard meaning in IFF. The control character LF (hex 0A) is defined -as a "newline" character. It denotes an intentional line break, that -is, a paragraph or line terminator. (There is no way to store an automatic -line break. That is strictly a function of the margins in the environment -the text is placed.) The control character ESC (hex 1B) is a reserved -escape character under the rules of ANSI standard 3.64-1979 American -National Standard Additional Control Codes for Use with ASCII, ISO -standard 2022, and ISO/DIS standard 6429.2. - -Characters in the range hex 7F through hex FF are not globally defined -in IFF. They are best left reserved for future standardization. But -note that the FORM type FTXT (formatted text) defines the meaning -of these characters within FTXT forms. In particular, character values -hex 7F through hex 9F are control codes while characters hex A0 through -hex FF are extended graphic characters like , as per the ISO and -ANSI standards cited above. [See the supplementary document "FTXT" -IFF Formatted Text.] - -Dates - -A "creation date" is defined as the date and time a stream of data -bytes was created. (Some systems call this a "last modified date".) -Editing some data changes its creation date. Moving the data between -volumes or machines does not. - -The IFF standard date format will be one of those used in MS-DOS, -Macintosh, or Amiga DOS (probably a 32-bit unsigned number of seconds -since a reference point). Issue: Investigate these three. - -Type IDs - -A "type ID", "property name", "FORM type", or any other IFF identifier -is a 32-bit value: the concatenation of four ASCII characters in the -range R S (SP, hex 20) through R~S (hex 7E). Spaces (hex 20) should -not precede printing characters; trailing spaces are ok. Control characters -are forbidden. - -typedef CHAR ID[4]; - -IDs are compared using a simple 32-bit case-dependent equality test. - -Data section type IDs (aka FORM types) are restriced IDs. (Cf. Data -Sections.) Since they may be stored in filename extensions (Cf. Single -Purpose Files) lower case letters and punctuation marks are forbidden. -Trailing spaces are ok. - -Carefully choose those four characters when you pick a new ID. Make -them mnemonic so programmers can look at an interchange format file -and figure out what kind of data it contains. The name space makes -it possible for developers scattered around the globe to generate -ID values with minimal collisions so long as they choose specific -names like "MUS4" instead of general ones like "TYPE" and "FILE". -EA will "register" new FORM type IDs and format descriptions as they're -devised, but collisions will be improbable so there will be no pressure -on this "clearinghouse" process. Appendix A has a list of currently -defined IDs. - -Sometimes it's necessary to make data format changes that aren't backward -compatible. Since IDs are used to denote data formats in IFF, new -IDs are chosen to denote revised formats. Since programs won't read -chunks whose IDs they don't recognize (see Chunks, below), the new -IDs keep old programs from stumbling over new data. The conventional -way to chose a "revision" ID is to increment the last character if -it's a digit or else change the last character to a digit. E.g. first -and second revisions of the ID "XY" would be "XY1" and "XY2". Revisions -of "CMAP" would be "CMA1" and "CMA2". - -Chunks - -Chunks are the building blocks in the IFF structure. The form expressed -as a C typedef is: - -typedef struct { - ID ckID; - LONG ckSize; /* sizeof(ckData) */ - UBYTE ckData[/* ckSize */]; - } Chunk; - -We can diagram an example chunk a "CMAP" chunk containing 12 data -bytes like this: - ---------------- - ckID: | 'CMAP' | - ckSize: | 12 | - ckData: | 0, 0, 0, 32 | -------- - | 0, 0, 64, 0 | 12 bytes - | 0, 0, 64, 0 | --------- - ---------------- - -The fixed header part means "Here's a type ckID chunk with ckSize -bytes of data." - -The ckID identifies the format and purpose of the chunk. As a rule, -a program must recognize ckID to interpret ckData. It should skip -over all unrecognized chunks. The ckID also serves as a format version -number as long as we pick new IDs to identify new formats of ckData -(see above). - -The following ckIDs are universally reserved to identify chunks with -particular IFF meanings: "LIST", "FORM", "PROP", "CAT ", and " -". The special ID " " (4 spaces) is a ckID for "filler" chunks, -that is, chunks that fill space but have no meaningful contents. The -IDs "LIS1" through "LIS9", "FOR1" through "FOR9", and "CAT1" through -"CAT9" are reserved for future "version number" variations. All IFF-compatible -software must account for these 23 chunk IDs. Appendix A has a list -of predefined IDs. - -The ckSize is a logical block size how many data bytes are in ckData. -If ckData is an odd number of bytes long, a 0 pad byte follows which -is not included in ckSize. (Cf. Alignment.) A chunk's total physical -size is ckSize rounded up to an even number plus the size of the header. -So the smallest chunk is 8 bytes long with ckSize = 0. For the sake -of following chunks, programs must respect every chunk's ckSize as -a virtual end-of-file for reading its ckData even if that data is -malformed, e.g. if nested contents are truncated. - -We can describe the syntax of a chunk as a regular expression with -"#" representing the ckSize, i.e. the length of the following {braced} -bytes. The "[0]" represents a sometimes needed pad byte. (The regular -expressions in this document are collected in Appendix A along with -an explanation of notation.) - -Chunk ::= ID #{ UBYTE* } [0] - -One chunk output technique is to stream write a chunk header, stream -write the chunk contents, then random access back to the header to -fill in the size. Another technique is to make a preliminary pass -over the data to compute the size, then write it out all at once. - -Strings, String Chunks, and String Properties - -In a string of ASCII text, LF denotes a forced line break (paragraph -or line terminator). Other control characters are not used. (Cf. Characters.) - -The ckID for a chunk that contains a string of plain, unformatted -text is "TEXT". As a practical matter, a text string should probably -not be longer than 32767 bytes. The standard allows up to 231 - 1 -bytes. - -When used as a data property (see below), a text string chunk may -be 0 to 255 characters long. Such a string is readily converted to -a C string or a Pascal STRING[255]. The ckID of a property must be -the property name, not "TEXT". - -When used as a part of a chunk or data property, restricted C string -format is normally used. That means 0 to 255 characters followed by -a NUL byte (ASCII value 0). - -Data Properties - -Data properties specify attributes for following (non-property) chunks. -A data property essentially says "identifier = value", for example -"XY = (10, 200)", telling something about following chunks. Properties -may only appear inside data sections ("FORM" chunks, cf. Data Sections) -and property sections ("PROP" chunks, cf. Group PROP). - -The form of a data property is a special case of Chunk. The ckID is -a property name as well as a property type. The ckSize should be small -since data properties are intended to be accumulated in RAM when reading -a file. (256 bytes is a reasonable upper bound.) Syntactically: - -Property::= Chunk - -When designing a data object, use properties to describe context information -like the size of an image, even if they don't vary in your program. -Other programs will need this information. - -Think of property settings as assignments to variables in a programming -language. Multiple assignments are redundant and local assignments -temporarily override global assignments. The order of assignments -doesn't matter as long as they precede the affected chunks. (Cf. LISTs, -CATs, and Shared Properties.) - -Each object type (FORM type) is a local name space for property IDs. -Think of a "CMAP" property in a "FORM ILBM" as the qualified ID "ILBM.CMAP". -Property IDs specified when an object type is designed (and therefore -known to all clients) are called "standard" while specialized ones -added later are "nonstandard". - -Links - -Issue: A standard mechanism for "links" or "cross references" is very -desirable for things like combining images and sounds into animations. -Perhaps we'll define "link" chunks within FORMs that refer to other -FORMs or to specific chunks within the same and other FORMs. This -needs further work. EA IFF 1985 has no standard link mechanism. - -For now, it may suffice to read a list of, say, musical instruments, -and then just refer to them within a musical score by index number. - -File References - -Issue: We may need a standard form for references to other files. -A "file ref" could name a directory and a file in the same type of -operating system as the ref's originator. Following the reference -would expect the file to be on some mounted volume. In a network environment, -a file ref could name a server, too. - -Issue: How can we express operating-system independent file refs? - -Issue: What about a means to reference a portion of another file? -Would this be a "file ref" plus a reference to a "link" within the -target file? - - - -4. Data Sections - -The first thing we need of a file is to check: Does it contain IFF -data and, if so, does it contain the kind of data we're looking for? -So we come to the notion of a "data section". - -A "data section" or IFF "FORM" is one self-contained "data object" -that might be stored in a file by itself. It is one high level data -object such as a picture or a sound effect. The IFF structure "FORM" -makes it self- identifying. It could be a composite object like a -musical score with nested musical instrument descriptions. - -Group FORM - -A data section is a chunk with ckID "FORM" and this arrangement: - -FORM ::= "FORM" #{ FormType (LocalChunk | FORM | LIST | CAT)* -} -FormType::= ID -LocalChunk ::= Property | Chunk - -The ID "FORM" is a syntactic keyword like "struct" in C. Think of -a "struct ILBM" containing a field "CMAP". If you see "FORM" you'll -know to expect a FORM type ID (the structure name, "ILBM" in this -example) and a particular contents arrangement or "syntax" (local -chunks, FORMs, LISTs, and CATs). (LISTs and CATs are discussed in -part 5, below.) A "FORM ILBM", in particular, might contain a local -chunk "CMAP", an "ILBM.CMAP" (to use a qualified name). - -So the chunk ID "FORM" indicates a data section. It implies that the -chunk contains an ID and some number of nested chunks. In reading -a FORM, like any other chunk, programs must respect its ckSize as -a virtual end-of-file for reading its contents, even if they're truncated. - -The FormType (or FORM type) is a restricted ID that may not contain -lower case letters or punctuation characters. (Cf. Type IDs. Cf. Single -Purpose Files.) - -The type-specific information in a FORM is composed of its "local -chunks": data properties and other chunks. Each FORM type is a local -name space for local chunk IDs. So "CMAP" local chunks in other FORM -types may be unrelated to "ILBM.CMAP". More than that, each FORM type -defines semantic scope. If you know what a FORM ILBM is, you'll know -what an ILBM.CMAP is. - -Local chunks defined when the FORM type is designed (and therefore -known to all clients of this type) are called "standard" while specialized -ones added later are "nonstandard". - -Among the local chunks, property chunks give settings for various -details like text font while the other chunks supply the essential -information. This distinction is not clear cut. A property setting -cancelled by a later setting of the same property has effect only -on data chunks in between. E.g. in the sequence: - -prop1 = x (propN = value)* prop1 = y - -where the propNs are not prop1, the setting prop1 = x has no effect. - -The following universal chunk IDs are reserved inside any FORM: "LIST", -"FORM", "PROP", "CAT ", "JJJJ", "LIS1" through "LIS9", "FOR1" through -"FOR9", and "CAT1" through "CAT9". (Cf. Chunks. Cf. Group LIST. Cf. -Group PROP.) For clarity, these universal chunk names may not be FORM -type IDs, either. - -Part 5, below, talks about grouping FORMs into LISTs and CATs. They -let you group a bunch of FORMs but don't impose any particular meaning -or constraints on the grouping. Read on. - -Composite FORMs - -A FORM chunk inside a FORM is a full-fledged data section. This means -you can build a composite object like a multi-frame animation sequence -from available picture FORMs and sound effect FORMs. You can insert -additional chunks with information like frame rate and frame count. - -Using composite FORMs, you leverage on existing programs that create -and edit the component FORMs. Those editors may even look into your -composite object to copy out its type of component, although it'll -be the rare program that's fancy enough to do that. Such editors are -not allowed to replace their component objects within your composite -object. That's because the IFF standard lets you specify consistency -requirements for the composite FORM such as maintaining a count or -a directory of the components. Only programs that are written to uphold -the rules of your FORM type should create or modify such FORMs. - -Therefore, in designing a program that creates composite objects, -you are strongly requested to provide a facility for your users to -import and export the nested FORMs. Import and export could move the -data through a clipboard or a file. - -Here are several existing FORM types and rules for defining new ones. - -FTXT - -An FTXT data section contains text with character formatting information -like fonts and faces. It has no paragraph or document formatting information -like margins and page headers. FORM FTXT is well matched to the text -representation in Amiga's Intuition environment. See the supplemental -document "FTXT" IFF Formatted Text. - -ILBM - -"ILBM" is an InterLeaved BitMap image with color map; a machine-independent -format for raster images. FORM ILBM is the standard image file format -for the Commodore-Amiga computer and is useful in other environments, -too. See the supplemental document "ILBM" IFF Interleaved Bitmap. - -PICS - -The data chunk inside a "PICS" data section has ID "PICT" and holds -a QuickDraw picture. Issue: Allow more than one PICT in a PICS? See -Inside Macintosh chapter "QuickDraw" for details on PICTs and how -to create and display them on the Macintosh computer. - -The only standard property for PICS is "XY", an optional property -that indicates the position of the PICT relative to "the big picture". -The contents of an XY is a QuickDraw Point. - -Note: PICT may be limited to Macintosh use, in which case there'll -be another format for structured graphics in other environments. - -Other Macintosh Resource Types - -Some other Macintosh resource types could be adopted for use within -IFF files; perhaps MWRT, ICN, ICN#, and STR#. - -Issue: Consider the candidates and reserve some more IDs. - -Designing New Data Sections - -Supplemental documents will define additional object types. A supplement -needs to specify the object's purpose, its FORM type ID, the IDs and -formats of standard local chunks, and rules for generating and interpreting -the data. It's a good idea to supply typedefs and an example source -program that accesses the new object. See "ILBM" IFF Interleaved Bitmap -for a good example. - -Anyone can pick a new FORM type ID but should reserve it with Electronic -Arts at their earliest convenience. [Issue: EA contact person? Hand -this off to another organization?] While decentralized format definitions -and extensions are possible in IFF, our preference is to get design -consensus by committee, implement a program to read and write it, -perhaps tune the format, and then publish the format with example -code. Some organization should remain in charge of answering questions -and coordinating extensions to the format. - -If it becomes necessary to revise the design of some data section, -its FORM type ID will serve as a version number (Cf. Type IDs). E.g. -a revised "VDEO" data section could be called "VDE1". But try to get -by with compatible revisions within the existing FORM type. - -In a new FORM type, the rules for primitive data types and word-alignment -(Cf. Primitive Data Types) may be overriden for the contents of its -local chunks but not for the chunk structure itself if your documentation -spells out the deviations. If machine-specific type variants are needed, -e.g. to store vast numbers of integers in reverse bit order, then -outline the conversion algorithm and indicate the variant inside each -file, perhaps via different FORM types. Needless to say, variations -should be minimized. - -In designing a FORM type, encapsulate all the data that other programs -will need to interpret your files. E.g. a raster graphics image should -specify the image size even if your program always uses 320 x 200 -pixels x 3 bitplanes. Receiving programs are then empowered to append -or clip the image rectangle, to add or drop bitplanes, etc. This enables -a lot more compatibility. - -Separate the central data (like musical notes) from more specialized -information (like note beams) so simpler programs can extract the -central parts during read-in. Leave room for expansion so other programs -can squeeze in new kinds of information (like lyrics). And remember -to keep the property chunks manageably short let's say 2 256 bytes. - -When designing a data object, try to strike a good tradeoff between -a super-general format and a highly-specialized one. Fit the details -to at least one particular need, for example a raster image might -as well store pixels in the current machine's scan order. But add -the kind of generality that makes it usable with foreseeable hardware -and software. E.g. use a whole byte for each red, green, and blue -color value even if this year's computer has only 4-bit video DACs. -Think ahead and help other programs so long as the overhead is acceptable. -E.g. run compress a raster by scan line rather than as a unit so future -programs can swap images by scan line to and from secondary storage. - -Try to design a general purpose "least common multiple" format that -encompasses the needs of many programs without getting too complicated. -Let's coalesce our uses around a few such formats widely separated -in the vast design space. Two factors make this flexibility and simplicity -practical. First, file storage space is getting very plentiful, so -compaction is not a priority. Second, nearly any locally-performed -data conversion work during file reading and writing will be cheap -compared to the I/O time. - -It must be ok to copy a LIST or FORM or CAT intact, e.g. to incorporate -it into a composite FORM. So any kind of internal references within -a FORM must be relative references. They could be relative to the -start of the containing FORM, relative from the referencing chunk, -or a sequence number into a collection. - -With composite FORMs, you leverage on existing programs that create -and edit the components. If you write a program that creates composite -objects, please provide a facility for your users to import and export -the nested FORMs. The import and export functions may move data through -a separate file or a clipboard. - -Finally, don't forget to specify all implied rules in detail. - - - -5. LISTs, CATs, and Shared Properties - -Data often needs to be grouped together like a list of icons. Sometimes -a trick like arranging little images into a big raster works, but -generally they'll need to be structured as a first class group. The -objects "LIST" and "CAT" are IFF-universal mechanisms for this purpose. - -Property settings sometimes need to be shared over a list of similar -objects. E.g. a list of icons may share one color map. LIST provides -a means called "PROP" to do this. One purpose of a LIST is to define -the scope of a PROP. A "CAT", on the other hand, is simply a concatenation -of objects. - -Simpler programs may skip LISTs and PROPs altogether and just handle -FORMs and CATs. All "fully-conforming" IFF programs also know about -"CAT ", "LIST", and "PROP". Any program that reads a FORM inside a -LIST must process shared PROPs to correctly interpret that FORM. - -Group CAT - -A CAT is just an untyped group of data objects. - -Structurally, a CAT is a chunk with chunk ID "CAT " containing a "contents -type" ID followed by the nested objects. The ckSize of each contained -chunk is essentially a relative pointer to the next one. - -CAT ::= "CAT " #{ ContentsType (FORM | LIST | CAT)* } -ContentsType ::= ID -- a hint or an "abstract data type" ID - -In reading a CAT, like any other chunk, programs must respect it's -ckSize as a virtual end-of-file for reading the nested objects even -if they're malformed or truncated. - -The "contents type" following the CAT's ckSize indicates what kind -of FORMs are inside. So a CAT of ILBMs would store "ILBM" there. It's -just a hint. It may be used to store an "abstract data type". A CAT -could just have blank contents ID ("JJJJ") if it contains more than -one kind of FORM. - -CAT defines only the format of the group. The group's meaning is open -to interpretation. This is like a list in LISP: the structure of cells -is predefined but the meaning of the contents as, say, an association -list depends on use. If you need a group with an enforced meaning -(an "abstract data type" or Smalltalk "subclass"), some consistency -constraints, or additional data chunks, use a composite FORM instead -(Cf. Composite FORMs). - -Since a CAT just means a concatenation of objects, CATs are rarely -nested. Programs should really merge CATs rather than nest them. - -Group LIST - -A LIST defines a group very much like CAT but it also gives a scope -for PROPs (see below). And unlike CATs, LISTs should not be merged -without understanding their contents. - -Structurally, a LIST is a chunk with ckID "LIST" containing a "contents -type" ID, optional shared properties, and the nested contents (FORMs, -LISTs, and CATs), in that order. The ckSize of each contained chunk -is a relative pointer to the next one. A LIST is not an arbitrary -linked list the cells are simply concatenated. - -LIST ::= "LIST" #{ ContentsType PROP* (FORM | LIST | CAT)* } -ContentsType ::= ID - -Group PROP - -PROP chunks may appear in LISTs (not in FORMs or CATs). They supply -shared properties for the FORMs in that LIST. This ability to elevate -some property settings to shared status for a list of forms is useful -for both indirection and compaction. E.g. a list of images with the -same size and colors can share one "size" property and one "color -map" property. Individual FORMs can override the shared settings. - -The contents of a PROP is like a FORM with no data chunks: - -PROP ::= "PROP" #{ FormType Property* } - -It means, "Here are the shared properties for FORM type <." - -A LIST may have at most one PROP of a FORM type, and all the PROPs -must appear before any of the FORMs or nested LISTs and CATs. You -can have subsequences of FORMs sharing properties by making each subsequence -a LIST. - -Scoping: Think of property settings as variable bindings in nested -blocks of a programming language. Where in C you could write: - -TEXT_FONT text_font = Courier; /* program's global default */ - -File(); { - TEXT_FONT text_font = TimesRoman; /* shared setting */ - - { - TEXT_FONT text_font = Helvetica; /* local setting */ - Print("Hello ");/* uses font Helvetica */ - } - - { - Print("there.");/* uses font TimesRoman */ - } - } - -An IFF file could contain: - -LIST { - PROP TEXT { - FONT {TimesRoman} /* shared setting */ - } - - FORM TEXT { - FONT {Helvetica}/* local setting*/ - CHRS {Hello } /* uses font Helvetica */ - } - - FORM TEXT { - CHRS {there.} /* uses font TimesRoman */ - } - } - -The shared property assignments selectively override the reader's -global defaults, but only for FORMs within the group. A FORM's own -property assignments selectively override the global and group-supplied -values. So when reading an IFF file, keep property settings on a stack. -They're designed to be small enough to hold in main memory. - -Shared properties are semantically equivalent to copying those properties -into each of the nested FORMs right after their FORM type IDs. - -Properties for LIST - -Optional "properties for LIST" store the origin of the list's contents -in a PROP chunk for the fake FORM type "LIST". They are the properties -originating program "OPGM", processor family "OCPU", computer type -"OCMP", computer serial number or network address "OSN ", and user -name "UNAM". In our imperfect world, these could be called upon to -distinguish between unintended variations of a data format or to work -around bugs in particular originating/receiving program pairs. Issue: -Specify the format of these properties. - -A creation date could also be stored in a property but let's ask that -file creating, editing, and transporting programs maintain the correct -date in the local file system. Programs that move files between machine -types are expected to copy across the creation dates. - - - -6. Standard File Structure - -File Structure Overview - -An IFF file is just a single chunk of type FORM, LIST, or CAT. Therefore -an IFF file can be recognized by its first 4 bytes: "FORM", "LIST", -or "CAT ". Any file contents after the chunk's end are to be ignored. - -Since an IFF file can be a group of objects, programs that read/write -single objects can communicate to an extent with programs that read/write -groups. You're encouraged to write programs that handle all the objects -in a LIST or CAT. A graphics editor, for example, could process a -list of pictures as a multiple page document, one page at a time. - -Programs should enforce IFF's syntactic rules when reading and writing -files. This ensures robust data transfer. The public domain IFF reader/writer -subroutine package does this for you. A utility program "IFFCheck" -is available that scans an IFF file and checks it for conformance -to IFF's syntactic rules. IFFCheck also prints an outline of the chunks -in the file, showing the ckID and ckSize of each. This is quite handy -when building IFF programs. Example programs are also available to -show details of reading and writing IFF files. - -A merge program "IFFJoin" will be available that logically appends -IFF files into a single CAT group. It "unwraps" each input file that -is a CAT so that the combined file isn't nested CATs. - -If we need to revise the IFF standard, the three anchoring IDs will -be used as "version numbers". That's why IDs "FOR1" through "FOR9", -"LIS1" through "LIS9", and "CAT1" through "CAT9" are reserved. - -IFF formats are designed for reasonable performance with floppy disks. -We achieve considerable simplicity in the formats and programs by -relying on the host file system rather than defining universal grouping -structures like directories for LIST contents. On huge storage systems, -IFF files could be leaf nodes in a file structure like a B-tree. Let's -hope the host file system implements that for us! - -Thre are two kinds of IFF files: single purpose files and scrap files. -They differ in the interpretation of multiple data objects and in -the file's external type. - -Single Purpose Files - -A single purpose IFF file is for normal "document" and "archive" storage. -This is in contrast with "scrap files" (see below) and temporary backing -storage (non-interchange files). - -The external file type (or filename extension, depending on the host -file system) indicates the file's contents. It's generally the FORM -type of the data contained, hence the restrictions on FORM type IDs. - -Programmers and users may pick an "intended use" type as the filename -extension to make it easy to filter for the relevant files in a filename -requestor. This is actually a "subclass" or "subtype" that conveniently -separates files of the same FORM type that have different uses. Programs -cannot demand conformity to its expected subtypes without overly restricting -data interchange since they cannot know about the subtypes to be used -by future programs that users will want to exchange data with. - -Issue: How to generate 3-letter MS-DOS extensions from 4-letter FORM -type IDs? - -Most single purpose files will be a single FORM (perhaps a composite -FORM like a musical score containing nested FORMs like musical instrument -descriptions). If it's a LIST or a CAT, programs should skip over -unrecognized objects to read the recognized ones or the first recognized -one. Then a program that can read a single purpose file can read something -out of a "scrap file", too. - -Scrap Files - -A "scrap file" is for maximum interconnectivity in getting data between -programs; the core of a clipboard function. Scrap files may have type -"IFF " or filename extension ".IFF". - -A scrap file is typically a CAT containing alternate representations -of the same basic information. Include as many alternatives as you -can readily generate. This redundancy improves interconnectivity in -situations where we can't make all programs read and write super-general -formats. [Inside Macintosh chapter "Scrap Manager".] E.g. a graphically- -annotated musical score might be supplemented by a stripped down 4-voice -melody and by a text (the lyrics). - -The originating program should write the alternate representations -in order of "preference": most preferred (most comprehensive) type -to least preferred (least comprehensive) type. A receiving program -should either use the first appearing type that it understands or -search for its own "preferred" type. - -A scrap file should have at most one alternative of any type. (A LIST -of same type objects is ok as one of the alternatives.) But don't -count on this when reading; ignore extra sections of a type. Then -a program that reads scrap files can read something out of single -purpose files. - -Rules for Reader Programs - -Here are some notes on building programs that read IFF files. If you -use the standard IFF reader module "IFFR.C", many of these rules and -details will be automatically handled. (See "Support Software" in -Appendix A.) We recommend that you start from the example program -"ShowILBM.C". You should also read up on recursive descent parsers. -[See, for example, Compiler Construction, An Advanced Course.] - -% The standard is very flexible so many programs can exchange -data. This implies a program has to scan the file and react to what's -actually there in whatever order it appears. An IFF reader program -is a parser. - -% For interchange to really work, programs must be willing to -do some conversion during read-in. If the data isn't exactly what -you expect, say, the raster is smaller than those created by your -program, then adjust it. Similarly, your program could crop a large -picture, add or drop bitplanes, and create/discard a mask plane. The -program should give up gracefully on data that it can't convert. - -% If it doesn't start with "FORM", "LIST", or "CAT ", it's not -an IFF-85 file. - -% For any chunk you encounter, you must recognize its type ID -to understand its contents. - -% For any FORM chunk you encounter, you must recognize its FORM -type ID to understand the contained "local chunks". Even if you don't -recognize the FORM type, you can still scan it for nested FORMs, LISTs, -and CATs of interest. - -% Don't forget to skip the pad byte after every odd-length chunk. - -% Chunk types LIST, FORM, PROP, and CAT are generic groups. They -always contain a subtype ID followed by chunks. - -% Readers ought to handle a CAT of FORMs in a file. You may treat -the FORMs like document pages to sequence through or just use the -first FORM. - -% Simpler IFF readers completely skip LISTs. "Fully IFF-conforming" -readers are those that handle LISTs, even if just to read the first -FORM from a file. If you do look into a LIST, you must process shared -properties (in PROP chunks) properly. The idea is to get the correct -data or none at all. - -% The nicest readers are willing to look into unrecognized FORMs -for nested FORM types that they do recognize. For example, a musical -score may contain nested instrument descriptions and an animation -file may contain still pictures. - -Note to programmers: Processing PROP chunks is not simple! You'll -need some background in interpreters with stack frames. If this is -foreign to you, build programs that read/write only one FORM per file. -For the more intrepid programmers, the next paragraph summarizes how -to process LISTs and PROPs. See the general IFF reader module "IFFR.C" -and the example program "ShowILBM.C" for details. - -Allocate a stack frame for every LIST and FORM you encounter and initialize -it by copying the stack frame of the parent LIST or FORM. At the top -level, you'll need a stack frame initialized to your program's global -defaults. While reading each LIST or FORM, store all encountered properties -into the current stack frame. In the example ShowILBM, each stack -frame has a place for a bitmap header property ILBM.BMHD and a color -map property ILBM.CMAP. When you finally get to the ILBM's BODY chunk, -use the property settings accumulated in the current stack frame. - -An alternate implementation would just remember PROPs encountered, -forgetting each on reaching the end of its scope (the end of the containing -LIST). When a FORM XXXX is encountered, scan the chunks in all remembered -PROPs XXXX, in order, as if they appeared before the chunks actually -in the FORM XXXX. This gets trickier if you read FORMs inside of FORMs. - -Rules for Writer Programs - -Here are some notes on building programs that write IFF files, which -is much easier than reading them. If you use the standard IFF writer -module "IFFW.C" (see "Support Software" in Appendix A), many of these -rules and details will automatically be enforced. See the example -program "Raw2ILBM.C". - -% An IFF file is a single FORM, LIST, or CAT chunk. - -% Any IFF-85 file must start with the 4 characters "FORM", "LIST", -or "CAT ", followed by a LONG ckSize. There should be no data after -the chunk end. - -% Chunk types LIST, FORM, PROP, and CAT are generic. They always -contain a subtype ID followed by chunks. These three IDs are universally -reserved, as are "LIS1" through "LIS9", "FOR1" through "FOR9", "CAT1" -through "CAT9", and " ". - -% Don't forget to write a 0 pad byte after each odd-length chunk. - -% Four techniques for writing an IFF group: (1) build the data -in a file mapped into virtual memory, (2) build the data in memory -blocks and use block I/O, (3) stream write the data piecemeal and -(don't forget!) random access back to set the group length count, -and (4) make a preliminary pass to compute the length count then stream -write the data. - -% Do not try to edit a file that you don't know how to create. -Programs may look into a file and copy out nested FORMs of types that -they recognize, but don't edit and replace the nested FORMs and don't -add or remove them. That could make the containing structure inconsistent. -You may write a new file containing items you copied (or copied and -modified) from another IFF file, but don't copy structural parts you -don't understand. - -% You must adhere to the syntax descriptions in Appendex A. E.g. -PROPs may only appear inside LISTs. - - - - -Appendix A. Reference - -Type Definitions - -The following C typedefs describe standard IFF structures. Declarations -to use in practice will vary with the CPU and compiler. For example, -68000 Lattice C produces efficient comparison code if we define ID -as a "LONG". A macro "MakeID" builds these IDs at compile time. - -/* Standard IFF types, expressed in 68000 Lattice C. */ - -typedef unsigned char UBYTE; /* 8 bits unsigned */ -typedef short WORD; /* 16 bits signed */ -typedef unsigned short UWORD; /* 16 bits unsigned */ -typedef long LONG; /* 32 bits signed */ - -typedef char ID[4]; /* 4 chars in ' ' through '~' */ - -typedef struct { - ID ckID; - LONG ckSize; /* sizeof(ckData) */ - UBYTE ckData[/* ckSize */]; - } Chunk; - -/* ID typedef and builder for 68000 Lattice C. */ -typedef LONG ID; /* 4 chars in ' ' through '~' */ -#define MakeID(a,b,c,d) ( (a)<<<<24 | (b)<<<<16 | (c)<<<<8 | (d) ) - -/* Globally reserved IDs. */ -#define ID_FORM MakeID('F','O','R','M') -#define ID_LIST MakeID('L','I','S','T') -#define ID_PROP MakeID('P','R','O','P') -#define ID_CAT MakeID('C','A','T',' ') -#define ID_FILLER MakeID(' ',' ',' ',' ') - -Syntax Definitions - -Here's a collection of the syntax definitions in this document. - -Chunk ::= ID #{ UBYTE* } [0] - -Property::= Chunk - -FORM ::= "FORM" #{ FormType (LocalChunk | FORM | LIST | CAT)* -} -FormType::= ID -LocalChunk ::= Property | Chunk - -CAT ::= "CAT " #{ ContentsType (FORM | LIST | CAT)* } -ContentsType ::= ID -- a hint or an "abstract data type" ID - -LIST ::= "LIST" #{ ContentsType PROP* (FORM | LIST | CAT)* } -PROP ::= "PROP" #{ FormType Property* } - -In this extended regular expression notation, the token "#" represents -a ckSize LONG count of the following {braced} data bytes. Literal -items are shown in "quotes", [square bracketed items] are optional, -and "*" means 0 or more instances. A sometimes-needed pad byte is -shown as "[0]". - -Defined Chunk IDs - -This is a table of currently defined chunk IDs. We may also borrow -some Macintosh IDs and data formats. - -Group chunk IDs - FORM, LIST, PROP, CAT. -Future revision group chunk IDs - FOR1 I FOR9, LIS1 I LIS9, CAT1 I CAT9. -FORM type IDs - (The above group chunk IDs may not be used for FORM type IDs.) - (Lower case letters and punctuation marks are forbidden in FORM -type IDs.) - 8SVX 8-bit sampled sound voice, ANBM animated bitmap, FNTR raster -font, FNTV vector font, FTXT formatted text, GSCR general-use musical -score, ILBM interleaved raster bitmap image, PDEF Deluxe Print page -definition, PICS Macintosh picture, PLBM (obsolete), USCR Uhuru Sound -Software musical score, UVOX Uhuru Sound Software Macintosh voice, -SMUS simple musical score, VDEO Deluxe Video Construction Set video. -Data chunk IDs - "JJJJ", TEXT, PICT. -PROP LIST property IDs - OPGM, OCPU, OCMP, OSN, UNAM. - - - -Support Software - -These public domain C source programs are available for use in building -IFF-compatible programs: - -IFF.H, IFFR.C, IFFW.C - - IFF reader and writer package. - These modules handle many of the details of reliably - reading and writing IFF files. - -IFFCheck.C This handy utility program scans an IFF file, checks - that the contents are well formed, and prints an outline - of the chunks. - -PACKER.H, Packer.C, UnPacker.C - - Run encoder and decoder used for ILBM files. - -ILBM.H, ILBMR.C, ILBMW.C - - Reader and writer support routines for raster image - FORM ILBM. ILBMR calls IFFR and UnPacker. ILBMW calls - IFFW and Packer. - -ShowILBM.C - Example caller of IFFR and ILBMR modules. This - Commodore-Amiga program reads and displays a FORM ILBM. -Raw2ILBM.C - Example ILBM writer program. As a demonstration, it - reads a raw raster image file and writes the image - as a FORM ILBM file. -ILBM2Raw.C - Example ILBM reader program. Reads a FORM ILBM file - and writes it into a raw raster image. - -REMALLOC.H, Remalloc.c - - Memory allocation routines used in these examples. - -INTUALL.H generic "include almost everything" include-file - with the sequence of includes correctly specified. - -READPICT.H, ReadPict.c - - given an ILBM file, read it into a bitmap and - a color map - -PUTPICT.H, PutPict.c - - given a bitmap and a color map, save it as - an ILBM file. - -GIO.H, Gio.c generic I/O speedup package. Attempts to speed - disk I/O by buffering writes and reads. - -giocall.c sample call to gio. - -ilbmdump.c reads in ILBM file, prints out ascii representation - for including in C files. - -bmprintc.c prints out a C-language representation of data for - a bitmap. - - - -Example Diagrams - -Here's a box diagram for an example IFF file, a raster image FORM -ILBM. This FORM contains a bitmap header property chunk BMHD, a color -map property chunk CMAP, and a raster data chunk BODY. This particular -raster is 320 x 200 pixels x 3 bit planes uncompressed. The "0" after -the CMAP chunk represents a zero pad byte; included since the CMAP -chunk has an odd length. The text to the right of the diagram shows -the outline that would be printed by the IFFCheck utility program -for this particular file. - - +-----------------------------------+ - |'FORM' 24070 | FORM 24070 IBLM - +-----------------------------------+ - |'ILBM' | - +-----------------------------------+ - | +-------------------------------+ | - | | 'BMHD' 20 | | .BMHD 20 - | | 320, 200, 0, 0, 3, 0, 0, ... | | - | + ------------------------------+ | - | | 'CMAP' 21 | | .CMAP 21 - | | 0, 0, 0; 32, 0, 0; 64,0,0; .. | | - | +-------------------------------+ | - | 0 | - +-----------------------------------+ - |'BODY' 24000 | .BODY 24000 - |0, 0, 0, ... | - +-----------------------------------+ - -This second diagram shows a LIST of two FORMs ILBM sharing a common -BMHD property and a common CMAP property. Again, the text on the right -is an outline a la IFFCheck. - - - +-----------------------------------------+ - |'LIST' 48114 | LIST 48114 AAAA - +-----------------------------------------+ - |'AAAA' | .PROP 62 ILBM - | +-----------------------------------+ | - | |'PROP' 62 | | - | +-----------------------------------+ | - | |'ILBM' | | - | +-----------------------------------+ | - | | +-------------------------------+ | | - | | | 'BMHD' 20 | | | ..BMHD 20 - | | | 320, 200, 0, 0, 3, 0, 0, ... | | | - | | | ------------------------------+ | | - | | | 'CMAP' 21 | | | ..CMAP 21 - | | | 0, 0, 0; 32, 0, 0; 64,0,0; .. | | | - | | +-------------------------------+ | | - | | 0 | | - | +-----------------------------------+ | - | +-----------------------------------+ | - | |'FORM' 24012 | | .FORM 24012 ILBM - | +-----------------------------------+ | - | |'ILBM' | | - | +-----------------------------------+ | - | | +-----------------------------+ | | - | | |'BODY' 24000 | | | ..BODY 24000 - | | |0, 0, 0, ... | | | - | | +-----------------------------+ | | - | +-----------------------------------+ | - | +-----------------------------------+ | - | |'FORM' 24012 | | .FORM 24012 ILBM - | +-----------------------------------+ | - | |'ILBM' | | - | +-----------------------------------+ | - | | +-----------------------------+ | | - | | |'BODY' 24000 | | | ..BODY 24000 - | | |0, 0, 0, ... | | | - | | +-----------------------------+ | | - | +-----------------------------------+ | - +-----------------------------------------+ - - - -Appendix B. Standards Committee - -The following people contributed to the design of this IFF standard: - -Bob "Kodiak" Burns, Commodore-Amiga -R. J. Mical, Commodore-Amiga -Jerry Morrison, Electronic Arts -Greg Riker, Electronic Arts -Steve Shaw, Electronic Arts -Barry Walsh, Commodore-Amiga diff --git a/16/PCGPE10/INTEL.DOC b/16/PCGPE10/INTEL.DOC deleted file mode 100644 index bd7d758c..00000000 --- a/16/PCGPE10/INTEL.DOC +++ /dev/null @@ -1,2807 +0,0 @@ - -Intel 8086 Family Architecture. . . . . . . . . . . . . . . . . . . . . 3 - -Instruction Clock Cycle Calculation . . . . . . . . . . . . . . . . . . 3 - -8088/8086 Effective Address (EA) Calculation . . . . . . . . . . . . . 3 - -Task State Calculation. . . . . . . . . . . . . . . . . . . . . . . . . 4 - -FLAGS - Intel 8086 Family Flags Register. . . . . . . . . . . . . . . . 4 - -MSW - Machine Status Word (286+ only) . . . . . . . . . . . . . . . . . 5 - -8086/80186/80286/80386/80486 Instruction Set. . . . . . . . . . . . . . 6 - AAA - Ascii Adjust for Addition. . . . . . . . . . . . . . . . . . 6 - AAD - Ascii Adjust for Division. . . . . . . . . . . . . . . . . . 6 - AAM - Ascii Adjust for Multiplication. . . . . . . . . . . . . . . 6 - AAS - Ascii Adjust for Subtraction . . . . . . . . . . . . . . . . 6 - ADC - Add With Carry . . . . . . . . . . . . . . . . . . . . . . . 7 - ADD - Arithmetic Addition. . . . . . . . . . . . . . . . . . . . . 7 - AND - Logical And. . . . . . . . . . . . . . . . . . . . . . . . . 7 - ARPL - Adjusted Requested Privilege Level of Selector (286+ PM). . 7 - BOUND - Array Index Bound Check (80188+) . . . . . . . . . . . . . 8 - BSF - Bit Scan Forward (386+). . . . . . . . . . . . . . . . . . . 8 - BSR - Bit Scan Reverse (386+) . . . . . . . . . . . . . . . . . . 8 - BSWAP - Byte Swap (486+) . . . . . . . . . . . . . . . . . . 8 - BT - Bit Test (386+) . . . . . . . . . . . . . . . . . . 9 - BTC - Bit Test with Compliment (386+). . . . . . . . . . . . . . . 9 - BTR - Bit Test with Reset (386+) . . . . . . . . . . . . . . . . . 9 - BTS - Bit Test and Set (386+) . . . . . . . . . . . . . . . . . . 9 - CALL - Procedure Call. . . . . . . . . . . . . . . . . . . . . . . 10 - CBW - Convert Byte to Word . . . . . . . . . . . . . . . . . . . . 10 - CDQ - Convert Double to Quad (386+). . . . . . . . . . . . . . . . 10 - CLC - Clear Carry. . . . . . . . . . . . . . . . . . . . . . . . . 11 - CLD - Clear Direction Flag . . . . . . . . . . . . . . . . . . . . 11 - CLI - Clear Interrupt Flag (disable) . . . . . . . . . . . . . . . 11 - CLTS - Clear Task Switched Flag (286+ privileged). . . . . . . . . 11 - CMC - Complement Carry Flag. . . . . . . . . . . . . . . . . . . . 11 - CMP - Compare. . . . . . . . . . . . . . . . . . . . . . . . . . . 12 - CMPS - Compare String (Byte, Word or Doubleword) . . . . . . . . . 12 - CMPXCHG - Compare and Exchange . . . . . . . . . . . . . . . . . . 12 - CWD - Convert Word to Doubleword . . . . . . . . . . . . . . . . . 12 - CWDE - Convert Word to Extended Doubleword (386+). . . . . . . . . 13 - DAA - Decimal Adjust for Addition. . . . . . . . . . . . . . . . . 13 - DAS - Decimal Adjust for Subtraction . . . . . . . . . . . . . . . 13 - DEC - Decrement. . . . . . . . . . . . . . . . . . . . . . . . . . 13 - DIV - Divide . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 - ENTER - Make Stack Frame (80188+) . . . . . . . . . . . . . . . . 14 - ESC - Escape . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 - HLT - Halt CPU . . . . . . . . . . . . . . . . . . . . . . . . . . 14 - IDIV - Signed Integer Division . . . . . . . . . . . . . . . . . . 14 - IMUL - Signed Multiply . . . . . . . . . . . . . . . . . . . . . . 15 - IN - Input Byte or Word From Port. . . . . . . . . . . . . . . . . 15 - INC - Increment. . . . . . . . . . . . . . . . . . . . . . . . . . 16 - INS - Input String from Port (80188+) . . . . . . . . . . . . . . 16 - INT - Interrupt. . . . . . . . . . . . . . . . . . . . . . . . . . 16 - INTO - Interrupt on Overflow . . . . . . . . . . . . . . . . . . . 17 - INVD - Invalidate Cache (486+). . . . . . . . . . . . . . . . . . 17 - INVLPG - Invalidate Translation Look-Aside Buffer Entry (486+) . . 17 - IRET/IRETD - Interrupt Return. . . . . . . . . . . . . . . . . . . 17 - Jxx - Jump Instructions Table. . . . . . . . . . . . . . . . . . . 18 - JCXZ/JECXZ - Jump if Register (E)CX is Zero. . . . . . . . . . . . 18 - JMP - Unconditional Jump . . . . . . . . . . . . . . . . . . . . . 19 - LAHF - Load Register AH From Flags . . . . . . . . . . . . . . . . 19 - LAR - Load Access Rights (286+ protected). . . . . . . . . . . . . 19 - LDS - Load Pointer Using DS. . . . . . . . . . . . . . . . . . . . 20 - LEA - Load Effective Address . . . . . . . . . . . . . . . . . . . 20 - LEAVE - Restore Stack for Procedure Exit (80188+). . . . . . . . . 20 - LES - Load Pointer Using ES. . . . . . . . . . . . . . . . . . . . 20 - LFS - Load Pointer Using FS (386+) . . . . . . . . . . . . . . . . 21 - LGDT - Load Global Descriptor Table (286+ privileged). . . . . . . 21 - LIDT - Load Interrupt Descriptor Table (286+ privileged) . . . . . 21 - LGS - Load Pointer Using GS (386+) . . . . . . . . . . . . . . . . 21 - LLDT - Load Local Descriptor Table (286+ privileged) . . . . . . . 22 - LMSW - Load Machine Status Word (286+ privileged). . . . . . . . . 22 - LOCK - Lock Bus. . . . . . . . . . . . . . . . . . . . . . . . . . 22 - LODS - Load String (Byte, Word or Double). . . . . . . . . . . . . 22 - LOOP - Decrement CX and Loop if CX Not Zero. . . . . . . . . . . . 23 - LOOPE/LOOPZ - Loop While Equal / Loop While Zero . . . . . . . . . 23 - LOOPNZ/LOOPNE - Loop While Not Zero / Loop While Not Equal . . . . 23 - LSL - Load Segment Limit (286+ protected). . . . . . . . . . . . . 23 - LSS - Load Pointer Using SS (386+) . . . . . . . . . . . . . . . . 24 - LTR - Load Task Register (286+ privileged) . . . . . . . . . . . . 24 - MOV - Move Byte or Word. . . . . . . . . . . . . . . . . . . . . . 24 - MOVS - Move String (Byte or Word). . . . . . . . . . . . . . . . . 25 - MOVSX - Move with Sign Extend (386+) . . . . . . . . . . . . . . . 25 - MOVZX - Move with Zero Extend (386+) . . . . . . . . . . . . . . . 25 - MUL - Unsigned Multiply. . . . . . . . . . . . . . . . . . . . . . 25 - NEG - Two's Complement Negation. . . . . . . . . . . . . . . . . . 26 - NOP - No Operation (90h) . . . . . . . . . . . . . . . . . . . . . 26 - NOT - One's Compliment Negation (Logical NOT). . . . . . . . . . . 26 - OR - Inclusive Logical OR. . . . . . . . . . . . . . . . . . . . . 26 - OUT - Output Data to Port. . . . . . . . . . . . . . . . . . . . . 27 - OUTS - Output String to Port (80188+) . . . . . . . . . . . . . . 27 - POP - Pop Word off Stack . . . . . . . . . . . . . . . . . . . . . 27 - POPA/POPAD - Pop All Registers onto Stack (80188+). . . . . . . . 28 - POPF/POPFD - Pop Flags off Stack . . . . . . . . . . . . . . . . . 28 - PUSH - Push Word onto Stack. . . . . . . . . . . . . . . . . . . . 28 - PUSHA/PUSHAD - Push All Registers onto Stack (80188+) . . . . . . 28 - PUSHF/PUSHFD - Push Flags onto Stack . . . . . . . . . . . . . . . 29 - RCL - Rotate Through Carry Left. . . . . . . . . . . . . . . . . . 29 - RCR - Rotate Through Carry Right . . . . . . . . . . . . . . . . . 29 - REP - Repeat String Operation. . . . . . . . . . . . . . . . . . . 30 - REPE/REPZ - Repeat Equal / Repeat Zero . . . . . . . . . . . . . . 30 - REPNE/REPNZ - Repeat Not Equal / Repeat Not Zero . . . . . . . . . 30 - RET/RETF - Return From Procedure . . . . . . . . . . . . . . . . . 31 - ROL - Rotate Left. . . . . . . . . . . . . . . . . . . . . . . . . 31 - ROR - Rotate Right . . . . . . . . . . . . . . . . . . . . . . . . 31 - SAHF - Store AH Register into FLAGS. . . . . . . . . . . . . . . . 32 - SAL/SHL - Shift Arithmetic Left / Shift Logical Left . . . . . . . 32 - SAR - Shift Arithmetic Right . . . . . . . . . . . . . . . . . . . 32 - SBB - Subtract with Borrow/Carry . . . . . . . . . . . . . . . . . 33 - SCAS - Scan String (Byte, Word or Doubleword) . . . . . . . . . . 33 - SETAE/SETNB - Set if Above or Equal / Set if Not Below (386+). . . 33 - SETB/SETNAE - Set if Below / Set if Not Above or Equal (386+). . . 33 - SETBE/SETNA - Set if Below or Equal / Set if Not Above (386+). . . 34 - SETE/SETZ - Set if Equal / Set if Zero (386+). . . . . . . . . . . 34 - SETNE/SETNZ - Set if Not Equal / Set if Not Zero (386+). . . . . . 34 - SETL/SETNGE - Set if Less / Set if Not Greater or Equal (386+) . . 34 - SETGE/SETNL - Set if Greater or Equal / Set if Not Less (386+) . . 35 - SETLE/SETNG - Set if Less or Equal / Set if Not greater or Equal (386+) 35 - SETG/SETNLE - Set if Greater / Set if Not Less or Equal (386+) . . 35 - SETS - Set if Signed (386+). . . . . . . . . . . . . . . . . . . . 35 - SETNS - Set if Not Signed (386+) . . . . . . . . . . . . . . . . . 36 - SETC - Set if Carry (386+) . . . . . . . . . . . . . . . . . . . . 36 - SETNC - Set if Not Carry (386+). . . . . . . . . . . . . . . . . . 36 - SETO - Set if Overflow (386+). . . . . . . . . . . . . . . . . . . 36 - SETNO - Set if Not Overflow (386+) . . . . . . . . . . . . . . . . 36 - SETP/SETPE - Set if Parity / Set if Parity Even (386+). . . . . . 37 - SETNP/SETPO - Set if No Parity / Set if Parity Odd (386+). . . . . 37 - SGDT - Store Global Descriptor Table (286+ privileged) . . . . . . 37 - SIDT - Store Interrupt Descriptor Table (286+ privileged). . . . . 37 - SHL - Shift Logical Left . . . . . . . . . . . . . . . . . . . . . 37 - SHR - Shift Logical Right. . . . . . . . . . . . . . . . . . . . . 38 - SHLD/SHRD - Double Precision Shift (386+). . . . . . . . . . . . . 38 - SLDT - Store Local Descriptor Table (286+ privileged). . . . . . . 38 - SMSW - Store Machine Status Word (286+ privileged) . . . . . . . . 38 - STC - Set Carry. . . . . . . . . . . . . . . . . . . . . . . . . . 39 - STD - Set Direction Flag . . . . . . . . . . . . . . . . . . . . . 39 - STI - Set Interrupt Flag (Enable Interrupts). . . . . . . . . . . 39 - STOS - Store String (Byte, Word or Doubleword). . . . . . . . . . 39 - STR - Store Task Register (286+ privileged). . . . . . . . . . . . 39 - SUB - Subtract . . . . . . . . . . . . . . . . . . . . . . . . . . 40 - TEST - Test For Bit Pattern. . . . . . . . . . . . . . . . . . . . 40 - VERR - Verify Read (286+ protected). . . . . . . . . . . . . . . . 40 - VERW - Verify Write (286+ protected) . . . . . . . . . . . . . . . 40 - WAIT/FWAIT - Event Wait. . . . . . . . . . . . . . . . . . . . . . 41 - WBINVD - Write-Back and Invalidate Cache (486+). . . . . . . . . . 41 - XCHG - Exchange. . . . . . . . . . . . . . . . . . . . . . . . . . 41 - XLAT/XLATB - Translate . . . . . . . . . . . . . . . . . . . . . . 41 - XOR - Exclusive OR . . . . . . . . . . . . . . . . . . . . . . . . 42 - -Intel 8086 Family Architecture - - General Purpose Registers Segment Registers - - AH/AL AX (EAX) Accumulator CS Code Segment - BH/BL BX (EBX) Base DS Data Segment - CH/CL CX (ECX) Counter SS Stack Segment - DH/DL DX (EDX) Data ES Extra Segment - (FS) 386 and newer - (Exx) indicates 386+ 32 bit register (GS) 386 and newer - - - Pointer Registers Stack Registers - - SI (ESI) Source Index SP (ESP) Stack Pointer - DI (EDI) Destination Index BP (EBP) Base Pointer - IP Instruction Pointer - - Status Registers - - FLAGS Status Flags (see FLAGS) - - Special Registers (386+ only) - - CR0 Control Register 0 DR0 Debug Register 0 - CR2 Control Register 2 DR1 Debug Register 1 - CR3 Control Register 3 DR2 Debug Register 2 - DR3 Debug Register 3 - TR4 Test Register 4 DR6 Debug Register 6 - TR5 Test Register 5 DR7 Debug Register 7 - TR6 Test Register 6 - TR7 Test Register 7 - - Register Default Segment Valid Overrides - - BP SS DS, ES, CS - SI or DI DS ES, SS, CS - DI strings ES None - SI strings DS ES, SS, CS - - - - see CPU DETECTING Instruction Timing - -Instruction Clock Cycle Calculation - - - Some instructions require additional clock cycles due to a "Next - Instruction Component" identified by a "+m" in the instruction - clock cycle listings. This is due to the prefetch queue being - purge on a control transfers. Below is the general rule for - calculating "m": - - - 88/86 not applicable - 286 "m" is the number of bytes in the next instruction - 386 "m" is the number of components in the next instruction - (the instruction coding (each byte), plus the data and - the displacement are all considered components) - - -8088/8086 Effective Address (EA) Calculation - - Description Clock Cycles - - Displacement 6 - Base or Index (BX,BP,SI,DI) 5 - Displacement+(Base or Index) 9 - Base+Index (BP+DI,BX+SI) 7 - Base+Index (BP+SI,BX+DI) 8 - Base+Index+Displacement (BP+DI,BX+SI) 11 - Base+Index+Displacement (BP+SI+disp,BX+DI+disp) 12 - - - - add 4 cycles for word operands at odd addresses - - add 2 cycles for segment override - - 80188/80186 timings differ from those of the 8088/8086/80286 - Task State Calculation - - "TS" is defined as switching from VM/486 or 80286 TSS to one of - the following: - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ New Task ³ - ÃÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄ´ - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´486 TSS³486 TSS³386 TSS³386 TSS³286 TSS³ - ³ Old Task ³ (VM=0)³ (VM=1)³ (VM=0)³ (VM=1)³ ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄ´ - 386 TSS (VM=0) ³ ³ ³ 309 ³ 226 ³ 282 ³ - ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄ´ - 386 TSS (VM=1) ³ ³ ³ 314 ³ 231 ³ 287 ³ - ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄ´ - 386 CPU/286 TSS ³ ³ ³ 307 ³ 224 ³ 280 ³ - ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄ´ - 486 CPU/286 TSS ³ 199 ³ 177 ³ ³ ³ 180 ³ - ÀÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÙ - - - Miscellaneous - - - all timings are for best case and do not take into account wait - states, instruction alignment, the state of the prefetch queue, - DMA refresh cycles, cache hits/misses or exception processing. - - to convert clocks to nanoseconds divide one microsecond by the - processor speed in MegaHertz: - - (1000MHz/(n MHz)) = X nanoseconds - - - see 8086 Architecture - - -FLAGS - Intel 8086 Family Flags Register - - ³11³10³F³E³D³C³B³A³9³8³7³6³5³4³3³2³1³0³ - ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ÀÄÄÄ CF Carry Flag - ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ÀÄÄÄ 1 - ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ÀÄÄÄ PF Parity Flag - ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ÀÄÄÄ 0 - ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ÀÄÄÄ AF Auxiliary Flag - ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ÀÄÄÄ 0 - ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ÀÄÄÄ ZF Zero Flag - ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ÀÄÄÄ SF Sign Flag - ³ ³ ³ ³ ³ ³ ³ ³ ³ ÀÄÄÄ TF Trap Flag (Single Step) - ³ ³ ³ ³ ³ ³ ³ ³ ÀÄÄÄ IF Interrupt Flag - ³ ³ ³ ³ ³ ³ ³ ÀÄÄÄ DF Direction Flag - ³ ³ ³ ³ ³ ³ ÀÄÄÄ OF Overflow flag - ³ ³ ³ ³ ÀÄÁÄÄÄ IOPL I/O Privilege Level (286+ only) - ³ ³ ³ ÀÄÄÄÄÄ NT Nested Task Flag (286+ only) - ³ ³ ÀÄÄÄÄÄ 0 - ³ ÀÄÄÄÄÄ RF Resume Flag (386+ only) - ÀÄÄÄÄÄÄ VM Virtual Mode Flag (386+ only) - - - see PUSHF POPF STI CLI STD CLD - MSW - Machine Status Word (286+ only) - - - ³31³30-5³4³3³2³1³0³ Machine Status Word - ³ ³ ³ ³ ³ ³ ÀÄÄÄÄ Protection Enable (PE) - ³ ³ ³ ³ ³ ÀÄÄÄÄÄ Math Present (MP) - ³ ³ ³ ³ ÀÄÄÄÄÄÄ Emulation (EM) - ³ ³ ³ ÀÄÄÄÄÄÄÄ Task Switched (TS) - ³ ³ ÀÄÄÄÄÄÄÄÄ Extension Type (ET) - ³ ÀÄÄÄÄÄÄÄÄÄÄ Reserved - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄ Paging (PG) - - - Bit 0 PE Protection Enable, switches processor between - protected and real mode - Bit 1 MP Math Present, controls function of the WAIT - instruction - Bit 2 EM Emulation, indicates whether coprocessor functions - are to be emulated - Bit 3 TS Task Switched, set and interrogated by coprocessor - on task switches and when interpretting coprocessor - instructions - Bit 4 ET Extension Type, indicates type of coprocessor in - system - Bits 5-30 Reserved - bit 31 PG Paging, indicates whether the processor uses page - tables to translate linear addresses to physical - addresses - - - see SMSW LMSW - 8086/80186/80286/80386/80486 Instruction Set - -AAA - Ascii Adjust for Addition - - Usage: AAA - Modifies flags: AF CF (OF,PF,SF,ZF undefined) - - Changes contents of AL to valid unpacked decimal. The high order - nibble is zeroed. - - Clocks Size - Operands 808x 286 386 486 Bytes - - none 8 3 4 3 1 - - -AAD - Ascii Adjust for Division - - Usage: AAD - Modifies flags: SF ZF PF (AF,CF,OF undefined) - - Used before dividing unpacked decimal numbers. Multiplies AH by - 10 and the adds result into AL. Sets AH to zero. This instruction - is also known to have an undocumented behavior. - - AL := 10*AH+AL - AH := 0 - - Clocks Size - Operands 808x 286 386 486 Bytes - - none 60 14 19 14 2 - - -AAM - Ascii Adjust for Multiplication - - - Usage: AAM - Modifies flags: PF SF ZF (AF,CF,OF undefined) - - AH := AL / 10 - AL := AL mod 10 - - Used after multiplication of two unpacked decimal numbers, this - instruction adjusts an unpacked decimal number. The high order - nibble of each byte must be zeroed before using this instruction. - This instruction is also known to have an undocumented behavior. - - Clocks Size - Operands 808x 286 386 486 Bytes - - none 83 16 17 15 2 - - -AAS - Ascii Adjust for Subtraction - - Usage: AAS - Modifies flags: AF CF (OF,PF,SF,ZF undefined) - - Corrects result of a previous unpacked decimal subtraction in AL. - High order nibble is zeroed. - - Clocks Size - Operands 808x 286 386 486 Bytes - - none 8 3 4 3 1 - ADC - Add With Carry - - Usage: ADC dest,src - Modifies flags: AF CF OF SF PF ZF - - Sums two binary operands placing the result in the destination. - If CF is set, a 1 is added to the destination. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg,reg 3 2 2 1 2 - mem,reg 16+EA 7 7 3 2-4 (W88=24+EA) - reg,mem 9+EA 7 6 2 2-4 (W88=13+EA) - reg,immed 4 3 2 1 3-4 - mem,immed 17+EA 7 7 3 3-6 (W88=23+EA) - accum,immed 4 3 2 1 2-3 - - -ADD - Arithmetic Addition - - Usage: ADD dest,src - Modifies flags: AF CF OF PF SF ZF - - Adds "src" to "dest" and replacing the original contents of "dest". - Both operands are binary. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg,reg 3 2 2 1 2 - mem,reg 16+EA 7 7 3 2-4 (W88=24+EA) - reg,mem 9+EA 7 6 2 2-4 (W88=13+EA) - reg,immed 4 3 2 1 3-4 - mem,immed 17+EA 7 7 3 3-6 (W88=23+EA) - accum,immed 4 3 2 1 2-3 - - -AND - Logical And - - Usage: AND dest,src - Modifies flags: CF OF PF SF ZF (AF undefined) - - Performs a logical AND of the two operands replacing the destination - with the result. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg,reg 3 2 2 1 2 - mem,reg 16+EA 7 7 3 2-4 (W88=24+EA) - reg,mem 9+EA 7 6 1 2-4 (W88=13+EA) - reg,immed 4 3 2 1 3-4 - mem,immed 17+EA 7 7 3 3-6 (W88=23+EA) - accum,immed 4 3 2 1 2-3 - - -ARPL - Adjusted Requested Privilege Level of Selector (286+ PM) - - Usage: ARPL dest,src - (286+ protected mode) - Modifies flags: ZF - - Compares the RPL bits of "dest" against "src". If the RPL bits - of "dest" are less than "src", the destination RPL bits are set - equal to the source RPL bits and the Zero Flag is set. Otherwise - the Zero Flag is cleared. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg,reg - 10 20 9 2 - mem,reg - 11 21 9 4 - BOUND - Array Index Bound Check (80188+) - - Usage: BOUND src,limit - Modifies flags: None - - Array index in source register is checked against upper and lower - bounds in memory source. The first word located at "limit" is - the lower boundary and the word at "limit+2" is the upper array bound. - Interrupt 5 occurs if the source value is less than or higher than - the source. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg16,mem32 - nj=13 nj=10 7 2 - reg32,mem64 - nj=13 nj=10 7 2 - - - nj = no jump taken - - -BSF - Bit Scan Forward (386+) - - Usage: BSF dest,src - Modifies flags: ZF - - Scans source operand for first bit set. Sets ZF if a bit is found - set and loads the destination with an index to first set bit. Clears - ZF is no bits are found set. BSF scans forward across bit pattern - (0-n) while BSR scans in reverse (n-0). - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg,reg - - 10+3n 6-42 3 - reg,mem - - 10+3n 7-43 3-7 - reg32,reg32 - - 10+3n 6-42 3-7 - reg32,mem32 - - 10+3n 7-43 3-7 - - -BSR - Bit Scan Reverse (386+) - - Usage: BSR dest,src - Modifies flags: ZF - - Scans source operand for first bit set. Sets ZF if a bit is found - set and loads the destination with an index to first set bit. Clears - ZF is no bits are found set. BSF scans forward across bit pattern - (0-n) while BSR scans in reverse (n-0). - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg,reg - - 10+3n 6-103 3 - reg,mem - - 10+3n 7-104 3-7 - reg32,reg32 - - 10+3n 6-103 3-7 - reg32,mem32 - - 10+3n 7-104 3-7 - - -BSWAP - Byte Swap (486+) - - Usage: BSWAP reg32 - Modifies flags: none - - Changes the byte order of a 32 bit register from big endian to - little endian or vice versa. Result left in destination register - is undefined if the operand is a 16 bit register. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg32 - - - 1 2 - BT - Bit Test (386+) - - Usage: BT dest,src - Modifies flags: CF - - The destination bit indexed by the source value is copied into the - Carry Flag. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg16,immed8 - - 3 3 4-8 - mem16,immed8 - - 6 6 4-8 - reg16,reg16 - - 3 3 3-7 - mem16,reg16 - - 12 12 3-7 - - -BTC - Bit Test with Compliment (386+) - - Usage: BTC dest,src - Modifies flags: CF - - The destination bit indexed by the source value is copied into the - Carry Flag after being complimented (inverted). - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg16,immed8 - - 6 6 4-8 - mem16,immed8 - - 8 8 4-8 - reg16,reg16 - - 6 6 3-7 - mem16,reg16 - - 13 13 3-7 - - -BTR - Bit Test with Reset (386+) - - Usage: BTR dest,src - Modifies flags: CF - - The destination bit indexed by the source value is copied into the - Carry Flag and then cleared in the destination. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg16,immed8 - - 6 6 4-8 - mem16,immed8 - - 8 8 4-8 - reg16,reg16 - - 6 6 3-7 - mem16,reg16 - - 13 13 3-7 - - -BTS - Bit Test and Set (386+) - - Usage: BTS dest,src - Modifies flags: CF - - The destination bit indexed by the source value is copied into the - Carry Flag and then set in the destination. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg16,immed8 - - 6 6 4-8 - mem16,immed8 - - 8 8 4-8 - reg16,reg16 - - 6 6 3-7 - mem16,reg16 - - 13 13 3-7 - CALL - Procedure Call - - Usage: CALL destination - Modifies flags: None - - Pushes Instruction Pointer (and Code Segment for far calls) onto - stack and loads Instruction Pointer with the address of proc-name. - Code continues with execution at CS:IP. - - Clocks - Operands 808x 286 386 486 - - rel16 (near, IP relative) 19 7 7+m 3 - rel32 (near, IP relative) - - 7+m 3 - - reg16 (near, register indirect) 16 7 7+m 5 - reg32 (near, register indirect) - - 7+m 5 - - mem16 (near, memory indirect) - 21+EA 11 10+m 5 - mem32 (near, memory indirect) - - 10+m 5 - - ptr16:16 (far, full ptr supplied) 28 13 17+m 18 - ptr16:32 (far, full ptr supplied) - - 17+m 18 - ptr16:16 (far, ptr supplied, prot. mode) - 26 34+m 20 - ptr16:32 (far, ptr supplied, prot. mode) - - 34+m 20 - m16:16 (far, indirect) 37+EA 16 22+m 17 - m16:32 (far, indirect) - - 22+m 17 - m16:16 (far, indirect, prot. mode) - 29 38+m 20 - m16:32 (far, indirect, prot. mode) - - 38+m 20 - - ptr16:16 (task, via TSS or task gate) - 177 TS 37+TS - m16:16 (task, via TSS or task gate) - 180/185 5+TS 37+TS - m16:32 (task) - - TS 37+TS - m16:32 (task) - - 5+TS 37+TS - - ptr16:16 (gate, same privilege) - 41 52+m 35 - ptr16:32 (gate, same privilege) - - 52+m 35 - m16:16 (gate, same privilege) - 44 56+m 35 - m16:32 (gate, same privilege) - - 56+m 35 - - ptr16:16 (gate, more priv, no parm) - 82 86+m 69 - ptr16:32 (gate, more priv, no parm) - - 86+m 69 - m16:16 (gate, more priv, no parm) - 83 90+m 69 - m16:32 (gate, more priv, no parm) - - 90+m 69 - - ptr16:16 (gate, more priv, x parms) - 86+4x 94+4x+m 77+4x - ptr16:32 (gate, more priv, x parms) - - 94+4x+m 77+4x - m16:16 (gate, more priv, x parms) - 90+4x 98+4x+m 77+4x - m16:32 (gate, more priv, x parms) - - 98+4x+m 77+4x - - -CBW - Convert Byte to Word - - Usage: CBW - Modifies flags: None - - Converts byte in AL to word Value in AX by extending sign of AL - throughout register AH. - - Clocks Size - Operands 808x 286 386 486 Bytes - - none 2 2 3 3 1 - - -CDQ - Convert Double to Quad (386+) - - Usage: CDQ - Modifies flags: None - - Converts signed DWORD in EAX to a signed quad word in EDX:EAX by - extending the high order bit of EAX throughout EDX - - Clocks Size - Operands 808x 286 386 486 Bytes - - none - - 2 3 1 - CLC - Clear Carry - - Usage: CLC - Modifies flags: CF - - Clears the Carry Flag. - - Clocks Size - Operands 808x 286 386 486 Bytes - - none 2 2 2 2 1 - - -CLD - Clear Direction Flag - - Usage: CLD - Modifies flags: DF - - Clears the Direction Flag causing string instructions to increment - the SI and DI index registers. - - Clocks Size - Operands 808x 286 386 486 Bytes - - none 2 2 2 2 1 - - -CLI - Clear Interrupt Flag (disable) - - Usage: CLI - Modifies flags: IF - - Disables the maskable hardware interrupts by clearing the Interrupt - flag. NMI's and software interrupts are not inhibited. - - Clocks Size - Operands 808x 286 386 486 Bytes - - none 2 2 3 5 1 - - -CLTS - Clear Task Switched Flag (286+ privileged) - - Usage: CLTS - Modifies flags: None - - Clears the Task Switched Flag in the Machine Status Register. This - is a privileged operation and is generally used only by operating - system code. - - Clocks Size - Operands 808x 286 386 486 Bytes - - none - 2 5 7 2 - - -CMC - Complement Carry Flag - - Usage: CMC - Modifies flags: CF - - Toggles (inverts) the Carry Flag - - Clocks Size - Operands 808x 286 386 486 Bytes - - none 2 2 2 2 1 - CMP - Compare - - Usage: CMP dest,src - Modifies flags: AF CF OF PF SF ZF - - Subtracts source from destination and updates the flags but does - not save result. Flags can subsequently be checked for conditions. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg,reg 3 2 2 1 2 - mem,reg 9+EA 7 5 2 2-4 (W88=13+EA) - reg,mem 9+EA 6 6 2 2-4 (W88=13+EA) - reg,immed 4 3 2 1 3-4 - mem,immed 10+EA 6 5 2 3-6 (W88=14+EA) - accum,immed 4 3 2 1 2-3 - - -CMPS - Compare String (Byte, Word or Doubleword) - - Usage: CMPS dest,src - CMPSB - CMPSW - CMPSD (386+) - Modifies flags: AF CF OF PF SF ZF - - Subtracts destination value from source without saving results. - Updates flags based on the subtraction and the index registers - (E)SI and (E)DI are incremented or decremented depending on the - state of the Direction Flag. CMPSB inc/decrements the index - registers by 1, CMPSW inc/decrements by 2, while CMPSD increments - or decrements by 4. The REP prefixes can be used to process - entire data items. - - Clocks Size - Operands 808x 286 386 486 Bytes - - dest,src 22 8 10 8 1 (W88=30) - - -CMPXCHG - Compare and Exchange - - Usage: CMPXCHG dest,src (486+) - Modifies flags: AF CF OF PF SF ZF - - Compares the accumulator (8-32 bits) with "dest". If equal the - "dest" is loaded with "src", otherwise the accumulator is loaded - with "dest". - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg,reg - - - 6 2 - mem,reg - - - 7 2 - - - add 3 clocks if the "mem,reg" comparison fails - - -CWD - Convert Word to Doubleword - - Usage: CWD - Modifies flags: None - - Extends sign of word in register AX throughout register DX forming - a doubleword quantity in DX:AX. - - Clocks Size - Operands 808x 286 386 486 Bytes - - none 5 2 2 3 1 - CWDE - Convert Word to Extended Doubleword (386+) - - Usage: CWDE - Modifies flags: None - - Converts a signed word in AX to a signed doubleword in EAX by - extending the sign bit of AX throughout EAX. - - Clocks Size - Operands 808x 286 386 486 Bytes - - none - - 3 3 1 - - -DAA - Decimal Adjust for Addition - - Usage: DAA - Modifies flags: AF CF PF SF ZF (OF undefined) - - Corrects result (in AL) of a previous BCD addition operation. - Contents of AL are changed to a pair of packed decimal digits. - - Clocks Size - Operands 808x 286 386 486 Bytes - - none 4 3 4 2 1 - - -DAS - Decimal Adjust for Subtraction - - Usage: DAS - Modifies flags: AF CF PF SF ZF (OF undefined) - - Corrects result (in AL) of a previous BCD subtraction operation. - Contents of AL are changed to a pair of packed decimal digits. - - Clocks Size - Operands 808x 286 386 486 Bytes - - none 4 3 4 2 1 - - -DEC - Decrement - - Usage: DEC dest - Modifies flags: AF OF PF SF ZF - - Unsigned binary subtraction of one from the destination. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg8 3 2 2 1 2 - mem 15+EA 7 6 3 2-4 - reg16/32 3 2 2 1 1 - - -DIV - Divide - - Usage: DIV src - Modifies flags: (AF,CF,OF,PF,SF,ZF undefined) - - Unsigned binary division of accumulator by source. If the source - divisor is a byte value then AX is divided by "src" and the quotient - is placed in AL and the remainder in AH. If source operand is a word - value, then DX:AX is divided by "src" and the quotient is stored in AX - and the remainder in DX. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg8 80-90 14 14 16 2 - reg16 144-162 22 22 24 2 - reg32 - - 38 40 2 - mem8 (86-96)+EA 17 17 16 2-4 - mem16 (150-168)+EA 25 25 24 2-4 (W88=158-176+EA) - mem32 - - 41 40 2-4 - ENTER - Make Stack Frame (80188+) - - Usage: ENTER locals,level - Modifies flags: None - - Modifies stack for entry to procedure for high level language. - Operand "locals" specifies the amount of storage to be allocated - on the stack. "Level" specifies the nesting level of the routine. - Paired with the LEAVE instruction, this is an efficient method of - entry and exit to procedures. - - Clocks Size - Operands 808x 286 386 486 Bytes - - immed16,0 - 11 10 14 4 - immed16,1 - 15 12 17 4 - immed16,immed8 - 12+4(n-1) 15+4(n-1) 17+3n 4 - - -ESC - Escape - - Usage: ESC immed,src - Modifies flags: None - - Provides access to the data bus for other resident processors. - The CPU treats it as a NOP but places memory operand on bus. - - Clocks Size - Operands 808x 286 386 486 Bytes - - immed,reg 2 9-20 ? 2 - immed,mem 2 9-20 ? 2-4 - - -HLT - Halt CPU - - Usage: HLT - Modifies flags: None - - Halts CPU until RESET line is activated, NMI or maskable interrupt - received. The CPU becomes dormant but retains the current CS:IP - for later restart. - - Clocks Size - Operands 808x 286 386 486 Bytes - - none 2 2 5 4 1 - - -IDIV - Signed Integer Division - - Usage: IDIV src - Modifies flags: (AF,CF,OF,PF,SF,ZF undefined) - - Signed binary division of accumulator by source. If source is a - byte value, AX is divided by "src" and the quotient is stored in - AL and the remainder in AH. If source is a word value, DX:AX is - divided by "src", and the quotient is stored in AL and the - remainder in DX. - Clocks Size - Operands 808x 286 386 486 Bytes - - reg8 101-112 17 19 19 2 - reg16 165-184 25 27 27 2 - reg32 - - 43 43 2 - mem8 (107-118)+EA 20 22 20 2-4 - mem16 (171-190)+EA 38 30 28 2-4 (W88=175-194) - mem32 - - 46 44 2-4 - IMUL - Signed Multiply - - Usage: IMUL src - IMUL src,immed (286+) - IMUL dest,src,immed8 (286+) - IMUL dest,src (386+) - Modifies flags: CF OF (AF,PF,SF,ZF undefined) - - Signed multiplication of accumulator by "src" with result placed - in the accumulator. If the source operand is a byte value, it - is multiplied by AL and the result stored in AX. If the source - operand is a word value it is multiplied by AX and the result is - stored in DX:AX. Other variations of this instruction allow - specification of source and destination registers as well as a - third immediate factor. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg8 80-98 13 9-14 13-18 2 - reg16 128-154 21 9-22 13-26 2 - reg32 - - 9-38 12-42 2 - mem8 86-104 16 12-17 13-18 2-4 - mem16 134-160 24 12-25 13-26 2-4 - mem32 - - 12-41 13-42 2-4 - reg16,reg16 - - 9-22 13-26 3-5 - reg32,reg32 - - 9-38 13-42 3-5 - reg16,mem16 - - 12-25 13-26 3-5 - reg32,mem32 - - 12-41 13-42 3-5 - reg16,immed - 21 9-22 13-26 3 - reg32,immed - 21 9-38 13-42 3-6 - reg16,reg16,immed - 2 9-22 13-26 3-6 - reg32,reg32,immed - 21 9-38 13-42 3-6 - reg16,mem16,immed - 24 12-25 13-26 3-6 - reg32,mem32,immed - 24 12-41 13-42 3-6 - - -IN - Input Byte or Word From Port - - Usage: IN accum,port - Modifies flags: None - - A byte, word or dword is read from "port" and placed in AL, AX or - EAX respectively. If the port number is in the range of 0-255 - it can be specified as an immediate, otherwise the port number - must be specified in DX. Valid port ranges on the PC are 0-1024, - though values through 65535 may be specified and recognized by - third party vendors and PS/2's. - - Clocks Size - Operands 808x 286 386 486 Bytes - - accum,immed8 10/14 5 12 14 2 - accum,immed8 (PM) 6/26 8/28/27 2 - accum,DX 8/12 5 13 14 1 - accum,DX (PM) 7/27 8/28/27 1 - - - 386+ protected mode timings depend on privilege levels. - - first number is the timing if: CPL ó IOPL - second number is the timing if: CPL > IOPL or in VM 86 mode (386) - CPL ò IOPL (486) - third number is the timing when: virtual mode on 486 processor - - 486 virtual mode always requires 27 cycles - INC - Increment - - Usage: INC dest - Modifies flags: AF OF PF SF ZF - - Adds one to destination unsigned binary operand. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg8 3 2 2 1 2 - reg16 3 2 2 1 1 - reg32 3 2 2 1 1 - mem 15+EA 7 6 3 2-4 (W88=23+EA) - - -INS - Input String from Port (80188+) - - Usage: INS dest,port - INSB - INSW - INSD (386+) - Modifies flags: None - - Loads data from port to the destination ES:(E)DI (even if a - destination operand is supplied). (E)DI is adjusted by the size - of the operand and increased if the Direction Flag is cleared and - decreased if the Direction Flag is set. For INSB, INSW, INSD no - operands are allowed and the size is determined by the mnemonic. - - Clocks Size - Operands 808x 286 386 486 Bytes - - dest,port - 5 15 17 1 - dest,port (PM) - 5 9/29 10/32/30 1 - none - 5 15 17 1 - none (PM) - 5 9/29 10/32/30 1 - - - 386+ protected mode timings depend on privilege levels. - - first number is the timing if: CPL ó IOPL - second number is the timing if: CPL > IOPL - third number is the timing if: virtual mode on 486 processor - - -INT - Interrupt - - Usage: INT num - Modifies flags: TF IF - - Initiates a software interrupt by pushing the flags, clearing the - Trap and Interrupt Flags, pushing CS followed by IP and loading - CS:IP with the value found in the interrupt vector table. Execution - then begins at the location addressed by the new CS:IP - - Clocks Size - Operands 808x 286 386 486 Bytes - - 3 (constant) 52/72 23+m 33 26 2 - 3 (prot. mode, same priv.) - 40+m 59 44 2 - 3 (prot. mode, more priv.) - 78+m 99 71 2 - 3 (from VM86 to PL 0) - - 119 82 2 - 3 (prot. mode via task gate) - 167+m TS 37+TS 2 - immed8 51/71 23+m 37 30 1 - immed8 (prot. mode, same priv.) - 40+m 59 44 1 - immed8 (prot. mode, more priv.) - 78+m 99 71 1 - immed8 (from VM86 to PL 0) - - 119 86 1 - immed8 (prot. mode, via task gate) - 167+m TS 37+TS 1 - INTO - Interrupt on Overflow - - Usage: INTO - Modifies flags: IF TF - - If the Overflow Flag is set this instruction generates an INT 4 - which causes the code addressed by 0000:0010 to be executed. - - Clocks Size - Operands 808x 286 386 486 Bytes - - none: jump 53/73 24+m 35 28 1 - no jump 4 3 3 3 - (prot. mode, same priv.) - - 59 46 1 - (prot. mode, more priv.) - - 99 73 1 - (from VM86 to PL 0) - - 119 84 1 - (prot. mode, via task gate) - TS 39+TS 1 - - -INVD - Invalidate Cache (486+) - - Usage: INVD - Modifies flags: none - - Flushes CPU internal cache. Issues special function bus cycle - which indicates to flush external caches. Data in write-back - external caches is lost. - - Clocks Size - Operands 808x 286 386 486 Bytes - - none - - - 4 2 - - -INVLPG - Invalidate Translation Look-Aside Buffer Entry (486+) - - Usage: INVLPG - Modifies flags: none - - Invalidates a single page table entry in the Translation - Look-Aside Buffer. Intel warns that this instruction may be - implemented differently on future processors. - - Clocks Size - Operands 808x 286 386 486 Bytes - - none - - - 12 2 - - - timing is for TLB entry hit only. - - -IRET/IRETD - Interrupt Return - - Usage: IRET - IRETD (386+) - Modifies flags: AF CF DF IF PF SF TF ZF - - Returns control to point of interruption by popping IP, CS - and then the Flags from the stack and continues execution at - this location. CPU exception interrupts will return to the - instruction that cause the exception because the CS:IP placed - on the stack during the interrupt is the address of the offending - instruction. - - Clocks Size - Operands 808x 286 386 486 Bytes - - iret 32/44 17+m 22 15 1 - iret (prot. mode) - 31+m 38 15 1 - iret (to less privilege) - 55+m 82 36 1 - iret (different task, NT=1) - 169+m TS TS+32 1 - iretd - - 22/38 15 1 - iretd (to less privilege) - - 82 36 1 - iretd (to VM86 mode) - - 60 15 1 - iretd (different task, NT=1) - - TS TS+32 1 - - - 386 timings are listed as real-mode/protected-mode - Jxx - Jump Instructions Table - - Mnemonic Meaning Jump Condition - - JA Jump if Above CF=0 and ZF=0 - JAE Jump if Above or Equal CF=0 - JB Jump if Below CF=1 - JBE Jump if Below or Equal CF=1 or ZF=1 - JC Jump if Carry CF=1 - JCXZ Jump if CX Zero CX=0 - JE Jump if Equal ZF=1 - JG Jump if Greater (signed) ZF=0 and SF=OF - JGE Jump if Greater or Equal (signed) SF=OF - JL Jump if Less (signed) SF != OF - JLE Jump if Less or Equal (signed) ZF=1 or SF != OF - JMP Unconditional Jump unconditional - JNA Jump if Not Above CF=1 or ZF=1 - JNAE Jump if Not Above or Equal CF=1 - JNB Jump if Not Below CF=0 - JNBE Jump if Not Below or Equal CF=0 and ZF=0 - JNC Jump if Not Carry CF=0 - JNE Jump if Not Equal ZF=0 - JNG Jump if Not Greater (signed) ZF=1 or SF != OF - JNGE Jump if Not Greater or Equal (signed) SF != OF - JNL Jump if Not Less (signed) SF=OF - JNLE Jump if Not Less or Equal (signed) ZF=0 and SF=OF - JNO Jump if Not Overflow (signed) OF=0 - JNP Jump if No Parity PF=0 - JNS Jump if Not Signed (signed) SF=0 - JNZ Jump if Not Zero ZF=0 - JO Jump if Overflow (signed) OF=1 - JP Jump if Parity PF=1 - JPE Jump if Parity Even PF=1 - JPO Jump if Parity Odd PF=0 - JS Jump if Signed (signed) SF=1 - JZ Jump if Zero ZF=1 - - Clocks Size - Operands 808x 286 386 486 Bytes - - Jx: jump 16 7+m 7+m 3 2 - no jump 4 3 3 1 - Jx near-label - - 7+m 3 4 - no jump - - 3 1 - - - It's a good programming practice to organize code so the - expected case is executed without a jump since the actual - jump takes longer to execute than falling through the test. - - see JCXZ and JMP for their respective timings - - -JCXZ/JECXZ - Jump if Register (E)CX is Zero - - Usage: JCXZ label - JECXZ label (386+) - Modifies flags: None - - Causes execution to branch to "label" if register CX is zero. Uses - unsigned comparision. - - Clocks Size - Operands 808x 286 386 486 Bytes - - label: jump 18 8+m 9+m 8 2 - no jump 6 4 5 5 - JMP - Unconditional Jump - - Usage: JMP target - Modifies flags: None - - Unconditionally transfers control to "label". Jumps by default - are within -32768 to 32767 bytes from the instruction following - the jump. NEAR and SHORT jumps cause the IP to be updated while FAR - jumps cause CS and IP to be updated. - - Clocks - Operands 808x 286 386 486 - - rel8 (relative) 15 7+m 7+m 3 - rel16 (relative) 15 7+m 7+m 3 - rel32 (relative) - - 7+m 3 - reg16 (near, register indirect) 11 7+m 7+m 5 - reg32 (near, register indirect) - - 7+m 5 - mem16 (near, mem indirect) 18+EA 11+m 10+m 5 - mem32 (near, mem indirect) 24+EA 15+m 10+m 5 - ptr16:16 (far, dword immed) - - 12+m 17 - ptr16:16 (far, PM dword immed) - - 27+m 19 - ptr16:16 (call gate, same priv.) - 38+m 45+m 32 - ptr16:16 (via TSS) - 175+m TS 42+TS - ptr16:16 (via task gate) - 180+m TS 43+TS - mem16:16 (far, indirect) - - 43+m 13 - mem16:16 (far, PM indirect) - - 31+m 18 - mem16:16 (call gate, same priv.) - 41+m 49+m 31 - mem16:16 (via TSS) - 178+m 5+TS 41+TS - mem16:16 (via task gate) - 183+m 5+TS 42+TS - ptr16:32 (far, 6 byte immed) - - 12+m 13 - ptr16:32 (far, PM 6 byte immed) - - 27+m 18 - ptr16:32 (call gate, same priv.) - - 45+m 31 - ptr16:32 (via TSS) - - TS 42+TS - ptr16:32 (via task state) - - TS 43+TS - m16:32 (far, address at dword) - - 43+m 13 - m16:32 (far, address at dword) - - 31+m 18 - m16:32 (call gate, same priv.) - - 49+m 31 - m16:32 (via TSS) - - 5+TS 41+TS - m16:32 (via task state) - - 5+TS 42+TS - - -LAHF - Load Register AH From Flags - - Usage: LAHF - Modifies flags: None - - Copies bits 0-7 of the flags register into AH. This includes flags - AF, CF, PF, SF and ZF other bits are undefined. - - AH := SF ZF xx AF xx PF xx CF - - Clocks Size - Operands 808x 286 386 486 Bytes - - none 4 2 2 3 1 - - -LAR - Load Access Rights (286+ protected) - - Usage: LAR dest,src - Modifies flags: ZF - - The high byte of the of the destination register is overwritten by - the value of the access rights byte and the low order byte is zeroed - depending on the selection in the source operand. The Zero Flag is - set if the load operation is successful. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg16,reg16 - 14 15 11 3 - reg32,reg32 - - 15 11 3 - reg16,mem16 - 16 16 11 3-7 - reg32,mem32 - - 16 11 3-7 - LDS - Load Pointer Using DS - - Usage: LDS dest,src - Modifies flags: None - - Loads 32-bit pointer from memory source to destination register - and DS. The offset is placed in the destination register and the - segment is placed in DS. To use this instruction the word at the - lower memory address must contain the offset and the word at the - higher address must contain the segment. This simplifies the loading - of far pointers from the stack and the interrupt vector table. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg16,mem32 16+EA 7 7 6 2-4 - reg,mem (PM) - - 22 12 5-7 - - -LEA - Load Effective Address - - Usage: LEA dest,src - Modifies flags: None - - Transfers offset address of "src" to the destination register. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg,mem 2+EA 3 2 1 2-4 - - - the MOV instruction can often save clock cycles when used in - place of LEA on 8088 processors - - -LEAVE - Restore Stack for Procedure Exit (80188+) - - Usage: LEAVE - Modifies flags: None - - Releases the local variables created by the previous ENTER - instruction by restoring SP and BP to their condition before - the procedure stack frame was initialized. - - Clocks Size - Operands 808x 286 386 486 Bytes - - none - 5 4 5 1 - - -LES - Load Pointer Using ES - - Usage: LES dest,src - Modifies flags: None - - Loads 32-bit pointer from memory source to destination register - and ES. The offset is placed in the destination register and the - segment is placed in ES. To use this instruction the word at the - lower memory address must contain the offset and the word at the - higher address must contain the segment. This simplifies the loading - of far pointers from the stack and the interrupt vector table. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg,mem 16+EA 7 7 6 2-4 (W88=24+EA) - reg,mem (PM) - - 22 12 5-7 - LFS - Load Pointer Using FS (386+) - - Usage: LFS dest,src - Modifies flags: None - - Loads 32-bit pointer from memory source to destination register - and FS. The offset is placed in the destination register and the - segment is placed in FS. To use this instruction the word at the - lower memory address must contain the offset and the word at the - higher address must contain the segment. This simplifies the loading - of far pointers from the stack and the interrupt vector table. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg,mem - - 7 6 5-7 - reg,mem (PM) - - 22 12 5-7 - - -LGDT - Load Global Descriptor Table (286+ privileged) - - Usage: LGDT src - Modifies flags: None - - Loads a value from an operand into the Global Descriptor Table - (GDT) register. - - Clocks Size - Operands 808x 286 386 486 Bytes - - mem64 - 11 11 11 5 - - -LIDT - Load Interrupt Descriptor Table (286+ privileged) - - Usage: LIDT src - Modifies flags: None - - Loads a value from an operand into the Interrupt Descriptor Table - (IDT) register. - - Clocks Size - Operands 808x 286 386 486 Bytes - - mem64 - 12 11 11 5 - - -LGS - Load Pointer Using GS (386+) - - Usage: LGS dest,src - Modifies flags: None - - Loads 32-bit pointer from memory source to destination register - and GS. The offset is placed in the destination register and the - segment is placed in GS. To use this instruction the word at the - lower memory address must contain the offset and the word at the - higher address must contain the segment. This simplifies the loading - of far pointers from the stack and the interrupt vector table. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg,mem - - 7 6 5-7 - reg,mem (PM) - - 22 12 5-7 - LLDT - Load Local Descriptor Table (286+ privileged) - - Usage: LLDT src - Modifies flags: None - - Loads a value from an operand into the Local Descriptor Table - Register (LDTR). - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg16 - 17 20 11 3 - mem16 - 19 24 11 5 - - -LMSW - Load Machine Status Word (286+ privileged) - - Usage: LMSW src - Modifies flags: None - - Loads the Machine Status Word (MSW) from data found at "src" - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg16 - 3 10 13 3 - mem16 - 6 13 13 5 - - -LOCK - Lock Bus - - Usage: LOCK - LOCK: (386+ prefix) - Modifies flags: None - - This instruction is a prefix that causes the CPU assert bus lock - signal during the execution of the next instruction. Used to - avoid two processors from updating the same data location. The - 286 always asserts lock during an XCHG with memory operands. This - should only be used to lock the bus prior to XCHG, MOV, IN and - OUT instructions. - - Clocks Size - Operands 808x 286 386 486 Bytes - - none 2 0 0 1 1 - - -LODS - Load String (Byte, Word or Double) - - Usage: LODS src - LODSB - LODSW - LODSD (386+) - Modifies flags: None - - Transfers string element addressed by DS:SI (even if an operand is - supplied) to the accumulator. SI is incremented based on the size - of the operand or based on the instruction used. If the Direction - Flag is set SI is decremented, if the Direction Flag is clear SI - is incremented. Use with REP prefixes. - - Clocks Size - Operands 808x 286 386 486 Bytes - - src 12/16 5 5 5 1 - LOOP - Decrement CX and Loop if CX Not Zero - - Usage: LOOP label - Modifies flags: None - - Decrements CX by 1 and transfers control to "label" if CX is not - Zero. The "label" operand must be within -128 or 127 bytes of the - instruction following the loop instruction - - Clocks Size - Operands 808x 286 386 486 Bytes - - label: jump 18 8+m 11+m 6 2 - no jump 5 4 ? 2 - - -LOOPE/LOOPZ - Loop While Equal / Loop While Zero - - Usage: LOOPE label - LOOPZ label - Modifies flags: None - - Decrements CX by 1 (without modifying the flags) and transfers - control to "label" if CX != 0 and the Zero Flag is set. The - "label" operand must be within -128 or 127 bytes of the instruction - following the loop instruction. - - Clocks Size - Operands 808x 286 386 486 Bytes - - label: jump 18 8+m 11+m 9 2 - no jump 5 4 ? 6 - - -LOOPNZ/LOOPNE - Loop While Not Zero / Loop While Not Equal - - Usage: LOOPNZ label - LOOPNE label - Modifies flags: None - - Decrements CX by 1 (without modifying the flags) and transfers - control to "label" if CX != 0 and the Zero Flag is clear. The - "label" operand must be within -128 or 127 bytes of the instruction - following the loop instruction. - - Clocks Size - Operands 808x 286 386 486 Bytes - - label: jump 19 8+m 11+m 9 2 - no jump 5 4 ? 6 - - -LSL - Load Segment Limit (286+ protected) - - Usage: LSL dest,src - Modifies flags: ZF - - Loads the segment limit of a selector into the destination register - if the selector is valid and visible at the current privilege level. - If loading is successful the Zero Flag is set, otherwise it is - cleared. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg16,reg16 - 14 20/25 10 3 - reg32,reg32 - - 20/25 10 3 - reg16,mem16 - 16 21/26 10 5 - reg32,mem32 - - 21/26 10 5 - - - 386 times are listed "byte granular" / "page granular" - LSS - Load Pointer Using SS (386+) - - Usage: LSS dest,src - Modifies flags: None - - Loads 32-bit pointer from memory source to destination register - and SS. The offset is placed in the destination register and the - segment is placed in SS. To use this instruction the word at the - lower memory address must contain the offset and the word at the - higher address must contain the segment. This simplifies the loading - of far pointers from the stack and the interrupt vector table. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg,mem - - 7 6 5-7 - reg,mem (PM) - - 22 12 5-7 - - -LTR - Load Task Register (286+ privileged) - - Usage: LTR src - Modifies flags: None - - Loads the current task register with the value specified in "src". - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg16 - 17 23 20 3 - mem16 - 19 27 20 5 - - -MOV - Move Byte or Word - - Usage: MOV dest,src - Modifies flags: None - - Copies byte or word from the source operand to the destination - operand. If the destination is SS interrupts are disabled except - on early buggy 808x CPUs. Some CPUs disable interrupts if the - destination is any of the segment registers - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg,reg 2 2 2 1 2 - mem,reg 9+EA 3 2 1 2-4 (W88=13+EA) - reg,mem 8+EA 5 4 1 2-4 (W88=12+EA) - mem,immed 10+EA 3 2 1 3-6 (W88=14+EA) - reg,immed 4 2 2 1 2-3 - mem,accum 10 3 2 1 3 (W88=14) - accum,mem 10 5 4 1 3 (W88=14) - segreg,reg16 2 2 2 3 2 - segreg,mem16 8+EA 5 5 9 2-4 (W88=12+EA) - reg16,segreg 2 2 2 3 2 - mem16,segreg 9+EA 3 2 3 2-4 (W88=13+EA) - reg32,CR0/CR2/CR3 - - 6 4 - CR0,reg32 - - 10 16 - CR2,reg32 - - 4 4 3 - CR3,reg32 - - 5 4 3 - reg32,DR0/DR1/DR2/DR3 - 22 10 3 - reg32,DR6/DR7 - - 22 10 3 - DR0/DR1/DR2/DR3,reg32 - 22 11 3 - DR6/DR7,reg32 - - 16 11 3 - reg32,TR6/TR7 - - 12 4 3 - TR6/TR7,reg32 - - 12 4 3 - reg32,TR3 3 - TR3,reg32 6 - - - when the 386 special registers are used all operands are 32 bits - MOVS - Move String (Byte or Word) - - Usage: MOVS dest,src - MOVSB - MOVSW - MOVSD (386+) - Modifies flags: None - - Copies data from addressed by DS:SI (even if operands are given) to - the location ES:DI destination and updates SI and DI based on the - size of the operand or instruction used. SI and DI are incremented - when the Direction Flag is cleared and decremented when the Direction - Flag is Set. Use with REP prefixes. - - Clocks Size - Operands 808x 286 386 486 Bytes - - dest,src 18 5 7 7 1 (W88=26) - - -MOVSX - Move with Sign Extend (386+) - - Usage: MOVSX dest,src - Modifies flags: None - - Copies the value of the source operand to the destination register - with the sign extended. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg,reg - - 3 3 3 - reg,mem - - 6 3 3-7 - - -MOVZX - Move with Zero Extend (386+) - - Usage: MOVZX dest,src - Modifies flags: None - - Copies the value of the source operand to the destination register - with the zeroes extended. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg,reg - - 3 3 3 - reg,mem - - 6 3 3-7 - - -MUL - Unsigned Multiply - - Usage: MUL src - Modifies flags: CF OF (AF,PF,SF,ZF undefined) - - Unsigned multiply of the accumulator by the source. If "src" is - a byte value, then AL is used as the other multiplicand and the - result is placed in AX. If "src" is a word value, then AX is - multiplied by "src" and DX:AX receives the result. If "src" is - a double word value, then EAX is multiplied by "src" and EDX:EAX - receives the result. The 386+ uses an early out algorithm which - makes multiplying any size value in EAX as fast as in the 8 or 16 - bit registers. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg8 70-77 13 9-14 13-18 2 - reg16 118-113 21 9-22 13-26 2 - reg32 - - 9-38 13-42 2-4 - mem8 (76-83)+EA 16 12-17 13-18 2-4 - mem16 (124-139)+EA 24 12-25 13-26 2-4 - mem32 - - 12-21 13-42 2-4 - NEG - Two's Complement Negation - - Usage: NEG dest - Modifies flags: AF CF OF PF SF ZF - - Subtracts the destination from 0 and saves the 2s complement of - "dest" back into "dest". - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg 3 2 2 1 2 - mem 16+EA 7 6 3 2-4 (W88=24+EA) - - -NOP - No Operation (90h) - - Usage: NOP - Modifies flags: None - - This is a do nothing instruction. It results in occupation of both - space and time and is most useful for patching code segments. - (This is the original XCHG AL,AL instruction) - - Clocks Size - Operands 808x 286 386 486 Bytes - - none 3 3 3 1 1 - - -NOT - One's Compliment Negation (Logical NOT) - - Usage: NOT dest - Modifies flags: None - - Inverts the bits of the "dest" operand forming the 1s complement. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg 3 2 2 1 2 - mem 16+EA 7 6 3 2-4 (W88=24+EA) - - -OR - Inclusive Logical OR - - Usage: OR dest,src - Modifies flags: CF OF PF SF ZF (AF undefined) - - Logical inclusive OR of the two operands returning the result in - the destination. Any bit set in either operand will be set in the - destination. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg,reg 3 2 2 1 2 - mem,reg 16+EA 7 7 3 2-4 (W88=24+EA) - reg,mem 9+EA 7 6 2 2-4 (W88=13+EA) - reg,immed 4 3 2 1 3-4 - mem8,immed8 17+EA 7 7 3 3-6 - mem16,immed16 25+EA 7 7 3 3-6 - accum,immed 4 3 2 1 2-3 - OUT - Output Data to Port - - Usage: OUT port,accum - Modifies flags: None - - Transfers byte in AL,word in AX or dword in EAX to the specified - hardware port address. If the port number is in the range of 0-255 - it can be specified as an immediate. If greater than 255 then the - port number must be specified in DX. Since the PC only decodes 10 - bits of the port address, values over 1023 can only be decoded by - third party vendor equipment and also map to the port range 0-1023. - - Clocks Size - Operands 808x 286 386 486 Bytes - - immed8,accum 10/14 3 10 16 2 - immed8,accum (PM) - - 4/24 11/31/29 2 - DX,accum 8/12 3 11 16 1 - DX,accum (PM) - - 5/25 10/30/29 1 - - - 386+ protected mode timings depend on privilege levels. - - first number is the timing when: CPL ó IOPL - second number is the timing when: CPL > IOPL - third number is the timing when: virtual mode on 486 processor - - -OUTS - Output String to Port (80188+) - - Usage: OUTS port,src - OUTSB - OUTSW - OUTSD (386+) - Modifies flags: None - - Transfers a byte, word or doubleword from "src" to the hardware - port specified in DX. For instructions with no operands the "src" - is located at DS:SI and SI is incremented or decremented by the - size of the operand or the size dictated by the instruction format. - When the Direction Flag is set SI is decremented, when clear, SI is - incremented. If the port number is in the range of 0-255 it can - be specified as an immediate. If greater than 255 then the port - number must be specified in DX. Since the PC only decodes 10 bits - of the port address, values over 1023 can only be decoded by third - party vendor equipment and also map to the port range 0-1023. - - Clocks Size - Operands 808x 286 386 486 Bytes - - port,src - 5 14 17 1 - port,src (PM) - - 8/28 10/32/30 1 - - - 386+ protected mode timings depend on privilege levels. - - first number is the timing when: CPL ó IOPL - second number is the timing when: CPL > IOPL - third number is the timing when: virtual mode on 486 processor - - -POP - Pop Word off Stack - - Usage: POP dest - Modifies flags: None - - Transfers word at the current stack top (SS:SP) to the destination - then increments SP by two to point to the new stack top. CS is not - a valid destination. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg16 8 5 4 4 1 - reg32 4 - - 4 1 - segreg 8 5 7 3 1 - mem16 17+EA 5 5 6 2-4 - mem32 5 - - 6 2-4 - POPA/POPAD - Pop All Registers onto Stack (80188+) - - Usage: POPA - POPAD (386+) - Modifies flags: None - - Pops the top 8 words off the stack into the 8 general purpose 16/32 - bit registers. Registers are popped in the following order: (E)DI, - (E)SI, (E)BP, (E)SP, (E)DX, (E)CX and (E)AX. The (E)SP value popped - from the stack is actually discarded. - - Clocks Size - Operands 808x 286 386 486 Bytes - - none - 19 24 9 1 - - -POPF/POPFD - Pop Flags off Stack - - Usage: POPF - POPFD (386+) - Modifies flags: all flags - - Pops word/doubleword from stack into the Flags Register and then - increments SP by 2 (for POPF) or 4 (for POPFD). - - Clocks Size - Operands 808x 286 386 486 Bytes - - none 8/12 5 5 9 1 (W88=12) - none (PM) - - 5 6 1 - - -PUSH - Push Word onto Stack - - Usage: PUSH src - PUSH immed (80188+ only) - Modifies flags: None - - Decrements SP by the size of the operand (two or four, byte values - are sign extended) and transfers one word from source to the stack - top (SS:SP). - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg16 11/15 3 2 1 1 - reg32 - - 2 1 1 - mem16 16+EA 5 5 4 2-4 (W88=24+EA) - mem32 - - 5 4 2-4 - segreg 10/14 3 2 3 1 - immed - 3 2 1 2-3 - - -PUSHA/PUSHAD - Push All Registers onto Stack (80188+) - - Usage: PUSHA - PUSHAD (386+) - Modifies flags: None - - Pushes all general purpose registers onto the stack in the following - order: (E)AX, (E)CX, (E)DX, (E)BX, (E)SP, (E)BP, (E)SI, (E)DI. The - value of SP is the value before the actual push of SP. - - Clocks Size - Operands 808x 286 386 486 Bytes - - none - 19 24 11 1 - PUSHF/PUSHFD - Push Flags onto Stack - - Usage: PUSHF - PUSHFD (386+) - Modifies flags: None - - Transfers the Flags Register onto the stack. PUSHF saves a 16 bit - value while PUSHFD saves a 32 bit value. - - Clocks Size - Operands 808x 286 386 486 Bytes - - none 10/14 3 4 4 1 - none (PM) - - 4 3 1 - - -RCL - Rotate Through Carry Left - - Usage: RCL dest,count - Modifies flags: CF OF - - ÚÄ¿ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ÚÄþ³C³<þÄÄþ³7 <ÄÄÄÄÄÄÄÄÄÄ 0³<Ä¿ - ³ ÀÄÙ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - Rotates the bits in the destination to the left "count" times with - all data pushed out the left side re-entering on the right. The - Carry Flag holds the last bit rotated out. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg,1 2 2 9 3 2 - mem,1 15+EA 7 10 4 2-4 (W88=23+EA) - reg,CL 8+4n 5+n 9 8-30 2 - mem,CL 20+EA+4n 8+n 10 9-31 2-4 (W88=28+EA+4n) - reg,immed8 - 5+n 9 8-30 3 - mem,immed8 - 8+n 10 9-31 3-5 - - -RCR - Rotate Through Carry Right - - Usage: RCR dest,count - Modifies flags: CF OF - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÄ¿ - ÚÄ>³7 þÄÄÄÄÄÄÄÄÄ> 0³þÄÄÄ>³C³þÄ¿ - ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ÀÄÙ ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - Rotates the bits in the destination to the right "count" times with - all data pushed out the right side re-entering on the left. The - Carry Flag holds the last bit rotated out. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg,1 2 2 9 3 2 - mem,1 15+EA 7 10 4 2-4 (W88=23+EA) - reg,CL 8+4n 5+n 9 8-30 2 - mem,CL 20+EA+4n 8+n 10 9-31 2-4 (W88=28+EA+4n) - reg,immed8 - 5+n 9 8-30 3 - mem,immed8 - 8+n 10 9-31 3-5 - REP - Repeat String Operation - - Usage: REP - Modifies flags: None - - Repeats execution of string instructions while CX != 0. After - each string operation, CX is decremented and the Zero Flag is - tested. The combination of a repeat prefix and a segment override - on CPU's before the 386 may result in errors if an interrupt occurs - before CX=0. The following code shows code that is susceptible to - this and how to avoid it: - - again: rep movs byte ptr ES:[DI],ES:[SI] ; vulnerable instr. - jcxz next ; continue if REP successful - loop again ; interrupt goofed count - next: - - Clocks Size - Operands 808x 286 386 486 Bytes - - none 2 2 2 1 - - -REPE/REPZ - Repeat Equal / Repeat Zero - - Usage: REPE - REPZ - Modifies flags: None - - Repeats execution of string instructions while CX != 0 and the Zero - Flag is set. CX is decremented and the Zero Flag tested after - each string operation. The combination of a repeat prefix and a - segment override on processors other than the 386 may result in - errors if an interrupt occurs before CX=0. - - Clocks Size - Operands 808x 286 386 486 Bytes - - none 2 2 2 1 - - -REPNE/REPNZ - Repeat Not Equal / Repeat Not Zero - - Usage: REPNE - REPNZ - Modifies flags: None - - Repeats execution of string instructions while CX != 0 and the Zero - Flag is clear. CX is decremented and the Zero Flag tested after - each string operation. The combination of a repeat prefix and a - segment override on processors other than the 386 may result in - errors if an interrupt occurs before CX=0. - - Clocks Size - Operands 808x 286 386 486 Bytes - - none 2 2 2 1 - RET/RETF - Return From Procedure - - Usage: RET nBytes - RETF nBytes - RETN nBytes - Modifies flags: None - - Transfers control from a procedure back to the instruction address - saved on the stack. "n bytes" is an optional number of bytes to - release. Far returns pop the IP followed by the CS, while near - returns pop only the IP register. - - Clocks Size - Operands 808x 286 386 486 Bytes - - retn 16/20 11+m 10+m 5 1 - retn immed 20/24 11+m 10+m 5 3 - retf 26/34 15+m 18+m 13 1 - retf (PM, same priv.) - 32+m 18 1 - retf (PM, lesser priv.) - 68 33 1 - retf immed 25/33 15+m 18+m 14 3 - retf immed (PM, same priv.) 32+m 17 1 - retf immed (PM, lesser priv.) 68 33 1 - - -ROL - Rotate Left - - Usage: ROL dest,count - Modifies flags: CF OF - - ÚÄ¿ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³C³<þÂÄþ³7 <ÄÄÄÄÄÄÄÄÄÄ 0³<Ä¿ - ÀÄÙ ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - Rotates the bits in the destination to the left "count" times with - all data pushed out the left side re-entering on the right. The - Carry Flag will contain the value of the last bit rotated out. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg,1 2 2 3 3 2 - mem,1 15+EA 7 7 4 2-4 (W88=23+EA) - reg,CL 8+4n 5+n 3 3 2 - mem,CL 20+EA+4n 8+n 7 4 2-4 (W88=28+EA+4n) - reg,immed8 - 5+n 3 2 3 - mem,immed8 - 8+n 7 4 3-5 - - -ROR - Rotate Right - - Usage: ROR dest,count - Modifies flags: CF OF - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÄ¿ - ÚÄ>³7 þÄÄÄÄÄÄÄÄÄ> 0³þÄÂÄ>³C³ - ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³ ÀÄÙ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - Rotates the bits in the destination to the right "count" times with - all data pushed out the right side re-entering on the left. The - Carry Flag will contain the value of the last bit rotated out. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg,1 2 2 3 3 2 - mem,1 15+EA 7 7 4 2-4 (W88=23+EA) - reg,CL 8+4n 5+n 3 3 2 - mem,CL 20+EA+4n 8+n 7 4 2-4 (W88=28+EA+4n) - reg,immed8 - 5+n 3 2 3 - mem,immed8 - 8+n 7 4 3-5 - SAHF - Store AH Register into FLAGS - - Usage: SAHF - Modifies flags: AF CF PF SF ZF - - Transfers bits 0-7 of AH into the Flags Register. This includes - AF, CF, PF, SF and ZF. - - Clocks Size - Operands 808x 286 386 486 Bytes - - none 4 2 3 2 1 - - -SAL/SHL - Shift Arithmetic Left / Shift Logical Left - - Usage: SAL dest,count - SHL dest,count - Modifies flags: CF OF PF SF ZF (AF undefined) - - ÚÄ¿ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÄ¿ - ³C³<ÄÄÄþ³7 <ÄÄÄÄÄÄÄÄÄÄ 0³<ÄÄÄþ³0³ - ÀÄÙ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ÀÄÙ - - Shifts the destination left by "count" bits with zeroes shifted - in on right. The Carry Flag contains the last bit shifted out. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg,1 2 2 3 3 2 - mem,1 15+EA 7 7 4 2-4 (W88=23+EA) - reg,CL 8+4n 5+n 3 3 2 - mem,CL 20+EA+4n 8+n 7 4 2-4 (W88=28+EA+4n) - reg,immed8 - 5+n 3 2 3 - mem,immed8 - 8+n 7 4 3-5 - - -SAR - Shift Arithmetic Right - - Usage: SAR dest,count - Modifies flags: CF OF PF SF ZF (AF undefined) - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÄ¿ - ÚÄþ³7 ÄÄÄÄÄÄÄÄÄÄ> 0³ÄÄÄþ>³C³ - ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ÀÄÙ - ÀÄÄÄ^ - - Shifts the destination right by "count" bits with the current sign - bit replicated in the leftmost bit. The Carry Flag contains the - last bit shifted out. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg,1 2 2 3 3 2 - mem,1 15+EA 7 7 4 2-4 (W88=23+EA) - reg,CL 8+4n 5+n 3 3 2 - mem,CL 20+EA+4n 8+n 7 4 2-4 (W88=28+EA+4n) - reg,immed8 - 5+n 3 2 3 - mem,immed8 - 8+n 7 4 3-5 - SBB - Subtract with Borrow/Carry - - Usage: SBB dest,src - Modifies flags: AF CF OF PF SF ZF - - Subtracts the source from the destination, and subtracts 1 extra if - the Carry Flag is set. Results are returned in "dest". - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg,reg 3 2 2 1 2 - mem,reg 16+EA 7 6 3 2-4 (W88=24+EA) - reg,mem 9+EA 7 7 2 2-4 (W88=13+EA) - reg,immed 4 3 2 1 3-4 - mem,immed 17+EA 7 7 3 3-6 (W88=25+EA) - accum,immed 4 3 2 1 2-3 - - -SCAS - Scan String (Byte, Word or Doubleword) - - Usage: SCAS string - SCASB - SCASW - SCASD (386+) - Modifies flags: AF CF OF PF SF ZF - - Compares value at ES:DI (even if operand is specified) from the - accumulator and sets the flags similar to a subtraction. DI is - incremented/decremented based on the instruction format (or - operand size) and the state of the Direction Flag. Use with REP - prefixes. - - Clocks Size - Operands 808x 286 386 486 Bytes - - string 15 7 7 6 1 (W88=19) - - -SETAE/SETNB - Set if Above or Equal / Set if Not Below (386+) - - Usage: SETAE dest - SETNB dest - (unsigned, 386+) - Modifies flags: none - - Sets the byte in the operand to 1 if the Carry Flag is clear - otherwise sets the operand to 0. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg8 - - 4 3 3 - mem8 - - 5 4 3 - - -SETB/SETNAE - Set if Below / Set if Not Above or Equal (386+) - - Usage: SETB dest - SETNAE dest - (unsigned, 386+) - Modifies flags: none - - Sets the byte in the operand to 1 if the Carry Flag is set - otherwise sets the operand to 0. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg8 - - 4 3 3 - mem8 - - 5 4 3 - SETBE/SETNA - Set if Below or Equal / Set if Not Above (386+) - - Usage: SETBE dest - SETNA dest - (unsigned, 386+) - Modifies flags: none - - Sets the byte in the operand to 1 if the Carry Flag or the Zero - Flag is set, otherwise sets the operand to 0. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg8 - - 4 3 3 - mem8 - - 5 4 3 - - -SETE/SETZ - Set if Equal / Set if Zero (386+) - - Usage: SETE dest - SETZ dest - Modifies flags: none - - Sets the byte in the operand to 1 if the Zero Flag is set, - otherwise sets the operand to 0. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg8 - - 4 3 3 - mem8 - - 5 4 3 - - -SETNE/SETNZ - Set if Not Equal / Set if Not Zero (386+) - - Usage: SETNE dest - SETNZ dest - Modifies flags: none - - Sets the byte in the operand to 1 if the Zero Flag is clear, - otherwise sets the operand to 0. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg8 - - 4 3 3 - mem8 - - 5 4 3 - - -SETL/SETNGE - Set if Less / Set if Not Greater or Equal (386+) - - Usage: SETL dest - SETNGE dest - (signed, 386+) - Modifies flags: none - - Sets the byte in the operand to 1 if the Sign Flag is not equal - to the Overflow Flag, otherwise sets the operand to 0. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg8 - - 4 3 3 - mem8 - - 5 4 3 - SETGE/SETNL - Set if Greater or Equal / Set if Not Less (386+) - - Usage: SETGE dest - SETNL dest - (signed, 386+) - Modifies flags: none - - Sets the byte in the operand to 1 if the Sign Flag equals the - Overflow Flag, otherwise sets the operand to 0. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg8 - - 4 3 3 - mem8 - - 5 4 3 - - -SETLE/SETNG - Set if Less or Equal / Set if Not greater or Equal (386+) - - Usage: SETLE dest - SETNG dest - (signed, 386+) - Modifies flags: none - - Sets the byte in the operand to 1 if the Zero Flag is set or the - Sign Flag is not equal to the Overflow Flag, otherwise sets the - operand to 0. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg8 - - 4 3 3 - mem8 - - 5 4 3 - - -SETG/SETNLE - Set if Greater / Set if Not Less or Equal (386+) - - Usage: SETG dest - SETNLE dest - (signed, 386+) - Modifies flags: none - - Sets the byte in the operand to 1 if the Zero Flag is clear or the - Sign Flag equals to the Overflow Flag, otherwise sets the operand - to 0. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg8 - - 4 3 3 - mem8 - - 5 4 3 - - -SETS - Set if Signed (386+) - - Usage: SETS dest - Modifies flags: none - - Sets the byte in the operand to 1 if the Sign Flag is set, otherwise - sets the operand to 0. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg8 - - 4 3 3 - mem8 - - 5 4 3 - SETNS - Set if Not Signed (386+) - - Usage: SETNS dest - Modifies flags: none - - Sets the byte in the operand to 1 if the Sign Flag is clear, - otherwise sets the operand to 0. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg8 - - 4 3 3 - mem8 - - 5 4 3 - - -SETC - Set if Carry (386+) - - Usage: SETC dest - Modifies flags: none - - Sets the byte in the operand to 1 if the Carry Flag is set, - otherwise sets the operand to 0. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg8 - - 4 3 3 - mem8 - - 5 4 3 - - -SETNC - Set if Not Carry (386+) - - Usage: SETNC dest - Modifies flags: none - - Sets the byte in the operand to 1 if the Carry Flag is clear, - otherwise sets the operand to 0. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg8 - - 4 3 3 - mem8 - - 5 4 3 - - -SETO - Set if Overflow (386+) - - Usage: SETO dest - Modifies flags: none - - Sets the byte in the operand to 1 if the Overflow Flag is set, - otherwise sets the operand to 0. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg8 - - 4 3 3 - mem8 - - 5 4 3 - - -SETNO - Set if Not Overflow (386+) - - Usage: SETNO dest - Modifies flags: none - - Sets the byte in the operand to 1 if the Overflow Flag is clear, - otherwise sets the operand to 0. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg8 - - 4 3 3 - mem8 - - 5 4 3 - SETP/SETPE - Set if Parity / Set if Parity Even (386+) - - Usage: SETP dest - SETPE dest - Modifies flags: none - - Sets the byte in the operand to 1 if the Parity Flag is set, - otherwise sets the operand to 0. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg8 - - 4 3 3 - mem8 - - 5 4 3 - - -SETNP/SETPO - Set if No Parity / Set if Parity Odd (386+) - - Usage: SETNP dest - SETPO dest - Modifies flags: none - - Sets the byte in the operand to 1 if the Parity Flag is clear, - otherwise sets the operand to 0. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg8 - - 4 3 3 - mem8 - - 5 4 3 - - -SGDT - Store Global Descriptor Table (286+ privileged) - - Usage: SGDT dest - Modifies flags: none - - Stores the Global Descriptor Table (GDT) Register into the - specified operand. - - Clocks Size - Operands 808x 286 386 486 Bytes - - mem64 - 11 9 10 5 - - -SIDT - Store Interrupt Descriptor Table (286+ privileged) - - Usage: SIDT dest - Modifies flags: none - - Stores the Interrupt Descriptor Table (IDT) Register into the - specified operand. - - Clocks Size - Operands 808x 286 386 486 Bytes - - mem64 - 12 9 10 5 - - -SHL - Shift Logical Left - - See: SAL - SHR - Shift Logical Right - - Usage: SHR dest,count - Modifies flags: CF OF PF SF ZF (AF undefined) - - ÚÄ¿ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÄ¿ - ³0³ÄÄÄþ>³7 ÄÄÄÄÄÄÄÄÄÄ> 0³ÄÄÄþ>³C³ - ÀÄÙ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ÀÄÙ - - Shifts the destination right by "count" bits with zeroes shifted - in on the left. The Carry Flag contains the last bit shifted out. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg,1 2 2 3 2 - mem,1 15+EA 7 7 2-4 (W88=23+EA) - reg,CL 8+4n 5+n 3 2 - mem,CL 20+EA+4n 8+n 7 2-4 (W88=28+EA+4n) - reg,immed8 - 5+n 3 3 - mem,immed8 - 8+n 7 3-5 - - -SHLD/SHRD - Double Precision Shift (386+) - - Usage: SHLD dest,src,count - SHRD dest,src,count - Modifies flags: CF PF SF ZF (OF,AF undefined) - - SHLD shifts "dest" to the left "count" times and the bit positions - opened are filled with the most significant bits of "src". SHRD - shifts "dest" to the right "count" times and the bit positions - opened are filled with the least significant bits of the second - operand. Only the 5 lower bits of "count" are used. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg16,reg16,immed8 - - 3 2 4 - reg32,reg32,immed8 - - 3 2 4 - mem16,reg16,immed8 - - 7 3 6 - mem32,reg32,immed8 - - 7 3 6 - reg16,reg16,CL - - 3 3 3 - reg32,reg32,CL - - 3 3 3 - mem16,reg16,CL - - 7 4 5 - mem32,reg32,CL - - 7 4 5 - - -SLDT - Store Local Descriptor Table (286+ privileged) - - Usage: SLDT dest - Modifies flags: none - - Stores the Local Descriptor Table (LDT) Register into the - specified operand. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg16 - 2 2 2 3 - mem16 - 2 2 3 5 - - -SMSW - Store Machine Status Word (286+ privileged) - - Usage: SMSW dest - Modifies flags: none - - Store Machine Status Word (MSW) into "dest". - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg16 - 2 10 2 3 - mem16 - 3 3 3 5 - STC - Set Carry - - Usage: STC - Modifies flags: CF - - Sets the Carry Flag to 1. - - Clocks Size - Operands 808x 286 386 486 Bytes - - none 2 2 2 2 1 - - -STD - Set Direction Flag - - Usage: STD - Modifies flags: DF - - Sets the Direction Flag to 1 causing string instructions to - auto-decrement SI and DI instead of auto-increment. - - Clocks Size - Operands 808x 286 386 486 Bytes - - none 2 2 2 2 1 - - -STI - Set Interrupt Flag (Enable Interrupts) - - Usage: STI - Modifies flags: IF - - Sets the Interrupt Flag to 1, which enables recognition of all - hardware interrupts. If an interrupt is generated by a hardware - device, an End of Interrupt (EOI) must also be issued to enable - other hardware interrupts of the same or lower priority. - - Clocks Size - Operands 808x 286 386 486 Bytes - - none 2 2 2 5 1 - - -STOS - Store String (Byte, Word or Doubleword) - - Usage: STOS dest - STOSB - STOSW - STOSD - Modifies flags: None - - Stores value in accumulator to location at ES:(E)DI (even if operand - is given). (E)DI is incremented/decremented based on the size of - the operand (or instruction format) and the state of the Direction - Flag. Use with REP prefixes. - - Clocks Size - Operands 808x 286 386 486 Bytes - - dest 11 3 4 5 1 (W88=15) - - -STR - Store Task Register (286+ privileged) - - Usage: STR dest - Modifies flags: None - - Stores the current Task Register to the specified operand. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg16 - 2 2 2 3 - mem16 - 3 2 3 5 - SUB - Subtract - - Usage: SUB dest,src - Modifies flags: AF CF OF PF SF ZF - - The source is subtracted from the destination and the result is - stored in the destination. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg,reg 3 2 2 1 2 - mem,reg 16+EA 7 6 3 2-4 (W88=24+EA) - reg,mem 9+EA 7 7 2 2-4 (W88=13+EA) - reg,immed 4 3 2 1 3-4 - mem,immed 17+EA 7 7 3 3-6 (W88=25+EA) - accum,immed 4 3 2 1 2-3 - - -TEST - Test For Bit Pattern - - Usage: TEST dest,src - Modifies flags: CF OF PF SF ZF (AF undefined) - - Performs a logical AND of the two operands updating the flags - register without saving the result. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg,reg 3 2 1 1 2 - reg,mem 9+EA 6 5 1 2-4 (W88=13+EA) - mem,reg 9+EA 6 5 2 2-4 (W88=13+EA) - reg,immed 5 3 2 1 3-4 - mem,immed 11+EA 6 5 2 3-6 - accum,immed 4 3 2 1 2-3 - - -VERR - Verify Read (286+ protected) - - Usage: VERR src - Modifies flags: ZF - - Verifies the specified segment selector is valid and is readable - at the current privilege level. If the segment is readable, - the Zero Flag is set, otherwise it is cleared. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg16 - 14 10 11 3 - mem16 - 16 11 11 5 - - -VERW - Verify Write (286+ protected) - - Usage: VERW src - Modifies flags: ZF - - Verifies the specified segment selector is valid and is ratable - at the current privilege level. If the segment is writable, - the Zero Flag is set, otherwise it is cleared. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg16 - 14 15 11 3 - mem16 - 16 16 11 5 - WAIT/FWAIT - Event Wait - - Usage: WAIT - FWAIT - Modifies flags: None - - CPU enters wait state until the coprocessor signals it has finished - its operation. This instruction is used to prevent the CPU from - accessing memory that may be temporarily in use by the coprocessor. - WAIT and FWAIT are identical. - - Clocks Size - Operands 808x 286 386 486 Bytes - - none 4 3 6+ 1-3 1 - - -WBINVD - Write-Back and Invalidate Cache (486+) - - Usage: WBINVD - Modifies flags: None - - Flushes internal cache, then signals the external cache to write - back current data followed by a signal to flush the external cache. - - Clocks Size - Operands 808x 286 386 486 Bytes - - none - - - 5 2 - - -XCHG - Exchange - - Usage: XCHG dest,src - Modifies flags: None - - Exchanges contents of source and destination. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg,reg 4 3 3 3 2 - mem,reg 17+EA 5 5 5 2-4 (W88=25+EA) - reg,mem 17+EA 5 5 3 2-4 (W88=25+EA) - accum,reg 3 3 3 3 1 - reg,accum 3 3 3 3 1 - - -XLAT/XLATB - Translate - - Usage: XLAT translation-table - XLATB (masm 5.x) - Modifies flags: None - - Replaces the byte in AL with byte from a user table addressed by - BX. The original value of AL is the index into the translate table. - The best way to discripe this is MOV AL,[BX+AL] - - Clocks Size - Operands 808x 286 386 486 Bytes - - table offset 11 5 5 4 1 - XOR - Exclusive OR - - Usage: XOR dest,src - Modifies flags: CF OF PF SF ZF (AF undefined) - - Performs a bitwise exclusive OR of the operands and returns - the result in the destination. - - Clocks Size - Operands 808x 286 386 486 Bytes - - reg,reg 3 2 2 1 2 - mem,reg 16+EA 7 6 3 2-4 (W88=24+EA) - reg,mem 9+EA 7 7 2 2-4 (W88=13+EA) - reg,immed 4 3 2 1 3-4 - mem,immed 17+EA 7 7 3 3-6 (W88=25+EA) - accum,immed 4 3 2 1 2-3 - \ No newline at end of file diff --git a/16/PCGPE10/JOYSTICK.TXT b/16/PCGPE10/JOYSTICK.TXT deleted file mode 100644 index 0ddd22a0..00000000 --- a/16/PCGPE10/JOYSTICK.TXT +++ /dev/null @@ -1,255 +0,0 @@ - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Programming the PC Joystick ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - Written for the PC-GPE by - Steve McGowan and Mark Feldman - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Programming Info ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -All joystick programming is done via port 201h. - - ÚÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄ¿ - ³ 7 ³ 6 ³ 5 ³ 4 ³ 3 ³ 2 ³ 1 ³ 0 ³ - ÀÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÙ - ³ ³ ³ ³ ³ ³ ³ ³ -Joystick B, Button 2 ÄÄÄÙ ³ ³ ³ ³ ³ ³ ÀÄÄÄ Joystick A, X Axis -Joystick B, Button 1 ÄÄÄÄÄÄÄÙ ³ ³ ³ ³ ÀÄÄÄÄÄÄÄ Joystick A, Y Axis -Joystick A, Button 2 ÄÄÄÄÄÄÄÄÄÄÄÙ ³ ³ ÀÄÄÄÄÄÄÄÄÄÄÄ Joystick B, X Axis -Joystick A, Button 1 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Joystick B, Y Axis - -Reading the status of the joystick buttons is fairly simple. Just read the -byte from the joystick port and check the status of the appropriate bit. A -clear bit (0) means the button is pressed, a set bit (1) means it is not -pressed. Note that the button's are not hardware debounced. Each time a -button is pressed it's bit may "bounce" between 0 and 1 a couple of times. - -Reading the position of the stick positions is a bit more complicated. You -must first write a dummy byte (any value will do) to the joystick port. This -will set each axis bit to 1. You must then time how long the bit takes to -drop back to 0, this time is roughly proportional to the position of -the joystick axis (see Steve McGowan's discussion below). - -AT computers also have a BIOS call which supports the joystick. I have come -across numerous machines which apparently did not support this call. My own -machine supports reading the joystick buttons apparently can't read the -stick position values, so I do not advise using this call for any serious -games. In any case here is info on the call: - -Joystick Support BIOS Call - -Int 15h - -To call: - AH = 84h - DX = 00h Read switch settings - 01h Read joystick position - -Returns: - PC, PCjr : Carry flag set, AH = 80h - PC XT : Carry flag set, AH = 86h - All others : DX = 00h on calling - AL = Switch settings (bits 4 - 7) - Carry flag set on error - DX = 01h on calling - AX = A(X) value - BX = A(Y) value - CX = B(X) value - DX = B(Y) value - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Hardware Pinout ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The joystick connects to a 15 pin female plug : - - __________________________ - \ 8 7 6 5 4 3 2 1 / - \ 9 10 11 12 13 14 15 / - ---------------------- - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Pin # Joystick ³ - ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ - ³ 1 +5v ³ - ³ 2 Joystick A, Button 1 ³ - ³ 3 Joystick A, X Axis ³ - ³ 4 Gnd ³ - ³ 5 Gnd ³ - ³ 6 Joystick A, Y Axis ³ - ³ 7 Joystick A, Button 2 ³ - ³ 8 +5v ³ - ³ 9 +5v ³ - ³ 10 Joystick B, Button 1 ³ - ³ 11 Joystick B, X Axis ³ - ³ 12 Gnd ³ - ³ 13 Joystick B, Y Axis ³ - ³ 14 Joystick B, Button 2 ³ - ³ 15 +5v ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Misc notes on Joystick handling by Steve McGowan ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -With a polling loop on a 486-66 I got x/y values between 8 and 980. When -I centered the stick the value was usually a value around 330. - -NOTE: a Gravis Game Pad it only put out 3 values, 8(min), 330(center), -and 980(max). Every joystick I have tried has been non-linear. - -The "speed compensation" that some games require is due to the fact that -the game designer did not anticipate the range of values that could -come back on faster machines. On a 486-25 you may see max values of 360, -I saw 980, on a Pentium the max value could be well over 2000. If you -had used a unsigned byte value you probably would have been in good -shape on an AT, or 386 but you would be in big trouble with faster machines. - -Because the joystick logic returns a non linear value, if you base your -scaling only on the 4 corners then the center will be off (biased towards -a corner). If you just use the center value and a single scaling factor -(i.e. of the center is at 330 then full throw should be at 660), then the -stick will saturate (660) half way to the full throw position (980). -That is why most joystick setup programs make the distinction between -hitting the 4 corners and centering the stick. - -Joystick position vs. loop count - - x,y-------------------- - 8,8| 330,8 | 980,8 - | | - | | delta 330 - | | - 8,330| 330,330 | 980,330 (y centered) - | | - | | delta 650 - | | - 8,980| 330,980 | 980,980 - -------------------- - (x centered) - -For the best effect you basically need 2 scale factors, depending on whether -you are above or below the center value. I think the curve is actually an -exponential (charging capacitor) but a straight line approximation should -do fine. - -The 10% dead zone in the center is a good idea. The centering mechanism of -joysticks vary in repeatablity, they don't always come back to the same place. -I have a cheap one that (1 time in 8) does not return to the X center if I -just let it snap to center. It hangs on the high side. - -I would recommend disabling interrupts while polling. An interrupt -in the middle of your polling loop will really throw off the results. And -any DMA that takes place will also give you bad values. - -Joysticks are noisy, so holding the stick in a fixed position will return -values that vary +-5% easily. I added a smoothing function to my joystick -code where I throw away single values that are not continuous. It helped -a lot with the noise and the DMA. - -I use protected mode and the interrupt disable() call doesn't actually work -because it only disables interrupts for the process not the processor. -The smoothing trick can help here too. - -If I turn on my machine and start the polling loop immediately, it will -put out a centered value of 330,330 but after warming up for 10 minutes -the value changes to 285,285. This variance also needs to be absorbed in -your center dead zone. If after warming up the 'center' value is outside your -dead zone then the cursor will drift (to the left and/or up). Make -sure your game has a "center joystick" command to get around joystick -interfaces with lousy temperature compensation. - -You must wait for all of the axis bits to settle before initiating -another read, otherwise strange results may come out. So, instead of -reading X, then Y, in two separate loops (which take twice as much time) -Read both X and Y simultaneously, polling until both bits settle. This -can be extended for two joysticks, assuming that they are both attached. -The respective X/Y bits never come true if there is no joystick attached. - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ A Simple Demo Joystick Unit ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -{ - JOY.PAS - By Mark Feldman - e-mail address : u914097@student.canberra.edu.au - myndale@cairo.anu.edu.au - - - A simple Pascal Joystick Unit. -} - - -unit Joy; - -Interface - -{ Define constants for use as JoystickButton and JoystickPosition parameters } -const JoystickAButton1 = $10; - JoystickAButton2 = $20; - JoystickBButton1 = $40; - JoystickBButton2 = $80; - JoystickAAxisX = $01; - JoystickAAxisY = $02; - JoystickBAxisX = $04; - JoystickBAxisY = $08; - -function JoystickButton(buttonnum : byte) : boolean; -function JoystickPosition(axisnum : byte) : word; - -Implementation - -const JOYSTICKPORT = $201; - -{ Button returns true is button is pressed } -function JoystickButton(buttonnum : byte) : boolean; -begin - JoystickButton := (Port[JOYSTICKPORT] and buttonnum) = 0; -end; - -{ Returns position value of joystick. The value returned is highly - dependent on machine speed. Changing the setting of the computer's - Turbo speed button will affect the value returned. - Returns $FFFF if the joystick is not connected -} -function JoystickPosition(axisnum : byte) : word; -var count : word; -begin - asm - mov word ptr count, 0 - cli { Disable interrupts so they don't interfere with timing } - mov dx, JOYSTICKPORT { Write dummy byte to joystick port } - out dx, al - @joystickloop: - inc count { Add one to count } - cmp count, $FFFF { Check for time out } - je @done - in al, dx { Get joystick port value } - and al, axisnum { Test the appropriate bit } - jne @joystickloop - @done: - sti { Enable interrupts again } - end; - JoystickPosition := count; -end; - -end. - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ References ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Title : Flights of Fantasy -Author : Christopher Lampton -Publishers : The Waite Group -ISBN : 1-878739-18-2 - -Title : DOS and BIOS Functions Quick Reference -Publishers : Que Corporation -ISBN : 0-88022-426-6 diff --git a/16/PCGPE10/KEYBOARD.TXT b/16/PCGPE10/KEYBOARD.TXT deleted file mode 100644 index 21c5587a..00000000 --- a/16/PCGPE10/KEYBOARD.TXT +++ /dev/null @@ -1,243 +0,0 @@ - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Programming the Keyboard ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - Written for the PC-GPE by Mark Feldman - e-mail address : u914097@student.canberra.edu.au - myndale@cairo.anu.edu.au - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ THIS FILE MAY NOT BE DISTRIBUTED ³ - ³ SEPARATE TO THE ENTIRE PC-GPE COLLECTION. ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Disclaimer ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ - -I assume no responsibility whatsoever for any effect that this file, the -information contained therein or the use thereof has on you, your sanity, -computer, spouse, children, pets or anything else related to you or your -existance. No warranty is provided nor implied with this information. - -ÚÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Overview ³ -ÀÄÄÄÄÄÄÄÄÄÄÙ - -The operation of the keyboard is really quite simple. Every time a key -is pressed or released an interrupt 9 is generated, and reading the value -from port 60h tells you what happened. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Decoding the Keyboard Byte ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -So let's say you've installed an interrupt handler to handle all keyboard -events and when an interrupt is generated your handler reads the byte from -port 60h. What now? - -Well..each key on the keyboard has an associated scan code which is contained -in the lower 7 bits of the byte. The most significant bit (ie bit 7) tells -you what was actually done, 0 = key was just pressed, 1 = key was just -released. If someone had just pressed the ESC key for instance, the port will -show a value of 1 (1 is the ESC key's scan code). If they hold their finger -on the button the keyboard will keep generating interrupt 9's and each -time the port will still show a value of 1. When the person releases the key -a final interrupt will be generated and the port will return 129 (1 + 128, -since the high bit will be set indicating the person has released the key). - -Well...it's almost this simple. Some keys are "extended" keys. When an -extended key is pressed an interrupt is generated and the keyboard port -will return a value of 224 (E0h). This means that an extended key was pressed -and it's *extended* scan code will be available during the *next* interrupt. -Note that the left control key has a scan code of 29, while the *right* -control key has an *extended* scan code of 29. The same applies to the alt -keys and the arrow keys (keypad arrows vs the other ones). - -It would be nice if all keys were created equal and we could just throw away -the 224 extended bytes and handle all the other bytes normally. Unfortunately -there are two buttons which on my machine at least (and others I have tested) -do some really weird stuff: - -PrtScn -ÄÄÄÄÄÄ -Pressing this button will send *2* extended characters to the handler, 42 -and 55, so the actual byte sequence will be 224, 42, 224, 55. (Also note -that the left shift key has a regular scan code of 42, so there goes our -idea of just throwing 224's away). Only the extended 55's are sent during -auto-repeat. When the key is released, the two are sent again with the high -bits set (224, 170, 224, and 183). If any of the shift or control keys are -being held down when the PrtScn button is pressed then only the (224, 55) is -sent when the key is pressed and only the (224, 183) is sent when it's -released. If the alt key is being held down (System Request) then the key -behaves like an ordinary key with scan code 84. The practical upshot of all -this is that the handlers you write to handle normal keys and extended keys -will work fine with all the different PrtScn combinations (although a program -would have to check normal key 84 *AND* extended key 55 in order to determine -if the key is currently being pressed). - -Pause/Break -ÄÄÄÄÄÄÄÄÄÄÄ -Welcome to hell. If you press this key while either of the the control keys -are being held down, it will behave like extended key 70, at all other times -it will send the following bytes: (225, 29, 69, 225, 157, 197). Holding the -key down does not result in autorepeat. Taking your finger off the key does -not send any extra bytes, they appear to be sent after the "key down" bytes -when you first press the key. Notice that 225 isn't 224, so our normal -extended character handler will not take care of this. My personal theory is -that while a scan code of 224 (E0h) means there is 1 more character -following, a scan code of 225 (E1h) means there are *2* more following. I've -seen a number of keyboard handler libraries and they all seem to overlook -this key. So why not be the first kid on your block to have a keyboard -handler which properly supports the Pause/Break key? CHECK IT OUT!! - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Writing a Handler ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Writing a keyboard handler is fairly straightforward. This section will -show how to do it in Pascal (you C and asm programmers would probably already -know this stuff anyway). - -First we'll declare a few things we'll need: - -const KEYBOARDINTR = 9; - KEYBOARDPORT = $60; - -var BIOSKeyboardHandler : procedure; - CallBIOSHandler : boolean; - -The CallBIOSHandler variable will be initialised by the calling program. If -we also want the BIOS handler to process all keystrokes then this variable -must be set to true. - -Next we need to store the value of the current handler and set up own our -own one. We'll use a procedure called KeyboardHandler to handle the actual -interrupt. - -CallBIOSHandler := false; { ...or set it to true if you want. } -GetIntVec(KEYBOARDINTR, @BIOSKeyboardHandler); -SetIntVec(KEYBOARDINTR, Addr(KeyboardHandler)); - -Ok, so everything is now set up and our handler will now be able to process -all keyboard events. The actual interrupt handler could look like this: - -{$F+} -procedure KeyboardHandler(Flags, CS, IP, AX, BX, CX, DX, - SI, DI, DS, ES, BP: Word); -interrupt; -var key : byte; -begin - - key := Port[KEYBOARDPORT]; - - { PROCESS THE KEYSTROKE HERE } - - if CallBIOSHandler then - - { Call the BIOS keyboard handler if the calling program wants us to } - begin - asm pushf end; - BIOSKeyboardHandler; - end - - { Otherwise just acknowledge the interrupt } - else Port[$20] := $20; -end; -{$F-} - - -When the program is finished we can set the old keyboard handler again: - -SetIntVec(KEYBOARDINTR, @BIOSKeyboardHandler); - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ A Word of Warning ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -When I was writing a simple handler to test the info in this file I did -something REALLY stoopid which I would like to share with the world. I -thought that my program was stuffing the keyboard up because when I exited -the program my editor (Borland Pascal 7.0) would act as though the control -button was being held down (I'm sure some of you have already started -laughing by now). I had to press it after each time I ran the program -just to sort it out. After spending a few hours looking all over the place -for info on what could possibly be wrong I realised what I was doing. I was -pressing CTRL-F9 to compile the program which would also immediately make it -run and I was releasing the control key when my program was running, ie the -regular BIOS handler was not getting the control key's "key up" command and -still thought it was being held down when my program returned control to -it. Moron..... - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Scan Codes ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The following is a list of all the regular key scan codes in numerical -order: - -Scan Scan -Code Key Code Key -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - 1 ESC 44 Z - 2 1 45 X - 3 2 46 C - 4 3 47 V - 5 4 48 B - 6 5 49 N - 7 6 50 M - 8 7 51 , < - 9 8 52 . > -10 9 53 / ? -11 0 54 RIGHT SHIFT -12 - _ 55 * (KEYPAD) -13 = + 56 LEFT ALT -14 BACKSPACE 57 SPACEBAR -15 TAB 58 CAPSLOCK -16 Q 59 F1 -17 W 60 F2 -18 E 61 F3 -19 R 62 F4 -20 T 63 F5 -21 Y 64 F6 -22 U 65 F7 -23 I 66 F8 -24 O 67 F9 -25 P 68 F10 -26 [ { 69 NUMLOCK (KEYPAD) -27 ] } 70 SCROLL LOCK -28 ENTER (RETURN) 71 7 HOME (KEYPAD) -29 LEFT CONTROL 72 8 UP (KEYPAD) -30 A 73 9 PGUP (KEYPAD) -31 S 74 - (KEYPAD) -32 D 75 4 LEFT (KEYPAD) -33 F 76 5 (KEYPAD) -34 G 77 6 RIGHT (KEYPAD) -35 H 78 + (KEYPAD) -36 J 79 1 END (KEYPAD) -37 K 80 2 DOWN (KEYPAD) -38 L 81 3 PGDN (KEYPAD) -39 ; : 82 0 INSERT (KEYPAD) -40 ' " 83 . DEL (KEYPAD) -41 ` ~ 87 F11 -42 LEFT SHIFT 88 F12 - - -The following is a list of all the extended key scan codes in numerical -order: - -Scan Scan -Code Key Code Key -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -28 ENTER (KEYPAD) 75 LEFT (NOT KEYPAD) -29 RIGHT CONTROL 77 RIGHT (NOT KEYPAD) -42 PRINT SCREEN (SEE TEXT) 79 END (NOT KEYPAD) -53 / (KEYPAD) 80 DOWN (NOT KEYPAD) -55 PRINT SCREEN (SEE TEXT) 81 PAGE DOWN (NOT KEYPAD) -56 RIGHT ALT 82 INSERT (NOT KEYPAD) -71 HOME (NOT KEYPAD) 83 DELETE (NOT KEYPAD) -72 UP (NOT KEYPAD) 111 MACRO -73 PAGE UP (NOT KEYPAD) - diff --git a/16/PCGPE10/LIMEMS41.DOC b/16/PCGPE10/LIMEMS41.DOC deleted file mode 100644 index 22f41ad1..00000000 --- a/16/PCGPE10/LIMEMS41.DOC +++ /dev/null @@ -1,13224 +0,0 @@ - - - The associated file (LIMEMS41.DOC) is a complete transcription of - the Lotus/Intel/Microsoft (LIM) Expanded Memory Specification - (EMS) Version 4.0, updated October 1987. It can be printed by - "COPY LIMEMS41.DOC PRN:" - - I created this transcription because of the difficulty I origin- - ally had finding a copy of the document, because of the number of - people who have subsequently expressed an interest in having - access to a machine-readable copy of the specification, and, - finally, because of the annoying number of typographical errors - contained in the original and updated documents. - - This transcription is not an exact letter-for-letter duplicate of - the original document. Some minor changes were necessitated by - the simple fact that the document's proportionally-spaced, multi- - fonted typography and line drawings did not lend themselves to - the generic fixed-spacing, single-fonted, non-graphical ASCII - transcription I wanted to produce for general dissemination. - - Other minor changes were made to correct obvious typographical - and grammatical errors, or to simply improve the visual aes- - thetics of the presented material. - - In one area, however, I simply trashed their original material - and substituted my own. This area is the Index. The original - document contains an Index that is little more than a reformatt- - ing of the Table of Contents. As anyone who has ever indexed a - large document knows, it is very difficult to produce an Index - that is both complete AND easy to use. I didn't have time to - produce one that was both, so I aimed for the former. In fact, - the Index I have provided is more of an alphabetical listing of - key words and phrases and the pages where they are referenced, - than it is a more typical Index with its multi-level headings and - subheadings. - - You should be able obtain a printed, 3-hole-punched, 5.5 x 8.5" - copy of the original (and uncorrected) document directly from - Intel by calling their "Information Department" at 1-800-538-3373 - and asking for a copy of the "LIM EMS 4.0 Developer's Kit." It - is available free of charge and mine arrived in about two weeks. - (European availability, however, is reported to be from poor to - non-existent.) - - It is my intent to provide this transcription as a public - service. I am, therefore, releasing it into the public domain. - The original document has also been released into the public - domain by Lotus, Intel, and Microsoft, though it remains their - copyrighted property (I'm not quite sure how they manage to do - that). - - I have tried as best I can to provide an accurate and corrected - transcription of the original document. It is inevitable, - however, that some typographical errors have slipped through in - spite of my hours of bleary-eyed proof reading. For these errors - I apologize and plead simple human frailty. - - THIS TRANSCRIPTION IS PROVIDED WITHOUT ANY GUARANTEES - OR WARRANTIES OF ANY KIND, AND I ASSUME ABSOLUTELY NO - LIABILITY FOR ITS ACCURACY, CONTENT, OR SUBSEQUENT USE. - - Dick Flanagan, W6OLD, Ben Lomond, California November 1987 - - - - - - - - - - - - LOTUS(R)/INTEL(R)/MICROSOFT(R) - - EXPANDED MEMORY SPECIFICATION [1] - - - - - - - - - - - - - Version 4.0 - 300275-005 - October, 1987 - - - - - - - - - - - - - Copyright (C) 1987 - - Lotus Development Corporation - 55 Cambridge Parkway - Cambridge, MA 02142 - - Intel Corporation - 5200 NE Elam Young Parkway - Hillsboro, OR 97124 - - Microsoft Corporation - 16011 NE 35th Way - Box 97017 - Redmond, WA 98073 - - - [1] Transcribed into machine-readable form by Dick Flanagan, - Ben Lomond, California. This transcription is released into the - public domain without warranty or assumption of liability. - - - - - - This specification was jointly developed by Lotus Develop- - ment Corporation, Intel Corporation, and Microsoft Corpora- - tion. Although it has been released into the public domain - and is not confidential or proprietary, the specification is - still the copyright and property of Lotus Development - Corporation, Intel Corporation, and Microsoft Corporation. - - - DISCLAIMER OF WARRANTY - - LOTUS DEVELOPMENT CORPORATION, INTEL CORPORATION, AND MICRO- - SOFT CORPORATION EXCLUDE ANY AND ALL IMPLIED WARRANTIES, - INCLUDING WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE. NEITHER LOTUS NOR INTEL NOR MICROSOFT - MAKE ANY WARRANTY OF REPRESENTATION, EITHER EXPRESS OR - IMPLIED, WITH RESPECT TO THIS SPECIFICATION, ITS QUALITY, - PERFORMANCE, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR - PURPOSE. NEITHER LOTUS NOR INTEL NOR MICROSOFT SHALL HAVE - ANY LIABILITY FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL - DAMAGES ARISING OUT OF OR RESULTING FROM THE USE OR MODIF- - ICATION OF THIS SPECIFICATION. - - - - This specification uses the following trademarks: - - Intel is a trademark of Intel Corporation - Lotus is a trademark of Lotus Development Corporation - Microsoft is a trademark of Microsoft Corporation - - - - - - - - - - - - - - - - - - - - - - - - - ii - - - - - - CONTENTS - - - - Chapter 1 - INTRODUCTION - What is Expanded Memory? . . . . . . . . . . . . . . . . . 1 - How Expanded Memory Works . . . . . . . . . . . . . . . . 1 - - Chapter 2 - WRITING PROGRAMS THAT USE EXPANDED MEMORY - What Every Program Must Do . . . . . . . . . . . . . . . . 4 - Advanced Programming . . . . . . . . . . . . . . . . . . . 5 - Saving The State of Mapping Hardware . . . . . . . . . . 6 - Retrieving Handle and Page Counts . . . . . . . . . . . 6 - Mapping and Unmapping Multiple Pages . . . . . . . . . . 6 - Reallocating Pages . . . . . . . . . . . . . . . . . . . 6 - Using Handles and Assigning Names to Handles . . . . . . 6 - Using Handle Attributes . . . . . . . . . . . . . . . . 7 - Altering Page Maps and Jumping/Calling . . . . . . . . . 7 - Moving or Exchanging Memory Regions . . . . . . . . . . 7 - Getting the Amount of Mappable Memory . . . . . . . . . 8 - Operating System Functions . . . . . . . . . . . . . . . 8 - Programming Guidelines . . . . . . . . . . . . . . . . . . 12 - Examples . . . . . . . . . . . . . . . . . . . . . . . . . 14 - Example 1 . . . . . . . . . . . . . . . . . . . . . . . 14 - Example 2 . . . . . . . . . . . . . . . . . . . . . . . 19 - Example 3 . . . . . . . . . . . . . . . . . . . . . . . 30 - Example 4 . . . . . . . . . . . . . . . . . . . . . . . 32 - - Chapter 3 - EMM FUNCTIONS - Function 1. Get Status . . . . . . . . . . . . . . . . . . 37 - Function 2. Get Page Frame Address . . . . . . . . . . . . 38 - Function 3. Get Unallocated Page Count . . . . . . . . . . 40 - Function 4. Allocate Pages . . . . . . . . . . . . . . . . 42 - Function 5. Map/Unmap Handle Pages . . . . . . . . . . . . 46 - Function 6. Deallocate Pages . . . . . . . . . . . . . . . 49 - Function 7. Get Version . . . . . . . . . . . . . . . . . 51 - Function 8. Save Page Map . . . . . . . . . . . . . . . . 53 - Function 9. Restore Page Map . . . . . . . . . . . . . . . 55 - Function 10. Reserved . . . . . . . . . . . . . . . . . . 57 - Function 11. Reserved . . . . . . . . . . . . . . . . . . 58 - Function 12. Get Handle Count . . . . . . . . . . . . . . 59 - Function 13. Get Handle Pages . . . . . . . . . . . . . . 61 - Function 14. Get All Handle Pages . . . . . . . . . . . . 63 - Function 15. Get/Set Page Map . . . . . . . . . . . . . . 65 - Get Page Map subfunction . . . . . . . . . . . . . . . . 65 - Set Page Map subfunction . . . . . . . . . . . . . . . . 67 - Get & Set Page Map subfunction . . . . . . . . . . . . . 69 - Get Size of Page Map Save Array subfunction . . . . . . 71 - - - iii - - - - - - Function 16. Get/Set Partial Page Map . . . . . . . . . . 73 - Get Partial Page Map subfunction . . . . . . . . . . . . 73 - Set Partial Page Map subfunction . . . . . . . . . . . . 76 - Get Size of Partial Page Map Save Array subfunction . . 78 - Function 17. Map/Unmap Multiple Handle Pages . . . . . . . 80 - Mapping Multiple Pages . . . . . . . . . . . . . . . . . 80 - Unmapping Multiple Pages . . . . . . . . . . . . . . . . 80 - Mapping and Unmapping Multiple Pages Simultaneously . . 80 - Alternate Mapping and Unmapping Methods . . . . . . . . 81 - Logical Page/Physical Page Method . .OF THE EXPANDED MEMORY MANAGER - Which method should your program use? . . . . . . . . . . 199 - The "open handle" technique . . . . . . . . . . . . . . . 199 - The "get interrupt vector" technique . . . . . . . . . . . 204 - - Appendix C - EXPANDED MEMORY MANAGER IMPLEMENTATION GUIDELINES - The amount of expanded memory supported . . . . . . . . . 206 - The number of handles supported . . . . . . . . . . . . . 206 - Handle Numbering . . . . . . . . . . . . . . . . . . . . . 206 - New handle type: Handles versus Raw Handles . . . . . . . 206 - The system Raw Handle (Raw Handle = 0000h) . . . . . . . . 207 - Terminate and Stay Resident (TSR) Program Cooperation . . 208 - Accelerator Cards . . . . . . . . . . . . . . . . . . . . 208 - - Appendix D - OPERATING SYSTEM/ENVIRONMENT USE OF FUNCTION 28 - Examples . . . . . . . . . . . . . . . . . . . . . . . . . 209 - Example 1 . . . . . . . . . . . . . . . . . . . . . . . 209 - Example 2 . . . . . . . . . . . . . . . . . . . . . . . 210 - Example 3 . . . . . . . . . . . . . . . . . . . . . . . 211 - - GLOSSARY - - INDEX - - - - - - - - - - - - - - - - v - - - - - - Chapter 1 - INTRODUCTION - - - Because even the maximum amount (640K bytes) of conventional - memory isn't always enough for large application programs, - Lotus Development Corporation, Intel Corporation, and Micro- - soft Corporation created the Lotus/Intel/Microsoft (LIM) - Expanded Memory Specification. - - The LIM Expanded Memory Specification defines the software - interface between the Expanded Memory Manager (EMM) -- a - device driver that controls and manages expanded memory -- - and application programs that use expanded memory. - - - What is Expanded Memory? - - Expanded memory is memory beyond DOS's 640K-byte limit. The - LIM specification supports up to 32M bytes of expanded - memory. Because the 8086, 8088, and 80286 (in real mode) - microprocessors can physically address only 1M bytes of - memory, they access expanded memory through a window in - their physical address range. The next section explains how - this is done. - - - How Expanded Memory Works - - Expanded memory is divided into segments called logical - pages. These pages are typically 16K bytes of memory. Your - computer accesses logical pages through a physical block of - memory called a page frame. The page frame contains - multiple physical pages, pages that the microprocessor can - address directly. Physical pages are also typically 16K - bytes of memory. - - This page frame serves as a window into expanded memory. - Just as your computer screen is a window into a large - spreadsheet, so the page frame is a window into expanded - memory. - - A logical page of expanded memory can be mapped into (made - to appear in) any one of the physical pages in the page - frame. Thus, a read or write to the physical page actually - becomes a read or write to the associated logical page. One - logical page can be mapped into the page frame for each - physical page. - - Figure 1-1 shows the relationship among the page frame, - physical pages, and logical pages. - - - Introduction 1 - - - - - - 32M +--------------+ - /| | - | | - / | | - | | - / | | - | | - / | | - | Expanded | - / | Memory | - 1024K +--------------+ | | - | / / / / / / | / | | - 960K +--------------+ | | - | Page Frame | | | - | | | | - | 12 16K-Byte | | | - | Physical | | | - | Pages | | | - 768K +--------------+ | Divided into | - | / / / / / / | \ | logical | - 640K +--------------+ | pages | - | | \ | | - | | | | - | | \ | | - | | | | - | 24 16K-Byte | \ | | - | Physical | | | - | Pages* | \ | | - | | | | - | | \ | | - | | | | - | | \ | | - 256K +--------------+ | | - | | \ | | - | / / / / / / | | | - | | \ | | - | / / / / / / | | | - | | \ | | - | / / / / / / | | | - | | \ | | - 0 +--------------+ | | - \ | | - | | - *Intended for operating \ | | - system/environment use only 0 +--------------+ - - - - Figure 1-1. Expanded Memory - - - - - Introduction 2 - - - - - - The page frame is located above 640K bytes. Normally, only - video adapters, network cards, and similar devices exist - between 640K and 1024K. - - This specification also defines methods for operating - systems and environments to access expanded memory through - physical pages below 640K bytes. These methods are intended - for operating system/environment developers only. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Introduction 3 - - - - - - Chapter 2 - WRITING PROGRAMS THAT USE EXPANDED MEMORY - - - This chapter describes what every program must do to use - expanded memory and describes more advanced techniques of - using expanded memory. - - This chapter also lists programming guidelines you should - follow when writing programs that use expanded memory and - provides the listings of some example programs. - - - What Every Program Must Do - - This section describes the steps every program must take to - use expanded memory. - - In order to use expanded memory, applications must perform - these steps in the following order: - - 1. Determine if EMM is installed. - - 2. Determine if enough expanded memory pages exist for your - application. (Function 3) - - 3. Allocate expanded memory pages. (Function 4, 18, or 27) - - 4. Get the page frame base address. (Function 2) - - 5. Map in expanded memory pages. (Function 5 or 17) - - 6. Read/write/execute data in expanded memory, just as if - it were conventional memory. - - 7. Return expanded memory pages to expand memory pool - before exiting. (Function 6 or 18) - - Table 2-1 overviews the functions while Chapter 3 describes - each of these functions in detail. Example programs at the - end of this chapter illustrate using expanded memory. - - - - - - - - - - - - - Writing Programs That Use Expanded Memory 4 - - - - - - Table 2-1. The Basic Functions - ---------------------------------------------------------------- - - Function Description - - ---------------------------------------------------------------- - - 1 The Get Status Function returns a status code - indicating whether the memory manager hardware is - working correctly. - - 2 The Get Page Frame Address function returns the - address where the 64K-byte page frame is located. - - 3 The Get Unallocated Page Count function returns the - number of unallocated pages (pages available to your - program) and the total number of pages in expanded - memory. - - 4 The Allocate Pages function allocates the number of - pages requested and assigns a unique EMM handle to - these pages. - - 5 The Map/Unmap Handle Page function maps a logical - page to a specific physical page anywhere in the - mappable regions of system memory. - - 6 The Deallocate Pages deallocates the logical pages - currently allocated to an EMM handle. - - 7 The Get Version function returns the version number - of the memory manager software. - - ---------------------------------------------------------------- - - - - Advanced Programming - - In addition to the basic functions, the Lotus/Intel/Micro- - soft Expanded Memory Specification provides several advanced - functions which enhance the capabilities of software that - uses expanded memory. - - The following sections describe the advanced programming - capabilities and list the advanced EMM functions. - - - Note............................................................ - Before using the advanced functions, programs should first - call Function 7 (Get Version) to determine whether the - installed version of EMM supports these functions. - - Writing Programs That Use Expanded Memory 5 - - - - - - Saving The State of Mapping Hardware - - Some software (such as interrupt service routines, device - drivers, and resident software) must save the current state - of the mapping hardware, switch mapping contexts, manipulate - sections of expanded memory, and restore the original - context of the memory mapping hardware. Use Functions 8 and - 9 or 15 and 16 to save the state of the hardware. - - - Retrieving Handle and Page Counts - - Some utility programs need to keep track of how expanded - memory is being used; use Functions 12 through 14 to do - this. - - - Mapping and Unmapping Multiple Pages - - Mapping multiple pages reduces the overhead an application - must perform during mapping. Function 17 lets a program map - (or unmap) multiple pages at one time. - - In addition, you can map pages using segment addresses - instead of physical pages. For example, if the page frame - base address is set to D000, you can map to either physical - page 0 or segment D000. Function 25 (Get Mappable Physical - Address Array) returns a cross reference between all - expanded memory physical pages and their corresponding - segment values. - - - Reallocating Pages - - Reallocating pages (Function 18) lets applications dynami- - cally allocate expanded memory pages without acquiring - another handle or obtain a handle without allocating pages. - Reallocating pages is an efficient means for applications to - obtain and release expanded memory pages. - - - Using Handles and Assigning Names to Handles - - This specification lets you associate a name with a handle, - so a family of applications can share information in - expanded memory. For example, a software package consisting - of a word processor, spreadsheet, and print spooler can - share the same data among the different applications. The - print spooler could use a handle name to reference data that - either the spreadsheet or word processor put in expanded - memory and could check for data in a particular handle - name's expanded memory pages. - - Writing Programs That Use Expanded Memory 6 - - - - - - Use Function 20 (Set Handle Name subfunction) to assign a - handle name to an EMM handle or Function 21 (Search for - Named Handle subfunction) to obtain the EMM handle as- - sociated with the handle name. In addition, you can use - Function 14 (Get Handle Pages) to determine the number of - expanded memory pages allocated to an EMM handle. - - - Using Handle Attributes - - In addition to naming a handle, you can use Function 19 to - associate an attribute (volatile or non-volatile) with a - handle name. A non-volatile attribute enables expanded - memory pages to preserve their data through a warmboot. - With a volatile attribute, the data is not preserved. The - default attribute for handles is volatile. - - Because using this function depends on the capabilities of - the expanded memory hardware installed in the system, you - should use the Get Attribute Capability subfunction before - attempting to assign an attribute to a handle's pages. - - - Altering Page Maps and Jumping/Calling - - You can use Functions 22 (Alter Page Map & Jump) and 23 - (Alter Page Map & Call) to map a new set of values into the - map registers and transfer program control to a specified - address within expanded memory. These functions can be used - to load and execute code in expanded memory. An application - using this feature can significantly reduce the amount of - conventional memory it requires. Programs can load needed - modules into expanded memory at run time and use Functions - 22 and 23 to transfer control to these modules. - - Using expanded memory to store code can improve program - execution in many ways. For example, sometimes programs - need to be divided into small overlays because of conven- - tional memory size limitations. Overlays targeted for - expanded memory can be very large because LIM EMS 4.0 - supports up to 32M bytes of expanded memory. This method of - loading overlays improves overall system performance by - conserving conventional memory and eliminating conventional - memory allocation errors. - - - Moving or Exchanging Memory Regions - - Using Function 24 (Move/Exchange Memory Region), you can - easily move and exchange data between conventional and - expanded memory. Function 24 can manipulate up to one - megabyte of data with one function call. Although applica- - - Writing Programs That Use Expanded Memory 7 - - - - - - tions can perform this operation without this function, - having the expanded memory manager do it reduces the amount - of overhead for the application. - - In addition, this function checks for overlapping regions - and performs all the necessary mapping, preserving the - mapping context from before the exchange/move call. - - - Getting the Amount of Mappable Memory - - Function 25 enables applications to determine the total - amount of mappable memory the hardware/system currently - supports. Not all expanded memory boards supply the same - number of physical pages (map registers). - - The Get Mappable Physical Address Array Entries subfunction - returns the total number of physical pages the expanded - memory hardware/system is capable of supporting. The Get - Mappable Physical Array subfunction returns a cross refer- - ence between physical page numbers and the actual segment - address for each of the physical pages. - - - Operating System Functions - - In addition to the functions for application programs, this - specification defines functions for operating systems/en- - vironments. These functions can be disabled at any time by - the operating system/environment, so programs should not - depend on their presence. Applications that avoid this - warning and use these functions run a great risk of being - incompatible with other programs, including the operating - system. - - - - - - - - - - - - - - - - - - - - Writing Programs That Use Expanded Memory 8 - - - - - - Table 2-2. The Advanced Functions - ---------------------------------------------------------------- - - Function Description - - ---------------------------------------------------------------- - - 8 The Save Page Map saves the contents of the page - mapping registers from all expanded memory boards in - an internal save area. - - 9 The Restore Page Map function restores (from an - internal save area) the page mapping register - contents on the expanded memory boards for a - particular EMM handle. - - 10 Reserved. - - 11 Reserved. - - 12 The Get Handle Count function returns the number of - open EMM handles in the system. - - 13 The Get Handle Pages function returns the number of - pages allocated to a specific EMM handle. - - 14 The Get All Handle Pages function returns an array - of the active EMM handles and the number of pages - allocated to each one. - - 15 The Get/Set Page Map subfunction saves or restores - the mapping context for all mappable memory regions - (conventional and expanded) in a destination array - which the application supplies. - - 16 The Get/Set Partial Page Map subfunction provides a - mechanism for saving a partial mapping context for - specific mappable memory regions in a system. - - 17 The Map/Unmap Multiple Handle Pages function can, in - a single invocation, map (or unmap) logical pages - into as many physical pages as the system supports. - - 18 The Reallocate Pages function can increase or - decrease the amount of expanded memory allocated to - a handle. - - 19 The Get/Set Handle Attribute function allows an - application program to determine and set the - attribute associated with a handle. - - - - Writing Programs That Use Expanded Memory 9 - - - - - - Table 2-2. The Advanced Functions (continued) - ---------------------------------------------------------------- - - Function Description - - ---------------------------------------------------------------- - - 20 The Get/Set Handle Name function gets the eight - character name currently assigned to a handle and - can assign an eight character name to a handle. - - 21 The Get Handle Directory function returns informa- - tion about active handles and the names assigned to - each. - - 22 The Alter Page Map & Jump function alters the memory - mapping context and transfers control to the - specified address. - - 23 The Alter Page Map & Call function alters the speci- - fied mapping context and transfers control to the - specified address. A return can then restore the - context and return control to the caller. - - 24 The Move/Exchange Memory Region function copies or - exchanges a region of memory from conventional to - conventional memory, conventional to expanded - memory, expanded to conventional memory, or expanded - to expanded memory. - - 25 The Get Mappable Physical Address Array function - returns an array containing the segment address and - physical page number for each mappable physical page - in a system. - - 26 The Get Expanded Memory Hardware Information - function returns an array containing the hardware - capabilities of the expanded memory system. - - 27 The Allocate Standard/Raw Pages function allocates - the number of standard or non-standard size pages - that the operating system requests and assigns a - unique EMM handle to these pages. - - 28 The Alternate Map Register Set function enables an - application to simulate alternate sets of hardware - mapping registers. - - 29 The Prepare Expanded Memory Hardware for Warm Boot - function prepares the expanded memory hardware for - an "impending" warm boot. - - - Writing Programs That Use Expanded Memory 10 - - - - - - Table 2-2. The Advanced Functions (continued) - ---------------------------------------------------------------- - - Function Description - - ---------------------------------------------------------------- - - 30 The Enable/Disable OS/E function enables operating - systems developers to enable and disable functions - designed for operating system use. - - ---------------------------------------------------------------- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Writing Programs That Use Expanded Memory 11 - - - - - - Programming Guidelines - - The following section contains guidelines for programmers - writing applications that use EMM. - - o Do not put a program's stack in expanded memory. - - o Do not replace interrupt 67h. This is the interrupt - vector the EMM uses. Replacing interrupt 67h could - result in disabling the Expanded Memory Manager. - - o Do not map into conventional memory address space your - application doesn't own. Applications that use the EMM - to swap into conventional memory space, must first - allocate this space from the operating system. If the - operating system is not aware that a region of memory it - manages is in use, it will think it is available. This - could have disastrous results. EMM should not be used - to "allocate" conventional memory. DOS is the proper - manager of conventional memory space. EMM should only - be used to swap data in conventional memory space - previously allocated from DOS. - - o Applications that plan on using data aliasing in - expanded memory must check for the presence of expanded - memory hardware. Data aliasing occurs when mapping one - logical page into two or more mappable segments. This - makes one 16K-byte expanded memory page appear to be in - more than one 16K-byte memory address space. Data - aliasing is legal and sometimes useful for applications. - - Software-only expanded memory emulators cannot perform - data aliasing. A simple way to distinguish software - emulators from actual expanded memory hardware is to - attempt data aliasing and check the results. For - example, map one logical page into four physical pages. - Write to physical page 0. Read physical pages 1-3 to - see if the data is there as well. If the data appears - in all four physical pages, then expanded memory - hardware is installed in the system, and data aliasing - is supported. - - o Applications should always return expanded memory pages - to the expanded memory manager upon termination. These - pages will be made available for other applications. If - unneeded pages are not returned to the expanded memory - manager, the system could "run out" of expanded memory - pages or expanded memory handles. - - o Terminate and stay resident programs (TSR's) should - ALWAYS save the state of the map registers before - changing them. Since TSR's may interrupt other programs - - Writing Programs That Use Expanded Memory 12 - - - - - - which may be using expanded memory, they must not change - the state of the page mapping registers without first - saving them. Before exiting, TSR's must restore the - state of the map registers. - - The following sections describe the three ways to save - and restore the state of the map registers. - - 1. Save Page Map and Restore Page Map (Functions 8 and - 9). This is the simplest of the three methods. The - EMM saves the map register contents in its own data - structures -- the application does not need to - provide extra storage locations for the mapping - context. The last mapping context to be saved, - under a particular handle, will be restored when a - call to Restore Page Map is issued with the same - handle. This method is limited to one mapping - context for each handle and saves the context for - only LIM standard 64K-byte page frames. - - 2. Get/Set Page Map (Function 15). This method - requires the application to allocate space for the - storage array. The EMM saves the mapping context in - an array whose address is passed to the EMM. When - restoring the mapping context with this method, an - application passes the address of an array which - contains a previously stored mapping context. - - This method is preferable if an application needs to - do more than one save before a restore. It provides - a mechanism for switching between more than one - mapping context. - - 3. Get/Set Partial Page Map (Function 16). This method - provides a way for saving a partial mapping context. - It should be used when the application does not need - to save the context of all mappable memory. This - function also requires that the storage array be - part of the application's data. - - o All functions using pointers to data structures must - have those data structures in memory which will not be - mapped out. Functions 22 and 23 (Alter Map & Call and - Alter Map & Jump) are the only exceptions. - - - - - - - - - - Writing Programs That Use Expanded Memory 13 - - - - - - Examples - - This section lists four example programs that demonstrate - the use of expanded memory. - - - Example 1 - - This program was written using the Microsoft C compiler - Version 3.0. EMM function calls are made with the int86 - function found in the dos.h library. To create an ex- - ecutable program use the following compile command line: - - msc /Gs /Oat /Ml program,,program; - - #include - #include - - #define EMM_INT 0x67 /* EMM interrupt number */ - #define GET_PAGE_FRAME 0x41 /* EMM get page frame */ - /* function number */ - #define GET_UNALLOC_PAGE_COUNT 0x42 /* EMM get unallocated */ - /* page count */ - /* function number */ - #define ALLOCATE_PAGES 0x43 /* EMM allocate pages */ - /* function number */ - #define MAP_PAGES 0x44 /* EMM map pages */ - /* function number */ - #define DEALLOCATE_PAGES 0x45 /* EMM deallocate pages */ - /* function number */ - #define DEVICE_NAME_LENGTH 8 /* length of a device */ - /* name string */ - #define TRUE 1 - #define FALSE 0 - - union REGS input_regs, output_regs; - struct SREGS segment_regs; - int pf_addr; - - /*------------------------------------------------------------*/ - /* Routine to convert a segment:offset pair to a far ptr. */ - /*------------------------------------------------------------*/ - char *build_ptr (segment, offset) - - unsigned int segment; - unsigned int offset; - { - char *ptr; - - ptr = (char *)(((unsigned long)segment << 16) + offset); - return (ptr); - } - - Writing Programs That Use Expanded Memory 14 - - - - - - /*------------------------------------------------------------*/ - /* Function which determines whether EMM device driver */ - /* is installed. */ - /*------------------------------------------------------------*/ - char emm_installed() - - { - char *EMM_device_name = "EMMXXXX0"; - char *int_67_device_name_ptr; - - /*--------------------------------------------------------*/ - /* AH = DOS get interrupt vector function. */ - /*--------------------------------------------------------*/ - input_regs.h.ah = 0x35; - - /*--------------------------------------------------------*/ - /* AL = EMM interrupt vector number. */ - /*--------------------------------------------------------*/ - input_regs.h.al = EMM_INT; - intdosx (&input_regs, &output_regs, &segment_regs); - - /*--------------------------------------------------------*/ - /* Upon return ES:0Ah points to location where */ - /* device name should be. */ - /*--------------------------------------------------------*/ - int_67_device_name_ptr = build_ptr (segment_regs.es, 0x0A); - - /*--------------------------------------------------------*/ - /* Compare memory with EMM device name. */ - /*--------------------------------------------------------*/ - if (memcmp (EMM_device_name, int_67_device_name_ptr, - DEVICE_NAME_LENGTH) == 0) - return (TRUE); - else - return (FALSE); - } - - /*------------------------------------------------------------*/ - /* Function which determines if there are enough unallocated */ - /* expanded memory pages for the application. */ - /*------------------------------------------------------------*/ - char enough_unallocated_pages (pages_needed) - - int pages_needed; - { - input_regs.h.ah = GET_UNALLOCATED_PAGE_COUNT; - int86 (EMM_INT, &input_regs, &output_regs); - if (output_regs.h.ah != 0 || pages_needed > output_regs.x.bx) - return (FALSE); - else - return (TRUE); - } - - Writing Programs That Use Expanded Memory 15 - - - - - - /*------------------------------------------------------------*/ - /* Function which allocates expanded memory pages and passes */ - /* back to the main EMM handle. */ - /*------------------------------------------------------------*/ - char allocate_expanded_memory_pages (pages_needed,emm_handle_ptr) - - int pages_needed; - unsigned int *emm_handle_ptr; - { - input_regs.h.ah = ALLOCATE_PAGES; - input_regs.x.bx = pages_needed; - int86 (EMM_INT, &input_regs, &output_regs); - if (output_regs.h.ah == 0) { - *emm_handle_ptr = output_regs.x.dx; - return (TRUE); - } - else - return (FALSE); - } - - /*------------------------------------------------------------*/ - /* Routine to map a logical page to a physical page. */ - /*------------------------------------------------------------*/ - char map_expanded_memory_pages (emm_handle, physical_page, - logical_page) - unsigned int emm_handle; - int physical_page; - int logical_page; - { - input_regs.h.ah = MAP_PAGES; - input_regs.h.al = physical_page; - input_regs.x.bx = logical_page; - input_regs.x.dx = emm_handle; - int86 (EMM_INT, &input_regs, &output_regs); - if (output_regs.h.ah == 0) - return (TRUE); - else - return (FALSE); - } - - - - - - - - - - - - - - - Writing Programs That Use Expanded Memory 16 - - - - - - /*------------------------------------------------------------*/ - /* Routine which gets the page frame base address from EMM. */ - /*------------------------------------------------------------*/ - char get_page_frame_address (pf_ptr) - - char **pf_ptr; - { - input_regs.h.ah = GET_PAGE_FRAME; - int86 (EMM_INT, &input_regs, &output_regs); - if (output_regs.h.ah != 0) /* check EMM status */ - return (FALSE); - else - *pf_ptr = build_ptr (output_regs.x.bx, 0); - return (TRUE); - } - - /*------------------------------------------------------------*/ - /* Routine to release all expanded memory pages allocated */ - /* by an EMM handle. */ - /*------------------------------------------------------------*/ - - char deallocate_expanded_memory_pages (emm_handle) - - unsigned int emm_handle; - { - input_regs.h.ah = DEALLOCATE_PAGES; - input_regs.x.dx = emm_handle; - int86 (EMM_INT, &input_regs, &output_regs); - if (output_regs.h.ah == 0) - return (TRUE); - else - return (FALSE); - } - - main() - - { - unsigned int emm_handle; - char *pf_addr; - int pages_needed; - int physical_page; - int logical_page; - int index; - - /*--------------------------------------------------------*/ - /* Determine if EMM is installed. */ - /*--------------------------------------------------------*/ - if (!emm_installed()) - exit(1); - - - - - Writing Programs That Use Expanded Memory 17 - - - - - - /*--------------------------------------------------------*/ - /* Determine if enough expanded memory pages exist for */ - /* application. */ - /*--------------------------------------------------------*/ - pages_needed = 1; - if (!enough_unallocated_pages (pages_needed)) - exit(1); - - /*--------------------------------------------------------*/ - /* Allocate expanded memory pages. */ - /*--------------------------------------------------------*/ - if (!allocate_expanded_memory_pages (pages_needed, - &emm_handle)) - exit(1); - - /*--------------------------------------------------------*/ - /* Map in the required pages. */ - /*--------------------------------------------------------*/ - physical_page = 0; - logical_page = 0; - if (!map_expanded_memory_pages (emm_handle, physical_page, - logical_page)) - exit(1); - - /*--------------------------------------------------------*/ - /* Get expanded memory page frame address. */ - /*--------------------------------------------------------*/ - if (!get_page_frame_address (&pf_addr)) - exit(1); - - /*--------------------------------------------------------*/ - /* Write to expanded memory. */ - /*--------------------------------------------------------*/ - for (index = 0; index < 0x3fff; index++) - pf_addr[index] = index; - - /*--------------------------------------------------------*/ - /* Return expanded memory pages before exiting. */ - /*--------------------------------------------------------*/ - if (!deallocate_expanded_memory_pages (emm_handle)) - exit(1); - } - - - - - - - - - - - - Writing Programs That Use Expanded Memory 18 - - - - - - Example 2 - - This program shows you how to use the basic functions of the LIM - Expanded Memory Specification with Turbo Pascal. The program - does the following: - - 1. Makes sure the LIM Expanded Memory Manager (EMM) has - been installed. - - 2. Displays the version number of the EMM. - - 3. Determines if there are enough pages of memory for the - program. It then displays the total number of EMM pages - present in the system and the number available for use. - - 4. Requests the desired number of pages from the EMM. - - 5. Maps a logical page into one of the physical pages. - - 6. Displays the base address of our EMM memory page frame. - Performs a simple read/write test on the EMM memory. - - 7. Returns the EMM memory given to us back to the EMM. - - 8. Exits. - - All the calls are structured to return the result or error code - of the Expanded Memory function performed as an integer. If the - error code is not zero, an error has occurred, a simple error - procedure is called, and the program terminates. - - Type - ST3 = string[3]; - ST80 = string[80]; - ST5 = string[5]; - - Registers = record - case integer of - 1: (AX,BX,CX,DX,BP,SI,DI,DS,ES,FLAGS: Integer); - 2: (AL,AH,BL,BH,CL,CH,DL,DH : Byte); - end; - - Const - EMM_INT = $67; - DOS_Int = $21; - GET_PAGE_FRAME = $41; - GET_UNALLOCATED_PAGE_COUNT = $42; - ALLOCATE_PAGES = $43; - MAP_PAGES = $44; - DEALLOCATE_PAGES = $45; - GET_VERSION = $46; - STATUS_OK = 0; - - Writing Programs That Use Expanded Memory 19 - - - - - - {------------------------------------------------------------} - { Assume the application needs one EMM page. } - {------------------------------------------------------------} - APPLICATION_PAGE_COUNT = 1; - - Var - Regs: Registers; - - Emm_handle, - Page_Frame_Base_Address, - Pages_Needed, - Physical_Page, - Logical_Page, - Offset, - Error_Code, - Pages_EMM_Available, - Total_EMM_Pages, - Available_EMM_Pages: Integer; - - Version_Number, - Pages_Number_String: ST3; - - Verify: Boolean; - - {------------------------------------------------------------} - { The function Hex_String converts an integer into a four } - { character hexadecimal number (string) with leading zeros. } - {------------------------------------------------------------} - Function Hex_String (Number: Integer): ST5; - Function Hex_Char (Number: Integer): Char; - Begin - If Number < 10 then - Hex_Char := Char (Number + 48) - else - Hex_Char := Char (Number + 55); - end; { Function Hex_char } - - Var - S: ST5; - - Begin - S := ''; - S := Hex_Char ((Number shr 1) div 2048); - Number := (((Number shr 1) mod 2048) shl 1) + (Number and 1); - S := S + Hex_Char (Number div 256); - Number := Number mod 256; - S := S + Hex_Char (Number div 16); - Number := Number mod 16; - S := S + Hex_Char (Number); - Hex_String := S + 'h'; - end; { Function Hex_String } - - - Writing Programs That Use Expanded Memory 20 - - - - - - {------------------------------------------------------------} - { The function Emm_Installed checks to see if the } - { EMM is loaded in memory. It does this by looking } - { for the string 'EMMXXXX0', which should be located } - { at 10 bytes from the beginning of the code segment the } - { EMM interrupt, 67h, points to. } - {------------------------------------------------------------} - Function Emm_Installed: Boolean; - Var - Emm_Device_Name : string[8]; - Int_67_Device_Name: string[8]; - Position : integer; - Regs : registers; - - Begin - Int_67_Device_Name := ''; - Emm_Device_Name := 'EMMXXXX0'; - with Regs do - Begin - {----------------------------------------------------} - { Get the code segment interrupt 67h points to } - { the EMM interrupt by using DOS function 35h. } - { (get interrupt vector) } - {----------------------------------------------------} - AH := $35; - AL := EMM_INT; - Intr (DOS_Int, Regs); - {----------------------------------------------------} - { The ES pseudo-register contains the segment } - { address pointed to by interrupt 67h. Create an } - { eight character string from the eight successive } - { bytes at address ES:$000A (10 bytes from ES) } - {----------------------------------------------------} - For Position := 0 to 7 do - Int_67_Device_Name := - Int_67_Device_Name + Chr (mem[ES:Position + $0A]); - Emm_Installed := True; - {----------------------------------------------------} - { If the string is the EMM manager signature, } - { 'EMMXXXX0', then EMM is installed and ready for } - { use. If not, then EMM is not present. } - {----------------------------------------------------} - If Int_67_Device_Name <> Emm_Device_Name - then Emm_Installed := False; - end; { with Regs do } - end; { Function Emm_Installed } - - - - - - - - Writing Programs That Use Expanded Memory 21 - - - - - - {------------------------------------------------------------} - { This function returns the total number of EMM pages } - { present in the system, and the number of EMM pages that } - { are available. } - {------------------------------------------------------------} - Function EMM_Pages_Available - (Var Total_EMM_Pages, Pages_Available: Integer): Integer; - Var - Regs: Registers; - - Begin - with Regs do - Begin - {----------------------------------------------------} - { Get the number of currently unallocated pages and } - { the total number of pages in the system from EMM. } - { Load pseudo-registers prior to invoking EMM. } - { AH = get unallocated page count function } - {----------------------------------------------------} - AH := GET_UNALLOCATED_PAGE_COUNT; - Intr (EMM_INT, Regs); - {----------------------------------------------------} - { Unload the pseudo-registers after invoking EMM. } - { BX = currently unallocated pages } - { DX = total pages in the system } - { AH = status } - {----------------------------------------------------} - Pages_Available := BX; - Total_EMM_Pages := DX; - EMM_Pages_Available := AH; - end; - end; { Function EMM_Pages_Available } - - - {------------------------------------------------------------} - { This function requests the specified number of pages } - { from the EMM. } - {------------------------------------------------------------} - Function Allocate_Expanded_Memory_Pages - (Pages_Needed: Integer; Var Handle: Integer): Integer; - Var - Regs: Registers; - - - - - - - - - - - - Writing Programs That Use Expanded Memory 22 - - - - - - Begin - with Regs do - Begin - {----------------------------------------------------} - { Allocate the specified number of pages from EMM. } - { Load pseudo-registers prior to invoking EMM. } - { AH = allocate pages function. } - { BX = number of pages to allocate. } - {----------------------------------------------------} - AH := ALLOCATE_PAGES; - BX := Pages_Needed; - Intr (EMM_INT, Regs); - {----------------------------------------------------} - { Unload the pseudo-registers after invoking EMM. } - { DX = EMM handle } - { AH = status } - {----------------------------------------------------} - Handle := DX; - Allocate_Expanded_Memory_Pages := AH; - end; - end; { Function Allocate_Expanded_Memory_Pages } - - - {------------------------------------------------------------} - { This function maps a logical page allocated by the } - { Allocate_Expanded_Memory_Pages function into one of the } - { four physical pages. } - {------------------------------------------------------------} - Function Map_Expanded_Memory_Pages - (Handle, Logical_Page, Physical_Page: Integer): Integer; - Var - Regs: Registers; - - Begin - with Regs do - Begin - {----------------------------------------------------} - { Map a logical page at a physical page. } - { Load pseudo-registers prior to invoking EMM. } - { AH = map page function } - { DX = handle } - { BX = logical page number } - { AL = physical page number } - {----------------------------------------------------} - AH := MAP_PAGES; - DX := Handle; - BX := Logical_Page; - AL := Physical_Page; - Intr (EMM_INT, Regs); - - - - - Writing Programs That Use Expanded Memory 23 - - - - - - {----------------------------------------------------} - { Unload the pseudo-registers after invoking EMM. } - { AH = status } - {----------------------------------------------------} - Map_Expanded_Memory_Pages := AH; - end; { with Regs do } - end; { Function Map_Expanded_Memory_Pages } - - - {------------------------------------------------------------} - { This function gets the physical address of the EMM page } - { frame we are using. The address returned is the segment } - { of the page frame. } - {------------------------------------------------------------} - Function Get_Page_Frame_Base_Address - (Var Page_Frame_Address: Integer): Integer; - Var - Regs: Registers; - - Begin - with Regs do - Begin - {----------------------------------------------------} - { Get the page frame segment address from EMM. } - { Load pseudo-registers prior to invoking EMM. } - { AH = get page frame segment function } - {----------------------------------------------------} - AH := GET_PAGE_FRAME; - Intr (EMM_INT, Regs); - {----------------------------------------------------} - { Unload the pseudo-registers after invoking EMM. } - { BX = page frame segment address } - { AH = status } - {----------------------------------------------------} - Page_Frame_Address := BX; - Get_Page_Frame_Base_Address := AH; - end; { with Regs do } - end; { Function Get_Page_Frame_Base_Address } - - - {------------------------------------------------------------} - { This function releases the EMM memory pages allocated to } - { us, back to the EMM memory pool. } - {------------------------------------------------------------} - Function Deallocate_Expanded_Memory_Pages - (Handle: Integer): Integer; - Var - Regs: Registers; - - - - - - Writing Programs That Use Expanded Memory 24 - - - - - - Begin - with Regs do - Begin - {----------------------------------------------------} - { Deallocate the pages allocated to an EMM handle. } - { Load pseudo-registers prior to invoking EMM. } - { AH = deallocate pages function } - { DX = EMM handle } - {----------------------------------------------------} - AH := DEALLOCATE_PAGES; - DX := Handle; - Intr (EMM_INT, Regs); - {----------------------------------------------------} - { Unload the pseudo-registers after invoking EMM. } - { AH = status } - {----------------------------------------------------} - Deallocate_Expanded_Memory_Pages := AH; - end; { with Regs do } - end; { Function Deallocate_Expanded_Memory_Pages } - - - {------------------------------------------------------------} - { This function returns the version number of the EMM as } - { a three-character string. } - {------------------------------------------------------------} - Function Get_Version_Number (Var Version_String: ST3): Integer; - Var - Regs: Registers; - Integer_Part, Fractional_Part: Char; - - Begin - with Regs do - Begin - {----------------------------------------------------} - { Get the version of EMM. } - { Load pseudo-registers prior to invoking EMM. } - { AH = get EMM version function } - {----------------------------------------------------} - AH := GET_VERSION; - Intr (EMM_INT, Regs); - - - - - - - - - - - - - - Writing Programs That Use Expanded Memory 25 - - - - - - {----------------------------------------------------} - { If the version number returned was OK, then } - { convert it to a three-character string. } - {----------------------------------------------------} - If AH=STATUS_OK then - Begin - {------------------------------------------------} - { The upper four bits of AH are the integer } - { portion of the version number, the lower four } - { bits are the fractional portion. Convert the } - { integer value to ASCII by adding 48. } - {------------------------------------------------} - Integer_Part := Char (AL shr 4 + 48); - Fractional_Part := Char (AL and $F + 48); - Version_String := Integer_Part + '.' + - Fractional_Part; - end; { If AH=STATUS_OK } - {----------------------------------------------------} - { Unload the pseudo-registers after invoking EMM. } - { AH = status } - {----------------------------------------------------} - Get_Version_Number := AH; - end; { with Regs do } - end; { Function Get_Version_Number } - - - {------------------------------------------------------------} - { This procedure prints an error message passed by the } - { caller, prints the error code passed by the caller in hex, } - { and then terminates the program with an error level of 1. } - {------------------------------------------------------------} - Procedure Error (Error_Message: ST80; Error_Number: Integer); - Begin - Writeln (Error_Message); - Writeln (' Error_Number = ', Hex_String (Error_Number)); - Writeln ('EMM test program aborting.'); - Halt (1); - end; { Procedure Error } - - - {--------------------------------------------------------------} - { This program is an example of the basic EMM functions that } - { you need in order to use EMM memory with Turbo Pascal. } - {--------------------------------------------------------------} - Begin - ClrScr; - Window (5,2,77,22); - - - - - - - Writing Programs That Use Expanded Memory 26 - - - - - - {------------------------------------------------------------} - { Determine if the Expanded Memory Manager is installed. If } - { not, then terminate 'main' with an ErrorLevel code of 1. } - {------------------------------------------------------------} - If not (Emm_Installed) then - Begin - Writeln ('The LIM EMM is not installed.'); - Halt (1); - end - else - Begin - { Get the version number and display it } - Error_Code := Get_Version_Number (Version_Number); - If Error_Code <> STATUS_OK then - Error ('Error getting EMM version number.', Error_Code) - else - Writeln ('LIM Expanded Memory Manager, version ', - Version_Number, ' is ready for use.'); - end; - Writeln; - - {------------------------------------------------------------} - { Determine if there are enough expanded memory pages for } - { this application. } - {------------------------------------------------------------} - Pages_Needed := APPLICATION_PAGE_COUNT; - Error_Code := EMM_Pages_Available (Total_EMM_Pages, - Available_EMM_Pages); - If Error_Code <> STATUS_OK then - Error ('Error determining number of EMM pages available.', - Error_Code); - Writeln ('There are a total of ', Total_EMM_Pages, - ' expanded memory pages present in this system.'); - Writeln (' ', Available_EMM_Pages, - ' of those pages are available for use.'); - Writeln; - - {------------------------------------------------------------} - { If there is an insufficient number of pages for the } - { application, then report the error and terminate the EMM } - { example program. } - {------------------------------------------------------------} - If Pages_Needed > Available_EMM_Pages then - Begin - Str (Pages_Needed, Pages_Number_String); - Error ('We need ' + Pages_Number_String + - ' EMM pages. There are not that many available.', - Error_Code); - end; { Pages_Needed > Available_EMM_Pages } - - - - - Writing Programs That Use Expanded Memory 27 - - - - - - {------------------------------------------------------------} - { Allocate expanded memory pages for our use. } - {------------------------------------------------------------} - Error_Code := - Allocate_Expanded_Memory_Pages (Pages_Needed, Emm_Handle); - Str (Pages_Needed, Pages_Number_String); - If Error_Code <> STATUS_OK then - Error ('EMM test program failed trying to allocate ' - + Pages_Number_String - + ' pages for usage.', Error_Code); - Writeln (APPLICATION_PAGE_COUNT, - ' EMM page(s) allocated for the EMM test program.'); - Writeln; - - {------------------------------------------------------------} - { Map in the required logical pages to the physical pages } - { given to us, in this case just one page. } - {------------------------------------------------------------} - Logical_Page := 0; - Physical_Page := 0; - Error_Code := Map_Expanded_Memory_Pages (Emm_Handle, - Logical_Page, - Physical_Page); - If Error_Code <> STATUS_OK then - Error ('EMM test program failed trying to map ' - + 'logical pages into physical pages.', - Error_Code); - - Writeln ('Logical Page ', - Logical_Page, - ' successfully mapped into Physical Page ', - Physical_Page); - Writeln; - - {------------------------------------------------------------} - { Get the expanded memory page frame address. } - {------------------------------------------------------------} - Error_Code := Get_Page_Frame_Base_Address - (Page_Frame_Base_Address); - If Error_Code <> STATUS_OK then - Error ('EMM test program unable to get the base Page' - + ' Frame Address.', - Error_Code); - Writeln ('The base address of the EMM page frame is = ' - + Hex_String (Page_Frame_Base_Address)); - Writeln; - - - - - - - - Writing Programs That Use Expanded Memory 28 - - - - - - {------------------------------------------------------------} - { Write a test pattern to expanded memory. } - {------------------------------------------------------------} - For Offset := 0 to 16382 do - Begin - Mem[Page_Frame_Base_Address:Offset] := Offset mod 256; - end; - - {------------------------------------------------------------} - { Make sure that what is in EMM memory is what was just } - { written. } - {------------------------------------------------------------} - Writeln ('Testing EMM memory.'); - - Offset := 1; - Verify := True; - while (Offset <= 16382) and (Verify = True) do - Begin - If Mem[Page_Frame_Base_Address:Offset] <> Offset mod 256 - then Verify := False; - Offset := Succ (Offset); - end; { while (Offset <= 16382) and (Verify = True) } - - {------------------------------------------------------------} - { If what is read does not match what was written, } - { an error occurred. } - {------------------------------------------------------------} - If not Verify then - Error ('What was written to EMM memory was not found during' - + ' memory verification test.', - 0); - Writeln ('EMM memory test successful.'); - Writeln; - - {------------------------------------------------------------} - { Return the expanded memory pages given to us back to the } - { EMM memory pool before terminating our test program. } - {------------------------------------------------------------} - Error_Code := Deallocate_Expanded_Memory_Pages (Emm_Handle); - If Error_Code <> STATUS_OK then - Error ('EMM test program was unable to deallocate ' - + 'the EMM pages in use.', - Error_Code); - Writeln (APPLICATION_PAGE_COUNT, - ' pages(s) deallocated.'); - Writeln; - Writeln ('EMM test program completed.'); - - end. - - - - - Writing Programs That Use Expanded Memory 29 - - - - - - Example 3 - - This program is written in Microsoft's macro assembler. - - - CODE SEGMENT - ASSUME CS:CODE, DS:CODE - - MOV AX,CS - MOV DX,AX - . - . - . - check_emm_installed: - - MOV AH,35h ; AH = DOS get interrupt vector - ; function - MOV AL,67h ; AL = EMM interrupt vector number - INT 21h - MOV DI,0Ah ; ES:DI points to where device - ; name should be - LEA SI,EMM_device_name ; DS:SI points to ASCII string - ; containing EMM device name - - MOV CX,device_name_length ; set up loop counter for string op - CLD ; set up direction flag for forward - REPE CMPSB ; Compare the strings - JNE exit ; IF strings not equal THEN exit - ; ELSE - check_enough_unallocated_pages: - - MOV AH,41h ; AH = EMM get unallocated page - ; count function code - INT 67h - OR AH,AH ; Check EMM status - JNZ emm_error_handler ; IF error THEN goto error handler - ; ELSE - allocate_expanded_memory_pages: - - MOV AH,43h ; AH = EMM allocate pages - ; function code - MOV BX,2 ; BX = number of pages needed - INT 67h - OR AH,AH ; Check EMM status - JNZ emm_error_handler ; IF error THEN goto error handler - ; ELSE - MOV emm_handle,DX ; save EMM handle - - map_expanded_memory_pages: - - MOV AH,44h ; AH = EMM map pages function - MOV DX,emm_handle ; DX = application's handle - - Writing Programs That Use Expanded Memory 30 - - - - - - map_0_to_0: - - MOV BX,0 ; BX = logical page 0 - MOV AL,0 ; AL = physical page 0 - INT 67h - OR AH,AH ; Check EMM status - JNZ emm_error_handler ; If error THEN goto error handler - ; ELSE - get_page_frame_address: - - MOV AH,41h ; AH = EMM get page frame base - ; address function - INT 67h - OR AH,AH ; Check EMM status - JNZ emm_error_handler ; IF error THEN goto error handler - MOV pf_addr,BX ; ELSE save pf_addr - - write_to_expanded_memory: ; Write zeros to memory mapped at - ; physical page 0 - MOV AX,pf_addr - MOV ES,AX ; ES points to physical page 0 - MOV DI,0 ; DI indexes into physical page 0 - MOV AL,0 ; Initialize AL for string STOSB - MOV CX,4000h ; Initialize loop counter to length - ; of expanded memory page size - CLD ; set up direction flag for forward - REP STOSB - - deallocate_pages: - - MOV AH,45h ; AH = EMM deallocate pages - ; function - MOV DX,emm_handle - INT 67h ; return handle's pages to EMM - OR AH,AH ; Check EMM status - JNZ emm_error_handler ; IF error THEN goto error handler - - exit: - - MOV AH,4Ch ; AH = DOS exit function - INT 21h ; return to DOS - - - EMM_device_name DB 'EMMXXXX0' ; ASCII EMM device name string - - device_name_length EQU 8 - - CODE ENDS - END - - - - - Writing Programs That Use Expanded Memory 31 - - - - - - Example 4 - - This program is an example of how to exchange a 256K-byte - block of data from conventional memory to expanded memory. - - - CODE SEGMENT - ASSUME CS:CODE, DS:CODE - . - . - . - xchg_packet_set_up: - - ;DS:SI = xchg_packet - - MOV AX,SEG xchg_packet - MOV DS,AX - MOV SI,OFFSET xchg_packet - - ;Moving 256K of data from conventional memory to expanded memory - - MOV WORD PTR [SI].region_length[0],0 - MOV WORD PTR [SI].region_length[2],4 - MOV [SI].src_mem_type,0 - MOV [SI].dest_mem_type,1 - - ;starting at segment: 4000h, offset: 0 - - MOV [SI].src_init_seg_page,4000h - MOV [SI].src_init_offset,0 - - ;Move data into expanded memory logical page 0, offset 0. - - MOV [SI].dest_init_seg_page,0 - MOV [SI].dest_init_offset,0 - - ;Initialize for future compatibility - - MOV [SI].src_handle,0 - - ;Need handle for expanded memory destination. - - MOV DX,emm_handle - MOV [SI].dest_handle,DX - - ;AX = EMM Exchange Memory function - - MOV AX,5701h - INT 67h - OR AH,AH - JNZ emm_error_handler - - - Writing Programs That Use Expanded Memory 32 - - - - - - xchg_struct STRUC - region_length DD ? - src_mem_type DB ? - src_handle DW ? - src_init_offset DW ? - src_init_seg_page DW ? - dest_mem_type DB ? - dest_handle DW ? - dest_init_offset DW ? - dest_init_seg_page DW ? - xchg_struct ENDS - - xchg_packet xchg_struct - - CODE ENDS - END - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Writing Programs That Use Expanded Memory 33 - - - - - - Chapter 3 - EMM FUNCTIONS - - - This chapter provides you with a standardized set of - expanded memory functions. Because they are standardized, - you avoid potential compatibility problems with other - expanded memory programs that also adhere to the memory - manager specification. Programs that deal directly with the - hardware or that don't adhere to this specification will be - incompatible. - - Table 3-1 presents a sequential list of the EMM functions. - The remainder of this chapter provides detailed descriptions - of each function. - - - Table 3-1. List of EMM Functions - ---------------------------------------------------------------- - - Number Function Name Hex Value Page - - ---------------------------------------------------------------- - - 1 Get Status 40h 37 - - 2 Get Page Frame Address 41h 38 - - 3 Get Unallocated Page Count 42h 40 - - 4 Allocate Pages 43h 42 - - 5 Map/Unmap Handle Page 44h 46 - - 6 Deallocate Pages 45h 49 - - 7 Get Version 46h 51 - - 8 Save Page Map 47h 53 - - 9 Restore Page Map 48h 55 - - 10 Reserved 49h 57 - - 11 Reserved 4Ah 58 - - 12 Get Handle Count 4Bh 59 - - 13 Get Handle Pages 4Ch 61 - - 14 Get All Handle Pages 4Dh 63 - - - EMM Functions 34 - - - - - - Table 3-1. List of EMM Functions (continued) - ---------------------------------------------------------------- - - Number Function Name Hex Value Page - - ---------------------------------------------------------------- - - 15 Get Page Map 4E00h 65 - Set Page Map 4E01h 67 - Get & Set Page Map 4E02h 69 - Get Size of Page Map Save Array 4E03h 71 - - 16 Get Partial Page Map 4F00h 73 - Set Partial Page Map 4F01h 76 - Get Size of Partial Page Map - Save Array 4F02h 78 - - 17 Map/Unmap Multiple Handle Pages - (Physical page number mode) 5000h 82 - Map/Unmap Multiple Handle Pages - (Segment address mode) 5001h 85 - - 18 Reallocate Pages 51h 88 - - 19 Get Handle Attribute 5200h 92 - Set Handle Attribute 5201h 94 - Get Handle Attribute Capability 5202h 96 - - 20 Get Handle Name 5300h 98 - Set Handle Name 5301h 100 - - 21 Get Handle Directory 5400h 102 - Search for Named Handle 5401h 105 - Get Total Handles 5402h 107 - - 22 Alter Page Map & Jump - (Physical page number mode) 5500h 109 - Alter Page Map & Jump - (Segment address mode) 5501h 109 - - 23 Alter Page Map & Call - (Physical page number mode) 5600h 113 - Alter Page Map & Call - (Segment address mode) 5601h 113 - Get Page Map Stack Space Size 5602h 118 - - 24 Move Memory Region 5700h 120 - Exchange Memory Region 5701h 126 - - 25 Get Mappable Physical Address Array 5800h 132 - Get Mappable Physical Address Array - Entries 5801h 136 - - EMM Functions 35 - - - - - - Table 3-1. List of EMM Functions (continued) - ---------------------------------------------------------------- - - Number Function Name Hex Value Page - - ---------------------------------------------------------------- - - 26 Get Hardware Configuration Array 5900h 138 - Get Unallocated Raw Page Count 5901h 142 - - 27 Allocate Standard Pages 5A00h 144 - Allocate Raw Pages 5A01h 147 - - 28 Get Alternate Map Register Set 5B00h 153 - Set Alternate Map Register Set 5B01h 157 - Get Alternate Map Save Array Size 5B02h 161 - Allocate Alternate Map Register Set 5B03h 163 - Deallocate Alternate Map Register Set 5B04h 166 - Allocate DMA Register Set 5B05h 168 - Enable DMA on Alternate Map - Register Set 5B06h 170 - Disable DMA on Alternate Map - Register Set 5B07h 173 - Deallocate DMA Register Set 5B08h 175 - - 29 Prepare Expanded Memory Hardware - for Warmboot 5Ch 177 - - 30 Enable OS/E Function Set 5D00h 179 - Disable OS/E Function Set 5D01h 182 - Return OS/E Access Key 5D02h 185 - - ---------------------------------------------------------------- - - - - - - - - - - - - - - - - - - - - - EMM Functions 36 - - - - - - Function 1. Get Status - - - - PURPOSE - - The Get Status function returns a status code indicating - whether the memory manager is present and the hardware is - working correctly. - - - CALLING PARAMETERS - - AH = 40h - Contains the Get Status Function. - - - REGISTERS MODIFIED - - AX - - - STATUS - - AH = 0 SUCCESSFUL. - The manager is present in the system, and the hardware - is working correctly. - - AH = 80h NON-RECOVERABLE. - The manager detected a malfunction in the memory manager - software. - - AH = 81h NON-RECOVERABLE. - The manager detected a malfunction in the expanded - memory hardware. - - AH = 84h NON-RECOVERABLE. - The function code passed to the memory manager is not - defined. - - - EXAMPLE - - MOV AH,40h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - - - - - - - EMM Functions 37 - - - - - - Function 2. Get Page Frame Address - - - - PURPOSE - - The Get Page Frame Address function returns the segment - address where the page frame is located. - - - CALLING PARAMETERS - - AH = 41h - Contains the Get Page Frame Address function. - - - RESULTS - - These results are valid only if the status returned is zero. - - BX = page frame segment address - Contains the segment address of the page frame. - - - REGISTERS MODIFIED - - AX, BX - - - STATUS - - AH = 0 SUCCESSFUL. - The manager has returned the page frame address in the - BX register. - - AH = 80h NON-RECOVERABLE. - The manager detected a malfunction in the memory manager - software. - - AH = 81h NON-RECOVERABLE. - The manager detected a malfunction in the expanded - memory hardware. - - AH = 84h NON-RECOVERABLE. - The function code passed to the memory manager is not - defined. - - - - - - - - EMM Functions 38 - - - - - - Function 2. Get Page Frame Address - - - - EXAMPLE - - page_frame_segment DW ? - - MOV AH,41h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - MOV page_frame_segment,BX ; save page frame address - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EMM Functions 39 - - - - - - Function 3. Get Unallocated Page Count - - - - PURPOSE - - The Get Unallocated Page Count function returns the number - of unallocated pages and the total number of expanded memory - pages. - - - CALLING PARAMETERS - - AH = 42h - Contains the Get Unallocated Page Count function. - - - RESULTS - - These results are valid only if the status returned is zero. - - BX = unallocated pages - The number of expanded memory pages that are currently - available for use (unallocated). - - DX = total pages - The total number of expanded memory pages. - - - REGISTERS MODIFIED - - AX, BX, DX - - - STATUS - - AH = 0 SUCCESSFUL. - The manager has returned the number of unallocated pages - and the number of total pages in expanded memory. - - AH = 80h NON-RECOVERABLE. - The manager detected a malfunction in the memory manager - software. - - AH = 81h NON-RECOVERABLE. - The manager detected a malfunction in the expanded - memory hardware. - - AH = 84h NON-RECOVERABLE. - The function code passed to the memory manager is not - defined. - - - EMM Functions 40 - - - - - - Function 3. Get Unallocated Page Count - - - - EXAMPLE - - un_alloc_pages DW ? - total_pages DW ? - - MOV AH,42h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - MOV un_alloc_pages,BX ; save unallocated page count - MOV total_pages,DX ; save total page count - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EMM Functions 41 - - - - - - Function 4. Allocate Pages - - - - The Allocate Pages function allocates the number of pages - requested and assigns a unique EMM handle to these pages. - The EMM handle owns these pages until the application - deallocates them. - - Handles which are assigned using this function will have - 16K-byte pages, the size of a standard expanded memory page. - If the expanded memory board hardware isn't able to supply - 16K-byte pages, it will emulate them by combining multiple - non-standard size pages to form a single 16K-byte page. All - application programs and functions that use the handles this - function returns will deal with 16K-byte pages. - - The numeric value of the handles the EMM returns are in the - range of 1 to 254 decimal (0001h to 00FEh). The OS handle - (handle value 0) is never returned by the Allocate Pages - function. Also, the uppermost byte of the handle will be - zero and cannot be used by the application. A memory - manager should be able to supply up to 255 handles, includ- - ing the OS handle. An application can use Function 21 to - find out how many handles an EMM supports. - - Allocating zero pages to a handle is not valid. If an - application needs to allocate 0 pages to a handle it should - use Function 27 (Allocate Standard Pages subfunction) - provided for this purpose. - - Note............................................................ - This note affects expanded memory manager implementors and - operating system developers only. Applications should not - use the following characteristics of the memory manager. An - application violating this rule will be incompatible with - future versions of Microsoft's operating systems and - environments. - - To be compatible with this specification, an expanded memory - manager will provide a special handle which is available to - the operating system only. This handle will have a value of - 0000h and will have a set of pages allocated to it when the - expanded memory manager driver installs. The pages that the - memory manager will automatically allocate to handle 0000h - are those that backfill conventional memory. Typically, - this backfill occurs between addresses 40000h (256K) and - 9FFFFh (640K). However, the range can extend below and - above this limit if the hardware and memory manager have the - capability. - - - - EMM Functions 42 - - - - - - Function 4. Allocate Pages - - - - An operating system won't have to invoke Function 4 to - obtain this handle because it can assume the handle already - exists and is available for use immediately after the - expanded memory device driver installs. When an operating - system wants to use this handle, it uses the special handle - value of 0000h. The operating system will be able to invoke - any EMM function using this special handle value. To - allocate pages to this handle, the operating system need - only invoke Function 18 (Reallocate Pages). - - There are two special cases for this handle: - - 1. Function 4 (Allocate Pages). This function must never - return zero as a handle value. Applications must always - invoke Function 4 to allocate pages and obtain a handle - which identifies the pages which belong to it. Since - Function 4 never returns a handle value of zero, an - application will never gain access to this special - handle. - - 2. Function 6 (Deallocate Pages). If the operating system - uses it to deallocate the pages which are allocated to - this special handle, the pages the handle owns will be - returned to the manager for use. But the handle will - not be available for reassignment. The manager should - treat a deallocate pages function request for this - handle the same as a reallocate pages function request, - where the number of pages to reallocate to this handle - is zero. - - - CALLING PARAMETERS - - AH = 43h - Contains the Allocate Pages function. - - BX = num_of_pages_to_alloc - Contains the number of pages you want your program to - allocate. - - - - - - - - - - - EMM Functions 43 - - - - - - Function 4. Allocate Pages - - - - RESULTS - - These results are valid only if the status returned is zero. - - DX = handle - Contains a unique EMM handle. Your program must use - this EMM handle (as a parameter) in any function that - requires it. You can use up to 255 handles. The - uppermost byte of the handle will be zero and cannot be - used by the application. - - - REGISTERS MODIFIED - - AX, DX - - - STATUS - - AH = 0 SUCCESSFUL. - The manager has allocated the requested pages to the - assigned EMM handle. - - AH = 80h NON-RECOVERABLE. - The manager detected a malfunction in the memory manager - software. - - AH = 81h NON-RECOVERABLE. - The manager detected a malfunction in the expanded - memory hardware. - - AH = 84h NON-RECOVERABLE. - The function code passed to the memory manager is not - defined. - - AH = 85h RECOVERABLE. - All EMM handles are being used. - - AH = 87h RECOVERABLE. - There aren't enough expanded memory pages present in the - system to satisfy your program's request. - - AH = 88h RECOVERABLE. - There aren't enough unallocated pages to satisfy your - program's request. - - AH = 89h RECOVERABLE. - Your program attempted to allocate zero pages. - - EMM Functions 44 - - - - - - Function 4. Allocate Pages - - - - EXAMPLE - - num_of_pages_to_alloc DW ? - emm_handle DW ? - - MOV BX,num_of_pages_to_alloc ; load number of pages - MOV AH,43h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - MOV emm_handle,DX ; save EMM handle - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EMM Functions 45 - - - - - - Function 5. Map/Unmap Handle Pages - - - - PURPOSE - - The Map/Unmap Handle Page function maps a logical page at a - specific physical page anywhere in the mappable regions of - system memory. The lowest valued physical page numbers are - associated with regions of memory outside the conventional - memory range. Use Function 25 (Get Mappable Physical - Address Array) to determine which physical pages within a - system are mappable and determine the segment addresses - which correspond to a specific physical page number. - Function 25 provides a cross reference between physical page - numbers and segment addresses. - - This function can also unmap physical pages, making them - inaccessible for reading or writing. You unmap a physical - page by setting its associated logical page to FFFFh. - - You might unmap an entire set of mapped pages, for example, - before loading and executing a program. Doing so ensures - the loaded program, if it accesses expanded memory, won't - access the pages your program has mapped. However, you must - save the mapped context before you unmap the physical pages. - This enables you to restore it later so you can access the - memory you mapped there. To save the mapping context, use - Function 8, 15, or 16. To restore the mapping context, use - Function 9, 15, or 16. - - The handle determines what type of pages are being mapped. - Logical pages allocated by Function 4 and Function 27 - (Allocate Standard Pages subfunction) are referred to as - pages and are 16K bytes long. Logical pages allocated by - Function 27 (Allocate Raw Pages subfunction) are referred to - as raw pages and might not be the same size as logical - pages. - - - CALLING PARAMETERS - - AH = 44h - Contains the Map Handle Page function. - - AL = physical_page_number - Contains the number of the physical page into which the - logical page number is to be mapped. Physical pages are - numbered zero-relative. - - - - - EMM Functions 46 - - - - - - Function 5. Map/Unmap Handle Pages - - - - BX = logical_page_number - Contains the number of the logical page to be mapped at - the physical page within the page frame. Logical pages - are numbered zero-relative. The logical page must be in - the range zero through (number of pages allocated to the - EMM handle - 1). However, if BX contains logical page - number FFFFh, the physical page specified in AL will be - unmapped (be made inaccessible for reading or writing). - - DX = emm_handle - Contains the EMM handle your program received from - Function 4 (Allocate Pages). - - - REGISTERS MODIFIED - - AX - - - STATUS - - AH = 0 SUCCESSFUL. - The manager has mapped the page. The page is ready to - be accessed. - - AH = 80h NON-RECOVERABLE. - The manager detected a malfunction in the memory manager - software. - - AH = 81h NON-RECOVERABLE. - The manager detected a malfunction in the expanded - memory hardware. - - AH = 83h NON-RECOVERABLE. - The memory manager couldn't find the EMM handle your - program specified. - - AH = 84h NON-RECOVERABLE. - The function code passed to the memory manager isn't - defined. - - AH = 8Ah RECOVERABLE. - The logical page is out of the range of logical pages - which are allocated to the EMM handle. This status is - also returned if a program attempts to map a logical - page when no logical pages are allocated to the handle. - - - - EMM Functions 47 - - - - - - Function 5. Map/Unmap Handle Pages - - - - AH = 8Bh RECOVERABLE. - The physical page number is out of the range of allow- - able physical pages. The program can recover by - attempting to map into memory at a physical page which - is within the range of allowable physical pages. - - - EXAMPLE - - emm_handle DW ? - logical_page_number DW ? - physical_page_number DB ? - - MOV DX,emm_handle ; load EMM handle - MOV BX,logical_page_number ; load logical page number - MOV AL,physical_page_number ; load physical page number - MOV AH,44h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EMM Functions 48 - - - - - - Function 6. Deallocate Pages - - - - PURPOSE - - Deallocate Pages deallocates the logical pages currently - allocated to an EMM handle. Only after the application - deallocates these pages can other applications use them. - When a handle is deallocated, its name is set to all ASCII - nulls (binary zeros). - - Note............................................................ - A program must perform this function before it exits to DOS. - If it doesn't, no other programs can use these pages or the - EMM handle. This means that a program using expanded memory - should trap critical errors and control-break if there is a - chance that the program will have allocated pages when - either of these events occur. - - - CALLING PARAMETERS - - AH = 45h - Contains the Deallocate Pages function. - - DX = handle - Contains the EMM handle returned by Function 4 (Allocate - Pages). - - - REGISTERS MODIFIED - - AX - - - STATUS - - AH = 0 SUCCESSFUL. - The manager has deallocated the pages previously allo- - cated to the EMM handle. - - AH = 80h NON-RECOVERABLE. - The manager detected a malfunction in the memory manager - software. - - AH = 81h NON-RECOVERABLE. - The manager detected a malfunction in the expanded - memory hardware. - - AH = 83h NON-RECOVERABLE. - The manager couldn't find the specified EMM handle. - - EMM Functions 49 - - - - - - Function 6. Deallocate Pages - - - - AH = 84h NON-RECOVERABLE. - The function code passed to the memory manager is not - defined. - - AH = 86h RECOVERABLE. - The memory manager detected a save or restore page - mapping context error (Function 8 or 9). There is a - page mapping register state in the save area for the - specified EMM handle. Save Page Map (Function 8) placed - it there and a subsequent Restore Page Map (Function 9) - has not removed it. - - If you have saved the mapping context, you must restore - it before you deallocate the EMM handle's pages. - - - EXAMPLE - - emm_handle DW ? - - MOV DX,emm_handle ; load EMM handle - MOV AH,45h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - - - - - - - - - - - - - - - - - - - - - - - - - EMM Functions 50 - - - - - - Function 7. Get Version - - - - PURPOSE - - The Get Version function returns the version number of the - memory manager software. - - - CALLING PARAMETERS - - AH = 46h - Contains the Get Version function. - - - RESULTS - - These results are valid only if the status returned is zero. - - AL = version number - Contains the memory manager's version number in binary - coded decimal (BCD) format. The upper four bits contain - the integer digit of the version number. The lower four - bits contain the fractional digit of version number. - For example, version 4.0 is represented like this: - - 0100 0000 - / \ - 4 . 0 - - When checking for a version number, an application - should check for a version number or greater. Vendors - may use the fractional digit to indicate enhancements or - corrections to their memory managers. Therefore, to - allow for future versions of memory managers, an - application shouldn't depend on an exact version number. - - - REGISTERS MODIFIED - - AX - - - STATUS - - AH = 0 SUCCESSFUL. - The manager is present in the system and the hardware is - working correctly. - - - - - EMM Functions 51 - - - - - - Function 7. Get Version - - - - AH = 80h NON-RECOVERABLE. - The manager detected a malfunction in the memory manager - software. - - AH = 81h NON-RECOVERABLE. - The manager detected a malfunction in the expanded - memory hardware. - - AH = 84h NON-RECOVERABLE. - The function code passed to the memory manager is not - defined. - - - EXAMPLE - - emm_version DB ? - - MOV AH,46h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - MOV emm_version,AL ; save version number - - - - - - - - - - - - - - - - - - - - - - - - - - - - EMM Functions 52 - - - - - - Function 8. Save Page Map - - - - PURPOSE - - Save Page Map saves the contents of the page mapping - registers on all expanded memory boards in an internal save - area. The function is typically used to save the memory - mapping context of the EMM handle that was active when a - software or hardware interrupt occurred. (See Function 9, - Restore Page Map, for the restore operation.) - - If you're writing a resident program, an interrupt service - routine, or a device driver that uses expanded memory, you - must save the state of the mapping hardware. You must save - this state because application software using expanded - memory may be running when your program is invoked by a - hardware interrupt, a software interrupt, or DOS. - - The Save Page Map function requires the EMM handle that was - assigned to your resident program, interrupt service - routine, or device driver at the time it was initialized. - This is not the EMM handle that the application software was - using when your software interrupted it. - - The Save Page Map function saves the state of the map - registers for only the 64K-byte page frame defined in - versions 3.x of this specification. Since all applications - written to LIM versions 3.x require saving the map register - state of only this 64K-byte page frame, saving the entire - mapping state for a large number of mappable pages would be - inefficient use of memory. Applications that use a mappable - memory region outside the LIM 3.x page frame should use - Function 15 or 16 to save and restore the state of the map - registers. - - - CALLING PARAMETERS - - AH = 47h - Contains the Save Page Map function. - - DX = handle - Contains the EMM handle assigned to the interrupt - service routine that's servicing the software or - hardware interrupt. The interrupt service routine needs - to save the state of the page mapping hardware before - mapping any pages. - - - - - EMM Functions 53 - - - - - - Function 8. Save Page Map - - - - REGISTERS MODIFIED - - AX - - - STATUS - - AH = 0 SUCCESSFUL. - The manager has saved the state of the page mapping - hardware. - - AH = 80h NON-RECOVERABLE. - The manager detected a malfunction in the memory manager - software. - - AH = 81h NON-RECOVERABLE. - The manager detected a malfunction in the expanded - memory hardware. - - AH = 83h NON-RECOVERABLE. - The memory manager couldn't find the EMM handle your - program specified. - - AH = 84h NON-RECOVERABLE. - The function code passed to the memory manager is not - defined. - - AH = 8Ch NON-RECOVERABLE. - There is no room in the save area to store the state of - the page mapping registers. The state of the map - registers has not been saved. - - AH = 8Dh CONDITIONALLY-RECOVERABLE. - The save area already contains the page mapping register - state for the EMM handle your program specified. - - - EXAMPLE - - emm_handle DW ? - - MOV DX,emm_handle ; load EMM handle - MOV AH,47h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - - - - EMM Functions 54 - - - - - - Function 9. Restore Page Map - - - - PURPOSE - - The Restore Page Map function restores the page mapping - register contents on the expanded memory boards for a - particular EMM handle. This function lets your program - restore the contents of the mapping registers its EMM handle - saved. (See Function 8, Save Page Map for the save opera- - tion.) - - If you're writing a resident program, an interrupt service - routine, or a device driver that uses expanded memory, you - must restore the mapping hardware to the state it was in - before your program took over. You must save this state - because application software using expanded memory might - have been running when your program was invoked. - - The Restore Page Map function requires the EMM handle that - was assigned to your resident program, interrupt service - routine, or device driver at the time it was initialized. - This is not the EMM handle that the application software was - using when your software interrupted it. - - The Restore Page Map function restores the state of the map - registers for only the 64K-byte page frame defined in - versions 3.x of this specification. Since all applications - written to LIM versions 3.x require restoring the map - register state of only this 64K-byte page frame, restoring - the entire mapping state for a large number of mappable - pages would be inefficient use of memory. Applications that - use a mappable memory region outside the LIM 3.x page frame - should use Function 15 or 16 to save and restore the state - of the map registers. - - - CALLING PARAMETERS - - AH = 48h - Contains the Restore Page Map function. - - DX = emm_handle - Contains the EMM handle assigned to the interrupt - service routine that's servicing the software or - hardware interrupt. The interrupt service routine needs - to restore the state of the page mapping hardware. - - - - - - EMM Functions 55 - - - - - - Function 9. Restore Page Map - - - - REGISTERS MODIFIED - - AX - - - STATUS - - AH = 0 SUCCESSFUL. - The manager has restored the state of the page mapping - registers. - - AH = 80h NON-RECOVERABLE. - The manager detected a malfunction in the memory manager - software. - - AH = 81h NON-RECOVERABLE. - The manager detected a malfunction in the expanded - memory hardware. - - AH = 83h NON-RECOVERABLE. - The memory manager couldn't find the EMM handle your - program specified. - - AH = 84h NON-RECOVERABLE. - The function code passed to the memory manager is not - defined. - - AH = 8Eh CONDITIONALLY-RECOVERABLE. - There is no page mapping register state in the save area - for the specified EMM handle. Your program didn't save - the contents of the page mapping hardware, so Restore - Page can't restore it. - - - EXAMPLE - - emm_handle DW ? - - MOV DX,emm_handle ; load EMM handle - MOV AH,48h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - - - - - - - EMM Functions 56 - - - - - - Function 10. Reserved - - - - In earlier versions of the Lotus/Intel/Microsoft Expanded - Memory Specification, Function 10 returned the page mapping - register I/O array. This function is now reserved and new - programs should not use it. - - Existing programs that use this function may still work - correctly if the hardware is capable of supporting them. - However, programs that use Functions 16 through 30 in - Version 4.0 of this specification must not use Functions 10 - and 11. These functions won't work correctly if your - program attempts to mix the use of the new functions - (Functions 16 through 30) and Functions 10 and 11. Func- - tions 10 and 11 are specific to the hardware on Intel - expanded memory boards and will not work correctly on all - vendors' expanded memory boards. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EMM Functions 57 - - - - - - Function 11. Reserved - - - - In earlier versions of the Lotus/Intel/Microsoft Expanded - Memory Specification, Function 11 returned a page transla- - tion array. This function is now reserved and new programs - should not use it. - - Existing programs that use this function may still work - correctly if the hardware is capable of supporting them. - However, programs that use Functions 16 through 30 in - Version 4.0 of this specification must not use Functions 10 - and 11. These functions won't work correctly if your - program attempts to mix the use of the new functions - (Functions 16 through 30) and Functions 10 and 11. Func- - tions 10 and 11 are specific to the hardware on Intel - expanded memory boards and will not work correctly on all - vendors' expanded memory boards. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EMM Functions 58 - - - - - - Function 12. Get Handle Count - - - - PURPOSE - - The Get Handle Count function returns the number of open EMM - handles (including the operating system handle 0) in the - system. - - - CALLING PARAMETERS - - AH = 4Bh - Contains the Get Handle Count function. - - - RESULTS - - These results are valid only if the status returned is zero. - - BX = total_open_emm_handles - Contains the number of open EMM handles [including the - operating system handle (0)]. This number will not - exceed 255. - - - REGISTERS MODIFIED - - AX, BX - - - STATUS - - AH = 0 SUCCESSFUL. - The manager has returned the number of active EMM - handles. - - AH = 80h NON-RECOVERABLE. - The manager detected a malfunction in the memory manager - software. - - AH = 81h NON-RECOVERABLE. - The manager detected a malfunction in the expanded - memory hardware. - - AH = 84h NON-RECOVERABLE. - The function code passed to the memory manager is not - defined. - - - - - EMM Functions 59 - - - - - - Function 12. Get Handle Count - - - - EXAMPLE - - total_open_emm_handles DW ? - - MOV AH,4Bh ; load function code - INT 67h ; call the memory manger - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on - ; error - MOV total_open_emm_handles,BX ; save total active handle - ; count - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EMM Functions 60 - - - - - - Function 13. Get Handle Pages - - - - PURPOSE - - The Get Handle Pages function returns the number of pages - allocated to a specific EMM handle. - - - CALLING PARAMETERS - - AH = 4Ch - Contains the Get Handle Pages function. - - DX = emm_handle - Contains the EMM handle. - - - RESULTS - - These results are valid only if the status returned is zero. - - BX = num_pages_alloc_to_emm_handle - Contains the number of logical pages allocated to the - specified EMM handle. This number never exceeds 2048 - because the memory manager allows a maximum of 2048 - pages (32M bytes) of expanded memory. - - - REGISTERS MODIFIED - - AX, BX - - - STATUS - - AH = 0 SUCCESSFUL. - The manager has returned the number of pages allocated - to the EMM handle. - - AH = 80h NON-RECOVERABLE. - The manager detected a malfunction in the memory manager - software. - - AH = 81h NON-RECOVERABLE. - The manager detected a malfunction in the expanded - memory hardware. - - AH = 83h NON-RECOVERABLE. - The memory manager couldn't find the EMM handle your - program specified. - - EMM Functions 61 - - - - - - Function 13. Get Handle Pages - - - - AH = 84h NON-RECOVERABLE. - The function code passed to the memory manager is not - defined. - - - EXAMPLE - - emm_handle DW ? - pages_alloc_to_handle DW ? - - MOV DX,emm_handle ; load EMM handle - MOV AH,4Ch ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on - ; error - MOV pages_alloc_to_handle,BX ; save number of pages - ; allocated to specified - ; handle - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EMM Functions 62 - - - - - - Function 14. Get All Handle Pages - - - - PURPOSE - - The Get All Handle Pages function returns an array of the - open EMM handles and the number of pages allocated to each - one. - - - CALLING PARAMETERS - - AH = 4Dh - Contains the Get All Handle Pages function. - - handle_page_struct STRUC - emm_handle DW ? - pages_alloc_to_handle DW ? - handle_page_struct ENDS - - ES:DI = pointer to handle_page - Contains a pointer to an array of structures where a - copy of all open EMM handles and the number of pages - allocated to each will be stored. Each structure has - these two members: - - .emm_handle - The first member is a word which contains the value - of the open EMM handle. The values of the handles - this function returns will be in the range of 0 to - 255 decimal (0000h to 00FFh). The uppermost byte of - the handle is always zero. - - .pages_alloc_to_handle - The second member is a word which contains the - number of pages allocated to the open EMM handle. - - - RESULTS - - These results are valid only if the status returned is zero. - - BX = total_open_emm_handles - Contains the number of open EMM handles (including the - operating system handle [0]). The number cannot be zero - because the operating system handle is always active and - cannot be deallocated. This number will not exceed 255. - - - - - - EMM Functions 63 - - - - - - Function 14. Get All Handle Pages - - - - REGISTERS MODIFIED - - AX, BX - - - STATUS - - AH = 0 SUCCESSFUL. - The manager has returned the array. - - AH = 80h NON-RECOVERABLE. - The manager detected a malfunction in the memory manager - software. - - AH = 81h NON-RECOVERABLE. - The manager detected a malfunction in the expanded - memory hardware. - - AH = 84h NON-RECOVERABLE. - The function code passed to the memory manager is not - defined. - - - EXAMPLE - - handle_page handle_page_struct 255 DUP (?) - total_open_handles DW ? - - MOV AX,SEG handle_page - MOV ES,AX - LEA DI,handle_page ; ES:DI points to handle_page - MOV AH,4Dh ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check the EMM status - JNZ emm_err_handler ; jump to error handler on error - MOV total_open_handles,BX ; save total open handle count - - - - - - - - - - - - - - EMM Functions 64 - - - - - - Function 15. Get/Set Page Map - Get Page Map subfunction - - - - PURPOSE - - The Get Page Map subfunction saves the mapping context for - all mappable memory regions (conventional and expanded) by - copying the contents of the mapping registers from each - expanded memory board to a destination array. The applica- - tion must pass a pointer to the destination array. This - subfunction doesn't require an EMM handle. - - Use this function instead of Functions 8 and 9 if you need - to save or restore the mapping context but don't want (or - have) to use a handle. - - - CALLING PARAMETERS - - AX = 4E00h - Contains the Get Page Map subfunction. - - ES:DI = dest_page_map - Contains a pointer to the destination array address in - segment:offset format. Use the Get Size of Page Map - Save Array subfunction to determine the size of the - desired array. - - - RESULTS - - These results are valid only if the status returned is zero. - - dest_page_map - The array contains the state of all the mapping regis- - ters on all boards in the system. It also contains any - additional information necessary to restore the boards - to their original state when the program invokes a Set - subfunction. - - - REGISTERS MODIFIED - - AX - - - STATUS - - AH = 0 SUCCESSFUL. - The manager has returned the array. - - EMM Functions 65 - - - - - - Function 15. Get/Set Page Map - Get Page Map subfunction - - - - AH = 80h NON-RECOVERABLE. - The manager detected a malfunction in the memory manager - software. - - AH = 81h NON-RECOVERABLE. - The manager detected a malfunction in the expanded - memory hardware. - - AH = 84h NON-RECOVERABLE. - The function code passed to the memory manager is not - defined. - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - - EXAMPLE - - dest_page_map DB ? DUP (?) - - MOV AX,SEG dest_page_map - MOV ES,AX - LEA DI,dest_page_map ; ES:DI points to dest_page_map - MOV AX,4E00h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - - - - - - - - - - - - - - - - - - - - - - EMM Functions 66 - - - - - - Function 15. Get/Set Page Map - Set Page Map subfunction - - - - PURPOSE - - The Set Page Map subfunction restores the mapping context - for all mappable memory regions (conventional and expanded) - by copying the contents of a source array into the mapping - registers on each expanded memory board in the system. The - application must pass a pointer to the source array. This - subfunction doesn't require an EMM handle. - - Use this function instead of Functions 8 and 9 if you need - to save or restore the mapping context but don't want (or - have) to use a handle. - - - CALLING PARAMETERS - - AX = 4E01h - Contains the Set Page Map subfunction. - - DS:SI = source_page_map - Contains a pointer to the source array address in - segment:offset format. The application must point to an - array which contains the mapping register state. Use - the Get Size of Page Map Save Array subfunction to - determine the size of the desired array. - - - REGISTERS MODIFIED - - AX - - - STATUS - - AH = 0 SUCCESSFUL. - The manager has passed the array. - - AH = 80h NON-RECOVERABLE. - The manager detected a malfunction in the memory manager - software. - - AH = 81h NON-RECOVERABLE. - The manager detected a malfunction in the expanded - memory hardware. - - - - - EMM Functions 67 - - - - - - Function 15. Get/Set Page Map - Set Page Map subfunction - - - - AH = 84h NON-RECOVERABLE. - The function code passed to the memory manager is not - defined. - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - AH = A3h NON-RECOVERABLE. - The contents of the source array have been corrupted, or - the pointer passed to the subfunction is invalid. - - - EXAMPLE - - source_page_map DB ? DUP (?) - - MOV AX,SEG source_page_map - MOV DS,AX - LEA SI,source_page_map ; DS:SI points to source_page_map - MOV AX,4E01h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - - - - - - - - - - - - - - - - - - - - - - - - - - EMM Functions 68 - - - - - - Function 15. Get/Set Page Map - Get & Set Page Map subfunction - - - - PURPOSE - - The Get & Set Page Map subfunction simultaneously saves a - current mapping context and restores a previous mapping - context for all mappable memory regions (both conventional - and expanded). It first copies the contents of the mapping - registers from each expanded memory board in the system into - a destination array. (The application must pass a pointer - to the destination array.) Then, the subfunction copies the - contents of a source array into the mapping registers on - each of the expanded memory boards. (The application must - pass a pointer to the source array.) - - Use this function instead of Functions 8 and 9 if you need - to save or restore the mapping context but don't want (or - have) to use a handle. - - - CALLING PARAMETERS - - AX = 4E02h - Contains the Get & Set Page Map subfunction. - - ES:DI = dest_page_map - Contains a pointer to the destination array address in - segment:offset format. The current contents of the map - registers will be saved in this array. - - DS:SI = source_page_map - Contains a pointer to the source array address in - segment:offset format. The contents of this array will - be copied into the map registers. The application must - point to an array which contains the mapping register - state. This address is required only for the Set or Get - and Set subfunctions. - - - RESULTS - - These results are valid only if the status returned is zero. - - dest_page_map - The array contains the mapping state. It also contains - any additional information necessary to restore the - original state when the program invokes a Set subfunc- - tion. - - - EMM Functions 69 - - - - - - Function 15. Get/Set Page Map - Get & Set Page Map subfunction - - - - REGISTERS MODIFIED - - AX - - - STATUS - - AH = 0 SUCCESSFUL. - The manager has returned and passed both arrays. - - AH = 80h NON-RECOVERABLE. - The manager detected a malfunction in the memory manager - software. - - AH = 81h NON-RECOVERABLE. - The manager detected a malfunction in the expanded - memory hardware. - - AH = 84h NON-RECOVERABLE. - The function code passed to the memory manager is not - defined. - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - AH = A3h NON-RECOVERABLE. - The contents of the source array have been corrupted, or - the pointer passed to the subfunction is invalid. - - - EXAMPLE - - dest_page_map DB ? DUP (?) - - source_page_map DB ? DUP (?) - - MOV AX,SEG dest_page_map - MOV ES,AX - MOV AX,SEG source_page_map - MOV DS,AX - LEA DI,dest_page_map ; ES:DI points to dest_page_map - LEA SI,source_page_map ; DS:SI points to source_page_map - MOV AX,4E02h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - - - EMM Functions 70 - - - - - - Function 15. Get/Set Page Map - Get Size of Page Map Save Array subfunction - - - - PURPOSE - - The Get Size of Page Map Save Array subfunction returns the - storage requirements for the array passed by the other three - subfunctions. This subfunction doesn't require an EMM - handle. - - - CALLING PARAMETERS - - AX = 4E03h - Contains the Get Size of Page Map Save Array subfunc- - tion. The size of this array depends on how the - expanded memory system is configured and how the - expanded memory manager is implemented. Therefore, the - size must be determined after the memory manager is - loaded. - - - RESULTS - - These results are valid only if the status returned is zero. - - AL = size_of_array - Contains the number of bytes that will be transferred to - the memory area an application supplies whenever a - program requests the Get, Set, or Get and Set subfunc- - tions. - - - REGISTERS MODIFIED - - AX - - - STATUS - - AH = 0 SUCCESSFUL. - The manager has returned the array size. - - AH = 80h NON-RECOVERABLE. - The manager detected a malfunction in the memory manager - software. - - AH = 81h NON-RECOVERABLE. - The manager detected a malfunction in the expanded - memory hardware. - - EMM Functions 71 - - - - - - Function 15. Get/Set Page Map - Get Size of Page Map Save Array subfunction - - - - AH = 84h NON-RECOVERABLE. - The function code passed to the memory manager is not - defined. - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - - EXAMPLE - - size_of_array DB ? - - MOV AX,4E03h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - MOV size_of_array,AL ; save array size - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EMM Functions 72 - - - - - - Function 16. Get/Set Partial Page Map - Get Partial Page Map subfunction - - - - PURPOSE - - The Get Partial Page Map subfunction saves a partial mapping - context for specific mappable memory regions in a system. - Because this function saves only a subset of the entire - mapping context, it uses much less memory for the save area - and may be potentially faster than Function 15. The - subfunction does this by copying the contents of selected - mapping registers from each expanded memory board to a - destination array. - - The application must pass a pair of pointers. The first - points to a structure which specifies which mappable - segments to save; the second points to the destination - array. - - Use this function instead of Functions 8 and 9 if you need - to save or restore the mapping context but don't want (or - have) to use a handle. - - - CALLING PARAMETERS - - AX = 4F00h - Contains the Get Partial Page Map subfunction. - - partial_page_map_struct STRUC - mappable_segment_count DW ? - mappable_segment DW (?) DUP (?) - partial_page_map_struct ENDS - - DS:SI = partial_page_map - Contains a pointer to a structure which specifies only - those mappable memory regions which are to have their - mapping context saved. The structure members are - described below. - - .mappable_segment_count - The first member is a word which specifies the - number of members in the word array which immediate- - ly follows it. This number should not exceed the - number of mappable segments in the system. - - - - - - - EMM Functions 73 - - - - - - Function 16. Get/Set Partial Page Map - Get Partial Page Map subfunction - - - - .mappable_segment - The second member is a word array which contains the - segment addresses of the mappable memory regions - whose mapping contexts are to be saved. The segment - address must be a mappable segment. Use Function 25 - to determine which segments are mappable. - - ES:DI = dest_array - Contains a pointer to the destination array address in - segment:offset format. To determine the size of the - required array, see the Get Size of Partial Page Map - Save Array subfunction. - - - RESULTS - - These results are valid only if the status returned is zero. - - dest_array - The array contains the partial mapping context and any - additional information necessary to restore this context - to its original state when the program invokes a Set - subfunction. - - - REGISTERS MODIFIED - - AX - - - STATUS - - AH = 0 SUCCESSFUL. - The manager has saved the partial map context. - - AH = 80h NON-RECOVERABLE. - The manager detected a malfunction in the memory manager - software. - - AH = 81h NON-RECOVERABLE. - The manager detected a malfunction in the expanded - memory hardware. - - AH = 84h NON-RECOVERABLE. - The function code passed to the memory manager is not - defined. - - - EMM Functions 74 - - - - - - Function 16. Get/Set Partial Page Map - Get Partial Page Map subfunction - - - - AH = 8Bh NON-RECOVERABLE. - One of the specified segments is not a mappable segment. - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - AH = A3h NON-RECOVERABLE. - The contents of the partial page map structure have been - corrupted, the pointer passed to the subfunction is - invalid, or the mappable_segment_count exceeds the - number of mappable segments in the system. - - - EXAMPLE - - partial_page_map partial_page_map_struct <> - - dest_array DB ? DUP (?) - - MOV AX,SEG partial_page_map - MOV DS,AX - LEA SI,partial_page_map ; DS:SI points to partial_page_map - MOV AX,SEG dest_array - MOV ES,AX - LEA DI,dest_array ; ES:DI points to dest_array - MOV AX,4F00h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - - - - - - - - - - - - - - - - - - - - EMM Functions 75 - - - - - - Function 16. Get/Set Partial Page Map - Set Partial Page Map subfunction - - - - PURPOSE - - The Set Partial Page Map subfunction provides a mechanism - for restoring the mapping context for a partial mapping - context for specific mappable memory regions in a system. - Because this function restores only a subset of the entire - mapping context and not the entire systems mapping context, - it uses much less memory for the save area and is potential- - ly faster than Function 15. The subfunction does this by - copying the contents of the source array to selected mapping - registers on each expanded memory board. The application - passes a pointer to the source array. - - Use this function instead of Functions 8 and 9 if you need - to save or restore the mapping context but don't want (or - have) to use a handle. - - - CALLING PARAMETERS - - AX = 4F01h - Contains the Set Partial Page Map subfunction - - source_array DB ? DUP (?) - - DS:SI = source_array - Contains a pointer to the source array in segment:offset - format. The application must point to an array which - contains the partial mapping register state. To deter- - mine the size of the required array, see the Get Size of - Partial Page Map Save Array subfunction. - - - REGISTERS MODIFIED - - AX - - - STATUS - - AH = 0 SUCCESSFUL. - The manager has restored the partial mapping context. - - AH = 80h NON-RECOVERABLE. - The manager detected a malfunction in the memory manager - software. - - - EMM Functions 76 - - - - - - Function 16. Get/Set Partial Page Map - Set Partial Page Map subfunction - - - - AH = 81h NON-RECOVERABLE. - The manager detected a malfunction in the expanded - memory hardware. - - AH = 84h NON-RECOVERABLE. - The function code passed to the memory manager is not - defined. - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - AH = A3h NON-RECOVERABLE. - The contents of the source array have been corrupted, or - the pointer passed to the subfunction is invalid. - - - EXAMPLE - - MOV AX,SEG source_array - MOV DS,AX - LEA SI,source_array ; DS:SI points to source_array - MOV AX,4F01h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - - - - - - - - - - - - - - - - - - - - - - - - EMM Functions 77 - - - - - - Function 16. Get/Set Partial Page Map - Get Size of Partial Page Map Save Array subfunction - - - - PURPOSE - - The Get Size of Partial Page Map Save Array subfunction - returns the storage requirements for the array passed by the - other two subfunctions. This subfunction doesn't require an - EMM handle. - - - CALLING PARAMETERS - - AX = 4F02h - Contains the Get Size of Partial Page Map Save Array - subfunction. The size of this array depends on the - expanded memory system configuration and the implementa- - tion of the expanded memory manager. Therefore, it will - vary between hardware configurations and implementations - and must be determined after a specific memory manager - is loaded. - - BX = number of pages in the partial array - Contains the number of pages in the partial map to be - saved by the Get/Set Partial Page Map subfunctions. - This number should be the same as the mappable_seg- - ment_count in the Get Partial Page Map subfunction. - - - RESULTS - - These results are valid only if the status returned is zero. - - AL = size_of_partial_save_array - Contains the number of bytes that will be transferred to - the memory areas supplied by an application whenever a - program requests the Get or Set subfunction. - - - REGISTERS MODIFIED - - AX - - - STATUS - - AH = 0 SUCCESSFUL. - The manager has returned the array size. - - - - EMM Functions 78 - - - - - - Function 16. Get/Set Partial Page Map - Get Size of Partial Page Map Save Array subfunction - - - - AH = 80h NON-RECOVERABLE. - The manager detected a malfunction in the memory manager - software. - - AH = 81h NON-RECOVERABLE. - The manager detected a malfunction in the expanded - memory hardware. - - AH = 84h NON-RECOVERABLE. - The function code passed to the memory manager is not - defined. - - AH = 8Bh NON-RECOVERABLE. - The number of pages in the partial array is outside the - range of physical pages in the system. - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - - EXAMPLE - - number_of_pages_to_map DW ? - size_of_partial_save_array DB ? - - MOV BX,number_of_pages_to_map - MOV AX,4F02h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on - ; error - MOV size_of_partial_save_array,AL ; save array size - - - - - - - - - - - - - - - - - EMM Functions 79 - - - - - - Function 17. Map/Unmap Multiple Handle Pages - - - - PURPOSE - - This function can, in a single invocation, map (or unmap) - logical pages into as many physical pages as the system - supports. Consequently, it has less execution overhead than - mapping pages one at a time. For applications which do a - lot of page mapping, this is the preferred mapping method. - - - Mapping Multiple Pages - - The handle passed to this function determines what type of - logical pages are being mapped. Logical pages that Function - 4 and Function 27 (Allocate Standard Pages subfunction) - allocate are referred to as pages and are 16K bytes. - Logical pages that Function 27 (Allocate Raw Pages subfunc- - tion) allocates are referred to as raw pages and might not - be the same size as the pages Function 4 and Function 27 - (Allocate Standard Pages subfunction) allocate. - - - Unmapping Multiple Pages - - This function can make specific physical pages unavailable - for reading or writing. A logical page which is unmapped - from a specific physical page cannot be read or written from - that physical page. The logical page which is unavailable - (unmapped) can be made available again by mapping it, or a - new logical page, at the physical page that was unmapped. - Unmapping a physical page is accomplished by setting the - logical page it is associated with to FFFFh. - - You might unmap an entire set of mapped pages, for example, - before loading and executing a program. This ensures that - the loaded program won't be able to access the pages your - program has mapped. However, you must save the mapping - context before you unmap the physical pages. This enables - you to restore it later so that you may access the memory - you had mapped there. You can save the mapping context with - Functions 8, 15, or 16. You can restore the mapping context - with Functions 9, 15, or 16. - - - Mapping and Unmapping Multiple Pages Simultaneously - - Both mapping and unmapping pages can be done in the same - invocation. - - - EMM Functions 80 - - - - - - Function 17. Map/Unmap Multiple Handle Pages - - - - Mapping or unmapping no pages is not considered an error. - If a request to map or unmap zero pages is made, nothing is - done and no error is returned. - - - Alternate Mapping and Unmapping Methods - - You can map or unmap pages using two methods. Both methods - produce identical results. - - 1. The first method specifies both a logical page and a - physical page at which the logical page is to be mapped. - This method is an extension of Function 5 (Map Handle - Page). - - 2. The second method specifies both a logical page and a - corresponding segment address at which the logical page - is to be mapped. While this is functionally the same as - the first method, it may be easier to use the actual - segment address of a physical page than to use a number - which only represents its location. The memory manager - verifies whether the specified segment address falls on - the boundary of a mappable physical page. The manager - then translates the segment address passed to it into - the necessary internal representation to map the pages. - - - - - - - - - - - - - - - - - - - - - - - - - EMM Functions 81 - - - - - - Function 17. Map/Unmap Multiple Handle Pages - Logical Page/Physical Page Method - - - CALLING PARAMETERS - - AX = 5000h - Contains the Map/Unmap Multiple Handle Pages subfunction - using the logical page/physical page method. - - log_to_phys_map_struct STRUC - log_page_number DW ? - phys_page_number DW ? - log_to_phys_map_struct ENDS - - DX = handle - Contains the EMM handle. - - CX = log_to_phys_map_len - Contains the number of entries in the array. For - example, if the array contained four pages to map or - unmap, then CX would contain 4. The number in CX should - not exceed the number of mappable pages in the system. - - DS:SI = pointer to log_to_phys_map array - Contains a pointer to an array of structures that - contains the information necessary to map the desired - pages. The array is made up of the following two - elements: - - .log_page_number - The first member is a word which contains the number - of the logical page which is to be mapped. Logical - pages are numbered zero-relative, so the number for - a logical page can only range from zero to (maximum - number of logical pages allocated to the handle - - 1). - - If the logical page number is set to FFFFh, the - physical page associated with it is unmapped rather - than mapped. Unmapping a physical page makes it - inaccessible for reading or writing. - - .phys_page_number - The second member is a word which contains the - number of the physical page at which the logical - page is to be mapped. Physical pages are numbered - zero-relative, so the number for a physical page can - only range from zero to (maximum number of physical - pages supported in the system - 1). - - - - EMM Functions 82 - - - - - - Function 17. Map/Unmap Multiple Handle Pages - Logical Page/Physical Page Method - - - - REGISTERS MODIFIED - - AX - - - STATUS - - AH = 0 SUCCESSFUL. - The logical pages have been mapped, or unmapped, at the - specified physical pages. - - AH = 80h NON-RECOVERABLE. - The manager has detected a malfunction in the memory - manager software. - - AH = 81h NON-RECOVERABLE. - The manager has detected a malfunction in the expanded - memory hardware. - - AH = 83h NON-RECOVERABLE. - The manager couldn't find the specified EMM handle. The - manager doesn't currently have any information pertain- - ing to the specified EMM handle. The program has - probably corrupted its EMM handle. - - AH = 84h NON-RECOVERABLE. - The function code passed to the manager is not defined. - - AH = 8Ah RECOVERABLE. - One or more of the mapped logical pages is out of the - range of logical pages allocated to the EMM handle. The - program can recover by attempting to map a logical page - which is within the bounds for the specified EMM handle. - When this error occurs, the only pages mapped were the - ones valid up to the point that the error occurred. - - AH = 8Bh RECOVERABLE. - One or more of the physical pages is out of the range of - mappable physical pages, or the log_to_phys_map_len - exceeds the number of mappable pages in the system. The - program can recover from this condition by attempting to - map into memory at the physical page which is in the - range of the physical page numbers supported by the - system. When this error occurs, the only pages mapped - were the ones valid up to the point that the error - occurred. - - - EMM Functions 83 - - - - - - Function 17. Map/Unmap Multiple Handle Pages - Logical Page/Physical Page Method - - - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - - EXAMPLE - - log_to_phys_map log_to_phys_map_struct ? DUP (?) - - emm_handle DW ? - - MOV AX,SEG log_to_phys_map - MOV DS,AX - LEA SI,log_to_phys_map ; DS:SI points to - ; log_to_phys_map - MOV CX,LENGTH log_to_phys_map ; set length field - MOV DX,emm_handle - MOV AX,5000h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on - ; error - - - - - - - - - - - - - - - - - - - - - - - - - - - - EMM Functions 84 - - - - - - Function 17. Map/Unmap Multiple Handle Pages - Logical Page/Segment Address Method - - - CALLING PARAMETERS - - AX = 5001h - Contains the Map/Unmap Multiple Handle Pages subfunction - using the logical page/segment address method. - - log_to_seg_map_struct STRUC - log_page_number DW ? - mappable_segment_address DW ? - log_to_seg_map_struct ENDS - - DX = handle - Contains the EMM handle. - - CX = log_to_segment_map_len - Contains the number of entries in the array. For - example, if the array contained four pages to map or - unmap, then CX would contain four. - - DS:SI = pointer to log_to_segment_map array - Contains a pointer to an array of structures that - contains the information necessary to map the desired - pages. The array is made up of the following elements: - - .log_page_number - The first member is a word which contains the number - of the logical pages to be mapped. Logical pages - are numbered zero-relative, so the number for a - logical page can range from zero to (maximum number - of logical pages allocated to the handle - 1). - - If the logical page number is set to FFFFh, the - physical page associated with it is unmapped rather - than mapped. Unmapping a physical page makes it - inaccessible for reading or writing. - - .mappable_segment_address - The second member is a word which contains the - segment address at which the logical page is to be - mapped. This segment address must correspond - exactly to a mappable segment address. The mappable - segment addresses are available with Function 25 - (Get Mappable Physical Address Array). - - - REGISTERS MODIFIED - - AX - - EMM Functions 85 - - - - - - Function 17. Map/Unmap Multiple Handle Pages - Logical Page/Segment Address Method - - - - STATUS - - AH = 0 SUCCESSFUL. - The logical pages have been mapped (or unmapped) at the - specified physical pages. - - AH = 80h NON-RECOVERABLE. - The manager has detected a malfunction in the memory - manager software. - - AH = 81h NON-RECOVERABLE. - The manager has detected a malfunction in the expanded - memory hardware. - - AH = 83h NON-RECOVERABLE. - The manager could not find the specified EMM handle. - The manager doesn't currently have any information - pertaining to the specified EMM handle. The program has - probably corrupted its EMM handle. - - AH = 84h NON-RECOVERABLE. - The function code passed to the manager is not defined. - - AH = 8Ah RECOVERABLE. - One or more of the logical pages to be mapped is out of - the range of logical pages allocated to the EMM handle. - The program can recover from this condition by mapping a - logical page which is within the bounds for the speci- - fied EMM handle. When this error occurs, the only pages - mapped or unmapped were the ones valid up to the point - that the error occurred. - - AH = 8Bh RECOVERABLE. - One or more of the mappable segment addresses specified - is not mappable, the segment address doesn't fall - exactly on a mappable address boundary, or the log_to_- - segment_map_len exceeds the number of mappable segments - in the system. The program can recover from this - condition by mapping into memory on an exact mappable - segment address. When this error occurs, the only pages - mapped were the ones valid up to the point that the - error occurred. - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - - - EMM Functions 86 - - - - - - Function 17. Map/Unmap Multiple Handle Pages - Logical Page/Segment Address Method - - - - EXAMPLE - - log_to_seg_map log_to_seg_map_struct 4 DUP (?) - - emm_handle DW ? - - MOV AX,SEG log_to_seg_map - MOV DS,AX - LEA SI,log_to_seg_map ; DS:SI points to - ; log_to_seg_map - MOV CX,LENGTH log_to_seg_map - MOV DX,emm_handle - MOV AX,5001h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on - ; error - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EMM Functions 87 - - - - - - Function 18. Reallocate Pages - - - - PURPOSE - - This function allows an application program to increase or - decrease (reallocate) the number of logical pages allocated - to an EMM handle. There are four reallocation cases of - interest: - - 1. A reallocation count of zero. The handle assigned to - the application remains assigned and is still available - for use by the application. The memory manager won't - reassign the handle to any other application. However, - the handle will have any currently allocated pages - returned to the memory manager. The application must - invoke the Deallocate Pages function (Function 6) before - returning to DOS, or the handle will remain assigned and - no other application will be able to use it. - - 2. A reallocation count equal to the current allocation - count. This is not treated as an error, and a success- - ful status is returned. - - 3. A reallocation count greater than the current allocation - count. The memory manager will attempt to add new pages - to those pages already allocated to the specified EMM - handle. The number of new pages added is the difference - between the reallocation count and the current alloca- - tion count. The sequence of logical pages allocated to - the EMM handle remains continuous after this operation. - The newly allocated pages have logical page numbers - which begin where the previously allocated pages ended, - and continue in ascending sequence. - - 4. A reallocation count less than the current allocation - count. The memory manager will attempt to subtract some - of the currently allocated pages and return them to the - memory manager. The number of old pages subtracted is - the difference between the current allocation count and - the re-allocation count. The pages are subtracted from - the end of the sequence of pages currently allocated to - the specified EMM handle. The sequence of logical pages - allocated to the EMM handle remains continuous after - this operation. - - - - - - - - EMM Functions 88 - - - - - - Function 18. Reallocate Pages - - - - The handle determines what type of logical pages are being - reallocated. Logical pages which were originally allocated with - Function 4 or Function 27 (Allocate Standard Pages subfunction) - are called pages and are 16K bytes long. Logical pages which - were allocated with Function 27 (Allocate Raw Pages subfunction) - are called raw pages and might not be the same size as pages - allocated with Function 4. - - - CALLING PARAMETERS - - AH = 51h - Contains the Reallocate Handle Pages function. - - DX = handle - Contains the EMM handle. - - BX = reallocation_count - Contains the total number of pages this handle should - have allocated to it after this function is invoked. - - - RESULTS - - BX = number of pages allocated to handle after reallocation - Contains the number of pages now allocated to the EMM - handle after the pages have been added or subtracted. - If the status returned is not zero, the value in BX is - equal to the number of pages allocated to the handle - prior to the invocation of this function. This informa- - tion can be used to verify that the request generated - the expected results. - - - REGISTERS MODIFIED - - AX, BX - - - STATUS - - AH = 0 SUCCESSFUL. - The pages specified have been added to or subtracted - from the handle specified. - - AH = 80h NON-RECOVERABLE. - The manager has detected a malfunction in the memory - manager software. - - EMM Functions 89 - - - - - - Function 18. Reallocate Pages - - - - AH = 81h NON-RECOVERABLE. - The manager has detected a malfunction in the expanded - memory hardware. - - AH = 83h NON-RECOVERABLE. - The manager could not find the specified EMM handle. - The manager doesn't have any information pertaining to - the specified EMM handle. The program may have cor- - rupted its EMM handle. - - AH = 84h NON-RECOVERABLE. - The function code passed to the manager is not defined. - - AH = 87h RECOVERABLE. - The number of pages that are available in the system is - insufficient for the new allocation request. The - program can recover from this condition by specifying - fewer pages be allocated to the EMM handle. - - AH = 88h RECOVERABLE. - The number of unallocated pages is insufficient for the - new allocation request. The program can recover from - this condition by either requesting again when addition- - al pages are available or specifying fewer pages. - - - EXAMPLE - - emm_handle DW ? - realloc_count DW ? - current_alloc_page_count DW ? - - MOV DX,emm_handle ; specify EMM handle - MOV BX,realloc_count ; specify count - MOV AH,51h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on - ; error - MOV current_alloc_page_count,BX - - - - - - - - - - EMM Functions 90 - - - - - - Function 19. Get/Set Handle Attribute - - - - Design Considerations - - This function is an option which will probably not be - available in a typical expanded memory manager, system, or - memory board. Most personal computer systems disable memory - refresh signals for a considerable period during a warm - boot. This can corrupt some of the data in memory boards, - even though there is no problem with the design of the - memory board, its operation, or the memory chips. This - memory refresh deficiency is present in the software design - of the ROM BIOS in most personal computer systems. - - The majority of memory board designs, chip types, or - personal computer systems won't be able to support the non- - volatility feature. The reason that this ROM BIOS deficien- - cy is not evident in the conventional or extended memory - area is that the ROM BIOS always initializes this area - during a warm boot. Memory data integrity is not a problem - with the conventional or extended memory region, because it - isn't physically possible to have data retained there across - a warm boot event -- the ROM BIOS sets it to zero. - - Consequently, expanded memory board manufacturers should not - supply this function unless their board can guarantee the - integrity of data stored in the board's memory during a warm - boot. Generally, this means the memory board has an - independent memory refresh controller which does not depend - on the system board's memory refresh. - - If the expanded memory manager, system, or memory board - cannot support this feature, it should return the not - supported status described in the function. - - - - - - - - - - - - - - - - - - EMM Functions 91 - - - - - - Function 19. Get/Set Handle Attribute - Get Handle Attribute subfunction - - - - PURPOSE - - This subfunction returns the attribute associated with a - handle. The attributes are volatile or non-volatile. - Handles with non-volatile attributes enable the memory - manager to save the contents of a handle's pages between - warm boots. However, this function may be disabled with a - user option or may not be supported by the memory board or - system hardware. - - If the handle's attribute has been set to non-volatile, the - handle, its name (if it is assigned one), and the contents - of the pages allocated to the handle are all maintained - after a warm boot. - - - CALLING PARAMETERS - - AX = 5200h - Contains the Get Handle Attribute subfunction. - - DX = handle - Contains the EMM handle. - - - RESULTS - - These results are valid only if the status returned is zero. - - AL = handle attribute - Contains the EMM handle's attribute. The only at- - tributes a handle may have are volatile or non-volatile. - A value of zero indicates the handle is volatile. A - value of one indicates that the handle is non-volatile. - - - REGISTERS MODIFIED - - AX - - - STATUS - - AH = 0 SUCCESSFUL. - The handle's attribute has been obtained. - - - - EMM Functions 92 - - - - - - Function 19. Get/Set Handle Attribute - Get Handle Attribute subfunction - - - - AH = 80h NON-RECOVERABLE. - The manager has detected a malfunction in the memory - manager software. - - AH = 81h NON-RECOVERABLE. - The manager has detected a malfunction in the expanded - memory hardware. - - AH = 83h NON-RECOVERABLE. - The manager couldn't find the specified EMM handle. The - manager doesn't have any information pertaining to the - specified EMM handle. The program may have corrupted - its EMM handle. - - AH = 84h NON-RECOVERABLE. - The function code passed to the manager is not defined. - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - AH = 91h NON-RECOVERABLE. - This feature is not supported. - - - EXAMPLE - - emm_handle DW ? - handle_attrib DB ? - - MOV DX,emm_handle ; specify EMM handle - MOV AX,5200h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - MOV handle_attrib,AL ; save handle attribute - - - - - - - - - - - - - - EMM Functions 93 - - - - - - Function 19. Get/Set Handle Attribute - Set Handle Attribute subfunction - - - - PURPOSE - - This subfunction can be used to modify the attribute which a - handle has associated with it. The attributes which a - handle may have are volatile or non-volatile. The non- - volatile attribute enables the EMM to save the contents of a - handle's pages between warm boots. However, this function - may be disabled with a user option or may not be supported - by the memory board or system hardware. - - If the handle's attribute has been set to non-volatile, the - handle, its name (if it is assigned one), and the contents - of the pages allocated to the handle are all maintained - after a warm boot. - - - CALLING PARAMETERS - - AX = 5201h - Contains the Set Handle Attribute function. - - DX = handle - Contains the EMM handle. - - BL = new handle attribute - Contains the handle's new attribute. A value of zero - indicates that the handle should be made volatile. A - value of one indicates that the handle should be made - non-volatile. - - A volatile handle attribute instructs the memory manager - to deallocate both the handle and the pages allocated to - it after a warm boot. If all handles have the volatile - attribute (the default attribute) at warm boot, the - handle directory will be empty and all of expanded - memory will be initialized to zero immediately after a - warm boot. - - - REGISTERS MODIFIED - - AX - - - - - - - EMM Functions 94 - - - - - - Function 19. Get/Set Handle Attribute - Set Handle Attribute subfunction - - - - STATUS - - AH = 0 SUCCESSFUL. - The handle's attribute has been modified. - - AH = 80h NON-RECOVERABLE. - The manager has detected a malfunction in the memory - manager software. - - AH = 81h NON-RECOVERABLE. - The manager has detected a malfunction in the expanded - memory hardware. - - AH = 83h NON-RECOVERABLE. - The manager could not find the specified EMM handle. - The manager doesn't have any information pertaining to - the specified EMM handle. The program may have cor- - rupted its EMM handle. - - AH = 84h NON-RECOVERABLE. - The function code passed to the manager is not defined. - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - AH = 90h NON-RECOVERABLE. - The attribute type is undefined. - - AH = 91h NON-RECOVERABLE. - This feature is not supported. - - - EXAMPLE - - emm_handle DW ? - new_handle_attrib DB ? - - MOV DX,emm_handle ; specify EMM handle - MOV BL,new_handle_attrib ; specify the set attribute - MOV AX,5201h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - - - - - - EMM Functions 95 - - - - - - Function 19. Get/Set Handle Attribute - Get Attribute Capability subfunction - - - - PURPOSE - - This subfunction can be used to determine whether the memory - manager can support the non-volatile attribute. - - - CALLING PARAMETERS - - AX = 5202h - Contains the Get Attribute Capability subfunction. - - - RESULTS - - These results are valid only if the status returned is zero. - - AL = attribute capability - Contains the attribute capability. A value of zero - indicates that the memory manager and hardware supports - only volatile handles. A value of one indicates that - the memory manager/hardware supports both volatile and - non-volatile handles. - - - REGISTERS MODIFIED - - AX - - - STATUS - - AH = 0 SUCCESSFUL. - The attribute capability has been returned. - - AH = 80h NON-RECOVERABLE. - The manager has detected a malfunction in the memory - manager software. - - AH = 81h NON-RECOVERABLE. - The manager has detected a malfunction in the expanded - memory hardware. - - AH = 84h NON-RECOVERABLE. - The function code passed to the manager is not defined. - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - EMM Functions 96 - - - - - - Function 19. Get/Set Handle Attribute - Get Attribute Capability subfunction - - - - EXAMPLE - - attrib_capability DB ? - - MOV AX,5202h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - MOV attrib_capability,AL ; save attribute capability - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EMM Functions 97 - - - - - - Function 20. Get/Set Handle Name - Get Handle Name subfunction - - - - PURPOSE - - This subfunction gets the eight character name currently - assigned to a handle. There is no restriction on the - characters which may be used in the handle name (that is, - anything from 00h through FFh). - - The handle name is initialized to ASCII nulls (binary zeros) - three times: when the memory manager is installed, when a - handle is allocated, and when a handle is deallocated. A - handle with a name which is all ASCII nulls, by definition, - has no name. When a handle is assigned a name, at least one - character in the name must be a non-null character in order - to distinguish it from a handle without a name. - - - CALLING PARAMETERS - - AX = 5300h - Contains the Get Handle Name function. - - DX = handle number - Contains the EMM handle. - - ES:DI = pointer to handle_name array - Contains a pointer to an eight-byte array into which the - name currently assigned to the handle will be copied. - - - RESULTS - - These results are valid only if the status returned is zero. - - handle_name array - Contains the name associated with the specified handle. - - - REGISTERS MODIFIED - - AX - - - STATUS - - AH = 0 SUCCESSFUL. - The handle name has been returned. - - - EMM Functions 98 - - - - - - Function 20. Get/Set Handle Name - Get Handle Name subfunction - - - - AH = 80h NON-RECOVERABLE. - The manager has detected a malfunction in the memory - manager software. - - AH = 81h NON-RECOVERABLE. - The manager has detected a malfunction in the expanded - memory hardware. - - AH = 83h NON-RECOVERABLE. - The manager couldn't find the specified EMM handle. The - manager doesn't have any information on the specified - EMM handle. The program may have corrupted its EMM - handle. - - AH = 84h NON-RECOVERABLE. - The function code passed to the manager is not defined. - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - - EXAMPLE - - handle_name DB 8 DUP (?) - emm_handle DW ? - - MOV AX,SEG handle_name - MOV ES,AX - LEA DI,handle_name ; ES:DI points to handle_name - MOV DX,emm_handle ; specify EMM handle - MOV AX,5300h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - - - - - - - - - - - - - - - EMM Functions 99 - - - - - - Function 20. Get/Set Handle Name - Set Handle Name subfunction - - - - PURPOSE - - This subfunction assigns an eight character name to a - handle. There is no restriction on the characters which may - be used in the handle name. The full range of values may be - assigned to each character in a name (that is, 00h through - FFh). - - At installation, all handles have their name initialized to - ASCII nulls (binary zeros). A handle with a name consisting - of all ASCII nulls has no name. When a handle is assigned a - name, at least one character in the name must be a non-null - character in order to distinguish it from a handle without a - name. No two handles may have the same name. - - A handle can be renamed at any time by setting the handle's - name to a new value. A handle can have its name removed by - setting the handle's name to all ASCII nulls. When a handle - is deallocated, its name is removed (set to ASCII nulls). - - - CALLING PARAMETERS - - AX = 5301h - Contains the Set Handle Name function. - - DX = handle number - Contains the EMM handle. - - DS:SI = pointer to handle_name - Contains a pointer to a byte array which contains the - name that is to be assigned to the handle. The handle - name must be padded with nulls if the name is less than - eight characters long. - - - REGISTERS MODIFIED - - AX - - - STATUS - - AH = 0 SUCCESSFUL. - The handle name has been assigned. - - - - EMM Functions 100 - - - - - - Function 20. Get/Set Handle Name - Set Handle Name subfunction - - - - AH = 80h NON-RECOVERABLE. - The manager has detected a malfunction in the memory - manager software. - - AH = 81h NON-RECOVERABLE. - The manager has detected a malfunction in the expanded - memory hardware. - - AH = 83h NON-RECOVERABLE. - The manager couldn't find the specified EMM handle. The - manager doesn't currently have any information pertain- - ing to the specified EMM handle. The program may have - corrupted its EMM handle. - - AH = 84h NON-RECOVERABLE. - The function code passed to the manager is not defined. - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - AH = A1h RECOVERABLE. - A handle with this name already exists. The specified - handle was not assigned a name. - - - EXAMPLE - - handle_name DB 'AARDVARK' - emm_handle DW ? - - MOV AX,SEG handle_name - MOV DS,AX - LEA SI,handle_name ; DS:SI points to handle_name - MOV DX,emm_handle ; specify EMM handle - MOV AX,5301h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - - - - - - - - - - - EMM Functions 101 - - - - - - Function 21. Get Handle Directory - Get Handle Directory subfunction - - - - PURPOSE - - This function returns an array which contains all active - handles and the names associated with each. Handles which - have not been assigned names have a default name of all - ASCII nulls (binary zeros). When a handle is first allo- - cated, or when all the pages belonging to a handle are - deallocated (that is, an open handle is closed), its default - name is set to ASCII nulls. It takes a subsequent assign- - ment of a name for a handle to have a name after it has been - opened. The full range of values may be assigned to each - character in a name (that is, 00h through FFh). - - The number of bytes required by the array is: - - 10 bytes * total number of handles - - The maximum size of this array is: - - (10 bytes/entry) * 255 entries = 2550 bytes. - - - CALLING PARAMETERS - - AX = 5400h - Contains the Get Handle Directory function. - - handle_dir_struct STRUC - handle_value DW ? - handle_name DB 8 DUP (?) - handle_dir_struct ENDS - - ES:DI = pointer to handle_dir - Contains a pointer to an area of memory into which the - memory manager will copy the handle directory. The - handle directory is an array of structures. There are - as many entries in the array as there are open EMM - handles. The structure consists of the following - elements: - - .handle_value - The first member is a word which contains the value - of the open EMM handle. - - - - - - EMM Functions 102 - - - - - - Function 21. Get Handle Directory - Get Handle Directory subfunction - - - - .handle_name - The second member is an 8 byte array which contains - the ASCII name associated with the EMM handle. If - there is no name currently associated with the - handle, it has a value of all zeros (ASCII nulls). - - - RESULTS - - These results are valid only if the status returned is zero. - - handle_dir - Contains the handle values and handle names associated - with each handle value. - - AL = number of entries in the handle_dir array - Contains the number of entries in the handle directory - array. This is also the same as the number of open - handles. For example, if only one handle is active, AL - will contain a one. - - - REGISTERS MODIFIED - - AX - - - STATUS - - AH = 0 SUCCESSFUL. - The handle directory has been returned. - - AH = 80h NON-RECOVERABLE. - The manager has detected a malfunction in the memory - manager software. - - AH = 81h NON-RECOVERABLE. - The manager has detected a malfunction in the expanded - memory hardware. - - AH = 84h NON-RECOVERABLE. - The function code passed to the manager is not defined. - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - - - EMM Functions 103 - - - - - - Function 21. Get Handle Directory - Get Handle Directory subfunction - - - - EXAMPLE - - handle_dir handle_dir_struct 255 DUP (?) - - num_entries_in_handle_dir DB ? - - MOV AX,SEG handle_dir - MOV ES,AX - LEA DI,handle_dir ; ES:DI points to handle_dir - MOV AX,5400h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on - ; error - MOV num_entries_in_handle_dir,AL ; save number of entries - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EMM Functions 104 - - - - - - Function 21. Get Handle Directory - Search For Named Handle subfunction - - - - PURPOSE - - This subfunction searches the handle name directory for a - handle with a particular name. If the named handle is - found, this subfunction returns the handle number associated - with the name. At the time of installation, all handles - have their names initialized to ASCII nulls. A handle with - a name which is all ASCII nulls has, by definition, no name. - When a handle is assigned a name, at least one character in - the name must be a non-null character in order to distin- - guish it from a handle without a name. - - - CALLING PARAMETERS - - AX = 5401h - Contains the Search for Named Handle subfunction. - - DS:SI = handle_name - Contains a pointer to an 8-byte string that contains the - name of the handle being searched for. - - - RESULTS - - These results are valid only if the status returned is zero. - - DX = value of named handle - The value of the handle which matches the handle name - specified. - - - REGISTERS MODIFIED - - AX, DX - - - STATUS - - AH = 0 SUCCESSFUL. - The handle value for the named handle has been found. - - AH = 80h NON-RECOVERABLE. - The manager has detected a malfunction in the memory - manager software. - - - - EMM Functions 105 - - - - - - Function 21. Get Handle Directory - Search For Named Handle subfunction - - - - AH = 81h NON-RECOVERABLE. - The manager has detected a malfunction in the expanded - memory hardware. - - AH = 84h NON-RECOVERABLE. - The function code passed to the manager is not defined. - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - AH = A0h NON-RECOVERABLE. - No corresponding handle could be found for the handle - name specified. - - AH = A1h NON-RECOVERABLE. - A handle found had no name (all ASCII nulls). - - - EXAMPLE - - named_handle DB 'AARDVARK' - named_handle_value DW ? - - MOV AX,SEG named_handle - MOV DS,AX - LEA SI,named_handle ; DS:SI points to named_handle - MOV AX,5401h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - MOV named_handle_value,DX ; save value of named handle - - - - - - - - - - - - - - - - - - EMM Functions 106 - - - - - - Function 21. Get Handle Directory - Get Total Handles subfunction - - - - PURPOSE - - This subfunction returns the total number of handles that - the memory manager supports, including the operating system - handle (handle value 0). - - - CALLING PARAMETERS - - AX = 5402h - Contains the Get Total Handles subfunction. - - - RESULTS - - These results are valid only if the status returned is zero. - - BX = total_handles - The value returned represents the maximum number of - handles which a program may request the memory manager - to allocate memory to. The value returned includes the - operating system handle (handle value 0). - - - REGISTERS MODIFIED - - AX, BX - - - STATUS - - AH = 0 SUCCESSFUL. - The total number of handles supported has been returned. - - AH = 80h NON-RECOVERABLE. - The manager has detected a malfunction in the memory - manager software. - - AH = 81h NON-RECOVERABLE. - The manager has detected a malfunction in the expanded - memory hardware. - - AH = 84h NON-RECOVERABLE. - The function code passed to the manager is not defined. - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - EMM Functions 107 - - - - - - Function 21. Get Handle Directory - Get Total Handles subfunction - - - - EXAMPLE - - total_handles DW ? - - MOV AX,5402h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - MOV total_handles,BX ; save total handle count - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EMM Functions 108 - - - - - - Function 22. Alter Page Map & Jump - - - - PURPOSE - - This function alters the memory mapping context and trans- - fers control to the specified address. It is analogous to - the FAR JUMP in the 8086 family architecture. The memory - mapping context which existed before the invocation of this - function is lost. - - Mapping no pages and jumping is not considered an error. If - a request to map zero pages and jump is made, control is - transferred to the target address, and this function - performs a far jump. - - - CALLING PARAMETERS - - AH = 55h - Contains the Alter Page Map & Jump function. - - log_phys_map_struct STRUC - log_page_number DW ? - phys_page_number_seg DW ? - log_phys_map_struct ENDS - - map_and_jump_struct STRUC - target_address DD ? - log_phys_map_len DB ? - log_phys_map_ptr DD ? - map_and_jump_struct ENDS - - AL = physical page number/segment selector - Contains a code which indicates whether the value - contained in the - - .log_phys_map.phys_page_number_seg - - members are physical page numbers or are the segment - address representation of the physical page numbers. A - zero in AL indicates that the values are physical page - numbers. A one in AL indicates that the values in these - members are the segment address representations of the - physical page numbers. - - DX = handle number - Contains the EMM handle. - - - - - EMM Functions 109 - - - - - - Function 22. Alter Page Map & Jump - - - - DS:SI = pointer to map_and_jump structure - Contains a pointer to a structure that contains the - information necessary to map the desired physical pages - and jump to the target address. The structure consists - of the following elements: - - .target_address - The first member is a far pointer which contains the - target address to which control is to be trans- - ferred. The address is represented in segment:of- - fset format. The offset portion of the address is - stored in the low portion of the double word. - - .log_phys_map_len - The second member is a byte which contains the - number of entries in the array of structures which - immediately follows it. The array is as long as the - application developer needs in order to map the - desired logical pages into physical pages. The - number of entries cannot exceed the number of - mappable pages in the system. - - .log_phys_map_ptr - The third member is a pointer to an array of struc- - tures which contain the logical page numbers and - physical pages or segment address at which they are - to be mapped. Each entry in the array of structures - contains the following two elements: - - .log_page_number - The first member of this structure is a word which - contains the number of the logical page to be - mapped. - - .phys_page_number_seg - The second member of this structure is a word which - contains either the physical page number or the - segment address representation of the physical page - number at which the previous logical page number is - to be mapped. The value passed in AL determines the - type of representation. - - - REGISTERS MODIFIED - - AX - - - - EMM Functions 110 - - - - - - Function 22. Alter Page Map & Jump - - - - Note............................................................ - Values in registers which don't contain required parameters - maintain the values across the jump. The values in regis- - ters (with the exception of AX) and the flag state at the - beginning of the function are still in the registers and - flags when the target address is reached. - - - STATUS - - AH = 0 SUCCESSFUL. - Control has been transferred to the target address. - - AH = 80h NON-RECOVERABLE. - The manager has detected a malfunction in the memory - manager software. - - AH = 81h NON-RECOVERABLE. - The manager has detected a malfunction in the expanded - memory hardware. - - AH = 83h NON-RECOVERABLE. - The manager could not find the specified EMM handle. - The manager does not currently have any information - pertaining to the specified EMM handle. The program may - have corrupted its EMM handle. - - AH = 84h NON-RECOVERABLE. - The function code passed to the manager is not defined. - - AH = 8Ah RECOVERABLE. - One or more of the logical pages to map into a cor- - responding physical page is out of the range of logical - pages which are allocated to the EMM handle. The - program can recover from this condition by mapping a - logical page which is within the bounds for the EMM - handle. - - AH = 8Bh RECOVERABLE. - One or more of the physical pages is out of the range of - allowable physical pages, or the log_phys_map_len - exceeds the number of mappable pages in the system. - Physical page numbers are numbered zero-relative. The - program can recover from this condition by mapping into - memory at a physical page which is in the range of - supported physical pages. - - - - EMM Functions 111 - - - - - - Function 22. Alter Page Map & Jump - - - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - - EXAMPLE - - log_phys_map log_phys_map_struct (?) DUP (?) - - map_and_jump map_and_jump_struct (?) - - emm_handle DW ? - phys_page_or_seg_mode DB ? - - MOV AX,SEG map_and_jump - MOV DS,AX - LEA SI,map_and_jump ; DS:SI points to - ; map_and_jump - MOV DX,emm_handle - MOV AH,55h ; load function code - MOV AL,phys_page_or_seg_mode ; specify physical page - ; or segment mode - INT 67h ; call memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on - ; error - - - - - - - - - - - - - - - - - - - - - - - - - EMM Functions 112 - - - - - - Function 23. Alter Page Map & Call - Alter Page Map & Call subfunction - - - - PURPOSE - - This subfunction saves the current memory mapping context, - alters the specified memory mapping context, and transfers - control to the specified address. It is analogous to the - FAR CALL in the 8086 family architecture. Just as a return - from a FAR CALL restores the original value in the code - segment register, this subfunction restores the state of the - specified mapping context after the return. - - There is no explicit expanded memory subfunction which - emulates a return from a FAR CALL. However, this facility - is implicitly available through the standard return from a - FAR CALL. The following paragraphs describe how this works: - - After this function is invoked, unless an error is detected, - the memory manager will transfer control to the address - specified. If an error occurs, the memory manager returns - immediately with the error code in the AH register. - Otherwise, the memory manager pushes on the stack informa- - tion which enables it to restore the mapping context after - the return. - - When the called procedure wants to return to the calling - procedure, it simply issues a standard FAR RETURN. The - memory manager traps this return, restores the specified - mapping context, and returns to the calling procedure. The - memory manager also returns a status from a successful - return just as it does for all functions. - - Developers using this subfunction must make allowances for - the additional stack space this subfunction will use. - - - CALLING PARAMETERS - - AH = 56h - Contains the Alter Page Map & Call function. - - log_phys_map_struct STRUC - log_page_number DW ? - phys_page_number_seg DW ? - log_phys_map_struct ENDS - - - - - - EMM Functions 113 - - - - - - Function 23. Alter Page Map & Call - Alter Page Map & Call subfunction - - - - map_and_call_struct STRUC - target_address DD ? - new_page_map_len DB ? - new_page_map_ptr DD ? - old_page_map_len DB ? - old_page_map_ptr DD ? - reserved DW 4 DUP (?) - map_and_call_struct ENDS - - AL = physical page number/segment selector - Contains a code which indicates whether the value - contained in the - - .new_page_map.phys_page_number_seg - .old_page_map.phys_page_number_seg - - members are physical page numbers or are the segment - address representation of the physical page numbers. A - value of zero in AL indicates that the values in these - members are physical page numbers. A value of one in AL - indicates that the values in these members are the - segment address representations of the physical page - numbers. - - DX = handle number - Contains the EMM handle. - - DS:SI = pointer to map_and_call structure - Contains a pointer to a structure which contains the - information necessary to map the desired physical pages - and call the target address. The structure members are - described here: - - .target_address - The first member is a far pointer which contains the - target address to which control is to be trans- - ferred. The address is represented in segment:of- - fset format. The offset portion of the address is - stored in the low portion of the pointer. The - application must supply this value. - - .new_page_map_len - The second member is a byte which contains the - number of entries in the new mapping context to - which new_page_map_ptr points. This number cannot - exceed the number of mappable pages in the system. - - - EMM Functions 114 - - - - - - Function 23. Alter Page Map & Call - Alter Page Map & Call subfunction - - - - .new_page_map_ptr - The third member is a far pointer that points to an - array of structures which contains a list of the - logical page numbers and the physical page num- - bers/segments at which they are to be mapped im- - mediately after the call. The contents of the new - array of structures are described at the end of the - map_and_call structure. - - .old_page_map_len - The fourth member is a byte which contains the - number of entries in the old mapping context to - which old_page_map_ptr points. This number cannot - exceed the number of mappable pages in the system. - - .old_page_map_ptr - The fifth member is a far pointer that points to an - array of structures which contains a list of the - logical page numbers and the physical page num- - bers/segments at which they are to be mapped im- - mediately after the return. The contents of the old - array of structures are described at the end of the - map_and_call structure. - - .reserved - The sixth member is reserved for use by the memory - manager. - - Each entry in the old and new array of structures contains - two elements: - - .log_page_number - The first member of this structure is a word which - contains a logical page number which is to be mapped - at the succeeding physical page number/segment - immediately after the CALL (in the case of the new - array of structures) or after the RETURN (in the - case of the old array of structures). - - .phys_page_number_seg - The second member of this structure is a word which - contains either the physical page number or the - segment address representation of the physical page - number/segment at which the preceding logical page - is to be mapped immediately after the CALL (in the - case of the new array of structures) or after the - RETURN (in the case of the old array of structures). - - EMM Functions 115 - - - - - - Function 23. Alter Page Map & Call - Alter Page Map & Call subfunction - - - - REGISTERS MODIFIED - - AX - - Note............................................................ - Values in registers which don't contain required parameters - maintain the values across the call. The values in regis- - ters (with the exception of AX) and the flag state at the - beginning of the function are still in the registers and - flags when the target address is reached. - - - STATUS - - AH = 0 SUCCESSFUL. - Control has been transferred to the target address. - - AH = 80h NON-RECOVERABLE. - The manager has detected a malfunction in the memory - manager software. - - AH = 81h NON-RECOVERABLE. - The manager has detected a malfunction in the expanded - memory hardware. - - AH = 83h NON-RECOVERABLE. - The manager couldn't find the specified EMM handle. The - manager doesn't have any information pertaining to the - specified EMM handle. The program may have corrupted - its EMM handle. - - AH = 84h NON-RECOVERABLE. - The function code passed to the manager is not defined. - - AH = 8Ah RECOVERABLE. - One or more of the logical pages to map into a cor- - responding physical page is out of the range of logical - pages which are allocated to the EMM handle. The - program can recover from this condition by mapping a - logical page which is within the bounds for the EMM - handle. - - - - - - - - EMM Functions 116 - - - - - - Function 23. Alter Page Map & Call - Alter Page Map & Call subfunction - - - - AH = 8Bh RECOVERABLE. - One or more of the physical pages is out of the range of - allowable physical pages, or you've specified more - physical pages than exist in the system. Physical page - numbers are numbered zero-relative. The program can - recover from this condition by mapping a physical page - which is in the range from zero to three. - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - - EXAMPLE - - new_page_map log_phys_map_struct (?) DUP (?) - - old_page_map log_phys_map_struct (?) DUP (?) - - map_and_call map_and_call_struct (?) - - emm_handle DW ? - phys_page_or_seg_mode DB ? - - MOV AX,SEG map_and_call - MOV DS,AX - LEA SI,map_and_call ; DS:SI points to - ; map_and_call - MOV DX,emm_handle ; specify EMM handle - MOV AH,56h ; load function code - MOV AL,phys_page_or_seg_mode ; specify physical page - ; or segment mode - INT 67h ; control is actually - ; transferred to the called - ; procedure at this point - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on - ; error - - - - - - - - - - - - EMM Functions 117 - - - - - - Function 23. Alter Page Map & Call - Get Page Map Stack Space Size subfunction - - - - PURPOSE - - Since the Alter Page Map & Call function pushes additional - information onto the stack, this subfunction returns the - number of bytes of stack space the function requires. - - - CALLING PARAMETERS - - AX = 5602h - Contains the Get Page Map Stack Space Size subfunction. - - - RESULTS - - These results are valid only if the status returned is zero. - - BX = stack space required - Contains the number of bytes which the Alter Page Map & - Call function will require. In other words, BX contains - the number (including the return address) which has to - be added to the stack pointer to remove all elements - from the stack. - - - REGISTERS MODIFIED - - AX, BX - - - STATUS - - AH = 0 SUCCESSFUL. - The size of the array has been returned. - - AH = 80h NON-RECOVERABLE. - The manager has detected a malfunction in the memory - manager software. - - AH = 81h NON-RECOVERABLE. - The manager has detected a malfunction in the expanded - memory hardware. - - AH = 84h NON-RECOVERABLE. - The function code passed to the manager is not defined. - - - - EMM Functions 118 - - - - - - Function 23. Alter Page Map & Call - Get Page Map Stack Space Size subfunction - - - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - - EXAMPLE - - stack_space_reqd DW ? - - MOV AX,5602h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - MOV stack_space_reqd,BX ; save required stack size count - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EMM Functions 119 - - - - - - Function 24. Move/Exchange Memory Region - Move Memory Region subfunction - - - - PURPOSE - - This subfunction copies a region of memory in the following - memory source/destination combinations. - - o conventional memory to conventional memory - - o conventional memory to expanded memory - - o expanded memory to conventional memory - - o expanded memory to expanded memory - - You do not have to save and restore the expanded memory - mapping context to perform these move operations. The - current mapping context is maintained throughout this - operation. - - The length of the region is limited by the amount of - expanded memory allocated to the handles specified. - However, in most practical applications, the region length - will be considerably smaller. A region length of zero is - not an error, and no move will be performed. - - A region length which exceeds 16K bytes is not an error. In - this case the function assumes that a group of logical pages - is the target for the move. The logical page specified - represents the first logical page in which the move will - take place. If the region length exceeds 16K bytes, or if - the region is less than 16K bytes but spans logical pages, - there must be sufficient logical pages remaining after the - first logical page for the entire region to fit. - - If your application needs to save a region of conventional - memory in expanded memory, you can move it without having to - perform a save or restore of the current mapping context. - The memory manager maintains the context. A move of up to - 1M bytes may be performed, although practical lengths are - substantially less than this value. - - If the source and destination handles are identical, the - source and destination regions are tested for overlap before - the move. If they overlap, the move direction is chosen so - that the destination region receives an intact copy of the - source region. A status will be returned indicating that - this overlap has occurred. - - - EMM Functions 120 - - - - - - Function 24. Move/Exchange Memory Region - Move Memory Region subfunction - - - - CALLING PARAMETERS - - AX = 5700h - Contains the Move Memory Region function. - - move_source_dest_struct STRUC - region_length DD ? - source_memory_type DB ? - source_handle DW ? - source_initial_offset DW ? - source_initial_seg_page DW ? - dest_memory_type DB ? - dest_handle DW ? - dest_initial_offset DW ? - dest_initial_seg_page DW ? - move_source_dest_struct ENDS - - DS:SI = pointer to move_source_dest structure - Contains a pointer to a data structure which contains - the source and destination information for the move. - The structure members are described here: - - .region_length - The first member is a double word which specifies - the length of the memory region (in bytes) to be - moved. - - .source_memory_type - The second member is a byte which specifies the type - of memory where the source region resides. A value - of zero indicates that the source region resides in - conventional memory (excluding the page frame seg- - ment). A value of one indicates that the source - region resides in expanded memory. - - .source_handle - If the source region resides in expanded memory, the - third member is a word which specifies the handle - number associated with the source memory region. If - the source region resides in conventional memory, - this variable has no meaning and should be set to - zero for future compatibility. - - .source_initial_offset - The fourth member is a word which specifies the - offset within the source region from which to begin - the move. - - EMM Functions 121 - - - - - - Function 24. Move/Exchange Memory Region - Move Memory Region subfunction - - - - If the source region resides in expanded memory, the - source_initial_offset is relative to the beginning - of the 16K logical page. Because the offset is - relative to the beginning of a 16K expanded memory - page, it may only take on values between 0000h and - 3FFFh. - - If the source region resides in conventional memory, - the source_initial_offset is a word which specifies - the offset, relative to the beginning of the source - segment, from which to begin the move. Because the - offset is relative to the beginning of a 64K-byte - conventional memory segment, it may take on values - between 0000h and FFFFh. - - .source_initial_seg_page - The fifth member is a word which specifies the - initial segment or logical page number within the - source region from which to begin the move. - - If the source region resides in expanded memory, the - value specifies the logical page within the source - region from which to begin the move. - - If the source region resides in conventional memory, - the source_initial_seg_page specifies the initial - segment address within conventional memory from - which to begin the move. - - .dest_memory_type - The sixth member is a byte which specifies the type - of memory where the destination region resides. A - value of zero indicates conventional memory; a value - of one indicates expanded memory. - - .dest_handle - If the destination region resides in expanded - memory, the seventh member is a word which specifies - the handle number associated with the destination - memory region. If the destination region resides in - conventional memory, this variable has no meaning - and should be set to zero for future compatibility. - - .dest_initial_offset - The eighth member is a word which specifies the - offset within the destination region from which to - begin the move. - - EMM Functions 122 - - - - - - Function 24. Move/Exchange Memory Region - Move Memory Region subfunction - - - - If the destination region resides in expanded - memory, the dest_initial_offset is relative to the - beginning of the 16K-byte logical page. Because the - offset is relative to the beginning of a 16K-byte - expanded memory page, it may only take on values - between 0000h and 3FFFh. - - If the destination region resides in conventional - memory, the dest_initial_offset is a word which - specifies the offset, relative to the beginning of - the destination segment, to begin the move. Because - the offset is relative to the beginning of a 64K - conventional memory segment, it may take on values - between 0000h and FFFFh. - - .dest_initial_seg_page - The ninth member is a word which specifies the - initial segment or logical page number within the - destination region from which to begin the move. - - If the destination region resides in expanded memory - then the value specifies the logical page within the - destination region from which to begin the move. - - If the destination region resides in conventional - memory, the dest_initial_seg_page specifies the - initial segment address within conventional memory - from which to begin the move. - - - REGISTERS MODIFIED - - AX - - - STATUS - - AH = 0 SUCCESSFUL. - The memory regions have been moved. - - AH = 80h NON-RECOVERABLE. - The manager has detected a malfunction in the memory - manager software. - - AH = 81h NON-RECOVERABLE. - The manager has detected a malfunction in the expanded - memory hardware. - - EMM Functions 123 - - - - - - Function 24. Move/Exchange Memory Region - Move Memory Region subfunction - - - - AH = 83h NON-RECOVERABLE. - The manager couldn't find either the source or destina- - tion EMM handles. The memory manager doesn't have any - information on the handles specified. The program may - have corrupted its EMM handles. - - AH = 84h NON-RECOVERABLE. - The function code passed to the manager is not defined. - - AH = 8Ah NON-RECOVERABLE. - One or more of the logical pages is out of the range of - logical pages allocated to the source/destination - handle. - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - AH = 92h SUCCESSFUL. - The source and destination expanded memory regions have - the same handle and overlap. This is valid for a move. - The move has been completed and the destination region - has a full copy of the source region. However, at least - a portion of the source region has been overwritten by - the move. Note that the source and destination expanded - memory regions with different handles will never physi- - cally overlap because the different handles specify - totally different regions of expanded memory. - - AH = 93h CONDITIONALLY-RECOVERABLE. - The length of the source or destination expanded memory - region specified exceeds the length of the expanded - memory region allocated either the source or destination - handle. Insufficient pages are allocated to this handle - to move a region of the size specified. The program can - recover from this condition by allocating additional - pages to the destination or source handle and attempting - to execute the function again. However, if the applica- - tion program allocated as much expanded memory as it - thought it needed, this may be a program error and is - not recoverable. - - AH = 94h NON-RECOVERABLE. - The conventional memory region and expanded memory - region overlap. This is invalid, the conventional - memory region cannot overlap the expanded memory region. - - - - EMM Functions 124 - - - - - - Function 24. Move/Exchange Memory Region - Move Memory Region subfunction - - - - AH = 95h NON-RECOVERABLE. - The offset within the logical page exceeds the length of - the logical page. The initial source or destination - offsets within an expanded memory region must be between - 0000h and 3FFFh (16383 or (length of a logical page - - 1)). - - AH = 96h NON-RECOVERABLE. - Region length exceeds 1M bytes. - - AH = 98h NON-RECOVERABLE. - The memory source and destination types are undefined. - - AH = A2h NON-RECOVERABLE. - An attempt was made to wrap around the 1M-byte address - space of conventional memory during the move. The - combination of source/destination starting address and - length of the region to be moved exceeds 1M bytes. No - data was moved. - - - EXAMPLE - - move_source_dest move_source_dest_struct (?) - - MOV AX,SEG move_source_dest - MOV DS,AX - LEA SI,move_source_dest ; DS:SI points to move_source_dest - MOV AX,5700h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - - - - - - - - - - - - - - - - - EMM Functions 125 - - - - - - Function 24. Move/Exchange Memory Region - Exchange Memory Region subfunction - - - - PURPOSE - - This subfunction exchanges (using a string move) a region of - memory in any of the following memory source/destination - combinations. - - o conventional memory to conventional memory - - o conventional memory to expanded memory - - o expanded memory to conventional memory - - o expanded memory to expanded memory - - The term expanded memory region refers only to the area of - memory above 640K bytes (9FFFFh). If a system provides - mappable conventional memory, this function treats the - mappable conventional memory regions as ordinary convention- - al memory. The contents of the source region and the - destination region are exchanged. - - The exchange operation can be performed without having to - save and restore the expanded memory mapping context. The - current mapping context is maintained throughout this - operation. The length of the region is limited to the - amount of expanded memory allocated to the specified EMM - handles. A length of zero is not an error; however, no - exchange will be performed. A region length which exceeds - 16K bytes is not an error. In this case the function - assumes that a group of logical pages is the target for the - exchange. The logical page specified represents the first - logical page in which the exchange will take place. If the - region length exceeds 16K bytes, or if the region is less - than 16K bytes but spans logical pages, there must be - sufficient logical pages remaining after the first logical - page for the entire region to fit. - - If your application needs to exchange a region of conven- - tional memory with expanded memory, you can simply exchange - it with the region of interest without having to perform a - save or restore of the current mapping context. An exchange - of up to 1M bytes may be performed, although practical - lengths are obviously below that value. Checking is done - before starting the exchange to prevent the possibility of - overlap during the exchange operation. Overlapping source - and destination regions for an exchange are invalid, and the - exchange will not take place. - - EMM Functions 126 - - - - - - Function 24. Move/Exchange Memory Region - Exchange Memory Region subfunction - - - - CALLING PARAMETERS - - AX = 5701h - Contains the Exchange Memory Region function. - - xchg_source_dest_struct STRUC - region_length DD ? - source_memory_type DB ? - source_handle DW ? - source_initial_offset DW ? - source_initial_seg_page DW ? - dest_memory_type DB ? - dest_handle DW ? - dest_initial_offset DW ? - dest_initial_seg_page DW ? - xchg_source_dest_struct ENDS - - DS:SI = pointer to xchg_source_dest structure - Contains a pointer to the data structure which contains - the source and destination information for the exchange. - The structure members are described here: - - .region_length - The first member is a double word which specifies - the length of the memory region to be exchanged. - - .source_memory_type - The second member is a byte which specifies the type - of memory where the source region resides. A value - of zero indicates that the source region resides in - conventional memory. A value of one indicates that - the source region resides in expanded memory. - - .source_handle - If the source region resides in expanded memory, the - third member is a word which specifies the handle - number associated with the source memory region. If - the source region resides in conventional memory, - this variable has no meaning and should be set to - zero for future compatibility. - - .source_initial_offset - The fourth member is a word which specifies the - offset within the source region from which to begin - the exchange. - - - - EMM Functions 127 - - - - - - Function 24. Move/Exchange Memory Region - Exchange Memory Region subfunction - - - - If the source region resides in expanded memory, the - source_initial_offset is relative to the beginning - of the 16K logical page. Because the offset is - relative to the beginning of a 16K expanded memory - page, it may only take on values between 0000h and - 3FFFh. - - If the source region resides in conventional memory, - the source_initial_offset is a word which specifies - the offset, relative to the beginning of the source - segment, from which to begin the exchange at. - Because the offset is relative to the beginning of a - 64K-byte conventional memory segment, it may take on - values between 0000h and FFFFh. - - .source_initial_seg_page - The fifth member is a word which specifies the - initial segment or logical page number within the - source region from which to begin the exchange. - - If the source region resides in expanded memory then - the value specifies the logical page within the - source region from which to begin the exchange. - - If the source region resides in conventional memory, - the source_initial_seg_page specifies the initial - segment address within conventional memory from - which to begin the exchange. - - .dest_memory_type - The sixth member is a byte which specifies the type - of memory where the destination region resides. A - value of zero indicates that the destination region - resides in conventional memory (excluding the page - frame segment). A value of one indicates that the - destination region resides in expanded memory. - - .dest_handle - If the destination region resides in expanded - memory, the seventh member is a word which specifies - the handle number associated with the destination - memory region. If the destination region resides in - conventional memory, this variable has no meaning - and should be set to zero for future compatibility. - - - - - EMM Functions 128 - - - - - - Function 24. Move/Exchange Memory Region - Exchange Memory Region subfunction - - - - .dest_initial_offset - The eighth member is a word which specifies the - offset within the destination region from which to - begin the exchange. - - If the destination region resides in expanded - memory, the dest_initial_offset is relative to the - beginning of the 16K-byte logical page. Because the - offset is relative to the beginning of a 16K-byte - expanded memory page, it may only take on values - between 0000h and 3FFFh. - - If the destination region resides in conventional - memory, the dest_initial_offset is a word which - specifies the offset, relative to the beginning of - the destination segment, to begin the exchange at. - Because the offset is relative to the beginning of a - 64K conventional memory segment, it may take on - values between 0000h and FFFFh. - - .dest_initial_seg_page - The ninth member is a word which specifies the - initial segment or logical page number within the - destination region from which to begin the exchange. - - If the destination region resides in expanded memory - then the value specifies the logical page within the - destination region from which to begin the exchange. - - If the destination region resides in conventional - memory, the dest_initial_seg_page specifies the - initial segment address within conventional memory - from which to begin the exchange. - - - - REGISTERS MODIFIED - - AX - - - STATUS - - AH = 0 SUCCESSFUL. - The memory regions have been exchanged. - - - - EMM Functions 129 - - - - - - Function 24. Move/Exchange Memory Region - Exchange Memory Region subfunction - - - - AH = 80h NON-RECOVERABLE. - The manager has detected a malfunction in the memory - manager software. - - AH = 81h NON-RECOVERABLE. - The manager has detected a malfunction in the expanded - memory hardware. - - AH = 83h NON-RECOVERABLE. - The manager could not find either the source or destina- - tion EMM handles. The memory manager does not currently - have any information pertaining to the handles speci- - fied. The program may have corrupted its EMM handles. - - AH = 84h NON-RECOVERABLE. - The function code passed to the manager is not defined. - - AH = 8Ah NON-RECOVERABLE. - One or more of the logical pages is out of the range of - logical pages allocated to the source/destination - handle. - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - AH = 93h CONDITIONALLY-RECOVERABLE. - The length of the source or destination expanded memory - region specified, exceeds the length of the expanded - memory region allocated to the source or destination - specified EMM handle. There are insufficient pages - allocated to this handle to exchange a region of the - size specified. The program can recover from this - condition by attempting to allocate additional pages to - the destination or source handle and attempting to - execute the function again. However, if the application - program was allocated as much expanded memory as it - thought it needed, this may be a program error and is - therefore not recoverable. - - AH = 94h NON-RECOVERABLE. - The conventional memory region and expanded memory - region overlap. This is invalid, the conventional - memory region cannot overlap the expanded memory region. - - - - - - EMM Functions 130 - - - - - - Function 24. Move/Exchange Memory Region - Exchange Memory Region subfunction - - - - AH = 95h NON-RECOVERABLE. - The offset within the logical page exceeds the length of - the logical page. The initial source or destination - offsets within an expanded memory region must be between - 0000h and 3FFFh (16383 or (length of a logical page - - 1)). - - AH = 96h NON-RECOVERABLE. - Region length exceeds 1M-byte limit. - - AH = 97h NON-RECOVERABLE. - The source and destination expanded memory regions have - the same handle and overlap. This is invalid, the - source and destination expanded memory regions cannot - have the same handle and overlap when they are being - exchanged. Note that the source and destination - expanded memory regions which have different handles - will never physically overlap because the different - handles specify totally different regions of expanded - memory. - - AH = 98h NON-RECOVERABLE. - The memory source and destination types are undefined. - - AH = A2h NON-RECOVERABLE. - An attempt was made to wrap around the 1M-byte address - space of conventional memory during the exchange. The - combination of source/destination starting address and - length of the region to be exchanged exceeds 1M bytes. - No data was exchanged. - - - EXAMPLE - - xchg_source_dest xchg_source_dest_struct (?) - - MOV AX,SEG xchg_source_dest - MOV DS,AX - LEA SI,xchg_source_dest ; DS:SI points to xchg_source_dest - MOV AX,5701h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - - - - - - EMM Functions 131 - - - - - - Function 25. Get Mappable Physical Address Array - Get Mappable Physical Address Array subfunction - - - - PURPOSE - - This subfunction returns an array containing the segment - address and physical page number for each mappable physical - page in a system. The contents of this array provide a - cross reference between physical page numbers and the actual - segment addresses for each mappable page in the system. The - array is sorted in ascending segment order. This does not - mean that the physical page numbers associated with the - segment addresses are also in ascending order. - - - CALLING PARAMETERS - - AX = 5800h - Contains the Get Mappable Physical Address Array - subfunction - - mappable_phys_page_struct STRUC - phys_page_segment DW ? - phys_page_number DW ? - mappable_phys_page_struct ENDS - - ES:DI = mappable_phys_page - Contains a pointer to an application-supplied memory - area where the memory manager will copy the physical - address array. Each entry in the array is a structure - containing two members: - - .phys_page_segment - The first member is a word which contains the - segment address of the mappable physical page - associated with the physical page number following - it. The array entries are sorted in ascending - segment address order. - - .phys_page_number - The second member is a word which contains the - physical page number which corresponds to the - previous segment address. The physical page numbers - are not necessarily in ascending order. - - - - - - - - EMM Functions 132 - - - - - - Function 25. Get Mappable Physical Address Array - Get Mappable Physical Address Array subfunction - - - - Example 1 - - An expanded memory board has its page frame starting - at address C0000h and has no mappable conventional - memory. For this configuration, physical page 0 - corresponds to segment address C000h, physical page - 1 corresponds to segment address C400h, etc. The - array would contain the following data (in this - order): - - C000h, 00h - C400h, 01h - C800h, 02h - CC00h, 03h - - - Example 2 - - An expanded memory board has a large page frame - starting at address C0000h and has mappable conven- - tional memory from 90000h through 9FFFFh. For this - configuration, physical page 0 corresponds to - segment address C000h, physical page 1 corresponds - to segment address C400h, etc. The array would - contain the following data in the order specified. - Note that the expanded memory region always has the - lowest numerically valued physical page numbers. - - 9000h, 0Ch - 9400h, 0Dh - 9800h, 0Eh - 9C00h, 0Fh - C000h, 00h - C400h, 01h - C800h, 02h - CC00h, 03h - D000h, 04h - D400h, 05h - D800h, 06h - DC00h, 07h - E000h, 08h - E400h, 09h - E800h, 0Ah - EC00h, 0Bh - - - - - EMM Functions 133 - - - - - - Function 25. Get Mappable Physical Address Array - Get Mappable Physical Address Array subfunction - - - - RESULTS - - These results are valid only if the status returned is zero. - - CX = number of entries in the mappable_phys_page - Multiply this number by (SIZE mappable_phys_page_struct) - to determine the number of bytes the physical page - address array requires. - - - REGISTERS MODIFIED - - AX, CX - - - STATUS - - AH = 0 SUCCESSFUL. - The hardware configuration array has been returned. - - AH = 80h NON-RECOVERABLE. - The manager has detected a malfunction in the memory - manager software. - - AH = 81h NON-RECOVERABLE. - The manager has detected a malfunction in the expanded - memory hardware. - - AH = 84h NON-RECOVERABLE. - The function code passed to the manager is not defined. - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - - - - - - - - - - - - - - - EMM Functions 134 - - - - - - Function 25. Get Mappable Physical Address Array - Get Mappable Physical Address Array subfunction - - - - EXAMPLE - - mappable_phys_page mappable_phys_page_struct (?) - - mappable_page_entry_count DW ? - - MOV AX,SEG mappable_phys_page - MOV ES,AX - LEA DI,mappable_phys_page ; ES:DI points to - ; mappable_phys_page - MOV AX,5800h ; load function code - INT 67h ; call the memory - ; manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler - ; on error - MOV mappable_page_entry_count,CX ; save mappable - ; page entry count - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EMM Functions 135 - - - - - - Function 25. Get Mappable Physical Address Array - Get Mappable Physical Address Array Entries subfunction - - - - PURPOSE - - This subfunction gets the number of entries which will be - required for the array the first subfunction returns. - - - CALLING PARAMETERS - - AX = 5801h - Contains the Get Physical Page Address Array Entries - subfunction. This subfunction returns a word which - represents the number of entries in the array returned - by the previous subfunction. This number also repre- - sents the number of mappable physical pages in a system. - - - RESULTS - - These results are valid only if the status returned is zero. - - CX = number of entries in the mappable_phys_page - Multiply this number by (SIZE mappable_phys_page_struct) - to determine the number of bytes the physical page - address array will require. - - - REGISTERS MODIFIED - - AX, CX - - - STATUS - - AH = 0 SUCCESSFUL. - The number of mappable physical pages has been returned. - - AH = 80h NON-RECOVERABLE. - The manager has detected a malfunction in the memory - manager software. - - AH = 81h NON-RECOVERABLE. - The manager has detected a malfunction in the expanded - memory hardware. - - AH = 84h NON-RECOVERABLE. - The function code passed to the manager is not defined. - - - EMM Functions 136 - - - - - - Function 25. Get Mappable Physical Address Array - Get Mappable Physical Address Array Entries subfunction - - - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - - EXAMPLE - - mappable_page_entry_count DW ? - - MOV AX,5801h ; load function code - INT 67h ; call memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler - ; on error - MOV mappable_page_entry_count,CX ; save mappable - ; page entry count - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EMM Functions 137 - - - - - - Function 26. Get Expanded Memory Hardware Information - Get Hardware Configuration Array subfunction - - - - Note............................................................ - This function is for use by operating systems only. This - function can be disabled at any time by the operating - system. Refer to Function 30 for a description of how an - operating system does this. - - - PURPOSE - - This subfunction returns an array containing expanded memory - hardware configuration information for use by an operating - system/environment. - - - CALLING PARAMETERS - - AX = 5900h - Contains the Get Hardware Configuration Array subfunc- - tion. - - hardware_info_struct STRUC - raw_page_size DW ? - alternate_register_sets DW ? - context_save_area_size DW ? - DMA_register_sets DW ? - DMA_channel_operation DW ? - hardware_info_struct ENDS - - ES:DI = hardware_info - Contains a pointer to a memory area that the operating - system supplies where the memory manager will copy - expanded memory hardware information. The structure - contains these five members: - - .raw_page_size - The first member is a word which contains the size - of a raw mappable physical page in paragraphs (16 - bytes). LIM standard pages are always 16K bytes. - However, other implementations of expanded memory - boards do not necessarily comply with this standard - and can emulate a 16K-byte page by mapping in - multiple smaller pages. This member specifies the - size of a mappable physical page viewed from the - hardware implementation level. - - - - - EMM Functions 138 - - - - - - Function 26. Get Expanded Memory Hardware Information - Get Hardware Configuration Array subfunction - - - - .alternate_register_sets - The second member is a word which specifies the - number of alternate mapping register sets. The - additional mapping register sets are termed alter- - nate mapping register sets in this document. - - All expanded memory boards have at least one set of - hardware registers to perform the logical to - physical page mapping. Some expanded memory boards - have more than one set of these mapping registers. - This member specifies how many of these alternate - mapping register sets exist (beyond the one set that - all expanded memory boards have) on the expanded - memory boards in the system. If an expanded memory - card has only one set of mapping registers (that is, - no alternate mapping register sets) this member has - a value of zero. - - .context_save_area_size - The third member is a word which contains the - storage requirements for the array required to save - a mapping context. The value returned in this - member is exactly the same as that returned by - Function 15 (Get Size of Page Map Save Array - subfunction). - - .DMA_register_sets - The fourth member is a word which contains the - number of register sets that can be assigned to DMA - channels. These DMA register sets, although similar - in use to alternate register sets, are for DMA - mapping and not task mapping. - - If the expanded memory hardware does not support DMA - register sets, care must be taken when DMA is taking - place. - - In a multitasking operating system, when one task is - waiting for DMA to complete, it is useful to be able - to switch to another task. However, if the DMA is - taking place in memory that the second task will - need to remap, remapping would be disastrous. - - - - - - - EMM Functions 139 - - - - - - Function 26. Get Expanded Memory Hardware Information - Get Hardware Configuration Array subfunction - - - - If the expanded memory hardware can detect when DMA - is occurring, the OS/E should allow task switches - and remapping during DMA. If no special support for - DMA is available, no remapping should be done when - DMA is in progress. - - .DMA_channel_operation - The fifth member is a word which specifies a special - case for the DMA register sets. A value of zero - specifies that the DMA register sets behave as - described in Function 28. A value of one specifies - that the expanded memory hardware has only one DMA - register set. In addition, if any channel is mapped - through this register set, then all channels are - mapped through it. For LIM standard boards, this - value is zero. - - - RESULTS - - These results are valid only if the status returned is zero. - - hardware_info - Contains the expanded memory hardware-specific informa- - tion described above. - - - REGISTERS MODIFIED - - AX - - - STATUS - - AH = 0 SUCCESSFUL. - The hardware configuration array has been returned. - - AH = 80h NON-RECOVERABLE. - The manager has detected a malfunction in the memory - manager software. - - AH = 81h NON-RECOVERABLE. - The manager has detected a malfunction in the expanded - memory hardware. - - AH = 84h NON-RECOVERABLE. - The function code passed to the manager is not defined. - - EMM Functions 140 - - - - - - Function 26. Get Expanded Memory Hardware Information - Get Hardware Configuration Array subfunction - - - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - AH = A4h NON-RECOVERABLE. - Access to this function has been denied by the operating - system. The function cannot be used at this time. - - - EXAMPLE - - hardware_info hardware_info_struct (?) - - MOV AX,SEG hardware_info - MOV ES,AX - LEA DI,hardware_info ; ES:DI points to hardware_info - MOV AX,5900h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EMM Functions 141 - - - - - - Function 26. Get Expanded Memory Hardware Information - Get Unallocated Raw Page Count subfunction - - - - PURPOSE - - The Get Unallocated Raw Page Count subfunction returns the - number of unallocated non-standard length mappable pages as - well as the total number of non-standard length mappable - pages in expanded memory to the operating system. - - One variety of expanded memory board has a page size which - is a sub-multiple of 16K bytes. An expanded memory page - which is a sub-multiple of 16K is termed a raw page. An - operating system may deal with mappable physical page sizes - which are sub-multiples of 16K bytes. - - If the expanded memory board supplies pages in exact - multiples of 16K bytes, the number of pages this function - returns is identical to the number Function 3 (Get Unallo- - cated Page Count) returns. In this case, there is no - difference between a page and a raw page. - - - CALLING PARAMETERS - - AX = 5901h - Contains the Get Unallocated Raw Page Count subfunction. - - - RESULTS - - These results are valid only if the status returned is zero. - - BX = unallocated raw pages - The number of raw pages that are currently available for - use. - - DX = total raw pages - The total number of raw pages in expanded memory. - - - REGISTERS MODIFIED - - AX, BX, DX - - - - - - - - EMM Functions 142 - - - - - - Function 26. Get Expanded Memory Hardware Information - Get Unallocated Raw Page Count subfunction - - - - STATUS - - AH = 0 SUCCESSFUL. - The manager has returned the number of unallocated raw - pages and the number of total raw pages in expanded - memory. - - AH = 80h NON-RECOVERABLE. - The manager detected a malfunction in the memory manager - software. - - AH = 81h NON-RECOVERABLE. - The manager detected a malfunction in the expanded - memory hardware. - - AH = 84h NON-RECOVERABLE. - The function code passed to the memory manager is not - defined. - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - - EXAMPLE - - unalloc_raw_pages DW ? - total_raw_pages DW ? - - MOV AX,5901h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - MOV unalloc_raw_pages,BX ; save unallocated raw page count - MOV total_raw_pages,DX ; save total raw page count - - - - - - - - - - - - - - - EMM Functions 143 - - - - - - Function 27. Allocate Standard/Raw Pages - Allocate Standard Pages subfunction - - - - PURPOSE - - The Allocate Standard Pages subfunction allocates the number - of standard size (16K bytes) pages that the operating system - requests and assigns a unique EMM handle to these pages. - The EMM handle owns these pages until the operating system - deallocates them. This subfunction allows you to allocate - zero pages to a handle, unlike Function 4 (Allocate Pages). - - Note............................................................ - This note affects expanded memory manager implementors and - operating system developers only. Applications should not - use the following characteristic of the memory manager. An - application violating this rule will be incompatible with - future versions of Microsoft's operating systems and - environments. - - To be compatible with this specification, an expanded memory - manager will provide a special handle which is available to - the operating system only. This handle will have a value of - 0000h and will have a set of pages allocated to it when the - expanded memory manager driver installs. The pages that the - memory manager will automatically allocate to handle 0000h - are those that backfill conventional memory. Typically, - this backfill occurs between addresses 40000h (256K) and - 9FFFFh (640K). However, the range can extend below and - above this limit if the hardware and memory manager have the - capability. - - An operating system won't have to invoke Function 27 to - obtain this handle because it can assume the handle already - exists and is available for use immediately after the - expanded memory device driver installs. When an operating - system wants to use this handle, it uses the special handle - value of 0000h. The operating system will be able to invoke - any EMM function using this special handle value. To - allocate pages to this handle, the operating system need - only invoke Function 18 (Reallocate Pages). - - There are two special cases for this handle: - - 1. Function 27 (Allocate Standard Pages subfunction). This - function must never return zero as a handle value. - Applications must always invoke Function 27 to allocate - pages and obtain a handle which identifies the pages - which belong to it. Since Function 27 never returns a - - - EMM Functions 144 - - - - - - Function 27. Allocate Standard/Raw Pages - Allocate Standard Pages subfunction - - - - handle value of zero, an application will never gain - access to this special handle. - - 2. Function 6 (Deallocate Pages). If the operating system - uses it to deallocate the pages which are allocated to - this handle, the pages the handle owns will be returned - to the manager for use. But the handle will not be - available for reassignment. The manager should treat a - deallocate pages function request for this handle the - same as a reallocate pages function request, where the - number of pages to reallocate to this handle is zero. - - - CALLING PARAMETERS - - AX = 5A00h - Contains the Allocate Standard Pages subfunction. - - BX = num_of_standard_pages_to_alloc - Contains the number of standard pages the operating - system wants to allocate. - - - RESULTS - - These results are valid only if the status returned is zero. - - DX = handle - Contains a unique EMM handle. The operating system must - use this EMM handle as a parameter in any function that - requires it. Up to 255 handles may be obtained. (Both - Function 27 and Function 4 must share the same 255 - handles.) - - For all functions using this handle, the length of the - physical and logical pages allocated to it are standard - length (that is, 16K bytes). - - - REGISTERS MODIFIED - - AX, DX - - - - - - - EMM Functions 145 - - - - - - Function 27. Allocate Standard/Raw Pages - Allocate Standard Pages subfunction - - - - STATUS - - AH = 0 SUCCESSFUL. - The manager has allocated the pages to an assigned EMM - standard handle. - - AH = 80h NON-RECOVERABLE. - The manager detected a malfunction in the memory manager - software. - - AH = 81h NON-RECOVERABLE. - The manager detected a malfunction in the expanded - memory hardware. - - AH = 84h NON-RECOVERABLE. - The function code passed to the memory manager is not - defined. - - AH = 85h RECOVERABLE. - All EMM handles are being used. - - AH = 87h RECOVERABLE. - There aren't enough expanded memory pages present in the - system to satisfy the operating system's request. - - AH = 88h RECOVERABLE. - There aren't enough unallocated pages to satisfy the - operating system's request. - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - - EXAMPLE - - num_of_standard_pages_to_alloc DW ? - emm_handle DW ? - - MOV BX,num_of_standard_pages_to_alloc - MOV AX,5A00h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on - ; error - MOV emm_handle,DX ; save handle - - - - EMM Functions 146 - - - - - - Function 27. Allocate Standard/Raw Pages - Allocate Raw Pages subfunction - - - - PURPOSE - - The Allocate Raw Pages function allocates the number of non- - standard size pages that the operating system requests and - assigns a unique EMM handle to these pages. The EMM handle - owns these pages until the operating system deallocates - them. This function allows you to allocate zero pages to a - handle, unlike Function 4 (Allocate Pages). - - A hardware vendor may design an expanded memory board that - has a page size which is a sub-multiple of 16K bytes. A - physical page which is a sub-multiple of 16K is termed a raw - page. The operating system may deal with page sizes which - are sub-multiples of 16K bytes. The memory manager must - treat any function using a handle with raw pages allocated - to it by Function 27 (Allocate Raw Pages subfunction) - differently than it does a handle that has normal 16K-byte - pages allocated to it. - - Handles which are assigned using Function 4 (Allocate Pages) - or Function 27 (Allocate Standard Pages subfunction) must - have pages which are 16K bytes -- this is the length of a - standard expanded memory page. If the expanded memory board - hardware is not able to supply 16K-byte pages, the memory - manager must emulate pages which are 16K bytes combining - multiple non-standard size pages to form a single 16K-byte - page. - - Handles which are assigned using Function 27 (Allocate Raw - Pages subfunction) are called raw handles. All logical - pages allocated to a raw handle may have a non-standard - length (that is, not 16K bytes). However, once the operat- - ing system has allocated a number of raw pages to a handle, - it is the responsibility of the memory manager to recognize - that raw handle as one that has non-standard size pages - allocated to it. The memory manager must identify these - handles and treat all functions which use handles which have - non-standard page lengths differently. The logical page - length becomes the length of the non-standard size page for - any raw handle that Function 27 assigns. - - Note............................................................ - This note affects expanded memory manager implementors and - operating system developers only. Applications should not - use the following characteristic of the memory manager. An - application violating this rule will be incompatible with - - - EMM Functions 147 - - - - - - Function 27. Allocate Standard/Raw Pages - Allocate Raw Pages subfunction - - - - future versions of Microsoft's operating systems and - environments. - - To be compatible with this specification, an expanded memory - manager will provide a special handle which is available to - the operating system only. This handle will have a value of - 0000h and will have a set of pages allocated to it when the - expanded memory manager driver installs. The pages that the - memory manager will automatically allocate to handle 0000h - are those that backfill conventional memory. Typically, - this backfill occurs between addresses 40000h (256K) and - 9FFFFh (640K). However, the range can extend below and - above this limit if the hardware and memory manager have the - capability. - - An operating system won't have to invoke Function 27 to - obtain this handle because it can assume the handle already - exists and is available for use immediately after the - expanded memory device driver installs. When an operating - system wants to use this handle, it uses the special handle - value of 0000h. The operating system will be able to invoke - any EMM function using this special handle value. To - allocate pages to this handle, the operating system need - only invoke Function 18 (Reallocate Pages). - - There are two special cases for this handle: - - 1. Function 27 (Allocate Raw Pages subfunction). This - function must never return zero as a handle value. - Applications must always invoke Function 27 to allocate - pages and obtain a handle which identifies the pages - which belong to it. Since Function 27 never returns a - handle value of zero, an application will never gain - access to this special handle. - - 2. Function 6 (Deallocate Pages). If the operating system - uses it to deallocate the pages which are allocated to - this handle, the pages the handle owns will be returned - to the manager for use. But the handle will not be - available for reassignment. The manager should treat a - deallocate pages function request for this handle the - same as a reallocate pages function request, where the - number of pages to reallocate to this handle is zero. - - - - - - EMM Functions 148 - - - - - - Function 27. Allocate Standard/Raw Pages - Allocate Raw Pages subfunction - - - - CALLING PARAMETERS - - AX = 5A01h - Contains the Allocate Raw Pages subfunction. - - BX = num_of_raw_pages_to_alloc - Contains the number of raw pages the operating system - wishes to allocate. - - - RESULTS - - These results are valid only if the status returned is zero. - - DX = raw handle - Contains a unique EMM raw handle. The operating system - must use this EMM raw handle as a parameter in any - function that requires it. Up to 255 handles may be - obtained. (Both Function 4 and Function 27 must share - the same 255 handles). - - For all functions using this raw handle, the length of - the physical and logical pages allocated to it may be - non-standard (that is, not 16K bytes). - - - REGISTERS MODIFIED - - AX, DX - - - STATUS - - AH = 0 SUCCESSFUL. - The manager has allocated the raw pages to an assigned - EMM raw handle. - - AH = 80h NON-RECOVERABLE. - The manager detected a malfunction in the memory manager - software. - - AH = 81h NON-RECOVERABLE. - The manager detected a malfunction in the expanded - memory hardware. - - - - - EMM Functions 149 - - - - - - Function 27. Allocate Standard/Raw Pages - Allocate Raw Pages subfunction - - - - AH = 84h NON-RECOVERABLE. - The function code passed to the memory manager is not - defined. - - AH = 85h RECOVERABLE. - All EMM handles are being used. - - AH = 87h RECOVERABLE. - There aren't enough expanded memory raw pages present in - the system to satisfy the operating system's request. - - AH = 88h RECOVERABLE. - There aren't enough unallocated raw pages to satisfy the - operating system's request. - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - - EXAMPLE - - num_of_raw_pages_to_alloc DW ? - emm_raw_handle DW ? - - MOV BX,num_of_raw_pages_to_alloc - MOV AX,5A01h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler - ; on error - MOV emm_raw_handle,DX ; save raw handle - - - - - - - - - - - - - - - - - - EMM Functions 150 - - - - - - Function 28. Alternate Map Register Set - - - - Note............................................................ - This function is for use by operating systems only. The - operating system can disable this function at any time. - Refer to Function 30 for a description of how an operating - system can enable or disable this function. - - - Design Considerations - - The hardware support for the entire set of subfunctions - described is generally not present on every expanded memory - board from every vendor of expanded memory board products. - For some of the subfunctions, software emulation is provid- - ed. For other subfunctions, a certain protocol in their use - must be observed. The subfunctions for which this is most - crucial are those which address system DMA capabilities. - - - System DMA Capabilities & Expanded Memory Support of DMA - - In a multitasking operating system, when one task is waiting - for DMA to complete, it is useful to be able to switch to - another task. This specification describes a capability - which may be designed into expanded memory boards to provide - DMA into memory regions which may be mapped out while the - DMA is occurring. For expanded memory boards that do not - provide this, it is crucial to understand that while DMA is - in progress into a region of mappable memory, the memory - mapping context cannot be changed. That is, all DMA action - must be complete before any remapping of pages can be done. - - - Expanded Memory Support of DMA Register Sets - - Expanded memory boards which have DMA register sets could - support DMA into a region of mappable memory while the - memory mapping context is being switched. It is important - to realize that these DMA register sets are separate from - the alternate map register sets. An example of how an OS/E - might use DMA register sets follows: - - Example 1 - - 1. Allocate a DMA register set. - - 2. Get current register set. - - 3. Set the DMA register set. - - EMM Functions 151 - - - - - - Function 28. Alternate Map Register Set - - - - 4. Map in the memory desired. - - 5. Get the DMA register set. - - 6. Set the original register set. - - 7. Assign the desired DMA channel to the DMA register set. - - The preceding set of calls makes all DMA accesses for the - desired DMA channel get mapped through the current DMA - register set regardless of the current register set. In - other words, the DMA register set overrides the current - mapping register set for DMA operations on the DMA channel - specified. A DMA channel that is not assigned to a DMA - register set has all its DMA operations mapped through the - current mapping register set. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EMM Functions 152 - - - - - - Function 28. Alternate Map Register Set - Get Alternate Map Register Set subfunction - - - - Note............................................................ - This function is for use by operating systems only. The - operating system can disable this function at any time. - Refer to Function 30 for a description of how an operating - system can enable or disable this function. - - - PURPOSE - - The subfunction does one of two things depending on the map - register set which is active at the time this function is - invoked: - - 1. If the preceding Set Alternate Map Register Set call was - done with the alternate map register set equal to zero - (BL = 0), these points apply: - - a. The context save area pointer saved within EMM by - the Set Alternate Map Register subfunction is - returned by this call. This pointer is always - returned for boards which do not supply alternate - mapping register sets. - - b. If the context save area pointer returned is not - equal to zero, this subfunction copies the contents - of the mapping registers on each expanded memory - board in the system into the save area specified by - the pointer. The format of this save area is the - same as that returned by Function 15 (Get Page Map - subfunction). This is intended to simulate getting - an alternate map register set. Note that the memory - manager does not allocate the space for the context: - the operating system must do so. - - c. If the context save area pointer returned is equal - to zero, this subfunction does not copy the contents - of the mapping registers on each expanded memory - board in the system into the save area specified by - the pointer. - - d. The context save area pointer must have been - initialized by a previous Set Alternate Map Register - Set call. Note that the value of the context save - area pointer saved within EMM is zero immediately - after installation. - - - - EMM Functions 153 - - - - - - Function 28. Alternate Map Register Set - Get Alternate Map Register Set subfunction - - - - e. The context save area must be initialized by a - previous Get Page Map call (Function 15). - - 2. If the preceding Set Alternate Map Register Set call was - done with the alternate map register set greater than - zero (BL > 0), then the number of the alternate map - register set which is in use at the time that this - function is invoked is returned. The context save area - pointer is not returned in this case. - - - CALLING PARAMETERS - - AX = 5B00h - Contains the Get Alternate Map Register Set subfunction. - - - RESULTS - - These results are valid only if the status returned is zero. - - If BL <> 0, current active alternate map register set number - Contains the alternate map register set which was active - at the time that this function was invoked. - - ES:DI Unaffected. - - If BL = 0 - Indicates that a pointer to an area which contains the - state of all the map registers on all boards in the - system, and any additional information necessary to - restore the boards to their original state, has been - returned. - - ES:DI = pointer to a map register context save area - Contains a pointer to an operating system supplied - context save area. The pointer is in standard seg- - ment:offset format. This pointer is always returned if - the expanded memory hardware does not supply alternate - mapping register sets. - - - - - - - - - EMM Functions 154 - - - - - - Function 28. Alternate Map Register Set - Get Alternate Map Register Set subfunction - - - - The operating system first passes this pointer to the - memory manager whenever it invokes a Set Alternate Map - Register Set subfunction (the description follows). If - the OS/E invokes this function before invoking a Set - Alternate Map Register Set subfunction, this function - returns a pointer value of zero. The OS/E must have - allocated the space for the save area. However, the OS - must request that the memory manager initialize the - contents of this save area before it contains any useful - information. - - The OS/E must initialize the save area it has allocated - by invoking Function 15 (Get Page Map subfunction). - After the OS/E has done this, the save area will contain - the state of all the map registers on all boards in the - system. The save area will also contain any additional - information necessary to restore the boards to their - original state when the operating system invokes a Set - Alternate Map Register Set subfunction. - - - REGISTERS MODIFIED - - AX, BX, ES:DI - - - STATUS - - AH = 0 SUCCESSFUL. - The manager got the alternate map register set. - - AH = 80h NON-RECOVERABLE. - The manager detected a malfunction in the memory manager - software. - - AH = 81h NON-RECOVERABLE. - The manager detected a malfunction in the expanded - memory hardware. - - AH = 84h NON-RECOVERABLE. - The function code passed to the memory manager is not - defined. - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - - - EMM Functions 155 - - - - - - Function 28. Alternate Map Register Set - Get Alternate Map Register Set subfunction - - - - AH = A4h NON-RECOVERABLE. - The operating system denied access to this function. - The function cannot be used at this time. - - - EXAMPLE - - alt_map_reg_set DB ? - context_save_area_ptr_seg DW ? - context_save_area_ptr_offset DW ? - - MOV AX,5B00h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler - ; on error - MOV alt_map_reg_set,BL - TEST BL,BL - JNZ no_ptr_returned - - MOV context_save_area_ptr_seg,ES ; save pointer values - MOV context_save_area_ptr_offset,DI - - no_ptr_returned: - - - - - - - - - - - - - - - - - - - - - - - - - EMM Functions 156 - - - - - - Function 28. Alternate Map Register Set - Set Alternate Map Register Set subfunction - - - - Note............................................................ - This function is for use by operating systems only. The - operating system can disable this function at any time. - Refer to Function 30 for a description of how an operating - system can enable or disable this function. - - - PURPOSE - - The subfunction does one of two things, depending on the map - register set specified: - - 1. If the alternate map register set specified is zero, map - register set zero is activated. If the map register - context restore area pointer is not equal to zero, the - contents of the restore area pointed to by ES:DI are - copied into register set zero on each expanded memory - board in the system. If the pointer is equal to zero, - the contents are not copied. - - Regardless of its value, the map register context - restore area pointer is saved within the memory manager. - It will be used during the Get Alternate Map Register - Set subfunction. - - The operating system must supply the pointer to the - area. This subfunction is intended to simulate setting - an alternate map register set. Note that the operating - system must allocate the space for the context. The - memory manager saves the context save area pointer - internally. - - 2. If the alternate map register set specified is not zero, - the alternate map register set specified is activated. - The restore area, which the operating system is pointing - to, is not used. - - - CALLING PARAMETERS - - AX = 5B01h - Contains the Set Alternate Map Register Set subfunction. - - - - - - - EMM Functions 157 - - - - - - Function 28. Alternate Map Register Set - Set Alternate Map Register Set subfunction - - - - BL = new alternate map register set number - Contains the number of the alternate map register set - which is to be activated. - - If BL <> 0 - A pointer to a map register context restore area is - not required and the contents of ES:DI is unaffected - and ignored. The alternate map register set - specified in BL is activated if the board supports - it. - - If BL = 0 - A pointer to an area which contains the state of all - the map registers on all boards in the system, and - any additional information necessary to restore the - boards to their original state, has been passed in - ES:DI. - - ES:DI = pointer to a map register context restore area - Contains a pointer to an OS/E supplied map register - context restore area. The pointer is in standard - segment:offset format. This pointer must always be - passed if the expanded memory hardware does not supply - alternate mapping register sets. - - The memory manager must save this pointer whenever the - OS/E invokes this function. The OS/E must have allo- - cated the space for the restore area. Additionally, the - contents of this restore area must have been initialized - by the memory manager before it will contain any useful - information. The OS/E initializes the restore area it - has allocated by invoking Function 15 (Get Page Map - subfunction). After the OS/E has done this, the restore - area will contain the state of the map registers on all - boards in the system, and any additional information - necessary to restore the boards to their original state - when the operating system invokes a Set Alternate Map - Register Set subfunction. - - - REGISTERS MODIFIED - - AX - - - - - - EMM Functions 158 - - - - - - Function 28. Alternate Map Register Set - Set Alternate Map Register Set subfunction - - - - STATUS - - AH = 0 SUCCESSFUL. - The manager set the alternate map register set. - - AH = 80h NON-RECOVERABLE. - The manager detected a malfunction in the memory manager - software. - - AH = 81h NON-RECOVERABLE. - The manager detected a malfunction in the expanded - memory hardware. - - AH = 84h NON-RECOVERABLE. - The function code passed to the memory manager is not - defined. - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - AH = 9Ah NON-RECOVERABLE. - Alternate map register sets are supported, but the - alternate map register set specified is not supported. - - AH = 9Ch NON-RECOVERABLE. - Alternate map register sets are not supported, and the - alternate map register set specified is not zero. - - AH = 9Dh NON-RECOVERABLE. - Alternate map register sets are supported, but the - alternate map register set specified is either not - defined or not allocated. - - AH = A3h NON-RECOVERABLE. - The contents of the source array have been corrupted, or - the pointer passed to the subfunction is invalid. - - AH = A4h NON-RECOVERABLE. - The operating system has denied access to this function. - The function cannot be used at this time. - - - - - - - - - EMM Functions 159 - - - - - - Function 28. Alternate Map Register Set - Set Alternate Map Register Set subfunction - - - - EXAMPLE - - alt_map_reg_set DB ? - context_restore_area_ptr_seg DW ? - context_restore_area_ptr_offset DW ? - - MOV AX,5B01h ; load function code - MOV BL,alt_map_reg_set - TEST BL,BL - JZ no_ptr_passed - - MOV ES,context_restore_area_ptr_seg - MOV DI,context_restore_area_ptr_offset - - no_ptr_passed: - - INT 67h ; call the memory manger - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler - ; on error - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EMM Functions 160 - - - - - - Function 28. Alternate Map Register Set - Get Alternate Map Save Array Size subfunction - - - - Note............................................................ - This function is for use by operating systems only. The - operating system can disable this function at any time. - Refer to Function 30 for a description of how an operating - system can enable or disable this function. - - - PURPOSE - - This subfunction returns the storage requirements for the - map register context save area referenced by the other - subfunctions. - - - CALLING PARAMETERS - - AX = 5B02h - Contains the Get Alternate Map Save Array Size subfunc- - tion. - - - RESULTS - - These results are valid only if the status returned is zero. - - DX = size_of_array - Contains the number of bytes that will be transferred to - the memory area supplied by an operating system whenever - an operating system requests the Get, Set, or Get and - Set subfunction. - - - REGISTERS MODIFIED - - AX, DX - - - STATUS - - AH = 0 SUCCESSFUL. - The manager has returned the array size. - - AH = 80h NON-RECOVERABLE. - The manager detected a malfunction in the memory manager - software. - - - - EMM Functions 161 - - - - - - Function 28. Alternate Map Register Set - Get Alternate Map Save Array Size subfunction - - - - AH = 81h NON-RECOVERABLE. - The manager detected a malfunction in the expanded - memory hardware. - - AH = 84h NON-RECOVERABLE. - The function code passed to the memory manager is not - defined. - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - AH = A4h NON-RECOVERABLE. - The operating system has denied access to this function. - The function cannot be used at this time. - - - EXAMPLE - - size_of_array DW ? - - MOV AX,5B02h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - MOV size_of_array,DX ; save size of array - - - - - - - - - - - - - - - - - - - - - - - - EMM Functions 162 - - - - - - Function 28. Alternate Map Register Set - Allocate Alternate Map Register Set subfunction - - - - Note............................................................ - This function is for use by operating systems only. The - operating system can disable this function at any time. - Refer to Function 30 for a description of how an operating - system can enable or disable this function. - - - PURPOSE - - The Allocate Alternate Map Register Set subfunction gets the - number of an alternate map register set for an operating - system if an alternate map register set is currently - available for use. If the hardware does not support - alternate map register sets, an alternate map register set - number of zero will be returned. - - The alternate map register set allocated may be referred to - by this number when using the Get or Set Alternate Map - Register Set subfunctions. The operating system can use - these subfunctions to switch map contexts very rapidly on - expanded memory boards with alternate map register sets. - - This subfunction copies the currently active alternate map - register set's contents into the newly allocated alternate - map register set's mapping registers. This is done so that - when the OS/E performs a Set Alternate Map Register Set - subfunction the memory mapped before the allocation of the - new alternate map will be available for reading and writing. - This function does not actually change the alternate map - register set in use, but in addition to allocating a new - alternate map register set, it prepares the new alternate - map register set for a subsequent Set Alternate Map Register - Set subfunction. - - - CALLING PARAMETERS - - AX = 5B03h - Contains the Allocate Alternate Map Register Set - subfunction. - - - - - - - - - EMM Functions 163 - - - - - - Function 28. Alternate Map Register Set - Allocate Alternate Map Register Set subfunction - - - - RESULTS - - These results are valid only if the status returned is zero. - - BL = alternate map register set number - Contains the number of an alternate map register set. - If there are no alternate map register sets supported by - the hardware, a zero will be returned. In this case, - the Get Alternate Map function (Function 28) should be - invoked in order to obtain a pointer to a map register - context save area. The OS/E must supply this area. The - save area is necessary because the hardware doesn't - support alternate map register sets. - - - REGISTERS MODIFIED - - AX, BX - - - STATUS - - AH = 0 SUCCESSFUL. - The manager has returned the alternate map register set - number. - - AH = 80h NON-RECOVERABLE. - The manager detected a malfunction in the memory manager - software. - - AH = 81h NON-RECOVERABLE. - The manager detected a malfunction in the expanded - memory hardware. - - AH = 84h NON-RECOVERABLE. - The function code passed to the memory manager is not - defined. - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - AH = 9Bh NON-RECOVERABLE. - Alternate map register sets are supported. However, all - alternate map register sets are currently allocated. - - - - - EMM Functions 164 - - - - - - Function 28. Alternate Map Register Set - Allocate Alternate Map Register Set subfunction - - - - AH = A4h NON-RECOVERABLE. - The operating system has denied access to this function. - The function cannot be used at this time. - - - EXAMPLE - - alt_map_reg_num DB ? - - MOV AX,5B03h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - MOV alt_map_reg_num,BL ; save number of - ; alternate map register set - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EMM Functions 165 - - - - - - Function 28. Alternate Map Register Set - Deallocate Alternate Map Register Set subfunction - - - - Note............................................................ - This function is for use by operating systems only. The - operating system can disable this function at any time. - Refer to Function 30 for a description of how an operating - system can enable or disable this function. - - - PURPOSE - - The Deallocate Alternate Map Register Set subfunction - returns the alternate map register set to the memory manager - for future use. The memory manager may reallocate the - alternate map register set when needed. - - This subfunction also makes the mapping context of the - alternate map register specified unavailable for reading or - writing (unmapping). This protects the pages previously - mapped in an alternate map register set by making them - inaccessible. Note that the current alternate map register - set cannot be deallocated. This makes all memory which was - currently mapped into conventional and expanded memory - inaccessible. - - - CALLING PARAMETERS - - AX = 5B04h - Contains the Deallocate Alternate Map Register Set - subfunction. - - BL = alternate register set number - Contains the number of the alternate map register set to - deallocate. Map register set zero cannot be allocated - or deallocated. However, if alternate map register set - zero is specified and this subfunction is invoked, no - error will be returned. The function invocation is - ignored in this case. - - - REGISTERS MODIFIED - - AX - - - - - - - EMM Functions 166 - - - - - - Function 28. Alternate Map Register Set - Deallocate Alternate Map Register Set subfunction - - - - STATUS - - AH = 0 SUCCESSFUL. - The manager has deallocated the alternate map register - set. - - AH = 80h NON-RECOVERABLE. - The manager detected a malfunction in the memory manager - software. - - AH = 81h NON-RECOVERABLE. - The manager detected a malfunction in the expanded - memory hardware. - - AH = 84h NON-RECOVERABLE. - The function code passed to the memory manager is not - defined. - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - AH = 9Ch NON-RECOVERABLE. - Alternate map register sets are not supported and the - alternate map register set specified is not zero. - - AH = 9Dh NON-RECOVERABLE. - Alternate map register sets are supported, but the - alternate map register set specified is either not - defined or not allocated. - - AH = A4h NON-RECOVERABLE. - The operating system has denied access to this function. - The function cannot be used at this time. - - - EXAMPLE - - alternate_map_reg_set DB ? - - MOV BL,alternate_map_reg_set ; specify alternate map - ; register set - MOV AX,5B04h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler - ; on error - - - EMM Functions 167 - - - - - - Function 28. Alternate Map Register Set - Allocate DMA Register Set subfunction - - - - Note............................................................ - This function is for use by operating systems only. The - operating system can disable this function at any time. - Refer to Function 30 for a description of how an operating - system can enable or disable this function. - - - PURPOSE - - The Allocate DMA Register Set subfunction gets the number of - a DMA register set for an OS/E, if a DMA register set is - currently available for use. If the hardware does not - support DMA register sets, a DMA register set number of zero - will be returned. - - In a multitasking operating system, when one task is waiting - for DMA to complete, it is useful to be able to switch to - another task. However, if the DMA is being mapped through - the current register set, the switching cannot occur. That - is, all DMA action must be complete before any remapping of - pages can be done. - - The operating system would initiate a DMA operation on a - specific DMA channel using a specific alternate map register - set. This alternate map register set would not be used - again, by the operating system or an application, until - after the DMA operation is complete. The operating system - guarantees this by not changing the contents of the alter- - nate map register set, or allowing an application to change - the contents of the alternate map register set, for the - duration of the DMA operation. - - - CALLING PARAMETERS - - AX = 5B05h - Contains the Allocate DMA Register Set subfunction. - - - RESULTS - - These results are valid only if the status returned is zero. - - BL = DMA register set number - Contains the number of a DMA register set. If there are - no DMA register sets supported by the hardware, a zero - will be returned. - - EMM Functions 168 - - - - - - Function 28. Alternate Map Register Set - Allocate DMA Register Set subfunction - - - - REGISTERS MODIFIED - - AX, BX - - - STATUS - - AH = 0 SUCCESSFUL. - The manager has allocated the DMA register set. - - AH = 80h NON-RECOVERABLE. - The manager detected a malfunction in the memory manager - software. - - AH = 81h NON-RECOVERABLE. - The manager detected a malfunction in the expanded - memory hardware. - - AH = 84h NON-RECOVERABLE. - The function code passed to the memory manager is not - defined. - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - AH = 9Bh NON-RECOVERABLE. - DMA register sets are supported. However, all DMA - register sets are currently allocated. - - AH = A4h NON-RECOVERABLE. - Access to this function has been denied by the operating - system. The function cannot be used at this time. - - - EXAMPLE - - DMA_reg_set_number DB ? - - MOV AX,5B05h ; load function code - INT 67h ; call memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler - ; on error - MOV DMA_reg_set_number,BL ; save number of DMA - ; register set - - - - EMM Functions 169 - - - - - - Function 28. Alternate Map Register Set - Enable DMA on Alternate Map Register Set subfunction - - - - Note............................................................ - This function is for use by operating systems only. The - operating system can disable this function at any time. - Refer to Function 30 for a description of how an operating - system can enable or disable this function. - - - PURPOSE - - This subfunction allows DMA accesses on a specific DMA - channel to be associated with a specific alternate map - register set. In a multitasking operating system, when a - task is waiting for the completion of DMA, it is useful to - be able to switch to another task until the DMA operation - completes. - - Any DMA on the specified channel will go through the speci- - fied DMA register set regardless of the current register - set. If a DMA channel is not assigned to a DMA register - set, DMA for that channel will be mapped through the current - register set. - - - CALLING PARAMETERS - - AX = 5B06h - Contains the Enable DMA on Alternate Map Register Set - subfunction. - - BL = DMA register set number - Contains the number of the alternate map register set to - be used for DMA operations on the DMA channel specified - by DL. If the alternate map register set specified is - zero, no special action will be taken on DMA accesses - for the DMA channel specified. - - DL = DMA channel number - Contains the DMA channel which is to be associated with - the DMA map register set specified in BL. - - - REGISTERS MODIFIED - - AX - - - - - EMM Functions 170 - - - - - - Function 28. Alternate Map Register Set - Enable DMA on Alternate Map Register Set subfunction - - - - STATUS - - AH = 0 SUCCESSFUL. - The manager has enabled DMA on the DMA register set and - the DMA channel specified. - - AH = 80h NON-RECOVERABLE. - The manager detected a malfunction in the memory manager - software. - - AH = 81h NON-RECOVERABLE. - The manager detected a malfunction in the expanded - memory hardware. - - AH = 84h NON-RECOVERABLE. - The function code passed to the memory manager is not - defined. - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - AH = 9Ah NON-RECOVERABLE. - Alternate DMA register sets are supported, but the - alternate DMA register set specified is not supported. - - AH = 9Ch NON-RECOVERABLE. - Alternate DMA register sets are not supported, and the - DMA register set specified is not zero. - - AH = 9Dh NON-RECOVERABLE. - DMA register sets are supported, but the DMA register - set specified is either not defined or not allocated. - - AH = 9Eh NON-RECOVERABLE. - Dedicated DMA channels are not supported. - - AH = 9Fh NON-RECOVERABLE. - Dedicated DMA channels are supported, but the DMA - channel specified is not supported. - - AH = A4h NON-RECOVERABLE. - The operating system has denied access to this function. - The function cannot be used at this time. - - - - - - EMM Functions 171 - - - - - - Function 28. Alternate Map Register Set - Enable DMA on Alternate Map Register Set subfunction - - - - EXAMPLE - - alt_map_reg_set DB ? - DMA_channel_num DB ? - - MOV BL,alt_map_reg_set - MOV DL,DMA_channel_num - MOV AX,5B06h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EMM Functions 172 - - - - - - Function 28. Alternate Map Register Set - Disable DMA on Alternate Map Register Set subfunction - - - - Note............................................................ - This function is for use by operating systems only. The - operating system can disable this function at any time. - Refer to Function 30 for a description of how an operating - system can enable or disable this function. - - - PURPOSE - - This subfunction disables DMA accesses for all DMA channels - which were associated with a specific alternate map register - set. - - - CALLING PARAMETERS - - AX = 5B07h - Contains the Disable DMA on Alternate Map Register Set - subfunction. - - BL = alternate register set number - Contains the number of the DMA register set for which - all operations are to be disabled. If the alternate map - register set specified is zero, no action will be taken. - - - REGISTERS MODIFIED - - AX - - - STATUS - - AH = 0 SUCCESSFUL. - The manager has disabled DMA operations on the alternate - DMA register set. - - AH = 80h NON-RECOVERABLE. - The manager detected a malfunction in the memory manager - software. - - AH = 81h NON-RECOVERABLE. - The manager detected a malfunction in the expanded - memory hardware. - - - - - EMM Functions 173 - - - - - - Function 28. Alternate Map Register Set - Disable DMA on Alternate Map Register Set subfunction - - - - AH = 84h NON-RECOVERABLE. - The function code passed to the memory manager is not - defined. - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - AH = 9Ah NON-RECOVERABLE. - Alternate DMA register sets are supported, but the - alternate DMA register set specified is not supported. - - AH = 9Ch NON-RECOVERABLE. - Alternate DMA register sets are not supported, and the - DMA register set specified is not zero. - - AH = 9Dh NON-RECOVERABLE. - DMA register sets are supported, but the DMA register - set specified is either not defined or not allocated. - - AH = 9Eh NON-RECOVERABLE. - Dedicated DMA channels are not supported. - - AH = 9Fh NON-RECOVERABLE. - Dedicated DMA channels are supported, but the DMA - channel specified is not supported. - - AH = A4h NON-RECOVERABLE. - The operating system has denied access to this function. - The function cannot be used at this time. - - - EXAMPLE - - DMA_reg_set DB ? - - MOV BL,DMA_reg_set - MOV AX,5B07h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - - - - - - - - - EMM Functions 174 - - - - - - Function 28. Alternate Map Register Set - Deallocate DMA Register Set subfunction - - - - Note............................................................ - This function is for use by operating systems only. The - operating system can disable this function at any time. - Refer to Function 30 for a description of how an operating - system can enable or disable this function. - - - PURPOSE - - The Deallocate DMA Register Set subfunction deallocates the - specified DMA register set. - - - CALLING PARAMETERS - - AX = 5B08h - Contains the Deallocate DMA Register Set subfunction. - - BL = DMA register set number - Contains the number of the DMA register set which should - not be used for DMA operations any longer. The DMA - register set would have been previously allocated and - enabled for DMA operations on a specific DMA channel. - If the DMA register set specified is zero, no action - will be taken. - - - REGISTERS MODIFIED - - AX - - - STATUS - - AH = 0 SUCCESSFUL. - The manager has deallocated the DMA register set. - - AH = 80h NON-RECOVERABLE. - The manager detected a malfunction in the memory manager - software. - - AH = 81h NON-RECOVERABLE. - The manager detected a malfunction in the expanded - memory hardware. - - - - - EMM Functions 175 - - - - - - Function 28. Alternate Map Register Set - Deallocate DMA on Alternate Map Register Set subfunction - - - - AH = 84h NON-RECOVERABLE. - The function code passed to the memory manager is not - defined. - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - AH = 9Ch NON-RECOVERABLE. - DMA register sets are not supported, and the DMA - register set specified is not zero. - - AH = 9Dh NON-RECOVERABLE. - DMA register sets are supported, but the DMA register - set specified is either not defined or not allocated. - - AH = A4h NON-RECOVERABLE. - The operating system has denied access to this function. - The function cannot be used at this time. - - - EXAMPLE - - DMA_reg_set_num DB ? - - MOV BL,DMA_reg_set_num - MOV AX,5B08h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - - - - - - - - - - - - - - - - - - - - EMM Functions 176 - - - - - - Function 29. Prepare Expanded Memory Hardware For Warm Boot - - - - PURPOSE - - This function prepares the expanded memory hardware for an - impending warm boot. This function assumes that the next - operation that the operating system performs is a warm boot - of the system. In general, this function will effect the - current mapping context, the alternate register set in use, - and any other expanded memory hardware dependencies which - need to be initialized at boot time. If an application - decides to map memory below 640K, the application must trap - all possible conditions leading to a warm boot and invoke - this function before performing the warm boot itself. - - - CALLING PARAMETERS - - AH = 5Ch - Contains the Prepare Expanded Memory Hardware for Warm - Boot function. - - - REGISTERS MODIFIED - - AX - - - STATUS - - AH = 0 SUCCESSFUL. - The manager has prepared the expanded memory hardware - for a warm boot. - - AH = 80h NON-RECOVERABLE. - The manager detected a malfunction in the memory manager - software. - - AH = 81h NON-RECOVERABLE. - The manager detected a malfunction in the expanded - memory hardware. - - AH = 84h NON-RECOVERABLE. - The function code passed to the memory manager is not - defined. - - - - - - - EMM Functions 177 - - - - - - Function 29. Prepare Expanded Memory Hardware for Warm Boot - - - - EXAMPLE - - MOV AH,5Ch ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EMM Functions 178 - - - - - - Function 30. Enable/Disable OS/E Function Set Functions - Enable OS/E Function Set subfunction - - - - Note............................................................ - This function is for use by operating systems only. The - operating system can disable this function at any time. - - - PURPOSE - - This subfunction provides an OS/E with the ability to enable - all programs or device drivers to use the OS/E specific - functions. The capability is provided only for an OS/E - which manages regions of mappable conventional memory and - cannot permit programs to use any of the functions which - affect mappable conventional memory regions, but must be - able to use these functions itself. When an OS/E disables - these functions and a program attempts to use them, the - memory manager returns a status to the program indicating - that the OS/E has denied the program access to the function. - In other words, the functions will not work when disabled. - However, all programs may use them when enabled. - - The OS/E (Operating System/Environment) functions this - subfunction enables are: - - Function 26. Get Expanded Memory Hardware Information. - Function 28. Alternate Map Register Sets. - Function 30. Enable/Disable Operating System Functions. - - It appears contradictory that the OS/E can re-enable these - functions when the function which re-enables them is itself - disabled. An overview of the process follows. - - The memory manager enables all the OS/E specific functions, - including this one, when it is loaded. The OS/E gets - exclusive access to these functions by invoking either of - the Enable/Disable OS/E Function Set subfunctions before any - other software does. - - On the first invocation of either of these subfunctions, the - memory manager returns an access_key which the OS/E must use - in all future invocations of either of these subfunctions. - The memory manager does not require the access_key on the - first invocation of the Enable/Disable OS/E Function Set - subfunctions. - - - - - - EMM Functions 179 - - - - - - Function 30. Enable/Disable OS/E Function Set Functions - Enable OS/E Function Set subfunction - - - - On all subsequent invocations, the access_key is required - for either the Enable or Disable OS/E Function Set subfunc- - tions. Since the access_key is returned only on the first - invocation of the Enable/Disable OS/E Function Set subfunc- - tions, and presumably the OS/E is the first software to - invoke this function, only the OS/E obtains a copy of this - key. The memory manager must return an access key with a - random value, a fixed value key defeats the purpose of - providing this level of security for an OS/E. - - - CALLING PARAMETERS - - AX = 5D00h - Contains the Enable OS/E Function Set subfunction. - - BX,CX = access_key - Required on all function invocations after the first. - The access_key value returned by the first function - invocation is required. - - - RESULTS - - These results are valid only if the status returned is zero. - - BX,CX = access_key - Returned only on the first function invocation, the - memory manager returns a random valued key which will be - required thereafter for the execution of this function. - On all invocations after the first, this key is not - returned. Neither BX nor CX is affected after the first - time this function is invoked. - - - REGISTERS MODIFIED - - AX, BX, CX - - - STATUS - - AH = 0 SUCCESSFUL. - The operating system function set has been enabled. - - - - - EMM Functions 180 - - - - - - Function 30. Enable/Disable OS/E Function Set Functions - Enable OS/E Function Set subfunction - - - - AH = 80h NON-RECOVERABLE. - The manager detected a malfunction in the memory manager - software. - - AH = 81h NON-RECOVERABLE. - The manager detected a malfunction in the expanded - memory hardware. - - AH = 84h NON-RECOVERABLE. - The function code passed to the memory manager is not - defined. - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - AH = A4h NON-RECOVERABLE. - The operating system has denied access to this function. - The function cannot be used at this time. The value of - the key which was passed to this function does not - entitle the program to execute this function. - - - EXAMPLE - - First invocation - - access_key DW 2 DUP (?) - - MOV AX,5D00h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - MOV access_key[0],BX - MOV access_key[2],CX - - - All invocations after the first - - access_key DW 2 DUP (?) - - MOV BX,access_key[0] - MOV CX,access_key[2] - MOV AX,5D00h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - - - EMM Functions 181 - - - - - - Function 30. Enable/Disable OS/E Function Set Functions - Disable OS/E Function Set subfunction - - - - Note............................................................ - This function is for use by operating systems only. The - operating system can disable this function at any time. - - - PURPOSE - - This subfunction provides an OS/E with the ability to - disable all programs or device drivers from using the OS/E - specific functions. The capability is provided only for an - OS/E which manages regions of mappable conventional memory - and cannot permit programs to use any of the functions which - would affect mappable conventional memory regions. When an - OS/E disables these functions and a program attempts to use - them, the memory manager returns a status to the program - indicating that the OS/E has denied the program access to - the function. In other words, the functions will not work - when disabled. - - The OS/E (Operating System) functions which are disabled by - this subfunction are: - - Function 26. Get Expanded Memory Hardware Information. - Function 28. Alternate Map Register Sets. - Function 30. Enable/Disable Operating System Functions. - - - CALLING PARAMETERS - - AX = 5D01h - Contains the Disable OS/E Function Set subfunction. - - BX,CX = access_key - Required on all function invocations after the first. - The access_key value returned by the first function - invocation is required. - - - - - - - - - - - - - EMM Functions 182 - - - - - - Function 30. Enable/Disable OS/E Function Set Functions - Disable OS/E Function Set subfunction - - - - RESULTS - - These results are valid only if the status returned is zero. - - BX,CX = access_key - Returned only on the first function invocation, the - memory manager returns a random valued key which will be - required thereafter for the execution of this function. - On all invocations after the first, this key is not - returned. Neither BX nor CX is affected after the first - time this function is invoked. - - - REGISTERS MODIFIED - - AX, BX, CX - - - STATUS - - AH = 0 SUCCESSFUL. - The operating system function set has been disabled. - - AH = 80h NON-RECOVERABLE. - The manager detected a malfunction in the memory manager - software. - - AH = 81h NON-RECOVERABLE. - The manager detected a malfunction in the expanded - memory hardware. - - AH = 84h NON-RECOVERABLE. - The function code passed to the memory manager is not - defined. - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - AH = A4h NON-RECOVERABLE. - The operating system has denied access to this function. - The function cannot be used at this time. The value of - the key which was passed to this function does not - entitle the program to execute this function. - - - - - - EMM Functions 183 - - - - - - Function 30. Enable/Disable OS/E Function Set Functions - Disable OS/E Function Set subfunction - - - - EXAMPLE - - First Function invocation - - access_key DW 2 DUP (?) - - MOV AX,5D01h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - MOV access_key[0],BX - MOV access_key[2],CX - - - All invocations after the first - - access_key DW 2 DUP (?) - - MOV BX,access_key[0] - MOV CX,access_key[2] - MOV AX,5D01h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - - - - - - - - - - - - - - - - - - - - - - - - - EMM Functions 184 - - - - - - Function 30. Enable/Disable OS/E Function Set Functions - Return Access Key subfunction - - - - Note............................................................ - This function is for use by operating systems only. The - operating system can disable this function at any time. - - - PURPOSE - - This subfunction provides an OS/E with the ability to return - the access key to the memory manager. Returning the access - key to the memory manager places the memory manager in the - state it is in at installation time (regarding the use of - the OS/E function set and the access key). That is, access - to the OS/E function set is enabled. Upon execution of the - next enable/disable OS/E function set subfunction, the - access key will once again be returned. - - - CALLING PARAMETERS - - AX = 5D02h - Contains the Return Access Key subfunction. - - BX,CX = access_key - Required on all function invocations. The access_key - value returned by the first function invocation of the - enable or disable subfunctions is required. - - - REGISTERS MODIFIED - - AX - - - STATUS - - AH = 0 SUCCESSFUL. - The access key has been returned to the memory manager. - - AH = 80h NON-RECOVERABLE. - The manager detected a malfunction in the memory manager - software. - - AH = 81h NON-RECOVERABLE. - The manager detected a malfunction in the expanded - memory hardware. - - - - EMM Functions 185 - - - - - - Function 30. Enable/Disable OS/E Function Set Functions - Return Access Key subfunction - - - - AH = 84h NON-RECOVERABLE. - The function code passed to the memory manager is not - defined. - - AH = 8Fh NON-RECOVERABLE. - The subfunction parameter is invalid. - - AH = A4h NON-RECOVERABLE. - The operating system has denied access to this function. - The function cannot be used at this time. The value of - the key which was passed to this function does not - entitle the program to execute this function. - - - EXAMPLE - - access_key DW 2 DUP (?) - - MOV BX,access_key[0] - MOV CX,access_key[2] - MOV AX,5D02h ; load function code - INT 67h ; call the memory manager - OR AH,AH ; check EMM status - JNZ emm_err_handler ; jump to error handler on error - - - - - - - - - - - - - - - - - - - - - - - - - EMM Functions 186 - - - - - - Appendix A - FUNCTION AND STATUS CODE CROSS REFERENCE TABLES - - - - This appendix contains two cross reference tables: one - lists the function codes and the status codes they return; - the other lists the status codes and the functions that - return them. - - - Table A-1. Function and Status Code Cross Reference - ---------------------------------------------------------------- - - Function Status Description - - ---------------------------------------------------------------- - - 40h 00h, 80h, 81h, 84h Get Memory Manager Status - - 41h 00h, 80h, 81h, 84h Get Page Frame Segment Address - - 42h 00h, 80h, 81h, 84h Get Unallocated Page Count - - 43h 00h, 80h, 81h, 84h Allocate Pages - 85h, 87h, 88h, 89h - - 44h 00h, 80h, 81h, 83h Map/Unmap Handle Page - 84h, 8Ah, 8Bh - - 45h 00h, 80h, 81h, 83h Deallocate Pages - 84h, 86h - - 46h 00h, 80h, 81h, 84h Get EMM Version - - 47h 00h, 80h, 81h, 83h Save Page Map - 84h, 8Ch, 8Dh - - 48h 00h, 80h, 81h, 83h Restore Page Map - 84h, 8Eh - - 49h Reserved - - 4Ah Reserved - - 4Bh 00h, 80h, 81h, 84h Get EMM Handle Count - - 4Ch 00h, 80h, 81h, 83h Get EMM Handle Pages - 84h - - 4Dh 00h, 80h, 81h, 84h Get All EMM Handle Pages - - - Cross Reference Tables 187 - - - - - - Table A-1. Function and Status Code Cross Reference (continued) - ---------------------------------------------------------------- - - Function Status Description - - ---------------------------------------------------------------- - - 4E00h 00h, 80h, 81h, 84h Get Page Map - 8Fh - - 4E01h 00h, 80h, 81h, 84h Set Page Map - 8Fh, A3h - - 4E02h 00h, 80h, 81h, 84h Get & Set Page Map - 8Fh, A3h - - 4E03h 00h, 80h, 81h, 84h Get Size of Page Map Save Array - 8Fh - - 4F00h 00h, 80h, 81h, 84h Get Partial Page Map - 8Bh, 8Fh, A3h - - 4F01h 00h, 80h, 81h, 84h Set Partial Page Map - 8Fh, A3h - - 4F02h 00h, 80h, 81h, 84h Get Size of Partial Page Map Array - 8Bh, 8Fh - - 5000h 00h, 80h, 81h, 83h Map/Unmap Multiple Handle Pages - 84h, 8Ah, 8Bh, 8Fh (physical page number mode) - - 5001h 00h, 80h, 81h, 83h Map/Unmap Multiple Handle Pages - 84h, 8Ah, 8Bh, 8Fh (segment address mode) - - 51h 00h, 80h, 81h, 83h Reallocate Pages - 84h, 87h, 88h - - 5200h 00h, 80h, 81h, 83h Get Handle Attribute - 84h, 8Fh, 91h - - 5201h 00h, 80h, 81h, 83h Set Handle Attribute - 84h, 8Fh, 90h, 91h - - 5202h 00h, 80h, 81h, 84h Get Handle Attribute Capability - 8Fh - - 5300h 00h, 80h, 81h, 83h Get Handle Name - 84h, 8Fh - - 5301h 00h, 80h, 81h, 83h Set Handle Name - 84h, 8Fh, A1h - - - Cross Reference Tables 188 - - - - - - Table A-1. Function and Status Code Cross Reference (continued) - ---------------------------------------------------------------- - - Function Status Description - - ---------------------------------------------------------------- - - 5400h 00h, 80h, 81h, 84h Get Handle Directory - 8Fh - - 5401h 00h, 80h, 81h, 84h Search for Named Handle - 8Fh, A0h, A1h - - 5402h 00h, 80h, 81h, 84h Get Total Handles - 8Fh - - 5500h 00h, 80h, 81h, 83h Alter Page Map & Jump (Physical - 84h, 8Ah, 8Bh, 8Fh page mode) - - 5501h 00h, 80h, 81h, 83h Alter Page Map & Jump (Segment - 84h, 8Ah, 8Bh, 8Fh address mode) - - 5600h 00h, 80h, 81h, 83h Alter Page Map & Call (Physical - 84h, 8Ah, 8Bh, 8Fh page mode) - - 5601h 00h, 80h, 81h, 83h Alter Page Map & Call (Segment - 84h, 8Ah, 8Bh, 8Fh address mode) - - 5602h 00h, 80h, 81h, 84h Get Alter Page Map & Call Stack - 8Fh Space Size - - 5700h 00h, 80h, 81h, 83h Move Memory Region - 84h, 8Ah, 8Fh, 92h - 93h, 94h, 95h, 96h - 98h, A2h - - 5701h 00h, 80h, 81h, 83h Exchange Memory Region - 84h, 8Ah, 8Fh, 93h - 94h, 95h, 96h, 97h - 98h, A2h - - 5800h 00h, 80h, 81h, 84h Get Mappable Physical Address - 8Fh Array - - 5801h 00h, 80h, 81h, 84h Get Mappable Physical Address - 8Fh Array Entries - - 5900h 00h, 80h, 81h, 84h Get Expanded Memory Hardware - 8Fh, A4h Information - - 5901h 00h, 80h, 81h, 84h Get Unallocated Raw Page Count - 8Fh - - Cross Reference Tables 189 - - - - - - Table A-1. Function and Status Code Cross Reference (continued) - ---------------------------------------------------------------- - - Function Status Description - - ---------------------------------------------------------------- - - 5A00h 00h, 80h, 81h, 84h Allocate Standard Pages - 85h, 87h, 88h, 8Fh - - 5A01h 00h, 80h, 81h, 84h Allocate Raw Pages - 85h, 87h, 88h, 8Fh - - 5B00h 00h, 80h, 81h, 84h Get Alternate Map Register Set - 8Fh, A4h - - 5B01h 00h, 80h, 81h, 84h Set Alternate Map Register Set - 8Fh, 9Ah, 9Ch, 9Dh - A3h, A4h - - 5B02h 00h, 80h, 81h, 84h Get Alternate Map Save Array Size - 8Fh, A4h - - 5B03h 00h, 80h, 81h, 84h Allocate Alternate Map Register - 8Fh, 9Bh, A4h Set - - 5B04h 00h, 80h, 81h, 84h Deallocate Alternate Map Register - 8Fh, 9Ch, 9Dh, A4h Set - - 5B05h 00h, 80h, 81h, 84h Allocate DMA Register Set - 8Fh, 9Bh, A4h - - 5B06h 00h, 80h, 81h, 84h Enable DMA on Alternate Map - 8Fh, 9Ah, 9Ch, 9Dh Register Set - 9Eh, 9Fh, A4h - - 5B07h 00h, 80h, 81h, 84h Disable DMA on Alternate Map - 8Fh, 9Ah, 9Ch, 9Dh Register Set - 9Eh, 9Fh, A4h - - 5B08h 00h, 80h, 81h, 84h Deallocate DMA Register Set - 8Fh, 9Ch, 9Dh, A4h - - 5Ch 00h, 80h, 81h, 84h Prepare Expanded Memory Hardware - for Warmboot - - 5D00h 00h, 80h, 81h, 84h Enable Operating System Function - 8Fh, A4h Set - - 5D01h 00h, 80h, 81h, 84h Disable Operating System Function - 8Fh, A4h Set - - - Cross Reference Tables 190 - - - - - - Table A-1. Function and Status Code Cross Reference (continued) - ---------------------------------------------------------------- - - Function Status Description - - ---------------------------------------------------------------- - - 5D02h 00h, 80h, 81h, 84h Return Operating System Access Key - 8Fh, A4h - ---------------------------------------------------------------- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cross Reference Tables 191 - - - - - - Table A-2. Status and Function Code Cross Reference - ---------------------------------------------------------------- - - Status Function Description - - ---------------------------------------------------------------- - - 00h All The function completed normally. - - 80h All The memory manager has detected a - malfunction in the expanded memory - software. A condition has been - detected which would not have - occurred if the memory manager had - been operating correctly. - - 81h All The memory manager has detected a - malfunction in the expanded memory - hardware. A condition has been - detected which would not occur if the - memory hardware were working correct- - ly. Diagnostics should be run on the - expanded memory system to determine - the source of the problem. - - 82h None This error code is not returned in - version 3.2 of the memory manager or - above. In earlier versions of the - memory manager this code meant a - "busy" status. This status indicated - that the memory manager was already - processing an expanded memory request - when the current request was made and - is unable to process another request. - In versions 3.2 of the memory manager - and above, the memory manager is - never "busy" and can always honor - requests. - - 83h 44h, 45h, 47h, 48h The memory manager can not find the - 4Ch, 5000h, 5001h handle specified. The program has - 51h, 5200h, 5201h probably corrupted its specified - 5300h, 5301h handle. The memory manager does not - 5500h, 5501h have any information pertaining to - 5600h, 5601h the specified handle. The program - 5700h, 5701h has probably corrupted its handle. - - 84h All The function code passed to the - manager is not currently defined. - Function codes in the range 40h - through 5Dh are currently defined. - - - Cross Reference Tables 192 - - - - - - Table A-2. Status and Function Code Cross Reference (continued) - ---------------------------------------------------------------- - - Status Function Description - - ---------------------------------------------------------------- - - 85h 43h, 5A00h, 5A01h No handles are currently available. - All assignable handles are currently - in use. The program may re-request - the assignment of a handle in the - hope that another program has - released a handle. The maximum - number of handles that may be - supported is 255. - - 86h 45h A mapping context restoration error - has been detected. This error occurs - when a program attempts to return a - handle and there is still a "mapping - context" on the context stack for the - indicated handle. A program can - recover from this error by restoring - the mapping context before returning - the handle. - - 87h 43h, 51h, 5A00h, The number of total pages that are - 5A01h available in the system is insuffi- - cient to honor the request. The - program can recover from this - condition by requesting fewer pages. - - 88h 43h, 51h, 5A00h, The number of unallocated pages - 5A01h currently available is insufficient - to honor the allocation request. The - program can recover from this - condition by re-posting the request - or by requesting fewer pages. - - 89h 43h A Function 4 (Allocate Pages) request - has been made specifying zero pages. - Zero pages cannot be assigned to a - handle with Function 4 (Allocate - Pages). If it is necessary to assign - zero pages to a handle, Function 27 - (Allocate Standard Pages and Allocate - Raw Pages subfunctions) may be used. - - - - - - - Cross Reference Tables 193 - - - - - - Table A-2. Status and Function Code Cross Reference (continued) - ---------------------------------------------------------------- - - Status Function Description - - ---------------------------------------------------------------- - - 8Ah 44h, 5000h, 5001h The logical page to map into memory - 5500h, 5501h is out of the range of logical pages - 5600h, 5601h which are allocated to the handle. - 5700h, 5701h The program can recover from this - condition by attempting to map a - logical page which is within the - bounds for the handle. - - 8Bh 44h, 4F00h, 4F02h One or more of the physical pages is - 5000h, 5001h out of the range of allowable - 5600h, 5601h physical pages. Physical page - 5500h, 5501 numbers are numbered zero-relative. - The program can recover from this - condition by mapping at a physical - page which is in the range from zero - to three. - - 8Ch 47h The mapping register context save - area is full. The program can - recover from this condition by - attempting to save the mapping - registers again. - - 8Dh 47h The mapping register context stack - already has a context associated with - the handle. The program has at- - tempted to save the mapping register - context when there was already a - context for the handle on the stack. - The program can recover from this - condition by not attempting to save - the context again (this assumes the - mapping register context on the stack - for the handle is correct). - - - - - - - - - - - - - Cross Reference Tables 194 - - - - - - Table A-2. Status and Function Code Cross Reference (continued) - ---------------------------------------------------------------- - - Status Function Description - - ---------------------------------------------------------------- - - 8Eh 48h The mapping register context stack - does not have a context associated - with the handle. The program has - attempted to restore the mapping - register context when there was no - context for the handle on the stack. - The program can recover from this - condition by not attempting to - restore the context again (this - assumes the current mapping register - context is correct). - - 8Fh All functions The subfunction parameter passed to - requiring the function is not defined. - subfunction codes - - 90h 5201h The attribute type is undefined. - - 91h 5200h, 5201h The system configuration does not - support non-volatility. - - 92h 5700h The source and destination expanded - memory regions have the same handle - and overlap. This is valid for a - move. The move has been completed - and the destination region has a full - copy of the source region. However, - at least a portion of the source - region has been overwritten by the - move. Note that the source and - destination expanded memory regions - with different handles will never - physically overlap because the - different handles specify totally - different regions of expanded memory. - - - - - - - - - - - - Cross Reference Tables 195 - - - - - - Table A-2. Status and Function Code Cross Reference (continued) - ---------------------------------------------------------------- - - Status Function Description - - ---------------------------------------------------------------- - - 93h 5700h, 5701h The length of the specified source or - destination expanded memory region - exceeds the length of the expanded - memory region allocated to the - specified source or destination - handle. There are insufficient pages - allocated to this handle to move/ex- - change a region of the size speci- - fied. The program can recover from - this condition by attempting to - allocate additional pages to the - destination or source handle or by - reducing the specified length. - However, if the application program - has allocated as much expanded memory - as it thought it needed, this may be - a program error and is therefore not - recoverable. - - 94h 5700h, 5701h The conventional memory region and - expanded memory region overlap. This - is invalid, the conventional memory - region cannot overlap the expanded - memory region. - - 95h 5700h, 5701h The offset within the logical page - exceeds the length of the logical - page. The initial source or destina- - tion offsets within an expanded - memory region must be between 0 and - the (length of a logical page - 1) or - 16383 (3FFFh). - - 96h 5700h, 5701h Region length exceeds 1M-byte limit. - - - - - - - - - - - - - Cross Reference Tables 196 - - - - - - Table A-2. Status and Function Code Cross Reference (continued) - ---------------------------------------------------------------- - - Status Function Description - - ---------------------------------------------------------------- - - 97h 5701h The source and destination expanded - memory regions have the SAME handle - AND overlap. This is invalid; the - source and destination expanded - memory regions cannot have the same - handle and overlap when they are - being exchanged. Note that the - source and destination expanded - memory regions with different handles - will never physically overlap because - the different handles specify totally - different regions of expanded memory. - - 98h 5700h, 5701h The memory source and destination - types are undefined/not supported. - - 9Ah 5B01h, 5B06h Alternate map register sets are - 5B07h supported, but the alternate map - register set specified is not - supported. - - 9Bh 5B03h, 5B05h Alternate map/DMA register sets are - supported. However, all alternate - map/DMA register sets are currently - allocated. - - 9Ch 5B01h, 5B04h Alternate map/DMA register sets are - 5B06h, 5B07h not supported, and the alternate - 5B08h map/DMA register set specified is not - zero. - - 9Dh 5B01h, 5B04h Alternate map/DMA register sets are - 5B06h, 5B07h supported, but the alternate map - 5B08h register set specified is not - defined, not allocated, or is the - currently allocated map register set. - - 9Eh 5B06h, 5B07h Dedicated DMA channels are not - supported. - - 9Fh 5B06h, 5B07h Dedicated DMA channels are supported. - But the DMA channel specified is not - supported. - - - - Cross Reference Tables 197 - - - - - - Table A-2. Status and Function Code Cross Reference (continued) - ---------------------------------------------------------------- - - Status Function Description - - ---------------------------------------------------------------- - - A0h 5401h No corresponding handle value could - be found for the handle name speci- - fied. - - A1h 5301h, 5401h A handle with this name already - exists. The specified handle was not - assigned a name. - - A2h 5700h, 5701h An attempt was made to "wrap around" - the 1M-byte address space during the - move/exchange. The source starting - address together with the length of - the region to be moved/exchanged - exceeds 1M bytes. No data was - moved/exchanged. - - A3h 4E01h, 4E02h The contents of the data structure - 4F00h, 4F01h passed to the function have either - 5B01h been corrupted or are meaningless. - - A4h 5900h, 5B00h The operating system has denied - 5B01h, 5B02h access to this function. The - 5B03h, 5B04h function cannot be used at this time. - 5B05h, 5B06h - 5B07h, 5B08h - 5D00h, 5D01h - 5D02h - - ---------------------------------------------------------------- - - - - - - - - - - - - - - - - - - Cross Reference Tables 198 - - - - - - Appendix B - TESTING FOR THE PRESENCE OF THE EXPANDED MEMORY MANAGER - - - - Before an application program can use the Expanded Memory - Manager, it must determine whether DOS has loaded the - manager. This appendix describes two methods your program - can use to test for the presence of the memory manager and - how to choose the correct one for your situation. - - The first method uses the DOS "open handle" technique; the - second method uses the DOS "get interrupt vector" technique. - - - Which method should your program use? - - The majority of application programs can use either the - "open handle" or the "get interrupt vector" method. - However, if your program is a device driver or if it - interrupts DOS during file system operations, you must use - only the "get interrupt vector" method. - - Device drivers execute from within DOS and can't access the - DOS file system; programs that interrupt DOS during file - system operations have a similar restriction. During their - interrupt processing procedures, they can't access the DOS - file system because another program may be using the system. - Since the "get interrupt vector" method doesn't require the - DOS file system, you must use it for these types of pro- - grams. - - - The "open handle" technique - - Most application programs can use the DOS "open handle" - technique to test for the presence of the memory manager. - This section describes how to use the technique and gives an - example. - - Caution......................................................... - Don't use this technique if your program is a device driver - or if it interrupts DOS during file system operations. Use - the "get interrupt vector" technique described later in this - appendix. - - - Using the "open handle" technique - - This section describes how to use the DOS "open handle" - technique to test for the presence of the memory manager. - Follow these steps in order: - - Testing For The Presence Of The EMM 199 - - - - - - 1. Issue an "open handle" command (DOS function 3Dh) in - "read only" access mode (register AL = 0). This - function requires your program to point to an ASCII - string which contains the path name of the file or - device in which you're interested (register set DS:DX - contains the pointer). In this case the file is - actually the name of the memory manager. - - You should format the ASCII string as follows: - - ASCII_device_name DB 'EMMXXXX0', 0 - - The ASCII codes for the capital letters EMMXXXX0 are - terminated by a byte containing a value of zero. - - 2. If DOS returns no error status code, skip Steps 3 and 4 - and go to Step 5. If DOS returns a "Too many open - files" error status code, go to Step 3. If DOS returns - a "File/Path not found" error status code, skip Step 3 - and go to Step 4. - - 3. If DOS returns a "Too many open files" (not enough - handles) status code, your program should invoke the - "open file" command before it opens any other files. - This will guarantee that at least one file handle will - be available to perform the function without causing - this error. - - After the program performs the "open file" command, it - should perform the test described in Step 6 and close - the "file handle" (DOS function 3Eh). Don't keep the - manager "open" after this status test is performed since - "manager" functions are not available through DOS. Go - to Step 6. - - 4. If DOS returns a "File/Path not found," the memory - manager is not installed. If your application requires - the memory manager, the user will have to reboot the - system with a disk containing the memory manager and the - appropriate CONFIG.SYS file before proceeding. - - 5. If DOS doesn't return an error status code you can - assume that either a device with the name EMMXXXX0 is - resident in the system, or a file with this name is on - disk in the current disk drive. Go to Step 6. - - 6. Issue an "I/O Control for Devices" command (DOS function - 44h) with a "get device information" command (register - AL = 0). DOS function 44h determines whether EMMXXXX0 - is a device or a file. - - - - Testing For The Presence Of The EMM 200 - - - - - - You must use the file handle (register BX) which you - obtained in Step 1 to access the "EMM" device. - - This function returns the "device information" in a word - (register DX). Go to Step 7. - - 7. If DOS returns any error status code, you should assume - that the memory manager device driver is not installed. - If your application requires the memory manager, the - user will have to reboot the system with a disk contain- - ing the memory manager and the appropriate CONFIG.SYS - file before proceeding. - - 8. If DOS didn't return an error status, test the contents - of bit 7 (counting from 0) of the "device information" - word (register DX) the function returned. Go to Step 9. - - 9. If bit 7 of the "device information" word contains a - zero, then EMMXXXX0 is a file, and the memory manager - device driver is not present. If your application - requires the memory manager, the user will have to - reboot the system with a disk containing the memory - manager and the appropriate CONFIG.SYS file before - proceeding. - - If bit 7 contains a one, then EMMXXXX0 is a device. Go - to Step 10. - - 10. Issue an "I/O Control for Devices" command (DOS function - 44h) with a "get output status" command (register AL = - 7). - - You must use the file handle you obtained in Step 1 to - access the "EMM" device (register BX). Go to Step 11. - - 11. If the expanded memory device driver is "ready," the - memory manager passes a status value of "FFh" in - register AL. The status value is "00h" if the device - driver is "not ready." - - If the memory manager device driver is "not ready" and - your application requires its presence, the user will - have to reboot the system with a disk containing the - memory manager and the appropriate CONFIG.SYS file - before proceeding. - - If the memory manager device driver is "ready," go to - Step 12. - - - - - - Testing For The Presence Of The EMM 201 - - - - - - 12. Issue a "Close File Handle" command (DOS function 3Eh) - to close the expanded memory device driver. You must - use the file handle you obtained in Step 1 to close the - "EMM" device (register BX). - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Testing For The Presence Of The EMM 202 - - - - - - An example of the "open handle" technique - - The following procedure is an example of the "open handle" - technique outlined in the previous section. - - ;--------------------------------------------------------------; - ; The following procedure tests for the presence of the ; - ; EMM in the system. It returns the CARRY FLAG SET if ; - ; the EMM is present. If the EMM is not present, this ; - ; procedure returns the CARRY FLAG CLEAR. ; - ;--------------------------------------------------------------; - - first_test_for_EMM PROC NEAR - PUSH DS - PUSH CS - POP DS - MOV AX,3D00h ; issue "device open" in - LEA DX,ASCII_device_name ; "read only" mode - INT 21h - JC first_test_for_EMM_error_exit ; test for error - ; during "device open" - MOV BX,AX ; get the "file - ; handle" returned by DOS - MOV AX,4400h ; issue "IOCTL - INT 21h ; get device info" - JC first_test_for_EMM_error_exit ; test for error - ; during "get device info" - TEST DX,0080h ; test to determine - JZ first_test_for_EMM_error_exit ; ASCII_device_name - ; is a device or a file - MOV AX,4407h ; issue "IOCTL" - INT 21h - JC first_test_for_EMM_error_exit ; test for error - ; during "IOCTL" - PUSH AX ; save "IOCTL" status - MOV AH,3Eh ; issue "close - INT 21h ; file handle" - POP AX ; restore "IOCTL" status - CMP AL,0FFh ; test for "device - JNE first_test_for_EMM_error_exit ; ready" status - ; returned by the driver - first_test_for_EMM_exit: - POP DS ; EMM is present - STC ; in the system - RET - - first_test_for_EMM_error_exit: - POP DS ; EMM is NOT present - CLC ; in the system - RET - ASCII_device_name DB 'EMMXXXX0', 0 - first_test_for_EMM ENDP - - Testing For The Presence Of The EMM 203 - - - - - - The "get interrupt vector" technique - - Any type of program can use the DOS "get interrupt vector" - technique to test for the presence of the memory manager. - This section describes how to use the technique and gives an - example. - - Caution......................................................... - Be sure to use this technique (and not the "open handle" - technique) if your program is a device driver or if it - interrupts DOS during file system operations. - - - Using the "get interrupt vector" technique - - This section describes how to use the DOS "get interrupt - vector" technique to test for the presence of the memory - manager. Follow these steps in order: - - 1. Issue a "get vector" command (DOS function 35h) to - obtain the contents of interrupt vector array entry - number 67h (addresses 0000:019Ch thru 0000:019Fh). - - The memory manager uses this interrupt vector to perform - all manager functions. The offset portion of this - interrupt service routine address is stored in the word - located at address 0000:019Ch; the segment portion is - stored in the word located at address 0000:019Eh. - - 2. Compare the "device name field" with the contents of the - ASCII string which starts at the address specified by - the segment portion of the contents of interrupt vector - address 67h and a fixed offset of 000Ah. If DOS loaded - the memory manager at boot time this name field will - have the name of the device in it. - - Since the memory manager is implemented as a character - device driver, its program origin is 0000h. Device - drivers are required to have a "device header" located - at the program origin. Within the "device header" is an - 8 byte "device name field." For a character mode device - driver this name field is always located at offset 000Ah - within the device header. The device name field - contains the name of the device which DOS uses when it - references the device. - - If the result of the "string compare" in this technique - is positive, the memory manager is present. - - - - - - Testing For The Presence Of The EMM 204 - - - - - - An example of the "get interrupt vector" technique - - The following procedure is an example of the "get interrupt - vector" technique outlined in the previous section. - - - ;--------------------------------------------------------------; - ; The following procedure tests for the presence of the ; - ; EMM in the system. It returns the CARRY FLAG SET if ; - ; the EMM is present. If the EMM is not present, this ; - ; procedure returns the CARRY FLAG CLEAR. ; - ;--------------------------------------------------------------; - - - second_test_for_EMM PROC NEAR - PUSH DS - PUSH CS - POP DS - MOV AX,3567h ; issue "get interrupt - ; vector" - INT 21h - MOV DI,000Ah ; use the segment in ES - ; returned by DOS, place - ; the "device name field" - ; OFFSET in DI - LEA SI,ASCII_device_name ; place the OFFSET of the - ; device name string in SI, - ; the SEGMENT is already - ; in DS - MOV CX,8 ; compare the name strings - CLD - REPE CMPSB - JNE second_test_for_EMM_error_exit - - second_test_for_EMM_exit: - POP DS ; EMM is present in - STC ; the system - RET - - second_test_for_EMM_error_exit: - POP DS ; EMM is NOT present - CLC ; in the system - RET - - ASCII_device_name DB 'EMMXXXX0' - second_test_for_EMM ENDP - - - - - - - - Testing For The Presence Of The EMM 205 - - - - - - Appendix C - EXPANDED MEMORY MANAGER IMPLEMENTATION GUIDELINES - - - - In addition to the functional specification, the expanded - memory manager should provide certain resources. The - following guidelines are provided so required resources are - present in expanded memory managers which comply with this - version of the LIM specification. - - o The amount of expanded memory supported: - Up to a maximum of 32M bytes of expanded memory should - be supported. - - o The number of handles supported: - The maximum number of expanded memory handles provided - should be 255, the minimum should be 64. - - o Handle Numbering: - Although a handle is a word quantity, there is a maximum - of 255 handles, including the operating system handle. - This specification defines the handle word as follows: - the low byte of the word is the actual handle value, the - high byte of the handle is set to 00h by the memory - manager. Previous versions of this specification did - not specify the value of handles. - - o New handle type: Handles versus Raw Handles: - The difference between a raw handle and a regular handle - is slight. If you use Function 27 to "Allocate raw - pages to a handle," what is returned in DX is termed a - raw handle. The raw handle does not necessarily refer - to 16K-byte pages. Instead it refers to the "raw" page - size, which depends on the expanded memory hardware. - - An application program can use Function 26 to find the - raw page size, and by using the raw handle Function 27 - returns, it can access them with the finer resolution - that a particular expanded memory board may allow. - - On the other hand, applications which use Function 4 to - "allocate pages to handle" receive a handle which always - refers to 16K-byte pages. On expanded memory boards - with smaller raw pages, the EMM driver will allocate and - maintain the number of raw pages it takes to create a - single composite 16K-byte page. The difference between - the expanded memory boards' raw page size and the 16K- - byte LIM page size is transparent to the application - when it is using a handle obtained with Function 4. - - - - EMM Implementation Guidelines 206 - - - - - - The memory manager must differentiate between pages - allocated to handles and pages allocated to raw handles. - The meaning of a call to the driver changes depending on - whether a handle or a raw handle is passed to the memory - manager. If, for example, a handle is passed to - Function 18 (Reallocate), the memory manager will - increase or decrease the number of 16K-byte pages - allocated to the handle. If Function 18 is passed a raw - handle, the memory manager will increase or decrease the - number of raw (non-16K-byte) pages allocated to the raw - handle. For LIM standard boards, there is no difference - between pages and raw pages. - - o The system Raw Handle (Raw Handle = 0000h): - For expanded memory boards that can remap the memory in - the lower 640K-byte address space, managing the pages of - memory which are used to fill in the lower 640K can be a - problem. To solve this problem, the memory manager will - create a raw handle with a value of 0000h when DOS loads - the manager. This raw handle is called the system - handle. - - At power up, the memory manager will allocate all of the - pages that are mapped into the lower 640K bytes to the - system handle. These pages should be mapped in their - logical order. For example, if the system board - supplies 256K bytes of RAM, and the 384K bytes above it - is mappable, the system handle should have its logical - page zero mapped into the first physical page at 256K, - its logical page one mapped into the next physical page, - and so on. - - The system handle should deal with raw pages. To - release some of these pages so application programs can - use them, an operating system could decrease the number - of pages allocated to the system handle with the - "Reallocate" function. Invoking the "Deallocate" - function would decrease the system handle to zero size, - but it must not deallocate the raw handle itself. The - "Deallocate" function treats the system handle dif- - ferently than it treats other raw handles. If the - operating system can ever be "exited" (for example, the - way Windows can be exited), it must increase the size of - the system handle back to what is needed to fill 640K - and map these logical pages back into physical memory - before returning to DOS. - - - - - - - - EMM Implementation Guidelines 207 - - - - - - There are two functional special cases for this handle: - - - The first special case deals with Function 4 - (Allocate Pages). This function must never return - zero as a handle value. Applications must always - invoke Function 4 to allocate pages and obtain a - handle which identifies its pages. Since Function 4 - will never return a handle value of zero, an - application will never gain access to this special - handle. - - - The second special case deals with Function 6 - (Deallocate Pages). If the operating system uses - Function 6 to deallocate the pages which are - allocated to the system handle, the pages will be - returned to the manager for use, but the handle will - not be available for reassignment. The manager - should treat a "deallocate pages" function request - for this handle the same as a "reallocate pages" - function request, where the number of pages to - reallocate to this handle is zero. - - o Terminate and Stay Resident (TSR) Program Cooperation: - In order for TSR's to cooperate with each other and with - other applications, TSR's must follow this rule: a - program may only remap the DOS partition it lives in. - This rule applies at all times, even when no expanded - memory is present. - - o Accelerator Cards: - To support generic accelerator cards, the support of - Function 34, as defined by AST, is encouraged. - - - - - - - - - - - - - - - - - - - - - - EMM Implementation Guidelines 208 - - - - - - Appendix D - OPERATING SYSTEM/ENVIRONMENT USE OF FUNCTION 28 - - - - All expanded memory boards have a set of registers that - "remember" the logical to physical page mappings. Some - boards have extra (or alternate) sets of these mapping - registers. Because no expanded memory board can supply an - infinite number of alternate map register sets, this - specification provides a way to simulate them using Function - 28 (Alternate Map Register Set). - - - Examples - - For the examples in this section, assume the hardware - supports alternate map register sets. First Windows is - brought up, then "Reversi" is started. Then control is - switched back to the MS-DOS Executive. For this procedure, - here are the calls to the expanded memory manager: - - Example 1 - - Allocate alt reg set ; Start up the MS-DOS - (for MS-DOS Executive) ; Executive - - Set alt reg set - (for MS-DOS Executive) - - Allocate alt reg set ; Start up Reversi - (for Reversi) - - Set alt reg set - (for Reversi) - - Map pages - (for Reversi) - - Set alt ret set ; Switch back to MS-DOS - (for MS-DOS Executive) ; Executive - - - - - - - - - - - - - Operating System Use Of Function 28 209 - - - - - - Notice this procedure needed no "get" calls because the - register set contained all the information needed to save a - context. However, using "Get" calls would have no ill - effects. - - Example 2 - - Allocate alt reg set ; Start up MS-DOS - (for MS-DOS Executive) ; Executive - - Set alt reg set - (for MS-DOS Executive) - - Get alt reg set - (for MS-DOS Executive) - - Allocate alt reg set ; Start up Reversi - (for Reversi) - - Set alt reg set - (for Reversi) - - Map pages - (for Reversi) - - Get alt reg set - (for Reversi) - - Set alt reg set ; Switch back to MS-DOS - (for MS-DOS Executive) ; Executive - - The important point to follow is that a Set must always - precede a Get. The model of Set then Get is the inverse of - what interrupt handlers use, which is Get then Set (Get the - old map context and Set the new one). Another crucial point - is that an alternate map register set must have the current - mapping when allocated; otherwise, the Set will create - chaos. - - What happens if this is simulated in software? The same Set - and Get model applies. The main difference is where the - context is saved. - - - - - - - - - - - - Operating System Use Of Function 28 210 - - - - - - Since the allocate call is dynamic and there is no limit on - the number of sets allocated, the OS/E must supply the space - required. Device drivers cannot allocate space dynamically, - since the request would fail. If the Allocate register set - call returns a status indicating the alternate map register - sets aren't supported, the OS/E must allocate space for the - context. It must also initialize the context using Function - 15. At that point it can do the Set, passing a pointer to - the map context space. On the Get call, the EMM driver is - to return a pointer to the same context space. - - Example 3 - - Allocate alt reg set ; Start up MS-DOS - (for MS-DOS Executive) ; Executive - - Get Page Map - (for MS-DOS Executive) - - Set alt reg set - (for MS-DOS Executive) - - Allocate alt reg set ; Start up Reversi - (for Reversi) - - Set alt reg set - (for Reversi) - - Map pages - (for Reversi) - - Get Page Map - (for Reversi) - - Set alt ret set ; Switch back to MS-DOS - (for MS-DOS Executive) ; Executive - - - - - - - - - - - - - - - - - - Operating System Use Of Function 28 211 - - - - - - GLOSSARY - - - - The following terms are used frequently in this specifica- - tion: - - - Allocate To reserve a specified amount of - expanded memory pages. - - Application Program An application program is the program - you write and your customer uses. Some - categories of application software are - word processors, database managers, - spreadsheet managers, and project - managers. - - Conventional memory The memory between 0 and 640K bytes, - address range 00000h thru 9FFFFh. - - Deallocate To return previously allocated expanded - memory to the memory manager. - - EMM See Expanded Memory Manager. - - Expanded memory Expanded memory is memory outside DOS's - 640K-byte limit (usually in the range of - C0000h thru EFFFFh). - - Expanded Memory A device driver that controls the - Manager (EMM) interface between DOS application - programs and expanded memory. - - Extended memory The 15M-byte address range between - 100000h thru FFFFFFh available on an - 80286 processor when it is operating in - protected virtual address mode. - - Handle A value that the EMM assigns and uses to - identify a block of memory requested by - an application program. All allocated - logical pages are associated with a - particular handle. - - Logical Page The EMM allocates expanded memory in - units (typically 16K bytes) called - logical pages. - - Mappable Segment A 16K-byte region of memory which can - have a logical page mapped at it. - - - Glossary 212 - - - - - - Map Registers The set of registers containing the - current mapping context of the EMM - hardware. - - Mapping The process of making a logical page of - memory appear at a physical page. - - Mapping Context The contents of the mapping registers at - a specific instant. This context - represents a map state. - - Page Frame A collection of 16K-byte contiguous - physical pages from which an application - program accesses expanded memory. - - Page Frame A page frame base address is the - Base Address location (in segment format) of the - first byte of the page frame. - - Physical Page A physical page is the range of memory - addresses occupied by a single 16K-byte - page. - - Raw Page The smallest unit of mappable memory - that an expanded memory board can - supply. - - Resident Application A resident application program is loaded - Program by DOS, executes, and remains resident - in the system after it returns control - to DOS. This type of program occupies - memory and is usually invoked by the - operating system, an application - program, or the hardware. Some example - of resident application programs are RAM - disks, print spoolers, and "pop-up" - desktop programs. - - Status code A code that an EMM function returns - which indicates something about the - result of running the function. Some - status codes indicate whether the - function worked correctly and others may - tell you something about the expanded - memory hardware or software. - - - - - - - - - Glossary 213 - - - - - - Transient Application A transient application program is - Program loaded by DOS, executes, and doesn't - remain in the system after it returns - control to DOS. After a transient - application program returns control to - DOS, the memory it used is available for - other programs. - - Unmap To make a logical page inaccessible for - reading or writing. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Glossary 214 - - - - - - INDEX - - - - Allocate Alternate Map Register Set 36, 163 - Allocate DMA Register Set 36, 168, 190 - Allocate Pages 5, 14, 23, 30, 34, 42, 43, 47, 49, 144, - 147, 148, 193, 206, 208 - Allocate Raw Pages 36, 46, 80, 89, 147-149, 190, 193, - 206 - Allocate Standard Pages 36, 42, 46, 80, 89, 144, 145, - 147, 190, 193 - Alter Page Map & Call 7, 10, 35, 113, 118, 189 - Alter Page Map & Jump 7, 10, 35, 109, 189 - Alternate Map 10, 36, 151, 153-155, 157-159, 161, 163, - 164, 165-168, 170, 173, 175, 179, 182, 190, 197, - 209, 210, 211 - Alternate Map Register Set 10, 36, 151, 153-155, 157, - 158, 159, 161, 163-168, 170, 173, 175, 190, 197, - 209, 210 - Alternate Mapping and Unmapping Methods 81 - Alternate Register 139, 166, 173, 177 - Data Aliasing 12 - Deallocate Alternate Map Register Set 36, 166 - Deallocate DMA Register Set 36, 175, 190 - Deallocate Pages 5, 14, 25, 31, 34, 43, 49, 88, 145, - 148, 208 - Design Considerations 91, 151 - Device Driver 1, 15, 43, 53, 55, 144, 148, 199, 201, - 202, 204, 212 - Disable DMA on Alternate Map Register Set 173 - Disable OS/E Function Set 36, 179, 180, 182, 185 - DMA 36, 138-140, 151, 152, 168-176, 190, 197 - DMA Channels 139, 171, 173, 174, 197 - DMA Register 36, 139, 140, 151, 152, 168-171, 173-176, - 190, 197 - DOS 1, 12, 14, 15, 19, 21, 30, 31, 49, 53, 88, 199-205, - 207-214 - Enable DMA on Alternate Map Register Set 170 - Enable OS/E Function Set 36, 179, 180 - Enable/Disable OS/E Function Set 179, 180, 182, 185 - Exchange Memory Region 7, 10, 35, 120, 126, 127, 189 - Expanded Memory Support of DMA 151 - Expanded Memory Support of DMA Register Sets 151 - Extended Memory 91 - Function 1 37 - Function 10 57 - Function 11 58 - Function 12 59 - Function 13 61 - Function 14 7, 63 - - - Index 215 - - - - - - Function 15 13, 53, 55, 65, 67, 69, 71, 73, 76, 139, - 153, 154, 155, 158, 211 - Function 16 13, 73, 76, 78 - Function 17 6, 80, 82, 85 - Function 18 6, 43, 88, 144, 148, 207 - Function 19 7, 91, 92, 94, 96 - Function 2 4, 38 - Function 20 7, 98, 100 - Function 21 7, 42, 102, 105, 107 - Function 22 109 - Function 23 113, 118 - Function 24 7, 120, 126 - Function 25 6, 8, 46, 74, 85, 132, 136 - Function 26 138, 142, 179, 182, 206 - Function 27 42, 46, 80, 89, 144, 145, 147-149, 193, 206 - Function 28 140, 151, 153, 157, 161, 163, 164, 166, - 168, 170, 173, 175, 179, 182, 209 - Function 29 177 - Function 3 4, 40, 142 - Function 30 138, 151, 153, 157, 161, 163, 166, 168, - 170, 173, 175, 179, 182, 185 - Function 4 4, 42, 43, 46, 47, 49, 80, 89, 144, 145, - 147, 149, 193, 206, 208 - Function 5 4, 46, 81 - Function 6 4, 43, 49, 88, 145, 148, 208 - Function 7 5, 51 - Function 8 46, 50, 53, 55 - Function 9 46, 50, 53, 55 - Get & Set Page Map 35, 69 - Get All Handle Pages 9, 34, 63 - Get Alternate Map Register Set 36, 153, 154, 157, 190 - Get Alternate Map Save Array Size 36, 161, 190 - Get Attribute Capability 7, 96 - Get Expanded Memory Hardware Information 10, 138, 142, - 179, 182 - Get Handle Attribute 35, 92 - Get Handle Count 9, 34, 59 - Get Handle Directory 10, 35, 102, 105, 107 - Get Handle Name 35, 98 - Get Handle Pages 7, 9, 34, 61 - Get Hardware Configuration Array 36, 138 - Get Interrupt Vector 15, 21, 30, 199, 204, 205 - Get Mappable Physical Address Array 6, 8, 10, 35, 46, - 85, 132, 136 - Get Mappable Physical Address Array Entries 8, 136 - Get Page Frame Address 5, 34, 38 - Get Page Map 35, 65, 118, 153-155, 158, 211 - Get Page Map Stack Space Size 35, 118 - Get Partial Page Map 35, 73, 78 - Get Size of Page Map Save Array 35, 65, 67, 71, 139 - Get Size of Partial Page Map Save Array 74, 76, 78 - Get Status 5, 34, 37 - - Index 216 - - - - - - Get Total Handles 35, 107 - Get Unallocated Page Count 5, 22, 34, 40, 142 - Get Unallocated Raw Page Count 36, 142, 189 - Get Version 5, 34, 51 - Get/Set Handle Attribute 9, 91, 92, 94, 96 - Get/Set Handle Name 10, 98, 100 - Get/Set Page Map 9, 13, 65, 67, 69, 71 - Get/Set Partial Page Map 9, 13, 73, 76, 78 - Handle Attribute 9, 35, 91-94, 96, 188 - Handle Name 6, 7, 10, 35, 98, 100, 105, 106, 188, 198 - Intel i, ii, 1, 5, 57, 58 - Interrupt Vector 12, 15, 21, 30, 199, 204, 205 - LIM 1, 7, 13, 19, 27, 53, 55, 138, 140, 206, 207 - Logical Page 1, 5, 12, 16, 19, 23, 28, 31, 32, 46-48, - 80-83, 85, 86, 88, 110, 111, 115, 116, 120, 122, - 123, 125, 126, 128, 129, 131, 147, 194, 196, 207, - 212-214 - Logical Page/Physical Page Method 82 - Logical Page/Segment Address Method 85 - Lotus i, ii, 1, 5, 57, 58 - Map Register 10, 13, 36, 53, 55, 151, 153-155, 157-159, - 161, 163-168, 170, 173, 175, 179, 182, 190, 197, - 209-211 - Map/Unmap Handle Pages 46 - Map/Unmap Multiple Handle Pages 9, 35, 80, 82, 85 - Mapping and Unmapping Multiple Pages Simultaneously 80 - Mapping Multiple Pages 6, 80 - Microsoft i, ii, 1, 5, 14, 30, 42, 57, 58, 144, 148 - Move Memory Region 35, 120, 121, 189 - Move/Exchange Memory Region 7, 10, 120, 126 - Open Handle 64, 102, 199, 200, 203, 204 - Operating System 3, 8, 10-12, 42, 43, 59, 63, 107, 138, - 139, 141, 142, 144-151, 153-159, 161-163, 165-171, - 173-177, 179-183, 185, 186, 190, 191, 198, 206, - 207-209, 213 - Page Frame 1-6, 14, 17-19, 24, 28, 31, 34, 38, 39, 47, - 53, 55, 121, 128, 133, 187, 213 - Page Map 7, 9, 10, 13, 34, 35, 50, 53, 55, 65, 67, 69, - 71, 73-76, 78, 109, 113, 118, 139, 153-155, 158, - 187, 188, 189, 211 - Page Mapping Register I/O Array 57 - Page Translation Array 58 - Physical Page 1, 5, 6, 8, 10, 12, 16, 23, 28, 31, 35, - 46, 47, 48, 80-83, 85, 109-112, 114-117, 132-134, - 136, 138, 139, 142, 147, 188, 194, 207, 209, 213 - Prepare Expanded Memory Hardware For Warm Boot 10, 177 - Raw Handle 147, 149, 150, 206, 207 - Raw Page 36, 142, 143, 147, 189, 206 - Reallocate Pages 9, 35, 43, 88, 144, 145, 148, 208 - Restore Page Map 9, 13, 34, 50, 53, 55 - Return Access Key 185 - Save Page Map 9, 13, 34, 50, 53, 55 - - Index 217 - - - - - - Search For Named Handle 7, 35, 105 - Set Alternate Map Register Set 36, 153-155, 157, 158, - 163, 190 - Set Handle Attribute 9, 35, 91, 92, 94, 96 - Set Handle Name 7, 10, 35, 98, 100 - Set Page Map 9, 13, 35, 65, 67, 69, 71, 188 - Set Partial Page Map 9, 13, 35, 73, 76, 78 - Standard Handle 146 - Standard Page 147 - System DMA Capabilities 151 - TSR 12, 13, 208 - Unmapping Multiple Pages 6, 80 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Index 218 - - MµpALLINFO.TXT -Following are BBSes that are members of DV-NET. DV-Net is an informal -network of BBS's that carry files that would be useful to DESQview users. -Not all BBSes that carry the DESQview conference are members of DV-Net. - -All address are NetMail addresses. - - ---------------------------------------------- - DVNet DESQview Support File Network - ---------------------------------------------- - DESQview is a trademark of Quarterdeck Office Systems - ----------------------------------------------------------- - DVNet is not affiliated with Quarterdeck Office Systems - ---------------------------------------------------------------- - - Name, City and State NetAddress Telephone Maxbaud - ------------------------------- ---------- ------------ ------- - *65'North, Fairbanks, AK 1:17/38 907-452-1460 9600HSTV32 - Opus 386, Davis, CA 1:203/910 916-753-6321 2400 - Carl's Corner, San Jose, CA 1:10/1 408-248-9704 9600HSTV32 - Carl's Corner, San Jose, CA 1:10/2 408-248-0198 2400 - SeaHunt BBS, Burlingame, CA 1:125/20 415-344-4348 9600HST - Stingray!, Clovis CA 1:205/12 209-298-9461 9600HST - SF PCUG BBS, San Francisco CA 1:1/310 415-621-2609 9600HSTV32RE - Bink of an Aye, Portland, OR 1:105/42 503-297-9043 9600PEPV32MO - P C Support, Portland, OR 1:105/66 503-297-9078 2400 - Atarian BBS, Portland, OR 1:105/10 503-245-9730 9600HSTV32 - Busker's BoneYard, Portland,OR 1:105/14 503-771-4773 9600PEP - Busker's Boneyard, Portland,OR 1:105/41 503-775-7926 9600HSTV32 - Pacifier BBS, Vancouver, WA 1:105/103 206-253-9770 9600HSTV32 - Puget Sound Gtwy., Puyallup, WA 1:138/3 206-566-8854 9600HST - Rampart General,Kansas City,MO 1:280/6 816-761-4039 9600HST - Oregon Trail XRoads, Casper WY 1:303/5 307-472-3615 9600H96 - Dawg Byte, Nashville, TN 1:116/29 615-385-4268 9600HST - Dickson County, Dickson, TN 1:116/25 615-446-4475 2400 - Programmers' Attic, Will., MI 1:159/850 517-655-3347 2400 - Dark Side Of the Moon,Savoy IL 1:233/493 217-356-6922 9600HSTV32 - Ecclesia Place, Monroeville, PA 1:129/75 412-373-8612 9600HST - The Other BBS, Harrisburg PA 1:270/101 717-657-2223 9600HST - IBM Tech Fido, Pepperell, MA 1:322/1 508-433-8452 9600HSTV32 - Waystar BBS, Marlborough, MA 1:322/14 508-481-7147 9600HST - Andromeda Galaxy, Troy NY 1:267/167 518-273-8313 9600HST - Treasure Island, Danbury, CT 1:141/730 203-791-8532, 9600HST - Addict's Attic,Germantown MD 1:109/423 301-428-8998 9600HST - Maple Shade Opus,Maple Shade NJ 1:266/12 609-482-8604 9600HSTV32 - Capital City , Burlington NJ 99:9230/1 609-386-1989 9600HSTV32 - Capital City , Burlington NJ 8:950/10 609-386-1989 9600HSTV32 - Southern Cross BBS, Miami FL 1:135/69 305-220-8752 9600HST - Software Designer, Albany, GA 1:3617/1 912-432-2440 9600HSTV32 - Software Designer, Albany, GA 8:928/1 912-432-2440 9600HSTV32 - Dragon's Lair, Galveston, TX 1:386/451 409-762-2761 9600HST - Dragon's Lair, Galveston, TX 1:386/1451 409-762-7456 2400MNP - Conch Opus, Houston, TX 1:106/357 713-667-7213 2400PCP - Inns of Court, Dallas, TX 1:124/6101 214-458-2620 9600HSTV32 - Dallas Email, Dallas, TX 8:930/101 214-358-1205 9600HSTV32MO - Spare Parts, Bedford, TX 1:130/38 817-540-3527 9600HST - QE2, Austin TX 1:382/58 512-328-1229 2400 - Ned's Opus HST Ottawa,ON Canada 1:163/211 613-523-8965 9600HST - Ned's Opus, Ottawa ON Canada 1:163/210 613-731-8132 2400 - Imperial Terran, St Cath,ON 1:247/102 416-646-7105 9600HST - Arcane BBS, Laval PQ Canada 1:167/116 514-687-9586 9600HST - Zone 2 & Zone 3 - ------------------------------ --------- ------------- ------- - The HEKOM Board (Netherlands) 2:286/3 31-3483-4072 2400MNP5 - BBS_D.C.V.V., Maaseik (Belgium) 2:295/26 32-11-568620 \ No newline at end of file diff --git a/16/PCGPE10/MIDI.TXT b/16/PCGPE10/MIDI.TXT deleted file mode 100644 index 14e5d273..00000000 --- a/16/PCGPE10/MIDI.TXT +++ /dev/null @@ -1,5939 +0,0 @@ - - Standard MIDI File Format - Dustin Caldwell - - The standard MIDI file format is a very strange beast. When viewed as a -whole, it can be quite overwhelming. Of course, no matter how you look at it, -describing a piece of music in enough detail to be able to reproduce it -accurately is no small task. So, while complicated, the structure of the midi -file format is fairly intuitive when understood. - I must insert a disclaimer here that I am by no means an expert with -midi nor midi files. I recently obtained a Gravis UltraSound board for my PC, -and upon hearing a few midi files (.MID) thought, "Gee, I'd like to be able to -make my own .MID files." Well, many aggravating hours later, I discovered that -this was no trivial task. But, I couldn't let a stupid file format stop me. -(besides, I once told my wife that computers aren't really that hard to use, -and I'd hate to be a hypocrite) So if any errors are found in this -information, please let me know and I will fix it. Also, this document's scope -does not extend to EVERY type of midi command and EVERY possible file -configuration. It is a basic guide that should enable the reader (with a -moderate investment in time) to generate a quality midi file. - -1. Overview - - A midi (.MID) file contains basically 2 things, Header chunks and Track -chunks. Section 2 explains the header chunks, and Section 3 explains the track -chunks. A midi file contains ONE header chunk describing the file format, -etc., and any number of track chunks. A track may be thought of in the same -way as a track on a multi-track tape deck. You may assign one track to each -voice, each staff, each instrument or whatever you want. - -2. Header Chunk - - The header chunk appears at the beginning of the file, and describes the -file in three ways. The header chunk always looks like: - -4D 54 68 64 00 00 00 06 ff ff nn nn dd dd - -The ascii equivalent of the first 4 bytes is MThd. After MThd comes the 4-byte -size of the header. This will always be 00 00 00 06, because the actual header -information will always be 6 bytes. - -ff ff is the file format. There are 3 formats: - -0 - single-track -1 - multiple tracks, synchronous -2 - multiple tracks, asynchronous - -Single track is fairly self-explanatory - one track only. Synchronous multiple -tracks means that the tracks will all be vertically synchronous, or in other -words, they all start at the same time, and so can represent different parts -in one song. Asynchronous multiple tracks do not necessarily start at the same -time, and can be completely asynchronous. - -nn nn is the number of tracks in the midi file. - -dd dd is the number of delta-time ticks per quarter note. (More about this -later) - - -3. Track Chunks - -The remainder of the file after the header chunk consists of track chunks. -Each track has one header and may contain as many midi commands as you like. -The header for a track is very similar to the one for the file: - -4D 54 72 6B xx xx xx xx - -As with the header, the first 4 bytes has an ascii equivalent. This one is -MTrk. The 4 bytes after MTrk give the length of the track (not including the -track header) in bytes. - Following the header are midi events. These events are identical to the -actual data sent and received by MIDI ports on a synth with one addition. A -midi event is preceded by a delta-time. A delta time is the number of ticks -after which the midi event is to be executed. The number of ticks per quarter -note was defined previously in the file header chunk. This delta-time is a -variable-length encoded value. This format, while confusing, allows large -numbers to use as many bytes as they need, without requiring small numbers to -waste bytes by filling with zeros. The number is converted into 7-bit bytes, -and the most-significant bit of each byte is 1 except for the last byte of the -number, which has a msb of 0. This allows the number to be read one byte at a -time, and when you see a msb of 0, you know that it was the last (least -significant) byte of the number. According to the MIDI spec, the entire delta- -time should be at most 4 bytes long. - Following the delta-time is a midi event. Each midi event (except a -running midi event) has a command byte which will always have a msb of 1 (the -value will be >= 128). A list of most of these commands is in appendix A. Each -command has different parameters and lengths, but the data that follows the -command will have a msb of 0 (less than 128). The exception to this is a meta- -event, which may contain data with a msb of 1. However, meta-events require a -length parameter which alleviates confusion. - One subtlety which can cause confusion is running mode. This is where -the actual midi command is omitted, and the last midi command issued is -assumed. This means that the midi event will consist of a delta-time and the -parameters that would go to the command if it were included. - -4. Conclusion - - If this explanation has only served to confuse the issue more, the -appendices contain examples which may help clarify the issue. Also, 2 -utilities and a graphic file should have been included with this document: - -DEC.EXE - This utility converts a binary file (like .MID) to a tab-delimited -text file containing the decimal equivalents of each byte. - -REC.EXE - This utility converts a tab-delimited text file of decimal values -into a binary file in which each byte corresponds to one of the decimal -values. - -MIDINOTE.PS - This is the postscript form of a page showing note numbers with -a keyboard and with the standard grand staff. - Appendix A - -1. MIDI Event Commands - -Each command byte has 2 parts. The left nybble (4 bits) contains the actual -command, and the right nybble contains the midi channel number on which the -command will be executed. There are 16 midi channels, and 8 midi commands (the -command nybble must have a msb of 1). -In the following table, x indicates the midi channel number. Note that all -data bytes will be <128 (msb set to 0). - -Hex Binary Data Description -8x 1000xxxx nn vv Note off (key is released) - nn=note number - vv=velocity - -9x 1001xxxx nn vv Note on (key is pressed) - nn=note number - vv=velocity - -Ax 1010xxxx nn vv Key after-touch - nn=note number - vv=velocity - -Bx 1011xxxx cc vv Control Change - cc=controller number - vv=new value - -Cx 1100xxxx pp Program (patch) change - pp=new program number - -Dx 1101xxxx cc Channel after-touch - cc=channel number - -Ex 1110xxxx bb tt Pitch wheel change (2000H is normal or no - change) - bb=bottom (least sig) 7 bits of value - tt=top (most sig) 7 bits of value - The following table lists meta-events which have no midi channel number. They -are of the format: - -FF xx nn dd - -All meta-events start with FF followed by the command (xx), the length, or -number of bytes that will contain data (nn), and the actual data (dd). - -Hex Binary Data Description -00 00000000 nn ssss Sets the track's sequence number. - nn=02 (length of 2-byte sequence number) - ssss=sequence number - -01 00000001 nn tt .. Text event- any text you want. - nn=length in bytes of text - tt=text characters - -02 00000010 nn tt .. Same as text event, but used for - copyright info. - nn tt=same as text event - -03 00000011 nn tt .. Sequence or Track name - nn tt=same as text event - -04 00000100 nn tt .. Track instrument name - nn tt=same as text event - -05 00000101 nn tt .. Lyric - nn tt=same as text event - -06 00000110 nn tt .. Marker - nn tt=same as text event - -07 00000111 nn tt .. Cue point - nn tt=same as text event - -2F 00101111 00 This event must come at the end of each - track - -51 01010001 03 tttttt Set tempo - tttttt=microseconds/quarter note - -58 01011000 04 nn dd ccbb Time Signature - nn=numerator of time sig. - dd=denominator of time sig. 2=quarter - 3=eighth, etc. - cc=number of ticks in metronome click - bb=number of 32nd notes to the quarter - note - -59 01011001 02 sf mi Key signature - sf=sharps/flats (-7=7 flats, 0=key of C, - 7=7 sharps) - mi=major/minor (0=major, 1=minor) - -7F 01111111 xx dd .. Sequencer specific information - xx=number of bytes to be sent - dd=data -The following table lists system messages which control the entire system. -These have no midi channel number. (these will generally only apply to -controlling a midi keyboard, etc.) - -Hex Binary Data Description -F8 11111000 Timing clock used when synchronization is - required. - -FA 11111010 Start current sequence - -FB 11111011 Continue a stopped sequence where left - off - -FC 11111100 Stop a sequence - - -The following table lists the numbers corresponding to notes for use in note -on and note off commands. - - -Octave|| Note Numbers - # || - || C | C# | D | D# | E | F | F# | G | G# | A | A# | B ------------------------------------------------------------------------------ - 0 || 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 - 1 || 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 - 2 || 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 - 3 || 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 - 4 || 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 - 5 || 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 - 6 || 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 - 7 || 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 - 8 || 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 - 9 || 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 - 10 || 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | - - - BIBLIOGRAPHY - - "MIDI Systems and Control" Francis Rumsey 1990 Focal Press - - "MIDI and Sound Book for the Atari ST" Bernd Enders and Wolfgang Klemme - 1989 M&T Publishing, Inc. - - MIDI file specs and general MIDI specs were also obtained by sending e-mail - to LISTSERV@AUVM.AMERICAN.EDU with the phrase GET MIDISPEC PACKAGE - in the message. - - -------------------------------- DEC.CPP ------------------------------------ - -/* file dec.cpp - -by Dustin Caldwell (dustin@gse.utah.edu) - -*/ - - -#include -#include -#include - -void helpdoc(); - -main() -{ - FILE *fp; - - unsigned char ch, c; - - if((fp=fopen(_argv[1], "rb"))==NULL) /* open file to read */ - { - printf("cannot open file %s\n",_argv[1]); - helpdoc(); - exit(-1); - } - - c=0; - ch=fgetc(fp); - - while(!feof(fp)) /* loop for whole file */ - { - printf("%u\t", ch); /* print every byte's decimal equiv. */ - c++; - if(c>8) /* print 8 numbers to a line */ - { - c=0; - printf("\n"); - } - - ch=fgetc(fp); - } - - fclose(fp); /* close up */ -} - -void helpdoc() /* print help message */ -{ - printf("\n Binary File Decoder\n\n"); - - printf("\n Syntax: dec binary_file_name\n\n"); - - printf("by Dustin Caldwell (dustin@gse.utah.edu)\n\n"); - printf("This is a filter program that reads a binary file\n"); - printf("and prints the decimal equivalent of each byte\n"); - printf("tab-separated. This is mostly useful when piped \n"); - printf("into another file to be edited manually. eg:\n\n"); - printf("c:\>dec sonata3.mid > son3.txt\n\n"); - printf("This will create a file called son3.txt which can\n"); - printf("be edited with any ascii editor. \n\n"); - printf("(rec.exe may also be useful, as it reencodes the \n"); - printf("ascii text file).\n\n"); - printf("Have Fun!!\n"); -} - ----------------------------- REC.CPP ---------------------------------- - -/* File rec.cpp - by Dustin Caldwell (dustin@gse.utah.edu) -*/ - -#include -#include -#include -#include - -void helpdoc(); - -main() -{ - FILE *rfp, *wfp; - - unsigned char ch, c; - char s[20]; - - if((rfp=fopen(_argv[1], "r"))==NULL) /* open the read file */ - { - printf("cannot open file %s \n",_argv[1]); - helpdoc(); - exit(-1); - } - - if((wfp=fopen(_argv[2], "wb"))==NULL) /* open the write file */ - { - printf("cannot open file %s \n",_argv[1]); - helpdoc(); - exit(-1); - } - - c=0; - - ch=fgetc(rfp); - - while(!feof(rfp)) /* loop for whole file */ - { - - if(isalnum(ch)) /* only 'see' valid ascii chars */ - { - c=0; - while(isdigit(ch)) /* only use decimal digits (0-9) */ - { - s[c]=ch; /* build a string containing the number */ - c++; - ch=fgetc(rfp); - } - s[c]=NULL; /* must have NULL terminator */ - - fputc(atoi(s), wfp);/* write the binary equivalent to file */ - - } - - ch=fgetc(rfp); /* loop until next number starts */ - - - } - - fclose(rfp); /* close up */ - fclose(wfp); -} - - -void helpdoc() /* print help message */ -{ - printf("\n Text File Encoder\n\n"); - - printf("\n Syntax: rec text_file_name binary_file_name\n\n"); - - printf("by Dustin Caldwell (dustin@gse.utah.edu)\n\n"); - printf("This is a program that reads an ascii tab-\n"); - printf("delimited file and builds a binary file where\n"); - printf("each byte of the binary file is one of the decimal\n"); - printf("digits in the text file.\n"); - printf(" eg:\n\n"); - printf("c:\>rec son3.txt son3.mid\n\n"); - printf("(This will create a file called son3.mid which is\n"); - printf("a valid binary file)\n\n"); - printf("(dec.exe may also be useful, as it decodes binary files)\n\n"); - printf("Have Fun!!\n"); -} - ------------------------------ MIDIFILE.PS --------------------------------- -%-12345X@PJL ENTER LANGUAGE = POSTSCRIPT -%!PS-Adobe -/wpdict 120 dict def -wpdict begin -/bdef {bind def} bind def - -/bflg false def -/Bfont 0 def -/bon false def - -/psz 0 def -/_S /show load def -/_t {0 rmoveto} bdef - -/_pixelsnap - {transform .25 sub round .25 add - exch .25 sub round .25 add exch itransform - } bdef -/_pixeldsnap - { dtransform round exch round exch idtransform } bdef - -/_lt {_pixelsnap lineto} bdef -/_rlt {_pixeldsnap rlineto} bdef -/_mt {_pixelsnap moveto} bdef -/_rmt {_pixeldsnap rmoveto} bdef - -/bshow {gsave psz 30 div 0 _rmt dup show grestore show} bdef - -/DUx 0 def -/DUy 0 def -/hscl 0 def - -/M {_mt - 2 mul -2 2 - { -2 roll 0 _rmt _S } for - } bdef - -/makeoutl - { dup /OutlineFlag known not - { dup dup length 2 add dict begin - {1 index /FID ne { def }{ pop pop } ifelse } forall - /UniqueID known {/UniqueID UniqueID 10000 add def} if - /PaintType PaintType 0 eq { 2 }{ PaintType } ifelse def - /StrokeWidth 15 def - /OutlineFlag true def - /OutlineFont currentdict end definefont - } if - } bdef - -/nbuff 50 string def -/orntsv 0 def -/plen 0 def -/pwid 0 def -/picstr 1 string def - -/WPencoding StandardEncoding 256 array copy def 0 - [ 127/Aacute/Acircumflex/Adieresis/Agrave/Aring/Atilde/Ccedilla - /Delta/Eacute/Ecircumflex/Edieresis/Egrave/Eth/Gamma/Iacute - /Icircumflex/Idieresis/Igrave/Lambda/Ntilde/Oacute - /Ocircumflex/Odieresis/Ograve/Omega/Otilde/Phi/Pi/Psi - /Scaron/Sigma/TeXtext32/Theta/Thorn - 209/Uacute/Ucircumflex/Udieresis/Ugrave/Upsilon/Xi/Yacute - /Ydieresis/Zcaron/aacute/acircumflex/adieresis/agrave - /aring/atilde/brokenbar - 228/ccedilla/copyright/degree/divide - 236/dotlessj/eacute/ecircumflex/edieresis/egrave - 242/eth/ff/ffi - 246/ffl/iacute - 252/icircumflex/idieresis/igrave/logicalnot - 1/minus/mu/multiply/ntilde/oacute/ocircumflex/odieresis - /ograve/onehalf/onequarter/onesuperior/otilde/plusminus - /registered/scaron/thorn/threequarters/threesuperior - /trademark/twosuperior/uacute/ucircumflex/udieresis - /ugrave/yacute/ydieresis/zcaron -] -{ dup type /nametype eq - { WPencoding 2 index 2 index put pop 1 add } - { exch pop } ifelse -} forall pop - -/reencode -{ dup FontDirectory exch known - { findfont } - { dup nbuff cvs dup length 1 sub get 82 eq - {dup nbuff cvs dup length 1 sub 0 exch getinterval - findfont begin - currentdict dup length dict begin -{ 1 index /FID ne {def} {pop pop} ifelse } forall -/FontName exch def - -/Encoding WPencoding def -currentdict dup end end -/FontName get exch definefont - } - { findfont } ifelse - } ifelse -} bdef - -/WPDLencoding StandardEncoding 256 array copy def 0 -[ 127 /SA420000/SD630000/SF010000/SF020000/SF030000 -/SF040000/SF050000/SF060000/SF070000/SF080000/SF090000 -/SF100000/SF110000/SF140000/SF150000/SF160000/SF190000 -/SF200000/SF210000/SF220000/SF230000/SF240000/SF250000/SF260000 -/SF270000/SF280000/SF360000/SF370000/SF380000/SF390000/SF400000 -/SF410000/SF420000/SF430000 -209 /SF440000/SF450000/SF460000/SF470000/SF480000 -/SF490000/SF500000/SF510000/SF520000/SF530000/SF540000 -/SF570000/SF580000/SF590000/SF600000/SF610000 -228 /SM570001/SM590000/SM600000/SM630000 -236 /SM680000/SM690000/SM700000/SM750000/SM750002 -242 /SM770000/SM790000/SP320000 -246 /SS000000/SS010000 -252 /SS260000/SS270000/SV040000/apostrophereverse -1/arrowboth/arrowdown/arrowleft/arrowright/arrowup/club -/deutschmark/diamond/diamondopen/exclamdbl/female -/fiveeighths/franc/heart/male/musicalnote/musicalnotedbl -/napostrophe/nsuperior/oneeighths/seveneighths/spade -/threeeights/underscoredbl/SM760000 -] -{ dup type /nametype eq - { WPDLencoding 2 index 2 index put pop 1 add } - { exch pop } ifelse -} forall pop - -/reencodeL - { dup FontDirectory exch known - { findfont } - { dup nbuff cvs dup length 1 sub get 76 eq - { dup nbuff cvs dup length 1 sub 0 exch getinterval - findfont begin - currentdict dup length dict begin - { 1 index /FID ne {def} {pop pop} ifelse } forall - /FontName exch def - /Encoding WPDLencoding def - currentdict dup end end - /FontName get exch definefont - } - { findfont } ifelse - } ifelse - } bdef - -/ron false def -/sflg false def -/slan 0 def -/sp 32 def - -/sshow - { save exch - gsave - psz 20 div dup neg _rmt dup show - grestore - dup - save exch - Bfont setfont - 1 setgray show - restore - currentfont makeoutl setfont show - currentpoint 3 -1 roll - restore _mt - } bdef - -/Sx 0 def -/Sy 0 def -/Ux 0 def -/Uy 0 def -/W /widthshow load def - -/_B {/bflg true def - sflg not {/_S /bshow load def /bon true def} if - } bdef -/_b {/bflg false def - bon {/_S /show load def /bon false def} if - } bdef -/_bd {save} bdef -/_bp {save 2 setmiterlimit .06 .06 scale 0 0 _mt} bdef -/_ccprocs - {/proc2 exch cvlit def - /proc1 exch cvlit def - /newproc proc1 length proc2 length add - array def - newproc 0 proc1 putinterval - newproc proc1 length proc2 putinterval - newproc cvx - } def -/_clr {3 {255 div 3 1 roll} repeat - ron {6 3 roll pop pop pop} {setrgbcolor} ifelse - } bdef -/_cp /closepath load def -/_cw {stroke initclip _mt 0 2 index - _rlt 0 _rlt 0 exch neg - _rlt clip newpath - } bdef -/_d /setdash load def -/_DU {currentpoint /DUy exch def /DUx exch def} bdef -/_du {gsave - save - 8 setlinewidth - currentpoint -30 add _mt - DUx DUy -30 add _lt stroke - restore - 8 setlinewidth - currentpoint -50 add _mt - DUx DUy -50 add _lt stroke - grestore - } bdef -/_ed {restore} bdef -/_ep {restore showpage 0 0 _mt} bdef -/_f /eofill load def -/_ff { exch reencode exch - 3 div dup /psz exch def - scalefont dup /Bfont exch def setfont - } bdef -/_ffs { /slan exch 10 div def /hscl exch 1000 div def - /psz exch 3 div def - [ psz hscl mul 0 slan dup sin exch cos div psz mul psz 0 0 ] - exch reencode exch makefont dup /Bfont exch def setfont - } bdef -/_g /setgray load def -/_gs {neg 100 add 100 div setgray} bdef -/_i {gsave - dup /picstr exch 7 add 8 idiv string def - 3 1 roll translate dup 1 scale - dup 1 1 [5 -1 roll 0 0 1 0 0] - {currentfile picstr readhexstring pop} image - grestore - } bdef -/_is {save 4 1 roll - dup /picstr exch 7 add 8 idiv string def - 3 1 roll translate dup 1 scale - dup 1 1 [5 -1 roll 0 0 1 0 0] - {currentfile picstr readhexstring pop} image - restore - } bdef -/_ie {1 eq { {1 exch sub} currenttransfer _ccprocs settransfer} if - /_isx exch def /_isy exch def - _isx mul exch _isy mul translate - add 2 div /_txc exch def - add 2 div /_tyc exch def - _txc _isx mul _tyc _isy mul translate - 360 exch sub rotate - 1 eq { _isx neg _isy scale } - { _isx _isy scale } - ifelse _txc neg _tyc neg translate - } bdef -/_irms {save - 12 1 roll - 1 eq {{1 exch sub} currenttransfer _ccprocs settransfer} if - /picstr exch string def translate - 2 index 6 index sub 2 div 2 index 6 index sub 2 div neg - translate - 5 index 5 index 2 div neg exch 2 div exch - 2 copy neg exch neg exch 5 2 roll translate - 360 exch sub rotate - 3 index 3 index 7 index div exch 8 index div exch scale - translate pop pop 2 index 2 index scale - 3 index 0 eq - { [ 3 index 0 0 5 index neg 0 0 ] } - { 3 index 1 eq - { [ 3 index 0 0 5 index 0 7 index ] } - { 3 index 128 eq - { [ 3 index neg 0 0 5 index neg 7 index 0 ] } - { [ 3 index neg 0 0 5 index 7 index 7 index ] } ifelse - } ifelse - } ifelse - {currentfile picstr readhexstring pop} image - pop - restore - } bdef - -/_l {_lt} bdef -/_lr {_rlt} bdef -/_m {_mt} bdef -/_O {currentfont makeoutl setfont} bdef -/_o {Bfont setfont} bdef -/_ornt {/pwid exch def /plen exch def - orntsv 1 eq {0 pwid translate -90 rotate} if - orntsv 2 eq {pwid plen translate 180 rotate} if - orntsv 3 eq {plen 0 translate 90 rotate} if - dup 1 eq {pwid 0 translate 90 rotate} if - dup 2 eq {pwid plen translate 180 rotate} if - dup 3 eq {0 plen translate -90 rotate} if - /orntsv exch def - } bdef -/_lod1 {currentpoint orntsv plen pwid 6 -1 roll restore save} bdef -/_lod2 {_bp 7 2 roll _ornt _mt} bdef -/_unlod {currentpoint orntsv plen pwid 7 -2 roll restore restore - _bp 6 1 roll _ornt _mt - } bdef -/_p {2 copy _mt 1 0 _rlt _mt} bdef -/_pl {{_lt} repeat} bdef -/_R { /ron true def /_S /_rshow load def /_t /_red load def} bdef -/_rshow { save exch - currentpoint - /RSy exch def /RSx exch def - ron { - sflg - { currentpoint - /Ry exch def /Rx exch def - dup stringwidth pop Rx Ry psz 4 div add _mt - Rx psz 15 add setlinewidth .95 setgray 0 setlinecap - add Ry psz 4 div add _lt stroke Rx Ry _mt 0 0 0 setrgbcolor - dup show Rx Ry _mt - sshow - } - { _redshow - }ifelse - } - { sflg {sshow} if - }ifelse - currentpoint 3 -1 roll - restore _mt - } bdef -/_red { gsave dup - currentpoint /Ry exch def /Rx exch def - Rx Ry psz 4 div add _mt - Rx psz 15 add setlinewidth .95 setgray 0 setlinecap - add Ry psz 4 div add _lt stroke - Rx Ry _mt - grestore - 0 rmoveto - }bdef -/_redshow {currentpoint - /Ry exch def /Rx exch def - dup stringwidth pop Rx Ry psz 4 div add _mt - Rx psz 15 add setlinewidth .95 setgray 0 setlinecap - add Ry psz 4 div add _lt stroke Rx Ry _mt 0 0 0 setrgbcolor - show currentpoint _mt - }bdef -/_rmxy {_rmt} bdef -/_s /stroke load def -/_SH bon {/bon false def} if - {/sflg true def /_S /_rshow load def - } bdef -/_sh { ron {/sflg false def bflg {_B} if} - {/_S /show load def /sflg false def bflg {_B} if}ifelse - }bdef -/_sp { gsave stroke grestore } bdef -/_ST {currentpoint /Sy exch def /Sx exch def} bdef -/_st {gsave - currentpoint pop - Sx dup Sy _mt sub - (\320) stringwidth pop div - dup floor cvi dup - dup 0 gt {{(\320) show} repeat}{pop} ifelse sub - dup 0 gt {1 scale (\320) show}{pop} ifelse - grestore - } bdef -/_U {currentpoint /Uy exch def /Ux exch def} bdef -/_u {gsave - currentpoint - -30 add _mt - Ux Uy -30 add _lt - 12 setlinewidth - stroke - grestore - } bdef -/_w /setlinewidth load def -end -/#copies 1 def /wpdict2 100 dict def -wpdict begin wpdict2 begin - -_bd -/_rhs{readhexstring}bdef/_tr{translate}bdef -/_ix{index}bdef/_mx{matrix}bdef -/ife{ifelse}bdef/_x{exch}bdef -/_is{save 4 1 roll -dup/picstr _x 7 add 8 idiv string def -3 1 roll _tr dup 1 scale -dup 1 1[5 -1 roll 0 0 1 0 0] -{currentfile picstr _rhs pop}image restore}bdef -/_epsi{1 eq{{1 _x sub}currenttransfer _ccprocs settransfer}if -/yp _x def/xp _x def/dhgt _x def/dwid _x def -4 copy sub/swid _x def -sub/shgt _x def -add 2 div/icx _x def add 2 div/icy _x def -xp dwid 2 div add icx sub yp dhgt 2 div sub -icy sub _tr icx icy _tr -360 _x sub rotate -dwid swid div/xsc _x def _x -dhgt shgt div/ysc _x def _x -dup 1 eq{xsc neg/xsc _x def pop} -{dup 2 eq{ysc neg /ysc _x def pop} -{3 eq{ysc neg/ysc _x def xsc neg/xsc _x def} -{}ife}ife}ife -xsc ysc scale -100 div _x 100 div _x scale -icx neg icy neg _tr}bdef -/_c{3{255 div 3 1 roll}repeat setrgbcolor}bdef -/eq3{3 copy 2 _ix eq{eq{true}{false}ife}{pop -pop false}ife}bdef -/g{255 div setgray}bdef -/_clr{ron{6 3 roll pop pop pop}{eq3{pop -pop g}{_c}ife}ife}bdef -/_r{/ron false def eq3{1 sub neg g pop -pop}{setrgbcolor}ife}bdef -/_ircms{save 15 1 roll -1 eq{{1 exch sub}currenttransfer _ccprocs settransfer}if -/pstr _x string def _tr -/Cli _x def/USy _x def/USx _x def/Rot _x def/HTd _x def -/WDd _x def/Bdep _x def/HTs _x def/WDs _x def/MIR _x def -USx 100 div USy 100 div scale -WDd WDs sub 2 div HTd HTs sub 2 div neg _tr -WDs HTs 2 div neg _x 2 div _x _tr -Rot 360 _x sub rotate WDd HTd HTs div _x WDs div _x scale -WDs 2 div neg HTs 2 div _tr -WDs HTs scale WDs HTs Bdep MIR 0 -eq{[WDs 0 0 HTs neg 0 0]}{MIR 1 eq{[WDs 0 0 HTs 0 HTs]} -{MIR 128 eq{[WDs neg 0 0 HTs neg WDs 0]} -{[WDs neg 0 0 HTs WDs HTs]}ife}ife}ife -{currentfile pstr _rhs pop}Cli -0 eq{image}{false 3 colorimage}ife -restore}bdef -/_bp{save 2 setlinecap 2 setmiterlimit -.06 .06 scale 0 0 moveto}bdef -/tctm _mx def/trot _mx def/tscale _mx def/rmtx _mx def -/fr{72 0 rmtx defaultmatrix dtransform -/yres _x def/xres _x def -xres dup mul yres dup mul add sqrt}bdef -/sus{/spotf _x def/sang _x def/csz _x def -/m tctm currentmatrix def/rm sang trot rotate def -/sm csz dup tscale scale def -sm rm m m concatmatrix m concatmatrix pop -1 0 m dtransform /y1 _x def/x1 _x def -/veclength x1 dup mul y1 dup mul add sqrt def -/frcy fr veclength div def /nsang y1 x1 atan def -frcy nsang/spotf load setscreen}bdef -/bitis{/ybit _x def /xbit _x def -/bval bstring ybit bwidth mul xbit 8 idiv add get def -/mask 1 7 xbit 8 mod sub bitshift def -bval mask and 0 ne}bdef -/bps{/y _x def /x _x def -/xndx x 1 add 2 div bpside mul cvi def -/yndx y 1 add 2 div bpside mul cvi def -xndx yndx bitis -{/onb onb 1 add def 1}{/ofb ofb 1 add def 0}ife}bdef -/stpatt{/csz _x def /angle _x def /bwidth _x def -/bpside _x def /bstring _x def -/onb 0 def /ofb 0 def -csz angle /bps load -sus{}settransfer -ofb ofb onb add div _g}bdef -/_fp{8 1 0 cpi stpatt}bdef -/_pf{gsave eofill grestore}bdef -/_np{newpath}bdef/_lc{setlinecap}bdef -/_sr{/cpi _x def}bdef -/nbuff 50 string def -letter _bp 0 13200 10200 _ornt /NewCenturySchlbk-RomanR 500 _ff -0 13200 10200 _ornt -/_r { sflg {/_t {0 rmoveto}bdef /ron false def} - { /_S /show load def /_t {0 rmoveto}bdef /ron false def}ifelse - }bdef -8907 11870 _m -(1)_S 3462 11439 _m -/NewCenturySchlbk-RomanR 750 _ff -(Standard)_S 83 _t -(MIDI)_S 83 _t -(File)_S 83 _t -(Format)_S /NewCenturySchlbk-RomanR 500 _ff -4469 11220 _m -(Dustin)_S 56 _t -(Caldwell)_S 1800 10820 _m -(The)_S 56 _t -(standard)_S 56 _t -(MIDI)_S 56 _t -(file)_S 56 _t -(format)_S 56 _t -(is)_S 56 _t -(a)_S 56 _t -(very)_S 56 _t -(strange)_S 56 _t -(beast.)_S 56 _t -(When)_S 56 _t -(viewed)_S 56 _t -(as)_S 56 _t -(a)_S 56 _t -(whole,)_S 56 _t -(it)_S 56 _t -(can)_S 56 _t -(be)_S 1200 10620 _m -(quite)_S 56 _t -(overwhelming.)_S 56 _t -(Of)_S 56 _t -(course,)_S 56 _t -(no)_S 56 _t -(matter)_S 56 _t -(how)_S 56 _t -(you)_S 56 _t -(look)_S 56 _t -(at)_S 56 _t -(it,)_S 56 _t -(describing)_S 56 _t -(a)_S 56 _t -(piece)_S 56 _t -(of)_S 56 _t -(music)_S 56 _t -(in)_S 56 _t -(enough)_S 1200 10420 _m -(detail)_S 56 _t -(to)_S 56 _t -(be)_S 56 _t -(able)_S 56 _t -(to)_S 56 _t -(reproduce)_S 56 _t -(it)_S 56 _t -(accurately)_S 56 _t -(is)_S 56 _t -(no)_S 56 _t -(small)_S 56 _t -(task.)_S 56 _t -(So,)_S 56 _t -(while)_S 56 _t -(complicated,)_S 56 _t -(the)_S 56 _t -(structure)_S 56 _t -(of)_S 1200 10220 _m -(the)_S 56 _t -(midi)_S 56 _t -(file)_S 56 _t -(format)_S 56 _t -(is)_S 56 _t -(fairly)_S 56 _t -(intuitive)_S 56 _t -(when)_S 56 _t -(understood.)_S 56 _t -1800 10020 _m -(I)_S 56 _t -(must)_S 56 _t -(insert)_S 56 _t -(a)_S 56 _t -(disclaimer)_S 56 _t -(here)_S 56 _t -(that)_S 56 _t -(I)_S 56 _t -(am)_S 56 _t -(by)_S 56 _t -(no)_S 56 _t -(means)_S 56 _t -(an)_S 56 _t -(expert)_S 56 _t -(with)_S 56 _t -(midi)_S 56 _t -(nor)_S 56 _t -(midi)_S 56 _t -(files.)_S 56 _t -(I)_S 1200 9820 _m -(recently)_S 56 _t -(obtained)_S 56 _t -(a)_S 56 _t -(Gravis)_S 56 _t -(UltraSound)_S 56 _t -(board)_S 56 _t -(for)_S 56 _t -(my)_S 56 _t -(PC,)_S 56 _t -(and)_S 56 _t -(upon)_S 56 _t -(hearing)_S 56 _t -(a)_S 56 _t -(few)_S 56 _t -(midi)_S 56 _t -(files)_S 56 _t -(\(.MID\))_S 1200 9620 _m -(thought,)_S 56 _t -("Gee,)_S 56 _t -(I'd)_S 56 _t -(like)_S 56 _t -(to)_S 56 _t -(be)_S 56 _t -(able)_S 56 _t -(to)_S 56 _t -(make)_S 56 _t -(my)_S 56 _t -(own)_S 56 _t -(.MID)_S 56 _t -(files.")_S 56 _t -(Well,)_S 56 _t -(many)_S 56 _t -(aggravating)_S 56 _t -(hours)_S 56 _t -(later,)_S 1200 9420 _m -(I)_S 56 _t -(discovered)_S 56 _t -(that)_S 56 _t -(this)_S 56 _t -(was)_S 56 _t -(no)_S 56 _t -(trivial)_S 56 _t -(task.)_S 56 _t -(But,)_S 56 _t -(I)_S 56 _t -(couldn't)_S 56 _t -(let)_S 56 _t -(a)_S 56 _t -(stupid)_S 56 _t -(file)_S 56 _t -(format)_S 56 _t -(stop)_S 56 _t -(me.)_S 56 _t -(\(besides,)_S 56 _t -(I)_S 1200 9220 _m -(once)_S 56 _t -(told)_S 56 _t -(my)_S 56 _t -(wife)_S 56 _t -(that)_S 56 _t -(computers)_S 56 _t -(aren't)_S 56 _t -(really)_S 56 _t -(that)_S 56 _t -(hard)_S 56 _t -(to)_S 56 _t -(use,)_S 56 _t -(and)_S 56 _t -(I'd)_S 56 _t -(hate)_S 56 _t -(to)_S 56 _t -(be)_S 56 _t -(a)_S 56 _t -(hypocrite\))_S 56 _t -(So)_S 1200 9020 _m -(if)_S 56 _t -(any)_S 56 _t -(errors)_S 56 _t -(are)_S 56 _t -(found)_S 56 _t -(in)_S 56 _t -(this)_S 56 _t -(information,)_S 56 _t -(please)_S 56 _t -(let)_S 56 _t -(me)_S 56 _t -(know)_S 56 _t -(and)_S 56 _t -(I)_S 56 _t -(will)_S 56 _t -(fix)_S 56 _t -(it.)_S 56 _t -(Also,)_S 56 _t -(this)_S 1200 8820 _m -(document's)_S 56 _t -(scope)_S 56 _t -(does)_S 56 _t -(not)_S 56 _t -(extend)_S 56 _t -(to)_S 56 _t -(EVERY)_S 56 _t -(type)_S 56 _t -(of)_S 56 _t -(midi)_S 56 _t -(command)_S 56 _t -(and)_S 56 _t -(EVERY)_S 56 _t -(possible)_S 56 _t -(file)_S 1200 8620 _m -(configuration.)_S 56 _t -(It)_S 56 _t -(is)_S 56 _t -(a)_S 56 _t -(basic)_S 56 _t -(guide)_S 56 _t -(that)_S 56 _t -(should)_S 56 _t -(enable)_S 56 _t -(the)_S 56 _t -(reader)_S 56 _t -(\(with)_S 56 _t -(a)_S 56 _t -(moderate)_S 56 _t -(investment)_S 56 _t -(in)_S 1200 8420 _m -(time\))_S 56 _t -(to)_S 56 _t -(generate)_S 56 _t -(a)_S 56 _t -(quality)_S 56 _t -(midi)_S 56 _t -(file.)_S 1200 8020 _m -(1.)_S 56 _t -(Overview)_S 1800 7620 _m -(A)_S 56 _t -(midi)_S 56 _t -(\(.MID\))_S 56 _t -(file)_S 56 _t -(contains)_S 56 _t -(basically)_S 56 _t -(2)_S 56 _t -(things,)_S 56 _t -(Header)_S 56 _t -(chunks)_S 56 _t -(and)_S 56 _t -(Track)_S 56 _t -(chunks.)_S 56 _t -(Section)_S 56 _t -(2)_S 1200 7420 _m -(explains)_S 56 _t -(the)_S 56 _t -(header)_S 56 _t -(chunks,)_S 56 _t -(and)_S 56 _t -(Section)_S 56 _t -(3)_S 56 _t -(explains)_S 56 _t -(the)_S 56 _t -(track)_S 56 _t -(chunks.)_S 56 _t -(A)_S 56 _t -(midi)_S 56 _t -(file)_S 56 _t -(contains)_S 56 _t -(ONE)_S 1200 7220 _m -(header)_S 56 _t -(chunk)_S 56 _t -(describing)_S 56 _t -(the)_S 56 _t -(file)_S 56 _t -(format,)_S 56 _t -(etc.,)_S 56 _t -(and)_S 56 _t -(any)_S 56 _t -(number)_S 56 _t -(of)_S 56 _t -(track)_S 56 _t -(chunks.)_S 56 _t -(A)_S 56 _t -(track)_S 56 _t -(may)_S 56 _t -(be)_S 1200 7020 _m -(thought)_S 56 _t -(of)_S 56 _t -(in)_S 56 _t -(the)_S 56 _t -(same)_S 56 _t -(way)_S 56 _t -(as)_S 56 _t -(a)_S 56 _t -(track)_S 56 _t -(on)_S 56 _t -(a)_S 56 _t -(multi-track)_S 56 _t -(tape)_S 56 _t -(deck.)_S 56 _t -(You)_S 56 _t -(may)_S 56 _t -(assign)_S 56 _t -(one)_S 56 _t -(track)_S 56 _t -(to)_S 1200 6820 _m -(each)_S 56 _t -(voice,)_S 56 _t -(each)_S 56 _t -(staff,)_S 56 _t -(each)_S 56 _t -(instrument)_S 56 _t -(or)_S 56 _t -(whatever)_S 56 _t -(you)_S 56 _t -(want.)_S 56 _t -1200 6420 _m -(2.)_S 56 _t -(Header)_S 56 _t -(Chunk)_S 1800 6020 _m -(The)_S 56 _t -(header)_S 56 _t -(chunk)_S 56 _t -(appears)_S 56 _t -(at)_S 56 _t -(the)_S 56 _t -(beginning)_S 56 _t -(of)_S 56 _t -(the)_S 56 _t -(file,)_S 56 _t -(and)_S 56 _t -(describes)_S 56 _t -(the)_S 56 _t -(file)_S 56 _t -(in)_S 56 _t -(three)_S 56 _t -(ways.)_S 1200 5820 _m -(The)_S 56 _t -(header)_S 56 _t -(chunk)_S 56 _t -(always)_S 56 _t -(looks)_S 56 _t -(like:)_S 1200 5420 _m -(4D)_S 56 _t -(54)_S 56 _t -(68)_S 56 _t -(64)_S 56 _t -(00)_S 56 _t -(00)_S 56 _t -(00)_S 56 _t -(06)_S 56 _t -(ff)_S 56 _t -(ff)_S 56 _t -(nn)_S 56 _t -(nn)_S 56 _t -(dd)_S 56 _t -(dd)_S 1200 5020 _m -(The)_S 56 _t -(ascii)_S 56 _t -(equivalent)_S 56 _t -(of)_S 56 _t -(the)_S 56 _t -(first)_S 56 _t -(4)_S 56 _t -(bytes)_S 56 _t -(is)_S 56 _t -(MThd.)_S 56 _t -(After)_S 56 _t -(MThd)_S 56 _t -(comes)_S 56 _t -(the)_S 56 _t -(4-byte)_S 56 _t -(size)_S 56 _t -(of)_S 56 _t -(the)_S 56 _t -(header.)_S 1200 4820 _m -(This)_S 56 _t -(will)_S 56 _t -(always)_S 56 _t -(be)_S 56 _t -(00)_S 56 _t -(00)_S 56 _t -(00)_S 56 _t -(06,)_S 56 _t -(because)_S 56 _t -(the)_S 56 _t -(actual)_S 56 _t -(header)_S 56 _t -(information)_S 56 _t -(will)_S 56 _t -(always)_S 56 _t -(be)_S 56 _t -(6)_S 56 _t -(bytes.)_S 56 _t -1200 4420 _m -(ff)_S 56 _t -(ff)_S 56 _t -(is)_S 56 _t -(the)_S 56 _t -(file)_S 56 _t -(format.)_S 56 _t -(There)_S 56 _t -(are)_S 56 _t -(3)_S 56 _t -(formats:)_S 1200 4020 _m -(0)_S 56 _t -(-)_S 56 _t -(single-track)_S 56 _t -1200 3820 _m -(1)_S 56 _t -(-)_S 56 _t -(multiple)_S 56 _t -(tracks,)_S 56 _t -(synchronous)_S 1200 3620 _m -(2)_S 56 _t -(-)_S 56 _t -(multiple)_S 56 _t -(tracks,)_S 56 _t -(asynchronous)_S 1200 3220 _m -(Single)_S 56 _t -(track)_S 56 _t -(is)_S 56 _t -(fairly)_S 56 _t -(self-explanatory)_S 56 _t -(-)_S 56 _t -(one)_S 56 _t -(track)_S 56 _t -(only.)_S 56 _t -(Synchronous)_S 56 _t -(multiple)_S 56 _t -(tracks)_S 56 _t -(means)_S 56 _t -(that)_S 56 _t -(the)_S 1200 3020 _m -(tracks)_S 56 _t -(will)_S 56 _t -(all)_S 56 _t -(be)_S 56 _t -(vertically)_S 56 _t -(synchronous,)_S 56 _t -(or)_S 56 _t -(in)_S 56 _t -(other)_S 56 _t -(words,)_S 56 _t -(they)_S 56 _t -(all)_S 56 _t -(start)_S 56 _t -(at)_S 56 _t -(the)_S 56 _t -(same)_S 56 _t -(time,)_S 56 _t -(and)_S 56 _t -(so)_S 1200 2820 _m -(can)_S 56 _t -(represent)_S 56 _t -(different)_S 56 _t -(parts)_S 56 _t -(in)_S 56 _t -(one)_S 56 _t -(song.)_S 56 _t -(Asynchronous)_S 56 _t -(multiple)_S 56 _t -(tracks)_S 56 _t -(do)_S 56 _t -(not)_S 56 _t -(necessarily)_S 56 _t -(start)_S 56 _t -(at)_S 1200 2620 _m -(the)_S 56 _t -(same)_S 56 _t -(time,)_S 56 _t -(and)_S 56 _t -(can)_S 56 _t -(be)_S 56 _t -(completely)_S 56 _t -(asynchronous.)_S 56 _t -1200 2220 _m -(nn)_S 56 _t -(nn)_S 56 _t -(is)_S 56 _t -(the)_S 56 _t -(number)_S 56 _t -(of)_S 56 _t -(tracks)_S 56 _t -(in)_S 56 _t -(the)_S 56 _t -(midi)_S 56 _t -(file.)_S 1200 1820 _m -(dd)_S 56 _t -(dd)_S 56 _t -(is)_S 56 _t -(the)_S 56 _t -(number)_S 56 _t -(of)_S 56 _t -(delta-time)_S 56 _t -(ticks)_S 56 _t -(per)_S 56 _t -(quarter)_S 56 _t -(note.)_S 56 _t -(\(More)_S 56 _t -(about)_S 56 _t -(this)_S 56 _t -(later\))_S _ep -_bp /NewCenturySchlbk-RomanR 500 _ff -0 13200 10200 _ornt -/_r { sflg {/_t {0 rmoveto}bdef /ron false def} - { /_S /show load def /_t {0 rmoveto}bdef /ron false def}ifelse - }bdef -8907 11870 _m -(2)_S 1200 11503 _m -(3.)_S 56 _t -(Track)_S 56 _t -(Chunks)_S 1200 11103 _m -(The)_S 56 _t -(remainder)_S 56 _t -(of)_S 56 _t -(the)_S 56 _t -(file)_S 56 _t -(after)_S 56 _t -(the)_S 56 _t -(header)_S 56 _t -(chunk)_S 56 _t -(consists)_S 56 _t -(of)_S 56 _t -(track)_S 56 _t -(chunks.)_S 56 _t -(Each)_S 56 _t -(track)_S 56 _t -(has)_S 56 _t -(one)_S 1200 10903 _m -(header)_S 56 _t -(and)_S 56 _t -(may)_S 56 _t -(contain)_S 56 _t -(as)_S 56 _t -(many)_S 56 _t -(midi)_S 56 _t -(commands)_S 56 _t -(as)_S 56 _t -(you)_S 56 _t -(like.)_S 56 _t -(The)_S 56 _t -(header)_S 56 _t -(for)_S 56 _t -(a)_S 56 _t -(track)_S 56 _t -(is)_S 56 _t -(very)_S 1200 10703 _m -(similar)_S 56 _t -(to)_S 56 _t -(the)_S 56 _t -(one)_S 56 _t -(for)_S 56 _t -(the)_S 56 _t -(file:)_S 1200 10303 _m -(4D)_S 56 _t -(54)_S 56 _t -(72)_S 56 _t -(6B)_S 56 _t -(xx)_S 56 _t -(xx)_S 56 _t -(xx)_S 56 _t -(xx)_S 1200 9903 _m -(As)_S 56 _t -(with)_S 56 _t -(the)_S 56 _t -(header,)_S 56 _t -(the)_S 56 _t -(first)_S 56 _t -(4)_S 56 _t -(bytes)_S 56 _t -(has)_S 56 _t -(an)_S 56 _t -(ascii)_S 56 _t -(equivalent.)_S 56 _t -(This)_S 56 _t -(one)_S 56 _t -(is)_S 56 _t -(MTrk.)_S 56 _t -(The)_S 56 _t -(4)_S 56 _t -(bytes)_S 56 _t -(after)_S 1200 9703 _m -(MTrk)_S 56 _t -(give)_S 56 _t -(the)_S 56 _t -(length)_S 56 _t -(of)_S 56 _t -(the)_S 56 _t -(track)_S 56 _t -(\(not)_S 56 _t -(including)_S 56 _t -(the)_S 56 _t -(track)_S 56 _t -(header\))_S 56 _t -(in)_S 56 _t -(bytes.)_S 56 _t -1800 9503 _m -(Following)_S 56 _t -(the)_S 56 _t -(header)_S 56 _t -(are)_S 56 _t -(midi)_S 56 _t -(events.)_S 56 _t -(These)_S 56 _t -(events)_S 56 _t -(are)_S 56 _t -(identical)_S 56 _t -(to)_S 56 _t -(the)_S 56 _t -(actual)_S 56 _t -(data)_S 56 _t -(sent)_S 1200 9303 _m -(and)_S 56 _t -(received)_S 56 _t -(by)_S 56 _t -(MIDI)_S 56 _t -(ports)_S 56 _t -(on)_S 56 _t -(a)_S 56 _t -(synth)_S 56 _t -(with)_S 56 _t -(one)_S 56 _t -(addition.)_S 56 _t -(A)_S 56 _t -(midi)_S 56 _t -(event)_S 56 _t -(is)_S 56 _t -(preceded)_S 56 _t -(by)_S 56 _t -(a)_S 56 _t -(delta-time.)_S 1200 9103 _m -(A)_S 56 _t -(delta)_S 56 _t -(time)_S 56 _t -(is)_S 56 _t -(the)_S 56 _t -(number)_S 56 _t -(of)_S 56 _t -(ticks)_S 56 _t -(after)_S 56 _t -(which)_S 56 _t -(the)_S 56 _t -(midi)_S 56 _t -(event)_S 56 _t -(is)_S 56 _t -(to)_S 56 _t -(be)_S 56 _t -(executed.)_S 56 _t -(The)_S 56 _t -(number)_S 56 _t -(of)_S 1200 8903 _m -(ticks)_S 56 _t -(per)_S 56 _t -(quarter)_S 56 _t -(note)_S 56 _t -(was)_S 56 _t -(defined)_S 56 _t -(previously)_S 56 _t -(in)_S 56 _t -(the)_S 56 _t -(file)_S 56 _t -(header)_S 56 _t -(chunk.)_S 56 _t -(This)_S 56 _t -(delta-time)_S 56 _t -(is)_S 56 _t -(a)_S 1200 8703 _m -(variable-length)_S 56 _t -(encoded)_S 56 _t -(value.)_S 56 _t -(This)_S 56 _t -(format,)_S 56 _t -(while)_S 56 _t -(confusing,)_S 56 _t -(allows)_S 56 _t -(large)_S 56 _t -(numbers)_S 56 _t -(to)_S 56 _t -(use)_S 56 _t -(as)_S 56 _t -(many)_S 1200 8503 _m -(bytes)_S 56 _t -(as)_S 56 _t -(they)_S 56 _t -(need,)_S 56 _t -(without)_S 56 _t -(requiring)_S 56 _t -(small)_S 56 _t -(numbers)_S 56 _t -(to)_S 56 _t -(waste)_S 56 _t -(bytes)_S 56 _t -(by)_S 56 _t -(filling)_S 56 _t -(with)_S 56 _t -(zeros.)_S 56 _t -(The)_S 1200 8303 _m -(number)_S 56 _t -(is)_S 56 _t -(converted)_S 56 _t -(into)_S 56 _t -(7-bit)_S 56 _t -(bytes,)_S 56 _t -(and)_S 56 _t -(the)_S 56 _t -(most-significant)_S 56 _t -(bit)_S 56 _t -(of)_S 56 _t -(each)_S 56 _t -(byte)_S 56 _t -(is)_S 56 _t -(1)_S 56 _t -(except)_S 56 _t -(for)_S 56 _t -(the)_S 1200 8103 _m -(last)_S 56 _t -(byte)_S 56 _t -(of)_S 56 _t -(the)_S 56 _t -(number,)_S 56 _t -(which)_S 56 _t -(has)_S 56 _t -(a)_S 56 _t -(msb)_S 56 _t -(of)_S 56 _t -(0.)_S 56 _t -(This)_S 56 _t -(allows)_S 56 _t -(the)_S 56 _t -(number)_S 56 _t -(to)_S 56 _t -(be)_S 56 _t -(read)_S 56 _t -(one)_S 56 _t -(byte)_S 56 _t -(at)_S 56 _t -(a)_S 1200 7903 _m -(time,)_S 56 _t -(and)_S 56 _t -(when)_S 56 _t -(you)_S 56 _t -(see)_S 56 _t -(a)_S 56 _t -(msb)_S 56 _t -(of)_S 56 _t -(0,)_S 56 _t -(you)_S 56 _t -(know)_S 56 _t -(that)_S 56 _t -(it)_S 56 _t -(was)_S 56 _t -(the)_S 56 _t -(last)_S 56 _t -(\(least)_S 56 _t -(significant\))_S 56 _t -(byte)_S 56 _t -(of)_S 56 _t -(the)_S 1200 7703 _m -(number.)_S 56 _t -(According)_S 56 _t -(to)_S 56 _t -(the)_S 56 _t -(MIDI)_S 56 _t -(spec,)_S 56 _t -(the)_S 56 _t -(entire)_S 56 _t -(delta-time)_S 56 _t -(should)_S 56 _t -(be)_S 56 _t -(at)_S 56 _t -(most)_S 56 _t -(4)_S 56 _t -(bytes)_S 56 _t -(long.)_S 56 _t -1800 7503 _m -(Following)_S 56 _t -(the)_S 56 _t -(delta-time)_S 56 _t -(is)_S 56 _t -(a)_S 56 _t -(midi)_S 56 _t -(event.)_S 56 _t -(Each)_S 56 _t -(midi)_S 56 _t -(event)_S 56 _t -(\(except)_S 56 _t -(a)_S 56 _t -(running)_S 56 _t -(midi)_S 56 _t -(event\))_S 1200 7303 _m -(has)_S 56 _t -(a)_S 56 _t -(command)_S 56 _t -(byte)_S 56 _t -(which)_S 56 _t -(will)_S 56 _t -(always)_S 56 _t -(have)_S 56 _t -(a)_S 56 _t -(msb)_S 56 _t -(of)_S 56 _t -(1)_S 56 _t -(\(the)_S 56 _t -(value)_S 56 _t -(will)_S 56 _t -(be)_S 56 _t -(>=)_S 56 _t -(128\).)_S 56 _t -(A)_S 56 _t -(list)_S 56 _t -(of)_S 56 _t -(most)_S 56 _t -(of)_S 1200 7103 _m -(these)_S 56 _t -(commands)_S 56 _t -(is)_S 56 _t -(in)_S 56 _t -(appendix)_S 56 _t -(A.)_S 56 _t -(Each)_S 56 _t -(command)_S 56 _t -(has)_S 56 _t -(different)_S 56 _t -(parameters)_S 56 _t -(and)_S 56 _t -(lengths,)_S 56 _t -(but)_S 56 _t -(the)_S 1200 6903 _m -(data)_S 56 _t -(that)_S 56 _t -(follows)_S 56 _t -(the)_S 56 _t -(command)_S 56 _t -(will)_S 56 _t -(have)_S 56 _t -(a)_S 56 _t -(msb)_S 56 _t -(of)_S 56 _t -(0)_S 56 _t -(\(less)_S 56 _t -(than)_S 56 _t -(128\).)_S 56 _t -(The)_S 56 _t -(exception)_S 56 _t -(to)_S 56 _t -(this)_S 56 _t -(is)_S 56 _t -(a)_S 1200 6703 _m -(meta-event,)_S 56 _t -(which)_S 56 _t -(may)_S 56 _t -(contain)_S 56 _t -(data)_S 56 _t -(with)_S 56 _t -(a)_S 56 _t -(msb)_S 56 _t -(of)_S 56 _t -(1.)_S 56 _t -(However,)_S 56 _t -(meta-events)_S 56 _t -(require)_S 56 _t -(a)_S 56 _t -(length)_S 1200 6503 _m -(parameter)_S 56 _t -(which)_S 56 _t -(alleviates)_S 56 _t -(confusion.)_S 56 _t -1800 6303 _m -(One)_S 56 _t -(subtlety)_S 56 _t -(which)_S 56 _t -(can)_S 56 _t -(cause)_S 56 _t -(confusion)_S 56 _t -(is)_S 56 _t -(running)_S 56 _t -(mode.)_S 56 _t -(This)_S 56 _t -(is)_S 56 _t -(where)_S 56 _t -(the)_S 56 _t -(actual)_S 56 _t -(midi)_S 1200 6103 _m -(command)_S 56 _t -(is)_S 56 _t -(omitted,)_S 56 _t -(and)_S 56 _t -(the)_S 56 _t -(last)_S 56 _t -(midi)_S 56 _t -(command)_S 56 _t -(issued)_S 56 _t -(is)_S 56 _t -(assumed.)_S 56 _t -(This)_S 56 _t -(means)_S 56 _t -(that)_S 56 _t -(the)_S 56 _t -(midi)_S 1200 5903 _m -(event)_S 56 _t -(will)_S 56 _t -(consist)_S 56 _t -(of)_S 56 _t -(a)_S 56 _t -(delta-time)_S 56 _t -(and)_S 56 _t -(the)_S 56 _t -(parameters)_S 56 _t -(that)_S 56 _t -(would)_S 56 _t -(go)_S 56 _t -(to)_S 56 _t -(the)_S 56 _t -(command)_S 56 _t -(if)_S 56 _t -(it)_S 56 _t -(were)_S 1200 5703 _m -(included.)_S 56 _t -1200 5303 _m -(4.)_S 56 _t -(Conclusion)_S 1800 4903 _m -(If)_S 56 _t -(this)_S 56 _t -(explanation)_S 56 _t -(has)_S 56 _t -(only)_S 56 _t -(served)_S 56 _t -(to)_S 56 _t -(confuse)_S 56 _t -(the)_S 56 _t -(issue)_S 56 _t -(more,)_S 56 _t -(the)_S 56 _t -(appendices)_S 56 _t -(contain)_S 1200 4703 _m -(examples)_S 56 _t -(which)_S 56 _t -(may)_S 56 _t -(help)_S 56 _t -(clarify)_S 56 _t -(the)_S 56 _t -(issue.)_S 56 _t -(Also,)_S 56 _t -(2)_S 56 _t -(utilities)_S 56 _t -(and)_S 56 _t -(a)_S 56 _t -(graphic)_S 56 _t -(file)_S 56 _t -(should)_S 56 _t -(have)_S 56 _t -(been)_S 1200 4503 _m -(included)_S 56 _t -(with)_S 56 _t -(this)_S 56 _t -(document:)_S 56 _t -1200 4103 _m -(DEC.EXE)_S 56 _t -(-)_S 56 _t -(This)_S 56 _t -(utility)_S 56 _t -(converts)_S 56 _t -(a)_S 56 _t -(binary)_S 56 _t -(file)_S 56 _t -(\(like)_S 56 _t -(.MID\))_S 56 _t -(to)_S 56 _t -(a)_S 56 _t -(tab-delimited)_S 56 _t -(text)_S 56 _t -(file)_S 56 _t -(containing)_S 56 _t -(the)_S 1200 3903 _m -(decimal)_S 56 _t -(equivalents)_S 56 _t -(of)_S 56 _t -(each)_S 56 _t -(byte.)_S 1200 3503 _m -(REC.EXE)_S 56 _t -(-)_S 56 _t -(This)_S 56 _t -(utility)_S 56 _t -(converts)_S 56 _t -(a)_S 56 _t -(tab-delimited)_S 56 _t -(text)_S 56 _t -(file)_S 56 _t -(of)_S 56 _t -(decimal)_S 56 _t -(values)_S 56 _t -(into)_S 56 _t -(a)_S 56 _t -(binary)_S 56 _t -(file)_S 56 _t -(in)_S 1200 3303 _m -(which)_S 56 _t -(each)_S 56 _t -(byte)_S 56 _t -(corresponds)_S 56 _t -(to)_S 56 _t -(one)_S 56 _t -(of)_S 56 _t -(the)_S 56 _t -(decimal)_S 56 _t -(values.)_S 1200 2903 _m -(MIDINOTE.PS)_S 56 _t -(-)_S 56 _t -(This)_S 56 _t -(is)_S 56 _t -(the)_S 56 _t -(postscript)_S 56 _t -(form)_S 56 _t -(of)_S 56 _t -(a)_S 56 _t -(page)_S 56 _t -(showing)_S 56 _t -(note)_S 56 _t -(numbers)_S 56 _t -(with)_S 56 _t -(a)_S 56 _t -(keyboard)_S 56 _t -(and)_S 1200 2703 _m -(with)_S 56 _t -(the)_S 56 _t -(standard)_S 56 _t -(grand)_S 56 _t -(staff.)_S _ep -_bp /NewCenturySchlbk-RomanR 500 _ff -0 13200 10200 _ornt -/_r { sflg {/_t {0 rmoveto}bdef /ron false def} - { /_S /show load def /_t {0 rmoveto}bdef /ron false def}ifelse - }bdef -8907 11870 _m -(3)_S 4645 11503 _m -(Appendix)_S 56 _t -(A)_S 1200 11103 _m -(1.)_S 56 _t -(MIDI)_S 56 _t -(Event)_S 56 _t -(Commands)_S 1200 10703 _m -(Each)_S 56 _t -(command)_S 56 _t -(byte)_S 56 _t -(has)_S 56 _t -(2)_S 56 _t -(parts.)_S 56 _t -(The)_S 56 _t -(left)_S 56 _t -(nybble)_S 56 _t -(\(4)_S 56 _t -(bits\))_S 56 _t -(contains)_S 56 _t -(the)_S 56 _t -(actual)_S 56 _t -(command,)_S 56 _t -(and)_S 56 _t -(the)_S 1200 10503 _m -(right)_S 56 _t -(nybble)_S 56 _t -(contains)_S 56 _t -(the)_S 56 _t -(midi)_S 56 _t -(channel)_S 56 _t -(number)_S 56 _t -(on)_S 56 _t -(which)_S 56 _t -(the)_S 56 _t -(command)_S 56 _t -(will)_S 56 _t -(be)_S 56 _t -(executed.)_S 56 _t -(There)_S 56 _t -(are)_S 1200 10303 _m -(16)_S 56 _t -(midi)_S 56 _t -(channels,)_S 56 _t -(and)_S 56 _t -(8)_S 56 _t -(midi)_S 56 _t -(commands)_S 56 _t -(\(the)_S 56 _t -(command)_S 56 _t -(nybble)_S 56 _t -(must)_S 56 _t -(have)_S 56 _t -(a)_S 56 _t -(msb)_S 56 _t -(of)_S 56 _t -(1\).)_S 1200 10103 _m -(In)_S 56 _t -(the)_S 56 _t -(following)_S 56 _t -(table,)_S 56 _t -(x)_S 56 _t -(indicates)_S 56 _t -(the)_S 56 _t -(midi)_S 56 _t -(channel)_S 56 _t -(number.)_S 56 _t -(Note)_S 56 _t -(that)_S 56 _t -(all)_S 56 _t -(data)_S 56 _t -(bytes)_S 56 _t -(will)_S 56 _t -(be)_S 56 _t -(<128)_S 1200 9903 _m -(\(msb)_S 56 _t -(set)_S 56 _t -(to)_S 56 _t -(0\).)_S 1200 9503 _m -_U (Hex)_S 2109 9503 _m -(Binary)_S 3422 9503 _m -(Data)_S 4836 9503 _m -(Description)_S _u 1200 9303 _m -(8x)_S 2109 9303 _m -(1000xxxx)_S 3422 9303 _m -(nn)_S 56 _t -(vv)_S 4836 9303 _m -(Note)_S 56 _t -(off)_S 56 _t -(\(key)_S 56 _t -(is)_S 56 _t -(released\))_S 4836 9103 _m -(nn=note)_S 56 _t -(number)_S 4836 8903 _m -(vv=velocity)_S 1200 8503 _m -(9x)_S 2109 8503 _m -(1001xxxx)_S 3422 8503 _m -(nn)_S 56 _t -(vv)_S 4836 8503 _m -(Note)_S 56 _t -(on)_S 56 _t -(\(key)_S 56 _t -(is)_S 56 _t -(pressed\))_S 4836 8303 _m -(nn=note)_S 56 _t -(number)_S 4836 8103 _m -(vv=velocity)_S 1200 7703 _m -(Ax)_S 2109 7703 _m -(1010xxxx)_S 3422 7703 _m -(nn)_S 56 _t -(vv)_S 4836 7703 _m -(Key)_S 56 _t -(after-touch)_S 4836 7503 _m -(nn=note)_S 56 _t -(number)_S 4836 7303 _m -(vv=velocity)_S 1200 6903 _m -(Bx)_S 2109 6903 _m -(1011xxxx)_S 3422 6903 _m -(cc)_S 56 _t -(vv)_S 4836 6903 _m -(Control)_S 56 _t -(Change)_S 4836 6703 _m -(cc=controller)_S 56 _t -(number)_S 4836 6503 _m -(vv=new)_S 56 _t -(value)_S 1200 6103 _m -(Cx)_S 2109 6103 _m -(1100xxxx)_S 3422 6103 _m -(pp)_S 4836 6103 _m -(Program)_S 56 _t -(\(patch\))_S 56 _t -(change)_S 4836 5903 _m -(pp=new)_S 56 _t -(program)_S 56 _t -(number)_S 1200 5503 _m -(Dx)_S 2109 5503 _m -(1101xxxx)_S 3422 5503 _m -(cc)_S 4836 5503 _m -(Channel)_S 56 _t -(after-touch)_S 4836 5303 _m -(cc=channel)_S 56 _t -(number)_S 1200 4903 _m -(Ex)_S 2109 4903 _m -(1110xxxx)_S 3422 4903 _m -(bb)_S 56 _t -(tt)_S 4836 4903 _m -(Pitch)_S 56 _t -(wheel)_S 56 _t -(change)_S 56 _t -(\(2000H)_S 56 _t -(is)_S 56 _t -(normal)_S 56 _t -(or)_S 56 _t -(no)_S 56 _t -(change\))_S 4836 4703 _m -(bb=bottom)_S 56 _t -(\(least)_S 56 _t -(sig\))_S 56 _t -(7)_S 56 _t -(bits)_S 56 _t -(of)_S 56 _t -(value)_S 4836 4503 _m -(tt=top)_S 56 _t -(\(most)_S 56 _t -(sig\))_S 56 _t -(7)_S 56 _t -(bits)_S 56 _t -(of)_S 56 _t -(value)_S _ep -_bp /NewCenturySchlbk-RomanR 500 _ff -0 13200 10200 _ornt -/_r { sflg {/_t {0 rmoveto}bdef /ron false def} - { /_S /show load def /_t {0 rmoveto}bdef /ron false def}ifelse - }bdef -8907 11870 _m -(4)_S 1200 11503 _m -(The)_S 56 _t -(following)_S 56 _t -(table)_S 56 _t -(lists)_S 56 _t -(meta-events)_S 56 _t -(which)_S 56 _t -(have)_S 56 _t -(no)_S 56 _t -(midi)_S 56 _t -(channel)_S 56 _t -(number.)_S 56 _t -(They)_S 56 _t -(are)_S 56 _t -(of)_S 56 _t -(the)_S 56 _t -(format:)_S 1200 11103 _m -(FF)_S 56 _t -(xx)_S 56 _t -(nn)_S 56 _t -(dd)_S 1200 10703 _m -(All)_S 56 _t -(meta-events)_S 56 _t -(start)_S 56 _t -(with)_S 56 _t -(FF)_S 56 _t -(followed)_S 56 _t -(by)_S 56 _t -(the)_S 56 _t -(command)_S 56 _t -(\(xx\),)_S 56 _t -(the)_S 56 _t -(length,)_S 56 _t -(or)_S 56 _t -(number)_S 56 _t -(of)_S 56 _t -(bytes)_S 56 _t -(that)_S 1200 10503 _m -(will)_S 56 _t -(contain)_S 56 _t -(data)_S 56 _t -(\(nn\),)_S 56 _t -(and)_S 56 _t -(the)_S 56 _t -(actual)_S 56 _t -(data)_S 56 _t -(\(dd\).)_S 1200 10103 _m -_U (Hex)_S 2109 10103 _m -(Binary)_S 3422 10103 _m -(Data)_S 4836 10103 _m -(Description)_S _u 1200 9903 _m -(00)_S 2109 9903 _m -(00000000)_S 3422 9903 _m -(nn)_S 56 _t -(ssss)_S 4836 9903 _m -(Sets)_S 56 _t -(the)_S 56 _t -(track's)_S 56 _t -(sequence)_S 56 _t -(number.)_S 4836 9703 _m -(nn=02)_S 56 _t -(\(length)_S 56 _t -(of)_S 56 _t -(2-byte)_S 56 _t -(sequence)_S 56 _t -(number\))_S 4836 9503 _m -(ssss=sequence)_S 56 _t -(number)_S 1200 9103 _m -(01)_S 2109 9103 _m -(00000001)_S 3422 9103 _m -(nn)_S 56 _t -(tt)_S 56 _t -(..)_S 4836 9103 _m -(Text)_S 56 _t -(event-)_S 56 _t -(any)_S 56 _t -(text)_S 56 _t -(you)_S 56 _t -(want.)_S 4836 8903 _m -(nn=length)_S 56 _t -(in)_S 56 _t -(bytes)_S 56 _t -(of)_S 56 _t -(text)_S 4836 8703 _m -(tt=text)_S 56 _t -(characters)_S 1200 8303 _m -(02)_S 2109 8303 _m -(00000010)_S 3422 8303 _m -(nn)_S 56 _t -(tt)_S 56 _t -(..)_S 4836 8303 _m -(Same)_S 56 _t -(as)_S 56 _t -(text)_S 56 _t -(event,)_S 56 _t -(but)_S 56 _t -(used)_S 56 _t -(for)_S 56 _t -(copyright)_S 56 _t -(info.)_S 4836 8103 _m -(nn)_S 56 _t -(tt=same)_S 56 _t -(as)_S 56 _t -(text)_S 56 _t -(event)_S 1200 7703 _m -(03)_S 2109 7703 _m -(00000011)_S 3422 7703 _m -(nn)_S 56 _t -(tt)_S 56 _t -(..)_S 4836 7703 _m -(Sequence)_S 56 _t -(or)_S 56 _t -(Track)_S 56 _t -(name)_S 4836 7503 _m -(nn)_S 56 _t -(tt=same)_S 56 _t -(as)_S 56 _t -(text)_S 56 _t -(event)_S 1200 7103 _m -(04)_S 2109 7103 _m -(00000100)_S 3422 7103 _m -(nn)_S 56 _t -(tt)_S 56 _t -(..)_S 4836 7103 _m -(Track)_S 56 _t -(instrument)_S 56 _t -(name)_S 4836 6903 _m -(nn)_S 56 _t -(tt=same)_S 56 _t -(as)_S 56 _t -(text)_S 56 _t -(event)_S 1200 6503 _m -(05)_S 2109 6503 _m -(00000101)_S 3422 6503 _m -(nn)_S 56 _t -(tt)_S 56 _t -(..)_S 4836 6503 _m -(Lyric)_S 4836 6303 _m -(nn)_S 56 _t -(tt=same)_S 56 _t -(as)_S 56 _t -(text)_S 56 _t -(event)_S 1200 5903 _m -(06)_S 2109 5903 _m -(00000110)_S 3422 5903 _m -(nn)_S 56 _t -(tt)_S 56 _t -(..)_S 4836 5903 _m -(Marker)_S 4836 5703 _m -(nn)_S 56 _t -(tt=same)_S 56 _t -(as)_S 56 _t -(text)_S 56 _t -(event)_S 1200 5303 _m -(07)_S 2109 5303 _m -(00000111)_S 3422 5303 _m -(nn)_S 56 _t -(tt)_S 56 _t -(..)_S 4836 5303 _m -(Cue)_S 56 _t -(point)_S 4836 5103 _m -(nn)_S 56 _t -(tt=same)_S 56 _t -(as)_S 56 _t -(text)_S 56 _t -(event)_S 1200 4703 _m -(2F)_S 56 _t -2109 4703 _m -(00101111)_S 3422 4703 _m -(00)_S 4836 4703 _m -(This)_S 56 _t -(event)_S 56 _t -(must)_S 56 _t -(come)_S 56 _t -(at)_S 56 _t -(the)_S 56 _t -(end)_S 56 _t -(of)_S 56 _t -(each)_S 56 _t -(track)_S 1200 4303 _m -(51)_S 2109 4303 _m -(01010001)_S 3422 4303 _m -(03)_S 56 _t -(tttttt)_S 4836 4303 _m -(Set)_S 56 _t -(tempo)_S 4836 4103 _m -(tttttt=microseconds/quarter)_S 56 _t -(note)_S 1200 3703 _m -(58)_S 2109 3703 _m -(01011000)_S 3422 3703 _m -(04)_S 56 _t -(nn)_S 56 _t -(dd)_S 56 _t -(cc)_S 56 _t -(bb)_S 4836 3703 _m -(Time)_S 56 _t -(Signature)_S 4836 3503 _m -(nn=numerator)_S 56 _t -(of)_S 56 _t -(time)_S 56 _t -(sig.)_S 4836 3303 _m -(dd=denominator)_S 56 _t -(of)_S 56 _t -(time)_S 56 _t -(sig.)_S 56 _t -(2=quarter)_S 56 _t -(3=eighth,)_S 56 _t -(etc.)_S 4836 3103 _m -(cc=number)_S 56 _t -(of)_S 56 _t -(ticks)_S 56 _t -(in)_S 56 _t -(metronome)_S 56 _t -(click)_S 4836 2903 _m -(bb=number)_S 56 _t -(of)_S 56 _t -(32nd)_S 56 _t -(notes)_S 56 _t -(to)_S 56 _t -(the)_S 56 _t -(quarter)_S 56 _t -(note)_S 1200 2503 _m -(59)_S 2109 2503 _m -(01011001)_S 3422 2503 _m -(02)_S 56 _t -(sf)_S 56 _t -(mi)_S 4836 2503 _m -(Key)_S 56 _t -(signature)_S 4836 2303 _m -(sf=sharps/flats)_S 56 _t -(\(-7=7)_S 56 _t -(flats,)_S 56 _t -(0=key)_S 56 _t -(of)_S 56 _t -(C,)_S 56 _t -(7=7)_S 56 _t -(sharps\))_S 4836 2103 _m -(mi=major/minor)_S 56 _t -(\(0=major,)_S 56 _t -(1=minor\))_S 1200 1703 _m -(7F)_S 2109 1703 _m -(01111111)_S 3422 1703 _m -(xx)_S 56 _t -(dd)_S 56 _t -(..)_S 4836 1703 _m -(Sequencer)_S 56 _t -(specific)_S 56 _t -(information)_S 4836 1503 _m -(xx=number)_S 56 _t -(of)_S 56 _t -(bytes)_S 56 _t -(to)_S 56 _t -(be)_S 56 _t -(sent)_S 4836 1303 _m -(dd=data)_S _ep -_bp /NewCenturySchlbk-RomanR 500 _ff -0 13200 10200 _ornt -/_r { sflg {/_t {0 rmoveto}bdef /ron false def} - { /_S /show load def /_t {0 rmoveto}bdef /ron false def}ifelse - }bdef -8907 11870 _m -(5)_S 1200 11303 _m -(The)_S 56 _t -(following)_S 56 _t -(table)_S 56 _t -(lists)_S 56 _t -(system)_S 56 _t -(messages)_S 56 _t -(which)_S 56 _t -(control)_S 56 _t -(the)_S 56 _t -(entire)_S 56 _t -(system.)_S 56 _t -(These)_S 56 _t -(have)_S 56 _t -(no)_S 56 _t -(midi)_S 1200 11103 _m -(channel)_S 56 _t -(number.)_S 56 _t -(\(these)_S 56 _t -(will)_S 56 _t -(generally)_S 56 _t -(only)_S 56 _t -(apply)_S 56 _t -(to)_S 56 _t -(controlling)_S 56 _t -(a)_S 56 _t -(midi)_S 56 _t -(keyboard,)_S 56 _t -(etc.\))_S 1200 10703 _m -_U (Hex)_S 2109 10703 _m -(Binary)_S 3422 10703 _m -(Data)_S 4836 10703 _m -(Description)_S _u 1200 10503 _m -(F8)_S 2109 10503 _m -(11111000)_S 4836 10503 _m -(Timing)_S 56 _t -(clock)_S 56 _t -(used)_S 56 _t -(when)_S 56 _t -(synchronization)_S 56 _t -(is)_S 56 _t -(required.)_S 1200 10103 _m -(FA)_S 2109 10103 _m -(11111010)_S 4836 10103 _m -(Start)_S 56 _t -(current)_S 56 _t -(sequence)_S 1200 9703 _m -(FB)_S 2109 9703 _m -(11111011)_S 4836 9703 _m -(Continue)_S 56 _t -(a)_S 56 _t -(stopped)_S 56 _t -(sequence)_S 56 _t -(where)_S 56 _t -(left)_S 56 _t -(off)_S 1200 9303 _m -(FC)_S 2109 9303 _m -(11111100)_S 4836 9303 _m -(Stop)_S 56 _t -(a)_S 56 _t -(sequence)_S 1200 8703 _m -(The)_S 56 _t -(following)_S 56 _t -(table)_S 56 _t -(lists)_S 56 _t -(the)_S 56 _t -(numbers)_S 56 _t -(corresponding)_S 56 _t -(to)_S 56 _t -(notes)_S 56 _t -(for)_S 56 _t -(use)_S 56 _t -(in)_S 56 _t -(note)_S 56 _t -1200 8503 _m -(on)_S 56 _t -(and)_S 56 _t -(note)_S 56 _t -(off)_S 56 _t -(commands.)_S /CourierR 500 _ff -1200 7952 _m -(Octave||)_S 2100 _t -(Note)_S 100 _t -(Numbers)_S 1200 7785 _m -100 _t -100 _t -100 _t -(#)_S 200 _t -(||)_S 1200 7618 _m -100 _t -100 _t -100 _t -100 _t -100 _t -100 _t -(||)_S 100 _t -(C)_S 300 _t -(|)_S 100 _t -(C#)_S 200 _t -(|)_S 100 _t -(D)_S 300 _t -(|)_S 100 _t -(D#)_S 200 _t -(|)_S 100 _t -(E)_S 300 _t -(|)_S 100 _t -(F)_S 300 _t -(|)_S 100 _t -(F#)_S 200 _t -(|)_S 100 _t -(G)_S 300 _t -(|)_S 100 _t -(G#)_S 200 _t -(|)_S 100 _t -(A)_S 300 _t -(|)_S 100 _t -(A#)_S 200 _t -(|)_S 100 _t -(B)_S 1200 7451 _m -(-----------------------------------------------------------------------------)_S 1200 7284 _m -100 _t -100 _t -100 _t -(0)_S 200 _t -(||)_S 300 _t -(0)_S 100 _t -(|)_S 300 _t -(1)_S 100 _t -(|)_S 300 _t -(2)_S 100 _t -(|)_S 300 _t -(3)_S 100 _t -(|)_S 300 _t -(4)_S 100 _t -(|)_S 300 _t -(5)_S 100 _t -(|)_S 300 _t -(6)_S 100 _t -(|)_S 300 _t -(7)_S 100 _t -(|)_S 300 _t -(8)_S 100 _t -(|)_S 300 _t -(9)_S 100 _t -(|)_S 200 _t -(10)_S 100 _t -(|)_S 100 _t -(11)_S 1200 7117 _m -100 _t -100 _t -100 _t -(1)_S 200 _t -(||)_S 200 _t -(12)_S 100 _t -(|)_S 200 _t -(13)_S 100 _t -(|)_S 200 _t -(14)_S 100 _t -(|)_S 200 _t -(15)_S 100 _t -(|)_S 200 _t -(16)_S 100 _t -(|)_S 200 _t -(17)_S 100 _t -(|)_S 200 _t -(18)_S 100 _t -(|)_S 200 _t -(19)_S 100 _t -(|)_S 200 _t -(20)_S 100 _t -(|)_S 200 _t -(21)_S 100 _t -(|)_S 200 _t -(22)_S 100 _t -(|)_S 100 _t -(23)_S 1200 6950 _m -100 _t -100 _t -100 _t -(2)_S 200 _t -(||)_S 200 _t -(24)_S 100 _t -(|)_S 200 _t -(25)_S 100 _t -(|)_S 200 _t -(26)_S 100 _t -(|)_S 200 _t -(27)_S 100 _t -(|)_S 200 _t -(28)_S 100 _t -(|)_S 200 _t -(29)_S 100 _t -(|)_S 200 _t -(30)_S 100 _t -(|)_S 200 _t -(31)_S 100 _t -(|)_S 200 _t -(32)_S 100 _t -(|)_S 200 _t -(33)_S 100 _t -(|)_S 200 _t -(34)_S 100 _t -(|)_S 100 _t -(35)_S 1200 6783 _m -100 _t -100 _t -100 _t -(3)_S 200 _t -(||)_S 200 _t -(36)_S 100 _t -(|)_S 200 _t -(37)_S 100 _t -(|)_S 200 _t -(38)_S 100 _t -(|)_S 200 _t -(39)_S 100 _t -(|)_S 200 _t -(40)_S 100 _t -(|)_S 200 _t -(41)_S 100 _t -(|)_S 200 _t -(42)_S 100 _t -(|)_S 200 _t -(43)_S 100 _t -(|)_S 200 _t -(44)_S 100 _t -(|)_S 200 _t -(45)_S 100 _t -(|)_S 200 _t -(46)_S 100 _t -(|)_S 100 _t -(47)_S 1200 6616 _m -100 _t -100 _t -100 _t -(4)_S 200 _t -(||)_S 200 _t -(48)_S 100 _t -(|)_S 200 _t -(49)_S 100 _t -(|)_S 200 _t -(50)_S 100 _t -(|)_S 200 _t -(51)_S 100 _t -(|)_S 200 _t -(52)_S 100 _t -(|)_S 200 _t -(53)_S 100 _t -(|)_S 200 _t -(54)_S 100 _t -(|)_S 200 _t -(55)_S 100 _t -(|)_S 200 _t -(56)_S 100 _t -(|)_S 200 _t -(57)_S 100 _t -(|)_S 200 _t -(58)_S 100 _t -(|)_S 100 _t -(59)_S 1200 6449 _m -100 _t -100 _t -100 _t -(5)_S 200 _t -(||)_S 200 _t -(60)_S 100 _t -(|)_S 200 _t -(61)_S 100 _t -(|)_S 200 _t -(62)_S 100 _t -(|)_S 200 _t -(63)_S 100 _t -(|)_S 200 _t -(64)_S 100 _t -(|)_S 200 _t -(65)_S 100 _t -(|)_S 200 _t -(66)_S 100 _t -(|)_S 200 _t -(67)_S 100 _t -(|)_S 200 _t -(68)_S 100 _t -(|)_S 200 _t -(69)_S 100 _t -(|)_S 200 _t -(70)_S 100 _t -(|)_S 100 _t -(71)_S 1200 6282 _m -100 _t -100 _t -100 _t -(6)_S 200 _t -(||)_S 200 _t -(72)_S 100 _t -(|)_S 200 _t -(73)_S 100 _t -(|)_S 200 _t -(74)_S 100 _t -(|)_S 200 _t -(75)_S 100 _t -(|)_S 200 _t -(76)_S 100 _t -(|)_S 200 _t -(77)_S 100 _t -(|)_S 200 _t -(78)_S 100 _t -(|)_S 200 _t -(79)_S 100 _t -(|)_S 200 _t -(80)_S 100 _t -(|)_S 200 _t -(81)_S 100 _t -(|)_S 200 _t -(82)_S 100 _t -(|)_S 100 _t -(83)_S 1200 6115 _m -100 _t -100 _t -100 _t -(7)_S 200 _t -(||)_S 200 _t -(84)_S 100 _t -(|)_S 200 _t -(85)_S 100 _t -(|)_S 200 _t -(86)_S 100 _t -(|)_S 200 _t -(87)_S 100 _t -(|)_S 200 _t -(88)_S 100 _t -(|)_S 200 _t -(89)_S 100 _t -(|)_S 200 _t -(90)_S 100 _t -(|)_S 200 _t -(91)_S 100 _t -(|)_S 200 _t -(92)_S 100 _t -(|)_S 200 _t -(93)_S 100 _t -(|)_S 200 _t -(94)_S 100 _t -(|)_S 100 _t -(95)_S 1200 5948 _m -100 _t -100 _t -100 _t -(8)_S 200 _t -(||)_S 200 _t -(96)_S 100 _t -(|)_S 200 _t -(97)_S 100 _t -(|)_S 200 _t -(98)_S 100 _t -(|)_S 200 _t -(99)_S 100 _t -(|)_S 100 _t -(100)_S 100 _t -(|)_S 100 _t -(101)_S 100 _t -(|)_S 100 _t -(102)_S 100 _t -(|)_S 100 _t -(103)_S 100 _t -(|)_S 100 _t -(104)_S 100 _t -(|)_S 100 _t -(105)_S 100 _t -(|)_S 100 _t -(106)_S 100 _t -(|)_S 100 _t -(107)_S 1200 5781 _m -100 _t -100 _t -100 _t -(9)_S 200 _t -(||)_S 100 _t -(108)_S 100 _t -(|)_S 100 _t -(109)_S 100 _t -(|)_S 100 _t -(110)_S 100 _t -(|)_S 100 _t -(111)_S 100 _t -(|)_S 100 _t -(112)_S 100 _t -(|)_S 100 _t -(113)_S 100 _t -(|)_S 100 _t -(114)_S 100 _t -(|)_S 100 _t -(115)_S 100 _t -(|)_S 100 _t -(116)_S 100 _t -(|)_S 100 _t -(117)_S 100 _t -(|)_S 100 _t -(118)_S 100 _t -(|)_S 100 _t -(119)_S 1200 5614 _m -100 _t -100 _t -(10)_S 200 _t -(||)_S 100 _t -(120)_S 100 _t -(|)_S 100 _t -(121)_S 100 _t -(|)_S 100 _t -(122)_S 100 _t -(|)_S 100 _t -(123)_S 100 _t -(|)_S 100 _t -(124)_S 100 _t -(|)_S 100 _t -(125)_S 100 _t -(|)_S 100 _t -(126)_S 100 _t -(|)_S 100 _t -(127)_S 100 _t -(|)_S 1200 5113 _m -100 _t -100 _t -100 _t -100 _t -100 _t -100 _t -100 _t -100 _t -100 _t -100 _t -100 _t -100 _t -100 _t -100 _t -100 _t -100 _t -100 _t -100 _t -100 _t -100 _t -100 _t -100 _t -100 _t -100 _t -100 _t -100 _t -100 _t -100 _t -100 _t -100 _t -100 _t -100 _t -(BIBLIOGRAPHY)_S 1200 4779 _m -100 _t -100 _t -("MIDI)_S 100 _t -(Systems)_S 100 _t -(and)_S 100 _t -(Control")_S 100 _t -(Francis)_S 100 _t -(Rumsey)_S 200 _t -(1990)_S 100 _t -(Focal)_S 100 _t -(Press)_S 1200 4445 _m -100 _t -100 _t -("MIDI)_S 100 _t -(and)_S 100 _t -(Sound)_S 100 _t -(Book)_S 100 _t -(for)_S 100 _t -(the)_S 100 _t -(Atari)_S 100 _t -(ST")_S 100 _t -(Bernd)_S 100 _t -(Enders)_S 100 _t -(and)_S 100 _t -(Wolfgang)_S 100 _t -(Klemme)_S 2109 4278 _m -100 _t -(1989)_S 100 _t -(M&T)_S 100 _t -(Publishing,)_S 100 _t -(Inc.)_S 1200 3944 _m -100 _t -100 _t -(MIDI)_S 100 _t -(file)_S 100 _t -(specs)_S 100 _t -(and)_S 100 _t -(general)_S 100 _t -(MIDI)_S 100 _t -(specs)_S 100 _t -(were)_S 100 _t -(also)_S 100 _t -(obtained)_S 100 _t -(by)_S 100 _t -(sending)_S 100 _t -(e-mail)_S 1200 3777 _m -(to)_S 2109 3777 _m -100 _t -(LISTSERV@AUVM.AMERICAN.EDU)_S 100 _t -(with)_S 100 _t -(the)_S 100 _t -(phrase)_S 100 _t -(GET)_S 100 _t -(MIDISPEC)_S 100 _t -(PACKAGE)_S 100 _t -(in)_S 1200 3610 _m -(the)_S 100 _t -(message.)_S 1200 3276 _m -100 _t -100 _t -_ep -_ed end end -%-12345X - ----------------------------- MIDINOTE.PS ---------------------------------- - -%!PS-Adobe-3.0 EPSF-2.0 -%%Creator: Windows PSCRIPT -%%Title: KEYS.CDR from CorelDRAW! -%%BoundingBox: 19 17 594 776 -%%DocumentNeededResources: (atend) -%%DocumentSuppliedResources: (atend) -%%Pages: 0 -%%BeginResource: procset Win35Dict 3 1 -/Win35Dict 60 dict def Win35Dict begin/bd{bind def}bind def/in{72 -mul}bd/ed{exch def}bd/ld{load def}bd/tr/translate ld/gs/gsave ld/gr -/grestore ld/fPP false def/SS{fPP{/SV save def}{gs}ifelse}bd/RS{fPP{SV -restore}{gr}ifelse}bd/EJ{gsave showpage grestore}bd/#C{userdict begin -/#copies ed end}bd/FEbuf 2 string def/FEglyph(G )def/FE{1 exch{dup -16 FEbuf cvrs FEglyph exch 1 exch putinterval 1 index exch FEglyph -cvn put}for}bd/SM{/iRes ed/cyP ed/cxPg ed/cyM ed/cxM ed 0 ne{0 cyP -72 mul 100 div tr -90 rotate}if pop}bd/CB{moveto/dy ed/dx ed dx 0 rlineto -0 dy rlineto dx neg 0 rlineto closepath clip newpath}bd end -%%EndResource -/SVDoc save def -%%EndProlog -%%BeginSetup -Win35Dict begin -%%EndSetup -SS -0 0 26 22 799 1100 300 SM -2397 3162 0 0 CB -%%BeginSetup -/AutoFlatness false def -% Options: Emulsion Up -% Options: Print Positive Output -/SepsColor false def -/ATraps false def -%%EndSetup -%%BeginProlog -%%BeginResource: procset wCorel4Dict -%Copyright (c)1992, 1993 Corel Corporation. All rights reserved. v4.00.00 -/wCorel4Dict 300 dict def wCorel4Dict begin -/bd{bind def}bind def/ld{load def}bd/xd{exch def}bd -/_ null def/rp{{pop}repeat}bd/@cp/closepath ld -/@gs/gsave ld/@gr/grestore ld/@np/newpath ld -/Tl/translate ld/$sv 0 def/@sv{/$sv save def}bd -/@rs{$sv restore}bd/spg/showpage ld/showpage{}bd -currentscreen/@dsp xd/$dsp/@dsp def/$dsa xd -/$dsf xd/$sdf false def/$SDF false def/$Scra 0 def -/SetScr/setscreen ld/setscreen{3 rp}bd/@ss{2 index 0 eq{$dsf 3 1 roll -4 -1 roll pop}if exch $Scra add exch load SetScr}bd -/$c 0 def/$m 0 def/$y 0 def/$k 0 def/$t 1 def -/$n _ def/$o 0 def/$fil 0 def/$C 0 def/$M 0 def -/$Y 0 def/$K 0 def/$T 1 def/$N _ def/$O 0 def -/$PF false def/s1c 0 def/s1m 0 def/s1y 0 def -/s1k 0 def/s1t 0 def/s1n _ def/$bkg false def -/SK 0 def/SM 0 def/SY 0 def/SC 0 def/SepMode 0 def -/CurrentInkName (Composite) def/$ink -1 def -/$op false def matrix currentmatrix/$ctm xd -/$ptm matrix def/$ttm matrix def/$stm matrix def -/$fst 128 def/$pad 0 def/$rox 0 def/$roy 0 def -/CorelDrawReencodeVect [ 16#0/grave 16#5/breve 16#6/dotaccent 16#8/ring 16#A/hungarumlaut 16#B/ogonek 16#C/caron 16#D/dotlessi -16#82/quotesinglbase/florin/quotedblbase/ellipsis/dagger/daggerdbl -16#88/circumflex/perthousand/Scaron/guilsinglleft/OE -16#91/quoteleft/quoteright/quotedblleft/quotedblright/bullet/endash/emdash -16#98/tilde/trademark/scaron/guilsinglright/oe -16#9F/Ydieresis 16#A1/exclamdown/cent/sterling/currency/yen/brokenbar/section -16#a8/dieresis/copyright/ordfeminine/guillemotleft/logicalnot/minus/registered/macron -16#b0/degree/plusminus/twosuperior/threesuperior/acute/mu/paragraph/periodcentered -16#b8/cedilla/onesuperior/ordmasculine/guillemotright/onequarter/onehalf/threequarters/questiondown -16#c0/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE/Ccedilla -16#c8/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex/Idieresis -16#d0/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis/multiply -16#d8/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls -16#e0/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla -16#e8/egrave/eacute/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis -16#f0/eth/ntilde/ograve/oacute/ocircumflex/otilde/odieresis/divide -16#f8/oslash/ugrave/uacute/ucircumflex/udieresis/yacute/thorn/ydieresis -] def AutoFlatness{/@ifl{dup currentflat exch sub 10 gt{ -([Error: PathTooComplex; OffendingCommand: AnyPaintingOperator]\n) -print flush newpath exit}{currentflat 2 add setflat}ifelse}bd -/@fill/fill ld/fill{currentflat{{@fill}stopped{@ifl}{exit}ifelse -}bind loop setflat}bd/@eofill/eofill ld/eofill{currentflat{ -{@eofill}stopped{@ifl}{exit}ifelse}bind loop -setflat}bd/@clip/clip ld/clip{currentflat{{@clip}stopped{@ifl}{exit} -ifelse}bind loop setflat}bd/@eoclip/eoclip ld -/eoclip{currentflat{{@eoclip}stopped{@ifl}{exit}ifelse}bind loop -setflat}bd/@stroke/stroke ld/stroke{currentflat{{@stroke}stopped{@ifl} -{exit}ifelse}bind loop setflat}bd}if/d/setdash ld -/j/setlinejoin ld/J/setlinecap ld/M/setmiterlimit ld -/w/setlinewidth ld/O{/$o xd}bd/R{/$O xd}bd -/W/eoclip ld/c/curveto ld/C/c ld/l/lineto ld -/L/l ld/rl/rlineto ld/m/moveto ld/n/newpath ld -/N/newpath ld/P{11 rp}bd/u{}bd/U{}bd/A{pop}bd -/q/@gs ld/Q/@gr ld/`{}bd/~{}bd/@{}bd/&{}bd -/@j{@sv @np}bd/@J{@rs}bd/g{1 exch sub/$k xd -/$c 0 def/$m 0 def/$y 0 def/$t 1 def/$n _ def/$fil 0 def}bd -/G{1 sub neg/$K xd _ 1 0 0 0/$C xd/$M xd/$Y xd/$T xd -/$N xd}bd/k{1 index type/stringtype eq{/$t xd -/$n xd}{/$t 0 def/$n _ def}ifelse/$k xd/$y xd -/$m xd/$c xd/$fil 0 def}bd/K{1 index type -/stringtype eq{/$T xd/$N xd}{/$T 0 def/$N _ def}ifelse -/$K xd/$Y xd/$M xd/$C xd}bd/sf{1 index type -/stringtype eq{/s1t xd/s1n xd}{/s1t 0 def -/s1n _ def}ifelse/s1k xd/s1y xd/s1m xd/s1c xd}bd -/i{dup 0 ne{setflat}{pop}ifelse}bd/v{4 -2 roll -2 copy 6 -2 roll c}bd/V/v ld/y{2 copy c}bd -/Y/y ld/@w{matrix rotate/$ptm xd matrix scale -$ptm dup concatmatrix/$ptm xd 1 eq{$ptm exch dup concatmatrix -/$ptm xd}if 1 w}bd/@g{1 eq dup/$sdf xd{/$scp xd -/$sca xd/$scf xd}if}bd/@G{1 eq dup/$SDF xd{/$SCP xd -/$SCA xd/$SCF xd}if}bd/@D{2 index 0 eq{$dsf 3 1 roll -4 -1 roll pop}if 3 copy exch $Scra add exch load -SetScr/$dsp xd/$dsa xd/$dsf xd}bd/$ngx{$SDF{$SCF -SepMode 0 eq{$SCA}{$dsa}ifelse $SCP @ss}if}bd -/p{/$pm xd 7{pop}repeat/$pyf xd/$pxf xd/$pn xd -/$fil 1 def}bd/@MN{2 copy le{pop}{exch pop}ifelse}bd -/@MX{2 copy ge{pop}{exch pop}ifelse}bd/InRange{3 -1 roll -@MN @MX}bd/wDstChck{2 1 roll dup 3 -1 roll -eq{1 add}if}bd/@dot{dup mul exch dup mul add -1 exch sub}bd/@lin{exch pop abs 1 exch sub}bd -/SetRgb/setrgbcolor ld/SetHsb/sethsbcolor ld -/GetRgb/currentrgbcolor ld/GetHsb/currenthsbcolor ld -/SetGry/setgray ld/GetGry/currentgray ld/cmyk2rgb{3{dup 5 -1 roll -add 1 exch sub dup 0 lt{pop 0}if exch}repeat -pop}bd/rgb2cmyk{3{1 exch sub 3 1 roll}repeat -3 copy @MN @MN 3{dup 5 -1 roll sub neg exch}repeat}bd -/rgb2hsb{SetRgb GetHsb}bd/hsb2rgb{3 -1 roll -dup floor sub 3 1 roll SetHsb GetRgb}bd/rgb2g{2 index .299 mul -2 index .587 mul add 1 index .114 mul add 4 1 roll -3 rp}bd/WaldoColor where{pop}{/setcmykcolor where{pop -/SetCmyk/setcmykcolor ld}{/SetCmyk{cmyk2rgb -SetRgb}bd}ifelse/currentcmykcolor where{pop -/GetCmyk/currentcmykcolor ld}{/GetCmyk{GetRgb -rgb2cmyk}bd}ifelse/setoverprint where{pop}{/setoverprint{/$op xd}bd -}ifelse/currentoverprint where{pop}{/currentoverprint{$op}bd}ifelse -/colorimage where{pop/ColorImage/colorimage ld}{/ColorImage{ -/ncolors exch def pop/dataaq exch def{dataaq -ncolors dup 3 eq{/$dat exch def 0 1 $dat length -3 div 1 sub{dup 3 mul $dat 1 index get 255 div -$dat 2 index 1 add get 255 div $dat 3 index 2 add get -255 div rgb2g 255 mul cvi exch pop $dat 3 1 roll put}for -$dat 0 $dat length 3 idiv getinterval pop}{4 eq{/$dat exch def -0 1 $dat length 4 div 1 sub{dup 4 mul $dat 1 index get -255 div $dat 2 index 1 add get 255 div $dat 3 index 2 add get -255 div $dat 4 index 3 add get 255 div cmyk2rgb rgb2g 255 mul -cvi exch pop $dat 3 1 roll put}for $dat 0 $dat length -ncolors idiv getinterval}if}ifelse}image}bd}ifelse -/@tc{5 -1 roll dup 1 ge{pop}{4{dup 6 -1 roll -mul exch}repeat pop}ifelse}bd/@scc{1 eq setoverprint -dup _ eq{pop SepMode 0 eq{SetCmyk 0}{0 4 $ink sub index -exch pop 5 1 roll 4 rp SepsColor true eq{$ink 3 gt{1 sub neg dup SetGry -exch}{dup 0 0 0 4 $ink roll SetCmyk}ifelse}{1 sub neg dup SetGry}ifelse -}ifelse exch pop}{SepMode 0 eq{pop @tc SetCmyk 0}{CurrentInkName eq{ -4 index}{0}ifelse 6 1 roll 5 rp 1 sub neg dup SetGry}ifelse}ifelse -SepMode 0 eq{pop true}{1 eq currentoverprint and not}ifelse}bd -/setcmykcolor{1 5 1 roll _ currentoverprint @scc -pop}bd/currentcmykcolor{0 0 0 0}bd/setrgbcolor{rgb2cmyk -setcmykcolor}bd/currentrgbcolor{currentcmykcolor -cmyk2rgb}bd/sethsbcolor{hsb2rgb setrgbcolor}bd -/currenthsbcolor{currentrgbcolor rgb2hsb}bd -/setgray{dup dup setrgbcolor}bd/currentgray{currentrgbcolor -rgb2g}bd}ifelse/WaldoColor true def/@sft{$tllx $pxf add dup $tllx gt -{$pwid sub}if/$tx xd $tury $pyf sub dup $tury lt{$phei add}if -/$ty xd}bd/@stb{pathbbox/$ury xd/$urx xd/$lly xd/$llx xd}bd -/@ep{{cvx exec}forall}bd/@tp{@sv/$in true def -2 copy dup $lly le{/$in false def}if $phei sub $ury ge{/$in false def}if -dup $urx ge{/$in false def}if $pwid add $llx le{/$in false def}if -$in{@np 2 copy m $pwid 0 rl 0 $phei neg rl $pwid neg 0 rl -0 $phei rl clip @np $pn cvlit load aload pop -7 -1 roll 5 index sub 7 -1 roll 3 index sub Tl -matrix currentmatrix/$ctm xd @ep 4 rp}{2 rp}ifelse -@rs}bd/@th{@sft 0 1 $tly 1 sub{dup $psx mul $tx add{dup $llx gt -{$pwid sub}{exit}ifelse}loop exch $phei mul -$ty exch sub 0 1 $tlx 1 sub{$pwid mul 3 copy -3 -1 roll add exch @tp pop}for 2 rp}for}bd/@tv{@sft -0 1 $tlx 1 sub{dup $pwid mul $tx add exch $psy mul $ty exch sub{ -dup $ury lt{$phei add}{exit}ifelse}loop 0 1 $tly 1 sub{$phei mul -3 copy sub @tp pop}for 2 rp}for}bd/@pf{@gs $ctm setmatrix -$pm concat @stb eoclip Bburx Bbury $pm itransform -/$tury xd/$turx xd Bbllx Bblly $pm itransform -/$tlly xd/$tllx xd/$wid $turx $tllx sub def -/$hei $tury $tlly sub def @gs $vectpat{1 0 0 0 0 _ $o @scc{eofill}if}{ -$t $c $m $y $k $n $o @scc{SepMode 0 eq $pfrg or{$tllx $tlly Tl -$wid $hei scale <00> 8 1 false [ 8 0 0 1 0 0 ]{}imagemask}{ -/$bkg true def}ifelse}if}ifelse @gr $wid 0 gt $hei 0 gt and{ -$pn cvlit load aload pop/$pd xd 3 -1 roll sub/$phei xd -exch sub/$pwid xd $wid $pwid div ceiling 1 add/$tlx xd -$hei $phei div ceiling 1 add/$tly xd $psx 0 eq{@tv}{@th}ifelse}if -@gr @np/$bkg false def}bd/@dlt{$fse $fss sub/nff xd -$frb dup 1 eq exch 2 eq or{$frt dup $frc $frm $fry $frk -@tc 4 copy cmyk2rgb rgb2hsb 3 copy/myb xd/mys xd -/myh xd $tot $toc $tom $toy $tok @tc cmyk2rgb -rgb2hsb 3 1 roll 4 1 roll 5 1 roll sub neg nff div/kdb xd -sub neg nff div/kds xd sub neg dup 0 eq{pop -$frb 2 eq{.99}{-.99}ifelse}if dup $frb 2 eq -exch 0 lt and{1 add}if dup $frb 1 eq exch 0 gt and{1 sub}if -nff div/kdh xd}{$frt dup $frc $frm $fry $frk -@tc 5 copy $tot dup $toc $tom $toy $tok @tc 5 1 roll -6 1 roll 7 1 roll 8 1 roll 9 1 roll sub neg nff div/$dk xd -sub neg nff div/$dy xd sub neg nff div/$dm xd -sub neg nff div/$dc xd sub neg nff div/$dt xd}ifelse}bd -/ffcol{5 copy $fsit 0 eq{setcmykcolor pop}{SepMode 0 ne{ -4 index 1 sub neg SetGry 5 rp}{setcmykcolor pop}ifelse}ifelse}bd -/@ftl{1 index 4 index sub dup $pad mul dup/$pdw xd -2 mul sub $fst div/$wid xd 2 index sub/$hei xd -pop Tl @dlt $fss 0 eq{ffcol 0 0 m 0 $hei l $pdw $hei l -$pdw 0 l @cp fill $pdw 0 Tl}if $fss $wid mul 0 Tl -nff{ffcol 0 0 m 0 $hei l $wid $hei l $wid 0 l -@cp fill $wid 0 Tl $frb dup 1 eq exch 2 eq or{4 rp -myh mys myb kdb add 3 1 roll kds add 3 1 roll -kdh add 3 1 roll 3 copy/myb xd/mys xd/myh xd -hsb2rgb rgb2cmyk}{$dk add 5 1 roll $dy add 5 1 roll -$dm add 5 1 roll $dc add 5 1 roll $dt add 5 1 roll}ifelse}repeat -5 rp $tot dup $toc $tom $toy $tok @tc ffcol 0 0 m -0 $hei l $pdw $hei l $pdw 0 l @cp fill 5 rp}bd -/@ftr{1 index 4 index sub dup $rox mul/$row xd -2 div 1 index 4 index sub dup $roy mul/$roh xd -2 div 2 copy dup mul exch dup mul add sqrt $row dup mul -$roh dup mul add sqrt add dup/$hei xd $fst div/$wid xd -4 index add $roh add exch 5 index add $row add -exch Tl 4 rp @dlt $fss 0 eq{ffcol fill 1.0 $pad 2 mul sub -dup scale}if $hei $fss $wid mul sub/$hei xd -nff{ffcol $wid 0 m 0 0 $hei 0 360 arc fill/$hei $hei $wid sub def -$frb dup 1 eq exch 2 eq or{4 rp myh mys myb -kdb add 3 1 roll kds add 3 1 roll kdh add 3 1 roll -3 copy/myb xd/mys xd/myh xd hsb2rgb rgb2cmyk}{$dk add 5 1 roll -$dy add 5 1 roll $dm add 5 1 roll $dc add 5 1 roll -$dt add 5 1 roll}ifelse}repeat 5 rp}bd/@ftc{1 index 4 index sub -dup $rox mul/$row xd 2 div 1 index 4 index sub -dup $roy mul/$roh xd 2 div 2 copy dup mul exch dup mul add sqrt -$row dup mul $roh dup mul add sqrt add dup/$hei xd -$fst div/$wid xd 4 index add $roh add exch 5 index add $row add -exch Tl 4 rp @dlt $fss 0 eq{ffcol fill}{n}ifelse -/$dang 180 $fst 1 sub div def/$sang $dang -2 div 180 add def -/$eang $dang 2 div 180 add def/$sang $sang $dang $fss mul add def -/$eang $eang $dang $fss mul add def/$sang $eang $dang sub def -nff{ffcol $wid 0 m 0 0 $hei $sang $fan add $eang $fan add arc fill -$wid 0 m 0 0 $hei $eang neg $fan add $sang neg $fan add arc fill -/$sang $eang def/$eang $eang $dang add def -$frb dup 1 eq exch 2 eq or{4 rp myh mys myb -kdb add 3 1 roll kds add 3 1 roll kdh add 3 1 roll -3 copy/myb xd/mys xd/myh xd hsb2rgb rgb2cmyk}{$dk add 5 1 roll -$dy add 5 1 roll $dm add 5 1 roll $dc add 5 1 roll -$dt add 5 1 roll}ifelse}repeat 5 rp}bd/@ff{/$fss 0 def -1 1 $fsc 1 sub{dup 1 sub $fsit 0 eq{$fsa exch 5 mul -5 getinterval aload 2 rp/$frk xd/$fry xd/$frm xd/$frc xd -/$frn _ def/$frt 1 def $fsa exch 5 mul 5 getinterval aload pop -$fss add/$fse xd/$tok xd/$toy xd/$tom xd/$toc xd -/$ton _ def/$tot 1 def}{$fsa exch 7 mul 7 getinterval aload 2 rp -/$frt xd/$frn xd/$frk xd/$fry xd/$frm xd/$frc xd -$fsa exch 7 mul 7 getinterval aload pop $fss add/$fse xd -/$tot xd/$ton xd/$tok xd/$toy xd/$tom xd/$toc xd}ifelse -$fsit 0 eq SepMode 0 eq or dup not CurrentInkName $frn eq -and or{@sv eoclip currentflat dup 5 mul setflat -Bbllx Bblly Bburx Bbury $fty 2 eq{@ftc}{$fty 1 eq{1 index 3 index m -2 copy l 3 index 1 index l 3 index 3 index l -@cp @ftr}{1 index 3 index m 2 copy l 3 index 1 index l -3 index 3 index l @cp 4 rp $fan rotate pathbbox -@ftl}ifelse}ifelse setflat @rs/$fss $fse def}if}for -@np}bd/@Pf{@sv SepMode 0 eq $ink 3 eq or{0 J 0 j [] 0 d -$t $c $m $y $k $n $o @scc pop $ctm setmatrix -72 1000 div dup matrix scale dup concat dup Bburx exch Bbury exch -itransform ceiling cvi/Bbury xd ceiling cvi/Bburx xd -Bbllx exch Bblly exch itransform floor cvi/Bblly xd -floor cvi/Bbllx xd $Prm aload pop $Psn load exec}{1 SetGry eofill}ifelse -@rs @np}bd/F{matrix currentmatrix $sdf{$scf $sca $scp @ss}if -$fil 1 eq{@pf}{$fil 2 eq{@ff}{$fil 3 eq{@Pf}{$t $c $m $y $k $n $o -@scc{eofill}{@np}ifelse}ifelse}ifelse}ifelse -$sdf{$dsf $dsa $dsp @ss}if setmatrix}bd/f{@cp F}bd -/S{matrix currentmatrix $ctm setmatrix $SDF{$SCF $SCA $SCP @ss}if -$T $C $M $Y $K $N $O @scc{matrix currentmatrix -$ptm concat stroke setmatrix}{@np}ifelse $SDF{$dsf $dsa $dsp @ss}if -setmatrix}bd/s{@cp S}bd/B{@gs F @gr S}bd/b{@cp B}bd -/E{5 array astore exch cvlit exch def}bd/@cc{ -currentfile $dat readhexstring pop}bd/@sm{/$ctm $ctm currentmatrix def -}bd/@E{/Bbury xd/Bburx xd/Bblly xd/Bbllx xd}bd -/@c{@cp}bd/@p{/$fil 1 def 1 eq dup/$vectpat xd{/$pfrg true def}{@gs -$t $c $m $y $k $n $o @scc/$pfrg xd @gr}ifelse -/$pm xd/$psy xd/$psx xd/$pyf xd/$pxf xd/$pn xd}bd -/@P{/$fil 3 def/$Psn xd array astore/$Prm xd}bd -/@k{/$fil 2 def/$roy xd/$rox xd/$pad xd/$fty xd/$fan xd -$fty 1 eq{/$fan 0 def}if/$frb xd/$fst xd/$fsc xd -/$fsa xd/$fsit 0 def}bd/@x{/$fil 2 def/$roy xd/$rox xd/$pad xd -/$fty xd/$fan xd $fty 1 eq{/$fan 0 def}if/$frb xd -/$fst xd/$fsc xd/$fsa xd/$fsit 1 def}bd/@ii{concat -3 index 3 index m 3 index 1 index l 2 copy l -1 index 3 index l 3 index 3 index l clip 4 rp}bd -/tcc{@cc}def/@i{@sm @gs @ii 6 index 1 ne{/$frg true def -2 rp}{1 eq{s1t s1c s1m s1y s1k s1n $o @scc -/$frg xd}{/$frg false def}ifelse 1 eq{@gs $ctm setmatrix -F @gr}if}ifelse @np/$ury xd/$urx xd/$lly xd/$llx xd -/$bts xd/$hei xd/$wid xd/$dat $wid $bts mul 8 div ceiling cvi string def -$bkg $frg or{$SDF{$SCF $SCA $SCP @ss}if $llx $lly Tl -$urx $llx sub $ury $lly sub scale $bkg{$t $c $m $y $k $n $o @scc pop}if -$wid $hei abs $bts 1 eq{$bkg}{$bts}ifelse [ $wid 0 0 -$hei neg 0 $hei 0 gt{$hei}{0}ifelse]/tcc load -$bts 1 eq{imagemask}{image}ifelse $SDF{$dsf $dsa $dsp @ss}if}{ -$hei abs{tcc pop}repeat}ifelse @gr $ctm setmatrix}bind def -/@M{@sv}bd/@N{/@cc{}def 1 eq{12 -1 roll neg 12 1 roll -@I}{13 -1 roll neg 13 1 roll @i}ifelse @rs}bd -/@I{@sm @gs @ii @np/$ury xd/$urx xd/$lly xd/$llx xd -/$ncl xd/$bts xd/$hei xd/$wid xd/$dat $wid $bts mul $ncl mul 8 div ceiling cvi string def -$ngx $llx $lly Tl $urx $llx sub $ury $lly sub scale -$wid $hei abs $bts [ $wid 0 0 $hei neg 0 $hei 0 gt{$hei}{0}ifelse] -/@cc load false $ncl ColorImage $SDF{$dsf $dsa $dsp @ss}if -@gr $ctm setmatrix}bd/z{exch findfont exch scalefont setfont}bd -/ZB{9 dict dup begin 4 1 roll/FontType 3 def -/FontMatrix xd/FontBBox xd/Encoding 256 array def -0 1 255{Encoding exch/.notdef put}for/CharStrings 256 dict def -CharStrings/.notdef{}put/Metrics 256 dict def -Metrics/.notdef 3 -1 roll put/BuildChar{exch -dup/$char exch/Encoding get 3 index get def -dup/Metrics get $char get aload pop setcachedevice -begin Encoding exch get CharStrings exch get -end exec}def end definefont pop}bd/ZBAddChar{findfont begin -dup 4 1 roll dup 6 1 roll Encoding 3 1 roll put -CharStrings 3 1 roll put Metrics 3 1 roll put -end}bd/Z{findfont dup maxlength 2 add dict exch -dup{1 index/FID ne{3 index 3 1 roll put}{2 rp}ifelse}forall -pop dup dup/Encoding get 256 array copy dup/$fe xd -/Encoding exch put dup/Fontname 3 index put -3 -1 roll dup length 0 ne{0 exch{dup type 0 type eq{exch pop}{ -$fe exch 2 index exch put 1 add}ifelse}forall -pop}if dup 256 dict dup/$met xd/Metrics exch put -dup/FontMatrix get 0 get 1000 mul 1 exch div -3 index length 256 eq{0 1 255{dup $fe exch get -dup/.notdef eq{2 rp}{5 index 3 -1 roll get -2 index mul $met 3 1 roll put}ifelse}for}if -pop definefont pop pop}bd/@ftx{{currentpoint 3 -1 roll -(0) dup 3 -1 roll 0 exch put dup @gs true charpath -$ctm setmatrix @@txt @gr @np stringwidth pop 3 -1 roll add exch moveto -}forall}bd/@ft{matrix currentmatrix exch $sdf{$scf $sca $scp @ss}if -$fil 1 eq{/@@txt/@pf ld @ftx}{$fil 2 eq{/@@txt/@ff ld @ftx}{$fil 3 eq -{/@@txt/@Pf ld @ftx}{$t $c $m $y $k $n $o @scc{show}{pop}ifelse}ifelse -}ifelse}ifelse $sdf{$dsf $dsa $dsp @ss}if setmatrix}bd -/@st{matrix currentmatrix exch $SDF{$SCF $SCA $SCP @ss}if -$T $C $M $Y $K $N $O @scc{{currentpoint 3 -1 roll -(0) dup 3 -1 roll 0 exch put dup @gs true charpath -$ctm setmatrix $ptm concat stroke @gr @np stringwidth pop 3 -1 roll add exch moveto -}forall}{pop}ifelse $SDF{$dsf $dsa $dsp @ss}if -setmatrix}bd/@te{@ft}bd/@tr{@st}bd/@ta{dup -@gs @ft @gr @st}bd/@t@a{dup @gs @st @gr @ft}bd -/@tm{@sm concat}bd/e{/t{@te}def}bd/r{/t{@tr}def}bd -/o{/t{pop}def}bd/a{/t{@ta}def}bd/@a{/t{@t@a}def}bd -/t{@te}def/T{@np $ctm setmatrix/$ttm matrix def}bd -/ddt{t}def/@t{/$stm $stm currentmatrix def -3 1 roll moveto $ttm concat ddt $stm setmatrix}bd -/@n{/$ttm exch matrix rotate def}bd/@s{}bd -/@l{}bd/@B{@gs S @gr F}bd/@b{@cp @B}bd/@sep{ -CurrentInkName (Composite) eq{/$ink -1 def}{CurrentInkName (Cyan) eq -{/$ink 0 def}{CurrentInkName (Magenta) eq{/$ink 1 def}{ -CurrentInkName (Yellow) eq{/$ink 2 def}{CurrentInkName (Black) eq -{/$ink 3 def}{/$ink 4 def}ifelse}ifelse}ifelse}ifelse}ifelse}bd -/@whi{@gs -72000 dup moveto -72000 72000 lineto -72000 dup lineto 72000 -72000 lineto closepath 1 SetGry fill -@gr}bd/@neg{ [{1 exch sub}/exec cvx currenttransfer/exec cvx] cvx settransfer -@whi}bd/currentscale{1 0 dtransform matrix defaultmatrix idtransform -dup mul exch dup mul add sqrt 0 1 dtransform -matrix defaultmatrix idtransform dup mul exch dup mul add sqrt}bd -/@unscale{currentscale 1 exch div exch 1 exch div exch scale}bd -/@square{dup 0 rlineto dup 0 exch rlineto neg 0 rlineto -closepath}bd/corelsym{gsave newpath Tl -90 rotate -7{45 rotate -.75 2 moveto 1.5 @square fill}repeat -grestore}bd/@reg{gsave newpath Tl -6 -6 moveto 12 @square -gsave 1 GetGry sub SetGry fill grestore 4{90 rotate -0 4 m 0 4 rl}repeat stroke 0 0 corelsym grestore}bd -/$corelmeter [1 .95 .75 .50 .25 .05 0] def -/@colormeter{@gs newpath 0 SetGry 0.3 setlinewidth -/Courier findfont 5 scalefont setfont/y exch def -/x exch def 0 1 6{x 20 sub y m 20 @square @gs $corelmeter exch get dup SetGry fill @gr -stroke x 2 add y 8 add moveto 100 mul 100 exch sub cvi 20 string cvs show -/y y 20 add def}for @gr}bd/@crop{gsave .3 setlinewidth -0 SetGry Tl rotate 0 0 m 0 -24 rl -4 -24 m 8 @square --4 -20 m 8 0 rl stroke grestore}bd/@colorbox{gsave -newpath Tl 100 exch sub 100 div SetGry -8 -8 moveto 16 @square fill -0 SetGry 10 -2 moveto show grestore}bd/deflevel 0 def -/@sax{/deflevel deflevel 1 add def}bd/@eax{ -/deflevel deflevel dup 0 gt{1 sub}if def deflevel 0 gt{/eax load}{eax} -ifelse}bd/eax{{exec}forall}bd/@rax{deflevel 0 eq{@rs @sv}if}bd -/@daq{dup type/arraytype eq{{}forall}if}bd -/@BMP{/@cc xd 12 index 1 eq{12 -1 roll pop -@i}{7 -2 roll 2 rp @I}ifelse}bd end -%%EndResource - -%%EndProlog -/#copies 1 def -wCorel4Dict begin -0.00 0.00 Tl -1.0000 1.0000 scale -%%BeginSetup -11.4737 setmiterlimit -0 45 /@dot @D -1.00 setflat -/$fst 128 def -%%EndSetup -[ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 278 -278 355 556 556 889 667 191 333 333 389 584 278 333 278 278 556 -556 556 556 556 556 556 556 556 556 278 278 584 584 584 556 1015 -667 667 722 722 667 611 778 722 278 500 667 556 833 722 778 667 -778 722 667 611 722 667 944 667 667 611 278 278 278 469 556 333 -556 556 500 556 556 278 556 556 222 222 500 222 833 556 556 556 -556 333 500 278 556 500 722 500 500 500 334 260 334 584 750 750 -750 222 556 333 1000 556 556 333 1000 667 333 1000 750 750 750 750 -222 222 333 333 350 556 1000 333 1000 500 333 944 750 750 667 278 -333 556 556 556 556 260 556 333 737 370 556 584 333 737 552 400 -549 333 333 333 576 537 278 333 333 365 556 834 834 834 611 667 -667 667 667 667 667 1000 722 667 667 667 667 278 278 278 278 722 -722 778 778 778 778 778 584 778 722 722 722 722 667 667 611 556 -556 556 556 556 556 889 500 556 556 556 556 278 278 278 278 556 -556 556 556 556 556 556 549 611 556 556 556 556 500 556 500 ] -CorelDrawReencodeVect /_R1-Helvetica /Helvetica Z - -%StartPage -@sv -/$ctm matrix currentmatrix def -@sv -%StartColorLayer (COMPOSITE) -%StartTile -/$ctm matrix currentmatrix def -@sv @sv -@rs 0 0 Tl 1.000000 1.000000 scale -0.000000 0.000000 Tl /$ctm matrix currentmatrix def @sv -@rax %%Note: Object -132.34 700.99 187.20 709.20 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.34 700.99 m -132.34 709.20 L -187.20 709.20 L -187.20 700.99 L -132.34 700.99 L -@c -S - -@rax %%Note: Object -132.41 270.43 168.05 275.90 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 270.43 m -132.41 275.90 L -168.05 275.90 L -168.05 270.43 L -132.41 270.43 L -@c -B - -@rax %%Note: Object -132.41 311.54 168.05 317.02 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 311.54 m -132.41 317.02 L -168.05 317.02 L -168.05 311.54 L -132.41 311.54 L -@c -B - -@rax %%Note: Object -132.41 303.34 168.05 308.81 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 303.34 m -132.41 308.81 L -168.05 308.81 L -168.05 303.34 L -132.41 303.34 L -@c -B - -@rax %%Note: Object -132.41 295.06 168.05 300.60 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 295.06 m -132.41 300.60 L -168.05 300.60 L -168.05 295.06 L -132.41 295.06 L -@c -B - -@rax %%Note: Object -132.41 264.89 187.27 273.17 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 264.89 m -132.41 273.17 L -187.27 273.17 L -187.27 264.89 L -132.41 264.89 L -@c -S - -@rax %%Note: Object -132.41 314.28 187.27 322.49 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 314.28 m -132.41 322.49 L -187.27 322.49 L -187.27 314.28 L -132.41 314.28 L -@c -S - -@rax %%Note: Object -132.41 306.07 187.27 314.28 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 306.07 m -132.41 314.28 L -187.27 314.28 L -187.27 306.07 L -132.41 306.07 L -@c -S - -@rax %%Note: Object -132.41 297.86 187.27 306.07 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 297.86 m -132.41 306.07 L -187.27 306.07 L -187.27 297.86 L -132.41 297.86 L -@c -S - -@rax %%Note: Object -132.41 273.17 187.27 281.38 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 273.17 m -132.41 281.38 L -187.27 281.38 L -187.27 273.17 L -132.41 273.17 L -@c -S - -@rax %%Note: Object -132.41 289.58 187.27 297.86 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 289.58 m -132.41 297.86 L -187.27 297.86 L -187.27 289.58 L -132.41 289.58 L -@c -S - -@rax %%Note: Object -132.41 281.38 187.27 289.58 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 281.38 m -132.41 289.58 L -187.27 289.58 L -187.27 281.38 L -132.41 281.38 L -@c -S - -@rax %%Note: Object -132.41 278.64 168.05 284.11 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 278.64 m -132.41 284.11 L -168.05 284.11 L -168.05 278.64 L -132.41 278.64 L -@c -B - -@rax %%Note: Object -132.41 97.70 168.05 103.18 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 97.70 m -132.41 103.18 L -168.05 103.18 L -168.05 97.70 L -132.41 97.70 L -@c -B - -@rax %%Note: Object -132.41 138.82 168.05 144.29 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 138.82 m -132.41 144.29 L -168.05 144.29 L -168.05 138.82 L -132.41 138.82 L -@c -B - -@rax %%Note: Object -132.41 130.61 168.05 136.08 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 130.61 m -132.41 136.08 L -168.05 136.08 L -168.05 130.61 L -132.41 130.61 L -@c -B - -@rax %%Note: Object -132.41 122.33 168.05 127.87 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 122.33 m -132.41 127.87 L -168.05 127.87 L -168.05 122.33 L -132.41 122.33 L -@c -B - -@rax %%Note: Object -132.41 92.16 187.27 100.44 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 92.16 m -132.41 100.44 L -187.27 100.44 L -187.27 92.16 L -132.41 92.16 L -@c -S - -@rax %%Note: Object -132.41 141.55 187.27 149.76 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 141.55 m -132.41 149.76 L -187.27 149.76 L -187.27 141.55 L -132.41 141.55 L -@c -S - -@rax %%Note: Object -132.41 133.34 187.27 141.55 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 133.34 m -132.41 141.55 L -187.27 141.55 L -187.27 133.34 L -132.41 133.34 L -@c -S - -@rax %%Note: Object -132.41 125.14 187.27 133.34 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 125.14 m -132.41 133.34 L -187.27 133.34 L -187.27 125.14 L -132.41 125.14 L -@c -S - -@rax %%Note: Object -132.41 100.44 187.27 108.65 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 100.44 m -132.41 108.65 L -187.27 108.65 L -187.27 100.44 L -132.41 100.44 L -@c -S - -@rax %%Note: Object -132.41 116.86 187.27 125.14 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 116.86 m -132.41 125.14 L -187.27 125.14 L -187.27 116.86 L -132.41 116.86 L -@c -S - -@rax %%Note: Object -132.41 108.65 187.27 116.86 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 108.65 m -132.41 116.86 L -187.27 116.86 L -187.27 108.65 L -132.41 108.65 L -@c -S - -@rax %%Note: Object -132.41 105.91 168.05 111.38 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 105.91 m -132.41 111.38 L -168.05 111.38 L -168.05 105.91 L -132.41 105.91 L -@c -B - -@rax %%Note: Object -132.41 155.23 168.05 160.70 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 155.23 m -132.41 160.70 L -168.05 160.70 L -168.05 155.23 L -132.41 155.23 L -@c -B - -@rax %%Note: Object -132.41 196.34 168.05 201.82 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 196.34 m -132.41 201.82 L -168.05 201.82 L -168.05 196.34 L -132.41 196.34 L -@c -B - -@rax %%Note: Object -132.41 188.14 168.05 193.61 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 188.14 m -132.41 193.61 L -168.05 193.61 L -168.05 188.14 L -132.41 188.14 L -@c -B - -@rax %%Note: Object -132.41 179.86 168.05 185.40 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 179.86 m -132.41 185.40 L -168.05 185.40 L -168.05 179.86 L -132.41 179.86 L -@c -B - -@rax %%Note: Object -132.41 149.69 187.27 157.97 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 149.69 m -132.41 157.97 L -187.27 157.97 L -187.27 149.69 L -132.41 149.69 L -@c -S - -@rax %%Note: Object -132.41 199.08 187.27 207.29 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 199.08 m -132.41 207.29 L -187.27 207.29 L -187.27 199.08 L -132.41 199.08 L -@c -S - -@rax %%Note: Object -132.41 190.87 187.27 199.08 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 190.87 m -132.41 199.08 L -187.27 199.08 L -187.27 190.87 L -132.41 190.87 L -@c -S - -@rax %%Note: Object -132.41 182.66 187.27 190.87 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 182.66 m -132.41 190.87 L -187.27 190.87 L -187.27 182.66 L -132.41 182.66 L -@c -S - -@rax %%Note: Object -132.41 157.97 187.27 166.18 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 157.97 m -132.41 166.18 L -187.27 166.18 L -187.27 157.97 L -132.41 157.97 L -@c -S - -@rax %%Note: Object -132.41 174.38 187.27 182.66 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 174.38 m -132.41 182.66 L -187.27 182.66 L -187.27 174.38 L -132.41 174.38 L -@c -S - -@rax %%Note: Object -132.41 166.18 187.27 174.38 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 166.18 m -132.41 174.38 L -187.27 174.38 L -187.27 166.18 L -132.41 166.18 L -@c -S - -@rax %%Note: Object -132.41 163.44 168.05 168.91 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 163.44 m -132.41 168.91 L -168.05 168.91 L -168.05 163.44 L -132.41 163.44 L -@c -B - -@rax %%Note: Object -132.34 673.56 167.98 679.03 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.34 673.56 m -132.34 679.03 L -167.98 679.03 L -167.98 673.56 L -132.34 673.56 L -@c -B - -@rax %%Note: Object -132.34 698.26 167.98 703.73 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.34 698.26 m -132.34 703.73 L -167.98 703.73 L -167.98 698.26 L -132.34 698.26 L -@c -B - -@rax %%Note: Object -132.34 668.09 187.20 676.30 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.34 668.09 m -132.34 676.30 L -187.20 676.30 L -187.20 668.09 L -132.34 668.09 L -@c -S - -@rax %%Note: Object -132.34 676.30 187.20 684.50 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.34 676.30 m -132.34 684.50 L -187.20 684.50 L -187.20 676.30 L -132.34 676.30 L -@c -S - -@rax %%Note: Object -132.34 692.78 187.20 700.99 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.34 692.78 m -132.34 700.99 L -187.20 700.99 L -187.20 692.78 L -132.34 692.78 L -@c -S - -@rax %%Note: Object -132.34 684.58 187.20 692.78 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.34 684.58 m -132.34 692.78 L -187.20 692.78 L -187.20 684.58 L -132.34 684.58 L -@c -S - -@rax %%Note: Object -132.34 681.77 167.98 687.24 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.34 681.77 m -132.34 687.24 L -167.98 687.24 L -167.98 681.77 L -132.34 681.77 L -@c -B - -@rax %%Note: Object -132.41 500.90 168.05 506.38 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 500.90 m -132.41 506.38 L -168.05 506.38 L -168.05 500.90 L -132.41 500.90 L -@c -B - -@rax %%Note: Object -132.41 542.02 168.05 547.49 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 542.02 m -132.41 547.49 L -168.05 547.49 L -168.05 542.02 L -132.41 542.02 L -@c -B - -@rax %%Note: Object -132.41 533.81 168.05 539.28 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 533.81 m -132.41 539.28 L -168.05 539.28 L -168.05 533.81 L -132.41 533.81 L -@c -B - -@rax %%Note: Object -132.41 525.53 168.05 531.07 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 525.53 m -132.41 531.07 L -168.05 531.07 L -168.05 525.53 L -132.41 525.53 L -@c -B - -@rax %%Note: Object -132.41 495.36 187.27 503.64 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 495.36 m -132.41 503.64 L -187.27 503.64 L -187.27 495.36 L -132.41 495.36 L -@c -S - -@rax %%Note: Object -132.41 544.75 187.27 552.96 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 544.75 m -132.41 552.96 L -187.27 552.96 L -187.27 544.75 L -132.41 544.75 L -@c -S - -@rax %%Note: Object -132.41 536.54 187.27 544.75 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 536.54 m -132.41 544.75 L -187.27 544.75 L -187.27 536.54 L -132.41 536.54 L -@c -S - -@rax %%Note: Object -132.41 528.34 187.27 536.54 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 528.34 m -132.41 536.54 L -187.27 536.54 L -187.27 528.34 L -132.41 528.34 L -@c -S - -@rax %%Note: Object -132.41 503.64 187.27 511.85 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 503.64 m -132.41 511.85 L -187.27 511.85 L -187.27 503.64 L -132.41 503.64 L -@c -S - -@rax %%Note: Object -132.41 520.06 187.27 528.34 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 520.06 m -132.41 528.34 L -187.27 528.34 L -187.27 520.06 L -132.41 520.06 L -@c -S - -@rax %%Note: Object -132.41 511.85 187.27 520.06 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 511.85 m -132.41 520.06 L -187.27 520.06 L -187.27 511.85 L -132.41 511.85 L -@c -S - -@rax %%Note: Object -132.41 509.11 168.05 514.58 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 509.11 m -132.41 514.58 L -168.05 514.58 L -168.05 509.11 L -132.41 509.11 L -@c -B - -@rax %%Note: Object -132.41 558.50 168.05 563.98 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 558.50 m -132.41 563.98 L -168.05 563.98 L -168.05 558.50 L -132.41 558.50 L -@c -B - -@rax %%Note: Object -132.41 599.62 168.05 605.09 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 599.62 m -132.41 605.09 L -168.05 605.09 L -168.05 599.62 L -132.41 599.62 L -@c -B - -@rax %%Note: Object -132.41 591.41 168.05 596.88 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 591.41 m -132.41 596.88 L -168.05 596.88 L -168.05 591.41 L -132.41 591.41 L -@c -B - -@rax %%Note: Object -132.41 583.13 168.05 588.67 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 583.13 m -132.41 588.67 L -168.05 588.67 L -168.05 583.13 L -132.41 583.13 L -@c -B - -@rax %%Note: Object -132.41 552.96 187.27 561.24 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 552.96 m -132.41 561.24 L -187.27 561.24 L -187.27 552.96 L -132.41 552.96 L -@c -S - -@rax %%Note: Object -132.41 602.35 187.27 610.56 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 602.35 m -132.41 610.56 L -187.27 610.56 L -187.27 602.35 L -132.41 602.35 L -@c -S - -@rax %%Note: Object -132.41 594.14 187.27 602.35 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 594.14 m -132.41 602.35 L -187.27 602.35 L -187.27 594.14 L -132.41 594.14 L -@c -S - -@rax %%Note: Object -132.41 585.94 187.27 594.14 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 585.94 m -132.41 594.14 L -187.27 594.14 L -187.27 585.94 L -132.41 585.94 L -@c -S - -@rax %%Note: Object -132.41 561.24 187.27 569.45 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 561.24 m -132.41 569.45 L -187.27 569.45 L -187.27 561.24 L -132.41 561.24 L -@c -S - -@rax %%Note: Object -132.41 577.66 187.27 585.94 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 577.66 m -132.41 585.94 L -187.27 585.94 L -187.27 577.66 L -132.41 577.66 L -@c -S - -@rax %%Note: Object -132.41 569.45 187.27 577.66 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 569.45 m -132.41 577.66 L -187.27 577.66 L -187.27 569.45 L -132.41 569.45 L -@c -S - -@rax %%Note: Object -132.41 566.71 168.05 572.18 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 566.71 m -132.41 572.18 L -168.05 572.18 L -168.05 566.71 L -132.41 566.71 L -@c -B - -@rax %%Note: Object -132.41 616.03 168.05 621.50 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 616.03 m -132.41 621.50 L -168.05 621.50 L -168.05 616.03 L -132.41 616.03 L -@c -B - -@rax %%Note: Object -132.41 657.14 168.05 662.62 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 657.14 m -132.41 662.62 L -168.05 662.62 L -168.05 657.14 L -132.41 657.14 L -@c -B - -@rax %%Note: Object -132.41 648.94 168.05 654.41 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 648.94 m -132.41 654.41 L -168.05 654.41 L -168.05 648.94 L -132.41 648.94 L -@c -B - -@rax %%Note: Object -132.41 640.66 168.05 646.20 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 640.66 m -132.41 646.20 L -168.05 646.20 L -168.05 640.66 L -132.41 640.66 L -@c -B - -@rax %%Note: Object -132.41 610.49 187.27 618.77 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 610.49 m -132.41 618.77 L -187.27 618.77 L -187.27 610.49 L -132.41 610.49 L -@c -S - -@rax %%Note: Object -132.41 659.88 187.27 668.09 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 659.88 m -132.41 668.09 L -187.27 668.09 L -187.27 659.88 L -132.41 659.88 L -@c -S - -@rax %%Note: Object -132.41 651.67 187.27 659.88 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 651.67 m -132.41 659.88 L -187.27 659.88 L -187.27 651.67 L -132.41 651.67 L -@c -S - -@rax %%Note: Object -132.41 643.46 187.27 651.67 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 643.46 m -132.41 651.67 L -187.27 651.67 L -187.27 643.46 L -132.41 643.46 L -@c -S - -@rax %%Note: Object -132.41 618.77 187.27 626.98 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 618.77 m -132.41 626.98 L -187.27 626.98 L -187.27 618.77 L -132.41 618.77 L -@c -S - -@rax %%Note: Object -132.41 635.18 187.27 643.46 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 635.18 m -132.41 643.46 L -187.27 643.46 L -187.27 635.18 L -132.41 635.18 L -@c -S - -@rax %%Note: Object -132.41 626.98 187.27 635.18 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 626.98 m -132.41 635.18 L -187.27 635.18 L -187.27 626.98 L -132.41 626.98 L -@c -S - -@rax %%Note: Object -132.41 624.24 168.05 629.71 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 624.24 m -132.41 629.71 L -168.05 629.71 L -168.05 624.24 L -132.41 624.24 L -@c -B - -@rax %%Note: Object -132.41 385.63 168.05 391.10 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 385.63 m -132.41 391.10 L -168.05 391.10 L -168.05 385.63 L -132.41 385.63 L -@c -B - -@rax %%Note: Object -132.41 426.74 168.05 432.22 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 426.74 m -132.41 432.22 L -168.05 432.22 L -168.05 426.74 L -132.41 426.74 L -@c -B - -@rax %%Note: Object -132.41 418.54 168.05 424.01 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 418.54 m -132.41 424.01 L -168.05 424.01 L -168.05 418.54 L -132.41 418.54 L -@c -B - -@rax %%Note: Object -132.41 410.26 168.05 415.80 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 410.26 m -132.41 415.80 L -168.05 415.80 L -168.05 410.26 L -132.41 410.26 L -@c -B - -@rax %%Note: Object -132.41 380.09 187.27 388.37 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 380.09 m -132.41 388.37 L -187.27 388.37 L -187.27 380.09 L -132.41 380.09 L -@c -S - -@rax %%Note: Object -132.41 429.48 187.27 437.69 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 429.48 m -132.41 437.69 L -187.27 437.69 L -187.27 429.48 L -132.41 429.48 L -@c -S - -@rax %%Note: Object -132.41 421.27 187.27 429.48 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 421.27 m -132.41 429.48 L -187.27 429.48 L -187.27 421.27 L -132.41 421.27 L -@c -S - -@rax %%Note: Object -132.41 413.06 187.27 421.27 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 413.06 m -132.41 421.27 L -187.27 421.27 L -187.27 413.06 L -132.41 413.06 L -@c -S - -@rax %%Note: Object -132.41 388.37 187.27 396.58 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 388.37 m -132.41 396.58 L -187.27 396.58 L -187.27 388.37 L -132.41 388.37 L -@c -S - -@rax %%Note: Object -132.41 404.78 187.27 413.06 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 404.78 m -132.41 413.06 L -187.27 413.06 L -187.27 404.78 L -132.41 404.78 L -@c -S - -@rax %%Note: Object -132.41 396.58 187.27 404.78 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 396.58 m -132.41 404.78 L -187.27 404.78 L -187.27 396.58 L -132.41 396.58 L -@c -S - -@rax %%Note: Object -132.41 393.84 168.05 399.31 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 393.84 m -132.41 399.31 L -168.05 399.31 L -168.05 393.84 L -132.41 393.84 L -@c -B - -@rax %%Note: Object -132.41 212.90 168.05 218.38 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 212.90 m -132.41 218.38 L -168.05 218.38 L -168.05 212.90 L -132.41 212.90 L -@c -B - -@rax %%Note: Object -132.41 254.02 168.05 259.49 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 254.02 m -132.41 259.49 L -168.05 259.49 L -168.05 254.02 L -132.41 254.02 L -@c -B - -@rax %%Note: Object -132.41 245.81 168.05 251.28 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 245.81 m -132.41 251.28 L -168.05 251.28 L -168.05 245.81 L -132.41 245.81 L -@c -B - -@rax %%Note: Object -132.41 237.53 168.05 243.07 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 237.53 m -132.41 243.07 L -168.05 243.07 L -168.05 237.53 L -132.41 237.53 L -@c -B - -@rax %%Note: Object -132.41 207.36 187.27 215.64 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 207.36 m -132.41 215.64 L -187.27 215.64 L -187.27 207.36 L -132.41 207.36 L -@c -S - -@rax %%Note: Object -132.41 256.75 187.27 264.96 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 256.75 m -132.41 264.96 L -187.27 264.96 L -187.27 256.75 L -132.41 256.75 L -@c -S - -@rax %%Note: Object -132.41 248.54 187.27 256.75 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 248.54 m -132.41 256.75 L -187.27 256.75 L -187.27 248.54 L -132.41 248.54 L -@c -S - -@rax %%Note: Object -132.41 240.34 187.27 248.54 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 240.34 m -132.41 248.54 L -187.27 248.54 L -187.27 240.34 L -132.41 240.34 L -@c -S - -@rax %%Note: Object -132.41 215.64 187.27 223.85 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 215.64 m -132.41 223.85 L -187.27 223.85 L -187.27 215.64 L -132.41 215.64 L -@c -S - -@rax %%Note: Object -132.41 232.06 187.27 240.34 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 232.06 m -132.41 240.34 L -187.27 240.34 L -187.27 232.06 L -132.41 232.06 L -@c -S - -@rax %%Note: Object -132.41 223.85 187.27 232.06 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 223.85 m -132.41 232.06 L -187.27 232.06 L -187.27 223.85 L -132.41 223.85 L -@c -S - -@rax %%Note: Object -132.41 221.11 168.05 226.58 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 221.11 m -132.41 226.58 L -168.05 226.58 L -168.05 221.11 L -132.41 221.11 L -@c -B - -@rax %%Note: Object -132.41 328.03 168.05 333.50 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 328.03 m -132.41 333.50 L -168.05 333.50 L -168.05 328.03 L -132.41 328.03 L -@c -B - -@rax %%Note: Object -132.41 369.14 168.05 374.62 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 369.14 m -132.41 374.62 L -168.05 374.62 L -168.05 369.14 L -132.41 369.14 L -@c -B - -@rax %%Note: Object -132.41 360.94 168.05 366.41 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 360.94 m -132.41 366.41 L -168.05 366.41 L -168.05 360.94 L -132.41 360.94 L -@c -B - -@rax %%Note: Object -132.41 352.66 168.05 358.20 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 352.66 m -132.41 358.20 L -168.05 358.20 L -168.05 352.66 L -132.41 352.66 L -@c -B - -@rax %%Note: Object -132.41 322.49 187.27 330.77 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 322.49 m -132.41 330.77 L -187.27 330.77 L -187.27 322.49 L -132.41 322.49 L -@c -S - -@rax %%Note: Object -132.41 371.88 187.27 380.09 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 371.88 m -132.41 380.09 L -187.27 380.09 L -187.27 371.88 L -132.41 371.88 L -@c -S - -@rax %%Note: Object -132.41 363.67 187.27 371.88 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 363.67 m -132.41 371.88 L -187.27 371.88 L -187.27 363.67 L -132.41 363.67 L -@c -S - -@rax %%Note: Object -132.41 355.46 187.27 363.67 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 355.46 m -132.41 363.67 L -187.27 363.67 L -187.27 355.46 L -132.41 355.46 L -@c -S - -@rax %%Note: Object -132.41 330.77 187.27 338.98 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 330.77 m -132.41 338.98 L -187.27 338.98 L -187.27 330.77 L -132.41 330.77 L -@c -S - -@rax %%Note: Object -132.41 347.18 187.27 355.46 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 347.18 m -132.41 355.46 L -187.27 355.46 L -187.27 347.18 L -132.41 347.18 L -@c -S - -@rax %%Note: Object -132.41 338.98 187.27 347.18 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 338.98 m -132.41 347.18 L -187.27 347.18 L -187.27 338.98 L -132.41 338.98 L -@c -S - -@rax %%Note: Object -132.41 336.24 168.05 341.71 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.41 336.24 m -132.41 341.71 L -168.05 341.71 L -168.05 336.24 L -132.41 336.24 L -@c -B - -@rax %%Note: Object -132.34 443.23 167.98 448.70 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.34 443.23 m -132.34 448.70 L -167.98 448.70 L -167.98 443.23 L -132.34 443.23 L -@c -B - -@rax %%Note: Object -132.34 484.34 167.98 489.82 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.34 484.34 m -132.34 489.82 L -167.98 489.82 L -167.98 484.34 L -132.34 484.34 L -@c -B - -@rax %%Note: Object -132.34 476.14 167.98 481.61 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.34 476.14 m -132.34 481.61 L -167.98 481.61 L -167.98 476.14 L -132.34 476.14 L -@c -B - -@rax %%Note: Object -132.34 467.86 167.98 473.40 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.34 467.86 m -132.34 473.40 L -167.98 473.40 L -167.98 467.86 L -132.34 467.86 L -@c -B - -@rax %%Note: Object -132.34 437.69 187.20 445.97 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.34 437.69 m -132.34 445.97 L -187.20 445.97 L -187.20 437.69 L -132.34 437.69 L -@c -S - -@rax %%Note: Object -132.34 487.08 187.20 495.29 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.34 487.08 m -132.34 495.29 L -187.20 495.29 L -187.20 487.08 L -132.34 487.08 L -@c -S - -@rax %%Note: Object -132.34 478.87 187.20 487.08 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.34 478.87 m -132.34 487.08 L -187.20 487.08 L -187.20 478.87 L -132.34 478.87 L -@c -S - -@rax %%Note: Object -132.34 470.66 187.20 478.87 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.34 470.66 m -132.34 478.87 L -187.20 478.87 L -187.20 470.66 L -132.34 470.66 L -@c -S - -@rax %%Note: Object -132.34 445.97 187.20 454.18 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.34 445.97 m -132.34 454.18 L -187.20 454.18 L -187.20 445.97 L -132.34 445.97 L -@c -S - -@rax %%Note: Object -132.34 462.38 187.20 470.66 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.34 462.38 m -132.34 470.66 L -187.20 470.66 L -187.20 462.38 L -132.34 462.38 L -@c -S - -@rax %%Note: Object -132.34 454.18 187.20 462.38 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.34 454.18 m -132.34 462.38 L -187.20 462.38 L -187.20 454.18 L -132.34 454.18 L -@c -S - -@rax %%Note: Object -132.34 451.44 167.98 456.91 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -132.34 451.44 m -132.34 456.91 L -167.98 456.91 L -167.98 451.44 L -132.34 451.44 L -@c -B - -@rax 174.17 95.54 177.19 99.94 @E -[0.07199 0.00000 0.00000 0.07199 174.16800 95.61600] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 83.00 z -0 0 (0) @t -T -@rax 174.17 153.22 180.50 157.54 @E -[0.07199 0.00000 0.00000 0.07199 174.16800 153.21599] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 83.00 z -0 0 (12) @t -T -@rax 174.17 210.82 180.50 215.14 @E -[0.07199 0.00000 0.00000 0.07199 174.16800 210.81599] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 83.00 z -0 0 (24) @t -T -@rax 174.17 268.34 180.50 272.74 @E -[0.07199 0.00000 0.00000 0.07199 174.16800 268.41599] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 83.00 z -0 0 (36) @t -T -@rax 174.17 325.94 180.50 330.34 @E -[0.07199 0.00000 0.00000 0.07199 174.16800 326.01599] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 83.00 z -0 0 (48) @t -T -@rax 174.17 383.54 180.50 387.94 @E -[0.07199 0.00000 0.00000 0.07199 174.16800 383.61600] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 83.00 z -0 0 (60) @t -T -@rax 174.17 441.22 180.50 445.54 @E -[0.07199 0.00000 0.00000 0.07199 174.16800 441.21597] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 83.00 z -0 0 (72) @t -T -@rax 174.17 498.74 180.50 503.14 @E -[0.07199 0.00000 0.00000 0.07199 174.16800 498.81598] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 83.00 z -0 0 (84) @t -T -@rax 174.17 556.34 180.50 560.74 @E -[0.07199 0.00000 0.00000 0.07199 174.16800 556.41595] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 83.00 z -0 0 (96) @t -T -@rax 174.17 613.94 183.82 618.34 @E -[0.07199 0.00000 0.00000 0.07199 174.16800 614.01599] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 83.00 z -0 0 (108) @t -T -@rax 174.17 671.54 183.82 675.94 @E -[0.07199 0.00000 0.00000 0.07199 174.16800 671.61597] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 83.00 z -0 0 (120) @t -T -@rax 174.17 695.52 183.82 699.91 @E -[0.07199 0.00000 0.00000 0.07199 174.16800 695.59198] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 83.00 z -0 0 (125) @t -T -@rax 174.17 637.92 183.38 642.31 @E -[0.07199 0.00000 0.00000 0.07199 174.16800 637.99194] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 83.00 z -0 0 (113) @t -T -@rax 174.17 580.32 182.95 584.71 @E -[0.07199 0.00000 0.00000 0.07199 174.16800 580.39197] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 83.00 z -0 0 (101) @t -T -@rax 174.17 522.72 180.50 527.11 @E -[0.07199 0.00000 0.00000 0.07199 174.16800 522.79199] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 83.00 z -0 0 (89) @t -T -@rax 174.17 465.19 180.50 469.44 @E -[0.07199 0.00000 0.00000 0.07199 174.16800 465.19199] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 83.00 z -0 0 (77) @t -T -@rax 174.17 407.52 180.50 411.91 @E -[0.07199 0.00000 0.00000 0.07199 174.16800 407.59198] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 83.00 z -0 0 (65) @t -T -@rax 174.17 349.92 180.50 354.31 @E -[0.07199 0.00000 0.00000 0.07199 174.16800 349.99197] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 83.00 z -0 0 (53) @t -T -@rax 174.17 292.39 179.64 296.71 @E -[0.07199 0.00000 0.00000 0.07199 174.16800 292.39200] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 83.00 z -0 0 (41) @t -T -@rax 174.17 234.72 180.50 239.11 @E -[0.07199 0.00000 0.00000 0.07199 174.16800 234.79199] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 83.00 z -0 0 (29) @t -T -@rax 174.17 177.19 180.50 181.51 @E -[0.07199 0.00000 0.00000 0.07199 174.16800 177.19199] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 83.00 z -0 0 (17) @t -T -@rax 174.17 119.52 177.19 123.84 @E -[0.07199 0.00000 0.00000 0.07199 174.16800 119.59200] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 83.00 z -0 0 (5) @t -T -@rax 194.40 745.06 392.04 755.21 @E -[0.07199 0.00000 0.00000 0.07199 194.39999 745.19995] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 194.00 z -0 0 (MIDI File Format Note Numbers) @t -T -@rax %%Note: Object -288.00 691.27 301.03 705.67 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -295.78 691.27 m -291.67 691.27 288.29 696.38 288.14 700.56 C -288.00 704.30 289.66 705.67 293.40 705.67 C -297.43 705.60 301.03 700.34 301.03 696.31 C -301.03 692.78 299.74 691.27 295.78 691.27 C -@c -293.33 696.10 m -294.34 694.58 296.57 692.64 298.01 692.71 C -300.82 693.00 297.36 698.69 296.35 699.98 c -294.55 702.36 292.54 704.30 290.95 704.09 C -288.14 703.37 292.32 697.46 293.33 696.10 c -@c -B - -@rax %%Note: Object -302.40 655.27 315.43 669.67 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -310.18 655.27 m -306.07 655.27 302.69 660.38 302.54 664.56 C -302.40 668.30 304.06 669.67 307.80 669.67 C -311.83 669.60 315.43 664.34 315.43 660.31 C -315.43 656.78 314.14 655.27 310.18 655.27 C -@c -307.73 660.10 m -308.74 658.58 310.97 656.64 312.41 656.71 C -315.22 657.00 311.76 662.69 310.75 663.98 c -308.95 666.36 306.94 668.30 305.35 668.09 C -302.54 667.37 306.72 661.46 307.73 660.10 c -@c -B - -@rax %%Note: Object -318.24 619.27 331.27 633.67 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -326.02 619.27 m -321.91 619.27 318.53 624.38 318.38 628.56 C -318.24 632.30 319.90 633.67 323.64 633.67 C -327.67 633.60 331.27 628.34 331.27 624.31 C -331.27 620.78 329.98 619.27 326.02 619.27 C -@c -323.57 624.10 m -324.58 622.58 326.81 620.64 328.25 620.71 C -331.06 621.00 327.60 626.69 326.59 627.98 c -324.79 630.36 322.78 632.30 321.19 632.09 C -318.38 631.37 322.56 625.46 323.57 624.10 c -@c -B - -@rax %%Note: Object -331.20 590.47 344.23 604.87 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -338.98 590.47 m -334.87 590.47 331.49 595.58 331.34 599.76 C -331.20 603.50 332.86 604.87 336.60 604.87 C -340.63 604.80 344.23 599.54 344.23 595.51 C -344.23 591.98 342.94 590.47 338.98 590.47 C -@c -336.53 595.30 m -337.54 593.78 339.77 591.84 341.21 591.91 C -344.02 592.20 340.56 597.89 339.55 599.18 c -337.75 601.56 335.74 603.50 334.15 603.29 C -331.34 602.57 335.52 596.66 336.53 595.30 c -@c -B - -@rax %%Note: Object -347.04 554.47 360.07 568.87 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -354.82 554.47 m -350.71 554.47 347.33 559.58 347.18 563.76 C -347.04 567.50 348.70 568.87 352.44 568.87 C -356.47 568.80 360.07 563.54 360.07 559.51 C -360.07 555.98 358.78 554.47 354.82 554.47 C -@c -352.37 559.30 m -353.38 557.78 355.61 555.84 357.05 555.91 C -359.86 556.20 356.40 561.89 355.39 563.18 c -353.59 565.56 351.58 567.50 349.99 567.29 C -347.18 566.57 351.36 560.66 352.37 559.30 c -@c -B - -@rax %%Note: Object -361.44 518.47 374.47 532.87 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -369.22 518.47 m -365.11 518.47 361.73 523.58 361.58 527.76 C -361.44 531.50 363.10 532.87 366.84 532.87 C -370.87 532.80 374.47 527.54 374.47 523.51 C -374.47 519.98 373.18 518.47 369.22 518.47 C -@c -366.77 523.30 m -367.78 521.78 370.01 519.84 371.45 519.91 C -374.26 520.20 370.80 525.89 369.79 527.18 c -367.99 529.56 365.98 531.50 364.39 531.29 C -361.58 530.57 365.76 524.66 366.77 523.30 c -@c -B - -@rax %%Note: Object -375.84 482.47 388.87 496.87 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -383.62 482.47 m -379.51 482.47 376.13 487.58 375.98 491.76 C -375.84 495.50 377.50 496.87 381.24 496.87 C -385.27 496.80 388.87 491.54 388.87 487.51 C -388.87 483.98 387.58 482.47 383.62 482.47 C -@c -381.17 487.30 m -382.18 485.78 384.41 483.84 385.85 483.91 C -388.66 484.20 385.20 489.89 384.19 491.18 c -382.39 493.56 380.38 495.50 378.79 495.29 C -375.98 494.57 380.16 488.66 381.17 487.30 c -@c -B - -@rax %%Note: Object -388.80 446.47 401.83 460.87 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -396.58 446.47 m -392.47 446.47 389.09 451.58 388.94 455.76 C -388.80 459.50 390.46 460.87 394.20 460.87 C -398.23 460.80 401.83 455.54 401.83 451.51 C -401.83 447.98 400.54 446.47 396.58 446.47 C -@c -394.13 451.30 m -395.14 449.78 397.37 447.84 398.81 447.91 C -401.62 448.20 398.16 453.89 397.15 455.18 c -395.35 457.56 393.34 459.50 391.75 459.29 C -388.94 458.57 393.12 452.66 394.13 451.30 c -@c -B - -@rax %%Note: Object -419.04 410.47 432.07 424.87 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -426.82 410.47 m -422.71 410.47 419.33 415.58 419.18 419.76 C -419.04 423.50 420.70 424.87 424.44 424.87 C -428.47 424.80 432.07 419.54 432.07 415.51 C -432.07 411.98 430.78 410.47 426.82 410.47 C -@c -424.37 415.30 m -425.38 413.78 427.61 411.84 429.05 411.91 C -431.86 412.20 428.40 417.89 427.39 419.18 c -425.59 421.56 423.58 423.50 421.99 423.29 C -419.18 422.57 423.36 416.66 424.37 415.30 c -@c -B - -@rax %%Note: Object -433.44 374.47 446.47 388.87 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -441.22 374.47 m -437.11 374.47 433.73 379.58 433.58 383.76 C -433.44 387.50 435.10 388.87 438.84 388.87 C -442.87 388.80 446.47 383.54 446.47 379.51 C -446.47 375.98 445.18 374.47 441.22 374.47 C -@c -438.77 379.30 m -439.78 377.78 442.01 375.84 443.45 375.91 C -446.26 376.20 442.80 381.89 441.79 383.18 c -439.99 385.56 437.98 387.50 436.39 387.29 C -433.58 386.57 437.76 380.66 438.77 379.30 c -@c -B - -@rax %%Note: Object -447.84 338.47 460.87 352.87 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -455.62 338.47 m -451.51 338.47 448.13 343.58 447.98 347.76 C -447.84 351.50 449.50 352.87 453.24 352.87 C -457.27 352.80 460.87 347.54 460.87 343.51 C -460.87 339.98 459.58 338.47 455.62 338.47 C -@c -453.17 343.30 m -454.18 341.78 456.41 339.84 457.85 339.91 C -460.66 340.20 457.20 345.89 456.19 347.18 c -454.39 349.56 452.38 351.50 450.79 351.29 C -447.98 350.57 452.16 344.66 453.17 343.30 c -@c -B - -@rax %%Note: Object -462.24 302.47 475.27 316.87 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -470.02 302.47 m -465.91 302.47 462.53 307.58 462.38 311.76 C -462.24 315.50 463.90 316.87 467.64 316.87 C -471.67 316.80 475.27 311.54 475.27 307.51 C -475.27 303.98 473.98 302.47 470.02 302.47 C -@c -467.57 307.30 m -468.58 305.78 470.81 303.84 472.25 303.91 C -475.06 304.20 471.60 309.89 470.59 311.18 c -468.79 313.56 466.78 315.50 465.19 315.29 C -462.38 314.57 466.56 308.66 467.57 307.30 c -@c -B - -@rax %%Note: Object -476.64 266.47 489.67 280.87 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -484.42 266.47 m -480.31 266.47 476.93 271.58 476.78 275.76 C -476.64 279.50 478.30 280.87 482.04 280.87 C -486.07 280.80 489.67 275.54 489.67 271.51 C -489.67 267.98 488.38 266.47 484.42 266.47 C -@c -481.97 271.30 m -482.98 269.78 485.21 267.84 486.65 267.91 C -489.46 268.20 486.00 273.89 484.99 275.18 c -483.19 277.56 481.18 279.50 479.59 279.29 C -476.78 278.57 480.96 272.66 481.97 271.30 c -@c -B - -@rax %%Note: Object -489.60 230.47 502.63 244.87 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -497.38 230.47 m -493.27 230.47 489.89 235.58 489.74 239.76 C -489.60 243.50 491.26 244.87 495.00 244.87 C -499.03 244.80 502.63 239.54 502.63 235.51 C -502.63 231.98 501.34 230.47 497.38 230.47 C -@c -494.93 235.30 m -495.94 233.78 498.17 231.84 499.61 231.91 C -502.42 232.20 498.96 237.89 497.95 239.18 c -496.15 241.56 494.14 243.50 492.55 243.29 C -489.74 242.57 493.92 236.66 494.93 235.30 c -@c -B - -@rax %%Note: Object -512.64 151.20 525.67 165.60 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -520.42 151.20 m -516.31 151.20 512.93 156.31 512.78 160.49 C -512.64 164.23 514.30 165.60 518.04 165.60 C -522.07 165.53 525.67 160.27 525.67 156.24 C -525.67 152.71 524.38 151.20 520.42 151.20 C -@c -517.97 156.02 m -518.98 154.51 521.21 152.57 522.65 152.64 C -525.46 152.93 522.00 158.62 520.99 159.91 c -519.19 162.29 517.18 164.23 515.59 164.02 C -512.78 163.30 516.96 157.39 517.97 156.02 c -@c -B - -@rax %%Note: Object -330.91 72.00 331.20 720.00 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -331.06 72.00 m -331.06 720.00 L -S - -@rax %%Note: Object -345.31 72.00 345.60 720.00 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -345.46 72.00 m -345.46 720.00 L -S - -@rax %%Note: Object -359.71 72.00 360.00 720.00 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -359.86 720.00 m -359.86 72.00 L -S - -@rax %%Note: Object -374.11 72.00 374.40 720.00 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -374.26 72.00 m -374.26 720.00 L -S - -@rax %%Note: Object -388.51 72.00 388.80 720.00 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -388.66 720.00 m -388.66 72.00 L -S - -@rax %%Note: Object -431.71 72.00 432.00 720.00 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -431.86 72.00 m -431.86 720.00 L -S - -@rax %%Note: Object -446.11 72.00 446.40 720.00 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -446.26 720.00 m -446.26 72.00 L -S - -@rax %%Note: Object -460.51 72.00 460.80 720.00 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -460.66 72.00 m -460.66 720.00 L -S - -@rax %%Note: Object -474.91 72.00 475.20 720.00 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -475.06 720.00 m -475.06 72.00 L -S - -@rax %%Note: Object -489.31 72.00 489.60 720.00 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -489.46 72.00 m -489.46 720.00 L -S - -@rax %%Note: Object -504.00 194.47 517.03 208.87 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -511.78 194.47 m -507.67 194.47 504.29 199.58 504.14 203.76 C -504.00 207.50 505.66 208.87 509.40 208.87 C -513.43 208.80 517.03 203.54 517.03 199.51 C -517.03 195.98 515.74 194.47 511.78 194.47 C -@c -509.33 199.30 m -510.34 197.78 512.57 195.84 514.01 195.91 C -516.82 196.20 513.36 201.89 512.35 203.18 c -510.55 205.56 508.54 207.50 506.95 207.29 C -504.14 206.57 508.32 200.66 509.33 199.30 c -@c -B - -@rax %%Note: Object -518.26 144.00 518.54 172.80 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -518.40 144.00 m -518.40 172.80 L -S - -@rax %%Note: Object -503.86 144.00 504.14 172.80 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -504.00 144.00 m -504.00 172.80 L -S - -@rax %%Note: Object -302.26 684.00 302.54 712.80 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -302.40 684.00 m -302.40 712.80 L -S - -@rax %%Note: Object -316.66 648.00 316.94 676.80 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -316.80 648.00 m -316.80 676.80 L -S - -@rax %%Note: Object -316.66 684.00 316.94 712.80 @E -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -316.80 684.00 m -316.80 712.80 L -S - -@rax %%Note: Object -331.20 71.93 395.06 101.38 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -366.12 87.55 m -366.62 85.82 368.57 83.88 370.80 83.88 c -371.95 83.88 374.11 84.53 374.98 86.54 c -375.26 87.34 376.13 87.05 375.19 85.39 c -373.54 82.01 369.22 80.42 365.26 83.09 c -364.10 83.66 362.66 85.32 362.09 86.76 C -356.62 85.68 L -358.06 84.02 359.42 82.58 361.51 80.86 c -365.47 77.47 371.66 75.89 375.98 80.14 c -378.86 83.09 379.08 87.12 378.22 90.00 C -366.12 87.55 L -@c -365.98 88.70 m -377.86 91.08 L -376.78 93.82 374.11 94.90 371.59 94.68 c -368.42 94.32 365.98 92.09 365.98 88.70 C -@c -349.92 85.54 m -348.55 87.77 342.36 91.80 338.69 90.94 c -336.46 90.65 336.46 88.20 338.69 86.83 c -341.57 85.10 346.54 84.10 349.92 85.54 C -@c -350.86 84.53 m -342.58 82.22 334.80 83.88 332.28 87.19 c -331.20 88.63 331.34 88.92 332.42 89.78 c -339.34 94.68 349.99 92.95 355.68 86.69 C -361.80 87.91 L -360.07 97.34 375.19 101.38 378.94 91.37 C -384.48 92.23 389.66 94.97 392.83 90.65 c -395.06 87.55 394.42 83.52 392.40 81.43 c -391.03 79.99 388.51 79.13 386.06 80.86 c -382.75 83.45 385.49 87.70 389.16 86.98 c -391.25 86.54 391.75 84.53 391.61 83.45 C -394.42 85.39 392.62 90.43 389.81 91.30 c -386.64 92.45 383.26 91.01 379.44 90.14 C -381.89 79.92 370.73 71.93 361.08 76.32 c -357.55 77.98 354.02 81.29 350.86 84.53 C -@c -B - -@rax %%Note: Object -439.13 72.00 482.40 100.80 @E - 0 O 0 @g -1.00 1.00 1.00 0.21 k -0 J 0 j [] 0 d 0 R 0 @G -1.00 1.00 1.00 0.21 K -0 0.22 0.22 0.00 @w -481.25 72.00 m -478.51 75.24 476.28 77.98 473.62 80.42 c -471.02 82.58 468.29 84.53 465.12 85.82 c -461.81 87.34 457.13 88.70 452.81 88.78 c -449.64 88.78 446.98 88.49 444.96 87.41 c -443.09 86.33 441.58 84.67 441.58 82.44 c -441.58 79.99 442.66 76.75 446.33 75.60 c -447.62 75.24 448.13 76.10 448.13 76.61 c -448.27 77.04 447.70 77.83 447.70 78.70 c -447.70 79.70 448.27 80.57 448.92 81.29 c -449.71 81.86 450.94 82.30 451.94 82.30 c -454.54 82.30 456.77 80.42 456.77 77.98 c -456.77 76.61 456.19 75.53 455.26 74.66 c -454.32 73.73 452.74 73.01 450.79 73.01 c -447.84 73.01 444.74 74.45 442.87 76.39 c -441.86 77.40 441.29 78.70 440.71 79.85 c -439.13 84.24 440.06 87.84 443.38 90.86 c -445.61 93.02 448.78 94.54 453.46 94.54 c -457.92 94.54 463.32 92.81 468.50 89.21 c -470.74 87.62 472.82 85.46 474.84 82.87 c -477.50 79.78 479.88 76.10 482.40 72.14 C -481.25 72.00 L -@c -446.90 96.26 m -446.04 96.26 445.25 96.48 444.74 96.98 c -444.31 97.34 444.02 97.85 444.02 98.57 c -444.02 99.14 444.31 99.72 444.89 100.01 c -445.25 100.44 446.04 100.80 446.98 100.80 c -447.91 100.80 448.56 100.44 449.14 99.94 c -449.64 99.65 449.86 99.07 449.86 98.42 c -449.86 97.92 449.50 97.34 449.14 96.98 c -448.56 96.55 447.84 96.26 446.90 96.26 c -@c -458.57 96.26 m -457.56 96.26 456.98 96.55 456.41 96.98 c -455.90 97.34 455.69 97.85 455.69 98.57 c -455.69 99.14 455.98 99.79 456.55 100.15 c -457.06 100.44 457.70 100.80 458.57 100.80 c -459.50 100.80 460.37 100.44 460.80 99.94 c -461.30 99.65 461.52 99.07 461.52 98.57 c -461.52 97.92 461.30 97.34 460.80 96.98 c -460.22 96.55 459.50 96.26 458.57 96.26 c -@c -B - -@rax 513.36 129.60 522.07 142.42 @E -[0.00001 0.07199 -0.07199 0.00001 522.00000 129.59999] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 167.00 z -0 0 (36) @t -T -@rax 506.16 180.00 514.87 192.82 @E -[0.00001 0.07199 -0.07199 0.00001 514.79999 179.99998] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 167.00 z -0 0 (38) @t -T -@rax 491.76 216.00 500.40 227.09 @E -[0.00001 0.07199 -0.07199 0.00001 500.39996 215.99998] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 167.00 z -0 0 (41) @t -T -@rax 477.43 252.00 486.07 264.82 @E -[0.00001 0.07199 -0.07199 0.00001 485.99997 251.99998] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 167.00 z -0 0 (45) @t -T -@rax 462.96 288.00 471.67 300.82 @E -[0.00001 0.07199 -0.07199 0.00001 471.59998 288.00000] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 167.00 z -0 0 (48) @t -T -@rax 448.56 324.00 457.27 336.74 @E -[0.00001 0.07199 -0.07199 0.00001 457.19998 324.00000] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 167.00 z -0 0 (52) @t -T -@rax 434.23 360.00 442.87 372.82 @E -[0.00001 0.07199 -0.07199 0.00001 442.79999 359.99997] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 167.00 z -0 0 (55) @t -T -@rax 419.76 396.00 428.47 408.82 @E -[0.00001 0.07199 -0.07199 0.00001 428.39999 395.99997] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 167.00 z -0 0 (59) @t -T -@rax 390.96 432.00 399.67 444.74 @E -[0.00001 0.07199 -0.07199 0.00001 399.59998 431.99997] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 167.00 z -0 0 (62) @t -T -@rax 376.56 468.00 385.27 480.82 @E -[0.00001 0.07199 -0.07199 0.00001 385.19998 467.99997] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 167.00 z -0 0 (65) @t -T -@rax 362.16 504.00 370.87 516.82 @E -[0.00001 0.07199 -0.07199 0.00001 370.79999 503.99997] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 167.00 z -0 0 (69) @t -T -@rax 347.76 540.00 356.40 552.74 @E -[0.00001 0.07199 -0.07199 0.00001 356.39999 540.00000] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 167.00 z -0 0 (72) @t -T -@rax 333.36 576.00 342.07 588.82 @E -[0.00001 0.07199 -0.07199 0.00001 342.00000 576.00000] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 167.00 z -0 0 (76) @t -T -@rax 318.96 604.80 327.67 617.62 @E -[0.00001 0.07199 -0.07199 0.00001 327.59998 604.79999] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 167.00 z -0 0 (79) @t -T -@rax 304.56 640.80 313.27 653.62 @E -[0.00001 0.07199 -0.07199 0.00001 313.19998 640.79999] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 167.00 z -0 0 (83) @t -T -@rax 290.16 676.80 298.87 689.62 @E -[0.00001 0.07199 -0.07199 0.00001 298.79999 676.79999] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 167.00 z -0 0 (86) @t -T -@rax 187.20 381.53 226.15 388.87 @E -[0.07199 0.00000 0.00000 0.07199 187.20000 381.59998] @tm - 0 O 0 @g -1.00 1.00 1.00 0.21 k -e -/_R1-Helvetica 139.00 z -0 0 (Middle C) @t -T -@rs @rs -/$ctm matrix currentmatrix def -%EndTile -%EndColorLayer -@rs -@rs -%EndPage -%%Trailer -end -%%DocumentProcessColors: Cyan Magenta Yellow Black -%%DocumentFonts: Helvetica -%%DocumentSuppliedResources: procset wCorel4Dict -EJ RS -%%PageTrailer -2397 3162 0 0 CB -%%Trailer -SVDoc restore -end -%%DocumentSuppliedResources: procset Win35Dict 3 1 - -%%DocumentNeededResources: -%%EOF - diff --git a/16/PCGPE10/MODEX.TXT b/16/PCGPE10/MODEX.TXT deleted file mode 100644 index 009aaf23..00000000 --- a/16/PCGPE10/MODEX.TXT +++ /dev/null @@ -1,720 +0,0 @@ - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ INTRODUCTION TO MODE X ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - By Robert Schmidt - - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ XINTRO18.TXT ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Title: INTRODUCTION TO MODE X - -Version: 1.8 - -Author: Robert Schmidt - -Copyright: (C) 1993 of Ztiff Zox Softwear - refer to Status below. - -Last revision: 25-Nov-93 (Modified for the PCGPE 17-Apr-94) - -Figures: 1. M13ORG - memory organization in mode 13h - 2. MXORG - memory organization in unchained modes - (Both files are appended to the end of this document) - - The figures are available as 7-bit ASCII text (ASC) files. - -Status: This article, its associated figures and source listings - named above, are all donated to the public domain. - Do with it whatever you like, but give credit where - credit is due. - - The standard disclaimer applies. - -Index: 0. ABSTRACT - 1. INTRODUCTION TO THE VGA AND ITS 256-COLOR MODE - 2. GETTING MORE PAGES AND PUTTING YOUR FIRST PIXEL - 3. THE ROAD FROM HERE - 4. BOOKS ON THE SUBJECT - 5. BYE - FOR NOW - - -0. ABSTRACT - -This text gives a fairly basic, yet technical, explanation to what, why -and how Mode X is. It first tries to explain the layout of the VGA -memory and the shortcomings of the standard 320x200 256-color mode, -then gives instructions on how one can progress from mode 13h to a -multipage, planar 320x200 256-color mode, and from there to the -quasi-standard 320x240 mode, known as Mode X. - -A little experience in programming the standard VGA mode 13h -(320x200 in 256 colors) is assumed. Likewise a good understanding of -hexadecimal notation and the concepts of segments and I/O ports is -assumed. Keep a VGA reference handy, which at least should have -definitions of the VGA registers at bit level. - -Throughout the article, a simple graphics library for unchained (planar) -256-color modes is developed. The library supports the 320x200 and -320x240 modes, active and visible pages, and writing and reading -individual pixels. - - -1. INTRODUCTION TO THE VGA AND ITS 256-COLOR MODE - -Since its first appearance on the motherboards of the IBM PS/2 50, 60 -and 80 models in 1987, the Video Graphics Array has been the de facto -standard piece of graphics hardware for IBM and compatible personal -computers. The abbreviation, VGA, was to most people synonymous with -acceptable resolution (640x480 pixels), and a stunning rainbow of colors -(256 from a palette of 262,144), at least compared to the rather gory -CGA and EGA cards. - -Sadly, to use 256 colors, the VGA BIOS limited the users to 320x200 -pixels, i.e. the well-known mode 13h. This mode has one good and one -bad asset. The good one is that each one of the 64,000 pixels is easily -addressable in the 64 Kb video memory segment at 0A000h. Simply calculate -the offset using this formula: - -offset = (y * 320) + x; - -Set the byte at this address (0A000h:offset) to the color you want, and -the pixel is there. Reading a pixel is just as simple: just read the -corresponding byte. This was heaven, compared to the havoc of planes and -masking registers needed in 16-color modes. Suddenly, the distance from a -graphics algorithm on paper to an implemented graphics routine in assembly -was cut down to a fraction. The results were impressively fast, too! - -The bad asset is that mode 13h is also limited to only one page, i.e. -the VGA can hold only one screenful at any one time (plus 1536 pixels, or -about four lines). Most 16-color modes let the VGA hold more than one page, -and this enables you to show one of the pages to the user, while drawing on -another page in the meantime. Page flipping is an important concept in making -flicker free animations. Nice looking and smooth scrolling is also almost -impossible in mode 13h using plain VGA hardware. - -Now, the alert reader might say: "Hold on a minute! If mode 13h enables -only one page, this means that there is memory for only one page. But I -know for a fact that all VGAs have at least 256 Kb RAM, and one 320x200 -256-color page should consume only 320*200=64000 bytes, which is less -than 64 Kb. A standard VGA should room a little more than four 320x200 -pages!" Quite correct, and to see how the BIOS puts this limitation on -mode 13h, I'll elaborate a little on the memory organization of the VGA. - -The memory is separated into four bit planes. The reason for this stems -from the EGA, where graphics modes were 16-color. Using bit planes, the -designers chose to let each pixel on screen be addressable by a single -bit in a single byte in the video segment. Assuming the palette has -not been modified from the default, each plane represent one of the EGA -primary colors: red, green, blue and intensity. When modifying the bit -representing a pixel, the Write Plane Enable register is set to the -wanted color. Reading is more complex and slower, since you can -only read from a single plane at a time, by setting the Read Plane -Select register. Now, since each address in the video segment can -access 8 pixels, and there are 64 Kb addresses, 8 * 65,536 = 524,288 -16-color pixels can be accessed. In a 320x200 16-color mode, this makes -for about 8 (524,288/(320*200)) pages, in 640x480 you get nearly 2 -(524,288/(640*480)) pages. - -In a 256-color mode, the picture changes subtly. The designers decided -to fix the number of bit planes to 4, so extending the logic above to 8 -planes and 256 colors does not work. Instead, one of their goals was to -make the 256-color mode as easily accessible as possible. Comparing the -8 pixels/address in 16-color modes to the 1-to-1 correspondence of -pixels and addresses of mode 13h, one can say that they have -succeeded, but at a certain cost. For reasons I am not aware of, the -designers came up with the following effective, but memory-wasting -scheme: - -The address space of mode 13h is divided evenly across the four bit -planes. When an 8-bit color value is written to a 16-bit address in the -VGA segment, a bit plane is automatically selected by the 2 least -significant bits of the address. Then all 8 bits of the data is written -to the byte at the 16-bit address in the selected bitplane (have a look at -figure 1). Reading works exactly the same way. Since the bit planes are so -closely tied to the address, only every fourth byte in the video memory is -accessible, and 192 Kb of a 256 Kb VGA go to waste. Eliminating the -need to bother about planes sure is convenient and beneficial, but to -most people the loss of 3/4 of the total VGA memory sounds just hilarious. - -To accomodate this new method of accessing video memory, the VGA -designers introduced a new configuration bit called Chain-4, which -resides as bit number 3 in index 4 of the Sequencer. In 16-color modes, -the default state for this bit is off (zero), and the VGA operates as -described earlier. In the VGA's standard 256-color mode, mode 13h, this -bit is turned on (set to one), and this turns the tieing of bit -planes and memory address on. - -In this state, the bit planes are said to be chained together, thus mode -13h is often called a _chained mode_. - -Note that Chain-4 in itself is not enough to set a 256-color mode - -there are other registers which deals with the other subtle changes in -nature from 16 to 256 colors. But, as we now will base our work with -mode X on mode 13h, which already is 256-color, we won't bother about -these for now. - - - -2. GETTING MORE PAGES AND PUTTING YOUR FIRST PIXEL - -The observant reader might at this time suggest that clearing the -Chain-4 bit after setting mode 13h will give us access to all 256 Kb of -video memory, as the two least significant bits of the byte address -won't be `wasted' on selecting a bit plane. This is correct. You might -also start feeling a little uneasy, because something tells you that -you'll instantly loose the simple addressing scheme of mode 13h. Sadly, -that is also correct. - -At the moment Chain-4 is cleared, each byte offset addresses *four* -sequential pixels, corresponding to the four planes addressed in 16-color -modes. Every fourth pixel belong in the same plane. Before writing to a byte -offset in the video segment, you should make sure that the 4-bit mask in the -Write Plane Enable register is set correctly, according to which of the four -addressable pixels you want to modify. In essence, it works like a 16-color -mode with a twist. See figure 2. - -So, is this mode X? Not quite. We need to elaborate to the VGA how to -fetch data for refreshing the monitor image. Explaining the logic -behind this is beyond the scope of this getting-you-started text, and it -wouldn't be very interesting anyway. Also, mode 13h has only 200 lines, -while I promised 240 lines. I'll fix that later below. Here is the minimum -snippet of code to initiate the 4 page variant of mode 13h (320x200), written -in plain C, using some DOS specific features (see header for a note about the -sources included): - -----8<-------cut begin------ - -/* width and height should specify the mode dimensions. widthBytes - specify the width of a line in addressable bytes. */ - -int width, height, widthBytes; - -/* actStart specifies the start of the page being accessed by - drawing operations. visStart specifies the contents of the Screen - Start register, i.e. the start of the visible page */ - -unsigned actStart, visStart; - -/* - * set320x200x256_X() - * sets mode 13h, then turns it into an unchained (planar), 4-page - * 320x200x256 mode. - */ - -set320x200x256_X() - { - - union REGS r; - - /* Set VGA BIOS mode 13h: */ - - r.x.ax = 0x0013; - int86(0x10, &r, &r); - - /* Turn off the Chain-4 bit (bit 3 at index 4, port 0x3c4): */ - - outport(SEQU_ADDR, 0x0604); - - /* Turn off word mode, by setting the Mode Control register - of the CRT Controller (index 0x17, port 0x3d4): */ - - outport(CRTC_ADDR, 0xE317); - - /* Turn off doubleword mode, by setting the Underline Location - register (index 0x14, port 0x3d4): */ - - outport(CRTC_ADDR, 0x0014); - - /* Clear entire video memory, by selecting all four planes, then - writing 0 to the entire segment. */ - - outport(SEQU_ADDR, 0x0F02); - memset(vga+1, 0, 0xffff); /* stupid size_t exactly 1 too small */ - vga[0] = 0; - - /* Update the global variables to reflect the dimensions of this - mode. This is needed by most future drawing operations. */ - - width = 320; - height = 200; - - /* Each byte addresses four pixels, so the width of a scan line - in *bytes* is one fourth of the number of pixels on a line. */ - - widthBytes = width / 4; - - /* By default we want screen refreshing and drawing operations - to be based at offset 0 in the video segment. */ - - actStart = visStart = 0; - - } - -----8<-------cut end------ - -As you can see, I've already provided some of the mechanics needed to -support multiple pages, by providing the actStart and visStart variables. -Selecting pages can be done in one of two contexts: - - 1) selecting the visible page, i.e. which page is visible on - screen, and - - 2) selecting the active page, i.e. which page is accessed by - drawing operations - -Selecting the active page is just a matter of offsetting our graphics -operations by the address of the start of the page, as demonstrated in -the put pixel routine below. Selecting the visual page must be passed -in to the VGA, by setting the Screen Start register. Sadly enough, the -resolution of this register is limited to one addressable byte, which -means four pixels in unchained 256-color modes. Some further trickery is -needed for 1-pixel smooth, horizontal scrolling, but I'll make that a subject -for later. The setXXXStart() functions provided here accept byte -offsets as parameters, so they'll work in any mode. If widthBytes and -height are set correctly, so will the setXXXPage() functions. - -----8<-------cut begin------ - -/* - * setActiveStart() tells our graphics operations which address in video - * memory should be considered the top left corner. - */ - -setActiveStart(unsigned offset) - { - actStart = offset; - } - -/* - * setVisibleStart() tells the VGA from which byte to fetch the first - * pixel when starting refresh at the top of the screen. This version - * won't look very well in time critical situations (games for - * instance) as the register outputs are not synchronized with the - * screen refresh. This refresh might start when the high byte is - * set, but before the low byte is set, which produces a bad flicker. - * I won't bother with this now. - */ - -setVisibleStart(unsigned offset) - { - visStart = offset; - outport(CRTC_ADDR, 0x0C); /* set high byte */ - outport(CRTC_ADDR+1, visStart >> 8); - outport(CRTC_ADDR, 0x0D); /* set low byte */ - outport(CRTC_ADDR+1, visStart & 0xff); - } - -/* - * setXXXPage() sets the specified page by multiplying the page number - * with the size of one page at the current resolution, then handing the - * resulting offset value over to the corresponding setXXXStart() - * function. The first page number is 0. - */ - -setActivePage(int page) - { - setActiveStart(page * widthBytes * height); - } - -setVisiblePage(int page) - { - setVisibleStart(page * widthBytes * height); - } - -----8<-------cut end------ - -Due to the use of bit planes, the graphics routines tend to get more -complex than in mode 13h, and your first versions will generally tend to -be a little slower than mode 13h algorithms. Here's a put pixel routine -for any unchained 256-color mode (it assumes that the 'width' variable -from the above code is set correctly). Optimizing is left as an exercise -to you, the reader. This will be the only drawing operation I'll cover -in this article, but all general primitives like lines and circles can be -based on this routine. (You'll probably not want to do that though, due -to the inefficiency.) - -----8<-------cut begin------ - -putPixel_X(int x, int y, char color) - { - - /* Each address accesses four neighboring pixels, so set - Write Plane Enable according to which pixel we want - to modify. The plane is determined by the two least - significant bits of the x-coordinate: */ - - outportb(0x3c4, 0x02); - outportb(0x3c5, 0x01 << (x & 3)); - - /* The offset of the pixel into the video segment is - offset = (width * y + x) / 4, and write the given - color to the plane we selected above. Heed the active - page start selection. */ - - vga[(unsigned)(widthBytes * y) + (x / 4) + actStart] = color; - - } - -char getPixel_X(int x, int y) - { - - /* Select the plane from which we must read the pixel color: */ - - outport(GRAC_ADDR, 0x04); - outport(GRAC_ADDR+1, x & 3); - - return vga[(unsigned)(widthBytes * y) + (x / 4) + actStart]; - - } - -----8<-------cut end------ - - -However, by now you should be aware of that the Write Plane Enable -register isn't limited to selecting just one bit plane, like the -Read Plane Select register is. You can enable any combination of all -four to be written. This ability to access 4 pixels with one -instruction helps quadrupling the speed in certain respects, especially when -drawing horizontal lines and filling polygons of a constant color. Also, most -block algorithms can be optimized in various ways so that they need only -a constant number of OUTs (typically four) to the Write Plane Enable -register. OUT is a relatively slow instruction. - -The gained ability to access the full 256 Kb of memory on a standard -VGA enables you to do paging and all the goodies following from that: -smooth scrolling over large maps, page flipping for flicker free -animation... and I'll leave something for your own imagination. - -In short, the stuff gained from unchaining mode 13h more than -upweighs the additional complexity of using a planar mode. - -Now, the resolution of the mode is of little interest in this -context. Nearly any 256-color resolution from (about) 80x8 to 400x300 -is available for most VGAs. I'll dwell particularly by 320x240, as this -is the mode that Michael Abrash introduced as 'Mode X' in his DDJ -articles. It is also the resolution that most people refer to when -using that phrase. - -The good thing about the 320x240 mode is that the aspect ratio is -1:1, which means that each pixel is 'perfectly' square, i.e. not -rectangular like in 320x200. An ellipse drawn with the same number of -pixels along both main axes will look like a perfect circle in 320x240, -but like a subtly tall ellipse in 320x200. - -Here's a function which sets the 320x240 mode. You'll notice that -it depends on the first piece of code above: - -----8<-------cut begin------ - -set320x240x256_X() - { - - /* Set the unchained version of mode 13h: */ - - set320x200x256_X(); - - /* Modify the vertical sync polarity bits in the Misc. Output - Register to achieve square aspect ratio: */ - - outportb(0x3C2, 0xE3); - - /* Modify the vertical timing registers to reflect the increased - vertical resolution, and to center the image as good as - possible: */ - - outport(0x3D4, 0x2C11); /* turn off write protect */ - outport(0x3D4, 0x0D06); /* vertical total */ - outport(0x3D4, 0x3E07); /* overflow register */ - outport(0x3D4, 0xEA10); /* vertical retrace start */ - outport(0x3D4, 0xAC11); /* vertical retrace end AND wr.prot */ - outport(0x3D4, 0xDF12); /* vertical display enable end */ - outport(0x3D4, 0xE715); /* start vertical blanking */ - outport(0x3D4, 0x0616); /* end vertical blanking */ - - /* Update mode info, so future operations are aware of the - resolution: */ - - height = 240; - - } - -----8<-------cut end------ - - -As you've figured out, this mode will be completely compatible with the -utility functions presented earlier, thanks to the global variable -'height'. Boy, am I foreseeing or what! - -Other resolutions are achieved through giving other values to the sync -timing registers of the VGA, but this is quite a large and complex -subject, so I'll postpone this to later, if ever. - -Anyway, I hope I've helped getting you started using mode X. As far as -I know, the two modes I've used above should work on *any* VGA and Super -VGA available, so this is pretty stable stuff. Let me know of any -trouble, and - - good luck! - - - -3. THE ROAD FROM HERE - -I'm providing information on various libraries and archives which relate -to what this article deals with. If you want me to add anything to this -list (for future articles), let me know, although I can't promise anything. -I am assuming you have ftp access. - - -wuarchive.wustl.edu:/pub/MSDOS_UPLOADS/programming/xlib06.zip - -This is the current de facto C/assembler library for programming -unchained modes (do not confuse with a X Windows library). All sources -are included, and the library is totally free. It has functions for -pixels, lines, circles, bezier curves, mouse handling, sprites (bitmaps), -compiled bitmaps, and supports a number of resolutions. The version number -('06') is current as of November 1993. - - -graphprg.zip - -Michael Abrash' articles in Doctor Dobbs Journal is always mentioned -with awe. In this 350 Kb archive, most of his interesting stuff has -been gathered. Read about Mode X development and techniques from month -to month. Included is also all the individual source code snippets from -each article, and also the full XSHARP library providing linedrawing, -polygons, bitmaps, solid 3D projection and speedy rendering, and even an -implementation of 2D texture mapping (can be used for quasi-3D texture -mapping), plus an article on assembly optimization on the i86 processor -family. Definitely recommended. - - -oak.oakland.edu:/pub/msdos/vga/vgadoc2.zip - -This is a bare bones VGA register reference. It also contains register -references for the CGA, EGA and Hercules cards, in addition to dozens of -SuperVGAs. Check out the BOOKS section for some decent VGA references -though - you don't want to start tweaking without a real one. - - -wuarchive.wustl.edu:/pub/MSDOS_UPLOADS/programming/tweak15b.zip - -TWEAK might be of interest to the more adventurous reader. TWEAK lets you -play around with the registers of the VGA in an interactive manner. -Various testing screens for viewing your newmade modes are applied at -the press of a key. Version 1.5 adds a test screen which autodetects your -graphics mode and displays various information about resolutions etc. -Keep a VGA reference handy. Don't try it if this is the first time you've -heard of 'registers' or 'mode X' or 'tweaking'. I was planning a version -based on the Turbo Vision interface, but time has been short. Maybe later! - - - - -4. BOOKS ON THE SUBJECT - -Extremely little has been published in written form about using -'Mode X'-style modes. Below are some books which cover VGA programming -at varying degrees of technical level, but the only one to mention -unchained modes and Mode X, is Michael Abrash'. I'd get one of the VGA -references first, though. - - o George Sutty & Steve Blair : "Advanced Pogrammer's Guide to the - EGA/VGA" from Brady. A bit old perhaps, but covers all *standard* - EGA/VGA registers, and discusses most BIOS functions and other - operations. Contains disk with C/Pascal/assembler source code. - There's a sequel out for SuperVGAs, which I haven't seen. - - o Michael Abrash : "Power Graphics Programming" from QUE/Programmer's - Journal. Collections of (old) articles from Programmer's Journal on - EGA/VGA, read modes and write modes, animation, tweaking (320x400 - and 360x480). His newer ravings in DDJ covers fast 256-color - bitmaps, compiled bitmaps, polygons, 3D graphics, texture mapping - among other stuff. - - o Richard F. Ferraro : "Programmer's Guide to the EGA and VGA video - cards including Super VGA". I don't have this one, but heard it's - nice. Detailed coverage of all EGA/VGA registers. The Super VGA - reference makes it attractive. - - o Richard Wilton : "Programmer's Guide to PC & PS/2 Video Systems" - Less technical, more application/algorithm oriented. Nice enough, - even though it is a bit outdated, in that he discusses CGA and - Hercules cards just as much as EGA/VGA. - - - - -5. BYE - FOR NOW - -I am considering writing a text describing in more detail the process of -using TWEAK to achieve the VGA resolution you want or need. However, I -thought I'd let this document go first, and see if I get any reactions. -If I don't, I'll stop. Feel free to forward any suggestions, -criticisms, bombs and beers. - -I can be reached via: - - o e-mail: robert@stud.unit.no - - o land mail: - - Robert Schmidt - Stud.post 170 - NTH - N-7034 Trondheim - NORWAY - -Nothing would encourage or please me more than a postcard from where you -live! - -ÚÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ M1ORG.ASC ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÙ - -Figure 1: Memory organization in mode 13h (ASCII version) - by Robert Schmidt - (C) 1993 Ztiff Zox Softwear - -a. Imagine that the top of the screen looks like this (pixel values are - represented by color digits 0-9 for simplicity - actual colors may - range from 0 to 255) - a screen width of 320 pixels is assumed: - - address: 0 10 310 319 - ---------------------------------------- - |0123456789012345 ..... 0123456789| - | | - | | - | - -b. In VGA memory, the screen is represented as follows (question marks - represent unused bytes): - - Plane 0: - - address: 0 10 310 319 - ---------------------------------------- - |0???4???8???2??? ..... ??2???6???| - | | - | | - - Plane 1: - - address: 0 10 310 319 - ---------------------------------------- - |?1???5???9???3?? ..... ???3???7??| - | | - | | - - Plane 2: - - address: 0 10 310 319 - ---------------------------------------- - |??2???6???0???4? ..... 0???4???8?| - | | - | | - - Plane 3: - - address: 0 10 310 319 - ---------------------------------------- - |???3???7???1???5 ..... ?1???5???9| - | | - | | - - I.e. a plane is selected automatically by the two least significant - bits of the address of the byte being read from or written two. - This renders 3/4 of the video memory unavailable and useless, but - all visible pixels are easily accessed, as each address in the video - segment provides access to one and ONLY ONE pixel. - -ÚÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ MXORG.ASC ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÙ - -Figure 2: Memory organization in unchained 256-color modes (like - Mode X) (ASCII version) - by Robert Schmidt - (C) 1993 Ztiff Zox Softwear - - -Imagine that the screen looks the same as in figure 1a. A screen width -of 320 pixels is still assumed. - -In VGA memory, the screen will be represented as follows: - - Plane 0: - - address: 0 10 70 79 (NOT 319!) - ---------------------------------------- - |0482604826048260 ..... 0482604826| - | | - | | - - Plane 1: - - address: 0 10 70 79 - ---------------------------------------- - |1593715937159371 ..... 1593715937| - | | - | | - - Plane 2: - - address: 0 10 70 79 - ---------------------------------------- - |2604826048260482 ..... 2604826048| - | | - | | - - Plane 3: - - address: 0 10 70 79 - ---------------------------------------- - |3715937159371593 ..... 3715937159| - | | - | | - -Note that if pixel i is in plane p, pixel i+1 is in plane (p+1)%4. -When the planes are unchained, we need to set the Write Plane Enable -register to select which planes should receive the data when writing, -or the Read Plane Select register when reading. As is evident, one -address in the video segment provides access to no less than FOUR -different pixels. - -ÚÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Zox3D ³ -ÀÄÄÄÄÄÄÄÙ - -Available via ftp : -ftp.wustl.edu:/pub/MSDOS_UPLOADS/games/programming/zox3d15.zip -wasp.eng.ufl.edu:/pub/msdos/demos//zox3d15.zip - -zox3d15.zip contains a demo of my 3D graphics engine. -It resembles Wolf3D, but has a number of additional -features: - -- texture mapped floor and ceiling (sky, in this demo) -- real, recursive MIRRORS! -- partly TRANSPARENT walls -- input from keyboard, joystick and mouse (at the same - time, too, if you wish) -- controllable camera height - NOT fixed like Wolf3D -- quick resizable window -- online help and fps rating -- advanced collision detection and handling -- supports a variety of tweaked X modes, from 256x256 to 400x300. - -The sky and mirrors have to be seen to be beleived! - -Zox3D does NOT implement objects, like the guards in -Wolf3D, but that should be a breeze to add. - -The complete sources are available. Read ZOX3D.DOC in -the demo archive for information. - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -Robert Schmidt - robert@stud.unit.no - Buuud@IRC diff --git a/16/PCGPE10/MODFORM.TXT b/16/PCGPE10/MODFORM.TXT deleted file mode 100644 index 69163f79..00000000 --- a/16/PCGPE10/MODFORM.TXT +++ /dev/null @@ -1,523 +0,0 @@ - -Protracker 1.1B Song/Module Format: - -Offset Bytes Description - 0 20 Songname. Remember to put trailing null bytes at the end... - -Information for sample 1-31: - -Offset Bytes Description - 20 22 Samplename for sample 1. Pad with null bytes. - 42 2 Samplelength for sample 1. Stored as number of words. - Multiply by two to get real sample length in bytes. - 44 1 Lower four bits are the finetune value, stored as a signed - four bit number. The upper four bits are not used, and - should be set to zero. - Value: Finetune: - 0 0 - 1 +1 - 2 +2 - 3 +3 - 4 +4 - 5 +5 - 6 +6 - 7 +7 - 8 -8 - 9 -7 - A -6 - B -5 - C -4 - D -3 - E -2 - F -1 - - 45 1 Volume for sample 1. Range is $00-$40, or 0-64 decimal. - 46 2 Repeat point for sample 1. Stored as number of words offset - from start of sample. Multiply by two to get offset in bytes. - 48 2 Repeat Length for sample 1. Stored as number of words in - loop. Multiply by two to get replen in bytes. - -Information for the next 30 samples starts here. It's just like the info for -sample 1. - -Offset Bytes Description - 50 30 Sample 2... - 80 30 Sample 3... - . - . - . - 890 30 Sample 30... - 920 30 Sample 31... - -Offset Bytes Description - 950 1 Songlength. Range is 1-128. - 951 1 Well... this little byte here is set to 127, so that old - trackers will search through all patterns when loading. - Noisetracker uses this byte for restart, but we don't. - 952 128 Song positions 0-127. Each hold a number from 0-63 that - tells the tracker what pattern to play at that position. -1080 4 The four letters "M.K." - This is something Mahoney & Kaktus - inserted when they increased the number of samples from - 15 to 31. If it's not there, the module/song uses 15 samples - or the text has been removed to make the module harder to - rip. Startrekker puts "FLT4" or "FLT8" there instead. - -Offset Bytes Description -1084 1024 Data for pattern 00. - . - . - . -xxxx Number of patterns stored is equal to the highest patternnumber - in the song position table (at offset 952-1079). - -Each note is stored as 4 bytes, and all four notes at each position in -the pattern are stored after each other. - -00 - chan1 chan2 chan3 chan4 -01 - chan1 chan2 chan3 chan4 -02 - chan1 chan2 chan3 chan4 -etc. - -Info for each note: - - _____byte 1_____ byte2_ _____byte 3_____ byte4_ -/ / / / -0000 0000-00000000 0000 0000-00000000 - -Upper four 12 bits for Lower four Effect command. -bits of sam- note period. bits of sam- -ple number. ple number. - -Periodtable for Tuning 0, Normal - C-1 to B-1 : 856,808,762,720,678,640,604,570,538,508,480,453 - C-2 to B-2 : 428,404,381,360,339,320,302,285,269,254,240,226 - C-3 to B-3 : 214,202,190,180,170,160,151,143,135,127,120,113 - -To determine what note to show, scan through the table until you find -the same period as the one stored in byte 1-2. Use the index to look -up in a notenames table. - -This is the data stored in a normal song. A packed song starts with the -four letters "PACK", but i don't know how the song is packed: You can -get the source code for the cruncher/decruncher from us if you need it, -but I don't understand it; I've just ripped it from another tracker... - -In a module, all the samples are stored right after the patterndata. -To determine where a sample starts and stops, you use the sampleinfo -structures in the beginning of the file (from offset 20). Take a look -at the mt_init routine in the playroutine, and you'll see just how it -is done. - -Lars "ZAP" Hamre/Amiga Freelancers - --------------------------- - -Found that document... - -Mark J Cox ------------------------------------------- m.j.h.cox@bradford.ac.uk -University of Bradford ---------------------------- bc732@cleveland.freenet.edu -Mark - - EFFECT COMMANDS - --------------- - Effect commands on protracker should - be compatible with all other trackers. - 0 - None/Arpeggio 8 - * NOT USED * - 1 - Portamento Up 9 - SampleOffset - 2 - Portamento Down A - VolumeSlide - 3 - TonePortamento B - PositionJump - 4 - Vibrato C - Set Volume - 5 - ToneP + VolSlide D - PatternBreak - 6 - Vibra + VolSlide E - Misc. Cmds - 7 - Tremolo F - Set Speed - - - E - COMMANDS - ------------ - The E command has been altered to - contain more commands than one. - E0- Filter On/Off E8- * NOT USED * - E1- Fineslide Up E9- Retrig Note - E2- Fineslide Down EA- FineVol Up - E3- Glissando Control EB- FineVol Down - E4- Vibrato Control EC- NoteCut - E5- Set Finetune ED- NoteDelay - E6- Patternloop EE- PatternDelay - E7- Tremolo Control EF- Invert Loop - - - Cmd 0. Arpeggio [Range:$0-$F/$0-$F] - ----------------------------------- - Usage: $0 + 1st halfnote add - + 2nd halfnote add - Arpeggio is used to simulate chords. - This is done by rapidly changing the - pitch between 3(or 2) different notes. - It sounds very noisy and grainy on - most samples, but ok on monotone ones. - Example: C-300047 C-major chord: - (C+E+G or C+4+7 halfnotes) - C-300037 C-minor chord: - (C+D#+G or C+3+7 halfnotes) - - - Cmd 1. Portamento up [Speed:$00-$FF] - ------------------------------------ - Usage: $1 + portamento speed - Portamento up will simply slide the - sample pitch up. You can NOT slide - higher than B-3! (Period 113) - Example: C-300103 1 is the command, - 3 is the portamentospeed. - NOTE: The portamento will be called as - many times as the speed of the song. - This means that you'll sometimes have - trouble sliding accuratly. If you - change the speed without changing the - sliderates, it will sound bad... - - - Cmd 2. Portamento down [Speed:$00-FF] - ------------------------------------- - Usage: $2 + portamento speed - Just like command 1, except that this - one slides the pitch down instead. - (Adds to the period). - You can NOT slide lower than C-1! - (Period 856) - Example: C-300203 2 is the command, - 3 is the portamentospeed. - - - Cmd 3. Tone-portamento [Speed:$00-$FF] - -------------------------------------- - Usage: Dest-note + $3 + slidespeed - This command will automatically slide - from the old note to the new. - You don't have to worry about which - direction to slide, you need only set - the slide speed. To keep on sliding, - just select the command $3 + 00. - Example: A-200000 First play a note. - C-300305 C-3 is the note to - slide to, 3 the command, - and 5 the speed. - - - Cmd 4. Vibrato [Rate:$0-$F,Dpth:$0-$F] - -------------------------------------- - Usage: $4 + vibratorate + vibratodepth - Example: C-300481 4 is the command, - 8 is the speed of the vibrato, - and 1 is the depth of the vibrato. - To keep on vibrating, just select - the command $4 + 00. To change the - vibrato, you can alter the rate, - depth or both. Use command E4- to - change the vibrato-waveform. - - - Cmd 5. ToneP + Volsl [Spd:$0-$F/$0-$F] - -------------------------------------- - Usage: $5 + upspeed + downspeed - This command will continue the current - toneportamento and slide the volume - at the same time. Stolen from NT2.0. - Example: C-300503 3 is the speed to - turn the volume down. - C-300540 4 is the speed to - slide it up. - - - Cmd 6. Vibra + Volsl [Spd:$0-$F/$0-$F] - -------------------------------------- - Usage: $6 + upspeed + downspeed - This command will continue the current - vibrato and slide the volume at the - same time. Stolen from NT2.0. - Example: C-300605 5 is the speed to - turn the volume down. - C-300640 4 is the speed to - slide it up. - - - Cmd 7. Tremolo [Rate:$0-$F,Dpth:$0-$F] - -------------------------------------- - Usage: $7 + tremolorate + tremolodepth - Tremolo vibrates the volume. - Example: C-300794 7 is the command, - 9 is the speed of the tremolo, - and 4 is the depth of the tremolo. - To keep on tremoling, just select - the command $7 + 00. To change the - tremolo, you can alter the rate, - depth or both. Use command E7- to - change the tremolo-waveform. - - - Cmd 9. Set SampleOffset [Offs:$00-$FF] - -------------------------------------- - Usage: $9 + Sampleoffset - This command will play from a chosen - position in the sample, and not from - the beginning. The two numbers equal - the two first numbers in the length - of the sample. Handy for speech- - samples. - Example: C-300923 Play sample from - offset $2300. - - - Cmd A. Volumeslide [Speed:$0-$F/$0-$F] - -------------------------------------- - Usage: $A + upspeed + downspeed - Example: C-300A05 5 is the speed to - turn the volume down. - C-300A40 4 is the speed to - slide it up. - NOTE: The slide will be called as - many times as the speed of the song. - The slower the song, the more the - volume will be changed on each note. - - - Cmd B. Position-jump [Pos:$00-$7F] - ---------------------------------- - Usage: $B + position to continue at - Example: C-300B01 B is the command, - 1 is the position to - restart the song at. - This command will also perform a - pattern-break (see 2 pages below). - You can use this command instead of - restart as on noisetracker, but you - must enter the position in hex! - - - Cmd C. Set volume [Volume:$00-$40] - ---------------------------------- - Usage: $C + new volume - Well, this old familiar command will - set the current volume to your own - selected. The highest volume is $40. - All volumes are represented in hex. - (Programmers do it in hex, you know!) - Example: C-300C10 C is the command, - 10 is the volume (16 decimal). - - - Cmd D. Pattern-break - [Pattern-pos:00-63, decimal] - ---------------------------- - Usage: $D + pattern-position - This command just jumps to the next - song-position, and continues play - from the patternposition you specify. - Example: C-300D00 Jump to the next - song-position and continue play - from patternposition 00. - Or: C-300D32 Jump to the next - song-position and continue play - from patternposition 32 instead. - - - Cmd E0. Set filter [Range:$0-$1] - -------------------------------- - Usage: $E0 + filter-status - This command jerks around with the - sound-filter on some A500 + A2000. - All other Amiga-users should keep out - of playing around with it. - Example: C-300E01 disconnects filter - (turns power LED off) - C-300E00 connects filter - (turns power LED on) - - - Cmd E1. Fineslide up [Range:$0-$F] - ---------------------------------- - Usage: $E1 + value - This command works just like the - normal portamento up, except that - it only slides up once. It does not - continue sliding during the length of - the note. - Example: C-300E11 Slide up 1 at the - beginning of the note. - (Great for creating chorus effects) - - - Cmd E2. Fineslide down [Range:$0-$F] - ------------------------------------ - Usage: $E2 + value - This command works just like the - normal portamento down, except that - it only slides down once. It does not - continue sliding during the length of - the note. - Example: C-300E26 Slide up 6 at the - beginning of the note. - - - Cmd E3. Glissando Ctrl [Range:$0-$1] - ------------------------------------ - Usage: $E3 + Glissando-Status - Glissando must be used with the tone- - portamento command. When glissando is - activated, toneportamento will slide - a halfnote at a time, instead of a - straight slide. - Example: C-300E31 Turn Glissando on. - C-300E30 Turn Glissando off. - - - Cmd E4. Set vibrato waveform - [Range:$0-$3] - ---------------------------- - Usage: $E4 + vibrato-waveform - Example: C-300E40 Set sine(default) - E44 Don't retrig WF - C-300E41 Set Ramp Down - E45 Don't retrig WF - C-300E42 Set Squarewave - E46 Don't retrig WF - C-300E43 Set Random - E47 Don't retrig WF - - - Cmd E5. Set finetune [Range:$0-$F] - ---------------------------------- - Usage: $E5 + finetune-value - Example: C-300E51 Set finetune to 1. - Use these tables to figure out the - finetune-value. - Finetune: +7 +6 +5 +4 +3 +2 +1 0 - Value: 7 6 5 4 3 2 1 0 - Finetune: -1 -2 -3 -4 -5 -6 -7 -8 - Value: F E D C B A 9 8 - - - Cmd E6. PatternLoop [Loops:$0-$F] - ---------------------------------- - Usage: $E6 + number of loops - This command will loop a part of a - pattern. - Example: C-300E60 Set loopstart. - C-300E63 Jump to loop 3 - times before playing on. - - - Cmd E7. Set tremolo waveform - [Range:$0-$3] - ---------------------------- - Usage: $E7 + tremolo-waveform - Example: C-300E70 Set sine(default) - E74 Don't retrig WF - C-300E71 Set Ramp Down - E75 Don't retrig WF - C-300E72 Set Squarewave - E76 Don't retrig WF - C-300E73 Set Random - E77 Don't retrig WF - - - Cmd E9. Retrig note [Value:$0-$F] - --------------------------------- - Usage: $E9 + Tick to Retrig note at. - This command will retrig the same note - before playing the next. Where to - retrig depends on the speed of the - song. If you retrig with 1 in speed 6 - that note will be trigged 6 times in - one note slot. Retrig on hi-hats! - Example: C-300F06 Set speed to 6. - C-300E93 Retrig at tick 3 - out of 6. - - - Cmd EA. FineVolsl up [Range:$0-$F] - ---------------------------------- - Usage: $EA + value - This command works just like the - normal volumeslide up, except that - it only slides up once. It does not - continue sliding during the length of - the note. - Example: C-300EA3 Slide volume up 1 - at the beginning of the note. - - - Cmd EB. FineVolsl down [Range:$0-$F] - ------------------------------------ - Usage: $EB + value - This command works just like the - normal volumeslide down, except that - it only slides down once. It does not - continue sliding during the length of - the note. - Example: C-300EB6 Slide volume down - 6 at the beginning of the note. - - - Cmd EC. Cut note [Value:$0-$F] - ------------------------------ - Usage: $EC + Tick to Cut note at. - This command will cut the note - at the selected tick, creating - extremely short notes. - Example: C-300F06 Set speed to 6. - C-300EC3 Cut at tick 3 out - of 6. - Note that the note is not really cut, - the volume is just turned down. - - - Cmd ED. NoteDelay [Value:$0-$F] - ------------------------------- - Usage: $ED + ticks to delay note. - This command will delay the note - to the selected tick. - Example: C-300F06 Set speed to 6. - C-300ED3 Play note at tick - 3 out of 6. - - - Cmd EE. PatternDelay [Notes:$0-$F] - ---------------------------------- - Usage: $EE + notes to delay pattern. - This command will delay the pattern - the selected numbers of notes. - Example: C-300EE8 Delay pattern 8 - notes before playing on. - All other effects are still active - when the pattern is being delayed. - - - Cmd EF. Invert Loop [Speed:$0-$F] - --------------------------------- - Usage: $EF + Invertspeed - This command will need a short loop - ($10,20,40,80 etc. bytes) to work. - It will invert the loop byte by byte. - Sounds better than funkrepeat... - Example: C-300EF8 Set invspeed to 8. - To turn off the inverting, set - invspeed to 0, or press ctrl + Z. - - - Cmd F. Set speed [Speed:$00-$FF] - -------------------------------- - Usage: $F + speed - This command will set the speed of the - song. - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Annotation by Mark Feldman (u914097@student.canberra.edu.au ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The 6 and 8 channel mod files differ from the normal mods in two ways: - -1) The signature string "M.K." at offset 1080 is either "6CHN" or "8CHN". -2) The pattern data table starting at offset 1084 stores 6 or 8 notes for - each pattern position position. diff --git a/16/PCGPE10/MOUSE.TXT b/16/PCGPE10/MOUSE.TXT deleted file mode 100644 index 7f59c0be..00000000 --- a/16/PCGPE10/MOUSE.TXT +++ /dev/null @@ -1,295 +0,0 @@ - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Programming the Microsoft Mouse ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - Written for the PC-GPE by Mark Feldman - e-mail address : u914097@student.canberra.edu.au - myndale@cairo.anu.edu.au - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ THIS FILE MAY NOT BE DISTRIBUTED ³ - ³ SEPARATE TO THE ENTIRE PC-GPE COLLECTION. ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Disclaimer ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ - -I assume no responsibility whatsoever for any effect that this file, the -information contained therein or the use thereof has on you, your sanity, -computer, spouse, children, pets or anything else related to you or your -existance. No warranty is provided nor implied with this information. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Introduction ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -A complete list of mouse function calls can be found in the file GMOUSE.TXT, -the file contains calls for both Microsoft (2 button) and Genius (3 button) -modes. - -Calling these functions from within a Pascal program is a fairly simple -matter. This procedure would get the mouse position and button states: - -const MOUSEINTR = $33; - -procedure GetMousePos(var x, y : word; var button1, button2 : boolean); -var regs : registers; -begin - regs.ax := 3; - Intr(MOUSEINTR, regs); - x := regs.cx; - y := regs.dx; - button1 := (regs.bx and 1) <> 0; - button2 := (regs.bx and 2) <> 0; -end; - - -The mouse position is returned in variables x and y, the button states are -returned in variable button1 and button2 (true = button is pressed). - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Writing Custom Handlers ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Most mouse drivers do not support SVGA modes, so you must write custom -handlers if you want mouse support for these modes. - -Rather than writing an entire mouse driver, you can write a simple handler -routine to take care of the graphics and tell the mouse driver to call it -whenever the mouse does anything. This function is descibed in the GMOUSE.DOC -file, but this demo Pascal program shows the general idea. It sets mode 13h, -resets the mouse and waits for a key to be pressed. Whenever you do anything -to the mouse (moving it or pressing a button) the handler will get called -and it will draw a pixel on the screen. The color of the pixel depends on -which buttons are being pressed. - -Uses Crt, Dos; - -{$F+} -{ called with bl = buttons, cx = x * 2, dx = y } -procedure Handler; far; assembler; -asm - - { This mouse "handler" just draws a pixel at the current mouse pos } - pusha - mov ax, $A000 - mov es, ax - shr cx, 1 - xchg dh, dl - mov di, dx - shr dx, 2 - add di, dx - add di, cx - mov al, bl - inc al - stosb - popa -end; -{$F-} - -begin - asm - - { Set graphics mode 13h } - mov ax, $13 - int $10 - - { Initialize mouse driver } - xor ax, ax - int $33 - - { Install custom handler } - mov ax, SEG Handler - mov es, ax - mov dx, OFS Handler - mov ax, 12 - mov cx, $1F - int $33 - - { Wait for a key press } - xor ah, ah - int $16 - - { Back to text mode } - mov ax, 3 - int $10 - end; -end. - - - - -Alternatively you may wish to write your own interrupt handler to process -mouse events as they happen. When a mouse event occurs, 3 interrupts are -generated and the bytes are availble via the COM port. - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Interrupt Port ³ - ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ - ³ COM1 $0C $3F8 ³ - ³ COM2 $0B $3F8 ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The three bytes sent are formatted as follows: - - - 1st byte 2nd byte 3rd byte - ÚÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄ¿ÚÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄ¿ÚÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄ¿ - ³-³1³?³?³Y³Y³X³X³³-³0³X³X³X³X³X³X³³-³0³Y³Y³Y³Y³Y³Y³ - ÀÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÙÀÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÙÀÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÙ - ³ ³ ÀÂÙ ÀÂÙ ÀÄÄÄÄÂÄÄÄÄÙ ÀÄÄÄÄÂÄÄÄÄÙ - ³ ³ ³ ³ ³ ³ - ³ ³ ³ ÀÄÄÄÄ¿ ³ ³ - ³ ³ ÀÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄ¿ ³ - ³ ³ ÚÁ¿ ÚÄÄÄÄÁÄÄÄÄ¿ ÚÁ¿ ÚÄÄÄÄÁÄÄÄÄ¿ - ³ ³ ÚÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄ¿ÚÄÂÄÂÄÂÄÂÄÂÄÂÄÂÄ¿ - ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³³ ³ ³ ³ ³ ³ ³ ³ ³ - Left Button ÄÄÙ ³ ÀÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÙÀÄÁÄÁÄÁÄÁÄÁÄÁÄÁÄÙ -Right Button ÄÄÄÄÙ X increment Y increment - - -The X and Y increment values are in 2's compliment signed char format. (BTW -thanks go to Adam Seychell for posting this info to comp.os.msdos.programmer). - - -A simple Borland Pascal 7.0 mouse handler follows. First we declare a few -things we'll need: - - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ -Uses Crt, Dos; - -{$F+} - -const COM1INTR = $0C; - COM1PORT = $3F8; - -var bytenum : word; - combytes : array[0..2] of byte; - x, y : longint; - button1, button2 : boolean; - MouseHandler : procedure; -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The bytenum variable is used to keep track of which byte is expected next -(ie 0, 1 or 2). The combytes variable is simply an array to keep track of -bytes received so far. The mouse position will be stored in the x and y -varaibles (note that this example will not perfrom any range checking). -Button1 and button2 will be used to store the states of each of the buttons. -MouseHandler will be used to store the normal mouse driver event handler. -We'll need it to reset everything once we are finished. - -Here's the actual handler: - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ -procedure MyMouseHandler; Interrupt; -var dx, dy : integer; -var inbyte : byte; -begin - - { Get the port byte } - inbyte := Port[COM1PORT]; - - { Make sure we are properly "synched" } - if (inbyte and 64) = 64 then bytenum := 0; - - { Store the byte and adjust bytenum } - combytes[bytenum] := inbyte; - inc(bytenum); - - { Have we received all 3 bytes? } - if bytenum = 3 then - begin - { Yes, so process them } - dx := (combytes[0] and 3) shl 6 + combytes[1]; - dy := (combytes[0] and 12) shl 4 + combytes[2]; - if dx >= 128 then dx := dx - 256; - if dy >= 128 then dy := dy - 256; - x := x + dx; - y := y + dy; - button1 := (combytes[0] And 32) <> 0; - button2 := (combytes[0] And 16) <> 0; - - { And start on first byte again } - bytenum := 0; - end; - - { Acknowledge the interrupt } - Port[$20] := $20; -end; -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Once again pretty simple stuff. We just read the byte from the com1 port and -figure out if it's time to do anything yet. If bit 6 is set to 1 then we -know that it's meant to be the first byte of the 3, so we reset our -bytenum variable to zero (in a perfect world bytes would always come in 3's -and we would never need to check, but it never hurts to be careful). - -When 3 bytes have been received we simple decode them according to the -diagram above and update the appropriate variables accordingly. - -The 'Port[$20] := $20;' command just lets the interrupt controller know we -have processed the interrupt so it can send us the next one when it wants to. - -Note that the above "handler" does nothing more than keep track of the -current mouse position and button states. If we were writing a proper mouse -driver for an SVGA game we would also have to write custom cursor routines. -I'll leave that bit to you! - -To actually install our mouse driver we'll have to set up all the variables, -save the address of the current mouse handler and install our own. We'll -also need call the existing mouse driver to set up the COM1 port to make -sure it sends us the mouse bytes as it receives them. We could do this -ourselves, but why make life harder than it already is? - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ -procedure InitMyDriver; -begin - - { Initialize the normal mouse handler } - asm - mov ax, 0 - int $33 - end; - - { Initialize some of the variables we'll be using } - bytenum := 0; - x := 0; - y := 0; - button1 := false; - button2 := false; - - { Save the current mouse handler and set up our own } - GetIntVec(COM1INTR, @MouseHandler); - SetIntVec(COM1INTR, Addr(MyMouseHandler)); -end; -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -And finally when our program is finished it'll need to clean up after -itself and return control back to the normal mouse driver: - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ -procedure CleanUpMyDriver; -begin - SetIntVec(COM1INTR, @MouseHandler); -end; -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -This little bit of source will test the above code. It does nothing more -than repeatedly write the mouse position and button states to the screen -until a keyboard key is pressed: - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ -begin - ClrScr; - InitMyDriver; - while not keypressed do - WriteLn(x : 5, y : 5, button1 : 7, button2 : 7); - CleanUpMyDriver; -end. -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ diff --git a/16/PCGPE10/PALLETTE.COL b/16/PCGPE10/PALLETTE.COL deleted file mode 100644 index a945ccc91ad58de0dfc013657f318ceae7b2ce49..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 768 zcmW-fi`r@c6hsHP6OtrJ5(%ZqCDeZZw>tgj1!m2xZvYU{;cytoaTtcSZJVZfKA%-p zm1UXdd6s2KlEiTwMNt@rK@j-9?|Gi>rf zT(dXTR#9qMswD9y3c0{v7K`(OJ8^8tvU`@;Gd6Km%kz#5~h5P}5LVQBl$* zqd2DUNdBJOE!k@_Oj0!xCE^wYhJG4=3Fv_asDJ{v0B7I`?13%tW0?N|62Q+Lz3{d|_gQ1tzU z>$0}Z7zR`oqBzdqZu~s^&#nDjn>l&T(PIwolUGhoF?+_35&m6L&ms zhLh7p>(_BzhjtZMrEgw$%XF*98|~;Qfi3SW$u-2aE?64BR5(@QWPueH%R diff --git a/16/PCGPE10/PARADISE.TXT b/16/PCGPE10/PARADISE.TXT deleted file mode 100644 index be114a8d..00000000 --- a/16/PCGPE10/PARADISE.TXT +++ /dev/null @@ -1,237 +0,0 @@ - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Programming the Paradise SVGA Chip ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - Written for the PC-GPE by Mark Feldman - e-mail address : u914097@student.canberra.edu.au - myndale@cairo.anu.edu.au - - Please read the file SVGINTRO.TXT - (Graphics/SVGA/Intro PC-GPE menu option) - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ THIS FILE MAY NOT BE DISTRIBUTED ³ - ³ SEPARATE TO THE ENTIRE PC-GPE COLLECTION. ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Disclaimer ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ - -I assume no responsibility whatsoever for any effect that this file, the -information contained therein or the use thereof has on you, your sanity, -computer, spouse, children, pets or anything else related to you or your -existance. No warranty is provided nor implied with this information. - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Introduction ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Western Digital have made a series of Paradise chips, the PVGA1A, WD90C00 -and WD90C11. Each chip is fully compatible with it's predecessors. There -is also a WD90C10 which is a stripped down version of the WD90C00 used for -motherboard VGA implementations and does not support 256 color modes higher -that 320x200; this chip will not be discussed here. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Paradise Extensions ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -To modify any of the Paradise extended registers you must enable the -extensions. Disable them once you are done. - -To enable extensions: - -PortW[$3CE] := $050F; { Extensions on } -PortW[$3D4] := $8529; { Unlock PR10-PR17 } -PortW[$3C4] := $4806; { Unlock extended sequencer } - -To disable extensions : - -PortW[$3CE] := $000F; { Extensions off } -PortW[$3D4] := $0029; { Lock PR10-PR17 } -PortW[$3C4] := $0006; { Lock extended sequencer } - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Identifying the Paradise SVGA Chip ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -To identify if a Paradise SVGA chip is present read the 4 bytes at memory -address C000:007D. These bytes should be the string "VGA=". - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Memory Address Value ³ - ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ - ³ C000:007Dh 86d ('V') ³ - ³ C000:007Eh 71d ('G') ³ - ³ C000:007Fh 65d ('A') ³ - ³ C000:0080h 61d ('=') ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Identifying which Paradise Chip is Present ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The Paradise chip present can be determined by trying to access selected -registers. The following pseudo-code will determine the chip id: - -var old_value : byte; - -Enable Extensions - -{ Test for a PVGA1A } -Port[$3D4] := $2B -old_value := Port[$3D5] -Port[$3D5] := $AA -if Port[$3D5] <> $AA then - begin - chip is a PVGA1A - Port[$3D5] := old_value - return - end -Port[$3D5] := old_value - -{ Distinguish between WD90C00 and WD90C10 } -Port[$3C4] := $12 -old_value := Port[$3C5] -Port[$3C5] := old_value and $BF -if (Port[$3C5] and $40) <> 0 then - begin - chip is a WD90C00 - return - end -Port[$3C5] := old_value or $40 -if (Port[$3C5] and $40) = 0 then - begin - chip is a WD90C00 - Port[$3C5] := old_value - return - end -Port[$3C5] := old_value - -{ Distinguish between WD90C10 and WD90C11 } -Port[$3C4] := $10 -old_value := Port[$3C5] -Port[$3C5] := old_value and $FB -if (Port[$3C5] and $04) <> 0 then - begin - chip is a WD90C10 - Port[$3C5] := old_value - return - end -Port[$3C5] := old_value or $04 -if (Port[$3C5] and $04) = 0 then - begin - chip is a WD90C10 - Port[$3C5] := old_value - return - end - -{ We made it this far so it's a WD90C11 } -chip is a WD90C11 -Port[$3C5] := old_value - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Paradise Graphics Display Modes ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Mode Resolution Colors Chips ³ - ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ - ³ 58h 800x600 16 pVGA1, WDC90cxx ³ - ³ 59h 800x600 2 pVGA1, WDC90cxx ³ - ³ 5Eh 640x400 256 pVGA1, WDC90cxx ³ - ³ 5Fh 640x480 256 pVGA1, WD90cxx ³ - ³ 5Ah 1024x768 2 WD90cxx ³ - ³ 5Bh 1024x768 4 WD90cxx ³ - ³ 5Dh 1024x768 16 WD90cxx, c11 (512K) ³ - ³ 5Ch 800x600 256 WD90c11 (512K) ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Paradise Display Memory ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Remember, extensions must be enabled before any of the following procedures -are called. - -The Paradise can work in either single-paging mode, duel-paging mode or -read/write mode. There are two registers used to select banks in each of -the Paradise bank selection modes: - - PR0A Address Offset A - Index : 09h at port 3CEh - Read/Write at port 3CFh - ÚÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄ¿ - ³ 7 ³ 6 ³ 5 ³ 4 ³ 3 ³ 2 ³ 1 ³ 0 ³ - ÀÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÙ - ÀÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÙ - Bank - - PR0B Address Offset A - Index : 0Ah at port 3CEh - Read/Write at port 3CFh - ÚÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄ¿ - ³ 7 ³ 6 ³ 5 ³ 4 ³ 3 ³ 2 ³ 1 ³ 0 ³ - ÀÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÙ - ÀÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÙ - Bank - -There are 128 banks and the bank granularity is 4k, so if you want a bank -granularity of 64k you must multiply the bank number by 16. - - -Single Paging Mode -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - -In single paging mode PR0A is set to map a bank to host memory at -A000:0000-FFFFh. The bank is used for both reading and writing operations. -To set up for single paging mode use the following procedure: - -Port[$3C4] := $11; { Disable read/write mode } -Port[$3C5] := Port[$3C5] and $7F; -Port[$3CE] := $0B; { Disable PR0B } -Port[$3CF] := Port[$3CF] and $F7; - -To set a 64k bank number in single paging mode use the following procedure: - -PortW[$3CE] := bank_number Shl 12 + $09; - - -Duel Paging Mode -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - -In duel paging mode PR0A is set to map a bank to host memory at -A000:0000-7FFFh and PR0B is set to map a bank to host memory at -A000:8000-FFFFh. Each bank is used for both reading and writing operations. - -To set up for duel paging mode use the following procedure: - -Port[$3C4] := $11; { Disable read/write mode } -Port[$3C5] := Port[$3C5] and $7F; -Port[$3CE] := $0B; { Enable PR0B } -Port[$3CF] := Port[$3CF] or $80; - -To set the lower bank use the same procedure as given for single-paging -mode. The upper bank can be set with the following procedure: - -PortW[$3CE] := bank_number Shl 12 + $0A; - - -Read/Write Paging Mode -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - -In read/write paging mode PR0A is used to map a bank at A000:0000-FFFFh for -read operations and PR0B is used to map a bank at A000:0000-FFFFh for write -operations. To set up for read/write paging mode use the following procedure: - -Port[$3C4] := $11; { Enable read/write mode } -Port[$3C5] := Port[$3C5] or $80; -Port[$3CE] := $0B; { Enable PR0B } -Port[$3CF] := Port[$3CF] or $80; - -Setting PR0A and PR0B is the same as for duel paging mode. - diff --git a/16/PCGPE10/PCGPE.EXE b/16/PCGPE10/PCGPE.EXE deleted file mode 100644 index 4b715805da3e4edf15728f4e31d4acc06faa31a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 144842 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

C3cT-)egsJFEi862ha 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 E0KhWp#Q*>R diff --git a/16/PCGPE10/PCX.TXT b/16/PCGPE10/PCX.TXT deleted file mode 100644 index f354b1e6..00000000 --- a/16/PCGPE10/PCX.TXT +++ /dev/null @@ -1,586 +0,0 @@ - -ZSoft PCX File Format Technical Reference Manual - - - -Introduction 2 -Image File (.PCX) Format 3 -ZSoft .PCX FILE HEADER FORMAT 4 -Decoding .PCX Files 6 -Palette Information Description 7 -EGA/VGA 16 Color Palette Information 7 -VGA 256 Color Palette Information 7 -24-Bit .PCX Files 8 -CGA Color Palette Information 8 -CGA Color Map 8 -PC Paintbrush Bitmap Character Format 9 -Sample "C" Routines 10 -FRIEZE Technical Information 14 -General FRIEZE Information 14 -7.00 and Later FRIEZE 14 -FRIEZE Function Calls 15 -FRIEZE Error Codes 18 - - - - - -Introduction - -This booklet was designed to aid developers and users in understanding -the technical aspects of the .PCX file format and the use of FRIEZE. -Any comments, questions or suggestions about this booklet should be -sent to: - - ZSoft Corporation - Technical Services - ATTN: Code Librarian - 450 Franklin Rd. Suite 100 - Marietta, GA 30067 - - - -Technical Reference Manual information compiled by: -Dean Ansley - - -Revision 5 - -To down load additional information and the source for a complete -Turbo Pascal program to show .PCX files on a CGA/EGA/VGA graphics -display, call our BBS at (404)427-1045. You may use a 9600 baud -modem or a 2400 baud standard modem. Your modem should be set for -8 data bits, 1 stop bit, and NO parity. - -Image File (.PCX) Format - -If you have technical questions on the format, please do not call -technical support. ZSoft provides this document as a courtesy to -its users and developers. It is not the function of Technical Support -to provide programming assistance. If something is not clear, leave a -message on our BBS, Compuserve, or write us a letter at the above address. - -The information in this section will be useful if you want to write a -program to read or write PCX files (images). If you want to write a -special case program for one particular image format you should be able -to produce something that runs twice as fast as "Load from..." in -PC Paintbrush. - -Image files used by PC Paintbrush product family and FRIEZE (those with a -.PCX extension) begin with a 128 byte header. Usually you can ignore this -header, since your images will probably all have the same resolution. If -you want to process different resolutions or colors, you will need to -interpret the header correctly. The remainder of the image file consists -of encoded graphic data. The encoding method is a simple byte oriented -run-length technique. We reserve the right to change this method to -improve space efficiency. When more than one color plane is stored in -the file, each line of the image is stored by color plane (generally ordered -red, green, blue, intensity), As shown below. - -Scan line 0: RRR... (Plane 0) - GGG... (Plane 1) - BBB... (Plane 2) - III... (Plane 3) -Scan line 1: RRR... - GGG... - BBB... - III... (etc.) - -The encoding method is: - FOR each byte, X, read from the file - IF the top two bits of X are 1's then - count = 6 lowest bits of X - data = next byte following X - ELSE - count = 1 - data = X - -Since the overhead this technique requires is, on average, 25% of -the non-repeating data and is at least offset whenever bytes are repeated, -the file storage savings are usually considerable. - -ZSoft .PCX FILE HEADER FORMAT - -Byte Item Size Description/Comments - 0 Manufacturer 1 Constant Flag, 10 = ZSoft .pcx - 1 Version 1 Version information - 0 = Version 2.5 of PC Paintbrush - 2 = Version 2.8 w/palette information - 3 = Version 2.8 w/o palette information - 4 = PC Paintbrush for Windows(Plus for - Windows uses Ver 5) - 5 = Version 3.0 and > of PC Paintbrush - and PC Paintbrush +, includes - Publisher's Paintbrush . Includes - 24-bit .PCX files - 2 Encoding 1 1 = .PCX run length encoding - 3 BitsPerPixel 1 Number of bits to represent a pixel - (per Plane) - 1, 2, 4, or 8 - 4 Window 8 Image Dimensions: Xmin,Ymin,Xmax,Ymax -12 HDpi 2 Horizontal Resolution of image in DPI* -14 VDpi 2 Vertical Resolution of image in DPI* -16 Colormap 48 Color palette setting, see text -64 Reserved 1 Should be set to 0. -65 NPlanes 1 Number of color planes -66 BytesPerLine 2 Number of bytes to allocate for a scanline - plane. MUST be an EVEN number. Do NOT - calculate from Xmax-Xmin. -68 PaletteInfo 2 How to interpret palette- 1 = Color/BW, - 2 = Grayscale (ignored in PB IV/ IV +) -70 HscreenSize 2 Horizontal screen size in pixels. New field - found only in PB IV/IV Plus -72 VscreenSize 2 Vertical screen size in pixels. New field - found only in PB IV/IV Plus -74 Filler 54 Blank to fill out 128 byte header. Set all - bytes to 0 - - NOTES: - -All sizes are measured in BYTES. - -All variables of SIZE 2 are integers. - -*HDpi and VDpi represent the Horizontal and Vertical resolutions which the -image was created (either printer or scanner); i.e. an image which was -scanned might have 300 and 300 in each of these fields. - -Decoding .PCX Files - -First, find the pixel dimensions of the image by calculating -[XSIZE = Xmax - Xmin + 1] and [YSIZE = Ymax - Ymin + 1]. Then calculate -how many bytes are required to hold one complete uncompressed scan line: - -TotalBytes = NPlanes * BytesPerLine - -Note that since there are always an even number of bytes per scan line, -there will probably be unused data at the end of each scan line. TotalBytes -shows how much storage must be available to decode each scan line, including -any blank area on the right side of the image. You can now begin decoding -the first scan line - read the first byte of data from the file. If the -top two bits are set, the remaining six bits in the byte show how many times -to duplicate the next byte in the file. If the top two bits are not set, -the first byte is the data itself, with a count of one. - -Continue decoding the rest of the line. Keep a running subtotal of how -many bytes are moved and duplicated into the output buffer. When the -subtotal equals TotalBytes, the scan line is complete. There should always -be a decoding break at the end of each scan line. But there will not be a -decoding break at the end of each plane within each scan line. When the -scan line is completed, there may be extra blank data at the end of each -plane within the scan line. Use the XSIZE and YSIZE values to find where -the valid image data is. If the data is multi-plane, BytesPerLine shows -where each plane ends within the scan line. - -Continue decoding the remainder of the scan lines (do not just read to -end-of-file). There may be additional data after the end of the image -(palette, etc.) - - Palette Information Description - -EGA/VGA 16 Color Palette Information - -In standard RGB format (IBM EGA, IBM VGA) the data is stored as 16 triples. -Each triple is a 3 byte quantity of Red, Green, Blue values. The values can -range from 0-255, so some interpretation may be necessary. On an IBM EGA, -for example, there are 4 possible levels of RGB for each color. Since -256/4 = 64, the following is a list of the settings and levels: - -Setting Level - 0-63 0 - 64-127 1 -128-192 2 -193-254 3 - -VGA 256 Color Palette Information - -ZSoft has recently added the capability to store palettes containing more -than 16 colors in the .PCX image file. The 256 color palette is formatted -and treated the same as the 16 color palette, except that it is substantially -longer. The palette (number of colors x 3 bytes in length) is appended to -the end of the .PCX file, and is preceded by a 12 decimal. Since the VGA -device expects a palette value to be 0-63 instead of 0-255, you need to -divide the values read in the palette by 4. - -To access a 256 color palette: - -First, check the version number in the header; if it contains a 5 there is -a palette. - -Second, read to the end of the file and count back 769 bytes. The value -you find should be a 12 decimal, showing the presence of a 256 color palette. - - 24-Bit .PCX Files - -24 bit images are stored as version 5 or above as 8 bit, 3 plane images. - -24 bit images do not contain a palette. - -Bit planes are ordered as lines of red, green, blue in that order. - -CGA Color Palette Information - -NOTE: This is no longer supported for PC Paintbrush IV/IV Plus. - -For a standard IBM CGA board, the palette settings are a bit more complex. -Only the first byte of the triple is used. The first triple has a valid -first byte which represents the background color. To find the background, -take the (unsigned) byte value and divide by 16. This will give a result -between 0-15, hence the background color. The second triple has a valid -first byte, which represents the foreground palette. PC Paintbrush supports -8 possible CGA palettes, so when the foreground setting is encoded between -0 and 255, there are 8 ranges of numbers and the divisor is 32. - -CGA Color Map - -Header Byte #16 - -Background color is determined in the upper four bits. - -Header Byte #19 - -Only upper 3 bits are used, lower 5 bits are ignored. The first three bits -that are used are ordered C, P, I. These bits are interpreted as follows: - -c: color burst enable - 0 = color; 1 = monochrome - -p: palette - 0 = yellow; 1 = white - -i: intensity - 0 = dim; 1 = bright - - PC Paintbrush Bitmap Character Format - -NOTE: This format is for PC Paintbrush (up to Vers 3.7) and PC Paintbrush -Plus (up to Vers 1.65) - -The bitmap character fonts are stored in a particularly simple format. The -format of these characters is as follows: - - -Header - -font width byte 0xA0 + character width (in pixels) -font height byte character height (in pixels) - -Character Width Table - -char widths (256 bytes) each char's width + 1 pixel of kerning - -Character Images - -(remainder of the file) starts at char 0 (Null) - -The characters are stored in ASCII order and as many as 256 may be provided. -Each character is left justified in the character block, all characters take -up the same number of bytes. - -Bytes are organized as N strings, where each string is one scan line of the -character. - -For example, each character in a 5x7 font requires 7 bytes. A 9x14 font -uses 28 bytes per character (stored two bytes per scan line in 14 sets of -2 byte packets). Custom fonts may be any size up to the current maximum of -10K bytes allowed for a font file. There is a maximum of 4 bytes per scan -line. - - Sample "C" Routines - -The following is a simple set of C subroutines to read data from a .PCX file. - -/* This procedure reads one encoded block from the image file and stores a -count and data byte. - -Return result: 0 = valid data stored, EOF = out of data in file */ - -encget(pbyt, pcnt, fid) -int *pbyt; /* where to place data */ -int *pcnt; /* where to place count */ -FILE *fid; /* image file handle */ -{ -int i; - *pcnt = 1; /* assume a "run" length of one */ - if (EOF == (i = getc(fid))) - return (EOF); - if (0xC0 == (0xC0 & i)) - { - *pcnt = 0x3F & i; - if (EOF == (i = getc(fid))) - return (EOF); - } - *pbyt = i; - return (0); -} -/* Here's a program fragment using encget. This reads an entire file and -stores it in a (large) buffer, pointed to by the variable "bufr". "fp" is -the file pointer for the image */ - -int i; -long l, lsize; - lsize = (long )hdr.BytesPerLine * hdr.Nplanes * (1 + hdr.Ymax - hdr.Ymin); - for (l = 0; l < lsize; ) /* increment by cnt below */ - { - if (EOF == encget(&chr, &cnt, fp)) - break; - for (i = 0; i < cnt; i++) - *bufr++ = chr; - l += cnt; - } - -The following is a set of C subroutines to write data to a .PCX file. - -/* Subroutine for writing an encoded byte pair (or single byte if it -doesn't encode) to a file. It returns the count of bytes written, 0 if error */ - -encput(byt, cnt, fid) -unsigned char byt, cnt; -FILE *fid; -{ - if (cnt) { - if ((cnt == 1) && (0xC0 != (0xC0 & byt))) - { - if (EOF == putc((int )byt, fid)) - return(0); /* disk write error (probably full) */ - return(1); - } - else - { - if (EOF == putc((int )0xC0 | cnt, fid)) - return (0); /* disk write error */ - if (EOF == putc((int )byt, fid)) - return (0); /* disk write error */ - return (2); - } - } - return (0); -} - - /* This subroutine encodes one scanline and writes it to a file. -It returns number of bytes written into outBuff, 0 if failed. */ - -encLine(inBuff, inLen, fp) -unsigned char *inBuff; /* pointer to scanline data */ -int inLen; /* length of raw scanline in bytes */ -FILE *fp; /* file to be written to */ -{ -unsigned char this, last; -int srcIndex, i; -register int total; -register unsigned char runCount; /* max single runlength is 63 */ - total = 0; - runCount = 1; - last = *(inBuff); - -/* Find the pixel dimensions of the image by calculating -[XSIZE = Xmax - Xmin + 1] and [YSIZE = Ymax - Ymin + 1]. -Then calculate how many bytes are in a "run" */ - - for (srcIndex = 1; srcIndex < inLen; srcIndex++) - { - this = *(++inBuff); - if (this == last) /* There is a "run" in the data, encode it */ - { - runCount++; - if (runCount == 63) - { - if (! (i = encput(last, runCount, fp))) - return (0); - total += i; - runCount = 0; - } - } - else /* No "run" - this != last */ - { - if (runCount) - { - if (! (i = encput(last, runCount, fp))) - return(0); - total += i; - } - last = this; - runCount = 1; - } - } /* endloop */ - if (runCount) /* finish up */ - { - if (! (i = encput(last, runCount, fp))) - return (0); - return (total + i); - } - return (total); -} - - FRIEZE Technical Information - -General FRIEZE Information - -FRIEZE is a memory-resident utility that allows you to capture and save -graphic images from other programs. You can then bring these images into -PC Paintbrush for editing and enhancement. - -FRIEZE 7.10 and later can be removed from memory (this can return you up -to 90K of DOS RAM, depending on your configuration). To remove FRIEZE from -memory, change directories to your paintbrush directory and type the word -"FRIEZE". - -7.00 and Later FRIEZE - -The FRIEZE command line format is: - -FRIEZE {PD} {Xn[aarr]} {flags} {video} {hres} {vres} {vnum} -Where: -{PD} Printer driver filename (without the .PDV extension) -{Xn[aarr]} - X=S for Serial Printer, P for Parallel Printer, D for disk file. - (file is always named FRIEZE.PRN) - n = port number - aa = Two digit hex code for which return bits cause - an abort (optional) - rr = Two digit hex code for which return bits cause - a retry (optional) - NOTE: These codes represent return values from serial or - parallel port BIOS calls. For values see and IBM - BIOS reference (such as Ray Duncan's Advanced MS-DOS - Programming). -{flags}Four digit hex code - First Digit controls Length Flag - Second Digit controls Width Flag - Third Digit controls Mode Flag - Fourth Digit controls BIOS Flag - 0 - None - 1 - Dual Monitor Present - 2 - Use internal (true) B/W palette for dithering - 2 color images - 4 - Capture palette along with screen IN VGA ONLY - Frieze 8.08 & up ONLY) - -NOTE: The length, width and mode flags are printer driver specific. -See PRINTERS.DAT on disk 1 (or Setup Disk) for correct use. In general -width flag of 1 means wide carriage, and 0 means standard width. Length -flag of 0 and mode flag of 0 means use default printer driver settings. - -If you need to use more than one BIOS flag option, add the needed flag values -and use the sum as the flag value. - -{video} Video driver combination, where the leading digit signifies the - high level video driver and the rest signifies the low - level video driver - Example = 1EGA - uses DRIVE1 and EGA.DEV -{hres} Horizontal resolution of the desired graphics mode -{vres} Vertical resolution of the desired graphics mode -{vnum} Hardware specific parameter (usually number of color planes) - -Note: The last four parameters can be obtained from the CARDS.DAT file, -in your PC Paintbrush product directory. - - -FRIEZE Function Calls - -FRIEZE is operated using software interrupt number 10h (the video interrupt -call). - -To make a FRIEZE function call, load 75 (decimal) into the AH register and -the function number into the CL register, then either load AL with the -function argument or load ES and BX with a segment and offset which point -to the function argument. Do an int 10h. FRIEZE will return a result code -number in AX. All other registers are preserved. In general, a result -code of 0 means success and other values indicate errors. However, function -20 (get Frieze Version) behaves differently; see below. -No. Definition Arguments -0 Reserved -1 Load Window - ES:BX - string (filename to read from) -2 Save Window - ES:BX - string (filename to write to) -3 Reserved -4 Reserved -6 Reserved -7 Set Window Size - ES:BX - 4 element word vector of window settings: - Xmin, Ymin, Xmax, Ymax -8 Reserved -9 Set Patterns - ES:BX - 16 element vector of byte values - containing the screen-to-printer color correspondence -10 Get Patterns - ES:BX - room for 16 bytes as above -11 Set Mode -12,13,14 Reserved -15 Get Window - ES:BX - room for 4 words of the current window - settings -16 Set Print Options - ES:BX - character string of printer options. - Same format as for the FRIEZE command. -17, 18, 19 Reserved -20 Get FRIEZE Version. - AH gets the whole number portion and AL gets the - decimal portion of the version number. (eg. for - Freize vesion 7.41, AH will contain 7 and AL will - contain 41. If AH =0, you are calling a pre-7.0 - version of FRIEZE). -21 Set Parameters - ES:BX points to an 8 word table (16 bytes) of - parameter settings: TopMargin, LeftMargin, - HSize,VSize, Quality/Draft Mode, PrintHres, - PrintVres, Reserved. - Margins and sizes are specified in hundredths - of inches. - Q/D mode parameter values: - 0 - draft print mode - 1 - quality print mode - Print resolutions are specified in DPI. - Any parameter which should be left unchanged may - be filled with a (-1) (0FFFF hex). The reserved - settings should be filled with a (-1). -22 Get Parameters - ES:BX points to an 8 word table (16 bytes) where - parameter settings are held. -23 Get Printer Res - ES:BX points to a 12 word table (24 bytes) that - holds six printer resolution pairs. -24 Reserved (versions 8.00 & up) - -FRIEZE Error Codes - -When FRIEZE is called using interrupt 10 hex, it will return an error code -in the AX register. A value of zero shows that there was no error. A -nonzero result means there was an error. These error codes are explained -below. - - 0 No Error - 1 Printout was stopped by user with the ESC key - 2 Reserved - 3 File read error - 4 File write error - 5 File not found - 6 Invalid Header - not an image, wrong screen mode - 7 File close error - 8 Disk error - usually drive door open - 9 Printer error - printer is off or out of paper -10 Invalid command - CL was set to call a nonexistent FRIEZE function -11 Can't create file - write protect tab or disk is full -12 Wrong video mode - FRIEZE cannot capture text screens. - -Technical Reference Manual - -Including information for: -Publisher's Paintbrushr -PC Paintbrush IVTM -PC Paintbrush IV PlusTM -PC Paintbrush PlusTM -PC Paintbrushr -FRIEZETM Graphics -PaintbrushTM -Revision 5 - -ZSoft Corporation -450 Franklin Rd. Suite 100 -Marietta, GA 30067 -(404) 428-0008 -(404) 427-1150 Fax -(404) 427-1045 BBS - -Copyright c 1985, 1987, 1988, 1990, 1991, ZSoft Corporation -All Rights Reserved - - - diff --git a/16/PCGPE10/PERSPECT.TXT b/16/PCGPE10/PERSPECT.TXT deleted file mode 100644 index cc58ad9b..00000000 --- a/16/PCGPE10/PERSPECT.TXT +++ /dev/null @@ -1,149 +0,0 @@ - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Perspective Transforms ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - By Andre Yew (andrey@gluttony.ugcs.caltech.edu) - - - - This is how I learned perspective transforms --- it was -intuitive and understandable to me, so perhaps it'll be to -others as well. It does require knowledge of matrix math -and homogeneous coordinates. IMO, if you want to write a -serious renderer, you need to know both. - - First, let's look at what we're trying to do: - S (screen) - | * P (y, z) - | /| - | / | - | / | - |/ | - * R | - / | | - / | | - / | | - E (eye)/ | | W ----------*-----|----*------------- - <- d -><-z-> - - E is the eye, P is the point we're trying to project, and -R is its projected position on the screen S (this is the point -you want to draw on your monitor). Z goes into the monitor (left- -handed coordinates), with X and Y being the width and height of the -screen. So let's find where R is: - - R = (xs, ys) - - Using similar triangles (ERS and EPW) - - xs/d = x/(z + d) - ys/d = y/(z + d) - (Use similar triangles to determine this) - - So, - - xs = x*d/(z + d) - ys = y*d/(z + d) - - Express this homogeneously: - - R = (xs, ys, zs, ws). - - Make xs = x*d - ys = y*d - zs = 0 (the screen is a flat plane) - ws = z + d - - and express this as a vector transformed by a matrix: - - [x y z 1][ d 0 0 0 ] - [ 0 d 0 0 ] = R - [ 0 0 0 1 ] - [ 0 0 0 d ] - - The matrix on the right side can be called a perspective transform. -But we aren't done yet. See the zero in the 3rd column, 3rd row of -the matrix? Make it a 1 so we retain the z value (perhaps for some -kind of Z-buffer). Also, this isn't exactly what we want since we'd -also like to have the eye at the origin and we'd like to specify some -kind of field-of-view. So, let's translate the matrix (we'll call -it M) by -d to move the eye to the origin: - - [ 1 0 0 0 ][ d 0 0 0 ] - [ 0 1 0 0 ][ 0 d 0 0 ] - [ 0 0 1 0 ][ 0 0 1 1 ] <--- Remember, we put a 1 in (3,3) to - [ 0 0 -d 1 ][ 0 0 0 d ] retain the z part of the vector. - - And we get: - - [ d 0 0 0 ] - [ 0 d 0 0 ] - [ 0 0 1 1 ] - [ 0 0 -d 0 ] - - Now parametrize d by the angle PEW, which is half the field-of-view -(FOV/2). So we now want to pick a d such that ys = 1 always and we get -a nice relationship: - - d = cot( FOV/2 ) - - Or, to put it another way, using this formula, ys = 1 always. - - Replace all the d's in the last perspective matrix and multiply -through by sin's: - - [ cos 0 0 0 ] - [ 0 cos 0 0 ] - [ 0 0 sin sin ] - [ 0 0 -cos 0 ] - - With all the trig functions taking FOV/2 as their arguments. -Let's refine this a little further and add near and far Z-clipping -planes. Look at the lower right 2x2 matrix: - - [ sin sin ] - [-cos 0 ] - - and replace the first column by a and b: - - [ a sin ] - [ b 0 ] - [ b 0 ] - - Transform out near and far boundaries represented homogeneously -as (zn, 1), (zf, 1), respectively and we get: - - (zn*a + b, zn*sin) and (zf*a + b, zf*sin). - - We want the transformed boundaries to map to 0 and 1, respectively, -so divide out the homogeneous parts to get normal coordinates and equate: - - (zn*a + b)/(zn*sin) = 0 (near plane) - (zf*a + b)/(zf*sin) = 1 (far plane) - - Now solve for a and b and we get: - - a = (zf*sin)/(zf - zn) - = sin/(1 - zn/zf) - b = -a*zn - b = -a*zn - - At last we have the familiar looking perspective transform matrix: - - [ cos( FOV/2 ) 0 0 0 ] - [ 0 cos( FOV/2 ) 0 0 ] - [ 0 0 sin( FOV/2 )/(1 - zn/zf) sin( FOV/2 ) ] - [ 0 0 -a*zn 0 ] - - There are some pretty neat properties of the matrix. Perhaps -the most interesting is how it transforms objects that go through -the camera plane, and how coupled with a clipper set up the right -way, it does everything correctly. What's interesting about this -is how it warps space into something called Moebius space, which -is kind of like a fortune-cookie except the folds pass through -each other to connect the lower folds --- you really have to see -it to understand it. Try feeding it some vectors that go off to -infinity in various directions (ws = 0) and see where they come -out. diff --git a/16/PCGPE10/PIT.TXT b/16/PCGPE10/PIT.TXT deleted file mode 100644 index a3127a15..00000000 --- a/16/PCGPE10/PIT.TXT +++ /dev/null @@ -1,297 +0,0 @@ - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Programming the Intel 8253 Programmable Interval Timer ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - Written for the PC-GPE by Mark Feldman - e-mail address : u914097@student.canberra.edu.au - myndale@cairo.anu.edu.au - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ THIS FILE MAY NOT BE DISTRIBUTED ³ - ³ SEPARATE TO THE ENTIRE PC-GPE COLLECTION. ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Disclaimer ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ - -I assume no responsibility whatsoever for any effect that this file, the -information contained therein or the use thereof has on you, your sanity, -computer, spouse, children, pets or anything else related to you or your -existance. No warranty is provided nor implied with this information. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Introduction ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The PIT chip has 3 channels, each of which are responsible for a different -task on the PC: - -Channel 0 is responsible for updating the system clock. It is usually -programmed to generate around 18.2 clock ticks a second. An interrupt 8 is -generated for every clock tick. - -Channel 1 controls DMA memory refreshing. DRAM is cheap, but it's memory -cells must be periodically refreshed or they quickly lose their charge. The -PIT chip is responsible for sending signals to the DMA chip to refresh -memory. Most machines are refreshed at a higher rate than neccesary, and -reprogramming channel 1 to refresh memory at a slower rate can sometime speed -up system performance. I got a 2.5 MHz speed-up when I did it to my 286, but -it didn't seem to work on my 486SUX33. - -Channel 2 is connected to the speaker. It's normally programmed to generate -a square wave so a continuous tone is heard. Reprogramming it for "Interrupt -on Terminal Count" mode is a nifty trick which can be used to play 8-bit -samples from the PC speaker. - -Each channel has a counter which counts down. The PIT input frequency is -1193181 ($1234DD) Hz. Each counter decrements once for every input clock -cycle. "Terminal Count", mentioned several times below, is when the counter -reaches 0. - -Loading the counters with 0 has the same effect as loading them with 10000h, -and is the highest count possible (approx 18.2 Hz). - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ The PIT Ports ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The PIT chip is hooked up to the Intel CPU through the following ports: - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Port Description ³ - ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ - ³ 40h Channel 0 counter (read/write) ³ - ³ 41h Channel 1 counter (read/write) ³ - ³ 42h Channel 2 counter (read/write) ³ - ³ 43h Control Word (write only) ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ The Control Word ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - ÚÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄ¿ - ³ 7 ³ 6 ³ 5 ³ 4 ³ 3 ³ 2 ³ 1 ³ 0 ³ - ÀÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÙ - ÀÄÂÄÙ ÀÄÂÄÙ ÀÄÄÄÂÄÄÄÙ ÀÄÄ BCD 0 - Binary 16 bit - ³ ³ ³ 1 - BCD 4 decades -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄ¿ ³ ³ -³ Select Counter ³ ³ ÀÄÄÄÄÄÄÄÄÄÄ Mode Number 0 - 5 -³ 0 - Select Counter 0 ³ ³ -³ 1 - Select Counter 1 ³ ³ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ -³ 2 - Select Counter 2 ³ ³ ³ Read/Load ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³ ³ 0 - Counter Latching ³ - ÀÄÄÄÄÄÄÄÄÄ´ 1 - Read/Load LSB only ³ - ³ 2 - Read/Load MSB only ³ - ³ 3 - Read/Load LSB then MSB ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ The PIT Modes ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The PIT is capable of operating in 6 different modes: - -MODE 0 - Interrupt on Terminal Count -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -When this mode is set the output will be low. Loading the count register -with a value will cause the output to remain low and the counter will start -counting down. When the counter reaches 0 the output will go high and remain -high until the counter is reprogrammed. The counter will continue to count -down after terminal count is reached. Writing a value to the count register -during counting will stop the counter, writing a second byte starts the -new count. - -MODE 1 - Programmable One-Shot -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -The output will go low once the counter has been loaded, and will go high -once terminal count has been reached. Once terminal count has been reached -it can be triggered again. - -MODE 2 - Rate Generator -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -A standard divide-by-N counter. The output will be low for one period of the -input clock then it will remain high for the time in the counter. This cycle -will keep repeating. - -MODE 3 - Square Wave Rate Generator -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -Similar to mode 2, except the ouput will remain high until one half of the -count has been completed and then low for the other half. - -MODE 4 - Software Triggered Strobe -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -After the mode is set the output will be high. Once the count is loaded it -will start counting, and will go low once terminal count is reached. - -MODE 5 - Hardware Triggered Strobe -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -Hardware triggered strobe. Similar to mode 5, but it waits for a hardware -trigger signal before starting to count. - -Modes 1 and 5 require the PIT gate pin to go high in order to start -counting. I'm not sure if this has been implemented in the PC. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Counter Latching ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Setting the Read/Load field in the Control Word to 0 (Counter Latch) causes -the appropriate channel to go into a sort of "lap" mode, the counter keeps -counting down internally but it appears to have stopped if you read it's -values through the channel's counter port. In this way you get a stable count -value when you read the counter. Once you send a counter latch command you -*must* then read the counter. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Doing Something Useful ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Ok, so let's say we are writing a game and we need to have a certain -routine called 100 times a second and we want to use channel 0 to do all -this timing in the background while the main program is busy doing other -stuff. - -The first thing we have to realise is that BIOS usually uses channel 0 to -keep track of the time, so we have 3 options: - -1) Have our own routine handle all timer interrupts. This will effectively - stop the PC clock and the system time will be wrong from that point on. - The clock will be reset to the proper time the next time the computer - is turned off and on again, but it's not a nice thing to do to someone - unless you really have to. - -2) Have our routine do whatever it has to do and then call the BIOS handler. - This would be fine if our program was receiving the usual 18.2 ticks - a second, but we need 100 a second and calling the BIOS handler for every - tick will speed up the system time. Same net result as case 1. - -3) Have our routine do the interrupt handling and call the BIOS handler only - when it needs to be updated! BINGO! - -The PIT chip runs at a freqency of 1234DDh Hz, and normally the BIOS timer -interrupt handler is called for every 10000h cycles of this clock. First we -need to reprogram channel 0 to generate an interrupt 100 times a second, ie -every 1234DDh / 100 = 11931 cycles. The best thing to do is keep a running -total of the number of clock ticks which have occurred. For every interrupt -generated we will add 11931 to this total. When it reaches 10000h our handler -will know it's time to tell BIOS about it and do so. - -So let's get into some good old Pascal code. First we'll define a few -constants and variables our program will need: - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ -Uses Crt, Dos; - -{$F+} { Force far mode, a good idea when mucking around with interrupts } - -const TIMERINTR = 8; - PIT_FREQ = $1234DD; - -var BIOSTimerHandler : procedure; - clock_ticks, counter : longint; -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The clock_ticks variable will keep track of how many cycles the PIT has -had, it'll be intialised to 0. The counter variable will hold the new -channel 0 counter value. We'll also be adding this number to clock_ticks -every time our handler is called. - -Next we need to do some initialization: - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ -procedure SetTimer(TimerHandler : pointer; frequency : word); -begin - - { Do some initialization } - clock_ticks := 0; - counter := $1234DD div frequency; - - { Store the current BIOS handler and set up our own } - GetIntVec(TIMERINTR, @BIOSTimerHandler); - SetIntVec(TIMERINTR, TimerHandler); - - { Set the PIT channel 0 frequency } - Port[$43] := $34; - Port[$40] := counter mod 256; - Port[$40] := counter div 256; -end; -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Pretty straightforward stuff. We save the address of the BIOS handler, -install our own, set up the variables we'll use and program PIT channel 0 -for the divide-by-N mode at the frequency we need. - -This next bit is what we need to do once our program is finished. It just -resets everything back to normal. - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ -procedure CleanUpTimer; -begin - { Restore the normal clock frequency } - Port[$43] := $34; - Port[$40] := 0; - Port[$40] := 0; - - { Restore the normal ticker handler } - SetIntVec(TIMERINTR, @BIOSTimerHandler); -end; -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -Ok, here's our actual handler. This particular handler just writes an -asterix (*) to the screen. Then it does the checks to see if the BIOS -handler should be called. If so it calls it, if not it acknowledges the -interrupt itself. - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - -procedure Handler; Interrupt; -begin - - { DO WHATEVER WE WANT TO DO IN HERE } - Write('*'); - - { Adjust the count of clock ticks } - clock_ticks := clock_ticks + counter; - - { Is it time for the BIOS handler to do it's thang? } - if clock_ticks >= $10000 then - begin - - { Yep! So adjust the count and call the BIOS handler } - clock_ticks := clock_ticks - $10000; - - asm pushf end; - BIOSTimerHandler; - end - - { If not then just acknowledge the interrupt } - else - Port[$20] := $20; -end; - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -And finally our calling program. What follows is just an example program -which sets everything up, waits for us to press a key and then cleans up -after itself. - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ -begin - SetTimer(Addr(Handler), 100); - ReadKey; - CleanUpTimer; -end. -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ References ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Title : "Peripheral Components" -Publisher : Intel Corporation -ISBN : 1-55512-127-6 diff --git a/16/PCGPE10/README.TXT b/16/PCGPE10/README.TXT deleted file mode 100644 index 8eddc503..00000000 --- a/16/PCGPE10/README.TXT +++ /dev/null @@ -1,293 +0,0 @@ - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ The PC GAMES PROGRAMMERS ENCYCLOPEDIA 1.0 ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Introduction ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Well, here it is! This is the first edition of the PC Games Programmers -Encyclopedia. The PC-GPE as it currently stands is a collection of text -files, each covering a different aspect of programming games for the PC. -Some files were obtained from the net, others were grabbed off Usenet, quite -a few were written for the PC-GPE. - -Every effort has been made to contact the original authors of all public -domain articles obtained via ftp. In some cases the original authors were -not able to be contacted. Seeing as these files were already available to the -public the liberty was taken to include them anyway. The files were not -modified in any way. There is a list at the end of this document showing -which files we couldn't contact the authors about. Please note that files -were *not* written exclusively for the PC-GPE unless stated otherwise. - -The information in the PC-GPE is provided to you free of charge. The authors -of each article have included their own conditions of use, eg some ask that -you give them credit if you use their source code. As a general rule of -thumb, an e-mail or postcard to an author telling them you found their file -helpful probably wouldn't go astray..... - -This first version of the PC-GPE is very hardware oriented. We hope to -include more actual game algorithms in future releases. If you would like to -see a particular topic included in the next PC-GPE release or if you think -you could contribute an article then by all means let us know (btw plugs for -personal projects in articles are accepted). The editor's e-mail address is -at the end of this file. - -Some of the text files are pretty long, so the PCGPE uses a protected mode -file viewer (PCGPE.EXE) which may play up when run on 286 machines. If this -happens read the DPMIUSER.DOC file for help on fixing the problem. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ PC-GPE Home Site ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The Games Programmers Encyclopedia official home site is: - -teeri.oulu.fi -/pub/msdos/programming/gpe - -There are plans to develop GPE's for the mac and other architectures for -cross-platform game development. The teeri site will also hold PC-GPE -updates/bug fixes/etc. - -Many thanks to Jouni Miettunen for all his help and for allowing us to use -teeri as the PC-GPE's home site. He's put a lot of work into it and it's a -great programming resource, particularly for people wanting to develop game -software. - - -ÚÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ History ³ -ÀÄÄÄÄÄÄÄÄÄÙ - -The PC-GPE was conceived, designed and largely built by the same people who -keep the Usenet groups rec.games.programmer and comp.graphics.algorithms -alive. It was noticed that information required for even the most basic game -development was strewn out across the vast wastelands of the Internet and was -time consuming and annoying (if not down-right impossible) to obtain. - -Most of us can't afford to go out and buy a book every time we want to look -up a particlar topic, so a bunch of us decided to grab the most commonly -sought-after free info and put it in one place. - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ The People Who Did All the Work ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -First a big thanks goes to everyone who wrote articles or allowed us to use -their existing articles. - -Also thanks to the Demo groups Asphixia and VLA (more specifically Lithium -and Denthor) for letting us use the asm and vga trainers they wrote. - -A number of people who didn't actually write articles contributed heaps -to the project right from the start with tips/comments/suggestions etc as -well as lots of info on where we could get stuff. Thanks go to Bri, Dizzy, -Claus Anderson, Nathan Clegg, Alex Curylo, Cameron Grant, Chris Matrakidis -and the many others who sent info. If it wasn't for them you probably -wouldn't be reading this now! - -And finally thanks to Jouni Miettunen for setting up the PC-GPE directory on -the teeri site, letting us use it as the official home site and supplying -a heap of information. - -The editor would also like to thank the scores of other people who e-mailed -him with suggestions, comments, requests etc...and continually hassled him to -hurry up and get the damn thing finished. - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Disclaimer ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ - -It's a pity we live in a world where the following kind of crap is -neccessary. Oh well, here goes.... - -Each article appearing in the PC-GPE is bound by any disclaimer that appears -within it. The editor assumes absolutely no responsibility whatsoever for -any effect that this file viewer or any of the PC-GPE articles have on you, -your sanity, computer, spouse, children, pets or anything else related to -you or your existance. No warranty is provided nor implied with this -information. The accuracy of the information contained is subject to -conjecture. Use all information at your own risk. The file PC-GPE.EXE may -not be distributed without all the original unmodified PC-GPE articles. The -distribution rights of individual articles is at the discretion of the -authors. - - -ÚÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ File List ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÙ - -The following is a list of all the PCGPE 1.0 files: - -File Description -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - -PCGPE EXE * PC-GPE main exe file -DPMIUSER DOC * PC-GPE.EXE DPMI info file -RTM EXE * PC-GPE.EXE DPMI support file -RTMRES EXE * PC-GPE.EXE DPMI support file -DPMIINST EXE * PC-GPE.EXE DPMI support file -DPMILOAD EXE * PC-GPE.EXE DPMI support file -DPMI16BI OVL * PC-GPE.EXE DPMI support file - -README TXT * PC-GPE main info doc -FTPSITES TXT List of FTP sites for game development programs/utils - -ASMINTRO TXT * VLA's assembly tutorial intro file -ASM0 TXT * VLA's assembly tutorial -ASM1 TXT * VLA's assembly tutorial -ASM2 TXT * VLA's assembly tutorial -ASM3 TXT * VLA's assembly tutorial -ANSI TXT * VLA's assembly tutorial support file - -INTEL DOC List of op codes plus timing info up to 486 -CPUTYPE TXT * Testing CPU type -TIMER ASM * Testing CPU speed - -TUT1 TXT * Asphixia's VGA Primer - Mode 13h -TUT2 TXT * Asphixia's VGA Primer - Palette/Fading -TUT3 TXT * Asphixia's VGA Primer - Lines/Circles -TUT4 TXT * Asphixia's VGA Primer - Virtual Screens -TUT5 TXT * Asphixia's VGA Primer - Scrolling -TUT6 TXT * Asphixia's VGA Primer - Look-up Tables -TUT7 TXT * Asphixia's VGA Primer - Animation -TUT8 TXT * Asphixia's VGA Primer - 3D/Optimisation -TUT9 TXT * Asphixia's VGA Primer - 3D Solids -TUT10 TXT * Asphixia's VGA Primer - Chain 4 mode -COPPER PAS * Asphixia's VGA Primer - Copper Effect -WORMIE PAS * Asphixia's VGA Primer - Worm Effect -PALLETTE COL * Asphixia's VGA Primer support file -SOFTROCK FNT * Asphixia's VGA Primer support file - -MODEX TXT * Introduction to mode x -SCROLL TXT * VGA scrolling -VGAREGS TXT * VGA palette and register set -VGABIOS TXT VGA BIOS function call list - -SVGINTRO TXT * SVGA - Intro to programming SVGA cards -VESASP12 TXT SVGA - The VESA standard -ATI TXT * SVGA - Programming the ATI chip set -CAT TXT * SVGA - Programming the Chips & Technologies chip set -GENOA TXT * SVGA - Programming the Genoa chip set -PARADISE TXT * SVGA - Programming the Paradise chip set -TRIDENT TXT * SVGA - Programming the Trident chip set -TSENG TXT * SVGA - Programming the Tseng chip set -VIDEO7 TXT * SVGA - Programming the Video7 chip set -XTENDED TXT * SVGA - 640x400x256 with no bank switching - -3DROTATE DOC * VLA's three dimensional rotations for computer graphics -3DSHADE DOC * VLA's three dimensional shading in computer graphics -PERSPECT TXT * Perspective transforms -BRES TXT * Bresenham's line and circle algorithms -CONIC CC * A bresenham-like general conic sections algorithm -BSP TXT * A Simple Explanation of BSP Trees -TEXTURE TXT * Texture mapping -FDTM TXT * Real-time free direction texture mapping - -STARS TXT * VLA's programming star fields -FIRE TXT * Programming fire effects - -PCX TXT PCX graphics file format -BMP TXT BMP graphics file format -GIF TXT GIF graphics file format -IFF DOC IFF/LBM graphics file format -FLI FOR FLI/FLC graphics file format - -SPEAKER TXT * Programming the PC speaker (inc 8-bit sample playback) -GAMEBLST TXT * Programming the GameBlaster sound card -ADLIB TXT Programming the Adlib sound card -SBDSP TXT * Programming the SoundBlaster sound card (DSP) -SBPRO TXT * Programming the SoundBlaster Pro sound card -GUSFAQ TXT * The GUS sound card's Frequently Asked Questions -GUS TXT * Programming the GUS sound card - -MODFORM TXT * The MOD sound file format -VOC TXT The VOC sound file format -WAV TXT * The WAV sound file format -CMF TXT * The CMF sound file format -MIDI TXT * The MID sound file format -UT TXT The UltraTracker sound file format - -SURROUND TXT Generating surround sound - -MOUSE TXT * Programming the mouse, general info -GMOUSE DOC Mouse driver function call list -KEYBOARD TXT * Programming for the PC keyboard -JOYSTICK TXT * Programming for the PC joystick -GAMEPAD TXT * Programming for the Gravis GamePad and Analog Pro - -LIMEMS41 DOC EMS (Expanded Memory Specification) -XMS30 TXT XMS (Extended Memory Specification) -DMA_VLA TXT * Intro to DMA - -PIT TXT * Programming the Intel 8253 Programmable Interval Timer -DOOM TXT * DOOM techniques - - -An asterix (*) indicates files which were either written for the PC-GPE or -included with permission from the author. - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Final Words from the Editor ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Greetz -ÄÄÄÄÄÄ - - Zob: Whaddaya mean you can't come out drinking with us for 6 months? What - the hell is "glandular fever" anyway? - -Wookie: Whaddaya mean I can't play ModemDOOM on a 2400? - - Fink: Live fast, die young, have a good lookin' corpse! - -MainFrame, bri_acid, wReam, Nocturnus, MArtist, RetroSpec, Matrix, Syntax, -Andrez, Gideon and the rest of the #coders gang : try and get some sleep - some time guys! - - Eyre: You/me babe, how 'bout it? - - Aggi: Remember, reality is mass hallucination resulting from alcohol - deficiency! - -Fetish: You know the routine hon, pick a number and join the queue like - the rest of 'em! - - -Why all my code is in Pascal -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - -Ok, ok, I'm expecting to get lots of crap over this one. To put it simply -Pascal is close to psuedo code and I wanted the routines to be understood -by everyone, Pascal programmers, C programmers and *REAL* (to wit, asm) -programmers alike. Apart from that I'm running a 40Mg doublespaced hard -drive and I have to use the fastest compiler possible. That's a good enough -reason isn't it?....people?..... - - -Shameless Plug -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - -There are two things in life I really can't stand, - -1) My ex-girlfriend -2) Being unemployed, which I am now! - -So if your company has any openings I'd really like to hear from you, -particularly if you develop game software. - -I'm a 3rd year computer engineering student and my specialties lie in -computer graphics and low-level PC hardware programming. I program in C++ -(Dos and Windows), Pascal, 80x86 assembly, QBasic (heh heh) and Prolog. - - -Mark Feldman -Internet: u914097@student.canberra.edu.au - myndale@cairo.anu.edu.au - diff --git a/16/PCGPE10/RTM.EXE b/16/PCGPE10/RTM.EXE deleted file mode 100644 index 2d11def4de88940cd561b5a23d7cdc5f9d6247a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 85998 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 diff --git a/16/PCGPE10/RTMRES.EXE b/16/PCGPE10/RTMRES.EXE deleted file mode 100644 index 12e8ffe9b44e0fbab2dbc3fc076cb173a0711dd1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7936 zcmeG>4N#L;w&(lFmk=Sct@2z~!$%uaE0h9hQw5|b60{YeB0pAZjSw_jNZ8~HYF|az z%uX9VVB6`w?oM~#?sMtuyoa=pt+W$hDqv7Rq)Tn5Qgyqoww;g0c6ZT=736#8ehG?p z+xIi`X1X))%W%)V=bU@ax#ymH@41)U$1^|!6z~8b%K!risfZ}ZMEGBQ89D$OdH?_W z`}IJwxnNV_>c3z6Z@2uhjYY-cUpAGb^$99J1wlqq!IRq_-#j#s08sFlo-1w`Xd3N& znexNR;W#&kJYx}*INDfrHYT=X5wt&ySZ#a8a2%oh8QN&mpy_1$>e<*2!DqSZE4oIw zM9bNgxsMBqoL&$uAB!Ws=h)uQB7K(keMKLLH6MwVb6yz)YAvBe^nRvh`n@M1-tztr ziazjJrhG-yqUEYsbS;EY%>|?uh^Kocl*0C2h@2DHk|~b1uSE-#5pDHZMtzpklw~|T zl7^9{p2lsXe&*2`mKCC9N-UcGCRt6E(e_8s^kba7?JwRwdL@9s<+raJjw^Xm9lLqU zVBmJIes|jQ!lo1mo*lf+<#M|Cr37`aVNHJSx?3^poz^m&>sB1VBlM5xU(;{Xf1*{4 zkx6GBW6BvX^Agj+oMEmrQEVLh09(j9S-ZpSDKEE|+HDSjue4PX*RA+bC1-rGv z{O#hy7_=8NbWwD%)*!*%B0PB4*u&f=##b*c{b%m(x*6 zOsulHtd%yw=5iyCbw`Db7o0bZwIO{cq6ool*kLW>SEVHJ&hqk`{cd6%w;|oT?Lz6U zS;$*_W7{Lx9A#*6$Q6cCtAjY8)Mc{@Hr}!^d(&;G3cJH*b@A4+G8c}UcUM_UZMU(w z_qqjJB_HOzmBU%Jmw(FUa@Z=!2zS|c?wZl;K{Luxcv)!9XZfL&bXt>FP;xtN-5TQ3 z8Fz(kwxc^scUkR@kiWjpke|!D1#9V3vnV&h!p6IITdS(TpMQ>Ou!h?2t1f16ymxNnxTZOGu zaAItP5jQ%8Bf{>e#+WYS%l0~~mG)BN`KJt}PESRd;~tb(WpnW5_6i#+3-Q_Z*vM+A zvTMK(;bF2>(}3mLuJu~EluF=<1+ELo=fUY*t*DDa*~od>k(ZQ5o^I zZBG@t4dV$zCu}tFg0jHNofvL7BUM&m*DVNZDOt{ZnayFh5eBjtY!0XAMx2tct-!sB zzv<1J>-YvvQDlhH8ak{RZ|~gRF}9(nVJLo-`Opuzd%Kx2D>cELrzjBaIB<@7UMJCC zk)2#68K__>q0k^K;TlGpdb%uB=O#Sy$N|BOnXr~S9Jdk}RM`caGA4M=y?d$nsQcxlnIq{))jOwDn51GSpfu!UV(*qBhA6mX*)#|J@*_M)$l6-N}+s~NJbg&?fdN0gP ztpCl=)z2-?!-Mbq7t*V8Ng%&dqPi|q())7fA6V&U@|J?S3o^WWLHv2EO8SYsWu|pe z<-G=ItxN74;iL)~J4Vu73u)<>O2;iXIU89iS7FK_OxLI`j+UwwCbPmcmk8%+X{o|= zmmKi3ytG>$yHi$0^O8dz(_)JJfB)sL+O!tuVdirQm5I3CpscFWo^0M>PjpsSglUFl z1h;rvnxMw^U-#-T%A}XUrS5*2lHR4R1_*|h_7Kb_O6o?8 zl5uJJIaC0_g#^+d-2vsMo?rxNQQ+<4q`M)&`QgDR4u<0zxX(2{eNdzJ!xBVv{wzYT ziye-O4TRcaOi-h5(toZYD9-7T~~fP4fwj^h~jABdzG#!b*ViZ}j>KIG#OACHJ^E(>#4YG(W)YUoEmaE*+y<0<2*_?$PXx8?x7v?%EJOF}oz2H2;?$1%EjpLGrK78jbr2u9${fMQG{6?Ulcmx_~gVSp3lOJ!iBkqz%MPmmrq`?B8A_v zmtXC4Rao)tSQk2zNrq^x&_=OjMXR&&atrdavzYs{c#2$8$nR?;R=v{KiEQRK?O#5j_vrO+_-`qw8S($628V^qs zs|fFH{gHx0kj-r&^F!3xG7q#-D9h6kG<5GprP8A5Z!=vP#!WpTaj%emA738~M@FG| zQ9pIGnrp2eO_7<8`f7AJMHnsG*7|{z&o8}_($kXXhpeMTI=m;wZgX)Hy$kT{C2VPz zgvF+wR$Q3smilvPmpqqir&5I@wNqP#x7)V11pQ(^vc>nWZHavXcOX>cy~r!N8f(tQ zs9V!xtLe7bUx)*l;>ZPEYr56Nr9Zu!PT*V4kGHLCiN!5)DKzO5z;uOd0^h@4;&I$O zG#gsAJ)X(nXX3P8ozl|*)cEUH-tDW=*7vqtdL>r;KSO zmd2X%zM88ImTP|M-r=~$nv=eosRo>0rB(Ff#%<$D8sef&J)N@Lbo!cz1~j1olg)2X z!~^Y^nhbUOnZq4S$9#Bx>aoPv>d&^*!^zLie>RuS98TWs?Pt%A4bi~TbR-?c{(y~x zyTO3Bwg*`=`w+XFUBRZZX>2;XlFeWrW<866!EJ|zI)#<{>m9_6|07I4jF9vTgxezs3IBLl&vdvQMN@Dc?YILWvG*>Th9BYIGvUqm zf4mFQp&rUym_BddmVz%M8pJ*o3+8@K3(;V1j>JD5o`mdh^7PV@rlJK#xpG#57 z2b9vRl*_Rslee0_b@F`keYrGF+~)Ha8wON3@jVAlFveyY4!nba1wTU{g3dguVQ@Iv zpEcP9n2FX+W=#qU2qm(!Fhs$6ROgmZT}2;?>-?=!KXmuu0ZK}PLx#hnlw<uF%-4sODb5#jky#mAa46qD06}fO|2PEMeE%ru3*W}U{z1Ihd>1|rMK&9-)HNHS z-xB##s$qk!uI3J4-Ku^If+u22hWyAqdH{KK$f-BN*n2Sft3+8(!>-+J2?)ej=<}_Szu1EwraI<914PhXS4NP~MPKsys=Dz(J^U>Yxl&R;S zzwOjPe=Quu>cNAJ*}}mF#9dV%#P~s6hYl_s?8t*TCp{6ZsRPw){lEnco(BTca{ekF zR*~Z?nh6QL(s61E7nO%;Bg|Nke(6K6%EpQd}cKEXVYz`$l=ol zLAs3!i>up5qqGG^geVa25zAmF1Q+CY%>!vZl%VO6U5fy7{G0u`Vy@UIe}4{+3g`1l zbs*#-)_Alq(kSM#MsYED%ymVRQJ^vX*_chnqGGIR@sjezEPm6V@!4Dr>4BG3mpZ;z zVEi_P`5T$=03*T_HxgamNw%6JFT&(#3!SZE5jW=~-m%v~FsVIhI4+&R%b9CQ6K=A` zCJv8mdCHio64ZEe9)CS}8E?blgmO^7aAic##rD-`rdsfb#l(OH(@BYj7l%mS?pnM} zM5TP5V>)vo0&fQVZYJmagg6muR4a}C_+tW_^@!)Az?68l;q*-Cw6=s2mZsBaVTf{c zw-%|KS@c-#z4V?syP03(O8VueAj=5V7%a_h8C8bcQB zBv)&6(w=FOi$%^74>eo8H5#ZXs;kk+us^S^hLfR&sFc61QbSahkOUXAWksrJ(J&S+ zKcp=Kwf$pATL=-Ms3Xf?Z$7#ocVk}^UV}r+FRG1}RaiZAN}$`*YxgCA5YbqOf$MtQ zr}7W6xNVc&JH&jyxY!SChU2arsrBc1Cd=K+D4d!_ODryDhcrJtwBkV<(jqr7Z zk0N{%;bREjLg+#0!hSm_(vODc6{w;*Fc%~J-%%h9)tHA7`UpeARW%Lw;giP@OT$`( zyo!cx2q&?<4`HS%lxKY>%dgqS0w2x`ztvtEHhLU_z0wwX8s(FclE`B!f}~VZB;w=c Kw+i?U5dRa+rhXp) diff --git a/16/PCGPE10/SBDSP.TXT b/16/PCGPE10/SBDSP.TXT deleted file mode 100644 index eab187f7..00000000 --- a/16/PCGPE10/SBDSP.TXT +++ /dev/null @@ -1,442 +0,0 @@ - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Programming the SoundBlaster DSP ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - Written for the PC-GPE by Mark Feldman - e-mail address : u914097@student.canberra.edu.au - myndale@cairo.anu.edu.au - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ THIS FILE MAY NOT BE DISTRIBUTED ³ - ³ SEPARATE TO THE ENTIRE PC-GPE COLLECTION. ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Disclaimer ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ - -I assume no responsibility whatsoever for any effect that this file, the -information contained therein or the use thereof has on you, your sanity, -computer, spouse, children, pets or anything else related to you or your -existance. No warranty is provided nor implied with this information. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Introduction ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The SoundBlaster is capable of both FM and digitised sounds. The FM wave -is fully Adlib compatible, so check the ADLIB.TXT file for info -on how to program it. This file will concentrate on recording and playback -of digital samples through the SoundBlaster CT-DSP 1321 chip. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ The SoundBlaster DSP I/O Ports ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The DSP (Digital Sound Processor) chip is programmed through 4 ports which -are determined by the SoundBlaster base address jumper setting: - - RESET 2x6h - - READ DATA 2xAh - -WRITE COMMAND/DATA output -WRITE BUFFER STATUS input 2xCh - - - DATA AVAILABLE 2xEh - -where x = 1 for base address jumper setting 210h - x = 2 for base address jumper setting 220h - . - . - x = 6 for base address jumper setting 260h - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Resetting the DSP ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -You have to reset the DSP before you program it. This is done with the -following procedure : - -1) Write a 1 to the SoundBlaster RESET port (2x6h) -2) Wait for 3 micro-seconds -3) Write a 0 to the SoundBlaster RESET port (2x6h) -4) Read the byte from the DATA AVAILABLE (2xEh) port until bit 7 = 1 -5) Poll for a ready byte (AAh) from the READ DATA port (2xAh). Before - reading the READ DATA port it is avdvisable. - -The DSP usually takes somewhere around 100 micro-seconds to reset itself. -If it fails to do within a reasonable time (say 200 micro-seconds) then -an error has occurred, possibly an incorrect I/O address is being used. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Writing to the DSP ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -A value can be written to the DSP with the following procedure : - -1) Read the DSP's WRITE BUFFER STATUS port (2xCh) until bit 7 = 0 -2) Write the value to the WRITE COMMAND/DATA port (2xCh) - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Reading the DSP ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -A value can be read from the DSP with the following procedure : - -1) Read the DSP's DATA AVAILABLE port (2xEh) until bit 7 = 1 -2) Read the data from the READ DATA port (2xAh) - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Turning the speaker on and controlling DMA ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Speaker and DMA control are handled by writing one of the following bytes -to the DSP: - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Value Description ³ - ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ - ³ D0h DMA Stop ³ - ³ D1h Turn speaker on ³ - ³ D3h Turn speaker off ³ - ³ D4h DMA Continue ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -DMA is discussed below. The DMA commands shown here can be used to pause -the sample during DMA playback playback. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Writing to the DAC ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The DAC (Digital to Analog Converter) is the part of the card which converts -a sample number (ie 0 -> 255) to a sound level. To generate a square sound -wave at maximum volume (for example) you could alternate writing 0's and -255's to the DAC. - -Programming the DAC in direct mode involves the main program setting the -DAC to a desired value. Only 8 bit DAC is available in direct mode. To set -the DAC level you write the value 10h to the DSP followed by the sample -number (0 -> 255). Note that no sound will be heard unless the speaker has -been turned on. In direct mode the main program is responsible for the -timing between samples, the DAC can output sound samples as fast as the -calling program can change it. Typically the timer interrupt is reprogrammed -and used to generate the timing required for a sample playback. Info on -programming the PIT chip can be found in the PIT.TXT file. - -The DAC can also be programmed to accept values sent to it via the DMA -chip. Draeden has written an excellent article on programming the DMA chip -(see DMA_VLA.TXT) so only a brief example of it's use will be given here. -The important thing to remember is that the DMA chip cannot transfer data -which crosses between page breaks. If the data does cross page breaks then -it will have to be split up into several transfers, with one page per -transfer. - -Setting the playback frequency for the DMA transfer is done by writing -the value 40h to the DSP followed by TIME_CONSTANT, where -TIME_CONSTANT = 256 - 1000000 / frequency - -There are several types of DMA transfers available. The following table -lists them: - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³DMA_TYPE_VALUE Description Frequency Range ³ - ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ - ³ 14h 8 bit 4KHz -> 23 KHz ³ - ³ 74h 4 bit ADPCM 4KHz -> 12 KHz ³ - ³ 75h 4 bit ADPCM with 4KHz -> 12 KHz ³ - ³ reference byte ³ - ³ 76h 2.6 bit ADPCM 4KHz -> 13 KHz ³ - ³ 77h 2.6 bit ADPCM with 4KHz -> 13 KHz ³ - ³ reference byte ³ - ³ 16h 2 bit ADPCM 4KHz -> 11 KHz ³ - ³ 17h 2 bit ADPCM with 4KHz -> 11 KHz ³ - ³ reference byte ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -ADPCM stands for Adaptive Pulse Code Modulation, a sound compression -technique where the difference between successive samples is stored rather -than their actual values. In the modes with reference bytes, the first -byte is the actual starting value. Having modes with and without reference -bytes means you can output successive blocks without the need for a -reference byte at the start of each one. - -The procedure for doing a DMA transfer is as follows: - -1) Load the sound data into memory -2) Set up the DMA chip for the tranfer -3) Set the DSP TIME_CONSTANT to the sampling rate -4) Write DMA_TYPE_VALUE value to the DSP -5) Write DATA_LENGTH to the DSP (2 bytes, LSB first) where - DATA_LENGTH = number of bytes to send - 1 - -Note that the DMA chip must be programmed before the BSP. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Reading from the ADC ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Reading samples from the ADC (Analog to Digital Converter) can also be -done in either direct or DMA mode. - -To read a sample in direct mode write the value 20h to the DSP and then -read the value from the DSP. Simple as that! - -To set up the DSP for a DMA transfer, follow this procedure : - -1) Get a memory buffer ready to hold the sample -2) Set up the DMA chip for the transfer -3) Set the DSP TIME_CONSTANT to the sampling rate -4) Write the value 24h to the DSP -5) Write DATA_LENGTH to the DSP (2 bytes, LSB first) where - DATA_LENGTH = number of bytes to read - 1 - -Note that the DMA chip must be programmed before the BSP. - -DMA reads only support 8 bit mode, compressed modes are done by software and -stored in the voc file. I haven't tried to figure out how the compression is -done. If someone does figure it out I'd like to know about it! - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Programming the DMA Chip ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -As mentioned before, Draeden has written a very good article on the dma -chip, but here is a brief run down on what you would need to do to program -the DMA channel 1 for the DSP in real mode: - -1) Calculate the 20 bit address of the memory buffer you are using - where Base Address = Segment * 16 + Offset - eg 1234h:5678h = 179B8h -2) Send the value 05h to port 0Ah (mask off channel 1) -3) Send the value 00h to port 0Ch (clear the internal DMA flip/flop) -4) Send the value 49h to port 0Bh (for playback) or - 45h to port 0Bh (for recording) -5) Write the LSB (bits 0 -> 7) of the 20 bit memory address to port 02h -6) Write the MSB (bits 8 -> 15) of the 20 bit memory address to ort 02h -7) Write the Page (bits 16 -> 19) of the 20 bit memory address to port 83h -8) Send the LSB of DATA_LENGTH to port 03h -9) Send the MSB of DATA_LENGTH to port 03h -10) Send the value 01h to port 0Ah (enable channel 1) - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ End of DMA Interrupt ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -When a DMA transfer is complete an interrupt is generated. The actual -interrupt number depends on the SoundBlaster card's IRQ jumper setting: - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ IRQ Jumper ³ - ³ Setting Interrupt ³ - ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ - ³ 2 0Ah ³ - ³ 3 0Bh ³ - ³ 5 0Dh ³ - ³ 7 0Fh ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -To service one of these interrupts you must perform these 3 tasks: - -1) Acknowledge the DSP interrupt by reading the DATA AVAILABLE port (2xEh) - once. -2) If there are more blocks to transfer then set them up -3) Output value 20h (EOI) to the interrupt controller port 20h - -Of course, as with any hardware interrupt you must also leave the -state of the system (registers etc..) the way it was when the interrupt -was called. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ A Simple DSP Pascal Unit ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -{ - - DSP.PAS - A demo SoundBlaster DSP unit for real mode - - By Mark Feldman -} - -Unit DSP; - -Interface - -{ ResetDSP returns true if reset was successful - base should be 1 for base address 210h, 2 for 220h etc... } -function ResetDSP(base : word) : boolean; - -{ Write DAC sets the speaker output level } -procedure WriteDAC(level : byte); - -{ ReadDAC reads the microphone input level } -function ReadDAC : byte; - -{ SpeakerOn connects the DAC to the speaker } -function SpeakerOn: byte; - -{ SpeakerOff disconnects the DAC from the speaker, - but does not affect the DAC operation } -function SpeakerOff: byte; - -{ Functions to pause DMA playback } -procedure DMAStop; -procedure DMAContinue; - -{ Playback plays a sample of a given size back at a given frequency using - DMA channel 1. The sample must not cross a page boundry } -procedure Playback(sound : Pointer; size : word; frequency : word); - -Implementation - -Uses Crt; - -var DSP_RESET : word; - DSP_READ_DATA : word; - DSP_WRITE_DATA : word; - DSP_WRITE_STATUS : word; - DSP_DATA_AVAIL : word; - -function ResetDSP(base : word) : boolean; -begin - - base := base * $10; - - { Calculate the port addresses } - DSP_RESET := base + $206; - DSP_READ_DATA := base + $20A; - DSP_WRITE_DATA := base + $20C; - DSP_WRITE_STATUS := base + $20C; - DSP_DATA_AVAIL := base + $20E; - - { Reset the DSP, and give some nice long delays just to be safe } - Port[DSP_RESET] := 1; - Delay(10); - Port[DSP_RESET] := 0; - Delay(10); - if (Port[DSP_DATA_AVAIL] And $80 = $80) And - (Port[DSP_READ_DATA] = $AA) then - ResetDSP := true - else - ResetDSP := false; -end; - -procedure WriteDSP(value : byte); -begin - while Port[DSP_WRITE_STATUS] And $80 <> 0 do; - Port[DSP_WRITE_DATA] := value; -end; - -function ReadDSP : byte; -begin - while Port[DSP_DATA_AVAIL] and $80 = 0 do; - ReadDSP := Port[DSP_READ_DATA]; -end; - -procedure WriteDAC(level : byte); -begin - WriteDSP($10); - WriteDSP(level); -end; - -function ReadDAC : byte; -begin - WriteDSP($20); - ReadDAC := ReadDSP; -end; - -function SpeakerOn: byte; -begin - WriteDSP($D1); -end; - -function SpeakerOff: byte; -begin - WriteDSP($D3); -end; - -procedure DMAContinue; -begin - WriteDSP($D4); -end; - -procedure DMAStop; -begin - WriteDSP($D0); -end; - -procedure Playback(sound : Pointer; size : word; frequency : word); -var time_constant : word; - page, offset : word; -begin - - SpeakerOn; - - size := size - 1; - - { Set up the DMA chip } - offset := Seg(sound^) Shl 4 + Ofs(sound^); - page := (Seg(sound^) + Ofs(sound^) shr 4) shr 12; - Port[$0A] := 5; - Port[$0C] := 0; - Port[$0B] := $49; - Port[$02] := Lo(offset); - Port[$02] := Hi(offset); - Port[$83] := page; - Port[$03] := Lo(size); - Port[$03] := Hi(size); - Port[$0A] := 1; - - { Set the playback frequency } - time_constant := 256 - 1000000 div frequency; - WriteDSP($40); - WriteDSP(time_constant); - - { Set the playback type (8-bit) } - WriteDSP($14); - WriteDSP(Lo(size)); - WriteDSP(Hi(size)); -end; - -end. - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ References ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Title : The SoundBlaster Developpers Kit -Publishers : Creative Labs Inc - Creative Technology PTE LTD - -Title : Sound Blaster - The Official Book -Authors : Richard Heimlich, David M. Golden, Ivan Luk, Peter M. Ridge -Publishers : Osborne/McGraw Hill -ISBN : 0-07-881907-5 - -Some of the information in this file was either obtained from or verified -by the source code in a public domain library called SOUNDX by Peter -Sprenger. I haven't tried using his library yet (I don't have a C compiler -at the moment) but it looks very well done and contains numerous sound card -detection routines. Says Peter : "It would be nice, that when you make -something commercial with my routines, that you send me a copy of your -project or send me some bucks, just enough for pizza and coke to support my -night programming sessions. If you send me nothing, ok. But USE the stuff, -if you can need it!". Heh...a REAL programmer! - -ftpsite: ftp.uwp.edu -directory: /pub/msdos/demos/programming/game-dev/source -filename: soundx.zip - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Sound Familiar? ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -What the...why is there a faint glimmer of sunlight outside? HOLY $#!^!! It's -5:30am! I'm goin' to bed! - diff --git a/16/PCGPE10/SBPRO.TXT b/16/PCGPE10/SBPRO.TXT deleted file mode 100644 index cc1915f7..00000000 --- a/16/PCGPE10/SBPRO.TXT +++ /dev/null @@ -1,267 +0,0 @@ - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Programming the SoundBlaster Pro ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - Written for the PC-GPE by Mark Feldman - e-mail address : u914097@student.canberra.edu.au - myndale@cairo.anu.edu.au - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ THIS FILE MAY NOT BE DISTRIBUTED ³ - ³ SEPARATE TO THE ENTIRE PC-GPE COLLECTION. ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Disclaimer ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ - -I assume no responsibility whatsoever for any effect that this file, the -information contained therein or the use thereof has on you, your sanity, -computer, spouse, children, pets or anything else related to you or your -existance. No warranty is provided nor implied with this information. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Introduction ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -I still own a SoundBlaster 1.0 (don't laugh) so I haven't been able to -test any of the information in this file, ie don't take any of this as -fact. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Stereo Sound ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Generating stereo FM sound on the SB Pro is similar to the way it's done -on the SB 1.x, you just use different ports for the left and right channels. -The file ADLIB.TXT has more information on this. - -Generating stereo sounds with the DSP is similar to the mono method, but you -send *two* bytes for every sample. The first one goes to the left channel -and the second one goes to the right. You also need to reset the mixer chip -and tell the soundblaster you want to play a stereo sound (see below). This -has the advantage in that you can store the info for both channels in a -single data block and transfer it by still using only one DMA channel. The -WAV file format actually stores it's audio waveform data like this (see the -PC-GPE file WAV.TXT). - - - Left channel bytes - - 0 1 2 3 4 5 6 -ÚÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄ -³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ........ -ÀÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄ - 0 1 2 3 4 5 6 - - Right channel bytes - -To play the sound the SoundBlaster Pro is set for stereo output and the DMA -chip is programmed to send this chunk as is. - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ The CT 1345 Mixer Chip ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -You access the mixer registers the same way you access the regular SB -registers, but Port 2x4h is the index port and 2x5h is the data read/write -port, where x = 2 for base address jumper setting 220h - x = 3 for base address jumper setting 230h - x = 4 for base address jumper setting 240h - -So setting a mixer register to a given value can be accomplished with the -following procedure: - -{ base = 220h, 230 or 240h } -procedure SetMixerReg(base : word; index, value : byte); -begin - Port[base + 4] := index; - Port[base + 5] := value; -end; - - -You can also read a register's current value: - -function GetMixerReg(base : word; index : byte) : byte; -begin - Port[base + 4] := index; - GetMixerReg := Port[base + 5]; -end; - - - - - -The Data Reset register is used to reset the mixer chip. Set this register to -0 before changing any of the other mixer registers. - - Index = 00h - ÚÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄ¿ - ³ 7 ³ 6 ³ 5 ³ 4 ³ 3 ³ 2 ³ 1 ³ 0 ³ - ÀÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÙ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - ³ - Data Reset - - - - -The Input register selects the SB Pro sound input source and filter type. - - Index = 0Ch - ÚÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄ¿ - ³ 7 ³ 6 ³ 5 ³ 4 ³ 3 ³ 2 ³ 1 ³ 0 ³ - ÀÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÙ - ÀÄÄÄÂÄÄÄÙ ÀÄÂÄÙ - ³ ³ - ÚÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄ¿ ÚÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ In Filter ³ ³ ADC Source ³ - ³ 000 - Low ³ ³ 00 - Microphone 1 ³ - ³ 001 - High ³ ³ 01 - CD ³ - ³ 010 - No Filter ³ ³ 10 - Microphone 2 ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³ 11 - Line In ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - - -The Output register determines whether to output sound in stereo or mono, in -stereo two bytes must be sent for each sample, the first one goes to the left -channel and the next one goes to the right. This register allows you to -bypass the output filter. - - Index = 0Eh - ÚÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄ¿ - ³ 7 ³ 6 ³ 5 ³ 4 ³ 3 ³ 2 ³ 1 ³ 0 ³ - ÀÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÙ - ³ ³ - ÚÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄ¿ ÚÄÄÁÄÄÄÄÄÄÄÄÄ¿ - ³ DNFI ³ ³ VSTC ³ - ³ 0 - Use O/P Filter ³ ³ 0 - Mono ³ - ³ 1 - Bypass O/P Filter ³ ³ 1 - Stereo ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -The Master Volume register allows you to set the master volume of each -channel: - - Index = 22h - ÚÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄ¿ - ³ 7 ³ 6 ³ 5 ³ 4 ³ 3 ³ 2 ³ 1 ³ 0 ³ - ÀÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÙ - ÀÄÄÄÄÄÂÄÄÄÄÄÙ ÀÄÄÄÄÄÂÄÄÄÄÄÙ - ³ ³ - ÚÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄ¿ÚÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄ¿ - ³ Master Volume ³³ Master Volume ³ - ³ Left ³³ Right ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -The Voice Volume register allows you to set the volume of each channel for -DSP output: - - Index = 04h - ÚÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄ¿ - ³ 7 ³ 6 ³ 5 ³ 4 ³ 3 ³ 2 ³ 1 ³ 0 ³ - ÀÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÙ - ÀÄÄÄÄÄÂÄÄÄÄÄÙ ÀÄÄÄÄÄÂÄÄÄÄÄÙ - ³ ³ - ÚÄÄÄÄÄÄÄÁÄÄÄÄÄÄ¿ÚÄÄÄÄÄÄÄÁÄÄÄÄÄÄ¿ - ³ Voice Volume ³³ Voice Volume ³ - ³ Left ³³ Right ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - Voice Volume Voice Volume - Left Right - - -The FM Volume register allows you to set the volume of each channel for -FM wave synthesis: - - - - Index = 26h - ÚÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄ¿ - ³ 7 ³ 6 ³ 5 ³ 4 ³ 3 ³ 2 ³ 1 ³ 0 ³ - ÀÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÙ - ÀÄÄÄÄÄÂÄÄÄÄÄÙ ÀÄÄÄÄÄÂÄÄÄÄÄÙ - ³ ³ - ÚÄÄÄÄÄÁÄÄÄÄÄ¿ ÚÄÄÄÄÄÁÄÄÄÄÄ¿ - ³ FM Volume ³ ³ FM Volume ³ - ³ Left ³ ³ Right ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÙ ÀÄÄÄÄÄÄÄÄÄÄÄÙ - - -The CD Volume register allows you to set the volume of each channel for -CD output: - - Index = 28h - ÚÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄ¿ - ³ 7 ³ 6 ³ 5 ³ 4 ³ 3 ³ 2 ³ 1 ³ 0 ³ - ÀÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÙ - ÀÄÄÄÄÄÂÄÄÄÄÄÙ ÀÄÄÄÄÄÂÄÄÄÄÄÙ - ³ ³ - ÚÄÄÄÄÄÁÄÄÄÄÄ¿ ÚÄÄÄÄÄÁÄÄÄÄÄ¿ - ³ CD Volume ³ ³ CD Volume ³ - ³ Left ³ ³ Right ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÙ ÀÄÄÄÄÄÄÄÄÄÄÄÙ - - -The Line Volume register allows you to set the volume of each channel for -line in channel: - - - Index = 2Eh - ÚÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄ¿ - ³ 7 ³ 6 ³ 5 ³ 4 ³ 3 ³ 2 ³ 1 ³ 0 ³ - ÀÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÙ - ÀÄÄÄÄÄÂÄÄÄÄÄÙ ÀÄÄÄÄÄÂÄÄÄÄÄÙ - ³ ³ - ÚÄÄÄÄÄÄÁÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÁÄÄÄÄÄÄ¿ - ³ Line Volume ³ ³ Line Volume ³ - ³ Left ³ ³ Right ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The Mic Mixing register allows you to set the input volume for the -microphone: - - Index = 0Ah - ÚÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄ¿ - ³ 7 ³ 6 ³ 5 ³ 4 ³ 3 ³ 2 ³ 1 ³ 0 ³ - ÀÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÙ - ÀÄÄÄÂÄÄÄÙ - ³ - ÚÄÄÄÄÄÄÁÄÄÄÄÄ¿ - ³ Mic Mixing ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ References ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Title : The SoundBlaster Developpers Kit -Publishers : Creative Labs Inc - Creative Technology PTE LTD - -Title : Sound Blaster - The Official Book -Authors : Richard Heimlich, David M. Golden, Ivan Luk, Peter M. Ridge -Publishers : Osborne/McGraw Hill -ISBN : 0-07-881907-5 - -Some of the information in this file was either obtained from or verified -by the source code in a public domain library called SOUNDX by Peter -Sprenger. I haven't tried using his library yet (I don't have a C compiler -at the moment) but it looks very well done and contains numerous sound card -detection routines. Says Peter : "It would be nice, that when you make -something commercial with my routines, that you send me a copy of your -project or send me some bucks, just enough for pizza and coke to support my -night programming sessions. If you send me nothing, ok. But USE the stuff, -if you can need it!". Heh...a REAL programmer! - -ftp site: ftp.uwp.edu -directory: /pub/msdos/demos/programming/game-dev/source -filename: soundx.zip - diff --git a/16/PCGPE10/SCROLL.TXT b/16/PCGPE10/SCROLL.TXT deleted file mode 100644 index b131853d..00000000 --- a/16/PCGPE10/SCROLL.TXT +++ /dev/null @@ -1,302 +0,0 @@ - - - - SSSSS CCCCC RRRRR OOOOO LL LL IIIIII NN NN GGGGG - SS SS CC CC RR RR OO OO LL LL II NNN NN GG GG - SS CC RR RR OO OO LL LL II NNNN NN GG - SSSSS CC RR RR OO OO LL LL II NN NN NN GG - SS CC RRRRR OO OO LL LL II NN NNNN GG GGG - SS SS CC CC RR RR OO OO LL LL II NN NNN GG GG - SSSSS CCCCC RR RR OOOOO LLLLL LLLLL IIIIII NN NN GGGGG - - by Alec Thomas (Kestrel) of FORGE Software Australia - (c9223826@cs.newcastle.edu.au) - - ------------- -INTRODUCTION ------------- -Okay, here it is fans (and air conditioners, open windows...geez I hate that -joke!), how to do scrolling using either X-mode (and associated variants) and -standard mode 13h (not hard but I thought I'd put it in anyway :) as well as -the basics of parallax scrolling... - -First things first - X-mode. Throughout this little dissertation, I'm going -to assume that you know the basics of X-mode (or mode-X or mode-Y or -whatever you want to call it) such as how to get into it, how to set the -offset register, etc. and just get on with the scrolling :) I'm not trying -to teach you X-mode, but SCROLLING!! - -One further thing. I'm not saying that the methods I'll explain below are -the best method of scrolling, I'm just showing how I got it to work myself -in the hope that someone out there can use it. Anyway, enough of this crap, -on with the STUFF!!! - -(just a little note, when I'm talking about rows, they number from 0-199 and -the same with columns (except 0-319), etc. unless otherwise stated) - -******************************************************************************** -* X-MODE SCROLLING * -******************************************************************************** ------------------- -VERTICAL SCROLLING ------------------- -Ok, this is the easiest form of scrolling using the VGA hardware...fast and -clean. The following example assumes you are using 320x200 X-mode with the -visible page starting at the top of the first page (offset 0). - -To scroll what is on the screen up off the top, you simply add 80 (decimal) -to the screen offset register. This causes the screen to jump up by one -row. However, it also causes whatever is off the bottom of the screen -(the next page!) to become visible...not a desireable effect. - -Easily fixed however. Draw the image you want to scroll, on the row that -will scroll on. So, when the screen offset is changed to scroll the screen -up, the new data is already there for all to see. Beautiful!!! - ------------ Scrolling A (up) -------------- -OFFSET = 0 -WHILE NOT FINISHED DO - OFFSET = OFFSET + 80 - DRAW TO ROW 200 - SET VGA OFFSET = OFFSET -END WHILE -------------------------------------------- - -Bzzzzz! Wrong! This works fine, until you have scrolled down to the -bottom of page 4. Because you're effectively off the bottom of the VGA -window (starting at segment A000h), you can't write to the rest of the -VGA memory (if there is any - only SVGA's have more than 256K on board -memory) and so, you'll be viewing garbage. - -No problem. The way around it is to only use two pages!!! "What?" I hear -you say. In fact, by using only two pages for scrolling, you gain two -major advantages: page flipping (because you're only using two pages for -the actual scrolling, you can use the spare two to perform page flipping) -and infinite scroll regions. - -You perform the infinite scrolling in exactly the same way as before, with -two minor additions: after changing the offset register, you copy the row -just scrolled on to the row just scrolled off. Also, after you have scrolled -a full page, you reset the offset to the top of the original page. - ------------ Scrolling B (up) -------------- -OFFSET = 0 -WHILE NOT FINISHED DO - OFFSET = OFFSET + 80 - IF OFFSET >= (200 * 80) THEN OFFSET = 0 - DRAW TO ROW 200 - SET VGA OFFSET = OFFSET - DRAW TO ROW -1 (was row 0 before scroll) -END WHILE -------------------------------------------- - -Ok, so that's how to do vertical scrolling, now on with horizontal scrolling. - - - --------------------- -HORIZONTAL SCROLLING --------------------- -Horizontal scrolling is essentially the same as vertical scrolling, all -you do is increment or decrement the VGA offset register by 1 instead of -80 as with vertical scrolling. - -However, horizontal scrolling is complicated by two things - - 1. Incrementing the offset register by one actually scrolls by FOUR - pixels (and there are FOUR planes on the VGA, what a coincidence) - - 2. You can't draw the image off the screen and then scroll it on - because of the way the VGA wraps to the next row every 80 bytes - (80 bytes * 4 planes = 320 pixels), if you tried it, you would - actually be drawing to the other side of the screen (which is - entirely visible) - -I'll solve these problems one at a time. - -Firstly, to get the VGA to scroll by only one pixel you use the horizontal -pixel panning (HPP) register. This register resides at - - PORT: 3C0H - INDEX: 13h - -and in real life, you use it like this - ------------------ Pixel Panning --------------- -IN PORT 3DAH (this clears an internal - flip-flop of the VGA) -OUT 13H TO PORT 3C0H -OUT value TO PORT 3C0H (where "value" is the - number of pixels to offset) ------------------------------------------------ - -To implement smooth horizontal scrolling, you would do the following: - --------------- Horizontal Scrolling ------------ -FOR X = 0 TO 319 DO - SET HPP TO ( X MOD 4 ) - SET VGA OFFSET TO ( X/4 ) -END FOR ------------------------------------------------- - -Okay, no problem at all (although I think you might have to fiddle -around with the HPP a bit to get it right...try different values and -see what works :). - -So, the next problem is with drawing the images off the screen where -they aren't visible and then scrolling them on!!! As it turns out, -there's yet ANOTHER register to accomplish this. This one's called the -offset register (no, not the one I was talking about before, that one -was actually the "start address" register) and it's at - - PORT: 3D4H/3D5H - OFFSET: 13H - -and here's how to use it - --------------- Offset Register --------------- -OUT 13H TO PORT 3D4H -OUT value TO PORT 3D5H ----------------------------------------------- - -Now, what my VGA reference says is that this register holds the number -of bytes (not pixels) difference between the start address of each row. -So, in X-mode it normally contains the value 80 (as we remember, -80 bytes * 4 planes = 320 pixels). This register does not affect the -VISIBLE width of the display, only the difference between addresses on -each row. - -When we scroll horizontally, we need a little bit of extra working space -so we can draw off the edge of the screen. - -Perhaps a little diagram will clarify it. The following picture is of a -standard X-mode addressing scheme with the OFFSET register set to 80. - - ROW OFFSET - 0 0 ======================== - 1 80 [ ] - 2 160 [ ] - .. .. [ VISIBLE ] - [ SCREEN ] - [ ] - [ ] - .. .. [ ] - 199 15920 ======================== - -and the next diagram is of a modified addressing scheme with the OFFSET -register set to 82 (to give us 4 extra pixels on each side of the screen) - -ROW OFFSET -0 0 ------========================------ -1 82 | V [ ] V | -2 164 | I [ ] I | -.. .. | N S [ VISIBLE ] N S | - | O I [ SCREEN ] O I | - | T B [ ] T B | - | L [ ] L | -.. .. | E [ ] E | -199 16318 ------========================------ - -Beautiful!!! - -As with vertical scrolling, however, you still have the problem of when -you reach the bottom of page 4...and it's fixed in the same manner. - -I haven't actually managed to get infinite horizontal scrolling working, -but the method I have just stated will give you a horizontal scrolling -range of over 200 screens!!!! So if you need more (which is extremely -unlikely), figure it out yourself. - - ------------------- -COMBINED SCROLLING ------------------- -To do both horizontal and vertical scrolling, all you have to do is combine -the two methods with a few little extras (it's always the way isn't it). - -You have to start off with the original screen on the current page and the -next page as well. When you scroll horizontally, you have to draw the edge -that's coming in to the screen to BOTH pages (that means you'll be drawing -the incoming edge twice, once for each page). You do this so that when you -have scrolled vertically down through a complete page, you can jump back -to the first page and it will (hopefully) have an identical copy, and you -can then continue scrolling again. - -I'm sorry about this being so confusing but it's a bit difficult to explain. - - - - - -******************************************************************************** -* STANDARD VGA SCROLLING * -******************************************************************************** -Without X-mode, there is no easy way to do scrolling using the VGA hardware. -So basically, you have to resort to redrawing the entire screen for every -frame. Several popular games (Raptor and Mortal Kombat spring to mind) -utilise this method with excellent effect, so it is quite effective. - -Basically all you do to implement this is redraw the screen every frame -with a slightly different offset into the "map". - -The following bit of pseudo-code will scroll down and to the right -through the map. - -------------- Standard Scrolling --------------- -X = 0 -Y = 0 -WHILE NOT FINISHED DO - DRAW TO SCREEN( 0, 0 ) FROM MAP( X, Y ) - X = X + 1 - Y = Y + 1 -END WHILE ------------------------------------------------- - - - - - -******************************************************************************** -* PARALLAX SCROLLING * -******************************************************************************** -Parallax scrolling is when the "world" appears to have different levels -of perspective. That is, images further away from the viewer move -proportionately slower than images closer to the screen. - -To implement parallax scrolling, you need two or more "maps". You start -from the most distant map and end with the closest map. When you scroll, -you offset the map furthest away by the smallest value and the map -closest to you by the largest value. - -The following pseudo-code implements a 3 level parallax scrolling world, -scrolling (as above) down to the right. - ---------------- Parallax Scrolling ------------------ -X = 0 -Y = 0 -WHILE NOT FINISHED DO - DRAW TO SCREEN( 0, 0 ) USING MAP_FAR AT ( X/4, Y/4 ) - DRAW TO SCREEN( 0, 0 ) USING MAP_MEDIUM AT ( X/2, Y/2 ) - DRAW TO SCREEN( 0, 0 ) USING MAP_NEAR AT ( X, Y ) - X = X + 4 - Y = Y + 4 -END WHILE ------------------------------------------------------ - -Obviously, with parallax scrolling, each successive map shouldn't delete -the previous map entirely. So you'll have to draw the maps using some -sort of masking (masking being where you can see through the background -colour to what was there previously). - - -******************************************************************************** -* DISCLAIMER * -******************************************************************************** -I'm sorry if any of this is confusing, but hey that's half the fun of it - -figuring out what the hell I'm raving on about :) - -So, if you can figure it out, have fun and make games (preferably good ones!) - -Later, - Kestrel => FORGE Software Australia diff --git a/16/PCGPE10/SOFTROCK.FNT b/16/PCGPE10/SOFTROCK.FNT deleted file mode 100644 index fa37613bd50b1bb39ccb8721d53aca1181cf01d8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15872 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 HjR^b?+lpp6 diff --git a/16/PCGPE10/SPEAKER.TXT b/16/PCGPE10/SPEAKER.TXT deleted file mode 100644 index 09621af3..00000000 --- a/16/PCGPE10/SPEAKER.TXT +++ /dev/null @@ -1,302 +0,0 @@ - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Programming the PC Speaker ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - Written for the PC-GPE by Mark Feldman - e-mail address : u914097@student.canberra.edu.au - myndale@cairo.anu.edu.au - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ THIS FILE MAY NOT BE DISTRIBUTED ³ - ³ SEPARATE TO THE ENTIRE PC-GPE COLLECTION. ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Disclaimer ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ - -I assume no responsibility whatsoever for any effect that this file, the -information contained therein or the use thereof has on you, your sanity, -computer, spouse, children, pets or anything else related to you or your -existance. No warranty is provided nor implied with this information. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Basic Programming Info ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The PC speaker has two states, in and out (0 and 1, on and off, Adam and -Eve etc). You can directly set the state of the PC speaker or you can hook -the speaker up to the output of PIT timer 2 to get various effects. - -Port 61h controls how the speaker will operate as follows: - -Bit 0 Effect -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - 0 The state of the speaker will follow bit 1 of port 61h - 1 The speaker will be connected to PIT channel 2, bit 1 is - used as switch ie 0 = not connected, 1 = connected. - -Playing around with the bits in port 61h can prevent the Borland BC++ and -Pascal sound() procedures from working properly. When you are done using the -speaker make sure you set bit's 0 and 1 of port 61h to 0. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Your First Tone ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Ok, so lets generate a simple tone. We'll send a string of 0's and 1's to the -PC speaker to generate a square wave. Here's the Pascal routine: - - -Uses Crt; - -const SPEAKER_PORT = $61; - -var portval : byte; - -begin - - portval := Port[SPEAKER_PORT] and $FC; - - while not KeyPressed do - begin - Port[SPEAKER_PORT] := portval or 2; - Delay(5); - Port[SPEAKER_PORT] := portval; - Delay(5); - end; - ReadKey; -end. - -On my 486SX33 this generates a tone of around about 100Hz. - -First this routine grabs the value from the speaker port, sets the lower two -bits to 0 and stores it. The loop first sets the speaker to "on", waits a -short while, sets it to "off" and waits another short while. I write the loop -to do it in this order so that when a key is pressed and the program exits -the loop the lower two bits in the speaker port will both be 0 so it won't -prevent other programs which then use the speaker from working properly. - -This is a really bad way of generating a tone. While the program is running -interrupts are continually occurring in the PC and this prevents the timing -from being accurate. Try running the program and moving the mouse around. -You can get a nicer tone by disabling interrupts first, but this would -prevent the KeyPressed function from working. In any case we want to -generate a nice tone of a given frequency, and using the Delay procedure -doesn't really allow us to do this. To top it all off, this procedure uses -all of the CPU's time so we can't do anything in the background while the -tone is playing. - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Using PIT Channel 2 ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Connecting the PC speaker to PIT channel 2 is simply a matter of programming -the channel to generate a square wave of a given frequency and then setting -the lower two bits in the speaker port to a 1. Detailed information on -programming the PIT chip can be found in the file PIT.TXT, but here is -the pascal source you'll need to do the job: - -const SPEAKER_PORT = $61; - PIT_CONTROL = $43; - PIT_CHANNEL_2 = $42; - PIT_FREQ = $1234DD; - -procedure Sound(frequency : word); -var counter : word; -begin - - { Program the PIT chip } - counter := PIT_FREQ div frequency; - Port[PIT_CONTROL] := $B6; - Port[PIT_CHANNEL_2] := Lo(counter); - Port[PIT_CHANNEL_2] := Hi(counter); - - { Connect the speaker to the PIT } - Port[SPEAKER_PORT] := Port[SPEAKER_PORT] or 3; -end; - -procedure NoSound; -begin - Port[SPEAKER_PORT] := Port[SPEAKER_PORT] and $FC; -end; - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Playing 8-bit Sound Through the PC Speaker ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Terminolgy -ÄÄÄÄÄÄÄÄÄÄ - -To clear up any confusion, here's my own definition of some words I'll be -using in this section: - -sample : A single value in the range 0-255 representing the input level of - the microphone at any given moment. - -volume : A sort of generic version of sample, not limited to the 0-255 range. - - song : A bunch of samples in a row representing a continuous sound. - -string : A bunch of binary values (0-1) in a row. - - - -Programs like the legendary "Magic Mushroom" demo do a handly little trick -to play 8-bit sound from the PC speaker by sending binary strings to the -PC speaker for every sample they play. If the bits are all 0's, then the -speaker will be "off". If they are all 1's the speaker will be "on". If they -alternate 0's and 1's then the speaker will behave as if it's "half" on, and -so forth. - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Bit string Time speaker is on ³ - ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ - ³ 11111111 100% ³ - ³ 11101110 75% ³ - ³ 10101010 50% ³ - ³ 10001000 25% ³ - ³ 00000000 0% ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Note that in this table I've used strings which are 8 bits long meaning that -there can only be 9 discrete volume levels (since anywhere from 0 to 8 of -them can be set to 1). In reality the strings would be longer. - -The problem with using bit strings such as this is getting accurate timing -between each bit you send. One way around this is to put all the 1's at the -front of the string and all the 0's at the end, like so: - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Bit string Time speaker is on ³ - ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ - ³ 11111111 100% ³ - ³ 11111100 75% ³ - ³ 11110000 50% ³ - ³ 11000000 25% ³ - ³ 00000000 0% ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -This way you can send all the 1's as a single pulse and your timing doesn't -have to be quite as accurate. The sound isn't quite as good, but I've found -it to be pretty reasonable. A real advantage in using this method is that -you can program the PIT chip for "interrupt on terminal count" mode, this -mode is similar to the one-shot mode, but counting starts as soon as you -load the PIT counter. So if you are playing an 11kHz song you simply load the -PIT counter 11000 times a second with a value that's proportional to the -sample value and trigger it. The speaker output will go low for the set time -and then remain high until the next time you trigger it (in practise it -doesn't matter whether the string of 1's make the speaker go "low" or -"high", just so long as it's consistent). I've managed to get good results -using PIT channel 2 to handle the one-shot for each sample and PIT channel 0 -to handle when to trigger channel 2 (ie 11000 times a second). *PLUS* I was -able to have a program drawing stuff on the screen while all this was going -on in the background! - -Incidently I should mention here that the "interrupt on terminal count" mode -does not generate an actual interrupt on the Intel CPU. The mode was given -this name since the PIT can can be hooked up to a CPU to generate an -interrupt. As far as I can tell IBM didn't do it like this. - -This technique does have one nasty side-effect though. If you are playing an -11kHz tone for example then the PC speaker will be being turned on and off -exactly 11000 times a second, in other words you'll hear a nice 11kHz sine -wave superimposed over the song (do any of you math weirdo's want to do -a FFT to prove this for me?). A way around this is to play the song back -at 22kHz and play each sample twice. This will result in a 22kHz sine wave -which will pretty much be filtered out by the tiny PC speaker and the simple -low-pass filter circuit that it's usually connected to on the motherboard. - -The PIT chip runs at a frequency of 1193181 Hz (1234DDh). If you are playing -an 11kHz song at 22kHz then 1193181 / 22000 = 54 clocks per second, so -you'll have to program the PIT to count a maximum of 54 clocks for each -sample. What I'm getting at is that you'll only be able to play 54 discreet -sample levels using this method, so you'll have to scale the 256 different -levels in an 8-bit song to fit into this range which will also result in -futher loss of sound quality. I sped things up considerably by pre- -calculating a lookup table like so: - -var count_values : array[0..255] of byte; - -for level := 0 to 255 do - count_values[level] := level * 54 div 255; - -Then for each sample I just look up what it's counter value is and send -that to the PIT chip. Since each value is of byte size you can program the -PIT chip to accept the LSB only (see PIT.TXT for more info). The following -pascal code will set the PIT chip up for "interrupt on terminal count" mode -where only the LSB of the count needs to be loaded: - -Port[PIT_CONTROL] := $90; -Port[SPEAKER_PORT] := Port[SPEAKER_PORT] or 3; - -And the following line will trigger the one-shot for a given sample value -from 0-255: - -Port[PIT_CHANNEL_2] := count_values[sample_value]; - -Do that 22000 times a second and whaddaya know, you'll hear "8-bit" sound -from your PC speaker! Here's a bit of code which works ok on my machine: - - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - -const SPEAKER_PORT = $61; - PIT_CONTROL = $43; - PIT_CHANNEL_2 = $42; - PIT_FREQ = $1234DD; - - DELAY_LENGTH = 100; - -procedure PlaySound(sound : PChar; length : word); -var count_values : array[0..255] of byte; - i, loop : word; -begin - - { Set up the count table } - for i := 0 to 255 do - count_values[i] := i * 54 div 255; - - { Set up the PIT and connect the speaker to it } - Port[PIT_CONTROL] := $90; - Port[SPEAKER_PORT] := Port[SPEAKER_PORT] or 3; - - { Play the sound } - - asm cli end; - for i := 0 to length - 1 do - begin - Port[PIT_CHANNEL_2] := count_values[byte(sound^)]; - for loop := 0 to DELAY_LENGTH do; - Port[PIT_CHANNEL_2] := count_values[byte(sound^)]; - for loop := 0 to DELAY_LENGTH do; - sound := sound + 1; - end; - asm sti end; - - { Reprogram the speaker for normal operation } - Port[SPEAKER_PORT] := Port[SPEAKER_PORT] and $FC; - Port[PIT_CONTROL] := $B6; -end; - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - -Note that in this simple example I used a loop of DELAY_LENGTH to get the -timing between samples. I had to fiddle around to get the right value for my -machine and it varies from machine to machine. I also disable interrupts -while the inner loop is playing, otherwise you hear the 18.2Hz timer tick -while the sound was playing. - - -Both of these techniques suffer from two drawbacks. The first is that -samples played from the speaker do not sound very loud. You can make them -louder by making the song you are playing louder, but this eventually means -the sample values will start falling outside the 0-255 range and you'll have -to clip them which starts distorting the sound. The second problem is that -this technique doesn't work on the psezio-electric "speakers" inside lap-top -computers. - diff --git a/16/PCGPE10/STARS.TXT b/16/PCGPE10/STARS.TXT deleted file mode 100644 index ddb6527c..00000000 --- a/16/PCGPE10/STARS.TXT +++ /dev/null @@ -1,710 +0,0 @@ ------------------------------ VLA.NFO ----------------------------------- - ÖÄÄÄÄÄÄÄÄÄÄ (% VLA Presents Intro To Starfields %) ÄÄÄÄÄÄÄÄÄÄ· - º º - ÓÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Written áy : Draeden ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄĽ - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ  VLA Members Are  ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - - (© Draeden - Main Coder ª) - (© Lithium - Coder/Ideas/Ray Tracing ª) - (© The Kabal - Coder/Ideas/Artwork ª) - (© Desolation - Artwork/Ideas ª) - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ The Finn - Mods/Sounds ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - - ÖÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Contact Us On These Boards: ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ· - º º - ³ % Phantasm BBS .................................. (206) 232-5912 ³ - ³ * The Deep ...................................... (305) 888-7724 ³ - ³ * Dark Tanget Systems ........................... (206) 722-7357 ³ - ³ * Metro Holografix .............................. (619) 277-9016 ³ - ³ ³ - º % - World Head Quarters * - Distribution Site º - ÓÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄĽ - - Or Via Internet Mail For The Group : tkabal@carson.u.washington.edu - - Or to reach the other members : - - - draeden@u.washington.edu - - - - lithium@u.washington.edu - - - - desolation@u.washington.edu - - - - -ÚÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ STARS.TXT ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÙ - - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -; -; TITLE: Star field -;WRITTEN BY: DRAEDEN -; DATE: 03/15/93 -; -; NOTES: -; -;ASSOCIATED FILES: -; -; STARGEN.BAS => Basic program that generates a set of 'randomized' -; numbers. Creates STARRND.DW -; -; STARS.ASM => The asm file. -; -; STARRND.DW => File that contains a set of shuffled numbers order. -; Used to create 'random' star field. -; -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - A star field is just a series of 3d point plotted onto a 2d plane (your -screen). The movement effect is achieved by simply decreasing the Z -cordinate and redisplaying the results. The formula for the 3d to 2d -conversion is: - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - ScreenX = ScreenDist * Xpos / Zpos - ScreenY = ScreenDist * Ypos / Zpos -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - This should make perfect sense. As the object gets futher away, (X,Y) -cordinates converge to (0,0). The screen dist is how far away the 'eye' is -from the screen, or, as I like to think of it, the window. Naturally, as you -get closer to the window, your field of view is greatly enhanced (you can see -more). But, because we can't make the monitor bigger, we have to shrink the -data that is being displayed. And when we have a large screen distance, we -should see less of the virtual world, and the objects should appear bigger. -When this formula is translated into assembler, you would immediatly decide -that 256 is the best screen distance. Why? Multiplying by 256 on the 386 is -as simple as this: - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -;we want to multiply ax by 256 and put it into dx:ax to set up for division - - movsx dx,ah ;3 cycles - shl ax,8 ;3 cycles -- total 6 - -;or we could do it the 'normal way'... - - mov dx,256 ;2 cycles, but we can have any screen distance - imul dx ;9-22 cycles on a 386, 13-26 on a 486 - ;a total of 11-28 cycles! -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - If you'll take note, the 6 cycle trick is AT LEAST 5 cycles faster than -the imul. Anyway... I bet you really don't care about a few cycles at this -point, so I won't spend much more time on it... - So, as you can see, the math part of it is easy.. the hard part is the -what's left. You need a routine that creates a star, presumably random, and -another routine that displays all the stars and advances them. Well, that's -how I broke it into subroutines... - - For the routine that creates the star you need it to: - - 1) See if we already have enough stars going (is NUMSTARS > MAXSTARS ?) - 2) If there's room, scan for the first open slot... - 3) Now that we've found where to put it, create a star by getting a set - of random numbers for the (X,Y) and setting the Z to the maximum. - Also select a color for the star. - - The display routine would need to: - - 1) Erase the old star. - 2) Calculate the screen X & Y positions for the new position. Are they - inside the screen boundries? If not, 'kill' the star, otherwise - display it. The shade of the color to use must be calculated by - using the Z cordinate. Color = BaseColor + Zpos / 256 - 3) Decrease the Zpos. - - And the main routine would: - - 1) Call MakeStars - 2) Wait for verticle retrace - 3) Call DisplayStars - 4) Check for keypress, if there is one, handle it, if its not one we're - looking for then exit program. - 5) Loop to step 1 - - To impliment this, we need to create an array of records which has enough -room for MAXSTARS. The record would contain the (X,Y,Z) cordinates, the -OldDi and the base color for the star. To create a star, it first checks to -see if there is room. If there is, then we scan through the array -looking%wor an open slot. If we don't find an empty space, then we don't -create a star. We create the star by grabbing a pair of (X,Y) cordinates -from the list of 'random' numbers and set the Z to MAXZPOS. Then, increase -NUMSTARS and return. - - In displaying the star, we would like to only have to calculate DI once. -So we save off a copy of DI in an array after we calculate it for the drawing -so that erasing the dot is really quick. Next we calculate the new DI for -the dot. This is done by using the formula mentioned above and this one: - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - DI = ScreenY * ScreenWidth + ScreenX - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - When doing the math, care must be taken to make sure that: - - a) the Zpos is not zero and X*256/ZPOS is not greater than 32767. - will cause a DIVIDE BY ZERO or a DIVIDE OVERFLOW - - b) SY and SX do not go outside the border of the screen. - - If either of these conditions are broken, the star must be terminated and -calculations for that star must be aborted. Actually, Zpos = 0 is used to -signify a nonactive star. To terminate the star, you'd simply change its -zpos to 0 and decrease NUMSTARS. - - To create the different shades, I used: - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - Color = BaseColor + Zpos/256 - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - I used 256 as the number to divide by because that enables me to do no -dividing at all- I just use AH, because AH = AX / 256 (AH is the upper 8 bits -of AX). This relation suggests that the MAXZPOS shoul be 16*256 for 16 -shades. So, the MAXZPOS = 4096. The palette will have to be set up so that -the shades go from light to black (lower # is lighter). Simple enough. (I -hope.) - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - RANDOM NUMBERS -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - Well, not truly random numbers, but random enough for a starfield. - - The problem: - There is no way on a PC to create truly random numbers with - great speed. - - Solution: - Don't use truly random numbers. Use a chart of non-repeating, - shuffled numbers that fall within your desired range. That way - the stars will be evenly spread out and the creation of a new star - is incredably fast. ( A few MOV instructions) All you have to is grab - the number and increase the NEXTRANDOM pointer. I chose to fill in - the array half with positive numbers, half with negative with a - minimum distance of 10 from 0. I did this so that no stars will - 'hit' the screen and just vanish. That doesn't look too good. - - Here's the BASIC file that made my numbers for me... - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - - NumStars = 400 - dim RndArray(NumStars) - randomize (timer) - - 'fill the array with numbers from -Numstars/2 to -10 - 'and from 10 to Numstars/2 - - i=10 - for r = 0 to NumStars/2 - RndArray(r)=i - i=i+1 - next - - i=-10 - for r = NumStars/2 to NumStars - RndArray(r)=i - i=i-1 - next - - 'randomly shuffle them.. - - print "Total numbers: ";NumStars - print "Shuffling - Please wait... " - - for q = 1 to numstars/5 - for r = 0 to NumStars - swnum1 = int(rnd*NumStars+.5) - swap RndArray(swnum1),RndArray(r) - next - next - - 'write the numbers neatly to a file - - open "starrnd.dw" for output as 1 - cc= 0 ' CC is my "Column Control" - print#1, "StarRnd dw ";:print#1, using"####";RndArray(0) - for r = 1 to NumStars - - IF cc=0 THEN ' is this the first one on the line? - print#1, "dw ";:print#1, using"####" ;RndArray(r); - ELSE - print#1, ",";:print#1, using"####"; RndArray(r); - END IF - - cc=cc+1:if cc= 10 then cc=0:print#1," " 'goto the next line - next - close #1 - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - This brings up another point. Whenever you can write a program in a -higher level language to create data for you, do it. It sure beats typing -then in by hand. For instance, the palette was made using the REPT macro, -the actual data is created by the compiler at compile time. Doing it that -way happens to be a whole lot easier than typing in every byte. - - Last minute note: I rigged the plus and minus keys up so that they -control the 'Warpspeed' can be from 0 - MaxWarp, which I set to 90 or -something like that. - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - Well, that's it for now. See INFO.VLA for information on contacting us. - - I would like some suggestions on what to write code for. What would you - like to see done? What code would you like to get your hands on? - - Send question, comments, suggestions to draeden@u.washington.edu or post - on Phantasm BBS. - - -ÚÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ STARS.ASM ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÙ - - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -; -; TITLE: Star field -;WRITTEN BY: DRAEDEN -; DATE: 03/15/93 -; -; NOTES: Need 386 to execute. -; -;ASSOCIATED FILES: -; -; STARGEN.BAS => Basic program that generates a set of 'randomized' -; numbers. Creates STARRND.DW -; -; STARS.TXT => The text file that explains starfields... -; -; STARRND.DW => File that contains a set of shuffled numbers. -; Used to create 'random' star field. -; -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - - DOSSEG - .MODEL SMALL - .STACK 200h - .CODE - .386 - ASSUME CS:@CODE, DS:@CODE - LOCALS - -;=== GLOBALS -;=== Data Includes - -INCLUDE starrnd.dw ;file that has label StarRnd numbers - -;=== DATA Structures - - Star_Struc STRUC - X dw 0 - Y dw 0 - Z dw 0 - OldDi dw 0 ;where to erase last dot - Color db 0 ;BASE color. a number 0-16 is added to it - Star_Struc ENDS - - StarStrucSize = 9 ;number of bytes per entry - -;=== DATA - -ScreenWidth EQU 320 -ScreenHeight EQU 200 - -NumRnds EQU 400 ;number of random numbers defined - -MaxZpos EQU 4096 -MinZpos EQU 2 -MaxStars EQU 190 -NumColors EQU 5 ;number of Base colors in the Color Chart - -WarpSpeed dw 15 ;how quickly the stars move toward ya -MaxWarp EQU 90 - -Xindex dw 30 ;index into the StarRnd chart for X & Y -Yindex dw 230 ; -note they must be different; set em the same to - ;see why -Cindex dw 0 ;index into ColorChart - -ColorChart db 0,16,32,48,64,80 ;a list of base colors (-1) - -Stars Star_Struc MaxStars DUP (<>) ;where all the data is held -NumActive dw 0 ;number of stars active - -Palette db 3 dup (0) ;the palette.. first entrie is BG color (black) - i = 15 - REPT 16 - db 2*i,3*i,4*i - i=i-1 - ENDM - i = 15 - REPT 16 - db 2*i,2*i,4*i - i=i-1 - ENDM - i = 15 - REPT 16 - db 3*i,3*i,4*i - i=i-1 - ENDM - i = 15 - REPT 16 - db 3*i,2*i,4*i - i=i-1 - ENDM - i = 15 - REPT 16 - db 3*i,3*i,3*i - i=i-1 - ENDM - i = 15 - REPT 16 - db 2*i,4*i,3*i - i=i-1 - ENDM - -;=== Code Includes -;=== SUBROUTINES - - ;finds 1st available slot for a star and puts it there -MakeStar PROC NEAR - pusha - mov ax,cs - mov es,ax - mov ds,ax - - cmp [NumActive],MaxStars ;is there room for another star? - jae NoEmptySpace - - ;search for 1st available slot - - mov si,0 -TryAgain: - cmp word ptr [Stars.Z+si],0 ;is this slot empty? - je GotOne ;yes, go fill it - - add si,StarStrucSize - cmp si,MaxStars*StarStrucSize - jb TryAgain - jmp NoEmptySpace - -GotOne: ;si points to the record for the star to fill - mov di,[Yindex] ;grab index for Ypos - add di,di ;multiply by 2 to make it a WORD index - mov ax,[StarRnd+di] ;get the number - shl ax,3 ;multiply by 8- could been done in BAS file - mov [Stars.Y+si],ax ;and save off the number - - mov di,[Xindex] ;grab index for Xpos - add di,di ;... same as above, but for Xpos - mov ax,[StarRnd+di] - shl ax,3 - mov [Stars.X+si],ax - - mov [Stars.Z+si],MaxZpos ;reset Zpos to the max - inc [NumActive] ;we added a star so increase the counter - - mov di,[Cindex] ;grab the color index - mov al,[ColorChart+di] ;grab the BaseColor for the star - mov [Stars.Color+si],al ;save it in the record - - ;increase all the index pointers - - inc [Cindex] ;increases the color counter - cmp [Cindex],NumColors - jb OkColor - mov [Cindex],0 -OkColor: - inc [Yindex] ;increases Yindex - cmp [Yindex],NumRnds ;note that for this one we - jb YindNotZero ; subtract NumRnds from Yindex if we - sub [Yindex],NumRnds ; go off the end of the chart -YindNotZero: - inc [Xindex] ;increase Xindex - cmp [Xindex],NumRnds ;have we gone through the entire chart? - jb XindNotZero ;nope... - -;This clever bit of code makes more use out of the chart by increasing Yindex -; one additional unit each time Xindex goes through the entire chart... the -; result is nearly NumRND^2 random non-repeating points - - inc [Yindex] ;yes, so change Yindex so that we get a - mov ax,[Yindex] ;new set of random (x,y) - cmp ax,[Xindex] ;does Xindex = Yindex? - jne NotTheSame ;if the index were the same, you'd see - ;a graph of the line Y = X, not good... - inc [Yindex] ;if they are the same, inc Yindex again -NotTheSame: - mov [Xindex],0 ;reset Xindex to 0 -XindNotZero: ;all done making the star... - -NoEmptySpace: - popa - ret -MakeStar ENDP - -DisplayStars PROC NEAR - pusha - mov ax,cs - mov ds,ax - mov ax,0a000h - mov es,ax - - mov si,0 -DispLoop: - mov cx,[Stars.Z+si] - or cx,cx ;if Zpos = 0 then this star is dead... - je Cont ;continue to the next one- skip this one - - mov di,[Stars.OldDi+si] ;grab old Di - mov byte ptr es:[di],0 ;erase the star - - cmp cx,MinZpos - jl TermStar ;if Zpos < MinZpos then kill the star - - mov ax,[Stars.Y+si] - movsx dx,ah ;'multiply' Ypos by 256 - shl ax,8 - - idiv cx ;and divide by Zpos - add ax,ScreenHeight/2 ;center it on the screen - mov di,ax - cmp di,ScreenHeight ;see if the star is in range. - jae PreTermStar ; If not, kill it - imul di,ScreenWidth ; DI = Y*ScreenWidth - - mov ax,[Stars.X+si] - movsx dx,ah ;multiply Xpos by 256 - shl ax,8 - - idiv cx ;and divide by Zpos - add ax,ScreenWidth/2 ;center it on the screen - cmp ax,ScreenWidth ;are we inside the screen boundries? - jae PreTermStar - add di,ax ; DI = Y * ScreenWidth + X - - mov [Stars.OldDi+si],di ;save old di - - ;calculate the color below - - add ch,cs:[Stars.Color+si] ;i'm dividing cx (the zpos) by 256 and - ; putting the result in ch and adding - ; the base color to it in one instruction - mov es:[di],ch ;put the dot on the screen - - mov ax,cs:[WarpSpeed] - sub cs:[Stars.Z+si],ax ;move the stars inward at WarpSpeed - -Cont: - add si,StarStrucSize ;point to next record - cmp si,MaxStars*StarStrucSize ;are we done yet? - jb DispLoop - popa - ret - -PreTermStar: - mov [Stars.Z+si],1 ;this is here so that the star will get erased - jmp short Cont ;next time through if I just went off and killed - ;the star, it would leave a dot on the screen -TermStar: - mov [Stars.Z+si],0 ;this actually kills the star, after it has - dec [NumActive] ;been erased - jmp short Cont - -DisplayStars ENDP - -;=== CODE - -START: - mov ax,cs - mov ds,ax - mov es,ax - - mov ax,0013h ;set vid mode 320x200x256 graph - int 10h - - mov dx,offset Palette - mov ax,1012h ; WRITE palette - mov bx,0 - mov cx,256 ;write entire palette - int 10h ;doesn't matter if we didnt define it all - -StarLoop: - call MakeStar ;make stars 2x as thick - call MakeStar - - mov dx,3dah -VRT: - in al,dx - test al,8 - jnz VRT ;wait until Verticle Retrace starts - -NoVRT: - in al,dx - test al,8 - jz NoVRT ;wait until Verticle Retrace Ends - - call DisplayStars - - mov ah,1 ;check to see if a char is ready - int 16h - jz StarLoop ;nope, continue - - mov ah,0 - int 16h ;get the character & put in AX - - cmp al,"+" ;compare ASCII part (al) to see what was pressed - jne NotPlus - - inc [WarpSpeed] - cmp [WarpSpeed],MaxWarp - jbe StarLoop - - mov [WarpSpeed],MaxWarp - jmp StarLoop - -NotPlus: - cmp al,"-" - jne NotMinus - - dec [WarpSpeed] - cmp [WarpSpeed],0 - jge StarLoop - - mov [WarpSpeed],0 - Jmp StarLoop - -NotMinus: - - mov ax,0003h ;set 80x25x16 char mode - int 10h - mov ax,4c00h ;return control to DOS - int 21h -END START - - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ STARRND.DW ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -StarRnd dw 166 -dw 67, 102, 46,-173,-154,-210,-192, 173,-196, -81 -dw -50, 36, 50,-200, -95, 209, -16,-179, -30, 18 -dw 174, 197, 127, 71, 29,-121,-160,-176, 19, -52 -dw -185, 89, 172, 74,-156, 157,-125, 144, -34, 69 -dw 17, -40, 64, -98,-153, 125, 160, 140,-204, 141 -dw 137,-165, -14, 154,-146, 119, 123, 165,-130, 168 -dw -180, 143, 52, 107,-107,-102, 57, 27, 117, 37 -dw 126, 15, -89, 184, 116, 183, -99,-139, 150, 188 -dw 38, 90, 93,-194, 207,-187, 62, 59, 196, 12 -dw -174, 54, 146,-137, 198, 162, 155,-163, -77,-144 -dw 191,-132, -43, 151,-103, 20, -46, 13,-140, 31 -dw 130,-169,-188, 109, -33,-150,-170, 68, -75,-201 -dw -100,-171, -19, -61,-206, 149, 99, -76,-186, -44 -dw -178, 34, 61, 28, 114, 199, 201, -83, -27, 63 -dw -38, 204, 208,-112,-208, 122, -90, 23,-122, 161 -dw 35,-168, 170,-164,-151, 75, -60,-109, 85, 193 -dw 45,-175,-134, 205, -21, 49, 133, -85, -47, -37 -dw -29, -96, -66, 73,-118, 147, -53, 120, 153,-155 -dw -11, 11, 95, -26, 134,-145, -49, -74, 42,-124 -dw 189, -42, 92,-167, 88,-126,-129,-108,-193, 195 -dw 190,-106,-117, 203, 84, 139,-123, -94, -88,-158 -dw 181, -97, -20, 82, -57, 112, -35, 14, -56, -58 -dw 200, 80,-183, 106, 87, 30, 51, -28, 98, -12 -dw -191,-128, -13,-184, 136, 43,-166, -62, -73,-116 -dw -31,-135,-101, 25, 41, -82, 110, 10, -45, -41 -dw 97, 175, 138, 171, 72,-133,-157, 58,-104, 187 -dw 192, -68, -87, 169,-110, 91, 129, 104, -70,-114 -dw -138,-115,-141, -67,-195, -79, -69, 40,-147, -80 -dw -119, 128, 152,-209, 83, 53, 159, 66,-190, 81 -dw -92, -10,-181, 135, 60, 33, -25, 70, 22, -72 -dw 103, -23, 131, 79, -64, 55, -86, -32,-182,-136 -dw 26, -54,-172,-148, 148, -65,-152,-207, -39, -71 -dw 65, 179,-177, 24, 118, -59, -63, 44, 105, 206 -dw 178, -84,-202, 132, 186, -17, 76, 176, -22, 177 -dw -198,-159,-162, 78, 77, -55,-120,-203,-113, 156 -dw -189,-197, 124, 121,-142, -15,-205, 56, 158, -18 -dw -93,-161, 39, 48, 101, -91, 182,-127, 108, 111 -dw -36,-143, 21,-149, -78, -48, 164, 202, 185, 180 -dw -51,-199, 100, 194, 32, -24, 142, 86,-111, 47 -dw 115,-105, 16, 167, 94, 163, 96, 113,-131, 145 - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ STARGEN.BAS ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -' -'Written by: Draeden /VLA -' Date: 03/15/93 -' -' Notes: Used for generating 'random' data for Stars.asm -' - - - NumStars = 400 - dim RndArray(NumStars) - randomize (timer) - - 'fill the array with numbers from -Numstars/2 to -10 - 'and from 10 to Numstars/2 - - i=10 - for r = 0 to NumStars/2 - RndArray(r)=i - i=i+1 - next - i=-10 - for r = NumStars/2 to NumStars - RndArray(r)=i - i=i-1 - next - - 'randomly shuffle them.. - - print "Total numbers: ";NumStars - print "Shuffling - Please wait... " - - for q = 1 to numstars/5 - for r = 0 to NumStars - swnum1 = int(rnd*NumStars+.5) - swap RndArray(swnum1),RndArray(r) - next - next - - 'write the numbers neatly to a file - - open "starrnd.dw" for output as 1 - cc= 0 - print#1, "StarRnd dw ";:print#1, using"####";RndArray(0) - for r = 1 to NumStars - - IF cc=0 THEN - print#1, "dw ";:print#1, using"####" ;RndArray(r); - ELSE - print#1, ",";:print#1, using"####"; RndArray(r); - END IF - - cc=cc+1:if cc= 10 then cc=0:print#1," " - next - close #1 - diff --git a/16/PCGPE10/SVGINTRO.TXT b/16/PCGPE10/SVGINTRO.TXT deleted file mode 100644 index d4e13f4b..00000000 --- a/16/PCGPE10/SVGINTRO.TXT +++ /dev/null @@ -1,473 +0,0 @@ - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Introduction to Programming the SVGA Cards ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - Written for the PC-GPE by Mark Feldman - e-mail address : u914097@student.canberra.edu.au - myndale@cairo.anu.edu.au - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ THIS FILE MAY NOT BE DISTRIBUTED ³ - ³ SEPARATE TO THE ENTIRE PC-GPE COLLECTION. ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Disclaimer ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ - -I assume no responsibility whatsoever for any effect that this file, the -information contained therein or the use thereof has on you, your sanity, -computer, spouse, children, pets or anything else related to you or your -existance. No warranty is provided nor implied with this information. - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ SVGA Section Overview ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The vast majority of the information presented in the PC-GPE was obtained -from the book "Programmer's Guide to the EGA and VGA Cards - Includes Super -VGAs, Second Edition" by Richard Ferraro, ISBN 0-201-57025-4, published -by Addison-Wesley. This book is by far the most comprehensive VGA/SVGA -reference I have seen to date and is more than worth it's price tag. I -heartily recommend it to anyone wishing to do any serious graphics -programming for the PC. - -The PC-GPE SVGA section was originally not going to be included in version 1 -due to the fact that I have only been able to verify that the info on the -Paradise SVGA is correct. I will include it however, in the hope that -everyone (and I mean *EVERYONE*) who reads these files and tries out the -routines will e-mail me with the results they get so I can make the -modifications in time for version 2. - -I will need to know these things: - -1) Your SVGA board name - -2) The id and revision number of the chip inside (if possible) - -3) What you tried and the results you got. This applies to *all* routines, - bank switching, chip detection etc.... I need to know everything! - -If a routine doesn't work as expected then let me know if it's doing anything -at all. "The routine is stuffed you idiot" won't exactly help me much, but -"I can only read pixels in bank 0 you idiot" just might...... - -And of course there's always the chance that I've misunderstood my references -so I need to have my mistakes pointed out to me as well. I'm a big boy...I -can take it! - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Writing to the VGA Ports ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Many of the PC-GPE SVGA texts have the PortW Pascal command as follows: - -PortW[PORTNUM] := VALUE; - -This command writes a 16 bit word to the port, the same as the asm op code: - -out dx, ax - -The effect of this code is the same as the following two Pascal statements: - -Port[PORTNUM] := Lo(VALUE); -Port[PORTNUM + 1] := Hi(VALUE); - -I'm not sure if this is common to all the PC ports or only works on the -VGA. (Perhaps someone could enlighten me?) - -The PortW command is very handy when writing to the SVGA extended registers. -The SVGA register sets are all extensions of the VGA register sets and -use an indexed addressing scheme to cut down on the number of ports they -use. The texts often have register maps which look similar to the following: - - PR0A Address Offset A - Index : 09h at port 3CEh - Read/Write at port 3CFh - ÚÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄ¿ - ³ 7 ³ 6 ³ 5 ³ 4 ³ 3 ³ 2 ³ 1 ³ 0 ³ - ÀÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÙ - ÀÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÙ - Bank - -For this particular map, the register name is PR0A Offset A. To select the -register and get it ready for reading and/or writing you write the value -09h to port 3CEh (the index port). The register can then be read from or -written to port 3CFh (the read/write port). - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Bank Switching ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -In real mode, the PC has addresses A000:0000-B000:FFFF allocated for video -memory, although most graphics modes only use the A000 segment. - -If you set an SVGA card to 640x480x256 color mode (for example) then there -will be a total of 307200 pixels on the screen. Since each pixel takes up -one byte in 256 color modes around 300K of video memory will be used to -store the screen data. In most cases all this memory is accessed through the -A000 segment. When you initially set the mode, bank 0 on the card will be -active and anything you read to or write from this segment will be in the -first 64K bytes in video memory (i.e. lines 0-101 and the first 256 bytes in -line number 102). If you want to access the next 64K you must switch the -card to bank number 1 so that the A000 segment now maps to the second bank, -and so forth. - -The problem here is that each card has a different method of doing the bank -switching. The PC-GPE files contain info on how to do the bank switching for -a number of the most commonly used SVGA cards. The VESA standard helped -inject some sanity into the otherwise chaotic world of SVGA programming by -introducing a "standard" method of bank switching for all cards. - -A note should be made here about bank granularity. In the section above I -assumed that bank 0 corresponded to the first 64K, bank 1 to the next etc.. -ie each bank has a 64K granularity. This is true for most cards, but some -do have smaller granularities (see the table below). The Paradise for -instance has a 4K granularity. It's very similar in concept to the PC's -segmented memory, segments are 64K long but they have a 16 byte granularity. -The Paradise chip's banks are also 64K long, but they have a 4K granularity. -All the bank switching code given in the PC-GPE SVGA files adjust for this -so that your code can assume the card has a 64K granularity in all cases. - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ SVGA Libraries ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -There are a few SVGA libraries available via anonymouse ftp. I haven't had -a chance to use any of them yet, but I've heard some of them are pretty good, -so they might be worth checking out. Here's two C libraries that I know of: - - site: ftp.fasttax.com -directory: /pc/graphic/scitech/beta - filename: svkt44bl.zip - - site: garbo.uwasa.fi -directory: /pc/programming - filename: SVGACC20.ZIP - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Common SVGA Cards ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The PC-GPE files contain information on programming the 7 VGA "standards" -as covered by Ferraro. According to Ferraro the majority of SVGA cards on -the market today conform to one of these standards. The standards are -Ati, Chips and Technologies, Genoa, Paradise, Trident, Tseng and Video7. -I've also included a file on the VESA specifications (VESASP12.TXT). VESA -seems to be the way to go now since public domain drivers are available for -most cards and you only need to write one set of graphics drivers if you use -it. VESA BIOS calls can be slow however, so if your program needs to do LOTS -of bank switching then you may need to work with the cards on a hardware -level. - -The following is a list of common SVGA's along with the chip it is based on, -the number of banks the card contains and the modes they support. The GR -field is the bank granularity. This information was obtained by examining -the configuration files in the shareware program VPIC. VPIC is a great -little program which supports numerous graphics file formats as well -as all the cards listed below (and a few more). VPIC can be obtained via -anonymous ftp from oak.oakland.edu, directory /pub/msdos/gif, filename -vpic. I tried to contact the author so I'd feel better about blatently -ripping all the info out of his data files but he doesn't seem to have an -e-mail address. Are you out there Bob Montgomery? - -Quite a number of the chip sets in the list are not mentioned in Ferraro. If -anyone has information on programming any of them drop me a line. - -Each mode in the table below has a mode number. To set the mode, load the AX -register with this value and do an interrupt 10h. Some modes below have two -numbers. In these cases load AX with the first number and BX with the second -before calling interrupt 10h. - -Only 16 and 256 color are presented in the table below. True-color modes -are not included in this version. - - -Board Chip Banks Modes Resolution Col GR -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - -Acumos ACUMOS 8 5Eh 640x400 256 64k - 5Fh 640x480 256 64k - 5Ch 800x256 256 64k - 10h 640x350 16 64k - 12h 640x480 16 64k - 58h 800x600 16 64k - 5dh 1024x768 16 64k - -Ahead A Chip AHEADA 4/8 60h 640x400 256 64k - 61h 640x480 256 64k - 62h 800x600 256 64k - 6Ah 800x600 16 64k - 74h 1024x768 16 64k - -Ahead B Chip AHEADB 8/16 60h 640x400 256 64k - 61h 640x480 256 64k - 62h 800x600 256 64k - 63h 1024x768 256 64k - 6Ah 800x600 16 64k - 74h 1024x768 16 64k - -ATI VGA Wonder ATI OLD 4/8 61h 640x400 256 32k - 62h 640x480 256 32k - 63h 800x600 256 32k - 54h 800x600 16 32k - 65h 1024x768 16 64k - -ATI VGA Wonder+ ATI NEW 4/8/16 61h 640x400 256 32k - 62h 640x480 256 32k - 63h 800x600 256 32k - 64h 1024x768 256 32k - 54h 800x600 16 32k - 55h 1024x768 16 32k - -ATI Ultra 8514A GA ATI NEW 4/8/16 61h 640x400 256 32k - 62h 640x480 256 32k - 63h 800x600 256 32k - 54h 800x600 16 32k - 55h 1024x768 16 32k - -ATI XL ATI NEW 4/8/16 61h 640x400 256 32k - 62h 640x480 256 32k - 63h 800x600 256 32k - 64h 1024x768 256 32k - 54h 800x600 16 32k - 55h 1024x768 16 32k - -Chips & Technology Chips and 4/8 78h 640x400 256 16k - Technologies 79h 640x480 256 16k - 7Ah 720x540 256 16k - 7Bh 800x600 256 16k - 70h 800x600 16 16k - 71h 960x720 16 16k - 72h 1024x768 16 16k - -Cirrus Logic GD54 VESA 16/64 4F02h,100h 640x400 256 4k - 4F02h,101h 640x480 256 4k - 4F02h,103h 800x600 256 4k - 4F02h,105h 1024x768 256 4k - 4F02h,102h 800x600 16 4k - 4F02h,104h 1024x768 16 4k - -Definicon, 16 Bit TSENG 4000 8/16 2dh 640x350 256 64k - 2fh 640x400 256 64k - 2eh 640x480 256 64k - 30h 800x600 256 64k - 38h 1024x768 256 64k - 29h 800x600 16 64k - 37h 1024x768 16 64k - 3Dh 1280x1024 16 64k - -Diamond 24x PARADISE 4/16 5eh 640x400 256 4k - 5fh 640x480 256 4k - 5ch 800x600 256 4k - 60h 1024x768 256 4k - 58h 800x600 16 4k - 5Dh 1024x768 16 4k - 6Ch 1280x960 16 4k - 64h 1280x1024 16 4k - -Diamond Speedstar 24 TSENG 4000 8/16 2dh 640x350 256 64k - 2fh 640x400 256 64k - 2eh 640x480 256 64k - 30h 800x600 256 64k - 38h 1024x768 256 64k - 29h 800x600 16 64k - 37h 1024x768 16 64k - -Everex EV-673 EVEREX 4/8 70h,13h 640x350 256 64k - 70h,14h 640x400 256 64k - 70h,15h 512x480 256 64k - 70h,30h 640x480 256 64k - 70h,31h 800x600 256 64k - 70h,02h 800x600 16 64k - 70h,20h 1024x768 16 64k - -Everev 678 TRIDENT 4/8 70h,14h 640x400 256 64k - 8800 70h,15h 512x480 256 64k - 70h,30h 640x480 256 64k - 70h,31h 800x600 256 64k - 70h,02h 800x600 16 64k - 70h,20h 1024x768 16 64k - -Everex Vision VGA HC TSENG 4000 8/16 2fh 640x400 256 64k - 2eh 640x480 256 64k - -Genoa 5400 TSENG 3000 4/8 2dh 640x350 256 64k - 2eh 640x480 256 64k - 30h 800x600 256 64k - 29h 800x600 16 64k - 37h 1024x768 16 64k - -Genoa 6400 GENOA 4/8 2bh 640x350 256 64k - 2eh 640x480 256 64k - 30h 800x600 256 64k - 29h 800x600 16 64k - 37h 1024x768 16 64k - -Genoa 7900 24 bit TSENG 4000 8/16 2dh 640x350 256 64k - 2fh 640x400 256 64k - 2eh 640x480 256 64k - 30h 800x600 256 64k - 38h 1024x768 256 64k - 29h 800x600 16 64k - 37h 1024x768 16 64k - -Headland 1024i HEADLAND 4/8 6F05h,66h 640x400 256 64k - 6F05h,67h 640x480 256 64k - 6F05h,68h 720x540 256 64k - 6F05h,69h 800x600 256 64k - 6F05h,61h 720x540 16 64k - 6F05h,62h 800x600 16 64k - 6F05h,65h 1024x768 16 64k - -Hi Res 512 ZYMOS 4/8 5ch 640x400 256 64k - 5dh 640x480 256 64k - 5eh 800x600 256 64k - 6ah 800x600 16 64k - 5fh 1024x768 16 64k - -Maxxon TRIDENT 8800 4/8 5ch 640x400 256 64k - 5dh 640x480 256 64k - 5eh 800x600 256 64k - 5bh 800x600 16 64k - 5fh 1024x768 16 64k - -C&T MK82452 CHIPS AND 8 78h 640x400 256 16k - TECHNOLOGIES 79h 640x480 256 16k - 70h 800x600 16 16k - 72h 1024x768 16 16k - -NCR 77C22 NCR 8/16 5eh 640x400 256 64k - 5fh 640x480 256 64k - 5ch 800x600 256 64k - 62h 1024x768 256 64k - 58h 800x600 16 64k - 5dh 1024x768 16 64k - -OAK OAK 8/16 53h 640x480 256 64k - 54h 800x600 256 64k - 59h 1024x768 256 64k - 52h 800x600 16 64k - 56h 1024x768 16 64k - -Orchid -Fahrenheight 1280 S3 8/16 4F02h,201h 640x480 256 64k - 4F02h,203h 800x600 256 64k - 4F02h,205h 1024x768 256 64k - 4F02h,202h 800x600 16 64k - 4F02h,204h 1024x768 16 64k - 4F02h,206h 1280x960 16 64k - 4F02h,206h 1280x1024 16 64k - -Orchid Pro -Designer II TSENG 4000 8/16 2dh 640x350 256 64k - 2fh 640x400 256 64k - 2eh 640x480 256 64k - 30h 800x600 256 64k - 38h 1024x768 256 64k - 29h 800x600 16 64k - 37h 1024x768 16 64k - -Paradise VGA Pro PARADISE 4/16 5eh 640x400 256 4k - 5fh 640x480 256 4k - 5ch 800x600 256 4k - 60h 1024x768 256 4k - 58h 800x600 16 4k - 5Dh 1024x768 16 4k - -Primus P2000 GA PRIMUS 8/16 2dh 640x480 256 64k - 2bh 800x600 256 64k - 31h 1024x768 256 64k - 37h 1280x1024 256 64k - 2ah 800x600 16 64k - 30h 1024x768 16 64k - 36h 1280x1024 16 64k - -Compaq QVision QVISION 8/16 32h 640x480 256 4k - 38h 1024x768 256 4k - 10h 640x350 16 4k - 12h 640x480 16 4k - 29h 800x600 16 4k - 37h 1024x768 16 4k - -Realtek RTVGA REALTEK 8/16 25h 640x400 256 64k - 26h 640x480 256 64k - 27h 800x600 256 64k - 28h 1024x768 256 64k - 1Fh 800x600 16 64k - 21h 1024x768 16 64k - 2Ah 1280x1024 16 64k - -Realtek RTVGA REALTEK 8/16 25h 640x400 256 64k - 26h 640x480 256 64k - 27h 800x600 256 64k - 28h 1024x768 256 64k - 1Fh 800x600 16 64k - 21h 1024x768 16 64k - 2Ah 1280x1024 16 64k - -S3 Graphics Accelerator S3 8/16 4F02h,201h 640x480 256 64k - 4F02h,203h 800x600 256 64k - 4F02h,205h 1024x768 256 64k - 4F02h,202h 800x600 16 64k - 4F02h,204h 1024x768 16 64k - 4F02h,206h 1280x960 16 64k - -STB EM 16 TSENG 4000 8/16 2dh 640x350 256 64k - 78h 640x400 256 64k - 2eh 640x480 256 64k - 30h 800x600 256 64k - 38h 1024x768 256 64k - 29h 800x600 16 64k - 37h 1024x768 16 64k - -Phoebes TRIDENT 8800CS 4/8 5ch 640x400 256 64k - 5dh 640x480 256 64k - 5bh 800x600 16 64k - 5fh 1024x768 16 64k - -Maxxon TRIDENT 8800CS 4/8 5ch 640x400 256 64k - 5dh 640x480 256 64k - 5eh 800x600 256 64k - 5bh 800x600 16 64k - 5fh 1024x768 16 64k - -Trident 8900 TRIDENT 8900 8/16 5Ch 640x400 256 64k - 5Dh 640x480 256 64k - 5Eh 800x600 256 64k - 62h 1024x768 256 64k - 5Bh 800x600 16 64k - 5Fh 1024x768 16 64k - -Tseng ET-3000 TSENG ET3000 4/8 2dh 640x350 256 64k - 2eh 640x480 256 64k - 30h 800x600 256 64k - 29h 800x600 16 64k - 36h 960x720 16 64k - 37h 1024x768 16 64k - -Tseng ET-4000 TSENG ET4000 8/16 2dh 640x350 256 64k - 2fh 640x400 256 64k - 2eh 640x480 256 64k - 30h 800x600 256 64k - 38h 1024x768 256 64k - 29h 800x600 16 64k - 37h 1024x768 16 64k - -Video 7 VRAM VIDEO7 4/8 6f05h,66h 640x400 256 64k - 6f05h,67h 640x480 256 64k - 6f05h,68h 720x540 256 64k - 6f05h,69h 800x600 256 64k - 6f05h,61h 720x540 16 64k - 6f05h,62h 800x600 16 64k - 6f05h,65h 1024x768 16 64k - -Western Digital 90C PARADISE 4/8 5eh 640x400 256 4k - 5fh 640x480 256 4k - 5ch 800x600 256 4k - 58h 800x600 16 4k - 5Dh 1024x768 16 4k diff --git a/16/PCGPE10/TEXTURE.TXT b/16/PCGPE10/TEXTURE.TXT deleted file mode 100644 index 69059568..00000000 --- a/16/PCGPE10/TEXTURE.TXT +++ /dev/null @@ -1,1566 +0,0 @@ - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Texture Mapping ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - Written for the PC-GPE by Sean Barrett. - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ THIS FILE MAY NOT BE DISTRIBUTED ³ - ³ SEPARATE TO THE ENTIRE PC-GPE COLLECTION. ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - --=-=-=-=- -=-=-=-=-=- -=-=-=-=-=- -=-=-=-=-=- -=-=-=-=-=- -=-=-=-=-=- -TEXTURE -TEXUE almost everything you need to know to texture map with the PC -TXR -X --=-=-=-=- -=-=-=-=-=- -=-=-=-=-=- -=-=-=-=-=- -=-=-=-=-=- -=-=-=-=-=- - -Copyright 1994 Sean Barrett. -Not for reproduction (electronic -or hardcopy) except for personal use. - -Contents: - - 0. warnings - 1. terminology and equations - 2. the basics - Perfect texture mapping - DOOM essentials - Wraparound textures - Non-rectangular polygons - 3. the hazards - going off the texture map - divide by 0 - it'll never be fast enough - 4. the complexities - handling arbitrarily-angled polygons - lighting - slow 16-bit VGA cards - mipmapping - - -=-=-=-=-=- -| Note: I am not providing any references as I simply -| derived the math myself and worked out the various -| techniques for myself (the 32-bit ADC trick was -| pointed out to me in another context by TJC, -| author of the Mars demo) over the last two years -| (since Wolfenstein 3D and Underworld came out). - -=-=-=-=-=- - -TEXTURE -TEXUE -TXR 0. Warnings -X - - I assume a RIGHT-handed 3D coordinate system, with X positive -to the right, Y positive disappearing into the screen/distance, -and Z positive up. To adjust this to the typical left-handed -3D space, simply swap all the 3D Ys & Zs. - - I assume the screen space is positive-X to the right, -positive-Y goes down. Adjust the signs as appropriate for -your system. - - I will present code and pseudo-code in C. I also include -some relatively tight inner loops written in assembly, but I'm -omitting the details of the loop setup. The inner loops, while -usually from real, working code, should generally be taken -as examples showing how fast it ought to be possible to run -a given task, not as necessarily perfect examples. I often -use 32-bit instructions (sorry 286 programmers) because they -can double the performance. However, I write in real mode, -because 16-bit addressing is often convenient for texture maps, -and it's straightforward to use segment registers as pointers -to texture maps. The translation to protected mode should not -prove problematic, but again, these should more be taken as -examples rather than simply being used directly. I optimize -for the 486, but I skip some obvious optimizations. For example, -I write "loop", because it's simpler and more clear. -Production code for the 486 should explicitly decrement and -then branch. Similarly, I write "stosb", etc. etc. - - -TEXTURE -TEXUE -TXR 1. Terminology and Equations -X - - - You really probably don't want to read this section first, -but rather refer back to it whenever you feel the need. So -skip up to section 2 and refer back as appropriate. I could've -made this an appendix, but it seems too important to put last. - -TEX -TE Terms -T - texture: A texture is a pixelmap of colors which is mapped - onto a polygon using "texture mapping". The size - of the polygon has nothing to do with the size (the - number of pixels) in the texture map. - - run: A run is a row or column of pixels. Normal texture - mapping routines process one run in an "inner loop". - - arbitrarily-angled polygon: a polygon which isn't a floor, - wall, or ceiling; technically, a polygon which isn't - parallel to the X or Z axes (or X or Y axes in a - Z-is-depth coordinate system). - - texture space: - polygon space: - polygon coordinate space: - Since a texture is flat, or two-dimensional, the relation - of the texture to the 3D world can be described with a - special coordinate space known by one of these names. - Because it is only 2D, the space can be characterized with - the location of the texture space in 2D, and two 3D vectors - which represent the axes of the coordinate space. Sometimes - called "uv" space, because the name of the coordinates are - usually u & v. - -TEX -TE Notation -T - - Vectors appear in all caps. - Components of vectors are P = < Px, Py, Pz >. - - Certain variables have consistent usage: - - x,y,z are coordinates in three-space - i,j are screen coordinates - u,v are coordinates in texture space - a,b,c are "magic coordinates" such that - u = a/c, v = b/c - -TEX -TE Equations -T - - Don't let this scare you off! Go read section 2, and - come back to this when you're ready. - - Let P,M, and N be vectors defining the texture space: P is the - origin, and M and N are the vectors for the u&v axes. - - Assume these vectors are in _view space_, where view space is - defined as being the space in which the transformation from - 3D to 2D is: - - (x,y,z) -> (i,j) - i = x / y - j = z / y - - In other words, you have to adjust P, M, and N to be relative - to the view, and if you have multiplications in your perspective - computation, you have to multiply the appropriate components of - P, M, and N to compute them. Note that since typically in 3D - up is positive, and in 2D down is positive, there may be a - multiplication by -1 that needs to go into Py, My, Ny. Note that - this also assumes that (0,0) in screen space is at the center - of the screen. Since it's generally not, simply translate - your screen coordinates (i,j) as if they were before applying - the texture mapping math (or if you're funky you can modify - your viewspace to pre-skew them). - - For example, if your transforms are: - i = Hscale * x / y + Hcenter - j = -Vscale * z / y + Vcenter - - Then you should simply multiply Px, Mx, and Nx by Hscale, - and multiply Py, My, and Mz by -Vscale. Then just remember - to subtract Hcenter and Vcenter from the i,j values right - before plugging them into the texture mapping equations. - - We begin by computing 9 numbers which are constant - for texture mapping the entire polygon (O stands for - Origin, H for Horizontal, and V for vertical; why I use - these names should become clear eventually): - - Oa = Nx*Pz - Nz*Px - Ha = Nz*Py - Ny*Pz - Va = Ny*Px - Nx*Py - - Ob = Mx*Pz - Mz*Px - Hb = Mz*Py - My*Pz - Vb = My*Px - Mx*Py - - Oc = Mz*Nx - Mx*Nz - Hc = My*Nz - Mz*Ny - Vc = Mx*Ny - My*Nx - - Ok. Then, for a given screen location (i,j), the formula - for the texture space (u,v) coordinates corresponding to - it is: - - a = Oa + i*Ha + j*Va - b = Ob + i*Hb + j*Vb - c = Oc + i*Hc + j*Hc - - u = a/c - v = b/c - - -TEXTURE -TEXUE -TXR 2. The Basics -X - - So you've got your polygon 3D engine running, and -you'd like to start adding a bit of texture to your -flat- or Gouraud-shaded polygons. Well, it will make -it look a lot cooler. But let's point out the -disadvantages of texture mapping right away: - - Slower - Sometimes hard to see polygon edges - - Each of these has certain ramifications on the -overall approach you want to take with your code, -which we'll come back to later, in sections 3 and 4. - - Practical advice: Don't try to get your riproaringly -fast texture mapper running first. Get a very simple, -slow, "perfect" texture mapper working first, as described -in the first subsection below. This will allow you to make -sure you've gotten the equations right. Realize that I -can't present the equations appropriate to every scenario, -since there are simply too many spaces people can work -in. I've chosen to present the math from an extremely -simple coordinate space which keeps the texture mapping -relatively simple. You'll have to work out the correct -transformations to make it work right, and a slow but -correct texture mapping routine may help you tweak the -code as necessary to achieve this. Use very simple -polygons to start your testing; centered and facing the -viewer should be your very first one (if done correctly, -this will simply scale the texture). - -TEX -TE Perfect Texture Mapping -T - - To start with, we'll do slow but exact "perfect" texture -mapping of a square tile with a simple texture map mapped onto -it. The polygon is defined in three-space using four points, -and the texture map is 256x256 pixels. Note that this is all -talking about using floating point, so those of you working in -C or Pascal are fine. Those in assembly should realize that -you have to do a bit of extra work to use fixed point, or you -can beat out the floating point by hand if you want. - - First we have to "map" the texture onto the polygon. -We have to define how the square texture map corresponds -to the square polygon. This is relatively simple. Let -one corner of the polygon be the origin (location <0,0>) -of the texture map. Let each of the other corners -correspond to corners just off the edge of the texture -map (locations <256, 0>, <256, 256>, and <0, 256>). - - We'd like to use the equations in section 1, which -require vectors P, M, and N, where P is the origin, -and M & N are the axes for u&v (which are _roughly_ -the coordinates in the texture map, but see below). -In other words, P, M and N tells us where the texture -lies relative to the polygon. P is the coordinate in -three-space where the origin of the texture is. M -tells us which way the "horizontal" dimension of the -texture lies in three-space, and N the "vertical". - - Suppose the polygon has four vertices V[0], V[1], -V[2], and V[3] (all four of these are vectors). Then, -P is simply V[0]. M is a vector going from the origin -to the corner <256, 0>, so M is a vector from V[0] to -V[1], so M = V[1] - V[0]. N is a vector from the origin -to the corner <0, 256>, so N is V[3] - v[0]. - - P = V[0] - M = V[1] - V[0] { note these are vector subtractions } - N = V[3] - V[0] - - Again, remember that we need P, M, and N in the viewspace -discussed with the equation, so make sure you've transformed -the Vs appropriately, or you can compute P, M, and N in world -or object space and transform them into viewspace. - - Compute the 9 magic numbers (vectors O, H, and V) as described -in section 1. Now, take your 3D polygon and process it as normal. -Scan convert it so that you have a collection of rows of pixels -to process. - - Now, iterate across each row. For each pixel in the polygon -whose screen coordinates are , apply the rest of the math -described in section 1; that is, compute a, b, and c, and from -them compute . - - I said before that are basically the texture map -coordinates. What they are in truth are the coordinates in texture -map space. Because of the way we defined texture map space, -we'll actually find that u and v both run from 0..1, not 0..256. -This is an advantage for descriptive purposes because u and v -are always 0 to 1, regardless of the size of the texture map. - - So, to convert u&v to pixelmap coordinates, multiply them -both by 256. Now, use them as indices into the texture map, -output the value found there, and voila, you've texture mapped! - -The loop should look something like this: - -[ loop #1 ] - for every j which is a row in the polygon - screen = 0xA0000000 + 320*j - for i = start_x to end_x for this row - a = Oa + (Ha * i) + (Va * j) - b = Ob + (Hb * i) + (Vb * j) - c = Oc + (Hc * i) + (Vc * j) - u = 256 * a / c - v = 256 * b / c - screen[i] = texture_map[v][u] - endfor - endfor - - Once you've got that working, congratulations! You're -done dealing with the annoying messy part, which is getting -those 9 magic numbers computed right. The rest of this is -just hard grunt work and trickery trying to make the code -faster. - - From here on in, I'm only going to look at the inner -loop, that is, a single run (row or column), and let the -rest of the runs be understood. - -TEX -TE Prepare to meet thy DOOM -T - - This subsection is concerned with vastly speeding -up texture mapping by restricting the mapper to walls, -floors and ceilings, or what is commonly called -DOOM-style texture mapping, although it of course predates -DOOM (e.g. Ultima Underworld [*], Legends of Valour). - -[* Yes, Underworld allowed you to tilt the view, -but it distorted badly. Underworld essentially used -DOOM-style tmapping, and tried to just use that on -arbitrarily-angled polygons. I can't even begin to -guess what Underworld II was doing for the same thing.] - - To begin with, let's take loop #1 and get as much -stuff out of the inner loop as we can, so we can see -what's going on. Note that I'm not going to do low-level -optimizations, just mathematical optimizations; I assume -you understand that array walks can be turned into -pointer walks, etc. - -[ loop #2 ] - a = Oa + Va*j - b = Ob + Vb*j - c = Oc + Vc*j - - a += start_x * Ha - b += start_x * Hb - c += start_x * Hc - - for i = start_x to end_x - u = 256 * a / c - v = 256 * b / c - screen[i] = texture_map[v][u] - a += Ha - b += Hb - c += Hc - endfor - - With fixed point math, the multiplies by 256 -are really just shifts. Furthermore, they can be -"premultiplied" into a and b (and Ha and Hb) outside -the loop. - - Ok, so what do we have left? Three integer adds, -a texture map lookup, and two extremely expensive fixed-point -divides. How can we get rid of the divides? - - This is the big question in texture mapping, and most -answers to it are _approximate_. They give results that -are not quite the same as the above loop, but are difficult -for the eye to tell the difference. - - However, before we delve into these, there's a very -special case in which we can get rid of the divides. - - We can move the divide by c out of the loop without -changing the results IFF c is constant for the duration -of the loop. This is true if Hc is 0. It turns out that -Hc is 0 if all the points on the run of pixels are the same -depth from the viewer, that is, they lie on a line of -so-called "constant Z" (I would call it "constant Y" in -my coordinate system). - - The requirement that a horizontal line of pixels be the -same depth turns out to be met by ceilings and floors. -For ceilings and floors, Hc is 0, and so the loop can be -adjusted to: - -[ loop #3 ] - __setup from loop #2__ - u = 256 * a / c - v = 256 * b / c - du = 256 * Ha / c - dv = 256 * Hb / c - for i = start_x to end_x - screen[i] = texture_map[v][u] - u += du - v += dv - endfor - - Now _that_ can be a very fast loop, although adjusting -the u&v values so they can be used as indices has been -glossed over. I'll give some sample assembly in the next -section and make it all explicit. - - First, though, let's look at walls. Walls are almost -identical to floors and ceilings. However, with walls, -Vc is 0, instead of Hc. This means that to write a loop -in which c is constant, we have to walk down columns instead -of across rows. This affects scan-conversion, of course. - - The other thing about walls is that with floors, since -you can rotate about the vertical axis (Z axis for me, Y axis -for most of you), the horizontal runs on the floors cut -across the texture at arbitrary angles. Since you're -bound to not tilt your head up or down, and since the -polygons themselves aren't tilted, you generally find -that for walls, Va is 0 as well. In other words, as you -walk down a column of a wall texture, both a & c are constant, -so u is constant; you generally only change one coordinate, -v, in the texture map. This means the inner loop only needs -to update one variable, and can be made to run _very_ fast. - - The only thing missing from this discussion for creating -a DOOM clone is how to do transparent walls, how to do -lighting things, and how to make it fast enough. These will -be discussed in section 4, although the some of the speed -issue is addressed by the inner loops in the next subsection, -and the rest of the speed issue is discussed in general terms -in section 3. - -TEX -TE ...wrapped around your finger... -T - - So far, we've only looked at texture mapping a single -polygon. Of course, it's obvious how to texture map -a lot of polygons--just lather, rinse, repeat. But it -may seem sort of wasteful to go through all the 3D math -and all over and over again if we just want to have one -long wall with the same texture repeating over and over -again--like linoleum tiles or wallpaper. - - Well, we don't have to. Let's think about this -idea of a "texture map space" some more. We defined -it as being a coordinate system "superimposed" on -the polygon that told us where the texture goes. -However, when we implemented it, we simply used the -polygon itself (in essence) as the coordinate space. - - To see this, make a polygon which is a rectangle, -perhaps four times as long as it is tall. When it -is drawn, you will see the texture is distorted, -stretched out to four times its length in one dimension. -Suppose we wanted it to repeat four times instead? - - The first step is to look at what the definition -of the texture map space means. The texture map space -shows how the physical pixelmap itself goes onto the -polygon. To get a repeating texture map, our first -step is to just get one of the copies right. If -we set up our P,M, & N so that the M only goes one -quarter of the way along the long edge of the -rectangle, we'll map the texture onto just that -quarter of the rectangle. - - Here's a picture to explain it: - - Polygon A-B-C-D Texture map - - A E u=0 u=1 - o--------o-___________ B v=0 11112222 - |111112222 ---------o 11112222 - |111112222 | 33334444 - |111112222 | 33334444 - |333334444 | v=1 - |333334444 | - |333334444 ___________---------o - o--------o- C - D F - - So, we used to map (u,v)=(0,0) to A, (u,v)=(1,0) to B, and -(u,v) = (0,1) to D. This stretched the texture map out to -fill the entire polygon map. - - Now, instead, we map (u,v)=(1,0) to E. In other words, -let P = A, M = E-A, and N = D-A. In this new coordinate -space, we will map the texture onto the first quarter of -the polygon. - - What about the rest of the polygon? Well, it simply -turns out that for the first quarter 0 <= u <= 1. For -the rest, 1 <= u <= 4. - - To make the texture wrap around, all we have to do is -ignore the integer part of u, and look at the fractional part. -Thus, as u goes from 1 to 2, we lookup in the texture map using -the fractional part of u, or (u-1). - - This is all very simple, and the upshot is that, once -you define P, M, and N correctly, you simply have to mask -your fixed-point u&v values; this is why we generally use -texture maps whose sides are powers of two, so that we can -mask to stay within the texture map. (Also because they -fit conveniently into segments this way, and also so that -the multiply to convert u&v values from 0..1 to indices -is just a shift.) - - I'm assuming that's a sufficient explanation of the -idea for you to get it all setup. So here's the assembly -inner loops I promised. I'm not going to bother giving -the ultra-fast vertical wall-drawing case, just the -horizontal floor/ceiling-drawing case. - - Note that a mask of 255 (i.e. for a 256x256 texture) -can be gotten for free; however, no program that I'm -aware of uses texture maps that large, since they -simply require too much storage, and they can cache very -poorly in the internal cache. - - First, here's your basic floor/ceiling texture mapper, -in C, with wraparound, and explicitly using fixed point -math--but no setup. - -[ loop #4 ] - mask = 127, 63, 31, 15, whatever. - for (i=0; i < len; ++i) { - temp = table[(v >> 16) & mask][(u >> 16) & mask]; - u += du; - v += dv; - } - - Now, here's an assembly one. This one avoids the -shifts and does both masks at the same time, and uses -16 bits of "fractional" precision and however many bits -are needed for the coordinates. Note that I assume -that the texture, even if it is 64x64, still has each -row starting 256 bytes apart. This just requires some -creative storage approaches, and is crucial for a fast -inner loop, since no shifting&masking is required to -assemble the index. - - mov al,mask - mov ah,mask - mov mask2,ax ; setup mask to do both at the same time - -loop5 and bx,mask2 ; mask both coordinates - mov al,[bx] ; fetch from the texture map - stosb - add dx,ha_low ; update fraction part of u - adc bl,ha_hi ; update index part of u - add si,hb_low ; these are constant for the loop - adc bh,hb_hi ; they should be on the stack - loop loop5 ; so that ds is free for the texture map - - This code is decent, but nowhere near as fast as it can be. -The main trick to improving performance is to use 32 bit adds -instead of two adds. The problem with this is that extra operations -are required to setup the indexing into the texture map. Through -the use of the ADC trick, these can be minimized. In the following -code, bl and bh are unchanged. However, the top half of EBX now -contains what used to be in si, and the other values have been -moved into registers. ESI contains hb_low in the top half, and -ha_hi in the low 8 bits. This means that ADC EBX,ESI achieves -the result of two of the additions above. Also, we start using -BP, so we move our variables into the data segment and the texture -map into FS. - -loop6 and bx,mask2 - mov al,fs:[bx] - stosb - add dx,bp ; update fractional part of u - adc ebx,esi ; update u (BL) and frac. part of v (EBX) - adc bh,ch ; update index part of v - dec cl - jnz loop6 - - This is a bit faster, although it has one bug. It's -possible for the addition into BL to overflow into BH. It might -not seem to be, since BL is masked every iteration back down to -stay in 0..127, 0..63, or whatever. However, if the step is -negative, then BL will be decremented each iteration, and may -"underflow" and subtract one from BH. To handle this, you need -a seperate version of the loop for those cases. - - If you're not doing wraparound textures, you can speed the -loop up a bit more by removing the and. You can run entirely -from registers except for the texture map lookup. Additionally, -unrolling the loop once cuts down on loop overhead, and is crucial -if you're writing straight to the VGA, since it doubles your -throughput to a 16-bit VGA card. - - Here's a very fast no-wraparound texture mapper. It uses -the ADC trick twice. Note that the carry flag is maintained -around the loop every iteration; unfortunately the 'and' required -for wraparound textures clears the carry flag (uselessly). EBX -and EDX contain u & v in their bottom 8 bits, and contain the -fractional parts of v & u in their top bits (note they keep the -_other_ coordinate's fractional parts). You have to have prepped -the carry flag first; if you can't figure this technique out, don't -sweat it, or look to see if someone else has a more clear discussion -of how to do fast fixed-point walks using 32-bit registers. - - This loop is longer because it does two pixels at a time. - -loop7 mov al,[bx] ; get first sample - adc edx,esi ; update v-high and u-low - adc ebx,ebp ; update u-high and v-low - mov bh,dl ; move v-high into tmap lookup register - mov ah,[bx] ; get second sample - adc edx,esi - adc ebx,ebp - mov bh,dl - mov es:[di],ax ; output both pixels - inc di ; add 2 to di without disturbing carry - inc di - dec cx - jnz loop7 - - I went ahead and 486-optimized the stosw/loop at the end to make -cycle-counting easier. All of these instructions are single cycle -instructions, except the branch, and the segment-override. So you're -looking at roughly 15 cycles for every two pixels. Your caching -behavior on the reads and writes will determine the actual speed. -It can be unrolled another time to further reduce the loop overhead; -the core operations are 9 instructions (10 cycles) for every two -pixels. Note the "inc di/inc di", which protects the carry flag. -If you unroll it again, four "inc di"s will be required. Unroll it -another time, and you're better off saving the carry flag, adding, -and restoring, for example "adc ax,ax/add di,8/shr ax,1", rather -than 8 "inc di"s. - -TEX -TE Lost My Shape (trying to act casual) -T - - Non-rectangular polygons are trivial under this system. -Some approaches require you to specify the (u,v) coordinates -for each of the vertices of the polygon. With this technique, -you instead specify the 3D coordinates for three of the -"vertices" of the texture map. So the easiest way of handling -a texture of a complex polygon is simply to use a square -texture which is larger than the polygon. For example: - - P1 P2 - x B _______ C x - / \ - / \ - A / \ - \ / D - \ / - \ _______ / - x F E - P3 - - Now, we simply define the texture map such that P is P1, -M is P2-P1, and N is P3-P1. Then, if our texture looks like -this: - - u=0 u=1 - ------------ - v=0 |..XXoooooo.. - |.XXXXoooooo. - |XXXXXXoooooo - |.XXXXXXoooo. - v=1 |..XXXXXXoo.. - - Then the regions marked by '.' in the texture map will -simply never be displayed anywhere on the polygon. - - Wraparound textures can still be used as per normal, -and concave polygons require no special handling either. - - Also, you can get special effects by having M and N not -be perpendicular to each other. - -TEXTURE -TEXUE -TXR 3. The Hazards -X - - This sections discusses some of the pitfalls and -things-aren't-quite-as-simple-as-they-sounded issues -that come up while texture mapping. All of the -information is, to some extent, important, whether -you've encountered this problem or not. - -TEX -TE Cl-cl-cl-close to the Edge -T - - At some time when you're texture mapping, you'll -discover (perhaps from the screen, perhaps from a -debugger) that your U & V values aren't within the -0..1 range; they'll be just outside it. - - This is one of these "argh" problems. It is -possible through very very careful definition of -scan-conversion operations to avoid it, but you're -likely to encounter it. - - If you use wraparound textures, you may not ever -notice it, however, since when it happens, the -texture will simply wraparound and display an -appropriate pixel. - - If not, you may get a black pixel, or just -garbage. It'll only happen at the edges of your -polygon. - - The reason this happens is because your scan-conversion -algorithm may generate pixels "in the polygon" whose -pixel-centers (or corners, depending on how you've -defined it) are just outside the texture--that is, -they're outside the polygon itself. - - The right solution to this is to fix your scan-converter. -If your texture mapper computes u&v coordinates based on -the top-left corner of the pixel (as the one I've defined -so far has), make sure your scan-converter only generates -pixels whose top-left corner is really within the polygon. -If you do this, you may need to make a minor change to my -definition of M & N, but I'm not going to discuss this -further, since you probably won't do this. - - A second option is to define P, M, and N such that the -texture map space is slightly bigger than the polygon; that -is, so that if you go just off the edge of the polygon, -you'll still be within the texture map. - - This is a pain since you end up having to transform extra -3D points to do it. - - The third, and probably most common solution, is to always -use wraparound textures, which hide the problem, but prevent -you from using textures that have one edge that highly contrasts -with another. - - The fourth, and probably second most common solution, -and the one that turns out to be a real pain, is to "clamp" -the u&v values to be within the texture all the time. - - Naively, you just put this in your inner loop: - - if (u < 0) u = 0; else if (u > 1) u = 1; - if (v < 0) v = 0; else if (v > 1) v = 1; - - Of course, you don't really do this, since it'd slow -you down far too much. You can do this outside the loop, -clamping your starting location for each run. However, -you can't, under this system, clamp the ending value -easily. - - Remember that in the loop we update u and v with -(essentially) Ha/c and Hb/c. These are constant -across the entire run, but not constant across the -entire polygon, because c has different values for -different runs. - - We can compute du and dv in a different way to -allow for clamping. What we do is we explicitly compute -(a,b,c) at (start_x, j) as we did before, but we also -compute (a,b,c) at (end_x, j). From these we compute -(u,v) at start_x & at end_x. Next we clamp both sets -of u & v. Then we compute du and dv with - - du = (u2 - u1) / (end_x - start_x - 1) - dv = (v2 - v1) / (end_x - start_x - 1) - - This is slightly more expensive than the old way, -because we have to compute u2 and v2, which requires -extra divides. However, for methods that explicitly -calculate u&v sets and then compute deltas (and we'll -see some in section 4), this is the way to go. - - One final thing you can do is interpolate the (a,b,c) -triple from the vertices as you scan convert. This will -guarantee that all (a,b,c) triples computed will lie be -within the polygon, and no clamping will be necessary -(but deltas must still be computed as above). However, -you have to make sure the (a,b,c) values you compute at -the vertices are clamped themselves, which is not too hard -by a bit more complicated than clamping (u,v) values. - -TEX -TE Out of This Domain -- Zero's Paradox -T - - Divides by zero are ugly. We programmers don't -like them. If this were an ideal world (a quick -nod to mathematicians and some physicists), the -texture mapping equations would be divide-by-zero-free. - - Unfortunately, it's a repercussion of the exact -same problem as above that you can bump into them. - - Remember above, I noted that it's possible to -get (u,v) pairs with a value just outside of the -0..1 range, because a pixel we're texture mapping -isn't even in the polygon? - - Well, even worse, it's possible for this pixel, -which isn't in the polygon, to be along the horizon -line (vanishing point) for the polygon. If this -happens, your Y value (sorry, Z for most of you) -would be infinite if you tried to compute the 3D -coordinates from the screen coordinates; and in -the (u,v) computation, you end up with a 0 value -for c. Since u = a/c, blammo, divide by 0. - - Well, the solution is simple. Test if c is 0, -and if it is, don't divide. But what _should_ you do? - - Well, let's look at an "even worse" case. Suppose -the pixel is so far off the polygon it's across the -horizon line. In this case, we'll end up with c having -the "wrong" sign, and while our divide won't fault on -us, our u&v values will be bogus. - - What do we do then? - - We can't clamp our a&b&c values very easily. -Fortunately, it turns out we don't have to. If -this happens, it means the edge of the polygon -must be very close to the horizon, or the viewer -must be very, very flat to the polygon (if you know -what I mean). If so, the viewer can't really tell -what should be "right" for the polygon, so if we -screw up the u&v values, it really doesn't matter. - - So the answer is, don't worry if c gets the -wrong sign, and if c comes out to be 0, use any -value for u&v that you like--(0,0) makes an obvious -choice. - - I've never had a serious problem with this, but -it is possible that this could actually give you some -pretty ugly results, if, say, two corners of a polygon -both "blew up", and you treated them both as being -(0,0). It can also cause problems with wraparound -polygons not repeating the right amount. - -TEX -TE Do the Dog -T - - Most polygon 3D graphics engines probably use -the painter's algorithm for hidden surface removal. -You somehow figure out what order to paint the polygons -in (depth sort, BSP trees, whatever), and then paint -them back-to-front. The nearer polygons obscure the -farther ones, and voila!, you're done. - - This works great, especially in a space combat -simulator, where it's rare that you paint lots of pixels. - - You can texture map this way, too. For example, -Wing Commander II doesn't texture map, but it does -real time rotation, which involves essentially the -same inner loop. Wing Commander II is fast--until -a lot of ships are on the screen close to you, at which -point it bogs down a bit. - - If you care about not slowing down too much in the above -case, or you want to do an "indoor" renderer with lots of -hidden surfaces, you'll find that with texture mapping, -you can ill-afford to use the painter's algorithm. - - You pay a noticeable cost for every pixel you texture -map. If you end up hiding 80% of your surfaces (i.e. there -are five "layers" everywhere on the screen), you end up -"wasting" 80% of the time you spend on texture mapping. - - To prevent this, you have to use more complex methods -of hidden surface removal. These will probably slow you down -somewhat, but you should make up for it with the gain in texture -mapping. - - The essential idea is to only texture map each screen pixel once. -To do this, you do some sort of "front-to-back" painting, where -you draw the nearest surface first. Any pixel touched by this -surface should never be considered for drawing again. - - There are many ways to do this. You can process a single -scanline or column at a time and use ray-casting or just -"scanline processing", then resolve the overlap between the -runs with whatever method is appropriate. You can stay -polygonal and maintain "2D clipping" information (a data -structure which tracks which pixels have been drawn so far). - - Beyond getting a fast inner loop for texture mapping, -getting a fast hidden-surface-removal technique (and a fast -depth-sorting technique if appropriate) is probably the -next most crucial thing for your frame rate. - - But the details are beyond the scope of this article. - - Note that if you attempt to use a Z-buffer, you will -still end up paying all of the costs of texture mapping for -every forward-facing polygon (or at least 50% of them if -you get really tricky; if you get really, really tricky, -the sky's the limit.) I strongly doubt that any PC game -now out, or that will come out in the next year, will -render full-screen texture mapping through a Z-buffer. -(Superimposing a rendered image on a Z-buffered background -is a different issue and is no doubt done all the time.) - - -TEXTURE -TEXUE -TXR 4. The Complexities -X - - In this section we will discuss lots of miscellaneous -topics. We'll look at some more optimizations, such as -considerations for dealing with slow VGA cards, and how to -texture map arbitrarily-angled polygons without doing two -divides per pixel. We'll talk about a technique that lets -you use textures with high-frequency components, and one way -to integrate lighting into texture-mapping. - -TEX -TE Arbitrarily-Angled Polygons -T - - First suggestion: Don't. Set up your world to -have all (or mostly) walls and floors. Supporting -arbitrarily-angled polygons is going to slow you -down, no matter what. - - The original texture mapping loop, which supported -arbitrarily-angled polygons, required two divides per -pixel. We don't have to go that slow, but we'll never -go as fast as DOOM-style rendering can go. (However, -as you start to use more sophisticated lighting algorithms -in your inner loop, the cost of handling arbitrarily- -angled polygons may start to become less important.) - - There is one way to texture map such polygons -"perfectly" without two divides per pixel, and a -host of ways to do it "imperfectly". I'll discuss -several of these ways in varying amounts of detail. -Your best bet is to implement them all and see -which ones you can get to run the fastest but still -look good. You might find that one is faster for -some cases but not for others. You could actually -have an engine which uses all the methods, depending -on the polygon it's considering and perhaps a "detail" -setting which controls how accurate the approximations -are. - - The "perfect" texture mapping algorithm is -described in another article, "Free-direction texture -mapping". I'll summarize the basic idea and the -main flaw. The basic idea is this. For ceilings -and walls, we were able to walk along a line on -the screen for which the step in the "c" parameter -was 0; this was a line of "constant Z" on the -polygon. - - It turns out that every polygon has lines of -"constant Z"--however, they can be at any angle, -not necessarily vertical or horizontal. - - What this means, though, is that if you walk -along those lines instead of walking along a horizontal -or vertical, you do not need a divide to compute your -texture map coordinates, just deltas. - - The details can be found in the other article. -The slope of the line to walk on the screen is something -like Hc/Vc. - - Note, however, that the "DOOM" approach was _just_ -an optimization for a special case. The wall & ceiling -renderers produce exactly the same results as a -perfect texture mapper, for the polygons that they -handle (ignoring rounding errors and fixed-point precision -effects). This is not true for the "free-direction" -texture mapper. While there is a line across the -screen for which the polygon has constant Z, -you cannot walk exactly along that line, since you -must step by pixels. The end result is that while -in the texture map space, you move by even steps, -in the screen space, you move with ragged jumps. -With perfect texture mapping, you always sample -from the texture map from the position corresponding -to the top-left/center of each pixel. With the -free-direction mapper, you sample from a "random" -location within the pixel, depending on how you're -stepping across the screen. This "random" displacement -is extremely systematic, and leads to a systematic -distortion of the texture. I find it visually -unacceptable with high-contrast textures, compared to -perfect texture mapping, but you should try it and decide -for yourself. The technically inclined should note that -this is simply the normal "floor" renderer with an extra -2D skew, and that while 2D skews are trivial, they are -non-exact and suffer from the flaw described above. - - The only other alternative for arbitrarily-angled -polygons is to use some kind of approximation. We -can characterize u and v as functions of i (the horizontal -screen position; or use 'j' if you wish to draw columns); -for instance, u = a / c, where a = q + i*Ha, c = p + i*Hc. -So we can say u(i) = (q + i*Ha) / (r + i*Hc). - - Now, instead of computing u(i) exactly for each i, -as we've done until now, we can instead compute some -function u'(i) which is approximately equal to u(i) and -which can be computed much faster. - - There are two straightforward functions which we -can compute very fast. One is the simple linear -function we used for DOOM-style mapping, u'(x) = r + x*s. -Since the function we're approximating is curved (a -hyperbola), a curved function is another possibility, -such as u'(x) = r + x*s + x^2*t. (SGI's Reality Engine -apparently uses a cubic polynomial.) - - If you try both of these approximations on a very -large polygon at a sharp angle, you will find that -they're not very good, and still cause visible -curvature. They are, of course, only approximations. -The approximations can be improved with a simple -speed/quality trade-off through subdivision. The -idea of subdivision is that the approximation is -always of high quality for a small enough region, -so you can simply subdivide each region until the -subregions are small enough to have the desired -quality. - - There are two ways to subdivide. One simple way -is to subdivide the entire polygon into smaller -polygons. This should be done on the fly, not -ahead of time, because only polygons that are at -"bad" angles need a lot of subdivision. After -dividing a polygon into multiple smaller ones, -render each one seperately. Use the original -P, M, and N values for all of the new polygons -to make the texture remain where it should be -after subdivision. - - The (probably) better way to subdivide is to -subdivide runs instead of polygons, and so I'll -discuss this in more detail. The essential thing -is that to do an approximation, you evaluate the -original function at two or more locations and -then fit your approximate function to the computed -values. One advantage of run subdivision is that -you can share points that you evaluated for one -subrun with those of the next. - - First lets turn back to the two approximations -under consideration. The first is what is called -"bilinear texture mapping", because the function -is linear and we're tracking two ("bi") values. -To use this method, we compute the function at -both endpoints: u1 = u(start_x), u2 = u(end_x). -Then we compute our start and step values. To -keep things simple, I'm going to assume the approximation -function u'(x) is defined from 0..end_x-start_x, not -from start_x..end_x. - - So, the linear function u'(x) = r + s*x, where -u'(0) = u1 and u'(end_x - start_x) = u2 is met by -letting r = u1, s = (u2 - u1) / (end_x - startx). - - Now, suppose our run goes from x = 10 to x = 70. -If we evaluate u(10), u(20), u(30), u(40),... u(70), -then we can have six seperate sections of bilinear -texture mapping. - - For a quadratic, there are several ways to compute -it. One way is to compute an additional sample in the -middle; u3 = u((start_x + end_x)/2). Then we can -fit u1,u2, and u3 to u'(x) = r + s*x + t*x^2 with: - - len = (end_x - start_x) - k = u1 + u2 - u3*2 - r = u1 - s = (u2 - u1 - 2*k)/len - t = 2*k / len^2 - - Note that to use this in code, you cannot simply -use a loop like this: - - r += s; - s += t; - - because the r,s, and t values aren't correct -for discrete advancement. To make them correct, -do this during the setup code: - - R = r - S = s + t - T = 2*t - - Then the loop of (...use R..., R += S, S += T) will work correctly. - - The biquadratic loop will be slower than the linear -loop, but will look better with fewer subdivisions. You -can share one of the endpoints from one biquadratic -section to the next. Note, though, that you require twice -as many calculations of u&v values for the same number of -subdivisions with a biquadratic vs. a bilinear. - - Another thing to do is to choose how to subdivide the run -more carefully. If you simply divide it in half or into quarters, -you'll discover that some of the subruns come out looking better -than others. So there are some things you can do to improve the -subdivision system. Another thing you can do is to try to make -most of your subruns have lengths which are powers of two. This -will let you use shifts instead of divides when computing r,s, and -t, which cuts down on your overhead, which lets you use more -subdivisions and get the same speed. - - Note something very important. Subdivision increases the -overhead per run; biquadratic and other things increase the -cost of the inner loop. Before you go crazy trying to optimize -your arbitrarily-angled polygon renderer, make sure you're -rendering some "typical" scenes. The "right" answer is going -to depend on whether you have lots of very shorts runs or -fewer, longer runs. If you optimize based on a simple test -case, you may end up suboptimal on the final code. - - You probably still want to have both a column-based and a -row-based renderer, and use whichever one the polygon is -"closer to" (e.g. if Hc is closer to 0 than Vc, use the row-based). -Note that the free-direction renderer looks its worst (to me) -for very small rotations, i.e. when Hc or Vc are very close to 0. -Since in these cases not much subdivision is needed, even if you -choose to use a free-direction mapper as your primary renderer, -you might still want to have "almost wall" and "almost floor" -renderers as well. - - Finally, there is one more approximation method you can use, -which is faster than any of the ones discussed so far, but is -simply totally and utterly wrong. This is the approach used -by Michael Abrash in his graphics column in Dr. Dobbs. While -it's quite wrong, it works on polygons which are entirely -constant Y (sorry, Z), and can be a noticeable speedup. - - What you do is 2D (instead of 3D) interpolation. You mark -each vertex with its coordinates in the texture map. Then when -you scan convert, you interpolate these values between vertices -on the edges of your runs. Thus, scan conversion will generate -runs with (u,v) values for the left and right end. Now simply -compute (du,dv) by subtracting and dividing by the length (no -clamping will be necessary), and use your fast bilinear inner -loop. When combined with 3D polygon subdivision, this approach -can actually be useful. - - A cheat: - - When the player is moving, set your internal quality -settings a little lower. When the player stops, switch -back to the normal quality; if the player pauses the game, -render one frame in normal quality. - - If done right, you can get a small boost to your fps -without anyone being able to tell that you did it. You -may have to use normal quality if the player is only -moving very slowly, as well. - - Note that while this may sound like an utterly cheap -trick just to improve the on-paper fps number, it's actually -quite related to the "progressive refinement" approach used -by some real VR systems (which, when the viewer isn't moving, -reuse information from the previous frame to allow them to -draw successive frames with more detail). - - There are a number of ways of improving this cheat -intelligently. If the player is moving parallel to a polygon, -that polygon will tend to be "stably" texture mapped (similar -mapping from frame to frame). If there is any distortion from -your approximation, this will be visible to the player. So -this means a rule of thumb is to only cheat (draw with -above-average distortion) on polygons that are not facing -parallel to the direction of motion of the player. - -TEX -TE Light My Fire -T - - If you're texture mapping, it's generally a good idea -to light your polygons. If you don't light them, then it -may be difficult to see the edge between two walls which -have the same texture (for instance, check out the "warehouse" -section of registered DOOM, which is sometimes confusing -when a near crate looks the same color as a far crate). - - Lighting is actually pretty straightforward, although -you take a speed hit in your inner loop. I'm not going -to worry about actual lighting models and such; see other -articles for discussion on how to do light-sourced polygons. - - Instead I'm going to assume you've computed the lighting -already. We'll start with "flat-run" shading, wherein an -entire run has the same intensity of light falling on it. - - DOOM uses flat-run shading. A given polygon has a certain -amount of light hitting it, which is the same for the entire -polygon. In addition, each run of the polygon is sort-of -lit by the player. Since runs are always at a constant -depth, you can use constant lighting across the run and -still change the brightness with distance from the player -(DOOM uses something that resembles black fog, technically). - - So the only real issue is _how_ you actually get the -lighting to affect the texture. Several approaches are -possible, but the only one that I think anyone actually uses -is with a lighting table. - - The lighting table is a 2D array. You use the light -intensity as one index, and the pixelmap color as the -other index. You lookup in the table, and this gives -you your final output color to display. (With two -tables, you can do simple dithering.) So the only thing -you have to do is precompute this table. - - Basically, your inner loop would look something like this: - - ...compute light... - for (i=start_x; i <= end_x; ++i) { - color = texture[v >> 16][u >> 16]; - output = light_table[light][color]; - screen[i] = output; - u += du; - v += dv; - } - - The next thing to consider is to Gouraud shade your -texture map. To do this, you need to compute the light -intensity at the left and right edge of the run; look -elsewhere for more details on Gouraud shading. - - Once you've got that, you just do something like this: - - z = light1 << 16; - dz = ((light2 - light1) << 16) / (end_x - start_x); - for (i=start_x; i <= end_x; ++i) { - color = texture[v >> 16][u >> 16]; - output = light_table[z >> 16][color]; - screen[i] = color; - u += du; - v += dv; - z += dz; - } - - Note that you shouldn't really do this as I've written the -code. light1 and light2 should be calculated with 16 bits of extra -precision in the first place, rather than having to be shifted -left when computing z. I just did it that way so the code -would be self-contained. - - I'm going to attempt to give a reasonably fast assembly -version of this. However, there's a big problem with doing -it fast. The 80x86 only has one register that you can -address the individual bytes in, and also use for indexing--BX. -This means that it's a real pain to make our inner loop alternate -texture map lookup and lighting fetch--whereas it's almost -trivial on a 680x0. I avoid this somewhat by processing two -pixels at a time; first doing two texture map lookups, then -doing two lighting lookups. - - Here's a flat-shading inner loop. I'm doing this code off the -top of my head, so it may have bugs, but it's trying to show -at least one way you might try to do this. Since I use BP, -I put variables in the FS segment, which means DS points -to the texture, GS to the lighting table. - - mov ch,fs:light - adc ax,ax -loop8 shr ax,1 ; restore carry - mov cl,[bx] ; get first sample, setting up cx for color lookup - adc edx,esi ; update v-high and u-low - adc ebx,ebp ; update u-high and v-low - mov bh,dl ; move v-high into tmap lookup register - mov ah,[bx] ; get second sample, save it in ah - adc edx,esi - adc ebx,ebp - mov dh,bl ; save value of bl - mov bx,cx ; use bx to address color map - mov al,gs:[bx] ; lookup color for pixel 1 - mov bl,ah ; switch to pixel 2 - mov ah,gs:[bx] ; lookup color for pixel 2 - mov es:[di],ax ; output both pixels - mov bl,dh ; restore bl from dh - mov bh,dl - adc ax,ax ; save carry so we can do CMP - add di,2 - cmp di,fs:last_di ; rather than having to decrement cx - jne loop8 - - For a Gouraud shading inner loop, we can now have three -different numbers u, v, and z, which we're all adding at every -step. To do this, we use THREE adc, and we have to shuffle -around which high-bits correspond to which low-bits in a -complex way. I'll leave you to figure this out for yourself, -but here's an attempt at the inner loop. - -loop9 shr ax,1 ; restore carry - mov al,fs:[bx] ; get first sample - mov ah,cl ; save away current z-high into AH - ; this makes AX a value we want to lookup - adc edx,esi ; update v-high and u-low - adc ebx,ebp ; update u-high and z-low - adc ecx,z_v_inc ; update z-high and v-low - mov bh,dl ; move v-high into tmap lookup register - mov ch,fs:[bx] ; get second sample, save it in ch - mov dh,bl ; save value of bl - mov bx,ax - mov al,gs:[bx] ; lookup first color value - mov bl,ch - mov bh,cl - mov ah,gs:[bx] ; lookup second color value - mov es:[di],ax ; output both pixels - mov bl,dh ; restore bl from dh - adc edx,esi - adc ebx,ebp - adc ecx,z_v_inc - mov bh,dl - adc ax,ax ; save carry - add di,2 - cmp di,last_di ; rather than having to decrement cx - jne loop9 - - Notice that both of these loops are significantly slower -than the original loop. I'm not personally aware of any -generally faster way to do this sort of thing (but the code -can be tweaked to be faster). The one exception is -that for flat-run shading, you could precompute the entire -texture with the right lighting. This would require a lot -of storage, of course, but if you view it as a cache, it -would let you get some reuse of information from frame to -frame, since polygons tend to be lit the same from frame to -frame. - - Finally, here's a brief discussion of transparency. -There are two ways to get transparency effects. The first -one is slower, but more flexible. You use _another_ lookup -table. You have to paint the texture that is transparent -after you've drawn things behind it. Then, in the inner -loop, you fetch the texture value (and light it) to draw. -Then you fetch the pixel that's currently in that location. -Lookup in a "transparency" table with those two values as -indices, and write out the result. The idea is that you -do this: table[new][old]. If new is a normal, opaque, -color, then table[new][old] == new, for every value of old. -If new is a special "color" which is supposed to be transparent, -then table[new][old] == old, for every value of old. This causes -old to show through. In addition, you can have translucency -effects, where table[new][old] gives a mixture of the colors -of old and new. This will let you do effects like the -translucent ghosts in the Ultima Underworlds. - - However, the above approach is extremely slow, since you -have to load the value from the pixel map and do the extra -table lookup. But it works for arbitrary polygons. DOOM -only allows transparency on walls, not on ceilings and floors. -Remember we noticed that the special thing about walls is -that u is constant as you draw a column from a wall; you -are walking down a column in the texture map at the same -time you are drawing a column on screen. What this means -is that you can use a data structure which encodes where -the transparency in each column of the texture map is, and -use that _outside_ the inner loop to handle transparency. -For example, your data structure tells you that you have -a run of 8 opaque pixels, then 3 transparent pixels, then -5 more opaque ones. You scale 8, 3, and 5 by the rate at -which you're walking over the textures, and simply treat -this as two seperate opaque runs. - - The details of this method depend on exactly how you're -doing your hidden surface removal, and since it doesn't -generalize to floors&ceilings, much less to arbitrarily -angled polygons, I don't think going into further detail -will be very useful (I've never bothered writing such a -thing, but I'm pretty sure that's all there is to it). - - -TEX -TE The Postman Always Rings Twice -T - - If you're going to write to a slow 16-bit VGA card, you -should try your darndest to always write 2 pixels at a time. - - For texture mapping, your best bet is to build your screen -in a buffer in RAM, and then copy it to the VGA all at once. -You can do this in Mode 13h or in Mode X or Y, as your heart -desires. You should definitely do this if you're painting -pixels more than once while drawing. - - If, however, you wish to get a speedup by not paying -for the extra copy, you might like to write directly to the -VGA card from your inner loop. - - You might not think this is very interesting. If the -write to the screen buffer in regular RAM is fast, how much -can you gain by doing both steps at once, instead of splitting -them in two? - - The reason it is interesting is because the VGA, while -slow to accept multiple writes, will let you continue doing -processing after a single write. What this means is that -if you overlap your texture mapping computation with your -write to the VGA, you can as much as double your speed on -a slow VGA card. For example, the fastest I can blast my -slow VGA card is 45 fps. I can texture map floor-style directly -to it at 30 fps. If I texture map to a memory buffer, -this is still somewhat slow, more than just the difference -between the 30 and 45 fps figures. Thus, my total rate if -I write to an offscreen buffer drops as low as 20 fps, depending -on exactly what I do in the texture map inner loop. - - Ok, so, now suppose you've decided it might be a speedup -to write directly to the VGA. There are two problems. First -of all, if you're in mode X or Y, it's very difficult to -write two bytes at a time, which is necessary for this -approach to be a win. Second of all, even in mode 13h, it's -difficult to write two bytes at a time when you're drawing -a column of pixels. - - I have no answer here. I expect people to stick to -offscreen buffers, or to simply process columns at a time -and write (at excruciatingly slow rates on some cards) to -the VGA only one byte at a time. - - One option is to set up a page flipping mode 13h (which -is possible on some VGA cards), and to paint two independent -but adjacent columns at the same time, so that you can write -a word at a time. I have a very simple demo that does the -latter, but it's not for the faint of heart, and I don't -think it's a win once you have a lot of small polygons. - - Another answer is to have a DOOM-style "low-detail" -mode which computes one pixel, duplicates it, and always -writes both pixels at the same time. - - A final answer is just to ignore the market of people -with slow VGA cards. I wouldn't be surprised if this -approach was commonplace in a year or two. But if you do -so with commercial software, please put a notice of this -requirement on the box. - -TEX -TE Mipmapping (or is it Mip-Mapping?) -T - - Mipmapping is a very straightforward technique that -can be used to significantly improve the quality of your -textures, so much so that textures that you could not -otherwise use because they look ugly become usable. - - The problem that mipmapping addresses is as follows. -When a texture is far in the distance, such that its -on-screen size in pixels is significantly smaller than -its actual size as a texture, only a small number of -pixels will actually be visible. If the texture contains -areas with lots of rapidly varying high contrast data, -the texture may look ugly, and, most importantly, -moire artifacts will occur. (To see this in DOOM, try -shrinking the screen to the smallest setting and going -outside in shareware DOOM. Many of the buildings will -show moire patterns. In registered DOOM, there is -a black-and-blue ceiling pattern which has very bad -artifacts if it is brightly lit. Go to the mission -with the gigantic round acid pool near the beginning. -Cheat to get light amplification goggles (or maybe -invulnerability), and you'll see it.) - - Mipmapping reduces these artifacts by precomputing -some "anti-aliased" textures and using them when the -textures are in the distance. - - The basic idea is to substitute a texture map half as -big when the polygon is so small that only every other -pixel is being drawn anyway. This texture map contains -one pixel for every 2x2 square in the original, and is -the color average of those pixels. - - For a 64x64 texture map, you'd have the original -map, a 32x32 map, a 16x16 map, an 8x8 map, etc. - - The mipmaps will smear out colors and lose details. -You can best test them by forcing them to be displayed -while they're still close to you; once they appear to -be working, set them up as described above. - - Mipmapping causes a somewhat ugly effect when you -see the textures switch from one mipmap to the next. -However, especially for some textures, it is far less -ugly than the effect you would get without them. - - For example, a fine white-and-black checkerboard -pattern (perhaps with some overlaid text) would look -very ugly without mipmapping, as you would see random -collections of white and black pixels (which isn't too -bad), and you would see curving moire patterns (which -is). With mipmapping, at a certain distance the whole -polygon would turn grey. - - I do not believe any existing games for the PC -use mipmapping. However, examining the data file -for the Amiga demo version of Legends of Valour showed -smaller copies of textures, which made it look like -mipmapping was being used. - - Mipmapping requires 33% extra storage for the -extra texture maps (25% for the first, 25% of 25% -for the second, etc.). - - This may also be a good idea for 2D bitmaps which -are scaled (e.g. critters in Underworld & DOOM, or -ships in Wing Commander II--although none of those -appeared to use it.) - - SGI's Reality Engine does mipmapping. Actually, -it does a texturemap lookup on two of the mipmaps, -the "closer" one and the "farther" one, and uses -a weighted average between them depending on which -size is closer to correct. (The RE also does -anti-aliasing, which helps even more.) - - -TEXTURE -TEXUE -TXR Where Do We Go From Here? -X - - The above discussion mostly covers what is basically -the state of the art of texture mapping on the PC. Hopefully -in the future every game will be at least as fast as the -inner loops in this article allow. - - As long as people want full-screen images, it'll -be a while before we have enough computational power -to do more than that. But if we did have more power, -what else could we do with it? - - o Better lighting - o Colored lighting (requires complex lookup tables) - o Phong shading (interpolation of normals--one sqrt() per pixel!) - o Higher resolution (640x400, or 640x400 and anti-alias to 320x200) - o A lot more polygons - o Bump mapping (can be done today with huge amounts of precomputation) - o Curved surfaces diff --git a/16/PCGPE10/TIMER.ASM b/16/PCGPE10/TIMER.ASM deleted file mode 100644 index edc57329..00000000 --- a/16/PCGPE10/TIMER.ASM +++ /dev/null @@ -1,129 +0,0 @@ -;-------------------------------------------------------------------------- -; Here is a source for measuring relative speed of computer. This source -; will NOT function properly under multitaskers, as they use timer them- -; selves. At least DesqView, OS/2 and Windows mess up with timer. -; -; This source is copyright 1994 of Teemu Peltonen aka Quark/Remedy Prods. -; If you modify this source, please do not spread it! You may spread the -; unmodified source as much as you like, but please check that length of -; the actual source (not including this comment between vertical lines) is -; 91 lines! -; -; The way of measuring computer's speed is not the best possible, but it -; works. Here's a small kind of table of speeds: -; -; CPU Output value -; 486DX/33MHz 024Ch -; 486SX/20MHz 03D4h -; 386DX/40MHz 05EDh -; 386DX/16MHz 0DBAh -; 286 /10MHz 1500h -; 086 /4.77MHz 6006h -; -; Notice! Values may differ from these about 2 up or down. You should -; run the tester for about five times and use the value that seems to -; appear most times. Disk caches and others can mess up test. -; -; Thanks to my BBS's users for testing this piece of software! -; -; If you wish to add your computer's speed here, please contact author. -; Feel free to contact me, even if you wouldn't want to add your speed.. -; Contact addresses are: -; teemu.peltonen@stream.nullnet.fi in Internet -; Teemu Peltonen@2:222/100 in Fidonet -; Teemu Peltonen@68:100/100 in DGi-net -; Or call Bitstream BBS (+358-21-4383244) and leave a comment to operator -; (command C). -;-------------------------------------------------------------------------- -stacki segment para stack use16 'stack' - dw 100h dup (?) -stacki ends - -data segment para public use16 'data' -hexval db '0123456789ABCDEF' -stringi db 'Relative speed of computer is ' -d db 0 -c db 0 -b db 0 -a db 0 -endi db 'h.$' -data ends - -code segment para public use16 'code' - assume cs:code, ds:data, ss:stacki -startup: - mov ax, seg data - mov ds, ax - - cli - - mov al, 34h - out 43h, al ;OUT can be used as immediate - ;if register value under 100h - - xor al, al - out 40h, al - out 40h, al - - sti - - mov cx, 1000h ;action here, -here: ;must not take - dec cx ;more than 1/18 - jnz here ;(0.0555) seconds to run - - cli - - mov al, 4h - out 43h, al - - - in al, 40h - mov dl, al - in al, 40h - mov dh, al - - sti - - neg dx ;Action took bx/1193180 seconds - - mov cl, dh - and cl, 11110000b - shr cl, 4 - xor bx, bx - mov bl, cl - mov ah, hexval[bx] - mov d, ah - - mov cl, dh - and cl, 00001111b - xor bx, bx - mov bl, cl - mov ah, hexval[bx] - mov c, ah - - mov cl, dl - and cl, 11110000b - shr cl, 4 - xor bx, bx - mov bl, cl - mov ah, hexval[bx] - mov b, ah - - mov cl, dl - and cl, 00001111b - xor bx, bx - mov bl, cl - mov ah, hexval[bx] - mov a, ah - - - mov ax, 0900h - mov dx, offset stringi - int 21h - - mov ax, 4c00h - int 21h - -code ends - end startup diff --git a/16/PCGPE10/TRIDENT.TXT b/16/PCGPE10/TRIDENT.TXT deleted file mode 100644 index 67d8f07a..00000000 --- a/16/PCGPE10/TRIDENT.TXT +++ /dev/null @@ -1,129 +0,0 @@ - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Programming the Trident SVGA Chip ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - Written for the PC-GPE by Mark Feldman - e-mail address : u914097@student.canberra.edu.au - myndale@cairo.anu.edu.au - - Please read the file SVGINTRO.TXT - (Graphics/SVGA/Intro PC-GPE menu option) - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ THIS FILE MAY NOT BE DISTRIBUTED ³ - ³ SEPARATE TO THE ENTIRE PC-GPE COLLECTION. ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Disclaimer ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ - -I assume no responsibility whatsoever for any effect that this file, the -information contained therein or the use thereof has on you, your sanity, -computer, spouse, children, pets or anything else related to you or your -existance. No warranty is provided nor implied with this information. - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Identifying the Trident SVGA Card ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -There are two Trident SVGA chips, the TVGA 8800 and 8900. - -The Trident SVGA chips can be identified by attempting to change the -Mode Control #1 register as follows: - - Index : 0Eh at port 3C4h - Read/write data from port 3C5h - ÚÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄ¿ - ³ 7 ³ 6 ³ 5 ³ 4 ³ 3 ³ 2 ³ 1 ³ 0 ³ - ÀÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÙ - ³ - PAGE - -First write the value 0Eh to port 3C4h. Then read the value in from port -3C5h and save it. for rest Next write the value 00h to port 3C5h and -read the value back in from the port. If bit 1 in the value read is set -(ie = 1) then a trident chip is present. Finally write the original value -back to port 3C5h to leave the SVGA adapter in it's original state. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Identifying which Trident Chip is Present ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The Trident chip can be identified with the following psuedo code : - -Port[$3C4] := $0B -Port[$3C5] := $00 -hardware_version_number := Port[$3C5] -if hardware_version_number >= 3 then - chip is an 8900 -else - chip is an 8800 - -This procedure leaves the chip in "New Mode". New Mode and Old mode are -discussed below. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Trident Graphics Display Modes ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Mode Resolution Colors Chip ³ - ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ - ³ 5Bh 800x600 16 8800/8900 ³ - ³ 5Ch 640x400 256 8800/8900 ³ - ³ 5Dh 640x480 256 8800/8900 ³ - ³ 5Eh 800x600 256 8900 ³ - ³ 5Fh 1024x768 16 8800/8900 ³ - ³ 61h 768x1024 16 8800/8900 ³ - ³ 62h 1024x768 256 8900 ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Trident Display Memory ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Both Trident chips can map video memory in either 64K or 128K paging -schemes. The 8800 defaults to the 128K paging scheme at power up. This -scheme is known as the "Old Mode". The 8900 defaults to the 64K paging -scheme, the "New Mode". This file will concentrate solely on the 64K new -mode operation. - -The new mode can be set with the following procedure: - -Port[$3C4] := $0B { Set the old mode 128K scheme } -Port[$3C5] := $00 -dummy_variable := Port[$3C5] { Toggle over to the new mode } - -Trident bank switching is weird, REALLY weird! In new mode, the New Mode -Control Register # 1 is used to select the active bank: - - Index : 0Eh at port 3C4h - Read/write data from port 3C5h - ÚÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄ¿ - ³ 7 ³ 6 ³ 5 ³ 4 ³ 3 ³ 2 ³ 1 ³ 0 ³ - ÀÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÙ - ÀÄÂÄÙ ³ ³ - Bank Page Seg - -Bits 3-0 can be considered as a single 4 bit bank number. However, when -you write to video memory the Trident inverts the Page bit to determine -which bank should actually be written to. So if you set these bits to the -value 0 (0000) then bank 0 will be used for all read operations and bank 2 -(0010) will be used for all write operations. - -The following code will set the bank number for all read operations: - -PortW[$3C4] := bank_number shl 8 + $0E; - -The following code will set the bank number for all write operations: - -PortW[$3C4] := (bank_number xor 2) shl 8 + $0E; - -It is important to realise that setting the write bank number changes the -read bank number, and visa-versa. How you are supposed to rapidly transfer -blocks of data around on the Trident screen is beyond me. - diff --git a/16/PCGPE10/TSENG.TXT b/16/PCGPE10/TSENG.TXT deleted file mode 100644 index 41c10ca3..00000000 --- a/16/PCGPE10/TSENG.TXT +++ /dev/null @@ -1,139 +0,0 @@ - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Programming the Tseng SVGA Chip ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - Written for the PC-GPE by Mark Feldman - e-mail address : u914097@student.canberra.edu.au - myndale@cairo.anu.edu.au - - Please read the file SVGINTRO.TXT - (Graphics/SVGA/Intro PC-GPE menu option) - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ THIS FILE MAY NOT BE DISTRIBUTED ³ - ³ SEPARATE TO THE ENTIRE PC-GPE COLLECTION. ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Disclaimer ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ - -I assume no responsibility whatsoever for any effect that this file, the -information contained therein or the use thereof has on you, your sanity, -computer, spouse, children, pets or anything else related to you or your -existance. No warranty is provided nor implied with this information. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Identifying the Tseng SVGA Card ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Tseng Labs have produced two SVGA Chips, the ET3000 and the ET4000. - -The Tseng SVGA chips can be identified by attempting to change the -Miscellaneous register as follows: - - Index : 06h at port 3C0h - Read/write data from port 3C1h - ÚÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄ¿ - ³ 7 ³ 6 ³ 5 ³ 4 ³ 3 ³ 2 ³ 1 ³ 0 ³ - ÀÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÙ - ÀÄÂÄÙ - High - -Output the value 6 to port 3C0h and read a byte from port 3C1h. Modify -the high field in this byte (eg new byte = byte XOR 30h) and write this -new byte to port 3C1h. Read the byte from port 3C1h and see if the byte -was successfully modified, if it was then a Tseng chip is present. Having -done this, write the original byte back to port 3C1h to leave the graphics -adapter in it's original state. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Identifying which Tseng Card is Present ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The ET4000 can be distinguished from the ET3000 by attempting to change the -ET4000 Extended Start Address register as follows: - - Index : 33h at port 3D4h - Read/write data from port 3D5h - ÚÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄ¿ - ³ 7 ³ 6 ³ 5 ³ 4 ³ 3 ³ 2 ³ 1 ³ 0 ³ - ÀÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÙ - ÀÄÂÄÙ ÀÄÂÄÙ - CAD DAD - -The same technique is used as was used to identify the presence of a -Tseng chip, both fields should be modified, written, tested for a successful -write and then restored to their original values. If the change was -successful an ET4000 chip is present, otherwise an ET3000 chip is. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Tseng Graphics Display Modes ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Mode Resolution Colors ³ - ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ - ³ 25h 640x480 16 ³ - ³ 29h 800x600 16 ³ - ³ 2Dh 640x350 256 ³ - ³ 2Eh 640x480 256 ³ - ³ 2Fh 640x400 256 ³ - ³ 30h 800x600 256 ³ - ³ 37h 1024x768 16 ³ - ³ 38h 1024x768 256 ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -All graphics modes in the above table are supported by the ET4000. I am not -sure which modes are supported by the ET3000. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Tseng Display Memory ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -In my opinion the Tseng memory mapping was designed to prevent graphics -programmers from suffering nervous breakdowns! - -Two banks can be mapped to the segment A000:0000-FFFFh, one for -reading and one for writing. The banks can be selected by writing to -the Segment Select Registers at port 3Cdh: - -ET3000 Segment Select Register: - Port 3CDh - ÚÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄ¿ - ³ 7 ³ 6 ³ 5 ³ 4 ³ 3 ³ 2 ³ 1 ³ 0 ³ - ÀÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÙ - ÀÄÄÄÂÄÄÄÙ ÀÄÄÄÂÄÄÄÙ - Read Write - Bank Bank - -ET4000 Segment Select Register: - Port 3CDh - ÚÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄ¿ - ³ 7 ³ 6 ³ 5 ³ 4 ³ 3 ³ 2 ³ 1 ³ 0 ³ - ÀÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÙ - ÀÄÄÄÄÄÂÄÄÄÄÄÙ ÀÄÄÄÄÄÂÄÄÄÄÄÙ - Read Write - Bank Bank - -Both of these registers can be read from as well as written to. - -Each bank is 64K long, has a 64K granularity and is mapped to host -memory A000:0000-FFFFh. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ DPMI and the ET4000 ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Apparently the ET4000 chip is capable of linear addressing in dos protect- -mode programs. To enable this feature write the value 36h to port 3D4h, -read the value from port 3D5h, set the lower nibble (bits 0 -> 3) to the -value 1 and rewrite the value to port 3D5h. Resetting these bits to the -value 0 puts the chip back in regular segmented addressing mode. - -I have no information where or how the entire ET4000 memory would then be -mapped to linear memory. If anyone has more information on this or has a -Tseng card they are willing to try it on let me know. - diff --git a/16/PCGPE10/TUT1.TXT b/16/PCGPE10/TUT1.TXT deleted file mode 100644 index e220d009..00000000 --- a/16/PCGPE10/TUT1.TXT +++ /dev/null @@ -1,369 +0,0 @@ - ÕÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͸ - ³ W E L C O M E ³ - ³ To the VGA Trainer Program ³ ³ - ³ By ³ ³ - ³ DENTHOR of ASPHYXIA ³ ³ ³ - ÔÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ; ³ ³ - ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³ - ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - --==[ PART 1 ]==-- - - - -þ Introduction - - - -Hi there! This is Denthor of ASPHYXIA, AKA Grant Smith. This training -program is aimed at all those budding young demo coders out there. I am -assuming that the reader is fairly young, has a bit of basic Std. 6 math -under his belt, has done a bit of programming before, probably in BASIC, -and wants to learn how to write a demo all of his/her own. - -This I what I am going to do. I am going to describe how certain routines -work, and even give you working source code on how you do it. The source -code will assume that you have a VGA card that can handle the -320x200x256 mode. I will also assume that you have Turbo Pascal 6.0 or -above (this is because some of the code will be in Assembly language, -and Turbo Pascal 6.0 makes this incredibly easy to use). By the end of -the first "run" of sections, you will be able to code some cool demo -stuff all by yourself. The info you need, I will provide to you, but it -will be you who decides on the most spectacular way to use it. - -Why not download some of our demos and see what I'm trying to head you -towards. - -I will be posting one part a week on the Mailbox BBS. I have the first -"run" of sections worked out, but if you want me to also do sections on -other areas of coding, leave a message to Grant Smith in private E-Mail, -or start a conversation here in this conference. I will do a bit of -moderating of a sort, and point out things that have been done wrong. - -In this, the first part, I will show you how you are supposed to set up -your Pascal program, how to get into 320x200x256 graphics mode without a -BGI file, and various methods of putpixels and a clearscreen utility. - -NOTE : I drop source code all through my explanations. You needn't try - to grab all of it from all over the place, at the end of each part I - add a little program that uses all the new routines that we have - learned. If you do not fully understand a section, leave me - private mail telling me what you don't understand or asking how I - got something etc, and I will try to make myself clearer. One - last thing : When you spot a mistake I have made in one of my - parts, leave me mail and I will correct it post-haste. - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ Disclaimer - - - -Hi again, sorry that I have to add this, but here goes. All source code -obtained from this series of instruction programs is used at your own -risk. Denthor and the ASPHYXIA demo team hold no responsibility for any -loss or damage suffered by anyone through the use of this code. Look -guys, the code I'm going to give you has been used by us before in -Demos, Applications etc, and we have never had any compliants of machine -damage, but if something does go wrong with your computer, don't blame -us. Sorry, but that's the way it is. - - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ The MCGA mode and how you get into it in Pascal without a BGI - - -Lets face it. BGI's are next to worthless for demo coding. It is -difficult to find something that is slower then the BGI units for doing -graphics. Another thing is, they wern't really meant for 256 color -screens anyhow. You have to obtain a specific external 256VGA BGI to get -into it in Pascal, and it just doesn't make the grade. - -So the question remains, how do we get into MCGA 320x200x256 mode in -Pascal without a BGI? The answer is simple : Assembly language. -Obviously assembly language has loads of functions to handle the VGA -card, and this is just one of them. If you look in Norton Gides to -Assembly Language, it says this ... - -____________________________________________________________________ -INT 10h, 00h (0) Set Video Mode - - Sets the video mode. - - On entry: AH 00h - AL Video mode - - Returns: None - - Registers destroyed: AX, SP, BP, SI, DI -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - -This is all well and good, but what does it mean? It means that if you -plug in the video mode into AL and call interrupt 10h, SHAZAM! you are -in the mode of your choice. Now, the MCGA video mode is mode 13h, and -here is how we do it in Pascal. - -Procedure SetMCGA; -BEGIN - asm - mov ax,0013h - int 10h - end; -END; - -There you have it! One call to that procedure, and BANG you are in -320x200x256 mode. We can't actually do anything in it yet, so to go back -to text mode, you make the video mode equal to 03h, as seen below : - -Procedure SetText; -BEGIN - asm - mov ax,0003h - int 10h - end; -END; - - -BANG! We are back in text mode! Now, cry all your enquiring minds, what -use is this? We can get into the mode, but how do we actually SHOW -something on the screen? For that, you must move onto the next section -.... - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ Clearing the screen to a specific color - -Now that we are in MCGA mode, how do we clear the screen. The answer is -simple : you must just remember that the base adress of the screen is -$a000. From $a000, the next 64000 bytes are what is actually displayed on -the screen (Note : 320 * 200 = 64000). So to clear the screen, you just use -the fillchar command (a basic Pascal command) like so : - - FillChar (Mem [$a000:0],64000,Col); - -What the mem command passes the Segment base and the Offset of a part of -memory : in this case the screen base is the Segment, and we are starting -at the top of the screen; Offset 0. The 64000 is the size of the screen -(see above), and Col is a value between 0 and 255, which represents the -color you want to clear the screen to. - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ Putting a pixel on the screen (two different methoods) - -If you look in Norton Guides about putting a pixel onto the screen, you -will see this : - - -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - Writes a pixel dot of a specified color at a specified screen - coordinate. - - On entry: AH 0Ch - AL Pixel color - CX Horizontal position of pixel - DX Vertical position of pixel - BH Display page number (graphics modes with more - than 1 page) - - Returns: None - - Registers destroyed: AX, SP, BP, SI, DI -ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ - -As seen from our SetMCGA example, you would write this by doing the following: - -Procedure INTPutpixel (X,Y : Integer; Col : Byte); -BEGIN - asm - mov ah,0Ch - mov al,[col] - mov cx,[x] - mov dx,[y] - mov bx,[1] - int 10h - end; -END; - -The X would be the X-Coordinate, the Y would be the Y-Coordinate, and the Col -would be the color of the pixel to place. Note that MCGA has 256 colors, -numbered 0 to 255. The startoff pallette is pretty grotty, and I will show -you how to alter it in my next lesson, but for now you will have to hunt for -colors that fit in for what you want to do. Luckily, a byte is 0 to 255, so -that is what we pass to the col variable. Have a look at the following. - - CGA = 4 colours. - 4x4 = 16 - EGA = 16 colors. - 16x16 = 256 - VGA = 256 colors. - Therefore an EGA is a CGA squared, and a VGA is an EGA squared ;-) - -Anyway, back to reality. Even though the abouve procedure is written in -assembly language, it is slooow. Why? I hear your enquiring minds cry. The -reason is simple : It uses interrupts (It calls INT 10h). Interrupts are -sloooow ... which is okay for getting into MCGA mode, but not for trying -to put down a pixel lickety-split. So, why not try the following ... - -Procedure MEMPutpixel (X,Y : Integer; Col : Byte); -BEGIN - Mem [VGA:X+(Y*320)]:=Col; -END; - - -The Mem command, as we have seen above, allows you to point at a certain -point in memory ... the starting point is $a000, the base of the VGA's -memory, and then we specify how far into this base memory we start. -Think of the monitor this way. It starts in the top left hand corner at -0. As you increase the number, you start to move across the screen to your -right, until you reach 320. At 320, you have gone all the way across the -screen and come back out the left side, one pixel down. This carries on -until you reach 63999, at the bottom right hand side of the screen. This -is how we get the equation X+(Y*320). For every increased Y, we must -increment the number by 320. Once we are at the beginning of the Y line -we want, we add our X by how far out we want to be. This gives us the -exact point in memory that we want to be at, and then we set it equal to -the pixel value we want. - -The MEM methood of putpixel is much faster, and it is shown in the sample -program at the end of this lesson. The ASPHYXIA team uses neither putpixel; -we use a DMA-Straight-To-Screen-Kill-Yer-Momma-With-An-Axe type putipixel -which is FAST. We will give it out, but only to those of you who show us -you are serious about coding. If you do do anything, upload it to me, -I will be very interested to see it. Remember : If you do glean anything -from these training sessions, give us a mention in your demos and UPLOAD -YOUR DEMO TO US! - -Well, after this is the sample program; have fun with it, UNDERSTAND it, -and next week I will start on fun with the pallette. - -See you all later, - - Denthor - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ TUTPROG1.PAS ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -{$X+} (* This is a handy little trick to know. If you put this at the top - of your program, you do not have to set a variable when calling - a function, i.e. you may just say 'READKEY' instead of - 'CH:=READKEY' *) - -USES Crt; (* This has a few nice functions in it, such as the - READKEY command. *) - -CONST VGA = $a000; (* This sets the constant VGA to the segment of the - VGA screen. *) - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure SetMCGA; { This procedure gets you into 320x200x256 mode. } -BEGIN - asm - mov ax,0013h - int 10h - end; -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure SetText; { This procedure returns you to text mode. } -BEGIN - asm - mov ax,0003h - int 10h - end; -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure Cls (Col : Byte); - { This clears the screen to the specified color } -BEGIN - Fillchar (Mem [$a000:0],64000,col); -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure INTPutpixel (X,Y : Integer; Col : Byte); - { This puts a pixel on the screen using interrupts. } -BEGIN - asm - mov ah,0Ch - mov al,[col] - mov cx,[x] - mov dx,[y] - mov bx,[1] - int 10h - end; -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure TestINTPutpixel; - { This tests out the speed of the INTPutpixel procedure. } -VAR loop1,loop2 : Integer; -BEGIN - For loop1:=0 to 319 do - For loop2:=0 to 199 do - INTPutpixel (loop1,loop2,Random (256)); - Readkey; - Cls (0); -END; - - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure MEMPutpixel (X,Y : Integer; Col : Byte); - { This puts a pixel on the screen by writing directly to memory. } -BEGIN - Mem [VGA:X+(Y*320)]:=Col; -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure TestMEMPutpixel; - { This tests out the speed of the MEMPutpixel procedure. } -VAR loop1,loop2 : Integer; -BEGIN - For loop1:=0 to 319 do - For loop2:=0 to 199 do - MEMPutpixel (loop1,loop2,Random (256)); - Readkey; - Cls (0); -END; - - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -BEGIN (* Of the main program *) - ClrScr; { This clears the text Screen (CRT unit) } - Writeln ('What will happen is that I will clear the screen twice. After'); - Writeln ('each clear screen you will have to hit a key. I will then fill'); - Writeln ('the screen twice with randomlly colored pixels using two different'); - Writeln ('methoods, after each of which you will have to hit a key. I will'); - Writeln ('then return you to text mode.'); - Writeln; Writeln; - Write ('Hit any kay to continue ...'); - Readkey; - - SetMCGA; - CLS (32); - Readkey; - CLS (90); - Readkey; - TestINTPutpixel; - TestMEMPutpixel; - SetText; - - Writeln ('All done. This concludes the first sample program in the ASPHYXIA'); - Writeln ('Training series. You may reach DENTHOR under the name of GRANT'); - Writeln ('SMITH on the MailBox BBS, or leave a message to ASPHYXIA on the'); - Writeln ('ASPHYXIA BBS. Get the numbers from Roblist, or write to :'); - Writeln (' Grant Smith'); - Writeln (' P.O. Box 270'); - Writeln (' Kloof'); - Writeln (' 3640'); - Writeln ('I hope to hear from you soon!'); - Writeln; Writeln; - Write ('Hit any key to exit ...'); - Readkey; -END. (* Of the main program *) \ No newline at end of file diff --git a/16/PCGPE10/TUT10.TXT b/16/PCGPE10/TUT10.TXT deleted file mode 100644 index c6344435..00000000 --- a/16/PCGPE10/TUT10.TXT +++ /dev/null @@ -1,514 +0,0 @@ - ÕÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͸ - ³ W E L C O M E ³ - ³ To the VGA Trainer Program ³ ³ - ³ By ³ ³ - ³ DENTHOR of ASPHYXIA ³ ³ ³ - ÔÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ; ³ ³ - ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³ - ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - --==[ PART 10 ]==-- - - - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ Introduction - -Wow! The trainer has finally reached part 10! This will also be the -first part introduced simultaneously to local BBS's and the INTERNET at -the same time! Yes folks, I put up a copy of previous tutorials onto -various ftp sites, and awaited the flames saying that the net.gurus -already knew this stuff, and why was I wasting disk space! The flames -did not appear (well, except for one), and I got some messages saying -keep it up, so from now on I will upload all future trainers to ftp -sites too (wasp.eng.ufl.edu , cs.uwp.edu etc.). I will also leave a -notice in the USENET groups comp.lang.pascal and comp.sys.ibm.pc.demos -when a new part is finished (Until enough people say stop ;-)) - -I can also be reached at my new E-Mail address, - smith9@batis.bis.und.ac.za - -Well, this tutorial is on Chain-4. When asked to do a trainer on -Chain-4, I felt that I would be walking on much travelled ground (I have -seen numerous trainers on the subject), but the people who asked me said -that they hadn't seen any, so could I do one anyway? Who am I to say no? - -The sample program attached isn't that great, but I am sure that all you -people out there can immediately see the potential that Chain-4 holds. - - -If you would like to contact me, or the team, there are many ways you -can do it : 1) Write a message to Grant Smith/Denthor/Asphyxia in private mail - on the ASPHYXIA BBS. - 2) Write to Denthor, EzE or Goth on Connectix. - 3) Write to : Grant Smith - P.O.Box 270 Kloof - 3640 - Natal - South Africa - 4) Call me (Grant Smith) at (031) 73 2129 (leave a message if you - call during varsity). Call +27-31-73-2129 if you call - from outside South Africa. (It's YOUR phone bill ;-)) - 5) Write to smith9@batis.bis.und.ac.za in E-Mail. - -NB : If you are a representative of a company or BBS, and want ASPHYXIA - to do you a demo, leave mail to me; we can discuss it. -NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling - quite lonely and want to meet/help out/exchange code with other demo - groups. What do you have to lose? Leave a message here and we can work - out how to transfer it. We really want to hear from you! - - - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ What is Chain-4? - -You people out there all have at least 256k vga cards. Most of you have -512k vga cards, and some have 1MB vga cards. But what you see on your -screen, as discussed in previous trainers, is 64k of data! What happened -to the other 192k??? Chain-4 is a method of using all 256k at one time. - -The way this is done is simple. 1 screen = 64k. 64k * 4 = 256k. -Therefore, chain-4 allows you to write to four screens, while displaying -one of them. You can then move around these four screens to see the data -on them. Think of the Chain-4 screen as a big canvas. The viewport, -the bit you see out of, is a smaller rectangle which can be anywhere -over the bigger canvas. - - +----------------------------+ Chain-4 screen - | +--+ | - | | | <- Viewport | - | +--+ | - | | - +----------------------------+ - - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ The size of the chain-4 screen - -The Chain-4 screen, can be any size that adds up to 4 screens. - -For example, it can be 4 screens across and one screen down, or one -screen across and 4 screens down, or two screens across and two screens -down, and any size in between. - -In the sample program, the size is a constant. The size * 8 is how many -pixels across there are on the chain-4 screen, ie - Size = 40 = 320 pixels across = 1 screen across, 4 screens down - Size = 80 = 640 pixels across = 2 screens across, 2 screens down -etc. - -We need to know the size of the screen for almost all dealings with the -Chain-4 screen, for obvious reasons. - - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ Layout of the chain-4 screen, and accessing it - -If you will remember all the way back to Part 1 of this series, I -explained that the memory layout of the MCGA screen is linear. Ie, the -top left hand pixel was pixel zero, the one to the right of it was -number one, the next one was number two etc. With Chain-4, things are -very different. - -Chain-4 gets the 4 screens and chains them together (hence the name :)). -Each screen has a different plane value, and must be accessed -differently. The reason for this is that a segment of memory is only 64k -big, so that we could not fit the entire Chain-4 screen into one -segment. - -All Chain-4 screens are accessed from $a000, just like in MCGA mode. -What we do is, before we write to the screen, find out what plane we are -writing to, set that plane, then plot the pixel. Here is how we find out -how far in to plot the pixel and what plane it is on : - - Instead of the linear model of MCGA mode, ie : - ÚÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄ¿ - ³00³01³02³03³04³05³06³07³08³09³10³11³ ... - - Each plane of the Chain-4 screen accesses the memory in this way : - - Plane 0 : - ÚÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄ¿ - ³00³ ³ ³ ³01³ ³ ³ ³02³ ³ ³ ³ ... - - Plane 1 : - ÚÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄ¿ - ³ ³00³ ³ ³ ³01³ ³ ³ ³02³ ³ ³ ... - - Plane 2 : - ÚÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄ¿ - ³ ³ ³00³ ³ ³ ³01³ ³ ³ ³02³ ³ ... - - Plane 3 : - ÚÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄ¿ - ³ ³ ³ ³00³ ³ ³ ³01³ ³ ³ ³02³ ... - -In this way, by choosing the right plane to write to, we can access all -of the 256k of memory available to us. The plane that we write to can -easily be found by the simple calculation of x mod 4, and the x -coordinate is also found by x div 4. We work out our y by multiplying -it by the size of our chain-4 screen. - -NOTE : It is possible to write to all four planes at once by setting the - correct port values. - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ Uses of Chain-4 - -The uses of Chain-4 are many. One could write data to one screen, then -flip to it (the move_to command is almost instantaneous). This means -that 64k of memory does not need to be set aside for a virtual screen, -you are using the vga cards memory instead! - -Scrolling is much easier to code for in Chain-4 mode. - -It is possible to "tweak" the mode into other resolutions. In our demo, -our vectors were in 320x240 mode, and our dot vectors were in 320x400 -mode. - -The main disadvantage of chain-4 as I see it is the plane swapping, -which can be slow. With a bit of clever coding however, these can be -kept down to a minimum. - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ The sample programs - -The first sample program is GFX.PAS. This is a until in which I have -placed most of our routines from previous tuts. All the procedures and -variables you can see under the INTERFACE section can be used in any -program with GFX in the USES clause. In other words, I could do this : - -USES GFX,crt; - -BEGIN - Setupvirtual; - cls (vaddr,0); - Shutdown; -END. - -This program would compile perfectly. What I suggest you do is this : -Rename the file to a name that suites you (eg your group name), change -the first line of the unit to that name, then add all useful procedures -etc. to the unit. Make it grow :-). - -The second file is the sample program (note the USES GFX,crt; up near -the top!). The program is easy to understand and is documented. The bit -that I want to draw your attention to is the constant, BIT. Because I -am distributing this file to many places in text form, not binary form, -I could not just add a .CEL file with the program. So what I did was -write some text in one color then saved it as a .CEL . I then wrote a -ten line program that did the following : Moving from left to right, it -counted how many pixels were of color zero, then saved the byte value to -an array. When it came across color one, is counted for how long that -went on then saved the byte value and saved it to an array and so on. -When it was finished, I converted the array into a text file in the -CONST format. Not too cunning, but I thought I had better explain it ;-) - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ In closing - -There are other documents and sample programs available on Chain-4 and -it's like : Try XLIB for one... - -Finally! Some BBS's have joined my BBS list! (Okay, only two new ones, -but it's a start ;-)) All you international BBS's! If you will regularly -download the tuts from an FTP site, give me your names! - -I own a car. The car's name is Bob. A few days ago, Bob was in an -accident, and now has major damage to his front. Knowing insurance, I -probably won't get much, probably nothing (the other guy wasn't insured, -and I am only 18 :( ). I will probably have to find work in order to pay -for my repairs. The point to this meandering is this : I am upset, so if -you think you are getting a quote, you can just forget it. - -Oh, well. Life goes on! - -See you next time, - - Denthor - -These fine BBS's carry the ASPHYXIA DEMO TRAINER SERIES : (alphabetical) - -ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍËÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍËÍÍÍÍÍËÍÍÍËÍÍÍÍËÍÍÍÍ» -ºBBS Name ºTelephone No. ºOpen ºMsgºFileºPastº -ÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÍÍÍÍÍÎÍÍÍÎÍÍÍÍÎÍÍÍ͹ -ºASPHYXIA BBS #1 º(031) 765-5312 ºALL º * º * º * º -ºASPHYXIA BBS #2 º(031) 765-6293 ºALL º * º * º * º -ºConnectix BBS º(031) 266-9992 ºALL º º * º * º -ºPOP! º(012) 661-1257 ºALL º º * º * º -ºPure Surf BBS º(031) 561-5943 ºA/H º º * º * º -ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÊÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÊÍÍÍÍÍÊÍÍÍÊÍÍÍÍÊÍÍÍͼ - -For international users : If you live outside the Republic of South -Africa, do the following : Dial +27, dont dial the first 0, but dial -the rest of the number. Eg, for the ASPHYXIA BBS : +27-31-765-5312 - -Open = Open at all times or only A/H -Msg = Available in message base -File = Available in file base -Past = Previous Parts available - - -ÚÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ C4TUT.PAS ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÙ - -(* -Well folks, here it is - the long awaited for Chain-4 trainer. The -routines are commented so I'm not going to say too much more here, -except a few things. - -1: If ya don't understand this (not suprising its bloody cryptic!) - then if ur serious go out and buy - Programming the EGA & VGA Cards - I don't know who the book is by, so don't ask. Perhaps you know Greg? - -2: The code is unoptimised. I wrote it specifically for this conf. and - I'm buggered if I'm gonna give out my wholely (sp? ahh stuff it :-)) - optimised code. If you want it faster, OPTIMISE IT!! - HINT: Its faster to load ax, with a low byte/high byte combination - and out a word instead of a byte at a time. If u don't know - what I'm talking about, too bad :-) - -3: If you use/like/whatever this code, please give Asphyxia a mention. - It wos bloody hard work figuring out how all this cr*p works, we - couldn't have done it with out a little guidence (thanx Gregie Poo). - -4: LiveWire got interested in the whole tut/trainer idea and MAY be - putting together a doc on how the whole thing works, including - Pel-Panning which I haven't included here. - - -5: Good luck with the code, and if you write anything with it, I'd - appreciate having a look at it :-). Feel free to direct any comments - about the code to me in this conf. Or at one of the contact addresses - given in the code. - - -l8rs -EzE / Asphyxia - - - ---------------------------------=[ Cut Here ]=------------------------- -*) -{$X+,G+} -Program Chain4_Tut; -Uses - Crt; - - -Const - Size : Byte = 80; - - -Var Loop : Integer; - - - -Procedure Init_C4; Assembler; -Asm - mov ax, 0013h - int 10h { set up bios initially for 13h } - - mov dx, 03c4h { Sequencer Address Register } - mov al, 4 { Index 4 - Memory mode } - out dx, al { select it. } - inc dx { 03c5h - here we set the mem mode. } - in al, dx { get whats already inside the reg } - and al, 11110111b { un-set 4th bit - chain4 } - out dx, al - - mov dx, 3d4h - mov al, 13h { Offset Register - allocates amt. mem for } - out dx, al { 1 displayable line as - length div 8, so } - inc dx { we use 80 (80*8) = 640 = 2 pages across } - mov al, [Size] { and cause of chain-4 i.e. 256k display } - out dx, al { mem, 2 pages down for four pages } - - { NOTE: setting AL above to 40 selects 1 } - { page across and four down (nice for } - { 1942 type scrolling games) and setting } - { AL to 160 selects 4 pages across and 1 } - { down, nice for horizontal scrolling } - -End; - - - -Procedure Cls_C4; Assembler; -Asm - mov dx, 03c4h { 03c4h } - mov al, 2 { Map Mask Register } - out dx, al - inc dx - mov al, 00001111b { Select all planes to write to } - out dx, al { Doing this to clear all planes at once } - - mov ax, 0a000h - mov es, ax - xor di, di { set es:di = Screen Mem } - mov ax, 0000h { colour to put = black } - mov cx, 32768 { 32768 (words) *2 = 65536 bytes - vga mem } - cld - rep stosw { clear it } -End; - - - -Procedure PutPixel_C4(X, Y : Integer; Col : Byte); Assembler; -Asm - mov ax, [Y] { Y val multiplied by... } - xor bx, bx - mov bl, [Size] { Size.... } - shl bx, 1 { *2 - just 'cause! (I can't remember why!)} - mul bx - mov bx, ax - - mov ax, [X] - mov cx, ax - shr ax, 2 - add bx, ax { add X val div 4 (four planes) } - - and cx, 00000011b { clever way of finding x mod 4, i.e. } - mov dx, 03c4h { which plane we're in. } - mov al, 2 { then use 03c4h index 2 - write plane sel.} - out dx, al { to set plane to write to. } - mov al, 1 { plane to write to = 1 shl (X mod 4) } - shl al, cl - inc dx - out dx, al - - mov ax, 0a000h - mov es, ax - mov al, [Col] - mov es: [bx], al { then write pixel. } -End; - - -Function GetPixel_C4(X, Y : Integer): Byte; Assembler; -Asm - mov ax, [Y] { Y val multiplied by... } - xor bx, bx - mov bl, [Size] { Size.... } - shl bx, 1 { *2 - just 'cause! (I can't remember why!)} - mul bx - mov bx, ax - - mov ax, [X] - mov cx, ax - shr ax, 2 - add bx, ax { add X val div 4 (four planes) } - - and cx, 00000011b { clever way of finding x mod 4, i.e. } - mov dx, 03c4h { which plane we're in. } - mov al, 4h { then use 03c4h index 4 - read plane sel. } - out dx, al { to set plane to read from. } - mov al, cl { Plane to read from = X mod 4 } - inc dx - out dx, al - - mov ax, 0a000h - mov es, ax - mov al, es: [bx] { then return pixel read } -End; - - - -Procedure MoveScr_C4(X,Y : Integer); Assembler; -Asm - mov ax, [Y] { Y val multiplied by... } - xor bx, bx - mov bl, [Size] { Size.... } - shl bx, 1 { *2 - just 'cause! (I can't remember why!)} - mul bx - mov bx, ax - - add bx, [X] { Add X val } - - mov dx, 03d4h - mov al, 0ch { CRTC address reg. } - out dx, al { Start Address High Reg. } - inc dx - mov al, bh { send high byte of start address. } - out dx, al - - dec dx - mov al, 0dh { Start Address Low Reg. } - out dx, al - inc dx - mov al, bl { send low byte of start address. } - out dx, al - -End; - - -Procedure SetText; Assembler; -Asm - mov ax, 0003h - int 10h -End; - -Procedure Creds; -Begin - SetText; - While KeyPressed do ReadKey; - - Asm - mov ah, 1 - mov ch, 1 - mov cl, 0 - int 10h - End; - - WriteLn('Chain-4 Trainer...'); - WriteLn('By EzE of Asphyxia.'); - WriteLn; - WriteLn('Contact Us on ...'); - WriteLn; - WriteLn; - WriteLn('the Asphyxia BBS (031) - 7655312'); - WriteLn; - WriteLn('Email : eze@'); - WriteLn(' asphyxia@'); - WriteLn(' edwards@'); - WriteLn(' bailey@'); - WriteLn(' mcphail@'); - WriteLn(' beastie.cs.und.ac.za'); - WriteLn; - WriteLn('or peter.edwards@datavert.co.za'); - WriteLn; - WriteLn('Write me snail-mail at...'); - WriteLn('P.O. Box 2313'); - WriteLn('Hillcrest'); - WriteLn('Natal'); - WriteLn('3650'); - Asm - mov ah, 1 - mov ch, 1 - mov cl, 0 - int 10h - End; - -End; - - - - -Begin - Init_C4; - Cls_C4; - Repeat - Putpixel_C4(Random(320),Random(200),Random(256)+1); - Until KeyPressed; - For Loop := 0 to 80 do - begin - MoveScr_C4(0,Loop); - Delay(10); - End; - ReadKey; - Loop := GetPixel_C4(100,100); - Creds; - WriteLn('Colour at location X:100, Y:100 was: ',Loop); -End. - ---------------------------------=[ Cut Here ]=------------------------- diff --git a/16/PCGPE10/TUT2.TXT b/16/PCGPE10/TUT2.TXT deleted file mode 100644 index a97738b7..00000000 --- a/16/PCGPE10/TUT2.TXT +++ /dev/null @@ -1,616 +0,0 @@ - ÕÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͸ - ³ W E L C O M E ³ - ³ To the VGA Trainer Program ³ ³ - ³ By ³ ³ - ³ DENTHOR of ASPHYXIA ³ ³ ³ - ÔÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ; ³ ³ - ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³ - ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - --==[ PART 2 ]==-- - - - -þ Introduction - - - -Hi there again! This is Grant Smith, AKA Denthor of ASPHYXIA. This is the -second part of my Training Program for new programmers. I have only had a -lukewarm response to my first part of the trainer series ... remember, if -I don't hear from you, I will assume that you are all dead and will stop -writing the series ;-). Also, if you do get in contact with me I will give -you some of our fast assembly routines which will speed up your demos no -end. So go on, leave mail to GRANT SMITH in the main section of the -MailBox BBS, start up a discussion or ask a few questions in this Conference, -leave mail to ASPHYXIA on the ASPHYXIA BBS, leave mail to Denthor on -Connectix, or write to Grant Smith, - P.O.Box 270 - Kloof - 3640 -See, there are many ways you can get in contact with me! Use one of them! - -In this part, I will put the Pallette through it's paces. What the hell is -a pallette? How do I find out what it is? How do I set it? How do I stop -the "fuzz" that appears on the screen when I change the pallette? How do -I black out the screen using the pallette? How do I fade in a screen? -How do I fade out a screen? Why are telephone calls so expensive? -Most of these quesions will be answered in this, the second part of my -Trainer Series for Pascal. - - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ What is the Pallette? - -A few weeks ago a friend of mine was playing a computer game. In the game -there was a machine with stripes of blue running across it. When the -machine was activated, while half of the the blue stripes stayed the same, -the other half started to change color and glow. He asked me how two stripes -of the same color suddenly become different like that. The answer is simple: -the program was changing the pallette. As you know from Part 1, there are -256 colors in MCGA mode, numbered 0 to 255. What you don't know is that each -if those colors is made up of different intensities of Red, Green and Blue, -the primary colors (you should have learned about the primary colors at -school). These intensities are numbers between 0 and 63. The color of -bright red would for example be obtained by setting red intensity to 63, -green intensity to 0, and blue intensity to 0. This means that two colors -can look exactly the same, eg you can set color 10 to bright red and color -78 to color bright red. If you draw a picture using both of those colors, -no-one will be able to tell the difference between the two.. It is only -when you again change the pallette of either of them will they be able to -tell the difference. Also, by changing the whole pallette, you can obtain -the "Fade in" and "Fade out" effects found in many demos and games. -Pallette manipulation can become quite confusing to some people, because -colors that look the same are in fact totally seperate. - - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ How do I read in the pallette value of a color? - -This is very easy to do. To read in the pallette value, you enter in the -number of the color you want into port $3c7, then read in the values of -red, green and blue respectively from port $3c9. Simple, huh? Here is a -procedure that does it for you : - -Procedure GetPal(ColorNo : Byte; Var R,G,B : Byte); - { This reads the values of the Red, Green and Blue values of a certain - color and returns them to you. } -Begin - Port[$3c7] := ColorNo; - R := Port[$3c9]; - G := Port[$3c9]; - B := Port[$3c9]; -End; - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ How do I set the pallette value of a color? - -This is also as easy as 3.1415926535897932385. What you do is you enter in -the number of the color you want to change into port $3c8, then enter the -values of red, green and blue respectively into port $3c9. Because you are -all so lazy I have written the procedure for you ;-) - - -Procedure Pal(ColorNo : Byte; R,G,B : Byte); - { This sets the Red, Green and Blue values of a certain color } -Begin - Port[$3c8] := ColorNo; - Port[$3c9] := R; - Port[$3c9] := G; - Port[$3c9] := B; -End; - - -Asphyxia doesn't use the above pallete procedures, we use assembler versions, -which will be given to PEOPLE WHO RESPOND TO THIS TRAINER SERIES (HINT, -HINT) - - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ How do I stop the "fuzz" that appears on my screen when I change the - pallette? - -If you have used the pallette before, you will have noticed that there is -quite a bit of "fuzz" on the screen when you change it. The way we counter -this is as follows : There is an elctron beam on your monitor that is -constantly updating your screen from top to bottom. As it gets to the -bottom of the screen, it takes a while for it to get back up to the top of -the screen to start updating the screen again. The period where it moves -from the bottom to the top is called the Verticle Retrace. During the -verticle retrace you may change the pallette without affecting what is -on the screen. What we do is that we wait until a verticle retrace has -started by calling a certain procedure; this means that everything we do -now will only be shown after the verticle retrace, so we can do all sorts -of strange and unusual things to the screen during this retrace and only -the results will be shown when the retrace is finished. This is way cool, -as it means that when we change the pallette, the fuzz doesn't appear on -the screen, only the result (the changed pallette), is seen after the -retrace! Neat, huh? ;-) I have put the purely assembler WaitRetrace routine -in the sample code that follows this message. Use it wisely, my son. - -NOTE : WaitRetrace can be a great help to your coding ... code that fits - into one retrace will mean that the demo will run at the same - speed no matter what your computer speed (unless you are doing a lot - during the WaitRetrace and the computer is slooooow). Note that in - the following sample program and in our SilkyDemo, the thing will run - at the same speed whether turbo is on or off. - - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ How do I black out the screen using the pallette? - -This is basic : just set the Red, Green and Blue values of all colors to -zero intensity, like so : - -Procedure Blackout; - { This procedure blackens the screen by setting the pallette values of - all the colors to zero. } -VAR loop1:integer; -BEGIN - WaitRetrace; - For loop1:=0 to 255 do - Pal (loop1,0,0,0); -END; - - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ How do I fade in a screen? - -Okay, this can be VERY effective. What you must first do is grab the -pallette into a variable, like so : - - VAR Pall := Array [0.255,1..3] of BYTE; - -0 to 255 is for the 256 colors in MCGA mode, 1 to 3 is red, green and blue -intensity values; - -Procedure GrabPallette; -VAR loop1:integer; -BEGIN - For loop1:=0 to 255 do - Getpal (loop1,pall[loop1,1],pall[loop1,2],pall[loop1,3]); -END; - -This loads the entire pallette into variable pall. Then you must blackout -the screen (see above), and draw what you want to screen without the -construction being shown. Then what you do is go throgh the pallette. For -each color, you see if the individual intensities are what they should be. -If not, you increase them by one unit until they are. Beacuse intensites -are in a range from 0 to 63, you only need do this a maximum of 64 times. - -Procedure Fadeup; -VAR loop1,loop2:integer; - Tmp : Array [1..3] of byte; - { This is temporary storage for the values of a color } -BEGIN - For loop1:=1 to 64 do BEGIN - { A color value for Red, green or blue is 0 to 63, so this loop only - need be executed a maximum of 64 times } - WaitRetrace; - For loop2:=0 to 255 do BEGIN - Getpal (loop2,Tmp[1],Tmp[2],Tmp[3]); - If Tmp[1]0 then dec (Tmp[1]); - If Tmp[2]>0 then dec (Tmp[2]); - If Tmp[3]>0 then dec (Tmp[3]); - { If the Red, Green or Blue values of color loop2 are not yet zero, - then, decrease them by one. } - Pal (loop2,Tmp[1],Tmp[2],Tmp[3]); - { Set the new, altered pallette color. } - END; - END; -END; - -Again, to slow the above down, put in a delay above the WaitRetrace. Fading -out the screen looks SO much more impressive then just clearing the screen; -it can make a world of difference in the impression your demo etc will -leave on the people viewing it. To restore the pallette, just do this : - -Procedure RestorePallette; -VAR loop1:integer; -BEGIN - WaitRetrace; - For loop1:=0 to 255 do - pal (loop1,Pall[loop1,1],Pall[loop1,2],Pall[loop1,3]); -END; - - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ In closing - -Well, there are most of those origional questions answered ;-) The following -sample program is quite big, so it might take you a while to get around it. -Persevere and thou shalt overcome. Pallette manipulation has been a thorn -in many coders sides for quite some time, yet hopefully I have shown you -all how amazingly simple it is once you have grasped the basics. - -I need more feedback! In which direction would you like me to head? Is there -any particular section you would like more info on? Also, upload me your -demo's, however trivial they might seem. We really want to get in contact -with/help out new and old coders alike, but you have to leave us that message -telling us about yourself and what you have done or want to do. - -IS THERE ANYBODY OUT THERE!?! - -P.S. Our new demo should be out soon ... it is going to be GOOOD ... keep - an eye out for it. - - [ And so she came across him, slumped over his keyboard - yet again . 'It's three in the morning' she whispered. - 'Let's get you to bed'. He stirred, his face bathed in - the dull light of his monitor. He mutters something. - As she leans across him to disconnect the power, she - asks him; 'Was it worth it?'. His answer surprises her. - 'No.' he says. In his caffiene-enduced haze, he smiles. - 'But it sure is a great way to relax.' ] - - Grant Smith - Tue 13 July, 1993 - 2:23 am. - -See you next week! - - Denthor - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ TUTPROG2.PAS ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -{$X+} - -Uses Crt; - -CONST VGA=$a000; - -Var Pall,Pall2 : Array[0..255,1..3] of Byte; - { This declares the PALL variable. 0 to 255 signify the colors of the - pallette, 1 to 3 signifies the Red, Green and Blue values. I am - going to use this as a sort of "virtual pallette", and alter it - as much as I want, then suddenly bang it to screen. Pall2 is used - to "remember" the origional pallette so that we can restore it at - the end of the program. } - - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure SetMCGA; { This procedure gets you into 320x200x256 mode. } -BEGIN - asm - mov ax,0013h - int 10h - end; -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure SetText; { This procedure returns you to text mode. } -BEGIN - asm - mov ax,0003h - int 10h - end; -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -procedure WaitRetrace; assembler; - { This waits until you are in a Verticle Retrace ... this means that all - screen manipulation you do only appears on screen in the next verticle - retrace ... this removes most of the "fuzz" that you see on the screen - when changing the pallette. It unfortunately slows down your program - by "synching" your program with your monitor card ... it does mean - that the program will run at almost the same speed on different - speeds of computers which have similar monitors. In our SilkyDemo, - we used a WaitRetrace, and it therefore runs at the same (fairly - fast) speed when Turbo is on or off. } - -label - l1, l2; -asm - mov dx,3DAh -l1: - in al,dx - and al,08h - jnz l1 -l2: - in al,dx - and al,08h - jz l2 -end; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure GetPal(ColorNo : Byte; Var R,G,B : Byte); - { This reads the values of the Red, Green and Blue values of a certain - color and returns them to you. } -Begin - Port[$3c7] := ColorNo; - R := Port[$3c9]; - G := Port[$3c9]; - B := Port[$3c9]; -End; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure Pal(ColorNo : Byte; R,G,B : Byte); - { This sets the Red, Green and Blue values of a certain color } -Begin - Port[$3c8] := ColorNo; - Port[$3c9] := R; - Port[$3c9] := G; - Port[$3c9] := B; -End; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure Putpixel (X,Y : Integer; Col : Byte); - { This puts a pixel on the screen by writing directly to memory. } -BEGIN - Mem [VGA:X+(Y*320)]:=Col; -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure line(a,b,c,d,col:integer); - { This draws a line from a,b to c,d of color col. } - Function sgn(a:real):integer; - BEGIN - if a>0 then sgn:=+1; - if a<0 then sgn:=-1; - if a=0 then sgn:=0; - END; -var u,s,v,d1x,d1y,d2x,d2y,m,n:real; - i:integer; -BEGIN - u:= c - a; - v:= d - b; - d1x:= SGN(u); - d1y:= SGN(v); - d2x:= SGN(u); - d2y:= 0; - m:= ABS(u); - n := ABS(v); - IF NOT (M>N) then - BEGIN - d2x := 0 ; - d2y := SGN(v); - m := ABS(v); - n := ABS(u); - END; - s := INT(m / 2); - FOR i := 0 TO round(m) DO - BEGIN - putpixel(a,b,col); - s := s + n; - IF not (s0 then dec (Tmp[1]); - If Tmp[2]>0 then dec (Tmp[2]); - If Tmp[3]>0 then dec (Tmp[3]); - { If the Red, Green or Blue values of color loop2 are not yet zero, - then, decrease them by one. } - Pal (loop2,Tmp[1],Tmp[2],Tmp[3]); - { Set the new, altered pallette color. } - END; - END; -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure RestorePallette; - { This procedure restores the origional pallette } -VAR loop1:integer; -BEGIN - WaitRetrace; - For loop1:=0 to 255 do - pal (loop1,Pall2[loop1,1],Pall2[loop1,2],Pall2[loop1,3]); -END; - - -BEGIN - ClrScr; - Writeln ('This program will draw lines of different colors across the'); - Writeln ('screen and change them only by changing their pallette values.'); - Writeln ('The nice thing about using the pallette is that one pallette'); - Writeln ('change changes the same color over the whole screen, without'); - Writeln ('you having to redraw it. Because I am using a WaitRetrace'); - Writeln ('command, turning on and off your turbo during the demonstration'); - Writeln ('should have no effect.'); - Writeln; - Writeln ('The second part of the demo blacks out the screen using the'); - Writeln ('pallette, fades in the screen, waits for a keypress, then fades'); - Writeln ('it out again. I haven''t put in any delays for the fadein/out,'); - Writeln ('so you will have to put ''em in yourself to get it to the speed you'); - Writeln ('like. Have fun and enjoy! ;-)'); - Writeln; Writeln; - Writeln ('Hit any key to continue ...'); - Readkey; - SetMCGA; - GrabPallette; - SetUpScreen; - repeat - PalPlay; - { Call the PalPlay procedure repeatedly until a key is pressed. } - Until Keypressed; - Readkey; - { Read in the key pressed otherwise it is left in the keyboard buffer } - Blackout; - HiddenScreenSetup; - FadeUp; - Readkey; - FadeDown; - Readkey; - RestorePallette; - SetText; - Writeln ('All done. This concludes the second sample program in the ASPHYXIA'); - Writeln ('Training series. You may reach DENTHOR under the name of GRANT'); - Writeln ('SMITH on the MailBox BBS, or leave a message to ASPHYXIA on the'); - Writeln ('ASPHYXIA BBS. Get the numbers from Roblist, or write to :'); - Writeln (' Grant Smith'); - Writeln (' P.O. Box 270'); - Writeln (' Kloof'); - Writeln (' 3640'); - Writeln ('I hope to hear from you soon!'); - Writeln; Writeln; - Write ('Hit any key to exit ...'); - Readkey; -END. diff --git a/16/PCGPE10/TUT3.TXT b/16/PCGPE10/TUT3.TXT deleted file mode 100644 index a70a8013..00000000 --- a/16/PCGPE10/TUT3.TXT +++ /dev/null @@ -1,624 +0,0 @@ - ÕÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͸ - ³ W E L C O M E ³ - ³ To the VGA Trainer Program ³ ³ - ³ By ³ ³ - ³ DENTHOR of ASPHYXIA ³ ³ ³ - ÔÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ; ³ ³ - ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³ - ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - --==[ PART 3 ]==-- - - - -þ Introduction - - - -Greetings! This is the third part of the VGA Trainer series! Sorry it -took so long to get out, but I had a running battle with the traffic -department for three days to get my car registered, and then the MailBox -went down. Ahh, well, life stinks. Anyway, today will do some things -vital to most programs : Lines and circles. - -Watch out for next week's part : Virtual screens. The easy way to -eliminate flicker, "doubled sprites", and subjecting the user to watch -you building your screen. Almost every ASPHYXIA demo has used a virtual -screen (with the exception of the SilkyDemo), so this is one to watch out -for. I will also show you how to put all of these loose procedures into -units. - -If you would like to contact me, or the team, there are many ways you -can do it : 1) Write a message to Grant Smith in private mail here on - the Mailbox BBS. - 2) Write a message here in the Programming conference here - on the Mailbox (Preferred if you have a general - programming query or problem others would benefit from) - 3) Write to ASPHYXIA on the ASPHYXIA BBS. - 4) Write to Denthor, Eze or Livewire on Connectix. - 5) Write to : Grant Smith - P.O.Box 270 Kloof - 3640 - 6) Call me (Grant Smith) at 73 2129 (leave a message if you - call during varsity) - -NB : If you are a representative of a company or BBS, and want ASPHYXIA - to do you a demo, leave mail to me; we can discuss it. -NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling - quite lonely and want to meet/help out/exchange code with other demo - groups. What do you have to lose? Leave a message here and we can work - out how to transfer it. We really want to hear from you! - - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ Circle Algorithim - -You all know what a circle looks like. But how do you draw one on the -computer? - -You probably know circles drawn with the degrees at these points : - - 0 - ÜÛ|ÛÜ - ÛÛÛ|ÛÛÛ - 270 ----+---- 90 - ÛÛÛ|ÛÛÛ - ßÛ|Ûß - 180 - -Sorry about my ASCI ;-) ... anyway, Pascal doesn't work that way ... it -works with radians instead of degrees. (You can convert radians to degrees, -but I'm not going to go into that now. Note though that in pascal, the -circle goes like this : - - 270 - ÜÛ|ÛÜ - ÛÛÛ|ÛÛÛ - 180 ----+---- 0 - ÛÛÛ|ÛÛÛ - ßÛ|Ûß - 90 - - -Even so, we can still use the famous equations to draw our circle ... -(You derive the following by using the theorem of our good friend -Pythagoras) - Sin (deg) = Y/R - Cos (deg) = X/R -(This is standard 8(?) maths ... if you haven't reached that level yet, -take this to your dad, or if you get stuck leave me a message and I'll -do a bit of basic Trig with you. I aim to please ;-)) - -Where Y = your Y-coord - X = your X-coord - R = your radius (the size of your circle) - deg = the degree - -To simplify matters, we rewrite the equation to get our X and Y values : - - Y = R*Sin(deg) - X = R*Cos(deg) - -This obviousy is perfect for us, because it gives us our X and Y co-ords -to put into our putpixel routine (see Part 1). Because the Sin and Cos -functions return a Real value, we use a round function to transform it -into an Integer. - - Procedure Circle (oX,oY,rad:integer;Col:Byte); - VAR deg:real; - X,Y:integer; - BEGIN - deg:=0; - repeat - X:=round(rad*COS (deg)); - Y:=round(rad*sin (deg)); - putpixel (x+ox,y+oy,Col); - deg:=deg+0.005; - until (deg>6.4); - END; - -In the above example, the smaller the amount that deg is increased by, -the closer the pixels in the circle will be, but the slower the procedure. -0.005 seem to be best for the 320x200 screen. NOTE : ASPHYXIA does not use -this particular circle algorithm, ours is in assembly language, but this -one should be fast enough for most. If it isn't, give us the stuff you are -using it for and we'll give you ours. - - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ Line algorithms - -There are many ways to draw a line on the computer. I will describe one -and give you two. (The second one you can figure out for yourselves; it -is based on the first one but is faster) - -The first thing you need to do is pass what you want the line to look -like to your line procedure. What I have done is said that x1,y1 is the -first point on the screen, and x2,y2 is the second point. We also pass the -color to the procedure. (Remember the screens top left hand corner is (0,0); -see Part 1) - -Ie. o (X1,Y1) - ooooooooo - ooooooooo - oooooooo (X2,Y2) - -Again, sorry about my drawings ;-) - -To find the length of the line, we say the following : - - XLength = ABS (x1-x2) - YLength = ABS (y1-y2) - -The ABS function means that whatever the result, it will give you an -absolute, or posotive, answer. At this stage I set a variable stating -wheter the difference between the two x's are negative, zero or posotive. -(I do the same for the y's) If the difference is zero, I just use a loop -keeping the two with the zero difference posotive, then exit. - -If neither the x's or y's have a zero difference, I calculate the X and Y -slopes, using the following two equations : - - Xslope = Xlength / Ylength - Yslope = Ylength / Xlength - -As you can see, the slopes are real numbers. -NOTE : XSlope = 1 / YSlope - -Now, there are two ways of drawing the lines : - - X = XSlope * Y - Y = YSlope * X - -The question is, which one to use? if you use the wrong one, your line -will look like this : - - o - o - o - -Instead of this : - - ooo - ooo - ooo - -Well, the solution is as follows : - - *\``|``/* - ***\|/*** - ----+---- - ***/|\*** - */``|``\* - -If the slope angle is in the area of the stars (*) then use the first -equation, if it is in the other section (`) then use the second one. -What you do is you calculate the variable on the left hand side by -putting the variable on the right hand side in a loop and solving. Below -is our finished line routine : - -Procedure Line (x1,y1,x2,y2:integer;col:byte); -VAR x,y,xlength,ylength,dx,dy:integer; - xslope,yslope:real; -BEGIN - xlength:=abs (x1-x2); - if (x1-x2)<0 then dx:=-1; - if (x1-x2)=0 then dx:=0; - if (x1-x2)>0 then dx:=+1; - ylength:=abs (y1-y2); - if (y1-y2)<0 then dy:=-1; - if (y1-y2)=0 then dy:=0; - if (y1-y2)>0 then dy:=+1; - if (dy=0) then BEGIN - if dx<0 then for x:=x1 to x2 do - putpixel (x,y1,col); - if dx>0 then for x:=x2 to x1 do - putpixel (x,y1,col); - exit; - END; - if (dx=0) then BEGIN - if dy<0 then for y:=y1 to y2 do - putpixel (x1,y,col); - if dy>0 then for y:=y2 to y1 do - putpixel (x1,y,col); - exit; - END; - xslope:=xlength/ylength; - yslope:=ylength/xlength; - if (yslope/xslope<1) and (yslope/xslope>-1) then BEGIN - if dx<0 then for x:=x1 to x2 do BEGIN - y:= round (yslope*x); - putpixel (x,y,col); - END; - if dx>0 then for x:=x2 to x1 do BEGIN - y:= round (yslope*x); - putpixel (x,y,col); - END; - END - ELSE - BEGIN - if dy<0 then for y:=y1 to y2 do BEGIN - x:= round (xslope*y); - putpixel (x,y,col); - END; - if dy>0 then for y:=y2 to y1 do BEGIN - x:= round (xslope*y); - putpixel (x,y,col); - END; - END; -END; - -Quite big, isn't it? Here is a much shorter way of doing much the same -thing : - -function sgn(a:real):integer; -begin - if a>0 then sgn:=+1; - if a<0 then sgn:=-1; - if a=0 then sgn:=0; -end; - -procedure line(a,b,c,d,col:integer); -var u,s,v,d1x,d1y,d2x,d2y,m,n:real; - i:integer; -begin - u:= c - a; - v:= d - b; - d1x:= SGN(u); - d1y:= SGN(v); - d2x:= SGN(u); - d2y:= 0; - m:= ABS(u); - n := ABS(v); - IF NOT (M>N) then - BEGIN - d2x := 0 ; - d2y := SGN(v); - m := ABS(v); - n := ABS(u); - END; - s := INT(m / 2); - FOR i := 0 TO round(m) DO - BEGIN - putpixel(a,b,col); - s := s + n; - IF not (s6.4); -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure Line2 (x1,y1,x2,y2:integer;col:byte); - { This draws a line from x1,y1 to x2,y2 using the first method } -VAR x,y,xlength,ylength,dx,dy:integer; - xslope,yslope:real; -BEGIN - xlength:=abs (x1-x2); - if (x1-x2)<0 then dx:=-1; - if (x1-x2)=0 then dx:=0; - if (x1-x2)>0 then dx:=+1; - ylength:=abs (y1-y2); - if (y1-y2)<0 then dy:=-1; - if (y1-y2)=0 then dy:=0; - if (y1-y2)>0 then dy:=+1; - if (dy=0) then BEGIN - if dx<0 then for x:=x1 to x2 do - putpixel (x,y1,col); - if dx>0 then for x:=x2 to x1 do - putpixel (x,y1,col); - exit; - END; - if (dx=0) then BEGIN - if dy<0 then for y:=y1 to y2 do - putpixel (x1,y,col); - if dy>0 then for y:=y2 to y1 do - putpixel (x1,y,col); - exit; - END; - xslope:=xlength/ylength; - yslope:=ylength/xlength; - if (yslope/xslope<1) and (yslope/xslope>-1) then BEGIN - if dx<0 then for x:=x1 to x2 do BEGIN - y:= round (yslope*x); - putpixel (x,y,col); - END; - if dx>0 then for x:=x2 to x1 do BEGIN - y:= round (yslope*x); - putpixel (x,y,col); - END; - END - ELSE - BEGIN - if dy<0 then for y:=y1 to y2 do BEGIN - x:= round (xslope*y); - putpixel (x,y,col); - END; - if dy>0 then for y:=y2 to y1 do BEGIN - x:= round (xslope*y); - putpixel (x,y,col); - END; - END; -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -procedure line(a,b,c,d,col:integer); - { This draws a line from x1,y1 to x2,y2 using the first method } - - function sgn(a:real):integer; - begin - if a>0 then sgn:=+1; - if a<0 then sgn:=-1; - if a=0 then sgn:=0; - end; - -var u,s,v,d1x,d1y,d2x,d2y,m,n:real; - i:integer; -begin - u:= c - a; - v:= d - b; - d1x:= SGN(u); - d1y:= SGN(v); - d2x:= SGN(u); - d2y:= 0; - m:= ABS(u); - n := ABS(v); - IF NOT (M>N) then - BEGIN - d2x := 0 ; - d2y := SGN(v); - m := ABS(v); - n := ABS(u); - END; - s := INT(m / 2); - FOR i := 0 TO round(m) DO - BEGIN - putpixel(a,b,col); - s := s + n; - IF not (s ''); -end; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure Setup; - { This loads the font and the pallette } -VAR f:file; - loop1:char; - loop2,loop3:integer; -BEGIN - getmem (font,sizeof (font^)); - If exist ('softrock.fnt') then BEGIN - Assign (f,'softrock.fnt'); - reset (f,1); - blockread (f,font^,sizeof (font^)); - close (f); - Writeln ('SoftRock.FNT from TEXTER5 found in current directory. Using.'); - END - ELSE BEGIN - Writeln ('SoftRock.FNT from TEXTER5 not found in current directory.'); - For loop1:=' ' to ']' do - For loop2:=1 to 16 do - for loop3:=1 to 16 do - font^[loop1,loop2,loop3]:=loop2; - END; - If exist ('pallette.col') then - Writeln ('Pallette.COL from TEXTER5 found in current directory. Using.') - ELSE - Writeln ('Pallette.COL from TEXTER5 not found in current directory.'); - Writeln; - Writeln; - Write ('Hit any key to continue ...'); - readkey; - setmcga; - If exist ('pallette.col') then loadpal ('pallette.col'); -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure ScrollMsg (Msg : String); - { This scrolls the string in MSG across the screen } -Var Loop1,loop2,loop3 : Integer; -Begin - For loop1:=1 to length (msg) do BEGIN - For loop2:=1 to xsize do BEGIN - - { This bit scrolls the screen by one then puts in the new row of - letters } - - waitretrace; - For Loop3 := 100 to 99+ysize do - move (mem[vga:1+(loop3*320)],mem[vga:(loop3*320)],319); - for loop3:=100 to 99+ysize do - putpixel (319,loop3,font^[msg[loop1],loop2,loop3-99],vga); - { Change the -99 above to the minimum of loop3-1, which you - will change in order to move the position of the scrolly } - END; - - {This next bit scrolls by one pixel after each letter so that there - are gaps between the letters } - - waitretrace; - For Loop3 := 100 to 99+ysize do - move (mem[vga:1+(loop3*320)],mem[vga:(loop3*320)],319); - for loop3:=100 to 99+ysize do - putpixel (319,loop3,0,vga); - END; -End; - - -BEGIN - ClrScr; - Writeln ('This program will give you an example of a scrolly. If the file'); - Writeln ('SOFTROCK.FNT is in the current directory, this program will scroll'); - Writeln ('letters, otherwise it will only scroll bars. It also searches for'); - Writeln ('PALLETTE.COL, which it uses for it''s pallette. Both SOFTROCK.FNT'); - Writeln ('and PALLETTE.COL come with TEXTER5.ZIP, at a BBS near you.'); - Writeln; - Writeln ('You will note that you can change what the scrolly says merely by'); - Writeln ('changing the string in the program.'); - Writeln; - Setup; - repeat - ScrollMsg ('ASPHYXIA RULZ!!! '); - until keypressed; - Settext; - freemem (font, sizeof (font^)); - Writeln ('All done. This concludes the fifth sample program in the ASPHYXIA'); - Writeln ('Training series. You may reach DENTHOR under the name of GRANT'); - Writeln ('SMITH on the MailBox BBS, or leave a message to ASPHYXIA on the'); - Writeln ('ASPHYXIA BBS. Get the numbers from Roblist, or write to :'); - Writeln (' Grant Smith'); - Writeln (' P.O. Box 270'); - Writeln (' Kloof'); - Writeln (' 3640'); - Writeln ('I hope to hear from you soon!'); - Writeln; Writeln; - Write ('Hit any key to exit ...'); - Readkey; -END. diff --git a/16/PCGPE10/TUT6.TXT b/16/PCGPE10/TUT6.TXT deleted file mode 100644 index 7311bb34..00000000 --- a/16/PCGPE10/TUT6.TXT +++ /dev/null @@ -1,434 +0,0 @@ - - ÕÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͸ - ³ W E L C O M E ³ - ³ To the VGA Trainer Program ³ ³ - ³ By ³ ³ - ³ DENTHOR of ASPHYXIA ³ ³ ³ - ÔÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ; ³ ³ - ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³ - ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - --==[ PART 6 ]==-- - - - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ Introduction - -Hi there! I'm back, with the latest part in the series : Pregenerated -arrays. This is a fairly simple concept that can treble the speed of -your code, so have a look. - -I still suggest that if you haven't got a copy of TEXTER that you get it. -This is shareware, written by me, that allows you to grab fonts and use -them in your own programs. - -I downloaded the Friendly City BBS Demo, an intro for a PE BBS, written -by a new group called DamnRite, with coder Brett Step. The music was -excellent, written by Kon Wilms (If I'm not mistaken, he is an Amiga -weenie ;-)). A very nice first production, and I can't wait to see more -of their work. I will try con a local BBS to allow me to send Brett some -fido-mail. - -If you would like to contact me, or the team, there are many ways you -can do it : 1) Write a message to Grant Smith in private mail here on - the Mailbox BBS. - 2) Write a message here in the Programming conference here - on the Mailbox (Preferred if you have a general - programming query or problem others would benefit from) - 3) Write to ASPHYXIA on the ASPHYXIA BBS. - 4) Write to Denthor, Eze or Livewire on Connectix. - 5) Write to : Grant Smith - P.O.Box 270 Kloof - 3640 - Natal - 6) Call me (Grant Smith) at (031) 73 2129 (leave a message if you - call during varsity) - -NB : If you are a representative of a company or BBS, and want ASPHYXIA - to do you a demo, leave mail to me; we can discuss it. -NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling - quite lonely and want to meet/help out/exchange code with other demo - groups. What do you have to lose? Leave a message here and we can work - out how to transfer it. We really want to hear from you! - - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ Why do I need a lookup table? What is it? - -A lookup table is an imaginary table in memory where you look up the -answers to certain mathematical equations instead of recalculating them -each time. This may speed things up considerably. Please note that a -lookup table is sometimes referred to as a pregenerated array. - -One way of looking at a lookup table is as follows : Let us say that for -some obscure reason you need to calculate a lot of multiplications (eg. -5*5 , 7*4 , 9*2 etc.). Instead of actually doing a slow multiply each -time, you can generate a kind of bonds table, as seen below : - - -ÉÍÑÍËÍÍÍÍÍÍÍÑÍÍÍÍÍÍÑÍÍÍÍÍÍÑÍÍÍÍÍÍÑÍÍÍÍÍÍÑÍÍÍÍÍÍÑÍÍÍÍÍÍÑÍÍÍÍÍÍÑÍÍÍÍÍÍ» -ÇÄÅĶ 1 ³ 2 ³ 3 ³ 4 ³ 5 ³ 6 ³ 7 ³ 8 ³ 9 º -ÇÄÁÄ×ÍÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍÍØÍÍÍÍÍ͵ -º 1 º 1 ³ 2 ³ 3 ³ 4 ³ 5 ³ 6 ³ 7 ³ 8 ³ 9 ³ -ÇÄÄÄ×ÄÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄ´ -º 2 º 2 ³ 4 ³ 6 ³ 8 ³ 10 ³ 12 ³ 14 ³ 16 ³ 18 ³ -ÇÄÄÄ×ÄÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄ´ -º 3 º 3 ³ 6 ³ 9 ³ 12 ³ 15 ³ 18 ³ 21 ³ 24 ³ 27 ³ -ÇÄÄÄ×ÄÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄ´ -º 4 º 4 ³ 8 ³ 12 ³ 16 ³ 20 ³ 24 ³ 28 ³ 32 ³ 36 ³ -ÇÄÄÄ×ÄÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄ´ -º 5 º 5 ³ 10 ³ 15 ³ 20 ³ 25 ³ 30 ³ 35 ³ 40 ³ 45 ³ -ÇÄÄÄ×ÄÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄ´ -º 6 º 6 ³ 12 ³ 18 ³ 24 ³ 30 ³ 36 ³ 42 ³ 48 ³ 54 ³ -ÇÄÄÄ×ÄÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄ´ -º 7 º 7 ³ 14 ³ 21 ³ 28 ³ 35 ³ 42 ³ 49 ³ 56 ³ 63 ³ -ÇÄÄÄ×ÄÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄ´ -º 8 º 8 ³ 16 ³ 24 ³ 32 ³ 40 ³ 48 ³ 56 ³ 64 ³ 72 ³ -ÇÄÄÄ×ÄÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄ´ -º 9 º 9 ³ 18 ³ 27 ³ 36 ³ 45 ³ 54 ³ 63 ³ 72 ³ 81 ³ -ÈÍÍÍÊÄÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÙ - -This means that instead of calculating 9*4, you just find the 9 on the -top and the 4 on the side, and the resulting number is the answer. This -type of table is very useful when the equations are very long to do. - -The example I am going to use for this part is that of circles. Cast -your minds back to Part 3 on lines and circles. The circle section took -quite a while to finish drawing, mainly because I had to calculate the -SIN and COS for EVERY SINGLE POINT. Calculating SIN and COS is obviously -very slow, and that was reflected in the speed of the section. - - - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ How do I generate a lookup table? - -This is very simple. In my example, I am drawing a circle. A circle has -360 degrees, but for greater accuracy, to draw my circle I will start -with zero and increase my degrees by 0.4. This means that in each circle -there need to be 8000 SINs and COSes (360/0.4=8000). Putting these into -the base 64k that Pascal allocates for normal variables is obviously not -a happening thing, so we define them as pointers in the following -manner: - TYPE table = Array [1..8000] of real; - - VAR sintbl : ^table; - costbl : ^table; - -Then in the program we get the memory for these two pointers. Asphyxia -was originally thinking of calling itself Creative Reboot Inc., mainly -because we always forgot to get the necessary memory for our pointers. -(Though a bit of creative assembly coding also contributed to this. We -wound up rating our reboots on a scale of 1 to 10 ;-)). The next obvious -step is to place our necessary answers into our lookup tables. This can -take a bit of time, so in a demo, you would do it in the very beginning -(people just think it's slow disk access or something), or after you -have shown a picture (while the viewer is admiring it, you are -calculating pi to its 37th degree in the background ;-)) Another way of -doing it is, after calculating it once, you save it to a file which you -then load into the variable at the beginning of the program. Anyway, -this is how we will calculate the table for our circle : - - Procedure Setup; - VAR deg:real; - BEGIN - deg:=0; - for loop1:=1 to 8000 do BEGIN - deg:=deg+0.4; - costbl^[loop1]:=cos (rad(deg)); - sintbl^[loop1]:=sin (rad(deg)); - END; - END; - -This will calculate the needed 16000 reals and place them into our two -variables. The amount of time this takes is dependant on your computer. - - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ How do I use a lookup table? - -This is very easy. In your program, wherever you put - cos (rad(deg)), -you just replace it with : - costbl^[deg] - -Easy, no? Note that the new "deg" variable is now an integer, always -between 1 and 8000. - - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ Where else do I use lookup tables? - -Lookup tables may be used in many different ways. For example, when -working out 3-dimensional objects, sin and cos are needed often, and are -best put in a lookup table. In a game, you may pregen the course an -enemy may take when attacking. Even saving a picture (for example, a -plasma screen) after generating it, then loading it up later is a form -of pregeneration. - -When you feel that your program is going much too slow, your problems -may be totally sorted out by using a table. Or, maybe not. ;-) - - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ In closing - -As you have seen above, lookup tables aren't all that exciting, but they -are useful and you need to know how to use them. The attached sample -program will demonstrate just how big a difference they can make. - -Keep on coding, and if you finish anything, let me know about it! I -never get any mail, so all mail is greatly appreciated ;-) - -Sorry, no quote today, it's hot and I'm tired. Maybe next time ;-) - - - Denthor - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ TUTPROG6.PAS ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -{$X+} -USES crt; - -CONST VGA = $a000; - -TYPE tbl = Array [1..8000] of real; - { This will be the shape of the 'table' where we look up - values, which is faster then calculating them } - -VAR loop1:integer; - Pall : Array [1..20,1..3] of byte; - { This is our temporary pallette. We ony use colors 1 to 20, so we - only have variables for those ones. } - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure SetMCGA; { This procedure gets you into 320x200x256 mode. } -BEGIN - asm - mov ax,0013h - int 10h - end; -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure SetText; { This procedure returns you to text mode. } -BEGIN - asm - mov ax,0003h - int 10h - end; -END; - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure Cls (Col : Byte); - { This clears the screen to the specified color } -BEGIN - Fillchar (Mem [VGA:0],64000,col); -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure Putpixel (X,Y : Integer; Col : Byte); - { This puts a pixel on the screen by writing directly to memory. } -BEGIN - Mem [VGA:X+(Y*320)]:=Col; -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -procedure WaitRetrace; assembler; - { This waits for a vertical retrace to reduce snow on the screen } -label - l1, l2; -asm - mov dx,3DAh -l1: - in al,dx - and al,08h - jnz l1 -l2: - in al,dx - and al,08h - jz l2 -end; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure Pal(ColorNo : Byte; R,G,B : Byte); - { This sets the Red, Green and Blue values of a certain color } -Begin - Port[$3c8] := ColorNo; - Port[$3c9] := R; - Port[$3c9] := G; - Port[$3c9] := B; -End; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Function rad (theta : real) : real; - { This calculates the degrees of an angle } -BEGIN - rad := theta * pi / 180 -END; - - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure NormCirc; - { This generates a spireal without using a lookup table } -VAR deg,radius:real; - x,y:integer; - -BEGIN - gotoxy (1,1); - Writeln ('Without pregenerated arrays.'); - for loop1:=60 downto 43 do BEGIN - deg:=0; - radius:=loop1; - repeat - X:=round(radius*COS (rad (deg))); - Y:=round(radius*sin (rad (deg))); - putpixel (x+160,y+100,61-loop1); - deg:=deg+0.4; { Increase the degree so the circle is round } - radius:=radius-0.02; { Decrease the radius for a spiral effect } - until radius<0; { Continue till at the centre (the radius is zero) } - END; -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure LookupCirc; - { This draws a spiral using a lookup table } -VAR radius:real; - x,y,pos:integer; - costbl : ^tbl; - sintbl : ^tbl; - - Procedure Setupvars; - { This is a nested procedure (a procedure in a procedure), and may - therefore only be used from within the main part of this procedure. - This section gets the memory for the table, then generates the - table. } - VAR deg:real; - BEGIN - getmem (costbl,sizeof(costbl^)); - getmem (sintbl,sizeof(sintbl^)); - deg:=0; - for loop1:=1 to 8000 do BEGIN { There are 360 degrees in a } - deg:=deg+0.4; { circle. If you increase the } - costbl^[loop1]:=cos (rad(deg)); { degrees by 0.4, the number of } - sintbl^[loop1]:=sin (rad(deg)); { needed parts of the table is } - END; { 360/0.4=8000 } - END; - { NB : For greater accuracy I increase the degrees by 0.4, because if I - increase them by one, holes are left in the final product as a - result of the rounding error margin. This means the pregen array - is bigger, takes up more memory and is slower to calculate, but - the finished product looks better.} - -BEGIN - cls (0); - gotoxy (1,1); - Writeln ('Generating variables....'); - setupvars; - gotoxy (1,1); - Writeln ('With pregenerated arrays.'); - for loop1:=60 downto 43 do BEGIN - pos:=1; - radius:=loop1; - repeat - X:=round (radius*costbl^[pos]); { Note how I am not recalculating sin} - Y:=round (radius*sintbl^[pos]); { and cos for each point. } - putpixel (x+160,y+100,61-loop1); - radius:=radius-0.02; - inc (pos); - if pos>8000 then pos:=1; { I only made a table from 1 to 8000, so it} - { must never exceed that, or the program } - { will probably crash. } - until radius<0; - END; - freemem (costbl,sizeof(costbl^)); { Freeing the memory taken up by the } - freemem (sintbl,sizeof(sintbl^)); { tables. This is very important. } -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure PalPlay; - { This procedure mucks about with our "virtual pallette", then shoves it - to screen. } -Var Tmp : Array[1..3] of Byte; - { This is used as a "temporary color" in our pallette } - loop1 : Integer; -BEGIN - Move(Pall[1],Tmp,3); - { This copies color 1 from our virtual pallette to the Tmp variable } - Move(Pall[2],Pall[1],18*3); - { This moves the entire virtual pallette down one color } - Move(Tmp,Pall[18],3); - { This copies the Tmp variable to no. 18 of the virtual pallette } - WaitRetrace; - For loop1:=1 to 18 do - pal (loop1,pall[loop1,1],pall[loop1,2],pall[loop1,3]); -END; - - -BEGIN - ClrScr; - writeln ('Hi there! This program will demonstrate the usefullness of '); - writeln ('pregenerated arrays, also known as lookup tables. The program'); - writeln ('will first draw a spiral without using a lookup table, rotate'); - writeln ('the pallette until a key is pressed, the calculate the lookup'); - writeln ('table, then draw the same spiral using the lookup table.'); - writeln; - writeln ('This is merely one example for the wide range of uses of a '); - writeln ('lookup table.'); - writeln; - writeln; - Write (' Hit any key to contine ...'); - Readkey; - setmcga; - directvideo:=FALSE; { This handy trick allows you to use GOTOXY and } - { Writeln in GFX mode. Hit CTRL-F1 on it for more } - { info/help } - For Loop1 := 1 to 18 do BEGIN - Pall[Loop1,1] := (Loop1*3)+9; - Pall[Loop1,2] := 0; - Pall[Loop1,3] := 0; - END; - { This sets colors 1 to 18 to values between 12 to 63. } - - WaitRetrace; - For loop1:=1 to 18 do - pal (loop1,pall[loop1,1],pall[loop1,2],pall[loop1,3]); - { This sets the true pallette to variable Pall } - - normcirc; { This draws a spiral without lookups } - Repeat - PalPlay; - Until keypressed; - readkey; - lookupcirc; { This draws a spiral with lookups } - Repeat - PalPlay; - Until keypressed; - Readkey; - - SetText; - Writeln ('All done. This concludes the sixth sample program in the ASPHYXIA'); - Writeln ('Training series. You may reach DENTHOR under the name of GRANT'); - Writeln ('SMITH on the MailBox BBS, or leave a message to ASPHYXIA on the'); - Writeln ('ASPHYXIA BBS. I am also an avid Connectix BBS user.'); - Writeln ('Get the numbers from Roblist, or write to :'); - Writeln (' Grant Smith'); - Writeln (' P.O. Box 270'); - Writeln (' Kloof'); - Writeln (' 3640'); - Writeln ('I hope to hear from you soon!'); - Writeln; Writeln; - Write ('Hit any key to exit ...'); - Readkey; -END. diff --git a/16/PCGPE10/TUT7.TXT b/16/PCGPE10/TUT7.TXT deleted file mode 100644 index 3ebb8594..00000000 --- a/16/PCGPE10/TUT7.TXT +++ /dev/null @@ -1,1195 +0,0 @@ - ÕÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͸ - ³ W E L C O M E ³ - ³ To the VGA Trainer Program ³ ³ - ³ By ³ ³ - ³ DENTHOR of ASPHYXIA ³ ³ ³ - ÔÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ; ³ ³ - ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³ - ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - --==[ PART 7 ]==-- - - - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ Introduction - -Hello! By popular request, this part is all about animation. I will be -going over three methods of doing animation on a PC, and will -concerntrate specifically on one, which will be demonstrated in the -attached sample code. - -Although not often used in demo coding, animation is usually used in -games coding, which can be almost as rewarding ;-) - -In this part I will also be a lot less stingy with assembler code :) -Included will be a fairly fast pure assembler putpixel, an asm screen -flip command, an asm icon placer, an asm partial-flip and one or two -others. I will be explaining how these work in detail, so this may also -be used as a bit of an asm-trainer too. - -By the way, I apologise for this part taking so long to be released, but -I only finished my exams a few days ago, and they of course took -preference ;-). I have also noticed that the MailBox BBS is no longer -operational, so the trainer will be uploaded regularly to the BBS lists -shown at the end of this tutorial. - -If you would like to contact me, or the team, there are many ways you -can do it : 1) Write a message to Grant Smith/Denthor/Asphyxia in private mail - on the ASPHYXIA BBS. - 2) Write a message in the Programming conference on the - For Your Eyes Only BBS (of which I am the Moderator ) - This is preferred if you have a general programming query - or problem others would benefit from. - 4) Write to Denthor, Eze or Livewire on Connectix. - 5) Write to : Grant Smith - P.O.Box 270 Kloof - 3640 - Natal - 6) Call me (Grant Smith) at (031) 73 2129 (leave a message if you - call during varsity) - 7) Write to mcphail@beastie.cs.und.ac.za on InterNet, and - mention the word Denthor near the top of the letter. - -NB : If you are a representative of a company or BBS, and want ASPHYXIA - to do you a demo, leave mail to me; we can discuss it. -NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling - quite lonely and want to meet/help out/exchange code with other demo - groups. What do you have to lose? Leave a message here and we can work - out how to transfer it. We really want to hear from you! - - - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ The Principals of Animation - -I am sure all of you have seen a computer game with animation at one or -other time. There are a few things that an animation sequence must do in -order to give an impression of realism. Firstly, it must move, -preferably using different frames to add to the realism (for example, -with a man walking you should have different frames with the arms an -legs in different positions). Secondly, it must not destroy the -background, but restore it after it has passed over it. - -This sounds obvious enough, but can be very difficult to code when you -have no idea of how to go about achieving that. - -In this trainer I will discuss various methods of meeting these two -objectives. - - - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ Frames and Object Control - -It is quite obvious that for most animation to succeed, you must have -numerous frames of the object in various poses (such as a man with -several frames of him walking). When shown one after the other, these -give the impression of natural movement. - -So, how do we store these frames? I hear you cry. Well, the obvious -method is to store them in arrays. After drawing a frame in Autodesk -Animator and saving it as a .CEL, we usually use the following code to -load it in : - -TYPE icon = Array [1..50,1..50] of byte; - -VAR tree : icon; - -Procedure LoadCEL (FileName : string; ScrPtr : pointer); -var - Fil : file; - Buf : array [1..1024] of byte; - BlocksRead, Count : word; -begin - assign (Fil, FileName); - reset (Fil, 1); - BlockRead (Fil, Buf, 800); { Read and ignore the 800 byte header } - Count := 0; BlocksRead := $FFFF; - while (not eof (Fil)) and (BlocksRead <> 0) do begin - BlockRead (Fil, mem [seg (ScrPtr^): ofs (ScrPtr^) + Count], 1024, BlocksRead); - Count := Count + 1024; - end; - close (Fil); -end; - -BEGIN - Loadcel ('Tree.CEL',addr (tree)); -END. - -We now have the 50x50 picture of TREE.CEL in our array tree. We may access -this array in the usual manner (eg. col:=tree [25,30]). If the frame is -large, or if you have many frames, try using pointers (see previous -parts) - -Now that we have the picture, how do we control the object? What if we -want multiple trees wandering around doing their own thing? The solution -is to have a record of information for each tree. A typical data -structure may look like the following : - -TYPE Treeinfo = Record - x,y:word; { Where the tree is } - speed:byte; { How fast the tree is moving } - Direction:byte; { Where the tree is facing } - frame:byte { Which animation frame the tree is - currently involved in } - active:boolean; { Is the tree actually supposed to be - shown/used? } - END; - -VAR Forest : Array [1..20] of Treeinfo; - -You now have 20 trees, each with their own information, location etc. -These are accessed using the following means : - Forest [15].x:=100; -This would set the 15th tree's x coordinate to 100. - - - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ Restoring the Overwritten Background - -I will discuss three methods of doing this. These are NOT NECESSARILY -THE ONLY OR BEST WAYS TO DO THIS! You must experiment and decide which -is the best for your particular type of program. - -METHOD 1 : - -Step 1 : Create two virtual pages, Vaddr and Vaddr2. -Step 2 : Draw the background to Vaddr2. -Step 3 : Flip Vaddr2 to Vaddr. -Step 4 : Draw all the foreground objects onto Vaddr. -Step 5 : Flip Vaddr to VGA. -Step 6 : Repeat from 3 continuously. - -In ascii, it looks like follows ... - - +---------+ +---------+ +---------+ - | | | | | | - | VGA | <======= | VADDR | <====== | VADDR2 | - | | | (bckgnd)| | (bckgnd)| - | | |+(icons) | | | - +---------+ +---------+ +---------+ - -The advantages of this approach is that it is straightforward, continual -reading of the background is not needed, there is no flicker and it is -simple to implement. The disadvantages are that two 64000 byte virtual -screens are needed, and the procedure is not very fast because of the -slow speed of flipping. - - -METHOD 2 : - -Step 1 : Draw background to VGA. -Step 2 : Grab portion of background that icon will be placed on. -Step 3 : Place icon. -Step 4 : Replace portion of background from Step 2 over icon. -Step 5 : Repeat from step 2 continuously. - -In terms of ascii ... - - +---------+ - | +--|------- + Background restored (3) - | * -|------> * Background saved to memory (1) - | ^ | - | +--|------- # Icon placed (2) - +---------+ - -The advantages of this method is that very little extra memory is -needed. The disadvantages are that writing to VGA is slower then writing -to memory, and there may be large amounts of flicker. - - -METHOD 3 : - -Step 1 : Set up one virtual screen, VADDR. -Step 2 : Draw background to VADDR. -Step 3 : Flip VADDR to VGA. -Step 4 : Draw icon to VGA. -Step 5 : Transfer background portion from VADDR to VGA. -Step 6 : Repeat from step 4 continuously. - -In ascii ... - - +---------+ +---------+ - | | | | - | VGA | | VADDR | - | | | (bckgnd)| - | Icon>* <|-----------|--+ | - +---------+ +---------+ - -The advantages are that writing from the virtual screen is quicker then -from VGA, and there is less flicker then in Method 2. Disadvantages are -that you are using a 64000 byte virtual screen, and flickering occurs -with large numbers of objects. - -In the attached sample program, a mixture of Method 3 and Method 1 is -used. It is faster then Method 1, and has no flicker, unlike Method 3. -What I do is I use VADDR2 for background, but only restore the -background that has been changed to VADDR, before flipping to VGA. - -In the sample program, you will see that I restore the entire background -of each of the icons, and then place all the icons. This is because if I -replace the background then place the icon on each object individually, -if two objects are overlapping, one is partially overwritten. - -The following sections are explanations of how the various assembler -routines work. This will probably be fairly boring for you if you -already know assembler, but should help beginners and dabblers alike. - - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ The ASM Putpixel - -To begin with, I will explain a few of the ASM variables and functions : - - - -There are 4 register variables : AX,BX,CX,DX. These are words (double -bytes) with a range from 0 to 65535. You may access the high and low -bytes of these by replacing the X with a "H" for high or "L" for low. -For example, AL has a range from 0-255. - -You also have two pointers : ES:DI and DS:SI. The part on the left is -the segment to which you are pointing (eg $a000), and the right hand -part is the offset, which is how far into the segment you are pointing. -Turbo Pascal places a variable over 16k into the base of a segment, ie. -DI or SI will be zero at the start of the variable. - -If you wish to be pointing to pixel number 3000 on the VGA screen (see -previous parts for the layout of the VGA screen), ES would be equal to -$a000 and DI would be equal to 3000. You can quite as easily make ES or -DS be equal to the offset of a virtual screen. - -Here are a few functions that you will need to know : - - mov destination,source This moves the value in source to - destination. eg mov ax,50 - add destination,source This adds source to destination, - the result being stored in destination - mul source This multiplies AX by source. If - source is a byte, the source is - multiplied by AL, the result being - stored in AX. If source is a word, - the source is multiplied by AX, the - result being stored in DX:AX - movsb This moves the byte that DS:SI is - pointing to into ES:DI, and - increments SI and DI. - movsw Same as movsb except it moves a - word instead of a byte. - stosw This moves AX into ES:DI. stosb - moves AL into ES:DI. DI is then - incremented. - push register This saves the value of register by - pushing it onto the stack. The - register may then be altered, but - will be restored to it's original - value when popped. - pop register This restores the value of a pushed - register. NOTE : Pushed values must - be popped in the SAME ORDER but - REVERSED. - rep command This repeats Command by as many - times as the value in CX - - -SHL Destination,count ; -and SHR Destination,count ; -need a bit more explaining. As you know, computers think in ones and -zeroes. Each number may be represented in this base 2 operation. A byte -consists of 8 ones and zeroes (bits), and have a range from 0 to 255. A -word consists of 16 ones and zeroes (bits), and has a range from 0 to -65535. A double word consists of 32 bits. - -The number 53 may be represented as follows : 00110101. Ask someone who -looks clever to explain to you how to convert from binary to decimal and -vice-versa. - -What happens if you shift everything to the left? Drop the leftmost -number and add a zero to the right? This is what happens : - - 00110101 = 53 - <----- - 01101010 = 106 - -As you can see, the value has doubled! In the same way, by shifting one -to the right, you halve the value! This is a VERY quick way of -multiplying or dividing by 2. (note that for dividing by shifting, we -get the trunc of the result ... ie. 15 shr 1 = 7) - -In assembler the format is SHL destination,count This shifts -destination by as many bits in count (1=*2, 2=*4, 3=*8, 4=*16 etc) -Note that a shift takes only 2 clock cycles, while a mul can take up to 133 -clock cycles. Quite a difference, no? Only 286es or above may have count -being greater then one. - -This is why to do the following to calculate the screen coordinates for -a putpixel is very slow : - - mov ax,[Y] - mov bx,320 - mul bx - add ax,[X] - mov di,ax - -But alas! I hear you cry. 320 is not a value you may shift by, as you -may only shift by 2,4,8,16,32,64,128,256,512 etc.etc. The solution is -very cunning. Watch. - - mov bx,[X] - mov dx,[Y] - push bx - mov bx, dx {; bx = dx = Y} - mov dh, dl {; dh = dl = Y} - xor dl, dl {; These 2 lines equal dx*256 } - shl bx, 1 - shl bx, 1 - shl bx, 1 - shl bx, 1 - shl bx, 1 - shl bx, 1 {; bx = bx * 64} - add dx, bx {; dx = dx + bx (ie y*320)} - pop bx {; get back our x} - add bx, dx {; finalise location} - mov di, bx - -Let us have a look at this a bit closer shall we? -bx=dx=y dx=dx*256 ; bx=bx*64 ( Note, 256+64 = 320 ) - -dx+bx=Correct y value, just add X! - -As you can see, in assembler, the shortest code is often not the -fastest. - -The complete putpixel procedure is as follows : - -Procedure Putpixel (X,Y : Integer; Col : Byte; where:word); - { This puts a pixel on the screen by writing directly to memory. } -BEGIN - Asm - push ds {; Make sure these two go out the } - push es {; same they went in } - mov ax,[where] - mov es,ax {; Point to segment of screen } - mov bx,[X] - mov dx,[Y] - push bx {; and this again for later} - mov bx, dx {; bx = dx} - mov dh, dl {; dx = dx * 256} - xor dl, dl - shl bx, 1 - shl bx, 1 - shl bx, 1 - shl bx, 1 - shl bx, 1 - shl bx, 1 {; bx = bx * 64} - add dx, bx {; dx = dx + bx (ie y*320)} - pop bx {; get back our x} - add bx, dx {; finalise location} - mov di, bx {; di = offset } - {; es:di = where to go} - xor al,al - mov ah, [Col] - mov es:[di],ah {; move the value in ah to screen - point es:[di] } - pop es - pop ds - End; -END; - -Note that with DI and SI, when you use them : - mov di,50 Moves di to position 50 - mov [di],50 Moves 50 into the place di is pointing to - - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ The Flip Procedure - -This is fairly straightforward. We get ES:DI to point to the start of -the destination screen, and DS:SI to point to the start of the source -screen, then do 32000 movsw (64000 bytes). - -procedure flip(source,dest:Word); - { This copies the entire screen at "source" to destination } -begin - asm - push ds - mov ax, [Dest] - mov es, ax { ES = Segment of source } - mov ax, [Source] - mov ds, ax { DS = Segment of source } - xor si, si { SI = 0 Faster then mov si,0 } - xor di, di { DI = 0 } - mov cx, 32000 - rep movsw { Repeat movsw 32000 times } - pop ds - end; -end; - -The cls procedure works in much the same way, only it moves the color -into AX then uses a rep stosw (see program for details) - -The PAL command is almost exactly the same as it's Pascal equivalent -(see previous tutorials). Look in the sample code to see how it uses the -out and in commands. - - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ In Closing - -The assembler procedures presented to you in here are not at their best. -Most of these are procedures ASPHYXIA abandoned for better ones after -months of use. But, as you will soon see, they are all MUCH faster then -the original Pascal equivalents I originally gave you. In future, I -hope to give you more and more assembler procedures for your ever -growing collections. But, as you know, I am not always very prompt with -this series (I don't know if even one has been released within one week -of the previous one), so if you want to get any stuff done, try do it -yourself. What do you have to lose, aside from your temper and a few -rather inventive reboots ;-) - -What should I do for the next trainer? A simple 3-d tutorial? You may -not like it, because I would go into minute detail of how it works :) -Leave me suggestions for future trainers by any of the means discussed -at the top of this trainer. - -After the customary quote, I will place a listing of the BBSes I -currently know that regularly carry this Trainer Series. If your BBS -receives it regularly, no matter where in the country you are, get a -message to me and I'll add it to the list. Let's make it more convenient -for locals to grab a copy without calling long distance ;-) - - [ There they sit, the preschooler class encircling their - mentor, the substitute teacher. - "Now class, today we will talk about what you want to be - when you grow up. Isn't that fun?" The teacher looks - around and spots the child, silent, apart from the others - and deep in thought. "Jonny, why don't you start?" she - encourages him. - Jonny looks around, confused, his train of thought - disrupted. He collects himself, and stares at the teacher - with a steady eye. "I want to code demos," he says, - his words becoming stronger and more confidant as he - speaks. "I want to write something that will change - peoples perception of reality. I want them to walk - away from the computer dazed, unsure of their footing - and eyesight. I want to write something that will - reach out of the screen and grab them, making - heartbeats and breathing slow to almost a halt. I want - to write something that, when it is finished, they - are reluctant to leave, knowing that nothing they - experience that day will be quite as real, as - insightful, as good. I want to write demos." - Silence. The class and the teacher stare at Jonny, stunned. It - is the teachers turn to be confused. Jonny blushes, - feeling that something more is required. "Either that - or I want to be a fireman." - ] - - Grant Smith - 14:32 - 21/11/93 - -See you next time, - - DENTHOR - -These fine BBS's carry the ASPHYXIA DEMO TRAINER SERIES : (alphabetical) - -ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍËÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍËÍÍÍÍÍËÍÍÍËÍÍÍÍËÍÍÍÍ» -ºBBS Name ºTelephone No. ºOpen ºMsgºFileºPastº -ÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÍÍÍÍÍÎÍÍÍÎÍÍÍÍÎÍÍÍ͹ -ºASPHYXIA BBS #1 º(031) 765-5312 ºALL º * º * º * º -ºASPHYXIA BBS #2 º(031) 765-6293 ºALL º * º * º * º -ºConnectix BBS º(031) 266-9992 ºALL º * º * º * º -ºFor Your Eyes Only BBS º(031) 285-318 ºA/H º * º * º * º -ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÊÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÊÍÍÍÍÍÊÍÍÍÊÍÍÍÍÊÍÍÍͼ - -Open = Open at all times or only A/H -Msg = Available in message base -File = Available in file base -Past = Previous Parts available - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ TUTPROG7.PAS ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -{$X+} -USES crt; - -CONST VGA = $a000; - -Type Toastinfo = Record { This is format of of each of our } - x,y:integer; { records for the flying toasters } - speed,frame:integer; - active:boolean; - END; - - icon = Array [1..30*48] of byte; { This is the size of our pictures } - - Virtual = Array [1..64000] of byte; { The size of our Virtual Screen } - VirtPtr = ^Virtual; { Pointer to the virtual screen } - -CONST frame1 : icon = ( -0,0,0,0,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5, -7,7,7,7,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5, -5,7,7,7,7,7,7,7,8,8,7,7,7,7,7,7,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0, -0,0,0,0,0,5,5,7,7,7,7,7,8,8,7,8,8,7,8,7,8,7,7,7,5,8,8,8,8,5,5,5,5,5,5,5,5,5,5,5, -5,0,0,0,0,0,0,0,0,0,0,0,5,7,7,7,7,7,7,8,7,7,7,8,7,7,7,7,7,7,0,0,0,0,0,0,8,5,5,5, -5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,5,7,7,8,8,7,7,8,7,7,8,7,7,7,7,7,0,0,0,0,0, -0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,5,7,8,8,8,7,7,8,7,7,8,7,7,7, -7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,5,7,8,8,8,7,7, -8,8,8,8,8,8,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9, -9,5,7,8,8,8,8,8,7,7,8,8,7,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,9,9,9,9,5,7,7,8,8,8,8,7,7,8,8,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1, -1,1,0,0,0,1,1,1,1,1,1,1,9,9,9,5,7,8,8,7,7,8,8,7,8,8,8,7,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,5,7,8,8,7,7,7,7,8,8,7,7,7,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,7,8,8,8,8,8,8,8,7, -7,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,7, -7,7,7,7,7,7,7,7,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1, -1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1, -1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2, -2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2, -2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1, -1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4, -4,6,6,6,6,6,6,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,3,3,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9, -9,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9, -9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -); - frame2 : icon = ( -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9, -9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1, -1,1,0,0,0,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2, -2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,5, -5,5,5,5,5,5,5,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1, -1,1,1,2,2,2,2,2,5,5,5,5,5,5,5,5,5,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1, -1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,5,5,5,5,5,5,5,5,5,2,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,5,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,2,5,5,5,5,5,5,5,5,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,5,5,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,5,5,5,5, -5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2, -2,2,2,2,2,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,5,1,1,1,1,1,1,0,0,0,1,1,1, -1,1,1,2,2,2,2,2,2,2,2,2,2,2,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,5,1,7,1,4, -4,6,6,6,6,6,6,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0, -0,0,0,5,5,1,1,1,1,1,1,1,1,1,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,5,5,5,5,5,5,5,5,0,0, -0,0,0,0,0,0,0,0,0,0,0,5,5,1,1,1,1,1,1,1,1,1,3,3,1,1,1,1,9,9,9,9,9,9,9,9,9,9,5,5, -5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9, -9,9,9,9,9,9,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,9,9,9,9,9,9,9,9,9,9,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5, -1,7,7,1,7,1,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,5,5,1,7,7,7,1,1,5,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,1,1,5,5,5,5,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5, -5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,0,0,0,0,0,0,0,0,0,0,0, -0,0,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -); - frame3 : icon = ( -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9, -9,9,9,9,9,9,9,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,9,9,9,9,9,9,9,9,9,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,7,1,1,1,1,1, -1,1,0,0,0,1,1,1,1,1,1,1,9,9,9,9,9,9,9,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0, -0,7,1,1,7,7,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,5,5,5,1,7,7,7,7,5,5,5,5,5,5, -5,0,0,0,0,0,0,0,7,1,7,7,7,1,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,5,5,1,1,1,7,7, -1,1,7,5,5,5,5,5,5,5,0,0,0,0,0,0,1,1,7,1,1,7,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2, -2,1,7,7,7,1,7,7,7,7,7,5,5,5,5,5,5,5,5,0,0,0,0,0,1,7,7,7,7,1,1,1,1,1,0,0,0,1,1,1, -1,1,1,2,2,2,2,2,2,1,7,7,7,7,7,7,7,1,1,5,5,5,5,5,5,5,5,5,0,0,0,0,7,7,1,7,1,7,1,1, -1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1,1,2,2,5,5,5,5,5,5,5,5,5,5,5,0,0,0, -7,7,7,7,7,1,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,5,5,5,5,5,5, -5,5,5,5,5,0,0,0,7,7,0,0,7,7,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2, -2,2,5,5,0,0,5,5,0,5,5,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,2,2,2,2,2, -2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1, -1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4, -4,6,6,6,6,6,6,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,3,3,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9, -9,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9, -9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -); - - -VAR Virscr : VirtPtr; { Our first Virtual screen } - VirScr2 : VirtPtr; { Our second Virtual screen } - Vaddr : word; { The segment of our virtual screen} - Vaddr2 : Word; { The segment of our 2nd virt. screen} - ourpal : Array [0..255,1..3] of byte; { A virtual pallette } - toaster : Array [1..10] of toastinfo; { The toaster info } - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure SetMCGA; { This procedure gets you into 320x200x256 mode. } -BEGIN - asm - mov ax,0013h - int 10h - end; -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure SetText; { This procedure returns you to text mode. } -BEGIN - asm - mov ax,0003h - int 10h - end; -END; - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure Cls (Col : Byte; Where:word); - { This clears the screen to the specified color } -BEGIN - asm - push es - mov cx, 32000; - mov es,[where] - xor di,di - mov al,[col] - mov ah,al - rep stosw - pop es - End; -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure Putpixel (X,Y : Integer; Col : Byte; where:word); - { This puts a pixel on the screen by writing directly to memory. } -BEGIN - Asm - push ds - push es - mov ax,[where] - mov es,ax - mov bx,[X] - mov dx,[Y] - push bx {; and this again for later} - mov bx, dx {; bx = dx} - mov dh, dl {; dx = dx * 256} - xor dl, dl - shl bx, 1 - shl bx, 1 - shl bx, 1 - shl bx, 1 - shl bx, 1 - shl bx, 1 {; bx = bx * 64} - add dx, bx {; dx = dx + bx (ie y*320)} - pop bx {; get back our x} - add bx, dx {; finalise location} - mov di, bx - {; es:di = where to go} - xor al,al - mov ah, [Col] - mov es:[di],ah - pop es - pop ds - End; -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -procedure WaitRetrace; assembler; - { This waits for a vertical retrace to reduce snow on the screen } -label - l1, l2; -asm - mov dx,3DAh -l1: - in al,dx - and al,08h - jnz l1 -l2: - in al,dx - and al,08h - jz l2 -end; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure Pal(Col,R,G,B : Byte); - { This sets the Red, Green and Blue values of a certain color } -Begin - asm - mov dx,3c8h - mov al,[col] - out dx,al - inc dx - mov al,[r] - out dx,al - mov al,[g] - out dx,al - mov al,[b] - out dx,al - end; -End; - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure GetPal(Col : Byte; Var R,G,B : Byte); - { This gets the Red, Green and Blue values of a certain color } -Var - rr,gg,bb : Byte; -Begin - asm - mov dx,3c7h - mov al,col - out dx,al - - add dx,2 - - in al,dx - mov [rr],al - in al,dx - mov [gg],al - in al,dx - mov [bb],al - end; - r := rr; - g := gg; - b := bb; -end; - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure SetUpVirtual; - { This sets up the memory needed for the virtual screen } -BEGIN - GetMem (VirScr,64000); - vaddr := seg (virscr^); - GetMem (VirScr2,64000); - vaddr2 := seg (virscr2^); -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure ShutDown; - { This frees the memory used by the virtual screen } -BEGIN - FreeMem (VirScr,64000); - FreeMem (VirScr2,64000); -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -procedure flip(source,dest:Word); - { This copies the entire screen at "source" to destination } -begin - asm - push ds - mov ax, [Dest] - mov es, ax - mov ax, [Source] - mov ds, ax - xor si, si - xor di, di - mov cx, 32000 - rep movsw - pop ds - end; -end; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure putico(X,Y:Word;VAR sprt : icon;Where:Word); ASSEMBLER; - { This puts an icon, EXCEPT it's color 0 (black) pixels, onto the screen - "where", at position X,Y } -label - _Redraw, _DrawLoop, _Exit, _LineLoop, _NextLine, _Store, _NoPaint; - -asm - push ds - push es - lds si,Sprt - mov ax,X { ax = x } - mov bx,Y { bx = y } -_Redraw: - push ax - mov ax,[where] - mov es,ax - - mov ax, bx {; ax = bx x = y} - mov bh, bl {; y = y * 256 bx = bx * 256} - xor bl, bl - shl ax, 1 - shl ax, 1 - shl ax, 1 - shl ax, 1 - shl ax, 1 - shl ax, 1 {; y = y * 64 ax = ax * 64} - add bx, ax {; y = (y*256) + (Y*64) bx = bx + ax (ie y*320)} - - pop ax {; get back our x} - - - add ax, bx {; finalise location} - mov di, ax - - mov dl,30 { dl = height of sprite } - xor ch,ch - mov cl,48 { cx = width of sprite } - cld - push ax - mov ax,cx -_DrawLoop: - push di { store y adr. for later } - mov cx,ax { store width } -_LineLoop: - mov bl,byte ptr [si] - or bl,bl - jnz _Store -_NoPaint: - inc si - inc di - loop _LineLoop - jmp _NextLine -_Store: - movsb - loop _LineLoop -_NextLine: - pop di - dec dl - jz _Exit - add di,320 { di = next line of sprite } - jmp _DrawLoop -_Exit: - pop ax - pop es - pop ds -end; - - - - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure Funny_line(a,b,c,d:integer;where:word); - { This procedure draws a line from a,b to c,d on screen "where". After - each pixel it plots, it increments a color counter for the next pixel. - you may easily alter this to be a normal line procedure, and it will - be quite a bit faster than the origional one I gave you. This is - because I replaced all the reals with integers. } - - function sgn(a:real):integer; - begin - if a>0 then sgn:=+1; - if a<0 then sgn:=-1; - if a=0 then sgn:=0; - end; -var i,s,d1x,d1y,d2x,d2y,u,v,m,n:integer; - count:integer; -begin - count:=50; - u:= c - a; - v:= d - b; - d1x:= SGN(u); - d1y:= SGN(v); - d2x:= SGN(u); - d2y:= 0; - m:= ABS(u); - n := ABS(v); - IF NOT (M>N) then - BEGIN - d2x := 0 ; - d2y := SGN(v); - m := ABS(v); - n := ABS(u); - END; - s := m shr 1; - FOR i := 0 TO m DO - BEGIN - putpixel(a,b,count,where); - inc (count); - if count=101 then count:=50; - s := s + n; - IF not (s0 then - putpixel (x+loop2,y+loop3,circ [loop2,loop3],vaddr); - END; - flip (vaddr,vga); { Copy the entire screen at vaddr, our virtual screen } - { on which we have done all our graphics, onto the } - { screen you see, VGA } - flip (vaddr,vaddr2); -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure rotatepal; - { This procedure rotates the colors between 50 and 100 } -VAR temp : Array [1..3] of byte; - loop1:integer; -BEGIN - Move(OurPal[100],Temp,3); - Move(OurPal[50],OurPal[51],50*3); - Move(Temp,OurPal[50],3); - For loop1:=50 to 100 do - pal (loop1,OurPal[loop1,1],OurPal[loop1,2],OurPal[loop1,3]); -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure ScreenTrans (x,y:word); - { This is a small procedure to copy a 30x30 pixel block from coordinates - x,y on the virtual screen to coordinates x,y on the true vga screen } -BEGIN - asm - push ds - push es - mov ax,vaddr - mov es,ax - mov ax,vaddr2 - mov ds,ax - mov bx,[X] - mov dx,[Y] - push bx {; and this again for later} - mov bx, dx {; bx = dx} - mov dh, dl {; dx = dx * 256} - xor dl, dl - shl bx, 1 - shl bx, 1 - shl bx, 1 - shl bx, 1 - shl bx, 1 - shl bx, 1 {; bx = bx * 64} - add dx, bx {; dx = dx + bx (ie y*320)} - pop bx {; get back our x} - add bx, dx {; finalise location} - mov di, bx {; es:di = where to go} - mov si, di - mov al,60 - mov bx, 30 { Hight of block to copy } -@@1 : - mov cx, 24 { Width of block to copy divided by 2 } - rep movsw - add di,110h { 320 - 48 = 272 .. or 110 in hex } - add si,110h - dec bx - jnz @@1 - - pop es - pop ds - end; - { I wrote this procedure late last night, so it may not be in it's - most optimised state. Sorry :-)} -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure NewToaster; - { This adds a new toaster to the screen } -VAR loop1:integer; -BEGIN - loop1:=0; - repeat - inc (loop1); - if not (toaster[loop1].active) then BEGIN - toaster[loop1].x:=random (200)+70; - toaster[loop1].y:=0; - toaster[loop1].active:=true; - toaster[loop1].frame:=1; - toaster[loop1].speed:=Random (3)+1; - loop1:=10; - END; - until loop1=10; -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure Fly; - { This is the procedure where we move and put the toasters } -VAR loop1,loop2:integer; - ch:char; -BEGIN - For loop1:=1 to 10 do - toaster[loop1].active:=FALSE; - ch:=#0; - NewToaster; - Repeat - if keypressed then BEGIN - ch:=readkey; - if ch='+' then NewToaster; { If '+' is pressed, add a toaster } - if ch='-' then BEGIN { if '-' is pressed, remove a toaster } - loop1:=0; - repeat - inc (loop1); - if toaster[loop1].active then BEGIN - screentrans (toaster[loop1].x,toaster[loop1].y); - toaster [loop1].active:=FALSE; - loop1:=10; - END; - until loop1=10; - END; - END; - for loop1:=1 to 10 do - if toaster[loop1].active then BEGIN - screentrans (toaster[loop1].x,toaster[loop1].y); - { Restore the backgrond the toaster was over } - dec (toaster[loop1].x,toaster[loop1].speed); - inc (toaster[loop1].y,toaster[loop1].speed); - { Move the toaster } - if (toaster[loop1].x<1) or (toaster[loop1].y>170) then BEGIN - toaster[loop1].active:=FALSE; - NewToaster; - END; - { When toaster reaches the edge of the screen, render it inactive - and bring a new one into existance. } - END; - for loop1:=1 to 10 do - if toaster[loop1].active then BEGIN - CASE toaster [loop1].frame of - 1 : putico (toaster[loop1].x,toaster[loop1].y,frame1,vaddr); - 3 : putico (toaster[loop1].x,toaster[loop1].y,frame2,vaddr); - 2,4 : putico (toaster[loop1].x,toaster[loop1].y,frame3,vaddr); - END; - toaster[loop1].frame:=toaster[loop1].frame+1; - if toaster [loop1].frame=5 then toaster[loop1].frame:=1; - { Draw all the toasters on the VGA screen } - END; - waitretrace; - flip (vaddr,vga); - rotatepal; - Until ch=#27; -END; - - -BEGIN - Randomize; { Make sure that the RANDOM funcion really is random } - SetupVirtual; { Set up virtual page, VADDR } - ClrScr; - writeln ('Hello! This program will demonstrate the principals of animation.'); - writeln ('The program will firstly generate an arb background screen to a'); - writeln ('virtual page, then flip it to the VGA. A toaster will then start'); - writeln ('to move across the screen. Note that the background will be restored'); - writeln ('after the toaster has passed over it. You may add or remove toasters'); - writeln ('by hitting "+" or "-" respectively. Note that the more frames you'); - writeln ('use, usually the better the routine looks. Because of space'); - writeln ('restrictions, we only had room for three frames.'); - writeln; - writeln ('The toasters were drawn by Fubar (Pieter Buys) in Autodesk Animator.'); - writeln ('I wrote a small little program to convert them into CONSTANTS. See'); - writeln ('the main text to find out how to load up AA CEL files directly.'); - writeln; - writeln; - Write (' Hit any key to contine ...'); - Readkey; - SetMCGA; - SetupScreen; { Draw the background screen to VADDR, then flip it to - the VGA screen } - Fly; { Make the toasters fly around the screen } - SetText; - ShutDown; { Free the memory taken up by virtual page } - Writeln ('All done. This concludes the seventh sample program in the ASPHYXIA'); - Writeln ('Training series. You may reach DENTHOR under the names of GRANT'); - Writeln ('SMITH/DENTHOR/ASPHYXIA on the ASPHYXIA BBS. I am also an avid'); - Writeln ('Connectix BBS user, which is unfortunatly offline for the moment.'); - Writeln ('For discussion purposes, I am also the moderator of the Programming'); - Writeln ('newsgroup on the For Your Eyes Only BBS.'); - Writeln ('The numbers are available in the main text. You may also write to me at:'); - Writeln (' Grant Smith'); - Writeln (' P.O. Box 270'); - Writeln (' Kloof'); - Writeln (' 3640'); - Writeln ('I hope to hear from you soon!'); - Writeln; Writeln; - Write ('Hit any key to exit ...'); - Readkey; -END. diff --git a/16/PCGPE10/TUT8.TXT b/16/PCGPE10/TUT8.TXT deleted file mode 100644 index abea3845..00000000 --- a/16/PCGPE10/TUT8.TXT +++ /dev/null @@ -1,792 +0,0 @@ - ÕÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͸ - ³ W E L C O M E ³ - ³ To the VGA Trainer Program ³ ³ - ³ By ³ ³ - ³ DENTHOR of ASPHYXIA ³ ³ ³ - ÔÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ; ³ ³ - ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³ - ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - --==[ PART 8 ]==-- - - - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ Introduction - -Hello everybody! Christmas is over, the last of the chocolates have been -eaten, so it's time to get on with this, the eighth part of the ASPHYXIA -Demo Trainer Series. This particular part is primarily about 3-D, but -also includes a bit on optimisation. - -If you are already a 3-D guru, you may as well skip this text file, have -a quick look at the sample program then go back to sleep, because I am -going to explain in minute detail exactly how the routines work ;) - -If you would like to contact me, or the team, there are many ways you -can do it : 1) Write a message to Grant Smith/Denthor/Asphyxia in private mail - on the ASPHYXIA BBS. - 2) Write a message in the Programming conference on the - For Your Eyes Only BBS (of which I am the Moderator ) - This is preferred if you have a general programming query - or problem others would benefit from. - 4) Write to Denthor, EzE or Goth on Connectix. - 5) Write to : Grant Smith - P.O.Box 270 Kloof - 3640 - Natal - 6) Call me (Grant Smith) at (031) 73 2129 (leave a message if you - call during varsity) - 7) Write to mcphail@beastie.cs.und.ac.za on InterNet, and - mention the word Denthor near the top of the letter. - -NB : If you are a representative of a company or BBS, and want ASPHYXIA - to do you a demo, leave mail to me; we can discuss it. -NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling - quite lonely and want to meet/help out/exchange code with other demo - groups. What do you have to lose? Leave a message here and we can work - out how to transfer it. We really want to hear from you! - - - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ Optimisation - -Before I begin with the note on 3-D, I would like to stress that many of -these routines, and probably most of your own, could be sped up quite a -bit with a little optimisation. One must realise, however, that you must -take a look at WHAT to optimise ... converting a routine that is only -called once at startup into a tightly coded assembler routine may show -off your merits as a coder, but does absolutely nothing to speed up your -program. Something that is called often per frame is something that -needs to be as fast as possible. For some, a much used procedure is the -PutPixel procedure. Here is the putpixel procedure I gave you last week: - -Procedure Putpixel (X,Y : Integer; Col : Byte; where:word); -BEGIN - Asm - push ds { 14 clock ticks } - push es { 14 } - mov ax,[where] { 8 } - mov es,ax { 2 } - mov bx,[X] { 8 } - mov dx,[Y] { 8 } - push bx { 15 } - mov bx, dx { 2 } - mov dh, dl { 2 } - xor dl, dl { 3 } - shl bx, 1 { 2 } - shl bx, 1 { 2 } - shl bx, 1 { 2 } - shl bx, 1 { 2 } - shl bx, 1 { 2 } - shl bx, 1 { 2 } - add dx, bx { 3 } - pop bx { 12 } - add bx, dx { 3 } - mov di, bx { 2 } - xor al,al { 3 } - mov ah, [Col] { 8 } - mov es:[di],ah { 10 } - pop es { 12 } - pop ds { 12 } - End; -END; - Total = 153 clock ticks -NOTE : Don't take my clock ticks as gospel, I probably got one or two - wrong. - -Right, now for some optimising. Firstly, if you have 286 instructions -turned on, you may replace the 6 shl,1 with shl,6. Secondly, the Pascal -compiler automatically pushes and pops ES, so those two lines may be -removed. DS:[SI] is not altered in this procedure, so we may remove -those too. Also, instead of moving COL into ah, we move it into AL and -call stosb (es:[di]:=al; inc di). Let's have a look at the routine now : - -Procedure Putpixel (X,Y : Integer; Col : Byte; where:word); -BEGIN - Asm - mov ax,[where] { 8 } - mov es,ax { 2 } - mov bx,[X] { 8 } - mov dx,[Y] { 8 } - push bx { 15 } - mov bx, dx { 2 } - mov dh, dl { 2 } - xor dl, dl { 3 } - shl bx, 6 { 8 } - add dx, bx { 3 } - pop bx { 12 } - add bx, dx { 3 } - mov di, bx { 2 } - mov al, [Col] { 8 } - stosb { 11 } - End; -END; - Total = 95 clock ticks - -Now, let us move the value of BX directly into DI, thereby removing a -costly push and pop. The MOV and the XOR of DX can be replaced by it's -equivalent, SHL DX,8 - -Procedure Putpixel (X,Y : Integer; Col : Byte; where:word); assembler; -asm - mov ax,[where] { 8 } - mov es,ax { 2 } - mov bx,[X] { 8 } - mov dx,[Y] { 8 } - mov di,bx { 2 } - mov bx, dx { 2 } - shl dx, 8 { 8 } - shl bx, 6 { 8 } - add dx, bx { 3 } - add di, dx { 3 } - mov al, [Col] { 8 } - stosb { 11 } -end; - Total = 71 clock ticks - -As you can see, we have brought the clock ticks down from 153 ticks to -71 ticks ... quite an improvement. (The current ASPHYXIA putpixel takes -48 clock ticks) . As you can see, by going through your routines a few -times, you can spot and remove unnecessary instructions, thereby greatly -increasing the speed of your program. - - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ Defining a 3-D object - -Drawing an object in 3-D is not that easy. Sitting down and plotting a -list of X,Y and Z points can be a time consuming business. So, let us -first look at the three axes you are drawing them on : - - Y Z - /|\ / - | / - X<-----|-----> - | - \|/ - -X is the horisontal axis, from left to right. Y is the vertical axis, -from top to bottom. Z is the depth, going straight into the screen. - -In this trainer, we are using lines, so we define 2 X,Y and Z -coordinates, one for each end of the line. A line from far away, in the -upper left of the X and Y axes, to close up in the bottom right of the -X and Y axes, would look like this : - -{ x1 y1 z1 x2 y2 z2 } - ( (-10,10,-10),(10,-10,10) ) - - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ Rotating a point with matrixes - -NOTE : I thought that more then one matix are matrisese (sp), but my - spellchecker insists it is matrixes, so I let it have it's way - ;-) - -Having a 3-D object is useless unless you can rotate it some way. For -demonstration purposes, I will begin by working in two dimensions, X and -Y. - -Let us say you have a point, A,B, on a graph. - Y - | /O1 (Cos (a)*A-Sin (a)*B , Sin (a)*A+Cos (a)*B) - |/ (A,B) - X<-----|------O--> - | - | - -Now, let us say we rotate this point by 45 degrees anti-clockwise. The -new A,B can be easily be calculated using sin and cos, by an adaption of -our circle algorithm, ie. - A2:=Cos (45)*A - Sin (45)*B - B2:=Sin (45)*A + Cos (45)*B -I recall that in standard 8 and 9, we went rather heavily into this in -maths. If you have troubles, fine a 8/9/10 maths book and have a look; -it will go through the proofs etc. - -Anyway, we have now rotated an object in two dimensions, AROUND THE Z -AXIS. In matrix form, the equation looks like this : - - [ Cos (a) -Sin (a) 0 0 ] [ x ] - [ Sin (a) Cos (a) 0 0 ] . [ y ] - [ 0 0 1 0 ] [ z ] - [ 0 0 0 1 ] [ 1 ] - -I will not go to deeply into matrixes math at this stage, as there are -many books on the subject (it is not part of matric maths, however). To -multiply a matrix, to add the products of the row of the left matrix and -the column of the right matrix, and repeat this for all the columns of the -left matrix. I don't explain it as well as my first year maths lecturer, -but have a look at how I derived A2 and B2 above. Here are the other -matrixes : - -Matrix for rotation around the Y axis : - [ Cos (a) 0 -Sin (a) 0 ] [ x ] - [ 0 1 0 0 ] . [ y ] - [ Sin (a) 0 Cos (a) 0 ] [ z ] - [ 0 0 0 1 ] [ 1 ] - -Matrix for rotation around the X axis : - [ 1 0 0 ] [ x ] - [ 0 Cos (a) -Sin (a) 0 ] . [ y ] - [ 0 Sin (a) Cos (a) 0 ] [ z ] - [ 0 0 0 1 ] [ 1 ] - -By putting all these matrixes together, we can translate out 3D points -around the origin of 0,0,0. See the sample program for how we put them -together. - -In the sample program, we have a constant, never changing base object. -This is rotated into a second variable, which is then drawn. I am sure -many of you can thing of cool ways to change the base object, the -effects of which will appear while the object is rotating. One idea is -to "pulsate" a certain point of the object according to the beat of the -music being played in the background. Be creative. If you feel up to it, -you could make your own version of transformers ;) - - - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ Drawing a 3D point to screen - -Having a rotated 3D object is useless unless we can draw it to screen. -But how do we show a 3D point on a 2D screen? The answer needs a bit of -explaining. Examine the following diagram : - - | ________------------- - ____|___------ o Object at X,Y,Z o1 Object at X,Y,Z2 - Eye -> O)____|___ - | ------________ - | -------------- Field of vision - Screen - -Let us pretend that the centre of the screen is the horizon of our -little 3D world. If we draw a three dimensional line from object "o" to -the centre of the eye, and place a pixel on the X and Y coordinates -where it passes through the screen, we will notice that when we do the -same with object o1, the pixel is closer to the horizon, even though -their 3D X and Y coords are identical, but "o1"'s Z is larger then -"o"'s. This means that the further away a point is, the closer to the -horizon it is, or the smaller the object will appear. That sounds -right, doesent it? But, I hear you cry, how do we translate this into a -formula? The answer is quite simple. Divide your X and your Y by your Z. -Think about it. The larger the number you divide by, the closer to zero, -or the horizon, is the result! This means, the bigger the Z, the -further away is the object! Here it is in equation form : - - nx := 256*x div (z-Zoff)+Xoff - ny := 256*y div (z-Zoff)+Yoff - -NOTE : Zoff is how far away the entire object is, Xoff is the objects X - value, and Yoff is the objects Y value. In the sample program, - Xoff start off at 160 and Yoff starts off at 100, so that the - object is in the middle of the screen. - -The 256 that you times by is the perspective with which you are viewing. -Changing this value gives you a "fish eye" effect when viewing the -object. Anyway, there you have it! Draw a pixel at nx,ny, and viola! you -are now doing 3D! Easy, wasn't it? - - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ Possible improvements - -This program is not the most optimised routine you will ever encounter -(;-)) ... it uses 12 muls and 2 divs per point. (Asphyxia currently has -9 muls and 2 divs per point) Real math is used for all the calculations -in the sample program, which is slow, so fixed point math should be -implemented (I will cover fixed point math in a future trainer). The -line routine currently being used is very slow. Chain-4 could be used to -cut down on screen flipping times. - -Color values per line should be added, base object morphing could be put -in, polygons could be used instead of lines, handling of more then one -object should be implemented, clipping should be added instead of not -drawing something if any part of it is out of bounds. - -In other words, you have a lot of work ahead of you ;) - - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ In closing - -There are a lot of books out there on 3D, and quite a few sample -programs too. Have a look at them, and use the best bits to create your -own, unique 3D engine, with which you can do anything you want. I am -very interested in 3D (though EzE and Goth wrote most of ASPHYXIA'S 3D -routines), and would like to see what you can do with it. Leave me a -message through one of the means described above. - -I am delving into the murky world of texture mapping. If anyone out -there has some routines on the subject and are interested in swapping, -give me a buzz! - -What to do in future trainers? Help me out on this one! Are there any -effects/areas you would like a bit of info on? Leave me a message! - -I unfortunately did not get any messages regarding BBS's that carry this -series, so the list that follows is the same one from last time. Give -me your names, sysops! - -Aaaaargh!!! Try as I might, I can't think of a new quote. Next time, I -promise! ;-) - -Bye for now, - - Denthor - - -These fine BBS's carry the ASPHYXIA DEMO TRAINER SERIES : (alphabetical) - -ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍËÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍËÍÍÍÍÍËÍÍÍËÍÍÍÍËÍÍÍÍ» -ºBBS Name ºTelephone No. ºOpen ºMsgºFileºPastº -ÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÍÍÍÍÍÎÍÍÍÎÍÍÍÍÎÍÍÍ͹ -ºASPHYXIA BBS #1 º(031) 765-5312 ºALL º * º * º * º -ºASPHYXIA BBS #2 º(031) 765-6293 ºALL º * º * º * º -ºConnectix BBS º(031) 266-9992 ºALL º * º º º -ºFor Your Eyes Only BBS º(031) 285-318 ºA/H º * º * º * º -ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÊÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÊÍÍÍÍÍÊÍÍÍÊÍÍÍÍÊÍÍÍͼ - -Open = Open at all times or only A/H -Msg = Available in message base -File = Available in file base -Past = Previous Parts available - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ TUTPROG8.PAS ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -{$X+} -USES Crt; - -CONST VGA = $A000; - MaxLines = 12; - Obj : Array [1..MaxLines,1..2,1..3] of integer = - ( - ((-10,-10,-10),(10,-10,-10)),((-10,-10,-10),(-10,10,-10)), - ((-10,10,-10),(10,10,-10)),((10,-10,-10),(10,10,-10)), - ((-10,-10,10),(10,-10,10)),((-10,-10,10),(-10,10,10)), - ((-10,10,10),(10,10,10)),((10,-10,10),(10,10,10)), - ((-10,-10,10),(-10,-10,-10)),((-10,10,10),(-10,10,-10)), - ((10,10,10),(10,10,-10)),((10,-10,10),(10,-10,-10)) - ); { The 3-D coordinates of our object ... stored as (X1,Y1,Z1), } - { (X2,Y2,Z2) ... for the two ends of a line } - - -Type Point = Record - x,y,z:real; { The data on every point we rotate} - END; - Virtual = Array [1..64000] of byte; { The size of our Virtual Screen } - VirtPtr = ^Virtual; { Pointer to the virtual screen } - - -VAR Lines : Array [1..MaxLines,1..2] of Point; { The base object rotated } - Translated : Array [1..MaxLines,1..2] of Point; { The rotated object } - Xoff,Yoff,Zoff:Integer; { Used for movement of the object } - lookup : Array [0..360,1..2] of real; { Our sin and cos lookup table } - Virscr : VirtPtr; { Our first Virtual screen } - Vaddr : word; { The segment of our virtual screen} - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure SetMCGA; { This procedure gets you into 320x200x256 mode. } -BEGIN - asm - mov ax,0013h - int 10h - end; -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure SetText; { This procedure returns you to text mode. } -BEGIN - asm - mov ax,0003h - int 10h - end; -END; - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure Cls (Where:word;Col : Byte); - { This clears the screen to the specified color } -BEGIN - asm - push es - mov cx, 32000; - mov es,[where] - xor di,di - mov al,[col] - mov ah,al - rep stosw - pop es - End; -END; - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure SetUpVirtual; - { This sets up the memory needed for the virtual screen } -BEGIN - GetMem (VirScr,64000); - vaddr := seg (virscr^); -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure ShutDown; - { This frees the memory used by the virtual screen } -BEGIN - FreeMem (VirScr,64000); -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -procedure flip(source,dest:Word); - { This copies the entire screen at "source" to destination } -begin - asm - push ds - mov ax, [Dest] - mov es, ax - mov ax, [Source] - mov ds, ax - xor si, si - xor di, di - mov cx, 32000 - rep movsw - pop ds - end; -end; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure Pal(Col,R,G,B : Byte); - { This sets the Red, Green and Blue values of a certain color } -Begin - asm - mov dx,3c8h - mov al,[col] - out dx,al - inc dx - mov al,[r] - out dx,al - mov al,[g] - out dx,al - mov al,[b] - out dx,al - end; -End; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Function rad (theta : real) : real; - { This calculates the degrees of an angle } -BEGIN - rad := theta * pi / 180 -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure SetUpPoints; - { This sets the basic offsets of the object, creates the lookup table and - moves the object from a constant to a variable } -VAR loop1:integer; -BEGIN - Xoff:=160; - Yoff:=100; - Zoff:=-256; - For loop1:=0 to 360 do BEGIN - lookup [loop1,1]:=sin (rad (loop1)); - lookup [loop1,2]:=cos (rad (loop1)); - END; - For loop1:=1 to MaxLines do BEGIN - Lines [loop1,1].x:=Obj [loop1,1,1]; - Lines [loop1,1].y:=Obj [loop1,1,2]; - Lines [loop1,1].z:=Obj [loop1,1,3]; - Lines [loop1,2].x:=Obj [loop1,2,1]; - Lines [loop1,2].y:=Obj [loop1,2,2]; - Lines [loop1,2].z:=Obj [loop1,2,3]; - END; -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure Putpixel (X,Y : Integer; Col : Byte; where:word); - { This puts a pixel on the screen by writing directly to memory. } -BEGIN - Asm - mov ax,[where] - mov es,ax - mov bx,[X] - mov dx,[Y] - mov di,bx - mov bx, dx {; bx = dx} - shl dx, 8 - shl bx, 6 - add dx, bx {; dx = dx + bx (ie y*320)} - add di, dx {; finalise location} - mov al, [Col] - stosb - End; -END; - - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure Line(a,b,c,d:integer;col:byte;where:word); - { This draws a solid line from a,b to c,d in colour col } - function sgn(a:real):integer; - begin - if a>0 then sgn:=+1; - if a<0 then sgn:=-1; - if a=0 then sgn:=0; - end; -var i,s,d1x,d1y,d2x,d2y,u,v,m,n:integer; -begin - u:= c - a; - v:= d - b; - d1x:= SGN(u); - d1y:= SGN(v); - d2x:= SGN(u); - d2y:= 0; - m:= ABS(u); - n := ABS(v); - IF NOT (M>N) then - BEGIN - d2x := 0 ; - d2y := SGN(v); - m := ABS(v); - n := ABS(u); - END; - s := m shr 1; - FOR i := 0 TO m DO - BEGIN - putpixel(a,b,col,where); - s := s + n; - IF not (s0 then BEGIN - temp.x:=lookup[y,2]*translated[loop1,1].x - lookup[y,1]*translated[loop1,1].y; - temp.y:=lookup[y,1]*translated[loop1,1].x + lookup[y,2]*translated[loop1,1].y; - temp.z:=translated[loop1,1].z; - translated[loop1,1]:=temp; - END; - - If z>0 then BEGIN - temp.x:=lookup[z,2]*translated[loop1,1].x + lookup[z,1]*translated[loop1,1].z; - temp.y:=translated[loop1,1].y; - temp.z:=-lookup[z,1]*translated[loop1,1].x + lookup[z,2]*translated[loop1,1].z; - translated[loop1,1]:=temp; - END; - - temp.x:=lines[loop1,2].x; - temp.y:=cos (rad(X))*lines[loop1,2].y - sin (rad(X))*lines[loop1,2].z; - temp.z:=sin (rad(X))*lines[loop1,2].y + cos (rad(X))*lines[loop1,2].z; - - translated[loop1,2]:=temp; - - If y>0 then BEGIN - temp.x:=cos (rad(Y))*translated[loop1,2].x - sin (rad(Y))*translated[loop1,2].y; - temp.y:=sin (rad(Y))*translated[loop1,2].x + cos (rad(Y))*translated[loop1,2].y; - temp.z:=translated[loop1,2].z; - translated[loop1,2]:=temp; - END; - - If z>0 then BEGIN - temp.x:=cos (rad(Z))*translated[loop1,2].x + sin (rad(Z))*translated[loop1,2].z; - temp.y:=translated[loop1,2].y; - temp.z:=-sin (rad(Z))*translated[loop1,2].x + cos (rad(Z))*translated[loop1,2].z; - translated[loop1,2]:=temp; - END; - END; -END; - - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure DrawPoints; - { This draws the translated object to the virtual screen } -VAR loop1:Integer; - nx,ny,nx2,ny2:integer; - temp:integer; -BEGIN - For loop1:=1 to MaxLines do BEGIN - If (translated[loop1,1].z+zoff<0) and (translated[loop1,2].z+zoff<0) then BEGIN - temp:=round (translated[loop1,1].z+zoff); - nx :=round (256*translated[loop1,1].X) div temp+xoff; - ny :=round (256*translated[loop1,1].Y) div temp+yoff; - temp:=round (translated[loop1,2].z+zoff); - nx2:=round (256*translated[loop1,2].X) div temp+xoff; - ny2:=round (256*translated[loop1,2].Y) div temp+yoff; - If (NX > 0) and (NX < 320) and (NY > 25) and (NY < 200) and - (NX2> 0) and (NX2< 320) and (NY2> 25) and (NY2< 200) then - line (nx,ny,nx2,ny2,13,vaddr); - END; - END; -END; - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure ClearPoints; - { This clears the translated object from the virtual screen ... believe it - or not, this is faster then a straight "cls (vaddr,0)" } -VAR loop1:Integer; - nx,ny,nx2,ny2:Integer; - temp:integer; -BEGIN - For loop1:=1 to MaxLines do BEGIN - If (translated[loop1,1].z+zoff<0) and (translated[loop1,2].z+zoff<0) then BEGIN - temp:=round (translated[loop1,1].z+zoff); - nx :=round (256*translated[loop1,1].X) div temp+xoff; - ny :=round (256*translated[loop1,1].Y) div temp+yoff; - temp:=round (translated[loop1,2].z+zoff); - nx2:=round (256*translated[loop1,2].X) div temp+xoff; - ny2:=round (256*translated[loop1,2].Y) div temp+yoff; - If (NX > 0) and (NX < 320) and (NY > 25) and (NY < 200) and - (NX2> 0) and (NX2< 320) and (NY2> 25) and (NY2< 200) then - line (nx,ny,nx2,ny2,0,vaddr); - END; - END; -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure MoveAround; - { This is the main display procedure. Firstly it brings the object towards - the viewer by increasing the Zoff, then passes control to the user } -VAR deg,loop1:integer; - ch:char; -BEGIN - deg:=0; - ch:=#0; - Cls (vaddr,0); - DrawLogo; - For loop1:=-256 to -40 do BEGIN - zoff:=loop1*2; - RotatePoints (deg,deg,deg); - DrawPoints; - flip (vaddr,vga); - ClearPoints; - deg:=(deg+5) mod 360; - END; - - Repeat - if keypressed then BEGIN - ch:=upcase (Readkey); - Case ch of 'A' : zoff:=zoff+5; - 'Z' : zoff:=zoff-5; - ',' : xoff:=xoff-5; - '.' : xoff:=xoff+5; - 'S' : yoff:=yoff-5; - 'X' : yoff:=yoff+5; - END; - END; - DrawPoints; - flip (vaddr,vga); - ClearPoints; - RotatePoints (deg,deg,deg); - deg:=(deg+5) mod 360; - Until ch=#27; -END; - - -BEGIN - SetUpVirtual; - Writeln ('Greetings and salutations! Hope you had a great Christmas and New'); - Writeln ('year! ;-) ... Anyway, this tutorial is on 3-D, so this is what is'); - Writeln ('going to happen ... a wireframe square will come towards you.'); - Writeln ('When it gets close, you get control. "A" and "Z" control the Z'); - Writeln ('movement, "," and "." control the X movement, and "S" and "X"'); - Writeln ('control the Y movement. I have not included rotation control, but'); - Writeln ('it should be easy enough to put in yourself ... if you have any'); - Writeln ('hassles, leave me mail.'); - Writeln; - Writeln ('Read the main text file for ideas on improving this code ... and'); - Writeln ('welcome to the world of 3-D!'); - writeln; - writeln; - Write (' Hit any key to contine ...'); - Readkey; - SetMCGA; - SetUpPoints; - MoveAround; - SetText; - ShutDown; - Writeln ('All done. This concludes the eigth sample program in the ASPHYXIA'); - Writeln ('Training series. You may reach DENTHOR under the names of GRANT'); - Writeln ('SMITH/DENTHOR/ASPHYXIA on the ASPHYXIA BBS. I am also an avid'); - Writeln ('Connectix BBS user, and occasionally read RSAProg.'); - Writeln ('For discussion purposes, I am also the moderator of the Programming'); - Writeln ('newsgroup on the For Your Eyes Only BBS.'); - Writeln ('The numbers are available in the main text. You may also write to me at:'); - Writeln (' Grant Smith'); - Writeln (' P.O. Box 270'); - Writeln (' Kloof'); - Writeln (' 3640'); - Writeln ('I hope to hear from you soon!'); - Writeln; Writeln; - Write ('Hit any key to exit ...'); - Readkey; -END. diff --git a/16/PCGPE10/TUT9.TXT b/16/PCGPE10/TUT9.TXT deleted file mode 100644 index 0e80d21b..00000000 --- a/16/PCGPE10/TUT9.TXT +++ /dev/null @@ -1,823 +0,0 @@ - ÕÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͸ - ³ W E L C O M E ³ - ³ To the VGA Trainer Program ³ ³ - ³ By ³ ³ - ³ DENTHOR of ASPHYXIA ³ ³ ³ - ÔÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ; ³ ³ - ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³ - ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - --==[ PART 9 ]==-- - - - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ Introduction - -Hi there! ASPHYXIA is BACK with our first MegaDemo, Psycho Neurosis! A -paltry 1.3MB download is all it takes to see the group from Durbs first -major production! We are quite proud of it, and think you should see it -;) - -Secondly, I released a small little trainer (a trainerette ;-)) on -RsaPROG and Connexctix BBS mail, also on the ASPHYXIA BBS as COPPERS.ZIP -It is a small Pascal program demonstrating how to display copper bars in -text mode. Also includes a check for horizontal retrace (A lot of people -wanted it, that is why I wrote the program) (ASPHYXIA ... first with the -trainer goodies ;-) aargh, sorry, had to be done )) - -Thirdly, sorry about the problems with Tut 8! If you had all the -checking on, the tutorial would probably die on the first points. The -reason is this : in the first loop, we have DrawPoints then -RotatePoints. The variables used in DrawPoints are set in RotatePoints, -so if you put RotatePoints before DrawPoints, the program should work -fine. Alternatively, turn off error checking 8-) - -Fourthly, I have had a surprisingly large number of people saying that -"I get this, like, strange '286 instructions not enabled' message! -What's wrong with your code, dude?" To all of you, get into Pascal, hit -Alt-O (for options), hit enter and a 2 (for Enable 286 instructions). Hard -hey? Doesn't anyone EVER set up their version of Pascal? - -Now, on to todays tutorial! 3D solids. That is what the people wanted, -that is what the people get! This tutorial is mainly on how to draw the -polygon on screen. For details on how the 3D stuff works, check out tut -8. - - - -If you would like to contact me, or the team, there are many ways you -can do it : 1) Write a message to Grant Smith/Denthor/Asphyxia in private mail - on the ASPHYXIA BBS. - 2) Write to Denthor, EzE or Goth on Connectix. - 3) Write to : Grant Smith - P.O.Box 270 Kloof - 3640 - Natal - 4) Call me (Grant Smith) at (031) 73 2129 (leave a message if you - call during varsity) - 5) Write to mcphail@beastie.cs.und.ac.za on InterNet, and - mention the word Denthor near the top of the letter. - -NB : If you are a representative of a company or BBS, and want ASPHYXIA - to do you a demo, leave mail to me; we can discuss it. -NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling - quite lonely and want to meet/help out/exchange code with other demo - groups. What do you have to lose? Leave a message here and we can work - out how to transfer it. We really want to hear from you! - - - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ How to draw a polygon - -Sounds easy enough, right? WRONG! There are many, many different ways to -go about this, and today I'll only be showing you one. Please don't take -what is written here as anything approaching the best method, it is just -here to get you on your way... - -The procedure I will be using here is based on something most of us -learned in standard eight ... I think. I seem to recall doing something -like this in Mrs. Reids maths class all those years ago ;) - -Take two points, x1,y1 and x2,y2. Draw them : - - + (x1,y1) - \ - \ <-- Point a somewhere along the line - \ - + (x2,y2) - -Right, so what we have to do is this : if we know the y-coord of a, what -is it's x-coord? To prove the method we will give the points random -values. - - + (2,10) - \ - \ <-- a.y = 12 - \ - + (15,30) - -Right. Simple enough problem. This is how we do it : - (a.y-y1) = (12 - 10) {to get a.y as though y1 was zero} - *(x2-x1) = *(15 - 2) {the total x-length of the line} - /(y2-y1) = /(30 - 10) {the total y-length of the line} - +x1 = +2 { to get the equation back to real coords} - -So our equation is : (a.y-y1)*(x2-x1)/(y2-y1)+x4 or - (12-10)*(15-2)/(30-10)+2 - which gives you : - 2*13/20+2 = 26/20+2 - = 3.3 - -That means that along the line with y=12, x is equal to 3.3. Since we -are not concerned with the decimal place, we replace the / with a div, -which in Pascal gives us an integer result, and is faster too. All well -and good, I hear you cry, but what does this have to do with life and -how it relates to polygons in general. The answer is simple. For each of -the four sides of the polygon we do the above test for each y line. We -store the smallest and the largest x values into separate variables for -each line, and draw a horizontal line between them. Ta-Dah! We have a -cool polygon! - -For example : Two lines going down : - - + + - / <-x1 x2->| <--For this y line - / | - + + - -Find x1 and x2 for that y, then draw a line between them. Repeat for all -y values. - -Of course, it's not as simple as that. We have to make sure we only -check those y lines that contain the polygon (a simple min y, max y test -for all the points). We also have to check that the line we are -calculating actually extends as far as where our current y is (check -that the point is between both y's). We have to compare each x to see -weather it is smaller then the minimum x value so far, or bigger then -the maximum (the original x min is set as a high number, and the x max -is set as a small number). We must also check that we only draw to the -place that we can see ( 0-319 on the x ; 0-199 on the y (the size of the -MCGA screen)) - -To see how this looks in practice, have a look at the sample code -provided. (Mrs. Reid would probably kill me for the above explanation, -so when you learn it in school, split it up into thousands of smaller -equations to get the same answer ;)) - -Okay, that's it! What's that? How do you draw a vertical line? Thats -simple ... - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ Drawing a vertical line - -Right, this is a lot easier than drawing a normal line (Tut 5 .. I -think), because you stay on the same y value. So, what you do is you set -ES to the screen you want to write to, and get DI to the start of the -y-line (see earlier trainers for a description of how SEGMENT:OFFSET -works. - -IN : x1 , x2, y, color, where - - asm - mov ax,where - mov es,ax - mov di,y - mov ax,y - shl di,8 { di:=di*256 } - shl ax,6 { ax:=ax*64 } - add di,ax { di := (y*256)+(y*64) := y*320 Faster then a - straight multiplication } - -Right, now you add the first x value to get your startoff. - add di,x1 -Move the color to store into ah and al - mov al,color - mov ah,al { ah:=al:=color } -then get CX equal to how many pixels across you want to go - mov cx,x2 - sub cx,x1 { cx:=x2-x1 } -Okay, as we all know, moving a word is a lot faster then moving a byte, -so we halve CX - shr cx,1 { cx:=cx/2 } -but what happens if CX was an odd number. After a shift, the value of -the last number is placed in the carry flag, so what we do is jump over -a single byte move if the carry flag is zero, or execute it if it is -one. - jnc @Start { If there is no carry, jump to label Start } - stosb { ES:[DI]:=al ; increment DI } - @Start : { Label Start } - rep stosw { ES:[DI]:=ax ; DI:=DI+2; repeat CX times } - -Right, the finished product looks like this : - -Procedure Hline (x1,x2,y:word;col:byte;where:word); assembler; - { This draws a horizontal line from x1 to x2 on line y in color col } -asm - mov ax,where - mov es,ax - mov ax,y - mov di,ax - shl ax,8 - shl di,6 - add di,ax - add di,x1 - - mov al,col - mov ah,al - mov cx,x2 - sub cx,x1 - shr cx,1 - jnc @start - stosb -@Start : - rep stosw -end; - -Done! - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -þ In closing - -This 3D system is still not perfect. It needs to be faster, and now I -have also dumped the problem of face-sorting on you! Nyahahahaha! - - [ My sister and I were driving along the other day when she - asked me, what would I like for my computer. - I thought long and hard about it, and came up with the - following hypothesis. When a girl gets a Barbie doll, she - then wants the extra ballgown for the doll, then the - hairbrush, and the car, and the house, and the friends - etc. - When a guy gets a computer, he wants the extra memory, the - bigger hard drive, the maths co-pro, the better - motherboard, the latest software, and the bigger monitor - etc. - I told my sister all of this, and finished up with : "So as - you can see, computers are Barbie dolls for MEN!" - She called me a chauvinist. And hit me. Hard. - ] - - Grant Smith - 19:24 - 26/2/94 - -See you next time! - - Denthor - -These fine BBS's carry the ASPHYXIA DEMO TRAINER SERIES : (alphabetical) - -ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍËÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍËÍÍÍÍÍËÍÍÍËÍÍÍÍËÍÍÍÍ» -ºBBS Name ºTelephone No. ºOpen ºMsgºFileºPastº -ÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÍÍÍÍÍÎÍÍÍÎÍÍÍÍÎÍÍÍ͹ -ºASPHYXIA BBS #1 º(031) 765-5312 ºALL º * º * º * º -ºASPHYXIA BBS #2 º(031) 765-6293 ºALL º * º * º * º -ºConnectix BBS º(031) 266-9992 ºALL º º * º * º -ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÊÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÊÍÍÍÍÍÊÍÍÍÊÍÍÍÍÊÍÍÍͼ - -Open = Open at all times or only A/H -Msg = Available in message base -File = Available in file base -Past = Previous Parts available - -Does no other BBS's ANYWHERE carry the trainer? Am I writing this for -three people who get it from one of these BBS's each week? Should I go -on? (Hehehehe ... I was pleased to note that Tut 8 was THE most -downloaded file from ASPHYXIA BBS last month ... ) - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ TUTPROG9.PAS ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -{$X+} -USES Crt; - -CONST VGA = $A000; - maxpolys = 5; - A : Array [1..maxpolys,1..4,1..3] of integer = - ( - ((-10,10,0),(-2,-10,0),(0,-10,0),(-5,10,0)), - ((10,10,0),(2,-10,0),(0,-10,0),(5,10,0)), - ((-2,-10,0),(2,-10,0),(2,-5,0),(-2,-5,0)), - ((-6,0,0),(6,0,0),(7,5,0),(-7,5,0)), - ((0,0,0),(0,0,0),(0,0,0),(0,0,0)) - ); { The 3-D coordinates of our object ... stored as (X1,Y1,Z1), } - { (X2,Y2,Z2) ... for the 4 points of a poly } - S : Array [1..maxpolys,1..4,1..3] of integer = - ( - ((-10,-10,0),(10,-10,0),(10,-7,0),(-10,-7,0)), - ((-10,10,0),(10,10,0),(10,7,0),(-10,7,0)), - ((-10,1,0),(10,1,0),(10,-2,0),(-10,-2,0)), - ((-10,-8,0),(-7,-8,0),(-7,0,0),(-10,0,0)), - ((10,8,0),(7,8,0),(7,0,0),(10,0,0)) - ); { The 3-D coordinates of our object ... stored as (X1,Y1,Z1), } - { (X2,Y2,Z2) ... for the 4 points of a poly } - P : Array [1..maxpolys,1..4,1..3] of integer = - ( - ((-10,-10,0),(-7,-10,0),(-7,10,0),(-10,10,0)), - ((10,-10,0),(7,-10,0),(7,0,0),(10,0,0)), - ((-9,-10,0),(9,-10,0),(9,-7,0),(-9,-7,0)), - ((-9,-1,0),(9,-1,0),(9,2,0),(-9,2,0)), - ((0,0,0),(0,0,0),(0,0,0),(0,0,0)) - ); { The 3-D coordinates of our object ... stored as (X1,Y1,Z1), } - { (X2,Y2,Z2) ... for the 4 points of a poly } - H : Array [1..maxpolys,1..4,1..3] of integer = - ( - ((-10,-10,0),(-7,-10,0),(-7,10,0),(-10,10,0)), - ((10,-10,0),(7,-10,0),(7,10,0),(10,10,0)), - ((-9,-1,0),(9,-1,0),(9,2,0),(-9,2,0)), - ((0,0,0),(0,0,0),(0,0,0),(0,0,0)), - ((0,0,0),(0,0,0),(0,0,0),(0,0,0)) - ); { The 3-D coordinates of our object ... stored as (X1,Y1,Z1), } - { (X2,Y2,Z2) ... for the 4 points of a poly } - Y : Array [1..maxpolys,1..4,1..3] of integer = - ( - ((-7,-10,0),(0,-3,0),(0,0,0),(-10,-7,0)), - ((7,-10,0),(0,-3,0),(0,0,0),(10,-7,0)), - ((-2,-3,0),(2,-3,0),(2,10,0),(-2,10,0)), - ((0,0,0),(0,0,0),(0,0,0),(0,0,0)), - ((0,0,0),(0,0,0),(0,0,0),(0,0,0)) - ); { The 3-D coordinates of our object ... stored as (X1,Y1,Z1), } - { (X2,Y2,Z2) ... for the 4 points of a poly } - X : Array [1..maxpolys,1..4,1..3] of integer = - ( - ((-7,-10,0),(10,7,0),(7,10,0),(-10,-7,0)), - ((7,-10,0),(-10,7,0),(-7,10,0),(10,-7,0)), - ((0,0,0),(0,0,0),(0,0,0),(0,0,0)), - ((0,0,0),(0,0,0),(0,0,0),(0,0,0)), - ((0,0,0),(0,0,0),(0,0,0),(0,0,0)) - ); { The 3-D coordinates of our object ... stored as (X1,Y1,Z1), } - { (X2,Y2,Z2) ... for the 4 points of a poly } - I : Array [1..maxpolys,1..4,1..3] of integer = - ( - ((-10,-10,0),(10,-10,0),(10,-7,0),(-10,-7,0)), - ((-10,10,0),(10,10,0),(10,7,0),(-10,7,0)), - ((-2,-9,0),(2,-9,0),(2,9,0),(-2,9,0)), - ((0,0,0),(0,0,0),(0,0,0),(0,0,0)), - ((0,0,0),(0,0,0),(0,0,0),(0,0,0)) - ); { The 3-D coordinates of our object ... stored as (X1,Y1,Z1), } - { (X2,Y2,Z2) ... for the 4 points of a poly } - - -Type Point = Record - x,y,z:real; { The data on every point we rotate} - END; - Virtual = Array [1..64000] of byte; { The size of our Virtual Screen } - VirtPtr = ^Virtual; { Pointer to the virtual screen } - - -VAR Lines : Array [1..maxpolys,1..4] of Point; { The base object rotated } - Translated : Array [1..maxpolys,1..4] of Point; { The rotated object } - Xoff,Yoff,Zoff:Integer; { Used for movement of the object } - lookup : Array [0..360,1..2] of real; { Our sin and cos lookup table } - Virscr : VirtPtr; { Our first Virtual screen } - Vaddr : word; { The segment of our virtual screen} - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure SetMCGA; { This procedure gets you into 320x200x256 mode. } -BEGIN - asm - mov ax,0013h - int 10h - end; -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure SetText; { This procedure returns you to text mode. } -BEGIN - asm - mov ax,0003h - int 10h - end; -END; - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure Cls (Where:word;Col : Byte); - { This clears the screen to the specified color } -BEGIN - asm - push es - mov cx, 32000; - mov es,[where] - xor di,di - mov al,[col] - mov ah,al - rep stosw - pop es - End; -END; - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure SetUpVirtual; - { This sets up the memory needed for the virtual screen } -BEGIN - GetMem (VirScr,64000); - vaddr := seg (virscr^); -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure ShutDown; - { This frees the memory used by the virtual screen } -BEGIN - FreeMem (VirScr,64000); -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -procedure flip(source,dest:Word); - { This copies the entire screen at "source" to destination } -begin - asm - push ds - mov ax, [Dest] - mov es, ax - mov ax, [Source] - mov ds, ax - xor si, si - xor di, di - mov cx, 32000 - rep movsw - pop ds - end; -end; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure Pal(Col,R,G,B : Byte); - { This sets the Red, Green and Blue values of a certain color } -Begin - asm - mov dx,3c8h - mov al,[col] - out dx,al - inc dx - mov al,[r] - out dx,al - mov al,[g] - out dx,al - mov al,[b] - out dx,al - end; -End; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure Hline (x1,x2,y:word;col:byte;where:word); assembler; - { This draws a horizontal line from x1 to x2 on line y in color col } -asm - mov ax,where - mov es,ax - mov ax,y - mov di,ax - shl ax,8 - shl di,6 - add di,ax - add di,x1 - - mov al,col - mov ah,al - mov cx,x2 - sub cx,x1 - shr cx,1 - jnc @start - stosb -@Start : - rep stosw -end; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure DrawPoly(x1,y1,x2,y2,x3,y3,x4,y4:integer;color:byte;where:word); - { This draw a polygon with 4 points at x1,y1 , x2,y2 , x3,y3 , x4,y4 - in color col } -var - x:integer; - mny,mxy:integer; - mnx,mxx,yc:integer; - mul1,div1, - mul2,div2, - mul3,div3, - mul4,div4:integer; - -begin - mny:=y1; mxy:=y1; - if y2mxy then mxy:=y2; - if y3mxy then mxy:=y3; { Choose the min y mny and max y mxy } - if y4mxy then mxy:=y4; - - if mny<0 then mny:=0; - if mxy>199 then mxy:=199; - if mny>199 then exit; - if mxy<0 then exit; { Verticle range checking } - - mul1:=x1-x4; div1:=y1-y4; - mul2:=x2-x1; div2:=y2-y1; - mul3:=x3-x2; div3:=y3-y2; - mul4:=x4-x3; div4:=y4-y3; { Constansts needed for intersection calc } - - for yc:=mny to mxy do - begin - mnx:=320; - mxx:=-1; - if (y4>=yc) or (y1>=yc) then - if (y4<=yc) or (y1<=yc) then { Check that yc is between y1 and y4 } - if not(y4=y1) then - begin - x:=(yc-y4)*mul1 div div1+x4; { Point of intersection on x axis } - if xmxx then - mxx:=x; { Set point as start or end of horiz line } - end; - if (y1>=yc) or (y2>=yc) then - if (y1<=yc) or (y2<=yc) then { Check that yc is between y1 and y2 } - if not(y1=y2) then - begin - x:=(yc-y1)*mul2 div div2+x1; { Point of intersection on x axis } - if xmxx then - mxx:=x; { Set point as start or end of horiz line } - end; - if (y2>=yc) or (y3>=yc) then - if (y2<=yc) or (y3<=yc) then { Check that yc is between y2 and y3 } - if not(y2=y3) then - begin - x:=(yc-y2)*mul3 div div3+x2; { Point of intersection on x axis } - if xmxx then - mxx:=x; { Set point as start or end of horiz line } - end; - if (y3>=yc) or (y4>=yc) then - if (y3<=yc) or (y4<=yc) then { Check that yc is between y3 and y4 } - if not(y3=y4) then - begin - x:=(yc-y3)*mul4 div div4+x3; { Point of intersection on x axis } - if xmxx then - mxx:=x; { Set point as start or end of horiz line } - end; - if mnx<0 then - mnx:=0; - if mxx>319 then - mxx:=319; { Range checking on horizontal line } - if mnx<=mxx then - hline (mnx,mxx,yc,color,where); { Draw the horizontal line } - end; - end; - - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Function rad (theta : real) : real; - { This calculates the degrees of an angle } -BEGIN - rad := theta * pi / 180 -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure SetUpPoints; - { This creates the lookup table } -VAR loop1,loop2:integer; -BEGIN - For loop1:=0 to 360 do BEGIN - lookup [loop1,1]:=sin (rad (loop1)); - lookup [loop1,2]:=cos (rad (loop1)); - END; -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure Putpixel (X,Y : Integer; Col : Byte; where:word); - { This puts a pixel on the screen by writing directly to memory. } -BEGIN - Asm - mov ax,[where] - mov es,ax - mov bx,[X] - mov dx,[Y] - mov di,bx - mov bx, dx {; bx = dx} - shl dx, 8 - shl bx, 6 - add dx, bx {; dx = dx + bx (ie y*320)} - add di, dx {; finalise location} - mov al, [Col] - stosb - End; -END; - - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure RotatePoints (X,Y,Z:Integer); - { This rotates object lines by X,Y and Z; then places the result in - TRANSLATED } -VAR loop1,loop2:integer; - temp:point; -BEGIN - For loop1:=1 to maxpolys do BEGIN - For loop2:=1 to 4 do BEGIN - temp.x:=lines[loop1,loop2].x; - temp.y:=lookup[x,2]*lines[loop1,loop2].y - lookup[x,1]*lines[loop1,loop2].z; - temp.z:=lookup[x,1]*lines[loop1,loop2].y + lookup[x,2]*lines[loop1,loop2].z; - - translated[loop1,loop2]:=temp; - - If y>0 then BEGIN - temp.x:=lookup[y,2]*translated[loop1,loop2].x - lookup[y,1]*translated[loop1,loop2].y; - temp.y:=lookup[y,1]*translated[loop1,loop2].x + lookup[y,2]*translated[loop1,loop2].y; - temp.z:=translated[loop1,loop2].z; - translated[loop1,loop2]:=temp; - END; - - If z>0 then BEGIN - temp.x:=lookup[z,2]*translated[loop1,loop2].x + lookup[z,1]*translated[loop1,loop2].z; - temp.y:=translated[loop1,loop2].y; - temp.z:=-lookup[z,1]*translated[loop1,loop2].x + lookup[z,2]*translated[loop1,loop2].z; - translated[loop1,loop2]:=temp; - END; - END; - END; -END; - - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure DrawPoints; - { This draws the translated object to the virtual screen } -VAR loop1:Integer; - nx,ny,nx2,ny2,nx3,ny3,nx4,ny4:integer; - temp:integer; -BEGIN - For loop1:=1 to maxpolys do BEGIN - If (translated[loop1,1].z+zoff<0) and (translated[loop1,2].z+zoff<0) and - (translated[loop1,3].z+zoff<0) and (translated[loop1,4].z+zoff<0) then BEGIN - temp:=round (translated[loop1,1].z+zoff); - nx :=round (256*translated[loop1,1].X) div temp+xoff; - ny :=round (256*translated[loop1,1].Y) div temp+yoff; - temp:=round (translated[loop1,2].z+zoff); - nx2:=round (256*translated[loop1,2].X) div temp+xoff; - ny2:=round (256*translated[loop1,2].Y) div temp+yoff; - temp:=round (translated[loop1,3].z+zoff); - nx3:=round (256*translated[loop1,3].X) div temp+xoff; - ny3:=round (256*translated[loop1,3].Y) div temp+yoff; - temp:=round (translated[loop1,4].z+zoff); - nx4:=round (256*translated[loop1,4].X) div temp+xoff; - ny4:=round (256*translated[loop1,4].Y) div temp+yoff; - drawpoly (nx,ny,nx2,ny2,nx3,ny3,nx4,ny4,13,vaddr); - END; - END; -END; - - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure MoveAround; - { This is the main display procedure. Firstly it brings the object towards - the viewer by increasing the Zoff, then passes control to the user } -VAR deg,loop1,loop2:integer; - ch:char; - - Procedure Whizz (sub:boolean); - VAR loop1:integer; - BEGIN - For loop1:=-64 to -5 do BEGIN - zoff:=loop1*8; - if sub then xoff:=xoff-7 else xoff:=xoff+7; - RotatePoints (deg,deg,deg); - DrawPoints; - flip (vaddr,vga); - Cls (vaddr,0); - deg:=(deg+5) mod 360; - END; - END; - -BEGIN - deg:=0; - ch:=#0; - Yoff:=100; - Xoff:=350; - Cls (vaddr,0); - For loop1:=1 to maxpolys do - For loop2:=1 to 4 do BEGIN - Lines [loop1,loop2].x:=a [loop1,loop2,1]; - Lines [loop1,loop2].y:=a [loop1,loop2,2]; - Lines [loop1,loop2].z:=a [loop1,loop2,3]; - END; - Whizz (TRUE); - - For loop1:=1 to maxpolys do - For loop2:=1 to 4 do BEGIN - Lines [loop1,loop2].x:=s [loop1,loop2,1]; - Lines [loop1,loop2].y:=s [loop1,loop2,2]; - Lines [loop1,loop2].z:=s [loop1,loop2,3]; - END; - Whizz (FALSE); - - For loop1:=1 to maxpolys do - For loop2:=1 to 4 do BEGIN - Lines [loop1,loop2].x:=p [loop1,loop2,1]; - Lines [loop1,loop2].y:=p [loop1,loop2,2]; - Lines [loop1,loop2].z:=p [loop1,loop2,3]; - END; - Whizz (TRUE); - - For loop1:=1 to maxpolys do - For loop2:=1 to 4 do BEGIN - Lines [loop1,loop2].x:=h [loop1,loop2,1]; - Lines [loop1,loop2].y:=h [loop1,loop2,2]; - Lines [loop1,loop2].z:=h [loop1,loop2,3]; - END; - Whizz (FALSE); - - For loop1:=1 to maxpolys do - For loop2:=1 to 4 do BEGIN - Lines [loop1,loop2].x:=y [loop1,loop2,1]; - Lines [loop1,loop2].y:=y [loop1,loop2,2]; - Lines [loop1,loop2].z:=y [loop1,loop2,3]; - END; - Whizz (TRUE); - - For loop1:=1 to maxpolys do - For loop2:=1 to 4 do BEGIN - Lines [loop1,loop2].x:=x [loop1,loop2,1]; - Lines [loop1,loop2].y:=x [loop1,loop2,2]; - Lines [loop1,loop2].z:=x [loop1,loop2,3]; - END; - Whizz (FALSE); - - For loop1:=1 to maxpolys do - For loop2:=1 to 4 do BEGIN - Lines [loop1,loop2].x:=i [loop1,loop2,1]; - Lines [loop1,loop2].y:=i [loop1,loop2,2]; - Lines [loop1,loop2].z:=i [loop1,loop2,3]; - END; - Whizz (TRUE); - - For loop1:=1 to maxpolys do - For loop2:=1 to 4 do BEGIN - Lines [loop1,loop2].x:=a [loop1,loop2,1]; - Lines [loop1,loop2].y:=a [loop1,loop2,2]; - Lines [loop1,loop2].z:=a [loop1,loop2,3]; - END; - Whizz (FALSE); - - cls (vaddr,0); - cls (vga,0); - Xoff := 160; - - Repeat - if keypressed then BEGIN - ch:=upcase (Readkey); - Case ch of 'A' : zoff:=zoff+5; - 'Z' : zoff:=zoff-5; - ',' : xoff:=xoff-5; - '.' : xoff:=xoff+5; - 'S' : yoff:=yoff-5; - 'X' : yoff:=yoff+5; - END; - END; - DrawPoints; - flip (vaddr,vga); - cls (vaddr,0); - RotatePoints (deg,deg,deg); - deg:=(deg+5) mod 360; - Until ch=#27; -END; - - -BEGIN - SetUpVirtual; - clrscr; - Writeln ('Hello there! Varsity has begun once again, so it is once again'); - Writeln ('back to the grindstone ;-) ... anyway, this tutorial is, by'); - Writeln ('popular demand, on poly-filling, in relation to 3-D solids.'); - Writeln; - Writeln ('In this program, the letters of ASPHYXIA will fly past you. As you'); - Writeln ('will see, they are solid, not wireframe. After the last letter has'); - Writeln ('flown by, a large A will be left in the middle of the screen.'); - Writeln; - Writeln ('You will be able to move it around the screen, and you will notice'); - Writeln ('that it may have bits only half on the screen, i.e. clipping is'); - Writeln ('perfomed. To control it use the following : "A" and "Z" control the Z'); - Writeln ('movement, "," and "." control the X movement, and "S" and "X"'); - Writeln ('control the Y movement. I have not included rotation control, but'); - Writeln ('it should be easy enough to put in yourself ... if you have any'); - Writeln ('hassles, leave me mail.'); - Writeln; - Writeln ('I hope this is what you wanted...leave me mail for new ideas.'); - writeln; - writeln; - Write (' Hit any key to contine ...'); - Readkey; - SetMCGA; - SetUpPoints; - MoveAround; - SetText; - ShutDown; - Writeln ('All done. This concludes the ninth sample program in the ASPHYXIA'); - Writeln ('Training series. You may reach DENTHOR under the names of GRANT'); - Writeln ('SMITH/DENTHOR/ASPHYXIA on the ASPHYXIA BBS. I am also an avid'); - Writeln ('Connectix BBS user, and occasionally read RSAProg.'); - Writeln ('The numbers are available in the main text. You may also write to me at:'); - Writeln (' Grant Smith'); - Writeln (' P.O. Box 270'); - Writeln (' Kloof'); - Writeln (' 3640'); - Writeln ('I hope to hear from you soon!'); - Writeln; Writeln; - Write ('Hit any key to exit ...'); - Readkey; -END. - diff --git a/16/PCGPE10/UT.TXT b/16/PCGPE10/UT.TXT deleted file mode 100644 index 7d5e77c0..00000000 --- a/16/PCGPE10/UT.TXT +++ /dev/null @@ -1,195 +0,0 @@ - -UltraTracker 1.5 ----------------- - - - Mysterious's ULTRA TRACKER File Format - by FreeJack of The Elven Nation - (some additional infos on the new format (V1.4/5) by MAS -> * marked) - -I've done my best to document the file format of Ultra Tracker (UT). -If you find any errors please contact me. -The file format has stayed consistent through the first four public releases. -At the time of this writting, Ultra Tracker is up to version 1.3 -(* With version V1.4/5 there are some changes done in the format. *) - -Thanks go to : -SoJa of YLYSY for help translating stuff. - -Marc Andr‚ Schallehn -Thanks for putting out this GREAT program. -Also thanks for the info on 16bit samples. - -With all this crap out of the way lets get to the format. - - -Sample Structure : -______________________________________________________________________________ -Samplename : 32 bytes (Sample name) -DosName : 12 bytes (when you load a sample into UT, - it records the file name here) -LoopStart : dbl word (loop start point) -LoopEnd : dbl word (loop end point) -SizeStart : dbl word (see below) -SizeEnd : dbl word (see below) -volume : byte (UT uses a logarithmic volume setting, ranging from 0-255) - (* V1.4: uses linear Volume ranging from 0-255 *) -Bidi Loop : byte (see below) -FineTune : word (Fine tune setting, uses full word value) -______________________________________________________________________________ - -8 Bit Samples : - -SizeStart : -The SizeStart is the starting offset of the sample. -This seems to tell UT how to load the sample into the Gus's onboard memory. -All the files I have worked with start with a value of 32 for the first sample, -and the previous SizeEnd value for all sample after that. (See Example below) -If the previous sample was 16bit, then SizeStart = (Last SizeEnd * 2) -SizeEnd : -Like the SizeStart, SizeEnd seems to tell UT where to load the sample into the -Gus's onboard memory. SizeEnd equal SizeStart + the length of the sample. - -Example : -If a UT file had 3 samples, 1st 12000 bytes, 2nd 5600 bytes, 3rd 8000 byte. -The SizeStart and SizeEnd would look like this: - -Sample SizeStart SizeEnd -1st 32 12032 -2nd 12032 17632 -3rd 17632 25632 - -***Note*** -Samples may NOT cross 256k boundaries. If a sample is too large to fit into the -remaining space, its Sizestart will equal the start of the next 256k boundary. -UT does keep track of the free space at the top of the 256k boundaries, and -will load a sample in there if it will fit. -Example : EndSize = 252144 -If the next sample was 12000 bytes, its SizeStart would be 262144, not 252144. -Note that this leaves 10000 bytes unused. If any of the following sample could -fit between 252144 and 262144, its Sizestart would be 252144. -Say that 2 samples after the 12000 byte sample we had a sample that was only -5000 bytes long. Its SizeStart would be 252144 and its SizeEnd would be 257144. -This also applies to 16 Bit Samples. - -16 Bit Samples : -16 bit samples are handled a little different then 8 bit samples. -The SizeStart variable is calculated by dividing offset (last SizeEnd) -by 2. The SizeEnd variable equals SizeStart + (SampleLength / 2). -If the first sample is 16bit, then SizeStart = 16. -Example : - sample1 = 8bit, 1000 bytes - sample2 = 16bit, 5000 bytes - - sample1 SizeStart = 32 - SizeEnd = 1032 (32 + 1000) - - sample2 SizeStart = 516 (offset (1032) / 2) - SizeEnd = 3016 (516 + (5000/2)) - -***Note*** -If a 16bit sample is loaded into banks 2,3, or 4 -the SizeStart variable will be -(offset / 2) + 262144 (bank 2) -(offset / 2) + 524288 (bank 3) -(offset / 2) + 786432 (bank 4) -The SizeEnd variable will be -SizeStart + (SampleLength / 2) + 262144 (bank 2) -SizeStart + (SampleLength / 2) + 524288 (bank 3) -SizeStart + (SampleLength / 2) + 786432 (bank 4) - -BiDi Loop : (Bidirectional Loop) -UT takes advantage of the Gus's ability to loop a sample in several different -ways. By setting the Bidi Loop, the sample can be played forward or backwards, -looped or not looped. The Bidi variable also tracks the sample -resolution (8 or 16 bit). - -The following table shows the possible values of the Bidi Loop. -Bidi = 0 : No looping, forward playback, 8bit sample -Bidi = 4 : No Looping, forward playback, 16bit sample -Bidi = 8 : Loop Sample, forward playback, 8bit sample -Bidi = 12 : Loop Sample, forward playback, 16bit sample -Bidi = 24 : Loop Sample, reverse playback 8bit sample -Bidi = 28 : Loop Sample, reverse playback, 16bit sample -______________________________________________________________________________ -Event Structure: -______________________________________________________________________________ -Note : byte (See note table below) -SampleNumber : byte (Sample Number) -Effect1 : nib (Effect1) -Effect2 : nib (Effect2) -EffectVar : word (Effect variables) - -The High order byte of EffectVar is the Effect variable for Effect1. -The Low order byte of EffectVar is the Effect variable for Effect2. -***(Note)*** -UT uses a form of compression on repetitive events. Say we read in the first -byte, if it = $FC then this signifies a repeat block. The next byte is the -repeat count. followed by the event structure to repeat. -If the first byte read does NOT = $FC then this is the note of the event. -So repeat blocks will be 7 bytes long : RepFlag : byte ($FC) - RepCount : byte - note : byte - samplenumber : byte - effect1 : nib - effect2 : nib - effectVar : word - -Repeat blocks do NOT bridge patterns. -______________________________________________________________________________ -Note Table: -______________________________________________________________________________ -note value of 0 = pause -C-0 to B-0 1 to 12 -C-1 to B-1 13 to 24 -C-2 to B-2 26 to 36 -C-3 to B-3 39 to 48 -C-4 to B-4 52 to 60 -______________________________________________________________________________ -Offset Bytes Type Description -______________________________________________________________________________ -0 15 byte ID block : should contain - 'MAS_UTrack_V001' - - (* V1.4: 'MAS_UTrack_V002') - - (* V1.5: 'MAS_UTrack_V003') - -15 32 AsciiZ Song Title -47 1 reserved This byte is reserved and - always contain 0; - - (* V1.4: jump-value: reserved * 32; - space between is used for song - text; - [reserved * 32] = RES ! ) - -48+RES 1 byte Number of Samples (NOS) -49+RES NOS * 64 SampleStruct Sample Struct (see Sample Structure) - -Patt_Seq = 48 + (NOS * 64) + RES - -Patt_Seq 256 byte Pattern Sequence -Patt_Seq+256 1 byte Number Of Channels (NOC) Base 0 -Patt_Seq+257 1 byte Number Of patterns (NOP) Base 0 - - (* V1.5: PAN-Position Table - Length: NOC * 1byte - [0 left] - [0F right] ) - -NOC+Patt_Seq+258 varies EventStruct Pattern Data (See Event -Structure) - -______________________________________________________________________________ -The remainder of the file is the raw sample data. (signed) -______________________________________________________________________________ - -That should about cover it. If you have any questions, feel free to e-mail -me at freejack@shell.portal.com - -I can also be contacted on The UltraSound Connection (813) 787-8644 -The UltraSound Connection is a BBS dedicated to the Gravis Ultrasound Card. - -Also I'm the author of Ripper and Gvoc. If anyone has any questions or -problems, please contact me. diff --git a/16/PCGPE10/VESASP12.TXT b/16/PCGPE10/VESASP12.TXT deleted file mode 100644 index 3949748e..00000000 --- a/16/PCGPE10/VESASP12.TXT +++ /dev/null @@ -1,1134 +0,0 @@ -VESA Super VGA Standard -Video Electronics Standards Association -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -2150 North First Street, Suite 360 Phone: (408) 435-0333 -San Jose, CA 95131-2020 Fax: (408) 435-8225 - - Super VGA BIOS Extension - Standard #VS911022 - October 22, 1991 - Document Version 1.0 - VBE Version 1.2 - -PURPOSE -~~~~~~~ -To standardize a common software interface to Super VGA video adapters in order -to provide simplified software application access to advanced VGA products. - -SUMMARY -~~~~~~~ -The standard provides a set of functions which an application program can use -to A) obtain information about the capabilities and characteristics of a -specific Super VGA implementation and B) to control the operation of such -hardware in terms of video mode initialization and video memory access. The -functions are provided as an extension to the VGA BIOS video services, accessed -through interrupt 10h. - - VESA Super VGA Standard VS911022-2 - -Contents -~~~~~~~~ -1. Introduction ................................................. Page 3 - -2. Goals and Objectives ......................................... 4 - 2.1 Video environment information ........................ 4 - 2.2 Programming support .................................. 4 - 2.3 Compatibility ........................................ 5 - 2.4 Scope of standard .................................... 5 - -3. Standard VGA BIOS ............................................ 6 - -4. Super VGA Mode Numbers ....................................... 7 - -5. CPU Video Memory Control ..................................... 9 - 5.1 Hardware design consideration ........................ 9 - 5.1.1 Limited to 64k/128k of CPU address space ..... 9 - 5.1.2 Crossing CPU video memory window boundaries .. 10 - 5.1.3 Operating on data frolm different areas ...... 10 - 5.1.4 Combining data from two different windows .... 10 - 5.2 Different types of hardware windows .................. 11 - 5.2.1 Single window systems ........................ 11 - 5.2.2 Dual window systems .......................... 11 - -6. Extended VGA BIOS ............................................ 12 - 6.1 Status Information ................................... 12 - 6.2 00h - Return Super VGA Information ................... 12 - 6.3 01h - Return Super VGA mode information .............. 14 - 6.4 02h - Set Super VGA mode ............................. 20 - 6.5 03h - Return Super VGA mode .......................... 20 - 6.6 04h - Save/restore Super VGA video state ............. 21 - 6.7 05h - Super VGGA video memory window control ......... 22 - 6.8 06h - Set/Get Logical Scan Line Length ............... 23 - 6.9 07h - Set/Get Display Start .......................... 24 - 6.10 08h - Set/Get DAC Palette Control .................... 25 - -7. Application Example .......................................... 26 - - VESA Super VGA Standard VS911022-3 - -1. Introduction -~~~~~~~~~~~~~~~~~~~~ -This document contains a specification for a standardized interface to extended -VGA video modes and functions. The specification consists of mechanisms for -supporting standard extended video modes and functions that have been approved -by the main VESA committee and non-standard video modes that an individual VGA -supplier may choose to add, in a uniform manner that application software can -utilize without having to understand the intricate details of the particular VGA -hardware. - -The primary topics of this specification are definitions of extended VGA video -modes and the functions necessary for application software to understand the -characteristics of the video mode and manipulate the extended memory associated -with the video mode. - -Readers of this document should already be familiar with programming VGAs at the -hardware level and Intel iAPX real mode assembly language. Readers who are -unfamiliar with programming the VGA should first read one of the many VGA -programming tutorials before attempting to understand these extensions to the -standard VGA. - - VESA Super VGA Standard VS911022-4 - -2. Goals and Objectives -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The IBM VGA has become a defacto standard in the PC graphics world. A multitude -of different VGA offerings exist in the marketplace, each one providing BIOS or -register compatibility with the IBM VGA. More and more of these VGA compatible -products implements various supersets of the VGA standard. These extensions -range from higher resolutions and more colors to improved performance and even -some graphics processing capabilities. Intense competition has dramatically -improved the price/performance ratio, to the benefit of the end user. - -However, several serious problems face a software developer who intends to take -advantage of these "Super VGA" environments. Because there is no standard -hardware implementation, the developer is faced with widely disparate Super VGA -hardware architectures. Lacking a common software interface, designing -applications for these environments is costly and technically difficult. Except -for applications supported by OEM-specific display drivers, very few software -packages can take advantage of the power and capabilities of Super VGA products. - -The purpose of the VESA VGA BIOS Extension is to remedy this situation. Being a -common software interface to Super VGA graphics products, the primary objective -is to enable application and system software to adapt to and exploit the wide -range of features available in these VGA extensions. - -Specifically, the VESA BIOS Extension attempts to address the following issues: -A) Return information about the video environment to the application, and B) -Assist the application in initializing and programming the hardware. - -2.1 Video environment information - -Today, an application has no standard mechanism to determine what Super VGA -hardware it is running on. Only by knowing OEM-specific features can an -application determine the presence of a particular video board. This often -involves reading and testing registers located at I/O addresses unique to each -OEM. By not knowing what hardware an application is running on, few, if any, of -the extended features of the underlying hardware can be used. - -The VESA BIOS Extension provides several functions to return information about -the video environment. These functions return system level information as well -as video mode specific details. Function 00h returns general system level -information, including an OEM identification string. The function also returns -a pointer to the supported video modes. Function 01h may be used by the -application to obtain information about each supported video mode. Function 03h -returns the current video mode. - - VESA Super VGA Standard VS911022-5 - -2.2 Programming support - -Due to the fact that different Super VGA products have different hardware -implementations, application software has great difficulty in adapting to each -environment. However, since each is based on the VGA hardware architecture, -differences are most common in video mode initialization and memory mapping. -The rest of the architecture is usually kept intact, including I/O mapped -registers, video buffer location in the CPU address space, DAC location and -function, etc. - -The VESA BIOS Extension provides several functions to interface to the different -Super VGA hardware implementations. The most important of these is Function -02h, Set Super VGA video mode. This function isolates the application from the -tedious and complicated task of setting up a video mode. Function 05h provides -an interface to the underlying memory mapping hardware. Function 04h enables an -application to save and restore a Super VGA state without knowing anything of -the specific implementation. - -2.3 Compatibility - -A primary design objective of the VESA BIOS Extension is to preserve maximum -compatibility to the standard VGA environment. In no way should the BIOS -extensions compromise compatibility or performance. Another but related concern -is to minimiza the changes necessary to an existing VGA BIOS. Ram, as well as -ROM-based implementations of the BIOS extension should be possible. - -2.4 Scope of standard - -The purpose of the VESA BIOS Extension is to provide support for extended VGA -environments. Thus, the underlying hardware architecture is assumed to be a -VGA. Graphics software that drives a Super VGA board will perform its graphics -output in generally the same way it drives a standard VGA, i.e. writing directly -to a VGA style frame buffer, manipulating graphics controller registers, -directly programming the palette, etc. No significant graphics processing will -be done in hardware. For this reason, the VESA BIOS Extension does not provide -any graphics output functions, such as BitBlt, line or circle drawing, etc. - -An important constraint of the functionalities that can be placed into the VESA -BIOS Extension is that ROM space is severely limited in certain existing BIOS -implementations. - -Outside the scope of this VESA BIOS Extension is the handling of different -monitors and monitor timings. Such items are dealt with in other VESA fora. -The purpose of the VESA BIOS Extension is to provide a standardized software -interface to Super VGA graphics modes, independent of monitor and monitor timing -issues. - - VESA Super VGA Standard VS911022-6 - -3. Standard VGA BIOS -~~~~~~~~~~~~~~~~~~~~~~~~~ -A primary design goal with the VESA BIOS Extension is to minimize the effects on -the standard VGA BIOS. Standard VGA BIOS functions should need to be modified -as little as possible. This is important since ROM, as well as RAM based -versions of the extensions, may be implemented. - -However, two standard VGA BIOS functions are affected by the VESA extension. -These are Function 00h (Set video mode) and Function 0Fh (Read current video -state). VESA-aware applications will not set the video mode using VGA BIOS -function 00h. Nor will such applications use VGA BIOS function 0Fh. VESA BIOS -functions 02h (Set Super VGA mode) and 03h (Get Super VGA mode) will be used -instead. - -However, VESA-unaware applications (such as old Pop-Up programs and other TSRs, -or the CLS command of MS-DOS), might use VGA BIOS function 0Fh to get the -present video mode. Later it may call VGA BIOS function 00h to -restore/reinitialize the old video mode. - -To make such applications work, VESA recommends that whatever value returned by -VGA BIOS function 0Fh (it is up to the OEM to define this number) should be used -to reinitialize the video mode through VGA BIOS function 00h. Thus, the BIOS -should keep track of the last Super VGA mode in effect. - -It is recommended, but not mandatory, to support output functions (such as -TTY-output, scroll, set pixel, etc.) in Super VGA modes. If the BIOS extension -doesn't support such output functions, bit D2 (Output functions supported) of -the ModeAttributes field (returned by VESA BIOS function 01h) should be clear. - - VESA Super VGA Standard VS911022-7 - -4. Super VGA mode numbers -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Standard VGA mode numbers are 7 bits wide and presently range from 00h to 13h. -OEMs have defined extended video modes in the range 14h to 7Fh. Values in the -range 80h to FFh cannot be used, since VGA BIOS function 00h (Set video mode) -interprets bit 7 as a flag to clear/not clear video memory. - -Due to the limitations of 7 bit mode numbers, VESA video mode numbers are 15 -bits wide. To initialize a Super VGA mode, its number is passed in the BX -register to VESA BIOS function 02h (Set Super VGA mode). - -The format of VESA mode numbers is as follows: - -D0-D8 = Mode number - If D8 == 0, this is not a VESA defined mode - If D8 == 1, this is a VESA defined mode -D9-D14 = Reserved by VESA for future expansion (= 0) -D15 = Reserved (= 0) - -Thus, VESA mode numbers begin at 100h. This mode numbering scheme implements -standard VGA mode numbers as well as OEM-defined mode numbers as subsets of the -VESA mode number. That means that regular VGA modes may be initialized through -VESA BIOS function 02h (Set Super VGA mode), simply by placing the mode number -in BL and clearing the upper byte (BH). OEM-defined modes may be initialized in -the same way. - -To date, VESA has defined a 7-bit video mode number, 6Ah, for the 800x600, -16-color, 4-plane graphics mode. The corresponding 15-bit mode number for this -mode is 102h. - -The following VESA mode numbers have been defined: - - GRAPHICS TEXT - -15-bit 7-bit Resolution Colors 15-bit 7-bit Columns Rows -mode mode mode mode -number number number number -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -100h - 640x400 256 108h - 80 60 -101h - 640x480 256 - 109h - 132 25 -102h 6Ah 800x600 16 10Ah - 132 43 -103h - 800x600 256 10Bh - 132 50 - 10Ch - 132 60 -104h - 1024x768 16 -105h - 1024x768 256 - -106h - 1280x1024 16 -107h - 1280x1024 256 - - VESA Super VGA Standard VS911022-8 - -10Dh - 320x200 32K (1:5:5:5) -10Eh - 320x200 64K (5:6:5) -10Fh - 320x200 16.8M (8:8:8) -110h - 640x480 32K (1:5:5:5) -111h - 640x480 64K (5:6:5) -112h - 640x480 16.8M (8:8:8) -113h - 800x600 32K (1:5:5:5) -114h - 800x600 64K (5:6:5) -115h - 800x600 16.8M (8:8:8) -116h - 1024x768 32K (1:5:5:5) -117h - 1024x768 64K (5:6:5) -118h - 1024x768 16.8M (8:8:8) -119h - 1280x1024 32K (1:5:5:5) -11Ah - 1280x1024 64K (5:6:5) -11Bh - 1280x1024 16.8M (8:8:8) - - VESA Super VGA Standard VS911022-9 - -5. CPU Video Memory Windows -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -A standard VGA sub-system provides 256k bytes of memory and a corresponding -mechanism to address this memory. Super VGAs and their modes require more than -the standard 256k bytes of memory but also require that the address space for -this memory be restricted to the standard address space for compatibility -reasons. CPU video memory windows provide a means of accessing this extended -VGA memory within the standard CPU address space. - -This chapter describes how several hardware implementations of CPU video memory -windows operate, their impact on application software design, and relates them -to the software model presented by the VESA VGA BIOS extensions. - -The VESA CPU video memory windows functions have been designed to put the -performance insensitive, non-standard hardware functions into the BIOS while -putting the performance sensitive, standard hardware functions into the -application. This provides portability among VGA systems together with the -performance that comes from accessing the hardware directly. In particular, the -VESA BIOS is responsible for mapping video memory into the CPU address space -while the application is responsible for performing the actual memory read and -write operations. - -This combination software and hardware interface is accomplished by informing -the application of the parameters that control the hardware mechanism of mapping -the video memory into the CPU address space and then letting the application -control the mapping within those parameters. - -5.1 Hardware -5.1.1 Limited to 64k/128k of CPU address space - -The first consideration in implementing extended video memory is to give access -to the memory to application software. - -The standard VGA CPU address space for 16 color graphics modes is typically at -segment A000h for 64k. This gives access to the 256k bytes of a standard VGA, -i.e. 64k per plane. Access to the extended video memory is accomplished by -mapping portions of the video memory into the standard VGA CPU address space. - -Every Super VGA hardware implementation provides a mechanism for software to -specify the offset from the start of video memory which is to be mapped to the -start of the CPU address space. Providing both read and write access to the -mapped memory provides a necessary level of hardware support for an application -to manipulate the extended video memory. - - VESA Super VGA Standard VS911022-10 - -5.1.2 Crossing CPU video memory window boundaries - -The organization of most software algorithms which perform video operations -consists of a pair of nested loops: and outer loop over rows or scan lines and -an inner loop across the row or scan line. The latter is the proverbial inner -loop, which is the bottle neck to high performance software. - -If a target rectangle is large enough, or poorly located, part of the required -memory may be with within the video memory mapped into the CPU address space and -part of it may not be addressable by the CPU without changing the mapping. It -is desirable that the test for remapping the video memory is located outside of -the inner loop. - -This is typically accomplished by selecting the mapping offset of the start of -video memory to the start of the CPU address space so that at least one entire -row or scan line can be processed without changing the video memory mapping. -There are currently no Super VGAs that allow this offset to be specified on a -byte boundary and there is a wide range among Super VGAs in the ability to -position a desired video memory location at the start of the CPU address space. - -The number of bytes between the closest two bytes in video memory that can be -placed on any single CPU address is defined as the granularity of the window -function. Some Super VGA systems allow any 4k video memory boundary to be -mapped to the start of the CPY address space, while other Super VGA systems -allow any 64k video memory boundary to be mapped to the start of the CPU address -space. These two example systems would have granularities of 4k and 64k, -respectively. This concept is very similar to the bytes that can be accessed -with a 16 bit pointer in an Intel CPU before a segment register must be changed -(the granularity of the segment register or mapping here is 16 bytes). - -Notes -~~~~~ -If the granularity is equal to the length of the CPU address space, i.e. the -least significant address bit of the hardware mapping function is more -significant than the most significant bit of the CPU address, then the inner -loop will have to contain the test for crossing the end or beginning of the CPU -address space. This is because if the length of the CPU address space (which is -the granularity in this case) is not evenly divisible by the length of a scan -line, then the scan line at the end of the CPU address will be in two different -video memory which cannot be mapped into the CPU address space simultaneously. - -5.1.3 Operating on data from different areas - -It is sometimes required or convenient to move or combine data from two -different areas of video memory. One example of this is storing menus in the -video memory beyond the displayed memory because there is hardware support in -all VGAs for transferring 32 bits of video data with an 8 bit CPU read and -write. Two separately mappable CPU video memory windows must be used if the -distance between the source and destination is larger than the size of the CPU -video memory window. - -5.1.4 Combining data from two different windows - -The above example of moving data from one CPU video memory window to another CPU -video memory only required read access to one window and only required write -access to the other window. Sometimes it is convenient to have read access to -both windows and write access to one window. An example of this would be a -raster operation where the resulting destination is the source data logically -combined with the original destination data. - - VESA Super VGA Standard VS911022-11 - -5.2 Different types of hardware windows - -Different hardware implementations of CPU video memory windows can be supported -by the VESA BIOS extension. The information necessary for an application to -understand the type of hardware implementation is provided by the BIOS to the -application. There are three basic types of hardware windowing implementations -and they are described below. - -The types of windowing schemes described below do not include differences in -granularity. - -Also note that is possible for a VGA to use a CPU address space of 128k starting -at segment A000h. - -5.2.1 Single window systems - -Some hardware implementations only provide a single window. This single window -will be readable as well as writeable. However, this causes a significant -performance degradation when moving data in video memory a distance that is -larger than the CPU address space. - -5.2.2 Dual window systems - -Many Super VGAs provide two windows to facilitate moving data within video -memory. There are two separate methods of providing two windows. - -5.2.2.1 Overlapping windows - -Some hardware implementations distinguish window A and window B by determining -if the CPU is attempting to do a memory read or a memory write operation. When -the two windows are distinguished by whether the CPU is trying to read or write -they can, and usually do, share the same CPU address space. However, one window -will be read only and the other will be write only. - -5.2.2.2 Non-overlapping windows - -Another mechanism used by two window systems to distinguish window A and window -B is by looking at the CPU address within the total VGA CPU address space. When -the two windows are distinguished by the CPU address within the VGA CPU address -space the windows cannot share the same address space, but they can each be both -read and written. - - VESA Super VGA Standard VS911022-12 - -6. Extended VGA BIOS -~~~~~~~~~~~~~~~~~~~~~~~~~ -Several new BIOS calls have been defined to support Super VGA modes. For -maximum compatibility with the standard VGA BIOS, these calls are grouped under -one function number. This number is passed in the AH register to the INT 10h -handler. - -The designated Super VGA extended function number is 4Fh. This function number -is presently unused in most, if not all, VGA BIOS implementations. A standard -VGA BIOS performs no action when function call 4Fh is made. Super VGA Standard -VS900602 defines subfunctions 00h through 07h. Subfunction numbers 08h through -0FFh are reserved for future use. - -6.1 Status Information - -Every function returns status information in the AX register. The format of the -status word is as follows: - - AL == 4Fh: Function is supported - Al != 4Fh: Function is not supported - AH == 00h: Function call successful - AH == 01h: Function call failed - -Software should treat a non-zero value in the AH register as a general failure -condition. In later versions of the VESA BIOS Extension new error codes might -be defined. - -6.2 Function 00h - Return Super VGA Information - -The purpose of this function is to provide information to the calling program -about the general capabilities of the Super VGA environment. The function fills -an information block structure at the address specified by the caller. The -information block size is 256 bytes. - - Input: AH = 4Fh Super VGA support - AL = 00h Return Super VGA information - ES:DI = Pointer to buffer - - Output: AX = Status - (All other registers are preserved) - - VESA Super VGA Standard VS911022-13 - -The information block has the following structure: - -VgaInfoBlock STRUC - VESASignature db 'VESA' ; 4 signature bytes - VESAVersion dw ? ; VESA version number - OEMStringPtr dd ? ; Pointer to OEM string - Capabilities db 4 dup(?) ; capabilities of the video environment - VideoModePtr dd ? ; pointer to supported Super VGA modes - TotalMemory dw ? ; Number of 64kb memory blocks on board - Reserved db 236 dup(?) ; Remainder of VgaInfoBlock -VgaInfoBlock ENDS - -The VESASignature field contains the characters 'VESA' if this is a valid block. - -The VESAVersion is a binary field which specifies what level of the VESA -standard the Super VGA BIOS conforms to. The higher byte specifies the major -version number. The lower byte specifies the minor version number. The current -VESA version number is 1.2. Applications written to use the features of a -specific version of the VESA BIOS Extension, are guaranteed to work in later -versions. The VESA BIOS Extension will be fully upwards compatible. - -The OEMStringPtr is a far pointer to a null terminated OEM-defined string. The -string may used to identify the video chip, video board, memory configuration, -etc. to hardware specific display drivers. There are no restrictions on the -format of the string. - -The Capabilities field describes what general features are supported in the -video environment. The bits are defined as follows: - - D0 = DAC is switchable - 0 = DAC is fixed width, with 6-bits per primary color - 1 = DAC width is switchable - D1-31 = Reserved - -The VideoModePtr points to a list of supported Super VGA (VESA-defined as well -as OEM-specific) mode numbers. Each mode number occupies one word (16 bits). -The list of mode numbers is terminated by a -1 (0FFFFh). Please refer to -chapter 2 for a description of VESA mode numbers. The pointer could point into -either ROM or RAM, depending on the specific implementation. Either the list -would be a static string stored in ROM, or the list would be generated at -run-time in the information block (see above) in RAM. It is the application's -responsibility to verify the current availability of any mode returned by this -Function through the Return Super VGA mode information (Function 1) call. Some -of the returned modes may not be available due to the video board's current -memory and monitor configuration. - -The TotalMemory field indicates the amount of memory installed on the VGA -board. Its value represents the number of 64kb blocks of memory currently -installed. - - VESA Super VGA Standard VS911022-14 - -6.3 Function 01h - Return Super VGA mode information - -This function returns information about a specific Super VGA video mode that was -returned by Function 0. The function fills a mode information block structure -at the address specified by the caller. The mode information block size is -maximum 256 bytes. - -Some information provided by this function is implicitly defined by the VESA -mode number. However, some Super VGA implementations might support other video -modes than those defined by VESA. To provide access to these modes, this -function also returns various other information about the mode. - - Input: AH = 4Fh Super VGA support - AL = 01h Return Super VGA mode information - CX = Super VGA video mode - (mode number must be one of those returned by Function 0) - ES:DI = Pointer to 256 byte buffer - - Output: AX = Status - (All other registers are preserved) - -The mode information block has the following structure: - -ModeInfoBlock STRUC - -; mandatory information - - ModeAttributes dw ? ; mode attributes - WinAAttributes db ? ; window A attributes - WinBAttributes db ? ; window B attributes - WinGranularity dw ? ; window granularity - WinSize dw ? ; window size - WinASegment dw ? ; window A start segment - WinBSegment dw ? ; window B start segment - WinFuncPtr dd ? ; pointer to windor function - BytesPerScanLine dw ? ; bytes per scan line - -; formerly optional information (now mandatory) - - XResolution dw ? ; horizontal resolution - YResolution dw ? ; vertical resolution - XCharSize db ? ; character cell width - YCharSize db ? ; character cell height - NumberOfPlanes db ? ; number of memory planes - BitsPerPixel db ? ; bits per pixel - NumberOfBanks db ? ; number of banks - MemoryModel db ? ; memory model type - BankSize db ? ; bank size in kb - NumberOfImagePages db ? ; number of images - Reserved db 1 ; reserved for page function - - VESA Super VGA Standard VS911022-15 - -; new Direct Color fields - - RedMaskSize db ? ; size of direct color red mask in bits - RedFieldPosition db ? ; bit position of LSB of red mask - GreenMaskSize db ? ; size of direct color green mask in bits - GreenFieldPosition db ? ; bit position of LSB of green mask - BlueMaskSize db ? ; size of direct color blue mask in bits - BlueFieldPosition db ? ; bit position of LSB of blue mask - RsvdMaskSize db ? ; size of direct color reserved mask in bits - DirectColorModeInfo db ? ; Direct Color mode attributes - Reserved db 216 dup(?) ; remainder of ModeInfoBlock -ModeInfoBlock ENDS - -The ModeAttributes field describes certain important characteristics of the -video mode. Bit D0 specifies whether this mode can be initialized in the -present video configuration. This bit can be used to block access to a video -mode if it requires a certain monitor type, and that this monitor is presently -not connected. Prior to Version 1.2 of the VESA BIOS Extension, it was not -required that the BIOS return valid information for the fields after -BytesPerScanline. Bit D1 was used to signify if the optional information was -present. Version 1.2 of the VBE requires that all fields of the ModeInfoBlock -contain valid data, except for the Direct Color fields, which are valid only if -MemoryModel field is set to a 6 (Direct Color) or 7 (YUV). Bit D1 is now -reserved, and must be set to a 1. Bit D2 indicates whether the BIOS has support -for output functions like TTY output, scroll, pixel output, etc. in this mode -(it is recommended, but not mandatory, that the BIOS have support for all output -functions). If bit D2 is 1 then the BIOS must support all of the standard -output functions. - -The field is defined as follows: - - D0 = Mode supported in hardware - 0 = Mode not supported in hardware - 1 = Mode supported in hardware - D1 = 1 (Reserved) - D2 = Output functions supported by BIOS - 0 = Output functions not supported by BIOS - 1 = Output functions supported by BIOS - D3 = Monochrome/color mode (see note below) - 0 = Monochrome mode - 1 = Color mode - D4 = Mode type - 0 = Text mode - 1 = Graphics mode - D5-D15 = Reserved - - VESA Super VGA Standard VS911022-16 - -Note: Monochrome modes have their CRTC address at 3B4h. Color modes have their -CRTC address at 3D4h. Monochrome modes have attributes in which only bit 3 -(video) and bit 4 (intensity) of the attribute controller output are -significant. Therefore, monochrome text modes have attributes of off, video, -high intensity, blink, etc. Monochrome graphics modes are two plane graphics -modes and have attributes of off, video, high intensity, and blink. Extended -two color modes that have their CRTC address at 3D4h are color modes with one -bit per pixel and one plane. The standard VGA modes 06h and 11h would be -classified as color modes, while the standard VGA modes 07h and 0Fh would be -classified as monochrome modes. - -The BytesPerScanline field specifies how many bytes each logical scanline -consists of. The logical scanline could be equal to or larger then the -displayed scanline. - - VESA Super VGA Standard VS911022-17 - -The WinAAttributes and WinBAttributes describe the characteristics of the CPU -windowing scheme such as whether the windows exist and are read/writeable, as -follows: - - D0 = Window supported - 0 = Window is not supported - 1 = Window is supported - D1 = Window readable - 0 = Window is not readable - 1 = Window is readable - D2 = Window writeable - 0 = Window is not writeable - 1 = Window is writeable - D3-D7 = Reserved - -If windowing is not supported (bit D0 = 0 for both Window A and Window B), then -an application can assume that the display memory buffer resides at the standard -CPU address appropriate for the MemoryModel of the mode. - -WinGranularity specifies the smallest boundary, in KB, on which the window can -be placed in the video memory. The value of this field is undefined if Bit D0 -of the appropriate WinAttributes field is not set. - -WinSize specifies the size of the window in KB. - -WinASegment and WinBSegment address specify the segment addresses where the -windows are located in CPU address space. - -WinFuncAddr specifies the address of the CPU video memory windowing function. -The windowing function can be invoked either through VESA BIOS function 05h, or -by calling the function directly. A direct call will provide faster access to -the hardware paging registers than using Int 10h, and is intended to be used by -high performance applications. If this field is Null, then Function 05h must be -used to set the memory window, if paging is supported. - -The XResolution and YResolution specify the width and height of the video mode. -In graphics modes, this resolution is in units of pixels. In text modes, this -resolution is in units of characters. Note that text mode resolutions, in units -of pixels, can be obtained by multiplying XResolution and YResolution by the -cell width and height, if the extended information is present. - -The XCharCellSize and YCharSellSize specify the size of the character cell in -pixels. - -The NumberOfPlanes field specifies the number of memory planes available to -software in that mode. For standard 16-color VGA graphics, this would be set to -4. For standard packed pixel modes, the field would be set to 1. - -The BitsPerPixel field specifies the total number of bits that define the color -of one pixel. For example, a standard VGA 4 Plane 16-color graphics mode would -have a 4 in this field and a packed pixel 256-color graphics mode would specify -8 in this field. The number of bits per pixel per plane can normally be derived -by dividing the BitsPerPixel field by the NumberOfPlanes field. - - VESA Super VGA Standard VS911022-18 - -The MemoryModel field specifies the general type of memory organization used in -this mode. The following models have been defined: - - 00h = Text mode - 01h = CGA graphics - 02h = Hercules graphics - 03h = 4-plane planar - 04h = Packed pixel - 05h = Non-chain 4, 256 color - 06h = Direct Color - 07h = YUV - 08h-0Fh = Reserved, to be defined by VESA - 10h-FFh = To be defined by OEM - -In Version 1.1 and earlier of the VESA Super VGA BIOS Extension, OEM defined -Direct Color video modes with pixel formats 1:5:5:5, 8:8:8, and 8:8:8:8 were -described as a Packed Pixel model with 16, 24, and 32 bits per pixel, -respectively. In Version 1.2 and later of the VESA Super VGA BIOS Extension, it -is recommended that Direct Color modes use the Direct Color MemoryModel and use -the MaskSize and FieldPosition fields of the ModeInfoBlock to describe the pixel -format. BitsPerPixel is always defined to be the total memory size of the -pixel, in bits. - -The NumberOfBanks field specifies the number of banks in which the scan lines -are grouped. The remainder from dividing the scan line number by the number of -banks is the bank that contains the scan line and the quotient is the scan line -number within the bank. For example, CGA graphics modes have two banks and -Hercules graphics mode has four banks. For modes that don't have scanline banks -(such as VGA modes 0Dh-13h), this field should be set to 1. - -The BankSize field specifies the size of a bank (group of scan lines) in units -of 1KB. For CGA and Hercules graphics modes this is 8, as each bank is 8192 -bytes in length. For modes that don't have scanline banks (such as VGA modes -0Dh-13h), this field should be set to 0. - -The NumberOfImagePages field specifies the number of additional complete display -images that will fit into the VGA's memory, at one time, in this mode. The -application may load more than one image into the VGA's memory if this field is -non-zero, and flip the display between them. - -The Reserved field has been defined to support a future VESA BIOS extension -feature and will always be set to one in this version. - -The RedMaskSize, GreenMaskSize, BlueMaskSize, and RsvdMaskSize fields define the -size, in bits, of the red, green, and blue components of a direct color pixel. -A bit mask can be constructed from the MaskSize fields using simple shift -arithmetic. For example, the MaskSize values for a Direct Color 5:6:5 mode -would be 5, 6, 5, and 0, for the red, green, blue, and reserved fields, -respectively. Note that in the YUV MemoryModel, the red field is used for V, -the green field is used for Y, and the blue field is used for U. The MaskSize -fields should be set to 0 in modes using a MemoryModel that does not have pixels -with component fields. - - VESA Super VGA Standard VS911022-19 - -The RedFieldPosition, GreenFieldPosition, BlueFieldPosition, and -RsvdFieldPosition fields define the bit position within the direct color pixel -or YUV pixel of the least significant bit of the respective color component. A -color value can be aligned with its pixel field by shifting the value left by -the FieldPosition. For example, the FieldPosition values for a Direct Color -5:6:5 mode would be 11, 5, 0, and 0, for the red, green, blue, and reserved -fields, respectively. Note that in the YUV MemoryModel, the red field is used -for V, the green field is used for Y, and the blue field is used for U. The -FieldPosition fields should be set to 0 in modes using a MemoryModel that does -not have pixels with component fields. - -The DirectColorModeInfo field describes important characteristics of direct -color modes. Bit D0 specifies whether the color ramp of the DAC is fixed or -programmable. If the color ramp is fixed, then it can not be changed. If the -color ramp is programmable, it is assumed that the red, green, and blue lookup -tables can be loaded using a standard VGA DAC color registers BIOS call -(AX=1012h). Bit D1 specifies whether the bits in the Rsvd field of the direct -color pixel can be used by the application or are reserved, and thus unusable. - - D0 = Color ramp is fixed/programmable - 0 = Color ramp is fixed - 1 = Color ramp is programmable - D1 = Bits in Rsvd field are usable/reserved - 0 = Bits in Rsvd field are reserved - 1 = Bits in Rsvd field are usable by the application - -Notes -~~~~~ -Version 1.1 and later VESA BIOS extensions will zero out all unused fields in -the Mode Information Block, always returning exactly 256 bytes. This -facilitates upward compatibility with future versions of the standard, as any -newly added fields will be designed such that values of zero will indicate -nominal defaults or non-implementation of optional features (for example, a -field containing a bit-mask of extended capabilities would reflect the absence -of all such capabilities). Applications that wish to be backwards compatible to -Version 1.0 VESA BIOS extensions should pre-initialize the 256 byte buffer -before calling Return Super VGA mode information. - - VESA Super VGA Standard VS911022-20 - -6.4 Function 02h - Set Super VGA video mode - -This function initializes a video mode. The BX register contains the mode to -set. The format of VESA mode numbers is described in chapter 2. If the mode -cannot be set, the BIOS should leave the video environment unchanged and return -a failure error code. - - Input: AH = 4Fh Super VGA support - AL = 02h Set Super VGA video mode - BX = Video mode - D0-D14 = Video mode - D15 = Clear memory flag - 0 = Clear video memory - 1 = Don't clear video memory - - Output: AX = Status - (All other registers are preserved) - -6.5 Function 03h - Return current video mode - -This function returns the current video mode in BX. The format of VESA video -mode numbers is described in chapter 2 of this document. - - Input: AH = 4Fh Super VGA support - AL = 03h Return current video mode - - Output: AX = Status - BX = Current video mode - (All other registers are preserved) - -Notes -~~~~~ -In a standard VGA BIOS, function 0Fh (Read current video state) returns the -current video mode in the AL register. In D7 of AL, it also returns the status -of the memory clear bit (D7 of 40:87). This bit is set if the mode was set -without clearing memory. In this Super VGA function, the memory clear bit will -not be returned in BX since the purpose of the function is to return the video -mode only. If an application wants to obtain the memory clear bit, it should -call VGA BIOS function 0Fh. - - VESA Super VGA Standard VS911022-21 - -6.6 Function 04h - Save/Restore Super VGA video state - -These functions provide a mechanism to save and restore the Super VGA video -state. The functions are a superset of the three subfunctions under standard -VGA BIOS function 1Ch (Save/restore video state). The complete Super VGA video -state (except video memory) should be saveable/restoreable by setting the -requested states mask (in the CX register) to 000Fh. - - Input: AH = 4Fh Super VGA support - AL = 04h Save/restore Super VGA video state - DL = 00h Return save/restore state buffer size - CX = Requested states - D0 = Save/restore video hardware state - D1 = Save/restore video BIOS data state - D2 = Save/restore video DAC state - D3 = Save/restore Super VGA state - - Output: AX = Status - BX = Number of 64-byte blocks to hold the state buffer - (All other registers are preserved) - - - Input: AH = 4Fh Super VGA support - AL = 04h Save/restore Super VGA video state - DL = 01h Save Super VGA video state - CX = Requested states (see above) - ES:BX = Pointer to buffer - - Output: AX = Status - (All other registers are preserved) - - - Input: AH = 4Fh Super VGA support - AL = 04h Save/restore Super VGA video state - DL = 02h Restore Super VGA video state - CX = Requested states (see above) - ES:BX = Pointer to buffer - - Output: AX = Status - (All other registers are preserved) - -Notes -~~~~~ -Due to the goal of complete compatibility with the VGA environment, the standard -VGA BIOS function 1Ch (Save/restore VGA state) has not been extended to save the -Super VGA video state. VGA BIOS compatibility requires that function 1Ch -returns a specific buffer size with specific contents, in which there is no room -for the Super VGA state. - - VESA Super VGA Standard VS911022-22 - -6.7 Function 05h - CPU Video Memory Window Control - -This function sets or gets the position of the specified window in the video -memory. The function allows direct access to the hardware paging registers. To -use this function properly, the software should use VESA BIOS Function 01h -(Return Super VGA mode information) to determine the size, location, and -granularity of the windows. - - Input: AH = 4Fh Super VGA support - AL = 05h Super VGA video memory window control - BH = 00h Select Super VGA video memory window - BL = Window number - 0 = Window A - 1 = Window B - DX = Window position in video memory - (in window granularity units) - - Output: AX = Status - (See notes below) - - - Input: AH = 4Fh Super VGA support - AL = 05h Super VGA video memory window control - BH = 01h Return Super VGA video memory window - BL = Window number - 0 = Window A - 1 = Window B - - Output: AX = Status - DX = Window position in video memory - (in window granularity units) - (See notes below) - -Notes -~~~~~ -This function is also directly accessible through a far call from the -application. The address of the BIOS function may be obtained by using VESA -BIOS Function 01h, Return Super VGA mode information. A field in the -ModeInfoBlock contains the address of this function. Note that this function -may be different among video modes in a particular BIOS implementation, so the -function pointer should be obtained after each set mode. - -In the far call version, no status information is returned to the application. -Also, the AX and DX registers will be destroyed. Therefore, if AX and/or DX -must be preserved, the application must do so priot to making the far call. - -The application must load the input arguments in BH, BL, and DX (for set window) -but does not need to load either AH or AL in order to use the far call version -of this function. - - VESA Super VGA Standard VS911022-23 - -6.8 Function 06h - Set/Get Logical Scan Line Length - -This function sets or gets the length of a logical scan line. This function -allows an application to set up a logical video memory buffer that is wider than -the displayed area. Function 07h then allows the application to set the -starting position that is to be displayed. - - Input: AH = 4Fh Super VGA support - AL = 06h Logical Scan Line Length - BL = 00h Select Scan Line Length - CX = Desired width in pixels - - Output: AX = Status - BX = Bytes Per Scan Line - CX = Actual Pixels Per Scan Line - DX = Maximum Number of Scan Lines - - - Input: AH = 4Fh Super VGA support - AL = 06h Logical Scan Line Length - BL = 01h Return Scan Line Length - - Output: AX = Status - BX = Bytes Per Scan Line - CX = Actual Pixels Per Scan Line - DX = Maximum Number of Scan Lines - -Notes -~~~~~ -The desired width in pixels may not be achieveable because of VGA hardware -considerations. The next larger value will be selected thta will accommodate -the desired number of pixels, and the actual number of pixels will be returned -in CX. BX returns a value that, when added to a pointer into video memory, will -point to the next scan line. For example, in a mode 13h this would be 320, but -in mode 12h this would be 80. DX returns the number of logical scan lines based -upon the new scan line length and the total memory installed and useable in this -display mode. This function is also valid in text modes. In text modes, the -application should find out the current character cell width through normal BIOS -functions, multiply that times the desired number of characters per line, and -pass the value in the CX register. - - VESA Super VGA Standard VS911022-24 - -6.9 Function 07h - Set/Get Display Start - -This function selects the pixel to be displayed in the upper left corner of the -display from the logical page. This function can be used to pan and scroll -around logical screens that are larger than the displayed screen. This function -can also be used to rapidly switch between two different displayed screens for -double buffered animation effects. - - Input: AH = 4Fh Super VGA support - AL = 07h Display Start Control - BH = 00h Reserved and must be 0 - BL = 00h Select Display Start - CX = First Displayed Pixel in Scan Line - DX = First Displayed Scan Line - - Output: AX = Status - - - Input: AH = 4Fh Super VGA support - AL = 07h Display Start Control - BL = 01h Return Display Start - - Output: AX = Status - BH = 00h Reserved and will be 0 - CX = First Displayed Pixel in Scan Line - DX = First Displayed Scan Line - -Notes -~~~~~ -This function is also valid in text modes. In text modes, the application -should find out the current character cell width through normal BIOS functions, -multiply that times the desired starting character column, and pass that value -in the CX register. It should also multiply the current character cell height -times the desired starting character row, and pass that value in the DX -register. - - VESA Super VGA Standard VS911022-25 - -6.10 Function 08h - Set/Get DAC Palette Control - -This function queries and selects the operating mode of the DAC palette. Some -DACs are configurable to provide 6-bits, 8-bits, or more of color definition per -red, green, and blue primary color. The DAC palette width is assumed to be -reset to standard VGA 6-bits per primary during a standard or VESA Set Super VGA -Mode (AX = 4F02h) call. - - Input: AH = 4Fh Super VGA support - AL = 08h Set/Get DAC Palette Control - BL = 00h Set DAC palette width - BH = Desired number of bits of color per primary - (Standard VGA = 6) - - Output: AX = Status - BH = Current number of bits of color per primary - (Standard VGA = 6) - - - Input: AH = 4Fh Super VGA support - AL = 08h Set/Get DAC Palette Control - BL = 01h Get DAC palette width - - Output: AX = Status - BH = Current number of bits of color per primary - (Standard VGA = 6) - -Notes -~~~~~ -An application can find out if DAC switching is available by querying Bit D0 of -the Capabilities field of the VgaInfoBlock structure returned by VESA Return -Super VGA Information (AX = 4F00h). The application can then attempt to set the -DAC palette width to the desired value. If the Super VGA is not capable of -selecting the requested palette width, then the next lower value that the Super -VGA is capable of will be selected. The resulting palette width is returned. - - VESA Super VGA Standard VS911022-26 - -7. Application Example -~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The following sequence illustrates how an application interface to the VESA BIOS -Extension. The hypothetical application is VESA-aware and calls the VESA BIOS -functions. However, the application is not limited to supporting just -VESA-defined video modes. This it will inquire what video modes are available -before setting up the video mode. - -1) The application would first allocate a 256 byte buffer. This buffer - will be used by the VESA BIOS to return information about the video - environment. Some applications will statically allocate this buffer, - others will use system calls to temporarily obtain buffer space. - -2) The application would then call VESA BIOS function 00h (Return Super VGA - information). If the AX register does not contain 004Fh on return from - the function call, the application can determine that the VESA BIOS - Extension is not present and handle such situation. - - If no error code is passed in AX, the function call was successful. The - buffer has been filled by the VESA BIOS Extension with various - information. The application can verify that indeed this is a valid - VESA block by identifying the characters 'VESA' in the beginning of the - block. The application can inspect the VESAVersion field to determine - whether the VESA BIOS Extension ha sufficient functionality. The - application may use the OEMStringPtr to locate OEM-specific information. - - Finally, the application can obtain a list of the supported Super VGA - modes by using the VideoModePtr. This field points to a list of the - video modes supported by the video environment. - -3) The application would then create a new buffer and call the VESA BIOS - function 01h (Return Super VGA mode information) to obtain information - about the supported video modes. Using the VideoModePtr obtained in - step 2) above, the application would call this function with a new mode - number until a suitable video mode is found. If no appropriate video - mode is found, it is up to the application to handle this situation. - - The Return Super VGA mode information function fills a buffer specified - by the application with information describing the features of the video - mode. The data block contains all the information an application needs - to take advantage of the video mode. - - The application would examine the ModeAttributes field. To verify that - the mode indeed is supported, the application would inspect bit D0. If - D0 is clear, then the mode is not supported by the hardware. This might - happen is a specific mode requires a certain type of monitor but that - monitor is not present. - -4) After the application has selected a video mode, the next step is to - initialize the mode. However, the application might first want to save - the present video mode. When the application exits, this mode would be - restored. To obtain the present video mode, the VESA BIOS function 03h - (Get Super VGA mode) would be used. If a non-VESA (standard VGA or - OEM-specific) mode is in effect, only the lower byte in the mode number - is filled. The upper byte is cleared. - -5) To initialize the video mode, the application would use VESA BIOS - function 02h (Set Super VGA mode). The application has from this point - on full access to the VGA hardware and video memory. - - VESA Super VGA Standard VS911022-27 - -6) When the application is about to terminate, it would restore the prior - video mode. The prior video mode, obtained in step 4) above could be - either a standard VGA mode, OEM-specific mode, or VESA-supported mode. - It would reinitialize the video mode by calling VESA BIOS function 02h - (Set Super VGA mode). The application would then exit. diff --git a/16/PCGPE10/VGABIOS.TXT b/16/PCGPE10/VGABIOS.TXT deleted file mode 100644 index 257f883c..00000000 --- a/16/PCGPE10/VGABIOS.TXT +++ /dev/null @@ -1,707 +0,0 @@ -----------1000------------------------------- -INT 10 - VIDEO - SET VIDEO MODE - AH = 00h - AL = mode (see below) -Return: AL = video mode flag (Phoenix BIOS) - 20h mode > 7 - 30h modes <= 7 except mode 6 - 3Fh mode 6 - AL = CRT controller mode byte (Phoenix 386 BIOS v1.10) -Notes: IBM standard modes do not clear the screen if the high bit of AL is set - (EGA or higher only) -SeeAlso: AX=0070h,AX=007Eh,AX=10F0h,AX=6F05h,AH=FFh"GO32",INT 5F/AH=00h - -Values for video mode: - text/ text pixel pixel colors display scrn system - grph resol box resoltn pages addr - 00h = T 40x25 8x14 16gray 8 B800 EGA - = T 40x25 8x16 16 8 B800 MCGA - = T 40x25 9x16 16 8 B800 VGA - 01h = T 40x25 8x14 16 8 B800 EGA - = T 40x25 8x16 16 8 B800 MCGA - = T 40x25 9x16 16 8 B800 VGA - 02h = T 80x25 8x14 16gray 4 B800 EGA - = T 80x25 8x16 16 4 B800 MCGA - = T 80x25 9x16 16 4 B800 VGA - 03h = T 80x25 8x14 16 4 B800 EGA - = T 80x25 8x16 16 4 B800 MCGA - = T 80x25 9x16 16 4 B800 VGA - 04h = G 40x25 8x8 320x200 4 B800 CGA,PCjr,EGA,MCGA,VGA - 05h = G 40x25 8x8 320x200 4gray B800 CGA,PCjr,EGA - = G 40x25 8x8 320x200 4 B800 MCGA,VGA - 06h = G 80x25 8x8 640x200 2 B800 CGA,PCjr,EGA,MCGA,VGA - 07h = T 80x25 9x14 mono var B000 MDA,Hercules,EGA - = T 80x25 9x16 mono B000 VGA - 0Bh = reserved (used internally by EGA BIOS) - 0Ch = reserved (used internally by EGA BIOS) - 0Dh = G 40x25 8x8 320x200 16 8 A000 EGA,VGA - 0Eh = G 80x25 8x8 640x200 16 4 A000 EGA,VGA - 0Fh = G 80x25 8x14 640x350 mono 2 A000 EGA,VGA - 10h = G 80x25 8x14 640x350 4 2 A000 64k EGA - = G 640x350 16 A000 256k EGA,VGA - 11h = G 80x30 8x16 640x480 mono A000 VGA,MCGA,ATI EGA,ATI VIP - 12h = G 80x30 8x16 640x480 16/256k A000 VGA,ATI VIP - = G 80x30 8x16 640x480 16/64 A000 ATI EGA Wonder - 13h = G 40x25 8x8 320x200 256/256k A000 VGA,MCGA,ATI VIP -----------1001------------------------------- -INT 10 - VIDEO - SET TEXT-MODE CURSOR SHAPE - AH = 01h - CH = bit 7 should be zero - bits 6,5 cursor blink - (00=normal, 01=invisible, 10=erratic, 11=slow) - (00=normal, other=invisible on EGA/VGA) - bits 4-0 top scan line containing cursor - CL = bottom scan line containing cursor (bits 0-4) -Notes: buggy on EGA systems--BIOS remaps cursor shape in 43 line modes, but - returns unmapped cursor shape - applications which wish to change the cursor by programming the - hardware directly on EGA or above should call INT 10/AX=1130h or - read 0040h:0085h first to determine the current font height -BUG: AMI 386 BIOS and AST Premier 386 BIOS will lock up the system if AL - is not equal to the current video mode -SeeAlso: AH=03h,AX=CD05h -----------1002------------------------------- -INT 10 - VIDEO - SET CURSOR POSITION - AH = 02h - BH = page number - 0-3 in modes 2&3 - 0-7 in modes 0&1 - 0 in graphics modes - DH = row (00h is top) - DL = column (00h is left) -SeeAlso: AH=03h,AH=05h -----------1003------------------------------- -INT 10 - VIDEO - GET CURSOR POSITION AND SIZE - AH = 03h - BH = page number - 0-3 in modes 2&3 - 0-7 in modes 0&1 - 0 in graphics modes -Return: AX = 0000h (Phoenix BIOS) - CH = start scan line - CL = end scan line - DH = row (00h is top) - DL = column (00h is left) -Notes: a separate cursor is maintained for each of up to 8 display pages - many ROM BIOSes incorrectly return the default size for a color display - (start 06h, end 07h) when a monochrome display is attached -SeeAlso: AH=01h,AH=02h -----------1004------------------------------- -INT 10 - VIDEO - READ LIGHT PEN POSITION (EGA Only) - AH = 04h -Return: AH = light pen trigger flag - 00h not down/triggered - 01h down/triggered - DH,DL = row,column of character light pen is on - CH = pixel row (graphics modes 04h-06h) - CX = pixel row (graphics modes with >200 rows) - BX = pixel column -Notes: on a CGA, returned column numbers are always multiples of 2 (320- - column modes) or 4 (640-column modes) - returned row numbers are only accurate to two lines -----------1005------------------------------- -INT 10 - VIDEO - SELECT ACTIVE DISPLAY PAGE - AH = 05h - AL = new page number (00h to number of pages - 1) (see AH=00h) -SeeAlso: AH=0Fh -----------1006------------------------------- -INT 10 - VIDEO - SCROLL UP WINDOW - AH = 06h - AL = number of lines by which to scroll up (00h = clear entire window) - BH = attribute used to write blank lines at bottom of window - CH,CL = row,column of window's upper left corner - DH,DL = row,column of window's lower right corner -Note: affects only the currently active page (see AH=05h) -Warning: some implementations have a bug which destroys BP -SeeAlso: AH=07h,AH=72h,AH=73h -----------1007------------------------------- -INT 10 - VIDEO - SCROLL DOWN WINDOW - AH = 07h - AL = number of lines by which to scroll down (00h=clear entire window) - BH = attribute used to write blank lines at top of window - CH,CL = row,column of window's upper left corner - DH,DL = row,column of window's lower right corner -Note: affects only the currently active page (see AH=05h) -Warning: some implementations have a bug which destroys BP -SeeAlso: AH=06h,AH=72h,AH=73h -----------1008------------------------------- -INT 10 - VIDEO - READ CHARACTER AND ATTRIBUTE AT CURSOR POSITION - AH = 08h - BH = page number (00h to number of pages - 1) (see AH=00h) -Return: AH = attribute - bit 7: blink - bits 6-4: background color - 000 black - 001 blue - 010 green - 011 cyan - 100 red - 101 magenta - 110 brown - 111 white - bits 3-0: foreground color - 0000 black 1000 dark gray - 0001 blue 1001 light blue - 0010 green 1010 light green - 0011 cyan 1011 light cyan - 0100 red 1100 light red - 0101 magenta 1101 light magenta - 0110 brown 1110 yellow - 0111 light gray 1111 white - AL = character -Notes: for monochrome displays, a foreground of 1 with background 0 is underlined - the blink bit may be reprogrammed to enable intense background colors - using AX=1003h or by programming the CRT controller -SeeAlso: AH=09h,AX=1003h -----------1009------------------------------- -INT 10 - VIDEO - WRITE CHARACTER AND ATTRIBUTE AT CURSOR POSITION - AH = 09h - AL = character to display - BH = page number (00h to number of pages - 1) (see AH=00h) - BL = attribute (text mode) or color (graphics mode) - if bit 7 set in graphics mode, character is xor'ed onto screen - CX = number of times to write character -Notes: all characters are displayed, including CR, LF, and BS - replication count in CX may produce an unpredictable result in graphics - modes if it is greater than the number of positions remaining in the - current row -SeeAlso: AH=08h,AH=0Ah,AH=4Bh,INT 17/AH=60h,INT 1F,INT 43,INT 44 -----------100A------------------------------- -INT 10 - VIDEO - WRITE CHARACTER ONLY AT CURSOR POSITION - AH = 0Ah - AL = character to display - BH = page number (00h to number of pages - 1) (see AH=00h) - BL = attribute (PCjr only) or color (graphics mode) - if bit 7 set in graphics mode, character is xor'ed onto screen - CX = number of times to write character -Notes: all characters are displayed, including CR, LF, and BS - replication count in CX may produce an unpredictable result in graphics - modes if it is greater than the number of positions remaining in the - current row -SeeAlso: AH=08h,AH=09h,AH=4Bh,INT 17/AH=60h,INT 1F,INT 43,INT 44 -----------100B--BH00------------------------- -INT 10 - VIDEO - SET BACKGROUND/BORDER COLOR - AH = 0Bh - BH = 00h - BL = background/border color (border only in text modes) -SeeAlso: AH=0Bh/BH=01h -----------100B--BH01------------------------- -INT 10 - VIDEO - SET PALETTE - AH = 0BH - BH = 01h - BL = palette ID - 00h background, green, red, and brown/yellow - 01h background, cyan, magenta, and white -SeeAlso: AH=0Bh/BH=00h -----------100C------------------------------- -INT 10 - VIDEO - WRITE GRAPHICS PIXEL - AH = 0Ch - BH = page number - AL = pixel color (if bit 7 set, value is xor'ed onto screen) - CX = column - DX = row -Notes: valid only in graphics modes - BH is ignored if the current video mode supports only one page -SeeAlso: AH=0Dh,AH=46h -----------100D------------------------------- -INT 10 - VIDEO - READ GRAPHICS PIXEL - AH = 0Dh - BH = page number - CX = column - DX = row -Return: AL = pixel color -Notes: valid only in graphics modes - BH is ignored if the current video mode supports only one page -SeeAlso: AH=0Ch,AH=47h -----------100E------------------------------- -INT 10 - VIDEO - TELETYPE OUTPUT - AH = 0Eh - AL = character to write - BH = page number - BL = foreground color (graphics modes only) -Notes: characters 07h (BEL), 08h (BS), 0Ah (LF), and 0Dh (CR) are interpreted - and do the expected things - IBM PC ROMs dated 4/24/81 and 10/19/81 require that BH be the same as - the current active page -SeeAlso: AH=02h,AH=0Ah -----------100F------------------------------- -INT 10 - VIDEO - GET CURRENT VIDEO MODE - AH = 0Fh -Return: AH = number of character columns - AL = display mode (see AH=00h) - BH = active page (see AH=05h) -Notes: if mode was set with bit 7 set ("no blanking"), the returned mode will - also have bit 7 set - EGA, VGA, and UltraVision return either AL=03h (color) or AL=07h - (monochrome) in all extended-row text modes -SeeAlso: AH=00h,AH=05h,AX=1130h,AX=CD04h -----------101000---------------------------- -INT 10 - VIDEO - SET SINGLE PALETTE REGISTER (PCjr,EGA,MCGA,VGA) - AX = 1000h - BL = palette register number (00h-0Fh) - = attribute register number (undocumented) - 10h attribute mode control register (should let BIOS control this) - 11h overscan color register (see also AX=1001h) - 12h color plane enable register (bits 3-0 enable corresponding - text attribute bit) - 13h horizontal PEL panning register - 14h color select register - BH = color or attribute register value -Notes: on MCGA, only BX = 0712h is supported - under UltraVision, the palette locking status (see AX=CD01h) - determines the outcome -SeeAlso: AX=1002h,AX=1007h,AX=CD01h -----------101001----------------------------- -INT 10 - VIDEO - SET BORDER (OVERSCAN) COLOR (PCjr,EGA,VGA) - AX = 1001h - BH = border color (00h-3Fh) -BUG: the original IBM VGA BIOS incorrectly updates the parameter save area - and places the border color at offset 11h of the palette table - rather than offset 10h -Note: under UltraVision, the palette locking status (see AX=CD01h) - determines the outcome -SeeAlso: AX=1002h,AX=1008h,AX=CD01h -----------101002----------------------------- -INT 10 - VIDEO - SET ALL PALETTE REGISTERS (PCjr,EGA,VGA) - AX = 1002h - ES:DX -> palette register list -Note: under UltraVision, the palette locking status (see AX=CD01h) - determines the outcome -SeeAlso: AX=1000h,AX=1001h,AX=1009h,AX=CD01h - -Format of palette register list: -Offset Size Description - 00h 16 BYTEs colors for palette registers 00h through 0Fh - 10h BYTE border color -----------101003----------------------------- -INT 10 - VIDEO - TOGGLE INTENSITY/BLINKING BIT (Jr, PS, TANDY 1000, EGA, VGA) - AX = 1003h - BL = new state - 00h background intensity enabled - 01h blink enabled -Note: although there is no function to get the current status, bit 5 of - 0040h:0065h indicates the state -SeeAlso: AH=08h -----------101007----------------------------- -INT 10 - VIDEO - GET INDIVIDUAL PALETTE REGISTER (VGA,UltraVision v2+) - AX = 1007h - BL = palette or attribute (undoc) register number (see AX=1000h) -Return: BH = palette or attribute register value -Notes: UltraVision v2+ supports this function even on color EGA systems in - video modes 00h-03h, 10h, and 12h; direct programming of the palette - registers will cause incorrect results because the EGA registers are - write-only. To guard against older versions or unsupported video - modes, programs which expect to use this function on EGA systems - should set BH to FFh on entry. -SeeAlso: AX=1000h,AX=1009h -----------101008----------------------------- -INT 10 - VIDEO - READ OVERSCAN (BORDER COLOR) REGISTER (VGA,UltraVision v2+) - AX = 1008h -Return: BH = border color (00h-3Fh) -Notes: UltraVision v2+ supports this function even on color EGA systems in - video modes 00h-03h, 10h, and 12h; direct programming of the palette - registers will cause incorrect results because the EGA registers are - write-only. To guard against older versions or unsupported video - modes, programs which expect to use this function on EGA systems - should set BH to FFh on entry. -SeeAlso: AX=1001h -----------101009----------------------------- -INT 10 - VIDEO - READ ALL PALETTE REGISTERS AND OVERSCAN REGISTER (VGA) - AX = 1009h - ES:DX -> 17-byte buffer (see AX=1002h) -Notes: UltraVision v2+ supports this function even on color EGA systems in - video modes 00h-03h, 10h, and 12h; direct programming of the palette - registers will cause incorrect results because the EGA registers are - write-only. To guard against older versions or unsupported video - modes, programs which expect to use this function on EGA systems - should set the ES:DX buffer to FFh before calling. -SeeAlso: AX=1002h,AX=1007h,AX=CD02h -----------101010----------------------------- -INT 10 - VIDEO - SET INDIVIDUAL DAC REGISTER (VGA/MCGA) - AX = 1010h - BX = register number - CH = new value for green (0-63) - CL = new value for blue (0-63) - DH = new value for red (0-63) -SeeAlso: AX=1012h,AX=1015h -----------101012----------------------------- -INT 10 - VIDEO - SET BLOCK OF DAC REGISTERS (VGA/MCGA) - AX = 1012h - BX = starting color register - CX = number of registers to set - ES:DX -> table of 3*CX bytes where each 3 byte group represents one - byte each of red, green and blue (0-63) -SeeAlso: AX=1010h,AX=1017h -----------101013----------------------------- -INT 10 - VIDEO - SELECT VIDEO DAC COLOR PAGE (VGA) - AX = 1013h - BL = subfunction - 00h select paging mode - BH = 00h select 4 blocks of 64 - BH = 01h select 16 blocks of 16 - 01h select page - BH = page number (00h to 03h) or (00h to 0Fh) -Note: not valid in mode 13h -SeeAlso: AX=101Ah -----------101015----------------------------- -INT 10 - VIDEO - READ INDIVIDUAL DAC REGISTER (VGA/MCGA) - AX = 1015h - BL = palette register number -Return: DH = red value - CH = green value - CL = blue value -SeeAlso: AX=1010h,AX=1017h -----------101017----------------------------- -INT 10 - VIDEO - READ BLOCK OF DAC REGISTERS (VGA/MCGA) - AX = 1017h - BX = starting palette register - CX = number of palette registers to read - ES:DX -> buffer (3 * CX bytes in size) (see also AX=1012h) -Return: buffer filled with CX red, green and blue triples -SeeAlso: AX=1012h,AX=1015h -----------101018----------------------------- -INT 10 - VIDEO - undocumented - SET PEL MASK (VGA/MCGA) - AX = 1018h - BL = new PEL value -SeeAlso: AX=1019h -----------101019----------------------------- -INT 10 - VIDEO - undocumented - READ PEL MASK (VGA/MCGA) - AX = 1019h -Return: BL = value read -SeeAlso: AX=1018h -----------10101A----------------------------- -INT 10 - VIDEO - GET VIDEO DAC COLOR-PAGE STATE (VGA) - AX = 101Ah -Return: BL = paging mode - 00h four pages of 64 - 01h sixteen pages of 16 - BH = current page -SeeAlso: AX=1013h -----------10101B----------------------------- -INT 10 - VIDEO - PERFORM GRAY-SCALE SUMMING (VGA/MCGA) - AX = 101Bh - BX = starting palette register - CX = number of registers to convert -SeeAlso: AH=12h/BL=33h -----------1011------------------------------- -INT 10 - VIDEO - TEXT-MODE CHARACTER GENERATOR FUNCTIONS (PS, EGA, VGA) - AH = 11h -The following functions will cause a mode set, completely resetting -the video environment, but without clearing the video buffer - AL = 00h, 10h: load user-specified patterns - ES:BP -> user table - CX = count of patterns to store - DX = character offset into map 2 block - BL = block to load in map 2 - BH = number of bytes per character pattern - AL = 01h, 11h: load ROM monochrome patterns (8 by 14) - BL = block to load - AL = 02h, 12h: load ROM 8 by 8 double-dot patterns - BL = block to load - AL = 03h: set block specifier - BL = block specifier - (EGA/MCGA) bits 0,1 = block selected by chars with attribute bit 3=0 - bits 2,3 = block selected by chars with attribute bit 3=1 - (VGA) bits 0,1,4 = block selected by attribute bit 3 = 0 - bits 2,3,5 = block selected by attribute bit 3 = 1 - AL = 04h, 14h: load ROM 8x16 character set (VGA) - BL = block to load -The routines called with AL=1xh are designed to be called only -immediately after a mode set and are similar to the routines called -with AL=0xh, except that: - Page 0 must be active. - Bytes/character is recalculated. - Max character rows is recalculated. - CRT buffer length is recalculated. - CRTC registers are reprogrammed as follows: - R09 = bytes/char-1 ; max scan line (mode 7 only) - R0A = bytes/char-2 ; cursor start - R0B = 0 ; cursor end - R12 = ((rows+1)*(bytes/char))-1 ; vertical display end - R14 = bytes/char ; underline loc - (*** BUG: should be 1 less ***) -SeeAlso: AX=CD10h -----------1011------------------------------- -INT 10 - VIDEO - GRAPHICS-MODE CHARACTER GENERATOR FUNCTIONS (PS, EGA, VGA) - AH = 11h - AL = 20h: set user 8 by 8 graphics characters (INT 1F) - ES:BP -> user table - AL = 21h: set user graphics characters - ES:BP -> user table - CX = bytes per character - BL = row specifier - 00h user set - DL = number of rows - 01h 14 rows - 02h 25 rows - 03h 43 rows - AL = 22h: ROM 8 by 14 set - BL = row specifier (see above) - AL = 23h: ROM 8 by 8 double dot - BL = row specifier (see above) - AL = 24h: load 8x16 graphics characters (VGA/MCGA) - BL = row specifier (see above) - AL = 29h: load 8x16 graphics characters (Compaq Systempro) - BL = row specifier (see above) -Notes: these functions are meant to be called only after a mode set - UltraVision v2+ sets INT 43 to the appropriate font for AL=22h,23h,24h, - and 29h -SeeAlso: INT 1F, INT 43 -----------101130----------------------------- -INT 10 - VIDEO - GET FONT INFORMATION (EGA, MCGA, VGA) - AX = 1130h - BH = pointer specifier - 00h INT 1Fh pointer - 01h INT 43h pointer - 02h ROM 8x14 character font pointer - 03h ROM 8x8 double dot font pointer - 04h ROM 8x8 double dot font (high 128 characters) - 05h ROM alpha alternate (9 by 14) pointer (EGA,VGA) - 06h ROM 8x16 font (MCGA, VGA) - 07h ROM alternate 9x16 font (VGA only) - 11h (UltraVision v2+) 8x20 font (VGA) or 8x19 font (autosync EGA) - 12h (UltraVision v2+) 8x10 font (VGA) or 8x11 font (autosync EGA) -Return: ES:BP = specified pointer - CX = bytes/character - DL = character rows on screen - 1 -Note: for UltraVision v2+, the 9xN alternate fonts follow the corresponding - 8xN font at ES:BP+256N -SeeAlso: AX=1100h,AX=1120h,INT 1F,INT 43 -----------1012--BL10------------------------- -INT 10 - VIDEO - ALTERNATE FUNCTION SELECT (PS, EGA, VGA, MCGA) - GET EGA INFO - AH = 12h - BL = 10h -Return: BH = 00h color mode in effect (I/O port 3Dxh) - 01h mono mode in effect (I/O port 3Bxh) - BL = 00h 64k bytes memory installed - 01h 128k bytes memory installed - 02h 192k bytes memory installed - 03h 256k bytes memory installed - CH = feature bits - CL = switch settings -----------1012--BL20------------------------- -INT 10 - VIDEO - ALTERNATE FUNCTION SELECT (PS,EGA,VGA,MCGA) - ALTERNATE PRTSC - AH = 12h - BL = 20h select alternate print screen routine -Notes: installs a PrtSc routine from the video card's BIOS to replace the - default PrtSc handler from the ROM BIOS, which usually does not - understand screen heights other than 25 lines - some adapters disable print-screen instead of enhancing it -SeeAlso: INT 05 -----------1012--BL30------------------------- -INT 10 - VIDEO - ALTERNATE FUNCTION SELECT (VGA) - SELECT VERTICAL RESOLUTION - AH = 12h - BL = 30h - AL = vertical resolution - 00h 200 scan lines - 01h 350 scan lines - 02h 400 scan lines -Return: AL = 12h if function supported -----------1012--BL31------------------------- -INT 10 - VIDEO - ALTERNATE FUNCTION SELECT (VGA, MCGA) - PALETTE LOADING - AH = 12h - BL = 31h - AL = 00h enable default palette loading - 01h disable default palette loading -Return: AL = 12h if function supported -----------1012--BL32------------------------- -INT 10 - VIDEO - ALTERNATE FUNCTION SELECT (VGA, MCGA) - VIDEO ADDRESSING - AH = 12h - BL = 32h - AL = 00h enable video addressing - 01h disable video addressing -Return: AL = 12h if function supported -----------1012--BL33------------------------- -INT 10 - VIDEO - ALTERNATE FUNCTION SELECT (VGA, MCGA) - GRAY-SCALE SUMMING - AH = 12h - BL = 33h - AL = 00h enable gray scale summing - 01h disable gray scale summing -Return: AL = 12h if function supported -SeeAlso: AX=101Bh,AX=BF06h -----------1012--BL34------------------------- -INT 10 - VIDEO - ALTERNATE FUNCTION SELECT (VGA) - CURSOR EMULATION - AH = 12h - BL = 34h - AL = 00h enable alphanumeric cursor emulation - 01h disable alphanumeric cursor emulation -Return: AL = 12h if function supported -----------1012--BL35------------------------- -INT 10 - VIDEO - ALTERNATE FUNCTION SELECT (PS) - DISPLAY-SWITCH INTERFACE - AH = 12h - BL = 35h - AL = 00h initial adapter video off - 01h initial planar video on - 02h switch active video off - 03h switch inactive video on - 80h *UNDOCUMENTED* set system board video active flag - ES:DX -> buffer (128 byte save area if AL = 0, 2 or 3) -Return: AL = 12h if function supported -----------1012--BL36------------------------- -INT 10 - VIDEO - ALTERNATE FUNCTION SELECT (PS, VGA) - VIDEO REFRESH CONTROL - AH = 12h - BL = 36h - AL = 00h enable refresh - 01h disable refresh -Return: AL = 12h if function supported -----------1013------------------------------- -INT 10 - VIDEO - WRITE STRING (AT and later,EGA) - AH = 13h - AL = write mode - bit 0: update cursor after writing - 1: string contains alternating characters and attributes - BH = page number - BL = attribute if string contains only characters - CX = number of characters in string - DH,DL = row,column at which to start writing - ES:BP -> string to write -Notes: recognizes CR, LF, BS, and bell - also available PC or XT with EGA or higher - HP 95LX only supports write mode 00h -BUG: on the IBM VGA Adapter, any scrolling which may occur is performed on - the active page rather than the requested page -SeeAlso: AH=09h,AH=0Ah -----------101A------------------------------- -INT 10 - VIDEO - DISPLAY COMBINATION (PS,VGA/MCGA) - AH = 1Ah - AL = 00h read display combination code -Return: BL = active display code (see below) - BH = alternate display code - 01h set display combination code - BL = active display code (see below) - BH = alternate display code -Return: AL = 1Ah if function was supported - -Values for display combination code: - 00h no display - 01h monochrome adapter w/ monochrome display - 02h CGA w/ color display - 03h reserved - 04h EGA w/ color display - 05h EGA w/ monochrome display - 06h PGA w/ color display - 07h VGA w/ monochrome analog display - 08h VGA w/ color analog display - 09h reserved - 0Ah MCGA w/ digital color display - 0Bh MCGA w/ monochrome analog display - 0Ch MCGA w/ color analog display - FFh unknown display type -----------101B------------------------------- -INT 10 - VIDEO - FUNCTIONALITY/STATE INFORMATION (PS,VGA/MCGA) - AH = 1Bh - BX = implementation type - 0000h return functionality/state information - ES:DI -> 64 byte buffer for state information (see below) -Return: AL = 1Bh if function supported - ES:DI buffer filled with state information -SeeAlso: AH=15h - -Format of state information: -Offset Size Description - 00h DWORD address of static functionality table (see below) - 04h BYTE video mode in effect - 05h WORD number of columns - 07h WORD length of regen buffer in bytes - 09h WORD starting address of regen buffer - 0Bh WORD cursor position for page 0 - 0Dh WORD cursor position for page 1 - 0Fh WORD cursor position for page 2 - 11h WORD cursor position for page 3 - 13h WORD cursor position for page 4 - 15h WORD cursor position for page 5 - 17h WORD cursor position for page 6 - 19h WORD cursor position for page 7 - 1Bh WORD cursor type - 1Dh BYTE active display page - 1Eh WORD CRTC port address - 20h BYTE current setting of register (3?8) - 21h BYTE current setting of register (3?9) - 22h BYTE number of rows - 23h WORD bytes/character - 25h BYTE display combination code of active display - 26h BYTE DCC of alternate display - 27h WORD number of colors supported in current mode - 29h BYTE number of pages supported in current mode - 2Ah BYTE number of scan lines active - (0,1,2,3) = (200,350,400,480) - 2Bh BYTE primary character block - 2Ch BYTE secondary character block - 2Dh BYTE miscellaneous flags - bit 0 all modes on all displays on - 1 gray summing on - 2 monochrome display attached - 3 default palette loading disabled - 4 cursor emulation enabled - 5 0 = intensity; 1 = blinking - 6 PS/2 P70 plasma display (without 9-dot wide font) active - 7 reserved - 2Eh 3 BYTEs reserved (00h) - 31h BYTE video memory available - 00h = 64K, 01h = 128K, 02h = 192K, 03h = 256K - 32h BYTE save pointer state flags - bit 0 512 character set active - 1 dynamic save area present - 2 alpha font override active - 3 graphics font override active - 4 palette override active - 5 DCC override active - 6 reserved - 7 reserved - 33h 13 BYTEs reserved (00h) - -Format of Static Functionality Table: -Offset Size Description - 00h BYTE modes supported #1 - bit 0 to bit 7 = 1 modes 0,1,2,3,4,5,6 supported - 01h BYTE modes supported #2 - bit 0 to bit 7 = 1 modes 8,9,0Ah,0Bh,0Ch,0Dh,0Eh,0Fh supported - 02h BYTE modes supported #3 - bit 0 to bit 3 = 1 modes 10h,11h,12h,13h supported - bit 4 to bit 7 reserved - 03h 4 BYTEs reserved - 07h BYTE scan lines supported - bit 0 to bit 2 = 1 if scan lines 200,350,400 supported - 08h BYTE total number of character blocks available in text modes - 09h BYTE maximum number of active character blocks in text modes - 0Ah BYTE miscellaneous function flags #1 - bit 0 all modes on all displays function supported - 1 gray summing function supported - 2 character font loading function supported - 3 default palette loading enable/disable supported - 4 cursor emulation function supported - 5 EGA palette present - 6 color palette present - 7 color paging function supported - 0Bh BYTE miscellaneous function flags #2 - bit 0 light pen supported - 1 save/restore state function 1Ch supported - 2 intensity blinking function supported - 3 Display Combination Code supported - 4-7 reserved - 0Ch WORD reserved - 0Eh BYTE save pointer function flags - bit 0 512 character set supported - 1 dynamic save area supported - 2 alpha font override supported - 3 graphics font override supported - 4 palette override supported - 5 DCC extension supported - 6 reserved - 7 reserved - 0Fh BYTE reserved -----------101C------------------------------- -INT 10 - VIDEO - SAVE/RESTORE VIDEO STATE (PS50+,VGA) - AH = 1Ch - AL = 00h return state buffer size -Return: BX = number of 64-byte blocks needed - 01h save video state - ES:BX -> buffer - 02h restore video state - ES:BX -> buffer containing previously saved state - CX = requested states - bit 0 video hardware - 1 BIOS data areas - 2 color registers and DAC state - 3-15 reserved -Return: AL = 1Ch if function supported diff --git a/16/PCGPE10/VGAREGS.TXT b/16/PCGPE10/VGAREGS.TXT deleted file mode 100644 index 07f141da..00000000 --- a/16/PCGPE10/VGAREGS.TXT +++ /dev/null @@ -1,806 +0,0 @@ - - Programming the VGA Registers - by Boone (boone@ucsd.edu), March '94 - - The IBM PC has long been slammed by owners of other computers which come -with superior graphics capabilities built right into hardware. The PC is a -strange beast to program in general, and when it comes to graphics the -programmer doesn't get much help from the video hardware. However, there are -quite a few neat tricks you can do using the VGA registers, as I'm sure you're -aware. The trick is knowing just which registers to use and how to use them to -achieve the desired results. In particular, precise timing is necessary to -avoid screen flicker and/or "snow". The registers on your video card are -necessary for just about any communication with the VGA besides basic -reading/writing of pixels. Some of the registers are standard, which are the -ones we will be discussing here. Most SVGA chipsets have their own special -functions associated with different registers for things such as bank -switching, which is part of what makes trying to write SVGA programs so -difficult. The registers are also used to set the various attributes of each -video mode: horizontal and vertical resolution, color depth, refresh rate, -chain-4 mode, and so on. Luckily, BIOS handles all this for us and since we -only need to set the video mode once at program start-up and once at exit, you -should need to mess with these particular functions too much, unless you are -using a special mode, such as mode X. (See the mode X section for more info on -all this.) If you want to experiment with the video mode registers, ftp -yourself a file called TWEAK*.* (my version is TWEAK10.ZIP). For now we'll -just assume the video mode has already been set to whatever mode you wish. - One of the most common techniques used by game programmers is fade in/out. -A clean fade is simple but very effective. Suprisingly, even big-budget games -like Ultima VII often have a lot of screen noise during their fades. With a -little effort you can easily write your own noise-free fade routines. There's -nothing like giving a professional first impression on your intro screen, since -the fade-in is likely to be the very first thing they see of your program. - BIOS is much to slow for this timing-critical opperation, so we'll have to -get down and dirty with our VGA card. Fading is a fairly simple process. As -you should know, the VGA palette consists of 256 colors with 3 attributes for -each color: red, green and blue. Every cycle of the fade, we have to go -through all 768 attributes and if it is larger than 0 subtract one. We'll use -regsiters 3C8h and 3C9h for palette opperations. The operation for sending a -palette to the card is straight-forward: send a 0 to port 3C8h and then your -768 byte buffer to port 3C9h. This is good enough for setting the palette at -the start of your program, but of course it has to go in a loop for the fade, -since you'll have to do this 256 times, subtracting one from each non-zero -member of the buffer. The pseudo-code looks something like this: - - constant PALSIZE = 256*3; - unsigned character buffer[PALSIZE]; - boolean done; - counter i,j; - - for j = 255 to 0 - { - for i = 0 to PALSIZE-1 - if buffer[i] > 0 - buffer[i] = buffer[i] - 1; - - output 0 to port 3C8h; - for i = 0 to PALSIZE-1 - output buffer[i] to port 3C9h; - } - - Easy enough, right? If you convert this to the language of your choice it -should run fine. (Make sure you have the buffer pre-loaded with the correct -palette, however, or you will get very strange results...) But you'll notice -the "snow" mentioned earlier. Depending on your video card, this could mean -that you see no noise at all to fuzz covering your entire screen. Even if it -look fine on your system, however, we want to make sure it will be smooth on -*all* setups it could potentially be run on. For that we're going to have to -ask the video card when it's safe to send the palette buffer to the card, and -for that we'll need the retrace register. - Putting aside palette concerns for a moment, I'll briefly cover the retrace -on your video card. (See the next section of this article for a more in-depth -discussion of this.) Bascially the vertical retrace is a short time in which -the screen is not being updated (from video memory to your monitor) and you can -safely do writes to your video memory or palette without worrying about getting -snow, flicker, tearing, or other unwanted side-effects. This is a pretty quick -period (retrace occurs 60 to 70 times a second) so you can't do too much at -once. - Returning to our fade: we want to update the palette during the vertical -retrace. The value we want is bit 3 of register 3DAh. While that bit is zero -we're safe to write. The best practice in this case is to wait for the bit to -change to one (screen is being traced) and then the instant it changes to 0, -blast all our new video info to the card. It won't be necessary in this case -since all we are doing is fading the palette and then waiting for the next -retrace, but if you're doing animation or playing music at the same time -you'll want to include this extra bit of code as a safety net. Otherwise you -might detect the 0 in the refresh bit at the very last instant of the retrace -and end up writing while the screen is being traced. The pseudo-code now goes -like this: - - for j = 255 to 0 - { - for i = 0 to PALSIZE-1 - if buffer[i] > 0 - buffer[i] = buffer[i] - 1; - - while bit 3 of port 3DAh is 0 - no opperation; - while bit 3 of port 3DAh is 1 - no opperation; - - output 0 to port 3C8h; - for i = 0 to PALSIZE-1 - output buffer[i] to port 3C9h; - } - - That's it! All that's left is for you to implement it in your favorite -language. However, I can hear the cries right now: "Code! Give us some real -assembly code we can use!" I'm reluctant to provided it as this is the exact -sort of thing that is easy to cut and paste into your program without knowing -how it works. However, I'll give you the unoptimized main loop in 80x86 -assembly as this may be clearer to you that my explanation or pseudo-code. Two -things to remember about this code: it is optimized enough to be smooth on any -video card (or any that I've seen, anyway) assuming that the fade is the _only_ -thing going on. There's some other things you may want to change if you plan -to say, play music during this process. Secondly, you'll need to have the -current palette loaded into the buffer beforehand. You could read it from the -VGA card using either registers or BIOS, but this is both slow and (in my -oppinion) sloppy coding. You should *never* ask the video card about anything -(excluding retrace) that you could keep track of yourself. In the case of the -palette, you probably already loaded it from disk anyway, or if you are using -the default palette just read the values once and store -them in your executable or in a resource file. - - palbuf DB 768 DUP (?) - fadecnt DW 040h - -; At this point, you should: -; 1) have the video mode set -; 2) have palbuf loaded with the current palette -; 3) have something on the screen to fade! - -fadeloop: - - xor al,al ; used for comparisons and port 3D8h - mov cx,768 ; loop counter - mov si,offset palbuf ; save palette buffer in si - -decloop: - mov dl,[si] ; put next pal reg in dx - cmp al,dl ; is it 0? - je next ; nope... - dec dl ; yes, so subtract one - mov [si],dl ; put it back into palette buffer - -next: - dec cx ; decrement counter - inc si ; increment our buffer - cmp cx,0 - jne decloop ; not done yet, so loop around - - mov cx,768 ; reset for palette output - sub si,768 ; reset palbuf pointer - mov dx,03c8h - out dx,al ; inform VGA of palette change - inc dx ; DX = 3C8h + 1 = 3C9h - - mov ch,02h ; do outter loop 2 times - mov dx,03dah ; prepare refresh register - mov bx,03c9h ; prepare palette reg (for quick loading) - - cli ; disable interrupts! - -outloop: - mov cl,80h ; do inner loop 128 times - - in al,dx ; wait for current retrace to end - test al,08h - jnz $-5 - - in al,dx ; wait for current screen trace to end - test al,08h - jz $-5 - - mov dx,bx ; load up the palette change register - -innerloop: - mov al,[si] ; load next byte of palbuf - out dx,al ; send it to the VGA card - dec cl ; decrement counter - inc si ; increment palbuf pointer - cmp cl,0 - jne innerloop ; loop while not done - - dec ch ; decrement outer loop counter - cmp ch,0 - jne outloop ; loop while not done - - sti ; restore interrupts - - mov ax,fadecnt ; entire palette has been sent - dec ax ; so check fade loop - mov fadecnt,ax - cmp ax,0 ; ready to quit? - jne fadeloop ; nope, keep fading! - - - I should add a few comments about this code segment. First of all, it -assumes you want to fade every color all the way down. You may only want to -fade certain sections of the palette (if your screen was only using a certain -number of colors) or maybe your palette is low-intensity so you don't need to -go the full 256 loops to get every color down to 0. It also goes by ones, so -if you want a faster fade you can have it subtract two from each attribute. -If you want to fade to a certain color other than black (for instance, fade to -red such as the "getting hit" effect in Doom), you'll need to check if each -attribute is above or below your target color and increment or decrement -accordingly. Also, you may have noticed something in the code absent from the -pseudo-code: it only sends 128 colors to the card each retrace! This is -because if you use all 256 the next retrace may start before you get all colors -sent to the video card, thanks to the unoptimized code. Some recommend as -little as 64 colors per retrace, however I've found 128 to be okay and -certainly much faster. The above code works for any VGA-equiped machine, -regardless of processor, but you'll probably want to compress all the IN and -OUT loops into REP INSB/OUTSB, REP INSW/OUTSW, or REP INSD/OUTSD instructions -depending upon the minimum processor requirement for your game/demo. - I won't describe fading in since it's the same sort of thing, and I'm sure -you can figure it out once you know how to use the registers themselves. It's -a little more complicated since you need a second buffer of target values for -your attributes, but otherwise quite similar. - - Next up is vertical retrace. This is simply one of many read registers on -your VGA, but it happens to be one of the most useful for animation and palette -fades (as shown above). Here's a quick rundown of what exactly the vertical -retrace is, and why it's useful. - There's an electron gun in the back of your monitor that keeps the pixels -"refreshed" with their correct values every 1/60th of a second or so. It fires -electrons at each pixel, row by row. The horizontal retrace is the time it -takes it to return from the right side of the screen after it has traced a row. -This is a very short time and I wouldn't worry about that too much right now, -as it is only useful for very specialized (and quite tricky) hardware effects. -More useful, however, is the vertical retrace which occurs when the electron -gun reaches the bottom of the screen (one entire screen traced) and it returns -diagonally to the upper-right hand corner of the screen. During this time you -are free to update anything you like having to do with video with no noise or -interference (since nothing on the screen is being updated). This is a fairly -short amount of time, though, so whatever you want to do you better do it -_quickly_. For animation, you'll usually want to keep a second buffer in main -memory (remember that video RAM is quite slow compared to main RAM) which you -can use to write your animations to. When the vertical retrace occurs, you'll -want to blast the entire thing to the VGA as quickly as possible, using a -memory copy instruction. You can find more on this in articles which cover -animation. - - Lastly I'll briefly describe the VGA mode-set registers. There are quite a -number of them and for the most part they're pretty boring. By sending -different values to these registers you can achieve the various video modes -that your card is capable of. These registers set values such as horizontal -and vertical resolution, retrace timing, addressing modes, color depth, timing, -and other fun stuff. The truth is that it's easier and just as effective to -let the BIOS (gasp!) handle setting the screen mode for you, particularly since -most games use standard modes such as 320x200 anyway. At the very least you -can let BIOS set the mode to begin with and then just modify the registers to -"tweak" the mode the way you want it. Any of these non-BIOS modes are -generally refered to as mode X. I don't want to go deep into detail on the -setting and usage of mode X because there is already so much info availible on -the topic. Check out the Mode X Faq (regularly posted in comp.sys.ibm.pc.demos -and rec.games.programmer), Micheal Abrash's collumn in Dr. Dobb's and his -X-sharp library, or the section on mode X in the PC-GPE. - One mode register I'll cover quickly is the chain-4 enable/disable. A lot -of programmers seem to have trouble visualizing what this thing does exactly. -Bit 3 of port 3C4h (index 4) controls chain-4 mode. Normally it is on. This -allows fast linear addressing of the bytes in video memory, which is the way -you are probably used to addressing them. For example, to change the second -pixel on the screen to a certain color, you simply write the value to address -A000:0001. With chain-4 disabled (the main feature of mode X besides better -resolution) A000:0000 refers to the first pixel in the upper-left corner of -your screen, A000:0001 refers to the fourth pixel, A000:0002 to the eight pixel -and so on. The odd pixels are accessed by changing the write plane. Since -there are four planes, you effectively get an extra two bits of addressing -space, boosting the total bit width for your pixel addressing from 16 to 18. -Standard chain-4 four only allows access to 64K of memory (2^16) while -disabling this feature gives you the full 256K (2^18) of memory to work with. -The disadvantage, of course, is that pixel writes are slower due to the port -writes required to access odd pixels. How can this be an advantage? For one -thing, you can write four pixels at a time as long as they are all the same -color - handy for single-color polygons, as in flight simulators. Secondly, -you get four times as much memory. This allows you to have higher resolutions -without bank switching, or scroll the screen using hardware scrolling, or do -page flipping for smooth animation. And since you can change the resolution, -you can give yourself a sqaure aspect ration (320x240) which is better for -bitmap rotations and the like. But remember that it can be slower for -bitmapped graphics because you have to do at least four writes to the card (to -change planes) in order to copy bitmaps from main RAM to video memory. Don't -use mode X just because you think it's "cool"; make sure you have a good reason -for wanting to use it in your program, or otherwise you're wasting a lot of -effort for no reason. - - Now, I'm sure you want me to continue until I divulge all the secrets of the -VGA register to you - but, I only have some much time and space. Besides, I -still haven't uncovered all of their mysteries and capabilities myself. -However, below is a list of the registers which you may want to play with for -various effects. The following list was posted on rec.games.programmer by -Andrew Bromage (bromage@mundil.cs.mu.OZ.AU), so thanks to him for posting in to -begin with. - That's it for this article and I hope it helped you understand your VGA card -a little better. If not, re-read it, and try writing your own programs which -use the registers. The only way to really understand it (as with most things) -is to get some hands-on experience. - If you've got any questions, comments, flames, or corrections related to -this document or game programming/design in general, feel free to post an -article in rec.games.programmer (in case you haven't noticed by now, I hang out -there regularly) or send mail to boone@ucsd.edu. - -Here's the list. Have fun... - - Documentation Over the I/O Registers for Standard VGA Cards - - Documentated by Shaggy of The Yellow One - Email: D91-SJD@TEKN.HJ.SE - -Feel free to spread this to whoever wants it..... ------------------------------------------------------------- -Port-Index: - Port: Write/03c2h Read/03cch -usage: d7 Vertical sync polarity - d6 Horizontal sunc polarity - d5 Odd /even page - d4 Disable video - d3 Clock select 1 - d2 Clock select 0 - d1 Enable/Disable display RAM - d0 I/O address select -Description: Sync polarity: Bits are set as below for VGA displays - that use sync polarity to determine screen resolution. - Many newer multiple frequency displays are insensitive - to sync polarity - - d7 d6 Resolution - 0 0 Invalid - 0 1 400 lines - 1 0 350 lines - 1 1 480 lines - - I/O address select: When set to zero, selects the - monochrome I/O address space (3bx). When set to one, - it selects the color I/O address space (3dx) - ------------------------------------------------------------- -Port-Index: - Port: 03c2h ; read only -usage: d7 Vertical Retrace Interrupt pendling - d6 Feature connector bit 1 - d5 Feature connector bit 0 - d4 Switch sense - d0-d3 Unused - -Description: d7 uses IRQ2 - ------------------------------------------------------------- -Port-Index: - Port: 03bah,03dah ; read only -usage: d3 Vertical retrace - d0 Horizontal retrace - ------------------------------------------------------------- -Port-Index: - Port: 03c3h,46e8h -usage: d7-d1 Reserved - d0 VGA enable/disable (03c3h only) - -Description: Disables access to display memmory and the other - VGA's ports - ------------------------------------------------------------- -Port-Index: 00h Port: 03d4h, 03b4h -usage: Horizontal total -Description: Total number of characters in horizontal scan minus - five ( including blanked and border characters) - ------------------------------------------------------------- -Port-Index: 01h Port: 03d4h, 03b4h -usage: Horizontal display enable -Description: Total number of characters displayed in horizontal - scan minus one. ------------------------------------------------------------- -Port-Index: 02h Port: 03d4h, 03b4h -usage: Start horizontal blanking -Description: Character at which blanking starts - ------------------------------------------------------------- -Port-Index: 03h Port: 03d4h, 03b4h -usage: End horizontal blanking - d7 Test - d6 Skew control - d5 Skew control - d0-d4 End blanking -Description: End blanking: is five LSB bits of six-bit value, - which define the character at which blanking stops. - The MSB bit of this value is in register index 5. - ------------------------------------------------------------- -Port-Index: 04h Port: 03d4h, 03b4h -usage: Start horizontal retrace -Description: Character at which horizontal retrace starts - ------------------------------------------------------------- -Port-Index: 05h Port: 03d4h, 03b4h -usage: End horizontal retrace - d7 End horizontal blanking bit 5 - d6 Horizontal retrace delay - d5 Horizontal retrace delay - d0-d4 End horizontal retrace -Description: End horizontal retrace: defines the character at - which horizontal retrace ends - ------------------------------------------------------------- -Port-Index: 06h Port: 03d4h, 03b4h -usage: Vertical total -Description: Total number of horizontal scan lines minus two - (including blanked and border characters). MSB bits - of this value are in register index 7 - ------------------------------------------------------------- -Port-Index: 07h Port: 03d4h, 03b4h -usage: Overflow register - d7 Vertical retrace start (bit 9) - d6 Vertical display enable end (bit 9) - d5 Vertical total (bit 9) - d4 Line compare (bit 8) - d3 Start vertical blank (bit 8) - d2 Vertical retrace start (bit 8) - d1 Vertical display enable end (bit 8) - d0 Vertical total (bit 8) ------------------------------------------------------------- -Port-Index: 08h Port: 03d4h, 03b4h -usage: Preset row scan - d7 Unused - d6 Byte panning control - d5 Byte panning control - d0-d4 Preset row scan -Description: Byte panning control: is used to control byte - panning. This register together with attribute - controller register 13h allows for up to 31 pixels of - panning in double word modes - Preset row scan: Which character scan line is the - first to be displayed ------------------------------------------------------------- -Port-Index: 09h Port: 03d4h, 03b4h -usage: Maximum scan line/Character height - d7 double scan - d6 bit d9 of line compare register - d5 bit d9 of start vertical blank register - d0-d4 Maximum scan line -Description: d0-d5=Character height-1, only in textmodes ------------------------------------------------------------- -Port-Index: 0ah Port: 03d4h, 03b4h -usage: Cursor start - d7,d6 Reserved (0) - d5 Cursor off - d4-d0 Cursor start -Description: ------------------------------------------------------------- -Port-Index: 0bh Port: 03d4h, 03b4h -usage: Cursor end - d7 reserved - d6,d5 Cursor skew - d4-d0 Cursor end -Description: ------------------------------------------------------------- -Port-Index: 0ch Port: 03d4h, 03b4h -usage: Start address high ------------------------------------------------------------- -Port-Index: 0dh Port: 03d4h, 03b4h -usage: Start address low -Description: Determine the offset in display memory to be - displayed on the upper-left corner on the screen ------------------------------------------------------------- -Port-Index: 0eh Port: 03d4h, 03b4h -usage: Cursor location (high byte) ------------------------------------------------------------- -Port-Index: 0fh Port: 03d4h, 03b4h -usage: Cursor location (low byte) -Description: Where the cursor is displayed on screen ------------------------------------------------------------- -Port-Index: 10h Port: 03d4h, 03b4h -usage: Vertical retrace start -Description: 8 bits out of 10 ------------------------------------------------------------- -Port-Index: 11h Port: 03d4h, 03b4h -usage: Vertical retrace end - d7 Write protect CRTC register 0 to 7 - d6 refresh cycle select - d5 enable vertical interrupt (when 0) - d4 Clear vertical interrupt (when 0) - d0-d3 Vertical retrace end ------------------------------------------------------------- -Port-Index: 12h Port: 03d4h, 03b4h -usage: Vertical display enable end -Description: eight LSB bits out of ten-bit value which define - scan line minus one at which the display ends. - The other two are in CRTC register index 7 ------------------------------------------------------------- -Port-Index: 13h Port: 03d4h, 03b4h -usage: Offset / Logical screen width -Description: Logical screen width between successive scan lines ------------------------------------------------------------- -Port-Index: 14h Port: 03d4h, 03b4h -usage: Underline location register - d7 Reserved - d6 Double word mode - d5 count by 4 - d0-d4 Underline location -Description: Underline location: Monochrome textmode only ------------------------------------------------------------- -Port-Index: 15h Port: 03d4h, 03b4h -usage: Start vertical blanking -Description: eight LSB bits of ten-bit value minus one which - define at which scan line the vertical blanking - starts. The other two bits are in CRTC registers - index 7 and 9 ------------------------------------------------------------- -Port-Index: 16h Port: 03d4h, 03b4h -usage: End vertical blanking -Description: eight LSB bits of a value which determine the scan - line after which vertical blanking ends. ------------------------------------------------------------- -Port-Index: 17h Port: 03d4h, 03b4h -usage: Mode control register - d7 Enable vertical and hoizontal retrace - d6 Byte mode (1), word mode (0) - d5 Address wrap - d4 Reserved - d3 count by 2 - d2 multiple vertical by 2 (use half in - CRTC (8,10,12,14,18) - d1 Select row scan counter (not used) - d0 compatibilty mode support (enable interleave) ------------------------------------------------------------- -Port-Index: 18h Port: 03d4h, 03b4h -usage: Line compare register -Description: Split screen, 8 bit value out of a ten-bit value ------------------------------------------------------------- -Port-Index: 00h Port: 03c4h -usage: Reset register - d7-d2 Reserved - d1 Synchronous reset - d0 Asynchronous reset -Description: Synchr. when set to zero, will halt and reset - the sequencer at the end of its current cycle - Asyncht. when set to zero, will immediatly halt - and reset the sequencer. Data can be loss. ------------------------------------------------------------- -Port-Index: 01h Port: 03c4h -usage: Clock mode register - d7,d6 Reserved - d5 display off - d4 Allow 32-bit Fetch (not used in standard modes) - d3 Divide dot clock by 2 (used in some 320*200 modes) - d2 Allow 16-bit fetch (used in mon graphics modes) - d1 Reserved - d0 Enable (0) 9 dot characters (mono text and 400-line) -Description: Display off: Will blank screen and give the cpu - uninterrupted access the display memory. ------------------------------------------------------------- -Port-Index: 02h Port: 03c4h -usage: Color plane write enable register - d7,d6 Reserved - d3 Plane 3 Write enable - d2 Plane 2 Write enable - d1 Plane 1 Write enable - d0 Plane 0 Write enable -Description: ------------------------------------------------------------- -Port-Index: 03h Port: 03c4h -usage: Character generator select register - d7,d6 Reserved - d5 Character generator table select A (MSB) - d4 Character generator table select B (MSB) - d3,d2 Character generator table select A - d1,d0 Character generator table select B -Description: This register is only of interest if your software - will be using multiple character sets. Either one - or two character sets can be active. Table A selects - the charcater with attribute d3 set to zero and - Table B is the one with d3 set to one. ------------------------------------------------------------- -Port-Index: 04h Port: 03c4h -usage: Memory mode register - d4-d7 Reserved - d3 Chain 4 (address bits 0&1 to select plan, mode 13h) - d2 Odd/even (address bit 0 to select plane 0&2 or - 1&3 text modes) - d1 Extended memory (disable 64k modes) - d0 Reserved -Description: ------------------------------------------------------------- -Port-Index: 00h Port: 03ceh -usage: Set / Reset register - d7-d4 Reserved (0) - d3 Fill data for plane 3 - d2 Fill data for plane 2 - d1 Fill data for plane 1 - d0 Fill data for plane 0 ------------------------------------------------------------- -Port-Index: 01h Port: 03ceh -usage: Set / Reset enable register - d7-d4 Reserved (0) - d3 enable set/reset for plane 3 (1 = enable) - d2 enable set/reset for plane 2 (1 = enable) - d1 enable set/reset for plane 1 (1 = enable) - d0 enable set/reset for plane 0 (1 = enable) -Description: Set/Reset enable defines which memory planes will - receive fill data from set/reset register. Any plane - that is disable for set/reset will be written with - normal processor output data ------------------------------------------------------------- -Port-Index: 02h Port: 03ceh -usage: Color compare register - d7-d4 Reserved - d3 Color compare value for plane 3 - d2 Color compare value for plane 2 - d1 Color compare value for plane 1 - d0 Color compare value for plane 0 -Description: one indicate that color is the same ------------------------------------------------------------- -Port-Index: 03h Port: 03ceh -usage: Data rotate / Function select register - d7-d5 Resrved (0) - d4,d3 Function select - d2-d0 Rotate count - - d4 d3 Function - 0 0 Write data unmodified - 0 1 Write data ANDed with processor latches - 1 0 Write data ORed with processor latches - 1 1 Write data XORed with processor latches -Description: Rotation is made before writing data ------------------------------------------------------------- -Port-Index: 04h Port: 03ceh -usage: Read plane select register - d7-d2 Reserved (0) - d1,d0 Defines color plane for reading (0-3) -Description: Doesnt matter in color compare mode ------------------------------------------------------------- -Port-Index: 05h Port: 03ceh -usage: Mode register - d7 Reserved (0) - d6 256-colour mode - d5 Shift register mode - d4 Odd / Even mode - d3 Color compare mode enable (1 = enable) - d2 Reserved (0) - d1,d0 Write mode - - d1 d0 Write mode - 0 0 Direct write (data rotate, set/reset may apply) - 0 1 Use processor latches as write data - 1 0 Color plane n (0-3) is filled with the value of - bit n in the write data - 1 1 Use (rotated) write data ANDed with Bit mask as - bit mask. Use set/reset as if set/reset was - enable for all planes -Description: ------------------------------------------------------------- -Port-Index: 06h Port: 03ceh -usage: Miscellaneous register - d7-d4 Reserved - d3-d2 Memory map - 00 = A000h for 128k - 01 = A000h for 64k - 10 = B000h for 32k - 11 = B800h for 32k - d1 Odd/even enable (used in text modes) - d0 Graphics mode enable -Description: Memory map defines the location and size of the - host window ------------------------------------------------------------- -Port-Index: 07h Port: 03ceh -usage: Color don't care register - d7-d4 Reserved (0) - d3 Plane 3 don't care - d2 Plane 2 don't care - d1 Plane 1 don't care - d0 Plane 0 don't care -Description: Color don't care is used in conjunction with color - compare mode. This register masks particular planes - from being tested during color compare cycles. ------------------------------------------------------------- -Port-Index: 08h Port: 03ceh -usage: Bitmask register -Description: The bitmask register is used to mask certain bit - positons from being modified. ------------------------------------------------------------- -Port-Index: - Port: 03c0h both index and data -usage: d7,d6 Reserved - d5 Palette address source - 0 = palette can be modified, screen is blanked - 1 = screen is enable, palette cannot be modified - d4-d0 Palette register address -Description: Palette register address selects which register of - the attributes controller will be addres,sed by the - next I/O write cycle ------------------------------------------------------------- -Port-Index: 00h-0fh Port: 03c0h -usage: Color palette register - d6,d7 Reserved - d5-d0 Color value -Description: not used in 256 color modes ------------------------------------------------------------- -Port-Index: 10h Port: 03c0h -usage: Mode control register - d7 p4,p5 source select - d6 pixel width - d5 Horizontal panning compatibility - d4 Reserved - d3 Background intensify / enable blinking - d2 Line graphics enable (text modes only) - d1 display type - d0 graphics / text mode -Description: p4,p5 source select: selects the source for video - outputs p4 and p5 to the DACs. If set to zero, p4 - and p5 are driven from the palette registers (normal - operation). If set to one, p4 and p5 video outputs - come from bits 0 and 1 of the color select register. - pixel width: is set to one in mode 13h (256-color mode) - horizontal panning compatibility: enhances the - operation of the line compare register of the CRT - controller, which allows one section of the screen - to be scrolled while another section remains stationary. - When this bit is set to one, the stationary - section of the screen will also be immune to horizontal - panning. ------------------------------------------------------------- -Port-Index: 11h Port: 03c0h -usage: Screen border color -Description: In text modes, the screen border color register - selects the color of the border that sorrounds the - text display area on the screen. This is also referred - to by IBM as overscan. Unfortunately, this feature - does not work properly on EGA displays in 350-line - modes. ------------------------------------------------------------- -Port-Index: 12h Port: 03c0h -usage: Color plane enable register - d7,d6 Reserved - d5,d4 Video status mux - d3 Enable color plane 3 - d2 Enable color plane 2 - d1 Enable color plane 1 - d0 Enable color plane 0 -Description: The video status mux bits can be used in conjunction - with the diagnostic bits of input status register 1 - to read palette registers. For the EGA, this is the - only means available for reading the palette registers. - Enable color planes can be used to enable or disable - color planes at the input to the color lockup table. - A zero in any of these bit positions will mask the - data from that color plane. The effect on the display - will be the same as if that color plane were cleared - to all zeros. ------------------------------------------------------------- -Port-Index: 13h Port: 03c0h -usage: Horizontal panning register - d7-d4 reserved - d3-d0 Horizontal pan -Description: Horizontal pan allows the display to be shifted - horizontally one pixel at a time. - - d3-d0 Number of pixels shifted to the left - 0+,1+,2+ 13h Other modes - 3+,7,7+ - 0 1 0 0 - 1 2 1 - - 2 3 2 1 - 3 4 3 - - 4 5 4 2 - 5 6 5 - - 6 7 6 3 - 7 8 7 - - 8 9 - - ------------------------------------------------------------- -Port-Index: 14h Port: 03c0h -usage: Color select register - d7-d4 Reserved - d3 color 7 - d2 color 6 - d1 color 5 - d0 color 4 -Description: Color 7 and color 6: are normally used as the high - order bits of the eight-bit video color data from the - attribute controller to the DACs. The only exceptions - are 256-color modes - Color 5 and color 4: can be used in place of the p5 - and p6 outputs from the palette registers (see mode - control register - index 10h). In 16-color modes, the - color select register can be used to rapidly cycle - between sets of colors in the video DAC. ------------------------------------------------------------- -Port-Index: - Port: 03c6h -usage: Pixel mask register -Description: ??? ------------------------------------------------------------- -Port-Index: - Port: 03c7h -usage: DAC state register (read-only) -Description: if d0 and d1 is set to zero it indicates that - the lookup table is in a write mode ------------------------------------------------------------- -Port-Index: - Port: 03c7h -usage: Lookup table read index register (Write only) -Description: Used when you want to read the palette (set color - number) ------------------------------------------------------------- -Port-Index: - Port: 03c8h -usage: Lookup table write index register -Description: Used when you want to change palette (set color - number) ------------------------------------------------------------- -Port-Index: - Port: 03c9h -usage: Lookup table data register -Description: Read color value (Red-Green-Blue) or write same data. ------------------------------------------------------------- diff --git a/16/PCGPE10/VIDEO7.TXT b/16/PCGPE10/VIDEO7.TXT deleted file mode 100644 index bd1ee1b4..00000000 --- a/16/PCGPE10/VIDEO7.TXT +++ /dev/null @@ -1,197 +0,0 @@ - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Programming the Video7 SVGA Chip ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - Written for the PC-GPE by Mark Feldman - e-mail address : u914097@student.canberra.edu.au - myndale@cairo.anu.edu.au - - Please read the file SVGINTRO.TXT - (Graphics/SVGA/Intro PC-GPE menu option) - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ THIS FILE MAY NOT BE DISTRIBUTED ³ - ³ SEPARATE TO THE ENTIRE PC-GPE COLLECTION. ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Disclaimer ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ - -I assume no responsibility whatsoever for any effect that this file, the -information contained therein or the use thereof has on you, your sanity, -computer, spouse, children, pets or anything else related to you or your -existance. No warranty is provided nor implied with this information. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Video7 Extensions ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -To modify any of the Video7 extended registers you must enable the -extensions. Disable them once you are done. - -To enable extensions: - -PortW[$3C4] := $EA06; - -To disable extensions: - -PortW[$3C4] := $AE06; - - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Identifying the Video7 SVGA Chip ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The presence of a Video7 chip can be detected with the following procedure: - -var old_value, new_value, id : byte; - -EnableVideo7Extensions; -Port[$3D4] := $0C; -old_value := Port[$3D5]; -Port[$3D5] := $55; -new_value := Port[$3D5]; -Port[$3D4] := $1F; -id := Port[$3D5]; -Port[$3D4] := $0C; -Port[$3D5] := old_value; -DisableVideo7Extentions; - -{ Check that register value is $55 Xor $EA } -if id = $BF then - card is a video7 -else - card isn't a video7 - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Identifying which Video7 Chip is Present ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Once you know that the video card has a video7 in it you can read the Chip -Revision register to find out which chip it is: - -Port[$3C4] := $8E; -chip := Port[$3C5]; - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Value in ³ - ³ chip variable Video7 Chip ³ - ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ - ³ 40h-49h 1024i ³ - ³ 50h-59h V7VGA Version 5 ³ - ³ 70h-7Eh V7VGA FASTWRITE/VRAM ³ - ³ 80h-FFh VEGA VGA ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Video7 Graphics Display Modes ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Mode Resolution Colors ³ - ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ - ³ 60h 752x410 16 ³ - ³ 61h 720x540 16 ³ - ³ 62h 800x600 16 ³ - ³ 63h 1024x768 2 ³ - ³ 64h 1024x768 4 ³ - ³ 65h 1024x768 16 ³ - ³ 66h 640x400 256 ³ - ³ 67h 640x480 256 ³ - ³ 68h 720x540 256 ³ - ³ 69h 800x600 256 ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Video7 Display Memory ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Remeber, the extensions must be enabled before calling any of the following -procedures. - -The Video7 version 1-3 chips use a ridiculously complex method to switch -banks (in my opinion at least), so for these chips I'll only include the code -to bank switch and leave the technical info on what it does and why it does -it till a future PC-GPE version (if ever). - -The version 1-3 chips map two banks to host memory A000:0000-FFFFh. One bank -is used for read operations, the other is used for write operations. For 256 -color modes there are 16 64k banks (numbered 0 - 15 for the following -procedures). One really "stuffed in the head" thing about these chips (from -a programmers point of view anyway) is that both bank registers use a common -SVGA register to store their 2 low order bits, so if you set the Read Bank -number, the Write Bank number's 2 low order bits will be set the same as the -Read Bank number's 2 low order bits. - -The Write Bank number for 256 color modes can be set with the following -procedure: - -Port[$3C4] := $F9; -Port[$3C5] := bank_number and 1; -Port[$3C2] := (Port[$3CC] and $DF) or ((bank_number and 2) shl 4); -Port[$3C4] := $F6; -Port[$3C5] := (Port[$3C5] and $FC) or (bank_number shr 2); - -The Read Bank number for 256 color modes can be set with the following -procedure: - -Port[$3C4] := $F9; -Port[$3C5] := bank_number and 1; -Port[$3C2] := (Port[$3CC] and $DF) or ((bank_number and 2) shl 4); -Port[$3C4] := $F6; -Port[$3C5] := (Port[$3C5] and $F3) or (bank_number and $0C); - -By version 4 Headlands Technologies had gotten their act together and -adopted a more "sane" bank switching scheme. Version 4 supports both single -and duel paging schemes. There are 16 64k long banks, and a 64k granularity -with the techniques used here. - -The single paging scheme maps a bank to host memory A000:0000-FFFFh for -both read and write operations. The single paging scheme is the -default for version 4, but can also be set with the following procedure: - -Port[$3C4] := $E0; -Port[$3C5] := Port[$3C5] and $7F - -The Single/Write Bank Register is used to select which bank to map to -host memory: - - Index : E8h at port 3C4h - Read/Write at port 3C5h - ÚÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄ¿ - ³ 7 ³ 6 ³ 5 ³ 4 ³ 3 ³ 2 ³ 1 ³ 0 ³ - ÀÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÙ - ÀÄÄÄÄÄÂÄÄÄÄÄÙ - Bank - -A bank can be selected with the following procedure: - -PortW[$3C4] := (bank_number shl 12) + $E8; - -In duel paging mode one bank is mapped to A000:0000-FFFF for write operations -and another for read operations. Duel paging mode can be selected with the -following procedure: - -Port[$3C4] := $E0; -Port[$3C5] := Port[$3C5] or $80; - -The Single/Write Bank Register (see above) is used to select which bank to -map to host memory for writing operations. The Read Bank Register selects -which bank to use for read operations: - - Index : E9h at port 3C4h - Read/Write at port 3C5h - ÚÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄ¿ - ³ 7 ³ 6 ³ 5 ³ 4 ³ 3 ³ 2 ³ 1 ³ 0 ³ - ÀÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÙ - ÀÄÄÄÄÄÂÄÄÄÄÄÙ - Bank - -A read bank can be selected with the following procedure: - -PortW[$3C4] := (bank_number shl 12) + $E9; diff --git a/16/PCGPE10/VOC.TXT b/16/PCGPE10/VOC.TXT deleted file mode 100644 index 71ef5625..00000000 --- a/16/PCGPE10/VOC.TXT +++ /dev/null @@ -1,72 +0,0 @@ - -Creative Voice (VOC) file format --------------------------------- - -~From: galt@dsd.es.com - -(byte numbers are hex!) - - HEADER (bytes 00-19) - Series of DATA BLOCKS (bytes 1A+) [Must end w/ Terminator Block] - -- --------------------------------------------------------------- - -HEADER: -======= - byte # Description - ------ ------------------------------------------ - 00-12 "Creative Voice File" - 13 1A (eof to abort printing of file) - 14-15 Offset of first datablock in .voc file (std 1A 00 - in Intel Notation) - 16-17 Version number (minor,major) (VOC-HDR puts 0A 01) - 18-19 2's Comp of Ver. # + 1234h (VOC-HDR puts 29 11) - -- --------------------------------------------------------------- - -DATA BLOCK: -=========== - - Data Block: TYPE(1-byte), SIZE(3-bytes), INFO(0+ bytes) - NOTE: Terminator Block is an exception -- it has only the TYPE byte. - - TYPE Description Size (3-byte int) Info - ---- ----------- ----------------- ----------------------- - 00 Terminator (NONE) (NONE) - 01 Sound data 2+length of data * - 02 Sound continue length of data Voice Data - 03 Silence 3 ** - 04 Marker 2 Marker# (2 bytes) - 05 ASCII length of string null terminated string - 06 Repeat 2 Count# (2 bytes) - 07 End repeat 0 (NONE) - 08 Extended 4 *** - - *Sound Info Format: **Silence Info Format: - --------------------- ---------------------------- - 00 Sample Rate 00-01 Length of silence - 1 - 01 Compression Type 02 Sample Rate - 02+ Voice Data - - ***Extended Info Format: - --------------------- - 00-01 Time Constant: Mono: 65536 - (256000000/sample_rate) - Stereo: 65536 - (25600000/(2*sample_rate)) - 02 Pack - 03 Mode: 0 = mono - 1 = stereo - - - Marker# -- Driver keeps the most recent marker in a status byte - Count# -- Number of repetitions + 1 - Count# may be 1 to FFFE for 0 - FFFD repetitions - or FFFF for endless repetitions - Sample Rate -- SR byte = 256-(1000000/sample_rate) - Length of silence -- in units of sampling cycle - Compression Type -- of voice data - 8-bits = 0 - 4-bits = 1 - 2.6-bits = 2 - 2-bits = 3 - Multi DAC = 3+(# of channels) [interesting-- - this isn't in the developer's manual] diff --git a/16/PCGPE10/WAV.TXT b/16/PCGPE10/WAV.TXT deleted file mode 100644 index ce9ec12f..00000000 --- a/16/PCGPE10/WAV.TXT +++ /dev/null @@ -1,112 +0,0 @@ - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ The Microsoft Multimedia WAV Sound File Format ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - Written for the PC-GPE by Mark Feldman - e-mail address : u914097@student.canberra.edu.au - myndale@cairo.anu.edu.au - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ THIS FILE MAY NOT BE DISTRIBUTED ³ - ³ SEPARATE TO THE ENTIRE PC-GPE COLLECTION. ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Disclaimer ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ - -I assume no responsibility whatsoever for any effect that this file, the -information contained therein or the use thereof has on you, your sanity, -computer, spouse, children, pets or anything else related to you or your -existance. No warranty is provided nor implied with this information. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ The RIFF File Format ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -WAV files use the RIFF file structure. The RIFF format was designed -for multi-media purposes. A RIFF files consists of a number of "chunks": - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Byte Length ³ - ³ Offset Name (in bytes) Description ³ - ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ - ³ 00h rID 4h Contains the characters "RIFF" ³ - ³ 04h rLen 4h The length of the data in the next chunk ³ - ³ 08h rData rLen The data chunk ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ The WAVE Form Definition ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The rData chunk in a WAV file is split up into several further chunks: - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ rData ³ - ³ Byte Length ³ - ³ Offset Name (in bytes) Description ³ - ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ - ³ 00h wID 4h Contains the characters "WAVE" ³ - ³ 04h Format 14h Contains data which specifies the format ³ - ³ Chunk of the Data in the Data Chunk ³ - ³ 18h WAVE Data ? Contains the WAV audio data ³ - ³ Chunk ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ The Format Chunk ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The Format Chunk is split up into these fields: - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ -³ Format ³ -³ Chunk Length ³ -³ Offset Name (in bytes) Description ³ -ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ -³ 00h fId 4 Contains the characters "fmt" ³ -³ 04h fLen 4 Length of data in the format chunk ³ -³ 08h wFormatTag 2 * ³ -³ 0Ah nChannels 2 Number of channels, 1=mono, 2=stereo ³ -³ 0Ch nSamplesPerSec 2 Playback frequency ³ -³ 0Eh nAvgBytesPerSec 2 ** ³ -³ 10h nBlockAlign 2 *** ³ -³ 12h FormatSpecific 2 Format specific data area ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -* The wFormatTag specifies the wave format, eg 1 = Pulse Code Modulation - (or in plain english, regular 8 bit sampled uncompressed sound) - -** Indicates the average number of bytes a second the data should be - transferred at = nChannels * nSamplesPerSec * (nBitsPerSample / 8) - -*** Indicates the block alignment of the data in the data chunk. Software - needs to process a multiplt of nBlockAlign at a time. - nBlockAlign = nChannels * (nBitsPerSample / 8) - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ The Data Chunk ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -The Data Chunk is split up into these fields: - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ -³ Data ³ -³ Chunk Length ³ -³ Offset Name (in bytes) Description ³ -ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ -³ 00h dId 4 Contains the characters "data" ³ -³ 02h dLen 4 Length of data in the dData field ³ -³ 00h dData dLen The actual waveform data ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -In mono 8-bit files each byte represents one sample. In stereo 8-bit files -two bytes are stored for each sample, the first byte is the left channel -value, the next is the right channel value. diff --git a/16/PCGPE10/WORMIE.PAS b/16/PCGPE10/WORMIE.PAS deleted file mode 100644 index db1528c9..00000000 --- a/16/PCGPE10/WORMIE.PAS +++ /dev/null @@ -1,307 +0,0 @@ -{$R-} -{$X+} -Program T_holic; - -USES - Crt; - -CONST - Vga : Word = $a000; - - Block : Array[1..40,1..40] of Byte = ( - - (0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0), - (0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0), - (0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0), - (0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0), - (0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0), - (0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0), - (0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0), - (0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0), - (0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0), - (0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0), - (1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1), - (1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1), - (1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1), - (1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1), - (1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1), - (1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1), - (1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1), - (1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1), - (1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1), - (1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1), - (1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1), - (1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1), - (1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1), - (1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1), - (1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1), - (1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1), - (1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1), - (1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1), - (1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1), - (1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1), - (0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0), - (0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0), - (0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0), - (0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0), - (0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0), - (0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0), - (0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0), - (0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0), - (0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0), - (0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0) - ); - - -VAR - WholePal : Array[1..256,1..3] of Byte; - CurX,CurY,CurCol : Word; - right,down:Boolean; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure SetMCGA; { This procedure gets you into 320x200x256 mode. } -BEGIN - asm - mov ax,0013h - int 10h - end; -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure SetText; { This procedure returns you to text mode. } -BEGIN - asm - mov ax,0003h - int 10h - end; -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -procedure WaitRetrace; assembler; -label - l1, l2; -asm - mov dx,3DAh -l1: - in al,dx - and al,08h - jnz l1 -l2: - in al,dx - and al,08h - jz l2 -end; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure GetPal(ColorNo : Byte; Var R,G,B : Byte); - { This reads the values of the Red, Green and Blue values of a certain - color and returns them to you. } -Begin - Port[$3c7] := ColorNo; - R := Port[$3c9]; - G := Port[$3c9]; - B := Port[$3c9]; -End; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure Pal(ColorNo : Byte; R,G,B : Byte); - { This sets the Red, Green and Blue values of a certain color } -Begin - Port[$3c8] := ColorNo; - Port[$3c9] := R; - Port[$3c9] := G; - Port[$3c9] := B; -End; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure FadeDown; - { This procedure fades the screen out to black. } -VAR loop1,loop2:integer; - Tmp : Array [1..3] of byte; - { This is temporary storage for the values of a color } -BEGIN - For loop1:=1 to 64 do BEGIN - WaitRetrace; - For loop2:=1 to 255 do BEGIN - Getpal (loop2,Tmp[1],Tmp[2],Tmp[3]); - If Tmp[1]>0 then dec (Tmp[1]); - If Tmp[2]>0 then dec (Tmp[2]); - If Tmp[3]>0 then dec (Tmp[3]); - { If the Red, Green or Blue values of color loop2 are not yet zero, - then, decrease them by one. } - Pal (loop2,Tmp[1],Tmp[2],Tmp[3]); - { Set the new, altered pallette color. } - END; - END; -END; - - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure Putpixel (X,Y : Integer; Col : Byte); - { This puts a pixel on the screen by writing directly to memory. } -BEGIN - Mem [VGA:X+(Y*320)]:=Col; -END; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure CunninglyManipulatePalette; - { This moves up the pallette by one so that the color of the block - being put down is always the same } -Var - Tmp : Array[1..3] of byte; - loop : Byte; -Begin - Move(WholePal[210],Tmp[1],3); { Save Last Colour } - Move(WholePal[1],WholePal[2],209*3); { Move Rest Up one } - Move(Tmp,WholePal[1],3); { Put Last Colour to First pos } - For Loop := 1 to 210 do - Pal(Loop,WholePal[Loop,1],WholePal[Loop,2],WholePal[Loop,3]); -End; - - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure PreparePalette; - { This sets up the palette to have pretty gradients in it for our use } -Var - Loop : Byte; -Begin - For loop := 1 to 30 do BEGIN - Wholepal [loop,1]:=loop*2; - Wholepal [loop,2]:=0; - Wholepal [loop,3]:=0; - END; - - For loop := 31 to 60 do BEGIN - Wholepal [loop,1]:=0; - Wholepal [loop,2]:=loop*2-30; - Wholepal [loop,3]:=0; - END; - - - For loop := 61 to 90 do BEGIN - Wholepal [loop,1]:=0; - Wholepal [loop,2]:=0; - Wholepal [loop,3]:=loop*2-30; - END; - - For loop := 91 to 120 do BEGIN - Wholepal [loop,1]:=loop*2-30; - Wholepal [loop,2]:=loop*2-30; - Wholepal [loop,3]:=loop*2-30; - END; - - For loop := 121 to 150 do BEGIN - Wholepal [loop,1]:=loop*2-30; - Wholepal [loop,2]:=loop*2-30; - Wholepal [loop,3]:=0; - END; - - For loop := 151 to 180 do BEGIN - Wholepal [loop,1]:=0; - Wholepal [loop,2]:=loop*2-30; - Wholepal [loop,3]:=loop*2-30; - END; - - For loop := 181 to 210 do BEGIN - Wholepal [loop,1]:=loop*2-30; - Wholepal [loop,2]:=0; - Wholepal [loop,3]:=loop*2-30; - END; -End; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure IngeniouslyMoveCurPos; - { This moves the position of the block to put down around the screen } -Begin - CurCol := (CurCol) mod 210 + 1; { This Does Work } - if right then CurX := CurX + 4 else CurX := CurX - 3; - if down then CurY := CurY + 3 else CurY := CurY - 2; - - If CurX > 250 then right:= FALSE; - If CurY > 150 then down := FALSE; - - If CurX < 10 then right := TRUE; - If CurY < 10 then down := TRUE; - -End; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure DrawBlock; - { This draws the block onto the VGA screen } -Var - Xloop,Yloop : Integer; -Begin - For XLoop := 1 to 40 do - For Yloop := 1 to 40 do - If block[Yloop,Xloop] = 1 then - PutPixel(CurX+Xloop,CurY+Yloop,CurCol); -End; - - -{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ} -Procedure StartSnakiepoo; - { This is the proc where we set things up & set em in motion! ;-) } -Begin - CurX := 100; - CurY := 100; - CurCol := 1; - PreparePalette; - Repeat - DrawBlock; - CunninglyManipulatePalette; - IngeniouslyMoveCurPos; - Until Keypressed; - fadedown; - Readkey; -End; - -Begin - ClrScr; - Writeln ('Hi there! This is a small little routine that Livewire'); - Writeln ('and Denthor of ASPHYXIA threw together during lunch break'); - Writeln ('at varsity. We first saw this routine in the T-Holic demo'); - Writeln ('by Extreme a few months back, and decided to write it as'); - Writeln ('a supliment to the ASPHYXIA VGA Demo Trainer Series on the'); - Writeln ('MailBox BBS here in Durban. '); - Writeln; - Writeln ('The routine consists of a wormy type thing bouncing around'); - Writeln ('the screen, and looks quite effective. The code is'); - Writeln ('documented, and the concept behind it is so easy everyone'); - Writeln ('should be able to understand it. '); - Writeln; - Writeln ('The Pal routines, setmcga, waitretrace etc. are taken'); - Writeln ('directly from the ASPHYXIA Trainer Series, and you should'); - Writeln ('read those to understand how they work.'); - Writeln; - Writeln ('See the Trainer Series for how to get into contact with us.'); - Writeln; Writeln; - Writeln ('Hit any key to continue .... '); - Readkey; - SetMCGA; - StartSnakiepoo; - SetText; - Writeln ('All done. This was a sample routine written by ASPHYXIA.'); - Writeln ('Please read the ASPHYXIA Demo Trainer Series on the MailBox BBS,'); - Writeln ('written by Denthor. You may reach DENTHOR under the name of GRANT'); - Writeln ('SMITH on the MailBox BBS, or leave a message to ASPHYXIA on the'); - Writeln ('ASPHYXIA BBS. Get the numbers from Roblist, or write to :'); - Writeln (' Grant Smith'); - Writeln (' P.O. Box 270'); - Writeln (' Kloof'); - Writeln (' 3640'); - Writeln ('We hope to hear from you soon!'); - Writeln; Writeln; - Write ('Hit any key to exit ...'); - Readkey; -End. \ No newline at end of file diff --git a/16/PCGPE10/XMS30.TXT b/16/PCGPE10/XMS30.TXT deleted file mode 100644 index 09698de5..00000000 --- a/16/PCGPE10/XMS30.TXT +++ /dev/null @@ -1,1079 +0,0 @@ -eXtended Memory Specification (XMS), ver 3.0 - - -January 1991 - - -Copyright (c) 1988, Microsoft Corporation, Lotus Development -Corporation, Intel Corporation, and AST Research, Inc. - -Microsoft Corporation -Box 97017 - -One Microsoft Way -Redmond, WA 98073 - -LOTUS (r) -INTEL (r) -MICROSOFT (r) -AST (r) Research - -This specification was jointly developed by Microsoft Corporation, -Lotus Development Corporation, Intel Corporation,and AST Research, -Inc. Although it has been released into the public domain and is not -confidential or proprietary, the specification is still the copyright -and property of Microsoft Corporation, Lotus Development Corporation, -Intel Corporation, and AST Research, Inc. - -Disclaimer of Warranty - -MICROSOFT CORPORATION, LOTUS DEVELOPMENT CORPORATION, INTEL -CORPORATION, AND AST RESEARCH, INC., EXCLUDE ANY AND ALL IMPLIED -WARRANTIES, INCLUDING WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE. NEITHER MICROSOFT NOR LOTUS NOR INTEL NOR AST -RESEARCH MAKE ANY WARRANTY OF REPRESENTATION, EITHER EXPRESS OR -IMPLIED, WITH RESPECT TO THIS SPECIFICATION, ITS QUALITY, -PERFORMANCE, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. -NEITHER MICROSOFT NOR LOTUS NOR INTEL NOR AST RESEARCH SHALL HAVE ANY -LIABILITY FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING -OUT OF OR RESULTING FROM THE USE OR MODIFICATION OF THIS -SPECIFICATION. - -This specification uses the following trademarks: - -Intel is a registered trademark of Intel Corporation, Microsoft is a -registered trademark of Microsoft Corporation, Lotus is a registered -trademark of Lotus Development Corporation, and AST is a registered -trademark of AST Research, Inc. - - - -Extended Memory Specification - - The purpose of this document is to define the Extended Memory Specification (XMS) version 3.00 for MS-DOS. XMS allows DOS programs to utilize additional memory found in Intel's 80286 and 80386 based machines in a consistent, machine independent manner. With some restrictions, XMS adds almost 64K to the 640K which DOS programs can access directly. Depending on available hardware, XMS may provide even more memory to DOS programs. XMS also provides DOS programs with a standard method of storing data in extended memory. - - To be considered fully XMS 3.0 compliant, all calls except those associated with UMB support must be implemented. UMB functions 10h, 11h and 12h are optional for XMS 3.0 and may return the Function Not Implemented error code, 80h. - -DEFINITIONS: ------------- - -Extended Memory: -Memory in 80286 and 80386 based machines which is located above the 1MB address boundary. - -High Memory Area (HMA): -The first 64K of extended memory. The High Memory Area is unique because code can be executed in it while in real mode. The HMA officially starts at FFFF:10h and ends at FFFF:FFFFh making it 64K-16 bytes in length. - -Upper Memory Blocks (UMBs): -Blocks of memory available on some 80x86 based machines which are located between DOS's 640K limit and the 1MB address boundary. The number, size, and location of these blocks vary widely depending upon the types of hardware adapter cards installed in the machine. - -Extended Memory Blocks (EMBs): -Blocks of extended memory located above the HMA which can only be used for data storage. - -A20 Line: -The 21st address line of 80x86 CPUs. Enabling the A20 line allows access to the HMA. - -XMM: -An Extended Memory Manager. A DOS device driver which implements XMS. XMMs are machine specific but allow programs to use extended memory in a machine-independent manner. - -HIMEM.SYS: -The Extended Memory Manager currently being distributed by Microsoft. - - - -Helpful Diagram: - -| | Top of Memory -| | -| | -| /\ | -| /||\ | -| || | -| || | -| | -| | -| | -| Possible Extended Memory Block | -| | -| | -| | -| || | -| || | -| \||/ | -| \/ | -| | -| | -| Other EMBs could exist above 1088K (1MB+64K) | -| | -| | -| | 1088K -| | -| | -| The High Memory Area | -| | -| | -| | 1024K or 1MB -| | -| /\ | -| /||\ | -| || | -| || | -| | -| | -| Possible Upper Memory Block | -| | -| || | -| || | -| \||/ | -| \/ | -| | -| Other UMBs could exist between 640K and 1MB | -| | -| | 640K - -| | -| | -| | -| Conventional or DOS Memory | -| | -| | -| | -| | -| | -+ + 0K - -DRIVER INSTALLATION: --------------------- - - An XMS driver is installed by including a DEVICE= statement in the -machine's CONFIG.SYS file. It must be installed prior to any other -devices or TSRs which use it. An optional parameter after the driver's -name (suggested name "/HMAMIN=") indicates the minimum amount of space in -the HMA a program can use. Programs which use less than the minimum will -not be placed in the HMA. See "Prioritizing HMA Usage" below for more -information. A second optional parameter (suggested name "/NUMHANDLES=") -allows users to specify the maximum number of extended memory blocks which -may be allocated at any time. - - NOTE: XMS requires DOS 3.00 or above. - - -THE PROGRAMMING API: --------------------- - - The XMS API Functions are accessed via the XMS driver's Control Function. -The address of the Control Function is determined via INT 2Fh. First, a -program should determine if an XMS driver is installed. Next, it should -retrieve the address of the driver's Control Function. It can then use any -of the available XMS functions. The functions are divided into several -groups: - - 1. Driver Information Functions (0h) - 2. HMA Management Functions (1h-2h) - 3. A20 Management Functions (3h-7h) - 4. Extended Memory Management Functions (8h-Fh) - 5. Upper Memory Management Functions (10h-11h) - - -DETERMINING IF AN XMS DRIVER IS INSTALLED: ------------------------------------------- - - The recommended way of determining if an XMS driver is installed is to -set AH=43h and AL=00h and then execute INT 2Fh. If an XMS driver is available, -80h will be returned in AL. - - Example: - ; Is an XMS driver installed? - mov ax,4300h - int 2Fh - cmp al,80h - jne NoXMSDriver - - -CALLING THE API FUNCTIONS: --------------------------- - - Programs can execute INT 2Fh with AH=43h and AL=10h to obtain the address -of the driver's control function. The address is returned in ES:BX. This -function is called to access all of the XMS functions. It should be called -with AH set to the number of the API function requested. The API function -will put a success code of 0001h or 0000h in AX. If the function succeeded -(AX=0001h), additional information may be passed back in BX and DX. If the -function failed (AX=0000h), an error code may be returned in BL. Valid -error codes have their high bit set. Developers should keep in mind that -some of the XMS API functions may not be implemented by all drivers and will -return failure in all cases. - - Example: - ; Get the address of the driver's control function - mov ax,4310h - int 2Fh - mov word ptr [XMSControl],bx ; XMSControl is a DWORD - mov word ptr [XMSControl+2],es - - ; Get the XMS driver's version number - mov ah,00h - call [XMSControl] ; Get XMS Version Number - - NOTE: Programs should make sure that at least 256 bytes of stack space - is available before calling XMS API functions. - - -API FUNCTION DESCRIPTIONS: --------------------------- - - The following XMS API functions are available: - - 0h) Get XMS Version Number - 1h) Request High Memory Area - 2h) Release High Memory Area - 3h) Global Enable A20 - 4h) Global Disable A20 - 5h) Local Enable A20 - 6h) Local Disable A20 - 7h) Query A20 - 8h) Query Free Extended Memory - 9h) Allocate Extended Memory Block - Ah) Free Extended Memory Block - Bh) Move Extended Memory Block - Ch) Lock Extended Memory Block - Dh) Unlock Extended Memory Block - Eh) Get Handle Information - Fh) Reallocate Extended Memory Block - 10h) Request Upper Memory Block - 11h) Release Upper Memory Block - 12h) Realloc Upper Memory Block - 88h) Query any Free Extended Memory - 89h) Allocate any Extended Memory Block - 8Eh) Get Extended EMB Handle - 8Fh) Realloc any Extended Memory - -Each is described below. - - -Get XMS Version Number (Function 00h): --------------------------------------- - - ARGS: AH = 00h - RETS: AX = XMS version number - BX = Driver internal revision number - DX = 0001h if the HMA exists, 0000h otherwise - ERRS: None - - This function returns with AX equal to a 16-bit BCD number representing -the revision of the DOS Extended Memory Specification which the driver -implements (e.g. AX=0235h would mean that the driver implemented XMS version -2.35). BX is set equal to the driver's internal revision number mainly for -debugging purposes. DX indicates the existence of the HMA (not its -availability) and is intended mainly for installation programs. - - NOTE: This document defines version 3.00 of the specification. - - -Request High Memory Area (Function 01h): ----------------------------------------- - - ARGS: AH = 01h - If the caller is a TSR or device driver, - DX = Space needed in the HMA by the caller in bytes - If the caller is an application program, - DX = FFFFh - RETS: AX = 0001h if the HMA is assigned to the caller, 0000h otherwise - ERRS: BL = 80h if the function is not implemented - BL = 81h if a VDISK device is detected - BL = 90h if the HMA does not exist - BL = 91h if the HMA is already in use - BL = 92h if DX is less than the /HMAMIN= parameter - - This function attempts to reserve the 64K-16 byte high memory area for -the caller. If the HMA is currently unused, the caller's size parameter is -compared to the /HMAMIN= parameter on the driver's command line. If the -value passed by the caller is greater than or equal to the amount specified -by the driver's parameter, the request succeeds. This provides the ability -to ensure that programs which use the HMA efficiently have priority over -those which do not. - - NOTE: See the sections "Prioritizing HMA Usage" and "High Memory Area - Restrictions" below for more information. - - -Release High Memory Area (Function 02h): ----------------------------------------- - - ARGS: AH = 02h - RETS: AX = 0001h if the HMA is successfully released, 0000h otherwise - ERRS: BL = 80h if the function is not implemented - BL = 81h if a VDISK device is detected - BL = 90h if the HMA does not exist - BL = 93h if the HMA was not allocated - - This function releases the high memory area and allows other programs to -use it. Programs which allocate the HMA must release it before exiting. -When the HMA has been released, any code or data stored in it becomes invalid -and should not be accessed. - - -Global Enable A20 (Function 03h): ---------------------------------- - - ARGS: AH = 03h - RETS: AX = 0001h if the A20 line is enabled, 0000h otherwise - ERRS: BL = 80h if the function is not implemented - BL = 81h if a VDISK device is detected - BL = 82h if an A20 error occurs - - This function attempts to enable the A20 line. It should only be used -by programs which have control of the HMA. The A20 line should be turned -off via Function 04h (Global Disable A20) before a program releases control -of the system. - - NOTE: On many machines, toggling the A20 line is a relatively slow - operation. - - -Global Disable A20 (Function 04h): ----------------------------------- - - ARGS: AH = 04h - RETS: AX = 0001h if the A20 line is disabled, 0000h otherwise - ERRS: BL = 80h if the function is not implemented - BL = 81h if a VDISK device is detected - BL = 82h if an A20 error occurs - BL = 94h if the A20 line is still enabled - - This function attempts to disable the A20 line. It should only be used -by programs which have control of the HMA. The A20 line should be disabled -before a program releases control of the system. - - NOTE: On many machines, toggling the A20 line is a relatively slow - operation. - - -Local Enable A20 (Function 05h): --------------------------------- - - ARGS: AH = 05h - RETS: AX = 0001h if the A20 line is enabled, 0000h otherwise - ERRS: BL = 80h if the function is not implemented - BL = 81h if a VDISK device is detected - BL = 82h if an A20 error occurs - - This function attempts to enable the A20 line. It should only be used -by programs which need direct access to extended memory. Programs which use -this function should call Function 06h (Local Disable A20) before releasing -control of the system. - - NOTE: On many machines, toggling the A20 line is a relatively slow - operation. - - -Local Disable A20 (Function 06h): ---------------------------------- - - ARGS: AH = 06h - RETS: AX = 0001h if the function succeeds, 0000h otherwise - ERRS: BL = 80h if the function is not implemented - BL = 81h if a VDISK device is detected - BL = 82h if an A20 error occurs - BL = 94h if the A20 line is still enabled - - This function cancels a previous call to Function 05h (Local Enable -A20). It should only be used by programs which need direct access to -extended memory. Previous calls to Function 05h must be canceled before -releasing control of the system. - - NOTE: On many machines, toggling the A20 line is a relatively slow - operation. - - -Query A20 (Function 07h): -------------------------- - - ARGS: AH = 07h - RETS: AX = 0001h if the A20 line is physically enabled, 0000h otherwise - ERRS: BL = 00h if the function succeeds - BL = 80h if the function is not implemented - BL = 81h if a VDISK device is detected - - This function checks to see if the A20 line is physically enabled. It -does this in a hardware independent manner by seeing if "memory wrap" occurs. - - -Query Free Extended Memory (Function 08h): ------------------------------------------- - - ARGS: AH = 08h - RETS: AX = Size of the largest free extended memory block in K-bytes - DX = Total amount of free extended memory in K-bytes - ERRS: BL = 80h if the function is not implemented - BL = 81h if a VDISK device is detected - BL = A0h if all extended memory is allocated - - This function returns the size of the largest available extended memory -block in the system. - - NOTE: The 64K HMA is not included in the returned value even if it is - not in use. - - -Allocate Extended Memory Block (Function 09h): ----------------------------------------------- - - ARGS: AH = 09h - DX = Amount of extended memory being requested in K-bytes - RETS: AX = 0001h if the block is allocated, 0000h otherwise - DX = 16-bit handle to the allocated block - ERRS: BL = 80h if the function is not implemented - BL = 81h if a VDISK device is detected - BL = A0h if all available extended memory is allocated - BL = A1h if all available extended memory handles are in use - - This function attempts to allocate a block of the given size out of the -pool of free extended memory. If a block is available, it is reserved -for the caller and a 16-bit handle to that block is returned. The handle -should be used in all subsequent extended memory calls. If no memory was -allocated, the returned handle is null. - - NOTE: Extended memory handles are scarce resources. Programs should - try to allocate as few as possible at any one time. When all - of a driver's handles are in use, any free extended memory is - unavailable. - - - -Free Extended Memory Block (Function 0Ah): ------------------------------------------- - - ARGS: AH = 0Ah - DX = Handle to the allocated block which should be freed - RETS: AX = 0001h if the block is successfully freed, 0000h otherwise - ERRS: BL = 80h if the function is not implemented - BL = 81h if a VDISK device is detected - BL = A2h if the handle is invalid - BL = ABh if the handle is locked - - This function frees a block of extended memory which was previously -allocated using Function 09h (Allocate Extended Memory Block). Programs -which allocate extended memory should free their memory blocks before -exiting. When an extended memory buffer is freed, its handle and all data -stored in it become invalid and should not be accessed. - - -Move Extended Memory Block (Function 0Bh): ------------------------------------------- - - ARGS: AH = 0Bh - DS:SI = Pointer to an Extended Memory Move Structure (see below) - RETS: AX = 0001h if the move is successful, 0000h otherwise - ERRS: BL = 80h if the function is not implemented - BL = 81h if a VDISK device is detected - BL = 82h if an A20 error occurs - BL = A3h if the SourceHandle is invalid - BL = A4h if the SourceOffset is invalid - BL = A5h if the DestHandle is invalid - BL = A6h if the DestOffset is invalid - BL = A7h if the Length is invalid - BL = A8h if the move has an invalid overlap - BL = A9h if a parity error occurs - - Extended Memory Move Structure Definition: - - ExtMemMoveStruct struc - Length dd ? ; 32-bit number of bytes to transfer - SourceHandle dw ? ; Handle of source block - SourceOffset dd ? ; 32-bit offset into source - DestHandle dw ? ; Handle of destination block - DestOffset dd ? ; 32-bit offset into destination block - ExtMemMoveStruct ends - - This function attempts to transfer a block of data from one location to -another. It is primarily intended for moving blocks of data between -conventional memory and extended memory, however it can be used for moving -blocks within conventional memory and within extended memory. - - NOTE: If SourceHandle is set to 0000h, the SourceOffset is interpreted - as a standard segment:offset pair which refers to memory that is - directly accessible by the processor. The segment:offset pair - is stored in Intel DWORD notation. The same is true for DestHandle - and DestOffset. - - SourceHandle and DestHandle do not have to refer to locked memory - blocks. - - Length must be even. Although not required, WORD-aligned moves - can be significantly faster on most machines. DWORD aligned move - can be even faster on 80386 machines. - - If the source and destination blocks overlap, only forward moves - (i.e. where the source base is less than the destination base) are - guaranteed to work properly. - - Programs should not enable the A20 line before calling this - function. The state of the A20 line is preserved. - - This function is guaranteed to provide a reasonable number of - interrupt windows during long transfers. - - -Lock Extended Memory Block (Function 0Ch): ------------------------------------------- - - ARGS: AH = 0Ch - DX = Extended memory block handle to lock - RETS: AX = 0001h if the block is locked, 0000h otherwise - DX:BX = 32-bit physical address of the locked block - ERRS: BL = 80h if the function is not implemented - BL = 81h if a VDISK device is detected - BL = A2h if the handle is invalid - BL = ACh if the block's lock count overflows - BL = ADh if the lock fails - - This function locks an extended memory block and returns its base -address as a 32-bit physical address. Locked memory blocks are guaranteed not -to move. The 32-bit pointer is only valid while the block is locked. -Locked blocks should be unlocked as soon as possible. - - NOTE: A block does not have to be locked before using Function 0Bh (Move - Extended Memory Block). - - "Lock counts" are maintained for EMBs. - - - -Unlock Extended Memory Block (Function 0Dh): --------------------------------------------- - - ARGS: AH = 0Dh - DX = Extended memory block handle to unlock - RETS: AX = 0001h if the block is unlocked, 0000h otherwise - ERRS: BL = 80h if the function is not implemented - BL = 81h if a VDISK device is detected - BL = A2h if the handle is invalid - BL = AAh if the block is not locked - - This function unlocks a locked extended memory block. Any 32-bit -pointers into the block become invalid and should no longer be used. - - -Get EMB Handle Information (Function 0Eh): ------------------------------------------- - - ARGS: AH = 0Eh - DX = Extended memory block handle - RETS: AX = 0001h if the block's information is found, 0000h otherwise - BH = The block's lock count - BL = Number of free EMB handles in the system - DX = The block's length in K-bytes - ERRS: BL = 80h if the function is not implemented - BL = 81h if a VDISK device is detected - BL = A2h if the handle is invalid - - This function returns additional information about an extended memory -block to the caller. - - NOTE: To get the block's base address, use Function 0Ch (Lock Extended - Memory Block). - - -Reallocate Extended Memory Block (Function 0Fh): ------------------------------------------------- - - ARGS: AH = 0Fh - BX = New size for the extended memory block in K-bytes - DX = Unlocked extended memory block handle to reallocate - RETS: AX = 0001h if the block is reallocated, 0000h otherwise - ERRS: BL = 80h if the function is not implemented - BL = 81h if a VDISK device is detected - BL = A0h if all available extended memory is allocated - BL = A1h if all available extended memory handles are in use - BL = A2h if the handle is invalid - BL = ABh if the block is locked - - This function attempts to reallocate an unlocked extended memory block -so that it becomes the newly specified size. If the new size is smaller -than the old block's size, all data at the upper end of the old block is -lost. - - -Request Upper Memory Block (Function 10h): ------------------------------------------- - - ARGS: AH = 10h - DX = Size of requested memory block in paragraphs - RETS: AX = 0001h if the request is granted, 0000h otherwise - BX = Segment number of the upper memory block - If the request is granted, - DX = Actual size of the allocated block in paragraphs - otherwise, - DX = Size of the largest available UMB in paragraphs - ERRS: BL = 80h if the function is not implemented - BL = B0h if a smaller UMB is available - BL = B1h if no UMBs are available - - This function attempts to allocate an upper memory block to the caller. -If the function fails, the size of the largest free UMB is returned in DX. - - NOTE: By definition UMBs are located below the 1MB address boundary. - The A20 Line does not need to be enabled before accessing an - allocated UMB. - - UMBs are paragraph aligned. - - To determine the size of the largest available UMB, attempt to - allocate one with a size of FFFFh. - - UMBs are unaffected by EMS calls. - - -Release Upper Memory Block (Function 11h): ------------------------------------------- - - ARGS: AH = 11h - DX = Segment number of the upper memory block - RETS: AX = 0001h if the block was released, 0000h otherwise - ERRS: BL = 80h if the function is not implemented - BL = B2h if the UMB segment number is invalid - - This function frees a previously allocated upper memory block. When an -UMB has been released, any code or data stored in it becomes invalid and -should not be accessed. - - - - -Reallocate Upper Memory Block (Function 12h) - - ARGS: - AH = 12h - BX = New size for UMB in paragraphs - DX = Segment number of the UMB to reallocate - RETS: - AX = 1 if the block was reallocated, 0 otherwise - ERRS: - BL = 80h if the function is not implemented - BL = B0h if no UMB large enough to satisfy the request is available. - In this event, DX is returned with the size of the largest UMB that is available. - BL = B2h if the UMB segment number is invalid - -This function attempts to reallocate an Upper Memory Block to a newly specified size. If the new size is smaller than the old block's size, all data at the upper end of the block is lost. - - - -Super Extended Memory Support - -These changes are intended to provide support for extended memory pools up to 4 Gb in size. The current XMS API, since it uses 16-bit values to specify block sizes in Kb, is limited to 64 Mb maximum block size. Future machines are expected to support memory above 64 MB. - -This support is implemented in the form of extensions to existing functions, rather than entirely new entry points, to allow for more efficient implementations. - -Programs should generally use the existing functions, instead of these extended ones, unless they have an explicit need to deal with memory above 64 Mb. - - -Query Any Free Extended Memory (Function 88h) - - Entry: - AH = 88h - Exit: - EAX = Size of largest free extended memory block in Kb. - BL = 0 if no error occurs, otherwise it takes an error code. - ECX = Highest ending address of any memory block. - EDX = Total amount of free memory in Kb. - Errors: - BL = 80h if the function is not implemented. - BL = 81h if a VDISK device is detected. - BL = A0h if all extended memory is allocated. - -This function uses 32-bit values to return the size of available memory, thus allowing returns up to 4GByte. Additionally, it returns the highest known physical memory address, that is, the physical address of the last byte of memory. There may be discontinuities in the memory map below this address. - -The memory pool reported on is the same as that reported on by the existing Query Free Extended Memory function. If the highest memory address is not more than 64 Mb, then these two functions will return the same results. - -Because of its reliance on 32-bit registers, this function is only available on 80386 and higher processors. XMS drivers on 80286 machines should return error code 80h if this function is called. - -If error code 81h is returned, the value in ECX will still be valid. If error code A0h is returned, EAX and EDX will be 0, and ECX will still be valid. - - -Allocate Any Extended Memory (Function 89h) - - Entry: - AH = 89h - EDX = Amount of extended memory requested, in Kb. - Exit: - AX = 1 if the block is allocated, 0 if not - DX = Handle to allocated block. - Errors: - BL = 80h if the function is not implemented. - BL = 81h if a VDISK device is detected. - BL = A0h if all available extended memory is allocated. - BL = A1h if all available extended memory handles are in use. - -This function is similar to the existing Allocate Extended Memory, except that it uses a 32-bit instead of a 16-bit value to specify the amount of memory requested. It allocates from the same memory and handle pool as the current function. Since it requires a 32-bit register, this function can be supported only on 80386 and higher processors, and XMS drivers on 80286 machines should return error code 80h. - - -Get Extended EMB Handle Information (Function 8Eh) - - Entry: - AH = 8Eh - DX = Extended memory block handle. - Exit: - AX = 1 if the block's information is found, 0 if not - BH = Block lock count - CX = Number of free EMB handles in the system - EDX = Block's length in Kb. - Errors: - BL = 80h if the function is not implemented. - BL = 81h if a VDISK device is detected. - BL = A2h if the handle is invalid. - -This function is similar to the Get EMB Handle Information function. Since it uses a 32-bit register to report the block size, it can be used to get information on blocks larger than 64 Mb. It also uses a 16-bit instead of 8-bit register to report the number of free handles, allowing the handle pool to be extended beyond 256 entries. - -Because of its reliance on a 32-bit register, this function is available on 80386 and higher processors. XMS drivers on 80286 machines should return error code 80h if this function is called. - - -Reallocate Any Extended Memory (Function 8Fh) - - Entry: - AH = 8Fh - EBX = New size for extended memory block, in Kb. - DX = Unlocked handle for memory block to be resized. - Exit: - AX = 1 if the block is reallocated, 0 if not - Errors: - BL = 80h if the function is not implemented. - BL = 81h if a VDISK device is detected. - BL = A0h if all available extended memory is allocated. - BL = A1h if all available extended memory handles are in use. - BL = A2h if the handle is invalid. - BL = ABh if the block is locked. - -This function is similar to the existing Reallocate Extended Memory, except that it uses a 32-bit instead of a 16-bit value to specify the amount of memory requested. It allocates from the same memory and handle pool as the current function. Since it requires a 32-bit register, this function can be supported only on 80386 and higher processors, and XMS drivers on 80286 machines should return error code 80h. - - - - -PRIORITIZING HMA USAGE: ------------------------ - - For DOS users to receive the maximum benefit from the High Memory Area, -programs which use the HMA must store as much of their resident code in it as -is possible. It is very important that developers realize that the HMA is -allocated as a single unit. - - For example, a TSR program which grabs the HMA and puts 10K of code into -it may prevent a later TSR from putting 62K into the HMA. Obviously, regular -DOS programs would have more memory available to them below the 640K line if -the 62K TSR was moved into the HMA instead of the 10K one. - - The first method for dealing with conflicts such as this is to require -programs which use the HMA to provide a command line option for disabling -this feature. It is crucial that TSRs which do not make full use of the HMA -provide such a switch on their own command line (suggested name "/NOHMA"). - - The second method for optimizing HMA usage is through the /HMAMIN= -parameter on the XMS device driver line. The number after the parameter -is defined to be the minimum amount of HMA space (in K-bytes) used by any -driver or TSR. For example, if "DEVICE=HIMEM.SYS /HMAMIN=48" is in a -user's CONFIG.SYS file, only programs which request at least 48K would be -allowed to allocate the HMA. This number can be adjusted either by -installation programs or by the user himself. If this parameter is not -specified, the default value of 0 is used causing the HMA to be allocated -on a first come, first served basis. - - Note that this problem does not impact application programs. If the HMA -is available when an application program starts, the application is free to -use as much or as little of the HMA as it wants. For this reason, -applications should pass FFFFh in DX when calling Function 01h. - - - -HIGH MEMORY AREA RESTRICTIONS: ------------------------------- - -- Far pointers to data located in the HMA cannot be passed to DOS. DOS - normalizes any pointer which is passed into it. This will cause data - addresses in the HMA to be invalidated. - -- Disk I/O directly into the HMA (via DOS, INT 13h, or otherwise) is not - recommended. - -- Programs, especially drivers and TSRs, which use the HMA *MUST* use - as much of it as possible. If a driver or TSR is unable to use at - least 90% of the available HMA (typically ~58K), they must provide - a command line switch for overriding HMA usage. This will allow - the user to configure his machine for optimum use of the HMA. - -- Device drivers and TSRs cannot leave the A20 line permanently turned - on. Several applications rely on 1MB memory wrap and will overwrite the - HMA if the A20 line is left enabled potentially causing a system crash. - -- Interrupt vectors must not point into the HMA. This is a result of - the previous restriction. Note that interrupt vectors can point into - any allocated upper memory blocks however. - -ERROR CODE INDEX: ------------------ - -If AX=0000h when a function returns and the high bit of BL is set, - - BL=80h if the function is not implemented - 81h if a VDISK device is detected - 82h if an A20 error occurs - 8Eh if a general driver error occurs - 8Fh if an unrecoverable driver error occurs - 90h if the HMA does not exist - 91h if the HMA is already in use - 92h if DX is less than the /HMAMIN= parameter - 93h if the HMA is not allocated - 94h if the A20 line is still enabled - A0h if all extended memory is allocated - A1h if all available extended memory handles are in use - A2h if the handle is invalid - A3h if the SourceHandle is invalid - A4h if the SourceOffset is invalid - A5h if the DestHandle is invalid - A6h if the DestOffset is invalid - A7h if the Length is invalid - A8h if the move has an invalid overlap - A9h if a parity error occurs - AAh if the block is not locked - ABh if the block is locked - ACh if the block's lock count overflows - ADh if the lock fails - B0h if a smaller UMB is available - B1h if no UMBs are available - B2h if the UMB segment number is invalid - - -IMPLEMENTATION NOTES FOR DOS XMS DRIVERS: ------------------------------------------ - -- A DOS XMS driver's control function must begin with code similar to the - following: - -XMMControl proc far - - jmp short XCControlEntry ; For "hookability" - nop ; NOTE: The jump must be a short - nop ; jump to indicate the end of - nop ; any hook chainThe nop's - ; allow a far jump to be - ; patched in. -XCControlEntry: - - -- XMS drivers must preserve all registers except those containing - returned values across any function call. - -- XMS drivers are required to hook INT 15h and watch for calls to - functions 87h (Block Move) and 88h (Extended Memory Available). The - INT 15h Block Move function must be hooked so that the state of the A20 - line is preserved across the call. The INT 15h Extended Memory - Available function must be hooked to return 0h to protect the HMA. - -- In order to maintain compatibility with existing device drivers, DOS XMS - drivers must not hook INT 15h until the first non-Version Number call - to the control function is made. - -- XMS drivers are required to check for the presence of drivers which - use the IBM VDISK allocation scheme. Note that it is not sufficient to - check for VDISK users at installation time but at the time when the HMA - is first allocated. If a VDISK user is detected, the HMA must not be - allocated. Microsoft will publish a standard method for detecting - drivers which use the VDISK allocation scheme. - -- XMS drivers which have a fixed number of extended memory handles (most - do) should implement a command line parameter for adjusting that number - (suggested name "/NUMHANDLES=") - -- XMS drivers should make sure that the major DOS version number is - greater than or equal to 3 before installing themselves. - -- UMBs cannot occupy memory addresses that can be banked by EMS 4.0. - EMS 4.0 takes precedence over UMBs for physically addressable memory. - -- All driver functions must be re-entrant. Care should be taken to not - leave interrupts disabled for long periods of time. - -- Allocation of a zero length extended memory buffer is allowed. Programs - which hook XMS drivers may need to reserve a handle for private use via - this method. Programs which hook an XMS driver should pass all requests - for zero length EMBs to the next driver in the chain. - -- Drivers should control the A20 line via an "enable count." Local En- - able only enables the A20 line if the count is zero. It then increments - the count. Local Disable only disables A20 if the count is one. It - then decrements the count. Global Enable/Disable keeps a flag which - indicates the state of A20. They use Local Enable/Disable to actually - change the state. - -- Drivers should always check the physical A20 state in the local Enable-Disable calls, to see - that the physical state matches the internal count. If the physical state does not match, it should - be modified so that it matches the internal count. This avoids problems with applications that - modify A20 directly. - - -IMPLEMENTATION OF CODE FOR HOOKING THE XMS DRIVER: - - In order to support the hooking of the XMS driver by multiple - pieces of code, the following code sample should be followed. - Use of other methods for hooking the XMS driver will not work - in many cases. This method is the official supported one. - - The basic strategy is: - - Find the XMS driver header which has the "near jump" dispatch. - - Patch the near jump to a FAR jump which jumps to my HOOK XMS - driver header. - - NOTES: - - o This architecture allows the most recent HOOKer to undo his - XMS driver hook at any time without having to worry about - damaging a "hook chain". - - o This architecture allows the complete XMS hook chain to be - enumerated at any time. There are no "hidden hooks". - - o This architecture allows the HOOKer to not have to worry - about installing an "INT 2F hook" to hook the AH=43h - INT 2Fs handled by the XMS driver. The base XMS driver - continues to be the only one installed on INT 2Fh AH=43h. - - This avoids all of the problems of undoing a software - interrupt hook. - - ; - ; When I wish to CHAIN to the previous XMS driver, I execute a FAR JMP - ; to the address stored in this DWORD. - ; - PrevXMSControlAddr dd ? - - ; - ; The next two data items are needed ONLY if I desire to be able to undo - ; my XMS hook. - ; PrevXMSControlJmpVal stores the previos XMS dispatch near jump offset - ; value that is used to unhook my XMS hook - ; PrevXMSControlBase stores the address of the XMS header that I hooked - ; - PrevXMSControlBase dd ? - PrevXMSControlJmpVal db ? - - ; - ; This is MY XMS control header. - ; - MyXMSControlFunc proc FAR - jmp short XMSControlEntry - nop - nop - nop - XMSControlEntry: - - ...... - - Chain: - jmp cs:[PrevXMSControlAddr] - - MyXMSControlFunc endp - - - ....... - ; - ; This is the code which installs my hook into the XMS driver. - ; - ; - ; See if there is an XMS driver to hook - ; - mov ax,4300h - int 2Fh - cmp al,80h - jne NoXMSDrvrToHookError - ; - ; Get the current XMS driver Control address - ; - mov ax,4310h - int 2Fh - NextXMSHeader: - mov word ptr [PrevXMSControlAddr+2],es - mov word ptr [PrevXMSControlBase+2],es - mov word ptr [PrevXMSControlBase],bx - mov cx,word ptr es:[bx] - cmp cl,0EBh ; Near JUMP - je ComputeNearJmp - cmp cl,0EAh ; Far JUMP - jne XMSDrvrChainMessedUpError - ComputeFarJmp: - mov si,word ptr es:[bx+1] ; Offset of jump - mov es,word ptr es:[bx+1+2] ; Seg of jump - mov bx,si - jmp short NextXMSHeader - - ComputeNearJmp: - cmp word ptr es:[bx+2],9090h ; Two NOPs? - jne XMSDrvrChainMessedUpError ; No - cmp byte ptr es:[bx+4],90h ; Total of 3 NOPs? - jne XMSDrvrChainMessedUpError ; No - mov di,bx ; Save pointer to header - xor ax,ax - mov al,ch ; jmp addr of near jump - mov [PrevXMSControlJmpVal],al - add ax,2 ; NEAR JMP is 2 byte instruction - add bx,ax ; Target of jump - mov word ptr [PrevXMSControlAddr],bx - ; - ; Now INSTALL my XMS HOOK - ; - cli ; Disable INTs in case someone calls - ; XMS at interrupt time - mov byte ptr es:[di],0EAh ; Far Immed. JUMP instruction - mov word ptr es:[di+1],offset MyXMSControlFunc - mov word ptr es:[di+3],cs - sti - ..... - - ; - ; Deinstall my XMS hook. This can be done IF AND ONLY IF my XMS header - ; still contains the near jump dispatch - ; - cmp byte ptr [MyXMSControlFunc],0EBh - jne CantDeinstallError - mov al,0EBh - mov ah,[PrevXMSControlJmpVal] - les bx,[PrevXMSControlBase] - cli ; Disable INTs in case someone calls - ; XMS at interrupt time - mov word ptr es:[bx],ax - mov word ptr es:[bx+2],9090h - mov byte ptr es:[bx+4],90h - sti - .... - -IMPLEMENTATION NOTES FOR HIMEM.SYS: ------------------------------------ - -- HIMEM.SYS currently supports true AT-compatibles, 386 AT machines, IBM - PS/2s, AT&T 6300 Plus systems and Hewlett Packard Vectras. - -- If HIMEM finds that it cannot properly control the A20 line or if there - is no extended memory available when HIMEM.SYS is invoked, the driver - does not install itself. HIMEM.SYS displays the message "High Memory - Area Unavailable" when this situation occurs. - -- If HIMEM finds that the A20 line is already enabled when it is invoked, - it will NOT change the A20 line's state. The assumption is that whoever - enabled it knew what they were doing. HIMEM.SYS displays the message "A20 - Line Permanently Enabled" when this situation occurs. - -- HIMEM.SYS is incompatible with IBM's VDISK.SYS driver and other drivers - which use the VDISK scheme for allocating extended memory. However, - HIMEM does attempt to detect these drivers and will not allocate the - HMA if one is found. - -- HIMEM.SYS supports the optional "/HMAMIN=" parameter. The valid values - are decimal numbers between 0 and 63. - -- By default, HIMEM.SYS has 32 extended memory handles available for use. - This number may be adjusted with the "/NUMHANDLES=" parameter. The - maximum value for this parameter is 128 and the minimum is 0. Each - handle currently requires 6 bytes of resident space. - - -Copyright (c) 1988, Microsoft Corporation - diff --git a/16/PCGPE10/XTENDED.TXT b/16/PCGPE10/XTENDED.TXT deleted file mode 100644 index c02ecc05..00000000 --- a/16/PCGPE10/XTENDED.TXT +++ /dev/null @@ -1,136 +0,0 @@ - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ Xtended Mode - Unchained 640x400x256 ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - Written for the PC-GPE by Mark Feldman - e-mail address : u914097@student.canberra.edu.au - myndale@cairo.anu.edu.au - - Please read the file SVGINTRO.TXT - (Graphics/SVGA/Intro PC-GPE menu option) - - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ THIS FILE MAY NOT BE DISTRIBUTED ³ - ³ SEPARATE TO THE ENTIRE PC-GPE COLLECTION. ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Disclaimer ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ - -I assume no responsibility whatsoever for any effect that this file, the -information contained therein or the use thereof has on you, your sanity, -computer, spouse, children, pets or anything else related to you or your -existance. No warranty is provided nor implied with this information. - - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Introduction ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -I am calling this mode Xtended mode simply because I don't know if it -already has a name. It is a variation of mode x and it has worked on every -SVGA I have tried it on. It seems very very unlikely that I was the first -person to try this, so if this mode has already been documented elsewhere I -would very much like to hear about it. - -Xtended mode is 640x400x256 and will only work on SVGA's supporting the -"regular" 640x400x256 mode. It's advantage is that it requires no -bank switching to access the entire display memory and, like mode x, polygon -fill graphics can be up to 4 times faster. - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Setting Xtended Mode ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Xtended mode is set similar to the way unchained mode 13h is set, the only -difference is that you you call BIOS to set the 640x400x256 graphics mode -instead of mode 13h. The 640x400x256 mode number varies from card to card. -The following table lists the mode number for each of the 7 "standard" -SVGAs: - - 640x400x256 mode numbers for various SVGA cards - ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ - ³ SVGA Chip Mode Number ³ - ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ - ³ ATI 61h ³ - ³ Chips & Technologies 78h ³ - ³ Genoa 7Eh ³ - ³ Paradise 5Eh ³ - ³ Trident 5Ch ³ - ³ Tseng 2Fh ³ - ³ Video 7 66h ³ - ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Alternatively the mode can be set with the VESA Set Super VGA Mode BIOS -call, the VESA SVGA mode number is 100h. Refer to the file "VESASP12.TXT" -for more information on VESA BIOS calls. - -The following Pascal procedure will set Xtended mode for a card with a VESA -driver: - -const VIDEO = $10; { Video interrupt number } - CRTC_ADDR = $3d4; { Base port of the CRT Controller (color) } - SEQU_ADDR = $3c4; { Base port of the Sequencer } - -procedure InitXtended; -begin - - { Set VESA 640x400x256 mode } - asm - mov ax, $4F02 - mov bx, $100 - int VIDEO - end; - - { Turn the VGA screen off } - Port[SEQU_ADDR] := 1; - Port[SEQU_ADDR + 1] := Port[SEQU_ADDR + 1] or $20; - - { Turn off the Chain-4 bit (bit 3 at index 4, port 0x3c4) } - PortW[SEQU_ADDR] := $0604; - - { Turn off word mode, by setting the Mode Control register - of the CRT Controller (index 0x17, port 0x3d4) } - PortW[CRTC_ADDR] := $E317; - - { Turn off doubleword mode, by setting the Underline Location - register (index 0x14, port 0x3d4) } - PortW[CRTC_ADDR] := $0014; - - { Clear entire video memory, by selecting all four planes, then writing - color 0 to the entire segment. Stoopid FillChar fills 1 byte too short! } - PortW[SEQU_ADDR] := $0F02; - FillChar(Mem[$A000 : 0], $8000, 0); - FillChar(Mem[$A000 : $8000], $8000, 0); - - { Give a small delay to let the screen sort itself out } - Delay(100); - - { Turn the screen back on } - Port[SEQU_ADDR] := 1; - Port[SEQU_ADDR + 1] := Port[SEQU_ADDR + 1] and $DF; -end; - -ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ -³ Drawing a Pixel ³ -ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ - -Drawing a pixel in Xtended mode is similar to drawing one in unchained mode -13h or mode x, we just have to keep in mind that the display is now twice -as wide. Also keep in mind that 640x400 has 4 times as many pixels as -320x200, so there is only one page in Xtended mode. - -This example Pascal routine will draw a pixel at any screen position. I'll -let you do the job of converting it to assembly: - -procedure XtendedPutPixel(x, y : word; color : byte); -begin - { Set map mask to select proper plane } - PortW[SEQU_ADDR] := $100 shl (x and 3) + 2; - - { Calculate address (y * 160 + x div 4) and write pixel } - Mem[$A000 : y shl 7 + y shl 5 + x shr 2] := color; -end; diff --git a/16/PCGPE10/suround.txt b/16/PCGPE10/suround.txt deleted file mode 100644 index 7a33f970..00000000 --- a/16/PCGPE10/suround.txt +++ /dev/null @@ -1,76 +0,0 @@ - -Midi And 4 Channel Surround Sound ---------------------------------- - -I got some email today asking how to do Dolby surround midi files. I tought -it could be of interest to other people. Note: Only a ram wavetable midi -device can reproduce the surround channel, with this method, but the center -channel can be done on any midi playback device. - -If you want something that comes out from the center channel, just put the -pan on the midi channel at 64. Coming from left? just put the panning to -the left (under 64). Coming from right? just put the panning to the right -(over 64). - -For elements that have to be present on both sides i'd recommend dupli -cating the track and giving two opposite panning. This gives much better -results than panning to center and shouldn't come out the front channel. -Also, if you sampled something in stereo, then you can use the left signal -to create a patch for the left track and a separate patch for the right -track. This works very well. - -Finally, for the surround channel, it's the same as stereo snce you use -two tracks. One for left, one for right. On the left you use the regular -instrument, and on the right, you use the *inverted* signal (a flip around -the X axis of the signal, as done by the invert function of most wave -editors). When i was asked the question, i hadn't tried this, but i just -did and it works. I use my own circuit to decode the surround channel (a -very simple design, found on archive.epas.utoronto.ca under the filename -surround.txt) and have not tried it on a real dolby surround or pro logic -unit, but it should work equally well. - -Of course by using two voices per sounds, you use the GUS voices much more -rapidly, but the sound is much better, even when it's the same signal on -both channels because of the slight phasing between the left and right -channels. Plus, you get much more balance control. - -So when you want something on the left, center or right channel, just use -mono panning. For the surround channel, on top of that, just add two voices -panned left and right, one playing the inverse of the other. Note, in mono, -this will disapear totally... - -This should be very simple to understand by looking at this diagram: - -P=panning, V=volume - CENTRE CHANNEL - P=64, V=presence - V /|\ - variation | - \|/ - LEFT CHANNEL RIGHT CHANNEL -P=1, V=presence P variation <--> P=127, V=presence - - Vleft=Vright /|\ - variation | - \|/ - - P=1,normal patch;P=127,inverted patch, - Vleft=Vright=presence - SURROUND CHANNEL (either 1 or two speakers, - this channel is mono) - -For stereo instead of panned mono: -P=1, left signal patch;P=127, right signal patch, Vleft=left presence, -Vright=right presence. So for <--> variation, you use the two volumes instead -of P. - -Hope this helps. - -Ciao, --- -Francois Dion - ' _ _ _ - CISM (_) (_) _) FM Montreal , Canada Email: CISM@ERE.UMontreal.CA - (_) / . _) 10000 Watts Telephone no: (514) 343-7511 -_______________________________________________________________________________ -Audio-C-DJ-Fractals-Future-Label-Multimedia-Music-Radio-Rave-Video-VR-Volvo-... -- 2.11.0

=? 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