#܂-Љ!sĐfoNNNNNNNNNNNNNNNNNNNNNN1 vv!>K > !'zӂv> >> 0>_Ӏw(vۀ>_1 10 MSEC uu!ww!!2!!!'E 1 0TRUE !E>21p>28>x>x>b>k>e>l>Lh>i>jkkikk/j&u`tUu`t.-l%ju>2~><2>_!:2ʕ!ڠ~d>_!,:2ʭ!~h>2uu:_T0 ͆}o[Rbk {0bk0"t! "v>:rO:sG*vp>q#=˜ *t`&.utup%ˡΡ*vq#q#} `-ʫ> =ÿ*: **:""2!0">2ɯ2:!n™!=Ù*``:=``:=+}ɯ2ɯ//2ɯ*DMV! >r#= tu x( >=> 2*"!6Ù:!*w#":=2!6Ù*0!%:':(͐ |NNNNNNNNNNNNNNNN`NNNNNNNNNNNNNNNNNNNNNN 1166313 14 1 0FALSE 1 0TRUE 1 0FALSE 1 3128 05 1 148 48 1 14 1 301 15 1 120 100 BYTES 1 316 06 1 1128 4 4096 1 177 8000 1 12 1 300 07 1 0FALSENNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNN͖*!"͖! :y(o&)^#V*:!! 02!ͧ "~<(:G:!*w*#> "*R(!0 "R":!!ͧ :ʦͪ:!!G>O0G*>0G}怰o~2&":!nÙ:!!?G:0G*}o%8`*~2&":!=Ù*0"Æ>_T0 ͆}o[Rbk {0bk0*!}o[RR"}0o![R},{0_!^)|?G*T])|?(!͐= *}0oÆ**:**KNNNNNNNNNNNNNNNNpNNNNNNNNNNNNNNNNNNNNNN 20000TRUE 001 2 303H 00208 2 380H 00309 2 200000 255 NULLS004 2 31 00510 2 38 00611 2 0TRUE 007 2+d  = mp͞@!~ʃ5@* ͡. ;ͣW!E# ¡")!91)ỳ*)Þʥzʖ=ʐ=|zJz?4)z zsPNNNNNNNNNNNNNNNNN5NNNNNNNNNNNNNNNNNNNNN!: **:""2!0">2ɯ2:!n™!=Ù*``:=``:=+}ɯ2ɯ//2ɯ*DMV! >r#= tu x( >=> 2*"!6Ù:!*w#":=2!6Ù*0!%:':(͐ Æ r#} P:*~w$o{(?2͙Q:zJ!:2>2!> _> ͇> Çͭ͘~#͇í _2ϳ<ˬϳˬˬϳ͒ˬ @4NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN2ԉ'zːpNNNNNNNNNNNNNNNNNNNNNN!2:2a{_p:ɬ:=2γ!d!6#5Ь>$͇!ͭ͡ʆͺKͺ>>͇ !F#xʙ~wÊw!"͒!~6͘*~ ᭷͇#έ>?͇ͺK ȭ=_.:;<>  o$>!ϳ2* "D@G:K:wQx2pt#*d6?fwS{j#6 t.¤ʤ#*”6?ÖwƒʫÚ#6 ¤#6­" #~?Į ¼xDIR ERA TYPESAVEREN USERҰt!ˮyгyNNNNNNNNNNNNNNNN%LNNNNNNNNNNNNNNNNNNNNNN2E>! ^#V w#P:BO|^#V#"##"##"##"!O*!O*|!6ʝ6>¯*w#w*w#w'û*·! J*""!N#F*^#V*~#foyx*{_zW+*yx#*DM*s#r*s#ryOxG*0MD!!N: EG>O: \S*C :qn& ^#V>O^"*}:*)=":O:o"*C *C!ͮ~2~2ͦ:2ͮ:޸O:w:w |g}o*# NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN# y# 21y_ͷy2ͼج2:r1ͭ͘A͇ j >1͇0͇!͵ͭ2ȭ:‹!_~#fo͢No Files:!ȭ!г ~ ޯ#0 Wxxȭ؂G º~ # ޯx~#!~ɯ2ϳü:ü:=!>!г~ @@I#~+ I 6?#BPØWլ̛а=`O> բİ{͘Êͅ>:͇ͅx ¬ª>  ð> ͇x ð Œ>.͇Ì͡аݬZ ͢All (Y/N)?!!5K#~YK#"LNNNNNNNNNNNNNNNN}NNNNNNNNNNNNNNNNNNNNNN ):BO!yoxg*:BO}!N#F "*#*s#r^ ~!J! J*:o$*C~i6iw**{#zr+s{ozg**͕** Ĺ,w͜͸ڹͲ!!N#F$**O!~#Һ:A#~$=2Ek͌BNNNNNNNNNNNNNNNNڹNNNNNNNNNNNNNNNNNNNNNN>PϳØȭ¬v͖͘!6!~=dw4!~ʘ͇ |͡*ʘ*=ʘ͢Read Error ȭ:=2͒ʅʘ>2ͨȭϳ걯2o&)|+!͵ϳñϳЬ<͢No SpaceͲØȭ:լ!͢File Existsk!ϳ߳* ==_n#"nG!~Wpnp2ϳϳ2!q*C"͡ʔ*JҔ^:Oyʃ?|x | s-|N-# S:2E!~Яw>T D^6kƹ-äPYyѻ 5*{zBK5ڋ>*Cw~#+w#w+ɯ2E22i^ *C :~ۼw~͔͔# # NNNNNNNNNNNNNNNNNNC.NNNNNNNNNNNNNNNNNNNNNN}| ͢Bad LoadØ= ͎ !~2ϳ>~2߳2\!ϳ!!~[ [#M~l#`x2͘ͲͼK͎ ȭ:_COM :г !ȭK$$$ SUB"C{2!"E9"1A22!ty)K!G_^#V*CȶζԶ~E ,&-AGMS!ʴ!մô!ô!ܴBdos Err On : $Bad Sector$Select$File R/O$ɵ:BA2ƴӵӵ!~6&NNNNNNNNNNNNNNNN 5rNNNNNNNNNNNNNNNNNNNNNNͼ w ~>2!E5T*C!"C"C!w# F! w͌x2͢*C ~<wʃG:!ʎì 4~ʶ¬:<ʶ$ʶïZͻx>2>2ͻ:!Z2:Eẅ́͊ѷͲҸ>2>2T*CGͻ:ẅ́n>2;O ^DM;}H>"*C ::ddslO s#r:E͊:==»y==»*Ww#*"ѷ͸*:G#š"ڹѷ͸:!Ҿw4!iw:ҸZ!E~=26PNNNNNNNNNNNNNNNNNpNNNNNNNNNNNNNNNNNNNNNN O͐  :E B 2>: b# : y! 4 5~yy5 6yҐ^H@Oy H H: –ͬ  #Hɵ: !  Hù H H $O͐ӵ: 2 *CN# x: 2 p&x~+é7ɵ2 H! >w_: ! 5ͤNkͱ¦ͱxʊ#Nx: ! 2 ͤ! 5™#wO~x½p Hy<< ·ʑ :!qMDӵ#,NNNNNNNNNNNNNNNNNN `!NNNNNNNNNNNNNNNNNNNNNNҸ2*C!!~~#~O~G#n,-.‹! w! yG!x͢.:E<ʄ! q!pQ:E<. ʄ$.:E<ʄi6}2ExN! ~态O>G~G!~G} *C!r#r#r ^ͥ_y#x#{s+p+q-*C ͥ!!q#p#w*:BOYG}*MD "ã:!Bw!>2*C~=2u:B2~2wE:A*Cw>"!""2B!"ڹ!rQQQâ~?ͦ~?rQ*"CQ-Q͜QüQrQ$Q*BNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN3։(zːo'NNNNNNNNNNNNNNNNNNNNNN):B"ڹ*)*)Q;*"E:;:A2AQÓQÜQҿ*C}/_|/*W}_*"}o|g":ʑ*C6:ʑw:2E**E}DQ>2EÕ~1 E@yÌH}~ÑÕ<)1z2A{2B>͉uuuu! >2:2<22<ʌ*"!n"_͡uuuu MEGATEL QUARK 51K CP/M V2.24 R02 preliminary !v >3¯2 21:COY$yNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNE"n!"f!"h!w#"j!"l!E"nw$vۀ2ہӃ>Ӏ$ۀہӃ>Ӏ$:ӷ^**:<2*d:HӀ$ x:Ӏ*$>7:O**̷R+һ˯ogd:ӷ):ӷ˯U}ӃzӁ:Ӏ$>k>K2:Ӏ+I|*:ӁӃ:Ӏ$2*":Ӂ ?hң>7hß*)[zQ+|M>Ӏv*f"!E"f:O>2>Ӏ$>2ʜ xsڧ̯Þۂ2Ӂ2*"f!~:̾w :!Ӿwd4vv*hv!Ӷv?>ӀͳoaNNNNNNNNNNNNNNNNrTNNNNNNNNNNNNNNNNNNNNNN~2D:COE:BO@,:BO:AW!Jy͌HǷU:Dº  @ _:O$> Ϳ>2!"2!":^=‚2 >3:¥xµ!~##ʝ͝ê:xyͪ!͊ͪ͝:xyyʀʀÀ: +*p:0<xůf___yO_ yɯ 0 0m(j*r:©:uӷ ʘ :uGy@ʀmʳ>my_lll`@:uӷAA :uGAy:ʝ@|NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN*u~:Oͨ:<ʖ:ӂv>2>:>Ӏ$>2X p̈́r%!~#wO>Ӏy>2!~#w>byC*~:ӂ>2v>2>³>Ӏ$>2X ̈́rÙ>r2ix2j:2kЯ:ӷ"̈́ͭ:j!ͳ!.:jG !x!:i:ӷ::ӷ::k=Q2k!!~:͆NQͭί7:2k:NlYQ!C~ίͭ:i{>ɯ<:ӷ>O:ӷʛ:ӷʛ Üy_O:ӷʫy !f~^#V#=~³^#V#~ͭ READ WRITE SEEK WITH READ SEʜNNNNNNNNNNNNNNNNAeNNNNNNNNNNNNNNNNNNNNNNm!9"\1\:84>2:*\>2C!:^={h!9"\1\y*\y2i&)~#foC{†`i n&C2>22228*":ӻ:<*":ӻ2K:G~<#~ͫ6  >2:w8:<*"ͫ:<*"ͫƷO:^=:ӑy͓y! 2l^#V ~#fol++~2 ~#foY2~2~2#~2_!g~/!_^#V!:ӻ:Է6K#:Ӿ+~#:Է+6#6  ǒNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNEK WITH WRITE>P`nψϣϯ>PhhhhPhhhhh, Drive Not Ready, Write Protect, Write Fault, Record/Sector Not Found, Corrupt Data/ID mark/CRC, Lost Data, Data ReQuest Fault, Busy, Bad/Wrong Track, Corrupt ID mark/CRC, Write Protect/Write Fault, Corrupt ID mark Retry (Y/N) ?  Allow (Y/N) ?  WARNING : CORRUPT DATA TRANSFERED ""!9"1W2ugto|@ʝ}!q|:=!p~<'`6+~<'`6+~<'$6*l#"lw2:2:<:ѷ:ӷ#2:GNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN *^#V+:O:ӹ8>2 :<ͨ:2*\: Է>2 2>2 ԯ2 !9"\1\!9:8ژ:Oz:ȯ2 y2 !9"\1\!9:8ړ:Oz: :2 Ol~#fo:O:1+ "y2:2 *": Է1=2 :! Ծ1*<1*:Ӿ1#:=$*#": Ol~#fo:"2ԯ2:ȯ2 >2ԯ2 :G:Ӑ_:ԷO{Vȷ PȀ2F""C"####:Ӿ*ʛ k"~ʬ#~ͤ*6#:w#*s#r#:w:8:Է*#Ͱ*"U*!^#V:G:ӐG:Է!ɠaNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNN***:>22 2 ͏n*06[#Ow#yw#6:#Ow#yw#6:#Ow#yw#6]/G~<W~_,V,~x--s^,F,{Ny<_yO q>28!q"9>202(>2QCERT223COM>>?ABQSYSG D<<<Ѱyi&) !~#fo~#fo <?ƒ ^g~OO #@z>/<e33ZO _ W{X!>:AO !>*R!>*R BIOS Error on : T-, S-!p=|~#O JNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN!go*: Է#*66:w: :ͤ*|}*<***MD! s! NC! ~w{" r*MDq#p>Ú>2!ý>ò>22 9.:<*:w:>G:O:>y*:w:>G:>:Oh*K|g}o>222"`)":!Ӿʅwo& ^#fk"!:ӷ~•×?w:ӷ§> w*f"*h"*j"*l"*n"*"f*"h*"j*"l*"n!"f!"h!#~"j!"l!QNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNN Please mount disk :AO in drive :0O, press when ready   ` ttPROFILEͧ >2:sQ!"<<<iYNeneration Uti Version 2.23 YPE RETURN DESTINATION DRIVE NAME (OR RETURN TO REBOOT) DEԞԧ԰uuԊkԀkԀkԀkԀz  ט'ا׶'٧ 'ڧhTBNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN1Ӊ%wȐlQNNNNNNNNNNNNNNNNNNNNNNڻ(?VC HqC 0C HqC 0C HqC 0C HqC 0( # (L?# (L?# (L?# (L? !"#$  %&'( !"#$  %&'(%&'(1234=>?@ )*+,5678ABCD !"#$ !"#$  %&'( !"#$  %&'(%&'(1234=>?@ )*+,5678ABCD !"#$   NNNNNNNNNNNNNNNN$NNNNNNNNNNNNNNNNNNNNNN>>( <02&((*$ **>> "&*2""  >> " $>> <" <"">""""""8 >>""*., "">""<""<""<" "<"""""<> < >> <  &"""">"""""$(0($" >"6**"""""2*&"""""""<""< """*$<""<($"" ">""""""""""""""**6"""""""> >>00000> >>">p|NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN!5CDDB02CDA !"#$  %&'(%&'(1234=>?@ )*+,5678ABCD !"#$   s=!ͧ 0>2:s_!!3MEGATEL QUARK System Generation Utility Version 2.23 R01SOURCE DRIVE NAME (OR RETURN TO SKIP) SOURCE ON , THEN TYPE RETURN DESTINATION DRIVE NAME (OR RETURN TO REBOOT) DESTINATION ON , THEN TYPE RETURN PERMANENT ERROR, TYPE RETURN TO IGNORE FUNCTION COMPLETENO SOURCE FILE ON DISKSOURCE FILE INCOMPLETE,!aBNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN $$$ ,2"< &""<  8&" ,2"" "$(4$4**"",2"""""",2"< "&,2  << """&""""**""""&>> ***:}NNNNNNNNNNNNNNNN7NNNNNNNNNNNNNNNNNNNNN!A9C0211800019EB2AA4022B7DB4C2EAF2 :1003D600032A9A025E23567EB3C8234E234623225F :1003E6009A02696022A402EB229C022AA202233A04 :10;255 BECOMES 00 JNZ RDOK ;OK TO READ IF NOT 255 ; ; FILE NOT PRESENT, ERROR AND REBOOT ; LXI H,NOFILE CALL CRMSG JMP REBOOT ; ;file present ; RDOK: XRA A STA FCBCR ;CURRENT RECORD = 0 ; ; PRE-READ AREA FROM TPA TO LOADP ; MVI C,(loadaddr-tpa)/cpmsectleng ; PRE-READ FILE PRERD: PUSH B ;SAVE COUNT LXI D,FCB ;INPUT FILE CONTROL COUNT CALL DREAD ;ASSUME RsNNNNNNNNNNNNNNNNN+NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNFNNNNNNNNNNNNNNNNNNNNNNSET TO DEFAULT BUFFER POP B ;RESTORE COUNT ORA A JNZ BADRD ;CANNOT ENCOUNTER END-OF FILE DCR C ;CONT DOWN JNZ PRERD ;*!*$*'*'*3F#~!uw<#C! ~#fo~~#fo~22!"MD!u"!t^#V~"#^#V#""*MD*N:ʮñ! ͧ 0**+}*^#V~#N#F#"i`""*#:=*#"MD!u:"2Ð1!85~2p:] ~\0 < """"UUUU 0 00 0 $B$B~$~$8DD8$$ >"">""**>"">">>>>>".&."> >><0($ >TiNNNNNNNNNNNNNNNNNN INNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN3׉)z̐pNNNNNNNNNNNNNNNNNNNNNNASM COM@QBIOS ASM QBIOS ASM !"#$QBIOS ASM%&'()*+,-./01234QBIOS ASMZ56789:aNNNNNNNNNNNNNNNNUNNNNNNNNNNNNNNNNNNNNNNnpNNNNNNNNNNNNNNNNNfNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNkNNNNNNNNNNNNNNNNNNNNNNnPNNNNNNNNNNNNNNNNNZNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNN!nBNNNNNNNNNNNNNNNN8NNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNnaNNNNNNNNNNNNNNNN 7NNNNNNNNNNNNNNNNNNNNNN1*" COPYRIGHT(C) 1978, DIGITAL RESEARCH á 4êü /L9ASMPRNHEXZpNNNNNNNNNNNNNNNNN dNNNNNNNNNNNNNNNNNNNNNN!4w_#~ ʸ A:4~~# ¼ > \ ?ʻ w# !ͼ ? !ͼ .KNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN2Չ'xɐlv*NNNNNNNNNNNNNNNNNNNNNN!)ͼ !ͼ :5͡ :6:6͡ :7͡ :\ ʻ 24!dͮ 25ͮ 27ͮ 26!8 ( ʃ !Y 1  :7ʞ !z 8  !"2D2X2#! 8 !ͼ z{* ! !"!8 w#  +6# *#"~!ͼ G:6QxJQS*!w#"! 1 !"!Y~~# …¡z!ͼ wʹ* ! w#" ! 8 !" ! zz_O4:  :6yLaNNNNNNNNNNNNNNNN#yNNNNNNNNNNNNNNNNNNNNNN?'  v:P@< !  PP27 ( *"  NZZ NCC POPEP M x_BH!œ#¶ ¦{KÈCÈ<:JCR:  !6 s!#  ɯ<:O=_Z!F!V#fjQ̓E!^#Vo&)~#FxGyѯ<àn8!~ڢͅ6~44O! s#r!~ ڿ6ͅ^4!mw!wp!~ͅ!55N! N#fio&)^#fkNNNNNNNNNNNNNNNNHNNNNNNNNNNNNNNNNNNNNNN:! G~#x=2> > ! >x6 #='G! ~ p( O*}O>4?:7w:#ĸ*"!͸* }w>ͪg( ʆ1 Y :7ʗ8 z !<ͼ CP/M ASSEMBLER - VER 2.0 NO SOURCE FILE PRESENT NO DIRECTORY SPACE SOURCE FILE NAME ERROR SOURCE FILE READ ERROR OUTPUT FILE WRITE ERROR CANNOT CLOSE FILES END OF ASSEMBLY G:7xʘ!#~ʄl͸Ä**!O {zʊ͸*"!!#^4!$wͯͯWƐ'@'ê>:ͪ!#^Ww*!{͚|͚}͚͚{!$~#͚͚> ͪ> ͪNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNz'{ͅ>ɯo>g"k!m6ů{_zW5>)D*kOxGd !m?FDM!xGyOڂÃ)sn55)=â|g}o=î--#zg{ozg{ozg{oÓ:: ;,!ɯ22=2l!"]!~H5_!m~0:ą:  *":  :‰:̅ԅ!^#=ʅVq”*qͦ1& O:lµ̅>2ly:_!w~!s!m~ùy !~=w_!m~ ͅYpNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN@2 0 0:x0_<2! wI2 2> 2 >2ɯ22 !~@_6^4#: w~$w: 0 q: A: A͋q: a{_2  2 - !ɯ2I:  ;*:  ͭͷ ͭ͋>9q>9: '!2 >9 7:! 6 >2>2: 2 Qͭ:Ğ! :lj<͖<j<|<: OʊQ>ÖH >2 2 û: B­>ôD> ¸!52 !"!N#~#A07O! ~*!) " pNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNͰ>2lyPLnR>UX:l̅2l͓*>ERʵ2C!" """ :ʼ:*1 |R|ͦ0FIL: R  R* } *" :¿::¿üX!C^#fk[@ :Œ:=ʌG!ʆF#H vÛc*| EH ͺ,^1 ͦ *""1 EH DH ͺ,1 ͦ :  1:  " > 2 NNNNNNNNNNNNNNNN܌NNNNNNNNNNNNNNNNNNNNN!:  '<ͭ'<>V$>O$:Ğà\ÞØ`rÍÖ![w#w#b!"!F#v2[G*##~w*##~<*}q!~ڬ6![^![^#fk"͎͘!G#*####*^#Vû!^*"* BNNNNNNNNNNNNNNNN̲NNNNNNNNNNNNNNNNNNNNNN:|: |Ë  |*" ͩ !6="1 :  1}1:n:>BʋSSͦSSxS 1:  1"" ͦ 1 |͍ >O U!" 1 1!|_!^#fk $8AP`ixH ñññ81Ľ y0îH ñGîG  ñH ñ(Ľ yîH ñîîĽ y0îîH ñG 1: :,; c*| } 8ObPNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNN!{zA"*![N![ N#Fr+sq#p/>G=#w#w3#w#w!JSYMBOL TABLE OVERFLOW G*##~w*##~͎*_###s#r^#V`à 4 Wm ()*+,-/ABCDEHLMDBDIDSDWEIIFINORSPACIADCADDADIANAANDANICMACMCCMPCPIDAADADDCRDCXENDEQUHLTINRINXJMPLDALXIMODMOVMVINOPNOTORAORGORIOUTPOPPSWRALRARRETRLCRRCRSTSBBSBISETSHLSHRSTASTCSUBSUIXORXRAXRICALLENDMLDAXLHLDPCHLPUSHSHLDSPHLSTAXXCHGXTHLENDIFMACROTITLE  PF FP! ( 2/NNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNĽ y0G G t :):,.>C :|: Jü;r :R: ʼʋ!ʼR!ʼʋ>SR{ozg!~4ʧͦ !6 ! **̈́**̈́\iͩ !w#H USE FACTOR !* "z{*"* "I !" :1 R O*UR X* G:xl :  *̩ : l x͖ *#"EH DH 0:~ ! ^4! w͆ Æ *! 6z͖ {͖ 4>R>V>D >P >L >NdNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN4։({̐oNNNNNNNNNNNNNNNNNNNNNN; ; CP/M 2.24 r01 BIOS MASTER SOURCE ; ; -Copyright (c) 1980 ; Digital Research ; Box 579, Pacific Grove ; California, 93950 ; -Copyright (c) 1985 ; Megatel Computer Technologies. ; 150 Turbine Drive ; Weston, Ontario ; M9L 2S2 ; ;* * * * * * * * * * ; ;UPDATES - YOU SHOULD READ THIS SECTION IF YOU ARE UPDATING ; YOUR O/S FROM CP/M 2.21 TO THE NEW CP/M 2.24 ; ;NB - ALL DOCUMENTATION REFERING TO MEMORY MANAGMENT, BANK SWITCHING, GRAPHICS ; TERMINAL EMULATION, AND COMMON BOUNDARY DOtNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNor does it use the same registers for ;the equivalent bios functions. ; ;INTERRUPT SERVICING ; ;The memory management routines are synchronized with the clock to ensure that ;no glitch appears on the screen when switching to a mapped memory config. ;Although the 'out of sync' condition does not effect the system operations. ; ;If user wish to install other interrupt(s) handling routine, make sure the ;TOTAL interrupt service time is less than 1 millisec(vertical retrace time). ;This is due to thekpNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN!ES NOT APPLY TO THE 64K SYSTEM. ; ;June/85- 'sectrans' routine no longer increment sector number by one if no ; translate table is supplied (reg DE is 0 on entry). cY. ; ;Apr/85 - Low write current is no longer an 'installation' option; we assume ; low write current is not required. However, user can change the ; 'low$port', 'low$mask' , and 'lowtrk' variables in the bios if the ; option is needed. cY. ; ;Feb/85 - updated from CP/M version 2.22 r02. cY. ; - include disk r/w, blockNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN! fact that the map type bit in the sam register can only ;be setup during the vertical retrace period. Interrupt servicing longer ;than 1 msec will cause the bank switching to not synchronize with the clock. ; ;It will take a maximum of 16 msec to service a mapped bank select, and a ;maximum of about 32 msec to service every 256 bytes to transfer to/from ;mapped bank to/from a not mapped bank, with the CLOCK INTERRUPT ENABLED. ;The time may tripple if clock interrupt is disabled. ; ;DEFINITION - ISeNNNNNNNNNNNNNNNN!2NNNNNNNNNNNNNNNNNNNNNNing/deblocking, interrupt handling, disk ; error handling, memory management routines, and ; buffered and interrupt driven parallel keyboard to the operating ; system. ; - common boundary for bank switching, memory to memory move, interrupt ; handling, and disk routines is tentatively set to 0e000h. User can ; change this by modify the memory configuration tables in MEMNAGE.ASM. ; - NB. Under previous CP/M 2.22 releases, maskable interrupts ; can be executed anywhere in the TPA bank anpNNNNNNNNNNNNNNNNNtaNNNNNNNNNNNNNNNNNNNNNNNSTALLABLE PARAMETER - eg: (value equ xxxxxx ;| nnn|) ;An installable parameter is a parameter patched by the installation ;prgram according to its parameter number. User must leave 6 character space ;followed by a white space, a ';', a '|', a three digit parameter number, ;and another '|'. The 6 character space will be stuffed by the installation ;program with data from the installation data file(QSYS.DAT). ;Parameter | 099| must be at the end of the bios file. Any code passing | 099| ;will be ovHNNNNNNNNNNNNNNNNNNGPNNNNNNNNNNNNNNNNNNNNN!d anywhere in the BIOS. ; The CP/M 2.23 releases is configured to allow maskable interrupt ; processing in the common memory(address from 0e000h to 0ffffh) only. ; This change is neccessary to accommodate a maskable interrupt ; while servicing the Non Maskable Interrupt in a buffer bank. ; Note that the Z80 NMI is presently used for disk operations. ;* * * * * * * * * * ; ;MEGATEL BIOS DOCUMENTATION, STANDARDS, AND PROGRAMMING NOTES ; ;MEMORY MANAGEMENT ; ;Presently, the Operating SyFNNNNNNNNNNNNNNNNWnNNNNNNNNNNNNNNNNNNNNN!erlayed by the sector translate tables, the allocation/checksum ;vectors storage and a 128 byte directory buffer for CP/M 2.2. ; ;DEFINITION - INSTALLABLE PARAMETER BLOCK(IPB) ;An 'installable parameter block' is a block of data statements starting at ;| nnn| in the bios source. By assigning the block a specific number ;'nnn', the installation program can alter the values of the 'db' ;or 'dw' statements according the semantics implied by 'nnn'. The number ;of statements per block is a constant(caNNNNNNNNNNNNNNNN d_NNNNNNNNNNNNNNNNNNNNNNstem bank(0) and the TPA bank(1) are neccessarily ;the same bank. In any case, the TPA bank has to be in context whenever ;control is passed to the user, ccp, or bdos. Also the bios jump table must be ;accessible from the TPA bank. ; ;MISCELLANEOUS ; ;When accessing routines through the bios jump table, first save all ;needed registers, or trouble may arise. For instance, CP/NET reroutes ;the console I/O jump entries in order to control console functions. It does ;not save/restore registers, n pNNNNNNNNNNNNNNNNN 1 NNNNNNNNNNNNNNNNNNNNNNn not be muddled with). ;SYTAX OF A DATA STATEMENT WITHIN THE IPB ;Each data statement must be PRECEDED BY a white space, a 'db' or 'dw', ;and another white space, followed by a six(6) byte parameter. The parameter ;will be replaces by a six byte value generated by the installation program. ;Only one statement per line will be processed. ;PROGRAMMER RESPONSIBILITY ;It is the programmer's responsibility to make sure Six bytes are provided ;for each parameter, and the syntax and the number of 'db' 7#aNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN2։'yʐnBNNNNNNNNNNNNNNNNNNNNN!and 'dw' statements ;are correct. ; ; ;* * * * * * * * * * ; ;DO NOT CHANGE THE FOLLOWING EQUATES, THEY ARE PRESET ; FALSE EQU 0 TRUE EQU NOT FALSE falsee equ false ;6 char name of false/true value trueee equ true ASSEMCOMT EQU FALSE ;DO NOT ASSEMBLE COMMENT STATEMENTS. - SOME ASSEMBLER ; STATEMENTS ARE INCLUDED TO SERVE AS EXAMPLES AND ; COMMENTS ONLY. THEY SHOULD NEVER BE ASSEMBLED. SAMB EQU 0BH ;SAM SETUP ROUTINE ENTRY POINT ; ;* * * * * * * * * * ; ;system assembly togglGBNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN* * * * * * * * ; ; linkage to memory management routines used by other O/S components ; ;bank/move routne jump table entry points - absolute address ; Ymove equ mvfix ;entry point for move routine Yxmove equ mvfix+3h ;; xmove Ybank equ mvfix+06h ;; bank ;;for coldboot(for both the loader and bios) bankinit equ mvfix+09h ;; bank init ivdmbank equ mvfix+0ch ;; vdm init ;;for interrupt servicing svdmbank equ mvfix+0fh ;; select vdm bank from non mapped stpabank equ mvfix+12h ;; select tpa ban*aNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNes and equates ; clock equ true ;clock interrupt enable or disable pkeyinrp equ true ;parallel keyboard - run interrupt or polled interrupt equ clock or pkeyinrp ;master interrupt flag banked equ false ;if more than 64k memory, run banked bankedbuf equ false ;disk i/o to banked blocking/deblocking buffer profile equ true ;run a system initialization program after ;a coldboot bootdisk equ 0 ;logical drive to boot from - always 0 cpmb equ 0ac00h ;base of cpm ccp - (53k cpm) cpmsize equuoNNNNNNNNNNNNNNNNdNNNNNNNNNNNNNNNNNNNNNNk from non mapped ;;for terminal emulator servicing sinvdm equ mvfix+15h ;; select vdm bank from anywhere soutvdm equ mvfix+18h ;; restore original bank after sinvdm ; ;abosolute address in move/bank routines ; top16k equ mvfix+1bh ;;accessing hidden memory hz equ mvfix+1ch ;;clock pulse( value 50/60 for 50/60 hz) memsize equ mvfix+1dh ;;0 - 128k, 1 - 256k bnkinrp equ mvfix+1eh ;;ei/nop, ret curbnk equ mvfix+20h ;; = @cbnk banktab equ mvfix+21h ;;address of the bank select table used by aNNNNNNNNNNNNNNNNWNNNNNNNNNNNNNNNNNNNNNN 1600h ;size of ccp and bdos ; valpha equ TRUE ; run alpha or graphic terminal emulation if valpha scn$clock equ TRUE ;|011| display clock on screen endif if not valpha scn$clock equ false ;can not display clock if graphics endif ; org cpmb+cpmsize ;base of bios ; nsects equ cpmsize/128 ;size of ccp+bdos in sectors bdos equ cpmb+806h ;start of bdos cdisk equ 4 ;address of CPM 'logged in drive' variable iobyte equ 3 ;address of 'MDS iobyte assignment' variable buff equ 80h NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN ; ;; the bank routine ;* * * * * * * * * * ; ;terminal emulator equates vout equ vidparm ;front/bank end of voutsz equ 0400h ;terminal emulator size(maximum) indvout equ vidparm-voutsz ;system independent portion of vout vidend equ 0 ; ;graphics primitives parameter block ; gpbaddr equ 0ff00h ;parameter block address pointer gpblock equ 0ff02h ;parameter block address ; ;tpa bank tpabank equ 0 ; ;blocking/deblocking buffers ; buffaddr1 equ indvout-400h buffaddr2 equ buffaddr1-40aNNNNNNNNNNNNNNNN1NNNNNNNNNNNNNNNNNNNNNN;default dma buffer address vint equ 38h ;maskable system interrupt address (rst 7) ; hidccp equ false ;save ccp in ccp bank - not for 64k os ; ccpbase equ 0e000h ;address of a copy of ccp in memory ; if not valpha inclgprim equ true ;if the graphics primitive package is not ; purchased, user may set this to false to ; reduce the bios size endif if valpha inclgprim equ false ;do not include primitives entry endif ; low$wrt$currnt equ false ;do not assemble low write current codeJINNNNNNNNNNNNNNNN!NNNNNNNNNNNNNNNNNNNNNN0h ; ;pointer to address of emulator variables ; use6 equ vout+3 use7 equ use6+2 use8 equ use6+4 use9 equ use6+6 ; ;* * * * * * * * * * ; ;clock display ; cl$top equ TRUE ;|012| ;display at top/bottom of screen if cl$top cl$pi60 equ vidend-003780 ;position for [ of screen clock cl$pi50 equ vidend-004804 endif if not cl$top cl$pi60 equ vidend-000015 cl$pi50 equ vidend-000015 endif hz60 equ 60 ;clock frequency counter hz50 equ 50 ; ;* * * * * * * * * * ; ; I/O ports excludincpNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNN ; ;include sector blocking/deblocking tables and storage for drive DBLK0 equ true ;drive 0 DBLK1 equ true ;drive 1 DBLK2 equ true ;drive 2 DBLK3 equ true ;drive 3 ; ;* * * * * * * * * * ; ; absolute(fixed) origin of variables/routines in common memory ; these are the addresses we want the code to run at when system is up ; vidparm equ 0ea80h ;terminal emulator variables, and stack mvfix equ vidparm+100h ;start location of memory managment module ; ;for a total of 80h bytes ;* * eaNNNNNNNNNNNNNNNN GNNNNNNNNNNNNNNNNNNNNNNg FD1793 disk controller equates ; pprport equ 05fh ;parallel printer port viaport equ 60h ;VIA-6522 base address-16 ports piaport equ 74h ;PIA-6821 base address-4 addresses aciaport equ 78h ;ACIA-6850 base address- 2 addresses ; nserdata equ aciaport+1 ;data port for hardware serial channel nserstat equ aciaport ;status port for hardware serial channel txrdy equ 1 ;bit one is the transmitter data register empty-1=>ready rxrdy equ 0 ;bit zero is the receiver data register full-1=>data rNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN5ى+}ΐpONNNNNNNNNNNNNNNNNNNNNNeady ; termiobyte equ 03H ;|002| ;terminal/keyboard configuration listiobyte equ 080H ;|003| ;list device configuration iobyteinit equ termiobyte or listiobyte ;initial value for iobyte ; ;* * * * * * * * * * ; ; miscellaneous equates ; NUMDISKS EQU 000004 ;number of logical drives configured nbronull equ 00000 ;|004| ;nbr of nulls sent to printer after ; null equ 0 ;null character EOT EQU 4 ;end of text LF EQU 0AH ;LINE FEED CR EQU 0DH ;CARRIAGE RETURN BLANK EQU 20H ;blaNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN bios jump table; see CP/M manual for more info ; ; start: jmp boot wboote: jmp wboot conste: jmp const conine: jmp conin conoute: jmp conout liste: jmp list punche: jmp punch readere: jmp reader homee: jmp home seldske: jmp seldsk settrke: jmp settrk setsece: jmp setsec setdmae: jmp setdma reade: jmp read writee: jmp write listste: jmp listst sectrane jmp sectran ; ;Megatel added bios functions ; setdmabnk jmp setdmab ;set dma bank ; userfunc jmp userf ;returns addresses o[NNNNNNNNNNNNNNNNNN)NNNNNNNNNNNNNNNNNNNNNNnk chbell equ 07h ;bell bell equ chbell ; ;* * * * * * * * * * ; ; I/O status byte masks and values ; ;IOBYTE implementation ; -CON: ; tty: full serial RS232C channel for input and output ; crt: memory mapped intrinsic screen, parallel input ; keyboard ; bat: input from full serial channel, output to memory ; mapped screen ; uc1: debug mode, duplicate tty: and crt: ; -RDR: ; tty: full serial RS232C channel ; ptr: unimplemented, comes from tty:-can be patched, see useread ; ur1: unimpl~KNNNNNNNNNNNNNNNNNYNNNNNNNNNNNNNNNNNNNNNNf system variables to user ; ;note that all system variables are in the ; ;common memory (above 0e000h) ; diskreset jmp dreset ;forces current disk driver parameters to be ;reset - used by DFCU and QCERT ; ;* * * * * * * * * * ; ;system identification ; use0: hertz db 60 ;system clock frequency 60 if 60hz 50 if 50hz version db 22 ;cpm version number verint db 41 ;Megatel release number ; use5: vidalpha db valpha and 0ffh ;alpha or graphic terminal flag db 0 ;colour terminal noGwNNNNNNNNNNNNNNNNNhNNNNNNNNNNNNNNNNNNNNNNemented, comes from tty: ; ur2: unimplemented, comes from tty: ; -PUN: ; tty: full serial RS232C channel ; ptp: software serial RS232C channel output ; up1: unimplemented, goes to tty:-can be patched, see usepunch ; up2: unimplemented, goes to tty: ; -LST:/PRN: - note: tty: and ul1: devices have settable ; null outputs for cr/lf cf config. ; tty: full serial RS232C channel-nulls implemented ; crt: to con: output ; lpt: centronics parallel port ; ul1: soft serial RS232C channel ; cmsk equ 111~}pNNNNNNNNNNNNNNNNN;NNNNNNNNNNNNNNNNNNNNNNt implemented ; ;* * * * * * * * * * ; ;cold boot section - initialization, load ccp and bdos, and jump to ccp ; ;boot variables ; ccpsect: db 0 ;starting sector which CCP and BDOS code is on ccptrack: db 0 ;starting system track which CCP and BDOS is on sysdisk: ;which drive to read ccp and bdos from db 0 secptrack db 0 ;stores sectors per track of drive A ; ;the cold boot is responsible for general system initializations, and ;the initial loading of CCP and BDOS ; Information passed NNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNN!11100b ;mask for local console I/O rmsk equ 11110011b ;mask for reader input pmsk equ 11001111b ;mask for punch output lmsk equ 00111111b ;mask for list output ;----- ctty equ 00000000b ;local console = tty ccrt equ 00000001b ;local console = crt cbat equ 00000010b ;batch mode-see page 1 cuse equ 00000011b ;user defined-duplicated to ; ; both local and true Rs232C ;----- rtty equ 00000000b ;reader = tty rptr equ 00000100b ;reader = ptr ruse1 equ 00001000b ;user defined reader 1 r5NNNNNNNNNNNNNNNNN4NNNNNNNNNNNNNNNNNNNNN!from loader ; reg D - the sector on which to start reading ccp ; reg E - the track on which to start reading ccp ; boot: ; ;cold boot section - tpa bank (bank 1) switched in on entry - ; lxi sp,sysstack ;store ccp sector and track location from loader mov a,d sta ccpsect mov a,e sta ccptrack call gsysdi ;do not allow interrupt while in cold boot ; ;initialize 128/256k bank config - init bank table ; mvi a,0 ;init as OS (vs loader) call bankinit ; if clock in piaport+1h gKNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNN!use2 equ 00001100b ;user defined reader 2 ;----- ptty equ 00000000b ;punch = tty pptp equ 00010000b ;punch = ptp puse1 equ 00100000b ;user defined punch 1 puse2 equ 00110000b ;user defined punch 2 ;----- ltty equ 00000000b ;list = tty (hard serial channel) lcrt equ 01000000b ;list = crt llpt equ 10000000b ;list = lpt (Centronics parallel) luse equ 11000000b ;list = soft serial channel ; ; ;* * * * * * * * * * ; ; jump vector for individual bios routines ; ;this is the standard CP/MBNNNNNNNNNNNNNNNN VNNNNNNNNNNNNNNNNNNNNN!;set up cra(ddra) of pia to address ori 4 ; Peripheral Output/Interface Register out piaport+1h endif in piaport+1 ;make sure vs interrupt is triggered on a ori 2 ;low-to-high for the system out piaport+1 lxi h,0ff95h ;set page mode-just in case, should never change call samb ;call routine to set SAM bits mvi a,iobyteinit sta iobyte ; lda hz sta hertz ;clock sta ticks sta timer ; cpi hz60 jz ishz60 ;skip setup if 60 hz-default parms are for 60 ; lhld cl$p50 6.NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN3Չ&wȐj 9NNNNNNNNNNNNNNNNNNNNNN ;change on screen clock position to 50hz shld clk$pos lxi h,110 ;soft stepping rates counter shld half$ms ; ishz60: ; ;init BIOS/BDOS jump entry in page 0 call bdosinit ;do all interrupt restart vector initialization for bank 1 here call srstvector ;init rst 5,6,7 and copy rst vect to all banks ;as well as initialize the interrupt handler ;put all physical interrupt enabling here if clock in piaport+1h ;enable real time clock interrupt ori 03h out piaport+1h endif if pNNNNNNNNNNNNNNNNNN lKNNNNNNNNNNNNNNNNNNNNNNrrors? jnz wboot ;retry the entire boot if an error occurs ; ; no error, move to next sector pop h ;recall dma address lxi d,128 ;dma=dma+128 dad d ;new dma address is in h,l pop d ;recall sector address pop b ;recall number of sectors remaining, and current trk dcr b ;sectors=sectors-1 jz gocpm ;transfer to cp/m if all have been loaded ; ; more sectors remain to load, check for track change inr d lda secptrack ;sector=maximum, if so, change tracks cmp d jnc load1 ;no carry gener&NNNNNNNNNNNNNNNN _zNNNNNNNNNNNNNNNNNNNNN!keyinrp in piaport+1 ;enable parallel keyboard interrupt ori 08h out piaport+1 endif ;--- ;store a fresh copy of CCP+BDOS into the ccp bank ; gostore: ; if hidccp mvi c,1 ;TPA bank mvi b,4 ;store ccp bank call Yxmove lxi b,cpmsize lxi d,cpmb ;source lxi h,ccpbase ;destination call Ymove endif call mout ;print message signon: ;signon message db 20h,cr,lf db 'MEGATEL QUARK 51K ' db 'CP/M V2.24 R02 ' db 'preliminary' db cr,lf,eot ; if profile ;run an initiaDBNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNated if sector < maximum sect/track ; ; end of current track, go to next track mvi d,1 ;begin with first sector of next track inr c ;track=track+1 ; ; save register state, and change tracks push b push d push h call settrk ;track address set from register c pop h pop d pop b jmp load1 ;for another sector endif ; gocpm: call bdosinit lda cdisk ;last logged disk number mov c,a ;send to ccp to log it in jmp cpmb ; bdosinit: lxi b,buff call setdmae ;set transient progj6NNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNlization program after loading lxi h,command ; ccp and before the first system prompt lxi d,cpmb+7 lxi b,9 ;nine character command ;ldir db 0edh,0b0h endif ; mvi a,tpabank ;set dma bank call setdmabnk xra a sta unacnt sta cdisk ;enable interrupt or leave interrupt disabled depending on sys config call gsysei mvi c,0 ;disk to log jmp cpmb ; ; wboot: lxi sp,sysstack call dskinit ;init disk - deactivate buffers if hidccp ;reload ccp/bdos from disk mvi c,4 ;ccp bank mNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNram dma buffer to 080h ; mvi a,cr ;initialize the acknowledge signal from the parallel printer port call listinit ; by sending unrequired cr, this will also flush the printer line buffer ; ; reset bios and bdos entry points ; mvi a,0c3h sta 0 lxi h,wboote shld 1 ;jmp wboot at location 00 sta 5 lxi h,bdos shld 6 ;jmp bdos at location 5 ret dskinit: lda nbrodsk ;Deactivate/unmark/deallocate all buffers for cntdeact: ; all drives. Any buffer not yet flushed dcr a ; will NNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNN!vi b,1 ;tpa bank call Yxmove lxi b,cpmsize lxi d,ccpbase ;source lxi h,cpmb ;destination call Ymove endif if not hidccp ;reload ccp from system tracks lda sysdisk mov c,a call getdpb mov a,m ;sectors per track sta secptrack ; lda sysdisk ;load system form boot disk - patchable mov c,a call seldsk ; lda ccptrack mov c,a call settrk ; mvi b,nsects ;b counts # of sectors to load lda ccptrack mov c,a ;c has the current track number lda ccpsect mov d,a ;d ãNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNto be deallocated at warmboot. Files push psw ; must be closed if written to before wboot. call deactdrive ;Deactivate if removable media pop psw ora a jnz cntdeact ; sta unacnt ;reset unallocated write count mvi a,tpabank ;init transient program dma bank to tpa bank call setdmabnk ret ; ; ;* * * * * * * * * * ; const: ;console status to reg-a lda iobyte ani (not cmsk) and 0ffh jnz cs0 ;--- ; console = tty ;full serial channel serstat: ;entry for other routines IjNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNN!has the next sector to read lxi h,cpmb ;base of cp/m (initial load point) load1: ;load one more sector push b ;save sector count, current track push d ;save next sector to read push h ;save dma address mov c,d ;get sector address to register c call setsec ;set sector address from register c pop b ;recall dma address to b,c push b ;replace on stack for later recall call setdma ;set dma address from b,c ; ; drive set to 0, track set, sector set, dma address set call read ora a ;any egBNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNN nserstat ani 1 ;test receiver ready bit of status to see if ; ; character ready to input rz ori 0ffh ret ;--- ; console = crt ;input is from parallel keyboard??? cs0: cpi ccrt jnz cs1 ;--- ; input from parallel keyboard port status ; parstatin: if pkeyinrp ;interrupt driven lxi h,c0ibp ;keyboard buffer pointer mov a,m inx h inx h sub m rz ori 0ffh ;a character is ready to be read ret endif if clock and (not pkeyinrp) ;polled on the clock lda flinchar 4NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN4׉(zːn NNNNNNNNNNNNNNNNNNNNNN ora a rz ori 0ffh ret endif if (not clock) and (not pkeyinrp) ;polled in piaport+1 ani 40h rz ori 0ffh ret endif ; ;--- ; console = bat ;input from serial channel?? cs1: cpi cbat jz serstat ;--- ; console = user ;input from parallel or serial channel call serstat rnz jmp parstatin ;--- conin: lda iobyte ani (not cmsk) and 0ffh jnz conin0 ;--- ; console = tty ;full serial channel serin: ;entry for other routines in nserstat ;wait for data on serial in NNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNN ;set up initial start bit if interrupt ;only play with the interrupt structure if interrupts di ; were turned on endif call nobit call send2bit call send2bit call send2bit mov a,c ani 1 ;only last data bit ori 2 ;stop bit mov c,a call send2bit if interrupt call extinrp endif pop b ;get original character back mov a,c ; for klugey routines ret send2bit: ;routine used by soft serial output xra a ;rrcr c db 0cbh,09h ;jrnc nobit db 30h,0ffh and nobit-$-1 NNNNNNNNNNNNNNNNNN ĦNNNNNNNNNNNNNNNNNNNNNNput ani 1 jz serin in nserdata ani 7fh ;strip parity ret ;--- ; console = crt ;input is from parallel keyboard??? conin0: cpi ccrt jnz conin1 ; parin: ;parallel keyboard ; call parstatin ;wait for an input jz parin ; ;interrupt driven if pkeyinrp lxi h,c0ibp call bufget ani 7fh ret endif ; ;polled on clock if clock and (not pkeyinrp) di ;critical section xra a sta flinchar lda inchar ani 7fh call extinrp ;extinrp does not change any registers ret m(NNNNNNNNNNNNNNNN ]1NNNNNNNNNNNNNNNNNNNNNNori 0f0h ;top four bits out first nobit: ;also used as entry to routine ;rrcr c db 0cbh,09h ;jrnc nobit1 db 30h,0ffh and nobit1-$-1 ori 0fh nobit1: push psw sserwait: ;wait loop for bits to be shifted out in viaport+0dh ;check status ani 4 ; to see if all 8 bits shifted (two logical) ;jrz sserwait db 28h,0ffh and (sserwait-$-1) pop psw out viaport+0ah ;output the two bits to shift register ret ; ; ret ;--- ; punch = user punch1: push h lhld usepunch xthl ret TmaNNNNNNNNNNNNNNNN nNNNNNNNNNNNNNNNNNNNNN!endif ; ;polled if (not clock) and (not pkeyinrp) in piaport ani 7fh ret endif ; ;--- ; console = bat ;input from serial channel?? conin1: cpi cbat jz serin ;--- ; console = user ;input from parallel or serial channel conin2: call serstat jnz serin call parstatin jnz parin ;parallel input ready jmp conin2 ; ;--- conout: lda iobyte ani (not cmsk) and 0ffh jnz conout0 ;--- ; console = tty ;full serial channel serout: ;entry for other routines in nserstat SNNNNNNNNNNNNNNNN ;SNNNNNNNNNNNNNNNNNNNNNN; ;--- list: lda iobyte ani (not lmsk) and 0ffh jnz list0 ;--- ; list = tty ;full serial channel lda nullcount ;check if null count required ora a jz serout call serout ;character to be printed is in the a register cpi lf jz lttynull ;output nulls cpi cr rnz ; lttynull: push b ;save character output lda nullcount mov b,a lttynul0: mvi c,null ;output null call serout dcr b jnz lttynul0 ; pop b mov a,c ;for klugy routines which expect c=>a ret ;--- ; xNNNNNNNNNNNNNNNN bNNNNNNNNNNNNNNNNNNNNN! ani 2 ;check for UART ready jz serout mov a,c out nserdata ret ;--- ; console = crt ;output is from parallel keyboard??? conout0: cpi ccrt jz vout ;--- ; console = bat ;output from serial channel?? cpi cbat jz vout ;--- ; console = user ;output from parallel or serial channel call serout ;if delay loop is required for slow external terminals place here ; may want to add fixed delay or delay for only those characters ; which are slow. ; jmp vout ; ;--- reader: lda iOBNNNNNNNNNNNNNNNN \NNNNNNNNNNNNNNNNNNNNNNlist = crt ;output to crt screen list0: cpi lcrt jz vout ;--- ; list = lpt: ;list to parallel port (Centronics compatible) ; ; must be acknowledge handshaking, or else ; ; modified to accept printer busy handshaking cpi llpt jnz list1 ; listlpt0: in viaport+0dh ;check CA1 for active edge ani 2 jz listlpt0 mvi a,2 ;clear CA1 interrupt flag (note - interrupt disabled for this routine) out viaport+0dh mov a,c ;send character listinit: ;entry for initializing printer accNNNNNNNNNNNNNNNN +mNNNNNNNNNNNNNNNNNNNNN!obyte ani (not rmsk) and 0ffh jnz reader0 ;--- ; reader = tty ;full serial channel jmp serin ;--- ; reader = ptr, ur1, or ur2 ;call dummy address reader0: push h lhld useread xthl ret ;--- punch: lda iobyte ani (not pmsk) and 0ffh jnz punch0 ;--- ; punch = tty ;full serial channel jmp serout ;----- ; punch = ptp ;soft serial channel punch0: cpi pptp jnz punch1 softserout: ;entry for the list output push b ;save original character for klugey routines xra aŎBNNNNNNNNNNNNNNNN ~>NNNNNNNNNNNNNNNNNNNNNNknowledge out pprport in viaport+0ch ;pulse the printer data strobe (data ready) xri 02h out viaport+0ch xri 02h out viaport+0ch ret ; ;--- ; list = ul1: ;output to soft serial channel list1: in viaport ani 40h ;check if printer busy jnz list1 ;*****NOTE***** change the sense of this depending on your printer ; lda nullcount ;check if null count required ora a jz softserout call softserout ;character to be printed is in the a register cpi lf jz lul1null ;output nu?NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN2։'z̐q pNNNNNNNNNNNNNNNNNNNNN!lls cpi cr rnz lul1null: push b ;save character output lda nullcount mov b,a lttynull0: mvi c,null ;output null call softserout dcr b jnz lttynull0 pop b mov a,c ;for klugy routines which expect c=>a ret ;--- listst: lda iobyte ani (not lmsk) and 0ffh jz serstat ;list = tty ;--- ; listst = crt ;output to crt screen listst0: cpi lcrt jnz listst0a ;c.Y. ori 0ffh ;always ready ret ;--- ; listst = lpt: ;list to parallel port (Centronics compatible) ; ;(CpNNNNNNNNNNNNNNNNN #NNNNNNNNNNNNNNNNNNNNNNddress in reg HL ret ; ;set next r/w to physical sector ; setsec: ;set sector number given by BC register ;sbcd sector db 0edh,43h dw seksec ret ; ;logical to physical sector translation - assume 255 sectors or less per track ; sectran: ;translate sector bc using table at de ;check for de=0 just return in origin 0 sector # ; in bc, as origin 1 sector # in hl mov a,e ora d jnz sectr1 ;jump if not zero mov h,b mov l,c ret sectr1: xchg ;translate table address tpNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNN must be acknowledge handshaking, or else ; ; modified to accept printer busy handshaking listst0a: cpi llpt jnz listst1 in viaport+0dh ani 2 rz ori 0ffh ;ready return ret ;--- ; listst = ul1: ;output to soft serial channel listst1: ; ;check that this is true ori 0ffh ;always ready-software serial channel waits ret ; ; ;* * * * * * * * * * ; ; FLOPPY DISK PRIMITIVE OPERATIONS ; ENTRY POINTS: ; HOME - RESTORE THE DISK ; SELDSK - SELECTS A DRIVE ; SETTRK - SETS TRqNNNNNNNNNNNNNNNN +NNNNNNNNNNNNNNNNNNNNNNo HL dad b ;translate(sector) address - 1 byte per sector mov l,m ;return sector number in L mvi h,0 ;want to pick up second byte if double precsion ret ; ;set dma ; setdma: ;set dma address given by regs b,c ;sbcd dmaadr db 0edh,43h dw dmaadr ret ; ;always set default transient program dma bank to the TPA bank. ;for the 128 byte-sectors, data is directly transfered to/from this bank, ;and for the multi 128 byte-sectors, data is transfered to/from the ;blocking/deblocking buffppNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNACK # ; SETSEC - SETS SECTOR # ; SETDMA - SETS DISK BUFFER ADDRESS ; READ - READ A SECTOR ; WRITE - WRITE A SECTOR ; ;restore routine ; home: ;move to home position lxi h,0 ;make sure stack is in common dad sp shld usrstack lxi sp,dskstck lda sekdsk call movdrvblk jc homecnt ;128 byte-sectors ; mvi a,0 ;set deactwr to false sta deactwrt ;flag to prevent unmarking of write pending ; buffers lda sekdsk call deactdrv ;deallocate read buffers for current drive and lNNNNNNNNNNNNNNNN MNNNNNNNNNNNNNNNNNNNNNNer bank(s) to this bank. ; ; calling routine passes bank number in register A setdmab: sta dmabank ret ; ; ;reset some disk driver parameters so that DFCU and QCERT do not confuse the ;os; only used by the DFCU and QCERT presently. ; dreset: mvi a,0ffh sta lstdrv ;just in case sta drv ;force reset of blocking/deblocking variables sta olddsk ;force reselect of drive sta curdsk ;force reset of mpdt variables ret ; ;* * * * * * * * * * ; ; block/deblock equates and variables۶NNNNNNNNNNNNNNNNNN ~NNNNNNNNNNNNNNNNNNNNNN ; force physical read on next operation homecnt: lhld usrstack sphl mvi a,0ffh ;set deactwrt to true for unmark write pending sta deactwrt lxi b,0 ;set track number to 0 ; ;set track ; settrk: ;set track address given by c ;sbcd sektrk ;store track number for future use db 0edh,43h dw sektrk ret ; ;select disk ; seldsk: ;select disk given by register c lxi h,0000h ;return 0000 in HL if error lda nbrodsk dcr a cmp c rc ;drive not implemented mov a,e ;VIaNNNNNNNNNNNNNNNN nNNNNNNNNNNNNNNNNNNNNNN ; ; ;types of write operations ; wrall equ 0 ;write to allocated, defered write wrdir equ 1 ;write to directory, non defered write wrual equ 2 ;write to unallocated ; ;data/directory buffer control block variables relative to bcb address(s) ; lastdsk equ 0 ;last disk to access this bcb wrtpend equ 1 ;write pending flag nbuf equ 2 ;number of buffers allocated lrubuf equ 3 ;pointer to lru buffer header bufheadaddr equ 5 ;pointer to buffer headers bufcap equ 7 ;buffer capacity lrumaskNNNNNNNNNNNNNNNN ]NNNNNNNNNNNNNNNNNNNNNNwas drive logged in ani 1 jnz waslogged ;drive was not logged in, clear blocking/deblocking buffer lxi h,0 ;make sure stack is in common dad sp shld usrstack lxi sp,dskstck push b mov a,c call deactdrive ;buffers for non removable media is not cleared pop b lhld usrstack sphl waslogged: mov a,c sta sekdsk ;store unit for later use getdph: mov l,c ;HL=disk number mvi h,0 dad h ;*2 lxi d,xdtbl dad d mov a,m inx h mov h,m mov l,a ;return disk header table aNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNN equ 9 ;set one bit for each buffer available, start ; with bit 0 for buffer 0 to bit 7 for buf 7 ; ;buffer header variables relative to buffer header address(s) ; do not change the relative positions of these ; hard coded in many places ; bufheadsz equ 11 ;size of each buffer header ; hstwrt equ 0 ;if buffer contains defered writes hstdsk equ 1 ;disk number hsttrk equ 2 ;track hstsec equ 4 ;sector hstbuf equ 6 ;actual buffer address hstbnk equ 8 ;which bank is the buffer in bufڂNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN5؉){ΐ q ]NNNNNNNNNNNNNNNNNNNNNNusage equ 9 ;buffer usage, when contains 0, buffer is lu bufmsk equ 10 ;buffer mask = 0ffh xor 2**(buffer number) ; where buffer number is 0 to 7 ; ;drive block equates ; drvblksz equ 9 ;drive block size ; ;flush write buffer for a drive, and do not deallocate, unless a drive ;is not logged in, then do not flush and deactivate all buffer for that drive. ;drive number passed in reg A ;NB : non removabel media is flushed when 1) a non defered(directory) write ;occurs, or 2) when a buffer3NNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNN ora a rz ;shared directory and data buffer lhld datbcb shld bcbaddr call deactbcb ;deactivate data buffer ora a ret ;copy drive block into working storage. drive number passed in register A ;upon return, carry is set if no blocking/deblocking. ;Or carry is reset if drive block is copied, 'drv' is updated to ;present drive, and drive number is returned in reg A movdrvblk: mov c,a lda nbrodsk dcr a sub c rc ;drive not implemented in the bios ; lda drv sub c ora a rzSNNNNNNNNNNNNNNNNNN ?NNNNNNNNNNNNNNNNNNNNNN contains a write defered sector is to about to be ;used by another r/w operation. removable media is flushed for the above ;reasons, plus 3) when another disk is selected ; flush: call movdrvblk rc ;no blocking/deblocking for this drive flushdrv: lhld dirbcb ;flush directory buffer shld bcbaddr ; note that directory buffer may contain call getlastdsk ; defered data writes lda drv cmp e cz flushwrt ;flush directory write pending for 'drv' only lda sharebuf ;shared directory and|NNNNNNNNNNNNNNNN zNNNNNNNNNNNNNNNNNNNNNN ;already copied, carry reset mov a,c call getdrvblk rc ;no drive block for this drive ; mov a,c lxi h,cdrvblk xchg lxi b,drvblksz ;ldir db 0edh,0b0h ora a ;reset carry, store drive number in 'drv' sta drv ret ; ;return address of dpb in reg HL given drive number in register C ;also returns address of xlt in reg DE getdpb: call getdph ;get dph mov e,m inx h mov d,m lxi b,10-1 dad b mov a,m inx h mov h,m mov l,a ret ; ;return address of dpb given driv%NNNNNNNNNNNNNNNN INNNNNNNNNNNNNNNNNNNNNN data buffer?? inr a rz lhld datbcb ;flush data buffer shld bcbaddr call getlastdsk lda drv cmp e cz flushwrt ;flush data write pending for 'drv' only ret ; ;flush all write pending buffers given bcb in 'bcbaddr' ;do not deallocate. ; flushwrt: call getwrtpend inr e rnz ;no write pending in this buffer group push h ;save address xra a ;clear write pending flag sta wrtflag call getnbuf mov c,e call getbufhead xchg lda drv mov b,a flushloop: push b push<NNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNe number in register C ;put physical drive number in variable 'xrdrv' xrdrvdpb: call getdph ;get dph dcx h ;two bytes below dph dcx h mov a,m sta xrdrv lxi d,10+2 dad d mov a,m inx h mov h,m mov l,a ret ; ;stores cpmspt, secmsk, secshf given drive number in register C getspt: call getdpb ;get dpb ldax d sta firstsec ;first sector number is either 0 or 1 mov a,m sta cpmspt lxi d,15 dad d mov a,m sta secshf inx h mov a,m sta secmsk ret ; ;get drive btNNNNNNNNNNNNNNNNNN /NNNNNNNNNNNNNNNNNNNNNN h mov a,m inr a jnz nothstwrt ;not write pending inx h mov a,m cmp b jnz nothstdsk ;not for this drive ;try flush call set$wrt$hst ;pass host parm pointer in register HL pop h mvi m,0 ;clear write pending flag push h nothstwrt: pop h pop b dcr c jz flushfini lxi d,bufheadsz dad d jmp flushloop nothstdsk: mvi a,0ffh ;flag any write still pending sta wrtflag jmp nothstwrt flushfini: pop h ;store write pending flag in bcb lda wrtflag mov m,a ret ; wrtwNNNNNNNNNNNNNNNNNN ?NNNNNNNNNNNNNNNNNNNNNNlock address, given drive number in reg A ;returns address in register DE, and carry set if address value is 0ffffh ;meaning no blocking/deblocking tables. carry is also set if blocking/ ;deblocking is not required. getdrvblk: mov e,a mvi d,0 lxi h,drvbdreq ;blocking deblocking required?? dad d mov a,m cma rlc rc lxi h,drvblktbl ;drive block table address dad d dad d mov e,m inx h mov d,m lxi h,1 dad d ret ;deactivate a buffer group, with bcb address in 'bcbaddr' (qNNNNNNNNNNNNNNNN  NNNNNNNNNNNNNNNNNNNNNNflag db 0 ; ;deactivate buffers allocated to the drive specified in register A ; check non removable media flag ; deactdrive: call movdrvblk ;copy drive block to working storage rc ;no blocking/deblocking for this drive lda nonrmv ;check non removable media flag inr a ora a ;reset carry rz ;buffer of non removable media need not be deactivated ; deactdrv: ;deactivate buffer for drive lhld dirbcb shld bcbaddr call deactbcb ;deactivate directory buffer lda sharebuf inr a yNNNNNNNNNNNNNNNN YNNNNNNNNNNNNNNNNNNNNNN deactbcb: call getlastdsk lda drv cmp e jnz notlastdsk ;this drive was the last to access this buffer group lda deactwrt ora a jz donotunwrt call getwrtpend mvi m,0 ;reset host write pending master switch notlastdsk: donotunwrt: call getnbuf ;how many buffers mov c,e call getbufhead xchg inx h deactloop: lda drv cmp m jnz notsamedrv dcx h mov a,m inx h ora a jz notpendbuf ;not a write pending buffer lda deactwrt ora a jz notunwrt ;write pending buffer PNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN2Չ'yːo NNNNNNNNNNNNNNNNNNNNNN not unmarked notpendbuf: dcx h mvi m,0 ;unmark write pending inx h mvi m,0ffh ;deactivate notsamedrv: notunwrt: dcr c rz lxi d,bufheadsz dad d jmp deactloop ; ; ;these routines returns bcb parameters actual address in register HL ; and parameters value in register DE. they do not touch registers A and BC ; getlastdsk: lxi d,lastdsk jmp getcommon getwrtpend: lxi d,wrtpend jmp getcommon getnbuf: lxi d,nbuf jmp getcommon getlrubuf: lxi d,lrubuf jmp getcommon gNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNers lda sekdsk ;disk to seek sta unadsk ;unadsk = sekdsk mov c,a call getdph mov a,m inx h mov h,m mov l,a ;xlate table lda cpmspt mov c,a mvi b,0 lda seksec ;cpir db 0edh,0b1h jnz alloc ;condition should not occure, unless user dcx h ; is using a different xlate table inr c shld unasec ;pointer to 'seksec' in the xlate table mov a,c sta unaseccnt ;how many more unallocated sectors on this ; track, including 'seksec' lda blksiz ;number of unalloc recs BNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNetbufhead: lxi d,bufheadaddr jmp getcommon getbufsiz: lxi d,bufcap jmp getcommon getlrumask: lxi d,lrumask getcommon: lhld bcbaddr dad d mov e,m inx h mov d,m dcx h ;starting address of parameter ret ; ;flush buffer of the last disk to do a r/w. do not deallocate. ;flushlast is done for removable medias whenever a different disk is selected ; flushlast: lda sekdsk mov c,a lda lstdrv cmp c rz ;drive changed call movdrvblk mvi a,0 sta unacnt ;set unallocated uBNNNNNNNNNNNNNNNN  NNNNNNNNNNNNNNNNNNNNNN sta unacnt lhld sektrk shld unatrk chkuna: ;check for write to unallocated sector lda unacnt ;any unalloc remain? ora a jz alloc ;skip if not ; ;more unallocated records remain dcr a ;unacnt = unacnt-1 sta unacnt lda sekdsk ;same disk? lxi h,unadsk cmp m ;sekdsk = unadsk? jnz alloc ;skip if not ; ;disks are the same lhld unatrk call sektrkcmp ;sektrk = unatrk? jnz alloc ;skip if not ; ;tracks are the same lhld unasec lda seksec cmp m jnz alloc ;skip if nQpNNNNNNNNNNNNNNNNN ?-NNNNNNNNNNNNNNNNNNNNNNwrite count to 0 rc lda nonrmv inr a rz ;do not have 'changed media' problem call flushdrv ;flush last drive right away before going on to ; a current r/w operation ret ; ;common exit for disk read/write routines ; dskexit: lda sekdsk ;this is now the last logical disk read/written sta lstdrv lhld usrstack sphl lda erflag ora a ret ; ; ;bios read entry point ; read: ;setup read deblocking pararmeters mvi a,1 sta readop ;read operation sta rsflag ;must reaVaNNNNNNNNNNNNNNNN j~NNNNNNNNNNNNNNNNNNNNNNot ; ;match, move to next sector for future ref inx h lda unaseccnt dcr a jnz noovf ; ;overflow to next track lhld unatrk inx h shld unatrk lda unadsk mov c,a call getdph mov a,m inx h mov h,m mov l,a lda cpmspt ; noovf: shld unasec sta unaseccnt ;match found, mark as unnecessary read xra a ;0 to accumulator sta rsflag ;rsflag = 0 jmp rwoper ;to perform the write ; alloc: ;not an unallocated record, requires pre-read xra a ;0 to accum sta unacnt ;unToPNNNNNNNNNNNNNNNNN YONNNNNNNNNNNNNNNNNNNNNNd data mvi a,wrual sta wrtype ;treat as unalloc xra a sta unacnt ; lxi h,0 dad sp shld usrstack lxi sp,dskstck lxi h,dskexit ;set up disk read/write routine exit push h ; call flushlast ;flush last disks buffer lda sekdsk call movdrvblk jc readhost ;no blocking/deblocking lda sekdsk mov c,a call getspt ;get cpmspt,secmsk,secshf,start sector number jmp rwoper ;to perform the read ; ; ;bios write entry point ; write: ;setup write deblocking parameters xra a sbpNNNNNNNNNNNNNNNNN IqNNNNNNNNNNNNNNNNNNNNNNacnt = 0 mvi a,1 ;1 to accum sta rsflag ;rsflag = 1 ; ; Common code for READ and WRITE blocking/deblock ; rwoper: xra a sta erflag ;no errors (yet) ; lda firstsec ;first sector number is either 1 or 0 mov b,a lda seksec sub b ;normalized sector number to base 0 mov e,a lda secshf ora a mov c,a mov a,e jz noshf ;no translation : one to one ; keepshift: ;translate seksec to host sector ora a ;reset carry rar dcr c jnz keepshift noshf: add b ;increment seDaNNNNNNNNNNNNNNNN z@NNNNNNNNNNNNNNNNNNNNNNta readop ;not a read operation mov a,c ;write type in c sta wrtype ; lxi h,0 dad sp shld usrstack lxi sp,dskstck lxi h,dskexit ;set up disk read/write routine exit push h ; call flushlast lda sekdsk call movdrvblk jc writehost ;no blocking/deblocking lda sekdsk mov c,a call getspt ;get cpmspt,secmsk,secshf,start sector number ; ;is this an unallocated write lda wrtype cpi wrual ;write unallocated? jnz chkuna ;check for unalloc ;write to unallocated, set paramet2NNNNNNNNNNNNNNNN /NNNNNNNNNNNNNNNNNNNNN!ctor numbers by one if first ; sector starts at 1 instead of 0. sta sekhst ;host sector to seek call choosebcb ;use dir or data bcb ?? shld savebcb ;this is the bcb to use shld bcbaddr ; ;check all buffer for disk/track/sector equals ;straight line code to make as fast as possible call getnbuf mov b,e call getbufhead xchg cntmatch: shld bufptr inx h lxi d,sekdsk ;assume sekdsk, sektrk, seksec are contiquous ldax d cmp m ;compare disk jnz notinbuff inx h inx d"BNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN3Չ'yʐmh5NNNNNNNNNNNNNNNNNNNNNN ldax d cmp m ;compare low byte of track jnz notinbuff inx h inx d ldax d cmp m ;compare high byte of track jnz notinbuff inx h lda sekhst cmp m ;compare low byte of host sector jz match notinbuff: ;continue checking thru the remaining buffer lhld bufptr dcr b jz nomatch ;not in buffer lxi d,bufheadsz dad d jmp cntmatch ; nomatch: ; ;drive/track/sector not in buffer, get least recently used buffer address call getlrubuf xchg shld bufptr mov a,m ;bufferBNNNNNNNNNNNNNNNN=fNNNNNNNNNNNNNNNNNNNNNNll Yxmove ;setup bank to bank move pop d pop h lxi b,128 ;move 128 bytes call Ymove endif if not bankedbuf lxi b,128 ;ldir db 0edh,0b0h endif ; ;data has been moved to/from host buffer call getlastdsk ;set last drive to access this bcb lda sekdsk mov m,a lda wrtype cpi wrdir ;non defered/directory write? rnz ;no ;current operation is a non defered write, must flush all write pending buffer lda sekdsk call flush ret ; ;compare register HL with 'sektrk', return with aNNNNNNNNNNNNNNNNWNNNNNNNNNNNNNNNNNNNNNN contains write pending data?? ora a jz filhst inx h mov a,m call flush ;must flush this buffer - flush all buffer for drive ; specified in reg A to minimize head movement filhst: ; set up buffer header, also may have to fill the host buffer lhld bufptr mvi m,0 ;start as no write pending inx h lda sekdsk mov m,a inx h xchg lhld sektrk xchg mov m,e inx h mov m,d inx h lda sekhst mov m,a lda sekdsk call movdrvblk ;in case block clobbered by the last flush RyNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN zero flag reset if not equal, ; or zero flag set if equal. return with carry flag set if 'sektrk' is less ; than value in reg HL, else carry flag is reset. sektrkcmp: xchg lhld sektrk mov a,h ;compare high byte cmp d rnz ;return if not equal or if 'sektrk' is less mov a,l ;compare low byte cmp e ;sets flags ret ; ;determine whether dir or dat bcb is to be used choosebcb: lhld dirtrk call sektrkcmp lhld dirbcb rc ;use directory buffer rz lhld datbcb ;use data bufferNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN!lda rsflag ;need to read? ora a jz match lhld bufptr inx h call set$read$hst ;must read if data not in buffer and operation ; is not an unallocated write match: ;lru housekeeping - make the buffer pointed to by 'bufptr' most recently used lhld savebcb shld bcbaddr call lrukeeping ;copy data to or from buffer lhld bufptr xchg if bankedbuf lxi h,hstbnk ;get buffer bank number dad d mov c,m ;this is the source bank if a read operation endif lxi h,hstbuf dad d mov NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN ret ; ;housekeeping neccessary for the lru ;bcb address in 'bcbaddr', most recently used buffer header pointer in 'bufptr' ; lrukeeping: call getlrumask ;one bit set for each buffer to be maintained lhld bufptr mov c,l mov b,h lxi h,bufusage dad b mov m,e ;make buffer<-bufptr most recently used lxi h,bufmsk dad b mov c,m call getnbuf mov b,e call getbufhead lxi h,bufusage dad d updtusage: ;update usage/status of other related buffers mov a,m ana c mov m,a jn*;pNNNNNNNNNNNNNNNNN“NNNNNNNNNNNNNNNNNNNNN!e,m inx h mov d,m ;reg DE contains host buffer dma address lda firstsec mov b,a lda seksec sub b ;normalized sector number mov b,a lda secmsk ora a lxi h,0 jz nomsk ;128 byte-sector ana b ;multiply reg A by 128 ora a ;reset carry rar ;rotate bit 0 into carry mov h,a rar ;shift carry into bit 7 ani 080h mov l,a nomsk: dad d ;sector located within host buffer xchg if bankedbuf lda dmabank ;this is the destination bank if a read op mov b,a endif lhld dmaadr ;dNNNNNNNNNNNNNNNNҭNNNNNNNNNNNNNNNNNNNNNNz notlru shld saveaddr ;save the address of the least used buffer notlru: lxi d,bufheadsz dad d dcr b jnz updtusage lhld saveaddr lxi d,-bufusage dad d mov c,l mov b,h call getlrubuf mov m,c inx h mov m,b ret ; ;read/write a 128byte sector ; writehost: mvi a,0ffh jmp rw128 readhost: mvi a,0 rw128: sta diskcmndflag ;set write/read operation flag lxi h,setparm lxi d,rwparm ;setup parameters for the physical layer lxi b,parmsz ;ldir db 0edh,0b0h jmp rwopeӥNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNma address set by user ; if not bankedbuf xchg endif ; lda readop ora a jnz rwmove ;read operation ; ;write operation, mark and switch direction of data transfer if bankedbuf mov a,c ;swap source and destination bank mov c,b mov b,a endif xchg ;swap source and destination address push h push d lhld bufptr ;set buffer write pending flag mvi m,0ffh call getwrtpend ;set write pending master flag mvi m,0ffh pop d pop h ; rwmove: if bankedbuf push h push d ca$NNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNN!ration ; ;host disk parameters pointer given in register HL, ;write one sector to disk. ; set$wrt$hst: mvi a,0ffh ;a write operation jmp rwhost ; ;host disk parameters pointer given in register HL, ;read one sector from disk. ; set$read$hst: mvi a,0 ;a read operation rwhost: sta diskcmndflag ;set write/read operation flag lxi d,rwparm ;setup parameters for the physical layer lxi b,parmsz ;ldir db 0edh,0b0h ; rwoperation: call diskoper sta erflag ;reg A and zero flag is noyNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN2Չ(yʐmNNNNNNNNNNNNNNNNNNNNNNn-zero if error jnz dskexit ret ; ;phsical read/write entry point ; ;disk operation related equates ; vdisk equ 66h ;disk drq interrupt-NMI dsksidebit equ 16 ;bit mask used to turn side select on/off dskdensbit equ 00020h ;bit mask used to turn density select on/off dskbits equ 0003fh ;bits on the disk select port which are associated ; with the disk densbits equ dskdensbit ;disk port bit mask for density select dskselbits equ 000c0h ;bits not associated with disk ; ;SETUP TNNNNNNNNNNNNNNNNKNNNNNNNNNNNNNNNNNNNNNNshld phytaddr lxi d,oldadrv lxi b,mpdt$sz ;make sure this is the length of a mpdt entry ;ldir db 0edh,0b0h notphys: ;add in density and side into selbit lxi h,selbit lda side ora a mov a,m jnz sideodd ori dsksidebit jmp sidesel sideodd: ani 0ffh and (not dsksidebit) sidesel: ani 0ffh and (not dskdensbit) ani dskbits ;mask off other bits, just to be sure...MaTed mov m,a lda density ora a jnz doubdens ;single density mvi a,dskdensbit ora m mov m,a douDNNNNNNNNNNNNNNNNxNNNNNNNNNNNNNNNNNNNNNNHE PHYSICAL DISK PARAMETERS FOR A R/W OPERATION ; diskoper: call dsk$parm$set lda diskcmndflag inr a jnz fd$read ; fd$write: call fdsk$write push psw lhld phytaddr lda oldadrv ;save for physical drive table mov m,a pop psw ora a ;check error code jz skip1 lda merrcd cpi 3 jc skip1 ;seek error mvi a,3 skip1: ori 10h ;indicate floppy mov b,a lda errorsave ;setup for listerror call listerror ;list error if any jc fd$write rz ;return if write ok or `NNNNNNNNNNNNNNNNtNNNNNNNNNNNNNNNNNNNNNNbdens: ret ; ;ACTUAL READ/WRITE OF A HOST/PHYSICAL SECTOR ; ;disk operation related equates ; numstepin equ 4 ;number of steps to take in before restore command is issued ; ; to solve the problem of going past track 0 sensor DKBASE EQU 080H ;CONTROLLER BASE ADDRESS ; DISK PORT NAMES DSKCMND EQU DKBASE ;CONTROLLER COMMAND PORT DSKST EQU DKBASE ;CONTROLLER STATUS PORT TRKREG EQU DKBASE+1 ;TRACK REGISTER SECTREG EQU DKBASE+2 ;SECTOR REGISTER DSKDATA EQU DKBASE+3 ;DISK DATA PORT du?NNNNNNNNNNNNNNNNENNNNNNNNNNNNNNNNNNNNNNerror ignored mov c,a lda merrcd ;check operation was write cpi 2 ;write error code mvi a,1 ;set error code rnz mov a,c ora a ret fd$read: call fdsk$read push psw lhld phytaddr lda oldadrv mov m,a pop psw ora a ;check error code jz skip3 lda merrcd cpi 3 jc skip3 ;must be seek error 3 or 4 mvi a,3 ;both treated as seek skip3: ori 10h ;indicate floppy mov b,a lda errorsave call listerror jc fd$read rz ;return if good read or error igNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN!skselport equ piaport+2 ;pia Peripheral Regisiter B ; ; DRQ BIT IS ON A SEPARATE DEVICE dskintrq equ 77h ;port that intrq is on CB1 of 6821 intrq equ 7h ;bit number for intrq on dskintrq port (above) ; dskready equ 7h ;bit number in disk status port that indicates that disk is ready selectmask equ 0fh ;bits which select drive ; DISK COMMANDS ; ;NOTE: rate selection done in code-parameter driven unload equ 10h ;unload head (seek - no verify) restr EQU 08H ;restore(no verify-assumes tr'BNNNNNNNNNNNNNNNN'NNNNNNNNNNNNNNNNNNNNNNnored mvi a,1 ;set error return ret dsk$parm$set: lda Xadrv mov c,a call xrdrvdpb ;set xrdrv and get dpb lxi d,-10 ;point to start of mxdpb dad d xchg ;save ; lhld track ;logical track to seek ldax d ;testing double sided ora a ; also resets carry flag jz psett1 ;double sided mov a,h rar mov h,a mov a,l rar mov l,a mvi a,0 ral ;get side bit psett1: ;entry defaults to side 0 sta side ;0=>side zero (even track) ; nonlabel side (single side[NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNack 0 sensor is good ; ; or the reseek will catch it) stepin equ 48h ;step in, no track update as restore sets track register ; ; and head is loaded, no verify SEEKCMD EQU 1CH ;SEEK COMMAND(verify-head loaded) seeknove equ 18h ;seek command (no verify-head loaded) rdcmnd EQU 088H ;READ SECTOR COMMAND wrcmnd EQU 0A8H ;WRITE SECTOR COMMAND FORCE EQU 0D0H ;FORCE INTERRUPT COMMAND NOPDSK EQU 18H ;FAKE SEEK WITH HEAD LOAD-only if disk data = track register ; terminate equ 1101$0tNNNNNNNNNNNNNNNN (NNNNNNNNNNNNNNNNNNNNNNd) ;1=>side one(odd) label side ;double density inx d ldax d sta density ;double tracked inx d ldax d ora a sta db$track shld abstrk ;absolute track number with side bit removed jz psett2 dad h psett2: shld ptrack lda Xrdrv ;check to see if physical parameters are lxi h,curdsk ; already setup cmp m jz notphys mov m,a add a ;get address of physical drive table('diskpar') mov l,a mvi h,0 lxi d,dkptab dad d mov e,m inx h mov h,m mov l,e $aNNNNNNNNNNNNNNNN {NNNNNNNNNNNNNNNNNNNNNN000b ; terminate current command stpin equ 0100$1011b ; step in command stpout equ 0110$1011b ; step out command rdaddr equ 1100$0000b ; read address command ; Equates for INI and OUTI instructions readbytes equ 0db08h ;EXAF and part of IN instruction writebytes equ 0d308h ;EXAF and part of OUT instruction ; ERROR MASKS FOR CONTROLLER DSKHOME EQU 98H ;RESTORE ERROR BIT MASK seekok EQU 98H ;SEEK ERROR BIT MASK WROK EQU 0FCH ;WRITE ERROR BIT MASK RDOK EQU 9CH ;READ ERROR BIT MASK rdNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN3։'yːnNNNNNNNNNNNNNNNNNNNNN!addok equ 98h ;read address error bit mask ; ; note that lost data is valid ; ; Utility routines for the diskoper routine-low level first ; swapnmiout: ;routine takes the 8 bytes from the vdisk ; ; address and stores the eight bytes in diskswap lhld vdisk ; could use LDIR instruction instead, slower shld diskswap lhld vdisk+2 shld diskswap+2 lhld vdisk+4 shld diskswap+4 lhld vdisk+6 shld diskswap+6 lhld vdisk+8 shld diskswap+8 ret ; swapnmiin: ;routine takes thePNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNo same track out dskdata ;tell which track we must move to mvi a,nopdsk ;seek no verify and load head ;not required orx rateoff ;proper step rate out dskcmnd ;output command call wfintr pop psw rz ;top bit is the not ready bit, 0=> ready headloaddelay: ;routine for invoking delay required after the drive has been ; ; selected, until the drive has come ready ie come to speed ; ;add delay for drive to come to speed if next operation is write lda diskcmndflag ora a jz nostart)aNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN 8 bytes from the disk swap area(diskswap) ; ; and stores the eight bytes back into vdisk interrupt lhld diskswap ; could use LDIR instruction instead shld vdisk lhld diskswap+2 shld vdisk+2 lhld diskswap+4 shld vdisk+4 lhld diskswap+6 shld vdisk+6 lhld diskswap+8 shld vdisk+8 ret ; wrroutnmi: ;puts the write routine at the vdisk interrupt address lxi h,writebytes shld vdisk lxi h,0d983h ;port and instructions-83h and EXX shld vdisk+2 lxi h,07e23h ;two more instructioNNNNNNNNNNNNNNNN.=NNNNNNNNNNNNNNNNNNNNNNdelay lhld drtspeed ;NOTE: This time must be less than 4 revolutions of the disk call delay ; or cannot guarentee the head will load-use long delay ONLY ; ; if drive requires long delay for motor startup and the head is ; ; always loaded (ie will not be deloaded by controller in 4 revs) ; ; also include delay below nostartdelay: lhld hdldtime ;NOTE: This time must be less than 4 revolutions of jmp delay ; the disk or cannot guarentee that the head will be loaded ; tundelay: }NNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNN!ns- INX H, MOV A,M shld vdisk+4 lxi h,08d9h shld vdisk+6 lxi h,45edh ;retn instruction - return from nonmaskable interrupt shld vdisk+8 ret ; rdroutnmi: ;puts the read routine at the vdisk interrupt address lxi h,readbytes shld vdisk lxi h,0d983h ;port and instructions-83h and EXX shld vdisk+2 lxi h,02377h ;two more instructions- MOV M,A and INX H shld vdisk+4 lxi h,08d9h shld vdisk+6 lxi h,45edh ;retn instruction - return from nonmaskable interrupt shld vdisk+8 ret ǣNNNNNNNNNNNNNNNNH_NNNNNNNNNNNNNNNNNNNNNN;routine for delaying until the tunnel erase has been turned off lda ioflag inr a rnz ;only have to do tunnel delay when last operation was a write xra a sta ioflag lhld dlytun ;delay required for tunnel erase to turn off jmp delay ; restore: ;routine forces selected drive back to track 0 call tundelay mvi c,numstepin ;number of steps to take toward center restorestep: lda rate$bts ;step in on restore so we do not get past track zero ori stepin ; with proper step rate...most NNNNNNNNNNNNNNNN{nNNNNNNNNNNNNNNNNNNNNNN; wfintr: ;routine for waiting for disk completion ; NOTE: may want to cause disk timeout prodecures at this point ; ;inputs the CB1 here to wait for completion in dskintrq ;port address of CB1 port ana a ;test the disk completion bit-interupt request-top bit (MSB) jp wfintr xthl ;delay for 1793 (disk controller) to set up return xthl ; code in dskselport ;make the disk completion interrupt go away-edge triggered in dskst ;get status, in case needed sta errorsave ;save for latppNNNNNNNNNNNNNNNNNkPNNNNNNNNNNNNNNNNNNNNNNof the time ;NOTE change if bothersome out dskcmnd ; sort of wipes out the benefit of the restore if we do call wfintr dcr c jnz restorestep ; lda rate$bts ;do actual restore ori restr out dskcmnd push h lhld hdsettime ;wait for head to settle call delay pop h call wfintr ani dskhome ;checking error bits ; rz ;Note:this is to change mvi a,4 ;cannot find home error stc ;set carry for error return ret ; track$set: ;seek to track if not on the proper track ; fNNNNNNNNNNNNNNNN XaNNNNNNNNNNNNNNNNNNNNNNer error analysis/reporting ret ; headunload: ;routine for unloading head-also causes deselection of all drives in trkreg ;seek to same track out dskdata ;tell which track we must move to mvi a,unload ;unload head command ;not required orx rateoff ;proper step rate out dskcmnd jmp wfintr ; headload: ;routine forloading head in dskst ;check to see if head is already loaded-do not need head load delay ani 80h ; if head is loaded(drive is selected) push psw in trkreg ;seek tpNNNNNNNNNNNNNNNNN  2NNNNNNNNNNNNNNNNNNNNN!lda nsktry ;set retry count mov c,a set$tr1: lhld abstrk xchg lhld curnt$trak ora a ; reset carry flag ;dsbc de db 0edh,52h ; HL now contains the number of steps to do jz good$track ; heads might already be on desired track push b ;save retry counter push psw ;save carry flag jnc track$out ;moving outwards xra a ; negate number of steps (make positive) sub l mov l,a sbb a sub h mov h,a track$out: push h ;save number of steps to move call tundelay ;delay bef$NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN2Չ'z̐o|NNNNNNNNNNNNNNNNNNNNNNorewe move to let ; tunnel erase collapse pop h ;double tracking logic lda db$track ora a jz no$dbtrk dad h ;must move twice as much to get anywhere no$dbtrk: lda rate$hd ora a jz soft$seek pop psw ;decide if moving out or in jc hard$in ;stepping out xra a ;0 to Areg mov d,l jmp hard$move hard$in: ;stepping in mvi d,0 ;0 to Areg mov a,l hard$move: out dsk$data mov a,d out trk$reg lda rate$bts ;do actual seek ori seek$nove ; but with no verify /NNNNNNNNNNNNNNNN/NNNNNNNNNNNNNNNNNNNNN!half$ms db 0edh,5bh dw half$ms delay$loop: dcx d mov a,d ora e jnz delay$loop dcx h mov a,h ora l jnz half$delay finish$delay: mvi a,terminate out dskcmnd ; terminate step command, in case xthl xthl xthl xthl in dskselport ;make the disk completion interrupt go away-edge triggered ret ; read$address: lhld vdisk ;store nmi bytes in temporary storage shld raddskswap ; so we can restore later ; ; after we have clobbered them with the disk dma routine lxi h,45Y\NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN out dsk$cmnd call wfintr ;should no be possible to get bad status jmp seek$verify soft$seek: pop psw ;restore carry flag mvi a,stpout jnc soft$out mvi a,stp$in soft$out: sta direct ; set direction to step in do$it: lda direct out dskcmnd dcx h ;moved counter decrement push h ; HL should now contain number of steps to do call soft$delay pop h mov a,h ora l jnz do$it seek$verify: lhld hdsettime ;wait for head to settle call delay ;now verify lda abstrk oaNNNNNNNNNNNNNNNNXNNNNNNNNNNNNNNNNNNNNNNedh ;retn instruction - return from nonmaskable interrupt shld vdisk lda nsktry ;set retry count mov c,a ; raddloop: ;entry for read address loop if interrupt mvi a,0ffh sta dsk$flg ;signal to interrupt routine that nmi is running endif mvi a,rdaddr ;load the read address command out dskcmnd call wfintr ;wait for disk operation to complete ; ;when here disk transfer has completed ani rdaddok if interrupt mvi a,0 ;signal that nmi is done sta dsk$flg endif jz raddgoodbNNNNNNNNNNNNNNNNkNNNNNNNNNNNNNNNNNNNNNNut trk$reg out dsk$data lda rate$bts ori seek$cmd out dsk$cmnd call wfintr ani seek$ok pop b jnz trretry lhld abstrk shld curnt$trak good$track: ; if low$wrt$currnt ;section for low write current ; lowtrk=0ffffh turns low write current off for a drive ; lowport=0 turns low write current off for all drives lda low$port ora a jz no$low$write mov c,a ;lded ptrack db 0edh,5bh dw ptrack lhld lowtrk lda low$mask ;inp b db 0edh,40h ora a ;reset carry ;"NNNNNNNNNNNNNNNNNN>NNNNNNNNNNNNNNNNNNNNNN ; ;check error seekrtry dcr c ;decrement retry counter jnz raddloop call restore jc raddbadd ;error exit xra a ;set up to say we are on track 0 jmp raddskip raddgood: ;restore 66H and alternate register bank ; in sectreg ; get current track number read by read address raddskip: ;entry if had to restore sta curnt$trak out trk$reg ;set track register xra a ;return with carry reset for no error sta curnt$trak+1 ;for consistency reset MSbyte raddbadd: lhld raddskswap ;[NNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNdsbc de db 0edh,52h jc low$off ;reset low write current cma ana b jmp low$exit low$off: ;set low current ora b low$exit: ;outp a db 0edh,79h no$low$write: ; endif ; lda abstrk ;set up track register,...just in case out trk$reg xra a ; A=0 for clean completion and carry reset ret trretry: ;error getting to track-retry dcr c ;retry counter jz bad$track push b ;save error retry count call read$address ;finds out what track we are on, or forces 0 pop b jncVNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNrestore original bytes from temporary area shld vdisk ret ; direct: ;direction to step db 0 curnt$trak: ;track that head is on dw 0 raddskswap: dw 0 ; diskset: ;routine is responsible for making the rest of the disk drivers ; ; not have to worry about different drives-ie as if only one drive ; ; exists on the system ; ; includes ; ; 1-reselecting drive ; ; 2-informing controller what track it is on-note the forced restore ; ; on track=0FFFFH ; ; 3-trying to guarentee that the kNNNNNNNNNNNNNNNN .NNNNNNNNNNNNNNNNNNNNNN set$tr1 ret ;read address supplies own error code bad$track: ;error exit mvi a,3 stc ret track$go: ;entry to force to track-no assumptions call read$address ;get what track are we on from disk jmp track$set ; soft$delay: ;routine for waiting for disk completion ;NOTE: delays must be minimum 1 millisecond for 8" and 2 mS for 5" ; also, 5" must be multiple of 2 lhld step$rate dad h ;double to get number of half mS to delay half$delay: ;one/half millisecond ;lded CNNNNNNNNNNNNNNNNNN {NNNNNNNNNNNNNNNNNNNNNNhead is loaded (ie drive is selected ; ; and up to speed) lxi h,oldadrv ;check logical drive same as last mov a,m cpi 0ffh ;special check for automatic match lda Xadrv jz diskseta cmp m ;actual comparison diskseta: mov m,a ;set oldadrv=Xadrv cnz mount ;ask for it to be mounted lda Xrdrv ;see if we are changing physical drives since lxi h,olddsk ; last call cmp m jz disksetb ;drive has changed mov m,a ;set olddsk=Xrdrv (last physical drive) call tundelay ;must F NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN3։'yʐo lxi b,table10! lxi d,-10000 next: mvi a,'0'-1 pdecl: push h! inr a! dad d! jnc stoploop inx sp! inx sp! jmp pdecl stoploop: push d! push b mov pNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNN sp lxi sp,newstck push h ;old stack push d push b push psw ;exx db 0d9h push h push d push b push psw ;exx db 0d9h lhld svhl ;restore reg HL lda curbnk sta orgbnk mvi a,3 ;swap to video bank call Ybank call indgprim ;indgprim address contain a instruction ; if graphics primitive is not loaded lda orgbnk ;swap to original bank call Ybank ;exx db 0d9h ;restore registers and stack pop psw pop b pop d pop h db 0d9h ; pop psw pop b pop dzBNNNNNNNNNNNNNNNN *NNNNNNNNNNNNNNNNNNNNN!c,a! call conoute pop b! pop d nextdigit: pop h ldax b! mov e,a! inx b ldax b! mov d,a! inx b mov a,e! ora d! jnz next ret table10: dw -1000,-100,-10,-1,0 pderr: lxi h,drive$msg ! call pmsg ; error header lda Xadrv ! adi 'A' ! mov c,a ! call conoute ; drive code lxi h,track$msg ! call pmsg ; track header lhld track ! call pdec ; track number lxi h,sector$msg ! call pmsg ; sector header lhld sector ! call pdec ; sector number ret ; error message components BNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN3Չ'yːoNNNNNNNNNNNNNNNNNNNNN!drive$msg db cr,lf,bell,'BIOS Error on ',0 track$msg db ': T-',0 sector$msg db ', S-',0 ; ;TIME DELAY 1/2 FOR EACH COUNT OF A (NOT 0) ; SECDELAY: push h secdeloop: lxi h,28846 ;approx 1/2 second call delay dcr a jnz secdeloop pop h ret ; ; TIME DELAY ROUTINE APPROX 12.0 MICROSECONDS/COUNT IN HL ; FIXED OVERHEAD APPROX 17.33333 MICROSECONDS ; NOT INCLUDING THE CALL. preserves register DE and BC DELAY: mov a,h ora l rz ;overhead is 3.3333 microseconds if HL=0 PUSH pNNNNNNNNNNNNNNNNNնNNNNNNNNNNNNNNNNNNNNNNurrent port - set to 0 for low ; write current not required, endif if low$wrt$currnt low$port db 76h ; else set to port number. endif low$mask db 08 ;bit on for bit position for enabling lwc db 0,0,0 ;not used - retain compatibility with cpm3.0 half$ms dw 105 ;half a msec timing for soft step rate rpterr db 0ffh ;print disk error message in the bios getresp db 0ffh ;get response to the retry and allow prompt ; from the keyboard, otherwise use the following default rstring db 05fh anNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN!D LXI D,-1 DELAY1: DAD D xthl xthl xthl xthl jc DELAY1 POP D RET ; ; MESSAGE OUTPUT ROUTINE ; MOUT: XTHL PUSH D PUSH B PUSH PSW MOUT2: MOV A,M INX H CPI EOT JZ MOUT1 push h MOV C,A CALL conoute ;call table entry for console output pop h JMP MOUT2 MOUT1: POP PSW POP B POP D XTHL RET ; conoutx: ;entry for calling conout but preserving registers push h ; as in version 2 push d push b push a call conoute pop a pop b pop d pop h NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNd 'Y' ;response to the retry prompt defaults to Yes db 05fh and 'N' ;response to the allow prompt defaults to No nbrotry db 0 ;0 to retry infinite number of times, else ; set to 1 to 255 for number of auto retries. ; ;physical disk parms required for an disk I/O ; errorsave: ds 1 ;temporary storage of error code from disk controller merrcd: ;Megatel internal error code db 0 phytaddr: ;address of active megatel physical table dw 0 side db 0 ;which side/surface is I/O to take p7-BNNNNNNNNNNNNNNNNL!NNNNNNNNNNNNNNNNNNNNNNret mount: call mout db cr,lf,'Please mount disk ',eot lda Xadrv adi 'A' mov c,a call conoutx call mout db ' in drive ',eot lda Xrdrv adi '0' mov c,a call conoutx call mout db ', press when ready ',eot mountl: call conine ani 7fh ;just in case cpi cr jnz mountl call mout db cr,eot ret ; ;* * * * * * * * * * ; ; null routine and routines not presently implimented ; useread: dw retnull usepunch: dw retnull ; retnull: ret ; ;* * * * * * * * * qNNNNNNNNNNNNNNNNrNNNNNNNNNNNNNNNNNNNNNNlace(0 or 1) density db 0ffh ;double density flag(0FFH-double 0-single) db$track db 0 ;double track flag ; xrdrv db 0ffh ;current host/physical drive to be accessed olddsk db 0ffh ;last host drive accessed curdsk db 0ffh ;host drive which has the characteristics ; given in the following table ; ;NOTE: this table must match the order of the MPDT ; oldadrv: ;last logical drive selected for this physical ds 1 ; drive lowtrk: ;track for low write current to begin, ds 2 ; 0ffffhRDNNNNNNNNNNNNNNNN*CNNNNNNNNNNNNNNNNNNNNNN* ; ; working storage ; ;Miscellaneous system variables ; nullcount: db nbronull ; if profile ;command setup for CCP on cold boot command: db 7 ;command length db 'PROFILE' db 0 ;to make total length of 9 endif ds 30 sysstack equ $ ; ;interrupt ; use$13: cur$map db 0 ;storage for memory bank number clk$flg: ;user select to display clock on screen if valpha db 0ffh and scn$clock endif if not valpha db 0 ;no clock for the graphics video endif dsk$flg db 0ffh ;if dZpNNNNNNNNNNNNNNNNN:}NNNNNNNNNNNNNNNNNNNNNN for no low write current hdldtime: ;head load time ds 2 hdsettime: ;head settle time ds 2 drtspeed: ;time for drive to come to speed(motor start) ds 2 drvpower: ;delay before turning on drive to allow for ds 2 ; power supply to recover dlytun: ;tunnel delay ds 2 ndrtry: ;number of disk retries ds 1 nsktry: ;number of seek retries ds 1 step$rate: ;seek step rate in milliseconds ds 2 rate$bts: ;rate bits for hardware step cf 1793 db 3 ; default to slowest r=pNNNNNNNNNNNNNNNNN  LNNNNNNNNNNNNNNNNNNNNNNisk NMI operation, block out memory switching ; on other interrupts clk$pos dw cl$pi60 ;where to display clock cl$p50 dw cl$pi50 ticks db 60 ;number of ticks per second - set at boot time inrpflag db 0 ;ei/di user flag ;master interrupt enable flag for global ei (gsysei) routine if interrupt inrpenable db 0fbh ;ei endif if not interrupt inrpenable db 0 ;nop endif ;* * * * * * * * * * ; ; Current Disk Driver I/O variables ; use$11: ; if not low$wrt$currnt low$port db 0 ;low write cg#NNNNNNNNNNNNNNNNNN \NNNNNNNNNNNNNNNNNNNNNNate(set in drvtbl) rate$hd: ;flag to do hardware step rate db 0ffh ;use hardware stepping selbit: ;select bits ds 1 tpi: ;tracks per inch-unused/word ds 2 mini: ;flag to indicate minifloppy ds 1 ;End of table ; ; ;NOTE: next two bytes must stay together diskcmndflag: ;0FFH => write command, otherwise read ds 1 ; used by diskoper, and transfered to next byte at end ioflag: ;hold of above byte used for tunnel erase delays ds 1 diskswap: ;temporary storage area fo+NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN3։'yːpT NNNNNNNNNNNNNNNNNNNNNNr bytes displaced by ds 12 ; disk NMI routines dkcabnk: db 1 ;save bank before bank switching ; ; ;drive, track, sector, dma, dma bank, blocking/deblocking variables ; ;current disk/track/sector(translated) to be read/written ;these are set by the seldsk, setsec, settrk, setdma routines, and will not ;be changed or modified otherwise. ; setparm: sekdsk db 0 ;seek disk number sektrk dw 0 ;seek track number seksec dw 0 ;seek sector number(logical translated) dmaadr dw 80h ;dma address pNNNNNNNNNNNNNNNNNXNNNNNNNNNNNNNNNNNNNNN!porting ; unacnt db 0 ;remaining unalloc rec cnt unadsk db 0 ;unalloc disk number unatrk dw 0 ;next unalloc track unasec dw 0 ;pointer to next unalloc sector number unaseccnt db 0 ;remaining unallo sector count for 'unatrk' ; bcbaddr dw 0 savebcb dw 0 saveaddr dw 0 bufptr dw 0 deactwrt db 0ffh ;init to unmark buffer when deactivate ds 40h dskstck: usrstack dw 0 ; ;* * * * * * * * * * ; ;tables used by the disk driver ; ;note : run time configuration of formats for removable media 8BNNNNNNNNNNNNNNNN2iNNNNNNNNNNNNNNNNNNNNNNset by user - default to 80h dmabank db tpabank ;dma bank is the TPA bank for disks which does ; ; not require blocking/deblocking ; sekhst dw 0 ;seek host sector number(physical) ; ;physical read/write routine parameters/ host disk and buffer variables ;these may be different from the above. ; rwparm: ;leave these in the same order as that of the buffer header ; minus the write pending flag xadrv db 0 ;current logical disk selected track dw 0 ;seek to track - still logical at this poinapNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNcan ;be done by patching the disk driver tables if ;1) exisiting dma buffer, translate table, allocation and check ; sum memory storage are sufficient for the new format. ;2) if blocking/deblocking is to be performed, drive block storage ; must be preallocated to the logical drive. ;3) a disk reset (bdos function 13) is performed after configuration, to ; deallocate all buffers which may contain invalid data. ;4) diskreset (Megatel added bios entry) be called to force reset of parameters ; 2NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNt sector dw 0 ;seek physical sector number(=sekhst) bufadr dw 80h ;host dma buffer address bufbank db tpabank parmsz equ $-rwparm ; abstrk dw 0 ;absolute track number with bottom bit shifted out ; - bottom bit is used to decide r/w surface - ptrack dw 0 ;low write current starting track ; it is double of abstrack if double tracking drive ; ;blocking/deblock variables ; lstdrv db 0ffh ;logical drive number of last processed r/w ; if lastdrv not equal drv, then defered ; writesKNNNNNNNNNNNNNNNN͜NNNNNNNNNNNNNNNNNNNNNN the disk driver is currently using. ; ; Non removable media can not be reconfigured. ; ; We have supplied an utility (DFCU) to configure a logical drive on the fly ; use17: ; nbrodsk db numdisks ;number of logic disks ; ; Set pointer to 0ffffh if blocking/deblocking table is not to be allocated,; ; or pointer is set to the starting address of the blocking/deblocking table. ; Note that if table is not allocated, then data is dmaed ; into/from TPA bank directely from/to disk controller. ; Als pNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN for 'lstdrv' will be flushed ; before r/w take place for 'drv' ;initialize to 0 ; drv db 0ffh ;stores the drive number associated with the ; following drive block cdrvblk: ;drive block for the current r/w operation nonrmv db 0 ;non removable flag - contains 0ffh if media is ; not removable dirtrk dw 0 ;which track does directory ends?? note that ; data may very well start on the same track sharebuf db 0 ;share directory and data buffer dirbcb dw 0 ;directory buffpNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNo note that you can allocate the table for a drive even if deblocking ; is not required(ie 128 byte-sectors : secshf and secmsk = 0), so that ; buffered(blocked) I/O using up to 8 buffers is still possible. ; if not dblk0 drvblk0 equ 0ffffh ;if no blocking deblocking parameters, endif ;set address/pointer to 0ffffh ; if not dblk1 drvblk1 equ 0ffffh endif ; if not dblk2 drvblk2 equ 0ffffh endif ; if not dblk3 drvblk3 equ 0ffffh endif ; drvblktbl: dw drvblk0 dw drvblk1 dw drvblk2 pNNNNNNNNNNNNNNNNN ݢNNNNNNNNNNNNNNNNNNNNNNer address datbcb dw 0 ;data buffer address (same as dirbcb if shared blksiz db 0 ;block size in units of 128 byte-sectors ; ;disk parameters needed by the deblocking routine - gotten from DPB firstsec db 0 ;first sector number cpmspt db 0 ;=hstblk * hstspt : cpm sectors per track secmsk db 0 ;=hstblk - 1 secshf db 0 ;=log2(hstblk) ; rsflag db 0 ;must read physical sector flag readop db 1 ;0 if write operation, 1 if read operation wrtype db 0 ;write operation type erflag db 0 ;error reNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNN dw drvblk3 ; use18: ;specify if sector blocking/deblocking is required for each drive ;set corresponding byte for each to 0 if not, 0ffh if yes. ;note that if the blocking/deblocking pointer is set to 0ffffh, than blocking/ ;deblocking can not be performed. ; drvbdreq: ;|043| db 000255 db 000255 db 000255 db 000255 ; if assemcomt DRVBLK equ $ db 0 ;non removable flag - contains 0ffh if media is ; not removable dw 3 ;dirtrk ;on which track does the directory end db 0lNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN4։(z̐p"NNNNNNNNNNNNNNNNNNNNN!ffh ;sharebuf ;shared directory and data buffer ; 0 if not shared, 0ffh if shared dw bcb ;dirbcb ;pointer to directory buffer control block dw bcb ;datbcb ;pointer to data buffer control block ; the above two address are the same if ; shared buffer. db 2048/128 ;blksiz ;cp/m block size in units of 128 bytes ; (file storage is allocated in blksiz*128 ; byte chucks) ; this is used as the init value for 'unacnt' bcb: ;buffer control block db 0ffh ;last disk NNNNNNNNNNNNNNNNwNNNNNNNNNNNNNNNNNNNNNNsector without having to modify the bios. ; However, user can downsize the buffers and increase the number of ; buffers after the system is installed if his/her physical sectors ; are smaller than 1k. Th increase of buffers will optimize disk ; performance. ; ; 3 - We are only using the buffer space available to all 128k/256k systems. ; But depending on the types of terminal emulation(alph vs graphics), ; clock frequency(50 vs 60 hz), and the size of memory(128k vs 256k), ; it is quite possibleNNNNNNNNNNNNNNNNNNDNNNNNNNNNNNNNNNNNNNNN!to access this bcb. note that if any ; write is pending within this buffer group, ; it is always for this drive. init to 0ffh db 0 ;if any write pending(defered writes that need ; flushing) for any of the buffers within ; this control block. 0 - no, 0ffh - yes ; initial value must be zero db 2 ;number of buffers. maximum is 8 dw bufhead ;least recently used buffer header pointer dw bufhead ;pointer to the beginning of buffer header list dw 512 ;buffer capacity -wNNNNNNNNNNNNNNNNJNNNNNNNNNNNNNNNNNNNNNN that additional memory is available for ; buffering. User may wish to optimize memory usage by adding more ; directory/data buffers to the system. ; ; 4 - For memory configuration information, see memory usage diagrams in ; the Quark Manual. ; bcb0: db 0ffh db 0 db 1 ;number of buffers - increase this if you have room dw bufhead0 dw bufhead0 dw 400h ;up to 1k sector size - change to correct sector size db 00000001b ;set one bit for every buffer available bufhead0: db 0 db 0ffhBNNNNNNNNNNNNNNNN{NNNNNNNNNNNNNNNNNNNNNN must be greater than ; or equal to host sector size. db 11111111b ;lru mask. set one bit for every buffer ; available. starting from bit 0 to bit 7 ; ;buffer header list for a bcb ; bufhead: ;header for buffer 1 db 0 ;defered write: 0-no, 0ffh-yes, must init to zero db 0ffh ;host disk number; initial value must be 0ffh dw 0 ;host track number dw 0 ;host sector number dw buf0$0 ;actual buffer address db 0 ;which bank is the buffer in db 0 ;buffer usage - when value is 0, bufyNNNNNNNNNNNNNNNNNN(NNNNNNNNNNNNNNNNNNNNNN dw 0 dw 0 dw buffaddr1 ;buffer address may be reconfigured db 0 ;buffer bank may be reconfigured db 0 db 0feh ;change this byte to reflect buffer number bcb1: db 0ffh db 0 db 1 dw bufhead1 dw bufhead1 dw 00400h db 00000001b bufhead1: db 0 db 0ffh dw 0 dw 0 dw buffaddr2 db 0 db 0 db 0feh if dblk0 drvblk0: db 0 ;media flag - change to reflect non removable media dw 3 ;|050| directory track end db 0 ;not shared directory and data buffer dw bcb0 UpNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNfer is least used db 0feh ;buffer mask- turn bit 0 to 7 off for buffer number 0 ; to 7 respectively. ;header for buffer 2 db 0 db 0ffh dw 0 dw 0 dw buf0$1 db 0 db 0 db 0fdh ;header for buffer 3 db 0 db 0ffh dw 0 dw 0 dw buf0$2 db 0 db 0 db 0fbh ;header for buffer 4 db 0 db 0ffh dw 0 dw 0 dw buf0$3 db 0 db 0 db 0f7h ;header for buffer 5 db 0 db 0ffh dw 0 dw 0 dw buf0$4 db 0 db 0 db 0efh ;header for buffer 6 db 0 db 0ffh dw 0 dXNNNNNNNNNNNNNNNNN'NNNNNNNNNNNNNNNNNNNNN!;directory bcb dw bcb1 ;data bcb db 16 ;|051| ;cp/m block size in '128 byte' units endif ; if dblk1 drvblk1: db 0 dw 3 ;|052| db 0 dw bcb0 dw bcb1 db 16 ;|053| endif ; if dblk2 drvblk2: db 0 dw 3 ;|054| db 0 dw bcb0 dw bcb1 db 16 ;|055| endif ; if dblk3 drvblk3: db 0 dw 3 ;|056| db 0 dw bcb0 dw bcb1 db 16 ;|057| endif ; DPBASE EQU $ ;BASE OF DISK PARAMETER BLOCKS DB 00 ;|024|PHYSICAL DRIVE DB 0 ;NOT USED DPE0: kpNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNw 0 dw buf0$5 db 0 db 0 db 0dfh ;header for buffer 7 db 0 db 0ffh dw 0 dw 0 dw buf0$6 db 0 db 0 db 0bfh ;header for buffer 8 db 0 db 0ffh dw 0 dw 0 dw buf0$7 db 0 db 0 db 07fh endif ; ;WITH REGARD TO BLOCKING DEBLOCKING CONFIGURATION ; ; 1 - The removable media should be set to true to allow higher performance ; of disk I/O if the media is not removable. ; ; 2 - We are allocating very large sized directory/data buffers so that user ; can install a 1k host E-NNNNNNNNNNNNNNNN ENNNNNNNNNNNNNNNNNNNNNNDW XLT0,0000H ;TRANSLATE TABLE DW 0000H,0000H ;SCRATCH AREA DW DIRBUF,DPB0 ;DIR BUFF,PARM BLOCK DW CSV0,ALV0 ;CHECK, ALLOC VECTORS DB 00 ;|025|PHYSICAL DRIVE DB 0 ;NOT USED DPE1: DW XLT1,0000H ;TRANSLATE TABLE DW 0000H,0000H ;SCRATCH AREA DW DIRBUF,DPB1 ;DIR BUFF,PARM BLOCK DW CSV1,ALV1 ;CHECK, ALLOC VECTORS DB 00 ;|026|PHYSICAL DRIVE DB 0 ;NOT USED DPE2: DW XLT2,0000H ;TRANSLATE TABLE DW 0000H,0000H ;SCRATCH AREA DW DIRBUF,DPB2 ;DIR BUFF,PARM BLOCK DW CSV2,ALV2 ;CHECK,pNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN4׉(z̐ocNNNNNNNNNNNNNNNNNNNNNN ALLOC VECTORS DB 00 ;|027|PHYSICAL DRIVE DB 0 ;NOT USED DPE3: DW XLT3,0000H ;TRANSLATE TABLE DW 0000H,0000H ;SCRATCH AREA DW DIRBUF,DPB3 ;DIR BUFF,PARM BLOCK DW CSV3,ALV3 ;CHECK, ALLOC VECTORS ; USE15: xdtbl: dw dpe0 dw dpe1 dw dpe2 dw dpe3 ; ;physical disk parameters table ; USE14: dkptab: dw diskpar0 dw diskpar1 dw diskpar2 dw diskpar3 ; if assemcomt ; ;DO NOT ASSEMBLE. THESE SERVE TO COMMENT 'DISKPARn' ; ; NOTE that 'diskpar' is also refered to as 'mpdt' at6NNNNNNNNNNNNNNNN0NNNNNNNNNNNNNNNNNNNNNN ;logical disk format parameters not supplied by the Digital Research's dpbs ; xdpb: ;the next 3 bytes are used by the DFCU to determine whether storage ;in memory is enough for a new format configuration db 48 ;number of bytes allocated to the translate table ;would be greater than or equal to the actual translate ;table size db 58 ;number of bytes allocated to the allocation vector ;would be >= actual allocation vector size db 64 ;number of bytes allocated to the check sum vect3pNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN places(for megatel ; physical disk table) ; ;if floppy diskpar: db 0ffh ;last logical drive to access this physical disk device dw 0ffffh ;track at which low write current is envoked ;each delay count = 17 usec dw 3600 ;wait for the head to load dw 324 ;wait for the head to settle after a seek dw 0 ;wait for drive to come to full speed after a select ;(motor start time) dw 0 ;time needed for power supply to recover from select ; to deselect to select dw 54 ;delay for tunnel eIrNNNNNNNNNNNNNNNNFNNNNNNNNNNNNNNNNNNNNNNor ;would be >= actual check sum vector size ; db 0ffh ;0ffh if double sided, else 0 db 0ffh ;0ffh if double density, else 0 db 0 ;0ffh if requires double tracking dw 77 ;number of tracks per side = ; (ending track number + 1) % 2 dw 128 ;number bytes per sector db 6 ;physical sector skew db 48 ;number of host/physical sectors per track db 20 ;gap size for formatting ; ;disk parameter block(D.R. standard) ; DPB: DW 68 ; 128 BYTE RECORDS PER TRACK DB 04h ; BLOCK SHIFT D9pNNNNNNNNNNNNNNNNNuNNNNNNNNNNNNNNNNNNNNN!rase db 8 ;number of sector r/w retries db 8 ;number of seek retries dw 0 ;software step rate - step done in software db 0 ;1793 step rate bits db 0ffh ;0ffh - use 1783 rate; 0 - use soft step rate db 0feh ;reset bit corresponding to SEL line(sel 0 here) dw 48 ;number of tracks per inch db 2 ;set to 1, 2, or 3 for 5", 8",or winchester ;if winchester db 0ffh dw 160 ;track to park heads on dw 0,0,0,0,0 ;don't care db 0,0 ;don't care dw 0 ;don't care db 4 ;number of heads for wNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNB 0FH ; BLOCK MASK DB 0 ; EXTENT MASK DW 280h ; MAXIMUM BLOCK NUMBER DW 0FFh ; MAXIMUM DIRECTORY ENTRY NUMBER DB 0F0h ; ALLOC VECTOR FOR DIRECTORY DB 0 DW 040h ; CHECKSUM SIZE DW 3 ; OFFSET FOR SYSTEM TRACKS DB 2 ; PHYSICAL SECTOR SIZE SHIFT DB 3 ; PHYSICAL SECTOR SIZE MASK endif ; xdpb0: ;|035| db 000068 db 000040 db 000032 db 000000 db 000255 db 000000 dw 000077 dw 000512 db 000003 db 000017 db 000020 ; DPB0: ;|036| DW 000068 DB 000004 DB 000015 DB 0/NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNinchester(one head per surface) db 0ffh ;1793 step db 0fdh ;SEL line(sel 1) dw 160 ;number cylinders db 3 ;set to 1, 2, or 3 for 5", 8",or winchester endif ; mpdt0: diskpar0: ;|030| db 000255 dw 065535 dw 017400 dw 003480 dw 029000 dw 017400 dw 000174 db 000009 db 000009 dw 000002 db 000003 db 000255 db 000254 dw 000048 db 000002 ; mpdt$sz equ $-mpdt0 ; diskpar1: ;|031| db 000255 dw 065535 dw 017400 dw 003480 dw 029000 dw 017400 dw 000174 db 00NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN!00000 DW 000313 DW 000127 DB 000192 DB 000000 DW 000032 DW 000003 DB 000002 DB 000003 ; xdpb1: ;|037| db 000128 db 000128 db 000128 db 000000 db 000255 db 000000 dw 000077 dw 000512 db 000003 db 000017 db 000020 ; DPB1: ;|038| DW 000068 DB 000004 DB 000015 DB 000000 DW 000313 DW 000127 DB 000192 DB 000000 DW 000032 DW 000003 DB 000002 DB 000003 ; xdpb2: ;|039| db 000128 db 000128 db 000128 db 000000 db 000255 db 000000 dw b_NNNNNNNNNNNNNNNNNN 0NNNNNNNNNNNNNNNNNNNNNN0009 db 000009 dw 000002 db 000003 db 000255 db 000253 dw 000048 db 000002 ; diskpar2: ;|032| db 000255 dw 065535 dw 017400 dw 003480 dw 029000 dw 017400 dw 000174 db 000009 db 000009 dw 000002 db 000003 db 000255 db 000251 dw 000048 db 000002 ; diskpar3: ;|033| db 000255 dw 065535 dw 017400 dw 003480 dw 029000 dw 017400 dw 000174 db 000009 db 000009 dw 000002 db 000003 db 000255 db 000247 dw 000048 db 000002 ; if assemcomt ;8NNNNNNNNNNNNNNNN eNNNNNNNNNNNNNNNNNNNNNN000077 dw 000512 db 000003 db 000017 db 000020 ; DPB2: ;|040| DW 000068 DB 000004 DB 000015 DB 000000 DW 000313 DW 000127 DB 000192 DB 000000 DW 000032 DW 000003 DB 000002 DB 000003 ; xdpb3: ;|041| db 000128 db 000128 db 000128 db 000000 db 000255 db 000000 dw 000077 dw 000512 db 000003 db 000017 db 000020 ; DPB3: ;|042| DW 000068 DB 000004 DB 000015 DB 000000 DW 000313 DW 000127 DB 000192 DB 000000 DW 000032 DW 000003 DB 0\NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN3։){͐q@NNNNNNNNNNNNNNNNNNNNNN00002 DB 000003 ; ;any code following parm '099' will be replaced by the installation program ; ;|099| XLT0: DB 00001,00002,00003,00004 DB 00013,00014,00015,00016 DB 00025,00026,00027,00028 DB 00037,00038,00039,00040 DB 00049,00050,00051,00052 DB 00061,00062,00063,00064 DB 00005,00006,00007,00008 DB 00017,00018,00019,00020 DB 00029,00030,00031,00032 DB 00041,00042,00043,00044 DB 00053,00054,00055,00056 DB 00065,00066,00067,00068 DB 00009,00010,00011,00012 DB 00021,00022,00NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN!023,00024 DB 00033,00034,00035,00036 DB 00045,00046,00047,00048 DB 00057,00058,00059,00060 XLT1: DB 00001,00002,00003,00004 DB 00013,00014,00015,00016 DB 00025,00026,00027,00028 DB 00037,00038,00039,00040 DB 00049,00050,00051,00052 DB 00061,00062,00063,00064 DB 00005,00006,00007,00008 DB 00017,00018,00019,00020 DB 00029,00030,00031,00032 DB 00041,00042,00043,00044 DB 00053,00054,00055,00056 DB 00065,00066,00067,00068 DB 00009,00010,00011,00012 DB 00021,00022,00023,00024 $edNNNNNNNNNNNNNNNN0"NNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNDB 00033,00034,00035,00036 DB 00045,00046,00047,00048 DB 00057,00058,00059,00060 DS 00060 XLT2: DB 00001,00002,00003,00004 DB 00013,00014,00015,00016 DB 00025,00026,00027,00028 DB 00037,00038,00039,00040 DB 00049,00050,00051,00052 DB 00061,00062,00063,00064 DB 00005,00006,00007,00008 DB 00017,00018,00019,00020 DB 00029,00030,00031,00032 DB 00041,00042,00043,00044 DB 00053,00054,00055,00056 DB 00065,00066,00067,00068 DB 00009,00010,00011,00012 DB 00021,00022,00023,00024 DNNNNNNNNNNNNNNNNNNV@NNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNeqNNNNNNNNNNNNNNNNNNNNNNB 00033,00034,00035,00036 DB 00045,00046,00047,00048 DB 00057,00058,00059,00060 DS 00060 XLT3: DB 00001,00002,00003,00004 DB 00013,00014,00015,00016 DB 00025,00026,00027,00028 DB 00037,00038,00039,00040 DB 00049,00050,00051,00052 DB 00061,00062,00063,00064 DB 00005,00006,00007,00008 DB 00017,00018,00019,00020 DB 00029,00030,00031,00032 DB 00041,00042,00043,00044 DB 00053,00054,00055,00056 DB 00065,00066,00067,00068 DB 00009,00010,00011,00012 DB 00021,00022,00023,00024 DBbpNNNNNNNNNNNNNNNNNuONNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNN F~NNNNNNNNNNNNNNNNNNNNNN 00033,00034,00035,00036 DB 00045,00046,00047,00048 DB 00057,00058,00059,00060 DS 00060 DIRBUF DS 128 CSV0 DS 00032 ALV0 DS 00040 CSV1 DS 00128 ALV1 DS 00128 CSV2 DS 00128 ALV2 DS 00128 CSV3 DS 00128 ALV3 DS 00128 END 1,00062,00063,00064 DB 00005,00006,00007,00008 DB 00017,00018,00019,00020 DB 00029,00030,00031,00032 DB 00041,00042,00043,00044 DB 00053,00054,00055,00056 DB 00065,00066,00067,00068 DB 00009,00010,00011,00012 DB 00021,00022,00023,00024 DBC[aNNNNNNNNNNNNNNNN -NNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN4؉*|ΐ rNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNN˩NNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNaNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNR>NNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNmNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNN4\NNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNN$bNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNN SNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNN BNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN4؉*|ΐ rNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNN,NNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNN$NNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNqNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNBNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNRNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNN aNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNN 4NNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN4؉*|ΐ r`sNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNN&NNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNgNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNVNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNN4NNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNN ;NNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNN hNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN4؉*|ΐ r&NNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNPuNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNcDNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN4؉*|ΐ r !NNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNN rNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNN CNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNN 1NNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNN dNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNN WNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNN GNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNN tNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNN !NNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN4؉*|ΐ r!NNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNN!NNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNN!NNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNN!t`NNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNN!GQNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNN!NNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNN!!3NNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNN!1 NNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNN!