IMD 1.17: 4/01/1980 22:15:13 msdos v1 disk2 p  <5Ȏ3ێ&& &Zu>} ]t uA-I[r@ؾ@  SQY[CuIO SYS No System I/O error @&G62ts.ztbU @m& RZB't&&OteQIuYtú3ú3 DSK ASM@~?BDSKTB ASMJ?.,RESTORE EXE.`Y]MEMTST EXEJ?RDCPM COM E "GRAPHICSCHRB&ENGLISH CHR'FRENCH CHR(yGERMAN CHR)iDANISH CHR0* SWEDISH CHR&+ SPANISH CHR ,ITALIAN CHRb-DATCOPY DATF.PBMSDOS ASMJq/8BCHR ASMC>@a  @`!#@%1 3@5`79;=?AE`GIK/SU`WYa Oe`gikoq s@u`y} @` @ ` @ ` @ ` @ ` ǀ ɠ @ ` ׀ ٠  @/@`!Aa   !Aa!!#A%a')+-/1!3A5a76N N BDSK ASMJ?@BEND ASMbJ?BDEFASCIIASMbJ?CDEFCONFGASMgxVDDEFMTR ASMxJ?J DEFFMT ASMcJ?MDEF6821 ASMcJ?ODEFEP2 ASMJ?Q DEFCHR ASMJ?TDEF8253 ASMdJ?ZsDEF8259AASMdJ?[DEF6845 ASMJ?]DEFZ207 ASMVJ?_DEFZ217 ASMJ?cDEFDSK ASMpJ?hDEFMS ASMCm%@a  @`!#@%1 3@5`79;=?AE`GIK/SU`WYa Oe`gikoq s@u`y} @` @ ` @ ` @ ` @ ` ǀ ɠ @ ` ׀ ٠  @/@`!Aa   !Aa!!#A%a')+-/1!3A5a76N N DEFIPAGEASMJ?w PARMS ASMJ?{DEFSBC ASMJ?|BINIT ASME~BDOSTB ASMqK?BCHRIO ASMGCBCONIO ASMeJ? BPRNIO ASMZJ?BAUXIO ASMJ?BDSKIO ASM]J?BDSKLA ASMcJ?BCLOCK ASMxVDOBIOS BATyJ?9MACLIB ASMfJ?:BMSDOSL ]J?;0REF EXE2Bad/write track function, side flag: ; 0 - side zero, 1 - side one) ; DSKPR_COUNT (word): ; transfer count ; (1-?? (total bytes must fit within the same segment)) ; DSKPR_BUFF (double word): ; Address of buffer. The first word is the offset, the second word is ; the segment. ; ; Register AL has the function to perform ; (AL) = DSK_RESET - Reset disk(home head) ; (AL) = DSK_STATUS - Get disk status(on success AH=aux status,AL=status) ; (AL) = > vector of disk table addresses ; ; ; All register are used. ; Segment registers are perserved. ; (DS must be set up before call) ; ; Last modified: 9/28/82 - bcb ; DSK PROC NEAR ; Check if the function is legal CMP AL,DSK_FMAX ; Is function legal ? JNA D0A ; Yes, keep going STC ; No, turn on CY to show error MOV AX,DSKST_FNERR ; Show function error RET ; and return ; Check for special functions D0A: CMP AL,DSK_GBIOSVEC ; Is function Get Disk Vector ? JEDSK_STEPIN - Step in head ; (AL) = DSK_READ - Read the specified sectors to the buffer addr ; (AL) = DSK_WRITE - Write the specified sectors from the buffer addr ; (AL) = DSK_VERIFY - Verify the specified sectors. (Not implemented yet) ; (AL) = DSK_FORMAT - Format a track. ; The write track command is used to write the data at DSK_BUFF. ; (AL) = DSK_READTRK - Perform the read track command. ; (AL) = DSK_GBIOSVEC - Get addr of disk vector used by the BIOS in ES:BX. ; (AL) = DS D0A1 ; Yes, skip to it CMP AL,DSK_SETFDC ; Is it FORCE DISK CHANGE JE D0A2 CMP AL,DSK_MAPDSK ; Is function Map Disk ? JNE D0B ; No, must be regular function PAGE ; ; Map device function ; ; AH = current drive name ; If AH = 0FFH ; returns ES:BX pointer to map table ; Else ; returns AL mapped from AH ; CMP AH,0FFH ; Is subfunction, Get Pointer to table? JNE DSKFMAP1 ; No, map a particular drive ; Get pointer to the map table PUSH CS ; G; ; DSK - This routine provides the necessary code to perform all disk I/O. ; ; The particular function to perform is passed in the AL register. ; ; Call with: ; ; The register pair ES:BX points to a parameter block(for all functions ; except GBIOSVEC and MAPDSK) with the following fields: ; ; DSKPR_DRIVE (byte): ; Logical drive number (0-MAXDSK allowed) ; DSKPR_SECTOR (word): ; Logical sector number ; (0-drive_max allowed) ; (On reK_MAPDSK - Maps logical in AH to physical in AL ; (AL) = DSK_SETFDC - Set force disk has been changed flag(DSK_FDC) ; (AL) = DSK_PREAD - Same as DSK_READ but do not apply BSEC value ; ; Returns: ; AX = Status of operation ; (See DEFDSK.ASM) ; CY = 0 - Operation was a success ; CY = 1 - Operation failed (see AX) ; For DSK_READ and DSK_WRITE: ; DSKPR_COUNT = number of sectors not read/written ; DSKPR_BUFF = Addr at end of read/write ; For DSK_GBIOSVEC: ; ES:BX -MZx/ dLattice C 1.00؎&+up3P쾀& F2ك+cG  G&FG3؎P ˋ&Uv 3P%]UFj$S2&0@F@0 t싶0tF~tF P'& FP<F PPF@tMVFuCFtt{>#tC >t6X%@P6I ~t ~uXČ]U츆P&*帉P*P*P *帆P*TP)帆P)帡P)帆P)P)P)PP)帉P)]U 츃? ׉F ^'PSQRP)P) ]U6 R#F P# SF=# P4#]U3FFF=} ƄFFu3]Ëv0uF F0F@(0FvuH(0%t F-aAv0F 0PvF.PvFvD0=:tP(FF@@4640=/Ft t464^CCSF^64Ft F@@4yP0(FiF /F F F^ S8SF (GAr s.~u1F 0-AƄ F /F F F^ S8SF 'FFv0=/FuNuGFF]U5v90tcƉF2v20=+Ft tF2v2^Sv9F4^4v2F0u 35]Ëv20=+v9uF95]UF v 0=:Ft)=/ttWP&]á2v 3]ËF @FF v0=/Ft tFvv Fv ^vt3]øWP@&]U3FF F=}vFFFv0= uFv0Fu=/u.V F @PvDvP !vF @]ËF F vFv0= Ftt 0=/tFv0= t|ƉFv0= uF~ u#v0=/t0tqP@%]ËvF1F ]U>uP %]69 u]øBP7 u%BP PSF$PvFH@SPBPZuiFHPu P$YFudždž=}! ㋶ZY0-0ָPC$ P:$>P1$lP($F@SPBPRuF P v$v SFv0PvD0PF@@^50SvPPP"卆PF60v=v;PPP"卆PiPv~ PvrF@SPBPt F0=t>@PP;# P0#BP]Uv0tF0PP]UFP >t_60F@(0%t F-aA6D0=:u0=A|0=F~P"]Ë60-@F dž=} B ?dž=} B0F\PP4FPP'=u$62S"1 P" PF\PF0PF0P0@SPF0P{=@tPuj3ۉ=}" 닶0-00@SPH PO!` P>! P3F0PF\PPFPP=t ]Uvvt P 3P]UvFu5 P 帵 P P P 2 P 3P:F]Uu]Ã>t>uPZ ]6u]6u P- ]BPfu7BP P SF P P= t3]6vFu P]v\tvBPv]UFF=}<, 0t(F/, 0AF^S8SFT3]F뼸]U P^FFH^ PFHFÉF 101vΉNIF 10NI-^ NIÉFN 101vΉNIF0NI-F %NvNF 10F1Ft 0vv F]U Fv0= uFv0Ft8=-t30@(0%u3 ]ËF ^F00F뺋F= w=s3 ]Ëv0u3 ]ñFFFFv0Ft8=-t30@(0%u3 ]ËF ^F00F뺋F=w=s3 ]Ëv0u3 ]ËFFFFv0Ft1@(0%u3 ]ËF ^F00FF=vnlF-P ^؋à ]Uv D80=uD90Ht*F @PP/ SFPv3]Ëv 0Ft Ht3]Ëv D0=t3]Ëv D0=F|=~3]FF=}8^ ؊0= u%F  v0POu3]FFF=}8^ ؊0= u%F v0P u3]F]UPvj]UPvS]UvPk=u3]ø]UvPE=u3]ø]Uvv =u3]ËvD*D(D]U P#FFF@v\0AKvF@:FFF=}+^؊0= tvFF~F͋vD0= tAvF.FF=}+^؊0= tvFF~F͋vF ]UF @P.v Dv ~ EDEDFF=}^ ؋N FFF=}^ ؋N F݋v Dv Dv Dv D-v Dv D.v D\v D1\/v D\v D5\3v Dv D7FF=}^ 8؋N F݃]Uv v Dv Dv Dv Dv DFF=}^ ؋N FFF=}^ ؋N F݋v Dv Dv D-v Dv D.v Dv D1\/v D\v D5\3v D\v D7v DFF=}^ ؋N 8F݃]Uv Dv Dv Dv DFF=}^ ؋N FFF=}^ ؋N F݋v D v D]U?Pv u*Pv tl P3]øBPv Hu3]øPX PJP tPc PJP u PG]ø.Pv bt P) P FF=} ƄR0F]UvFF=}^CFvDD]U~_u]Ëv)0%Wu3]ËFC3]ø]",+,/,},{,*,=,:,;,,,.,?, ,0.;;u.=yU 3FFF=}^ FFF=}^ Fvv D0=:uc0F@(0%tF-aAv v 0-@0=FF|=~>t P3 ]ÊFvDF v 0u>t Pi3 ]Fv 0Fu=.u0F@(0%tF-aAv v 0PRu v 0=?uOF^~ CF ^|v 0=.uz0uq>t PFSv 0=*u0F=}^?Fv 0Ft!=.tF >t PkF~tv 0uF Fv 0Fu@(0%tF-aAv v 0PGu v 0=?uBF^~ CF ^|v 0t>t PF;v 0=*uF=}'^?F>t PF~t3 ]ø ]U3v90tyƉF0v00=+Ft tF0v0^Sv9F2u3]ÊF2v0F7^ SP*t3]Ëv00=+v9uF9|33]UF~ }7v 0=?t v 0=?t0v 0;t3]F F Fø]U젂0;F u]øBPF BPR0ۉFu I0@Pv P3M P*&0@I0@SvPj P M P = uBP=tPv]à0u)I0@Pv P P P'I0@Pv P P P# = u{Pvk3]UJFD} @PFPBP~ uP63J]ÍFPSuP3J]ø@PFPBP< FFtFF0=t<6FP|t͍FPtFPtFPvD-FD뢃~FuPvD3J]ËFDJ]UF FFFt F^~uN%PVv v~uF vƉF vvƋvvD<D=F ]U>(u]vP: SFPv]Uo 0FF@(0%t F-aAFF0=YFt=NuɊF0Pc PZ PQ F0=Yu]3]UN>)uN]øM PA~RuFLFL=}BDFLFL~L}6FPvRFLFPvvBDvRFRtFLFLFL=}zDFt rDj PFLڸ P PxFLFL=|NzDFt PrDxFL׸p PhtN]3N]U>+tvD;2t3]Â>tvD;0w3]Â>tvD;.r3]vHt3]ø]UFt%QP^FF]U~ ~?v 0v0;}]Ëv 0v0;~]FF N 3]Uv v FF=}^ C؋N AFv Dv Dv Dv DFF=}^ ؋N FFF=}^ ؋N F݋v D&\$v D\v Dv Dv D v D]U>-u]ËvD-0HPu]ËF@P^P SFT PvJvD1\/AQlj{UF@S6SPFu]v8PBP6u]ø68FF ^ F;F}F F v F 0 0;t3]FU >u3 ]á4Fv0=/Ft tFv64v F^v ]U 젂FFFx)F0F 0^RF FNЃ ]UH~LuFPvLFP&t]vBP SF8 Pv.W]UvD-0HPu3]ËvD1\/LlNjF@PGuF@Pu3]ËF@PP SF PvvD5\3F ^F ^33# ~TF 3ɺ }^ v 6PBPu3]ËF@v 6SPtF 3ۅyK)F^ 띋FvD@PF Ft"F@PF@Pt3]ø]UvP SF P PPvY= t3]ø]UFF~~;6;$uP6Pv /=Fu666~FN뿋F+F]U ~u3 ]vvv_^;ÉFuà ]Ã~u3 ]ËF^؋N+ȉN^~~vF~FNF ]U66]U~u3]vvv W^;ÉFuÃ]ËFF0@Pu3]ËFF)Fvvv ;FF|ʋF]UFF~~/8;:uv +FtvF>88NˋF+F]UP8PvV8F8:8F]U8:8]U~uV!VN(!<uF]U~uV!VN'!]ô*! **U&0Ft &]øPP&%]UF%PPF]U&0t]ËF&]Uv0uv PF@@v\0v]UFFv0tFv$v Ptv]U PZu33CÃ]UFF=}#80Ft 2PIFv v ]UFV!2]UFvv0tFF]Uv0;Fuƃ]ËvF0u3]UvF~ F u]U.0*,t ,G]U.0FvQ;ÉFuÃ]ËF0@.v,;t0@3]U,]U ~u3 ]ËFH*F ^v~tKvD^ ;w/;u vvD+F DFF ),F ]ËFF^믋F Pz;ÉFt ]3 ]U~u]ËF^K^F Ë^,*F N^Fu\;v FvƋv FDƋv3]ËF;F u ~ FDENjv3]ËF ;FsF),]ËF ;FuFvt^ ;vF),]ËFvDt^ ;u GD3]ËF^ FN^%F v3ۋFDÃ]VW333ҋyؾ _^VW3333 _^VW33ҋyu _^VW33ҋu33_^P _U _^VWu3_^P _F~|+y_^VWu3_^ F~|t +_^VWu33_^P _F~ | +y_^VWu33_^Pp _d _^QRZYQRZYQRZYQR ZYQRFZYQRfZYU썆F^ 0uމ^C0=%Fu\0=%uFPFPFPF tFF;F}CF䋶Fo+F ]U 썆F 0t|މ^C0=%Fu[0=%u0PFFPF PF P@FtFF;F}B 0PUFvHx ]P3XPx+u3;twH XUvvӋ]U2F^;sG0tFF=u3]vv v s]U>u*6u]á~ u]ËF @@H;Fv]ËF)^؋F]U졲]U63FF v:0-F FFFu F:F v:0F@(0%tJ~0uF0v:F:0%Fv:0@(0%tF F:0ÉFыv:0=.u7F:Fv:0@(0%tF F:0ÉFыv:0=lu F:FFv:0~tv>\ N^ v>3ɅyIN ^F yBV ^^ F1~tv>\ N^ v>3F ^F FHFF ^3ɺ v 0vR"F ^3ɺ x F ^F Fu~u FHB"-FF"^ظ +FF ^~tv>\ N^ v>3F ^FFH^ N3ہيJ"^ V^ FV^ F FuF"^ظ+FF ^>~tv>\ N^ v>3F ^F FH^ N3ہ0J"^ V^ FV^ F FuF"^ظ +FF ^~uFF F ;F}~>5<0tF v>^pF"F v>FN"VFOFHFA36]f0e0g0c0sk0o/xM/u.d]. .;0u.0y뿃~uFt;F }F FF )FF~ t?F HF xFFv<~FދFHFxQFFv<FFHFxFFv<FF HF xFFv<~FދFv@F:@6]Ã~uF~~FF@^"S^S^SvP^>7 v>^"NɉF N^y^~u~ t~}F~ tN3F~tF~t!F@^؋F^xF~t1F,FFFyF=cF~F~~F~ u)F;F~!^)^FHFxvt]ËvD]UF x=~ ]ËF ؁^t%@t ]ËFvDFD 0FtNFPvv =u3]Ã>t]ËvD]U Fx=~ ]ËF ؋%u  ]ËFO33ۅyKF^IFP Pv 壌4FP!Pv 壌 ]<t<t<t>t ]ËFF^^FP Pv| 壌t ]ÍFPPvT 壌t ]ËF^ ]UFx=~ ]ËF ؋%u ]øPvPvF 3]U v+D\0FFt\=tW~tQ^ u$vD0^CStP^kv\FvDF;FuF ]F~t9vD0vtP)v\\0FtDvD~uvD0 DF;F}vD0 DF=t%v\K\x 0vvFvD0%0t ]ËF ]UN u33F u33NFy3v3yڃu%x ;r+COu3ɋ)ѿ;r u;r+COu΋3FtFtڃ]þ@3^NV~ = r- GNu^NV~ ËF F FЉFFЉFFЉFË3Ã3ɿCK[ÃCOOyËF^NV NuF^NV U(FF v,DyN%u |u |u FFuNF txvN |F ϋFxA=7FF^NV ֊͊ߊĿOu% F 3333ҋv4Ft D\Lv2F(]U vDt0%t VPvD0Pv0t@Pv F@uPvFP3P3SvFG6vFF1PvFF3 ]] [[+...]]][...] Switches: Default state: /O off, /Q off and /V off. /A AFTER date. /A: /O OVERWRITE files. /B BEFORE date. /B: /Q QUERY each. /D DIRECTORY master. /T TODAY's date. /L LIST directory. /L /V VERIFY files. RESTORE version %.2f Copyright (c) 1982 Zenith Data Systems >Invalid exception file specifications. Invalid switch %s specified. Invalid date in switch. Too many parameters specified. Not enough parameters specified. Can not find master backup file %s. Invalid backup file.  Drive Filename Date Start End Size in Volume Volume bytes %-12s %s %3d %3d %7ld %d file(s) on %d volume(s) Invalid drive designation. Name Volumes Files Date %s %c:%-.8s %3d %4d %s Internal error in returning memory You have specified too many files for BACKUP sources.  Enter more than one BACKUP command to specify these files, or enter a single BACKUP command specifying fewer files as BACKUP sources. Invalid selection file specifications. Can not open master backup file %s, insert another disk and hit RETURN, or hit any other key to abort. No files selected.  Invalid version of RESTORE for file %s CON PRN Backup file name can not be ambiguous. Invalid filename. Extension on backup file specified. Extention 000 will be assumed. Invalid drive designation on backup file. Insert backup master volume 1, %s,in drive %c and hit RETURN when ready. Insert backup volume %d, %s, in drive %c Can not open master backup file %s, insert another disk in drive %c and hit RETURN when ready, Can not open backup file %s, insert another disk in drive %c Restore %s (Y/N) ? Files to be restored are: %-19sIs this correct (Y/N) ?Verifying %s Verify error, try restore again (Y/N) ? File %s already exists, do you wish to delete it (Y/N) ?%s Out of disk on restoration of %s, 6 ((((( H ((((( H 0123456789ABCDEF@ CONAUXCOM1LPT1PRNNULjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~ERASEDELTYPEREMCOPYPPAUSE DATE TIME  or $FMZ5 v3PȎغN): $E$n>EuÀ>At >St >At >FttGt+W£.Ž،ŽepG;+W£.Ž،(>At >Tt  #1 Ë(GG+G@rr)àú 3ۊ8u': $Unit contains $K of memory $192$128$ Testing 1st bank system memory...$ Testing 2nd bank system memory...$  Testing 3rd bank system memory...$ System memory test completed $>?EuÀ>?Bt >?At"2 @|n s>?At >?Rt"2| .`J< s>?At >?Gt"2J ? smS( ús  : $ETest of BLUE video plane ... $ETest of RED video plane ... $ETest of GREEN video plane ... $p rOË&:u &u ÊYtGOr UààuO@+r%r)r XQ*?Yr#Q'Yr Ê2ĪÊ2Įu r OOOO0r-OO !r‹OO .r OOQW&:u3&u2_YǀQWO&:u&u_YÊOG_Yr Uà'/àrQW_YǀQWu_YǀO_Y`(r%r6r )QGAZrRYr/&Qgo[2ra*YrÊQW2Ī_YǀÊQW2Įu_YǀO_Yа ݊ ݣ9 Šڰ ܋±ݰ ܊ð ܡ9 ݰ ܊ݡ9 آN GàN ۲" ٲ"tut ú ú E$jY8 Kk$ xú qx1$y1$Hô ô ôHôð ܊Ëа܋±ݰ܊ú $m70$ $&S@ۋa_[pq3%àpqð8ðP tXËVWؿ_^Üruqú~㋗k؎PX$0<:r $p q $ Data verify error $ Data parity error $at location H Expected data: H Actual data: H $E$!ô!ô!ô!ô !ô !ð !jkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~ERASEDELTYPEREMCOPYPPAUSE DATE TIME  or $F +ȁr . 3Ҵ!>] u |>lu>m u\ ul\ uQ2\cm= u] l u!@ H: u2hx\ Xs]SV   ^V $ m     3ҋ > QRaZY€ >  u ! 7uZ E!E#+ ٺ (! u2 t! XP  Z^[\rx ! ! !ú ! ! u!@H <~Ɋ  t o ú]밺; !2l>m u m ?xlr M =A>15: u   % lsð  ð R!ZË VWS  [_^ t :~vu0 FE E =r5D"FL Ft$F tN 3^  PSWK_[Z r&d&D&D&D V=^&Ds&L V^s]V ؎_ D2&ED 36&E&eDt&M&MDt&e؎H@t&EPD u&M D t&E( ÉÉÉÉËمtڊ2Kû <s36;tй r>Ô >âH@HARD DISK ERROR on CP/M drive $Source and destination drives must not be the same $Drive not available for CP/M reading $Insufficient disk space $No room in directory to create file $Source file(s) not found $File transfer complete $Cannot read 96 TPI disk on a 48 TPI drive $DIR ? Usage: RDCPM source [destination] -or- RDCPM DIR drive $ RDCPM version 1.16 Copyright(C) 1983 Zenith Data Systems RDCPM reads a file, file group, or directory from a disk that has been formatted using a CP/M compatible system and will copy the file(s) to a disk having been formatted with MS-DOS. The RDCPM command is similar to the COPY command, except that the source file(s) are expected to be on a CP/M disk. $ Where "source" is a CP/M filespec, and "destination" a Z-DOS filespec or drive name. $ RDCPM version 1.16 Copyright(C) 1983 Zenith Data Systems $ RDCPM version 1.16 Copyright(C) 1983 Zenith Data Systems $ ?      ;@error $at location H Expected data: H Actual data: H $E$!ô!ô!ô!ô !ô !ð !jkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~ERASEDELTYPEREMCOPYPPAUSE DATE TIME  or $FP,22, Q&&Y""&`>>>a?bcdefghi>>j>kUUUUlm*nopqrstuvwxyf<>>a?bcdefghi>>j>kUUUUlm*nopqrstuvwxyf<`?+@2AQM?QAWZZW[^\$]/^6_[`$ p "| "; <" = "<P,22, Q&&Y""&["> \"""&]"> ^"`>>>a?bcdefghi>>j>kUUUUlm*nopqrstuvwxyf<>j>kUUUUlm*nopqrstuvwxyf<:?_@"YZZY[m\#]+^&_?`$$$:    "<;"">""<""""="""""> P,22, Q&&Y""&["\"""]"""&^$$,"", `>>>a?bcdefghi>>j>kUUUUlm*nopqrstuvwxyf<""<""""i>>j>kUUUUlm*nopqrstuvwxyf<""P,22, Q&&Y""&[6 ?H6\&*2@]"`>>>a?bcdefghi>>j>kUUUUlm*nopqrstuvwxyf<""P,22, Q&&Y""&[6 ?H6\&*2@]"`i>>j>kUUUUlm*nopqrstuvwxyf<""<""""=">""P,22, Q&&Y""&["\"""]"`>>>a?bcdefghi>>j>kUUUUlm*nopqrstuvwxyf<""<""""=">""P,22, Q&&Y""&["\"""]"`i>>j>kUUUUlm*nopqrstuvwxyf<>>a?bcdefghi>>j>kUUUUlm*nopqrstuvwxyf<>j>kUUUUlm*nopqrstuvwxyf</?!@2M?WZZW[^\$]|^6_``>m,wzzw{=|\}~~}"""& "> " b$()B """;"> <$ p "|=" >@"P,22, Q&&Y""&["]">"6*"`>>>a?bcdefghi>>j>kUUUUlm*nopqrstuvwxyf<kUUUUlm*nopqrstuvwxyf< place to store string ; ; Returns: ; DI - updated ; ; Uses: AL, AH ; EIDBYTE PROC NEAR DB 0D4H,010H ; Separate hex digits in AH, AL XCHG AL,AH ; Change order for STOSB ADD AL,090H ; "Trick" procedure to convert to ASCII DAA ADC AL,040H DAA STOSB MOV AL,AH ADD AL,090H DAA ADC AL,040H DAA STOSB RET EIDBYTE ENDP SAVESP1 DW ? SAVEDS DW ? SAVEAX DW ? EIMESG DB CC_CR,CC_LF DB 'ERROR - MEMORY PARITY OR BUSS' DB CC_CR,CC_LF,CC_LF EIMESG1 DB "F =0000 IP=0000 CS=0000 DS=0000 ES=0000 SS=0000 SP=0000" DB CC_CR,CC_CR,CC_LF DB "AX=0000 BX=0000 CX=0000 DX=0000 DI=0000 SI=0000 BP=0000" DB CC_CR,CC_LF,CC_LF DB "SYSTEM HALT" DB CC_CR,CC_LF EIMESGL EQU (OFFSET $)-(OFFSET EIMESG) PAGE ; ; BIOS reserved function entry point trap ; (You get here if you do an BIOS call to a reserved entry point) ; BIOS_RES PROC FAR CLI ; Turn off interrupts INC WORD PTR CS:RECURLV ; Bump recursion level, first time through ? JNZ BIOS_RES1 ; No, skip MOV CS:SAVESS,SS ; Yes, save old stack MOV CS:SAVESP,SP PUSH CS ; Set up local stack POP SS MOV SP,OFFSET BIOS_SIZE+BIOS_WORKSP BIOS_RES1: STI ; Turn interrupts back on PUSH DS ; Save some regs PUSH AX PUSH CX PUSH BX PUSH CS ; Set up DS POP DS MOV BX,OFFSET RSMESG ; Get addr of message MOV CH,OFFSET RSMESGL ; Get length of message CALL PMESG ; Print message POP BX ; Restore the regs POP CX POP AX POP DS CLI ; Turn interrupts off (for a bit) DEC WORD PTR CS:RECURLV ; Decr recursion level, at bottom yet ? JNS BIOS_RES2 ; No, skip MOV SS,CS:SAVESS ; Yes, restore stack MOV SP,CS:SAVESP BIOS_RES2: STI ; Turn interrupts back on RET ; Return RSMESG DB CC_CR,CC_LF,CC_LF DB 'RESERVED BIOS ENTRY POINT CALLED' DB CC_CR,CC_LF,CC_LF RSMESGL EQU (OFFSET $)-(OFFSET RSMESG) BIOS_RES ENDP PAGE ; ; PMESG - Print a message on the console ; ; Call with: ; BX -> message to print ; CH = length of message ; ; Uses: AX, BX, CX ; PMESG PROC NEAR MOV AL,[BX] ; Get next character PUSH CS ; Make call into CALL FAR CALL NEAR PTR BIOS_CONOUT ; Print character in AL INC BX ; Bump char pointer DEC CH ; Decr remaining characters, Finished ? JNZ PMESG ; No, keep going RET ; Yes, return PMESG ENDP PAGE ; Recursion variables(so BIOS can call itself) RECURLV DW -1 ; Recursion level SAVESS DW ? ; Save area for SS SAVESP DW ? ; Save area for SP ; Font table information(must be together) FNT_INFO LABEL BYTE FNT_RAM DD ? ; Addr of font table setup at boot time FNT_ROM DD ? ; Addr of font table in ROM monitor FNT_SIZE DW ? ; Size of font table FNT_MSIZE DW ? ; Maximum size allocated for font table ; Memory information(Must be together) BIOS_MCL DB ZSM0+ZRM2+ZMCLPZ+ZMCLPK ; Select map 0 with ROM at top ; of addr space, parity gen and checking enabled BIOS_EDCNT DB 0 ; Error down counter ; Disk table DSKPR DB DSKPR_SIZE DUP(?) ; Parameter packet for call to DSK ; ; Configuration vector ; ; NOTE: ERRNZ macros can't be used in the config and ASP tables ; here (their conditionaled out of DEFMS.ASM) so anyone playing ; in this area PLEASE be careful! ; CONFG_INFO: DW OFFSET DSK_TPTR ; Addr of disk table vector DW OFFSET CHRD_PRN ; Addr of PRN: configuration table DW OFFSET CHRD_AUX ; Addr of AUX: configuration table DW OFFSET CHRD_CON ; Addr of CON: configuration table DW OFFSET FNT_INFO ; Addr of FONT information DW OFFSET BIOS_DATE_TIME ; Addr of date and time fields DW OFFSET DISK_TAB ; Addr of DOS disk table DW OFFSET BIOS_MCL ; Addr of Memory control info DW OFFSET BIOS_ASP ; Addr of aspect ration information DW OFFSET CQ_ZCON ; Addr of descriptor for CON que DW OFFSET CQ_ZSERA ; Addr of descriptor for Serial A que DW OFFSET CQ_ZSERB ; Addr of descriptor for Serial B que DW -1 BIOS_ASP LABEL NEAR DB ASP_X ; Aspect ratio X value DB ASP_Y ; Aspect ratio Y value ASP_LPEFV DW 5 ; Default light pen error ASP_LPHFV DB 0 ; Show no hits so far ASP_LPHCAV DW 0 ; Character address of hit ASP_LPHPAV DB 0 ; Pixel address of hit PRSC_IN_PROGRESS DB 0 ; != 0 if print screen in progress FNT_TAB: ; Start of font table (overlays Init code) SUBTTL BINIT - Initialization routines PAGE INCLUDE BINIT.ASM SUBTTL BCONIO - BIOS console entry points PAGE INCLUDE BCONIO.ASM SUBTTL BPRNIO - BIOS printer entry points PAGE INCLUDE BPRNIO.ASM SUBTTL BAUXIO - BIOS aux entry points PAGE INCLUDE BAUXIO.ASM SUBTTL BCLOCK - BIOS clock entry points and clock driver PAGE INCLUDE BCLOCK.ASM SUBTTL BDOSTB - Disk tables for MS-DOS PAGE INCLUDE BDOSTB.ASM BIOSP ENDP BIOS_SEG ENDS END  eaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaad %TYPE\G %NOSYS %TYPECreating Backup.... *.* %TYPEPlace Distribution Disk I back in drive A: %WAITand the backup copy of Disk I back in drive B: ~<< ``aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~DELTYPEREMCOPYPPAUSE DATE TIME  or $F PAGE ,132 TITLE BCHR - Character I/O routines .LFCOND .TFCOND ; ; BCHR - Character device I/O routines ; IF1 %OUT *Pass 1 started* ENDIF IF2 %OUT *Pass 2 started* ENDIF INCLUDE PARMS.ASM IF LISTI IF1 %OUT *Full listing being generated* ENDIF ELSE IF1 %OUT *Include files are not part of listing* ENDIF .XLIST ENDIF INCLUDE DEFMS.ASM INCLUDE DEFASCII.ASM INCLUDE DEFCONFG.ASM INCLUDE DEFIPAGE.ASM INCLUDE DEFMTR.ASM  INCLUDE DEF6821.ASM INCLUDE DEF6845.ASM INCLUDE DEFEP2.ASM INCLUDE DEFCHR.ASM INCLUDE DEF8259A.ASM INCLUDE MACLIB.ASM .LIST PAGE BIOS_SEG SEGMENT PUBLIC 'BIOSCODE' ASSUME CS:BIOS_SEG,DS:BIOS_SEG,ES:NOTHING,SS:BIOS_SEG EXTRN ASP_LPEFV:WORD EXTRN ASP_LPHCAV:WORD EXTRN ASP_LPHPAV:BYTE EXTRN ASP_LPHFV:BYTE EXTRN RECURLV:WORD EXTRN SAVESS:WORD EXTRN SAVESP:WORD EXTRN BIOS_SIZE:NEAR EXTRN PRSC_IN_PROGRESS:BYTE PUBLIC CQ_ZSERA PUBLIC CQ_ZSERB PUBLIC CQ_ZCON PUBLIC BIOS_PRNFUNC PUBLIC BIOS_AUXFUNC PUBLIC BIOS_CONFUNC PUBLIC CHRD_PRN PUBLIC CHRD_AUX PUBLIC CHRD_CON PUBLIC ISR_KD PUBLIC ISR_UKB PUBLIC ISR_UCRT PUBLIC ISR_PRSC PUBLIC KQ_PUT PUBLIC ISR_SA PUBLIC ISR_USAI PUBLIC ISR_USAO PUBLIC ISR_SB PUBLIC ISR_USBI PUBLIC ISR_USBO PUBLIC ISR_ULP PUBLIC VSYNC_CNT PUBLIC VIDEO_ROM PUBLIC VIDEO_PGM PAGE INCLUDE BCHRIO.ASM BIOS_SEG ENDS END  PAGE ,132 TITLE BDSK - Disk routines for MS-DOS BIOS .LFCOND .TFCOND IF1 %OUT *Pass 1 started* ENDIF IF2 %OUT *Pass 2 started* ENDIF INCLUDE PARMS.ASM IF LISTI IF1 %OUT *Full listing being generated* ENDIF ELSE IF1 %OUT *Include files are not part of listing* ENDIF .XLIST ENDIF INCLUDE DEFCONFG.ASM INCLUDE DEFASCII.ASM INCLUDE DEFMS.ASM INCLUDE DEFZ207.ASM INCLUDE DEFZ217.ASM INCLUDE DEFSBC.ASM INCLUDE DEFDSK.ASM INCLUDE MACLIB.ASM .LIST PAGE BIOS_SEG SEGMENT PUBLIC 'BIOSCODE' ASSUME CS:BIOS_SEG,DS:BIOS_SEG,ES:NOTHING,SS:BIOS_SEG EXTRN RECURLV:WORD EXTRN SAVESS:WORD EXTRN SAVESP:WORD EXTRN DSKPR:BYTE EXTRN PMESG:NEAR EXTRN BIOS_CONIN:FAR EXTRN BIOS_FLUSH:FAR EXTRN BIOS_SIZE:NEAR EXTRN ALARM_ST:NEAR EXTRN ALARM_CK:NEAR EXTRN ALARM_SP:NEAR EXTRN ALARM_WAIT:NEAR PUBLIC BIOS_READ PUBLIC BIOS_WRITE PUBLIC BIOS_DSKCHG PUBLIC BIOS_MAPDEV PUBLIC BIOS_DSKFUNC PUBLIC DSK_TPTR PUBLIC DSK PUBLIC DSKT_FG PUBLIC DSKT_PORT PUBLIC DSKT_DNCTR PUBLIC DSKT_DSEL IF WINCH PUBLIC DSK_WCB PUBLIC DISK4 PUBLIC DISK5 ENDIF PAGE INCLUDE BDSKLA.ASM PAGE INCLUDE BDSKIO.ASM PAGE INCLUDE DSK.ASM PAGE INCLUDE BDSKTB.ASM BIOS_SEG ENDS END effgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~DELTYPEREMCOPYPPAUSE DATE TIME  or $F PAGE ,132 TITLE BEND - End of BIOS .LFCOND .TFCOND INCLUDE PARMS.ASM BIOS_SEG SEGMENT PUBLIC 'BIOSCODE' ASSUME CS:BIOS_SEG,DS:BIOS_SEG,ES:NOTHING,SS:BIOS_SEG PUBLIC BIOS_SIZE BIOS_SIZE: DB 0 BIOS_SEG ENDS END PAGE INCLUDE BDSKTB.ASM BIOS_SEG ENDS END effgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~DELTYPEREMCOPYPPAUSE DATE TIME  or $F; ; ASCII characters ; CC_NUL EQU 0 CC_SOH EQU 1 CC_STX EQU 2 CC_ETX EQU 3 CC_EOT EQU 4 CC_ENQ EQU 5 CC_ACK EQU 6 CC_BEL EQU 7 CC_BS EQU 8 CC_HT EQU 9 CC_LF EQU 10 CC_VT EQU 11 CC_FF EQU 12 CC_CR EQU 13 CC_SO EQU 14 CC_SI EQU 15 CC_DLE EQU 16 CC_DC1 EQU 17 CC_DC2 EQU 18 CC_DC3 EQU 19 CC_DC4 EQU 20 CC_NAK EQU 21 CC_SYN EQU 22 CC_ETB EQU 23 CC_CAN EQU 24 CC_EM EQU 25 CC_SUB EQU 26 CC_ESC EQU 27 CC_FS EQU 28 CC_GS EQU 29 CC_RS EQU 30 CC_US EQU 31 CC_SP EQU 32 CS:BIOS_SEG,DS:BIOS_SEG,ES:NOTHING,SS:BIOS_SEG PUBLIC BIOS_SIZE BIOS_SIZE: DB 0 BIOS_SEG ENDS END PAGE INCLUDE BDSKTB.ASM BIOS_SEG ENDS END effgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~DELTYPEREMCOPYPPAUSE DATE TIME  or $F; ; Configuration type info ; Z207A EQU 0B0H ; First Z-207 disk controller base port ; (See DEFZ207 to program controller) Z217A EQU 0AEH ; Reserved for future use ZGRNSEG EQU 0E000H ; Segment of green video plane ZREDSEG EQU 0D000H ; Segment of red video plane ZBLUSEG EQU 0C000H ; Segment of blue video plane ZVIDEO EQU 0D8H ; Video 68A21 port ; PA0 -> enable red display ; PA1 -> enable green display ; PA2 -> enable blue display ; PA3 -> not flash screen ; PA4 -> not write multiple red ; PA5 -> not write multiple green ; PA6 -> not write multiple blue ; PA7 -> disable video RAM ; PB7-PB0 -> LA15-LA8 ; CA1 - not used ; CA2 -> clear screen ; CB1 - not used ; CB2 -> value to write (0 or 1) on clear screen ; (see DEF6821 to program the 6821) ZCRTC EQU 0DCH ; Video 6845 CRT-C port ; (see DEF6845 to program the 6845) ZLPEN EQU 0DEH ; Light pen latch ZLPEN_BIT EQU 00000111B ; Bit hit by pen ZLPEN_ROW EQU 11110000B ; Row hit by pen ZP IA EQU 0E0H ; Parallel printer plus light pen and ; video vertical retrace 68A21 port ; PA0 -> PDATA1 ; PA1 -> PDATA2 ; PA2 -> not STROBE ; PA3 -> not INIT ; PA4 <- VSYNC ; PA5 -> clear VSYNC flip flop ; PA6 <- light pen switch ; PA7 -> clear light pen flip flop ; PB0 <- BUSY ; PB1 <- not ERROR ; PB2 -> PDATA3 ; PB3 -> PDATA4 ; PB4 -> PDATA5 ; PB5 -> PDATA6 ; PB6 -> PDATA7 ; PB7 -> PDATA8 ; CA1 <- light pen hit (from flip flop) ; CA2 <- VSYNC (from flip flop) ; CB1 <- not ACKNLG ; CB2 <- BUSY ; (See DEF6821 to program the PIA) ZTIMER EQU 0E4H ; Timer 8253 port ZTIMEVAL EQU 2500 ; 100ms divide by N value ; (See DEF8253 to program the 8253) ZTIMERS EQU 0FBH ; Timer interrupt status port ZTIMERS0 EQU 001H ; Timer 0 interrupt ZTIMERS2 EQU 002H ; Timer 2 interrupt ZSERA EQU 0E8H ; First 2661-2 serial port ZSERB EQU 0ECH ; Second 2661-2 serial port ; (See DEFEP2 to program 2661-2) ZM8259A EQU 0F2H ; Master 8259A interrupt controller port ZINTEI EQU 0 ; Parity error or S-100 pin 98 interrupt ZINTPS EQU 1 ; Processor swap interrupt ZINTTIM EQU 2 ; Timer interrupt ZINTSLV EQU 3 ; Slave 8259A interrupt ZINTSA EQU 4 ; Serial port A interrupt ZINTSB EQU 5 ; Serial port B interrupt ZINTKD EQU 6 ; Keyboard, Display, or Light pen interrupt ZINTPP EQU 7 ; Parallel port interrupt ; (See DEF8259A to program the 8259A) ZM8259AI  EQU 64 ; Base interrupt number for master ZS8259A EQU 0F0H ; Secondary 8259A interrupt controller port ZS8259AI EQU 72 ; Base interrupt number for slave BIOSAI EQU ZS8259AI+8 ; Base of BIOS generated interrupts ZKEYBRD EQU 0F4H ; Keyboard port ZKEYBRDD EQU ZKEYBRD+0 ; Keyboard data port ZKEYBRDC EQU ZKEYBRD+1 ; Keyboard command port ZKEYRES EQU 0 ; Reset command ZKEYARD EQU 1 ; Autorepeat on command ZKEYARF EQU 2 ; Autorepeat off command ZKEYKCO EQU 3 ; Key click on command ZKEYKCF EQU 4 ; Key click off command ZKEYCF EQU 5 ; Clear keyboard FIFO command ZKEYCLK EQU 6 ; Generate a click sound command ZKEYBEP EQU 7 ; Generate a beep sound command ZKEYEK EQU 8 ; Enable keyboard command ZKEYDK EQU 9 ; Disable keyboard command ZKEYUDM EQU 10 ; Enter UP/DOWN mode command ZKEYNSM EQU 11 ; Enter normal scan mode command  ZKEYEI EQU 12 ; Enable keyboard interrupts command ZKEYDI EQU 13 ; Disable keyboard interrupts command ZKEYBRDS EQU ZKEYBRD+1 ; Keyboard status port ZKEYOBF EQU 001H ; Output buffer not empty ZKEYIBF EQU 002H ; Input buffer full ZMCL EQU 0FCH ; Memory control latch ZMCLMS EQU 00000011B ; Map select mask ZSM0 EQU 0 ; Map select 0 ZSM1 EQU 1 ; Map select 1 ZSM2 EQU 2 ; Map select 2 ZSM3 EQU 3 ; Map select 3 ZMCLRM EQU 00001100B ; Monitor ROM mapping mask ZRM0 EQU 0*4 ; Power up mode - ROM everywhere on reads ZRM1 EQU 1*4 ; ROM at top of every 64K page ZRM2 EQU 2*4 ; ROM at top of 8088's addr space ZRM3 EQU 3*4 ; Disable ROM ZMCLPZ EQU 00010000B ; 0=Set Parity to the zero state ZMCLPK EQU 00100000B ; 0=Disable parity checking circuity Z205BA EQU 098H ; Base address for Z-205 boards Z205BMC EQU 8 ; Maximum of 8 Z-205 boards installed ZHAL EQU 0FDH ; Hi-address latch ZHAL85 EQU 0FFH ; 8085 Mask ZHAL88 EQU 0F0H ; 8088 Mask ZPSP EQU 0FEH ; Processor swap port ZPSPPS EQU 10000000B ; Processor select (0=8085, 1=8088) ZPSPPS5 EQU 00000000B ; Select 8085 ZPSPPS8 EQU 10000000B ; Select 8088 ZPSPSI EQU 00000010B ; Generate interrupt on swapping ZPSPI8 EQU 00000001B ; 8088 processes all interrupts ZDIPSW EQU 0FFH ; Configuration dip switches ZDIPSWBOOT EQU 00000111B  ; Boot device field ZDIPSWAB EQU 00001000B ; 1=Auto boot(0=Manual boot) ZDIPSWRES EQU 01110000B ; Reserved ZDIPSWHZ EQU 10000000B ; 1=50Hz(0=60HZ) PAGE INCLUDE BDSKTB.ASM BIOS_SEG ENDS END effgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~DELTYPEREMCOPYPPAUSE DATE TIME  or $F; ; Definitions for the Monitor ROM ; ; Entry points to ROM monitor MTR_SEG SEGMENT AT 0FE01H ; Segment addr for Monitor ROM calls ORG 000H MTR_RES LABEL FAR ; Reset function ORG 005H MTR_MON LABEL FAR ; Monitor call ORG 00AH MTR_SWIM LABEL FAR ; Trace/breakpoint handler ORG 00FH MTR_DCRT LABEL FAR ; Dumb display output ORG 014H MTR_DKBD LABEL FAR ; Dumb keyboard handler ORG 019H MTR_SCRT LABEL FAR ; Smart display output ORG 01EH MTR_SKBD LABEL FAR ; Smart keyboard input ORG 023H MTR_TTY_INTR LABEL FAR ; Vertical retrace interrupt handler MTR_SEG ENDS MTR_D_SEG SEGMENT AT 0 ; ROM Monitor data segment(not really located at 0) ORG 000H ; Monitor Parameters MTR_WIP LABEL FAR ; Far jump to wild interrupt handler DB 5 DUP(?) ; the far jump MTR_VER DB ? ; BCD version of ROM monitor MTR_CVER EQU 01H ; Lowest version BIOS can run on MTR_DS_SIZE DW ? ; Size of the ROM monitor data segment ; Boot parameters MTR_BINDX DB ? ; Boot device index MTR_BPORT DB ? ; Boot device base port number MTR_BSTRING DB 80 DUP(?) ; Boot string MTR_BUNIT DB ? ; Boot unit number ; Pointers to All sorts of things MTR_DCI DD ? ; Addr of Display Character Initialization Routine MTR_DFC DD ? ; Addr of Display Font Character Routine MTR_DXMTC DD ? ; Addr of Dumb Keyboard Transmit Character Routine MTR_EDC DD ? ; Addr of Erase Display Character Routine MTR_EMEC DD ? ; Addr of Extended-Mode Escape Character Handler Routine MTR_FONT DD ? ; Addr of Character Font table MTR_FNT_SIZE EQU 9*(256-' ') ; Size of reserved font table(number of bytes copied from rom font area if version = 1) MTR_MDC DD ? ; Addr of Move Display Characters Routine MTR_MDL DD ? ; Addr of Move Display Line Routine MTR_PROMPT DD ? ; Addr of Display ROM Monitor Prompt Routine MTR_RDC DD ? ; Addr of Read Displayed Character Routine MTR_SXMTC DD ? ; Addr of Smart Keyboard Transmit Character Routine MTR_UIES DD ? ; Addr of Unimplemented Escape Sequence Handler Routine MTR_XCA DD ? ; Addr of Transmit Character Attributes Routine ; If version = 1, next word is not present, and all references must have ; -2 added to them for labels beyond this point MTR_FNTSIZ DW ? ; Size of FONT in bytes (If version > 1) MTR_KYB DB 256 DUP (?) ; Keyboard map table MTR_CHR DB 256 DUP (?) ; Display map table MTR_HORP DB ? ; Horizontal position of cursor (column) MTR_VERP DB ? ; Vertical position of cursor (row) MTR_MIB DB ? ; Base interrupt number for master MTR_SIB DB ? ; Base interrupt number for slave MTR_RESF DB ? ; Reset flag to re-enter monitor MTR_D_SEG ENDS IPAGE_SEG SEGMENT AT 0 ; The interrupt area page ORG 03FEH MTR_DS LABEL WORD ; Location that contains monitor DS value IPAGE_SEG ENDS effgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~DELTYPEREMCOPYPPAUSE DATE TIME  or $F ; ; DEFFMT - Loader/Format definitions ; ; DEFFMT defines the format table at the head ; of the loader. The data is placed here by the ; FORMAT utility, and used during boot by the ; loader to determine disk layout and by the ; BIOS to boot itself and the DOS. ; FMT_OFFSET EQU 3 ; Offset of table into start of loader ; MicroSoft(MS) defined entries of table FMT_VER EQU 0 ; Version of table FMT_CVER EQU 01H ; Current version FMT_SECS EQU FMT_VER+1 ; Sector size of disk(in bytes) FMT_CLF EQU FMT_SECS+2 ; Cluster factor FMT_NRS EQU FMT_CLF+1 ; Number of reserved sectors FMT_FATS EQU FMT_NRS+2 ; Number of FATs FMT_DIRS EQU FMT_FATS+1 ; Number if directory entries FMT_NPS EQU FMT_DIRS+2 ; Number of physical sectors ; Zenith Data System(ZDS) defined entries of table FMT_SHFT EQU FMT_NPS+2 ; Shift count (Log2 SECS) FMT_SPT EQU FMT_SHFT+1 ; Sectors/track FMT_DATA EQU FMT_SPT+1 ; Data area sector number FMT_CLST EQU FMT_DATA+2 ; Shift count (Log2 cluster size) FMT_DIR EQU FMT_CLST+1 ; Directory area sector number FMT_FLG EQU FMT_DIR+2 ; Flag byte (DSK_FLAG) FMT_SEL EQU FMT_FLG+1 ; Select byte (DSK_SEL) FMT_PORT EQU FMT_SEL+1 ; Port number of controller FMT_SIZE EQU FMT_PORT+2 ; Size of FMT table effgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~DELTYPEREMCOPYPPAUSE DATE TIME  or $F; ; Definitions for 6821 Peripheral interface adapter(PIA) ; ; Register displacements PIADATA EQU 0 ;PERIPHERAL DATA REGISTER A PIADDRA EQU 0 ;DATA DIRECTION REGISTER A PIACTLA EQU 1 ;CONTROL REGISTER A PIADATB EQU 2 ;PERIPHERAL DATA REGISTER B PIADDRB EQU 2 ;DATA DIRECTION REGISTER B PIACTLB EQU 3 ;CONTROL REGISTER B ; CONTROL WORD FORMAT PIAC1 EQU 00000011B ;CONTROL OF CA1(CB1) INTERRUPT LINE PIAC10 EQU 00H ; ACTIVE TRANSITION 1->0 ; IRQ PIN IS DISABLED PIAC11 EQU 01H ; ACTIVE TRANSITION 1->0 ; IRQ PIN IS ENABLED PIAC12 EQU 02H ; ACTIVE TRANSITION 0->1 ; IRQ PIN IS DISABLED PIAC13 EQU 03H ; ACTIVE TRANSITION 0->1 ; IRQ PIN IS ENABLED PIADDAC EQU 00000100B ;DATA DIRECTION ACCESS CONTROL BIT ; 0=DATA DIRECTION REG, 1=PERIPHERAL DATA REG PIAC2 EQU 00111000B ;CONTROL OF CA2(CB2) ; INPUT MODES PIAC20 EQU 00H ; ACTIVE TRANSITION 1->0 ; IRQ PIN IS DISABLED PIAC21 EQU 08H ; ACTIVE TRANSITION 1->0 ; IRQ PIN IS ENABLED PIAC22 EQU 10H ; ACTIVE TRANSITION 0->1 ; IRQ PIN IS DISABLED PIAC23 EQU 18H ; ACTIVE TRANSITION 0->1 ; IRQ PIN IS ENABLED ; OUTPUT MODES PIAC24 EQU 20H ; 0 ON R(W) OPERATION, 1 ON ACTIVE CA1(CB1) PIAC25 EQU 28H ; 0 ON R(W) OPERATION, 1 ON E AFTER DESELECT PIAC26 EQU 30H ; RESET PIAC27 EQU 38H ; SET PIAIRQ2 EQU 01000000B ;IRQ FOR CA2(CB2) PIAIRQ1 EQU 10000000B ;IRQ FOR CA1(CB1)  ; ; Definitions for Enhanced programmable communication interface chip 2661-2 ; ; PORT DISPLACEMENTS EPDATA EQU 0 ;DATA EPSTAT EQU 1 ;STATUS EPSYN EQU 1 ;SYN1/SYN2/DLE EPMODE EQU 2 ;MODE EPCMD EQU 3 ;COMMAND ; STATUS REGISTER EPTXR EQU 00000001B ;TRANSMITTER READY EPRXR EQU 00000010B ;RECEIVER READY EPTXE EQU 00000100B ;TRANSMITTER EMPTY EPDSC EQU 00000100B ;DATA SET CHANGE EPPE EQU 00001000B ;PARITY ERROR EPOE EQU 00010000B ;OVERRUN ERROR EPFE EQU 00100000B ;FRAME ERROR EPSD EQU 00100000B ;SYNC DETECTED EPDCD EQU 01000000B ;DATA CARRIER DETECT EPDSR EQU 10000000B ;DATA SET READY ; MODE REGISTER 1 EPMBRF EQU 00000011B ;MODE AND BAUDRATE FACTOR EPS1X EQU 000H ; SYNCHRONOUS 1X RATE EPA1X EQU 001H ; ASYNCHRONOUS 1X RATE EPA16X EQU 002H ; ASYNCHRONOUS 16X RATE EPA64X EQU 003H ; ASYNCHRONOUS 64X RATE EPCL EQU 00001100B ;CHARACTER LENGTH EPCL5 EQU 000H ; LENGTH 5 EPCL6 EQU 004H ; LENGTH 6 EPCL7 EQU 008H ; LENGTH 7 EPCL8 EQU 00CH ; LENGTH 8 EPPC EQU 00010000B ;PARITY CONTROL (0=DISABLED , 1=ENABLED) EPPT EQU 00100000B ;PARITY TYPE (0=ODD , 1=EVEN) EPASBL EQU 11000000B ;ASYNCHRONOUS STOP BIT LENGTH EPSB1 EQU 040H ; LENGTH 1 EPSB15 EQU 080H ; LENGTH 1.5 EPSB2 EQU 0C0H ; LENGTH 2 EPSTC EQU 01000000B ;SYNCHRONOUS TRANSPARENCY CONTROL ; (0=NORMAL , 1=TRANSPARENT) EPNSC EQU 10000000B ;NUMBER OF SYNC CHARACTERS ; (0=DOUBLE , 1=SINGLE) ; MODE REGISTER 2 EPBRS EQU 00001111B ;BAUD RATE SELECTION EPMR2U EQU 11110000B ;SEE TEXT  EPMR2A EQU 70H ;VALUE FOR ASYNC OPERATION ; COMMAND REGISTER EPTXEN EQU 00000001B ;TRANSMITTER ENABLE EPDTR EQU 00000010B ;DATA TERMINAL READY EPRXEN EQU 00000100B ;RECEIVER ENABLE EPSBRK EQU 00001000B ;SEND BREAK (ASYNC) EPSDLE EQU 00001000B ;SEND DLE (SYNC) EPRESE EQU 00010000B ;RESET STATUS ERRORS EPRTS EQU 00100000B ;REQUEST TO SEND EPOM EQU 11000000B ;OPERATING MODE EPNORM EQU 000H ; NORMAL EPOM1 EQU 040H ; MODE 1 EPOMLL EQU 080H ; LOCAL LOOP BACK EPOMRL EQU 0C0H ; REMOTE LOOP BACK ; BAUDRATE SELECTION VALUES EPB455 EQU 0 ;45.5 EPB050 EQU 1 ;50 EPB075 EQU 2 ;75 EPB110 EQU 3 ;110 EPB134 EQU 4 ;134.5 EPB150 EQU 5 ;150 EPB300 EQU 6 ;300 EPB600 EQU 7 ;600 EPB120 EQU 8 ;1200 EPB180 EQU 9 ;1800 EPB200 EQU 10 ;2000 EPB240 EQU 11 ;2400 EPB480 EQU 12 ;4800 EPB960 EQU 13 ;9600 EPB192 EQU 14 ;19200 EPB384 EQU 15 ;38400 EPBMAX EQU EPB384 ;MAX BAUD RATE  ; ; DEFCHR - Definitions for the character devices (CON, AUX, and PRN) ; ; Define functions of BIOS_CONFUNC, BIOS_PRNFUNC, and BIOS_AUXFUNC CHR_WRITE EQU 0 ; Write function CHR_READ EQU CHR_WRITE+1 ; Read function CHR_STATUS EQU CHR_READ+1 ; Status function CHR_SFGS EQU 0 ; Get status subfunction CHRS_WA EQU 00000001B ; sent, waiting for CHRS_WD EQU 00000010B ; seen, waiting for CHRS_SN EQU 00000100B ; Sending nulls CHRS_TXR EQU 10000000B ; Transmitter ready to send data CHRS_RXR EQU 01000000B ; Receiver has data CHRS_RXOF EQU 00100000B ; Receiver queue overflow CHRS_RXE EQU 00010000B ; Other type of reciver error CHRS_TXE EQU 00001000B ; Transmitter error CHR_SFGC EQU CHR_SFGS+1 ; Get configuration info subfunction CHR_CONTROL EQU CHR_STATUS+1 ; Control function CHR_CFSU EQU 0 ; Setup new configuration parms subfunction CHR_CFCI EQU CHR_CFSU+1 ;  Clear input subfunction CHR_CFCO EQU CHR_CFCI+1 ; Clear output subfunction CHR_LOOK EQU CHR_CONTROL+1; Nondestructive read function CHR_FMAX EQU CHR_LOOK ; Maximum function number ; Configuration information packet CHRD_CLASS EQU 0 ; Device class CHRDCL_CRT EQU 0 ; Internal keyboard/display CHRDCL_SER EQU CHRDCL_CRT+1; 2661 serial port CHRDCL_PAR EQU CHRDCL_SER+1; PIA parallel port CHRDCL_MAX EQU CHRDCL_PAR ; Maximum class value CHRD_ATTR EQU CHRD_CLASS+1 ; Attributes CHRDA_SPI EQU 00000001B ; Strip parity on input CHRDA_SPO EQU 00000010B ; Strip parity on output CHRDA_MLI EQU 00000100B ; Map lower to upper case on input CHRDA_MLO EQU 00001000B ; Map lower to upper case on output ; The remaining fields are used only with the 2661 serial ports ; (except CHRD_NCHR and CHRD_NCNT which can be used by para printer) CHRD_PORT EQU CHRD_ATTR+1 ; Port number CHRD_BAUD EQU CHRD_PORT+2 ; Baud rate BD455 EQU 0 ; 45.5 BD050 EQU 1 ; 50 BD075 EQU 2 ; 75 BD110 EQU 3 ; 110 BD134 EQU 4 ; 134.5 BD150 EQU 5 ; 150 BD300 EQU 6 ; 300 BD600 EQU 7 ; 600 BD120 EQU 8 ; 1200 BD180 EQU 9 ; 1800 BD200 EQU 10 ; 2000 BD240 EQU 11 ; 2400 BD480 EQU 12 ; 4800 BD960 EQU 13 ; 9600 BD192 EQU 14 ; 19200 BD384 EQU 15 ; 38400 BDMAX EQU BD384 ; Maximum valid baud rate CHRD_HSHK EQU CHRD_BAUD+1 ; Handshaking protocol CHRDH_NO EQU 0 ; None CHRDH_EAH EQU CHRDH_NO+1 ; / CHRDH_DCH EQU CHRDH_EAH+1 ; / (CTRL-S/CTRL-Q) CHRDH_DCDH EQU CHRDH_DCH+1 ; DCD(data carrier detect) high CHRDH_DCDL EQU CHRDH_DCDH+1; DCD low CHRDH_DSRH EQU CHRDH_DCDL+1; DSR(data set ready) high CHRDH_DSRL EQU CHRDH_DSRH+1; DSR low CHRDH_MAX EQU CHRDH_DSRL ; Maximum valid value CHRD_BCTL EQU CHRD_HSHK+1 ; Stop bits/parity/char length ; (2661 Mode register 1) CHRDB_SB EQU 11000000B ; Stop bits CHRDB_SB1 EQU 040H ; 1 stop bit CHRDB_SB15 EQU 080H ; 1.5 stop bits CHRDB_SB2 EQU 0C0H ; 2 stop bits CHRDB_PT EQU 00100000B ; Parity type(0=odd, 1=even) CHRDB_PC EQU 00010000B ; Parity contr(0=disabled, 1=enabled) CHRDB_CL EQU 00001100B ; Character length CHRDB_CL5 EQU 00H ; 5 bits CHRDB_CL6 EQU 04H ; 6 bits CHRDB_CL7 EQU 08H ; 7 bits CHRDB_CL8 EQU 0CH ; 8 bits CHRD_ECNT EQU CHRD_BCTL+1 ; If / used, chars to ; send before sent CHRD_NCNT EQU CHRD_ECNT+1 ; Number of NULLs to send after ; CHRD_NCHR seen CHRD_NCHR EQU CHRD_NCNT+1 ; Character after which to send NULLs CHRD_RES EQU CHRD_NCHR+1 ; Reserved for future use CHRD_SIZE EQU CHRD_RES+6 ; Size of a CHRD ; Error codes that are returned CHRE_ILGFH EQU 0 ; Illegal function code in AH CHRE_ILGFL EQU CHRE_ILGFH+1; Illegal function code in AL CHRE_NWR EQU CHRE_ILGFL+1; No writes allowed to device CHRE_NRD EQU CHRE_NWR+1 ; No reads allowed to device CHRE_BSUP EQU CHRE_NRD+1 ; Bad set up parameters CHRE_WRB EQU CHRE_BSUP+1 ; Device busy on write CHRE_RDNR EQU CHRE_WRB+1 ; Device not ready on read CHRE_HTO EQU CHRE_RDNR+1 ; Software handshake time out CHRE_ILR EQU CHRE_HTO+1 ; Illegal responce from device CHRE_IQE EQU CHRE_ILR+1 ; Input queue empty CHRE_NIQ EQU CHRE_IQE+1 ; Device has no input queue ; Internal character device control table(It includes an embedded CHRD) CID_CHRD EQU 0 ; A CHRD CID_CLASS EQU CID_CHRD+CHRD_SIZE ; Class of character device ; (must be mult of 2) CIDCL_CRT EQU CHRDCL_CRT*2 ; Internal video/keyboard CIDCL_SER EQU CHRDCL_SER*2 ; 2661 serial port CIDCL_PAR EQU CHRDCL_PAR*2 ; PIA parallel port CID_TYPE EQU CID_CLASS+2 ; Special types CIDTY_NORM EQU 0 ; Normal type CIDTY_CSP EQU CIDTY_NORM+1 ; Special CRT CID_IPORT EQU CID_TYPE+2 ; Input port CID_OPORT EQU CID_IPORT+2 ; Output port CID_SPORT EQU CID_OPORT+2 ; Status port CID _CPORT EQU CID_SPORT+2 ; Control port CID_ST EQU CID_CPORT+2 ; Status(see CHRD_SFGS for values) CID_IRM EQU CID_ST+1 ; Input ready mask CID_IPM EQU CID_IRM+1 ; Input polarity mask CID_ORM EQU CID_IPM+1 ; Output ready mask CID_OPM EQU CID_ORM+1 ; Output polarity mask CID_ECTR EQU CID_OPM+1 ; Char counter for sending CID_NCTR EQU CID_ECTR+1 ; Null down counter CID_SIZE EQU CID_NCTR+1 ; Size of the a CID ; ; Define input queue for character devices ; CQ_SADDR EQU 0 ; Addr of start of queue CQ_EADDR EQU CQ_SADDR+2 ; Addr of end of queue CQ_QSIZE EQU CQ_EADDR+2 ; Size of queue CQ_ELMTS EQU CQ_QSIZE+2 ; Number of elements currently in queue CQ_STATUS EQU CQ_ELMTS+2 ; Status (as defined under CHR_STATUS) CQ_FRONT EQU CQ_STATUS+1 ; Addr of first element in queue CQ_REAR EQU CQ_FRONT+2 ; Addr of last element in queue CQ_SEGM EQU CQ_REAR+2 ; Segment of que CQ_SIZE EQU CQ_SEGM+2 ; Size of a CQ ; ; Definitions for 8253 programmable interval timer ; ; PORT DISPLACEMENTS PITC0 EQU 000H ;COUNTER 0 PITC1 EQU 001H ;COUNTER 1 PITC2 EQU 002H ;COUNTER 2 PITCW EQU 003H ;CONTROL WORD ; CONTROL WORD PITSC EQU 11000000B ;SELECT COUNTER PITSC0 EQU 000H ; 0 PITSC1 EQU 040H ; 1 PITSC2 EQU 080H ; 2 PITRL EQU 00110000B ;READ/LOAD PITRLCL EQU 000H ; COUNTER LATCHING OPERATION PITRLMB EQU 010H ; MSB PITRLLB EQU 020H ; LSB PITRLW EQU 030H ; WORD PITM EQU 00001110B ;MODE PITMITC EQU 000H ; 0 - INTERRUPT ON TERMINAL COUNT PITMP1S EQU 002H ; 1 - PROGRAMMABLE ONE SHOT PITMRG EQU 004H ; 2 - RATE GENERATOR PITMSW EQU 006H ; 3 - SQUARE WAVE RATE GENERATOR PITMSTS EQU 008H ; 4 - SOFTWARE TRIGGERED STROBE PITMHTS EQU 00AH ; 5 - HARDWARE TRIGGERED STROBE PITBCD EQU 00000001B ;0 = 16 BIT BINARY COUNTER ;1 = 4 DIGIT BCD COUNTER effgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~DELTYPEREMCOPYPPAUSE DATE TIME  or $F; ; Definitions for 8259A interrupt controller ; ; REGISTER DISPLACEMENTS ICW1 EQU 0 ;ICW1 ICW2 EQU 1 ;ICW2 ICW3 EQU 1 ;ICW3 ICW4 EQU 1 ;ICW4 OCW1 EQU 1 ;OCW1 OCW2 EQU 0 ;OCW2 OCW3 EQU 0 ;OCW3 ; ICW1 REGISTER FLAGS ICW1A EQU 11100000B ;A7-A5 ICW1OP EQU 00010000B ;1=ICW1 , 0=OCW'S ICW1LT EQU 00001000B ;TRIGGER MODE (0=EDGE , 1=LEVEL) ICW1ADI EQU 00000100B ;CALL INTERVAL (0=8 , 1=4) ICW1SNG EQU 00000010B ;0=CASCADE , 1=SINGLE ICW1IL4 EQU 00000001B ;ICW4 (0=NOT USED , 1=USED)  ; ICW3 REGISTER FLAGS (MASTER DEVICE) ICW3S0 EQU 00000001B ;IR INPUT 0 HAS SLAVE ICW3S1 EQU 00000010B ;IR INPUT 1 HAS SLAVE ICW3S2 EQU 00000100B ;IR INPUT 2 HAS SLAVE ICW3S3 EQU 00001000B ;IR INPUT 3 HAS SLAVE ICW3S4 EQU 00010000B ;IR INPUT 4 HAS SLAVE ICW3S5 EQU 00100000B ;IR INPUT 5 HAS SLAVE ICW3S6 EQU 01000000B ;IR INPUT 6 HAS SLAVE ICW3S7 EQU 10000000B ;IR INPUT 7 HAS SLAVE ; ICW3 REGISTER FLAGS (SLAVE DEVICE) ICW3SID EQU 00000111B ;SLAVE ID MASK ; ICW4 REGISTER FLAGS ICW4SFN EQU 00010000B ;1=SPECIAL FULLY NESTED MODE ICW4BMS EQU 00001000B ;BUFFERED MODE SLAVE ICW4BMM EQU 00001100B ;BUFFERED MODE MASTER ICW4AE EQU 00000010B ;AUTO EOI ICW4UPM EQU 00000001B ;MICRO-PROCESSOR MODE ; (0=8080/85 , 1=8086/88) ; OCW1 REGISTER (INTERRUPT MASK REGISTER) OCW1IM0 EQU 00000001B ;IR0 OCW1IM1 EQU 00000010B ;IR1 OCW1IM2 EQU 00000100B ;IR2 OCW1IM3 EQU 00001000B ;IR3 OCW1IM4 EQU 00010000B ;IR4 OCW1IM5 EQU 00100000B ;IR5 OCW1IM6 EQU 01000000B ;IR6 OCW1IM7 EQU 10000000B ;IR7 ; OCW2 REGISTER OCW2OP EQU 00000000B ;OCW2 OCW2R EQU 10000000B ;PRIORITY ROTATION OCW2SL EQU 01000000B ;SELECT A SPECIFIC LEVEL OCW2EOI EQU 00100000B ;END OF INTERRUPT COMMAND OCW2L EQU 00000111B ;IR LEVEL TO BE ACTED UPON ; OCW3 REGISTER OCW3OP EQU 00001000B ;OCW3 OCW3RSM EQU 01000000B ;RESET SPECIAL MASK MODE OCW3SSM EQU 01100000B ;SET SPECIAL MASK MODE OCW3P EQU 00000100B ;POLL COMMAND OCW3RIR EQU 00000010B ;READ IR REG OCW3RIS EQU 00000011B ;READ IS REG DATE TIME  or $F ; ; 6845 CRT-CONTROLLER EQUATES ; ; PORT DISPLACEMENTS CRTREG EQU 0 ; CRT-C REGISTER SELECT CRTDAT EQU 1 ; CRT-C DATA ; CRT-C INTERNAL REGISTERS ; NOTE: A "*" INDICATES THE VALUE WRITTEN/READ IS ONE ; LESS THAN ACTUAL VALUE CRTHT EQU 0 ; * HORIZONTAL TOTAL CRTHD EQU 1 ; HORIZONTAL DISPLAYED CRTHSP EQU 2 ; * HORIZONTAL SYNC POSITION CRTSW EQU 3 ; SYNC WIDTH CRTSW_WH EQU 00001111B ; HORIZONTAL WIDTH CRTSW_WV EQU 11110000B ; VERTICAL WIDTH CRTVT EQU 4 ; * VERTICAL TOTAL CRTVTA EQU 5 ; VERTICAL TOTAL ADJUST CRTVD EQU 6 ; VERTICAL DISPLAYED CRTVSP EQU 7 ; * VERTICAL SYNC POSITION CRTIS EQU 8 ; INTERLACE AND SKEW CRTIS_IS EQU 00000001B ; INTERLACE SYNC CRTIS_ISV EQU 00000011B ; INTERLACE AND SYNC CRTIS_DS1 EQU 00010000B ; DISPTMG ONE-CHR SKEW CRTIS_DS2 EQU 00100000B ; DISPTMG TWO-CHR SKEW CRTIS_DNO EQU 00110000B ; NON-OUTPUT CRTIS_CS1 EQU 01000000B ; CURSOR ONE-CHR SKEW CRTIS_CS2 EQU 10000000B ; CURSOR TWO-CHR SKEW CRTIS_CNO EQU 11000000B ; NON-OUTPUT CRTMRA EQU 9 ; MAXIMUM RASTER ADDRESS CRTCSR EQU 10 ; CURSOR START RASTER CRTCSR_SRA EQU 00011111B ; START RASTER ADDRESS CRTCSR_ND EQU 00100000B ; NOT DISPLAYED CRTCSR_BS EQU 00100000B ; BLINK SLOW(WITH CRTCSR_CB) CRTCSR_CB EQU 01000000B ; BLINK ENABLE CRTCER EQU 11 ; CURSOR END RASTER CRTSAH EQU 12 ; START ADDRESS (MSB) CRTSAL EQU 13 ; START ADDRESS (LSB) CRTCH EQU 14 ; CURSOR (MSB) CRTCL EQU 15 ; CURSOR (LSB) CRTLPH EQU 16 ; LIGHT PEN ADDRESS (MSB) CRTLPL EQU 17 ; LIGHT PEN ADDRESS (LSB) VEL OCW2EOI EQU 00100000B ;END OF INTERRUPT COMMAND OCW2L EQU 00000111B ;IR LEVEL TO BE ACTED UPON ; OCW3 REGISTER OCW3OP EQU 00001000B ;OCW3 OCW3RSM EQU 01000000B ;RESET SPECIAL MASK MODE OCW3SSM EQU 01100000B ;SET SPECIAL MASK MODE OCW3P EQU 00000100B ;POLL COMMAND OCW3RIR EQU 00000010B ;READ IR REG OCW3RIS EQU 00000011B ;READ IS REG DATE TIME  or $F; ; Definitions for Z-207 disk controller board ; ; PORT DISPLACEMENTS FDCMD EQU 0 ;1797 COMMAND REGISTER FDSTA EQU 0 ; STATUS REGISTER FDTRK EQU 1 ; TRACK REGISTER FDSEC EQU 2 ; SECTOR REGISTER FDDAT EQU 3 ; DATA REGISTER FDCON EQU 4 ;DISK CONTROL PORT FDAS EQU 5 ;AUX STATUS PORT ; SOME USEFUL DEFINITIONS FDHOLES EQU 2 ;NUMBER OF INDEX HOLES FOR DISK TO COME TO SPEED FDSTEPS EQU 10 ;NUMBER OF STEPS TO STEP IN FDHULDM EQU 3 ;HEAD UNLOAD MULTIPLIER FD5MOM EQU 20 ;5.25 INCH MOTOR STARTUP MULTIPLIER FD8NRD EQU 0FFFFH ;8 INCH MOTOR MAX STARTUP TRYS FDHLDM EQU 4 ;HEAD LOAD MULTIPLIER FDCOML EQU 60/4 ;TICS BEFORE STATUS CAN BE READ AFTER A COMMAND FD5IT EQU 23 ;INSIDE TRACK NUMBER ON 48TPI, 5.25 INCH ; COMMANDS FDCRST EQU 000H ;RESTORE FDCSEK EQU 010H ;SEEK FDCSTP EQU 020H ;STEP FDCSTI EQU 040H ;STEP IN FDCSTO EQU 060H ;STEP OUT FDCRDS EQU 080H ;READ SECTOR FDCWRS EQU 0A0H ;WRITE SECTOR FDCRDA EQU 0C0H ;READ ADDRESS FDCRDT EQU 0E0H ;READ TRACK FDCWRT EQU 0F0H ;WRITE TRACK FDCFI EQU 0D0H ;FORCE INTERRUPT ; TYPE 1 COMMAND FLAGS FDFUTR EQU 00010000B ;UPDATE TRACK REGISTER FDFHLB EQU 00001000B ;HEAD LOAD AT BEGINNING FDFVRF EQU 00000100B ;VERIFY FLAGS ; TYPE 1 COMMAND STEP RATE FLAGS FDFS6 EQU 00000000B ;STEP RATE 6 MS FDFS12 EQU 00000001B ; 12 FDFS20 EQU 00000010B ; 20 FDFS30 EQU 00000011B ; 30 ; TYPE 2&3 COMMAND FLAGS FDFMRF EQU 00010000B ;MULTIPLE RECORD FLAG FDFSLF EQU 00001000B ;SECTOR LENGTH FLAG FDFDLF EQU 00000100B ;30 MS DELAY FDFSS1 EQU 00000010B ;SELECT SIDE 1 FDFDDM EQU 00000001B ;DELETED DATA MARK ; TYPE 4 COMMAND FLAGS FDFINI EQU 00000000B ;TERMINATE WITH NO INTERRUPT FDFII0 EQU 00000001B ;NOT READY TO READY TRANSITION FDFII1 EQU 00000010B ;READY TO NOT READY TRANSITION FDFII2 EQU 00000100B ;INDEX PULSE FDFII3 EQU 00001000B ;IMMEDIATE INTERRUPT ; STATUS FLAGS FDSNRD EQU 10000000B ;NOT READY FDSWPV EQU 01000000B ;WRITE PROTECT VIOLATION FDSHLD EQU 0010 0000B ;HEAD IS LOADED FDSRTE EQU 00100000B ;RECORD TYPE FDSWTF EQU 00100000B ;WRITE FAULT FDSSEK EQU 00010000B ;SEEK ERROR FDSRNF EQU 00010000B ;RECORD NOT FOUND FDSCRC EQU 00001000B ;CRC ERROR FDSTK0 EQU 00000100B ;FOUND TRACK 0 FDSLDT EQU 00000100B ;LOST DATA FDSIND EQU 00000010B ;INDEX HOLE FDSBSY EQU 00000001B ;BUSY ; INFO RETURNED BY A READ ADDRESS COMMAND FDRATRK EQU 0 ;TRACK FDRASID EQU 1 ;SIDE FDRASEC EQU 2 ;SECTOR FDRASL EQU 3 ;SECTOR LENGTH FDRACRC EQU 4 ;2 BYTE CRC FDRAL EQU 6 ;LENGTH OF READ ADDRESS INFO ; DISK HEADER SECTOR LENGTH VALUES FDSL128 EQU 0 ;SECTOR LENGTH 128 FDSL256 EQU 1 ;SECTOR LENGTH 256 FDSL512 EQU 2 ;SECTOR LENGTH 512 FDSL1K EQU 3 ;SECTOR LENGTH 1024 ; CONTROL REGISTER FLAGS CONDS EQU 00000011B ;DRIVE SELECT BITS CONDS8 EQU 00000100B ;0=5 1/4" , 1=8" CONDSEN EQU 00001000B ;DRIVE SELECT ENABLE CONPC EQU 00010000B ;WRITE PRE-COMPENSATION ; 5 1/4" 0=YES , 1=NO ; 8" 0=ALL TRACKS , 1=TRACKS 44-76 CON5FS EQU 00100000B ;5 1/4" FAST STEP CONWE EQU 01000000B ;ENABLE WAIT FOR DRQ OR IRQ CONSD EQU 10000000B ;ENABLE SINGLE DENSITY ; AUXILARY STATUS REGISTER FLAGS ASIRQ EQU 00000001B ;1797 INTERRUPT REQUEST ASMO EQU 00000010B ;5 1/4" MOTOR ON AS96T EQU 00001000B ;5 1/4" DRIVES ARE 96TPI AS5PC EQU 00010000B ;5 1/4" DRIVES NEED WRITE PRE-COMPENSATION AS2S EQU 01000000B ;SELECTED 8" DRIVE CONTAINS 2 SIDED MEDIA ASDRQ EQU 10000000B ;1797 DRQ  ; ; Define the parameters for the Z-217 controller ; ; 11/22/82 - bcb ; Z217SPT EQU 18 ; Sectors/track Z217BPS EQU 512 ; Bytes/sector ; Define the port offsets WICOM EQU 0 ; Command port offset WISTA EQU 0 ; Status port offset WIRES EQU 1 ; Reset port offset WIACK EQU 1 ; Interrupt ackowledge port offset ; Define status register bits WISINT EQU 80H ; Interrupt WISBUSY EQU 40H ; Busy WISTMAIP EQU 20H ; TMA in progress WISBUM EQU 10H ; Burst mode WISERR EQU 08H ; Error WISIME EQU 04H ; Immediate mode error WISPAUS EQU 02H ; Paused WISDONE EQU 01H ; Done ; Define the commands WICBOOT EQU 00H ; Boot WICSETUP EQU 08H ; Setup WICEXE EQU 10H ; Execute WICPAU EQU 18H ; Pause WICCONT EQU 20H ; Continue ; Define the Flag byte WIFIEN EQU 80H ; Interrupts enabled WIFUBUM EQU 40H ; Use burst mode WIFIPC EQU 20H ; Ignore PAUSE and CONT WIFDR EQU 04H ; Disable retries WIFDECC EQU 02H ; Disable ecc errors WIFCHAIN EQU 01H ; Chain next command ; Define the control block commands WICBRCL EQU 00H ; Recal drive WICBSTS EQU 01H ; Read drive status WICBRDL EQU 11H ; Read logical WICBWRL EQU 10H ; Write logical WICBSKL EQU 13H ; Seek logical WICBFMD EQU 20H ; Format drive WICBFMT EQU 21H ; Format track WICBSDP EQU 22H ; Set drive parameters WICBWRA EQU 30H ; Write absolute WICBRDA EQU 31H ; Read absolute WICBSKA EQU 33H ; Seek absolute ; Define a type 0/1 control block WI1COM EQU 0 ; Command WI1DSHS EQU WI1COM+1 ; Drive select in bits 7-5, sector number 4-0 WI1SECH EQU WI1DSHS+1 ; Sector number(high) WI1SECL EQU WI1SECH+1 ; Sector number(low) WI1CNT EQU WI1SECL+1 ; Sector count (0=256) WI1TMAH EQU WI1CNT+1 ; Data TMA addr(high) WI1TMAM EQU WI1TMAH+1 ; Data TMA addr(middle) WI1TMAL EQU WI1TMAM+1 ; Data TMA addr(low) WI1NCAH EQU WI1TMAL+1 ; Next command addr(high) WI1NCAM EQU WI1NCAH+1 ; Next command addr(middle) WI1NCAL EQU WI1NCAM+1 ; Next command addr(low) WI1FLAGS  EQU WI1NCAL+1 ; Flags WI1ERR EQU WI1FLAGS+1 ; Error code WI1HSE EQU WI1ERR+1 ; Head in bits 7-5, sector in 4-0 of error WI1SCHE EQU WI1HSE+1 ; Sector number(high) of error WI1SCLE EQU WI1SCHE+1 ; Sector number(low) of error WI1_SIZE EQU WI1SCLE+1 ; Size of control block ; Define a type 2 control block WI2COM EQU 0 ; Command WI2DSHS EQU WI2COM+1 ; Drive/max head number WI2MCH EQU WI2DSHS+1 ; Max cylinder hi WI2MCL EQU WI2MCH+1 ; Max cylinder lo WI2RWCH EQU WI2MCL+1 ; Reduced write current hi WI2RWCL EQU WI2RWCH+1 ; Reduced write current lo WI2PCH EQU WI2RWCL+1 ; Precomp hi WI2PCL EQU WI2PCH+1 ; Precomp lo WI2SRC EQU WI2PCL+1 ; Step rate code WI2ECS EQU WI2SRC+1 ; ECC correction span to use WI2CIF EQU WI2ECS+1 ; Cell size and interleave factor WI2FFC EQU WI2CIF+1 ; fill character for formatting ; Define a type 3 control block WI3COM EQU 0 ; Command WI3DSHS EQU WI3COM+1 ; Drive select bits 7-5, head select in 2-0 WI3CYH EQU WI3DSHS+1 ; Cylinder number(high) WI3CYL EQU WI3CYH+1 ; Cylinder number(low) WI3SEC EQU WI3CYL+1 ; Sector number WI3TMAH EQU WI3SEC+1 ; Data TMA addr(high) WI3TMAM EQU WI3TMAH+1 ; Data TMA addr(middle) WI3TMAL EQU WI3TMAM+1 ; Data TMA addr(low) WI3NCAH EQU WI3TMAL+1 ; Next command addr(high) WI3NCAM EQU WI3NCAH+1 ; Next command addr(middle) WI3NCAL EQU WI3NCAM+1 ; Next command addr(low) WI3FLAGS EQU WI3NCAL+1 ; Flags WI3ERR EQU WI3FLAGS+1 ; Error code WI3HSE EQU WI3ERR+1 ; Head in bits 7-5, sector in 4-0 of error WI3CYHE  EQU WI3HSE+1 ; Cylinder number(high) of error WI3CYLE EQU WI3CYHE+1 ; Cylinder number(low) of error WI3_SIZE EQU WI3CYLE+1 ; Size of control block ; Define the error codes WIENO EQU 00H ; No error WIEDNR EQU 01H ; Drive not ready WIENSC EQU 02H ; No seek complete WIENTZ EQU 03H ; No track 0 WIENI EQU 04H ; No index WIENDS EQU 05H ; No drive selected WIEHNF EQU 10H ; Header A.M. not found WIESKE EQU 11H ; Seek error WIESNF EQU 12H ; Sector not found WIEHECC EQU 13H ; ECC error in header WIEDAM EQU 14H ; Data A.M. not found WIENECC EQU 15H ; Non-Correctable ECC error in data field WIECECC EQU 16H ; Correctable ECC error in data field WIEWF EQU 17H ; Write fault WIEIOC EQU 20H ; Illegal op code WIEIDA EQU 21H ; Illegal disk addr WIEFP EQU 22H ; Format protected WIEWP EQU 23H ; Write protected WIEMISC EQU 30H ; Miscellaneous error WIEDIAG EQU 40H ; Error during diagnostic ; ; Define Functions performed by Disk driver routines ; DSK_RESET EQU 0 ; Reset function DSK_STATUS EQU DSK_RESET+1 ; Status function DSK_READ EQU DSK_STATUS+1 ; Read function DSK_WRITE EQU DSK_READ+1 ; Write function DSK_VERIFY EQU DSK_WRITE+1 ; Verify function DSK_FORMAT EQU DSK_VERIFY+1 ; Format(write track) function DSK_STEPIN EQU DSK_FORMAT+1 ; Step in function DSK_READTRK EQU DSK_STEPIN+1 ; Read track function DSK_GBIOSVEC EQU DSK_READTRK+1 ; Get BIOS disk vector addr DSK_MAPDSK EQU DSK_GBIOSVEC+1 ; Get Logical to physical mapping DSK_SETFDC EQU DSK_MAPDSK+1 ; Set FDC bit in drive table DSK_PREAD EQU DSK_SETFDC+1 ; Physical read DSK_FMAX EQU DSK_PREAD ; Max function value ; ; Define the disk info block (one is needed for each drive) ; MAXDSK EQU 15 ; Maximum number of disks MAXDSK5 EQU 2 ; Maximum 5 inch drives (0-1) MAXDSK8 EQU 4 ; Maximum 8 inch drives (2-3) MAXDSKW EQU 6 ; Maximum winchester drive (4-5) DSK_STA EQU 0 ; Status of last operation   DSKST_FNERR EQU 0100H ; Invalid function DSKST_ORERR EQU 0200H ; Improper order of function DSKST_DNERR EQU 0300H ; Invalid disk number DSKST_DTERR EQU 0400H ; Invalid disk type DSKST_NIERR EQU 0500H ; Function not implemented DSKST_NDERR EQU 0600H ; No disk in drive DSK_TYPE EQU DSK_STA+2 ; Disk type DSK_TZ207 EQU 0 ; Z-207 type disk DSK_TZ217 EQU DSK_TZ207+1 ; Z-217 type disk DSK_LTRK EQU DSK_TYPE+1 ; Last track DSK_LOPT EQU DSK_LTRK+1 ; Last operation DSK_OWR EQU 01H ; Write was last op DSK_ORD EQU 02H ; Read was last op DSK_ORS EQU 04H ; Reset was last op DSK_OSI EQU 08H ; Step in was last op DSK_OFT EQU 10H ; Format was last op DSK_ORT EQU 20H ; Read track was last op DSK_OUK EQU 80H ; Track is unknown DSK_FLAG EQU DSK_LOPT+1 ; Flags DSK_FDS EQU 01H ; Disk is double sided DSK_FFS EQU 02H ; Drive can be fast stepped DSK_FDP EQU 04H ; Disk is 48 tpi and should be double stepped DSK_FWP EQU 08H ; Disk is software write protected DSK_FDC EQU 10H ; Force DISK HAS CHANGED one time DSK_FSL EQU 20H ; Long head settle DSK_FRS EQU 40H ; Restore fast then slow DSK_ASN EQU 80H ; No partition assigned DSK_SEL EQU DSK_FLAG+1 ; Command to select drive ; Flag from superblock for winchester DSK_RS EQU DSK_SEL+1 ; Command to reset drive DSK_SPHI EQU DSK_RS+1 ; Command to step in DSK_FMT EQU DSK_SPHI+1 ; Command to format(write) a track DSK_RD EQU DSK_FMT+1 ; Command to read a sector DSK_WR EQU DSK_RD+1 ; Command to write a sector DSK_SK EQU DSK_WR+1 ; Command to seek to a track DSK_SERR EQU DSK_SK+1 ; Number of "soft" errors DSK_MAXT EQU DSK_SERR+2 ; Maximum track number of drive DSK_NRETRY EQU DSK_MAXT+1 ; Maximum retry count DSK_SPT EQU DSK_NRETRY+1; Sectors per track ; Sectors per cylinder for winchester DSK_BPS EQU DSK_SPT+1 ; Number of bytes per sector DSK_BPWT EQU DSK_BPS+2 ; Number of bytes per write track operation DSK_BPRT EQU DSK_BPWT+2 ; Number of bytes per read track operation DSK_DELAY EQU DSK_BPRT+2 ; Counter value for short delay DSK_LDELAY EQU DSK_DELAY+2 ; Counter value for a long delay DSK_PORT EQU DSK_LDELAY+2; Base Port number DSK_RDT EQU DSK_PORT+2 ; Read track command DSK_IMGFLG EQU DSK_RDT+1 ; Imaginary drive flag DSKIF_ID EQU 80H ; (0 - real drive; 1 - imaginary drive) DSKIF_DV EQU 40H ; (0 - disk is not in drive; 1 - disk is in drive) DSKIF_NM EQU 20H ; (0 - can map imag to drive; 1 - can't) DSKIF_DN EQU 0FH ; (Mask for disk in drive) DSK_TDSEL EQU DSK_IMGFLG+1 ; Time to wait before deselecting drive(in 100ths of secs) DSK_NAME EQU DSK_TDSEL+2 ; Name for drive DSK_SIZE EQU DSK_NAME+1 ; Size of DSK DSK_BSEC EQU DSK_NAME+1 ; Base sector DSKW_NPS EQU DSK_BSEC+2 ; Number of physical sectors DSKW_FAT EQU DSKW_NPS+2 ; Size of FAT in sectors DSKW_SIZE EQU DSKW_FAT+1 ; Size of DSK for winchester ; ; Define the parameter table passed to the disk drive routines ;  DSKPR_DRIVE EQU 0 ; Logical drive number DSKPR_SECTOR EQU DSKPR_DRIVE+1 ; Logical sector number DSKPR_COUNT EQU DSKPR_SECTOR+2 ; Sector transfer count DSKPR_BUFF EQU DSKPR_COUNT+2 ; Buffer addr (offset,paragraph) DSKPR_SIZE EQU DSKPR_BUFF+4 ; Size of this thig 0000100B ;POLL COMMAND OCW3RIR EQU 00000010B ;READ IR REG OCW3RIS EQU 00000011B ;READ IS REG DATE TIME  or $F; ; Definitions for MS-DOS ; IFDEF BIOS FBIOS = BIOS ELSE FBIOS = 0 ENDIF IF NOT FBIOS LORGADDR = 400H ; Loader org address ; ; BIOS entry points ; BIOS_SEG SEGMENT AT 40H ; Segment where the BIOS is located ; MicroSoft(MS) defined entry points ORG 0*3 BIOS_INIT LABEL FAR ; Initialization routine (only exists ; at boot time) ORG 1*3 BIOS_STATUS LABEL FAR ; Console input status ORG 2*3 BIOS_CONIN LABEL FAR ; Console input ORG 3*3 BIOS_CONOUT LABEL FAR ; Console output ORG 4*3 BIOS_PRINT LABEL FAR ; Printer output ORG 5*3 BIOS_AUXIN LABEL FAR ; Aux input ORG 6*3 BIOS_AUXOUT LABEL FAR ; Aux output ORG 7*3 BIOS_READ LABEL FAR ; Disk input ORG 8*3 BIOS_WRITE LABEL FAR ; Disk output ORG 9*3 BIOS_DSKCHG LABEL FAR ; Disk change status ORG 10*3 BIOS_SETDATE LABEL FAR ; Set current date ORG 11*3 BIOS_SETTIME LABEL FAR ; Set current time ORG 12*3 BIOS_GETDATE LABEL FAR ; Get current date ORG 13*3  BIOS_FLUSH LABEL FAR ; Flush keyboard buffer ORG 14*3 BIOS_MAPDEV LABEL FAR ; Device mapping ORG 15*3 BIOS_MRES9 LABEL FAR ; Reserved for MicroSoft entry points ORG 16*3 BIOS_MRES8 LABEL FAR ORG 17*3 BIOS_MRES7 LABEL FAR ORG 18*3 BIOS_MRES6 LABEL FAR ORG 19*3 BIOS_MRES5 LABEL FAR ORG 20*3 BIOS_MRES4 LABEL FAR ORG 21*3 BIOS_MRES3 LABEL FAR ORG 22*3 BIOS_MRES2 LABEL FAR ORG 23*3 BIOS_MRES1 LABEL FAR ; Zenith Data System(ZDS) defined entry points ORG 24*3 BIOS_DSKFUNC LABEL FAR ; Disk function ORG 25*3 BIOS_PRNFUNC LABEL FAR ; PRN(Printer) function ORG 26*3 BIOS_AUXFUNC LABEL FAR ; AUX(modem) function ORG 27*3 BIOS_CONFUNC LABEL FAR ; CON(console) function ORG 28*3 BIOS_ZRES4 LABEL FAR ; Reserved for Zenith entry points ORG 29*3 BIOS_ZRES3 LABEL FAR ORG 30*3 BIOS_ZRES2 LABEL FAR ORG 31*3 BIOS_ZRES1 LABEL FAR ORG 32*3 BIOS_REL LABEL BYTE ; Bios release number in hex ; (ie 012H is release 1.2x) ORG OFFSET BIOS_REL+1 BIOS_CTADDR LABEL WORD ; Addr of configuration information ORG OFFSET BIOS_CTADDR+2 BIOS_SEG ENDS ; ; Configuration vecter ; CONFG_DSK EQU 0 ; Addr of disk vector CONFG_PRN EQU CONFG_DSK+2 ; Addr of PRN configuraiton table CONFG_AUX EQU CONFG_PRN+2 ; Addr of AUX configuration table CONFG_CON EQU CONFG_AUX+2 ; Addr of CON configuration table CONFG_FNT EQU CONFG_CON+2 ; Addr of Font information FNT_RAM EQU 0 ; Ptr to font table in RAM FNT_ROM EQU FNT_RAM+4 ; Ptr to font table in ROM FNT_SIZE EQU FNT_ROM+4 ; Size of font table in ROM FNT_MSIZE EQU FNT_SIZE+2 ; Space allocated for font table in RAM CONFG_CLOCK EQU CONFG_FNT+2 ; Addr of Date and time fields BIOS_DATE EQU 0 ; Days since Jan 1, 1980 BIOS_HRS EQU BIOS_DATE+2 ; Hours since midnight BIOS_MIN EQU BIOS_HRS+1 ; Minutes BIOS_SEC EQU BIOS_MIN+1 ; Seconds BIOS_HSEC EQU BIOS_SEC+1 ; Hundredths of seconds(a word) CONFG_DOSTB EQU CONFG_CLOCK+2 ; Addr of DOS disk tables CONFG_MCL EQU CONFG_DOSTB+2 ; Addr of memory control info CONFG_ASP EQU CONFG_MCL+2 ; Addr of aspect ratio & light pen info ASP_XVAL EQU 0 ; X aspect ratio value ASP_YVAL EQU ASP_XVAL+1 ; Y aspect ratio value ASP_LPEF EQU ASP_YVAL+1 ; Light pen error (in character cells) ASP_LPHF EQU ASP_LPEF+2 ; Light pen hit flag (=1 when hit) ASP_LPHCA EQU ASP_LPHF+1 ; Character address of hit ASP_LPHPA EQU ASP_LPHCA+2 ; Pixel address within character address ASP_PRSCF EQU ASP_LPHPA+1 ; Flag for PRINT SCREEN function CONFG_QCON EQU CONFG_ASP+2 ; Address of con que descriptor CONFG_QSRA EQU CONFG_QCON+2 ; Address of Serial A descriptor CONFG_QSRB EQU CONFG_QSRA+2 ; Address of Serial B descriptor CONFG_SIZE EQU CONFG_QSRB+2 ; Length of configuration vector ENDIF ASP_X EQU 31 ; Default aspect ratio X ASP_Y EQU 64 ; Default aspect ratio Y BIOS_CREL EQU 10H ; Current release of BIOS BIOS_WORKSP EQU 256 ; Number of bytes needed for ; workspace in BIOS  BIOS_RELDATE EQU 1200 ; Release date 04/15/83 (this changes ; for each release) MS_SIZEMEM EQU 1 ; Flag for DOS to size memory at init ; ; System functions for "interrupt 21" ; (Note: functions followed by "*" are ; not CP/M compatable ; DOSF_TERM EQU 0 ; Program terminate DOSF_CONIN EQU 1 ; Console input DOSF_CONOUT EQU 2 ; Console output DOSF_AUXIN EQU 3 ; Aux input DOSF_AUXOUT EQU 4 ; Aux output DOSF_PRINTOUT EQU 5 ; Printer output DOSF_DRCIO EQU 6 ; Direct console I/O DOSF_DRCI EQU 7 ; * Direct console input DOSF_DRCINE EQU 8 ; * Console input(no echo) DOSF_OUTSTR EQU 9 ; Output string DOSF_INSTR EQU 10 ; Input string DOSF_STCON EQU 11 ; Status of console DOSF_CONINF EQU 12 ; * Flush keyboard buffer and input DOSF_RSDISK EQU 13 ; Disk system reset DOSF_SELDISK EQU 14 ; Select default disk DOSF_OPFILE EQU 15 ; Open file DOSF_CLFILE EQU 16 ; Close file DOSF_SRHFI EQU 17 ; Search for first DOSF_SRHNX EQU 18 ; Search for next DOSF_DEFILE EQU 19 ; Delete file DOSF_SEQREAD EQU 20 ; Sequential read DOSF_SEQWRITE EQU 21 ; Sequential write DOSF_CRFILE EQU 22 ; Create file DOSF_REFILE EQU 23 ; Rename file DOSF_24 EQU 24 ; * not used DOSF_GETDISK EQU 25 ; Get default disk DOSF_SDIOA EQU 26 ; Set disk I/O address DOSF_GFATA EQU 27 ; * Get file allocation table addr ;* The remaining functions are not CP/M compatable DOSF_GFATA128 EQU 28 ; Get file allocation table addr DOSF_29 EQU 29 ; not used DOSF_30 EQU 30 ; not used DOSF_31 EQU 31 ; not used DOSF_32 EQU 32 ; not used DOSF_RANREAD EQU 33 ; Random read DOSF_RANWRITE EQU 34 ; Random write DOSF_GFSIZE EQU 35 ; Get file size DOSF_SFPOS EQU 36 ; Set file position DOSF_SIVEC EQU 37 ; Set interrupt vecter DOSF_CESEG EQU 38 ; Create segment DOSF_RBLREAD EQU 39 ; Random block read DOSF_RBLWRITE EQU 40 ; Random block write DOSF_PARSE EQU 41 ; Parse file name DOSF_GDATE EQU 42 ; Get date DOSF_SDATE EQU 43 ; Set date DOSF_GTIME EQU 44 ; Get time DOSF_STIME EQU 45 ; Set time DOSF_CVERF EQU 46 ; Set/Reset verify flag ; ; Define the interrupts ; DOSI_TERM EQU 20H ; Program terminate DOSI_FUNC EQU 21H ; Perform a function DOSI_TADDR EQU 22H ; Terminate address DOSI_CADDR EQU 23H ; ^C Exit address DOSI_FERADDR EQU 24H ; Fatal error exit addr DOSI_ADREAD EQU 25H ; Absolute disk read DOSI_ADWRITE EQU 26H ; Absolute disk write DOSI_TERMR EQU 27H ; Program terminate, but stay resident ; ; Define the program header  ; PHD_TERM EQU 000H ; Termination point (has INT 20H) PHD_MEMSIZE EQU 002H ; Memory size (first seg num ; after end of mem) PHD_AFUNC EQU 005H ; Alternate function entry point PHD_EXADDR EQU 00AH ; Exit handler addr PHD_ABADDR EQU 00EH ; ^C handler addr PHD_FEADDR EQU 012H ; Fatal error handler addr PHD_STACK EQU 05BH ; End of stack area PHD_FCB1 EQU 05CH ; First program argument PHD_FCB2 EQU 06CH ; Second program argument PHD_DIOA EQU 080H ; Default disk transfer area PHD_CODESTART EQU 100H ; Start of code (Size of a PHD) ; ; Define the "User" File control block (FCB) ; FCB_DRIVE EQU 0 ; Drive number FCB_FNAME EQU FCB_DRIVE+1 ; File name FCB_EXT EQU FCB_FNAME+8 ; Extension to file name FCB_CURBLK EQU FCB_EXT+3 ; Current block FCB_RECSZ EQU FCB_CURBLK+2 ; Record size FCB_FILSZ EQU FCB_RECSZ+2 ; File size FCB_DATE EQU FCB_FILSZ+4 ; Date file modified FCB_TIME EQU FCB_DATE+2 ; Time file modified FCB_RES EQU FCB_TIME+2 ; Reserved FCB_CURREC EQU FCB_RES+8 ; Current record(in block) FCB_RANREC EQU FCB_CURREC+1 ; Random record number FCB_SIZE EQU FCB_RANREC+4 ; Size of a FCB ; ; Define the extended file control block ; XFCB_FLAG EQU 0 ; Flag field XFCB_RES EQU XFCB_FLAG+1 ; Reserved XFCB_ATTR EQU XFCB_RES+5 ; Attribute byte XFCBA_HID EQU 02H ; Hidden files XFCBA_SYS EQU 04H ; System files XFCB_FCB EQU XFCB_ATTR+1 ; Normal FCB XFCB_SIZE EQU XFCB_FCB+FCB_SIZE ; Size of a XFCB ; ; Define the directory entries ; DE_FNAME EQU 0 ; File name DE_EXT EQU DE_FNAME+8 ; Extension to file name DE_ATTR EQU DE_EXT+3 ; File attribute DEA_HID EQU 02H ; Hidden file DEA_SYS EQU 04H ; System file DE_RES EQU DE_ATTR+1 ; Reserved DE_TIME EQU DE_RES+10 ; Time the file was modified DE_DATE EQU DE_TIME+2 ; Date the file was modified DE_START EQU DE_DATE+2 ; Starting allocation unit DE_FSIZE EQU DE_START+2 ; File size DE_SIZE EQU DE_FSIZE+4 ; Size of a DE (should be 32) ; ; Define the "Drive parameter table" for MS-DOS usage ; (Used only by the BIOS at init time) DPT_SECSIZ EQU 0 ; Size in bytes of a physical sector DPT_CLUSIZ EQU DPT_SECSIZ+2 ; Number of sectors in an ; allocation unit DPT_RESSEC EQU DPT_CLUSIZ+1 ; Number of reserved sectors at ; start of disk DPT_FATCNT EQU DPT_RESSEC+2 ; Number of FAT's DPT_MAXENT EQU DPT_FATCNT+1 ; Number of directory entries DPT_DSKSIZ EQU DPT_MAXENT+2 ; Number of physical sectors on ; the disk DPT_SIZE EQU DPT_DSKSIZ+2 ; Size of a DPT ; ; Define the disk errors ; DSKE_WRITEP EQU 0 ; Write protect DSKE_NREADY EQU 2 ; Not ready DSKE_DATA EQU 4 ; Data error DSKE_SEEK EQU 6 ; Seek DSKE_SECT EQU 8 ; Sector not found DSKE_WFAULT EQU 10 ; Write fault DSKE_OTHER EQU 12 ; Anything else 0000100B ;POLL COMMAND OCW3RIR EQU 00000010B ;READ IR REG OCW3RIS EQU 00000011B ;READ IS REG DATE TIME  or $F; ; Define the interrupt page offsets ; IPAGE_SEG SEGMENT AT 0 ORG 0 INT_ZERO LABEL DWORD ; Hardware defined interrupts ORG 4*0 INT_DIV LABEL DWORD ; Divide error ORG 4*1 INT_STEP LABEL DWORD ; Single step ORG 4*2 INT_NMI LABEL DWORD ; Non-maskable interrupt ORG 4*3 INT_BRK LABEL DWORD ; Breakpoint ORG 4*4 INT_OVFL LABEL DWORD ; Overflow error ; Print Screen Emulation INT_PRSCA EQU 5 ; Interrupt 5 for print screen ORG 4*INT_PRSCA INT_PRSC LABEL DWORD ; Print screen ; MS-DOS defined interrupts ORG 4*DOSI_TERM INT_TERM LABEL DWORD ; Terminate program function ORG 4*DOSI_FUNC INT_FUNC LABEL DWORD ; Perform function ORG 4*DOSI_TADDR INT_TADDR LABEL DWORD ; Resume addr on program termination ORG 4*DOSI_CADDR INT_CADDR LABEL DWORD ; ^C handler ORG 4*DOSI_FERADDR INT_FERADDR LABEL DWORD ; Fatal error handler ORG 4*DOSI_ADREAD INT_ADREAD LABEL DWORD ; Absolute disk read ORG 4*DOSI_ADWRITE INT_ADWRITE LABEL DWORD ; Absolute disk write ORG 4*DOSI_TERMR INT_TERMR LABEL DWORD ; Terminate but stay resident ; Master 8259A interrupt controller defined interrupts ORG 4*ZM8259AI INT_ZM8259A LABEL DWORD ; Base of Master 8259A interrupts ORG 4*(ZM8259AI+ZINTEI) INT_EI LABEL DWORD ; Parity or S-100 pin 98 ORG 4*(ZM8259AI+ZINTPS) INT_PS LABEL DWORD ; Processor swap ORG 4*(ZM8259AI+ZINTTIM) INT_TIM LABEL DWORD ; Timer ORG 4*(ZM8259AI+ZINTSLV) INT_SLV LABEL DWORD ; Slave 8259A ORG 4*(ZM8259AI+ZINTSA) INT_SA LABEL DWORD ; Serial port A ORG 4*(ZM8259AI+ZINTSB) INT_SB LABEL DWORD ; Serial port B ORG 4*(ZM8259AI+ZINTKD) INT_KD LABEL DWORD ; Keyboard/Display/Light pen ORG 4*(ZM8259AI+ZINTPP) INT_PP LABEL DWORD ; Parallel port ; Slave 8259A interrupt controller defined interrupts ORG 4*ZS8259AI INT_ZS8259A LABEL DWORD ; Base of Slave 8259A interrupts ORG 4*(ZS8259AI+0) INT_SLV0 LABEL DWORD ; Slave line 0 ORG 4*(ZS8259AI+1) INT_SLV1 LABEL DWORD ; Slave line 1 ORG 4*(ZS8259AI+2) INT_SLV2 LABEL DWORD ; Slave line 2 ORG 4*(ZS8259AI+3) INT_SLV3 LABEL DWORD ; Slave line 3 ORG 4*(ZS8259AI+4) INT_SLV4 LABEL DWORD ; Slave line 4 ORG 4*(ZS8259AI+5) INT_SLV5 LABEL DWORD ; Slave line 5 ORG 4*(ZS8259AI+6) INT_SLV6 LABEL DWORD ; Slave line 6 ORG 4*(ZS8259AI+7) INT_SLV7 LABEL DWORD ; Slave line 7 ; BIOS generated software interrupts ORG 4*(BIOSAI+0) INT_UKB LABEL DWORD ; User keyboard interrupt INT_UKBA EQU BIOSAI+0 ORG 4*(BIOSAI+1) INT_UTM LABEL DWORD ; User timer interrupt INT_UTMA EQU BIOSAI+1 ORG 4*(BIOSAI+2) INT_USAI LABEL DWORD ; Users serial A interrupts INT_USAIA EQU BIOSAI+2 ORG 4*(BIOSAI+3) INT_USBI LABEL DWORD ; User serial B interrupt INT_USBIA EQU BIOSAI+3 ORG 4*(BIOSAI+4) INT_ULP LABEL DWORD ; User light pen interrupt INT_ULPA EQU BIOSAI+4 ORG 4*(BIOSAI+5) INT_UCRT LABEL DWORD ; User keyboard output INT_UCRTA EQU BIOSAI+5 ORG 4*(BIOSAI+6) INT_USAO LABEL DWORD ; Serial A output INT_USAOA EQU BIOSAI+6 ORG 4*(BIOSAI+7) INT_USBO LABEL DWORD ; Serial B output INT_USBOA EQU BIOSAI+7 IPAGE_SEG ENDS  0000100B ;POLL COMMAND OCW3RIR EQU 00000010B ;READ IR REG OCW3RIS EQU 00000011B ;READ IS REG DATE TIME  or $F IF1 IFNDEF PARMS PARMS = NOT 0 ENDIF ENDIF IF PARMS FALSE EQU 0 TRUE EQU NOT FALSE WINCH EQU TRUE ; Flag to include winchester code LOADER EQU FALSE ; Flag that this is not the loader BIOS EQU NOT LOADER ; Flag that this is the BIOS DSK_RTY EQU TRUE ; Flag to do retries on disk operations LISTI EQU TRUE ; Flag to produce include file listings SEPA EQU TRUE ; Flag for separate assembley ENDIF ;** DEFSBC - Define SBC and Superblock ; ; This file defines the outlay of the SBC ; and the superblock of the winchester controller ; SBCSEC EQU 0 ; First sector of SBC SBCSIZ EQU 5 ; Number of sectors (512 bytes) SBCTAB STRUC ; Layout of table at front SBCTRES DB 3 DUP (?) ; Reserved SBCTVER DB 0 ; Version of PART/SBC SBCTREV DB 0 ; Revision of PART/SBC SBCTDBS DB 27 DUP (?) ; Default boot string SBCTBSA DB 3 DUP (?) ; FWA of bad sector table A SBCTBSB DB 3 DUP (?) ; FWA of bad sector table B SBCTSBA DB 3 DUP (?) ; FWA of super block A SBCTSBB DB 3 DUP (?) ; FWA of super block B SBCTSCS DW 0 ; Sector size SBCTSPT DW 0 ; Sectors/track SBCTTPC DW 0 ; Tracks/cylinder (number of heads) SBCTCPV DW 0 ; Cylinders/volume SBCTSPR DW 0 ; Sectors/region SBCTNPS DB 3 DUP (?) ; Number of physical sectors SBCTNPR DB 0 ; Number of regions - 1 SBCTCSA DW 0 ; CRC for superblock A SBCTCSB DW 0 ; CRC for superblock B SBCTCBA DW 0 ; CRC for bad sector table A SBCTCBB DW 0 ; CRC for bad sector table B SBCTSDP DB 12 DUP (?) ; Set Drive for z217 controller SBCTFUS DB 3 DUP (?) ; First user sector number SBCTDAT DB 6 DUP (0) ; Date partitioned SBCCRC DW ? ; CRC of SBC (assuming SBCCRC = 0) DB 39 DUP (?) ; Reserved for future use SBCTAB ENDS ; Definition of the superblock entry SBAEPNL EQU 16 ; Length of name entry SBAEONL EQU 10 ; Length of o/s name SBAENTL EQU 30 ; Length of an entry SBAENT STRUC ; SuperBlock A entry SBAEPN DB SBAEPNL DUP (?) ; Entry name SBAEON DB SBAEONL DUP (?) ; O/S name SBAEFL DB ? ; Flag byte SBAESS DB 3 DUP (?) ; Starting sector number SBAENT ENDS ; Bit assignments for SBAEFL SBAEFLNF EQU 10000000B ; Partition not formatted  0000100B ;POLL COMMAND OCW3RIR EQU 00000010B ;READ IR REG OCW3RIS EQU 00000011B ;READ IS REG DATE TIME  or $F; BIOS_INIT - Initialization code ; ; The loader jumps here after loading the BIOS. ; ; Assumptions: ; 1) The boot device port number, unit number, and ; parameter string are stored at known locations. ; 2) On entry, the CS=start of BIOS, IP=zero, the ; DS=start of loader, SI=offset of loader table, ; and the other regs are undefined. ; ; The following functions are performed: ; 1) All devices are initialized (some done by ROM monitor) ; 2) The disk drive parameter table is fixed up. ; 3) The DOS is read from the disk. ; 4) The addr of the disk drive parameter table is passed to DOS. ; 5) The font file (ALTCHAR.SYS) if present, is loaded ; 6) The program "COMMAND.COM" is loaded and executed. ; ; NOTE: The code from FNT_TAB up to FNT_END ; Is overlaid by the font table from ROM ; BIOS_INIT: ; Set up segment registers and stack MOV AX,CS ; Set up segment registers MOV ES,AX CLI ; Turn off interrupts before changing SS/SP MOV SS,AX MOV SP,OFFSET(BIOS_SIZE+BIOS_WORKSP) ; Set up a local stack INC WORD PTR CS: RECURLV ; Bump recursion level ; Save information from loader MOV SI,FMT_OFFSET ; Get offset of table in loader MOV DI,OFFSET LDR_HDR ; Get dest offset MOV CX,OFFSET FMT_SIZE ; Get size of header CLD ; Set direction REP MOVSB ; Move loader header to local area ; Move work area for monitor ROM to a safe place XOR SI,SI ; Set both source and dest offsets to zero XOR DI,DI MOV ES,SI ; Address interrupt vector area MOV DS,ES: WORD PTR MTR_DS ; Get current DS used by monitor MOV BX,CS ; Get base addr of BIOS MOV DX,OFFSET(BIOS_SIZE+BIOS_WORKSP+15) ; offset of work area MOV CL,4 ; Get divide by 16 shift count SHR DX,CL ; Divide to get para number ADD BX,DX ; Compute para number MOV ES,BX ; Set up dest for move MOV CX,WORD PTR DS: MTR_DS_SIZE ; Get number of bytes to move REP MOVSB ; Move the ROM monitor's work area ; ; Initialize interrupt vectors ; (BX has new value for monitor DS) ASSUME DS:IPAGE_SEG XOR SI,SI ; Set source offset MOV DI,4 ; Set dest offset MOV ES,SI ; Set up seg regs to address int vectors MOV DS,SI MOV WORD PTR INT_ZERO,OFFSET ISR_WILD ; default interrupt handler MOV WORD PTR INT_ZERO+2,CS MOV CX,2*(256-16) ; Get count for smear REP MOVSW ; Smear interrupt handler addr over all MOV WORD PTR MTR_DS,BX ; Store ROM monitor DS addr MOV CS:MTR_DS_VAL,BX ; Save locally MOV WORD PTR MTR_DS-2,0 ; Make offset part a zero MOV ES,BX ; Addr ROM monitor data page MOV WORD PTR ES:MTR_DXMTC,OFFSET MTR_SKBD ; Set up kyb handlers MOV WORD PTR ES:MTR_DXMTC+2,SEG MTR_SEG MOV WORD PTR ES:MTR_SXMTC,OFFSET KQ_PUT MOV WORD PTR ES:MTR_SXMTC+2,CS ; Finish remaining inits (CS is already set up for them) ; 8259 master interrupts MOV WORD PTR INT_EI,OFFSET ISR_EI ; Parity or buss error MOV WORD PTR INT_TIM,OFFSET ISR_TIM ; Timer interrupt handler MOV WORD PTR INT_SLV,OFFSET ISR_SLV ; Slave 8259A MOV WORD PTR INT_SA,OFFSET ISR_SA ; Serial port A MOV WORD PTR INT_SB,OFFSET ISR_SB ; Serial port B MOV WORD PTR INT_KD,OFFSET ISR_KD ; Keyboard/Display/Light pen MOV WORD PTR INT_PP,OFFSET ISR_PP ; Parallel port ; 8259 slave interrupts MOV WORD PTR INT_SLV0,OFFSET ISR_SLV0 ; Slave line 0 MOV WORD PTR INT_SLV1,OFFSET ISR_SLV1 ; Slave line 1 MOV WORD PTR INT_SLV2,OFFSET ISR_SLV2 ; Slave line 2 MOV WORD PTR INT_SLV3,OFFSET ISR_SLV3 ; Slave line 3 MOV WORD PTR INT_SLV4,OFFSET ISR_SLV4 ; Slave line 4 MOV WORD PTR INT_SLV5,OFFSET ISR_SLV5 ; Slave line 5 MOV WORD PTR INT_SLV6,OFFSET ISR_SLV6 ; Slave line 6 MOV WORD PTR INT_SLV7,OFFSET ISR_SLV7 ; Slave line 7 ; BIOS generated interrupts MOV WORD PTR INT_UKB,OFFSET ISR_UKB ; Keyboard routine MOV WORD PTR INT_USAI,OFFSET ISR_USAI ; Serial A device MOV WORD PTR INT_USBI,OFFSET ISR_USBI ; Serial B device MOV WORD PTR INT_USAO,OFFSET ISR_USAO ; Serial A output MOV WORD PTR INT_USBO,OFFSET ISR_USBO ; Serial B output MOV WORD PTR INT_UTM,OFFSET ISR_UTM ; timer routine MOV WORD PTR INT_ULP,OFFSET ISR_ULP ; light pen routine MOV WORD PTR INT_UCRT,OFFSET ISR_UCRT ; Crt output MOV WORD PTR INT_PRSC,OFFSET ISR_PRSC ; Print screen ASSUME DS:BIOS_SEG MOV AX,CS ; Recover DS,ES MOV DS,AX MOV ES,AX ; Initialize the que segment addresses MOV WORD PTR CQ_SEGM+CQ_ZCON,AX MOV WORD PTR CQ_SEGM+CQ_ZSERA,AX MOV WORD PTR CQ_SEGM+CQ_ZSERB,AX ; ; Initialize the Keyboard ; MOV AL,ZKEYDK ; Disable keyboard until ready OUT ZKEYBRDC,AL BINITKEY1: IN AL,ZKEYBRDS ; Wait for command to complete TEST AL,ZKEYIBF JNZ BINITKEY1 MOV AL,ZKEYCF ; Flush typeahead buffer OUT ZKEYBRDC,AL IN AL,ZKEYBRDD ; ; Save video state set up by the ROM monitor ; IN AL,ZVIDEO+PIADATA ; Get current video state MOV BYTE PTR VIDEO_ROM,AL ; Save it ; ; Initialize the Serial port A ; XOR AL,AL ; Turn off unit OUT ZSERA+EPCMD,AL IN AL,ZSERA+EPCMD ; Reset mode reg ptr  MOV AL,EPSB1+EPCL8+EPA16X ; Set mode reg 1 OUT ZSERA+EPMODE,AL MOV AL,EPMR2A+EPB960 ; Set mode reg 2 OUT ZSERA+EPMODE,AL MOV AL,EPNORM+EPRTS+EPRESE+EPRXEN+EPDTR OUT ZSERA+EPCMD,AL ; Set Command port IN AL,ZSERA+EPDATA ; Clear input IN AL,ZSERA+EPDATA ; ; Initialize the Serial port B ; XOR AL,AL ; Turn off unit OUT ZSERB+EPCMD,AL IN AL,ZSERB+EPCMD ; Reset mode reg ptr MOV AL,EPSB1+EPCL8+EPA16X ; Set mode reg 1 OUT ZSERB+EPMODE,AL MOV AL,EPMR2A+EPB960 ; Set mode reg 2 OUT ZSERB+EPMODE,AL MOV AL,EPNORM+EPRTS+EPRESE+EPRXEN+EPDTR OUT ZSERB+EPCMD,AL ; Set Command port IN AL,ZSERB+EPDATA ; Clear input IN AL,ZSERB+EPDATA ; ; Initialize PIA port ; MOV AL,PIADDAC ; Set control ports for data OUT ZPIA+PIACTLA,AL OUT ZPIA+PIACTLB,AL MOV AL,01011111B ; Load initial data value for port A OUT ZPIA+PIADATA,AL MOV AL,11111111B ; Load initial data value for port B OUT ZPIA+PIADATB,AL XOR AL,AL ; Set control ports for direction OUT ZPIA+PIACTLA,AL OUT ZPIA+PIACTLB,AL MOV AL,10101111B ; Set direction reg for port A OUT ZPIA+PIADDRA,AL MOV AL,11111100B ; Set direction reg for port B OUT ZPIA+PIADDRB,AL ; Make 0->1 transitions of light pen cause CA1 to be set, but do not cause interrupt ; Make 0->1 transitions of vsync cause CA2 to be set and cause interrupts MOV AL,PIADDAC+PIAC12+PIAC23 ; Set control port A for data OUT ZPIA+PIACTLA,AL ; Disable transitions of parallel printer to cause interrupt MOV AL,PIADDAC ; Set control port B for data OUT ZPIA+PIACTLB,AL ; Clear CA1,CA2 and CB1,CB2 by reading the port and then using ; dummy I/O to drive clock on PIA (and thus cause clear to occur) IN AL,ZPIA+PIADATA ; Clear CA1,CA2 IN AL,ZPIA+PIADATB ; Clear CB1,CB2 IN AL,ZDIPSW ; Read from a "safe" place(the dip switch) ; Turn off clear of light pen/vsync so CA1/CA2 transitions can occur IN AL,ZPIA+PIADATA ; Get current data value OR AL,10100000B ; Turn off clear of Vsync/Light pen flipflops OUT ZPIA+PIADATA,AL ; Allow vsync to cause interrupts ; ; Initialize the Timer ; ; Make sure all counter read cycles are completed IN AL,ZTIMER+PITC0 IN AL,ZTIMER+PITC0 IN AL,ZTIMER+PITC1 IN AL,ZTIMER+PITC1 IN AL,ZTIMER+PITC2 IN AL,ZTIMER+PITC2 ; Init counter modes MOV AL,PITSC0+PITRLW+PITMSW OUT ZTIMER+PITCW,AL ; Counter 0 - square wave generator MOV AL,PITSC1+PITRLW+PITMITC OUT ZTIMER+PITCW,AL ; Counter 1 - event counter MOV AL,PITSC2+PITRLW+PITMITC OUT ZTIMER+PITCW,AL ; Counter 2 - intr on terminal count ; Init counter values XOR AL,AL ; Timer 1 OUT ZTIMER+PITC1,AL OUT ZTIMER+PITC1,AL MOV AX,ZTIMEVAL ; Timer 0 OUT ZTIMER+PITC0,AL MOV AL,AH OUT ZTIMER+PITC0,AL ; Wait for first rising clock from counter 0 MOV AL,0FFH-ZTIMERS0 OUT ZTIMERS,AL XOR CX,CX ; Get timeout value TIMEL: IN AL,ZTIMERS ; Get status TEST AL,ZTIMERS0 ; Has it occured yet ? LOOPZ TIMEL ; No, try again JNZ BINIC1 ; If clock responded, then skip JMP TIMERR ; Clock never responded BINIC1: ; Clear any pending interrupts MOV AL,0FFH-ZTIMERS0-ZTIMERS2 OUT ZTIMERS,AL ; ; Initialize parity generation ; MOV AL,BIOS_MCL ; Get value of memory control latch TEST AL,ZMCLPK ; Is parity checking specified ? JZ MEMIF ; No, skip AND AL,NOT ZMCLPK ; Turn off checking(and on generation) OUT ZMCL,AL ; Output value ; Set up the Z-205 boards MOV DX,Z205BA ; DX = base address MOV CX,Z205BMC ; CX = number of boards MEMIL0: OUT DX,AL ; Set it up INC DX LOOP MEMIL0 XOR AX,AX ; Start at segment 0 MEMIL: MOV DS,AX ; Set up segment regs MOV ES,AX MOV AX,DS:0 ; Get first word MOV BX,AX ; Save a copy INC AX ; Bump value INC WORD PTR DS:0 ; Bump memory CMP AX,WORD PTR DS:0 ; Are they the same ? JNE MEMIC ; No, skip MOV WORD PTR DS:0,BX ; Restore value XOR SI,SI ; Set up regs for move XOR DI,DI MOV CX,08000H ; Get number of words to move REP MOVSW ; Move words onto themselves MEMIC: MOV AX,DS ; Get segment ADD AX,01000H ; Point to next segment, finished ? JNZ MEMIL ; No, try again MOV AX,CS ; Restore seg regs MOV ES,AX MOV DS,AX MEMIF: ; ; Initialize the Slave 8259A interrupt controller ; MOV AL,ICW1OP+ICW1LT+ICW1IL4 OUT ZS8259A+ICW1,AL ; Level triggered, cascaded MOV AL,ZS8259AI ; Get slave base interrupt number OUT ZS8259A+ICW2,AL ; Set interrupt base number MOV AL,ZINTSLV OUT ZS8259A+ICW3,AL ; Set slave number MOV AL,ICW4UPM+ICW4SFN OUT ZS8259A+ICW4,AL ; Set processor to 8086, fully nested, non buffered MOV AL,0FFH OUT ZS8259A+OCW1,AL ; Don't allow any interrupts ; ; Initialize the Master 8259A interrupt controller ; (interrupts are still disabled) ; MOV AL,ICW1OP+ICW1LT+ICW1IL4 OUT ZM8259A+ICW1,AL ; Level triggered, cascaded MOV AL,ZM8259AI ; Get Master base interrupt number OUT ZM8259A+ICW2,AL ; Set interrupt base number MOV AL,ICW3S3 OUT ZM8259A+ICW3,AL ; Slave is connected to line 3 MOV AL,ICW4UPM+ICW4SFN OUT ZM8259A+ICW4,AL ; Set processor to 8086, special fully nested, nonbuffered MOV AL,NOT (OCW1IM0 OR OCW1IM2 OR OCW1IM4 OR OCW1IM5 OR OCW1IM6) OUT ZM8259A+OCW1,AL ; Allow Fatal hardware, timer, serial A, ; serial B, and keyboard/video interrupts STI ; Now turn on interrutps ; ; Initialize PRN, AUX, and CON ; ; Init PRN MOV BX,OFFSET CHRD_PRN ; Get addr of configuration table for PRN MOV AH,CHR_CONTROL ; Get control function code MOV AL,CHR_CFSU ; Get set up subfunction code PUSH CS ; Make call into CALLF CALL NEAR PTR BIOS_PRNFUNC ; Configure the printer, any errors ? JNC BINITC1A ; No, skip JMP PRNERR ; Yes, tell user ; Init AUX BINITC1A: MOV BX,OFFSET CHRD_AUX ; Get addr of configuration table for AUX MOV AH,CHR_CONTROL ; Get control function code MOV AL,CHR_CFSU ; Get set up subfunction code PUSH CS ; Make call into CALLF CALL NEAR PTR BIOS_AUXFUNC ; Configure the aux device, any errors ? JNC BINITC1B ; No, skip JMP AUXERR ; Yes, tell user ; Init CON BINITC1B:  MOV BX,OFFSET CHRD_CON ; Get addr of configuration table for CON MOV AH,CHR_CONTROL ; Get control function code MOV AL,CHR_CFSU ; Get set up subfunction code PUSH CS ; Make call into CALLF CALL NEAR PTR BIOS_CONFUNC ; Configure the console, any errors ? JNC BINITC1C ; No, skip JMP CONERR ; Yes, tell user BINITC1C: ; ; Print sign on message ; MOV BX,OFFSET SMESG ; Get addr of sign on message MOV CH,OFFSET SMESGL ; Get length of sign on message CALL PMESG ; Print message  ; Check version of ROM for compatibility PUSH DS MOV DS,MTR_DS_VAL ; Get ROM's DS MOV AL,DS:MTR_VER ; Get version number POP DS MOV BYTE PTR ROM_VER,AL ; Save it for later CMP AL,MTR_CVER ; Are versions compatable ? JNB BINITLD ; Yes, skip JMP ROMERR ; No, Show error ; Check if loader and BIOS have compatible revs BINITLD: CMP BYTE PTR LDR_HDR+FMT_VER,FMT_CVER ; Are versions equal ? JE BINITFX ; Yes, go fix up disk table JMP VERERR ; No, go print error message ; ; Fix up disk tables to correspond with boot device ; ; Using the port number, device type, and unit number we must compute ; a BIOS disk number and an MSDOS drive number. ; For now, if the boot device was a 5.25 inch floppy, then the BIOS ; disk number is 0 and the MSDOS drive number is 0. If the boot ; device was a 8 inch floppy, then the BIOS disk number is 2 and ; the MSDOS drive number is 2. BINITFX: MOV AL,BYTE PTR LDR_HDR+FMT_SEL ; Get select command MOV AH,AL ; Save second copy  CMP AL,-1 ; Is winchester? JZ BINITC1H ; Yes, do winchester stuff TEST AL,CONDS8 ; Is drive an 8 incher JZ BINITC1D ; No, skip MOV BYTE PTR BBDRIVE,2 ; Set up BIOS disk for 8 inch floppies MOV BYTE PTR BMDRIVE,2 ; Set up MSDOS drive for 8 inch floppies JMP SHORT BINITC1E ; Skip BINITC1D: MOV BYTE PTR BBDRIVE,0 ; Set up BIOS disk for 5.25 inch floppies MOV BYTE PTR BMDRIVE,0 ; Set up MSDOS drive for 5.25 inch floppies BINITC1E: AND AL,CONDS ; Issolate unit number ADD BYTE PTR BMDRIVE,AL ; Bump MSDOS drive number ADD BYTE PTR BBDRIVE,AL ; Bump BIOS disk number BINITC1H: ; ; Set up winchester drive ; ; Note: Disk 4 and disk 5 are same physical unit! MOV SI,2*MAXDSK8 ; Get index of winchester MOV SI,DSK_TPTR[SI] ; Get addr of winchester disk table MOV DI,WORD PTR DSK_PORT[SI] ; Get base port MOV CX,3 BINITW0A: MOV DX,WISTA ; Get status port offset ADD DX,DI ; Compute status port IN AL,DX ; Get status CMP AL,WISDONE ; Does drive exist ? JZ BINITW0 ; Yes, continye DEC CX ; Count a try JNZ BINITW0B JMP NEAR PTR BINITD207 BINITW0B: MOV DX,WIRES ; Get reset port offset ADD DX,DI ; Compute reset port OUT DX,AL ; Reset drive PUSH CX MOV CX,WORD PTR DSK_DELAY[SI] ; Get delay time CALL ALARM_WAIT ; Wait around for a while POP CX JMP BINITW0A BINITW0: MOV AL,WICSETUP ; Get setup command MOV DX,WICOM ; Get command port offset ADD DX,DI ; Compute command port OUT DX,AL ; Issue setup command PUSH DX ; Save command port for later MOV CX,1000 ; Get max number of times to check status MOV DX,WISTA ; Get status port offset ADD DX,DI ; Compute status port BINITW1: IN AL,DX ; Get status TEST AL,WISBUSY ; Is it busy yet ? LOOPZ BINITW1 ; Has count run out ? JCXZ BINITD207 ; Jump if not busy and count run out ; compute addr of control block by shifting seg left by 4 and adding offset XOR DX,DX ; Clear high order MOV BX,CS ; Get segment SHL BX,1 ; First shift RCL DX,1 SHL BX,1 ; Second shift RCL DX,1 SHL BX,1 ; Third shift RCL DX,1 SHL BX,1 ; Fourth shift RCL DX,1 ADD BX,OFFSET DSK_WCB ; Add offset ADC DX,0 ; propagate cary ; DX:BX = 20 bit address MOV AL,DL ; Get high byte POP DX ; Recover command port OUT DX,AL ; Output high byte MOV BYTE PTR DSK_WCB+WI3NCAH,AL ; Save in control table MOV AL,BH ; Get middle byte OUT DX,AL ; Output it MOV BYTE PTR DSK_WCB+WI3NCAM,AL ; Save in control table MOV AL,BL ; Get low byte OUT DX,AL ; Output it MOV BYTE PTR DSK_WCB+WI3NCAL,AL ; Save in control table ; Now assign the partitions, and calculate FAT size CALL NEAR PTR Z217INIT JMP SHORT BINITD207 ; ; Set up drive types, and flag imaginary drives ; BINITD207: MOV BL,BYTE PTR BBDRIVE ; Get new value XOR BH,BH ; Clear uppper part SHL BX,1 ; Convert to word ptr MOV BX,DSK_TPTR[BX] ; Get disk table addr ; Store values from loader in table MOV AH,BYTE PTR LDR_HDR+FMT_SEL ; Get select command CMP AH,-1 ; Is winchester? JZ BINITC1EA ; If yes, flags already setup MOV BYTE PTR DSK_SEL[BX],AH ; Store select command BINITC1EA: MOV AL,BYTE PTR LDR_HDR+FMT_FLG ; Get flag byte MOV AH,BYTE PTR DSK_FLAG[BX] ; Get flag byte in table AND AL,DSK_FDS OR DSK_FDP ; Isolate double sided and double step AND AH,NOT (DSK_FDS OR DSK_FDP) ; Remove those from table value OR AL,AH ; Put them together MOV BYTE PTR DSK_FLAG[BX],AL ; Put it in table MOV AX,WORD PTR LDR_HDR+FMT_SECS ; Get bytes per sector MOV WORD PTR DSK_BPS[BX],AX ; Store it MOV AL,BYTE PTR LDR_HDR+FMT_SPT ; Get sectors per track MOV BYTE PTR DSK_SPT[BX],AL ; Store it ; Fixup the base port number in the disk table MOV DX,WORD PTR DSK_PORT[BX] ; Get default base port number MOV AX,WORD PTR LDR_HDR+FMT_PORT ; Get boot base port number CMP AX,DX ; Are boot and default ports the same ? JE BINITC1I ; Yes, nothing to do MOV SI,OFFSET DSK_TPTR ; Get addr of disk vector BINITC1F: MOV BX,[SI] ; Get the addr of the next DSK table CMP BX,-1 ; Are we finished ? JE BINITC1I ; Yes, exit loop CMP DX,WORD PTR DSK_PORT[BX] ; Is base port the default port ? JNE BINITC1G ; No, skip MOV WORD PTR DSK_PORT[BX],AX ; Yes, store boot port BINITC1G: ADD SI,2 ; Point to next vector entry JMP BINITC1F ; Do next entry BINITC1I: MOV SI,OFFSET DSK_TPTR ; Get addr of DSK vector MOV WORD PTR EXSTDRV,0 ; Flag all drives as existing ; Reset each disk drive, and flag non-existant ones MOV CX,MAXDSK8 ; Get down counter for disks to do MOV AL,0 ; AL has drive number(starts at zero) RSTDRV: MOV BYTE PTR DSKPR+DSKPR_DRIVE,AL ; Set drive to use PUSH SI ; Save regs PUSH CX MOV BX,[SI] ; Get addr of DSK table MOV AH,DSK_FLAG[BX] ; Get flag byte AND BYTE PTR DSK_FLAG[BX],NOT DSK_FRS ; Turn off double restore PUSH AX MOV BX,OFFSET DSKPR ; Get addr of parm pkt for DSK MOV AL,DSK_RESET PUSH SI CALL DSK ; Reset the drive POP SI JC RSTDRV0 ; Could not restore it, drive missing ; Check for track 0 indicator TEST AL,FDSTK0 ; Is track zero seen ? JNZ RSTDRV1 ; Yes, drive exists - skip ; No track zero, flag drive is imaginary RSTDRV0: POP AX ; Get drive number PUSH AX MOV BX,[SI] ; Get addr of DSK table MOV BYTE PTR DSK_IMGFLG[BX],DSKIF_ID ; Mark drive as imaginary MOV CL,AL ; Turn on proper bit to show as non existant MOV AX,1 SHL AX,CL OR WORD PTR EXSTDRV,AX ; Set bit for non existant JMP SHORT RSTDRV3 ; Don't bother to step in/out RSTDRV1: ; Step head in MOV CX,FDSTEPS ; Number of steps to take RSTDRV2: PUSH CX ; Save count MOV AL,DSK_STEPIN ; Get function MOV BX,OFFSET DSKPR ; Get addr of parm table CALL DSK ; Step in head POP CX ; Recover count LOOP RSTDRV2 ; Decr count and loop if not finished ; Now restore head again MOV BX,OFFSET DSKPR ; Get addr of parm table MOV AL,DSK_RESET ; Get function CALL DSK ; Reset drive RSTDRV3: POP AX ; Restore regs POP CX POP SI MOV BX,[SI] ; Get addr of DSK table MOV BYTE PTR DSK_FLAG[BX],AH ; Restore flags INC AL ; Bump drive index ADD SI,2 ; Point to next vector entry LOOP RSTDRV ; Do next drive ; Now map non-existant drives into imaginary ones MOV AX,WORD PTR EXSTDRV ; Get bit vector of existance AND AX,11B ; 0FFFFH SHR (16-MAXDSK5) ; Only look at 5 inchers XOR BX,BX ; Get index zero in DSK vector MOV CX,MAXDSK5 ; Get count CALL MAPDRV ; Map those drives MOV AX,WORD PTR EXSTDRV ; Get bit vector of existance MOV CX,MAXDSK5 ; Skip over 5 inchers SHR AX,CL AND AX,11B ; 0FFFFH SHR (16-(MAXDSK8-MAXDSK5)) ; Only look at 8 inchers MOV BX,MAXDSK5*2 ; Get word index into DSK vector MOV CX,MAXDSK8-MAXDSK5 ; Get count CALL MAPDRV ; Map those drives JMP RSTDRV6 ; Skip to next section PAGE ; ; MAPDRV - Map non-existant drives into imaginary ones ; ; Call with: ; BX = Word index in DSK of first drive ; AX = Bit vector showing if a drive exists ; CX = Number of entries to try ; EXSTDRV = Bit vector - 1 bits for each nonexistant drive ; ; On exit: ; Nonexistant drives flagged as such, and mapped ; to a physical disk drive ; ; USES: All registers ; MAPDRV PROC NEAR PUSH BX ; Save drive index MOV BX,DSK_TPTR[BX] ; Get addr of DSK entry MOV WORD PTR MAPDRVA,BX ; Save first entry addr MOV WORD PTR MAPDRVB,BX ; And current entry MOV WORD PTR MAPDRVC,CX ; Save count POP BX ; Restore drive index SHR BX,1 ; Save first drive number MOV BYTE PTR MAPDRVD,BL ; Now map each drive that has a 1 bit in AX set MAPDRV1: SHR AX,1 ; Is drive nonexistant ? JNC MAPDRV6 ; No, no need to map this guy ; Must map this drive MAPDRV2: PUSH AX ; Save bit vector and count PUSH CX ; MAPDRVB has current entry, MAPDRVA has first entry ; and MAPDRVC has number of entries to test for MOV SI,MAPDRVB ; SI has entry to map MOV DI,MAPDRVA MOV CX,MAPDRVC ; Start looking MOV AL,BYTE PTR MAPDRVD ; Get drive number MAPDRV3: TEST BYTE PTR DSK_IMGFLG[DI],DSKIF_ID+DSKIF_NM ; Does drive exist ? JNZ MAPDRV4 ; No, This is a phony drive too! ; Have a valid drive OR BYTE PTR DSK_IMGFLG[SI],AL ; Set drive to map JMP SHORT MAPDRV5 ; Exit loop ; No valid drive yet MAPDRV4: ADD DI,DSK_SIZE ; Point to next entry INC AL ; Bump drive number LOOP MAPDRV3 ; Keep looking ; Could not find a mate for this one MOV BYTE PTR DSK_IMGFLG[SI],DSKIF_DV+DSKIF_NM ; Flag valid ; Have mapped this one MAPDRV5: POP CX ; Recover regs POP AX MAPDRV6: ADD WORD PTR MAPDRVB,DSK_SIZE ; Bump to next LOOP MAPDRV1 ; Once for each drive RET MAPDRVA DW ? ; Word index of start MAPDRVB DW ? ; Word index of current MAPDRVC DW ? ; Number of entries MAPDRVD DB ? ; Drive number MAPDRV ENDP EXSTDRV DW ? ; Bit vector of drive existance RSTDRV6: ; ; Read in the DOS ; ; Compute the para addr to put directory (and DOS later) MOV BX,CS ; Get current segment number XOR AX,AX ; Get addr of interrupt vectors MOV DS,AX MOV DS,DS:MTR_DS ; Get addr of ROM monitor's Data segment MOV DX,WORD PTR DS: MTR_DS_SIZE ; Get size of ROM monitor's Data segment PUSH CS ; Restore DS POP DS ADD DX,OFFSET(BIOS_SIZE+BIOS_WORKSP+15) ; Get offset of free memory MOV CL,4 ; Get divide by 16 shift count SHR DX,CL ; Compute offset in para's PUSH DX ; Save for a bit ADD BX,DX ; Compute free memory para MOV WORD PTR DOS_INIT+2,BX ; Store DOS addr ; Read first directory block MOV WORD PTR DSKPR+DSKPR_BUFF+2,BX ; Store in disk packet  MOV WORD PTR DSKPR+DSKPR_BUFF,0 ; Set offset MOV AL,BBDRIVE ; Get BIOS drive number MOV BYTE PTR DSKPR+DSKPR_DRIVE,AL ; Store drive number MOV BX,WORD PTR LDR_HDR+FMT_DIR ; Get sector number of directory block MOV WORD PTR DSKPR+DSKPR_SECTOR,BX ; Store in table MOV WORD PTR DSKPR+DSKPR_COUNT,1 ; Read one sector MOV BX,OFFSET DSKPR ; Get addr of packet MOV AL,DSK_READ ; Get function CALL DSK ; Read a sector, did an error occur ? JNC BINIC2 ; No, skip JMP DSKERR ; Yes, go handle it BINIC2: ; Check if the second entry in the directory is the DOS POP BX ; Recover para offset of directory block MOV CL,4 ; Get mult by 16 shift count SHL BX,CL ; Compute byte offset LEA SI,DE_SIZE+DE_FNAME[BX] ; Get offset of second name MOV DI,OFFSET DOS_NAME ; Get addr of Name of DOS MOV CX,DE_ATTR-DE_FNAME ; Get length of a file name REPE CMPSB ; Are the names equal ? JE BINIC3 ; Yes, skip JMP DOSERR ; No, go handle it BINIC3: ; Read in the DOS MOV AX,WORD PTR DE_SIZE+DE_START[BX] ; Get starting allocation unit number SUB AX,2 ; Zero base it MOV CL,BYTE PTR LDR_HDR+FMT_CLST ; Get shift count SHL AX,CL ; Make into a sector offset in data area ADD AX,WORD PTR LDR_HDR+FMT_DATA ; Convert to a logical sector MOV WORD PTR DSKPR+DSKPR_SECTOR,AX ; Store in table MOV AX,WORD PTR DE_SIZE+DE_FSIZE[BX] ; Get file size(assume < 64K) ADD AX,WORD PTR LDR_HDR+FMT_SECS ; Round up to sector boundary DEC AX MOV CL,BYTE PTR LDR_HDR+FMT_SHFT ; Get sector shift SHR AX,CL ; Compute number of sectors to read MOV WORD PTR DSKPR+DSKPR_COUNT,AX ; Store in table MOV WORD PTR DSKPR+DSKPR_BUFF,0 ; Set offset MOV BX,OFFSET DSKPR ; Get addr of DSK table MOV AL,DSK_READ ; Get function code CALL DSK ; Read the DOS in, did error occur ? JNC BINIT_MSDOS ; No, skip JMP DSKERR ; Yes, handle it ; ; Set up and Call DOS init routine ; BINIT_MSDOS: MOV SI,OFFSET DISK_TAB ; Get addr of disk drive parm table MOV DX,MS_SIZEMEM ; Flag for DOS to size memory CALL DWORD PTR DOS_INIT ; Call the DOS init routine PUSH DS ; Save addr of program header which is returned PUSH CS ; Restore DS POP DS ; Turn on parity checking(if specified) MOV AL,BIOS_MCL ; Get value of memory control latch OUT ZMCL,AL ; Output it ; Set up the Z-205 boards MOV DX,Z205BA ; DX = base address MOV CX,Z205BMC ; CX = number of boards MEMIL01: OUT DX,AL ; Set it up INC DX LOOP MEMIL01 ; Select current diskette as default MOV DL,BMDRIVE ; Set default drive to the boot drive MOV AH,DOSF_SELDISK ; Get function code INT DOSI_FUNC ; Set the default drive ; ; Set up font table information ; MOV WORD PTR FNT_RAM,OFFSET FNT_TAB ; Store RAM font table addr MOV WORD PTR FNT_RAM+2,CS ; Save RAM paragraph for font MOV WORD PTR FNT_SIZE,MTR_FNT_SIZE ; Assume Version 1 of ROM MOV WORD PTR FNT_MSIZE,MTR_FNT_SIZE ; Store allocated space MOV DS,MTR_DS_VAL ; Get ROM DS value CMP BYTE PTR DS:MTR_VER,1 ; Is ROM version 1 JE GET_FNT ; Yes, skip ; Not version 1, Check out actual size MOV BX,WORD PTR DS:MTR_FNTSIZ ; Get real FONT size MOV WORD PTR CS:FNT_SIZE,BX ; Set it in GET_FNT: MOV BX,DS:MTR_FONT ; Get offset of font table MOV DX,DS:MTR_FONT+2 ; And paragraph address MOV DS:MTR_FONT,OFFSET FNT_TAB ; Set up our local font MOV DS:MTR_FONT+2,CS ; And set in page value as well MOV CS:WORD PTR FNT_ROM,BX ; Save addr of font MOV CS:WORD PTR FNT_ROM+2,DX JMP MOVE_FNT ; Jump to FONT read routine ; ; Winchester support code for boot ; DI = Base port of z217 ; ; Stepping stone for far conditional jumps Z217INIT9J1: JMP NEAR PTR Z217INIT9 Z217INIT PROC NEAR ; First, assign the proper partitions to E: and F: MOV WORD PTR PDSKPR+DSKPR_BUFF+2,CS ; Set in segment name ; Now read in the SBC and issue the SDP command, and set up SBASEC MOV BX,OFFSET PDSKPR ; Default values set up MOV AL,DSK_PREAD PUSH DI CALL DSK POP DI JC Z217INIT9J1 ; If error reading block ; SBC read in at PBUFF MOV SI,OFFSET PBUFF MOV BX,WORD PTR [SI]+SBCCRC PUSH BX MOV CX,512 ; Hash the SBC MOV WORD PTR [SI]+SBCCRC,0 ; Force an old zero CALL HASH POP BX CMP AX,BX ; Valid SBC? JNZ Z217INIT9J1 ; Must not be! MOV SI,OFFSET PBUFF MOV AX,WORD PTR [SI].SBCTSBA ; AX = superblock sector MOV BX,WORD PTR [SI].SBCTCSA ; BX = checksum for SBA MOV CX,WORD PTR [SI].SBCTSBB ; CX = sector for block b MOV WORD PTR PDSKPR+DSKPR_SECTOR,AX ; Sector 0 of super block MOV WORD PTR SBBSEC,CX MOV WORD PTR SBACRC,BX ; Save these MOV SI,OFFSET PBUFF+SBCTSDP ; SI = pointer to SDP cmd ; Compute the number of sectors per cylinder (assume 18 x 512) MOV CL,BYTE PTR [SI]+1 AND CL,7 ; CL = max head number INC CL ; CL = number of heads XOR DX,DX MOV AX,Z217SPT ; AX = sectors/track MUL CL ; AL = sectors/cylinder MOV BYTE PTR DISK4+DSK_SPT,AL MOV BYTE PTR DISK5+DSK_SPT,AL ; Save the values ; Save the old info from the parameter block MOV AL,BYTE PTR DSK_WCB+WI3NCAH MOV AH,BYTE PTR DSK_WCB+WI3NCAM PUSH AX ; Save next command address MOV AL,BYTE PTR DSK_WCB+WI3NCAL MOV AH,BYTE PTR DSK_WCB+WI3FLAGS ; Also the flag byte PUSH AX PUSH DI MOV DI,OFFSET DSK_WCB ; DI = destination MOV CX,12 ; Size REP MOVSB ; Move in the SDP command POP DI ; DI = base port MOV AL,WICEXE ; Get Execute command MOV DX,WICOM ; Get command port offset ADD DX,DI ; Compute command port MOV BYTE PTR DSK_WCB+WI3ERR,0FFH ; Set flag for completion OUT DX,AL Z217INITSDP: MOV AL,BYTE PTR DSK_WCB+WI3ERR ; Get error code CMP AL,0FFH ; Is command finished ? JE Z217INITSDP ; No, keep looking ; Now restore the original values POP AX MOV BYTE PTR DSK_WCB+WI3NCAL,AL ; Save in control table MOV BYTE PTR DSK_WCB+WI3FLAGS,AH ; And flags POP AX MOV BYTE PTR DSK_WCB+WI3NCAM,AH ; Save in control table MOV BYTE PTR DSK_WCB+WI3NCAH,AL ; Save in control table ; Now read the super block TRYAGAIN: MOV WORD PTR PDSKPR+DSKPR_COUNT,1 MOV WORD PTR PDSKPR+DSKPR_BUFF,OFFSET PBUFF MOV BX,OFFSET PDSKPR MOV AL,DSK_PREAD CALL DSK ; Read one JNC SBOK ; If ok, check crc JMP SHORT SBOK1 ; If errors ; Super block is ok SBOK: MOV SI,OFFSET PBUFF MOV CX,512 CALL HASH ; Check the hash value CMP AX,WORD PTR SBACRC ; Check it JZ SBALLOK ; Checksum is bad, or read error SBOK1: MOV AX,WORD PTR SBBSEC CMP AX,WORD PTR PDSKPR+DSKPR_SECTOR ; See which one we got JNZ SBOK2 ; is ok JMP NEAR PTR Z217INIT9 ; Try super block B SBOK2: MOV WORD PTR PDSKPR+DSKPR_SECTOR,AX JMP SHORT TRYAGAIN ; Try the other one SBALLOK: MOV SI,OFFSET PBUFF ; SI points to first ; See if we booted from the Z-217 CMP BYTE PTR LDR_HDR+FMT_SEL,-1 ; ZR set if booted from z217 JNZ FOSI3 ; Nope, continue ; Booted from Z-217, locate the partition MOV CX,WORD PTR LDR_HDR+FMT_NRS ; CX = BSEC of boot partition SBALLOK1: CMP WORD PTR [SI].SBAESS,CX ; Check it JZ FOSI3 ; If got it ADD SI,SBAENTL JMP SHORT SBALLOK1 ; Look for next ; Find entries for z-dos FOSI3: CMP BYTE PTR [SI],' ' ; Did not find this one JZ FOSI5 PUSH SI MOV DI,OFFSET OSNAME MOV CX,SBAEONL ; Size of name ADD SI,SBAEPNL ; SI points to OS name REPZ CMPSB ; Compare them POP SI JNZ FOSI4 ; Not here ; Have one here MOV AX,WORD PTR [SI].SBAESS ; Get base sector MOV BX,WORD PTR [SI+SBAENTL].SBAESS MOV CL,BYTE PTR [SI].SBAEFL ; Get the flag byte CMP WORD PTR EBSEC,-1 ; Got one for E: JZ FOSI3E ; Nope ; Had one for E:, get one for F: MOV WORD PTR FBSEC,AX MOV WORD PTR FBSIZ,BX MOV BYTE PTR FBFLG,CL ; Save the flags JMP SHORT FOSI5 ; If F:, done FOSI3E: MOV WORD PTR EBSEC,AX MOV WORD PTR EBSIZ,BX MOV BYTE PTR EBFLG,CL JMP SHORT FOSI4 ; Do next ; Stepping stone Z217INIT9J: JMP NEAR PTR Z217INIT9 FOSI4: ADD SI,SBAENTL JMP SHORT FOSI3 ; Have the OSID for E: and F: (-1 if non-existant) FOSI5: MOV BX,WORD PTR EBSEC CMP BX,-1 JZ FOSI9 ; No E: partition ; Found the one we want MOV WORD PTR DISK4+DSK_BSEC,BX ; Set it in table MOV CX,WORD PTR EBSIZ ; Get start of next SUB CX,BX ; CX = size of this one MOV WORD PTR DISK4+DSKW_NPS,CX ; See if partition within range CMP CX,(8*2*1024) ; 16k = 8 megabytes JNC FOSI10 ; NC means too large CMP CX,2+24+15+100 ; Minimum size JC FOSI10 MOV WORD PTR DRWA1+DPT_DSKSIZ,CX ; Set it here too OR BYTE PTR DISK4+DSK_FLAG,DSK_ASN MOV AL,BYTE PTR EBFLG MOV BYTE PTR DISK4+DSK_SEL,AL FOSI9: MOV BX,WORD PTR FBSEC CMP BX,-1 JZ FOSI10 ; If no match here ; Found one for F: MOV WORD PTR DISK5+DSK_BSEC,BX ; Set it in table MOV CX,WORD PTR FBSIZ ; Get start of next SUB CX,BX ; CX = size of this one MOV WORD PTR DISK5+DSKW_NPS,CX ; See if partition within range CMP CX,(8*2*1024) ; 16k = 8 megabytes JNC FOSI10 ; NC means too large CMP CX,2+24+15+100 ; Minimum size JC FOSI10 MOV WORD PTR DRWA2+DPT_DSKSIZ,CX ; Set it here too OR BYTE PTR DISK5+DSK_FLAG,DSK_ASN MOV AL,BYTE PTR FBFLG MOV BYTE PTR DISK5+DSK_SEL,AL FOSI10: ; Now assign the boot partition CMP BYTE PTR LDR_HDR+FMT_SEL,-1 ; Get select command JNZ Z217INIT0 ; Not booted from 217 ; Booted from 217, assume drive is E: MOV AL,BYTE PTR DISK4+DSK_SPT MOV BYTE PTR LDR_HDR+FMT_SPT,AL ; Set in his SPT value MOV BYTE PTR BBDRIVE,4 MOV BYTE PTR BMDRIVE,4 ; Set drive to E: ; See if booted partition is first or second. if second, make F: MOV AX,WORD PTR LDR_HDR+FMT_NRS ; NRS = BSEC value CMP AX,WORD PTR DISK4+DSK_BSEC JZ Z217INIT0 ; If him, ok MOV AL,BYTE PTR DISK5+DSK_SPT MOV BYTE PTR LDR_HDR+FMT_SPT,AL ; Set in his SPT value INC BYTE PTR BBDRIVE INC BYTE PTR BMDRIVE ; If not, must be F: Z217INIT0: ; Now calculate the FAT sizes MOV SI,OFFSET DRWA1 MOV DI,OFFSET DISK4 PUSH WORD PTR [SI+DPT_DSKSIZ] ; Save this TEST BYTE PTR DISK4+DSK_FLAG,DSK_ASN JZ Z217INIT1 ; Drive does not exist RE_FAT_1A: MOV BYTE PTR [DI+DSKW_FAT],0 ; Set phony fat size MOV BYTE PTR ITERCNT,0 ; Set 0 iterations CALL NEAR PTR CALCFAT ; Calc fat for this guy RE_FAT_1: MOV AL,BYTE PTR [DI+DSKW_FAT] PUSH AX CALL NEAR PTR CALCFAT ; This time use real fat size POP AX CMP AL,BYTE PTR [DI+DSKW_FAT] ; Did it change? JZ Z217INIT1 INC BYTE PTR ITERCNT ; Oscillating? CMP BYTE PTR ITERCNT,5 JC RE_FAT_1 ; Not yet ; Am oscillating DEC WORD PTR [SI+DPT_DSKSIZ] JMP RE_FAT_1A ; Try again Z217INIT1: POP WORD PTR [SI+DPT_DSKSIZ] ; Back to original MOV SI,OFFSET DRWA2 MOV DI,OFFSET DISK5 PUSH WORD PTR [SI+DPT_DSKSIZ] TEST BYTE PTR DISK5+DSK_FLAG,DSK_ASN JZ Z217INIT8 ; F: does not exist either RE_FAT_2A: MOV BYTE PTR [DI+DSKW_FAT],0 ; Set phony fat size MOV BYTE PTR ITERCNT,0 CALL NEAR PTR CALCFAT ; Calc fat for this guy RE_FAT_2: MOV AL,BYTE PTR [DI+DSKW_FAT] PUSH AX CALL NEAR PTR CALCFAT ; And for this guy too POP AX CMP AL,BYTE PTR [DI+DSKW_FAT] JZ Z217INIT8 ; If got it INC BYTE PTR ITERCNT CMP BYTE PTR ITERCNT,5 ; Oscillating JC RE_FAT_2 ; Nope, do again DEC WORD PTR [SI+DPT_DSKSIZ] JMP RE_FAT_2A ; Try this again Z217INIT8: POP WORD PTR [SI+DPT_DSKSIZ] Z217INIT9: RET ; Do a hash, SI = source, CX = count HASH: XOR AX,AX XOR BH,BH HASH1: MOV BL,BYTE PTR [SI] ADD AX,BX INC SI LOOP HASH1 NOT AX RET Z217INIT ENDP ;* CALCFAT - Calculate fat size ; ; CALCFAT calculates the FAT size and places the ; value at [DI+DSKW_FAT] so that FORMAT can find it ; and patch the loader properly ; CALCFAT PROC NEAR MOV CX,WORD PTR [SI+DPT_DSKSIZ] ; CX = number of sectors SUB CX,WORD PTR [SI+DPT_RESSEC] ; Subtract out reserved ones MOV BL,BYTE PTR [DI+DSKW_FAT] XOR BH,BH ; BX = fat size SUB CX,BX ; For FAT 1 SUB CX,BX ; FAT 2 PUSH CX ; Save it MOV CX,WORD PTR [SI+DPT_MAXENT] ; CX = number of directorys MOV AX,32 ; Directory size in bytes XOR DX,DX MUL CX ; DX:AX = bytes per entry MOV CX,WORD PTR [SI+DPT_SECSIZ] ; CX = bytes/sector XOR DX,DX DIV CX ; AX = secotrs/directory POP CX SUB CX,AX ; CX = user entries MOV AX,CX MOV CL,BYTE PTR [SI+DPT_CLUSIZ] ; CX = cluster factor XOR CH,CH XOR DX,DX DIV CX ; AX = user groups MOV CX,3 MUL CX ; DX:AX = user groups * 3 MOV CX,2 DIV CX ; AX = number of fat entries OR DX,DX ; remainder = 0? JZ CALCFAT1 INC AX CALCFAT1: ADD AX,3 ; Include the reserved ones MOV CX,WORD PTR [SI+DPT_SECSIZ] ; CX = bytes/sector XOR DX,DX DIV CX ; AX = number of fat entries OR DX,DX ; remainder = 0? JZ CALCFAT2 INC AX CALCFAT2: MOV BYTE PTR [DI+DSKW_FAT],AL ; Should be in AL RET CALCFAT ENDP ; ; Errors during init ; DSKERR: MOV BX,OFFSET DSKMESG ; Get addr of message MOV CH,OFFSET DSKMESGL ; Get Length of message CALL PMESG ; Print message DSKERRL: JMP SHORT DSKERRL DOSERR: MOV BX,OFFSET DOSMESG ; Get addr of message MOV CH,OFFSET DOSMESGL ; Get length of message CALL PMESG ; Print message DOSERRL: JMP SHORT DOSERRL TIMERR: MOV BX,OFFSET TIMMESG ; Get addr of error message MOV CH,OFFSET TIMMESGL ; Get length of error message CALL PMESG ; Print message TIMERRL: JMP SHORT TIMERRL ; Loop forever PRNERR: MOV BX,OFFSET PRNMESG ; Get addr of error message MOV CH,OFFSET PRNMESGL ; Get length of error message CALL PMESG ; Print message PRNERRL: JMP SHORT PRNERRL ; Loop forever AUXERR: MOV BX,OFFSET AUXMESG ; Get addr of error message MOV CH,OFFSET AUXMESGL ; Get length of error message CALL PMESG ; Print message AUXERRL: JMP SHORT AUXERRL ; Loop forever CONERR: MOV BX,OFFSET CONMESG ; Get addr of error message MOV CH,OFFSET CONMESGL ; Get length of error message CALL PMESG ; Print message CONERRL: JMP SHORT CONERRL ; Loop forever ROMERR: MOV BX,OFFSET ROMMESG ; Get addr of error message MOV CH,OFFSET ROMMESGL ; Get length of error message CALL PMESG ; Print message ROMERRL: JMP SHORT ROMERRL ; Loop forever VERERR: MOV BX,OFFSET VERMESG ; Get addr of error message MOV CH,OFFSET VERMESGL ; Get length of error message CALL PMESG ; Print message VERERRL: JMP SHORT VERERRL ; Loop forever DSKMESG DB CC_CR,CC_LF,CC_LF DB 'Disk read error' DB CC_CR,CC_LF,CC_LF DSKMESGL EQU (OFFSET $)-(OFFSET DSKMESG) DOSMESG DB CC_CR,CC_LF,CC_LF DB 'Disk is not a system disk' DB CC_CR,CC_LF,CC_LF DOSMESGL EQU (OFFSET $)-(OFFSET DOSMESG) TIMMESG DB CC_CR,CC_LF,CC_LF DB 'Timer failure' DB CC_CR,CC_LF,CC_LF TIMMESGL EQU (OFFSET $)-(OFFSET TIMMESG) PRNMESG DB CC_CR,CC_LF,CC_LF DB 'PRN Configured wrong' DB CC_CR,CC_LF,CC_LF PRNMESGL EQU (OFFSET $)-(OFFSET PRNMESG) AUXMESG DB CC_CR,CC_LF,CC_LF DB 'AUX Configured wrong' DB CC_CR,CC_LF,CC_LF AUXMESGL EQU (OFFSET $)-(OFFSET AUXMESG) CONMESG DB CC_CR,CC_LF,CC_LF DB 'CON Configured wrong' DB CC_CR,CC_LF,CC_LF CONMESGL EQU (OFFSET $)-(OFFSET CONMESG) VERMESG DB CC_CR,CC_LF,CC_LF DB 'Version mismatch between BIOS and LOADER' DB CC_CR,CC_LF,CC_LF VERMESGL EQU (OFFSET $)-(OFFSET VERMESG) ROMMESG DB CC_CR,CC_LF,CC_LF DB 'Version mismatch between BIOS and system ROM' DB CC_CR,CC_LF,CC_LF ROMMESGL EQU (OFFSET $)-(OFFSET ROMMESG) ; Buffer for i/o to z-217 PBUFF LABEL NEAR DB 512 DUP (?) ; Reserve enough extra room for the font table OVL_CODE EQU (OFFSET $)-(OFFSET FNT_TAB) ; Get amount of code to be overlaid IF MTR_FNT_SIZE GT OVL_CODE DB MTR_FNT_SIZE-OVL_CODE DUP (?) ; Res any additional amount ENDIF FNT_END: ; ; Move in Font table ; MOVE_FNT: MOV DS,DX ; Get addr of ROM's font table MOV SI,BX MOV DI,OFFSET FNT_TAB ; Get addr to copy it PUSH CS POP ES MOV CX,WORD PTR CS: FNT_SIZE ; Get size of table REP MOVSB ; Move in the new font table MOV AX,CS ; Restore DS, ES MOV DS,AX MOV ES,AX ; Now prepare to read in the font file (if present) MOV DX,OFFSET FNT_FCB ; Get FCB addr of font file MOV AH,DOSF_OPFILE ; Get open function code INT DOSI_FUNC ; Open font file TEST AL,AL ; Did an error occur ? JZ RED_KYB ; No, skip JMP FNT_DON ; Yes, File not present ; Found font file, set up to read bytes RED_KYB: MOV SI,OFFSET FNT_FCB MOV WORD PTR [SI+FCB_RANREC],0 MOV WORD PTR [SI+FCB_RANREC+2],0 MOV WORD PTR [SI+FCB_RECSZ],1 ; Set record 0, size 1 byte MOV DX,OFFSET FNT_BUF MOV AH,DOSF_SDIOA INT DOSI_FUNC ; Set DMA address for reads RED_KY1: MOV DX,OFFSET FNT_FCB MOV CX,2 MOV AH,DOSF_RBLREAD ; Read 2 entries from table INT DOSI_FUNC TEST AL,AL ; EOF reading file JZ RED_KY2 ; Nope JMP FNT_EOF ; Yes, skip further processing RED_KY2: MOV BX,WORD PTR FNT_BUF INC BX ; 2 byte of 0ffh mark end JZ RED_CHR ; end of keyboard info ; Not end, patch this entry in keyboard map table MOV AL,BYTE PTR FNT_BUF XOR AH,AH MOV SI,AX ; SI = index pointer into table CMP BYTE PTR ROM_VER,2 ; Version 1 of rom (Or less) JNB RED_KY3 ; Nope DEC SI DEC SI ; Show MTR_KYB as two bytes closer RED_KY3: PUSH DS MOV AX,WORD PTR MTR_DS_VAL MOV DS,AX ; DS points to MTR data segment val MOV AL,CS:BYTE PTR FNT_BUF+1 ; AL = mapped value of key MOV DS:BYTE PTR [SI+MTR_KYB],AL ; Map it in POP DS JMP SHORT RED_KY1 ; Read next ; Keyboard all mapped in, now do the character fonts RED_CHR: MOV DX,OFFSET FNT_FCB MOV AH,DOSF_RBLREAD MOV CX,1 ; Get character font index value INT DOSI_FUNC TEST AL,AL ; EOF? JNZ FNT_EOF ; Get index, and redefine the font MOV AL,BYTE PTR FNT_BUF CMP AL,0FFH ; End of font information JE FNT_CHR ; Yes XOR AH,AH  MOV BX,AX MOV CL,3 SHL BX,CL ; BX = index * 8 ADD BX,AX ; BX = index * 9 CMP BX,MTR_FNT_SIZE ; Is character in range ? JNB FNT_EOF ; No, bail out ADD BX,OFFSET FNT_TAB ; BX = Pointer into table MOV DX,BX MOV AH,DOSF_SDIOA INT DOSI_FUNC ; Set DMA address to there MOV DX,OFFSET FNT_FCB MOV AH,DOSF_RBLREAD MOV CX,9 ; Size of font character INT DOSI_FUNC ; Redefine this font character TEST AL,AL JNZ FNT_EOF ; EOF somewhere inside font char ; Reset DMA address MOV DX,OFFSET FNT_BUF MOV AH,DOSF_SDIOA INT DOSI_FUNC JMP RED_CHR ; Get next one ; Now map any FONT values FNT_CHR: MOV DX,OFFSET FNT_BUF MOV AH,DOSF_SDIOA INT DOSI_FUNC ; Set DMA address for reads RED_CH1: MOV DX,OFFSET FNT_FCB MOV CX,2 MOV AH,DOSF_RBLREAD ; Read 2 entries from table INT DOSI_FUNC TEST AL,AL ; EOF reading file JZ RED_CH2 ; Nope JMP FNT_EOF ; Yes, skip further processing RED_CH2: MOV BX,WORD PTR FNT_BUF INC BX ; 2 byte of 0ffh mark end JZ FNT_EOF  ; end of font info ; Not end, patch this entry in font map table MOV AL,BYTE PTR FNT_BUF XOR AH,AH MOV SI,AX ; SI = index pointer into table CMP BYTE PTR ROM_VER,2 ; Version 1 of rom (Or less) JNB RED_CH3 ; Nope DEC SI DEC SI ; Show MTR_CHR as two bytes closer RED_CH3: PUSH DS MOV AX,WORD PTR MTR_DS_VAL MOV DS,AX ; DS points to MTR data segment val MOV AL,CS:BYTE PTR FNT_BUF+1 ; AL = mapped value of key MOV DS:BYTE PTR [SI+MTR_CHR],AL ; Map it in POP DS JMP SHORT RED_CH1 ; Read next ; EOF on font file, or valid end marker seen FNT_EOF: MOV DX,OFFSET FNT_FCB MOV AH,DOSF_CLFILE INT DOSI_FUNC ; Close the font file ; All done reading font file FNT_DON: POP DS ; Restore DOS DS value MOV DX,PHD_CODESTART ; Offset to read program into MOV AH,DOSF_SDIOA ; Set disk I/O area addr (DS:DX) INT DOSI_FUNC ; Set I/O area to read in COMMAND.COM MOV BX,DS ; BX = dos returned DS value MOV AX,CS ; Get orignal DS MOV DS,AX MOV DX,OFFSET FCB ; Get FCB addr MOV AH,DOSF_OPFILE ; Open file function INT DOSI_FUNC ; Open file COMMAND.COM TEST AL,AL ; Did open succeed ? JNZ COMERR ; No, an error MOV WORD PTR FCB+FCB_RANREC,0 ; Set record number to zero MOV WORD PTR FCB+FCB_RANREC+2,0 MOV WORD PTR FCB+FCB_RECSZ,1 ; Set record size to 1 MOV CX,-1 ; Number of records to read(to EOF) MOV AH,DOSF_RBLREAD ; Block read function value INT DOSI_FUNC ; Read in COMMAND.COM(CX has bytes to read) JCXZ COMERR ; Jump if no bytes read CMP AL,1  ; Was EOF reached ? JNE COMERR ; No, an error ; Setup standard environment for a program MOV DS,BX ; Recover program segment addr MOV ES,BX ; Set all other segment registers CLI ; Turn off interrupts before modifying SS/SP MOV SS,BX MOV SP,PHD_STACK ; Set up new stack DEC CS:RECURLV ; Decr stack recursion STI ; Turn interrupts back on XOR AX,AX ; Put zero on top of stack for return addr PUSH AX MOV DX,PHD_DIOA ; Get offset of default disk I/O area MOV AH,DOSF_SDIOA ; Function to set disk I/O area INT DOSI_FUNC ; Set disk I/O area for COMMAND.COM PUSH BX ; New CS segment value MOV AX,PHD_CODESTART ; Offset to start execution PUSH AX ; Push it to set up return block on stack ; Turn on keyboard CLI ; Turn off interrupts MOV AL,ZKEYEI ; Enable keyboard interrupts OUT ZKEYBRDC,AL MOV AL,ZKEYEK ; Enable keyboard OUT ZKEYBRDC,AL XOR AX,AX ; Clear AX RET ; Jump to COMMAND.COM ; ; Error Exits for INIT ; COMERR: MOV BX,OFFSET COMMESG ; Get addr of message MOV CH,OFFSET COMMESGL ; Get length of message CALL PMESG ; Print the message COMERRL: JMP SHORT COMERRL ; Loop forever COMMESG DB CC_CR,CC_LF,CC_LF DB 'Error loading COMMAND.COM' DB CC_CR,CC_LF,CC_LF COMMESGL EQU (OFFSET $)-(OFFSET COMMESG) ; ; Data values for BIOS_INIT ; LDR_HDR DB FMT_SIZE DUP(?) ; Local storage for Loader header BBDRIVE DB ? ; Boot BIOS disk number BMDRIVE DB ? ; Boot MSDOS disk number DOS_INIT DW 0,0 ; Place to put addr of DOS ROM_VER DB ? ; Version number from rom MTR_DS_VAL DW ? ; Monitor ds value FNT_BUF DW ? ; Buffer for font reads ITERCNT DB ? ; Iteration count SBBSEC DW ? ; Sector of block B SBACRC DW ? ; Checksum of super block EBSIZ DW -1 ; Size of partition E: EBSEC DW -1 ; First sector FBSIZ DW -1 ; Size for F: FBSEC DW -1 ; Base sector for f: EBFLG DB 0 ; Flag from SBA for drive E: FBFLG DB 0 ; Flag from SBA for drive F: OSNAME DB 'Z-DOS ' PDSKPR LABEL NEAR ; DSKPR for partition reading ERRNZ PDSKPR,DSKPR_DRIVE DB 4 ; Drive 4 (or 5, same thing!) ERRNZ PDSKPR,DSKPR_SECTOR DW SBCSEC ; Sector to access ERRNZ PDSKPR,DSKPR_COUNT DW 1 ; Number of sectors ERRNZ PDSKPR,DSKPR_BUFF DW OFFSET PBUFF ; Offset of buffer DW 0 ; segment of buffer ERRNZ PDSKPR,DSKPR_SIZE DOS_NAME DB 'Z-DOS SYS' FCB LABEL NEAR ERRNZ FCB,FCB_DRIVE DB 0 ; Use default drive ERRNZ FCB,FCB_FNAME DB 'COMMAND ' ERRNZ FCB,FCB_EXT DB 'COM' ; Filename and extension ERRNZ FCB,FCB_CURBLK DB FCB_SIZE-FCB_CURBLK DUP (?) ERRNZ FCB,FCB_SIZE FNT_FCB LABEL NEAR ERRNZ FNT_FCB,FCB_DRIVE DB 0 ; Use default drive ERRNZ FNT_FCB,FCB_FNAME DB 'ALTCHAR ' ERRNZ FNT_FCB,FCB_EXT DB 'SYS' ; Filename and extension ERRNZ FNT_FCB,FCB_CURBLK DB FCB_SIZE-FCB_CURBLK DUP (?) ERRNZ FNT_FCB,FCB_SIZE 0000100B ;POLL COMMAND OCW3RIR EQU 00000010B ;READ IR REG OCW3RIS EQU 00000011B ;READ IS REG DATE TIME  or $F; ; This table tells the DOS the possible disk configurations ; that are possible. ; DISK_TAB: DB 12 ; Number of disk formats/drives ; This table must be ordered in groups ; ----- Group 1 ---------------- DB 0 ; Drive A: DW OFFSET DR5D8 ; 5.25 inch, double sided, 80 tracks DB 1 ; Drive B: DW OFFSET DR5D8 ; 5.25 inch, double sided, 80 tracks DB 2 ; Drive C: DW OFFSET DR8S1 ; 8 inch, single sided, single density DB 3 ; Drive D: DW OFFSET DR8S1 ; 8 inch, single sided, single density DB 4 ; Drive E: DW OFFSET DRWA1 ; 5.25 inch Winchester partition 1 DB 5 ; Drive F: DW OFFSET DRWA2 ; 5.25 inch winchester partition 2 ; ----- Group 2 ----------------- DB 0 ; Drive A: DW OFFSET DR5S4 ; 5.25 inch, single sided, 40 tracks DB 1 ; Drive B: DW OFFSET DR5S4 ; 5.25 inch, single sided, 40 tracks DB 2 ; Drive C: DW OFFSET DR8D2 ; 8 inch, double sided, double density DB 3 ; Drive D: DW OFFSET DR8D2 ; 8 inch, double sided, double density  ; ----- Group 3 ----------------- DB 0 ; Drive A: DW OFFSET DR5D4 ; 40 track double sided DB 1 ; Drive B: DW OFFSET DR5D4 ; 40 track double sided ; ; MS-DOS disk tables ; DR5D8 LABEL BYTE ; double density, 96 tpi, double sided disks ERRNZ DR5D8,DPT_SECSIZ DW 512 ; Sector size ERRNZ DR5D8,DPT_CLUSIZ DB 4 ; Cluster factor ERRNZ DR5D8,DPT_RESSEC DW 1 ; Reserved sectors ERRNZ DR5D8,DPT_FATCNT DB 2 ; Number of FAT's ERRNZ DR5D8,DPT_MAXENT DW 144 ; Number of directory entries ERRNZ DR5D8,DPT_DSKSIZ DW 80*8*2 ; Number of physical sectors ERRNZ DR5D8,DPT_SIZE DR5S4 LABEL BYTE ; 48tpi, double density, single sided ERRNZ DR5S4,DPT_SECSIZ DW 512 ; Sector size ERRNZ DR5S4,DPT_CLUSIZ DB 1 ; Cluster factor ERRNZ DR5S4,DPT_RESSEC DW 1 ; Reserved sectors ERRNZ DR5S4,DPT_FATCNT DB 2 ; Number of FAT's ERRNZ DR5S4,DPT_MAXENT DW 64 ; Number of directory entries ERRNZ DR5S4,DPT_DSKSIZ DW 8*40 ; Number of physical sectors ERRNZ DR5S4,DPT_SIZE DR5D4 LABEL BYTE ; 48tpi, double density, double sided ERRNZ DR5D4,DPT_SECSIZ DW 512 ; Sector size ERRNZ DR5D4,DPT_CLUSIZ DB 2 ; Cluster factor ERRNZ DR5D4,DPT_RESSEC DW 1 ; Reserved sectors ERRNZ DR5D4,DPT_FATCNT DB 2 ; Number of FAT's ERRNZ DR5D4,DPT_MAXENT DW 112 ; Number of directory entries ERRNZ DR5D4,DPT_DSKSIZ DW 8*40*2 ; Number of physical sectors ERRNZ DR5D4,DPT_SIZE DR8D2 LABEL BYTE ; 8" double density ERRNZ DR8D2,DPT_SECSIZ DW 1024 ; Sector size ERRNZ DR8D2,DPT_CLUSIZ DB 1 ; Cluster factor ERRNZ DR8D2,DPT_RESSEC DW 1 ; Reserved sectors ERRNZ DR8D2,DPT_FATCNT DB 2 ; Number of FAT's ERRNZ DR8D2,DPT_MAXENT DW 192 ; Number of directory entries ERRNZ DR8D2,DPT_DSKSIZ DW 77*8*2 ; Number of physical sectors ERRNZ DR8D2,DPT_SIZE DR8S1 LABEL BYTE ; single density, 8 inch ERRNZ DR8S1,DPT_SECSIZ DW 128 ; Sector size ERRNZ DR8S1,DPT_CLUSIZ DB 4 ; Cluster factor ERRNZ DR8S1,DPT_RESSEC DW 4 ; Reserved sectors ERRNZ DR8S1,DPT_FATCNT DB 2 ; Number of FAT's ERRNZ DR8S1,DPT_MAXENT DW 104 ; Number of directory entries ERRNZ DR8S1,DPT_DSKSIZ DW 77*26 ; Number of physical sectors ERRNZ DR8S1,DPT_SIZE ; This winchester partition is E: DRWA1 LABEL BYTE ; 5.25 inch winchester ERRNZ DRWA1,DPT_SECSIZ DW 512 ; Sector size ERRNZ DRWA1,DPT_CLUSIZ DB 4 ; Cluster factor ERRNZ DRWA1,DPT_RESSEC DW 2 ; Number of reserved sectors ERRNZ DRWA1,DPT_FATCNT DB 2 ; Number of FAT's ERRNZ DRWA1,DPT_MAXENT DW 480 ; Number of directory entries ERRNZ DRWA1,DPT_DSKSIZ DW (4*18*153)/2 ; Number of physical sectors ERRNZ DRWA1,DPT_SIZE ; This winchester partition is F:, back half of disk DRWA2 LABEL BYTE ; 5.25 inch winchester ERRNZ DRWA2,DPT_SECSIZ DW 512 ; Sector size ERRNZ DRWA2,DPT_CLUSIZ DB 4 ; Cluster factor ERRNZ DRWA2,DPT_RESSEC DW 2 ; Number of reserved sectors ERRNZ DRWA2,DPT_FATCNT DB 2 ; Number of FAT's ERRNZ DRWA2,DPT_MAXENT DW 480 ; Number of directory entries ERRNZ DRWA2,DPT_DSKSIZ DW (4*18*153)/2 ; Number of physical sectors ERRNZ DRWA2,DPT_SIZE ; Use default drive ERRNZ FNT_FCB,FCB_FNAME DB 'ALTCHAR ' ERRNZ FNT_FCB,FCB_EXT DB 'SYS' ; Filename and extension ERRNZ FNT_FCB,FCB_CURBLK DB FCB_SIZE-FCB_CURBLK DUP (?) ERRNZ FNT_FCB,FCB_SIZE 0000100B ;POLL COMMAND OCW3RIR EQU 00000010B ;READ IR REG OCW3RIS EQU 00000011B ;READ IS REG DATE TIME  or $F; ; Character I/O routines ; ; Special keys recognized by the BIOS ; ; These are the key codes generated by the keyboard processor. The key codes ; can be modified to be any key code the user wants. Note however that the ; key code chosen will NOT be placed in the type-ahead buffer, and so will ; never get passed to the system (or ZBASIC or others). Some other key ; choices and their codes are: ; ; Shift break - 0EAH ; Shift I LINE - 0E4H ; HELP - 095H ; Shift HELP - 0D5H ; ; For an entire list of key codes, see the Z100 technical manual in the ; keyboard section. ; SPECIAL_KEY EQU 0AAH ; "BREAK" key - clear type ahead PRINT_SCREEN_KEY EQU 0E2H ; Shift F12, print screen key ; Combinations of light pens/terminals have a latency when reporting ; a light pen hit. Some of this is built into the hardware, and the ; following value is an estimate, which is deducted from the value ; obtained from the hardware, which compensates for this. Users with ; non-standard terminals and light pens (no "standard" light pen is ; yet spec'd) will have to adjust even further in software. ; ; This is only in full character positions, so the closest we ; can get is to within 1 character. The pixel adjustment is ; left to the user, since it is felt that this is much less ; critical than the full character adjustment LPERROR EQU 5 ; 5 character positions off ; ; Data used by Character I/O routines ; ; Input queue sizes ZSERA_IQS EQU 255 ; Input queue size for SERIAL A ZSERB_IQS EQU 255 ; Input queue size for SERIAL B ZCON_IQS EQU 90 ; Input queue size for console ZCON_IQS1 EQU 80 ; Actual input queue size for console ; Data for console driver VSYNC_CNT DW 0 ; Number of unserviced vsyncs seen VSYNC_MAX EQU 5 ; Max number before force of service VIDEO_ROM DB ? ; Value of video control bits seen by ROM VIDEO_PGM DB ? ; Value of video control bits seen by program ; Input queue for the Console Q_ZCON DB ZCON_IQS DUP(?) ; Input queue for console CQ_ZCON LABEL BYTE ; Input queue descriptor for console ERRNZ CQ_ZCON,CQ_SADDR DW OFFSET Q_ZCON ; Addr of start of queue ERRNZ CQ_ZCON,CQ_EADDR DW (OFFSET Q_ZCON)+ZCON_IQS-1 ; Addr of end of queue ERRNZ CQ_ZCON,CQ_QSIZE DW ZCON_IQS ; Size of queue ERRNZ CQ_ZCON,CQ_ELMTS DW 0 ; Current number of elements in queue ERRNZ CQ_ZCON,CQ_STATUS DB 0 ; Current error status ERRNZ CQ_ZCON,CQ_FRONT DW OFFSET Q_ZCON ; Addr of front element in queue ERRNZ CQ_ZCON,CQ_REAR DW (OFFSET Q_ZCON)+ZCON_IQS-1 ; Addr of rear elem in queue ERRNZ CQ_ZCON,CQ_SEGM DW 0 ; Segment of que ERRNZ CQ_ZCON,CQ_SIZE ; Input queue for ZSERA 2661 USART Q_ZSERA DB ZSERA_IQS DUP(?) ; Input queue for ZSERA port CQ_ZSERA LABEL BYTE ; queue descriptor for ZSERA port ERRNZ CQ_ZSERA,CQ_SADDR DW OFFSET Q_ZSERA ; Addr of start of queue ERRNZ CQ_ZSERA,CQ_EADDR DW (OFFSET Q_ZSERA)+ZSERA_IQS-1 ; Addr of end of queue ERRNZ CQ_ZSERA,CQ_QSIZE DW ZSERA_IQS ; Size of queue ERRNZ CQ_ZSERA,CQ_ELMTS DW 0  ; Current number of elements in queue ERRNZ CQ_ZSERA,CQ_STATUS DB 0 ; Current error status ERRNZ CQ_ZSERA,CQ_FRONT DW OFFSET Q_ZSERA ; Addr of front element in queue ERRNZ CQ_ZSERA,CQ_REAR DW (OFFSET Q_ZSERA)+ZSERA_IQS-1 ; Addr of rear elem in queue ERRNZ CQ_ZSERA,CQ_SEGM DW 0 ; Segment of que ERRNZ CQ_ZSERA,CQ_SIZE ; Input queue for ZSERB 2661 USART Q_ZSERB DB ZSERB_IQS DUP(?) ; Input queue for ZSERB port CQ_ZSERB LABEL BYTE ; queue descriptor for ZSERB port ERRNZ CQ_ZSERB,CQ_SADDR DW OFFSET Q_ZSERB ; Addr of start of queue ERRNZ CQ_ZSERB,CQ_EADDR DW (OFFSET Q_ZSERB)+ZSERB_IQS-1 ; Addr of end of queue ERRNZ CQ_ZSERB,CQ_QSIZE DW ZSERB_IQS ; Size of queue ERRNZ CQ_ZSERB,CQ_ELMTS DW 0 ; Current number of elements in queue ERRNZ CQ_ZSERB,CQ_STATUS DB 0 ; Current error status ERRNZ CQ_ZSERB,CQ_FRONT DW OFFSET Q_ZSERB ; Addr of front element in queue ERRNZ CQ_ZSERB,CQ_REAR DW (OFFSET Q_ZSERB)+ZSERB_IQS-1 ; Addr of rear elem in queue ERRNZ CQ_ZSERB,CQ_SEGM DW 0 ; Segment of que ERRNZ CQ_ZSERB,CQ_SIZE ; Control table for the PRN: device CID_PRN LABEL BYTE ; device control table for PRN: ERRNZ CID_PRN,CID_CHRD CHRD_PRN LABEL BYTE ; Configuration table for PRN: ERRNZ CHRD_PRN,CHRD_CLASS DB CHRDCL_SER ; Serial printer ERRNZ CHRD_PRN,CHRD_ATTR DB 0 ; No special attributes ERRNZ CHRD_PRN,CHRD_PORT DW ZSERA ; First 2661 ERRNZ CHRD_PRN,CHRD_BAUD DB BD480 ; 4800 baud ERRNZ CHRD_PRN,CHRD_HSHK DB CHRDH_DCDH  ; DCD Positive ERRNZ CHRD_PRN,CHRD_BCTL DB CHRDB_SB1+CHRDB_CL8 ; 1 stop bit, no parity, 8 data bits ERRNZ CHRD_PRN,CHRD_ECNT DB 0 ; No ETX/ACK count ERRNZ CHRD_PRN,CHRD_NCNT DB 0 ; Don't send null's ERRNZ CHRD_PRN,CHRD_NCHR DB 0 ; Character to pad ERRNZ CHRD_PRN,CHRD_RES DB 6 DUP (0) ; Reserved ERRNZ CHRD_PRN,CHRD_SIZE DB CID_SIZE-CHRD_SIZE DUP (0) ERRNZ CID_PRN,CID_SIZE ; Control table for the AUX: device CID_AUX LABEL BYTE ; device control table for AUX: ERRNZ CID_AUX,CID_CHRD CHRD_AUX LABEL BYTE ; Configuration table for AUX: ERRNZ CHRD_AUX,CHRD_CLASS DB CHRDCL_SER ; Serial printer ERRNZ CHRD_AUX,CHRD_ATTR DB 0 ; No special attributes ERRNZ CHRD_AUX,CHRD_PORT DW ZSERB ; Second 2661 ERRNZ CHRD_AUX,CHRD_BAUD DB BD960 ; 9600 baud ERRNZ CHRD_AUX,CHRD_HSHK DB CHRDH_NO ; No handshake ERRNZ CHRD_AUX,CHRD_BCTL DB CHRDB_SB1+CHRDB_CL8 ; 1 stop bit, no parity, 8 data bits ERRNZ CHRD_AUX,CHRD_ECNT DB 0 ; No ETX/ACK count ERRNZ CHRD_AUX,CHRD_NCNT DB 0 ; Don't send null's ERRNZ CHRD_AUX,CHRD_NCHR DB 0 ; No pad character ERRNZ CHRD_AUX,CHRD_RES DB 6 DUP (0) ; Reserved ERRNZ CHRD_AUX,CHRD_SIZE DB CID_SIZE-CHRD_SIZE DUP (0) ERRNZ CID_AUX,CID_SIZE ; Control table for the CON: device CID_CON LABEL BYTE ; device control table for CON: ERRNZ CID_CON,CID_CHRD CHRD_CON LABEL BYTE ; Configuration table for CON: ERRNZ CHRD_CON,CHRD_CLASS DB CHRDCL_CRT ; System CRT ERRNZ CHRD_CON,CHRD_ATTR DB 0 ; No special attributes ERRNZ CHRD_CON,CHRD_PORT DW ZSERA ; First 2661 ERRNZ CHRD_CON,CHRD_BAUD DB BD480 ; 4800 baud ERRNZ CHRD_CON,CHRD_HSHK DB CHRDH_DCDH ; DCD Positive ERRNZ CHRD_CON,CHRD_BCTL DB CHRDB_SB1+CHRDB_CL8 ; 1 stop bit, no parity, 8 data bits ERRNZ CHRD_CON,CHRD_ECNT DB 0 ; No ETX/ACK count ERRNZ CHRD_CON,CHRD_NCNT DB 0 ; Don't send null's ERRNZ CHRD_CON,CHRD_NCHR DB 0 ; No pad character ERRNZ CHRD_CON,CHRD_RES DB 6 DUP (0) ; Reserved ERRNZ CHRD_CON,CHRD_SIZE ERRNZ CID_CON,CID_CLASS DW CIDCL_CRT ; Is a CRT ERRNZ CID_CON,CID_TYPE DB CID_SIZE-CID_TYPE DUP (0) ERRNZ CID_CON,CID_SIZE TCID DB CID_SIZE DUP(?) ; Temporary CID PAGE ; ; ISR_KD - Interrupt service routine for Keyboard, Video vertical retrace, ; and light pen. ; ISR_KD: INC WORD PTR CS:RECURLV ; Bump recursion level, first time through ? JNZ ISR_KD1 ; No, then skip set up of stack MOV CS:SAVESP,SP ; Set up a new stack MOV CS:SAVESS,SS PUSH CS POP SS MOV SP,OFFSET(BIOS_SIZE+BIOS_WORKSP) ISR_KD1: PUSH AX ; Save regs PUSH BX PUSH CX PUSH DX PUSH SI PUSH DI PUSH BP PUSH DS PUSH ES ;?? STI ; Let higher priorty interrupts in ; ; Check for interrupts until none are present ; ISR_KDL: ; Check for interrupt from PIA IN AL,ZPIA+PIACTLA ; Get status TEST AL,PIAIRQ1 OR PIAIRQ2 ; either vsync or light pen interrupt? JZ ISR_KD2 ; No, skip to keyboard check MOV AH,AL ; Save status ; Check for light pen as source of interrupt TEST AH,PIAIRQ1 ; Did light pen cause interrupt ? JZ ISR_KD1A ; No, skip ; Check light pen switch IN AL,ZPIA+PIADATA ; Read PA TEST AL,040H ; Check light pen bit JNZ ISR_KDL1 ; Yep, was light pen MOV AL,AH ; Restore it in AL JMP SHORT ISR_KD1A ; Nope, bail out ; Was light pen ISR_KDL1: CALL ISR_KDLP ; Check for vertical retrace as source of interrupt ISR_KD1A: TEST AH,PIAIRQ2 ; Did vertical retrace cause interrupt ? JZ ISR_KD1B ; No, skip INC WORD PTR CS:VSYNC_CNT ; Bump count of vsyncs seen IN AL,ZPIA+PIADATA ; Read PIA(clears interrupt request) CMP WORD PTR CS:VSYNC_CNT,VSYNC_MAX ; Have too many vsyncs gone by ? JA ISR_KD1AZ ; Yes, force service TEST AL,00010000B ; Is vertical sync still active ? JZ ISR_KD1B ; No, skip ISR_KD1AZ: CALL FAR PTR MTR_TTY_INTR ; Yes, let ROM monitor handle it MOV WORD PTR CS:VSYNC_CNT,0 ; Show vsync serviced ; Clear vertical retrace/light pen interrupt ISR_KD1B: IN AL,ZPIA+PIADATA ; Read PIA (Clears interrupt request, if not already cleared) AND AL,01011111B ; Clear vsync/light pen flip flops OUT ZPIA+PIADATA,AL ; Clear vsysc flip flop IN AL,ZDIPSW ; Dummy I/O to drive clock on PIA IN AL,ZPIA+PIADATA ; Read PIA OR AL,10100000B ; Enable vsync/light pen to cause interrupts OUT ZPIA+PIADATA,AL ; Let vsync cause interrupts ; Check for keyboard interrupt ISR_KD2: IN AL,ZKEYBRDS ; Get status of keyboard TEST AL,ZKEYOBF ; Is output buffer empty ? JZ ISR_KDR ; Yes, nothing more to do IN AL,ZKEYBRDD ; No, read char(clears interrupt request) XOR AH,AH ; Set AH = 0 INT INT_UKBA ; Do the interrupt CLI ; Insure interrupts are off OR AH,AH ; Still zero? (No one wanted it) JNZ ISR_KDLJ ; Nope, some one else got it ; Nobody wanted the key, put it in the que CMP AL,SPECIAL_KEY ; Was special key hit ? JE ISR_KDSK ; Yes, go process it ; Check for print screen key CMP AL,PRINT_SCREEN_KEY ; Was it this one? JNZ ISR_KD2A ; Nope  TEST CS:BYTE PTR PRSC_IN_PROGRESS,0FFH ; One currently running? JNZ ISR_KDLJ ; Yes, ignore this key ; Had a PRINT_SCREEN_KEY MOV CS:BYTE PTR PRSC_IN_PROGRESS,0FFH ; Flag busy INT INT_PRSCA CLI ; Interrupts back off MOV CS:BYTE PTR PRSC_IN_PROGRESS,0 ; Turn it back off JMP SHORT ISR_KDLJ ; And exit ; Check if queue is full ISR_KD2A: MOV BX,WORD PTR CS:CQ_ZCON+CQ_ELMTS ; BX = number in queue ADD BX,10 ; Insure expansion room CMP BX,WORD PTR CS:CQ_ZCON+CQ_QSIZE ; Is it full yet? JNC ISR_KDFL CALL FAR PTR MTR_DKBD ; Translate and store char(AL has char) JMP ISR_KDL ; See if more interrupts ISR_KDFL: MOV AL,ZKEYBEP ; Get beep command OUT ZKEYBRDC,AL ; Beep keyboard ISR_KDLJ: JMP ISR_KDL ; See if more interrupts ISR_KDSK: MOV BX,OFFSET CQ_ZCON ; Get addr of queue descriptor CALL Q_FLUSH ; Flush the typeahead queue JMP ISR_KDL ; See if more interrupts ISR_KDR: CLI ; Turn off interrupts for a bit MOV AL,OCW2OP+OCW2EOI OUT ZM8259A+OCW2,AL ; Tell 8259A that interrupt serviced POP ES ; Recover regs POP DS POP BP POP DI POP SI POP DX POP CX POP BX POP AX DEC WORD PTR CS:RECURLV ; Dec recursion level, at bottom ? JNS ISR_KDR1 ; No, skip MOV SS,CS:SAVESS ; Yes, recover stack MOV SP,CS:SAVESP ISR_KDR1: IRET ; and return ; ; ISR_KDLP - Service light pen hit ; ISR_KDLP: AND AL,NOT 040H ; Clear it for next time OUT ZPIA+PIADATA,AL ; Set it so MOV AL,AH ; Clear status PUSH AX ; Save the status PUSH BX ; Location for LP address MOV AL,CRTLPH ; Read hi address value OUT ZCRTC+CRTREG,AL ; Set it IN AL,ZCRTC+CRTDAT ; Read the value MOV BH,AL MOV AL,CRTLPL ; Read low address value OUT ZCRTC+CRTREG,AL IN AL,ZCRTC+CRTDAT ; Read it MOV BL,AL ; BX = relative address of hit, now get real address MOV AL,CRTSAH ; Read hi address value OUT ZCRTC+CRTREG,AL ; Set it IN AL,ZCRTC+CRTDAT ; Read the value MOV AH,AL MOV AL,CRTSAL ; Read low address value OUT ZCRTC+CRTREG,AL IN AL,ZCRTC+CRTDAT ; Read it, AX = start address SUB BX,AX ; BX = relative hit address SUB BX,WORD PTR ASP_LPEFV ; Subtract light pen error value IN AL,ZLPEN ; Read light pen hit register MOV BYTE PTR ASP_LPHFV,1 ; Show a hit MOV WORD PTR ASP_LPHCAV,BX ; Show address MOV BYTE PTR ASP_LPHPAV,AL ; and pixel address INT INT_ULPA ; User interrupt routine CLI POP BX POP AX ; Restore interrupts and AX RET PAGE ; ; KQ_PUT - Put character in keyboard typeahead queue ; (Note: This is only called by ROM monitor) ; ; Call with: ; AL = char ; ; Assumes: No keyboard interrupt can occur during execution ; KQ_PUT PROC FAR PUSH BX ; Save regs MOV BX,OFFSET CQ_ZCON ; Get addr of console input queue CALL NEAR PTR Q_PUT ; Store char in queue, any errors ? JNC KQ_RT ; No, skip MOV AL,ZKEYBEP ; Get keyboard beep command OUT ZKEYBRDC,AL ; Beep keyboard KQ_RT: POP BX ; Restore reg RET ; and return KQ_PUT ENDP PAGE ; ; ISR_SA - Interrupt service routine for the ZSERA port, a 2661 USART. ; If the transmitter is empty, it is simply turned off. ; If the receiver has data, it is read and stored in ; the input queue. ; ISR_SA: PUSH AX ; Save regs PUSH BX ;?? STI ; Let higher interrupts in MOV BX,OFFSET CQ_ZSERA ; Get addr of queue descriptor IN AL,ZSERA+EPSTAT ; Get status MOV AH,AL ; Save it TEST AH,EPRXR ; Does receiver have data ? JZ ISR_SA1 ; No, skip IN AL,ZSERA+EPDATA ; Read char PUSH AX ; Save AH status XOR AH,AH ; Show not yet used INT INT_USAIA ; Interrupt routine CLI OR AH,AH ; Was it used POP AX JNZ ISR_SA1 CALL Q_PUT ; Put char in queue, did it fit ? JNC ISR_SA1 ; Yes, skip OR BYTE PTR CS:CQ_STATUS[BX],CHRS_RXOF ; Show error ISR_SA1: TEST AH,EPTXR ; Is transmitter empty ? JZ ISR_SA2 ; No, nothing to do IN AL,ZSERA+EPCMD ; Read command AND AL,NOT EPTXEN ; Turn off transmitter OUT ZSERA+EPCMD,AL ; Execute command ISR_SA2: MOV AL,OCW2OP+OCW2EOI ; Tell interrupt controller OUT ZM8259A+OCW2,AL ; that interrupt serviced POP BX ; Restore regs POP AX IRET ; and return PAGE ; ; ISR_SB - Interrupt service routine for the ZSERB port, a 2661 USART. ; If the transmitter is empty, it is simply turned off. ; If the receiver has data, it is read and stored in ; the input queue. ; ISR_SB: PUSH AX ; Save regs PUSH BX ;?? STI ; Let higher interrupts in MOV BX,OFFSET CQ_ZSERB ; Get addr of queue descriptor IN AL,ZSERB+EPSTAT ; Get status MOV AH,AL ; Save it TEST AH,EPRXR ; Does receiver have data ? JZ ISR_SB1 ; No, skip IN AL,ZSERB+EPDATA ; Read char PUSH AX XOR AH,AH ; Show not yet used INT INT_USBIA ; Interrupt on it CLI OR AH,AH ; Used? POP AX JNZ ISR_SB1 ; Yes, ignore CALL Q_PUT ; Put char in queue, did it fit ? JNC ISR_SB1 ; Yes, skip OR BYTE PTR CS:CQ_STATUS[BX],CHRS_RXOF ; Show error ISR_SB1: TEST AH,EPTXR ; Is transmitter empty ? JZ ISR_SB2 ; No, nothing to do IN AL,ZSERB+EPCMD ; Read command AND AL,NOT EPTXEN ; Turn off transmitter OUT ZSERB+EPCMD,AL ; Execute command ISR_SB2: MOV AL,OCW2OP+OCW2EOI ; Tell interrupt controller OUT ZM8259A+OCW2,AL ; that interrupt serviced POP BX ; Restore regs POP AX IRET ; and return PAGE ; ; Q_STATUS - Queue status ; ; Nondestructive read of a queue ; ; Call with: ; BX -> CQ(queue descriptor) ; ; Returns: ; DH = Queue size ; DL = Number of elements in queue ; Z set - AL = 0, no chars in queue ; Z clear - AL = first char in queue ; ; Assumes: No interrupt can occur which also touches queue ; Q_STATUS PROC NEAR PUSH SI ; Save regs MOV SI,WORD PTR CS:CQ_ELMTS[BX] ; Get number of elems in queue MOV DX,SI ; Get element count MOV DH,BYTE PTR CS:CQ_QSIZE[BX] ; Get size of queue XOR AL,AL ; Assume no element in queue OR SI,SI ; Was there any ? JZ Q_SR ; No, return MOV SI,WORD PTR CS:CQ_FRONT[BX] ; Get addr of front element PUSH ES PUSH SI MOV SI,WORD PTR CS:CQ_SEGM[BX] ; Get segment MOV ES,SI POP SI LODS BYTE PTR ES:0 ; Get element POP ES Q_SR: POP SI ; Restore regs RET ; and return Q_STATUS ENDP PAGE ; ; Q_FLUSH - Flush queue ; ; Call with: ; BX -> CQ(queue descriptor) ; ; Assumes: No interrupt can occur which also touches queue ; Q_FLUSH PROC NEAR PUSH SI ; Save regs MOV SI,WORD PTR CS:CQ_SADDR[BX] ; Get start addr  MOV WORD PTR CS:CQ_FRONT[BX],SI ; Set front elem ptr MOV SI,WORD PTR CS:CQ_EADDR[BX] ; Get end addr MOV WORD PTR CS:CQ_REAR[BX],SI ; Set rear elem ptr MOV WORD PTR CS:CQ_ELMTS[BX],0 ; Set number of elems to 0 MOV BYTE PTR CS:CQ_STATUS[BX],0 ; Clear errors POP SI ; Recover regs RET ; and return Q_FLUSH ENDP PAGE ; ; Q_GET - Get an element from a queue ; ; Call with: ; BX -> CQ(queue descriptor) ; ; Returns: ; Z set - queue empty ; Z clear - AL = char removed from front of queue ; ; Assumes: No interrupt can occcur which also touches queue ; Q_GET PROC NEAR PUSH SI ; Save regs MOV SI,WORD PTR CS:CQ_ELMTS[BX] ; Get number of elems in queue OR SI,SI ; Is queue empty ? JZ Q_G2 ; Yes, skip DEC SI ; Decr number of elemts MOV WORD PTR CS:CQ_ELMTS[BX],SI ; Store updated count MOV SI,WORD PTR CS:CQ_FRONT[BX] ; Get addr of front element PUSH ES PUSH SI MOV SI,WORD PTR CS:CQ_SEGM[BX] ; Get segment MOV ES,SI POP SI LODS BYTE PTR ES:0 ; Get element POP ES CMP SI,WORD PTR CS:CQ_EADDR[BX] ; Should ptr be wrapped ? JNA Q_G1 ; No, skip MOV SI,WORD PTR CS:CQ_SADDR[BX] ; Wrap ptr Q_G1: MOV WORD PTR CS:CQ_FRONT[BX],SI ; Store updated ptr OR SI,SI ; Clear Z flag Q_G2: POP SI ; Restore regs RET ; and return Q_GET ENDP PAGE ; ; Q_PUT - Put an element in a queue ; Call with: ; AL = character to put in queue ; BX -> CQ(queue descriptor) ; ; Returns: ;  CY clear - no error ; CY set - no room in queue to put element ; ; Assumes: No interrupt can occur which also touches queue ; Q_PUT PROC NEAR PUSH SI ; Save regs MOV SI,WORD PTR CS:CQ_ELMTS[BX] ; Get number currently in queue CMP SI,WORD PTR CS:CQ_QSIZE[BX] ; Is there room for another ? JB Q_P1 ; Yes, skip STC ; No, show error POP SI ; Recover regs RET ; and return Q_P1: INC SI ; Bump element count MOV WORD PTR CS:CQ_ELMTS[BX],SI ; Store updated count MOV SI,WORD PTR CS:CQ_REAR[BX] ; Get rear ptr INC SI ; Bump it CMP SI,WORD PTR CS:CQ_EADDR[BX] ; Should it be wrapped JNA Q_P2 ; No, skip MOV SI,WORD PTR CS:CQ_SADDR[BX] ; Wrap ptr Q_P2: PUSH ES PUSH SI MOV SI,WORD PTR CS:CQ_SEGM[BX] ; Get segment MOV ES,SI POP SI MOV BYTE PTR ES:[SI],AL ; Get element POP ES MOV WORD PTR CS:CQ_REAR[BX],SI ; Store updated ptr CLC ; Clear CY to show success POP SI ; Recover regs RET ; and return Q_PUT ENDP PAGE ; ; BIOS_AUXFUNC - Perform a AUX: related function ; ; Call with: ; AH = function to perform ; ; AH = CHR_WRITE - Write character function ; AH = CHR_READ - Read character function ; AH = CHR_STATUS - Status function(may need ES:BX) ; AH = CHR_CONTROL - Control function(may need ES:BX) ; AH = CHR_LOOK - Nondestructive read function ; ; Returns: ; CY = 0 - function executed normally ; CY = 1 - function returns error code in AX ; ; Uses: BX, DX, DI, and SI ; BIOS_AUXFUNC: MOV SI,OFFSET CID_AUX ; Get internal printer control table addr JMP NEAR PTR CHRFUNC ; Join common code ; ; BIOS_PRNFUNC - Perform a PRN related function ; ; Call with: ; AH = function to perform ; ; AH = CHR_WRITE - Write character function ; AH = CHR_READ - Read character function ; AH = CHR_STATUS - Status function(may need ES:BX) ; AH = CHR_CONTROL - Control function(may need ES:BX) ; AH = CHR_LOOK - Nondestructive read function ; ; Returns: ; CY = 0 - function executed normally ; CY = 1 - function returns error code in AX ; ; Uses: BX, DX, DI, and SI ; BIOS_PRNFUNC: MOV SI,OFFSET CID_PRN ; Get internal aux control table addr JMP NEAR PTR CHRFUNC ; Join common code ; ; BIOS_CONFUNC - Perform a CON: related function ; ; Call with: ; AH = function to perform ; ; AH = CHR_WRITE - Write character function ; AH = CHR_READ - Read character function ; AH = CHR_STATUS - Status function(may need ES:BX) ; AH = CHR_CONTROL - Control function(may need ES:BX) ; AH = CHR_LOOK - Nondestructive read function ; ; Returns: ; CY = 0 - function executed normally ; CY = 1 - function returns error code in AX ; ; Uses: BX, DX, DI, and SI ; BIOS_CONFUNC: MOV SI,OFFSET CID_CON ; Get internal console control table addr ; JMP NEAR PTR CHRFUNC ; Join common code PAGE ; ; CHRFUNC - Perform a character device related function ; ; Call with: ; SI -> internal control table (CID) ; AH = function to perform ; ; AH = CHR_WRITE - Write character function ; AH = CHR_READ - Read character function ; AH = CHR_STATUS - Status function(may need ES:BX) ; AH = CHR_CONTROL - Control function(may need ES:BX) ; AH = CHR_LOOK - Nondestructive read function ; ; Returns: ; CY = 0 - function executed normally ; CY = 1 - function returns error code in AX ; ; Uses: BX, DX, DI, and SI ; CHRFUNC PROC FAR CMP AH,CHR_FMAX ; Is function code valid ? JNA CF1 ; Yes, skip MOV AX,CHRE_ILGFH ; No, get ILLEGAL FUNCTION error code STC ; Show error by setting CY RET ; and return CF1: PUSH DS ; Save DS PUSH CS ; Setup new DS POP DS MOV DI,AX ; Save AX MOV AL,AH ; Put function in lower part XOR AH,AH ; Clear upper part SHL AX,1 ; Make into word offset XCHG AX,DI ; Restore AX and make offset available CALL WORD PTR CHRFC[DI] ; Case to function POP DS ; Recover DS RET ; and return CHRFUNC ENDP CHRFC: DW OFFSET CHRFWR ; Write function DW OFFSET CHRFRD ; Read function DW OFFSET CHRFST ; Status function DW OFFSET CHRFCT ; Control function DW OFFSET CHRFLK ; Look function PAGE ; ; CHRFWR - Character device write function ; ; Call with: ; SI -> CID ; AL = character to write ; ; Returns: ; CY clear - char written ; CY set - AX has error code ; ; Uses: BX, DX, DI CHRFWR PROC NEAR CMP WORD PTR CID_TYPE[SI],CIDTY_CSP ; Is it special console ? JNE CHRFWR0Z ; No, skip ; Short cut ROM call PUSH AX ; Save regs PUSH CX PUSH BP PUSH DS PUSH ES XOR AH,AH INT INT_UCRTA ; Let user deal with it OR AH,AH JNZ SKIPCHR ; If user wanted it MOV AH,AL ; Save char to display IN AL,ZVIDEO+PIADATA ; Read video control port for program MOV VIDEO_PGM,AL ; Save it MOV AL,VIDEO_ROM ; Get ROM's value OUT ZVIDEO+PIADATA,AL ; Restore ROM's video status MOV AL,AH ; Restore char CALL MTR_SCRT ; Have ROM monitor display char IN AL,ZVIDEO+PIADATA ; Read video control port for ROM MOV VIDEO_ROM,AL ; Save it MOV AL,VIDEO_PGM ; Get program's value OUT ZVIDEO+PIADATA,AL ; Restore program's video status SKIPCHR: POP ES ; Restore regs POP DS POP BP POP CX POP AX CLC ; Show success RET ; and return ; Normal output processing CHRFWR0Z: MOV BX,AX ; Save char to write CALL CHRFOS ; Get output status, any errors ? JNC CHRFWR1 ; No, skip RET ; Yes, return error (CY already set) CHRFWR1: MOV AL,BL ; Recover char to write TEST BYTE PTR CID_CHRD+CHRD_ATTR[SI],CHRDA_SPO ; Should parity be stripped ? JZ CHRFWR2 ; No, skip AND AL,07FH ; Strip the parity bit CHRFWR2: TEST BYTE PTR CID_CHRD+CHRD_ATTR[SI],CHRDA_MLO ; Should lower case be mapped to upper ? JZ CHRFWR3 ; No, skip CALL UPCASE ; Convert char to upper case CHRFWR3: MOV DI,CID_CLASS[SI] ; Get device class CALL WORD PTR CHRFODC[DI] ; Output character CMP AL,CID_CHRD+CHRD_NCHR[SI] ; Should nulls be sent ? JNE CHRFWR4 ; No, skip MOV AL,CID_CHRD+CHRD_NCNT[SI] ; Yes, get number of nulls to send MOV CID_NCTR[SI],AL ; Store as down counter CHRFWR4: MOV AX,BX ; Recover AX CMP BYTE PTR CID_CHRD+CHRD_HSHK[SI],CHRDH_EAH ; Using ETX/ACK ? JNE CHRFWR6 ; No, skip MOV BL,BYTE PTR CID_ECTR[SI] ; Get char count INC BL ; Bump it CMP AL,CC_ESC ; Is char an ESC ? JNE CHRFWR5 ; No, skip MOV BH,BYTE PTR CID_CHRD+CHRD_ECNT[SI] ; Get max count SUB BH,3 ; Allow for 3 char ESC sequences CMP BL,BH ; Will it fit ? JNA CHRFWR5 ; Yes, skip MOV BL,BH ; No, use decrement count so it will CHRFWR5: MOV BYTE PTR CID_ECTR[SI],BL ; Store new count CHRFWR6: CLC ; Show success RET ; and return CHRFWR ENDP PAGE ; ; CHRFOS - Get character device output status ; ; Call with: ; SI -> CID ; BL = possible char(only ESC's are significant when ETX/ACK'ing) ; ; Returns: ; CY clear - output device ready ; CY set - AX has error code ; ; Uses: AX, DI ; CHRFOS PROC NEAR MOV DI,CID_CLASS[SI] ; Get device class CALL WORD PTR CHRFOSC[DI] ; Get status from device(returned in AL) AND AL,CID_ORM[SI] ; Issolate ready/busy bits in status XOR AL,CID_OPM[SI] ; Adjust for polarity CMP AL,CID_ORM[SI] ; Is device busy(not ready) ? JE CHRFOS1 ; No, skip MOV AX,CHRE_WRB ; Yes, get DEVICE BUSY error code STC ; Show failure RET ; and return CHRFOS1: CMP BYTE PTR CID_CHRD+CHRD_HSHK[SI],CHRDH_EAH ; Is / hndshkng being used ? JNE CHRFOS5 ; No, skip ; Using / handshaking TEST BYTE PTR CID_ST[SI],CHRS_WA ; Are we waiting for ? JNZ CHRFOS2 ; Yes, go to it MOV AL,CID_ECTR[SI] ; Get character counter CMP AL,CID_CHRD+CHRD_ECNT[SI] ; Is it equal to limit ? JNB CHRFOS2A ; Yes, skip JMP CHRFOS12 ; No, skip to check for nulls CHRFOS2A: MOV BYTE PTR CID_ECTR[SI],0 ; Reinitialize counter MOV AL,CC_ETX ; Get char CALL WORD PTR CHRFODC[DI] ; Output character OR BYTE PTR CID_ST[SI],CHRS_WA ; Show waiting for MOV AX,CHRE_WRB ; Get DEVICE BUSY error code STC ; Show failure RET ; and return ; Waiting on CHRFOS2: CALL CHRFIS ; Get input status, is char available ? JNC CHRFOS3 ; Yes, skip  RET ; No, return error(CY already set) CHRFOS3: CALL WORD PTR CHRFIDC[DI] ; Read character AND AL,07FH ; Strip parity CMP AL,CC_ACK ; Is character an JE CHRFOS4 ; Yes, skip MOV AX,CHRE_ILR ; No, get ILLEGAL RESPONCE error message STC ; Show failure RET ; and return CHRFOS4: AND BYTE PTR CID_ST[SI],NOT CHRS_WA ; Clear wait flag JMP CHRFOS12 ; Go check on nulls ; Test for / handshaking CHRFOS5: CMP BYTE PTR CID_CHRD+CHRD_HSHK[SI],CHRDH_DCH ; Is / handshaking being used JE CHRFOS6 ; Yes, skip JMP CHRFOS12 ; No, go check on nulls ; Using / handshaking CHRFOS6: TEST BYTE PTR CID_ST[SI],CHRS_WD ; Are we waiting for ? JZ CHRFOS9 ; No, skip ; Waiting on CALL CHRFIS ; Get input status, was char available ? JNC CHRFOS7 ; Yes, skip MOV AX,CHRE_WRB ; No, get DEVICE BUSY error code RET ; Return failure (CY already set) CHRFOS7: CALL WORD PTR CHRFIDC[DI] ; Read the data AND AL,07FH ; Mask off parity bit CMP AL,CC_DC1 ; Was character a ? JE CHRFOS8 ; Yes, skip MOV AX,CHRE_ILR ; No, get ILLEGAL RESPONSE error code STC ; Show failure RET ; and return CHRFOS8: AND BYTE PTR CID_ST[SI],NOT CHRS_WD ; Show no longer waiting JMP CHRFOS12 ; Go check on nulls ; Not waiting on , see if present CHRFOS9: CALL CHRFIS ; Get input status, was char available JNC CHRFOS10 ; Yes, skip JMP CHRFOS12 ; No, go check on nulls ; Char available, see if CHRFOS10: CALL WORD PTR CHRFIDC[DI] ; Read the data AND AL,07FH ; Mask off parity bit CMP AL,CC_DC3 ; Was character a ? JE CHRFOS11 ; Yes, skip MOV AX,CHRE_ILR ; No, get ILLEGAL RESPONSE error code STC ; Show failure RET ; and return CHRFOS11: OR BYTE PTR CID_ST[SI],CHRS_WD ; Show waiting on MOV AX,CHRE_WRB ; Get DEVICE BUSY error code STC ; Show failure RET ; and return ; Check if a NULL should be written CHRFOS12: CMP BYTE PTR CID_NCTR[SI],0 ; Any nulls need to be written ? JNE CHRFOS13 ; Yes, skip CLC ; No, show success RET ; and return CHRFOS13: DEC BYTE PTR CID_NCTR[SI] ; Decr number of NULLS remaining to send MOV AL,CC_NUL ; Get NULL char CALL WORD PTR CHRFODC[DI] ; Output char MOV AX,CHRE_WRB ; Show device busy STC ; Show failure RET ; and return CHRFOS ENDP PAGE ; ; CHRFRD - Character device read function ; ; Call with: ; SI -> CID ; ; Returns: ;  CY clear - AL has char that was read ; CY set - AX has error code ; ; Uses: BX, DX, DI CHRFRD PROC NEAR MOV BX,AX ; Save AX CALL CHRFIS ; Get input status, any errors ? JNC CHRFRD1 ; No, skip RET ; Yes, return failure(CY already set) CHRFRD1: MOV DI,CID_CLASS[SI] ; Get device class CALL WORD PTR CHRFIDC[DI] ; Read a character TEST BYTE PTR CID_CHRD+CHRD_ATTR[SI],CHRDA_SPI ; Should parity be stripped ? JZ CHRFRD2 ; No, skip AND AL,07FH ; Strip the parity bit CHRFRD2: TEST BYTE PTR CID_CHRD+CHRD_ATTR[SI],CHRDA_MLI ; Should lower case be mapped to upper ? JZ CHRFRD3 ; No, skip CALL UPCASE ; Convert char to upper case CHRFRD3: MOV AH,BH ; Restore AH CLC ; Show success RET ; and return CHRFRD ENDP PAGE ; ; CHRFIS - Get character device input status ; ; Call with: ; SI -> CID ; ; Returns: ; CY clear - input device has char ; CY set - AX has error code ; ; Uses: AX, DI ; CHRFIS PROC NEAR MOV DI,CID_CLASS[SI] ; Get device class CALL WORD PTR CHRFISC[DI] ; Get status AND AL,CID_IRM[SI] ; Issolate ready/busy bits XOR AL,CID_IPM[SI] ; Adjust for polarity CMP AL,CID_IRM[SI] ; Is character ready ? JNE CHRFIS1 ; No, skip CLC ; Yes, show success RET ; and return CHRFIS1: MOV AX,CHRE_RDNR ; Get READER NOT READY error code STC ; Show failure RET ; and return CHRFIS ENDP PAGE ; ; CHRFLK - Nondestructive read (check if input queue is empty and ; if not, then return a copy of the first element) ; ; Call with: ; SI -> CID ; ; Returns: ; CY clear - AL = copy of first char in queue ; CY set - AX has error code ; ; Uses: AX, DI, BX ; CHRFLK PROC NEAR MOV DI,CID_CLASS[SI] ; Get device class CALL WORD PTR CHRFGIQD[DI] ; Get queue descriptor addr, does it exist? JNC CHRFLK1 ; Yes, skip MOV AX,CHRE_NIQ ; Return "No input queue" error RET CHRFLK1: CALL Q_STATUS ; Any chars in input queue ? JNZ CHRFLK2 ; Yes, skip MOV AX,CHRE_IQE ; Return "Input queue emptry" error STC ; Set CY to show error CHRFLK2: RET ; and return CHRFLK ENDP PAGE ; ; CHRFGIQD - Get input queue descriptor ; ; Call with: ; SI -> CID ; ; Returns: ; CY clear - BX -> CQ (character queue descriptor) ; CY set - device has no input queue ; CHRFGIQD PROC NEAR DW OFFSET CHRFGI_CRT ; Internal video/keyboard DW OFFSET CHRFGI_SER ; 2661-2 ports DW OFFSET CHRFGI_PAR ; PIA port ; Internal video/keyboard CHRFGI_CRT: MOV BX,OFFSET CQ_ZCON ; Get addr of input queu descriptor CLC ; Show success RET ; and return ; 2661 serial ports CHRFGI_SER: MOV BX,CID_CHRD+CHRD_PORT[SI] ; Get base port CMP BX,ZSERA ; Is it the serial A port ? JNE CHRFGI_SER1 ; No, skip MOV BX,OFFSET CQ_ZSERA ; Get addr of input queue desc CLC ; show success RET CHRFGI_SER1: CMP BX,ZSERB ; Is it the serial B port ? JNE CHRFGI_SER2 ; No, skip MOV BX,OFFSET CQ_ZSERB ; Get addr of input queue desc CLC ; show success RET CHRFGI_SER2: STC ; Show failure RET ; PIA parallel port CHRFGI_PAR: STC ; Show failure RET CHRFGIQD ENDP PAGE ; ; Raw Output data routines ; ; Call with: ; AL = char to write ; SI -> CID ; ; Uses: DX, AH ; CHRFODC PROC NEAR DW OFFSET CHRFOD_CRT ; Internal video/keyboard DW OFFSET CHRFOD_SER ; 2661-2 ports DW OFFSET CHRFOD_PAR ; PIA port ; Internal video/keyboard output data CHRFOD_CRT: CLI ; Disable interrupts for a bit INC WORD PTR RECURLV ; Bump recursion level, first time through ? JNZ CHRFOD_CRT1 ; No, skip MOV SAVESP,SP ; Set up new stack MOV SAVESS,SS PUSH CS POP SS MOV SP,OFFSET(BIOS_SIZE+BIOS_WORKSP) CHRFOD_CRT1: STI ; Enable interrupts PUSH AX ; Save regs PUSH BX PUSH CX PUSH DX PUSH SI PUSH DI PUSH BP PUSH DS PUSH ES MOV AH,AL ; Save char to display IN AL,ZVIDEO+PIADATA ; Read video control port for program MOV VIDEO_PGM,AL ; Save it MOV AL,VIDEO_ROM ; Get ROM's value OUT ZVIDEO+PIADATA,AL ; Restore ROM's video status MOV AL,AH ; Restore char XOR AH,AH ; AH = flag, AL = character INT INT_UCRTA ; Exectue CRT interrupt OR AH,AH ; Check flag JNZ CHRFOD_CRT1B ; If to ignore it CALL MTR_SCRT ; Have ROM monitor display char CHRFOD_CRT1B: IN AL,ZVIDEO+PIADATA ; Read video control port for ROM MOV VIDEO_ROM,AL ; Save it MOV AL,VIDEO_PGM ; Get program's value OUT ZVIDEO+PIADATA,AL ; Restore program's video status POP ES ; Restore regs POP DS POP BP POP DI POP SI POP DX POP CX POP BX POP AX CLI ; Disable interrupts DEC WORD PTR RECURLV ; Dec recursion level, at bottom JNS CHRFOD_CRT2 ; No, skip MOV SS,SAVESS ; Yes, recover stack MOV SP,SAVESP CHRFOD_CRT2: STI ; Enable interrupts RET ; and return ; 2661-2 output data CHRFOD_SER: CLI PUSH AX XOR AH,AH ; Show AH = 0 CMP WORD PTR CID_CHRD+CHRD_PORT[SI],ZSERA ; Get base port JNZ CHRFOD_SERINT1 INT INT_USAOA ; Interrupt on it JMP SHORT CHRFOD_SERINT2 CHRFOD_SERINT1: INT INT_USBOA ; Serial B interrupt CHRFOD_SERINT2: CLI OR AH,AH ; Test return value POP AX JNZ CHRFOD_SER1 ; If to ignore the character MOV DX,CID_OPORT[SI] ; Get output data port addr OUT DX,AL ; Write the byte MOV AH,AL ; Save char MOV DX,CID_CPORT[SI] ; Get command port IN AL,DX ; Get current command OR AL,EPTXEN ; Enable transmitter OUT DX,AL MOV AL,AH ; Recover char CHRFOD_SER1: STI RET ; and return ; PIA output data CHRFOD_PAR: PUSH AX ; Save character for a bit MOV AH,AL ; Get second copy of char MOV DX,CID_SPORT[SI] ; Get status port OUT DX,AL ; Output part of data byte MOV DX,CID_OPORT[SI] ; Get output data port CLI ; Disable interrupts for a bit MOV AL,10101100B ; Get assumed current value AND AH,00000011B ; Issolate new part OR AL,AH ; Insert new value OUT DX,AL ; Output new value AND AL,11111011B ; Clear strobe bit OUT DX,AL ; Strobe printer OR AL,00000100B ; Set strobe line back high OUT DX,AL ; Set back to normal STI ; Enable interrupts POP AX ; Recover AX RET CHRFODC ENDP PAGE ; ; Raw Output status routines ; ; Call with: ; SI -> CID ; ; Returns: ; AL = device status ; ; Uses: DX, AH ; CHRFOSC PROC NEAR DW OFFSET CHRFOS_CRT ; Internal video/keyboard DW OFFSET CHRFOS_SER ; 2661-2 ports DW OFFSET CHRFOS_PAR ; PIA port ; Internal video/keyboard output status CHRFOS_CRT: XOR AL,AL ; Is always ready RET ; 2661-2 output status CHRFOS_SER: CLI ; Disable interrupts MOV DX,CID_CPORT[SI] ; Get command port IN AL,DX ; Get current command MOV AH,AL ; Save copy OR AL,EPTXEN ; Enable transmitter OUT DX,AL ; Turn on transmitter MOV DX,CID_SPORT[SI] ; Get status port IN AL,DX ; Get status XCHG AL,AH ; Save status/get command MOV DX,CID_CPORT[SI] ; Get command port OUT DX,AL ; Restore to previous state MOV AL,AH ; Restore status STI ; Turn on interrupts RET ; and return ; PIA output status CHRFOS_PAR: MOV DX,CID_SPORT[SI] ; Get status port IN AL,DX ; Get status AND AL,00000011B ; Clear high part RET CHRFOSC ENDP PAGE ; ; Raw Input data routines ; ; Call with: ; SI -> CID ; ; Returns: ; AL = data byte read ; ; Uses: DX ; CHRFIDC PROC NEAR DW OFFSET CHRFID_CRT ; Internal video/keyboard DW OFFSET CHRFID_SER ; 2661-2 ports DW OFFSET CHRFID_PAR ; PIA port ; Internal video/keyboard input data CHRFID_CRT: PUSH BX ; Save regs MOV BX,OFFSET CQ_ZCON ; Get addr of queue descriptor CHRFID_QL: CLI ; Disable interrupts for a bit CALL Q_GET ; Get char from type ahead queue STI ; Turn interrupts back on NOP ; Let an interrupt in JZ CHRFID_QL ; If typeahead queue empty POP BX ; Restore regs RET ; and return ; 2661-2 input data CHRFID_SER: MOV DX,CID_CHRD+CHRD_PORT[SI] ; Get base port  CMP DX,ZSERA ; Is it the serial A port ? JNE CHRFID_SER1 ; No, skip PUSH BX ; Yes, save regs MOV BX,OFFSET CQ_ZSERA ; Get addr of queue descriptor JMP CHRFID_QL ; Join common code CHRFID_SER1: CMP DX,ZSERB ; Is it the serial B port ? JNE CHRFID_SER2 ; No, skip PUSH BX ; Yes, save regs MOV BX,OFFSET CQ_ZSERB ; Get addr of queue descriptor JMP CHRFID_QL ; Join common code CHRFID_SER2: MOV DX,CID_IPORT[SI] ; Get input data port IN AL,DX ; Read data RET ; PIA input data CHRFID_PAR: XOR AL,AL ; You can't read from the parallel printer RET CHRFIDC ENDP PAGE ; ; Raw Input status routines ; ; Call with: ; SI -> CID ; ; Returns: ; AL = status ; AH = raw status ; DH = input queue size ; DL = number of elements in queue ; CHRFISC PROC NEAR DW OFFSET CHRFIS_CRT ; Internal video/keyboard DW OFFSET CHRFIS_SER ; 2661-2 ports DW OFFSET CHRFIS_PAR ; PIA port ; Internal video/keyboard input status CHRFIS_CRT: PUSH BX ; Save regs MOV BX,OFFSET CQ_ZCON ; Get addr of queue descriptor XOR AH,AH ; Clear raw status CHRFIS_QS: CLI ; Disable interrupts MOV AL,CQ_STATUS[BX] ; Get status OR BYTE PTR CID_ST[SI],AL ; Propagate to CID CALL Q_STATUS ; Is there a character in the queue ? JZ CHRFIS_QS1 ; No, skip MOV AL,0FFH ; Yes, show not empty CHRFIS_QS1: STI ; Turn interrupts back on POP BX ; Restore regs RET ; and return ; 2661-2 input status CHRFIS_SER: MOV DX,CID_SPORT[SI] ; Get status port IN AL,DX ; Get status MOV AH,AL ; Move to proper reg MOV DX,CID_CHRD+CHRD_PORT[SI] ; Get base port CMP DX,ZSERA ; Is it the serial A port ? JNE CHRFIS_SER1 ; No, skip PUSH BX ; Yes, save regs MOV BX,OFFSET CQ_ZSERA ; Get addr of queue descriptor JMP CHRFIS_QS ; Join common code CHRFIS_SER1: CMP DX,ZSERB ; Is it the serial B port ? JNE CHRFIS_SER2 ; No, skip PUSH BX ; Yes, save regs MOV BX,OFFSET CQ_ZSERB ; Get addr of queue descriptor JMP CHRFIS_QS ; Join common code CHRFIS_SER2: XOR DX,DX ; Clear queue stats RET ; PIA input status CHRFIS_PAR: XOR AX,AX ; Meaningless XOR DX,DX ; Clear queue stats RET CHRFISC ENDP PAGE ; ; CHRFST - Get character device status function ; ; Call with: ; SI -> CID ; AL = Subfunction ; ; AL = CHR_SFGS - Get status ; AL = CHR_SFGC - Return configuration info to addr ES:BX ; ; Returns: ; CY clear - ; CHR_SFGS - AH = synthesized status ; AL = raw status ; BH = input queue size ; BL = number of elements in queue ; CHR_SFGC - Printer configuration is copied to addr ES:BX ; CY set - AX has error code ; ; Uses: DX, DI ; CHRFST PROC NEAR CMP AL,CHR_SFGS ; Is function, get status ? JNE CHRFST1 ; No, skip MOV DI,CID_CLASS[SI] ; Get device class XOR BH,BH ; Clear status byte CALL CHRFIS ; Get input status, errors ? JC CHRFST0A ; Yes, skip OR BH,CHRS_RXR ; No, show receiver has data CHRFST0A: CALL CHRFOS ; Get output status, errors ? JC CHRFST0B ; Yes, skip OR BH,CHRS_TXR ; No, show transmitter ready CHRFST0B: OR BH,CID_ST[SI] ; Add other status bits MOV DI,CID_CLASS[SI] ; Get device class CALL WORD PTR CHRFSTC[DI] ; Get raw status MOV AL,AH ; Get raw status MOV AH,BH ; Move synthesized status to proper reg ;??? put in other errors like parity and framing etc MOV BX,DX ; Get queue stats CMP BYTE PTR CID_NCTR[SI],0 ; Sending nulls ? JE CHRFST0C ; No, skip OR AH,CHRS_SN ; Yes, show it CHRFST0C: CLC ; Show success RET ; and return CHRFSTC: DW OFFSET CHRFIS_CRT ; Same as input status DW OFFSET CHRFIS_SER ; Same as input status DW OFFSET CHRFOS_PAR ; Same as output status ; Check if status is Get configuration info CHRFST1: CMP AL,CHR_SFGC ; Is subfunction get configuration info ? JE CHRFST2 ; Yes, skip MOV AX,CHRE_ILGFL ; No, get error code STC ; Show error RET ; and return ; Move device configuration info to caller CHRFST2: LEA SI,CID_CHRD[SI] ; Get source ptr MOV DI,BX ; Get dest ptr PUSH CX ; Save CX MOV CX,CHRD_SIZE ; Get length of CHRD CLD ; Set direction REP MOVSB ; Copy the CHRD POP CX ; Recover CX CLC ; Show success RET ; and return CHRFST ENDP PAGE ; ; CHRFCT - Character device control function ; ; Call with: ; SI -> CID ; AL = Subfunction ; ; AL = CHR_CFSU - Set up new configuration parms using those at ES:BX ; AL = CHR_CFCI - Clear input ; AL = CHR_CFCO - Clear output ; ; Returns: ; CY clear - success ; CY set - AX has error code ; ; Uses: DI, DX CHRFCT PROC NEAR CMP AL,CHR_CFSU ; Is function, set up new parms ? JE CHRFCT0 ; Yes, skip JMP CHRFCT1 ; No, to next check CHRFCT0: ; Set up new configuration PUSH CX ; Save CX ; Clear temp CID to zero PUSH SI ; Save some regs PUSH ES PUSH DS ; Set up ES POP ES MOV SI,OFFSET TCID ; Get source MOV DI,OFFSET TCID+1 ; Get dest MOV BYTE PTR TCID,0 ; Store zero in first byte MOV CX,CID_SIZE-1 ; Get count for smear CLD ; Set direction REP MOVSB ; Smear zero over CID ; Copy caller's CHRD into temp CID ; (SI and ES on stack) MOV SI,BX ; Get source offset POP DS ; Get source segment MOV DI,OFFSET TCID+CID_CHRD ; Get dest offset(dest segment already setup) MOV CX,CHRD_SIZE ; Get size REP MOVSB ; Move caller's CHRD into temp CID ; Restore regs PUSH DS ; Exchange DS and ES PUSH ES POP DS POP ES POP SI ; Recover SI ; Finish init of CID MOV CL,TCID+CID_CHRD+CHRD_CLASS ; Get new device class CMP CL,CHRDCL_MAX ; Is class valid ? JNA CHRFCT0A ; Yes, skip JMP CHRCTS_BEX ; No, skip to failure exit CHRFCT0A: XOR CH,CH ; Clear high part SHL CX,1 ; Convert to word ptr MOV WORD PTR TCID+CID_CLASS,CX ; Store in temp CID MOV DI,CX ; Make avail as index JMP WORD PTR CHRFCTSC[DI] ; Case to class CHRFCTSC: DW OFFSET CHRCTS_CRT DW OFFSET CHRCTS_SER DW OFFSET CHRCTS_PAR ; Internal Video/keyboard CHRCTS_CRT: MOV BYTE PTR TCID+CID_CHRD+CHRD_HSHK,CHRDH_NO ; No handshaking MOV BYTE PTR TCID+CID_CHRD+CHRD_NCNT,0 ; Don't send nulls TEST BYTE PTR TCID+CID_CHRD+CHRD_ATTR,0FFH ; Any attributes ? JNZ CHRCTS_CRT1 ; Yes, skip MOV WORD PTR TCID+CID_TYPE,CIDTY_CSP ; No, show special type CHRCTS_CRT1: MOV BYTE PTR TCID+CID_IRM,0FFH ; Store input ready mask JMP CHRCTS_GEX ; Join common exit ; 2661-2 serial CHRCTS_SER: ; Check if baud rate OK CMP BYTE PTR TCID+CID_CHRD+CHRD_BAUD,BDMAX ; Is baud rate valid ? JNA CHRCTS_SER1 ; Yes, skip JMP CHRCTS_BEX ; No, join failure exit CHRCTS_SER1: ; Compute ports MOV CX,WORD PTR TCID+CID_CHRD+CHRD_PORT ; Get base port OR CX,CX ; Was port specified ? JNZ CHRCTS_SER1B ; Yes, skip MOV CX,ZSERA ; No, assume a port CMP SI,OFFSET CID_AUX ; Are we setting up AUX: ? JNE CHRCTS_SER1A ; No, skip MOV CX,ZSERB ; Yes, get default port for it CHRCTS_SER1A: MOV WORD PTR TCID+CID_CHRD+CHRD_PORT,CX ; Save base port CHRCTS_SER1B: ADD CX,EPDATA ; Compute input/output ports MOV WORD PTR TCID+CID_IPORT,CX ; Store input data port MOV WORD PTR TCID+CID_OPORT,CX ; Store output data port ADD CX,EPSTAT-EPDATA ; Compute status port MOV WORD PTR TCID+CID_SPORT,CX ; Store status port ADD CX,EPCMD-EPSTAT ; Compute command port MOV WORD PTR TCID+CID_CPORT,CX ; Store command port ; Check if handshaking is ok and setup ready and polarity masks MOV CL,TCID+CID_CHRD+CHRD_HSHK ; Get handshaking type CMP CL,CHRDH_MAX ; Is type valid ? JNA CHRCTS_SER2 ; Yes, skip JMP CHRCTS_BEX ; No, join failure exit CHRCTS_SER2: XOR CH,CH ; Clear upper half MOV DI,CX ; Make avail as index SHL DI,1 ; Mult by 4 (the size of a table entry) SHL DI,1 MOV CL,BYTE PTR CHRCTS_SITAB+0[DI] ; Get first entry MOV TCID+CID_IRM,CL ; Store input ready mask MOV CL,BYTE PTR CHRCTS_SITAB+1[DI] ; Get second entry MOV TCID+CID_IPM,CL ; Store input polarity mask MOV CL,BYTE PTR CHRCTS_SITAB+2[DI] ; Get third entry MOV TCID+CID_ORM,CL ; Store output ready mask MOV CL,BYTE PTR CHRCTS_SITAB+3[DI] ; Get fourth entry MOV TCID+CID_OPM,CL ; Store output polarity ready mask ; Program the 2661 MOV DX,WORD PTR TCID+CID_CPORT ; Get command port MOV CL,AL ; Save AL CLI ; Disable interrutps XOR AL,AL ; Turn unit off OUT DX,AL IN AL,DX ; Reset mode register ptr MOV AL,BYTE PTR TCID+CID_CHRD+CHRD_BCTL ; Get mode reg 1 AND AL,CHRDB_SB+CHRDB_PT+CHRDB_PC+CHRDB_CL ; Issolate settable bits OR AL,EPA16X ; Add mode factor MOV DX,EPMODE ; Get mode port offset ADD DX,WORD PTR TCID+CID_CHRD+CHRD_PORT ; Compute mode port OUT DX,AL ; Set mode reg 1 MOV AL,EPMR2A ; Get mode/clk selector mode reg 2 OR AL,BYTE PTR TCID+CID_CHRD+CHRD_BAUD ; Add baud rate OUT DX,AL ; Set mode reg 2 MOV AL,EPNORM+EPRTS+EPRESE+EPRXEN+EPDTR ; Get command to turn on 2661 MOV DX,WORD PTR TCID+CID_CPORT ; Get command port OUT DX,AL ; Turn on 2661 MOV DX,WORD PTR TCID+CID_IPORT ; Get input port IN AL,DX ; Clear device IN AL,DX MOV AL,CL ; Restore AL STI ; Restore interrupts JMP CHRCTS_GEX ; Join common exit CHRCTS_SITAB: ; No handshaking: input ready, input polarity, output ready, output polarity DB EPRXR DB 0 DB EPTXR DB 0 ; / handshaking: input ready, input polarity, output ready, output polarity DB EPRXR DB 0 DB EPTXR DB 0 ; / handshaking: input ready, input polarity, output ready, output polarity DB EPRXR DB 0 DB EPTXR DB 0 ; DCD high handshaking: input ready, input polarity, output ready, output polarity DB EPDCD+EPRXR DB 0 DB EPDCD+EPTXR DB 0 ; DCD low handshaking: input ready, input polarity, output ready, output polarity DB EPDCD+EPRXR DB 0 DB EPDCD+EPTXR DB EPDCD ; DSR high handshaking: input ready, input polarity, output ready, output polarity DB EPDSR+EPRXR DB 0 DB EPDSR+EPTXR DB 0 ; DSR low handshaking: input ready, input polarity, output ready, output polarity DB EPDSR+EPRXR DB 0 DB EPDSR+EPTXR DB EPDSR ; PIA Parallel CHRCTS_PAR: MOV CX,ZPIA ; Get Base port MOV WORD PTR TCID+CID_CHRD+CHRD_PORT,CX ; Store it ADD CX,PIADATB ; Compute status port MOV WORD PTR TCID+CID_SPORT,CX ; Store status port ADD CX,PIADATA-PIADATB ; Compute output data port MOV WORD PTR TCID+CID_OPORT,CX ; Store output data port MOV BYTE PTR TCID+CID_CHRD+CHRD_HSHK,CHRDH_NO ; No handshaking MOV BYTE PTR TCID+CID_ORM,00000001B ; Store output ready mask MOV BYTE PTR TCID+CID_OPM,00000001B ; Store output polarity mask JMP CHRCTS_GEX ; Join common exit ; Common success exit for set up CHRCTS_GEX: ; Copy temp CID to CID at SI PUSH SI ; Save SI for later MOV DI,SI ; Set up DI, SI for move MOV SI,OFFSET TCID PUSH ES ; Save ES PUSH DS ; Set up ES POP ES MOV CX,CID_SIZE ; Get size of CID REP MOVSB ; Copy CID  POP ES ; Recover ES POP SI ; Recover SI MOV DI,CID_CLASS[SI] ; Get class CALL WORD PTR CHRFCTIC[DI] ; Clear input queue POP CX ; Recover CX CLC ; Show success RET ; And return ; Common failure exit for set up CHRCTS_BEX: POP CX ; Recover CX MOV AX,CHRE_BSUP ; Get BAD SETUP error code STC ; Show failure RET ; and return ; Check if subfunction is clear input CHRFCT1: CMP AL,CHR_CFCI ; Is function clear input ? JNE CHRFCT2 ; No, skip MOV DI,CID_CLASS[SI] ; Get device class CALL WORD PTR CHRFCTIC[DI] ; Case to device RET ; And return CHRFCTIC: DW OFFSET CHRCTI_CRT DW OFFSET CHRCTI_SER DW OFFSET CHRCTI_PAR ; Internal video/keyboard clear input CHRCTI_CRT: PUSH BX ; Save regs MOV BX,OFFSET CQ_ZCON ; Get addr of queue descriptor CHRCTI_QF: CLI ; Disable interrupts CALL Q_FLUSH ; Clear the typeahead queue STI ; Turn interrupts back on CLC ; Show success POP BX ; Restore regs RET ; and return ; 2661-1 clear input CHRCTI_SER: CLI ; Disable interrupts MOV DX,WORD PTR CID_CPORT[SI] ; Get command port IN AL,DX ; Get current command AND AL,NOT EPRXEN ; Turn off receiver OR AL,EPRESE ; and clear errors OUT DX,AL ; Do it OR AL,EPRXEN ; Or in command to turn it on OUT DX,AL ; Turn on receiver MOV DX,WORD PTR CID_IPORT[SI] ; Get input port IN AL,DX ; Clear receiver IN AL,DX MOV DX,CID_CHRD+CHRD_PORT[SI] ; Get base port CMP DX,ZSERA ; Is it the serial A port ? JNE CHRCTI_SER1 ; No, skip PUSH BX ; Yes, save regs MOV BX,OFFSET CQ_ZSERA ; Get addr of queue descriptor JMP CHRCTI_QF ; Join common code CHRCTI_SER1: CMP DX,ZSERB ; Is it the serial B port ? JNE CHRCTI_SER2 ; No, skip PUSH BX ; Yes, save regs MOV BX,OFFSET CQ_ZSERB ; Get addr of queue descriptor JMP CHRCTI_QF ; Join common code CHRCTI_SER2: CLC ; Show success STI ; Turn on interrupts RET ; and return ; PIA clear input CHRCTI_PAR: ; ; (Nothing to do) ; CLC  ; Show success RET ; and return ; Check if subfunction is clear output CHRFCT2: CMP AL,CHR_CFCO ; Is subfunction clear output ? JE CHRFCT3 ; Yes, go to it MOV AX,CHRE_ILGFL ; No, get error code STC ; Show failure RET ; and return CHRFCT3: MOV DI,CID_CLASS[SI] ; Get device class CALL WORD PTR CHRFCTOC[DI] ; Case to device RET ; and return CHRFCTOC: DW OFFSET CHRCTO_CRT DW OFFSET CHRCTO_SER DW OFFSET CHRCTO_PAR ; Internal video/keyboard clear output CHRCTO_CRT: ; ; (Nothing to do) ; CLC ; Show success RET ; and return ; 2661-2 clear output CHRCTO_SER: MOV AL,EPNORM+EPRTS+EPRESE+EPDTR+EPRXEN ; Turn off transmitter MOV DX,WORD PTR CID_CPORT[SI] ; Get command port OUT DX,AL ; Turn off transmitter CLC ; Show success RET ; and return ; PIA clear output CHRCTO_PAR: ; ; (Nothing to do) ; CLC ; Show success RET ; and return CHRFCT ENDP ; ; UPCASE - Convert character to uppper case ; ; Call with: ; AL - character to convert ; ; Returns: ; AL - converted char ; UPCASE PROC NEAR CMP AL,'a' ; Is character less than an 'a' ? JB UPCASE1 ; Yes, skip to end CMP AL,'z' ; Is character greater than a 'z' ? JA UPCASE1 ; Yes, skip to end AND AL,05FH ; No, convert to upper case UPCASE1: RET UPCASE ENDP PAGE ; ; default interrupt handler routines ; ; ;**** NOTE: The interrupt routines are on a physical device level, i.e. ; there is no way to interrupt on PRN or AUX or CON output, but only ; on the physical output to Serial A, Serial B, CRT/KYB, or Light pen ; ; ; ISR_UKB - User keyboard interrupt ; ISR_UCRT - User CRT output interrupt ; ; ENTRY: ; AL = Keycode ; AH = 0 if no one has yet handled this key ; ; EXIT: ; AL = Keycode ; If (AH = 0 on entry) ; AH = 0 if we don't want it ; AH != 0 if we processed it (BIOS will ignore) ; else ; AH != 0 ; ; USES: AH ; ; NOTE: Users should exit from their routine by simply using ; a JMPF to the next routine wanting interrupts (found at ; 0:int_uk). In this way, more than one routine can trap keyboard ; keys. The use flag (in AH) is used to inform the bios that ; the key code is special (if AH != 0) and should NOT be placed ; in the queue, or is not special (if AH = 0) and should be ; treated as a normal character. ; ISR_UKB: IRET ; Return to BIOS ISR_UCRT: IRET ; ; ISR_USAI - Serial A interrupt routine ; ISR_USAO - Serial A output routine ; ; ENTRY, EXIT, USAGE, and NOTES from above apply ; ISR_USAI: IRET ISR_USAO: IRET ; ; ISR_USBI - Serial B interrupt routine ; ISR_USBO - Serial B output routine ; ENTRY, EXIT, USAGE, and NOTES from above apply ; ISR_USBI: IRET ISR_USBO: IRET ; ; ISR_ULP - Light Pen interrupt routine ; ; ENTRY: ; BX = Character address of hit ; Address is (line * 80) + column ; ; AL = Address within the character cell ; ; 76543210 ; **** - Scan line hit ; * - Not used ; *** - pixel on scan line ; ; EXIT: NONE ; ; USES: NONE ; ; See notes on interrupt handling above ; ISR_ULP: IRET ; ; ISR_PRSC - Print Screen Subroutine ; ; Entry: None ; ; Exit: None ; ; Uses: None ; ; This interrupt, as opposed to the interrupts above, should ; have it's vector completely stolen by the replacing routine. ; the new routine should exit with an IRET, and never give ; this routine back control, since this would cause a second ; screen image to be printed. ; ISR_PRSC: IRET  ; Use default drive ERRNZ FNT_FCB,FCB_FNAME DB 'ALTCHAR ' ERRNZ FNT_FCB,FCB_EXT DB 'SYS' ; Filename and extension ERRNZ FNT_FCB,FCB_CURBLK DB FCB_SIZE-FCB_CURBLK DUP (?) ERRNZ FNT_FCB,FCB_SIZE 0000100B ;POLL COMMAND OCW3RIR EQU 00000010B ;READ IR REG OCW3RIS EQU 00000011B ;READ IS REG DATE TIME  or $F PAGE ; ; BIOS_STATUS - Console status ; ; Check if a character is ready at the console. ; ; Returns: ; "Z" clear - character in AL ; "Z" set - AL = 0 (No character ready) ; ; Uses: No registers are modified ; BIOS_STATUS PROC FAR PUSH BX ; Save regs PUSH DI PUSH SI PUSH DX PUSH AX MOV AH,CHR_LOOK ; Get Look function PUSH CS ; Make into far call CALL NEAR PTR BIOS_CONFUNC ; Get copy of first char in queue, empty? MOV BL,0 ; Assume queue empty, was it ? JC BSTAT1 ; Yes, skip MOV BL,AL ; No, Save char BSTAT1: MOV AL,0FFH ; Get -1 ADC AL,0 ; Set "Z" flag appropriately POP AX ; Recover AX MOV AL,BL ; Get char POP DX ; Restore regs POP SI POP DI POP BX RET ; and return BIOS_STATUS ENDP PAGE ; ; BIOS_CONIN - Console input ; ; Wait for character from the console, then return the character. ; ; Returns: ; AL = character ; ; Uses: No registers are modified ; BIOS_CONIN PROC FAR PUSH BX ; Save regs PUSH DI PUSH SI PUSH DX BCONIN1: PUSH AX MOV AH,CHR_READ ; Get read function PUSH CS ; Make call a far call CALL NEAR PTR BIOS_CONFUNC ; Read char, any errors ? MOV BL,AL ; Save char POP AX JC BCONIN1 ; If an error, then try again MOV AL,BL ; Get char POP DX ; Restore regs POP SI POP DI POP BX RET ; and return BIOS_CONIN ENDP ; ; BIOS_FLUSH - Flush the keyboard type ahead queue ; ; Uses: No registers are changed. ;  BIOS_FLUSH PROC FAR PUSH BX ; Save regs PUSH DI PUSH SI PUSH DX PUSH AX MOV AH,CHR_CONTROL ; Get control function MOV AL,CHR_CFCI ; Get clear input subfunction PUSH CS ; Make call a far call CALL NEAR PTR BIOS_CONFUNC ; Clear input, (ignore errors) POP AX ; Restore regs POP DX POP SI POP DI POP BX RET ; and return BIOS_FLUSH ENDP PAGE ; ; BIOS_CONOUT - Console output ; ; Call with: ; AL = character to output ; ; Uses: No registers are changed. ; BIOS_CONOUT PROC FAR PUSH BX ; Save regs PUSH DI PUSH SI PUSH DX BCONOUT1: PUSH AX MOV AH,CHR_WRITE ; Get write function PUSH CS ; Make call a far call CALL NEAR PTR BIOS_CONFUNC ; Write char, any errors ? POP AX JC BCONOUT1 ; If an error, then try again POP DX ; Restore regs POP SI POP DI POP BX RET ; and return BIOS_CONOUT ENDP  ; ; BIOS_PRINT - Printer output ; ; Output the character to the printer. ; ; Call with: ; AL = character to print ; ; Uses: No regs are changed. ; BIOS_PRINT PROC FAR PUSH BX ; Save regs PUSH DI PUSH SI PUSH DX BPRINTL: PUSH AX MOV AH,CHR_WRITE ; Get write function code PUSH CS ; Make call into far call CALL NEAR PTR BIOS_PRNFUNC ; Print char, any errors POP AX JC BPRINTL ; Yes, try again POP DX ; Restore regs POP SI POP DI POP BX RET BIOS_PRINT ENDP  ; Use default drive ERRNZ FNT_FCB,FCB_FNAME DB 'ALTCHAR ' ERRNZ FNT_FCB,FCB_EXT DB 'SYS' ; Filename and extension ERRNZ FNT_FCB,FCB_CURBLK DB FCB_SIZE-FCB_CURBLK DUP (?) ERRNZ FNT_FCB,FCB_SIZE 0000100B ;POLL COMMAND OCW3RIR EQU 00000010B ;READ IR REG OCW3RIS EQU 00000011B ;READ IS REG DATE TIME  or $F ; ; BIOS_AUXIN - Aux input ; ; Wait for a character from the MODEM(auxiliary) input device. ; ; Returns: ; AL = character read ; ; Uses: No registers are modified. ; BIOS_AUXIN PROC FAR PUSH BX ; Save regs PUSH DI PUSH SI PUSH DX BAUXIN1: PUSH AX MOV AH,CHR_READ ; Get read function code PUSH CS ; Make call into far call CALL NEAR PTR BIOS_AUXFUNC ; Read char, any errors MOV BL,AL ; Save char POP AX JC BAUXIN1 ; If an error, then try again MOV AL,BL ; Get char POP DX ; Restore regs POP SI POP DI POP BX RET ; and return BIOS_AUXIN ENDP ; ; BIOS_AUXOUT - Aux output ; ; Output a character to the MODEM(auxiliary) output device. ; ; Call with: ; AL = character to output ; ; Uses: No registers are modified. ; BIOS_AUXOUT PROC FAR PUSH BX ; Save regs PUSH DI PUSH SI PUSH DX BAUXOUT1: PUSH AX MOV AH,CHR_WRITE ; Get write function code PUSH CS ; Make call into far call CALL NEAR PTR BIOS_AUXFUNC ; Write char, any errors ? POP AX JC BAUXOUT1 ; If an error, then try again POP DX ; Restore regs POP SI POP DI POP BX RET ; and return BIOS_AUXOUT ENDP RNZ FNT_FCB,FCB_CURBLK DB FCB_SIZE-FCB_CURBLK DUP (?) ERRNZ FNT_FCB,FCB_SIZE 0000100B ;POLL COMMAND OCW3RIR EQU 00000010B ;READ IR REG OCW3RIS EQU 00000011B ;READ IS REG DATE TIME  or $F ; ; BIOS_READ - Read from the disk ; ; Call with: ; AL = Device number ; CX = Number of sectors to read ; DX = Logical sector number ; DS:BX = transfer addr ; ; Returns: ; CX = number of sectors not read ; Success: CY = 0 ; Failure: CY = 1, AL = error code ; ; Uses: All other regs(segment regs are preserved) ; BIOS_READ: MOV AH,DSK_READ ; Get function to do JMP NEAR PTR BIOS_RDWR ; Join common code ; ; BIOS_WRITE - Write to the disk ; ; Call with: ; AL = Device number ; AH = Verify flag: 0=no verify, 1=verify after write ; CX = Number of sectors to write ; DX = Logical sector number ; DS:BX = transfer addr ; ; Returns: ; CX = Number of sectors not written ; Success: CY = 0 ; Failure: CY = 1, AL = error code ; ; Uses: All other regs(segment regs are perserved) ; BIOS_WRITE: MOV AH,DSK_WRITE ; Get function to do (ignore verify for now) ; ; Common code for read and write ; BIOS_RDWR PROC FAR PUSH DS ; Save DS PUSH ES ; Save ES MOV CS: WORD PTR DSKPR+DSKPR_BUFF+2,DS ; Store DS PUSH CS ; Set up DS seg reg POP DS ; Put the parameters in the packet MOV BYTE PTR DSKPR+DSKPR_DRIVE,AL ; Drive number MOV WORD PTR DSKPR+DSKPR_SECTOR,DX ; Logical sector MOV WORD PTR DSKPR+DSKPR_COUNT,CX ; Sector count MOV WORD PTR DSKPR+DSKPR_BUFF,BX ; Offset of buffer MOV BX,OFFSET DSKPR ; Get addr of packet PUSH DS ; Set up ES seg reg POP ES MOV AL,AH ; Get function to do PUSHF ; Save interrupt status STI ; Turn interrupts on CALL DSK ; Perform the function, Did error occur ? LAHF ; Save flags POPF ; Restore interrupt status SAHF ; Restore flags JNC BIOS_RWF ; No, success so return MOV SI,-1 ; Start with entry -1 RW_EL: INC SI ; Bump entry number MOV AH,BYTE PTR RW_ERRB[SI] ; Get error code CMP AH,0FFH ; At end of table ? JE RW_EFI ; Yes, get out TEST AL,AH ; Do any bits match ? JZ RW_EL ; No, try next entry RW_EFI: MOV AL,BYTE PTR RW_ERRC[SI] ; Yes, get error code STC ; Turn on CY to show error BIOS_RWF: MOV CX,WORD PTR DSKPR+DSKPR_COUNT ; Return remaining sectors POP ES ; Restore ES POP DS ; Restore DS RET ; and return BIOS_RDWR ENDP ; Corresponding Z-DOS error codes RW_ERRC DB DSKE_WRITEP ; Write protect DB DSKE_NREADY ; Not ready DB DSKE_DATA ; Data error DB DSKE_SEEK ; Seek error DB DSKE_SECT ; Sector error DB DSKE_WFAULT ; Write fault DB DSKE_OTHER ; Catchall error ; List of errors generated by z207 RW_ERRB DB FDSWPV ; Write protect DB FDSNRD ; Not ready DB FDSCRC+FDSLDT ; CRC error and Lost data DB FDSSEK ; Seek error DB 0 DB FDSWTF ; Write fault DB -1 ; Translate z217 errors to z207 errors RW_ERRD DB WIEDNR,FDSNRD ; Drive not ready DB WIENSC,FDSSEK ; No seek complete DB WIENTZ,FDSSEK ; No track zero DB WIENI,FDSNRD ; No index pulse DB WIENDS,FDSNRD ; No drive select DB WIEHNF,FDSSEK ; No header AM found DB WIESKE,FDSSEK ; Seek error DB WIESNF,FDSSEK ; Sector not found DB WIEHECC,FDSSEK ; ECC error in header DB WIEDAM,FDSCRC+FDSLDT ; Data AM not found DB WIENECC,FDSCRC+FDSLDT ; Non-correctable ECC error DB WIECECC,FDSCRC+FDSLDT ; Correctable ECC error DB WIEWF,FDSWTF ; Write fault DB WIEIOC,-1 ; Illegal op code DB WIEIDA,FDSSEK ; Illegal disk address DB WIEFP,FDSWTF ; Drive format protected DB WIEWP,FDSWTF ; Drive write protected DB WIEMISC,-1 ; Misc. error DB -1,-1 ; Terminates table ; ; BIOS_DSKFUNC - Execute an arbitrary disk function (Interface to DSK) ; ; (See description of DSK for parameters) ; ; All regs are preserved ; BIOS_DSKFUNC PROC FAR CLI ; Turn off interrupts INC WORD PTR CS:RECURLV ; Bump recursion level, first time through ? JNZ BDSK1 ; No, skip MOV CS: SAVESP,SP ; Save current stack MOV CS: SAVESS,SS PUSH CS ; Set up new stack POP SS MOV SP,OFFSET(BIOS_SIZE+BIOS_WORKSP) BDSK1: STI ; Turn interrupts back on PUSH CX ; Save regs PUSH DX PUSH SI PUSH DI PUSH DS PUSH CS ; Set up DS POP DS CALL DSK ; Execute the function POP DS ; Restore regs POP DI POP SI POP DX POP CX CLI ; Turn interrupts off DEC WORD PTR CS:RECURLV ; Decr recursion level, at bottom ? JNS BDSK2 ; No, skip MOV SS,CS: SAVESS ; Restore stack MOV SP,CS: SAVESP BDSK2: STI ; Turn interrupts back on RET ; and return BIOS_DSKFUNC ENDP  ; ; BIOS_DSKCHG - Disk change test ; ; Check if the specified disk has been changed. ; ; Call with: ; AL = drive number ; ; Returns: ; CY = 0 (normal exit) ; = -1 if disk has been changed ; AH = 0 if it is not known if disk is changed ; = 1 if disk could not have been changed ; AL = drive number (can change) ; CY = 1 (error exit) ; AL = error code ; ; No other registers are changed. ; ;  ; BIOS_DSKCHG handles device mapping for the 8" drives, since ; bit densities can change, and BIOS_MAPDEV won't be able to ; get a valid FATID. ; ; Last modified: 7/29/82 - dtp ; BIOS_DSKCHG PROC FAR PUSH DS ; Save regs PUSH DI PUSH CS ; Set up DS POP DS MOV AH,AL ; Drive number in proper reg MOV AL,DSK_MAPDSK ; Get function PUSH CS ; Make call into far call CALL NEAR PTR BIOS_DSKFUNC ; Map drive number MOV DI,AX ; Get drive number AND DI,0FFH ; Isolate it  SHL DI,1 ; Convert it to a word index MOV DI,WORD PTR DSK_TPTR[DI] ; Get addr of DSK entry IF WINCH CMP AL,MAXDSK8 ; > 8" disk drive? JB DSKCHG0 ; Nope, is 5 or 8 ; Is > 8" disk drive, must be a winchester, DI = table entry TEST BYTE PTR [DI]+DSK_FLAG,DSK_ASN JZ BIOS_DSKCHGNR ; Not assigned, show not ready TEST BYTE PTR [DI]+DSK_SEL,SBAEFLNF ; Formatted? JNZ BIOS_DSKCHGNR ; Nope, show not ready MOV BYTE PTR BIOS_DSKCHV,1 JMP NEAR PTR BIOS_DSKCHG2 ENDIF ; Check if drive is still selected, if so assume disk has not been changed DSKCHG0: MOV BYTE PTR BIOS_DSKCHV,0 ; Assume don't know if disk changed CLI ; Disable interrupts MOV AH,BYTE PTR DSK_FLAG[DI] ; Get falg byte TEST AH,DSK_FDC ; Force disk change ? JNZ BIOS_DCHG ; Yes, skip TEST BYTE PTR DSKT_FG,0FFH ; Has select timed out ? JZ BIOS_DCHG ; Yes, skip CMP DI,DSK_LDRIVE ; Is last drive the same as the current one ? JNE BIOS_DCHG ; No, skip MOV BYTE PTR BIOS_DSKCHV,1 ; Yes, show disk hasn't changed BIOS_DCHG: STI ; Turn interrupts back on AND AH,NOT DSK_FDC ; Remove force disk change(if present) MOV BYTE PTR BIOS_DSKCHGA,AH ; Save flag value ; Make drive look single sided for status and restore call. AND AH,NOT DSK_FDS ; Turn off double sided MOV BYTE PTR DSK_FLAG[DI],AH ; Store back flag byte MOV BYTE PTR DSKPR+DSKPR_DRIVE,AL ; Store drive number PUSH ES ; Save regs PUSH BX MOV BX,CS ; Set up ES:BX to point to DSK parm pkt MOV ES,BX MOV BX,OFFSET DSKPR MOV AL,DSK_STATUS ; Get function PUSH CS ; Make call into far call CALL NEAR PTR BIOS_DSKFUNC ; Get status of drive, any errors ? JC BIOS_DSKCHG0 ; Yes, skip TEST BYTE PTR BIOS_DSKCHV,1 ; Is disk still selected ?(must clear CY) JNZ BIOS_DSKCHG0 ; Yes, don't do I/O PUSH AX ; Save status in AH MOV AL,DSK_RESET ; Get function PUSH CS ; Make call a far call CALL NEAR PTR BIOS_DSKFUNC ; Restore head POP AX ; Restore status BIOS_DSKCHG0: POP BX ; Restore regs POP ES MOV AL,BYTE PTR BIOS_DSKCHGA ; Get saved flags MOV BYTE PTR DSK_FLAG[DI],AL ; Restore original flag MOV AL,BYTE PTR DSKPR+DSKPR_DRIVE ; Get drive number JNC BIOS_DSKCHG0A ; If no 'C' set (no error) ; 'C' set, must be invalid or not ready drive BIOS_DSKCHGNR: STC MOV AL,DSKE_NREADY ; Show error JMP SHORT BIOS_DSKCHG2 ; Bail out ; Check for 5" disk drive, AH has auxilary status, AL has drive index BIOS_DSKCHG0A: CMP AL,MAXDSK5 ; Is disk a 5 incher ? JB BIOS_DSKCHG1A ; Yes, go to it ; Disk is 8", check for number of sides ; Set up DI as a table pointer MOV DI,AX ; Get drive index AND DI,0FFH ; Issolate drive number SHL DI,1 ; Convert it to word index MOV DI,DSK_TPTR[DI] ; Get addr of DSK entry TEST AH,AS2S ; Is disk double sided ? JNZ BIOS_DSKCHGDS ; Yes, go do it ; Set up of single sided/single density disks AND BYTE PTR DSK_FLAG[DI],NOT DSK_FDS ; Clear double sided OR BYTE PTR DSK_SEL[DI],CONSD ; Make single density MOV WORD PTR DSK_BPS[DI],128 ; Set sector size MOV WORD PTR DSK_BPWT[DI],5365 ; Set track size MOV WORD PTR DSK_BPRT[DI],5365 MOV BYTE PTR DSK_SPT[DI],26 ; Set sectors/track JMP SHORT BIOS_DSKCHG1A ; Skip other case ; Set up of double sided/double density disks BIOS_DSKCHGDS: ADD AL,OFFSET DSK_BMPVAL AND BYTE PTR DSK_SEL[DI],NOT CONSD ; Make double density OR BYTE PTR DSK_FLAG[DI],DSK_FDS ; Make double sided MOV WORD PTR DSK_BPS[DI],1024 ; Set sector size MOV WORD PTR DSK_BPWT[DI],10729 ; Set track size MOV WORD PTR DSK_BPRT[DI],10729 MOV BYTE PTR DSK_SPT[DI],8 ; Set sectors/track BIOS_DSKCHG1A: CLC ; Clear "C" to show no error BIOS_DSKCHG2: POP DI ; Recover DI MOV AH,BIOS_DSKCHV ; Get change flag POP DS ; Recover DS RET ; and return BIOS_DSKCHGA DB ? ; Save for DSK_FLAG BIOS_DSKCHV DB ? ; Disk change value BIOS_DSKCHG ENDP ; ; BIOS_MAPDEV - Map disk I/O drivers ; ; Call with: ; AL = I/O driver used to read FAT ; AH = First byte of FAT (range F8 to FF) ; ; Returns: ; AL = I/O driver for this diskette and drive ; ; No other registers are changed. ; BIOS_MAPDEV PROC FAR PUSH DS ; Save DS and set up new DS PUSH CS POP DS ; Determine drive type CMP AL,MAXDSK5 ; Is drive an 8 incher or winchester ? JNL BIOS_MAPDEV2 ; Yes, nothing to do ; Drive is a 5 incher PUSH SI ; Save regs PUSH BX MOV SI,AX ; Get drive index AND SI,0FFH ; Issolate index SHL SI,1 ; Convert to word index MOV SI,DSK_TPTR[SI] ; Get addr of DSK entry MOV BL,BYTE PTR DSK_FLAG[SI] ; Get current flags AND BL,NOT (DSK_FDS OR DSK_FDP) ; Clear setable flags ; Set up disk table to assume double sided 80 track MOV BH,DSK_FDS ; Show as double sided MOV BYTE PTR DSK_MAXT[SI],80 ; Set max track number ; Now see if actually is single sided 40 track CMP AH,0FDH ; Was assumption correct ? JE BIOS_MAPDEV1 ; Yes, skip to end ; Was a small disk, patch tables MOV BH,DSK_FDP ; Show as double step MOV BYTE PTR DSK_MAXT[SI],40 ; Set number of tracks ADD AL,OFFSET DSK_BMPVAL ; Map to next set of slots ; Now see if we really must double step PUSH AX ; Save AL value PUSH DX ; Save DX CALL DSK_IAS ; Read auxiliary status TEST AL,AS96T ; See if drives are 96tpi POP DX ; Restore regs POP AX JNZ BIOS_MAPDEV0 ; Yes, leave at double step ; Drives are really 48tpi MOV BH,0 ; Clear double step ; Now see if single or double sided BIOS_MAPDEV0: CMP AH,0FEH ; Single sided? JZ BIOS_MAPDEV1 ; Yes, skip ; Disk is double sided, patch flag byte OR BH,DSK_FDS ; Add in double sided ADD AL,OFFSET (DSK_BMPVAL1-DSK_BMPVAL) ; Map drive number again BIOS_MAPDEV1: OR BH,BL ; Put together flag bits MOV BYTE PTR DSK_FLAG[SI],BH ; Store new flag bits POP BX ; Recover regs POP SI BIOS_MAPDEV2: POP DS RET BIOS_MAPDEV ENDP 0000100B ;POLL COMMAND OCW3RIR EQU 00000010B ;READ IR REG OCW3RIS EQU 00000011B ;READ IS REG DATE TIME  or $F; ; BIOS_SETDATE - Set the date ; ; Call with: ; AX = the number of days since Jan 1, 1980. ; ; Uses: No registers are used. ; BIOS_SETDATE PROC FAR PUSHF ; Save status CLI ; Turn off interrupts MOV CS: BIOS_DATE,AX ; Save it POPF ; Restore status RET BIOS_SETDATE ENDP ; ; BIOS_SETTIME - Set the time ; ; CALL with: ; CH = hours (0-23) ; CL = minutes (0-59) ; DH = seconds (0-59) ; DL = hundredths of seconds (0-99) ; ; Uses: No registers are used ; BIOS_SETTIME PROC FAR PUSHF ; Save current status CLI ; Turn off interrupts MOV CS: BIOS_HRS,CH ; Save hours MOV CS: BIOS_MIN,CL ; Save minutes MOV CS: BIOS_SEC,DH ; Save seconds MOV CS: BYTE PTR BIOS_HSEC,DL ; Save hundredths of seconds POPF ; Restore status RET BIOS_SETTIME ENDP ; ; BIOS_GETDATE - Get time and date ; ; Returns: ; AX = count of days since Jan 1, 1980. ; CH = hours ; CL = minutes ; DH = seconds ; DL = hunderdths of seconds ; ; Uses: No registers are used ; BIOS_GETDATE PROC FAR PUSHF ; Save current status CLI ; Turn off interrupts MOV AX,CS: BIOS_DATE ; Get date MOV CH,CS: BIOS_HRS ; Get hours MOV CL,CS: BIOS_MIN ; Get minutes MOV DH,CS: BIOS_SEC ; Get seconds MOV DL,CS: BYTE PTR BIOS_HSEC ; Get hundredths of seconds POPF ; Restore status RET BIOS_GETDATE ENDP ; ; Date and time fields ; BIOS_DATE_TIME LABEL BYTE ; These fields must be together(see DEFMS) BIOS_DATE DW BIOS_RELDATE ; Days since 1980 BIOS_HRS DB 08 ; Hours since midnight BIOS_MIN DB 00 ; Minutes BIOS_SEC DB 0 ; Seconds BIOS_HSEC DW 0 ; Hundredths of seconds (needs to be a word) ALARM_FLAG DB 0 ; Alarm clock timer flag TICCNT DW 0 ; Tic counter PTICCNT DW 0 ; Previous tic counter value CW100 DW 100 ; Word constant 100 CB60 DB 60 ; Byte constant 60 PAGE ; ; ALARM_ST - Start alarm clock ; ; Call with: ; CX = tics before alarm goes off(a tic = 4 msec) ; ; Returns: ; Timer 2 starts running and ALARM_FLAG = FALSE ; ALARM_ST PROC NEAR CLI ; Disable interrupts MOV BYTE PTR CS:ALARM_FLAG,FALSE ; Show alarm hasn't gone off yet PUSH AX ; Save AX MOV AL,PITSC2+PITRLW+PITMITC ; Clear timer OUT ZTIMER+PITCW,AL MOV AL,NOT ZTIMERS2 ; Clear interrupt flag OUT ZTIMERS,AL MOV AL,CL ; Set clock period OUT ZTIMER+PITC2,AL MOV AL,CH OUT ZTIMER+PITC2,AL POP AX STI ; Restore interrupts RET ; and return ALARM_ST ENDP ; ; ALARM_CK - Check alarm and stop timer if alarm has gone off ; ; Returns: ; "CY" clear - alarm hasn't gone off yet ; "CY" set - alarm has gone off(and timer cleared) ; ALARM_CK PROC NEAR CLI ; Disable interrupts TEST BYTE PTR CS:ALARM_FLAG,TRUE ; Has alarm gone off ? JZ ALARM_CKR ; No, skip to end(CY is clear) STC ; Set CY to show alarm has gone off ALARM_CKST: PUSH AX ; Save AX MOV AL,PITSC2+PITRLW+PITMITC ; Get command to stop timmer 2 OUT ZTIMER+PITCW,AL ; Stop timmer POP AX ; Recover AX ALARM_CKR: STI ; Turn interrupts on RET ; and return ALARM_CK ENDP PAGE ; ; ALARM_SP - Stop Alarm clock ; ALARM_SP PROC NEAR CLI ; Disable interrupts JMP ALARM_CKST ; Join common code ALARM_SP ENDP ; ; ALARM_WAIT - Start alarm clock and wait for it to go off ; ; Call with: ; CX = tics before alarm goes off(a tic = 4 msec) ; ; Returns: ; Routine delays until the specified time has elapsed ; ALARM_WAIT PROC NEAR CALL ALARM_ST ; Start clock ALARM_WL: CALL ALARM_CK ; Has time elasped ? JNC ALARM_WL ; No, look again RET ; Yes, return ALARM_WAIT ENDP PAGE ; ; ISR_TIM - Interrupt service routine for timer ; ; Invoked when a timer interrupt occurs ; ; Updates time and date variables ; BIOS_DATE - days since Jan 1, 1980 ; BIOS_HR - hours since midnight ; BIOS_MN - minutes ; BIOS_SEC - seconds ; BIOS_HSEC - hundredths of seconds ; ; Updates disk drive variables(an deselect a drive) ; DSKT_FG - flag that drive is selected ; DSKT_DNCTR - down counter on select time ; DSKT_PORT - port to use to deselect drive ; DSKT_DSEL - command to deselect drive ; ISR_TIM: PUSH AX ; Save regs and set up DS PUSH DX PUSH DS MOV AX,CS MOV DS,AX ; Check cause of interrupt TIMINT1: IN AL,ZTIMERS ; Get cause of timer interrupt TEST AL,ZTIMERS0 ; Is it timer 0 ? JNZ TIM0INT ; Yes, go to it TEST AL,ZTIMERS2 ; Is it timer 2 ? JZ TIMINTX ; No, go handle it ; Handle timer 2 interrupts TIM2INT: OR BYTE PTR ALARM_FLAG,TRUE ; Set flag MOV AL,NOT ZTIMERS2 ; Clear intr OUT ZTIMERS,AL JMP SHORT TIMINT1 ; Go check for other interrupts ; Timer interrupt exit TIMINTX: MOV AL,OCW2OP+OCW2EOI OUT ZM8259A+OCW2,AL ; Tell 8259A that interrupt serviced POP DS ; Restore regs POP DX POP AX IRET ; and return ; Handle ti mer 0 interrupts TIM0INT: MOV AL,PITSC1+PITRLCL OUT ZTIMER+PITCW,AL ; Latch counter 1 value IN AL,ZTIMER+PITC1 ; Get counter 1's LSB MOV AH,AL ; Save it IN AL,ZTIMER+PITC1 ; Get counter 1's MSB XCHG AH,AL ; Swap bytes into proper regs NEG AX ; Take 2's complement MOV TICCNT,AX ; Save it as tic count ; (each tic is one hundredth of a sec) SUB AX,PTICCNT ; Compute elapsed tics TEST BYTE PTR DSKT_FG,0FFH ; Should disk deselect be looked at ? JZ TOD0 ; No, skip over SUB WORD PTR DSKT_DNCTR,AX ; Decr down counter, time out ? JG TOD0 ; No, skip MOV DX,DSKT_PORT ; Yes, get port number PUSH AX ; Save AX MOV AL,BYTE PTR DSKT_DSEL ; Get deselect command OUT DX,AL ; Deselect the drive MOV BYTE PTR DSKT_FG,00H ; Show disk deselected POP AX ; Recover AX TOD0: ; Execute user routine with tic in AX PUSH AX INT INT_UTMA ; Execute the interrupt routine CLI ; Insure that interrupts remain off POP AX ADD AX,BIOS_HSEC ; Compute new hundredths CMP AX,200 ; Did a lot of time go by(more than 2 sec)? JB TOD1 ; No, go handle the easy case XOR DX,DX ; Clear for divide DIV CW100 ; Word divide by 100 MOV BIOS_HSEC,DX ; Store remainder, which is hundredths of sec XOR DH,DH ; Clear high part MOV DL,BIOS_SEC ; Get seconds in DX ADD AX,DX ; Compute new seconds DIV CB60 ; Byte divide by 60 MOV BIOS_SEC,AH ; Store remainder, which is seconds ADD BIOS_MIN,AL ; Compute new minutes JMP SHORT TOD2 ; join back with other code TOD1: MOV BIOS_HSEC,AX ; Assume LT 100, Store hundredths SUB AX,100 ; Was assumption correct ? JB TOD3 ; Yes, value was ok - so not much to do MOV BIOS_HSEC,AX ; No, store correct value INC BIOS_SEC ; Bump seconds up MOV AL,BIOS_SEC ; Get seconds SUB AL,60 ; Did seconds go up to 60 JB TOD3 ; No, not much to do now MOV BIOS_SEC,AL ; Yes, store new value INC BIOS_MIN ; Bump minutes up TOD2: MOV AL,BIOS_MIN ; Get minutes SUB AL,60 ; Did minutes go up to or over 60 JB TOD3 ; No, not much to do MOV BIOS_MIN,AL ; Yes, store correct value INC BIOS_HRS ; Bump hours up CMP BIOS_HRS,24 ; Did hours go up to 24 JB TOD3 ; No, don't need to do any more MOV BIOS_HRS,0 ; Yes, fix it INC BIOS_DATE ; Bump days up TOD3: MOV AX,TICCNT ; Get tic counter MOV PTICCNT,AX ; Save it MOV AL,0FFH-ZTIMERS0 ; Clear intr OUT ZTIMERS,AL JMP TIMINT1 ; Check for more intrs ; ; Interrupt service routine for TIC timer ; ; Entry: AX = Number of 100th seconds since last call ; ; Exit: NONE ; ; Uses: NONE ; ; NOTE: Users trapping this interrupt should be sure that ; AX remains unchanged and that interrupts are left as is. ; The user routine should exit using a JMPF to the next routine ; in the interrupt list (found at 0:INT_UT) ; ISR_UTM: IRET 0000100B ;POLL COMMAND OCW3RIR EQU 00000010B ;READ IR REG OCW3RIS EQU 00000011B ;READ IS REG DATE TIME  or $Fet segment POP ES MOV BX,OFFSET DSKMAP ; Get offset RET ; and return ; Map drive in AH to one in AL DSKFMAP1: MOV AL,AH ; Make index into table XOR AH,AH MOV SI,AX ; Make index available MOV AL,BYTE PTR DSKMAP[SI+1] ; Map disk RET ; and return ; Disk map table ; ; First entry is count of entries that follow ; each following entry contains the physical ; drive to access when referencing that logical ; number. ; IF WINCH DSKMAP DB 6,0,1,2,3,4,5 ELSE DSKMAP DB 4,0,1,2,3 ENDIF ; ; Get BIOS disk vector function ; D0A1: MOV BX,OFFSET DSK_TPTR ; Get offset of vector PUSH CS ; Get segment of vector POP ES XOR AX,AX ; Show success(clear CY) RET ; and return ; ; SETFDC - Set the FDC bit in the (AH) drive table ; AH = Drive name (0=a, 1=b) NOT already mapped ; D0A2: PUSH SI CALL NEAR PTR DSKFMAP1 ;Map to real drive ; AL = real mapped drive name CBW SHL AX,1 MOV SI,AX MOV SI,WORD PTR DSK_TPTR[SI] ;SI = p ointer to table OR BYTE PTR DSK_FLAG[SI],DSK_FDC ;Set the FDC bit POP SI XOR AX,AX RET ;Return with no error PAGE ; ; Regular disk function ; D0B: MOV DSK_FUN,AL ; Save function CBW ; Extend AL to AX SHL AX,1 ; Compute word offset MOV DI,AX ; Make avail as index ; Check if drive number is legal ; (DI has function) MOV AL,ES:DSKPR_DRIVE[BX] ; Get logical drive number CMP AL,0FFH ; Is drive special one ? JE D0D ; Yes, then Ok CMP AL,MAXDSK ; Is drive number within range ? JB D0D ; Yes, skip D0C: STC ; No, illegal drive number MOV AX,DSKST_DNERR ; Get error code RET ; and return D0D: CBW ; Extend AL to AX SHL AX,1 ; Compute word offset MOV SI,AX ; Make avail as index MOV SI,DSK_TPTR[SI] ; Get addr of disk parameter table CMP SI,-1 ; Does table exist ? JE D0C ; No, show error and return ; Check if drive type valid CMP BYTE PTR DSK_TYPE[SI],DSK_TZ207 ; Is it disk type valid ? JE D0E ; Yes, skip IF WINCH CMP BYTE PTR DSK_TYPE[SI],DSK_TZ217 ; Winchester? JNZ D0D1 ; Nope JMP NEAR PTR DSKW ; Yes, dispatch it D0D1: ENDIF STC ; Show error MOV AX,DSKST_DTERR ; Get error code RET ; and return D0E: CMP BYTE PTR DSK_FUN,DSK_SETFDC ; Is function Set Force Disk change ? JNE D0E1 ; No, skip OR BYTE PTR DSK_FLAG[SI],DSK_FDC ; Set flag XOR AX,AX ; Clear CY to show success RET ; and return ; Check if proper disk is in drive D0E1: TEST BYTE PTR DSK_IMGFLG[SI],DSKIF_DV ; Is correct disk in drive ? JNZ D0E2 ; Yes, skip CLI ; No, disable interrupts XOR AL,AL ; Get deselect command CALL DSK_OCON ; Deselect all drives MOV BYTE PTR DSK_DBIT,FDFDLF ; Force delay MOV BYTE PTR DSKT_FG,00H ; Disable timer from deselecting drive STI ; Turn interrupts back on CALL GRD ; Prompt user to switch diskettes JMP DSKSL ; Join common code ; Check if current and previous disks are the same and timer hasn't run out D0E2: CMP SI,DSK_LDRIVE ; Is current disk same as last disk ? JNE DSKSL ; No, join select code CLI ; Disable interrupts TEST BYTE PTR DSKT_FG,0FFH ; Has timeout occured ? JNZ D0E4 ; No, skip STI ; Turn interrupts back on ; Wait for head to unload MOV CX,FDHULDM ; Get head unload multiplier D0E3: CALL DSK_LWAIT ; Wait for head to completely unload LOOP D0E3 JMP DSKSL ; Join common select code D0E4: MOV BYTE PTR DSKT_FG,00H ; Disable timer from deselecting drive MOV BYTE PTR DSK_DBIT,00H ; Set no delay needed STI ; Enable interrupts JMP D1C ; Join common code to start operation ; Select drive and load head DSKSL: CLI ; Disable interrupts MOV BYTE PTR DSK_DBIT,FDFDLF ; Set delay bit XOR AH,AH ; Get a zero XCHG AH,BYTE PTR DSKT_FG ; Disable timer from deselecting drive MOV DSK_LDRIVE,SI ; Save drive number STI ; Turn interrupts back on XOR AL,AL ; Get deselect command CALL DSK_OCON ; Deselect previous drive MOV AL,BYTE PTR DSK_SEL[SI] ; Get select command TEST AL,CONDS8 ; Is drive an 8 incher ? JNZ DSKSL2 ; Yes, go to it ; 5.25 inch Startup CALL DSK_OCON ; Select current drive OR AH,AH ; Has disk timed out ? JNZ DSKSL5 ; No, skip motor start up CALL DSK_IAS ; Get Aux status TEST AL,ASMO ; Is motor running ? JNZ DSKSL5 ; Yes, skip motor start up ; Wait for motor to come up to speed MOV CX,FD5MOM ; Get 5.25 motor multiplier DSKSL1: CALL DSK_LWAIT ; Wait for motor to come up to speed LOOP DSKSL1 JMP DSKSL5 ; Join common code DSKSL2: ; 8 inch Startup ; Ensure side zero is selected if single sided disk and ; previous operation was on side one CMP BYTE PTR SIDFLG,0 ; Was side zero used last ? JE DSKSL3 ; Yes, nothing to do TEST BYTE PTR DSK_FLAG[SI],DSK_FDS ; Is disk double sided ? JNZ DSKSL3 ; Yes, nothing to do ; Disk is single sided and side one was used last. ; Force select of side 0. MOV AL,FDCRDA ; Get read address command CALL DSK_OCMD ; Issue command CALL DSK_WAIT ; Wait a little !bit for command to start MOV AL,FDCFI+FDFINI ; Get force interrupt command CALL DSK_OCMD ; Force interrupt to stop command CALL DSK_WAIT ; Wait for things to settle ; Clear DRQ bit(if present) CALL DSK_IDAT ; Read data returned to clear CALL DSK_ISTA ; Read status DSKSL3: MOV AL,BYTE PTR DSK_SEL[SI] ; Get select command CALL DSK_OCON ; Select current drive ; Wait for motor to come up to speed MOV CX,FD8NRD ; Get 8 inch counter DSKSL4: CALL DSK_ISTA ; Get status TEST AL,FDSNRD ; Is disk not ready LOOPNZ DSKSL4 ; Keep looping if not ready and counter not 0 DSKSL5: ; Load head TEST BYTE PTR DSK_FLAG[SI],DSK_FSL ; Should we skip head load ? JNZ D1C ; Yes, skip CALL DSK_ITRK ; Get current track CALL DSK_ODAT ; Set desired track MOV AL,FDCSEK+FDFHLB ; Get seek command to load head CALL DSK_EXCMD ; Load head ; Wait for head to load MOV CX,FDHLDM ; Get head load multiplier DSKSL6: CALL DSK_LWAIT ; Wait for head to load LOOP DSKSL6 ; Go to function ; (DI has function index) D1C: JMP WORD PTR D3[DI] ; Case to function D3 DW OFFSET DSKFRS ; Restore function DW OFFSET DSKFST ; Status function DW OFFSET DSKFRD ; Read function DW OFFSET DSKFWR ; Write function DW OFFSET DSKFVF ; Verify function DW OFFSET DSKFFT ; Format function DW OFFSET DSKFSI ; Step in function DW OFFSET DSKFRT ; Read track function DW OFFSET DSKBDO ; GBIOSVEC DW OFFSET DSKBDO ; MAPDSK DW OFFSET DSKBDO ; SETFDC DW OFFSET DSKFRD ; PREAD PAGE ; ; GRD - Get required disk ; ; GRD insures that the disk being accessed is in ; the needed drive. If not, it will prompt the ; user for the disk. ; ; Call with: ; SI -> to disk table ; ES:BX -> disk packet ; ; USES: AX, CX ; GRD PROC NEAR PUSH SI ; Save Regs PUSH DI PUSH BX MOV BYTE PTR DSK_DBIT,FDFDLF ; Turn on delay flag PUSH SI ; Save drive pointer TEST BYTE PTR DSK_IMGFLG[SI],DSKIF_ID ; Is drive imaginary ? JZ GRD2 ; No,a real drive ; User accessing a phantom drive, link to real drive MOV AL,BYTE PTR DSK_IMGFLG[SI] ; Get real drive number AND AL,DSKIF_DN ; Isolate drive bits XOR AH,AH ; Clear upper part SHL AX,1 ; Make into word index MOV SI,AX ; Make avail MOV SI,DSK_TPTR[SI] ; Get pointer to real drive ; See if real drive already in use by other phantom diskette TEST BYTE PTR DSK_IMGFLG[SI],DSKIF_DV ; Is real drive valid ? JNZ GRD3 ; Yes, Not in use by others ; Drive is in use by other phantom disk, update values GRD2: MOV AL,BYTE PTR DSK_IMGFLG[SI] ; Get real drive number AND AL,DSKIF_DN ; Issolate those bits XOR AH,AH ; Clear high part SHL AX,1 ; Make into word index MOV DI,AX ; Make avail MOV DI,DSK_TPTR[DI] ; ptr to destination pointer ; Back data from DI to SI tables AND BYTE PTR DSK_IMGFLG[DI],0FFH-DSKIF_DV AND BYTE PTR DSK_IMGFLG[SI],0FFH-DSKIF_DN MOV AL,BYTE PTR DSK_LTRK[DI] MOV BYTE PTR DSK_LTRK[SI],AL ; Real drive now all set GRD3: POP DI ; DI desired drive TEST BYTE PTR DSK_IMGFLG[DI],DSKIF_ID ; Was it a real drive ? JZ GRD4 ; Yes, skip ; Update logical drives tables MOV AL,BYTE PTR DSK_LTRK[SI] MOV BYTE PTR DSK_LTRK[DI],AL MOV AL,BYTE PTR DSK_SEL[SI] AND AL,CONDS ; Isolate unit number MOV AH,AL ; Save it MOV AL,BYTE PTR DSK_SEL[DI] AND AL,NOT CONDS OR AL,AH ; AL = new drive select MOV BYTE PTR DSK_SEL[DI],AL AND BYTE PTR DSK_IMGFLG[SI],NOT DSKIF_DV OR BYTE PTR DSK_IMGFLG[DI],DSKIF_DV MOV AL,BYTE PTR DSK_NAME[DI] SUB AL,'A' ; Make binary AND AL,DSKIF_DN MOV AH,BYTE PTR DSK_IMGFLG[SI] AND AH,NOT DSKIF_DN OR AL,AH MOV BYTE PTR DSK_IMGFLG[SI],AL ; Show where it is at ; Get disk from user GRD4: MOV AL,BYTE PTR DSK_NAME[DI] MOV BYTE PTR GRDA,AL TEST BYTE PTR DSK_IMGFLG[DI],DSKIF_ID JNZ GRD5 OR BYTE PTR DSK_IMGFLG[DI],DSKIF_DV JMP SHORT GRD6 GRD5: MOV AL,BYTE PTR DSK_IMGFLG[DI] AND AL,DSKIF_DN ; Get his real drive ADD AL,'A' ! GRD6: MOV BYTE PTR GRDB,AL MOV BX,OFFSET GRDMSG MOV CH,GRDMSGL CALL PMESG ; Request disk from user ; Flush keyboard buffer PUSH CS CALL NEAR PTR BIOS_FLUSH ; Flush type-ahead ; Get a key from user GRD7: PUSH CS CALL NEAR PTR BIOS_CONIN ; Get a character CMP AL,0DH ; RETURN? JNZ GRD7 POP BX POP DI POP SI RET ; Message for user prompt GRDMSG DB CC_BEL,'Place disk ' GRDA DB 'x in drive ' GRDB DB 'x:.',0AH,0DH,'Hit RETURN when ready.',CC_LF,CC_CR GRDMSGL EQU (OFFSET $)-(OFFSET GRDMSG) GRD ENDP PAGE ; ; Restore(home) disk function ; ; Clear errors and move head to track zero. ; (ES:BX has parameter block addr,SI has offset of disk parameter table) ; DSKFRS: CALL DSK_RST ; Restore the disk JC D5 XOR AH,AH ; Clear AH TEST AL,FDSTK0 ; Did we find track 0 ? JNZ D5 ; Yes, all is well STC ; No, set CY to show error D5: JMP DSK_DSEL ; Deselect drive and return ; ; Status function ; ; Clear errors and get current status ; (ES:BX has parameter block addr,SI has offset of disk parameter table) ; ; 4/23/82 - Returns AUXSTAT in AH if no errors ; DSKFST: MOV AL,FDCFI+FDFINI ; Get command to force Type I Status CALL DSK_OCMD ; Force Type I status CALL DSK_WAIT ; Wait around for things to settle CALL DSK_ISTA ; Get status MOV CL,AL ; Save status CALL DSK_IAS ; Read aux status MOV AH,AL ; AH gets AUXSTAT MOV AL,CL ; AL get Status ; See if there is a disk in the drive (it's already running) TEST AL,FDSIND ; Do we see an index hole? JZ DSKFST3 ; No, Must be a disk in the drive ; We see a hole, wait for it to leave, but time wait PUSH AX ; Save status MOV CX,DSK_LDELAY[SI]; Get long delay tic count CALL ALARM_ST ; Start alarm clock DSKFST0: CALL DSK_ISTA ; Get status in AL TEST AL,FDSIND ; Still at hole ? JZ DSKFST1 ; No, all done CALL ALARM_CK ; Was alarm gone off ? JNC DSKFST0 ; No, keep looking ; Timed out, Must not be a disk in the drive  POP AX ; Get status OR AL,FDSNRD ; Show disk not ready JMP SHORT DSKFST3 ; Skip to common exit ; No index hole, disk must be there DSKFST1: CALL ALARM_SP ; Stop clock POP AX ; Restore status ; Common exit DSKFST3: TEST AL,FDSNRD ; Was drive ready ? JZ DSKFST4 ; Yes, skip XOR AH,AH ; No, set error OR AX,DSKST_NDERR STC DSKFST4: JMP DSK_DSEL PAGE ; ; Verify disk function ; ; (We really haven't decided what this does yet or if we need it at all.) ; DSKFVF: MOV AX,DSKST_NIERR ; Get error code (not implemented) STC ; Show error with CY JMP DSK_DSEL ; Deselect the drive and return ; ; Read track function ; (ES:BX has parameter block addr, SI has offset of disk parameter table) DSKFRT: XOR DL,DL ; Assume side 0 TEST ES: WORD PTR DSKPR_SECTOR[BX],0FFFFH ; Was assumption correct ? JZ DSKFRT1 ; Yes, skip MOV DL,FDFSS1 ; No, get side one flag DSKFRT1: MOV BYTE PTR SIDFLG,DL ; Set side flag MOV AL,DSK_SEL[SI] ; Get disk select command OR AL,CONWE ; Add in wait states CALL DSK_OCON MOV CX,DSK_BPRT[SI] ; Get bytes per track(when reading) PUSH ES ; Save ES LES DI,ES:DWORD PTR DSKPR_BUFF[BX] ; Get buffer addr in ES:DI CLD ; Set direction PUSHF ; Save interrupt status CLI ; Disable interrupts MOV AL,DSK_RDT[SI] ; Get read track command OR AL,BYTE PTR SIDFLG ; Or in side MOV DX,DSK_PORT[SI] ; Get base port ADD DX,FDDAT ; Compute data port PUSH DX ; Save it MOV DX,DSK_PORT[SI] ; Get base port ADD DX,FDCMD ; Compute command port OUT DX,AL ; Start read POP DX ; Get data port DSKFRT2: IN AL,DX ; Get next data byte STOS BYTE PTR ES:[DI] ; Save the byte LOOP DSKFRT2 ; Get more MOV AL,DSK_SEL[SI] ; Get select command CALL DSK_OCON ; Turn offf wait state I/O CALL DSK_WCMPLT ; Wait for read to complete POPF ; Recover interrupt status POP ES ; Restore ES CALL DSK_WAIT ; Wait some more MOV BYTE PTR DSK_LOPT[SI],DSK_ORT ; Show last operation TEST AL,FDSNRD ; Was "not ready seen ? JZ DSKFRT3 ; No, skip MOV BYTE PTR DSK_LOPT[SI],DSK_OUK ; Show error STC DSKFRT3: MOV AH,0 JMP DSK_DSEL PAGE ; ; Read disk and Write disk functions ; ; (ES:BX has parameter block addr, SI has offset of disk parameter table) ; DSKFWR: ; Write function entry point TEST BYTE PTR DSK_FLAG[SI],DSK_FWP+DSK_FDP ; Is file protected ? JZ DSKFRD ; No, skip MOV AX,FDSWPV ; Yes, make it look like hardware protect STC ; Turn on CY to show error JMP DSK_DSEL ; Deselect the drive and return DSKFRD: ; Read function entry point MOV AX,ES:DSKPR_SECTOR[BX] ; Get logical sector to read MOV CUR_SECTOR,AX ; Save locally MOV BYTE PTR DSK_WRIC,0 ; Show write has not occured ; ; Convert the logical sector in CUR_SECTOR to track, sector, and side ; (SI -> Disk parm table; ES:BX has parameter block addr) ; DSKFSUL: IF DSK_RTY MOV BYTE PTR RETRY_FLAG,0 ; Set retry type flag MOV BYTE PTR RETRY_INDX,0 ; Set retry index in cycle MOV AL,BYTE PTR DSK_NRETRY[SI] ; Get max number of retry cycles INC AL ; Make one-based from zero-based MOV BYTE PTR RETRY_CREM,AL ; Store as down counter ENDIF DSKCRTY: TEST BYTE PTR DSK_LOPT[SI],DSK_OUK ; Is disk at an unknown track ? JNZ D6 ; Yes, home it MOV AL,DSK_LTRK[SI] ; Disk at known track, get track CALL DSK_OTRK ; Tell controller current track number JMP SHORT D7 ; Skip ; Here if track number too large or too small SEEKERR: MOV AX,FDSSEK ; Show seek errors STC JMP DSK_DSEL ; and bail out D6: CALL DSK_RST ; Home disk D7: MOV AX,CUR_SECTOR ; Get logical sector MOV CL,BYTE PTR DSK_SPT[SI] ; CX = sectors/track XOR CH,CH JCXZ SEEKERR ; If CX = 0, bail out XOR DX,DX ; CX = spt, DX:AX = cur sector DIV CX ; DX = sector, AX = track ; Insure that it really fit OR AH,AH JNZ SEEKERR ; If bad track number MOV AH,DL ; AH = sector number INC AH ; Convert sector from zero- to one- based XOR DL,DL ; Assume side zero TEST BYTE PTR DSK_FLAG[SI],DSK_FDS ; Is disk two sided ? JZ D8 ; No, skip over two sided code SHR AL,1 ; Even tracks on side zero, odd on other side JNC D8 ; Skip if even track number MOV DL,FDFSS1 ; Load up side one command/flag ; Test if we need to seek D8: CMP AL,BYTE PTR DSK_MAXT[SI] JA SEEKERR ; If track number too large or small MOV BYTE PTR SIDFLG,DL ; Save side flag MOV CH,DSK_LTRK[SI] ; Get last track CMP CH,AL ; Is last track = new track ? JZ D10 ; Yes, then don't need to seek to it ; Seek to proper sector ; (CH = last track, AL = new track) MOV BYTE PTR DSK_DBIT,FDFDLF ; Turn delay on CMP BYTE PTR DSK_WRIC,0 ; Has a write occured ? JE D8A ; No, skip CALL DSK_WAIT ; Yes, wait for it to complete D8A: MOV DSK_LTRK[SI],AL ; Set last track to new track CALL DSK_ODAT ; Tell controller desired track TEST BYTE PTR DSK_FLAG[SI],DSK_FFS ; Can drive fast step ? JZ D9A ; No, skip over fast step MOV AL,DSK_SEL[SI] ; Get select command OR AL,CON5FS ; Or in fast step CALL DSK_OCON ; Make drive fast step D9A: MOV AL,DSK_SK[SI] ; Get seek command CALL DSK_EXCMD ; Execute the command TEST BYTE PTR DSK_FLAG[SI],DSK_FDP ; Should drive double step ? JZ D9B ; No, skip over double step MOV AL,DSK_LTRK[SI] ; Yes, get track number CALL DSK_ODAT ; Tell controller desired track number MOV AL,CH ; Get original track number CALL DSK_OTRK ; Tell controller current(sic) track MOV AL,DSK_SK[SI] ; Get seek command CALL DSK_EXCMD ; Execute the command(ie double step) D9B: CALL DSK_LWAIT ; Wait a long time for head to settle TEST BYTE PTR DSK_FLAG[SI],DSK_FFS ; Can drive fast step ? JZ D9C ; No, skip over fast step MOV AL,DSK_SEL[SI] ; Get select command CALL DSK_OCON ; Turn off fast step D9C: MOV AL,DSK_LTRK[SI] ; Get track back CALL DSK_OTRK ; Tell controller where head is again ; We have positioned to the desired track D10: MOV AL,AH ; Sector to proper reg CALL DSK_OSEC ; Tell controller desired sector CMP BYTE PTR DSK_"FUN,DSK_READ ; Was function Disk read ? JNE DSKFWR1 ; No, is a write JMP DSKFRD1 ; Yes, is read PAGE ; ; Now we are ready for actual write ; (SI -> Disk parameter table; ES:BX -> parameter block) ; DSKFWR1: MOV AH,DSK_SEL[SI] ; Get disk select command OR AH,CONWE ; Add enable wait state I/O TEST AH,CONDS8 ; Is drive an eight incher ? JNZ DSKFWR2 ; Yes, skip CALL DSK_IAS ; Get AUX status TEST AL,AS96T ; Are drives 96 tpi ? JNZ DSKFWR2 ; Yes, skip CMP BYTE PTR DSK_LTRK[SI],FD5IT ; Are we on the inside tracks ? JB DSKFWR2 ; No, skip AND AH,NOT CONPC ; Yes, turn on pre-comp DSKFWR2: MOV AL,AH ; Get select command CALL DSK_OCON ; Make disk do wait state I/O MOV CX,DSK_BPS[SI] ; Get bytes per sector PUSH ES ; Save ES LES DI,ES:DWORD PTR DSKPR_BUFF[BX] ; Load ES:DI with buffer addr CLD ; Set direction flag for LODS instr MOV AL,DSK_WR[SI] ; Get write command OR AL,DSK_DBIT ; Add in delay information MOV BYTE PTR DSK_DBIT,0 ; Clear delay OR AL,SIDFLG ; Add in side information PUSHF ; Save current interrupt status CLI ; Turn off interrupts ; Set up DX for port i/o MOV DX,DSK_PORT[SI] ; Get base port number of controller ADD DX,FDDAT ; Compute data port number PUSH DX ; Save data port number MOV DX,DSK_PORT[SI] ; Get base port number ADD DX,FDCMD ; Compute command port number XCHG SI,DI ; LODS uses SI OUT DX,AL ; Start write POP DX ; Recover data port number ; Write a sector ; (DX = data port number; ES:SI -> data to write; CX = count to write) W10A: LODS BYTE PTR ES:[SI] ; Get byte to write OUT DX,AL ; Write byte LOOP W10A ; Decr count, branch if not finished XCHG SI,DI ; Recover SI (and don't lose DI) MOV AL,DSK_SEL[SI] ; Get disk select command CALL DSK_OCON ; Turn off wait state I/O CALL DSK_WCMPLT ; Wait for finish and get final status MOV BYTE PTR DSK_WRIC,0FFH ; Show that a write has occured POPF ; Restore interrupt status POP ES ; Recover ES TEST AL,AL ; Did an error occur ? JZ W12 ; No, onward ; Error on write IF DSK_RTY TEST AL,FDSWPV ; Is disk write protected ? JNZ W10C ; Yes, skip retries XOR BYTE PTR RETRY_FLAG,0FFH ; Should we just try write again ? JZ W10B ; No, skip JMP DSKCRTY ; Yes, try again W10B: CALL DSK_WAIT ; Wait for operation to complete PUSH AX ; Save status CALL DSK_RTRY ; Perform retry operation POP AX ; Recover status JC W13 ; If too many errors JMP DSKCRTY ; Try operation again  ENDIF W10C: STC ; Show error with carry JMP SHORT W13 ; and join common exit ; Success on write W12: INC WORD PTR CUR_SECTOR ; Compute next logical sector MOV ES:DSKPR_BUFF[BX],DI ; Save new buffer offset DEC ES:WORD PTR DSKPR_COUNT[BX] ; decr rem sectors, any left ? JZ W13 ; No, join common code JMP DSKFSUL ; Yes, write another ; Write common exit W13: MOV BYTE PTR DSK_LOPT[SI],DSK_OWR ; Show last op was a write LAHF ; Save CY CALL DSK_WAIT ; Wait for operation to complete SAHF ; Restore CY MOV AH,0 ; Clear hi part (CY is error flag) JMP DSK_DSEL ; Deselect the drive and return PAGE ; ; Now we are ready for actual read ; (SI -> disk parameter table; ES:BX -> parameter block) ; DSKFRD1: MOV AL,DSK_SEL[SI] ; Get disk select command OR AL,CONWE ; Add in wait state I/O CALL DSK_OCON ; Turn on wait state I/O MOV CX,DSK_BPS[SI] ; Get number of bytes per sector PUSH ES ; Save ES LES DI,ES:DWORD PTR DSKPR_BUFF[BX] ; Load ES:DI with buffer addr CLD ; Set direction flag for STOSB instr MOV AL,DSK_RD[SI] ; Get read command OR AL,DSK_DBIT ; Add in delay information MOV BYTE PTR DSK_DBIT,0 ; Clear delay OR AL,SIDFLG ; Add in side information PUSHF ; Save interrupt status CLI ; Turn off interrupts ; Set up DX for port I/O MOV DX,DSK_PORT[SI] ; Get controller base port ADD DX,FDDAT ; Compute data port number PUSH DX ; Save data port number MOV DX,DSK_PORT[SI] ; Get controller base port number ADD DX,#FDCMD ; Compute command port number OUT DX,AL ; Start read POP DX ; Recover data port number ; Read sector ; (DX = data port number; ES:DI -> buffer; CX = number of bytes in sector) D10A: IN AL,DX ; Read a byte STOSB ; Store byte in buffer LOOP D10A ; Decr count, branch if not finished MOV AL,DSK_SEL[SI] ; Get disk select command CALL DSK_OCON ; Turn off wait state I/O CALL DSK_WCMPLT ; Wait for finish and get final status POPF ; Restore interrupt status POP ES ; Recover ES TEST AL,AL ; Did an error occur ? JZ D12 ; No, onward ; Error on read IF DSK_RTY XOR BYTE PTR RETRY_FLAG,0FFH ; Should we just try read again ? JZ D10B ; No, skip JMP DSKCRTY ; Yes, try again D10B: PUSH AX ; Save status CALL DSK_RTRY ; Perform recovery operation POP AX ; Recover status JC D13 ; If too many errors JMP DSKCRTY ; Otherwise, try again ELSE STC ; Show error with cary RET ENDIF ; Success on read D12: INC WORD PTR CUR_SECTOR ; Compute next logical sector MOV ES: DSKPR_BUFF[BX],DI ; Save new buffer offset DEC ES: WORD PTR DSKPR_COUNT[BX] ; decr rem sectors, any left ? JZ D13 ; No, join common code JMP DSKFSUL ; Yes, go read another sector D13: MOV BYTE PTR DSK_LOPT[SI],DSK_ORD ; Show last op was a read MOV AH,0 ; Clear hi part (AL and CY already set) JMP DSK_DSEL ; Deslect the drive and return PAGE ; ; Format disk function ; ; (ES:BX has parmeter block addr; SI has offset of disk parameter table) ; DSKFFT: TEST BYTE PTR DSK_FLAG[SI],DSK_FWP ; Is disk write protected ? JZ D13A ; No, skip onward MOV AX,FDSWPV ; Yes, make it look like hardware protect STC ; Turn on CY to show error JMP DSK_DSEL ; Deselect the drive and return D13A: TEST BYTE PTR DSK_LOPT[SI],DSK_ORS+DSK_OSI+DSK_OFT ; Was last ; operation a Restore, Step, or format ? JNZ D13B ; Yes, skip onward MOV AX,DSKST_ORERR ; No, get error code STC ; Turn on CY to show error JMP DSK_DSEL ; Deselect the drive and return D13B: MOV BYTE PTR SIDFLG,0 ; Assume side 0 TEST ES: WORD PTR DSKPR_SECTOR[BX],0FFFFH ; Was side one JZ D13BA ; No, skip MOV BYTE PTR SIDFLG,FDFSS1 ; Yes, get side one command D13BA: MOV AH,DSK_SEL[SI] ; Get disk select command OR AH,CONWE ; Add enable wait state I/O TEST AH,CONDS8 ; Is drive an eight incher ? JNZ D13BB ; Yes, skip CALL DSK_IAS ; Get AUX status TEST AL,AS96T ; Are drives 96 tpi ? JNZ D13BB ; Yes, skip CMP BYTE PTR DSK_LTRK[SI],FD5IT ; Are we on the inside tracks ? JB D13BB ; No, skip AND AH,NOT CONPC ; Yes, turn on pre-comp D13BB: MOV AL,AH ; Get select command CALL DSK_OCON ; Turn on wait state I/O MOV CX,DSK_BPWT[SI] ; Get number of bytes to write PUSH ES ; Save ES LES DI,ES:DWORD PTR DSKPR_BUFF[BX] ; Load ES:DI with buffer addr CLD ; Set direction flag for LODS instr PUSHF ; Save interrupt status CLI ; Turn off interrupts MOV AL,DSK_FMT[SI] ; Get format(write track) command OR AL,SIDFLG ; Add in side select information MOV DX,DSK_PORT[SI] ; Get controller base port ADD DX,FDDAT ; Compute data port PUSH DX ; Save data port MOV DX,DSK_PORT[SI] ; Get controller base port ADD DX,FDCMD ; Compute command port XCHG SI,DI ; Use SI for LODSB instr OUT DX,AL ; Start write POP DX ; Recover data port ; Write the track ; (DX = data port number; ES:SI -> buffer; CX = number of bytes to write) D13D: LODS BYTE PTR ES:[SI] ; Get byte to write OUT DX,AL ; Write a byte LOOP D13D ; Decr count, branch if not finished XCHG SI,DI ; Recover SI MOV AL,DSK_SEL[SI] ; Get disk select command CALL DSK_OCON ; Turn off wait state I/O CALL DSK_WCMPLT ; Wait for unit not busy and get final status POPF ; Restore interrupt status POP ES ; Recover ES CALL DSK_WAIT ; Wait for operation to complete MOV BYTE PTR DSK_LOPT[SI],DSK_OFT ; Assume operation succeeded TEST AL,AL ; Did an error occur ? JZ D13F ; No, onward MOV BYTE PTR DSK_LOPT[SI],DSK_OUK ; Yes, show #error STC ; Set CY to show error D13F: MOV AH,0 ; Clear upper part of status JMP DSK_DSEL ; Deselect the drive and return PAGE ; ; Step in function ; ; (ES:BX has parameter block addr; SI has offset of disk paramter table) ; DSKFSI: TEST BYTE PTR DSK_LOPT[SI],DSK_OSI+DSK_OFT+DSK_ORS ; Was last ; operation a Step in, Format, or Restore ? JNZ D13G ; Yes, skip onward MOV AX,DSKST_ORERR ; No, get error code STC ; Show error with CY JMP DSK_DSEL ; Deselect the drive and return D13G: INC WORD PTR DSK_LTRK[SI] ; Bump the track count TEST BYTE PTR DSK_FLAG[SI],DSK_FFS ; Can drive fast step JZ D13GB ; No, nothing special to do MOV AL,DSK_SEL[SI] ; Yes, get disk select command OR AL,CON5FS ; Or in fast step CALL DSK_OCON ; Make disk fast step D13GB: MOV AL,DSK_SPHI[SI] ; Get step in command CALL DSK_EXCMD ; Execute the command CALL DSK_LWAIT ; Wait a long time for head to settle PUSH AX ; Save status TEST BYTE PTR DSK_FLAG[SI],DSK_FFS ; Were we fast stepping ? JZ D13GC ; No, skip MOV AL,DSK_SEL[SI] ; Get select command CALL DSK_OCON ; Turn off fast step D13GC: POP AX ; Recover status MOV BYTE PTR DSK_LOPT[SI],DSK_OSI ; Assume no error CLC ; Show no error D13H: MOV AH,0 ; Clear upper part of status JMP DSK_DSEL ; Deselect the drive and return PAGE ; ; DSK_DSEL - Common exit to deselect the disk and return ; ; SI -> disk parameter table ; AX = status to return ; CY = error flag ; DSK_DSEL:  MOV DSK_STA[SI],AX ; Save status PUSH AX ; Save status for a bit LAHF ; Save carry CLI ; Disable interrupts MOV BYTE PTR DSKT_FG,0FFH ; Allow timer to deselect drive MOV DX,DSK_TDSEL[SI] ; Get time before drive is deselected MOV DSKT_DNCTR,DX ; Store as down counter for timer MOV DX,DSK_PORT[SI] ; Get base port ADD DX,FDCON ; Add control port offset MOV DSKT_PORT,DX ; Save port for timer MOV BYTE PTR DSKT_DSEL,0 ; Store deselect command for timer STI ; Turn interrupts back on SAHF ; Restore carry POP AX ; Restore status JNC DSK_DSEL0 ; Skip if no error MOV BYTE PTR SIDFLG,FDFSS1 ; An error occured, set side 1 flag to force side 0 select DSK_DSEL0: RET ; and return PAGE ; ; DSK_RST - Restore the disk ; ; Call with: ; SI -> disk parameter table ; ; Returns: ; AL = status ; DSK_RST: MOV BYTE PTR DSK_LTRK[SI],0 ; Show last track is zero TEST BYTE PTR DSK_FLAG[SI],DSK_FFS ; Can drive fast step ? JZ D14A ; No, skip over MOV AL,DSK_SEL[SI] ; Get disk select command OR AL,CON5FS ; Or in fast step CALL DSK_OCON ; Make disk fast step D14A: MOV AL,DSK_RS[SI] ; Get restore command CALL DSK_EXCMD ; Execute the command JC D14E ; If errors TEST BYTE PTR DSK_FLAG[SI],DSK_FRS ; Should we try again ? JZ D14C ; No, skip PUSH CX ; Save CX MOV CX,FDSTEPS ; Get number of steps D14B: MOV AL,DSK_SPHI[SI] ; Get Step command CALL DSK_EXCMD ; Execute the command LOOP D14B ; Do it until done POP CX ; Restore CX MOV AL,DSK_RS[SI] ; Get restore command OR AL,FDFS30 ; Make step real slow CALL DSK_EXCMD ; Execute the command D14C: CALL DSK_LWAIT ; Wait a long time for the head to settle PUSH AX ; Save status XOR AL,AL ; Set track to zero CALL DSK_OTRK ; Tell controller the track MOV BYTE PTR DSK_LOPT[SI],DSK_ORS ; Show last op was a reset TEST BYTE PTR DSK_FLAG[SI],DSK_FFS ; Can drive fast step ? JZ D14D ; No, skip MOV AL,DSK_SEL[SI] ; Get back disk select command CALL DSK_OCON ; Make disk act regular D14D: POP AX ; Recover status D14E: RET ; and return PAGE ; ; DSK_RTRY - Does retries of a disk operation ; ; Call with: ; AL = Status ; RETRY_INDX = Retry cycle index ; RETRY_CREM = Down counter of retry cycles ; ; Returns: ; CY set - RETRY_CREM went to zero after a cycle completed ; CY clear - RETRY_INDX updated and if cycle completed, ; then RETRY_CREM decremented ; ; Uses: AX,DI,DX$ DSK_RTRY: CMP BYTE PTR RETRY_INDX,0 ; At start of cycle ? JNE DSKRTRY0 ; No, skip DSK_RDECR: DEC BYTE PTR RETRY_CREM ; Decr remaining cycles, any left ? JNZ DSKRTRY0 ; Yes, skip STC ; No, show recoverry procedure failed RET ; and return DSKRTRY0: INC WORD PTR DSK_SERR[SI] ; Count as a soft error TEST AL,FDSNRD+FDSWPV ; Is error Not Ready or Write Protect ? JNZ DSK_RDECR ; Yes, then fail immediately MOV AL,RETRY_INDX ; Get retry cycle index INC BYTE PTR RETRY_INDX ; Increment the index CBW ; Extend in to word SHL AX,1 ; Make into word MOV DI,AX ; Make avail as index JMP WORD PTR DSKRTRY1[DI] ; Case to recovery routine DSKRTRY1: DW DSKRTRYSI ; Step in 1 track DW DSKRTRYSO ; Step out 1 track DW DSKRTRYRS ; Restore head DW DSKRTRYSI ; Step in 1 track DW DSKRTRYSO ; Step out 1 track DW DSKRTRYFL ; End cycle ; ; DSKRTRYFL - End of recovery cycle and when all below procedures fail ; DSKRTRYFL: MOV BYTE PTR RETRY_INDX,0 ; Reset cycle index to zero JMP DSK_RTRY ; Start over again ; ; DSKRTRYSI - Step head in 1 track ; DSKRTRYSI: CALL DSK_ITRK ; Get current track number CMP AL,DSK_MAXT[SI] ; At maximum track yet ? JB DSKRTRYSI1 ; No, continue CLC ; Yes, don't do anything RET ; and return DSKRTRYSI1: INC AL ; Incr track number MOV BYTE PTR DSK_LTRK[SI],AL ; Set new track number MOV AL,DSK_SPHI[SI] ; Get step in command CALL DSK_EXCMD ; Step the head in TEST BYTE PTR DSK_FLAG[SI],DSK_FDP ; Should drive double step ? JZ DSKRSIR ; No, skip MOV AL,DSK_SPHI[SI] ; Get step in command CALL DSK_EXCMD ; Step the head in DSKRSIR: CALL DSK_LWAIT ; Wait for head to settle CLC ; Show not finished with cycle RET ; and return ; ; DSKRTRYSO - Step head out ; DSKRTRYSO: CALL DSK_ITRK ; Get current track TEST AL,AL ; On track zero ? JNZ DSKRTRYSO1 ; No, Continue CLC ; Yes, don't do anything RET ; and return DSKRTRYSO1: DEC AL ; Decr track number MOV BYTE PTR DSK_LTRK[SI],AL ; Save it CALL DSK_ODAT ; Tell controller desired track MOV AL,DSK_SK[SI] ; Get seek command CALL DSK_EXCMD ; Seek to track TEST BYTE PTR DSK_FLAG[SI],DSK_FFS ; Should disk double step ? JZ DSKRSOR ; No, skip MOV AL,BYTE PTR DSK_LTRK[SI] ; Get track number CALL DSK_ODAT ; Tell controller desired track INC AL ; Compute old position CALL DSK_OTRK ; Tell controller where head is MOV AL,DSK_SK[SI] ; Get seek command CALL DSK_EXCMD ; Seek again(ie double step) DSKRSOR:  CALL DSK_LWAIT ; Wait for head to settle CLC ; Show not finished with cycle RET ; and return ; ; DSKRTRYRS - Restore head to track 0 ; DSKRTRYRS: PUSH CX ; Save CX XOR AL,AL ; Deselect drive to lift head CALL DSK_OCON ; Wait for head to unload MOV CX,FDHULDM+1 ; Get head unload multiplier DRS1: CALL DSK_LWAIT ; Wait for head unload LOOP DRS1 MOV AL,DSK_SEL[SI] ; Reselect the disk CALL DSK_OCON ; Wait for head load MOV CX,FDHLDM ; Get head load multiplier DRS2: CALL DSK_LWAIT ; Wait foor head to load LOOP DRS2 CALL DSK_RST ; Restore the head CALL DSK_LWAIT ; Wait for head to settle CLC ; Show not finished with cycle POP CX ; Restore CX RET ; and return PAGE ; ; DSK_WAIT - Wait for operation to complete ; ; Call with: ; SI -> disk parameter table ; DSK_WAIT: PUSH CX MOV CX,WORD PTR DSK_DELAY[SI] ; Get count for short delay JMP SHORT D16 ; ; DSK_LWAIT - Wait a long time for operation to complete ; ; Call with: ; SI -> disk parameter table ; DSK_LWAIT: PUSH CX MOV CX,WORD PTR DSK_LDELAY[SI] ; Get count for long delay D16: CALL ALARM_WAIT ; Wait for time to go by POP CX RET ; ; DSK_EXCM/DSK_WCMPLT - (Execute command) and wait for it to complete ; ; Call with: ; SI -> Disk parameter table ; AL = command to execute ; ; Returns: ; Al = status ; DSK_EXCMD: ; Check to see if controller exists PUSH BX PUSH AX CALL $DSK_ITRK ; Read current track setting MOV BL,AL ; BL gets current track number INC AL CALL DSK_OTRK ; Output modified track CALL DSK_ITRK ; Should have modified track number XCHG AL,BL ; BL = new, should be AL + 1 CALL DSK_OTRK ; Output the original one again INC AL CMP AL,BL ; 'ZR' set if controller exists POP AX POP BX JZ DSK_EXCMD1 ; Controller not here MOV AL,FDSNRD STC RET ; Show not read ; Controller exists DSK_EXCMD1: CALL DSK_OCMD ; Execute command DSK_WCMPLT: CALL DSK_IAS ; Get aux status TEST AL,ASIRQ ; Is command completed ? JZ DSK_WCMPLT ; No, keep looking DSK_WCMPLT1: PUSH CX ; Save CX MOV CX,FDCOML ; Get time to wait before reading status CALL ALARM_WAIT ; Wait for command to get started POP CX ; Recover CX DSK_WCMPLT2: CALL DSK_ISTA ; Get status TEST AL,FDSBSY ; Is controller chip busy ? JNZ DSK_WCMPLT2 ; Yes, try again RET ; No, return ; ; DSK_IAS, DSK_ISTA, DSK_ITRK, DSK_ISEC, DSK_IDAT - routines to do input ; through controller base port at DSK_PORT[SI] ; ; Returns: ; AL = value from command ; ; Uses: DX ; DSK_IAS: MOV DX,FDAS ; Get Aux status port offset JMP SHORT DSK_PIN ; Join command code DSK_ITRK: MOV DX,FDTRK ; Get track port offset JMP SHORT DSK_PIN ; Join common code DSK_ISEC: MOV DX,FDSEC ; Get sector port offset JMP SHORT DSK_PIN ; Join common code DSK_IDAT: MOV DX,FDDAT ; Get data port offset JMP SHORT DSK_PIN ; Join common code DSK_ISTA: MOV DX,FDSTA ; Get status port offset DSK_PIN: ADD DX,WORD PTR DSK_PORT[SI] ; Add base port IN AL,DX ; Execute command RET ; and return ; ; DSK_OCON, DSK_OCMD, DSK_OTRK, DSK_OSEC, DSK_ODAT - Routines to do ; output through controller base port DSK_PORT[SI] ; ; Call with: ; AL = value to output ; ; Uses: DX ; DSK_OCON: MOV DX,FDCON ; Get control port offset JMP SHORT DSK_POUT ; Join common code DSK_OCMD: MOV DX,FDCMD ; Get command port offset JMP SHORT DSK_POUT ; Join common code DSK_OTRK: MOV DX,FDTRK ; Get track port offset JMP SHORT DSK_POUT ; Join common code DSK_OSEC: MOV DX,FDSEC ; Get sector port offset JMP SHORT DSK_POUT ; Join comon code DSK_ODAT: MOV DX,FDDAT ; Get data port offset DSK_POUT: ADD DX,WORD PTR DSK_PORT[SI] ; Add in base port OUT DX,AL ; Output value RET ; and return PAGE ; ; Winchester Driver ; DSKW: ; Go to function ; (DI has function index) JMP WORD PTR DSKW1[DI] ; Case to function DSKW1 DW OFFSET DSKWFRS ; Reset function DW OFFSET DSKWFST ; Status function DW OFFSET DSKWFRD ; Read function DW OFFSET DSKWFWR ; Write function DW OFFSET DSKWFVF ; Verify function DW OFFSET DSKWFFT ; Format function DW OFFSET DSKWFSI ; Step in function DW OFFSET DSKWFRT ; Read track function DW OFFSET DSKBDO ; GBIOSVEC DW OFFSET DSKBDO ; MAPDSK DW OFFSET DSKBDO ; SETFDC DW OFFSET DSKWPRD ; PREAD PAGE ; ; Reset(home) function for winchester ; ; Clears errors and moves head to track zero. ; ; Call with: ; ES:BX -> parameter block addr ; SI -> disk table ; ; Returns: ; CY clear - no errors ; CY set - errors ; DSKWFRS: CLC ; No errors on RESET RET ; and return PAGE ; ; DSKWFST - Status function for winchester ; ; Clear errors and get current status. ; ; ; Call with: ; ES:BX -> parameter block addr ; SI -> disk table ; ; Returns: ; CY clear - no errors ; CY set - errors ; DSKBDO: ; Bad operation DSKWFST: MOV AX,DSKST_NIERR ; Get not implemented error code STC ; Show error RET ; and return PAGE ; ; DSKWFVF - verify function for winchester ; ; (we haven't decided what we want to do with this) ; ; Call with: ; ES:BX -> parameter block addr ; SI -> disk table ; ; Returns: ; CY clear - no errors ; CY set - errors ; DSKWFVF: MOV AX,DSKST_NIERR ; Get not implemented error code STC ; Show error% RET ; and return PAGE ; ; DSKWFRD - Read function for winchester ; ; Reads one or more sectors from the disk ; ; Call with: ; ES:BX -> parameter block addr ; SI -> disk table ; ; Returns: ; CY clear - no errors ; CY set - errors ; DSKWFRD: MOV BYTE PTR PFLAG,0 ; Show no PREAD MOV AL,WICBRDL ; Get log read command JMP SHORT DSKWRDWR ; Join common code DSKWPRD: MOV BYTE PTR PFLAG,1 ; Show pread MOV AL,WICBRDL JMP SHORT DSKWRDWR ; Common entry ; ; DSKWFWR - Write function for winchester ; ; Writes one or more sectors to the disk ; ; Call with: ; ES:BX -> parameter block addr ; SI -> disk table ; ; Returns: ; CY clear - no errors ; CY set - errors ; DSKWFWR: MOV BYTE PTR PFLAG,0 ; Show logical MOV AL,WICBWRL ; Get log write command ; JMP SHORT DSKWRDWR ; Join common code ; ; Common code for read and write ; DSKWRDWR: MOV BYTE PTR DSK_WCB+WI1COM,AL ; Store command MOV AX,WORD PTR ES:DSKPR_SECTOR[BX] ; Get logical sector number TEST BYTE PTR PFLAG,0FFH JNZ DSKWRDWRP ADD AX,WORD PTR DSK_BSEC[SI] ; Add base sector DSKWRDWRP: MOV WORD PTR CUR_SECTOR,AX ; Save locally MOV DI,WORD PTR DSK_BPS[SI] ; Get bytes per sector MOV WORD PTR RETRY_SECTOR,0 ; Show sector of last error ; Compute next 256 sector block to read DSKWRDWR0: MOV AX,WORD PTR CUR_SECTOR ; Get logical sector number MOV BYTE PTR DS:(DSK_WCB+WI1DSHS),0 ; Store sector/drive MOV BYTE PTR DS:(DSK_WCB+WI1SECH),AH ; Store hi sector number MOV BYTE PTR DS:(DSK_WCB+WI1SECL),AL ; Store lo sector number ; Get number of sectors to read/write MOV AL,BYTE PTR ES:DSKPR_COUNT[BX] MOV BYTE PTR DS:(DSK_WCB+WI1CNT),AL ; Set in number of sectors XOR AH,AH TEST AL,0FFH ; Zero? JNZ DSKWRDWRSC1 ; No, save count MOV AH,1 ; Zero = 256 DSKWRDWRSC1: MOV CS:WORD PTR SECCNT,AX ; Save count for later ; Compute buffer addr and store in table XOR DX,DX ; Clear high part MOV CX,WORD PTR ES:DSKPR_BUFF+2[BX] ; Get segment SHL CX,1 ; First shift RCL DX,1 SHL CX,1 ; Second shift RCL DX,1 SHL CX,1 ; Third shift RCL DX,1 SHL CX,1 ; Fourth shift RCL DX,1 ADD CX,WORD PTR ES:DSKPR_BUFF[BX] ; Add offset ADC DX,0 ; Propagate cary MOV BYTE PTR DSK_WCB+WI1TMAH,DL ; Store high part MOV BYTE PTR DSK_WCB+WI1TMAM,CH ; Store middle part MOV BYTE PTR DSK_WCB+WI1TMAL,CL ; Store low part ; Setup and do operation MOV DX,WICOM ; Get command port offset ADD DX,WORD PTR DSK_PORT[SI] ; Compute command port DSKWRDWREXEC: MOV BYTE PTR DS:(DSK_WCB+WI3ERR),0FFH ; Set completion code MOV AL,WICEXE ; Get execute command OUT DX,AL ; Start operation DSKWRDWR1: MOV AL,BYTE PTR DSK_WCB+WI3ERR ; Get error code CMP AL,0FFH ; Is command finished ? JE DSKWRDWR1 ; No, keep looking CMP AL,0 ; Any errors ? JE DSKWRDWR2 ; No, keep going ; Here on errors CMP AL,WIEDNR ; Drive not ready? JZ DSKWRDWREXEC ; Yes, execute it again! ; Not a "drive not ready" problem PUSH BX CALL DSKW_RETRY ; Do a disk retry POP BX JC DSKWRDWROE ; If too late, bad errors JMP NEAR PTR DSKWRDWR2 ; Disk error - retries don't help DSKWRDWROE: MOV AL,BYTE PTR DSK_WCB+WI3ERR ; AL = error code ; Look up the equivelant Z217 error code MOV SI,OFFSET RW_ERRD DSKWRDWROE1: CMP BYTE PTR [SI],AL ; This one? JZ DSKWRDWROE2 ; Yes CMP BYTE PTR [SI],-1 ; Terminator? JZ DSKWRDWROE2 ; Yes ADD SI,2 ; Search for it JMP SHORT DSKWRDWROE1 ; Found it, pointer in [si+1] DSKWRDWROE2: MOV AL,BYTE PTR [SI+1] ; AL = error code STC RET ; Transfer error, computed count exceeded DSKWRDWRTE: MOV AX,FDSCRC+FDSLDT ; Make it look like a data error STC ; Show error RET ; and return DSKWRDWR2: MOV AX,CS:WORD PTR SECCNT SUB WORD PTR ES:DSKPR_COUNT[BX],AX CMP WORD PTR ES:DSKPR_COUNT[BX],0 ; All done? JZ DSKWRDWR3 ; Yes ; Compute next address and current sector number ADD WORD PTR CUR_SECTOR,AX ; Bump current sector number M%UL DI ; DX:AX = bytes read JC DSKWRDWRTE ; Error, DX must be > 0 ; DX is checked for zero, since transfers must be < 64k bytes ADD WORD PTR ES:DSKPR_BUFF[BX],AX ; Compute next addr in buffer JMP DSKWRDWR0 ; do next one DSKWRDWR3: XOR AX,AX ; Clear AX and CY to show success RET ; and return PAGE ; ; DSKWFFT - Format function for winchester ; ; Formats the disk ; ; Call with: ; ES:BX -> parameter block addr ; SI -> disk table ; ; Returns: ; CY clear - no errors ; CY set - errors ; DSKWFFT: MOV AX,DSKST_NIERR ; Get not implemented error code STC ; Show error RET ; and return PAGE ; ; DSKFSI - Step in function for winchester ; ; Steps the head in one sector track ; ; Call with: ; ES:BX -> parameter block addr ; SI -> disk table ; ; Returns: ; CY clear - no errors ; CY set - errors ; DSKWFSI: MOV AX,DSKST_NIERR ; Get not implemented error code STC ; Show error  RET ; and return PAGE ; ; DSKWFRT - Read track function for winchester ; ; Reads a track from the disk ; ; Call with: ; ES:BX -> parameter block addr ; SI -> disk table ; ; Returns: ; CY clear - no errors ; CY set - errors ; DSKWFRT: MOV AX,DSKST_NIERR ; Get not implemented error code STC ; Show error RET ; and return ; ; DSKW_RETRY - Do a winchester retry ; ; Retry the read/write operation ; ; Call with: ; RETRY_SECTOR - Last sector with errors ; SECCNT - Number of sectors attempted ; WI1HSE-WI1SCLE - Sector of error ; ; Returns: ; 'cy' set if retries all failed ; 'cy' clear if retry attempted ; RETRY_SECTOR updated ; SECCNT updated ; CUR_SECTOR updated ; DSKW_RETRY: MOV AX,WORD PTR DSK_WCB+WI1SCHE ; AX = sector of error XCHG AH,AL CMP AX,WORD PTR RETRY_SECTOR ; Same as last time JZ DSKW_RETSS ; Yes, retry same sector ; New sector, calculate figures MOV WORD PTR RETRY_SECTOR,AX ; Set it here MOV BX,WORD PTR CUR_SECTOR ; BX = old starting SUB AX,BX ; AX = sectors read MOV WORD PTR SECCNT,AX MOV BYTE PTR RETRY_INDX,-1 ; Set index for errors JMP SHORT DSKW_RETSS1 ; Here for each subsequent attempt of a single bad sector DSKW_RETSS: MOV WORD PTR SECCNT,0 ; Show none read DSKW_RETSS1: INC BYTE PTR RETRY_INDX ; 0=first, 1=second, ... CMP BYTE PTR RETRY_INDX,3 ; Try 3 at best STC JNZ DSKW_RETSS2 ; If not bad ; Had 3 retries, too bad RET ; 'cy' is set ; Try another time DSKW_RETSS2: MOV BL,BYTE PTR RETRY_INDX XOR BH,BH SHL BX,1 ; BX = word index JMP WORD PTR DSKW_RETSSV[BX] ; Try it ; Jump vector for winchester retries DSKW_RETSSV LABEL NEAR DW OFFSET DSKW_RETSSSH ; Seek to higher cylinder DW OFFSET DSKW_RETSSSL ; Seek to lower cylinder DW OFFSET DSKW_RETSSRS ; Restore system ; ; DSKW_RETSSSH - Seek to higher cylinder ; DSKW_RETSSSH: MOV BX,WORD PTR [SI+DSK_SPT] ; Get sectors/cylinder JMP SHORT DSKW_RETSSSX ; ; DSKW_RETSSSL - Seek to lower cylinder ; DSKW_RETSSSL: MOV BX,WORD PTR [SI+DSK_SPT] ; Sectors/cylinder NEG BX ; Make it minus ; JMP SHORT DSKW_RETSSSX DSKW_RETSSSX: MOV AX,WORD PTR RETRY_SECTOR ADD AX,BX ; AX = target XCHG AH,AL MOV WORD PTR DSK_WCB+WI1SECH,AX MOV BL,BYTE PTR DSK_WCB ; Save the old one MOV BYTE PTR DSK_WCB,WICBSKL ; Seek logical DSKW_RETSSSX0: MOV BYTE PTR DS:(DSK_WCB+WI3ERR),0FFH ; Set completion code MOV DX,WICOM ; Get command port offset ADD DX,WORD PTR DSK_PORT[SI] ; Compute command port MOV AL,WICEXE ; Get execute command OUT DX,AL ; Start operation DSKW_RETSSSX1: MOV AL,BYTE PTR DSK_WCB+WI3ERR ; Get error code CMP AL,0FFH ; Is command finished ? JE DSKW_RETSSSX1 ; No, keep looking MOV BYTE PTR DSK_WCB,BL ; Restore old op-code CLC RET ; Return to caller ; ; DSKW_RETSSRS - Restore head ; DSKW_RETSSRS: MOV BL,BYTE PTR DSK_WCB MOV BYTE PTR DSK_WCB,WICBRCL ; Recal drive JMP SHORT DSKW_RETSSSX0 ; Execu&te it PAGE ; ; Variables used by disk routines ; SIDFLG DB 0 ; Side flag - 0 if side 0, FDFSS1 if side 1 CUR_SECTOR DW ? ; Current logical sector IF DSK_RTY RETRY_INDX DB ? ; Index in cycle of retry procedure RETRY_FLAG DB ? ; Flag (00 = retry without seek) RETRY_SECTOR DW ? ; sector of last retry RETRY_CREM DB ? ; Remaining number of retry cycles ENDIF SECCNT DW ? ; Sectors transfered in DSKW PFLAG DB 0 ; =0 if logical read, else physical read IF NOT LOADER DSK_FUN DB ? ; Function to perform DSK_WRIC DB ? ; Flag that shows that a write hass occured DSK_LDRIVE DW -1 ; Last drive DSK_DBIT DB ? ; Delay command ENDIF DSK ENDP d at 0:INT_UT) ; ISR_UTM: IRET 0000100B ;POLL COMMAND OCW3RIR EQU 00000010B ;READ IR REG OCW3RIS EQU 00000011B ;READ IS REG DATE TIME  or $F ; ; This table contains pointers to the actual disk ; tables used by the bios. ; ; LAST MODIFIED: 1/20/83 - bcb ; ; These variables must be located before DSK_TPTR ; Variables used by timer(must disable interrupts when acessing them) DSKT_FG DB 0 ; !=0 timer should look at remaining vars DSKT_DNCTR DW ? ; Down counter for deselect(100ths of secs) DSKT_PORT DW ? ; Port number to use to deselect drive DSKT_DSEL DB ? ; Deselect command DW OFFSET SPDISK ; Special disk (before DSK_TPTR) DSK_TPTR LABEL WORD DW OFFSET DISK0 DW OFFSET DISK1 DW OFFSET DISK2 DW OFFSET DISK3 DW OFFSET DISK4 DW OFFSET DISK5 DSK_BMPVAL EQU ((OFFSET $)-(OFFSET DSK_TPTR))/2 ; Define alternate formats DW OFFSET DISK0 DW OFFSET DISK1 DW OFFSET DISK2 DW OFFSET DISK3 DSK_BMPVAL1 EQU ((OFFSET $)-(OFFSET DSK_TPTR))/2 ; Define alternates for 5" DW OFFSET DISK0 DW OFFSET DISK1 ; ; The Special DISK ; ; NOTE: The -1 bytes in this table are used to terminate the ; above word table when being searched at boot time. If SPDISK ; is moved to another location, then a word of -1 must be ; placed after the last entry in the above table! ; SPDISK DB DSK_SIZE DUP(0FFH) ; Initialized to an invalid value ; ; 5.25 inch Unit 0 ; DISK0 LABEL BYTE ERRNZ DISK0,DSK_STA DW 0 ; Status ERRNZ DISK0,DSK_TYPE DB DSK_TZ207 ; Z-207 type disk ERRNZ DISK0,DSK_LTRK DB 0 ; Last track ERRNZ DISK0,DSK_LOPT DB DSK_OUK ; Last operation is unknown ERRNZ DISK0,DSK_FLAG DB DSK_FDS+DSK_FDC+DSK_FSL ; Double sided disk ERRNZ DISK0,DSK_SEL DB CONDSEN+0+CONPC ; Select disk 0, no precomp ERRNZ DISK0,DSK_RS DB FDCRST+FDFHLB+FDFS6 ; Restore(home) command ERRNZ DISK0,DSK_SPHI DB FDCSTI+FDFHLB+FDFS6+FDFUTR ; Step in command ERRNZ DISK0,DSK_FMT DB FDCWRT+FDFDLF ; Format(write track) command ERRNZ DISK0,DSK_RD DB FDCRDS+FDFSLF ; Read command ERRNZ DISK0,DSK_WR DB FDCWRS+FDFSLF ; Write command ERRNZ DISK0,DSK_SK DB FDCSEK+FDFHLB+FDFS6 ; Seek command ERRNZ DISK0,DSK_SERR DW 0 ; # of soft errors ERRNZ DISK0,DSK_MAXT DB 80 ; Number of tracks on disk ERRNZ DISK0,DSK_NRETRY DB 1 ; Number of retrys ERRNZ DISK0,DSK_SPT DB 8 ; Sectors per track ERRNZ DISK0,DSK_BPS DW 512 ; Bytes per sector ERRNZ DISK0,DSK_BPWT DW 6437 ; Bytes per write track ERRNZ DISK0,DSK_BPRT DW 6437 ; Bytes per read track ERRNZ DISK0,DSK_DELAY DW 400 ; 400 instr = 1.5mls ERRNZ DISK0,DSK_LDELAY DW 4000 ; 4000 instr = 15mls ERRNZ DISK0,DSK_PORT DW Z207A ; Base Port number ERRNZ DISK0,DSK_RDT DB FDCRDT+FDFDLF ; Read track command ERRNZ DISK0,DSK_IMGFLG DB DSKIF_DV ; Drive exits ERRNZ DISK0,DSK_TDSEL DW 100 ; Time to wait before deselect ERRNZ DISK0,DSK_NAME DB 'A' ; Drive A: ERRNZ DISK0,DSK_SIZE ; ; 5.25 inch, Unit 1 ; DISK1 LABEL BYTE ERRNZ DISK1,DSK_STA DW 0 ; Status ERRNZ DISK1,DSK_TYPE DB DSK_TZ207 ; Z-207 type disk ERRNZ DISK1,DSK_LTRK DB 0 ; Last track ERRNZ DISK1,DSK_LO&PT DB DSK_OUK ; Last operation is unknown ERRNZ DISK1,DSK_FLAG DB DSK_FDS+DSK_FDC+DSK_FSL ; Double sided disk ERRNZ DISK1,DSK_SEL DB CONDSEN+1+CONPC ; Select disk 1, no precomp ERRNZ DISK1,DSK_RS DB FDCRST+FDFHLB+FDFS6 ; Restore(home) command ERRNZ DISK1,DSK_SPHI DB FDCSTI+FDFHLB+FDFS6+FDFUTR ; Step in command ERRNZ DISK1,DSK_FMT DB FDCWRT+FDFDLF ; Format(write track) command ERRNZ DISK1,DSK_RD DB FDCRDS+FDFSLF ; Read command ERRNZ DISK1,DSK_WR DB FDCWRS+FDFSLF ; Write command ERRNZ DISK1,DSK_SK DB FDCSEK+FDFHLB+FDFS6 ; Seek command ERRNZ DISK1,DSK_SERR DW 0 ; # of soft errors ERRNZ DISK1,DSK_MAXT DB 80 ; Number of tracks on disk ERRNZ DISK1,DSK_NRETRY DB 1 ; Number of retrys ERRNZ DISK1,DSK_SPT DB 8 ; Sectors per track ERRNZ DISK1,DSK_BPS DW 512 ; Bytes per sector ERRNZ DISK1,DSK_BPWT DW 6437 ; Bytes per write track ERRNZ DISK1,DSK_BPRT DW 6437 ; Bytes per read track ERRNZ DISK1,DSK_DELAY DW 400 ; 400 instr = 1.5mls ERRNZ DISK1,DSK_LDELAY DW 4000 ; 4000 instr = 15mls ERRNZ DISK1,DSK_PORT DW Z207A ; Base Port number ERRNZ DISK1,DSK_RDT DB FDCRDT+FDFDLF ; Read track command ERRNZ DISK1,DSK_IMGFLG DB DSKIF_DV ; Drive exits ERRNZ DISK1,DSK_TDSEL DW 100 ; Time to wait before deselect ERRNZ DISK1,DSK_NAME DB 'B' ; Drive B: ERRNZ DISK1,DSK_SIZE ; ; DISK2 - 8" unit 0 ; DISK2 LABEL BYTE ERRNZ DISK2,DSK_STA DW 0 ; Status ERRNZ DISK2,DSK_TYPE DB DSK_TZ207 ; Z-207 type disk ERRNZ DISK2,DSK_LTRK DB 0 ; Last track ERRNZ DISK2,DSK_LOPT DB DSK_OUK ; Last operation is unknown ERRNZ DISK2,DSK_FLAG DB DSK_FDS+DSK_FDC+DSK_FRS ; Double sided disk ERRNZ DISK2,DSK_SEL DB CONDSEN+0+CONDS8+CONPC ; Select disk 0, no precomp ERRNZ DISK2,DSK_RS DB FDCRST+FDFHLB+FDFS6 ; Restore(home) command ERRNZ DISK2,DSK_SPHI DB FDCSTI+FDFHLB+FDFS6+FDFUTR ; Step in command ERRNZ DISK2,DSK_FMT DB FDCWRT+FDFDLF ; Format(write track) command ERRNZ DISK2,DSK_RD DB FDCRDS+FDFSLF ; Read command ERRNZ DISK2,DSK_WR DB FDCWRS+FDFSLF ; Write command ERRNZ DISK2,DSK_SK DB FDCSEK+FDFHLB+FDFVRF+FDFS6 ; Seek command ERRNZ DISK2,DSK_SERR DW 0 ; # of soft errors ERRNZ DISK2,DSK_MAXT DB 77 ; Number of tracks on disk ERRNZ DISK2,DSK_NRETRY DB 1 ; Number of retrys ERRNZ DISK2,DSK_SPT DB 8 ; Sectors per track ERRNZ DISK2,DSK_BPS DW 1024 ; Bytes per sector ERRNZ DISK2,DSK_BPWT DW 1 ; Bytes per write track ERRNZ DISK2,DSK_BPRT DW 1 ; Bytes per read track ERRNZ DISK2,DSK_DELAY DW 400 ; 400 instr = 1.5mls ERRNZ DISK2,DSK_LDELAY DW 4000 ; 4000 instr = 15mls ERRNZ DISK2,DSK_PORT DW Z207A ; Base Port number ERRNZ DISK2,DSK_RDT DB FDCRDT+FDFDLF ; Read track command ERRNZ DISK2,DSK_IMGFLG DB DSKIF_DV ; Drive exits ERRNZ DISK2,DSK_TDSEL DW 100 ; Time to wait before deselect ERRNZ DISK2,DSK_NAME DB 'C' ; Drive C: ERRNZ DISK2,DSK_SIZE ; ; DISK3 - 8" unit 1 ; DISK3 LABEL BYTE ERRNZ DISK3,DSK_STA DW 0 ; Status ERRNZ DISK3,DSK_TYPE DB DSK_TZ207 ; Z-207 type disk ERRNZ DISK3,DSK_LTRK DB 0 ; Last track ERRNZ DISK3,DSK_LOPT DB DSK_OUK ; Last operation is unknown ERRNZ DISK3,DSK_FLAG DB DSK_FDS+DSK_FDC+DSK_FRS ; Double sided disk ERRNZ DISK3,DSK_SEL DB CONDSEN+1+CONDS8+CONPC ; Select disk 1, no precomp ERRNZ DISK3,DSK_RS DB FDCRST+FDFHLB+FDFS6 ; Restore(home) command ERRNZ DISK3,DSK_SPHI DB FDCSTI+FDFHLB+FDFS6+FDFUTR ; Step in command ERRNZ DISK3,DSK_FMT DB FDCWRT+FDFDLF ; Format(write track) command ERRNZ DISK3,DSK_RD DB FDCRDS+FDFSLF ; Read command ERRNZ DISK3,DSK_WR DB FDCWRS+FDFSLF ; Write command ERRNZ DISK3,DSK_SK DB FDCSEK+FDFHLB+FDFVRF+FDFS6 ; Seek command ERRNZ DISK3,DSK_SERR DW 0 ; # of soft errors ERRNZ DISK3,DSK_MAXT DB 77 ; Number of tracks on disk ERRNZ DISK3,DSK_NRETRY DB 1 ; Number of retrys ERRNZ DISK3,DSK_SPT DB 8 ; Sectors per track ERRNZ DISK3,DSK_BPS DW 1024 ; Bytes per sector ERRNZ DISK3,DSK_BPWT DW 1 ; Byt'es per write track ERRNZ DISK3,DSK_BPRT DW 1 ; Bytes per read track ERRNZ DISK3,DSK_DELAY DW 400 ; 400 instr = 1.5mls ERRNZ DISK3,DSK_LDELAY DW 4000 ; 4000 instr = 15mls ERRNZ DISK3,DSK_PORT DW Z207A ; Base Port number ERRNZ DISK3,DSK_RDT DB FDCRDT+FDFDLF ; Read track command ERRNZ DISK3,DSK_IMGFLG DB DSKIF_DV ; Drive exits ERRNZ DISK3,DSK_TDSEL DW 100 ; Time to wait before deselect ERRNZ DISK3,DSK_NAME DB 'D' ; Drive D: ERRNZ DISK3,DSK_SIZE ; ; DISK4 - Winchester unit E: ; DISK4 LABEL BYTE ERRNZ DISK4,DSK_STA DW 0 ; Status ERRNZ DISK4,DSK_TYPE DB DSK_TZ217 ; Z-217 type disk ERRNZ DISK4,DSK_LTRK DB 0 ; Last track ERRNZ DISK4,DSK_LOPT DB DSK_OUK ; Last operation is unknown ERRNZ DISK4,DSK_FLAG DB 0 ; Holds flag from superblock ERRNZ DISK4,DSK_SEL DB 0 ; Select value ERRNZ DISK4,DSK_RS DB 0 ; Restore(home) command ERRNZ DISK4,DSK_SPHI DB 0 ; Step in command ERRNZ DISK4,DSK_FMT DB 0 ; Format(write track) command ERRNZ DISK4,DSK_RD DB 0 ; Read command ERRNZ DISK4,DSK_WR DB 0 ; Write command ERRNZ DISK4,DSK_SK DB 0 ; Seek command ERRNZ DISK4,DSK_SERR DW 0 ; # of soft errors ERRNZ DISK4,DSK_MAXT DB 0 ; Number of tracks on disk ERRNZ DISK4,DSK_NRETRY DB 0 ; Number of retrys ERRNZ DISK4,DSK_SPT DB 18 ; Sectors per track ERRNZ DISK4,DSK_BPS DW 512 ; Bytes per sector ERRNZ DISK4,DSK_BPWT DW 0 ; Bytes per write track ERRNZ DISK4,DSK_BPRT DW 0 ; Bytes per read track ERRNZ DISK4,DSK_DELAY DW 400 ; 400 instr = 1.5mls ERRNZ DISK4,DSK_LDELAY DW 4000 ; 4000 instr = 15mls ERRNZ DISK4,DSK_PORT DW Z217A ; Base Port number ERRNZ DISK4,DSK_RDT DB 0 ; Read track command ERRNZ DISK4,DSK_IMGFLG DB DSKIF_DV+DSKIF_NM ; Drive exits but can't be reused ERRNZ DISK4,DSK_TDSEL DW 0 ; Time to wait before deselect ERRNZ DISK4,DSK_NAME DB 'E' ; Drive E: ERRNZ DISK4,DSK_SIZE ERRNZ DISK4,DSK_BSEC DW 0 ; Base partition sector number ERRNZ DISK4,DSKW_NPS DW 0 ; Number of sectors in partition ERRNZ DISK4,DSKW_FAT DB 0 ; # sectors/FAT table ERRNZ DISK4,DSKW_SIZE ; ; DISK5 - Winchester unit F: ; DISK5 LABEL BYTE ERRNZ DISK5,DSK_STA DW 0 ; Status ERRNZ DISK5,DSK_TYPE DB DSK_TZ217 ; Z-217 type disk ERRNZ DISK5,DSK_LTRK DB 0 ; Last track ERRNZ DISK5,DSK_LOPT DB DSK_OUK ; Last operation is unknown ERRNZ DISK5,DSK_FLAG DB 0 ; Holds flag from superblock ERRNZ DISK5,DSK_SEL DB 0 ; Select ERRNZ DISK5,DSK_RS DB 0 ; Restore(home) command ERRNZ DISK5,DSK_SPHI DB 0 ; Step in command ERRNZ DISK5,DSK_FMT DB 0 ; Format(write track) command ERRNZ DISK5,DSK_RD DB 0 ; Read command ERRNZ DISK5,DSK_WR DB 0 ; Write command ERRNZ DISK5,DSK_SK DB 0 ; Seek command ERRNZ DISK5,DSK_SERR DW 0 ; # of soft errors ERRNZ DISK5,DSK_MAXT DB 0 ; Number of tracks on disk ERRNZ DISK5,DSK_NRETRY DB 0 ; Number of retrys ERRNZ DISK5,DSK_SPT DB 18 ; Sectors per track ERRNZ DISK5,DSK_BPS DW 512 ; Bytes per sector ERRNZ DISK5,DSK_BPWT DW 0 ; Bytes per write track ERRNZ DISK5,DSK_BPRT DW 0 ; Bytes per read track ERRNZ DISK5,DSK_DELAY DW 400 ; 400 instr = 1.5mls ERRNZ DISK5,DSK_LDELAY DW 4000 ; 4000 instr = 15mls ERRNZ DISK5,DSK_PORT DW Z217A ; Base Port number ERRNZ DISK5,DSK_RDT DB 0 ; Read track command ERRNZ DISK5,DSK_IMGFLG DB DSKIF_DV+DSKIF_NM ; Drive exits but can't be reused ERRNZ DISK5,DSK_TDSEL DW 0 ; Time to wait before deselect ERRNZ DISK5,DSK_NAME DB 'F' ; Drive F: ERRNZ DISK5,DSK_SIZE ERRNZ DISK5,DSK_BSEC DW 0 ; Base partition sector number ERRNZ DISK5,DSKW_NPS DW 0 ; Number of sectors in partition ERRNZ DISK5,DSKW_FAT DB 0 ; # sectors/FAT table ERRNZ DISK5,DSKW_SIZE ; ; Command block for winchester I/O ; DSK_WCB LABEL BYTE DB WI1_SIZE DUP (0) ; Fill with zeros ERRNZ DSK_WCB,WI1_SIZE ERRNZ DSK_WCB,WI3_SIZE ; Insure enough for both ' REM *** DOBIOS.BAT - This batch file makes the BIOS REM *** REM *** The result will be on the default drive and takes REM *** approximately 30 minutes to complete. REM *** REM *** 8/6/82 - dtp PAUSE Is this what you want to do ?(if not then press ^C) MASM BMSDOS; MASM BCHR; MASM BDSK; MASM BEND; LINK @BMSDOSL EXE2BIN BMSDOS.EXE .BIN ERASE BMSDOS.EXE REM *** DOBIOS completed ***  ; MACLIB - library of commonly used macro definitions SVC MACRO DOSF ;Supervisor (DOS function) call MOV AH,DOSF INT 21H ENDM RETF MACRO ;Return far instruction emulation LOCAL TEMP1 TEMP1 PROC FAR RET TEMP1 ENDP ENDM PUSHALL MACRO ;Save all registers PUSH AX PUSH BX PUSH CX PUSH DX PUSH SI PUSH DI PUSH BP PUSH DS PUSH ES ENDM POPALL MACRO ;Restore all registers POP ES POP DS POP BP POP DI POP SI POP DX POP CX POP BX POP AX ENDM ERRNZ MACRO LABEL,ADDRESS ;Check current location IF (($-OFFSET LABEL)-ADDRESS NE 0) #1: DW LABEL,ADDRESS ENDIF ENDM ERRZR MACRO LABEL,ADDRESS ;Error if zero IF (($-OFFSET LABEL)-ADDRESS EQ 0) #1: DW LABEL,ADDRESS ENDIF ENDM 0000100B ;POLL COMMAND OCW3RIR EQU 00000010B ;READ IR REG OCW3RIS EQU 00000011B ;READ IS REG DATE TIME  or $FBMSDOS+BCHR+BDSK+BEND BMSDOS BMSDOS/MAP; %`A C`GENDIF ENDM ERRZR MACRO LABEL,ADDRESS ;Error if zero IF (($-OFFSET LABEL)-ADDRESS EQ 0) #1: DW LABEL,ADDRESS ENDIF ENDM 0000100B ;POLL COMMAND OCW3RIR EQU 00000010B ;READ IR REG OCW3RIS EQU 00000011B ;READ IS REG DATE TIME  or $F