From b50a0eb714c64dee65050539243e02ef2aa308b5 Mon Sep 17 00:00:00 2001 From: sparky4 Date: Fri, 13 Jun 2014 12:06:51 -0500 Subject: [PATCH] modified: 16/DOS_GFX.EXE modified: 16/DOS_GFX.OBJ modified: 16/Project 16.bfproject modified: 16/dos_gfx.cpp modified: 16/dos_gfx.h new file: 16/lib/x/MODEX.BAK new file: 16/scrasm/80X86.ASC new file: 16/scrasm/80X86.TXT new file: 16/scrasm/CONSTANT.INC new file: 16/scrasm/DIAGONAL.MAP new file: 16/scrasm/DIAGONAL.PAL new file: 16/scrasm/DIAGONAL.TIL new file: 16/scrasm/GENMAP.C new file: 16/scrasm/GENMAP.EXE new file: 16/scrasm/GENMAP.LNK new file: 16/scrasm/GENMAP.OBJ new file: 16/scrasm/GENPAL.C new file: 16/scrasm/GENPAL.EXE new file: 16/scrasm/GENPAL.LNK new file: 16/scrasm/GENPAL.OBJ new file: 16/scrasm/GENSQ.C new file: 16/scrasm/GENSQ.EXE new file: 16/scrasm/GENSQ.LNK new file: 16/scrasm/GENSQ.OBJ new file: 16/scrasm/INIT.INC new file: 16/scrasm/KEYB.INC new file: 16/scrasm/LZTIMER.ASM new file: 16/scrasm/LZTIMER.OBJ new file: 16/scrasm/MAIN.ASM new file: 16/scrasm/MAIN.OBJ new file: 16/scrasm/MAKEFILE new file: 16/scrasm/MAP.INC new file: 16/scrasm/MODEX.INC new file: 16/scrasm/PAGE.INC new file: 16/scrasm/PALETTE.INC new file: 16/scrasm/SCROLL.DOC new file: 16/scrasm/SCROLL.EXE new file: 16/scrasm/SCROLL.INC new file: 16/scrasm/SCROLL.LNK new file: 16/scrasm/SCROLL.MAP new file: 16/scrasm/SCROLL.PAL new file: 16/scrasm/SCROLL.TIL new file: 16/scrasm/SPRITE.INC --- 16/DOS_GFX.EXE | Bin 35702 -> 35970 bytes 16/DOS_GFX.OBJ | Bin 5389 -> 5583 bytes 16/Project 16.bfproject | 24 +- 16/dos_gfx.cpp | 55 ++-- 16/dos_gfx.h | 8 +- 16/lib/x/MODEX.BAK | Bin 0 -> 25600 bytes 16/scrasm/80X86.ASC | 164 +++++++++++ 16/scrasm/80X86.TXT | 494 +++++++++++++++++++++++++++++++ 16/scrasm/CONSTANT.INC | 127 ++++++++ 16/scrasm/DIAGONAL.MAP | Bin 0 -> 65057 bytes 16/scrasm/DIAGONAL.PAL | Bin 0 -> 768 bytes 16/scrasm/DIAGONAL.TIL | Bin 0 -> 65536 bytes 16/scrasm/GENMAP.C | 99 +++++++ 16/scrasm/GENMAP.EXE | Bin 0 -> 18664 bytes 16/scrasm/GENMAP.LNK | 1 + 16/scrasm/GENMAP.OBJ | Bin 0 -> 2543 bytes 16/scrasm/GENPAL.C | 51 ++++ 16/scrasm/GENPAL.EXE | Bin 0 -> 17676 bytes 16/scrasm/GENPAL.LNK | 1 + 16/scrasm/GENPAL.OBJ | Bin 0 -> 1895 bytes 16/scrasm/GENSQ.C | 102 +++++++ 16/scrasm/GENSQ.EXE | Bin 0 -> 18916 bytes 16/scrasm/GENSQ.LNK | 1 + 16/scrasm/GENSQ.OBJ | Bin 0 -> 2977 bytes 16/scrasm/INIT.INC | 375 +++++++++++++++++++++++ 16/scrasm/KEYB.INC | 237 +++++++++++++++ 16/scrasm/LZTIMER.ASM | 636 ++++++++++++++++++++++++++++++++++++++++ 16/scrasm/LZTIMER.OBJ | Bin 0 -> 3231 bytes 16/scrasm/MAIN.ASM | 134 +++++++++ 16/scrasm/MAIN.OBJ | Bin 0 -> 18324 bytes 16/scrasm/MAKEFILE | 47 +++ 16/scrasm/MAP.INC | 413 ++++++++++++++++++++++++++ 16/scrasm/MODEX.INC | 88 ++++++ 16/scrasm/PAGE.INC | 109 +++++++ 16/scrasm/PALETTE.INC | 239 +++++++++++++++ 16/scrasm/SCROLL.DOC | 297 +++++++++++++++++++ 16/scrasm/SCROLL.EXE | Bin 0 -> 33596 bytes 16/scrasm/SCROLL.INC | 441 ++++++++++++++++++++++++++++ 16/scrasm/SCROLL.LNK | 2 + 16/scrasm/SCROLL.MAP | Bin 0 -> 344 bytes 16/scrasm/SCROLL.PAL | Bin 0 -> 768 bytes 16/scrasm/SCROLL.TIL | Bin 0 -> 9984 bytes 16/scrasm/SPRITE.INC | 280 ++++++++++++++++++ 43 files changed, 4385 insertions(+), 40 deletions(-) create mode 100644 16/lib/x/MODEX.BAK create mode 100644 16/scrasm/80X86.ASC create mode 100644 16/scrasm/80X86.TXT create mode 100644 16/scrasm/CONSTANT.INC create mode 100644 16/scrasm/DIAGONAL.MAP create mode 100644 16/scrasm/DIAGONAL.PAL create mode 100644 16/scrasm/DIAGONAL.TIL create mode 100644 16/scrasm/GENMAP.C create mode 100644 16/scrasm/GENMAP.EXE create mode 100644 16/scrasm/GENMAP.LNK create mode 100644 16/scrasm/GENMAP.OBJ create mode 100644 16/scrasm/GENPAL.C create mode 100644 16/scrasm/GENPAL.EXE create mode 100644 16/scrasm/GENPAL.LNK create mode 100644 16/scrasm/GENPAL.OBJ create mode 100644 16/scrasm/GENSQ.C create mode 100644 16/scrasm/GENSQ.EXE create mode 100644 16/scrasm/GENSQ.LNK create mode 100644 16/scrasm/GENSQ.OBJ create mode 100644 16/scrasm/INIT.INC create mode 100644 16/scrasm/KEYB.INC create mode 100644 16/scrasm/LZTIMER.ASM create mode 100644 16/scrasm/LZTIMER.OBJ create mode 100644 16/scrasm/MAIN.ASM create mode 100644 16/scrasm/MAIN.OBJ create mode 100644 16/scrasm/MAKEFILE create mode 100644 16/scrasm/MAP.INC create mode 100644 16/scrasm/MODEX.INC create mode 100644 16/scrasm/PAGE.INC create mode 100644 16/scrasm/PALETTE.INC create mode 100644 16/scrasm/SCROLL.DOC create mode 100644 16/scrasm/SCROLL.EXE create mode 100644 16/scrasm/SCROLL.INC create mode 100644 16/scrasm/SCROLL.LNK create mode 100644 16/scrasm/SCROLL.MAP create mode 100644 16/scrasm/SCROLL.PAL create mode 100644 16/scrasm/SCROLL.TIL create mode 100644 16/scrasm/SPRITE.INC diff --git a/16/DOS_GFX.EXE b/16/DOS_GFX.EXE index 13b89317f3689d21e6f85000608aff996db46f4b..d4df1da3e32f74f72ff89c6c72677496f5b37b9e 100644 GIT binary patch delta 15833 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 diff --git a/16/DOS_GFX.OBJ b/16/DOS_GFX.OBJ index 35e3f4ed617b65a74bc2c2ce1950811062822244..f17a0b16baf7f45788d4f3ee34931c1803b59d5c 100644 GIT binary patch delta 3006 zcmZuz3s6+o8UFu!&%JjSML{0oGpmA%MqIR_gHe33iVCc_98f6)c^d?TUDPzPOIc$! zLIp30FQOFNngnHhjCM6m#kwk;*=VMdnb;a>jlsQtj~QTx1t2p3ph#r4of3Vw$f6=B3of$L8XD0 zR9bDhrG~VEs`65swWPc(-Vl|)#eQnD5QcKzJOo>|x?7By;y|;zQ84cZ`f(!+kl0SM z+5J+D0WPcGi;23qASGv-7pAC2_OsyQt>*yGfO+7bT-`rcZEQR?s(YEMU`tCnctt+M zJB$n77(UcHmkXXHJjj#GgFR^k&V!s;e3&Pfv=YKb9^|d2Hg@7WsJ@=iNNwJyHU~&+ zqxxf9_+$Mv&}Af4ZH+9nRjE6q3BxwE{sFKQU6hcz|-&5rPQAX?~+<9+UZSny2WQ#Uq^a`3UDqKGK=NM>+HO z2yY1=O-75JUDUprOy0+XorlQe4jyz^7?9`Vsa)EvvvO(-^^gq$iyE9Yx-aC&Un5BP{34W8uR+YpBenvY1Qc zb%bX#m3AtdNZ(KVFqQ38f09Q`*Os+WJdY4pM-v8HP}~)noQBxWxWfRNuB|s^G9=X9 z->+#e>PB@`z(_665PzNt0a^CHwyXh5q83Tp&lLyzXA|Dp0rS{#Sj0}ia&{6@*eOV3ry+x7YQ8UHHd%A?j#4A3R|lmA zIj~wDFy3$Hw80DQ4t(?^&3AL``^1R%HFFu65l9Fo!$y)>QDoMu6wjn`E|m$SCzGB* zJeN>Nyn?WmxP!`_R5nuCOdEMW5BL6ti{9g0OsJ2BAUgF0*6Nb{g7V11$yL$SYVY6? z(UdGmlm=Z{zD(-+f@}tVPA}!BP7hpVH-fKf^{O(HhVUx!1$3U0>CBm_TuW2T zp*>$nD5Xnl3m2R%e2n)HA8U6W<*!`!ZIm;R!+sC>>?{Wv|z?E2(PQ_{+ni&8UzXllB}l9*|MKWo=#g=}^+zX=%) z&Q97?-DdX!%GL;GZ4$5hU)zlS>h2fxfz%oj(Pg?v>2|w;+*6*rd9T6QMP2onHQlcD z<;%Ulnkqi0mRjq?7scy-G3`b1AAT|CMe){vm_(0>SLWlq6Zm-V96q6IsYUNuVbOb2 zd1O}(@jT*1#I2T0y=MyrZ&Bc)iU#6M#19g0BmO($r!4x6`VkPAoSCsO$&!|6Nn5x$ z5tNF`k}_*y4%jrSCMxbye^_ zs~`GkU4MdIs_VyX;-l;bwS9+>qCVVq`BC=6I~RN{=4}G2Zr&)cinqUg7Tc+vZSDKV zt$poi9=->5|3%`_xs7N(M91BOG%1Nk(s7^Q9nTHkcycI#$|ZcPa}|HZ%jr8Omq&T) zxWT!XkLfy0MjWC4Y3CEi*AIok$(c(NEj%%8by8{ybhKszeyuzo@q*uiIvTKtGSF*# zMN8#twKF&@iw@Di)I73J9fUu{EVh%rxo*#S7Sb{cx+EG?Ph$r1iCtrek0Tz%Cwiyx zNnJB3o=x#ws#{E)R@S?MPjso7!=~8j*`lj8ue`Lp(ppeurMoq{>MlT_UwhLhOhy<) z_it7Hz}1_LFgPP2zoe{);*#j9Zn}gw=9ZM@SS2{vtkOd`598$oOpq5~io6iB<;7Sm zC*nrggm21AagUsYN9E;sQC?xkujG~3BPXMzq~J&;6{jm^T&k?XmC9<&S1eeftiwtr z3%4rS=umR7PFas{EBUxnDZsr-F@C6&;4x(bo>WTloU#!+l`_1plw*%lfjZqL9ILCs z7~Qhg0ATb1rG4nO?rt0d$drtPqD|`SA!qd+p#K!2@&iC!Elg0yhSuR_wJr3G{{nmP B(Q^O* delta 2788 zcmZuzYgAO%72f;abMIvkW#l0$1XLahwaQe%Mx%(p2o_|-;Q%U*L@a zQHsWBvuF)Q)esL^y1YeMX;Wu=o9Q-9>qF5@FcQfm!#-(ghJRTdxTJKx@% z$9K-zGoSx#OUkyDQzn;vnjMifdBMB|rgZ(cvfgg1u6lml(*13*(0p~H^Uv8s{!e&u zLxZj3SekrEQ3N!1-0TXUj-f`p;Q0g$0MAw|uV|x3$Y9VUBD0=^IGYBmaE)ZNToZ70R|Qv4_nyU`x6Zjs`Z zm7d=N)}eY@I$R1c;(AbeGtE3{WoI5}0uR>)5{B?FZ8(qcjo^{mXzGt8q>+}vBeZND z=Cg27t0vw+`~@1GrqMjqKTJ5mBZ^h8oacHP-h)i|0A|1!kOk+#43}Xh+=N`X3waQX zvmg}nAqop27A-Iaiy#%}LN;0<56i%c^Pm#vLme&z7cPPhd=_58#jqPI;VoPOzr||! z8kfT*Y=Ar11Oo&I#0gFqEv$sG!lCv;wOO$WiGq4jIk?avyKfJ=0?^W9IHT`VqIHJQ z{*1Jbr}z-sr>LdysMZO5Xlo`P)|$_Ux0dpuzJ)y6x13_FlI1K(n^{CB;VO1X^q_>dK;4nhx9B7sK zFl_)0Yb5KU2=N3HA%in5j}OsiQ_HC>=Mq^RrPWf~MC}IBw-Vn;t%u_8kamH3xG z5Y=8oK@&4U`LOVVU3pr%PytO~N|ZDy)Zt!Ui}gY=l1wZSa}khOdN8a7EY*H-#;5S9l4+ z#H|n|Zi6JT1JcCpkS(fEChmZR;>*w=z5;IXH?T+C310D4I48aax5Q5Pm-sr|7vBJ2 z9+21`P}rMbU~j`9_6`hT`yefv?T1))07kHbkjM_f7%)r#;Ha~Qm zd#Ir4Z^fVSVwWSxeP8chzh%11X*b@`K)K`ITcGz!JEwwArj>*dM$*dC=)ugON0mcu zA??aaw|YLIf@)D67pOM5VtiZqQ?0M@Sl#_qrwb`So>?gL8yh9v0$ z6iGiqiPQs&q+Y0$LU5TBhHE5SI5tZW_@WerZPFOrDkbAiDFxqjq%=GyrQ=0u5?+y>#%t1KyeCaTNqz=HbZ6ONn}NPJi*MfLPRDybus=N&VF; z0kt+DZZWc@!jKzPar;tcsB7|;`zkO zh?f(uAijclBXKA37UCO;Z|3pzHb?mm^0@EY<3K7XwPel)rJ=EAMN^dxLJCS}=2&@7 z(cHYk*%0G#QR$9X9vw&D5%~B1T}Q(G&LHU#H)jQOkMg5)(_eL{X}>2<$x0{T9DUun*{wb=z$YY0{(&e)b7Ws?9ck{ zai2}moeSk7eGzmchS9T5q-Q;jC-}1H!*dpoYqjy1?q%c*Ipu5QiQVgoZy>&jC;GPY zr0$(bBy^JCq2NB^hln5HiRGRUz;6^POE=1|uK#hSdM+%*^#SOmZgG8WePh!Sds9Ny zm}L89fPn$+1-}rBFo5czy^?zNWTzD&q$H!VW<@piYm)7k5Tv?_niaNX5`446PM=KE zF-4w%COI3^hQR-0zXw6Xj9GVcj0HHjbJzh O>V=3F1hq19`F{altb02E diff --git a/16/Project 16.bfproject b/16/Project 16.bfproject index b5009ceb..378d9de2 100644 --- a/16/Project 16.bfproject +++ b/16/Project 16.bfproject @@ -1,7 +1,7 @@ c2e.convert_special: 0 e2c.convert_num: 0 -openfiles: /dos/z/16/16/dos_gfx.cpp:8135:7436:1: -openfiles: /dos/z/16/16/dos_gfx.h:327:0:0: +openfiles: /dos/z/16/16/dos_gfx.cpp:1620:647:1: +openfiles: /dos/z/16/16/dos_gfx.h:665:373:0: openfiles: /dos/z/16/16/dos_kb.c:1039:46:0: openfiles: /dos/z/16/16/dos_kb.h:23:0:0: openfiles: /dos/z/16/16/lib/lib_com.cpp:0:0:0: @@ -80,25 +80,25 @@ recent_files: file:///dos/z/16/16/xx.bat recent_files: file:///dos/z/16/16/lib/x/MXPN.ASM recent_files: file:///dos/z/4x4_16/!/c/TUT10.C recent_files: file:///dos/z/16/16/lib/x/MXVS.ASM -recent_files: file:///dos/z/16/16/lib/x/MODEX.H -recent_files: file:///dos/z/4x4_16/modex/DEMO01.PAS -recent_files: file:///dos/z/4x4_16/modex/DEMO07.PAS +recent_files: file:///dos/z/16/16/lib/x/MAKEFILE +recent_files: file:///dos/z/16/16/lib/x/MODEX.DEF recent_files: file:///dos/z/16/16/dos_gfx.h +recent_files: file:///dos/z/16/16/dos_gfx.cpp recent_files: file:///dos/z/16/16/dos_kb.c recent_files: file:///dos/z/16/16/dos_kb.h recent_files: file:///dos/z/16/16/lib/lib_com.cpp -recent_files: file:///dos/z/16/16/lib/lib_com.h recent_files: file:///dos/z/16/16/16.txt +recent_files: file:///dos/z/16/16/lib/lib_com.h recent_files: file:///dos/z/16/16/scroll.txt recent_files: file:///dos/z/16/16/project16.txt -recent_files: file:///dos/z/16/16/lib/intro/lib.c -recent_files: file:///dos/z/16/src/lib/dos_gfx.h +recent_files: file:///dos/z/16/16/lib/x/MODEX.H +recent_files: file:///dos/z/4x4_16/modex/DEMO07.PAS recent_files: file:///dos/z/16/16/lib/x/MXBB.ASM -recent_files: file:///dos/z/16/src/lib/dos_gfx.cpp +recent_files: file:///dos/z/16/src/lib/dos_gfx.h +recent_files: file:///dos/z/4x4_16/modex/DEMO01.PAS recent_files: file:///dos/z/16/16/lib/x/MXCR.ASM -recent_files: file:///dos/z/16/16/dos_gfx.cpp -recent_files: file:///dos/z/16/16/lib/x/MAKEFILE -recent_files: file:///dos/z/16/16/lib/x/MODEX.DEF +recent_files: file:///dos/z/16/16/lib/intro/lib.c +recent_files: file:///dos/z/16/src/lib/dos_gfx.cpp snr_replacetype: 0 savedir: file:///dos/z/16/16 spell_check_default: 1 diff --git a/16/dos_gfx.cpp b/16/dos_gfx.cpp index 41b7d533..52e259db 100644 --- a/16/dos_gfx.cpp +++ b/16/dos_gfx.cpp @@ -48,10 +48,11 @@ void setvideo(/*byte mode, */short vq){ mxSetMode( MX_320x240 ); // mxSetVirtualScreen(SW+(SW/4), SH+(SH/4)); // mxSetVirtualScreen(SW*2, SH*2); - mxSetVirtualScreen(VW,(VH+(TILEWH*BUFFMX))); + mxSetVirtualScreen(VW,BH); // mxSetVirtualScreen((640-(TILEWH*4)),(480-(TILEWH*4))); mxSetClip(true); - mxSetClipRegion(0, 0, VW, (VH+(TILEWH*BUFFMX))); + mxSetClipRegion(0, 0, VW, BH); + mxPan(TILEWH*2,TILEWH*2); //mxSetClipRegion(0, VH+1, VW, (TILEWH*BUFFMX)); } } @@ -212,17 +213,17 @@ short ding(int q){ } } // fixer - if(q!=16){ + if(q!=16){ #ifdef TILE if(xx<0) xx=(VW-TILEWH); if(yy<0) yy=(VH-TILEWH); if(xx>(VW-TILEWH)) xx=0; - if(yy>(VH-TILEWH)/*+(TILEWH*BUFFMX)*/) yy=0; - #else + if(yy>(VH-TILEWH)/*+(TILEWH*BUFFMX)*/) yy=0; + #else if(xx<0) xx=VW; if(yy<0) yy=VH; if(xx>VW) xx=0; - if(yy>VH) yy=0; + if(yy>VH) yy=0; #endif } @@ -272,8 +273,8 @@ int main(void) // main variables d=4; // switch variable key=4; // default screensaver number - xpos=0; - ypos=0; + xpos=TILEWH*2; + ypos=TILEWH*2; xdir=1; ydir=1; setvideo(1); @@ -319,21 +320,21 @@ int main(void) mxPutPixel(VW-1, y, 15); } - getch(); + getch(); //text box - mxSetTextColor(10, OP_TRANS); //set font - mxBitBlt(xpos, ypos+(TILEWH*12), 320, TILEWH*BUFFMX, 0, VH); //copy background - mxFillBox(xpos, ypos+(TILEWH*12), 320, TILEWH*BUFFMX, 0, OP_SET); // background for text box - //+(QUADWH*6) - mxOutText(xpos+1, ypos+SH-48, "========================================"); + mxSetTextColor(10, OP_TRANS); //set font + mxBitBlt(xpos, ypos+(TILEWH*12), 320, TILEWH*BUFFMX, 0, BS); //copy background + mxFillBox(xpos, ypos+(TILEWH*12), 320, TILEWH*BUFFMX, 0, OP_SET); // background for text box + //+(QUADWH*6) + mxOutText(xpos+1, ypos+SH-48, "========================================"); mxOutText(xpos+1, ypos+SH-40, "| |Chikyuu:$line1"); mxOutText(xpos+1, ypos+SH-32, "| |$line2"); mxOutText(xpos+1, ypos+SH-24, "| |$line3"); - mxOutText(xpos+1, ypos+SH-16, "| |$line4"); - mxOutText(xpos+1, ypos+SH-8, "========================================"); - mxFillBox(xpos+QUADWH, ypos+QUADWH+(TILEWH*12), TILEWH*2, TILEWH*2, 9, OP_SET); - getch(); - mxBitBlt(0, VH, 320, TILEWH*BUFFMX, xpos, ypos+(TILEWH*12)); //copy background + mxOutText(xpos+1, ypos+SH-16, "| |$line4"); + mxOutText(xpos+1, ypos+SH-8, "========================================"); + mxFillBox(xpos+QUADWH, ypos+QUADWH+(TILEWH*12), TILEWH*2, TILEWH*2, 9, OP_SET); //portriat~ + getch(); + mxBitBlt(0, BS, 320, TILEWH*BUFFMX, xpos, ypos+(TILEWH*12)); //copy background //mxBitBlt(0, (TILEWH*12)+1, 320, TILEWH*3, 0, 0); getch(); while(!kbhit()){ @@ -341,18 +342,19 @@ int main(void) // scrolly(1); // vScroll(1); // delay(100); - //for(int i=0;i(VW-SW-1)) || (xpos<1))delay(500); + mxWaitRetrace(); //} if( (xpos>(VW-SW-1)) || (xpos<1)){xdir=-xdir;} - if( (ypos>((VH+(TILEWH*BUFFMX))-SH-1)) || (ypos<1)){ydir=-ydir;} // { Hit a boundry, change + if( (ypos>(BH-SH-1)) || (ypos<1)){ydir=-ydir;} // { Hit a boundry, change // direction! } } ch=getch(); @@ -360,7 +362,8 @@ int main(void) if(ch==0x1b)break; // 'ESC' } setvideo(0); - printf("wwww\nVirtual Resolution: %dx%d\n", VW,VH); + printf("wwww\nFull Buffer Virtual Resolution: %dx%d\n", VW,BH); + printf("Virtual Resolution: %dx%d\n", VW,VH); printf("Resolution: %dx%d\n", SW,SH); printf("Mode X Library Version: %d\n", mxGetVersion()); printf("bakapi ver. 1.04.09.04\nis made by sparky4i†ƒÖ…j feel free to use it ^^\nLicence: GPL v2\n"); diff --git a/16/dos_gfx.h b/16/dos_gfx.h index b9045057..231c1061 100644 --- a/16/dos_gfx.h +++ b/16/dos_gfx.h @@ -21,8 +21,12 @@ #define SW 320 #define SH 240 -#define VW 560 -#define VH 416 +//#define VW 560 +//#define VH 416 +#define VW (SW+64) +#define VH (SH+64) +#define BS (VH*2) // buffer space! not BULLSHIT +#define BH BS+(TILEWH*BUFFMX) // buffer resolution //void drawChar(int x, int y, int color, byte c); //void drawText(int x, int y, int color, byte string); diff --git a/16/lib/x/MODEX.BAK b/16/lib/x/MODEX.BAK new file mode 100644 index 0000000000000000000000000000000000000000..560a1c68304c56844f41325820f296a21192ac4e GIT binary patch literal 25600 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 literal 0 HcmV?d00001 diff --git a/16/scrasm/80X86.ASC b/16/scrasm/80X86.ASC new file mode 100644 index 00000000..e16af972 --- /dev/null +++ b/16/scrasm/80X86.ASC @@ -0,0 +1,164 @@ +_80x86 OPTIMIZATION_ +by Michael Abrash + + +[LISTING ONE] + +; Copies one string to another string, converting all characters to +; uppercase in the process, using a loop containing LODSB and STOSB. +; Adapted from Zen of Assembly Language, by Michael Abrash; not a +; standalone program, but designed to be used with the Zen timer from +; that book via the Zen timer's PZTIME.BAT batch file: ZTimerOn starts +; the clock, ZTimerOff stops it, and the test-bed program linked in by +; PZTIME.BAT starts the program, reports the results, and ends. + + jmp Skip ;skip over data in CS and subroutine + +SourceString label word ;sample string to copy + db 'This space intentionally left not blank',0 +DestString db 100 dup (?) ;destination for copy + +; Copies one zero-terminated string to another string, +; converting all characters to uppercase. +; Input: DS:SI = start of source string; DS:DI = start of destination buffer +; Output: none +; Registers altered: AX, BX, SI, DI, ES +; Direction flag cleared + +CopyStringUpper: + mov ax,ds + mov es,ax ;for STOS + mov bl,'a' ;set up for fast register-register + mov bh,'z' ; comparisons + cld +StringUpperLoop: + lodsb ;get next character and point to following character + cmp al,bl ;below 'a'? + jb IsUpper ;yes, not lowercase + cmp al,bh ;above 'z'? + ja IsUpper ;yes, not lowercase + and al,not 20h ;is lowercase-make uppercase +IsUpper: + stosb ;put character into new string and point to + ; following location + and al,al ;is this the zero that marks end of the string? + jnz StringUpperLoop ;no, do the next character + ret + +; Calls CopyStringUpper to copy & convert SourceString->DestString. +Skip: + call ZTimerOn ;start timing + mov si,offset SourceString ;point SI to the string to copy from + mov di,offset DestString ;point DI to the string to copy to + call CopyStringUpper ;copy & convert to uppercase + call ZTimerOff ;stop timing + + +[LISTING TWO] + +; Copies one string to another string, converting all characters to +; uppercase in the process, using no string instructions. +; Not a standalone program, but designed to be used with the Zen +; timer, as described in Listing 1. + + jmp Skip ;skip over data in CS and subroutine + +SourceString label word ;sample string to copy + db 'This space intentionally left not blank',0 +DestString db 100 dup (?) ;destination for copy + +; Copies one zero-terminated string to another string, +; converting all characters to uppercase. +; Input: DS:SI = start of source string; DS:DI = start of destination string +; Output: none +; Registers altered: AL, BX, SI, DI + +CopyStringUpper: + mov bl,'a' ;set up for fast register-register + mov bh,'z' ; comparisons +StringUpperLoop: + mov al,[si] ;get the next character and + inc si ; point to the following character + cmp al,bl ;below 'a'? + jb IsUpper ;yes, not lowercase + cmp al,bh ;above 'z'? + ja IsUpper ;yes, not lowercase + and al,not 20h ;is lowercase-make uppercase +IsUpper: + mov [di],al ;put the character into the new string and + inc di ; point to the following location + and al,al ;is this the zero that marks the end of the string? + jnz StringUpperLoop ;no, do the next character + ret + +; Calls CopyStringUpper to copy & convert SourceString->DestString. +Skip: + call ZTimerOn + mov si,offset SourceString ;point SI to the string to copy from + mov di,offset DestString ;point DI to the string to copy to + call CopyStringUpper ;copy & convert to uppercase + call ZTimerOff + + +[LISTING THREE] + +; Clears a buffer using MOV/ADD in a loop. +; Not a standalone program, but designed to be used with the Zen +; timer, as described in Listing 1. + + mov dx,2 ;repeat the test code twice, to make + ; sure it's in the cache (if there is one) + mov bx,dx ;distance from the start of one word + ; to the start of the next + sub ax,ax ;set buffer to zeroes +TestTwiceLoop: + mov cx,1024 ;clear 1024 words starting at address + mov di,8000h ; DS:8000h (this is just unused memory + ; past the end of the program) + call ZTimerOn ;start timing (resets timer to 0) +StoreLoop: + mov [di],ax ;clear the current word + add di,bx ;point to the next word + dec cx ;count off words to clear until none + jnz StoreLoop ; remain + call ZTimerOff ;stop timing + dec dx ;count off passes through test code + jz StoreDone ;that was the second pass; we're done + jmp TestTwiceLoop ;that was first pass; do second pass with all + ; instructions and data in the cache +StoreDone: + + +[LISTING FOUR] + +; Clears a buffer using MOV/ADD in an unrolled loop. +; Not a standalone program, but designed to be used with the Zen +; timer, as described in Listing 1. + + mov dx,2 ;repeat the test code twice, to make + ; sure it's in the cache (if there is one) + mov bx,dx ;distance from the start of one word + ; to the start of the next + sub ax,ax ;set buffer to zeroes +TestTwiceLoop: + mov si,1024 ;clear 1024 words starting at address + mov di,8000h ; DS:8000h (this is just unused memory + ; past the end of the program) + call ZTimerOn ;start timing (resets timer to 0) + mov cl,4 ;divide the count of words to clear by + shr si,cl ; 16, because we'll clear 16 words + ; each time through the loop +StoreLoop: + REPT 16 ;clear 16 words in a row without looping + mov [di],ax ;clear the current word + add di,bx ;point to the next word + ENDM + dec si ;count off blocks of 16 words to clear + jnz StoreLoop ; until none remain + call ZTimerOff ;stop timing + dec dx ;count off passes through test code + jz StoreDone ;that was the second pass; we're done + jmp TestTwiceLoop ;that was the first pass; do the second pass + ; with all instructions and data in the cache +StoreDone: + diff --git a/16/scrasm/80X86.TXT b/16/scrasm/80X86.TXT new file mode 100644 index 00000000..afba3707 --- /dev/null +++ b/16/scrasm/80X86.TXT @@ -0,0 +1,494 @@ +Journal: Dr. Dobb's Journal March 1991 v16 n3 p16(8) +----------------------------------------------------------------------------- +Title: 80x86 optimization: aim down the middle and pray. (80x86 family of + microprocessors) (tutorial) +Author: Abrash, Michael. +AttFile: Program: 80X86.ASC Source code listing. + +Summary: Optimizing code for 8088, 80286, 80386 and 80486 microprocessors + is difficult because the chips use significantly different memory + architectures and instruction execution times. Code cannot be + optimized for the 80x86 family; rather, code must be designed to + produce good performance on a range of systems or optimized for + particular combinations of processors and memory. Programmers + must avoid the unusual instructions supported by the 8088, which + have lost their performance edge in subsequent chips. String + instructions should be used but not relied upon. Registers should + be used rather than memory operations. Branching is also slow for + all four processors. Memory accesses should be aligned to improve + performance. Generally, optimizing an 80486 requires exactly the + opposite steps as optimizing an 8088. +----------------------------------------------------------------------------- +Descriptors.. +Company: Intel Corp. (Products). +Ticker: INTC. +Product: Intel 80286 (Microprocessor) (Programming) + Intel 80386 (Microprocessor) (Programming) + Intel 80486 (Microprocessor) (Programming) + Intel 8088 (Microprocessor) (Programming). +Topic: Microprocessors + Optimization + Programming + Tutorial + Assembly Language + Guidelines + Type-In Programs + Microcode + Processor Architecture. +Feature: illustration + graph. +Caption: Official and actual cycles per binary-to-hex ASCII conversion. + (graph) + Actual performance in microseconds of two solutions to a problem. + (graph) + Actual performance of three clearing approaches across the 80x86 + family. (graph) + +----------------------------------------------------------------------------- +Full Text: + +Optimization + +Picture this: You're an archer aiming at a target 100 feet away. A strong +wind comes up and pushes each arrow to the left as it flies. Naturally, you +compensate by aiming farther to the right. That's what it's like optimizing +for the 8088; once you learn to compensate for the strong but steady effects +of the prefetch queue and the 8-bit bus, you can continue merrily on your +programming way. + +Now the wind starts gusting unpredictably. There's no way to compensate, so +you just aim for the bull's-eye and hope for the best. That's what it's like +writing code for good performance across the entire 80x86 family, or even for +the 286/386SX/386 heart of today's market. You just aim down the middle and +pray. + +The New World of the 80x86 + +In the beginning, the 8088 was king, and that was good. The optimization +rules weren't obvious, but once you learned them, you could count on them +serving you well on every computer out there. + +Not so these days. There are four major processor types--8088, 80286, 80386, +and 80486--with a bewildering array of memory architectures: cached (in +several forms), page mode, static-column RAM, interleaved, and, of course, +the 386SX, with its half-pint memory interface. The processors offer wildly +differing instruction execution times, and memory architectures warp those +times further by affecting the speed of instruction fetching and access to +memory operands. Because actual performance is a complex interaction of +instruction characteristics, instruction execution times, and memory access +speed, the myriad processor-memory combinations out there make "exact +performance" a meaningless term. A specific instruction sequence may run at +a certain speed on a certain processor in a certain system, but that often +says little about the performance of the same instructions on a different +processor, or even on the same processor with a different memory system. The +result: Precise optimization for the general PC market is a thing of the +past. (We're talking about optimizing for speed here; optimizing for size is +the same for all processors so long as you stick to 8088-compatible code.) + +So there is no way to optimize performance ideally across the 80x86 family. +An optimization that suits one processor beautifully is often a dog on +another. Any 8088 programmer would instinctively replace: + +DEC CX JNZ LOOPTOP + +with: + +LOOP LOOPTOP + +because LOOP is significantly faster on the 8088. LOOP is also faster on the +286. On the 386, however, LOOP is actually two cycles slower than DEC/JNZ. +The pendulum swings still further on the 486, where LOOP is about twice as +slow as DEC/JNZ--and, mind you, we're talking about what was originally +perhaps the most obvious optimization in the entire 80x86 instruction set. + +In short, there is no such thing as code that's truly optimized for the +80x86. Instead, code is either optimized for specific processor-memory +combinations, or aimed down the middle, designed to produce good performance +across a range of systems. Optimizing for the 80x86 family by aiming down +the middle is quite different from optimizing for the 8088, but many PC +programmers are inappropriately still applying the optimization lore they've +learned over the years on the PC (or AT). The world has changed, and many of +those old assumptions and tricks don't hold true anymore. + +You will not love the new world of 80x86 optimization, which is less precise +and offers fewer clever tricks than optimizing for the 8088 alone. Still, +isn't it better to understand the forces affecting your code's performance +out in the real world than to optimize for a single processor and hope for +the best? + +Better, yes. As much fun, no. Optimizing for the 8088 was just about as +good as it gets. So it goes. + +Optimization Rules for a New World + +So, how do you go about writing fast code nowadays? One way is to write +different versions of critical code for various processors and memory access +speeds, selecting the best version at runtime. That's a great solution, but +it requires an awful lot of knowledge and work. + +An alternative is to optimize for one particular processor and settle for +whatever performance you get on the others. This might make sense when the +8088 is the target processor because it certainly needs the optimization more +than any other processor. However, 8088 optimization works poorly at the +upper end of the 80x86 family. + +Nowadays, though, most of us want to optimize for the 286 and 386 systems +that dominate the market, or across all 80x86 processors, and that's a tough +nut to crack. The 286 and 386 come in many configurations, and you can be +sure, for example, that a 386SX, an interleaved 386, and a cached 386 have +markedly different performance characteristics. There are, alas, no hard and +fast optimization rules that apply across all these environments. + +My own approach to 80x86 optimization has been to develop a set of general +rules that serve reasonably well throughout the 80x86 line, especially the +286 and 386, and to select a specific processor (in my case a cached 386, for +which cycle times tend to be accurate) to serve as the tiebreaker when +optimization details vary from one processor to another. (Naturally, it's +only worth bothering with these optimizations in critical code.) The rules +I've developed are: + +* Avoid accessing memory operands; use the registers to the max. + +* Don't branch. + +* Use string instructions, but don't go much out of your way to do so. + +* Keep memory accesses to a minimum by avoiding memory operands and keeping +instructions short. + +* Align memory accesses. + +* Forget about many of those clever 8088 optimizations, using oddball +instructions such as DAA and XLAT, that you spent years learning. + +Next I'll discuss each of these rules in turn in the context of +8088-compatible real mode, which is still the focus of the 80x86 world. +Later, I'll touch on protected mode. + +Let's start by looking at the last--and most surprising--rule. + +Kiss Those Tricks Goodbye + +To skilled assembly language programmers, the 8088 is perhaps the most +wonderful processor ever created, largely because the instruction set is +packed with odd instructions that are worthless to compilers but can work +miracles in the hands of clever assembly programmers. Unfortunately, each +new generation of the 80x86 has rendered those odd instructions and marvelous +tricks less desirable. As the execution time for the commonly used +instruction ADD BX, 4 has gone down from four cycles (8088) to three cycles +(286) to two cycles (386) to one cycle (486), the time for the less +frequently used instruction CBW has gone from two cycles (8088 and 286) up to +three cycles (386 and 486)! + +Consider this ancient optimization for converting a binary digit to hex +ASCII: + +ADD AL,90H DAA ADC AL,40H DAA + +Now consider the standard alternative: + +ADD AL,'0' CMP AL,'9' JBE HaveAscii ADD AL,'A'-('9'+1) HaveAscii: + +As Figure 1 indicates, the standard code should be slower on an 8088 or 286, +but faster on a 386 or a 486--and real-world tests confirm those results, as +shown in Figure 2. (All "actual performance" timings in this article were +performed with the Zen timer from Zen of Assembly Language, see "References" +for details. The systems used for the tests were: 8088, standard 4.77 MHz PC +XT; 80286, standard one-wait-state, 8 MHz PC AT; 386SX, 16 MHz noncached; +80386, 20 MHz externally cached with all instructions and data in external +cache for all tests except Listings One and Two; 80486, 25 MHz internally +cached, with all instructions and data in internal cache for all tests except +Listings One and Two.) + +In other words, this nifty, time-tested optimization is an anti-optimization +on the 386 and 486. + +Why is this? On the 386, DAA--a rarely used instruction--takes four cycles, +and on the 486 it takes two cycles, in both cases twice as long as the more +common instructions CMP and ADD; in contrast, on the 8088 all three +instructions are equally fast at four cycles. Also, the instruction-fetching +advantage that the 1-byte DAA provides on the 8088 means nothing on a cached +386. + +Nor is this an isolated example. Most oddball instructions, from AAA to +XCHG, have failed to keep pace with the core instructions--ADC, ADD, AND, +CALL, CMP, DEC, INC, Jcc, JMP, LEA, MOV, OR, POP, PUSH, RET, SBB, SUB, TEST, +and XOR--during the evolution from 8088 to 486. As we saw earlier, even LOOP +lags behind on the 386 and 486. Check your favorite tricks for yourself; +they might or might not hold up on the 386, but will most likely be +liabilities on the 486. Sorry, but I just report the news, and the news is: +Kiss most of those tricks goodbye as the 386 and 486 come to dominate the +market. (This means that hand-optimization in assembly language yields less +of a performance boost nowadays than it did when the 8088 was king; the +improvement is certainly significant, but rarely in the 200-500 percent range +anymore. Sic transit gloria mundi.) Most startling of all, string +instructions lose much of their allure as we move away from the 8088, hitting +bottom on the 486. + +The 486: All the Rules Change + +The 486 represents a fundamental break with 8088-style optimization. +Virtually all the old rules fail on the 486, where, incredibly, a move to or +from memory often takes just one cycle, but exchanging two registers takes +three cycles. The nonbranching core instructions mentioned earlier take only +one cycle on the 486 when operating on registers; MOV can, under most +conditions, access memory in one cycle; and CALL and JMP take only three +cycles, given a cache hit. However, noncore instructions take considerably +longer. XLAT takes four cycles; even STC and CLC take two cycles each. The +486's highly asymmetric execution times heavily favor core instructions and +defeat most pre-486 optimizations. + +Core instructions do have a weakness on the 486. While 486 MOVs involving +memory are remarkably fast, accessing memory for an operand to OR, ADD, or +the like costs cycles. Even with the 8K internal cache, memory is not as +fast as registers, except when MOV is used (and sometimes not even then), so +registers are still preferred operands. (AND [BX],1 is fast, at only three +cycles, but AND BX,1 takes only one cycle--three times as fast.) + +OUT should be avoided whenever possible on the 486, and likewise for IN. OUT +takes anywhere from 10 to 31 cycles, depending on processor mode and +privileges, more than an order of magnitude slower than MOV. The lousy +performance of OUT -- true on the 386 as well -- has important implications +for graphics applications. + +String instructions are so slow on the 486 that you should check cycle times +before using any string instruction other than the always superior REP MOV's. +For example, LODSB takes five cycles on the 486, but MOV AL,[SI]/INC SI takes +only two cycles; likewise for STOSB and MOV [DI],AL/INC DI. Listing One +(page 73) uses LODSB/STOSB to copy a string, converting lowercase to +uppercase while copying; Listing Two (page 73) uses MOV/INC instead. Figure +3 summarizes the performance of the two routines on a variety of processors; +note the diminishing effectiveness of string instructions on the newer +processors. Think long and hard before using string instructions other than +REP MOVS on the 486. + +Optimization for the 486 is really a whole new ball game. When optimizing +across the 80x86 family, the 486 will generally be the least of your worries +because it is so much faster than the rest of the family; anything that runs +adequately on any other processor will look terrific on the 486. Still, the +future surely holds millions of 486s, so it wouldn't hurt to keep one eye on +the 486 as you optimize. + +String Instructions: Fading Stars + +On the 8088, string instructions are so far superior to other instructions +that it's worth going to great lengths to use them, but they lose much of +that status on newer processors. One of the best things about string +instructions on the 8088 is that they require little instruction fetching, +because they're 1-byte instructions and because of the REP prefix; however, +instruction fetching is less of a bottleneck on newer processors. String +instructions also have superior cycle times on the 8088, but that advantage +fades on the 286 and 386 as well. + +On the 286, string instructions (when they do exactly what you need) are +still clearly better than the alternatives. On the 386, however, some string +instructions are, even under ideal circumstances, the best choice only by a +whisker, if at all. For example, since Day One, clearing a buffer has been +done with REP STOS. That's certainly faster than the looping MOV/ADD +approach shown in Listing Three (page 73), but on the 386 and 486 it's no +faster than the unrolled loop MOV/ADD approach of Listing Four (page 73), as +shown in Figure 4. (Actually, in my tests REP STOS was a fraction of a cycle +slower on the 386, and fractionally faster on the 486.) REP STOS is much +easier to code and more compact, so it's still the approach of choice for +buffer clearing--but it's not necessarily fastest on a 486 or fast-memory +386. This again demonstrates just how unreliable the old optimization rules +are on the newer processors. + +The point is not that you shouldn't use string instructions on the 386. REP +MOVs is the best way to move data, and the other string instructions are +compact and usually faster, especially on uncached systems. However, on the +386 it's no longer worth going to the trouble of juggling registers and +reorganizing data structures to use string instructions. Furthermore, when +you truly need maximum performance on the 386, check out nonstring +instructions in unrolled loops. It goes against every lesson learned in a +decade of 8088 programming, but avoiding string instructions sometimes pays +on the 386. + +The Siren Song of Memory Accesses + +Finally, here's a rule that's constant from the 8088 to the 486: Use the +registers. Avoid memory. + +Don't be fooled by the much faster memory access times of the 286 and 386. +The effective address calculation time of the 8088 is mostly gone, so MOV +AX,[BX] takes only five cycles on the 286, and ADD [SI],DX takes only seven +on the 386. That's so much faster than the 17 and 29 cycles, respectively, +that they take on the 8088 that you might start thinking that memory is +pretty much interchangeable with registers. + +Think again. MOV AX,BX is still more than twice as fast as MOV AX,[BX] on +the 286, and ADD SI,DX is more than three times as fast as ADD [SI],DX on the +386. Memory operands can also reduce performance by slowing instruction +fetching. Memory is fast on the 286 and 386. Registers are faster. Use +them as heavily as possible. + +Don't Branch + +Here's another rule that stays the same across the 80x86 family: Don't +branch. Branching suffers on the 8088 from lengthy cycle counts and emptying +the prefetch queue. Emptying the prefetch queue is a lesser but nonetheless +real problem in the post-8088 world, and the cycle counts of branches are +still killers. As Figure 4 indicates, it pays to eliminate branches by +unrolling loops or using repeated string instructions. + +Modern-Day Instruction Fetching + +Instruction fetching is the bugbear of 8088 performance; the 8088 simply +can't fetch instruction bytes as quickly as it can execute them, thanks to +its undersized bus. Minimizing all memory accesses, including instruction +fetches, is paramount on the 8088. + +Instruction fetching is less of a problem nowadays. Figure 5 shows the +maximum rates at which various processors can fetch instruction bytes; +clearly, matters have improved considerably since the 8088, although +instructions also execute in fewer cycles on the newer processors. Fetching +problems can occur on any 80x86 processor, even the 486, but the only +processors other than the 8088 that face major instruction fetching problems +are the one-wait-state 286 and the 386SX, although uncached 386s may also +outrun memory. However, the problems here are different from and less +serious than with the 8088. + +Consider: An 8088 executes a register ADD in three cycles, but requires eight +cycles to fetch that instruction, a fetch/execute ratio of 2.67. A +one-wait-state 286 requires three cycles to fetch a register ADD and executes +it in two cycles, a ratio of 1.5. A 386SX can fetch a register ADD in two +cycles, matching the execution time nicely, and a cached 386 can fetch two +register ADDs in the two cycles it takes to execute just one. For +register-only code--the sort of code critical loops should contain--the 386 +generally runs flat out, and the 286 and 386SX usually (not always, but +usually) outrun memory by only a little at worst. Greater fetching problems +can arise when working with large instructions or instruction sequences that +access memory nonstop, but those are uncommon in critical code. This is a +welcome change from the 8088, where small, register-only instructions tend to +suffer most from inadequate instruction fetching. + +Also, uncached 386 systems often use memory architectures that provide +zero-wait-state performance when memory is accessed sequentially. In +register-only code, instruction fetches are the only memory accesses, so +fetching proceeds at full speed when the registers are used heavily. + +So, is instruction fetching a problem in the post-8088 world? Should +instructions be kept short? + +Yes. Smaller instructions can help considerably on the one-wait-state 286 +and on the 386SX. Not as much as on the 8088, but it's still worth the +trouble. Even a cached 386 can suffer from fetching problems, although +that's fairly uncommon. For example, when several MOV WORD PTR [MemVar],0 +instructions are executed in a row, as might happen when initializing memory +variables, performance tends to fall far below rated speed, as shown in +Figure 6. The particular problem with MOV WORD PTR [MemVar],0 is that it +executes in just two (386) or three (286) cycles, yet has both an addressing +displacement field and a constant field. This eats up memory bandwidth by +requiring more instruction fetching. It also accesses memory, eating up +still more bandwidth. We'll see this again, and worse, when we discuss +protected mode. + +Generally, though, post-8088 processors with fast memory systems and +full-width buses run most instructions at pretty near their official cycle +times; for these systems, optimization consists mostly of counting cycles. +Slower memory or constricted buses (as in the 386SX) require that memory +accesses (both instruction fetches and operand accesses) be minimized as +well. Fortunately, the same sort of code--register only--meets both +requirements. + +Use the registers. Avoid constants. Avoid displacements. Don't branch. +That's the big picture. Don't sweat the details. + +Alignment: The Easy Optimization + +The 286, 386SX, and 386 take twice as long to access memory words at odd +addresses as at even addresses. The 386 takes twice as long to access memory +dwords at addresses that aren't multiples of four as those that are. You +should use ALIGN 2 to word align all word-sized data, and ALIGN 4 to dword +align all data that's accessed as a dword operand, as in: + +ALIGN 4 MemVar dd ? : MOV EAX,[MemVar] + +Alignment also applies to code; you may want to word or dword align the +starts of procedures, labels that can only be reached by branching, and the +tops of loops. (Code alignment matters only at branch targets, because only +the first instruction fetch after a branch can suffer from nonalignment.) +Dword alignment of code is optimal, and will help on the 386 even in real +mode, but word alignment will produce nearly as much improvement as dword +alignment without wasting nearly as many bytes. + +Alignment improves performance on many 80x86 systems without hindering it on +any. Recommended. + +Protected Mode + +There are two sorts of protected mode, 16-bit and 32-bit. The primary +optimization characteristic of 16-bit protected mode (OS/2 1.X, Rational DOS +Extender) is that it takes an ungodly long time to load a segment register +(for example, MOV ES,AX takes 17 cycles on a 286) so load segment registers +as infrequently as possible in 16-bit protected mode. + +Optimizing for 32-bit protected mode (OS/2 2.0, SCO Unix, Phar Lap DOS +Extender) is another matter entirely. Typically, no segment loads are needed +because of the flat address space. However, 32-bit protected mode code can +be bulky, and that can slow instruction fetching. Constants and addressing +displacements can be as large as 4 bytes each, and an extra byte, the SIB +byte, is required whenever two 32-bit registers are used to address an +operand or scaled addressing is used. So, for example, MOV DWORD PTR +[MemVar],0 is a 10-byte instruction in 32-bit protected mode. The +instruction is supposed to execute in two cycles, but even a 386 needs four +to six cycles to fetch it, plus another two cycles to access memory; a few +such instructions in a row can empty the prefetch queue and slow performance +considerably. The slowdown occurs more quickly and is more acute on a 386SX, +which needs 14 cycles to perform the memory accesses for this nominally +2-cycle instruction. + +Code can get even larger when 32-bit instructions are executed in 16-bit +segments, adding prefix bytes. (Avoid prefix bytes if you can; they increase +instruction size and can cost cycles.) Figure 7 shows actual versus nominal +cycle times of multiple MOV DWORD PTR [EBX*4+MemVar],0 instructions running +in a 16-bit segment. Although cache type (write-back, write-through) and +main-memory write time also affect the performance of stores to memory, there +is clearly a significant penalty for using several large (in this case, +13-byte) instructions in a row. + +Fortunately, this is a worst case, easily avoided by keeping constants and +displacements out of critical loops. For example, you should replace: + +ADDLOOP: MOV DWORD PTR BaseTable[EDX+EBX],0 ADD EBX,4 DEC ECX JNZ ADDLOOP + +with: + +LEA EBX,BaseTable[EDX+EBX] SUB EAX,EAX ADDLOOP: MOV [EBX],EAX ADD EBX,4 +DEC ECX JNZ ADDLOOP + +Better yet, use REP STOSD or unroll the loop! + +Happily, register-only instructions are no larger in 32-bit protected mode +than otherwise and run at or near their rated speed in 32-bit protected mode +on all processors. All in all, in protected mode it's more important than +ever to avoid large constants and displacements and to use the registers as +much as possible. + +Conclusion + +Optimization across the 80x86 family isn't as precise as 8088 optimization, +and it's a lot less fun, with fewer nifty tricks and less spectacular +speed-ups. Still, familiarity with the basix 80x86 optimization rules can +give you a decided advantage over programmers still laboring under the +delusion that the 286, 386, and 486 are merely faster 8088s. + +References + +Abrash, Michael. Zen of Assembly Language. Glenview, Ill.: Scott, Foresman, +1990. + +Barrenechea, Mark. "Peak Performance: On to the 486." Programmer's Journal, +(November-December 1990). + +Paterson, Tim. "Assembly Language Tricks of the Trade." Dr. Dobb's Journal +(March 1990). + +Turbo Assembler Quick Reference Guide. Borland International, 1990. + +i486 Microprocessor Programmer's Reference Manual. Intel Corporation, 1989. + +80386 Programmer's Reference Manual. Intel Corporation, 1986. + +Microsystems Components Handbook: Microprocessors Volume I. Intel +Corporation, 1985. diff --git a/16/scrasm/CONSTANT.INC b/16/scrasm/CONSTANT.INC new file mode 100644 index 00000000..02ce404b --- /dev/null +++ b/16/scrasm/CONSTANT.INC @@ -0,0 +1,127 @@ +PEL_READ_REG EQU 03C7h ;Color register, read address +PEL_WRITE_REG EQU 03C8h ;Color register, write address +PEL_DATA_REG EQU 03C9h ;Color register, data port +SC_INDEX equ 03C4h ;Sequence Controller Index +CRTC_INDEX equ 03D4h ;CRT Controller Index +MISC_OUTPUT equ 03C2h ;Miscellaneous Output register +SCREEN_SEG equ 0a000h ;segment of display memory in mode X +INPUT_STATUS_1 equ 03DAh ;Input Status 1 register +ATC_INDEX equ 03C0h ;Attribute Controller +START_ADDRESS_HIGH equ 0Ch ;bitmap start address high byte +START_ADDRESS_LOW equ 0Dh ;bitmap start address low byte +GC_INDEX EQU 03CEh +BIT_MASK EQU 08h +MAP_MASK EQU 02h + +ALL_COPY_BITS EQU 00000h+BIT_MASK +ALL_DRAW_BITS EQU 0FF00h+BIT_MASK + +SQUARE_WIDTH EQU 16 +SQUARE_HEIGHT EQU 16 +SCREEN_WIDTH EQU 320 +SCREEN_HEIGHT EQU 240 +VIRTUAL_WIDTH EQU 352 +VIRTUAL_HEIGHT EQU 240 + +PAGE_0 EQU 0 +PAGE_1 EQU 05540h ;05470h ;5540h +PAGE_2 EQU 0AA80h ;0A8E0h ;AA80h + +SCROLL_SPEED EQU 1 ; Don't let it go above 8! +MAGIC_NUM EQU 100 + +CPU8086 EQU 0 +CPU80286 EQU 1 +CPU80386 EQU 2 +CPU80486 EQU 3 + +;====================================================================== +; Key Assignments +;====================================================================== +kESC EQU 2 +kONE EQU 4 +kTWO EQU 6 +kTHREE EQU 8 +kFOUR EQU 10 +kFIVE EQU 12 +kSIX EQU 14 +kSEVEN EQU 16 +kEIGHT EQU 18 +kNINE EQU 20 +kZERO EQU 22 +kMINUS EQU 24 +kEQUAL EQU 26 +kBACKSPACE EQU 28 +kTAB EQU 30 +kQ EQU 32 +kW EQU 34 +kE EQU 36 +kR EQU 38 +kT EQU 40 +kY EQU 42 +kU EQU 44 +kI EQU 46 +kO EQU 48 +kP EQU 50 +kL_BRACE EQU 52 +kR_BRACE EQU 54 +kENTER EQU 56 +kCTRL EQU 58 +kA EQU 60 +kS EQU 62 +kD EQU 64 +kF EQU 66 +kG EQU 68 +kH EQU 70 +kJ EQU 72 +kK EQU 74 +kL EQU 76 +kSEMICOLON EQU 78 +kQUOTE EQU 80 +kBACKQUOTE EQU 82 +kL_SHIFT EQU 84 +kBACKSLASH EQU 86 +kZ EQU 88 +kX EQU 90 +kC EQU 92 +kV EQU 94 +kB EQU 96 +kN EQU 98 +kM EQU 100 +kCOMMA EQU 102 +kPERIOD EQU 104 +kSLASH EQU 106 +kR_SHIFT EQU 108 +kGREY_STAR EQU 110 +kALT EQU 112 +kSPACE EQU 114 +kCAPSLOCK EQU 116 +kF1 EQU 118 +kF2 EQU 120 +kF3 EQU 122 +kF4 EQU 124 +kF5 EQU 126 +kF6 EQU 128 +kF7 EQU 130 +kF8 EQU 132 +kF9 EQU 134 +kF10 EQU 136 +kNUMLOCK EQU 138 +kSCRLLOCK EQU 140 +kHOME EQU 142 +kUP EQU 144 +kPAGE_UP EQU 146 +kGREY_MINUS EQU 148 +kLEFT EQU 150 +kPAD_FIVE EQU 152 +kRIGHT EQU 154 +kGREY_PLUS EQU 156 +kEND EQU 158 +kDOWN EQU 160 +kPAGE_DOWN EQU 162 +kINSERT EQU 164 +kDELETE EQU 166 + +kF11 EQU 174 +kF12 EQU 176 + \ No newline at end of file diff --git a/16/scrasm/DIAGONAL.MAP b/16/scrasm/DIAGONAL.MAP new file mode 100644 index 0000000000000000000000000000000000000000..1fb5529e33c171ad8bbb93d881bd8933412de427 GIT binary patch literal 65057 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𝔚QZtmV7q6cwylM4GJ7x?Dd|yk%rt?Vy?(HsMe%7B=7XpbcZU^xCG7) z1&HLPtTH5NXvFwX$_^DA3T>*&#|Ea;Mv8VzJ{w-Vu<(Kg1&%KEdQaU*L+&dvSL7R1 zYf>DFcY12NLlJB8Im+KVti<2hYk*nHdW%)xhbm*Ng5h4K8&)%1cyPJs`9ac z>9moe-IC9S7cVTlph1D7i@n}cH`0*%O3W4c2GyDrhvA)`n(nYg8kfM?VF8iclvRc# z4UHHdR@q^L!=g=9`Pjg8+DOrE$!Eih7ZzU7puo|^Uhk~O*1(59+CYne38Z_aCUe=BsXQ1AxT3c#)nsS_~7tpQ&m1TFr7A1v|IAo z@ZyDq7c?kvbg|ca>P8xJUx~RQ-=JEP;_$rFQ_~%xNaGSXI|3k*o3hG~q@fYxBPcsU za0IleDjyq|P8%uOE%|JC@xsCj8WcFX*y}xYBMrH)#9WbYP_0RE1m5YX>5f>WaS5Cq z5fI5uS!GDl(1`I7l^roSBHC1yj}1(xjTG&cd^WszVc`W03LIVR^`5$shTKF4RfZ%DjTj$Q*-?X|qD@u#*uZq!NYQS|XTysZ7GBVxz|qBC@2MMU z$bBW|ihP4=O^T!PPESpDv?7g5;OuCCNN&n1Lz0F@jE|=5Xu;9YrmB2wU^;E2Xt(6E z;l&FJFKAHU=wh$;)QvRcz7lgqzCpDn#nE`Dr=~l4k;Wx(c62}_H)WL}Nkb#XM^|?A z;OJ;mRX#Q_oipgWN4Y{wxT#;{3 ztx0hV-s!37j#;E}37j1h5XnthWk}M{i19I%9Wyv4+EkT~4NRwv6z!ILHoSOY;ROu} z99``7p1P5S+*e|*$Tz6gq&Oz;^wf06D$=+F&W;6$;U( zrqf1>c1u1RUc9jIf(8YSF7|p)-AF_3D=}B(8&qpj9E*2)YPw?=XK&%{x6c z-EoREE`hV-03x|5s|-mR8ZkbOvf~8DL7S@bv4QEdk)qv_&xRK-EWDsWfuoDP-cvWy zko!u^75N6$niR+3ot~QRxJ4S5z}ayDk=&G3h9nJ*7#~;Jaf9QcO;!2Wz;xP3(Qe6S z!;2RdUeKVx(ZycxsT*m?eI@3Ke1mFDisSN5Pfd5cB8^Mn?0A4kZptb{l7>c%kEiT- z!ST?hs(frg@qS1C~$PK*L&(l8ggHWxgy`7 zT9e}Vywg+DouEkL5;!{nAd;K1%8;a?5#tjmJ3(*)w5ci|8<8a^XSfp_YoShI5$xT^hNYc=V@d=fkFgPLFRF#hn zOs9<$?UsBtym(>Z1q})uUF`Lqx{-$5S7NTnH>lR6I3e%!)O05*(zpc9P6UYLrmQj~ zX=udwM9NMSoCs~I%Etz#(?*JROFkQ3ys+?s1_h2T_Igj^Tmok&21IgGRvD5sG-7;WWhV|!j5bx}V*}G^BSpI-XQ#aC(`%26e`3BXR6er=Go|^8YMH-jD*+~JB+>}*@Bn^!ipH$gN zgOj37Rr%P!blOPKZpmlEix(DN(4fH4#a{2J8)?XWCFY8JgKABRlk!eaO?R>)jZ5I{ zWPnI+$|^&WhDMA}rtDMc&DePJ9&}DC2)3fKqNP1l_5z(BgQ9JcJkolXj4@_HZYwwQnXw0+3@0pg%>m^ zaCEWPd+J6Sa$kwLBHy4|lj7vO(^J!(qDbQsI6DO(lAE&1kffmz<5MU*MQ{qVsVW~E zm`)oh+AaBPc=5u*3mOzSy4dSIbt4VAuf$xDZ&0mCaSGn)sp(Exq;UzHoe~hqO<83~ z($I+UDV3cvI3?Otm5𝔚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𝔚QZtmV7q6cwylM z4GJ7x?Dd|yk%rt?Vy?(HsMe%-B=7XpbdM_1xCG7~1&HLPtTH5NXvFwY${rOw3T>*& z#|Ea;Mv8VzJ{w-Vu<(Kg1&%KEdQaU*L+&dvSL7R1Yf?OlcY12NM;B>a0%wl~L~>JB z8Im+KV*F@jj}9J9moe-IC9S7cVTlph1D7i@n}c zH`0*%O3W4c2GyDrkKvu3n(nbh8kfM?V*!!elvRc#4UHH-R@q~N$D&PD`Pjg8+DOrE z$!Eih7ZzU7puo|^Uhk~X>4(59+CZSe38Z_ zaQ1jWBsXQ1AxT3c#*bI__~7wqQ&m1TFr7A1v|IAo@ZyDq7c?kvbg|ca>P8xJUx~RQ z-=JEP;_7H1maS5C~5fI5uS!GDl(1`I9l|3F4RfZ%DjTk>w z*;9k3qD@u#*uZq!NYQS|XTysZ7GBVxz|qBC@2MMU$bBW|ihP4=O^T=TPESquv?7g5 z;OuFDNN&n1Lz0F@jGw0LX~EObrmB2wU^;E2Xt(6E;l&FJFKAHU=wh$;)QvRcz7lgq zzCpDn#nX7Fr>1*)k;Wx(_H;lbH)WL}Nkb#XPgnNz;OS^nRX#Q_oiAcfZ(>pgWN4Y{wxT#;{3tx53=-s!37o>`=E37kC>5Xnth zWk}M{i19O(Ju`SF+EkT~4NRwv6z!ILHoSOY;ROu}99``7p1P5S+*e|*$Tz6gq;U(rqf1>c1u1RUc9jIf(8YSF7|p) z-AF_3D=}B(8&qpjJd1aFYPx3^XK|%{x6c-E)dGE`hV>03x|5s|-mR8Zmy3 zvgZWPL7S@bv4QEdk)qv_&xRK-EWDsWfuoDP-cvWyko!u^75N6$niS9Bot~QRxkVb6 zz}a&Fk=&G3h9nJ*7(Z9pbA#uiO;!2Wz;xP3(Qe6S!;2RdUeKVx(ZycxsT*m?eI@3K ze1mFDis$l9Pfho{B8^Mn?0JAlZptb{l7>c%pQr43!Sm3js(frg@qS1C~$PK*L&(l8ggHWxgy`7T9e}Wywg+Dy`V_r5;%JSAd;K1 z%8;a?5#tvqdqMC5w5ci|8<S z>8a^nSfp_YoV^eb$xT^hNYc=V@e7r`FnA%_RF#hnOs9<$?UsBtym(>Z1q})uUF`Lq zx{-$5S7NTnH>lR6cp>lf)O0T@(zpc9UId8brmQj~X=udwMao_jya;Wo%Etz#(?*JR zOFkQ3ys+?s1_h2T_Igj zWiJk1j5bx}V*}G^BSpI-XQ#aC(`%26e z`3BXR6ffbOo|^8ZMH-jD*-HVD+>}*@Bn^!izf{>vgO{RBRr%P!blOPKZpmlEix(DN z(4fH4#a{2J8)?XWCFY8JgKABRm-0?eP4}`QjZ5I{Wq?R-$|^&WhDMBErtD?G%h0B( zd~9GkZKPOc&DePdwG$@C2;m~KqNP1 zl_5z(BgQXR_VVE6Xj4@_HZYwwQnXw0+3@0pg%>m^aCEWPd+J6Sa$kwLBHy4|lj7yP z(^J#EqDbQsIC}*klAE&1kffmz<5wtqMequ=sVW~Em`)oh+AaBPc=5u*3mOzSy4dSI zbt4VAuf$xDZ&0mC@e1DQsp(!>q;UzHy%G?~O<83~($I+UE0w)6cqQ6Ym5𝔚QZt zmV7q6cwylM4GJ7x?Dd|yk%rt?Vy?(HsMe%-CGYgqbgwGXxCG8#1&HLPtTH5NXvFwc z%3c+`3T>*&#|Ea;Mv8VzJ{w-Vu<(Kg1&%KEdQaU*L+&dvSL7R1Yf`+5cY12NR~Knq z0%xxVL~>JB8Im+KV*F}luMS>~HdW9moe-IC9S7cVTl zph1D7i@n}cH`0*%O3W4c2GyDrui>4Zn(nnl8kfM?YXOnmlvRc#4UHJTR@rNV*P=~T z`Pjg8+DOrE$!Eih7ZzU7puo|^Uhk~+EG(59+CZSeUZi`aQ1pYBsXQ1AxT3c#;;fQ`r!3wQ&m1TFr7A1v|IAo@ZyDq7c?kvbg|ca z>P8xJUx~RQ-=JEP;`O}KQ`5bnNaGSXdjlYno3hG~q@fYxHz<2U@CLN0Djyq|P8%uO zE%|JC@xsCj8WcFX*y}xYBMrH)#9WbYP_0Sv2HxqZ>E2kRaS5Eg5fI5uS!GDl(1`IH zmAx@|BidAzj}1(xjTG&cd^WszVc`W03LIVR^`5$shTKF4 zRfZ%DjTpaG*;|9RqD@u#*uZq!NYQS|XTysZ7GBVxz|qBC@2MMU$bBW|ihP4=O^Ubj zPESquwjzy7;OuRHNN&n1Lz0F@jNhj0ZNb~nrmB2wU^;E2Xt(6E;l&FJFKAHU=wh$; z)QvRcz7lgqzCpDn#oKtNr>1**k;Wx(_I5xdH)WL}Nkb#XZ&&vA;O%HrRX#Q_oipgWN4Y{wxT#;{3tx53?-s!37-dUt^ z37owX5XnthWk}M{i19m>y)$?x+EkT~4NRwv6z!ILHoSOY;ROu}99``7p1P5S+*e|* z$Tz6gq;U(rqf1>c1u1RUc9jI zf(8YSF7|p)-AF_3D=}B(8&qpjyo+~wYPxq9XG2Q&t(0G&ExTZe{Nd-iLz%{x6c-Fu2OE`hW603x|5 zs|-mR8Zmy4viAhc%->2+-!TZprs(frg@qS1C~$PK*L&(l8ggHWxgy`7T9e}aywg+DeV|C= z5;*$+Ad;K1%8;a?5#tXi`#|skw5ci|8<8a^HSfp_YoP7`w$xT^hNYc=V@duTCF!&(aRF#hnOs9<$?UsBtym(>Z z1q})uUF`Lqx{-$5S7NTnH>lR6_#p4})N~&z(zpc9J_Ly5rmQj~X=udwL&`oBd-X zQ#aC(`%26e`3BXR6d&Q8o|^8XMH-jD*+&79+>}*@Bn^!ie^l8=gO8$3Rr%P!blOPK zZpmlEix(DN(4fH4#a{2J8)?XWCFY8JgKABRkMd4WP4}@PjZ5I{V}M9*$|^&WhDMA( zrtD+E$Izy#d~9GkZKPKc&DeP`*@MY zC2;m}KqNP1l_5z(BgP+B_VM83Xj4@_HZYwwQnXw0+3@0pg%>m^aCEWPd+J6Sa$kwL zBHy4|lj7sN(^J!ZqDbQsIQs-3lAE&1kffmz<4-92MDPi;sVW~Em`)oh+AaBPc=5u* z3mOzSy4dSIbt4VAuf$xDZ&0mC@d@7Psp&phq;UzHeG(AKO<83~($I+UCzX9N_$1m? zm5𝔚QZtmV7q6cwylM4GJ7x?Dd|yk%rt?Vy?(HsMe(TB=7Xpbe}5HxCG8V1&HLP ztTH5NXvFwa%03l*3T>*&#|Ea;Mv8VzJ{w-Vu<(Kg1&%KEdQaU*L+&dvSL7R1Yf^lQ zcY12NPZw!i0%xBFL~>JB8Im+KV*F`kpAJ5aHdW9moe z-IC9S7cVTlph1D7i@n}cH`0*%O3W4c2GyDrpW&UJn(nhj8kfM?X91DilvRc#4UHIo zR@rBR&!SCL`Pjg8+DOrE$!Eih7ZzU7puo|^Uhk~q2A(59+Ca-e38Z_aQ1mXBsXQ1AxT3c#-CUA`QYP8xJUx~RQ-=JEP;`6-IQ`3E+NaGSX`vM@6o3hG~q@fYxFDUy$@CCG~ zDjyq|P8%uOE%|JC@xsCj8WcFX*y}xYBMrH)#9WbYP_0Sv1>WhY>AqN`aS5D#5fI5u zS!GDl(1`IDm3=YzBHC1yj}1(xjTG&cd^WszVc`W03LIVR^`5$shTKwRpny?(`h3` zyCt6uFJ4%9L4yKE7kj;@Zlodim6$8?4XQOMzRWv4HQiT=G%kU&uK*&sDXR=g8X7VF zin6Z+UqPFy^09&Gw2`9SlFx=0FD$&EL4l)-z1~wd(vbT~%oX_t)tVGv;hmnE?yE%_ zm%!Oq0g>F4RfZ%DjTnDb*;j+FqD@u#*uZq!NYQS|XTysZ7GBVxz|qBC@2MMU$bBW| zihP4=O^UDbPESquwIYp6;OuLFNN&n1Lz0F@jK8MrYr)shrmB2wU^;E2Xt(6E;l&FJ zFKAHU=wh$;)QvRcz7lgqzCpDn#n*VJr>6UQk;Wx(_H{rcH)WL}Nkb#XUsv|^;Ol5p zRX#Q_oi%7xb(|w~z;}SUg1|X7~ zvdWO8p%LS6DEmh64Ya8$9~+oX8!6f?`D}Rc!omw06gaxr>pgWN4Y{wxT#;{3tx53> z-s!37zFDMk37mZs5XnthWk}M{i19a-eKYtb+EkT~4NRwv6z!ILHoSOY;ROu}99``7 zp1P5S+*e|*$Tz6gr1&Q9^wf0UD$=+F&b|eR;U(rqf1> zc1u1RUc9jIf(8YSF7|p)-AF_3D=}B(8&qpje2aH_YPxS1XLT%{x6c-FJ#K zE`hV}03x|5s|-mR8ZrKkvhM`nL7S@bv4QEdk)qv_&xRK-EWDsWfuoDP-cvWyko!u^ z75N6$niSvRot~QRyG0t8z}a^Jk=&G3h9nJ*7=KsUcZ2VuO;!2Wz;xP3(Qe6S!;2Rd zUeKVx(ZycxsT*m?eI@3Ke1mFDitqAHPfho|B8^Mn?0bMnZptb{l7>c%zo+bb!S~Rn zs(frg@qS1C~$PK*L&(l8ggHWxgy`7T9e}Y zywg+D{h&zW5;*$-Ad;K1%8;a?5#t{y`$6ynw5ci|8<8a^{Sfp_Yoc$0G$xT^hNYc=V@eh^#F!&+bRF#hnOs9<$ z?UsBtym(>Z1q})uUF`Lqx{-$5S7NTnH>lR6_#yA~)O0^8(zpc9eguf*rmQj~X=udw zN6LN_{0MET%Etz#(?*JROFkQ3ys+?s1_h2T_Igj-XQ#aC(`%26e`3BXR6hGmeo|^8bMH-jD*-rtH+>}*@Bn^!i|5VvegP)>J zRr%P!blOPKZpmlEix(DN(4fH4#a{2J8)?XWCFY8JgKABRpYl#mP4}}RjZ5I{XMjj< z$|^&WhDMBkrtD|I&(Nl-d~9GkZKPS zc&DeP`+1SZC2;n0KqNP1l_5z(BgQ{h_VeK9Xj4@_HZYwwQnXw0+3@0pg%>m^aCEWP zd+J6Sa$kwLBHy4|lj7&R(^J#^qDbQsIQs=4lAE&1kffmz<6kKIMeqx>sVW~Em`)oh z+AaBPc=5u*3mOzSy4dSIbt4VAuf$xDZ&0mC@eAJRsp)=Mq;UzH{Spw#O<83~($I+U zFO~f=_$As@m5𝔚QZtmV7q6cwylM4GJ7x?Dd|yk%rt?Vy?(HsMe(TCGYgqbiXRn zxCG9A1&HLPtTH5NXvFwe%6=963T>*&#|Ea;Mv8VzJ{w-Vu<(Kg1&%KEdQaU*L+&dv zSL7R1Yf}7*cY12NUl(ay0%yMlL~>JB8Im+KV*G1mzYczlHdW zs`9ac>9moe-IC9S7cVTlph1D7i@n}cH`0*%O3W4c2GyDrzu}#pn(ntn8kfM?Zvm0q zlvRc#4UHK8R@rZZ-=a-b`Pjg8+DOrE$!Eih7ZzU7puo|^UhkCa-eUZi`aQ1sZBsXQ1AxT3c#=lqg`{4IzQ&m1TFr7A1 zv|IAo@ZyDq7c?kvbg|ca>P8xJUx~RQ-=JEP;`hAMQ`7ySNaGSX`vV}7o3hG~q@fYx zKPdY{@CUT1Djyq|P8%uOE%|JC@xsCj8WcFX*y}xYBMrH)#9WbYP_0Sv2j1za>Hb)x zaS5FL5fI5uS!GDl(1`ILmHjdJBidAzj}1(xjTG&cd^WszVc`W03LIVR^`5$shTK(c)HQir|G%kU&zW^e+ zDXR=g8X7VFi?Y82e?gn7^09&Gw2`9SlFx=0FD$&EL4l)-z1~wd(vbT~%oX_t)tVH4 z;hmnE?yp4}m%!Oy0g>F4RfZ%DjTrw`*6URk;Wx(_IE%eH)WL}Nkb#X ze^>VR;O}TtRX#Q_oipgWN4Y{wx zT#;{3tx53@-s!37{#m4P37q{C5XnthWk}M{i19y_{WJI{+EkT~4NRwv6z!ILHoSOY z;ROu}99``7p1P5S+*e|*$Tz6gr1&TA^wf0!D$=+F&i)06;U(rqf1>c1u1RUc9jIf(8YSF7|p)-AF_3D=}B(8&qpj{EK&bYPx?HXI zQ&t(0G&ExTZ)N`u{*5+OM8 z%{x6c-G7QSE`hWE03x|5s|-mR8ZrKlvi}7CL7S@bv4QEdk)qv_&xRK-EWDsWfuoDP z-cvWyko!u^75N6$niT)xot~QRzeO6Cz}bHRk=&G3h9nJ*82?wc% z|EKJK!T->vs(frg@qS1C~$PK*L&(l8ggHW Mxgy`7T9X6(KVmnBasU7T literal 0 HcmV?d00001 diff --git a/16/scrasm/GENMAP.C b/16/scrasm/GENMAP.C new file mode 100644 index 00000000..01652048 --- /dev/null +++ b/16/scrasm/GENMAP.C @@ -0,0 +1,99 @@ +#include +#include +#include +#include + +#define WIDTH 255 + +#define MAPNAME "Diagonal" +#define FILENAME "%s.MAP" +char fn[100] = FILENAME; +typedef unsigned char BYTE; +typedef unsigned short int WORD; +typedef BYTE ROW[WIDTH]; + +ROW r; + +#define MAGIC_NUM 100 +#define SQUARE_WIDTH 16 +#define SQUARE_HEIGHT 16 +#define SCREEN_WIDTH 320 +#define SCREEN_HEIGHT 200 +#define VIRTUAL_WIDTH 352 +#define VIRTUAL_HEIGHT 240 +typedef struct MAPHEADER { + BYTE name[12]; /* 12 Includes [n]=0 and [n+1]=26 */ + WORD width; /* 2 */ + WORD height; /* 2 */ + WORD extent; /* 2 */ + WORD off_x1; /* 2 */ + WORD off_y1; /* 2 */ + WORD off_x2; /* 2 */ + WORD off_y2; /* 2 */ + WORD x_wrap; /* 2 */ + WORD y_wrap; /* 2 */ + WORD magic; /* 2 */ + } MAPHEADER, far *LPMAPHEADER; +MAPHEADER mh; + +void main(int argc, char *argv[]) + { + FILE *fp; + int i,j; + BYTE b; + int width = WIDTH; + int height = WIDTH; + + if (argc > 1) { + width = atoi(argv[1]); + if (width > WIDTH) + width = WIDTH; + printf("Width = %d\n",width); + height=width; + if (argc > 2) { + height = atoi(argv[2]); + if (height > WIDTH) + height = WIDTH; + printf("Height = %d\n",height); + } + } + + sprintf(fn,FILENAME,MAPNAME); + fp = fopen(fn,"wb"); + if (!fp) { + printf("Couldn't open %s for write.\n",fn); + exit(1); + } + + memset(&mh, 0xFF, sizeof(MAPHEADER)); /* Will reveal missing initializing */ + strcpy((char *)mh.name,MAPNAME); + mh.name[8]=0; + mh.name[9]=26; /* Ctrl-Z */ + mh.width = (WORD)width; + mh.height = (WORD)height; + mh.extent = (WORD)((WORD)width * (WORD)height); + mh.off_x1 = (WORD)0; + mh.off_y1 = (WORD)0; + mh.off_x2 = (WORD)(((VIRTUAL_WIDTH / SQUARE_WIDTH) - 1) % width); + mh.off_y2 = (WORD)((((VIRTUAL_HEIGHT / SQUARE_HEIGHT) - 1) % height) * width); + mh.x_wrap = (WORD)width; + mh.y_wrap = (WORD)height; + mh.magic = MAGIC_NUM; + fwrite(&mh, 1, sizeof(MAPHEADER), fp); + + for (i = 0; iS}cLp`{3hWV5BL|H^FHw_`iRMp~j|)b_RH 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 bn$1GF5Xx_WerKb66~fPgpZ~4ebjJP%cYq1R literal 0 HcmV?d00001 diff --git a/16/scrasm/GENMAP.LNK b/16/scrasm/GENMAP.LNK new file mode 100644 index 00000000..95ee9882 --- /dev/null +++ b/16/scrasm/GENMAP.LNK @@ -0,0 +1 @@ +genmap.obj; diff --git a/16/scrasm/GENMAP.OBJ b/16/scrasm/GENMAP.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..6f1e7a9dc563d3e5bf1a4ff8a99df366280a0329 GIT binary patch literal 2543 zcmZ8jduSZx7XN*-v$M0ic}&wZ)Kcr_(x76EwZ6qilkBePHOa;#owRB*ZZ@;Y>b~5a zB#mISWWmIAA%AG8rD`>Dxp28yL~ua`(XkP3FNg@Dh=|~$B1+@h#uz)EZ+13D2TpQ+ z=QZd1&SUmTALLOzor-2#W0;kImsp32V|N2$M z-MO>>V0U|@t6vI++KKh-+&OTtH)KO%aO?`WwSmxq0k>^m2_b3}Lkiy07uny7;~sQc z%r7vT`v^6z3J27RRj$s>@SGRT^9=CF75*v#@cI}|$f&mj%Vmi;>4(BL2@S5zVvu3h z4LrX)kJ)#5G-`cgW9kX7N^b^++!s!OMwA9#wG#n7L+(P5<5eqmq1&ThH z7%|2IcLrKUeCX5@qhp2xf{Ey8CLK+pCEwcJ){DtubY#YpBk3!RKqjlF11chHycQhNwWhN`yhm!u23_39R07pA*RZnc}k-YH;6(DM467Xo*Tq146A!~Vule9R` zmn`(d34<(BdMdATCU4|o*(r)DG77nW{)ZCq9iR>_h07L}!mAc$rbYII>l`pYBw3RJ zX=hAfE?hn`O%}GowzVe8yIWKU7)aW7TJVRy4mL_AAwIo>Q6mBhfEJzo`sIH`C3>?XKZWESbsc zRDw%ziwJ;bV8cTrgI{flTY;F0CenVYJ`JuSMsuSR9Eiw)gBYEPtywv+L@jZv#7Sdz zKXb(jS3JzQ3swMZxQ4hg$=s8?{b^FzvLz@&JS#v#4MZr4M@x<*CN#qjfu$*@22!WJ zqzXW6KR6KLY%|2cNMBGUcC+H@iwsg*+vzqcELTTTN%7L`bcWi3p}xOk9+;n1QiRkP zPS)dW(}QP^7tg-03TMyLMV%_ZeF=Vwl82N}Jf>>~&n(M46HzUh$Wvw_m?CM3%27HqAr>9zh$L z|N78-IN1+Vq7L>EDMXhO?IPMkbSu#vL|xSJy=sj)sS4%^qJI;;p$dgJNoE!cAJB|^ zsn(j`6bs)ITUNbT;H~P`cw++#Zanip!dKB5c2V80g@Ws_1-r2W*Av=V04 zn-IaxI6#t7+=@qW8zyikW^fmt#ohQ9_Tp8v;cW!5gb+SO7~kR^{D4lJC+~~+Cw|Ah zkXaY%ST`D353XPlw6b2@$nL}KtPgwH0QR%}IK)(pvO#3n0Zg%jm}B?jIC}ukvj_1X zb_nmVA^e|d_?$h2uUQm7v0-~;FEPA!B^bMj7Iub6#WmOt9sk8vq}UF;!rXX(8NAhK z`ro3lv)8)Bze&{NTgb%?mqLIZ8BUj1)J*AxC`e+KxkxE$StIxJ@_9+j!A0((7E2p8 z=6aF#{%|y}bA6Wd65)6lCqVO@I!Xe2;k3Y_L5Bi zn`l{3`oBRc;k2ETN3nBCM^n0;Lo?acID3Y_ljFMTYI3jwNk44pX~V%Z$C-FsJAA!^ z8!LFKiklq$9!I~`(O2;{NQbq_Tr}(Gw?mrRhj~PvVp~^O>j@shk|D-%i=AqyLaPhfyU+!A@Z0< literal 0 HcmV?d00001 diff --git a/16/scrasm/GENPAL.C b/16/scrasm/GENPAL.C new file mode 100644 index 00000000..f913ae07 --- /dev/null +++ b/16/scrasm/GENPAL.C @@ -0,0 +1,51 @@ +#include +#include +#include +#include + +#define COLORS 256 +#define PALNAME "Diagonal" +#define FILENAME "%s.PAL" +char fn[100] = FILENAME; +typedef unsigned char BYTE; +typedef unsigned short int WORD; +typedef struct COLOR { + BYTE r,g,b; + } COLOR, far *LPCOLOR; + +void main() /* int argc, char *argv[]) */ + { + FILE *fp; + int i; + int colors = COLORS; + COLOR c; + int r,dr,g,dg,b,db; + + sprintf(fn,FILENAME,PALNAME); + fp = fopen(fn,"wb"); + if (!fp) { + printf("Couldn't open %s for write.\n",fn); + exit(1); + } + + r=0; dr=2; + g=0; dg=3; + b=0; db=5; + for (i = 0; i < colors; i++) { + c.r = (BYTE)r; r+=dr; + if (r > 63) { r = 63; dr = -dr; } + else if (r < 0) { r = 0; dr = -dr; } + c.g = (BYTE)g; g+=dg; + if (g > 63) { g = 63; dg = -dg; } + else if (g < 0) { g = 0; dg = -dg; } + c.b = (BYTE)b; b+=db; + if (b > 63) { b = 63; db = -db; } + else if (b < 0) { b = 0; db = -db; } + fwrite(&c, sizeof(c),1, fp); + printf("Palette %d\r",i); + } + fclose(fp); + printf("All done! \n"); + exit(0); + } + \ No newline at end of file diff --git a/16/scrasm/GENPAL.EXE b/16/scrasm/GENPAL.EXE new file mode 100644 index 0000000000000000000000000000000000000000..c242a3d46e6f1999bc6a3190db1193e9a7c694dd GIT binary patch literal 17676 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 vF@ju!+`%26v!Ei literal 0 HcmV?d00001 diff --git a/16/scrasm/GENPAL.LNK b/16/scrasm/GENPAL.LNK new file mode 100644 index 00000000..4b4ff212 --- /dev/null +++ b/16/scrasm/GENPAL.LNK @@ -0,0 +1 @@ +genpal.obj; diff --git a/16/scrasm/GENPAL.OBJ b/16/scrasm/GENPAL.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..ae94092e11c393af00468d5bbde72ee8db2d69b4 GIT binary patch literal 1895 zcmZ8hQD|Fb6#o8uZ*FeVWxZ{;;@sR)*E-#_tL{P6Nllwvr=&|*vdqD@YntA4aaj`Y zz3t}EZjd0ES)dOxR64AJK8qmaRSe9By}MT*gjPzavD8pH;`wh9DF$-+&iT&y|MUOn z`_COOlvyKJNM=V#a&K(dkIOWHRRyi=OX8$_`;1dw^@(C9P|VB zh;0P;q%PX)V))X7p=k!Vl{PjAd%O%^Dd=qpEwLqGsRt_S6Z*vgDacTE0T0G3lzV}% zBjMoLz*HzU8h&R2We<5`geF5+z5oFTW|Fh{Tr!IhYcv`NhdC^@0-+Cd$a2WtqdT00jF7|*4 zqMpu$vDk}yK6rIKnKJD;%a{R{6;S1r1Kd05P-jzDuUYmrD7sZJGdVjASx@t_;MO}1 zmu}q5*pw_W$~<3Ls{t!O;=)614UCLv%|rh%qU0^s<(j(7lJ06-#f2@{;wr#nY6G1( zsm3};c&Kdy549bEK244`Mfx;2T6fWB1EB1Rwq4d%D%uXywu=kfqo2gW7X1$gj9dCS`So9p@gdxNyxZ2K=+t-TFXHy zo3{+Q$tQ40@Pnkc>qkn(M~+8UAze>qavti{PRoQaV=4r<2{H#YIhy74R*R`Zy1?P4 z6FJKx8=Rl!XoI5+r`H{N+DCAWpq$EQ^QOgPR$8LUQUYY`fdrrG*0VF2dEM@Tz`|5u zFYQ3J@QS60i}8?`ps3P&3rEiF#y#Y>AX}MRhHmqv3d}v9)Uz3jmXZKf)-(C(xipsC zcr4S-QG)-qIz_C1SCS;?j_r+dP$=lhtCO6 zx+Y($hca)ww@K5 zB2KGiJ^`uoQAmO;6_`kdq!(=S@5W!UWI`lf(o;Fxu{kf%P@hg(2ImXJ%Vejs$=R;$ z=5{7)?4#`{y0f8(wj76@ef-2wStifnm^9$zb1cxqkZ48%G&Y?$z@>6*@=6J}Yj$^h z{BUg_gGc4Z6tJhWt3=1_2yGU!zz#dR^Hb3&Kb*_APt`u9Xd2fCo$S5;T~ha +#include +#include +#include + +#define WIDTH 256 + +#define FILENAME "DIAGONAL.TIL" +char fn[100] = FILENAME; +typedef unsigned char BYTE; +typedef BYTE ROW[16]; +typedef ROW BITMAP[16]; + +BITMAP b; +BITMAP c; + +BITMAP pattern={{1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0}, + {1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {1,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0}, + {1,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0}, + {1,0,0,1,0,0,0,0,0,0,0,2,0,0,0,0}, + {0,0,1,0,0,1,1,0,1,1,0,0,2,0,0,0}, + {0,0,1,0,0,1,2,0,1,2,0,0,2,0,0,0}, + {0,1,0,0,0,0,0,0,0,0,0,0,0,2,0,0}, + {0,1,0,0,0,0,0,0,0,0,0,0,0,2,0,0}, + {0,1,0,0,1,2,0,0,0,1,2,0,0,2,0,0}, + {0,0,1,0,1,2,1,1,1,1,2,0,2,0,0,0}, + {0,0,1,0,0,2,2,2,2,2,0,0,2,0,0,2}, + {0,0,0,1,0,0,0,0,0,0,0,2,0,0,0,2}, + {0,0,0,0,2,2,0,0,0,2,2,0,0,0,0,2}, + {0,0,0,0,0,0,2,2,2,0,0,0,0,0,2,2}, + {0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2}}; + +void copy_pattern(BITMAP b,BITMAP patt, BYTE l, BYTE m, BYTE h) + { + int x,y; + + for (y=0; y<16; y++) { + for (x=0; x<16; x++) { + switch (patt[y][x]) { + case 0: + b[y][x] = m; + break; + case 1: + b[y][x] = l; + break; + case 2: + b[y][x] = h; + break; + } + } + } + } + +/* Transforms linear to planar */ +void transform(BITMAP b,BITMAP c) + { + int x,y,p; + BYTE *pb = (BYTE *)c; + + for (p=0; p<4; p++) { + for (y=0; y<16; y++) { + for (x=0; x<16; x+=4) { + *(pb++) = b[y][x+p]; + } + } + } + } + +void main(int argc,char *argv[]) + { + FILE *fp; + int i; + int width = WIDTH; + + fp = fopen(fn,"wb"); + if (!fp) { + printf("Couldn't open %s for write.\n",fn); + exit(1); + } + if (argc > 1) { + width = atoi(argv[1]); + if (width > WIDTH) + width = WIDTH; + printf("Width = %d\n",width); + } + + for (i = 0; i< width; i++) { + BYTE less,more; + + less = (BYTE)((i + width - 1) % width); + more = (BYTE)((i + 1) % width); + copy_pattern(b, pattern, less, (BYTE)i, more); + transform(b,c); + fwrite(c, 16,16, fp); + printf("Square %d\r",i); + } + fclose(fp); + printf("All done! \n"); + exit(0); + } + \ No newline at end of file diff --git a/16/scrasm/GENSQ.EXE b/16/scrasm/GENSQ.EXE new file mode 100644 index 0000000000000000000000000000000000000000..71cf2657d4497bdedfdf4c4c967725933c1a712d GIT binary patch literal 18916 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 literal 0 HcmV?d00001 diff --git a/16/scrasm/INIT.INC b/16/scrasm/INIT.INC new file mode 100644 index 00000000..eddeeed4 --- /dev/null +++ b/16/scrasm/INIT.INC @@ -0,0 +1,375 @@ +;; Error messages +ERR_OK EQU 0 +msgErr0 db 'Later!',13,10,'$' +ERR_MEM EQU 1 +msgErr1 db 'Error 001: Out of memory?',13,10,'$' +ERR_CPU EQU 2 +msgErr2 db 'Error 002: CPU must be at least an 80386.',13,10,'$' +ERR_FILE EQU 3 +msgErr3 db 'Error 003: File error.',13,10,'$' +ERR_FILENOTFOUND EQU 4 +msgErr4 db 'Error 004: File not found.',13,10,'$' +msgtblError dw offset msgErr0, offset msgErr1, offset msgErr2, + offset msgErr3, offset msgErr4 +nError db 0 + +;; CPU name strings +CPUName86 DB "8088/8086$" +CPUName286 DB "80286DX/SX$" +CPUName386 DB "80386DX/SX$" +CPUName486 DB "80486DX/SX or better$" +CPUNameTable DW CPUName86,CPUName286,CPUName386,CPUName486 + +EVEN +msgCPUTypeIs DB "Your CPU type: $" +EVEN +msgCPUTypeIsEnd DB 13,10,'$' +nCPU DB 0 + +EVEN +msgPages DB 'Pages displayed: ' +strNumPages DB 6 dup (?),13,10,'$' + +EVEN +bufText DW 80*50 DUP (?) ; Needs this much to hold + ; a 50-line screen... +wCPos DW 0 +nDisplay DB 0 + +EVEN +fnMap1 db 'DIAGONAL.MAP',0 +fnTiles1 db 'DIAGONAL.TIL',0 +fnPalette db 'DIAGONAL.PAL',0 ; only one allowed, for now +fnMap2 db 'SCROLL.MAP',0 +fnTiles2 db 'SCROLL.TIL',0 + +fntblMap dw offset fnMap1,offset fnMap2 +fntblTiles dw offset fnTiles1,offset fnTiles2 +nMap dw 0 + +;; CPUType routine snatched from Ray Duncan's _Power Programming MASM_ +;; chapter 14. Reformatted to my style, but I left the code alone +;; except that it used to push a bunch of stuff, but doesn't any more +;; because I don't care what gets destroyed. +CPUType PROC near + pushf ; now try to clear bits 12-15 + pop ax ; of CPU flags + and ax,0fffh + push ax ; set modified CPU flags + popf + pushf + pop ax ; get flags again + and ax,0f000h ; if bits 12-15 are still + cmp ax,0f000h ; set, this is 8086/88 + jne cpu1 ; jump, not 8086/88 + mov nCPU,CPU8086 ; set nCPU = 86/88 CPU type + jmp cpux ; and exit + +cpu1: or ax,0f000h ; must be 286 or later, + push ax ; now try to set bits 12-15 + popf ; of CPU flags + pushf + pop ax ; if bits 12-15 can't be + and ax,0f000h ; set, this is a 286 + jnz cpu2 ; jump, not 80286 + mov nCPU,CPU80286 ; set nCPU = 286 CPU type + jmp cpux ; and exit + +cpu2: mov bx,sp ; 386 or later, save SP + and sp,not 3 ; avoid stack alignment fault + pushfd ; get value of EFLAGS + pop eax + mov ecx,eax ; save copy of EFLAGS + xor eax,40000h ; flip AC bit in EFLAGS + push eax ; try and force EFLAGS + popfd + pushfd ; get back EFLAGS value + pop eax + mov sp,bx ; restore old stack pointer + xor eax,ecx ; can AC bit be changed? + jnz cpu3 ; no, jump, not a 386 + mov nCPU,CPU80386 ; set nCPU = 386 CPU type + jmp cpux ; and exit + +cpu3: mov nCPU,CPU80486 ; set nCPU = 486 CPU type + +cpux: mov bl,nCPU + xor bh,bh + shl bx,1 + DOSPRINT + DOSPRINT CPUNameTable[bx] + DOSPRINT + ret ; return with nCPU = CPU type +CPUType ENDP + +;; Initialize: So far, all it does is make sure you have a 386 + +;; (because that's what I assembled the code for). +Initialize PROC near + ; Set DS = CS in this program, since data is local + mov ax,cs + mov segCode,ax ; Store the Code Segment + mov bx,ds + mov segPSP,bx ; Store the PSP Segment + mov ds,ax ; Set DS = CS + + ; Resize code to 64K + CODE_SIZE EQU 64 ; <- this is arbitrary. + ; ES already -> allocated segment + mov ah,4ah + mov bx,64*CODE_SIZE + int 21h + mov nError,ERR_MEM + jc TerminateError + +;; I've chosen not to implement sprites yet so that I can get this out +;; the door... +;; ; 320x200 buffer for sprite drawing. To draw sprites, first draw them +;; ; into this buffer, adding rectangles to the current rectangle list. +;; ; Then, use BUFFER_COPY to put out the buffers with the current +;; ; rectangle list to the screen. BUFFER_COPY will ensure minimal VGA +;; ; writing. +;; ; Create a buffer segment +;; mov bx,(320 * 200) / 16 +;; mov ah,48h +;; int 21h +;; mov nError,ERR_MEM +;; jc TerminateError +;; mov segBuffer,ax + + call CPUType + mov nError,ERR_CPU + cmp nCPU,2 + jl TerminateError + + mov ds,segCode + mov dx,offset fnPalette + call LoadPaletteFile + jc TerminateError + + call LoadIndex + jc TerminateError + + KEYB_START + + call Beginning ; Can display an entry screen here + + ; This is linked in from Michael Abrash's zen timer code. + ; (But I wrote the Click myself) + call Click + call ZTimerOn + + call MainLoop + + call ZTimerOff + call Click + + call Ending ; Can display an exit screen here + + KEYB_END + +Terminate: mov nError,ERR_OK +TerminateError: + mov ax,cs ;DOS functions require that DS point + mov ds,ax ; to text to be displayed on the screen + mov bh,0 + mov bl,nError + shl bx,1 + DOSPRINT msgtblError[bx] + + mov ax,pages + mov ds,segCode + mov si,offset strNumPages + call Int2Ascii + DOSPRINT + + call ZTimerReport + + mov al,nError + mov ah,4ch ; DOS Terminate + int 21h + ; Don't need to RET! We're outta here +Initialize ENDP + +;; Clicks the internal speaker. I use this to indicate that page timing +;; has started. +Click PROC + in al,61h + mov ah,al + or al,3 + out 61h,al + + mov cx,5000 ; (this is an arbitrary delay!) +spkr_on: loop spkr_on + mov al,ah + out 61h,al + ret +Click ENDP + +;; Copied from an old 8088 "Learn Assembly" book and changed a bit +Int2Ascii PROC + mov cx,6 + mov byte ptr cs:[si],' ' + mov byte ptr cs:[si+1],'0' + mov byte ptr cs:[si+2],'0' + mov byte ptr cs:[si+3],'0' + mov byte ptr cs:[si+4],'0' + mov byte ptr cs:[si+5],'0' + add si,6 + mov cx,10 + or ax,ax + jns clear_divide + neg ax + mov byte ptr cs:[si-6],'-' +clear_divide: mov dx,0 + div cx + add dx,'0' + dec si + mov cs:[si],dl + or ax,ax + jnz clear_divide + ret +Int2Ascii ENDP + +;; Given a filename at DS:DX, reads the file into memory and returns +;; a pointer to it as DX:0000. +;; Note that this routine obviously will only work correctly for +;; a file < 640k in size, but you can bring in files bigger than 64k. +;; This code comes from Future Crew's STMIK sampler "Mental Surgery" +;; and I commented it up to make it fit in with my stuff a little better. +;; Thank you, FC, for releasing that code! Several of the routines +;; in this program were inspired or helped along by having that source... +;; Most recently, added in error codes. +EVEN +LoadFile PROC NEAR + ;set: DX=offset to filename + ;return: DX=segment of file + + ; Open the datafile at DS:DX. + mov ax,3D00h ; 3D,00 -> Open file, read only + ; DS:DX already points at filename + int 21h ; returns AX=file handle + mov cl,ERR_FILENOTFOUND + jc ferror + mov bx,ax ; Store file handle in BX + mov si,bx ; and also in a variable + + ; Get the length of the file so we know how much to allocate + mov ax,4202h ; 42,02 -> Seek, signed from end + mov cx,0 ; CX:DX is a long file offset, + ; BX is already set as file handle + mov dx,0 ; zero in this case = end of file + int 21h ; (returns long offset in DX:AX) + mov cl,ERR_FILE + jc ferror + +;;; shr dx,1 ; This is original FC code, +;;; rcr ax,1 ; which I removed because the +;;; shr dx,1 ; 386 has a nice instruction +;;; rcr ax,1 ; to do this all! +;;; shr dx,1 ; But 286 users will want to +;;; rcr ax,1 ; return to this code, instead +;;; shr dx,1 ; of SHRD dx,ax,4 +;;; rcr ax,1 ; + + ; Now turn that long DX:AX into a number of paragraphs to allocate + ; for when we read the file. + shrd ax,dx,4 ; Divides long DX:AX by 4, + mov bx,ax ; and stores this in BX + inc bx ; HHMMMM? One more needed for small #'s + mov ah,48h ; 48 -> Allocate memory + ; BX already = # of paragraphs + int 21h + mov cl,ERR_MEM + jc ferror + mov di,ax ; store this in a variable + + ; Seek the file back to the beginning in order to read it into + ; the memory we just allocated. + mov ax,4200h ; 42,00 -> Seek, absolute offset + mov bx,si ; BX is the file handle. + mov cx,0 ; CX:DX is a long offset + mov dx,0 + int 21h + jc ferror + + ; Now read the file into memory + mov ds,di ; DS points at alloc'd memory +ReadBlock: mov ah,3fh ; 3F -> Read file + mov cx,32768 ; read 32768 bytes at a time + mov dx,0 ; DS:DX points at beginning of + int 21h ; this block of memory. + mov cl,ERR_FILE + jc ferror + mov dx,ds ; Offset DS by (32768/16), which + add dx,800h ; is the number of paragraphs in + mov ds,dx ; each block of 32768 bytes. + cmp ax,32768 ; Did we actually read 32768 bytes? + je ReadBlock ; If so, there's more to read... + ; Otherwise, we've read all the + ; data in the file. + + ; So now, close the file handle. + mov ah,3Eh ; 3E -> Close file + ; BX still is the file handle + int 21h + + ; Everything went ok. Return the segment in DX. + mov dx,di + mov nError,ERR_OK + ret +ferror: mov nError,cl + ret +LoadFile ENDP + +;; Eventually, this should load in an index of all data files to +;; allow for filenames to be specified outside of the program. The +;; goal is to make the program have no hardcoded filenames... +;; Of course, the structure of this index and its entries will be +;; hardcoded, as will the structures of all of the files it includes. +LoadIndex PROC near + ret +LoadIndex ENDP + +;; Save the current video mode and cursor position with standard +;; BIOS calls +SaveVideo PROC near + mov ah,0Fh + int 10h ; Get current display Mode + mov nDisplay,al + mov ah,03h + mov bh,0 + int 10h + mov wCPos,dx + + mov ds,segText + mov si,0 + mov es,segCode + mov di,offset bufText + mov cx,80*50 + rep movsw + ret +SaveVideo ENDP + +;; Restore the current video mode and cursor position with standard +;; BIOS calls +RestoreVideo PROC near + mov ah,00h + mov al,nDisplay + int 10h ; Get current display Mode + mov ah,02h + mov bh,0 + mov dx,wCPos + int 10h + + PAL_UPDATE ; When flipping into text mode, re-do the + ; palette because the BIOS changes it. + + mov es,segText + mov di,0 + mov ds,segCode + mov si,offset bufText + mov cx,80*50 + rep movsw + ret +RestoreVideo ENDP + \ No newline at end of file diff --git a/16/scrasm/KEYB.INC b/16/scrasm/KEYB.INC new file mode 100644 index 00000000..ef730cf0 --- /dev/null +++ b/16/scrasm/KEYB.INC @@ -0,0 +1,237 @@ +;; ==================================================================== +;; Macros +;; ==================================================================== +;; Jump if key pressed +JKEYP MACRO key,label + cmp byte ptr cs:_keyFlags[key+1],1 + je label + ENDM +;; Jump if key not pressed +JKEYNP MACRO key,label + cmp byte ptr cs:_keyFlags[key+1],1 + jne label + ENDM + +;; Note that JNKEY and JKEY both modify _flKeyChanged, so you cannot +;; use one after the other! In other words, +;; JKEYNP no_key +;; JKEYP yes_key ;<-- this will fail +;; will not work like you'd think it would. The second call (JKEYP) +;; will not know that a key has been pressed! +;; Jump if no key pressed: +JNKEY MACRO label + cmp cs:_flKeyChanged,0 + je label + mov cs:_flKeyChanged,0 ; <--- important! + ENDM +;; Jump if key pressed: +JKEY MACRO label + cmp cs:_flKeyChanged,0 + mov cs:_flKeyChanged,0 + jne label + ENDM + +;; Start keyboard interrupts +KEYB_START MACRO + call SwapInt9 + mov cs:_flKeyChanged,0 + ENDM + +;; Clear keyboard interrupts +KEYB_END MACRO + call SwapInt9 + ENDM + +;; Credit for these routines: Steve Dollins, Brown Computer Group. +;; I didn't write any of the code below -- just heisted it from some +;; stuff that he wrote and released! Very useful keyboard routines. +;; Any comments prefixed SDE were added by me. +_keyFlags dw 256 dup (0) ; SDE: since they only use 2 bits + ; per word, this is a tradeoff, + ; space for time + +oldint9_offset dw offset newint9 +oldint9_segment dw seg newint9 + +_flKeyChanged dw 0 + +;----------------------------------------------------------------------- +; void SwapInt9( void ) +; +; SwapInt9() exchanges the vector in oldint9_segment:oldint9_offset +; with the vector in the interrupt table for INT 9h. +;----------------------------------------------------------------------- + +SwapInt9 PROC far + mov ax,cs + mov ds,ax + + mov ax,03509h ; Get interrupt 09h + int 21h ; return in ES:BX + + mov ax,oldint9_segment + mov dx,oldint9_offset + push ds + mov ds,ax + mov ax,02509h ; Set new interrupt + int 21h ; to address in DS:DX + pop ds + + mov oldint9_segment,es ; Save the old interrupt + mov oldint9_offset,bx + ret +SwapInt9 ENDP + + +;----------------------------------------------------------------------- +; newint9 is the new keyboard interrupt (INT 9h). +; +; Reads the scan code from the keyboard and modifies the key +; flags table. The high byte is set to the position of the key, +; pressed=1, release=0. The low byte is set to 1 when the key +; is pressed and left unmodified when the key is released. +;----------------------------------------------------------------------- +newint9 PROC far + push ax + push bx + push ds + + mov ax,cs + mov ds,ax + + JKEYNP kCTRL,not_ctrlaltdel ; SDE code + JKEYNP kALT,not_ctrlaltdel ; To still allow ctrl- + JKEYNP kDELETE,not_ctrlaltdel ; alt-delete. Nothing + jmp ctrlaltdel ; worse than a total lockup! +not_ctrlaltdel: + + in ax,60h ; get scan code in AL, control byte in AH + mov bx,ax ; save a copy in BX + xchg ah,al ; swap to get control byte in AL + or al,80h ; clear keyboard + out 61h,al ; of interrupt + and al,7Fh + out 61h,al + mov al,20h ; send generic EOI to + out 20h,al ; PIC + + and bx,0007fh ; strip all but the scan code + shl bx,1 ; multiply by two to get our offset + + ; if the key was released, the high bit is set in the scan code + bt ax,15 ; move this high bit into the carry flag + setnc byte ptr [_keyFlags+bx+1] ; set "Is being pressed" flag + jc short int09done ; if the key was released, we're done + mov byte ptr [_keyFlags+bx],1 ; set "Has been pressed" flag + mov _flKeyChanged,1 ; state of keyboard has changed +int09done: + mov _flKeyChanged,1 ; state of keyboard has changed + pop ds + pop bx + pop ax + iret +ctrlaltdel: int 19h ; SDE -- added this. + ; Allows a reboot. +newint9 ENDP + +;; Defines the current key procedure (used as a jump-through) +kprocCur dw KprocDirect + +;; This is a keyboard procedure. Normally, this would control some +;; sprite, or something, and the screen would follow the sprite. For +;; the purposes of this code, though (namely, sprite-less scrolling) +;; it just directly affects ScrollDX and ScrollDY. +;; This keyproc is inertialess, use + and - to increase speed and +;; the up/down/left/right keys to move directions. +;; Pressing K will switch to the other keyprocedure on the fly. +;; P pauses the screen -- note that this is just for completely +;; freezing the screen... it doesn't return until you let go! + +EVEN +scroll_speed_x dw SCROLL_SPEED ; (defaults) +scroll_speed_y dw SCROLL_SPEED * VIRTUAL_WIDTH ; (defaults) +KprocDirect PROC near +chk_leftright: mov ax,0 + JKEYNP kRIGHT,not_right + mov ax,scroll_speed_x + mov ScrollDX,ax + jmp chk_updown +not_right: JKEYNP kLEFT,not_left + sub ax,scroll_speed_x + mov ScrollDX,ax + jmp chk_updown +not_left: mov ScrollDX,ax + +chk_updown: mov ax,0 + JKEYNP kUP,not_up + sub ax,scroll_speed_y + mov ScrollDY,ax + jmp chk_other +not_up: JKEYNP kDOWN,not_down + mov ax,scroll_speed_y + mov ScrollDY,ax + jmp chk_other +not_down: mov ScrollDY,ax + +chk_other: JKEYNP kK,not_k + mov kprocCur,KprocInertia +not_k: JKEYNP kM,not_m + mov bDoTransition,1 +not_m: JKEYNP kGREY_MINUS,not_minus + cmp scroll_speed_x,1 + jle not_minus + dec scroll_speed_x + sub scroll_speed_y,VIRTUAL_WIDTH +not_minus: JKEYNP kGREY_PLUS,not_plus + cmp scroll_speed_x,16 + jge not_plus + inc scroll_speed_x + add scroll_speed_y,VIRTUAL_WIDTH +not_plus: + +pause_key: JKEYP kP,pause_key + + ret +KprocDirect ENDP + +;; This keyproc has inertia, so + and - don't work. +;; Use up/down/left/right keys to increase speed in those directions. +;; Pressing K will switch to the other keyprocedure on the fly. +;; P pauses the screen -- note that this is just for completely +;; freezing the screen... it doesn't return until you let go! +KprocInertia PROC near +chk2_leftright: JKEYNP kRIGHT,not2_right + cmp ScrollDX,16 + je not2_right + inc ScrollDX + jmp chk2_updown +not2_right: JKEYNP kLEFT,not2_left + cmp ScrollDX,-16 + je not2_left + dec ScrollDX + jmp chk2_updown +not2_left: + +chk2_updown: JKEYNP kUP,not2_up + cmp ScrollDY,-VIRTUAL_WIDTH * 16 + je not2_up + add ScrollDY,-VIRTUAL_WIDTH + jmp chk2_other +not2_up: JKEYNP kDOWN,not2_down + cmp ScrollDY,VIRTUAL_WIDTH * 16 + je not2_down + add ScrollDY,VIRTUAL_WIDTH + jmp chk2_other +not2_down: + +chk2_other: JKEYNP kK,not2_k + mov kprocCur,KprocDirect +not2_k: JKEYNP kM,not2_m + mov bDoTransition,1 +not2_m: + +pause2_key: JKEYP kP,pause2_key + + ret +KprocInertia ENDP + \ No newline at end of file diff --git a/16/scrasm/LZTIMER.ASM b/16/scrasm/LZTIMER.ASM new file mode 100644 index 00000000..5fed7be1 --- /dev/null +++ b/16/scrasm/LZTIMER.ASM @@ -0,0 +1,636 @@ +; +; *** Listing 2-5 *** +; +; The long-period Zen timer. (LZTIMER.ASM) +; Uses the 8253 timer and the BIOS time-of-day count to time the +; performance of code that takes less than an hour to execute. +; Because interrupts are left on (in order to allow the timer +; interrupt to be recognized), this is less accurate than the +; precision Zen timer, so it is best used only to time code that takes +; more than about 54 milliseconds to execute (code that the precision +; Zen timer reports overflow on). Resolution is limited by the +; occurrence of timer interrupts. +; +; By Michael Abrash 4/26/89 +; +; Externally callable routines: +; +; ZTimerOn: Saves the BIOS time of day count and starts the +; long-period Zen timer. +; +; ZTimerOff: Stops the long-period Zen timer and saves the timer +; count and the BIOS time-of-day count. +; +; ZTimerReport: Prints the time that passed between starting and +; stopping the timer. +; +; Note: If either more than an hour passes or midnight falls between +; calls to ZTimerOn and ZTimerOff, an error is reported. For +; timing code that takes more than a few minutes to execute, +; either the DOS TIME command in a batch file before and after +; execution of the code to time or the use of the DOS +; time-of-day function in place of the long-period Zen timer is +; more than adequate. +; +; Note: The PS/2 version is assembled by setting the symbol PS2 to 1. +; PS2 must be set to 1 on PS/2 computers because the PS/2's +; timers are not compatible with an undocumented timer-stopping +; feature of the 8253; the alternative timing approach that +; must be used on PS/2 computers leaves a short window +; during which the timer 0 count and the BIOS timer count may +; not be synchronized. You should also set the PS2 symbol to +; 1 if you're getting erratic or obviously incorrect results. +; +; Note: When PS2 is 0, the code relies on an undocumented 8253 +; feature to get more reliable readings. It is possible that +; the 8253 (or whatever chip is emulating the 8253) may be put +; into an undefined or incorrect state when this feature is +; used. +; +; *************************************************************** +; * If your computer displays any hint of erratic behavior * +; * after the long-period Zen timer is used, such as the floppy * +; * drive failing to operate properly, reboot the system, set * +; * PS2 to 1 and leave it that way! * +; *************************************************************** +; +; Note: Each block of code being timed should ideally be run several +; times, with at least two similar readings required to +; establish a true measurement, in order to eliminate any +; variability caused by interrupts. +; +; Note: Interrupts must not be disabled for more than 54 ms at a +; stretch during the timing interval. Because interrupts +; are enabled, keys, mice, and other devices that generate +; interrupts should not be used during the timing interval. +; +; Note: Any extra code running off the timer interrupt (such as +; some memory-resident utilities) will increase the time +; measured by the Zen timer. +; +; Note: These routines can introduce inaccuracies of up to a few +; tenths of a second into the system clock count for each +; code section timed. Consequently, it's a good idea to +; reboot at the conclusion of timing sessions. (The +; battery-backed clock, if any, is not affected by the Zen +; timer.) +; +; All registers and all flags are preserved by all routines. +; + DOSSEG + .model small + .code + public ZTimerOn, ZTimerOff, ZTimerReport + +; +; Set PS2 to 0 to assemble for use on a fully 8253-compatible +; system; when PS2 is 0, the readings are more reliable if the +; computer supports the undocumented timer-stopping feature, +; but may be badly off if that feature is not supported. In +; fact, timer-stopping may interfere with your computer's +; overall operation by putting the 8253 into an undefined or +; incorrect state. Use with caution!!! +; +; Set PS2 to 1 to assemble for use on non-8253-compatible +; systems, including PS/2 computers; when PS2 is 1, readings +; may occasionally be off by 54 ms, but the code will work +; properly on all systems. +; +; A setting of 1 is safer and will work on more systems, +; while a setting of 0 produces more reliable results in systems +; which support the undocumented timer-stopping feature of the +; 8253. The choice is yours. +; +PS2 equ 1 +; +; Base address of the 8253 timer chip. +; +BASE_8253 equ 40h +; +; The address of the timer 0 count registers in the 8253. +; +TIMER_0_8253 equ BASE_8253 + 0 +; +; The address of the mode register in the 8253. +; +MODE_8253 equ BASE_8253 + 3 +; +; The address of the BIOS timer count variable in the BIOS +; data segment. +; +TIMER_COUNT equ 46ch +; +; Macro to emulate a POPF instruction in order to fix the bug in some +; 80286 chips which allows interrupts to occur during a POPF even when +; interrupts remain disabled. +; +MPOPF macro + local p1, p2 + jmp short p2 +p1: iret ;jump to pushed address & pop flags +p2: push cs ;construct far return address to + call p1 ; the next instruction + endm + +; +; Macro to delay briefly to ensure that enough time has elapsed +; between successive I/O accesses so that the device being accessed +; can respond to both accesses even on a very fast PC. +; +DELAY macro + jmp $+2 + jmp $+2 + jmp $+2 + endm + +StartBIOSCountLow dw ? ;BIOS count low word at the + ; start of the timing period +StartBIOSCountHigh dw ? ;BIOS count high word at the + ; start of the timing period +EndBIOSCountLow dw ? ;BIOS count low word at the + ; end of the timing period +EndBIOSCountHigh dw ? ;BIOS count high word at the + ; end of the timing period +EndTimedCount dw ? ;timer 0 count at the end of + ; the timing period +ReferenceCount dw ? ;number of counts required to + ; execute timer overhead code +; +; String printed to report results. +; +OutputStr label byte + db 0dh, 0ah, 'Timed count: ' +TimedCountStr db 10 dup (?) + db ' microseconds', 0dh, 0ah + db '$' +; +; Temporary storage for timed count as it's divided down by powers +; of ten when converting from doubleword binary to ASCII. +; +CurrentCountLow dw ? +CurrentCountHigh dw ? +; +; Powers of ten table used to perform division by 10 when doing +; doubleword conversion from binary to ASCII. +; +PowersOfTen label word + dd 1 + dd 10 + dd 100 + dd 1000 + dd 10000 + dd 100000 + dd 1000000 + dd 10000000 + dd 100000000 + dd 1000000000 +PowersOfTenEnd label word +; +; String printed to report that the high word of the BIOS count +; changed while timing (an hour elapsed or midnight was crossed), +; and so the count is invalid and the test needs to be rerun. +; +TurnOverStr label byte + db 0dh, 0ah + db '****************************************************' + db 0dh, 0ah + db '* Either midnight passed or an hour or more passed *' + db 0dh, 0ah + db '* while timing was in progress. If the former was *' + db 0dh, 0ah + db '* the case, please rerun the test; if the latter *' + db 0dh, 0ah + db '* was the case, the test code takes too long to *' + db 0dh, 0ah + db '* run to be timed by the long-period Zen timer. *' + db 0dh, 0ah + db '* Suggestions: use the DOS TIME command, the DOS *' + db 0dh, 0ah + db '* time function, or a watch. *' + db 0dh, 0ah + db '****************************************************' + db 0dh, 0ah + db '$' + +;******************************************************************** +;* Routine called to start timing. * +;******************************************************************** + +ZTimerOn proc near + +; +; Save the context of the program being timed. +; + push ax + pushf +; +; Set timer 0 of the 8253 to mode 2 (divide-by-N), to cause +; linear counting rather than count-by-two counting. Also stops +; timer 0 until the timer count is loaded, except on PS/2 +; computers. +; + mov al,00110100b ;mode 2 + out MODE_8253,al +; +; Set the timer count to 0, so we know we won't get another +; timer interrupt right away. +; Note: this introduces an inaccuracy of up to 54 ms in the system +; clock count each time it is executed. +; + DELAY + sub al,al + out TIMER_0_8253,al ;lsb + DELAY + out TIMER_0_8253,al ;msb +; +; In case interrupts are disabled, enable interrupts briefly to allow +; the interrupt generated when switching from mode 3 to mode 2 to be +; recognized. Interrupts must be enabled for at least 210 ns to allow +; time for that interrupt to occur. Here, 10 jumps are used for the +; delay to ensure that the delay time will be more than long enough +; even on a very fast PC. +; + pushf + sti + rept 10 + jmp $+2 + endm + MPOPF +; +; Store the timing start BIOS count. +; (Since the timer count was just set to 0, the BIOS count will +; stay the same for the next 54 ms, so we don't need to disable +; interrupts in order to avoid getting a half-changed count.) +; + push ds + sub ax,ax + mov ds,ax + mov ax,ds:[TIMER_COUNT+2] + mov cs:[StartBIOSCountHigh],ax + mov ax,ds:[TIMER_COUNT] + mov cs:[StartBIOSCountLow],ax + pop ds +; +; Set the timer count to 0 again to start the timing interval. +; + mov al,00110100b ;set up to load initial + out MODE_8253,al ; timer count + DELAY + sub al,al + out TIMER_0_8253,al ;load count lsb + DELAY + out TIMER_0_8253,al ;load count msb +; +; Restore the context of the program being timed and return to it. +; + MPOPF + pop ax + ret + +ZTimerOn endp + +;******************************************************************** +;* Routine called to stop timing and get count. * +;******************************************************************** + +ZTimerOff proc near + +; +; Save the context of the program being timed. +; + pushf + push ax + push cx +; +; In case interrupts are disabled, enable interrupts briefly to allow +; any pending timer interrupt to be handled. Interrupts must be +; enabled for at least 210 ns to allow time for that interrupt to +; occur. Here, 10 jumps are used for the delay to ensure that the +; delay time will be more than long enough even on a very fast PC. +; + sti + rept 10 + jmp $+2 + endm + +; +; Latch the timer count. +; + +if PS2 + + mov al,00000000b + out MODE_8253,al ;latch timer 0 count +; +; This is where a one-instruction-long window exists on the PS/2. +; The timer count and the BIOS count can lose synchronization; +; since the timer keeps counting after it's latched, it can turn +; over right after it's latched and cause the BIOS count to turn +; over before interrupts are disabled, leaving us with the timer +; count from before the timer turned over coupled with the BIOS +; count from after the timer turned over. The result is a count +; that's 54 ms too long. +; + +else + +; +; Set timer 0 to mode 2 (divide-by-N), waiting for a 2-byte count +; load, which stops timer 0 until the count is loaded. (Only works +; on fully 8253-compatible chips.) +; + mov al,00110100b ;mode 2 + out MODE_8253,al + DELAY + mov al,00000000b ;latch timer 0 count + out MODE_8253,al + +endif + + cli ;stop the BIOS count +; +; Read the BIOS count. (Since interrupts are disabled, the BIOS +; count won't change.) +; + push ds + sub ax,ax + mov ds,ax + mov ax,ds:[TIMER_COUNT+2] + mov cs:[EndBIOSCountHigh],ax + mov ax,ds:[TIMER_COUNT] + mov cs:[EndBIOSCountLow],ax + pop ds +; +; Read the timer count and save it. +; + in al,TIMER_0_8253 ;lsb + DELAY + mov ah,al + in al,TIMER_0_8253 ;msb + xchg ah,al + neg ax ;convert from countdown + ; remaining to elapsed + ; count + mov cs:[EndTimedCount],ax +; +; Restart timer 0, which is still waiting for an initial count +; to be loaded. +; + +ife PS2 + + DELAY + mov al,00110100b ;mode 2, waiting to load a + ; 2-byte count + out MODE_8253,al + DELAY + sub al,al + out TIMER_0_8253,al ;lsb + DELAY + mov al,ah + out TIMER_0_8253,al ;msb + DELAY + +endif + + sti ;let the BIOS count continue +; +; Time a zero-length code fragment, to get a reference for how +; much overhead this routine has. Time it 16 times and average it, +; for accuracy, rounding the result. +; + mov cs:[ReferenceCount],0 + mov cx,16 + cli ;interrupts off to allow a + ; precise reference count +RefLoop: + call ReferenceZTimerOn + call ReferenceZTimerOff + loop RefLoop + sti + add cs:[ReferenceCount],8 ;total + (0.5 * 16) + mov cl,4 + shr cs:[ReferenceCount],cl ;(total) / 16 + 0.5 +; +; Restore the context of the program being timed and return to it. +; + pop cx + pop ax + MPOPF + ret + +ZTimerOff endp + +; +; Called by ZTimerOff to start the timer for overhead measurements. +; + +ReferenceZTimerOn proc near +; +; Save the context of the program being timed. +; + push ax + pushf +; +; Set timer 0 of the 8253 to mode 2 (divide-by-N), to cause +; linear counting rather than count-by-two counting. +; + mov al,00110100b ;mode 2 + out MODE_8253,al +; +; Set the timer count to 0. +; + DELAY + sub al,al + out TIMER_0_8253,al ;lsb + DELAY + out TIMER_0_8253,al ;msb +; +; Restore the context of the program being timed and return to it. +; + MPOPF + pop ax + ret + +ReferenceZTimerOn endp + +; +; Called by ZTimerOff to stop the timer and add the result to +; ReferenceCount for overhead measurements. Doesn't need to look +; at the BIOS count because timing a zero-length code fragment +; isn't going to take anywhere near 54 ms. +; + +ReferenceZTimerOff proc near +; +; Save the context of the program being timed. +; + pushf + push ax + push cx + +; +; Match the interrupt-window delay in ZTimerOff. +; + sti + rept 10 + jmp $+2 + endm + + mov al,00000000b + out MODE_8253,al ;latch timer +; +; Read the count and save it. +; + DELAY + in al,TIMER_0_8253 ;lsb + DELAY + mov ah,al + in al,TIMER_0_8253 ;msb + xchg ah,al + neg ax ;convert from countdown + ; remaining to elapsed + ; count + add cs:[ReferenceCount],ax +; +; Restore the context and return. +; + pop cx + pop ax + MPOPF + ret + +ReferenceZTimerOff endp + +;******************************************************************** +;* Routine called to report timing results. * +;******************************************************************** + +ZTimerReport proc near + + pushf + push ax + push bx + push cx + push dx + push si + push di + push ds +; + push cs ;DOS functions require that DS point + pop ds ; to text to be displayed on the screen + assume ds:_TEXT +; +; See if midnight or more than an hour passed during timing. If so, +; notify the user. +; + mov ax,[StartBIOSCountHigh] + cmp ax,[EndBIOSCountHigh] + jz CalcBIOSTime ;hour count didn't change, + ; so everything's fine + inc ax + cmp ax,[EndBIOSCountHigh] + jnz TestTooLong ;midnight or two hour + ; boundaries passed, so the + ; results are no good + mov ax,[EndBIOSCountLow] + cmp ax,[StartBIOSCountLow] + jb CalcBIOSTime ;a single hour boundary + ; passed-that's OK, so long as + ; the total time wasn't more + ; than an hour + +; +; Over an hour elapsed or midnight passed during timing, which +; renders the results invalid. Notify the user. This misses the +; case where a multiple of 24 hours has passed, but we'll rely +; on the perspicacity of the user to detect that case. +; +TestTooLong: + mov ah,9 + mov dx,offset TurnOverStr + int 21h + jmp short ZTimerReportDone +; +; Convert the BIOS time to microseconds. +; +CalcBIOSTime: + mov ax,[EndBIOSCountLow] + sub ax,[StartBIOSCountLow] + mov dx,54925 ;number of microseconds each + ; BIOS count represents + mul dx + mov bx,ax ;set aside BIOS count in + mov cx,dx ; microseconds +; +; Convert timer count to microseconds. +; + mov ax,[EndTimedCount] + mov si,8381 + mul si + mov si,10000 + div si ;* .8381 = * 8381 / 10000 +; +; Add timer and BIOS counts together to get an overall time in +; microseconds. +; + add bx,ax + adc cx,0 +; +; Subtract the timer overhead and save the result. +; + mov ax,[ReferenceCount] + mov si,8381 ;convert the reference count + mul si ; to microseconds + mov si,10000 + div si ;* .8381 = * 8381 / 10000 + sub bx,ax + sbb cx,0 + mov [CurrentCountLow],bx + mov [CurrentCountHigh],cx +; +; Convert the result to an ASCII string by trial subtractions of +; powers of 10. +; + mov di,offset PowersOfTenEnd - offset PowersOfTen - 4 + mov si,offset TimedCountStr +CTSNextDigit: + mov bl,'0' +CTSLoop: + mov ax,[CurrentCountLow] + mov dx,[CurrentCountHigh] + sub ax,PowersOfTen[di] + sbb dx,PowersOfTen[di+2] + jc CTSNextPowerDown + inc bl + mov [CurrentCountLow],ax + mov [CurrentCountHigh],dx + jmp CTSLoop +CTSNextPowerDown: + mov [si],bl + inc si + sub di,4 + jns CTSNextDigit +; +; +; Print the results. +; + mov ah,9 + mov dx,offset OutputStr + int 21h +; +ZTimerReportDone: + pop ds + pop di + pop si + pop dx + pop cx + pop bx + pop ax + MPOPF + ret + +ZTimerReport endp + + end + \ No newline at end of file diff --git a/16/scrasm/LZTIMER.OBJ b/16/scrasm/LZTIMER.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..0511b4d5a24855619e478e21e5ac23c289a35415 GIT binary patch literal 3231 zcmbVP3v?7$8U7!W$L0YE?+_b?5{f*Uq=iZ$RUi*u4P?r$6aoSvJ4qIjoiIB~+M*H( zP#^^>Z!p*Zo?6kKLW`(Hph~i&NVJNZ^E>~ zZ);I=UHLOyG3n{9nOeTnk)H0HIVGpCz!{yFpCerICOnEnD7l4s`M0*lz{E^NiNg=1 z1wal=+~$D(rwJfB7N<*l7KkV@cxt->e23<|oC$!jMJ_3-&^wuyVM6F(nqFm?)(T$6 zj?UK7(l=?DWA`crU>BZjmga}I`9LoKU==&Y9_dDWj$MS}L zfI@7=y44cH@3ls&8yapg4g|H*Q(_uEy~OakeTi}D5+H$bqPRtAV}PVV01Yb< z#^!W|n$24QE?$pDJ!?ss$!o{NHa{e*sGQsep8y2 zhN=IjWr##omwPI7RlEWoZ<$(M>{C5nwaPTgOx@?pP$!kDf>bRvOtBhvvudNHv!vLk z4^yiuba7Wr-Sm6yzLxH@vQc8`=_0oM7Kc$ze_5Fz_ZVK^Xw@$i%5ZswPSrJO zO1=nLSy}9L4-0!cV@VRV)bA~kz+v{>iBVf6)86+A?v;x-|fch;TR=~Xgzi%+z|zV&-BO?wD1<7mD1%mW$sLTm1= z2k~9*l(Oc+<*_R-+&Cj+-OdP#O#$GyNpP#}A!y5nOE+(4)CynhJ|*M541k$4IwKza zUjzHU6op3pUlLG6x*MThb3QX|`mW+!$!-v!xt%s8a-S`KesXYnzc!r*-JqxST09JPaIFb&B0p7|IJ?eT1 zo)rM8n*hxCFOP~jSuI@cmsfpleC?;o^B?YaIO}&qz^x%cV4({G`!yjta8N@90w*+# zg}`Y|>_UN$?fROmgD$&XC^11p_75($>m?EuTnI7= zQxDugJ#iED!Y$MrcTgXEg;H=Q^~Il28vdO6;a*a4A3ch1QU<<7nYf=u;;(2l9-tgN zM!DEbbFhU<@Lh7_3DWV;REqCY8GbDuG5gf%wF`FAPhnp~$-^V;Yh539M$MZRyz~^xy zU%=UX5$Es~oX4$L${%4lx1pD>VikXkCby%-f5*jq4VQ2SewV+%@9}k9&UbJH1FdAF z7nx`kGp%NY)^HTnaWuWev9y*Qw2r&d4>^g}b24q_?zEMA&^GQ#JGc+M!YQmJrtdKD+?$^+0oDkFjcX?)qZp56wRC! z-bPN;$3P=$m;l)u<&j_^r79JarWm9uRn%WuL=P(_4N!cPu2?is@zW#9Vj84WQ--ps z;X@KRHY!=}S@H3riXJm2D=X{C2zylDDA~FKx;d?4)5@7t=**Q_e4RP{o*yFS~q=#r7qnY@-2sWm*4ajF4j$_WhO~byh|hs(af0<&bEfKy2wkM6b@? zU4(eu)V(FT-I6Nknf3@~S>T=%6;iSkn$RgJ&r{~Hk~_&Ag?_8bZwcavnak=g*rI5h z0LcQ~!m+~VvM^_HMTrzGHKue*OTKr$#ZV%+$3@tW_31<;<@!xA7Aw3y5uI`(?8igv zCI%wcEuvw#Dip_1e<4;DNWNdO7b&9qh;ZP@IhQX+Xwp|eqG-4~?-9@^BJ6L3mo8HO zz2hAjUa*L_OOW>wf*rI-Xq5%-o_LWa)n9}^k_#JSHC)P#Jv6N0W>w~p#%xXOcg+*! z&fh#+W{$=x4PWENA84p5jaxKKRvKT|a56OqWkzZKtIQhB*JUr z{Op>hYWM;*6=`ChYx=&1`}p|FE^OMP;b5idfQC!xxX3^wq3N84LzJeEH2eiMb!d2< z1EAqADIgdJa3E8|hqy&3i-s1F??fJ4pkW#ZM5g;Dw=9#HDX?9`Z*j}3QgPsrCh|kC JHR2C~^>0nZe=Yz3 literal 0 HcmV?d00001 diff --git a/16/scrasm/MAIN.ASM b/16/scrasm/MAIN.ASM new file mode 100644 index 00000000..1c33a0fb --- /dev/null +++ b/16/scrasm/MAIN.ASM @@ -0,0 +1,134 @@ +;;=======================================================================;; +;; ;; +;; Scrolling Routines -- main program ;; +;; ;; +;; All other INC files are included here. The main routines for the ;; +;; frame-by-frame execution loop are also here. Finally I tried to keep ;; +;; global variables stored in this file as well. ;; +;; ;; +;;=======================================================================;; + dosseg + .model small + .386 + + .code + extrn ZTimerOn:far, ZTimerOff:far, ZTimerReport:far + +INCLUDE constant.inc + + +DW_TABLE MACRO inc,num + count = 0 + number = 0 + WHILE (count LT num) + DW number + count = count + 1 + number = number + inc + ENDM + ENDM + +DOSPRINT MACRO st + mov ah,9 + mov dx,st + int 21h + ENDM + +EVEN +Mult320 label WORD +MultBufWidth label WORD + DW_TABLE 320,200 +MultVirtWidth label WORD + DW_TABLE (VIRTUAL_WIDTH/4),200 + +INCLUDE palette.inc +INCLUDE keyb.inc +INCLUDE modex.inc +INCLUDE page.inc +INCLUDE init.inc +INCLUDE map.inc +;INCLUDE sprite.inc NOT FOR NOW +INCLUDE scroll.inc + +;; Various segments that need to be filled in later... +EVEN +segVideo dw 0A000h ; videoram segment +segText dw 0B800h ; text segment +segMap dw -1 ; Map info segment +segTiles dw -1 ; Tile bitmap segment +segBuffer dw -1 ; Local 320x200 buffer segment +segCode dw -1 ; Code segment +segPSP dw -1 ; PSP segment +segPalette dw -1 ; Palette segment +segTextPal dw -1 ; Saved text palette + +EVEN +bDoTransition db 0 + +;; This routine is called for each frame. +;; Right now it just scrolls, but later all sprite animation would +;; occur here too. +EVEN +OneFrame PROC near + call Scroll ; Scrolls the screen +; call AnimateSprites ; prepares sprites on drawpage + jmp FlipPage ; shows drawpage... + ; no RET necessary +OneFrame ENDP + +;; Each frame -- call the frame motion code, then check for keyhit. +EVEN +MainLoop PROC NEAR +next_frame: call OneFrame + JNKEY next_frame + JKEYP kESC,all_done ; ESC -> quit, always + call kprocCur + mov al,bDoTransition + cmp al,0 + je next_frame +transition: FLASH_OFF 16,segPalette + mov bDoTransition,0 + mov ax,1 + sub ax,nMap + mov nMap,ax ; Flip maps + + call LoadData + call update_full ;<<<< + call OneFrame + FLASH_ON 16,segPalette + jmp next_frame +all_done: ret +MainLoop ENDP + +;; Beginning code -- Leaves text mode (saving the text screen) via +;; a fade. It loads the map data and draws one +;; frame before it fades on. +Beginning PROC near + NEW_PAL segTextPal + PAL_SAVE segTextPal + FADE_OFF 1,segTextPal + call SaveVideo + MODEX_START ; 320x200 Mode X graphics mode + PAL_BLACK + + call LoadData ; This call will change... + + call update_full ;<<<< + call OneFrame + FADE_ON 1,segPalette + ret +Beginning ENDP + +;; Ending code -- restore to text mode via a flash +Ending PROC near + FLASH_OFF 8,segPalette + call RestoreVideo + FLASH_ON 8,segTextPal + ret +Ending ENDP + + .data + + .stack 2048 + + END Initialize + \ No newline at end of file diff --git a/16/scrasm/MAIN.OBJ b/16/scrasm/MAIN.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..ff612818dd2a95532fff4a45d6d644adbf8a1b90 GIT binary patch literal 18324 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 $*.lnk + echo $(PROGRAM); >> $*.lnk + +scroll.exe: $(OBJS) scroll.lnk + link /CO @$*.lnk + +gensq.obj: $*.c + +gensq.lnk: makefile + echo $*.obj; > $*.lnk + +gensq.exe: $*.obj $*.lnk + +genmap.obj: $*.c + +genmap.lnk: makefile + echo $*.obj; > $*.lnk + +genmap.exe: $*.obj $*.lnk + +genpal.obj: $*.c + +genpal.lnk: makefile + echo $*.obj; > $*.lnk + +genpal.exe: $*.obj $*.lnk + + \ No newline at end of file diff --git a/16/scrasm/MAP.INC b/16/scrasm/MAP.INC new file mode 100644 index 00000000..c87494c2 --- /dev/null +++ b/16/scrasm/MAP.INC @@ -0,0 +1,413 @@ +;; MAP in own segment allows map of tiles to be up to 65536 tiles in area +;; which translates to about 16.8 million pixels of virtual screen. This +;; can be represented in almost any rectangle -- just set MAP_WIDTH. + +;; Sorry this code isn't commented -- I was working on it right up until +;; the point that I released this. You have any questions? Ask away +;; (my internet address is in the DOC file). + +MAPHEADER STRUCT, NONUNIQUE + MapName BYTE "" + Wid WORD 2 + Ht WORD 3 + Extent WORD 4 + OffX1 WORD 5 + OffY1 WORD 6 + OffX2 WORD 7 + OffY2 WORD 8 + WrapX WORD 9 + WrapY WORD 10 + Magic WORD 11 +MAPHEADER ENDS +MapInfo MAPHEADER <> + + +; In: DS:DX = offset of filename +LoadMapFile PROC near + mov ax,segMap + cmp ax,-1 + je map_not_loaded + sub ax,(SIZEOF MAPHEADER) / 16 + mov es,ax + mov ah,49h + int 21h + mov nError,ERR_MEM + jc lm_err + mov segMap,-1 + +map_not_loaded: call LoadFile + jc lm_err + + mov ds,dx + mov si,0 + mov ax,cs + mov es,ax + lea di,MapInfo + mov cx,(SIZEOF MAPHEADER) / 4 + rep movsd + + add dx,(SIZEOF MAPHEADER) / 16 + mov cs:segMap,dx + + mov BlankPage.Valid,0 + mov ShowPage.Valid,0 + mov DrawPage.Valid,0 + + mov upper_left,0 + mov ScrollPosX,0 + mov ScrollPosY,0 + mov ScrollDX,0 + mov ScrollDY,0 + +lm_err: ret +LoadMapFile ENDP + +LoadTilesFile PROC near + mov ax,segTiles + cmp ax,-1 + je tiles_not_loaded + mov es,ax + mov ah,49h + int 21h + mov nError,ERR_MEM + jc lt_err + mov segMap,-1 + +tiles_not_loaded: call LoadFile + jc lm_err + mov segTiles,dx + + mov BlankPage.Valid,0 + mov ShowPage.Valid,0 + mov DrawPage.Valid,0 + +lt_err: ret +LoadTilesFile ENDP + +EVEN +LoadData PROC near + ; Load squares from data file + mov bx,nMap + shl bx,1 + mov dx,fntblTiles[bx] + mov ds,segCode + call LoadTilesFile + ; returns Carry if error + jc load_error + + ; Load map from data file + mov ds,segCode + mov bx,nMap + shl bx,1 + mov dx,fntblMap[bx] + call LoadMapFile + ; returns Carry if error + +load_error: ret +LoadData ENDP + +EVEN +update_full PROC + mov ds,segTiles + mov es,segVideo + mov fs,segMap + + mov dx,SC_INDEX + mov al,MAP_MASK + out dx,al + + mov di,DrawPage.Address + add di,upper_left + mov bp,MapInfo.OffX1 + add bp,MapInfo.OffY1 + + mov dx,MapInfo.WrapX + + mov ch,(VIRTUAL_WIDTH/SQUARE_WIDTH) +draw_full_loop: push cx + push si + push dx + + mov al,11h + mov si,0 + +update_f_loop: mov dx,SC_INDEX + 1 + out dx,al + push bp + call draw_col + pop bp + sub di,(VIRTUAL_WIDTH * VIRTUAL_HEIGHT) / 4 + add si,(SQUARE_WIDTH * SQUARE_HEIGHT) / 4 + shl al,1 + jnc update_f_loop + + pop dx + dec dx + jnz update_f_go_on + mov dx,MapInfo.Wid + sub bp,dx +update_f_go_on: inc bp + pop si + add di,(SQUARE_WIDTH/ 4) + pop cx + dec ch + jnz draw_full_loop + + + + + + + + + + + + mov dx,GC_INDEX + mov ax,ALL_COPY_BITS + out dx,ax + + mov dx,SC_INDEX + mov ax,0F02h + out dx,ax + + mov ds,segVideo + mov si,DrawPage.Address + add si,upper_left + mov es,segVideo + mov di,BlankPage.Address + add di,upper_left + mov cx,(VIRTUAL_WIDTH * VIRTUAL_HEIGHT) / 4 + rep movsb + mov si,DrawPage.Address + add si,upper_left + mov di,ShowPage.Address + add di,upper_left + mov cx,(VIRTUAL_WIDTH * VIRTUAL_HEIGHT) / 4 + rep movsb + + mov dx,GC_INDEX + mov ax,ALL_DRAW_BITS + out dx,ax + + ret +update_full ENDP + +EVEN +update_left PROC + mov ds,cs:segTiles + mov es,cs:segVideo + mov fs,cs:segMap + + mov dx,SC_INDEX + mov al,MAP_MASK + out dx,al + + mov al,011h + mov si,0 + mov di,cs:DrawPage.Address + add di,cs:upper_left ; becomes DI later + mov bp,MapInfo.OffX1 + add bp,MapInfo.OffY1 + +update_l_loop: mov dx,SC_INDEX + 1 + out dx,al + push bp + call draw_col + pop bp + sub di,(VIRTUAL_WIDTH * VIRTUAL_HEIGHT) / 4 + add si,(SQUARE_WIDTH * SQUARE_HEIGHT) / 4 + shl al,1 + jnc update_l_loop + + ret +update_left ENDP + +EVEN +update_right PROC near + mov ds,cs:segTiles + mov es,cs:segVideo + mov fs,cs:segMap + + mov dx,SC_INDEX + mov al,MAP_MASK + out dx,al + + mov bp,MapInfo.OffX2 + add bp,MapInfo.OffY1 + + mov al,011h + mov si,0 + + mov di,cs:DrawPage.Address ; becomes DI + add di,cs:upper_left + add di,(VIRTUAL_WIDTH - SQUARE_WIDTH) / 4 + +update_r_loop: mov dx,SC_INDEX + 1 + out dx,al + + push bp + call draw_col + pop bp + sub di,(VIRTUAL_WIDTH * VIRTUAL_HEIGHT) / 4 + add si,(SQUARE_WIDTH * SQUARE_HEIGHT) / 4 + shl al,1 + jnc update_r_loop + + ret +update_right ENDP + +EVEN +update_top PROC + mov ds,cs:segTiles + mov es,cs:segVideo + mov fs,cs:segMap + + mov dx,SC_INDEX + mov al,MAP_MASK + out dx,al + + mov di,cs:DrawPage.Address + add di,cs:upper_left + mov bp,MapInfo.OffX1 + add bp,MapInfo.OffY1 + + mov al,011h + mov si,0 + +update_top_loop: + mov dx,SC_INDEX + 1 + out dx,al + push bp + call draw_row + pop bp + sub di,VIRTUAL_WIDTH / 4 + add si,(SQUARE_WIDTH * SQUARE_HEIGHT) / 4 + shl al,1 + jnc update_top_loop + + ret +update_top ENDP + +EVEN +update_bottom PROC + mov ds,cs:segTiles + mov es,cs:segVideo + mov fs,cs:segMap + + mov dx,SC_INDEX + mov al,MAP_MASK + out dx,al + + mov di,cs:DrawPage.Address + add di,cs:upper_left + add di,(VIRTUAL_WIDTH * (VIRTUAL_HEIGHT - SQUARE_HEIGHT)) / 4 + mov bp,MapInfo.OffX1 + add bp,MapInfo.OffY2 + + mov al,011h + mov si,0 + +update_bottom_loop: + mov dx,SC_INDEX + 1 + out dx,al + push bp + call draw_row + pop bp + sub di,VIRTUAL_WIDTH / 4 + add si,(SQUARE_WIDTH * SQUARE_HEIGHT) / 4 + shl al,1 + jnc update_bottom_loop + + ret +update_bottom ENDP + +; Draws ONE plane of a single col +EVEN +draw_col PROC near + ; DI->upper left corner of col to draw + ; BP->col of map to draw + ; SI used to point at tiles + ; AX,CX used + ; BX used to push SI + ; DX unused + shl eax,16 ; save it + mov ax,MapInfo.WrapY + + mov cl,(VIRTUAL_HEIGHT / SQUARE_HEIGHT) +do_col_loop: mov bx,si + mov bh,byte ptr fs:[bp] ; change tile # + + mov ch,SQUARE_HEIGHT +do_col_sq_loop: mov dl,byte ptr ds:[bx+2] + mov dh,byte ptr ds:[bx+3] + shl edx,16 + mov dl,byte ptr ds:[bx+0] + mov dh,byte ptr ds:[bx+1] + mov es:[di],edx ; 32-bit write + add di,VIRTUAL_WIDTH / 4 + add bx,4 + dec ch + jnz do_col_sq_loop + + add bp,MapInfo.Wid + dec ax + jnz yayaya + mov ax,MapInfo.Ht + sub bp,MapInfo.Extent +yayaya: + + dec cl + jnz do_col_loop + + shr eax,16 ; restore it + + ret +draw_col ENDP + +; Draws ONE plane of a single row +EVEN +draw_row PROC near + push ax +; shl eax,16 ; save ax + + mov ax,MapInfo.WrapX + + ; DI->upper left corner of row to draw + ; BP->row of map to draw + ; SI used to point at tiles + ; AX,CX used + ; BX used to push SI + ; DX unused + + mov cl,(VIRTUAL_WIDTH / SQUARE_WIDTH) +do_row_loop: mov bx,si + mov bh,byte ptr fs:[bp] ; change tile # + + mov ch,SQUARE_HEIGHT +do_row_sq_loop: mov dl,byte ptr ds:[bx+2] + mov dh,byte ptr ds:[bx+3] + shl edx,16 + mov dl,byte ptr ds:[bx+0] + mov dh,byte ptr ds:[bx+1] + mov es:[di],edx + add di,(VIRTUAL_WIDTH / 4) + add bx,4 + dec ch + jnz do_row_sq_loop + + add di,(-VIRTUAL_WIDTH*SQUARE_HEIGHT + SQUARE_WIDTH) / 4 + inc bp + dec ax + jnz yayaya2 + mov ax,MapInfo.Wid + sub bp,ax +yayaya2: + dec cl + jnz do_row_loop + +; shr eax,16 ; restore it + pop ax + ret +draw_row ENDP + \ No newline at end of file diff --git a/16/scrasm/MODEX.INC b/16/scrasm/MODEX.INC new file mode 100644 index 00000000..174aa354 --- /dev/null +++ b/16/scrasm/MODEX.INC @@ -0,0 +1,88 @@ +; ==================================================================== +; Entry points: +; ==================================================================== +MODEX_START MACRO + mov ax,13h ;let the BIOS set standard 256-color + int 10h ; mode (320x200 linear) +; PALETTE_BLACK + call ModifyForX + ENDM + +; ==================================================================== +; This is MODE-X code from Dr. Dobb's Journal, by Michael Abrash. +; I modified it from 320x240 back to 320x200, and then to 512 virtual +; width, for scrolling purposes. +; ==================================================================== + +; Mode X (320x240, 256 colors) mode set routine. Works on all VGAs. +; **************************************************************** +; * Revised 6/19/91 to select correct clock; fixes vertical roll * +; * problems on fixed-frequency (IBM 851X-type) monitors. * +; **************************************************************** +; Modified from public-domain mode set code by John Bridges. + +; Index/data pairs for CRT Controller registers that differ between +; mode 13h and mode X. +CRTParms label word +; dw 00d06h ;vertical total +; dw 03e07h ;overflow (bit 8 of vertical counts) +; dw 04109h ;cell height (2 to double-scan) +; dw 0ea10h ;v sync start +; dw 0ac11h ;v sync end and protect cr0-cr7 +; dw 0df12h ;vertical displayed = 480 + dw 00014h ;turn off dword mode * +; dw 0e715h ;v blank start +; dw 00616h ;v blank end + dw 0e317h ;turn on byte mode * + + dw (VIRTUAL_WIDTH*32)+13h ; width of screen = VWid NEW +; dw 09012h ;vertical displayed = 400 (already like this) +CRT_PARM_LENGTH equ (($-CRTParms)/2) + +ModifyForX PROC near + mov dx,SC_INDEX + mov ax,0604h + out dx,ax ;disable chain4 mode + mov ax,0100h + out dx,ax ;synchronous reset while setting Misc + ; Output for safety, even though clock + ; unchanged + mov dx,MISC_OUTPUT + mov al,0e3h + out dx,al ;select 25 MHz dot clock & 60 Hz scanning rate + + mov dx,SC_INDEX + mov ax,0300h + out dx,ax ;undo reset (restart sequencer) + + mov dx,CRTC_INDEX ;reprogram the CRT Controller + mov al,11h ;VSync End reg contains register write + out dx,al ; protect bit + inc dx ;CRT Controller Data register + in al,dx ;get current VSync End register setting + and al,7fh ;remove write protect on various + out dx,al ; CRTC registers + dec dx ;CRT Controller Index + cld + push cs + pop ds + mov si,offset CRTParms ;point to CRT parameter table + mov cx,CRT_PARM_LENGTH ;# of table entries +SetCRTParmsLoop: + lodsw ;get the next CRT Index/Data pair + out dx,ax ;set the next CRT Index/Data pair + loop SetCRTParmsLoop + + mov dx,SC_INDEX + mov ax,0f02h + out dx,ax ;enable writes to all four planes + mov ax,SCREEN_SEG ;now clear all display memory, 8 pixels + mov es,ax ; at a time + sub di,di ;point ES:DI to display memory + sub ax,ax ;clear to zero-value pixels + mov cx,8000h ;# of words in display memory + rep stosw ;clear all of display memory + + ret +ModifyForX ENDP + \ No newline at end of file diff --git a/16/scrasm/PAGE.INC b/16/scrasm/PAGE.INC new file mode 100644 index 00000000..a55bdf0b --- /dev/null +++ b/16/scrasm/PAGE.INC @@ -0,0 +1,109 @@ +;; ==================================================================== +;; (Code follows) +;; ==================================================================== + +EVEN +upper_left dw 0 ; Stores upper left corner offset + ; relative to page offset. +pages dw 0 ; for counting frame-per-sec + +PAGE_INFO STRUCT 2,NONUNIQUE + Address dw 0 + UpperLeftAddress dw 0 + MapPosX dw 0 + MapPosY dw 0 + Alignment db 0 + AlignmentMask db 0 + ScrollOffset dw 0 + Rectangles dw 0 + Valid db 0 +PAGE_INFO ENDS + +DrawPage PAGE_INFO +ShowPage PAGE_INFO +BlankPage PAGE_INFO + +ROTATE3 MACRO reg,item + mov reg,cs:ShowPage.item + xchg reg,cs:BlankPage.item + xchg reg,cs:DrawPage.item + mov cs:ShowPage.item,reg + ENDM ; Leaves ShowPage.item in reg! + +;; This procedure is used to flip between the three available pages. +;; Originally from Dr. Dobb's Journal's Graphics Programming column by +;; Michael Abrash, I've reworked the code to be more specific to my +;; own purposes, and commented it more. +EVEN +FlipPage PROC near + ; This series of instructions circles the show_page, blank_page, + ; and draw page appropriately and leaves the current page to show + ; in AX. Note that it's a lot more instructions than it looks like, + ; but I unrolled the copy loop for speed. So-so good idea, because + ; if you add a field and forget to rotate it, it could mean trouble! + ROTATE3 ax,Rectangles + ROTATE3 ax,ScrollOffset + ROTATE3 ax,MapPosX + ROTATE3 ax,MapPosY +; ROTATE3 al,AlignmentMask SPRITES ... + ROTATE3 al,Alignment + mov di,ax ; DI = scroll offset low, and + ; garbage in the high bits... + and di,3 ; DI = pixel pan, 0 to 3. + shl di,1 ; Mode X requires 0 2 4 or 6. + ROTATE3 ax,Address + ROTATE3 al,Valid + ROTATE3 ax,UpperLeftAddress ; Leaves AX=ShowPage.ULAddr + + add ax,cs:ShowPage.ScrollOffset + + ; AX is set up to be the current show page already. + ; By pre-loading BX with the low-address set code, and CX with + ; the high-address set code, we can more quickly flip the page + ; after the vertical retrace period. + mov bl,START_ADDRESS_LOW ;preload for fastest + mov bh,al ; flipping once display + mov cl,START_ADDRESS_HIGH ; enable is detected + mov ch,ah + + ; Wait for display enable to be active (status is active low), to be + ; sure both halves of the start address will take in the same frame. + mov dx,INPUT_STATUS_1 +WaitDE: in al,dx + test al,01h + jnz WaitDE ;display enable is active low (0 = active) + + ; Set the start offset in display memory of the page to display. + mov dx,CRTC_INDEX + mov ax,bx + out dx,ax ;start address low + mov ax,cx + out dx,ax ;start address high + + ; Now wait for vertical sync, so the other page will be invisible when + ; we start drawing to it. + mov dx,INPUT_STATUS_1 +WaitVS: in al,dx + test al,08h + jz WaitVS ;vertical sync is active high (1 = active) + + ; Finally, have to adjust the pixel panning register in order + ; to fine-tune the starting address on a pixel level. + ; This pixel pan value is the scroll offset mod 4 -- but since + ; Mode X's pixel pan works by values of 2 (0, 2, 4 or 6) we + ; have to shift appropriately. + mov dx,ATC_INDEX + mov al,13h ; 13h = set pixel pan + out dx,al + mov ax,di ; DI = pixel pan calculated above + out dx,al + mov dx,ATC_INDEX + mov al,32 ; Allows the computer to use this register + out dx,al ; again. Without this OUT, the screen will + ; remain blank! + + ; Increment the page counter now! + inc cs:pages + ret +FlipPage ENDP + \ No newline at end of file diff --git a/16/scrasm/PALETTE.INC b/16/scrasm/PALETTE.INC new file mode 100644 index 00000000..e3bd381e --- /dev/null +++ b/16/scrasm/PALETTE.INC @@ -0,0 +1,239 @@ +;; Palette operations +;; Note that where needed in the macros, a "palette" refers to +;; the segment handle to a 768-byte piece of memory. So palettes +;; can be loaded and freed, they're not permanent, but if you want +;; to use a fixed (not allocated) palette you'd better make sure +;; it's segment aligned or else you can't use these macros. If it +;; is, you can just supply "seg myPalette" as the 'palette' argument +;; to any of these macros. + +;; Fade from a palette to black +FADE_OFF MACRO fade,palette + mov si,0 + mov ds,palette + mov bh,fade ; positive -> Gets dimmer... + mov bl,0 ; Starts exact + mov cx,64/fade+1 ; Total number of loops required + call FadePalette + ENDM + +;; Fade from black to a palette +FADE_ON MACRO fade,palette + mov si,0 + mov ds,palette + mov bh,-fade ; negative -> Gets brighter... + mov bl,64 ; Starts totally dimmed + mov cx,64/fade+1 ; Total number of loops required + call FadePalette + ENDM + +;; Flash from a palette to white +FLASH_OFF MACRO fade,palette + mov si,0 + mov ds,palette + mov bh,-fade ; negative -> gets brighter + mov bl,0 ; Starts exact + mov cx,64/fade+1 ; Total number of loops required + call FadePalette + ENDM + +;; Flash from white to a palette +FLASH_ON MACRO fade,palette + mov si,0 + mov ds,palette + mov bh,fade ; positive -> Gets dimmer... + mov bl,-64 ; Starts totally bright + mov cx,64/fade+1 ; Total number of loops required + call FadePalette + ENDM + +;; Save a palette into a palette-sized piece of memory +PAL_SAVE MACRO palette + mov es,palette + mov di,0 + call SavePalette + ENDM + +; Returns AX = a new segment for a palette +NEW_PAL MACRO palette + mov bx,(256 * 3) / 16 + mov ah,48h + int 21h + mov palette,ax + ENDM + +;; Black the entire palette temporarily. Used to blank the screen while +;; drawing a frame before fading in. +PAL_BLACK MACRO + mov ax,seg tmppal + mov ds,ax + mov si,OFFSET tmppal + mov bh,-1 ; Doesn't really matter... + mov bl,64 ; Starts totally dimmed + mov cx,1 ; Just one time -- to leave it black + call FadePalette + ENDM + +;; drawing a frame before fading in. +PAL_WHITE MACRO + mov ax,seg tmppal + mov ds,ax + mov si,OFFSET tmppal + mov bh,-1 ; Doesn't really matter... + mov bl,-64 ; Starts totally dimmed + mov cx,1 ; Just one time -- to leave it black + call FadePalette + ENDM + +;; Black the entire palette temporarily. Used to blank the screen while +;; drawing a frame before fading in. +PAL_UPDATE MACRO + mov cx,0 ; 0 times = update + call FadePalette + ENDM + +WAITBORDER MACRO + LOCAL wbr1,wbr2 + mov dx,INPUT_STATUS_1 +wbr1: in al,dx + test al,8 + jnz wbr1 +wbr2: in al,dx + test al,8 + jz wbr2 + ENDM + +;; Fade Palette: +;; The following code is modified greatly from the Future Crew's palette +;; fading code. Works on blocks of 256 colors only, so far, but I might +;; change it later. Also, it theoretically could "anti-fade" -- fade to +;; white -- which I call flashing, so I added that ability, which was +;; missing from FC's code. +EVEN +tmppal DB 768 dup (?) ; Stores old palette +FadePalette PROC NEAR + mov ax,seg tmppal + mov es,ax + +FadeLoop: push cx + push si + + cmp cx,0 + je JustUpdate + + ; Load in the colors in the palette + mov di,OFFSET tmppal ; ES:DI -> temp palette + mov cx,768 ; Reads 256*3 bytes at a time. +loadpal_loop: mov al,ds:[si] ; Load one color byte + inc si + sub al,bl ; Subtract the fade amount + jge pal_more ; Limit the range by clipping + xor al,al ; to between 0 and 63 + jmp pal_ok ; (there's probably a faster +pal_more: cmp al,63 ; way to do it than this, + jle pal_ok ; but I don't know it) + mov al,63 +pal_ok: mov es:[di],al ; Store that byte in the new + inc di + dec cx ; temp palette and loop. + jnz loadpal_loop + + ; Get ready to move this block of palette values +JustUpdate: sti ; Let interrupts happen now, + WAITBORDER ; while waiting for a retrace, + cli ; instead of more critical times + + mov dx,PEL_WRITE_REG; Set up to write to color register, + xor al,al ; starting at palette entry 0. + out dx,al + mov dx,PEL_DATA_REG ; Point at color port + + ; Quickly put out the first half of the color palette + mov di,OFFSET tmppal + mov cl,(768/6)/2 ; Does 2 loops of 128 colors each. + cli ; Waits a retrace inbetween... +FirstHalfLoop: REPEAT 6 ; Steps of 6 -- reduces the + mov al,es:[di] ; number of LOOP instructions + inc di + out dx,al + ENDM + dec cl + jnz FirstHalfLoop + sti + + WAITBORDER ; Waits one retrace -- less flicker + mov dx,PEL_DATA_REG ; Reset DX + + ; Now, quickly put out the other half of the colors. + mov cl,(768/6)/2 + cli +SecondHalfLoop: REPEAT 6 ; Steps of 6 -- reduces the + mov al,es:[di] ; number of LOOP instructions + inc di + out dx,al + ENDM + dec cl + jnz SecondHalfLoop + + ; For the next iteration, restore everything and loop + pop si + pop cx + + cmp cx,0 + je JustUpdated + + add bl,bh ; Change brightness by BH + + dec cx + jnz FadeLoop + + ; All done, re-enable interrupts and return +JustUpdated: sti + ret +FadePalette ENDP + +;; Saves the palette into the memory pointed at by DS:SI. That memory +;; must be at least 768 bytes long... +SavePalette PROC NEAR + mov dx,PEL_READ_REG ; Set up to read from color register, + xor al,al ; starting at palette entry 0. + out dx,al + mov dx,PEL_DATA_REG + + ; Quickly read in the first half of the color palette + mov cl,(768/6) + cli +ReadPalLoop: REPEAT 6 ; Steps of 6 -- reduces the + in al,dx ; number of LOOP instructions + mov es:[di],al + inc di + ENDM + dec cl + jnz ReadPalLoop + ; All done, re-enable interrupts and return + sti + ret +SavePalette ENDP + +;; Load a palette from a file. Opens the file and reads it into +;; memory (standard LoadFile) and then points the palette at that +;; newly allocated memory. Also, frees old memory before it does +;; any loading ... +LoadPaletteFile PROC near + mov ax,segPalette + cmp ax,-1 + je pal_not_loaded + mov es,ax + mov ah,49h + int 21h + mov nError,ERR_MEM + jc lp_err + mov segPalette,-1 + +pal_not_loaded: call LoadFile + jc lp_err + + mov segPalette,dx +lp_err: ret +LoadPaletteFile ENDP + \ No newline at end of file diff --git a/16/scrasm/SCROLL.DOC b/16/scrasm/SCROLL.DOC new file mode 100644 index 00000000..0893db36 --- /dev/null +++ b/16/scrasm/SCROLL.DOC @@ -0,0 +1,297 @@ + ________________________________________________ + |+----------------------------------------------+| + || I N T R O D U C I N G : || + |+----------------------------------------------+| + || Steve's 4-Way || + || ___ ___ ____ ___ _ _ || + || / __| / __| | _ \ / _ \ | | | | || + || | <_ | | | |_> | | | | | | | | | || + || \_ \ | | | / | | | | | | | | || + || __> | | |__ | |\ \ | |_| | | |__ | |__ || + || |___/ \___| |_| \_| \___/ |____| |____| || + |+______________________________________________+| + +------------------------------------------------+ + + There, now that I have the hype outta the way, let me explain what +this program is. I'm releasing the source code to my 4-way scrolling +code so that others can learn from it. There aren't enough really +good resources out there for someone learning to program games, so I'm +trying to do my part to help. + +WHAT IT IS: + + The code is 100% assembly, for which I use MASM 6.0, so there may +be a few problems converting to Turbo Assembler. I also use the ".386" +directive, meaning that you can't run this code with a 286 or earlier. +But most of the code should be easily convertible. I haven't been +programming for 386's much so I really don't make the use of the 386 +registers like I could have. Mostly I just did it for some extra 386 +instructions. + + You'll need a VGA which can support mode 13h, the MCGA mode. This +code runs in "tweaked" MCGA mode, or what is called "Mode X". For more +information on Mode X, check out the 1991 - 1992 issues of Doctor Dobbs +Journal, wherein you will find Michael Abrash's excellent Graphics +Programming column. This is where I (and many others) found out about +Mode X, which is an excellent graphics mode for fast 256-color graphics. +Also, you can take a look at XLIB, YakIcons, FastGraph, etc which are all +graphics libraries (public domain or otherwise) which support Mode X +graphics and probably have some good documentation on programming the mode. +Additionally, check out _The Programmer's Guide to the EGA and VGA Cards_, +by Richard Ferraro, and _Power Graphics Programming_ (out of print, but +available directly from Que Books) by Michael Abrash. Finally, you can +ask about graphics programming on many newsgroups such as +"rec.games.programmer"... + +WHAT IT DOES: + + The code will allow you to create "tiled" background patterns and then +to omnidirectionally scroll over them. You could implement sprite routines +and then animate them over the background, but I haven't gotten this far +yet. The scrolling is always relational -- ie no "jump-to"'s, just "scroll +left", "scroll up", etc. Jump to would be very easy to implement, I just +haven't done it yet. + + It runs at about 60-70 fps on a 386/20, which means that it is operating +in under the time of one vertical refresh (_just_ under, according to some +timing I've done). This could probably be reduced, but the best way to +reduce it is to limit the speed at which it scrolls -- if you stick to +scrolling at most 8 pixels at a time in two axes or 16 pixels at a time +in one axis, it is very fast. More than that, and it occasionally takes +more than one refresh period even on my 486. Still, that should be +fast enough for just about any game. + + I also included some routines to generate maps, tiles, and palettes +so you can see the file formats. These are in C, and the executables +are around in case you don't care to recompile. None of the utilities +are exactly production quality. You'll have to look at the code to +figure out the arguments! Luckily you can just run them with no args +and they perform default behavior. + + Lastly, the program SCROLL.EXE is a demo of what it can do. In this +demo you can use one of two sets of keyboard controls to scroll around. +One, the default set of commands, lets you press up/down/left/right and +scroll in that direction. The other has "intertia" -- pressing up/down +left/right will accelerate you in that direction. You'll see what I +mean, just experiment. You can switch keyhandlers by pressing K. +You can also switch between the diagonal pattern map and a logo map +by pressing M. (By the way, it will eventually run out of memory loading +the maps and the diagonal map will screw up... don't worry about it, +it'd be fixed if I had more time). Try it out. + +CREDIT WHERE CREDIT IS DUE: + + People who (unknowingly) helped me out: + + Keyboard by Steven Dollins, Brown Computer Group. From his + KEYINT routines, which is an INT 9 handler to let you + keep track of many keys being pressed at the same time. + Graphics, basically, by Michael Abrash, whose Mode X columns + influenced me greatly. + Palette fades and file I/O by the Future Crew. Thanks for + letting out the Mental Surgery code! + CPU detection by Ray Duncan, taken from one of his books. + + Obviously I haven't just pirated the code, it's all from publicly +released source code and I modified it a bit. But I wouldn't have come +up with this whole thing without those helping hands. Thanks. + +HOW IT WORKS: + + Here's how the scrolling works. I'll explain it from a single-page +point of view, although it actually uses several pages of video memory. +The video memory is laid out like this: +ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÑÍÍÍÍÍÍÍÍÍÍÍÍ» ÄÄÄ +º ³ / / / / º ³ +º ³/ / / / º ³ +º ³ / / / /º ³ +º Visible page ³ / Not / / º ³ +º ³/ visible/ º ³ +º ³ / / / /º 64K +º ³ / / / / º ³ +ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ/ / / / º ³ +º / / / / / / / / / / / / / / /º ³ +º / / / / / / / / / / / / / / / º ³ +º/ / / / / / / / / / / / / / / º ³ +ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ ÄÄÄ +In other words, it has a virtual width greater than the actual screen +width, and a virtual height higher than the actual screen height. The +VGA hardware allows hardware panning around within the virtual area, so +that makes panning much easier: you only have to draw the information +that is coming on to the screen with each pan. + +What is Happening: What the user sees: +ÉÍÍÍÍÍÍÍÍÑÍÍÍÍ» ÚÄÄÄÄÄÄÄÄ¿ +º hel³////º ³ hel³ The picture that is +ÇÄÄÄÄÄÄÄÄÙ////º ÀÄÄÄÄÄÄÄÄÙ coming on to the screen +º/////////////º ("hello") appears to +ÈÍÍÍÍÍÍÍÍÍÍÍÍͼ the user to be scrolling +ÉÍÑÍÍÍÍÍÍÍÑÍÍÍ» ÚÄÄÄÄÄÄÄÄ¿ left, although it is +º/³ hell³///º ³ hell³ actually at a stationary +º/ÀÄÄÄÄÄÄÄÙ///º ÀÄÄÄÄÄÄÄÄÙ location in memory... +º/////////////º Each time the frame moves, +ÈÍÍÍÍÍÍÍÍÍÍÍÍͼ it is not necessary to +ÉÍÍÑÍÍÍÍÍÍÍÑÍÍ» ÚÄÄÄÄÄÄÄÄ¿ redraw the parts that stay +º//³ hello³//º ³ hello³ on the screen, just the +º//ÀÄÄÄÄÄÄÄÙ//º ÀÄÄÄÄÄÄÄÄÙ parts that become visible. +º/////////////º +ÈÍÍÍÍÍÍÍÍÍÍÍÍͼ + + The same works up&down too, or even left/right and up/down at the same +time. The problem occurs when you scroll enough to hit the edge of the +virtual space. Luckily, video memory increases and wraps at the right +edge to one line down on the left edge. So you end up with a situation +like this after scrolling too far right: +ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÑÍÍÍÍ» ÄÄÄ +ÇÄÄÄÄÄÄÄ¿//////³ º ³ User sees: +º ³//////³ Thº ³ ÚÄÄÄÄÄÄÄÄÄÄÄ¿ +ºe quick³//////³ º 64K ³ ³ +º ³//////ÀÄÄÄĶ ³ ³ The quick³ +ÇÄÄÄÄÄÄÄÙ///////////º ³ ³ ³ +º///////////////////º ³ ÀÄÄÄÄÄÄÄÄÄÄÄÙ +ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ ÄÄÄ +The wrapping is transparent to the user. So, it appears that you can +scroll left & right infinitely, by simply always updating the amount of +memory that has scrolled into view. + + But what happens when you scroll too far down? Now Intel segments come +to the rescue! Because the video memory is 64K, and that is also the +largest amount of memory you can access in a segment, the segment arithmetic +performs the top-to-bottom wrapping for me. It results in a similar +situation as is pictured above, but with the screen split horizontally +instead of vertically. Again, it's completely transparent to the user. + + One performance optimization that I've done is to organize the background +picture that is being scrolled into quantitized "tiles" -- 16x16 pixels in +area. This means that you can store a large amount of picture data if that +data is repetitive -- as the backgrounds of many video games are. This also +helps when figuring out how much new stuff to draw on the screen. I can wait +until the panning crosses a 16-pixel border, then draw another 16-pixel +strip, and then wait for another tile crossing, etc. You can see this in +the MAP.INC and SCROLL.INC code. 16x16 pixels also leads to 256-pixel-square +tiles, which is always a convenient number in assembly... it helps out in +several places in the code. + + So, the display page is "wandering" around the video memory, only drawing +what is necessary at any time. Meanwhile you can animate sprites over the +background, etc. The only problem is that with one page, information is +constantly being drawn to that page and you can never guarantee that it is in +a correct state at the time of a vertical refresh period. Instead, I actually +use several pages, so that one can be shown while the other is worked on. +This guarantees a perfect picture at any time. So for now, let's ignore the +scrolling for a second, and talk about the paging, because it's easier to +understand the paging if scrolling isn't happening. + + Here's a basic explanation of how the paging works. I use three separate +pages, a Draw page, a Show page, and a Blank page. The Show page refers to +the page that is currently showing, the Draw page to the page that is +under construction (to be shown next frame), and the Blank page should always +be maintained as an up-to-date blank background page. (The Blank page is +useful for sprite programming which I am going to be doing next.) Each +of the pages is 352x240, although the screen resolution is only 320x200. + + Each frame, the pages rotate DrawPage->ShowPage->BlankPage->DrawPage. +This means that at the beginning of the frame, the Draw Page is already +blank, so all that is necessary is to draw on a bunch of sprites. The +BlankPage, though, is no longer blank (it's still got stuff from what +was the ShowPage) so we have to erase it, by blanking out the sprites +(luckily the new DrawPage _is_ empty, so we can use a Mode X 32-bit video- +to-video copy to blank it). Hope you're still with me. + + So, this loop continues with each frame, and the loop invariants are +maintained: Show Page is always a "good" frame -- don't touch it. Blank +Page is always blank. Draw Page can look like anything. Now to include +the scrolling again: + + The way I do scrolling with several pages is that the pages ALL wander +around video memory, only they're smaller (1/3 of the size that they could +have been, to be exact!). Here's a picture of the situation at its worst: +ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍ» ÄÄÄ +º ³//ÀÄÄÄÄÄÄÄĺ ³ +ºÄÄÙ///////////º ³ +º/////ÚÄÄÄÄÄÄÄĺ ³ +ºÄÄ¿//³PAGE 0 º ³ +º ³//³ (Draw) º ³ +º ³//ÀÄÄÄÄÄÄÄĺ ³ +ºÄÄÙ///////////º 64K +º/////ÚÄÄÄÄÄÄÄĺ (21K each page) +ºÄÄ¿//³PAGE 1 º ³ +º ³//³ (Show) º ³ +º ³//ÀÄÄÄÄÄÄÄĺ ³ +ºÄÄÙ///////////º ³ +º/////ÚÄÄÄÄÄÄÄĺ ³ +ºÄÄ¿//³PAGE 2 º ³ +º ³//³ (Blank)º ³ +ÈÍÍÍÍÍÍÍÍÍÍÍÍÍͼ ÄÄÄ +The pages always maintain an equal distance apart as they wander. Since +all pages move in parallel, the way it used to work is that as soon as the +pages scrolled, I would draw the newly-visible picture information on +all three of the pages. This worked great, except that it resulted in +a slight pause every time the screen scrolled because it was doing hardware +pan most of the time (which is very fast) and the drawing routines were +slow. Now, I've spread the copying over successive frames to allow a +smoother scrolling rate. This is possible because it's not really necessary +to draw the new information to a page before that page becomes the show +page... + + I hope that this has made some sense. It's pretty complicated stuff. +Take a look at the code and maybe that will help. Or, write me mail +(my email address is below). Or, design your own way and ignore this +whole thing. + +COMING SOON: + + Next up are Sprite routines. I threw in what I started as SPRITE.INC, +although it's not included in the project right now. + Sound support + + Who knows what else? Depends on what people send me! + +------------------------------------------------------------------------- + R E A D T H I S +------------------------------------------------------------------------- + R E A D T H I S +------------------------------------------------------------------------- + + This code is being released as "SwapWare". That means that if you wanted +to go ahead and use my code directly, I really wouldn't care. But I ask +that you send me some of your code that you think is neat. Especially if +it's modifications that you make to this code, such as quick sprite drawing +or optimizations. + + I'm not going to brag and say that I "threw this together in a few hours". +I didn't, it took me many days of work to get it working properly. But +I'm also not looking for money as recompensation for my labor. I make +great money at my real day job and you probably have a better use for your +donations, such as legitimizing your unregistered shareware and pirated +games. I'm in this for the knowledge ... so my best payback would be to +get lots of code from people out there, stuff to really help make a great +game. In particular, these would be great: + * 32-bit code + * Tricky optimizations + * Fast BitBlt/masked BitBlt code + * Useful File I/O functions + * 3D polygon and texture mapping code + * Maintenance routines -- like numeric conversions, etc. + * Hardware access code like timing routines and interrupt + handlers +Any of those would be very helpful when writing a fast scrolling game. + +You can contact me (for the rest of this term only) at + seisner@athena.mit.edu +Feel free to ask any questions you want! I check my mail about once or +twice a week so don't expect instant turnaround... If you're desperate +to talk to me, say if you work at Origin and want to give me the source +code to Strike Commander or whatnot, you can also reach me at: + Steve Eisner + (617) 247-8691 +and leave a message. But I'd rather you wrote e-mail. + + Thanks, + Steve Eisner + +* Read rec.games.programmer! And for those who already do: + I dream of a world where no one argues over why Wolfenstein + 3-D sucks or why it doesn't. Would people just give it a + break? + \ No newline at end of file diff --git a/16/scrasm/SCROLL.EXE b/16/scrasm/SCROLL.EXE new file mode 100644 index 0000000000000000000000000000000000000000..8181acf10f9d8d572a19b978175493810c0e29c9 GIT binary patch literal 33596 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 A(f|Me literal 0 HcmV?d00001 diff --git a/16/scrasm/SCROLL.PAL b/16/scrasm/SCROLL.PAL new file mode 100644 index 0000000000000000000000000000000000000000..5dee1969fc3e9dfe5bee855460c512ba3a850e69 GIT binary patch literal 768 zcmWO4fugA}007W2rBcR}O4&6{OBqvI%Gm$^)qCd~4gg>dt%dE`E^_?PL#dC+Ix03v zg)s=;JrU8Lq&#;GQ)M~QO6RqSZwB9WAV;TF@YMk&t+()|8fhN>SZXNw zlH!w9V#CCj>_HvpR+3`YH{A-DDwc&TZ^J$?U|nElC!m;^{jyVjYmIcim7<1NXuY#PGDO4-Zu+wYE-7ycLg$qcMMwm451?r(j8`H-i|kUs2#rtj?8 zzS_F`$GkJ3Bk}Q^QB&u2hxB8b^GGx&cNN?7&#-QLu%QFE&i%-Q*o0SD&xDb>SN7nB z6u6BkI~p5UF=8ip*+}i&aGpNr_5auFq6EH9vx+~=|K`|#B6sn>?~lNp;HtafY3cua z4^$#LvhkE1D`@`Q@NP>sTzR~gD?e)^KuO)sZOf~tMQn)rLG8-tQ{p}~A62eY`-{9Y ziO;KVOvKAzeqFsUXS|KRoll*l&ogk&wL|0#z@V^GM^fCTZ0YbEe5@MS~NL#H5>YR z=v-WDVtDWK`c~|e4!rCwFua-+eA`YC!oa(qN#JJC_#5_S%3_!JUl!fJFT;R8#P@rs zeO#yV@40@pT} zQndQDBE~f&&p!636_YAm6XyawwEv&b+F`!WF`)nBV=%)!p5e7AW8UXDqt?fgw)buP ztc_%TYQy7(8~8;VgzzoV8ona|IL*geTjEnqZ9ROxJ7j#6!~6Stct5^};~@lo!yeuB zdIyXLbl9N7@rd$s*zdz0-R)2_GM<0iGhQ~(LpU7w{EZf#?UQ1XM{t>{j zTob*5kIs2k2DTwH-S9juV?()j>C@(2Tl*#~1mMNzgbYYsl>FJ%$B&v8VZ)OXu^vx!)-#x2;#m$jt z_pa;TY&O~38&xnP&MR(@-PTP%=5Is&%vV4RUm1uNsG+|8WhJxfUnt-BpT{_XcKHCu zG(OmW9bj7nmCV^Y9QFqS(8Wgya}Kg>n~{RqBkbp&b-*7fA8t;L5Q&tHZMNkMg!%kk z%QtReygP}$mq+3EyDvD(js$Xe>0H-8yZiC{a(X$x7Q0^nI{!P$D9czo+qbm;;iwyc z`-8O~a1W=i1`9WSlTiTkd|$xV@QwAZ-F$c9x8*6c)n{mE8`{`s%=+=&=)LAvn%i@Q z*ndKeHU%yHxYm#_bt!f zYFvG9TMP5r?`nk|?Y2C-T)r-suDf(?*L7{vwsl=M{M2<-*JW8%MNyPz$?1GLeSUsA z=k3?!>q|TagtrX>U03i`S(Rm36z6jR%rD}cw-*yR@45y9313CJEYFw#KjZ(7|N628 zz$<`;_~pK7DgrQG5fFg*&(wdv{}=YZWB=Q>gs_1C5pHx@c|9=5^-};gO literal 0 HcmV?d00001 diff --git a/16/scrasm/SPRITE.INC b/16/scrasm/SPRITE.INC new file mode 100644 index 00000000..9c3f2e48 --- /dev/null +++ b/16/scrasm/SPRITE.INC @@ -0,0 +1,280 @@ +; SPRITE routines +MAX_SPRITE EQU 100 + +RECTANGLE STRUCT 2,NONUNIQUE + X WORD 0 + Y WORD 0 + Wid4 BYTE 0 + Ht BYTE 0 + Color BYTE 0 + Next WORD 0 + ; DrawMe is used to not bother with sprites that you know + ; are contained totally within another, allowing animated + ; eyes, etc to be stored in separate sprites. These will be + ; drawn to the local buffer but skipped when copying to the + ; screen, so if they are not TOTALLY contained, they will + ; just get clipped away. + DrawMe BYTE 1 ; default, yes draw me. + ; (Storage from this point on ... NEVER provide anything but + ; default for these values!) + address_virt WORD 0 + address_buf WORD 0 + next_line_virt WORD 0 + next_line_buf WORD 0 +RECTANGLE ENDS + +SPRITE STRUCT 2, NONUNIQUE + RECTANGLE <> ; Contains rectangle info +SPRITE ENDS + +EVEN +rect5 SPRITE <<40 ,60 , 2,8, C_TRANSPARENT, 0 , 0>> +rect4 SPRITE <<80 ,30 , 2,8, C_TRANSPARENT, offset rect5, 0>> +rect3 SPRITE <<120,60 , 2,8, C_TRANSPARENT, offset rect4, 0>> +rect2 SPRITE <<55 ,100, 2,8, C_TRANSPARENT, offset rect3, 0>> +rect1 SPRITE <<105,100, 2,8, C_TRANSPARENT, offset rect2, 0>> + +rect6 SPRITE <<36 ,56 , 4,16, C_BLUE, offset rect1, 1>> +rect7 SPRITE <<76 ,26 , 4,16, C_BLUE, offset rect6, 1>> +rect8 SPRITE <<116,56 , 4,16, C_BLUE, offset rect7, 1>> +rect9 SPRITE <<51 ,96 , 4,16, C_BLUE, offset rect8, 1>> +rect10 SPRITE <<101,96 , 4,16, C_BLUE, offset rect9, 1>> + +;; Simply adding in these 5 rectangles (~20000 pixels for both +;; drawing and erasing) really slows things down! That's why +;; it's important to optimize the sprite drawing routines! +rect11 SPRITE <<35 ,55 ,14,36, C_GREEN, offset rect10, 1>> +rect12 SPRITE <<75 ,25 ,14,36, C_GREEN, offset rect11, 1>> +rect13 SPRITE <<115,55 ,14,36, C_GREEN, offset rect12, 1>> +rect14 SPRITE <<50 ,95 ,14,36, C_GREEN, offset rect13, 1>> +rect15 SPRITE <<100,95 ,14,36, C_GREEN, offset rect14, 1>> + +FIRST_SPRITE EQU rect10 + +EVEN +AnimateSprites PROC near + ret + ; Blank out the draw page, by copying from the blank page + ; to the draw page all rectangles which had changed. The + ; blank page must always be entirely blank if this is going + ; to work! + mov di,cs:DrawPage.UpperLeftAddress + add di,cs:DrawPage.ScrollOffset + mov si,cs:BlankPage.UpperLeftAddress + add si,cs:BlankPage.ScrollOffset + mov bp,cs:BlankPage.Rectangles + call CopyRectangles + + ; Now draw the sprites. Uses a temporary buffer to ensure + ; minimal drawing to the screen, but that's not really necessary, + ; if memory is at a minimum. It's just faster... + mov bp,offset FIRST_SPRITE + mov cs:DrawPage.Rectangles,bp + call do_fill_buffer + mov di,cs:DrawPage.UpperLeftAddress + add di,cs:DrawPage.ScrollOffset + mov bh,cs:DrawPage.AlignmentMask + mov bp,offset FIRST_SPRITE + jmp smart_rects ; "call" +AnimateSprites ENDP + +smart_dest DW 0 +out_di DW 0 +out_si DW 0 + +EVEN +smart_rects PROC near + add di,cs:DrawPage.Address + mov ds,cs:segBuffer + mov es,cs:segVideo + mov dx,3c4h + mov al,02h + out dx,al + inc dx + mov cs:smart_dest,di + + ; === Beginning of loop through rectangles! === +sp_nextrect: + cmp cs:[bp].RECTANGLE.DrawMe,1 + jne sp_next + ; Draw this rectangle from the buffer to screen memory. + ; Calculate the output address. + mov si,cs:[bp].RECTANGLE.address_buf + mov di,cs:[bp].RECTANGLE.address_virt + add di,cs:smart_dest + + ; Loop over 4 planes + mov bl,4 +sp_plane_loop: mov al,bh + out dx,al + + mov cs:out_di,di + mov cs:out_si,si + + ; Loop over height + mov ch,cs:[bp].RECTANGLE.Ht +sp_row_loop: + + ; Loop over width of rectangle (Wid4 is actually width/4) + mov cl,cs:[bp].RECTANGLE.Wid4 +sp_col_loop: + + ; Read a byte from the buffer + ; Is it transparent (no-modify)? If so, just jump over the draw + mov al,byte ptr ds:[si] + cmp al,C_TRANSPARENT + je sp_next_pixel + ; Otherwise, draw it on the spreen, and mark it transparent + ; so that it won't be drawn again. + mov byte ptr es:[di],al + mov byte ptr ds:[si],C_TRANSPARENT + + ; Skip to next 4-byte group (next column that can be drawn in + ; Mode X) Also increment spreen draw address, but only by 1 + ; because ModeX is 4 pixels per byte +sp_next_pixel: + add si,4 + inc di + + dec cl + jnz sp_col_loop + + ; End of row. Skip space to get to left edge of next row down + ; Skip SI = (SCREEN_WIDTH - #bytesdrawn) + ; Only draw up to height of rectangle + add si,cs:[bp].RECTANGLE.next_line_buf + add di,cs:[bp].RECTANGLE.next_line_virt + dec ch + jnz sp_row_loop + + mov di,cs:out_di + mov si,cs:out_si + inc si + rol bh,1 + adc di,0 + + dec bl + jnz sp_plane_loop + + ; Follow chain to next rectangle +sp_next: mov bp,cs:[bp].RECTANGLE.Next + cmp bp,0 + jne sp_nextrect + ; All done +sp_end: ret +smart_rects ENDP + +; BP -> first rectangle. Follows BP->next, stops when BP = 0 +EVEN +do_fill_buffer PROC near + mov es,cs:segBuffer + + cmp bp,0 + je fill_end +fill_loop: + + mov bx,cs:[bp].RECTANGLE.Y + shl bx,1 ; BX = word index y + mov di,cs:MultBufWidth[bx] ; DI = SW * y + mov cx,cs:[bp].RECTANGLE.X ; CX = x + add di,cx ; DI = (SW * y) + x + mov cs:[bp].RECTANGLE.address_buf,di ; (DI used later) + + mov ax,cs:MultVirtWidth[bx] ; AX = (VW/4) * y + shr cx,2 ; CX = (x / 4) + add ax,cx ; AX = (VW * y + x)/4 + mov cs:[bp].RECTANGLE.address_virt,ax + + mov dx,(VIRTUAL_WIDTH / 4) + sub dl,cs:[bp].RECTANGLE.Wid4 ; DX = (VW - w) / 4 + mov cs:[bp].RECTANGLE.next_line_virt,dx + + mov dx,(SCREEN_WIDTH / 4) + sub dl,cs:[bp].RECTANGLE.Wid4 ; DX = (SW - w) / 4 + shl dx,2 ; DX = SW - w + mov cs:[bp].RECTANGLE.next_line_buf,dx + + mov ah,cs:[bp].RECTANGLE.Color + mov al,cs:[bp].RECTANGLE.Color + + mov ch,cs:[bp].RECTANGLE.Ht +fill_row_loop: mov cl,cs:[bp].RECTANGLE.Wid4 +fill_col_loop: mov es:[di],ax + mov es:[di+2],ax + add di,4 + dec cl + jnz fill_col_loop + add di,dx + dec ch + jnz fill_row_loop + + mov bp,cs:[bp].RECTANGLE.Next + cmp bp,0 + jne fill_loop +fill_end: ret +do_fill_buffer ENDP + +EVEN +CopyRectangles PROC near + mov ax,cs:segVideo + mov ds,ax + mov es,ax + + ; Calculate the difference between the source and destination + ; pages. Since in a movsb loop the two would remain a constant + ; distance apart, we can just calculate a displacement and then + ; not have to worry about SI; instead use DI and DI+BX, thanks + ; to the thoughtful x86 ALU! + mov bx,di + sub bx,si + + mov dx,GC_INDEX + mov ax,ALL_COPY_BITS + out dx,ax + + mov dx,SC_INDEX + mov ax,0F02h + out dx,ax + mov si,di ;store destination + + ; === Beginning of loop through rectangles! === +cr_nextrect: cmp cs:[bp].RECTANGLE.DrawMe,1 + jne cr_next + ; Draw this rectangle from the buffer to screen memory. + ; Calculate the output address. + mov di,cs:[bp].RECTANGLE.address_virt + mov dx,cs:[bp].RECTANGLE.next_line_virt + add di,si + + ; Loop over height + mov ch,cs:[bp].RECTANGLE.Ht +cr_row_loop: + + ; Loop over width of rectangle (Wid4 is actually width/4) + mov cl,cs:[bp].RECTANGLE.Wid4 +cr_col_loop: mov al,ds:[di + bx] + stosb + dec cl + jnz cr_col_loop + mov al,ds:[di + bx] + mov es:[di],al + + ; End of row. Skip space to get to left edge of next row down + ; Only draw up to height of rectangle + add di,dx + dec ch + jnz cr_row_loop + + ; Follow chain to next rectangle +cr_next: mov bp,cs:[bp].RECTANGLE.Next + cmp bp,0 + jne cr_nextrect + ; All done +cr_end: + mov dx,GC_INDEX + mov ax,ALL_DRAW_BITS + out dx,ax + ret +CopyRectangles ENDP + + \ No newline at end of file -- 2.39.2