IMD 1.17: 10/06/2011 8:25:17 48k cp/m version 2.2 cbios rev e mod 2 #909 boot; ab: djdma 8, cd: djdma 5, ef: dj/b, gh: hddma m5 movcpm; ab: hddma m5, bc: djdma 8, de: djdma 5, gh: dj/b multio 9600 console; multio 1200 serial lst: ssdd 8/1024  >&2P!"Q2S:ʑ!@"~ʭqʭ4#¡z5û#)#)% \X COPYRIGHT (C) 1979, DIGITAL RESEARCH _͌> ͒> Ò> Ò͘~#͌ì _2<Ñ2͘ˑÑÑÑ͘ߑÑ !2:2a{_:ʖ:>Ľˑʖ:=2̘–!B!6#5ڑʖ:Ľ!ͬ’ʧݒÂݒ )!F#xʺ~0wëw!" !~6ͽ:ý(!ϔ#͘*~ ""͌#>?͌͘ݒ =_.:;<> Oo$>!͘Y2*O"ʉ@G:ʐ:wÖx2p0ʹ#*©6?ëw˜0ï#6 ¹.0#*ٓ6?ۓwȓ0ߓ#6 #6" #~?  xDIR ERA TYPESAVEREN USER"ɠ!yΘO#< Ty#O 321y_͸2y2ͽ:1͘ВA͌>>͌9ؒВ2^ :¥.!_~#fow]!v"!ߔçREAD ERRORçNO FILE^: !Θ ~ 3#0 Wx x G ~ # 3x~#B!Y~ɯ2͘:=!ý:=!:ý^T!Θ~  6?#ˆ:`O> K{̕͘ВA͒>:͒ԕ͢>:͒͢xK > K > ͒x  ٕٕ͢’ØÆ^ BRͧ9!5‚#~Y‚#"T͘<ÆALL (Y/N)?^ TБʧ͘!6!~ڇ w4!Y~ʆ͌’†t=ʆٔf ^ T͘ 2o&)|+!ؒ͘Ԗ͘ڑ<ͧՒÆNO SPACE^ :Ty!͘ݘB*O=?_s#"^sG!~Ypsp2͘m͘ÆÆf ͧFILE EXISTS _:Θ É:Θ ė:ʉ=2)ͽÉ֘ T!@Бk!ؒ͘}|q=qf^!~2͘>`~2ݘ2\!͘!B!~> >#0~O#Cx2͘Ւ1)ͽÂf zͧÆBAD LOADCOMf^:Θ ! Â$$$ SUB"ɠ"C{2֦!"E9"1A22ަ!ty)K!G_^#V*CțΛԛ~Eȥץ ,&-AGMS!ʙ!ՙô!ô!ܙBdos Err On : $Bad Sector$Select$File R/O$ɚ:BA2ƙӚӚ!~6 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Ӛ#2E>! ^#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*# ):BO!yoxg*:BO}!N#F "*Ȧ#*s#r^ ~!J! J*:馅o$*C~i6iw**{#zr+s{ozg**̦͕** Ğ,w͜͸ڞͲ!!N#F$**O!~#ҟ:A#~$=2Ek͌:Ԧ:Ŧ/GyO>2Ԧ!ئq*C"٦͡ʔ*٦JҔ^:ئOyʃ?|x | s-|N-# S:2E!Ԧ~Яw>T D^6kƞ-äPYyѠ 5*Ʀ{zBK5ڋ>*Cw~#+w#w+ɯ2E22i^ *C :ݦ~ۡw~͔͔# # ͡ w ~>2Ҧ!E5T*C!"C"C!w# F! w͌x2Ҧ͢*C ~<wʃG:Ŧ!Ҧʎì 4~ʶ¬:Ӧ<ʶ$ʶïZͻx>2զ>2Ӧͻ:!ᦾZ2:Eẅ́͊ќͲҝ>2զ>2ӦT*CGͻ:ẅ́n>2צ;O ^DM;}H>"*C :ݦ:צddslO s#r:E͊:զ==»y==»*Ww#*"ќ͸*:ĦG#š"ڞќ͸:!ᦾңw4!iw:զҝZ!E~=26ҝ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~=2֦u:B2ߦ~2wE:A*Cw>"!""2B!"ڞ!rQQQâ~?¥ͦ~?rQ*٦"CQ-Q͜QüQrQ$Q*):B"ڞ*)*)Q;*"E:֦;:A2AQÓQÜQҤ*C}/_|/*W}_*"}o|g":ަʑ*C6:ষʑw:ߦ2֦E**E}DQ>2զ*xMfÇèë);,#I@Ù2:LOM ʎyH:LOMH> !#>22!"!"22:>>!2Oʪ:::O1>2&.DҮv`i"`i"`i":g.Dy2Ҡ{a.D|ʠ͓s#r#q#~Ѩy2N uk2:2%a.D͓^#V#Nf:_!!:%O:26:g. D|^#V#"~#fo"*>~<:w#ʪ">!$ BAD MAP OVERFLOW! !y2>J2*|O|g+i|g}o[#|g"!ʇ#x:=o&)))))))!>ªǪǪ>2>=>2>> 2g2 .@*!|.@.@*#DM.@.@.@>7>xϩ.@ϩͼ!ʪ:8:==:N=>2ũ:g|>OogyK#{_~#foy!:O*>zŠ{Š*"!*"#y¿#:¿#:¿#:¿#: ¿#!ʪ n۪w# xЪo&))))~#O  :O0 >2(!"C><<;f!"C2(O!"CDM 'T*  ͛ ͛!~# x† ͛ڱ' £*͊ ~#fo~٫ n&ͯЫ/g2ܬO>$!>þ###!ʪ>2>2>2ͼ:ܬO͚!"#"2ڠ'2ݬ !_͊ʪͯ:ݬ wxO s#r!N:ܬ2ܬO0 xO0!ެ:ܬ_~~ 8u     %&'()*+, -. /0  12!"34#$!"#$1234%&'(5678 )*+,9:;<  -./0 12345678 !"#$%&'(9:;<=>?@)*+,-./0?4 < @+ 4 h@x1@W@MǮJW:Ϳ!P6z#6#6!`:@^!ʪ#)#)# 2:Z ~#fo~ n&͹ ݮ/g2oڠ!"#"2ڠ͹ !_Zʪ͹ HyO s#r!N:ડuw%f!@:ʌ=Ã!"i! "q!P6c#6#6!rcɯMaE&W:E!P6#6#6!`:@گ#)#) :%JJ2%:@ʘy#ژW>"O>2%Ø2: :!\!% n&2oڠ>2!"+"2ڠ:R!"ڠ¤>͹¤>O!~ʠʸ####è#~2#~#foް s#rް͹:f&6FV6  !"#$%&'( O!P6.#p`ôxOͧÝ!P6##q#p#w#6%#wj!P6%#6~‰z|7+6(#6cÓOy2:怱2yO:ây2!P6"#:w###`:O!Q~O#>O#>O#>>!> !Pw#+`:T?1㳈ӲGA|ͶӲ22!" z!ʪ!<2$$$$" za | |72_ڠ:Ͷڠβ Ӳƴ:o&))))2Ųy2>à Dz>Ã_! 6#6ͻ׳6#6_!׳^#V+q#pi`" z̓!"`i" y=V 2y2 XT!"P2R! 6#6#6#6û>Ã>2@* @ڡڡ:2/O:2:2!6UC~7zƳ7:_!`i#|/g}/o#|}O?(Q?(?(?&üӼ6׺"b8x活 W Morrow Designs 48K CP/M 2.2E + Seagate M5 122L>2! ʪ6d !骯22!"î:LO>LHHMI:LOI:LOε!_^#V`0  Y`@:0  >KH_IW>K!{#z+## *H>KzI{H>KM:LO>K*J|I}H>KHIMOVCPM COMjABOOT& ASM ABOOT& ASM9ASM COM@BAUD COM!BAUD DOCBIOS ASM\ !"BOOTMW ASM>#$%&BOOTMW COM 'CBIOS& ASM()*+,-./CBIOS& ASM01234567CBIOS& ASM89:;<=>?CBIOS& ASM@ABCDEFGCBIOS& ASMHIJKLMNOCBIOS& ASMPQRSTUVWCBIOS& ASMXYZ[\]^_CBIOS& ASM`abcdefgCBIOS ASMEhijklDDT COM&mnoDEBLOCK ASMOpqrstDISKDEF LIB1uvwxDUMP ASM!yz{DUMP COM|ED COM4}~FIRMB ASMyFORMATDJASMFORMATDJASMFORMATDJASMFORMATDJCOMFORMATMWCOMFORMATMWCOMaFORMATMWDOC1!~# x  y2!"%8 K ͯ>H"s:=j 2y2/2 l>2sT!"P2RͯH>2ͯ‘!"ͯ!"""!6UC~7zº7\X COPYRIGHT (C) 1979, DIGITAL RESEARCH _͌> ͒> Ò> Ò͘~#͌ì _2<2 !2:2a{_:ʖ:>Ľʖ:=2–!B!6#5ʖ:Ľ!ͬʧ )!F#xʺ~0wëw!" !~6ͽ:ý(!FORMT# ASMPFORMT# COM HTYP ASMHTYP ASMzHTYP PRLINSTALL COM:INSTALL DOC#LOAD COMMAKEPRL COMMAKEPRL COM?MAKEPRL DOCMBASIC COMMBASIC COM>NOTESHD DOCtPIP COM:PRL DOC REGEN ASM|REGEN COMSINGLE ASMZSINGLE COMSTAT COM)SUBMIT COM CBIOS& ASMXSUB COMSYSGEN COM MBASIC COM    MBASIC COM>-Copyright (C) Digital Research, 1979 1] ʒ?ʒ! ``0 s))) O A|s}s.g))æ|z Invalid memory size$!$ʢ~/w/wʕ|g*"|?¹>@G!>0w#w!4~:60+4z!N#F! x-  # !=!v"!|6!z#+w+w >q*# Ax!G}o|g"! :m z Ç!"  xʇ ~#z*!:m ʜ xü Synchronization error$ {~#o}oÜ:m r! ~#* DM! x w# !N#F! D!d>0w#w6!e4~:!60+4!*"jEz Ready for "sysgen" or "save 00 cpm00.com"$*  Constructing 00K CP/M 2.2$#͘*~ ""͌#>?͌͘ =_.:;<> Oo$>!Y2*O"ʉ@G:ʐ:wÖx2p0ʹ#*©6?ëw˜0ï#6 ¹.0#*6?w0#6 #6" #~?  xDIR ERA TYPESAVEREN USER"ɠ!yO#< Ty#O 321y_͸2y2ͽ:˜1͘A͌>>͌92^ :¥.!_~#fow]!v"!çREAD ERRORçNO FILE^: ! ~ 3#0 Wx x   G ~ # 3x~#B!Y~ɯ2:=!ý:=!:ý^T!~  6?#ˆ:`O> K{͘A͒>:͒͢>:͒͢xK > K > ͒x  ͢ØÆ^ BRͧ9!5‚#~Y‚#"T<ÆALL (Y/N)?^ Tʧ͘!6!~ڇ w4!Y~ʆ͌†t=ʆf ^ T 2o&)|+!<ͧ(>ͦ!q:_  !p+q.*   !q*&!p+q*2!p+q*2!p+q*22!p+q*!p+q*!p+q*!p+q*2!p+q*ÆNO SPACE^ :Ty!B*O=?_s#"^sG!~Ypsp2mÆÆf ͧÆFILE EXISTS _: É: :ʉ=2)ͽÉ T!@k!}|q=qf^!~2>`~22\!!B!~> >#0~O#Cx2͘1)ͽÂf zͧÆBAD LOADCOMf^: ! Â$$$ SUB"ɠ"C {2!"E 9" 1A 22!ty)K!G_^#V*C   ~E , &-AGMS  !!ô!ô!Bdos Err On : $Bad Sector$Select$File R/O$ :B A2 ! ~6  O͐  : E  B 2 >: b # : y! 4 5~yy 5 6y Ґ ^H @Oy H  H : – ͬ   #H : !  H ù  H  H $O͐ : 2 *C N# 2>2T *C G ͻ : w ̈́ n> 2;O ^ DM;}H> "*C  ::dd slO s#r:E ͊ :==»y==»*Ww# *" ͸ *:G#š" ͸ :!w4!i w: Z!E ~=26 2*C !!~~#~O~G#n,-.‹! w! yG!x͢.:E <ʄ! q!pQ:E <. ʄ$.:E <ʄ i 6}2E x N! ~态O>G~G!~G} *C !r#r#r ^ ͥ_y#x#{s+p+q-*C  ͥ!!q#p#w*:B O Y G }*MD "ã:!B w!>2*C ~=2u:B 2~2wE:A *C w>" !""2B !" !r QQQâ~?ͦ ~?r Q *"C Q- Q͜QüQr Q$Q*):B  " *)*)Q;*"E :;:A  2A QÓQÜQ*C }/_|/*W}_*"}o|g":ʑ*C 6:ʑw:2E* *E }DQ>2o ڠ!"##"#2ڠ͹ !_Z͹ HyO s#r!N:!#uw%f!@:!ʌ=Ã!"i! "q!P6c#6#6!rc MaE &W :E!P6#6#6!` :@#)#) :%J J 2%:@ʘ y#ژ W>"O>2%Ø 2: :!\!% n&2o ڠ>2!"#+"#2ڠ:R$!"#ڠ¤>͹ ¤>O!~ʠʸ####è#~2#~#fo s#r͹ :f##F#V#6#  !"#$%&'( O!P6.#p` ô xOͧ Ý !P6##q#p#w#6%#wj !P6%#6~‰ z| 7+6(#6c Ó Oy2!:!怱2!yO:!â y2!!P6"#:!w###` :!O!Q~O#>O#>O#>>!> !P!w#!+` :T?1!"!!!!G"A"|""!Ͷ!!!2#2#!#" #z!%!!<2#$$$$" #z!a! |" |!72#_"ڠ:#Ͷ!ڠ! !#:#o&))))2#!y2#>Ã" !>Ã"_"! #6#6ͻ""6#6!_"!!"^#V  x : 2 p & x ~+é 7 2 H ! >w _ : ! 5ͤ N k ͱ ¦ ͱ xʊ #N x : ! 2 ͤ ! 5™ #wO ~x½  p H    y< < ʑ  : !qMD # 2E > ! ^#V w#P :B O|^#V#"##"##"##"!O *!O *|!6ʝ 6>*w#w*w#w'û *! J * ""!N#F*^#V*~#foyx *{_zW+ * yx # *DM*s#r*s#ryOxG*0MD!!N: E G>O: \ S *C  :q n& ^#V> O^ "*}:*)= ":O:o"*C  *C !ͮ ~2~2ͦ :2ͮ : O:w:w |g}o *# ) :B O! yoxg*:B O }!N#F "*#*s#r^  ~!J  ! J *:o$*C ~i 6i w**{#z r+s{ozg**͕ **  , w͜ ͸ Ͳ ! !N#F$**O !~#:LOM ʎyH:LOMH>  !#>22!"!"2#2:>>!2O:::O1>2&.DҮv`i"#`i"`i"#:#g.Dy2#Ҡ{a.D|ʠ͓s#r#q#~y2N uk2:#2%#a.D͓^#V#Nf:#_!!:%#O:26:#g. D|^#V#"#~#fo"#*>#~<:#w#">!$ BAD MAP OVERFLOW! !'y2>J2*#|O|g+i|g}o[#|g"#!##ʇ#x:#=o&)))))))#!>ª>2>=>2>> 2g2 .@*!#|.@.@*##DM.@#.@.@>7>x.@ͼ#!#:8:==:N=>2:#g|>OogyK#{_~#foy!':#O*>zŠ{Š*#"!#*#"##y¿#:#¿#:#¿#:#¿#: #¿#!# nw# xo&))))~#O  +q#pi`" #z̓"!"#`i" #y=V" 2#y2# X"T!#"P2R! #6#6#6#6û">Ã">2#@* #@"ڡ""ڡ":#2#/O:#2#:#2#!#6UC~7z"7:#_!"`i#|/g}/o#"|}#O?(Q?(?(?)&#++)6#++))))"*b*)**)8+x+)#,,)#,, W Morrow Designs 48K CP/M 2.2E + Seagate M5 122L>2'!' 6d$ %!#2#2!"î:LO>LHHMI:LOI:LO$!$_^#V$`0  Y`@:0  >KH_IW>K!${$#z%+## $*H>KzI{H>KM:LO>K*J|I}H>KHI"**#"͕  : 2 Þ y<_WyOxOxG* ~V5dw^  :ʈNÎ N#Fyʝ*}|\#u* #DM*6# x±**s#r͡ *6#6  ^ >:A #~$=2E k͌ : :/GyO>2!q*C " ͡  ʔ*J Ҕ^ :Oyʃ?|x | s-|N-# S:2E !~Яw > T   D ^ 6k -äPYy 5*{zBK5ڋ>*C w~#+w#w+ɯ2E 22 i  ^ *C :~w~͔͔# #  w ~>2!E 5T *C !"C  "C !w# F! w͌ x 2͢ *C  ~<wʃG:!ʎì 4~ʶ ¬:<ʶ$ ʶïZͻ   x >2>2ͻ :!Z2:E w ̈́ ͊ Ͳ  > :O0 >2(!"C><<;f!"C2(O!"CDM 'T*   ͛ ͛!~# x† ͛ڱ' £*͊ ~#fo~ n&ͯ/g2O>$!>þ ###!>2>2>2ͼ:O͚!"##"#2ڠ'2 !_͊ͯ: wxO s#r!N:#2O0 xO0!:_~~ 8u     %&'()*+, -. /0  12!"34#$!"#$1234%&'(5678 )*+,9:;<  -./0 12345678 !"#$%&'(9:;<=>?@)*+,-./0?4 < @+ 4 h@x1@W@M J W :Ϳ!P6z#6#6!` :@^#!#)# )## 2!: Z ~#fo~ n&͹ /g2!$@B B HH II$@DI ABI$"$H$H@$$I! H*  $H@@A I $D!!$I"BI"I"@$BIIH$$$$BBI$@BI!"$$A DI$@ A$@$$@H! "!$$" @B$!!!DH$$"H @@BHH  !$$A"D@ "A" "BHA " !$ D B I $ !$$ H@BD D$ HI DIA!$$$ $" "$D ! $"  $AB " BDD $$D!"DI$!$BH!"IB I$"D HD" " $"! @H !BI " I  $I$I$DI$ !I$@"$"$! $I$I!AT$ @$D$$$@ A"AB $$ $HB@I@$$@@   !D HA $@D!$ $ @@@"H @@I $HU IB * * 0 12 e80 9480 15 * * 0 13 f00 9500 5 * * 0 14 f80 9580 16 * * 0 15 1000 9600 6 * * 0 16 1080 9680 17 * * 0 17 1100 9700 7 * * 0 18 1180 9780 18 * * 0 19 1200 9800 8 * * 0 20 1280 9880 19 * * 0 21 1300 9900 9 BDOS * * 0 22 1380 9980 20 * * 0 23 1400 9a00 10 * * 0 24 1480 9a80 21 * * 0 25 1500 9b00 11 * * 0 26 1580 9b80 22 * * * * Track 1 is recorded in double density format. There are * * 1024 bytes per sector. * * * * 1 1 1600 9c00 4 * * 1 2 1a00 a000 1 * * 1 3 1e00 a400 5 CBIOS (@ a700h) * * 1 4 2200 a800 2 * * 1 5 2600 ac00 6 * * 1 6 2a00 b000 3 * * 1 7 2e00 b400 7 * * 1 8 3200 b800 Unused * * * * Three spare sectors (track 0, sectors 2 to 4) have been * * provided for a more advanced boot loader at a later date. * * * * The warm boot loader starts on track 0, sector 5 and * * continues through to track 1 sector 3. Only the first * * 3/4 K bytes of track 1, sector 3 i * Cbios on track 0, sector 20. * * * * track sector sysgen load order Name * * 0 1 900 fc00 1 Cold boot * * 0 2 b00 9500 2 CCP * * 0 3 d00 9700 3 * * 0 4 f00 9900 4 * * 0 5 1100 9b00 5 * * 0 6 1300 9d00 6 BDOS * * 0 7 1500 9f00 7 * * 0 8 1700 a100 8 * * 0 9 1900 a300 9 * * 0 10 1b00 a500 10 * * 0 11 1d00 a700 11 * * 0 12 1f00 a900 12 * * 0 13 2100 ab00 13 CBIOS * * 0 14 2300 ad00 14 * * 0 15 2500 af00 15 * * 0 16 2700 b100 16 * * 0 17 2900 b300 17 * * 0 18 2b00 b500 18 * * 0 19 2d00 b700 19 * * 0 20 2f00 b900 20 * * 0 21 3100 Unused * * * * The warm boot load sequence starts at track 0, sector 2 * * and goes straight through to sector 12. There is still * * plenty of room left in this loader for more advanced * * things like sector interleaving although this is hardly * * necessary on a hard disk. * * * * * * Shugart SA1000 disk interface boot loader for the * * Morrow DH"$ @BI $"   !HAIB$ !A@"$@" I$H$$HI $H !$A $@ TTTT$ @H$s loaded since CP/M * * requires that the warm boot loader load up to the start * * of (but not past) the Cbios jump table. * * * * * * 8 inch floppy disk boot loader for the * * Morrow Designs Disk Jockey DMA (DJDMA) * * * * The loading is identical to that of of the DJ2DB except * * that the loader itself is loaded at 80h and the 'order' * * column does not apply. The DJDMA is capable of loading a * * complete track at a time and thus it merely zaps the * * tracks in all at once. * * * * * * 5 1/4 inch floppy disk boot loader for the * * Morrow Designs Disk Jockey DMA (DJDMA) * * * * The cold boot loader (track 0, sector 0) is loaded into * * RAM at 80h. This loader will start loading from track 0, * * sector 1 and stops at track 1, sector 9. The load * * sequence is as follows: * * * * track sector sysgen load order Name * * 0 0 900 80 0 Cold boot * * 0 1 b00 9500 1 CCP * * 0 2esigns Hard Disk DMA controller (HDDMA) * * * * track sector sysgen load order Name * * 0 1 900 100 0 Cold boot + CCP * * 0 2 d00 9300 1 * * 0 3 1100 9700 2 * * 0 4 1500 9b00 3 Bdos (@ 9d00) * * 0 5 1900 9f00 4 * * 0 6 1d00 a300 5 * * 0 7 2100 a700 6 Cbios * * 0 8 2500 ab00 7 * * 0 9 2900 af00 8 * * * * 1 10 2d00 b300 9 * * * * Since 1k byte sectors were implemented on this disk; * * track 0, sector 1 contains both the cold boot loader and * * part of the CCP. The cold boot loader relocates this * * peice of the CCP to it proper resting place as part of * * the boot process. * * * ***************************************************************** ***************************************************************** * * * The following table gives a general idea as to where the * * various parts of of the operating system are in memory. * * * * The only changes to the map that I see in the fu***************************************************************** * * * Morrow Designs CP/M vers 2.2 Cold Boot Loader. * * Cbios revision E.2, 3/4/82. * * * * The following routines will boot CP/M from the * * Disk Jockey 2D Rev. B 8 inch disk controller (DJ2D/B), * * Disk Jockey DMA 8 + 5 1/4 inch controller (DJDMA), * * Hard Disk Controller revision 3 (HDC3), * * or the Hard Disk DMA (HDDMA) disk controllers. * * * * 8 inch floppy disk boot loader for the * * Morrow Designs Disk Jockey 2D/B (DJ2DB) * * * * The 'order' column is the interleave sequence used by the * * loader during the load. * * * * track sector sysgen load order Name * * * * 0 1 900 ff00 0 Boot loader * * 0 2 980 Unused * * 0 3 a00 * * 0 4 a80 * * 0 5 b00 9100 1 CCP * * 0 6 b80 9180 12 * * 0 7 c00 9200 2 * * 0 8 c80 9280 13 * * 0 9 d00 9300 3 * * 0 10 d80 9380 14 * * 0 11 e00 9400 4 d00 9700 2 * * 0 3 f00 9900 3 * * 0 4 1100 9b00 4 * * 0 5 1300 9d00 5 BDOS * * 0 6 1500 9f00 6 * * 0 7 1700 a100 7 * * 0 8 1900 a300 8 * * 0 9 1b00 a500 9 * * * * 1 0 1d00 a700 10 * * 1 1 1f00 a900 11 * * 1 2 2100 ab00 12 CBIOS * * 1 3 2300 ad00 13 * * 1 4 2500 af00 14 * * 1 5 2700 b100 15 * * 1 6 2900 b300 16 * * 1 7 2b00 b500 17 * * 1 8 2d00 b700 18 * * 1 9 2f00 b900 19 * * * * The warm boot starts from track 0 sector 1 and continues * * through to track 1 sector 1. * * * * * * Shugart SA4000 disk interface boot loader for the * * Morrow Designs Hard Disk Controller rev. 3 (HDC3) * * * * The cold boot loader (track 0, sector 1) is loaded into * * RAM at either 100h or the 2DB's RAM depending on whether * * this loader is assembled with a 2DB or not. This cold * * boot loader will start loading the CCP from track 0, * * sector 2 and will finish up with the last part of the * ture is * * the increasing the space for the uninitialized tables * * following the Cbios. The amount of code and table space * * that can actually be loaded from the disk is fixed by the * * amount of space available on the system tracks. * * * * Our most restrictive (smallest) drive is the 5 1/4 inch * * 'minnie floppy'. This drive has 20 512 byte sectors for * * a total of 10k bytes on the system tracks. The 8 inch * * floppy disk drive is also very close to being filled up. * * * * Since 512 bytes are reserved for the cold boot loader we * * have a total of 9.5k bytes for the operating system. Out * * of this 5.5k bytes are used by the (CCP + BDOS) leaving * * us with a total of 4k bytes of loaded code and data space * * to play with. Right now we are using all of this space * * so any major additions will have to result in a little * * (lot?) of code shuffeling or in the creation of a Cbios * * that simply will not fit on a small disk drive. * * * * sysgen complt equ 4 ;Complete bit of status tmout equ 8 ;Time out bit of status wfault equ 10h ;Write fault bit of status drvrdy equ 20h ;Drive ready bit of status indx equ 40h ;Index bit of status pstep equ 4 ;Step bit of function nstep equ 0fbh ;Step bit mask of function hdrlen equ 4 ;Sector header length secln equ 512 ;Sector data length wenabl equ 0fh ;Write enable wreset equ 0bh ;Write reset of function scenbl equ 5 ;Controller control dskclk equ 7 ;Disk clock for control mdir equ 0f7h ;Direction mask for function null equ 0fch ;Null command idbuff equ 0 ;Initialize data command isbuff equ 8 ;Initialize header command rsect equ 1 ;Read sector command wsect equ 5 ;Write sector command endif ***************************************************************** * * * The following equates are for the Hard Disk DMA. * * * ***************************************************************** if maxmw ne 0 cyl equ 153 ;Specifications for a Seagate TechnologMA if wanted. * * * ***************************************************************** if (maxdm ne 0) or (maxmf ne 0) djkick equ 0efh ;Kick port for DJDMA controller channl equ 50h if maxdm ne 0 ;8 inch boot loader trkoff equ 22*128 ;Number of bytes loaded from track 0 else ;5 1/4 inch boot loader trkoff equ 9*512 ;Number of bytes loaded from track 0 endif setdma equ 23h ;Set DMA address djhalt equ 25h ;Halt controller djbran equ 26h ;Branch controller command redtrk equ 29h ;Read track command endif ***************************************************************** * * * Define the origin address for the various boot loaders. * * * ***************************************************************** if maxhd ne 0 ;HDC3 boot equ bios+biosln-512 ;Very last part of CP/M system endif if maxmw ne 0 ;HDDMA boot equ 100h endif if maxfd ne 0 ;DJ2D/B boot equ djram+300h ;Upper 3/4 of on board floppy RAM endif if (maxdm ne 0) or ( 48k 56k 60k 62k 64k * * image CP/M CP/M CP/M CP/M CP/M * * * * 900 ???? ???? ???? ???? ???? Loader * * b00 9500 b500 c500 cd00 d500 CCP * * 1300 9d00 bd00 cd00 d500 dd00 BDOS * * 2100 ab00 cb00 db00 e300 ed00 Cbios * * 3100 bb00 db00 eb00 f300 fb00 Tables * * 35ff bfff dfff efff f7ff ffff The End * * * * ???? 8d00 ad00 bd00 c500 cd00 DDT * * * ***************************************************************** msize equ 48 ;Memory size of target CP/M biosln equ 1900h ;BIOS length codlen equ 11h ;Code length ccpln equ 800h bdosln equ 0e00h size equ (msize*1024) ccp equ size-(biosln+ccpln+bdosln) bdos equ ccp+ccpln bios equ ccp+ccpln+bdosln cboot equ bios ;Cold boot address for CP/M loaddr equ ccp ;Load address for floppy retries equ 10 ;Maximum # of disk retries ***************************************************************** * * * Only one of the following equates should be set. The * * others sould be 0. These equates defy 506 heads equ 4 ;Number of heads per cylinder spt equ 9 ;Sectors per track precomp equ 64 ;Cylinder to start write precomensation lowcurr equ 128 ;Cylinder to start low current stepdly equ 30 ;Step delay (0-12.7 milliseconds) headdly equ 20 ;Settle delay (0-255 milliseconds) sectsiz equ 7 ;Sector size code (must be 3 for this Cbios) ; 0 = 128 byte sectors ; 1 = 256 byte sectors ; 3 = 512 byte sectors ; 7 = 1024 byte sectors (default for CP/M) ; f = 2048 byte sectors ;Define controller commands dmaread equ 0 ;Read sector dmawrit equ 1 ;Write sector dmarhed equ 2 ;Find a sector dmawhed equ 3 ;Write headers (format a track) dmalcon equ 4 ;Load disk parameters dmassta equ 5 ;Sense disk drive status dmanoop equ 6 ;Null controller operation reset equ 54h ;Reset controller attn equ 55h ;Send a controller attention chan equ 50h ;Default channel address stepout equ 10h ;Step direction out stepin equ 0 ;Step direction in band1 equ 40h ;No maxmf ne 0) ;DJDMA boot equ 80h endif offset equ 900h-boot ;DDT offset org boot ***************************************************************** * * * Cold Boot loader for a hard disk. * * * ***************************************************************** if (maxhd ne 0) or (maxmw ne 0) lxi sp,cstkhd ;Set up stack at end of this sector if maxhd ne 0 lxi b,19*100h+2 ;B = sector count, C = sector # call clodhd jmp cboot ;Go to CP/M else lxi h,boot+200h ;Copy part of CCP up lxi d,ccp lxi b,200h movlop: mov a,m ;Get a byte stax d ;Save it inx h ;Bump pointers inx d dcx b ;Bump counter mov a,b ;Test for end ora c jnz movlop lxi b,10*100h+2 ;B = sector count, C = sector # call clodhd jmp cboot ;Go to CP/M endif clodhd push b ;Save sector and count mov a,c ;Load sector sta hdsec lxi h,ccp-200h ;Get DMA address (self modifying) cdmahd equ $-2 ;Storage for previous DMA address if maxhd ne 0 lxi d,200h ;Offset ine the boot loader * * that is to be used. * * * ****************************************************************** maxhd equ 0 ;Set to boot an HDC3 controller maxmw equ 1 ;Set to boot a HDDMA controller maxfd equ 0 ;Set to boot a DJ2D/B controller maxdm equ 0 ;Set to boot a DJDMA controller with 8 inch maxmf equ 0 ;Set to boot a DJDMA controller with 5 1/4 inch ***************************************************************** * * * The following equates are for the Hard Disk Controller 3. * * * ***************************************************************** if maxhd ne 0 hdorg equ 50h ;Hard Disk Controller hdstat equ hdorg ;Hard Disk Status hdcntl equ hdorg ;Hard Disk Control hddata equ hdorg+3 ;Hard Disk Data hdfunc equ hdorg+2 ;Hard Disk Function hdcmnd equ hdorg+1 ;Hard Disk Command hdreslt equ hdorg+1 ;Hard Disk Result retry equ 2 ;Retry bit of result tkz equ 1 ;Track zero bit of status opdone equ 2 ;Operaction done bit of status precomp, high current band2 equ 0c0h ;Precomp, high current band3 equ 80h ;precomp, low current track0 equ 1 ;Track zero status wfault equ 2 ;Write fault from drive dready equ 4 ;Drive ready endif ***************************************************************** * * * The following equates are for the Disk Jockey 2D/B. * * * ***************************************************************** if maxfd ne 0 origin equ 0f800h ;Orgin of DJ 2D Mod B PROM djram equ origin+400h ;Disk Jockey 2D Mod B routines tkzero equ origin+9h ;Track 0 seek trkset equ origin+0ch ;Set track setsec equ origin+0fH ;Set sector setdma equ origin+12h ;Set DMA address dread equ origin+15h ;Read sector dmast equ origin+24h ;Get DMA address status equ origin+27h ;Disk status dskerr equ origin+2ah ;Flash error light setden equ origin+2dh ;Set density endif ***************************************************************** * * * The following equates are for the Disk Jockey Dto new DMA address else lxi d,400h endif dad d ;Add in offset, HL = new DMA address shld cdmahd ;Save new DMA address call crdhd ;Attempt a read pop b ;Recover sector number and count ; B = count, C = number dcr b ;Update sector count rz ;All done ? inr c ;Bump sector number jmp clodhd ;Continue reading ***************************************************************** * * * crdhd does the actual read from the controller, the DMA * * address and sector # have already been set up. * * * ***************************************************************** if maxhd ne 0 ;Low level HDC3 drivers crdhd lxi b,retries*100h+1 ;Maximum # of attempts crhd push b ;Save error count call hdread ;Attempt the read pop b ;Restore the error count rnc ;Return if no error dcr b ;Update error count jnz crhd ;Try again if not too many errors jmp $ ;Dynamic error halt hdread call hdprep ;Prepare the sector header image rc ;Error exit mvi a,rsbits 2 - 4 rlc sta dmasel1 ;Save in command channel head select ret divspt mvi c,0 ;Clear head counter divsptx sui spt ;Subtract a tracks worth of sectors rc ;Return if all done inr c ;Bump to next head jmp divsptx hdreset mvi a,(ret) ;One time code sta hdreset out reset ;Send reset pulse to controller lxi h,dmachan ;Address of command channel shld chan ;Default channel address xra a sta chan+2 ;Clear extended address byte xthl ;Wait for reset (around 10 uSEC's) xthl call hdissue ;Do load constants jc error ;Controller not present mvi a,dmassta ;Sense status command sta dmaop rdychek call hdissue ani dready ;Check for drive ready jnz rdychek ;Loop if not ready lxi h,0ffffh shld dmastep ;Do recalibrate call hdissue lxi h,0 shld dmastep ;Clear step counter shld dmarg0 ;Clear cylinder # shld dmarg3 ;Clear sector # + read disk command ret hdissue lxi h,dmastat ;Status byte mvi m,0 out attn ;Start controller lxi d,0 ;Timet ;Set up the proper track call dread ;Read the sector pop b jnc t0boot ;Continue if no error dcr b jnz fread ;Keep trying if error jmp dskerr ;Too many errors, flash the light t1boot lxi h,cboot ;We jump to cboot next time shld exit mvi c,1 ;Select double density call setden xra a ;First sector - 2 sta newsec mvi a,8 ;Size of (logical) track + 1 sta trksiz dcr a ;Number of sectors to back up sta backup lxi h,loaddr+0700h ;DMA start address for first revolution - 2048 shld newdma lxi h,loaddr+0300h ;DMA start address for second revolution - 2048 shld nxtdma lxi h,2048 ;Difference between DMA addresses shld secsiz lxi h,retries*100h+1;Maximum # of errors, track # shld nxtrty jmp t0boot ;Go load in track 1 endif ***************************************************************** * * * Cold boot loader for the Disk Jockey DMA controller * * * ***************************************************************** if (maxdm ne 0) ect ;Read sector command out hdcmnd call process ;Process the read rc ;Error exit xra a ;Pointer to data buffer out hdcmnd mvi b,secln/4 ;Number of bytes to read lhld cdmahd ;Get destination of data in hddata ;Two dummy data bytes in hddata rtloop in hddata ;Move four bytes mov m,a ;Byte one inx h in hddata ;Byte two mov m,a inx h in hddata ;Byte three mov m,a inx h in hddata ;Byte four mov m,a inx h dcr b ;Update byte count jnz rtloop ret process in hdstat ;Wait for command to finish mov b,a ani opdone jz process mvi a,dskclk ;Turn on Disk Clock out hdcntl in hdstat ani tmout ;Timed out ? stc rnz in hdreslt ani retry ;Any retries ? stc rnz xra a ;No error exit ret hdprep in hdstat ;Is Drive ready ? ani drvrdy stc rnz mvi a,isbuff ;Initialize pointer to header buffer out hdcmnd mvi a,null out hdfunc ;Select drive A xra a out hddata ;Form head byte out hddata ;Form track byte mvi a,0 ;e out counter mov b,e ;Controller busy status hdiloop mov a,m ;Get status ora a ;Set up CPU flags rm ;Return no error (carry reset) stc rnz ;Return error status xthl ;Waste some time xthl xthl xthl dcx d ;Bump timeout counter mov a,d ora e jnz hdiloop ;Loop if still busy stc ;Set error flag ret hdsec db 0 ;Currently selected sector dmachan equ $ ;Command channel area dmasel0 db 10h ;Drive select (step out, drive 0) dmastep dw 0 ;Relative step counter dmasel1 db 0 ;Head select dmadma dw 0 ;DMA address db 0 ;Extended address dmarg0 db 0 ;First argument dmarg1 db stepdly ;Second argument (stepping time) dmarg2 db headdly ;Third argument (Settle time) dmarg3 db sectsiz ;Fourth argument (Sector size) dmaop db dmalcon ;Operation code dmastat db 0 ;Controller status byte dmalnk dw dmachan ;Link address to next command channel db 0 ;extended address org boot+200h cstkhd equ $ ;Stack area at end of sector endif endif ********or (maxmf ne 0) ;Set up DJDMA loader mvi a,djbran ;Load branch channel command sta channl lxi h,commnd ;Load new command channel address shld channl+1 xra a sta channl+3 djstrt: out djkick ;Start controller djwait: lda djdone ;Get final status ora a ;0 = still busy jz djwait ;Loop if busy lxi h,sectb0 ;Check for bad load lxi b,40ffh ;b = ok, c = loaded lxi d,endtbl-sectb0 ;Error count + # of sectors djloop: mov a,m ;Load sector code cmp c ;Check for 0ffh (already loaded) jz djcont ;Skip if load was 'ok' mov m,c ;Load 'loaded' flag cmp b ;Check for 'ok' status jz djcont ;Skip if load ok inr m ;Make flag = 0 inr d ;Bump error counter djcont: dcr e ;Bump sector count inx h ;Bump table pointer jnz djloop mov a,d ;Check out error counter ora a jz cboot ;Start CP/M if no errors dcr m ;Drop retry counter jnz djstrt ;Retry load operation jmp $ ;Dynamic error halt commnd: db setdma ;Set DMA address dw ccp-512 ;Start at CCP db 0 ;Form sector byte hdsec equ $-1 out hddata mvi a,80h ;Form Key out hddata mvi a,dskclk ;Turn on Disk clock out hdcntl mvi a,wenabl ;Write enable on out hdcntl ret org boot+200h-2 ;Last word on sector is load address cstkhd equ $ dw boot endif if maxmw ne 0 ;Low level HDDMA routines crdhd call hdsetup ;Set up parameters lxi b,retries*100h+1 ;Maximum # of attempts crhd push b ;Save error count call hdissue ;Attempt the read pop b ;Restore the error count rnc ;Return if no error dcr b ;Update error count jnz crhd ;Try again if not too many errors error jmp $ ;Dynamic error halt hdsetup shld dmadma ;Set up DMA address call hdreset ;Reset controller lda hdsec ;Set logical sector number dcr a ;Range is actaully 0-16 call divspt ;Figure out head number -> (c) adi spt ;Make real sector number sta dmarg3 mov a,c sta dmarg2 ;Save head number cma ;Negative logic for the controller ani 7 ;3 bits of head select rlc ;Shove over to ********************************************************* * * * Cold boot loader for the Disk Jockey 2D Revision B controller * * * ***************************************************************** if maxfd ne 0 t0boot mvi a,5-2 ;First sector - 2 newsec equ $-1 inr a ;Update sector # inr a cpi 27 ;Size of track in sectors + 1 trksiz equ $-1 jc nowrap ;Skip if not at end of track jnz t1boot ;Done with this track exit equ $-2 sui 27-6 ;Back up to sector 6 backup equ $-1 lxi h,loaddr-80h ;Memory address of sector - 100h nxtdma equ $-2 shld newdma nowrap sta newsec ;Save the updated sector # mov c,a call setsec ;Set up the sector lxi h,loaddr-100h ;Memory address of sector - 100h newdma equ $-2 lxi d,100h ;Update DMA address secsiz equ $-2 dad d nowrp shld newdma ;Save the updated DMA address mov b,h mov c,l call setdma ;Set up the new DMA address lxi b,retries*100h+0;Maximum # of errors, track # nxtrty equ $-2 fread push b call trksExtended address db redtrk ;Read track db 0 ;Track 0 db 0 ;Side 0 db 0 ;Drive 0 dw sectb0 ;Sector table 0 db 0 ;Extended address db 0 ;Returned status db setdma ;Set DMA address dw ccp+trkoff ;Load address for track 1 db 0 ;Extended address db redtrk ;Read track db 1 ;Track 1 db 0 ;Side 0 db 0 ;Drive 0 dw sectb1 ;Sector table 1 db 0 ;Extended address db 0 ;Returned status db djhalt ;Halt controller djdone: db 0 ;Returned status org boot+5dh ;Boot + 5ch contains 'configuration byte' if maxdm ne 0 ;Booting from 8 inch drives sectb0: dw 0ffffh, 0ffffh ;Do not load boot loader dw 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ;22 sectors to be loaded sectb1: dw 0, 0, 0, 0ff00h ;First seven sectors db retries ;Retry counter else ;Booting from 5 1/5 inch drives sectb0: dw 0ffh, 0, 0, 0, 0;Do not load boot loader sectb1: dw 0, 0, 0, 0, 0 ;Load ten sectors db retries ;Retry counter endif endtbl equ $-1 ;end of table marker end@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! ~*!) " :  '<ͭ'<>V$>O$:Ğà\ÞØ`rÍÖ![w#w#b!"!F#v2[G*##~w*##~<*}q!~ڬ6![^![^#fk"͎͘!G#*####*^#Vû!^*"*if end !4w_#~ ʸ A:4~~# ¼ > \ ?ʻ w# !ͼ ? !ͼ {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/?'  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&)^#fk1*" COPYRIGHT(C) 1978, DIGITAL RESEARCH á 4êü /L9ASMPRNHEX!)ͼ !ͼ :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:  :6y:! 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*!{͚|͚}͚͚{!$~#͚͚> ͪ> ͪz'{ͅ>ɯ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~ ͅͰ>2lyPLnR>UX:l̅2l͓*>E2C!" """ :ʼ:*1 |R|ͦ0FIL: R  R* } *" :¿::¿üX!C^#fk[@ :Œ:=ʌG!ʆF#H vÛc*| EH ͺ,^1 ͦ *""1 EH DH ͺ,1 ͦ :  1:  " > 2 !!N#F!~w#~wN#Fh4!\F*}o|g!yLx#W!:F** ͳ* y2:OGyˆxʢ*##yOxGyʪ!%F** ͳ!*###ͳ!$0~#~#~#~!02829:2::2;!8!(W##~2#~2*}o|g*ͳ*!s }o|g*#ͳ!*###ͳ! *! *͜! *͜! !  !9! !N#F!R i`! 6! !!N#F!R i`! 6! !~#fo~@!~#fo~OG! !~w#~w  !N#F !C ! ' !~#fo"D!~#fo"@!~#fo"B!>w#w!:Dw:E#w!>w#w!@>#*D> *D~ !@>#%*D~-®!>w#w*D#"D:@2@:A2A%:@2@:A2A*D#"Dó! ~3#~:@:A*D~0*D ~A{*D >Z{*D ~OG! MDÇ*D ~OGyxx*D##"D:@2@:A2A*D~+%*D#"D:@2@:A2A%!@># *D~0 *D>9 !*D~OG! rrow Designs Inc.H  _ O!9~#fo||g}o  !9~ /<_ O!9~#fo|g}o º MD!9q#p!! 9~+ ~ ! 9N#F ! 9~w#~w! 9~w+~w !9q#p&!!9OG!9N#F!9~#fo ## # +++ #!9MD!9~#~#~#~ !9~w#~w#~w#~w#~w#~w#~w#~w!9MD! 9  # # #x!9MD! 9  # # #!94x!9!9#~#~+++~#~#~#>#>+++>#~#~#~ #~{$>#># >#!9MD!9~#fo! 9MD!9~#foU!9N#F!97!9MD!9~#fo! 9MD!9~#foU!9N#F!97! 9MD!9~#fo#!9MD!9~#fo#U!9N#Fkb9$!9~#foN#F#N#F! 9~#foN#F#N#F!!9~+++ʓ~i!9MD!9  # # #!9~w#~w#~w#~w!9~w+~w+~w+~w:!9N#F!9~#~}|! 9&}!!9!9!9N#F###q#p+++q!9N#F#q#pMo:|: |Ë  |*" ͩ !6="1 :  1}1:n:>BʋSSͦSSxS 1:  1"" ͦ 1 |R >O U!" 1 1!|_!^#fk $8AP`ixH ñññ81Ľ y0îH ñGîG  ñH ñ(Ľ yîH ñîîĽ y0îîH ñG 1: :,; c*| } 8OĽ 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 >N}|Ø *B!~#) !N#F>O>G0 !N#Fywx#w!@>#? *D~Ae *D>Ze *D~OG! MDm *D~OGylv x? *D#"D? *D~a *D>z !!N#F! N#F !~#fo }|:@2@:A2A*D#"D*D~A *D>Z !*D~A *D>Z *D~OG! MD *D~OG! }|!!   # *D!yOx#G= ' !~#fo"D*D"B!#~ !># !~#fo>o>g"@*B*B#"B6-ì !~#fo"@!~# !> w#w !#~ !!~#fo>o>g}|!:@:A#! !N#F*@!N#F *BR *B "B*B*@!N#F4 0 }*B>9L *B~'w*B!DyOx#G= ' !~#fo"D>2@2A!:@:A# *D*D~A *D>Z *D~OG! MDö *D~OGyw*@#"@*D#"Dw !~#foMD= !,~# ! :, :- *,i`", *. ' *,"D!~#fo",*DMD= !9*D*B*@i`!"@"B"D!9~w#~w#~w#~w+MD!9 _ #Z { !94Z ! 9~ +w>#w! 9N#Fx O>GP O>G! 9q#p! 9~ +w>#w! 9N#Fx O>GP*3 !9N#F#^#V#~#fo"kb"i`"OG!9!>w>#w!>w>#w!:w#w!N#F!N#F_ !~#ʻ!N#F!~w#~w!N#F!~w#~w~!~w#~wq!N#F!~w#~w6!!}|!N#F!~w#~w2ywx#w!>w>#w!~#fo~D!~#fo~|!~#fo> !~#fo~|î!~#fo>w#w!!~#fo!yOxG! !~#fo~!N#F!~w#~w!~#~!N#F!~w#~w6!~#fo> !~#fo~ !~w#~w baud. set to H, Serial port Multi I/O @ Can't find multi I/OBase must be on an 8 byte boundryDevice # out of range.Baud rate must be between 75-38400Usage: baud rate [device #] [base] .BAUD Version !~w#~w! *͜! *͜! !~#~!F!>>#! !!!N#F!~w#~wN#Fhy:K:! 2021:22:23!0+!>>#! !!!N#F!~w#~wN#Fh::)!>>#)!sFÈ!>>#4!!  O>G! 9q#p! 9N#FP ! 9q#p! 9N#FP ! 9q#p!9~_ /<à O!9~#fo) k !9~ /<_ O!9~#fo||g}o  !9~ /<_ O!9~#fo|g}o º MD!9q#p!! 9~+ ~ ! 9N#F ! 9~w#~w! 9~w+~w !9q#p&!!9OG!9N#F!9~#fo ## # +++ #!9MD!9~#~#~#~ !9~w#~w#~w#~w#~w#~w#~w#~w!9MD! 9  # # #x!9MD! 9  # # #!94x!9!9#~#~+++~#~#~#>#>+++>#~#~#~ #~{$>#># >#!9MD!9~#fo! 9MD!9~#foU!9N#F!97!9MD!9~#fo! 9MD!9~#foU!9N#F!97! 9MD!9~#fo#!9MD!9~#fo#U!9N#Fkb9$!9~#foN#F#N#F! 9~#foN#F#N#F!!9~+++ʓ~i!9MD!9  # # #!9~w#~w#~w#~w!9~w+~w+~w+~w:!9N#F!9~#~}|! 9&}!!9!9!9N#F###q#p+++q!9N#F#q#pMo  NAME baud - change serial baud rate on multi I/O SYNOPSIS baud baud-rate [device #] [multi I/O base] DESCRIPTION Baud is used to change the baud rate on a multi I/O or Decision I motherboard. Device # is the port number on the Multi I/O or decision motherboard in the range of one to three. Multi I/O base is the base address of the multi I/O. The default device # is one if not specified. The Multi I/O base is assumed to be 48. EXAMPLES To change serial port 1 on a multi I/O with a base of 48H to 9600 baud you would type: baud 9600 1 48 or baud 9600 To change the baud rate of the third serial port on multi I/O with a base of zero to 110 baud: baud 110 3 0 baud.doc 3/17/81 ldk eader paper tape reader in (result to reg-a) ; home move to track 00 ; ; (the following calls set-up the io parameter block for the ; mds, which is used to perform subsequent reads and writes) ; seldsk select disk given by reg-c (0,1,2...) ; settrk set track address (0,...76) for sub r/w ; setsec set sector address (1,...,26) ; setdma set subsequent dma address (initially 80h) ; ; read/write assume previous calls to set i/o parms ; read read track/sector to preset dma address ; write write track/sector from preset dma address ; ; jump vector for indiviual routines jmp boot wboote: jmp wboot jmp const jmp conin jmp conout jmp list jmp punch jmp reader jmp home jmp seldsk jmp settrk jmp setsec jmp setdma jmp read jmp write jmp listst ;list status jmp sectran ; maclib diskdef ;load the disk definition library disks 4 ;four disks diskdef 0,1,26,6,1024,243,64,64,offset diskdef 1,0 diskdef 2,0 diskdef 3,0 ; endef occurs at end of assembly ; ; end of conrror retries lxi b,cpmb ;set dma address to start of disk system call setdma mvi c,0 ;boot from drive 0 call seldsk mvi c,0 call settrk ;start with track 0 mvi c,2 ;start reading sector 2 call setsec ; ; read sectors, count nsects to zero pop b ;10-error count mvi b,nsects rdsec: ;read next sector push b ;save sector count call read jnz booterr ;retry if errors occur lhld iod ;increment dma address lxi d,128 ;sector size dad d ;incremented dma address in hl mov b,h mov c,l ;ready for call to set dma call setdma lda ios ;sector number just read cpi 26 ;read last sector? jc rd1 ; must be sector 26, zero and go to next track lda iot ;get track to register a inr a mov c,a ;ready for call call settrk xra a ;clear sector number rd1: inr a ;to next sector mov c,a ;ready for call call setsec pop b ;recall sector count dcr b ;done? jnz rdsec ; ; done with the load, reset default buffer address gocpm: ;(enter here from cold start boot) ; enable rstroller - independent code, the remaining subroutines ; are tailored to the particular operating environment, and must ; be altered for any system which differs from the intel mds. ; ; the following code assumes the mds monitor exists at 0f800h ; and uses the i/o subroutines within the monitor ; ; we also assume the mds system has four disk drives revrt equ 0fdh ;interrupt revert port intc equ 0fch ;interrupt mask port icon equ 0f3h ;interrupt control port inte equ 0111$1110b;enable rst 0(warm boot),rst 7 (mon) ; ; mds monitor equates mon80 equ 0f800h ;mds monitor rmon80 equ 0ff0fh ;restart mon80 (boot error) ci equ 0f803h ;console character to reg-a ri equ 0f806h ;reader in to reg-a co equ 0f809h ;console char from c to console out po equ 0f80ch ;punch char from c to punch device lo equ 0f80fh ;list from c to list device csts equ 0f812h ;console status 00/ff to register a ; ; disk ports and commands base equ 78h ;base of disk command io ports dstat equ base ;disk status (input) rtypt0 and rst7 di mvi a,12h ;initialize command out revrt xra a out intc ;cleared mvi a,inte ;rst0 and rst7 bits on out intc xra a out icon ;interrupt control ; ; set default buffer address to 80h lxi b,buff call setdma ; ; reset monitor entry points mvi a,jmp sta 0 lxi h,wboote shld 1 ;jmp wboot at location 00 sta 5 lxi h,bdos shld 6 ;jmp bdos at location 5 sta 7*8 ;jmp to mon80 (may have been changed) lxi h,mon80 shld 7*8+1 ; leave iobyte set ; previously selected disk was b, send parameter to cpm lda cdisk ;last logged disk number mov c,a ;send to ccp to log it in ei jmp cpmb ; ; error condition occurred, print message and retry booterr: pop b ;recall counts dcr c jz booter0 ; try again push b jmp wboot0 ; booter0: ; otherwise too many retries lxi h,bootmsg call prmsg jmp rmon80 ;mds hardware monitor ; bootmsg: db '?boot',0 ; ; const: ;console status to reg-a ; (exactly the same as mds call) jmp csts ; conin: ;console c; MDS-800 I/O Drivers for CP/M 2.0 ; (four drive single density version) ; ; Version 2.0 August, 1979 ; vers equ 20 ;version 2.0 ; ; Copyright (c) 1979 ; Digital Research ; Box 579, Pacific Grove ; California, 93950 ; org 4A00h ;base of bios in 20K system cpmb equ 3400h ;base of cpm CCP bdos equ 3C06H ;base of bdos in 20K system cpml equ $-cpmb ;length (in bytes) of cpm system nsects equ cpml/128;number of sectors to load offset equ 2 ;number of disk tracks used by cp/m cdisk equ 0004h ;address of last logged disk buff equ 0080h ;default buffer address retry equ 10 ;max retries on disk i/o before error ; ; perform following functions ; boot cold start ; wboot warm start (save i/o byte) ; (boot and wboot are the same for mds) ; const console status ; reg-a = 00 if no character ready ; reg-a = ff if character ready ; conin console character in (result in reg-a) ; conout console character out (char in reg-c) ; list list out (char in reg-c) ; punch punch out (char in reg-c) ; re equ base+1 ;result type (input) rbyte equ base+3 ;result byte (input) ; ilow equ base+1 ;iopb low address (output) ihigh equ base+2 ;iopb high address (output) ; readf equ 4h ;read function writf equ 6h ;write function recal equ 3h ;recalibrate drive iordy equ 4h ;i/o finished mask cr equ 0dh ;carriage return lf equ 0ah ;line feed ; signon: ;signon message: xxk cp/m vers y.y db cr,lf,lf db '20' ;sample memory size db 'k CP/M vers ' db vers/10+'0','.',vers mod 10+'0' db cr,lf,0 ; boot: ;print signon message and go to ccp ; (note: mds boot initialized iobyte at 0003h) lxi sp,buff+80h lxi h,signon call prmsg ;print message xra a ;clear accumulator sta cdisk ;set initially to disk a jmp gocpm ;go to cp/m ; ; wboot:; loader on track 0, sector 1, which will be skipped for warm ; read cp/m from disk - assuming there is a 128 byte cold start ; start. ; lxi sp,buff ;using dma - thus 80 thru ff ok for stack ; mvi c,retry ;max retries push b wboot0: ;enter here on e haracter to reg-a call ci ani 7fh ;remove parity bit ret ; conout: ;console character from c to console out jmp co ; list: ;list device out ; (exactly the same as mds call) jmp lo ; listst: ;return list status xra a ret ;always not ready ; punch: ;punch device out ; (exactly the same as mds call) jmp po ; reader: ;reader character in to reg-a ; (exactly the same as mds call) jmp ri ; home: ;move to home position ; treat as track 00 seek mvi c,0 jmp settrk ; seldsk: ;select disk given by register c lxi h,0000h ;return 0000 if error mov a,c cpi ndisks ;too large? rnc ;leave HL = 0000 ; ani 10b ;00 00 for drive 0,1 and 10 10 for 2,3 sta dbank ;to select drive bank mov a,c ;00, 01, 10, 11 ani 1b ;mds has 0,1 at 78, 2,3 at 88 ora a ;result 00? jz setdrive mvi a,00110000b ;selects drive 1 in bank setdrive: mov b,a ;save the function lxi h,iof ;io function mov a,m ani 11001111b ;mask out disk number ora b ;mask in new disk number mov m,aontroller mov a,b out ihigh ;high address jmp wait0 ;to wait for complete ; iodr1: ;drive bank 1 out ilow+10h ;88 for drive bank 10 mov a,b out ihigh+10h ; wait0: call instat ;wait for completion ani iordy ;ready? jz wait0 ; ; check io completion ok call intype ;must be io complete (00) unlinked ; 00 unlinked i/o complete, 01 linked i/o complete ; 10 disk status changed 11 (not used) cpi 10b ;ready status change? jz wready ; ; must be 00 in the accumulator ora a jnz werror ;some other condition, retry ; ; check i/o error bits call inbyte ral jc wready ;unit not ready rar ani 11111110b ;any other errors? jnz werror ; ; read or write is ok, accumulator contains zero ret ; wready: ;not ready, treat as error for now call inbyte ;clear result byte jmp trycount ; werror: ;return hardware malfunction (crc, track, seek, etc.) ; the mds controller has returned a bit in each position ; of the accumulator, corresponding to the conditions: ***************************************************************** * * * Boot program for HDDMA controller. * * * ***************************************************************** ; ; Define normal Cbios stuff ; alf equ 'J'-64 ;A line feed acr equ 'M'-64 ;A carraige return maxhd equ 1 ;Number of hard disk drives hdspt equ 9 ;Number of sectors per track retries equ 10 ;Number of disk retries before error bdos equ 5 ;Bdos entry point wmess equ 9 ;Write a message org 0100h buffer jmp start ds 1021 ;Space for boot loader start lxi h,0 ;65536 retries again push h call hdreset ;Reset controller call hdstat ;Check drive status pop h ora a jnz ok ;The controller has responded lxi d,nocon ;Missing controller message jmp errpr ok ani dready ;Check for drive ready jz ready dcx h ;Bump retry count mov a,h ora l jnz again lxi d,nodrv ;Drive does not respond jmp errpr ready mvi c,0 ;Select drive 0 call hddrv call hdhome ;R ;save it in iopb mov l,c mvi h,0 ;HL=disk number dad h ;*2 dad h ;*4 dad h ;*8 dad h ;*16 lxi d,dpbase dad d ;HL=disk header table address ret ; ; settrk: ;set track address given by c lxi h,iot mov m,c ret ; setsec: ;set sector number given by c lxi h,ios mov m,c ret sectran: ;translate sector bc using table at de mvi b,0 ;double precision sector number in BC xchg ;translate table address to HL dad b ;translate(sector) address mov a,m ;translated sector number to A sta ios mov l,a ;return sector number in L ret ; setdma: ;set dma address given by regs b,c mov l,c mov h,b shld iod ret ; read: ;read next disk record (assuming disk/trk/sec/dma set) mvi c,readf ;set to read function call setfunc call waitio ;perform read function ret ;may have error set in reg-a ; ; write: ;disk write function mvi c,writf call setfunc ;set to write function call waitio ret ;may have error set ; ; ; utility subroutines prmsg: ;print messag ; 0 - deleted data (accepted as ok above) ; 1 - crc error ; 2 - seek error ; 3 - address error (hardware malfunction) ; 4 - data over/under flow (hardware malfunction) ; 5 - write protect (treated as not ready) ; 6 - write error (hardware malfunction) ; 7 - not ready ; (accumulator bits are numbered 7 6 5 4 3 2 1 0) ; ; it may be useful to filter out the various conditions, ; but we will get a permanent error message if it is not ; recoverable. in any case, the not ready condition is ; treated as a separate condition for later improvement trycount: ; register c contains retry count, decrement 'til zero dcr c jnz rewait ;for another try ; ; cannot recover from error mvi a,1 ;error code ret ; ; intype, inbyte, instat read drive bank 00 or 10 intype: lda dbank ora a jnz intyp1 ;skip to bank 10 in rtype ret intyp1: in rtype+10h ;78 for 0,1 88 for 2,3 ret ; inbyte: lda dbank ora a jnz inbyt1 in rbyte ret inbyt1: in rbyte+10h ret ; instat: lda dbank ora a ecalibrate mvi c,1 ;Sector 1 call hdsec lxi b,buffer ;DMA address call hddma mvi c,retries ;Number of read retries retry push b call hdread pop b jnc 0100h ;Jump to boot loader if no error dcr c ;Bump retry count jnz retry lxi d,nosec errpr mvi c,wmess ;Print string command call bdos jmp 0 ;Return to CP/M nocon db acr, alf, 'No HDDMA controller present.', acr, alf, '$' nodrv db acr, alf, 'Drive not ready.', acr, alf, '$' nosec db acr, alf, 'Read error, track 0 sector 0.', acr, alf, '$' ***************************************************************** * * * The follwing equates are for the HDDMA hard disk controller * * * ***************************************************************** cyl equ 153 ;Specifications for a Seagate Technology 506 heads equ 4 ;Number of heads per cylinder precomp equ 64 ;Cylinder to start write precomensation lowcurr equ 128 ;Cylinder to start low current stepdly equ 30 ;Step delay (0-12.7 milliseconds) headde at h,l to 0 mov a,m ora a ;zero? rz ; more to print push h mov c,a call conout pop h inx h jmp prmsg ; setfunc: ; set function for next i/o (command in reg-c) lxi h,iof ;io function address mov a,m ;get it to accumulator for masking ani 11111000b ;remove previous command ora c ;set to new command mov m,a ;replaced in iopb ; the mds-800 controller req's disk bank bit in sector byte ; mask the bit from the current i/o function ani 00100000b ;mask the disk select bit lxi h,ios ;address the sector select byte ora m ;select proper disk bank mov m,a ;set disk select bit on/off ret ; waitio: mvi c,retry ;max retries before perm error rewait: ; start the i/o function and wait for completion call intype ;in rtype call inbyte ;clears the controller ; lda dbank ;set bank flags ora a ;zero if drive 0,1 and nz if 2,3 mvi a,iopb and 0ffh ;low address for iopb mvi b,iopb shr 8 ;high address for iopb jnz iodr1 ;drive bank 1? out ilow ;low address to c jnz insta1 in dstat ret insta1: in dstat+10h ret ; ; ; ; data areas (must be in ram) dbank: db 0 ;disk bank 00 if drive 0,1 ; 10 if drive 2,3 iopb: ;io parameter block db 80h ;normal i/o operation iof: db readf ;io function, initial read ion: db 1 ;number of sectors to read iot: db offset ;track number ios: db 1 ;sector number iod: dw buff ;io address ; ; ; define ram areas for bdos operation endef end  ly equ 20 ;Settle delay (0-255 milliseconds) sectsiz equ 7 ;Sector size code (must be 3 for this Cbios) ; 0 = 128 byte sectors ; 1 = 256 byte sectors ; 3 = 512 byte sectors (default) ; 7 = 1024 byte sectors ; f = 2048 byte sectors ;Define controller commands dmaread equ 0 ;Read sector dmawrit equ 1 ;Write sector dmarhed equ 2 ;Find a sector dmawhed equ 3 ;Write headers (format a track) dmalcon equ 4 ;Load disk parameters dmassta equ 5 ;Sense disk drive status dmanoop equ 6 ;Null controller operation reset equ 54h ;Reset controller attn equ 55h ;Send a controller attention chan equ 50h ;Default channel address stepout equ 10h ;Step direction out stepin equ 0 ;Step direction in band1 equ 40h ;No precomp, high current band2 equ 0c0h ;Precomp, high current band3 equ 80h ;precomp, low current track0 equ 1 ;Track zero status wfault equ 2 ;Write fault from drive dready equ 4 ;Drive ready sekcmp equ 8 ;Seek complete *******************spt ;Subtract a tracks worth of sectors rc ;Return if all done inr c ;Bump to next head jmp divsptx hdread mvi a,dmaread ;Load disk read command jmp hdprep hdwrite mvi a,dmawrit ;Load disk write command hdprep sta dmaop ;Save command channel op code lda dmarg0 ;Get cylinder address mvi c,band1 ;Handle write precompensation and cpi precomp ; low current flags jc hdpreps ;cylinder = (0 - precomp) mvi c,band2 cpi lowcurr jc hdpreps mvi c,band3 ;cylinder > low_current hdpreps lda hdhead ;Load head address sta dmarg2 cma ;Negative logic for the controller ani 7 ;3 bits of head select rlc ;Shove over to bits 2 - 4 rlc ora c ;Add on low current and precomp bits mov c,a lda hddrive ;Load drive address ora c ;Slap in drive bits sta dmasel1 ;Save in command channel head select lda hdsectr ;Load sector address sta dmarg3 jmp hdissue ;Execute command hdreset out reset ;Send reset pulse to controller lxi h,dmachan ;Address of command********************************************** * * * Th followin ar th lowes leve driver fo th HDDM * * controller. * * * ***************************************************************** hddrv lda hddrive ;Get drive cmp c ;Check to see if drive is already selected jnz hddrv2 ora a ;Return carry reset if ok hdside ret hddrv2 mov a,c ;Get selected drive ani 3 ;Mask for lower two bits mov c,a sta hddrive ;Save new selected drive sta dmasel0 ;Save in command channel drive select hdsel mvi a,dmanoop sta dmaop ;Set up operation code jmp hdissue ;Execute disk command hdstat mvi a,dmassta ;Sense status operation code sta dmaop jmp hdissue ;Execute disk command hdhome call drvptr ;Get pointer to current cylinder number mvi m,0ffh ;Fake at cyl 255 for max head travel mvi c,0 ;Seek to cylinder 0 hdtrk call drvptr ;Get track pointer mov e,m ;Get old track number mov m,c ;Store new track number mov l,c ;Build cylinder wor channel shld chan ;Default channel address xra a sta chan+2 ;Clear extended address byte lxi h,1000h ;Delay for reset complete hdrl dcx h mov a,h ora l jnz hdrl lxi h,dmarg1 ;Load arguments mvi m,stepdly ;Load step delay inx h mvi m,headdly ;Head settle delay inx h mvi m,sectsiz ;Sector size code inx h mvi m,dmalcon ;Load constants command hdissue lxi h,dmastat ;Status byte mvi m,0 out attn ;Start controller lxi d,0 ;Time out counter mov b,e ;Controller busy status hdiloop mov a,m ;Get status ora a ;Set up CPU flags rm ;Return no error (carry reset) stc rnz ;Return error status xthl ;Waste some ime xthl xthl xthl dcx d ;Bump timeout counter mov a,d ora e jnz hdiloop ;Loop if still busy stc ;Set error flag ret drvptr lhld hddrive ;Get currently select drives track address xchg mvi d,0 lxi h,drives dad d ;Offset into track table ret drives equ $ ;Collection of track addresses rept maxhd db 0ffh ;Ini!^RJ&+|sJͪ  $ ;  No HDDMA controller present. $ Drive not ready. $ Read error, track 0 sector 0. $:³yO22>2Á>2Á͝6͝^qi&"yo:}/2́!"`i"y= 2y2 >+>2:@@AA:2/O:2:2ÁT!"P2R!+|m!6#6#6#6!6UC~7zŒ7*!d mvi h,0 shld dmarg0 ;Set command channel cylinder number mov a,c ;Load new track address sub e ;Subtract from old track rz ;Already on track mov l,a ;Set up step count lda hddrive ;Get drive number jnc stepi ;Skip if stepping in ori stepout ;Tack on step out bit push psw ;Save for a while mov a,l ;Complement track count cma inr a ;Twos complement that is mov l,a pop psw stepi sta dmasel0 ;Load command channel, drive select shld dmastep ;Load command channel, number of tracks to step mvi a,dmanoop ;No-operation command for the channel sta dmaop call hdissue ;Step to proper track lxi h,0 ;Clear step counter shld dmastep ret hddma mov h,b ;Set DMA address mov l,c shld dmadma ret hdsec mov a,c ;Load sector number dcr a ;Range is actaully 0-16 call divspt ;Figure out head number -> (c) adi hdspt ;Make sector number sta hdsectr mov a,c sta hdhead ;Save head number ret divspt mvi c,0 ;Clear head counter divsptx sui hdtialize to (way out on the end of the disk) endm db 0ffh hddrive db 0ffh ;Currently selected drive hdhead db 0 ;Currently selected head hdsectr db 0 ;Currently selected sector dmachan equ $ ;Command channel area dmasel0 db 0 ;Drive select dmastep dw 0 ;Relative step counter dmasel1 db 0 ;Head select dmadma dw 0 ;DMA address db 0 ;Extended address dmarg0 db 0 ;First argument dmarg1 db 0 ;Second argument dmarg2 db 0 ;Third argument dmarg3 db 0 ;Fourth argument dmaop db 0 ;Operation code dmastat db 0 ;Controller status byte dmalnk dw dmachan ;Link address to next command channel db 0 ;extended address end  ***************************************************************** * * * Morrow Designs CBIOS for CP/M Ver 2.2. * * * * This CBIOS can be configured to run with the following * * devices. The disks may be configured to run with any or * * all of the disk systems. The logical order of the disks * * can be set to any order. * * * * Disk systems: * * HDC3 10, 20 and 26 megabyte hard disks. * * HDDMA 5, 16, 40 megabyte hard disk systems. * * DJDMA floppy controller with 8 and 5 1/4 inch disks. * * DJ 2D/B floppy controller with 8 inch disks. * * * * Console I/O: * * Disk Jockey 2D/B serial. * * Disk Jockey DMA serial. * * Multi I/O serial. * * Decision I serial. * * * * Printer I/O: * * Multi I/O serial with handshaking. * * Multi I/O Diablo 1620 simulator for the Hytype II. * * Multi I/O Centronics parallel. * * * * Note: Floppy systems diskette (drive A:) has to have 1024 * * byte sectors in orMemorex ;HDDMA controller disk drives. Set only one M5 equ 1 ;Seagate M506 M16A equ 0 ;Ampex DF516 M16C equ 0 ;CMI 5616 M19 equ 0 ;CMI 5619 M40 equ 0 ;Quantum Q2040 wmdrive equ 0 ;Device to warm boot from. This is the ; CP/M logical drive number. badsiz equ 32 ;Number of badmap entries ***************************************************************** * * * Since most hard disk drives hold more than 8 megabytes we * * partition the drive. We partition our drives using two * * different formulas. * * * * One is the so called 'standard partitioning' where we try * * to create as many 8 megabyte partitions as possible plus * * a small partition to take up the slack on the end of the * * drive. * * * * Another way the drives are partitioned is the so called * * 'even partition' formula. This means that the drive is * * split into equale sized partitions with the only * * restriction being that no partition be over 8 megabytes * * iprinter. * * For an explanation of the values look for the deflst * * table. * * * ***************************************************************** lsttyp equ 2 lbaud equ 96 ***************************************************************** * * * The next equate determines if you have a Multi I/O Rev 3 * * or a Decision I mother board for parallel i/o. If are not * * using either of these boards then you need not worry about * * this equate. If you are using a Multi I/O rev. other than * * 3.x then you should set multr3 to 0. * * * ***************************************************************** multr3 equ 0 ;0 = Decision, 1 = Multi I/O if contyp eq 2 congrp equ 1 ;Cosole port (1 = p1, 2 = p2, 3 = p3) endif if lsttyp ge 2 lstgrp equ 3 ;Printer port (1 = p1, 2 = p2, 3 = p3) endif ***************************************************************** * * * The following equates are internal to the CBIOS. * * * ***********der for the cold and warm boot * * loaders to work. Be sure to format all new * * system diskettes with 1024 byte sectors. The * * system diskette can be either single or double * * sided. The sector size on normal (non A: drive) * * diskettes is not restricted. Thus if you have a * * diskette with software that is supposed to run on * * the A: drive then you should mount the diskette * * in the B: drive and then PIP it over to a 1024 * * byte sector disktte. * * * * Written by Les Kent and Marc Kupper 3/4/82 * * * ***************************************************************** title 'CBIOS Revision E for CP/M Version 2.2 - March 4, 1982' revnum equ 52 ;Cbios revision number 5.x = E cpmrev equ 22 ;CP/M revision number 2.2 debug equ 0 ;Set for debugging mode ***************************************************************** * * * The following is set to the memory size of the CP/M the CBIOS * * is being created for. * * * ***n length. * * * * All hard disk drives shipped from Morrow Designs are * * partitioned using the standard partition formula. If the * * user wishes to implement even partitioning then he/she * * must set hdpart or mwpart to the number of partitions * * desired. * * * ***************************************************************** hdpart equ 0 ;Set to number of non standard partitions mwpart equ 0 ;Set to number of non standard partitions ***************************************************************** * * * The following equates define the console and printer * * environments. * * * ***************************************************************** ***************************************************************** * * * Define the console driver to be used. * * * * contyp is: 0 Nothing, used for patching to PROM's. * * 1 Provide for 128 bytes of patch space. * * 2 Multi I/O or Decision I driver. * * 3 2D/B ****************************************************** m10 equ m10f or m10m if hdpart ne 0 ;Use non standard partitions hdlog equ hdpart else hdlog equ m10*2+m20*3+m26*3 ;Logical disks per drive for HDC3 endif if mwpart ne 0 ;Use non standard partitions mwlog equ mwpart else mwlog equ m5*1+m16a*2+m16c*2+m19*2+m40*5 ;Logical disks per drive endif hdc3 equ m26 or m20 or m10 ;HDC3 controller fujitsu equ m20 or m10f hdrev equ 26*m26+20*m20+10*m10 ;Hard disk type hdspt equ 32*m26+21*m20+21*m10 ;Sectors per track hdma equ m5 or m16a or m16c or m19 or m40 ;HD DMA controller mwrev equ 05*m5+16*m16a+16*m16c+19*m19+40*m40 ;Hard disk type mwspt equ 9*m5+9*m16a+9*m16c+9*m19+9*m40 ;Sectors per track maxlog equ (maxhd*hdlog)+(maxmw*mwlog)+maxfd+maxdm+maxmf ***************************************************************** * * * The folowing equates will define the Decision I mother * * board I/O or the Multi I/O environments if needed. * * * ****************************************************************************** msize equ 48 ;Memory size of target CP/M biosln equ 1900h ;BIOS length. Also in ABOOT&.ASM ***************************************************************** * * * The following equates set up the disk systems to be included * * along with the types of drives and the logical order of the * * drives. * * * ***************************************************************** maxhd equ 0 ;Set to number of HDC3 hard disk drives maxmw equ 2 ;Set to number of HDDMA hard disks maxfd equ 2 ;Set to number of 2D/B floppies maxdm equ 2 ;Set to number of DJ DMA floppies 8 inch maxmf equ 2 ;Set to number of DJ DMA floppies 5 1/4 inch hdorder equ 0 ;Set the order of logical drives ELSE 0 if mworder equ 1 ; not included. fdorder equ 4 dmorder equ 2 mforder equ 3 ;HDC3 controller disk drives. Set only one M26 equ 0 ;Shugart SA4000 M20 equ 0 ;Fujitsu M2302B M10F equ 0 ;Fujitsu M2301B M10M equ 0 ;driver. * * 4 DJDMA serial port * * * * Set cbaud to the divisor latch value for the console. * * For an explanation of the values look for the defcon * * table. * * * ***************************************************************** contyp equ 2 cbaud equ 12 ***************************************************************** * * * Define the printer driver to be used. * * * * lsttyp is: 0 Nothing, used for patching to PROM's. * * 1 Provide for 128 bytes of patch space. * * 2 Multi I/O serial, no protocol. * * 3 Multi I/O serial, CTS protocol. * * 4 Multi I/O serial, DSR protocol. * * 5 Multi I/O serial, Xon / Xoff protocol. * * 6 Multi I/O parallel, Centronics. * * 7 Multi I/O parallel, Diablo HyType II. * * * * Note: The Decision board is functionally identical to the * * Multi I/O board for printer I/O. Selections 2 - 6 * * will work on the Decision I. * * * * Set pbaud to the divisor latch value for the  ************************************************* multio equ (contyp eq 2) or (lsttyp ge 2) ;Multi I/O board used? if multio ;Define Multi I/O environment mbase equ 48h ;Base address of Multi I/O or Decision I grpsel equ mbase+7 ;Group select port dll equ mbase ;Divisor (lsb) dlm equ mbase+1 ;Divisor (msb) ier equ mbase+1 ;Interupt enable register clk equ mbase+2 ;WB14 printer select port lcr equ mbase+3 ;Line control register mcr equ mbase+4 lsr equ mbase+5 ;Line status register msr equ mbase+6 rbr equ mbase ;Read data buffer thr equ mbase ;Tranmitter data buffer dlab equ 80h ;Divisor latch access bit thre equ 20h ;Status line THRE bit cts equ 10h ;Clear to send dsr equ 20h ;Data set ready dr equ 1 ;Line status DR bit wls0 equ 1 ;Word length select bit 0 wls1 equ 2 ;Word length select bit 1 for 8 bit word stb equ 4 ;Stop bit count - 2 stop bits ; Define multi I/O ports addresses for group zero gzero equ 0 daisy0 equ mbase ;Daisy input ports daisy1 equ mb** * * * CP/M system equates. * * * ***************************************************************** ccpln equ 800h bdosln equ 0e00h size equ (msize*1024) ccp equ size-(biosln+ccpln+bdosln) bdos equ ccp+ccpln bios equ ccp+ccpln+bdosln offsetc equ 2100h-bios ;Offset for sysgen if debug dbgtmp set offsetc ;DDT offset ! dbgtmp set ccp ;CCP address ! dbgtmp set bdos ;BDOS address ! dbgtmp set bios ;Cbios address ! endif cdisk equ 4 ;Address of last logged disk buff equ 80h ;Default buffer address tpa equ 100h ;Transient memory intioby equ 0 ;Initial IOBYTE iobyte equ 3 ;IOBYTE location wbot equ 0 ;Warm boot jump address entry equ 5 ;BDOS entry jump address ***************************************************************** * * * The following are internal Cbios equates. Most are misc. * * constants. * * * ***************************************************************** retries equ 10 ;.sel1 equ 2 ;Drive select, Return DPH d.sel2 equ 3 ;Drive select d.home equ 4 ;Home drive d.strk equ 5 ;Set track d.ssec equ 6 ;Set sector d.sdma equ 7 ;Set DMA address d.read equ 8 ;Read a physical sector d.write equ 9 ;Write a physical sector d.bad equ 10 ;Return pointer to bad sector info ***************************************************************** * * * The jump table below must remain in the same order, the * * routines may be changed, but the function executed must be * * the same. * * * ***************************************************************** org bios ;Cbios starting address jmp cboot ;Cold boot entry point wboote: jmp wboot ;Warm boot entry point if contyp ne 0 const: jmp cstty ;Console status routine cin: jmp ciflsh ;Console input cout: jmp cotty ;Console output else jmp $ ;Console status routine PROM pointer cin: jmp $ ;Console input PROM pointer cout: jmp $ ;Console output PROM pointer endif if lsttyp ne 0 jmpase+1 sensesw equ mbase+1 ;Sense switches if multr3 eq 0 ;Daisy output ports are different daisi0 equ mbase ; for Decision I and Multi I/O. daisi1 equ mbase+1 ;These two are the Decision I ports else daisi0 equ mbase+1 ; and these are the Multi I/O's. daisi1 equ mbase endif ; Define daisy 0 status input bits ribbon equ 01h ;End of ribbon paper equ 02h ;Paper out cover equ 04h ;Cover open pfrdy equ 08h ;Paper feed ready crrdy equ 10h ;Carriage ready pwrdy equ 20h ;Print wheel ready check equ 40h ;Printer check (error) ready equ 80h ;Printer ready ; Define daisy 0 status input bits for Diablo HyType II driver crstrd equ 1020h ;Carriage ready pfstrd equ 810h ;Paper feed ready pwstrd equ 2040h ;Print wheel ready ; Define daisy 0 output bits d9 equ 01h ;Data bit 9 d10 equ 02h ;Data bit 10 d11 equ 04h ;Data bit 11 d12 equ 08h ;Data bit 12 pfstb equ 10h ;Paper feed strobe crstb equ 20h ;Carriage strobe pwstb equ 40h ;Print wheel strobe rest Max retries on disk i/o before error clear equ 'Z'-64 ;Clear screen on an ADM 3 anul equ 0 ;Null aetx equ 'C'-64 ;ETX character aack equ 'F'-64 ;ACK character abel equ 'G'-64 ;Bell abs equ 'H'-64 ;Back Space aht equ 'I'-64 ;Horizontal tab alf equ 'J'-64 ;Line feed avt equ 'K'-64 ;Vertical tab aff equ 'L'-64 ;Form Feed acr equ 'M'-64 ;Carriage return xon equ 'Q'-64 ;Xon character xoff equ 'S'-64 ;Xoff character aesc equ 1bh ;Escape character ars equ 1eh ;RS character aus equ 1fh ;US character asp equ ' ' ;Space adel equ 7fh ;Delete ***************************************************************** * * * The following are the macros used in generating the DPH, DPB * * and allocation tables. * * * ***************************************************************** dpbgen macro nam,log,dspt,dbsh,dblm,dexm,ddsm,ddrm,dal0,dal1,dcks,doff dpb&nam&log equ $ dw dspt db dbsh db dblm db dexm dw ddsm dw ddrm db dal0 db dal1 dw dcks dw do list ;List device output else jmp cout ;List device output endif jmp punch ;Punch device output jmp reader ;Reader device input jmp home ;Home drive jmp setdrv ;Select disk jmp settrk ;Set track jmp setsec ;Set sector jmp setdma ;Set DMA address jmp read ;Read the disk jmp write ;Write the disk if lsttyp ne 0 jmp listst ;List device status else jmp $ ;List device status endif jmp sectran ;Sector translation if maxfd ne 0 jmp fdsel ;Hookup for SINGLE.COM program else jmp donop endif ***************************************************************** * * * Immediatly following the SINGLE hookup jump we have a * * series of pointers that point to various internal tables. * * At the start of each of these tables we have a revision * * byte and a length byte. The revision byte is the * * current revision number for that particular structure and * * the length byte is the length of that structure. This * * length does not iequ 80h ;Printer restore (Ribbon lift on Multi I/O) ; Define clock select bits rlift equ 40h ;Ribbon lift pselect equ 80h ;Select (Not used by Diablo) ; Define Modem Control Register bits dtrenb equ 1 ;DTR enable rtsenb equ 2 ;RTS enable ; Define group select bits s0 equ 01h ;Group number (0-3) s1 equ 02h smask equ 03h bank equ 04h enint equ 08h restor equ 10h ;Printer restore on Multi I/O denable equ 20h ;Driver enable on Multi I/O ; Define special constants for the HyTyp II driver cperi equ 10 ;Default to 10 characters per inch lperi equ 6 ;Default lines per inch hinc equ 120 ;Horizontal increments per inch vinc equ 48 ;Vertical increments per inch numtabs equ 160 ;Number of horizontal tabs maxchrs equ 1024 ;Maximum number of printer characters to queue maxrgt equ 1584 ;Maximum carriage position dfrmln equ 110 ;Forms length times 10 autolf equ 0 ;Default to no Auto line feed. endif ***************************************************************ff db 0 endm dphgen macro nam,log,dpb1,dpb2 dph&nam&log equ $ dw 0 dw 0,0,0 dw dirbuf dw &dpb1&dpb2 dw csv&nam&log dw alv&nam&log endm alloc macro nam,log,al,cs csv&nam&log: ds cs alv&nam&log: ds al endm ***************************************************************** * * * The following marco is used in generating the logical order * * of the CP/M drives. * * * ***************************************************************** order macro num if num eq hdorder dw hddst endif if num eq mworder dw mwdst endif if num eq fdorder dw fddst endif if num eq dmorder dw dmdst endif if num eq mforder dw mfdst endif endm ***************************************************************** * * * The folloing are offset numbers of Device Specification * * Tables. * * * ***************************************************************** d.wboot equ 0 ;Warm boot d.stran equ 1 ;Sector translation dnclude the revision byte nor the length * * byte. * * * * The pointers defined so far are as follows: * * * * 1) This points to the drive configuration table. * * * * 2) This points to the I/O configuration bytes for * * the serial drivers. Eg, the console, printer, * * reader, and punch devices. * * * * 3) This will be a null (0) pointer. It marks the * * end of the table. * * * ***************************************************************** dw drconf ;Drive configuration table pointer dw ioconf ;I/O configuration table pointer dw 0 ***************************************************************** * * * Drive configuration table. * * * ***************************************************************** drconf: db 0 ;Revision 0 structure db 32 ;32 bytes long now ***************************************************************** * * * The following is the table of pointers to the Device group ;Get group byte * * ori congrp ;Select the console port * * out grpsel ;Select the group * * * * ;Modify a bit in the group byte * * lda group ;Get group byte * * ori bank ;Set the bank bit * * sta group ;Save new group setting * * ori group2 ;Select second serial port * * out grpsel ;Select the desired group * * * * Note: You should not set the group bits themselves in * * the group byte. * * * ***************************************************************** group: db 0 ;Group byte ***************************************************************** * * * Console driver routines. * * * * Routine used depends on the value of contyp. Possible * * contyp values are listed as follows: * * * * contyp is: 0 Nothing, used for patching to PROM's. * * 1 Provide for 128 bytes of patch space. * * 2 Multi I/O or Decision I driver. * * 3 2D/B driver. * * 4 DJDMA serial port * * * ***************************** ***************************************************************** * * * Due to its length, the tinit routine driver is below the * * cboot routine. * * * ***************************************************************** ***************************************************************** * * * Read a character from the serial port. * * * ***************************************************************** citty: lda group ;Get group byte ori congrp ;Select console out grpsel conin1: in lsr ;Read status register ani dr ;Wait till character ready jz conin1 in rbr ;Read character ani 7fh ;Strip parity ret ***************************************************************** * * * Output a character to serial port. * * * ***************************************************************** cotty: lda group ;Get group byte ori congrp ;Select console out grpsel conout1:in lsr ;Read status ani thre ; * * Specification Tables. The order of this table defines * * the logical order of the CP/M drives. * * * ***************************************************************** dsttab: equ $ dn set 1 rept 16 order %dn dn set dn+1 endm ***************************************************************** * * * I/O configuration table. * * * ***************************************************************** ioconf: db 0 ;Revision 0 structure db 5 ;5 bytes long now ***************************************************************** * * * The following two words define the default baud rate for * * the console and the LST: devices. These words must * * immediatly follow the Cbios jump table so that the user * * can easly modify them and that they will also be used in * * the future by Morrow Designs software. * * * * The following is a list of possible baud rates and the * * value needed for the defcon or deflst words. * * *************************************************** ciflsh: call flush ;Flush disk buffers on input jmp citty ***************************************************************** * * * contyp: 1 Blank space for console driver * * * * Note: If the user plans to utilize this space then the * * one time code such as tinit{sould be placed just below * * the cboot routine. This space (belowe cboot) is recyled * * for use as a disk buffer after cboot is done. * * * ***************************************************************** if contyp eq 1 tinit equ $ ;Make it easy to find this place cotty equ $ citty equ $ cstty equ $ ret ds 127 endif ;Blank space ***************************************************************** * * * contyp: 2 Multi I/O or Decision I console driver * * * ***************************************************************** if contyp eq 2 ***************************************************************** * Wait till transmitter buffer empty jz conout1 mov a,c ;Character is in (c) out thr ;Output to transmitter buffer ret ***************************************************************** * * * Return serial port status. Returns zero if character is not * * ready to be read. Else returns 255 if ready. * * * ***************************************************************** cstty: lda group ;Get group byte ori congrp ;Select console out grpsel in lsr ;Read status register ani dr rz ;No charactter ready mvi a,0ffh ;Character ready ret endif ;Multi I/O or Decision I ***************************************************************** * * * contyp: 3 2DB console driver * * * ***************************************************************** if contyp eq 3 cotty: jmp fdcout ;Console output citty: jmp fdcin ;Console input cstty: call fdtstat ;Console status mvi a,0ffh rz inr a ret endif ;2DB ************ * Baud rate defcon/deflst Baud rate defcon/deflst * * 50 2304 2000 58 * * 75 1536 2400 48 * * 110 1047 3600 32 * * 134.5 857 4800 24 * * 150 768 7200 16 * * 300 384 9600 12 * * 600 192 19200 6 * * 1200 96 38400 3 * * 1800 64 56000 2 * * * ***************************************************************** defcon: dw cbaud ;Console baud rate deflst: dw lbaud ;Printer baud rate ***************************************************************** * * * The next byte is to make sure that the group select byte * * on the Mult I/O or Decsion I stays consistant throughout * * the Cbios. Only the group bits themselves (bits 0 and 1) * * should be changed as you output to the group port. If * * you modify one of the other bits (such a driver-enable) * * then you should modify the same bit in the group byte * * provided. Example: * * * * ;Select console group * * lda  * * This driver on cold boot will inspect bits 1-3 of the sense * * switches. If the value found is in the range 0-6 then the * * console baud rate will be taken from the rate table. * * Otherwise the current divisor latch value will be checked. * * If the divisor seems to be ok then no action will be taken * * as far as the baud rate setting goes. If the divisor is not * * ok then the baud rate will be set from the DEFCON word * * which is found just below the regular Cbios jump table. The * * standard divisor table is given below. * * * * Sense switch: 123 (0 = off, 1 = on) * * 000 = 110 * * 001 = 300 * * 010 = 1200 * * 011 = 2400 * * 100 = 4800 * * 101 = 9600 * * 110 = 19200 * * defcon = 9600 * * * * Note: If you are compiling with multr3 (a Multi I/O) then * * the switches will not be available so the baud rate * * will be taken from defcon. * * * ******************************************************************************************************** * * * contyp: 4 DJDMA console driver * * * ***************************************************************** if contyp eq 4 cotty: lxi h,dmchan mvi m,serout ;Command for serial output inx h mov m,c jmp docmd citty: lxi h,serin+1 ;Serial input status xra a ci2: cmp m ;Wait till 40h deposited at 3fH jz ci2 mov m,a ;Clear status dcx h ;Point to input data mvi a,7fh ;For masking out parity ana m ret cstty: lda serin+1 ;Pick up serial input status ora a rz ;If zero then no character ready mvi a,0ffh ;Set character ready ret endif ***************************************************************** * * * LST: device driver routines. * * * * Routine used depends on the value of lsttyp. Possible * * lsttyp values are listed as follows: * * * * lsttyp is: 0 Nothing, used for patching to PROM's. * * 1 Provide for 128 bytes of patch space. * * 2 Multi I/Ondshaking (TI 810). It should be connected to the DSR * * input on the list device serial port. * * * ***************************************************************** if lsttyp eq 4 ;DSR protocol in msr ani dsr jz ll ;Wail till DSR comes up endif ***************************************************************** * * * The Xon/Xoff driver is used for a printer with software * * handshaking (Diablo 630). * * * ***************************************************************** if lsttyp eq 5 ;Xon / Xoff protocol xloop: call listst ;Check printer status ora a jz xloop ;Loop if not ready endif mov a,c out thr ret listst: lda group ;Get group byte ori lstgrp ;Select list device out grpsel in lsr ;Check if transmitter buffer empty ani thr rz ;Return not ready if lsttyp eq 3 ;CTS protocol in msr ani cts rz ;Return not ready if CTS is false endif if lsttyp eq 4 ;DSR protocol in msr ani dsr rz ;Return 5 GND * * 34 NC * * 35 /slct in <- 10 /d12 * * 35 <-> 24 /Select * * * * IMPORTANT: For this interface to work /select (24) on the * * parallel conector must be tied to ground (35). * * * ***************************************************************** list: lda group ;Get group byte out grpsel rl: in daisy0 ;Wait till printer ready and selected ani ready+paper jz rl pl: in daisy0 ;Test if out of paper ani ribbon jnz pl el: in daisy0 ani cover jnz el mov a,c ;Move character into (a) out daisi1 ;Latch data mvi a,d11+d10+d9 ;Make sure strobe is high out daisi0 dcr a ;Pulse strobe low out daisi0 inr a out daisi0 ack: in daisy0 ;Wait till ready again ani ready jz ack ret listst: lda group ;Get group byte out grpsel ;Select group zero in daisy0 ;Wait till printer ready and selected ani ready+paper rz in daisy0 ;Test if out of paper ani ribbon rz in daisy0 ani cover xri cover rz dcr a ret  serial, no protocol. * * 3 Multi I/O serial, CTS protocol. * * 4 Multi I/O serial, DSR protocol. * * 5 Multi I/O serial, Xon / Xoff protocol. * * 6 Multi I/O parallel, Centronics. * * 7 Multi I/O parallel, Diablo HyType II. * * * ***************************************************************** ***************************************************************** * * * lsttyp: 1 Blank space for printer driver * * * * Note: If the user plans to utilize this space then the * * one time code such as linit sould be placed just below * * the cboot routine. This space (belowe cboot) is recyled * * for use as a disk buffer after cboot is done. * * * ***************************************************************** if lsttyp eq 1 linit equ $ ;Make it easy to find this place list equ $ listst equ $ ret ds 127 endif ;Blank space ***************************************************************** * * * lsttyp: 2 Serial printer, no prnot ready if DSR is true endif if lsttyp eq 5 ;Xon / Xoff protocol mvi b,xon ;Last character recieved from printer lstflg equ $-1 in lsr ani dr ;Check for a character jz xskip ;No character present in rbr ;Get character ani 7fh mov b,a ;Save sta lstflg ;Kludge flag (last character recieved) xskip: mov a,b sui xoff ;Check for Xoff char (control S) jnz xsdone ;Printer ready ret ;Printer not ready xsdone equ $ ;Printer ready for data endif mvi a,0ffh ret ;Printer ready endif ;Multi I/O serial ***************************************************************** * * * lsttyp: 6 Centronics parallel printer driver. * * * ***************************************************************** if lsttyp eq 6 ***************************************************************** * * * Decision I Diablo parallel to Centronics parallel interface. * * * * The following cable must be made from the 50 pin Diablo * * conector to the endif ;Centronics parallel if lsttyp eq 7 ;Diablo HyTyp II ***************************************************************** * * * Diablo 1620 simulator for the Diablo Hytype II. * * * ***************************************************************** ***************************************************************** * * * This routine does all of the character decoding, escape * * sequences forward, backward, etc. The list of escape * * sequences, and special characters recognized is: * * * * adel ignored * * anul ignored * * aack ignored (when received) * * abel ignored * * aff form feed * * aetx etx/ack handshake * * aht horizontal tab * * alf line feed * * asp space * * abs backspace * * acr carriage return * * aesc 0 ignored * * aesc 1 set tab stop at current print position * * aesc 2 clear all tab stops * * aesc 3 graphics mode on * * aesc 4 graphics mode off * * aesc 5 forotocol * * * * lsttyp: 3 Serial printer, CTS protocol * * * * lsttyp: 4 Serial printer, DSR protocol * * * * lsttyp: 5 Serial printer, Xon / Xoff protocol * * * ***************************************************************** if (lsttyp ge 2) and (lsttyp le 5) list: lda group ;Get group byte ori lstgrp ;Select list device out grpsel ll: in lsr ani thre ;Wait till transmitter buffer empty jz ll ***************************************************************** * * * The CTS driver is used for a printer with hardware * * handshaking (TI 810). It should be connected to the CTS * * input on the list device serial port. * * * ***************************************************************** if lsttyp eq 3 ;CTS protocol in msr ani cts ;Wait till clear to send jz ll endif ***************************************************************** * * * The DSR driver is used for a printer with hardware * * ha 35 pin Centronics. * * * * Centronics Multi I/O * * pin signal pin signal * * 1 /strobe <- 46 /d9 * * 2 data1 <- 37 /d1 * * 3 data2 <- 36 /d2 * * 4 data3 <- 39 /d3 * * 5 data4 <- 33 /d4 * * 6 data5 <- 40 /d5 * * 7 data6 <- 42 /d6 * * 8 data7 <- 43 /d7 * * 9 data8 <- 45 /d8 * * 10 /acknlg -> 12 /check * * 11 busy -> 28 /printer ready * * 12 pe -> 3 /paper * * 13 slct -> 4 /ribbon * * 14 /auto feed xt <- 1 /d10 * * 15 NC * * 16 0V <-> 2 GND * * 17 chassis gnd * * 18 NC * * 19 /strobe rtn <-> 8 GND * * 20 data1 rtn <-> 11 GND * * 21 data2 rtn <-> 14 GND * * 22 data3 rtn <-> 16 GND * * 23 data4 rtn <-> 18 GND * * 24 data5 rtn <-> 20 GND * * 25 data6 rtn <-> 22 GND * * 26 data7 rtn <-> 25 GND * * 27 data8 rtn <-> 38 GND * * 28 /acknlg rtn <-> 41 GND * * 29 busy rtn <-> 44 GND * * 30 pe rtn <-> 47 GND * * 31 /init <- 9 /d11 * * 32 /error -> 5 /cover * * 33 GND <-> 3ward print * * aesc 6 backward print * * aesc 8 clear tab stop * * aesc 9 set left margin * * aesc A ignored * * aesc B ignored * * aesc D negative half line feed * * aesc U half line feed * * aesc alf negative line feed * * aesc aht c absolute horizontal tab * * aesc avt c absolute vertical tab * * aesc ars c set vmi * * aesc aus c set hmi * * * ***************************************************************** list: lda group ;Set printer initialized flag ori denable sta group mov a,c ;Get the character to print ani 7fh ;Strip off parity rz cpi adel ;Ignore delete rz mov c,a ;Save character lda escflg lxi h,level0 ;Level zero characters ana a mov a,c ;Scan for char in A jz lookup ;Look up activity for this character lda escflg lxi h,level1 ;Single character escape sequences cpi aesc mov a,c ;Scan for char in A jz lookup ;Execute single level escape sequence lxi h,level2 ;Two character escape sars dw settwo db aus dw settwo db 0 dw func1 level2: db aht dw abshtab ;Absolute horizontal tab db avt dw absvtab ;Absolute vertical tab db ars dw setvmi db aus dw sethmi db 0 dw func2 ***************************************************************** * * * The following routines execute escape sequences, etc. * * * ***************************************************************** settwo: doaesc: mov a,c ;Get the escape character sta escflg func0: ret doaetx: ret doalf: call lfvmi ;Get line feed vmi adjvp: xchg lhld dlvpos ;Get vertical motion displacement dad d shld dlvpos ret lfvmi: lda grhflg ana a lxi h,1 ;Only 1/48 if in graphics mode rnz lhld vmi ;Get vertical motion index ret neglf: call lfvmi ;Get line feed vmi call neghl call adjvp jmp func1 doasp: call sphmi ;Get space horizontal motion spdir: lda dirflg ;Forward or backwards ? ana a cnz neghl ;Negate HL adjhp: xchg ;Adjust Horizontatal tab mvi d,0 dcx d ;Form 16 bit tab column call newdlh jmp func2 newdlh: lhld hmi call hltde ;Multiply by hmi xchg lhld hpos ;And subtract current horizontal position xchg call hlmde shld dlhpos ret absvtab:mov e,c ;Absolute vertical tab mvi d,0 dcx d lhld vmi call hltde ;Multiply by vmi xchg lhld vpos ;And subtract the current vertical position xchg call hlmde shld dlvpos jmp func2 sethtab:call tabcol ;Set horizontal tab ora m ;OR in tab stop mov m,a ; and save jmp func1 tabcol: lhld hpos ;Compute address of current character col xchg lhld dlhpos dad d ;Get logical position xchg lhld hmi ;And divide by hmi to get character column xchg call hldde mtabp: ;Make a tab pointer ;HL -> Tab column desired (1-160) ;HL <- address of tab stop ; A <- bit mask for tab stop lxi d,8 ;Number of stops per byte call hldde ;HL/DE -> HL, HL mod DE -> DE mov c,e ;Save inr c ;Make range (1-8) lxi d,tabstp ;Tab array equence lda escflg ***************************************************************** * * * Lookup scans the table pointed at by HL looking for a match * * of the character in register A. * * * ***************************************************************** lookup: dcr m ;Test if end of table inr m jz gother ;Execute the default function cmp m ;Otherwise test for a match jz gother inx h ;Bump over character inx h ;Bump over function address inx h jmp lookup gother: inx h ;Bump over character mov a,m ;Get low byte of function address inx h mov h,m ;Get high byte of function address mov l,a ;Form Address of function pchl ;Execute it ***************************************************************** * * * Each of the following tables contains entries of the form: * * 1 byte character to match * * 2 bytes of address to execute * * terminated by a first byte of 0. * * * *********************************************l position lhld dlhpos ;Get current adjustment dad d ;Update it shld dlhpos ;And save ret sphmi: lda grhflg ;In graphics mode ? ana a lxi h,2 ;Only 1/60 if in graphics mode rnz lhld hmi ret doabs: call sphmi ;Space increment call neghl ;Negative to start with jmp spdir ;Adjust backwards doacr: xra a sta dirflg ;Forward printing sta grhflg ;No graphics mode lhld hpos ;Get current offset xchg lhld lmar ;Get left margin call hlmde shld dlhpos ;Don't move yet though mvi a,autolf ;In Auto line feed mode ? ana a jnz doalf ;Do line feed also ret dochar: mov l,c mvi h,0 call wheel ;Print the character in register C lda grhflg ana a lxi h,0 ;Don't move if in graphics mode jnz spdir lhld hmi jmp spdir clrall equ $ ;Clear all horizontal tabs lxi h,tabstp ;Beginning of tab stop array mvi d,tablen ;Size of tab array (bytes) notblp: mvi m,80h ;Reset tabs (reset to 0 later) kludge equ $-1 ;Used on first reset (warmboot) inx dad d ;Make array pointer xra a stc mtab0: rar dcr c ;Bump bit counter jnz mtab0 ret clrhtab:call tabcol ;Clear horizontal tab cma ana m ;Mask out tab stop mov m,a jmp func1 doaht: lhld hpos ;Compute address of current character col xchg lhld dlhpos dad d ;Get logical position xchg lhld hmi ;And divide by hmi to get character column xchg call hldde tablop: lxi d,numtabs inx h ;Start with next position call hlcde ;Compare position with number of tabs jnc tofar ;Past last tab push h ;Save col pointer call mtabp ;Generate tab pointer ana m ;Check out tab stop pop h ;Restore col pointer jz tablop ;Loop if stop not set xchg jmp newdlh ;Set new col position and return tofar: lhld hpos ;Go all the way to the right xchg lxi h,maxrgt call hlmde shld dlhpos ret doaff: lxi h,dfrmln ;Multiply forms length by 48 lxi d,48 call hltde lxi d,10 call hldde ;And divide it by 10 push h ;Save this result lhld vpos ;Get logic******************** level0: db aesc dw doaesc ;Beginning of an escape sequence db aff dw doaff ;Form feed db aetx dw doaetx db aht dw doaht ;horizontal tab db alf dw doalf ;Line feed db asp dw doasp ;Space db abs dw doabs ;Back space db acr dw doacr ;Carriage return db 0 dw dochar ;Any other character level1: db '1' dw sethtab ;Set horizontal tab db '2' dw clrall ;Clear all horizontal tabs db '3' dw setgrp ;Graphics mode db '4' dw clrgrp ;Clear graphics mode db '5' dw clrdir ;Forward printing db '6' dw setdir ;Backward printing db '8' dw clrhtab ;Clear horizontal tab db '9' dw setlmar ;Set left margin db '0' dw func1 ;No operation level 1 db 'A' dw func1 db 'B' dw func1 db 'a' dw func1 db 'b' dw func1 db 'D' dw neghlf ;Negative half line feed db 'U' dw poshlf ;Half line feed db alf dw neglf ;Negative line feed db aht dw settwo ;Two character escape sequence db avt dw settwo db  h ;Next tab stop dcr d ;Update repeat count jnz notblp ;Continue zeroing func2 equ $ func1: xra a ;Clear escape sequence flag sta escflg ret setgrp: mvi a,1 ;Set graphics mode on sta grhflg jmp func1 clrgrp: xra a ;Turn graphics mode off sta grhflg jmp func1 clrdir: xra a ;Forward print mode sta dirflg jmp func1 setdir: mvi a,a ;Set backward printing mode sta dirflg jmp func1 setlmar:lhld hpos ;Get current position xchg lhld dlhpos ;Get offset dad d shld lmar jmp func1 setvmi: mov l,c ;Set the motion index mvi h,0 dcx h shld vmi jmp func2 sethmi: mov l,c mvi h,0 dcx h shld hmi jmp func2 poshlf: call hlfvmi ;Half line feed vmi call adjvp jmp func1 neghlf: call hlfvmi ;Negative half line feed call neghl call adjvp jmp func1 hlfvmi: lhld vmi ;Get vmi for full line feed divid2: mov a,h ;High byte ora a ;Clear the carry rar mov h,a mov a,l rar mov l,a ret abshtab:mov e,c ;Absolute horizonal vertical position xchg lhld dlvpos dad d pop d push d ;Get copy of forms length call hldde ;HL mod DE xchg pop d xchg call hlmde xchg lhld dlvpos dad d shld dlvpos jmp papr ***************************************************************** * * * Neghl forms the twos complement of HL. * * * ***************************************************************** neghl: mov a,h cma mov h,a mov a,l cma mov l,a inx h ret ***************************************************************** * * * Hlmde subtracts DE from HL and returns. * * * ***************************************************************** hlmde: xchg call neghl xchg dad d ret ***************************************************************** * * * Hlcde compares HL with DE. On return the Z flag is set if * * they are equal, the Carry flag is set if HL is less than DE. * * * ********************************************************* required motion is to the left mov a,h ana a mvi c,0 jp posh call neghl mvi c,d11 posh: xchg lxi h,0 shld dlhpos ;Reset the horizontal increment xchg mov a,l ani 1 jz nohhlf ;No half spaces mov a,c ori d12 mov c,a nohhlf: call divid2 mov a,h ani d9+d10 ora c mov h,a lxi d,crstrd jmp cmnd papr: lhld dlvpos ;Check for any paper motion mov a,h ora l rz ;No motion mov a,h ana a mvi c,0 jp posv call neghl mvi c,d11 posv: mov a,h ani d9+d10 ora c mov h,a push h ;Save paper motion lhld vpos xchg lhld dlvpos ;Get logical position dad d push h ;Save for now lxi h,dfrmln ;Get default form length lxi d,48 call hltde ;Multiply by 48 lxi d,10 call hldde ;Divide by 10 pop d xchg call hldde ;Compute HL mod DE xchg shld vpos ;Save new vertical position lxi h,0 shld dlvpos ;Reset vertical motion pop h lxi d,pfstrd ;Paper feed strobe jmp cmnd wheel: push h call carrg ;Position the carriage firstsole. The user may patch * * here for their particular devices. * * * ***************************************************************** punch: jmp cout reader: jmp cin ***************************************************************** * * * Gocpm is the entry point from cold boots, and warm boots. It * * initializes some of the locations in page 0, and sets up the * * initial DMA address (80h). * * * ***************************************************************** gocpm: lxi h,buff ;Set up initial DMA address call setdma mvi a,(jmp) ;Initialize jump to warm boot sta wbot sta entry ;Initialize jump to BDOS lxi h,wboote ;Set up low memory entry to CBIOS warm boot shld wbot+1 lxi h,bdos+6 ;Set up low memory entry to BDOS shld entry+1 xra a ;A <- 0 sta bufsec ;Set buffer to unknown state sta bufwrtn ;Set buffer not dirty flag lda cwflg ;Get cold/warm boot flag ora a lxi d,coldbeg ;Beginning of initial command mvi a,coldend-co******** hlcde: mov a,h cmp d rnz mov a,l cmp e ret ***************************************************************** * * * Divide the number in HL by the number in DE. Return the * * quotient in HL and the remainder in DE. * * * ***************************************************************** hldde: mov a,d ;Start by negating DE and cma ; moving the left operand to BC mov b,a mov a,e cma mov c,a inx b mvi a,16 ;Repeat count in reg A lxi d,0 ;Initial remainder is zero div3: dcr a ;Test if done rm ;All done ? dad h ;Shift right operand to the left xchg push psw ;Save carry dad h ;Shift left operand to the left pop psw jnc div1 ;Does it fit ? inx h div1: push h dad b jnc div2 xchg inx h xthl pop h jmp div3 div2: pop h xchg jmp div3 ***************************************************************** * * * Multiply the contents of HL by the contents of DE. * * * ************************** call papr pop h lxi d,pwstrd cmnd: lda group ;Get group byte out grpsel ;Select group zero cmnd0: in daisy0 ana d jz cmnd0 mov a,l ;Negate low data bits cma mov l,a mov a,h ani d9+d10+d11+d12 ;Mask in data bits only cma if multr3 ;Mask out ribbon lift bit on Multi I/O ani 0ffh-rest endif mov h,a mov a,l out daisi1 ;Output low bits mov a,h out daisi0 ;Output high bits xra e ;Slap strobe bits in out daisi0 mov a,h ;And drop strobes back down out daisi0 ret ***************************************************************** * * * New list device status routine. Returns 0ffh if the printer * * can except another character, otherwise it returns 0. * * * ***************************************************************** listst: lda group ;Check printer initialized flag ani denable rz ;0 = printer not initialized lda group ;Get group byte out grpsel ;Select group zero lxi d,pwstrd in daisy0 ana d xra a rz ldbeg+1 ;Length of command jz cldcmnd lxi d,warmbeg mvi a,warmend-warmbeg+1 cldcmnd:lxi h,ccp+8 ;Command buffer sta ccp+7 ;Store length in CCP internal buffer mov c,a mvi b,0 call movbyt ;Move command to internal CCP buffer lda cwflg ora a lda autoflg jz cldbot rar cldbot: rar lda cdisk ;Jump to CP/M with currently selected disk in C mov c,a jc ccp jmp ccp+3 ;Enter CP/M cwflg: db 0 ;Cold/warm boot flag ***************************************************************** * * * The following byte determines if an initial command is to be * * given to CP/M on warm or cold boots. The value of the byte is * * used to give the command to CP/M: * * * * 0 = never give command. * * 1 = give command on cold boots only. * * 2 = give the command on warm boots only. * * 3 = give the command on warm and cold boots. * * * ***************************************************************** autoflg:db 0 ;Auto command feature ********************************************* hltde: mov c,l mov b,h lxi h,0 mult: mov a,b ora c rz mov a,b ora a rar mov b,a mov a,c rar mov c,a cc dadde xchg dad h xchg jmp mult dadde: dad d ret ***************************************************************** * * * The routines below actually interface to the printer, * * causing paper feed, carriage, and print wheel motion. * * * ***************************************************************** carrg: lhld dlhpos ;Check for any accumulated motion mov a,h ora l rz lhld hpos ;Check for too much motion xchg lhld dlhpos dad d mov a,h ana a jp lftok lhld hpos call neghl shld dlhpos lftok: lhld hpos xchg lhld dlhpos dad d lxi d,maxrgt call hlcde jc rgtok lhld hpos ;Otherwise move only to maxright xchg lxi h,maxrgt call hlmde shld dlhpos rgtok: lhld hpos ;Update the horizontal position xchg lhld dlhpos dad d shld hpos lhld dlhpos ;check if cma ret ***************************************************************** * * * Dynamic data locations used by the simulator. * * * ***************************************************************** hmi: dw 0 ;Horizontal motion index. Set by linit ; and escape sequences. vmi: dw 0 ;Vertical motion index. Set by linit ; and escape sequences. vpos: dw 0 ;Vertical position. Set by platen motion dlvpos: dw 0 ;Delta vpos. Set by platen motion hpos: dw 0 ;Horizontal position. Set by carriage motion dlhpos: dw 0 ;Delta hpos. Set by carriage motion lmar: dw 0 ;Left margin dirflg: db 0 ;Direction flag grhflg: db 0 ;Graphics mode flag escflg: db 0 ;Escape sequence in progress flag tabstp: ds numtabs/8+1 ;Tab stops bit array tablen equ numtabs/8+1 ;Length of tabs array endif ***************************************************************** * * * The following routines are used to make the reader and punch * * devices peform I/O through the con*********************************************************** * * * If there is a command inserted here, it will be given if the * * auto feature is enabled. * * For Example: * * * * coldbeg db 'MBASIC MYPROG' * * coldend db 0 * * * * will execute microsoft basic, and mbasic will execute the * * "MYPROG" basic program. * * * ***************************************************************** coldbeg:db '' ;Cold boot command goes here coldend:db 0 warmbeg:db '' ;Warm boot command goes here warmend:db 0 ***************************************************************** * * * WBOOT loads in all of CP/M except the CBIOS, then initializes * * system parameters as in cold boot. See the Cold Boot Loader * * listing for exactly what happens during warm and cold boots. * * * ***************************************************************** wboot: lxi sp,tpa ;Set up stack pointer mvi a,1 sta cwflg ;Set cold/warm boot flag  * operations. If the drive has never been selected it calls * * a low level drive select routine that should perform some * * sort of check if the device is working. If not working then * * it should report an error. If the logical drive has been * * selected before then setdrv just returns the DPH without * * checking the drive. * * * ***************************************************************** setdrv: mov a,c ;Save the logical drive number sta cpmdrv cpi maxlog ;Check for a valid drive number jnc zret ;Illegal drive mov a,e ;Check if bit 0 of (e) = 1 ani 1 jnz setd3 ;Drive has allready been accessed. mov h,c ;Move logical drive into (h) mvi l,d.sel1 call jumper ;Call low level drive select mov a,h ;Check if the low level drive select returned ora l ; zero to indicate an error jz zret ;Yes, an error so report to CP/M push h ;Save DPH address call gdph ;Get entry if DPH save table pop d ;DPH -> (de) mov m,e ;Put address of DPH k up current drive mov h,a ;Call drive routine to return a pointer to mvi l,d.bad ;the track and sector of the bad map call jumper mov a,h ;If routine returns 0 then the device has ora l ; no bad sector map jz badret mov e,m ;Pick up track number of bad sector map -> (de) inx h mov d,m inx h xchg shld cpmtrk xchg mov a,m ;Pick up sector number of of bad sector map inx h mov h,m mov l,a shld truesec call fill ;Read in bad sector map into the buffer rc lhld badptr ;Pick up bad map pointer lxi d,buffer ;Start at beginning of buffer badl: ldax d ;Pick up an entry from the buffer ora a jz bade ;All done mov a,m ;Pick up entry from bad map table inr a jz overflo ;Bad map overflow lda cpmdrv ;Put drive in table mov m,a inx h lxi b,8 call movbyt ;Move the rest of information into the table jmp badl bade: shld badptr ;Restore new bad map pointer badret: pop d pop b ret overflo:lxi h,omes call message jmp bad mvi h,wmdrive ;Move drive to warm boot off of into (h) mvi l,d.wboot ;Peform warm boot operation call jumper jnc gocpm ;No error hlt ;Halt computer db 0 jmp wboot ;In case user restarts the computer ***************************************************************** * * * Setsec just saves the desired sector to seek to until an * * actual read or write is attempted. * * * ***************************************************************** setsec: mov h,b ;Enter with sector number in (bc) mov l,c shld cpmsec donop: ret ***************************************************************** * * * Setdma saves the DMA address for the data transfer. * * * ***************************************************************** setdma: mov h,b ;Enter with DMA address in (bc) mov l,c shld cpmdma ;CP/M dma address ret ***************************************************************** * * * Home is translated into a seek to track zero. in table inx h mov m,d inx h mov m,c ;Put sector size in table inx h mov a,m ;Check if bad map has ever been read for this ora a ; drive cz getbad ;Never been read so read in bad map xchg ;DPH -> (hl) setd0: mov a,c ;Move sector size code into (a) sta secsiz ;Save sector size xra a setd1: dcr c ;Create number of (128 bytes/physical sector)-1 jz setd2 rlc ori 1 jmp setd1 setd2: sta secpsec ;Save for deblocking lda cpmdrv ;Save current drive as old drive sta lastdrv ; in case of select errors ret setd3: push d ;Save DPH address mov h,c ;Drive in (h) mvi l,d.sel2 ;Select drive call jumper call gdph ;Quick select pop d mov e,m ;DPH -> (de) inx h mov d,m inx h mov c,m ;Sector size -> (c) xchg ;DPH -> (hl) jmp setd0 gdph: lda cpmdrv ;Return pointer to DPH save area. rlc ;Each entry is 4 bytes long rlc mov e,a mvi d,0 lxi h,dphtab ;DPH save area table dad d ;Add offset ret ;(hl) = DPH save area for current dret omes: db 0dh, 0ah, 'BAD MAP OVERFLOW!', 0dh, 0ah, 0 nobad: lxi h,0 ;Used by device drives to indicate no bad ret ; sector map badptr: dw badmap ;Pointer to next available bad map entry ***************************************************************** * * * Write routine moves data from memory into the buffer. If the * * desired CP/M sector is not contained in the disk buffer, the * * buffer is first flushed to the disk if it has ever been * * written into, then a read is performed into the buffer to get * * the desired sector. Once the correct sector is in memory, the * * buffer written indicator is set, so the buffer will be * * flushed, then the data is transferred into the buffer. * * * ***************************************************************** write: mov a,c ;Save write command type sta writtyp mvi a,1 ;Set write command jmp rwent ***************************************************************** * * * Read routine to buffer da * * * ***************************************************************** home: lxi b,0 ;Track to seek to ***************************************************************** * * * Settrk saves the track # to seek to. Nothing is done at this * * point, everything is deffered until a read or write. * * * ***************************************************************** settrk: mov h,b ;Enter with track number in (bc) mov l,c shld cpmtrk ret ***************************************************************** * * * Sectran translates a logical sector number into a physical * * sector number. * * * ***************************************************************** sectran:lda cpmdrv ;Get the Drive Number mov h,a ;Drive in (h) mvi l,d.stran jmp jumper ;See device level sector translation routines ***************************************************************** * * * Setdrv selects the next drive to be used in read/write * rive zret: lxi h,0 ;Seldrv error exit lda lastdrv ;Get last selected drive mov c,a lda cdisk ;Pick up user/drive ani 0f0h ;Save user number ora c ;Put together with old drive sta cdisk ret ***************************************************************** * * * DPH save area. Each entry is 4 bytes long: * * 0 - LSB of DPH address * * 1 - MSB of DPH address * * 2 - Sector size code (1 = 128, 2 = 256, 3 = 512... * * 3 - Bad map has been initilized (0 = Uninitilized) * * * ***************************************************************** dphtab: rept maxlog*4 db 0 endm ***************************************************************** * * * Getbad - Check if a device has a bad map. If the device has * * a bad sector map then append bad entries to end of badmap * * table. * * * ***************************************************************** getbad: mvi m,1 ;Set drive initilized push b push d lda cpmdrv ;Picta from the disk. If the sector * * requested from CP/M is in the buffer, then the data is simply * * transferred from the buffer to the desired dma address. If * * the buffer does not contain the desired sector, the buffer is * * flushed to the disk if it has ever been written into, then * * filled with the sector from the disk that contains the * * desired CP/M sector. * * * ***************************************************************** read: xra a ;Set the command type to read rwent: sta rdwr ;Save command type ***************************************************************** * * * Redwrt calculates the physical sector on the disk that * * contains the desired CP/M sector, then checks if it is the * * sector currently in the buffer. If no match is made, the * * buffer is flushed if necessary and the correct sector read * * from the disk. * * * ***************************************************************** redwrt: mvi b,0 ;The 0 is modified tgr to transfer xchg ;DE = address in buffer lxi h,0 ;Get DMA address, the 0 is modified t/ ; contain the DMA address cpmdma equ $-2 mvi a,0 ;The zero gets modified to contain ; a zero if a read, or a 1 if write rdwr equ $-1 ana a ;Test which kind of operation jnz into ;Transfer data into the buffer outof: call mov128 xra a ret into: xchg ; call mov128 ;Move the data, HL = destination ; DE = source mvi a,1 sta bufwrtn ;Set buffer written into flag mvi a,0 ;Check for directory write writtyp equ $-1 dcr a mvi a,0 sta writtyp ;Set no directory write rnz ;No error exit ***************************************************************** * * * Flush writes the contents of the buffer out to the disk if * * it has ever been written into. * * * ***************************************************************** flush: mvi a,0 ;The 0 is modified to reflect if ; the buffer has been written into bufwrtn equ $-1 ana a ;Test drive, track, and sector. ; Then read the buffer ***************************************************************** * * * Jumpbuf, jumper are used to dispatch to a low level device * * subroutine. Jumper is called with the drive in (h) and the * * routine number (see description above) in (l). It passes * * along the (bc) and (de) registers unaltered. Jumpbuf is * * a call to jumper with the drive number from bufdrv. * * * ***************************************************************** jumpbuf:lda bufdrv ;Dispatch with bufdrv for drive mov h,a jumper: push d push b push h mov a,h ;Logical drive into (a) lxi d,dsttab ;Drive specification pointer table jumpl: mov c,a ;Save logical in (c) ldax d mov l,a inx d ldax d mov h,a ;Get a DST pointer in (hl) inx d mov a,c ;Logical in (a) sub m ;Subtract from first entry in DST jnc jumpl ;Keep scanning table till correct driver found inx h ;Bump (hl) to point to start of dispatch table po contain the log2 secsiz equ $-1 ; of the physical sector size/128 ; on the currently selected disk. lhld cpmsec ;Get the desired CP/M sector # mov a,h ani 80h ;Save only the side bit mov c,a ;Remember the side mov a,h ani 7fh ;Forget the side bit mov h,a dcx h ;Temporary adjustment divloop:dcr b ;Update repeat count jz divdone ora a mov a,h rar mov h,a mov a,l rar ;Divide the CP/M sector # by the size ; of the physical sectors mov l,a jmp divloop ; divdone:inx h mov a,h ora c ;Restore the side bit mov h,a shld truesec ;Save the physical sector number lxi h,cpmdrv ;Pointer to desired drive,track, and sector lxi d,bufdrv ;Pointer to buffer drive,track, and sector mvi b,6 ;Count loop dtslop: dcr b ;Test if done with compare jz move ;Yes, match. Go move the data ldax d ;Get a byte to compare cmp m ;Test for match inx h ;Bump pointers to next data item inx d jz dtslop ;Match, continue testing *************************if written into rz ;Not written, all done mvi a,d.write sta rwop+1 ***************************************************************** * * * Prep prepares to read/write the disk. Retries are attempted. * * Upon entry, H&L must contain the read or write operation * * address. * * * ***************************************************************** prep: call alt ;Check for alternate sectors di ;Reset interrupts xra a ;Reset buffer written flag sta bufwrtn mvi b,retries ;Maximum number of retries to attempt retrylp:push b ;Save the retry count mvi l,d.sel2 ;Select drive call jumpbuf lhld alttrk ;Track number -> (hl) mov a,h ;Test for track zero ora l push h ;Save track number mvi l,d.home cz jumpbuf pop b ;Restore track # mvi l,d.strk call jumpbuf lhld altsec ;Sector -> (hl) mov b,h mov c,l mvi l,d.ssec call jumpbuf lxi b,buffer ;Set the DMA address mvi l,d.sdma call jumpbuf rwop: mvi l,0 ;Get operaop d ;Real (hl) -> (de) mov a,e ;Move offset number into (a) rlc ;Each entry is 2 bytes mov e,a ;Make an offset mvi d,0 dad d ;(hl) = **Routine mov a,m ;Pick up address of handler for selected inx h ; function. mov h,m mov l,a ;(hl) = *routine mov a,c ;Logical in (a) pop b ;Restore saved registers pop d pchl ***************************************************************** * * * Check for alternate sectors in bad sector table. If an * * alternate sector is found replace alttrk and altsec with * * new sector number else pass along unaltered. * * * ***************************************************************** alt: lxi h,badmap ;Address of bad map -> (hl) lda bufdrv ;Pick up drive number currently working on mov c,a ;Move drive into (c) for speed in search all: xchg lhld badptr ;Get bad map pointer xchg ; -> (de) mov a,d ;Check if at end of bad map table cmp h jnz alt2 ;Still more mov a,e cmp l jnz alt2 ;Still more**************************************** * * * Drive, track, and sector don't match, flush the buffer if * * necessary and then refill. * * * ***************************************************************** call fill ;Fill the buffer with correct physical sector rc ;No good, return with error indication ***************************************************************** * * * Move has been modified to cause either a transfer into or out * * the buffer. * * * ***************************************************************** move: lda cpmsec ;Get the CP/M sector to transfer dcr a ;Adjust to proper sector in buffer ani 0 ;Strip off high ordered bits secpsec equ $-1 ;The 0 is modified to represent the # of ; CP/M sectors per physical sectors mov l,a ;Put into HL mvi h,0 dad h ;Form offset into buffer dad h dad h dad h dad h dad h dad h lxi d,buffer ;Beginning address of buffer dad d ;Form beginning address of secttion address call jumpbuf pop b ;Restore the retry counter mvi a,0 ;No error exit status rnc ;Return no error dcr b ;Update the retry counter stc ;Assume retry count expired mvi a,0ffh ;Error return rz ;Return sad news mov a,b cpi retries/2 jnz retrylp ;Try again push b ;Save retry count mvi l,d.home ;Home drive after (retries/2) errors call jumpbuf pop b jmp retrylp ;Try again ***************************************************************** * * * Fill fills the buffer with a new sector from the disk. * * * ***************************************************************** fill: call flush ;Flush buffer first rc ;Check for error lxi d,cpmdrv ;Update the drive, track, and sector lxi h,bufdrv lxi b,5 ;Number of bytes to move call movbyt ;Copy the data lda rdwr ana a jz fread lda writtyp dcr a dcr a rz lda secsiz ;Check for 128 byte sectors dcr a rz fread: mvi a,d.read sta rwop+1 jmp prep ;Select  lhld buftrk ;No alternate sector so use selected sector shld alttrk lhld bufsec shld altsec ret alt2: push h ;Save current bad map entry address mov a,c ;Move drive into (a) cmp m ;Check if drive in table matches jnz altmis ;Does not match skip this entry inx h ;Point to LSB of alternate track lda buftrk ;Pick up LSB of buffer track cmp m jnz altmis inx h ;Point to MSB alternate track lda buftrk+1 ;Pick up MSB of buffer track cmp m jnz altmis inx h ;Point to LSB of alternate sector lda bufsec ;Pick up LSB of buffer sector cmp m jnz altmis inx h ;Point to MSB of alternate sector lda bufsec+1 ;Pick up MSB of buffer sector cmp m jnz altmis ;Found an alternate sector inx h ;Point to real info on the alternate sector lxi d,alttrk xchg ;MOVLOP (de) = source, (hl) = dest push b lxi b,4 call movbyt ;Move alternate sector info in correct place pop b pop h ret altmis: pop h ;Current alternate did not match lxi d,9 ;Buler origin hdstat equ hdorg ;Hard Disk Status hdcntl equ hdorg ;Hard Disk Control hdcmnd equ hdorg+1 ;Hard Disk Command hdreslt equ hdorg+1 ;Hard Disk Result hdfunc equ hdorg+2 ;Hard Disk Function hddata equ hdorg+3 ;Hard Disk Data retry equ 2 ;Retry bit of result tkzero equ 01h ;Track zero bit of status opdone equ 02h ;Operaction done bit of status complt equ 04h ;Complete bit of status tmout equ 08h ;Time out bit of status wfault equ 10h ;Write fault bit of status drvrdy equ 20h ;Drive ready bit of status index equ 40h ;Index bit of status pstep equ 4 ;Step bit of function nstep equ 0fbh ;Step bit mask of function hdrlen equ 4 ;Sector header length seclen equ 512 ;Sector data length wenabl equ 0fh ;Write enable wreset equ 0bh ;Write reset of function scenbl equ 5 ;Controller control dskclk equ 7 ;Disk clock for control mdir equ 0f7h ;Direction mask for function null equ 0fch ;Null command idbuff equ 0 ;Initialize data command rsect equ 1 ;Read sez hdtdel if not fujitsu lxi h,0 ;Time one revolution of the drive mvi c,index in hdstat ana c mov b,a ;Save current index level in B hdinxd1:in hdstat ana c cmp b ;Loop util index level changes jz hdinxd1 hdindx2:inx h in hdstat ;Start counting until index returns to ana c ; previous state cmp b jnz hdindx2 if m10 ;Memorex M10's have 40 ms head settle dad h endif if m26 ;Shugart M26's have 30 ms head settle xra a mov a,h rar mov d,a mov a,l rar mov e,a dad d endif shld settle ;Save the Count for timeout delay endif call hdhome hdl2: lda hdcur ;Load logical drive lxi d,dphhd0 ;Start of hard disk DPH's mvi c,3 ;Hard disk sector size equals 512 bytes jmp retdph dcrc: dcr c ;Conditional decrement C routine ret divlog: mvi c,0 divlx: sui hdlog rc inr c jmp divlx hddrv: sta hdcur call divlog ;Get the physical drive # hdd2: mov a,c sta hddisk ;Select the drive ori null out hdfunc mvi a,wenabl oump pointer by the length of an entry dad d jmp all ;Loop for more ***************************************************************** * * * Mover moves 128 bytes of data. Source pointer in DE, Dest * * pointer in HL. * * * ***************************************************************** mov128: lxi b,128 ;Length of transfer movbyt: xra a ;Check if host processor is a Z80 adi 3 jpo z80mov ;Yes, Its a Z80 so use block move m8080: ldax d ;Get a byte of source mov m,a ;Move it inx d ;Bump pointers inx h dcx b ;Update counter mov a,b ;Test for end ora c jnz m8080 ret z80mov: xchg ;Source in (hl), Destination in (de) dw 0b0edh ;ldir xchg ret ***************************************************************** * * * Return DPH pointer. Enter with (de) with DPH base address * * and (a) with logical drive number. Returns with DPH address * * in (hl). * * * **********************************************************ctor command wsect equ 5 ;Write sector command isbuff equ 8 ;Initialize header command ***************************************************************** * * * Device Specification Table for HDC3 * * * ***************************************************************** hddst: db maxhd*hdlog ;Number of logical drives dw hdwarm ;Warm boot dw hdtran ;Sector translation dw hdldrv ;Select logical drive 1 (First time select) dw hddrv ;Select logical drive 2 (General sel ect) dw hdhome ;Home current selected drive dw hdseek ;Seek to selected track dw hdsec ;Select sector dw hddma ;Set DMA address dw hdread ;Read a sector dw hdwrite ;Write a sector dw nobad ;No bad sector map hdwarm: call divlog ;Get physical drive number in (c) xra a lxi h,ccp-200h ;Initial DMA address push h sta head ;Select head zero inr a ; 1 -> (a) push psw ;Save first sector - 1 call hdd2 ;Select drive mvi c,0 call hdhome ;Home the drive hdwrld: pop psw ;Rt hdcntl ret hdhome: call hdptr mvi m,0 ;Set track to zero in hdstat ;Test status ani tkzero ;At track zero ? rz ;Yes if not fujitsu hdstepo:in hdstat ;Test status ani tkzero ;At track zero ? jz hddelay mvi a,1 stc call accok ;Take one step out jmp hdstepo else xra a jmp accok endif if not fujitsu hddelay:lxi h,0 ;Get hddelay settle equ $-2 deloop: dcx h ;Wait 20ms mov a,h ora l inx h dcx h jnz deloop ret endif hdseek: call hdptr ;Get pointer to current track mov e,m ;Get current track mov m,c ;Update the track mov a,e ;Need to seek at all ? sub c rz cmc ;Get carry into direction jc hdtrk2 cma inr a if fujitsu hdtrk2: jmp accok else hdtrk2: call accok jmp hddelay endif accok: mov b,a ;Prep for build call build sloop: ani nstep ;Get step pulse low out hdfunc ;Output low step line ori pstep ;Set step line high out hdfunc ;Output high step line dcr b ;Update repeat count jnz sloop ******* retdph mov l,a ;Move logical drive into (l) mvi h,0 dad h ;Multiply by 16 (size of DPH) dad h dad h dad h dad d ;(hl) = pointer to DPH ret ***************************************************************** * * * Utility routine to output the message pointed at by (hl) * * terminated with a null. * * * ***************************************************************** message:mov a,m ;Get a character of the message inx h ;Bump text pointer ora a ;Test for end rz ;Return if done push h ;Save pointer to text mov c,a ;Output character in C call cout ;Output the character pop h ;Restore the pointer jmp message ;Continue until null reached ***************************************************************** * * * The following equates are for the Diskus Hard disk * * * ***************************************************************** if hdc3 ne 0 ;Want HDC3 controller included ? hdorg equ 50h ;Hard Disk Controlestore sector pop h ;Restore DMA address inr a sta hdsectr cpi 12 ;Past BDOS ? rz ;Yes, all done inr h ;Update DMA address inr h shld hdadd push h push psw hdwrrd: lxi b,retries*100h+0;Retry counter hdwr: push b ;Save the retry count call hdread ;Read the sector pop b jnc hdwrld ;Test for error dcr b ;Update the error count jnz hdwr ;Keep trying if not to many errors stc ;Error flag ret hdtran: mov h,b mov l,c inx h ret hdldrv: sta hdcur ;Save logical disk call divlog ;Divide by logical disks per drive mov a,c sta hddisk ;Save new physical drive call hdptr ;Get track pointers mov a,m ;Get current track inr a ;Check if -1 jnz hdl2 ;Nope, allready accessed ori null ;Select drive out hdfunc mvi a,scenbl ;Enable the controller out hdcntl mvi c,239 ;Wait approx 2 minutes for Disk to ready lxi h,0 hdtdel: dcx h mov a,h ora l cz dcrc jz zret ;Drive not ready error in hdstat ;Test if ready yet ani drvrdy jn;Keep going the required # of tracks jmp wsdone hddma: mov h,b ;Save the DMA address mov l,c shld hdadd ret wsdone: in hdstat ;Wait for seek complete to finish ani complt jz wsdone ret if m26 hdsec: mvi a,01fh ;For compatibility with Cbios rev 2.3, 2.4 ana c cz getspt sta hdsectr mvi a,0e0h ana c rlc rlc rlc sta head getspt: mvi a,hdspt ret else hdsec: mov a,c call divspt adi hdspt ana a cz getspt sta hdsectr mov a,c sta head getspt: mvi a,hdspt dcr c ret divspt: mvi c,0 divsx: sui hdspt rc inr c jmp divsx endif hdread: call hdprep rc xra a out hdcmnd cma out hddata out hddata mvi a,rsect ;Read sector command out hdcmnd call process rc xra a out hdcmnd mvi b,seclen/4 lxi h,0 hdadd equ $-2 in hddata in hddata rtloop: in hddata ;Move four bytes mov m,a inx h in hddata mov m,a inx h in hddata mov m,a inx h in hddata mov m,a inx h dcr b jnz rtloop ret hdwriteine fddma equ fdorig+12h ;Disk Jockey 2D set DMA address fdread equ fdorig+15h ;Disk Jockey 2D read routine fdwrite equ fdorig+18h ;Disk Jockey 2D write routine fdsel equ fdorig+1bh ;Disk Jockey 2D select drive routine fdtstat equ fdorig+21h ;Disk Jockey 2D terminal status routine fdstat equ fdorig+27h ;Disk Jockey 2D status routine fderr equ fdorig+2ah ;Disk Jockey 2D error, flash led fdden equ fdorig+2dh ;Disk Jockey 2D set density routine fdside equ fdorig+30h ;Disk Jockey 2D set side routine fdram equ fdorig+400h ;Disk Jockey 2D RAM address dblsid equ 20h ;Side bit from controller io equ fdorig+3f8h ;Start of I/O registers dreg equ io+1 cmdreg equ io+4 clrcmd equ 0d0h ***************************************************************** * * * Device Specification Table for the Disk Jockey 2D/B * * * ***************************************************************** fddst: db maxfd ;Number of logical drives dw fdwarm ;Warm boot dw fdtran ;Sector translation dw f call wrmread lxi b,0300h ;Size of partial sector lxi d,ccp+1300h ;Address for sector 3 lxi h,ccp+0f00h ;Address of sector 3 wrmcpy: mov a,m ;Get a byte and stax d ; save it. inx d ;Bump pointers inx h dcx b ;Bump counter mov a,b ;Check if done ora c jnz wrmcpy ; if not, loop lxi b,ccp+0f00h ;Address for sector 2 lxi d,10*100h+2 ;Retry count + sector 2 call wrmread xra a ;Clear error indicator ret wrmread:push d call fddma ;Set DMA address pop b call fdsec ;Set sector wrmfrd: push b ;Save error count call fdread ;Read a sector jc wrmerr ;Do retry stuff on error call fdstat ;Sector size must be 1024 bytes ani 0ch ;Mask length bits sui 0ch ;Carry (error) will be set if < 0c0h wrmerr: pop b ;Fetch retry count rnc ;Return if no error dcr b ;Bump error count jnz wrmfrd jmp fderr ;Error, flash the light fdtran: inx b push d ;Save table address push b ;Save sector # call fdget ;Get DPH for current drive lxi d:call hdprep ;Prepare header rc xra a out hdcmnd lhld hdadd mvi b,seclen/4 wtloop: mov a,m ;Move 4 bytes out hddata inx h mov a,m out hddata inx h mov a,m out hddata inx h mov a,m out hddata inx h dcr b jnz wtloop mvi a,wsect ;Issue write sector command out hdcmnd call process rc mvi a,wfault ana b stc rz xra a ret process:in hdstat ;Wait for command to finish mov b,a ani opdone jz process mvi a,dskclk out hdcntl in hdstat ani tmout ;Timed out ? stc rnz in hdreslt ani retry ;Any retries ? stc rnz xra a ret hdprep: in hdstat ani drvrdy stc rnz mvi a,isbuff ;Initialize pointer out hdcmnd call build ori 0ch out hdfunc lda head out hddata ;Form head byte call hdptr mov a,m ;Form track byte out hddata ana a mvi b,80h jz zkey mvi b,0 zkey: mvi a,0 ;Form sector byte hdsectr equ $-1 out hddata mov a,b out hddata mvi a,dskclk out hdcntl mvi a,wenabl out hdcntl xra a dldrv ;Select drive 1 dw fdsel2 ;Select drive 2 dw fdlhome ;Home drive dw fdseek ;Seek to specified track dw fdssec ;Set sector dw fddma ;Set DMA address dw fdread ;Read a sector dw fdwrite ;Write a sector dw nobad ;No bad sector map ***************************************************************** * * * Floppy disk warm boot loader * * * ***************************************************************** fdwarm: mov c,a call fdsel ;Select drive A mvi c,0 ;Select side 0 call fdside wrmfail:call fdhome ;Track 0, single density jc wrmfail ;Loop if error ;The next block of code re-initializes ; the warm boot loader for track 0. mvi a,5-2 ;Initialize the sector to read - 2 sta newsec lxi h,ccp-100h ;First revolution DMA - 100h shld newdma ;Load all of track 0 t0boot: mvi a,5-2 ;First sector - 2 newsec equ $-1 inr a ;Update sector # inr a cpi 27 ;Size of track in sectors + 1 jc nowrap ;Skip if not at end of ,10 ;Load DPH pointer dad d mov a,m inx h mov h,m mov l,a mov a,m ;Get # of CP/M sectors/track ora a ;Clear carry rar ;Divide by two sub c ;Subtract sector number push psw ;Save adjusted sector jm sidetwo sidea: pop psw ;Discard adjusted sector pop b ;Restore sector requested pop d ;Restore address of xlt table sideone:xchg ;hl <- &(translation table) dad b ;bc = offset into table mov l,m ;hl <- physical sector mvi h,0 ret sidetwo:call fdgsid ;Check out number of sides jz sidea ;Single sided pop psw ;Retrieve adjusted sector pop b cma ;Make sector request positive inr a mov c,a ;Make new sector the requested sector pop d call sideone mvi a,80h ;Side two bit ora h ; and sector mov h,a ret fdldrv: sta fdlog ;Save logical drive mov c,a ;Save drive # mvi a,0 ;Have the floppies been accessed yet ? flopflg equ $-1 ana a jnz flopok mvi b,17 ;Floppies havn't been accessed lxi h,fdboot ;Check if 2D controller is  ret hdptr: lhld hddisk xchg mvi d,0 lxi h,drives dad d ret build: mvi a,0 head equ $-1 ral ral ral ral ori 0 hddisk equ $-1 xri 0f0h ret drives equ $ rept maxhd db 0ffh endm hdcur: db 0 ;Current logical disk endif ***************************************************************** * * * The following equates relate the Morrow Designs 2D/B * * controller. If the controller is non standard (0F800H) * * only the FDORIG equate need be changed. * * * ***************************************************************** if maxfd ne 0 ;Include Discus 2D ? fdorig equ 0f800H ;Origin of Disk Jockey PROM fdboot equ fdorig+00h ;Disk Jockey 2D initialization fdcin equ fdorig+03h ;Disk Jockey 2D character input routine fdcout equ fdorig+06h ;Disk Jockey 2D character output routine fdhome equ fdorig+09h ;Disk Jockey 2D track zero seek fdseek equ fdorig+0ch ;Disk Jockey 2D track seek routine fdsec equ fdorig+0fh ;Disk Jockey 2D set sector routtrack jnz t1boot ;Done with this track sui 27-6 ;Back up to sector 6 lxi h,ccp-80h ;Memory address of sector - 100h shld newdma nowrap: sta newsec ;Save the updated sector # mov c,a call fdsec ;Set up the sector lxi h,ccp-100h ;Memory address of sector - 100h newdma equ $-2 lxi d,100h ;Update DMA address dad d nowrp: shld newdma ;Save the updated DMA address mov b,h mov c,l call fddma ;Set up the new DMA address lxi b,retries*100h+0;Maximum # of errors, track # wrmfred:push b call fdseek ;Set up the proper track call fdread ;Read the sector pop b jnc t0boot ;Continue if no error dcr b jnz wrmfred ;Keep trying if error jmp fderr ;Too many errors, flash the light ;Load track 1, sector 1, sector 3 (partial), sector 2 (1024 byte sectors) t1boot: mvi c,1 ;Track 1 call fdseek lxi b,ccp+0b00h ;Address for sector 1 lxi d,10*100h+1 ;Retry count + sector 1 call wrmread lxi b,ccp+0f00h ;Address for sector 2 lxi d,10*100h+3 ;Retry count + sector 3installed mvi a,(jmp) clopp: cmp m ;Must have 17 jumps jnz zret inx h inx h inx h dcr b jnz clopp lxi d,fdinit ;Initialization sequence lxi h,fdorig+7e2h ;Load address lxi b,30 ;Byte count call movbyt ;Load controller RAM mvi a,0ffh ;Start 1791 sta dreg mvi a,clrcmd ;1791 reset sta cmdreg mvi a,1 ;Set 2D initialized flag sta flopflg flopok: call flush ;Flush buffer since we are using it lda fdlog ;Select new drive mov c,a call fdsel call fdlhome ;Recalibrate the drive lxi h,1 ;Select sector 1 of track 2 shld truesec inx h shld cpmtrk xra a ;Make sure we are doing a read sta rdwr call fill ;Fill in buffer with sector jc zret ;Test for error return call fdstat ;Get status on current drive sta fdldst ;Save drive status ani 0ch ;Mask in sector size bits push psw ;Used to select a DPB rar lxi h,xlts ;Table of XLT addresses mov e,a mvi d,0 dad d push h ;Save pointer to proper XLT call fdget ;Get pointer to proper;Floppy drive status byte fdlsid: rept maxfd db 0ffh ;Double sided flag 0 = single, 1 = double endm endif if (maxfd ne 0) or (maxdm ne 0) ***************************************************************** * * * Xlts is a table of address that point to each of the xlt * * tables for each sector size. * * * ***************************************************************** xlts: dw xlt128 ;Xlt for 128 byte sectors dw xlt256 ;Xlt for 256 byte sectors dw xlt512 ;Xlt for 512 byte sectors dw xlt124 ;Xlt for 1024 byte sectors ***************************************************************** * * * Xlt tables (sector skew tables) for CP/M 2.0. These tables * * define the sector translation that occurs when mapping CP/M * * sectors to physical sectors on the disk. There is one skew * * table for each of the possible sector sizes. Currently the * * tables are located on track 0 sectors 6 and 8. They are * * loaded into memory in the Cbios ram by the col*************************************** * * * The following DPB defines a diskette as 512 byte sectors, * * double density, and single sided. * * * ***************************************************************** dpb512s:dw 60 ;CP/M sectors/track db 4 ;BSH db 15 ;BLM db 0 ;EXM dw 280 ;DSM dw 127 ;DRM db 0c0h ;AL0 db 0 ;AL1 dw 32 ;CKS dw 2 ;OFF db 3 ***************************************************************** * * * The following DPB defines a diskette as 1024 byte sectors, * * double density, and single sided. * * * ***************************************************************** dp1024s:dw 64 ;CP/M sectors/track db 4 ;BSH db 15 ;BLM db 0 ;EXM dw 299 ;DSM dw 127 ;DRM db 0c0h ;AL0 db 0 ;AL1 dw 32 ;CKS dw 2 ;OFF db 4 ***************************************************************** * * * The following DPB defines a diskette for 128 byte sectors, * * single density, and double sided DPH pop d lxi b,2 ;Copy XLT pointer into DPH call movbyt lxi d,8 ;Offset to DPB pointer in DPH dad d ;HL <- &DPH.DPB push h call fdgsid ;Get pointer to side flag table entry lda fdldst ;Get drive status ani dblsid ;Check double sided bit mov m,a ;Save sides flag lxi d,dpb128s ;Base for single sided DPB's jz sideok lxi d,dpb128d ;Base of double sided DPB's sideok: xchg pop d ;(HL) -> DPB base, (DE) -> &DPH.DPB pop psw ;Offset to correct DPB ral ral ;Make 0, 10, 20, 30 mov c,a mvi b,0 ;Make offset dad b ;(hl) is now a DPB pointer xchg ;Put proper DPB address in DPH.DPB mov m,e inx h mov m,d lxi h,15 ;Offset to DPB.SIZ dad d mov c,m ;Fetch sector size code fdget: lda fdlog ;Return proper DPH lxi d,dphfd0 jmp retdph fdsel2: sta fdlog mov c,a jmp fdsel fdlhome:mvi c,0 ;Select side 0 call fdside jmp fdhome ;Do actual home fdssec: push b ;Save sector number mov a,b ;Check side select bit rlc ;Move high bit to bid boot routine. * * * ***************************************************************** xlt128: db 0 db 1,7,13,19,25 db 5,11,17,23 db 3,9,15,21 db 2,8,14,20,26 db 6,12,18,24 db 4,10,16,22 xlt256: db 0 db 1,2,19,20,37,38 db 3,4,21,22,39,40 db 5,6,23,24,41,42 db 7,8,25,26,43,44 db 9,10,27,28,45,46 db 11,12,29,30,47,48 db 13,14,31,32,49,50 db 15,16,33,34,51,52 db 17,18,35,36 xlt512: db 0 db 1,2,3,4,17,18,19,20 db 33,34,35,36,49,50,51,52 db 5,6,7,8,21,22,23,24 db 37,38,39,40,53,54,55,56 db 9,10,11,12,25,26,27,28 db 41,42,43,44,57,58,59,60 db 13,14,15,16,29,30,31,32 db 45,46,47,48 xlt124: db 0 db 1,2,3,4,5,6,7,8 db 25,26,27,28,29,30,31,32 db 49,50,51,52,53,54,55,56 db 9,10,11,12,13,14,15,16 db 33,34,35,36,37,38,39,40 db 57,58,59,60,61,62,63,64 db 17,18,19,20,21,22,23,24 db 41,42,43,44,45,46,47,48 ***************************************************************** * * * Each of the following tables describes a diskette with. * * * ***************************************************************** dpb128d:dw 52 ;CP/M sectors/track db 4 ;BSH db 15 ;BLM db 1 ;EXM dw 242 ;DSM dw 127 ;DRM db 0c0h ;AL0 db 0 ;AL1 dw 32 ;CKS dw 2 ;OFF db 1 ***************************************************************** * * * The following DPB defines a diskette as 256 byte sectors, * * double density, and double sided. * * * ***************************************************************** dpb256d:dw 104 ;CP/M sectors/track db 4 ;BSH db 15 ;BLM db 0 ;EXM dw 486 ;DSM dw 255 ;DRM db 0f0h ;AL0 db 0 ;AL1 dw 64 ;CKS dw 2 ;OFF db 2 ***************************************************************** * * * The following DPB defines a diskette as 512 byte sectors, * * double density, and double sided. * * * ***************************************************************** dpb512d:dw 120 ;CP/M sectors/track db 4 ;BSH db 15 ;BLMt zero ani 1 mov c,a call fdside ;Call select side 0 = side A, 1 = Side B pop b jmp fdsec fdgsid: lxi h,fdlsid ;Side flag table lda fdlog ;Drive number push d mov e,a ;Make offset mvi d,0 dad d ;Offset to proper entry pop d mov a,m ;Set up flags ora a ret fdinit: dw 0 ;Initialization bytes loaded onto 2D/B dw 1800h ;Head loaded timeout dw 0 ;DMA address db 0 ;Double sided flag db 0 ;Read header flag db 07eh ;Drive select constant db 0 ;Drive number db 8 ;Current disk db 0 ;Head loaded flag db 9 ;Drive 0 parameters db 0ffh ;Drive 0 track address db 9 ;Drive 1 parameters db 0ffh ;Drive 1 track address db 9 ;Drive 2 parameters db 0ffh ;Drive 2 track address db 9 ;Drive 3 parameters db 0ffh ;Drive 3 track address db 9 ;Current parameters db 0 ;Side desired db 1 ;Sector desired db 0 ;Track desired db 0 ;Header image, track db 0 ;Sector db 0 ;Side db 0 ;Sector dw 0 ;CRC fdlog: db 0 fdldst: db 0  the * * specified characteristics. * * * ***************************************************************** ***************************************************************** * * * The following DPB defines a diskette for 128 byte sectors, * * single density, and single sided. * * * ***************************************************************** dpb128s:dw 26 ;CP/M sectors/track db 3 ;BSH db 7 ;BLM db 0 ;EXM dw 242 ;DSM dw 63 ;DRM db 0c0h ;AL0 db 0 ;AL1 dw 16 ;CKS dw 2 ;OFF db 1 ***************************************************************** * * * The following DPB defines a diskette for 256 byte sectors, * * double density, and single sided. * * * ***************************************************************** dpb256s:dw 52 ;CP/M sectors/track db 4 ;BSH db 15 ;BLM db 0 ;EXM dw 242 ;DSM dw 127 ;DRM db 0c0h ;AL0 db 0 ;AL1 dw 32 ;CKS dw 2 ;OFF db 2 ************************** db 0 ;EXM dw 561 ;DSM dw 255 ;DRM db 0f0h ;AL0 db 0 ;AL1 dw 64 ;CKS dw 2 ;OFF db 3 ***************************************************************** * * * The following DPB defines a diskette as 1024 byte sectors, * * double density, and double sided. * * * ***************************************************************** dp1024d:dw 128 ;CP/M sectors/track db 4 ;BSH db 15 ;BLM db 0 ;EXM dw 599 ;DSM dw 255 ;DRM db 0f0h ;AL0 db 0 ;AL1 dw 64 ;CKS dw 2 ;OFF db 4 endif ***************************************************************** * * * The following equates relate the Morrow Designs DJDMA * * controller. * * * ***************************************************************** if (maxdm ne 0) or (maxmf ne 0) dmchan equ 50h ;Default channel address dmkick equ 0efh ;Kick I/O port address rdsect equ 20h ;Read sector command wrsect equ 21h ;Write a sector command gstat equ 22h ;Get drivetrck ;Read track command db 0 ;Track 0 db 0 ;Side 0 db 0 ;Drive 0 dw dmwsec ;Sector load/status map db 0 dmwst: db 0 ;Track read status db dmsdma dw ccp+dmtrck ;DMA address for track 1 db 0 db rdtrck db 1 ;Track 1 db 0 ;Side 0 db 0 ;Drive 0 dw dmwsec+26 ;Map is loaded right after track 0 status map db 0 db 0 ;Track read status db dmsdma dw buffer ;Sector 3 gets loaded in system buffer db 0 db rdsect db 1 ;Track 1 db 3 ;Side 0, sector 3 db 0 ;Drive 0 dmwend: db 0 ;Read status dw 0 ;Room for the halt dmwsec: dw 0ffffh, 0ffffh ;Do not load boot loader dw 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ;22 sectors to be loaded dw 0, 0ffffh, 0ffffh, 0ffffh ;First 2 sectors on track 2 dmselr: sta dmlog mvi b,0 ;8 inch logical drives start at zero jmp dmsel2 dmtran: inx b push d ;Save table address push b ;Save sector # call dmget lxi d,10 dad d mov a,m inx h mov h,m mov l,a mov a,m ;Get # of CP/M sectors/track ora a ;Clearrite to controller memory dw settlhi db 0 dw 2 add1: dw 0 dmend: db haltc ;Halt command db 0 ;Status stephi: dw 066h ;3 MS track to track step rate settlhi:dw 200h ;15 MS head settle delay sethigh:push d lxi h,1340h ;Pointer to start of Drive Paramter Table in ; DJDMA lxi d,10h ;Size of SPT table lda dmlog seth0: ora a ;Still more tables to skip jz seth1 dad d ;Offset to next table dcr a jmp seth0 seth1: xchg ;Move pointer to DPT in (de) lxi h,4 dad d shld add0 ;Address of step delay lxi h,10 dad d shld add1 ;Address of head settle delay lxi h,dmchan mvi m,bracha inx h mvi m,sethi and 0ffh inx h mvi m,(sethi/100h) and 0ffh inx h mvi m,0 ;Extended address 0 lxi h,dmend-1 xra a call docmd2 pop d ret endif ***************************************************************** * * * Drive specification table for DJDMA 5 1/4 inch drives * * * ********************************************************* status dmsdma equ 23h ;Set DMA address intrqc equ 24h ;Set Interrupt request haltc equ 25h ;Halt command bracha equ 26h ;Channel branch setcha equ 27h ;Set channel address setcrc equ 28h ;Set CRC retry count rdtrck equ 29h ;Read track command wrtrck equ 2ah ;Write track command serout equ 2bh ;Serial ouput through bit banger serial port senabl equ 2ch ;Enable serial input trksiz equ 2dh ;Set number of tracks setlog equ 2eh ;Set logical drives readm equ 0a0h ;Read from controller memory writem equ 0a1h ;Write to controller memory n.dubl equ 80h ;Double density n.2side equ 40h ;2 sided drive serin equ 03eh ;Address of serial input data, (status - 1) ***************************************************************** * * * Device Specification Table for the Disk Jockey DMA floppy * * * ***************************************************************** if maxdm ne 0 dmdst: db maxdm ;Number of logical drives dw dmwarm ;Warm boot dw dmtran ;Sector cary rar ;Divide by two sub c push psw ;Save adjusted sector jm dmside2 dmsidea:pop psw ;Discard adjusted sector pop b ;Restore sector requested pop d ;Restor address of xlt table dmside1:xchg ;hl <- &(translation table) dad b ;bc = offset into table mov l,m ;hl <- physical sector mvi h,0 ret dmside2:call dmstat ani 20h jz dmsidea pop psw ;Retrieve adjusted sector pop b cma ;Make sector request positive inr a mov c,a ;Make new sector the requested sector pop d call dmside1 mvi a,80h ;Side two bit ora h ; and sector mov h,a ret dmldrv: sta dmlog call dminit ;Test for a drive jc zret lxi h,1 ;Select sector 1 of track 2 shld truesec inx h shld cpmtrk xra a ;Make sure we are doing a read sta rdwr call fill ;Flush buffer and refill jc zret ;Test for error return call dmstat ;Get status on current drive ani 0ch ;Mask in sector size bits push psw ;Used to select a DPB rar lxi h,xlts ;Table of XLT addresses******** if maxmf ne 0 mfdst: db maxmf ;Number of logical drives dw mfwarm ;Warm boot dw mftran ;Sector translation dw mfldrv ;Select drive 1 dw mfsel2 ;Select drive 2 dw dmhome ;Home drive dw mfseek ;Seek to specified track dw mfssec ;Set sector dw dmdma ;Set DMA address dw dmread ;Read a sector dw dmwrite ;Write a sector dw nobad ;No bad sector map mftrck equ 9*512 ;Amount of code on track 0 mfwarm: call mfsel2 ;Select drive 0 lxi h,dmchan ;Set up branch mvi m,bracha inx h mvi m,(mfwchn and 0ffh) ;Low address byte inx h mvi m,(mfwchn / 0100h) ;High address byte inx h mvi m,0 mfwfal: lxi h,mfwend-1 ;Pointer to end of command structure cal docm ;Rea i tracks lda mfwst ;Check out drive status ani 40h ;Test for ok jz mfwfal ;Failed, loop xra a ;Return no error ret mfwchn: db dmsdma ;Set track 0 DMA address dw ccp-512 ;First track DMA address - boot loader db 0 db rdtrck ;Read track command db 0 ;Track 0 db 0  translation dw dmldrv ;Select drive 1 dw dmselr ;Select drive 2 dw dmhome ;Home drive dw dmseek ;Seek to specified track dw dmssec ;Set sector dw dmdma ;Set DMA address dw dmread ;Read a sector dw dmwrite ;Write a sector dw nobad ;No bad sector map dmtrck equ 22*128 ;Amount of code on track 0 dmwarm: call dmselr ;Select drive 0 lxi h,dmchan ;Set up branch mvi m,bracha inx h mvi m,(dmwchn and 0ffh) ;Low address byte inx h mvi m,(dmwchn / 0100h) ;High address byte inx h mvi m,0 dmwbad: lxi h,dmwend-1 ;Pointer to end of command structure call docmd ;Read in tracks lda dmwst ;Get track read status ani 40h jz dmwbad ;Loop on 'terrible' errors like no disk lxi b,300h ;3/4 K bytes of sector 3 needs to be moved lxi d,buffer ;Sector 3 is in our buffer lxi h,ccp+1300h ; and this is where we want it to go... call movbyt xra a ret dmwchn: db dmsdma ;Set track 0 DMA address dw ccp-512 ;First track DMA address - boot loader db 0 db rd mov e,a mvi d,0 dad d push h ;Save pointer to proper XLT call dmget pop d lxi b,2 ;Number of bytes to move call movbyt ;Move the address of XLT lxi d,8 ;Offset to DPB pointer dad d ;HL <- &DPH.DPB push h call dmstat ani 20h ;Check double sided bit lxi d,dpb128s ;Base for single sided DPB's jz dmsok lxi d,dpb128d ;Base of double sided DPB's call sethigh ;Set controller to know about fast steping dmsok: xchg ;HL <- DBP base, DE <- &DPH.DPB pop d ;Restore DE (pointer into DPH) pop psw ;Offset to correct DPB ral ral mov c,a mvi b,0 dad b xchg ;Put DPB address in DPH mov m,e inx h mov m,d lxi h,15 dad d mov c,m dmget: lda dmlog lxi d,dphdm0 jmp retdph sethi: db writem ;Write to controller memory dw stephi ;Point to step rate for fast stepping db 0 ;Extended address 0 dw 2 ;Move two bytes to controller add0: dw 0 ;This address is patched from below to point ;to the drive table for new selected drive db writem ;W;Side 0 db 0 ;Drive 0 dw mfwsec ;Sector load/status map db 0 mfwst db 0 ;Track read status db dmsdma dw ccp+mftrck ;DMA address for track 1 db 0 db rdtrck db 1 ;Track 1 db 0 ;Side 0 db 0 ;Drive 0 dw mfwsec+10 ;Map is loaded right after track 0 status map db 0 mfwend: db 0 ;Track read status dw 0 ;Room for the halt mfwsec: dw 0ffh, 0, 0, 0, 0 ;Do not load boot loader dw 0, 0ffffh, 0ffffh, 0ffffh, 0ffffh ;first two sectors loaded mfssec: dcr c ;Minnie floppy sectors start at zero lda dblflg ;Get double sided flags ora a jz dmssec ;Nope, single sided mvi b,80h ;Set high bit for double sided select jmp dmssec dblflg: db 0 mfseek: xra a ;Clear double sided select sta dblflg lda mfcon ani n.2side jz dmseek ;Only siingle sided mov a,c ;Move selected track in (a) sbi 35 ;Subtract by track by number of tracks jc dmseek ;Less than track 35 mov d,a ;Save adjusted track number mvi a,34 sub d ;Adjust to count tracks back out m ani 80h ;Check density bit mvi c,3 ;512 byte sectors rnz mvi c,2 ;256 byte sectors ret mfgdph lda mflog lxi d,dphmf0 jmp retdph mfcon: db 0 mflog: db 0 mfs: db 10h ;North Star db 0 ;Single density, 35 tracks, single sided. dw dpbmf0 db 90h ;North Star db n.dubl ;Double density, 35 tracks, single sided. dw dpbmf1 db 0b0h ;North Star db n.dubl ;Double density, 35 tracks, single sided. dw dpbmf2 db 0f0h ;North Star db n.dubl+n.2side ;Double density, 35 tracks, souble sided dw dpbmf3 db 0e5h ;North Star. Default format db n.dubl ;Double density, 35 tracks, single sided. dw dpbmf1 db 0 mfxltd db 1, 2, 3, 4 db 21,22,23,24 db 5, 6, 7, 8 db 25,26,27,28 db 9,10,11,12 db 29,30,31,32 db 13,14,15,16 db 33,34,35,36 db 17,18,19,20 db 37,38,39,40 mfxlts db 1, 2 db 3, 4 db 5, 6 db 7, 8 db 9,10 db 11,12 db 13,14 db 15,16 db 17,18 db 19,20 endif ***************************************************** ; Drive select MSB -----------------------+ | ; Drive select LSB --------------------------+ ; dmstat lxi h,dmchan mvi m,gstat ;Set up read status inx h lda lldrv ;Get last selected drive mov m,a ;Store drive in command inx h ;Skip over returned status inx h inx h call docmd ;Issue command lda llss ;Get side bit of last operation ani 80h rrc ;Move to bit 7 mov c,a lxi h,dmchan+1 ;Point to drive mov a,m ;Load drive ora c ani 4 ;Mask upper drive select bit for 5 1/4 rlc rlc ;Move to bit 4 ora m ;Put together with lower drive bits ora c mov c,a inx h mvi a,10h ;Double density bit ana m rlc ;20h rlc ;40h rlc ;80h for density bit ora c mov c,a inx h mvi a,3 ;Sector length mask ana m ;And in rlc ;Move to bits 2 & 3 rlc ora c mov c,a inx h mvi a,4 ;Mask for double sided bit ana m rlc ;8 rlc ;10 rlc ;20 ora c ret dmwrite mvi a,wrsect db 01 ;Ugh... dmread mvi a,rdsect lxi h,dmchan lov c,a ;Resave new track number mvi a,0ffh ;Set double sided flag sta dblflg jmp dmseek mfsel2: sta mflog mvi b,4 ;5 1/4 inch drives start at drive 4 jmp dmsel2 mftran: inr c ;Increment Sector number lda mfcon ani n.dubl lxi h,mfxltd-1 ;Point to double sided sector translation table jnz mftdubl ;Single density sector translation lxi h,mfxlts-1 mftdubl:dad b ;Add offset sector number to table mov l,m ;Pick up sector number from table mvi h,0 ;MSB of sector number equal 0 ret mfldrv: sta mflog call dminit ;Test for a controller jc zret mvi a,n.dubl sta mfcon lxi h,1 ;Select sector 1 of track 0 shld truesec dcx h shld cpmtrk xra a ;Make sure we are doing a read sta rdwr call fill ;Flush buffer and refill jc zret ;Test for error return lda buffer+5ch ;Get diskette configuration byte push psw ;Save configuration byte lxi h,1 shld cpmtrk ;Load track 1 sector 1 call fill ;This is to fix bug with DJDMA firmware on jc zret ;************ * * * Common routines for the DJDMA with 8 and 5 1/4 inch drives * * * ***************************************************************** dmsel2: mov c,a ;Move drive into (c) lxi h,dmchan mvi m,setlog ;Set logical drives inx h mov m,b ;Drive in (b) push b call docmd pop b jmp dmsel dmssec: push b ;Save sector number mov a,b rlc ani 1 mov c,a call dmside pop b jmp dmsec dmdma lxi h,dmchan ;Default channel address mvi m,dmsdma ;Set DMA address inx h mov m,c ;Low byte first inx h mov m,b ;High byte next docmd xra a inx h mov m,a docmd2 inx h mvi m,haltc inx h mov m,a out dmkick tests ora m jz tests ret dminit lxi h,dmchan ;See if controller will halt mvi m,haltc inx h mvi m,0 out dmkick ;Start controller lxi d,0 ;Set up timeout counter dminwt mov a,m ora a jnz dmiok ;Controller has responded dcx d ;Bump timeout counter mov a,d ora e jnz dminwt stc ;Set error flag ret dmiokxi d,lltrk-1 mvi b,4 cload mov m,a inx h inx d ldax d dcr b jnz cload dcx h call docmd lda dmchan+4 cpi 80h cmc ret lltrk db 0 llss db 1 lldrv db 0 dmlog db 0 endif ***************************************************************** * * * The follwing equates are for the HDDMA hard disk controller * * * ***************************************************************** if maxmw ne 0 ;HDDMA controller present ? if m5 ;Specifications for a Seagate Technology 506 cyl equ 153 ;Number of cylinders heads equ 4 ;Number of heads per cylinder precomp equ 64 ;Cylinder to start write precomensation lowcurr equ 128 ;Cylinder to start low current stepdly equ 30 ;Step delay (0-12.7 milliseconds) steprcl equ 30 ;Recalibrate step delay headdly equ 200 ;Settle delay (0-25.5 milliseconds) endif if m16a ;Specifications for an AMPEX DF516 cyl equ 192 heads equ 8 precomp equ 0 lowcurr equ 96 stepdly equ 1 steprcl equ 10 headdly equ 0 endif  returning single density status on track 0 pop psw ora a jnz mfl9 ;Non zero mvi a,90h ;Double density default configuration call dmstat ;If zero then determine sector size ani 80h ;Check density bit jnz mfl9 ;Its double density mvi a,10h ;Single density default configuration byte mfl9: mov c,a ;Move configuration byte into (c) lxi h,mfs ;Address of configuration table -> (hl) mfl2: mov a,m ;Get an entry ora a ;Check for end of the table jz zret ;Yes, select error cmp c ;Check if entry matches selected drive jz mfl3 inx h ;Skip onfiguration byte inx h ;Skip drive type inx h ;Skip DPB address inx h jmp mfl2 mfl3: inx h mov a,m ;Pick up drive type sta mfcon inx h mov a,m inx h mov h,m mov l,a ;DPB address -> (hl) push h ;Save DPB address call mfgdph ;Get DPH lxi d,10 ;Offset to DPB address in DPH dad d pop d mov m,e ;Store DPB address in DPH inx h mov m,d call mfgdph push h call dmstat ;Get status pop h  dcx h ;Back to start of command mvi m,setcrc inx h mvi m,1 xra a jmp docmd2 ;Do command dmerr jmp dmerr dmhome xra a mov c,a ;Put a zero into (c) for track zero dmseek mov a,c ;Enter with track in (c) sta lltrk ;Save for use later ret dmsec lda llss ;Load sector ani 80h ;Save side select bit stores ora c sta llss ret dmside mov a,c ;Move side bit into (a) ani 1 rrc ;Move around to bit 7 mov c,a ;Resave in (c) lda llss ani 7fh ;Mask out old side select bit jmp stores dmsel mov a,c ;Move drive into (a) sta lldrv dmden ret ;Double density only ; Retur statu i th (a) register in the form: ; ; 7 6 5 5 3 2 1 0 ; ^ ^ ^ ^ ^ ^ ^ ^ ; Density --------------+ | | | | | | | ; Side select -------------+ | | | | | | ; Double sided ---------------+ | | | | | ; 5 1/4 -------------------------+ | | | | ; Sector size MSB ------------------+ | | | ; Sector size LSB ---------------------+ | |  if m16c ;Specifications for an CMI 5616 cyl equ 256 heads equ 6 precomp equ 128 lowcurr equ 128 stepdly equ 2 steprcl equ 30 headdly equ 0 endif if m19 ;Specifications for an CMI 5619 cyl equ 306 heads equ 6 precomp equ 128 lowcurr equ 128 stepdly equ 2 steprcl equ 30 headdly equ 0 endif if m40 ;Specifications for a Quantum Q2040 cyl equ 255 heads equ 8 precomp equ 255 lowcurr equ 255 stepdly equ 0 steprcl equ 10 headdly equ 0 endif sectsiz equ 7 ;Sector size code (must be 3 for this Cbios) ; 0 = 128 byte sectors ; 1 = 256 byte sectors ; 3 = 512 byte sectors (default) ; 7 = 1024 byte sectors ; f = 2048 byte sectors ;Define controller commands dmaread equ 0 ;Read sector dmawrit equ 1 ;Write sector dmarhed equ 2 ;Find a sector dmawhed equ 3 ;Write headers (format a track) dmalcon equ 4 ;Load disk parameters dmassta equ 5 ;Sense disk drive status dmanoop equ 6 ;Null controller operation reset equ 54h ;Reset controller dmadma push h push psw call mwwread ;Read in a sector jnc mwwlod ret ;Return with error mwwread mvi c,retries ;Retry counter mwwerr push b ;Save the retry count call mwread ;Read the sector pop b rnc dcr c ;Update the error count jnz mwwerr ;Keep trying if not too many errors stc ;Set error flag ret mwldrv sta mwcurl ;Save current logical drive call mwreset ;Reset controller card jc zret ;Controller failure lda mwcurl call mwdrv ;Select drive jc zret ;Select error call mwstat ;Get drive status ani dready ;Check if drive ready jnz zret call mwhome ;Home drive lxi d,dphmw0 ;Start of hard disk DPH's lda mwcurl mov l,a mvi h,0 dad h dad h dad h dad h dad d ;(hl) = pointer to DPH mvi c,4 ;Return sector size of 1024 ret mwdr sta mwcurl call mwdlog mov a,c sta mwdrive ;Save new selected drive mwsel mvi a,dmanoop jmp mwprep ;Execute disk command mwdlog: mvi c,0 mwllx: sui mwlog rc inr c jmp mwi h,dmarg1 ;Load arguments mvi m,stepdly ;Load step delay inx h mvi m,headdly ;Head settle delay inx h mvi m,sectsiz ;Sector size code inx h mvi m,dmalcon ;Load constants command jmp mwissue ;Do load constants mwread mvi a,dmaread ;Load disk read command jmp mwprep mwwrite mvi a,dmawrit ;Load disk write command mwprep sta dmaop ;Save command channel op code mvi c,band1 lhld dmarg0 lxi d,precomp call mwhlcde jc mwpreps mvi c,band2 lxi d,lowcurr call mwhlcde jc mwpreps mvi c,band3 ;cylinder > low_current mwpreps lda mwhead ;Load head address sta dmarg2 cma ;Negative logic for the controller ani 7 ;3 bits of head select rlc ;Shove over to bits 2 - 4 rlc ora c ;Add on low current and precomp bits mov c,a lda mwdrive ;Load drive address ora c ;Slap in drive bits sta dmasel1 ;Save in command channel head select lda mwsectr ;Load sector address sta dmarg3 mwissue lxi h,dmastat ;Status byte mvi m,0 out attn ;Start cont attn equ 55h ;Send a controller attention chan equ 50h ;Default channel address stepout equ 10h ;Step direction out stepin equ 0 ;Step direction in band1 equ 40h ;No precomp, high current band2 equ 0c0h ;Precomp, high current band3 equ 80h ;precomp, low current track0 equ 1 ;Track zero status wflt equ 2 ;Write fault from drive dready equ 4 ;Drive ready sekcmp equ 8 ;Seek complete ***************************************************************** * * * Drive Specification Table for the HD DMA hard disk controller * * * ***************************************************************** mwdst: db maxmw*mwlog ;Number of logical drives dw mwwarm ;Warm boot dw mwtran ;Sector translation dw mwldrv ;Select logical drive 1 (First time select) dw mwdrv ;Select logical drive 2 (General select) dw mwhome ;Home current selected drive dw mwseek ;Seek to selected track dw mwsec ;Select sector dw mwdma ;Set DMA address dw mwread ;Read a sector dw mwwllx mwstat mvi a,dmassta ;Sense status operation code jmp mwprep ;Execute disk command mwhome call mwreset ;Reset controller lxi h,dmarg1 ;Load arguments mvi m,steprcl ;Load step delay (slow) inx h mvi m,headdly ;Head settle delay call mwissue ;Do load constants again call mwptr ;Get pointer to current cylinder number mvi m,0ffh ;Fake at cyl 255 for max head travel inx h mvi m,0ffh lxi b,0 ;Seek to cylinder 0 call mwseek ;Recal slowly jmp mwreset ;Back to fast stepping mode mwbad: lxi h,mwbtab ;Return pointer to bad sector location ret mwbtab: dw 0 ;Track 0 dw 19 ;Head 2, sector 0 = (2 * SPT + 0) + 1 mwseek cal mwptr ;Ge trac pointer mov e,m ;Get old track number inx h mov d,m dcx h mov m,c ;Store new track number inx h mov m,b mov l,c ;Build cylinder word mov h,b shld dmarg0 ;Set command channel cylinder number mov a,d inr a lxi h,0ffffh jnz mwskip0 mvi c,stepout jmp mwskip mwskip0:mov h,b ;(hl) = new traroller lxi d,0 ;Time out counter mov b,e ;Controller busy status mwiloop mov a,m ;Get status ora a ;Set up CPU flags rm ;Return no error (carry reset) stc rnz ;Return error status xthl ;Waste some ime xthl xthl xthl dcx d ;Bump timeout counter mov a,d ora e jnz mwiloop ;Loop if still busy stc ;Set error flag ret mwptr lda mwdrive ;Get currently select drives track address rlc mov e,a mvi d,0 lxi h,mwtab dad d ;Offset into track table ret mwtran: mov h,b mov l,c inx h ret mwneghl:mov a,h cma mov h,a mov a,l cma mov l,a inx h ret mwhlmde:xchg call mwneghl xchg dad d ret mwhlcde:mov a,h cmp d rnz mov a,l cmp e ret mwtab equ $ ;Collection of track addresses rept maxmw db 0ffh ;Initialize to (way out on the end of the disk) db 0ffh endm db 0ffh mwcurl db 0 ;Current logical drive mwdrive db 0ffh ;Currently selected drive mwhead db 0 ;Currently selected head mwsectr db 0 ;Currentrite ;Write a sector dw mwbad ;Return bad sector map info ***************************************************************** * * * Th followin ar th lowes leve driver fo th Morro * * Design Har Dis DM controller. * * * ***************************************************************** mwwarm xra a call mwdrv ;Select drive A call mwhome ;Home and reset the drive lxi b,0 ;Make sure we are on track 0 call mwseek xra a sta mwhead ;Select head zero sta mwsectr ;Select sector 1 lxi h,buffer ;Load sector 1 into buffer shld dmadma call mwwread ;Read CCP into buffer rc ;Return if error lxi d,buffer+200h lxi h,ccp lxi b,200h ;Move 200h bytes call movbyt lxi h,ccp-200h ;Initial DMA address push h xra a push a ;Save first sector -1 mwwlod pop psw ;Restore sector pop h ;Restore DMA address inr a sta mwsectr cpi 6 ;Past BDOS ? rz ;Yes, all done inr h ;Update DMA address by 1024 bytes inr h inr h inr h shldck, (de) = old track mov l,c call mwhlmde mvi c,stepout mov a,h ani 80h ;Check hit bit for negitive direction jnz mwsout ;Step in mvi c,0 jmp mwskip mwsout: call mwneghl mwskip: shld dmastep lda mwdrive ora c sta dmasel0 mv a,dmanoo ;No-operatio comman fo th channel call mwprep ;Step to proper track lxi h,0 ;Clear step counter shld dmastep ret mwdma mov h,b ;Set DMA address mov l,c shld dmadma ret mwsec mov a,c ;Load sector number dcr a ;Range is actaully 0-16 call mwdspt ;Figure out head number -> (c) adi mwspt ;Make sector number sta mwsectr mov a,c sta mwhead ;Save head number ret mwdspt mvi c,0 ;Clear head counter mwdsptx sui mwspt ;Subtract a tracks worth of sectors rc ;Return if all done inr c ;Bump to next head jmp mwdsptx mwreset out reset ;Send reset pulse to controller lxi h,dmachan ;Address of command channel shld chan ;Default channel address xra a sta chan+2 ;Clear extended address byte lxly selected sector dmachan equ $ ;Command channel area dmasel0 db 0 ;Drive select dmastep dw 0 ;Relative step counter dmasel1 db 0 ;Head select dmadma dw 0 ;DMA address db 0 ;Extended address dmarg0 db 0 ;First argument dmarg1 db 0 ;Second argument dmarg2 db 0 ;Third argument dmarg3 db 0 ;Fourth argument dmaop db 0 ;Operation code dmastat db 0 ;Controller status byte dmalnk dw dmachan ;Link address to next command channel db 0 ;extended address endif ***************************************************************** * * * Cbios ram locations that don't need initialization. * * * ***************************************************************** cpmsec: dw 0 ;CP/M sector # cpmdrv: db 0 ;CP/M drive # cpmtrk: dw 0 ;CP/M track # truesec:dw 0 ;Physical sector that contains CP/M sector bufdrv: db 0 ;Drive that buffer belongs to buftrk: dw 0 ;Track that buffer belongs to bufsec: dw 0 ;Sector that buffer belongs to alttrk: dw 0 ;Alternatedpbhd0 dw 672 ;CP/M sectors/track db 5 ;BSH db 31 ;BLM db 1 ;EXM dw 2015 ;DSM dw 511 ;DRM db 0ffh ;AL0 db 0ffh ;AL1 dw 0 ;CKS dw 1 ;OFF dpbhd1 dw 672 ;CP/M sectors/track db 5 ;BSH db 31 ;BLM db 1 ;EXM dw 2015 ;DSM dw 511 ;DRM db 0ffh ;AL0 db 0ffh ;AL1 dw 0 ;CKS dw 98 ;OFF dpbhd2 dw 672 ;CP/M sectors/track db 5 ;BSH db 31 ;BLM db 1 ;EXM dw 1028 ;DSM dw 511 ;DRM db 0ffh ;AL0 db 0ffh ;AL1 dw 0 ;CKS dw 195 ;OFF endif endif endi ;En o H DPH' an DPB's if maxmf ne 0 dpbgen mf,0, 20, 3, 7, 0, 04fh, 63, 0c0h, 0, 16, 3 dpbgen mf,1, 40, 4, 15, 1, 051h, 63, 80h, 0, 16, 2 dpbgen mf,2, 40, 3, 7, 0, 0a4h, 63, 0c0h, 0, 16, 2 dpbgen mf,3, 40, 4, 15, 1, 0a9h, 63, 80h, 0, 16, 2 dn set 0 rept maxmf dphgen mf,%dn,dpbmf,%dn dn set dn+1 endm endif if maxfd ne 0 dn set 0 rept maxfd dphgen fd,%dn,0,0 dn set dn+1 endm endif if maxdm ne 0 dn set 0 rept maxdm dphgen dm,%dn,0,0 d********************** prompt: db 80h, clear ;Clean buffer and screen db acr,alf,acr,alf,acr,alf db 'Morrow Designs ' db '0'+msize/10 ;CP/M memory size db '0'+(msize mod 10) db 'K CP/M ' ;CP/M version number db cpmrev/10+'0' db '.' db (cpmrev mod 10)+'0' db (revnum/10)+'A'-1 if (maxhd ne 0) or (maxmw ne 0) db ' + ' if maxhd ne 0 if m10 ne 0 db 'M10' endif if m20 ne 0 db 'M20' endif if m26 ne 0 db 'M26' endif if maxmw ne 0 db ' + ' endif endif if maxmw ne 0 if m5 ne 0 db 'Seagate M5' endif if m16a ne 0 db 'Ampex M16' endif if m16c ne 0 db 'CMI M16' endif if m19 ne 0 db 'CMI M19' endif if m40 ne 0 db 'Quantum M40' endif endif endif db acr,alf db 0 ;End of message ***************************************************************** * * * Cboot is the cold boot loader. All of CP/M has been loaded in * * when control is passed here. * * * ********************************************** track altsec: dw 0 ;Alterante sector lastdrv:db 0 ;Last selected drive ***************************************************************** * * * DPB and DPH area. * * * ***************************************************************** if maxhd ne 0 dphdsk set 0 ;Generate DPH's for the hdc3 hard disks rept maxhd ldsk set 0 rept hdlog dphgen hd,%dphdsk,dpbhd,%ldsk dphdsk set dphdsk+1 ldsk set ldsk+1 end endm if hdpart ne 0 ;Use non-standard partitioning if m10 ne 0 hdsecpt equ 336 ;Sectors per track hdbls equ 2562 ;Total blocks hdtrks equ 244 ;Total tracks endif if m20 ne 0 hdsecpt equ 672 hdbls equ 5124 hdtrks equ 244 endif if m26 ne 0 hdsecpt equ 1024 hdbls equ 6464 hdtrks equ 202 endif ldsk set 0 ;Generate DPB's for a hdc3 hard disk rept hdlog if ldsk eq 0 ;On logical drive 0 dsm set (hdbls/hdlog)-(hdbls/hdtrks+1) ; take off a tracks worth else dsm set hdbls/hdlog endif off set (hdtrks/hdlog)*ldsk+1 n set dn+1 endm endif if maxmw ne 0 ***************************************************************** * * * mwsectp is the number of 128 byte sectors per cylinder. * * mwsectp = 2.25 * heads * * * * mwtrks is the total number of data cylinders. * * mwtrks = tracks - 1 * * * * mwbls is the total number of 4096 byte blocks. * * mwbls = mwsecpt*mwtrks/32 * * * ***************************************************************** if m5 ne 0 mwsecpt equ 288 ;Sectors per track mwbls equ 1368 ;Total data blocks (4096 byte) mwtrks equ 152 ;Total data tracks endif if m16a ne 0 mwsecpt set 576 mwbls set 3438 mwtrks set 191 endif if m16c ne 0 mwsecpt set 432 mwbls set 3442 mwtrks set 255 endif if m19 ne 0 mwsecpt set 432 mwbls set 4117 mwtrks set 305 endif if m40 ne 0 mwsecpt set 576 mwbls set 9198 mwtrks set 511 endif dphdsk set 0 ;Generate DPH's for the HDDMA hard disks rept maxmw ldsk******************* cboot: lxi sp,tpa ;Set up stack xra a ;Clear cold boot flag sta cwflg sta group ;Clear group select byte mvi a,intioby sta iobyte lxi d,badmap ;Clear out bad map stax d lxi h,badmap+1 lxi b,9*badsiz ;32 map entries call movbyt mvi m,0ffh ;End marker if contyp ne 0 ;Do not call tinit for PROM's call tinit ;Initialize the terminal endif if lsttyp ne 0 ;Do not call linit for PROM's call linit ;Initialize the list device endif lxi h,prompt ;Prep for sending signon message call message ;Send the prompt xra a ;Select disk A sta cpmdrv sta cdisk lxi h,bios+3 ;Patch cold boot to warm code shld bios+1 jmp gocpm if contyp eq 2 ;Multi I/O, Decision I ***************************************************************** * * * Terminal initilization routine. This routine reads the sense * * switch on the WB-14 and sets the speed accordingly. * * * ********************************************************** dpbgen hd,%ldsk,%hdsecpt,5,31,1,%dsm,511,0ffh,0ffh,0,%off ldsk set ldsk+1 endm else ;Else use standard DPH's if m26 ne 0 dpbhd0 dw 1024 ;CP/M sectors/track db 5 ;BSH db 31 ;BLM db 1 ;EXM dw 1973 ;DSM dw 511 ;DRM db 0ffh ;AL0 db 0ffh ;AL1 dw 0 ;CKS dw 1 ;OFF dpbhd1 dw 1024 ;CP/M sectors/track db 5 ;BSH db 31 ;BLM db 1 ;EXM dw 1973 ;DSM dw 511 ;DRM db 0ffh ;AL0 db 0ffh ;AL1 dw 0 ;CKS dw 64 ;OFF dpbhd2 dw 1024 ;CP/M sectors/track db 5 ;BSH db 31 ;BLM db 1 ;EXM dw 1973 ;DSM dw 511 ;DRM db 0ffh ;AL0 db 0ffh ;AL1 dw 0 ;CKS dw 127 ;OFF endif if m10 ne 0 dpbhd0 dw 336 ;CP/M sectors/track db 5 ;BSH db 31 ;BLM db 1 ;EXM dw 1269 ;DSM dw 511 ;DRM db 0ffh ;AL0 db 0ffh ;AL1 dw 0 ;CKS dw 1 ;OFF dpbhd1 dw 336 ;CP/M sectors/track db 5 ;BSH db 31 ;BLM db 1 ;EXM dw 1280 ;DSM dw 511 ;DRM db 0ffh ;AL0 db 0ffh ;AL1 dw 0 ;CKS dw 122 ;OFF endif if m20 ne 0  set 0 rept mwlog dphgen mw,%dphdsk,dpbmw,%ldsk dphdsk set dphdsk+1 ldsk set ldsk+1 end endm if mwpart ne 0 ;Generate DPB's for a HDDMA hard disk ldsk set 0 ;Use non-standard partitioning rept mwlog dsm set mwbls/mwlog-1 off set (mwtrks/mwlog)*ldsk+1 dpbgen mw,%ldsk,%mwsecpt,5,31,1,%dsm,511,0ffh,0ffh,0,%off ldsk set ldsk+1 endm else ;Use standard partitioning blocks set mwbls off set 1 trkoff set 8000h/(mwsecpt*10h/32)+1 ldsk set 0 rept mwbls/2048 ;Generate some 8 megabyte DPB's dpbgen mw,%ldsk,%mwsecpt,5,31,1,2047,511,0ffh,0ffh,0,%off off set off+trkoff blocks set blocks-2048 ldsk set ldsk+1 endm if blocks gt 256 ;If there is any stuff left, then use it blocks set blocks-1 dpbgen mw,%ldsk,%mwsecpt,5,31,1,%blocks,511,0ffh,0ffh,0,%off endif endif endif buffer equ $ ***************************************************************** * * * Signon message output during cold boot. * * * ************************************************** tinit: lda group ;Get group byte ori congrp ;Select console device out grpsel mvi a,dtrenb+rtsenb ;Enable DTR and RTS outputs to terminal out mcr in rbr ;Clear reciever buffers in rbr xra a out lsr ;Clear status out ier ;Set no interrupts if not multr3 ;Multi I/O has no sense switches lda group ;Get group byte out grpsel ;Select group zero to read sense switch in sensesw ;Get sense switch. ani 0e0h ;Mask in upper three bits rlc rlc rlc ;Move into lower 3 bits cpi 7 ;check for sense = 7 push psw ;Save value lda group ;Get group byte ori congrp ;Reselect serial port group out grpsel pop psw jz valid ;Do default rate lxi h,btab ;Pointer to baud rate table add a ;Table of words so double mov e,a ;Make a 16 bit number into (de) mvi d,0 dad d ;Get a pointer into baud rate table mov e,m ;Get lower byte of word inx h ;Point to high byte of word mov d,m ;Get upper byte. (de) now has divisor jmp setit ;Set baud atch out lcr ;Set the baud rate in (de) mov a,d out dlm ;Set upper divisor mov a,e out dll ;Set lower divisor mvi a,wls1+wls0+stb out lcr done: xra a ;Clear status register out lsr ret endif ;Multi I/O, Decision I if contyp eq 3 ;2D/B console initialization tinit: call fdtstat ;Clean input buffer rnz ;All empty call fdcin jmp tinit endif ;2D/B console if contyp eq 4 tinit: call dminit ;See if controller present rc ;No controller, return lxi d,dmaci ;Console initialization command sequence lxi h,dmchan lxi b,10 ;Command length call movbyt dcx h xra a ;Clear serial input status sta serin+1 jmp docmd2 ;Do stuff and return dmaci: db writem ;Zot monitor disable flag dw tinit ;Any non-zero byte will do db 0 dw 1 ;One byte dw 13f5h ;Magical place in monitor db senabl ;Enable serial input db 1 endif if (lsttyp ge 2) and (lsttyp le 5) ;Serial Multi I/O list drivers linit: lda group ;Get group byte ori lndif linit9: lxi h,hinc/cperi shld hmi ;Save hmi = 120/(characters per inch) lxi h,vinc/lperi shld vmi ;Save vmi = 48/(lines per inch) lxi h,0 ;Other variables default to zero shld vpos shld dlvpos shld hpos shld dlhpos shld lmar call clrall ;Clear the TAB array xra a sta kludge ;Reset TAB clear byte sta dirflg sta grhflg ret endif db 0,0ffh,0 codelen equ ($-bios) ;Length of Cbios code if debug dbgtmp set codelen ;Cbios code length ! endif ds 512-($-buffer) ;Maximum size buffer for 512 byte sectors if (maxfd ne 0) or (maxdm ne 0) or (maxmw ne 0) ds 512 ;Additional space for 1k sector devices endif ***************************************************************** * * * Each bad map entry consists of 9 bytes: * * Logical drive number (1 byte) * * Track number of bad sector (2 bytes) * * Sector number of bad sector (2 bytes) * * Track number of alternate sector (2 bytes) * * Sector number of alrate. btab: dw 1047 ;110 Baud 000 dw 384 ;300 001 dw 96 ;1200 010 dw 48 ;2400 011 dw 24 ;4800 100 dw 12 ;9600 101 dw 6 ;19200 110 else jmp valid ;Skip over table endif ***************************************************************** * * * The following is a list of valid baud rates. The current * * baud rate is checked on cold boot. If it is not in the * * vtab table then the baud rate will be set from the defcon * * word found below the Cbios jump table. If the user * * happens to have a weird baud rate that is not in this * * table or is looking for a way to save space then entries * * can be added or deleted from the table. * * * ***************************************************************** vtab: dw 2304 ;50 baud dw 1536 ;75 dw 1047 ;110 dw 857 ;134.5 dw 768 ;150 dw 384 ;300 dw 192 ;600 dw 96 ;1200 dw 64 ;1800 dw 58 ;2000 dw 48 ;2400 dw 32 ;3600 dw 24 ;4800 dw 16 ;7200 dw 12 ;9600 dw 6 stgrp ;Select list device out grpsel mvi a,dlab ;Access divisor latch out lcr lhld deflst ;Get LST: baud rate divisor mov a,h out dlm ;Set upper baud rate mov a,l out dll mvi a,stb+wls0+wls1 out lcr in rbr ;Clear input buffer xra a out ier ;No interupts ret endif if lsttyp eq 6 ;Multi I/O parallel, Centronics linit: lda group ;Get group byte ori denable ;Set driver enable bit sta group out grpsel ;Select group zero with drivers enabled xra a out daisi1 ;Zero out data mvi a,d9+d10 ;Set strobe high, init low out daisi0 mvi a,10 ;Wait about 50uS for printer to initilize dloop: dcr a jnz dloop mvi a,d11+d9+d10 out daisi0 ret endif if lsttyp eq 7 ;Diablo HyType II ***************************************************************** * * * Initialize Diablo HyType printer. If the printer fails * * to initialize then the output drivers will be turned off * * and any attempts to print will result in redirection to * * the cternate sector (2 bytes) * * * ***************************************************************** badmap: ds badsiz*9+1 ;32 entries + end marker dirbuf: ds 128 ;Directory buffer ***************************************************************** * * * Allocation and checked directory table area * * * ***************************************************************** if maxhd ne 0 if hdpart ne 0 ;Use non-standard partitioning dn set 0 rept maxhd ;Generate CKS and ALV tables ldsk set 0 rept hdlog if ldsk eq 0 ;On logical drive 0 dsm set (hdbls/hdlog)-(hdbls/hdtrks+1) ; take off a tracks worth else dsm set hdbls/hdlog endif alv set (dsm/8)+1 alloc hd,%dn,%((hdbls/hdlog)/8)+1,0 ldsk set ldsk+1 dn set dn+1 endm endm else ;Standard partitioning dn set 0 rept maxhd if m26 ne 0 alloc hd,%dn,247,0 dn set dn+1 alloc hd,%dn,247,0 dn set dn+1 alloc hd,%dn,247,0 dn set dn+1 endif if m10 ne 0 alloc hd,%dn,159,0 dn set dn+ ;19200 svtab equ ($-vtab)/2 ;Length of the vtab table ***************************************************************** * * * Valid checks if the divisor latch is a reasonable value. * * If the value seems off then it will get the default baud * * rate from defcon and jump to setit. * * * ***************************************************************** valid: mvi a,dlab+wls0+wls1+stb out lcr ;Access divisor latch in dll ;Get lower divisor value mov e,a in dlm ;Get upper divisor value mov d,a mvi a,wls1+wls0+stb out lcr lxi h,vtab ;Valid baud rate table mvi c,svtab ;Length of the baud rate table vloop: mov a,e cmp m ;Check low byte jnz vskip ;First byte is bad inx h mov a,d cmp m ;Check high byte jz done ;Baud rate is OK... Do cleanup dcx h vskip: inx h ;Skip to next entry inx h dcr c ;Bump entry counter jnz vloop nvalid: lhld defcon ;Get default baud rate xchg setit: mvi a,dlab+wls1+wls0+stb ;Enable divisor access lonsole. * * * ***************************************************************** if multr3 ;Multi I/O initialization linit: lda group ;Get group byte ori denable ;Add driver enable bit out grpsel ori rest ;Toggle restore high out grpsel mvi a,10 ;Hold line up for 50uS dloop: dcr a jnz dloop lda group out grpsel ;Turn denable and restore off else ;Mother board initialization linit: lda group ;Get group byte out grpsel ;Select group zero mvi a,pselect+rlift ;Set select line active, rlift not active out clk mvi a,0ffh out daisi0 mvi a,0ffh-rest ;Strobe restore bit low out daisi0 mvi a,10 ;Wait about 50uS dloop: dcr a jnz dloop mvi a,0ffh ;Raise restore back up out daisi0 endif xra a out daisi1 ;Clear data buffers if multr3 ;Lift ribbon lda group ori denable out grpsel ;Re-enable the drivers mvi a,0ffh-rest ;Pull -ribbon lift down out daisi0 else mvi a,pselect ;Re-enable drivers and lift ribbon out clk e; Skeletal CBIOS for first level of CP/M 2.0 alteration ; msize equ 20 ;cp/m version memory size in kilobytes ; ; "bias" is address offset from 3400H for memory systems ; than 16K (referred to as "b" throughout the text). ; bias equ (msize-20)*1024 ccp equ 3400H+bias ;base of ccp bdos equ ccp+806h ;base of bdos bios equ ccp+1600h ;base of bios cdisk equ 0004H ;current disk number 0=A,...,15=P iobyte equ 0003h ;intel i/o byte ; org bios ;origin of this program nsects equ ($-ccp)/128 ;warm start sector count ; ; jump vector for individual subroutines jmp boot ;cold start wboote: jmp wboot ;warm start jmp const ;console status jmp conin ;console character in jmp conout ;console character out jmp list ;list character out jmp punch ;punch character out jmp reader ;reader character out jmp home ;move head to home position jmp seldsk ;select disk jmp settrk ;set track number jmp setsec ;set sector number jmp setdma ;set dma address jmp read ;read disk jmp ess 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 cpi 00h ;any errors? 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 mov a,d ;sector=27?, if so, change tracks cpi 27 jc load1 ;carry generated if sector<27 ; ; 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 settr;must be between 0 and 3 rnc ;no carry if 4,5,... ; disk number is in the proper range ds 10 ;space for disk select ; compute proper disk parameter header address lda diskno mov l,a ;L=disk number 0,1,2,3 mvi h,0 ;high order zero dad h ;*2 dad h ;*4 dad h ;*8 dad h ;*16 (size of each header) lxi d,dpbase dad d ;HL=.dpbase(diskno*16) ret ; settrk: ;set track given by register c mov a,c sta track ds 10h ;space for track select ret ; setsec: ;set sector given by register c mov a,c sta sector ds 10h ;space for sector select ret ; sectran: ;translate the sector given by BC using the ;translate table given by DE xchg ;HL=.trans dad b ;HL=.trans(sector) mov l,m ;L = trans(sector) mvi h,0 ;HL= trans(sector) ret ;with value in HL ; setdma: ;set dma address given by registers b and c mov l,c ;low order address mov h,b ;high order address shld dmaad ;save the address ds 10h ;space for setting the dma address ret ; read: ;perform read operatiowrite ;write disk jmp listst ;return list status jmp sectran ;sector translate ; ; fixed data tables for four-drive standard ; IBM-compatible 8" disks ; disk parameter header for disk 00 dpbase: dw trans,0000H dw 0000H,0000H dw dirbf,dpblk dw chk00,all00 ; disk parameter header for disk 01 dw trans,0000H dw 0000H,0000H dw dirbf,dpblk dw chk01,all01 ; disk parameter header for disk 02 dw trans,0000H dw 0000H,0000H dw dirbf,dpblk dw chk02,all02 ; disk parameter header for disk 03 dw trans,0000H dw 0000H,0000H dw dirbf,dpblk dw chk03,all03 ; ; sector translate vector trans: db 1,7,13,19 ;sectors 1,2,3,4 db 25,5,11,17 ;sectors 5,6,7,8 db 23,3,9,15 ;sectors 9,10,11,12 db 21,2,8,14 ;sectors 13,14,15,16 db 20,26,6,12 ;sectors 17,18,19,20 db 18,24,4,10 ;sectors 21,22,23,24 db 16,22 ;sectors 25,26 ; dpblk: ;disk parameter block, common to all disks dw 26 ;sectors per track db 3 ;block shift factor db 7 ;block mask db 0 ;null mask dw 242 ;disk ;track address set from register c pop h pop d pop b jmp load1 ;for another sector ; ; end of load operation, set parameters and go to cp/m gocpm: mvi a,0c3h ;c3 is a jmp instruction sta 0 ;for jmp to wboot lxi h,wboote ;wboot entry point shld 1 ;set address field for jmp at 0 ; sta 5 ;for jmp to bdos lxi h,bdos ;bdos entry point shld 6 ;address field of jump at 5 to bdos ; lxi b,80h ;default dma address is 80h call setdma ; ei ;enable the interrupt system lda cdisk ;get current disk number mov c,a ;send to the ccp jmp ccp ;go to cp/m for further processing ; ; ; simple i/o handlers (must be filled in by user) ; in each case, the entry point is provided, with space reserved ; to insert your own code ; const: ;console status, return 0ffh if character ready, 00h if not ds 10h ;space for status subroutine mvi a,00h ret ; conin: ;console character into register a ds 10h ;space for input routine ani 7fh ;strip parity bit ret ; conout: ;console charan (usually this is similar to write ; so we will allow space to set up read command, then use ; common code in write) ds 10h ;set up read command jmp waitio ;to perform the actual i/o ; write: ;perform a write operation ds 10h ;set up write command ; waitio: ;enter here from read and write to perform the actual i/o ; operation. return a 00h in register a if the operation completes ; properly, and 01h if an error occurs during the read or write ; ; in this case, we have saved the disk number in 'diskno' (0,1) ; the track number in 'track' (0-76) ; the sector number in 'sector' (1-26) ; the dma address in 'dmaad' (0-65535) ds 256 ;space reserved for I/O drivers mvi a,1 ;error condition ret ;replaced when filled-in ; ; the remainder of the CBIOS is reserved uninitialized ; data area, and does not need to be a part of the ; system memory image (the space must be available, ; however, between "begdat" and "enddat"). ; track: ds 2 ;two bytes for expansion sector: ds 2 ;two k size-1 dw 63 ;directory max db 192 ;alloc 0 db 0 ;alloc 1 dw 16 ;check size dw 2 ;track offset ; ; end of fixed tables ; ; individual subroutines to perform each function boot: ;simplest case is to just perform parameter initialization xra a ;zero in the accum sta iobyte ;clear the iobyte sta cdisk ;select disk zero jmp gocpm ;initialize and go to cp/m ; wboot: ;simplest case is to read the disk until all sectors loaded lxi sp,80h ;use space below buffer for stack mvi c,0 ;select disk 0 call seldsk call home ;go to track 00 ; mvi b,nsects ;b counts # of sectors to load mvi c,0 ;c has the current track number mvi d,2 ;d has the next sector to read ; note that we begin by reading track 0, sector 2 since sector 1 ; contains the cold start loader, which is skipped in a warm start lxi h,ccp ;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 addrcter output from register c mov a,c ;get to accumulator ds 10h ;space for output routine ret ; list: ;list character from register c mov a,c ;character to register a ret ;null subroutine ; listst: ;return list status (0 if not ready, 1 if ready) xra a ;0 is always ok to return ret ; punch: ;punch character from register c mov a,c ;character to register a ret ;null subroutine ; ; reader: ;read character into register a from reader device mvi a,1ah ;enter end of file for now (replace later) ani 7fh ;remember to strip parity bit ret ; ; ; i/o drivers for the disk follow ; for now, we will simply store the parameters away for use ; in the read and write subroutines ; home: ;move to the track 00 position of current drive ; translate this call into a settrk call with parameter 00 mvi c,0 ;select track 0 call settrk ret ;we will move to 00 on first read/write ; seldsk: ;select disk given by register C lxi h,0000h ;error return code mov a,c sta diskno cpi 4 bytes for expansion dmaad: ds 2 ;direct memory address diskno: ds 1 ;disk number 0-15 ; ; scratch ram area for BDOS use begdat equ $ ;beginning of data area dirbf: ds 128 ;scratch directory area all00: ds 31 ;allocation vector 0 all01: ds 31 ;allocation vector 1 all02: ds 31 ;allocation vector 2 all03: ds 31 ;allocation vector 3 chk00: ds 16 ;check vector 0 chk01: ds 16 ;check vector 1 chk02: ds 16 ;check vector 2 chk03: ds 16 ;check vector 3 ; enddat equ $ ;end of data area datsiz equ $-begdat;size of data area end maad' (0-65535) ds 256 ;space reserved for I/O drivers mvi a,1 ;error condition ret ;replaced when filled-in ; ; the remainder of the CBIOS is reserved uninitialized ; data area, and does not need to be a part of the ; system memory image (the space must be available, ; however, between "begdat" and "enddat"). ; track: ds 2 ;two bytes for expansion sector: ds 2 ;two z8O!B N#N ¾SP.* |} !9":q!"28!"9:] !ç 1;#ø##>%><7"T6*}^!T42 G Ͱ *hMͽG:ͮ+GGW +GU!ͩ>̀+! @!!BH @@ABH B! "BHI$$BI$BI $ HI D$HD$$ H B!$D$"$B$DA!ABI$H B$I $HI$H$! $I $I$$A !A@$I$"!$H$I$I "! $A$  HHAA"I @$BH! $!D$H$ I$$DH@H"B$HDDH@$""A $@ D$BB H A$$BAB"DH I$I "D H@ @@" @D"II!$I A"UUUI$$ D$$"#"!N#FW" *D>7Å*G|H+"G H:FBÅ> Å >* *͍ \" ( *"W !)~##{nZ*F#h!Cs!^#V   ##::^#V#þ*^#V>%#x'8_#*͍ !" >- Ͱ Aڥ ҥ _!7^#V~  \p Z t ů2[\͍͢ ҥ ͊ =¥ ` " ͍ ҥ ͊ ʻ` " =ʻ` "=¥ ý> 2͊ ` "W=` =¥ *W}o"Y  *W"[( Ϳ ~ #? }"W*[Ϳ 0 *W}#|#*W? ͊ ¥ ` ` ` {zA|¥ W}d ͊ ` ` ` DMʡڏ"=ʡͲ=ʡYPͲ1**!I~4#~#F#x~#s#r#w>͊ ¥ ` `  ( Ϳ ᯕo>g( 2|2\  !]w# ʥ .&  0 6 #& .K !e K w# ʥ : U 6 #K 6AW w#] !e~H#~E#~X*}|{ "!{ ͊ !ʦ =¥ ` kʥ j \͢@ w# ͅ ú n ʥ : W _ O { `i"@ w# ͅ ¥ n S n S GтWx ͢!i ~T #H  *( Ϳ *(  NEXT PC͊ =¥ `  ( Ϳ ~ Ϳ Ͱ ʵ .͍ =¥ ` |¥ }w#~ ÿ >2F͊ ! =¥ ` }ʥ +"G> Å >  !  # =COPYRIGHT (C) 1978, DIGITAL RESEARCH DDT VERS 2.0$10 !~=W!xe ~#Xbxʇ {z~#o}o҃i.*|g> >کÝ!p+q*DM͡:͆ ͆:_2:`!!:*& N͆!4!6ÃO$+q+p+qy͏ , $  ͌ 9!z6 # L!zw͌j# X:z 0 ͘=N#Fy}80*z{¯#z+++ ¥ z#½# · 9!`͠ y9!rͷ y=!z{w# % w!P͠ y͓}*w#"͌ @.@<!Eͷ~P !ͷ’P͌Q!ͷªP}QxQ!ͷ͓G@Q! ͷ y͓Gþ!ͷ ͓Q!ͷ͓Q͌Q!.ͷ6y#G͙Qà!2ͷQ͓͌Q!>ͷq eg͙Q:zJEËC–EQyQxQRQ** {zҷ*~#" <AOGƐ'@'OxƐ'@'ON#  ¥   Ϳ Ͱ ͊ =¥ ` xS |¥ }ҥ gA>M Ag}M M c |¥ }!w s#r:[ʎ _!~ʠ ![4á \͢  2[y 7 >?  _͢!a"]> _͢a_!`~> 5*]~#"] 0 7   > >  ͢| } : >. *Y}o| , 0 å ^#V#!S ))))o J k s#r#!P4 !P6# ,¨ >2Pë g  g  g  ¥ Pʥ ! XN!~  ! _^! ^#V~ x% >= 7 !~ ( !   #x ` F Ϳ F Ϳ ͍ Ҁ *" !6é +"Y*~ #? ک Ϳ ʥ ^#V( é ~ CZMEIABDHSP!"G"+"!91*~!I~6 =G#^#V#~x "#"!N#FW" *D>7Å*G|H+"G H:FBÅ> Å >* *͍ \" ( *"W !)~##{nZ*F#h!Cs!^#V   ##::^#V#þ*^#V>%#x'8_#*;***************************************************** ;* * ;* Sector Deblocking Algorithms for CP/M 2.0 * ;* * ;***************************************************** ; ; utility macro to compute sector mask smask macro hblk ;; compute log2(hblk), return @x as result ;; (2 ** @x = hblk on return) @y set hblk @x set 0 ;; count right shifts of @y until = 1 rept 8 if @y = 1 exitm endif ;; @y is not 1, shift right one position @y set @y shr 1 @x set @x + 1 endm endm ; ;***************************************************** ;* * ;* CP/M to host disk constants * ;* * ;***************************************************** blksiz equ 2048 ;CP/M allocation size hstsiz equ 512 ;host disk sector size hstspt equ 20 ;host disk sectors/trk hstblk equ hstsiz/1**************** read: ;read the selected CP/M sector xra a ;accum = 0 sta unacnt ;unacnt = 0 mvi a,1 sta readop ;read operation sta rsflag ;must read data mvi a,wrual sta wrtype ;treat as unalloc jmp rwoper ;to perform the read ; ;***************************************************** ;* * ;* The WRITE entry point takes the place of * ;* the previous BIOS defintion for WRITE. * ;* * ;***************************************************** write: ;write the selected CP/M sector xra a ;0 to accumulator sta readop ;not a read operation mov a,c ;write type in c sta wrtype cpi wrual ;write unallocated? jnz chkuna ;check for unalloc ; ; write to unallocated, set parameters mvi a,blksiz/128 ;next unalloc recs sta unacnt lda sekdsk ;disk to seek sta unadsk ;unadsk = sekdsk lhld sektrk shld unatrk ;unatrk = sectrk lda seksec sta unasec st lxi h,hstsec ;sekhst = hstsec? cmp m jz match ;skip if match ; nomatch: ;proper disk, but not correct sector lda hstwrt ;host written? ora a cnz writehst ;clear host buff ; filhst: ;may have to fill the host buffer lda sekdsk sta hstdsk lhld sektrk shld hsttrk lda sekhst sta hstsec lda rsflag ;need to read? ora a cnz readhst ;yes, if 1 xra a ;0 to accum sta hstwrt ;no pending write ; match: ;copy data to or from buffer lda seksec ;mask buffer number ani secmsk ;least signif bits mov l,a ;ready to shift mvi h,0 ;double count rept 7 ;shift left 7 dad h endm ; hl has relative host buffer address lxi d,hstbuf dad d ;hl = host address xchg ;now in DE lhld dmaadr ;get/put CP/M data mvi c,128 ;length of move lda readop ;which way? ora a jnz rwmove ;skip if read ; ; write operation, mark and switch direction mvi a,1 sta hstwrt ;hstwrt = 1 xchg ;source/dest swap ; rwmove: ;C initially 128, DE is source, HL 28 ;CP/M sects/host buff cpmspt equ hstblk * hstspt ;CP/M sectors/track secmsk equ hstblk-1 ;sector mask smask hstblk ;compute sector mask secshf equ @x ;log2(hstblk) ; ;***************************************************** ;* * ;* BDOS constants on entry to write * ;* * ;***************************************************** wrall equ 0 ;write to allocated wrdir equ 1 ;write to directory wrual equ 2 ;write to unallocated ; ;***************************************************** ;* * ;* The BDOS entry points given below show the * ;* code which is relevant to deblocking only. * ;* * ;***************************************************** ; ; DISKDEF macro, or hand coded tables go here dpbase equ $ ;disk param block base ; boot: wboot: ;enter here on system ;unasec = seksec ; 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 lxi h,unatrk call sektrkcmp ;sektrk = unatrk? jnz alloc ;skip if not ; ; tracks are the same lda seksec ;same sector? lxi h,unasec cmp m ;seksec = unasec? jnz alloc ;skip if not ; ; match, move to next sector for future ref inr m ;unasec = unasec+1 mov a,m ;end of track? cpi cpmspt ;count CP/M sectors jc noovf ;skip if no overflow ; ; overflow to next track mvi m,0 ;unasec = 0 lhld unatrk inx h shld unatrk ;unatrk = unatrk+1 ; noovf: ;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 is dest ldax d ;source character inx d mov m,a ;to dest inx h dcr c ;loop 128 times jnz rwmove ; ; data has been moved to/from host buffer lda wrtype ;write type cpi wrdir ;to directory? lda erflag ;in case of errors rnz ;no further processing ; ; clear host buffer for directory write ora a ;errors? rnz ;skip if so xra a ;0 to accum sta hstwrt ;buffer written call writehst lda erflag ret ; ;***************************************************** ;* * ;* Utility subroutine for 16-bit compare * ;* * ;***************************************************** sektrkcmp: ;HL = .unatrk or .hsttrk, compare with sektrk xchg lxi h,sektrk ldax d ;low byte compare cmp m ;same? rnz ;return if not ; low bytes equal, test high 1s inx d inx h ldax d cmp m ;sets flags ret ; ;***************************************************** ;*  boot to initialize xra a ;0 to accumulator sta hstact ;host buffer inactive sta unacnt ;clear unalloc count ret ; seldsk: ;select disk mov a,c ;selected disk number sta sekdsk ;seek disk number mov l,a ;disk number to HL mvi h,0 rept 4 ;multiply by 16 dad h endm lxi d,dpbase ;base of parm block dad d ;hl=.dpb(curdsk) ret ; settrk: ;set track given by registers BC mov h,b mov l,c shld sektrk ;track to seek ret ; setsec: ;set sector given by register c mov a,c sta seksec ;sector to seek ret ; setdma: ;set dma address given by BC mov h,b mov l,c shld dmaadr ret ; sectran: ;translate sector number BC mov h,b mov l,c ret ; ;***************************************************** ;* * ;* The READ entry point takes the place of * ;* the previous BIOS defintion for READ. * ;* * ;*************************************to accum sta unacnt ;unacnt = 0 inr a ;1 to accum sta rsflag ;rsflag = 1 ; ;***************************************************** ;* * ;* Common code for READ and WRITE follows * ;* * ;***************************************************** rwoper: ;enter here to perform the read/write xra a ;zero to accum sta erflag ;no errors (yet) lda seksec ;compute host sector rept secshf ora a ;carry = 0 rar ;shift right endm sta sekhst ;host sector to seek ; ; active host sector? lxi h,hstact ;host active flag mov a,m mvi m,1 ;always becomes 1 ora a ;was it already? jz filhst ;fill host if not ; ; host buffer active, same as seek buffer? lda sekdsk lxi h,hstdsk ;same disk? cmp m ;sekdsk = hstdsk? jnz nomatch ; ; same disk, same track? lxi h,hsttrk call sektrkcmp ;sektrk = hsttrk? jnz nomatch ; ; same disk, same track, same buffer? lda sekh * ;* WRITEHST performs the physical write to * ;* the host disk, READHST reads the physical * ;* disk. * ;* * ;***************************************************** writehst: ;hstdsk = host disk #, hsttrk = host track #, ;hstsec = host sect #. write "hstsiz" bytes ;from hstbuf and return error flag in erflag. ;return erflag non-zero if error ret ; readhst: ;hstdsk = host disk #, hsttrk = host track #, ;hstsec = host sect #. read "hstsiz" bytes ;into hstbuf and return error flag in erflag. ret ; ;***************************************************** ;* * ;* Unitialized RAM data areas * ;* * ;***************************************************** ; sekdsk: ds 1 ;seek disk number sektrk: ds 2 ;seek track number seksec: ds 1 ;seek sector number ; hstdsk: ds 1 ;htracks to skip (word) ; [0] is an optional 0 which forces 16K/directory entry ; ; for convenience, the form ; dn,dm ; defines disk dn as having the same characteristics as ; a previously defined disk dm. ; ; a standard four drive CP/M system is defined by ; disks 4 ; diskdef 0,1,26,6,1024,243,64,64,2 ; dsk set 0 ; rept 3 ; dsk set dsk+1 ; diskdef %dsk,0 ; endm ; endef ; ; the value of "begdat" at the end of assembly defines the ; beginning of the uninitialize ram area above the bios, ; while the value of "enddat" defines the next location ; following the end of the data area. the size of this ; area is given by the value of "datsiz" at the end of the ; assembly. note that the allocation vector will be quite ; large if a large disk size is defined with a small block ; size. ; dskhdr macro dn ;; define a single disk header list dpe&dn: dw xlt&dn,0000h ;translate table dw 0000h,0000h ;scratch area dw dirbuf,dpb&dn ;dir buff,parm block dw csv&dn,alv&dn ;check, alloc vec > 256 extmsk set (extmsk shr 1) endif ;; may be optional [0] in last position if not nul k16 extmsk set k16 endif ;; now generate directory reservation bit vector dirrem set dir ;;# remaining to process dirbks set bls/32 ;;number of entries per block dirblk set 0 ;;fill with 1's on each loop rept 16 if dirrem=0 exitm endif ;; not complete, iterate once again ;; shift right and add 1 high order bit dirblk set (dirblk shr 1) or 8000h if dirrem > dirbks dirrem set dirrem-dirbks else dirrem set 0 endif endm dpbhdr dn ;;generate equ $ ddw %sectors,<;sec per track> ddb %blkshf,<;block shift> ddb %blkmsk,<;block mask> ddb %extmsk,<;extnt mask> ddw %(dks)-1,<;disk size-1> ddw %(dir)-1,<;directory max> ddb %dirblk shr 8,<;alloc0> ddb %dirblk and 0ffh,<;alloc1> ddw %(cks)/4,<;check size> ddw %ofs,<;offset> ;; generate the translate table, if requested if nul skf xlt&dn equ 0 ;no xlate table else if skf = 0 xlt&dn equ 0 ;no xlate table else ;; generaost disk number hsttrk: ds 2 ;host track number hstsec: ds 1 ;host sector number ; sekhst: ds 1 ;seek shr secshf hstact: ds 1 ;host active flag hstwrt: ds 1 ;host written flag ; unacnt: ds 1 ;unalloc rec cnt unadsk: ds 1 ;last unalloc disk unatrk: ds 2 ;last unalloc track unasec: ds 1 ;last unalloc sector ; erflag: ds 1 ;error reporting rsflag: ds 1 ;read sector flag readop: ds 1 ;1 if read operation wrtype: ds 1 ;write operation type dmaadr: ds 2 ;last dma address hstbuf: ds hstsiz ;host buffer ; ;***************************************************** ;* * ;* The ENDEF macro invocation goes here * ;* * ;***************************************************** end tors endm ; disks macro nd ;; define nd disks ndisks set nd ;;for later reference dpbase equ $ ;base of disk parameter blocks ;; generate the nd elements dsknxt set 0 rept nd dskhdr %dsknxt dsknxt set dsknxt+1 endm endm ; dpbhdr macro dn dpb&dn equ $ ;disk parm block endm ; ddb macro data,comment ;; define a db statement db data comment endm ; ddw macro data,comment ;; define a dw statement dw data comment endm ; gcd macro m,n ;; greatest common divisor of m,n ;; produces value gcdn as result ;; (used in sector translate table generation) gcdm set m ;;variable for m gcdn set n ;;variable for n gcdr set 0 ;;variable for r rept 65535 gcdx set gcdm/gcdn gcdr set gcdm - gcdx*gcdn if gcdr = 0 exitm endif gcdm set gcdn gcdn set gcdr endm endm ; diskdef macro dn,fsc,lsc,skf,bls,dks,dir,cks,ofs,k16 ;; generate the set statements for later tables if nul lsc ;; current disk dn same as previous fsc dpb&dn equ dpb&fsc ;equivalent parameters als&dn eqte the translate table nxtsec set 0 ;;next sector to fill nxtbas set 0 ;;moves by one on overflow gcd %sectors,skf ;; gcdn = gcd(sectors,skew) neltst set sectors/gcdn ;; neltst is number of elements to generate ;; before we overlap previous elements nelts set neltst ;;counter xlt&dn equ $ ;translate table rept sectors ;;once for each sector if sectors < 256 ddb %nxtsec+(fsc) else ddw %nxtsec+(fsc) endif nxtsec set nxtsec+(skf) if nxtsec >= sectors nxtsec set nxtsec-sectors endif nelts set nelts-1 if nelts = 0 nxtbas set nxtbas+1 nxtsec set nxtbas nelts set neltst endif endm endif ;;end of nul fac test endif ;;end of nul bls test endm ; defds macro lab,space lab: ds space endm ; lds macro lb,dn,val defds lb&dn,%val&dn endm ; endef macro ;; generate the necessary ram data areas begdat equ $ dirbuf: ds 128 ;directory access buffer dsknxt set 0 rept ndisks ;;once for each disk lds alv,%dsknxt,als lds csv,%dsknxt,css dsknxt set dsknxt+1 endm e; CP/M 2.0 disk re-definition library ; ; Copyright (c) 1979 ; Digital Research ; Box 579 ; Pacific Grove, CA ; 93950 ; ; CP/M logical disk drives are defined using the ; macros given below, where the sequence of calls ; is: ; ; disks n ; diskdef parameter-list-0 ; diskdef parameter-list-1 ; ... ; diskdef parameter-list-n ; endef ; ; where n is the number of logical disk drives attached ; to the CP/M system, and parameter-list-i defines the ; characteristics of the ith drive (i=0,1,...,n-1) ; ; each parameter-list-i takes the form ; dn,fsc,lsc,[skf],bls,dks,dir,cks,ofs,[0] ; where ; dn is the disk number 0,1,...,n-1 ; fsc is the first sector number (usually 0 or 1) ; lsc is the last sector number on a track ; skf is optional "skew factor" for sector translate ; bls is the data block size (1024,2048,...,16384) ; dks is the disk size in bls increments (word) ; dir is the number of directory elements (word) ; cks is the number of dir elements to checksum ; ofs is the number of u als&fsc ;same allocation vector size css&dn equ css&fsc ;same checksum vector size xlt&dn equ xlt&fsc ;same translate table else secmax set lsc-(fsc) ;;sectors 0...secmax sectors set secmax+1;;number of sectors als&dn set (dks)/8 ;;size of allocation vector if ((dks) mod 8) ne 0 als&dn set als&dn+1 endif css&dn set (cks)/4 ;;number of checksum elements ;; generate the block shift value blkval set bls/128 ;;number of sectors/block blkshf set 0 ;;counts right 0's in blkval blkmsk set 0 ;;fills with 1's from right rept 16 ;;once for each bit position if blkval=1 exitm endif ;; otherwise, high order 1 not found yet blkshf set blkshf+1 blkmsk set (blkmsk shl 1) or 1 blkval set blkval/2 endm ;; generate the extent mask byte blkval set bls/1024 ;;number of kilobytes/block extmsk set 0 ;;fill from right with 1's rept 16 if blkval=1 exitm endif ;; otherwise more to shift extmsk set (extmsk shl 1) or 1 blkval set blkval/2 endm ;; may be double byte allocation if (dks) nddat equ $ datsiz equ $-begdat ;; db 0 at this point forces hex record endm ; = gcd(sectors,skew) neltst set sectors/gcdn ;; neltst is number of elements to generate ;; before we overlap previous elements nelts set neltst ;;counter xlt&dn equ $ ;translate table rept sectors ;;once for each sector if sectors < 256 ddb %nxtsec+(fsc) else ddw %nxtsec+(fsc) endif nxtsec set nxtsec+(skf) if nxtsec >= sectors nxtsec set nxtsec-sectors endif nelts set nelts-1 if nelts = 0 nxtbas set nxtbas+1 nxtsec set nxtbas nelts set neltst endif endm endif ;;end of nul fac test endif ;;end of nul bls test endm ; defds macro lab,space lab: ds space endm ; lds macro lb,dn,val defds lb&dn,%val&dn endm ; endef macro ;; generate the necessary ram data areas begdat equ $ dirbuf: ds 128 ;directory access buffer dsknxt set 0 rept ndisks ;;once for each disk lds alv,%dsknxt,als lds csv,%dsknxt,css dsknxt set dsknxt+1 endm eEA (RESTORED AT FINIS) LXI SP,STKTOP ; READ AND PRINT SUCCESSIVE BUFFERS CALL SETUP ;SET UP INPUT FILE CPI 255 ;255 IF FILE NOT PRESENT JNZ OPENOK ;SKIP IF OPEN IS OK ; ; FILE NOT THERE, GIVE ERROR MESSAGE AND RETURN LXI D,OPNMSG CALL ERR JMP FINIS ;TO RETURN ; OPENOK: ;OPEN OPERATION OK, SET BUFFER INDEX TO END MVI A,80H STA IBP ;SET BUFFER POINTER TO 80H ; HL CONTAINS NEXT ADDRESS TO PRINT LXI H,0 ;START WITH 0000 ; GLOOP: PUSH H ;SAVE LINE POSITION CALL GNB POP H ;RECALL LINE POSITION JC FINIS ;CARRY SET BY GNB IF END FILE MOV B,A ; PRINT HEX VALUES ; CHECK FOR LINE FOLD MOV A,L ANI 0FH ;CHECK LOW 4 BITS JNZ NONUM ; PRINT LINE NUMBER CALL CRLF ; ; CHECK FOR BREAK KEY CALL BREAK ; ACCUM LSB = 1 IF CHARACTER READY RRC ;INTO CARRY JC FINIS ;DON'T PRINT ANY MORE ; MOV A,H CALL PHEX MOV A,L CALL PHEX NONUM: INX H ;TO NEXT LINE NUMBER MVI A,' ' CALL PCHAR MOV A,B CALL PHEX JMP GLOOP ; FINIS: ; END OF DUMP, RETURN TO CCP ; (NOTE  ; STACK AREA DS 64 ;RESERVE 32 LEVEL STACK STKTOP: ; END ARRY SET FOR EOF STC RET ; G0: ;READ THE BYTE AT BUFF+REG A MOV E,A ;LS BYTE OF BUFFER INDEX MVI D,0 ;DOUBLE PRECISION INDEX TO DE INR A ;INDEX=INDEX+1 STA IBP ;BACK TO MEMORY ; POINTER IS INCREMENTED ; SAVE THE CURRENT FILE ADDRESS LXI H,BUFF DAD D ; ABSOLUTE CHARACTER ADDRESS IS IN HL MOV A,M ; BYTE IS IN THE ACCUMULATOR ORA A ;RESET CARRY BIT RET ; SETUP: ;SET UP FILE ; OPEN THE FILE FOR INPUT XRA A ;ZERO TO ACCUM STA FCBCR ;CLEAR CURRENT RECORD ; LXI D,FCB MVI C,OPENF CALL BDOS ; 255 IN ACCUM IF OPEN ERROR RET ; DISKR: ;READ DISK FILE RECORD PUSH H! PUSH D! PUSH B LXI D,FCB MVI C,READF CALL BDOS POP B! POP D! POP H RET ; ; FIXED MESSAGE AREA SIGNON: DB 'FILE DUMP VERSION 1.4$' OPNMSG: DB CR,LF,'NO INPUT FILE PRESENT ON DISK$' ; VARIABLE AREA IBP: DS 2 ;INPUT BUFFER POINTER OLDSP: DS 2 ;ENTRY SP VALUE FROM CCP ;THAT A JMP TO 0000H REBOOTS) CALL CRLF LHLD OLDSP SPHL ; STACK POINTER CONTAINS CCP'S STACK LOCATION RET ;TO THE CCP ; ; ; SUBROUTINES ; BREAK: ;CHECK BREAK KEY (ACTUALLY ANY KEY WILL DO) PUSH H! PUSH D! PUSH B; ENVIRONMENT SAVED MVI C,BRKF CALL BDOS POP B! POP D! POP H; ENVIRONMENT RESTORED RET ; PCHAR: ;PRINT A CHARACTER PUSH H! PUSH D! PUSH B; SAVED MVI C,TYPEF MOV E,A CALL BDOS POP B! POP D! POP H; RESTORED RET ; CRLF: MVI A,CR CALL PCHAR MVI A,LF CALL PCHAR RET ; ; PNIB: ;PRINT NIBBLE IN REG A ANI 0FH ;LOW 4 BITS CPI 10 JNC P10 ; LESS THAN OR EQUAL TO 9 ADI '0' JMP PRN ; ; GREATER OR EQUAL TO 10 P10: ADI 'A' - 10 PRN: CALL PCHAR RET ; PHEX: ;PRINT HEX CHAR IN REG A PUSH PSW RRC RRC RRC RRC CALL PNIB ;PRINT NIBBLE POP PSW CALL PNIB RET ; ERR: ;PRINT ERROR MESSAGE ; D,E ADDRESSES MESSAGE ENDING WITH "$" MVI C,PRINTF ;PRINT BUFFER FUNCTION CALL BDOS RET ; ; GNB: ;GET NEXT BYTE LDA IBP CPI 80H JNZ G0 ; FILE DUMP PROGRAM, READS AN INPUT FILE AND PRINTS IN HEX ; ; COPYRIGHT (C) 1975, 1976, 1977, 1978 ; DIGITAL RESEARCH ; BOX 579, PACIFIC GROVE ; CALIFORNIA, 93950 ; ORG 100H BDOS EQU 0005H ;DOS ENTRY POINT CONS EQU 1 ;READ CONSOLE TYPEF EQU 2 ;TYPE FUNCTION PRINTF EQU 9 ;BUFFER PRINT ENTRY BRKF EQU 11 ;BREAK KEY FUNCTION (TRUE IF CHAR READY) OPENF EQU 15 ;FILE OPEN READF EQU 20 ;READ FUNCTION ; FCB EQU 5CH ;FILE CONTROL BLOCK ADDRESS BUFF EQU 80H ;INPUT DISK BUFFER ADDRESS ; ; NON GRAPHIC CHARACTERS CR EQU 0DH ;CARRIAGE RETURN LF EQU 0AH ;LINE FEED ; ; FILE CONTROL BLOCK DEFINITIONS FCBDN EQU FCB+0 ;DISK NAME FCBFN EQU FCB+1 ;FILE NAME FCBFT EQU FCB+9 ;DISK FILE TYPE (3 CHARACTERS) FCBRL EQU FCB+12 ;FILE'S CURRENT REEL NUMBER FCBRC EQU FCB+15 ;FILE'S RECORD COUNT (0 TO 128) FCBCR EQU FCB+32 ;CURRENT (NEXT) RECORD NUMBER (0 TO 127) FCBLN EQU FCB+33 ;FCB LENGTH ; ; SET UP STACK LXI H,0 DAD SP ; ENTRY STACK POINTER IN HL FROM THE CCP SHLD OLDSP ; SET SP TO LOCAL STACK AR ; READ ANOTHER BUFFER ; ; CALL DISKR ORA A ;ZERO VALUE IF READ OK JZ G0 ;FOR ANOTHER BYTE ; END OF DATA, RETURN WITH CARRY SET FOR EOF STC RET ; G0: ;READ THE BYTE AT BUFF+REG A MOV E,A ;LS BYTE OF BUFFER INDEX MVI D,0 ;DOUBLE PRECISION INDEX TO DE INR A ;INDEX=INDEX+1 STA IBP ;BACK TO MEMORY ; POINTER IS INCREMENTED ; SAVE THE CURRENT FILE ADDRESS LXI H,BUFF DAD D ; ABSOLUTE CHARACTER ADDRESS IS IN HL MOV A,M ; BYTE IS IN THE ACCUMULATOR ORA A ;RESET CARRY BIT RET ; SETUP: ;SET UP FILE ; OPEN THE FILE FOR INPUT XRA A ;ZERO TO ACCUM STA FCBCR ;CLEAR CURRENT RECORD ; LXI D,FCB MVI C,OPENF CALL BDOS ; 255 IN ACCUM IF OPEN ERROR RET ; DISKR: ;READ DISK FILE RECORD PUSH H! PUSH D! PUSH B LXI D,FCB MVI C,READF CALL BDOS POP B! POP D! POP H RET ; ; FIXED MESSAGE AREA SIGNON: DB 'FILE DUMP VERSION 1.4$' OPNMSG: DB CR,LF,'NO INPUT FILE PRESENT ON DISK$' ; VARIABLE AREA IBP: DS 2 ;INPUT BUFFER POINTER OLDSP: DS 2 ;ENTRY SP VALUE FROM CCP ;!!9"1W͜Q>2!͢QG}DrYQ|͏}͏#> ex͏#r* _> e> e ҉0Ë7e}} :³ʳ7_<2!~ɯ2|\\FILE DUMP VERSION 1.4$ NO INPUT FILE PRESENT ON DISK$!Y , <    *$A!6 # T!w $r# *`: 0 *A*! ~ ʰxkb))))_y‘BK{ͅ*!66!"80*{#z+++ #CBIOS& ASMw`abcdefgCBIOS ASMEhijklDDT COM&mnoDEBLOCK ASMOpqrstDISKDEF LIB1uvwxDUMP ASM!yz{DUMP $$$!!6e*!M͛ /$^L:!@OL:! 2͑e:b:! L:h<2hb:! b:hO>!hw:! pX:! …!!6  LÊ!!6ûô:!ʛ͑:! ҩ OҸû:!R†!6G>!!!6 :2.t -? >!!6!6s, !6:xB!6OU2!SB!G6:҃!6:G҃*G& ~2!:G<2G_ Qқ=e  b:!-®! 6:!#¿͇;J:!:!!6Lv:!:Jv: *#"͎! 6:!B)! >w!"&*o"(R :!C:eR :!DKeX :!K\ͷX :!Lj^ :!Pš͎҇! 6F×͢җ:Ç :!T¨F :!U¾: 2 :!V͎"$DMͩ/ *oDMͩ : 2 :! (::H%^bF : ͎H :!Ay! 6*""&*o"(R͎an͢na! 6R :!F”͢ґ Ä :!J $:2$͢ :=2:<2!*& ~2!ü*""I*M*o/!:"6:0O  ú!p+q:/(*DMͩ:  : I N* *DM:aO>!Һ x!: ڦ> ʡ* +" >¡! 6: <2 =O! N͒:  O͒: ! 6:h!o$O* ͸ ! 6 !h6!: 2 3* & 6 : <2 =O! N͒*dM  :sGsu n>!6:<2=O! N͒!">!"͎/Ҵ*+">>!": *#"*""*!".+",*$"**o".!",!36:3{.*22*,**"0M ~ H3*0"**+"*+">23:2/k!36,*+s#rx:3x*0"*: “**"&*"+"(á*$#"&**#"(*"#""*$#"$*"+""*$+"$*#"!4qM*"*$: *(y"$DM}|C#~ *#"*&DMyxC 1*+":4?w+"$""ͷR: —*$"("҈!"&Ô""&*""&$mڸ*o"(**$"($"O26͛*"M :6w͢:6 "&! 6R*I""ë :!M:H| ! 6>F ͛e: <2 O! Hqy d F : 2! 6*#s#r :!N ͢ *o/ Ҧ Ͷn! 6!"&R! 6o$ Î Ç :!S0 $͢- :2"+s#r!:* *& ~2!:<2 :!W> v :!X³ Z͎\ Ee ð :7/҃ E!76e ͕ :xƒ - ͷ*&"K(Kڰ *KM N͔*K"KҌ :!Z ͎  ͢ : :!  'v!gq:f *g&!lq:l $ !h4:l 1 !h6*lM :hB     !h55!mq:m :hO>H2ny} !m6 !o6:n!oښ *mM !o4‚ !pq:p ڪ >:p :p H:p H!qq*qM͛  ^W :q@2q*qMW   !sp+q*r !up+q *tDM !wp+q*v !zp+q*y2x!|p+q*{2x!~p+q*}2x!p+q*!p+q*!p+q*!p+q*2x!p+q*!6   >>! q* &!p+q*!7q:*7M͒:7o$+͛ͪ*$M ~28Om:8 I͇͢u$oqo͛rP! 6!"&*$"(R͎ҔM͢ҡÔ($ҵ! 6R͇vͶ2!*!Mm$"*"M :!w͢:! e2!:! : /HH/Q:! @!!6 R!!6 :!KR$*& :!w:<2dn!:s+q*$";!>6:>/;oH*;#"(";:92=*=& *(M !::=2>/H:=<2=*(#"(æÀ:>*(+"(R:>!6$:2*o/*!My:<2=O!s Hq**DMͷ! 6: e!"*""?k*&"?*?+M ~2A :hHҏ *&"?(?:A ½8*#" ҽ*?M ~2AO *?"?ҕ!"*"*"^: 2B! 6F:B2 o(>&H6͛9!C6>!Ca R>:C<2C?! 6!"͇͢Ґq"ڊ͛Íq!!6 !!6 !6*!Ma2D*!M͒2!:D/!+w!6e2!͢!Eq!E:!:H:H!Fq COPYRIGHT (C) 1979, DIGITAL RESEARCH DISK OR DIRECTORY FULL$FILE EXISTS, ERASE IT$NEW FILE$** FILE IS READ/ONLY **$"SYSTEM" FILE NOT ACCESSIBLE$BAK$$$BAK$$$-(Y/N)?$NO MEMORY$BREAK "$" AT $1mM"m +!8s~1m!f6 *M  *!M 1m! 6!6! 6: 2Ebͽ!e:d\::eH2 H҆ͽ:e2!:d2e:!2dû :!I¬!: :H2 ҮX:h2iҐ:!ʍ:!:!H:!H,!"! 6#~ F)ͷX:! X):i!h)9 e:!:h2jO>F L>!":i!jHҼ*"+M ~ ʼͲ!f6!h6!"! 6F!f6:h2k!iҠ:i2k:j2h:k!hҶ9 æ:h2j!!6:j2he:! >"Ͳ*"M ~2!O :! *+":7 e !p+q*DM  =? ) !p+q.*DMF -L *9"`!"b!h6!j6!|6.!=\ -x !e:dʥ *eM \R :xʥ @ *dM \, :x \͕ :x - V :e _ :f w : =e !e:d*eM =e : =e =͕ !]6:x>- !"!76!6!6!66*dM  *dM !6:8!*`*;DM \u 2xʻ>!xҨ- *`*;6:82*`"`:<2w!"`9`h*`*;~2*`#"`:*eM !b+!s{!f!6:!b*b*^DM =ͅ N- *b"b:<2)f!"b!q9bڀ*b*^:w*b#"b!q:6ڶZͅ ʱ- !66*6& :w:6<26!J6*b}:J<2Jm=? :x- : ;*dM .=\ -=ͨ ;: *eM =ͨ .M= -C!q:Y*M !q:a/>z!/H!q*MaҎ:_:!q:ҥ*My:!p+q!'"!6>**ͪ{2**ͪ"*! ͪ":!!"*FM8 *FM   Oy2F :FY5>>:!02HO> /!";u*)))*) *H& "PҘ! 6+s#ré! 6"DM!>))덑o|g =±^#V) ^#V|g}o _{ozgi`N#Fogo&og_{_z#W H = LIBX$$$$$$$LIB$:2*o/*!My:<2=O!s Hq**DMͷ! 6: e!"*""?k*&"?*?+M ~2A :hHҏ *&"?(?:A ½8*#" ҽ*?M ~2AO *?"?ҕ!"*"*"^: 2B! 6F:B2 o(>&H6͛9!C6>!Ca R>:C<2C?! 6!"͇͢Ґq"ڊ͛Íq!!6 !!6 !6*!Ma2D*!M͒2!:D/!+w!6e2!͢!Eq!E:!:H:H!FqJMP DMA DREAD JMP READ DWRITE JMP WRITE SELDRV JMP DRIVE TPANIC JMP CPAN TSTAT JMP TMSTAT DMAST JMP DMSTAT STATUS JMP DISKST DSKERR JMP LERROR SETDEN JMP DENFIX SETSID JMP SIDEFX DS 66Q BOOT LXI SP,TRACK+1 ;initialize SP CALL TIMOUT ;poc/reset timeout LXI H,1 PUSH H ;track 0, sector 1 MVI L,DCRINT ;set up the PUSH H ; side select MVI H,377Q ; and initial PUSH H ; drive PUSH H ; parameters PUSH H PUSH H LXI H,10Q ;initialize PUSH H ; tzflag & cdisk MVI L,176Q ;initialize PUSH H ; disk & drvsel MVI L,10Q ;initialize PUSH H ; hdflag & dsflag MVI H,30Q ;initialize PUSH H ; timer constant MVI A,177Q ;start 1791 STA DREG MVI A,CLRCMD ;1791 reset STA CMDREG LDHEAD XRA A ;load the head CALL HDCHK ; and test for JNC DOOROK ; drive ready MVI A,LIGHT ;turn on the STA DCREG ; error LED CALL TIMOUT ;timeout to JMP LDHEAD ; close drive door DOOROK MVI A,NOLITE ;turn off the STA DCREG  RET ; positions 0 & 1 DMSTAT PUSH H ;save the HL pair LHLD DMAADR ;move the MOV B,H ; DMA address to MOV C,L ; the BC pair POP H ;recover HL RET DRIVE MOV A,C ;drive select ANI 3 ; values must be STA DISK ; between zero RET ; and three DMA LXI H,-RAM ;test the DAD B ; DMA address JC DMASET ; for conflict LXI H,8-ORIGIN DAD B ; with the I/O JNC DMASET ; on the DJ/2D MVI A,20Q ; controller RET DMASET MOV H,B ;store the MOV L,C ; BC pair SHLD DMAADR RET HOME CALL HDLOAD ;load the head RC ;not ready error CALL HENTRY ;move the head PUSH PSW ;save status SBB A ;update the STA TRACK ; track STA TRKREG ; registers XRA A ;set the not STA TZFLAG ; verified flag JMP LEAVE+1 ;unload the head HENTRY XRA A ;set the force STA HDFLAG ; verify flag LXI H,0 ;timeout constant MVI A,HCMD ;move the head CALL CENTRY ;to track 0 ANI TZERO ;track zero bit R ; error LED CALL MEASUR ;head load time POP B ;adjust the stack LXI B,RAM+300H ;DMA addr PUSH B ;initialize PUSH D ; dmaadr & timer LXI H,0 ;initialize PUSH H ; intrfg & ramins NOP ;debug instruction PUSH B ;boot address MVI B,12 ;number of retrys LDLOOP PUSH B ;save the retry no. CALL READ ;read boot sector POP B ;restor retry no. RNC ;successful read? DCR B ;no - count down JNZ LDLOOP ; and try again LERROR MVI C,11Q LXI D,0a2c3h LELOOP DCX D MOV A,D ORA E JNZ LELOOP MVI A,10Q ;blink XRA C ; the LED at MOV C,A ; top of the STA DCMD ; circuit board JMP LERROR+2 COUT LDA USTAT ;get UART status ANI OSTAT ;output ready mask JNZ COUT ;test buffer empty MOV A,C ;character data CMA ;negative logic bus STA UDATA ;send data to UART CMA ;make positive RET CIN LDA USTAT ;get UART status ANI ISTAT ;input ready mask JNZ CIN ;wait for input LDA UDATA ;get the character CMA ;adNZ STC ;error flag RET SECSET XRA A ;test for ORA C ; zero value STC ;error flag RZ ;error return ANI 37Q ;trim & clear cry STA SECTOR RET SEEK MOV A,C ;test for CPI 77 ; track CMC ; too large RC STA TRACK RET ISSUE STA ECOUNT+1 ;update count CALL MEASUR ;find index MVI C,1 ;Start with sector 1 ISLOOP MOV A,C ;Initilize the STA SECREG ; sector register LDA SECTOR ;Test for CMP C ; target sector RZ MVI A,RDCMD ;do a fake CALL COMAND ; read command JC PLEAVE ;Abort on error INR C ;Increment sector number JMP ISLOOP COMNDP STA CMDREG ;Start operation MOV C,B ;Initilize block count LXI D,DATREG ;Data register LHLD DMAADR ;transfer address RET WRITE CALL PREP ;prepare for write JC LEAVE ;abort operation WRENTRY MVI A,WRCMD ;write sector cmd CALL COMNDP WRLOOP MOV A,M ;load 1st byte of data INX H STAX D ;write 1st byte of data MOV A,M ;load 2nd byte of data INX H S***************************************************************** * * * Firmware for Disk Jockey Model B. * * * ***************************************************************** title '*** Disk Jockey Model B Firmware ***' ORIGIN EQU 0F800H ORG ORIGIN RAM EQU ORIGIN+400h IO EQU ORIGIN+3f8h UDATA EQU IO DREG EQU IO+1 USTAT EQU IO+1 DCMD EQU IO+2 DSTAT EQU IO+2 CSTALL EQU IO+3 CMDREG EQU IO+4 CSTAT EQU IO+4 TRKREG EQU IO+5 SECREG EQU IO+6 DATREG EQU IO+7 LIGHT EQU 1 HEAD EQU 1 DENSITY EQU 1 INTRQ EQU 4 ISTAT EQU 4 TZERO EQU 4 LOAD EQU 4 ULOAD EQU 6 OSTAT EQU 10Q DSIDE EQU 10Q NOLITE EQU 11Q DCRINT EQU 11Q HCMD EQU 11Q INDEX EQU 20Q WINDXD EQU 22Q SKCMD EQU 30Q RINDXD EQU 32Q SVCMD EQU 35Q WPROT EQU 100Q ACCESS EQU 100Q RSTBIT EQU 200Q READY EQU 200Q RDCMD EQU 210Q WRCMD EQU 250Q STBITS EQU 300Q RACMD EQU 304Q CLRCMD EQU 320Q DBOOT JMP BOOT TERMIN JMP CIN TRMOUT JMP COUT TKZERO JMP HOME TRKSET JMP SEEK SETSEC JMP SECSET SETDMA just for negative bus ANI 177Q ;trim to 7 bits RET CPAN LDA USTAT ;get UART status ANI ISTAT ;input ready mask RNZ ;test for data CALL CIN ;get character CMP C ;test for panic chtr RET TMSTAT LDA USTAT ;get UART status ANI ISTAT ;input ready mask RET DISKST LXI H,TRKREG ;most recent MOV C,M ; track to C INX H ;most recent MOV B,M ; sector to B LDA DCREG ;get current CMA ; density in ANI 1 ; the msb RRC ; position MOV D,A ;save in D LDA SIDE ;put the RLC ; most recent RLC ; side select RLC ; in bit positin ORA D ; 6 and merge MOV D,A ;save in D LDA DSFLAG ;get the XRI DSIDE ; most recent RAL ; double sided RAL ; status and place ADD D ; in bit position MOV D,A ; 5 and merge LDA SECLEN ;get the RAL ; sector length RAL ; code bits in ORA D ; positions 2 & 3 MOV D,A ; and merge LDA CDISK ;get the current ADD D ; disk no. in bit #TAX D ;write 2nd byte of data MOV A,M ;load 3rd byte of data INX H STAX D ;write 3rd byte of data DCR c ;reduce block count MOV A,M INX H STAX D JNZ WRLOOP ;write next 4 bytes LXI H,WRENTRY JMP CBUSY READ CALL PREP ;prepare for read JC LEAVE ;abort operation RDENTRY MVI a,RDCMD CALL COMNDP RDLOOP LDAX D ;read 1st byte MOV M,A ;store 1st byte INX H LDAX D ;read 2nd byte MOV M,A ;store 2nd byte INX H LDAX D ;read 3rd byte MOV M,A ;store 3rd byte INX H DCR c ;reduce block count LDAX D ;read 4th byte MOV M,A ;store 4th byte INX H JNZ RDLOOP ;read next 4 bytes LXI H,RDENTRY CBUSY PUSH H ;Save return LXI H,CSTAT ;Wait for 1791 CALL BUSY ; to finish command ANI 137Q ;Error mask JZ LEAVE-1 ;No error CPI 20Q ;Premature interupt JNZ PLEAVE ;Other type of error LDA ECOUNT ;decrement error count DCR A ; by one JM STEST ;Hard interupt error STA ECOUNT ;Update count RET STEST LDA ECOUNT+1 ;Decremhe sector MOV C,A ; size and setup MVI B,0 ; the table offset LXI H,STABLE ;sector table DAD B ;sector size pntr LDA SECTOR ;get the sector MOV B,A ; and save in B ADD M ;compare w/table MVI A,20Q ;error flag RC ;error return MOV A,B ;initialize 1791 STA SECREG ; sector register MVI A,40Q ;128 byte sector LXi h,505h SHLD ECOUNT SZLOOP DCR C ;reduce size count MOV B,A ;sector size to B RM ;return on minus RAL ;double the count ORA A ;clear the carry JMP SZLOOP STABLE DB 345Q ;26 sector diskettes DB 345Q ;26 sector diskettes DB 360Q ;15 sector diskettes DB 367Q ;8 sector diskettes HDLOAD LXI H,DISK ;new drv ptr MOV C,M ;save new drv in C INX H ;current drv ptr MOV E,M ;save old drv in E MOV M,C ;update current drv INX H ;home cmd flag MOV A,E ;test for CMP C ; drive change MOV A,M ;head load mask MVI M,HEAD ;update the mask JZ HDCHK ;no drive change? INX H ;addr of drive table PUSH H ice busy MOV A,M ;restore status RNC ;return if not busy JMP PATCH+3 ;jump around patch PATCH JMP HDLOAD ;patch for old ATE DCX D ;test for MOV A,D ; two disk ORA E ; revolutions JNZ BUSY ;47 machine cycles MOV E,M ;get error code PUSH H ;save cmd address INX H ;track register MOV D,M ;save present track LDA DRVSEL ;control bits XRI RSTBIT ;reset the 1791 STA DREG ; controller to XRI STBITS ; clear the XTHL ; command busy STA DREG ; fault condition MVI M,CLRCMD ;force interrupt XTHL ;restore the MOV M,D ; the track reg POP H ;restore the stack MOV A,E ;error code to A STC ; error flag RET MEASUR LXI D,0 ;initialize count LXI H,DSTAT ;status port MVI C,INDEX ;index bit flag INDXLO MOV A,M ;wait for ANA C ; index JZ INDXLO ; pulse high INDXHI MOV A,M ;wait for ANA C ; index JNZ INDXHI ; pulse low INDXCT INX D ;advance count XTHL ;four dummy XTHL ; insent error DCR A JP ISSUE MVI A,20Q PLEAVE STC ;error flag POP H LEAVE PUSH PSW ;save the status LDA DCREG ;control bits XRI LOAD ;toggle the STA DCMD ; head load bit LDA DRVSEL ;enable access to STA DREG ; the data register POP PSW ;recover the status RET PREP CALL HDLOAD ;load the head RC ;test for drive ready LDA TRKREG ;get old track INR A ;test for head CZ HENTRY ; not calibrated RC ;seek error? LXI H,TRKREG ;old track LDA TRACK ;new track CMP M ;test for head motion INX H ;advance to the INX H ; data register MOV M,A ;save new track MOV A,C ;turn off data reg STA DREG ; access control bit JZ TVERFY ;test for seek XRA A ;force a read STA HDFLAG ; header operation LDA DSTAT ;get the double ANI DSIDE ; sided flag STA DSFLAG ;save for status RAR ;shift for RAR ; 3/6 ms step RAR ; rate constant ADI SKCMD ;do a LXI H,0 ; seek CALL CENTRY ; operation JC S ;save table addr MVI D,0 ;set up the MOV B,D ; offset address DAD D ;calculate the DAD D ; parameter addr LDA DCREG ;save the MOV M,A ;density status INX H ;track pointer LXI D,TRKREG ;1791 trk reg LDAX D ;get current track MOV M,A ;save in the table POP H ;beginning of table DAD B ;new drive DAD B ; table pointer MOV A,M ;get density status STA DCREG ;update DCREG INX H ;get the old MOV A,M ; track number STAX D ; and update 1791 MVI A,177Q ;drive select bits DSROT RLC ;rotate to DCR C ; select the JP DSROT ; proper drive ANI 177Q ;set the run bit STA DRVSEL ;save in drv reg XRA A ;force a head load HDCHK LXI H,DSTAT ;test for ANA M ; head loaded STA HDFLAG ;save the head PUSH PSW ; loaded status LDA DRVSEL ;get current drive MOV C,A ;save LDA SIDE ;get current side CMA ; and merge ANA C ; with drive select STA DREG ;select drive & side XRI ACCESS ;toggle access bittructions XTHL ; to lengthen XTHL ; the delay MOV A,M ;wait for ANA C ; the index JZ INDXCT ; to go high RET ;98 machine cycles DENFIX MOV A,C ;trim the ANI 1 ; excess bits CMA ;compliment and MOV B,A ; save in B LXI H,DISK ;new disk ptr MOV E,M ;get disk no. MVI D,0 ;offset addr INX H ;current disk ptr MOV A,M ;move to ACC XRA E ;cmpr old w/new PUSH PSW ;save status INX H ;disk table INX H ; address DAD D ;add the DAD D ; offset MOV A,M ;get parameters ORI 1 ;mask off density ANA B ;set new density MOV M,A ;update parameters POP PSW ;test new=old? RNZ MOV A,M ;updata CDISK STA DCREG ; also RET TIMOUT LXI H,0 ;time-out delay TILOOP DCX H ;decrement count MOV A,H ;test for delay ORA L ; count equal zero XTHL ;long NOP XTHL ; instruction JNZ TILOOP RET SBEGIN PUSH H LXI H,DSTALL DSTALL PCHL POP H RET SIDEFX MOV A,C ;get the side bit ANI 1 ;tERROR ;seek error? TVERFY LDA HDFLAG ;get the force ORA A ; verify hdr flag JNZ CHKSEC ;no seek & head OK MVI B,2 ;verify retry count SLOOP MVI A,SVCMD ;do a verify CALL COMAND ; command ANI 231Q ;error bit mask MOV D,A ;save JZ RDHDR ;no error LDA DCREG ;denisty control XRI DENSITY ;flip the density STA DCREG ;update and STA DCMD ; change density DCR B ;decrement retry JNZ SLOOP ; count & test MOV A,D SERROR STC PUSH PSW CALL HENTRY POP PSW RET RDHDR MVI B,12Q ;number of retrys RHLOOP LXI D,DATREG ;Data register LXI H,TRACK+1 ;Data pointer MVI A,RACMD ;Start read header command STA CMDREG RHL1 LDAX D ;get disk data 0 MOV M,A ;store in mem INR L ;advance pointer JNZ RHL1 ;test end of page LXI H,CSTAT ;wait for 1791 CALL BUSY ; to finish cmd ORA A ;test for errors JZ CHKSEC ;transfer OK? DCR B ;no - test for JNZ RHLOOP ; hard error JMP SERROR ;recalibrate CHKSEC LDA SECLEN ;get t MOV C,A ;save for PREP routine LDA DCREG ;den & head cntl bits MOV B,A ;save LDA TRACK ;get the new track SUI 1 ;force single SBB A ; density DCR A ; if track = 0 CMA ;compliment ORA B ;merge w/control bits MOV M,A ;load head & set density POP PSW ;head load status JNZ RDYCHK ;conditionally PUSH H ; wait for head LHLD TIMER ; load time out TLOOP DCX H ;count down MOV A,H ; 40 ms for ORA L ; head load JNZ TLOOP ; time out POP H RDYCHK MOV A,M ;test for ANI READY ; drive ready RNZ UNLOAD LDA DCREG ;force a ORI ULOAD ; head MOV M,A ; unload MVI A,READY ;set drive STC ; not ready RET ; error flag COMAND LHLD TIMER ;get index count DAD H ; and multiply DAD H ; by four CENTRY XCHG ;save in D-E pair LXI H,CSTAT ;issue command MOV M,A ; to the 1791 NBUSY MOV A,M ;wait RAR ; for the JNC NBUSY ; busy flag BUSY MOV A,M ;test for RAR ; dev$rim the excess RAL ;move the bit RAL ; to the side RAL ; select bit RAL ; position STA SIDE ;save side bit RET PWRJMP NOP ;power-on NOP ; jump NOP ; sequence NOP ; with NOP NOP ; padding JMP DBOOT DS 10Q ;I/O locations org ram+3c9h STACK DS 31Q ECOUNT DW 0 TIMER DW 1800h ;head load time out DMAADR DW RAM+300H ;dma address DSFLAG DB 10Q HDFLAG DB 0 ;read header flag DRVSEL DB 176Q ;drive select constant DISK DB 0 ;new drive CDISK DB 10Q ;current disk TZFLAG DB 0 ;home cmd indicator DOPRAM DB 11Q ;drive 0 parameters DOTRK DB 377Q ;drive 0 track no D1PRAM DB 11Q ;drive 1 parameters D1TRK DB 377Q ;drive 1 track no D2PRAM DB 11Q ;drive 2 parameters D2TRK DB 377Q ;drive 2 track no D3PRAM DB 11Q ;drive 3 parameters D3TRK DB 377Q ;drive 3 track no DCREG DB 11Q ;current parameters SIDE DB 0 ;new side SECTOR DB 1 ;new sector TRACK DB 0 ;new track TRKNO DB 0 ;disk SIDENO DB 0 ; sector SECTNO DBt ;Formatting IBM cp 1 jp z,nstart ;Formatting North Star jp 0 ;Return to CP/M ibmst: ld hl,1030h ;Initalize command addresss ld (dotcmd+1),hl ld hl,sdadvt ld (atcmd+1),hl ld hl,slcmd+1 ;Set 8 inch drive as 0-3 ld (hl),0 dec hl ld c,4 call lcmd ld hl,drmess ;Get drive number call getcc ld (single+1),a ;Store the drive number in code ld (drive),a ; and save in a safe place ld a,26 ;26 Sectors per track for single ld (nspt),a ld hl,26*128 ;Load number of bytes per track ld (trksiz),hl ld a,0e5h ;We format with e5's ld (verval),a ld hl,dnmess ;Get density call getcc ld (densty),a ;Save for later use jp z,side ;Skip sector size if single density ld hl,slmess ;Select sector length message call getcc ld d,0 ;Form offset into sector table ld e,a ld hl,tsize ;Get track size add hl,de ld h,(hl) ;Get high byte of size ld l,0 ld (trksiz),hl ;Save track size inc a ;Adjust for sector length code ld (dlcode-ddfmt+double)ld a,(densty) or a ;Test for double density jp z,contue ;Make no adjustments for single density ld hl,lddcmd ;Load double density format command ld c,9 ;Offset to halt status call lcmd ;Load the code into controller ld hl,ddadvt ;Advance track execute address ld (atcmd+1),hl ;Update the command execute address ld hl,1030h ;Format execute address contue: ld (dotcmd+1),hl ;Update track format execute address ld hl,atcmd ;Advance track command ld c,5 ;Offset to status call lcmd ;Load the command and execute cp 77 ;Last track value (77 decimal) jp nz,fmtrck ;Zero => formatting done ld a,77 ;77 tracks on an 8 inch drive ld (ntrack),a jp verify ;Verify disk fmtrck: ld hl,ftrack ;Pointer to track # call ptrack ;Print and update track number ld hl,dotcmd ;Format a track command ld c,5 ;Offset to status call lcmd ;Load and execute the command jp z,contue+3 ;Loop back for more tracks ld hl,femess ;Drive has become not ready call putm jp 0 ; header SECLEN DB 0 ; data CRCLO DB 0 ; buffer CRCHI DB 0 ,a ;Store in format code ld hl,sptabl add hl,de ld a,(hl) ;Fetch number of sectors ld (dlast-ddfmt+double),a ;Store in format code dec a ld (nspt),a ; and in the verify section ld a,20h ;Sector length code is 80,100, or 0 dcnst: add a,a dec e ;Decrement the sector type jp p,dcnst ;Test for cycle done ld (dsize-ddfmt+double),a ;Store 1/4 length in format code side: ld a,(drive) ;Get drive # add a,"0" ;Make ASCII decimal ld (wdriv8),a ;Save in wait message ld hl,wdmes8 ;Wait for a disk call putm ld hl,wdmess call getcc retryf: ld hl,sscmd+1 ;Test various drive parameters ld a,(drive) ;Load drive # to sense ld (hl),a dec hl ld c,7 ;Offset to status call lcmd ld hl,nrmess ;Not ready message cp 82h ;Test for not ready jp z,nready ;Skip if not ready ld a,(sscmd+4) ;fetch status port value ld b,a ;Save for a while ld hl,wpmess ;Write protected message and 40h ;Mask in write protected bit jp nz,nready ;Skip if write protected  start ;Stop the formatting page ; ; The following routine set up and execute the North Star formatter ; nstart: ld hl,1030h ld (nscmex+1),hl ld a,20h ld (data-nsfmt+nsform),a ld (cpdata-nsfmt+nsform),a ld (verval),a xor a ld (track-nsfmt+nsform),a ld a,10 ;Load number of sectors per track ld (nspt),a ld hl,10*512 ;Load number of bytes per track ld (trksiz),hl ld hl,slcmd+1 ;Set 5 1/4 inch drive as 0-3 ld (hl),4 dec hl ld c,4 call lcmd ld hl,drmess ;Get drive number call getcc ld (nsform+1),a ld (drive),a ld hl,ntmess ;Get number of tracks call getcc ld d,0 ld e,a ld hl,nstrak add hl,de ld a,(hl) ld (strack-nsfmt+nsform),a ld (ntrack),a push de ld hl,dnmess ;Get density call getcc pop de ld b,051h jp z,nstore push af rrca add a,e ld e,a pop af ld b,0d1h nstore: ld (den1-nsfmt+nsform),a ld a,b ld (den2-nsfmt+nsform),a push de ld hl,simess ;Get number of sides call getcc pop de ld (dflag-nsfmt+nsform title djdma/format.asm 01-29-82 .z80 channl equ 50h ;Start channel address index equ 10h ;Delta index status bit wproct equ 40h ;Write protected status bit dready equ 80h ;Drive ready status bit home equ 0a0h ;Internal home-disk routine address seek equ 0a3h ; seek-track sdrive equ 0a6h ; set-drive hsync equ 0a9h ; header-sync diskd equ 4001h ;Disk data port status equ 4003h ;Status port contrl equ 4007h ;Control port crlfs equ 0d0ah ;Carraige return / line feed sequence acr equ 0dh ;A carraige return character alf equ 0ah ;A line feed character aesc equ 1bh ;An escape character adel equ 7fh ;A delete character retries equ 3 ;Disk retries before giving up on verify bdos equ 5 ;Bdos entry address wcon equ 2 ;Write console function direct equ 6 ;Direct console I/O page 63 start: ld sp,ecode+30h ;Initialize the stack pointer ld hl,"0 " ;Initialize track number to 0 ld (ftrack+1),hl ld hl,qfmess ;Ask about type of format call getc jp z,ibms ld a,b ;Restore full status port value and 4 ;Mask in 'sides' bit rrca ;Shift to bit 0 rrca ld (ddsbit-ddfmt+double),a ;Store in format code double density ld (sdsbit-sdfmt+single),a ;Store in format code single density rrca ;Zap around to bit 7 ld (nside),a ;And save side flag ld hl,ftmess ;Formatting ... message call putm ld a,1 ;Load track counter ld (ctrack),a ld hl,lsdcmd ;Load single density code command ld c,9 ;Offset to halt status call lcmd ;Load the code ld hl,dotcmd ;Format track 0 command ld c,5 ;Offset to status call lcmd ;Execute the command jp z,proced ;Zero => no error ld hl,nrmess ;Drive not ready message cp 82h ;Drive not ready error code jp z,nready ;Test for drive not ready ld hl,wpmess ;Well... the write tab fell off... nready: call getcc ;Send the message jp z,start ;Zero => start the program over jp retryf ;Go back and do the command over proced: ld hl,sdrdy ;Adjusted execution address of format %),a rrca ld (nside),a ;Set up side flag rlca jp z,nsdatc rlca rlca add a,e ld e,a nsdatc: push de ld hl,nsmess ;Ask about North Star vs CP/M format call getcc pop de jp z,nsload ld a,e and 80h ld a,10h jp z,nstord ld hl,nstype-80h add hl,de ld a,(hl) nstord: ld (cpdata-nsfmt+nsform),a ld a,0e5h ld (data-nsfmt+nsform),a ld (verval),a nsload: ld a,(drive) ;Get drive # add a,"0" ;Make ASCII decimal ld (wdriv5),a ;Save in wait message ld hl,wdmes5 ;Wait for a disk call putm ld hl,wdmess call getcc nsrtry: ld hl,nscmlm ld c,9 call lcmd ld hl,nscmex ld c,5 call lcmd jp z,nsproc ld hl,nrmess cp 82h jp z,$+6 ld hl,wpmess ;Tell about fault call getcc jp z,start jp nsrtry nsproc: ld hl,ftmess ;Formatting ... message call putm xor a ;Initialize track counter ld (ctrack),a ld hl,entry ld (nscmex+1),hl nscont: ld hl,ftrack ;Print track # call ptrack ld hl,nscmat ld c,5 call lcmd ld b,a ld a,(strack-nsfer added to hl should produce a pointer to the ; halt status. ; lcmd: ld a,26h ;Branch channel command ld (channl),a ld (channl+1),hl ;Channel address xor a ld (channl+3),a ;Extended address ld b,0 add hl,bc ;Offset to status byte ld (hl),a ;Clear halt status out (0efh),a ;Start controller waitc: or (hl) ;Wait for halt complete jp z,waitc dec hl ;Back up to command status dec hl ld a,(hl) ;Load status cp 40h ;Comper to Ok status ret ; ; Print a track #, do fancy backspacing, ect. ; ptrack: ld (ptrk),hl ;Save ASCII pointer ld a,(ctrack) ;Load current track push af ld hl,(ptrk) ;Place to deposite track # call decim3 ;Figure track # pop af inc a ;Bump to next track ld (ctrack),a ld bc,300h ;b = fore count, b = back count ld hl,(ptrk) ;Pointer to current track # ld de,otrack ;Pointer to old track # ex de,hl ;Set pointers the way we want them ptrkcp: ld a,(de) ;Get a digit cp (hl) ;Compare against old number jp nz,ptrk The routine is called with a pointer to a string in hl and ; returns a value in (a) and (zero). The format for the string ; follows: ; ; db "initial prompt string" ; db 0 ;Null terminator ; db 2 ;Number of 'reply values' ; db "a", "A", acr ;A list of characters to be ; ; with the coresponding reply ; ; 'value.' ; db 83h ;The reply value. Parity must ; ; be set. ; db "Reply echo string for a, A, or acr." ; db 0 ;Null terminator ; db "d", "D" ;A list of characters to be ; ; with the coresponding reply ; ; 'value.' ; db 85h ;The reply value. Parity must ; ; be set. ; db "Reply echo string for d or D." ; db 0 ;Null terminator ; ; This structure will return a 3 if an 'a', 'A', or acr is typed ; and a 5 if a 'd' or 'D' is typed. The routine prints a CRLF ; before the initial prompt string and a CRLF after the reply ; string. If an ESC or DEL is typed then a code of 80h will be ; returned and the minus flag will be set. ; mt+nsform) cp b jp z,verify ;Go verify disk ld hl,nscmex ld c,5 call lcmd jp z,nscont ld hl,femess ;Drive not ready call putm jp start page ; ; Verify the disk ; verify: ld hl,vtmess ;Send verifying ... message call putm ld hl,sacmd ;Set the DMA address ld c,5 ;Halt status offset call lcmd xor a ;Initialize track counters ld (ctrack),a ld (rtcmd+1),a ld a,(drive) ;Initialize the drive number ld (rtcmd+3),a vertrk: ld hl,vtrack ;Print track # call ptrack ld a,(nside) ld (rtcmd+2),a ;Load sides flag ld a,retries ;Initialize retry counters ld (retrys),a ;Soft error counter ld (retryh),a ;Hard error counter versid: ld hl,rtcmd ;Verify a side ld c,9 ;Status offset call lcmd ;Read a track jp nz,verfat ;Fatal drive error ld hl,sectab ;Lets check out sectors ld a,(nspt) ;Load number of sectors to check ld c,a ld a,40h ;'Ok' code verspt: cp (hl) jp nz,vererr ;Sector does not verify inc hl dec c jp nz,verspt ld hl,dn ;Skip if done inc c ;Bump offset inc de ; current pointer inc hl ; old pointer dec b ; counter jp nz,ptrkcp ;Compare next digit ret ;Numbers were the same ptrkdn: push hl ;Save pointer to first dirty digit ptrklp: ld (hl),a ;Copy dirty string over inc de ld a,(de) inc hl dec b jp nz,ptrklp ld hl,bsmess ;Back space add hl,bc ;Offset neccesary amount call putm pop hl ;Retreive string pointer call putm ;And print ld c,6 ld e,0ffh call 5 ret ; ; Put 'a' in (hl) in ASCII decimal form with leading spaces ; decim3: ld c,"0" ;Initialize 'leader' flag ld d,100 ;Hundreds call decfig ld d,10 ;Tens call decfig decim1: ld c,0 ;Force leading 0 ld d,1 ;Ones jp decfig decfig: ld e,"0"-1 declop: inc e sub d jp nc,declop add a,d push af ld a,e cp c ;Handle leading space (sometimes) jp nz,decok ld e," " ;Load space jp decokk decok: ld c," " decokk: ld (hl),e ;Save digit inc hl ;Bump to negetc: push hl ld hl,crlf ;Print an initial CRLF call putm pop hl call putm ;Print prompt inc hl ;Bump to number of valid replies ld c,(hl) ld a,c ld (valid),a ;Save reply count ld (string),hl ;Save string pointer gtchk: push bc ;Save reply count push hl ;Save string pointer gtwait: ld c,direct ;Direct console I/O ld e,255 ;We want input! call bdos or a ;Test for no character typed jp z,gtwait ;Wait for a character pop hl pop bc cp 3 ;Check for control C jp z,0 ; exit to CP/M cp aesc ;Escape and delete get special coverage jp z,gtspec cp adel jp z,gtspec ld b,a ;Save user reply gtscan: inc hl ;Bump to reply string ld a,(hl) ;Load reply character or a ;Test for end of reply string jp m,gtflsh ;Not in this reply list, flush string cp b ;Compare to user reply jp nz,gtscan ;No match, continue scan gtdone: inc hl ;Look for reply value ld a,(hl) or a jp p,gtdone push af ;Save value inc hl ;Bump to resportcmd+2 ;Side ok, check for other side ld a,(hl) ;Get side flag ld (hl),0 ;Clear flag just in case ... or a ;Test flag jp nz,versid ;Verify other side dec hl ;Bump to track count inc (hl) ;Bump track number ld a,(ntrack) ;Test for end of disk cp (hl) jp nz,vertrk ;Verify next track ld hl,vdmess ;Verify done call putm jp start ;Restart verfat: ld hl,retryh ;Bump hard retry count dec (hl) jp nz,versid ld hl,vemess ;Verify error jp errpr vererr: ld hl,retrys ;Bump hard retry count dec (hl) jp nz,versid ld hl,vsmess ;Verify error errpr: call putm ;Tell user about it jp start ; and quit ; ; Execute controller command. ; hl -> Start of command sequence ; c -> Offset pointer to status byte of sequence ; a <- Status return (z flag set if = 40h) ; ; The command sequence must end with a halt. If any status ; is returned from the regular part of the command then this ; status must immediatly precede the halt. The value in the ; c registxt position pop af ret ; ; Print a null terminated text to the terminal ; putm: ld a,(hl) ;Get current byte of message or a ;Test for end of message ret z ;Return at end of message push hl ;Save the character pointer call putc ;Output the character pop hl ;Recover the character pointer inc hl ;Advance the character pointer jp putm ;Go get the next character ; ; Print a character to the terminal ; putc: push af push bc push de push hl ld e,a ld c,wcon call bdos pop hl pop de pop bc pop af ret ; ; Call getc. Parse ESC and DEL codes. If these codes ; were typed then return to start. ; getcc: call getc ;Get code jp m,start ;Restart if ESC or DEL ret ;Return regular status ; ; This routine prints a prompt and then accepts an input character. ; This input character is compared to a 'reply list'. If the ; character is found then an associated 'reply string' is echoed ; and a value associated with that character is returned. ; ;&nse message call putm ld hl,crlf ;Print a trailing CRLF call putm pop af ;Restore reply value and 7fh ;Clear parity bit ret gtflsh: inc hl ;Look for and of message (null) ld a,(hl) or a jp nz,gtflsh dec c ;Bump reply count jp nz,gtscan ;Continue scan ld a,(valid) ;Reinitialize reply count ld c,a ld hl,(string) ;Reinitialize string pointer jp gtchk ;User guessed wrong, let us try again gtspec: ld a,80h ;Special flag or a ;Zap flags ret page slcmd: db 02eh ;Set/get logical drive settings db 0 ;Logical to set db 0 ;Logical drives returned db 25h db 0 lddcmd: db 0a1h ;Write controller memory command dw double ;Main memory address pointer db 0 dw single-double ;Byte count dw 1030h ;Controller memory address pointer db 25h ;Controller halt command db 0 ;Halt command status byte lsdcmd: db 0a1h ;Write controller memory for single dw single db 0 dw nsform-single dw 1030h db 25h db 0 dotcmd: db 0a2h at drive 0" db 0 db "1", 81h db "Preparing to format drive 1" db 0 db "2", 82h db "Preparing to format drive 2" db 0 db "3", 83h db "Preparing to format drive 3" db 0 dnmess: db "Select: double density", acr, alf db " S single density", acr, alf db " " db 0 db 2 db "d", "D", acr, 81h db " Double density selected." db 0 db "s", "S", 80h db " Single density selected." db 0 ntmess: db "Select the number of tracks ( 0=35, 1=40, 2=80 ): " db 0 db 3 db "0", acr, 80h db "35 track drive" db 0 db "1", 81h db "40 track drive" db 0 db "2", 82h db "80 track drive" db 0 slmess: db "Select the sector length ( 0=256, 1=512, 2=1024 ): " db 0 db 3 db "0", 80h db "256 byte sectors" db 0 db "1", 81h db "512 byte sectors" db 0 db "2", acr, 82h db "1024 byte sectors" db 0 nsmess: db "Select: N North star or", acr, alf db " CP/M data compatibility.", acr, alf db " " db 0 db 2 db "n", "N", 80h db " North d retrys: db 0 ;Retry counter, soft valid: db 0 ;Temp save for number of valid replies string: dw 0 ;Temp pointer to parse trees sectab: db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ;Sector status table db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 page ; ; The following routines are the actual formatting routines. ; These routines are loaded into controller RAM at 1030h ; and executed as needed. Currently there are 3 routines: ; ; IBM 8 inch single density. ; IBM 8 inch double density. ; North Star 5 1/4 inch multi desity. ; ; ; IBM 8 inch single density formatter routine ; double equ $ .phase 1030h ddfmt: ld hl,status bit 7,(hl) ;Check that the drive is ready nrexit: ld a,82h ;Drive not ready error code ret z ;Error exit bit 6,(hl) ;Test for write protected ld a,90h ;Write protected error code ret nz ;Error exit ld (ix+0bh),0 ;Reset index counter ld a,(dtrck) ;Get the new track value cp (iy+1) ;Compare with current track push af ;Save the ;Execute controller routine command dw 1030h ;Format a track address db 0 ;Execute command status db 25h ;Halt command db 0 ;Status byte atcmd: db 0a2h dw sdadvt ;Advance the track value address db 0 db 25h db 0 sscmd: db 022h ;Sense drive status db 0 ;Drive # db 0 ;Drive characteristic byte db 0 ;Sector size byte db 0 ;Status port byte db 0 ;Completion status db 25h db 0 sacmd: db 023h ;Set DMA address dw buffer db 0 db 25h db 0 rtcmd: db 029h ;Read track command db 0 ;Track # db 0 ;Side # db 0 ;Drive # dw sectab ;Sactor table db 0 db 0 ;Status db 25h db 0 nscmlm: db 0a1h ;Load controller memory dw nsform db 0 dw ecode-nsform dw 1030h db 25h db 0 nscmex: db 0a2h ;Execute controller memory dw 1030h db 0 db 25h db 0 nscmat: db 0a2h ;Advance track command (internal) dw advtrk db 0 db 25h db 0 nstrak: db 35 ;Track count table db 40 db 80 nstype: db 90h db Star data format." db 0 db "c", "C", acr, 81h db " CP/M data format." db 0 simess: db "Select: single sided or", acr, alf db " D double sided media.", acr, alf db " " db 0 db 2 db "s", "S", acr, 80h db " Single sided media selected." db 0 db "d", "D", 81h db " Double sided media selected." db 0 nrmess: db "Drive not ready - (R)estart program, or (C)ycle: " db 0 db 2 db "r", "R", 80h db "Restarting program" db 0 db "c", "C", acr, 81h db "Cycling" db 0 femess: dw crlfs db "Drive has become 'not ready' during formatting" db 0 wpmess: db "Write protected - (R)estart program, or (C)ycle: " db 0 db 2 db "r", "R", 80h db "Restarting program" db 0 db "c", "C", acr, 81h db "Cycling" db 0 wdmes5: dw crlfs, crlfs db "Insert a write enabled diskette in 5 1/4 inch drive " wdriv5: db "0." db 0 wdmes8: dw crlfs, crlfs db "Insert a write enabled diskette in 8 inch drive " wdriv8: db "0." db 0 wdmess: db "Close the drtrack call nz,seek ;Move the head(s) if needed ld hl,diskd ;Pointer to disk shift register ld de,contrl ;Pointer to control port pop af ;Recover the tack cp 2bh ;Compare with track 43 ld a,4 ;No write precompensation jr c,loadpc ;Carry => track is less than 43 ld a,14h ;Write precompensation bit set loadpc: ld (precmp),a ;Setup the write precompensation byte sbc a,a ;Push carry bit throughout accumulator or 0feh ;Low current bit now set and (iy+2) ;Merge with drive pattern or 2 ;Select side 0 ld (iy+2),a ;Restore drive pattern or 0ch ;Turn off step command ld (4005h),a ;Update the drive register ld b,50h ;Preamble length ddlbl1: ld a,(status) and index ;Look for index pulse jr nz,ddlbl1 ;Wait for no index pulse present ddlbl2: ld a,(status) and index jr z,ddlbl2 ;Wait for leading edge of new indes pulse ld a,90h ;Control byte - normal write/no crc ld (de),a ;Initialize control port ld a,0 precmp equ $-1 ;Write precompensation & controller start 0a0h db 0c0h db 0 db 0f0h db 0d0h db 0e0h tsize: db 26*256/100h ;Number of pages per track db 15*512/100h db 8*1024/100h sptabl: db 27 ;26 sectors per track (256 bytes) db 16 ;15 sectors per track (512 bytes) db 9 ;8 sectors per track (1024 bytes) page qfmess: dw crlfs db "Floppy disk format command for the Morrow Designs", acr, alf db "Disk Jockey DMA (DJDMA) floppy disk controller.", acr, alf dw crlfs db "Type an ESC or DEL, at any time, to return to the main menu." dw crlfs dw crlfs db "Select: (I) IBM 3740 compatable 8 inch format.", acr, alf db " (N) North Star compatable 5 1/4 inch format.", acr, alf db " back to CP/M.", acr, alf dw crlfs db "Select (I, N, or ): " db 0 db 3 db "i", "I", 80h db "IBM 3740 format" db 0 db "n", "N", 81h db "North Star format" db 0 db alf, acr, 82h db "Returning to CP/M" db 0 drmess: db "Select a drive ( 0, 1, 2, or 3 ): " db 0 db 4 db "0", acr, 80h db "Preparing to formive door and then press " db 0 db 1 db alf, acr, 80h db 0 ftmess: dw crlfs db "Formatting track:" ftrack: db " 0" ;ASCII track number db 0 vtmess: dw crlfs db "Verifying track: " vtrack: db " 0" db 0 bsmess: db 8, 8, 8 ;Back terminal 3 spaces db 0 otrack: db " 0" ;Old ASCII track number db 0 vdmess: dw crlfs, crlfs db "Verify done." dw crlfs db 0 vemess: dw crlfs, crlfs db "Fatal verify error, probable bad diskette." dw crlfs db 0 vsmess: dw crlfs, crlfs db "Sector verify error" dw crlfs db 0 crlf: dw crlfs db 0 page drive: db 0 ;# of drive being formatted densty: db 0 ;Density flag for current drive nspt: db 0 ;Number of sectors per track trksiz: dw 0 ;Size of a track (bytes) verval: db 0 ;Byte to verify with nside: db 0 ;Number of sides flag ntrack: db 0 ;Number of tracks on current drive ctrack: db 0 ;Current track number ptrk: dw 0 ;Pointer to ASCII track # retryh: db 0 ;Retry counter, har' ld (4006h),a ;Start the controller ddlbl3: ld (hl),4eh djnz ddlbl3 ;Write the preamble ld b,0ch ;Zero preamble length ddlbl4: ld (hl),0 djnz ddlbl4 ;Write the zero preamble ld a,80h ;Control byte for 16 bit write ld (de),a ;Change mode ld (hl),52h ;First half of c2 ld (hl),24h ;Second half of c2 ld (hl),52h ;Another c2 ld (hl),24h ld (hl),52h ;The third c2 ld a,90h ;Control byte 8 bit write ld (de),a ;Change mode ld (hl),24h ;Finish the sync bytes ld (hl),0fch ;Index mark ld b,32h ;Postamble length ddlbl5: ld (hl),4eh djnz ddlbl5 ;Write the postamble dmloop: ld b,0ch ;Zero preamble length ddlbl6: ld (hl),0 djnz ddlbl6 ;Write the preamble ld a,81h ;16 bit write mode w/crc ld (de),a ;Change mode ld (hl),44h ;First half of a1 ld (hl),89h ;Second half of a1 ld (hl),44h ;Second a1 ld (hl),89h ld (hl),44h ;Third a1 ld a,91h ;8 bit write mode w/crc ld (de),a ;Change mode ld (hl),89h ;Finish sync bytes ld (hl),0feh ;Sector header id byte ro => track write is done ld a,(iy+2) ;Drive pattern or 0ch ;Turn off the step command and 0fdh ;Change read/write heads ld (4005h),a ;Update the command register ld (hl),4eh ;First preamble byte jp ddlbl3 ;Format the other side ddlblc: ld (hl),4eh ;Trailing fill byte ld (hl),4eh ;Trailing fill byte ld (hl),4eh ;Trailing fill byte xor a ld (de),a ;Turn off the write gate ld a,6 ld (4006h),a ;Turn off the controller ld a,40h ;Status code ret ddadvt: ld a,(dtrck) ;Get the current track value inc a ;Increment ld (dtrck),a ;Restore the new value ret ;Return with current track value .dephase page ; ; IBM 8 inch double density formatter routine ; single equ $ .phase 1030h sdfmt: ld a,0 ;Second byte filled with proper drive number call sdrive ;Select the new drive ret nz ;Return if wrong value ld a,(iy+2) ;Get the drive pattern or 0fh ;Side 0 and no step command ld (4005h),a ;Update drive control register ld hl,0 ;Delay for the head load sdwait the crc bytes ld a,90h ;Reset the crc ld (de),a ;Change modes ld b,0bh ;Sector header postamble length sdlbl7: ld (hl),0ffh djnz sdlbl7 ;Write the postamble ld a,80h ;16 bit write mode ld (de),a ;Change modes ld b,0ch ;Data field preamble length sdlbl8: ld (hl),0aah ;Half a zero cell djnz sdlbl8 ;Write the preamble ld a,81h ;Enable crc & 16 bit write ld (de),a ;Change modes ld (hl),0f5h ;First half of fb ld a,91h ;8 bit write ld (de),a ;Change modes ld (hl),6fh ;Second half of fb ld b,80h ;Sector data field length sdlbl9: ld (hl),0e5h djnz sdlbl9 ;Write the data field ld a,0a1h ld (de),a ;Change modes ld (hl),a ld (hl),a ;Write the crc bytes ld a,90h ;Reset the crc ld (de),a ;Change modes ld a,(ssect) ;Get the current sector inc a ;Advance cp 1bh ;Compare with 27 ld (hl),0ffh ;First postamble byte jr nz,$+4 ;Zero => all sectors written ld a,1 ld (ssect),a ;Update the sector ld b,1ah ;Postamble length less one sdlbla: ld (hl ld (hl),0 ;Write the track number dtrck equ $-1 ld (hl),0 ;Write the side dside equ $-1 ld (hl),1 ;Write the sector number dsect equ $-1 ld (hl),1 ;Sector length code dlcode equ $-1 ld a,0a1h ;Mode to write crc bytes ld (de),a ;Change mode ld (hl),a ld (hl),a ;Write the crc bytes ld a,90h ;Reset crc generator ld (de),a ;Change mode ld b,16h ;4e postamble length ddlbl7: ld (hl),4eh djnz ddlbl7 ;Write the postamble ld b,0ch ;Data field preamble ddlbl8: ld (hl),0 djnz ddlbl8 ;Write the preamble ld a,81h ;16 bit write w/crc ld (de),a ;Change mode ld (hl),44h ;First half of a1 ld (hl),89h ;Second half of a1 ld (hl),44h ;Second a1 ld (hl),89h ld (hl),44h ;Third a1 ld a,91h ;8 bit write w/crc ld (de),a ;Change mode ld (hl),89h ;Finish the 3 sync bytes ld (hl),0fbh ;Data header id byte ld b,40h ;Sector length divided by four dsize equ $-1 ddlbl9: ld (hl),0e5h ;Empty sector data byte ld (hl),0e5h ld (hl),0e5h ld (hl),0e5h ;Write four f: dec hl ld a,h or l jr nz,sdwait ld (ix+0bh),a ;Reset the index counter sdtrk0: call home ;Calibrate the head(s) bit 5,(hl) ;Test for track zero jr z,snrext sdrdy: ld hl,status bit 7,(hl) ;Test for the drive ready snrext: ld a,82h ;Drive not ready code ret z ;Error exit bit 6,(hl) ;Write protect bit ld a,90h ;Write protect error code ret nz ld (ix+0bh),0 ;Reset the index counter ld a,(strck) ;Get the new track cp (iy+1) ;Compare with current track call nz,seek ;Do track seek if necessary ld hl,diskd ;Controller data register ld de,contrl ;Control register ld b,28h ;Preamble length sdlbl1: ld a,(status) and index jr nz,sdlbl1 ;Wait for no index pulse sdlbl2: ld a,(status) and index jr z,sdlbl2 ;Wait for leading edge of new index pulse ld a,90h ;Clear the crc register & turn on write gate ld (de),a ;Change modes ld a,44h ;Single density & start bit ld (4006h),a ;Start the controller sdlbl3: ld (hl),0ffh djnz sdlbl3 ;Write the preamble ),0ffh djnz sdlbla ;Write the postamble jr nz,smloop ;Test for more sectors to format ld (hl),0ffh ;First fill byte ld b,0 ;Side bit sdsbit equ $-1 ld a,(sside) ;Get the current side xor b ;Conditionally switch side bits ld (sside),a ;Update the side byte ld (hl),0ffh ;Write second fill byte ld b,19h ;Preamble length less one ex Af,Af' ;Save the double sided status sdlblb: ld (hl),0ffh ;Write a fill byte ld a,(status) and index jr z,sdlblb ;Wait for the index hole ex Af,Af' ;Recover the double sided status jr z,sdlblc ;Zero => single sided ld a,(iy+2) ;Get the drive pattern or 0ch ;Turn off the step command and 0fdh ;Turn on head one ld (4005h),a ;Update drive control register ld (hl),0ffh ;Write first preamble byte jp sdlbl3 ;Go format the other side sdlblc: ld (hl),0ffh ;Trailing byte xor a ld (de),a ;Turn off write gate ld a,6 ld (4006h),a ;Turn off the controller ld a,40h ;Status code ret sdadvt: ld a,(strck) ;Get the current track incill bytes djnz ddlbl9 ;Test for data field write done ld a,0a1h ;Crc control byte ld (de),a ;Change mode ld (hl),a ;Write the crc bytes ld (hl),a ld a,90h ;Turn off the crc generator ld (de),a ;Change mode ld a,(dsect) ;Get the sector number inc a cp 1bh ;Test for last sector +1 dlast equ $-1 ld (hl),4eh ;First byte of postamble jr nz,$+4 ;Zero => all sectors written ld a,1 ld (dsect),a ;Update the sector number ld b,35h ;Postamble length less one ddlbla: ld (hl),4eh djnz ddlbla ;Write the postamble jr nz,dmloop ld (hl),4eh ;First fill byte ld b,0 ;Double sided bit test ddsbit equ $-1 ld a,(dside) xor b ;Conditionally switch the side byte ld (dside),a ;Update the side byte ld (hl),4eh ;Second fill byte ld b,4fh ;Preamble length less one ex Af,Af' ;Save the double sided status dlblb: ld (hl),4eh ;Write a fill byte ld a,(status) and index ;Wait for the index pulse jr z,dlblb ex Af,Af' ;Recover the double sided status jr z,ddlblc ;Ze ld a,80h ;16 bit write mode ld (de),a ;Change modes ld b,0ch ;Zero preamble length sdlbl4: ld (hl),0aah ;Half a zero cell djnz sdlbl4 ;Write the zero preamble ld (hl),0f7h ;First half of fc ld a,90h ;8 bit write mode ld (de),a ;Change modes ld (hl),7ah ;Second half of fc ld b,1ah ;Postamble length sdlbl5: ld (hl),0ffh djnz sdlbl5 ;Write the postamble smloop: ld a,80h ;16 bit write mode ld (de),a ;Change modes ld b,0ch ;Sector header preamble length sdlbl6: ld (hl),0aah ;Half a zero cell djnz sdlbl6 ;Write the preamble ld a,81h ;Enable crc & 16 bit write ld (de),a ;Change modes ld (hl),0f5h ;First half of fe ld a,91h ;Enable crc & 8 bit write ld (de),a ;Change modes ld (hl),7eh ;Second half of fe ld (hl),0 ;Write the track strck equ $-1 lD (hl),0 ;Write the side byte sside equ $-1 ld (hl),1 ;Write the sector number ssect equ $-1 ld (hl),0 ;Write the sector length code ld a,0a1h ld (de),a ;Change modes ld (hl),a ld (hl),a ;Write( a ;Advance track value ld (strck),a ;Update the track value ret ;Return with track value .dephase page ; ; North Star multi desity formatter routine ; nsform equ $ .phase 1030h nsfmt: ld a,0 call sdrive ret nz ld (ix+0bh),0 ld a,(iy+2) or 0eh ld (4004h),a call hsync nsexit: ld a,82h ret z track0: call home bit 5,(hl) jr z,nsexit entry: ld (ix+0bh),0 ld a,(track) cp (iy+1) call nz,seek ld a,(4003h) and 40h ld a,90h ret nz ld (ix+0ah),80h wsect0: call hsync jr z,nsexit xor a cp (ix+0ah) jr nz,wsect0 ld a,90h ld (contrl),a ld hl,diskd ld c,0 ld (ix+9),c ld b,11h ld a,0 den1 equ $-1 rra ld a,64h jr nc,cstart ld a,18h strack equ $-1 rra add a,5 cp (iy+1) sbc a,a and 10h or 24h ld b,20h cstart: ld (4006h),a zerow: ld (hl),0 ex (sp),hl ex (sp),hl djnz zerow ld a,(den1) or a jr z,lasts ld (hl),0fbh ex (sp),hl ex (sp),hl lasts: ld (hl),0fbh ld b,5ch ld e,20h data equ $-1 ld d,20h cpda nN North Star data format.cC CP/M data format.Select: single sided or D double sided media. sS Single sided media selected.dD Double sided media selected.Drive not ready - (R)estart program, or (C)ycle: rRRestarting programcC Cycling Drive has become 'not ready' during formattingWrite protected - (R)estart program, or (C)ycle: rRRestarting programcC Cycling Insert a write enabled diskette in 5 1/4 inch drive 0. Insert a write enabled diskette in 8 inch drive 0.Close the drive door and then press  Formatting track: 0 Verifying track: 0 0 Verify done. Fatal verify error, probable bad diskette. Sector verify error !@~>v>6 :ģ!@@+>8>2w 2@P:@ :@(>>2@6N 6>6R6$6R6$6R>6$626N 6>6D66D66D>666666>ww>6N 6>6D66D66D>66@6666>ww>:<6N >256N 6N:26Nta equ $-1 xor a d1loop: ex (sp),hl ex (sp),hl ld (hl),e xor e rlca djnz d1loop ld b,51h den2 equ $-1 ex (sp),hl ex (sp),hl ld (hl),d xor d rlca ex Af,Af' ld a,e ld (cpdata),a ex Af,Af' ex (sp),hl ex (sp),hl ld (hl),e xor e rlca d2loop: ex (sp),hl ex (sp),hl ld (hl),e xor e rlca ex (sp),hl ex (sp),hl ld (hl),e xor e rlca djnz d2loop ex (sp),hl ex (sp),hl ld (hl),a ld a,(den1) or a ld b,11h jr z,$+4 ld b,20h iloop: ex (sp),hl ex (sp),hl ld (hl),e ld a,(status) and index jr z,iloop inc c ld a,0ah cp c jr nz,zerow ld c,0 ld a,(nsdsid) xor 0 dflag equ $-1 ld (nsdsid),a jr z,ftdone ld a,(iy+2) or 0eh and 0fdh ld (4004h),a jr zerow ftdone: ld (contrl),a ;Turn off write gate ld a,40h ret advtrk: ld a,(track) ;Get the current track inc a ;Advance track value ld (track),a ;Update the track value ret ;Return with track value track: 0 nsdsid: 0 .dephase ecode equ $ ;End of code ma1e! 0"S !_͒I!0"!:"!6+!͋26 2 >2 ! " >2 !y͋2 ʆ!V͋_!Yf." <2 !\~2 =2 > ~2 : 02 ! p! ͋!": w+! :%G!E @x2 2 2 !? p>2 !  !! !E ͋Ú!P: ! !Y"!0"!M/>M2 ^!R !! p!0"D> 222 23> 2 !" !6+!͋2H2 !͋_!O~22 !y͋Qʨ_2x2!< ͋22 _!͋{>!~2>22 : 02 ! p! ͋!9 !C$! !E ͋!? p2 !O"D!R !IG:^!C4! p!V p!)2 20: 22!i : 21>2 2 !/ ! : O>@# ¡!1~6+4: y!u p! 5! ! 5! p>&2P"Q2S w++~@" : * D<2 * q ( #w#)!m pp0dW WW/Y{j l s#~|#p_͒! pp#Ny2 " ʨG#~#~#p! p#~ : O* æ>.%O6N:@((~ 2@6NÅ6N6N6N>2@>@:<2>ͦ~2@!+| w ͠n(!@~>v>6 :ģ!@@(:@ :@(>>D2@6> 66>6z6> 6>6>6~6666>ww> 6> 6>6>6o6>ww>:<6 >26 6:266:@((~ 2@6È6>2@>@:<2>ͦ6 ~2@ͩ>͠n(6 :ģ:@@>6 ͩ(دݾ >2@!@q >>d0>$ 2@6:(66\  sQr{2sssw:( s:@( > :2( ~2@2@>@:<2!!1/>29"96 1:91x1*9##ssw:( srker, stack follows ds 30h ;Room for the stack buffer equ $ ;Track read buffer end BAUD COM!BAUD DOCBIOS ASM\ !"BOOTMW ASM>#$%&BOOTMW COM 'CBIOS& ASM()*+,-./CBIOS& ASM01234567CBIOS& ASM89:;<=>?CBIOS& ASM@ABCDEFGCBIOS& ASMHIJKLMNOCBIOS& ASMPQRSTUVWCBIOS& ASMXYZ[\]^_CBIOS& ASMw`abcdefgCBIOS ASMEhijklDDT COM&mnoDEBLOCK ASMOpqrstDISKDEF LIB1uvwxDUMP ASM!yz{DUMP COM|ED COM4}~FIRMB ASMyFORMATDJ$$$FORMATDJ$$$FORMATDJ$$$ 10%5 0%0%:%"%#e%) %G0%0%%#(P  Floppy disk format command for the Morrow Designs Disk Jockey DMA (DJDMA) floppy disk controller. Type an ESC or DEL, at any time, to return to the main menu. Select: (I) IBM 3740 compatable 8 inch format. (N) North Star compatable 5 1/4 inch format. back to CP/M. Select (I, N, or ): iIIBM 3740 formatnNNorth Star format Returning to CP/MSelect a drive ( 0, 1, 2, or 3 ): 0 Preparing to format drive 01Preparing to format drive 12Preparing to format drive 23Preparing to format drive 3Select: double density S single density dD Double density selected.sS Single density selected.Select the number of tracks ( 0=35, 1=40, 2=80 ): 0 35 track drive140 track drive280 track driveSelect the sector length ( 0=256, 1=512, 2=1024 ): 0256 byte sectors1512 byte sectors2 1024 byte sectorsSelect: N North star or CP/M data compatibility. )@ Written by: Les Kent *>#KM!9N#F#^#V#~#fo"Z^kb"X^i`"V^OGm40quantumm16aampexm19m16ccmim5seagateHeader CRCWrite faultData CRCData overrunData header not foundHeader not foundWrong headWrong cylDrive not readyController Busy,testverifyBad sector size.sizeBad skew factor.skewBad head number.headBad track number.trackBad drive arg.drive\!~w#~w!~w#~w!~#͢!\^ywx#w!~#fo~#2!~#foN#F!~#foN#F1(y`!~#fo"?m!~w#~w!~w#~w!~#fo~#p͢p!~w#~w!N#F!~w#~w}!!~#foN#F1(y&!~#p!~w#~w!~w#~w! !Am!~#foN#F͚5!~#foN#F)yʹ:Bm!Am>>#ù!Km~#qͯq!!~#foN#F1(y!~#p!~w#~w!~w#~w! !Mm!~#foN#F͚5!~#foN#F)yg:Nmg*?m##~#fo !Mmyx#og!͵!~w#~wp!!~#foN#F1(y!~#p!~w#~} :em2em:fm2fm Drive not ready.Can't read drive status.Controller does not respond.=V>P2,q2-q*,q*,q#",q^yOxGyw*,q*,q#",q!^!ʹW}o|g}*,q*,q#",q6:Am2^>2^2^>2^:Am2^>2^*?m ~2^*?m ~2^*Cm!͢V }2^>2^!^"^>2^͵ y"!C ͵>2^͵ y7!* ͵:^OGyOxGyR! ͵ʹSVLoad constants timeout in home. Can't recalibrate drive. Load constants timeout in home. \*Am}o|g}2^>2^2^>2^:Am2^>2^*?m ~2^*?m ~2^*Cm!͢V }2^>2^͵ y"!%KM!"^>2^͵ y@!y%KM>2^2^*?m ~2^>2^͵ ym!X%KM>2^2^\Seek timeout =V>P2,q2-q:^¢:^¨ʹ!:^¸:^#¾SV:Am2^>2^!!^  #*Am}o|g}2^*^!yOx#Gi`"^!:Am2^!~#fo!^yOx#Gi`"^>2^͵ y9!z%KM!~#fo"^SV sector: head: Verify timeout: track: =V:Am2^>2^2^!~#fo}/o|/g}o|g))!AmyOx#Gy2^!~#fo}o|g}2^!N#F!͉W}o|g}2^!~2^>2^!^",q*,q6*,q~OG!QmA_ !~#~*um)))C_ ! ~#~*=c#"=c\*um#"um9\ HardSoft%+ 5i %+ 4i %+ 6i %p Track Head Sector Type No bad sectors detected. Bad sector report: \!%!=c~#!}%\!Z!*=c(!b%!>w#w!!=c  #!~#fo)))C_ ~ #~+!DMD0!?MD!~#fo)))A_ N#F!~#fo)))?_ N#F!~#fo)))=_ N#F!I%! 9!~w#~w!=%\\!!~#fo)))=_ ~#fo!~#fo)))=_ yOx#Gywx#w+~#!~#foMD\!!~#fo)))?_ ~#fo!~#fo)))?_ yOx#Gywx#w+~#,!~#foMD\!~#fo)))A_ ~#fo!~#fo)))A_ yOx#G\\!9!!~#fo)))=_ ~#~!!~#fo)))?_ ~#~!!~#fo)))A_ ~#~!!~#fo)))C_ ~#~!~#fo)))=_ !~#fo)))=_ ~#~!~#fo)))?_ !~#fo)))?_ ~#~!~#fo)))A_ !~#fo)))A_ ~#~!~#fo)))C_ !~#fo)))C_ ~#~!~#fo)))=_ !~#~!~#fo)))?_ !~#~!~#fo)))A_ !~#~!~#fo)))C_ !~#~\Can't write bad sector map.Timeout on writw!~w#~w! !Om!~#foN#F͚5!~#foN#F)y:Pm*?m####~OG! !Omyx# !͵!~w#~wp!u!~#foN#F1(y!~#p!~w#~w!~w#~w! !Im!~#foN#F͚5!~#foN#F)yʒ:Jm!Im>@>#Ò!z͵!~w#~wp!_!~#foN#F1(yʪ!~#p!~w#~w!~w#~w! !Cm!~#foN#F͚5!~#foN#F)*CmMD!*ÿ[!d͵!~w#~wp!G!~#foN#F1(y7!~w#~w>2Gm2Hmp>2Em2Fm!~w#~wp>2Em2Fm>2Em2Fm>2Em2Fm>2Em2Fm!N͵!B!~#foN#F1(yk!~w#~w>2Km2Lmp͢pͭ\Usage: formatmw drive-type [agruments] \!zKM\ \!N#F!!KM\Checking format. Formatting. \P*?m ~#fo *Cm( !8_*Em ~OG ͢V"Qm` :Mm=:Nm]>2[m2\m*?m##~#fo "]mi*Mm"[m*Mm"]m:Omv:Pm›>2Wm2Xm*?m####~OGi` "Ymç*Om"Wm*Om"Ymͣ !?c"^ʹ!*[m"_m!_m:]m:^m# *_m͈*_mͧ *Wm"am!am:Ym:Zm#( *am !yx#>2gm> 2*q2+q:*q2*q:+q2+q!*q~#ʂ͵ y—![!N#Fc!S!N#Fc!I*,q~OGc!GSVSV:gmOGy‘x²^:^OGy¦xʂ:^2gm:gm#!*q~##!?e"(q!?e*Cm :(q:)q^*(q~OG!yx#e*(q?e}o|g*,q~OG!N#F!N#Fͼe! !*qyOx#G! *,q~OG!N#F!N#F:gmOGͭ! 9*,q4*(q#"(q FATAL! Count: Sector: Head: error. Track: Verify: \!!~#fo)$_ N#F!!N#Fc!!N#Fc!! N#Fc! ~ #~T!y! N#Fc!! N#F!N#F!N#F,!q!! N#F!N#F!N#F,!o\ Byte: Sector: Head: Data compare: Track: \!!N#Fc!!N#Fc!!N#Fc!! N#Fc!!!N#F!N#F!N#F,\\!!Uͬ[\\!!Tͬ[\\!9! !N#F!"i`! 6!\\!9!!~#fo}o|g!"i`! 6!\\!9!~#fo~!! Ky$!ing bad sector map.\!?e"wm!?m:wm:xm<*wm*wm#"wm6>2ym2zm!=c:ym:zm#y*ym)))?e *ym)))=_ ~#fo}o|g}*ym)))@e *ym)))=_ N#F!ʹW}o|g}*ym)))?_ N#F*QmW*ym)))A_ ~#fo #"{m*ym)))Ae *{m}o|g}*ym)))Be *{m!͉W}o|g}*ym)))Ce 6*ym)))De 6*Qm)#*ym #"{m*ym)))Ee *{m}o|g}*ym)))Fe *{m!͉W}o|g}*ym#"ymF!͈:Am2^>2^2^*Am}o|g}@o|g}2^*?m >#:^2^*?m >#:^2^!?e"^>2^>2^>2^>2^>2^>2^͵ y !͵:^OGyx&!͵\=V!~#fo",q!~#fo"(q!~#fo"*q!>w#w!:,qw:-q#w!>w#w!(q>#Ғ*,q> *,q~!(q>#*,q~-o !>w#w*,q#",q:(q2(q:)q2)q:(q2(q:)q2)q*,q#",qt! ~#~’ :(q:)qڒ *,q~0’ *,q ~A< *,q >Z< *,q ~OG! MDH *,q ~OGyxQ x’ *,q##",q:(q2(q:)q2)qÒ *,q~+*,q#",q:(q2(q:)q2)q!(q># *,q~0D!*,q>9D!!*,q~OG! }|Y!**q!~# !N#F>O>G !N#Fywx#w!(q>#*am*_mf *am#"amʹ!Gm~#2 \*_m#"_m!!?e"^>2^*[m"_m!_m:]m:^m# *_m͈*Wm"am!am:Ym:Zm# !*am*_ms*am#"amh ʹ\*_m#"_mK \!9!>w#w!!Qm  # !~#fo))Bc *Qm#}!~w#~wö !!>w#w+~#~!!Qm  #V !~#fo))Bc ~OG:Qm:RmY !!~#fo#*QmV}| \!~#fo))Bc !N#F!~w#~w}!!~#fo*Im *QmV}| =V!~#fo",q!?c"(q!?e:(q:)q *(q*,q}o|g}*(q *,q!͉W}o|g}*(q####"(qû SV=V!Ac",q!?e:,q:-q9 *,q!~*,q####",q SV Head: error. Track: Format timeout.=V!~#fo",q!~#fo"(q!~#fo"*q:Am2^>2^2^*(q}/o|/g}o|g))!AmyOx#Gy@OxGy2^*?m :,q:-q# :^2^*?m :,q:-q# :^2^!8_*Em ~OG! }/o|/g}2^*Qm}/o|/g}2^*Cm!͢V }/o|/g}2^:*q2^>2^͵ yZ !V ͵:^OGyi xr SV:^OGi`)$_ N#F!F *,qc!> *(qc!< SV\!"cm> 2em2fm>2^=!em~# :^ \\*cm:cm2cm:dm2dm!!Kyw!~BKMB\!~#fo~ x! !Kx!~$! KyL!!Kyox$KM$!~#fo~OG!K!~w#~wChecking disk. \!!>w#w!~#fo)^ #~ !N#F!~#fo)^ N#F;!~w#~w\ Reading - pass: data: Writing - pass: \P*?m ~#fo *Cm( !8_*Em ~OG ͢V"Qm` :Mm‚:Nm¢>2mm2nm*?m##~#fo "omî*Mm"mm*Mm"om:Om»:Pm>2im2jm*?m####~OGi` "km*Om"im*Om"kmͣ !?c"^ʹ!*!N#Fc!"!N#F͚! *mm"qm!qm:om:pm#*qm͈*qmͧ *im"sm!sm:km:lm#*sm !N#F*sm*qmf *sm#"smSʹ!Gm~#£\*qm#"qm.!!N#Fc! !?e"^>2^*mm"qm!qm:om:pm#*qm͈*im"sm!sm:km:lm#"!N#F*sm*qms*sm#"smʹ\*qm#"qm\>2um2vm!=c:um:vm#*um)))=_ ! a #0*um)))?_ ! } #0*um)))A_ ! ™ #0*um)))C_ !   #:*um)))C_ ! ~#~:*um)))=_ !~#~*um)))?_ !~#~*um)))*"*,q~A&!*,q>Z&!*,q~OG! MD.!*,q~OGyl7!x"*,q#",q"*,q~a!*,q>z!Þ!!!N#F! N#FW!~#fo }|:(q2(q:)q2)q*,q#",qÒ *,q~A *,q>Z !*,q~A!*,q>Z!*,q~OG! MD!*,q~OG! }|!!   #Y! *,q!yOx#GSV=V!~#fo",q*,q"*q!#~b"!>#b"!~#fo>o>g"(q**q**q#"*q6-m"!~#fo"(q!~#…"!> w#wê"!#~"!!~#fo>o>g}|!:(q:)q#"!N#F*(q!N#F/W**q"**q "*q**q*(q!N#FJW0 }**q>9 #**q~'w**q!,qyOx#GSV can't write can't read =V!9!t!}|!"(q!*(q*(q#"(q~!>##!>#*$*(q> :$*(q~*$:$!>w#w!v=#ywx#w!"*q!t:*q#:+q#$**q~<%!-D!!**q ͞%yʌ%!!/#**q !1#!%! 9!KMÌ%!>#Q$â#!~w#~w*(q#"(qÀ#!>#$*(q> $*(q~$!tN#F!t~w#~w*(q~A$*(q>Z$*(q~OG! MDò$*(q~OGyw!~w#~w*(q#"(qQ$!tN#F!t~w#~w6s#!v!N#FͽSV**q#!!N#F!!yOx#G! ~#fo >+F+N=--!$3!9ywx#w! ! ~#fo }|ã+!!}|!*(q! ~#fo##N#F+++N#F!5ywx#w! ! ~#fo####}|ã+!!}|!>w#w! ! ~#fo####}|ã+**q~dq.!!}|!!>>#!.(.!N#F!! ~#fo >+F+N=;.!͌0!9ywx#w! ! ~#fo }|ã+**q~cʕ.**q~sʕ.**q~iʕ.!~.!~a.!! N#F! ~w#~w}|**q~c9/!>w#wÿ/!:*qw:+q#w!>w#wã+!! N#F! ~w#~w~#~**q~cŽ/!(q>#/!~w#~wÎ/!!~#fo~#~!!N#F!͉W}!!~!!}|!>w#wÿ/!!}|!*(q!N#F!p9ywx#w**q~cʣ+**q~sʣ+**q~iʣ+:*q2*q:+q2+qã+!># 0!N#F!N#F!N#F!~#fo\!~#p)!!  #p)!!!N#F!~#fo\!~w#~w*0\!N#F!!N#F?\=V!9!~#fo",q!!qR0!!q~#~0!qUoU*,q*,q#",q6-!!~#fo!~#fo }|*,q *,qN#FKy!9xA9! !k7!K!KM7*,q >w#w7!~#foMDSV*,q >w#wR9=V!~#fo",q*,q"*q!#~9!>#9!!~#fo>o>g}|**q**q#"*q6-!~#fo}o|g"(q!~#9!> w#w:!#~:!!~#fo>o>g}|!:(q:)q#L:!N#F*(q!N#F/W**qp9**q "*q**q*(q!N#FJW0 }**q>9w:**q~'w**q!,qyOx#GSV=V!9!~#fo",q>2(q2)q!#~:!!q~#~:!qUoU!!pRb;*q "*q!*q>#2*q2+q!:*q:+q#.=!~#.=!!q~#~™;!q!pSoU!!U!!q~#~;!q! q!N#F[[,UoU*,q*,q#",q!~#fo0 }**q#"*ql;!!pRr#b;!**q)))p q~#~d%!-D!!**q l0y6%xʌ%!! #**q !"#!%! 9!KMÌ%!N#F!~w#~w)!v :*qw:+q#w**q~$**q#"*qÌ%\!N#F!~#ʹ%ü%!N#F?\\!!N#F!}m!7<)\=V!",q*,q~#/&*,qN#F͚5*,qN#F!N#FK*,q##",q%SV=V!~#fo",q!!  #V&SV!~#fo "(q!~#fo"*q!*q:(q:)q#&*(q#"(q!*q:(q:)q#&*,q !N#F*(q*,q~#fo\>&&!:(q&:)q#t'*,q !N#F*(q*,q ~#fo\t':*q2*q:+q2+q!*q:(q:)q#A'*,q !N#F**q*,q~#fo\x&!*q:(q:)q#p&*,q **q*(q*,q ~#fo\p&*(q!yOx#G!~#fo!(qyOx#G}|'*,q*(q !N#F2&*,q!N#F*(q 2& (*,q!N#F*(q 2&*,q*(q !N#F2&SV\!!~#fo !2&\=V!~#fo",q!~#fo"(q*(q~u(*,q*,q#",q*(q*(q#"(q J(SV*,q~ƒ(Æ(SV=V!~#fo",q!~#fo"(q!~#fo"*q*,q~nʿ(*,q~N(*,q#",q*(q**qN#F**q~w#~w~#fo}|*,qMDSV*(q>w#w*,q~0!>>#1!>w#w!!~#fo#! >+F+N=41!͊:! 9ywx#w!!N#F!~#fo#!LC~w#~w>2(q2)q!:(q:)q#1!:(q:)q#1*,q*,q#",q!*(q ~*(q#"(q!~w#~wÄ1!>#O2*,q*,q#",q6.>2*q2+q!:*q:+q#ғ2*(q**q !yx#2*,q*,q#",q!*(q ~*(q#"(q**q#"*q1*,q*,q#",q6e!#~2*,q*,q#",q6-!!~#fo>o>g}|2!:*q:+q#O2*,q*,q#",q60**q#"*qÓ2*,q*,q#",q6+*,q*,q#",q!N#F! ͢V0 }*,q*,q#",q!N#F! V0 }*,q!yOx#GSV=V!9!~#fo",q!~#fo"*q!!qR3**q**q#"*q6-!!q~#~r3!qUoU!"(q!!! >+F+N= 3*(q͊:! 9ywx#w!!~#fo*,q }|!>>#3!>w#w!!N#F!!LC~w#~w!!  #Q4!~#fo!yOx#G*(q "(q!!~#~!>#4**q**q#"*q60!,q>#4**q**q#"*q6.4!>#l4**q**q#"*q*(q!yOxGyx4*(q*(q#"(q~OG40yw!~w#~wÉ4!#~)5!,q>#)5**q***q eW:(q2(q:)q2)q:*q2*q:+q2+qè2,q2-q!o:,q:-q#Ҽ=*,q-D*,q#",qÛ=:oOG!K*oMDSV=V!~#fo",q!oywx#w!~#fo~#9>*,q"*q!~#fo~#fo"(q**q*(q O>*(q~O>**q#"*q*(q#"(q>SV!~w#~w=**q*(q ?>!~#fo##~OGSV=V!~#fo",q!~#fo"(q>2*q2+q*(q~.>*(q~>:*q:+q>**q**q#"*q*,q *(q~a>*(q>z>*(q~OG! MD>*(q~OGyw*(q#"(qÑ>:*q:+q(?**q**q#"*q*,q 6 >*(q~.;?*(q#"(qI?*(q~I?SV>2*q2+q*(q~ʸ?:*q:+q?**q**q#"*q*,q *(q~a?*(q>z?*(q~OG! MDë?*(q~OGyw*(q#"(qS?:*q:+q?**q**q#"*q*,q 6 ø?*(q~OGSV=V!9!~#fo",q:o@!!Ky2o!>w#w!!o  #H@!~#fo))p ~`@!!o  #p@SV!~w#~w#@!!~#fo))p }|!~#fo6!!~#©@!~#fo~w!~#fo##>w#w!:,qw:-q#w>2(q2)q*,q~:5A*,q~5A:(q:)qfA*(q*(q#"(q!(*,q>9(*(q*,q~OG*(q~#foMD)) )  }|*,q#",q(=V!9!~#fo",q*,q"*q**q~})**q~%})**q#"*qU)**q ",qO)!*q:,q:-q#Ҷ)**q!,qyOx#G*,q!N#F!~#fo\**q**q#"*q~)SV!>w#w!6 **q~- *!>w#w!**q#"*q**q~**q#"*q-***q~+-*!**q#"*q**q~**q#"*q! !**q͉(i`"*q!>w#w**q~.w*! !**q ͉(i`"*q**q~aʛ***q~hʛ***q~oʛ***q~u*!**q**q#"*q~!~h*>2(q2)q+!6ï*!~o*>2(q2)q+!~u*> 2(q2)q+!"(q**q~x+!>w#wã+**q~b+!! N#F! ~w#~w~#~!! N#F! ~w#~w~#fo}|!~#ʣ+!!!  #+!N#FÝ+!N#Fywx#w!~#/!!  #/!!!N#F!~#fo\!~w#~wí+**q~pq,!! ~#fo~#~!! N#F! ~w#~wN#F͚5ywx#w!~#ʣ+!!!  #a,!N#Fh,!N#Fywx#wã+**q~l,!~ac-!! ~#fo~#~#~#~!>w#w!~w#~w+#~-!!~#fo !##~!!uZë,**q~f-!!}|*q#"*q60!~w#~w:,q2,q:-q2-q4!,q>#5**q**q#"*q*(q!yOxGyxn5*(q*(q#"(q~OGq50yw:,q2,q:-q2-q)5**q!yOx#GSV=V!~#fo",q*,q"(q*(q~5*(q#"(qî5*(q!,qyOx#GSV=V!~#fo",q*,q"(q!#~@6! >#@6!!q~#~#~#~!qZ~#~#~#~*(q*(q#"(q6-! ~#X6! > w#w}6! #~}6! ! ~#fo>o>g}|!! #~~+~ !#~6!!YX6! N#F!q~#~#~#~!q!Y##N#F+++N#F*(q5*(q "(q*(q!q~#~#~#~!q!7Z>02"q2#q2!q2 q! q+X##~*(q>9K7*(q~'w*(q!,qyOx#GSVwrite error write error bad putl call =V!~#fo",q!~#fo"(q!,q~#7!!x7!K!KMSV!~#fo"*q!*q>#e8!*,q *,q ~#fo }|!*q>#8*,q ~#~8!N#F!~w#~w*(q*(q#"(q~:*q2*q:+q2+q*,q ~w#~w7*,q ~v8#~R9*,q ~#R9*,q ~#fo*,q ~ R9*,q N#F*,q *,qN#FK*,q y8x#_9! !^7!K!KMR9!*q>#7!+ *,q~a'A*,q>z'A*,q~OG! MD/A*,q~OGywfA!*(q 6*,q~:pA!~#fo",q!~#fo#:owåA*,q#",q@!~#fo#!=yw~žA!N#F-DSV*,q#",q!~#fo#~A!~#fo#~OGyAx9B!~A#~9B!!Ei`"*q!~#fo##:*qw:+q#w!**qQ**q( >w>#w!~#fo#~FB!~#foMDSV!~#foMDSV*,q**qn>yjB!N#F-DSV!~#fo#~OG!K!~#fo}o|g}›B|B**q!Kx)C!N#F-DSV**q!K!~B#~B!N#F-D!~#foMDSV**q!KxC!N#F-DSV!~#fo~w!o~#?C!=Mi`"o!~#foMDSV=V!~#fo",q!#~C!!  #C*,q!~#fo ~5C!~#fo "(q:)qC*,q*(q ~9D*,q*(q 60:(q2(q:)q2)qÛCSV:)qC*,q61!~#fo"(q!(q>#'D*,q*(q 60:(q2(q:)q2)qC*,q*(q 4CSV=V!N#FMi`",q!,q~#PDSV*,q ~#D*,q~OGyOxGyD!*,qͣO*,q~OGy OxGyʻD*,q ~#fo ~w*,q N#F!K*,q !*,q N#F;Hywx#w*,q6!~#foMDSV=V!~#fo",q!w+L=V!~#fo",q:-q7M!o:,q:-q#7M*,q))p ~=MSV*,q))p MDSV\!o~#vM!M:oeM:ovM*o\i`"oNM*o\vM=V*o",q!~#fo"o*,qMDSVOOO=V!~#fo",q*,q ~#fo"(q!*(q$ q~#~#~#~!q!uZ##~#~*(q$ ##N#Fi`}o|g"*q*(q! !!*qyOx#Gyw*(q" *(q* **q }|!~#pN!*(q( gN #pNSV!*,qͣOxN!N#F!N#F*,qͷPxNSV*(q ~OG*(q ~OGyOxG}|NNi`"*q!*(q( N #N**qMDSV*(q( !~#~!*q~#2O!*(q* QSV*,q ~OG!K*(q* !K*(q!Ki`"*q!!K**qMD!Mÿ[SV!*(q* QSVSV=V!~#fo",q*,q ~#fo"(q*,q~OGyOxGyO!*(q( N#F*,qͷPyOxKPSV!~#ʱP*,q~OGyOxGyʱP*,q ~OG!K*(q!K*,q~wñP*,q ~OG!K*(q* !K*(q!Ki`"*q!!K!*q~#ʠPSV*,q~w*,q~wOSV=V!~#fo",q*,q ~#fo"*q!N#F!͉W"(q**q ~OG:(qP:)qQ!94æX!9!9G^#~#~+++~#~#~ Y#>#>+++>#~#~#~ #~{RY>#># ># Y!9MD!9~#fo2Y! 9MD!9~#fo2Y̓X!9N#F!9eYY Y!9MD!9~#fo2Y! 9MD!9~#fo2Y̓X!9N#F!9eYY Y! 9MD!9~#fo# Y!9MD!9~#fo# Y̓X!9N#Fkb9RYY YY!9~OZ/<ÅZG^O!9~#fo##~w#~w+++~w#~w \ZG^!9~Z/#w>+++w>#wMD!9!9!N#F!>w#w#w##w#w!!\! N#F !#~L[G^[q#px#w#w+[[q#p#w#w+[[ w #w #w #w+[[ w #w #w #w+[&}!!9\~#[#~#foy#[x#[+++~#fo##ÿ[!9!9!N#F!]y\!q#p! N#F!]y0\!N#Fï\!yOx#GR\y\+~w#~w!]\O>G! ~#+~wc\q\w y~\^\!MD!  #w\!N#F!\!MD ! ~#fo+ #w¼\G^!9!9N#F! ~\i`+ >#w\ ]+~#fo"(q*,q*(q "*q**q*,q~#fo!(qyOx#Gywx#w**q *,q ~#~*,q*(q }|**qMDSV=V!~#fo",q*,q ~#fo"(q*,q*,q~#fo ####!(qyœEx#E*,q*(q~#fo####  *,q *(q ~#~SVout of heap space =V!N#F!N#F-Fi`",q!,q~#F*,qMDSV!!E!K!KMSV=V!~#fo",q:,q:-qPFUF*,qMDi`#}o|g##",q!o"(q*(q~#fo"*q!*q~#ʼF**q~#fo####!,qyx#F**q!,q  #F*(q**q ~#~G:oF:o!G:o2o:o2o!G**q "(qkF*(q*,q**qDywx#w**q !~#~**q MDSV!>w#w!,q:o:o#uG!!:ow:o#w+N#F͆Iywx#w+~#uG:o2o:o2o,G!~# G!!:,qw:-q#w+N#F͆Iywx#w!~#°GSV!~#fo!~#fo }|!o~#G!~#fo"o!~#fo!~#fo :o:oH!~#fo!~#fo "o!!~#fo##;HeFbad free call =V!~#fo ",q!~#ʏH!o:,q:-q#uH!o:,q:-q#ڜH!!,H!K!KM!~#foMDSV!o~#¼H*,q >w#w*,q"oÏH!o:,q:-q#H*,q :ow:o#w*,q"o*,qaEÏH*o"(q*(q ~#fo"*q*,q~OGy OxGy¬Q*,q ~OG!K*,q~OGyOxGyXQ**q!KxXQSV*,q~w**q :(qw**q!KxQ!~#¥Q**q!KxQ*,q~wSV*,q~ w**q !~#fo}o|g}SV=V!~#fo",q!~#fo"(q:(q2(q:)q2)q:)q R*,q6*,q#",qQSV! 9~#foN#Fx)RO>G!9~#fo^#Vz@R_>WxƀGzƀWyoxYR^R>ÆR>ÆR! 9N#F!9~#fo# ##‹R +‹RqRч/^YRTR!9!9!6!N#F!]yR! N#F > S!~R!>#wR!4!q#p! N#F S!4 !]ySy!Ox#Gyƀ+wx#w !#w DS!69!#~w WS!MD! +wSlSژS!MD!  #‰S!4! +~w ŸS!5PS!N#F!\!~S!~#S~w! N#F !#~SG^!9!9! N#F!6 Tƀ4 !]yU!q#p!N#F!]y^T! N#F &%UTU!~O#~Gyր+wx#w! #w zT>8!w! ~#+~w T!~T!MD!  #¯T!#~w T!5‡T!N#F!\!~T!~#T~w! N#F ]\ÿ]! ~/]# +~w]!9~w#~w ]! ~V]i`+ #~w>]!9~w#~w/] n]i`7#~wb] ]!9~]i`+#w}]ÿ]ʙ]i`>#w]>w! !9z~w+~ w++~ w³]!!9N#F!9^#V! #~#~ ]! ~#~W]+ ^^)^>w+~w})^i`>#w ^J!9N#F###q#p+++q!9N#F#q#p((((2(`` (~`` (v (r (U @  +@!*q~#!I!,q:*q:+q#!I**q"(qH!*q~#]I*,q :*qw:+q#w*(q :,qw:-q#w*,qaE*(qaEÏH*,q >w#w*(q :,qw:-q#w*(qaEÏH\!:ow:o#w*o!~#fo "o!:o:oI!.q:o:oI!~#fo"o\!~#foMD\JJJK=V!~#fo",q!~#fo"*q!>#QJ! KyOxGydJ!KyCJxdJ!KMdJ**q!yOx#GSV*,q ~J*,q ~OG!Iÿ[*,q ~#fo"(q!*,qͧMy¦JxKSV**q~OG!K!~w#~w**q#"*qJ**q~OG!KJ**q~OG!KJ!~#foMDSV!>#K*(q! ~ʐK*(q" N#F*(q" ~w#~w**q**q#"*q~*(q$ >2q2q>2q>2q!q+X!~w#~w*(q! 5K*,q~OGyOxGyʾK*(q! ~ʾK*(q" ~#fo6*,q~wJ =V!N#FMi`"*q!*q~#KSV**q~OGyOxGy L!N#F!N#F**qISV!~#fo",q!>#kL*,q"(q!>#~L*,q~ ~L*,q#",q!~w#~w>L*,q!yOx#GSV*,q!(qyOx#G*(q**qI*,q!(qyOx#G}´L|ʽLSV!>#+L!!K**qIyLxLSV*,q#",q!~w#~ !#~UG^!9~#fo~#*U~ƀw!9!9!N#F ! #wHU!~ƀw! N#F![G^!9N#F!9~#fo~#~…UG^MD!9!9!N#F!]yUy֨OxGU!~#+~wUyUUyU!#~wU U! ͑UN#F!~#~G^͑UN#F!~+~ +~+~ G^͑UMDV!9*,q**q*(qi`!"(q"*q",q!9~w#~w#~w#~w+MD!9 _ #pV{ !94pV! 9~V+w>#w! 9N#FxVO>GfVVO>G! 9q#pG^! 9~W+w>#w! 9N#FxWO>GfV$WO>G! 9q#pG^! 9N#FfV! 9q#pG^! 9N#FfV! 9q#pG^!9~uW/<ÙWG^O!9~#fo) WW!9~W/ ?2jʜ xy!6>@=«~fzWN̓f6 ~~~!*!>*ͮ& :kJo&N#F!!B xy&>*ͮ>YZ_b$>MOg͎͓F͎:hͮ  :> :a{ _ 22::>>*3<E:j2u8<2u:j.PN>2p F p N66662Np ^ p f6666r6s66Np  p ‡6666@p —@p ž@p ¥@p ¬6>6Np ¸cp p p ~!8#^ w=  @ (Yq ÒPN 662N 66N 66 @@@@6N倀jN tN Drive $ Is Not Ready.$ Is Write Protected.$ Improper Response.$ Select Drive (A,B,C,or D): $Disk Jockey 2D Disk Format program Revision 5.2 Type "^C" to return to CP/M, "N" Form Feed abel equ 7 ;Bell asp equ 20h ;Space anul equ 0 ;Null adel equ 7fh ;Delete ars equ 1eh ;RS character aus equ 1fh ;US character avt equ 0bh ;Vertical tab ***************************************************************** * The following equates are for the Mult I/O board. * ***************************************************************** grp equ 7 ;Group select port offset clk equ 2 ;WB14 printer select port pic0 equ 4 ;Interrupt controller port 0 pic1 equ 5 ;Interrupt controller port 1 daisy0 equ 0 ;Daisy wheel port 0 daisy1 equ 1 ;Daisy wheel port 1 imask equ 40h ;Interrupt enable mask d4 equ 10h ;8259 data bit 4 ltim equ 8 ;Level triggered interrupt mode addi equ 4 ;Address interval sngl equ 2 ;Single 8259 eoi6 equ 66h ;End of interrupt 6 rstbit equ 080h ;Restore Bit data11 equ 4 ;Data bits on daisy port data12 equ 8 data910 equ 3 crstrd equ 1020h ;Carriage ready pfstrd equ 810h ;Paper feed ready pwstrd equ 2040h ;Print wheel ready cp/K software handshake ; returns with: ; A = 0 No ACK to transmit ; A = 0ffh ACK transmitted endif ***************************************************************** * Dynamic data locations used by the simulator. * ***************************************************************** ; (made for electric pencil) base: db 48h ;Default Mult I/O board base address ; Can be changed with -bxx. dfrmln: dw 110 ;Default forms length 10 times the forms ; length switch. Can be changed ; with -fxx. dspace: dw cperi ;Default characters per inch. ; Can be changed with -cxx. dlines: dw lperi ;Default lines per inch. ; Can be changed with -lxx. autolf: db 0 ;Default to no Auto line feed. ; Can be changed with -ax. hmi: dw 0 ;Horizontal motion index. Set by RESTORE ; and escape sequences. vmi: dw 0 ;Vertical motion index. Set by RESTORE ; and escape sequences. vpos: dw 0 ;Vertical position. Set by platen motion dlvpos: dw 0 ;Delta vpos.  nomore: call rest ;Reset the printer jmp owboot ;Go to the warm boot scan: push h ;Return the next character in the command lhld scstuf ;Pointer to next char mov a,m ;Get next char ana a ;Test error return jz noupdt ;No update inx h ;Update pointer shld scstuf ;Save new pointer noupdt: pop h ;Restore registers ret if int newh: call scan ;End of command ? rz cpi '1' jc zret ;Invalid ? cpi '3'+1 jnc zret sui '0' sta ackxon ;Set new handshake option endif zret: mvi a,0 ret newb: call scan ;End of command ? rz call okhex ;Valid hex character ? jc zret ral ! ral ! ral ! ral mov b,a call scan rz call okhex ;Valid hex character ? jc zret ora b mov b,a ani 7 ;Check if divisible by 8 jnz zret mov a,b sta base ;New I/O base jmp zret newf: call gettwo ;New default forms length jc zret lxi d,10 ;Set to ten times the forms length call hltde shld dfrmln jmp zret gettwo: call scan ;Get two decimal digitwith ETX/ACK handshake. * ***************************************************************** nconin: lda ackxon ;Determine the type of handshake cpi 3 jnz oconin ;None, do old conin call oconst ana a jnz oconin call hndetx ana a mvi a,aack jz nconin ret endif ***************************************************************** * List is the New list device output. As implemented, it uses * * an XON/XOFF or ETX/ACK protocal. * ***************************************************************** nlist: if not int jmp diablo else lda ackxon dcr a jm lst dcr a jm lstetx dcr a jm lstxon jmp lst lstetx: push b ;Save the character call lst ;Print the character pop b mov a,c ;Check if it was a carriage return cpi acr rnz mvi c,aetx ;Send an ETX call lst wetx: call hndetx ;Check if ACK ana a rnz jmp wetx lstxon: push b ;Save char to print call hndxof ;Check XOFF cpi 1 ;Is it full ? cz wxoff pop b ;Recover char to pSet by platen motion hpos: dw 0 ;Horizontal position. Set by carriage motion dlhpos: dw 0 ;Delta hpos. Set by carriage motion lmar: dw 0 ;Left margin dirflg: db 0 ;Direction flag grhflg: db 0 ;Graphics mode flag escflg: db 0 ;Escape sequence in progress flag scstuf dw 80h ;Scan buffer data tabstp: ds numtabs ;Tab stops array ds 30 ;Stack space stack equ $ if int queue: ds maxchrs ;Circular Queue of printer characters quetop: dw queue ;Queue top pointer quebot: dw queue ;Queue bottom pointer hlsave: dw 0 ;Used by interrupt routine afsave: db 0 ;Used by interrupt routine hndflg: db 0 ;Handshake in progress flag etxflg: db 0 ;Used for ETX/ACK handshake ackxon: db 2 ;Default handshake is XON/XOFF ; Can be changed with -Hx. ; Possible handshakes are: ; 0 = none ; 1 = ETX/ACK ; 2 = XON/XOFF ; 3 = ETX/ACK through console * * The following data only needs to be included if the 8259 * has not been initialized. * dw 0,0,0,0 dw 0s jz nogd ;No digits call ok09 ;Check for 0-9 jc nogd add a ;Multiply by 10 mov b,a add a add a add b mov b,a call scan ;Get next character jz nogd ;No character call ok09 ;Check if 0-9 jc nogd ;No good add b ;Add into result mov l,a mvi h,0 ;Make it a 16 bit number ret nogd: stc ;Error return ret newc: call scan ;Change the default characters per inch rz cpi '1' ;Must be 10 or 12 jnz zret call scan rz ;Only one character cpi '0' mvi l,10 ;It was ten jz newcok cpi '2' mvi l,12 ;It was 12 jnz zret newcok: mvi h,0 ;Make 16 bit integer shld dspace jmp zret newl: call gettwo ;New lines per inch jc zret ;Error reading digits shld dlines jmp zret newa: call scan ;New auto line feed cpi '1' ;Must be 0 or 1 jz newaok cpi '0' jnz zret newaok: sui '0' ;Set the auto flag sta autolf jmp zret okhex: call ok09 ;Check first if 0-9 rnc ;Yes okaf: cpi 'A' ;Check if less than 'A' rc cpi 'F'+1 ;Checrint jmp lst wxoff: call hndxof ;Check XON cpi 0ffh jnz wxoff ret endif ***************************************************************** * New list device status routine. Returns 0ffh if the printer * * can except another character, otherwise it returns 0. * ***************************************************************** nlstst: if not int call group0 lxi d,pwstrd lda base call input ana d mvi a,0 rz cma ret else call hndxof ;Check # of characters in queue cpi 1 mvi a,0 rz ;Can not except another char cma ret ***************************************************************** * Xonoff status. Checks if there are any characters in the * * printers character queue. Returns with reg A = 1 if the * * character queue is within 10 characters of being full, or * * returns with reg A = 0ffh if the character queue is within * * 10 characters from being empty, otherwise returns 0. * * This can be used to implement the XON and XOFF protocal. *,0,0,0 dw 0,0,0,0 dw 0,0,0,0 table: jmp noint ;No interrupt db 0 jmp noint db 0 jmp noint db 0 jmp noint db 0 jmp noint db 0 jmp noint db 0 jmp pwint db 0 jmp noint db 0 endif ***************************************************************** * New Boot routine, examine the command line put at 80H by * * install. * ***************************************************************** nwboot: mvi a,1 ;Is this a second warm boot ? wbflg equ $-1 ana a mvi a,0 ;Reset the warm boot flag sta wbflg jz owboot ;Don't reset if second warm boot jmp skpdsh cloop: call scan jz nomore cpi '-' ;Check for flag jnz cloop skpdsh: call scan jz nomore if int cpi 'H' ;New handshake routine -Hx cz newh endif cpi 'B' ;New I/O base -Bxx cz newb cpi 'F' ;New forms length -Fxx cz newf cpi 'C' ;New characters per inch -Cxx cz newc cpi 'L' ;New lines per inch -Lxx cz newl cpi 'A' ;New auto line feed -Ax cz newa jmp cloop k if greater than 'F' cmc rc sui 'A'+10 ;Make into binary ret ok09: cpi '0' ;Check for 0-9 rc ;Less than '0' cpi '9'+1 ;Check if greater than '9' cmc rc sui '0' ;Turn into binary ret ***************************************************************** * New select disk routine, disable interrupts. * ***************************************************************** if int nsel: di call osel ;Execute old disk select ei ret nrd: di ;Execute old disk read call ord ei ret nwr: di call owr ;Execute old disk write ei ret ***************************************************************** * New console status routine, used with ETX/ACK handshake. * ***************************************************************** nconst: lda ackxon cpi 3 jnz oconst call oconst ;Check old console status ana a rnz jmp hndetx ;Check ETX handshake ***************************************************************** * New console input routine, used 0 ***************************************************************** xonoff: call quesiz ;Get number of characters in queue xchg lxi h,maxchrs-10 call hlcde mvi a,1 rc lxi h,10 call hlcde mvi a,0 rc cma ret ***************************************************************** * ETX/ACK handshake routine. * ***************************************************************** etxack: di lda etxflg mov b,a xra a sta etxflg ei mov a,b ret ***************************************************************** * Quesiz returns the number of characters in the queue in HL. * ***************************************************************** quesiz: di lhld quetop ;Get pointer to top of queue xchg lhld quebot ;Get pointer to bottom of queue ei call hlcde ;Compare HL with DE jnc hlmde ;Subtract DE from HL xchg call hlmde xchg lxi h,maxchrs jmp hlmde endif ***************************************************************** * Lstdev just puts cers per inch lxi h,hinc ;HL = maximum increments per inch call hldde ;Divide Hl by DE shld hmi ;Save hmi = 120/(characters per inch) lhld dlines ;Lines per inch xchg ;DE = lines per inch lxi h,vinc ;HL = MAximum increments per inch call hldde ;Divide HL by DE shld vmi ;Save vmi = 48/(lines per inch) lxi h,0 ;Other variables default to zero shld vpos shld dlvpos shld hpos shld dlhpos shld lmar xra a sta dirflg sta grhflg if int sta escflg sta hndflg lxi h,queue ;Zero the command queue shld quetop shld quebot mvi b,eoi6 ;Specific end of interrupt 6 lda base adi pic0 call output lda base ;Get the interrupt mask bits adi pic1 call input ani 0ffh-imask ;Enable the daisy port interrupt mov b,a lda base adi pic1 call output ;Output the daisy port interrupt mask low ei ;Ok for interrupts now endif ***************************************************************** * Clear all tab stops. * ******************** ;Go back ***************************************************************** * Empty turns off the print wheel interrupt mask bit if the * * character queue is empty when an interrupt occurs. * ***************************************************************** empty: call paper ;Print any remaining motion call carrg call group0 lda base ;Base of Mult I/O adi pic1 ;Get the interrupt mask register call input ;Read the current mask ori imask ;Turn on the bit mov b,a ;Data into B lda base ;Put the mask back adi pic1 call output jmp intret ret endif ***************************************************************** * Diablo does all of the character decoding, escape sequences * * forward, backward, etc. The list of escape sequences, and * * special characters recognized is: * * adel ignored * * anul ignored * * aack ignored (when received) * * abel ignored * * aff form feed * * aetx etx/ack handshake * * aht horizontal tab * * haracters in the printer queue. characters * * are removed from the queue by the print wheel interrupt * * service routine. * ***************************************************************** if int lstdev: di ;Disabled while manipulating queue lhld quebot ;Get pointer to next slot mov m,c ;Insert the character inx h ;Point to next slot shld quebot lxi d,queue+maxchrs ;Address of first byte beyond queue call hlcde ;Compare HL with DE jnz lstdon ;No match, don't wrap around lxi h,queue ;First address in queue shld quebot lstdon: call group0 lda base adi pic1 ;8259 mask register call input ;Get current mask contents ani 0ffh-imask ;Turn on print wheel interrupt mov b,a lda base adi pic1 call output ei ret endif ***************************************************************** * Restore routine. Restore should be executed to reset the * * printer into a known state, and initialize all the ram * * dynamic data locations. * ********************************************* notabs: lxi h,tabstp ;Beginning of tab stop array lxi d,numtabs ;Number of tab stops notblp: mvi m,0 ;Reset the tab inx h ;Next tab stop dcx d ;Update repeat count mov a,e ;Test for zero ora d jnz notblp ;Continue zeroing ret ***************************************************************** * Noint should never be executed. If it is then just die. * ***************************************************************** if int noint: jmp noint ;Die in jump self endif ***************************************************************** * Pwint is the interrupt service routine for the Hityp II. * * Remember: interrupts are disabled. * ***************************************************************** pwint: if int sta afsave ;Save the acumulator shld hlsave ;Save HL ral ;Get the carry into register A lxi h,0 dad sp ;Get the Stack pointer lxi sp,stack ;Set up new stack push h ;Save old stack pointer alf line feed * * asp space * * abs backspace * * acr carriage return * * aesc 0 ignored * * aesc 1 set tab stop at current print position * * aesc 2 clear all tab stops * * aesc 3 graphics mode on * * aesc 4 graphics mode off * * aesc 5 forward print * * aesc 6 backward print * * aesc 8 clear tab stop * * aesc 9 set left margin * * aesc A ignored * * aesc B ignored * * aesc D negative half line feed * * aesc U half line feed * * aesc alf negative line feed * * aesc aht c absolute horizontal tab * * aesc avt c absolute vertical tab * * aesc ars c set vmi * * aesc aus c set hmi * ***************************************************************** diablo: mov a,c ;Get the character to print ani 7fh ;Strip off parity rz cpi adel ;Ignore delete rz mov c,a ;Save character lda escflg lxi h,level0 ;Level zero characters ana a mov a,c ;Scan for char in A jz lookup ;Look up activity for this  * Restore assumes that the 8259 interrupt controller on the * * Mult I/O board has already been initialized. * ***************************************************************** restor: if int di ;No interrupts lxi d,table lxi h,table mov a,l ani 0e0h ;Form 32 byte boundry mov l,a push h mvi c,32 sloop: ldax d mov m,a inx h inx d dcr c jnz sloop pop h call group0 mov a,l ori d4+ltim+addi+sngl mov b,a lda base adi pic0 call output mov b,h lda base adi pic1 call output mvi b,0ffh lda base adi pic1 call output * * End of 8259 initialization * endif select: call group0 lda base adi clk mvi b,80h ;Set select line active. call output lda base ;Get base I/O port mvi b,0ffh-rstbit ;Low bit on restore, others high call output ;Output data in register B lda base ;Base I/O port mvi b,-1 ;Output Restore bit high call output ;Output data in register B lhld dspace ;Characters per inch xchg ;DE = charactrar ;Restore the carry lda afsave ;Get original contents of acumulator push psw ;Save acc lhld hlsave ;Get original contents of HL push h ;Save HL push b ;Save BC push d ;Save DE call group0 ;Select group 0 lhld quebot ;Get bottom of queue xchg lhld quetop ;Get top of queue call hlcde ;Is there anything in the queue ? jz empty ;No, queue is empty mov c,m ;Get the next character inx h ;Bump queue pointer shld quetop ;Save the adjusted queue top lxi d,queue+maxchrs ;Address of byte past queue call hlcde ;Need to wrap ? jnz pwdon lxi h,queue ;Adjust queue top shld quetop pwdon: call diablo ;Process the character intret: call group0 mvi b,eoi6 ;End of interrupt service routine lda base adi pic0 call output pop d ;Restore DE pop b ;Restore BC pop h ;Get original HL pop psw ;Restore PSW shld hlsave ;Save HL pop h ;Get original SP sphl ;Restore original SP lhld hlsave ;Restore HL ei ;Turn interrupts back on ret 1character lda escflg lxi h,level1 ;Single character escae sequences cpi aesc mov a,c ;Scan for char in A jz lookup ;Execute single level escape sequence lxi h,level2 ;Two character escape sequence lda escflg ***************************************************************** * Lookup scans the table pointed at by HL looking for a match * * of the character in register A. * ***************************************************************** lookup: dcr m ;Test if end of table inr m jz gother ;Execute the default function cmp m ;Otherwise test for a match jz gother inx h ;Bump over character inx h ;Bump over function address inx h jmp lookup gother: inx h ;Bump over character mov a,m ;Get low byte of function address inx h mov h,m ;Get high byte of function address mov l,a ;Form Address of function pchl ;Execute it ***************************************************************** * Each of the following tables contains entries of the form: * * 1i call neghl call adjvp jmp func1 doasp: call sphmi ;Get space horizontal motion spdir: lda dirflg ;Forward or backwards ? ana a cnz neghl ;Negate HL adjhp: xchg ;Adjust Horizontal position lhld dlhpos ;Get current adjustment dad d ;Update it shld dlhpos ;And save ret sphmi: lda grhflg ;In graphics mode ? ana a lxi h,2 ;Only 1/60 if in graphics mode rnz lhld hmi ret doabs: call sphmi ;Space increment call neghl ;Negative to start with jmp spdir ;Adjust backwards doacr: xra a sta dirflg ;Forward printing sta grhflg ;No graphics mode lhld hpos ;Get current offset xchg lhld lmar ;Get left margin call hlmde shld dlhpos ;Don't move yet though lda autolf ;In Auto line feed mode ? ana a jnz doalf ;Do line feed also ret dochar: mov l,c mvi h,0 call wheel ;Print the character in register C lda grhflg ana a lxi h,0 ;Don't move if in graphics mode jnz spdir lhld hmi jmp spdir clrall: call notabs ;Clear all hoct off array address call hlmde xchg jmp newdlh tofar: lhld hpos xchg lxi h,maxrgt call hlmde shld dlhpos ret doaff: lhld dfrmln ;Multiply forms length by 48 lxi d,48 call hltde lxi d,10 call hldde ;And divide it by 10 push h ;Save this result lhld vpos ;Get logical vertical position xchg lhld dlvpos dad d pop d push d ;Get copy of forms length call hldde ;HL mod DE xchg pop d xchg call hlmde xchg lhld dlvpos dad d shld dlvpos jmp paper group0: lda base adi grp mvi b,0 ***************************************************************** * Output the data in register B to the port in register A. * ***************************************************************** output: sta outnum ;Put port number in the instruction mov a,b ;Data to register A. out 0 ;Self modified to port number outnum equ $-1 ret ***************************************************************** * Input from the port in register A. * ************ byte character to match * * 2 bytes of address to execute * * terminated by a first byte of 0. * ***************************************************************** level0: db aesc dw doaesc ;Beginning of an escape sequence db aff dw doaff ;Form feed db aetx dw doaetx db aht dw doaht ;horizontal tab db alf dw doalf ;Line feed db asp dw doasp ;Space db abs dw doabs ;Back space db acr dw doacr ;Carriage return db 0 dw dochar ;Any other character level1: db '1' dw sethtab ;Set horizontal tab db '2' dw clrall ;Clear all horizontal tabs db '3' dw setgrp ;Graphics mode db '4' dw clrgrp ;Clear graphics mode db '5' dw clrdir ;Forward printing db '6' dw setdir ;Backward printing db '8' dw clrhtab ;Clear horizontal tab db '9' dw setlmar ;Set left margin db '0' dw func1 ;No operation level 1 db 'A' dw func1 db 'B' dw func1 db 'a' dw func1 db 'b' dw func1 db 'D' dw neghlf ;Negative half line feed drizontal tabs func2: func1: xra a ;Clear escape sequence flag sta escflg ret setgrp: mvi a,1 ;Set graphics mode on sta grhflg jmp func1 clrgrp: xra a ;Turn graphics mode off sta grhflg jmp func1 clrdir: xra a ;Forward print mode sta dirflg jmp func1 setdir: mvi a,a ;Set backward printing mode sta dirflg jmp func1 setlmar: lhld hpos ;Get current position xchg lhld dlhpos ;Get offset dad d shld lmar jmp func1 setvmi: mov l,c ;Set the motion index mvi h,0 dcx h shld vmi jmp func2 sethmi: mov l,c mvi h,0 dcx h shld hmi jmp func2 poshlf: call hlfvmi ;Half line feed vmi call adjvp jmp func1 neghlf: call hlfvmi ;Negative half line feed call neghl call adjvp jmp func1 hlfvmi: lhld vmi ;Get vmi for full line feed divid2: mov a,h ;High byte ora a ;Clear the carry rar mov h,a mov a,l rar mov l,a ret abshtab: mov e,c ;Absolute horizontal tab mvi d,0 dcx d ;Form 16 bit tab column call newdlh jmp***************************************************** input: sta innum ;Put port number in the instruction in 0 ;Self modified port number innum equ $-1 ret ***************************************************************** * Neghl forms the twos complement of HL. * ***************************************************************** neghl: mov a,h cma mov h,a mov a,l cma mov l,a inx h ret ***************************************************************** * Hlmde subtracts DE from HL and returns. * ***************************************************************** hlmde: xchg call neghl xchg dad d ret ***************************************************************** * Hlcde compares HL with DE. On return the Z flag is set if * * they are equal, the Carry flag is set if HL is less than DE. * ***************************************************************** hlcde: mov a,h cmp d rnz mov a,l cmp e ret *********************************************b 'U' dw poshlf ;Half line feed db alf dw neglf ;Negative line feed db aht dw settwo ;Two character escape sequence db avt dw settwo db ars dw settwo db aus dw settwo db 0 dw func1 level2: db aht dw abshtab ;Absolute horizontal tab db avt dw absvtab ;Absolute vertical tab db ars dw setvmi db aus dw sethmi db 0 dw func2 ***************************************************************** * The following routines execute escape sequences, etc. * ***************************************************************** settwo: doaesc: mov a,c ;Get the escape character sta escflg func0: ret doaetx: if int mvi a,0ffh ;Set the handshake flag sta etxflg endif ret doalf: call lfvmi ;Get line feed vmi adjvp: xchg lhld dlvpos ;Get vertical motion displacement dad d shld dlvpos ret lfvmi: lda grhflg ana a lxi h,1 ;Only 1/48 if in graphics mode rnz lhld vmi ;Get vertical motion index ret neglf: call lfvmi ;Get line feed vm func2 newdlh: lhld hmi call hltde ;Multiply by hmi xchg lhld hpos ;And subtract current horizontal position xchg call hlmde shld dlhpos ret absvtab: mov e,c ;Absolute vertical tab mvi d,0 dcx d lhld vmi call hltde ;Multiply by vmi xchg lhld vpos ;And subtract the current vertical position xchg call hlmde shld dlvpos jmp func2 sethtab: call tabcol ;Set horizontal tab mvi m,1 jmp func1 tabcol: lhld hpos ;Compute address of current character col xchg lhld dlhpos dad d ;Get logical position xchg lhld hmi ;And divide by hmi to get character column xchg call hldde lxi d,tabstp dad d ;Index into the tab stop array ret clrhtab: call tabcol ;Clear horizontal tab mvi m,0 jmp func1 doaht: call tabcol ;Get current tab column lxi d,tabstp+numtabs tablop: inx h ;Start with next position call hlcde jnc tofar ;Past last tab mov a,m ;Get value of current column ana a ;Test if it is set jz tablop lxi d,tabstp ;Subtra2******************** * Divide the number in HL by the number in DE. Return the * * quotient in HL and the remainder in DE. * ***************************************************************** hldde: mov a,d ;Start by negating DE and cma ; moving the left operand to BC mov b,a mov a,e cma mov c,a inx b mvi a,16 ;Repeat count in reg A lxi d,0 ;Initial remainder is zero div3: dcr a ;Test if done rm ;All done ? dad h ;Shift right operand to the left xchg push psw ;Save carry dad h ;Shift left operand to the left pop psw jnc div1 ;Does it fit ? inx h div1: push h dad b jnc div2 xchg inx h xthl pop h jmp div3 div2: pop h xchg jmp div3 ***************************************************************** * Multiply the contents of HL by the contents of DE. * ***************************************************************** hltde: mov c,l mov b,h lxi h,0 mult: mov a,b ora c rz mov a,b ora a rar mov b,a mov a,c rar movv h,a lda base adi daisy1 mov b,l call output lda base mov b,h call output mov a,h xra e mov b,a lda base call output mov b,h lda base jmp output end DD$*?yi2M2N*G*K"I:>Bi&:N!i*?i͂2O>2N2N2M>2M*G*I"Ki&+"Ai&+"?EE*A|g}oY2*?**G"IY*A**C"Ed6*G*I*?Rd6d#ҝ~ʇR2*G!0"I*80* *C*E*E"Eø:72x2|/g}/o#|}z/G{/O>=))# %#MD!xxGyOB)/*I|*G*I|`*G"I*G*I0~*G!0"I*G*I"G*I|!"I}ʪyO |g  *E|||g*C*E*80* "C!"E D͸@ :7 }/o|/g:7E:7D|G:7D:7$I$I"$!$DH"II@HI!I BB@I"HA$"I$I$I$I$$$IH I" $$$ $II $D!$$DDAD @@BI"$$ "AH c,a cc dadde xchg dad h xchg jmp mult dadde: dad d ret ***************************************************************** * The routines below actually interface to the printer, * * causing paper feed, carriage, and print wheel motion. * ***************************************************************** carrg: lhld dlhpos ;Check for any accumulated motion mov a,h ora l rz lhld hpos ;Check for to much motion xchg lhld dlhpos dad d mov a,h ana a jp lftok lhld hpos call neghl shld dlhpos lftok: lhld hpos xchg lhld dlhpos dad d lxi d,maxrgt call hlcde jc rgtok lhld hpos ;Otherwise move only to maxright xchg lxi h,maxrgt call hlmde shld dlhpos rgtok: lhld hpos ;Update the horizontal position xchg lhld dlhpos dad d shld hpos lhld dlhpos ;check if required motion is to the left mov a,h ana a mvi c,0 jp posh call neghl mvi c,data11 posh: xchg lxi h,0 shld dlhpos ;Reset the horizontal increment xchg mov a,l > !$'* 02Hn >>2)QK-QKBcF̊CLA4*P~^#"P>Q`GQ`G`x27`͜` *"8`QʿڿGGQʿڿo&7Q1`Q0. 2. `&":`͜`"<`Q10`02>`AG?K0:?0Ù@ :7>/:7:7:7*:!x"?*<!0"A!"C"E"G"I"K2M2N!R6#{ˆ͸DyO:O!yʾ:O!yʾ!-:O54###þ#~#fo< A  B f 1\23456ani 1 jz nohhlf ;No half spaces mov a,c ori data12 mov c,a nohhlf: call divid2 mov a,h ani data910 ora c mov h,a lxi d,crstrd jmp cmnd paper: lhld dlvpos ;Check for any paper motion mov a,h ora l rz ;No motion mov a,h ana a mvi c,0 jp posv call neghl mvi c,data11 posv: mov a,h ani data910 ora c mov h,a push h ;Save paper motion lhld vpos xchg lhld dlvpos ;Get logical position dad d push h ;Save for now lhld dfrmln ;Get default form length lxi d,48 call hltde ;Multiply by 48 lxi d,10 call hldde ;Divide by 10 pop d xchg call hldde ;Compute HL mod DE xchg shld vpos ;Save new vertical position lxi h,0 shld dlvpos ;Reset vertical motion pop h lxi d,pfstrd ;Paper feed strobe jmp cmnd wheel: push h call carrg ;Position the carriage first call paper pop h lxi d,pwstrd cmnd: call group0 lda base call input ana d jz cmnd mov a,l cma mov l,a mov a,h ani data910+data11+data12 cma mo8y90ABabDU Z < <<< ( Dy2ON*E"E:N!*ANEy:M*I"I:N!*?yi2M2N*G*K"I:>Bi&:N!i*?i͂2O>2N2N2M>2M*G*I"Ki&+"Ai&+"?EE*A|g}oY2*?**G"IY*A**C"Ed6*G*I*?Rd6d#ҝ~ʇR2*G!0"I*80* *C*E*E"Eø:72x2|/g}/o#|}z/G{/O>=))# %#MD!xxGyOB)/*I|*G*I|`*G"I*G*I0~*G!0"I*G*I"G*I|!"I}ʪyO |g  *E|||g*C*E*80* "C!"E D͸@ :7 }/o|/g:7E:7D|G:7D:7$I$I"$!$DH"II@HI!I BB@I"HA$"I$I$I$I$$$IH I" $$$ $II $D!$$DDAD @@BI"$$ "AH3* â Memory may be corrupted. Error reading %s. Next Load address: %h. Invalid CBIOS format in %s. Invalid load address %s. Can not open %s. Odd number of arguments. Usage: install [-string] file1.prl address1 [ file2.prl address2 ...] Install Revision %i.%i !9!>w#w!>w#w* ! * ! !<!~#fo##~#fo~-!~#fo##~w#~w!>w>#w!~#fo##~#fo~!!N#F!~w#~w!~#fo##N#F!~#fo##~w#~w~!~#fo6á>2!~#~>!<͢>!~w#~w!~w#~w!~#fo}o|g}^!<͢! ywx#w!>w#w!!  #!~#fo!!!~#fo)!~#fo N#Fzywx#w+#~Z!~#fo)!~#fo N#F!<͢Z!ywx#w!>w#w!!  #!~#fo)!~#fo N#F!N#FH!~w#~w!~w#~w!~#fo##!~#fo)##!~#fo N#Fpywx#w+~#!~#fo##!~#fo~#fo  !~#fo##~#fo}o|g}!~#fo)##!~#fo N#F!<͢!~w#!>w>#w!!}|!~w#~wͩ!N#F!~w#~w6!!N#F!~w#~w~OGyOxGywx#w!># !>#J!~#fo~ J!~w#~w!~w#~w~ !!}|!~w#~w!!~#fo#}|!!  #!!~#fo~!~#fo!~#fo~!~#fo!~!~w#~w!~w#~w !>#!~#fo~ ʦͩ!~#fo!~#fo~!~w#~w!~w#~w!~w#~wJͩ!N#F!~w#~w6q !!~#~!!}|!~w#~w!>w#w!!  #V!~#fo~™ͩͩ!~#fo!~#fo#}|!~w#~w!~w#~wÙͩͩ!~#fo!~#fo#}|!~w#~w!N#F!N#F1!~w#~w;!9!!~#~!N#F!} ~ !!N#F!| }|!!~#fo$ ~#~!>#v!~#›!~#fo& !~!N#F!~y!~#fo!yOx#G!~#fo$ !~#~!~#foMD!!  #!N#F!N#F!~#fo& !!yOx#G ͤ!!  #!>w# ~w!~w#~wu!!~#fo##N#F! Hywx#w!:w:#w!*3  Ҟ!~#fo~OGyOxGyvx !~#fo##N#F!h<! <͢ !:w:#w!!~#fo~#fo }|!*3  !N#F!N#F1!~w#~w!~w#~w!~w#~wC!N#F!O<!9!!~#fo~!~#fo!~#fo~!~#fo!~!>w#w!~#fo~!~#fo~0!~#fo>9!!~#fo~OG!~#fo))))  }|!~#foMD!~#fo~A!~#fo>Z!~#fo~OG! MD#!~#fo~OGyax!~#fo~A^!~#fo>Z^!~#fo~OG! MDk!~#fo~OG>f>!!~#fo~A!~#fo>Z!~#fo~OG! MDø!~#fo~OG!~#fo))))  }|!~w#~wÂCan not write in location %h. Insufficient memory to read %s. Invalid PRL file format in %s. !9!!!~#foN#Fͬytxʓ!N#F!;<! <͢!~OGyOxGy­x!N#F!'<! <͢!!~#~!!~#~!~#fo##~#fo!~w!>w>#wÛ!N#F!N#F!~#fo& !!yOx#G ͤ!!  #!!  #!>w#w!9!>w#w!|ywx#w!~#~!~#fo#~ !~#fo~ !~w#~wö!~w#~w!~Ʀw#~wÙ!~#fo~ !~#fo#~:y!~#fo!~#fo~aT!~#fo>zT!~#fo~OG! MDa!~#fo~OG! }!~w#~wÃ!~#fo6!!~#~!!~#fo#}|!!~#fo  !~#fo~ʫ!~#fo~.!~w#~w!!~#fo  ҧ!N#F!~w#~w6 !~#fo !~#fo 6~!~#fo! !~#fo" !~#fo# 6~ w!~#fo$ >w#w!N#F!~y—x/!~#fo#6 !N#F!~w#~w6 ç!N#F!~w#~w!~#fo~a!~#fo>z!~#fo~OG! MD!~#fo~OGyw!~w#~wç!~#foMD!9!!}|!!N#F!~w#~w~ ʖ!~%ʙ!~OG!~S!!N#F!~w#~w~ OG!ï!~#fo#~!-!~!~#fo!~#fo~#fo>o>g}| usOh)odi#fo !~#fo !~#fo##yx#B !N#F!<! <͢!>w#w!!~#fo!~#fo   !~#fo##~#fo!~#fo !~#fo}o|g}!~#fo##~#fo!~#fo ~OGyOxG!~#fo}o|gy xf !~#fo##~#fo!~#fo !<! <͢f !N#F!~#fo##N#F!~#foN#Fͬ!yD x#v !N#F!;<! <͢v !~w#~wM !>w#w!!  # !!~#fo!yOx#G>>  !N#F!yOx#Gywx#w!!N#F!}|!~#fo}o|g} !~w#~w !~#fo##~#fo!~#fo !~#fo }o|g} !~#fo##~#fo!~#fo !~#fo  }o|gMD!N#F!!~#foN#Fͬ!yª x# !N#F!;<! <͢!!N#F!~#fo##~#fo!~#fo !~#fo##N#FA !~w#~wÁ !~#fo##~#fo!~#fo !~#fo MD!9!!N#F!}!~#ʻ !>w>#w!~#ʾ !~#ʾ ! ~#fo~OG!yOx#Gy !~#fo!  ! ~w#~wa !#~~w+~w!~w#~w!~w#~wv !9! !N#F!~w#~wN#FSS!!N#F!~w#~wN#FS!!N#F!~w#~wN#FS!N#F!~w#~wN#FͯS!~OG!~S!~#fo~!~#fo~ ! !~!N#F!~w#~w~OG!~ò!!  #B!N#F!N#F!N#F!!N#F!N#F}|  ډ!~#foA  !~ß!~#fo0 !~*#~##~#®~®+++~#fo!9N#F#^#V!xxGyO)MD!9q#po!9~o3||g}o'/<3)"MD!9q#poG! 9~#fo!9~o/< !9~o3|g}oa'!9N#F#q#p!9N#F#^#V"""O>/G!9N#F#^#V#~#foͻz w#û!9TT|xTDxTDLL|7xLTD(D|/g}/o#x/Gy/Ox/Gy/O>=))k# w#`` 4NAME install -- integrate new device drivers into Cpm, Revision 1.3. SYNOPSIS install -string newbios address [ prlfile2 address2 ... ] DESCRIPTION Install integrates new device drivers into an existing Cpm 2 system. "Newbios" is a skeletal Cpm bios module in prl format (see the prl document) containing the new drivers. Install first loads newbios at the given address (usually the top of Cpm), then patches it into the existing bios by exchanging the addresses of the 17 jump vectors that begin each bios. If additional prlfiles are given, they are loaded at the requested addresses with no patching. Finally, install prints (top of newbios) + (newbios buffer size, if any) + 1 as the "new load address". Additional drivers can now be installed at this address. The flagged argument (-string) is copied to 80H and left there for examination by the newely installed "Newbios", or a NULL if no flagged argument is present. The bios modules provilternative, there is a combined driver package that requires only 5K of memory. To use it, configure a 43K Cpm (assuming 48K of memory, or use available memory - 5K), and type install M26+dj.prl AC00 djram.prl E400 FILES The provided files are: install.com Install program. install.doc This document. prl.doc Prl file format. M26.prl M26 drivers, require 3.5K, default to drives N,O, and P. dj.prl Dj drivers, require 3.25K, default to drives L and M. djram.prl Dj ramware. Load at controller address + 400 hex. M26+dj.prl Combined m26 and dj drivers, require 5K, default to drives L and M for the Disk Jockey, and N,O and P for the M26. M26+dj.asm Assembler source for M26.prl, dj.prl, and djram.prl. Requires the Digital Research assembler "mac", or "asm" plus hand editing of the macros. djram.asm Assembler source. BUGS Addresses must be specified in 4-digit hex (with no lead@ COPYRIGHT (C) 1978, DIGITAL RESEARCH ERROR: $, LOAD ADDRESS $DISK READ$INVERTED LOAD ADDRESS$DISK WRITE$LOAD ADDRESS $ERROR ADDRESS $BYTES READ:$INVALID HEX DIGIT$CHECK SUM ERROR $FIRST ADDRESS $LAST ADDRESS $BYTES READ $RECORDS WRITTEN $HEXCANNOT OPEN SOURCE$COMNO MORE DIRECTORY SPACE$CANNOT CLOSE FILE$*!9"!e !" !" \!""͊: ƒde"\\\͊: ²d\͝: )d;! q* &f  ! q> ! : A O: 0O! q: O: O! p+q* |O* }O! p+q*  f! p+q* DMB! p+q)R* DMB1B* DM+;! p+q* i2 ! p+q* i2 ! p+q* i2 i2 !" p+q*! f!$ p+q*# i!& p+q*% i!( p+q*' i2 !* p+q*) f!/ s+p+q+p+q:/ =2/ X*+ *- w*+ #"+ *- #"- 1* #" ͖r*   ~!" ! ͸×* " x20 º*   DM":0 Ad*   6!" Ç!" : !"6 "8 ": }2< !"4 "= ! ded here (see below) use this as an initial drive specification. i.e. -c specifies that the newely installed bios should respond to drives C on. The Cpm system must be "standard": its bios must begin with the jump table defined in the "Cpm 2.0 Alteration Guide", and it must store the address of this table at location 1 in memory. A "skeletal" bios module begins with the same jump table, but may leave some of the required functions unimplimemted. The corresponding jump vectors are left as jump selfs. EXAMPLES To install the m26 hard disk as drives C, D, and E in a 48K Cpm (assuming that you have memory above 48K), execute install -C M26.prl C000 Here, M26.prl is the "skeletal bios" (provided with install) containing the m26 drivers, and C000 (hex for 48K) is the top of Cpm. If you only have 48K of memory in your system, you will first have to move your Cpm downward to make room. At this writing, the m26 drivers requiing 0 and no trailing H). Install should also accept octal and X-notation. When the DJ drivers are first accessed, they locate the controller by searching memory for a certain pattern in the controller rom. The search is done carefully, but nevertheless might clobber somebody's memory-mapped io. install.doc 8/26/80 bdg  M26.prl M26 drivers, require 3.5K, default to drives N,O, and P. dj.prl Dj drivers, require 3.25K, default to drives L and M. djram.prl Dj ramware. Load at controller address + 400 hex. M26+dj.prl Combined m26 and dj drivers, require 5K, default to drives L and M for the Disk Jockey, and N,O and P for the M26. M26+dj.asm Assembler source for M26.prl, dj.prl, and djram.prl. Requires the Digital Research assembler "mac", or "asm" plus hand editing of the macros. djram.asm Assembler source. BUGS Addresses must be specified in 4-digit hex (with no lead6Y: !2 6=21 á:1 : r+s#r==_HL"4 " >6 ͪS* "6 =23 :1 =21 v=O* #" Y8  ͝҉* +"8 .!2 ʞR̀* "4 4 = ͝* #" çR*6 DM+R*8 DM+R*: DM+R*< M!? q=  ͝Kd*= ! ͸p!@ 6>!@ X*= }O!< *@ & w*= #"= !@ 4)!< 4\mad* }O!< :? wlR*4 DM+{R* DM+R 4 ͝*4 }¿= 4 ͝< N*4 #"4  å;*4 DM+: Y2A 0O> :A 0:A AO>&R̀:A A H.2B !2 w:B !D s+q*C &͍:D _og_{ozg^#V) _{ozgi`N#Fogo&og_{_z#Wre approximately 3.5K bytes, (see FILES below), so you should construct a 44K Cpm, and type install -C M26.prl B000 (B000 is 44K in hex.) If you don't know how to move your Cpm downward see your system manual. The required program is usually called "movcpm". To install the Disk Jockey as drives L and M in a 44K Cpm (with at least 48K of memory), type install dj.prl B000 djram.prl E400 Here, dj.prl contains the Disk Jockey 2D drivers, B000 is the top of the 44K Cpm (the dj drivers require 3.25K), djram.prl is updated controller firmware to be loaded into the controller ram, and E400 is the address of the controller ram. (If you have a non-standard controller, use the controller address + 400 hex.) To install both the m26 and the Disk Jockey, you could first install one and then install the other on top of it (at the printed "new load address"). This would require 6.75K of memory above Cpm. As a better a5*0F!9N#F#^#V#~#fo"Xkb"Xi`"XOGposLoad size is %h hex bytes longOutput file is %p Addresses don't matchSizes don't matchUnexpected last line in %pCan't make room for headerCan't create '%p'prlhx1hx1hx0Bad option -%acprlMAKEPRL Version %i.%i gV!9!>w#w!>w#w!>w#w! >w#w!>w#w!>w#w!>w#w!~w#~w!~w#~w!N#F!N#F!!~#±@ !~#fo~#fo~-!!~#fo~#~!~w#~w+~#fo~OG!2[U!~#~ʽ!~#~ʽ@ ý!!!!~w#~w+~#foN#F(!~w#~w!~w#~w!~w#~wñ!!$!~w#~w+~#foN#F !>w#wF!~#fo~OG!; F!!!D!~#foN#F !~#~!!!4!~#foN#F 3!!!4!~#fo##N#F !~A#~ʄ!!~#fo~#fo~!~#fo~!~#fo~.!~#fo6\!"!Dywx#w! !4ywx#w!!!!$$ywx#w+~#~!$!; !!$!~#foN#Ft line in hex file '%p'File '%p' not in hex formatCan't read '%p'gV!9!!N#F9 yg x{ !N#F!4 ; !!!!!^ ywx#w+~¬ #~ !N#F! ; !~ #~ !N#F! ; !!  # !N#F! ; !!'X##N#F+++N#F!N#F̈́)xB!N#F! ; nVBad line in hex filegV!9!!N#F9 y€x‰nV!! N#F!N#F!N#F!^ ywx#w+~#~!H; !~#~nVnVCan't open '%p'gV!!!!N#F͐ywx#w+~.#~E!N#F!; nV!~#foMDnVCan't write out bitmapSeek error in wrheadCan't write headerCan't rewind filegV!9!>w#w!~#~!!~#fo 6!~w#~wö!!}|!N#F!~w#~w6!N#F!~w#~w!~#fo!yOx#GyOxGyw!N#F!~w#~w!~#fo!yOx#G!8Q}o|g}!N#F!~w#~w6!N#F!~w#~w! ~#fo}o|g}!N#F!~w#~w! N#F!8Q}o|g}!!d`!yOx#GP can't write can't read O!9!t!}|!"``!*``*``#"``~!>#!>#*``> ,*``~,!>w#w!v/ywx#w!"b`!t:b`:c`#*b`~<!=!!*b` ͐y~!!!*b` !#!! 9!F~!>#CÔ!~w#~w*``#"``r!>#*``> *``~!tN#F!t~w#~w*``~A*``>Z*``~OG! MDä*``~OGyw!~w#~w*``#"``C!tN#F!t~w#~w6e!v!N#FP*b`#"b`ò*b`~>V!=!!*b` $y(x~!!*b` !!! 9!F~!N#F!~w#~w)!v :b`w:c`#w*b`~*b`#"b`~gV!N#F!~#ʫî!N#F͛9nVgV!N#F!\c,nVgV!!N#F!\!#.nVO!"d`*d`~#8*d`N#FL)*d`N#F!N#FzE*d`##"d`PO!~#fo"d`!~#fo"``!~#fo"b`*d`~nq*d`~N¢*d`#"d`*``*b`N#F*b`~w#~w~#fo}|*d`MDP*``>w#w*d`~0*d`>9*``*d`~OG*``~#foMD)) )  }|*d`#"d`ìO!9!~#fo"d Ä!~w#~w\!D!!"N#FD !4!! N#FD !>w#w!~#~ !!~#fo 6!~w#~wP!!!N#FzEy x«!; !!!!"N#F]yx!T!!! N#F]yx!4!; ! ~w#~w!~w#~w!#X##N#F+++N#F!N#Fr! N#F!!N#F!N#F!N#F!N#Fͣ! 9!"N#F=! N#F=!N#F=!$!]!~#fo!yOx#G!>!!FnV!!  #!; !~#fo!yOx#Gyx(!p; !>w#w!!  #!!~#fo!~#fo }o|g}|!>w>#w!N#F!~w#~wᗕ>!!~#fo||g}o}|x!!~#fo!~#fo !8Q}|!~#fo)!T ~#fo!~#fo)! yOx#Gyx3!!~#fo ! V!!~#fo !~#fo}/o|/g ! !  #y! !~#~!!~#fo!~#fo  !!~#fo!~#fo }|!X##N#F+++N#F!N#F!~#fo)! N#F!~#fo!~#fo !~#fo!yOx#G! ||} !!+X##N#F+++N#F!N#F̈́)xT!; !!!N#FzEytx!~; !!##N#F+++N#F!N#F̈́)x!i; !N#F! N#F!N#FzEyx!R; nVCan't read in seg %iCan't write out seg %igV!9!\~#_!>w#w!~#~!/X!~#fo 6!~w#~w0!!~#fo}o|g!QP}|!!~#fo}o|g}|!!/\ ° #=*/\! ##N#F+++N#F!N#FZyxr*/\!; r!>w#w!~ր#~0!~#fo)1\ >w#w!~w#~w>2\2\_!/X!~#fo !~!:\:\#!!~#fo"\!!~#fo)1\ ~#!N#F! ##N#F+++N#F!N#F'y¶x!N#F!; !~#fo"/\*/\)1\ >w#w=!>w#w!~#~!/X!~#fo 6!~w#~wnVgV!!##N#F+++N#F! N#F!N#F͍! 9nVgV!!##N#F+++N#F! N#F!N#F͍! 9nVgV!9!!N#F!͖Qx2P`2Q`x2S`y2R`!P`!Q~#~#~#~!!##N#F+++N#F!N#F̈́)x`*d`"b`*b`~/*b`~%/*b`#"b`*b` "d`!b`:d`:e`#h*b`!d`yOx#G*d`!N#F!~#fomV*b`*b`#"b`~|P!>w#w!6 *b`~-½!>w#w!*b`#"b`*b`~*b`#"b`*b`~+!*b`#"b`*b`~*b`#"b`! !*b`;i`"b`!>w#w*b`~.)! !*b` ;i`"b`*b`~aM*b`~hM*b`~oM*b`~ux!*b`*b`#"b`~!~h>2``2a`õ!6a!~o˜>2``2a`õ!~u¯> 2``2a`õ!"``*b`~x!>w#wU*b`~b¡!! N#F! ~w#~w~#~!! N#F! ~w#~w~#fo}|!~#U!!!  #H!N#FO!N#Fywx#w!~#ʟ#!!  ##!!!N#F!~#fomV!~w#~w_*b`~p# !! ~#fo~#~!! N#F! ~w#~wN#FL)ywx#w!~#U!!!  # !N#F !N#Fywx#wU*b`~l› !~a!!! ~#fo~#~#~#~!>w#w!~w#~w+#~n!!!~#fo !##~!!$T] *b`~f¢!!!}|!!N#F!!yOx#G! ~#fo >+F+N= !&!9ywx#w!  9!~w#~w3gV!~#fo~ʃ !~#fo~. ! ~@ #~ !~#fo~ !N#F!~w#~w!N#F!~w#~w~C !N#F!~w#~w6.!~#fo~, !N#F!~w#~w!N#F!~w#~w~Û !N#F!~w#~w!N#F!~w#~w~ !~#fo6! ~& #~ʃ nV!~#fo6nVgV!!N#F!~w#~w!N#F80yʎ !~#fo ~ ” !~#fo 6nVnV!~#fo ~ < !~w#~w< Error: gV! ! N#F!N#F!N#F!N#F!!FnVUsage: makeprl [-s hex-no] [-o output] hex-file1 [hex-file2]gV! !!FnVgV!~#fo~:y nV!~#fo ~0 !~#fo ~0ʣ nV!!N#F!!~#fo#(y x nV!!N#F!!~#fo###(y x nV!>w#w!!~#fo  #~ !!~#fo)! ~#fo !!~#fo) !~#fo (yu xʣ nV!~#fo#~0³ !~#fo##~0³ nV!~w#~w nVCan't rewind '%p'file '%p' not at correct start addressUnexpected lasnV! >w#w+~#1!!/X!N#FzEnV!!/X!N#F80nVCan't write out memoryFlush can't seekgV!9!*/\!͖Qx2P`2Q`x2S`y2R`!P`!Q~#~#~#~*\#"\!!##N#F+++N#F!N#F̈́)x!a; *\}o|g!/X!N#FzEyx"!J; nVO!~#fo"d`!~#fo"``!~#fo"b`!>w#w!:d`w:e`#w!>w#w!``>#ґ*d`> *d`~!``>#*d`~-n!>w#w*d`#"d`:``2``:a`2a`:``2``:a`2a`*d`#"d`s! ~#~‘:``:a`ڑ*d`~0‘*d` ~A;*d` >Z;*d` ~OG! MDG*d` ~OGyxPx‘*d`##"d`:``2``:a`2a`Ñ*d`~+*d`#"d`:``2``:a`2a`!``>#*d`~0C*d`>9C!*d`~OG! }|X*b`!~#!N#F>O>G!N#Fywx#w!``>#*d`~A%*d`>Z%*d`~OG! MD-*d`~OGyl6x*d`#"d`*d`~a*d`>zÝ!!N#F! N#F͖Q!~#fo }|:``2``:a`2a`*d`#"d`Ñ*d`~A*d`>Z!*d`~A*d`>Z*d`~OG! MD*d`~OG! }|!!   #X*6! ~#fo }|U!!}|!*``! ~#fo##N#F+++N#F!ͮ*ywx#w! ! ~#fo####}|U!!}|!>w#w! ! ~#fo####}|U*b`~d#"!!}|!!>>#!!!N#F!! ~#fo >+F+N=!!>$!9ywx#w! ! ~#fo }|U*b`~cG"*b`~sG"*b`~iG"!~ʉ"!~a¤"!! N#F! ~w#~w}|*b`~c"!>w#wq#!:b`w:c`#w!>w#wU!! N#F! ~w#~w~#~*b`~c@#!``>#@#!~w#~w@#!!~#fo~#~!!N#F!8Q}!!~!!}|!>w#wq#!!}|!*``!N#F!3ywx#w*b`~cU*b`~sU*b`~iU:b`2b`:c`2c`U!>##!N#F!N#F!N#F!~#fomV!~#"!!  #"!!!N#F!~#fomV!~w#~w#gV!N#F!!N#F͛9nVO!9!~#fo"d`!!F`;K$!!P`~#~s$!P`NO*d`*d`#"d`6-!!~#fo!~#fo }|!>>#$!>w#w!!~#fo#! >+F+N=$!94! 9ywx N#F*d` *d`N#FzE*d` y.-x#N-! !G,!zE!Fg-*d` >w#w*d` :``w:`` t-:a`‹-*d` ~ˆ-#~,*``MDP*d` N#F*d` *d`N#FzE*d` y-x#-! !:,!zE!FP*d` >w#w*``MDPwrite error write error bad putl call O!~#fo"d`!~#fo"``!d`~#c.!!.!zE!FP!~#fo"b`!b`>#/!*d` *d` ~#fo }|!b`>#/*d` ~#~/!N#F!~w#~w*``*``#"``~:b`2b`:c`2c`*d` ~w#~wÛ.*d` ~/#~/*d` ~#/*d` ~#fo*d` ~ /*d` N#F*d` *d`N#FzE*d` yo/x#/! !-!zE!F/!b`>#n.!*d` *d`N#FzEy½/x/! !.!zE!Fn.*d` >w#wn.!~#foMDP*d` >w#w/10122+222 223O!N#FʹFi`"b`!b`~#[0P*b` ~#fo"d`!~#fo"``!>#0*b` ~0*b` ~OG! 0[U*``!yOx#GP!*b`VG!0[U!d`~#0P*d`! ~P1*d`* 6}*d`* ! ! !c`*``~g9:b`:c`g9*b`*b`#"b`*d` *``~aR9*``>zR9*``~OG! MDZ9*``~OGyw*``#"``9:b`:c`9*b`*b`#"b`*d` 6 g9*``~OGPO!9!~#fo"d`:^9!! y2^!>w#w!!"_  #9!~#fo))_ ~:!!"_  #:P!~w#~w9!!~#fo))_ }|!~#fo6!!~#X:!~#fo~w!~#fo##>w#w!:d`w:e`#w>2``2a`*d`~::*d`~::``:a`;*``*``#"``! *d`~a:*d`>z:*d`~OG! MD:*d`~OGyw;!*`` 6*d`~:;!~#fo"d`!~#fo#:^wT;*d`#"d`À:!~#fo#!̈́7yw~M;!N#F=P*d`#"d`!~#fo#~;!~#fo#~OGyy;x;!~Š;#~;!!͑?i`"b`!~#fo##:b`w:c`#w!*b`|K*b`( >w>#w!~#fo#~;!~#foMDP!~#foMDP*d`*b`8y2``2a`!:``:a`#%!:``:a`#҈%*d`*d`#"d`!*`` ~*``#"``!~w#~w6%!>#&*d`*d`#"d`6.>2b`2c`!:b`:c`#E&*``*b` !yx#E&*d`*d`#"d`!*`` ~*``#"``*b`#"b`í%*d`*d`#"d`6e!#~m&*d`*d`#"d`6-!!~#fo>o>g}|{&!:b`:c`#&*d`*d`#"d`60*b`#"b`E&*d`*d`#"d`6+*d`*d`#"d`!N#F! QP0 }*d`*d`#"d`!N#F! ͘P0 }*d`!yOx#GPO!9!~#fo"d`!~#fo"b`!!F`;K8'*b`*b`#"b`6-!!P`~#~$'!P`NO!"``!!! >+F+N=R'*``94! 9ywx#w!!~#fo*d` }|!>>#'!>w#w!!N#F!!<~w#~w!!  #(!~#fo!yOx#G*`` "``!!~#~!>#;(*b`*b`#"b`60!d`>#(*b`*b`#"b`6.×(!>#(*b`*b`#"b`*``!yOxGyxҁ(*``*``#"``~OGÄ(0yw!~w#~w;(!#~(!d`>#(*b`*b`#"b`60!~w#~w:d`2d`:e`2e`×(!d`>#9)*b`*b`#"b`*``!yO *d`! *d`+ ~OGyw*d`" *d`, }|*d`" ~#fo*d`+ ~OG 6 *``*d`" N#F*d`" ~w#~w~*d`! 5*b`~OGyOxGy1*``#"``!~w#~wt0*``!! yw{1P*``~ t0*``~t0*``~ʟ0*``~ 1*``!yOx#GP*``#"``!~w#~wt0P*``!yOx#GP!>#t0*d`! ~t0*``*d`" ~#fo~*b`~OGyOxGy¾2*``#"``!~w#~w*d`! 5*d`" ~w#~w*d`$ >2P`2Q`>2S`>2R`!P`Q+2*``~OG!$0[U*``!yOx#GP222*b` ~OGy2x3!F*``#"``!~w#~w2O!~#fo"d`*d`"b`!#~s3!>#s3!!~#fo>o>g}|*b`*b`#"b`6-!~#fo}o|g"``!~#ž3!> w#w3!#~3!!~#fo>o>g}|!:``:a`#3!N#F*``!N#FP*b`3*b` "b`*b`*``!N#FP0 }*b`>9&4*b`~'w*b`!d`yOx#GPO!9!~#fo"d`>2``2a`!#~4!!P`~#~s4!P`NO!!`;K5*N` "b`!b`>#5!*b`)))` ;K6!!P`~#~4!P`*b`)))` @LO*``!*b`~#fo"d`!#~=!!  #=*d`!~#fo ~5=!~#fo "``:a`=*d`*`` ~9=*d`*`` 60:``2``:a`2a`J=P:a`=*d`61!~#fo"``!``>#=*d`*`` 60:``2``:a`2a`Ý=*d`*`` 4Æ=PO!N#FʹFi`"d`!d`~#=P*d` ~#ʌ>*d`~OGyOxGyŒ>!*d`RI*d`~OGy OxGyj>*d` ~#fo ~w*d` N#F! *d` !*d` N#FAywx#w*d`6!~#foMDPO!~#fo"d`!~#fo"``*d`*`` "b`*b`*d`~#fo!``yOx#Gywx#w*b` *d` ~#~*d`*`` }|*b`MDPO!~#fo"d`*d` ~#fo"``*d`*d`~#fo ####!``yK?x#{?*d`*``~#fo####  *d` *`` ~#~Pout of heap space O!N#F!N#F?i`"d`!d`~#ʿ?*d`MDP!!~?!zE!FPO!~#fo"d`:d`:e`?@*d`MDi`#}o|g##"d`!_"``*``~#fo"b`!b`~#k@*b`~#fo####!d`yx#ڍ@*b`!d`  #Қ@*``*b` ~#~ñ@:_x@:_@:_2_:_2_@*b` "``@*``*d`*b`͞>ywx#w*b` !~#~*b` MDP!>w#w!d`:_:_#$A!!:_w:_#w+N#FxGyx )*``*``#"``~OG#)0yw:d`2d`:e`2e`(*b`!yOx#GPO!~#fo"d`*d`"``*``~r)*``#"```)*``!d`yOx#GPO!N#FʹFi`"b`!b`~#ʮ)*b` ~)P*b` ~#fo"``! ~#)*``$ !~#~#~#~á*! ~)#~**``$ !Qá*>2d`2e`!*d`*b`fJxT*!*`` ~*d`}ƀo|g"d`**``$ *d`!~#fo MDx2P`2Q`x2S`y2R`!P`!S!Q~#~#~#~!~#foMDPO!~#fo"d`*d`"``!#~+! >#+!!P`~#~#~#~!P`͕T~#~#~#~*``*``#"``6-! ~#4+! > w#wY+! #~Y+! ! ~#fo>o>g}|!! #~~+~ !#~+!!R+! N#F!P`~#~#~#~!P`!ͨS##N#F+++N#F*``ͮ**`` "``*``!P`~#~#~#~!P`!S>02Z`2[`2Y`2X`!X`Q##~*``>9',*``~'w*``!d`yOx#GPwrite error write error bad putc call O!~#fo"d`!~#fo"``!d`~#Ÿ,!!T,!zE!F:a`,*d` ~#~,*d` N#F*d` ~w#~w*d` :``wg-*d` >#-*``MDP*d` Q "``6>2b`2c`!:b`:c`#6!~#6!!P`~#~H5!P`!`ͦMO!!ͭO!!P`~#~5!P`!X`!N#F UNO*d`*d`#"d`!~#fo0 }*b`#"b`5!!`;K!6!!P`~#~5!P`!`@LO*``#"``5:b`2b`:c`2c`à4!P`~#~/6!P`!`ͦM!`;K5*N` "b`!b`>#5!*b`)))` P`~#~|6!P`!ͦMO!`;K6!!O!*b` Q:``2``:a`2a`:b`2b`:c`2c`W6!:b`:c`#7*d`*d`#"d`60*b`#"b`6*``MDPPONMLKJIHGFEDCBACONRDRPUNLSTO>2d`2e`!"_:d`:e`#k7*d`=*d`#"d`J7:^OG! *^MDPO!~#fo"d`!^ywx#w!~#fo~#7*d`"b`!~#fo~#fo"``*b`*`` 7*``~7*b`#"b`*``#"``7P!~w#~wß7*b`*`` 7!~#fo##~OGPO!~#fo"d`!~#fo"``>2b`2c`*``~.ʮ8*``~ʮ8:b`:c`8*b`*b`#"b`*d` *``~a8*``>z8*``~OG! MDá8*``~OGyw*``#"``@8:b`:c`8*b`*b`#"b`*d` 6 î8*``~.8*``#"``8*``~8P>2b`275Cywx#w+~#$A:_2_:_2_@!~#OA!!:d`w:e`#w+N#F5Cywx#w!~#_AP!~#fo!~#fo }|!_~#ŽA!~#fo"_!~#fo!~#fo :_:_A!~#fo!~#fo "_!!~#fo##A@bad free call O!~#fo "d`!~#>B!_:d`:e`#$B!_:d`:e`#KB!!A!zE!F!~#foMDP!_~#kB*d` >w#w*d`"_>B!_:d`:e`#қB*d` :_w:_#w*d`"_*d`?>B*_"``*`` ~#fo"b`!b`~#B!d`:b`:c`#B*b`"``áB!b`~# C*d` :b`w:c`#w*`` :d`w:e`#w*d`?*``?>B*d` >w#w*`` :d`w:e`#w*``?>BgV!:_w:_#w*_!~#fo "_!:_:_xC!f`:_:_҉C!~#fo"_nV!~#foMDnVDD^DDO!~#fo"d`!~#fo"b`!>#D! yOxGyD! yCxD!FD*b`!yOx#GP*d` ~1D*d` ~OG!C[U*d` ~#fo"``!*d`VGyUDx¾DP*b`~OG! !~w#~w*b`#"b`ÿC*b`~OG! pD*b`~OG! pD!~#foMDP!>#?E*``! ~?E*``" N#F*``" ~w#~w*b`*b`#"b`#~w M!MD! +&MMGM!MD!  #8M!4! +~w NM!5L!N#F!rV!~ʈM!~#ʈM~w! N#F !#~—MW!9!9! N#F!6 Mƀ4 !]WyN!q#p!N#F!]Wy N! N#F &%NN!~O#~Gyր+wx#w! #w )N>8!w! ~#+~w ?N!~hN!MD!  #^N!#~w oN!56N!N#F!rV!~ʨN!~#ʨN~w! N#F !#~·NW!9~#fo~#N~ƀw!9!9!N#F ! #wN!~ƀw! N#F!̀UW!9N#F!9~#fo~#~4OWMD!9!9!N#F!]WyʨOy֨OxGO!~#+~w|OyrOèOyʨO!#~w›O ÎO! @ON#F!~#~W@ON#F!~+~ +~+~ W@OMDóO!9*d`*b`*``i`!"``"b`"d`!9~w#~w#~w#~w+MD!9 _ #P{ !94P! 9~iP+w>#w! 9N#Fx}PO>GPҍPO>G! 9q#pW! 9~P+w>#w! 9N#FxPO>GPPO>G! 9q#pW! 9N#FP! 9q#pW! 9~*``$ >2P`2Q`>2S`>2R`!P`Q!~w#~w*``! 5þD*d`~OGyOxGymE*``! ~mE*``" ~#fo6*d`~wÿC O!N#FʹFi`"b`!b`~#EP*b`~OGyOxGyE!N#F!N#F*b`ͦCP!~#fo"d`!>#F*d`"``!>#-F*d`~ -F*d`#"d`!~w#~wE*d`!yOx#GP*d`!``yOx#G*``*b`ͦC*d`!``yOx#G}cF|lFP!>#E!!wE*b`ͦCy”FxʝFP*d`#"d`!~w#~wEO!~#fo"d`:e`F!"_:d`:e`#F*d`))_ ~FP*d`))_ MDPgV!_~#%G!.G:_G:_%G*_mVi`"_F* _mV%GO*_"d`!~#fo"_*d`MDP8I2IIIO!~#fo"d`*d` ~#fo"``!*``$ P`~#~#~#~!P`!$T##~#~*``$ ##N#Fi`}o|g"b`*``! !!b`yOx#Gyw*``" *``* *b` }|!~#H!*``( H #HP!*d`RIxPH!N#F!N#F*d`fJxVHP*`` ~OG*`` ~OGyOxG}|HÈHi`"b`!*``( £H #®H*b`MDP*``( !~#~!b`~#H!*``* |KP*d` ~OG! *``* !N#FP! 9q#pW!9~$Q/#>+++>#~#~#~ #~{S>#># >#͹R!9MD!9~#foR! 9MD!9~#foR2R!9N#F!9SR͹R!9MD!9~#foR! 9MD!9~#foR2R!9N#F!9SR͹R! 9MD!9~#fo#R!9MD!9~#fo#R2R!9N#Fkb9SR͹RíS!9~S/<4TWO!9~#fo##~w#~w+++~w#~w TW!9~4T/#w>+++w>#wMD!9!9!N#F!>w#w#w##w#w!!rV! N#F !#~975717-7+7)7'7%7#7!77777 7 7 7 7 7 7f`.G $_ @ BCG@M [u+p *``! i`"b`!! *b`MD!JG[UP!*``* |KPPO!~#fo"d`*d` ~#fo"``*d`~OGyOxGyʮI!*``( N#F*d`fJy¥IxIP!~#`J*d`~OGyOxGy`J*d` ~OG! *``! *d`~w`J*d` ~OG! *``* ! *``! i`"b`!! !b`~#OJP*d`~w*d`~wîIPO!~#fo"d`*d` ~#fo"b`!N#F!8Q"``*b` ~OG:``¬J:a`J*d`~OGy OxGy[K*d` ~OG! *d`~OGyOxGyK*b`! xKP*d`~w*b` :``w*b`! xTK!~#TK*b`! xTK*d`~wP*d`~ w*b` !~#fo}o|g}PO!~#fo"d`!~#fo"``:``2``:a`2a`:a`K*d`6*d`#"d`ÕKP! 9~#foN#FxKO>G!9~#fo^#VzK_>WxƀGzƀWyoxL L>5L>5L! 9N#F!9~#fo# ##:L +:L LчWLL!9!9!6!N#F!]WyŠL! N#F > àM!~L!>#w›L!4!q#p! N#F L!4 !]WyʠMy!Ox#Gyƀ+wx#w !#w L!69!TWͶTq#px#w#wTͶTq#p#w#wTͶT w #w #w #wTͶT w #w #w #wT~#gU#~#foy#{Ux#|U+++~#fo##[U!9!9!N#F!]WyaV!q#p! N#F!]WyU!N#FKV!yOx#GUyV+~w#~w!UO>G! ~#+~wU Vw yVU!MD!  #w)V!N#F!rV!MD ! ~#fo+ #wXVW!9!9N#F! ~Vi`+ >#w‹VæV+¦VšV[W! ~V# +~w³V!9~w#~wæV! ~Vi`+ #~wV!9~w#~wV Wi`7#~wVæV!9~"Wi`+#wW[W5Wi`>#w+W>w! !9z~w+~ w++~ wOW!!9N#F!9^#V! #~#~ yW! ~#~WҚW+©W WW>w+~w}Wi`>#w¼WJ!9N#F###q#p+++q!9N#F#q#pcopyright (c) 1979 by Whitesmiths, Ltd.8 NAME makeprl - make a prl file from absolute hex files SYNOPSIS makeprl [-s hex number] [-o output file] hex1 hex2 DESCRIPTION Makeprl is used to create prl files suitable for loading by the install program (see install.doc). The format for prl files can be found in prl.doc. The -s option is used for entering the reserved buffer space. (The reserved buffer space is entered as a 16 bit number in addresses 4 and 5 of the header, see prl.doc). The -o option is the output file specifier. If no output file is specified the name from hex1 is taken with '.prl' type extension added. If the output file does not have a type exentension, the default '.prl' is added. The next two arguments must be specified. The first argument is the hex file input with an orgin at 0. The second is the second hex file input with an orgin at 100 hex. If the hex files do not , in Ok Break!9~#…  w N#F#i`zʙ D w   *|<ʺ :  MD=96543>7@?2C: * "   have a type extension, '.hx0' and '.hx1' are added respectively. EXAMPLES To create a prl file of the hard disk i/o drivers you would first have to begin with the assembly language source. Assemble it at orgin 0 and rename the hex output (with a .'hx0' extenson say). Then you would have to assemble it again with an orgin of 100 hex (Consult your assembler manual on how to do this. With some assemblers you would have to reedit the source file and change the 'org' statement). After you have assembled the source with an orgin of 100 hex you could rename it with a '.hx1' extension. Now you are ready to use the makeprl program. This is an example of a typical way to do the above described procedure. The example assumes that the source is configured correctly. mac hd+dj ren hd+dj.hx0=hd+dj.hex mac hd+dj $+r ren hd+dj~]y)):DE9WAzD5D9E TCD E"D   < DDDD=9"D"yLLMPM@$$YXTZZSRbSYdXY|T{TSYjIII{(*f(6 88&W7899N9K HFIII"MIFFy))*l*QQQUDV\VgQjQmQ;LM$Xq"9BLdhiNBTSUTϫLOSONԚLEAҒINSNDBV+V,V-O HRAL̶OMMOθHAIιATI͆EFSTҭEFINԮEFSNǯEFDB̰EƘELETŪNāLSŢRASŦDIԧRROҨRRX O/QO҂IELILERIOTωO TωOSUEEXNPUԅƋNSTNNMNKEYILEԈINűOASEPRINԞLISԟPOISԓO O0EEFTO1ERGOKI2KS3KD4IDEXԃUL̖AMEהOUԝΕPEοCTPTIOκUOKřRINԑOEEEAćUΊESTORŌETURΎE͏ESUMũSEIGHTNENUͬESEANDOMIZŻTOАWAХAVPCTEGQI TRTRINGPACEYSTEͽROΣROFƤABHEA SINSAARPTIDTȡAIԗHILŴENĵRITŷO۾yy||PF<2(z{*y):*)%,,c-G.r)%%'n')0+$+P+2)NEXT without FORSyntax errorRETURN without GOSUBOut of DATAIllegal funct *" 2 2 |< " % * C{K2* " * |'_#x * ~?’ !s DGDQBʷY|nA2SSDB!h :=!": * T1>* > @IK 2 ê 2 *  D " : ?IK 2<= Z~ ̽(;" ҌSW]2" ^8$ܭ"ʪ: * " * B" t##s#r#F w# y !6"*" kC*"* " *bk~####~  32#s#rODO *DM~#+##~#foD`i~#fo??2 2 ;F~"j @s: ~@?>,ju2EڀG#uO#u #u# ʋSʦTuO>ôuU#uB>,u!AO ^#V#uOʓ# y(u.!>ғ+>͈2 ͈H!+^>2 ̆͆>͈l~.ʐ: 0 : ~@ʼ.@>͈Z}͈|͈H~.: *' |>}e. Ұõ͈!' !# ~͈.hx1=hd+dj.hex makeprl -o hd+dj.prl hd+dj.hx0 hd+dj.hx1 In the makeprl line it would not be required to specify the output or add type extensions because the program uses defaults. The makeprl line could be written. makeprl hd+dj hd+dj This form does the same as the first but is quicker to type. The specification for the -s option must be a four digit hex number. FILES makeprl.com Makeprl program makeprl.doc This document. makeprl.doc 3/17/81 ldk  of a typical way to do the above described procedure. The example assumes that the source is configured correctly. mac hd+dj ren hd+dj.hx0=hd+dj.hex mac hd+dj $+r ren hd+djion callOverflowOut of memoryUndefined line numberSubscript out of rangeDuplicate DefinitionDivision by zeroIllegal directType mismatchOut of string spaceString too longString formula too complexCan't continueUndefined user functionNo RESUMERESUME without errorUnprintable errorMissing operandLine buffer overflow??FOR Without NEXT??WHILE without WENDWEND without WHILEGraphics statement not implementedFIELD overflowInternal errorBad file numberFile not foundBad file modeFile already open?Disk I/O errorFile already exists??Disk fullInput past endBad record numberBad file name?Direct statement in fileToo many filesJJJJJJJJJJpP8`1` :9#=Hiʽ&@2vH> 4> ͈̈́î#͈:RJX>2 2 UH~|s@~#͈^!@}O|G!E>: y +=2 u͈#u2EҞ:Һ0Ҟ.ʞH~   > : <=`+~   #>d2 ͨ9D" : ! Ϳ(" !9w ? +V+^##* D " B* *D  {y)~i ͑(Þ)ͳ(QZ~>Ÿ)ͳ(D(OG+2 $2* "* 3E3ĐB" !9" ~: #~#ʨ #^#V":! >[@T1>]@2ցALO! N#F#~: 2Ұ ګP: [* 3#2 Ґq…~#" &o" >2 !~##" +fv<2  G(" ! 20?<=:  * ###^#V,U: 2 * "' * ") U! (U1E AOG2'21EAG2x3Z: * #*D > 2 /$`i s 7>O2y*D,:**' ͋ DO} ;)c>2,  N#fi-++<~(|Z y)}/o|/g"' 0: Ҍ7y)z ,{ʧ+F¯{o|Pº{o|<{o|2{/o|/}//o|//}o|g,:: 2 ͨ9: " " B!9(: * ~)D,* D,Ú2q (2 !9(!9.,: G:q OdJ}!s Oc* 2* D)>" : OBO/2 Oí9~ #~ #ÂJ͎ 2 x x +20 D,͋ 1 Q 2͋ 2^ 2͋ 2^ 2^ /<2y)z͋ 22 2 D,Ë 2o J+2{>2W]!"N#F#xʪ *|̅BN#F#Dک " T1~ > @!! QBç ~B# # xD(!M(D(y!) y)#x+y+z+{z|N(O(}O(!0 (7 D(!M(D(O!) y#)+e)H)M(*'  )(!C6(%,)Û)~%:) 2) :* A*:* ¼)))|/g}/o)! :* )A*"' >2 )aj)* ͳ(5*x(!& F(&*' 5*|UX( *!"# "% >>) GOW_ͳ((ge*>g&|:&S&z< D(*s(*j(ҥ* )!* ~:' ~A*6{y%!* ~*O+~+µ*!*)*yͳ((+6+q*:) O!) >$-,2" Ð,!# ~5#*!x!+>)<)+ <=+|G+y3+|Gz)*͘(,Q0|)+DM!>)ڈ+)p+ ڈ+=b+|+x+ʙ+*͘(*'x)*s(| ++DM!>+ +7>{_zW}o|g=+v+|G+|)Ooyg)*' +|5*X(ͧ+g{o)+!6 ~w!7 ~G+N* (Q,/<#Fwx+ A,F+N9(!/ G>w2" !6 $-:/ 2" x,,,4ʗ0P-,>,!+ -G:) ¹,!" Vwz# ž,x‘,%!" X-,x,!* w%:" ,!+ ~++w!# 4#,4ʗ0+6S !0 ->!0 #"  "!>:yHG+2ȸ#"<֌WVͨ9D" : G: xf: ' q# ¨*' #^#V*DҜ* DҤ! DҤ>HFH(2DZzPY" : {:_ ͋ ~GD+K x[,  <2~Zz< 2* * "~5#####͋ J  fOgD,* fZ |J" 2 " ~,2ʍD+ͅ(ʧ2 * 2©©Õ>2Q+2QB"?ʎʎ,O; c1F6 *' 4*|H*' :/:G @22go"D#ʭQiL͙ͨ9:*QKJDF>V?Redo from start #~ "^x: !KDG* Q! R#ʃiL">2>2 F~,¹2 2ýD;GG: >?@> @QKJD6,+>2 2ͨ9~+(#2 2 W]!#~ "! _6![!_.6!!6!I!: G! >2 { W! !!<~d!#~#r! j*!:G@ #T]~ʀ!#!~!ʚ!y_­!: >2 ![¹!2 !: >2 !> yG{!~#_yG!!2 !2E0:?+2͸" ʩ6 ʬ6* c1: O *" H5">&{: F"!F"#~ ̽(~#x": L" i".s"Ds"EL"L"{ʁ"* !8$ҟ"T]DJ!h DG!* D±"`i" "N]~"N]D,͋ y):* :) Í% PX2#,#OBK2#D,O2#D,Z zJ`iDJ^# J!DJ^{#Vq#~#+N#͔#^{#Vʏ##s#r x# 2 *+#~##^#V2ʝ#O: y$#2©#2©#ez#$¦#e > ($DB!$DGT1L1+æ#Undefined line ¦#e###N#F>!#* +p+q+w: Õ#DBDADSDE: * * D ~0  2 <2 2~͆$#|$ÆAʗ$y)ó$!$DG.KJD#~.~˜$y)"87Random number seed (-32768- to 32767)$*" +2%% 2-# -~/w!" Oyw#-q;-NsY+0-&- W~w+E->-!) B-~w# Z-D(:7 %'͠.qʘ-G,P-x -x-Ð,!) ,-Ð-L} :* A--!0 (c-:) -2) !s(.# !0 (.%,# !0 (>.%.%,!6 6.=-...!* 5%!7 >5=.>!0 N#F#=+.>!7 p+q+=<.:7 ʣ0:* %'44ʗ0͠.!Z qA>,?w.>,:) <=,!# Z-!S X-xe.!* 5e.%y26 +Y ~q+«.(+~ڗ0w%,4×0%2*o%>2, `h)~&ʄ-.+.+2/.ʉ/e/E8/2l&/L&/q&/Q7/: Q/>Q/~%ʖ/#ʧ/!ʨ/dQ/Dh/ͱ/2M2V0h/_{_//l/j(!\') h/ܱ/.2!\'!y)h/ͱ/2h/)*-(.=c'-2, *|$2 > ͆$> ͆$!' "^()2, ~,l>2- {:- =lH+2~,+2x6,\* 2 hD,ͨ9~,z: 2 *|Q½2WG"ʧ: Wʤ:,+FO: y!W2..+2,q+2d: 0D#~# #^#V" 2zDD(+Bͮ2, " * ~" ڪ_O: {}H !xV0zQz!' :  N#F#N#F#!# N#F#N#FKG* W " 2ì)͘(7ãy)ãxdd!]s*' ~Fãy2 : 4ʂGWxDzkxz Ҋ! N#F*' *("% "# ͨ(*!: og~#fo(2 R"' W)!]͘(*ͳ(") "' Ä*͘(*l'2 .2Ee ڸ<=ʮW"Fj&ʄ2:2* ,12D(#͈ VQ!ͨ9D)|J)IʣB"I+UnD)} * j(ͨ9"' (~a{_&Z2vOH#~v2EҲ:0ùG7))))o Ù+28  )))0O )#~ց2($%#~#Y #^#V" 2y~3%$$$$$2%** "ͨ9+2%h%D,+=%":, 2- 2, !G6Ͷ(Í%Ͷ(s(x:* ʨ(ҧ%/<͘(ͨ((gg&|!' %G&(ʗ0.͎&(&G~_#~W#~OS&hcGy&JTeox%2* | &y&O&)zWyO%x\E(&!* w%%x!* :&F#~怩Oè( 4Ö0~_#~W#~O!+ ~/woG}_}W}Ov&CZQi& ozŠ&y-OҀ&Ð&-yOzW{_xGÊ&$cCu͍M r5D(J&1r'ͳ(>2* ͘(!&7͘(ͨ(!&7n'͘(S(Í%D(.(y2A'"<'PX!%!*'!' ~#^'WyB'O|g}oxGV'x Gz4'CZQO͘(!-ͥ(D(ʟ0.(44+~2'+~2'+~2'AOW_2'}o|gxG>?Ұ'2'7y<=':'x'> )&{_zWyO)xG:'2'y“'!* 5“'%>.!6 N#G.x&(}!* Gx%(ƀw\'(w+D(/%o0ͳ(xڏ0G͍%!* 4Ï0:* :) /<!* Op#6%ͅ(+ !) ~wͅ(og) D(*' ||N(*' *) Ͷ("' `i") !' ^#V#N#F#' (: Gw#(!) ~7w?##wy7O!0 ((!0 (' : D1 1H1(1!# H1(* |91* D! " ! "!c DGCG)1À11n16+ͅ(16-j(#60: W: 3 315!9 F : _ ʹ1x*¹1{¹1Aq21E1D10ʹ1,ʹ1.1+60{1+6${+p2 !9 6 ͘(*# *% 2. ͠2E~A2:!20!2 #~2>DG2"# `i"% #~+ʈ2-_20OxG҈2#~F2`xE}2y 12>2. Í2|12u212"# `i"% ͨ(#W͖4:. 22225560̽(\5+~02.Ľ( 3>"w#6+26-/</ 2:#p#w#6!9 #zҋ3(4-5z 55{(= 5͜1@3p#6!8 #: ~ E3*E3+Y32-+$0ƒ3#2҃3++wy3F3ʃ36%/4ʧ3K6B)3c1+6%)3D(Ė43_x 5 5\55H5-3_y/3/3{_x4 5 54 5yL5O 5GO\54* = 5P63*ѯ54D(7Ė4y/OzWO/U4c4/<!@T1> @!  ~#B=G%BM=v0l= l=_zWM=!K=w=>O>?=1ڒ= !? >#=i>>4>?(d>=a>>@QB=~B#=!.>7%B_.>~ >Bܬ>>#~== QB*=~>\B~.>Bͬ>>>\@~%B V> V>V> V>>@7>wB#4>6H=%Bʜ>ʞ> ?ʞ> ʼ>ʼ> ʼ> i>_¼>>_>B+i> ~7\'#~+w#î>y>>@i> o&DM#BwB#>x+>B>x+~B> QBz\@@_W@W~#!ʹ@#?&ʴ@ʒ@+>s?+~#.?_ʨ@\Q?j?$?*j?x#ڽ?~$> ?#W!@~#.?#?,@z@W?~#>.j?# !@~##?@T]^###xG#z+A@xA@~-<@A@>Wʝ@CxJzd1DG+27y@2 ;v@, 2~#N#fi_xp?Ø@@@3?QBH@~#@Ê@ý@>@ʝ@:**' AqIGG*' <`@=G> `@@@z>+@W~HJ#^#VF͎ * sG2D(͋ D,D)FI͎ IIIRI͎ > {FGI* w#aIIIO>~zIx]G#F#fh DMFoͽHHGInI~IJKrI=O~GCH_#~#foFr+2.pD)C2>J͎ JD,:*D,*' D)H\'HG=O>x~#F#fh GN#^#VwJ nJ#YJѯx<#VJkJD(ͨ9:*#^#V* DگJ*DүJF(D,͋ J~KHG!\'y~J?@> @IKA›K6YKp22 AKQB!+=:>\2vKHK@+ʊK~@;K+@;K@QB! 2ObK:ʱK>\@2yLwD7 \L L KIKLwDIKKQK@> @>ÃKK>#ÊKL6QB! ;K ;Kx<9L*|>=L! Z"Îyq#@ ;K2 > @AML ;KÛK: LBw! >2 ;2 2" $2L33L " ** L L M" *" ##^#V#~#fo"ͅ(LA3* "!9~#L LN#F`i6B)4=60# 55H560#=5{5#HT56." #H 6,#5(!C6(%,*S6> H5/>,҅5>,p#=|5!# ͥ(ø5~%>A*ͨ(6?H5ͳ(/{_#zW#yO++5G&#ͨ(p#ھ5>56>H5N#F#*' /}o|g 6"' p#=5H5w1_cƤ~@zZrN vH Tʚ;@B''d G"8 կ6))))6y=660:6 666!s(͘(!G6ͥ( 7)!w%>2, D(xW7"70%yͳ(?7͌*)|") "' 6s(&'8;':* Ҍ7hڞ7͘(͌*Ɓʏ7͊%!77J'͘(:) 7%Í0ͨ(|Yt&wz^Pc|u~r1͘(+ͳ('͘(~#ͥ(='Ͷ(͍%7RO2!&ͥ( 85*D(!u8k8!8ͥ(!u8Ȇw#O Ͷ(':t8<2t8!8O ́%ͳ({YOO6+F6!s84~֫b8w %!8ÿ(w+w+wF85Jʙ9v" GSљ e͘w>ROhFhiuh!9́%:* w"~'͘(͌*͊%)8͍%͍%D(s(͍%s(:) 9*|jV:ʆA#A:=2aA 7A> @:(A ]A`A:<:WA!wA`A`A<2Oɯ2:> aA> aA2:yG¥A: ʷA=2 >A ºA> @: ªA A:G: AQBAA<2 O*|$BW\'SS: 7P:!kC!h DG:uD/2uD: QB6! > @> @*|gB:sB2ɯ2 :=@zB%B%B2wD5D2B·BB%BF_I!g "' >2 :2@ > @[B> CD~ +B*  >ƕo>Cg9*++"  3C͈G3CC* D:G!^#V#GCT*ͯD2 2 2 w#w#" *+" : ŒC2 2 ! 6#…C7!8(!s8w#w#w2 og" " * : ·C" D* " " : T*++" ##! " w%nAgo" 2 "q " " 2 * |}~D##~:7 */DZ`i+" <@DT" ! " !*}ƒD22>^@@@QB* | * "͋ <2>2! ͨ9! (* D,ͨ9 * DJ( (>2 ͨ9J2D L >2 ͨ9(y)"  B!9 +2" MD(ͨ9s#r#~,]M 2CMD)" >!=M=M=M!9DM!M* * * 2 2 ~§M2 #+2͚R!" +2'ND,,M"" +2'ND,MDADLDL\OD, 2 28$`i"  NT]" DJ\O*+#~#N#^#V"2+N:;NXN2+;N2>N>2 ͨ9ʶNxGͽ;>2 „N~(ŠNN~(Jͨ9z£NxG: WF:zJBK!N N 2 ~(ŠN ͪN+2>N(N2D)>ND,^N* * D2ON##~w#< NO* " N* DOy_xW `i" * D\O##~w#2 : sS:2ÿR2 2 * DM* " * #* " DUP `i" * |*+ `iQ+2PPc1F*' #^#V °Pr+s+5GG+2P;PD,+2>,@ÍP>"@GG>"@óP*| Q~ Qʹ\}o|g Q>2) !$97:) 2) "~Ie&X4#]I͘(ͬ8͘(ͨ(ͦ8l'D(6s(:* k9QYn'!%!u97!9 J;xn{/|t1}=Z}~L~l+2D,92 N1E G2#~.:9:9092E:G#~:9092E9.9x' 2~&:*:%$!#y_! V+z2 2: =ʽ;F:~(A;3A;2 : 2 ʚ:*  " À:ox:: x:;&* D<^#~#;: ;~<#^^#V#;: DM\'ʈ<  #:;#;+<;: w#_]G! w#s#r+"P#~ FFF"2x,G G+~ G#yF >* "' >2 ( D" ~ #FH͸( @ [BNG* * /O #D{G" # _G* " !* ! * DG4H!o " * " * * DG~###<G5H_öG* ~#fo* G" ##^#V#" öG* DYH~###>>F* (I>>>HJ<#N#fi2 ( ,QZQQͨ9:*;W_W QQ"QG{,xQPXW7R! Oz"y"R WR "RO{,yĐRW7R "R{ 1R,> 1R1R7R7R͐RWQ"BR jRWjR BR,jR bRWjR jR*( 46! { ~RBF2..ɷw#kRX͚R:2+2RD,DR 22!6"UC:2*""*#|lV* *DSS~#lVS V:SS=S~,2~#2͋ SůSѯ0Q  ! ~#fo" !"a]| G~,͈ DADSͨ9:*O*a] "a]* D q#s#r:T7ͨ9:*HF~O#^#VT*DT* DTY* * DUy]GH#s#r#^#V#^#VyTGO UU~#T ] \ \ ** D!$9}o|g!u9}o|g E] ] ]*|<: J>C*+6*^~ Rê !0`2 "" * ^#V"B"B"##^#V")B##^#V"A##^#V"gA 2B!]!!""C!"22 2 2 2!"!" ! " ! "o *" >2!^"^:^¼^<2^!~"^ʼ^F#~+w##+^+6"^!2ʼ^/_^+6""^#/_^2P^ü^62Sʦ^Mt^F 2D:ʓ^zJ{J2Ø^" +2ʼ^D/d^2D:" Ø^+* +" +:!|]"2<s#r# *  DM=^#"" {ozgC|g}o_|_!{ozgC" "" " *C}o|g++!_DGT1!y_DG!DG" QB! "h] Owned by Microsoft Bytes freeBASIC-80 Rev. 5.2 [CP/M Version] Copyright 1977, 78, 79, 80 (C) by Microsoft Created: 14-Jul-80  version i desired. Th tw file 'BIOS.COM an 'CBIOS.COM ar example o dis an termina I/ routine supplie b Digita Reasearch. MOVCPM Th 'MOVCPM.COM featur o CP/ ca b use t directl relocat th COL an WAR boo programs th CBIOS an CP/M I modification ar don t an o th above th 'MOVCPM.COM progra wil relocat al bu th modifie portions Follo th procedure o th nex pag i an o th abov program ar modified. I relocate CP/ progra i create usin th command: movcpm xx th relocate CP/ wil begi executing However th relocate CP/͠ i highl unstable I particular i war boo occurs th syste ma no reboo properly Thi i no bu i th 'MOVCPM.COM program bu rathe functio o th origina an relocate CP/M's I i recommende tha th followin procedur b use instead: movcpm xx * sysgen cold boot U>  U$UxFGT2D$D(͋ ~,OU20Q (QD)}JFʉUBpU%BʂUw# bUG* MDW uUO #~~(PY!' ůw͵W:D͗Z = =Uѯý < !% ^#Vr+s?Q:V PY0V!'V`i>}V!' ~U͵W)=V*T]% N#F+q#p###6 –W͵W:C͗Z>®W>w+w!(LW7?*' 6#67H~ #^#fk_XN#~:X++@ y@  ! #TX~.2X@X7X#X2-z  > @X9X> YX9XW!< !! w#„XDADSW:!!J!< H~ #N#F OXIXR D,#2͋ D,{ _.pl 63 .po 0 .he Notes on CP/M Ver. 2.2 With Discus M26, M10, and M20 .fo Page # Ther ar severa feature o Morro Design versio o CP/ Ver 2. wit whic user accustome t singl densit CP/ o inc drive ma no b familiar I addition som explanatio i require fo certai utilit command provide b Morro Designs Thes specia feature an utilitie ar discusse below. CBIOS Th CBIOS supplie wit CP/ Ver 2. ha som uniqu feature whic allo user t easil us flopp diskette o differen densitie and/o secto sizes Th CBIOS wil rea an writ diskette formate i IB 374 singl densit format an IB syste 3 doubl densit format Th compatibilit wit IB diskette i ONL i th formattin information NO i th fil structure Thi mean tha th Dis Jocke 2Ġ ca rea IB diskettes bu softwar i neede t rea IB files N c the system. This will insure that the newly relocated CP/M is stable. Fo user wit th Discu Har Dis System th 'MOVCPM.COM progra relocate th CBIOS an BOOT fo th Har Dis version NOT fo th flopp version. ASSIGNING DENSITY User familia wit th Lifeboat/Morro Design 2 CP/ Ver 1. wh ar accustome t usin th 'DENSITY.COM progra wil appreciat th automati determinatio o th densit o diskette Ther i n nee t infor CP/ Ver 2. ahea o tim o th densit o diskette Jus inser th diskette th res i al take car of. Car mus b taken however whe removin o replacin diskett whic ha alread bee accesse b CP/M dis rese operatio shoul b performe b b doin war boot o makin BDOӠ cal t rese th dis syste (se th CP/͠ interfac guide). A thes ne feature hav bee adde th siz o th Cbio ha grow t th poin wher th v?Q zW Z" 2Y{2Y!*~ 2Y6B#6A#6S"#! w# =Y66͵W~nY< ÃY<ƒY bY!%w#w#w#w~ʤYC~W* ) p# ªYCTT _W!<  Z!!6# ͏ZW2-!"͋Z!*͋Z! O!  ~#@y`Z~ ]Z>.@ JZ: W:yZ> @@QB!:Z~*6?# ZO!!4¯Z#4¯Z#4y"Z ><+2ZC* DJ! s#r#wZ2g]0Q ! ^#V~,C+2 { +s#r! w#w! ~#fo!DM[Ë[BK>!)`[)#a[))o[ n[#=V[}_}la)J҆[#xJ"a]! "c]!) "e]!}o|gDڵ[bk:g][D[\DM*e]*c]M\"c]PY\}o|g*a]#"a]˜[\DM*c]*e]M\"c]PY[2*a]! ~#foDs#r<\:I\!I\!& èV~# xN\DMͶ\ ͫ\! w!( V6 ʃ\zwʹ\ ͫ\! ~!æ\! ^#V! s#rDMͣ\͝\D2" ͕#\>S]C ** D!u9}o|g!$9}o|ghang i necessar withi th CBIOS t allo user t rea and/o writ an o th IB standar secto sizes Th CBIOS als support singl an doubl side drives User wit doubl side drive mus us doubl side diskette i orde t tak advantag o th buil i doubl side features I singl side diskette ar use i doubl side drive th singl side parameter o th CBIOS wil tak precedenc ove th doubl side parameter (thre millisecon seek an extende storage) Th CBIOS require approximatel 2ˠ o memor abov th regula CBIOS supplie b Digita Research Th sourc fo th CBIOS i i th fil 'CBIOS&.ASM' an th sourc fo th COL an WAR boot i i th fil 'ABOOT&.ASM' Th dis paramete header an dis paramete block require b CP/ ar han code i th sourc files Th fil 'DISKS.ASM contain macr librar definition whic ca b substitute fo th han code<ersio fo th doubl densit controlle ca n longe fi o th firs tw track i formatte i singl density Thi mean tha yo ca onl boo u wit diskett tha ha bee formatte wit 102 byt sectors. FORMATTING A DISKETTE Th comman fil 'FORMT#.COM wil format o initialize flopp diskett i an IB standar format Typin FORMT# wil execut progra tha wil inquir th secto size 128 256 512 o 1024 t b formatted an th drive-- A B C o D-- wher th initializatio wil tak place Th driv specifie reflect th flopp drive only nothin else S formattin driv 'A format th firs flopp connecte t th Dis Jocke 2D Formattin diskett wil automaticall writ secto header fo th selecte secto size I i i desire t forma th har disk th progra 'FORMATHD.COM shoul b used. CAUTION Yo mus us cautio wit th FORMATH progra a thiP B carefu abou whic drive (Har Dis o Floppy ar drive A, B etc a thi step destroys the original CP/M on the destination drive. -Reset the system and do a COLD BOOT. A a exampl o th relocatio procedure th followin i sampl configuratio fo Cbio wit 48 o memory th Dis Jocke 2 a 0F800H th Discu Har Dis a 50H an Dis Jocke 2 I/O. -Edi th 'CBIOS&.ASM file mak sur th followin label have these values: MSIZE = 48 Specifies 48K of memory. FIRST = 1 Specifies Discus Hard Disk drive precedes the Disk Jockey 2D drives. MAXHD = 1 Specifies one Discus Hard Disk drive. MAXFFLOP 2 Specifies 2 Disk Jockey 2D drives. IOTYPE = 3 Specifies Disk Jockey 2D I/O. HDORG = 50H Discus Hard Disk I/O ports begin at 50H. ORIGIN = 0F800H Disk Jockey 2D begins at 0F800iv system It purpos i t allo thes user t cop CP/ file betwee diskettes User wit dua driv堠 system ca perfor suc copie faste an䠠 mor convenientl simpl b usin PIP. 'SINGLE operate b interceptin CP/ call t dis driv selec routines Rathe tha selectin NEנ drive 'SINGLE prompt th use t plac a "A o "B diskett int Driv A I othe words 'SINGLE turn Driv int logica dua driv system Th user however mus kee trac o whic diskett ha bee designate th "A diskett an whic th "B diskette A a example t cop fil fro driv t driv A giv the command: SINGLE S t begi operatio i singl mod (th "S argumen i fo Start) Th progra wil respon tha 'SINGLE ha bee installed an retur t CP/M An operatio tha involve changin drive wil no resul i promp t plac th "A o "B ca eras th dat o th har dis an i ca no b recovered I yo hav t forma th dis thin abou wha i o th har dis when you use the 'D' option for formating. Yo shoul tak not tha i you floppie hav bee adde t you syste vi th INSTAL progra o tha the ar drive C: D: o abov the th CP/ driv number hav nothin t d wit FORMT an tha driv wil alway b th firs flopp dis drive. RECONFIGURING A SYSTEM T reconfigur th CP/ syste fo you particula hardwar th 'CBIOS&.ASM an 'ABOOT&.ASM file shoul b modifie t mee you requirements Man parameter o th Cbio ca b modifie b changin th valu o certai ke variable whic ar use durin th assembly Fo exampl th labe MSIZ i use t adjus th memor siz o th reconfigure CP/M th labe FIRS is used to specify the ordering of the disk drives, etc. Onc th 'CBIOS&.ASM an 'ABOOT&.ASM fileH. -Edi th 'ABOOT&.ASM file mak sur th followin label have these values: MSIZE = 48 Specifies 48K of memory. FIRST = 1 Specifies Discus Hard Disk drive precedes the Disk Jockey 2D drives. MAXHD = 1 Specifies one Discus Hard Disk drive. MAXFFLOP 2 Specifies 2 Disk Jockey 2D drives. HDORG = 50H Discus Hard Disk I/O ports begin at 50H. ORIGIN = 0F800H Disk Jockey 2D begins at 0E000H. -Assemble the 'CBIOS&.ASM' file: A>MAC CBIOS& -Assemble the 'ABOOT&.ASM' file: A>MAC ABOOT& -Fin th valu o th labe 'OFFSETB i th 'ABOOT&.PRN file. A>TYPE ABOOT&.PRN Watc fo th labe 'OFFSETB t b printe o th console record the value, 0D00 in this example. -Fin th valu o th labe 'OFFSETC i th 'CBIOS&.PRN file. A>TYPE CBIOS&.P diskett int Driv A I ou example th "B diskett woul b th on wit th fil whic w wis t cop ont th syste diskette On coul no type: PIP A:DEST.FILE=B:SOURCE.FILE[V] Dependin upo th lengt o th fil t b transferred fai numbe o request t plac th "A o "B diskett int Driv wil appea unti th cop i completed A entir syste dis coul als b backe u thi way Firs on woul forma th destinatio disk Next th command: PIP A:=B:*.* woul begi th copy Thi proces wil tak man man swap bu wil d th job Th numbe o diskett swap depend o th amoun o memor whic PIP ha t use an o th amoun o dat t b transferred. I general an CP/ comman whic ca b use i regula mod ca b use whil i singl mode Ther ar tw exceptions however Th 'FORMT#.COM program becaus i make direc call t Dis hav bee edite an reassembled th followin procedur ma b use䠠 t incorporat th ne driver int CP/M: -Typ "TYP ABOOT&.PRN" watc fo th labe "OFFSETB i th listing an recor it value. -Typ "TYP CBIOS&.PRN" watc fo th labe "OFFSETC i th listing an recor it value. -Typ "MOVCP x *" wher x represent th memor size i kilobytes o th desire system. -Type "SAVE 47 CPMxx.COM", with xx as above. -Type "DDT CPMxx.COM", with xx as above. -Type "IABOOT&.HEX". -Type "ROFFSETB", with OFFSETB value from the step above. -Type "ICBIOS&.HEX" -Type "ROFFSETC"with OFFSETC value from the steps above. -Type control C (^C) to return from DDT to CP/M. -Typ "SYSGEN". CP/ wil reques th nam o th sourc drive Answe b pressin retur (a thi poin th sourc fo th ne syste i i RA memory no o th dis wher yo wan it). -Typ th destinatio drive-- throug RN Watc fo th labe 'OFFSETC t b printe o th console record the value, 7600 in this example. -Relocate the CCP and BDOS parts of CP/M: A>MOVCPM 48 * -Save the system image on the disk: A>SAVE 47 CPM48.COM -Load the system image into memory with DDT: A>DDT CPM48.COM NEXT PC 3000 0100 -IABOOT&.HEX -R0D00 NEXT PC 3000 0000 -ICBIOS&.HEX -R7600 NEXT PC 3000 0000 -^C A> -Now, write the system image out to the disk: A>SYSGEN Answe th firs questio aske wit return th syste imag i i memory Answe th secon questio wit th destinatio drive for the new system. -Reset the system and do a COLD BOOT. SINGLE COMMAND Th progra 'SINGLE.COM i o interes mainl t thos user wh hav onl singl dr= Jocke 2 firmware wil no functio properl i singl mode an 'MOVCPM.COM becaus o memor relocatio problems. To exit single mode, type: SINGLE E Thi wil retur th use t th standar CP/ syste (Th "E argumen i fo End) Typin 'SINGL E' whe no i singl mod wil repor a erro an retur withou an chang bein made a wil typin 'SINGL S' i alread i singl mode. REGEN Th 'REGEN.COM comman regenerate CP/͠ singl densit diskette whic hav bee formatte i suc wa s tha i i incompatibl wit th norma operatio o th 179 controlle chi (IMSA diskette i particula hav thi problem). Th 'REGEN progra i designe t b use wit diskette whic hav bee formatte incorrectly-- no wit diskette tha hav bee partiall destroyed Th bes sympto o diskett tha coul b use wit th 'REGEN progra i tha th Dis Jocke 1 boa!p+q* !q*& *M *M !p+q*!!p+q*"!p+q*$!6  !kp+q*j> >ڪ Þ !qp+q/ *pDM9: :M2r:N!r !:r *r& N!r4 !6:͔: :ͳ.!ws+p+q+p+q:w=2wN *s*u w*s#"s*u#"u' !"*M^7 !x6:!xھ **DM͆ 2yʭ :yʗ ͯ *"*6:2x÷ *"!x4d !"/ !j}=2| !"*KM^'_ !z6:|!z1 * "}*}DM͆ ' ͯ *"!z4 :e !"͆ !z6:|!z '? 2*H#"H!{6:{ր!Ң *{& :{4 2!{4m *":ڹ ͯ !z4I '2!"!q: !4>!S :S! :2*M! ^#V͎ * :w*#" = = = = = ͯ  *M !6q  !6q  !6q  *& !6à  !6 à  !60à  *& !6  !6  !6  *& . 1 4 7 : = F P [ f q  r ca rea i (th DJ1 doe no utiliz th 179 controlle chip bu th Dis Jocke 2 cannot. Essentially th 'REGEN progra read complet trac o dat an forma informatio int memory filter ou th formatting re-format th trac an the re-write th data Thi proces i repeate unti th whol diskett ha bee regenerated Th origina diskett i bot th sourc an destinatio diskette an mus therefor b writ enabled. Th fina resul shoul b singl densit diskett tha i readabl bot o th machin tha originall produce i a well as on the Disk Jockey 2D controller. Simpl typin 'REGEN wil invok thi program I ha enoug prompt t explai it use. FIRMB Th fil 'FIRMB.ASM contain th firmwar sourc fo Dis Jocke 2Ġ Mode controller BOOTHD Th progra 'BOOTHD.COM contain boo stra loade fo th Discu Har Dis cont(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE) COPYRIGHT (C) 1979, DIGITAL RESEARCH, PIP VERS 1.5$$$ SUB =.:,<> _[]INPIRDPTRUR1UR2RDROUTLPTUL1PRNLSTPTPUP1UP2PUNTTYCRTUC1CONNULEOFDISK READ ERROR$DISK WRITE ERROR$VERIFY ERROR$NOT A CHARACTER SINK$READER STOPPING $NOT A CHARACTER SOURCE$ABORTED$BAD PARAMETER$INVALID USER NUMBER$RECORD TOO LONG$INVALID DIGIT$END OF FILE, CTL-Z?$CHECKSUM ERROR$CORRECT ERROR, TYPE RETURN OR CTL-Z$INVALID FORMAT$HEX$$$$NO DIRECTORY SPACE$NO FILE$COM$START NOT FOUND$QUIT NOT FOUND$CANNOT CLOSE DESTINATION FILE$DESTINATION IS R/O, DELETE (Y/N)?$**NOT DELETED**$$$$$$$NOT FOUND$COPYING -$REQUIRES CP/M 2.0 OR NEWER FOR OPERATION.$UNRECOGNIZED DESTINATION$CANNOT WRITE$INVALID PIP FORMAT$CANNOT READ$INVALID SEPARATOR$1 :2L> ̈́M9  :2!q: " *M n :c4 *M n :2!c:Q !c:2: !:cw>!n !5 Y : { !6!q:!lwҙ  â :0O !q:O| :O| !6:]2l:o'2o:n'2n:m'2m*mMͣ *nMͣ *oMͣ :]:   *}2D" * * *&"!q:UY: Y:ҩ: ʩ:_2ʘ:€!6<:<2!ژ!6 >!]Ҥ; !6:Q::H: !6*M : !6!q:a/>z!/H:_2:!q:A/>Z!/H8: 2::=O>m:W!Q} Hmd>9>!6:2*M!E ^#V͎ڗO **~2*#"m2m͖ 2m!6m!6m!6 m2mͯ m!62m!62m!62m!62m'2:2:TҒ:2!6*ME:2::Ҳ:<22ý: 2:} >ͯ :i:2:d*M:[ roller 'BOOTHD.COM coul b programme int PRO s tha yo coul boo directl ont th har disk withou havin t bothe wit th floppies. HDFIRM Th sourc fo se o lo leve driver fo th Discu Har Dis ma b foun i th fil 'HDFIRM.ASM' Th driver ma b堠 use䠠 b applicatio program whic mus hav堠 direc interactio wit th har disk' hardware.  Th fina resul shoul b singl densit diskett tha i readabl bot o th machin tha originall produce i a well as on the Disk Jockey 2D controller. Simpl typin 'REGEN wil invok thi program I ha enoug prompt t explai it use. FIRMB Th fil 'FIRMB.ASM contain th firmwar sourc fo Dis Jocke 2Ġ Mode controller BOOTHD Th progra 'BOOTHD.COM contain boo stra loade fo th Discu Har Dis cont221@:2!o6+6+6!6#6!6#6:G*o .!N6:^*M^!K6!6!6+6' :$::=2K  :ʤ\:ҷ\x'Ͳ:!\͢  :͈'! Ͳ:$: $͈Ͳ!N6' :!Cwͯ !6:^͢c!6{:/>!/H{ͯ :<2Š ::=HҮͯ !6:Ҿ:2 !6::/H͈;!6:> !/>HHͯ :^!w:<2:0}:@E}:!S!W6: z!]6:cm!c6:_z!_6l ::,: HHҰͯ : 2ó:E:1:2v!q!*8!*6: >ͦ>ͦ!q:_  !p+q.*   !q*&!p+q*2!p+q*2!p+q*22!p+q*!p+q*!p+q*!p+q*2!p+q*>*M:>!(:=2%> >>!F!5+N! ~2!4<2T>>!b}*bMͭz:b2!b6:<2é>!`ҥ*`MͭҞ!`6!6> :é:(!q:!wO! ~2*& :w>!:!4!6>:N<2N!> *N& N2 !p+q!6!6+6 !6: S: M!6g8:N2M*M8p!6!6!6>!ڕ*&P 6!4z!6!6#6#6!6*M8:ھ:*͇g2ê::¿::,͡A<2O>*M8):[ͱ!N5!6ñ:5!6#6>!ڰ!6:<2O>/:!O!T *M͡H~K:¡!6[–ͱ!N5:2:2!4=:[¼ͱ4:!6:.2O8: :* ͇g:[ ͱ!N5!6:%:<2*6 * 6å!q!6> !d*&I :]>!4A>:<2O* :w:?†!6!q!6?!:ҠgÐ!q*&*~!6:22: :]Hں:A2O>: 2ͯ DM!  ::=H-\:N2O_og_{ozg^#V))) _{ozg^#V) d^#V|g}o n_{ozgO{ozgi`N#Fogo&og H ©=¨* * REGEN.ASM vers 1.1 september 30, 1980 * * By Bryan G. Moore * Design Technology * 4888-H Ronson Court * San Diego, CA 92111 * * Modified for all revision Disk Jockey 2D'S by Bobby Dale Gifford * 9/30/80 * * The program is used to correct the format on Single Density * IBM 3740 compatible diskettes. Attempts to use other diskettes * will probably result in an error message. * * vernum equ 11 ;Version number * 10 origin equ 0F800H bdos equ 5 ;CP/M entry point wboot equ 0 ;Warm boot diskio equ origin+3f8h datreg equ diskio+7 drvsel equ diskio+1 cstall equ diskio+3 cmdreg equ diskio+4 secreg equ diskio+6 trkreg equ diskio+5 sbegin equ origin+3deh ramins equ origin+7e2h dside equ 10Q unloadb equ 17Q sicmd equ 131Q immirq equ 320Q unloada equ 30Q restor equ 11Q rtcmd equ 0e4h wsec equ 0a0h rsec equ 80h index equ 20Q trkzro equ 4 intrqa equ 1 intrqb equ 4 lhsdenb equ 90dh lhddenb equ 80ch lhsdena equ 111h lhddena equ 10h acr equ 0dh alf equ 0ah org 100h ÷:S:QHI:N<22: H@"2Í202O> c!6Í202O> ڍ*&O*& !sc*&P :w:·>!ұͯ :22:_!6=!6>'!E!4!p+q*0 !r+s+p+q*~$7*>*>H&>*#"*#"> 2:R͎:!6!6=2:ʙ!6:“H9Ž>!6-e!6ͻ2=2ʺ-é:>>"ͻ2:!!5ͻ2ͬ!\-:>>!p+q:,!6*DM9:<!6:z 2W!6D*&L :w:<2Ov*:>=20O> ڒ:0:AO>Ҥ::A }}Hͬ!wͻO`idͻV[2O>2:!X!6:!:=O!L NE!4 E E:/.*&L 6$L9k9.Xͯ *KM^020 :020:121'ͳ':²ͯ !G6!"!"7 *M^n/ :a/:H!6:ͯ !&6NAME prl -- "page reelocatable" format DESCRIPTION Prl ("page relocatable") is a file format for relocatable object code defined in the Mpm users manual. It begins with a 256 byte header: header[0] Octal 375. Not documented by Mpm. header[1 to 2] Program size (low byte first). header[3] Not documented by Mpm. header[4 to 5] Size of any required buffer space (low byte first). header[6 to 255] Currently unused, reserved by Mpm. Next comes "program-size" bytes of binary object code assembled at address 0. Finally comes a "bit map", one bit for each byte of code, beginning with the most significant bit of the map's first byte. A 1 bit indicates that the corresponding byte of code should be relocated by adding to it the most significant byte of the load address. The usual way to make a prl file is to assemble the source code twice, once at 0 and once at 100 hex. Then build the map by comparin;CP/M Tpa begin lxi sp,stack ;Stack pointer lxi d,prompt ;Sign-on call pbuff ;To console lhld origin+7 ;Adjust the calling routines for different inx h ; revisions of the Disk Jockey mov a,m lxi h,stdvsl+1 lxi d,4 mov m,a xri 3 dad d mov m,a dad d mov m,a start lxi d,srcmsg ;Prompt the user to select drive call readdrv ;Get a drive designator sta sdisk ;Save source disk lxi d,dstmsg ;Prompt the user to select drive call readdrv ;Get drive designator sta ddisk ;Save destination disk mount lxi d,mntmsg ;Prompt the user to call prbuff ;Read console jnz start ;Ignore anything else regena lxi d,acralf call pbuff xra a ;Select source call select ;Select the drive lxi h,cmdreg mvi m,immirq ;Immediate interupt request mvi a,40h ;Simple delay wirqda dcr a jnz wirqda mov a,m ;Check ready rar jc notrdy ral ral jc notrdy lxi d,0 call gtindx ;Get polarity of index pulse call gtstat ;Test for double sided ani dside jnz ixlo2*">!b!ͯ >!`0ͯ !q:E:24J!46*}a!44EJ *KM^'́:‚ͯ !36'n::0:f9OY#9.3'ͳ.:020' 'ͳ'7 6'!j>A+!s!"@͓1!"<**"͓n "Dn"":!Q2҂:X!Wғä:ڤ*MEÓ:ұ@@:O2Mc;!6#6>!)*&P ~"::H:H:H:H"!6!4:_jYO jM*"S*" 3@bl*M1͓!""7 *M^͆ \͔!":͎H*#"ͧÝ/ :>͛9ͯ .*#":_!' !'6!36' :1/!aE*#">z?C9IͲÁ.!6> !ڇ*&' ~2 ʀ: y.*M!4Q>!қ:=2á:2:Ҭ\>!ҿ:=2K:2K!:!:K\: \!p+q͈*g the bytes one-for-one, setting the corresponding bit to the difference. If two bytes differ by more than 1, then some non-relocatable construct has been used. BUGS The load address must be on a page boundry (multiple of 256). prl.doc 8/5/80 gf ruct has been used. BUGS The load address must be on a page boundry (multiple of 256). ?pa dblside lxi d,sglside ;No double sided diskettes jmp notrdyx ixlopa call gtstat ;Wait for index pulses ani index xra b jnz restora dcx d mov a,d ora a jnz ixlopa notrdy lxi d,rmessg ;Not ready message notrdyx xchg lxi d,amessg push h call pbuff ;Print drive message lda cdisk ana a lda sdisk jz notdrv lda ddisk notdrv adi 'A' ;And drive letter mov e,a mvi c,2 call bdos pop d call pbuff call unload ;Unload the heads jmp mount restora call restore regenb mvi a,1 ;Select destination call select ;Select the drive lxi h,cmdreg mvi m,immirq ;Immediate interupt request mvi a,40h ;Simple delay wirqdb dcr a jnz wirqdb mov a,m ;Check ready rar jc notrdy ral ral jc notrdy lxi d,wmessg ral jc notrdyx lxi d,0 call gtindx ;Get polarity of index pulse call gtstat ani dside ;Test for double sided diskette jz dblside ixlopb call gtstat ;Wait for index pulses ani index xra b jnz regen dcx d mov a,d ora a data jnz sc1 ;Error - continue search push d ;Save pointer to last CRC byte xchg ;Flip Data address into D,E lhld secix ;Get sector pointer index mov m,e ;Store the inx h ; new sector mov m,d ; data address inx h ;Point to next address storage shld secix ;Save sector index pop d ;Restore pointer to last CRC byte inx d ;Bump to next raw data byte lxi h,secno ;Point to the sector number inr m ; and bump to next sector mov a,m ;Get this number xchg ;Flip data pointer back to HL cpi 27 ;More sectors to go ? jc sloop ;Yes - jump lhld secix ;Get sector data address index dcx h ;To last high order mov d,m dcx h ;Low order mov e,m ;Load the start address lxi h,130 ;Sector length + CRC word dad d ;Compute last address used lxi d,-nbuf ;Negative of last track buffer address dad d ;Is sector data address out of bounds ? jc terr ;Yes - jump mvi a,1 call select ;Select destination drive mvi a,10 ;Reset some counters sta trcnt ;Reset track read error counte jmp wboot ;Ignore anything else * * Step to next track * tkstep lda sdisk mov b,a lda ddisk cmp b jz samedrv mvi a,'*' call pchar call takstep lda trkreg dcr a sta trkreg samedrv xra a call select call takstep jmp dloop takstep lxi d,cmdreg mvi a,sicmd stax d wsicms ldax d rar jnc wsicms wsicmd ldax d rar jc wsicmd ret * * Re-write error, track did not verify * Bump counter, then flag permanent error * rwerr lxi h,rwcnt ;Point to Track Verify Retry counter dcr m ;Decrement it jnz rewrt ;Go re-write if not expired lxi d,vmsg ;Permanent verify error * * Permanent error common routine * No error codes determined yet * Unload head, then abort * perr call pbuff ;Print the error message call unload lda trkreg ;Get current track number mvi l,'0'-1 ;L is one less than 0 per1 inr l ;Bump digit value sui 10 ;Hit tens digit count jnc per1 ;Loop til C = ASCII tens digit adi '0'+10 ;Restore + ASCII bias for units mov h,a ;Pljnz ixlopb jmp notrdy restore lxi h,cmdreg mvi m,restor ;Home to track 0 command wrstrs mov a,m rar ;Wait for busy jnc wrstrs wrstrd mov a,m rar ;Wait for not busy jc wrstrd mov a,m ani trkzro jz notrdy ret regen call restore xra a ;Initialize track number sta tkno ;Start with track 0 mvi a,10 ;Reset read retry sta trcnt ; counter to 10 dloop xra a call select call wnbusy ;Wait until not busy lxi d,datreg ;Pointer acts as Data Register lxi h,tkbuf ;Track buffer mvi c,24 ;C is page count mvi a,rtcmd ;Setup controller sta cmdreg datin ldax d ;Load a data byte mov m,a ;Store in memory inr l ;Bump pointer / counter jnz datin ;Get next byte inr h ;Bump high order dcr c ;Hit page count jnz datin ;Loop til track read in * * Scan track for Sector Address Mark (FE Hex) * Since this value is not always read properly using the Read * Track command, this search assumes the high four bits of the * Sector Address Mark are ones. * lxr sta rwcnt ;Reset the Re-Write counter rewrt lxi h,sectb ;Point to Sector Data address table shld secix ;Initialize index value mvi a,1 ;Initialize sector number sta secno twloop call wnbusy ;Wait for Controller Ready lda secno ;Fetch sector number sta secreg ;Send to controller lhld secix ;Get sector address index mov e,m ;Load the next dma address inx h mov d,m ;High order inx h shld secix ;Save for next loop lxi h,datreg;Controller data register mvi a,wsec ;Write Sector command sta cmdreg ;Start controller mvi c,128 ;Bytes in a sector wloop ldax d ;Get source byte from memory mov m,a ;Write the data to the controller inx d ;Next data byte dcr c ;Hit data byte count jnz wloop ;Loop until data written lxi h,secno ;Point to the sector number inr m ;Increment to next mov a,m ;Load the value cpi 27 ;More sectors to write ? jc twloop ;Yes - jump * * Read the track back. Ignore the data, but verify the CRC * status from the Disk Jockey 1791. * call wnbusace units digit mov a,l ;Get the tens digit cpi '0' ;Is it an ASCII 0 ? jnz per2 ;No - use it mvi l,' ' ;Else make it a space per2 shld tdsply ;Save track number display lxi d,retmsg ;Prompt to press return jmp done ;Treat as if done * * Track read error - decrement counter and try again * terr lxi h,trcnt ;Point to the track read counter dcr m ;Have we tried too many times ? jnz dloop ;No - try again lxi d,tmessg ;Track read message jmp perr ;Continue error routine * * Wait until drive not busy * wnbusy lda cmdreg ;Wait for controller to accomplish ani 1 jnz wnbusy ;Loop until it does ret ;Return when Ready * * Wait for index hole to go by * windex call gtindx windxh call gtstat ani index xra b jz windxh windxl call gtstat ani index xra b jnz windxl ret * * Search up to (B) bytes at HL for pattern represented * by (C). Assumes upper 4 bits are 1s. Exit to TERR if * byte not found. * searc mov a,m ;Load a byte ori 0f0h ;Turn oni h,sectb ;Initialize sector data pointer table shld secix ; to first sector lxi h,tkbuf ;Initial Track buffer pointer mvi a,1 ;Initial sector number (1) sta secno ;Save sector number sloop lxi b,0feh ;Give up after 256 bytes call searc ;Search for Sector Address mark lxi d,4 ;Field byte count call setcrc ;Evaluate CRC status inx h ;Offset to track number jnz sloop ;Error - Continue Sector mark search lda tkno ;Get current track cmp m ;Compare with memory image jnz terr ;Illegal track number inx h ;Next byte must be 0 mov a,m ;Is it a zero ? ora a jnz terr ;No - jump inx h ;Sector number lda secno ;Get current sector number cmp m ;Correct sector ? jnz terr ;No - jump inx h ;Next byte mov a,m ; must also be ora a ; a zero jnz terr ;Not a zero - jump inx h ;Skip CRC word inx h sc1 lxi b,0fbh ;Search pattern and retry call searc ;Search for mark lxi d,128 ;Sector length (including Data Mark) call setcrc ;Get the CRC status inx h ;Offset pointer to y ;Wait until not busy call windex ;Wait for index hole lxi h,datreg ;Data register pointer mvi a,1 ;Initialize the rtl1 sta secreg ; sector number mvi c,128 ;Bytes in a sector mvi a,rsec ;Read Sector command sta cmdreg ;Start controller rtloop mov a,m ;Read a byte dcr c ;Done this sector ? jnz rtloop ;No - Loop until sector is read call wnbusy ;Wait until not busy lda cmdreg ;Load controller status ani 9ch ;Extract Not Ready, Not Found, ; CRC Error, Lost Data jnz rwerr ;Go re-write if error lda secreg ;Load sector register inr a ;Next sector cpi 27 ;More sectors to do ? jc rtl1 ;Yes - Loop lxi h,tkno ;Point to Track number inr m ;Bump it mov a,m ;Get next track number cpi 77 ;Is re-formatting complete ? jc tkstep ;No - do next track call unload finish lxi d,fmessg ;Send completion done call prbuff ; message to console cpi 'R' ;More Re-formatting ? jz start ;Yes - jump exit xra a call selda call restore call unload @ upper nibble mov m,a ;Save in memory cmp c ;Match ? rz ;Yes - Return inx h ;Bump data pointer dcr b ;Hit byte search count jnz searc ;Loop til search complete pop psw ;Clear stack jmp terr ;Go to error routine * * Checksum checker * Adapted from the Disk Jockey I Shugart Firmware * Performs the Cyclic Redundancy Check (CRC) * The polynomial is G(X) = X^16 + X^12 + X^5 + 1. * * Entry SETCRC - Pointer to data block in HL, * Field length (in bytes) - 1 in D,E * Verify checksum at end of block * Return with Z set if match * setcrc push h ;Save start address pointer xchg ;Flip start addr to DE dad d ;HL points to last byte xchg ;Swap back again crech lxi b,-1 ;Initial value per formula crechx push d ;Save terminating pointer mov a,m xra c mov d,a rrc rrc rrc rrc ani 0fh xra d mov e,a rrc rrc rrc mov d,a ani 1fh xra b mov c,a mov a,d ani 0e0h xra e mov b,a ;Update high order CRC word mov a,d rrc ani 0f0h xra c mov c,a ;S readdrv ;Invalid input ret * * Pbuff is the CP/M print buffer function * pbuff mvi c,9 jmp bdos pchar push h push b push d push psw mov e,a mvi c,2 call bdos pop psw pop d pop b pop h ret * * Rbuff is the CP/M read buffer function * prbuff call pbuff rbuff lxi d,inbuff mvi c,10 call bdos lda inbuff+1 ana a rz lda inbuff+2 cpi 'a' rc cpi 'z'+1 rnc sui ' ' ret inbuff db 10,10 ds 10 conin mvi c,1 call bdos ani 7fh cpi 3 jz finish ret stdvsl sta diskio+1 ret stbits sta diskio+2 ret gtstat lda diskio+2 ret unload call model mvi a,unloada jz stbits mvi a,unloadb jmp stbits * * Messages and data * prompt db acr,alf db 'Format correction program, VERS ' DB (VERNUM/10)+'0','.',(VERNUM MOD 10)+'0' DB acr,alf,'by Design Technology, San Diego, CA$' srcmsg db acr,alf db 'Select source drive A,B,C, or D (RETURN to exit): $' dstmsg db acr,alf db 'Select destination drive A,B,C or D (RETURN to exi1H͌*#~!www9v2nv2͌͠!6>@=G~xxgi^{¢ziFU͌::ʐ:A_͌->!6>@=±~xx1{gczx!6 ~~~x2> 2ͧ! >2w,$ !"! >2#5:š#~š#:š#~š###b*s#r#"!4~5*+V+^!ښ>> 22!">2ͧ:2*^#V#"!>2w !4~ڵͧͰ!>2>2~ ͧ:k:<!4~M6͠RF:G:P>*͑Z:=2Z>Y`e!5ªy͌:./, Ҁ:g}0‘. "G-!!5u:§gʳ¼~w#Ú~W_WOzGzO#z {G:Sx2:t/::G:̌O> I?p_ xyp:͌ͣ)Avv _͌ ::a{ ¼~22:p>> Format correctioave low order CRC word inx h ;Bump pointer to next data byte pop d ;Restore terminating pointer mov a,d ;Get high order cmp h ;Test for done CRECH jc crec1 ;Done - Test CRC and set flags jnz crechx ;Continue - next data byte mov a,e ;Get low order and cmp l ; test terminating pointer jnc crechx ;Loop if more bytes to scan crec1 xchg ;Swap CRC word pointer to D,E pop h ;Restore data start address pointer ldax d ;Test low order cmp c ;Clear Z flag if no match inx d ;Next byte rnz ;Done if error ldax d ;High order cmp b ;Set flags and ret ;Return * * Select selects the disk specified by drive A and * loads the head * select mov b,a ;Save in B lda cdisk ;Get currently selected disk cmp b jz loadhd mov a,b ;Recover request sta cdisk ;Update selected drive ana a lda sdisk ;Assume source lxi d,mntsrc ;Mount source message jz sselec ;Source select ? lda ddisk ;Not source, destination lxi d,mntdst ;Mount destination message st): $' mntmsg db acr,alf db 'Press RETURN to correct the format' db acr,alf,'on the above specified diskette: $' fmessg db acr,alf db 'Function Complete' db acr,alf db 'Type R to reformat another, RETURN to exit: $' wmessg db ' is Write Protected.$' rmessg db ' is Not Ready.$' amessg db acr,alf db 'Drive $' sglside db ' is not single sided.$' mntsrc db acr,alf db 'Insert source diskette, then press RETURN: $' mntdst db acr,alf db 'Insert destination diskette, then press RETURN: $' tmessg db acr,alf db 'Track read error' db acr,alf db 'Invalid CRC, Illegal Density, or' db acr,alf db 'Illegal track or sector sequence.$' retmsg db acr,alf db 'Error occured on Track: ' tdsply db ' .' db acr,alf db 'Type R to reformat another, RETURN to exit: $' vmsg db acr,alf db 'Diskette will not accept re-formatting.' db acr,alf db 'Permanent Verification Error and' db acr,alf db 'probable physical damage.$' acralf db acr,alf,'$' * * Data spacen program, VERS 1.1 by Design Technology, San Diego, CA$ Select source drive A,B,C, or D (RETURN to exit): $ Select destination drive A,B,C or D (RETURN to exit): $ Press RETURN to correct the format on the above specified diskette: $ Function Complete Type R to reformat another, RETURN to exit: $ is Write Protected.$ is Not Ready.$ Drive $ is not single sided.$ Insert source diskette, then press RETURN: $ Insert destination diskette, then press RETURN: $ Track read error Invalid CRC, Illegal Density, or Illegal track or sector sequence.$ Error occured on Track: . Type R to reformat another, RETURN to exit: $ Diskette will not accept re-formatting. Permanent Verification Error and probable physical damage.$ $selec push psw ;Save drive to select lda sdisk ;Get source drive mov b,a ;Save in B lda ddisk ;Get destination drive cmp b ;Same ? push psw cz unload pop psw push psw cz pbuff pop psw cz conin ;Print string, and read console pop psw ;Recover drive to select selda mov c,a mvi a,7fh ;Drive select bits qloop rlc ;Rotate select bits dcr c ; to proper drive position jp qloop ani 3fh call stdvsl loadhd call model lxi b,lhsdena jz selprep lxi b,lhsdenb selprep mov a,b call stbits mov a,c jmp stbits * * Get index level * gtindx call model mvi b,0 rz mvi b,index ret * * Get disk Jockey 2D model * model lda diskio-4 cpi (ret) ret * * Prompt the console for a drive, then read and verify the drive * selected * readdrv push d ;Save prompt call pbuff ;Send the prompt call rbuff ;Read the console character pop d ;Recover prompt jz exit sui 'A' ;Subtract ASCII bias jc readdrv ;Invalid input cpi 4 ;Upper limit jp * sdisk db 0ffh ddisk db 0ffh cdisk db 0ffh trcnt DS 1 ;Track read retry counter rwcnt DS 1 ;Re-write counter tkno DS 1 ;Track number secno DS 1 ;Sector number secix DS 2 ;Sector data pointer table pointer sectb ds 2*26 ;Space for sector address table ds 40 stack equ $ org (($+255)shr 8)shl 8 ;Must start on page tkbuf ds 1800H ;Lots of space for track buffer nbuf equ $-1 ;Last byte in track buffer storage area end A ***************************************************************** * * * Single Drive copy program. This program allows pip (or any * * other program) to copy or move data between diskettes by * * prompting for a disk change operation on drive A. Will allow * * back ups to be made with only one drive. * * * * Written for Thinker Toys by Bobby Dale Gifford. * * 12/17/79 * * * * The program SINGLE tricks CP/M into thinking there are * * two drives when in actuality only one drive is present in the * * system. To execute the program give the command: * * SINGLE S * * followed by a carriage return. The messge: * * SINGLE INSTALLED * * should appear, followed by the CP/M prompt. At this time, * * if an access to drive B is made, a prompt will appear * * requesting you to insert a diskette of the proper density * * into drive A. Type a return. CP/M will now access drive A * * thinking it is actually drive B. When CP/M return to drive * * A, another p * * Exit by printing an error message. No change made. * * * ***************************************************************** exit lxi d,what ;No change message exit1 call list ;Entry point for different message on exit jmp wboot ;Do a warm boot on exit ***************************************************************** * * * List a message on the CP/M console device. * * * ***************************************************************** list mvi c,9 ;Print buffer command jmp entry ;Enter CP/M ***************************************************************** * * * Insert the code for the new selection routine into the ram * * below the ccp. * * * ***************************************************************** insert lhld entry+1 ;Get pointer to base of BDOS lxi d,-(ccpsize+6+100h) dad d push h ;Save pointer to relocated single lxi d,heart ;Pointer to code to relocate lxi b,map ;Pointer to relocation map relrst byte of the jump cpi (jmp) ;Is it a jump opcode ? jnz exit1 ;Error if not inx h mov a,m ;Should point to newsel cpi newsel-heart jnz exit1 ;Error if not inx h ;Point to high byte of address mov d,m mvi e,5 ;Form address to controller page ldax d ;Get the byte of controller address mov m,a ;Reconstruct controller address dcx h mvi m,1bh ;Offset into controller rom to drive select lxi d,remmsg jmp exit1 ***************************************************************** * * * Unknown command error message. * * * ***************************************************************** what db acr,alf db 'Unknown command - NO change made.$' ***************************************************************** * * * Successful insertion message. * * * ***************************************************************** insmsg db acr,alf db 'Single installed.$' ***************************************************************** rompt will be given to you requesting that you * * reinsert the original drive A diskette. This procedure will * * continue until the command: * * SINGLE E * * is given followed by a carriage return. A message should * * appear saying: * * SINGLE REMOVED * * followed by the CP/M prompt. * * The program is intended to allow backing up diskettes * * for those users with only one drive. To back up a diskette * * follow these these procedures. * * * * 1) Execute SINGLE S. * * 2) Use PIP to copy all or a selected group of files * * (actually any program should run). * * 3) Follow the prompts for inserting diskettes ( Suggest * * you write protect the original diskette (Tab OFF)). * * 5) When the CP/M prompt reappears, ececute SINGLE E. * * * ***************************************************************** title '*** Single Drive Utility For CP/M Ver 2.2 ***' acr equ 0ah ;Carriage return alf equ 0dh ;Line feed wboot equ 0 ;CP/Mo ldax b ;Get a relocation byte ana a ;Test if byte needs relocated jm putjmp ;If minus then all done mov m,h ;Assume relocation jnz incre ;Move this byte directly ldax d mov m,a incre inx h ;Bump relocation address inx d ;Bump source inx b ;Bump relocation map jmp relo putjmp lhld wboot+1 ;Get pointer to CBIOS lxi d,seljmp ;Offset to drive select jump dad d ;Form pointer to drive select jump lxi d,badmsg ;Message pointer mov a,m ;Get the jump opcode cpi (jmp) ;Is it a jump instruction ? jnz exit1 ;Exit if not a jump inx h mov a,m ;Get first byte of jump address cpi 1bh ;Is it a jump with correct offset ? jnz exit1 inx h ;Get page address of controller mov a,m pop h ;Restore pointer to relocated code push h push psw ;Save page address of controller inx h lda entry+1 mov m,a ;Insert first byte of new bdos location inx h lda entry+2 mov m,a ;Insert second byte of new bdos location xra a sta entry+1 ;Modify entry to jump to * * * Seccessful removal message. * * * ***************************************************************** remmsg db acr,alf db 'Single removed.$' ***************************************************************** * * * Bad Cbios format message. * * * ***************************************************************** badmsg db acr,alf db 'Bad Cbios format found - NO change made.$' ***************************************************************** * * * Byte for byte map of code to relocate. A zero represents no * * relocation, a 1 represents a relocateable byte, and a 0ff * * represents the end of the map. * * * ***************************************************************** map db 0,0,0 ;jmp db 0,0,0 ;jmp db 0,0,0 ;jmp db 0,0,0 ;jmp db 0,0,0 ;jmp db 0,0,0 ;jmp db 0,0,1 ;lxi db 0,0,0 ;shld db 0,0 ;mvi db 0 ;mov db 0,0,1 ;sta db 0 ;cmp db 0 ;rz db 0,0,1 ;lxi db 0 ;ana db 0,0,1 ;jz  warm boot tpa equ 100h ;CP/M transient program area tbuff equ 80h ;Command line buffer ccpsize equ 800h ;Size of CP/M ccp aspc equ ' ' ;Space entry equ 5 ;CP/M BDOS entry location seljmp equ 30h ;Offset to jump to select drive ***************************************************************** * * * Main reconfiguration program. * * * ***************************************************************** org tpa start lda tbuff ;Check if any command given mov b,a ;Put counter in B lxi h,tbuff+1 ;Beginning of command line loop dcr b ;Check for end of command line jm exit ;If minus then error exit without change mov a,m ;Get charactor typed on command line inx h ;Bump scanning pointer cpi aspc ;Skip spaces jz loop ;Continue if space cpi 'S' ;Check for "Start" command jz insert ;Insert the code if true cpi 'E' ;Check for "End" command jz remove ;Remove the code if true ***************************************************************** * relocated code mov a,h sta entry+2 pop psw ;Restore controller page address lxi d,3 dad d mov m,a ;Form second jump (home) dad d mov m,a ;Form third jump (seek) dad d mov m,a ;Form fourth jump (status) lda wboot+2 ;Get page address of CBIOS dad d mov m,a ;Form fifth jump (oldinp) dad d mov m,a ;Form sixth jump (oldout) lhld wboot+1 ;Get pointer to CBIOS lxi d,seljmp+1 ;Offset to select drive jump dad d pop d ;Restore pointer to relocated code xchg lxi b,newsel-heart dad b xchg mov m,e inx h mov m,d lxi d,insmsg jmp list ***************************************************************** * * * Remove does the opposite of insert. It modifies the address * * to be in the original state. * * * ***************************************************************** remove lhld wboot+1 ;Pointer to CBIOS lxi d,seljmp ;Offset to select drive dad d ;Form offset to select drive lxi d,badmsg ;Assume error mov a,m ;Get the fiBdb 0,0,1 ;lxi db 0,0,1 ;call db 0,0,1 ;call db 0,0,1 ;lxi db 0,0,1 ;call db 0,0,1 ;call db 0 ;push db 0,0,1 ;call db 0 ;pop db 0,0,1 ;lda db 0 ;ana db 0,0,1 ;lxi db 0,0,1 ;jz db 0,0,1 ;lxi db 0 ;mov db 0,0,1 ;lda db 0 ;ana db 0,0 ;mvi db 0,0,1 ;jz db 0,0 ;mvi db 0,0,1 ;jmp db 0 ;mov db 0 ;mov db 0 ;ana db 0 ;rz db 0 ;inx db 0 ;push db 0,0,1 ;call db 0 ;pop db 0,0,1 ;jmp db 0,0,0,0,0 db 0,0,0,0,0 db 0,0,0,0,0 db 0,0,0,0,0 db 0,0,0,0,0 db 0,0,0,0,0 db 0,0,0,0,0 db 0,0,0,0,0 db 0,0,0,0,0 db 0,0,0,0,0 db 0,0,0,0,0 db 0ffh ds 100h-($ mod 100h) ***************************************************************** * * * The rest of the program is relocated to execute with the * * current CP/M being executed under. * * * ***************************************************************** heart equ $ ;Beginning of code to relocate diff set tpa-$ oldbdos jmp 0 ;New jump to bd*********************************************** insamsg db acr,alf,acr,alf db 'Insert "A" (return) : ' db 0 insbmsg db acr,alf db 'Insert "B" (return) : ' db 0 crlf db acr,alf,0 end 3 Copyright (c) 1979, Digital Research????????????CON:RDR:PUN:LST:DEV:VAL:USR:DSK:TTY:CRT:BAT:UC1:TTY:PTR:UR1:UR2:TTY:PTP:UP1:UP2:TTY:CRT:LPT:UL1:R/OR/WSYSDIRR/O R/W SYS DIR ** Aborted **Active User :Active Files: Drive Characteristics65536: 128 Byte Record CapacityKilobyte Drive Capacity32 Byte Directory EntriesChecked Directory EntriesRecords/ ExtentRecords/ BlockSectors/ TrackReserved Tracks is Temp R/O Disk: d:=R/OSet Indicator: d:filename.typ $R/O $R/W $SYS $DIRDisk Status : DSK: d:DSK:User Status : USR:Iobyte Assign: =Bad DelimiterInvalid AssignmentBad Delimiter: Bytes Remaining On R/, Space: Invalid File Indicator** Too Many Files **File Not Found Size Recs Bytes Ext Acc65536 set to R/O Invalid Disk AssignmentWrong CP/M Version (Requires 2.0)!9"2!T OË!]6:\:] Hr3 Ë:\ʀË͇ /ҋͺ *2!"q*"&L ͐ ͐ ͐!$p+q*#~*#N͐*##"#÷!&p+q͠*%DMͱ O O!(q*(&os home jmp 09h ;Controller track 0 seek seek jmp 0ch ;Controller seek routine status jmp 27h ;Controller status routine oldinp jmp 09h ;Jump installed oldout jmp 0ch ;Jump installed newsel lxi h,oldbdos+diff ;Insert new bdos jump in case of warm boot shld entry+1 mvi b,0 ;Get last selected drive olddrv equ $-1 mov a,c ;Put new drive into A sta olddrv+diff ;Update last selected drive cmp b ;Check if same drive rz ;Done if same lxi h,insamsg+diff ;Insert A message ana a ;Test for drive A jz next+diff ;Take jump if selecting A lxi h,insbmsg+diff ;Else get insert B message next call mesg+diff ;Print message call oldinp+diff ;Get response lxi h,crlf+diff ;Echo carriage return and line feed call mesg+diff call status+diff ;Get status of currently selected drive push b ;Save track call home+diff ;Home drive pop b ;Restore track lda olddrv+diff ;Get drive to select ana a ;Test for drive A lxi h,trkb+diff ;Point to place to save track for B jz next0+di:G!~# S*Eʟ% *: ItCw#8*0~#~#~#:w#:w2|2www:ww*1 s#r%*0~#~#Vw+6 Unknown command - NO change made.$ Single installed.$ Single removed.$ Bad Cbios format found - NO change made.$NO change made.$ Single installed.$ S ' !"y2!g*!Z !Z :!VK!Qq:Ny#Z Insert "A" (return) : Insert "B" (return) : L!*p+q*)O2'!,p+q*+O2'O2'O!.p+q*-LRRLR\LR" O!/q*/& L!1p+q*0#L~*##N!ͽ͞"T!Vq*VMͳ!Xp+q!W* >Wr#MͲ!_p+q!`6>!`6*`&*^*`&Y />!`4 >*]& ~ O!]49!a6:a*]& ~2bO>z*bM >!b/~,H~:H~*H~.H~>H~<H~=H*]& 6!]4T!]4!cq*a&Y :cw!a4!gr+s+p+q!h6>fr*d*f!is*d́"dPY! "f>!h#~Haͫo!h6:i0O͐!mr+s+p+q*lTZs#r*lڶ*l+s#r*jN#F+q#pÌ!nq!"o"q}2uo&"s* s:n*sDM2u:uqos*s"s*o͊O !v6>!vQ*v&w 6`i+46)A*:'ʓ:'O!) ~2vʍ:vO!w 6,]!v6>!v*v&w ~һ*vM !v4˜8AO͐:͐ͱ*##N!ͽ"* N#F*͠"ff ;Take jump if selecting drive A lxi h,trka+diff ;Place to save track for A next0 mov m,c ;Save track number lda olddrv+diff ;Get drive to select ana a ;Test for drive A trka equ $+1 ;Storage for track on drive A mvi c,0 ;Pick up track for A jz seek+diff ;If selecting A then take the jump trkb equ $+1 ;Pick up track for drive B mvi c,0 jmp seek+diff ;Seek to proper track ***************************************************************** * * * Mesg prints a message on the console. * * * ***************************************************************** mesg mov c,m ;Get char to print mov a,c ;Put copy into A ana a ;Test for end rz ;Return if done inx h ;Bump pointer to message push h ;Save pointer call oldout+diff ;Print the char pop h ;Restore the pointer jmp mesg+diff ;Continue printing ***************************************************************** * * * Messages output by the program. * * * ******************C>!H% - *DM ͱͷDM  ͱ* N#F 9ͱ * ^#V))DM Tͱ* ~ *} *M!+s#r#4 !s+p+q!6!66:!ڄ !6!6>!r *&**&Y i !6!4+4A :} :!4- >!699 2¨ :!4: :2!6+6>! :O!9 DMi ͱ:!O!Y DMi :2:2͠!4 F :® )!6>!ګ ͠:O!9 DMi 8ͱ!6> !ڤ Å :2k ä  ͐:!O!Y DMi w !4C F :¿ >F : F :=229:Y= ;>9*&Y DM =2 I>!6:=28 :2:2 :!!29:Y T >:Y,e \>Ì !p+q*~:ʉ *N͐*#"o :͐!p+q!'"!6> **{2*́"PY! ">!+~H !6:0O͐à k͐1 alloc hd,%dn,161,0 dn set dn+1 endif if m20 ne 0 alloc hd,%dn,252,0 dn set dn+1 alloc hd,%dn,252,0 dn set dn+1 alloc hd,%dn,129,0 dn set dn+1 endif endm endif endif if maxfd ne 0 dn set 0 rept maxfd alloc fd,%dn,75,64 dn set dn+1 endm endif if maxdm ne 0 dn set 0 rept maxdm alloc dm,%dn,75,64 dn set dn+1 endm endif if maxmf ne 0 dn set 0 rept maxmf alloc mf,%dn,22,16 dn set dn+1 endm endif if maxmw ne 0 if mwpart ne 0 ;Use non-standard partitioning dn set 0 rept maxmw*mwlog alv set ((mwbls/mwlog)/8)+1 alloc mw,%dn,%alv,0 dn set dn+1 endm else ;Use standard partitioning dn set 0 rept maxmw blocks set mwbls rept mwbls/2048 ;Generate some 8 megabyte ALV's alloc mw,%dn,257,0 blocks set blocks-2048 dn set dn+1 endm if blocks gt 256 ;If there is any stuff left, then use it alv set (blocks/8)+1 alloc mw,%dn,%alv,0 dn set dn+1 endif endm endif endif end ͠Q" 8AO͐jͱͷDM͏ m  Z"l"!6>ʥ *}҆ *M ͱ*}x O͐} W͐ͱ !+s#r!+s#r#4D ͠:\ʹ :\=Oͳͩ !6!)6l :) :)=2) :] & !"}2\!h6?!j6?\:'C:'ƀo&")!)6!"):)/)HҘ]!)6> !)ڎ*)&*)*)&*) y!)6 Ä:) 2):)<2)M*)#")/:)ҩ*)+")`*")#"]!*)!/H!")!"]*)) *)s#r!)6> !).*)&*)*)&*) w:)<2)*)) >w#6*)) w#6*)!) w#6*)%) w#6*)) N#F*)) q#p*)%) *) ~e *) * ~o&͞ *)%) q#p!)6* >!)6!)6>!)=:)!)w=*)&*)~2):)*)& *):)2):):*)!) *)) s, >X\:)“>!d!")>!)d!")!")*++!)a*)) ^#V")]*)")*)) ^#V")]!)6> !)T*)&*)~2)*)&*)~2)O;*)) ^#V" copyright(c) 1977, digital research $Error On Line $SUBNo 'SUB' File Present$Disk Write Error$Command Buffer Overflow$Command Too Long$Parameter Error$Invalid Control Character$Directory Full$Cannot Close, Read/Only?$!9"!͇͊!p+q* ͊!p+q*͍2!p+q*͍2!p+q*͊!p+q*͍!p+q*͍!p+q*͍2!s+p+q+p+q:=2ʦ** w*#"*#"!p+q(+*DM*p*& 6:ep\:=ͧ!t6>!t%\= >!t6:t<2t=O! ~2u b:<2O>9b!60+~9b!60+4:uat:u_2u:uMʉSͧ!v6!"v!|6:|Ҁ!x6 2}:} Hk:} h:}$6 2}$*}M3:}02}O> ͧ3!z6ͭ:}"!}5́ͭ́3*yM"h:}^a a2}O>Vͧ^:}>*z& ~ !z4í!{q*v#"v͙dͧ*vv :{w:x<2xO>}|ͧnPermanent error, Type return to ignoreFunction completeInvalid drive (Use A through P)No such fileSource file incompleteCan not generate systems on 5/14 in single density.ination drive name (Or return to warm boot)Destination on , then type returnPermanent error, Type return to ignoreFunction completenvalid drive (Use ?)*)) *)) N#Fq#p*)) *)s#r*)#")!)6 J:)!)J!)6 :)<2)*)")҈q:tw͠ͱ!"))ҍ*)) ^#V")]͠.*)DM\ -°!\6:\ͣ:ͱ*}DM'ͫ*)%) N#F'ͫ*)!) N#F'k͐ͫ*)) N#FͫR͐/͐ *) ~IO͐NW͐ͫ8AO͐:͐ *) ~2)t(͐:)҃)͐*)#")Ã& \!"))\Ұ*)")]͠*)M! ^#V *) >*) w *) >*) w *) >*) w *) >*) w.*)DM\ -+!\6uͱ:)O! DMͱ*)#")Ù*))))))"):m w>.Yn -:YS:Z Hҧ!6> 2)½>!)6> !)*)&*)>2) :) .͐*)M͐:)<2)99:Y=/9&ͩ c,Hͩ 9 EHͺ i`N#Fog_og_ogDM!>))덑o|gҘ =†DM!>))ҭ =¥~ ³^#V) ½^#V|g}o _{ozgi`N#Fogo&og_{_z#W-!6]:ͧz2~e:~2O! 6*~& 6$>!~_z*~& w!~5Bx:yͧ*v+"vv ~_{ozg001 $$$$ SUBDÉ Extended Submit Vers 2.0, Copyright (c) 1979, Digital Research Extended Submit Already Present$Requires CP/M Version 2.0 or later$:ʜ F  Ұ f!~=ŐW!x ~#bx {~#o}o.6::!"*"!E""1 5!"!E"* (xsub active)$|y ʍ"*`is<̓ :=2s!^#6 #6 #6$ ~O #w# !6:=2s$$$ SUB * !"!4*DM͂e/7 ͫ*"!4 :1 :<2!":ʚ ͂e!:q2q:2e:ր2O:2ä H$! A "!$""urnPermanent error, Type return to ignoreFunction completeInvalid drive (Use A through P)No such fileSource file incompleteCan not generate systems on 5/14 in single density.?, in Ok Break!9~#b  T N#F#`izv C T  *|<ʗ :  D=96543>7@?2C: * "   *" 2 2 |< "  * Ì]z))DEc9@gQC}DE CsD +"]D  $ |D}DDD<|""XL{LL{PtM=$$YXTZZSR\SZeXY{TzTSYHIyII|(*g(678&+7y8919JHFIHH"+IFFz)) *m*zQ}QQU@VXVaQdQgQ;LM$Xq"9BLdhiUTϫNBTSLOSONԚLEAҒINSNDBV+V,V-O HRAL̶OMMOθHAIιELETŪATI͆EFSTҭEFINԮEFSNǯEFDB̰EƘLSŢNāRASŦDIԧRROҨRRX O/QO҂IELILERIOTωO TωOSUEEXNPUԅƋNSTNNMNKEYILPRINԞLISԟPOEԈINűOASEISԓO O0EEFTO1ERGOKI2KS3KD4IDEXԃUL̖AMEהOPEοUԝΕCTPTIOκRINԑUOKřOEEETURΎEAćUΊESTORŌE͏ESUMũSEIGHTNENUͬESEANDOMIZŻTOАWAХAVPCTEGQI TRTRINGPACEYSTEͽHEROΣROFƤABA SINSAARPTIDTȡAIԗHILŴENĵRITŷO۾yy||PF<2(z{ *z);*)&,,d-D.s)%%'i')1+%+Q+3)NEXT without FORSyntax errorRETURN without GOSUBOut of DATAIllegal functC{K2* " * |< " " * |! 4 4 5wY2B!{DP 2R U >(_#U * ~?o !P #GC!BʻY|<1>DA2MSB!E :* > @(K 2 Ç 2 *  C " :b ʢ >(Kڢ <=ʢ (ͬ~ ̾(" ҊSe]" ;5$ܢ"ʇ: \*v " * ͶB" t##s#r## w# y}ͯ!6"*" 7C*"* "â *bk~####~ ҷ ڷù#s#rïC *DM~#+##~#foC`i~#fo??2i 2h ;#~=!@}O|G!""y O:h ~ʂ#Y:aJg>2h 2i U%~|*O~#Ym?>HjZEڗ;;>ʸ;>HOZ#þGO TOUBZ!AO ^#V#ZOd#<y(!!!Z.!>dG>Y2i Y%=+ZOiMk֢ύ>2i W„Y>5W>Y{~.ʧ:"0":i ~O.O>Y(ͬ}Y|Y%~.ͬ:g * |>}e. BCOPYRIGHT (C) 1978, DIGITAL RESEARCH   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOP~# |o&)))))))a{__> ͞> Þͤ~͞#ó*>z:O!$'*!ͳ0|- ^#V">#2=+?~(?>2=>(2)>2(w ~#f>P2)>2(Pz@zw>2)@zPͿ:=ʛŽ:2\ ! ">2!4:(AN>2:)!4 !^!*FNyͅ*DM2: !ͳ͐ 0ͤú<2:ʺ!":=>!">62)@Ϳæ1!Cͳ:] ʠ\ K> Yi>: y +=2i ZY#ZEo:ҋ0o.o%~ Ҡ ʠ ʠ> :i <ʩ=m+~ ʬ ʬ ʬ#>d2 ͋9C" :g ͬ! (" !9T  +V+^##* C" B* *Cd Nz)~S ͒(q)ʹ(QZ~>r)ʹ(E(OdG+ $* "* 3àE3\B" !9" ~: #~#ʅ #^#V": >[@1>]@ցLO! N#F#~: ҆ ځ#:l `#2l f>R~#"j &o"n >2m !~##"j +fC͎*j <2m n G("j ! 0?<=:l ҫ ګ*n ¨###^#V,:m 2g *n " *p " !n (E AOGEAGx3Ø(:l  *j #*C > 2 ,$`i P "  "!>:yHG+ȸ#"* u )4} )H>2  N#fi-++<(aZz)}/o|/g" :g q7xz)z ,{ʨ+F•{o|P {o|<«{o|2¸{/o|/}//o|//}o|g,::e 2 ͋9:g " " ͬB!9(:g * ~)C,* C,Á2N 2g !9(!9.,:g G:N Od}!P O:* * C)>" : OBO/2 OÐ9~ #~#`J x 2b b + C,u W : u 2_H 2u 2_H 2H /<z)zu 2 2 C,u Y +{>2e]!"N#F#xʇ TFQBN#F#Cچ " 1~ > @ !b !BÑ ~ͥB# b 2 e] #~  xE(!N(E(y! y )#x+y+z+{z|O(@)}P(! ( E(!N(E(O! y#)+f)I)N(d* )(! 6(&,)Ü)y%: 2 : B*: ½)))|/g}/o)! : )B*" >2g )aj)d* ʹ(6*x(! F#&* 6*|UY(d *!" " >>)d GOW_ʹ((gf*>b&|5&N&z< dE(*t(̀*k(dҦ* )! ~: ~B*6{y%! ~*O+~+¶*!*) *yʹ((+6+q*: O! >%-,2 Ñ,! ~5#*!x"+>);)+ ;=+|G+y4+|Gz)*͙(,N0|)+DM!>)ډ+)q+ ډ+=c+|+x+ʚ+*͙(*'x)*t(| ++DM!>+ +7>{_zW}o|g=+w+|G+|)Ooyg)* +|6*Y(ͨ+g{o)+! ~w! ~G+N (R,/<#Fwx+ B,F+N9(! G>w2 ! %-x,: 2 ,,4ʈ0Q-,>,! -G: º,! Vwz# Ÿ,x’,%! Y-,x,! w%: ,! ~++w! 4#,4ʈ0+60 ! ->! <֌W-͋9C" :g G:g x=ͬ:g  H * #^#V*Cs* C{! C{>HͣFH(µC(zʢPY" : {:_ u ~GC+K x),  <2~(z˜<* * "~ #####u   =>C,* =( |" 2 " â ~,dC+͆(~ʕ *n €€l>2á Q+!B>ee,%;d)1F6 * 4TF* ::G<:?=:G<:e ?=!B&Gá(* TF~\:I:G<:\V:G:e \!B\/V tz|TF›:::o<ʛ& ,C)+(* TF~:::e /<!B{= @è2go"C#ʧQHLo͋9;*0KDF>-?Redo from start #~ "4N: !!#G* Q!a ;#YHL">2>2 F~,2 ÓC;&G: ʫ>?@> @0KDů2 6,+>2 ͉:~+[(# "4([])! _!A!_.!!!/!: -!<-!> >2 { =! ! <~J!#~#X! k*l!~#>l!+!:G@ #T]~u!#y!~v!ʏ!y_¢!: >2 ÷![®!2 !: >2 !> XG{!~#_XG!!2 E0:?+͎ " o6 r6*n )1:l O " H*">&{:m ;"!;"#~ ̾(~#m":m A" ^".h"Dh"EA"A"{v"*j 5$Ҕ"T]C!E #G!* C¦"`i" "\]~"\]C,u "z)d: E()È% PX/#,#BK/#C,/#C,( z`iC[# !C^#Vzn#~#+K#͑#^#Vzʌ##s#r u# 2 *+#~##^#Vʚ#O: y$#¦#¦#3z##£#3 > %$B!$#G11+ã#Undefined line #3###N#F>!#*j +p+q+w: Ò#CBCACSCE: * * C ~0  2 <2 ~̓$#y$\Aʔ$z)ð$!$#G KD#~.~•$z)"j87Random number seed (-32768 to 32767)$*" +%%$ 2 -# -~/w! Oyw#-q<-NsY+1-'- W~w+F-?-! C-~w# [-E(: %'͝.qʙ-G,Q-x ‚-y-Ñ,! --Ñ-L} : A--! (d-: -2 !t(. ! (.&, ! (>.".&,! 3.=-..! 5%! >5=.>! N#F#=(.>! p+q+=9.: ʔ0: %'44ʈ0͝.!7 qA>,?t.>,: <=,! [-!0 Y-xb.! 5b.%y2 +6 ~q+¨.(+~ڈ0w&,4È0%3*j%>2 `h)~&i-.+.+/.ʆ/e /E5/l#/L#/q#/Q4/:g N/>N/~%ʓ/#ʤ/!ʥ/dN/De/ͮ/2S0e/_{_//i/k(d!W')d e/ܮ/.!W'!z)e/ͮ/e/) *d.(.=d^'- ̓$> ̓$!  101(d0! 1(* |* "1C, ~,B>2 d: =Bd̨H+~,ʿ+N6,E* 2 QC,͋9~,c: 2 TF—Qd¢WG"ʌ: Wʉ:,+FO: y!...+ʽ,G+M: C#~# #^#V" cCC(+B͓2 " * ~" ڎ_4:g {[H !xVzʬQںzʺ! :g  N#F#N#F! N#F#N#FKG* W " Ð)͙(6Çz)uÇxdd!BdX* \FÇy2h :g g+Wx(zOxdz o! N#F* *(" " ͩ( *!:h og~#fox(2g 6" ;)!A͙(*ʹ(" " i*͙(*g' .EJ ]<=ʓ<"FO&i:* ,C(#r PQ͉:C)|)IoBI'UTC)}* k(͋9" d(~a{_&([OʭH¬#~[Eҗ:0ÞG7))))o~ +8  )))0O í)#~ց(7>OyC,;*%#~#Y #^#V" y~.%$$$$$%** "͋9+%c%C,+8%": 2 2 ! 6ͷ(È%ͷ(t(x: ʩ(Ң%/<͙(ͩ((gb&|! %B&#ʈ0.͉&#&G~_#~W#~ON&hcGy&JTeox%2 |&y%O&)zWyO%x\E#&! w%%x! 5&F#~怩Oé( 4Ç0~_#~W#~O! ~/woG}_}W}Oq&CZQd& oz…&y-O{&Ë&-yOzW{_xGÅ&$cCu͍M r5E(&1r'ʹ(>2 ͙(!&ͧ7͙(ͩ(!&ͧ7i'͙(T(È%E(.(y2<'"7'PX!%!%'! ~#Y'Wy='O|g}oxGQ'x Gz/'CZQO͙(!-ͦ(E(ʐ0.(4g04g0+~2'+~2'+~2'AOW_2'}o|gxG>?ұ'2'7y<=':'x'> $&{_zWyO)xG:'2'y”'! 5”'%>.! N#G.x'(}! Gx&(ƀwW'(w+E(/%g0ʹ(xڀ0G͈%! 4À0: : /<! Op#6%͆(d+ ! ~w͆(og)d E(* ||O(* * ͷ(" `i" ! ^#V#N#F# (:g Gw#(! ~7w?##wy7O! ((! ( dF !@ #G"G)Ͳ1F1Ͳ1416+͆(F16-k(#60: W:g 22һ1ͺ5! F : _ 1x*1{1Aqʟ1Eʟ1Dʟ101,1.¢1+60{ʫ1+6${+p2 ! 6 ͙(* * 2 f2E~2:101 #~1>DG1" `i" #~+N2-%20OxGN2#~ 2`xEC2y 1>2 S2|1;21" `i" ͩ(#W\4: 2Ë22ҏ2460̾("5+~0ʞ2.ľ(2d>"w#6+26-/</ 2:#p#w#6! #zQ334z4ͺ5{(=4b13p#6! #: ~ 3* 3+3-+$0I3#I3++w?3 3I36%3m36C){3)1+6%)d3E(\43_x44"5452_y/3/3{_x34434y5O4GO"53* =4P2*ѯ3E(7\4y/OzWO/4)4/<!@1> @!b  ~#=GA"=[0A= A=_zW"=! =L=ʺ>O>>ʨ=1g= !>=#ʻ=>>= >>(9>ʵ=6>>@!B<~ͥB#¨=!>7A_>~=ͥB܁>=#~== !B<~>\ͥB~>ͥB́>=>\@~A +> +>+> +>>@ >wͥB# >6Hͨ=Aq>s> >s> ʑ>ʑ> ʑ> >>_‘>>_ʙ>ͥB+>> ~7W'#~+w#Ã>yڡ>>@>> o&DM#͹BwͥB#Þ>x+>ͥB>x+~ͥB> !Bz\@@_W@W~#!ʎ@#ʡ?&ʉ@g@+>H?+~#.?_}@\&???$ʚ?*??x#ڒ?~$> ž?#W?~#.?#ʡ?,?z@Wá?~#>.??# ?~##??T]^###xG#z+@x@~-@@>Wr@Cxz*1#G+7N@2 ;K@, ~#_~#foxE?m@@@?!BͫH@~#@_@Ò@>@r@;** AxxOI&G* 5@G> 5@@@z>+@TFfV:\A@:@27A C(u C,C)d$Ix 'IH0Ix > {͹FGH* w#?IHIO>~XIxIx C,;*C,* C)ͥHW'ͫHG=O>x~#F#fh GN#^#VUJ LJ#7Jѯx<#4JIJC(͋9;*#^#V* CڍJ*CҍJͣF(C,u ~JͥHG!W'y~?@> @(KͿAzK68Kp22 ͿAoK!B!=:>\2UK'K@+iK~@K+@K@!B!b 2OAK:ʐK>\@2yKCD7 ;L K ´K(KKCD(KK0K@> @>bKK>#iKK6!B!b K KxL*|>L!b ("_yq#@ K2e > @ͿA,L KzK: Bw!a >2 ;2 " $L33oL " ** áL LL" *" ##^#V#~#fo"͆(ʵLA3à* "à!9~#L L~#foC L >2 ͋9d 6.#605#H56." #H 6,#dq5(! 6(&,*6> 5/>,K5>,p#=B5! ͦ(~5y%>B*ͩ(_6?5ʹ(/{_#zW#yO++Ғ5B&#ͩ(p#ڄ5>5e6>5N#F#* /}o|g5" p#=55w1_cƤ~@zZrN vH Tʚ;@B''d G" կʎ6))))Ÿ6y=ʟ6ʫ60:ڨ6 ʸ6ʊ6È6!t(͙(! 6ͦ(6)!r%>2 E(x+76ʗ0%yʹ(7: 77͍*)|" " ܻ6t(ͽ&'8;': `7hr7͙(͍*Ɓc7ͅ%!{7ͧ7J'͙(: o7%~0é(|Yt&wz^Pc|u~r1͙(+ʹ('͙(~#ͦ(='ͷ(͈%ð7RO!&ͦ(76*E(!H8>8!i8ͦ(!H8Ȇw#O ͷ(':G8<2G8!i8O |%ʹ({YOO6+F6!F84~֫58w %!i8(w+w+w85Jʙ9v" GSљ e͘w>ROhFhiuh!8|%: w: 82 t("~'͙(͍*ͅ%)8͈%͈%E(t(͈%t(: 82 !9͘7: 2 "~A> @:A 3A6A:<:-A!MA6A<2Oɯ2:> 7A> 7A2:XG{A:e ʍA=2e >îA A> @:e €A ڮA:G:e ʥA!BʮA<2e OTFAWMS: 0P:A!7C!E #G:AD/2AD:e !B6!a > @> @TF3B:?B2ɯ2e :=@FBAA2CDD͙BƒBʌBAͷF_H!D " >2g :2@ > @+B> BC~ +üB*v  >ƕo>gB9*++"  BgGBB* C:G!^#V#C T*}D2 2 2 w#w#" *+" : XC2 2 ! 6#QC7!i8(!F8w#w#w2 og" " *v : ƒC" C* " " : T*++" ##!z "x r%DAgo" 2 "N " " 2 * |}~C##~:  *C(`i+" < D T" !z "x !*}<-D" * " 2DAB!J b Æ >OD22>^@@@!B* | * "u <2>2 ͋9! (* dC,͋9Gd * CD( (>2 ͋9D2 `i D * CD `i" ~,D(""  B!9 +" _MC(͋9s#r#~,=M #MC)" >!=_M=_M=_M!9DM!jM* * * à2 2 ~‡M2 #+͔R!" +NC,,ʸM"" +NC,MCACLCLNOC, 2 5$`i" NT]" CNO**+#~#N#^#V"N:N2 ͉:ʢNxG͒;>2 hN~(nNþN~(͉:zNxGN::g W):zBK!N N 2 ~(nN ͖N+"N(NC)"NC,BN"* * C#ON##~w#͚< NO* " N* C Oy_xW `i" * CNO##~w#͚2 : mS:2ùR2 2 * DM* " * #* " CNP `i" * *+zʠ `ià Q+PdP)1F* #^#V ªPr+s+5&G+P;ʿPC,+>,@ÇP>"@&G>"@íP*|Q~Q\}o|gQ> @+|Ie&X4#]I͙(8͙(ͩ(y8g'E(6t(: N9QYi'!%!X9͘7!8 J;xn{/|t1}=Z}~L~l+C,}92f NE G2#~.9ʵ9:ү90ҵ9E9G#~:90Ҽ9EҼ9.ʼ9x' 2~&9 :%$!#y_! V+z2g : =ʒ;):~(;3;2 : 2 }:*  " c:o[::g [::&* C;^#~#¸;:g ¸;~;#^^#V#˜;:f DMW']< #:¹;#ʾ;+͸<þ;:g w#_ʖ*x " >2g ( C"x ~ #FͨH͹( @ +B-G* * /O #CZG" # >G*v " !* !z *x CxGH!L " * " * * CʹG~###͚<²GH_ÕG* ^#Vz* G" ##^#V#" ÕG* C7H~###͚>>ͬ͹F* (H>>>ͥH<2g #~#fo(d ,»QZûQ Q͋9;*W_Wڬ Q¾Q"QG{,xQPXW1R!b Oz"yR QR RO{,yĊRW1R R{ +R,> +R+R1R1R͊RWQ"hV* *CMS~#hVSV:SS=S~,~#u SůSѯ*Qʦ   ! ~#fo" !"o]| G~,r CACS͋9;*O*o] "o]* Cڸ q#s#r9T7͋9;*ͥHF~O#^#VT*CT* CTY* * CUy2!^" :^^<2^!~" ^F#~+w##D^+6" !^/x^+6"" #/x^i^^6ZS^Mʐ^F C:dʯ^z{2ô^"v +^C/}^C:d" ô^+*v +"v +:!]"2<s#r# *  DM=^#"" {ozgB|g}o_|0_!{ozgB"v "" " *B}o|g++!_#G1!_#G!#G" !B! v] Owned by Microsoft Bytes freeBASIC-80 Rev. 5.21 [CP/M Version] Copyright 1977-1981 (C) by Microsoft Created: 28-Jul-81 U>  U!Ux͹FFTC$C(u ~,KU*Qʠ "QC)}͹FʅU͙BlUA~Uw# ^UF* DWڬ qU6Qʦ ʠ !' ~U U#~¸U`i}WÙU>O #~(PY!' ůwͱW:!͞Zʻ =ʝ =UѯÚ <ʻ !% ^#Vr+s9Q6V PY,V!#V`i>yV!' ~UͱW)9V6Qʦ !&QV! ~+n6Qʦ ! ~*~Ee\DM'~U4N#V pʝVzw w+s#r#6#6DM:V!" s#r#6 W! {zVWw<W<ʻ !! {w:W}W!! ~!) ;WU;W~#>W*~ʖ\( ~hW+~#5O ~+~tWzWJW7>*T]% N#F+q#p###6 ’WͱW: ͞Z>ªW>w+w!(HW7?*' 6#67ͥH~ʲ #^#fk_XN#~:X++@bXy@bXbX #RX~.0X>X7X#X2 z bXbX> >X7X> WX7Xò W<ʣ ! w#…XCACSW:!<¾ ͥH~ʠ #N#F OXIXR  C,#u C,{ʦ _9Q¯ WzZ" 1Y{1Y!~ 1Y6B#6A#6Sz"# w# >YwwͱWoY<ʻ ÅY<…Y£ cY!%w#w#w#w~ʨYCzW* ) p# ®YC T T _W<Yʣ Z!6# ͖ZW2 !͒Z!͒Zʣ O!  ~#@ygZ~ dZ>.@ QZ:e W:ڀZ> @@!BAZ~*6?# –ZO!!4¶Z#4¶Z#4y"Zʻ ><+Z* C! s#r#wZ2u]*Q  ! ^#V~,+ zʵ +s#r! w#w! ~#fo!CT[Ò[BK>!)g[)#h[))v[ u[#=][}_}la)ҍ[#x"o]! "q]!) "s]!}o|gCڼ[bk:u]\C[ \DM*s]*q]X\"q]PY\*o]#"o]}o|g|Ÿ[ \DM*q]*s]X\"q]PY[2*o]! ~#foCs#rG\:T\!T\!& äV~# xY\DM\ʓ\͹\! w!( V6 ʎ\zwø \ʓ\͹\! ~!ô\! ^#V! s#rDMͱ\ͫ\C" ͒#\>;S"]C ** C!X9}o|gHIJKL