From fce0f75959b9806f4016beb7b19e19b37cc97b6c Mon Sep 17 00:00:00 2001 From: Rich Turner Date: Wed, 3 Mar 1982 16:51:26 -0800 Subject: [PATCH] MS-DOS v1.25 Release --- v1.25/Tim_Paterson_16Dec2013_email.txt | 23 + v1.25/bin/ART.BAS | Bin 0 -> 1920 bytes v1.25/bin/BALL.BAS | Bin 0 -> 2048 bytes v1.25/bin/BASIC.COM | Bin 0 -> 11392 bytes v1.25/bin/BASICA.COM | Bin 0 -> 16768 bytes v1.25/bin/CALENDAR.BAS | Bin 0 -> 3840 bytes v1.25/bin/CHKDSK.COM | Bin 0 -> 1720 bytes v1.25/bin/CIRCLE.BAS | Bin 0 -> 1664 bytes v1.25/bin/COLORBAR.BAS | Bin 0 -> 1536 bytes v1.25/bin/COMM.BAS | Bin 0 -> 4352 bytes v1.25/bin/COMMAND.COM | Bin 0 -> 4959 bytes v1.25/bin/COMP.COM | Bin 0 -> 1649 bytes v1.25/bin/DEBUG.COM | Bin 0 -> 5999 bytes v1.25/bin/DISKCOMP.COM | Bin 0 -> 1640 bytes v1.25/bin/DISKCOPY.COM | Bin 0 -> 2008 bytes v1.25/bin/DONKEY.BAS | Bin 0 -> 3584 bytes v1.25/bin/EDLIN.COM | Bin 0 -> 2392 bytes v1.25/bin/EXE2BIN.EXE | Bin 0 -> 1280 bytes v1.25/bin/FORMAT.COM | Bin 0 -> 3816 bytes v1.25/bin/LINK.EXE | Bin 0 -> 41856 bytes v1.25/bin/MODE.COM | Bin 0 -> 2509 bytes v1.25/bin/MORTGAGE.BAS | Bin 0 -> 6272 bytes v1.25/bin/MUSIC.BAS | Bin 0 -> 8704 bytes v1.25/bin/PIECHART.BAS | Bin 0 -> 2304 bytes v1.25/bin/SAMPLES.BAS | Bin 0 -> 2432 bytes v1.25/bin/SETCLOCK.COM | Bin 0 -> 853 bytes v1.25/bin/SPACE.BAS | Bin 0 -> 1920 bytes v1.25/bin/SYS.COM | Bin 0 -> 605 bytes v1.25/source/ASM.ASM | 4006 +++++++++++++++++++++++ v1.25/source/COMMAND.ASM | 2166 +++++++++++++ v1.25/source/HEX2BIN.ASM | 214 ++ v1.25/source/IO.ASM | 1934 ++++++++++++ v1.25/source/MSDOS.ASM | 4031 ++++++++++++++++++++++++ v1.25/source/STDDOS.ASM | 23 + v1.25/source/TRANS.ASM | 1213 +++++++ 35 files changed, 13610 insertions(+) create mode 100644 v1.25/Tim_Paterson_16Dec2013_email.txt create mode 100644 v1.25/bin/ART.BAS create mode 100644 v1.25/bin/BALL.BAS create mode 100644 v1.25/bin/BASIC.COM create mode 100644 v1.25/bin/BASICA.COM create mode 100644 v1.25/bin/CALENDAR.BAS create mode 100644 v1.25/bin/CHKDSK.COM create mode 100644 v1.25/bin/CIRCLE.BAS create mode 100644 v1.25/bin/COLORBAR.BAS create mode 100644 v1.25/bin/COMM.BAS create mode 100644 v1.25/bin/COMMAND.COM create mode 100644 v1.25/bin/COMP.COM create mode 100644 v1.25/bin/DEBUG.COM create mode 100644 v1.25/bin/DISKCOMP.COM create mode 100644 v1.25/bin/DISKCOPY.COM create mode 100644 v1.25/bin/DONKEY.BAS create mode 100644 v1.25/bin/EDLIN.COM create mode 100644 v1.25/bin/EXE2BIN.EXE create mode 100644 v1.25/bin/FORMAT.COM create mode 100644 v1.25/bin/LINK.EXE create mode 100644 v1.25/bin/MODE.COM create mode 100644 v1.25/bin/MORTGAGE.BAS create mode 100644 v1.25/bin/MUSIC.BAS create mode 100644 v1.25/bin/PIECHART.BAS create mode 100644 v1.25/bin/SAMPLES.BAS create mode 100644 v1.25/bin/SETCLOCK.COM create mode 100644 v1.25/bin/SPACE.BAS create mode 100644 v1.25/bin/SYS.COM create mode 100644 v1.25/source/ASM.ASM create mode 100644 v1.25/source/COMMAND.ASM create mode 100644 v1.25/source/HEX2BIN.ASM create mode 100644 v1.25/source/IO.ASM create mode 100644 v1.25/source/MSDOS.ASM create mode 100644 v1.25/source/STDDOS.ASM create mode 100644 v1.25/source/TRANS.ASM diff --git a/v1.25/Tim_Paterson_16Dec2013_email.txt b/v1.25/Tim_Paterson_16Dec2013_email.txt new file mode 100644 index 0000000..45c4055 --- /dev/null +++ b/v1.25/Tim_Paterson_16Dec2013_email.txt @@ -0,0 +1,23 @@ +From: Tim Paterson +To: Len Shustek +Date: Mon, 16 Dec 2013 10:34:17 -0800 +Subject: RE: Source code to MS-DOS 1.0 + + +I have found and attached the source code for MS-DOS 1.25 as shipped by Seattle Computer Products. Version 1.25 was the first general release to OEM customers other than IBM so was used by all the first clone manufacturers. + +IBM's DOS 1.1 corresponds to MS-DOS 1.24. There is one minor difference between 1.24 and 1.25, as noted in the revision history at the top of MSDOS.ASM. + +Of the file attached, only STDDOS.ASM/MSDOS.ASM (DOS main code) and COMMAND.ASM (command processor) would have been used by an OEM other than Seattle Computer. The other files: + +IO.ASM - I/O system unique to SCP (equivalent to ibmbio.sys). +ASM.ASM & HEX2BIN.ASM - Old 8086 assembler developed by SCP (used to assemble older version of DOS). +TRANS.ASM - Z80 to 8086 assembly source code translator developed by SCP. + +I also have a 6” stack of printouts of assembly listings for some of these and probably other related programs. + +Tim Paterson +Paterson Technology +http://www.patersontech.com/ + + diff --git a/v1.25/bin/ART.BAS b/v1.25/bin/ART.BAS new file mode 100644 index 0000000000000000000000000000000000000000..2de324aa4c26300152c9cf1a6a573f7d10125b7a GIT binary patch literal 1920 zcmeyrjb{yWzd}exs)DDJuR=g-QE`4=Vvd4yer`c&NotXTV^ImiE1qr4{R&~JMa7x< zc?yPlh6V~6&YI5o1(ija=@}(pozD411qz0i7KSAY8%gB^VXd|ZQ76rL+6`S~j` z6!P9IhlwSK#N@5!4a1TA;wMVRgXj zl!BNJzp&Lr1tm`>UnPcXynmQaDM;w>^XLeI1Tlh0iGi7qjb*&6n3S_(gU2&uYE|@pou4Snvt3oKoQD)9Xr^)b{&jRE{ zeux(Zbwt5lRMK$PRKS}Klo-_coj^MIAUef$Bp^Biic*V<6^aWIlT#Iv5{nc{@)eTv z^GY)FN>h~>toeOdx)tudc&4PJa8{vHfzOA9!Gk}H#o5;d6vy`%68IBXx)q>Yn4&Ni zh8q4Xgg7X`r8OZ2{97EOhB3Ooi3nlGO57%)Ig6k%n!&p(G{fdYR3IMImc2r+!%U&b;~LCM44 z$3?+2L{W)BS6~B3AksfnJ;+tT&p$*VG}zP6T_ME7Rl(Wc$3IBlJ;*V@!_zrf!Pno< zGsHhg!O_JrAjCCDQHdd2U>8Vph=*seLO_tedyu2ALTIpSumW6jH0(f)E;lk60K!3w%R}qXj#UAOkBRs$jwXi&F0^aMp&rz$K5MY#kkgO#8d>%YkgO1WuD3@(D=Ak~tr41R(VtSc1w zBv~0^1SMgr85kJy1m##yCKqS-mKq*6i2n!!t`fc2Duuns>LL#9v#NV))=ja-AB z6|z$+L76DEBC|xvnxRUliPba0@cI9a*ZjX;@+&iR3-z#iMi?OkmJ3Y-2`D^Q(C~~f zeB~Kor1?ff;iZCSgb~9Ip#`j-kr3T^FZst zHD76XMi}XMMjC1A{O@=z{89)Mgsj5*aHtW~abnOGJ^__|DFia(B`A74BaB{wct)>; zz=6TwBYcU~(^28M!v8i6xC>uvct#q&0@&}x61Q-43mXFv34tXgGvxsk3Vcnh3{QoBu|lefZUy9;22__QoK^VOqo4#8R??Aq!OZYgn1yY>f&{ouIbhYu Lz`!6Sh0A^b45cW$ literal 0 HcmV?d00001 diff --git a/v1.25/bin/BALL.BAS b/v1.25/bin/BALL.BAS new file mode 100644 index 0000000000000000000000000000000000000000..132087a79902931b22f08a44b43503532facab70 GIT binary patch literal 2048 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 literal 0 HcmV?d00001 diff --git a/v1.25/bin/BASICA.COM b/v1.25/bin/BASICA.COM new file mode 100644 index 0000000000000000000000000000000000000000..dc085788ba4c092c21ff2ced24ae0198a4671c32 GIT binary patch literal 16768 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 HHS7lfHT5Ka literal 0 HcmV?d00001 diff --git a/v1.25/bin/CHKDSK.COM b/v1.25/bin/CHKDSK.COM new file mode 100644 index 0000000000000000000000000000000000000000..bf88ed2f4aad31d204e978c4d1d2ce4af472a743 GIT binary patch literal 1720 zcmdn9gT28nmO-JEpX)%0=q@u>KKU)2XBE#X>rTEEY&#hl zy2Tc;IdzJyV{1ODWPG5zjKSJ$9oznT)^ZK*ZzU4lKQBIO-?N4N;ydpDrS=XlgqTVa z8~^{{FD|pTTgO%&+Wr0Yoq$d^rcO7O?t{B@7(Bi|>b}4%wu)_w@L5H!10~Ea75@Kc z+rYM~p7piSu34-BAb)osf3clummVvaeelIVq#j;VJ?f>OL}*Xa#hCZGI=UUx{@mH^Uk$))J=IeD06FMKH2$V*Agxg6%bD1S8uP zw*PF~*g!^hf9Q5&>JDS+=3B<*$$YT+5`*K#mqlzBUtPTM`kS@b61H02?`BKbxG$A3 zI#?eoaW?)BQu(5Qv9pY=vyP+tYV#|lE&Ndb1pHgLgss!<^G*haEgEMPw+Nh7+_eqt zm56{B4;Z0diEKWq<7mydf~}nS<%)mC2lnn@-^awz&9{i{yBov*|E1C|PB4^+HU9t3 zU&{3#cL%V&ILWYZ4VyOG7B+3RO>DLd3?)(^6}uR^%~r5!n{8mz zhN#qHdoiD(*=`dXLkZ`?O>Da@*j`LySh$Eyn{5r-?gX|MoeT?^7B1`re8I%fb*4+|YoZ#x1e4hMSd)M5Dku=@kE*($c?V;nm< z7`8CI;AYsQa8_|6^9v@1$ir*8E}T_-^z-n41`uFlutxxp09Krom{L-dn4GPkpunJ@ zkeHXEprGQJSC*KQnWB(Vlv$RlP+X9joSBxHoLG{Xp9hyKNGwXsO)W_+QgO`5$%jZP zq!tzB7b&EHaAr=bf{IIKQEGBYeo-YvMmG&4YNeo{prGQGnUh+qkX)2sT&$aunU|fK zVx_>#1(JfuDHLZ`r9!kJ3H4j}~Vp(ElPGV9{szQDq*aluMgdq@nb5nEkiz*SKAjk1?sbGzhQ9%Ie8BzrR literal 0 HcmV?d00001 diff --git a/v1.25/bin/CIRCLE.BAS b/v1.25/bin/CIRCLE.BAS new file mode 100644 index 0000000000000000000000000000000000000000..611fc0da8ef0633fbbbe92cb21c0e54d9236b89b GIT binary patch literal 1664 zcmeyrlV=Tczd}exs)DDJuR=g-QE`4=Vvd4yer`c&NotXTb7oO;PAbD&o^8zi3Sp^5 z#hLke3Wj=y1_~O^n$GzJl|`B986{xN&iO?J3Wk;zhB_e9h(VtB0CT^BPiAszUU6!Q zf^T9;YEfolj)Ja2Kv8~rQDQELE=VmZsZ_{M1DU{J$a|i7x%#g?X0#iw(Yp@c-Y~D}ICl&5m zolp?e5whB^z|XHEs3T~#K!IPw>VVZL1u-3dVXKJ>N}f)>N(}pW|1h6YkkH}h(Gdg* zVg!W}!)snPmi-F+TsneQr$CexSmpm|8vIu^UtZJT7uDfEtN9Yd-=WE%z$d_RN`aqS z2cc@S=1V072ypfca`thBuoV=Pz?wE|GPv1;~s15HAYqh=RSSq~WZofH$(082I^}Ksxy# zI>mJ)AUXqzQj3cfiVG5xQx%dDixf)o6_WGwN;30GQFSh~XapGM0%7N*?|`E()F@ib@R90vkXAk^Z6T zL9PmZ{visX!JdBZ3Lze@3eNsM{z3ZgL5=|)p3cDvzW#omA^t%MjxLS?A+AA+N(_+# zyFi*lJUoLH0)qVAgB*PoLW5m{72tXt{ah4+TmwTrgIt3ZLOdKpV7m2`7@7o*fOH20 zxdwyeTor-?9GzVioE(D`Li`n+{ry5b{X$*!lo)yh&OyA+ut4AjYT(~sVOT5h2od;4 z1>PV9Bs3f!u`oOo_=XTi3;bUK46KL%YkgN(F{yN(_dA;vmHutPFO7a;*Cm_~k(vmtmoxJnKXSC6pk7 z2Z*Cfn4_PwtBZn@W3Z>Qg03zo^c0-^eSJaUrVbW$R98Y215FB^&xI7uD9C6iTQyrL ztWe-nU}ab@r~q>m0|UbyK}A+b;nA&tD1Ja?i^5rje?3aYiMa(isl`e7L zMu9&?;k<${LzPeptE16#$Ctr|R^1AYM$cpqef4NoII92>Gtd1b&9JASDH}9{_6i B-{b%Q literal 0 HcmV?d00001 diff --git a/v1.25/bin/COLORBAR.BAS b/v1.25/bin/COLORBAR.BAS new file mode 100644 index 0000000000000000000000000000000000000000..067792c004a27d37ef0c3eb012f4c8ba6ef5c290 GIT binary patch literal 1536 zcmeyrn`aGkzd}exs)DDJuR=g-QE`4=Vvd4yer`c&NotXTbAC>KQBq%>4>s zsYS(^`FRS4dWHrH8qS)|`303lnduoNVC~NNMFk3mmKKIOAkv6Ik@o;|zk*L@a%x_2 zYKnqyVo7RIW@3(lu0lXjetJ=2E{HBjEh?#0$WH^Az~IVzin(9Gv9u&3zeqt>!96E6 zFHa%3q%^UpM8PGoC?zvFn<1R{Jo9vgU{`l5g&7L`SvrCY8N64RgB^VXd|XwYEBW~= zF%j+vcP~g|FI$(85 zK}?5V*lMDJlBbie62m3lKg_2TBy{+BbOb?y7{Q~&@Sm5BWxoPHmyV#-DG((ER{4LL z2LDyfm)A7-MRoYkYQ6;VcW5%0@CmS-QsC#-L8#iS`BF&%0-XJQ{DYhvgCIO5u%^wL z3{iYiAWb}|njl6iK#bn3$PYrAt|v) zp(I}+IX|x?Gp{sNiNTWJhoxKLp2CY~3Q9@}XB9dX_UeUD|j-f348;^1&@vpgP{NeDy zAv?7alt@!6GC?-p5!}bxt#I$fGf<35Yl4&LK30ZTf+tw5`fs|p`nZO;GJF!e#Ck$O zkl~Nu9aeB+V_*_`#(IE3Q|JS0w*tJd0+mP#XBGbSC@4Y1f|Yb+UNAE-Fi1(!!+roZ C=*T|+ literal 0 HcmV?d00001 diff --git a/v1.25/bin/COMM.BAS b/v1.25/bin/COMM.BAS new file mode 100644 index 0000000000000000000000000000000000000000..ef3439a3165e501633dbbca8ee9574cd73986b3e GIT binary patch literal 4352 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 literal 0 HcmV?d00001 diff --git a/v1.25/bin/COMMAND.COM b/v1.25/bin/COMMAND.COM new file mode 100644 index 0000000000000000000000000000000000000000..751326fc092d1859d10b8b184fc4e33bf9cf0781 GIT binary patch literal 4959 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 Ak^lez literal 0 HcmV?d00001 diff --git a/v1.25/bin/DISKCOPY.COM b/v1.25/bin/DISKCOPY.COM new file mode 100644 index 0000000000000000000000000000000000000000..e2436d1c70d1534c2df35a5ee4a7479c54d78aa9 GIT binary patch literal 2008 zcmaF4k}V`7Rl(EAS0Ny^s5n0_F-O5UKewQ?B(+GvC9^m?wWK6f!8yMmGqp$|EVZaO zGe1wkP|wgnLBmWh~*^b(Zz4;)`B}*UT?!7+&-+K!llJ_Z>-t`)+ zcb73c$cP<`JZBYo6m0TJna(QMRF=Nj!@ziq&6E{v2ve!ZF*aLPMvzX25{?CCtQQ_E zGGlE}vtVU@S@j{;^rIHrZLSvXo8+nJZAL&-J!c8)U9p z(;uc1)}}u!r813gLB@dW5it4&b_&P>!xw@KujlUg%lcwEt@qz(lFbBx1%x8s*G+)ePXtJ|rWhi|C zbvM($qY!_9UB9bK&78GE&6E|%7amQ2m`gnWv01S;*;%o&l&*t2T@B=^hEg+-6%9L* zSYNzh09pF7_&>x?AS+&`{okR)_Tm!5>%JEfj4uoR?|8@d;t0db^#5FMOP_**;=!(X zu%~uiVtaY!FE}DW&Sg0(T*L11!JXW}URy4#6$2M6m};Ua#p+J#Q6 z|IU=$ieg8yNDSm@v43nftW9<{tSqHxcCBK2srUCqD8uW6ARjO>yxtkqVb;Lbz}LWL z(0u`v#v6aVV=K{X{FTI7qIR6EoXxuJ*;t|HEVY~^fCZ@6B6;!vw#+m+7-QVepg zLeyb!zKA*;)O5(PLu@(wu3AV?Okf8EEk_CSt{LoS6?ZKF5rXVz6`{%*kN_hC10xdy z0}~Si12Yo?0}B%a11l2)0~-?q13MD~0|yf?ms@^OZemGEW?s5Nc}8YVszP#pL1kuM zIxm+BFPCRtacWVCLUDd+QF5w63arG*%u`4y$}CG&aIivFR+3nho?3!iS#U{FW_GGV zVqT>}c50rm&`~JPOi5KRU|8*3}*#5vR!(i!u;<**NrWbXBGb) zX!^}q%5#h@22|$9GBCcD|Hc->@V}IAQ4GUt&RyF%KpEn!!Z)^9hX19^i((lT#4vEM zEoA+7Vo?l3*MkMI3><7HK)hH6t0SeXpsd3Pt}u43Vc*Dd`Bl#e<_kub{vGQSvtwPz z#Grj>Bgf?zyV^NynHY+eEHYy?dfUa@)Zn44OXT7)VL3DV+%)a1;x%;dz9 J%=|o%0su?K$3Xx9 literal 0 HcmV?d00001 diff --git a/v1.25/bin/DONKEY.BAS b/v1.25/bin/DONKEY.BAS new file mode 100644 index 0000000000000000000000000000000000000000..8b6ac8afd3dd0783654a869e7fbae851d652a391 GIT binary patch literal 3584 zcmeyrlV=Tczd}exs)DDJuR=g-QE`4=Vvd4yer`c&NotXTOMYHKs}l->Izm?a z75Mpe1a$4 zW7)63&!r=1bqYjDfmQyWron$z^W`-Seo-C%vzjkK{2iJMLVN-&rxf_Pbr7mHYra%c zfB+YNKX2Da2wOox39MfswRlh3J{|=Yck~Wsen}RqN)NLjS?pyB-0GHN;7$C&Tkk4O&kW*5Cn%u#{P|07% z(y71~#=_9b-@yV-S4{{9f@N^DV@b&le4DkJ=;xvkihDic9Py_!43&VVYM~J}RF7O5^Afe&- zh=t*@z&C_ATHwDCU|>Z=7%cFGSQ)+vaItnO@I7K-_$R>4dQ#yo1CJmN>r{p1plIi3 zWsnr)W&Jl5RkPoC-gq6WSke_wG0>3;c<1$PZ6kwgGpo9`c@Bndi33K#w zc6Cv3at!u#R?yW2g`R@5zppPS+|)WvgZ@g%t{XLaYo6 z1%+UaVqjpnD=5qgDLlFr5akZ2Y*9F?@UKUyI5D>%C$(5fN9F~yg4IHW{R$Ewhgu!5 zYGimUD8ky$@LI5mb-#ij!&ku`*0l#%cA)~{n$q+1b zg0)wHZwfm@tk5M8>kAu0vd|sY0}O>i&sf_OoS^C^3VmP&d0QCdZ5>7{Cshqk&F8OV z7#v>mAFyg>SSIv~)k#%DQ1iJkNKQ!eIsZY1H9{ya^Yl< ztT;p#VzO(nGgS7da0*CP0wPrl{ej?i(A)YNfy3{urO&d@Bfgv}-5Ie+F$ey!L4TQ&Z7ycX7Em?yFh?0OLQm8j-x zNsupU6wWJ%GprKX!FEJJM!`=E`HvsI>#8oM6a=RD>z3ycZpDVrx5v)U-H>==SYzE zc{msfMIV5)D!fyG>E-Xy5!cjlQe~Jf`iiaDY6I9b{u<3!8ZHqp`4x2dr$XJ;sleC9 z#xPg(3)=yP)uR8{{!LO)3bt@IR${m!%EA6`l9H3Jp^=VZk#VlJp^kBiQIMgZi&3dz zkx`0Cj!~&$j-e96Pf;O|!W8o$!@LxuQllc{6tf)TQllKh6ysc7Lmk5$V@5LqK9A0uoEPKZU|S8z`(iG2gKIN;aN;kN;o2Cv0(*#Gq_ zXb9;DX)^p4D`Rg{03}5YnHFYE1`+WF_J5sVxmOzevO4^_kc7%0CEmr}$DklSh5Z17 zj`%!~#lZ#^N({E*E7(EN;pA&*qGM>G#E>Yy2_)&OZKR`X5@Z1m3&T)D5Up(p7BysO z5#Iw=0}6MLgfTckK!h$hjEs~R)`%YiDRD9OF${%ByBPTxh8p=8LujyKLnVeo;uqlR zOnr5Ybc{m{l^8CI-vav))b!)i)DdBLE&hc4xPk`1stzdEgIF3M76Y@yJD51PrWI72 zTa!Uf;s^V`P6Z8qUP!jr)!~uq< zlknhhHjH@g9AV{b82Q{e(#qKg#Cyrl&!8k3#L=V>@LXKsjDn!Td4*R(R#DG|-e?HF z4bZfTGJG!dDvH5fGKK?OMi@ruI2(crGecFYe;pdmMlimSDnpKB8d#BwVT6tgNRbOf zk&6+GZ=}jFU9te`lGjm&kl+9@z|Jv>c&QFPuS+$hW^f!);8%V5zvDIk2^~?Z zW(I4iMI4|y2Hae^z;4yd;4Za>;{d2(%EHEwBejhq*!Ov`FF1)nswo8}NL{LslV6-# etf<6LCv^Z}#0zGtW`-`QQ*a{~7^I{OBQ*gWU;%~z literal 0 HcmV?d00001 diff --git a/v1.25/bin/EDLIN.COM b/v1.25/bin/EDLIN.COM new file mode 100644 index 0000000000000000000000000000000000000000..5ed51488e2bbede19eb8ab2cd4e078047bf608bc GIT binary patch literal 2392 zcmaD|&&w5(k*eV76~9sS(KTcQ3BTIoL^L+U}$M!$jhbTlbM{FSDc!n;G0;IT9lcXqoAu0P?Vou zl$Z;m3sQ?pDi!k6K>BvYaK8M_bd0T@i(!ukZOqIZL1Kv*X;K%CM7} z;q$T*r!D-uVi?XUE~?|=I#9yCiEn;UCxek=@?3&H_avIaF3eJ}kn2ZlBu4PzU&#<_XYjHJ~!{RK4#c5o- zJbAl+ZIL>w*v-er;MvJHgX& zz{SV_F_rnnUyx^aD68($grwq0|$wt!sD^o7a9yU@nuXZ@%tT^cXBa&T30I9 zeRE+G7x#e@Hfy#9t|I=6kN;2iVt(26e~pbo$?wCvzH)*B?`75h7jOUD=#`k-D3_S; zVqnXvKZ;=Wxf+I^h)pf%ext}^a!yJ=kAC$!J+W@LDAox#HOe+kcD|8Bk+T%Xpt zyL{jD{Pu{XC#+N{LWiz~Haem><(0zWFC$ILYlD(i5v@3#Z ziv}p!mCAL0-|xxWX*Y?hn{O7E_BqGTOZ-8p1d<>QZxJ}FxN9dkCeA8=0<+t05|{O@ zl4s?7+_y`(b}=&S_vE#{RdNli`}_tjt^c(*}i?VJyZ6x-RS#V7T~L=zx0L5eRYV(TB|flU|51bRB!a#L#u9>%)Z? z5D4NPQ{gXR+RVUWpmq4A7z@8vDPrtNVMmT@#nP_V03z{o)L- znfEg?fZcYk#IRd$0$1RRjQ^2qY!r$`ZMaGVZFoy~Z8%Ff12)9HIK&*mBvCNPw0y{Kd8w(H>X2dRM?=gG*|!R6?sDb~kT%yyiukBfo9 z>BVuz7k3y+d0saEf6Tt-1sk*1qo0R&DRRBGev!jaY7DX&WZ?^j|1YcncJuXd zZQ%N}u2i(su7j)7u7|6WuaE0LTNl@hNem@tckw|I*uoyJ#gn)ec5yA9z;*Z=TP@fB zk{`RIz;as{&ngDIn9LMm!&~yiCbHy#P37VJa@;Q#GjJVv{I!#>h0FM)4Q~nC{(0Ol z`WZU;+PFZm)cl*V`7*a22g~ z1UYPh95=|tAeVFh|Fo`jYWKzN``vskT%P;nxvdU-Ue*8|izW-@m$xp9Nu`aGoxgIW~1BZ=IuCb9S`C-Fb@@19d>(3yUao;Xw0i~Z8 zs((xG2Zw{)#C^Mzsr#1m3*o=r*W)$@_D}cs zPO%AGoo17`O6OXe&EhJV{^Hc%PEf>|P2zgd^!LTDKU=tV$?=?3+`#oBfw7BEo@Xn= zWBYEg7Os5?JmAc9szfg=Jh1ya^C#w?3ukd@9|DyaGq{SS+u3G;N{n;X-^*E-c%epUC*Q&r1&Px(m*dFJpg!%I8{+vx-oMLHrZ?2bAQyKWd+M?6#Z1_4o6V_J4oe zyWe%+0(qrVZUR@Q-Yl*caesEn@qh~S7e^TODeyGeNR_B|`TXC?(0z^hqLcO2;u)Wp zEZM-d%K7z)o)djH`VRD6*yF+bViH5Q-YhPV+q=KIfl4s#v(Q50<=LORT;WMYCEg~o zG!0bL2%J^iB79cytOBTl`TzgL;$NV;lyUd}|1Xk%gG;oMr=W5cR5a~mWB_T=II9RM zd-laJ^wtP;Uqh-r#UV9n2G>qDhR;jERq0uU4ZJUy7&dSPP1?eAR&i3)VPy9{`v21O zr<0?%XI@!iPG*WiN>OH6szQE|LRw}{szP33ZmNnKjHQrUT3n)#l&Vl%keZyCmYJHO z;+&Y5mtUfgnvz+fpy%Z14c4ZsTa*gY3FfHy9Bd(onO~ximS38e!po)Nujj32ub|?SnU|_ilAo`T jlb@Fk)|&!qzhveWl$OA>IVR;7LH(i;sqd$0ub=_|c;DZt literal 0 HcmV?d00001 diff --git a/v1.25/bin/EXE2BIN.EXE b/v1.25/bin/EXE2BIN.EXE new file mode 100644 index 0000000000000000000000000000000000000000..d43a3f2692b219b2bb8fe9d0071b48d647dc6b4d GIT binary patch literal 1280 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 weY9##2f|Z{M>@llGGvv-~5zRh2;F)+{C;T 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 literal 0 HcmV?d00001 diff --git a/v1.25/bin/PIECHART.BAS b/v1.25/bin/PIECHART.BAS new file mode 100644 index 0000000000000000000000000000000000000000..943b398803051e41bf7e5b786ac52959b10e3dd7 GIT binary patch literal 2304 zcmeyrn`aGkzd}exs)DDJuR=g-QE`4=Vvd4yer`c&NotWoKxS%kMq*J3!+V}>%>4>s zsYS(^`FRS4dWHrH8qS)|`303lnduoNVC~NNMFk3mmKKIOAkv6Ik@o;|zk*L@a%x_2 zYKnqyVo7RIW@3(lu0lXjetJ=2E{HBjEh?#0$WH^Az+lXKo_V@Lu&cY3!VCreEFD1x zSKcek!H&KGKCZzk&z1cAl^Fba?=g2O@O@%tNaB5gBp2x#ti;gI`-%Ca!d+!1g#b*@M~BdusWq6ro%66HBmvy)5%wfVH58k=2Hq1I{Z93f*?T*?<+Cf z=VfErufWfxBWQIBL`i{F{-377e^vA4H4T1I9saYLFG2hrnhYX*0xYK#__=iusy1uB zR8jzg08dwE567SoFh@Z_39MfswRlh3J{|=Yck~Xsen}RqN)NLjS?py z)8R%><B-0GHN;7$C&TP{?0`kW*5Cn%u#{ zP|aV*(y71~#=_9f-@yV-S4{{9f@N^DV@b&le4DkJ=;xvkihA9F!Py_!43&TQzM~J}RDewj< zAfe&-h=t**z&C_ATHwDEU|>Z=7%cFGSQ&l@aItnO@I7K-U=ZYHJ*jY)flrW!b*jR0 zP_*;2GDr*Zvi_T_pj2RJro^Bs$Olp^!pdMI$j`c8fnOe!aT%rx3b0O8P(leJcz`&% zggN>-ySgYiIR<+=E9mNiLQlcj-`5uuZt7rBM|CAcG0>#o`CLfhjDn1YvQ@K{!U_dG zAy$UPf6k%;s2-4tB(bREN0Z|M;1S?n%FmMRkIjNwc5M1OcS%;`Fga~Z`$zAHelEz6C3J!n=087%i9(k^`tnM1Q;RZ_70MEGN>ded@)C1Xm8^p_ zJi+es)MS_^bcZ$gdGJe+5W^CoXROT(2ZTN#%&`JVJO>ePf~}evP73{Ebu@Y|$Z%eW zh3x>t3n4zXQwqX5{35UZPtpic(R>3cTSHVBRD~tjHYjLFzSfXsV328r%WA%o)REA9 z1($dU)26AQpu;bqsUxD}#9%C}#MY$X42~#2h7e&LHb=wfjz(6FM$a9MUIuA6YrYnK zE$@G5TE;DY&nAXcVKX*I$LAW3hA$nBG~Wm_)CoJVIY&I_U-0sOkA|b8=4%a~pjW{` znhev0z1W;1pYx}@`rnBnu~#^R?cYQN4d)0Q=SWSR;2<3#omY;AuVnLun9FruIU4DR zy%A^lA{@u|uOFleX0YtpGd>NkgM)OOBVk6ugfw-W6+SD7>IgCDiDa<(L_Bwnfa%iU z7kC*Qr1?tp_5Vp4jw%|?nwnNVkQo|?mi=?Iwh!OEc zQqyXp0$7(d!(@>fP%vxwfP`O5>PWuUfT(>bq^bEz11A1b5@8dn8XX~q*&=Oh%?i#8 z%S0xyol@Wz*AZekCbEQWqLO1?eo01Zk%BX*`nOlmh*ZcgQt;DMvSzp|vX0GB<@r6U zZUsk`=inlmZyg)MPmx1x5D`Bmh4)~oJWvS&%44FUXP|PCFu6*wTm>tGyy!KyP6fUR NYzzzxQd0D_9{_2bvupqW literal 0 HcmV?d00001 diff --git a/v1.25/bin/SAMPLES.BAS b/v1.25/bin/SAMPLES.BAS new file mode 100644 index 0000000000000000000000000000000000000000..2d2b2aa5476fd13a31d536e89d2968174a3e9a30 GIT binary patch literal 2432 zcmeyri-(J$Um+wTRl(EAS0Ny^s5n0_F-O5UKewQ?B(+E(I5D>%C$*U29ghe@zd~4Q zQE_H|o`RvCp@D*iv!-)?L1j^9dPWIYw{w0`fr6o>g`p0JG-6QTm1F2v@X1V0%_~k# zQSePHNiE7u%u&!)2q?-=FG|b>(FLhRC6x;KX&@6Ae0hx+PAc5BI-ww_BV@H-fuCPT zP)E>efdapV)d8zh3Sv6^!d4R%lsuh$l^6%YF&wYNFqhYjVZQ=D zmyV#-DG((ER{4LL2LDyfm)A7-MRoYkYQ6;VcW5$P;tgOprNGavgHW|u^QDpk1Oz+! z2KcxJLpTabU`?Af8Gi6afi&@;YJwQ805N*ACW9_t3P=?%sw%M2C_xG`9d2|mUmi#k zACjgkXs+I;$t;Ef$6hJ$=fAf0>=o#HwY5S;-;DDY?L2r5|h-*onIbqrGQj&yQSa0+#E za}8p6$2X0^+1Euy;km*+1{VGW4BZMK?sFw2g|iBs3VhQT7!>$dK}8jwD}aJtS`#9d z!N_3AzXc(uqyW`)f`P%Ae;-4q0$&dULlOT82DIb>Nf{!bGysVug@7P`_aH~#U?qlW z{FlIqLsC9o=0OpvEc-d;rBC7gUjw zi-N9#vuBXAkE?=$f`*f0u&1*lrpb{4zd*XUVY*xubQN6u{k&Zx@#*Rp_zlv<1JmUO z%4D9d&K@9t;I!+gz#ot(?8h^iw(IvA>) zVXAzg2^*sHt&kapQWuy~Ncx5-6caYbQ0NL%2uacqg^t1&7z*8B3Im|27@{;o*b+mj zJ4`7k=|YrE7Pi7r<^faY3{9&LrTc`fF_e13l|qv&MCmhO8w{mhFs0y>3sJ`>VuztF z5vC3)YD`4zG1Mi&)WM@BUc>=IRWeK!YSeUyIASPGfhk3fnvEh(7z$Hi3X!Acj)*gc z!Zesd)Tm(=b-_@Y4pWMV8a+{03}qQGWvEdTDe8uyG!w2AC2AT)-7%DA!IUCJ&0^6I ybaiM|&|1+r#!dyk6ATOoMKc&-H4Uh4JYdzxa9Z>QGenkwK}rf#nn9wRT>AlpkEqH3 literal 0 HcmV?d00001 diff --git a/v1.25/bin/SETCLOCK.COM b/v1.25/bin/SETCLOCK.COM new file mode 100644 index 0000000000000000000000000000000000000000..3bf8501eb9d7f2c3ef66bcba4fe04b77417d97cd GIT binary patch literal 853 zcmaDE$i%?Fz|inVyO>q)zaBGV32Vb2-O?`sdjHM-G3fo5V`jAZU&_*agz0=la9~hq zSog=h2bh9-!x%R*HvG{o5$+A+nx?yl{ar*r*AcIGyLV@Ak zV>T!4lVPu4#l=QNMr$89znx3#iA{1D(}v`4-`kEHe(~=Ag(ncmb>uL}EfBn~pRxPj zpWZOW!)qt4op^W)=UK(WlXtQ(ta-8bKdXU3+mROn3~fhVa5Hore!<4@=*13RuEQOy z?uQ+NLllBsgIyhioIP|DJpG*Y6oOnGeH21GeO(otef*uh6+HbyT!Y*kom~|Ig8bcs z9DNni@{1HoGEx;hoqQDnT!VuB{TzK1oc(sjSW#+WX=-taLS}kieo<j_4(v>3_`Hn0lylcjrWXePUbg<} z4dZ@ebFYMV!~dY(Frjx&@1i!`d$*H=A#fx63xe zJ$ls}Ci14`K;(nl+P8bdINw;g{x4&6?sEPA&gl));diTFocR0V{NF9QXBFLE9RI8J zw(;N|_AT0H6<=)lyTNMz8m8uB%zt0(_!7q;iaH3zOb14dxe3e|PO>dQtOt*Bqu7Wq-8~EdIyPcVGuQqgp## b3&Ub&#-0;u?QCrfi&+`v*mw0ao>d0`IoVVl literal 0 HcmV?d00001 diff --git a/v1.25/bin/SPACE.BAS b/v1.25/bin/SPACE.BAS new file mode 100644 index 0000000000000000000000000000000000000000..52ba147e7935692f53aca58b4008854dd3363a72 GIT binary patch literal 1920 zcmeyrgJ%tMzd}exs)DDJuR=g-QE`4=Vvd4yer`c&NotWoa6w{nD#II|ZOr`&VW~yM znfZANhI)nu3L4Iu&iMtEMVaXtC1AbI`9%c^hL#qFIv~=BL5}wTbH9R5W^!s?acYW! zZ(>PmQD$O}g04b9QGR++VlId-NG&R7J3|YKan1daC1AJVARh}#P z`71G$@ZMwYRN(u>%+SvJ0!c2?HCTyZ3-2f9lL~jOPACZK2wCk{;OEy7)Dg5=pun$T zb-?PBf|w4!u+>BbB~K?`C5G#~f0$1xNa*nM=m>%YF~UfRfrXEaWxoPHmyV#-DG((E zR{4LL2LDyfm)A7-MRoYkYQ6;VcW5$L@(HkRTbE1l(++#4>x)jpB_jPACjgkXs+I; z$?%2G0^~)0h!+KQM8RHE(s0&Pz?%$|7&Q2uKsxy#I>mJ)AUXqzQj3cfib2UsAt|v) zp(I}+IX|x?Gp{sNiNS{7hoxKL-iv2SN(yHcIu-bQSQtF{!&sbsT~rjFE8Js9kA4ub+D+Tx)P!oXj1TeE~IcqK}JK_s@Y0mg#w=tE5ivvA(*2W7#LWDgjpelN4El^ z+yRv>3TGAm^(Yl5<`(3n7AxtYz3|vAYto;l^LKR@ostPr+ zu2t}S_z^ut&D%8VzLP1DJ&}zSeq>doNQlV+A2dw^0)ZkyB!=Iw5!!M^J zq@$xFo0gVVZ}qPqCM={QWc6>7Qc|v=nSqX>fkCRV0i2y-Y@lSdK|zDR31q@64gP%~ zT1VLGUnf}1O%o#4q^aY{@KR_2>jni4K^;MmXo?R1aZMdT9Va)d4I2EZ5Wy2*L1C!i zNwA=d4kK7pM90aEfkk)~>nR0(aUEeRg^5a#yzUz8te|AgAT7KFBqgCEY&B7-Bwr!5 zBC|xvnjunnA8V6>*K=WoGYaBXus9I50>yo9QjVEPiIJ&kzHOFua@QHUhEuyR80oXm}gycpGWzc*L&>Erl4lkF9a!{($$~A0q2%xu{#`$r&MI;pDBZV9n|TXAn7Mh2)UG(?vx++y z85Z*~FLq$w{gY`YL&J+yhFx*YTcpk^?$&1B$)NBelwm;(!y+T*MGVYcVlfO`WX>w` z$!}r!{&3>%pG+@&8A=UyYcs!aWhmF!6{if=_mk;GB$6R7d>D2;1-tjG!mg!EufOg( z!}R*Y7WMASXB9jB4Z7W>JKc4<-DNx7^$u_02Z?eWD81J0E^d5@`Jl)5j{)882FwRN zj4yrv7-fCvaQ9{71D);~o$gu=o$jJrG`jr_&MJ1h>vXzHcf0F#y31}6IIDQrGp{T$ zCo@GMr6{v3RiU^bH90daGdZy&Ge1uSCRdPHl$e`Zl3JwVnOB@zRH9H^SzMButB{ge zoUM?V2i5Dy%axdyqEK8?l$o8XkeFAgkeynoP@a*Rr%;rdm{Q5hrQ(;bP?VpatB{so z1T!N)Pa!3>xFj@XlFX!>RG7Nr%&JtCV2HgXMTvREX{kj;sVOQ9 g{~17ljlt8&*U8ggLBZMI7bJiOBk6GQ4<<$j0N+c|{r~^~ literal 0 HcmV?d00001 diff --git a/v1.25/source/ASM.ASM b/v1.25/source/ASM.ASM new file mode 100644 index 0000000..d870d97 --- /dev/null +++ b/v1.25/source/ASM.ASM @@ -0,0 +1,4006 @@ +; Seattle Computer Products 8086 Assembler version 2.44 +; by Tim Paterson +; Runs on the 8086 under MS-DOS + +;* * * * * * REVISION HISTORY * * * * * * +; +; 12/29/80 2.01 General release with 86-DOS version 0.34 +; 02/22/81 2.10 Increased buffer size from 128 bytes to 1024 bytes +; 03/18/81 2.11 General cleanup and more documentation +; 03/24/81 2.20 Modify ESC handling for full 8087 operation +; 04/01/81 2.21 Fix date in HEX and PRN files; modify buffer handling +; 04/03/81 2.22 Fix 2.21 buffer handling +; 04/13/81 2.23 Re-open source file for listing to allow assembling CON: +; 04/28/81 2.24 Allow nested IFs +; 07/30/81 2.25 Add Intel string mnemonics; clean up a little +; 08/02/81 2.30 Re-write pass 2: +; Always report errors to console +; Exact byte lengths for HEX and PRN files +; 11/08/81 2.40 Add 8087 mnemonics; print full error messages; +; allow expressions with *, /, and () +; 07/04/82 2.41 Fix Intel's 8087 "reverse-bit" bug; don't copy date +; 08/18/82 2.42 Increase stack from 80 to 256 (Damn! Overflowed again!) +; 01/05/83 2.43 Correct over-zealous optimization in 2.42 +; 05/09/83 2.44 Add memory usage report +; +;* * * * * * * * * * * * * * * * * * * * * + +SYMWID: EQU 5 ;5 symbols per line in dump +FCB: EQU 5CH +BUFSIZ: EQU 1024 ;Source code buffer +LSTBUFSIZ:EQU BUFSIZ ;List file buffer +HEXBUFSIZ:EQU 70 ;Hex file buffer (26*2 + 5*2 + 3 + EXTRA) +EOL: EQU 13 ;ASCII carriage return +OBJECT: EQU 100H ;DEFAULT "PUT" ADDRESS + +;System call function codes +PRINTMES: EQU 9 +OPEN: EQU 15 +CLOSE: EQU 16 +READ: EQU 20 +SETDMA: EQU 26 +MAKE: EQU 22 +BLKWRT: EQU 40 + +;The following equates define some token values returned by GETSYM +UNDEFID:EQU 0 ;Undefined identifier (including no nearby RET) +CONST: EQU 1 ;Constant (including $) +REG: EQU 2 ;8-bit register +XREG: EQU 3 ;16-bit register (except segment registers) +SREG: EQU 4 ;Segment register +FREG: EQU 6 ;8087 floating point register + +;Bits to build 8087 opcode table entries +ONEREG: EQU 40H ;Single ST register OK as operand +NEEDOP: EQU 80H ;Must have an operand +INTEGER:EQU 20H ;For integer operations +REAL: EQU 28H ;For real operations +EXTENDED EQU 10H ;For Long integers or Temporary real +MEMORY: EQU 18H ;For general memory operations +STACKOP:EQU 10H ;Two register arithmetic with pop +ARITH: EQU 8 ;Non-pop arithmetic operations + + ORG 100H + PUT 100H + + JMPS BEGIN + +HEADER: DB 13,10,'Seattle Computer Products 8086 Assembler Version 2.44' + DB 13,10,'Copyright 1979-1983 by Seattle Computer Products, Inc.' + DB 13,10,13,10,'$' + +BEGIN: + MOV SP,STACK + MOV DX,HEADER + MOV AH,PRINTMES + INT 33 + MOV AL,[FCB+17] + MOV [SYMFLG],AL ;Save symbol table request flag + MOV SI,FCB+9 ;Point to file extension + LODB ;Get source drive letter + CALL CHKDSK ;Valid drive? + OR AL,AL + JZ DEFAULT ;If no extension, use existing drive spec + MOV [FCB],AL +DEFAULT: + LODB ;Get HEX file drive letter + CMP AL,'Z' ;Suppress HEX file? + JZ L0000 + CALL CHKDSK +L0000: + MOV [HEXFCB],AL + LODB ;Get PRN file drive letter + MOV AH,0 ;Signal no PRN file + CMP AL,'Z' ;Suppress PRN file? + JZ NOPRN + CMP AL,'Y' ;Print errors only on console? + JZ NOPRN + MOV AH,2 + CMP AL,'X' ;PRN file to console? + JZ NOPRN + MOV AH,4 + CMP AL,'P' ;PRN file to printer? + JZ NOPRN + CALL CHKDSK + MOV AH,80H +NOPRN: + MOV [LSTFCB],AL + MOV [LSTDEV],AH ;Flag device for list ouput + MOV SI,EXTEND + MOV DI,FCB+9 + MOVW + MOVB ;Set extension to ASM + MOVW ;Zero extent field + MOV DX,FCB + MOV AH,OPEN + INT 33 + MOV BX,NOFILE + OR AL,AL + JZ $+5 + JMP PRERR + MOV DX,HEXFCB + CALL MAKFIL + MOV DX,LSTFCB + CALL MAKFIL + XOR AX,AX + MOV [FCB+12],AX ;Zero CURRENT BLOCK field + MOV [FCB+32],AL ;Zero Next Record field + MOV [FCB+14],BUFSIZ ;Set record size + MOV [BUFPT],SRCBUF ;Initialize buffer pointer + MOV [CODE],START+1 ;POINTER TO NEXT BYTE OF INTERMEDIATE CODE + MOV [IY],START ;POINTER TO CURRENT RELOCATION BYTE + XOR AX,AX + MOV [PC],AX ;DEFAULT PROGRAM COUNTER + MOV [BASE],AX ;POINTER TO ROOT OF ID TREE=NIL + MOV [RETPT],AX ;Pointer to last RET record + MOV [IFFLG],AL ;NOT WITHIN IF/ENDIF + MOV [CHKLAB],AL ;LOOKUP ALL LABELS + DEC AX + MOV [LSTRET],AX ;Location of last RET + MOV AX,[6] ;HL=END OF MEMORY + MOV [HEAP],AX ;BACK END OF SYMBOL TABLE SPACE + MOV [BCOUNT],4 ;CODE BYTES PER RELOCATION BYTE + +;Assemble each line of code + +LOOP: + CALL NEXTCHR ;Get first character on line + CMP AL,1AH + JZ ENDJ + MOV AL,-1 ;Flag that no tokens have been read yet + MOV [SYM],AL + CALL ASMLIN ;Assemble the line + MOV AL,[SYM] + CMP AL,-1 ;Any tokens found on line? + JNZ L0002 + CALL GETSYM ;If no tokens read yet, read first one +L0002: + CMP AL,';' + JZ ENDLN + CMP AL,EOL + JZ ENDLN + MOV AL,14H ;Garbage at end of line error + JP ENDLIN +ENDJ: JMP END + +ENDLN: + XOR AL,AL ;Flag no errors on line +ENDLIN: +;AL = error code for line. Stack depth unknown + MOV SP,STACK + CALL NEXLIN + JP LOOP + +NEXLIN: + MOV CH,0C0H ;Put end of line marker and error code (AL) + CALL PUTCD + CALL GEN1 + MOV AL,[CHR] +GETEOL: + CMP AL,10 + JZ RET + CMP AL,1AH + JZ ENDJ + CALL NEXTCHR ;Scan over comments for linefeed + JP GETEOL + +ABORT: + MOV BX,NOMEM +PRERR: + MOV DX,BX + MOV AH,PRINTMES + INT 33 + INT 32 + +MAKFIL: + MOV SI,DX + LODB ;Get drive select byte + CMP AL,20H ;If not valid, don't make file + JNC RET + MOV CX,4 + MOV DI,SI + MOV SI,FCB+1 + REP + MOVW ;Copy source file name + MOV AH,MAKE + INT 33 + MOV [DI-9+14],1 ;Set record length to 1 byte + MOV BX,NOSPAC + OR AL,AL ;Success? + JNZ PRERR + RET + +CHKDSK: + SUB AL,' ' ;If not present, set zero flag + JZ RET + SUB AL,20H + JZ DSKERR ;Must be in range A-O + CMP AL,'P'-'@' + JC RET +DSKERR: + MOV BX,BADDSK + JP PRERR + +ERROR: + MOV AL,CL + JMP ENDLIN + +NEXTCHR: + MOV SI,[BUFPT] + CMP SI,SRCBUF + JNZ GETCH +;Buffer empty so refill it + PUSH DX + PUSH AX ;AH must be saved + MOV DX,SI + MOV AH,SETDMA + INT 33 + MOV DX,FCB + MOV AH,READ + INT 33 + XCHG AX,DX ;Put error code in DL + POP AX ;Restore AH + MOV AL,DL ;Error code back in AL + POP DX + CMP AL,1 + MOV AL,1AH ;Possibly signal End of File + JZ NOMOD ;If nothing read +GETCH: + LODB + CMP SI,SRCBUF+BUFSIZ + JNZ NOMOD + MOV SI,SRCBUF +NOMOD: + MOV [BUFPT],SI + MOV [CHR],AL + RET + + +MROPS: + +; Get two operands and check for certain types, according to flag byte +; in CL. OP code in CH. Returns only if immediate operation. + + PUSH CX ;Save type flags + CALL GETOP + PUSH DX ;Save first operand + CALL GETOP2 + POP BX ;First op in BX, second op in DX + MOV AL,SREG ;Check for a segment register + CMP AL,BH + JZ SEGCHK + CMP AL,DH + JZ SEGCHK + MOV AL,CONST ;Check if the first operand is immediate + MOV CL,26 + CMP AL,BH + JZ ERROR ;Error if so + POP CX ;Restore type flags + CMP AL,DH ;If second operand is immediate, then done + JZ RET + MOV AL,UNDEFID ;Check for memory reference + CMP AL,BH + JZ STORE ;Is destination memory? + CMP AL,DH + JZ LOAD ;Is source memory? + TEST CL,1 ;Check if register-to-register operation OK + MOV CL,27 + JZ ERROR + MOV AL,DH + CMP AL,BH ;Registers must be of same length +RR: + MOV CL,22 + JNZ ERROR +RR1: + AND AL,1 ;Get register length (1=16 bits) + OR AL,CH ;Or in to OP code + CALL PUT ;And write it + POP CX ;Dump return address + MOV AL,BL + ADD AL,AL ;Rotate register number into middle position + ADD AL,AL + ADD AL,AL + OR AL,0C0H ;Set register-to-register mode + OR AL,DL ;Combine with other register number + JMP PUT + +SEGCHK: +;Come here if at least one operand is a segment register + POP CX ;Restore flags + TEST CL,8 ;Check if segment register OK + MOV CL,22 + JZ ERR1 + MOV CX,8E03H ;Segment register move OP code + MOV AL,UNDEFID + CMP AL,DH ;Check if source is memory + JZ LOAD + CMP AL,BH ;Check if destination is memory + JZ STORE + MOV AL,XREG + SUB AL,DH ;Check if source is 16-bit register + JZ RR ;If so, AL must be zero + MOV CH,8CH ;Change direction + XCHG DX,BX ;Flip which operand is first and second + MOV AL,XREG + SUB AL,DH ;Let RR perform finish the test + JP RR + +STORE: + TEST CL,004H ;Check if storing is OK + JNZ STERR + XCHG DX,BX ;If so, flip operands + AND CH,0FDH ; and zero direction bit +LOAD: + MOV DH,25 + CMP AL,BH ;Check if memory-to-memory + JZ MRERR + MOV AL,BH + CMP AL,REG ;Check if 8-bit operation + JNZ XRG + MOV DH,22 + TEST CL,1 ;See if 8-bit operation is OK + JZ MRERR +XRG: + MOV AL,DL + SUB AL,6 ;Check for R/M mode 6 and register 0 + OR AL,BL ; meaning direct load/store of accumulator + JNZ NOTAC + TEST CL,8 ;See if direct load/store of accumulator + JZ NOTAC ; means anything in this case +; Process direct load/store of accumulator + MOV AL,CH + AND AL,2 ;Preserve direction bit only + XOR AL,2 ; but flip it + OR AL,0A0H ;Combine with OP code + MOV CH,AL + MOV AL,BH ;Check byte/word operation + AND AL,1 + OR AL,CH + POP CX ;Dump return address + JMP PUTADD ;Write the address + +NOTAC: + MOV AL,BH + AND AL,1 ;Get byte/word bit + AND AL,CL ;But don't use it in word-only operations + OR AL,CH ;Combine with OP code + CALL PUT + MOV AL,BL + ADD AL,AL ;Rotate to middle position + ADD AL,AL + ADD AL,AL + OR AL,DL ;Combine register field + POP CX ;Dump return address + JMP PUTADD ;Write the address + +STERR: + MOV DH,29 +MRERR: + MOV CL,DH + +ERR1: JMP ERROR + +GETOP2: +;Get the second operand: look for a comma and drop into GETOP + MOV AL,[SYM] + CMP AL,',' + MOV CL,21 + JNZ ERR1 + + +GETOP: + +; Get one operand. Operand may be a memory reference in brackets, a register, +; or a constant. If a flag (such as "B" for byte operation) is encountered, +; it is noted and processing continues to find the operand. +; +; On exit, AL (=DH) has the type of operand. Other information depends +; on the actual operand: +; +; AL=DH=0 Memory Reference. DL has the address mode properly prepared in +; the 8086 R/M format (middle bits zero). The constant part of the address +; is in ADDR. If an undefined label needs to be added to this, a pointer to +; its information fields is in ALABEL, otherwise ALABEL is zero. +; +; AL=DH=1 Value. The constant part is in DATA. If an undefined label needs +; to be added to this, a pointer to its information fields is in DLABEL, +; otherwise DLABEL is zero. "$" and "RET" are in this class. +; +; AL=DH=2 8-bit Register. DL has the register number. +; +; AL=DH=3 16-bit Register. DL has the register number. +; +; AL=DH=4 Segment Register. DL has the register number. + + CALL GETSYM +GETOP1: +;Enter here if we don't need a GETSYM first + CMP AL,'[' ;Memory reference? + JZ MEM + CMP AL,5 ;Flag ("B", "W", etc.)? + JZ FLG + CMP AL,REG ;8-Bit register? + JZ NREG + CMP AL,XREG ;16-Bit register? + JZ NREG + CMP AL,SREG ;Segment register? + JZ NREG +VAL: ;Must be immediate + XOR AL,AL ;No addressing modes allowed +VAL1: + CALL GETVAL + MOV AX,[CON] ;Defined part + MOV [DATA],AX + MOV AX,[UNDEF] ;Undefined part + MOV [DLABEL],AX + MOV DL,CH + MOV DH,CONST + MOV AL,DH + RET +NREG: + PUSH DX + CALL GETSYM + POP DX + MOV AL,DH + RET +MEM: + CALL GETSYM + MOV AL,1 + CALL GETVAL + MOV AL,[SYM] + CMP AL,']' + MOV CL,24 + JNZ ERR1 + CALL GETSYM + MOV BX,[CON] + MOV [ADDR],BX + MOV BX,[UNDEF] + MOV [ALABEL],BX + MOV DL,CH + MOV DH,UNDEFID + MOV AL,DH + RET +FLG: + CMP DL,[MAXFLG] ;Invalid flag for this operation? + MOV CL,27H + JG ERR1 + CALL GETSYM + CMP AL,',' + JZ GETOP + JP GETOP1 + + +GETVAL: + +; Expression analyzer. On entry, if AL=0 then do not allow base or index +; registers. If AL=1, we are analyzing a memory reference, so allow base +; and index registers, and compute addressing mode when done. The constant +; part of the expression will be found in CON. If an undefined label is to +; be added to this, a pointer to its information fields will be found in +; UNDEF. + + MOV AH,AL ;Flag is kept in AH + MOV [UNDEF],0 + MOV AL,[SYM] + CALL EXPRESSION + MOV [CON],DX + MOV AL,AH + MOV CH,0 ;Initial mode + TEST AL,10H ;Test INDEX bit + RCL AL ;BASE bit (zero flag not affected) + JZ NOIND ;Jump if not indexed, with BASE bit in carry + CMC + RCL CH ;Rotate in BASE bit + RCL AL ;BP bit + RCL CH + RCL AL ;DI bit + RCL CH ;The low 3 bits now have indexing mode +MODE: + OR CH,080H ;If undefined label, force 16-bit displacement + TEST [UNDEF],-1 + JNZ RET + MOV BX,[CON] + MOV AL,BL + CBW ;Extend sign + CMP AX,BX ;Is it a signed 8-bit number? + JNZ RET ;If not, use 16-bit displacement + AND CH,07FH ;Reset 16-bit displacement + OR CH,040H ;Set 8-bit displacement + OR BX,BX + JNZ RET ;Use it if not zero displacement + AND CH,7 ;Specify no displacement + CMP CH,6 ;Check for BP+0 addressing mode + JNZ RET + OR CH,040H ;If BP+0, use 8-bit displacement + RET + +NOIND: + MOV CH,6 ;Try direct address mode + JNC RET ;If no base register, that's right + RCL AL ;Check BP bit + JC MODE + INC CH ;If not, must be BX + JP MODE + +EXPRESSION: +;Analyze arbitrary expression. Flag byte in AH. +;On exit, AL has type byte: 0=register or undefined label + MOV CH,-1 ;Initial type + MOV DI,DX + XOR DX,DX ;Initial value + CMP AL,'+' + JZ PLSMNS + CMP AL,'-' + JZ PLSMNS + MOV CL,'+' + PUSH DX + PUSH CX + MOV DX,DI + JP OPERATE +PLSMNS: + MOV CL,AL + PUSH DX + PUSH CX + OR AH,4 ;Flag that a sign was found + CALL GETSYM +OPERATE: + CALL TERM + POP CX ;Recover operator + POP BX ;Recover current value + XCHG DX,BX + AND CH,AL + OR AL,AL ;Is it register or undefined label? + JZ NOCON ;If so, then no constant part + CMP CL,"-" ;Subtract it? + JNZ ADD + NEG BX +ADD: + ADD DX,BX +NEXTERM: + MOV AL,[SYM] + CMP AL,'+' + JZ PLSMNS + CMP AL,'-' + JZ PLSMNS + MOV AL,CH + RET +NOCON: + CMP CL,"-" + JNZ NEXTERM +BADOP: + MOV CL,5 + JMP ERROR + +TERM: + CALL FACTOR +MULOP: + PUSH DX ;Save value + PUSH AX ;Save type + CALL GETSYM + POP CX + CMP AL,"*" + JZ GETFACT + CMP AL,"/" + JNZ ENDTERM +GETFACT: + OR CL,CL ;Can we operate on this type? + JZ BADOP + PUSH AX ;Save operator + CALL GETSYM ;Get past operator + CALL FACTOR + OR AL,AL + JZ BADOP + POP CX ;Recover operator + POP BP ;And current value + XCHG AX,BP ;Save AH in BP + CMP CL,"/" ;Do we divide? + JNZ DOMUL + OR DX,DX ;Dividing by zero? + MOV CL,29H + JZ ERR2 + MOV BX,DX + XOR DX,DX ;Make 32-bit dividend + DIV AX,BX + JMPS NEXFACT +DOMUL: + MUL AX,DX +NEXFACT: + MOV DX,AX ;Result in DX + XCHG AX,BP ;Restore flags to AH + MOV AL,-1 ;Indicate a number + JMPS MULOP +ENDTERM: + POP DX + MOV AL,CL + RET + +FACTOR: + MOV AL,[SYM] + CMP AL,CONST + JZ RET + CMP AL,UNDEFID + JZ UVAL + CMP AL,"(" + JZ PAREN + CMP AL,'"' + JZ STRING + CMP AL,"'" + JZ STRING + CMP AL,XREG ;Only 16-bit register may index + MOV CL,20 + JNZ ERR2 + TEST AH,1 ;Check to see if indexing is OK + MOV CL,1 + JZ ERR2 + MOV AL,DL + MOV CL,3 + SUB AL,3 ;Check for BX + JZ BXJ + SUB AL,2 ;Check for BP + JZ BPJ + DEC AL ;Check for SI + MOV CL,4 + JZ SIJ + DEC AL ;Check for DI + JZ DIJ + MOV CL,2 ;Invalid base/index register +ERR2: JMP ERROR + +DIJ: + OR AH,20H ;Flag seeing index register DI +SIJ: + TEST AH,10H ;Check if already seen index register + JNZ ERR2 + OR AH,10H ;Flag seeing index register + RET + +BPJ: + OR AH,40H ;Flag seeing base register BP +BXJ: + TEST AH,80H ;Check if already seen base register + JNZ ERR2 + OR AH,80H ;Flag seeing base register + RET + +PAREN: + CALL GETSYM ;Eat the "(" + CALL EXPRESSION + CMP B,[SYM],")" ;Better have closing paren + MOV CL,20 + JNZ ERR30 + RET + +UVAL: + MOV CL,6 + TEST AH,8 ;Check if undefined label has been seen + JNZ ERR30 + OR AH,8 ;Flag seeing undefined label + MOV [UNDEF],BX + RET + +ERR30: JMP ERROR + +STRING: + MOV CH,AL + MOV AL,[CHR] + CMP AL,CH + MOV CL,35 + MOV DL,AL + MOV DH,0 + JNZ L0003 + CALL ZERLEN +L0003: + CALL GETCHR + MOV CL,37 + TEST AH,2 + JZ ERR30 + TEST AH,4 + MOV CL,38 + JNZ ERR30 +STRGDAT: + MOV AL,DL + CMP AL,EOL + MOV CL,39 + JZ ERR30 + CALL PUT + MOV AL,[DATSIZ] + OR AL,AL + JNZ BYTSIZ + MOV AL,DH + CALL PUT +BYTSIZ: + MOV AL,[CHR] + MOV DL,AL + CALL GETCHR + JP STRGDAT + +ZERLEN: + CALL NEXTCHR + CMP AL,CH + JNZ ERR30 + RET + +GETCHR: + CALL NEXTCHR + CMP AL,CH + JNZ RET + CALL NEXTCHR + CMP AL,CH + JZ RET + POP BX ;Kill return address to STRGDAT loop + MOV AL,-1 ;Flag type as constant + RET + + +GETSYM: + +; The lexical scanner. Used only in the operand field. Returns with the token +; in SYM and AL, sometimes with additional info in BX or DX. +; +; AL=SYM=0 Undefined label. BX has pointer to information fields. +; +; AL=SYM=1 Constant (or defined label). DX has value. +; +; AL=SYM=2,3,4 8-bit register, 16-bit register, or segment register, +; respectively. DL has register number. +; +; AL=SYM=5 A mode flag (such as "B" for byte operation). Type of flag in DL +; and also stored in FLAG: -1=no flags, 0=B, 1=W, 2=S, 3=L, 4=T. +; +; AL=SYM=6 8087 floating point register, ST(n) or ST. DL has register number. +; +; All other values are the ASCII code of the character. Note that this may +; never be a letter or number. + + PUSH AX ;Save AH + CALL GETSY + POP AX + MOV AL,[SYM] + RET + +SCANB: + MOV AL,[CHR] +SCANT: + CMP AL,' ' + JZ NEXB + CMP AL,9 + JNZ RET +NEXB: + CALL NEXTCHR + JP SCANT + +DOLLAR: + MOV DX,[OLDPC] + MOV AL,CONST + MOV [SYM],AL +NEXTCHJ: + JMP NEXTCHR + +GETSY: + CALL SCANB + CMP AL,'$' + JZ DOLLAR + MOV [SYM],AL + OR AL,20H + CMP AL,'z'+1 + JNC NEXTCHJ + CMP AL,'a' + JC $+5 + JMP LETTER + CMP AL,'9'+1 + JNC NEXTCHJ + CMP AL,'0' + JC NEXTCHJ + MOV BX,SYM + MOV B,[BX],CONST + CALL READID + DEC BX + MOV AL,[BX] + MOV CL,7 + MOV BX,0 + CMP AL,'h' + JNZ $+5 + JMP HEX + INC CL + MOV [IX],ID +DEC: + MOV SI,[IX] + MOV AL,[SI] + INC [IX] + CMP AL,'9'+1 + JC $+5 + JMP ERROR + SUB AL,'0' + MOV DX,BX + SHL BX + SHL BX + ADD BX,DX + SHL BX + MOV DL,AL + MOV DH,0 + ADD BX,DX + DEC CH + JNZ DEC + XCHG DX,BX + RET + +HEX: + MOV DX,ID + DEC CH +HEX1: + MOV SI,DX + LODB + INC DX + SUB AL,'0' + CMP AL,10 + JC GOTIT + CMP AL,'g'-'0' + JNC ERR4 + SUB AL,'a'-10-'0' +GOTIT: + SHL BX + SHL BX + SHL BX + SHL BX + ADD BL,AL + DEC CH + JNZ HEX1 + XCHG DX,BX + RET + +ERR4: JMP ERROR + +GETLET: + CALL SCANB + CMP AL,EOL + STC + JZ RET + CMP AL,';' + STC + JZ RET + MOV CL,10 + OR AL,20H + CMP AL,'a' + JC ERR4 + CMP AL,'z'+1 + JNC ERR4 +READID: + MOV BX,ID + MOV CH,0 +MOREID: + MOV [BX],AL + INC CH + INC BX + CALL NEXTCHR + CMP AL,'0' + JC NOMORE + OR AL,20H + CMP AL,'z'+1 + JNC NOMORE + CMP AL,'9'+1 + JC MOREID + CMP AL,'a' + JNC MOREID +NOMORE: + MOV CL,AL + MOV AL,CH + MOV [LENID],AL + OR AL,AL + MOV AL,CL + RET + +LETTER: + CALL READID + MOV AL,CH + DEC AL + JNZ NOFLG + MOV AL,[ID] + MOV CX,5 + MOV DI,FLGTAB + UP + REPNE + SCAB ;See if one of B,W,S,L,T + JZ SAVFLG ;Go save flag + XOR AL,AL + MOV CH,[LENID] +NOFLG: + DEC AL + PUSH BX + JNZ L0004 + CALL REGCHK +L0004: + POP BX + MOV AL,DH + JZ SYMSAV + CALL LOOKRET +SYMSAV: + MOV [SYM],AL + RET + +SAVFLG: + MOV DL,CL ;Need flag type in DL + XCHG [FLAG],CL + CMP CL,-1 + MOV CL,32 + MOV AL,5 + JZ SYMSAV +ERRJ3: JMP ERROR + +FLGTAB: DB "tlswb" + +FPREG: +;Have detected "ST" for 8087 floating point stack register + MOV DL,0 ;Default is ST(0) + CALL SCANB ;Get next character + CMP AL,"(" ;Specifying register number? + JNZ HAVREG +;Get register number + CALL NEXTCHR ;Skip over the "(" + CALL GETOP ;A little recursion never hurt anybody + CMP AL,CONST ;Better have found a constant + MOV CL,20 ;Operand error if not + JNZ ERRJ3 + CMP [DLABEL],0 ;Constant must be defined + MOV CL,30 + JNZ ERRJ3 + MOV DX,[DATA] ;Get constant + CMP DX,7 ;Constant must be in range 0-7 + MOV CL,31 + JA ERRJ3 + MOV AL,[SYM] + CMP AL,")" + MOV CL,24 + JNZ ERRJ3 +HAVREG: + MOV DH,FREG + XOR AL,AL ;Zero set means register found + RET + +REGCHK: + MOV BX,ID + CMP [BX],"s"+7400H ;"st" + JZ FPREG + MOV CL,[BX] + INC BX + MOV AL,[BX] + MOV BX,REGTAB + MOV DH,XREG + MOV DL,0 + CMP AL,'x' + JZ SCANREG + MOV DH,REG + CMP AL,'l' + JZ SCANREG + MOV DL,4 + CMP AL,'h' + JZ SCANREG + MOV DH,SREG + MOV DL,0 + MOV BX,SEGTAB + CMP AL,'s' + JZ SCANREG + MOV DH,XREG + CMP AL,'p' + JZ PREG + CMP AL,'i' + JNZ RET + MOV DL,6 + MOV AL,CL + CMP AL,'s' + JZ RET + INC DL + CMP AL,'d' + RET +PREG: + MOV DL,4 + MOV AL,CL + CMP AL,'s' + JZ RET + INC DL + CMP AL,'b' + RET +SCANREG: + MOV AL,CL + MOV CX,4 + UP + MOV DI,BX + REPNZ + SCAB + MOV BX,DI + JNZ RET + MOV AL,CL + ADD AL,DL + MOV DL,AL + XOR AL,AL + RET + +REGTAB: DB 'bdca' + +SEGTAB: DB 'dsce' + +LOOK: + MOV CH,[BX] + INC BX + MOV DX,ID + CALL CPSLP + JZ RET + XOR AL,80H + ROL AL ;Make end-of-symbol bit least significant + MOV CL,AL + DEC BX + MOV AL,[BX] + XOR AL,80H + ROL AL + CMP AL,CL + JNC SMALL + INC CH + INC CH +SMALL: + MOV DL,CH + MOV DH,0 + ADD BX,DX + MOV DX,[BX] + INC BX + MOV AL,DL + OR AL,DH + STC + JZ RET + XCHG DX,BX + JP LOOK + +LOOKRET: + MOV AL,CH + CMP AL,3 ;RET has 3 letters + JNZ LOOKUP + DEC BX + OR B,[BX],080H + MOV DX,RETSTR+2 +CHKRET: + MOV SI,DX + LODB + CMP AL,[BX] + JNZ LOOKIT + DEC BX + DEC DX + DEC CH + JNZ CHKRET + MOV DX,[LSTRET] + MOV AL,DL + AND AL,DH + INC AL + JZ ALLRET + MOV BX,[PC] + SUB BX,DX + MOV AL,BL + CBW + CMP AX,BX ;Signed 8-bit number? + MOV AL,1 + JZ RET +ALLRET: + MOV BX,[RETPT] + MOV AL,BH + OR AL,BL + MOV AL,0 + JNZ RET + MOV BX,[HEAP] + DEC BX + DEC BX + DEC BX + MOV [HEAP],BX + XOR AL,AL + MOV [BX],AL + MOV [RETPT],BX + RET + +LOOKUP: + DEC BX + OR B,[BX],080H +LOOKIT: + MOV BX,[BASE] + MOV AL,BH + OR AL,BL + JZ EMPTY + CALL LOOK + JC ENTER + MOV DX,4 + ADD BX,DX + MOV AL,[BX] + OR AL,AL + JZ RET + INC BX + MOV DX,[BX] + INC BX + RET + +ENTER: + PUSH BX ;Save pointer to link field + CALL CREATE ;Add the node + POP SI + MOV [SI-1],DX ;Link new node + RET ;Zero was set by CREATE + +EMPTY: + CALL CREATE + MOV [BASE],DX + RET + + +CREATE: + +; Add a new node to the identifier tree. The identifier is at ID with +; bit 7 of the last character set to one. The length of the identifier is +; in LENID, which is ID-1. +; +; Node format: +; 1. Length of identifier (1 byte) +; 2. Identifier (1-80 bytes) +; 3. Left link (2-byte pointer to alphabetically smaller identifiers) +; 4. Right link (0 if none larger) +; 5. Data field: +; a. Defined flag (0=undefined, 1=defined) +; b. Value (2 bytes) +; +; This routine returns with AL=zero and zero flag set (which indicates +; on return from LOOKUP that it has not yet been defined), DX points +; to start of new node, and BX points to data field of new node. + + MOV AL,[LENID] + ADD AL,8 ;Storage needed for the node + MOV BX,[HEAP] + MOV DL,AL + MOV DH,0 + SUB BX,DX ;Heap grows downward + MOV [HEAP],BX + XCHG DX,BX + MOV BX,[CODE] ;Check to make sure there's enough + CMP BX,DX + JB $+5 + JMP ABORT + PUSH DX + MOV BX,LENID + MOV CL,[BX] + INC CL + MOV CH,0 + UP + MOV SI,BX + MOV DI,DX + REP + MOVB ;Move identifier and length into node + MOV DX,DI + MOV BX,SI + MOV CH,4 + XCHG DX,BX +NILIFY: + MOV [BX],CL ;Zero left and right links + INC BX + DEC CH + JNZ NILIFY + XOR AL,AL ;Set zero flag + MOV [BX],AL ;Zero defined flag + POP DX ;Restore pointer to node + RET + +CPSLP: + MOV SI,DX + LODB + CMP AL,[BX] + LAHF + INC DX + INC BX + SAHF + JNZ RET + DEC CH + JNZ CPSLP + RET + +GETLAB: + MOV BX,0 + MOV [LABPT],BX + MOV B,[FLAG],-1 + MOV DH,0 + MOV AL,[CHR] + CMP AL,' '+1 + JC NOT1 + OR DH,001H +NOT1: + CALL GETLET + JC RET + CMP AL,':' + JNZ LABCHK + CALL NEXTCHR + JP LABEL +LABCHK: + OR AL,AL + TEST DH,001H + JZ RET +LABEL: + MOV AL,[CHKLAB] + OR AL,AL + JZ $+5 + JMP GETLET + CALL LOOKUP + MOV CL,11 + JNZ ERR5 + MOV DX,[PC] + MOV B,[BX],1 + INC BX + MOV [BX],DX + MOV [LABPT],BX + JMP GETLET + +ERR5: JMP ERROR + +ASMLIN: + MOV B,[MAXFLG],1 ;Allow only B and W flags normally + MOV BX,[PC] + MOV [OLDPC],BX + CALL GETLAB + JNC $+5 + JMP ENDLN + MOV BX,LENID + MOV AL,[BX] + MOV CL,12 + SUB AL,2 + MOV CH,AL + JC ERR5 + INC BX + CMP B,[BX],"f" ;See if an 8087 mnemonic + JZ NDPOP + CMP AL,5 + JNC ERR5 + MOV AL,[BX] + SUB AL,'a' + MOV CL,AL + ADD AL,AL + ADD AL,AL + ADD AL,CL + ADD AL,CH + ADD AL,AL + MOV BX,OPTAB + MOV DL,AL + MOV DH,0 + ADD BX,DX + MOV BX,[BX] + INC CH + MOV CL,CH + MOV AH,[BX] + INC BX + OR AH,AH + JZ OPERR +FINDOP: + MOV CH,CL + MOV DX,ID+1 + XCHG AX,BP ;Save count of opcodes in BP + CALL CPSLP + JZ HAVOP + XCHG AX,BP + MOV DH,0 + MOV DL,CH + INC DX + INC DX + ADD BX,DX + DEC AH + JNZ FINDOP +OPERR: + MOV CL,12 + JMP ERROR + +HAVOP: + MOV AL,[BX+2] ;Get opcode + JMP [BX] + +NDPOP: ;First letter is "F" so must be 8087 opcode ("Numeric Data Processor") + MOV B,[MAXFLG],4 ;Allow all type flags + INC BX + CMP B,[BX],"n" ;"No-wait" form? + MOV AH,0 + JNZ SAVNFLG + MOV AH,1 + DEC AL + INC BX ;Skip over the "N" +SAVNFLG: + MOV [NOWAIT],AH ;0 for wait, 1 for no wait + CMP AL,1 + JB OPERR ;Not enough char left for valid opcode? + CMP AL,5 + JA OPERR ;Too many? + CBW + XCHG AX,DX ;Save length in DX + MOV SI,DX + OR B,[SI+BX],80H ;Set high bit of last character + MOV AL,[BX] ;Get first char of opcode + INC BX + SUB AL,"a" + JB TRY2XM1 ;Go see if opcode starts with "2" + CMP AL,"z"-"a" + JA OPERR + CBW + SHL AX ;Double to index into address table + XCHG AX,SI ;Put in index register + MOV DI,[SI+NDPTAB] ;Get start of opcode table for this letter +LOOKNDP: + MOV AH,[DI] ;Number of opcodes starting with this letter + OR AH,AH + JZ OPERR ;Any start with this letter? +FNDNDP: + INC DI + MOV SI,BX ;Pointer to start of opcode + MOV CX,DX ;Get length of opcode + REPE + CMPB ;Compare opcode to table entry + JZ HAVNDP + DEC DI ;Back up in case that was last letter + MOV AL,80H ;Look for char with high bit set +ENDOP: + SCASB + JA ENDOP + INC DI ;Skip over info about opcode + DEC AH + JNZ FNDNDP +OPERRJ: JP OPERR + +TRY2XM1: + CMP AL,"2"-"a" + JNZ OPERR + MOV DI,XM1 + JP LOOKNDP + +SPECIALOP: + AND AL,7 ;Mask to special op number + JZ FWAIT ;If zero, go handle FWAIT +;Handle FNOP + CMP B,[NOWAIT],0 ;Was "N" present (If not opcode was "FOP") + JZ OPERR + MOV AL,9BH ;Need Wait opcode after all + CALL PUT + MOV AL,0D9H + CALL PUT + MOV AL,0D0H + JMP PUT + +FWAIT: + CMP B,[NOWAIT],0 ;"FNWAIT" not legal + JNZ OPERRJ + RET ;Nothing to do - "WAIT" already sent + +HAVNDP: + MOV SI,DI + CMP B,[NOWAIT],0 + JNZ NWAIT + MOV AL,9BH ;Wait opcode + CALL PUT +NWAIT: + LODW ;Get opcode info + TEST AL,0F8H ;Any operand bits set? + JZ NOOPS ;If no operands, output code + TEST AL,78H ;Special case? + JZ SPECIALOP + PUSH AX + CALL GETSYM ;See if any operands + POP CX + CMP AL,";" + JZ NOOPCHK + CMP AL,EOL + JZ NOOPCHK + CMP AL,FREG ;Is it 8087 register? + JNZ MEMOP + XCHG AX,CX + TEST AL,ONEREG ;One register OK as operand? + JNZ PUTREG ;Yes - save it + TEST AL,20H ;Memory-only operation? + MOV CL,20 + JNZ ERRJ4 + TEST AL,18H ;Two-register operation? + JPE ERRJ4 ;Must be exactly one bit set + PUSH DX ;Save register number + PUSH AX ;Save opcode + CALL GETSYM + CMP AL,"," + MOV CL,15H + JNZ ERRJ4 + CALL GETSYM + MOV CL,20 + CMP AL,FREG + JNZ ERRJ4 + POP AX + POP BX + XOR AL,2 ;Flip "POP" bit + AND AL,0FBH ;Reset direction bit to ST(0) + OR BL,BL ;Is first register ST(0)? + JZ ST0DEST + XCHG DX,BX + OR BL,BL ;One of these must be ST(0) + JNZ ERRJ4 + XOR AL,4 ;Flip direction + JMPS PUTREG +ST0DEST: + TEST AL,2 ;Is POP bit set? + JNZ ERRJ4 ;Don't allow destination ST(0) then pop +PUTREG: + AND AH,0F8H ;Zero out register field + OR AH,DL + OR AH,0C0H + PUSH AX + CALL GETSYM ;Get to next symbol + POP AX + JMPS NOOPS + +NOOPCHK: + XCHG AX,CX + TEST AL,80H ;Is no operands OK? + MOV CL,20 + JNZ ERRJ4 +NOOPS: +;First test for FDIV or FSUB and reverse "R" bit if "D" bit is set + PUSH AX + AND AX,0E005H + CMP AX,0E004H + POP AX + JNZ NOREV + XOR AH,8 ;Reverse "R" bit +NOREV: + AND AL,7 + OR AL,0D8H ;ESC hook + CALL PUT + MOV AL,AH + JMP PUT + +BADFLAG: + MOV CL,20H +ERRJ4: JMP ERROR + +MEMOP: + PUSH CX ;Save opcode + CALL GETOP1 ;Get memory operand + CMP AL,UNDEFID ;Is it? + MOV CL,20 + JNZ ERRJ4 + POP AX + TEST AL,20H ;Does it have memory format field? + JNZ GETFORMAT + TEST AL,8 ;Check if any memory operand legal + JZ ERRJ4 + TEST AL,10H ;Check for 2-op arithmetic + JNZ PUTMEM ;If not, just use as plain memory op +GETFORMAT: + AND AL,0F9H ;Zero memory format bits + MOV CL,[FLAG] + DEC CL ;Must now be in range 0-3 + JL BADFLAG + MOV CH,AL ;Save opcode byte + SHR AL ;Put format bits in bits 2 & 3 + AND AL,0CH + OR AL,CL ;Combine format bits with flag + MOV BX,FORMATTAB + XLAT + OR AL,AL ;Valid combination? + JS BADFLAG + OR AH,AL ;Possibly set new bits in second byte + OR AL,CH ;Set memory format bits +PUTMEM: + AND AL,7 + OR AL,0D8H + CALL PUT + MOV AL,AH + AND AL,38H + OR AL,DL ;Combine addressing mode + JMP PUTADD + +FORMATTAB: +;There are 16 entries in this table. The 4-bit index is built like this: +; Bit 3 0 for normal memory ops, 1 if extended is OK +; Bit 2 0 for integer, 1 for real +; Bit 0 & 1 Flag: 00=W, 01=S, 10=L, 11=T +; +;The entries in the table are used as two 3-bit fields. Bits 0-2 are ORed +;into the first byte of the opcode for the Memory Format field. Bits 3-6 +;are ORed into the second byte to modify the opcode for extended operands. +;If bit 7 is set, then that combination is illegal. + + DB 6,2,80H,80H ;Normal integers + DB 80H,0,4,80H ;Normal reals + DB 6,2,2EH,80H ;Extended integers + DB 80H,0,4,2BH ;Extended reals + +GRP1: + MOV CX,8A09H + CALL MROPS + MOV CX,0C6H + MOV AL,BH + CMP AL,UNDEFID + JNZ L0006 + CALL STIMM +L0006: + AND AL,1 + JZ BYTIMM + MOV AL,0B8H + OR AL,BL + CALL PUT + JMP PUTWOR + +BYTIMM: + MOV AL,0B0H + OR AL,BL + CALL PUT +PUTBJ: JMP PUTBYT + +IMMED: + MOV AL,BH + CMP AL,UNDEFID + JZ STIMM + MOV AL,BL + OR AL,AL + JZ RET + MOV AL,BH + CALL IMM + OR AL,0C0H + CALL PUT +FINIMM: + MOV AL,CL + POP CX + TEST AL,1 + JZ PUTBJ + CMP AL,83H + JZ PUTBJ + JMP PUTWOR + +STIMM: + MOV AL,[FLAG] + CALL IMM + CALL PUTADD + JP FINIMM + +IMM: + AND AL,1 + OR AL,CL + MOV CL,AL + CALL PUT + MOV AL,CH + AND AL,38H + OR AL,BL + RET + +PUT: +;Save byte in AL as pure code, with intermediate code bits 00. AL and +;DI destroyed, no other registers affected. + PUSH BX + PUSH CX + MOV CH,0 ;Flag as pure code + CALL GEN + POP CX + POP BX + RET + +GEN: +;Save byte of code in AL, given intermediate code bits in bits 7&8 of CH. + CALL PUTINC ;Save it and bump code pointer +GEN1: + MOV AL,[RELOC] + RCL CH + RCL AL + RCL CH + RCL AL + MOV [RELOC],AL + MOV BX,BCOUNT + DEC B,[BX] + JNZ RET + MOV B,[BX],4 + MOV BX,RELOC + MOV AL,[BX] + MOV B,[BX],0 + MOV DI,[IY] + MOV [DI],AL + MOV BX,[CODE] + MOV [IY],BX + INC BX + MOV [CODE],BX + RET + +PUTINC: + INC [PC] +PUTCD: + MOV DI,[CODE] + STOB + MOV [CODE],DI + RET + +PUTWOR: +;Save the word value described by [DLABEL] and [DATA] as code. If defined, +;two bytes of pure code will be produced. Otherwise, appropriate intermediate +;code will be generated. + PUSH CX + MOV CH,80H + PUSH DX + PUSH BX + JP PUTBW + +PUTBYT: +;Same as PUTWOR, above, but for byte value. + PUSH CX + MOV CH,40H + PUSH DX + PUSH BX + MOV BX,[DLABEL] + MOV AL,BH + OR AL,BL + JNZ PUTBW + MOV BX,[DATA] + OR AL,BH + JZ PUTBW + INC BH + JZ PUTBW + MOV CL,31 + JMP ERROR +PUTBW: + MOV DX,[DLABEL] + MOV BX,[DATA] +PUTCHK: + OR DX,DX + JZ NOUNDEF + MOV AL,DL + CALL PUTCD + MOV AL,DH + CALL PUTCD + MOV AL,BL + CALL PUTINC + MOV AL,BH + TEST CH,080H + JZ SMPUT + CALL GEN + JP PRET +SMPUT: + CALL PUTCD + CALL GEN1 +PRET: + POP BX + POP DX + POP CX + RET + +NOUNDEF: + MOV AL,BL + MOV CL,BH + PUSH CX + MOV CH,0 + CALL GEN + POP CX + MOV AL,CL + TEST CH,080H + MOV CH,0 + JZ PRET + CALL GEN + JP PRET + +PUTADD: +;Save complete addressing mode. Addressing mode is in AL; if this is a register +;operation (>=C0), then the one byte will be saved as pure code. Otherwise, +;the details of the addressing mode will be investigated and the optional one- +;or two-byte displacement will be added, as described by [ADDR] and [ALABEL]. + PUSH CX + PUSH DX + PUSH BX + MOV CH,0 + MOV CL,AL + CALL GEN ;Save the addressing mode as pure code + MOV AL,CL + MOV CH,80H + AND AL,0C7H + CMP AL,6 + JZ TWOBT ;Direct address? + AND AL,0C0H + JZ PRET ;Indirect through reg, no displacement? + CMP AL,0C0H + JZ PRET ;Register to register operation? + MOV CH,AL ;Save whether one- or two-byte displacement +TWOBT: + MOV BX,[ADDR] + MOV DX,[ALABEL] + JP PUTCHK + +GRP2: + CALL GETOP + MOV CX,0FF30H + CMP AL,UNDEFID + JZ PMEM + MOV CH,50H + CMP AL,XREG + JZ PXREG + MOV CH,6 + CMP AL,SREG + JNZ $+5 + JMP PACKREG + MOV CL,20 + JMP ERROR + +PMEM: + MOV AL,CH + CALL PUT + MOV AL,CL + OR AL,DL + JMP PUTADD + +PXREG: + MOV AL,CH + OR AL,DL + JMP PUT + +GRP3: + CALL GETOP + PUSH DX + CALL GETOP2 + POP BX + MOV CX,8614H + MOV AL,SREG + CMP AL,BH + JZ ERR6 + CMP AL,DH + JZ ERR6 + MOV AL,CONST + CMP AL,BH + JZ ERR6 + CMP AL,DH + JZ ERR6 + MOV AL,UNDEFID + CMP AL,BH + JZ EXMEM + CMP AL,DH + JZ EXMEM1 + MOV AL,BH + CMP AL,DH + MOV CL,22 + JNZ ERR6 + CMP AL,XREG + JZ L0008 + CALL RR1 +L0008: ;RR1 never returns + MOV AL,BL + OR AL,AL + JZ EXACC + XCHG DX,BX + MOV AL,BL + OR AL,AL + MOV AL,BH + JZ EXACC + CALL RR1 +EXACC: + MOV AL,90H + OR AL,DL + JMP PUT + +EXMEM: + XCHG DX,BX +EXMEM1: + CMP AL,BH + JZ ERR6 + MOV CL,1 ;Flag word as OK + CALL NOTAC ;NOTAC never returns +ERR6: JMP ERROR + +GRP4: + PUSH AX + CALL GETOP + POP CX + XCHG CL,CH + CMP AL,CONST + JZ FIXED + SUB AL,XREG + DEC DL + DEC DL + OR AL,DL + MOV CL,20 + JNZ ERR6 + MOV AL,CH + OR AL,8 + JMP PUT +FIXED: + MOV AL,CH + CALL PUT + JMP PUTBYT + +GRP5: + PUSH AX + CALL GETOP + MOV CL,20 + CMP AL,CONST + JNZ ERR6 + MOV BX,[DLABEL] + MOV AL,BH + OR AL,BL + MOV CL,30 + JNZ ERR6 + MOV BX,[DATA] + POP AX + OR AL,AL + JZ ORG + DEC AL + JZ DSJ + DEC AL + JZ EQU + DEC AL + JZ $+5 + JMP IF +PUTOP: + MOV AL,-3 + JP NEWLOC +ALIGN: + MOV AL,[PC] + AND AL,1 + JZ RET + MOV BX,1 +DSJ: + XCHG DX,BX + MOV BX,[PC] + ADD BX,DX + MOV [PC],BX + XCHG DX,BX + MOV AL,-4 + JP NEWLOC +EQU: + XCHG DX,BX + MOV BX,[LABPT] + MOV AL,BH + OR AL,BL + MOV CL,34 + JZ ERR7 + MOV [BX],DL + INC BX + MOV [BX],DH + RET +ORG: + MOV [PC],BX + MOV AL,-2 +NEWLOC: + CALL PUTCD + MOV AL,BL + CALL PUTCD + MOV AL,BH + CALL PUTCD + MOV CH,0C0H + JMP GEN1 +GRP6: + MOV CH,AL + MOV CL,4 + CALL MROPS + MOV CL,23 +ERR7: JMP ERROR +GRP7: + MOV CH,AL + MOV CL,1 + CALL MROPS + MOV CL,80H + MOV DX,[DLABEL] + MOV AL,DH + OR AL,DL + JNZ ACCJ + XCHG DX,BX + MOV BX,[DATA] + MOV AL,BL + CBW + CMP AX,BX + XCHG DX,BX + JNZ ACCJ + OR CL,002H +ACCJ: JMP ACCIMM +GRP8: + MOV CL,AL + MOV CH,0FEH + JP ONEOP +GRP9: + MOV CL,AL + MOV CH,0F6H +ONEOP: + PUSH CX + CALL GETOP +ONE: + MOV CL,26 + CMP AL,CONST + JZ ERR7 + CMP AL,SREG + MOV CL,22 + JZ ERR7 + POP CX + CMP AL,UNDEFID + JZ MOP + AND AL,1 + JZ ROP + TEST CL,001H + JZ ROP + MOV AL,CL + AND AL,0F8H + OR AL,DL + JMP PUT +MOP: + MOV AL,[FLAG] + AND AL,1 + OR AL,CH + CALL PUT + MOV AL,CL + AND AL,38H + OR AL,DL + JMP PUTADD +ROP: + OR AL,CH + CALL PUT + MOV AL,CL + AND AL,38H + OR AL,0C0H + OR AL,DL + JMP PUT +GRP10: + MOV CL,AL + MOV CH,0F6H + PUSH CX + CALL GETOP + MOV CL,20 + MOV AL,DL + OR AL,AL + JNZ ERRJ1 + MOV AL,DH + CMP AL,XREG + JZ G10 + CMP AL,REG +ERRJ1: JNZ ERR8 +G10: + PUSH AX + CALL GETOP + POP AX + AND AL,1 + MOV [FLAG],AL + MOV AL,DH +ONEJ: JP ONE +GRP11: + CALL PUT + MOV AL,0AH + JMP PUT +GRP12: + MOV CL,AL + MOV CH,0D0H + PUSH CX + CALL GETOP + MOV AL,[SYM] + CMP AL,',' + MOV AL,DH + JNZ ONEJ + PUSH DX + CALL GETOP + SUB AL,REG + MOV CL,20 + DEC DL + OR AL,DL + JNZ ERR8 + POP DX + MOV AL,DH + POP CX + OR CH,002H + PUSH CX + JMP ONE +GRP13: + MOV CH,AL + MOV CL,1 + CALL MROPS + MOV CL,80H +ACCIMM: + CALL IMMED + OR CH,004H + AND CH,0FDH +AIMM: + MOV AL,BH + AND AL,1 + LAHF + PUSH AX + OR AL,CH + CALL PUT + POP AX + SAHF + JNZ $+5 + JMP PUTBYT + JMP PUTWOR + +ERR8: JMP ERROR + +GRP14: +;JMP and CALL mnemonics + LAHF + XCHG AH,AL + PUSH AX + XCHG AH,AL + MOV B,[MAXFLG],3 ;Allow "L" flag + CALL GETOP + CMP AL,CONST + JZ DIRECT + MOV CL,20 + CMP AL,REG + JZ ERR8 + CMP AL,SREG + JZ ERR8 + CMP AL,XREG + JNZ NOTRG + OR DL,0C0H +NOTRG: +;Indirect jump. DL has addressing mode. + MOV AL,0FFH + CALL PUT + POP AX + XCHG AH,AL + SAHF + AND AL,38H + OR AL,DL + MOV CH,[FLAG] + CMP CH,3 ;Flag "L" present? + JZ PUTADDJ ;If so, do inter-segment + MOV CL,27H + CMP CH,-1 ;Better not be a flag + JNZ ERR8 + AND AL,0F7H ;Convert to intra-segment +PUTADDJ: + JMP PUTADD +DIRECT: + MOV AL,[SYM] + CMP AL,',' + JZ LONGJ + POP AX + XCHG AH,AL + SAHF + DEC AL + CMP AL,0E9H + JZ GOTOP + MOV AL,0E8H +GOTOP: + CALL PUT + MOV DX,[PC] + INC DX + INC DX + SUB [DATA],DX + JMP PUTWOR +LONGJ: + POP AX + XCHG AH,AL + SAHF + CALL PUT + CALL PUTWOR + CALL GETOP + MOV CL,20 + CMP AL,CONST + JNZ ERR8 + JMP PUTWOR + +GRP16: +;RET mnemonic + LAHF + XCHG AH,AL + PUSH AX + XCHG AH,AL + CALL GETSYM + CMP AL,5 + JZ LONGR + CMP AL,EOL + JZ NODEC + CMP AL,';' + JZ NODEC +GETSP: + CALL GETOP1 + POP CX + CMP AL,CONST + MOV CL,20 + JNZ ERR9 + MOV AL,CH + AND AL,0FEH + CALL PUT + JMP PUTWOR +LONGR: + CMP DL,3 ;Is flag "L"? + MOV CL,27H + JNZ ERR10 ;If not, bad flag + POP AX + XCHG AH,AL + SAHF + OR AL,8 + LAHF + XCHG AH,AL + PUSH AX + XCHG AH,AL +NOTLON: + CALL GETSYM + CMP AL,EOL + JZ DORET + CMP AL,';' + JZ DORET + CMP AL,',' + JNZ L0011 + CALL GETSYM +L0011: + JP GETSP +NODEC: +;Return is intra-segment (short) without add to SP. +;Record position for RET symbol. + MOV BX,[PC] + MOV [LSTRET],BX + XCHG DX,BX + MOV BX,[RETPT] + MOV AL,BH + OR AL,BL + JZ DORET + MOV B,[BX],1 + INC BX + MOV [BX],DX + MOV BX,0 + MOV [RETPT],BX +DORET: + POP AX + XCHG AH,AL + SAHF + JMP PUT + +GRP17: + CALL PUT + CALL GETOP + CMP AL,CONST + MOV CL,20 +ERR9: JNZ ERR10 + MOV BX,[DATA] + MOV DX,[PC] + INC DX + SUB BX,DX + MOV [DATA],BX + CALL PUTBYT + MOV BX,[DLABEL] + MOV AL,BH + OR AL,BL + JNZ RET + MOV BX,[DATA] + MOV AL,BL + CBW + CMP AX,BX ;Signed 8-bit number? + JZ RET + MOV CL,31 +ERR10: JMP ERROR + RET +GRP18: + CALL GETOP + CMP AL,CONST + MOV CL,20 + JNZ ERR10 + MOV BX,[DLABEL] + MOV AL,BH + OR AL,BL + JNZ GENINT + MOV BX,[DATA] + MOV DX,3 + SBB BX,DX + JNZ GENINT + MOV AL,0CCH + JMP PUT +GENINT: + MOV AL,0CDH + CALL PUT + JMP PUTBYT + +GRP19: ;ESC opcode + CALL GETOP + MOV CL,20 + CMP AL,CONST + JNZ ERRJ ;First operand must be immediate + MOV CL,1EH + TEST [DLABEL],-1 ;See if all labels have been defined + JNZ ERRJ + MOV AX,[DATA] + CMP AX,64 ;Must only be 6 bits + MOV CL,1FH + JNB ERRJ + MOV BL,AL ;Save for second byte + SHR AL + SHR AL + SHR AL + OR AL,0D8H ;ESC opcode + CALL PUT + PUSH BX + CALL GETOP2 + POP BX + AND BL,7 ;Low 3 bits of first operand + SHL BL + SHL BL + SHL BL + CMP AL,UNDEFID ;Check for memory operand + JZ ESCMEM + CMP AL,CONST ;Check for another immediate + JZ ESCIMM + MOV CL,20 +ERRJ: JMP ERROR + +ESCMEM: + OR BL,DL ;Combine mode with first operand + MOV AL,BL + JMP PUTADD + +ESCIMM: + MOV CL,1EH + TEST [DLABEL],-1 ;See if second operand is fully defined + JNZ ERRJ + MOV AX,[DATA] + MOV CL,1FH + CMP AX,8 ;Must only be 3 bit value + JNB ERRJ + OR AL,BL ;Combine first and second operands + OR AL,0C0H ;Force "register" mode + JMP PUT + +GRP20: + MOV CH,AL + MOV CL,1 + CALL MROPS + MOV CL,0F6H + CALL IMMED + MOV CH,0A8H + JMP AIMM +GRP21: + CALL GETOP + CMP AL,SREG + MOV CL,28 + JNZ ERRJ + MOV CH,26H +PACKREG: + MOV AL,DL + ADD AL,AL + ADD AL,AL + ADD AL,AL + OR AL,CH + JMP PUT +GRP22: + CALL GETOP + MOV CX,8F00H + CMP AL,UNDEFID + JNZ $+5 + JMP PMEM + MOV CH,58H + CMP AL,XREG + JNZ $+5 + JMP PXREG + MOV CH,7 + CMP AL,SREG + JZ PACKREG + MOV CL,20 +ERR11: JMP ERROR +GRP23: + MOV [DATSIZ],AL +GETDAT: + CALL GETSYM + MOV AL,2 + CALL VAL1 + MOV AL,[SYM] + CMP AL,',' + MOV AL,[DATSIZ] + JNZ ENDDAT + CALL SAVDAT + JP GETDAT +ENDDAT: + CMP AL,2 + JNZ SAVDAT + MOV BX,[DATA] + LAHF + OR BL,080H + SAHF + MOV [DATA],BX +SAVDAT: + OR AL,AL + JZ $+5 + JMP PUTBYT + JMP PUTWOR +IF: + OR BX,BX + JZ SKIPCD + INC B,[IFFLG] + RET + +SKIPCD: + INC B,[CHKLAB] +SKIPLP: + XOR AL,AL + CALL NEXLIN + CALL NEXTCHR + CMP AL,1AH + JZ END + CALL GETLAB + JC SKIPLP + MOV DI,LENID + MOV SI,IFEND + MOV CH,0 + MOV CL,[DI] + INC CL + REPE + CMPB + JZ ENDCOND + MOV DI,LENID + MOV SI,IFNEST + MOV CL,[DI] + INC CL + REPE + CMPB + JNZ SKIPLP + INC B,[CHKLAB] + JP SKIPLP + +ENDCOND: + DEC B,[CHKLAB] + JNZ SKIPLP + RET + +ENDIF: + MOV AL,[IFFLG] + MOV CL,36 + DEC AL + JS ERRJMP + MOV [IFFLG],AL + RET + +ERRJMP: JMP ERROR + +;********************************************************************* +; +; PASS 2 +; +;********************************************************************* + +END: + MOV DL,4 +WREND: + MOV CH,0FFH + MOV AL,CH + CALL GEN + DEC DL + JNZ WREND + MOV [BUFPT],SRCBUF + MOV B,[HEXCNT],-5 ;FLAG HEX BUFFER AS EMPTY + MOV [LSTPNT],LSTBUF + MOV [HEXPNT],HEXBUF + XOR AX,AX + MOV [ERRCNT],AX + MOV [PC],AX + MOV [LINE],AX ;Current line number + MOV [HEXADD],OBJECT + MOV DX,FCB + MOV AH,OPEN + INT 33 ;Re-open source file + XOR AX,AX + MOV [FCB+12],AX ;Set CURRENT BLOCK to zero + MOV [FCB+20H],AL ;Set NEXT RECORD field to zero + MOV [FCB+14],BUFSIZ + MOV [COUNT],AL + MOV CH,1 + MOV SI,START +FIXLINE: + MOV DI,START ;Store code over used up intermediate code + XOR AL,AL + MOV [SPC],AL ;No "special" yet (ORG, PUT, DS) + MOV [ERR],AL ;No second pass errors yet +NEXBT: + SHL CL ;Shift out last bit of previous code + DEC CH ;Still have codes left? + JNZ TESTTYP + LODB ;Get next flag byte + MOV CL,AL + MOV CH,4 +TESTTYP: + SHL CL ;Set flags based on two bits + JO FIXUP + LODB + JC EMARK +OBJBT: + STOB + JP NEXBT + +FIXUP: +;Either a word or byte fixup is needed from a forward reference + LODW ;Get pointer to symbol + XCHG AX,BX + LODW ;Get constant part + ADD AX,[BX+1] ;Add symbol value to constant part + CMP B,[BX],0 ;See if symbol got defined + JNZ HAVDEF + MOV B,[ERR],100 ;Undefined - flag error + XOR AX,AX +HAVDEF: + OR CL,CL ;See if word or byte fixup + JS DEFBYT + STOW + JP NEXBT + +DEFBYT: + MOV DX,AX + CBW ;Extend sign + CMP AX,DX ;See if in range +127 to -128 + JZ OBJBT ;If so, it's always OK + NOT AH ;Check for range +255 to -256 + CMP AH,DH + JNZ RNGERR ;Must always be in this range +;Check for short jump. If so, we're out of range; otherwise we're OK + CMP DI,START+1 ;Only one other byte on line? + JNZ OBJBT ;Can't be short jump if not + MOV AL,[START] ;Get the first byte of this line + CMP AL,0EBH ;Direct short jump? + JZ RNGERR + AND AL,0FCH + CMP AL,0E0H ;LOOP or JCXZ instruction? + JZ RNGERR + AND AL,0F0H + CMP AL,70H ;Conditional jump? + MOV AL,DL ;Get code byte in AL + JNZ OBJBT ;If not, we're OK +RNGERR: + MOV B,[ERR],101 ;Value out of range + JP OBJBT + +FINIJ: JMP FINI + +EMARK: + CMP AL,-1 ;End of file? + JZ FINIJ + CMP AL,-10 ;Special item? + JA SPEND + PUSH CX + PUSH SI + PUSH AX ;Save error code + MOV AH,[LSTDEV] + AND AH,0FEH ;Reset error indicator + OR AL,[ERR] ;See if any errors on this line + JZ NOERR + OR AH,1 ;Send line to console if error occured +NOERR: + MOV [LSTDEV],AH + MOV CX,DI + CALL STRTLIN ;Print address of line + MOV SI,START + SUB CX,SI ;Get count of bytes of code + JZ SHOLIN +CODLP: + LODB + CALL SAVCD ;Ouput code to HEX and PRN files + LOOP CODLP +SHOLIN: + MOV AL,0 + XCHG AL,[COUNT] + MOV CX,7 ;Allow 7 bytes of code per line + SUB CL,AL + MOV AL,' ' + JZ NOFIL +BLNK: ;Put in 3 blanks for each byte not present + CALL LIST + CALL LIST + CALL LIST + LOOP BLNK +NOFIL: + CALL OUTLIN + POP AX ;Restore error code + CALL REPERR + MOV AL,[ERR] + CALL REPERR + POP SI + POP CX + MOV AL,[SPC] ;Any special funtion? + OR AL,AL + JNZ SPCFUN + JMP FIXLINE + +SPEND: + MOV [SPC],AL ;Record special function + LODW ;Get it's data + MOV [DATA],AX + JMP NEXBT + +SPCFUN: + MOV DX,[DATA] + CMP AL,-2 + JZ DORG + CMP AL,-3 + JZ DPUT +DDS: +;Handle DS pseudo-op + ADD [PC],DX + ADD [HEXADD],DX + JMP FIXLINE + +DORG: +;Handle ORG pseudo-op + MOV [PC],DX + JMP FIXLINE + +DPUT: +;Handle PUT pseudo-op + MOV [HEXADD],DX + JMP FIXLINE + +OUTLIN: +;Copy the source line to the ouput device. Line will be preceded by +;assembler-generated line number. This routine may be called several times +;on one line (once for each line of object code bytes), so it sets a flag +;so the line will only be output on the first call. + MOV AL,-1 + XCHG AL,[LINFLG] + OR AL,AL + JNZ CRLF ;Output line only if first time + MOV AX,[LINE] + INC AX + MOV [LINE],AX + MOV BH,0 ;No leading zero suppression + CALL OUT10 + MOV AL," " + CALL LIST + MOV AL,[LSTFCB] + CMP AL,'Z' + JZ CRLF ;Don't call NEXTCHR if listing suppressed + PUSH SI ;Save the only register destroyed by NEXTCHR +OUTLN: + CALL NEXTCHR + CALL LIST + CMP AL,10 ;Output until linefeed found + JNZ OUTLN + POP SI + RET + +PRTCNT: + MOV AX,[ERRCNT] + MOV BX,ERCNTM +PRNT10: + PUSH AX + CALL PRINT + POP AX + MOV BH,"0"-" " ;Enable leading zero suppression + CALL OUT10 +CRLF: + MOV AL,13 + CALL LIST + MOV AL,10 + JP LIST + +OUT10: + XOR DX,DX + MOV DI,10000 + DIV AX,DI + OR AL,AL ;>10,000? + JNZ LEAD + SUB AL,"0"-" " ;Convert leading zero to blank +LEAD: + ADD AL,"0" + CALL LIST + XCHG AX,DX + MOV BL,100 + DIV AL,BL + MOV BL,AH + CALL HIDIG ;Convert to decimal and print 1000s digit + CALL DIGIT ;Print 100s digit + MOV AL,BL + CALL HIDIG ;Convert to decimal and print 10s digit + MOV BH,0 ;Ensure leading zero suppression is off + JP DIGIT + +HIDIG: + AAM ;Convert binary to unpacked BCD + OR AX,3030H ;Add "0" bias +DIGIT: + XCHG AL,AH + CMP AL,"0" + JZ SUPZ + MOV BH,0 ;Turn off zero suppression if not zero +SUPZ: + SUB AL,BH ;Convert leading zeros to blanks + JP LIST + +STRTLIN: + MOV B,[LINFLG],0 + MOV BX,[PC] + MOV AL,BH + CALL PHEX + MOV AL,BL +PHEXB: + CALL PHEX + MOV AL,' ' +LIST: + PUSH AX + PUSH DX + AND AL,7FH + MOV DL,AL + TEST B,[LSTDEV],3 ;See if output goes to console + JZ PRNCHK + MOV AH,2 + INT 33 ;Output to console +PRNCHK: + TEST B,[LSTDEV],4 ;See if output goes to printer + JZ FILCHK + MOV AH,5 + INT 33 ;Output to printer +FILCHK: + MOV AL,DL + POP DX + TEST B,[LSTDEV],80H ;See if output goes to a file + JZ LISTRET + CALL WRTBUF +LISTRET: + POP AX + RET + +WRTBUF: + PUSH DI + MOV DI,[LSTPNT] + STOB + CMP DI,LSTBUF+LSTBUFSIZ + JNZ SAVPT + PUSH AX + PUSH CX + PUSH DX + CALL FLUSHBUF + POP DX + POP CX + POP AX +SAVPT: + MOV [LSTPNT],DI + POP DI + RET + +PHEX: + PUSH AX + CALL UHALF + CALL LIST + POP AX + CALL LHALF + JP LIST + +FINI: + OR B,[LSTDEV],1 + CALL PRTCNT + MOV BX,SYMSIZE + MOV AX,[6] + SUB AX,[HEAP] ;Size of symbol table + CALL PRNT10 + MOV BX,FRESIZE + MOV AX,[HEAP] + SUB AX,[CODE] ;Free space remaining + CALL PRNT10 + AND B,[LSTDEV],0FEH + MOV AL,[HEXFCB] + CMP AL,'Z' + JZ SYMDMP + MOV AL,[HEXCNT] + CMP AL,-5 + JZ L0012 + CALL ENHEXL +L0012: + MOV AL,':' + CALL PUTCHR + MOV CH,10 +HEXEND: + PUSH CX + MOV AL,'0' + CALL PUTCHR + POP CX + DEC CH + JNZ HEXEND + MOV AL,13 + CALL PUTCHR + MOV AL,10 + CALL PUTCHR + MOV AL,1AH + CALL PUTCHR + CALL WRTHEX ;Flush HEX file buffer + MOV DX,HEXFCB + MOV AH,CLOSE + INT 33 +SYMDMP: + MOV AL,[SYMFLG] + CMP AL,'S' + JNZ ENDSYM + MOV AL,[LSTDEV] + OR AL,AL ;Any output device for symbol table dump? + JNZ DOSYMTAB + OR AL,1 ;If not, send it to console + MOV [LSTDEV],AL +DOSYMTAB: + MOV BX,SYMMES + CALL PRINT + MOV DX,[BASE] + MOV AL,DH + OR AL,DL + JZ ENDSYM + MOV B,[SYMLIN],SYMWID ;No symbols on this line yet + MOV BX,[HEAP] + MOV SP,BX ;Need maximum stack for recursive tree walk + CALL NODE +ENDSYM: + TEST B,[LSTDEV],80H ;Print listing to file? + JZ EXIT + MOV AL,1AH + CALL WRTBUF ;Write end-of-file mark + MOV DI,[LSTPNT] + CALL FLUSHBUF + MOV AH,CLOSE + INT 33 +EXIT: JMP 0 + +NODE: + XCHG DX,BX + PUSH BX + MOV DL,[BX] + MOV DH,0 + INC BX + ADD BX,DX + MOV DX,[BX] + OR DX,DX + JZ L0014 + CALL NODE +L0014: + POP BX + MOV AL,[BX] + INC BX + MOV CH,AL + ADD AL,24 + SHR AL + SHR AL + SHR AL + MOV CL,AL + INC CL ;Invert last bit + AND CL,1 ;Number of extra tabs needed (0 or 1) + SHR AL ;Number of positions wide this symbol needs + SUB [SYMLIN],AL + JNC WRTSYM ;Will it fit? + SUB AL,SYMWID + NEG AL + MOV [SYMLIN],AL + CALL CRLF ;Start new line if not +WRTSYM: + MOV AL,[BX] + INC BX + CALL LIST + DEC CH + JNZ WRTSYM + INC CL +TABVAL: + MOV AL,9 + CALL LIST + LOOP TABVAL + INC BX + INC BX + PUSH BX + MOV AL,[BX+4] + CALL PHEX + MOV AL,[BX+3] + CALL PHEX + CMP B,[SYMLIN],0 ;Will any more fit on line? + JZ NEXSYMLIN + MOV AL,9 + CALL LIST + JP RIGHTSON +NEXSYMLIN: + CALL CRLF + MOV B,[SYMLIN],SYMWID +RIGHTSON: + POP BX + MOV DX,[BX] + OR DX,DX + JNZ NODE + RET + +SAVCD: + MOV [PREV],AL + PUSH BX + PUSH CX + PUSH AX + PUSH DX + CALL CODBYT + POP DX + MOV BX,COUNT + INC B,[BX] + MOV AL,[BX] + CMP AL,8 + JNZ NOEXT + MOV B,[BX],1 + CALL OUTLIN + MOV AL,' ' + MOV CH,5 +TAB: + CALL LIST + DEC CH + JNZ TAB +NOEXT: + POP AX + CALL PHEXB + POP CX + INC [PC] + INC [HEXADD] + POP BX + RET + +REPERR: + OR AL,AL ;Did an error occur? + JZ RET + INC [ERRCNT] + PUSH AX + MOV BX,ERRMES ;Print "ERROR" + CALL PRINT + POP AX +;We have error number in AL. See if there's an error message for it + MOV DI,ERRTAB + MOV BL,80H +ERRLOOK: + SCASB ;Do we have the error message + JBE HAVMES ;Quit looking if we have it or passed it + XCHG AX,BX ;Put 80H in AL to look for end of this message +NEXTMES: + SCASB ;Look for high bit set in message + JA NEXTMES ; which means we've reached the end + XCHG AX,BX ;Restore error number to AL + JMPS ERRLOOK ;Keep looking + +HAVMES: + MOV BX,DI ;Put address of message in BX + JZ PRNERR ;Do we have a message for this error? + CALL PHEX ;If not, just print error number + JMP CRLF + +PRNERR: + CALL PRINT + JMP CRLF + +PRINT: + MOV AL,[BX] + CALL LIST + OR AL,AL + JS RET + INC BX + JP PRINT + +OUTA: + MOV DL,AL +OUT: + AND DL,7FH + MOV CL,2 +SYSTEM: + CALL 5 + RET + +CODBYT: + CMP B,[HEXFCB],"Z" + JZ RET + PUSH AX + MOV DX,[LASTAD] + MOV BX,[HEXADD] + MOV [LASTAD],BX + INC DX + MOV AL,[HEXCNT] + CMP AL,-5 + JZ NEWLIN + CMP BX,DX + JZ AFHEX + CALL ENHEXL +NEWLIN: + MOV AL,':' + CALL PUTCHR + MOV AL,-4 + MOV [HEXCNT],AL + XOR AL,AL + MOV [CHKSUM],AL + MOV BX,[HEXPNT] + MOV [HEXLEN],BX + CALL HEXBYT + MOV AL,[HEXADD+1] + CALL HEXBYT + MOV AL,[HEXADD] + CALL HEXBYT + XOR AL,AL + CALL HEXBYT +AFHEX: + POP AX +HEXBYT: + MOV CH,AL + MOV BX,CHKSUM + ADD AL,[BX] + MOV [BX],AL + MOV AL,CH + CALL UHALF + CALL PUTCHR + MOV AL,CH + CALL LHALF + CALL PUTCHR + MOV BX,HEXCNT + INC B,[BX] + MOV AL,[BX] + CMP AL,26 + JNZ RET +ENHEXL: + MOV DI,[HEXLEN] + MOV CH,AL + CALL UHALF + STOB + MOV AL,CH + CALL LHALF + STOB + MOV AL,-6 + MOV [HEXCNT],AL + MOV AL,[CHKSUM] + ADD AL,CH + NEG AL + CALL HEXBYT + MOV AL,13 + CALL PUTCHR + MOV AL,10 + CALL PUTCHR +WRTHEX: +;Write out the line + MOV DX,HEXBUF + MOV [HEXPNT],DX + MOV AH,SETDMA + INT 33 + SUB DI,DX ;Length of buffer + MOV CX,DI + MOV DX,HEXFCB + MOV AH,BLKWRT + INT 33 + OR AL,AL + JNZ DSKFUL + RET + +PUTCHR: + MOV DI,[HEXPNT] + STOB + MOV [HEXPNT],DI + RET + +FLUSHBUF: + MOV CX,DI + MOV DX,LSTBUF + MOV DI,DX + SUB CX,DX + JZ RET ;Buffer empty? + MOV AH,SETDMA + INT 33 + MOV DX,LSTFCB + MOV AH,BLKWRT + INT 33 + OR AL,AL + JZ RET +DSKFUL: + MOV BX,WRTERR + JMP PRERR + +UHALF: + RCR AL + RCR AL + RCR AL + RCR AL +LHALF: + AND AL,0FH + OR AL,30H + CMP AL,'9'+1 + JC RET + ADD AL,7 + RET + +NONE: DB 0 + +; 8086 MNEMONIC TABLE + +; This table is actually a sequence of subtables, each starting with a label. +; The label signifies which mnemonics the subtable applies to--A3, for example, +; means all 3-letter mnemonics beginning with A. + +A3: + DB 7 + DB 'dd' + DW GRP7 + DB 2 + DB 'nd' + DW GRP13 + DB 22H + DB 'dc' + DW GRP7 + DB 12H + DB 'aa' + DW PUT + DB 37H + DB 'as' + DW PUT + DB 3FH + DB 'am' + DW GRP11 + DB 0D4H + DB 'ad' + DW GRP11 + DB 0D5H +A5: + DB 1 + DB 'lign' + DW ALIGN + DB 0 +C3: + DB 7 + DB 'mp' + DW GRP7 + DB 3AH + DB 'lc' + DW PUT + DB 0F8H + DB 'ld' + DW PUT + DB 0FCH + DB 'li' + DW PUT + DB 0FAH + DB 'mc' + DW PUT + DB 0F5H + DB 'bw' + DW PUT + DB 98H + DB 'wd' + DW PUT + DB 99H +C4: + DB 3 + DB 'all' + DW GRP14 + DB 9AH + DB 'mpb' + DW PUT + DB 0A6H + DB 'mpw' + DW PUT + DB 0A7H +C5: + DB 2 + DB 'mpsb' + DW PUT + DB 0A6H + DB 'mpsw' + DW PUT + DB 0A7H +D2: + DB 5 + DB 'b' + DW GRP23 + DB 1 + DB 'w' + DW GRP23 + DB 0 + DB 'm' + DW GRP23 + DB 2 + DB 's' + DW GRP5 + DB 1 + DB 'i' + DW PUT + DB 0FAH +D3: + DB 4 + DB 'ec' + DW GRP8 + DB 49H + DB 'iv' + DW GRP10 + DB 30H + DB 'aa' + DW PUT + DB 27H + DB 'as' + DW PUT + DB 2FH +D4: + DB 1 + DB 'own' + DW PUT + DB 0FDH +E2: + DB 1 + DB 'i' + DW PUT + DB 0FBH +E3: + DB 3 + DB 'qu' + DW GRP5 + DB 2 + DB 'sc' + DW GRP19 + DB 0D8H + DB 'nd' + DW END + DB 0 +E5: + DB 1 + DB 'ndif' + DW ENDIF + DB 0 +H3: + DB 1 + DB 'lt' + DW PUT + DB 0F4H +H4: + DB 1 + DB 'alt' + DW PUT + DB 0F4H +I2: + DB 2 + DB 'n' + DW GRP4 + DB 0E4H + DB 'f' + DW GRP5 + DB 4 +I3: + DB 4 + DB 'nc' + DW GRP8 + DB 41H + DB 'nb' + DW GRP4 + DB 0E4H + DB 'nw' + DW GRP4 + DB 0E5H + DB 'nt' + DW GRP18 + DB 0CCH +I4: + DB 4 + DB 'mul' + DW GRP10 + DB 28H + DB 'div' + DW GRP10 + DB 38H + DB 'ret' + DW PUT + DB 0CFH + DB 'nto' + DW PUT + DB 0CEH +J2: + DB 10 + DB 'p' + DW GRP17 + DB 0EBH + DB 'z' + DW GRP17 + DB 74H + DB 'e' + DW GRP17 + DB 74H + DB 'l' + DW GRP17 + DB 7CH + DB 'b' + DW GRP17 + DB 72H + DB 'a' + DW GRP17 + DB 77H + DB 'g' + DW GRP17 + DB 7FH + DB 'o' + DW GRP17 + DB 70H + DB 's' + DW GRP17 + DB 78H + DB 'c' + DW GRP17 + DB 72H +J3: + DB 17 + DB 'mp' + DW GRP14 + DB 0EAH + DB 'nz' + DW GRP17 + DB 75H + DB 'ne' + DW GRP17 + DB 75H + DB 'nl' + DW GRP17 + DB 7DH + DB 'ge' + DW GRP17 + DB 7DH + DB 'nb' + DW GRP17 + DB 73H + DB 'ae' + DW GRP17 + DB 73H + DB 'nc' + DW GRP17 + DB 73H + DB 'ng' + DW GRP17 + DB 7EH + DB 'le' + DW GRP17 + DB 7EH + DB 'na' + DW GRP17 + DB 76H + DB 'be' + DW GRP17 + DB 76H + DB 'pe' + DW GRP17 + DB 7AH + DB 'np' + DW GRP17 + DB 7BH + DB 'po' + DW GRP17 + DB 7BH + DB 'no' + DW GRP17 + DB 71H + DB 'ns' + DW GRP17 + DB 79H +J4: + DB 6 + DB 'mps' + DW GRP17 + DB 0EBH + DB 'cxz' + DW GRP17 + DB 0E3H + DB 'nge' + DW GRP17 + DB 7CH + DB 'nae' + DW GRP17 + DB 72H + DB 'nbe' + DW GRP17 + DB 77H + DB 'nle' + DW GRP17 + DB 7FH +L3: + DB 3 + DB 'ea' + DW GRP6 + DB 8DH + DB 'ds' + DW GRP6 + DB 0C5H + DB 'es' + DW GRP6 + DB 0C4H +L4: + DB 5 + DB 'oop' + DW GRP17 + DB 0E2H + DB 'odb' + DW PUT + DB 0ACH + DB 'odw' + DW PUT + DB 0ADH + DB 'ahf' + DW PUT + DB 9FH + DB 'ock' + DW PUT + DB 0F0H +L5: + DB 4 + DB 'oope' + DW GRP17 + DB 0E1H + DB 'oopz' + DW GRP17 + DB 0E1H + DB 'odsb' + DW PUT + DB 0ACH + DB 'odsw' + DW PUT + DB 0ADH +L6: + DB 2 + DB 'oopne' + DW GRP17 + DB 0E0H + DB 'oopnz' + DW GRP17 + DB 0E0H +M3: + DB 2 + DB 'ov' + DW GRP1 + DB 88H + DB 'ul' + DW GRP10 + DB 20H +M4: + DB 2 + DB 'ovb' + DW PUT + DB 0A4H + DB 'ovw' + DW PUT + DB 0A5H +M5: + DB 2 + DB 'ovsb' + DW PUT + DB 0A4H + DB 'ovsw' + DW PUT + DB 0A5H +N3: + DB 3 + DB 'ot' + DW GRP9 + DB 10H + DB 'eg' + DW GRP9 + DB 18H + DB 'op' + DW PUT + DB 90H +O2: + DB 1 + DB 'r' + DW GRP13 + DB 0AH +O3: + DB 2 + DB 'ut' + DW GRP4 + DB 0E6H + DB 'rg' + DW GRP5 + DB 0 +O4: + DB 2 + DB 'utb' + DW GRP4 + DB 0E6H + DB 'utw' + DW GRP4 + DB 0E7H +P3: + DB 2 + DB 'op' + DW GRP22 + DB 8FH + DB 'ut' + DW GRP5 + DB 3 +P4: + DB 2 + DB 'ush' + DW GRP2 + DB 0FFH + DB 'opf' + DW PUT + DB 9DH +P5: + DB 1 + DB 'ushf' + DW PUT + DB 9CH +R3: + DB 6 + DB 'et' + DW GRP16 + DB 0C3H + DB 'ep' + DW PUT + DB 0F3H + DB 'ol' + DW GRP12 + DB 0 + DB 'or' + DW GRP12 + DB 8 + DB 'cl' + DW GRP12 + DB 10H + DB 'cr' + DW GRP12 + DB 18H +R4: + DB 2 + DB 'epz' + DW PUT + DB 0F3H + DB 'epe' + DW PUT + DB 0F3H +R5: + DB 2 + DB 'epnz' + DW PUT + DB 0F2H + DB 'epne' + DW PUT + DB 0F2H +S3: + DB 11 + DB 'ub' + DW GRP7 + DB 2AH + DB 'bb' + DW GRP7 + DB 1AH + DB 'bc' + DW GRP7 + DB 1AH + DB 'tc' + DW PUT + DB 0F9H + DB 'td' + DW PUT + DB 0FDH + DB 'ti' + DW PUT + DB 0FBH + DB 'hl' + DW GRP12 + DB 20H + DB 'hr' + DW GRP12 + DB 28H + DB 'al' + DW GRP12 + DB 20H + DB 'ar' + DW GRP12 + DB 38H + DB 'eg' + DW GRP21 + DB 26H +S4: + DB 5 + DB 'cab' + DW PUT + DB 0AEH + DB 'caw' + DW PUT + DB 0AFH + DB 'tob' + DW PUT + DB 0AAH + DB 'tow' + DW PUT + DB 0ABH + DB 'ahf' + DW PUT + DB 9EH +S5: + DB 4 + DB 'casb' + DW PUT + DB 0AEH + DB 'casw' + DW PUT + DB 0AFH + DB 'tosb' + DW PUT + DB 0AAH + DB 'tosw' + DW PUT + DB 0ABH +T4: + DB 1 + DB 'est' + DW GRP20 + DB 84H +U2: + DB 1 + DB 'p' + DW PUT + DB 0FCH +W4: + DB 1 + DB 'ait' + DW PUT + DB 9BH +X3: + DB 1 + DB 'or' + DW GRP13 + DB 32H +X4: + DB 2 + DB 'chg' + DW GRP3 + DB 86H + DB 'lat' + DW PUT + DB 0D7H + + +; 8087 MNEMONIC TABLE +; Similar to 8086 table above, except NOT distinguished by opcode length + +XM1: ;F2XM1 + DB 1 ;One opcode + DM "xm1" + DB 1,0F0H + +NDPA: + DB 3 + DM "dd" + DB 6+ARITH,0C1H + DM "ddp" + DB NEEDOP+STACKOP,0 + DM "bs" + DB 1,0E1H + +NDPB: + DB 2 + DM "ld" + DB 7+NEEDOP+MEMORY,20H + DM "stp" + DB 7+NEEDOP+MEMORY,30H + +NDPC: + DB 5 + DM "om" + DB 0+ONEREG+REAL,0D1H + DM "omp" + DB 0+ONEREG+REAL,0D9H + DM "hs" + DB 1,0E0H + DM "ompp" + DB 6,0D9H + DM "lex" + DB 3,0E2H + +NDPD: + DB 6 + DM "iv" + DB 6+ARITH,0F1H + DM "ivp" + DB NEEDOP+STACKOP,30H + DM "ivr" + DB 6+ARITH,0F9H + DM "ivrp" + DB NEEDOP+STACKOP,38H + DM "ecstp" + DB 1,0F6H + DM "isi" + DB 3,0E1H + +NDPE: + DB 1 + DM "ni" + DB 3,0E0H + +NDPF: + DB 1 + DM "ree" + DB 5+NEEDOP+ONEREG,0 + +NDPI: + DB 13 + DM "add" + DB 2+NEEDOP+INTEGER,0 + DM "ld" + DB 3+NEEDOP+INTEGER+EXTENDED,0 + DM "sub" + DB 2+NEEDOP+INTEGER,20H + DM "stp" + DB 3+NEEDOP+INTEGER+EXTENDED,18H + DM "st" + DB 3+NEEDOP+INTEGER,10H + DM "mul" + DB 2+NEEDOP+INTEGER,8 + DM "div" + DB 2+NEEDOP+INTEGER,30H + DM "subr" + DB 2+NEEDOP+INTEGER,28H + DM "divr" + DB 2+NEEDOP+INTEGER,38H + DM "com" + DB 2+NEEDOP+INTEGER,10H + DM "comp" + DB 2+NEEDOP+INTEGER,18H + DM "ncstp" + DB 1,0F7H + DM "nit" + DB 3,0E3H + +NDPL: + DB 10 + DM "d" + DB 1+NEEDOP+ONEREG+REAL+EXTENDED,0 + DM "dz" + DB 1,0EEH + DM "d1" + DB 1,0E8H + DM "dpi" + DB 1,0EBH + DM "dl2t" + DB 1,0E9H + DM "dl2e" + DB 1,0EAH + DM "dlg2" + DB 1,0ECH + DM "dln2" + DB 1,0EDH + DM "dcw" + DB 1+NEEDOP+MEMORY,28H + DM "denv" + DB 1+NEEDOP+MEMORY,20H + +NDPM: + DB 2 + DM "ul" + DB 6+ARITH,0C9H + DM "ulp" + DB NEEDOP+STACKOP,8 + +NDPO: + DB 1 + DM "p" + DB NEEDOP+1,0 ;Flag special handling + +NDPN: + DB 1 + DM "op" + DB 1,0D0H + +NDPP: + DB 3 + DM "rem" + DB 1,0F8H + DM "tan" + DB 1,0F2H + DM "atan" + DB 1,0F3H + +NDPR: + DB 2 + DM "ndint" + DB 1,0FCH + DM "stor" + DB 5+NEEDOP+MEMORY,20H + +NDPS: + DB 12 + DM "t" + DB 5+NEEDOP+ONEREG+REAL,0D0H + DM "tp" + DB 7+NEEDOP+ONEREG+REAL+EXTENDED,0D8H + DM "ub" + DB 6+ARITH,0E1H + DM "ubp" + DB NEEDOP+STACKOP,0E0H + DM "ubr" + DB 6+ARITH,0E9H + DM "ubrp" + DB NEEDOP+STACKOP,0E8H + DM "qrt" + DB 1,0FAH + DM "cale" + DB 1,0FDH + DM "ave" + DB 5+NEEDOP+MEMORY,30H + DM "tcw" + DB 1+NEEDOP+MEMORY,38H + DM "tenv" + DB 1+NEEDOP+MEMORY,30H + DM "tsw" + DB 5+NEEDOP+MEMORY,38H + +NDPT: + DB 1 + DM "st" + DB 1,0E4H + +NDPW: + DB 1 + DM "ait" + DB NEEDOP,0 ;Flag special handling + +NDPX: + DB 3 + DM "ch" + DB 1+ONEREG,0C9H + DM "am" + DB 1,0E5H + DM "tract" + DB 1,0F4H + +NDPY: + DB 2 + DM "l2x" + DB 1,0F1H + DM "l2xp1" + DB 1,0F9H + + +OPTAB: +; Table of pointers to mnemonics. For each letter of the alphabet (the +; starting letter of the mnemonic), there are 5 entries. Each entry +; corresponds to a mnemonic whose length is 2, 3, 4, 5, and 6 characters +; long, respectively. If there are no mnemonics for a given combination +; of first letter and length (such as A-2), then the corresponding entry +; points to NONE. Otherwise, it points to a place in the mnemonic table +; for that type. + +; This table only needs to be modified if a mnemonic is added to a group +; previously marked NONE. Change the NONE to a label made up of the first +; letter of the mnemonic and its length, then add a new subsection to +; the mnemonic table in alphabetical order. + + DW NONE + DW A3 + DW NONE + DW A5 + DW NONE + DW NONE ;B + DW NONE + DW NONE + DW NONE + DW NONE + DW NONE ;C + DW C3 + DW C4 + DW C5 + DW NONE + DW D2 ;D + DW D3 + DW D4 + DW NONE + DW NONE + DW E2 ;E + DW E3 + DW NONE + DW E5 + DW NONE + DW NONE ;F + DW NONE + DW NONE + DW NONE + DW NONE + DW NONE ;G + DW NONE + DW NONE + DW NONE + DW NONE + DW NONE ;H + DW H3 + DW H4 + DW NONE + DW NONE + DW I2 ;I + DW I3 + DW I4 + DW NONE + DW NONE + DW J2 ;J + DW J3 + DW J4 + DW NONE + DW NONE + DW NONE ;K + DW NONE + DW NONE + DW NONE + DW NONE + DW NONE ;L + DW L3 + DW L4 + DW L5 + DW L6 + DW NONE ;M + DW M3 + DW M4 + DW M5 + DW NONE + DW NONE ;N + DW N3 + DW NONE + DW NONE + DW NONE + DW O2 ;O + DW O3 + DW O4 + DW NONE + DW NONE + DW NONE ;P + DW P3 + DW P4 + DW P5 + DW NONE + DW NONE ;Q + DW NONE + DW NONE + DW NONE + DW NONE + DW NONE ;R + DW R3 + DW R4 + DW R5 + DW NONE + DW NONE ;S + DW S3 + DW S4 + DW S5 + DW NONE + DW NONE ;T + DW NONE + DW T4 + DW NONE + DW NONE + DW U2 ;U + DW NONE + DW NONE + DW NONE + DW NONE + DW NONE ;V + DW NONE + DW NONE + DW NONE + DW NONE + DW NONE ;W + DW NONE + DW W4 + DW NONE + DW NONE + DW NONE ;X + DW X3 + DW X4 + DW NONE + DW NONE + DW NONE ;Y + DW NONE + DW NONE + DW NONE + DW NONE + DW NONE ;Z + DW NONE + DW NONE + DW NONE + DW NONE + +NDPTAB: +;Lookup table for 8087 mnemonics. There is one entry for each letter of the +;alphabet + DW NDPA + DW NDPB + DW NDPC + DW NDPD + DW NDPE + DW NDPF + DW NONE ;G + DW NONE ;H + DW NDPI + DW NONE ;J + DW NONE ;K + DW NDPL + DW NDPM + DW NDPN + DW NDPO + DW NDPP + DW NONE ;Q + DW NDPR + DW NDPS + DW NDPT + DW NONE ;U + DW NONE ;V + DW NDPW + DW NDPX + DW NDPY + DW NONE ;Z + +;Error message table + +ERRTAB: + DM 1,"Register not allowed in immediate value" + DM 2,"Index or base register must be BP, BX, SI, or DI" + DM 3,"Only one base register (BX, BP) allowed" + DM 4,"Only one index register (SI or DI) allowed" + DM 5,"Only addition allowed on register or undefined label" + DM 6,"Only one undefined label per expression allowed" + DM 7,"Illegal digit in hexadecimal number" + DM 8,"Illegal digit in decimal number" + DM 10,"Illegal character in label or opcode" + DM 11,"Label defined twice" + DM 12,"Opcode not recognized" + DM 20,"Invalid operand" + DM 21,'"," and second operand expected' + DM 22,"Register mismatch" + DM 23,"Immediate operand not allowed" + DM 24,'"]" expected' + DM 25,"Two memory operands not allowed" + DM 26,"Destination must not be immediate value" + DM 27,"Both operands must not be registers" + DM 28,"Operand must be segment register" + DM 29,"First operand must be register" + DM 30,"Undefined label not allowed" + DM 31,"Value out of range" + DM 32,"Missing or illegal operand size flag" + DM 33,"Must have label on same line" + DM 35,"Zero-length string illegal" + DM 36,"ENDIF without IF" + DM 37,"One-character strings only" + DM 38,"Illegal expression" + DM 39,"End of string not found" + DM 100,"Undefined label" + DM 101,"Value out of range (forward)" + DB 255 + +ERRMES: DM '***** ERROR: ' +NOSPAC: DB 13,10,'File creation error',13,10,"$" +NOMEM: DB 13,10,'Insufficient memory',13,10,'$' +NOFILE: DB 13,10,'File not found',13,10,'$' +WRTERR: DB 13,10,'Disk full',13,10,'$' +BADDSK: DB 13,10,'Bad disk specifier',13,10,'$' +ERCNTM: DM 13,10,13,10,'Error Count =' +SYMSIZE DM 13,10,'Symbol Table size = ' +FRESIZE DM 'Free space = ' +SYMMES: DM 13,10,'Symbol Table',13,10,13,10 +EXTEND: DB 'ASM',0,0 +IFEND: DB 5,'endif' +IFNEST: DB 2,'if' +RETSTR: DM 'ret' +HEXFCB: DB 0,' HEX',0,0,0,0 + DS 16 + DB 0,0,0,0,0 +LSTFCB: DB 0,' PRN',0,0,0,0 + DS 16 + DB 0,0,0,0,0 +PC: DS 2 +OLDPC: DS 2 +LABPT: DS 2 +FLAG: DS 1 +MAXFLG: DS 1 +ADDR: DS 2 +ALABEL: DS 2 +DATA: DS 2 +DLABEL: DS 2 +CON: DS 2 +UNDEF: DS 2 +LENID: DS 1 +ID: DS 80 +CHR: DS 1 +SYM: DS 1 +BASE: DS 2 +HEAP: DS 2 +SYMFLG: DS 1 +SYMLIN: DS 1 +CODE: DS 2 +DATSIZ: DS 1 +RELOC: DS 1 +BCOUNT: DS 1 +COUNT: DS 1 +ERR: DS 1 +LINE: DS 2 +HEXLEN: DS 2 +HEXADD: DS 2 +LASTAD: DS 2 +HEXCNT: DS 1 +CHKSUM: DS 1 +LINFLG: DS 1 +PREV: DS 1 +IFFLG: DS 1 +CHKLAB: DS 1 +ERRCNT: DS 2 +LSTRET: DS 2 +RETPT: DS 2 +LSTDEV: DS 2 +SPC: DS 1 +NOWAIT: DS 1 +IX: DS 2 +IY: DS 2 +HEXPNT: DS 2 +LSTPNT: DS 2 +HEXBUF: DS HEXBUFSIZ +LSTBUF: DS LSTBUFSIZ +BUFPT: DS 2 +SRCBUF: DS BUFSIZ + DS 100H + ALIGN +STACK: EQU $ +START: EQU $ + \ No newline at end of file diff --git a/v1.25/source/COMMAND.ASM b/v1.25/source/COMMAND.ASM new file mode 100644 index 0000000..830bf73 --- /dev/null +++ b/v1.25/source/COMMAND.ASM @@ -0,0 +1,2166 @@ +; COMMAND version 1.17 +; +; This version of COMMAND is divided into three distinct parts. First +; is the resident portion, which includes handlers for interrupts +; 22H (terminate), 23H (Cntrl-C), 24H (fatal error), and 27H (stay +; resident); it also has code to test and, if necessary, reload the +; transient portion. Following the resident is the init code, which is +; overwritten after use. Then comes the transient portion, which +; includes all command processing (whether internal or external). +; The transient portion loads at the end of physical memory, and it may +; be overlayed by programs that need as much memory as possible. When +; the resident portion of command regains control from a user program, +; a checksum is performed on the transient portion to see if it must be +; reloaded. Thus programs which do not need maximum memory will save +; the time required to reload COMMAND when they terminate. + +;Use the following booleans to set assembly flags +FALSE EQU 0 +TRUE EQU NOT FALSE + +IBMVER EQU FALSE ;Switch to build IBM version of Command +MSVER EQU TRUE ;Switch to build MS-DOS version of Command + +HIGHMEM EQU TRUE ;Run resident part above transient (high memory) + +LINPERPAG EQU 23 +NORMPERLIN EQU 1 +WIDEPERLIN EQU 5 + + IF IBMVER +SYM EQU ">" +COMDRV EQU 1 + ENDIF + + IF MSVER +SYM EQU ":" +COMDRV EQU 0 + ENDIF + +FCB EQU 5CH +DSKRESET EQU 13 +SETBASE EQU 38 +SRCHFRST EQU 17 +SRCHNXT EQU 18 +RENAM EQU 23 +INCHAR EQU 1 +GETFAT EQU 27 +OPEN EQU 15 +CLOSE EQU 16 +MAKE EQU 22 +DELETE EQU 19 +RDBLK EQU 39 +WRBLK EQU 40 +SETDMA EQU 26 +SELDRV EQU 14 +GETDRV EQU 25 +PRINTBUF EQU 9 +OUTCH EQU 2 +INBUF EQU 10 +GETDATE EQU 2AH +SETDATE EQU 2BH +GETTIME EQU 2CH +SETTIME EQU 2DH +RR EQU 33 +RECLEN EQU 14 +FILLEN EQU 16 +OFFDATE EQU 20 + + +;The following are all of the segments used in the load order + +CODERES SEGMENT +CODERES ENDS + +DATARES SEGMENT BYTE +DATARES ENDS + +INIT SEGMENT BYTE +INIT ENDS + +TAIL SEGMENT PARA +TAIL ENDS + +TRANCODE SEGMENT PARA +TRANCODE ENDS + +TRANDATA SEGMENT BYTE +TRANDATA ENDS + +TRANSPACE SEGMENT BYTE +TRANSPACE ENDS + +RESGROUP GROUP CODERES,DATARES,INIT,TAIL +TRANGROUP GROUP TRANCODE,TRANDATA,TRANSPACE + +;Data for resident portion + +DATARES SEGMENT BYTE + ORG 0 +ZERO = $ +MESBAS DW OFFSET RESGROUP:ERR0 + DW OFFSET RESGROUP:ERR2 + DW OFFSET RESGROUP:ERR4 + DW OFFSET RESGROUP:ERR6 + DW OFFSET RESGROUP:ERR8 + DW OFFSET RESGROUP:ERR10 + DW OFFSET RESGROUP:ERR12 +ERR0 DB "Write protect$" +ERR2 DB "Not ready$" +ERR4 DB "Data$" +ERR6 DB "Seek$" +ERR8 DB "Sector not found$" +ERR10 DB "Write fault$" +ERR12 DB "Disk$" +READ DB "read$" +WRITE DB "writ$" +ERRMES DB " error " +IOTYP DB "writing" +DRVNUM DB " drive " +DRVLET DB "A" +NEWLIN DB 13,10,"$" +REQUEST DB "Abort, Retry, Ignore? $" +BADFAT DB 13,10,"File allocation table bad,$" +COMBAD DB 13,10,"Invalid COMMAND.COM" +NEEDCOM DB 13,10,"Insert DOS disk in " + IF IBMVER + DB "drive A" + ELSE + DB "default drive" + ENDIF +PROMPT DB 13,10,"and strike any key when ready",13,10,"$" +NEEDBAT DB 13,10,"Insert disk with batch file$" +ENDBATMES DB 13,10,"Terminate batch job (Y/N)? $" +LOADING DB 0 +BATFCB DB 1,"AUTOEXECBAT" + DB 21 DUP(?) + DW 0 + DW 0 ;Initialize RR field to zero +PARMTAB DW 10 DUP(-1) ;No parameters initially +BATCH DB 1 ;Assume batch mode initially +COMFCB DB COMDRV,"COMMAND COM" + DB 25 DUP(?) +TRANS DW OFFSET TRANGROUP:COMMAND +TRNSEG DW ? +BATBYT DB ? +MEMSIZ DW ? +SUM DW ? +INITADD DB 4 DUP(?) +RESDATASIZE EQU $-ZERO +DATARES ENDS + +;Data for transient portion + +TRANDATA SEGMENT BYTE + ORG 0 +ZERO EQU $ +BADNAM DB "Bad command or file name",13,10,"$" +MISNAM DB "Missing file name$" +RENERR DB "Duplicate file name or " +NOTFND DB "File not found$" +EXEBAD DB "Error in EXE file$" +NOSPACE DB "Insufficient disk space",13,10,"$" +FULDIR DB "File creation error",13,10,"$" +OVERWR DB "File cannot be copied onto itself",13,10,"$" +LOSTERR DB "Content of destination lost before copy",13,10,"$" +COPIED DB " File(s) copied$" +DIRMES DB " File(s)$" +TOOBIG DB "Program too big to fit in memory$" +BADDRV DB "Invalid drive specification$" +PAUSMES DB "Strike a key when ready . . . $" +BADSWT DB "Illegal switch",13,10,"$" +WEEKTAB DB "SunMonTueWedThuFriSat" +BADDAT DB 13,10,"Invalid date$" +CURDAT DB "Current date is $" +NEWDAT DB 13,10,"Enter new date: $" +BADTIM DB 13,10,"Invalid time$" +CURTIM DB "Current time is $" +NEWTIM DB 13,10,"Enter new time: $" +SUREMES DB "Are you sure (Y/N)? $" + +COMTAB DB 4,"DIR",1 + DW OFFSET TRANGROUP:CATALOG + DB 7,"RENAME",1 + DW OFFSET TRANGROUP:RENAME + DB 4,"REN",1 + DW OFFSET TRANGROUP:RENAME + DB 6,"ERASE",1 + DW OFFSET TRANGROUP:ERASE + DB 4,"DEL",1 + DW OFFSET TRANGROUP:ERASE + DB 5,"TYPE",1 + DW OFFSET TRANGROUP:TYPEFIL + DB 4,"REM",1 + DW OFFSET TRANGROUP:COMMAND + DB 5,"COPY",1 + DW OFFSET TRANGROUP:COPY + DB 6,"PAUSE",1 + DW OFFSET TRANGROUP:PAUSE + DB 5,"DATE",0 + DW OFFSET TRANGROUP:DATE + DB 5,"TIME",0 + DW OFFSET TRANGROUP:TIME + DB 0 ;Terminate command table + +COMBUF DB 128,1,13 + +TRANDATASIZE EQU $-ZERO +TRANDATA ENDS + +;Uninitialized transient data +TRANSPACE SEGMENT BYTE + ORG 0 +ZERO = $ + DB 128 DUP(?) +TPA DW 1 DUP(?) +RESSEG DW 1 DUP(?) +CHKDRV DB 1 DUP(?) +FILTYP DB 1 DUP(?) +CURDRV DB 1 DUP(?) +PARM1 DB 1 DUP(?) +PARM2 DB 1 DUP(?) +COMSW DW 1 DUP(?) +ARG1S DW 1 DUP(?) +ARG2S DW 1 DUP(?) +FLAGER DB 1 DUP(?) +CFLAG DB 1 DUP(?) +SPECDRV DB 1 DUP(?) +BYTCNT DW 1 DUP(?) +NXTADD DW 1 DUP(?) +LINCNT DB 1 DUP(?) +LINLEN DB 1 DUP(?) +FILECNT DW 1 DUP(?) +EXEFCB LABEL WORD +IDLEN DB 1 DUP(?) +ID DB 8 DUP(?) +COM DB 3 DUP(?) +DEST DB 37 DUP(?) +DESTNAME DB 11 DUP(?) +DIRBUF DB 37 DUP(?) +BITS DW 1 DUP(?) +FULLSCR DW 1 DUP(?) +EXEEND DW 1 DUP(?) +;Header variables for EXE file load +;These are overlapped with COPY variables, below +RUNVAR LABEL WORD +RELPT DW 1 DUP(?) +RELSEG DW 1 DUP(?) +PSIZE LABEL WORD +PAGES DW 1 DUP(?) +RELCNT DW 1 DUP(?) +HEADSIZ DW 1 DUP(?) + DW 1 DUP(?) +LOADLOW DW 1 DUP(?) +INITSS DW 1 DUP(?) +INITSP DW 1 DUP(?) + DW 1 DUP(?) +INITIP DW 1 DUP(?) +INITCS DW 1 DUP(?) +RELTAB DW 1 DUP(?) +RUNVARSIZ EQU $-RUNVAR + + DB 80H DUP(?) +STACK LABEL WORD + +PRETRLEN EQU $-ZERO ;Used later to compute TRNLEN + + ORG RUNVAR-ZERO ;Overlaps EXE variables + +SRCPT DW 1 DUP(?) +INEXACT DB 1 DUP(?) +APPEND DB 1 DUP(?) +NOWRITE DB 1 DUP(?) +ASCII DB 1 DUP(?) +PLUS DB 1 DUP(?) +SOURCE DB 11 DUP(?) +TRANSPACESIZE EQU $-ZERO +TRANSPACE ENDS + + +;START OF RESIDENT PORTION + +CODERES SEGMENT +ASSUME CS:RESGROUP,DS:RESGROUP,ES:RESGROUP,SS:RESGROUP + ORG 0 +ZERO = $ +PARMBUF LABEL WORD + + ORG 100H + +RSTACK LABEL WORD + +PROGSTART: + JMP CONPROC + +LTPA DW 0 ;WILL STORE TPA SEGMENT HERE +MYSEG DW 0 ;Put our own segment here + +CONTC: + MOV AX,CS + MOV DS,AX + MOV SS,AX + MOV SP,OFFSET RESGROUP:RSTACK + STI + CALL SETVECT + MOV AH,DSKRESET + INT 33 ;Reset disks in case files were open + TEST [BATCH],-1 + JZ LODCOM +ASKEND: + MOV DX,OFFSET RESGROUP:ENDBATMES + MOV AH,PRINTBUF + INT 33 + MOV AX,0C00H+INCHAR + INT 33 + AND AL,5FH + CMP AL,"N" + JZ LODCOM + CMP AL,"Y" + JNZ ASKEND + MOV [BATCH],0 +LODCOM: + MOV AX,CS + MOV SS,AX + MOV SP,OFFSET RESGROUP:RSTACK + MOV DS,AX + CALL SETVECT + CALL CHKSUM + CMP DX,[SUM] + JZ HAVCOM + MOV [LOADING],1 + CALL LOADCOM +CHKSAME: + CALL CHKSUM + CMP DX,[SUM] + JZ HAVCOM + CALL WRONGCOM + JMP SHORT CHKSAME +HAVCOM: + MOV [LOADING],0 + MOV SI,OFFSET RESGROUP:LTPA + MOV DI,OFFSET TRANGROUP:TPA + MOV ES,[TRNSEG] + CLD + MOVSW ;Move TPA segment to transient storage + MOVSW ;Move resident segment too + MOV AX,[MEMSIZ] + MOV WORD PTR ES:[2],AX + JMP DWORD PTR [TRANS] + +RESIDENT: + ADD DX,15 + MOV CL,4 + SHR DX,CL ;Number of paragraphs of new addition + ADD CS:[LTPA],DX + XOR AX,AX + MOV DS,AX + JMP DWORD PTR DS:[80H] ;Pretend user executed INT 20H + +DSKERR: + ;****************************************************** + ; THIS IS THE DEFAULT DISK ERROR HANDLING CODE + ; AVAILABLE TO ALL USERS IF THEY DO NOT TRY TO + ; INTERCEPT INTERRUPT 24H. + ;****************************************************** + STI + PUSH DS + PUSH CS + POP DS ;Set up local data segment + PUSH DX + CALL CRLF + POP DX + ADD AL,"A" ;Compute drive letter + MOV [DRVLET],AL + TEST AH,80H ;Check if hard disk error + JNZ FATERR + MOV SI,OFFSET RESGROUP:READ + TEST AH,1 + JZ SAVMES + MOV SI,OFFSET RESGROUP:WRITE +SAVMES: + LODSW + MOV WORD PTR [IOTYP],AX + LODSW + MOV WORD PTR [IOTYP+2],AX + AND DI,0FFH + CMP DI,12 + JBE HAVCOD + MOV DI,12 +HAVCOD: + MOV DI,WORD PTR [DI+MESBAS] ;Get pointer to error message + XCHG DI,DX ;May need DX later + MOV AH,PRINTBUF + INT 33 ;Print error type + MOV DX,OFFSET RESGROUP:ERRMES + INT 33 + CMP [LOADING],0 + JNZ GETCOMDSK +ASK: + MOV DX,OFFSET RESGROUP:REQUEST + MOV AH,PRINTBUF + INT 33 + MOV AX,0C00H+INCHAR + INT 33 ;Get response + CALL CRLF + OR AL,20H ;Convert to lower case + MOV AH,0 ;Return code for ignore + CMP AL,"i" ;Ignore? + JZ EXIT + INC AH + CMP AL,"r" ;Retry? + JZ EXIT + INC AH + CMP AL,"a" ;Abort? + JNZ ASK +EXIT: + MOV AL,AH + MOV DX,DI + POP DS + IRET + +FATERR: + MOV DX,OFFSET RESGROUP:BADFAT + MOV AH,PRINTBUF + INT 33 + MOV DX,OFFSET RESGROUP:DRVNUM + INT 33 + MOV AL,2 ;Abort + POP DS + IRET + +GETCOMDSK: + MOV DX,OFFSET RESGROUP:NEEDCOM + MOV AH,PRINTBUF + INT 33 + MOV AX,0C07H ;Get char without testing or echo + INT 33 + JMP LODCOM + +CRLF: + MOV DX,OFFSET RESGROUP:NEWLIN + PUSH AX + MOV AH,PRINTBUF + INT 33 + POP AX +RET10: RET + +LOADCOM: + PUSH DS + MOV DS,[TRNSEG] + MOV DX,100H + MOV AH,SETDMA + INT 33 + POP DS + MOV DX,OFFSET RESGROUP:COMFCB + MOV AH,OPEN + INT 33 ;Open COMMAND.COM + OR AL,AL + JZ READCOM + MOV DX,OFFSET RESGROUP:NEEDCOM +PROMPTCOM: + MOV AH,PRINTBUF + INT 33 + MOV AX,0C07H ;Get char without testing or echo + INT 33 + JMP SHORT LOADCOM +READCOM: + MOV WORD PTR[COMFCB+RR],OFFSET RESGROUP:TRANSTART + XOR AX,AX + MOV WORD PTR[COMFCB+RR+2],AX + MOV [COMFCB],AL ;Use default drive + INC AX + MOV WORD PTR[COMFCB+RECLEN],AX + MOV CX,COMLEN + MOV DX,OFFSET RESGROUP:COMFCB + MOV AH,RDBLK + INT 33 + OR AL,AL + JZ RET10 +WRONGCOM: + MOV DX,OFFSET RESGROUP:COMBAD + JMP SHORT PROMPTCOM + +CHKSUM: + CLD + PUSH DS + MOV DS,[TRNSEG] + MOV SI,100H + MOV CX,COMLEN + SHR CX,1 + XOR DX,DX +CHK: + LODSW + ADD DX,AX + LOOP CHK + POP DS + RET + +SETVECT: + MOV DX,OFFSET RESGROUP:LODCOM + MOV AX,2522H ;Set Terminate address + INT 21H + MOV DX,OFFSET RESGROUP:CONTC + MOV AX,2523H ;Set Ctrl-C address + INT 21H + MOV DX,OFFSET RESGROUP:DSKERR + MOV AX,2524H ;Set Hard Disk Error address + INT 33 + MOV DX,OFFSET RESGROUP:RESIDENT + MOV AX,2527H ;Set Terminate and Stay Resident address + INT 33 + RET +RESCODESIZE EQU $-ZERO +CODERES ENDS + +;******************************************************************* +;START OF INIT PORTION +;This code is overlayed the first time the TPA is used. + +INIT SEGMENT BYTE + + ORG 0 +ZERO = $ +CONPROC: + MOV SP,OFFSET RESGROUP:RSTACK + + IF HIGHMEM + MOV AX,WORD PTR DS:[2] + SUB AX,((RESCODESIZE+RESDATASIZE)+15)/16 ;Subtract size of resident + MOV WORD PTR DS:[2],AX + MOV ES,AX + MOV SI,100H + MOV DI,SI + MOV CX,((RESCODESIZE+RESDATASIZE)-100H+1)/2 ;Length of resident in words + REP MOVSW ;Move to end of memory + MOV DS,AX + MOV [LTPA],CS + ENDIF + + IF NOT HIGHMEM + MOV AX,CS + ADD AX,((RESCODESIZE+RESDATASIZE)+15)/16 ;Compute segment of TPA + MOV [LTPA],AX + MOV AX,WORD PTR DS:[2] + ENDIF + + MOV [MYSEG],DS + MOV [MEMSIZ],AX + SUB AX,TRNLEN ;Subtract size of transient + MOV [TRNSEG],AX + CALL SETVECT + CALL LOADCOM + CALL CHKSUM + MOV [SUM],DX + + IF MSVER + IF HIGHMEM + PUSH DS + PUSH CS + POP DS + ENDIF + MOV DX,OFFSET RESGROUP:HEADER + MOV AH,PRINTBUF + INT 33 + IF HIGHMEM + POP DS + ENDIF + ENDIF + + MOV DX,OFFSET RESGROUP:BATFCB + MOV AH,OPEN + INT 33 ;See if AUTOEXEC.BAT exists + MOV WORD PTR[BATFCB+RECLEN],1 ;Set record length to 1 + OR AL,AL ;Zero means file found + JZ DRV0 + MOV [BATCH],0 ;Not found--turn off batch job + MOV AX,OFFSET TRANGROUP:DATINIT + MOV WORD PTR[INITADD],AX + MOV AX,[TRNSEG] + MOV WORD PTR[INITADD+2],AX + CALL DWORD PTR DS:[INITADD] + + IF IBMVER + MOV DX,OFFSET RESGROUP:HEADER + MOV AH,PRINTBUF + INT 33 + ENDIF + +DRV0: + JMP HAVCOM + + + IF MSVER +HEADER DB 13,10,"Command v. 1.17" + IF HIGHMEM + DB "H" + ENDIF + DB 13,10,"$" + ENDIF + + IF IBMVER +HEADER DB 13,10,13,10,"The IBM Personal Computer DOS",13,10 + DB "Version 1.10 (C)Copyright IBM Corp 1981, 1982",13,10,"$" + DB "Licensed Material - Program Property of IBM" + ENDIF + +INITSIZE EQU $-ZERO +INIT ENDS + +;This TAIL segment is used to produce a PARA aligned label in the resident +; group which is the location where the transient segments will be loaded +; initialy. + +TAIL SEGMENT PARA + ORG 0 +TRANSTART LABEL WORD +TAIL ENDS + +;******************************************************************** +;START OF TRANSIENT PORTION +;This code is loaded at the end of memory and may be overwritten by +;memory-intensive user programs. + +TRANCODE SEGMENT PARA +ASSUME CS:TRANGROUP,DS:TRANGROUP,ES:TRANGROUP,SS:TRANGROUP + +WSWITCH EQU 1 ;Wide display during DIR +PSWITCH EQU 2 ;Pause (or Page) mode during DIR +VSWITCH EQU 4 ;Verify during COPY +ASWITCH EQU 8 ;ASCII mode during COPY +BSWITCH EQU 10H ;Binary mode during COPY + + ORG 0 +ZERO = $ + + ORG 100H ;Allow for 100H parameter area + +SETDRV: + MOV AH,SELDRV + INT 21H +COMMAND: + CLD + MOV AX,CS + MOV SS,AX + MOV SP,OFFSET TRANGROUP:STACK + MOV ES,AX + MOV DS,AX + STI + MOV AX,46*100H + MOV DL,0 + INT 33 ;Turn off verify after write + MOV AX,CS ;Get segment we're in + SUB AX,[TPA] ;AX=size ot TPA in paragraphs + MOV DX,16 + MUL DX ;DX:AX=size of TPA in bytes + OR DX,DX ;See if over 64K + JZ SAVSIZ ;OK if not + MOV AX,-1 ;If so, limit to 65535 bytes +SAVSIZ: + MOV [BYTCNT],AX ;Max no. of bytes that can be buffered + CALL CRLF2 +GETCOM: + MOV AH,GETDRV + INT 21H + MOV [CURDRV],AL + ADD AL,"A" + CALL OUT ;Print letter for default drive + MOV AL,SYM + CALL OUT + MOV DS,[RESSEG] ;All batch work must use resident seg. +ASSUME DS:RESGROUP + TEST [BATCH],-1 + JNZ READBAT + PUSH CS + POP DS ;Need local segment to point to buffer +ASSUME DS:TRANGROUP + MOV DX,OFFSET TRANGROUP:COMBUF + MOV AH,INBUF + INT 21H ;Get a command + JMP DOCOM + +;All batch proccessing has DS set to segment of resident portion +ASSUME DS:RESGROUP +NEEDPARM: + CALL GETBATBYT + CMP AL,"%" ;Check for two consecutive % + JZ SAVBATBYT + CMP AL,13 ;Check for end-of-line + JZ SAVBATBYT + SUB AL,"0" + JB RDBAT ;Ignore parameter reference if invalid + CMP AL,9 + JA RDBAT + CBW + MOV SI,AX + SHL SI,1 ;Two bytes per entry + MOV SI,[SI+OFFSET RESGROUP:PARMTAB] ;Get pointer to corresponding parameter + CMP SI,-1 ;Check if parameter exists + JZ RDBAT ;Ignore if it doesn't + MOV AH,OUTCH +RDPARM: + LODSB ;From resident segment + CMP AL,0DH ;Check for end of parameter + JZ RDBAT + STOSB ;To transient segment + MOV DL,AL + INT 33 ;Display paramters too + JMP SHORT RDPARM + +PROMPTBAT: + MOV AH,PRINTBUF + MOV DX,OFFSET RESGROUP:NEEDBAT + INT 33 ;Prompt for batch file + MOV AH,PRINTBUF + MOV DX,OFFSET RESGROUP:PROMPT + INT 33 + MOV AX,0C00H+INCHAR + INT 33 + JMP COMMAND + +BADCOMJ1:JMP BADCOM + +READBAT: + MOV DX,OFFSET RESGROUP:BATFCB + MOV AH,OPEN + INT 33 ;Make sure batch file still exists + OR AL,AL + JNZ PROMPTBAT ;If OPEN fails, prompt for disk + MOV WORD PTR [BATFCB+RECLEN],1 + MOV DX,OFFSET RESGROUP:BATBYT + MOV AH,SETDMA + INT 33 + MOV DI,OFFSET TRANGROUP:COMBUF+2 +RDBAT: + CALL GETBATBYT + CMP AL,"%" ;Check for parameter + JZ NEEDPARM +SAVBATBYT: + STOSB + CALL OUT ;Display batched command line + CMP AL,0DH + JNZ RDBAT + SUB DI,OFFSET TRANGROUP:COMBUF+3 + MOV AX,DI + MOV ES:[COMBUF+1],AL ;Set length of line + CALL GETBATBYT ;Eat linefeed + PUSH CS + POP DS ;Go back to local segment +ASSUME DS:TRANGROUP +DOCOM: +;All segments are local for command line processing + MOV AL,10 + CALL OUT + MOV SI,OFFSET TRANGROUP:COMBUF+2 + MOV DI,OFFSET TRANGROUP:IDLEN + MOV AX,2901H ;Make FCB with blank scan-off + INT 21H + CMP AL,1 ;Check for ambiguous command name + JZ BADCOMJ1 ;Ambiguous commands not allowed + CMP AL,-1 + JNZ DRVGD + JMP DRVBAD +DRVGD: + MOV AL,[DI] + MOV [SPECDRV],AL + MOV AL," " + MOV CX,9 + INC DI + REPNE SCASB ;Count no. of letters in command name + MOV AL,9 + SUB AL,CL + MOV [IDLEN],AL + MOV DI,81H + MOV CX,0 + PUSH SI +COMTAIL: + LODSB + STOSB ;Move command tail to 80H + CMP AL,13 + LOOPNZ COMTAIL + NOT CL + MOV BYTE PTR DS:[80H],CL + POP SI +;If the command has 0 parameters must check here for +;any switches that might be present. +;SI -> first character after the command. + MOV [FLAGER],0 ;Set error flag before any calls to switch + CALL SWITCH ;Is the next character a "/" + MOV [COMSW],AX + MOV DI,FCB + MOV AX,2901H + INT 21H + MOV [PARM1],AL ;Save result of parse + CALL SWITCH + MOV [ARG1S],AX + MOV DI,FCB+10H + MOV AX,2901H + INT 21H ;Parse file name + MOV [PARM2],AL ;Save result + CALL SWITCH + MOV [ARG2S],AX + MOV AL,[IDLEN] + MOV DL,[SPECDRV] + OR DL,DL ;Check if drive was specified + JZ OK + JMP DRVCHK +OK: DEC AL ;Check for null command + JNZ FNDCOM + JMP GETCOM + +RETSW: + XCHG AX,BX ;Put switches in AX + RET + +SWITCH: + XOR BX,BX ;Initialize - no switches set +SWLOOP: + CALL SCANOFF ;Skip any delimiters + CMP AL,"/" ;Is it a switch specifier? + JNZ RETSW ;No -- we're finished + INC SI ;Skip over "/" + CALL SCANOFF + INC SI +;Convert lower case input to upper case + CMP AL,"a" + JB SAVCHR + CMP AL,"z" + JA SAVCHR + SUB AL,20H ;Lower-case changed to upper-case +SAVCHR: + MOV DI,OFFSET TRANGROUP:SWLIST + MOV CX,SWCOUNT + REPNE SCASB ;Look for matching switch + JNZ BADSW + MOV AX,1 + SHL AX,CL ;Set a bit for the switch + OR BX,AX + JMP SHORT SWLOOP + +BADSW: + MOV [FLAGER],1 ;Record error in switch + JMP SHORT SWLOOP + +SWLIST DB "BAVPW" +SWCOUNT EQU $-SWLIST + +DRVBAD: + MOV DX,OFFSET TRANGROUP:BADDRV + JMP ERROR + +FNDCOM: + MOV SI,OFFSET TRANGROUP:COMTAB ;Prepare to search command table + MOV CH,0 +FINDCOM: + MOV DI,OFFSET TRANGROUP:IDLEN + MOV CL,[SI] + JCXZ EXTERNAL + REPE CMPSB + LAHF + ADD SI,CX ;Bump to next position without affecting flags + SAHF + LODSB ;Get flag for drive check + MOV [CHKDRV],AL + LODSW ;Get address of command + JNZ FINDCOM + MOV DX,AX + CMP [CHKDRV],0 + JZ NOCHECK + MOV AL,[PARM1] + OR AL,[PARM2] ;Check if either parm. had invalid drive + CMP AL,-1 + JZ DRVBAD +NOCHECK:CALL DX +COMJMP: JMP COMMAND + +BADCOMJ:JMP BADCOM + +SETDRV1: + JMP SETDRV + +DRVCHK: + DEC DL ;Adjust for correct drive number + DEC AL ;Check if anything else is on line + JZ SETDRV1 +EXTERNAL: + MOV AL,[SPECDRV] + MOV [IDLEN],AL + MOV WORD PTR[COM],4F00H+"C" ;"CO" + MOV BYTE PTR[COM+2],"M" + MOV DX,OFFSET TRANGROUP:IDLEN + MOV AH,OPEN + INT 33 ;Check if command to be executed + MOV [FILTYP],AL ;0 for COM files, -1 for EXE files + OR AL,AL + JZ EXECUTE + MOV WORD PTR[COM],5800H+"E" ;"EX" + MOV BYTE PTR[COM+2],"E" + INT 33 ;Check for EXE file + OR AL,AL + JZ EXECUTE + MOV WORD PTR[COM],4100H+"B" ;"BA" + MOV BYTE PTR[COM+2],"T" + INT 33 ;Check if batch file to be executed + OR AL,AL + JNZ BADCOMJ +BATCOM: +;Batch parameters are read with ES set to segment of resident part + MOV ES,[RESSEG] +ASSUME ES:RESGROUP + MOV DI,OFFSET RESGROUP:PARMTAB + MOV AX,-1 + MOV CX,10 + REP STOSW ;Zero parameter pointer table + MOV SI,OFFSET TRANGROUP:COMBUF+2 + MOV DI,OFFSET RESGROUP:PARMBUF + MOV BX,OFFSET RESGROUP:PARMTAB +EACHPARM: + CALL SCANOFF + CMP AL,0DH + JZ HAVPARM + MOV ES:[BX],DI ;Set pointer table to point to actual parameter + INC BX + INC BX +MOVPARM: + LODSB + CALL DELIM + JZ ENDPARM ;Check for end of parameter + STOSB + CMP AL,0DH + JZ HAVPARM + JMP SHORT MOVPARM +ENDPARM: + MOV AL,0DH + STOSB ;End-of-parameter marker + CMP BX,OFFSET RESGROUP:PARMTAB+20 ;Maximum number of parameters? + JB EACHPARM +HAVPARM: + MOV SI,OFFSET TRANGROUP:IDLEN + MOV DI,OFFSET RESGROUP:BATFCB + MOV CX,16 + REP MOVSW ;Move into private batch FCB + XOR AX,AX + PUSH ES + POP DS ;Simply batch FCB setup +ASSUME DS:RESGROUP + MOV WORD PTR[BATFCB+RR],AX + MOV WORD PTR[BATFCB+RR+2],AX ;Zero RR field + INC AX + MOV WORD PTR[BATFCB+RECLEN],AX ;Set record length to 1 byte + MOV [BATCH],AL ;Flag batch job in progress + JMP COMMAND +ASSUME DS:TRANGROUP,ES:TRANGROUP + +EXECUTE: + MOV AX,WORD PTR[IDLEN+16] + OR AX,WORD PTR[IDLEN+18] ;See if zero length + JZ BADCOM ;If so, error + XOR AX,AX + MOV WORD PTR[IDLEN+RR],AX + MOV WORD PTR[IDLEN+RR+2],AX ;Set RR field to zero + INC AX + MOV WORD PTR[IDLEN+RECLEN],AX ;Set record length field to 1 + MOV DX,[TPA] + MOV BX,DX + MOV AH,SETBASE + INT 21H + TEST [FILTYP],-1 ;Check if file is COM or EXE + JZ COMLOAD + JMP EXELOAD +COMLOAD:PUSH DS + MOV DS,DX + MOV DX,100H + MOV AH,SETDMA + INT 21H + POP DS + MOV CX,[BYTCNT] + SUB CX,100H + MOV DX,OFFSET TRANGROUP:IDLEN + MOV AH,RDBLK + INT 21H + DEC AL + MOV DX,OFFSET TRANGROUP:TOOBIG + JNZ ERROR +;Set up exit conditions + MOV CX,[BYTCNT] + MOV DS,BX + MOV ES,BX + CLI + MOV SS,BX + MOV SP,CX + STI + SUB CX,100H ;Allow some stack space + XOR AX,AX + PUSH AX + MOV AX,100H + PUSH BX + PUSH AX + CALL SETUP +XXX PROC FAR + RET +XXX ENDP +BADCOM: + MOV DX,OFFSET TRANGROUP:BADNAM +ERROR: + MOV AH,PRINTBUF + INT 21H + JMP COMMAND + +CHKCNT: + TEST [FILECNT],-1 + JNZ ENDDIR + MOV DX,OFFSET TRANGROUP:NOTFND + JMP ERROR + +ENDDIR: +;Make sure last line ends with CR/LF + MOV AL,[LINLEN] + CMP AL,[LINCNT] ;Will be equal if just had CR/LF + JZ MESSAGE + CALL CRLF2 +MESSAGE: + MOV SI,[FILECNT] + XOR DI,DI + CALL DISP32BITS + MOV DX,OFFSET TRANGROUP:DIRMES + MOV AH,PRINTBUF + INT 21H + RET + +CATALOG: + MOV AL,"?" ;*.* is default file spec. + MOV DI,5DH + MOV CX,11 + REP STOSB + MOV SI,81H + CALL SWITCH + MOV DI,5CH + MOV AX,41*100H+0DH ;Parse with default name and extension + INT 33 + +;Begin by processing any switches that may have been specified. +;BITS will contain any information about switches that was +;found when the command line was parsed. + +SETSWT: + MOV AX,[COMSW] ;Get switches from command + OR AX,[ARG1S] ;OR in switches from first parameter + MOV [BITS],AX + MOV BYTE PTR[FULLSCR],LINPERPAG + TEST AL,1 ;Look for /W + MOV AL,NORMPERLIN + JZ DIR + MOV AL,WIDEPERLIN +DIR: + MOV [LINLEN],AL ;Set number of entries per line + MOV [LINCNT],AL + MOV [FILECNT],0 ;Keep track of how many files found + MOV DX,OFFSET TRANGROUP:DIRBUF ;Set Disk transfer address + MOV AH,SETDMA + INT 21H + MOV AH,SRCHFRST +SHOWDIR: + MOV DX,5CH ;DX -> Unopened FCB + INT 21H ;Search for a file to match FCB + INC AL ;FF = file not found + JNZ AGAIN ;Either an error or we are finished + JMP CHKCNT +AGAIN: + INC [FILECNT] ;Keep track of how many we find + MOV SI,OFFSET TRANGROUP:DIRBUF+1 ;SI -> information returned by sys call + CALL SHONAME + TEST BYTE PTR[BITS],1 ;/W set? + JNZ NEXENT ;If so, no size, date, or time + CALL DISPSIZE ;Print size of file + CALL TWOSPC + MOV AX,WORD PTR[DIRBUF+25] ;Get date + OR AX,AX + JZ NEXENT ;Skip if no date + MOV DX,AX + MOV CL,5 + SHR AX,CL ;Align month + AND AL,0FH + MOV BH,"0"-" " ;Enable zero suppression + CALL OUT2 + MOV AL,"-" + CALL OUT + MOV AL,DL + AND AL,1FH ;Mask to day + CALL OUT2 + MOV AL,"-" + CALL OUT + MOV AL,DH + SHR AL,1 ;Align year + ADD AX,80 ;Relative 1980 + CMP AL,100 + JB MILLENIUM + SUB AL,100 +MILLENIUM: + CALL OUT2 + MOV BX,WORD PTR[DIRBUF+23] ;Get time + OR BX,BX ;Time field present? + JZ NEXENT + CALL TWOSPC + SHR BX,1 + SHR BX,1 + SHR BX,1 + SHR BL,1 + SHR BL,1 ;Hours in BH, minutes in BL + MOV AL,BH + MOV DH,"a" ;Assume A.M. + CMP AL,12 ;In the afternoon? + JB MORN + MOV DH,"p" + JE MORN + SUB AL,12 ;Keep it to 12 hours or less +MORN: + OR AL,AL ;Before 1 am? + JNZ SHOHOURS + MOV AL,12 +SHOHOURS: + MOV BH,"0"-" " ;Enable zero suppression + CALL OUT2 + MOV AL,":" + CALL OUT + MOV AL,BL ;Output minutes + CALL OUT2 + MOV AL,DH ;Get "a" or "p" + CALL OUT +NEXENT: + DEC [LINCNT] + JNZ SAMLIN +NEXLIN: + MOV AL,[LINLEN] + MOV [LINCNT],AL + CALL CRLF2 + TEST BYTE PTR[BITS],2 ;/P switch present? + JZ SCROLL ;If not, just continue + DEC BYTE PTR[FULLSCR] + JNZ SCROLL + MOV BYTE PTR[FULLSCR],LINPERPAG + MOV AH,PRINTBUF + MOV DX,OFFSET TRANGROUP:PAUSMES + INT 33 + MOV AX,0C08H ;Wait for any character to be typed + INT 21H + CALL CRLF2 +SCROLL: + MOV AH,SRCHNXT + JMP SHOWDIR + +SAMLIN: + MOV AL,9 ;Output a tab + CALL OUT + JMP SHORT SCROLL + +SHONAME: + MOV CX,8 + CALL OUTCNT + CALL ONESPC + MOV CX,3 +OUTCNT: + LODSB + CALL OUT + LOOP OUTCNT + RET + +TWOSPC: + CALL ONESPC +ONESPC: + MOV AL," " + JMP OUT + +CRLF2: + MOV AL,13 + CALL OUT + MOV AL,10 + JMP OUT + +DISPSIZE: + MOV SI,WORD PTR[DIRBUF+29] + MOV DI,WORD PTR[DIRBUF+31] +DISP32BITS: +;Prints the 32-bit number DI:SI on the console in decimal. Uses a total +;of 9 digit positions with leading blanks. + XOR AX,AX + MOV BX,AX + MOV BP,AX + MOV CX,32 +CONVLP: + SHL SI,1 + RCL DI,1 + XCHG AX,BP + CALL CONVWRD + XCHG AX,BP + XCHG AX,BX + CALL CONVWRD + XCHG AX,BX + ADC AL,0 + LOOP CONVLP +; Conversion complete. Print 9-digit number. + MOV CX,1810H ;Allow leading zero blanking for 8 digits + XCHG DX,AX + CALL DIGIT + XCHG AX,BX + CALL OUTWORD + XCHG AX,BP +OUTWORD: + PUSH AX + MOV DL,AH + CALL OUTBYTE + POP DX +OUTBYTE: + MOV DH,DL + SHR DL,1 + SHR DL,1 + SHR DL,1 + SHR DL,1 + CALL DIGIT + MOV DL,DH +DIGIT: + AND DL,0FH + JZ BLANKZER + MOV CL,0 +BLANKZER: + DEC CH + AND CL,CH + OR DL,30H + SUB DL,CL + MOV AH,OUTCH + INT 21H + RET + +CONVWRD: + ADC AL,AL + DAA + XCHG AL,AH + ADC AL,AL + DAA + XCHG AL,AH +RET20: RET + +ERASE: + MOV CX,11 + MOV SI,FCB+1 +AMBSPEC: + LODSB + CMP AL,"?" + JNZ ALLFIL + LOOP AMBSPEC +ALLFIL: + CMP CX,0 + JNZ NOPRMPT +ASKAGN: + MOV DX,OFFSET TRANGROUP:SUREMES ;"Are you sure (Y/N)?" + MOV AH,PRINTBUF + INT 21H + MOV AX,0C00H+INCHAR + INT 21H + AND AL,5FH + CMP AL,"N" + JZ RET20 + CMP AL,"Y" + CALL CRLF2 + JZ NOPRMPT + JMP SHORT ASKAGN +NOPRMPT: + MOV AH,DELETE + MOV BX,OFFSET TRANGROUP:NOTFND + CMP BYTE PTR DS:[FCB+1]," " ;Check if parameter exists + JMP SHORT OPFILE +RENAME: + MOV AH,RENAM + MOV BX,OFFSET TRANGROUP:RENERR + CMP BYTE PTR DS:[FCB+16+1]," " ;Check if parameter exists +OPFILE: + MOV DX,OFFSET TRANGROUP:MISNAM + JZ ERRJ ;Error if missing parameter + MOV DX,FCB + INT 21H + INC AL + JNZ RET20 + MOV DX,BX +ERRJ: JMP ERROR + +TYPEFIL: + MOV DS,[TPA] + XOR DX,DX + MOV AH,SETDMA + INT 21H + PUSH CS + POP DS + MOV DX,FCB + MOV AH,OPEN + INT 21H + OR AL,AL + MOV DX,OFFSET TRANGROUP:NOTFND + JNZ ERRJ + XOR AX,AX + MOV WORD PTR DS:[FCB+RR],AX ;Set RR field + MOV WORD PTR DS:[FCB+RR+2],AX + INC AX + MOV WORD PTR DS:[FCB+RECLEN],AX ;Set record length + MOV ES,[TPA] +TYPELP: + MOV DX,FCB + MOV CX,[BYTCNT] + MOV AH,RDBLK + INT 21H + JCXZ RET30 + XOR SI,SI ;Start at 0 in TPA +OUTLP: + LODS BYTE PTR ES:[SI] ;In TPA segment + CMP AL,1AH + JZ RET30 + MOV AH,OUTCH + MOV DL,AL + INT 21H + LOOP OUTLP + JMP SHORT TYPELP + +RET30: RET ;Need a nearby RET + +COPY: + XOR AX,AX + MOV [PLUS],AL ;Will keep track of "+"s + MOV [FILECNT],AX + MOV SI,81H ;Point to input line + CALL SWITCH ;Skip over switches on command + MOV BP,AX + MOV DI,FCB + CALL PARSNAM ;Scan first source + MOV [PARM1],DL ;Save ambiguous flag + MOV [SRCPT],SI ;Save pointer to command line +;Parse each name to find destination and check for /V switch +SCANNAM: + CALL PARSE + JNZ SCANNAM +GETDEST: + MOV DI,OFFSET TRANGROUP:DEST + MOV BX,BP ;Remeber switches so far + XOR BP,BP ;Must have dest. swtiches alone + CALL PARSNAM + MOV [ARG2S],BP ;Remember switches on destination + JNZ HAVDESTNAM ;File name present? + INC DI ;Point to file name spot + MOV AL,"?" ;Substitute *.* + MOV CX,11 + REP STOSB +HAVDESTNAM: + OR BX,BP ;BX = all switches combined + AND BL,VSWITCH ;Verify requested? + JZ NOVER + MOV AX,46*100H+1 ;Set verify + MOV DL,0 + INT 33 +NOVER: + MOV DI,OFFSET TRANGROUP:DESTNAME + MOV SI,OFFSET TRANGROUP:DEST+1 + MOV BX,FCB+1 + CALL BUILDNAME ;See if we can make it unambiguous + MOV DI,OFFSET TRANGROUP:DESTNAME + MOV AL,"?" + MOV CX,11 + REPNE SCASB ;Scan for "?" to see if ambiguous + MOV AL,1 ;Flag if ambig. + JZ AMBIG + DEC AX ;AL=0 if unambig. +AMBIG: + MOV DL,AL + MOV AH,[PLUS] ;1=found "+" + XOR AL,1 ;0=ambig, 1=unambig destination + AND AL,[PARM1] ;Source ambig. AND dest unambig. + OR AL,AH ;OR found "+" means concatenation + MOV [ASCII],AL ;Concatenation implies ASCII mode + MOV [INEXACT],AL ;ASCII implies inexact copy + SHL AL,1 + OR AL,DL ;Combine multiple and concat flags + MOV [PARM2],AL + MOV AL,BYTE PTR[COMSW] + CALL SETASC ;Check /A,/B on command + MOV AL,BYTE PTR[ARG1S] + CALL SETASC ;Check for ASCII on first filename + MOV BYTE PTR[COMSW],AL ;Save starting switch values + MOV AH,SRCHFRST + CALL SEARCH ;Search for first source name +MULTDEST: + JZ FIRSTSRC ;Find a first source name? + TEST [PARM2],1 ;If multiple, we're done + JNZ ENDCOPY + XOR AX,AX + MOV [NXTADD],AX + MOV [CFLAG],AL ;Flag nothing read yet +NEXTSNG: + MOV DI,FCB + MOV SI,[SRCPT] + CALL PARSESRC ;Parse next file name into FCB + MOV [PARM1],DL ;Remember if it's ambiguous + MOV [SRCPT],SI + JZ SNGCLOS + MOV AH,SRCHFRST + CALL SEARCH ;Search for new file name + JNZ NEXTSNG ;If none, skip it and move to next name +READSNG: + CALL CHECKREAD +SNGLOOP: + CALL SEARCHNEXT ;See if any more of this name + JZ READSNG + JMP SHORT NEXTSNG + +SNGCLOS: + CALL CLOSEFIL +ENDCOPY: + MOV SI,[FILECNT] + XOR DI,DI + CALL DISP32BITS + MOV DX,OFFSET TRANGROUP:COPIED + MOV AH,PRINTBUF + INT 21H + JMP COMMAND ;Stack could be messed up + +FIRSTSRC: + MOV SI,OFFSET TRANGROUP:DIRBUF+1 + MOV DI,OFFSET TRANGROUP:SOURCE + MOV CX,11 + REP MOVSB ;Copy first source name to SOURCE + MOV SI,OFFSET TRANGROUP:DESTNAME + MOV DI,OFFSET TRANGROUP:DEST+1 + MOV BX,OFFSET TRANGROUP:SOURCE + CALL BUILDNAME ;Build destination name + XOR AX,AX + MOV [NXTADD],AX + MOV [CFLAG],AL + MOV [APPEND],AL + MOV [NOWRITE],AL + TEST [PARM2],1 ;Multiple destinations? + JZ NOPRT + MOV SI,OFFSET TRANGROUP:DIRBUF+1 + CALL SHONAME ;If so, show first source + CALL CRLF2 +NOPRT: + CALL COMPNAME ;Source and dest. the same? + JNZ DOREAD ;If not, read source in + TEST [PARM2],2 ;Concatenation? + MOV DX,OFFSET TRANGROUP:OVERWR + JZ COPERRJ ;If not, overwrite error + MOV [APPEND],1 ;Set physical append + MOV AH,OPEN + MOV DX,OFFSET TRANGROUP:DEST + INT 33 ;Open (existing) destination + CMP [ASCII],0 ;ASCII flag set? + JZ BINARYAPP +;ASCII append. Must find logical EOF, then seek there with dest. FCB + MOV [NOWRITE],1 + CALL READIN ;Find EOF + CALL FLSHFIL ;Seek there + MOV [NOWRITE],0 + CALL FLSHFIL ;Truncate file + JMP SHORT SNGLCHK + +SNGLOOPJ:JMP SNGLOOP + +COPERRJ:JMP COPERR + +BINARYAPP: + MOV WORD PTR[DEST+RECLEN],1 ;Set record length to 1 + MOV SI,OFFSET TRANGROUP:DEST+16 ;Point to file size + MOV DI,OFFSET TRANGROUP:DEST+RR + MOVSW + MOVSW ;Seek to end of file + MOV [CFLAG],1 + JMP SHORT SNGLCHK +DOREAD: + CALL READIN +SNGLCHK: + TEST [PARM2],1 ;Single or multiple destinations? + JZ SNGLOOPJ + MOV SI,[SRCPT] +MULTAPP: + CALL PARSE + JZ MULTCLOS + PUSH SI + MOV SI,OFFSET TRANGROUP:DIRBUF+1 + MOV DI,SI + MOV BX,OFFSET TRANGROUP:SOURCE + CALL BUILDNAME + CALL CHECKREAD + POP SI + JMP SHORT MULTAPP +MULTCLOS: + CALL CLOSEFIL + MOV AL,BYTE PTR[COMSW] + MOV [ASCII],AL ;Restore ASCII flag + CALL SEARCHNEXT + JMP MULTDEST + +PARSE: + MOV DI,OFFSET TRANGROUP:DIRBUF +PARSESRC: + CALL SCANOFF + CMP AL,"+" + JNZ RETZF + MOV [PLUS],1 ;Keep track of "+" signs + INC SI ;Skip over it +PARSNAM: + MOV AX,2901H + INT 33 ;Parse file name + CMP AL,-1 ;Illegal? + MOV DX,OFFSET TRANGROUP:BADDRV + JZ COPERRJ + XCHG AX,DX ;Save parse flag in DL + MOV AL,BYTE PTR[DI] ;Get drive number + OR AL,AL ;Is it default? + JNZ PARSW + MOV AL,[CURDRV] ;Substitute actual drive + INC AX + MOV BYTE PTR[DI],AL +PARSW: + PUSH BX + PUSH DI + CALL SWITCH ;Process switches + OR BP,AX ;Combine all switches + CALL SETASC ;Check for /A or /B + POP DI + POP BX + CMP BYTE PTR[DI+1]," " ;Did we even get a file name? + RET + +RETZF: + XOR AX,AX +RET35: RET + +SEARCHNEXT: + MOV AL,[PARM1] ;Is name ambiguous? + DEC AL + JNZ RET35 ;Don't perform search if not + MOV AH,SRCHNXT +SEARCH: + PUSH AX + MOV AH,SETDMA + MOV DX,OFFSET TRANGROUP:DIRBUF + INT 33 ;Put result of search in DIRBUF + POP AX ;Restore search first/next command + MOV DX,FCB + INT 33 ;Do the search + OR AL,AL + RET + +SETASC: +;Given switch vector in AX, +; Set ASCII switch if /A is set +; Clear ASCII switch if /B is set +; Leave ASCII unchanged if neither or both are set +; Also sets INEXACT if ASCII is ever set. AL = ASCII on exit, flags set + AND AL,ASWITCH+BSWITCH + JPE LOADSW ;PE means both or neither are set + AND AL,ASWITCH + MOV [ASCII],AL + OR [INEXACT],AL +LOADSW: + MOV AL,[ASCII] + OR AL,AL + RET + +BUILDNAME: +; [SI] = Ambiguous input file name +; [BX] = Source of replacement characters +; [DI] = Destination +; File name is copied from [SI] to [DI]. If "?"s are encountered, +; they are replaced with the character in the same position at [BX]. + MOV CX,11 +BUILDNAM: + LODSB + CMP AL,"?" + JNZ NOTAMBIG + MOV AL,BYTE PTR[BX] +NOTAMBIG: + STOSB + INC BX + LOOP BUILDNAM + RET + +COMPNAME: + MOV SI,OFFSET TRANGROUP:DEST + MOV DI,OFFSET TRANGROUP:DIRBUF + MOV CX,6 + REPE CMPSW + RET + +CHECKREAD: +;Read file in (with READIN) if not identical to destination + CALL COMPNAME ;See if source and destination the same + JNZ READIN + CMP [APPEND],0 ;If physical append, it's OK + JNZ RET40 + MOV DX,OFFSET TRANGROUP:LOSTERR ;Tell him he's not going to get it + MOV AH,PRINTBUF + INT 33 +RET40: RET + +READIN: +;Open source file and read it in. If memory fills up, flush it out to +;destination and keep reading. If /A switch set, chop file at first ^Z. +; Inputs/Outputs: +; [NXTADD] has current pointer in buffer +; [CFLAG] <>0 if destination has been created + + MOV DX,OFFSET TRANGROUP:DIRBUF + MOV AH,OPEN + INT 21H + OR AL,AL ;Successful open? + JNZ RET40 ;If not, just ignore it + XOR AX,AX + MOV WORD PTR[DIRBUF+RR],AX + MOV WORD PTR[DIRBUF+RR+2],AX + INC AX + MOV WORD PTR[DIRBUF+RECLEN],AX +COPYLP: + MOV DX,[NXTADD] + MOV AH,SETDMA + PUSH DS + MOV DS,[TPA] + INT 33 + POP DS + MOV CX,[BYTCNT] + SUB CX,DX ;Compute available space + MOV DX,OFFSET TRANGROUP:DIRBUF + MOV AH,RDBLK ;Read in source file + INT 21H + JCXZ RET40 + CMP [ASCII],0 + JZ BINREAD + MOV DX,CX + MOV DI,[NXTADD] + MOV AL,1AH + PUSH ES + MOV ES,[TPA] + REPNE SCASB ;Scan for EOF + POP ES + JNZ USEALL + INC CX +USEALL: + SUB DX,CX + MOV CX,DX +BINREAD: + ADD CX,[NXTADD] + MOV [NXTADD],CX + CMP CX,[BYTCNT] ;Is buffer full? + JB RET40 ;If not, we must have found EOF + CALL FLSHFIL + JMP SHORT COPYLP + +CLOSEFIL: + MOV AX,[NXTADD] + MOV BX,AX + OR AL,AH ;See if any data is loaded + OR AL,[CFLAG] ; or file was created + JZ RET50 ;Don't close or count if not created + MOV AL,BYTE PTR[ARG2S] + CALL SETASC ;Check for /B or /A on destination + JZ BINCLOS + CMP BX,[BYTCNT] ;Is memory full? + JNZ PUTZ + CALL FLSHFIL ;Empty it to make room for 1 lousy byte + XOR BX,BX +PUTZ: + PUSH DS + MOV DS,[TPA] + MOV WORD PTR[BX],1AH ;Add End-of-file mark (Ctrl-Z) + POP DS + INC [NXTADD] +BINCLOS: + CALL FLSHFIL + CMP [INEXACT],0 ;Copy not exact? + JNZ NODATE ;If so, don't copy date & time + MOV SI,OFFSET TRANGROUP:DIRBUF+OFFDATE + MOV DI,OFFSET TRANGROUP:DEST+OFFDATE ;Make date & time same as original + MOVSW ;Copy date + MOVSW ;Copy time +NODATE: + MOV DX,OFFSET TRANGROUP:DEST + MOV AH,CLOSE + INT 21H + INC [FILECNT] +RET50: RET + +FLSHFIL: +;Write out any data remaining in memory. +; Inputs: +; [NXTADD] = No. of bytes to write +; [CFLAG] <>0 if file has been created +; Outputs: +; [NXTADD] = 0 + + MOV AL,1 + XCHG [CFLAG],AL + OR AL,AL + JNZ EXISTS + CMP [NOWRITE],0 + JNZ SKPMAK ;Don't actually create if NOWRITE set + MOV DX,OFFSET TRANGROUP:DEST + MOV AH,MAKE + INT 21H + MOV DX,OFFSET TRANGROUP:FULDIR + OR AL,AL + JNZ COPERR +SKPMAK: + XOR AX,AX + MOV WORD PTR[DEST+RR],AX + MOV WORD PTR[DEST+RR+2],AX + INC AX + MOV WORD PTR[DEST+RECLEN],AX +EXISTS: + XOR CX,CX + XCHG CX,[NXTADD] + CMP [NOWRITE],0 ;If NOWRITE set, just seek CX bytes + JNZ SEEKEND + XOR DX,DX + PUSH DS + MOV DS,[TPA] + MOV AH,SETDMA + INT 33 + POP DS + MOV DX,OFFSET TRANGROUP:DEST + MOV AH,WRBLK + INT 21H + OR AL,AL + JZ RET60 + MOV DX,OFFSET TRANGROUP:DEST + MOV AH,CLOSE + INT 21H + MOV AH,DELETE + INT 33 + MOV DX,OFFSET TRANGROUP:NOSPACE +COPERR: + MOV AH,9 + INT 21H + JMP ENDCOPY + +SEEKEND: + ADD WORD PTR[DEST+RR],CX + ADC WORD PTR[DEST+RR+2],0 ;Propagate carry +RET60: RET + +GETBATBYT: +;Get one byte from the batch file and return it in AL. End-of-file +;returns and ends batch mode. DS must be set to resident segment. +;AH, CX, DX destroyed. +ASSUME DS:RESGROUP + MOV DX,OFFSET RESGROUP:BATFCB + MOV AH,RDBLK + MOV CX,1 + INT 33 ;Get one more byte from batch file + JCXZ BATEOF + MOV AL,[BATBYT] + CMP AL,1AH + JNZ RET70 +BATEOF: + MOV AL,0DH ;If end-of-file, then end of line + MOV [BATCH],0 ;And turn off batch mode +RET70: RET +ASSUME DS:TRANGROUP + +SCANOFF: + LODSB + CALL DELIM + JZ SCANOFF + DEC SI ;Point to first non-delimiter + RET + +DELIM: + CMP AL," " + JZ RET80 + CMP AL,"=" + JZ RET80 + CMP AL,"," + JZ RET80 + CMP AL,9 ;Check for TAB character +RET80: RET + +PAUSE: + MOV DX,OFFSET TRANGROUP:PAUSMES + MOV AH,PRINTBUF + INT 33 + MOV AX,0C00H+INCHAR ;Get character with KB buffer flush + INT 33 +RET90: RET + +;Date and time are set during initialization and use +;this routines since they need to do a long return + +DATINIT: + PUSH ES + PUSH DS ;Going to use the previous stack + MOV AX,CS ;Set up the appropriate segment registers + MOV ES,AX + MOV DS,AX + MOV WORD PTR DS:[81H],13 ;Want to prompt for date during initialization + CALL DATE + CALL TIME + POP DS + POP ES +YYY PROC FAR + RET +YYY ENDP + +; DATE - Gets and sets the time + +DATE: + MOV SI,81H ;Accepting argument for date inline + CALL SCANOFF + CMP AL,13 + JZ PRMTDAT + MOV BX,2F00H+"-" ;"/-" + CALL INLINE + JMP COMDAT + +PRMTDAT: + MOV DX,OFFSET TRANGROUP:CURDAT + MOV AH,PRINTBUF + INT 33 ;Print "Current date is " + MOV AH,GETDATE + INT 33 ;Get date in CX:DX + CBW + MOV SI,AX + SHL SI,1 + ADD SI,AX ;SI=AX*3 + ADD SI,OFFSET TRANGROUP:WEEKTAB + MOV BX,CX + MOV CX,3 + CALL OUTCNT + MOV AL," " + CALL OUT + MOV AX,BX + MOV CX,DX + MOV DL,100 + DIV DL + XCHG AL,AH + XCHG AX,DX + MOV BL,"-" + CALL SHOW +GETDAT: + MOV DX,OFFSET TRANGROUP:NEWDAT + MOV BX,2F00H+"-" ;"/-" in BX + CALL GETBUF +COMDAT: JZ RET90 + JC DATERR + LODSB + CMP AL,BL + JZ SEPGD + CMP AL,BH + JNZ DATERR +SEPGD: CALL GETNUM + JC DATERR + MOV CX,1900 + CMP BYTE PTR[SI],13 + JZ BIAS + MOV AL,100 + MUL AH + MOV CX,AX + CALL GETNUM + JC DATERR +BIAS: + MOV AL,AH + MOV AH,0 + ADD CX,AX + LODSB + CMP AL,13 + JNZ DATERR + MOV AH,SETDATE + INT 33 + OR AL,AL + JNZ DATERR + JMP RET90 +DATERR: + MOV DX,OFFSET TRANGROUP:BADDAT + MOV AH,PRINTBUF + INT 33 + JMP GETDAT + +; TIME gets and sets the time + +TIME: + MOV SI,81H ;Accepting argument for time inline + CALL SCANOFF + CMP AL,13 + JZ PRMTTIM + MOV BX,3A00H+":" + CALL INLINE + JMP COMTIM + +PRMTTIM: + MOV DX,OFFSET TRANGROUP:CURTIM + MOV AH,PRINTBUF + INT 33 ;Print "Current time is " + MOV AH,GETTIME + INT 33 ;Get time in CX:DX + MOV BL,":" + CALL SHOW +GETTIM: + XOR CX,CX ;Initialize hours and minutes to zero + MOV DX,OFFSET TRANGROUP:NEWTIM + MOV BX,3A00H+":" + CALL GETBUF +COMTIM: JZ RET100 ;If no time present, don't change it + JC TIMERR + MOV CX,DX + XOR DX,DX + LODSB + CMP AL,13 + JZ SAVTIM + CMP AL,BL + JNZ TIMERR + MOV BL,"." + CALL GETNUM + JC TIMERR + MOV DH,AH ;Position seconds + LODSB + CMP AL,13 + JZ SAVTIM + CMP AL,BL + JNZ TIMERR + CALL GETNUM + JC TIMERR + MOV DL,AH + LODSB + CMP AL,13 + JNZ TIMERR +SAVTIM: + MOV AH,SETTIME + INT 33 + OR AL,AL + JZ RET100 ;Error in time? +TIMERR: + MOV DX,OFFSET TRANGROUP:BADTIM + MOV AH,PRINTBUF + INT 33 ;Print error message + JMP GETTIM ;Try again + +GETBUF: + MOV AH,PRINTBUF + INT 33 ;Print "Enter new date: " + MOV AH,INBUF + MOV DX,OFFSET TRANGROUP:COMBUF + INT 33 ;Get input line + CALL CRLF2 + MOV SI,OFFSET TRANGROUP:COMBUF+2 + CMP BYTE PTR[SI],13 ;Check if new date entered + JZ RET100 +INLINE: + CALL GETNUM ;Get one or two digit number + JC RET100 + MOV DH,AH ;Put in position + LODSB + CMP AL,BL + JZ NEXT + CMP BL,":" ;Is it a date seperator? + JNZ DATESEP + DEC SI + MOV DL,0 +RET100: RET ;Time may have only an hour specified +DATESEP: + CMP AL,BH + STC + JNZ RET100 +NEXT: CALL GETNUM + MOV DL,AH ;Put in position + RET + +GETNUM: + CALL INDIG + JC RET100 + MOV AH,AL ;Save first digit + CALL INDIG ;Another digit? + JC OKRET + AAD ;Convert unpacked BCD to decimal + MOV AH,AL +OKRET: + OR AL,1 +RET110: RET + +INDIG: + MOV AL,BYTE PTR[SI] + SUB AL,"0" + JC RET110 + CMP AL,10 + CMC + JC RET110 + INC SI + RET + +SHOW: + MOV AL,CH + MOV BH,"0"-" " ;Enable leading zero suppression + CALL OUT2 + MOV AL,BL + CALL OUT + MOV AL,CL + CALL OUT2 + MOV AL,BL + CALL OUT + MOV AL,DH + CALL OUT2 + CMP BL,":" ;Are we outputting time? + JNZ SKIPIT + MOV AL,"." + CALL OUT +SKIPIT: MOV AL,DL +OUT2: ;Output binary number as two ASCII digits + AAM ;Convert binary to unpacked BCD + XCHG AL,AH + OR AX,3030H ;Add "0" bias to both digits + CMP AL,"0" ;Is MSD zero? + JNZ NOSUP + SUB AL,BH ;Suppress leading zero if enabled +NOSUP: + MOV BH,0 ;Disable zero suppression + CALL OUT + MOV AL,AH +OUT: +;Print char in AL without affecting registers + XCHG AX,DX + PUSH AX + MOV AH,OUTCH + INT 33 + POP AX + XCHG AX,DX + RET + +EXELOAD: + MOV AX,CS + ADD AX,LOADSEG + MOV [EXEEND],AX ;Store in EXEEND + MOV DX,OFFSET TRANGROUP:RUNVAR ;Read header in here + MOV AH,SETDMA + INT 33 + MOV CX,RUNVARSIZ ;Amount of header info we need + MOV DX,OFFSET TRANGROUP:EXEFCB + MOV AH,RDBLK + INT 33 ;Read in header + OR AL,AL + JNZ BADEXE ;Must not reach EOF + MOV AX,[HEADSIZ] ;Size of header in paragraphs +;Convert header size to 512-byte pages by multiplying by 32 & rounding up + ADD AX,31 ;Round up first + MOV CL,5 + SHR AX,CL ;Multiply by 32 + MOV [EXEFCB+RR],AX ;Position in file of program + MOV WORD PTR[EXEFCB+RECLEN],512 ;Set record size + ADD BX,10H ;First paragraph above parameter area + MOV DX,[PAGES] ;Total size of file in 512-byte pages + SUB DX,AX ;Size of program in pages + MOV [PSIZE],DX + SHL DX,CL ;Convert pages back to paragraphs + MOV AX,DX + ADD DX,BX ;Size + start = minimum memory (paragr.) + MOV CX,[EXEEND] ;Get memory size in paragraphs + CMP DX,CX ;Enough memory? + JA SHRTERR + MOV DX,[INITSP] + ADD DX,15 + SHR DX,1 + SHR DX,1 + SHR DX,1 + SHR DX,1 + ADD DX,[INITSS] + ADD DX,BX ;Adjusted value of SP + CMP DX,CX ;Is it valid? + JA SHRTERR + CMP [LOADLOW],-1 ;Load low or high? + JZ LOAD ;If low, load at segment BX + SUB CX,AX ;Memory size - program size = load addr. + MOV BX,CX +LOAD: + MOV BP,BX ;Save load segment +LOAD1: +LOADSEG EQU (LOAD1-ZERO)/16 + PUSH DS + MOV DS,BX + XOR DX,DX ;Address 0 in segment + MOV AH,SETDMA + INT 33 ;Set load address + POP DS + MOV CX,[PSIZE] ;Number of records to read + MOV DX,OFFSET TRANGROUP:EXEFCB + MOV AH,RDBLK + INT 33 ;Read in up to 64K + SUB [PSIZE],CX ;Decrement count by amount read + JZ HAVEXE ;Did we get it all? + TEST AL,1 ;Check return code if not + JNZ BADEXE ;Must be zero if more to come + ADD BX,1000H-20H ;Bump data segment 64K minus one record + JMP SHORT LOAD1 ;Get next 64K block + +BADEXE: + MOV DX,OFFSET TRANGROUP:EXEBAD + JMP ERROR + +SHRTERR: + MOV DX,OFFSET TRANGROUP:TOOBIG + JMP ERROR + +HAVEXE: + MOV AX,[RELTAB] ;Get position of table + MOV [EXEFCB+RR],AX ;Set in random record field + MOV WORD PTR[EXEFCB+RECLEN],1 ;Set one-byte record + MOV DX,OFFSET TRANGROUP:RELPT ;4-byte buffer for relocation address + MOV AH,SETDMA + INT 33 + CMP [RELCNT],0 + JZ NOREL +RELOC: + MOV AH,RDBLK + MOV DX,OFFSET TRANGROUP:EXEFCB + MOV CX,4 + INT 33 ;Read in one relocation pointer + OR AL,AL ;Check return code + JNZ BADEXE + MOV DI,[RELPT] ;Get offset of relocation pointer + MOV AX,[RELSEG] ;Get segment + ADD AX,BP ;Bias segment with actual load segment + MOV ES,AX + ADD WORD PTR ES:[DI],BP ;Relocate + DEC [RELCNT] ;Count off + JNZ RELOC +;Set up exit conditions +NOREL: + MOV AX,[INITSS] + ADD AX,BP + CLI + MOV SS,AX ;Initialize SS + MOV SP,[INITSP] + STI + ADD [INITCS],BP + MOV AX,[TPA] ;Get pointer to parameter area + MOV CX,[BYTCNT] ;Size of TPA segment + MOV ES,AX + MOV DS,AX ;Set segment registers to point to it + CALL SETUP + JMP DWORD PTR CS:[INITIP] ;Long jump to program + +SETUP: + AND CL,0F0H ;Adjust to even paragraph boundary + MOV AX,WORD PTR DS:[6] ;Get current memory size + SUB AX,CX ;Find out how much we're changing it + MOV WORD PTR DS:[6],CX + MOV CL,4 + SAR AX,CL ;Convert to a segment address + ADD WORD PTR DS:[8],AX ;Adjust long jump to go to same place + MOV DX,80H + MOV AH,SETDMA + INT 33 ;Set default disk transfer address + MOV AX,WORD PTR CS:[PARM1] ;Pass on info about FCBs + XOR CX,CX + MOV DX,CX ;Assume no batch file +ASSUME CS:RESGROUP + TEST CS:[BATCH],-1 ;Batch file in progress? +ASSUME CS:TRANGROUP + JZ RET120 ;If not, all set up + MOV CX,CS:[RESSEG] + MOV DX,OFFSET RESGROUP:BATFCB ;CX:DX points to batch FCB +RET120: RET +TRANCODESIZE EQU $-ZERO +TRANCODE ENDS +COMLEN EQU TRANDATASIZE+TRANCODESIZE-102H ;End of COMMAND load. ZERO Needed to make COMLEN absolute +TRNLEN EQU (PRETRLEN+TRANCODESIZE+TRANDATASIZE+15)/16 ;Length of transient in paragraphs + END PROGSTART + \ No newline at end of file diff --git a/v1.25/source/HEX2BIN.ASM b/v1.25/source/HEX2BIN.ASM new file mode 100644 index 0000000..d7ba742 --- /dev/null +++ b/v1.25/source/HEX2BIN.ASM @@ -0,0 +1,214 @@ +; HEX2BIN version 1.02 +; Converts Intel hex format files to straight binary + +FCB: EQU 5CH +READ: EQU 20 +SETDMA: EQU 26 +OPEN: EQU 15 +CLOSE: EQU 16 +CREATE: EQU 22 +DELETE: EQU 19 +BLKWRT: EQU 40 +GETSEG: EQU 38 +BUFSIZ: EQU 1024 + + ORG 100H + PUT 100H + +HEX2BIN: + MOV DI,FCB+9 + CMP B,[DI]," " + JNZ HAVEXT + MOV SI,HEX + MOVB + MOVW +HAVEXT: +;Get load offset (default is -100H) + MOV CL,4 ;Needed for shifts + MOV [OFFSET],-100H + MOV SI,FCB+11H ;Scan second FCB for offset + LODB + CMP AL," " ;Check if offset present + JZ HAVOFF + MOV B,[SIGN],0 ;Assume positive sign for now + CMP AL,"+" + JZ GETOFF ;Get a positive offset + CMP AL,"-" + JNZ GETOFF1 ;If not + or -, then not signed + MOV B,[SIGN],1 ;Flag as negative offset +GETOFF: + LODB ;Eat sign +GETOFF1: + CALL HEXCHK ;Check for valid hex character + JC HAVOFF ;No offset if not valid + XOR BX,BX ;Intialize offset sum to 0 +CONVOFF: + SHL BX,CL ;Multiply current sum by 16 + OR BL,AL ;Add in current hex digit + LODB ;Get next digit + CALL HEXCHK ;And convert it to binary + JNC CONVOFF ;Loop until all hex digits read + TEST B,[SIGN],-1 ;Check if offset was to be negative + JZ SAVOFF + NEG BX +SAVOFF: + MOV [OFFSET],BX +HAVOFF: + MOV DX,STARTSEG + MOV AX,DS + ADD DX,AX ;Compute load segment + MOV AH,GETSEG + INT 33 + MOV ES,DX + SEG ES + MOV CX,[6] ;Get size of segment + MOV [SEGSIZ],CX + XOR AX,AX + MOV DI,AX + MOV BP,AX + SHR CX + REP + STOW ;Fill entire segment with zeros + MOV AH,OPEN + MOV DX,FCB + INT 21H + OR AL,AL + JNZ NOFIL + MOV B,[FCB+32],0 + MOV [FCB+14],BUFSIZ ;Set record size to buffer size + MOV DX,BUFFER + MOV AH,SETDMA + INT 33 + MOV AH,READ + MOV DX,FCB ;All set up for sequential reads + MOV SI,BUFFER+BUFSIZ ;Flag input buffer as empty +READHEX: + CALL GETCH + CMP AL,":" ;Search for : to start line + JNZ READHEX + CALL GETBYT ;Get byte count + MOV CL,AL + MOV CH,0 + JCXZ DONE + CALL GETBYT ;Get high byte of load address + MOV BH,AL + CALL GETBYT ;Get low byte of load address + MOV BL,AL + ADD BX,[OFFSET] ;Add in offset + MOV DI,BX + CALL GETBYT ;Throw away type byte +READLN: + CMP DI,[SEGSIZ] + JAE ADERR + CALL GETBYT ;Get data byte + STOB + CMP DI,BP ;Check if this is the largest address so far + JBE HAVBIG + MOV BP,DI ;Save new largest +HAVBIG: + LOOP READLN + JP READHEX + +NOFIL: + MOV DX,NOFILE +QUIT: + MOV AH,9 + INT 21H + INT 20H + +ADERR: + MOV DX,ADDR + JMP SHOWERR + +GETCH: + CMP SI,BUFFER+BUFSIZ + JNZ NOREAD + INT 21H + CMP AL,1 + JZ ERROR + MOV SI,BUFFER +NOREAD: + LODB + CMP AL,1AH + JZ DONE + RET + +GETBYT: + CALL HEXDIG + MOV BL,AL + CALL HEXDIG + SHL BL + SHL BL + SHL BL + SHL BL + OR AL,BL + RET + +HEXCHK: + SUB AL,"0" + JC RET + CMP AL,10 + JC CMCRET + SUB AL,"A"-"0"-10 + JC RET + CMP AL,16 +CMCRET: + CMC + RET + +HEXDIG: + CALL GETCH + CALL HEXCHK + JNC RET +ERROR: + MOV DX,ERRMES +SHOWERR: + MOV AH,9 + INT 21H +DONE: + MOV [FCB+9],4F00H+"C" ;"CO" + MOV B,[FCB+11],"M" + MOV DX,FCB + MOV AH,CREATE + INT 21H + OR AL,AL + JNZ NOROOM + XOR AX,AX + MOV [FCB+33],AX + MOV [FCB+35],AX ;Set RR field + INC AX + MOV [FCB+14],AX ;Set record size + XOR DX,DX + PUSH DS + PUSH ES + POP DS ;Get load segment + MOV AH,SETDMA + INT 21H + POP DS + MOV CX,BP + MOV AH,BLKWRT + MOV DX,FCB + INT 21H + MOV AH,CLOSE + INT 21H +EXIT: + INT 20H + +NOROOM: + MOV DX,DIRFUL + JMP QUIT + +HEX: DB "HEX" +ERRMES: DB "Error in HEX file--conversion aborted$" +NOFILE: DB "File not found$" +ADDR: DB "Address out of range--conversion aborted$" +DIRFUL: DB "Disk directory full$" + +OFFSET: DS 2 +SEGSIZ: DS 2 +SIGN: DS 1 +BUFFER: DS BUFSIZ + +START: +STARTSEG EQU (START+15)/16 + \ No newline at end of file diff --git a/v1.25/source/IO.ASM b/v1.25/source/IO.ASM new file mode 100644 index 0000000..3b9f181 --- /dev/null +++ b/v1.25/source/IO.ASM @@ -0,0 +1,1934 @@ +; I/O System for 86-DOS version 1.20 and later. Revised 8-02-82. +; +; Assumes a CPU Support card at F0 hex for character I/O, +; with disk drivers for SCP, Tarbell, or Cromemco controllers. +; +; Select whether console input is interrupt-driven or polled. +INTINP: EQU 1 +; +; Select whether the auxiliary port is the Support Card parallel port +; or on channel 1 of a Multiport Serial card addressed at 10H. +PARALLELAUX: EQU 1 +SERIALAUX: EQU 0 +; +; Select whether the printer is connected to the Support card parallel +; output port (standard) or channel 0 of a Multiport Serial card +; addressed at 10H. +PARALLELPRN: EQU 1 +SERIALPRN: EQU 0 +; +; If the Multiport Serial was chosen for either the auxiliary or the +; printer, select the baud rate here. Refer to Multiport Serial manual +; page 11 to pick the correct value for a given baud rate. +PRNBAUD:EQU 7 ; 1200 baud +AUXBAUD:EQU 0FH ; 19200 baud +; +; Select disk controller here. +SCP: EQU 1 +TARBELLSD: EQU 0 +TARBELLDD: EQU 0 +CROMEMCO4FDC: EQU 0 +CROMEMCO16FDC: EQU 0 +; +; Select if you want a special conversion version which can read/write +; both the new Microsoft format and the old SCP format. +; For a two drive system, drives A and B are the new Microsoft format, +; and drives C and D are the old SCP format (where C is the same physical +; drive as A, and D is the same drive as B). CONVERT has no effect +; on 5.25-inch drives. +CONVERT:EQU 1 +; +; Select disk configuration: +LARGE: EQU 1 ; Large drives. +COMBIN: EQU 0 ; Two 8-inch and one 5.25-inch. +SMALL: EQU 0 ; Three 5.25-inch drives. +CUSTOM: EQU 0 ; User defined. +; +; If 8-inch drives are PerSci, select FASTSEEK here: +; (Fastseek with Tarbell controllers doesn't work yet). +FASTSEEK: EQU 1 +; +; For double-density controllers, select double-sided operation of +; 8-inch disks in double-density mode. +LARGEDS: EQU 0 +; +; For double-density controllers, select double-sided operation of +; 5.25-inch disks in double-density mode. +SMALLDS: EQU 0 +; +; Use table below to select head step speed. Step times for 5" drives +; are double that shown in the table. Times for Fast Seek mode (using +; PerSci drives) is very small - 200-400 microseconds. +; +; Step value 1771 1793 +; +; 0 6ms 3ms +; 1 6ms 6ms +; 2 10ms 10ms +; 3 20ms 15ms +; +STPSPD: EQU 0 +; +; ****** End of selections ******************************************** +; +BIOSSEG:EQU 40H ; I/O system segment. +BIOSLEN:EQU 2048 ; Maximum length of I/O system. +DOSLEN: EQU 8192 ; Maximum length of MS-DOS. +QSIZE: EQU 80 ; Input queue size. +PBUFSIZ:EQU 128 ; Size of print buffer +BASE: EQU 0F0H ; CPU Support card base port number. +SIOBASE:EQU 10H ; Base port number of Multiport Serial card. +STAT: EQU BASE+7 ; Serial I/O status port. +DATA: EQU BASE+6 ; Serial I/O data port. +DAV: EQU 2 ; Data available bit. +TBMT: EQU 1 ; Transmitter buffer empty bit. +SERIAL: EQU SERIALPRN+SERIALAUX +STCDATA:EQU BASE+4 ; Ports for 9513 Timer chip. +STCCOM: EQU BASE+5 + + IF SERIALAUX +AUXSTAT:EQU SIOBASE+3 +AUXDATA:EQU SIOBASE+2 + ENDIF + + IF PARALLELAUX +AUXSTAT:EQU BASE+13 +AUXDATA:EQU BASE+12 + ENDIF + + IF SERIALPRN +PRNSTAT:EQU SIOBASE+1 +PRNDATA:EQU SIOBASE+0 + ENDIF + + IF PARALLELPRN +PRNSTAT:EQU BASE+13 +PRNDATA:EQU BASE+12 + ENDIF + + ORG 0 + PUT 100H + + JMP INIT + JMP STATUS + JMP INP + JMP OUTP + JMP PRINT + JMP AUXIN + JMP AUXOUT + JMP READ + JMP WRITE + JMP DSKCHG + JMP SETDATE + JMP SETTIME + JMP GETTIME + JMP FLUSH + JMP MAPDEV +MAPDEV: + RET L + +INIT: + XOR BP,BP ; Set up stack just below I/O system. + MOV SS,BP + MOV SP,BIOSSEG*16 + + IF INTINP-1 + MOV AL,0FFH ; Mask all interrupts. + OUTB BASE+3 + ENDIF + + IF INTINP + DI ; Set up keyboard interrupt vector. + MOV [BP+64H],KBINT + MOV [BP+66H],CS + EI + ENDIF + + MOV [BP+4*38H],PRNFCB + MOV [BP+4*38H+2],CS + PUSH CS + POP DS +; +; Initialize time-of-day clock. +; + MOV SI,STCTAB + MOV CX,4 ;Initialize 4 registers + UP +INITSTC: + LODB + OUT STCCOM ;Select register to initialize + LODB + OUT STCDATA + LODB + OUT STCDATA + LOOP INITSTC + + IF SERIAL + MOV CX,4 +SERINIT: + LODB + OUT SIOBASE+1 + OUT SIOBASE+3 + LOOP SERINIT + LODB ;Baud rate for channel 0 + OUT SIOBASE+8 + LODB ;Baud rate for channel 1 + OUT SIOBASE+9 + ENDIF +; +; Move MS-DOS down to the first segment just above the I/O system. +; + MOV SI,BIOSLEN ; Source points to where MS-DOS currently is. + MOV AX,DOSSEG ; Destination is beginning of DOSSEG. + MOV ES,AX + SUB DI,DI + MOV CX,DOSLEN/2 ; CX is number of words to move. + REP + MOVSW + + MOV SI,INITTAB + MOV DX,1 ; Do auto memory scan. + CALL 0,DOSSEG +; +; Change disk read and write vectors (INT 37 and INT 38) to go to +; DIRECTREAD and DIRECTWRITE rather than READ and WRITE. +; + SUB BP,BP + MOV W,[BP+37*4],DIRECTREAD + MOV W,[BP+38*4],DIRECTWRITE + + MOV DX,100H + MOV AH,26 ;Set DMA address + INT 33 + MOV CX,[6] ;Get size of segment + MOV BX,DS ;Save segment for later +; +; DS must be set to CS so we can point to the FCB. +; + MOV AX,CS + MOV DS,AX + MOV DX,FCB ;File Control Block for COMMAND.COM + MOV AH,15 + INT 33 ;Open COMMAND.COM + OR AL,AL + JNZ COMERR ;Error if file not found + XOR AX,AX + MOV [FCB+33],AX ; Set 4-byte Random Record field to + MOV [FCB+35],AX ; beginning of file. + INC AX + MOV [FCB+14],AX ;Set record length field + MOV AH,39 ;Block read (CX already set) + INT 33 + JCXZ COMERR ;Error if no records read + TEST AL,1 + JZ COMERR ;Error if not end-of-file +; +; Make all segment registers the same. +; + MOV DS,BX + MOV ES,BX + MOV SS,BX + MOV SP,5CH ;Set stack to standard value + XOR AX,AX + PUSH AX ;Put zero on top of stack for return + MOV DX,80H + MOV AH,26 + INT 33 ;Set default transfer address (DS:0080) + PUSH BX ;Put segment on stack + MOV AX,100H + PUSH AX ;Put address to execute within segment on stack + RET L ;Jump to COMMAND + +COMERR: + MOV DX,BADCOM + MOV AH,9 ;Print string + INT 33 + EI +STALL: JP STALL + +STCTAB: DB 17H ;Select master mode register + DW 84F3H ;Enable time-of-day + DB 1 ;Counter 1 mode register + DW 0138H + DB 2 + DW 0038H + DB 3 + DW 0008H ;Set counter 3 to count days + + IF SERIAL + DB 0B7H, 77H, 4EH, 37H, PRNBAUD, AUXBAUD + ENDIF + +BADCOM: DB 13,10,"Error in loading Command Interpreter",13,10,"$" +FCB: DB 1,"COMMAND COM" + DS 25 +; +; ************ Time and Date ************ +; +GETTIME: + MOV AL,0A7H ;Save counters 1,2,3 + OUT STCCOM + MOV AL,0E0H ;Enable data pointer sequencing + OUT STCCOM + MOV AL,19H ;Select hold 1 / hold cycle + OUT STCCOM + CALL STCTIME ;Get seconds & 1/100's + XCHG AX,DX + CALL STCTIME ;Get hours & minutes + XCHG AX,CX + IN STCDATA + MOV AH,AL + IN STCDATA + XCHG AL,AH ;Count of days + JP POINTSTAT + +STCTIME: + CALL STCBYTE + MOV CL,AH +STCBYTE: + IN STCDATA + MOV AH,AL + SHR AH + SHR AH + SHR AH + SHR AH + AND AL,0FH ;Unpack BCD digits + AAD ;Convert to binary + MOV AH,AL + MOV AL,CL + RET + +SETTIME: + PUSH CX + PUSH DX + CALL LOAD0 ;Put 0 into load registers to condition timer + MOV AL,43H ;Load counters 1 & 2 + OUT STCCOM + POP DX + POP CX + CALL LOAD + MOV AL,43H + OUT STCCOM ;Load counters 1&2 + CALL LOAD0 + MOV AL,27H ;Arm counters 1,2,3 + OUT STCCOM + JP POINTSTAT + +LOAD0: + XOR CX,CX + MOV DX,CX +LOAD: + MOV AL,09 ;Counter 1 load register + CALL OUTDX + MOV AL,0AH ;Counter 2 load register + MOV DX,CX +OUTDX: + OUT STCCOM ;Select a load register + MOV AL,DL + CALL OUTBCD + MOV AL,DH +OUTBCD: + AAM ;Convert binary to unpacked BCD + SHL AH + SHL AH + SHL AH + SHL AH + OR AL,AH ;Packed BCD + OUT STCDATA + RET + +SETDATE: + XCHG AX,DX ;Put date in DX + MOV AL,0BH ;Select Counter 3 load register + OUT STCCOM + XCHG AX,DX + OUT STCDATA + MOV AL,AH + OUT STCDATA + MOV AL,44H ;Load counter 3 + OUT STCCOM +POINTSTAT: + PUSH AX + MOV AL,1FH ;Point to status register + OUT STCCOM ; so power-off glitches won't hurt + POP AX + RET L +; +; ************ CONSOLE INPUT ************ +; + + IF INTINP-1 ; Non-interrupt driven input. +STATUS: + IN STAT + AND AL,DAV + JZ NOTHING ; Jump if nothing there. + PUSHF ; Save Z flag. + INB DATA + AND AL,7FH + SEG CS + MOV [QUEUE],AL ; Put new character in buffer. + POPF ; Return with Z flag clear. + RET L +NOTHING: + SEG CS + MOV AL,[QUEUE] ; See if there's anything in the buffer. + NOT AL ; Set up the Z flag. + TEST AL,80H + PUSHF + NOT AL + POPF + RET L + +INP: + MOV AL,-1 + SEG CS + XCHG AL,[QUEUE] ; Remove the character from the buffer. + AND AL,AL + JNS INRET ; Return if we have a character. +INLOOP: + IN STAT ; Wait till a character is available. + AND AL,DAV + JZ INLOOP + IN DATA + AND AL,7FH +INRET: +FLUSH: + RET L + +QUEUE: DB -1 ; For storing characters from STATUS to INP. + ENDIF + + IF INTINP ; Interrupt-driven input. +; +; Console keyboard interrupt handler. +; +KBINT: + PUSH AX + PUSH SI + MOV AL,20H ;End of Interrupt command + OUT BASE+2 ;Send to slave + IN DATA ;Get the character + AND AL,7FH + CMP AL,"C"-"@" + JZ FLSH + CMP AL,"S"-"@" + JZ FLSH + CMP AL,"F"-"@" + JNZ SAVKY +FLSH: + CALL 13*3,BIOSSEG ; Call I/O system keyboard buffer flush. +SAVKY: + SEG CS + MOV SI,[REAR] ;Pointer to rear of queue + CALL INCQ + SEG CS + CMP SI,[FRONT] ;Any room in queue? + JZ QFULL + SEG CS + MOV [SI],AL ;Put character in queue + SEG CS + MOV [REAR],SI ;Save pointer +LEAVINT: + POP SI + POP AX + IRET +QFULL: + MOV AL,7 ; BELL character. + CALL 3*3,BIOSSEG ; Call I/O system console output function. + JMPS LEAVINT + +STATUS: + PUSH SI +;See if printer ready + IN PRNSTAT + AND AL,TBMT + JZ NOPRN + SEG CS + MOV SI,[PFRONT] + SEG CS + CMP SI,[PREAR] ;Anything in print queue? + JNZ SENDPRN + SEG CS + CMP B,[PRNFCB],-1 ;Print spooling in progress? + JZ NOPRN ;If not, nothing to print +;Print spooling in progress. Get next buffer + PUSH DS + PUSH CS + POP DS + PUSH AX + PUSH CX + PUSH DX + PUSH [STKSAV] + PUSH [STKSAV+2] + PUSH [DMAADD] + PUSH [DMAADD+2] + MOV DX,PQUEUE + MOV AH,26 ;Set DMA address + INT 33 + MOV DX,PRNFCB + MOV CX,PBUFSIZ + MOV AH,39 ;Read buffer + INT 33 + OR AL,AL + JZ NOTEOF + MOV B,[PRNFCB],-1 ;Turn off print spooling at EOF +NOTEOF: + POP [DMAADD+2] + POP [DMAADD] + POP [STKSAV+2] + POP [STKSAV] + MOV SI,CX + POP DX + POP CX + POP AX + POP DS + OR SI,SI + JZ NOPRN + ADD SI,PQUEUE-1 + SEG CS + MOV [PREAR],SI + MOV SI,ENDPQ-1 +SENDPRN: + CALL INCPQ + SEG CS + MOV [PFRONT],SI + SEG CS + LODSB ;Get character to print + OUT PRNDATA +NOPRN: + DI ; Disable interrupts while checking queue. + SEG CS + MOV SI,[FRONT] + SEG CS + CMP SI,[REAR] ; Anything in queue? + JZ NOCHR ; Jump if nothing in queue. + CALL INCQ + SEG CS + LODSB ;Get character (if there is one) + OR SI,SI ;Reset zero flag +NOCHR: + EI + POP SI + RET L ;Zero clear if we have a character + +INP: + CALL STATUS,BIOSSEG ; Get I/O system console input status. + JZ INP + PUSH SI + DI ; Disable interrupts while changing queue pointers. + SEG CS + MOV SI,[FRONT] + CALL INCQ ; Permanently remove char from queue + SEG CS + MOV [FRONT],SI + EI + POP SI + RET L + +FLUSH: + DI + SEG CS + MOV [REAR],QUEUE + SEG CS + MOV [FRONT],QUEUE + EI + RET L + +INCQ: + INC SI + CMP SI,ENDQ ;Exceeded length of queue? + JB RET + MOV SI,QUEUE + RET + +INCPQ: + INC SI + CMP SI,ENDPQ ;Exceeded length of queue? + JB RET + MOV SI,PQUEUE + RET + +FRONT: DW QUEUE +REAR: DW QUEUE +QUEUE: DS QSIZE +ENDQ: EQU $ +PFRONT: DW PQUEUE +PREAR: DW PQUEUE +PQUEUE: DS PBUFSIZ +ENDPQ: EQU $ +PRNFCB: DB -1 + DS 36 + ENDIF + +; +; ************ Console and Printer Output ************ +; +OUTP: + PUSH AX +OUTLP: + IN STAT + AND AL,TBMT + JZ OUTLP + POP AX + OUT DATA + RET L + +PRINT: + PUSH SI + SEG CS + MOV SI,[PREAR] + CALL INCPQ +PRINLP: + SEG CS + CMP SI,[PFRONT] + JNZ PRNCHR +;Print queue is full + PUSH AX + CALL STATUS,BIOSSEG ;Poll and maybe print something + POP AX + JMPS PRINLP +PRNCHR: + SEG CS + MOV [PREAR],SI + SEG CS + MOV [SI],AL + POP SI + RET L +; +; ************ Auxiliary I/O ************ +; +AUXIN: + IN AUXSTAT + AND AL,DAV + JZ AUXIN + IN AUXDATA + RET L + +AUXOUT: + PUSH AX +AUXLP: + IN AUXSTAT + AND AL,TBMT + JZ AUXLP + POP AX + OUT AUXDATA + RET L +; +; ************ 1771/1793-type controller disk I/O ************ +; +TARBELL:EQU TARBELLSD+TARBELLDD +CROMEMCO:EQU CROMEMCO4FDC+CROMEMCO16FDC + +WD1791: EQU SCP+TARBELLDD+CROMEMCO16FDC +WD1771: EQU TARBELLSD+CROMEMCO4FDC + + IF WD1791 +READCOM:EQU 80H +WRITECOM:EQU 0A0H + ENDIF + + IF WD1771 +READCOM:EQU 88H +WRITECOM:EQU 0A8H + ENDIF + + IF SCP +SMALLBIT:EQU 10H +BACKBIT:EQU 04H +DDENBIT:EQU 08H +DONEBIT:EQU 01H +DISK: EQU 0E0H + ENDIF + + IF TARBELL +BACKBIT:EQU 40H +DDENBIT:EQU 08H +DONEBIT:EQU 80H +DISK: EQU 78H + ENDIF + + IF CROMEMCO +SMALLBIT:EQU 10H +BACKBIT:EQU 0FDH ; Send this to port 4 to select back. +DDENBIT:EQU 40H +DONEBIT:EQU 01H +DISK: EQU 30H + ENDIF + + IF SMALLDS-1 +SMALLDDSECT: EQU 8 + ENDIF + + IF SMALLDS +SMALLDDSECT: EQU 16 + ENDIF + + IF LARGEDS-1 +LARGEDDSECT: EQU 8 + ENDIF + + IF LARGEDS +LARGEDDSECT: EQU 16 + ENDIF +; +; Disk change function. +; On entry: +; AL = disk drive number. +; On exit: +; AH = -1 (FF hex) if disk is changed. +; AH = 0 if don't know. +; AH = 1 if not changed. +; +; CF clear if no disk error. +; AL = disk I/O driver number. +; +; CF set if disk error. +; AL = disk error code (see disk read below). +; + IF WD1771 +DSKCHG: + MOV AH,0 ; AH = 0 in case we don't know. + SEG CS + CMP AL,[CURDRV] + JNZ RETL + PUSH AX ; Save drive number. + + IF CROMEMCO + INB DISK+4 + ENDIF + + IF TARBELL + INB DISK + ENDIF + + AND AL,20H ; Look at head load bit + POP AX + JZ RETL + MOV AH,1 ; AH = 1, disk not changed. +RETL: + CLC ; No disk error. + RET L + ENDIF ; End of 1771 DSKCHG. + + IF WD1791 +DSKCHG: + MOV AH,0 ; AH = 0 in case we don't know. + SEG CS + CMP AL,[CURDRV] + JNZ DENSCHK ; Check density if not same drive. + PUSH AX + + IF SCP+CROMEMCO + INB DISK+4 + ENDIF + + IF TARBELL + INB DISK + ENDIF + + AND AL,20H ; Look at head load bit + POP AX + JZ DENSCHK ; Check density if head not loaded. + MOV AH,1 ; AH = 1, disk not changed. + MOV BX,PREVDENS + SEG CS + XLAT ; Get previous density + CLC ; No disk error. + RET L +DENSCHK: + CALL CHKNEW ; Unload head if selecting new drive. + CBW + XCHG AX,SI + ADD SI,PREVDENS + MOV CX,4 ; Try each density twice + MOV AH,0 ; Disk may not have been changed. +CHKDENS: + SEG CS + MOV AL,[SI] ; Get previous disk I/O driver number. + MOV BX,DRVTAB + SEG CS + XLAT ; Get drive select byte for previous density + + IF CROMEMCO16FDC + CALL MOTOR ; Wait for motor to come up to speed. + ENDIF + + OUT DISK+4 ; Select disk + MOV AL,0C4H ; READ ADDRESS command + CALL DCOM + AND AL,98H + IN DISK+3 ; Eat last byte to reset DRQ + JZ HAVDENS ; Jump if no error in reading address. + NOT AH ; AH = -1 (disk changed) if new density works. + SEG CS + XOR B,[SI],1 ; Try other density + LOOP CHKDENS + MOV AX,2 ; Couldn't read disk at all, AH = 0 for don't + STC ; know if disk changed, AL = error code 2 - + RET L ; disk not ready, carry set to indicate error. + +HAVDENS: + SEG CS + LODSB ; AL = disk I/O driver number. + CLC ; No disk error. + RET L + +PREVDENS:DB 1,3,5,7,9,11,13 ; Table of previous disk I/O driver numbers. + ENDIF ; End of 1793 DSKCHG function. + +CHKNEW: + MOV AH,AL ; Save disk drive number in AH. + SEG CS ; AL = previous disk drive number, + XCHG AL,[CURDRV] ; make new drive current. + CMP AL,AH ; Changing drives? + JZ RET +; +; If changing drives, unload head so the head load delay one-shot will +; fire again. Do it by seeking to the same track with the H bit reset. +; + IN DISK+1 ; Get current track number + OUT DISK+3 ; Make it the track to seek to + MOV AL,10H ; Seek and unload head + CALL DCOM + MOV AL,AH ; Restore current drive number + RET + + IF CROMEMCO16FDC +MOTOR: + PUSH AX + MOV AH,AL + IN DISK+4 ; See if the motor is on. + TEST AL,08H + MOV AL,AH + OUTB DISK+4 ; Select drive & start motor. + JNZ MOTORSON ; No delay if motors already on. + PUSH CX + MOV CX,43716 ; Loop count for 1 second. +MOTORDELAY: ; (8 MHz, 16-bit memory). + AAM ; 83 clocks. + AAM ; 83 clocks. + LOOP MOTORDELAY ; 17 clocks. + POP CX +MOTORSON: + POP AX + RET + ENDIF +; +; Disk read function. +; +; On entry: +; AL = Disk I/O driver number +; BX = Disk transfer address in DS +; CX = Number of sectors to transfer +; DX = Logical record number of transfer +; On exit: +; CF clear if transfer complete +; +; CF set if hard disk error. +; CX = number of sectors left to transfer. +; AL = disk error code +; 0 = write protect error +; 2 = not ready error +; 4 = "data" (CRC) error +; 6 = seek error +; 8 = sector not found +; 10 = write fault +; 12 = "disk" (none of the above) error +; +READ: + CALL SEEK ;Position head + JC ERROR + PUSH ES ; Make ES same as DS. + MOV BX,DS + MOV ES,BX +RDLP: + CALL READSECT ;Perform sector read + JC POPESERROR + INC DH ;Next sector number + LOOP RDLP ;Read each sector requested + CLC ; No errors. + POP ES ; Restore ES register. + RET L +; +; Disk write function. +; Registers same on entry and exit as read above. +; +WRITE: + CALL SEEK ;Position head + JC ERROR +WRTLP: + CALL WRITESECT ;Perform sector write + JC ERROR + INC DH ;Bump sector counter + LOOP WRTLP ;Write CX sectors + CLC ; No errors. +WRITERET: + RET L + +POPESERROR: + POP ES ; Restore ES register. +ERROR: + MOV BL,-1 + SEG CS + MOV [DI],BL ; Indicate we don't know where head is. + MOV SI,ERRTAB +GETCOD: + INC BL ; Increment to next error code. + SEG CS + LODB + TEST AH,AL ; See if error code matches disk status. + JZ GETCOD ; Try another if not. + MOV AL,BL ; Now we've got the code. + SHL AL ; Multiply by two. + STC + RET L + +ERRTAB: + DB 40H ;Write protect error + DB 80H ;Not ready error + DB 8 ;CRC error + DB 2 ;Seek error + DB 10H ;Sector not found + DB 20H ;Write fault + DB 7 ;"Disk" error +; +; Direct disk read and write from INT 37 and INT 38. Subroutine GETIODRIVER +; calls DSKCHG to convert disk drive number to I/O driver number. +; +; Setting CURDRV to -1 before calling DSKCHG forces DSKCHG to check the disk's +; density before returning the I/O driver number. This is necessary because +; programs such as FORMAT could change the density of a disk and leave the +; head loaded. If the head is loaded DSKCHG assumes the disk hasn't been +; changed and returns the old I/O driver number which could be wrong. +; +; CURDRV is set to -1 before returning so when DSKCHG is called by the +; operating system, it will tell the operating system the disk may have +; been changed (because it may have been). +; +DIRECTREAD: + + IF WD1791 + CALL GETIODRIVER ; Convert drive number to I/O driver number. + JC DIRECTRET ; Return if DSKCHG returned error. + ENDIF + + CALL 7*3,BIOSSEG ; Call READ. + JMPS DIRECTRET + +DIRECTWRITE: + + IF WD1791 + CALL GETIODRIVER ; Convert drive number to I/O driver number. + JC DIRECTRET ; Return if DSKCHG returned error. + ENDIF + + CALL 8*3,BIOSSEG ; Call WRITE. +DIRECTRET: + SEG CS + MOV B,[CURDRV],-1 ; Force DSKCHG to do density check. + RET L + + IF WD1791 +GETIODRIVER: + SEG CS + MOV B,[CURDRV],-1 ; Force DSKCHG to do density check. + PUSH BX + PUSH CX + CALL 9*3,BIOSSEG ; Call DSKCHG. + POP CX + POP BX + RET + ENDIF +; +; Function: +; Seeks to proper track. +; On entry: +; Same as for disk read or write above. +; On exit: +; AH = Drive select byte +; DL = Track number +; DH = Sector number +; SI = Disk transfer address in DS +; DI = pointer to drive's track counter in CS +; CX unchanged (number of sectors) +; +SEEK: + MOV SI,BX ; Save transfer address + CBW + MOV BX,AX ; Prepare to index on drive number + + IF WD1791 ; If two disk formats per drive. + SHR AL ; Convert to physical disk drive number. + ENDIF + + CALL CHKNEW ; Unload head if changing drives. + SEG CS + MOV AL,[BX+DRVTAB] ; Get drive-select byte. + + IF CROMEMCO16FDC + CALL MOTOR ; Wait for the motors to come up to speed. + ENDIF + + OUTB DISK+4 ; Select drive. + + IF CROMEMCO + OR AL,80H ; Set auto-wait bit. + ENDIF + + MOV AH,AL ; Save drive-select byte in AH. + XCHG AX,DX ; AX = logical sector number. + MOV DL,26 ; 26 sectors/track unless changed below + + IF SCP + TEST DH,SMALLBIT ; Check if small disk. + JZ BIGONE ; Jump if big disk. + MOV DL,18 ; Assume 18 sectors on small track. + TEST DH,DDENBIT ; Check if double-density. + JZ HAVSECT ; Jump if not. + MOV DL,SMALLDDSECT ; Number of sectors on small DD track. + JP HAVSECT +BIGONE: + TEST DH,DDENBIT ; Check if double-density. + JZ HAVSECT ; Jump if not. + MOV DL,LARGEDDSECT ; Number of sectors on big DD track. + ENDIF + + IF TARBELLDD ; Tarbell DD controller. + TEST DH,DDENBIT ; Check for double-density. + JZ HAVSECT + MOV DL,LARGEDDSECT ; Number of sectors on DD track. + ENDIF + + IF CROMEMCO4FDC + TEST DH,SMALLBIT ; Check if small disk. + JNZ HAVSECT ; Jump if not. + MOV DL,18 ; 18 sectors on small disk track. + ENDIF + + IF CROMEMCO16FDC + TEST DH,SMALLBIT ; Check if small disk. + JNZ BIGONE ; Jump if big disk. + MOV DL,18 ; Assume 18 sectors on small track. + TEST DH,DDENBIT ; Check if double-density. + JZ HAVSECT ; Jump if not. + MOV DL,SMALLDDSECT ; Number of sectors on small DD track. + JP HAVSECT +BIGONE: + TEST DH,DDENBIT ; Check if double-density. + JZ HAVSECT ; Jump if not. + MOV DL,LARGEDDSECT ; Number of sectors on big DD track. + ENDIF + +HAVSECT: + DIV AL,DL ; AL = track, AH = sector. + XCHG AX,DX ; AH has drive-select byte, DX = track & sector. + INC DH ; Sectors start at one, not zero. + SEG CS + MOV BL,[BX+TRKPT] ; Get this drive's displacement into track table. + ADD BX,TRKTAB ; BX now points to track counter for this drive. + MOV DI,BX + MOV AL,DL ; Move new track number into AL. + SEG CS + XCHG AL,[DI] ; Xchange current track with desired track + OUT DISK+1 ; Inform controller chip of current track + CMP AL,DL ; See if we're at the right track. + JZ RET + MOV BH,2 ; Seek retry count + CMP AL,-1 ; Head position known? + JNZ NOHOME ; If not, home head +TRYSK: + CALL HOME + JC SEEKERR +NOHOME: + MOV AL,DL ; AL = new track number. + OUT DISK+3 + MOV AL,1CH+STPSPD ; Seek command. + CALL MOVHEAD + AND AL,98H ; Accept not ready, seek, & CRC error bits. + JZ RET + JS SEEKERR ; No retries if not ready + DEC BH + JNZ TRYSK +SEEKERR: + MOV AH,AL ; Put status in AH. + TEST AL,80H ; See if it was a Not Ready error. + STC + JNZ RET ; Status is OK for Not Ready error. + MOV AH,2 ; Everything else is seek error. + RET + +SETUP: + MOV BL,DH ; Move sector number to BL to play with + + IF SCP+CROMEMCO16FDC + TEST AH,DDENBIT ; Check for double density. + JZ CHECKSMALL ; Not DD, check size for SD. + ENDIF + + IF TARBELLDD + TEST AH,DDENBIT ; Check for double density. + JZ CHECK26 ; Not DD. + ENDIF + + IF WD1791 + + IF (SCP+TARBELL)*LARGEDS+SCP*SMALLDS + MOV AL,AH ; Select front side of disk. + OUT DISK+4 + ENDIF + + IF CROMEMCO*(LARGEDS+SMALLDS) + MOV AL,0FFH ; Select front side of disk. + OUT 04H + ENDIF + + CMP BL,8 ; See if legal DD sector number. + JBE PUTSEC ; Jump if ok. + + IF (LARGEDS-1)*((SMALLDS*(SCP+CROMEMCO))-1) + JP STEP ; If only SS drives, we gotta step. + ENDIF + + IF SCP*LARGEDS*(SMALLDS-1) + TEST AH,SMALLBIT ; Check for 5.25 inch disk. + JNZ STEP ; Jump if small because SMALLDS is off. + ENDIF + + IF SCP*SMALLDS*(LARGEDS-1) + TEST AH,SMALLBIT ; Check for 8 inch disk. + JZ STEP ; Jump if large because LARGEDS is off. + ENDIF + + IF CROMEMCO16FDC*LARGEDS*(SMALLDS-1) + TEST AH,SMALLBIT ; Check for 5.25 inch disk. + JZ STEP ; Jump if small because SMALLDS is off. + ENDIF + + IF CROMEMCO16FDC*SMALLDS*(LARGEDS-1) + TEST AH,SMALLBIT ; Check for 8 inch disk. + JNZ STEP ; Jump if large because LARGEDS is off. + ENDIF + + IF LARGEDS+SMALLDS*(SCP+CROMEMCO) + SUB BL,8 ; Find true sector for back side. + CMP BL,8 ; See if ok now. + JA STEP ; Have to step if still too big. + + IF SCP+TARBELLDD + MOV AL,AH ; Move drive select byte into AL. + OR AL,BACKBIT ; Select back side. + OUT DISK+4 + ENDIF + + IF CROMEMCO16FDC + MOV AL,BACKBIT ; Select back side. + OUT 04H + ENDIF + + JP PUTSEC + ENDIF + + ENDIF + + IF SCP +CHECKSMALL: + TEST AH,SMALLBIT ; See if big disk. + JZ CHECK26 ; Jump if big. + ENDIF + + IF CROMEMCO +CHECKSMALL: + TEST AH,SMALLBIT ; See if big disk. + JNZ CHECK26 ; Jump if big. + ENDIF + + IF SCP+CROMEMCO + CMP BL,18 ; See if legal small SD/SS sector. + JA STEP ; Jump if not. + ENDIF + +CHECK26: + CMP BL,26 ; See if legal large SD/SS sector. + JBE PUTSEC ; Jump if ok. +STEP: + INC DL ; Increment track number. + MOV AL,58H ; Step in with update. + CALL DCOM + SEG CS + INC B,[DI] ; Increment the track pointer. + MOV DH,1 ; After step, do first sector. + MOV BL,DH ; Fix temporary sector number also. +PUTSEC: + MOV AL,BL ; Output sector number to controller. + OUT DISK+2 + DI ; Interrupts not allowed until I/O done + + IF SCP+CROMEMCO + INB DISK+4 ; Get head-load bit. + ENDIF + + IF TARBELL + INB DISK + ENDIF + + NOT AL + AND AL,20H ; Check head load status + JZ RET + MOV AL,4 + RET + +READSECT: + CALL SETUP + MOV BL,10 ; Retry count for hard error. + XCHG DI,SI ; Transfer address to DI. + PUSH DX ; Save track & sector number. + MOV DL,DISK+3 ; Disk controller data port. +RDAGN: + OR AL,READCOM + OUT DISK + + IF CROMEMCO + MOV AL,AH ; Turn on auto-wait. + OUT DISK+4 + ENDIF + + MOV BP,DI ; Save address for retry. + JMPS RLOOPENTRY +RLOOP: + STOB ; Write into memory. +RLOOPENTRY: + + IF SCP + IN DISK+5 ; Wait for DRQ or INTRQ. + ENDIF + + IF TARBELL+CROMEMCO + IN DISK+4 + ENDIF + + IF TARBELL + SHL AL + INB DX ; Read data from disk controller chip. + JC RLOOP + ENDIF + + IF SCP+CROMEMCO + SHR AL + INB DX ; Read data from disk controller chip. + JNC RLOOP + ENDIF + + EI ; Interrupts OK now + CALL GETSTAT + AND AL,9CH + JZ RDPOP + MOV DI,BP ; Get origainal address back for retry. + MOV BH,AL ; Save error status for report + MOV AL,0 + DEC BL + JNZ RDAGN + MOV AH,BH ; Put error status in AH. + STC +RDPOP: + POP DX ; Get back track & sector number. + XCHG SI,DI ; Address back to SI. + + IF TARBELL +FORCINT: + MOV AL,0D0H ; Tarbell controllers need this Force Interrupt + OUT DISK ; so that Type I status is always available + MOV AL,10 ; at the 1771/1793 status port so we can find +INTDLY: ; out if the head is loaded. SCP and Cromemco + DEC AL ; controllers have head-load status available + JNZ INTDLY ; at the DISK+4 status port. + ENDIF + + RET + +WRITESECT: + CALL SETUP + MOV BL,10 + PUSH DX ; Save track & sector number. + MOV DL,DISK+3 ; Disk controller data port. +WRTAGN: + OR AL,WRITECOM + OUT DISK + + IF CROMEMCO + MOV AL,AH ; Turn on auto-wait. + OUT DISK+4 + ENDIF + + MOV BP,SI +WRLOOP: + + IF SCP + INB DISK+5 + ENDIF + + IF TARBELL+CROMEMCO + INB DISK+4 + ENDIF + + IF SCP+CROMEMCO + SHR AL + LODB ; Get data from memory. + OUTB DX ; Write to disk. + JNC WRLOOP + ENDIF + + IF TARBELL + SHL AL + LODB ; Get data from memory. + OUTB DX ; Write to disk. + JC WRLOOP + ENDIF + + EI ; Interrupts OK now. + DEC SI + CALL GETSTAT + AND AL,0FCH + JZ WRPOP + MOV SI,BP + MOV BH,AL + MOV AL,0 + DEC BL + JNZ WRTAGN + MOV AH,BH ; Error status to AH. + STC +WRPOP: + POP DX ; Get back track & sector number. + + IF TARBELL + JMPS FORCINT + ENDIF + + IF SCP+CROMEMCO + RET + ENDIF +; +; Subroutine to restore the read/write head to track 0. +; + IF SCP+CROMEMCO+TARBELL*(FASTSEEK-1) +HOME: + ENDIF + + IF FASTSEEK*CROMEMCO + TEST AH,SMALLBIT ; Check for large disk. + JNZ RESTORE ; Big disks are fast seek PerSci. + ENDIF + + MOV BL,3 +TRYHOM: + + IF SCP*FASTSEEK + MOV AL,AH ; Turn on Restore to PerSci. + OR AL,80H + OUTB DISK+4 + ENDIF + + MOV AL,0CH+STPSPD ; Restore with verify command. + CALL DCOM + AND AL,98H + + IF SCP*FASTSEEK + MOV AL,AH ; Restore off. + OUTB DISK+4 + ENDIF + + JZ RET + JS HOMERR ; No retries if not ready + MOV AL,58H+STPSPD ; Step in with update + CALL DCOM + DEC BL + JNZ TRYHOM +HOMERR: + STC + RET +; +; RESTORE for PerSci drives. +; Doesn't exist yet for Tarbell controllers. +; + IF FASTSEEK*TARBELL +HOME: +RESTORE: + RET + ENDIF + + IF FASTSEEK*CROMEMCO4FDC +RESTORE: + MOV AL,0C4H ;READ ADDRESS command to keep head loaded + OUT DISK + MOV AL,77H + OUT 4 +CHKRES: + IN 4 + AND AL,40H + JZ RESDONE + IN DISK+4 + TEST AL,DONEBIT + JZ CHKRES + IN DISK + JP RESTORE ;Reload head +RESDONE: + MOV AL,7FH + OUT 4 + CALL GETSTAT + MOV AL,0 + OUT DISK+1 ;Tell 1771 we're now on track 0 + RET + ENDIF + + IF FASTSEEK*CROMEMCO16FDC +RESTORE: + MOV AL,0D7H ; Turn on Drive-Select and Restore. + OUTB 4 + PUSH AX + AAM ; 10 uS delay. + POP AX +RESWAIT: + INB 4 ; Wait till Seek Complete is active. + TEST AL,40H + JNZ RESWAIT + MOV AL,0FFH ; Turn off Drive-Select and Restore. + OUTB 4 + SUB AL,AL ; Tell 1793 we're on track 0. + OUTB DISK+1 + RET + ENDIF +; +; Subroutine to move the read/write head to the desired track. +; Usually falls through to DCOM unless special handling for +; PerSci drives is required in which case go to FASTSK. +; + IF SCP+CROMEMCO+TARBELL*(FASTSEEK-1) +MOVHEAD: + ENDIF + + IF CROMEMCO*FASTSEEK + TEST AH,SMALLBIT ; Check for PerSci. + JNZ FASTSK + ENDIF + +DCOM: + OUT DISK + PUSH AX + AAM ;Delay 10 microseconds + POP AX +GETSTAT: + IN DISK+4 + TEST AL,DONEBIT + + IF TARBELL + JNZ GETSTAT + ENDIF + + IF SCP+CROMEMCO + JZ GETSTAT + ENDIF + + IN DISK + RET +; +; Fast seek code for PerSci drives. +; Tarbell not installed yet. +; + IF FASTSEEK*TARBELL +MOVHEAD: +FASTSK: + RET + ENDIF + + IF FASTSEEK*CROMEMCO +FASTSK: + MOV AL,6FH + OUT 4 + MOV AL,18H + CALL DCOM +SKWAIT: + IN 4 + TEST AL,40H + JNZ SKWAIT + MOV AL,7FH + OUT 4 + MOV AL,0 + RET + ENDIF + +CURDRV: DB -1 +; +; Explanation of tables below. +; +; DRVTAB is a table of bytes which are sent to the disk controller as drive- +; select bytes to choose which physical drive is selected for each disk I/O +; driver. It also selects whether the disk is 5.25-inch or 8-inch, single- +; density or double-density. Always select side 0 in the drive-select byte if +; a side-select bit is available. There should be one entry in the DRVTAB +; table for each disk I/O driver. Exactly which bits in the drive-select byte +; do what depends on which disk controller is used. +; +; TRKTAB is a table of bytes used to store which track the read/write +; head of each drive is on. Each physical drive should have its own +; entry in TRKTAB. +; +; TRKPT is a table of bytes which indicates which TRKTAB entry each +; disk I/O driver should use. Since each physical drive may be used for +; more than one disk I/O driver, more than one entry in TRKPT may point +; to the same entry in TRKTAB. Drives such as PerSci 277s which use +; the same head positioner for more than one drive should share entrys +; in TRKTAB. +; +; INITTAB is the initialization table for 86-DOS as described in the +; 86-DOS Programer's Manual under "Customizing the I/O System." +; + IF SCP*COMBIN*FASTSEEK +; +; A PerSci 277 or 299 and one 5.25-inch drive. +; +DRVTAB: DB 00H,08H,01H,09H,10H,18H,00H,08H,01H,09H +TRKPT: DB 0,0,0,0,1,1,0,0,0,0 +TRKTAB: DB -1,-1 +INITTAB: + IF CONVERT-1 + DB 6 ; Number of disk I/O drivers. + ENDIF + + IF CONVERT + DB 10 + ENDIF + + DB 0 ; Disk I/O driver 0 uses disk drive 0. + DW LSDRIVE ; Disk I/O driver 0 is 8-inch single-density. + DB 0 ; Disk I/O driver 1 uses disk drive 0. + DW LDDRIVE ; Disk I/O driver 1 is 8-inch double-density. + DB 1 ; Etc. + DW LSDRIVE + DB 1 + DW LDDRIVE + DB 2 + DW SSDRIVE + DB 2 + DW SDDRIVE + + IF CONVERT + DB 3 + DW OLDLSDRIVE + DB 3 + DW OLDLDDRIVE + DB 4 + DW OLDLSDRIVE + DB 4 + DW OLDLDDRIVE + ENDIF + ENDIF + + IF SCP*LARGE*FASTSEEK +; +; PerSci 277 or 299. +; +DRVTAB: DB 00H,08H,01H,09H,00H,08H,01H,09H +TRKPT: DB 0,0,0,0,0,0,0,0 +TRKTAB: DB -1 +INITTAB: + IF CONVERT-1 + DB 4 + ENDIF + + IF CONVERT + DB 8 + ENDIF + + DB 0 + DW LSDRIVE + DB 0 + DW LDDRIVE + DB 1 + DW LSDRIVE + DB 1 + DW LDDRIVE + + IF CONVERT + DB 2 + DW OLDLSDRIVE + DB 2 + DW OLDLDDRIVE + DB 3 + DW OLDLSDRIVE + DB 3 + DW OLDLDDRIVE + ENDIF + ENDIF + + IF TARBELLDD +; +; Two 8-inch Shugart-type drives. +; +DRVTAB: DB 0,8,10H,18H,0,8,10H,18H +TRKPT: DB 0,0,1,1,0,0,1,1 +TRKTAB: DB -1,-1 +INITTAB: + + IF CONVERT-1 + DB 4 + ENDIF + + IF CONVERT + DB 8 + ENDIF + + DB 0 + DW LSDRIVE + DB 0 + DW LDDRIVE + DB 1 + DW LSDRIVE + DB 1 + DW LDDRIVE + + IF CONVERT + DB 2 + DW OLDLSDRIVE + DB 2 + DW OLDLDDRIVE + DB 3 + DW OLDLSDRIVE + DB 3 + DW OLDLDDRIVE + ENDIF + ENDIF + + IF TARBELLSD +; +; Four 8-inch Shugart-type drives. +; +DRVTAB: DB 0F2H,0E2H,0F2H,0E2H +TRKPT: DB 0,1,0,1 +TRKTAB: DB -1,-1 +INITTAB: + + IF CONVERT-1 + DB 2 + ENDIF + + IF CONVERT + DB 4 + ENDIF + + DB 0 + DW LSDRIVE + DB 1 + DW LSDRIVE + + IF CONVERT + DB 2 + DW OLDLSDRIVE + DB 3 + DW OLDLSDRIVE + ENDIF + ENDIF +; +; Cromemco drive select byte is derived as follows: +; Bit 7 = 0 +; Bit 6 = 1 if double density (if 16FDC) +; Bit 5 = 1 (motor on) +; Bit 4 = 0 for 5", 1 for 8" drives +; Bit 3 = 1 for drive 3 +; Bit 2 = 1 for drive 2 +; Bit 1 = 1 for drive 1 +; Bit 0 = 1 for drive 0 +; + IF CROMEMCO4FDC*LARGE +; +; PerSci 277 drive. +; +DRVTAB: DB 31H,32H,31H,32H +TRKPT: DB 0,0,0,0 +TRKTAB: DB -1 +INITTAB: + + IF CONVERT-1 + DB 2 + ENDIF + + IF CONVERT + DB 4 + ENDIF + + DB 0 + DW LSDRIVE + DB 1 + DW LSDRIVE + + IF CONVERT + DB 2 + DW OLDLSDRIVE + DB 3 + DW OLDLSDRIVE + ENDIF + ENDIF + + IF CROMEMCO4FDC*COMBIN +; +; A PerSci 277 and one 5.25-inch drive. +; +DRVTAB: DB 31H,32H,24H,31H,32H +TRKPT: DB 0,0,1,0,0 +TRKTAB: DB -1,-1 +INITTAB: + + IF CONVERT-1 + DB 3 + ENDIF + + IF CONVERT + DB 5 + ENDIF + + DB 0 + DW LSDRIVE + DB 1 + DW LSDRIVE + DB 2 + DW SSDRIVE + + IF CONVERT + DB 3 + DW OLDLSDRIVE + DB 4 + DW OLDLSDRIVE + ENDIF + ENDIF + + IF CROMEMCO4FDC*SMALL +; +; Three 5.25-inch drives. +; +DRVTAB: DB 21H,22H,24H +TRKPT: DB 0,1,2 +TRKTAB: DB -1,-1,-1 +INITTAB:DB 3 + DB 0 + DW SSDRIVE + DB 1 + DW SSDRIVE + DB 2 + DW SSDRIVE + ENDIF + + IF CUSTOM +; +; Cromemco 4FDC with two 8-inch Shugart-type drives. +; +DRVTAB: DB 31H,32H,31H,32H +TRKPT: DB 0,1,0,1 +TRKTAB: DB -1,-1 +INITTAB: + IF CONVERT-1 + DB 2 + ENDIF + + IF CONVERT + DB 4 + ENDIF + + DB 0 + DW LSDRIVE + DB 1 + DW LSDRIVE + + IF CONVERT + DB 2 + DW OLDLSDRIVE + DB 3 + DW OLDLSDRIVE + ENDIF + ENDIF + + IF CROMEMCO16FDC*SMALL +; +; Three 5.25-inch drives. +; +DRVTAB: DB 21H,61H,22H,62H,24H,64H +TRKPT: DB 0,0,1,1,2,2 +TRKTAB: DB -1,-1,-1 +INITTAB:DB 6 + DB 0 + DW SSDRIVE + DB 0 + DW SDDRIVE + DB 1 + DW SSDRIVE + DB 1 + DW SDDRIVE + DB 2 + DW SSDRIVE + DB 2 + DW SDDRIVE + ENDIF + + IF CROMEMCO16FDC*COMBIN +; +; A PerSci 277 or 299 and one 5.25-inch drive. +; +DRVTAB: DB 31H,71H,32H,72H,24H,64H,31H,71H,32H,72H +TRKPT: DB 0,0,0,0,1,1,0,0,0,0 +TRKTAB: DB -1,-1 +INITTAB: + IF CONVERT-1 + DB 6 + ENDIF + + IF CONVERT + DB 10 + ENDIF + + DB 0 + DW LSDRIVE + DB 0 + DW LDDRIVE + DB 1 + DW LSDRIVE + DB 1 + DW LDDRIVE + DB 2 + DW SSDRIVE + DB 2 + DW SDDRIVE + + IF CONVERT + DB 3 + DW OLDLSDRIVE + DB 3 + DW OLDLDDRIVE + DB 4 + DW OLDLSDRIVE + DB 4 + DW OLDLDDRIVE + ENDIF + ENDIF + + IF CROMEMCO16FDC*LARGE +; +; A PerSci 277 or 299. +; +DRVTAB: DB 31H,71H,32H,72H,31H,71H,32H,72H +TRKPT: DB 0,0,0,0,0,0,0,0 +TRKTAB: DB -1 +INITTAB: + IF CONVERT-1 + DB 4 + ENDIF + + IF CONVERT + DB 8 + ENDIF + + DB 0 + DW LSDRIVE + DB 0 + DW LDDRIVE + DB 1 + DW LSDRIVE + DB 1 + DW LDDRIVE + + IF CONVERT + DB 2 + DW OLDLSDRIVE + DB 2 + DW OLDLDDRIVE + DB 3 + DW OLDLSDRIVE + DB 3 + DW OLDLDDRIVE + ENDIF + ENDIF + + IF SMALL+COMBIN +SSDRIVE: + DW 128 ; Sector size in bytes. + DB 2 ; Sector per allocation unit. + DW 54 ; Reserved sectors. + DB 2 ; Number of allocation tables. + DW 64 ; Number of directory entrys. + DW 720 ; Number of sectors on the disk. + + IF SMALLDS-1 +SDDRIVE: ; This is the IBM Personal Computer + DW 512 ; disk format. + DB 1 + DW 1 + DB 2 + DW 64 + DW 320 + ENDIF + + IF SMALLDS +SDDRIVE: + DW 512 + DB 2 + DW 1 + DB 2 + DW 112 + DW 640 + ENDIF + ENDIF ; End of small drive DPTs. + + IF COMBIN+LARGE +LSDRIVE: + DW 128 ; Size of sector in bytes. + DB 4 ; Sectors per allocation unit. + DW 1 ; Number of reserved sectors. + DB 2 ; Number of File Allocation Tables. + DW 68 ; Number of directory entrys. + DW 77*26 ; Number of sectors on the disk. + + IF CONVERT +OLDLSDRIVE: + DW 128 + DB 4 + DW 52 ; Old format had two tracks reserved. + DB 2 + DW 64 ; 64 directory entrys. + DW 77*26 + ENDIF + + IF LARGEDS-1 +OLDLDDRIVE: +LDDRIVE: + DW 1024 + DB 1 + DW 1 + DB 2 + DW 96 + DW 77*8 + ENDIF + + IF LARGEDS +LDDRIVE: + DW 1024 + DB 1 + DW 1 + DB 2 + DW 192 ; 192 directory entrys in new 8-inch DD/DS format. + DW 77*8*2 + + IF CONVERT +OLDLDDRIVE: + DW 1024 + DB 1 + DW 1 + DB 2 + DW 128 ; 128 directory entrys in old 8-inch DD/DS format. + DW 77*8*2 + ENDIF + ENDIF + + ENDIF ; End of large drive DPTs. + +DOSSEG: EQU ($+15)/16+BIOSSEG ; Compute segment to use for 86-DOS. +DOSDIF: EQU 16*(DOSSEG-BIOSSEG) +STKSAV: EQU 1701H+DOSDIF +DMAADD: EQU 15B4H+DOSDIF + END + \ No newline at end of file diff --git a/v1.25/source/MSDOS.ASM b/v1.25/source/MSDOS.ASM new file mode 100644 index 0000000..8538b76 --- /dev/null +++ b/v1.25/source/MSDOS.ASM @@ -0,0 +1,4031 @@ +; 86-DOS High-performance operating system for the 8086 version 1.25 +; by Tim Paterson + + +; ****************** Revision History ************************* +; >> EVERY change must noted below!! << +; +; 0.34 12/29/80 General release, updating all past customers +; 0.42 02/25/81 32-byte directory entries added +; 0.56 03/23/81 Variable record and sector sizes +; 0.60 03/27/81 Ctrl-C exit changes, including register save on user stack +; 0.74 04/15/81 Recognize I/O devices with file names +; 0.75 04/17/81 Improve and correct buffer handling +; 0.76 04/23/81 Correct directory size when not 2^N entries +; 0.80 04/27/81 Add console input without echo, Functions 7 & 8 +; 1.00 04/28/81 Renumber for general release +; 1.01 05/12/81 Fix bug in `STORE' +; 1.10 07/21/81 Fatal error trapping, NUL device, hidden files, date & time, +; RENAME fix, general cleanup +; 1.11 09/03/81 Don't set CURRENT BLOCK to 0 on open; fix SET FILE SIZE +; 1.12 10/09/81 Zero high half of CURRENT BLOCK after all (CP/M programs don't) +; 1.13 10/29/81 Fix classic "no write-through" error in buffer handling +; 1.20 12/31/81 Add time to FCB; separate FAT from DPT; Kill SMALLDIR; +; Add FLUSH and MAPDEV calls; allow disk mapping in DSKCHG; +; Lots of smaller improvements +; 1.21 01/06/82 HIGHMEM switch to run DOS in high memory +; 1.22 01/12/82 Add VERIFY system call to enable/disable verify after write +; 1.23 02/11/82 Add defaulting to parser; use variable escape character +; Don't zero extent field in IBM version (back to 1.01!) +; 1.24 03/01/82 Restore fcn. 27 to 1.0 level; add fcn. 28 +; 1.25 03/03/82 Put marker (00) at end of directory to speed searches +; +; ************************************************************* + + +; Interrupt Entry Points: + +; INTBASE: ABORT +; INTBASE+4: COMMAND +; INTBASE+8: BASE EXIT ADDRESS +; INTBASE+C: CONTROL-C ABORT +; INTBASE+10H: FATAL ERROR ABORT +; INTBASE+14H: BIOS DISK READ +; INTBASE+18H: BIOS DISK WRITE +; INTBASE+40H: Long jump to CALL entry point + + IF IBM +ESCCH EQU 0 +CANCEL EQU 1BH ;Cancel with ESC +TOGLINS EQU TRUE ;One key toggles insert mode +TOGLPRN EQU TRUE ;One key toggles printer echo +NUMDEV EQU 6 ;Include "COM1" as I/O device name +ZEROEXT EQU TRUE + ELSE +ESCCH EQU 1BH +CANCEL EQU "X"-"@" ;Cancel with Ctrl-X +TOGLINS EQU FALSE ;Separate keys for insert mode on and off +TOGLPRN EQU FALSE ;Separate keys for printer echo on and off +NUMDEV EQU 5 ;Number of I/O device names +ZEROEXT EQU FALSE + ENDIF + +MAXCALL EQU 36 +MAXCOM EQU 46 +INTBASE EQU 80H +INTTAB EQU 20H +ENTRYPOINTSEG EQU 0CH +ENTRYPOINT EQU INTBASE+40H +CONTC EQU INTTAB+3 +EXIT EQU INTBASE+8 +LONGJUMP EQU 0EAH +LONGCALL EQU 9AH +MAXDIF EQU 0FFFH +SAVEXIT EQU 10 + +; Field definition for FCBs + +FCBLOCK STRUC + DB 12 DUP (?) ;Drive code and name +EXTENT DW ? +RECSIZ DW ? ;Size of record (user settable) +FILSIZ DW ? ;Size of file in bytes +DRVBP DW ? ;BP for SEARCH FIRST and SEARCH NEXT +FDATE DW ? ;Date of last writing +FTIME DW ? ;Time of last writing +DEVID DB ? ;Device ID number, bits 0-5 + ;bit 7=0 for file, bit 7=1 for I/O device + ;If file, bit 6=0 if dirty + ;If I/O device, bit 6=0 if EOF (input) +FIRCLUS DW ? ;First cluster of file +LSTCLUS DW ? ;Last cluster accessed +CLUSPOS DW ? ;Position of last cluster accessed + DB ? ;Forces NR to offset 32 +NR DB ? ;Next record +RR DB 3 DUP (?) ;Random record +FCBLOCK ENDS +FILDIRENT = FILSIZ ;Used only by SEARCH FIRST and SEARCH NEXT + +; Description of 32-byte directory entry (same as returned by SEARCH FIRST +; and SEARCH NEXT, functions 17 and 18). +; +; Location bytes Description +; +; 0 11 File name and extension ( 0E5H if empty) +; 11 1 Attributes. Bits 1 or 2 make file hidden +; 12 10 Zero field (for expansion) +; 22 2 Time. Bits 0-4=seconds/2, bits 5-10=minute, 11-15=hour +; 24 2 Date. Bits 0-4=day, bits 5-8=month, bits 9-15=year-1980 +; 26 2 First allocation unit ( < 4080 ) +; 28 4 File size, in bytes (LSB first, 30 bits max.) +; +; The File Allocation Table uses a 12-bit entry for each allocation unit on +; the disk. These entries are packed, two for every three bytes. The contents +; of entry number N is found by 1) multiplying N by 1.5; 2) adding the result +; to the base address of the Allocation Table; 3) fetching the 16-bit word at +; this address; 4) If N was odd (so that N*1.5 was not an integer), shift the +; word right four bits; 5) mask to 12 bits (AND with 0FFF hex). Entry number +; zero is used as an end-of-file trap in the OS and as a flag for directory +; entry size (if SMALLDIR selected). Entry 1 is reserved for future use. The +; first available allocation unit is assigned entry number two, and even +; though it is the first, is called cluster 2. Entries greater than 0FF8H are +; end of file marks; entries of zero are unallocated. Otherwise, the contents +; of a FAT entry is the number of the next cluster in the file. + + +; Field definition for Drive Parameter Block + +DPBLOCK STRUC +DEVNUM DB ? ;I/O driver number +DRVNUM DB ? ;Physical Unit number +SECSIZ DW ? ;Size of physical sector in bytes +CLUSMSK DB ? ;Sectors/cluster - 1 +CLUSSHFT DB ? ;Log2 of sectors/cluster +FIRFAT DW ? ;Starting record of FATs +FATCNT DB ? ;Number of FATs for this drive +MAXENT DW ? ;Number of directory entries +FIRREC DW ? ;First sector of first cluster +MAXCLUS DW ? ;Number of clusters on drive + 1 +FATSIZ DB ? ;Number of records occupied by FAT +FIRDIR DW ? ;Starting record of directory +FAT DW ? ;Pointer to start of FAT +DPBLOCK ENDS + +DPBSIZ EQU 20 ;Size of the structure in bytes +DIRSEC = FIRREC ;Number of dir. sectors (init temporary) +DSKSIZ = MAXCLUS ;Size of disk (temp used during init only) + +;The following are all of the segments used +;They are declared in the order that they should be placed in the executable + +CODE SEGMENT +CODE ENDS + +CONSTANTS SEGMENT BYTE +CONSTANTS ENDS + +DATA SEGMENT WORD +DATA ENDS + +DOSGROUP GROUP CODE,CONSTANTS,DATA + +SEGBIOS SEGMENT +SEGBIOS ENDS + + +; BOIS entry point definitions + + IF IBM +BIOSSEG EQU 60H + ENDIF + IF NOT IBM +BIOSSEG EQU 40H + ENDIF + +SEGBIOS SEGMENT AT BIOSSEG + ORG 0 + DB 3 DUP (?) ;Reserve room for jump to init code +BIOSSTAT DB 3 DUP (?) ;Console input status check +BIOSIN DB 3 DUP (?) ;Get console character +BIOSOUT DB 3 DUP (?) ;Output console character +BIOSPRINT DB 3 DUP (?) ;Output to printer +BIOSAUXIN DB 3 DUP (?) ;Get byte from auxilliary +BIOSAUXOUT DB 3 DUP (?) ;Output byte to auxilliary +BIOSREAD DB 3 DUP (?) ;Disk read +BIOSWRITE DB 3 DUP (?) ;Disk write +BIOSDSKCHG DB 3 DUP (?) ;Dsik-change status +BIOSSETDATE DB 3 DUP (?) ;Set date +BIOSSETTIME DB 3 DUP (?) ;Set time +BIOSGETTIME DB 3 DUP (?) ;Get time and date +BIOSFLUSH DB 3 DUP (?) ;Clear console input buffer +BIOSMAPDEV DB 3 DUP (?) ;Dynamic disk table mapper + +SEGBIOS ENDS +; Location of user registers relative user stack pointer + +STKPTRS STRUC +AXSAVE DW ? +BXSAVE DW ? +CXSAVE DW ? +DXSAVE DW ? +SISAVE DW ? +DISAVE DW ? +BPSAVE DW ? +DSSAVE DW ? +ESSAVE DW ? +IPSAVE DW ? +CSSAVE DW ? +FSAVE DW ? +STKPTRS ENDS + +; Start of code + +CODE SEGMENT +ASSUME CS:DOSGROUP,DS:DOSGROUP,ES:DOSGROUP,SS:DOSGROUP + + ORG 0 +CODSTRT EQU $ + JMP DOSINIT + +ESCCHAR DB ESCCH ;Lead-in character for escape sequences +ESCTAB: + IF NOT IBM + DB "S" ;Copy one char + DB "V" ;Skip one char + DB "T" ;Copy to char + DB "W" ;Skip to char + DB "U" ;Copy line + DB "E" ;Kill line (no change in template) + DB "J" ;Reedit line (new template) + DB "D" ;Backspace + DB "P" ;Enter insert mode + DB "Q" ;Exit insert mode + DB "R" ;Escape character + DB "R" ;End of table + ENDIF + IF IBM + DB 64 ;Crtl-Z - F6 + DB 77 ;Copy one char - --> + DB 59 ;Copy one char - F1 + DB 83 ;Skip one char - DEL + DB 60 ;Copy to char - F2 + DB 62 ;Skip to char - F4 + DB 61 ;Copy line - F3 + DB 61 ;Kill line (no change to template ) - Not used + DB 63 ;Reedit line (new template) - F5 + DB 75 ;Backspace - <-- + DB 82 ;Enter insert mode - INS (toggle) + DB 65 ;Escape character - F7 + DB 65 ;End of table + ENDIF + +ESCTABLEN EQU $-ESCTAB + IF NOT IBM +HEADER DB 13,10,"MS-DOS version 1.25" + IF HIGHMEM + DB "H" + ENDIF + IF DSKTEST + DB "D" + ENDIF + + DB 13,10 + DB "Copyright 1981,82 Microsoft, Inc.",13,10,"$" + ENDIF + +QUIT: + MOV AH,0 + JMP SHORT SAVREGS + +COMMAND: ;Interrupt call entry point + CMP AH,MAXCOM + JBE SAVREGS +BADCALL: + MOV AL,0 +IRET: IRET + +ENTRY: ;System call entry point and dispatcher + POP AX ;IP from the long call at 5 + POP AX ;Segment from the long call at 5 + POP CS:[TEMP] ;IP from the CALL 5 + PUSHF ;Start re-ordering the stack + CLI + PUSH AX ;Save segment + PUSH CS:[TEMP] ;Stack now ordered as if INT had been used + CMP CL,MAXCALL ;This entry point doesn't get as many calls + JA BADCALL + MOV AH,CL +SAVREGS: + PUSH ES + PUSH DS + PUSH BP + PUSH DI + PUSH SI + PUSH DX + PUSH CX + PUSH BX + PUSH AX + + IF DSKTEST + MOV AX,CS:[SPSAVE] + MOV CS:[NSP],AX + MOV AX,CS:[SSSAVE] + MOV CS:[NSS],AX + POP AX + PUSH AX + ENDIF + + MOV CS:[SPSAVE],SP + MOV CS:[SSSAVE],SS + MOV SP,CS + MOV SS,SP +REDISP: + MOV SP,OFFSET DOSGROUP:IOSTACK + STI ;Stack OK now + MOV BL,AH + MOV BH,0 + SHL BX,1 + CLD + CMP AH,12 + JLE SAMSTK + MOV SP,OFFSET DOSGROUP:DSKSTACK +SAMSTK: + CALL CS:[BX+DISPATCH] +LEAVE: + CLI + MOV SP,CS:[SPSAVE] + MOV SS,CS:[SSSAVE] + MOV BP,SP + MOV BYTE PTR [BP.AXSAVE],AL + + IF DSKTEST + MOV AX,CS:[NSP] + MOV CS:[SPSAVE],AX + MOV AX,CS:[NSS] + MOV CS:[SSSAVE],AX + ENDIF + + POP AX + POP BX + POP CX + POP DX + POP SI + POP DI + POP BP + POP DS + POP ES + IRET +; Standard Functions +DISPATCH DW ABORT ;0 + DW CONIN + DW CONOUT + DW READER + DW PUNCH + DW LIST ;5 + DW RAWIO + DW RAWINP + DW IN + DW PRTBUF + DW BUFIN ;10 + DW CONSTAT + DW FLUSHKB + DW DSKRESET + DW SELDSK + DW OPEN ;15 + DW CLOSE + DW SRCHFRST + DW SRCHNXT + DW DELETE + DW SEQRD ;20 + DW SEQWRT + DW CREATE + DW RENAME + DW INUSE + DW GETDRV ;25 + DW SETDMA + DW GETFATPT + DW GETFATPTDL + DW GETRDONLY + DW SETATTRIB ;30 + DW GETDSKPT + DW USERCODE + DW RNDRD + DW RNDWRT + DW FILESIZE ;35 + DW SETRNDREC +; Extended Functions + DW SETVECT + DW NEWBASE + DW BLKRD + DW BLKWRT ;40 + DW MAKEFCB + DW GETDATE + DW SETDATE + DW GETTIME + DW SETTIME ;45 + DW VERIFY + +INUSE: +GETIO: +SETIO: +GETRDONLY: +SETATTRIB: +USERCODE: + MOV AL,0 + RET + +VERIFY: + AND AL,1 + MOV CS:VERFLG,AL + RET + +FLUSHKB: + PUSH AX + CALL FAR PTR BIOSFLUSH + POP AX + MOV AH,AL + CMP AL,1 + JZ REDISPJ + CMP AL,6 + JZ REDISPJ + CMP AL,7 + JZ REDISPJ + CMP AL,8 + JZ REDISPJ + CMP AL,10 + JZ REDISPJ + MOV AL,0 + RET + +REDISPJ:JMP REDISP + +READER: +AUXIN: + CALL STATCHK + CALL FAR PTR BIOSAUXIN + RET + +PUNCH: + MOV AL,DL +AUXOUT: + PUSH AX + CALL STATCHK + POP AX + CALL FAR PTR BIOSAUXOUT + RET + + +UNPACK: + +; Inputs: +; DS = CS +; BX = Cluster number +; BP = Base of drive parameters +; SI = Pointer to drive FAT +; Outputs: +; DI = Contents of FAT for given cluster +; Zero set means DI=0 (free cluster) +; No other registers affected. Fatal error if cluster too big. + + CMP BX,[BP.MAXCLUS] + JA HURTFAT + LEA DI,[SI+BX] + SHR BX,1 + MOV DI,[DI+BX] + JNC HAVCLUS + SHR DI,1 + SHR DI,1 + SHR DI,1 + SHR DI,1 + STC +HAVCLUS: + RCL BX,1 + AND DI,0FFFH + RET +HURTFAT: + PUSH AX + MOV AH,80H ;Signal Bad FAT to INT 24H handler + MOV DI,0FFFH ;In case INT 24H returns (it shouldn't) + CALL FATAL + POP AX ;Try to ignore bad FAT + RET + + +PACK: + +; Inputs: +; DS = CS +; BX = Cluster number +; DX = Data +; SI = Pointer to drive FAT +; Outputs: +; The data is stored in the FAT at the given cluster. +; BX,DX,DI all destroyed +; No other registers affected + + MOV DI,BX + SHR BX,1 + ADD BX,SI + ADD BX,DI + SHR DI,1 + MOV DI,[BX] + JNC ALIGNED + SHL DX,1 + SHL DX,1 + SHL DX,1 + SHL DX,1 + AND DI,0FH + JMP SHORT PACKIN +ALIGNED: + AND DI,0F000H +PACKIN: + OR DI,DX + MOV [BX],DI + RET + +DEVNAME: + MOV SI,OFFSET DOSGROUP:IONAME ;List of I/O devices with file names + MOV BH,NUMDEV ;BH = number of device names +LOOKIO: + MOV DI,OFFSET DOSGROUP:NAME1 + MOV CX,4 ;All devices are 4 letters + REPE CMPSB ;Check for name in list + JZ IOCHK ;If first 3 letters OK, check for the rest + ADD SI,CX ;Point to next device name + DEC BH + JNZ LOOKIO +CRET: + STC ;Not found + RET + +IOCHK: + IF IBM + CMP BH,NUMDEV ;Is it the first device? + JNZ NOTCOM1 + MOV BH,2 ;Make it the same as AUX +NOTCOM1: + ENDIF + NEG BH + MOV CX,2 ;Check rest of name but not extension + MOV AX,2020H + REPE SCASW ;Make sure rest of name is blanks + JNZ CRET +RET1: RET ;Zero set so CREATE works + +GETFILE: +; Same as GETNAME except ES:DI points to FCB on successful return + CALL MOVNAME + JC RET1 + PUSH DX + PUSH DS + CALL FINDNAME + POP ES + POP DI +RET2: RET + + +GETNAME: + +; Inputs: +; DS,DX point to FCB +; Function: +; Find file name in disk directory. First byte is +; drive number (0=current disk). "?" matches any +; character. +; Outputs: +; Carry set if file not found +; ELSE +; Zero set if attributes match (always except when creating) +; BP = Base of drive parameters +; DS = CS +; ES = CS +; BX = Pointer into directory buffer +; SI = Pointer to First Cluster field in directory entry +; [DIRBUF] has directory record with match +; [NAME1] has file name +; All other registers destroyed. + + CALL MOVNAME + JC RET2 ;Bad file name? +FINDNAME: + MOV AX,CS + MOV DS,AX + CALL DEVNAME + JNC RET2 + CALL STARTSRCH +CONTSRCH: + CALL GETENTRY + JC RET2 +SRCH: + MOV AH,BYTE PTR [BX] + OR AH,AH ;End of directory? + JZ FREE + CMP AH,[DELALL] ;Free entry? + JZ FREE + MOV SI,BX + MOV DI,OFFSET DOSGROUP:NAME1 + MOV CX,11 +WILDCRD: + REPE CMPSB + JZ FOUND + CMP BYTE PTR [DI-1],"?" + JZ WILDCRD +NEXTENT: + CALL NEXTENTRY + JNC SRCH +RET3: RET + +FREE: + CMP [ENTFREE],-1 ;Found a free entry before? + JNZ TSTALL ;If so, ignore this one + MOV CX,[LASTENT] + MOV [ENTFREE],CX +TSTALL: + CMP AH,[DELALL] ;At end of directory? + JZ NEXTENT ;No - continue search + STC ;Report not found + RET + +FOUND: +;Check if attributes allow finding it + MOV AH,[ATTRIB] ;Attributes of search + NOT AH + AND AH,[SI] ;Compare with attributes of file + ADD SI,15 + AND AH,6 ;Only look at bits 1 and 2 + JZ RET3 + TEST BYTE PTR [CREATING],-1 ;Pass back mismatch if creating + JZ NEXTENT ;Otherwise continue searching + RET + + +GETENTRY: + +; Inputs: +; [LASTENT] has previously searched directory entry +; Function: +; Locates next sequential directory entry in preparation for search +; Outputs: +; Carry set if none +; ELSE +; AL = Current directory block +; BX = Pointer to next directory entry in [DIRBUF] +; DX = Pointer to first byte after end of DIRBUF +; [LASTENT] = New directory entry number + + MOV AX,[LASTENT] + INC AX ;Start with next entry + CMP AX,[BP.MAXENT] + JAE NONE +GETENT: + MOV [LASTENT],AX + MOV CL,4 + SHL AX,CL + XOR DX,DX + SHL AX,1 + RCL DX,1 ;Account for overflow in last shift + MOV BX,[BP.SECSIZ] + AND BL,255-31 ;Must be multiple of 32 + DIV BX + MOV BX,DX ;Position within sector + MOV AH,[BP.DEVNUM] ;AL=Directory sector no. + CMP AX,[DIRBUFID] + JZ HAVDIRBUF + PUSH BX + CALL DIRREAD + POP BX +HAVDIRBUF: + MOV DX,OFFSET DOSGROUP:DIRBUF + ADD BX,DX + ADD DX,[BP.SECSIZ] + RET + +NEXTENTRY: + +; Inputs: +; Same as outputs of GETENTRY, above +; Function: +; Update AL, BX, and [LASTENT] for next directory entry. +; Carry set if no more. + + MOV DI,[LASTENT] + INC DI + CMP DI,[BP.MAXENT] + JAE NONE + MOV [LASTENT],DI + ADD BX,32 + CMP BX,DX + JB HAVIT + INC AL ;Next directory sector + PUSH DX ;Save limit + CALL DIRREAD + POP DX + MOV BX,OFFSET DOSGROUP:DIRBUF +HAVIT: + CLC + RET + +NONE: + CALL CHKDIRWRITE + STC +RET4: RET + + +DELETE: ; System call 19 + CALL MOVNAME + MOV AL,-1 + JC RET4 + MOV AL,CS:[ATTRIB] + AND AL,6 ;Look only at hidden bits + CMP AL,6 ;Both must be set + JNZ NOTALL + MOV CX,11 + MOV AL,"?" + MOV DI,OFFSET DOSGROUP:NAME1 + REPE SCASB ;See if name is *.* + JNZ NOTALL + MOV BYTE PTR CS:[DELALL],0 ;DEL *.* - flag deleting all +NOTALL: + CALL FINDNAME + MOV AL,-1 + JC RET4 + OR BH,BH ;Check if device name + JS RET4 ;Can't delete I/O devices +DELFILE: + MOV BYTE PTR [DIRTYDIR],-1 + MOV AH,[DELALL] + MOV BYTE PTR [BX],AH + MOV BX,[SI] + MOV SI,[BP.FAT] + OR BX,BX + JZ DELNXT + CMP BX,[BP.MAXCLUS] + JA DELNXT + CALL RELEASE +DELNXT: + CALL CONTSRCH + JNC DELFILE + CALL FATWRT + CALL CHKDIRWRITE + XOR AL,AL + RET + + +RENAME: ;System call 23 + CALL MOVNAME + JC ERRET + ADD SI,5 + MOV DI,OFFSET DOSGROUP:NAME2 + CALL LODNAME + JC ERRET ;Report error if second name invalid + CALL FINDNAME + JC ERRET + OR BH,BH ;Check if I/O device name + JS ERRET ;If so, can't rename it + MOV SI,OFFSET DOSGROUP:NAME1 + MOV DI,OFFSET DOSGROUP:NAME3 + MOV CX,6 ;6 words (12 bytes)--include attribute byte + REP MOVSW ;Copy name to search for +RENFIL: + MOV DI,OFFSET DOSGROUP:NAME1 + MOV SI,OFFSET DOSGROUP:NAME2 + MOV CX,11 +NEWNAM: + LODSB + CMP AL,"?" + JNZ NOCHG + MOV AL,[BX] +NOCHG: + STOSB + INC BX + LOOP NEWNAM + MOV BYTE PTR [DI],6 ;Stop duplicates with any attributes + CALL DEVNAME ;Check if giving it a device name + JNC RENERR + PUSH [LASTENT] ;Save position of match + MOV [LASTENT],-1 ;Search entire directory for duplicate + CALL CONTSRCH ;See if new name already exists + POP AX + JNC RENERR ;Error if found + CALL GETENT ;Re-read matching entry + MOV DI,BX + MOV SI,OFFSET DOSGROUP:NAME1 + MOV CX,5 + MOVSB + REP MOVSW ;Replace old name with new one + MOV BYTE PTR [DIRTYDIR],-1 ;Flag change in directory + MOV SI,OFFSET DOSGROUP:NAME3 + MOV DI,OFFSET DOSGROUP:NAME1 + MOV CX,6 ;Include attribute byte + REP MOVSW ;Copy name back into search buffer + CALL CONTSRCH + JNC RENFIL + CALL CHKDIRWRITE + XOR AL,AL + RET + +RENERR: + CALL CHKDIRWRITE +ERRET: + MOV AL,-1 +RET5: RET + + +MOVNAME: + +; Inputs: +; DS, DX point to FCB or extended FCB +; Outputs: +; DS:DX point to normal FCB +; ES = CS +; If file name OK: +; BP has base of driver parameters +; [NAME1] has name in upper case +; All registers except DX destroyed +; Carry set if bad file name or drive + + MOV CS:WORD PTR [CREATING],0E500H ;Not creating, not DEL *.* + MOV AX,CS + MOV ES,AX + MOV DI,OFFSET DOSGROUP:NAME1 + MOV SI,DX + LODSB + MOV CS:[EXTFCB],AL ;Set flag if extended FCB in use + MOV AH,0 ;Set default attributes + CMP AL,-1 ;Is it an extended FCB? + JNZ HAVATTRB + ADD DX,7 ;Adjust to point to normal FCB + ADD SI,6 ;Point to drive select byte + MOV AH,[SI-1] ;Get attribute byte + LODSB ;Get drive select byte +HAVATTRB: + MOV CS:[ATTRIB],AH ;Save attributes + CALL GETTHISDRV +LODNAME: +; This entry point copies a file name from DS,SI +; to ES,DI converting to upper case. + CMP BYTE PTR [SI]," " ;Don't allow blank as first letter + STC ;In case of error + JZ RET5 + MOV CX,11 +MOVCHK: + CALL GETLET + JB RET5 + JNZ STOLET ;Is it a delimiter? + CMP AL," " ;This is the only delimiter allowed + STC ;In case of error + JNZ RET5 +STOLET: + STOSB + LOOP MOVCHK + CLC ;Got through whole name - no error +RET6: RET + +GETTHISDRV: + CMP CS:[NUMDRV],AL + JC RET6 + DEC AL + JNS PHYDRV + MOV AL,CS:[CURDRV] +PHYDRV: + MOV CS:[THISDRV],AL + RET + + +OPEN: ;System call 15 + CALL GETFILE +DOOPEN: +; Enter here to perform OPEN on file already found +; in directory. DS=CS, BX points to directory +; entry in DIRBUF, SI points to First Cluster field, and +; ES:DI point to the FCB to be opened. This entry point +; is used by CREATE. + JC ERRET + OR BH,BH ;Check if file is I/O device + JS OPENDEV ;Special handler if so + MOV AL,[THISDRV] + INC AX + STOSB + XOR AX,AX + IF ZEROEXT + ADD DI,11 + STOSW ;Zero low byte of extent field if IBM only + ENDIF + IF NOT ZEROEXT + ADD DI,12 ;Point to high half of CURRENT BLOCK field + STOSB ;Set it to zero (CP/M programs set low byte) + ENDIF + MOV AL,128 ;Default record size + STOSW ;Set record size + LODSW ;Get starting cluster + MOV DX,AX ;Save it for the moment + MOVSW ;Transfer size to FCB + MOVSW + MOV AX,[SI-8] ;Get date + STOSW ;Save date in FCB + MOV AX,[SI-10] ;Get time + STOSW ;Save it in FCB + MOV AL,[BP.DEVNUM] + OR AL,40H + STOSB + MOV AX,DX ;Restore starting cluster + STOSW ; first cluster + STOSW ; last cluster accessed + XOR AX,AX + STOSW ; position of last cluster + RET + + +OPENDEV: + ADD DI,13 ;point to 2nd half of extent field + XOR AX,AX + STOSB ;Set it to zero + MOV AL,128 + STOSW ;Set record size to 128 + XOR AX,AX + STOSW + STOSW ;Set current size to zero + CALL DATE16 + STOSW ;Date is todays + XCHG AX,DX + STOSW ;Use current time + MOV AL,BH ;Get device number + STOSB + XOR AL,AL ;No error + RET +FATERR: + XCHG AX,DI ;Put error code in DI + MOV AH,2 ;While trying to read FAT + MOV AL,[THISDRV] ;Tell which drive + CALL FATAL1 + JMP SHORT FATREAD +STARTSRCH: + MOV AX,-1 + MOV [LASTENT],AX + MOV [ENTFREE],AX +FATREAD: + +; Inputs: +; DS = CS +; Function: +; If disk may have been changed, FAT is read in and buffers are +; flagged invalid. If not, no action is taken. +; Outputs: +; BP = Base of drive parameters +; Carry set if invalid drive returned by MAPDEV +; All other registers destroyed + + MOV AL,[THISDRV] + XOR AH,AH ;Set default response to zero & clear carry + CALL FAR PTR BIOSDSKCHG ;See what BIOS has to say + JC FATERR + CALL GETBP + MOV AL,[THISDRV] ;Use physical unit number + MOV SI,[BP.FAT] + OR AH,[SI-1] ;Dirty byte for FAT + JS NEWDSK ;If either say new disk, then it's so + JNZ MAPDRV + MOV AH,1 + CMP AX,WORD PTR [BUFDRVNO] ;Does buffer have dirty sector of this drive? + JZ MAPDRV +NEWDSK: + CMP AL,[BUFDRVNO] ;See if buffer is for this drive + JNZ BUFOK ;If not, don't touch it + MOV [BUFSECNO],0 ;Flag buffers invalid + MOV WORD PTR [BUFDRVNO],00FFH +BUFOK: + MOV [DIRBUFID],-1 + CALL FIGFAT +NEXTFAT: + PUSH AX + CALL DSKREAD + POP AX + JC BADFAT + SUB AL,[BP.FATCNT] + JZ NEWFAT + CALL FATWRT +NEWFAT: + MOV SI,[BP.FAT] + MOV AL,[BP.DEVNUM] + MOV AH,[SI] ;Get first byte of FAT + OR AH,0F8H ;Put in range + CALL FAR PTR BIOSMAPDEV + MOV AH,0 + MOV [SI-2],AX ;Set device no. and reset dirty bit +MAPDRV: + MOV AL,[SI-2] ;Get device number +GETBP: + MOV BP,[DRVTAB] ;Just in case drive isn't valid + AND AL,3FH ;Mask out dirty bit + CMP AL,[NUMIO] + CMC + JC RET7 + PUSH AX + MOV AH,DPBSIZ + MUL AH + ADD BP,AX + POP AX +RET7: RET + +BADFAT: + MOV CX,DI + ADD DX,CX + DEC AL + JNZ NEXTFAT + CALL FIGFAT ;Reset registers + CALL DREAD ;Try first FAT once more + JMP SHORT NEWFAT + +OKRET1: + MOV AL,0 + RET + +CLOSE: ;System call 16 + MOV DI,DX + CMP BYTE PTR [DI],-1 ;Check for extended FCB + JNZ NORMFCB3 + ADD DI,7 +NORMFCB3: + TEST BYTE PTR [DI.DEVID],0C0H ;Allow only dirty files + JNZ OKRET1 ;can't close if I/O device, or not writen + MOV AL,[DI] ;Get physical unit number + DEC AL ;Make zero = drive A + MOV AH,1 ;Look for dirty buffer + CMP AX,CS:WORD PTR [BUFDRVNO] + JNZ FNDDIR +;Write back dirty buffer if on same drive + PUSH DX + PUSH DS + PUSH CS + POP DS + MOV BYTE PTR [DIRTYBUF],0 + MOV BX,[BUFFER] + MOV CX,1 + MOV DX,[BUFSECNO] + MOV BP,[BUFDRVBP] + CALL DWRITE + POP DS + POP DX +FNDDIR: + CALL GETFILE +BADCLOSEJ: + JC BADCLOSE + MOV CX,ES:[DI.FIRCLUS] + MOV [SI],CX + MOV DX,ES:WORD PTR [DI.FILSIZ] + MOV [SI+2],DX + MOV DX,ES:WORD PTR [DI.FILSIZ+2] + MOV [SI+4],DX + MOV DX,ES:[DI.FDATE] + MOV [SI-2],DX + MOV DX,ES:[DI.FTIME] + MOV [SI-4],DX + CALL DIRWRITE + +CHKFATWRT: +; Do FATWRT only if FAT is dirty and uses same I/O driver + MOV SI,[BP.FAT] + MOV AL,[BP.DEVNUM] + MOV AH,1 + CMP [SI-2],AX ;See if FAT dirty and uses same driver + JNZ OKRET + +FATWRT: + +; Inputs: +; DS = CS +; BP = Base of drive parameter table +; Function: +; Write the FAT back to disk and reset FAT +; dirty bit. +; Outputs: +; AL = 0 +; BP unchanged +; All other registers destroyed + + CALL FIGFAT + MOV BYTE PTR [BX-1],0 +EACHFAT: + PUSH DX + PUSH CX + PUSH BX + PUSH AX + CALL DWRITE + POP AX + POP BX + POP CX + POP DX + ADD DX,CX + DEC AL + JNZ EACHFAT +OKRET: + MOV AL,0 + RET + +BADCLOSE: + MOV SI,[BP.FAT] + MOV BYTE PTR [SI-1],0 + MOV AL,-1 + RET + + +FIGFAT: +; Loads registers with values needed to read or +; write a FAT. + MOV AL,[BP.FATCNT] + MOV BX,[BP.FAT] + MOV CL,[BP.FATSIZ] ;No. of records occupied by FAT + MOV CH,0 + MOV DX,[BP.FIRFAT] ;Record number of start of FATs + RET + + +DIRCOMP: +; Prepare registers for directory read or write + CBW + ADD AX,[BP.FIRDIR] + MOV DX,AX + MOV BX,OFFSET DOSGROUP:DIRBUF + MOV CX,1 + RET + + +CREATE: ;System call 22 + CALL MOVNAME + JC ERRET3 + MOV DI,OFFSET DOSGROUP:NAME1 + MOV CX,11 + MOV AL,"?" + REPNE SCASB + JZ ERRET3 + MOV CS:BYTE PTR [CREATING],-1 + PUSH DX + PUSH DS + CALL FINDNAME + JNC EXISTENT + MOV AX,[ENTFREE] ;First free entry found in FINDNAME + CMP AX,-1 + JZ ERRPOP + CALL GETENT ;Point at that free entry + JMP SHORT FREESPOT +ERRPOP: + POP DS + POP DX +ERRET3: + MOV AL,-1 + RET + +EXISTENT: + JNZ ERRPOP ;Error if attributes don't match + OR BH,BH ;Check if file is I/O device + JS OPENJMP ;If so, no action + MOV CX,[SI] ;Get pointer to clusters + JCXZ FREESPOT + CMP CX,[BP.MAXCLUS] + JA FREESPOT + PUSH BX + MOV BX,CX + MOV SI,[BP.FAT] + CALL RELEASE ;Free any data already allocated + CALL FATWRT + POP BX +FREESPOT: + MOV DI,BX + MOV SI,OFFSET DOSGROUP:NAME1 + MOV CX,5 + MOVSB + REP MOVSW + MOV AL,[ATTRIB] + STOSB + XOR AX,AX + MOV CL,5 + REP STOSW + CALL DATE16 + XCHG AX,DX + STOSW + XCHG AX,DX + STOSW + XOR AX,AX + PUSH DI + MOV CL,6 +SMALLENT: + REP STOSB + PUSH BX + CALL DIRWRITE + POP BX + POP SI +OPENJMP: + CLC ;Clear carry so OPEN won't fail + POP ES + POP DI + JMP DOOPEN + + +DIRREAD: + +; Inputs: +; DS = CS +; AL = Directory block number +; BP = Base of drive parameters +; Function: +; Read the directory block into DIRBUF. +; Outputs: +; AX,BP unchanged +; All other registers destroyed. + + PUSH AX + CALL CHKDIRWRITE + POP AX + PUSH AX + MOV AH,[BP.DEVNUM] + MOV [DIRBUFID],AX + CALL DIRCOMP + CALL DREAD + POP AX +RET8: RET + + +DREAD: + +; Inputs: +; BX,DS = Transfer address +; CX = Number of sectors +; DX = Absolute record number +; BP = Base of drive parameters +; Function: +; Calls BIOS to perform disk read. If BIOS reports +; errors, will call HARDERR for further action. +; BP preserved. All other registers destroyed. + + CALL DSKREAD + JNC RET8 + MOV CS:BYTE PTR [READOP],0 + CALL HARDERR + CMP AL,1 ;Check for retry + JZ DREAD + RET ;Ignore otherwise + + +HARDERR: + +;Hard disk error handler. Entry conditions: +; DS:BX = Original disk transfer address +; DX = Original logical sector number +; CX = Number of sectors to go (first one gave the error) +; AX = Hardware error code +; DI = Original sector transfer count +; BP = Base of drive parameters +; [READOP] = 0 for read, 1 for write + + XCHG AX,DI ;Error code in DI, count in AX + SUB AX,CX ;Number of sectors successfully transferred + ADD DX,AX ;First sector number to retry + PUSH DX + MUL [BP.SECSIZ] ;Number of bytes transferred + POP DX + ADD BX,AX ;First address for retry + MOV AH,0 ;Flag disk section in error + CMP DX,[BP.FIRFAT] ;In reserved area? + JB ERRINT + INC AH ;Flag for FAT + CMP DX,[BP.FIRDIR] ;In FAT? + JB ERRINT + INC AH + CMP DX,[BP.FIRREC] ;In directory? + JB ERRINT + INC AH ;Must be in data area +ERRINT: + SHL AH,1 ;Make room for read/write bit + OR AH,CS:[READOP] +FATAL: + MOV AL,[BP.DRVNUM] ;Get drive number +FATAL1: + PUSH BP ;The only thing we preserve + MOV CS:[CONTSTK],SP + CLI ;Prepare to play with stack + MOV SS,CS:[SSSAVE] + MOV SP,CS:[SPSAVE] ;User stack pointer restored + INT 24H ;Fatal error interrupt vector + MOV CS:[SPSAVE],SP + MOV CS:[SSSAVE],SS + MOV SP,CS + MOV SS,SP + MOV SP,CS:[CONTSTK] + STI + POP BP + CMP AL,2 + JZ ERROR + RET + +DSKREAD: + MOV AL,[BP.DEVNUM] + PUSH BP + PUSH BX + PUSH CX + PUSH DX + CALL FAR PTR BIOSREAD + POP DX + POP DI + POP BX + POP BP +RET9: RET + + +CHKDIRWRITE: + TEST BYTE PTR [DIRTYDIR],-1 + JZ RET9 + +DIRWRITE: + +; Inputs: +; DS = CS +; AL = Directory block number +; BP = Base of drive parameters +; Function: +; Write the directory block into DIRBUF. +; Outputs: +; BP unchanged +; All other registers destroyed. + + MOV BYTE PTR [DIRTYDIR],0 + MOV AL,BYTE PTR [DIRBUFID] + CALL DIRCOMP + + +DWRITE: + +; Inputs: +; BX,DS = Transfer address +; CX = Number of sectors +; DX = Absolute record number +; BP = Base of drive parameters +; Function: +; Calls BIOS to perform disk write. If BIOS reports +; errors, will call HARDERR for further action. +; BP preserved. All other registers destroyed. + + MOV AL,[BP.DEVNUM] + MOV AH,CS:VERFLG + PUSH BP + PUSH BX + PUSH CX + PUSH DX + CALL FAR PTR BIOSWRITE + POP DX + POP DI + POP BX + POP BP + JNC RET9 + MOV CS:BYTE PTR [READOP],1 + CALL HARDERR + CMP AL,1 ;Check for retry + JZ DWRITE + RET + + +ABORT: + LDS SI,CS:DWORD PTR [SPSAVE] + MOV DS,[SI.CSSAVE] + XOR AX,AX + MOV ES,AX + MOV SI,SAVEXIT + MOV DI,EXIT + MOVSW + MOVSW + MOVSW + MOVSW + MOVSW + MOVSW +ERROR: + MOV AX,CS + MOV DS,AX + MOV ES,AX + CALL WRTFATS + XOR AX,AX + CLI + MOV SS,[SSSAVE] + MOV SP,[SPSAVE] + MOV DS,AX + MOV SI,EXIT + MOV DI,OFFSET DOSGROUP:EXITHOLD + MOVSW + MOVSW + POP AX + POP BX + POP CX + POP DX + POP SI + POP DI + POP BP + POP DS + POP ES + STI ;Stack OK now + JMP CS:DWORD PTR [EXITHOLD] + + +SEQRD: ;System call 20 + CALL GETREC + CALL LOAD + JMP SHORT FINSEQ + +SEQWRT: ;System call 21 + CALL GETREC + CALL STORE +FINSEQ: + JCXZ SETNREX + ADD AX,1 + ADC DX,0 + JMP SHORT SETNREX + +RNDRD: ;System call 33 + CALL GETRRPOS1 + CALL LOAD + JMP SHORT FINRND + +RNDWRT: ;System call 34 + CALL GETRRPOS1 + CALL STORE + JMP SHORT FINRND + +BLKRD: ;System call 39 + CALL GETRRPOS + CALL LOAD + JMP SHORT FINBLK + +BLKWRT: ;System call 40 + CALL GETRRPOS + CALL STORE +FINBLK: + LDS SI,DWORD PTR [SPSAVE] + MOV [SI.CXSAVE],CX + JCXZ FINRND + ADD AX,1 + ADC DX,0 +FINRND: + MOV ES:WORD PTR [DI.RR],AX + MOV ES:[DI.RR+2],DL + OR DH,DH + JZ SETNREX + MOV ES:[DI.RR+3],DH ;Save 4 byte of RECPOS only if significant +SETNREX: + MOV CX,AX + AND AL,7FH + MOV ES:[DI.NR],AL + AND CL,80H + SHL CX,1 + RCL DX,1 + MOV AL,CH + MOV AH,DL + MOV ES:[DI.EXTENT],AX + MOV AL,CS:[DSKERR] + RET + +GETRRPOS1: + MOV CX,1 +GETRRPOS: + MOV DI,DX + CMP BYTE PTR [DI],-1 + JNZ NORMFCB1 + ADD DI,7 +NORMFCB1: + MOV AX,WORD PTR [DI.RR] + MOV DX,WORD PTR [DI.RR+2] + RET + +NOFILERR: + XOR CX,CX + MOV BYTE PTR [DSKERR],4 + POP BX + RET + +SETUP: + +; Inputs: +; DS:DI point to FCB +; DX:AX = Record position in file of disk transfer +; CX = Record count +; Outputs: +; DS = CS +; ES:DI point to FCB +; BL = DEVID from FCB +; CX = No. of bytes to transfer +; BP = Base of drive parameters +; SI = FAT pointer +; [RECCNT] = Record count +; [RECPOS] = Record position in file +; [FCB] = DI +; [NEXTADD] = Displacement of disk transfer within segment +; [SECPOS] = Position of first sector +; [BYTPOS] = Byte position in file +; [BYTSECPOS] = Byte position in first sector +; [CLUSNUM] = First cluster +; [SECCLUSPOS] = Sector within first cluster +; [DSKERR] = 0 (no errors yet) +; [TRANS] = 0 (No transfers yet) +; [THISDRV] = Physical drive unit number +; If SETUP detects no records will be transfered, it returns 1 level up +; with CX = 0. + + PUSH AX + MOV AL,[DI] + DEC AL + MOV CS:[THISDRV],AL + MOV AL,[DI.DEVID] + MOV SI,[DI.RECSIZ] + OR SI,SI + JNZ HAVRECSIZ + MOV SI,128 + MOV [DI.RECSIZ],SI +HAVRECSIZ: + PUSH DS + POP ES ;Set ES to DS + PUSH CS + POP DS ;Set DS to CS + OR AL,AL ;Is it a device? + JNS NOTDEVICE + MOV AL,0 ;Fake in drive 0 so we can get SP +NOTDEVICE: + CALL GETBP + POP AX + JC NOFILERR + CMP SI,64 ;Check if highest byte of RECPOS is significant + JB SMALREC + MOV DH,0 ;Ignore MSB if record >= 64 bytes +SMALREC: + MOV [RECCNT],CX + MOV WORD PTR [RECPOS],AX + MOV WORD PTR [RECPOS+2],DX + MOV [FCB],DI + MOV BX,[DMAADD] + MOV [NEXTADD],BX + MOV BYTE PTR [DSKERR],0 + MOV BYTE PTR [TRANS],0 + MOV BX,DX + MUL SI + MOV WORD PTR [BYTPOS],AX + PUSH DX + MOV AX,BX + MUL SI + POP BX + ADD AX,BX + ADC DX,0 ;Ripple carry + JNZ EOFERR + MOV WORD PTR [BYTPOS+2],AX + MOV DX,AX + MOV AX,WORD PTR [BYTPOS] + MOV BX,[BP.SECSIZ] + CMP DX,BX ;See if divide will overflow + JNC EOFERR + DIV BX + MOV [SECPOS],AX + MOV [BYTSECPOS],DX + MOV DX,AX + AND AL,[BP.CLUSMSK] + MOV [SECCLUSPOS],AL + MOV AX,CX ;Record count + MOV CL,[BP.CLUSSHFT] + SHR DX,CL + MOV [CLUSNUM],DX + MUL SI ;Multiply by bytes per record + MOV CX,AX + ADD AX,[DMAADD] ;See if it will fit in one segment + ADC DX,0 + JZ OK ;Must be less than 64K + MOV AX,[DMAADD] + NEG AX ;Amount of room left in segment + JNZ PARTSEG ;All 64K available? + DEC AX ;If so, reduce by one +PARTSEG: + XOR DX,DX + DIV SI ;How many records will fit? + MOV [RECCNT],AX + MUL SI ;Translate that back into bytes + MOV BYTE PTR [DSKERR],2 ;Flag that trimming took place + MOV CX,AX + JCXZ NOROOM +OK: + MOV BL,ES:[DI.DEVID] + MOV SI,[BP.FAT] + RET + +EOFERR: + MOV BYTE PTR [DSKERR],1 + XOR CX,CX +NOROOM: + POP BX ;Kill return address + RET + +BREAKDOWN: + +;Inputs: +; DS = CS +; CX = Length of disk transfer in bytes +; BP = Base of drive parameters +; [BYTSECPOS] = Byte position witin first sector +;Outputs: +; [BYTCNT1] = Bytes to transfer in first sector +; [SECCNT] = No. of whole sectors to transfer +; [BYTCNT2] = Bytes to transfer in last sector +;AX, BX, DX destroyed. No other registers affected. + + MOV AX,[BYTSECPOS] + MOV BX,CX + OR AX,AX + JZ SAVFIR ;Partial first sector? + SUB AX,[BP.SECSIZ] + NEG AX ;Max number of bytes left in first sector + SUB BX,AX ;Subtract from total length + JAE SAVFIR + ADD AX,BX ;Don't use all of the rest of the sector + XOR BX,BX ;And no bytes are left +SAVFIR: + MOV [BYTCNT1],AX + MOV AX,BX + XOR DX,DX + DIV [BP.SECSIZ] ;How many whole sectors? + MOV [SECCNT],AX + MOV [BYTCNT2],DX ;Bytes remaining for last sector +RET10: RET + + +FNDCLUS: + +; Inputs: +; DS = CS +; CX = No. of clusters to skip +; BP = Base of drive parameters +; SI = FAT pointer +; ES:DI point to FCB +; Outputs: +; BX = Last cluster skipped to +; CX = No. of clusters remaining (0 unless EOF) +; DX = Position of last cluster +; DI destroyed. No other registers affected. + + MOV BX,ES:[DI.LSTCLUS] + MOV DX,ES:[DI.CLUSPOS] + OR BX,BX + JZ NOCLUS + SUB CX,DX + JNB FINDIT + ADD CX,DX + XOR DX,DX + MOV BX,ES:[DI.FIRCLUS] +FINDIT: + JCXZ RET10 +SKPCLP: + CALL UNPACK + CMP DI,0FF8H + JAE RET10 + XCHG BX,DI + INC DX + LOOP SKPCLP + RET +NOCLUS: + INC CX + DEC DX + RET + + +BUFSEC: +; Inputs: +; AL = 0 if buffer must be read, 1 if no pre-read needed +; BP = Base of drive parameters +; [CLUSNUM] = Physical cluster number +; [SECCLUSPOS] = Sector position of transfer within cluster +; [BYTCNT1] = Size of transfer +; Function: +; Insure specified sector is in buffer, flushing buffer before +; read if necessary. +; Outputs: +; SI = Pointer to buffer +; DI = Pointer to transfer address +; CX = Number of bytes +; [NEXTADD] updated +; [TRANS] set to indicate a transfer will occur + + MOV DX,[CLUSNUM] + MOV BL,[SECCLUSPOS] + CALL FIGREC + MOV [PREREAD],AL + CMP DX,[BUFSECNO] + JNZ GETSEC + MOV AL,[BUFDRVNO] + CMP AL,[THISDRV] + JZ FINBUF ;Already have it? +GETSEC: + XOR AL,AL + XCHG [DIRTYBUF],AL ;Read dirty flag and reset it + OR AL,AL + JZ RDSEC + PUSH DX + PUSH BP + MOV BP,[BUFDRVBP] + MOV BX,[BUFFER] + MOV CX,1 + MOV DX,[BUFSECNO] + CALL DWRITE + POP BP + POP DX +RDSEC: + TEST BYTE PTR [PREREAD],-1 + JNZ SETBUF + XOR AX,AX + MOV [BUFSECNO],AX ;Set buffer valid in case of disk error + DEC AX + MOV [BUFDRVNO],AL + MOV BX,[BUFFER] + MOV CX,1 + PUSH DX + CALL DREAD + POP DX +SETBUF: + MOV [BUFSECNO],DX + MOV AL,[THISDRV] + MOV [BUFDRVNO],AL + MOV [BUFDRVBP],BP +FINBUF: + MOV BYTE PTR [TRANS],1 ;A transfer is taking place + MOV DI,[NEXTADD] + MOV SI,DI + MOV CX,[BYTCNT1] + ADD SI,CX + MOV [NEXTADD],SI + MOV SI,[BUFFER] + ADD SI,[BYTSECPOS] + RET + +BUFRD: + XOR AL,AL ;Pre-read necessary + CALL BUFSEC + PUSH ES + MOV ES,[DMAADD+2] + SHR CX,1 + JNC EVENRD + MOVSB +EVENRD: + REP MOVSW + POP ES + RET + +BUFWRT: + MOV AX,[SECPOS] + INC AX ;Set for next sector + MOV [SECPOS],AX + CMP AX,[VALSEC] ;Has sector been written before? + MOV AL,1 + JA NOREAD ;Skip preread if SECPOS>VALSEC + MOV AL,0 +NOREAD: + CALL BUFSEC + XCHG DI,SI + PUSH DS + PUSH ES + PUSH CS + POP ES + MOV DS,[DMAADD+2] + SHR CX,1 + JNC EVENWRT + MOVSB +EVENWRT: + REP MOVSW + POP ES + POP DS + MOV BYTE PTR [DIRTYBUF],1 + RET + +NEXTSEC: + TEST BYTE PTR [TRANS],-1 + JZ CLRET + MOV AL,[SECCLUSPOS] + INC AL + CMP AL,[BP.CLUSMSK] + JBE SAVPOS + MOV BX,[CLUSNUM] + CMP BX,0FF8H + JAE NONEXT + MOV SI,[BP.FAT] + CALL UNPACK + MOV [CLUSNUM],DI + INC [LASTPOS] + MOV AL,0 +SAVPOS: + MOV [SECCLUSPOS],AL +CLRET: + CLC + RET +NONEXT: + STC + RET + +TRANBUF: + LODSB + STOSB + CMP AL,13 ;Check for carriage return + JNZ NORMCH + MOV BYTE PTR [SI],10 +NORMCH: + CMP AL,10 + LOOPNZ TRANBUF + JNZ ENDRDCON + CALL OUT ;Transmit linefeed + XOR SI,SI + OR CX,CX + JNZ GETBUF + OR AL,1 ;Clear zero flag--not end of file +ENDRDCON: + MOV [CONTPOS],SI +ENDRDDEV: + MOV [NEXTADD],DI + POP ES + JNZ SETFCBJ ;Zero set if Ctrl-Z found in input + MOV DI,[FCB] + AND ES:BYTE PTR [DI.DEVID],0FFH-40H ;Mark as no more data available +SETFCBJ: + JMP SETFCB + +READDEV: + PUSH ES + LES DI,DWORD PTR [DMAADD] + INC BL + JZ READCON + INC BL + JNZ ENDRDDEV +READAUX: + CALL AUXIN + STOSB + CMP AL,1AH + LOOPNZ READAUX + JMP SHORT ENDRDDEV + +READCON: + PUSH CS + POP DS + MOV SI,[CONTPOS] + OR SI,SI + JNZ TRANBUF + CMP BYTE PTR [CONBUF],128 + JZ GETBUF + MOV WORD PTR [CONBUF],0FF80H ;Set up 128-byte buffer with no template +GETBUF: + PUSH CX + PUSH ES + PUSH DI + MOV DX,OFFSET DOSGROUP:CONBUF + CALL BUFIN ;Get input buffer + POP DI + POP ES + POP CX + MOV SI,2 + OFFSET DOSGROUP:CONBUF + CMP BYTE PTR [SI],1AH ;Check for Ctrl-Z in first character + JNZ TRANBUF + MOV AL,1AH + STOSB + MOV AL,10 + CALL OUT ;Send linefeed + XOR SI,SI + JMP SHORT ENDRDCON + +RDERR: + XOR CX,CX + JMP WRTERR + +RDLASTJ:JMP RDLAST + +LOAD: + +; Inputs: +; DS:DI point to FCB +; DX:AX = Position in file to read +; CX = No. of records to read +; Outputs: +; DX:AX = Position of last record read +; CX = No. of bytes read +; ES:DI point to FCB +; LSTCLUS, CLUSPOS fields in FCB set + + CALL SETUP + OR BL,BL ;Check for named device I/O + JS READDEV + MOV AX,ES:WORD PTR [DI.FILSIZ] + MOV BX,ES:WORD PTR [DI.FILSIZ+2] + SUB AX,WORD PTR [BYTPOS] + SBB BX,WORD PTR [BYTPOS+2] + JB RDERR + JNZ ENUF + OR AX,AX + JZ RDERR + CMP AX,CX + JAE ENUF + MOV CX,AX +ENUF: + CALL BREAKDOWN + MOV CX,[CLUSNUM] + CALL FNDCLUS + OR CX,CX + JNZ RDERR + MOV [LASTPOS],DX + MOV [CLUSNUM],BX + CMP [BYTCNT1],0 + JZ RDMID + CALL BUFRD +RDMID: + CMP [SECCNT],0 + JZ RDLASTJ + CALL NEXTSEC + JC SETFCB + MOV BYTE PTR [TRANS],1 ;A transfer is taking place +ONSEC: + MOV DL,[SECCLUSPOS] + MOV CX,[SECCNT] + MOV BX,[CLUSNUM] +RDLP: + CALL OPTIMIZE + PUSH DI + PUSH AX + PUSH DS + MOV DS,[DMAADD+2] + PUSH DX + PUSH BX + PUSHF ;Save carry flag + CALL DREAD + POPF ;Restore carry flag + POP DI ;Initial transfer address + POP AX ;First sector transfered + POP DS + JC NOTBUFFED ;Was one of those sectors in the buffer? + CMP BYTE PTR [DIRTYBUF],0 ;Is buffer dirty? + JZ NOTBUFFED ;If not no problem +;We have transfered in a sector from disk when a dirty copy of it is in the buffer. +;We must transfer the sector from the buffer to correct memory address + SUB AX,[BUFSECNO] ;How many sectors into the transfer? + NEG AX + MOV CX,[BP.SECSIZ] + MUL CX ;How many bytes into the transfer? + ADD DI,AX + MOV SI,[BUFFER] + PUSH ES + MOV ES,[DMAADD+2] ;Get disk transfer segment + SHR CX,1 + REP MOVSW + JNC EVENMOV + MOVSB +EVENMOV: + POP ES +NOTBUFFED: + POP CX + POP BX + JCXZ RDLAST + CMP BX,0FF8H + JAE SETFCB + MOV DL,0 + INC [LASTPOS] ;We'll be using next cluster + JMP SHORT RDLP + +SETFCB: + MOV SI,[FCB] + MOV AX,[NEXTADD] + MOV DI,AX + SUB AX,[DMAADD] ;Number of bytes transfered + XOR DX,DX + MOV CX,ES:[SI.RECSIZ] + DIV CX ;Number of records + CMP AX,[RECCNT] ;Check if all records transferred + JZ FULLREC + MOV BYTE PTR [DSKERR],1 + OR DX,DX + JZ FULLREC ;If remainder 0, then full record transfered + MOV BYTE PTR [DSKERR],3 ;Flag partial last record + SUB CX,DX ;Bytes left in last record + PUSH ES + MOV ES,[DMAADD+2] + XCHG AX,BX ;Save the record count temporarily + XOR AX,AX ;Fill with zeros + SHR CX,1 + JNC EVENFIL + STOSB +EVENFIL: + REP STOSW + XCHG AX,BX ;Restore record count to AX + POP ES + INC AX ;Add last (partial) record to total +FULLREC: + MOV CX,AX + MOV DI,SI ;ES:DI point to FCB +SETCLUS: + MOV AX,[CLUSNUM] + MOV ES:[DI.LSTCLUS],AX + MOV AX,[LASTPOS] + MOV ES:[DI.CLUSPOS],AX +ADDREC: + MOV AX,WORD PTR [RECPOS] + MOV DX,WORD PTR [RECPOS+2] + JCXZ RET28 ;If no records read, don't change position + DEC CX + ADD AX,CX ;Update current record position + ADC DX,0 + INC CX +RET28: RET + +RDLAST: + MOV AX,[BYTCNT2] + OR AX,AX + JZ SETFCB + MOV [BYTCNT1],AX + CALL NEXTSEC + JC SETFCB + MOV [BYTSECPOS],0 + CALL BUFRD + JMP SHORT SETFCB + +WRTDEV: + PUSH DS + LDS SI,DWORD PTR [DMAADD] + OR BL,40H + INC BL + JZ WRTCON + INC BL + JZ WRTAUX + INC BL + JZ ENDWRDEV ;Done if device is NUL +WRTLST: + LODSB + CMP AL,1AH + JZ ENDWRDEV + CALL LISTOUT + LOOP WRTLST + JMP SHORT ENDWRDEV + +WRTAUX: + LODSB + CALL AUXOUT + CMP AL,1AH + LOOPNZ WRTAUX + JMP SHORT ENDWRDEV + +WRTCON: + LODSB + CMP AL,1AH + JZ ENDWRDEV + CALL OUT + LOOP WRTCON +ENDWRDEV: + POP DS + MOV CX,[RECCNT] + MOV DI,[FCB] + JMP SHORT ADDREC + +HAVSTART: + MOV CX,AX + CALL SKPCLP + JCXZ DOWRTJ + CALL ALLOCATE + JNC DOWRTJ +WRTERR: + MOV BYTE PTR [DSKERR],1 +LVDSK: + MOV AX,WORD PTR [RECPOS] + MOV DX,WORD PTR [RECPOS+2] + MOV DI,[FCB] + RET + +DOWRTJ: JMP DOWRT + +WRTEOFJ: + JMP WRTEOF + +STORE: + +; Inputs: +; DS:DI point to FCB +; DX:AX = Position in file of disk transfer +; CX = Record count +; Outputs: +; DX:AX = Position of last record written +; CX = No. of records written +; ES:DI point to FCB +; LSTCLUS, CLUSPOS fields in FCB set + + CALL SETUP + CALL DATE16 + MOV ES:[DI.FDATE],AX + MOV ES:[DI.FTIME],DX + OR BL,BL + JS WRTDEV + AND BL,3FH ;Mark file as dirty + MOV ES:[DI.DEVID],BL + CALL BREAKDOWN + MOV AX,WORD PTR [BYTPOS] + MOV DX,WORD PTR [BYTPOS+2] + JCXZ WRTEOFJ + DEC CX + ADD AX,CX + ADC DX,0 ;AX:DX=last byte accessed + DIV [BP.SECSIZ] ;AX=last sector accessed + MOV CL,[BP.CLUSSHFT] + SHR AX,CL ;Last cluster to be accessed + PUSH AX + MOV AX,ES:WORD PTR [DI.FILSIZ] + MOV DX,ES:WORD PTR [DI.FILSIZ+2] + DIV [BP.SECSIZ] + OR DX,DX + JZ NORNDUP + INC AX ;Round up if any remainder +NORNDUP: + MOV [VALSEC],AX ;Number of sectors that have been written + POP AX + MOV CX,[CLUSNUM] ;First cluster accessed + CALL FNDCLUS + MOV [CLUSNUM],BX + MOV [LASTPOS],DX + SUB AX,DX ;Last cluster minus current cluster + JZ DOWRT ;If we have last clus, we must have first + JCXZ HAVSTART ;See if no more data + PUSH CX ;No. of clusters short of first + MOV CX,AX + CALL ALLOCATE + POP AX + JC WRTERR + MOV CX,AX + MOV DX,[LASTPOS] + INC DX + DEC CX + JZ NOSKIP + CALL SKPCLP +NOSKIP: + MOV [CLUSNUM],BX + MOV [LASTPOS],DX +DOWRT: + CMP [BYTCNT1],0 + JZ WRTMID + MOV BX,[CLUSNUM] + CALL BUFWRT +WRTMID: + MOV AX,[SECCNT] + OR AX,AX + JZ WRTLAST + ADD [SECPOS],AX + CALL NEXTSEC + MOV BYTE PTR [TRANS],1 ;A transfer is taking place + MOV DL,[SECCLUSPOS] + MOV BX,[CLUSNUM] + MOV CX,[SECCNT] +WRTLP: + CALL OPTIMIZE + JC NOTINBUF ;Is one of the sectors buffered? + MOV [BUFSECNO],0 ;If so, invalidate the buffer since we're + MOV WORD PTR [BUFDRVNO],0FFH ; completely rewritting it +NOTINBUF: + PUSH DI + PUSH AX + PUSH DS + MOV DS,[DMAADD+2] + CALL DWRITE + POP DS + POP CX + POP BX + JCXZ WRTLAST + MOV DL,0 + INC [LASTPOS] ;We'll be using next cluster + JMP SHORT WRTLP +WRTLAST: + MOV AX,[BYTCNT2] + OR AX,AX + JZ FINWRT + MOV [BYTCNT1],AX + CALL NEXTSEC + MOV [BYTSECPOS],0 + CALL BUFWRT +FINWRT: + MOV AX,[NEXTADD] + SUB AX,[DMAADD] + ADD AX,WORD PTR [BYTPOS] + MOV DX,WORD PTR [BYTPOS+2] + ADC DX,0 + MOV CX,DX + MOV DI,[FCB] + CMP AX,ES:WORD PTR [DI.FILSIZ] + SBB CX,ES:WORD PTR [DI.FILSIZ+2] + JB SAMSIZ + MOV ES:WORD PTR [DI.FILSIZ],AX + MOV ES:WORD PTR [DI.FILSIZ+2],DX +SAMSIZ: + MOV CX,[RECCNT] + JMP SETCLUS + + +WRTERRJ:JMP WRTERR + +WRTEOF: + MOV CX,AX + OR CX,DX + JZ KILLFIL + SUB AX,1 + SBB DX,0 + DIV [BP.SECSIZ] + MOV CL,[BP.CLUSSHFT] + SHR AX,CL + MOV CX,AX + CALL FNDCLUS + JCXZ RELFILE + CALL ALLOCATE + JC WRTERRJ +UPDATE: + MOV DI,[FCB] + MOV AX,WORD PTR [BYTPOS] + MOV ES:WORD PTR [DI.FILSIZ],AX + MOV AX,WORD PTR [BYTPOS+2] + MOV ES:WORD PTR [DI.FILSIZ+2],AX + XOR CX,CX + JMP ADDREC + +RELFILE: + MOV DX,0FFFH + CALL RELBLKS +SETDIRT: + MOV BYTE PTR [SI-1],1 + JMP SHORT UPDATE + +KILLFIL: + XOR BX,BX + XCHG BX,ES:[DI.FIRCLUS] + OR BX,BX + JZ UPDATE + CALL RELEASE + JMP SHORT SETDIRT + + +OPTIMIZE: + +; Inputs: +; DS = CS +; BX = Physical cluster +; CX = No. of records +; DL = sector within cluster +; BP = Base of drives parameters +; [NEXTADD] = transfer address +; Outputs: +; AX = No. of records remaining +; BX = Transfer address +; CX = No. or records to be transferred +; DX = Physical sector address +; DI = Next cluster +; Carry clear if a sector to transfer is in the buffer +; Carry set otherwise +; [CLUSNUM] = Last cluster accessed +; [NEXTADD] updated +; BP unchanged. Note that segment of transfer not set. + + PUSH DX + PUSH BX + MOV AL,[BP.CLUSMSK] + INC AL ;Number of sectors per cluster + MOV AH,AL + SUB AL,DL ;AL = Number of sectors left in first cluster + MOV DX,CX + MOV SI,[BP.FAT] + MOV CX,0 +OPTCLUS: +;AL has number of sectors available in current cluster +;AH has number of sectors available in next cluster +;BX has current physical cluster +;CX has number of sequential sectors found so far +;DX has number of sectors left to transfer +;SI has FAT pointer + CALL UNPACK + ADD CL,AL + ADC CH,0 + CMP CX,DX + JAE BLKDON + MOV AL,AH + INC BX + CMP DI,BX + JZ OPTCLUS + DEC BX +FINCLUS: + MOV [CLUSNUM],BX ;Last cluster accessed + SUB DX,CX ;Number of sectors still needed + PUSH DX + MOV AX,CX + MUL [BP.SECSIZ] ;Number of sectors times sector size + MOV SI,[NEXTADD] + ADD AX,SI ;Adjust by size of transfer + MOV [NEXTADD],AX + POP AX ;Number of sectors still needed + POP DX ;Starting cluster + SUB BX,DX ;Number of new clusters accessed + ADD [LASTPOS],BX + POP BX ;BL = sector postion within cluster + CALL FIGREC + MOV BX,SI +;Now let's see if any of these sectors are already in the buffer + CMP [BUFSECNO],DX + JC RET100 ;If DX > [BUFSECNO] then not in buffer + MOV SI,DX + ADD SI,CX ;Last sector + 1 + CMP [BUFSECNO],SI + CMC + JC RET100 ;If SI <= [BUFSECNO] then not in buffer + PUSH AX + MOV AL,[BP.DEVNUM] + CMP AL,[BUFDRVNO] ;Is buffer for this drive? + POP AX + JZ RET100 ;If so, then we match + STC ;No match +RET100: RET +BLKDON: + SUB CX,DX ;Number of sectors in cluster we don't want + SUB AH,CL ;Number of sectors in cluster we accepted + DEC AH ;Adjust to mean position within cluster + MOV [SECCLUSPOS],AH + MOV CX,DX ;Anyway, make the total equal to the request + JMP SHORT FINCLUS + + +FIGREC: + +;Inputs: +; DX = Physical cluster number +; BL = Sector postion within cluster +; BP = Base of drive parameters +;Outputs: +; DX = physical sector number +;No other registers affected. + + PUSH CX + MOV CL,[BP.CLUSSHFT] + DEC DX + DEC DX + SHL DX,CL + OR DL,BL + ADD DX,[BP.FIRREC] + POP CX + RET + +GETREC: + +; Inputs: +; DS:DX point to FCB +; Outputs: +; CX = 1 +; DX:AX = Record number determined by EXTENT and NR fields +; DS:DI point to FCB +; No other registers affected. + + MOV DI,DX + CMP BYTE PTR [DI],-1 ;Check for extended FCB + JNZ NORMFCB2 + ADD DI,7 +NORMFCB2: + MOV CX,1 + MOV AL,[DI.NR] + MOV DX,[DI.EXTENT] + SHL AL,1 + SHR DX,1 + RCR AL,1 + MOV AH,DL + MOV DL,DH + MOV DH,0 + RET + + +ALLOCATE: + +; Inputs: +; DS = CS +; ES = Segment of FCB +; BX = Last cluster of file (0 if null file) +; CX = No. of clusters to allocate +; DX = Position of cluster BX +; BP = Base of drive parameters +; SI = FAT pointer +; [FCB] = Displacement of FCB within segment +; Outputs: +; IF insufficient space +; THEN +; Carry set +; CX = max. no. of records that could be added to file +; ELSE +; Carry clear +; BX = First cluster allocated +; FAT is fully updated including dirty bit +; FIRCLUS field of FCB set if file was null +; SI,BP unchanged. All other registers destroyed. + + PUSH [SI] + PUSH DX + PUSH CX + PUSH BX + MOV AX,BX +ALLOC: + MOV DX,BX +FINDFRE: + INC BX + CMP BX,[BP.MAXCLUS] + JLE TRYOUT + CMP AX,1 + JG TRYIN + POP BX + MOV DX,0FFFH + CALL RELBLKS + POP AX ;No. of clusters requested + SUB AX,CX ;AX=No. of clusters allocated + POP DX + POP [SI] + INC DX ;Position of first cluster allocated + ADD AX,DX ;AX=max no. of cluster in file + MOV DL,[BP.CLUSMSK] + MOV DH,0 + INC DX ;DX=records/cluster + MUL DX ;AX=max no. of records in file + MOV CX,AX + SUB CX,WORD PTR [RECPOS] ;CX=max no. of records that could be written + JA MAXREC + XOR CX,CX ;If CX was negative, zero it +MAXREC: + STC +RET11: RET + +TRYOUT: + CALL UNPACK + JZ HAVFRE +TRYIN: + DEC AX + JLE FINDFRE + XCHG AX,BX + CALL UNPACK + JZ HAVFRE + XCHG AX,BX + JMP SHORT FINDFRE +HAVFRE: + XCHG BX,DX + MOV AX,DX + CALL PACK + MOV BX,AX + LOOP ALLOC + MOV DX,0FFFH + CALL PACK + MOV BYTE PTR [SI-1],1 + POP BX + POP CX ;Don't need this stuff since we're successful + POP DX + CALL UNPACK + POP [SI] + XCHG BX,DI + OR DI,DI + JNZ RET11 + MOV DI,[FCB] + MOV ES:[DI.FIRCLUS],BX +RET12: RET + + +RELEASE: + +; Inputs: +; DS = CS +; BX = Cluster in file +; SI = FAT pointer +; BP = Base of drive parameters +; Function: +; Frees cluster chain starting with [BX] +; AX,BX,DX,DI all destroyed. Other registers unchanged. + + XOR DX,DX +RELBLKS: +; Enter here with DX=0FFFH to put an end-of-file mark +; in the first cluster and free the rest in the chain. + CALL UNPACK + JZ RET12 + MOV AX,DI + CALL PACK + CMP AX,0FF8H + MOV BX,AX + JB RELEASE +RET13: RET + + +GETEOF: + +; Inputs: +; BX = Cluster in a file +; SI = Base of drive FAT +; DS = CS +; Outputs: +; BX = Last cluster in the file +; DI destroyed. No other registers affected. + + CALL UNPACK + CMP DI,0FF8H + JAE RET13 + MOV BX,DI + JMP SHORT GETEOF + + +SRCHFRST: ;System call 17 + CALL GETFILE +SAVPLCE: +; Search-for-next enters here to save place and report +; findings. + JC KILLSRCH + OR BH,BH + JS SRCHDEV + MOV AX,[LASTENT] + MOV ES:[DI.FILDIRENT],AX + MOV ES:[DI.DRVBP],BP +;Information in directory entry must be copied into the first +; 33 bytes starting at the disk transfer address. + MOV SI,BX + LES DI,DWORD PTR [DMAADD] + MOV AX,00FFH + CMP AL,[EXTFCB] + JNZ NORMFCB + STOSW + INC AL + STOSW + STOSW + MOV AL,[ATTRIB] + STOSB +NORMFCB: + MOV AL,[THISDRV] + INC AL + STOSB ;Set drive number + MOV CX,16 + REP MOVSW ;Copy remaining 10 characters of name + XOR AL,AL + RET + +KILLSRCH: +KILLSRCH1 EQU KILLSRCH+1 +;The purpose of the KILLSRCH1 label is to provide a jump label to the following +; instruction which leaves out the segment override. + MOV WORD PTR ES:[DI.FILDIRENT],-1 + MOV AL,-1 + RET + +SRCHDEV: + MOV ES:[DI.FILDIRENT],BX + LES DI,DWORD PTR [DMAADD] + XOR AX,AX + STOSB ;Zero drive byte + SUB SI,4 ;Point to device name + MOVSW + MOVSW + MOV AX,2020H + STOSB + STOSW + STOSW + STOSW ;Fill with 8 blanks + XOR AX,AX + MOV CX,10 + REP STOSW + STOSB +RET14: RET + +SRCHNXT: ;System call 18 + CALL MOVNAME + MOV DI,DX + JC NEAR PTR KILLSRCH1 + MOV BP,[DI.DRVBP] + MOV AX,[DI.FILDIRENT] + OR AX,AX + JS NEAR PTR KILLSRCH1 + PUSH DX + PUSH DS + PUSH CS + POP DS + MOV [LASTENT],AX + CALL CONTSRCH + POP ES + POP DI + JMP SAVPLCE + + +FILESIZE: ;System call 35 + CALL GETFILE + MOV AL,-1 + JC RET14 + ADD DI,33 ;Write size in RR field + MOV CX,ES:[DI.RECSIZ-33] + OR CX,CX + JNZ RECOK + MOV CX,128 +RECOK: + XOR AX,AX + XOR DX,DX ;Intialize size to zero + OR BH,BH ;Check for named I/O device + JS DEVSIZ + INC SI + INC SI ;Point to length field + MOV AX,[SI+2] ;Get high word of size + DIV CX + PUSH AX ;Save high part of result + LODSW ;Get low word of size + DIV CX + OR DX,DX ;Check for zero remainder + POP DX + JZ DEVSIZ + INC AX ;Round up for partial record + JNZ DEVSIZ ;Propagate carry? + INC DX +DEVSIZ: + STOSW + MOV AX,DX + STOSB + MOV AL,0 + CMP CX,64 + JAE RET14 ;Only 3-byte field if RECSIZ >= 64 + MOV ES:[DI],AH + RET + + +SETDMA: ;System call 26 + MOV CS:[DMAADD],DX + MOV CS:[DMAADD+2],DS + RET + +NOSUCHDRV: + MOV AL,-1 + RET + +GETFATPT: ;System call 27 + MOV DL,0 ;Use default drive + +GETFATPTDL: ;System call 28 + PUSH CS + POP DS + MOV AL,DL + CALL GETTHISDRV + JC NOSUCHDRV + CALL FATREAD + MOV BX,[BP.FAT] + MOV AL,[BP.CLUSMSK] + INC AL + MOV DX,[BP.MAXCLUS] + DEC DX + MOV CX,[BP.SECSIZ] + LDS SI,DWORD PTR [SPSAVE] + MOV [SI.BXSAVE],BX + MOV [SI.DXSAVE],DX + MOV [SI.CXSAVE],CX + MOV [SI.DSSAVE],CS + RET + + +GETDSKPT: ;System call 31 + PUSH CS + POP DS + MOV AL,[CURDRV] + MOV [THISDRV],AL + CALL FATREAD + LDS SI,DWORD PTR [SPSAVE] + MOV [SI.BXSAVE],BP + MOV [SI.DSSAVE],CS + RET + + +DSKRESET: ;System call 13 + PUSH CS + POP DS +WRTFATS: +; DS=CS. Writes back all dirty FATs. All registers destroyed. + XOR AL,AL + XCHG AL,[DIRTYBUF] + OR AL,AL + JZ NOBUF + MOV BP,[BUFDRVBP] + MOV DX,[BUFSECNO] + MOV BX,[BUFFER] + MOV CX,1 + CALL DWRITE +NOBUF: + MOV CL,[NUMIO] + MOV CH,0 + MOV BP,[DRVTAB] +WRTFAT: + PUSH CX + CALL CHKFATWRT + POP CX + ADD BP,DPBSIZ + LOOP WRTFAT + RET + + +GETDRV: ;System call 25 + MOV AL,CS:[CURDRV] +RET15: RET + + +SETRNDREC: ;System call 36 + CALL GETREC + MOV [DI+33],AX + MOV [DI+35],DL + CMP [DI.RECSIZ],64 + JAE RET15 + MOV [DI+36],DH ;Set 4th byte only if record size < 64 +RET16: RET + + +SELDSK: ;System call 14 + MOV AL,CS:[NUMDRV] + CMP DL,AL + JNB RET17 + MOV CS:[CURDRV],DL +RET17: RET + +BUFIN: ;System call 10 + MOV AX,CS + MOV ES,AX + MOV SI,DX + MOV CH,0 + LODSW + OR AL,AL + JZ RET17 + MOV BL,AH + MOV BH,CH + CMP AL,BL + JBE NOEDIT + CMP BYTE PTR [BX+SI],0DH + JZ EDITON +NOEDIT: + MOV BL,CH +EDITON: + MOV DL,AL + DEC DX +NEWLIN: + MOV AL,CS:[CARPOS] + MOV CS:[STARTPOS],AL + PUSH SI + MOV DI,OFFSET DOSGROUP:INBUF + MOV AH,CH + MOV BH,CH + MOV DH,CH +GETCH: + CALL IN + CMP AL,"F"-"@" ;Ignore ^F + JZ GETCH + CMP AL,CS:ESCCHAR + JZ ESC + CMP AL,7FH + JZ BACKSP + CMP AL,8 + JZ BACKSP + CMP AL,13 + JZ ENDLIN + CMP AL,10 + JZ PHYCRLF + CMP AL,CANCEL + JZ KILNEW +SAVCH: + CMP DH,DL + JAE BUFFUL + STOSB + INC DH + CALL BUFOUT + OR AH,AH + JNZ GETCH + CMP BH,BL + JAE GETCH + INC SI + INC BH + JMP SHORT GETCH + +BUFFUL: + MOV AL,7 + CALL OUT + JMP SHORT GETCH + +ESC: + CALL IN + MOV CL,ESCTABLEN + PUSH DI + MOV DI,OFFSET DOSGROUP:ESCTAB + REPNE SCASB + POP DI + SHL CX,1 + MOV BP,CX + JMP [BP+OFFSET DOSGROUP:ESCFUNC] + +ENDLIN: + STOSB + CALL OUT + POP DI + MOV [DI-1],DH + INC DH +COPYNEW: + MOV BP,ES + MOV BX,DS + MOV ES,BX + MOV DS,BP + MOV SI,OFFSET DOSGROUP:INBUF + MOV CL,DH + REP MOVSB + RET +CRLF: + MOV AL,13 + CALL OUT + MOV AL,10 + JMP OUT + +PHYCRLF: + CALL CRLF + JMP SHORT GETCH + +KILNEW: + MOV AL,"\" + CALL OUT + POP SI +PUTNEW: + CALL CRLF + MOV AL,CS:[STARTPOS] + CALL TAB + JMP NEWLIN + +BACKSP: + OR DH,DH + JZ OLDBAK + CALL BACKUP + MOV AL,ES:[DI] + CMP AL," " + JAE OLDBAK + CMP AL,9 + JZ BAKTAB + CALL BACKMES +OLDBAK: + OR AH,AH + JNZ GETCH1 + OR BH,BH + JZ GETCH1 + DEC BH + DEC SI +GETCH1: + JMP GETCH +BAKTAB: + PUSH DI + DEC DI + STD + MOV CL,DH + MOV AL," " + PUSH BX + MOV BL,7 + JCXZ FIGTAB +FNDPOS: + SCASB + JNA CHKCNT + CMP ES:BYTE PTR [DI+1],9 + JZ HAVTAB + DEC BL +CHKCNT: + LOOP FNDPOS +FIGTAB: + SUB BL,CS:[STARTPOS] +HAVTAB: + SUB BL,DH + ADD CL,BL + AND CL,7 + CLD + POP BX + POP DI + JZ OLDBAK +TABBAK: + CALL BACKMES + LOOP TABBAK + JMP SHORT OLDBAK +BACKUP: + DEC DH + DEC DI +BACKMES: + MOV AL,8 + CALL OUT + MOV AL," " + CALL OUT + MOV AL,8 + JMP OUT + +TWOESC: + MOV AL,ESCCH + JMP SAVCH + +COPYLIN: + MOV CL,BL + SUB CL,BH + JMP SHORT COPYEACH + +COPYSTR: + CALL FINDOLD + JMP SHORT COPYEACH + +COPYONE: + MOV CL,1 +COPYEACH: + MOV AH,0 + CMP DH,DL + JZ GETCH2 + CMP BH,BL + JZ GETCH2 + LODSB + STOSB + CALL BUFOUT + INC BH + INC DH + LOOP COPYEACH +GETCH2: + JMP GETCH + +SKIPONE: + CMP BH,BL + JZ GETCH2 + INC BH + INC SI + JMP GETCH + +SKIPSTR: + CALL FINDOLD + ADD SI,CX + ADD BH,CL + JMP GETCH + +FINDOLD: + CALL IN + MOV CL,BL + SUB CL,BH + JZ NOTFND + DEC CX + JZ NOTFND + PUSH ES + PUSH DS + POP ES + PUSH DI + MOV DI,SI + INC DI + REPNE SCASB + POP DI + POP ES + JNZ NOTFND + NOT CL + ADD CL,BL + SUB CL,BH +RET30: RET +NOTFND: + POP BP + JMP GETCH + +REEDIT: + MOV AL,"@" + CALL OUT + POP DI + PUSH DI + PUSH ES + PUSH DS + CALL COPYNEW + POP DS + POP ES + POP SI + MOV BL,DH + JMP PUTNEW + +ENTERINS: + IF TOGLINS + NOT AH + JMP GETCH + ENDIF + IF NOT TOGLINS + MOV AH,-1 + JMP GETCH + +EXITINS: + MOV AH,0 + JMP GETCH + ENDIF + +ESCFUNC DW GETCH + DW TWOESC + IF NOT TOGLINS + DW EXITINS + ENDIF + DW ENTERINS + DW BACKSP + DW REEDIT + DW KILNEW + DW COPYLIN + DW SKIPSTR + DW COPYSTR + DW SKIPONE + DW COPYONE + + IF IBM + DW COPYONE + DW CTRLZ +CTRLZ: + MOV AL,"Z"-"@" + JMP SAVCH + ENDIF +BUFOUT: + CMP AL," " + JAE OUT + CMP AL,9 + JZ OUT + PUSH AX + MOV AL,"^" + CALL OUT + POP AX + OR AL,40H + JMP SHORT OUT + +NOSTOP: + CMP AL,"P"-"@" + JZ INCHK + IF NOT TOGLPRN + CMP AL,"N"-"@" + JZ INCHK + ENDIF + CMP AL,"C"-"@" + JZ INCHK + RET + +CONOUT: ;System call 2 + MOV AL,DL +OUT: + CMP AL,20H + JB CTRLOUT + CMP AL,7FH + JZ OUTCH + INC CS:BYTE PTR [CARPOS] +OUTCH: + PUSH AX + CALL STATCHK + POP AX + CALL FAR PTR BIOSOUT + TEST CS:BYTE PTR [PFLAG],-1 + JZ RET18 + CALL FAR PTR BIOSPRINT +RET18: RET + +STATCHK: + CALL FAR PTR BIOSSTAT + JZ RET18 + CMP AL,'S'-'@' + JNZ NOSTOP + CALL FAR PTR BIOSIN ;Eat Cntrl-S +INCHK: + CALL FAR PTR BIOSIN + CMP AL,'P'-'@' + JZ PRINTON + IF NOT TOGLPRN + CMP AL,'N'-'@' + JZ PRINTOFF + ENDIF + CMP AL,'C'-'@' + JNZ RET18 +; Ctrl-C handler. +; "^C" and CR/LF is printed. Then the user registers are restored and the +; user CTRL-C handler is executed. At this point the top of the stack has +; 1) the interrupt return address should the user CTRL-C handler wish to +; allow processing to continue; 2) the original interrupt return address +; to the code that performed the function call in the first place. If the +; user CTRL-C handler wishes to continue, it must leave all registers +; unchanged and IRET. The function that was interrupted will simply be +; repeated. + MOV AL,3 ;Display "^C" + CALL BUFOUT + CALL CRLF + CLI ;Prepare to play with stack + MOV SS,CS:[SSSAVE] + MOV SP,CS:[SPSAVE] ;User stack now restored + POP AX + POP BX + POP CX + POP DX + POP SI + POP DI + POP BP + POP DS + POP ES ;User registers now restored + INT CONTC ;Execute user Ctrl-C handler + JMP COMMAND ;Repeat command otherwise + +PRINTON: + IF TOGLPRN + NOT CS:BYTE PTR [PFLAG] + RET + ENDIF + IF NOT TOGLPRN + MOV CS:BYTE PTR [PFLAG],1 + RET + +PRINTOFF: + MOV CS:BYTE PTR [PFLAG],0 + RET + ENDIF + +CTRLOUT: + CMP AL,13 + JZ ZERPOS + CMP AL,8 + JZ BACKPOS + CMP AL,9 + JNZ OUTCHJ + MOV AL,CS:[CARPOS] + OR AL,0F8H + NEG AL +TAB: + PUSH CX + MOV CL,AL + MOV CH,0 + JCXZ POPTAB +TABLP: + MOV AL," " + CALL OUT + LOOP TABLP +POPTAB: + POP CX +RET19: RET + +ZERPOS: + MOV CS:BYTE PTR [CARPOS],0 +OUTCHJ: JMP OUTCH + +BACKPOS: + DEC CS:BYTE PTR [CARPOS] + JMP OUTCH + + +CONSTAT: ;System call 11 + CALL STATCHK + MOV AL,0 + JZ RET19 + OR AL,-1 + RET + + +CONIN: ;System call 1 + CALL IN + PUSH AX + CALL OUT + POP AX + RET + + +IN: ;System call 8 + CALL INCHK + JZ IN +RET29: RET + +RAWIO: ;System call 6 + MOV AL,DL + CMP AL,-1 + JNZ RAWOUT + LDS SI,DWORD PTR CS:[SPSAVE] ;Get pointer to register save area + CALL FAR PTR BIOSSTAT + JNZ RESFLG + OR BYTE PTR [SI.FSAVE],40H ;Set user's zero flag + XOR AL,AL + RET + +RESFLG: + AND BYTE PTR [SI.FSAVE],0FFH-40H ;Reset user's zero flag +RAWINP: ;System call 7 + CALL FAR PTR BIOSIN + RET +RAWOUT: + CALL FAR PTR BIOSOUT + RET + +LIST: ;System call 5 + MOV AL,DL +LISTOUT: + PUSH AX + CALL STATCHK + POP AX + CALL FAR PTR BIOSPRINT +RET20: RET + +PRTBUF: ;System call 9 + MOV SI,DX +OUTSTR: + LODSB + CMP AL,"$" + JZ RET20 + CALL OUT + JMP SHORT OUTSTR + +OUTMES: ;String output for internal messages + LODS CS:BYTE PTR [SI] + CMP AL,"$" + JZ RET20 + CALL OUT + JMP SHORT OUTMES + + +MAKEFCB: ;Interrupt call 41 +DRVBIT EQU 2 +NAMBIT EQU 4 +EXTBIT EQU 8 + MOV DL,0 ;Flag--not ambiguous file name + TEST AL,DRVBIT ;Use current drive field if default? + JNZ DEFDRV + MOV BYTE PTR ES:[DI],0 ;No - use default drive +DEFDRV: + INC DI + MOV CX,8 + TEST AL,NAMBIT ;Use current name fiels as defualt? + XCHG AX,BX ;Save bits in BX + MOV AL," " + JZ FILLB ;If not, go fill with blanks + ADD DI,CX + XOR CX,CX ;Don't fill any +FILLB: + REP STOSB + MOV CL,3 + TEST BL,EXTBIT ;Use current extension as default + JZ FILLB2 + ADD DI,CX + XOR CX,CX +FILLB2: + REP STOSB + XCHG AX,CX ;Put zero in AX + STOSW + STOSW ;Initialize two words after to zero + SUB DI,16 ;Point back at start + TEST BL,1 ;Scan off separators if not zero + JZ SKPSPC + CALL SCANB ;Peel off blanks and tabs + CALL DELIM ;Is it a one-time-only delimiter? + JNZ NOSCAN + INC SI ;Skip over the delimiter +SKPSPC: + CALL SCANB ;Always kill preceding blanks and tabs +NOSCAN: + CALL GETLET + JBE NODRV ;Quit if termination character + CMP BYTE PTR[SI],":" ;Check for potential drive specifier + JNZ NODRV + INC SI ;Skip over colon + SUB AL,"@" ;Convert drive letter to binary drive number + JBE BADDRV ;Valid drive numbers are 1-15 + CMP AL,CS:[NUMDRV] + JBE HAVDRV +BADDRV: + MOV DL,-1 +HAVDRV: + STOSB ;Put drive specifier in first byte + INC SI + DEC DI ;Counteract next two instructions +NODRV: + DEC SI ;Back up + INC DI ;Skip drive byte + MOV CX,8 + CALL GETWORD ;Get 8-letter file name + CMP BYTE PTR [SI],"." + JNZ NODOT + INC SI ;Skip over dot if present + MOV CX,3 ;Get 3-letter extension + CALL MUSTGETWORD +NODOT: + LDS BX,CS:DWORD PTR [SPSAVE] + MOV [BX.SISAVE],SI + MOV AL,DL + RET + +NONAM: + ADD DI,CX + DEC SI + RET + +GETWORD: + CALL GETLET + JBE NONAM ;Exit if invalid character + DEC SI +MUSTGETWORD: + CALL GETLET + JBE FILLNAM + JCXZ MUSTGETWORD + DEC CX + CMP AL,"*" ;Check for ambiguous file specifier + JNZ NOSTAR + MOV AL,"?" + REP STOSB +NOSTAR: + STOSB + CMP AL,"?" + JNZ MUSTGETWORD + OR DL,1 ;Flag ambiguous file name + JMP MUSTGETWORD +FILLNAM: + MOV AL," " + REP STOSB + DEC SI +RET21: RET + +SCANB: + LODSB + CALL SPCHK + JZ SCANB + DEC SI + RET + +GETLET: +;Get a byte from [SI], convert it to upper case, and compare for delimiter. +;ZF set if a delimiter, CY set if a control character (other than TAB). + LODSB + AND AL,7FH + CMP AL,"a" + JB CHK + CMP AL,"z" + JA CHK + SUB AL,20H ;Convert to upper case +CHK: + CMP AL,"." + JZ RET21 + CMP AL,'"' + JZ RET21 + CMP AL,"/" + JZ RET21 + CMP AL,"[" + JZ RET21 + CMP AL,"]" + JZ RET21 + + IF IBM +DELIM: + ENDIF + CMP AL,":" ;Allow ":" as separator in IBM version + JZ RET21 + IF NOT IBM +DELIM: + ENDIF + + CMP AL,"+" + JZ RET101 + CMP AL,"=" + JZ RET101 + CMP AL,";" + JZ RET101 + CMP AL,"," + JZ RET101 +SPCHK: + CMP AL,9 ;Filter out tabs too + JZ RET101 +;WARNING! " " MUST be the last compare + CMP AL," " +RET101: RET + +SETVECT: ; Interrupt call 37 + XOR BX,BX + MOV ES,BX + MOV BL,AL + SHL BX,1 + SHL BX,1 + MOV ES:[BX],DX + MOV ES:[BX+2],DS + RET + + +NEWBASE: ; Interrupt call 38 + MOV ES,DX + LDS SI,CS:DWORD PTR [SPSAVE] + MOV DS,[SI.CSSAVE] + XOR SI,SI + MOV DI,SI + MOV AX,DS:[2] + MOV CX,80H + REP MOVSW + +SETMEM: + +; Inputs: +; AX = Size of memory in paragraphs +; DX = Segment +; Function: +; Completely prepares a program base at the +; specified segment. +; Outputs: +; DS = DX +; ES = DX +; [0] has INT 20H +; [2] = First unavailable segment ([ENDMEM]) +; [5] to [9] form a long call to the entry point +; [10] to [13] have exit address (from INT 22H) +; [14] to [17] have ctrl-C exit address (from INT 23H) +; [18] to [21] have fatal error address (from INT 24H) +; DX,BP unchanged. All other registers destroyed. + + XOR CX,CX + MOV DS,CX + MOV ES,DX + MOV SI,EXIT + MOV DI,SAVEXIT + MOVSW + MOVSW + MOVSW + MOVSW + MOVSW + MOVSW + MOV ES:[2],AX + SUB AX,DX + CMP AX,MAXDIF + JBE HAVDIF + MOV AX,MAXDIF +HAVDIF: + MOV BX,ENTRYPOINTSEG + SUB BX,AX + SHL AX,1 + SHL AX,1 + SHL AX,1 + SHL AX,1 + MOV DS,DX + MOV DS:[6],AX + MOV DS:[8],BX + MOV DS:[0],20CDH ;"INT INTTAB" + MOV DS:(BYTE PTR [5]),LONGCALL + RET + +DATE16: + PUSH CX + CALL READTIME + SHL CL,1 ;Minutes to left part of byte + SHL CL,1 + SHL CX,1 ;Push hours and minutes to left end + SHL CX,1 + SHL CX,1 + SHR DH,1 ;Count every two seconds + OR CL,DH ;Combine seconds with hours and minutes + MOV DX,CX + POP CX + MOV AX,WORD PTR [MONTH] ;Fetch month and year + SHL AL,1 ;Push month to left to make room for day + SHL AL,1 + SHL AL,1 + SHL AL,1 + SHL AX,1 + OR AL,[DAY] +RET22: RET + +FOURYEARS EQU 3*365+366 + +READTIME: +;Gets time in CX:DX. Figures new date if it has changed. +;Uses AX, CX, DX. + CALL FAR PTR BIOSGETTIME + CMP AX,[DAYCNT] ;See if day count is the same + JZ RET22 + CMP AX,FOURYEARS*30 ;Number of days in 120 years + JAE RET22 ;Ignore if too large + MOV [DAYCNT],AX + PUSH SI + PUSH CX + PUSH DX ;Save time + XOR DX,DX + MOV CX,FOURYEARS ;Number of days in 4 years + DIV CX ;Compute number of 4-year units + SHL AX,1 + SHL AX,1 + SHL AX,1 ;Multiply by 8 (no. of half-years) + MOV CX,AX ;<240 implies AH=0 + MOV SI,OFFSET DOSGROUP:YRTAB ;Table of days in each year + CALL DSLIDE ;Find out which of four years we're in + SHR CX,1 ;Convert half-years to whole years + JNC SK ;Extra half-year? + ADD DX,200 +SK: + CALL SETYEAR + MOV CL,1 ;At least at first month in year + MOV SI,OFFSET DOSGROUP:MONTAB ;Table of days in each month + CALL DSLIDE ;Find out which month we're in + MOV [MONTH],CL + INC DX ;Remainder is day of month (start with one) + MOV [DAY],DL + CALL WKDAY ;Set day of week + POP DX + POP CX + POP SI +RET23: RET + +DSLIDE: + MOV AH,0 +DSLIDE1: + LODSB ;Get count of days + CMP DX,AX ;See if it will fit + JB RET23 ;If not, done + SUB DX,AX + INC CX ;Count one more month/year + JMP SHORT DSLIDE1 + +SETYEAR: +;Set year with value in CX. Adjust length of February for this year. + MOV BYTE PTR [YEAR],CL +CHKYR: + TEST CL,3 ;Check for leap year + MOV AL,28 + JNZ SAVFEB ;28 days if no leap year + INC AL ;Add leap day +SAVFEB: + MOV [MONTAB+1],AL ;Store for February + RET + +;Days in year +YRTAB DB 200,166 ;Leap year + DB 200,165 + DB 200,165 + DB 200,165 + +;Days of each month +MONTAB DB 31 ;January + DB 28 ;February--reset each time year changes + DB 31 ;March + DB 30 ;April + DB 31 ;May + DB 30 ;June + DB 31 ;July + DB 31 ;August + DB 30 ;September + DB 31 ;October + DB 30 ;November + DB 31 ;December + +GETDATE: ;Function call 42 + PUSH CS + POP DS + CALL READTIME ;Check for rollover to next day + MOV AX,[YEAR] + MOV BX,WORD PTR [DAY] + LDS SI,DWORD PTR [SPSAVE] ;Get pointer to user registers + MOV [SI.DXSAVE],BX ;DH=month, DL=day + ADD AX,1980 ;Put bias back + MOV [SI.CXSAVE],AX ;CX=year + MOV AL,CS:[WEEKDAY] +RET24: RET + +SETDATE: ;Function call 43 + MOV AL,-1 ;Be ready to flag error + SUB CX,1980 ;Fix bias in year + JC RET24 ;Error if not big enough + CMP CX,119 ;Year must be less than 2100 + JA RET24 + OR DH,DH + JZ RET24 + OR DL,DL + JZ RET24 ;Error if either month or day is 0 + CMP DH,12 ;Check against max. month + JA RET24 + PUSH CS + POP DS + CALL CHKYR ;Set Feb. up for new year + MOV AL,DH + MOV BX,OFFSET DOSGROUP:MONTAB-1 + XLAT ;Look up days in month + CMP AL,DL + MOV AL,-1 ;Restore error flag, just in case + JB RET24 ;Error if too many days + CALL SETYEAR + MOV WORD PTR [DAY],DX ;Set both day and month + SHR CX,1 + SHR CX,1 + MOV AX,FOURYEARS + MOV BX,DX + MUL CX + MOV CL,BYTE PTR [YEAR] + AND CL,3 + MOV SI,OFFSET DOSGROUP:YRTAB + MOV DX,AX + SHL CX,1 ;Two entries per year, so double count + CALL DSUM ;Add up the days in each year + MOV CL,BH ;Month of year + MOV SI,OFFSET DOSGROUP:MONTAB + DEC CX ;Account for months starting with one + CALL DSUM ;Add up days in each month + MOV CL,BL ;Day of month + DEC CX ;Account for days starting with one + ADD DX,CX ;Add in to day total + XCHG AX,DX ;Get day count in AX + MOV [DAYCNT],AX + CALL FAR PTR BIOSSETDATE +WKDAY: + MOV AX,[DAYCNT] + XOR DX,DX + MOV CX,7 + INC AX + INC AX ;First day was Tuesday + DIV CX ;Compute day of week + MOV [WEEKDAY],DL + XOR AL,AL ;Flag OK +RET25: RET + +DSUM: + MOV AH,0 + JCXZ RET25 +DSUM1: + LODSB + ADD DX,AX + LOOP DSUM1 + RET + +GETTIME: ;Function call 44 + PUSH CS + POP DS + CALL READTIME + LDS SI,DWORD PTR [SPSAVE] ;Get pointer to user registers + MOV [SI.DXSAVE],DX + MOV [SI.CXSAVE],CX + XOR AL,AL +RET26: RET + +SETTIME: ;Function call 45 +;Time is in CX:DX in hours, minutes, seconds, 1/100 sec. + MOV AL,-1 ;Flag in case of error + CMP CH,24 ;Check hours + JAE RET26 + CMP CL,60 ;Check minutes + JAE RET26 + CMP DH,60 ;Check seconds + JAE RET26 + CMP DL,100 ;Check 1/100's + JAE RET26 + CALL FAR PTR BIOSSETTIME + XOR AL,AL + RET + + +; Default handler for division overflow trap +DIVOV: + PUSH SI + PUSH AX + MOV SI,OFFSET DOSGROUP:DIVMES + CALL OUTMES + POP AX + POP SI + INT 23H ;Use Ctrl-C abort on divide overflow + IRET + +CODSIZ EQU $-CODSTRT ;Size of code segment +CODE ENDS + + +;***** DATA AREA ***** +CONSTANTS SEGMENT BYTE + ORG 0 +CONSTRT EQU $ ;Start of constants segment + +IONAME: + IF NOT IBM + DB "PRN ","LST ","NUL ","AUX ","CON " + ENDIF + IF IBM + DB "COM1","PRN ","LPT1","NUL ","AUX ","CON " + ENDIF +DIVMES DB 13,10,"Divide overflow",13,10,"$" +CARPOS DB 0 +STARTPOS DB 0 +PFLAG DB 0 +DIRTYDIR DB 0 ;Dirty buffer flag +NUMDRV DB 0 ;Number of drives +NUMIO DB ? ;Number of disk tables +VERFLG DB 0 ;Initialize with verify off +CONTPOS DW 0 +DMAADD DW 80H ;User's disk transfer address (disp/seg) + DW ? +ENDMEM DW ? +MAXSEC DW 0 +BUFFER DW ? +BUFSECNO DW 0 +BUFDRVNO DB -1 +DIRTYBUF DB 0 +BUFDRVBP DW ? +DIRBUFID DW -1 +DAY DB 0 +MONTH DB 0 +YEAR DW 0 +DAYCNT DW -1 +WEEKDAY DB 0 +CURDRV DB 0 ;Default to drive A +DRVTAB DW 0 ;Address of start of DPBs +DOSLEN EQU CODSIZ+($-CONSTRT) ;Size of CODE + CONSTANTS segments +CONSTANTS ENDS + +DATA SEGMENT WORD +; Init code overlaps with data area below + + ORG 0 +INBUF DB 128 DUP (?) +CONBUF DB 131 DUP (?) ;The rest of INBUF and console buffer +LASTENT DW ? +EXITHOLD DB 4 DUP (?) +FATBASE DW ? +NAME1 DB 11 DUP (?) ;File name buffer +ATTRIB DB ? +NAME2 DB 11 DUP (?) +NAME3 DB 12 DUP (?) +EXTFCB DB ? +;WARNING - the following two items are accessed as a word +CREATING DB ? +DELALL DB ? +TEMP LABEL WORD +SPSAVE DW ? +SSSAVE DW ? +CONTSTK DW ? +SECCLUSPOS DB ? ;Position of first sector within cluster +DSKERR DB ? +TRANS DB ? +PREREAD DB ? ;0 means preread; 1 means optional +READOP DB ? +THISDRV DB ? + + EVEN +FCB DW ? ;Address of user FCB +NEXTADD DW ? +RECPOS DB 4 DUP (?) +RECCNT DW ? +LASTPOS DW ? +CLUSNUM DW ? +SECPOS DW ? ;Position of first sector accessed +VALSEC DW ? ;Number of valid (previously written) sectors +BYTSECPOS DW ? ;Position of first byte within sector +BYTPOS DB 4 DUP (?) ;Byte position in file of access +BYTCNT1 DW ? ;No. of bytes in first sector +BYTCNT2 DW ? ;No. of bytes in last sector +SECCNT DW ? ;No. of whole sectors +ENTFREE DW ? + + DB 80H DUP (?) ;Stack space +IOSTACK LABEL BYTE + DB 80H DUP (?) +DSKSTACK LABEL BYTE + + IF DSKTEST +NSS DW ? +NSP DW ? + ENDIF + +DIRBUF LABEL WORD + +;Init code below overlaps with data area above + + ORG 0 + +MOVFAT: +;This section of code is safe from being overwritten by block move + REP MOVS BYTE PTR [DI],[SI] + CLD + MOV ES:[DMAADD+2],DX + MOV SI,[DRVTAB] ;Address of first DPB + MOV AL,-1 + MOV CL,[NUMIO] ;Number of DPBs +FLGFAT: + MOV DI,ES:[SI.FAT] ;get pointer to FAT + DEC DI ;Point to dirty byte + STOSB ;Flag as unused + ADD SI,DPBSIZ ;Point to next DPB + LOOP FLGFAT + MOV AX,[ENDMEM] + CALL SETMEM ;Set up segment + +XXX PROC FAR + RET +XXX ENDP + +DOSINIT: + CLI + CLD + PUSH CS + POP ES + MOV ES:[ENDMEM],DX + LODSB ;Get no. of drives & no. of I/O drivers + MOV ES:[NUMIO],AL + MOV DI,OFFSET DOSGROUP:MEMSTRT +PERDRV: + MOV BP,DI + MOV AL,ES:[DRVCNT] + STOSB ;DEVNUM + LODSB ;Physical unit no. + STOSB ;DRVNUM + CMP AL,15 + JA BADINIT + CBW ;Index into FAT size table + SHL AX,1 + ADD AX,OFFSET DOSGROUP:FATSIZTAB + XCHG BX,AX + LODSW ;Pointer to DPT + PUSH SI + MOV SI,AX + LODSW + STOSW ;SECSIZ + MOV DX,AX + CMP AX,ES:[MAXSEC] + JBE NOTMAX + MOV ES:[MAXSEC],AX +NOTMAX: + LODSB + DEC AL + STOSB ;CLUSMSK + JZ HAVSHFT + CBW +FIGSHFT: + INC AH + SAR AL,1 + JNZ FIGSHFT + MOV AL,AH +HAVSHFT: + STOSB ;CLUSSHFT + MOVSW ;FIRFAT (= number of reserved sectors) + MOVSB ;FATCNT + MOVSW ;MAXENT + MOV AX,DX ;SECSIZ again + MOV CL,5 + SHR AX,CL + MOV CX,AX ;Directory entries per sector + DEC AX + ADD AX,ES:[BP.MAXENT] + XOR DX,DX + DIV CX + STOSW ;DIRSEC (temporarily) + MOVSW ;DSKSIZ (temporarily) +FNDFATSIZ: + MOV AL,1 + MOV DX,1 +GETFATSIZ: + PUSH DX + CALL FIGFATSIZ + POP DX + CMP AL,DL ;Compare newly computed FAT size with trial + JZ HAVFATSIZ ;Has sequence converged? + CMP AL,DH ;Compare with previous trial + MOV DH,DL + MOV DL,AL ;Shuffle trials + JNZ GETFATSIZ ;Continue iterations if not oscillating + DEC WORD PTR ES:[BP.DSKSIZ] ;Damp those oscillations + JMP SHORT FNDFATSIZ ;Try again + +BADINIT: + MOV SI,OFFSET DOSGROUP:BADMES + CALL OUTMES + STI + HLT + +HAVFATSIZ: + STOSB ;FATSIZ + MUL ES:BYTE PTR[BP.FATCNT] ;Space occupied by all FATs + ADD AX,ES:[BP.FIRFAT] + STOSW ;FIRDIR + ADD AX,ES:[BP.DIRSEC] + MOV ES:[BP.FIRREC],AX ;Destroys DIRSEC + CALL FIGMAX + MOV ES:[BP.MAXCLUS],CX + MOV AX,BX ;Pointer into FAT size table + STOSW ;Allocate space for FAT pointer + MOV AL,ES:[BP.FATSIZ] + XOR AH,AH + MUL ES:[BP.SECSIZ] + CMP AX,ES:[BX] ;Bigger than already allocated + JBE SMFAT + MOV ES:[BX],AX +SMFAT: + POP SI ;Restore pointer to init. table + MOV AL,ES:[DRVCNT] + INC AL + MOV ES:[DRVCNT],AL + CMP AL,ES:[NUMIO] + JAE CONTINIT + JMP PERDRV + +BADINITJ: + JMP BADINIT + +CONTINIT: + PUSH CS + POP DS +;Calculate true address of buffers, FATs, free space + MOV BP,[MAXSEC] + MOV AX,OFFSET DOSGROUP:DIRBUF + ADD AX,BP + MOV [BUFFER],AX ;Start of buffer + ADD AX,BP + MOV [DRVTAB],AX ;Start of DPBs + SHL BP,1 ;Two sectors - directory and buffer + ADD BP,DI ;Allocate buffer space + ADD BP,ADJFAC ;True address of FATs + PUSH BP + MOV SI,OFFSET DOSGROUP:FATSIZTAB + MOV DI,SI + MOV CX,16 +TOTFATSIZ: + INC BP ;Add one for Dirty byte + INC BP ;Add one for I/O device number + LODSW ;Get size of this FAT + XCHG AX,BP + STOSW ;Save address of this FAT + ADD BP,AX ;Compute size of next FAT + CMP AX,BP ;If size was zero done + LOOPNZ TOTFATSIZ + MOV AL,15 + SUB AL,CL ;Compute number of FATs used + MOV [NUMDRV],AL + XOR AX,AX ;Set zero flag + REPZ SCASW ;Make sure all other entries are zero + JNZ BADINITJ + ADD BP,15 ;True start of free space + MOV CL,4 + SHR BP,CL ;First free segment + MOV DX,CS + ADD DX,BP + MOV BX,0FH + MOV CX,[ENDMEM] + CMP CX,1 ;Use memory scan? + JNZ SETEND + MOV CX,DX ;Start scanning just after DOS +MEMSCAN: + INC CX + JZ SETEND + MOV DS,CX + MOV AL,[BX] + NOT AL + MOV [BX],AL + CMP AL,[BX] + NOT AL + MOV [BX],AL + JZ MEMSCAN +SETEND: + IF HIGHMEM + SUB CX,BP + MOV BP,CX ;Segment of DOS + MOV DX,CS ;Program segment + ENDIF + IF NOT HIGHMEM + MOV BP,CS + ENDIF +; BP has segment of DOS (whether to load high or run in place) +; DX has program segment (whether after DOS or overlaying DOS) +; CX has size of memory in paragraphs (reduced by DOS size if HIGHMEM) + MOV CS:[ENDMEM],CX + IF HIGHMEM + MOV ES,BP + XOR SI,SI + MOV DI,SI + MOV CX,(DOSLEN+1)/2 + PUSH CS + POP DS + REP MOVSW ;Move DOS to high memory + ENDIF + XOR AX,AX + MOV DS,AX + MOV ES,AX + MOV DI,INTBASE + MOV AX,OFFSET DOSGROUP:QUIT + STOSW ;Set abort address--displacement + MOV AX,BP + MOV BYTE PTR DS:[ENTRYPOINT],LONGJUMP + MOV WORD PTR DS:[ENTRYPOINT+1],OFFSET DOSGROUP:ENTRY + MOV WORD PTR DS:[ENTRYPOINT+3],AX + MOV WORD PTR DS:[0],OFFSET DOSGROUP:DIVOV ;Set default divide trap address + MOV DS:[2],AX + MOV CX,9 + REP STOSW ;Set 5 segments (skip 2 between each) + MOV WORD PTR DS:[INTBASE+4],OFFSET DOSGROUP:COMMAND + MOV WORD PTR DS:[INTBASE+12],OFFSET DOSGROUP:IRET ;Ctrl-C exit + MOV WORD PTR DS:[INTBASE+16],OFFSET DOSGROUP:IRET ;Fatal error exit + MOV AX,OFFSET BIOSREAD + STOSW + MOV AX,BIOSSEG + STOSW + STOSW ;Add 2 to DI + STOSW + MOV WORD PTR DS:[INTBASE+18H],OFFSET BIOSWRITE + MOV WORD PTR DS:[EXIT],100H + MOV WORD PTR DS:[EXIT+2],DX + IF NOT IBM + MOV SI,OFFSET DOSGROUP:HEADER + CALL OUTMES + ENDIF + PUSH CS + POP DS + PUSH CS + POP ES +;Move the FATs into position + MOV AL,[NUMIO] + CBW + XCHG AX,CX + MOV DI,OFFSET DOSGROUP:MEMSTRT.FAT +FATPOINT: + MOV SI,WORD PTR [DI] ;Get address within FAT address table + MOVSW ;Set address of this FAT + ADD DI,DPBSIZ-2 ;Point to next DPB + LOOP FATPOINT + POP CX ;True address of first FAT + MOV SI,OFFSET DOSGROUP:MEMSTRT ;Place to move DPBs from + MOV DI,[DRVTAB] ;Place to move DPBs to + SUB CX,DI ;Total length of DPBs + CMP DI,SI + JBE MOVJMP ;Are we moving to higher or lower memory? + DEC CX ;Move backwards to higher memory + ADD DI,CX + ADD SI,CX + INC CX + STD +MOVJMP: + MOV ES,BP + JMP MOVFAT + +FIGFATSIZ: + MUL ES:BYTE PTR[BP.FATCNT] + ADD AX,ES:[BP.FIRFAT] + ADD AX,ES:[BP.DIRSEC] +FIGMAX: +;AX has equivalent of FIRREC + SUB AX,ES:[BP.DSKSIZ] + NEG AX + MOV CL,ES:[BP.CLUSSHFT] + SHR AX,CL + INC AX + MOV CX,AX ;MAXCLUS + INC AX + MOV DX,AX + SHR DX,1 + ADC AX,DX ;Size of FAT in bytes + MOV SI,ES:[BP.SECSIZ] + ADD AX,SI + DEC AX + XOR DX,DX + DIV SI + RET + +BADMES: + DB 13,10,"INIT TABLE BAD",13,10,"$" + +FATSIZTAB: + DW 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + +DRVCNT DB 0 + +MEMSTRT LABEL WORD +ADJFAC EQU DIRBUF-MEMSTRT +DATA ENDS + END + \ No newline at end of file diff --git a/v1.25/source/STDDOS.ASM b/v1.25/source/STDDOS.ASM new file mode 100644 index 0000000..1216b4c --- /dev/null +++ b/v1.25/source/STDDOS.ASM @@ -0,0 +1,23 @@ + TITLE MS-DOS version 1.25 by Tim Paterson March 3, 1982 + PAGE 60,132 +; Use the following booleans to set the switches +FALSE EQU 0 +TRUE EQU NOT FALSE + +; Use the switches below to produce the standard Microsoft version of the IBM +; version of the operating system +MSVER EQU TRUE +IBM EQU FALSE + +; Set this switch to cause DOS to move itself to the end of memory +HIGHMEM EQU FALSE + +; Turn on switch below to allow testing disk code with DEBUG. It sets +; up a different stack for disk I/O (functions > 11) than that used for +; character I/O which effectively makes the DOS re-entrant. + +DSKTEST EQU FALSE + + INCLUDE MSDOS.ASM + + \ No newline at end of file diff --git a/v1.25/source/TRANS.ASM b/v1.25/source/TRANS.ASM new file mode 100644 index 0000000..6b06619 --- /dev/null +++ b/v1.25/source/TRANS.ASM @@ -0,0 +1,1213 @@ +; Z80 to 8086 Translator version 2.21 +; Runs on the 8086 under 86-DOS +; by Tim Paterson +; + ORG 100H +EOF: EQU 1AH ;End of file +EOL: EQU 0DH +FCB: EQU 5CH +SYSTEM: EQU 5 +OPEN: EQU 15 +CLOSE: EQU 16 +SETDMA: EQU 26 +CREATE: EQU 22 +DELETE: EQU 19 +READ: EQU 20 +WRITE: EQU 21 +PRNBUF: EQU 9 + MOV SP,STACK + MOV DX,HEADER + MOV CL,9 + CALL SYSTEM + MOV BX,FCB+12 + XOR AL,AL + MOV CH,4 +CLRFCB: + MOV [BX],AL + INC BX + DEC CH + JNZ CLRFCB + MOV [FCB+32],AL + MOV BX,FCB + MOV DX,PUTFCB + MOV CX,16 + UP + MOV SI,BX + MOV DI,DX + REP + MOVB + MOV DX,DI + MOV BX,SI + MOV [PUTFCB+32],AL + MOV BX,"A"+5300H ;"AS" + MOV [PUTFCB+9],BX + MOV AL,'M' + MOV [PUTFCB+11],AL + MOV DX,FCB + MOV CL,OPEN + CALL SYSTEM + INC AL + MOV DX,NOFILE + JZ ABORTJ + MOV DX,PUTFCB + MOV CL,DELETE + CALL SYSTEM + MOV DX,PUTFCB + MOV CL,CREATE + CALL SYSTEM + INC AL + MOV DX,NOROOM +ABORTJ: + JZ ABORT + MOV DX,PUTFCB + MOV CL,OPEN + CALL SYSTEM + MOV BX,PUTBUF + MOV [PUTPT],BX + MOV BX,GETBUF+80H + MOV [GETPT],BX +TRANLN: + XOR AL,AL + MOV [OP1],AL + MOV [OP2],AL + MOV BX,OPCODE + CALL LOAD + MOV BX,OP1 + CALL GETOP + MOV B,[BX],0 + MOV BX,OP2 + CALL GETOP +DOLIN: + MOV B,[BX],0 + CALL FINDOP +ENLIN: + MOV SP,STACK + MOV AL,[CHAR] + CMP AL,';' + JNZ NOCOM + MOV AL,9 + CALL PUTCH + MOV AL,';' +NOCOM: + CALL PUTCH +PUTLIN: + CMP AL,EOF + JZ END + CALL GETCH + CALL PUTCH + CMP AL,10 + JNZ PUTLIN + JP TRANLN +END: + MOV CH,127 + MOV AL,1AH +FILL: + CALL PUTCH + DEC CH + JNZ FILL + MOV DX,PUTFCB + MOV CL,CLOSE + CALL SYSTEM + MOV DX,ENDMES +ABORT: + MOV CL,PRNBUF + CALL SYSTEM + JMP 0 +DELIM: + CALL GETCH +DELCHK: + CMP AL,EOL + JZ DOLIN + CMP AL,EOF + JZ DOLIN + CMP AL,';' + JZ DOLIN + CMP AL,' ' + JZ RET + CMP AL,':' + JZ RET + CMP AL,',' + JZ RET + CMP AL,9 + RET +HEX: + AND AL,0FH + ADD AL,90H + DAA + ADC AL,40H + DAA +PUTCH: + PUSH BX + PUSH DX + PUSH CX + LAHF + XCHG AH,AL + PUSH AX + XCHG AH,AL + AND AL,7FH + MOV BX,[PUTPT] + MOV [BX],AL + INC BX + MOV [PUTPT],BX + CMP BX,PUTBUF+80H + JNZ POPRET + MOV DX,PUTBUF + MOV [PUTPT],DX + MOV CL,SETDMA + CALL SYSTEM + MOV DX,PUTFCB + MOV CL,WRITE + CALL SYSTEM + OR AL,AL + MOV DX,WRTERR + JNZ ABORT +POPRET: + POP AX + XCHG AH,AL + SAHF +NOTAF: + POP CX + POP DX + POP BX + RET +; +; Get character from source file. +; +GETCH: + PUSH BX + PUSH DX + PUSH CX + MOV BX,[GETPT] ; Get buffer pointer. + CMP BX,GETBUF+80H ; Past end-of-buffer? + JNZ GETIT ; Jump if not. + MOV DX,GETBUF ; Set `DMA address'. + MOV CL,SETDMA + CALL SYSTEM + MOV DX,FCB ; Read the next record from source file. + MOV CL,READ + CALL SYSTEM + CMP AL,0 ; Entire record read OK? + JE OKRECORD + CMP AL,3 ; Partial record read? + JE OKRECORD + MOV AL,EOF ; Force end-of-file character in case + JP TESEND ; there is nothing in the record. +OKRECORD: + MOV BX,GETBUF ; Reset buffer pointer. +GETIT: + MOV AL,[BX] ; Get next character from buffer. + INC BX ; Point to next character. + MOV [GETPT],BX ; Save new pointer. +TESEND: + MOV [CHAR],AL + JP NOTAF ; Pop registers and return. +LOAD: + CALL DELIM + JZ LOADOP +EATLAB: + CALL PUTCH + CALL DELIM + JNZ EATLAB +ENLAB: + MOV AL,':' + CALL PUTCH +LOADOP: + MOV BX,OPCODE +EATEM: + CALL DELIM + JZ EATEM +LOADLP: + CALL IDCHK + JNC $+5 + JMP OPERR + MOV [BX],AL + INC BX + CALL DELIM + JNZ LOADLP + MOV B,[BX],0 + CMP AL,':' + JNZ RET + MOV BX,OPCODE + CALL TRANS + JP ENLAB +GETOP: + XOR AL,AL + LAHF + XCHG AX,BP + SAHF +GETLP: + CALL DELIM + JZ GETLP +OPCHAR: + CMP AL,'(' + JNZ NOTLEF + LAHF + XCHG AX,BP + SAHF + INC AL + LAHF + XCHG AX,BP + SAHF + MOV B,[BX],'[' + JP NEXCH +NOTLEF: + CMP AL,')' + JNZ NOTRIT + LAHF + XCHG AX,BP + SAHF + DEC AL + LAHF + XCHG AX,BP + SAHF + MOV B,[BX],']' + JP NEXCH +NOTRIT: + MOV [BX],AL + CMP AL,'''' + JZ EATQUO + CALL IDCHK + JNC GETID +NEXCH: + INC BX + CALL GETCH +IDRET: + CALL DELCHK + JNZ OPCHAR + CMP AL,' ' + JZ OPCHAR + RET +EATQUO: + INC BX + CALL GETCH + MOV [BX],AL + CMP AL,';' + JZ L0000 + CALL DELCHK +L0000: + CMP AL,'''' + JNZ EATQUO + JP NEXCH +IDCHK: + CMP AL,'0' + JC RET + CMP AL,'9'+1 + CMC + JNC RET + CMP AL,40H + JC RET + AND AL,5FH + CMP AL,'A' + JC RET + CMP AL,'Z'+1 + CMC + RET +GETID: + MOV [BX],AL + MOV CH,1 +LODID: + INC BX + CALL GETCH + CALL IDCHK + JC RWCHK + MOV [BX],AL + INC CH + JP LODID +RWCHK: + LAHF + XCHG AH,AL + PUSH AX + XCHG AH,AL + PUSH BX + DEC BX + DEC CH + MOV DL,CH + JZ LOOKRW + MOV DL,[BX] + DEC BX + DEC CH + JNZ NORW +LOOKRW: + MOV AL,[BX] + MOV DH,AL + PUSH BX + MOV BX,RWTAB + MOV CX,LENRW +RWLK: + UP + MOV DI,BX + REPNZ + SCAB + MOV BX,DI + JNZ NOTRW + PUSH BX + PUSH CX + MOV CX,LENRW-1 + LAHF + ADD BX,CX + RCR SI + SAHF + RCL SI + MOV AL,[BX] + POP CX + POP BX + CMP AL,DL + JZ HAVRW + MOV AL,CL + OR AL,AL + MOV AL,DH + JNZ RWLK +NOTRW: + POP BX +NORW: + POP BX +ENDRW: + POP AX + XCHG AH,AL + SAHF + JMP IDRET +HAVRW: + POP BX + INC CL + MOV [BX],CL + INC BX + POP DX + PUSH BX + MOV AL,CL + MOV BX,IXSI + CMP AL,RSI + JZ IXIY + MOV BX,IYDI + CMP AL,RDI + JNZ NORW +IXIY: + LAHF + XCHG AX,BP + SAHF + JZ NOTENC + LAHF + XCHG AX,BP + SAHF + CALL OUTSTR + JP NORW +NOTENC: + LAHF + XCHG AX,BP + SAHF + POP BX + DEC BX + MOV B,[BX],'[' + INC BX + ADD AL,RIX-1 + MOV [BX],AL + INC BX + MOV B,[BX],']' + INC BX + JP ENDRW + RET +FINDOP: + MOV BX,OPCODE + MOV CX,5 + XOR AL,AL + UP + MOV DI,BX + REPNZ + SCAB + MOV BX,DI + JNZ OPERR + MOV AL,4 + SUB AL,CL + JZ RET + DEC AL + JZ OPERR + MOV CL,AL + DEC BX + DEC BX + OR B,[BX],080H + MOV AL,[OPCODE] + SUB AL,'A' + JC OPERR + ADD AL,AL + MOV DL,AL + MOV DH,0 + MOV BX,OPTAB + LAHF + ADD BX,DX + RCR SI + SAHF + RCL SI + MOV DL,[BX] + INC BX + MOV DH,[BX] + XCHG DX,BX + MOV AL,9 + CALL PUTCH +LOOKOP: + MOV AL,[BX] + OR AL,AL + JZ OPERR + MOV DX,OPCODE+1 + MOV CH,CL +LOOKLP: + MOV SI,DX + LODB + CMP AL,[BX] + JNZ NEXOP + INC DX + INC BX + DEC CH + JNZ LOOKLP + MOV DX,[BX] + MOV BX,[BX+2] + JMP DX +NEXOP: + RCR SI + TEST B,[BX],080H + RCL SI + LAHF + INC BX + SAHF + JZ NEXOP + MOV DX,4 + LAHF + ADD BX,DX + RCR SI + SAHF + RCL SI + JP LOOKOP +OPERR: + MOV BX,OPCODE + CALL OUTSTR + CALL TWOOPS + MOV BX,OPCDER + CALL OUTSTR + JMP ENLIN +LD: + CALL OUTSTR + MOV BX,OP1 + MOV DX,OP2+1 + CALL LCHECK + JNZ $+5 + JMP LDAX + XCHG DX,BX + DEC BX + INC DX + CALL LCHECK + JNZ $+5 + JMP STAX +;If immediate move, check for byte memory reference + MOV AL,[OP2] + CMP AL,20H ;Could be immediate? + MOV AL,9 + JC L0001 + CALL BYTCHK ;Add "B," if memory reference +L0001: + CALL TRAN1 + JP TRNOP2 +TWOOPS: + CALL TRNOP1 +TRNOP2: + MOV AL,',' +TRAN2: + MOV BX,OP2 +PTRANS: + CALL PUTCH +TRANS: + MOV AL,[BX] + LAHF + INC BX + SAHF + OR AL,AL + JZ RET + CALL TRNTOK + JP TRANS +LCHECK: + MOV AL,[BX] + CMP AL,RAL + JNZ RET + MOV SI,DX + LODB + CMP AL,RCX + JZ RET + CMP AL,RDX + RET + +ONEOP: + CALL OUTSTR + MOV AL,9 + CALL BYTCHK ;If memory reference, add "B," flag + JMPS TRAN1 + +TRNOP1: + MOV AL,9 +TRAN1: + MOV BX,OP1 + JP PTRANS +IN: + MOV AL,[OP1] + CMP AL,RAL + XCHG DX,BX + MOV BX,OP2 + JZ GETPORT + MOV BX,SAVEAX + CALL OUTSTR + CALL OUTSTR + MOV BX,OP2 + CALL GETPORT + MOV BX,MOV0 + CALL ONEOP + MOV AL,',' + CALL PUTCH + MOV AL,RAL + CALL TRNTOK +IODONE: + MOV BX,RESTAX + JMP OUTSTR +OUT: + MOV AL,[OP2] + XCHG DX,BX + MOV BX,OP1 + CMP AL,RAL + JZ GETOUT + MOV BX,SAVEAX + CALL OUTSTR + MOV BX,MOVAL + CALL OUTSTR + CALL TRNOP2 + MOV BX,CRLFTB + CALL OUTSTR + MOV BX,OP1 + CALL GETOUT + JP IODONE +GETPORT: + MOV AL,[BX] + CMP AL,'[' + JNZ NOBRAK + LAHF + INC BX + SAHF + PUSH BX + MOV CX,80 + MOV AL,']' + UP + MOV DI,BX + REPNZ + SCAB + MOV BX,DI + LAHF + DEC BX + SAHF + MOV B,[BX],0 + POP BX +NOBRAK: + MOV AL,[BX] + CMP AL,RGCL + JNZ FIXPOR + MOV BX,IO1 + CALL OUTSTR + XCHG DX,BX + CALL OUTSTR + MOV AL,RDX + CALL TRNTOK + MOV BX,IO2 + JMP OUTSTR +GETOUT: + CALL GETPORT + JNC RET + MOV BX,BADIO + JMP OUTSTR +FIXPOR: + XCHG DX,BX + CALL OUTSTR + XCHG DX,BX + JMP TRANS +LDAX: + MOV BX,LDAX1 +LSAX: + CALL OUTSTR + MOV SI,DX + LODB + CALL TRNTOK + JP OUTSTR +STAX: + MOV BX,STAX1 + JP LSAX +TRNTOK: + CMP AL,' ' + JC $+5 + JMP PUTCH + PUSH BX + PUSH CX + MOV CL,AL + MOV CH,0 + MOV BX,TOKTAB-2 + LAHF + ADD BX,CX + RCR SI + SAHF + RCL SI + LAHF + ADD BX,CX + RCR SI + SAHF + RCL SI + MOV AL,[BX] + CALL PUTCH + INC BX + MOV AL,[BX] + POP CX + POP BX + OR AL,AL + JZ RET + JMP PUTCH +PUSH: + MOV DX,PUSHAF + JP AFCHK +POP: + MOV DX,POPAF +AFCHK: + MOV AL,[OP1] + CMP AL,RAX + JNZ ONEOPJ + XCHG DX,BX +OUTSTR: + MOV AL,[BX] + OR AL,AL + JNZ L0002 + CALL NEWOP +L0002: + CALL PUTCH + INC BX + ADD AL,AL + JNC OUTSTR + RET +NEWOP: + MOV AL,13 + CALL PUTCH + MOV AL,10 + CALL PUTCH + MOV AL,9 + RET +LDDR: + CALL OUTSTR + MOV BX,BLMOVE + JP OUTSTR +CPDR: + CALL OUTSTR + MOV BX,CMPREP + JP OUTSTR +ADD: + MOV AL,[OP1] + CMP AL,RBX + JZ DAD +ARITH: + CALL OUTSTR + MOV AL,[OP2] + OR AL,AL + JZ $+5 + JMP TWOOPS + MOV AL,9 + CALL PUTCH + MOV AL,RAL + CALL TRNTOK + MOV AL,',' + JMP TRAN1 +ACCUM: + CALL OUTSTR + MOV AL,9 + CALL PUTCH + MOV AL,RAL + JMP TRNTOK +ONEOPJ: JMP ONEOP +DAD: + MOV BX,DAD1 + CALL OUTSTR + CALL TWOOPS + MOV BX,DAD2 + JP OUTSTR + +INCDEC: + MOV AL,[OP1] + CMP AL,RCX+1 ;16-bit? + JNC ONEOPJ + MOV BX,LAHF + CALL OUTSTR + XCHG DX,BX + MOV BX,OPCODE-1 + CALL ONEOP + XCHG DX,BX +OUTSTRJ: + JMP OUTSTR +JUMP: + MOV AL,[OP1] + CMP AL,'[' + JNZ DIRECT + MOV AL,[OP1+1] + MOV [OP1],AL + XOR AL,AL + MOV [OP1+1],AL +DIRECT: + MOV AL,[OP2] + OR AL,AL + JZ ONEOPJ + CALL FIXCON + MOV BX,OP2 +OUTCON: + MOV CH,AL + MOV AL,'J' + CALL PUTCH + MOV AL,CH + CALL TRNTOK + MOV AL,9 + CALL PTRANS + MOV AL,CH + CMP AL,ODDPAR + MOV BX,WARNPA + JZ OUTSTRJ + CMP AL,EVEPAR + JZ OUTSTRJ + RET +FIXCON: + MOV AL,[OP1] + CMP AL,RGCL + JNZ RET + MOV AL,CY + RET +RETURN: + MOV AL,[OP1] + OR AL,AL + JZ OUTSTRJ + MOV BX,'R'+4500H ;"RE" + MOV [OP2],BX + MOV BX,'T' + MOV [OP2+2],BX + JP DIRECT +ONEOPJ1: + JMP ONEOP +DOCALL: + MOV AL,[OP2] + OR AL,AL + JZ ONEOPJ1 + CALL FIXCON + DEC AL + XOR AL,1 + INC AL + MOV BX,LABEL + CALL OUTCON + MOV BX,OPCODE-1 + CALL OUTSTR + MOV AL,[OP2] + OR AL,AL + MOV AL,9 + MOV BX,OP2 + JZ L0003 + CALL PTRANS +L0003: + MOV BX,CRLF + CALL OUTSTR + CALL TRANS + CALL OUTSTR + MOV BX,LABEL+4 +NEXLAB: + INC [BX] + MOV AL,[BX] + CMP AL,'9'+1 + JNZ RET + MOV B,[BX],'0' + LAHF + DEC BX + SAHF + JP NEXLAB +EX: + MOV AL,[OP1] + CMP AL,RAX + JZ OUTSTRJ1 + MOV AL,[OP1+1] + CMP AL,STP + JZ XTHL + MOV BX,XCHG + CALL OUTSTR + JMP TWOOPS +XTHL: + MOV BX,XTHL1 + CALL OUTSTR + CALL TRNOP2 + MOV BX,XTHL2 +OUTSTRJ1: + JMP OUTSTR +PSEUDO: + CALL ONEOP + MOV AL,[OP2] + OR AL,AL + JZ RET + JMP TRNOP2 + RET +BITSET: + MOV CL,0 + JP SETRES +RES: + MOV CL,-1 +SETRES: + CALL OUTSTR + PUSH BX + MOV AL,[OP2] + CMP AL,'[' + MOV AL,9 + JNZ L0004 + CALL BFLAG +L0004: + CALL TRAN2 + MOV AL,',' + CALL PUTCH + CALL GETBIT + MOV BX,BITERR + JNC L0005 + CALL OUTSTR +L0005: + POP BX + JMP OUTSTR + +BYTCHK: +;Check if memory reference and add "B," for byte mode + CMP B,[OP1],"[" ;Memory reference? + JNZ RET + CMP B,[OP1+1],RIX ;Referencing IX as a word? + JZ RET + CMP B,[OP1+1],RIY + JZ RET +BFLAG: + CALL PUTCH + MOV AL,'B' + CALL PUTCH + MOV AL,',' + RET + +GETBIT: + MOV AL,[OP1+1] + OR AL,AL + STC + JNZ RET + MOV AL,[OP1] + SUB AL,'0' + JC RET + CMP AL,8 + CMC + JC RET + MOV CH,AL + INC CH + XOR AL,AL + STC +SHFT: + RCL AL + DEC CH + JNZ SHFT + XOR AL,CL + MOV CH,AL + MOV AL,'0' + CALL PUTCH + MOV AL,CH + RCR AL + RCR AL + RCR AL + RCR AL + CALL HEX + MOV AL,CH + CALL HEX + MOV AL,'H' + JMP PUTCH +OPTAB: + DW AOPS,BOPS,COPS,DOPS,EOPS + DW FOPS,GOPS,HOPS,IOPS,JOPS + DW KOPS,LOPS,MOPS,NOPS,OOPS + DW POPS,QOPS,ROPS,SOPS,TOPS + DW UOPS,VOPS,WOPS,XOPS,YOPS + DW ZOPS +AOPS: + DM 'DD' + DW ADD,OPCODE + DM 'DC' + DW ARITH,OPCODE + DM 'ND' + DW ARITH,OPCODE + DB 0 +BOPS: + DM 'IT' + DW BITSET,TESBIT + DB 0 +COPS: + DM 'ALL' + DW DOCALL,OPCODE + DM 'P' + DW ARITH,CMP + DM 'PL' + DW ACCUM,NOT + DM 'PIR' + DW OUTSTR,CPIR + DM 'PDR' + DW CPDR,DOWN + DM 'CF' + DW OUTSTR,CMC + DB 0 +DOPS: + DM 'EC' + DW INCDEC,OPCODE + DM 'JNZ' + DW ONEOP,DJNZ + DM 'AA' + DW OUTSTR,OPCODE + DM 'I' + DW OUTSTR,OPCODE + DM 'W' + DW PSEUDO,OPCODE + DM 'B' + DW PSEUDO,OPCODE + DM 'M' + DW PSEUDO,OPCODE + DM 'S' + DW ONEOP,OPCODE + DB 0 +EOPS: + DM 'X' + DW EX,EXAF + DM 'I' + DW OUTSTR,OPCODE + DM 'XX' + DW OUTSTR,EXX + DM 'QU' + DW ONEOP,OPCODE + DM 'NDIF' + DW OUTSTR,OPCODE + DB 0 +FOPS: + DB 0 +GOPS: + DB 0 +HOPS: + DM 'ALT' + DW OUTSTR,HLT + DB 0 +IOPS: + DM 'NC' + DW INCDEC,OPCODE + DM 'N' + DW IN,INB + DM 'F' + DW ONEOP,OPCODE + DB 0 +JOPS: + DM 'R' + DW JUMP,JR + DM 'P' + DW JUMP,JMP + DB 0 +KOPS: + DB 0 +LOPS: + DM 'D' + DW LD,MOV + DM 'DIR' + DW OUTSTR,UP + DM 'DDR' + DW LDDR,DOWN + DB 0 +MOPS: + DB 0 +NOPS: + DM 'EG' + DW ACCUM,OPCODE + DB 0 +OOPS: + DM 'R' + DW ARITH,OPCODE + DM 'UT' + DW OUT,OUTB + DM 'RG' + DW ONEOP,OPCODE + DB 0 +POPS: + DM 'OP' + DW POP,OPCODE + DM 'USH' + DW PUSH,OPCODE + DB 0 +QOPS: + DB 0 +ROPS: + DM 'ET' + DW RETURN,OPCODE + DM 'LA' + DW ACCUM,RCL + DM 'RA' + DW ACCUM,RCR + DM 'LCA' + DW ACCUM,ROL + DM 'RCA' + DW ACCUM,ROR + DM 'L' + DW ONEOP,RCL + DM 'R' + DW ONEOP,RCR + DM 'LC' + DW ONEOP,ROL + DM 'RC' + DW ONEOP,ROR + DM 'ES' + DW RES,RESBIT + DM 'ETI' + DW OUTSTR,IRET + DM 'ETN' + DW OUTSTR,IRET + DM 'ST' + DW ONEOP,CALL + DB 0 +SOPS: + DM 'UB' + DW ARITH,OPCODE + DM 'BC' + DW ARITH,SBB + DM 'LA' + DW ONEOP,SAL + DM 'RA' + DW ONEOP,SAR + DM 'RL' + DW ONEOP,SHR + DM 'CF' + DW OUTSTR,STC + DM 'ET' + DW BITSET,SETBIT + DB 0 +TOPS: + DB 0 +UOPS: + DB 0 +VOPS: + DB 0 +WOPS: + DB 0 +XOPS: + DM 'OR' + DW ARITH,OPCODE + DB 0 +YOPS: + DB 0 +ZOPS: + DB 0 +LDAX1: DM 9,'SI,' + DM 0,'LODB' +STAX1: DM 9,'DI,' + DM 0,'STOB' +PUSHAF: DB 'LAHF',0,'XCHG',9,'AH,AL',0,'PUSH',9,'AX',0 + DM 'XCHG',9,'AH,AL' +POPAF: DM 'POP',9,'AX',0,'XCHG',9,'AH,AL',0,'SAHF' +DOWN: DM 'DOWN' +UP: DB 'UP' +BLMOVE: DB 0,'MOV',9,'SI,BX',0,'MOV',9,'DI,DX' + DB 0,'REP',0,'MOVB',0,'MOV',9,'DX,DI' + DM 0,'MOV',9,'BX,SI' +CPIR: DB 'UP' +CMPREP: DB 0,'MOV',9,'DI,BX',0,'REPNZ',0,'SCAB' + DM 0,'MOV',9,'BX,DI' +DAD1: DM 'LAHF',0,'ADD' +DAD2: DM 0,'RCR',9,'SI',0,'SAHF',0,'RCL',9,'SI' +LAHF: DM 'LAHF' + DM 0,'SAHF' +DJNZ: DB 'DEC',9,'CH',13,10 + DB '; *** WARNING: DJNZ does not affect flags - DEC does.',0 + DM 'JNZ' +WARNPA: DM 13,10,'; *** WARNING: Parity flag not always same as Z80.' +IO1: DB 'MOV',9,'DI,DX',0,'MOV',9,'DL,CL',0 + DM 'XOR',9,'DH,DH',13,10,9 +IO2: DM 0,'MOV',9,'DX,DI' +BADIO: DM 13,10,'; *** WARNING: Flags not same as Z80.' +BITERR: DM 13,10,' *** ERROR: Cannot determine bit number.' +SETBIT: DM 'LAHF',0,'OR' + DM 0,'SAHF' +RESBIT: DM 'LAHF',0,'AND' + DM 0,'SAHF' +TESBIT: DM 'RCR',9,'AH',0,'TEST' + DM 0,'RCL',9,'AH' +XTHL1: DM 'POP',9,'SI',0,'XCHG',9,'SI' +XTHL2: DM 0,'PUSH',9,'SI' +EXX: DB 'XCHG',9,'BX,[HL]',0,'XCHG',9,'DX,[DE]',0 + DM 'XCHG',9,'CX,[BC]' +EXAF: DM 'LAHF',0,'XCHG',9,'AX,BP',0,'SAHF' +MOVAL: DM 0,'MOV',9,'AL' +IXSI: DM 9,'MOV',9,'SI,[IX]',13,10 +IYDI: DM 9,'MOV',9,'DI,[IY]',13,10 +RESTAX: DB 0 +SAVEAX: DM 'XCHG',9,'AX,SI' +CRLFTB: DM 13,10,9 +INB: DM 'INB',9 +OUTB: DM 'OUTB',9 +XCHG: DM 'XCHG' +JMP: DM 'JMP' +JR: DM 'JMPS' +RCL: DM 'RCL' +RCR: DM 'RCR' +ROL: DM 'ROL' +ROR: DM 'ROR' +SAL: DM 'SAL' +SAR: DM 'SAR' +SHR: DM 'SHR' +STC: DM 'STC' +IRET: DM 'IRET' +HLT: DM 'HLT' +CMC: DM 'CMC' +NOT: DM 'NOT' +MOV0: DB 0 +MOV: DM 'MOV' +CMP: DM 'CMP' +SBB: DM 'SBB' +CALL: DM 'CALL' +TOKTAB: + DB 'SIDI' + DB 'PEPOS',0,'NSNZZ',0,'NCC',0 + DB 'AXSPBXDXCX' + DB 'BLBHDLDHCLCHALIXIY' +RWTAB: + DB 'ABCDEHLBDHSACNZNPMPPII' +LENRW: EQU $-RWTAB + DB 0,0,0,0,0,0,0,'CELPF',0,'C',0,'Z',0,0,'OEYX' +HEADER: DB 13,10,'Z80 to 8086 Translator version 2.21',13,10,'$' +NOROOM: DB 13,10,'File creation error',13,10,'$' +NOFILE: DB 13,10,'File not found',13,10,'$' +ENDMES: DB 13,10,'Translation complete',13,10,'$' +WRTERR: DB 13,10,'Out of disk space',13,10,'$' +OPCDER: DM 13,10,'*** Opcode Error ' +CRLF: DM 13,10 +LABEL: DB 'L0000',0 + DM ':',9 +PUTPT: DS 2 +GETPT: DS 2 +CHAR: DS 1 + DB 0 +OPCODE: DS 80 +OP1: DS 80 +OP2: DS 80 +PUTBUF: DS 128 +GETBUF: DS 128 +PUTFCB: DS 33 + DS 50 +STACK: EQU $ + ORG 1 ;This is really just for equates without EQU +RSI: DS 1 +RDI: DS 1 +ODDPAR: DS 1 +EVEPAR: DS 1 + DS 5 ;MINUS,PLUS,NOT ZERO,ZERO,NOT CARRY +CY: DS 1 +RAX: DS 1 +STP: DS 1 +RBX: DS 1 +RDX: DS 1 +RCX: DS 1 +RBL: DS 1 +RBH: DS 1 +RDL: DS 1 +RDH: DS 1 +RGCL: DS 1 +RCH: DS 1 +RAL: DS 1 +RIX: DS 1 +RIY: DS 1 + \ No newline at end of file