IMD 1.17: 18/01/2011 11:42:57 48tpi cp/m-86 version 1.1b rev b *non-system pc series 62-0030-002 eagle computer Ȏ؎м|+}|&>x&z+}}D }u t}}V}M࣫}D@L:Er*E&}}PM袭}u}:Er}*}}}}u}%}Q.}WV>}J}&% &  ^_Ê uCôtS[ô+ۋ }\} t}}}}r+}u CPM SYSError in reading the operating system.Diskette in drive A is not a system diskette.Q ?}$*P(*! COPYRIGHT (C) 1980, DIGITAL RESEARCH ͎ñ3б QYð Q[ uCS[';20 빱:뵱 뱊бñG'tù رԺ's ñ' V u. 0 >,. 0 Q$ТX$9 .> u0 AsA+>&_9 .> ;t׋65 tu+: tE>( t5H ؋⹐ \ 7 < t tS[C?. t: u̻( ? u!Ê< t'C,0< suűrrruÀ? uCuûK؊': t$Ȼ9 :t: t Ȼ9 :uà9 W '> t  > t /.  u(? u ?CuR)uuȊȰ Es u p t bZR$PuzQYAj:e^:[V$< uXP<u $< t 5ŀ s u$XIu`Z. u!d  tC?YtC5 >( tg'HuL. uJ>( tCetr S#[uCJ<tS[uuE. :u: PtU'765 <=t<_u5F65 u+X:  t:ň/u/'t')8o G( uW{ '>( u: tȢ9 1 t̠9 >0 t30'u=@t+؎%: S'[7G\'! t t < tN tſ&E.&E.*. ?t.0 (, : uh(8؎Ћ@ F2ك+cG  GFG3؎Pg&U}43S,5Hu))x00;uB3P P(F%t.yP P P |P}(OPPm u3P(UP66; 帱P7^=FtF0F3]à),6Q*+]u,0仴SPPu]u)0仴SPPt\]3x2S1/4((.;u.y)U *v FcFF^0^Cvv c^lu ]v 76cHuñc؃ce HtFc3 ]Uv-.]UyP PP ~u P& P&P& P P P&=u3]øHPs3PKPvH *v0P 6iP*&vP&=t]ø P P VP&GUyP PP FF0=v F 0PbF0@Fۋv 0@P|P% P P 帇P%0=FFt= u]3]UyPx00;ux0u PU% PJ%00;ux0u P)% JP%{P%帮P %P%P$/P$dP$帖P$ ) @@ ]U0Ft F]øPPi$%]UF%PPK$F]U0t]ËF]Uv0uv P$F@@v\0v]UFFv0tFv$v P#v]U P#u33CÃ]U6cg6e]UPv'6uv>6g6cWUtÃ>uteEe;r0=}6>..> }6> >}6ge6eH]UvPh"F]Uv<tF0P]U3PPP %]UF ^ NVR2RFN^"]Uv0u3]áevD)PP!vF1v1 -]ø]v -3]=t=tUv u3]áevD)PPZ!v FYv .3]ø]à-0Hu]v .Pv #!]=t=t=t]U FFFF^;|FûF^vS^sF y F@Fƃ~ ~ FHF3 ]ËF yFvv7F F ]U0=FuFPYPPP'!P>P5F0= F|P PPF0]Uu3]7u3]]U-P+0Ht 40u3-]ø PPPFPP+^SF;Pr-]Uu3]=t3]ø]UP33P P"PVP>SFF=t=u]3]UP3P P40HuPP P6P]UiP帬P|=t]37]U 3Pv v .40t00;u*v V5FF0='0PMHuF0@v VhF0@F]Ue#!P=Fu]Ã~uG]6cgP=Fu]Ã~u]Ã~u-0u]U6cPV3]U e& P2c7F^03v0=uP,u ]vP vgP F@PCvXF@PMHttP=Fu ]Ã~u vFIvgP=F u ]Ã~ u vF~ u -0t ~ unF*PF0P6c ]UHu]v]UHu]v Pu]v-FtHuF]vu]vBu]v vqu]ø]U-0uvD\ #!]U3> }->u&vF0%v F 0+ã̡]UPF PpF Pd]U PPFw0^;|^0FHAPPF~|v0^0;uvF F = }v0%PF .PF F = }v0%PF PF;eFu3 ]Fq PF1F ]U c SFvCOPYDISKCMDLDCOPY CMDBLMCMD CMD( LOADER CMD/ GENDEF CMDLLDBDOS H86ALDCPM H86BACKUP CMDQ !"#$%&RESTORE CMDI'(456789:;<=\TBIOS A860)*+,-./0123LDBIOS A86456789:;<=LDCPM A86,>?@RANDOM A868ABCDDEBLOCK LIBQEFGHIJSINGLES DEFK8087 LIB[LMNOPQCOPYDISKA86 RSTUVWXYZNEWSYS SUB[TRACK A868\]^_LDCOPY A86Y`abcdeCPMBIOS A86fghijklmnopqrstuCPMBIOS A86vwxyz{|}~CPMBIOS A86CPMBIOS A86\PCRESTOR$$$ 44VV[؎мS5`tZ ð     2>,A$$tȎм$$$&_tUWV%#^_]%#$&$$$ω$#3$'###!S)r 6ٷ. #<uU###jS$A##YPQ'#(#26$6$#>$$YXQ!Q$YPQ(#2$#>$>$YXñ"##ȎS"[PS\+\E+E;v[X++" "<tf<u"|t>D"|DtD"Q8RZY>$t1Q6Y"9DsD8\|t Ts [T t)"7T>$t5H;"wױ7="+,>###;uE# "8t ðÀ>"u "ډ"ð|t.|t\;\v+\\UUðTTÃ|tDD"">"u """, "<t<u"|uD< u ÃpuS5[T"ÃË%sá$##"$"$"ʱ3 ">$tuMT"p "Q?t$GOQpu€YY Ў"$0"&E "8t 0D&ED|tD&&e&>"u &e& ƒv"$$"$"$#<t >#wh##$%$ڊOW[3ۊ؁%$Ë$%#$.#>#GEE)#u >*#tsunD9GrGSyuX:*#sMHuD+9GrG-Su2u-k99& COPYRIGHT (C) 1981, DIGITAL RESEARCH ؎ >] t d>e ueCfMgD\u |QR\ZY<tIt uúMS,A:r-&-b#l0< uRRTAE< t8,A:r&~So!< u  ;u;t[ ۋVQY^+^@;u @;ut tE< ugىeRZúGðj0> t  :tFF=RV>;u^^>u<t$;u#.%t.%u 9=_^]ZY[&-=/=Xϊ':r*KË7 00;r ͉̓ÆĉX$t u=03=92% <0u ÌȎr%t*;% tBw t% tCS[;S@&c=t;;;[WR>;;t tĪ>;Z_WR; BLOCK SIZE) DB 01 ;NULL MASK DW 194 ;DISK SIZE - 1 DW 191 ;DIRECTORY MAX DB 0E0H ;ALLOC 0 DB 0 ;ALLOC 1 DW 48 ;CHECK SIZE DW 2 ;TRACK OFFSET ; DB 7 ;SECTOR MASK DB 3 ;SECTOR SHIFT FACTOR DB 0 ;TRACK / HEAD METHOD DB 1 ;READ SIZE DW E48_BASE DW EXLT ;TRANSLATION TABLE ;----------------------------------------------------------- ; PC SINGLE SIDED ; ; 512 BYTES PER SECTOR ; 8 SECTORS PER TRACK ; 40 TRACKS PER DRIVE ; DOUBLE DENSITY ;----------------------------------------------------------- DPBK5 DW 32 ;LOGICAL SECTORS/TRACK DB 3 ;BLOCK SHIFT FACTOR DB 7 ;BLOCK MASK DB 0 ;EXTENT MASK DW 155 ;AVAILABLE BLOCKS - 1 DW 63 ;DIRECTORY ENTRIES - 1 DB 0C0H ;AL0 DB 00H ;AL1 DW 16 ;CHECK VECTOR SIZE DW 1 ;NUM RESERVED TRACKS DB 1FH ;SECTOR MASK DB 5 ;SECTOR SHIFT DB 1 ;TRACK / HEAD METHOD DB 8 ;READ SIZE DW PC_BASE DW 0 ;TRANSLATION ;----------------------------------------------------------- ; PC DOUBLE SIDED ; ; 512 BYTES PER SECTOR ; 8 SECTORS PER TRACK ; 80 TRACKS PER DRIVE ; DOUBLE DENSITY ;----------------------------------------------------------- DPBK6 DW 32 ;LOGICAL SECTORS/TRACK DB 4 ;BLOCK SHIFT FACTOR DB 15 ;BLOCK MASK DB 1 ;EXTENT MASK DW 157 ;AVAILABLE BLOCKS - 1 DW 63 ;DIRECTORY ENTRIES - 1 DB 80H ;AL0 DB 00H ;AL1 DW 16 ;CHECK VECTOR SIZE DW 1 ;NUM RESERVED TRACKS DB 1FH ;SECTOR MASK DB 5 ;SECTOR SHIFT DB 1 ;TRACK / HEAD METHOD DB 8 ;READ SIZE DW PC_BASE DW 0 ;TRANSLATION TABLE ;----------------------------------------------------------- ; WINCHESTER DISK ; ; 512 BYTE SECTORS ; 17 SECTORS PER TRACK ; TOTAL SIZE OF DISK(S) WE SET DYNAMICALLY ; ;----------------------------------------------------------- ; FIRST LOGICAL WINCHESTER DRIVE ;----------------------------------------------------------- XLTB10 EQU 0 ;NO TRANSLATION TABLE DPBK10 DW 17*4 ;SECTORS PER TRACK DB 4 ;SHIFT FACTOR DB 15 ;BLOCK MASK (8K BLOCK) DB 00 ;NULL MASK DW 4095 ;DISK SIZE - 1 DW 1023 ;DIRECTORY MAX DB 0FFH ;ALLOC 0 DB 0FFH ;ALLOC 1 DW 0 ;CHECK SIZE DW 2 ;TRACK OFFSET ; DB 3 ;SECTOR MASK DB 2 ;SECTOR SHIFT DB 2 ;DRIVER TYPE DB 0 ;READ SIZE DW 0 ;POINTER DW 0 ;TRANSLATION VECTOR DPBK10SZ EQU OFFSET $ - OFFSET DPBK10 ;----------------------------------------------------------- ; SECOND LOGICAL WINCHESTER DISK ;----------------------------------------------------------- DPBK11 DW 17*4 ;SECTORS PER TRACK DB 4 ;SHIFT FACTOR DB 15 ;BLOCK MASK (8K BLOCK) DB 00 ;NULL MASK DW 0 ;DISK SIZE - 1 DW 1023 ;DIRECTORY MAX DB 0FFH ;ALLOC 0 DB 0FFH ;ALLOC 1 DW 0 ;CHECK SIZE DW 2 ;TRACK OFFSET ; DB 3 ;SECTOR MASK DB 2 ;SECTOR SHIFT DB 2 ;DRIVER TYPE DB 0 DW 0 ;POINTER DW 0 ;TRANSLATION VECTOR ;----------------------------------------------------------- ; THIRD LOGICAL WINCHESTER DRIVE ;----------------------------------------------------------- DPBK12 DW 17*4 ;SECTORS PER TRACK DB 4 ;SHIFT FACTOR DB 15 ;BLOCK MASK (8K BLOCK) DB 00 ;NULL MASK DW 0 ;DISK SIZE - 1 DW 1023 ;DIRECTORY MAX DB 0FFH ;ALLOC 0 DB 0FFH ;ALLOC 1 DW 0 ;CHECK SIZE DW 2 ;TRACK OFFSET ; DB 3 ;SECTOR MASK DB 2 ;SECTOR SHIFT DB 2 ;DRIVER TYPE DB 0 DW 0 ;POINTER DW 0 ;TRANSLATION VECTOR ;----------------------------------------------------------- ; FOURTH LOGICAL WINCHESTER DRIVE ;----------------------------------------------------------- DPBK13 DW 17*4 ;SECTORS PER TRACK DB 4 ;SHIFT FACTOR DB 15 ;BLOCK MASK (8K BLOCK) DB 00 ;NULL MASK DW 0 ;DISK SIZE - 1 DW 1023 ;DIRECTORY MAX DB 0FFH ;ALLOC 0 DB 0FFH ;ALLOC 1 DW 0 ;CHECK SIZE DW 2 ;TRACK OFFSET ; DB 3 ;SECTOR MASK DB 2 ;SECTOR SHIFT DB 2 ;DRIVER TYPE DB 0 DW 0 ;POINTER DW 0 ;TRANSLATION VECTOR ;----------------------------------------------------------- ; DEFINE PHYSICAL TRACK OFFSETS ;------------------Xَэ&HP~+ɋUVN]0102821100654321UPP]UHĸpn@j\PP!P*PPPPw>uP(PePP\P\P\PF>u\P=>u-PV@]U]UPFP]U P P]U~ v FA, F0P]UFPF$P]UFPFP]U Pv]Uv]UkPvsP6pJ]U츃P]UPv]UPv]UPv]UPv]UPPz]UPvi]UPvY]UPvI]UPv9]UPv&]UFȈF t]UFN ]U>w:fu]u]UF,0< vF,A<vF,A ]Ur6s(6jwBP,uPjPPÙ>tPfjƇjj]Uz|~$%|>wLJuxp<uAPPnt>uJt>tt4t"<uu&PPePaP$㉇J.t$>t;~te9~u@ÈPv@Y"rP>ttB~ȢP [JjP Yi.t뷀>u .t6t~<w3 Ãjt j%1jnunuƸiPPP<P\PtmP.%P]Up@;v P Fn6p]Up@;r@"sn6pp]UP6xP6pP1x;ps u!n6x0=x P]U6x7:P P]U6\Ptm%]U@|@;w ]UK&&]UtHtt Ppp;|vH|]UPPZPYp]U'>'w'(t'u''rB>'w;!<w!'طM:(t!u؀>!t뷰]à'1]U..:Fwt.u]Ulm6l< tl]UP> u]I0s>]t> ù>0u뿀>0 u]U3>3w1s 3Ƈ5 35P3u042>0 r@"4sW211<v@"2s'015:t21Ǡ2s40뗠4s00]U>]u@P> u@Y"sp>AuP0 Ylƀ>Mu(hP0 Yn0P0 Yi뗀>Xu9P0 Yp4]CODE DATA EXTRASTACKX1 X2 X3 X4 8080 NZERONHEADCGROUPDGROUPEGROUPSGROUPTORY SCRATCH PAD DPB0 DW DPBK2 DW CSV0 ;CHECK VECTOR 0 DW ALV0 ;ALLOCATION VECTOR 0 ; ; DRIVE B: DISK PARAMETER HEADER ; DPH1 DW 0 ;NO TRANSLATE TABLE DW 0,0,0 ;RESERVED DW DIRBUF ;DIRECTORY SCRATCH PAD DPB1 DW DPBK2 DW CSV1 ;CHECK VECTOR 1 DW ALV1 ;ALLOCATION VECTOR 1 ; ; DRIVE C: DISK PARAMETER HEADER ; DPH2 DW 0 ;NO TRANSLATE TABLE DW 0,0,0 ;RESERVED DW DIRBUF ;DIRECTORY SCRATCH PAD DPB2 DW 0 DW CSV0 ;CHECK VECTOR 0 DW ALV0 ;ALLOCATION VECTOR 0  ; ; DRIVE D: DISK PARAMETER HEADER ; DPH3 DW 0 ;NO TRANSLATE TABLE DW 0,0,0 ;RESERVED DW DIRBUF ;DIRECTORY SCRATCH PAD DPB3 DW 0 DW CSV1 ;CHECK VECTOR 1 DW ALV1 ;ALLOCATION VECTOR 1 ; ; DRIVE E: DISK PARAMETER HEADER ; DPH4 DW 0 ;NO TRANSLATE TABLE DW 0,0,0 ;RESERVED DW DIRBUF ;DIRECTORY SCRATCH PAD DPB4 DW DPBK10 DW CSV10 ;CHECK VECTOR 0 DW ALV10 ;ALLOCATION VECTOR 0 ; ; DRIVE F: DISK PARAMETER HEADER ; DPH5 DW 0 ;NO TRANSLATE TABLE DW 0,0,0 ;RESERVED DW DIRBUF ;DIRECTORY SCRATCH PAD DPB5 DW DPBK11 DW CSV11 ;CHECK VECTOR 1 DW ALV11 ;ALLOCATION VECTOR 1 ; ; DRIVE G: DISK PARAMETER HEADER ; DPH6 DW 0 ;NO TRANSLATE TABLE DW 0,0,0 ;RESERVED DW DIRBUF ;DIRECTORY SCRATCH PAD DPB6 DW DPBK12 DW CSV12 ;CHECK VECTOR 2 DW ALV12 ;ALLOCATION VECTOR 2 ; ; DRIVE H: DISK PARAMETER HEADER ; DPH7 DW 0 ;NO TRANSLATE TABLE DW 0,0,0 ;RESERVED DW DIRBUF ;DIRECTORY SCRATCH PAD DPB7 DW DPBK13 DW CSV13 ;CHECK VECTOR 3 DW ALV13 ;ALLOCATION VECTOR 3 MXDSK EQU ((OFFSET $) -(OFFSET DPBASE))/16 EJECT ;----------------------------------------------------------- ; EAGLE II FORMAT ; ; 1024 BYTES PER SECTOR ; 5 SECTORS PER TRACK ; 80 TRACKS PER DRIVE ; DOUBLE DENSITY ;----------------------------------------------------------- DPBK1 DW 40 ;SECTORS PER TRACK DB 4 ;SHIFT FACTOR DB 15 ;BLOCK MASK (2048 BLOCK SIZE) DB 01 ;NULL MASK DW 194 ;DISK SIZE - 1 DW 191 ;DIRECTORY MAX  DB 0E0H ;ALLOC 0 DB 0 ;ALLOC 1 DW 48 ;CHECK SIZE DW 2 ;TRACK OFFSET ; DB 7 ;SECTOR MASK DB 3 ;SECTOR SHIFT FACTOR DB 0 ;TRACK / HEAD METHOD DB 1 ;READ SIZE DW E96_BASE DW EXLT ;TRANSLATION TABLE ;----------------------------------------------------------- ; EAGLE III - EAGLE 1600 FORMAT ; ; 1024 BYTES PER SECTOR ; 5 SECTORS PER TRACK ; 160 TRACKS PER DRIVE ; DOUBLE DENSITY ;----------------------------------------------------------- DPBK2 DW 40 ;SECTORS PER TRACK DB 4 ;SHIFT FACTOR DB 15 ;BLOCK MASK (2048 BLOCK SIZE) DB 0 ;NULL MASK DW 394 ;DISK SIZE - 1 DW 191 ;DIRECTORY MAX DB 0E0H ;ALLOC 0 DB 0 ;ALLOC 1 DW 48 ;CHECK SIZE DW 2 ;TRACK OFFSET ; DB 7 ;SECTOR MASK DB 3 ;SECTOR SHIFT FACTOR DB 0 ;TRACK / HEAD METHOD DB 1 ;READ SIZE DW E96_BASE DW EXLT ;TRANSLATION TABLE ; ; EAGLE TRANSLATION TABLE ; EXLT EQU $ ;TRANSLATION VECTOR ;COMMON TO ALL EAGLE DISKETTES DB 0,2,4,1,3 ;----------------------------------------------------------- ; EAGLE 48TPI SINGLE SIDED FORMAT (FOR FEAR) ; ; 1024 BYTES PER SECTOR ; 5 SECTORS PER TRACK ; 40 TRACKS PER DRIVE ; DOUBLE DENSITY ;----------------------------------------------------------- DPBK3 DW 40 ;SECTORS PER TRACK DB 4 ;SHIFT FACTOR DB 15 ;BLOCK MASK (2048 BLOCK SIZE) DB 01 ;NULL MASK DW 94 ;DISK SIZE - 1 DW 63 ;DIRECTORY MAX DB 080H ;ALLOC 0 DB 0 ;ALLOC 1 DW 16 ;CHECK SIZE DW 2 ;TRACK OFFSET ; DB 7 ;SECTOR MASK DB 3 ;SECTOR SHIFT FACTOR DB 0 ;TRACK / HEAD METHOD DB 1 ;READ SIZE DW E48_BASE DW EXLT ;TRANSLATION TABLE ;----------------------------------------------------------- ; EAGLE 48TPI DOUBLE SIDED (1200) ; ; 1024 BYTES PER SECTOR ; 5 SECTORS PER TRACK ; 80 TRACKS PER DRIVE ; DOUBLE DENSITY ;----------------------------------------------------------- DPBK4 DW 40 ;SECTORS PER TRACK DB 4 ;SHIFT FACTOR DB 15 ;BLOCK MASK (2048 COPYRIGHT (C) 1982, DIGITAL RESEARCH [], ERROR: $, LOAD ADDRESS $DISK WRITE$DISK READ$INSUFFICIENT MEMORY TO CREATE CMD FILE $LOAD ADDRESS $ERROR ADDRESS $BYTES READ:$RECORDS WRITTEN $ABSCANNOT OPEN SOURCE$CMDNO MORE DIRECTORY SPACE$CANNOT CLOSE FILE$kk3ȎЎ؎tȎмY&_tUWV]^_]]&ωH2_MKLS)r 6rÊٷ.v<uUpSgArfcY_kPQ_`266>YXQ!Q$YPQ`2>>YX  û u%? rPX< t< t < t<t< à u$t <u <t2à uQYQYQ>tY<t< s t<u< uÊ{s P^Y@ u $u #:s u n i<$tAQY&CSQS[Y< u< t<u t͠Q<u t&K|<u QS<u<u[:sG<uK[~<u5Q?Y[SQ tC&QS[YS t* uC&QS[Y&<u <u؎m:s,[&/ ؎bD ?t uLD0? u0!  ËÎS DB 'K' ;ERASE IN LINE. ESC [ code K DW AEOL DB 'm' ;SPECIAL VIDEO MODE ESC [ code m DW AMODE DB 's' ;SAVE CURSOR POSIT ESC [ s DW VSAVCUR DB 'u' ;MOVE CURSOR TO SAVED ESC [ u DW VRSTCUR ENDANSI DB 00 ;END OF TABLE DW VIDASCII ; ; ; MEMORY REGION TABLE ; MRT DB 01 ;ONE REGION MRTSTART RW 1 ;START AVAILABLE RAM MRTLEN RW 1 ;LENGTH AVAILABLE RAM PSSS DW 0 ; PSSP DW 0 ; ; ; USER BREAK INTERRUPT VARIABLES ; BRKFLAG DB FALSE ;PREVENT REENTRY ; SPBREAK  RW 1 SSBREAK RW 1 ; BREAKMES DB ' *** User Program Break ***' DB ' Return to CP/M (Y/N)?',0 ; ; DIVIDE BY ZERO ERROR MESSAGE ; ZEROMES DB ' *** User Divide by Zero ' DB 'Error *** Type any key ' DB 'to continue.',0 ; ; TIMER INTERRUPT VARIABLES ; SPSAVE RW 1 ;SAVE STACK POINTER SSSAVE RW 1 ;SAVE STACK SEGMENT ; TIMERCOUNT DB -1 ; CMONTH DW '99' ;INITIALLY IMPOSSIBLE CDAY DW '99' CHOUR DW '99' CUSER DB 99 ; TIMEMSG DB ' User ' BUSER RW 1 DB ' ' BMONTH DB 'Dec' DB '. ' BDAY RW 1 DB ', ' BCENT DB '19' BYEAR RW 1 DB ' ' BHOUR RW 1 DB ':' BMINUTE RW 1 DB ':' BSECOND RW 1 DB ' ' BAMPM DB 'pm' DB ' ' BSYSMES RB 14 DB 0 ; MONTHNAMES DB 'JanFebMarAprMayJun' DB 'JulAugSepOctNovDec' ; MONTHLENGTH DW '32' FEBLENGTH DW '29','32','31','32','31' DW '32','32','31','32','31','32' ; ; ; ERROR MESSAGES ; ERRDISK DB 'Disk Error - Drive ' EDRIVE RB 1 DB ': ',0 ; DE81 DB 'Invalid format',0 DE80 DB 'No Response',0 DE40 DB 'Bad Seek',0 DE20 DB 'Disk Controller',0 DE10 DB 'Read Error',0 DE09 DB 'DMA Boundary',0 DE08 DB 'DMA Overrun',0 DE04 DB 'Sector Not Found',0 DE03 DB 'Write Protect',0 DE02 DB 'No Address Mark',0 DE01 DB 'Illegal Command',0 DE00 DB 'Unknown Error',0 ; ; TABLE MATCHING THE RETURN CODE WITH MESSAGE ; EDSKTBL DB 81H DW DE81 DB 80H DW DE80 DB 60H DW DE80 DB 40H DW DE40 DB 20H DW DE20 DB 10H DW DE10 DB 09H DW DE09 DB 08H DW DE08 DB 04H DW DE04 DB 03H DW DE03 DB 02H DW DE02 DB 01H DW DE01 EDSK_CNT EQU (OFFSET $ - OFFSET EDSKTBL)/3 DW DE00 ; ERRQUEST DB '. Retry, Ignore, Accept?',0 ; ERRCOUNT DB 80 ;NUMBER OF CHARACTERS ERRBUF RS 80 ;ERROR MESSAGE BUFFER ; ;----------------------------------------------------------- ; DISK PARAMETERS ;----------------------------------------------------------- DISK DB 0 ;SELECTED LOGICAL DISK SECTOR DB 0 ;SELECTED LOGICAL SECT TRACK DW 0 ;SELECTED LOGICAL TRACK DMAOFFSET DW 0 ;DMA ADDRESS OFFSET DMABASE DW 0 ;DMA ADDRESS SEGMENT DMAADDR EQU DWORD PTR DMAOFFSET VFLAG DB FALSE ;VERIFY AFTER WRITE ? SDISK DB 0 ;SECOND LEVEL DISK NUMBER SSECTOR DB 0 ;SECOND LEVEL SECTOR NUMBER STRACK DW 0 ;SECOND LEVEL TRACK NUMBER RSECTOR DB 0 ;PHYSICAL SECTOR WORK ; THE FOLLOWING 4 BYTES MUST REMAIN IN THIS ORDER FSECTOR DB 0 ;CONVERTED SECTOR FTRACK DB 0 ;CONVERTED TRACK NUMBER FDISK DB 0 ;CONVERTED DISK FHEAD DB 0 ;CONVERTED HEAD NUMBER UDISK DB 0 ;LAST UNALLOC DISK USECTOR DB 0 ;LAST UNALLOC SECTOR UTRACK DW 0 ;LAST UNALLOC TRACK UNACNT DB 0 ;UNALLOC REC CNT ERFLAG DB 0 ;ERROR REPORTING RSFLAG DB 0 ;READ SECTOR FLAG READOP DB 0 ;1 IF READ OPERATION WRTYPE DB 0 ;WRITE TYPE SYSWRT DB 0 ;"DIRTY" BUFFER FLAG SYSACT DB 0 ;SYSTEM BUFFER ACTIVE RETRY DB 0 ;RETRY COUNT ; WINCHESTER DRIVE INFOMATION BLOCK WDIB DB 17 ;SECTORS PER TRACK DB 2 ;SECTOR SHIFT SIZE  DW 512 ;SECTOR SIZE IN BYTES DW 340H ;PORT BASE ADDRESS DB 1 ;CONTROLLER BIT DB 0 ;DRIVE NUMBER DB -1 ;CURRENT LATCH SETTING DB 4 ;OPTION CODE (FAST SEEK) ; WINCHESTER DRIVE CONTROL BLOCK WDCB DB 0,0,0,0,0,0 ; CURRENT STATUS AREA WSTAT RB 6 ; WORK AREA DISK_CMD DB 0 DMA_CODE DB 0 COMMAND EQU WORD PTR DISK_CMD EJECT ; ; DRIVE A: DISK PARAMETER HEADER ; DPBASE EQU $ DPH0 DW 0 ;NO TRANSLATE TABLE DW 0,0,0 ;RESERVED DW DIRBUF ;DIRECð  ˻'QYÊ[ tP$&(ډA**,28J t 3&ËR E t߻oRWR62Rȋ6& ? YA 4P*OËـ>JtًȵRËR Ê4RTP"5 ؉RË úPڊN6"OG<u2PڠNù*2CQY á $Ë  9B$ ڊs t**VË Ë$;rBR+ӋZñW=sQOW.Yt :t s_È3(**~ûC:uûË9Cds䠦$QYV u QYLQZuR>JtQSQCS t7;r[CYҋ7Cˋ0C;0E$beMt;?t:u C,$uȢrѠFwQ.6""*$YËYFeuYJt u u:uGڋ;u3BCBCu¹هً:rهيC2C\t $t6""Ct $tuDt 2!"1GDtP:Nrut vZ"S[urg"_"HaGt ga`K$ȢH<sLM$À>a`uu3ۉ "N{->t db<bub>dtcKa`nnpt[>a`uG $uaL??t??t' PË"\0 ÉÀ>Kt$>a`uOM t LHc>_uBdos Err On : $Bad Sector$Select$File R/O$P<aagnvbddȎЎ؎Z$t t$$tt@A$6 uʰ:P 6\d>\u,Pt 6)HPg 9sP ]U\:Fu]UƋ^u \:u۰]U>\ t@ 9]Usx]UsP$P]]U>u>\u>t>v&PS #.PD5Ps$P9P{:vWQP"s:Pr[PPZP:_P2QP)?PoP6|PPPPPPPPPtS]U츺Pk ]U> wƇu\,uP> t@Y rP}LJ,Ps P 5>\ t@P>\,t@Y ss>\t P };r;vQ>usP~ Ƈ~>u ;vȀ>u +9w>uU>uC>u3>u#> u>@u%>u >v>t;wZ>uUuvHs_㋇)sP Ρ ,>u%% u@P;w@Y s8s]Xs]À>uxsP s.x;P IP6@P62MP"P8P<PXP\PvPzP]À> s P ]á+@r3 s!;P6 PR6PD A&;P >t 6P:P l PQ >t&&PP6P6 Ps>v @A&60 PAPA P6Q P6a Py>us 6r PY P6I Pp Pv6 P P  P>vs 6 PHP PhHP P\P PbP PW1P P26 P'! P6 % P sP ) P < P 661H9wl1 tj >tB >sg V PU ;r)u@s L P6 P P 1PX1 t6 T P k P6n o P 1P s P ]UF1v uFFFF]Uv6 P@ v6 v@ ]U;P ? vk :P 0 v  ]UC ;P  P - P P P P s:PO P P <wiÊsW QP^ s:P P6C Pz P61 s:P[ P6  PM u P  P) C P/ 3 P : P +> P F P P[ Ps ]Us  P ]U>wƇu9r84  o P>\ tnw PMs| X.  P P|+ Pp Pd 8 >\ t P+g]U1]UPFP]U P P]U Pv]Uv]UPv]UPv]UPv]UPv]UPv~]UPvn]UPv[]UPvK]U@v[]U9s]á@=vD>s0P\P_tƇЁ]US<u9S]UTTȢT5t#V58VwVVu7]U45W<u:PAW< t@P>Wt@Y sI>W u P2>W u PI4uW< r<t,a<s&W_6W!`W뙠45764]U4XwXƇXum?$u2X>Xw&Xƻm,AY<s ƇXuӀ>e u e򤸀P\P >u P$P Pw897|XX<wƇ:INT A MESSAGE ON THE STATUS LINE ;----------------------------------------------------------- PRNBOS: PUSH ES ;SAVE PUSH DI PUSH DX LES DI,DWORD PTR BOSOFF ;SET THE CURRENT ADDRESS MOV DX,BOSSTAT ;GET THE DEVICE ADDRESS PRNBOS1: IN AL,DX ;GET THE STATUST TEST AL,8 ;ARE WE IN VSYNC? JZ PRNBOS1 ;NO MOV AH,07H ;ATTRIBUTE PRNBOS2: LODSB ;GET THE BYTE OR AL,AL ;END? JZ PRNBOS3 ;YES STOSB ;PUT IT ON THE LINE MOV AL,AH ;ATTRIBUTE STOSB JMPS PRNBOS2 ;KEEP IT UP PRNBOS3: MOV BOSOFF,DI ;NEW POSITION POP DX POP DI POP ES RET ;ALL DONE ;----------------------------------------------------------- ; CLEAR THE MESSAGE LINE ;----------------------------------------------------------- CLRBOS: PUSH ES ;SAVE PUSH DI PUSH DX MOV DI,0F00H ;BOTTOM OF SCREEN MOV ES,BOSSEG ;SEGMENT MOV DX,BOSSTAT ;GET THE DEVICE ADDRESS CLRBOS1: IN AL,DX ;GET THE STATUST TEST AL,8 ;ARE WE IN VSYNC? JZ CLRBOS1 ;NO MOV AX,720H  MOV CX,160 CLRBOS2: STOSB XCHG AH,AL STOSB XCHG AH,AL LOOP CLRBOS2 POP DX POP DI POP ES RET ;ALL DONE ;----------------------------------------------------------- ; RESTORE FROM STATUS LINE ;----------------------------------------------------------- RSTBOS: CLI MOV BOSFLAG,FALSE ;CLEAR IN USE STI RET ;AND LEAVE ;----------------------------------------------------------- ; PRINT THE MESSAGE TO THE SCREEN ;----------------------------------------------------------- PRNMSG: MOV CL,[SI] ;GET A BYTE OR CL,CL ;IS IT NULL? JZ PRNMSG_RET ;YES INC SI PUSH SI CALL COUT ;OUTPUT THE MESSAGE POP SI JMP PRNMSG PRNMSG_RET: RET ;NOW LEAVE ; CODETOP EQU OFFSET $ ; EJECT ; ; *** DATA AREA *** ; DSEG ; ORG CODETOP EPROM DB 0 ;EPROM VERSION NUMBER IOBYTE DB 0 ;IOBYTE - NOT USED DOSEL DW 0 ;FORCE SELECT PROCESS DRIVES DW 0 ;ACTIVE DRIVES WDRIVES DW 0 ;WINCHESTER DRIVES LPT_CHAR DB 0 LPT_LINES DB 0 ; ; FUNCTION KEY DEFINITIONS ; DW PFKTABLE ;TABLE ADDRESS DW PFKBASE ;TABLE SIZE DW PFKSIZE ;NUMBER OF KEYS PFKSCAN DB 59,60,61,62,63,64,65,66,67,68 DB 71,72,73,75,77,79,80,81,82,83 DB 84,85,86,87,88,89,90 DB 91,92,93,94,95,96,97 DB 133,134 DB -1 PFKSIZE EQU OFFSET $ - OFFSET PFKSCAN PFKTABLE DB 'DIR A:',CR,0,'............' ;F1 PFKBASE EQU OFFSET $ - OFFSET PFKTABLE DB 'DIR B:',CR,0,'............' ;F2 DB 'STAT',CR,0,'..............' ;F3 DB 'STAT B:',CR,0,'...........' ;F4 DB 'PIP',0,'................' ;F5 DB 'PIP B:=A:*.*[V]',0,'....' ;F6 DB 'STAT *.*',CR,0,'..........' ;F7 DB 'STAT B:*.*',CR,0,'........' ;F8 DB 'ASSIGN',CR,0,'............' ;F9 DB 'DISKUTIL',CR,0,'..........' ;F10 ; DB ESC,'H',0,'.................' ;HOME DB ESC,'A',0,'.................' ;UP ARROW DB ESC,'I',0,'.................' ;PAGE UP DB ESC,'D',0,'.................' ;CURSOR LEFT DB ESC,'C',0,'.................' ;CURSOR RIGHT DB 1AH,0,'..................' ;END DB ESC,'B',0,'.................' ;CURSOR DOWN DB 0AH,0,'..................' ;PAGE DOWN DB ESC,'L',0,'.................' ;INSERT DB 7FH,0,'..................' ;DELETE ; DB 0,'...................' ;F11 DB 0,'...................' ;F12 DB 0,'...................' ;F13 DB 0,'...................' ;F14 DB 0,'...................' ;F15 DB 0,'...................' ;F16 DB 0,'...................' ;F17 DB 0,'...................' ;F18 DB 0,'...................' ;F19 DB 0,'...................' ;F20 DB 0,'...................' ;F21 DB 0,'...................' ;F22 DB 0,'...................' ;F23 DB 0,'...................' ;F24 DB 0,'...................' ;ENHANCE DB 'HELP',CR,0,'..............' ;HELP DELTAVEC RW 1 ;FOR CHANGING VECTORS DELTALO RB 1 DB 0 ;HIGH ORDER OF CHANGE ; ; CHARACTER I/O BRANCH TABLES ; INROUTINES DW KEYIN ;KEYBOARD DW KEYIN ;COVER SCREEN DW SPIN0 ;SERIAL PORT #0 DW SPIN1 ;SERIAL P  ƇB XuƇ:$ P]]U>H u GNHoDPw]U8r38EPvV4*^ZZt P ?P]U~tv]U4:5r9s]Ê44]U^]s]\>\uZ>[ t>[u[4s\&s\>['u \[\9s P런r>[t2[^_È^v>\u]]ø P^[ [>\u>[$ts]뗀>\t >[$u[>s݀>[Ot>[Qu >[Hu>t[$>Bu ^>Du^ :^wvȴÊ_t+袀sr@s\u>\u P\].>\u%>['u [<'t]À>[ u ! PZ]]Q]U[,0< v@]U[APv@Y ]U[,A<v@]UPY ]U[\]]UPP8]U\. >ltlPYP>u2 P6]U졆HrsF]Ut PBPX>u] P]U P| Pv]U Pk]U,P`]UF0PR]U;PE]UF t[F 1 1>t@"FPw@Y"FsFs P6F 1F]U~ v F, AFF0v]UFPF$P]UFPFP]UvhPs]UFPPPdP]UvPP'P]UvPP'P]U7sE6s]6>5u]ð;P:5sȴW]U^?$t 7F]UvFPPPdPg]U)v]Uv]U> s;Pnv]Uq P]Ut P]Uv]Uv]Uvv]Uvv]U>\t>\u]À>\u>_;u >_ t_\]À>^v]Ê^㋇x Ê^ \>t[^w@˷_֋P:t@Y"sʈǂ>u]\^\]U[:Ft@s[] Error(s)$@  @?End-File$offset $bad val$dpbase$equ$Base of Disk Parameter Blocks$dpe$xlt$Translate Table$Scratch Area$dirbuf,$dpb$Dir Buff, Parm Block$csv$alv$Check, Alloc Vectors$range $equ$ diskparm$delimit$missing$numeric$duplic  BOUNDS MOV AH,3 ;WILL NOW READ THE CURSOR. INT 10H ;AND PRESERVE THE POSITION POP CX ;RECALL SCREEN BOUNDS PUSH DX ;SAVE CURRENT CURSOR XOR DX,DX ;WILL SET CURSOR POSITION TO [0,0] ;-------------------------------------------------------------------------- ; POSITION CURSOR, READ THE CHARACTER ; PRINT THE CHARACTER THEN BUMP CURSOR ;-------------------------------------------------------------------------- PRS10: MOV AH,2 ;TO INDICATE CURSOR SET REQUEST INT 10H ;NEW CURSOR POSITION ESTABLISHED MOV AH,8 ;TO INDICATE READ CHARACTER INT 10H ;CHARACTER NOW IN [AL] OR AL,AL ;SEE IF VALID CHAR JNZ PRS15 ;JUMP IF VALID CHAR MOV AL,' ' ;MAKE A BLANK PRS15: CALL PS_OUT INC DL ;ADVANCE TO NEXT COLUMN CMP CL,DL ;SEE IF AT END OF LINE JNZ PRS10 ;IF NOT PROCEED ; NEW LINE XOR DL,DL ;BACK TO COLUMN 0 MOV AH,DL ;[AH]=0 CALL PS_CRLF ;LINE FEED CARRIAGE RETURN INC DH ;ADVANCE TO NEXT LINE CMP CH,DH ;FINISHED? JNZ PRS10 ;IF NOT CONTINUE ; END OF SCREEN POP DX ;RECALL CURSOR POSITION MOV AH,2 ;TO INDICATE CURSOR SET REQUEST INT 10H ;CURSOR POSITION RESTORED MOV AX,PS_SEG MOV DS,AX MOV PS_STATUS,0 ;INDICATE FINISHED PS_EXIT: CLI POP ES POP DI POP SI POP DX ;RESTORE ALL THE REGISTERS USED POP CX POP BX MOV SS,CS:PSSS ;RESTORE USER STACK MOV SP,CS:PSSP PS_EXIT1: POP AX ;RESTORE AX POP DS IRET ;----------------------------------------------------------- ; CARRIAGE RETURN, LINE FEED SUBROUTINE ;----------------------------------------------------------- PS_CRLF: MOV AL,CR CALL PS_OUT MOV AL,LF CALL PS_OUT RET ;----------------------------------------------------------- ; COMMON OUTPUT ROUTINE FOR PRINT SCREEN ;----------------------------------------------------------- PS_OUT: PUSH BX PUSH CX PUSH DX MOV CL,AL CALL LSTOT POP DX POP CX POP BX RET EJECT ;----------------------------------------------------------- ; SETUP THE SYSTEM INFORMATION ;----------------------------------------------------------- SETSYS: MOV AL,CRT_SPD ;GET THE SPEED FLAG MOV AH,16 INT 10H ;DO IT MOV AH,15 INT 10H ;GET THE CURRENT STAT MOV CX,0607H ;ASSUME COLOR CMP AL,3 ;IS IT? JZ SETSYS1 ;YES MOV CX,0B0CH ;BLACK AND WHITE SETSYS1: CMP CRT_CURSOR,0 ;IS IT DASH OR BLOCK? JZ SETSYS1A ;DASH SUB CH,CH ;BLOCK SETSYS1A: MOV CURTYPE,CX ;SAVE IT FOR LATER MOV AH,1 ;DO IT INT 10H ; MOV BX,OFFSET SER0 ;POINT TO FIRST SERIAL PORT MOV DX,0 ;FIRST LOGICAL NUMBER MOV CX,MAXSER ;SET THE COUNT SETSYS2: MOV AL,CNTL[BX] ;GET THE CONTROL OR AL,AL ;IS IT ZERO JZ SETSYS2A ;YES MOV AH,0 ;INIT CODE INT 14H SETSYS2A: ADD BX,SERSIZE ;POINT TO NEXT INC DX ;BUMP LOGICAL LOOP SETSYS2 ;CONTINUE ; SEND THE LPT INIT STRING SETSYS3: CALL LISTAT ;CHECK IF PRINTER READY OR AL,AL JZ SETSYS6 ;NOT READY, DONT BOTHER MOV BX,OFFSET LPT_INIT ;YES, TRY TO DO IT SETSYS4: MOV CL,[BX] ;GET THE CHARACTER OR CL,CL JZ SETSYS6 ;ALL DONE INC BX PUSH BX ;SAVE THE POINTER CALL LSTOUT ;PUT IT OUT THE DOOR POP BX ;RESTORE JMPS SETSYS4 ;CONTINUE ; ALL DONE (I HOPE) SETSYS6: RET EJECT ;----------------------------------------------------------- ; SPECIAL DRIVERS TO DISPLAY BOTTOM LINE ; WE NEED TO DO THIS BECAUSE THE USUAL VIDEO ; DRIVERS ARE NOT RECURSIVE ;----------------------------------------------------------- SETBOS: CLI ;JUST IN CASE MOV AX,TRUE XCHG AX,BOSFLAG STI PUSH ES ;SAVE IT FOR NOW PUSH BX MOV AX,EPROM_SEG MOV ES,AX MOV AX,ES:CRT_BASE ;GET THE ADDRESS MOV BX,0B000H ;ASSUME SEGMENT CMP AX,3B4H ;IS IT B&W? JZ SETBOS1 ;YES MOV BX,0B800H ;NO, COLOR SETBOS1: ADD AL,6 ;STATUS REGISTER MOV BOSSTAT,AX ;SAVE IT MOV BOSSEG,BX ;SAVE IT MOV BOSOFF,0F00H ;BEGINNING OF SCREEN POP BX POP ES RET ;ALL DONE ;----------------------------------------------------------- ; PR  $Alloc $no disk$Disk $ is the same as Disk $dpb$Equivalent Parameters$als$Same Allocation Vector Size$css$Same Checksum Vector Size$xlt$Same Translate Table$too few$Disk $ is CP/M 1.4 Double Density Compatible$65536$128 Byte Record Capacity$Kilobyte Drive Capacity$32 Byte Directory Entries$Checked Directory Entries$Records / Extent$Records / Block$Sectors / Track$Reserved Tracks$Sector Skew Factor$dpb$equ$Disk Parameter Block$Sectors Per Track$Block Shift$Block Mask$Extnt Mask$1.4 Compatible$Disk Size - 1$Directory Max$Alloc0$Alloc1$Check Size$Offset$xlt$equ$No Translate Table$Translate Table$als$equ$Allocation Vector Size$css$equ$Check Vector Size$ds$rs$Uninitialized Scratch Memory Follows:$begdat$equ$Start of Scratch Area$dirbuf$Directory Buffer$alv$als$Alloc Vector$csv$css$Check Vector$enddat$equ$End of Scratch Area$datsiz$equ$-begdat$Size of Scratch Area$Marks End of Module$program$No Stmt$ maclib$ macpar$ disks$ diskdef$extra $ DISKDEF Table Generator, Vers 1.0 $DEF No Input File Present, Command Form is: GENDEF x $ Where x.DEF Holds Disk Definitions With Optional Parameters : C: Create Diskdef Comment O: Generate Offset-Relative Labels Z: Z80, 8080, or 8085 (else 8086, 8088) x.LIB is Created Upon Completion. $Premature End-of-File$Length $Convert$Quote $ LIBno ".LIB" directory space$".LIB" disk full$cannot close ".LIB"$dw$db$ DISKSENDEFMACLIBDISKDEF]UX PPPw_ PPPi^7^G  > w$ s _ P_.  uո_ PX PJv]U^G$ࢧ o/G]UP^OʉRPY"PQ^OʉX ˆGP^']UO AP:P]U]U츐 PFPdP]U^]U$PrPPe(;v!&(+9&w$P&s$]U*P Pm P**GP@*6* P P6* PP@P P P PP P P:02000085000079 :02000085000079 :040000030000038076 :1B03808131053F07F705440712129007490767076C0772077E078507EC034376 :1B039B810EDA0D640EDE0EE40E0F0F130F140F1D0F1E0F1F0F200F260F2C0FF8 :1B03B681330F4C09390F3F0F400F460F470F480F490F4A0F4B0F8B078B078777 :1B03D1810F880F890FF10332053B0545054605460546054605460546053005A6 :0B03EC81B022E99703BBA011E94A0B86 :1B0400810000000000001E8CC88ED88F069D1180F905740580F90D7205C60685 :1B041B81B111FF8C16941189269611803E98110174078CC88ED0BC59118B1E83 :1B04368196118E069411268B5F0481E300027401FB8CD85557560E078C065DF6 :1B04518110E81A005E5F5D8E065D10FA8E1694118B269611C606B111008E1E0D :1B046C819D11CF891699118816481032C0A39B11A25F10A24D10A24B10BB4CE3 :1B0487810F5380F929720980E90680F9367201C38AD9B7008ACA03DB2EFFA7E6 :1B04A2818003BB7610E819003C037555EB10BB8110EB08BB8D10EB03BB88101D :1B04BD81E80300E9700053E86701A0A4110441A27210B96610E8630159E85FE3 :1B04D88101E96B001E5051C6065F10FF880E601032ED8B3699118936A911BF72 :1B04F3819110893E99118E1E9D11FCF3A459581FC351B121EB0351B124E8CDEF :1B050E81FF59C30650518A0E601032ED8E069D11BE91108B3EA911893E9911D3 :1B052981FCF3A4595807C3C3C3C3C606981100E9C80C8916A2118BCAE8EF0C23 :1B054481C3C3C3BB1E108A07C607000AC07525E93F02E8EEFFE80A00721A505A :1B055F818AC8E8930058C33C0D740E3C0A740A3C0974063C0874023C20C3A051 :1B057A811E100AC0751EE81702240174F1E80B023C13750DE804023C03740365 :1B05958132C0C3E998FFA21E10B001C3A01B100AC0751651E8CDFF5951E8EEAC :1B05B081015951803EB611007403E8D301598AC1BB1D103C7F7416FE073C201A :1B05CB817310FE0F8A070AC074088AC13C087503FE0FC33C0A75FBC60700C310 :1B05E6818AC1E87BFF730A50B15EE8AEFF5980C94080F90975A5B120E8A0FF85 :1B060181A01D10240775F4C3E80500B120E88E01B108E98901B123E886FFE8AF :1B061C811000A01D103A061C1073E1B120E875FFEBF0B10DE86EFFB10AE9697D :1B063781FF8BF1AC3C2474C941518AC81E161FE8AEFF1F59EBEBA01D10A21CBE :1B065281108B1E9911268A0F4353B5005153E8E4FE5B593C0D7503E9C6003CD1 :1B066D810A74F93C08750E0AED74E6FECDA01D10A21B10EB513C7F750C0AED8E :1B06888174D4268A07FECD4BEB7C3C05750C5153E893FFC6061C1000EBBE3C9D :1B06A381107506 FLOW AND SET CARRY IF NO OVERFLOW ; ADDECIMAL: MOV AL,[BX] INC AL DAA ;+1 DECIMAL CMP AL,AH JC ADDEC1 ;SKIP NO OVERFLOW SUB AL,AL ;ELSE RESET, CLC ADDEC1: MOV [BX],AL ;RESTORE COUNT DEC BX ;FOR NEXT TIME RET ; ; ADD ONE TO AN ASCII NUMBER ; ENTRY: BX -> ASCII VALUE ; CX = OVERFLOW RESET VALUE ; DX = ONE TOO MANY ; IF NO OVERFLOW, THEN ROUTINE SKIPS ITS RETURN ; AND JUMPS STRAIGHT TO TIMINT3 ; INCASCII: MOV AX,[BX] XCHG AL,AH ;SO THAT AH = MSB INC AL AAA ;INC AH ON CARRY OR AX,'00' ;BACK TO ASCII CMP AX,DX ;CHECK OVERFLOW JC INCA1 ;SKIP IF NONE ; XCHG CL,CH MOV [BX],CX ;ELSE RESET VALUE XCHG CL,CH ;RESTORE CX SUB BX,3 ;FOR NEXT TIME RET INCA1: XCHG AL,AH ;BACK TO BACKWARDS MOV [BX],AX ;RESTORE COUNT POP AX ;CLEAR THE RETURN JMP TIMINT3 ;STRAIGHT TO UPDATE ; ; ADJUST MONTH LENGTH TABLE FOR LEAP YEAR ; LEAP: MOV AX,AYEAR ;FETCH ASCII YEAR CALL ASCIINUM ;CHANGE TO A NUMBER TEST AL,AL  ;CHECK FOR 0 JZ LEAP1 ; TEST AL,03H ;DIVISIBLE BY 4? JNZ LEAP1 ;IF NOT, SKIP ; MOV FEBLENGTH,'30' ;FEB LEAP YEAR + 1 RET LEAP1: MOV FEBLENGTH,'29' ;NOT LEAP YEAR + 1 RET ; ; CONVERT AN ASCII NUMBER TO BINARY ; ASCIINUM: AND AX,0F0FH ;MASK THE TOP NIBBLES XCHG AL,AH ;AL = LSB AAD ;THAT DOES IT RET ; ; BLANK ASCII LEADING ZERO IN AL ; EXIT: CARRY AND ZERO SET IF BLANKED ; LZBLANK: CMP AL,'0' JNZ LZB1 MOV AL,' ' STC LZB1: RET ;----------------------------------------------------------- ; DIVIDE BY ZERO ERROR TRAP INTERRUPT ; TRASHES REGISTERS AND RETURNS TO BDOS ;----------------------------------------------------------- ZEROINT: MOV AX,CS MOV DS,AX CALL SETBOS CALL CLRBOS MOV SI,OFFSET ZEROMES CALL PRNBOS CALL BEEP CALL CIN ;GET IT ABORT: CALL CLRBOS CALL RSTBOS ;RESET BOTTOM OF SCREEN MOV CL,0 ;RESET CODE MOV DL,0 ;FREE MEM INT 0E0H ;BACK TO BDOS EJECT ;------------------------------------------------------------------------ ; PRINT SCREEN INTERRUPT ; ; THIS LOGIC WILL BE INVOKED BY INTERRUPT 05H TO PRINT ; THE SCREEN. THE CURSOR POSITION AT THE TIME THIS ROUTINE ; IS INVOKED WILL BE SAVED AND RESTORED UPON COMPLETION. THE ; ROUTINE IS INTENDED TO RUN WITH INTERRUPTS ENABLED. ; IF A SUBSEQUENT 'PRINT SCREEN' KEY IS DEPRESSED DURING THE ; TIME THIS ROUTINE IS PRINTING IT WILL BE IGNORED. ; ; ADDRESS 50:0 CONTAINS THE STATUS OF THE PRINT SCREEN: ; ; 50:0 = 0 EITHER PRINT SCREEN HAS NOT BEEN ; CALLED OR UPON RETURN FROM A CALL ; THIS INDICATES A SUCCESSFUL OPER. ; ; = 1 PRINT SCREEN IS IN PROGRESS ; ;------------------------------------------------------------------------- PRINT_SCREEN: PUSH DS PUSH AX ;SAVE AX MOV AX,PS_SEG MOV DS,AX MOV AL,1 XCHG AL,PS_STATUS OR AL,AL JNZ PS_EXIT1 ;JUMP IF PRINT ALREADY IN PROGRESS ; CORRECT POSSIBLE PROBLEM MOV AL,0BH ;LOOK AT IN SERVICE REGISER OUT INTC0,AL ;LOOK AT THE CONTROLLER IN AL,INTC0 AND AL,2 ;KEYBOARD INTERRUPT IN SERVICE JZ PS_GO MOV AL,EOI OUT INTC0,AL ;YES, CLEAR IT PS_GO: MOV CS:PSSS,SS MOV CS:PSSP,SP MOV AX,CS MOV SS,AX MOV SP,OFFSET PS_STACK ;USE OUR OWN STACK STI ;MUST RUN WITH INTERRUPTS ENABLED PUSH BX PUSH CX ;WILL USE THIS LATER FOR CURSOR PUSH DX ;WILL HOLD CURRENT CURSOR POSITION PUSH SI PUSH DI PUSH ES PUSH CS ;ADDRESSABILITY POP DS MOV AH,15 ;WILL REQUEST THE CURRENT SCREEN INT 10H ; [AL]=MODE ; [AH]=NUMBER COLUMNS/LINE ; [BH]=VISUAL PAGE ;-------------------------------------------------------------------------- ; AT THIS POINT WE KNOW THE COLUMNS/LINE ARE IN [AX] AND THE ; THE PAGE IF APPLICABLE IS IN [BH]. THE STACK HAS DS,AX,BX, ; CX,DX PUSHED. [AL] HAS VIDEO MODE ; ;-------------------------------------------------------------------------- MOV CL,AH ;WILL MAKE USE OF [CX] REGISTER TO MOV CH,CRTROW ;CONTROL ROW & COLUMNS PUSH CX ;SAVE SCREEN F616B611EBB23C1875145BA01C10BB1D10903A07739190FE71 :1B06BE810FE847FFEBED3C157507E84BFF5BE97EFF3C12753551E83FFF595BA8 :1B06D98153510AED740F43268A0FFECD5153E8FCFE5B59EBED53A01B100AC0A0 :1B06F48174102A061D10A21B10E809FFFE0E1B1075F7EB9843268807FEC5519A :1B070F81538AC8E8D1FE5B59268A073C038AC5750B3C0175078CD88EC0E96DB8 :1B072A81FE3AC17303E92CFF5B26882FB10D8CD88EC0E962FEE814FEEB44E8AE :1B074581CE0AEB3F8AC1FEC07409FEC0754CE84400EB30E83F000AC07503E978 :1B0760811508E83000EB21E8CF0AEB1C8BCAE8CB0AC38BCA1E8E1E9D11E8BCAE :1B077B81FE1FC38E069D11E9C8FEE8F1FDA29B11C3B001EBF8BB0F12EB0DBB07 :1B0796810912EB08BB0612EB03BB0C12FFD3C3FFD3CBBB0610FF2751B5008B65 :1B07B181F28BFBFCF3A459C38A0EA411E85B0A83FB0074508B1783C302891E18 :1B07CC81241083C302891E261083C302891E281083C30287DA891E41108B1EC7 :1B07E7812A10891EAD11BB2A10B108E8B8FF8B162C10BB3210B10FE8ACFFA0BD :1B0802813810BB4A10C607FF0AC07403C60700B0FF0AC0C3E8FF0933C08B1E5B :1B081D8126108907C38B165210E8FE09EB078A0E4510E8F8090AC074DFBB0420 :1B08388110E96FFF8B1EA611B102D3EB891E5210891E5710A15210BA0000F721 :1B085381363210528BC88B362610890C030E3F10E8B809598B164110E8C20959 :1B086E818BCBE9AE09BB34108A0FA05010D2E88AE8B1072A0FA04F10D2E00290 :1B088981C5C38B1E991183C31003D9803E4A100074058A1FB700C303D98B1F8C :1B08A481C3E8CBFF8AC8B500E8DCFF891E5210C38B1E52100BDBC38A0E34101D :1B08BF818B1E5210D3E3891E5410A05010220635100AD8891E5210C38B1E9974 :1B08DA811183C30C8A07C3BA0F0003169911BB110003DAC3E8F0FF8A07A25079 :1B08F5811087DA8A07A24E10E8D7FFA036102207A24F10C3E8D5FFA047103CE5 :1B09108102750232C002065010880787DAA04E108807C3B980008B1E2A1032EA :1B092B81C0020743E2FBC3518A0EA411BB0100D3E3590BD9C3A120108A0EA467 :1B09468111D3E82401C38B0E2010E8DFFF891E20108B163910428B1E24108969 :1B09618117C3E81B00BA090003DA8A07D0D0731BBB0A10EB08E8C7FF7411BB08 :1B097C810810E92AFE8B1E2A10A05610B40003D8C38B1E991183C30E8A07C380 :1B099781E8F3FFC60700C3E8ECFF0C808807C38B16A6118B1E24103B17C3E877 :1B09B281F2FF72FA428917C3522BD38BDA5AC3B1FF8B1657108B1E3D10E8EC53 :1B09CD81FF73E051E84FFF8B1E5710031E2E1059FEC1740D3A07740BE8BEFF48 :1B09E8817306E85FFFC38807C3E8CDFFE81900B101E833FEEB06E80F00E81E31 :1B0A0381FE8B0EA211E82808BBA011EB088CD9E81E08BB2A108B0FE907088B11 :1B0A1E81162A108B1EA011B180068E069D11E87EFD07C3BBA6118A07433A0765 :1B0A39817502FEC0C3BBFFFF891EA611C38B1639108B1EA61143891EA611E87C :1B0A548164FF7302EBE4A0A611240351B105D2E059A256100AC0750B51E8CC78 :1B0A6F81FDE88BFF59E94CFFC3E806FF83C31051B1115AFEC97501C352803E6C :1B0A8A814A1000740851538A0FB500EB07FEC9518B0F43530BC974088B1E379E :1B0AA581103BD972005B4359EBD28B1E3710B103D3EB438BCB8B1E3010C607BA :1B0AC0810043E2FA8B163B108B1E30108917E845FD8B1E2410C7070300E862E4 :1B0ADB81FFB1FFE865FFE84DFF743BE898FE803FE574EEA0A5113A07750C43C2 :1B0AF6818A072C247505FEC8A29B11B101E872FFE8A8FEEBD1A04610E977FC4E :1B0B1181518A2E3610F6D522CD22C52AC1241F59C38B1E9911891E5910C606DF :1B0B2C814610FF880EA811C3E8EBFFE804FFE8D9FCC606651000B100E8FFFE75 :1B0B4781E8E7FE7503E980008B1659108BF2AC3CE5740752E848FE5A73EBE875 :1B0B62811DFE8A0EA811B5000AC974388BF2AC3C3F742980FD0D742480FD0C6B :1B0B7D8174082A07247F7533EB17518A0FE884FF599FF6066510FF7545C6069F :1B0B98816210009E759F4243FEC5FEC9EBC4C606461000A0A6112403A29B11F1 :1B0BB3818AE8FEC5C30AED7530F607FF752BF6066210FF7424C6066510FFEB46 :1B0BCE81CFE86CFEB0FF8AE8FEC5E9ADFB9E750E43803F0075088B36A6118954 :1B0BE981366310E94EFFB100B22052B5008B16991103D1E882FD59E8AAFBE8B3 :1B0C048136FCE9E8FDC3B10CE825FFE81FFE74F5B100B20CE8D8FFE81FFFEB3B :1B0C1F81EFB10FE80FFFE809FE74DFE8AAFC5053E84FFD87DA8B1E9911B12068 :1B0C3A8152E86FFBE85DFD5ABB0C0003DA8A0FBB0F0003DA8A2F5B5888073AC5 :1B0C55810F8AC57406B0007202B0808B1E9911BA0F0003DA8807C3833F007555 :1B0C7081FA8BF2AD8907C333C0A29B11A3A611E8BEFC75F2E806FD248075EBDE :1B0C8B81B10FE8A4FEE89EFD74E1B91000E8E6FC03D987DA8B1E991103D9B1FB :1B0CA68110803E4A1000741B8A070AC08BF2AC750288070AC075068A078BFA16 :1B0CC181FCAA3A077547EB16E8A0FF87DAE89BFF87DA8BF28B043B07753342F0 :1B0CDC8143FEC94243FEC975C2B9ECFF03D987DA03D98BF2AC3A0772118807B6 :1B0CF781B9030003D987DA03D98A078BFAFCAAC6064310FFE9F5FEFE0E9B111E :1B0D1281C332C0A24310E85 N SIGNON ; CONSUMES ABOUT 6 SEC PER HOUR ; TIMERINT: DEC CS:TIMERCOUNT ;18 OR 19 PER SECOND JZ TIMINT1 IRET ;USUALLY RETURN ; ; COME HERE ONCE EVERY SECOND ; TIMINT1: PUSH AX PUSH DS MOV AX,CS ;GET THIS SEGMENT MOV DS,AX ;FOR STACK SAVE MOV SPSAVE,SP ;SAVE CURRENT STACK MOV SSSAVE,SS ; AND SEGMENT MOV SS,AX MOV SP,TIMESTACK ;SET UP LOCAL STACK PUSH BX PUSH CX PUSH DX PUSH BP PUSH SI PUSH DI PUSH ES ;AND PROMPTLY USE IT MOV ES,AX CLD ;FOR LATER MOV TIMERCOUNT,TICK ;RESET THE COUNT STI ;ENABLE INTERRUPTS ; ; INCREMENT RAM CLOCKS ; MOV BX,OFFSET DSECOND MOV AH,60H ;FOR OVERFLOW CALL ADDECIMAL JC TIMINT2 ;SKIP IF NO OVERFLOW CALL ADDECIMAL JC TIMINT2 MOV AH,24H ;FOR HOURS CALL ADDECIMAL TIMINT2: MOV CX,'00' ;OVERFLOW RESET VALUE MOV BX,OFFSET ASECOND MOV DX,'60' ;FOR OVERFLOW CHECK CALL INCASCII ; CALL INCASCII ;INCREMENT MINUTES ; MOV DX,'24' ;24 HOURS CALL INCASCII ;  CALL LEAP ;NEXT DAY, CHECK YEAR MOV CX,'01' ;OVERFLOW RESET VALUE MOV AX,AMONTH ;GET THIS MONTH CALL ASCIINUM ;CONVERT TO NUMBER DEC AX ;RANGE 0-11 ADD AX,AX ;2 BYTES PER MOV BX,AX MOV DX,MONTHLENGTH[BX] MOV BX,OFFSET ADAY CALL INCASCII ;NEXT DAY ; MOV DX,'13' ;MONTH TOO HIGH CALL INCASCII ;NEXT MONTH ; MOV CX,'00' ;OVERFLOW RESET VALUE MOV DX,':0' ;ASCII 100 MOV BX,OFFSET AYEAR CALL INCASCII ; MOV BX,OFFSET BCENT CALL INCASCII ;INTO THE NEXT CENTURY ; ; NOW SET UP BOTTOM LINE DISPLAY ; TIMINT3: MOV AX,ASECOND ;SIMPLE ONES FIRST MOV BSECOND,AX MOV AX,AMINUTE MOV BMINUTE,AX MOV AX,AYEAR MOV BYEAR,AX ; MOV AX,AMONTH CMP AX,CMONTH ;IF NEW MONTH JNZ TIMINT4 ; THEN FIX IT ; MOV AX,ADAY CMP AX,CDAY ;IF DAY AND MONTH SAME JZ TIMINT5 ; THEN SKIP IT TIMINT4: MOV AX,AMONTH MOV CMONTH,AX ;UPDATE CHECK COPY MOV AX,ADAY MOV CDAY,AX ;FOR DAYS TOO CALL LZBLANK ;ZAP LEADING ZERO MOV BDAY,AX ;BOTTOM LINE DAY ; MOV DI,OFFSET BMONTH MOV AX,AMONTH MOV CMONTH,AX ;UPDATE CHECK COPY ; RCR AL,1 ;CHECK MSB SBB AL,AL ;ALL ONES IF CARRY AND AX,0F0AH ;MASK AH, AL = 0 OR 10 ADD AL,AH ;AL = MONTH NUMBER MOV AH,AL ADD AL,AL ADD AL,AH ;AL = 3 * MONTH SUB AH,AH MOV SI,OFFSET MONTHNAMES - 3 ADD SI,AX MOV CX,3 REP MOVSB ;MONTH ABBREV TIMINT5: MOV AX,AHOUR CMP AX,CHOUR ;IF SAME, SKIP JZ TIMINT8 ; MOV CHOUR,AX ;UPDATE CHECK COPY MOV DX,'00' MOV CX,'12' XCHG AH,AL ;SWITCH AH = MSB CMP AX,CX ;CHECK AM/PM JB TIMINT6 ;SKIP IF AM ; MOV BAMPM,'p' JZ TIMINT7 ;IF 12, SKIP MINUS SUB AX,CX ;AMERICAN TIME AAS OR AX,DX ;BACK TO ASCII JMPS TIMINT7 ;DONE TIMINT6: MOV BAMPM,'a' CMP AX,DX JNZ TIMINT7 ;SKIP IF NOT ZERO MOV AX,CX ;IF ZERO, MAKE 12 TIMINT7: XCHG AL,AH ;BACK TO BACKWARDS CALL LZBLANK ;BLANK LEADING ZERO MOV BHOUR,AX ; ; GET USER NUMBER ; TIMINT8: MOV AL,BDOSUSER CMP AL,CUSER JZ TIMINT10 ;SKIP IF SAME ; MOV CUSER,AL ;UPDATE CHECK COPY SUB AH,AH AAA OR AX,'00' ;BACK TO ASCII XCHG AL,AH ;BACK TO BACKWARDS CALL LZBLANK ;BLANK LEADING ZERO JNC TIMINT9 ;SKIP IF NO BLANK XCHG AL,AH ;ELSE SWITCH BACK TIMINT9: MOV BUSER,AX ;THE BOTTOM LINE ; ; COPY SYSTEM BLOCK MESSAGE UP ; TIMINT10: MOV SI,OFFSET SYSMESSAGE MOV DI,OFFSET BSYSMES MOV CX,14 ;MESSAGE LENGTH REP MOVSB ; ; FINALLY UPDATE THE BOTTOM LINE ; CLI ;IN CASE CMP BOSFLAG,0 ;IS THE LINE TIED UP? JNZ TIMINT11 ;YES CALL SETBOS MOV AL,STATFLAG TEST AL,1 JZ TIMPRINT OR STATFLAG,81H ;SET IT TEST AL,80H JNZ TIMPRINT1 CALL CLRBOS JMPS TIMPRINT1 TIMPRINT: MOV SI,OFFSET TIMEMSG CALL PRNBOS ;PRINT THE MESSAGE TIMPRINT1: CALL RSTBOS TIMINT11: POP ES POP DI POP SI POP BP POP DX POP CX POP BX CLI ;FOR STACK SWITCH MOV SP,SPSAVE MOV SS,SSSAVE POP DS POP AX IRET ;BACK TO ROS ; ; ; ADD ONE TO A DECIMAL NUMBER ; OVER CFFE813FD74F28B1E991183C30C8A07FEC0241FC3 :1B0D2D818807740F8AE8A0361022C522064310740DEB1C83C302FE078A0724D4 :1B0D48810F741CB10FE8E4FDE8DEFC7507A04410FEC0740BE8CBFEE88CFB3226 :1B0D6381C0E921FAE822FAE931FCC606471001C6064410FFE874FBA050103A42 :1B0D7E81064E1072183C807528E889FFE854FB33C0A350108807803E9B1100FC :1B0D99817514E807FBE813FB740CE815FBE8A3FAE876FAE95AFBE9DAF98B1E5D :1B0DB48122108A0EA411D3CB5387DAE8F7F95B7503E8E0F9D0DB72678B0E2227 :1B0DCF8110E85FFB891E2210E9D5FCA04810A2A411EBD0E81FF7EB03E81FF7AF :1B0DEA818B1E9911C606611000F647088074098067087FC606611060C6064B79 :1B0E058110FF8B1E99118A07241FFEC8A248103C1E7312A0A411A24C108A0798 :1B0E2081A24D1024E08807E8B0FFA0A5118B1E99110807C3803E611060750787 :1B0E3B818B1E9911C60700C3F7060210FFFF75048C0E021033DB891E20108998 :1B0E56811E22108A1EB711881EA411E94EFFE87BFFE82DFB803EA51100740B4A :1B0E7181C7066410FE00C6066210FFE8A1FDE83C00F6066210FF7501C3C6064D :1B0E8C81621000813E6410FE0074F28B1E631080E3FC4B891EA611C606611060 :1B0EA781608B1E9911C60700B10FE86EFCE886FCE86EFDE80100C3E870FB74ED :1B0EC281C65B803E61106075128B1E99118A470A24807507A26110B0FFEB4C16 :1B0EDD81C3E801FFE993FDE81DF68B1E9D11891EAB11B1008B1E9911803F3F9E :1B0EF8817410E8DAF9803F3F7403E892FAE8E2FEB10FE827FCEB01C3E90AFB06 :1B0F1381C3E8CBFEE81AFFE950FEC3C3C38B1E2210EB1BA0A411E95CF889163B :1B0F2E81A011E9D1FA8B1E3010EB088B1E2010EB02C3C3891E9B11C3C3C3C33B :1B0F4981C3C3C3803E4B100074248B1E9911803E6110607504804F0880C60793 :1B0F648100A04D100AC0740B8807A04C10A24810E863FE803E5F10FF7503E851 :0C0F7F8190F5A19B118BD8C3C3C3C3C3E1 :02000086000078 :1B100082A5070000A404B004B504BA04000000000000000000000000000000D4 :1B101B8200000000E50000000000000000000000000000000000000000000053 :1B1036820000000000000000000000000000000000000000000000000000001D :1B10518200000000000000000000000000000000000000000042646F73204515 :1B106C827272204F6E20203A202442616420536563746F722453656C6563744D :0A1087822446696C6520522F4F2425 :0B1194820000000000000000000000CE :1B11A082000000000000000000000000000000000000000000000000000000B2 :0211BB820000B0 :0111C88200A4 :0211E08250003B :0111FA820072 :00000001FF 000000000000000000000000000D4 :1B101B8200000000E50000000.[.&YۜXӍ&0PV> 3 ȜX.[.&YP.Y.[.[..YUVN]U]U Pv]UPvZ]UPvZ]UPv]UPv]UPv]UPvpZ]UFȈFZu* P]U>v\P&t]ȴÊ< u&66<9v6055<9v 504,a<s&_]U9Pt@ P ]U2  r T <u@P> u@Y"r> t׀> $uI$ <$te ,0 < vz D > t  `rWs6 뇀> ^u,A <v PS P6 jπ> t@ 6 T2]U [ < t@P> t@Y s ]ð]U [ u ]U2@2=vQ PF2 <}vi P]U9P,Y9PP>Zu PzQ t3 ƇƇ$> t,  ø9P>Zu P(]U2H2Ê]001 $$$$ SUB DR0[DI],DL MOV DCB_ADR1[DI],AH MOV DCB_ADR2[DI],AL RET ;--------------------------------------------------------------- ; SEARCH THE ALTERNATE TRACK TABLE ; ENTER WITH AX = TRACK ; EXIT WITH AX = CORRECT TRACK ;--------------------------------------------------------------- CHECK_ALT: SUB DX,DX MOV BX,OFFSET ALTRK0 ;POINTER TO THE ALTERNATE TABLE CMP CTL[SI],1 ;FIRST CONTROLLER? JZ CHECK_ALT1 ;YES MOV BX,OFFSET ALTRK1 ;NO CHECK_ALT1: CMP [BX],DX ;IS THIS SLOT EMPTY  JZ CHECK_ALT_END ;YES, END OF SEARCH CMP [BX],AX ;IS THIS THE REQUEST TRACK? JZ CHECK_ALT_FND ;YES ADD BX,4 ;POINT TO NEXT JMPS CHECK_ALT1 CHECK_ALT_FND: MOV AX,2[BX] ;GET THE ALTERNATE TO USE CHECK_ALT_END: RET ; EJECT ;-------------------------------------------------------- ; DISK ERROR HANDLING ; ENTRY: AH = ERROR CODE ; EXIT: ZF = 1 FOR RETRY ; ZF = 0, CF = 0 FOR IGNORE ; ZF = 0, CF = 1 FOR ACCEPT ;-------------------------------------------------------- DISKERROR: CLD ;FOR LATER PUSH SI PUSH DI ;SAVE POINTERS MOV DL,AH ;SAVE CODE MOV AL,DISK ADD AL,'A' ;MAKE DRIVE NAME MOV EDRIVE,AL ;IN ERROR MESSAGE MOV SI,OFFSET EDSKTBL MOV CX,EDSK_CNT ;NUMBER OF CODES DSKERR1: LODSB ;GET THE CODE CMP AL,DL ;IS THIS IT? JZ DSKERR2 ;SKIP WHEN FOUND ; INC SI ;PAST MESSAGE OFFSET INC SI LOOP DSKERR1 ;UNKNOWN FALL THROUGH DSKERR2: MOV DX,[SI] ;DX -> SUB MESSAGE MOV SI,OFFSET ERRDISK ; ; ERROR HANDLING ROUTINE ; PRINTS MESSAGE, SUB MESSAGE, AND QUESTION ; ON THE BOTTOM LINE, AND GETS USER RESPONSE. ; ENTRY: SI -> ERROR MESSAGE ; DX -> SUB MESSAGE ; EXIT: ZF = 1 FOR RETRY ; ZF = 0 FOR IGNORE OR ACCEPT ; PUSH DX ;SAVE PUSH SI DSKWAIT: CMP BOSFLAG,0 ;INUSE? JNZ DSKWAIT ;YES CLI CALL SETBOS ;SET FOR BOTTOM OF SCREEN CALL CLRBOS POP SI ;GET THE ERROR MESSAGE CALL PRNBOS ;PRINT IT POP SI ;GET THE SUBMESSAGE CALL PRNBOS MOV SI,OFFSET ERRQUEST ;ASK THE QUESTION CALL PRNBOS ; DSKERR4: CALL BEEP CALL CIN ;GET THE INPUT CMP AL,CTRLC ;CONTROL C ? JZ DSKERR_B ;BACK TO BDOS AND AL,0DFH ;CONVERT UPPER CASE CMP AL,'R' ;RETRY ? JZ DSKERR_R CMP AL,'I' ;IGNORE ? JZ DSKERR_I CMP AL,'A' ;ACCEPT ? JNZ DSKERR4 ;INVALID RESPONSE STC ;FOR ACCEPT DSKERR_I: INC AX ;ZF = 0, IGNORE, ACCEPT DSKERR_R: PUSHF ;SAVE RESPONSE FLAGS CALL CLRBOS CALL RSTBOS POPF POP DI ;RESTORE POINTERS POP SI RET ; ABORT BACK TO BDOS DSKERR_B: JMP ABORT ;LEAVE THIS PLACE EJECT ; ; *** INTERRUPT HANDLING ROUTINES *** ; ; USER BREAK INTERRUPT ROUTINE ; ENTERED WHEN USER HITS CONTROL-BREAK AT KEYBOARD ; BREAKINT: TEST CS:BRKFLAG,TRUE ;HERE ALREADY? JZ BRKINT1 ;SKIP IF NOT IRET ;DO NOT REENTER BRKINT1: PUSH AX PUSH DS MOV AX,CS ;GET CURRENT SEGMENT MOV DS,AX MOV SPBREAK,SP ;SAVE STACK POINTER MOV SSBREAK,SS ;AND SEGMENT MOV SP,BRKSTACK ;OUR OWN STACK MOV SS,AX ;IN THIS SEGMENT ; PUSH BX ;NOW PUSH THE WORKS PUSH CX PUSH DX PUSH BP PUSH SI PUSH DI PUSH ES CLI MOV AL,20H ;EOI COMMAND OUT 20H,AL ;TO INT CONTROL PORT MOV BRKFLAG,TRUE ;WE'RE HERE NOW STI ;OK TO INTERRUPT CALL SETBOS CALL CLRBOS MOV SI,OFFSET BREAKMES CALL PRNBOS ;PRINT THE MESSAGE BRKINT2: CALL BEEP ;GET IS ATTENTION CALL CIN ;GET THE INPUT CMP AL,CTRLC ;CONTROL C ? JZ BRKINT3 AND AL,0DFH ;UPPER CASE  CMP AL,'Y' ;BACK TO CP/M ? JZ BRKINT3 CMP AL,'N' ;OR RETURN TO USER ? JNZ BRKINT2 ;TRY AGAIN ; CALL CLRBOS CALL RSTBOS ;RESTORE POP ES ;RESTORE REGISTERS POP DI POP SI POP BP POP DX POP CX POP BX CLI ;HOLD THE INT'S MOV BRKFLAG,FALSE ;YOU MAY REENTER MOV SP,SPBREAK MOV SS,SSBREAK POP DS POP AX IRET ;BACK TO CALLER ; BRKINT3: MOV BRKFLAG,FALSE ;YOU MAY COME BACK JMP ABORT ;WE'RE GONE ; ; TIMER INTERRUPT ROUTINE ; VECTOR SET UP I :02000086000078 :0400000300000000F9 :1B000081E9FD1133C08ED8C706800306048C0E82038CC88ED08ED88EC0BCB8C1 :1B001B8101E89200E897003CFF7509BAE100E8A400E9AE008CCAE89400BAB894 :1B00368101E88900E89800A1BB012EA355018BD0E87F00BA2601E881002EA1DD :1B0051815501E83600BA0000E8670052E875003C0174153C007409BA0B01E8BA :1B006C816200E96C005A81C28000E9E0FFBA3B01E851005848E80800E846006F :1B0087812EFF2E5301B90404D3C05150E807005859FECD75F3C3240F3C0977B4 :1B00A281050430E9020004378AD0B102E92900B10EBA0000E92100B10FBA57F0 :1B00BD8101B10FE91700B11AE91200B133E90D00BA5001B109E90500BA570181 :1B00D881B114CDE0C3F4E9FCFF0D0A5468652046696C652043504D2E5359537A :1B00F381204E6F7420466F756E64204F6E2054686973204469736B240D0A4544 :1B010E8172726F7220496E2052656164696E672043504D2E535953240D0A5324 :1B01298165676D656E742041646472657373203D20240D0A202020204C61737C :1301448174204F6666736574203D20240D0A240000000050 :02015381002504 :1B0157810043504D20202020205359530000000000000000000000000000008D :0601728100000000000006 :00000001FF 0 :1B00 copyright(c) 1977, digital research $Error On Line $SUBNo 'SUB' File Present$Disk Write Error$Command Buffer Overflow$Command Too Long$Parameter Error$Invalid Control Character$Directory Full$Cannot Close, Read/Only?$00@P؎Ћ F2ك+cG  GFG3؎P+U53S,4Hu))x00;uB3P P2-F%t.yP P P,|P&-OPPu3P-UPt66帱PXw=FtF0F3]à,)RR*su+:=t]à,)Q*+Hu$]w6,)Q*+Hu6]u,0仴SPPt]u)0仴SPPt]5432g146--.;u.yU-*v 3P6常P+Pv l0=FFtu F0]øPv 0=Fu]ÊF0Huv 6c0=~R+Pv P+,=t P+P*!0=FFtu3]ø]ñc؉e]U=*v +PV0FHt3]Ë6c0=uyP$Pu* ]áeSF[*s=t PJ*oPrP8*U 0=FFtjtfP+Pv 0=FFtu F0]3Pv 0=Fu]ÊF0Hu v 9 P;tFSe)0=FFtu3]ø]UPsu3P6bP\)帱PPv r@u]v "uv vP suUoPv CP(帱PmPv @u]v v h u3]3Pv v F @F FF0tvF0=?t F0HF݊F0u]øFPp(P\Uv0P6iP)(vP(FF n~u]øcP(帱P,=Ft= uv]3]Á~t]øP'3]3]=t=tU5wv-.]Ue+c=| cv-.e]UsucFFv0=tFF@cF6eF;FscPd3SSv F'F0Pvv 3Pv v v 0u*v rvF0= uF땃]Uv FD0=:vuFF F0^0;^ DATA_END ;NO XCHG CX,DX IN AL,DX ;GET A BYTE MOV ES:[BX],AL ;PUT IT IN THE BUFFER INC BX XCHG DX,CX ;PUT IT BACK OR BX,BX ;DID WE CROSS A SEGMENT? JNZ READ_DATA1 ;NO MOV AX,ES ;YES, GET THE SEGMENT ADD AH,10H MOV ES,AX ;PUT IT BACK JMP READ_DATA1 READ_DATA_END: RET ;PROCESS IT COMPLETE ;--------------------------------------------------------------- ; WRITE DATA (FOR NON DMA FUNCTIONS) ; ES:BX POINT TO THE BUFFER ;--------------------------------------------------------------- WRITE_DATA: MOV DX,DEV[SI] ;GET THE BASE (DATA) PORT MOV CX,DX ;COPY IT ADD DX,SASI_STAT ;SET FOR THE CONTROL PORT WRITE_DATA1: IN AL,DX ;GET THE STATUS TEST AL,REQ ;ARE WE WRITEY? JZ WRITE_DATA1 ;NOT YET TEST AL,CD ;ARE WE STILL IN DATA MODE? JNZ WRITE_DATA_END ;NO XCHG CX,DX MOV AL,ES:[BX] OUT DX,AL ;PUT THE BYTE OUT INC BX XCHG DX,CX ;PUT IT BACK OR BX,BX ;DID WE CROSS A SEGMENT? JNZ WRITE_DATA1 ;NO MOV AX,ES ;YES, GET THE SEGMENT ADD AH,10H MOV ES,AX ;PUT IT BACK JMP WRITE_DATA1 WRITE_DATA_END: RET ;COMPLETE ;--------------------------------------------------------------- ; ; OUTPUT THE DCB ; ; DI = DCB OFFSET FROM DS ; SI = DIB OFFSET ;--------------------------------------------------------------- OUTPUT_DCB: PUSH DI ;SAVE THE DCB ADDRESS CALL SELECT ;SELECT THE CONTROLLER JNZ OUTPUT_DCB_RET ;CONTROLLER NOT SELECTED MOV DX,DEV[SI] ;GET THE PORT ADDRESS MOV BX,DX ;SAVE THE BASE (DATA) ADDRESS ADD DX,SASI_STAT ;SET UP DX AS STATUS ADDRESS MOV CX,WDCBSZ ;SET THE SIZE OUTPUT_DCB1: IN AL,DX ;GET THE STATUS TEST AL,REQ ;IS IT READY FOR A BYTE? JZ OUTPUT_DCB1 ;NO MOV AL,[DI] XCHG BX,DX ;GET THE DATA ADDRESS OUT DX,AL ;PUT IT OUT XCHG DX,BX ;PUT BACK THE STATUS PORT INC DI ;POINT TO NEXT BYTE LOOP OUTPUT_DCB1 ;GO AGAIN SUB AL,AL ;SET ZERO FLAG OUTPUT_DCB_RET: POP DI ;RESTORE THE DCB ADDRESS RET ;OPERATION IS COMPLETE ;--------------------------------------------------------------- ; GET THE STATUS FROM THE CONTROLLER ; IF THERE IS AN ERROR, GET THE FULL STATUS ;--------------------------------------------------------------- GET_STAT: CALL INPUT_STAT ;GET THE NORMAL STATUS TEST AH,ERR_BIT ;IS IT SET? JZ GET_STAT_RET ;NO, LEAVE MOV DCB_CMD[DI],SENSE_STAT ;SET FOR A SENSE STATUS CALL OUTPUT_DCB ;SEND IT CALL INPUT_STAT ;GET THE RESULT CMP AH,CORRECTED ;CHECK FOR CORRECTED JNZ GET_STAT_RET SUB AX,AX GET_STAT_RET: RET ;--------------------------------------------------------------- ; READ STATUS ;--------------------------------------------------------------- INPUT_STAT: MOV BX,OFFSET WSTAT MOV DX,DEV[SI] ;GET THE BASE (DATA) PORT MOV CX,DX ;SAVE IT ADD DX,SASI_STAT ;SET FOR SASI PORT MOV BYTE PTR [BX],-1 ;CLEAR THE FIRST BYTE PUSH BX ;SAVE THE START OF THE AREA INPUT_STAT1: IN AL,DX ;GET THE CURRENT STATUS TEST AL,BSY ;SET THE DIRECTION JZ INPUT_STAT_RET ;WE ARE IN OUTPUT - LEAVE TEST AL,REQ ;SIGNAL STEADY? JZ INPUT_STAT1 ;NO MOV AH,AL ;SAVE IT XCHG DX,CX ;SET THE DATA PORT IN AL,DX ;GET THE DATA BYTE MOV [BX],AL ;PUT IT IN INC BX ;POINT TO NEXT ONE XCHG DX,CX ;RESTORE THE STATUS ADDRESS TEST AH,MSG ;WAS THAT THE LAST BYTE? JZ INPUT_STAT1 ;TRY AGAIN INPUT_STAT_RET: POP BX ;RESTORE MOV AH,[BX] ;GET THE FIRST BYTE RET ;OPERATION COMPLETE ;--------------------------------------------------------------- ; CONVERT TRACK/SECTOR/DRIVE TO DCB FORMAT ;--------------------------------------------------------------- XEBEC_ADR: PUSH CX ;SAVE SECTOR CALL CHECK_ALT ;CHECK THE ALTERNATE TABLE SUB DX,DX ;CLEAR HIGHER ORDER MOV CL,SCTS[SI] ;GET THE SECTORS PER TRACK SUB CH,CH MUL CX ;MULITPLY POP CX ;GET THE SECTOR BACK SUB CH,CH ;JUST IN CASE ADD AX,CX ;COMBINE JNC XEBEC_ADR1 ;NO CARRY INC DX ;CARRY XEBEC_ADR1: MOV CH,DRV[SI] MOV CL,3 ROR CH,CL ;SHIFT IT ADD DL,CH ;COMBINE MOV DCB_A0= t0= u F0]ÊF0@FFUyP00;u P#&00;u P &/P&`P%帅P%帽P%P%)P%WP%希P%帾P% ) @@ ]Ut FPPL%0FtF0]U~ u PP %vP%F]U0t]ËF]U>uPP$P0]Ut@]Uv0uv P$F@@v\0v]Uv<tF0P]U6cg6e]UPv6uv>6g6cWUtÃ>uteEe;r0=}6>..> }6> >}6ge6eH]UvP(#F]Uv<tF0P]U3PPP %]UF ^ NVR2RFN^"]Uvu3]áevD)PP"v F1v -]ø]v -3]=t=tUvu3]áevD)PP"v FYvm .3]ø]à-0Hu]vA .Pvo #!]=t=t=t]U FFFF^;|FûF^vS^3F y F@Fƃ~ ~ FHF3 ]ËF yFvvF F ]U0=FuFPPP!PvPmF0= F|P PPFF0]UNu3]7eu3]]U-/P+0Ht 40u3-]ø PP[2PU 3PhPFP,FPhP +^SF/P-]U3Pv v +v FFtv PF6iPv PF~u]ñF6iD 0%vt PVPb+ 0QQ XFlU]u3]=t3]ø]U/P3P P"lP帩P0/SF~F=t=u]3]U/PS3P P40HuP! P a P帉 P]U츼 P P|=t]37]U 3Pv v 40t00;u*v V5FF0='0P?HuF0@v VF0@F]Ue#!P=Fu]Ã~uG]6cgP=Fu]Ã~u]Ã~u-0u]U6cPV3]U e > Pc7F^03v0=uP,u ]vP vgP F@P5vXF@P?HttP=Fu ]Ã~u vFIvgP=F u ]Ã~ u vF~ u -0t ~ unF*PF0P6c ]UVHu]v0]U5Hu]v Pu]vmFtHuF]vu]v4u]v vcu]ø]U-0uvD\ #!]U3D B >B }->D u&vF0%v F 0+ãD B ̡D ]UF PpF PF P]U J PDM P;Fw0^;|^0FHAPGP PF~|v0^0;uvF F = }v0%PF .PF F = }v0%PF S PF;eFu3 ]FqW PF1F ]U cZ SFJvFt8] P*0=FFt=uӸ PHM P  ]3 ]U~u3P POFHȻS%P8]Uv0PvP]U3P+PvvvhFvD)]Uev\)FFNt7v9tvD%0=t]v"v*뿸]Uvt)Pmv!PavD%0]UevD)t&v(t]vvϸ]Uvt)Pv"PvD%0]UvPvD%0%]UvPvD%0%]UvPvD%0%]UvD!T#]UvD)]U~u#vD \ 0䢏 %D 0 \  vD D ]UeaF^F;Fw F]U3PPP^%t33CÃ]U3PPP^%]U FvD0=:u0%vF3PPUIZ ;NUMBER OF ENTRIES MOV DX,10H SINIT7: MOV AX,HTALC[BX] ;GET ALLOCATION MOV CDSM[DI],AX ;SET IT OR AX,AX JZ SINIT7A OR WDRIVES,DX ;SET IT SINIT7A: ADD BX,8 ;NEXT ADD DI,DPBK10SZ ;NEXT ADD DX,DX LOOP SINIT7 ;AGAIN SUB AX,AX ;MAKE A ZERO MOV CX,MXDSK ;NOW FIX THE HEADERS MOV BX,OFFSET DPBASE MOV DX,1 SINIT8: MOV DI,DPB[BX] ;GET THE BLOCK ADDRESS CMP DI,AX ;IS IT ZERO ALREADY? JZ SINIT9 ;YES CMP CDSM[DI],AX ;IS THE ALLOCATION ZERO? JNZ SINIT9A ;NO MOV DPB[BX],AX ;CLEAR THE POINTER JMPS SINIT9 SINIT9A: OR DRIVES,DX ;SET ACTIVE DRIVE SINIT9: ADD BX,16 ;NEXT ENTRY ADD DX,DX LOOP SINIT8 ;KEEP GOING SASI_INIT_RET: RET ;----------------------------------------- ; SETUP_DMA ; ; THIS ROUTINE SETS UP THE DMA CONTROLLER FOR READ/WRITE ; OPERATIONS. ;----------------------------------------- SETUP_DMA: OUT DMA_CLRF,AL ;SET THE FIRST/LAST F/F MOV AL,DMA_CODE OUT DMA_MODE,AL ;OUTPUT THE MODE BYTE MOV AX,DS ;GET THE SEGMENT VALUE MOV CL,4 ;SHIFT COUNT ROL AX,CL ;ROTATE LEFT MOV CH,AL ;GET HIGHEST NIBBLE OF SEG TO CH AND AL,0F0H ;ZERO THE LOW NIBBLE FROM SEGMENT ADD AX,OFFSET LOCALBUF ;TEST FOR CARRY FROM ADDITION JNC SETDMA1 ; INC CH ;CARRY MEANS HIGH 4 BITS MUST BE INC SETDMA1: PUSH AX ;SAVE START ADDRESS OUT DMA1_ADR,AL ;OUTPUT LOW ADDRESS MOV AL,AH OUT DMA1_ADR,AL ;OUTPUT HIGH ADDRESS MOV AL,CH ;GET HIGH 4 BITS AND AL,0FH OUT DMA1_PAGE,AL ;OUTPUT THE HIGH 4 BITS TO PAGE ; DETERMINE COUNT MOV AH,DCB_CNT[DI] ;NUMBER OF SECTORS SUB AL,AL ;TIMES 256 INTO AX SHR AX,1 ;SECTORS * 128 INTO AX MOV CL,SSSZ[SI] ;GET THE SHIFT SIZE SHL AX,CL ;MULTIPLY BY CORRECT AMOUNT DEC AX ;-1 FOR DMA VALUE PUSH AX ;SAVE COUNT VALUE OUT DMA1_CNT,AL ;LOW BYTE OF COUNT MOV AL,AH OUT DMA1_CNT,AL ;HIGH BYTE OF COUNT POP CX ;RECOVER COUNT VALUE POP AX ;RECOVER ADDRESS VALUE ADD AX,CX ;ADD, TEST FOR 64K OVERFLOW MOV AL,1 ;MODE FOR 8237 OUT DMA_MASK,AL ;INITIALIZE THE DISK CHANNEL RET ;RETURN TO CALLER, CFL SET BY ABOVE ;--------------------------------------------------------------- ; OUTPUT A COMMAND AND GET THE STATUS ;--------------------------------------------------------------- CMD_AND_STAT: CALL OUTPUT_DCB JNZ CMD_RETURN ;ERROR CALL GET_STAT CMD_RETURN: RET ;--------------------------------------------------------------- ; SELECT THE CONTROLLER ; ; [SI] = DIB (DRIVE INFORMATION BLOCK) ; ; RETURN ZERO FLAG SET IF SELECTED ; CLEARED IF NO RESPONSE ;--------------------------------------------------------------- SELECT: MOV DX,DEV[SI] ;GET THE PORT ADDRESS MOV BX,DX ;SAVE A COPY MOV AL,CTL[SI] ;GET THE CONTROLLER BIT OUT DX,AL ;SET THE DATA LATCH ADD DX,SASI_CTRL ;POINT TO THE CONTROL LATCH MOV AL,CLS[SI] AND AL,NOT SEL ;SET FOR SELECT TRUE OUT DX,AL ;SELECT TRUE XCHG BX,DX ADD DX,SASI_STAT ;POINT TO THE STATUS PORT MOV CX,100 SELECT1: IN AL,DX ;GET THE STATUS INFORMATION AND AL,1FH SUB AL,REQ+BSY+CD ;ARE THE LINES RIGHT? JZ SELECT2 ;YES LOOP SELECT1 ;NO WAIT FOR A WHILE SELECT_ERR: MOV AH,80H ;TIMEOUT SELECT2: MOV DX,BX ;RESTORE THE CONTROL ADDRESS MOV AL,CLS[SI] ;GET THE CURRENT SETTING OUT DX,AL ;RESET JNZ SELECT_RET ;ERROR MOV CX,100 IN AL,DX AND AL,1FH MOV AH,AL STEADY1: IN AL,DX ;GET THE STATUS INFORMATION AND AL,1FH SUB AL,AH LOOPZ STEADY1 ;NO WAIT FOR A WHILE SELECT_RET: RET ;AND LEAVE ;--------------------------------------------------------------- ; READ DATA FROM THE SASI PORT (FOR NON DMA FUNCTIONS) ; ES:BX POINT TO THE BUFFER ;--------------------------------------------------------------- READ_DATA: MOV DX,DEV[SI] ;GET THE DATA PORT MOV CX,DX ;COPY IT ADD DX,SASI_STAT ;SET FOR THE CONTROL PORT READ_DATA1: IN AL,DX ;GET THE STATUS TEST AL,REQ ;ARE WE READY? JZ READ_DATA1 ;NOT YET TEST AL,CD ;ARE WE STILL IN DATA MODE? JNZ READ_0@vF~ }wvv0Uvv [vv?PFFvv0^C\0FtF- vv0vF=*t=t=.tF냋vv0=.Ft tFFv0.uFF ~ }wvv0Uvv [vv?PFFvv0^C\0FtF- vv0vF=*t=t=.tF냋vv0 ]U40u]ð7v\#L!~ ]M V.-03@P S]U40Hu]vvX#! S.- PPz Pt]U/0u]vv P PP/ P) P P" P 3]U PwN P帐 P P P]U3FFF= te=t`=Fu F~NT PӸ[ P ȃ~ |F;F }Fv F뫋F= t=t] P듋v v~u]ÍF P>]U3Pv v ~ uc00;uT40Ht 50KuCFF0=C0PHu3Pv v F0@v VtF0@FF v V[c;eu]ød P]Ui P PPkl Pe3]U-0Hu]3P+Pv50Hu *v v vF@^ CQSPF ^ QSP]U.0Hu]3P+Pv50Hu v v+vF@^ CQSPeF ^ QSPN]U> u] PyiF-PFb^cãa]UaeF+ã'^]Uce^+؉F%]U-0Hu]Ëv0PFvt3]á#!vD#\!-]U.0Hu]Ëv0Pvttvt3]á#!vD#\!.3PV]U=Ft=t = t=uF]Ã~ u ]Ã~  ]ËF]U3PP P帰 > F ^^ u > |F> 1u>t > tF66U SF帶 P帹 Pe帶 P帽 Pv]0%t- FF =Fu]ÊF 0u~ u>u3]Ã~ u-F 0t$6 ]0%t 0%]ËF]ËF=t=u: ^ 0ۉFFtF H0KF NN^ PF ~ t4F0^ 0;&0FPSvv tF F 0@F F ~ tv~ u6 6/>tP PQ6 ]0%t6V P > 1u666  P > u66  P 66F 3PP P帰 F UFv6 ]0t;|;]3]v P> 1tt= uF; |;]3]Ã~ uF; | =9]3]à 0;}~0|~9]ËF=0|;]3]á =uv ;|;]3]3]UvHu]á7t=|@;0u79;6967QvU9;0H;]U P;740uZ50uQ*0Hu#+0=u  P g P ]à*0=u P ]ø P ]à40Hu50u GP 50Hu40u P ]U~ u]ø P常P] 50Hu40u PC P8 v0=Ft=u@P$ P FԸP r3]UFF0t.v0 u0FvF0PqF0HFɸ.P]FF0tvF0P@F0HF܃]UFPvu]3]UF F tv P& F6iP v P F~u3]ñFi؉^>stÃ]ËvD 0%uƃ]U]0Ft- F=Ft= uF]Ã~Yu]Ã~Nu3]UPP` uPPO FtF0%]UOPP@=u3]UF N tvF~ F ]UFNtF F v 0 0;t3]ø]Uv v ]0Fu3]Ëv 3Sv VFzFv VFt]øPRP{UP3]Uv 0@v \0:Ft]Ëv 0%^00;ÈFu]à60Hu0F0%0FHPF9HuF0@v F]øPRPUPO3]UFv X6X0tA~ t;0=0F|=9~3]Ëv  6X0-0v XN 볡X;Fu3]ø]U~ u3]3Pvv 3PvZP ZFv ~!^C 0^v  ֋v0t~ F N]Uv 0v0;u F HF t0u3]FF ΋v 0v0+؋Ã]Uv 0=|vtOV BX,DX ADD DX,SASI_CTRL ;POINT TO CONTROL ADD BX,SASI_STAT ;POINT TO STATUS MOV AL,CLS[SI] ;GET THE CURRENT LATCH SETTING MOV AH,AL ;SAVE THE ORIGINAL STATE AND AL,NOT DMA_ENABLE OUT DX,AL ;ENABLE DMA XCHG BX,DX SASI_WAIT: IN AL,DX ;GET THE STATUS TEST AL,CD ; JZ SASI_WAIT ;WAIT FOR COMPLETE MOV DX,BX MOV AL,AH OUT DX,AL SASI_CMPL: CALL GET_STAT ;GET THE STATUS JZ SASI_RET ;COMPLETE SASI_TRANS_ERR: OR AH,0C0H ;UNIQUE CODES IN THE TABLE PUSH SI ;SAVE POINTERS PUSH DI CALL DISKERROR POP DI ;RESTORE POP SI JZ SASI_TRANS ;TRY AGAIN MOV AL,1 ;ASSUME ERROR JC SASI_RET ;YES SUB AL,AL ;IGNORE THE ERROR SASI_RET: RET ;--------------------------------------------------------------- ; INITIALIZE THE DRIVE ;--------------------------------------------------------------- SASI_INIT: MOV SI,OFFSET WDIB ;SET THE INFORMATION BLOCK MOV CTL[SI],1 ;START WITH CONTROLLER ONE INIT_AGAIN: MOV DI,OFFSET WDCB ;SET THE DCB ADDRESS MOV DCB_CMD[DI],TEST_READY ;CHECK FOR A DRIVE READY MOV RETRY,255 ;SET FOR MAX TRIES SASI_TEST_RDY: CALL OUTPUT_DCB ;SEND THE COMMAND JNZ SINIT6_PIPE ;CONTROLLER NOT THERE CALL GET_STAT ;GET THE STATUS JZ SASI_DRV_RDY ;OK DEC RETRY JNZ SASI_TEST_RDY JMPS SINIT6_PIPE ;NO GO SASI_DRV_RDY: SUB AL,AL MOV DCB_ADR0[DI],AL ;SET TO ADDRESS SECTOR 0 MOV DCB_ADR1[DI],AL MOV DCB_ADR2[DI],AL MOV DCB_OPT[DI],AL MOV DCB_CNT[DI],1 ;SET FOR ONE SECTOR SASI_INIT1: MOV DCB_CMD[DI],READ_CMD ;SET FOR A READ CALL OUTPUT_DCB ;ISSUE THE COMMAND JNZ SASI_INIT_ERR MOV BX,OFFSET WHATBUF ;WHERE TO PUT IT CALL READ_DATA ;GET THE SECTOR CALL GET_STAT ;CHECK FOR AN ERROR JNZ SASI_INIT3 ;ERROR ; SECTOR HAS BEEN READ - DO A CHECKSUM MOV BX,OFFSET WHATBUF ;POINT TO THE BUFFER MOV AL,55H ;SET THE STARTING VALUE MOV CX,SSIZ[SI] ;GET THE SECTOR SIZE DEC CX SASI_INIT2: ADD AL,[BX] ;FORM THE CHECKSUM INC BX LOOP SASI_INIT2 CMP AL,[BX] ;IS IT THE SAME? JZ SASI_INIT4 ;NO, CONTINUE SASI_INIT3: INC DCB_ADR2[DI] ;BUMP SECTOR ADDRESS MOV AL,DCB_ADR2[DI] CMP AL,SCTS[SI] ;MAX? JB SASI_INIT1 ;NO, TRY AGAIN SASI_INIT_ERR: SINIT6_PIPE: JMP SINIT6 ; ID SECTOR IS IN MEMORY SASI_INIT4: MOV DCB_CMD[DI],INIT_CMD ;SET FOR AN INIT CALL OUTPUT_DCB ;ISSUE IT JNZ SASI_INIT_ERR MOV BX,OFFSET WHATBUF ;POINT AT THE BUFFER CALL WRITE_DATA ;PUT IT OUT CALL GET_STAT ;WAS IT OK? PUSH SI MOV DI,OFFSET ALTRK0 CMP CTL[SI],1 ;FIRST CONTROLLER? JZ SASI_INIT4A ;YES MOV DI,OFFSET ALTRK1 ;NO SASI_INIT4A: MOV SI,OFFSET WHATBUF MOV AX,OFFSET IDALT ADD SI,AX MOV CX,ALTSIZ ;SET THE SIZE REP MOVSW ;MOVE IT OVER POP SI ; CHECK OUT THE HDTBL MOV BX,OFFSET HDTBL ;POINT TO THE TOP MOV CX,HDTBLSIZ ;MAX NUMBER MOV DI,OFFSET WHATBUF ADD DI,OFFSET IDCPM ;POINT TO THE ALLOCATION INFO MOV DH,2[DI] ;SET A FLAG MOV DL,3 ;ASSUME OLD STYLE OR DH,DH JZ SINIT1 ;IT IS INC DL ;NEW STYLE SINIT1: CMP AX,HTALC[BX] ;THIS SLOT TAKEN? JNZ SINIT2 ;NO ADD BX,8 ;YES, BUMP LOOP SINIT1 ;CONTINUE JMPS SINIT5 ;TABLE FULL SINIT2: MOV AL,OPT[SI] ;GET THE OPTION CODE MOV HTOPT[BX],AL ;SET IT MOV AL,CTL[SI] ;GET THE CONTROLLER MOV HTCTL[BX],AL ;SAVE IT MOV AL,DRV[SI] MOV HTDRV[BX],AL MOV BP,0[DI] ;GET THE OFFSET OR DH,DH ;OLD OR NEW? JZ SINIT3 ;OLD MOV AX,2[DI] ;NEW ADD DI,4 JMPS SINIT4 SINIT3: MOV AX,4[DI]  ;OLD STYLE ADD DI,6 SINIT4: MOV HTOFF[BX],BP ;SET THE OFFSET IN THE TABLE MOV HTALC[BX],AX ;SET THE ALLOCATION ADD BX,8 ;NEXT ENTRY DEC DL ;COUNT DOWN JZ SINIT5 ;THATS ALL LOOP SINIT2 ;CONTINUE SINIT5: MOV AL,CTL[SI] ;GET THE CONTROLLER ADD AL,AL ;NEXT ONE MOV CTL[SI],AL ;PUT IT BACK JMP INIT_AGAIN ;TRY FOR A SECOND ONE ; ID SECTORS ON ALL DRIVES HAVE BEEN READ SINIT6: MOV BX,OFFSET HDTBL ;TABLE MOV DI,OFFSET DPBK10 ;FIRST ENTRY MOV CX,HDTBLS3]Fv0PGu3]Fv0=|t]Fv0Pu3]ø]UF=St=su s]ËF=Ot=ouu]3]U40t00Hu]à30uu3]à30u OP3P`Pv S+v 0PSv 021'u3]øPOPP30F@^Qv 3"u3]øPv u3]ø]U40u]øPvu3]ø20FûSv PFjPv(u3]øPvu3]ø]U20@=2]210@vv1]U F SSPF00u FFFF0FH~Ft vFvv j ]Uvt3]ËF vD)103ۅyK\#D!t)Prvt3]v]U00Hu v ]F v rF~t3]0F v D)103ۅyK\#D!t)Pv t3]v =]U PPvFkSFPv@tv0t]øPPvb]U v0@\0%tF> |yv0Ffv0@\0%uf F0ãfFFv0Ft)@\0%uF=}F~FɋvƄvF0=>vu &FFv0Ft)@\0%uF=}F~FɋvƄMFv0Ft-@\0%uF=>uf=<u==u볋v0FFt*v0@\0%tFv0t(PP?6SF/&SSFF u P~uv *PBP*~uv AP'P0uvD0 D0uvD0 Dv D0 DP6ҋ3P ]USQRVWNV_^ZY[2]U 썆F 0t|މ^C0=%Fu[0=%u0PFfڋFPF PF PFtFF;F}B 0P*ڋFvڋx ]UFF=}#n0Ft hPFv v S]U~NF]U썆F 0uމ^C0=%Ft0=%u40rKۉFrx6pp0멸pPv뛍FPF PFP~F u|FF;F|hrKۉrxppB0vB0pSPcF뾡rHrx6ppF0pPv5]UFvv0tFF]U ~u3 ]ËFH^F ^v~tKvD^ ;w/;u vvD+F DFF )`F ]ËFF^믋F P;É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Ã]Ubd^`t `G]UbdFv7 ;ÉFuÃ]ËFd@bv ;td@3]U`]U 3v0-FFF u ^^ v0=+uFFv0C\0t!F ^Fv00ÉFƃ~ t^FvF ]Uv 0v0;u0u3]FF ًv 0v0+؋Ã]UhF^;sG0tFF=u3]vv v ]U vDt0%t VP` vD0Pv0t@Pv F@uPv FP3P3Sv'FG6v FF1Pv FF3 ]\ N^ v>3ɅyIN ^F yBV ^^ F1~tv>\ N^ v>3F ^F FHFF ^3ɺ ve ----------------------- ; READ/WRITE FLOPPY DISK DRIVE VIA ; THE EPROM BIOS ;-------------------------------------------------------- FLOPPY: MOV DISK_CMD,AH ;SAVE THE COMMAND PUSH ES ;SAVE IN CASE DIFFERENT SUB AX,AX MOV ES,AX ;POINT TO THE BASE PAGE MOV SI,BX ;PUT OUR PARAMETER TABLE IN SI MOV DI,RHWP[SI] ;GET THE HARDWARE POINTER MOV ES:PARMOFF,DI ;SET THE OFFSET IN BASE PAGE MOV AX,DS MOV ES:PARMSEG,AX ;AND THE SEGMENT MOV ES,AX ;SET EXTRA TO HERE MOV AH,SDISK AND AH,1 MOV FDISK,AH SUB AH,AH ;ASSUME HEAD 0 MOV AL,BYTE PTR STRACK ;GET OUR TRACK NUMBER MOV CH,RTPS[DI] ;GET OUR REAL TRACKS PER SIDE CMP AL,CH ;ARE WE BEYOND HEAD 0 JB FLOPPY2 ;NO INC AH ;SET FOR HEAD 1 TEST RSDF[SI],1 ;WHICH METHOD? JNZ FLOPPY1 ;IBM ; CHECK FOR HEAD WRAP AROUND SUB AL,CH ;YES JMPS FLOPPY2 ;CONTINUE ; IBM DOUBLE SIDED DOES IT DIFFERENT FLOPPY1: MOV CH,79 ;ADJUST SUB CH,AL ;GOING BACK THE OTHER WAY MOV AL,CH ;PUT IT BACK FLOPPY2: MOV FTRACK,AL MOV FHEAD,AH MOV BX,RXLT[SI] ;GET THE TRANSLATION TABLE MOV AL,SSECTOR ;GET THE REQUESTED SECTOR OR BX,BX ;ANY NECESSARY? JZ FLOPPY3 ;NO XLAT BX ;YES FLOPPY3: INC AL ;ADJUST TO A REAL VALUE MOV FSECTOR,AL ;AND SAVE IT ; DO THE REQUESTED OPERATION FLOPPY_RETRY: MOV RETRY,TRIES ;RESET THE COUNT FLOPPY_TRY: MOV AH,DISK_CMD ;GET THE COMMAND MOV AL,RDSZ[SI] ;GET THE READ SIZE MOV BX,OFFSET LOCALBUF ;USE LOCAL BUFFER MOV CX,WORD PTR FSECTOR MOV DX,WORD PTR FDISK INT 13H ;CALL THE DISK DRIVER JNC FLOPPY_OK ; ERROR ON THE FLOPPY HAS OCCURRED FLOPPY_ERR: TEST RETRY,3 JNZ FLOPPY_ERR1 PUSH DS ;NOT A GOOD IDEA BUT OK FOR NOW MOV CX,EPROM_SEG MOV DS,CX AND SEEK_STATUS,0F0H POP DS FLOPPY_ERR1: DEC RETRY JNZ FLOPPY_TRY ;TRY AGAIN MOV DOSEL,0 ;FORCE RESELECT CALL DISKERROR ;REPORT IT JZ FLOPPY_RETRY ;TRY AGAIN MOV AL,1 ;ASSUME ERROR JC FLOPPY_ERR2 ;ACCEPT FLOPPY_OK: SUB AL,AL ;IGNORE FLOPPY_ERR2: OR ERFLAG,AL ;SET IT POP ES ;RESTORE RET ;AND LEAVE EJECT ;-------------------------------------------------------- ; SASI WINCHESTER DRIVERS ;-------------------------------------------------------- SASI: CMP AH,2 ;READ? JNZ SASI_WRITE ;NO SASI_READ: MOV AL,READ_CMD ;SET CODES FOR READ MOV AH,DMA_READ JMPS SASI_COMMON ; SASI_WRITE: MOV AL,WRITE_CMD ;SET FOR A WRITE MOV AH,DMA_WRITE ; ; COMMON ROUTINES FOR SASI PORT HARD DISK ; SASI_COMMON: MOV COMMAND,AX ;SAVE THE COMMAND MOV SI,OFFSET WDIB ;POINT TO THE DRIVE INFORMAT MOV DI,OFFSET WDCB ;POINT TO THE CONTROL BLOCK MOV BL,SDISK ;GET THE REQUESTED DISK AND BX,3 ADD BX,BX ;X2 ADD BX,BX ;X4 ADD BX,BX ;X8 MOV AX,OFFSET HDTBL ;POINT TO THE TABLE ADD BX,AX ;POINT TO THE RIGHT ENTRY MOV AL,HTOPT[BX] ;GET THIS DRIVES OPTION CODE MOV OPT[SI],AL ;SET IT MOV AL,HTCTL[BX] ;GET THE CONTROLLER MOV CTL[SI],AL ;SAVE IT MOV AL,HTDRV[BX] ;GET THE DRIVE (IN CASE) MOV DRV[SI],AL ;AND SAVE IT MOV AX,STRACK ;GET THE TRACK ADD AX,HTOFF[BX] ;ADD THE OFFSET MOV CL,SSECTOR ;AND THE SECTOR CALL XEBEC_ADR ;SET THE ADDRESS ;--------------------------------------------------------------- ; DO THE TRANSFER ;--------------------------------------------------------------- SASI_TRANS: MOV AL,DISK_CMD MOV DCB_CMD[DI],AL ;SET THE COMMAND MOV AL,OPT[SI] MOV DCB_OPT[DI],AL MOV DCB_CNT[DI],1 ;SET THE COUNT TO ONE SECTOR SASI_TRY_DMA: CALL SETUP_DMA JNC SASI_USE_DMA ;OK, CONTINUE ; DMA BOUNDARY PROBLEM - USE BYTE BY BYTE SASI_NON_DMA: CALL OUTPUT_DCB ;SET THE DCB JNZ SASI_TRANS_ERR MOV BX,OFFSET LOCALBUF ;LOCAL BUFFER PUSH DS POP ES CMP DCB_CMD[DI],READ_CMD JNZ SASI_DO_WRITE ;THIS IS A WRITE CALL READ_DATA JMPS SASI_CMPL SASI_DO_WRITE: CALL WRITE_DATA JMPS SASI_CMPL ; DO A DMA TRANSFER SASI_USE_DMA: CALL OUTPUT_DCB ;SET THE DCB JNZ SASI_TRANS_ERR MOV DX,DEV[SI] ;GET THE PORT ADDRESS M0vR"F ^3ɺ K 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]f[9eT9gM9c39s8oc8x7u07d6 .;i9u.k9y뿃~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~!^)^FHFxvu*6f u]á~ u]ËF @@H;Fv]ËF)^؋F]U]UFF=} ؋%tF~u]ËF @@Pv t]ø ^FtNF @@Pvv t]øPv ^Ft Nf~uN@ ~uN nFF]UFF=} ؋%tF~u]ËF @@Pvv ~t]ø ^FtNF @@Pvv t]øPv F عNFtF]UF x=~ ]ËF ؁^t% t ]ËFvDFD 0FtNFPvv B Hu3]Ã>t]ËvD]UF x=~ ]ËF ؁^t%@t ]ËFvDFD 0FtNFPvv =u3]Ã>t]ËvD]U Fx=~ ]ËF ؋%u ]ËFO33yKF^LFP Pv7FP!Pv" ]=t=t=tރ>t ]ËFF^^FP Pvt ]ÍFPPv_t ]ËF^ ]UF x=~ ]ËF ؋%u ]øPv Sv FFF 3~u~t]3]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 FuNF txv N xF ϋFxA=7FF^NV ֊͊ߊĿOu% F 3333ҋv4Ft D\Lv2F(]UF+r;r;s+듉]3]Uvu]Ë؋~u#G SPXP to quit: %s Invalid file name The file name already exists. Do you wish to delete it (Y or N)? File name not found. Eagle CP/M-86 Version 1.2 Eagle MSDOS Version 1.2 Hard Disk Backup Menu. Your options are: (1) Backup all files on the hard disk. (2) Perform a selective files backup. (3) Create a selective backup list. (4) Display hard disk files. (5) Display floppy diskettes files. (6) Return to the previous menu. Which is your choice? jK kEInitializing the diskette. Please do not interrupt...*.* A request to terminate the operation has been received. Do you wish to terminate this operation (Y or N)? The operation has been terminated. Any files transferred during this operation are incomplete and cannot be used. The operation has been terminated. Press any key to return to the main menu... Insert a formatted diskette in the floppy disk drive. Press to stop, any other key to continue...EYkJ: j Push to exit, any other key for next page Floppy diskette number %d is full.EThe destination floppy diskette is full.The destination hard disk or floppy diskette is full.Press any key to return to the main menu... --------------- W A R N I N G ---------------- | Any data stored on the diskette you insert | | in the floppy disk drive will be destroyed.| --------------- W A R N I N G ---------------- ?x7 ENo files to display. Press any key to return to the main menu...jK k%sYour options are %c thru %cYour options are %c thru %c%cYour options are %d thru %dE Transferring files from drive A (left) to drive B (right). Transferring files from the hard disk to the floppy diskette. Transferring files from drive B (right) to drive A (left). Transferring files from the floppy diskette to the hard disk. Backing up Hard Disk Files.  Restoring Hard Disk Files. The file(s) listed below were not restored: transferred: Press any key to return to the main menu...VOLUME LOG%sKvolume.log Please enter date or comment (up to 15 characters): Disk Backup warCan't open stdin file Can't create stdout file ((((( H ((((( H 0123456789ABCDEF@ CONAXIAXOLSTNUL - ; SET DMA BASE ADDRESS ; ENTRY: CX = READ/WRITE TARGET SEGMENT ;----------------------------------------------------------- SETDMAB: MOV DMABASE,CX RET EJECT ;----------------------------------------------------------- ; SELECT DISK DRIVE ; ENTRY: CL = DRIVE CODE NUMBER ; DL LSB = 0 IF FIRST DISK SELECT ; EXIT: BX = ADDRESS OF DISK PARAMETER HEADER ;----------------------------------------------------------- SELDSK: SUB BX,BX CMP CL,MXDSK JNB SELDSK2 ;EXIT ILLEGAL DRIVE MOV AX,1 SHL AX,CL ;CREATE A DRIVE BIT MOV DISK,CL ;SAVE DISK CODE MOV BL,CL MOV CL,4 SHL BX,CL ;BX = DRIVE CODE * 16 MOV CX,OFFSET DPBASE ADD BX,CX MOV CX,DPB[BX] OR CX,CX JZ SELDSK_ERR ;NO GOOD TEST DOSEL,AX JZ SELDSK0 ;FORCE A RE-SELECT AND DL,1 ;IS THIS A "NEW" DISK JNZ SELDSK2 ;NO SELDSK0: OR DOSEL,AX ;SET IT ; DRIVE IS A FLOPPY, TRY TO DETERMINE FORMATT PUSH ES PUSH SI PUSH DI PUSH BX ;SAVE THE POINTER MOV SI,CX ;GET THE BLOCK TEST RSDF[SI],0FEH ;FLOPPY OR WINCHESTER? JNZ SELDSK_NF ;WINCHESTER CALL WHATDISK ;GET THE DISK TYPE MOV CX,SI SELDSK_NF: POP BX ;RESTORE POP DI POP SI POP ES OR CX,CX ;VALID? JZ SELDSK_ERR ;NO MOV DPB[BX],CX ;SET IT JMPS SELDSK2 ;NO SELDSK_ERR: SUB BX,BX ;INVALID MOV DOSEL,BX ;ERROR SELDSK2: MOV AX,BX ;SPREAD THE STUFF RET ;----------------------------------------------------------- ; CHECK FOR THE PROPER FORMAT ; RETURNS WITH SI POINTING TO ; THE PROPER DISK PARAMETER BLOCK ;----------------------------------------------------------- WHATDISK: MOV DL,DISK ;MOVE THE DRIVE NUMBER TO DL AND DL,1 ; SUB DH,DH ;ASSUME HEAD 0 MOV BX,OFFSET WHATBUF ;BUFFER ADDRESS MOV CL,1 ;SECTOR ONE PUSH DS POP ES ;ADDRESSABILITY MOV RETRY,3 ;SET A RETRY COUNT WHATTYPE: MOV CH,0 ;TRACK 0/SECTOR 1 MOV SI,OFFSET DPBK5 ;TRY PC SINGLE SIDED (48TPI) CALL TRYREAD ;IS THAT IT? JNC PC_FMT ;MAYBE MOV SI,OFFSET DPBK2 ;TRY EAGLE 96TPI MOV CH,BYTE PTR COFF[SI] ;GET TRACK OFFSET CALL TRYREAD JNC EAGLE96 ;APPEARS TO BE EAGLE 96TPI MOV SI,OFFSET DPBK3 ;TRY EAGLE 48TPI MOV CH,BYTE PTR COFF[SI] ;GET TRACK OFFSET CALL TRYREAD JNC EAGLE48 ;APPEARS TO BE EAGLE 48TPI DEC RETRY JNZ WHATTYPE MOV AH,81H ;SET THE ERROR CODE CALL DISKERROR ;ISSUE MESSAGE JZ WHATDISK ;TRY AGAIN SUB SI,SI ;NO GOOD RET ;AND LEAVE ;----------------------------------------------------------- ; DISKETTE APPEARS TO BE A PC DISKETTE ; DETERMINE IF SINGLE/DOUBLE SIDED ;----------------------------------------------------------- PC_FMT: ADD BX,01FFH ;POINT AT LAST BYTE IN SECTOR CMP BYTE PTR [BX],0 ;SINGLE OR DOUBLE? JZ PC_FMT_RET ;SINGLE MOV SI,OFFSET DPBK6 ;DOUBLE PC_FMT_RET: RET ;NO LEAVE ;----------------------------------------------------------- ; DISKETTE APPEARS TO BE EAGLE 400K 48TPI ; WE HAD TO READ THE DIRECTORY TRACK FIRST ; TO BE SURE ITS A 48TPI DISK IN A 96TPI ; SYSTEM. NOW READ THE ID SECTOR FOR TYPE ;----------------------------------------------------------- EAGLE48: MOV CH,0 ;NOW TRY TRACK 0, SECTOR 1 CALL READFLOP JNZ EAGLE48_RET ;BAD NEWS ADD BX,03FFH ;POINT TO LAST BYTE IN SECTOR CMP BYTE PTR [BX],0 ;IS IT? JZ EAGLE48_RET ;YES MOV SI,OFFSET DPBK4 ;NO, DOUBLE SIDED EAGLE48_RET: RET ;----------------------------------------------------------- ; THE DISKETTE APPEARS TO BE AN EAGLE 96TPI ; TRY TO DETERMINE IF SINGLE/DOUBLE SIDED ;----------------------------------------------------------- EAGLE96: PUSH CX ;SAVE THE TRACK/SECTOR MOV AH,4 ;MINIMUM MOV CL,RLSHF[SI] ;NUMBER OF SECTORS SHL AH,CL ;NUMBER OF DIRECTORY ENTRIES POP CX ;RESTORE E96_CHK: CMP DIRC[BX],0E5H ;IS THIS DELETED? JZ E96_NEXT SUB AL,AL ;MAKE A ZERO CMP DM0[BX],AL ;IS THE FIRST DM BYTE ZERO? JZ E96_NEXT ;YES CMP DM2[BX],AL ;IS THE THIRD DM BYTE ZERO? JZ E96_NEXT ;YES CMP DM1[BX],3 ;IS THE SECOND BYTE ZERO? ؎Ћ@ F2ك+cG  GFG3؎Pg&U}43S,5Hu))x00;uB3P P(F%t.yP P P |P}(OPPm u3P(UP66; 帱P7^=FtF0F3]à),6Q*+]u,0仴SPPu]u)0仴SPPt\]3x2S1/4((.;u.y)U *v FcFF^0^Cvv c^lu ]v 76cHuñc؃ce HtFc3 ]Uv-.]UyP PP ~u P& P&P& P P P&=u3]øHPs3PKPvH *v0P 6iP*&vP&=t]ø P P VP&GUyP PP FF0=v F 0PbF0@Fۋv 0@P|P% P P 帇P%0=FFt= u]3]UyPx00;ux0u PU% PJ%00;ux0u P)% JP%{P%帮P %P%P$/P$dP$帖P$ ) @@ ]U0Ft F]øPPi$%]UF%PPK$F]U0t]ËF]Uv0uv P$F@@v\0v]UFFv0tFv$v P#v]U P#u33CÃ]U6cg6e]UPv'6uv>6g6cWUtÃ>uteEe;r0=}6>..> }6> >}6ge6eH]UvPh"F]Uv<tF0P]U3PPP %]UF ^ NVR2RFN^"]Uv0u3]áevD)PP!vF1v1 -]ø(8؎Ћ F2ك+cG  GFG3؎P'U"43S,5Hu))x00;uB3P P<)F%t.yP P P6|P0)OPP u3P)UP~66 帱Pb=FtF0F3]à),6Q*+]u,0仴SPPZu]u)0仴SPP5t\]3x2S1/4((.;u.y)U *v FcFF^0^Cvv c^lu ]v 76cHuñc؃cev HtFc3 ]U.pv-.]UyP PPr ~u Pf' P['PR' P PB P<'=u3]øHP3PKPv *v0P 6iP&vP&=t]ø P P VP&GUyP1 PP FF0=v F 0P=F0@Fۋv 0@P|Pr& P Pb 帇P\&y0=FFt= u]3]UyP00;u P&00;u P%P%EP%jP%帘P%P%P%-P% ) @@ ]UZt ZFPPL%0FtF0]U~ u PP %vP%F]UZ0t]ËFZ]U>ZuPP$PZ0]Ut@]Uv0uv P$F@@v\0v]Uv<tF0P]U6cg6e]UdddPv6`uv>`6g6cWUbtÃ>utebEe^\^;br0ff=}6\>^f.\.^f>f }6bb>``ff >f}6bbfge6edH]UvP(#F]Uv<tF0P]U3PPP %]UF ^ NVR2RFN^"]Uvu3]áevD)PP"v F1v -]ø]v  ;----------------------------------------------------------- ; SERIAL OUTPUT PORT STATUS CHECK ; ENTRY: DX = SERIAL PORT NUMBER ; AH = STATUS CHECK MASK ; EXIT: AL = 0FFH IF READY ; AL = 0 IF NOT ;----------------------------------------------------------- SOSTAT: MOV BX,DX ADD BX,BX ;X2 ADD BX,BX ;X4 ADD BX,BX ;X8 MOV AX,OFFSET SER0 ADD BX,AX ;POINT TO SERIAL CONTROL BLOCK MOV AH,3 ;STATUS CODE INT 14H ;RS232 INTERRUPT XCHG AL,AH AND AL,TBE ;TEST XMT BUFFER EMPTY JZ SORET ;NO, NOT READY MOV AL,TRUE ;JUST IN CASE TEST PBSY[BX],1 ;PRINT BUSY/LOW? JZ SORET ;YES, RETURN TEST PBSY[BX],2 ;HIGH OR LOW JZ SOSTATA ;LOW XOR AH,CTS ;CHANGE STATE SOSTATA: MOV AL,FALSE AND AH,CTS JZ SORET MOV AL,TRUE SORET: RET ;----------------------------------------------------------- ; SERIAL OUTPUT STATUS ;----------------------------------------------------------- SPOUT3: INC DX SPOUT2: INC DX SPOUT1: INC DX SPOUT0: ;----------------------------------------------------------- ; SERIAL PORT OUTPUT ; ENTRY: CL = CHAR ; DX = SERIAL PORT NUMBER ;----------------------------------------------------------- SERIALOUT: CALL SOSTAT ;CHECK THE REAL STATUS OR AL,AL JZ SERIALOUT ;NOT YET MOV AH,01 ;SEND CHAR CODE MOV AL,CL INT 14H ;RS232 INTERRUPT RET ;----------------------------------------------------------- ; SERIAL INPUT STATUS ;----------------------------------------------------------- SISTAT3: INC DX SISTAT2: INC DX SISTAT1: INC DX SISTAT0: ;----------------------------------------------------------- ; SERIAL OUTPUT PORT STATUS CHECK ; ENTRY: DX = SERIAL PORT NUMBER ; AH = STATUS CHECK MASK ; EXIT: AL = 0FFH IF READY ; AL = 0 IF NOT ;----------------------------------------------------------- SISTAT: MOV BX,DX ADD BX,BX ;X2 ADD BX,BX ;X4 ADD BX,BX ;X8 MOV AX,OFFSET SER0 ADD BX,AX ;POINT TO SERIAL CONTROL BLOCK MOV AH,3 ;STATUS CODE INT 14H ;RS232 INTERRUPT XCHG AH,AL AND AL,RDR JZ SIRET MOV AL,TRUE SIRET: RET ;----------------------------------------------------------- ; SERIAL IN FOR PORTS #1 AND #0 ;----------------------------------------------------------- SPIN3: INC DX SPIN2: INC DX SPIN1: INC DX SPIN0: ;----------------------------------------------------------- ; SERIAL PORT INPUT ; ENTRY: DX = SERIAL PORT NUMBER ; EXIT: AL = RECEIVED CHAR ;----------------------------------------------------------- SERIALIN: CALL SISTAT OR AL,AL JZ SERIALIN MOV AH,02H ;RECEIVE CHAR CODE INT 14H ;RS232 INTERRUPT RET EJECT ;----------------------------------------------------------- ; *** BIOS DISK ROUTINES *** ;----------------------------------------------------------- ; HOME THE DISK HEAD SET TRACK = 0 ;----------------------------------------------------------- HOME: SUB CX,CX ;SET FOR TRACK ZERO CMP SYSWRT,0 ;IS THE BUFFER DIRTY? JNZ SETTRK ;CONTINUE MOV SYSACT,0 ;NO, CLEAR ACTIVE ;----------------------------------------------------------- ; SET TRACK ; ENTRY: CX = TRACK NUMBER ;----------------------------------------------------------- SETTRK: MOV TRACK,CX ;SAVE TRACK CODE RET ;----------------------------------------------------------- ; SET SECTOR ; ENTRY: CX = SECTOR NUMBER ;----------------------------------------------------------- SETSEC: MOV SECTOR,CL ;8 BITS ONLY RET ;----------------------------------------------------------- ; SECTOR TRANSLATION ; ENTRY: CX = LOGICAL SECTOR NUMBER ; EXIT: BX = PHYSICAL SECTOR NUMBER ;----------------------------------------------------------- SECTRAN: MOV BX,CX ;NOT MUCH TO IT RET ;----------------------------------------------------------- ; SET DMA OFFSET ADDRESS ; ENTRY: CX = READ/WRITE TARGET ADDRESS ;----------------------------------------------------------- SETDMA: MOV DMAOFFSET,CX RET ;-----------------------------------------------------------3]=t=tUvu3]áevD)PP"v FYvm .3]ø]à-0Hu]vA .Pvo #!]=t=t=t]U FFFF^;|FûF^vS^3F y F@Fƃ~ ~ FHF3 ]ËF yFvvF F ]U0=FuFhPkPnP!kPvqPmF0= F|P PkPFF0]UNu3]7eu3]]U-츟P+0Ht 40u3-]ø PP[帢PU 3PPFP,FPP +^SF帟P-]U3Pv v +v FFtv PF6iPv PF~u]ñF6iD 0%vt PVtPb+}0tQQt}XFlU]u3]=t3]ø]U츟P3P P"PP0SF~F=t=u]3]U츟PS3P P40HuSP帑P PP]U,PoP|=t]37]U 3Pv v 40t00;u*v V5FF0='0P?HuF0@v VF0@F]Ue#!P=Fu]Ã~uG]6cgP=Fu]Ã~u]Ã~u-0u]U6cPV3]U e Pc7F^03v0=uP,u ]vP vgP F@P5vXF@P?HttP=Fu ]Ã~u vFIvgP=F u ]Ã~ u vF~ u -0t ~ unF*PF0P6c ]UVHu]v0]U5Hu]v Pu]vmFtHuF]vu]v4u]v vcu]ø]U-0uvD\ #!]U3> }->u&vF0%v F 0+ã̡]U츶PpF PF P]U 츺PD帽P;Fw0^;|^0FHAPGPF~|v0 title 'Track Buffered BIOS - SBC204' ; 5 Jan 82 -jrp ; Copyright (C) 1980,1981 ; Digital Research, Inc. ; Box 579, Pacific Grove ; California, 93950 ; ; (Permission is hereby granted to use ; or abstract the following program in ; the implementation of CP/M, MP/M or ; CP/NET for the 8086 or 8088 Micro- ; processor) true equ -1 false equ not true ; Track buffering equates... host_sectsiz equ 128 host_spt equ 26 host_fsn equ 1 bdos_int equ 224 bios_code equ 2500h ccp_offset equ 0000h bdos_ofst equ 0B06h ;BDOS entry point csts equ 0DAh ;i8251 status port cdata equ 0D8h ; " data port lsts equ 41h ;2651 No. 0 on BLC8538 status port ldata equ 40h ; " " " " " data port blc_reset equ 60h ;reset selected USARTS on BLC8538 ;********************************************* ;* * ;* Intel iSBC 204 Disk Controller Ports * ;* * ;********************************************* base204 equ 0a0h ;SBC204 assigned address fdc_com equ base204+0 ;8271 FDC out command fdc_stat equ base204+0 ;8271 in status fdc_parm equ base204+1 ;8271 out parameter fdc_rslt equ base204+1 ;8271 in result fdc_rst equ base204+2 ;8271 out reset dmac_adr equ base204+4 ;8257 DMA base address out dmac_cont equ base204+5 ;8257 out control dmac_scan equ base204+6 ;8257 out scan control dmac_sadr equ base204+7 ;8257 out scan address dmac_mode equ base204+8 ;8257 out mode dmac_stat equ base204+8 ;8257 in status fdc_sel equ base204+9 ;FDC select port (not used) fdc_segment equ base204+10 ;segment address register reset_204 equ base204+15 ;reset entire interface max_retries equ 10 ;max retries on disk i/o ;before perm error cr equ 0dh ;carriage return lf equ 0ah ;line feed cseg org ccpoffset ccp: org bios_code ;********************************************* ;* * ;* BIOS Jump Vector for Individual Routines * ;AST ONE GETONE: CALL GETPARM OR AL,AL JNZ GETONE_RET INC AL GETONE_RET: RET ; ; CURSOR POSITIONING ROUTINES ; AUP: MOV SI,OFFSET VUP ;CURSOR UP JMPS MOVCUR ADOWN: MOV SI,OFFSET VDOWN ;CURSOR DOWN JMPS MOVCUR AFORW: MOV SI,OFFSET VFORW ;CURSOR FORWARD JMPS MOVCUR ABACK: MOV SI,OFFSET VBACK ;CURSOR BACK MOVCUR: PUSH SI CALL GETONE ;GET NUMBER OF POSITIONS INTO CX POP SI MOV CX,AX ;SET THE COUNT MOVCUR1: PUSH SI ;JUST IN CASE PUSH CX CALL SI POP CX POP SI LOOP MOVCUR1 ;KEEP MOVING UNTIL DONE RET ; ; DIRECT CURSOR POSITIONING ROUTINE ; APOS: CALL GETONE DEC AL ;ADJUST MOV DH,AL CALL GETONE DEC AL ;ADJUST MOV DL,AL JMP SETCUR ; ; ERASE ALL/PART OF SCREEN ; AEOS: CALL GETPARM ;GET COMMAND TYPE DEC AL ;ERASE FROM BEGINING OF SCREEN JZ AESBEG DEC AL ;ERASE TO END OF SCREEN JZ AESALL JMP VEOSEND AESBEG: JMP VEOSBEG AESALL: JMP VEOSALL ; ; ERASE ALL/PART OF A LINE ; AEOL: CALL GETPARM ;GET COMMAND TYPE DEC AL JZ AELBEG ;ERASE FROM BEGINNING TO CURSOR DEC AL ;ERASE WHOLE LINE JZ AELALL JMP VEOLEND AELBEG: JMP VEOLBEG AELALL: JMP VEOLALL ; ; SPECIAL VIDEO MODES ; AMODE: CALL GETPARM ;ASSUME ONE JMPS AVMODE0 AVMODE: CALL GETPARM ;GET COMMAND TYPE JBE AVMODE0 ;OK RET AVMODE0: CMP AL,0 ;ALL OFF JNZ AVMODE1 ;NO MOV ATTRIB,07H JMP AVMODE ;CONTINUE AVMODE1: CMP AL,1 ;BOLD? JNZ AVMODE4 ;NO CALL VINTON JMP AVMODE ;CONTINUE AVMODE4: CMP AL,4 JNZ AVMODE5 ;NO CALL VUNLON ;TURNH UNDERLINING ON JMP AVMODE ;CONTINUE AVMODE5: CMP AL,5 JNZ AVMODE7 CALL VBLINKON ;BLINK ON JMP AVMODE AVMODE7: CMP AL,7 JNZ AVMODE8 CALL VREVON ;REVERSE ON JMP AVMODE AVMODE8: CMP AL,8 JNZ AVMODE CALL VCNLON ;CONCEAL ON JMP AVMODE ;CONTINUE ; ; GENERAL PURPOSE SCREEN ERASER ; *JUMP* TO THIS ROUTINE WITH OLD CURSOR ON STACK ; ENTRY: CX = ERASE CHARACTER COUNT ; DX = START ERASE LOCATION ; ERASER: JCXZ ERASER1 ;NOTHING TO DO CALL SETCURSOR MOV AX,0920H ;WRITE SPACES MOV BH,0 ;SCREEN ZERO MOV BL,ATTRIB INT 10H ;VIDEO INTERRUPT ERASER1: POP DX ;RESTORE CURSOR JMP SETCURSOR ;DISPLAY IT ; ; CALCULATE NUMBER OF CHARACTERS FROM TOP LEFT ; CHARCOUNT: MOV AL,CRTCOL MUL DH ;TIMES LINE NUMBER ADD AX,DX ;ADD IN CHAR NUMBER SUB AH,DH ;CORRECT MSB RET EJECT ;----------------------------------------------------------- ; PRINTER OUTPUT - SET THE DEVICE ;----------------------------------------------------------- PRNOUT3: INC DX PRNOUT2: INC DX PRNOUT1: INC DX PRNOUT0: ;----------------------------------------------------------- ; PRINTER CHARACTER OUT ; ENTRY: CL = CHAR ; DX = PRINTER NUMBER ;----------------------------------------------------------- PRNOUT: MOV AH,0 ;PRINT CODE = 0 MOV AL,CL INT 17H ;PRINTER INTERRUPT RET ;----------------------------------------------------------- ; PRINTER STATUS - SET THE DEVICE NUMBER ;----------------------------------------------------------- PRNSTAT3: INC DX PRNSTAT2: INC DX PRNSTAT1: INC DX PRNSTAT0: ;----------------------------------------------------------- ; RETURN PRINTER STATUS ; ENTRY: DX = PRINTER NUMBER ; EXIT: AL = 0FFH IF PRINTER READY ; AL = 0 IF PRINTER BUSY ;----------------------------------------------------------- PRNSTAT: MOV AH,02 ;STATUS CODE INT 17H ;PRINTER INTERRUPT MOV AL,AH SUB AH,AH AND AL,0B9H ;INTERESTING BITS CMP EPROM,0 ;VERSION ZERO? JNZ PRSTAT0 ;NO CMP DX,1 ;EAGLE PRINTER? JA PRSTAT0 ;NO XOR AL,80H ;YES PRSTAT0: CMP AL,90H ;READY PATTERN MOV AL,0FFH ;READY RESPONSE CODE JZ PRSTAT1 ;SKIP IF READY MOV AL,0 ;NOT READY PRSTAT1: MOV BX,AX RET EJECT ;----------------------------------------------------------- ; SERIAL OUTPUT STATUS ;----------------------------------------------------------- SOSTAT3: INC DX SOSTAT2: INC DX SOSTAT1: INC DX SOSTAT0: * * ;********************************************* jmp INIT ;Enter from BOOT ROM or LOADER jmp WBOOT ;Arrive here from BDOS call 0 jmp CONST ;return console keyboard status jmp CONIN ;return console keyboard char jmp CONOUT ;write char to console device jmp LISTOUT ;write character to list device jmp PUNCH ;write character to punch device jmp READER ;return char from reader device jmp HOME ;move to trk 00 on cur sel drive jmp SELDSK ;select disk for next rd/write jmp SETTRK ;set track for next rd/write jmp SETSEC ;set sector for next rd/write jmp SETDMA ;set offset for user buff (DMA) jmp READ ;read a 128 byte sector jmp WRITE ;write a 128 byte sector jmp LISTST ;return list status jmp SECTRAN ;xlate logical->physical sector jmp SETDMAB ;set seg base for buff (DMA) jmp GETSEGT ;return offset of Mem Desc Table jmp GETIOBF ;return I/O map byte (IOBYTE) jmp SETIOBF ;set I/O map byte (IOBYTE) ;print signon message and initialize hardware INIT: mov ax,cs ;we entered with a JMPF so use mov ds,ax ; CS: as the initial value of DS:, mov es,ax ; and ES: mov ss,ax ; use local stack during initialization mov sp,offset stkbase cld ;set forward direction push ds ;save the DS register mov ax,0 mov ds,ax mov es,ax ;set ES and DS to zero ;setup interrupt 0 to address trap routine mov int0_offset,offset int_trap mov int0_segment,CS mov di,4 mov si,0 ;then propagate mov cx,510 ;trap vector to rep movs ax,ax ;all 256 interrupts ;BDOS offset to proper interrupt mov bdos_offset,bdos_ofst pop ds ;restore the DS register ; Initialize the BLC 8538 printer port mov al,0FFh out blc_reset,al ;reset all usarts on 8538 mov al,4Eh out ldata+2,al ;set usart 0 in async 8 bit mode mov al,3Eh out ldata+2,al ;set usart 0 to 9600 baud mov al,37h out ldata+3,al ;enable Tx/Rx, and set up RTS,DTR mov bx,offset signon call pmsg ;print signon message call clear_flags ; initialize track buffering mov cl,0 ;default to dr A: on coldstart jmp ccp ;jump to cold start entry of CCP WBOOT: jmp ccp+6 ;direct entry to CCP at command level int_trap: cli ;block interrupts mov ax,cs mov ds,ax ;get our data segment mov bx,offset int_trp call pmsg hlt ;hardstop ;********************************************* ;* * ;* CP/M Character I/O Interface Routines * ;* Console is Usart (i8251a) on iSBC 86/12 * ;* at ports D8/DA * ;* * ;********************************************* CONST: ;console status in al,csts and al,2 jz const_ret or al,255 ;return non-zero if RDA const_ret: ret ;Receiver Data Available CONIN: ;console input call const jz CONIN ;wait for RDA in al,cdata and al,7fh ;read data and remove parity bit ret CONOUT: ;console output in al,csts and al,1 ;get console status jz CONOUT ;wait for TBE mov al,cl out cdata,al ;Transmitter Buffer Empty ret ;then return data LISTOUT: ;list device output call LISTST jz LISTOUT ;wait for printer not busy mov al,cl out ldata,al ;send char to TI 810 ret LISTST: ;poll list status in al,lsts and al,81h ;look at both TxRDY and DTR cmp al,81h jnz zero_ret ;either false, printer is busy or al,255 ;both true, LPT is ready ret PUNCH: ;not implemented in this configuration READER: mov al,1ah ret ;return EOF for now GETIOBF: mov al,0 ;TTY: for consistency ret ;IOBYTE not implemented SETIOBF: ret ;iobyte not implemented zero_ret: and al,0 ret ;return zero in AL and flags ; Routine to get and echo a console character ; and shift it to upper case uconecho: call CONIN ;get a console character push ax mov cl,al ;save and call CONOUT pop ax ;echo to console cmp al,'a' jb uret ;less than 'a' is ok cmp al,'z' ja uret ;greater than 'z' is ok sub al,'a'-'A' ;else shift to cLINE END ; VNOWRAP: MOV WRAPFLAG,FALSE RET ; ; ESC a - SET VIDEO MODE ; VSETMODE: MOV STATE,OFFSET VSETMOD1 RET VSETMOD1: AND AL,7 ;MASK IT OFF SUB AH,AH INT 10H MOV AH,15 INT 10H MOV CRTCOL,AH ;RESET COLUMNS MOV STATE,OFFSET VIDNORM RET ; ; ESC d - REDIRECT CONSOLE INPUT ; VNEWCONI: MOV AX,OFFSET SYS_CONI JMPS VNEW ; ; ESC e - REDIRECT CONSOLE OUTPUT ; VNEWCONO: MOV AX,OFFSET SYS_CONO JMPS VNEW ; ; ESC f - REDIRECT AUXILARY INPUT ; VNEWAUXI: MOV AX,OFFSET SYS_AUXI JMPS VNEW ; ; ESC g - REDIRECT AUXILARY OUTPUT ; VNEWAUXO: MOV AX,OFFSET SYS_AUXO JMPS VNEW ; ; ESC h - REDIRECT LIST OUTPUT ; VNEWLST: MOV AX,OFFSET SYS_LST ; JMPS VNEW ;FALL THROUGH ; ; REDIRECT ANY I/O DEVICE VECTOR ; ENTRY: AX -> A PARTICULAR VECTOR ; VNEW: MOV DELTAVEC,AX ;VECTOR TO CHANGE MOV STATE,OFFSET VNEW1 RET ;WAIT FOR NEXT CHAR ; ; NEXT STATE ; VNEW1: AND AL,7FH ;MASK IT OFF MOV DELTALO,AL ; MOV STATE,OFFSET VNEW2 ;NEXT TIME RET ;WAIT FOR ONE MORE ; ; LAST STATE VNEW2: MOV AH,AL AND AX,7F00H ;MASK OFF AND ZERO LOW ORDER SHR AX,1 ;ADJUST IT ADD AX,WORD PTR DELTALO ;COMBINE THE LOW ORDER MOV BX,DELTAVEC ;GET THE VECTOR TO CHANGE MOV [BX],AX ;SET IT MOV STATE,OFFSET VIDNORM RET ;BACK TO NORMAL ; ; ESC ? - GIVE DATE/TIME/MESSAGE ; VDATE: PUSH DS POP ES ;JUST IN CASE MOV SI,OFFSET AMONTH MOV DI,OFFSET KEYBUF MOV KEYPTR,DI MOV CX,32 REP MOVSB RET ; ; ESC i - SET TRANSPARENT MODE ; VTRANS: MOV STATE,OFFSET VTRANS1 RET VTRANS1: AND AL,1 MOV VTMFLAG,AL ;SET THE FLAG MOV STATE,OFFSET VIDNORM RET ;AND LEAVE ; ; ESC : - SET PROGRAMMABLE FUNCTION KEYS ; VPFK: MOV STATE,OFFSET EPFK1 RET ;READY FOR KEY CODE ; ; GET KEY SCAN CODE ; EPFK1: MOV STATE,OFFSET VIDNORM ;DEFAULT CALL GETPFK ;AX -> PFK ENTRY JC EPFK1A ;SKIP IF ILLEGAL ; MOV EPFKPTR,BX ;SAVE POINTER MOV EPFKCOUNT,CL ;SAVE CHAR COUNT MOV STATE,OFFSET EPFK2 ;ADVANCE EPFK1A: RET ; ; GET THE STRING ; EPFK2: MOV BX,EPFKPTR ;POINT TO ENTRY MOV [BX],AL ;STORE CHAR DEC EPFKCOUNT JZ EPFK2A ;SKIP IF FILLED ; TEST CL,CL ;OR IF CHAR = 0 JZ EPFK2A ; INC EPFKPTR ;BUMP THE POINTER FOR NEXT TIME RET ;KEEP VIDSTATE ; PROCESS COMPLETE EPFK2A: MOV STATE,OFFSET VIDNORM RET ;TO NORMALCY ; ; SET FOR ANSI SEQUENCE ; ANSI: MOV BX,OFFSET PARMS ;YES, GET PARAMETER POINTER MOV PRMPNT,BX ;SETUP IN POINTER INDEX MOV BYTE PTR [BX],0 ;CLEAR FIRST ENTRY MOV STATE, OFFSET ANSI3 ;SET THE STATE RET ; ; ANSI STATE, ENTERED ON OR MORE TIMES FOR PARAMETER PASSING ; ANSI3: MOV SI,PRMPNT CMP AL,';' ;LOOK FOR DECIMAL # SEPERATOR JNZ ANSI3B ;NO INC SI ;POINT TO NEXT MOV AX,OFFSET LASTPRM ;RANGE CHECK CMP SI,AX JBE ANSI3A ;YES MOV SI,AX ;NO, OUT OF RANGE ANSI3A: MOV PRMPNT,SI MOV BYTE PTR [SI],0 ;PRE-INITIALIZE IT TO ZERO RET ; ; CHECK FOR ASCII DIGITS ; ANSI3B: CMP AL,'0'  ;CHECK FOR ASCII DIGIT JB ANSI3C ;NO, CHECK FOR CODE CMP AL,'9' ;STILL CHECKING FOR ASCII DIGIT JA ANSI3C ; SUB AL,'0' ;CONVERT XCHG [SI],AL ;GET EXISTING # MOV AH,10 ;SCALE BY 10 MUL AH ADD [SI],AL ;ADD TO NEW DIGIT RET ; ; WASN'T A DIGIT. CHECK FOR COMMAND ; ANSI3C: MOV ENDANSI,AL ;SET THE END OF TABLE MOV ENDPRM,SI ;SAVE THE LAST (MAX) PNTR MOV PRMPNT,OFFSET PARMS MOV SI,OFFSET ANSITBL-3 ;GET START OF COMMAND TABLE ; GO TO THE CORRECT ROUTINE DISPATCH: MOV DX,CURSOR ;SETUP THE CURSOR MOV STATE,OFFSET VIDNORM ;CLEAR THE STATE INCASE DISPATCH1: ADD SI,3 ;UPDATE COMMAND TABLE POINTER CMP AL,[SI] ;CHECK FOR VALID COMMAND JNZ DISPATCH1 ;NO, KEEP CHECKING JMP WORD PTR 1[SI] ;YES, TRANSFER TO THAT ROUTINE ; ; GET BINARY PARAMETER FROM STORAGE ; GETPARM: MOV SI,PRMPNT ;GET PARAMETER POINTER MOV AL,[SI] INC SI CMP SI,ENDPRM ;MAX? JA GETPARM_RET MOV PRMPNT,SI GETPARM_RET: RET ; MAKE SURE VALUE IS AT LEaps uret: ret ; utility subroutine to print messages pmsg: mov al,[BX] ;get next char from message test al,al jz return ;if zero return mov CL,AL call CONOUT ;print it inc BX jmps pmsg ;next character and loop ;********************************************* ;* * ;* Disk Input/Output Routines * ;* * ;********************************************* SELDSK: ;select disk given by register CL mov cpm_disk,cl ; save the selected drive mov bx,0000h cmp cl,2 ;this BIOS only supports 2 disks jnb return ;return w/ 0000 in BX if bad drive ;now, we need disk parameter address mov ch,0 mov bx,cx ;BX = word(CL) mov cl,4 shl bx,cl ;multiply drive code * 16 add bx,offset dp_base ;create offset from Disk Parameter Base return: ret home: test wr_flag,1 ! jnz home1 ; if the buffer is clean, mov cur_disk,-1 ; insure we read the directory by invalidating ;  the track buffer home1: mov cx,0 ; home is a settrk zero settrk: mov cpm_track,cx ; save track number for next operation ret setsec: mov cpm_sec,cx ; save sector number for next operation ret setdma: mov dma_offset,cx ; save DMA offset address ret setdmab: mov dma_segment,cx ; save DMA segment address ret sectran: mov bx,cx ; Put logical sector into dest. reg. test dx,dx ; see if table address is zero jz sectran_exit ; yeah, logical = physical add bx,dx ; else, we need to fetch the mov bl,[BX] ; actual sector number from the table mov bh,0 ; zero high byte for good luck sectran_exit: ret GETSEGT: ;return address of physical memory table mov bx,offset seg_table ret read: call track_setup push es ; save the extra segment register mov si,offset track_buffer ; source segment is systems DS: add si,ax ; gives the offset into the buffer les di,dma_longword ; point ES:DI at the users sector rep movsw ; doit pop es ; restore the extra segment sub ax,ax ; make a zero return code ret write: push cx ; save the write mode from the BDOS call track_setup push ax ; save buffer offset push ds ; save the data segment push es ; save the extra segment mov bx,ds ! mov es,bx ; destination is our data segment mov di,offset track_buffer ; destination is in track buffer add di,ax ; plus appropriate offset lds si,dma_longword ; source is users DMA address rep movsw ; move that sector pop es ; restore the extra segment pop ds ; and the data segment registers pop ax ; recover buffer offset mov cx,host_sectsiz ; setup to divide by host sector size sub dx,dx ; extend ax to 32 bits div cx ; find out which host sector we changed mov bx,ax ; put into index [BX] mov sec_flags[BX],1 ; set the update flag for that sector mov wr_flag,1 ; also set the dirty buffer flag pop cx ; recover BDOS write code cmp cl,1 ; is this a directory update ? jne write_return ; no, we may leave dirty records ; in the buffer call flush_buffer ; we have a directory write, need to ; flush the buffer to insure the ; disks integrity write_return: sub ax,ax ; never return BAD SECTOR code ret track_setup: ; common code for setting up reads and writes mov al,cpm_disk ; see if selected disk is cmp al,cur_disk ; the same as last time jne wrong_track ; no, we have wrong track mov ax,cpm_track ; see if desired track is same as cmp ax,cur_track ; the track in the buffer je correct_track ; same drive and track, we don't need to read ; Desired operation is on a different track then is in our buffer, ; So it will be nessecary to read in the desired track. First, we ; must check to see if any sectors of the current buffer are dirty. wrong_track: call flush_buffer ; write any old records, if nessecary mov ax,cpm_track ; get desired track number mov cur_track,ax ; make in new track mov al,cpm_disk ; get desired disk number movR ;FOR LOCAL SHORT ; ; ESC A - CURSOR UP ; VUP: DEC DH ;ROW = ROW - 1 JNS SETCUR ;IF POS, SET CURSOR RET ;ELSE FORGET IT ; ; ESC B - CURSOR DOWN ; VDOWN: INC DH ;ROW = ROW + 1 CMP DH,CRTROW ;TOO FAR ? JB SETCUR ;IF NOT, SET CURSOR RET ;ELSE IGNORE IT ; ; ESC C - CURSOR FORWARD ; VFORW: INC DL ;COL = COL + 1 CMP DL,CRTCOL ;TOO FAR ? JB SETCUR ;IF NOT, SET CURSOR RET ;ELSE SKIP IT ; ; ESC D - CURSOR BACKWARD ; VBACK: DEC DL JNS SETCUR RET ; ; ESC j - SAVE CURSOR LOC ; VSAVCUR: MOV SAVECURSOR,DX ;STASH IT RET ; ; ESC k - RESTORE CURSOR LOC ; VRSTCUR: MOV DX,SAVECURSOR ;GET IT BACK JMP SETCUR ;AND SET IT ; ; ESC Y - SET CURSOR ; VSETCUR: MOV STATE,OFFSET VSET1 RET ;LOOK FOR NEXT CHAR ; VSET1: SUB AL,' ' ;CORRECT JNS VSET1A ;SKIP IF POSITIVE MOV AL,0 ;ELSE TOP ROW VSET1A: CMP AL,CRTROW JB VSET1B ;SKIP IF OK MOV AL,CRTROW ;ELSE PAGE BOTTOM DEC AL VSET1B: MOV CURHOLD,AL ;SAVE CURSOR ROW MOV STATE,OFFSET VSET2 RET ;READY FOR COLUMN ; VSET2: SUB AL,' ' ;CORRECT JNS VSET2A ;SKIP IF POSITIVE MOV AL,0 ;ELSE FIRST COL VSET2A: CMP AL,CRTCOL JB VSET2B ;SKIP IF OK MOV AL,CRTCOL ;ELSE LAST COL DEC AL VSET2B: MOV DH,CURHOLD ;GET THE VALUE MOV DL,AL ;UPDATE ROW MOV STATE,OFFSET VIDNORM JMP SETCURSOR ;MOVE CURSOR NOW ; ; ESC E - ERASE THE SCREEN ; VEOSALL: CALL VHOME ;GET TO TOP LEFT MOV AX,0920H ;WRITE SPACES MOV BX,WORD PTR ATTRIB MOV CX,CRTSIZE INT 10H ;VIDEO INTERRUPT RET ; ; ESC d - ERASE BEGINNING OF SCREEN TO CURSOR ; VEOSBEG: PUSH DX ;SAVE CURSOR CALL CHARCOUNT ;AX = NUM TO ERASE MOV CX,AX INC CX MOV DX,0 ;SCREEN START JMP ERASER ; ; ESC J - ERASE TO END OF SCREEN ; VEOSEND: PUSH DX ;SAVE CURSOR CALL CHARCOUNT ;CHARS FROM TOP LEFT MOV CX,CRTSIZE SUB CX,AX ;CHARS TO END JMP ERASER ; ; ESC l - ERASE ENTIRE LINE ; VEOLALL: PUSH DX ;SAVE CURSOR MOV DL,0 ;FRONT OF LINE MOV CX,WORD PTR CRTCOL JMP ERASER ; ; ESC o - ERASE BEGINNING OF LINE TO CURSOR ; VEOLBEG: PUSH DX INC DL MOV CL,DL ;CHAR COUNT MOV CH,0 MOV DL,0 JMP ERASER ; ; ESC K - ERASE TO END OF LINE ; VEOLEND: PUSH DX MOV CX,WORD PTR CRTCOL SUB CL,DL ;CHAR COUNT JMP ERASER ; ; ESC b - SET FOREGROUND COLOR ; VFRGND: MOV STATE,OFFSET VFRGND1 RET ;GET NEXT CHAR ; VFRGND1: MOV AH,ATTRIB JMPS VFGBG ;COMMON ROUTINE ; ; ESC c - SET BACKGROUND COLOR ; VBKGND: MOV STATE,OFFSET VBKGND1 RET ; VBKGND1: MOV AH,AL MOV CL,4 ROL AH,CL ;MOVE TO MSB'S MOV AL,ATTRIB VFGBG: AND AL,0FH ;LSB'S ONLY AND AH,0F0H ;MSB'S ONLY OR AL,AH ;MASH 'EM MOV ATTRIB,AL MOV STATE,OFFSET VIDNORM RET ; ; ESC m - TURN CURSOR ON ; VCURON: MOV CURFLAG,TRUE ;TURN ON THE FLAG CURON: MOV CX,CURTYPE ;NORMAL LINES JMPS VIDOFF ;COMMON ROUTINE ; ; ESC n - TURN CURSOR OFF ; VCUROFF: MOV CURFLAG,FALSE ;TURN OFF THE FLAG CUROFF: MOV CX,2E0FH ;BELOW THE HORIZON VIDOFF: MOV AH,01 ;CURSOR TYPE CODE INT 10H ;VIDEO INTERRUPT RET ; ; ESC p - REVERSE VIDEO ON ; VREVON: AND ATTRIB,0F8H ;BLACK FOREGROUND OR ATTRIB,070H ;WHITE BACKGROUND RET ; ; ESC q - REVERSE VIDEO OFF ; VREVOFF: AND ATTRIB,08FH ;BLACK BACKGROUND OR ATTRIB,007H ;WHITE FOREGROUND RET ; ; ESC s - TURN BLINK ON ; VBLINKON: OR ATTRIB,80H RET ; ; ESC t - TURN BLINK OFF ; VBLINKOFF: AND ATTRIB,7FH RET ; ; ESC r - TURN THE INTENSITY ON ; VINTON: OR ATTRIB,08H RET ; ; ESC u - TURN DOWN THE INTENSITY ; VINTOFF: AND ATTRIB,0F7H RET ; ; ESC x - UNDERLINE ON ; VUNLON: AND ATTRIB,0F8H OR ATTRIB,1 RET ; ; ESC y - UNDERLINE OFF ; VUNLOFF: OR ATTRIB,7 RET ; ; ESC W - CONCEALED ON ; VCNLON: AND ATTRIB,88H RET ; ; ESC X - CONCEALED OFF ; VCNLOFF: AND ATTRIB,88H OR ATTRIB,07H RET ; ; ESC v - WRAP AROUND AT LINE END ; VWRAP: MOV WRAPFLAG,TRUE RET ; ; ESC w - NO WRAP AT  cur_disk,al ; make it current drive mov cur_dma_adr,offset track_buffer ; point dma offset at track buffer mov cur_sec,host_fsn ; starting from first sector call track_read ; load the track correct_track: mov ax,cpm_sec ; get the cp/m sector number if (host_fsn ne 0) sub ax,host_fsn ; correct if we start with sector one endif mov cl,7 ; log2(128) shl ax,cl ; sector times 128 gives offset mov cx,64 ! cld ; move 64 words forward ret flush_buffer: test wr_flag,1 ; see if we have anything to write jz no_flush ; no, skip scanning for dirty sectors mov bx,host_fsn ; start at first host sector mov cx,host_spt ; for host_spt sectors... next_sect: test sec_flags-host_fsn[BX],1 ; see if this sector has been changed jz not_updated ; no, leave it alone mov sec_flags-host_fsn[BX],0 ; zero the flag for next time push bx ; save the registers push cx mov cur_sec,bx ; save host sector number mov ax,host_sectsiz if (host_fsn ne 0) sub bx,host_fsn endif mul bx ; make track buffer offset add ax,offset track_buffer ; make direct pointer mov cur_dma_adr,ax ; save for write routine call sector_write pop cx pop bx not_updated: inc bx loop next_sect no_flush: mov wr_flag,0 ; clear the dirty buffer flag ret clear_flags: ; Clear all variables associated with the track buffer, ; so next operation will have to read a track. ; This is involves clearing all write flags and setting ; the old drive code to the invalid -1. push es ; save extra segment mov cur_disk,-1 ; insure initial pre-read sub ax,ax ; make a zero mov wr_flag,al ; clear the dirty buffer flag mov di,offset sec_flags ; point to the update flag list mov bx,ds ! mov es,bx ; ES <- DS mov cx,host_spt ! cld ; set length and direction rep stosb ; zero the sector update flags mov cur_dma_seg,ds ; get our segment address pop es ; recover extra segment ret track_READ: mov io_com,4 ; read track takes 4 byte command mov io_com+1,13h ; special read track command jmps r_w_common sector_WRITE: mov io_com,3 ; write sector takes 3 byte command mov io_com+1,0ah ; basic write sector command r_w_common: cmp cur_disk,1 ! jne not_first_b ; see if drive B test b_first_flag,-1 ! jz not_first_b ; and first reference to B call restore ; then restore drive B mov b_first_flag,0 ; and clear flag not_first_b: mov bx,offset io_com ;point to command string mov ax,cur_sec ; put sector in mov sect,al ; iopb as 8 bits mov ax,cur_track ; same with mov trk,al ; track . . ; fall into execute and return execute: ;execute command string. ;[BX] points to length, ; followed by Command byte, ; followed by length-1 parameter bytes mov last_com,BX ;save command address for retries outer_retry: ;allow some retrying mov rtry_cnt,max_retries retry: mov BX,last_com call send_com ;transmit command to i8271 ; check status poll mov BX,last_com mov al,1[bx] ;get command op code mov cx,0800h ;mask if it will be "int req" cmp al,2ch jb exec_poll ;ok if it is an interrupt type mov cx,8080h ;else we use "not command busy" and al,0fh cmp al,0ch ;unless there isn't mov al,0 ja exec_exit ; any result ;poll for bits in CH, exec_poll: ; toggled with bits in CL in al,fdc_stat ;read status and al,ch xor al,cl ; isolate what we want to poll jz exec_poll ;and loop until it is done ;Operation complete, in al,fdc_rslt ; see if result code indicates error and al,1eh jz exec_exit ;no error, then exit ;some type of error occurred . . . cmp al,10h je dr_nrdy ;was it a not ready drive ? ;no, dr_rdy: ; then we just retry read or write push ax ; save error code call restore ; after physically homing this disk pop ax ; recover error code dec rtry_cnt jnz retry ; up to 10 times ; retries do not recover from the ; hard error mov ah,0 mov bx,ax ;make error code 16 bits mov bx,errtbl[BX] call pmsg ;print appropriate messag----------------------------- ; KEYBOARD INPUT ; EXIT: AL = CHAR ;----------------------------------------------------------- KEYIN: NOP KEYIN1: MOV BX,KEYPTR ;CHECK KEY BUFFER MOV AL,[BX] ;GET THE CHARACTER TEST AL,AL ;RETURN BUF CHAR JZ KEYIN3 ;ELSE READ KEYBOARD INC KEYPTR KEYIN2: MOV BX,AX ;JUST IN CASE RET KEYIN3: SUB AH,AH ;READ CODE = 0 INT 16H ;KEYBOARD INTERRUPT OR AL,AL JNZ KEYIN2 ;RETURN IF ASCII ; ; CHECK FOR PROGRAMMABLE FUNCTION KEYS ;  MOV AL,AH ;GET KEY CODE CALL GETPFK ;AX -> PFK ENTRY JC KEYIN3 ;C SET IF ILLEGAL ; PUSH SI PUSH DI MOV SI,BX ;TABLE POINTER MOV DI,OFFSET KEYBUF MOV KEYPTR,DI ;CHECKED AT ENTRY REP MOVSB ;MOVE TO KEYBUFFER POP DI POP SI JMPS KEYIN1 ;START IT ;----------------------------------------------------------- ; POINT TO PFK ENTRY - SHARED BY ESCAPE ':' ; SET CARRY IF NOT A LEGAL PFK ; RETURNS WITH [DI] = TABLE ENTRY ;----------------------------------------------------------- GETPFK: PUSH DI ;SAVE PUSH SI MOV SI,OFFSET PFKSCAN MOV CX,(-2)[SI] ;GET THE COUNT MOV DX,(-4)[SI] ;BLOCK SIZE MOV DI,(-6)[SI] ;GET THE TABLE OFFSET GETPFK1: CMP [SI],AL ;IS THIS IT JZ GETPFK2 ;YES INC SI ;NO ADD DI,DX LOOP GETPFK1 ;KEEP IT UP STC ;NO GETPFK2: MOV BX,DI ;POINTER IN BX MOV CX,DX ;SIZE IN CX POP SI POP DI RET EJECT ;----------------------------------------------------------- ; VIDEO SCREEN DRIVERS ; ; BEFORE ENTERING THE ROUTINES, GET ; A CURSOR POSITION REPORT FROM THE EPROM ; ROUTINES - THIS IS IN CASE SOMEONE WRITES ; TO THE SCREEN DIRECTLY. ;----------------------------------------------------------- VIDOUT: PUSH CX ;SAVE THE CHARACTER MOV AH,3 SUB BX,BX INT 10H ;READ CURSOR MOV CURSOR,DX ;SET IT POP AX ;RESTORE CHARACTER JMP STATE ; ; NORMAL ASCII VIDEO VECTOR ; CHARACTER IS IN THE AL REGISTER ; VIDNORM: CMP AL,ESC JNZ VIDNORM1 ;NO JMP VIDESC ;YES VIDNORM1: TEST VTMFLAG,1 ;TRANSPARENT MODE? JNZ VIDASCII ;YES CMP AL,BS JZ VIDBS ;BACK SPACE CMP AL,LF JZ VIDLF ;LINE FEED CMP AL,CR JZ VIDCR ;CARRIAGE RETURN CMP AL,BEL JZ BEEP ;BEEPER ; ; PRINTABLE ASCII CHARACTERS FALL THROUGH ; VIDASCII: MOV AH,9 ;WRITE CODE MOV BX,WORD PTR ATTRIB ;CHARCTER ATTRIBUTE AND PAGE MOV CX,1 ;ONE COPY OF CHAR INT 10H ;VIDEO INTERRUPT ; INC DL ;NEXT COLUMN CMP DL,CRTCOL ;PAST THE EDGE ? JB SETCURSOR ;IF NOT, SKIP ; ; TEST FOR END OF LINE WRAP AROUND ; TEST WRAPFLAG,TRUE JZ VIDRETURN ;IF NO WRAP, DONE ; CALL VIDCR ;ELSE, DO A RETURN ;FALL INTO A LINE FEDD ; ; VIDEO LINE FEED ; VIDLF: INC DH ;NEXT LINE CMP DH,CRTROW ;AT PAGE END ? JB SETCURSOR ;IF NOT, SKIP ; MOV AX,0601H ;SCROLL ONE LINE MOV BH,ATTRIB MOV CX,0000H ;UPPER LEFT CORNER MOV DH,CRTROW DEC DH MOV DL,CRTCOL DEC DL INT 10H ;VIDEO INTERRUPT VIDRETURN: RET ; ; VIDEO CARRIAGE RETURN ;  VIDCR: MOV DL,0 ;FIRST COLUMN SETCURSOR: MOV CURSOR,DX ;UPDATE OUR COPY MOV AH,2 ;SET COURSOR CODE MOV BH,0 ;PAGE 0 INT 10H ;VIDEO INTERRUPT RET ; ; USE PROM TTY ROUTINE FOR BEEP ; BEEP: MOV AX,0E07H ;ROUTINE AND CHARACTER MOV BX,WORD PTR ATTRIB ;CHARCTER ATTRIBUTE AND PAGE MOV CX,1 ;ONE COPY OF CHAR INT 10H ;VIDEO INTERRUPT RET ; ; VIDEO BACK SPACE ; VIDBS: DEC DL ;BACK ONE COLUMN JNS SETCURSOR ;IF POS, NO PROB ; TEST WRAPFLAG,TRUE ;IF NO WRAP AROUND  JZ VIDRETURN ; THEN FORGET IT ; DEC DH ;IF TOP ROW, JS VIDRETURN ; THEN FORGET IT MOV DL,CRTCOL ;ELSE WRAP AROUND DEC DL JMPS SETCURSOR ; ; VIDEO ESCAPE - SET UP STATE VECTOR ; VIDESC: MOV STATE,OFFSET VIDESC1 RET ;READY FOR NEXT CHAR ; ; CHARACTER AFTER ESCAPE COMES HERE ; VIDESC1: MOV ENDESC,AL ;SET THE END POINT MOV SI,OFFSET ESCTBL-3 ;POINT TO CORRECT TABLE JMP DISPATCH ; ; ESC H - HOME CURSOR ; VHOME: SUB DX,DX ;0,0 = TOP LEFT SETCUR: JMP SETCURSOe in al,cdata ;flush usart receiver buffer call uconecho ;read upper case console character cmp al,'C' je wboot_l ;cancel cmp al,'R' je outer_retry ;retry 10 more times cmp al,'I' je z_ret ;ignore error or al,255 ;set code for permanent error exec_exit: ret dr_nrdy: ;here to wait for drive ready call test_ready jnz retry ;if it's ready now we are done call test_ready jnz retry ;if not ready twice in row, mov bx,offset nrdymsg call pmsg ;"Drive Not Ready" nrdy01: call test_ready jz nrdy01 ;now loop until drive ready jmps retry ;then go retry without decrement zret: and al,0 ret ;return with no error code wboot_l: ;can't make it w/ a short leap jmp WBOOT ;********************************************* ;* * ;* The i8271 requires a read status command * ;* to reset a drive-not-ready after the * ;* drive becomes ready * ;* * ;********************************************* test_ready: mov dh, 40h ;proper mask if dr 1 test sel_mask,80h jnz nrdy2 mov dh, 04h ;mask for dr 0 status bit nrdy2: mov bx,offset rds_com call send_com dr_poll: in al,fdc_stat ;get status word test al,80h jnz dr_poll ;wait for not command busy in al,fdc_rslt ;get "special result" test al,dh ;look at bit for this drive ret ;return status of ready restore: ;move selected disk to home position (Track 0) mov bx,offset hom_com call execute jz restore_exit ;home drive and return if OK mov bx,offset bad_hom ;else print call pmsg ;"Home Error" jmps restore ;and retry restore_exit: ret ;********************************************* ;* * ;* Send_com sends a command and parameters * ;* to the i8271: BX addresses parameters. * ;* The DMA controller is also initialized * ;* if this is a read or write * ;* * ;********************************************* send_com: in al,fdc_stat test al,80h ;insure command not busy jnz send_com ;loop until ready ;see if we have to initialize for a DMA operation mov al,1[bx] ;get command byte cmp al,13h jne write_maybe ;if not a read it could be write mov cl,40h jmps init_dma ;is a read command, go set DMA write_maybe: cmp al,0ah jne dma_exit ;leave DMA alone if not read or write mov cl,80h ;we have write, not read init_dma: ;we have a read or write operation, setup DMA controller ; (CL contains proper direction bit) mov al,04h out dmac_mode,al ;enable dmac mov al,00 out dmac_cont,al ;send first byte to control port mov al,cl out dmac_cont,al ;load direction register mov ax,cur_dma_adr out dmac_adr,al ;send low byte of DMA mov al,ah out dmac_adr,al ;send high byte mov ax,cur_dma_seg out fdc_segment,al ;send low byte of segment address mov al,ah out fdc_segment,al ;then high segment address dma_exit: mov cl,[BX] ;get count inc BX mov al, 80h cmp cur_disk,0 jne sel1 ;drive 1 if not zero mov al, 40h ;else drive is 0 sel1: mov sel_mask,al ; save select mask or al,[BX] ;merge command and drive code out fdc_com,al ;send command byte parm_loop: dec cl jz parm_exit ;no (more) parameters, return inc BX ;point to (next) parameter parm_poll: in al,fdc_stat test al,20h ;test "parameter register full" bit jnz parm_poll ;idle until parm reg not full mov al,[BX] out fdc_parm,al ;send next parameter jmps parm_loop ;go see if there are more parameters parm_exit: ret ;********************************************* ;* * ;* Data Areas * ;* * ;********************************************* data_offset equ offset $ dseg org data_offset ;contiguous with code segment signon db cr,lf,cr,lf db ' CP/M-86, 1 Feb 82 ',cr,lf,0 bad_hom db cr,lf,'Home Error',cr,lf,0 intNDARD JMPS LSTOUT3 CMP CH,LPT_SIZE LSTOUT3: JB LSTOUT2 ;KEEP TRYING RET ;ALL DONE ; NOTHING ELSE TO DO LSTOUT4: MOV DX,SYS_LST JMPS XOUTPUT ;----------------------------------------------------------- ; LIST STATUS ;----------------------------------------------------------- LISTAT: MOV DX,SYS_LST JMPS XOSTATUS EJECT ;----------------------------------------------------------- ; CONSOLE INPUT ;----------------------------------------------------------- CONIN: MOV DX,SYS_CONI JMPS XINPUT ;COMMON INPUT ;----------------------------------------------------------- ; CONSOLE OUTPUT ;----------------------------------------------------------- CONOUT: MOV DX,SYS_CONO JMPS XOUTPUT ;COMMON OUTPUT ;----------------------------------------------------------- ; CONSOLE STATUS ;----------------------------------------------------------- CONSTAT: MOV DX,SYS_CONI JMPS XISTATUS ;----------------------------------------------------------- ; AUXILARY INPUT ;----------------------------------------------------------- ; AUXIN: MOV DX,SYS_AUXI JMPS XINPUT ;COMMON INPUT ;----------------------------------------------------------- ; AUXILARY OUTPUT ;----------------------------------------------------------- AUXOUT: MOV DX,SYS_AUXO JMPS XOUTPUT ;COMMON OUTPUT EJECT ;----------------------------------------------------------- ; COMMON CHARACTER INPUT ROUTINE ;----------------------------------------------------------- XINPUT: MOV BX,OFFSET INROUTINES MOV AL,1AH XINPUT1: TEST DX,1 ;IS THIS IT? JZ XINPUT2 ;THATS IT SUB DX,DX JMP WORD PTR [BX] ;TRANSFER TO FIRST ROUTINE XINPUT2: INC BX ;NEXT ROUTINE INC BX SHR DX,1 JNZ XINPUT1 RET ;----------------------------------------------------------- ; COMMON INPUT STATUS ;----------------------------------------------------------- XISTATUS: MOV BX,OFFSET INSTATUS MOV AL,TRUE ;ASSUME READY XISTAT1: TEST DX,1 ;IS THIS IT? JZ XISTAT2  ;THATS IT SUB DX,DX ;CLEAR JMP WORD PTR [BX] ;GO TO THE ROUTINE XISTAT2: INC BX ;NEXT ROUTINE INC BX SHR DX,1 JNZ XISTAT1 RET EJECT ;----------------------------------------------------------- ; COMMON CHARACTER OUTPUT ROUTINE ;----------------------------------------------------------- XOUTPUT: MOV BX,OFFSET OUTROUTINES XOUTPUT1: TEST DX,1 ;IS THIS IT? JZ XOUTPUT2 ;THATS IT PUSH BX PUSH CX PUSH DX SUB DX,DX CALL WORD PTR [BX] ;TRANSFER TO THAT ROUTINE POP DX POP CX POP BX XOUTPUT2: INC BX ;CHECK FOR NEXT INC BX SHR DX,1 JNZ XOUTPUT1 ;AGAIN RET ;NOW LEVAVE ;----------------------------------------------------------- ; COMMON INPUT STATUS ;----------------------------------------------------------- XOSTATUS: MOV BX,OFFSET OUTSTATUS XOSTAT1: TEST DX,1 ;IS THIS IT? JZ XOSTAT2 ;THATS IT PUSH BX PUSH DX SUB DX,DX CALL WORD PTR [BX] POP DX POP BX TEST AL,AL ;IS IT READY? JZ XOSTAT3 ;NO XOSTAT2: INC BX INC BX SHR DX,1 JNZ XOSTAT1 ;AGAIN MOV AL,TRUE ;ALL DEVICES ARE READY OR AL,AL XOSTAT3: RET ;NOW LEVAVE EJECT ;----------------------------------------------------------- ; NULL INPUT/OUTPUT ROUTINES ;----------------------------------------------------------- VIDSTAT: NULLST: MOV AL,TRUE ;NULL STATUS - ALWAYS READY OR AL,AL RET NULLI: MOV AL,1AH ;END OF FILE NULLO: RET ;JUST LEAVE ;----------------------------------------------------------- ; KEYBOARD STATUS ; EXIT: AL = 0FFH IF CHAR READY ; AL = 0 IF NOT READY ;----------------------------------------------------------- KEYSTAT: PUSH SI MOV SI,KEYPTR ;CHECK PFK BUFFER MOV AL,[SI] ;CHAR FROM BUFFER POP SI TEST AL,AL ;VALID IF NOT ZERO JNZ KEYSTAT1 ;SKIP IF READY ; MOV AH,01H ;STATUS CODE INT 16H ;KEYBOARD INTERRUPT MOV AL,0 ;ASSUME NOT READY JZ KEYSTAT2 KEYSTAT1: MOV AL,TRUE ;CHARACTER READY KEYSTAT2: RET ;------------------------------_trp db cr,lf,'Interrupt Trap Halt',cr,lf,0 errtbl dw er0,er1,er2,er3 dw er4,er5,er6,er7 dw er8,er9,erA,erB dw erC,erD,erE,erF er0 db cr,lf,'Error Code 0 :',0 er1 db cr,lf,'Error Code 1 :',0 er2 db cr,lf,'Error Code 2 :',0 er3 db cr,lf,'Error Code 3 :',0 er4 db cr,lf,'Clock Error :',0 er5 db cr,lf,'Late DMA :',0 er6 db cr,lf,'ID CRC Error :',0 er7 db cr,lf,'Data CRC Error :',0 er8 db cr,lf,'Drive Not Ready :',0 er9 db cr,lf,'Write Protect :',0 erA db cr,lf,'Track 00 Not Found :',0 erB db cr,lf,'Write Fault :',0 erC db cr,lf,'Sector Not Found :',0 erD db cr,lf,'Error Code D :',0 erE db cr,lf,'Error Code E :',0 erF db cr,lf,'Error Code F :',0 nrdymsg equ er8 b_first_flag db -1 rtry_cnt db 0 ;disk error retry counter last_com dw 0 ;address of last command string cur_dma_adr dw 0 ;dma offset stored here cur_dma_seg dw 0 ;dma segment stored here sel_mask db 40h ;select mask, 40h or 80h ; Various command strings for i8271 io_com db 3 ;length (changed to 4 to read a track) rd_wr db 0 ;read/write function code trk db 0 ;track # sect db 0 ;sector # sec_len db 26 ;transfer 26 sectors on a track read hom_com db 2,29h,0 ;home drive command rds_com db 1,2ch ;read status command ; Track buffering variables cpm_disk rb 1 cpm_track rw 1 cpm_sec rw 1 cur_disk rb 1 cur_track rw 1 cur_sec rw 1 dma_offset rw 1 dma_segment rw 1 dma_longword equ dword ptr dma_offset bdos_wr_code rb 1 wr_flag rb 1 ; System Memory Segment Table segtable db 2 ;2 segments dw tpa_seg ;1st seg starts after BIOS dw tpa_len ;and extends to 08000 dw 1000h ;second is 10000 - dw 1000h ;1FFFF (64k) ; include singles.lib ;read in disk definitions ; DISKS 2 dpbase equ $ ;Base of Disk Parameter Blocks dpe0 dw xlt0,0000h ;Translate Table dw 0000h,0000h ;Scratch Area dw dirbuf,dpb0 ;Dir Buff, Parm Block dw csv0,alv0 ;Check, Alloc Vectors dpe1 dw xlt1,0000h ;Translate Table dw 0000h,0000h ;Scratch Area dw dirbuf,dpb1 ;Dir Buff, Parm Block dw csv1,alv1 ;Check, Alloc Vectors ; DISKDEF 0,1,26,6,1024,243,64,64,2 ; ; 1944: 128 Byte Record Capacity ; 243: Kilobyte Drive Capacity ; 64: 32 Byte Directory Entries ; 64: Checked Directory Entries ; 128: Records / Extent ; 8: Records / Block ; 26: Sectors / Track ; 2: Reserved Tracks ; 6: Sector Skew Factor ; dpb0 equ offset $ ;Disk Parameter Block dw 26 ;Sectors Per Track db 3 ;Block Shift db 7 ;Block Mask db 0 ;Extnt Mask dw 242 ;Disk Size - 1 dw 63 ;Directory Max db 192 ;Alloc0 db 0 ;Alloc1 dw 16 ;Check Size dw 2 ;Offset xlt0 equ offset $ ;Translate Table db 1,7,13,19 db 25,5,11,17 db 23,3,9,15 db 21,2,8,14 db 20,26,6,12 db 18,24,4,10 db 16,22 als0 equ (243+7)/8 ;Allocation Vector Size css0 equ 16 ;Check Vector Size ; DISKDEF 1,0 ; ; Disk 1 is the same as Disk 0 ; dpb1 equ dpb0 ;Equivalent Parameters als1 equ als0 ;Same Allocation Vector Size css1 equ css0 ;Same Checksum Vector Size xlt1 equ xlt0 ;Same Translate Table ; ENDEF ; ; Uninitialized Scratch Memory Follows: ; dirbuf rs 128 ;Directory Buffer alv0 rs als0 ;Alloc Vector csv0 rs css0 ;Check Vector alv1 rs als1 ;Alloc Vector csv1 rs css1 ;Check Vector sec_flags rb host_spt track_buffer rb host_spt*host_sectsiz loc_stk rw 32 ;local stack for initialization stkbase equ offset $ lastoff equ offset $ tpa_seg equ ((lastoff+07FFh)/0400h)*40h ; round off to 1K boundary tpa_len equ 0800h - tpa_seg db 0 ;fill last address for GENCMD ;********************************************* ;* * ;* Dummy Data Section for Interrupt Vectors * ;* * ;********************************************* dseg 0 ;absolute low memory org 0 ;(interrupt vectors) int0_offset rw 1 int0_segment rw 1 ; pad to system call vector org bdos_int * 4 bdos_offset rw 1 bdos_segment rw 1 END MMY ;23 - JMP DUMMY ;24 - JMP DUMMY ;25 - JMP DUMMY ;26 - JMP GETDRIVES ;27 - RETURN DRIVE INDICATORS JMP GETWDRIVE ;28 - RETURN WINCHESTER DRIVES JMP PFKINFO ;29 - KEYBOARD INFORMATION JMP SYSINFO_ADR ;30 - GET SYSINFO ADDRESS JMP SETSYS ;31 - SET THE PARAMETERS RB 80H - (((OFFSET $) -( OFFSET BIOS)) AND 7FH) EJECT ; SYSTEM INFORMATION DW INFOSIZE ;NUMBER OF BYTES SYSINFO DW 0 ;RESERVED FOR NOW DW 0,0,0,0 CRT_SPD DB 0 ;CRT speed flag, 0 = slow, no "sparkle" ;1 = fast, sparkle CRT_CURSOR DB 0 ;crt cursor DB 0 ;0 = underline 1 = block SYS_CONI DW 1 ;CONSOLE INPUT SYS_CONO DW 1 ;CONSOLE OUTPUT SYS_AUXI DW 1 ;AUX INPUT SYS_AUXO DW 1 ;AUX OUTPUT SYS_LST DW 08H STATFLAG DB 1 ;DISPLAY STATUS LINE DSKFLAG DB 0 ;DISK CONTROL FLAG DB 0,0,0,0,0 ;RESERVED LPT_SIZE DB 0 ;LINES/PAGE LPT_FLAG DB 0 ;LPT FLAGS LPT_INIT DB 0 ;INIT STRING FOR CURRENT PRINTER RB 63 SER0 DB 0E3H,0,0,0,0,0,0,0 SER1 DB 0E3H,0,0,0,0,0,0,0 SER2 DB 0E3H,0,0,0,0,0,0,0 SER3 DB 0E3H,0,0,0,0,0,0,0 SER4 DB 0E3H,0,0,0,0,0,0,0 SER6 DB 0E3H,0,0,0,0,0,0,0 MAXSER EQU 6 ;MAX NUMBER OF CONTROL BLOCKS RB 80H - (OFFSET $ AND 7FH) INFOSIZE EQU OFFSET $ - OFFSET SYSINFO EJECT ;----------------------------------------------------------- ; LEAVE A DUMMY RETURN ;----------------------------------------------------------- DUMMY: RET ;----------------------------------------------------------- ; WARM BOOT JUST JUMPS TO THE CCP ;----------------------------------------------------------- WBOOT: CALL DSKFLUSH ;FLUSH ANY BUFFERS JMP CCP_ENTRY ;WARM ENTRY POINT EJECT ;----------------------------------------------------------- ; GET MEMORY REGION TABLE ; EXIT: BX = MRT OFFSET ;----------------------------------------------------------- GETMRT: MOV BX,OFFSET MRT MOV AX,BX RET ;----------------------------------------------------------- ; GET I/O BYTE ;----------------------------------------------------------- GETIOB: MOV AL,IOBYTE SUB AH,AH MOV BX,AX RET ;----------------------------------------------------------- ; SET I/O BYTE ;----------------------------------------------------------- SETIOB: MOV IOBYTE,CL RET ;----------------------------------------------------------- ; GET DRIVES FLAG ;----------------------------------------------------------- GETDRIVES: MOV AX,DRIVES MOV BX,AX RET ;----------------------------------------------------------- ; GET WINCHESTER FLAG ;----------------------------------------------------------- GETWDRIVE: MOV AX,WDRIVES MOV BX,AX RET EJECT ;----------------------------------------------------------- ; RETURN THE ADDRESS OF THE CPMINFO AREA ;----------------------------------------------------------- SYSINFO_ADR: MOV AX,OFFSET SYSINFO ;ADDRESS MOV BX,AX ;IN BOTH PLACES RET ;----------------------------------------------------------- ; RETURN THE KEYBOARD TABLE INFORMATION ;----------------------------------------------------------- PFKINFO: MOV AX,OFFSET PFKSCAN ;POINT TO THE PLACE MOV BX,AX RET EJECT ;----------------------------------------------------------- ; LIST OUTPUT ;----------------------------------------------------------- LSTOUT: MOV BX,OFFSET LPT_FLAG ; CHECK FOR FILTER THE LINE FEEDS MOV AL,CL XCHG LPT_CHAR,AL ;GET THE LAST AND SET NEW CMP CL,LF ;IS THIS A LINE FEED? JNZ LSTOUT1 ;NO INC LPT_LINES ;BUMP THE LENGTH TEST BYTE PTR [BX], 1 ;FILTER LINE FEEDS? JZ LSTOUT1 ;NO CMP AL,CR ;WAS THE LAST ONE CR? JNZ LSTOUT1 ;YES RET ;IGNORE THIS CHARACTER ; CHECK FOR GENERATION OF A FORM FEED LSTOUT1: TEST BYTE PTR [BX], 2 JZ LSTOUT4 ;NO MOV CL,LF ;YES, USE LINE FEEDS SUB CH,CH XCHG LPT_LINES,CH ;SET THE COUNT LSTOUT2: PUSH CX ;SAVE COUNT AND CHARACTER CALL LSTOUT4 ;PUT THE CHARACTER OUT POP CX INC CH ;BUMP THE COUNT CMP LPT_SIZE,0 ;SPECIFIC SIZE? JNZ LSTOUT3 ;YES CMP CH,66 ;NO ASSUME STA^0;uvF F = }v0%PF .PF F = }v0%PF PF;eFu3 ]FqPF1F ]U cSFJvFt8P*0=FFt=uӸ PH帽P  ]3 ]U~u3P POFHȻS%P8]Uv0PvP]U3P+Pv vvhFvD)]Uev\)FFNt7v9tvD%0=t]v"v*뿸]Uvt)Pmv!PavD%0]UevD)t&v(t]vvϸ]Uvt)Pv"PvD%0]UvPvD%0%]UvPvD%0%]UvPvD%0%]UvD!T#]UvD)]U~u#vD \ 0%D 0\ vD D ]UeaF^F;Fw F]U3PPP^%t33CÃ]U3PPP^%]U FvD0=:u0%vF3PPU0@vF~ }wvv0Uvv [vv?PFFvv0^C0FtF- vv0vF=*t=t=.tF냋vv0=.Ft tFFv0.uFF ~ }wvv0Uvv [vv?PFFvv0^C0FtF- vv0vF=*t=t=.tF냋vv0 ]U40u]ð7v\#L!~ ]M V.-03@P S]U40Hu]vvX#!0 S.- PPz3 Pt]U/0u]vv0 P PP/\ P) P P帒 P 3]U0 Pw帾 P PA P市 P]U3FFF= te=t`=Fu F~N PӸ P ȃ~ |F;F }Fv F뫋F= t=t P듋v v~u]ÍF P>]U3Pv v ~ uc00;uT40Ht 50KuCFF0=C0PHu3Pv v F0@v VtF0@FF v V[c;eu]ø P]U P PPk Pe3]U-0Hu]3P+Pv*50Hu *v v vF@^ CQSPF ^ QSP]U.0Hu]3P+Pv50Hu v v+vF@^ CQSPeF ^ QSPN]U> u] PyiF-PFb^cãa]UaeF+ã'^]Uce^+؉F%]U-0Hu]Ëv0PFvt3]á#!vD#\!-]U.0Hu]Ëv0Pvttvt3]á#!vD#\!.3PV]U=Ft=t = t=uF]Ã~ u ]Ã~  ]ËF]U3PP P > F ^^ u > |F> 1u>t > tF66U# SF& P) Pe& P- Pv0%t- FF =Fu]ÊF 0u~ u>u3]Ã~ u-F 0t$6 0%t 0%]ËF]ËF=t=u: ^ 0ۉFFtF H0KF NN^ & PF ~ t4F0^ 0;&0FPSvv tF F 0@F F ~ tv~ u6 6/>tP0 PQ6 0%t6V3 P > 1u666 O P > u66 m P 66F 3PP P F UFv6 0t;|;]3]v P> 1tt= uF; |;]3]Ã~ uF; | =9]3]à 0;}~0|~9]ËF=0|;]3]á =uv ;|;]3]3]UvHu]á7t=|@;0u79;6967QvU9;0H;]U츊 P;740uZ50uQ*0Hu#+0=u P P ]à*0=u" P ]øl P ]à40Hu50u P 50Hu40u P ]U~ u]ø P( P] 50Hu40u S PC e P8 v0=Ft=u@P$z P FԸ P r3]UFF0t.v0 u0FvF0PqF0HFɸ.P]FF0tvF0P@F0HF܃]U TITLE 'EAGLE CP/M-86 BIOS - 05/20/83' ;----------------------------------------------------------- ; CONSTANTS ;----------------------------------------------------------- TRUE EQU 0FFH FALSE EQU 0 ; ASCII CHARACTERS BEL EQU 07H BS EQU 08H LF EQU 0AH CR EQU 0DH EM EQU '$' ESC EQU 1BH CTRLC EQU 3 ; ; LOCATIONS ; TRIES EQU 10 ;MAX NUMBER OF RETRIES TIMER EQU 40H ;BASE ADDRESS OF 8253 TIMER TICK EQU 19 ;TICKS PER SECOND NOSKIP EQU 80H ;NO SKIP FLAG ; DOS FUNCTION CALLS RESET EQU 13 OPENFIL EQU 15 CLOSE EQU 16 READSEQ EQU 20 SETDMAOFF EQU 26 SETDMASEG EQU 50 ; SERIAL PORT STATUS BITS CTS EQU 10H ;CLEAR TO SEND TBE EQU 20H ;XMIT BUFFER EMPTY RDR EQU 01H ;RCV DATA READY ; DISK ERROR FLAGS TIMEOUT EQU 80H ;FUNCTION TIMEOUT BAD_SEEK EQU 40H RCD_NOT_FND EQU 04H WRT_PROTECT EQU 03H DMA_CROSS EQU 09H ; DMA CONTROLLER ADDRESSES DMA EQU 00 ;BASE ADDRESS FOR THE DMA CONTROLLER DMA_CMD EQU DMA+8 ;COMMAND PORT DMA_STATUS EQU DMA+8 ;STATUS PORT DMA_REQ EQU DMA+9 ;REQUEST PORT DMA_MASK EQU DMA+10 ;MASK PORT DMA_MODE EQU DMA+11 ;MODE PORT DMA_CLRF EQU DMA+12 ;CLEAR FIRST FLAG DMA1_ADR EQU DMA+2 ;DMA 1 ADDRESS PORT DMA1_CNT EQU DMA+3 ;DMA 1 COUNTER PORT DMA3_ADR EQU DMA+6 ;DMA 3 COUNTER PORT DMA3_CNT EQU DMA+7 ;DMA 3 COUNTER PORT DMA1_PAGE EQU 83H ;DMA 1 PAGE LATCH DMA3_PAGE EQU 82H ;DMA 3 PAGE LATCH ; PORT OFFSETS FROM BASE ADDRESS SASI_DATA EQU 0 ;OFFSET TO DATA PORT SASI_STAT EQU 2 ;OFFSET TO STATUS PORT (INPUT) SASI_CTRL EQU 4 ;OFFSET TO CONTROL PORT (OUTPUT) SASI_PEC EQU 6 ;OFFSET TO CLEAR PARITY ERROR ; SASI CONTROL LATCH BITS SEL EQU 1 ;CONTROLLER SELECT (0 = TRUE) ATN EQU 2 ;ATTENTION (0 = TRUE) RST EQU 4 ;RESET (0 = TRUE) DMA_ENABLE EQU 8 ;ENABLE DMA CONTROL (0 = ENABLE) INT_ENABLE EQU 10H ;ENABLE INTERRUPTS (0 = ENABLE) INT_SELECT EQU 20H ;SELECT INTERRUPT CONTROL ;0 = INTERRUPT ON CONTROL GOING LOW ;1 = INTERRUPT ON MSG GOING TRUE ; SASI STATUS PORT BITS CD EQU 1 ;1 = CONTROL MODE, 0 = DATA IO EQU 2 ;1 = CPU INPUT, CPU OUTPUT MSG EQU 4 ;1 = MESSAGE COMPLETE BSY EQU 8 ;1 = BUSY (SELECTED) REQ EQU 10H ;1 = REQUEST TRUE PERR EQU 20H ;1 = PARITY ERROR DETECTED (INPUT) ERR_BIT EQU 2 ;ERROR BIT IN XEBEC RETURN CODE CORRECTED EQU 98H ;RETURN CODE FOR A CORRECTED ERROR DMA_READ EQU 45H ;DISK READ/MEMORY WRITE DMA_WRITE EQU 49H ;DISK WRITE/MEMORY READ ; XEBEC COMMAND CODES TEST_READY EQU 0 ;TEST READY COMMAND RECAL EQU 1 ;RECALIBRATE COMMAND SENSE_STAT EQU 3 ;SENSE ERROR STATUS COMMAND READ_CMD EQU 8 ;READ (SECTOR(S)) COMMAND WRITE_CMD EQU 0AH ;WRITE (SECTOR(S)) COMMAND INIT_CMD EQU 0CH ;INITIALIZE DRIVE COMMAND ; INTC0 EQU 20H EOI EQU 20H ; BDOS CONSTANTS ON ENTRY TO WRITE WRALL EQU 0 ;WRITE TO ALLOCATED WRDIR EQU 1 ;WRITE TO DIRECTORY WRUAL EQU 2 ;WRITE TO UNALLOCATED EJECT ; BEGINNING OF THE BIOS CSEG ; ORG 0 AUTOEXEC: ORG 3 ;START OF CCP CCP: ORG 6 CCP_ENTRY: ; ORG 0B06H ;BDOS ENTRY POINT BDOS: ; ORG 2500H ;BIOS JUMP TABLE ; BIOS: JMP INIT ; 0 - COLD START JMP WBOOT ; 1 - WARM RESTART CIST: JMP CONSTAT ; 2 - CONSOLE STATUS CIN: JMP CONIN ; 3 - CONSOLE CHAR INPUT COUT: JMP CONOUT ; 4 - CONSOLE CHAR OUTPUT LSTOT: JMP LSTOUT ; 5 - LIST CHAR OUTPUT JMP AUXOUT ; 6 - AUXILARY CHAR OUTPUT JMP AUXIN ; 7 - AUXILARY CHAR INPUT JMP HOME ; 8 - SET TRACK = 0 JMP SELDSK ; 9 - SELECT DRIVE NUMBER  JMP SETTRK ;10 - SET TRACK NUMBER JMP SETSEC ;11 - SET SECTER NUMBER JMP SETDMA ;12 - SET DMA OFFSET JMP READ ;13 - READ ONE SECTOR JMP WRITE ;14 - WRITE ONE SECTOR JMP LISTAT ;15 - RETURN LIST STATUS JMP SECTRAN ;16 - LOGICAL => PHYSICAL JMP SETDMAB ;17 - SET DMA BASE JMP GETMRT ;18 - RETURN MEMORY TABLE JMP GETIOB ;19 - RETURN I/O BYTE JMP SETIOB ;20 - SET I/O BYTE ; ; EXTENDED FUNCTIONS ; JMP DUMMY ;21 - LEAVE SOME JUMP SPACE JMP DUMMY ;22 - JMP DU Pvu]3]UF F tv P& F6iP v P F~u3]ñFi؉^>stÃ]ËvD 0%uƃ]U0Ft- F=Ft= uF]Ã~Yu]Ã~Nu3]UPP` uPPO FtF0%]UOPP@=u3]UF N tvF~ F ]UFNtF F v 0 0;t3]ø]Uv v ]0Fu3]Ëv 3Sv VFzFv VFt]øP P{ P3]Uv 0@v \0:Ft]Ëv 0%^00;ÈFu]à60Hu0F0%0FHPF9HuF0@v F]øP P PO3]UFv  6 0tA~ t;0=0F|=9~3]Ëv  6 0-0v  N 볡 ;Fu3]ø]U~ u3]3Pvv ' 3Pv P Fv ~!^C 0^v  ֋v0t~ F N]Uv 0v0;u F HF t0u3]FF ΋v 0v0+؋Ã]Uv 0=|vt3]Fv0PGu3]Fv0=|t]Fv0Pu3]ø]UF=St=su s]ËF=Ot=ouu]3]U40t00Hu]à30uu3]à30u OP3P Pv S+v 0PSv 021'u3]øPOPP30F@^Qv 3"u3]øPv u3]ø]U40u]øPvu3]ø20FûSv PFjPv(u3]øPvu3]ø]U20@=2]210@vv1]U F SSPF00u FFFF0FH~Ft vFvv j ]Uvt3]ËF vD)103ۅyK\#D!t)Prvt3]v]U00Hu v ]F v rF~t3]0F v D)103ۅyK\#D!t)Pv t3]v =]U PPvF SFPv@tv0t]øPPvb]U v0@0%tF,>, |yv0Fv0@0%u F0ãFFv0Ft)@0%uF=}F~2FɋvƄ2vF0=>vu F0Fv0Ft)@0%uF=}F~CFɋvƄCM,,FVv0Ft-@0%uF=>uf=<u==u볋v0FFt*v0@0%tFv0tP2P?60CSF/廖STSFF u P~uv PBP*~uv P'P20uvD0 DC0uvD0 Dv D0 DVP6,֋3P ]USQRVWNV_^ZY[2]U 썆F 0t|މ^C0=%Fu[0=%u0PFfڋFPF PF PFtFF;F}B 0P*ڋFvڋx ]UFF=}#0Ft PFv v S]U썆F 0uމ^C0=%Ft0=%u40KۉFx60멸Pv뛍FPF PFPF u|FF;F|hKۉxB0vB0SPtF뾡Hx6F0PvF]U~NF]UFvv0tFF]U ~u3 ]ËFHF ^v~tKvD^ ;w/;u vvD+F DFF )F ]ËFF^믋F P;É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Ã]Ut G]UFv7 ;ÉFuÃ]ËF@v ;t@3]U]U 3v0-FFF u ^^ v0=+uFFv0C0t!F ^Fv00ÉFƃ~ t^FvF ]Uv 0v0;u0u3]FF ًv 0v0+؋Ã]UFX^;sG0tFall putchar mov al,lf call putchar ret ;**** crmsg: ;print message addressed by dx til zero ;with leading crlf push dx call crlf pop dx ;drop thru to outmsg0 ;**** outmsg: mov cl,prstr jmp bdos ;dx has string addr ;**** bdma: ;dx has address mov cl,setdmaf jmp bdos ;**** dread: ;disk read function mov cl,dreadf jmp bdos ;**** open: ;file open function mov cl,openf jmp bdos ;**** bios: mov fnum,al ;bios function number mov bcx,cx mov bdx,dx  mov dx,offset(bds) mov cl,biosf jmp bdos ; **************************** ; * ; * bios utilities ; * ; **************************** seldsk equ 9 ;wboot+24 for disk select settrk equ 10 ;wboot+27 for set track function setsec equ 11 ;wboot+30 for set sector function setdma equ 12 ;wboot+33 for set dma address readf equ 13 ;wboot+36 for read function writf equ 14 ;wboot+39 for write function sel: ;select disk given by register a mov cl,al mov al,seldsk jmp bios ;**** trk: ;set up track mov al,settrk ;offset for settrk entry jmp bios ;gone to settrk ;**** sec: ;set up sector number mov al,setsec jmp bios ;**** dma: ;set dma address to value of cx mov al,setdma jmp bios ;**** read: ;perform read operation mov al,readf jmp bios ;**** write: ;perform write operaton mov al,writf jmp bios ; ************************** ; * ; * data areas ; * ; ************************** dseg org 0100h ; skip past page zero ;messages signon db 'LDCOPY VERS ' db vers/10+'0','.',vers mod 10+'0','$' askget db 'Source Drive Name $' getmsg db 'Source On ' gdisk rs 1 ;filled in at get function db ', Then Type Return$' askput db 'Destination Drive Name (Or Return To Reboot) $' putmsg db 'Destination On ' pdisk rs 1 ;filled in at put function db ', Then Type Return$' errmsg db 'Permanent Error, Type Return To Ignore$' done db 'Function Complete$' qdisk db 'Invalid Drive Name$' nofile db 'No Source File On Disk$' badfile db 'Source File Read Error$' ;translate table tran dw 1,3,5,7,9,11,13,15,17,19,21,23,25 dw 2,4,6,8,10,12,14,16,18,20,22,24,26 ;leave room for double density dw 0,0,0,0,0,0,0,0 dw 0,0,0,0,0,0,0,0 dw 0,0,0,0,0,0,0,0 dw 0,0,0,0,0,0,0,0 ; (64 extra bytes reserved) ; ************************* ; * ; * variables ; * ; ************************ bds: ;bios data structure fnum rb 1 ;storage for bios parameters bcx rw 1 ;the bdos bios func puts these bdx rw 1 ;in registers before jumping to bios nlt dw sdlt ;number of loader tracks spt dw sdspt ;sectors per track ndisks db sdndisks ;number of disks secsiz dw sdsecsiz ;sector size maxsecs dw sdlt * sdspt ;maximum sectors to read from file sdisk rb 1 ;selected disk for current operation track rw 1 ;current track rewr rb 1 ;read if 0,write if 1 sector rw 1 ;current sector dmaddr dw 0 ;current dma address retry rb 1 ;number of tries on this sector conbuf db 30 rb 32 ;console buffer ;make stack on even address loadp rs sdsecsiz*sdspt*sdlt db 0 ; force out last data segement byte end F=Xu3]vv v ]U vDt0%t VP` vD0Pv0t8@Pv F@u8Pv FP3P3Sv'FG68v FF18Pv FF3 ]\ N^ v>3ɅyIN ^F yBV ^^ F1~tv>\ N^ v>3F ^F FHFF ^3ɺ ve 0vR"F ^3ɺ K F ^F Fu~u FHB"-FF"^ظ +FF ^~tv>\ N^ v>3F ^FFH^ N3ہيXJ"^ 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]fe5e^5gW5c=5s4om4x3u:3d2 .;s5u.u5y뿃~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~!^)^FHFxvhu*6 hu]áhjnl~ u]ËF @@H;nFv]ËF)nj^؋Fj]Uhljn]UFF=} ؋p%tF~u0]ËF p@@Pv t0]ø ^FtNF p@@Pvv 2t0]øPv ^Ft Nf~uN@ ~uN nFpF]UFF=} ؋p%tF~u0]ËF p@@Pvv ~t0]ø ^FtNF p@@Pvv 2t0]øPv F عpNFtpF]UF x=~0 ]ËF ؁p^t% t0 ]ËFvDFD 0FtNFPvv B 2Hu3]Ã>2t0]ËvD]UF x=~0 ]ËF ؁p^t%@t0 ]ËFvDFD 0FtNFPvv =2u3]Ã>2t0]ËvD]U Fx=~0 ]ËF ؋p%u0 ]in message call sel ;select dest drive in al mov dx,offset putmsg call crmsg ;check with user for ok call getchar cmp al,cr ;user mistake if not cr, reboot jnz pboot call crlf mov rewr,1 ;set to write for getput call getput ;to put loader back on diskette mov dx,offset done call outmsg jmp putldr ;for another put operation pboot: jmp reboot ;back to cp/m ; *********************** ; * ; * getput: get or put loader (rewr=0 for read, 1 for write) ; * disk is already selected ; * ; *********************** getput: mov bx,offset loadp ;load point in ram for cp/m during LDCOPY mov dmaddr,bx ;clear track to 00 mov track,-1 ;start with track equal -1 rwtrk: ;read or write next track inc track ;track = track + 1 mov cx,track cmp cx,nlt ;number of loader tracks = current track ? jnz nxttrk ;end of this routine > 128 bytes jmp endrw ;end of read or write ;otherwise notdone, go to next track nxttrk: mov cx,track call trk ;to set track mov sector,-1 ;counts 0, 1, 2, . . . 25 ;sector incremented before read or write rwsec: ;read or write sector inc sector ;to next sector mov bx,sector ;current sector cmp bx,spt ;sectors per track jz endtrk ;read or write sector to or from l_5: ;current dma address mov si,offset tran add bx,bx ; double sector number mov cx,[bx+si] ;xlate to physical sector push si push cx call sec ;set up sector number pop cx pop si mov bx,[si] sub cx,bx ;tran(sector)-tran(0) call multsec ;cx * sector size add cx,dmaddr ;base of dma for this track ;+(tran(sector)-tran(0))*secsiz call dma ;dma address set from cx ;dma address set, clear retry count trysec: ;try to read or write current sector Mov Cl, 00 Mov Ax, Track Inc Ax Cmp Ax, Nlt Jne Normal_Write Mov Ax, Sector Inc Ax Cmp Ax, Spt Jne Normal_Write Mov Cl, 01 Normal_Write: or rewr,0 ;read or write? jz tryread ;must be write call write jmp chkrw ;check for error returns tryread: call read chkrw: or al,al jz rwsec mov dx,offset errmsg call outmsg call getchar cmp al,cr jne reboot1 ;local jmp then to reboot, >128 ;typed a cr, ok to ignore call crlf jmp rwsec endtrk: ;end of track mov cx,spt ;sectors per track call multsec ;*secsiz mov bx,dmaddr ;base dma for this track add bx,cx ;+ spt * secsiz mov dmaddr,bx ;ready for next track jmp rwtrk ;for another track endrw: ;end of read or write, return to caller ret reboot1:jmp reboot ;farther than 128 bytes ; ***************************************** ; * ; * utility subroutines ; * ; **************************************** ; ;***** multsec: ;cx * sector size push dx ;return value in cx mov ax,secsiz mul cx mov cx,ax pop dx ret ;***** baddisk: mov dx,offset qdisk ;bad disk name call crmsg ret ; ********************** ; * ; * bdos subroutines ; * ; ********************** bdos: int bdosint ret ;function numbers in cl reset equ 0 ;warm boot coni equ 1 ;console input cono equ 2 ;console output prstr equ 9 ;print string rconb equ 10 ;read console buffer self equ 14 ;select disk openf equ 15 ;disk open setdmaf equ 26 ;where data will go dreadf equ 20 ;disk read biosf equ 50 ;bios call reboot: mov al,0 call sel call crlf mov cl,reset mov dl,0 ; release memory jmp bdos ;**** getchar: ;get an upper case char into al call getbuf ;use buffered console read cmp conbuf+1,0 ;just a crlf? mov al,cr jz ex mov al,conbuf+2 ;first char read cmp al,'a' ;translate to upper case if lower jb ex cmp al,'z' ja ex and al,5fh ;it is lower, make upper ex: ret ;**** getbuf: ;read console buffer mov cl,rconb mov dx,offset conbuf jmp bdos ;**** putchar: ;write character from al to console mov dl,al mov cl,cono jmp bdos ;**** crlf: ;send carriage return, line feed mov al,cr cËFO33ۅyKF2^LFP Pv27FP!Pv2"0 ]=t=t=tރ>2t0 ]ËFF^^FP Pv2t0 ]ÍFPPv_2t0 ]ËF^ ]UF x=~0 ]ËF ؋p%u0 ]øPv Sv FFF 3p~u~t]3]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 FuNF txv N xF ϋFxA=7FF^NV ֊͊ߊĿOu% F 3333ҋv4Ft D\Lv2F(]UF+r;r;s+듉]3]Uvu]Ë؋~u#G SPXP to cancel, any other key to continue...Jvolume.logThe diskette is not a backup diskette disk # %dIs this the correct diskette (Y or N)? Eagle CP/M-86 Version 1.2 Eagle MSDOS Version 1.2 Hard Disk Restore Menu. Your options are: (1) Restore hard disk files. (2) Display hard disk files. (3) Display floppy diskettes files. (4) Return to the previous menu. Which is your choice? jK kEInitializing the diskette. Please do not interrupt...*.* A request to terminate the operation has been received. Do you wish to terminate this operation (Y or N)? The operation has been terminated. Any files transferred during this operation are incomplete and cannot be used. The operation has been terminated. Press any key to return to the main menu... Insert a formatted diskette in the floppy disk drive. Press to stop, any other key to continue...EYkJ: j Push to exit, any other key for next page Floppy diskette number %d is full.EThe destination floppy diskette is full.The destination hard disk or floppy diskette is full.Press any key to return to the main menu... --------------- W A R N I N G ---------------- | Any data stored on the diskette you insert | | in the floppy disk drive will be destroyed.| --------------- W A R N I N G ---------------- ?x7 ENo files to display. Press any key to return to the main menu...jK k%sYour options are %c thru %cYour options are %c thru %c%cYour options are %d thru %dE Transferring files from drive A (left) to drive B (right). Transferring files from the hard disk to the floppy diskette. Transferring files from drive B (right) to drive A (left). Transferring files from the floppy diskette to the hard disk. Backing up Hard Disk Files. Restoring Hard Disk Files. The file(s) listed below were not restored: transferred: Press any key to return to the main menu...VOLUME LOG%sKvolume.log Please enter date or comment (up to 15 characters): Disk Backup w.arCan't open stdin file Can't create stdout file ((((( H ((((( H 0123456789ABCDEFDesired operation is on a different track then is in our buffer, ; So it will be nessecary to read in the desired track. First, we ; must check to see if any sectors of the current buffer are dirty. wrong_track: call flush_buffer ; write any old records, if nessecary mov ax,cpm_track ; get desired track number mov cur_track,ax ; make in new track mov al,cpm_disk ; get desired disk number mov cur_disk,al ; make it current drive mov cur_dma,offset track_buffer ; point dma offset at track buffer mov cur_sec,host_fsn ; starting from first sector call track_read ; load the track correct_track: mov ax,cpm_sec ; get the cp/m sector number if (host_fsn ne 0) sub ax,host_fsn ; correct if we start with sector one endif mov dl,7 ; log2(128) shl ax,dl ; sector times 128 gives offset mov cx,64 ! cld ; move 64 words forward ret flush_buffer: test wr_flag,1 ; see if we have anything to write jz no_flush ; no, skip scanning for dirty sectors mov bx,0  ; start at host sector 0 mov cx,host_spt ; for host_spt sectors... next_sect: test sec_flags[BX],1 ; see if this sector has been changed jz not_updated ; no, leave it alone mov sec_flags[BX],0 ; zero the flag for next time push bx ; save the registers push cx mov cur_sec,bx ; save host sector number mov ax,host_sectsiz mul bx ; make track buffer offset add ax,offset track_buffer ; make direct pointer mov cur_dma,ax ; save for write routine call sector_write pop cx pop bx not_updated: inc bx loop next_sect no_flush: mov wr_flag,0 ; clear the dirty buffer flag ret clear_flags: ; Clear all variables associated with the track buffer, ; so next operation will have to read a track. ; This is involves clearing all write flags and setting ; the old drive code to the invalid -1. mov cur_disk,-1 ; insure initial pre-read sub ax,ax ; make a zero mov wr_flag,al ; clear the dirty buffer flag mov di,offset sec_flags ; point to the update flag list mov bx,ds ! mov es,bx ; ES <- DS mov cx,host_spt ! cld ; set length and direction rep stosb ; zero the sector update flags ret track_read: ; read an entire track from the drive "cur_disk", ; the track "cur_track" into "track_buffer". ret sector_write: ; write a physical sector to disk "cur_disk", ; track "cur_track", sector "cur_sec" from ; the buffer at DS:"cur_dma". ret dseg cpm_disk rb 1 cpm_track rw 1 cpm_sec rw 1 dma_offset rw 1 dma_segment rw 1 dma_longword equ dword ptr dma_offset cur_disk rb 1 cur_sec rw 1 cur_track rw 1 cur_dma rw 1 bdos_wr_code rb 1 ; 1 indicates a directory write wr_flag rb 1 ; bit 0 on indicates we have a dirty buffer sec_flags rb host_spt ; bit 0 of each byte on indicates ; corresponding host sector has been ; updated and needs writing. track_buffer rb host_sectsiz * host_spt 1~tv>\ N^ v>3F ^F FHFF ^3ɺ v 0vR"F ^3ɺ 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]fegcsGox%ud5 .;u.y뿃~uFt;F }F FF )FF~ t?F HF xFFv<~FދFHFxQFFv<FFHFxFFv<FF HF xFFv<~FދFv@F:@6]Ã~uF~~FF@^"S^S^SvP^>7P v>^"NɉF N^y^~u~ t~}F~ tN3F~tF~t!F@^؋F^xF~t1F,FFFyF=cF~F~~  title 'CP/M-86 Loader' ; The CPMLDR consists of this module along with the ; LDRBDOS and LBIOS. ; CPMLDR resides on the first two tracks of a ; CP/M-86 system diskette and is brought into memory ; by the ROM bootstrap loader to load initiate CP/M-86 ; It opens the file 'CPM.SYS' using the LDRBDOS and LBIOS ; and then reads it into memory. Finally, a jump to the BIOS ; initialization entry point starts CP/M-86 ; The first 128 byte record of the CPM.SYS file is a header ; with the following format: ; ty rb 1 ;seg type (not used here) ; len rw 1 ;length (not used here) ; abs dw ldrstart ;absolute segment address for LOADER ; min rw 1 ;minimum mem (not used here) ; max rw 1 ;max mem needed (not used here) ; (This header record is constructed automatically by the ; GENCMD utility). ; CPMLDR may be read into any segment that does not ; overlap the desired system load segment as it makes ; all memory references using copies of the CS: register ; it is entered with. false equ 0 true equ not false cr equ 0dh lf equ 0ah lbios_offset equ 1200h ; offset of LBIOS biosoff equ 2500h ; offset of BIOS from start of CPM.SYS ; this is the entry point into CPM.SYS bootdrv equ 0 ; boot drive always zero ; 128 bytes of CPM.SYS lbdosoff equ 406H ;location of LBDOS in LOADER bdos_int equ 224 ;lbdos interrupt number ; dummy section for interrupt vectors dseg 0 org 0 abs_zero rw 2*bdosint bdos_offset rw 1 bdos_segment rw 1 ; bdos function numbers coutf equ 2 pstrf equ 9 seldsk equ 14 openf equ 15 readsf equ 20 dmaf equ 26 dmabf equ 51 ;******************************* ;* ;* CPMLDR starts here ;* ;******************************* cseg org 0 ; JMPF to here from boot ROM jmp LBIOS ; allow loader BIOS to ; initialize start: ; loader BIOS jumps here xor ax,ax ! mov ds,ax ; temp DS at absolute zero mov bdos_offset,lbdosoff ; to patch in interrupt table mov bdos_segment,cs ; offset and segment mov ax,cs ! mov ss,ax ; make ss, ds, es = cs mov ds,ax ! mov es,ax mov sp,offset(stack) ; set up local stack call initlbdos ;warm up lbdos and lbios call openfnc ;open CPM.SYS cmp al,255 ! jne perr ; insure good file mov dx,offset nofile ! call msg ; no CPM.SYS file jmp stop ; then halt the machine perr: mov dx,cs ! call setdmab mov dx,offset page1 ! call setdma ;read first page of CPM.SYS call read mov ax,word ptr page1+3 ;get abs field from header mov ldseg,ax ; save it and mov dx,ax ! call setdmab ; set DMA segment for disk IO mov dx,offset segment ! call msg ; put memory map on console mov ax,ldseg ! call phex ; print base system segment ; mov dx,0 ;offset of CPM in segment readit: call setdma ; set DMA offset for push dx ! call read ; next sector read cmp al,01H ! je done ; check for EOF cmp al,0 ! je prerr ; check for good write mov dx,offset rerr ! call msg ; print READ ERROR message  jmp stop ; hard stop on any error prerr: pop dx ! add dx,80h ; address for next record jmp readit done: mov dx,offset lenmsg ! call msg ; print length message pop ax ! dec ax ! call phex ; print last address call pcrlf ; and a crlf jmpf bios ; leap to BIOS initialization ;***************************** ;* ;* subroutines ;* ;***************************** ;****** phex: ;print 4 hex characters from ax mov cx,0404h ; 4 in both CH and CL lhex: rol ax,cl ; rotate left 4 push cx ! push ax ; save crucial registers call pnib ; print hex nibble pop ax ! pop cx ; restore registers dec ch ! jnz lhex ; and loop four times ret pnib: ;print low nibble in AL as hex char and al,0fh ! cmp al,9 ja p10 ;above 9 ? add al,'0' ;digit jmp prn p10: add al,'A'-10 ;char a-e prn: mov dl,al ;****** putchar: mov cl,coutf jmp sys_vec ;****** initlbdos: mov cl,seldsk ! mov dx,bootdrv ; select boot disk jmp sys_vec ;****** openfnc: mov cl,op @ CONAXIAXOLSTNULx|n bit jnz old_disk ; not first time selected if nz ; here if CP/M is about to login to the drive being ; selected. old_disk: mov bl,cpm_disk ! mov bh,0 mov dl,4 ! shl bx,dl ; times 16 add bx,offset dpbase ; gives offset from DPBASE ret ; back to BDOS setdma: mov dma_offset,cx ; save DMA offset address ret setdma_seg: mov dma_segment,cx ; save DMA segment address ret home: test wr_flag,1 ! jnz home1 ; if the buffer is clean, mov cur_disk,-1 ; insure we read the directory by invalidating ; the track buffer home1: mov cx,0 ; home is a settrk zero settrk: mov cpm_track,cx ; save track number for next operation ret setsec: mov cpm_sec,cx ; save sector number for next operation ret sectran: mov bx,cx ; Put logical sector into dest. reg. test dx,dx ; see if table address is zero jz sectran_exit ; yeah, logical = physical add bx,dx ; else, we need to fetch the mov bl,[BX] ; actual sector number from the table mov bh,0 ; zero high byte for good luck sectran_exit: ret read: call setup push es ; save the extra segment register mov si,offset track_buffer ; source segment is systems DS: add si,ax ; gives the offset into the buffer les di,dma_longword ; point ES:DI at the users sector rep movsw ; doit pop es ; restore the extra segment sub ax,ax ; make a zero return code ret  write: push cx ; save the write mode from the BDOS call setup push ax ; save buffer offset push ds ; save the data segment push es ; save the extra segment mov bx,ds ! mov es,bx ; destination is our data segment mov di,offset track_buffer ; destination is in track buffer add di,ax ; plus appropriate offset lds si,dma_longword ; source is users DMA address rep movsw ; move that sector pop es ; restore the extra segment pop ds ; and the data segment registers pop ax ; recover buffer offset mov cx,host_sectsiz ; setup to divide by host sector size sub dx,dx ; extend ax to 32 bits div cx ; find out which host sector we changed mov bx,ax ; put into index [BX] mov sec_flags[BX],1 ; set the update flag for that sector mov wr_flag,1 ; also set the dirty buffer flag pop cx ; recover BDOS write code cmp cl,1 ; is this a directory update ? jne return ; no, we may leave dirty records ; in the buffer call flush_buffer ; we have a directory write, need to ; flush the buffer to insure the ; disks integrity return: mov ax,0 ; never return BAD SECTOR code ret setup: ; common code for setting up reads and writes mov al,cpm_disk ; see if selected disk is cmp al,cur_disk ; the same as last time jne wrong_track ; no, we have wrong track mov ax,cpm_track ; see if desired track is same as cmp ax,cur_track ; the track in the buffer je correct_track ; same drive and track, we don't need to read ; !enf ! mov dx,offset fcb ; fcb already initialized mov cl,openf jmp sys_vec ;******** ; setdma: ;set new dma addr in dx mov cl,dmaf jmp sys_vec ;******** ; setdmab: ; set new dma segment base from DX mov cl,dmabf jmp sys_vec ;****** ; pcrlf: mov dx,offset crlf ;print carriage return, line feed ;****** ; msg: ;print msg starting at dx until $ mov cl,pstrf ;print string function jmp sys_vec ;***** ; read: mov dx,offset fcb ! mov cl,readsf ; jmp sys_vec ;****** ; sys_vec: int bdos_int ret ;****** ; stop: hlt ; hard stop 8086 for error jmp stop ;******************************** ;* ;* DATA AREA ;* ;******************************** nofile db cr,lf,'The File CPM.SYS Not Found On This Disk$' rerr db cr,lf,'Error In Reading CPM.SYS$' segment db cr,lf,'Segment Address = $' lenmsg db cr,lf,' Last Offset = $' crlf db cr,lf,'$' ; vector for jmpf indirect to start CP/M bios dd abs_zero ; (dummy value) org offset bios ; overlay preceding with DW's biosstart dw biosoff ; first word is BIOS offset ldseg rw 1 ; second is segment to put CPM.SYS fcb db 0,'CPM ','SYS',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 org (offset $+1) and 0FFFEh ; even address for stack rw 32 stack equ offset $ dseg org stack page1 rb 128 ; dummy section for BIOS init label org lbios_offset lbios: end  d:filename.typ Certian CP/M-86 commands can select and process several files when "wildcard" characters ar included in the primary filename or filetype. The two wildcard characters are ?, which matches an single letter in the same position, and *, which matches any character at that position and any other characters remaining in the filename or filetype. The command summary indicates which commands can accept wildcard characters in the filespec. ///2co; ;**************************************************** ;* * ;* Sample Random Access Program for CP/M-86 * ;* * ;**************************************************** ; ; BDOS Functions ; coninp equ 1 ;console input function conout equ 2 ;console output function pstring equ 9 ;print string until '$' rstring equ 10 ;read console buffer version equ  12 ;return version number openf equ 15 ;file open function closef equ 16 ;close function makef equ 22 ;make file function readr equ 33 ;read random writer equ 34 ;write random ; ; Equates for non graphic characters cr equ 0dh ;carriage return lf equ 0ah ;line feed ; ; ; load SP, ready file for random access ; cseg pushf ;push flags in CCP stack pop ax ;save flags in AX cli ;disable interrupts mov bx,ds ;set SS register to base of DATA group mov ss,bx ;set SS, SP with interrupts disabled mov sp,offset stack ; for 80888 push ax ;restore the flags popf ; ; CP/M-86 initial release returns the file ; system version number of 2.2: check is ; shown below for illustration purposes. ; mov cl,version call bdos cmp al,20h ;version 2.0 or later? jnb versok ; bad version, message and go back mov dx,offset badver call print  jmp abort ; versok: ; correct version for random access mov cl,openf ;open default fct mov dx,offset fcb call bdos inc al ;err 255 becomes zero jnz ready ; ; cannot open file, so create it mov cl,makef mov dx,offset fcb call bdos inc al ;err 255 becomes zero jnz ready ; ; cannot create file, directory full mov dx,offset nospace call print jmp abort ;back to ccp ;!k number for this pass track_size rw 1 ; size of each track in bytes btr rw 1 ; last track number of this pass dma_offset rw 1 ; current buffer offset dma_segment rw 1 ; current buffer segment base message_pointer rw 1 ; points to appropriate read/write message disk_function rw 1 ; points to '' '' '' subroutine base_sector rw 1 ; either 0 or 1 normally max_track rw 1 ; total number of tracks on disk line_buff db 80 db 0 rb 80 bios_function rb 1 ; bios function number bios_cx rw 1 ; first argument for BIOS call bios_dx rw 1 ; second argument for BIOS call disk_def rs 0 ; disk definition table gets copied here spt rw 1 ; 128 byte sectors per track bsh rb 1 ; block shift factor blm rb 1 ; block mask exm rb 1 ; extent mask dsm rw 1 ; disk size in blocks drm rw 1 ; directory size al0 rb 1 ; alloc 0 al1 rb 1 ; alloc 1 cks rw 1 ; checksum size off rw 1 ; directory offset rw 128 stack_end rw 0 verify_buffer rs 128 ; sector buffer for verify function db 0 ; force out data segment end arCan't open stdin file Can't create stdout file ((((( H ((((( H 0123456789ABCDEF@ CONAXIAXOLSTNUL>BFJNpip cpmx.h86=cpm.h86,cpmbios.h86 gencmd cpmx 8080 nhead code[a51] era cpmx.h86 era cpm.sys ren cpm.sys=cpmx.cmd " ; loop back to "ready" after each command ; ready: ; file is ready for processing ; call readcom ;read next command mov ranrec,dx ;store input record# mov ranovf,0h ;clear high byte if set cmp al,'Q' ;quit? jnz notq ; ; quit processing, close file mov cl,closef mov dx,offset fcb call bdos inc al ;err 255 becomes 0 jz error ;error message, retry jmps abort ;back to ccp ; ; ; end of quit command, process write ;  ; notq: ; not the quit command, random write? cmp al,'W' jnz notw ; ; this is a random write, fill buffer until cr mov dx,offset datmsg call print ;data prompt mov cx,127 ;up to 127 characters mov bx,offset buff ;destination rloop: ;read next character to buff push cx ;save loop conntrol push bx ;next destination call getchr ;character to AL pop bx ;restore destination pop cx ;restore counter cmp al,cr ;end of line? jz erloop ; not end, store character mov byte ptr [bx],al inc bx ;next to fill loop rloop ;decrement cx ..loop if not 0 erloop: ; end of read loop, store 00 mov byte ptr [bx],0h ; ; write the record to selected record number mov cl,writer mov dx,offset fcb call bdos or al,al ;error code zero? jz ready ;for another record jmps error ;message if not ; ; ; ; end of write command, process read ; ; notw: ; not a write command, read record? cmp al,'R' jz ranread jmps error ;skip if not ; ; read random record ranread: mov cl,readr mov dx,offset fcb call bdos or al,al ;return code 00? jz readok jmps error ; ; read was successful, write to console readok: call crlf ;new line mov cx,128 ;max 128 characters mov si,offset buff ;next to get wloop: lods al ;next character and al,07fh ;mask parity jnz wloop1 jmp ready ;for another command if 00 wloop1: push cx ;save counter push si ;save next to get cmp al,' ' ;graphic? jb skipw ;skip output if not graphic call putchr ;output character skipw: pop si pop cx loop wloop ;decrement CX and check for 00 jmp ready ; ; ; end of read command, all errors end-up here ; ; error: mov dx,offset errmsg call print jmp ready ; ; BDOS entry subroutine bdos: int 224 ;entry to BDOS if by INT 224 ret ; abort: ;return to CCP Mov Dl, 0  mov cl,0 call bdos ;use function 0 to end execution ; ; utility subroutines for console i/o ; getchr: ;read next console character to a mov cl,coninp call bdos ret ; putchr: ;write character from a to console mov cl,conout mov dl,al ;character to send call bdos ;send character ret ; crlf: ;send carriage return line feed mov al,cr ;carriage return call putchr mov al,lf ;line feed call putchr ret ; print: ;print the buffer addressed by dx until $ push dx call crlf pop dx ;new line mov cl,pstring call bdos ;print the string ret ; readcom: ;read the next command line to the conbuf mov dx,offset prompt call print ;command? mov cl,rstring mov dx,offset conbuf call bdos ;read command line ; command line is present, scan it mov ax,0 ;start with 0000 mov bx,offset conlin readc: mov dl,[bx] ;next command character inc bx ;to next command position mov dh,0 ;zero high byte for add or dl,dl ;check for end of command jnz getnum ret ; not zero, numeric? getnum: sub dl,'0' cmp dl,10 ;carry if numeric jnb endrd mov cl,10 mul cl ;multipy accumulator by 10 add ax,dx ;+digit jmps readc ;for another char endrd: ; end of read, restore value in a and return value in bx mov dx,ax ;return value in DX mov al,-1[bx] cmp " ; point at buffer int BDOS ; read the line mov al,line_buff+1 ; get input length cmp al,1 ; insure single char entered jb get_char_1 ; no, go mov al,line_buff+2 ; get the character ret get_char_1: mov al,cr ; null string, return a ret crlf: ; print a mov si,offset crlf_message ; fall into pmsg pmsg: ; print message at [SI] to zero lods al ; get a character test al,al ; see if zero terminator jz pmsg_x ; yes, exit push si ; save pointer call conout ; not done, print character pop si ; recover pointer jmp pmsg ; and loop pmsg_x: ret conin: ; get character from console into AL mov cl,6 mov dl,0FFh int BDOS test al,al jz conin ret conout: ; output character in AL to console mov dl,al mov cl,6 int BDOS ret pdec: ; print unsigned 16 bits in AX as decimal ; with zero suppresion mov cx,0 ; cx is digit counter pdec_1: ; here to divide out next digit sub dx,dx ; Zero DX mov bx,10 ; constant 10 div bx ; quotient to AX, remainder to DX add dl,'0' ; make remainder ascii digit push dx ; and stick onto stack inc cx ; bump digit counter test ax,ax ; see if any quotient left jnz pdec_1 ; yes, continue stacking digits pdec_2: pop ax ; get a digit from the stack push cx ; save count call conout ; print it pop cx ; restore count loop pdec_2 ; and continue if more in stack ret ; done. . . ; ** DATA SEGMENT ** dseg cr equ 0dh ; ascii carriage return lf equ 0ah ; ascii line feed drive_cnt equ 16 ; CP/M currently supports up to 16 drives BDOS equ 224 ; system call interrupt number ; CP/M-86 Page Zero code_length rw 1 ; low 16 bits code length code_length_H rb 1 ; high 8 bits '' '' code_base rw 1 ; base of the code segment model_8080 rb 1 ; 8080 memory model flag data_length rw 1 ; low 16 bits data length data_length_H rb 1 ; high 8 bits '' '' data_base rw 1 ; base of the data segment rs 1 ; not used extra_length rw 1 ; low 16 bits extra length extra_length_H rb 1 ; high 8 bits '' '' extra_base rw 1 ; base of the extra segment org 005Ch default_FCB rs 35 ; default File Control Block org 0080h default_buffer rs 128 ; default record buffer org 0100h ; start of user data segment ; MESSAGES signon_message db cr,lf,'CP/M-86 Full Disk COPY Utility' db cr,lf,' Version ' db ver/10+'0', '.', (ver mod 10)+'0',cr,lf,0  source_message db cr,lf,cr,lf,'Enter Source Disk Drive (A-D) ? ',0 dest_message db cr,lf,cr,lf,' Destination Disk Drive (A-D) ? ',0 ready_message db cr,lf,cr,lf,'Copying Disk ' source_ascii rb 1 db ': to Disk ' dest_ascii rb 1 db ':',cr,lf db 'Is this what you want to do (Y/N) ? ',0 memory_message db cr,lf,'Insufficient memory available for copy',0 abort_message db cr,lf,cr,lf,'Copy aborted',cr,lf,0 done_message db cr,lf,'Copy completed.',0 another_message db cr,lf,cr,lf,'Copy another disk (Y/N) ? ',0 copy_message db cr,lf,'Copy started',cr,lf,0 reading_message db cr,' Reading Track ',0 writing_message db cr,' Writing Track ',0 verify_message db cr,'Verifying Track ',0 space_message db ' ',0 bad_drive db cr,lf,'Illegal Diskette Drive',cr,lf,0 same_message db cr,lf,'Source and Destination cannot be the same' db cr,lf,0 type_error_message db cr,lf,'Source and Destination disks must be' db cr,lf,'the same type',cr,lf,0 continue_message db cr,lf,'Ignore error (Y/N) ? ',0 sector_message db ', Sector ',0 disk_error_message db cr,lf,'Permanent Error ',0 crlf_message db cr,lf,0 exit_message db cr,lf,'COPY program exiting',cr,lf,0 ; VARIABLES source rb 1 ; source drive select code dest rb 1 ; destination drive select code selected_disk rb 1 ; current drive select code trk rw 1 ; current track number sector rw 1 ; current sector number (0 origin) nts rw 1 ; number of tracks per buffer full base_track rw 1 ; starting trac#al,'a' ;check for lower case jnb transl ret transl: and al,5fH ;translate to upper case ret ; ; ; Template for Page 0 of Data Group ; Contains default FCB and DMA buffer ; dseg org 05ch fcb rb 33 ;default file control block ranrec rw 1 ;random record position ranovf rb 1 ;high order (overflow) byte buff rb 128 ;default DMA buffer ; ; string data area for console messages badver db 'sorry, you need cp/m version 2$' nospace db 'no directory space$' datmsg db 'type data: $' errmsg db 'error, try again.$' prompt db 'next command? $' ; ; ; fixed and variable data area ; conbuf db conlen ;length of console buffer consiz rs 1 ;resulting size after read conlin rs 32 ;length 32 buffer conlen equ offset $ - offset consiz ; rs 31 ;16 level stack stack rb 1 db 0 ;end byte for GENCMD end x,ax ;return value in DX mov al,-1[bx] cmp xternal devices that can be assigned to your computer. STAT accepts wildcards in the command tail. Note that STAT accepts a dollar sign ($), square bracket ([), or no delimiter before RO, RW, SYS, DIR, and SIZE options. ///2examples EXAMPLES: A>STAT A>STAT B:=RO A>STAT myfile.txt A>STAT C:letter.bak A>STAT genledgr.dat RO,SYS A>STAT *.cmd RO A>STAT *.bak A>STAT B:*.* ///2options STAT OPTIONS: RW = Read Write RO = Read Only SYS = System attribute DIR = NO System attribute SIZE = Show the size of the file or files VAL: = Shows possible devices USR: = Shows USER numbers containing files DSK: = Shows characteristics of the default drive DEV: = Shows current physical to logical device assignments ///1submit FORMAT: ;***************************************************** ;* * ;* Sector Blocking / Deblocking * ;* * ;* This algorithm is a direct translation of the * ;* CP/M-80 Version, and is included here for refer- * ;* ence purposes only. The file DEBLOCK.LIB is in- * ;* cluded on your CP/M-86 disk, and should be used * ;* for actual applications. You may wish to contact * ;* Digital Research for notices of updates. * ;* * ;***************************************************** ; ;***************************************************** ;* * ;* CP/M to host disk constants * ;* * ;* (This example is setup for CP/M block size of 16K * ;* with a host sector size of 512 bytes, and 12 sec- * ;* tors per track. Blksiz, hstsiz, hstspt, hstblk * ;* and secshf may change for different hardware.) * ;***************************************************** una equ byte ptr [BX] ;name for byte at BX ; blksiz equ 16384 ;CP/M allocation size hstsiz equ 512 ;host disk sector size hstspt equ 12 ;host disk sectors/trk hstblk equ hstsiz/128 ;CP/M sects/host buff ; ;***************************************************** ;* * ;* secshf is log2(hstblk), and is listed below for * ;* values of hstsiz up to 2048. * ;* * ;* hstsiz hstblk secshf * ;* 256 2 1 * ;* 512 4 2 * ;* 1024 8 3 * ;* 2048 16 4 * ;* * ;*************************************#nt,dx ; save DMA segment mov cx,dx ; put in argument register call setdmab ; pass to CBIOS mov cx,dma_offset ; get the offset again call setdma ; and pass it to BIOS also mov ax,sector ; fetch current sector number inc ax ; add one to it cmp ax,spt ; see if last sector on track mov cl,0 ; might be then normal write jb execute_function ; skip if not last mov cl,1 ; if last, then treating as ; dir write forces flush execute_function: call disk_function ; read/write/verify a sector test al,al ; check error return code jz no_disk_error ; see if we got a bad sector ; got fatal disk error mov si,offset disk_error_message call pmsg ; print disk error mov si,message_pointer ; get pointer to read/write inc si ; skip leading call pmsg ; print that mov ax,trk ; get track number call pdec ; print it mov si,offset sector_message ; print ", Sector " call pmsg mov ax,sector ; get sector number (0 org)  add ax,base_sector ; correct if 1 origin call pdec ; print the sector number mov si,offset continue_message ; see if user wants to ignore call get_yn ; ask for a Y/N response jnc next_5 ; yes, continue jmp aborting ; NO, go ask for new disks next_5: call crlf no_disk_error: pop cx ; recover sector number inc cx ; sector = sector + 1 cmp cx,spt ; see if past last sector jae next_6 ; done, exit jmp next_sector ; else, continue next_6: dec trk ; track = track - 1 jmp next_track ; continue loading buffer next_track_x: ret verify: ; verify a 128 byte sector mov cx,offset verify_buffer ; point at our 128 byte buffer call setdma ; make it the dma buffer mov cx,ds ; get our data segment call setdmab ; point dma base address call read ; read 128 byte record push ax ; save read error in stack mov si,offset verify_buffer ; point to sector we just read les di,dword ptr dma_offset ; get pointer to one we wrote mov cx,128 ; 128 byte record cld ! rep cmpsb ; compare them mov al,0 ; no error je verify_good ; so we are ok mov al,0FFh ; else, we got compare error verify_good: pop dx ; recover read error byte or al,dl ; merge into return code ret ; back to caller ; *********************************** ; * ; * BIOS direct entry points ; * ; *********************************** home: mov al,8 jmps bios_call seldsk: mov al,9 jmps bios_call settrk: mov al,10  jmps bios_call setsec: mov al,11 jmps bios_call setdma: mov al,12 jmps bios_call setdmab: mov al,17 jmps bios_call read: mov al,13 jmps bios_call write: mov al,14 jmps bios_call sectran: mov al,16 jmps bios_call bios_call: mov bios_function,al mov bios_CX,cx mov bios_DX,DX mov cl,50 mov dx,offset bios_function int BDOS ret ; **************************************** ; * ; * Operator interaction subroutines ; * ; **************************************** get_drive: ; print message and read drive code call pmsg ; first, print the message call get_upper ; then get an upper case letter sub al,'A' ; and normalize to 0... ret get_upper: ; get upper case console input w/ echo call get_char ; get console character cmp al,'a' ; see if lower case jb get_upper_x ; below, leave cmp al,'z' ; insure not > z ja get_upper_x ; not lower at all sub al,'a'-'A' ; make upper get_upper_x: ret get_yn: ; print message and get Y or N push si ; save message pointer call pmsg ; print the message call get_upper ; get a upper case letter pop si ; recover message pointer cmp al,'Y' ; see if response was 'Y' je get_yn_x ; yes, return w/ no carry cmp al,'N' ; see if was 'N' jne get_yn ; no, invalid. reprompt stc ; set carry for a NO get_yn_x: ret get_char: ; read a line from CONIN and return first char mov cl,10 ; function for line in mov dx,offset line_buff$**************** secshf equ 2 ;log2(hstblk) cpmspt equ hstblk * hstspt ;CP/M sectors/track secmsk equ hstblk-1 ;sector mask ; ;***************************************************** ;* * ;* BDOS constants on entry to write * ;* * ;***************************************************** wrall equ 0 ;write to allocated wrdir equ 1 ;write to directory wrual equ 2 ;write to unallocated ; ;***************************************************** ;* * ;* The BIOS entry points given below show the * ;* code which is relevant to deblocking only. * ;* * ;***************************************************** seldsk: ;select disk ;is this the first activation of the drive? test DL,1 ;lsb = 0? jnz selset ;this is the first activation, clear host buff mov hstact,0 mov unacnt,0 selset: mov al,cl ! cbw ;put in AX mov sekdsk,al ;seek disk number mov cl,4 ! shl al,cl ;times 16 add ax,offset dpbase mov bx,ax ret ; home: ;home the selected disk mov al,hstwrt ;check for pending write test al,al jnz homed mov hstact,0 ;clear host active flag homed: mov cx,0 ;now, set track zero ; (continue HOME routine) ret ; settrk: ;set track given by registers CX mov sektrk,CX ;track to seek ret ; setsec: ;set sector given by register cl mov seksec,cl ;sector to seek ret ; setdma: ;set dma address given by CX mov dma_off,CX ret ; setdmab: ;set segment address given by CX mov dma_seg,CX ret ; sectran: ;translate sector number CX with table at [DX] test DX,DX ;test for hard skewed jz notran ;(blocked must be hard skewed) mov BX,CX add BX,DX mov BL,[BX] ret no_tran: ;hard skewed disk, physical = logical sector mov BX,CX ret ; read: ;read the selected CP/M sector mov unacnt,0 ;clear unallocated counter mov readop,1 ;read operation mov rsflag,1 ;must read data mov wrtype,wrual ;treat as unalloc jmp rwoper ;to perform the read ; write: ;write the selected CP/M sector mov readop,0 ;write operation mov wrtype,cl cmp cl,wrual ;write unallocated? jnz chkuna ;check for unalloc ; ; write to unallocated, set parameters ; mov unacnt,(blksiz/128) ;next unalloc recs mov al,sekdsk ;disk to seek mov unadsk,al ;unadsk = sekdsk mov ax,sektrk mov unatrk,ax ;unatrk = sektrk mov al,seksec mov unasec,al ;unasec = seksec ; chkuna: ;check for write to unallocated sector ; mov bx,offset unacnt ;point "UNA" at UNACNT mov al,una ! test al,al ;any unalloc remain? jz alloc ;skip if not ; ; more unallocated records remain dec al ;unacnt = unacnt-1 mov una,al mov al,sekdsk ;same disk? mov BX,offset unadsk cmp al,una ;sekdsk = unadsk? jnz alloc ;skip if not ; ; disks are the same mov AX, unatrk cmp AX, sektrk jnz alloc ;skip if not ; ; tracks are the same mov al,seksec ;same sector? ; mov BX,offset unasec ;point una at unasec ; cmp al,una ;seksec = unasec? jnz alloc ;skip if not ; ; match, move to next sector for future ref inc una ;unasec = unasec+1 mov al,una ;end of track? cmp al,cpmspt ;count CP/M sectors jb noovf ;skip if below ; ; overflow to next track mov una,0 ;unasec = 0 inc unatrk ;unatrk=unatrk+1 ; noovf: ;match found, mark as unnecessary read mov rsflag,0 ;rsflag = 0 jmps rwoper ;to perform the write ; alloc: ;not an unallocated record, requires pre-read mov unacnt,0 ;unacnt = 0 mov rsflag,1 ;rsflag = 1 ;drop through to rwoper ; ;***************************************************** ;* * ;* Common code for READ and WRITE follows * ;* * ;***************************************************** rwoper: ;enter here to perform the read/write mov erflag,0 ;no errors ($ck,ax ; save value ; compute number of tracks that will ; fit in our data segment mov ax,extra_length ; get low 16 bits of DS length mov dl,extra_length_H ; get other 8 bits mov dh,0 ; zero rest of 32 bit divisor div track_size ; divide buff_len / track_size mov NTS,ax ; save this value. cmp ax,2 ; must be at least 2 tracks jae adequite_memory ; ok, continue mov si,offset memory_message ; else print call pmsg ; error message aborting: ; here if exiting because of error mov si,offset abort_message call pmsg jmp another adequite_memory: mov si,offset ready_message ; insure this is correct call get_yn ; print request jc aborting ; if NO, then get new input mov si,offset copy_message ; else tell user OK. call pmsg mov ax,max_track ; get maximum track number mov base_track,ax ; save as outer loop index next_block: mov ax,base_track ; get loop index cmp ax,0 ; see if we are outside limits jl next_block_x ; yes, terminate loop sub ax,nts ; lower by number of tracks per buffer inc ax ; and adjust by 1. jns not_neg ; check to make sure its positive mov ax,0 ; no, zero is floor not_neg: mov btr,ax ; save as last track for this copy pass mov si,offset reading_message ; point to read message mov ax,offset read ; and proper subroutine mov cl,source ; select source diskette call track_block mov si,offset writing_message ; point to write message mov ax,offset write ; and proper subroutine mov cl,dest ; select destination call track_block mov si,offset verify_message ; point to verify message mov ax,offset verify mov cl,dest ; reselect destination call track_block mov ax,base_track sub ax,nts ; adjust base track by number we copied mov base_track,ax jmps next_block next_block_x: ; here, we are done with a sucessful copy mov si,offset done_message ; print message call pmsg ; announcing success another: mov si,offset another_message call getyn ; see if we want another copy jc exit ; no, go exit next_copy_v: ; convienient for short jumps jmp next_copy ; back for another disk copy exit: ; here, we are exiting mov si,offset exit_message call pmsg mov cl,13 int BDOS mov cl,0 ; reboot mov dl,0 ; CP/M-86 int BDOS different_type: mov si,offset type_error_message call pmsg jmp aborting track_block: mov message_pointer,si ; save pointer to message mov disk_function,ax ; save pointer to read/write mov selected_disk,cl ; save drive select code mov dl,1 ; tell bios have selected before call seldsk ; select diskette drive mov ax,base_track ; get base track number for this pass mov trk,ax ; save as loop index next_track: ; first inner loop... mov ax,trk ; get the index cmp ax,btr ; see if less than last jnl next_4 ; no, continue jmp next_track_x ; yeah, exit loop next_4: mov si,message_pointer call pmsg ; print " Track " mov ax,trk ; get the track number call pdec ; print as decimal mov si,offset space_message ; then, print some call pmsg ; spaces to blank any garbage mov cx,trk ; get desired track address call settrk ; give to bios mov cx,0 ; start with logical sector 0 next_sector: push cx ; save current sector number mov sector,cx ; save sector number (0 org) add cx,base_sector ; correct for first sector number call setsec ; pass to cbios ; compute dma address and segment mov ax,base_track ; get starting track number sub ax,trk ; gives relative track of pass mov dx,0 ; make dword mul spt ; compute sector of track add ax,sector ; add in current logical sector adc dx,0 ; make double precision add mov cx,128 ; length of a sector mul cx ; gives base offset as 32 bits mov dma_offset,ax ; gives base dma offset mov cl,12 ! shl dx,cl ; move to high nibble add dx,extra_base ; offset extra segment mov dma_segme%yet) mov al, seksec ;compute host sector mov cl, secshf shr al,cl mov sekhst,al ;host sector to seek ; ; active host sector? mov al,1 xchg al,hstact ;always becomes 1 test al,al ;was it already? jz filhst ;fill host if not ; ; host buffer active, same as seek buffer? mov al,sekdsk cmp al,hstdsk ;sekdsk = hstdsk? jnz nomatch ; ; same disk, same track? mov ax,hsttrk cmp ax,sektrk ;host track same as seek track jnz nomatch ; ; same disk, same track, same buffer? mov al,sekhst cmp al,hstsec ;sekhst = hstsec? jz match ;skip if match nomatch: ;proper disk, but not correct sector mov al, hstwrt test al,al ;"dirty" buffer ? jz filhst ;no, don't need to write call writehst ;yes, clear host buff ; (check errors here) ; filhst: ;may have to fill the host buffer mov al,sekdsk ! mov hstdsk,al mov ax,sektrk ! mov hsttrk,ax mov al,sekhst ! mov hstsec,al mov al,rsflag test al,al ;need to read? jz filhst1 ; call readhst ;yes, if 1 ; (check errors here) ; filhst1: mov hstwrt,0 ;no pending write ; match: ;copy data to or from buffer depending on "readop" mov al,seksec ;mask buffer number and ax,secmsk ;least signif bits are masked mov cl, 7 ! shl ax,cl ;shift left 7 (* 128 = 2**7) ; ; ax has relative host buffer offset ; add ax,offset hstbuf ;ax has buffer address mov si,ax ;put in source index register mov di,dma_off ;user buffer is dest if readop ; push DS ! push ES ;save segment registers ; mov ES,dma_seg ;set destseg to the users seg ;SI/DI and DS/ES is swapped ;if write op mov cx,128/2 ;length of move in words mov al,readop test al,al ;which way? jnz rwmove ;skip if read ; ; write operation, mark and switch direction mov hstwrt,1 ;hstwrt = 1 (dirty buffer now) xchg si,di ;source/dest index swap mov ax,DS mov ES,ax mov DS,dma_seg ;setup DS,ES for write ; rwmove: cld ! rep movs AX,AX ;move as 16 bit words pop ES ! pop DS ;restore segment registers ; ; data has been moved to/from host buffer cmp wrtype,wrdir ;write type to directory? mov al,erflag ;in case of errors jnz return_rw ;no further processing ; ; clear host buffer for directory write test al,al ;errors? jnz return_rw ;skip if so mov hstwrt,0 ;buffer written call writehst mov al,erflag return_rw: ret ; ;***************************************************** ;* * ;* WRITEHST performs the physical write to the host * ;* disk, while READHST reads the physical disk. * ;* * ;***************************************************** writehst: ret ; readhst: ret ; ;***************************************************** ;* * ;* Use the GENDEF utility to create disk def tables * ;* * ;***************************************************** dpbase equ offset $ ; disk parameter tables go here ; ;***************************************************** ;* * ;* Uninitialized RAM areas follow, including the * ;* areas created by the GENDEF utility listed above. * ;* * ;***************************************************** sek_dsk rb 1 ;seek disk number sek_trk rw 1 ;seek track number sek_sec rb 1 ;seek sector number ; hst_dsk rb 1 ;host disk number hst_trk rw 1 ;host track number hst_sec rb 1 ;host sector number ; sek_hst rb 1 ;seek shr secshf hst_act rb 1 ;host active flag hst_wrt rb 1 ;host written flag ; una_cnt rb 1 ;unalloc rec cnt una_dsk rb 1 ;last unalloc disk una_trk rw 1 ;last unalloc track una_sec rb 1 ;last unalloc sector ; erflag rb 1 ;error reporting rsflag rb 1 ;read sector flag readop rb 1 ;1 if read operation wrtype rb 1 ;write operation type dma_seg rw 1 ;last dma segment dma_off rw 1 ;last dma offset hstbuf rb hstsi% title 'COPYDISK 1 Feb 82' ver equ 20 ; Version 2.0 -jrp ; COPYDISK duplicates entire diskettes using all of the ; available storage as a multiple track buffer. ; This program must be built with a large extra segment ; as follows: ; ASM86 COPYDISK ; GENCMD COPYDISK EXTRA[M0200,XFF00] ; This allows COPYDISK to utilize all the left-over memory in your ; system as its buffer. cseg ; code segment start: mov si,offset signon_message call pmsg ; print signon message next_copy: ; reload local stack for retries. pushf ; save interrupt flag in stack pop bx ; put it in bx cli ; disable interrupts mov ax,ds ; get our data segment mov ss,ax ; and use as stack segment mov sp,offset stack_end ; set stack pointer push bx ; flags back into stack popf ; restore interrupt status mov si,offset source_message ; prompt for source drive call get_drive ; request drive code cmp al, cr - 'A' ; see if it was a jne next_1 ; no, continue jmp exit ; yes, we should exit next_1: cmp al,drive_cnt ; see if valid drive code jb save_source ; yes, go save it drive_err: mov si,offset bad_drive ; else, print call pmsg ; a bad drive message jmp another ; and try to get another save_source: mov source,al ; save it as the source drive add al,'A' ; make ascii drive code mov source_ascii,al ; save for messages mov cl,source ; get source drive mov dl,0 ; force first time selection call seldsk ; select it test bx,bx ; insure the drive exists jz drive_err ; no, fatal mov si,ES:word ptr 10[bx] ; get pointer to DPB ; create local copy of disk definition push ds ! push es ; save segments pop ds ! pop es ; and exchange them mov di,offset disk_def ; point to local disk def table mov cx,15 ; diskdef is 15 bytes long cld ! rep movsb ; copy it push ds ! push es ; swap back pop ds ! pop es ; segment registers mov dx,es:word ptr 00[bx] ; get secttran table address mov cx,0 ; logical sector zero call sectran ; find out first sector number mov base_sector,bx ; save this for track reads mov si,offset dest_message ; prompt for destination call get_drive ; get the drive code cmp al,source ; see if same as source jne not_same ; no, go see if > max mov si,offset same_message ; can't have same drive call pmsg ; so we print message jmp another ; and go try again not_same: cmp al,drive_cnt ; is dest > max? jnb drive_err ; go print invalid drive error mov dest,al ; save destination drive add al,'A' ; make ascii drive code mov dest_ascii,al ; save for messages mov cl,dest ; get destination drive mov dl,0 ; force first time selection call seldsk ; select destination drive test bx,bx ; insure drive exists jz drive_err ; no, go error out mov di,ES:word ptr 10[bx] ; point to destination DPB mov si,offset disk_def ; point to source drives def mov cx,15 ; length of a definition cld ! rep cmpsb ; compare the definitions je next_2 ; must be equal. jmp different_type ; else go print error next_2: mov dx,es:word ptr 00[bx] ; get secttran table address mov cx,0 ; logical sector zero call sectran ; find out first sector number cmp bx,base_sector ; make sure its the same je next_3 ; the same is OK, jmp different_type ; no, fatal error next_3: ; determine track capacity mov ax,spt ; get the sectors per track mov dl,128 ; length of a sector mul dl ; get track capacity mov track_size,ax ; save it ; determine number of tracks on diskette mov al,blm ; get block mask inc al ; plus 1 gives sectors/block mov ah,0 ; make 16 bits mov dx,0 ; make 32 bits mul dsm ; total sectors/data area add ax,spt ; force round up dec ax ; by adding SPT-1 div spt ; compute number of tracks add ax,off ; add in operating sys tracks dec ax ; number of last track mov max_tra&z ;host buffer end |F=PF^PvVvPvދYvP\PvP\^ƉFܸEPv4^XF=|-Pv4^XF؉F+Pv4^Xv޸PvL\PaF썆\FVF uFF Fv4^(~0FF PvVF޸PvދF^^PvVwPvދYvFށP\PvP\^ƉF܍\PF썆\FFF9FF*F FFF FFދF u,F Fv4^t4vXZTPZFF KF=|!v 4^4XRPvXZTPZv 4^4X3RPvXZTPZvލ\Pvt4\FvFv 4^4XFvFF uF;FrFFFwv 4XFܸFF[FFܸFFFCcsdDxXuUoObBfegewod\F uF;FwF u-Pv܊^;t 0PF^;t.Pv4vvЃv,4Xv,4XvVv4,X^;wPvVvvЃF;FwvvY+FvvvvЃF uF u)v4,X uPvVvvЃv4XPv4vvЃ]4F̍v4^Fv4,X ux Pv̊^;t Pv̊^;t PvX6APv̊^;sZPv̊^;v Pv̊Yv́4XwPvXF҉FЉFθF̸FPv4^^ƉFv4,X uv̊ u<Pv̊^;t F́F<>Pv̊^;t F́FFPv4^VF^ƉXF=}P P Pv̊ uv́4Xv,4Xv́4X+F̸>PvЊ^;tvЁ4XF̸PPv! ^;uPvv ^;uPPv ^;uP PPEPFԉXFPvQP ]fFFF=|,vV^ƉƋ4 u v4XF=tPPKFF uPv4X5^#PvtXPv^;:PFƊ^;tF disks 2 diskdef 0,1,26,6,1024,243,64,64,2 diskdef 1,0 endef PF^#PPvX^P^ƉƊD^;tPvtY PvX^P^ƉƊDPvXPPvtX^#^;t3Pv4^;tPvtX PvtX PvtX v4XPvtX5^# uvvPvX uF uv4VPMPv4VFP6^;PYPvtXvtPvtX ufPvtvtV#FPvV^ƉXPvtX5^# u F uv4V#PPv4t#t!XZYuRPvtXZTPZPvtX^# uvttXZ uv4t!,\t4XZvtVPv4V!PFPYPF^;|1PvVvt^ƉƊ^;t v4XPYPF^+ƙRPvtTY[ӉTF]ËF u#v4 u v4Vv]Ë]PvtX^# u6PvtX^# uPv4^;tPvtXvtV P PPPvt XPvtƊ^Pvt X Pvt XPvt^ƉXv4V~PvtXPvtX^# u PvtƊ^;t% PvtXPvt X Pvt X]øPvtt XZY!RFZFFF=|vttPYPvX^RPvtt XZ^_^_;u;rPYPvX^Pvt^PPkFF3RPv4t!XZTPZv4V!P>FF=t F=t=PPYPPYPvX^Pvt^P5F F u v4XF u@PvtY PYPvX^Pvt X]L PvtX^# ugvtvt X^;|Pvt vt^ƉXvt XRPvtt XZ^_RPvttXZ^_;u;r.vt XRPvtt XZ^_RPvtXZTPZFvt PYPvX^^;|PYPvX^Pvt^PPvXRPPvtt XZY^_RPv4t!XZTPZv4V"PA u@PvtY v4XIPvtY#]UNV]vvX^Fv&demacro FCOM dw 0d1d8h endm codemacro FCOM src:Db(0,7) db 0d8h dbit 5(1ah),3(src(0)) endm codemacro FCOM src:Mb segfix src db 0d8h modrm 2,src endm codemacro FCOM src:Mw segfix src db 0dch modrm 2,src endm codemacro FCOMP dw 0d9d8h endm codemacro FCOMP src:Db(0,7) db 0d8h dbit 5(1bh),3(src(0))  endm codemacro FCOMP src:Mb segfix src db 0d8h modrm 3,src endm codemacro FCOMP src:Mw segfix src db 0dch modrm 3,src endm codemacro FCOMPP dw 0c9deh endm codemacro FICOM src:Mb segfix src db 0dah modrm 2,src endm codemacro FICOM src:Mw segfix src db 0deh modrm 2,src endm codemacro FICOMP src:Mb segfix src db 0dah modrm 3,src endm codemacro FICOMP src:Mw segfix src db 0deh modrm 3,src endm codemacro FTST dw 0e4d9h endm codemacro FXAM dw 0e5d9h endm codemacro FPTAN dw 0f2d9h endm codemacro FPATAN dw 0f3d9h endm codemacro F2XM1 dw 0f0d9h endm codemacro FYL2X dw 0f1d9h endm codemacro FYL2XP1 dw 0f9d9h endm codemacro FLDZ dw 0eed9h endm codemacro FLD1 dw 0e8d9h endm codemacro FLDPI dw 0ebd9h endm codemacro FLDL2T dw 0e9d9h endm codemacro FLDL2E dw 0ead9h endm codemacro FLDLG2 dw 0ecd9h endm codemacro FLDLN2 dw 0edd9h endm codemacro FINIT dw 0e3dbh endm FNINIT equ FINIT codemacro FDISI dw 0e1dbh endm FNDISI equ FDISI codemacro FENI dw 0e0dbh endm FNENI equ FENI codemacro FLDCW src:Mw segfix src db 0d9h modrm 5,src endm codemacro FSTCW dst:Mw segfix dst db 0d9h modrm 7,dst endm FNSTCW equ FSTCW codemacro FSTSW dst:Mw segfix dst db 0ddh modrm 7,dst  endm FNSTSW equ FSTSW codemacro FCLEX dw 0e2dbh endm FNCLEX equ FCLEX codemacro FSAVE dst:M segfix dst db 0ddh modrm 6,dst endm FNSAVE equ FSAVE codemacro FRSTOR src:M segfix src db 0ddh modrm 4,src endm codemacro FSTENV dst:M segfix dst db 0d9h modrm 6,dst endm FNSTENV equ FSTENV codemacro FLDENV src:M  segfix src db 0d9h modrm 4,src endm codemacro FINCSTP dw 0f7d9h endm codemacro FDECSTP dw 0f6d9h endm codemacro FFREE dst:Db(0,7) db 0ddh dbit 5(18h),3(dst(0)) endm codemacro FNOP dw 0d0ddh endm FWAIT equ WAIT list DPv D0%$P%"P[P,]=t=tv + PY]U PPvP5 P PgPf3]UvvI]U0Ft- F=Ft= uF]Ã~Yu]Ã~Nu3]UPPuPPFtF0%]U u3]=t3]ø]U3P P}P5 @P, !FF=t=u]3]UH=Ft=t = t=uF]Ã~ u ]Ã~  ]ËF]U졈H3SSS( >F ^^ u > |F>1u>t > tF[FUzPP Iv0%t- 'nolist ; ***************************** ; * Codemacros for 8087 * ; * numeric data processor: * ; *************************** ; ; stack references: st equ 0 ; stack top (= register 0) st0 equ 0 ; register 0 st1 equ 1 ; register 1 st2 equ 2 ; register 2 st3 equ 3 ; register 3 st4 equ 4 ; register 4 st5 equ 5 ; register 5 st6 equ 6 ; register 6 st7 equ 7 ; register 7 ; ; codemacro FLD src:Mb segfix src db 0d9h modrm 0,src endm codemacro FLD src:Mw segfix src db 0ddh modrm 0,src endm codemacro FLD src:Db(0,7) db 0d9h dbit 5(18h),3(src(0)) endm codemacro FLDTR src:M segfix src db 0dbh modrm 5,src endm codemacro FST dst:Mb  segfix dst db 0d9h modrm 2,dst endm codemacro FST dst:Mw segfix dst db 0ddh modrm 2,dst endm codemacro FST dst:Db(0,7) db 0ddh dbit 5(1ah),3(dst(0)) endm codemacro FSTP dst:Mb segfix dst db 0d9h modrm 3,dst endm codemacro FSTP dst:Mw segfix dst db 0ddh modrm 3,dst endm codemacro FSTP  dst:Db(0,7) db 0ddh dbit 5(1bh),3(dst(0)) endm codemacro FSTPTR dst:M segfix dst db 0dbh modrm 7,dst endm codemacro FXCH dw 0c9d9h endm codemacro FXCH dst:Db(0,7) db 0d9h dbit 5(19h),3(dst(0)) endm codemacro FILD src:Mb segfix src db 0dbh modrm 0,src endm codemacro FILDLI src:Mw segfix src db  0dfh modrm 5,src endm codemacro FILD src:Mw segfix src db 0dfh modrm 0,src endm codemacro FIST dst:Mb segfix dst db 0dbh modrm 2,dst endm codemacro FIST dst:Mw segfix dst db 0dfh modrm 2,dst endm codemacro FISTP dst:Mb segfix dst db 0dbh modrm 3,dst endm codemacro FISTPLI dst:Mw segfix dst db 0dfh modrm 7,dst endm codemacro FISTP dst:Mw segfix dst db 0dfh modrm 3,dst endm codemacro FBLD src:Mb segfix src db 0dfh modrm 4,src endm codemacro FBSTP dst:Mb segfix dst db 0dfh modrm 6,dst endm codemacro FADD dw 0c1d8h endm codemacro FADD dst:Db(0),src:Db(0,7) db 0d8h dbit  5(18h),3(src(0)) endm codemacro FADD src:Mb segfix src db 0d8h modrm 0,src endm codemacro FADD src:Mw segfix src db 0dch modrm 0,src endm codemacro FADD dst:Db(0,7),src:Db(0) db 0dch dbit 5(18h),3(dst(0)) endm codemacro FADDP dst:Db(0,7),src:Db(0) db 0deh dbit 5(18h),3(dst(0)) endm codemacro FIADD src:Mb segfix src db 0dah modrm 0,src endm codemacro FIADD src:Mw segfix src db 0deh modrm 0,src endm codemacro FSUB dw 0e1d8h endm codemacro FSUB dst:Db(0),src:Db(0,7) db 0d8h dbit 5(1ch),3(src(0)) endm codemacro FSUB src:Mb segfix src db 0d8h modrm 4,src endm codemacro FSUB src:Mw segfix src db 0dch ' modrm 4,src endm codemacro FSUB dst:Db(0,7),src:Db(0) db 0dch dbit 5(1ch),3(dst(0)) endm codemacro FSUBP dst:Db(0,7),src:Db(0) db 0deh dbit 5(1ch),3(dst(0)) endm codemacro FISUB src:Mb segfix src db 0dah modrm 4,src endm codemacro FISUB src:Mw segfix src db 0deh modrm 4,src endm codemacro FSUBR dw 0e9d8h endm  codemacro FSUBR dst:Db(0),src:Db(0,7) db 0d8h dbit 5(1dh),3(src(0)) endm codemacro FSUBR src:Mb segfix src db 0d8h modrm 5,src endm codemacro FSUBR src:Mw segfix src db 0dch modrm 5,src endm codemacro FSUBR dst:Db(0,7),src:Db(0) db 0dch dbit 5(1dh),3(dst(0)) endm codemacro FSUBRP dst:Db(0,7),src:Db(0) db 0deh  dbit 5(1dh),3(dst(0)) endm codemacro FISUBR src:Mb segfix src db 0dah modrm 5,src endm codemacro FISUBR src:Mw segfix src db 0deh modrm 5,src endm codemacro FMUL dw 0c9d8h endm codemacro FMUL dst:Db(0),src:Db(0,7) db 0d8h dbit 5(19h),3(src(0)) endm codemacro FMUL src:Mb segfix src db 0d8h modrm 1,src endm codemacro FMUL src:Mw segfix src db 0dch modrm 1,src endm codemacro FMUL dst:Db(0,7),src:Db(0) db 0dch dbit 5(19h),3(dst(0)) endm codemacro FMULP dst:Db(0,7),src:Db(0) db 0deh dbit 5(19h),3(dst(0)) endm codemacro FIMUL src:Mb segfix src db 0dah modrm 1,src endm codemacro FIMUL src:Mw segfix src db 0deh modrm 1,src endm codemacro FDIV dw 0f1d8h endm codemacro FDIV dst:Db(0),src:Db(0,7) db 0d8h dbit 5(1eh),3(src(0)) endm codemacro FDIV src:Mb segfix src db 0d8h modrm 6,src endm codemacro FDIV src:Mw segfix src db 0dch modrm 6,src endm codemacro FDIV dst:Db(0,7),src:Db(0) db 0dch dbit 5(1eh),3(dst(0)) endm codemacro FDIVP dst:Db(0,7),src:Db(0) db 0deh dbit 5(1eh),3(dst(0)) endm codemacro FIDIV src:Mb segfix src db 0dah modrm 6,src endm codemacro FIDIV src:Mw segfix src db 0deh modrm 6,src endm codemacro FDIVR dw 0f9d8h endm codemacro FDIVR dst:Db(0),src:Db(0,7) db 0d8h dbit 5(1fh),3(src(0)) endm codemacro  FDIVR src:Mb segfix src db 0d8h modrm 7,src endm codemacro FDIVR src:Mw segfix src db 0dch modrm 7,src endm codemacro FDIVR dst:Db(0,7),src:Db(0) db 0dch dbit 5(1fh),3(dst(0)) endm codemacro FDIVRP dst:Db(0,7),src:Db(0) db 0deh dbit 5(1fh),3(dst(0)) endm codemacro FIDIVR src:Mb segfix src db 0dah modrm  7,src endm codemacro FIDIVR src:Mw segfix src db 0deh modrm 7,src endm codemacro FSQRT dw 0fad9h endm codemacro FSCALE dw 0fdd9h endm codemacro FPREM dw 0f8d9h endm codemacro FRNDINT dw 0fcd9h endm codemacro FXTRACT dw 0f4d9h endm codemacro FABS dw 0e1d9h endm codemacro FCHS dw 0e0d9h endm co