IMD 1.17: 10/06/2011 21:54:39 cp/m ver 2.2 cbios ver 3.1 #509 disk jockey 2d @ f800h  >&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 COMbFIRMB ASMy OBASIC COM,-./XSUB COM SYSGEN COM REGEN ASM| JKLMNREGEN COMOBASIC COM0RANTEST BAS1ABOOT# ASM ABOOT# ASM!"#$%&'(ABOOT# ASM()*+PIP COM:23PQCBIOS# ASM456789:;CBIOS# ASM<=>?@ABCCBIOS# ASMLDEFGHFORMT# COM ILOAD COMOMBASIC COMRSDUMP ASM!TUVDDT COM&WXYSINGLE COMZSUBMIT COM [BIOS ASM\\]^_`aED COM4bcdeSINGLE ASMZfghijkDISKS ASMlmDT12 COMnopqrs|}STAT COM)tuvCBIOS ASMEwxyz{DT12 COM~DUMP COM1><<2O!| 2.}2"DM =*1!"DMͶ>OچO!"Æ ¹*1 !"DMͶ>O چ O!"Æ ¹*1!"DMͶ>OچO!"Æ ¹*1!"DMͶ>OچO!"Æ ¹*1 ͨ!w# ‘!"ͨ!"DM>O ڨ O!"è *1ͨ!w# ‘!"ͨ!"DM>OڨO!"è *$1!w# x>2F1-y2dc' O2d-c- f*DEBLOCK ASMOASM COM@DISKDEF LIB1FORMT# ASMPMBASIC COM>DT12 COM,COPYRIGHT (C) DIGITAL RESEARCH, 1979 1] ʑ?ʑ! __0 r))) O @|r}r.g))å{r INVALID MEMORY SIZE$!$ʡ~/w/wʔ|g*"w|?¸>@G!>0w#w!4~:60+4{r!N#F! x, # =!v"w!t6!r#+w+ww >j*w# @xG}o|g"y! :m s À!"xʀ ~#s*y!:m ʕ xô SYNCRONIZATION ERROR$ {~#o}oÕ:m j! ~#* DM! x w#!N#F! D!\>0w#w.!]4~:60+4*"b=r READY FOR "SYSGEN" OR "SAVE 00 CPM00.COM"$*y  CONSTRUCTING 00K CP/M Vers. 2.2$3áÒE8×vðû*Ò:L!3w# CC*#~!wwwww>>26҃>2͝q>>26ͭ"’y/2/¡:/͡:G:O:/W:W:W:*DM>>y2! ! 7>`i"'2222!> }7ɯ7y?2yM?22ͭy2:>x V2H*>k~#~#~# ~#!|õ>kw#w#w# w#¢!!͇_:=2:=N>7::<'!:##wy2!}A:l>xWH:2$z7' !>2w,U!͇lJA:O! :G>x2> !" GÊy2!+| 0!N#^q#{~6#6B:w#w ~2#~> -22:O:/:O:=/wOj*+|c~ :w>7*))!w~҂~~z‡^#V:w6r{7~µ~ʺ~¿y/G!^#~##~w~22:2:!$>W!\q:\_  !^p+q.*]   !`q*`&!bp+q*a2_!dp+q*c2_!fp+q*e2_2_!hp+q*g!jp+q*i!lp+q*k!np+q*m2_!pp+q*o\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?w0#6 #6" #~?  xDIR ERA TYPESAVEREN USER"-!yO#< Ty#O 321y_͸2y2ͽ:˜1͘A͌>>͌92^ :¥.!_~#fow]!v"!çREAD ERRORçNO FILE^: 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 !~#:A #~$=2E k͌ : :/GyO>2!q*C " ͡  ʔ*J Ҕ^ :Oyʃ?|x | s-|N-# S:2E !~Яw > T   D ^ 6k -äPYy 5*{zBK52:O=ʃz<2!ʟ#ʐ :=o&)))))))!>55>2>=>2>!2" :O3:O :O0O>7>!7!w#7!R!o!:_~#fo!R!:V!:r!:|!ÄlFy:=2>222@!>=@@ >>2      %&'()*+, -. /0  12!"34#$!"#$1234%&'(5678 )*+,9:;<  -./0 12345678 !"#$%&'(9:;<=>?@)*+,-./0?4 < 3@+ t4  h@x1@;W@|! !,! !l!V !!  ! ~ 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!~Ypsp2mÆÆf ͧÆFILE EXISTS _: É: :ʉ=2)ͽÉ T!@k!}|q=qf^!~2>`~22\!!B!~> >#0~O#Cx2͘1)ͽÂf zͧÆBAD LOADCOMf^: ! Â$$$ SUB *C ^ O T  *C ~w D  -'   -@ ͦ ~^ *C  O x ! N!Fwyxʋ>ڋ>*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 ̈́ ͊ Ͳ  >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#{ @$A $@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 @$"DHI$@@BI "-"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#  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+ *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>2à@LaÁvlÐÒÅÊibÌ× 24K CP/M Vers. 2.2, Cbios rev 3.1 For Thinker Toys Disk Jockey 2D Controller @ 0F800H. ~#O Ó1!!6͓22!͊>22!"!"22:O!>2G7::1>>22ʳ2O3-0>2?!"^>r><<V *^"^2?O!"^DMr> u*y2`i"y2A~ n& ~ʥ/oy2={$>22 =' !Z_A7 D@!$$@@  A"B$@EEEEEUUU@"H@ """"CD211B213617CD9317AF32BA1C5A :101FB000320400218000CD8A183EC3320000320571 :101FC00000210317220100210609220600AF32BFBB :101FD00MP 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 W Extended Submit Vers 2.0Xsub Already Present$Requires CP/M Version 2.0 or later$:y*###ƒ# yk   җ 4!~=ŐW!xʵ ~#èbx {~#o}où.xsubb!np+q*m2_!pp+q*o ]xsub*"-!/"*"+!""1 M*!"́!"* (xsub active)$|*y ʥ*"*7***x*́͋<͛ :%*=26͋!7^#6 #6 #6$ 8*7~O #w# !6:6=2% ͋*-"*$$$ SUBq:(=2(N *$*& w*$#"$*&#"&' !"N*M^7 !)6:!)ھ *N*DM͆ 2*ʭ :*ʗ ͯ *N"P*6:2)÷ *N"N!) $@BA$! A "!$""; 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 ;adj***************************************************************** * * * 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 200Q WRCMD EQU 240Q 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 COPYRIGHT (C) 1978, DIGITAL RESEARCH   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMN~# zo&)))))))a{__> ͜> Ü͢~͜#ñ*'x: O!$'*{#z+| ^#V"'0P0K>N2)>2(9x)x\>2))x9ͽ! "$>2!!!4:(N>2":)!"4!"^!*FNy̓*$DM2&:& !ͱ͎ ͢{<2&:#{ê!"$>42))ͽg1i!ͱ:] T\<!ͬ2|\K ! DM\š3! ͬ!͎ͬ ʚAoTA26A2 ͢!,ͱ͎ ͢2#!ͱ!J͎ͬ AڵÚA2A2 !w͎ͬ ͢!#6!ͱÚ2 ͢!ìSYSGEN VER 2.2SOURCE DRIVE NAME (OR RETURN TO SKIP)SOURCE ON , THEN TYPE RETURNDESTINATION DRIVE NAME (OR RETURN TO REBOOT)DESTINATION ON , THEN TYPE RETURNPERMANENT ERROR, TYPE RETURN TO IGNOREFUNCTION COMPLETEINVALID DRIVE NAME (USE A - P)NO SOURCE FILEqu 0ah org 100h ;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 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 RN ON DISKSOURCE FILE INCOMPLETERN TO SKIP)SOURCE ON , ?at: $ Diskette is Write Protected$ Drive not ready$ Reformatting in progress $ Track read error Invalid CRC, Illegal Density, or Illegal track or sector sequence$ Diskette will not accept re-formatting Permanent Verification Error and probable physical damage$ Error occured on Track: . Press RETURN$1H͌*#~!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 correctioZ 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 ST* * 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 ;Disk Jockey 2D prom 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 en 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.$ $Q ;Index mark READY EQU 40Q ;Drive ready sense TRKZRO EQU 4 ;Track 0 sensor WPROT EQU 100Q ;Write protected ; ; ASCII Characters used ; CR EQU 15Q ;Carriage return LF EQU 12Q ;Line feed CTLC EQU 3 ;Abort character ; ORG 100H ;CP/M version JMPAX 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 ;Decremee 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 ce 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 ; instnt 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 SE;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 bit ructions 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 ;trRROR ;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 th 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 ; deviim 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 DB berSubscript out of rangeRedimensioned arrayDivision by zeroIllegal directType mismatchOut of string spaceString too longString formula too complexCan't continueUndefined user functionNo RESUMERESUME without errorUnprintable errorMissing operandLine buffer overflowFIELD overflowInternal errorBad file numberFile not foundBad file modeFile already open?Disk I/O errorFile already exists??Disk fullInput past endBad record numberBad file nameMode-mismatchDirect statement in fileToo many filesH8jII,2%Oɯ2&:%> > 2%:*±" H> : 8 \:'G: <2 O*5|ʠz/7X4:1!FA ! |":*/2*>d2 ͙  "  *-ͺʈ:҈:̀:~d&94=:A9QZ~>5́=:A98OG* 3{" !9" ~:ʋ #~# #^#V"-:R ʊ>[?>]ͫFցL%O! N#F#~: ʫ : * ì#2 ~#o&" >2 <2  GZ9" !$  ҫ0?<=: F F* @###^#VC<! : 2 {9*/j `iү+". oo<Ó5" ! " !*-}<ʴ"$ * "& 2*! – á >2&2*>^@*& |$ *$ "-͆&:'G{<2">2R 1!J V9** ͺ,1ˆ:** ʹV9J V9>2 12 `i *, ʹe `i", ~,ͫM AOGͫ¯ͫAGͫx>ƕo> g9*+++" $  0 *-|< :! $ à* "-  *-" " 6 * À {K2#* " * |/_#‰ * |"|2*X4! :#*!"-:  * ? >* >  2 â *  ʹ " +ڽ ͫ<=ʽ ~ K9ͦ " ҕ4ͫ" G ʯW-(ʆ *( ͼ "( t##s#r# w# y| ͮ !6"9*5"" A *7"9*" "5ý */bk~####~ Ҷ ڶ ͬͫø #s#rî   ͺ */DM~#+ͫ!ʹ bk))0_E +ͫ* }_|W *( ( ʹ "+E A \ 3E F| *->3À: * *-ʹ# ү > 2 N-`i$ ͙ " $ "-!F>:yHG+ͫȸ#"<֌W1ͺ" ̀ͧ!͈9P*X #^#V*/ʹD*+ʹL*( ʹL>#"#V9…ͫͺzs PYү" :! :#_- ͆&~Gʔͺ+K xʓ,Õ! " <2#~z€<ͫ* * "-~#####͆&$  ͺ,*  |" 2 " ý ̀~,̫4ͺ+9Lͫ} }ÒͫNN<>2&o\2+ͫʆa(BB,;̀?5"*5|*X :&ʿ:%:'G: "> "o: 6!> > *5|:"=2 *5|% ~9:&+:%p3:(G: 9/t̓&ͺ)+o*5|% ~o:&l:%o: / xͫv2&go"5ͺ#21̈́:ڝ8"?REDO FROM START : !|"* Z2!#">2*6"ͺG:%:,}O!Uej"&- V.& 3(  (&b&K&  M,*',Q1i05O.N.43g410q1V5U54X1g$$$ 9:8DE)Fv7D#FFF< &f #"$#$,(J$!"` :=:i::222_--.222;LMx  C\o(267NBTSUTϫLOSONԚLEAҒINSNDBV+V,V-O HRATI͆EFSTҭEFINԮEFSNǯEFDB̰EƘELETŪNāLSŢRASŦDIԧRROҨRRX O/QO҂IELILERIOTωO TωOSUEEXNPUԅƋNSTNNMILEԈINűOASEPRINԞLISԟPOISԓO O0EEFTO1ERGOKI2KS3KD4IDEXԃUL̖AMEהOUԝΕPEοCTUOKřRINԑOEEEAćUΊESTORŌETURΎE͏ESUMũSEIGHTNENUͬESETOАWAХAVPCTEGQI TRTRINGPACEYSTEͽROΣROFƤABHEA SINSAARPTIDTȡAIԗO۾yy||PF<2(z{i:::=:f<_<==:z6w6789q;e;;9NEXT without FORSyntax errorRETURN without GOSUBOut of DATAIllegal function callOverflowOut of memoryUndefined line num##~#foʹ`i~#fo?? :YG!9^#V# 5*/ 2 2 w#w#"( */+" !0 6#M 2! og" "& * " U*( "* ", 5*+++" ##! " ͆go2 * >?> 2 2 ;~"n Dw: ~D?>D8͗ڇ!AO ^#V#͗Oʢ#  +>͌2 ͌ó ! +``>2 ~t͊%͊>͌p~.ʗ:0: ~D.D>͌}͌|͌ó ~i>: *X |>}e. ҷü͌!X !T ~͌#=ó 7ʫý&DͫH> 8> ͌õ#͌:VJ\>2 2 U³ ~|wD~#͌b!@}O|G!>: y$ ~a{_w+=2 g~ ҽ ʽ ʽ> : \2)>+#~+!2)O:)J>\2)yʊ7  ʊ nÊ@#_ x<>ʕyq# 2 > oʥ 4|}~#ʫ *5|.:&) > :% :%<;"͙ ڝ#~+6,!*. 2 -ͺ,1~,U: >?͙ ڝ#~+*5|2‚ͫWG"u:,+9"!ͫxi>b>+ͫʝ,+ͫ): k*5|!|"Æ?Extra ignored #~#$ #^#V" ͫU1" ͙  " ~#~#.39n6M9D9͓9W####N#F#^#Vi`q;: 7r+s^#V#9D9i"-i`B" * ~,Fͫͺ(+ "" *" ~ڲҲW " ͫÖzG~" _: y#!MxVz-Q;z;!X : === !N#F#N#F#!T N#F#N#F*!KGd* Ã=:&9D&:&xdd!*X w&y2 xʗ: ʿWxzʈ:!w N#F*X i:́9"V "T 69i:!c: O ~#fó92 ʥ"X ê=:!mð&9]:A9"Z "X ]:&9]:8ͫ$ i> &<.=Ҷʨ"6"ʱ&Gͫ:#i Xͫ* C<‡ͫͺ(#t̓&͚2w1ͺ)|%:o $$ 6 |ͺ)}̓*" 81"X {9&ͫOH#:)0)G)7))))o* All sector sizes: * * Track 0 sector 1 e700 * * 0 8 3200h * * 0 10 3300h * * 0 12 3400h * * 0 14 3500h * * 0 16 3600h * * 0 18 2d80h * * 0 20 2e80h * * 0 22 2f80h * * 0 24 3080h * * 0 26 3180h * * 0 9 3280h * * 0 11 3380h * * 0 13 3480h * * 0 15 3580h * * 0 17 2d00h * * 0 19 2e00h * * 0 21 2f00h * * 0 23 3000h * * 0 25 3100h * * * * The following depend on the sector size, all sectors are from * * track 1. * * * * 256 512 1024 * * sec address sec address sec address * * 1 3200h 1 3200h 1 3200h * * 3 3400h 3 3600h 3 3a00h * * 5 3600h 5 3a00h 5 4200h * * 7 3800h 7 3e00h ------------- * * 9 3a00h 9 4200h 2 3600h * * 11 3c00h 11 4600h 4 3e00h * * 13 3e00h ------------- 6 4600h * * 15 4000h 2 3400h * * 17 4200h 4 3800h * * 19 4400h 6 3c00h * * 21 4600h 8 4000h * * 23 4800h 10 4400h * * ----------- 12 4800h * * 2 jc nowrp+diff wrp lxi d,-980h dad d nowrp shld newdma+diff ;Save the updated DMA address mov b,h mov c,l call putdma ;Set up the new DMA address lxi b,retries*100h+0;Maximum # of errors fread push b call puttrk ;Set up the proper track call doread ;Read the sector pop b jnc firmlod+diff ;Continue if no error dcr b jnz fread+diff ;Keep trying if error jmp boterr ;To many errors, flash the light ds 80h-($ mod 80h) stac equ $ ***************************************************************** * * * The following equates relate to the Thinker Toys 2D controller* * If the controller is non standard (0E000H) only the ORIGIN * * equate need be changed. This version of the Cbios will work * * with 2D controller boards rev 0, 1, 3, 3.1, 4. * * * ***************************************************************** djram equ origin+400h ;Disk Jockey 2D ram address djboot equ djram ;Disk Jockey 2D Boot routine djcin equ djram+3h ;Disk Jockey 2D character input r7+ͫ)8 7)))0O %:#~ցOͫyY|ͺ,̈́:*X ͆&n͠} j=: N#fi#~#N#F#^#N#F{zد< #ʌ?8< 9Z̓:}/o|/g"X Ï: 7:zM<{;k F{o|P{o|< {o|2{/o|/}//o|//+ͫͺ,#2 F OͫJWOͫKK~%$!#xA_!0 V+z2 ͫ: =d~(1312 *( ** ʹo>&ã|wʹʹO*, ͼ ", `i"* +6ʹs#s#rW_2[ go"X /! "X * W*, ʹ: ʦ#‡~#ˆ~>##^#V#j:  DM7  $ w#_q#p#O ##" q#: y q#p#E;=BKڡ ", +6ʹW* ^) ++s#r#8 GO~#^#V#ʹҡE;=DM : DM)0 )5 )5 *" *, !9W #Ϳ"*+* }o|gC<:%i : og%:͎ ͠N#F!7: #!X ͫҦ ڦ ͫ: O! ͎ ͺg&s#rʭ !!s#r~(ͫ1~)ͺ, !: "" ~#fo ~(`3300h * * 4 3500h * * 6 3700h * * 8 3900h * * 10 3b00h * * 12 3d00h * * 14 3f00h * * 16 4100h * * 18 4300h * * 20 4500h * * 22 4700h * * 24 4900h * * * ***************************************************************** title '*** Cold Boot Loader for CP/M Ver. 2.2 ***' ***************************************************************** * * * Cold Boot loader common to all sector sizes. * * This sector is loaded into memory at e700h in a standard * * configuration. It is responsible for reading most of track 0 * * into memory on cold boots. * * * ***************************************************************** origin equ 0F800H putden equ origin+02dh ;Set density routine on Disk Jockey 2D putdma equ origin+12h ;Disk Jockey 2D set DMA address routine getstat equ origin+27h ;Disk status routine on Disk Jockey 2D putsec equ origin+0fH ;Disk Jockey 2D set sector routine puttrkoutine djcout equ djram+6h ;Disk Jockey 2D character output routine djhome equ djram+9h ;Disk Jockey 2D track zero seek djtrk equ djram+0ch ;Disk Jockey 2D track seek routine djsec equ djram+0fh ;Disk Jockey 2D set sector routine djdma equ djram+012h ;Disk Jockey 2D set DMA address djread equ djram+15h ;Disk Jockey 2D read routine djwrite equ djram+18h ;Disk Jockey 2D write routine djsel equ djram+1bh ;Disk Jockey 2D select drive routine djdmast equ djram+24h ;Disk Jockey 2D dma status djstat equ djram+27h ;Disk Jockey 2D status routine djerr equ djram+2ah ;Disk Jockey 2D error, blink led djden equ djram+2dh ;Disk Jockey 2D set density routine djtstat equ djram+21h ;Disk Jockey 2D terminal status routine djside equ djram+30h ;Disk Jockey 2D set side routine ***************************************************************** * * * The following three sectors of code reside at 80H. There is * * one sector for each of the possible sector sizes (256,512, * * 1024). Each sector is respons***************************************************************** * * * CP/M vers 2.2 Cold Start Loader for Disk Jockey 2D (all revs).* * * * Written by Bobby Dale Gifford. * * 11/21/79 * * * * Th col boo loade (secto 1 trac 0 i loade * * int th ra o th controlle b th col boo routin o * * th firmware The first thing the boot does is to load into * * the controller ram, a version of the Disk Jockey 2D firmware. * * From then on, all calls to the firmware will actually be * * directed to the Disk Jockey Ram. The next process is to load * * in a boot routine which can load in all of CP/M. This is * * done by determining the size of the sectors on track 1, and * * using this information to load in the proper boot into 80H. * * * * The following tables explain the order of sector loading for * * each of the different sector sizes. An entry of ------ * * represents a wrap back around (negative DMA adjustment). * * *  equ origin+0ch ;Disk Jockey 2D set track routine puthom equ origin+9h ;Disk Jockey 2D track 0 seek doread equ origin+15h ;Disk Jockey 2D read routine boterr equ origin+2ah ;Disk Jockey 2D flash error light routine org origin ;Disk Jockey 2D ram msize equ 24 ;Memory size of target CP/M bias equ (msize-20)*1024 ;Memory offset from 20k system ccp equ 2d00h+bias ;Console command processor bios equ ccp+1600h ;CBIOS address retries equ 10 ;Maximum # of retires diff set origin+700h-$ ;Offset to boot loader address lxi sp,stac+diff firmlod mvi a,6 ;Previous sector # newsec equ $-1 inr a ;Update sector # inr a cpi 27 ;Test if all done jz ccp+500h jc nowrap+diff ;Test if wrap around sui 19 nowrap sta newsec+diff ;Save the updated sector # mov c,a call putsec ;Set up the sector lxi h,ccp+400h ;Previous DMA address newdma equ $-2 lxi d,100h ;Update DMA address dad d mov a,h cpi (ccp+980h)/100h jc nowrp+diff jnz wrp+diff mov a,l cpi (ccp+980h) mod 100h  ible for performing a Cold Boot * * for the specified sector size. * * * ***************************************************************** diff set 80h-$ lxi sp,cstk256+diff ;Set up stack at end of this sector lxi b,24*100h+1 ;B = sector count, C = sector # clod256 push b ;Save sector and count call djsec ;Set the next sector to read lxi h,ccp+300h ;Get DMA address (self modifying) cdma256 equ $-2 ;Storage for previous DMA address lxi d,200h ;Offset to new DMA address dad d ;Add in offset, HL = new DMA address shld cdma256+diff ;Save new DMA address mov b,h ;Put DMA address into BC mov c,l call djdma ;Set the DMA address call crd256+diff ;Attempt a read pop b ;Recover sector number and count ; B = count, C = number dcr b ;Update sector count jz bios ;All done ? mvi a,2 ;Sector update add c ;Add in the sector skew factor mov c,a ;Put new sector back into C cpi 25 ;Past the end of the track ? jc clod256+diff ;Take jump if not past end r in C lxi h,ccp+300h ;Negative DMA adjustment shld cdma512+diff ;Save the new DMA address jmp clod512+diff ;Continue reading ***************************************************************** * * * Crd512 does the actual read from the controller, the DMA * * address and sector # have already been set up. * * * ***************************************************************** crd512 lxi b,retries*100h+1 ;Maximum # of attempts cr512 push b ;Save error count call djtrk ;Initialize the track call djread ;Attempt the read pop b ;Restore the error count rnc ;Return if no error dcr b ;Update error count jnz cr512+diff ;Try again if not to many errors jmp djerr ;Go and flash the light on controller ds 80h-($ mod 80h) cstk512 equ $ ***************************************************************** * * * The next sector loads CP/M from a 1024 byte sector diskette. * * * ***************************************************************** di * * * * The following table shows how sectors are read in, skewing * * of the sectors is necessary because sequential sectors can * * not be read without waiting one complete revolution between * * each one. Entries of ---- represent a wrap around (negative * * DMA adjustment). An entry flagged with ** represents only a * * partial load from that sector. * * * * 256 512 1024 * * sec address sec address sec address * * 1 3200h 1 3200h 1 3200h * * 3 3400h 3 3600h 3 3a00h * * 5 3600h 5 3a00h ** 5 4200h * * 7 3800h 7 3e00h ------------- * * 9 3a00h ** 9 4200h 2 3600h * * 11 3c00h ------------- 4 3e00h * * 13 3e00h 2 3400h * * 15 4000h 4 3800h * * 17 4200h 6 3c00h * * ----------- 8 4000h * * 2 3300h * * 4 3500h * * 6 3700h * * 8 3900h * * 10 3b00h * * 12 3d00h * * 14 3f00h * * 16 4100h * * * ***************************************************************** diffof track sui 23 ;Perform a negative sector adjustment mov c,a ;Put new sector in C lxi h,ccp+400h ;Negative DMA adjustment shld cdma256+diff ;Save the new DMA address jmp clod256+diff ;Continue reading ***************************************************************** * * * Crd256 does the actual read from the controller, the DMA * * address and sector # have already been set up. * * * ***************************************************************** crd256 lxi b,retries*100h+1 ;Maximum # of attempts cr256 push b ;Save error count call djtrk ;Initialize the track call djread ;Attempt the read pop b ;Restore the error count rnc ;Return if no error dcr b ;Update error count jnz cr256+diff ;Try again if not to many errors jmp djerr ;Go and flash the light on controller ds 80h-($ mod 80h) cstk256 equ $ ***************************************************************** * * * The next loads CP/M from a 512 byte sector diskette. * * ff set 80h-$ lxi sp,cstk124+diff ;Set up stack at end of this sector lxi b,6*100h+1 ;B = sector count, C = sector # clod124 push b ;Save sector and count call djsec ;Set the next sector to read lxi h,ccp-300h ;Get DMA address (self modifying) cdma124 equ $-2 ;Storage for previous DMA address lxi d,800h ;Offset to new DMA address dad d ;Add in offset, HL = new DMA address shld cdma124+diff ;Save new DMA address mov b,h ;Put DMA address into BC mov c,l call djdma ;Set the DMA address call crd124+diff ;Attempt a read pop b ;Recover sector number and count ; B = count, C = number dcr b ;Update sector count jz bios ;All done ? mvi a,2 ;Sector update add c ;Add in the sector skew factor mov c,a ;Put new sector back into C cpi 7 ;Past the end of the track ? jc clod124+diff ;Take jump if not past end of track sui 5 ;Perform a negative sector adjustment mov c,a ;Put new sector in C lxi h,ccp+100h ;Negative DMA adjustment shld cdma124+diff ;Save the set 80h-$ lxi sp,wstk256+diff ;Set up stack at end of this sector lxi b,17*100h+1 ;B = sector count, C = sector # wlod256 push b ;Save sector and count call djsec ;Set the next sector to read lxi h,ccp+300h ;Get DMA address (self modifying) wdma256 equ $-2 ;Storage for previous DMA address lxi d,200h ;Offset to new DMA address dad d ;Add in offset, HL = new DMA address shld wdma256+diff ;Save new DMA address mov b,h ;Put DMA address into BC mov c,l call djdma ;Set the DMA address call wrd256+diff ;Attempt a read pop b ;Recover sector number and count ; B = count, C = number dcr b ;Update the sector count jz bios+3 ;All done ? mvi a,2 ;Sector update add c ;Add in the sector skew factor mov c,a ;Put new sector back into C cpi 19 ;Past the end of the track ? jc wlod256+diff ;Take jump if not past end of track sui 17 ;Perform a negative sector adjustment mov c,a ;Put new sector in C lxi h,ccp+400h ;Negative DMA adjustment shld wdma256+diff ;S * ***************************************************************** diff set 80h-$ lxi sp,cstk512+diff ;Set up stack at end of this sector lxi b,12*100h+1 ;B = sector count, C = sector # clod512 push b ;Save sector and count call djsec ;Set the next sector to read lxi h,ccp+100h ;Get DMA address (self modifying) cdma512 equ $-2 ;Storage for previous DMA address lxi d,400h ;Offset to new DMA address dad d ;Add in offset, HL = new DMA address shld cdma512+diff ;Save new DMA address mov b,h ;Put DMA address into BC mov c,l call djdma ;Set the DMA address call crd512+diff ;Attempt a read pop b ;Recover sector number and count ; B = count, C = number dcr b ;Update sector count jz bios ;All done ? mvi a,2 ;Sector update add c ;Add in the sector skew factor mov c,a ;Put new sector back into C cpi 13 ;Past the end of the track ? jc clod512+diff ;Take jump if not past end of track sui 11 ;Perform a negative sector adjustment mov c,a ;Put new secto new DMA address jmp clod124+diff ;Continue reading ***************************************************************** * * * Rd124 does the actual read from the controller, the DMA * * address and sector # have already been set up. * * * ***************************************************************** crd124 lxi b,retries*100h+1 ;Maximum # of attempts cr124 push b ;Save error count call djtrk ;Initialize the track call djread ;Attempt the read pop b ;Restore the error count rnc ;Return if no error dcr b ;Update error count jnz cr124+diff ;Try again if not to many errors jmp djerr ;Go and flash the light on controller ds 80h-($ mod 80h) cstk124 equ $ ***************************************************************** * * * The next three sectors of code also reside at 80H. There is * * one sector for each of the possible sector sizes (256,512, * * 1024). Each sector is responsible for performing a WARM Boot * * for the specified sector size.  ave the new DMA address jmp wlod256+diff ;Continue reading ***************************************************************** * * * Wrd256 does the actual read from the controller, the DMA * * address and sector # have already been set up. * * * ***************************************************************** wrd256 lxi b,retries*100h+1 ;Maximum # of attempts wr256 push b ;Save error count call djtrk ;Initialize the track call djread ;Attempt the read pop b ;Restore the error count rnc ;Return if no error dcr b ;Update error count jnz wr256+diff ;Try again if not to many errors jmp djerr ;Go and flash the light on controller ds 80h-($ mod 80h) wstk256 equ $ ***************************************************************** * * * Disk Jockey 2D CP/M from a 512 byte sector diskette. * * * ***************************************************************** diff set 80h-$ lxi sp,wstk512+diff ;Set up stack at end of this sector lxi ds 80h-($ mod 80h) wstk512 equ $ ***************************************************************** * * * The next sector loads CP/M from a 1024 byte sector diskette. * * * ***************************************************************** diff set 80h-$ lxi sp,wstk124+diff ;Set up stack at end of this sector lxi b,1*100h+5 ;B = sector count, C = sector # call wlod124+diff ;Load sector 6 into CCP lxi h,ccp+1500h ;Destination of move lxi d,ccp+500h ;Source of move mvi c,0 mov124 ldax d ;Get a byte of source mov m,a ;Move it inx h ;Bump destination inx d ;Bump source dcr c ;All done with this page ? jnz mov124+diff lxi h,ccp+100h ;Initial DMA address shld wdma124+diff lxi b,4*100h+2 ;B = sector count, C = sector # call wlod124+diff jmp bios+3 wlod124 push b ;Save sector and count call djsec ;Set the next sector to read lxi h,ccp-300h ;Get DMA address (self modifying) wdma124 equ $-2 ;Storage for previous DMA address lxi d,800h ;Offsetp initial stack at end of this sector lxi h,djram ;Destination pointer lxi d,stk+diff ;Source pointer lxi b,300h ;Length of transfer mloop ldax d ;Get one byte of source mov m,a ;Put at destination inx h ;Bump destination inx d ;Bump source dcx b ;Update count of bytes to move mov a,b ;Test if all done ora c jnz mloop+diff ;Continue moving New Firmware call djboot ;Initialize the new firmware mvi a,1 sta botbias+diff ;Set up for proper sector select dowarm lxi sp,stk+diff mvi c,1 ;Set the density to double call djden mvi c,1 ;Set up to read sector 1 on track 1 mov a,c sta trknum+diff ;Set track call djsec ;Set sector lxi b,stk+diff ;Set the DMA address call djdma call reed+diff ;Read the sector into memory at ; end of this sector call djstat ;Determine the sector size ani 0ch ;Strip off unwanted bits rar ;Form the desired sector for Cold Boot rar ; based on the length of the adi 4 ; sectors on this diskette botbias equ $-1 mo b,1*100h+9 ;B = sector count, C = sector # call wlod512+diff ;Load sector 9 into CCP lxi h,ccp+1500h ;Destination of move lxi d,ccp+500h ;Source of move mvi c,0 mov512 ldax d ;Get a byte of source mov m,a ;Move it inx h ;Bump destination inx d ;Bump source dcr c ;All done with this page ? jnz mov512+diff lxi h,ccp+300h ;Initial DMA address shld wdma512+diff lxi b,8*100h+2 ;B = sector count, C = sector # call wlod512+diff jmp bios+3 wlod512 push b ;Save sector and count call djsec ;Set the next sector to read lxi h,ccp+100h ;Get DMA address (self modifying) wdma512 equ $-2 ;Storage for previous DMA address lxi d,400h ;Offset to new DMA address dad d ;Add in offset, HL = new DMA address shld wdma512+diff ;Save new DMA address mov b,h ;Put DMA address into BC mov c,l call djdma ;Set the DMA address call wrd512+diff ;Attempt a read pop b ;Recover sector number and count ; B = count, C = number dcr b ;Update sector count rz ;All done ?  to new DMA address dad d ;Add in offset, HL = new DMA address shld wdma124+diff ;Save new DMA address mov b,h ;Put DMA address into BC mov c,l call djdma ;Set the DMA address call wrd124+diff ;Attempt a read pop b ;Recover sector number and count ; B = count, C = number dcr b ;Update sector count rz ;All done ? mvi a,2 ;Sector update add c ;Add in the sector skew factor mov c,a ;Put new sector back into C cpi 6 ;Past the end of the track ? jc wlod124+diff ;Take jump if not past end of track sui 5 ;Perform a negative sector adjustment mov c,a ;Put new sector in C lxi h,ccp-300h ;Negative DMA adjustment shld wdma124+diff ;Save the new DMA address jmp wlod124+diff ;Continue reading ***************************************************************** * * * Wr124 does the actual read from the controller, the DMA * * address and sector # have already been set up. * * * ***************************************************************** wrv c,a ;Prepare to read the Cold Boot call djsec ;Set up the sector xra a ;Track 0 sta trknum+diff lxi b,80h ;Cold Boot loads at 80H push b ;Used as jump address to Cold Boot-- call djdma ; | mvi c,0 ;Density on track 0 is single | call djden ; | call reed+diff ;Read in the Cold Boot | mvi c,1 ;Set the density back to double | jmp djden ; | ;Go to the Cold Boot <-------------- ***************************************************************** * * * Reed does the actual read from the controller, the DMA * * address and sector # have already been set up. * * * ***************************************************************** reed lxi b,retries*100h+0 ;Maximum # of attempts trknum equ $-2 ;Storage for track number reed1 push b ;Save error count call djtrk ;Initialize the track call djread ;Attempt the read pop b ;Restore the error count rnc ;Return if no error dcr b ;Update error count jnz reed1+diff ;Tmvi a,2 ;Sector update add c ;Add in the sector skew factor mov c,a ;Put new sector back into C cpi 10 ;Past the end of the track ? jc wlod512+diff ;Take jump if not past end of track sui 9 ;Perform a negative sector adjustment mov c,a ;Put new sector in C lxi h,ccp+100h ;Negative DMA adjustment shld wdma512+diff ;Save the new DMA address jmp wlod512+diff ;Continue reading ***************************************************************** * * * Wrd512 does the actual read from the controller, the DMA * * address and sector # have already been set up. * * * ***************************************************************** wrd512 lxi b,retries*100h+1 ;Maximum # of attempts wr512 push b ;Save error count call djtrk ;Initialize the track call djread ;Attempt the read pop b ;Restore the error count rnc ;Return if no error dcr b ;Update error count jnz wr512+diff ;Try again if not to many errors jmp djerr ;Go and flash the light on controller d124 lxi b,retries*100h+1 ;Maximum # of attempts wr124 push b ;Save error count call djtrk ;Initialize the track call djread ;Attempt the read pop b ;Restore the error count rnc ;Return if no error dcr b ;Update error count jnz wr124+diff ;Try again if not to many errors jmp djerr ;Go and flash the light on controller ds 80h-($ mod 80h) wstk124 equ $ ***************************************************************** * * * The next sector of code resides at CCP+500h. It's task is to * * move the firmware code into the Disk Jockey Ram, then * * loading a sector into 80H which will load the rest of CP/M. * * The sector loaded at 80H is dependent on the sector size * * of the diskette being booted from. * * * ***************************************************************** diff set ccp+500h-$ ;Used to relocate this sector of code jmp docold+diff ;Jump to cold boot portion jmp dowarm+diff ;Jump to warm boot portion docold lxi sp,stk+diff ;Set u ry again if not to many errors jmp djerr ;Go and flash the light on controller ds 80h-($ mod 80h) stk equ $ ***************************************************************** * * * Disk Jockey 2D firmware revision 3.1 and 4.0 * * By George Morrow * * * * The following firmware is loaded into memory and then moved * * into the controller ram. * * * ***************************************************************** rom equ origin ram equ origin+400h IO EQU ROM+3f8h UDATA EQU IO DCMD EQU IO+1 DSTAT EQU DCMD DREG EQU IO+2 USTAT EQU DREG CMDREG EQU IO+4 CSTAT EQU CMDREG TRKREG EQU IO+5 SECREG EQU IO+6 DATREG EQU IO+7 * * RCMD EQU 200Q WCMD EQU 240Q HEAD EQU 4 LOAD EQU 20Q DENSTY EQU 1 ULOAD EQU 30Q RSTBIT EQU 4 ACCESS EQU 2 READY EQU 40Q INDEX EQU 20Q RACMD EQU 304Q CLRCMD EQU 320Q SVCMD EQU 35Q SKCMD EQU 30Q HCMD EQU 11Q ISTAT EQU 4 OSTAT EQU 10Q DSIDE EQU 10Q TZERO EQU 4 MDINT EQU 3 LIGHT EQU 36Q NOLITE EQU 76Q * * DBOOTI ISTAT ;input ready bit RET * * DISKST LDA SECREG ;get current MOV B,A ; sector no in B LDA TRKREG ;get current MOV C,A ; track no in C LDA DCREG ;get current CMA ; density in ANI 1 ; the msb RRC ;position MOV D,A ;save in D LDA SIDE ;put the RLC ; side RLC ; select RLC ; flag ADD D ; in bit MOV D,A ; position 6 LDA SECLEN ;put the RLC ; sector length RLC ; code bits ADD D ; 2 & 3 MOV D,A LDA CDISK ;put the current ADD D ; disk no in bits RET ; 0 & 1 * * DMSTAT PUSH H ;save the H-L pair LHLD DMAADR ;H-L pain MOV B,H ;move the DMA MOV C,L ;addr to B-C POP H ;recover H-L RET * * DRIVE MVI A,374Q ;test for the ADD C ; new drive number MVI A,20Q ;less than 4 RC MOV A,C ;store the new STA DISK ;drive in DISK RET * * DMA LXI H,8-ROM ;test the DAD B ; DMA address JNC DMASET ; for conflict LXI H,-RAM ; with the I/O DAD B ; on the DJ/2D  entry address jmp cbusy read call prep ;prepare for read jc leave ;abort operation rdentry mvi a,rcmd ;start a read call comndp ; sector operation rdloop ldax d ;read 1st byte mov m,a ;store 1st byte inx h ;advance pointer ldax d ;read 2nd byte mov m,a ;store 2nd byte inx h ;advance pointer ldax d ;read 3rd byte mov m,a ;store 3rd byte inx h ;advance pointer dcr c ;reduce block count ldax d ;read 4th byte mov m,a ;store 4th byte inx h ;advance pointer jnz rdloop ;read next 4 bytes lxi h,rdentry ;return entry address CBUSY push h ;save return address lxi h,cstat ;wait for the 1791 call busy ; to finish command ani 137Q ;error bit mask jz leave-1 ; test cpi 10h ;premature interrupt jnz pleave ;other error type lda ecount ;decrement error dcr a ; count number 1 jm stest ;hard interrupt error sta ecount ;update count ret ;do operation over stest lda ecount+1 ;decrement error dcr a ; count number 2 jp iss JMP BOOT TERMIN JMP CIN TRMOUT JMP COUT TKZERO JMP HOME TRKSET JMP SEEK SETSEC JMP SECSET SETDMA JMP DMA DREAD JMP READ DWRITE JMP WRITE SELDRV JMP DRIVE TPANIC JMP CPAN TSTAT JMP TMSTAT DMAST JMP DMSTAT STATUS JMP DISKST DSKERR JMP ROM+52Q SETDEN JMP DENFIX SETSID JMP SIDEFX * * BOOT lda io-4 ;Test for Model A or B cpi (ret) jz modela lxi d,origin lxi h,ram mvi c,boot-dboot ;Copy prom jump table into ram modelm ldax d mov m,a inx d inx h dcr c jnz modelm ret modela mvi c,0 ;Copy last page of ram call modelm LHLD ROM+7 ;find the 2nd INX H ; byte of input routine LXI D,4 ;offset MOV A,M ;get addr of USTAT LXI H,SDSEL+1 ;I/O routines MOV M,A ;store USTAT addr DAD D ;increment mem addr MOV M,A ;store USTAT addr DAD D ;increment mem addr XRI 3 ;switch the addr MOV M,A ;store DSTAT addr DAD D ;increment mem addr MOV M,A ;store DATAT addr DAD D ;increment mem addr MOV M,A ;store DSTAT addr DSETUP MVI A,MDINT ;initializ JC DMASET ;controller STC MVI A,20Q RET DMASET MOV H,B ;get the DMA addr MOV L,C ;to the H-L par SHLD DMAADR ;store XRA A ;clear the error RET ; flag and return * * HOME call hdload ;load the head rc ;not ready error call hentry ;move the head PUSH PSW ;save the flags 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 ;update STA HDFLAG ; flags LXI H,0 ;time out constant MVI A,HCMD ;do the home CALL CENTRY ; command ANI TZERO ;track zero bit RNZ STC ;error flag RET * * SECSET XRA A ;test for ORA C ; sector zero STC ;error flag RZ MOV A,C ;test for CPI 27 ; sector CMC ;too large RC STA SECTOR ;save RET * * SEEK MOV A,C ;test for CPI 77 ; track CMC ; too large RC STA TRACK ;save RET * * issue sta ecount+1 ;update count call measur ;find the index mvi c,1 ue ;issue a command mvi a,10h ;irrecoverable error pleave stc ;error flag pop h ;adjust the stack LEAVE PUSH PSW ;save the flags LDA DCREG ;1791 control bits XRI LOAD ;toggle the CALL SCBITS ; head load bits POP PSW ;recover the flags RET * * PREP CALL HDLOAD ;load the head RC ;disk not ready? LDA TRKREG ;get the old trk INR A ;test for head CZ HENTRY ; not calibrated rc ;seek error? LXI H,TRKREG ;present trk LDA TRACK ;the new track CMP M ;test for head motion INX H ;advance to the INX H ; data register MOV M,A ;save the new trk MOV A,C ;turn off data CALL SCBITS ; access control bit JZ TVERFY ;test for seej XRA A ;force a read STA HDFLAG ; header operation CALL LDSTAT ;get the ANI DSIDE ; double RAR ; RAR ; flag RAR ; to do 3 ms ADI SKCMD ; step operation LXI H,0 ;do a seek CALL CENTRY ; command JC SERROR ;seek error? TVERFY LDA HDFLAG ;get the force ORA A ; verify track e 1791 CALL SCBITS ; control bits MVI A,CLRCMD ;1791 reset STA CMDREG ; command LDHEAD XRA A ;load the head CALL HDCHK ; and test for JNC DOOROK ; drive ready MVI A,LIGHT ;turn on the STA DRVSEL ; error LED CALL TIMOUT ;time out to JMP LDHEAD ; close drive door DOOROK MVI A,NOLITE ;turn off the STA DRVSEL ; error LED MVI M,MDINT ;open data reg CALL MEASUR ;head load time XCHG ; new TIMER value SHLD TIMER RET * * COUT CALL LUSTAT ;get UART status ANI OSTAT ;output ready bit JNZ COUT ;test output ready MOV A,C ;character data CMA STA UDATA ;send to UART CMA RET * * CIN CALL LUSTAT ;get UART status ANI ISTAT ;input ready bit JNZ CIN ;test input ready LDA UDATA ;get the character CMA ANI 177Q RET * * CPAN CALL LUSTAT ;get UART status ANI ISTAT ;input ready bit RNZ ;test for character CALL CIN ;get character CMP C ;test for panic RET * * TMSTAT CALL LUSTAT ;get UART status AN ;start w/sector 1 isloop mov a,c ;initialize the sta secreg ; sector register lda sector ;test for cmp c ; target sector rz mvi a,rcmd ;do a fake call comand ; read command jc pleave ;abort on error inr c ;increment sector no. jmp isloop comndp sta cmdreg ;do the command mov c,b ;initialize 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,wcmd ;start a write call comndp ; sector operation wrloop mov a,m ;load 1st byte of data inx h ;advance pointer stax d ;write 1st byte of data mov a,m ;load 2nd byte of data inx h ;advance pointer stax d ;write 2nd byte of data mov a,m ;load 3rd byte of data inx h ;advance pointer stax d ;write 3rd byte of data dcr c ;reduce block count mov a,m ;load 4th byte of data inx h ;advance pointer stax d ;write 4th byte of data jnz wrloop ;write next 4 bytes lxi h,wrentry ;return flag JNZ CHKSEC ;no seek & head OK MVI B,2 ;verify retry no 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 ;1791 control reg XRI DENSTY ;flip the density bit STA DCREG ;update XRI ACCESS CALL SCBITS ;change density DCR B ;dec retry count JNZ SLOOP ; and try again mov a,d ;restore error bits SERROR stc ;error flag push psw ;save the status call hentry ;seek to track 0 pop psw ;recover errors ret RDHDR MVI B,12Q ;number of retrys RHLOOP LXI D,DATREG ;data register LXI H,TRACK+1 ;storage area MVI A,RACMD ;do the read STA CMDREG ; header command RHL1 LDAX D ;get a data byte MOV M,A ;store in memory INR L ;inc mem pointer JNZ RHL1 ;test for more data LXI H,CSTAT ;wait for 1791 CALL BUSY ;to finish cmd ORA A ;test for errors JZ CHKSEC ;transfer OK? DCR B ;dec retry count JNZ RHLOOP ;test for JMP SERROR ; hard error CHKSEC LDA SEC load INX H ;addr of disk table JZ HDCHK ;no disk change? PUSH H ;save table address MVI D,0 ;set up the MOV B,D ; offset address DAD D ;get the current DAD D ; disk parameters LDA DCREG ;save the MOV M,A ;density info INX H ;current track LXI D,TRKREG LDAX D ;get current trk MOV M,A ;save POP H ;recover tbl addr DAD B ;add the DAD B ; offset MOV A,M ;get control bits STA DCREG ;update DCREG INX H ;get the old MOV A,M ;track number STAX D ;and update 1791 MVI A,177Q ;disk select bits DSROT RLC ;rotate to DCR C ; select the JP DSROT ; proper drive STA DRVSEL ;save XRA A ;force head load HDCHK CALL LOADS ;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 CALL SDSEL ;select drive & side LDA DCREG ;1791 control bits MOV C,A ;save LDA TRACructions XTHL ; for delay MOV A,M ;wait ANA C ; for next JNZ INDXCT ; low index RET ;98 machine cycles * * DENFIX MOV A,C ;trim excess ANI 1 ; bits, CMA ; compliment MOV B,A ; B and save LXI H,DISK ;new disk MOV E,M ;get disk no MVI D,0 ;offset addr INX H ;current disk MOV A,M ;move to ACC XRA E ;compare 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 POP PSW ;check for nd=cd RNZ ;new disk not old MOV A,M ;update CDISK STA DCREG ; also RET * * SDSEL STA DREG ;drive select reg RET LUSTAT LDA USTAT ;UART status reg RET SCBITS STA DCMD ;1791 control reg RET LDSTAT LDA DSTAT ;drive status reg RET LOADS LXI H,DSTAT ;drive status reg RET end LEN ;get the sector MOV C,A ; size and setup MVI B,0 ; the offset LXI H,STABLE ;sec size tbl DAD B ;add the offset LDA SECTOR ;get the sector MOV B,A ;save in B ADD M ;compare w/table entry MVI A,20Q ;error flag RC ;error return MOV A,B ;save the sector STA SECREG ; in sector reg mvi a,40q ;128 byte sector lxi h,505h ;initialize shld ecount ; error counts 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 * * SIDEFX MOV A,C ;get the side bit ANI 1 ;trim excess bits RAL ;move the bit RAL ; to the side RAL ; select bit RAL ; position STA SIDE ;save RET * * TIMOUT LXI H,0 ;time out delay TILOOP DCX H ;decrement MOV A,H ;test for ORA L ; count zero XTHL ;long XTHL ; NOP JNZ TILOOP RET TOEND * * DS 300h-TOEND+DBOOT-66Q DS 25Q * * STACK * * STABLE DB 345Q DB 345Q DB 360Q DB 367Q * *K ;get the new trk SUI 1 ;force single SBB A ; density DCR A ; if track = 0 CMA ;compliment ORA C ;merge w/control bits MOV M,A ;set 1791 control XRI ACCESS ;toggel access bit MOV C,A ;save PREP routine 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 ;disk status addr RDYCHK MOV A,M ;test for ANI READY ; disk ready RZ UNLOAD LDA DCREG ;force a ORI ULOAD ; head MOV M,A ; unload MVI A,200Q ;set disk 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 ; device busy MOV A,M ;restore status RNC ; ecount dw 0 ;error count cells TIMER DW 3000h ;head load time DMAADR DW 200Q ;dma address HDFLAG DB 0 ;read header flag DRVSEL DB 376Q ;drive select constant DISK DB 0 ;new drive CDISK DB 10Q ;current drive TZFLAG DB 0 ;track zero indicator D0PRAM DB 3 ;drive 0 parameters D0TRK DB 377Q ;drive 0 track no D1PRAM DB 3 ;drive 1 parameters D1TRK DB 377Q ;drive 1 track no D2PRAM DB 3 ;drive 2 parameters D2TRK DB 377Q ;drive 2 track no D3PRAM DB 3 ;drive 3 parameters D3TRK DB 377Q ;drive 3 track no DCREG DB 3 ;current parameters SIDE DB 0 ;new side select SECTOR DB 3 ;new sector TRACK DB 0 ;new track TRKNO DB 0 ;disk SIDENO DB 0 ; sector SECTNO DB 0 ; header SECLEN DB 0 ; data CRCLO DB 0 ; buffer CRCHI DB 0 * * HDLOAD LXI H,DISK MOV C,M ;new disk no to C INX H MOV E,M ;current disk to E MOV M,C ;update current disk INX H ;addr of disk table MOV A,E ;test for CMP C ; disk change MOV A,M ;head load flag MVI M,HEAD ;update headreturn if not busy DCX D ;test for MOV A,D ; two disk ORA E ; revolutions JNZ BUSY ;47 machine cycles mov e,m ;save error code PUSH H ;save cmd address INX H ;track register MOV D,M ;save present track xthl ;recover cmd reg. push d ;save status xchg ;adjust registers call loads ;get control reg LDA DCREG ;1791 control bits xri RSTBIT ;reset the 1791 mov m,a ; controller to xri rstbit ; clear fault xchg ;adjust registers stax d ;start controller MVI M,CLRCMD ;force an interrupt pop d ;recover status POP H ;recover track reg mov m,d ;restore track mov a,e ;restore error code STC ; error flag RET * * MEASUR LXI D,0 ;initialize count CALL LOADS ;status port MVI C,INDEX ;index bit flag INDXHI MOV A,M ;wait for ANA C ; index JNZ INDXHI ; pulse low INDXLO MOV A,M ;wait for ANA C ; index JZ INDXLO ; pulse high INDXCT INX D ;advance count XTHL ;four XTHL ; dummy XTHL ; inst !ͫ" !ͺ, >2 17҈:["ѯ~) !*" ͺ(* 1 ~)W!ͺ,ͺ,>!ͫͺ)>ͺ̀+ͫ ʶ!!Қ!p+qv!+p+qv!+p+q+p+qv! ["!YO q* *X ʹ!"u!! #~" w#q#pv!*-#| $ ͺ>2 G6QD "TD "?5"#$~#͕"N#F*"o͸#͕"! w#s#r+"P#~ K"K"<""̫#y*" >* "X >2 V9 ʹ" ~$ #5"#F9  Æ"*+* /O #ʹڳ"" #$ "* " !*+! * ʹ"0#*( ** ʹ#~###"1#_"*, ʹU#~#D9 #" N #* ʹ#"#ů#^#V#DM* ʹ`iʹ`i}+F+N+n& PY+DM* Ϳ q#pi`+"*X ̈́:~*X $ '"##* Ͱ#Ͱ#!W"~#N#Fo,- ù#̈́:*X #PYN* ʹ#G " * +F+N+ʹ" i #W~i ##^#V>'"͉&* sW"ͫͺ(͆&ͺ,̀ͺ)C$͉&F$$O$͉&> {'"_$* w#^$$$O>~w$x͕"#F#fh DM*"o͸##W"$k$~$ &o$=O~GC#i _#~#foFr~b>pͺ)Cͫ|> %͉& > G-!#-|"??+,Undefined line ,###N#F>!-* +p+q+w: ó,̀2ʡ1!$ ~}-#N>O #~ 9PY!$ 6i/ʞ1«-ѯÛ1<ʼ1!" ^#Vr+s̓2- PY-!-`i>".!$ ~Ć-i/&-̀2ʧ1!# ~+nk ̀2ʧ1! ~i *5~ʀDM$~̃-4~O#V pG.zw w23t2¡1!" ^#V~,+ͫ {ʶ1+s#r#6#6DM! {zV.w<.<ʼ1!! {w:3.9/!! ~!& .̓-.Æ~# .*5% ~#/+~#5O ~+~0/6/ /7>*5T]" N#F+q#p###6 N/i/=c/>w+w!% /7?*5$ 6#67̀#~ʳ1#^#fk_ڸ/N#~:ʼ/++@ʳ1y@ڳ1ҳ1l #0~.//7/#/z ʳ1ڳ1> //>  0/͕/l<ʤ1!\l w# 40ͺAͺS͕/:l!\l<¿1\̀#~ʡ1#N#F Oʓ0Iʓ0R¡1ͺ,#̫͆&ͺ,{ʧ1_̓2°1z͕/" 0{0!u~ 06B#6A#6S"5#l w# 0i/~ 1:!Z ~w9og%:ʈ:8*X ||8*X *Z D9"X `i"Z !X ^#V#N#F#X Z9: Gw#Z9!Z ~7w?##wy7O!^ U9Ç9!^ V9X T x8!88y!Z yͭ9#x+y+z+{z|88}8!^ V9e 8!88O!Z y#ª9+998*X ʈ:G:!7:[ .:͍:"X >2 ͓9aj$:Z:ʈ:A9:xc9!W F7*X :|U8ʈ:Z:!"T "V >>*: $ GOW_A9c9g:>A7|7-7z< 8:9:8:ʈ::![ ~:X ~͍:6{y6![ ~:;O+~+;!%:yA9c9+6:;!Z >_==2S )ڡ)^; ڡ=P;|G.);)ұ; ;=£;|;x*<;]:&9]:ô7x%:]:9| "<. < <7>{_zW}o|g=<÷;|G)<|%:Ooyg%:*X .<|:8;g{o(:*6=!\ L=G:Z ~x~#F#fh GN#^#Vt% k%#V%ѯx<#h%S%~ #~ #ͺ(1̈́:#^#V*+ʹڰ%"V9ͺ,͆&~ &ͺ̀#G!7y~<%yH #^#fk GN#~#foyw# %)&ͺ,͆&ͺ)͉&2$&i s&s&+ͫB&ͺ,͆&C&͆&2'V&/<2(ͫ̀:z͆&2D&2,&ͺ,Æ&ͫ̀j&+ͫ{>2& !"-N#F#xʢ *5|pN#F#ʹڡ " ?> &!&ß&~+#&&#~ ' c'&<~'#~#'' ̶:!:G@ #T]~5'#9'~6'y[R'~#_!+P'&+ͫ&' QD TD* ?: O ʕ' H '>&{: ڱ'!ʱ'#~ K9~#': ڷ' '.'D'E·'÷'{'* & W- (T]ʹ! |"! *( ʹ(`i"( E(~i ̀E(ͺ,͆&::[ :Z z6́̈́:ͺ;*X {(: ʅ(2 F#N#fiï(X~#\) ¥( ”(C>\*_W*W~#!)#))+>ʲ(+~#. )\ʐ(©($(*©(x#(~$> (#<ʼ1!17@?2C:$ 1!l6# R2ĕ/!mN2!uN2lʤ1O!  ~#y#2~ 2>. 2: W:'<2> l1~*6?# R2#t2ѻ¡1ͺ,`i"5+ͫ#̫͉̀&_:Yڧ1!9N#F ̈́2!& >>>ͧ!'"* ̈́9$>>>#<#N#fi2 {9x ,2Z2Z21̈́:W_z/ڭ1 33"%3G{,x%3PXz/s3!Oz"y^3 ʓ3 ^3O{,y3z/s3 ^3{ m3,> m3m3s3s33z/*3"~3 ¦3z/ڦ3 ~3,ʦ3 ž3z/ڦ3 ʦ3*5% 46!{ ʹ38"ͫi>ɷw#ç3ë03:Y22+ͫ3ͺ,ͺR 2Y21!6"9. :22Y*7"9"5z/<…4*/*+ ʹa4 /w#4ͪ ##"( !Y~226A :22Y:1ʢ F͆ͼ-Õ . 3+ͫz4X4 21z/<ʡ1*5% ~ʽ 4ý *5|B$ Ë3+ͫʻ4ͺ,ͺAÚ&ͳ,>.*( */ʹX4~#.4-:Y44=4~,ͫ͆w6:S =!\ ~++w!T 4#=47+6 !^ <=>!^ T 2C=# B=~/w!S Oyw#V=qv=NsY+k=a= W~w+€=y=!Z }=~w# •=8͆85>q=G4=͋=x µ=¬=! qA>+=? >>+=:Z <==!T ͕=! ͓=x=![ 5=7y2d + ~q+@>́9+~7wf<476|:`h%:~&-ʆ>+ʆ>+ͫP?.?E£>ͫL>·>~% ?#?!?D>?!>ͫ-++ͫ?>_{-?=?>8!7.: >?Æ> #>??=:i:8J>=8=yZ:7ҥ?t$͓9?ͻ8͸?}?s:J>́98s:f<}?&98z6{ ?0_2>! |"%:p@ @{"p@?6+9 @6-8#60: W: @@y@͜C!g F : _ =@x*=@Aqͫ]@E]@D]@0=@,=@.`@+60{i@+6${+p2 !g 6 WRB@Ҕ@B60K9C+~0ʣ@.K9@>"w#6+@6-/</ @:#p#w#6!g #zVAABzB͜C{̬8=WV)~#.+)#),7)z@W)~#>.©(# V)~##+)T)T]^###xG#z+v)xv)~-q)v)>W)̀Cxz?|"+ͫ7ʮ)2 ;ʫ), ͫ~#N#fi_x¯()*r(#Æ>*)̀̈́:*X An$"*X G> ʕ) *z>+2#* <0*" ү`i##N#F#&|<>!?> ! ~#`*Gok*0ڇ* ҇*_zWk*!i*’*O++*1ڨ* ! ,#+#*c+-+J++(^+*[+>1*~+#*!D+7o_D+~!++ܡ++#~++&H*~>\+~D++͡+5+>\~ow+#J+6H*oʑ+ +ʓ+ ʱ+ʱ+ ʱ+ c+_±+>_ʹ+++c+ ~77#~+w#ã+y+>c+ o&DM#Ϳ w+#c+x+~++&z z 56x'"W"ß5ͫͺ$ͺ(͆&~,06ͫt2¡1l2ͺ)}'"b6͡]6w# C6͆W"Éz/ڭ1P6!CD9z6D99x:[ 69Ҕ6/<&969c9gA7!X 6!77#47.W77G~_#~W#~O-7hcGy6JTeox62[ )zWyO6x\E7![ w6x![ 7F#~怩O69 4$ ~_#~W#~O!\ ~/woG}_}W}OP7CZQC7 o-yOzW{_xGS7V"vE88![ ~5pz68!e7t6!i7WEz6͸?1r8.͐8y27"7PX!6!7!X ~#8Wy7O|g}oxGz7CZQO&9!=398 .͐844+~2B8+~2>8+~2:8AOW_2E8}o|gxG>?S82E87y<=7{_zWyO)xG:E82E8y68![ 5687>.!d N#G.xʴ8}![ Gx8ƀw7c9w+8/67A9x7Gz6![ 47:[ :Z /<![ Op#6698<ʈB&@ Ap#6!f #:" ~ A*A+$Aͫ-+$0NA#ͫNA++wDAANA6%ArAC9A?+6%͓9iA8RBA_xBBCBB@_y;?A=?A{_xABBAByBOBGOCA*" =BPAZ:ѯB87RBy;?OzWO=? B.B/< B/>9=.C>9=p#=%C!T 39`Ck6<͍:69AD?BA9/{_#zW#yO++tC!7#69p#fC>âCGD>BN#F#*X /}o|gҵC"X p#=¢CBw1_cƤ~@zZrN vH Tʚ;@B''d GE(f կpD))))Dy=ʁDʍD0:ڊD ʚDlDjD!9&9!C39ñD=:8xDD 6yA9D:͓9|"Z "X ܝD9v7ʹ7&98;ANA C ; with drive select STA DREG ;select drive & side XRI ACCESS ;toggle access bit 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 ;wa!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  7:[ Ү8:ƀڮ8!e7n6ͮ7w69!6EfEJô7@.tpO.wnz*|P~&9;A9ʹ7&9~#39=ʹ7D9z6oE8!EE!F39!EȆw#O D9ʹ7:E<2E!FO n6A9{YOO6+F6!E4~֫Ew 6!FM9w+w+wE5Jʙ9v" GSљ e͘w>ROhFhiuh!mFn6&9I698&9:w6!qFt687YFk689!qFn69!uFWEId&X4#]I&9)F&969#F88D9:[ ڼFQY8!t6!FWE!mF J;xn{/|t1}=Z}~L~l */+6*Z~3â !I"+" * ^#V"t"H##^#V"##^#V"h##^#V" !"-2*2 2##"%! " *" !~>2Y"ZGF#~+w##lG+p"Z!ͫG/ʟG+6""Z#/ʟGͫGGpͫMʮGF ͫͺ:Gz{2YG" +ͫGͺ/ãG* +"  +:Y!F"792Y<s#r# =H#"/Iʹ "+" {ozg ?!pH|"!|"" ! "F Owned by Microsoft Memory size Bytes free BASIC Rev. 4.51 [CP/M Version] Copyright 1977 (C) by Microsoft (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:[ I "R",,"B:RFILEI #, AS N$I #,  AS I$I I I( N$(,)J2 I$(I) J< #,IJA I$JF I#JK+JL @JM "R",,"B:RFILESJN #,  AS N$bJP I mJZ #,IvJd N$~Jx IJ}JA I$Jensity 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 221@: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****************************************************************** * * * Cbios for CP/M Ver 2.2 for Disk Jockey 2D controller (all * * revs). Handles diskettes with sector sizes of 128 bytes * * single density, 256, 512, 1024 bytes double density. * * * * Written by Bobby Dale Gifford. * * 9/1/79 * * * * Disk Map of sectors used by Cold Boot, Warm Boot, Firmware, * * and CP/M: * * * * trk 0 sec 1 = First sector of cold boot. e700h * * 0 2 = Cold boot 256. 80h * * 0 3 = Cold boot 512. 80h * * 0 4 = Cold boot 1024. 80h * * 0 5 = Warm boot 256. 80h * * 0 6 = Warm boot 512. 80h * * 0 7 = Warm boot 1024. 80h * * 0 8 = Cold/Warm boot. 3200h * * 0 9 = Firmware. e400h * * 0 10 = Firmware+80h. e480h * * 0 11 = Firmware+100h e500h * * 0 12 = Firmware+180h. e580h * * 0 13 = Firmware+200h. e600h * * 0 ine djstat equ djram+27h ;Disk Jockey 2D status routine djerr equ djram+2ah ;Disk Jockey 2D error, flash led djden equ djram+2dh ;Disk Jockey 2D set density routine djside equ djram+30h ;Disk Jockey 2D set side routine ***************************************************************** * * * CP/M system equates. If reconfiguration of the CP/M system * * is being done, the changes can be made to the following * * equates. * * * ***************************************************************** msize equ 24 ;Memory size of target CP/M bias equ (msize-20)*1024 ;Memory offset from 20k system ccp equ 2d00h+bias ;Console command processor bdos equ ccp+800h ;BDOS address bios equ ccp+1600h ;CBIOS address 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 ********************* (HEX) db origin/4096+'A'-10 else db origin/4096+'0' endif if (origin/256 and 0fh) > 10 db (origin/256 and 0fh)+'A'-10 else db (origin/256 and 0fh)+'0' endif db '00H.' db acr,alf,0 ***************************************************************** * * * Utility routine to output the message pointed at by H&L, * * terminated with a null. * * * ***************************************************************** message mov a,m ;Get a character of the message inx h ;Bump text pointer ana 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 ***************************************************************** * * * Cboot is the cold boot loader. All of CP/M has been loaded in * * when control is passed here. * * * **************************************************************** 14 = Firmware+280h. e680h * * 0 15 = Firmware+300h. e700h * * 0 16 = Firmware+380h. e780h * * 0 17 = CCP. 2d00h * * 0 10 = CCP+80h. 2d80h * * 0 12 = CCP+100h. 2e00h * * 0 14 = CCP+180h. 2e80h * * 0 16 = CCP+200h. 2f00h * * 0 18 = CCP+280h. 2f80h * * 0 20 = CCP+300h. 3000h * * 0 22 = CCP+380h. 3080h * * 0 24 = CCP+400h. 3100h * * 0 26 = CCP+480h. 3180h * * 1 = Rest of CP/M. 3200h-4fffh * * * ***************************************************************** title '*** Cbios For CP/M Ver. 2.2 ***' ***************************************************************** * * * The following revision number is in reference to the CP/M * * 2.0 Cbios. * * * ***************************************************************** revnum equ 31 ;Cbios revision number cpmrev equ 22 ;CP/M revision number *********************************************************** * * * The following are internal Cbios equates. Most are misc. * * constants. * * * ***************************************************************** retries equ 10 ;Max retries on disk i/o before error acr equ 0dh ;A carriage return alf equ 0ah ;A line feed aetx equ 3 ;A ETX char aack equ 6 ;A ACK char clear equ 1ah ;Clear screen char on ADM3 terminal maxdisk equ 4 ;Maximum # of disk drives dblsid equ 8 ;Side bit from controller ***************************************************************** * * * 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 jmp const ;Console status routine jmp conin ;Console input cout jmp c* cboot lxi sp,tpa ;Set up stack call tinit ;Initialize the terminal lxi h,prompt ;Prep for sending signon message call message ;Send the prompt xra a ;Select disk A sta cpmdrv sta cdisk ***************************************************************** * * * 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 ;Address in warm boot jump shld wbot+1 lxi h,bdos+6 ;Address in BDOS jump shld entry+1 xra a ;A <- 0 sta bufsec ;Disk Jockey buffer empty sta bufwrtn ;Set buffer not dirty flag lda cdisk ;Jump to CP/M with currently selected disk in C mov c,a lxi d,cmndbeg ;Beginning of initial command lxi h,c************************************************** * * * The following equates relate the Thinker Toys 2D controller. * * If the controller is non standard (0E000H) only the ORIGIN * * equate need be changed. This version of the Cbios will work * * with 2D controller boards rev 0, 1, 3, 3.1, 4. * * * ***************************************************************** origin equ 0F800H djram equ origin+400h ;Disk Jockey 2D RAM address djcin equ djram+3h ;Disk Jockey 2D character input routine djcout equ djram+6h ;Disk Jockey 2D character output routine djhome equ djram+9h ;Disk Jockey 2D track zero seek djtrk equ djram+0ch ;Disk Jockey 2D track seek routine djsec equ djram+0fh ;Disk Jockey 2D set sector routine djdma equ djram+012h ;Disk Jockey 2D set DMA address djread equ djram+15h ;Disk Jockey 2D read routine djwrite equ djram+18h ;Disk Jockey 2D write routine djsel equ djram+1bh ;Disk Jockey 2D select drive routine djtstat equ djram+21h ;Disk Jockey 2D terminal status routonout ;Console output jmp list ;List device output 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 jmp listst ;List device status jmp sectran ;Sector translation djdrv jmp djsel ;Hook for SINGLE.COM program ***************************************************************** * * * Signon message output during cold boot. * * * ***************************************************************** prompt db acr,alf,alf db '0'+msize/10 ;CP/M memory size db '0'+(msize mod 10) db 'K CP/M Vers. ' ;CP/M version number db cpmrev/10+'0' db '.' db (cpmrev mod 10)+'0' db ', Cbios rev ' db revnum/10+'0','.' ;Cbios revision number db revnum mod 10+'0' db acr,alf db 'For Thinker Toys Disk Jockey 2D Controller ' db '@ 0' if origin/4096 > 10 ;Controller origincp+8 ;Command buffer mvi a,cmndend-cmndbeg+1 ;Length of command sta ccp+7 mov b,a call movlop lda cwflg ana a lda autoflg jz cldbot rar cldbot rar 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 1 ;Auto command feature ***************************************************************** * * * If there is a command inserted here, it will be given if the * * auto feature is enabled. * * For Example: * * * * cmnd***** * * * Setsec just saves the desired sector to seek to until an * * actual read or write is attempted. * * * ***************************************************************** setsec mov a,c ;Save the sector number sta cpmsec ;CP/M sector # ret ***************************************************************** * * * Setdma saves the DMA address for the data transfer. * * * ***************************************************************** setdma mov h,b ;hl <- bc mov l,c shld cpmdma ;CP/M dma address ret ***************************************************************** * * * Home is translated into a seek to track zero. * * * ***************************************************************** home mvi c,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 writever selected before mvi a,1 ;Select sector 1 of track 1 sta truesec sta cpmtrk call fill ;Flush buffer and refill jc zret ;Test for error return call djstat ;Get status on current drive ani 0ch ;Strip off unwanted 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 getdpb ;Get DPH pointer into DE xchg ; pop d mvi b,2 ;Number of bytes to move call movlop ;Move the address of XLT lxi d,8 ;Offset to DPB pointer dad d ;HL <- &DPH.DPB push h lhld origin+7 ;Get address of DJ terminal out routine inx h ;Bump to look at address of ; uart status location mov a,m xri 3 ;Adjust for proper rev DJ mov l,a mvi h,(origin+300h)/100h mov a,m ani dblsid ;Check double sided bit lxi d,dpb128s ;Base for single sided DPB's jnz sideok lxi d,dpb128d ;Base of double sided DPB's sideok xchg ;HL <- DBP base, DE <- &DPH.DPB pop d ;Restore DE (pointer into Dbeg db 'MBASIC MYPROG' * * cmndend db 0 * * * * will execute microsoft basic, and mbasic will execute the * * "MYPROG" basic program. * * * ***************************************************************** cmndbeg db '' ;Initial command goes here cmndend 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 wflg equ $-1 ;Test if beginning or ana a ; ending a warm boot mvi a,1 sta wflg sta cwflg ;Set cold/warm boot flag jz gocpm xra a sta wflg mov c,a call djdrv ;Select drive A mvi c,0 ;Select single density call djden mvi c,0 ;Select side 0 call djside mvi a,15 ;Initialize the see. * * * ***************************************************************** settrk mov a,c ;A <- track # sta cpmtrk ;CP/M track # ret ***************************************************************** * * * Sectran translates a logical sector # into a physical sector * * #. * * * ***************************************************************** sectran inx b push d ;Save table address push b ;Save sector # call getdpb ;Get DPB address into HL mov a,m ;Get # of CP/M sectors/track ora a ;Clear cary rar ;Divide by two sub c push psw ;Save adjusted sector jm sidetwo sidea pop psw ;Discard adjusted sector pop b ;Restore sector requested pop d ;Restor 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 lxi b,15 ;Offset to side bit dad b mov a,m ani 8 ;Test for double sided jz sidea ;Media is only single sided pop psPH) 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 setdrv1 call getdpb ;Get address of DPB in HL lxi b,15 ;Offset to sector size dad b mov a,m ;Get sector size ani 7h sta secsiz mov a,m rar rar rar rar ani 0fh sta secpsec xchg ;HL <- DPH ret zret lxi h,0 ;Seldrv error exit ret ***************************************************************** * * * Getdpb returns HL pointing to the DPB of the currently * * selected drive, DE pointing to DPH. * * * ***************************************************************** getdpb lda cpmdrv ;Get drive # mov l,a ;Form offset mvi h,0 dad h dad h dad h dad h lxi d,dpzero ;Base of DPH's dad d push h ;Save address of DPH lxi d,10 ;Offset to DPB dad d mov a,m ;Get low byte of DPB address inx h mov h,m ;Get low byte of DPB mov l,a pop d ret *****************************************ctor to read sta newsec lxi h,ccp-100h ;And the DMA address shld newdma call warmlod ;Read in CP/M lxi b,ccp+500h ;Load address for rest of warm boot call djdma mvi c,8 call djsec call warmrd jmp ccp+503h warmlod mvi a,15 ;Previous sector newsec equ $-1 inr a ;Update the previous sector inr a cpi 27 ;Was it the last ? jc nowrap sui 9 ;Yes cpi 19 rz lhld newdma lxi d,-480h dad d shld newdma nowrap sta newsec ;Save the new sector to read mov c,a call djsec lxi h,ccp-100h ;Get the previous DMA address newdma equ $-2 lxi d,100h ;Update the DMA address dad d shld newdma ;Save the DMA address mov b,h mov c,l call djdma ;Set the DMA address call warmrd jmp warmlod warmrd lxi b,retries*100h+0;Maximum # of errors wrmread push b call djtrk ;Set the track call djread ;Read the sector pop b rnc ;Continue if successful dcr b jnz wrmread ;Keep trying jmp djerr ************************************************************w ;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 l ; and sector mov l,a ret ***************************************************************** * * * Setdrv selects the next drive to be used in read/write * * operations. If the drive has never been selected before, a * * parameter table is created which correctly describes the * * diskette currently in the drive. Diskettes can be of four * * different sector sizes: * * 1) 128 bytes single density. * * 2) 256 bytes double density. * * 3) 512 bytes double density. * * 4) 1024 bytes double density. * * * ***************************************************************** setdrv mov a,c ;Save the drive # sta cpmdrv cpi maxdisk ;Check for a valid drive # jnc zret ;Illegal drive # mov a,e ;Test if drive ever logged in before ani 1 jnz setdrv1 ;Bit 0 of E = 0 -> N************************ * * * 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 ***************************************************************** * * * 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 commandb ;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 ***************************************************************** * * * 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 # 0 pop b ;Restore track # call djtrk ;Seek to proper track lda bufsec ;Get sector involved in operation push psw ;Save the sector # rlc ;Bit 0 of A equals side # ani 1 ;Strip off unnecessary bits mov c,a ;C <- side # call djside ;Select the side pop psw ;A <- sector # ani 7fh ;Strip off side bit mov c,a ;C <- sector # call djsec ;Set the sector to transfer lxi b,buffer ;Set the DMA address call djdma call djread ;The read operation is modified to write retryop equ $-2 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 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 type sta writtyp mvi a,1 ;Set write command db (mvi) or (b*8) ;This "mvi b" instruction causes ; the following "xra a" to ; be skipped over. ***************************************************************** * * * Read routine to buffer data from the disk. If the sector * * requested from CP/M is in the buffer, then the data is simply * * transferre fro th buffe t th desire 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 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 * * sectof ; 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 sector to transfer xchg ;DE = address in buffer lxi h,0 ;Get DMA address, the 0 is modified to ; 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 mover xra a ret into xchg ; call mover ;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 * * lxi d,cpmdrv ;Update the drive, track, and sector lxi h,bufdrv mvi b,3 ;Number of bytes to move call movlop ;Copy the data lxi h,djread jmp prep ;Select drive, track, and sector. ; Then read the buffer ***************************************************************** * * * Mover moves 128 bytes of data. Source pointer in DE, Dest * * pointer in HL. * * * ***************************************************************** mover mvi b,128 ;Length of transfer movlop ldax d ;Get a bte of source mov m,a ;Move it inx d ;Bump pointers inx h dcr b ;Update counter jnz movlop ;Continue moving until done ret ***************************************************************** * * * Terminal driver routines. Iobyte is initialized by the cold * * boot routine, to modify, change the "intioby" equate. The * * I/O routines that follow all work exactly the same way. Using * * iobyte, they obtain the address to jump to in order to execute* * the or 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 to contain the log2 secsiz equ $-1 ; of the physical sector size/128 ; on the currently selected disk. lda cpmsec ;Get the desired CP/M sector # push psw ;Temporary save ani 80h ;Save only the side bit mov c,a ;Remember the side pop psw ;Get the sector back ani 7fh ;Forget the side bit dcr a ;Temporary adjustment divloop dcr b ;Update repeat count jz divdone ora a ;Clear the cary flag rar ;Divide the CP/M sector # by the size ; of the physical sectors jmp divloop ; divdone inr a ora c ;Restore the side bit sta 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,4 ;Count loop dtslop dcr  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 if written into rz ;Not written, all done lxi h,djwrite ;Write operation ***************************************************************** * * * Prep prepares to read/write the disk. Retries are attempted. * * Upon entry, H&L must contain the read or write operation * * address. * * * ***************************************************************** prep xra a ;Reset buffer written flag sta bufwrtn shld retryop ;Set up the read/write operation mvi b,retries ;Maximum number of retries to attempt retrylp push b ;Save the retry count lda bufdrv ;Get drive number involved in the operation mov c,a call djdrv ;Select the drive lda buftrk ana a ;Test for track zero mov c,a push b cz djhome ;Home the drive if track desired function. There is a table with four entries for * * each of the possible assignments for each device. To modify * * the I/O routines for a different I/O configuration, just * * change the entries in the tables. * * * ***************************************************************** citty equ djcin ;Input from the Disk Jockey 2D cotty equ djcout ;Output to the Disk Jockey 2D ***************************************************************** * * * const: get the status for the currently assigned console * * device. The console device can be gotten from iobyte, * * then a jump to the correct console status routine is * * performed. * * * ***************************************************************** const lxi h,cstble ;Beginning of jump table jmp conin1 ;Select correct jump ***************************************************************** * * * csreader: if the console is assigned to the reader then a * * jump will be made here bits into position, used * by list and punch. * readr1 rar jmp seldev ***************************************************************** * * * punch: select the correct punch device. The selection comes * * from bits 4&5 of iobyte. * * * ***************************************************************** punch lxi h,ptble ;Beginning of punch table lda iobyte * * Entry at pnch1 rotates bits a little more in prep for * seldev, used by list. * pnch1 rar rar jmp readr1 ***************************************************************** * * * list: select a list device based on bits 6&7 of iobyte * * * ***************************************************************** list lxi h,ltble ;Beginning of the list device routines list1 lda iobyte rar rar jmp pnch1 ***************************************************************** * * * Listst: Get the status of the currently assigned list device * * * *********************t from 2d) dw ciptr ;Input from paper tape reader (currently ; SWITCHBOARD serial port 1) dw ciur1 ;Input from user reader 1 (currently ; SWITCHBOARD serial port 1) dw ciur2 ;Input from user reader 2 (currently ; SWITCHBOARD serial port 1) * * console status table * cstble dw cstty ;Status of tty (currently assigned ; by intioby, ststus from 2d) dw cscrt ;Status from crt (currently SWITCHBOARD ; serial port 1) dw csreadr ;Status from reader (depends on reader device ) dw csuc1 ;Status from user console 1 (currently ; SWITCHBOARD serial port 1) * * status from reader device * csrtble dw cstty ;Status from tty (currently assigned ; by intioby, status of 2d) dw csptr ;Status from paper tape reader (currently ; SWITCHBOARD serial port 1) dw csur1 ;Status from user reader 1 (currently ; SWITCHBOARD serial port 1) dw csur2 ;Status of user reader 2 (currently ; SWITCHBOARD serial port 1) * * Status from list e, where another jump will * * occur to the correct reader status. * * * ***************************************************************** csreadr lxi h,csrtble ;Beginning of reader status table jmp readera ***************************************************************** * * * conin: take the correct jump for the console input routine. * * The jump is based on the two least significant bits of * * iobyte. * * * ***************************************************************** conin call flush ;Flush the disk buffer lxi h,citble ;Beginning of character input table * * Entry at conin1 will decode the two least significant bits * of iobyte. This is used by conin,conout, and const. * conin1 lda iobyte ral * * Entry at seldev will form an offset into the table pointed * to by H&L and then pick up the address and jump there. * seldev ani 6h ;Strip off unwanted bits mvi d,0 ;Form offset mov e,a dad d ;Add offset mov a,m ;Pick u******************************************** listst lxi h,lstble ;Beginning of the list device status jmp list1 ***************************************************************** * * * If customizing I/O routines is being performed, the table * * below should be modified to reflect the changes. All I/O * * devices are decoded out of iobyte and the jump is taken from * * the following tables. * * * ***************************************************************** * * console input table * citble dw citty ;Input from tty (currently assigned ; by intioby,input from 2d) dw cicrt ;Input from crt (currently SWITCHBOARD ; serial port 1) dw reader ;Input from reader (depends on reader ; selection) dw ciuc1 ;Input from user console 1 (currently ; SWITCHBOARD serial port 1) * * console output table * cotble dw cotty ;Output to tty (currently assigned ; by intioby,output to 2d) dw cocrt ;Output to crt (currently SWITCHBOARD device * lstble dw ready ;Console always ready dw ready ;Get list status dw lslpt dw lslpt ***************************************************************** * * * The following equates set output device to output to the * * SWITCHBOARD serial port 1. * * * ***************************************************************** cocrt equ $ ;Output from crt couc1 equ $ ;Output from user console 1 coptp equ $ ;Output from paper tape punch coup1 equ $ ;Output from user punch 1 coup2 equ $ ;Output from user punch 2 colpt in 2 ;Output from line printer,get status ani 80h ;Wait until ok to send jz colpt mov a,c ;output the character out 1 ret ***************************************************************** * * * Custom I/O printer driver for Diablo printer with 1200 baud * * ETX/ACK handshake. * * * ***************************************************************** coul1 call colpt ;Output the character lda count dcr a stap high byte inx h mov h,m ;Pick up low byte mov l,a ;Form address pchl ;Go there ! ***************************************************************** * * * conout: take the proper branch address based on the two least * * significant bits of iobyte. * * * ***************************************************************** conout push b ;Save the character call flush ;Flush the disk buffer pop b ;Restore the character lxi h,cotble ;Beginning of the character out table jmp conin1 ;Do the decode ***************************************************************** * * * reader: select the correct reader device for input. The * * reader is selected from bits 2 and 3 of iobyte. * * * ***************************************************************** reader lxi h,rtble ;Beginning of reader input table * * Entry at readera will decode bits 2 & 3 of iobyte, used * by csreader. * readera lda iobyte * * Entry at reader1 will shift th ; serial port 1) dw list ;Output to list device (depends on ; bits 6&7 of iobyte) dw couc1 ;Output to user console 1 (currently ; SWITCHBOARD serial port 1) * * list device table * ltble dw cotty ;Output to tty (currently assigned ; by intioby,output to 2d) dw cocrt ;Output to crt (currently SWITCHBOARD ; serial port 1) dw colpt ;Output to line printer (currently ; SWITCHBOARD serial port 1) dw coul1 ;Output to user line printer 1 (currently ; SWITCHBOARD serial port 1) * * punch device table * ptble dw cotty ;Output to the tty (currently assigned ; by intioby,output to 2d) dw coptp ;Output to paper tape punch (currently ; SWITCHBOARD serial port 1) dw coup1 ;Output to user punch 1 (currently ; SWITCHBOARD serial port 1) dw coup2 ;Output to user punch 2 (currntlly ; SWITCHBOARD serial port 1) * * reader device input table * rtble dw citty ;Input from tty (currently assigned ; by intioby, inpu count rnz mvi a,50 sta count mvi c,aetx call colpt pwait call ciptr cpi aack jnz pwait ret count db 50 ***************************************************************** * * * The following equates set the input from the devices to come * * from the SWITCHBOARD serial port 1. * * * ***************************************************************** ciuc1 equ $ ;Input from user console 1 cicrt equ $ ;Input from crt ciur1 equ $ ;Input from user reader 1 ciur2 equ $ ;Input from user reader 2 ciptr in 2 ;Input from paper tape reader, get status ani 40h ;Wait for character jz ciptr in 1 ani 7fh ;Strip off the parity ret ***************************************************************** * * * console status routines, test if a character has arrived. * * * ***************************************************************** cstty call djtstat ;Status from Disk Jockey 2D stat mvi a,0 ;Prep for zero return rnz ;Nothing found 6,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 the * * specified characteristics. The tables are currently stored * * on track 0 sector 13. They are read into memory by the GOCPM * * routine in the CBIOS for CP/M ver 2.0. * * * ***************************************************************** ***************************************************************** * * * The following DPB defines a diskette for ble sided. ***************************************************************** * * * The following DPB defines a diskette for 128 byte sectors, * * single density, and double sided. * * * ***************************************************************** 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 9h ***************************************************************** * * * 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 1ah ***************************************************************** * * * The following DPB defines a diskette as 512 byte sec dcr a ;Return with 0FFH ret ***************************************************************** * * * The following equates cause the devices to get status from * * the SWITCHBOARD serial port 1. * * * ***************************************************************** csur1 equ $ ;Status of user reader 1 csur2 equ $ ;Status of user reader 2 csptr equ $ ;Status of paper tape reader csuc1 equ $ ;Status of user console 1 cscrt in 2 ;Status from crt, get status ani 40h ;Strip of data ready bit xri 40h ;Make correct polarity jmp stat ;Return proper indication ***************************************************************** * * * List device status routines. * * * ***************************************************************** lslpt in 2 ;All other devices wait ani 80h rz ready mvi a,0ffh ret ***************************************************************** * * * Tinit can be modified for different I/O setups. * * 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 1h ;16*((#cpm sectors/physical sector) -1) + ;log2(#bytes per sector/128) + 1 + ;8 if double sided. ***************************************************************** * * * 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 12h ;16*((#cpm sectors/physical sector) -1) + ;log2(#bytes per sector/128) + 1 + ;8 if double sided. *******************************************************tors, * * double density, and double sided. * * * ***************************************************************** dpb512d dw 120 ;CP/M sectors/track db 4 ;BSH db 15 ;BLM db 0 ;EXM dw 561 ;DSM dw 255 ;DRM db 0f0h ;AL0 db 0 ;AL1 dw 64 ;CKS dw 2 ;OFF db 3bh ***************************************************************** * * * 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 7ch ***************************************************************** * * * CP/M disk parameter headers, unitialized. * * * ***************************************************************** dpzero dw 0 ;Address of translation table (filled ; in by setdr * ***************************************************************** tinit mvi c,clear ;Initialize the terminal routine mvi a,intioby ;Initialize IOBYTE sta iobyte jmp cout ***************************************************************** * * * 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 cold 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,1********** * * * 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 33h ;16*((#cpm sectors/physical sector) -1) + ;log2(#bytes per sector/128) + 1 + ;8 if double sided. ***************************************************************** * * * 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 74h ;16*((#cpm sectors/physical sector) -1) + ;log2(#bytes per sector/128) + 1 + ;8 if douv) dw 0,0,0 ;Used by BDOS dw dirbuf ;Address of directory buffer dw 0 ;Address of DPB (filled in by setdrv) dw csv0 ;Directory check vector dw alv0 ;Allocation vector dpone dw 0 dw 0,0,0 dw dirbuf dw 0 dw csv1 dw alv1 dptwo dw 0 dw 0,0,0 dw dirbuf dw 0 dw csv2 dw alv2 dpthre dw 0 dw 0,0,0 dw dirbuf dw 0 dw csv3 dw alv3 ***************************************************************** * * * Cbios ram locations that don't need initialization. * * * ***************************************************************** cpmsec db 0 ;CP/M sector # cpmdrv db 0 ;CP/M drive # cpmtrk db 0 ;CP/M track # truesec db 0 ;Disk Jockey sector that contains CP/M sector bufdrv db 0 ;Drive that buffer belongs to buftrk db 0 ;Track that buffer belongs to bufsec db 0 ;Sector that buffer belongs to buffer ds 1024 ;Maximum size buffer for 1K sectors alv0 ds 75 ;Allocation vector for drive A alv1 ds 75 ;Allocation vector for drive B alv2 dto restart.$ Insert a Write Enabled Diskette in Drive $ Close the Drive Door and then Press RETURN: $ Function Complete. Type RETURN to return to CP/M, or F to Format another: $ Select a sector size: 1) 128 Byte Single density. 2) 256 Byte Double density. 3) 512 Byte Double Density. 4) 1024 Byte Double Density. Sector Size: $ $ESSG ;print the bad CALL pbuff ; input message JMP CROK ; and wait for input NOTLOW CPI 4 ;test for drive JP INPUTB ; select too large STA DRVNO ;save drive no. fmtsiz lxi d,denmsg ;Select the sector size call pbuff call rbuff cpi 'N' jz CROK sui '1' ;Strip off ASCII bias jp sizchk sizerr lxi d,bmessg call pbuff jmp fmtsiz sizchk cpi 4 jnc sizerr sta newsize SENDI LXI d,IMESSG ;send out the LXI h,JMESSG ; diskette insert CALL SENDMP ; message GETIN2 CALL rbuff ;wait for response CPI 'N' ;test for new JZ CROK ; parameter request PROCED lxi d,acralf call pbark are ones. * lxi 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 s 75 ;Allocation vector for drive C alv3 ds 75 ;Allocation vector for drive D csv0 ds 64 ;Directory check vector for drive A csv1 ds 64 ;Directory check vector for drive B csv2 ds 64 ;Directory check vector for drive C csv3 ds 64 ;Directory check vector for drive D dirbuf ds 128 ;Directory buffer end Ґ^H@Oy H H: –ͬ  #Hɦ: !  Hù H H $O͐Ӧ: 2 *CN#  ani dside jnz ixlopa 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 dh ;Offset pointer to 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 tr1*#~!www͎͎͓N2hA:{͎12i͎͓N1^{͎BU2k !8͓̓Ne͎:iO> ?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"  mov a,d ora a jnz 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 Mack read error counter 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  units mov h,a ;Place 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 byt@ 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 "= ! 1791. * call wnbusy ;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 re ori 0f0h ;Turn on 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 6Y: !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#Westore call unload 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 xra c mov c,a ;Save 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 d*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 ©=¨:   *R}2: "8 *8x *: *:&"R!;q:Y:; Y:Wҩ:; ʩ:2<ʘ:<€!<6<:<2!<ژ!6 >!Ҥ; !W6::;:TH:; !6*;M :; !W6!=q:=a/>z!=/H:=_2=:=!>q:>A/>Z!>/H8:> 2>:>:U=O>m:!} Hmd>9>!A6:2?*UM!E ^#VNJڗO *N*~2@*N#"Nm2@m͖ 2@m!6m!6m!6 m2@mͯ m!62m!62m!62m!A62@m'2:?2:Ғ:T2?!T6*@ME:?2T:A:Ҳ:X<2X2Aý:@ 2A:A} >ͯ ::@2@:*@M:  , in Ok Break!9~#b  T N#F#`izv C T  *|<ʗ :  D=96543>7@?2C: * "   *" 2 2 |< "  * ÷: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:ͯ !&6Ì]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. 2*">!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͈*ion 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 WHILEFIELD 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 filespP8`@` :; 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 ;=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# EA (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 z8O!B N#N ¾SP.* |} !9":q!"28!"9:] !ç 1THAT 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 ͍ !" >- Ͱ 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) 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>}|ͧ ¥   Ϳ Ͱ ͊ =¥ ` 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_#*: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) : -!6]:ͧz2~e:~2O! 6*~& 6$>!~_z*~& w!~5Bx:yͧ*v+"vv ~_{ozg001 $$$$ SUB;#ø##>%><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$$; 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 eharacter 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,aeader 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 rs ;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 messagtroller - 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 ce 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 "&! 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*ontroller 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:  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**ͪ"*! ͪ":!! ; 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 !!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  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 ***************************************************************** * !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 ***************************************************************** * * * 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 rel*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$$$$$$$LIBrompt 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.0 ***' 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 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. * * * ******************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 fidb 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 rst 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.$' ***************************************************************** 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 org 100h maclib diskdef disks 9 ***************************************************************** * * * 128 byte single sided. * * * ***************************************************************** diskdef 0,1,26,,1024,243,64,64,2,0 ***************************************************************** * * * 256 byte single sided. * * * ***************************************************************** diskdef 1,1,52,,2048,243,128,128,2,0 ***************************************************************** * * * 512 byte single sided. * * * ***************************************************************** diskdef 2,1,60,,2048,281,128,128,2 ***************************************************************** * * * 1024 byte single sided. * * * ***************************************************************** diskdef 3,1,64,,2048,300,128,128,2 ***************************************************************** * * * 128 byte double sided. * * * ***************************************************************** diskdef 4,1,52,,2048,243,128,128,2 ***************************************************************** * * * 256 byte double sided. * * * ***************************************************************** diskdef 5,1,104,,2048,487,256,256,2 ***************************************************************** * * * 512 byte double sided. * * * ***************************************************************** diskdef 6,1,120,,2048,562,256,256,2 ***************************************************************** * * * 1024 byte double sided. * * * ***************************************************************** diskdef 7,1,128,,2048,600,256,256,2 ***************************************************************** * * * M26 partitioning to 8 megabytes. * * * ***************** C************************************************ diskdef 8,1,1024,,4096,1974,2048,0,1 ***************************************************************** * * * other storage * * * ***************************************************************** endef 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*(&͠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"; 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 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*͠")*)) *)) 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#Wwrite ;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 ;dis>!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͐ 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 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 operatiok ;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 !bytes in a sector)(1H ,11X,12Hdouble sided)(1H ,11X,12Hsingle sided)(1H ,11X,48Hwrite protected (no further testing is possible))(1H ,11X,13Hwrite enabled)(6H0Drive,I2,14H is not ready.)(6H0Drive,I2,28H reports an ERROR condition:)"G"GGG*G[m:Gւ/2G'JI!Lu*G!L>kuͽ}2G:G@2GYJI!Lu*G!L>kuͽ}!Gh2GH!Lu*G!L>kuͽ}6H!LuG!L>kuͽ}IH!LuG!L>kuͽ}:G/2G;K*G+}2G*G}!G/2HJ>2G8K*G++}/2GJ>2G8K*G+++}/2GK>2G8K^H!LuG!L>]uͽ}2G@K> 2GH!LuG!L>kuͽ}*G}/2GtK!"GK*G+}/2G’K!"GK*G++}/2G±K!"GK*G+++}/2GK!"GKH!LuG!L>]uͽ}2GH!LuG!L>]uͽ}:G/2GFL*G~og>og{ozg}/2GAL2GFL>2G:Gog>og{ozg}/2GzLI!Luͽ}ÆL+I!Luͽ}:Gog>og{ozg}/2G¼LDI!Luͽ}2GI!Luͽ}>2G(54H Begin1NIMD0NIMA 1NIMA 0NIM1NIM1XAM0XAM1XAMA 0XAMA 0(52H Disk Test DJDMA: Production Acceptance (26_Aug_82))(1H ,6X,33HTo STOP testing type a period (.))(1H ,6X,50HTo obtain an ERROR REPORT type a question mark (?))(1H ,6X,20HBeginning Disk Test:)(6H Drive,I2,26H -> PASSED this test with:)(6H Drive,I2,26H -> FAILED this test with:)(1H ,5X,I5,12H Soft errors)(1H ,5X,I5,12H Hard errors)CA!Fuͽ}!ALG!r/2A>CsERROR >2A:A=2AC:Aog)"A}A"A!*As#r*AA"A!*As#r*A=A"A!*As#r*AMA"A!*As#r*A]A"A!*As#r*AmA"A!*As#r:A<2ACCA!Fuͽ}"B!Fuͽ}`B!Fuͽ}!"A:>A/2AE22A!FWcogͪt!ASA!>AIog>og{ozg}/2A^E!>AͪMog>og{ozg}/2AD!>A`Oog>og{ozg}/2AD!>APog>og{ozg}/2AD:/2AEB!Fu>A!F>kuͽ}ning: Timing test (average of five revolutions):)(1H ,5X,F4.1,9H% Error (,F5.1,28Hms) is within limits [2.0%].)(1H ,5X,F4.1,9H% Error (,F5.1,25Hms) out of limits [2.0%].)"L!Ob!LS!"LL!Ouͽ}>2L:L=2L~NLG*Lm*Lͪt!LS:G/2L-N!Lb!Or! Or!LS*L"L?N!Lb!$Or!LS!Lb! Or!(Os!LS!Lb!Lͅr!LS*L*L"L:L<2LM!Lb!,Or!LS*Lͪt!LS!0Or!LS!Ljr!4Or=2LN1M!OuLL!O>duͽ}>2LOoM!OuLL!O>duͽ}!Ld2L2L:LfVPzH H(21H Beginning: Seek test)"AOFO!Ouͽ}>29O:G2DO:DO2EOODO*AOP/2EO£O29OO:DO2DODO*AOP/2EOO29OO:DO2DO|O:9OO(1H ,10X,20H Seek error on track,I3)"O"O>2O:O!G=2OSP:O og"O>*Ow:O<2O#P2O>2O*O!PWc/2OP*O"OOO*O n:O@2OPO!Pu*O!P>kuͽ}!Od/2O¿P2O*O!PWc/2OP2O:O"P*PͷQEB!Fu>A!F>kuͽ}B!Fu!F>kuͽ}B!Fu!F>kuͽ}A!FWcogͪt!AS:>Aog)"A?A"A:og*As#r*A_A"A*A_A~#fo:og*As#r*AOA"A:og*As#r*AoA"A*AoA~#fo:og*As#r:>A<2>A D*k>2A:A=2AtF:Aog)"A}A"A*A=A~#fo*As#r*AA"A*AMA~#fo*As#r*A=A"A!*As#r*AMA"A!*As#r:A<2AE*]uͽ}*Fw2Fog>og{ozg}/2FGQm G!Guͽ}>2FGGGGG(6H0Drive,I2,36H is active. Its characteristics are:)(1H ,6X,I4,5H inch)(1H ,6X,I4,7H tracks)(1H ,6X,I4,48H = Invalid number of sectors per track size code)(1H ,6X,I4,8H sectors)(1H ,6X,I4,47H = Invalid number of bytes per sector size code)(1H ,6X,I4,18H "/2PQ2P*PW/2P%Q2P>2P(41H Beginning: Sector Write-Read-Verify test)(1H ,11X,52HError: media is WRITE PROTECTED (test not performed))"4QHQ!cSuͽ}!ͪt!BQS:Gog>og{ozg}/2FQRvQ!cSuͽ}!?Qd2?Q2,Qog{ozg}/2FQ³Rog{ozg}!FQ/2GQ°R2,QRog{ozg}/2FQUSog{ozg}!FQ/2GQRS2,QÿR>2,Q}S~S}S~S(1H ,10X,21H Write error on track,I3,6H, side,I2,8H, sector,I3)"tS"vS`i"xS2}S>2~S*xSw*G"S*S}=/2S T*S:!"S*vS~*Sw*S+"SS*vS"SS|S*tSn:|S@2S€TS!TuS*vS!T>kuͽ}!|Sh!{Sd/2SyT>*xSw2lSÅT>2lS:lSTTTTTT(1H ,10X,20H Read error on track,I3,6H, side,I2,8H, sector,I3)(1H !=2#\´]*\"(\*\"*\(\"\*\ n:"\@2#\u]0\!C^u*\DM*\!?^>kuͽ}!"\h!!\d/2#\p]>*\w2\!!\B_og>og{ozg}/2#\£]>2\:<2: \<2 \\>2 \: \!G=2#\#^: \og~@2#\^`\!C^u*\",\,\*\!?^>kuͽ}: \og~2"\!"\h: \<2 \ù]!!\d/2#\:^>*\w2\(1H ,10X,22H Verify error on track,I3)"P^"R^`i"T^*G:Gogu"Z^*Z^}=/2\^"_*Z^"]^:"_^*]^:!"a^*_^~*a^2\^_c^!,_u*R^!(_>kuͽ}!X^d/2\^_>*T^w2H^*Z^+"Z^æ^>2H^"9_>21_>2;_:;_!G=2<__:;_ og"=_~2<_*=_~@!<_/2?_»_:;_2<_og"=_>@*=_w:<_ og"@_>*@_w_:;_2<_og"=_:<_ og~*=_w:<_ og"@_*@_w21_:;_<2;_O_:1_(1H ,11X,46HBad function argument given to GETTRK function,I3)" `" `* `~=/2x`a:Gogͪt!t`S>2s`!aq!t`sq* `w:s`=2r`:;***************************************************** ;* * ;* 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,10X,22H Verify error on track,I3,6H, side,I2,8H, sector,I3)"T"T`i"T2T>2T*Tw*G"T*T}=/2TU*T:!"T*T~*Tw*T+"T\U*T"TTT*T͢n:T@2TUT!VuT*T!V>kuͽ}!Th!Td/2TU>*Tw2T*T~/2TV!"T V*G"T*T}=/2TˆV*T"T:"T*T:!"T*T~*T2T~VT!VuT*T!V>kuͽ}!Td/2TyV>*Tw2T*T+"T V>2T(40H Beginning: Track Write-Read-Verify test)(1H ,11X,52HError: media is WRITE PROTECTED (test not performed))"VV!Wuͽ}:Gog>og{ozg}/2VhWV!Wuͽ}!Vdq2V2Vɯ2V:V==2VW!VX:G=2V:V2VW2V:V==2VWVV*VͦX/2VW2V:G/2VWW:V<2VØW:V=2VÈW:V<2VlW>2V"W*W~/2X'X>2W>_2X1X>m2W>2X*G:Gogu"X*X}=/2X‡X*X:!"X:W*Xw*X+"X:!"X:X*Xw*X+"XBXXX"X"X`i"X2X>2X*X!YWcog>og{ozg}/2XX:X*X"XX*X*XdZo!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+++ #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 systemg>og{ozg}/2XˆY*X"XX*X*X͞\og>og{ozg}/2XˆYX*X*X͉^og>og{ozg}/2XˆY:X*X!YWc2X:Xog>og{ozg}!X/2XY2X:XY(1H ,10X,21H Write error on track,I3,6H, side,I2)(1H ,10X,21H Write error on track,I3,6H, side,I2,8H, sector,I3)"Y"Y>!Y#>2Y:Y!G=2Y¾Z:Y2Y og"Y*Yw:Yog"Y>@*Yw:Y<2YxZ>2Y:Y!=2Yz[*Y"Y*Y"YYY*Yan:Y@2Y;[Y! \u*YDM*Y!\>kuͽ}!Yh!Yd/2Y6[>*Yw2Y!YB_og>og{ozg}/2Yi[>2Y:<2:Y<2YZ>2Y:Y!G=2Y[:Yog~@2Y[%Z! \u*Y"YY*Y!\>kuͽ}:Yog~2Y!Yh:Y<2Y[!Yd/2Y\>*Yw2Y \(1H ,10X,20H Read error on track,I3,6H, side,I2)(1H ,10X,20H Read error on track,I3,6H, side,I2,8H, sector,I3)"\"\>!\#>2 \: \!G=2#\\: \2#\ og"$\*$\w:#\og"&\>@*&\w: \<2 \ò\>2 \: \# 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 ;h**************** 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 ost 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  ;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 ; ;***************************************************** ;* $1*" 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 @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û!^*"*:|: |Ë  |*" ͩ !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!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&)^#fk%; 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 ; tracks 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 ;; generators 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&***************************************************************** * * * Disk format program for Disk Jockey 2D controller. * * 11/16/79 * * * ***************************************************************** title '*** Format Program for CP/M Ver. 2.0 ***' org 100h revnum equ 52 ;Revision # times 10 bdos equ 5 ;CP/M entry point wboot equ 0 origin equ 0F800H DISKIO EQU ORIGIN+3f8h DATREG EQU DISKIO+7 DRVSEL EQU DISKIO+1 CSTALL EQU DISKIO+3 CMDREG EQU DISKIO+4 DSIDE EQU 10Q UNLOADB EQU 17Q WTCMD EQU 364Q SICMD EQU 131Q IMMIRQ EQU 320Q UNLOADA EQU 30Q RESTOR EQU 11Q 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 START lxi sp,stack LHLD ORIGIN+7 ;adjust INX H ; the MOV A,M ; calling LXI H,STDVSL+1 ; routines LXI D,4 ; for MOV M,A ; different XRI 3 ; versions DAD D ; of the MOV M,A ; disk DAD D ; jockey a newsize add a jz findix mov l,a mvi h,0 DAD D MOV C,M INX H MOV B,M LXI H,SLIST CALL OVLAY LXI B,DDLIST LXI H,DLIST CALL OVLAY call model lxi b,lhddena jz loadd lxi b,lhddenb loadd mov a,b call stbits mov a,c call stbits FINDIX CALL INDEXP MVI H,1 TKSTEP mvi a,'*' call pchar LXI D,CMDREG MVI A,SICMD STAX D WSICMS LDAX D RAR JNC WSICMS WSICMD LDAX D RAR JC WSICMD CALL TRACK MOV H,D INR H MVI A,77 CMP H JNZ TKSTEP call unload lxi d,fmessg call pbuff call rbuff cpi 'F' jz crok jmp wboot SENDMP PUSH h ;save second half CALL pbuff ;send first half LDA LETTER ;print the CALL pchar ; letter POP d ;send the second pbuff mvi c,9 jmp bdos rbuff lxi d,inbufx mvi c,10 call bdos lda inbufx+1 ana a mvi a,acr rz lda inbuf cpi 'a' rc cpi 'z'+1 rnc sui 40q ret 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 inbufx  and data mark WTL9 MVI M,0FBH ;data mark LXI B,0e540H ;data & count OVLS2 EQU $-2 WTL10 MOV M,B ;write first DCR C ; quarter of JNZ WTL10 ; sector data MVI C,40H ;count OVLS3 EQU $-1 WTL11 MOV M,B ;write second DCR C ; quarter of JNZ WTL11 ; sector data MVI C,40H ;count OVLS4 EQU $-1 WTL12 MOV M,B ;write third DCR C ; quarter of JNZ WTL12 ; sector data MVI C,40H ;count OVLS5 EQU $-1 WTL13 MOV M,B ;write fourth DCR C ; quarter of JNZ WTL13 ; sector data MVI M,0F7H ;crc data bytes MVI A,27 ;last sector + 1 OVLS6 EQU $-1 LXI B,4E36H ;count & data OVLS7 EQU $-2 WTL14 MOV M,B ;data DCR C ; postamble JNZ WTL14 ; field CMP E ;last sector test JNZ SLOOP WTL15 MOV M,B ;fill data DCR C ; to index hole JNZ WTL15 WTL16 MOV M,B ;fill data DCR C ; to index hole JNZ WTL16 WTL17 MOV M,B ;fill data DCR C ; to index hole JNZ WTL17 RET OVLAY MOV A,M ;length of list PUSH H ;save list ptr LXI H,WTRACK ;overlay area XTHL ; recoMOV M,A ; controller LXI d,SMESSG ;print the CALL pbuff ; sign on message CROK LXI d,DMESSG ;echo the CR and CALL pbuff ; print drive select CALL rbuff ;wait for response CPI 'N' ; new parameter JZ CROK ; request STA LETTER ;save for exit SUI 'A' ;test for good JP NOTLOW ; drive select INPUTB LXI d,BMESSG ;print the bad CALL pbuff ; input message JMP CROK ; and wait for input NOTLOW CPI 4 ;test for drive JP INPUTB ; select too large STA DRVNO ;save drive no. fmtsiz lxi d,denmsg ;Select the sector size call pbuff call rbuff cpi 'N' jz CROK sui '1' ;Strip off ASCII bias jp sizchk sizerr lxi d,bmessg call pbuff jmp fmtsiz sizchk cpi 4 jnc sizerr sta newsize SENDI LXI d,IMESSG ;send out the LXI h,JMESSG ; diskette insert CALL SENDMP ; message GETIN2 CALL rbuff ;wait for response CPI 'N' ;test for new JZ CROK ; parameter request PROCED lxi d,acralf call pbuff LDA DRVNO ;get the drive no MOdb 10,0 inbuf db 0,0,0,0,0,0,0,0,0,0 STDVSL STA DISKIO+1 RET STBITS STA DISKIO+2 RET GTSTAT LDA DISKIO+2 RET model lda diskio-4 cpi (ret) ret unload call model mvi a,unloada jz stbits mvi a,unloadb jmp stbits gtindx call model mvi b,0 rz mvi b,index ret INDEXP call gtindx windxh call gtstat ANI INDEX xra b JZ windxh windxl call gtstat ani index xra b jnz windxl ret indxw call gtindx jmp windxl TABLE DW L128 DW L256 DW L512 DW L1024 TRACK lda select call stdvsl XRA A STA SIDENO CALL WTRACK call gtstat ANI DSIDE RNZ INR A STA SIDENO LDA SELECT ANI 357Q call stdvsl WIL call indxw XCHG WTRACK LXI D,DATREG ;1791 data reg MVI L,1 ;initialize sector reg LXI B,4e50H ;data & count OVLD1 EQU $-2 MVI A,WTCMD ;issue a write STA CMDREG ; track command XCHG ;adjust the registers WTL1 MOV M,B ;index mark DCR C ; preamble JNZ WTL1 ; field LXI B,0CH ;data & count OVLD2 EQU $-2 WTL2 MOV M,B ver pointer MVI D,0 OVLAY1 INX H ;increment pointer MOV E,M ;get offset XTHL ;exchange pointers DAD D ;add the offset PUSH PSW ;save length count LDAX B ;get replacement data MOV M,A ;do the replacement INX B ;next replacement data POP PSW ;recover length count DCR A ;decrement XTHL ;exchange pointers JNZ OVLAY1 POP H ;adjust stack RET * The lists below represents the distances * between successive locations of the WTRACK * routine that are to be overlaid in order * that the same routine will serve to format * different sized and density diskette * sector formats DLIST DB 18 ;length of list DB OVLD1-WTRACK DB 1 DB OVLD2-OVLD1-1 DB OVLD3-OVLD2 DB 1 DB 1 DB OVLD4-OVLD3-2 DB 1 DB OVLD5-OVLD4-1 DB OVLD6-OVLD5 DB 1 DB 1 DB OVLD7-OVLD6-2 DB 1 DB OVLD8-OVLD7-1 DB OVLD9-OVLD8 DB 1 DB 1 SLIST DB 9 ;list length DB OVLS1-WTRACK DB OVLS2-OVLS1 DB 1 DB OVLS3-OVLS2-1 DB OVLS4-OVLS3 DB OVLS5-OVLS4 DB OVLS6-OVLS5 DB OVLS7-OVLS6 V C,A MVI A,177Q ;drive select bits QLOOP RLC ;rotate select bits DCR C ; to proper drive JP QLOOP ; position ani 3fh STA SELECT ;save for TRACK routine call stdvsl call model lxi b,lhsdena jz prep lxi b,lhsdenb prep mov a,b call stbits mov a,c call stbits lxi h,cmdreg mvi m,immirq mvi a,40h wirqd dcr a jnz wirqd mov a,m rar jc notrdy ral ral jc notrdy lxi d,wmessg ral jc notrdyx LXI D,0 call gtindx IXLOOP call gtstat ani index xra b JNZ dorest DCX D MOV A,D ORA E JNZ IXLOOP NOTRDY LXI d,RMESSG ;not ready message notrdyx xchg LXI d,AMESSG ;drive message CALL SENDMP ;send error message call unload JMP SENDI ;back for more input dorest MVI M,RESTOR wrstrs mov a,m rar jnc wrstrs wrstrd MOV A,M rar jc wrstrd MOV A,M ANI TRKZRO JZ NOTRDY LXI B,SDLIST LXI H,DLIST CALL OVLAY LXI B,L128 LXI H,SLIST CALL OVLAY mvi a,'*' call pchar CALL INDEXP MVI H,0 CALL TRACK LXI D,TABLE ld;index mark DCR C ; zero leader JNZ WTL2 ; field OVLD3 MVI M,0F6H ;special double MVI M,0F6H ; density clock MVI M,0F6H ; and data mark WTL3 MVI M,0FCH ;index mark LXI B,4E32H ;data & count OVLD4 EQU $-2 WTL4 MOV M,B ;sector mark DCR C ; preamble JNZ WTL4 ; field SLOOP LXI B,0CH ;data & count OVLD5 EQU $-2 WTL5 MOV M,B ;sector mark DCR C ; zero leader JNZ WTL5 ; field OVLD6 MVI M,0F5H ;special double MVI M,0F5H ; density clock MVI M,0F5H ; and data mark WTL6 MVI M,0FEH ;sector mark MOV M,D ;track number MVI M,0 ;side number SIDENO EQU $-1 MOV M,E ;sector number MVI M,1 ;sector length OVLS1 EQU $-1 MVI M,0F7H ;crc data bytes INR E ;increment sector LXI B,4E16H ;data & count OVLD7 EQU $-2 WTL7 MOV M,B ;sector mark DCR C ; postamble JNZ WTL7 ; field LXI B,0CH ;data & count OVLD8 EQU $-2 WTL8 MOV M,B ;data mark DCR C ; zero leader JNZ WTL8 ; field OVLD9 MVI M,0F5H ;special double MVI M,0F5H ; density clock MVI M,0F5H ;' DB 1 * Overlay data for single density * formatted diskettes SDLIST DW 0FF28H DB 6 JMP WTL3 DW 0FF1AH DB 6 JMP WTL6 DW 0FF0BH DB 6 JMP WTL9 * Overlay data for double density * formatted diskettes DDLIST DW 4E50H DB 0CH MVI M,0F6H DB 36H DW 4E32H DB 0CH MVI M,0F5H DB 36H DW 4E16H DB 0CH MVI M,0F5H DB 36H * Overlay data for single density * 26 sectors/track 128 byte sectors L128 DB 0 DW 0e520H DB 20H DB 20H DB 20H DB 27 DW 0FF1BH * Overlay data for double density * 26 sectors/track 256 byte sectors L256 DB 1 DW 0e540H DB 40H DB 40H DB 40H DB 27 DW 4E36H * Overlay data for double density * 15 sectors/track 512 byte sectors L512 DB 2 DW 0e580H DB 80H DB 80H DB 80H DB 16 DW 4E6AH * Overlay data for double density * 8 sectors/track 1024 byte sectors L1024 DB 3 DW 0e500H DB 0 DB 0 DB 0 DB 9 DW 4E74H AMESSG db acr,alf db 'Drive $' RMESSG db ' Is Not Ready.$' WMESSG db ' Is Write Pr 4 ;Upper limit jp 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,Y! d! ~Y#=%iʎ%à&O[H> 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+ȸ#"otected.$' BMESSG db acr,alf db 'Improper Response.$' DMESSG db acr,alf db 'Select Drive (A,B,C,or D): $' SMESSG db 'Disk Jockey 2D Disk Format program' db ' Revision ' db '0'+revnum/10,'.','0'+(revnum mod 10) db acr,alf db 'Type "^C" to return to CP/M, "N" to restart.$' IMESSG db acr,alf db 'Insert a Write Enabled Diskette in Drive $' JMESSG db acr,alf db 'Close the Drive Door and then Press RETURN: $' FMESSG db acr,alf db 'Function Complete.' db acr,alf db 'Type RETURN to return to CP/M, or F to Format another: $' denmsg db acr,alf db 'Select a sector size:' db acr,alf db ' 1) 128 Byte Single density.' db acr,alf db ' 2) 256 Byte Double density.' db acr,alf db ' 3) 512 Byte Double Density.' db acr,alf db ' 4) 1024 Byte Double Density.' db acr,alf db 'Sector Size: $' acralf db acr,alf,'$' letter db 0 drvno db 0 select db 0 newsize db 0 ds 50 stack equ $ end C or D (RETURN to exit): $' 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,'<֌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([])estination message sselec 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$' * * Data space * 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 (, ~,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! ((! ( d !@ #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/<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 ! ->!  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!_.!!!/!: -!<-!> >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)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* * CUy!@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 ͋9dU>  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,{ʦ _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> @+|*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|g2de2de>2d:d(1H ,14X,53H Controller failed to respond before time out occured)(1H ,14X,30H Normal completion - no errors)(1H ,14X,22H Improper command code)(1H ,14X,25H Illegal disk drive value)(1H ,14X,16H Drive not ready)(1H ,14X,20H Illegal track value)(1H ,14X,17H Unreadable media)(1H ,14X,38H Improper sector header - no sync byte)(1H ,14X,32H CRC error in sector header read)(1H ,14X,11H Seek error)(1H ,14X,45H Compare error in sector header scan (status:,I5,1H))(1H ,14X,24H CRC error in data field)(1H ,14X,39H Illegal sector value for current media)(1H ,14X,25H Media is write protected)(1H ,14X,40H Lost data - DMA channel did not respond)(1H ,14X,39H Lost command - channel did not respond)(1H ,14X,28H Unrecognizable error code =,I5)"e*e~/2e!h!e!;juͽ}6j*e~@/2eAhce!;juͽ}6j*e~ր/2eahe!;juͽ}6j*e~ց/2ehe!;juͽ}6j*e~ւ/2e¡he!;juͽ}6j*e~փ/2ehe!;juͽ}6j*e~ք/2ehf!;juͽ}6j*e~օ/2ei3f!;juͽ}6Jb!qq!qb!qȆw!qO s:q<2q!qO ͅr!^#V#N#F#{YOO6+F6!q4~֫wqw (!qSw+w+wSq5Jʙ9v" GSљ e͘w>hFhiuhͪtþqb!w#qÒq} rqr r1u!F#^#V#Nr}~#qG++NyÚq!b>Mr%r:͋[ryIr!6>ug>|t!>rakbqrptqrÒbqr!~+>wÒͼtÈr̓ʒ:kқr/< uҒ1ug!r~_#~W#~O#4Ճ.惯G~_#~W#~Ot(ͼtr̓ʒ>OËrͼtr̓t͒ȯGPt"y2Fou u!D*:O:s4ՃRsbsg.*:Oz;sbsg.*:Hsx<=ys{_zWxG)yOHGͰs> 2ō!PA"ƍ!US"ȍ!E "ʍs*nj6 ތ*nj6 T'̍~#·s!ō ~ό#sͰs> 2ō!ST"ƍ!OP"ȍ! "ʍs'ͼts̓n͒Pty+F+F+Fw`h|Htgy,t:O|g}oxG-| t}t(ElaOt!~Gxhtƀw1uw+ɷՃyx{n!6>uwgtzt >|{>2(/2!^" :^^<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 j*e~ֆ/2e!iff!;juͽ}6j*e~և/2eAif!;juͽ}6j*e~֍=Ɓ2e*e~ֈ?!e/2 e~if!;ju*e!7j>kuͽ}6j*e~֎/2ežif!;juͽ}6j*e~֏/2e¾ig!;juͽ}6j*e~֐/2eiEg!;juͽ}6j*e~֑/2eikg!;juͽ}6j*e~֒/2ejg!;juͽ}6jg!;ju*e!7j>kuͽ}(23H0Error Report on trial:,I7)(1H ,6X,12HDrive ,8(I7))(1H ,3X,20HErrors on LAST trial)(1H ,3X,20HErrors on THIS trial)(1H ,3X,20HErrors on ALL trials)(1H ,6X,12HSoft Errors ,8(I7))(1H ,6X,12HHard Errors ,8(I7))(1H )Lj!!mu]uͽ}>2@j:@j=2Ijvk:@j@jog"Jj:@j=*Jjw:@j<2@jFkkj!!mu>2@j:@j@jog"Jj*Jj!m>ku:@j< kͽ}j!!muͽ}j!!mu>2@j:@jog)}A"Jj*Jj!m>]u:@j< kͽ}k!!mu>2@j:@jog)A"Jj*Jj!m>]u:@j< kͽ}j!!muͽ}j!!mu>2@j:@jog)=A"Jj*Jj!m>]u:@j!>A<7lͽ}k!!mu>2@j:@jog)MA"Jj*Jj!m>]u:@j!>A2@j:@jog)]A"Jj*Jj!m>]u:@j< lͽ}k!!mu>2@j:@jog)mA"Jj*Jj!m>oG}_}W}OFun||DM!>)),u =$u!~7w?##wy7O**""!}u!}u!}u!}u!"5I~#fo"yI"O*y"S:ʨu:wÎu͔Îu>22<2}u>2u2222}~#fo"!ō"V~#+u!"!9##"[u:vgo""""Wv!>#*~#1vgo"*~#?vgo"*~#fo"*~#foWv"222222qgo""S*|ʏv *"(_:2Z2[2X2Y<2:>Z}ͽyv ¹v> ͢wìv:s/͢=w:GE~͢w!w# 0w:bw*ZDM*X"*V *Ów`i"Z"O*XDM*X"*O*V ́w`i"X^w:*+}|w:±w*"X>Z}*VÅw>Z}*X"*VÅww#=„w*S+"S|w<w>G!\60#ɂ!s4:0w˃w"~:#x w+xw!\|8x}8x!s4#"v|/W}/_*">2q:?{с:rG:jxx2pw:yx2u}:x0E~!p5ʫx<ˆx:pxʫx}ÛxE:qʶxDE~:s!2sx+x-/<2sE~:s_! ˄{0GE~}0GE~:?{с:r`=/2x`6a:r` `og~* `/2x`,a6a:r`=2r``:r`/2x`aa:s` `og"y`* `~*y`w:s`<2s`:s`!G=/2x``>2s`>2`* `~/2x`a:s`!G=/2x`¨a2`:s` `og~* `w:s`<2s`>2`{`!au* `!a>kuͽ}2`(1H ,11X,35HThe bad track table has been filled)(1H ,11X,48HThe following tracks failed during drive testing)(1H ,15X,5HTrack,I4)(1H ,11X,38HThere were no bad tracks on this drive)(1H ,11X,46HBad function argument given to BADTRK function,I3)"a"a*a~=/2bbxc>2_b2a*a~/2bbc:_bd=2bb¾c:_baog"cb*a~*cbw:_b<2_b>2aceb!duͽ}2a:a*a~/2bb/d:_b=og"`b*`b}=/2bb*d*`ba~*a/2bb d>2a*`b+"`bc2a*a~/2bbd:_b==/2bb²db!duͽ}!"`b*`b:_bog{ozg}/2bb¯db!du*`ba"cb*cb!d>kuͽ}*`b#"`bbdþdb!duͽ}2ac!du*a!d>kuͽ}>2a"d:<2!]u:@j< lͽ}%k!!muͽ}>&2P>2S>Lo!kp"Qmo*p:pw*p:qw#:qw!p"Qmo>Lo>2p!;"p!p"Qmo*p~2p2p!p"Qmo:p*pw:pGʜm>Þm>*pwxʭm>(ïm>M*pw:p*qw#>wxm:pm>m>*qw:p@m>m>*qw>Lo*p~2p*p~n>n> 2p!p"Qmo*p: qw#:qw>Lo>2p*p~2p*p~2p*p~2p!;"p!p"Qmo!p"Qmo*p:pw>Lo>2p*p~2p*p~2p*p~2p!;!"p!p"Qmo!p"Qmo*p:pw>Lo>2p*p~2p*p~2p*p~*q2p*q~2p!p"Qmo!;"p!p"Qmo!p"Qmo*p:pw>Lo>2p*p~2p*p~2p*p~*q2p*q~2p!p"Qmo!;!"p!p"Qmo!p"Qmo*p:pw"p"pdo`i"p==!p#>2p:p¤ozʤoͦoxo:p ozʠoͦoÌo o.o*7o?o*k7?!7?~O0#z C0CCCC:0_!gc!gc[S"2:@OA>=u#|go-0@q0&pp00&p#&p "&ppP0"@ q0&p)!&p*!&p &p!&p(&p%+rG!s:wyw2u:r2p:s,y2u!pw}:s/Vy*"!"}!s4Fy*"}Vy:?{с:s]x!r/<]xFw!{~w2!~w<2x22{2r2>2 E~éy**DM*0z+|¾y""÷**FE~*#"*+"|#y÷*ZDM!5&z*X+}|+z*V ~2`i"Z>z> zy9z !40z:~I”z:=[z==[z=[zbz:rfz:!wz:|z#lz:ʦ:ʎzæ>2U:ҥz:!r:tºz:|ºz:xw~/2с:sw:s2p2u}!~{/W+~/_>22s! ˄}0o!s4{¤{!\:sG2p2u2s#{!\"v}V+^à{|{0z {>00{:{02>ɯ2r2t2||-|>2"|+%||*Z+"Z!4;|:.M|>2t2s;|:@zE]|Db||+q|-v|>2U|y2|*Z+"Z!4{|Ox ڜ|:> GÇ|:Uxʱ|/<2sG!r~w@z{:¾|ͣ}ͺͺ'wͺ:!w#w|'w!r:swþ|0z |CZQ o-yOzW{_xG`iN#F#q#p#=&2K""`i"L2N:N^!_r:K*Lw_~#fo:N<2NW:KҊ!!>2@j:@jog)=A"Jj*Jj!>:@j!>A #w#҅R>w: _ V Gr*%|x}{"ʅ"%Ay ʭ*|ʡ­Ƈ<ʿyw>7<@ڇO@؇y8%6!~{2ڇ:>0[*V*X&2w#)́7[*V>2Xw? [2Ʌ:X:Xv:>߈*V~#=|> w:Ʌ7[2X2Ʌ߈Ԉ݈*X&*Vw"X Ԉ}ڨ::Ʌ?ɷ6 5!/Ɓ:{<2|?{F}T?{>20z}æ!~2}>T>Fw> #w#w#w>22v> T}> T}>O}2O!>:44=_^#V ^#V}ڐ}*|œ}:*|œ}:*[u!w#«}!é}:!Uw0:>Z}!p5}:*E~!50E~*vF#"vE~!{~!!p2~6~2p/1~:-E~!u5+~.E~}~: E~!56~~*X*Z{zf~#"Z*V+p!5j~:::ʷx!~4ʈ~: *"*"÷!"**:~~'ʿ~0zw#ì~#~'ʲ~"÷~'~GE~*#"#~*#"#~'~÷:= !4!"Å2·*+"|ʷ*"!4÷!U6:T:}T*ZzM*V6 "X|:U2Z2[:l*V"X!"Z÷!~ʅwÔ*S+"S|Ô:+*|ʷ+":x2r22s2Ugo"""":{!w:4*:G:*O~#"O:}Z}*V"Xɯ2Ugo"**~# -1U "2G0S S*T])))_*|^#x:Uoo>g"|x!~w+ ys!~w+Œ!č͉—!w#«6 "Ԁ,ʷ/+)~'ʗ~P:2÷|:!"2~G!t _#>Ww2Ʌ>w7a4!_#>WE>6 o&`6#=~2% w ʼn#w¹:_!>ׅp+qͅ,?4:׉̋:X*V~*#> ~~+#1> > ~~0> #~=#~ *X*Vz~~#3:׉> ~͓2׉:׉*؉> ~> ~*%S|v}y"؉"%_>2׉fɧ֊42Xތ ʫ*X&*Vw"X }ګ::X*V=> ό~+ 1> ό > ό~ 0 > ό#~#ό= **** at address ** :!̈́~"~L>#O! ~ό#~ό:<2qҁ! ͎̈́́'!/~ό#Ä|͛}͛> όͤƐ':'όIDF0MPIRFWITEXDOMLDZLGSQIBTLOBDEISBEINOVCNGLGSSNA2IODTBIRCEFFNDFUNOM??*rwÅ22!$"%*+ 2!!!!"" ό> όP !w4:0ww"~:#x w+xw!w|8x}8x!w4#"|/W}/_*x"Dx>2hv: w?{с:G:bvjxx2w:bxyx2?}:rx_*nj~ #~"nj =!>^# y x:yO!:!~ ^#V"y<*"!" F:}2{2xy f:.p *}2x*+"x:XH(AILEFGDy{~v|}||||y{~v/{'}Nxx\yKx:G*O:»w#»"O*|ʷx!~ix2Uw:====+>2>w:V>27ԢE!U~w-ɂN!ͩ}ɂ!ͩ}!s4/Gs!~#\2U!w#q!s4>Z}**Z"Z*VDMyxҷ: *X"Z÷ E~*+"|¨÷:G:{2s!U>w!s5sͣ}s'w!~/G#~/=G!w#02Ʌ2׉ ډׅׅׅׅׅys#r#q#pË̓n͋"`i"**DM^#V#N#F#xyÚ::7͆ͣ}͆'wͣ}͕'w³͆͆͆!s4|/G}/O!> 7>{_zW}o|g=܄|g}o#6 #> wό:Ɍ*:Ǎ*_*xG!x:xwyw2zx:y2x:y,y2yyw}:y/Vy*Hx"!";y}!3y4Fy*>y"Dy}Vy:x?{с:Jy]x!y/<]xFw!~w2!y~w<2evx2y2{y2oy2y>2y E~éy*v*vvDM*0z+|¾y"y"y÷*y*yFE~*y#"y*y+"y|#y÷*[wDM!y5&z*x2y2{y2oy2y>2y E~éy*v*,-./0123456789:;<=>?@ABCDEFGHIJKL