IMD 1.17: 4/04/2010 8:00:44 Ampro LittleBoard Source Disk #2  >A!]]COM$$$ SUB COPYRIGHT (C) 1979LISTTYPEGO ERA SAVE REN GET _JUMP1y2O2y2T >62!12<2!"6͑ϯ2~;(1*~ew# gη((~; #"")<:>6+>ͣ: :G(>2*)"!"ó̯2Ò!~(ͪ#οÒs\s͉  !N>2":~n(#"g\Ґ^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#"##"##"##"!gl2c22:2~2: &2c#( :yѯ2~2> . # :~!8 n(#= >** >?!#?!*#!4#~A8@0/2#~ ͓~ ( ͓8#~ k 02Я=~# (+;ɯy > ͋ί:No File> ͪ> _>(ͪ !*5 6>P( ʳ\ͣ~#ͪ  _2<\!~6 >_ M!Ӷ2a{_ͣ:Aͪ: 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*8 >1ͪ0ͪ:̷(H ((>:=2) 2!N!6#5 /(p>$ͪ!>Ò>!~!8 N>2p>>ͪ !~#I6  ~!8=_.:,<>nίɅo$~#!d~+ H(6!]~*(#͓8Wy888 88Oy0 0?7!] ~ (-H()08 80#OzW{_W{_}~2 ~2> :<=>O!+F#~(  # ~#fo###ܯ=x23 ͐ί͍({ ͣ | >̈́o(: >{>.ͪ~#ͪ*{#zr+s{ozg**͕** پ,w͜͸Ͳ!!N#F$**O!~#:A׾#~$=2Ek͌::/GyO>2!q*C"͡ʔ*JҔ^:Oyʃ?|x | sۖ-|N-#  !I~=`O> ̈́\,\I>2:m2\v\(ʐͣ>2*y8 !~ ( ( ( ͷͷ > ͷx #Uo&!l\Nv͖*(+)z(\ \/<  ?( AFN Erro\3Erase!]o>?ͪ͛Y9I\vlv͖!\lO~q#\*Ð͞8!3: $::2:з(=2Tó!mͣ"W!~n(#pó!lN͞">2S:2E!~Яw>T D^6k-äPYy 5*{zBK5ڋ>*Cw~#+w#w+ɯ2E22i^ *C :~w~͔͔# #  w ~>2!E5T*C!"C"C!w# F! w͌xٯ2͢*C ~<wʃG:!ʎ6ӯ2!@~$ :<2#~#$ :2/ 26(͍(!!>˼8! = >>OFulÒmˑԙԥԫԱ"C{2!"E9"1Aׯ22!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ì 4~ʶ¬:<ʶ$ʶïZͻدx>2>2ͻ:!Zݯ2:E׷ẅ́͊Ͳ>2>2T*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 "ã:!B׾w!>2*C~=2u:B2~2wE:A*C׶w>"!""2B!"!rQQQâ~?ͦ~?rQ*"CQ-Q͜QüQrQ$Q*):B"*)*)Q;*"E:;:A2AQÓQÜQ*C}/_|/*W}_*"}o|g":ʑ*C6=^^>2^&6>^ ( =(͸8v(&~v(^^>!&͸GƸw:r :_!]~:r_!p:r :_!~@!O!w(yy>#^yǾC= :qa##~o:X(:T͘^#V_~_:r :(:_{o!k*io!:V0066s1C:us1&:Ìs1C:}s1: ø@(t s1C*(:@(%?>ӄۄ:l( >ӄۄ ۄ:ʑw:2E**E}DQ>2LÃ: #}G G %}U}FFSTARTUP n.Dnv +;K[kCZ(yӀCu(ۀCͬ(y>ӌی>ӌی:m( >ӌی یC͸(yӈCی(ۈۄ(*:( ۀw#":G:>(*F#":x !""!pʎwڎ!4>< 36#4 ,6#4> #6*#"D(>n !"!4>d 6!{ɞ@@@@@@@@@@@2(^?( (@ (? !>&0FVaÑ!!@@P`p  :a2xayaNwy#!Jɨ|z>P!r !r䇇_O"3DP`p7;B7777:[ 2ZCNCVy2P2XCi`iy2q2Ms1>2v:qa"tw~(G#~2r~2sxO! ~#fo:v!<R:_!p~G!t~w:*t##w2yˮ8 (>!w"m-!k:|O"o!d6!{qM:k2e(=!d5(4*o"*m">2{!|"o!"m:#wM*"o*"mɯ*V))))G:2|2:T2ɯ!#"':{G: !!>!`$@‡ nn =2kÈG>!!x=2k>"% $ (ó!% ["'>"$_#!~#fo@!{^*o!{^*o3*m!k3!l3#"'>!(%%G(Cxê('%G(C7x7ê>A:a21)02t2!"2!":O!xà BOOT FAILED!Cv˶o68͂7>2Vͺ:O7O:8 o! ~͘ ! ~#~:=(=(7oG2c_!~2bx_!~2L:s_!. ~#fo"~2aɆƇǀ @Cvoo(K( =x28͂<7vs1:c:2\<2g2f>2h}s1:c62gy2hB!L\!\(,5#M Q+4~*n*^#"^2f~2\<2f2e!x!x!xp!6|/G}/O!j !b !m@!K6!22Z2\2 58k CP/M vers 2.2K Z80 Operating System AMPRO BIOS Version 3.8 Copyright (C) 1983,84,85,86 AMPRO Computers, Inc. SCSI initiator ID = x (Arbitration Disabled) (Clock Enabled) (Console Buffer Enabled) Z3ENV@ KPPB:`B:B:XRSH VAR ADM-3A *=%+ %+ T)($$$C:cG:P/2Y!Z~6(+M!Q :Y(6:[:Q2q*R"V6:M2Q2q*N"R"V:Y2T:f:2[:P!b驪o&B~#fo[i:g >2[:h:e2[:Q2q*R"V6:eɯ<>2kkkk8>2&͸ĺ F͸y_:r>(o> 8ͫ>2d:¤ͻ > ͂!5 >2e"^>*0 0~#O ,:d=2d2"^:*0 0w#O :d=2d(>= 8.GOW^>>>^= zyx!6G+|cC!5c> CONFIG COM0 SWAP COM ASM COM@DISK7 COM LOAD COM-A60103 E DIR COMISYSGEN COMHG-1-2 PRN+HG-1-2 HEX%HG-1-2 ASMlqrstuvwHG-1-2 COM HF-1-5 ASMyz{|}~HF-1-5 ASMHI-1-2 ASMHI-1-2 ASM#HF-1-5 COM)<=>HI-1-2 HEX #%')*?HI-1-2 PRN"$&(+,-./0123456HI-1-2 PRN4789:;@ABCDEFHI-1-2 COM2GHJK1*" COPYRIGHT(C) 1978, DIGITAL RESEARCH á 4êü /L9ASMPRNHEX :! 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*!{͚|͚}͚͚{!$~#͚͚> ͪ> ͪ@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û!^*"*!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/!)ͼ !ͼ :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?'  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 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~ ͅ file | D - Delete file | F - Forward 22 | G - Group copy J - Jump to fn.ft | L - Length of file | N - New DIRectory | P - Print text R - Rename file | S - Stat of disk | T - Tag file | U - Untag file V - View text | X - Exit to CP/M | advances cursor -- B backs up !"" "=ƀo&:\w* ͉6 #"\< *""j Ͷ**  # 0 Nwy#* "*Ͷ * ""*Ͷ ͠*+*jͶ0 x  No BuffͰ>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 er Spaceui`"!" *~@:t( 8 >10: #~#>.~#~2k#" : :e͌ͪ*"!G~ȸ(####~#foɯ2*~*6 ( *~*6*>222>}#*"!":fo*ͼ/o:(:( *" *}o|g"> 2k:(<*:G> >(k):<2 >2t22**Ͷ!"* Ͷ * " <- *"torage free on drive: ͚ :mͪÀ}e:|: |Ë  |*" ͩ !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*| } 8Olete? (y/n): Y€<  ++ NO FILE FOUND ++À*"*Ͷ( ͉"Ͷ*Ͷ2l ++ List Empty ++Ö*u ͉ename file to: ^! ~#?(\v! O>w#:u2 !͉!͒<(? ++ FILE ALREADY EXISTS ++À ++ NO WILDCARDS ++À*! ͉u<€! ,6# >!N#Di&6 Oڄ .(#*(w#O . 6?#.„#O8 (.( *( w##Ò6?#ump to filename: u^!Ľ 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"% * "*Ͷ ! "!*#v ?(#s cancels, turns up one line, other keys page screen >22>Brint on LST Device (y/n)? Y€ Printing... >2=2>2o}!͒<  Unable to Open FileÀ22n €!~ʀ_:oO{     :r  #{ 2n:o(1:<2د2 [more...]   >2::<2د2ʄʄ:n<2n:o! ~(#! >.E(c) 1984 by f. gaude'!9"b1bͪͱ2t2:\(=2mͪ:] :e !] ͉2h2|/2l\<82l ++ NO FILE FOUND ++ ---> Command (n/x): Xʔew DIRectory: :2tͰ͚> 2]2e!" >!> ,2::(6082:0H0 ::(08 603&2>G::(00x2:*#"(**Ͷ* 2/22!"p}!͒2 !v͉<  Can't Open SourceÀ: hCopy to DIRectory: :\G: @:G:t 6 ++ Drives or User Areas must be different ++À͚:\2u:Ͱ:(Bu<(? ---> Copy exists, erase? (y/n): Y( :tͰuu< $ Destination Directory FullÀ!v ͉͉:>  ---> Copying file . 2:tͰ!"*j"h*h(=(C Source R ead ErrorÀ*h~##*h"h*#"*Ͷ >2:Ͱ*j"h*|(K+"*h"hu( ++ COPY DISK FULL ++u2À: u<  Copy Close Error*p"r!"p!͒u<ʂ2u(=(A Copy Read ErrorÀ!~##*pO!p ~W$^"p:tͰ*p*rͶ 3 ---> File copy certified :/2)  ++ FILE CRC ERROR ++!p!yg)0>g>!or$s%# ~#(> > _> > > A 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#Wq=  ͝Kd*= ! ͸p!@ 6>!@ X*= }O!< *@ & w*= #"= !@ 4)!< 4\mad* }O!< :? wlR*4 DM+{R* DM+R 4 ͝*4 }¿= 4 ͝< N*4 #"4  å;*4 DM+: Y2> _ *. a{_!Fxʄ#~#w6 #  ʄ [0!m(#7,:;<=>> * ~#6#2m :__ z{|g}o 8 |{0 ͶcͶͶ<2\@2##~2g#~2f##^#V"d }08 :\=_.!~w+ *1*d#8W+}(z i`:g()= k bytes free on DIRectory :  BCG DLJFxNG P RSTUV: X??????????? 1>+2#|>*.\~@22<229*.3:E!AL!@+  >21~Ž#~o&)!:A2 :<[FLOPPY DISK ASSIGNMENTS: CP/M drive Floppy disk ------------------------ $ x $First SecondThird Fourth> 0> 0͹_ͳ AMPRO System Configuration Utility Copyright (c) 1984,85,86 - AMPRO Computers, Inc. Version 2.6 With this utility you may view and change the various @ 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 parameters of your AMPRO system. You will be asked to choose to view the current parameters now in memory or to view the parameters on a system disk. You will be asked for any changes you might make. After any changes you will be asked whether to install the new parameters in memory and/or on a system disk. View parameters from Memory or from Disk? (M or D) Press to quit. $_M:DŒͳDisk$:Nͳ Which disk shall you read from? (A thru P) $G_AQ: 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 "= ! O=2͞Gͳ There is no system on this disk $õͳMemory$́ͳ Configuration Table: Parameter: Currently: 1. Terminal $:!#±!1͛ͳ 2. Printer $:!1@!#!?͛ͳ 3. Max. Floppy Drives $:>:0Oͳ 4. Step Rate $:qͳ, $:qͳ, $:qͳ, $:qͳ $äͳ6ms$ã=Žͳ12ms$ã=œͳ2ms$ãͳ3ms$: ͳ Note: The first step rate is used for all drives when using bios 1.x6Y: !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+: Y2 or 2.x $ͳ 5. Autocommand $!͛ͳ 6. $!#͛7ͳ baud rate $'ͳ hand shake $:!ʶ!͛ͳ 7. $!1͛7ͳ baud rate $'ͳ hand shake $:!A!͛ͳ Any (more) changes? (1 through 7 or No) $GNn1s8s76* 5 4ʚ 3ʠ 2 ͳ 1. Terminal, Serial port A or Serial port B. (A or B)$G_C A :2Gͳ 2. Printer, Serial port A, Serial port B or Parallel port. (A, B or P)$G_Aʄ Bʄ Pf Bʔ A@ʔ :?2G:V ͳ 3. The maximum number of floppy disk drives is preset to four (4) in the Ampro BIOS version 3.0 or greater. Press the RETURN key to continue - $G GA ͳ 3. Max. drives. (1, 2, 3 or 4)$G1{ 5{ 2Gͳ 4. Step rates for each floppy drive (in milliseconds). Choices: 1770 1772 1 -- 6ms 3ʆ4j5N62!>Gw#> w!~?@w##~w!>Gw#>w!~?@w##~w!>Gw#>4w!~?@w##~w!>Gw#>hw!~?@w##~w!>Gw#>w!~?@w##~w!>Gw#>w!~?w##~w!>Gw#>w!~?w##~w!>w#>Gw!~?w##~wͳ Hand shake? (Yes or No) $ G_Y0Ny2Gͳ data bits $``8m 7m@6m5ͳ configuration stop bits $ ²ͳ1.5$þ1ʻ2ͳ parity $!M!Q!6ms 2 -- 12ms 12ms 3 -- 20ms 2ms 4 -- 30ms 3ms $ͳ First floppy drive rate (1-4): $G ʦ 1ʜ 2ʜ 3ʜ 4n y2Oͳ Second floppy drive rate (1-4): $G  1 2 3 4 y2Oͳ Third floppy drive rate (1-4): $G b 1X 2X 3X 4* y2Oͳ Foruth floppy drive rate (1-4): $G 1ʶ 2ʶ 3ʶ 4ˆ y2OGͳ 5. Autocommand. Command file to be executed on cold boVÛͳ Install changes in Memory or on Disk? (M or D) Press to exit.$_MmDʙQ͏ͳ Changes installed in memory.$:Nͳ Install changes on which disk? (A thru P) $G_AQO2"=2ͳ Changes installed on disk A$ pG!~ !g~!l~4!q~h!v~!~@!{~!~@![~!aÛ*.@@Ð*.@!@Ð>2 2">2!A!~G ·x!@@Ð:1~ͳ No disk at this letter $>>ot. $> !^#6! ͐Gͳ Serial port A configuration Data bits. (5, 6, 7 or 8) $G ʰ 5j 9j 8`ʝ 7 ʝ 6@ʝ !~柱wyO!~?wͳ Stop bits. A=1, B=1.5, C=2. (A, B or C)$G _A D A B  !~wͳ Parity. Odd, Even or None. (O, E or N) $ vG_OnEnNE!~wͳ Baud rates: 0. 110 5. 2400 1. 300 6. 4800 2. 450 7. 9600 3. 600 2 2">2!A!@@͐2"Aͳ Disk Write Error $>:1~:O ~#fo~@j>-2!2 : O:!O:"ʋ~# x~#$O ̹Û͛ x½Y> >>>>!>$>'>*>9*oͳT1 $ͳT2 $ͳT3 $Serial Port A$Serial Port B$Parallel Port$odd$even$none$38400$19200$9600$4800$2400$1200$600$450$300$110$yes$no$ 8. 19200 4. 1200 9. 38400 Choose one. (0 through 9) $ ʥG:M0Mʌ1p2T3845678ʮ!>w#w!~?@w##~wå!>w#w!~?w##~wå!>Gw#> w!~?@w##~wå!>Gw#>w!~?@w##~wå!>Gw#>4w!~?@w##~wå!>Gw#>hw!~?@w##~wå!>Gw#>w!~?@w##~wå!>Gw#>w!~?w##~wå!>Gw#>w!~?w##~wå!>w#>Gw!~?w##~wͳ Hand shake? (Yes or No) $ G_YNy2Gͳ Serial port B conPO AMPRO SWAP Utility Copyright (C) 1985 AMPRO Computers, Inc. Version 2.0 [F2.05] $ Usage: SWAP $ This program requires AMPRO bios version 3.1 or later. $ The AMPRO SWAP utility allows you to swap the definition of any two CP/M drive letters. For example, if you have two floppy drives at A: and B:, and two hard disk partitions at F: and G:, you could swap pairs A and F, B and G, C and F, and D and G, to place the hard disk partitions at A: and B:, and the floppy drives at C: and D:. NOfiguration Data bits. (5, 6, 7 or 8) $G o5)9)8`\7 \6@\!~柱wyO!~?wͳ Stop bits. A=1, B=1.5, C=2. (A, B or C)$G _AڞDҞAB !~wͳ Parity. Odd, Even or None. (O, E or N) $ 5G_O-E-N!~wͳ Baud rates: 0. 110 5. 2400 1. 300 6. 4800 2. 450 7. 9600 3. 600 4. 1200 Choose one. (0 through 7) $ G801ʾ2TE: Swapping drive A: has these two restrictions: (1) The A: drive can only be swapped with an existing drive (one of those listed by SWAP under "current assignments"). (2) Be sure to use the AMPRO SYSGEN utility to write a system to the drive which is to become drive A:, before swapping drive A: with any other drive. $!9" 1W !X ͒ ~2##"‚ͱk ̓ : Җq hI _ !ͣ h2R2?AOF!ͣ h?2AGyyx ~  2  Ö  Which drive do you want to swap (A-P, ? for list, to quit): $ Swap x: with which drive (A-P, ? for list, to quit): $ <<< Drive x: successfully swapped with drive x: >>> $?ABCDEFGHIJKLMNOP ERROR -- Cannot swap drive A: with a non-existant drive letter. $ͱ7k( ( ( Ö>>> Current CP/M Drive Letter Assignments <<< $ ͮ xʍ:7چ ~6$w~ ʡ ʡ$ʭnͽ ̽ #Í>( =´_Gyͽ h Tk!p  ; START: IF CMD$LINE$OK ; If we want to allow cmd line input, LXI H,0080H ; . Save the command line. LXI D,INBUF ; . . LXI B,128 ; . . DW LDIR80 ; . . LXI H,INBUF ; . Set up ptrs and count of chrs MOV A,M ; . . STA CMD$LINE$CHRS ; . Save count of characters, INX H ; . Bump line pt~L! ͒ 2 0! ͒ x!  ͒  k#x> FLOPPY DISK ASSIGNMENTS < CP/M drive Floppy disk ------------------------ $ x (*) $First SecondThird Fourthk(*) = Current foreign format drive letter. $:x k< 2 ͓ m<͏͒ !  !͒ ! "~R 02 ###~02 #####F*p##":x G:<#͏(  k> HARD DISK ASSIGNMENTS < CP/M drive(s) Addr Unit # -------------------------------ü:` >2_|~U#~o&)!:_A2 :_<" FLOPPY DISK ASSIGNMENTS: CP/M drive Floppy disk ------------------------ $ x $First SecondThird Fourth:= >2_|~3##~02#~x02:_A2 :_< HARD DISK ASSIGNMENTS: CP/M drive Addr Unit # ------------------------------------- $ 0 0 $1!~#O~# /"y2ͻ*.\~@22m<292---- $ 0 0 $> ͽ> ͽ:Ľ q#?  d< "y 2x  ~   < !x #~!p O ͈ Aw  +͈ ~wA22 #~2| ~2} ~2 #~2~ #~2{ A2 *y { ͒ !"y !x 4<Z ABCD* <͒ > 2 #|+ ͒ >~#fo $ ñ  ͧ ! = O ~ =G # :]/ ͺ_44 AQ2 21Oͺ ~44JIͺ_44 4AhQh2 2Oqͺ ʴ44ÜÝ,> .>!>!  #bCOPYRIGHT (C)h\2: Ϳ>P2 b!">2: Ϳb>P2 vb=OO| ~#fo~2 ! "X> DRIVE SELECTxy> >2 >$2 2 G ~ q z  z  $q I " " x2 #: * 6$: ͂ ( * #~ g  >$͂ ͽ#x ~#– >ê >2 : *=2~#"@ !X #">2í ʭ , > . >_ Ͱ 2 Ͱ Ľ: ( + kO !P ͣ Press the RETURN key to continue ...$ ] X x:x 2 y x ͓   : k =e N#¡ • Nwy#¤ { a _>= =½  ERROR $>.**:͌Q*"*#": F.$":=2Z R/W ERROR - ABORTED - $*!>͌Q2"LR:OU:¯[ò^:**7<>g2#|+s>~# : =2*~#"_>2>  y#:=27: F.$":=2Z R/W ERROR - ABORTED - $*!>͌Q AMPRO System Generation Utility Copyright (C) 1984,1985 AMPRO Computers, Inc. Version 3.3 $ E' 02BD 596F752077 DB 'You will be asked for the controller ' 02E2 747970652C DB 'type, controller SCSI address, drive unit number, ' 0314 616E642074 DB 'and the drive descriptor information.' 0339 0D0A0A24 DB CR,LF,LF,'$' WARNING$MSG: 033D 4341555449 DB 'CAUTION: ALL DATA WILL BE ERASED ON THE DRIVE YOU ' 036F 53454C4543 DB 'SELECT TO FORMAT.',CR,LF,LF,LF 0384 24 DB '$' ; ; Initialize the command line input pointer.nter Source Drive? (A thru P) $ Place source on A, then type $ Enter Destination Drive? (A thru P) $ Place destination disk on A, then type $ $ NO SYSTEM IN MEMORY. $ Source = Memory Image. $~#"_>2>  y#:=27: F.$":=2Z R/W ERROR - ABORTED - $*!>͌Q AMPRO System Generation Utility Copyright (C) 1984,1985 AMPRO Computers, Inc. Version 3.3 $ E  ; * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * Hard Disk Auto-Boot Installer * ; * * ; * Copyright (C) 1985 AMPRO Computers, Inc. * ; * All rights reserved. * ; *  can run this ; utility. ; ; Sector 31 (1F hex) of the hard disk system track is reserved. ; ; Requires special SCSI boot prom . ; ;------------------------------------------------------------------------ ; ; The following equates are entry points into the boot prom ; 800F = SETDMA EQU 800FH 8012 = READTRK EQU * ; * * * * * * * * * * * * * * * * * * * * * * * ; ; ; Revision history: ; ; Ver Date Who Description ; --- -------- --- ----------------------------------------- ; ; 1.2 1/7/85 fsw Installs users HD$ALV$AVAIL: information ; in bios at boot time. ; 8012H ; 9000 = BOOT EQU 9000h ; location of boot loader 0100 = TPA EQU 100H 8EFD = OFFSET EQU (BOOT-TPA)-3 ; -3 for jmp start before patch area 0000 = WBOOT EQU 0 ; location of bios warm boot ; 0000 = CONTROL EQU 0 ; board control port ; 0008 = SREAD EQU 08H ; scsi read data 000A = SWRITE EQU 0AH ; scsi write data ; 000D = CR EQU 0DH 000A = LF EQU ; 1.0 9/20/85 fsw Initial release. ; ; 000C = VERS EQU 12 ; version 1.2 ; ; This version saves all the setup disk parameters that the user ; has defined by running SYSGEN, HINIT, and SWAP to the hard disk. ; This user defined information is stored on the last sector (sector 31) ; of the system track, and is used to "patch" the standard BIOS on boot. ;  0AH ;----------------------------------------------------------------- ; 0100 ORG TPA ; cp/m tpa 0100 C34201 JMP START ; ;****************************************************************** ;************************Boot loader******************************* ; values set at 0 are patched to users addresses by the program. ; PATCH$START: 0103 3E40  ; The information on this sector will be read somewhere into memory ; by the hard disk boot prom with an offset of 15872 bytes (3E00 hex) ; from the boot dma address. The user's dpbase (256 bytes), the 64 byte ; PHYTAB with the user's logical/physical configuration, the user's ; hard disk DBP's (176 bytes), the users HD$ALV$AVAIL block (12 bytes), ; and the users hard disk byte/block flag (1 byte) are savMVI A,40H ; must turn off rom 0105 D300 out control 0107 210000 DMA: lxi H,0 ; set dmaadr address 010A CD0F80 call setdma 010D CD1280 call readtrk ; read first track 0110 CD1280 call readtrk ; read second track ; ; find the user disk information that was loaded in to memory ; from sector 15 of the hard disk ; 0113 2A0590 lhld (dma+1)+offset ; get load address 0116 11003E lxi d,15872 ; offset ted in that order. ; (total 509 bytes) ; ; The boot loader is modified to find this offset and install the users ; changes in bios before jumping to cold boot. ; ; NOTES: ; ; Only the system track of the hard disk with SCSI id 0 and LUN 0 will ; be patched. ; ; Only Little Board's jumpered for SCSI initiator id 7o where hard disk sector 31 ; landed 0119 19 dad d ; sorce address in 'hl' ; ; move the users dpbase into bios ; 011A 110000 DDPBAS: lxi d,0 ; patched to destination address 011D 010001 lxi b,256 ; number of bytes to move 0120 EDB0 dw 0b0edh ; z80 ldir ; ; move the users phytab into bios ; 0122 110000 DOPHY: lxi d,0 ; patched to address of phytbl   0125 014000 lxi b,64 0128 EDB0 dw 0b0edh ; move the 4 bytes with z80 ldir ; ; move the users dpb's into bios ; 012A 110000 DODPB: lxi d,0 ; patched to destination address 012D 01B000 lxi b,176 ; size hard disk DPB's 0130 EDB0 dw 0b0edh ; z80 ldir ; ; move the users HD$ALV$AVAIL info into bios ; 0132 110000 HDAVL: lxi d,0 ; patched to destination address 0135 010Ce moved, give signon ; 01B2 CD4207 SIGNON: call puts 01B5 0D0A0A0A db cr,lf,lf,lf 01B9 2020202020 db ' AMPRO Hard Disk Auto-Boot Installer ',cr,lf 01F5 2020202020 db ' Copyright (C) 1985 AMPRO Computers, Inc. ',cr,lf 0234 2020202020 db ' Version ',VERS/10+'0','.',VERS MOD 10+'0' 0260 0D0A0A db cr,lf,lf 0263 5468697320 db 'This utility will install your current hard disk ' 0294 00 lxi b,12 ; bytes to move 0138 EDB0 dw 0b0edh ; z80 ldir ; ; move the users byte, block mode value to bios ; 013A 110000 CTLBYT: lxi d,0 ; patched to destination address 013D 7E mov a,m ; 'hl' has location of byte 013E 12 stax d ; store at 'de' location ; 013F C30000 GOBIOS: JMP 0 ; go to cold boot ; 003F = SIZE$PATCH: equ $-patch$start ; :10010000C342013E40D300210000CD0F80CD1280BC :10011000CD12802A059011003E1911000001000146 :10012000EDB0110000014000EDB011000001B00081 :10013000EDB0110000010C00EDB01100007E12C303 :10014000000021000039226A0731CB0721CB0701CB :100150000004AF77230B78B1C252012A01002E00B0 :10016000116C07014000EDB0DB29E607FE07CAB2BB :1001700001C630328D01CD42070D0A4C6974746C92 :100180006520426F617264204944203D2020202C6C :10019000206D757374203D203720746F2072756E4A :1001A0002074686973207574696C6974792E00C352 :1001B0003C07CD42 ;********************End of Boot loader**************************** ;****************************************************************** ; 0142 210000 START: lxi h,0 ; init new stack and save old 0145 39 dad sp 0146 226A07 shld oldstk 0149 31CB07 lxi sp,stack ; ; clear the buffer area to zeros ; 014C 21CB07 lxi h,btsec 014F 010004 lxi b,1024 ; do 1024 bytes 0152 AF CL070D0A0A0A20202020202020DB :1001C000202020202020202020202020202020410E :1001D0004D50524F2048617264204469736B204136 :1001E00075746F2D426F6F7420496E7374616C6CFF :1001F0006572200D0A202020202020202020202091 :10020000202020202020202020436F7079726967F1 :10021000687420284329203139383520414D505207 :100220004F20436F6D7075746572732C20496E6337 :100230002E200D0A202020202020202020202020D9 :1002400020202020202020202020202020202020AE :10025000202020202056657273696F6E20312E3267 :100260000D0A0A54686973207574696C6EAR: xra a 0153 77 mov m,a 0154 23 inx h 0155 0B dcx b 0156 78 mov a,b 0157 B1 ora c 0158 C25201 jnz clear ; ; move the bios jump table to use it's io, easier ; 015B 2A0100 lhld wboot+1 ; get address of bios 015E 2E00 mvi l,0 ; begining of bios jmp table 0160 116C07 lxi d,bj$tbl ; bios jmp table 0163 014000 lxi b,64 ; move 64 bytes 0166 EDB0 dw 0b0edh ; z80 ldir 974792081 :1002700077696C6C20696E7374616C6C20796F7532 :10028000722063757272656E742068617264206496 :1002900069736B20636F6E66696775726174696FED :1002A0006E206F6E207468652073797374656D209D :1002B0000D0A747261636B73206F66207468652029 :1002C000534353492068617264206469736B2064EE :1002D00072697665206C6F63617465642061742057 :1002E0005343534920494420302C204C554E203054 :1002F0002E200D0A0A5072696F7220746F20757378 :10030000696E6720746869732070726F6772616DBF :1003100020796F75206D757374207573652053593E :10032 ; ; check id of board ; 0168 DB29 in 29h ; get board id 016A E607 ani 07h ; mask board id 016C FE07 cpi 7 ; must be 7 016E CAB201 jz signon 0171 C630 adi '0' 0173 328D01 sta shid ; show id setting 0176 CD4207 call puts 0179 0D0A4C6974 db cr,lf,'Little Board ID = ' 018D 20202C206DSHID: db ' , must = 7 to run this utility.',0 01AF C33C07 jmp exit ; ; bios jmp tabl0005347454E20746F20777269746520746856 :10033000652070726F7065722073697A65200D0A8E :1003400043502F4D2073797374656D20746F207442 :1003500068652073797374656D20747261636B7363 :10036000206F66207468652053435349206861728A :1003700064206469736B2064726976652066726FAD :100380006D20776869636820796F75200D0A776939 :100390006C6C20626F6F742E2020496E2061646443 :1003A0006974696F6E2C20796F75206D7573742078 :1003B0006861766520616C7265616479207573652A :1003C00064207468652048494E495420616E642059 :1003D00053574150200D0A 636F6E6669 db 'configuration on the system ',cr,lf 02B2 747261636B db 'tracks of the SCSI hard disk drive located at ' 02E0 5343534920 db 'SCSI ID 0, LUN 0. ',cr,lf,lf 02F5 5072696F72 db 'Prior to using this program you must use SYSGEN ' 0325 746F207772 db 'to write the proper size ',cr,lf 0340 43502F4D20 db 'CP/M system to the system tracks of the SCSI hard ' 0372 6469736B20 db 'disk drive from which you ',cr,lf 038E 77696C6C20 db '5C6 :10049000726520746F206261636B757020796F756F :1004A000722068617264206469736B206265666F94 :1004B000726520796F7520706572666F726D200DA0 :1004C0000A746869732066756E6374696F6E206F55 :1004D0007220617474656D70742068617264206448 :1004E00069736B206175746F2D626F6F74696E67CD :1004F00021200D0A0A0D0A446F20796F7520776953 :10050000736820746F20636F6E74696E75653F2029 :1005100028592F4E292000CD7507E65FFE59C23CB1 :10052000073E0832640721640711CB073E01CDA8BE :1005300007C2E4061AFE3ECA9B05FE21CA9B05CDF2 :10054000420will boot. In addition, you must have already ' 03BD 7573656420 db 'used the HINIT and SWAP ',cr,lf 03D7 7574696C69 db 'utilities to customize your system. ',cr,lf,lf 03FE 4E4F54453A db 'NOTE: The CP/M system you install on the hard ' 042D 6469736B20 db 'disk must identical to ',cr,lf 0446 7468652073 db 'the system you are running now. ',cr,lf,lf 0469 5741524E49 db 'WARNING!!! ',cr,lf 0476 4173206120 db 'As a70D0A56616C696420426F6F74207314 :100550006563746F72206E6F742070726573656E60 :1005600074206F6E2068617264206469736B2C2044 :10057000646F2053595347454E2C2048494E4954E7 :100580002C20616E6420535741502C207468656E96 :100590002072657472792E00C33C071AFE2113C2C3 :1005A0009B05EB7E23666F2208012A01002E0022A4 :1005B00040012E80221B0111CB09010001EDB0D5B5 :1005C000CD9F071106001922CE05210000CD0000A5 :1005D000222301D1014000EDB0D50E001E01CD87D0 :1005E00007110A00197E23666F7EFE29D22A06CDE6 :1005F00042070D0A52756E204849 safety measure, be sure to backup your hard ' 04A7 6469736B20 db 'disk before you perform ',cr,lf 04C1 7468697320 db 'this function or attempt hard disk auto-booting! ',cr,lf,lf 04F5 0D0A446F20 db cr,lf,'Do you wish to continue? (Y/N) ',0 0517 CD7507 call conin 051A E65F ani 5fh ; make it upper case 051C FE59 cpi 'Y' 051E C23C07 jnz exit ; exits if input not Y ; 4E495420616EDB :1006000064205357415020746F20736574207570B7 :1006100020796F75722073797374656D20666972C5 :1006200073742E0D0A00D1C33C072A01002E8011DD :10063000500019110A00197E23666FD1222B010187 :10064000B000EDB0D5CD9F0711030019225006CDA3 :100650000000D1E5223301010C00EDB0E1D5110419 :1006600000197E23666F7ED112223B0121CB070148 :100670008000AF77230B78B1C2720621030111CB42 :1006800007013F00EDB03E0A3264073E01216407D6 :1006900011CB07CDA807C2E4063E0A3264073E1F0D :1006A00032670721640711CB093E01CDA807C2E4D8 : ; read the current boot sector into memory ; 0521 3E08 DOIT: mvi a,sread ; scsi read command 0523 326407 sta scsicmd 0526 216407 lxi h,scsicmd ; point to scsi command 0529 11CB07 lxi d,btsec ; data area 052C 3E01 mvi a,1 ; target address 052E CDA807 call scsi 0531 C2E406 jnz scsierr ; not zero results=error ; ; we have the boot sector in memory lets see if sysgen has been ; done on the hard disk. two choices are present for the first byte ; of the AMPRO boot sector either mvi a,xx or lxi h,xxxx , check for ; both. ; 0534 1A ldax d ; call to scsi returns data pointer 0535 FE3E cpi 3eh ; see if mvi a,x 0537 CA9B05 jz next 053A FE21 cpi 21h ; could be lxi h,xxx 053C CA9B05 jz next 053F CD4207 call puts ; neither 0542 0D0A56616C db cr,lf,'Valid Boot sector not present on hard disk, ' 7574696C6974696573CF :1003E00020746F20637573746F6D697A6520796FFF :1003F00075722073797374656D2E200D0A0A4E4F45 :1004000054453A20205468652043502F4D2073797D :100410007374656D20796F7520696E7374616C6C8F :10042000206F6E207468652068617264206469734F :100430006B206D757374206964656E746963616C9B :1004400020746F200D0A7468652073797374656D6C :1004500020796F75206172652072756E6E696E67A6 :10046000206E6F772E200D0A0A5741524E494E4793 :10047000212121200D0A417320612073616665747A :1004800079206D6561737572652C20626520737 0570 646F205359 db 'do SYSGEN, HINIT, and SWAP, then retry.',0 0598 C33C07 jmp exit ; ; figure out the dma address to load track 0 at ; the rest if the info we will find in the bios jmp table ; 059B 1A NEXT: ldax d ; find the lxi h,xxx instruction for 059C FE21 cpi 21h ; dma address 059E 13 inx d 059F C29B05 jnz next 05A2 EB xchg ; location of dma address in 'hl' 05A3 7E mov a, m 05A4 23 inx h 05A5 66 mov h,m ; dma address in 'hl' 05A6 6F mov l,a 05A7 220801 shld dma+1 ; set dma address in new boot loader ; ; fix the cold boot address ; 05AA 2A0100 lhld wboot+1 ; get address of warm boot from cp/m 05AD 2E00 mvi l,0 ; make it a cold boot 05AF 224001 shld gobios+1 ; patch jmp in boot loader ; ; get users dpbase, always at cold boot+80h in Airst hard disk dpb ; 062A 2A0100 MOVDPB: lhld wboot+1 ; get address of bios 062D 2E80 mvi l,80h ; offset to dpbase 062F 115000 lxi d,16*5 ; offset to first hard disk dpb header 0632 19 dad d ; 'hl'= first hard disk 0633 110A00 lxi d,10 ; offset to dpb address 0636 19 dad d 0637 7E mov a,m ; get the address of the dpb in 'hl' 0638 23 inx h 0639 66 mov h,m 063A 6F mov l,a 063B D1 pop d ; resMPRO bios ; 05B2 2E80 mvi l,80h ; offset from cold boot 05B4 221B01 shld ddpbas+1 ; load address in boot loader 05B7 11CB09 lxi d,udpbase ; move the dpbase to save area 05BA 010001 lxi b,256 05BD EDB0 dw 0b0edh ; move it, ldir 05BF D5 push d ; save buffer destination address ; ; get address of phytbl ; 05C0 CD9F07 call gettbl ; get address of next table 05C3 110600 lxi d,6 ; offsetore destination address 063C 222B01 shld dodpb+1 ; address of users hd dpb for boot loader 063F 01B000 lxi b,176 ; move 176 bytes, 11 dpb's 0642 EDB0 dw 0b0edh ; z80 ldir ; ; find the HD$ALV$AVAIL block to save and the scsi controller burst/byte ; mode value and save. needed for Shugart and other non-burst controllers ; 0644 D5 push d ; save 'de' 0645 CD9F07 call gettbl ; get address of next table t to phtbac 05C6 19 dad d ; 'hl'=address of phtbac routine 05C7 22CE05 shld gtbl+1 05CA 210000 lxi h,0 ; if 'hl'=00 returns address of phytbl 05CD CD0000 GTBL: call 0 ; call phtbac 05D0 222301 shld dophy+1 ; patch location of phytab in users bios 05D3 D1 pop d ; get destination address 05D4 014000 lxi b,64 ; move 64 bytes 05D7 EDB0 dw 0b0edh ; z80 ldir 05D9 D5 push d ; save address ; ; the patch area 0648 110300 lxi d,3 ; 064B 19 dad d ; 064C 225006 shld brst+1 064F CD0000 BRST: CALL 0 ; call get hd$info 0652 D1 pop d ; get table address back 0653 E5 push h ; save address of HD$ALV$AVAIL 0654 223301 shld hdavl+1 ; save bios address in boot loader 0657 010C00 lxi b,12 ; bytes to move into table 065A EDB0 dw 0b0edh ; z80 ldir 065C E1 pop h ; get location of HD$ALV$AVAIL back 065D D5 now contains the phytab as designated by the user. ; ; lets find the users DPB's for the hard disk. Test first to see ; if SWAP has been run ; 05DA 0E00 mvi c,0 ; drive 'A' 05DC 1E01 mvi e,1 ; not first time select 05DE CD8707 call seldsk ; do select to return dpb header address 05E1 110A00 lxi d,10 ; offset to dpb address 05E4 19 dad d 05E5 7E mov a,m ; get the address of the dpb in 'h push d ; save table address 065E 110400 lxi d,4 ; 0661 19 dad d ; 'hl' points to address of byte, burst 0662 7E mov a,m 0663 23 inx h 0664 66 mov h,m 0665 6F mov l,a ; address of byte,burst mode byte 0666 7E mov a,m ; get current value, 0 or 1 0667 D1 pop d 0668 12 stax d ; save value 0669 223B01 shld ctlbyt+1 ; save bios address in boot loader ; ; l' 05E6 23 inx h 05E7 66 mov h,m 05E8 6F mov l,a 05E9 7E mov a,m ; 'hl' has address of DBP 05EA FE29 cpi 40+1 ; sectors per track information 05EC D22A06 jnc movdpb ; have hard disk DPB 05EF CD4207 call puts 05F2 0D0A52756E db cr,lf,'Run HINIT and SWAP to set up your system first.' 0623 0D0A00 db cr,lf,0 0626 D1 pop d ; restore stack for exit 0627 C33C07 jmp exit ; ; ; find address of fwe have all the information from the users bios in the patch area ; read to overlay the first sector and write back to disk. ; 066C 21CB07 lxi h,btsec ; clean the boot sector 066F 018000 lxi b,128 0672 AF CLEAN: xra a 0673 77 mov m,a 0674 23 inx h 0675 0B dcx b 0676 78 mov a,b 0677 B1 ora c 0678 C27206 jnz clean ; ; overlay the new boot loader on the boot sector   ; 067B 210301 lxi h,patch$start ; begining of new boot loader 067E 11CB07 lxi d,btsec ; location of boot sector in ram 0681 013F00 lxi b,size$patch ; number of patch bytes 0684 EDB0 dw 0b0edh ; z80 ldir, movit ; ; now write it back to hard disk ; 0686 3E0A mvi a,swrite ; scsi write 0688 326407 sta scsicmd 068B 3E01 mvi a,1 ; target address 068D 216407 lxi h,scsicmd ; the scsi command  ; ; SEND BYTES TO CONSOLE UNTIL ZERO ENCOUNTERED ; 0742 E1 PUTS: pop h ; 'hl' has address of msg 0743 4E mov c,m ; get char 0744 CD7807 call conout ; send to comsole 0747 7E mov a,m 0748 FE0A cpi lf 074A CC5407 cz wait ; wait 10 ms after lf for slow terminals 074D 23 inx h ; next byte 074E 7E mov a,m ; 074F A7 ana a ; see if end=0 0750 C24307 jnz puts+1 ; nope 0753 E9  0690 11CB07 lxi d,btsec ; data area 0693 CDA807 call scsi ; do the write 0696 C2E406 jnz scsierr ; if error ; ; boot sector written, now do users swap and disk information ; 0699 3E0A mvi a,swrite ; scsi write 069B 326407 sta scsicmd 069E 3E1F mvi a,31 ; sector 31 06A0 326707 sta lowaddr ; 06A3 216407 lxi h,scsicmd 06A6 11CB09 lxi d,user$tab ; users bios information 06A9 3E01 mvi a,1 0 pchl ; hl has return address ; 0754 0604 WAIT: mvi b,4 0756 110000 lxi d,0 0759 13 WAIT1: inx d 075A 7B mov a,e 075B BA cmp d 075C C25907 jnz wait1 075F 05 dcr b 0760 C8 rz 0761 C35907 jmp wait1 ; ; scsi command block ; 0764 08 SCSICMD db sread ; 0765 00 db 0 ; high address 0766 00 db 0 ; middle address 0767 00 LOWADDR db 6AB CDA807 call scsi ; do the write 06AE C2E406 jnz scsierr 06B1 CD4207 call puts 06B4 0D0A446F6E db cr,lf,'Done! You may now boot from hard disk.',cr,lf,lf,0 06E1 C33C07 jmp exit ; ; show any scsi error that may have occured ; SCSIERR: 06E4 1A ldax d ; 'de' has address of sense info 06E5 F5 push psw ; save it 06E6 E6F0 ani 0f0h 06E8 1F rar ; convert upper nibble to ascii 0 ; low address 0768 01 db 1 ; number of sectors=1 0769 00 db 0 ; reserved ;***********************Save area************************** ; 076A OLDSTK: ds 2 ; storage for old stack pointer ; BJ$TBL: ; table of bios jumps 076C CBOOT ds 3 ; cold boot address 076F ds 3 ; warm boot 0772 CONST: ds 3 ; console status 0775 CONIN: ds 3 ; console character in  06E9 1F rar 06EA 1F rar 06EB 1F rar 06EC FE0A cpi 10 ; alpha or numeric 06EE DAF606 jc num0 06F1 C637 adi '7' ; alpha offset (A thru F) 06F3 C3F706 jmp num0+1 ; 06F6 C630 NUM0: adi '0' ; numeric offset (0 thru 9) 06F8 323607 sta errtyp ; ; do second digit ; 06FB F1 pop psw 06FC E60F ani 0fh 06FE FE0A cpi 10 0700 DA0807 jc num1 ; numeri 0778 CONOUT: ds 3 ; console character out 077B ds 3 ; list char out 077E ds 3 ; punch char out 0781 ds 3 ; reader char in 0784 ds 3 ; home 0787 SELDSK: ds 3 ; select disk 078A SETTRK: ds 3 ; set track number 078D SETSEC: ds 3 ; set sector number 0790 ds 3 ; set dma address 0793 ds 3 ; read disk 0796 ds 3 ; write disk 0799 ds 3 ; return list statusc 0703 C637 adi '7' ; alpha offset (A thru F) 0705 C30A07 jmp num1+2 0708 C630 NUM1: adi '0' ; numeric offset (0 thru 9) 070A 323707 sta errtyp+1 ; 070D CD4207 ERRMSG: call puts 0710 0D0A534353 db cr,lf,'SCSI read/write error, Sense byte = ' 0736 20200D0A0AERRTYP: db ' ',cr,lf,lf,0 ; fall thru and exit ; 073C AF EXIT: xra a 073D 2A6A07 lhld oldstk 0740 F9 sphl 0741 C9 ret  079C ds 3 ; sector translate 079F GETTBL: ds 3 ; point to next jmp table 07A2 ds 3 ; getedsk, pointer to 'e' disk prameters 07A5 ds 3 ; ioinit 07A8 SCSI: ds 3 ; scsi direct driver ; 07AB ds 32 ; 32 byte stack area 07CB = STACK: EQU $ ; 07CB BTSEC: DS 512 ; USER$TAB: 09CB UDPBASE: DS 256 ; users dpbase 0ACB UPHYTAB : DS 64 ; users phytab 0B0B UHDDPB: DS 176 ; users hd dpb's 0BBB UHDAVAL: DS 12 ; users hd$alv$avail values 0BC7 BYTEBLK: DS 1 ; scsi controller byte, block value 01FD = TBL$SIZE: EQU $-user$tab 0BC8 END LDA CDRIVE$OK ; Check for drive defined 0687 B7 ORA A ; . 0688 200C DB JRNZ,DPOK-$-1 ; Drive defined -- conti * * * * * * * * * * * * * * * * * * * * * * * * * * * * * CLEAR$HDC: 06CE CDE119 CALL LB$HD$INFO ; Get pointer to HD info 06D1 E5 PUSH H ; Bump to absolute start 06D2 23 INX H ; . 06D3 23 INX H ; . 06D4 5E MOV E,M ; Get absolute start vector 06D5 23 INX H ; . 06D6 56 MOV D,M ; . 06D7 E1 POP H ; Plug in current HD info 06D8 73 MOV M,E ; . 06D9 23 INX nue 068A 112813 LXI D,NO$DRIVE$MSG ; No drive defined -- display message 068D 218D13 LXI H,NO$DRIVE$OKC ; . and return to main menu. 0690 CD1318 CALL PROMPT ; . 0693 C39A05 JMP AGAIN ; . DPOK: 0696 119013 LXI D,CPM$LTR$MSG ; Get CP/M drive letter 0699 1803 DB JR,GET$PART-$-1 ; . GET$PART$2: ; . 069B 11F413 LXI D,CPM$LTR$MSG2 ; . GET$PART: ; . 069E 213F14 LXI H,CPM$LB>@!*>@ ~!9"j1!w# xR*.l@)ʲ02B Little Board ID = , must = 7 to run this utility.<B AMPRO Hard Disk Auto-Boot Installer Copyright (C) 1985 AMPRO Computers, Inc. Version 1.2 This utility will install your current hard disk configuration on the system tracks of the SCSI hard disk drive located at SCSI ID 0, LUN 0. Prior to us1006B00006CD42070D0A446F6E65212020596F75E3 :1006C000206D6179206E6F7720626F6F7420667283 :1006D0006F6D2068617264206469736B2E0D0A0A65 :1006E00000C33C071AF5E6F01F1F1F1FFE0ADAF6CB :1006F00006C637C3F706C630323607F1E60FFE0AE4 :10070000DA0807C637C30A07C630323707CD4207B3 :100710000D0A5343534920726561642F77726974DF :1007200065206572726F722C2053656E736520624E :10073000797465203D2020200D0A0A00AF2A6A073F :10074000F9C9E14ECD78077EFE0ACC5407237EA777 :10075000C24307E90604110000137BBAC25907051A :0A076000C8C359070ing this program you must use SYSGEN to write the proper size CP/M system to the system tracks of the SCSI hard disk drive from which you will boot. In addition, you must have already used the HINIT and SWAP utilities to customize your system. NOTE: The CP/M system you install on the hard disk must identical to the system you are running now. WARNING!!! As a safety measure, be sure to backup your hard disk before you perform this function or attempt hard disk auto-booting! Do you wi800000001009B :0000000000 0A65 :1006E00000C33C071AF5E6F01F1F1F1FFE0ADAF6CB :1006F00006C637C3F706C630323607F1E60FFE0AE4 :10070000DA0807C637C30A07C630323707CD4207B3 :100710000D0A5343534920726561642F77726974DF :1007200065206572726F722C2053656E736520624E :10073000797465203D2020200D0A0A00AF2A6A073F :10074000F9C9E14ECD78077EFE0ACC5407237EA777 :10075000C24307E90604110000137BBAC25907051A :0A076000C8C359070sh to continue? (Y/N) u_Y<>2d!d>ͨ>ʛ!ʛB Valid Boot sector not present on hard disk, do SYSGEN, HINIT, and SWAP, then retry.<!›~#fo"*."@." ͟"!"#@͇ ~#fo~)*B Run HINIT and SWAP to set up your system first. <*.P ~#fo"+͟"P"3 ~#fo~";!w# xr!?> 2d>!dͨ> 2d>2g!d >ͨB Done! You may now boot from hard disk. < 7026  via warm boot, 06CB C3A219 JMP LB$WBOOT ; . then JUMP! ENDIF IF NOT RTN$VIA$WB ; Otherwise, DW LSPD80,STACK ; . Get old stack ptr back. RET ; . and return to cp/m ENDIF * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Routines specific to this program . . . * * * 7 027B SCSI read/write error, Sense byte = *jNx~ T#~C{YY 3207 DW INIT$XEBEC ; Xebec 1410(A) 071C 5C07 DW INIT$DTC ; Data Technology 500 Series NO$INIT$NEEDED: 071E 112815 LXI D,CD$MSG ; Just set message 0721 C9 RET INIT$SHUGART: 0722 CDE119 CALL LB$HD$INFO ; Get HD info pointer 0725 110400 LXI D,4 ; Bump to byte/block ptr 0 728 19 DAD D ; . 0729 CD2517 CALL GET$HL$PTR ; Get pointer in HL 072C 3601 MVI M,1 ; Set byte mode 072E 112815 LXI D,CD$MSG ; Set A-OK message 0731 C9 RET INIT$XEBEC: 0732 115407 LXI D,X$ID ; Where to put the fmt data 0735 21C615 LXI H,DRV$CYLS ; . 0738 010700 LXI B,7 ; . 073B EDB0 DB 0EDH,0B0H ; . (LDIR) 073D 214E07 LXI H,X$IC ; Init Drive Characteristics 0740 115407 LXI D,532A3073AC8153D32A0073A85 :10077000CD155F1600219207197E329E07AF32CD4C :1007800015219707119D07CDFE06112815C811D414 :1007900014C93C04030201C200000000000B000069 :1007A0000000000000002ACF15CD4C17CD4C17CD0E :1007B0004C1722D8152922D6152AD615010700096B :1007C000CD4C17CD4C17CD4C1722DA15ED4BDF155C :1007D00009ED5BD115CD6016380A117514CD7F1760 :1007E000CD0B19C93ACE15CDE7193603237EE6F0B5 :1007F00032DC15473ACD15E60FB077233AC515F62A :100800000A77233AC315772AE1153ADC154F06001B :1008100009010A000922DD152323ED5BDFX$ID ; . 0743 CDFE06 CALL DO$SCSI ; . 0746 112815 LXI D,CD$MSG ; Init ok -- load A-OK msg 0749 C8 RZ ; 074A 11D414 LXI D,INIT$ERR$MSG ; Init failed -- load error msg 074D C9 RET 074E 0C X$IC: DB 0CH 074F 0000000000 DB 0,0,0,0,0 0754 0000000000X$ID: DB 0,0,0,0,0,0,0,11 INIT$DTC: 075C 2AC615 LHLD DRV$CYLS 075F 22A107 SHLD D$CYL 0762 3ACA15 LDA DRV$RWC+1 0765 32A307 STA D$RWC 071573238F :100820007223732372232ADA151922DF15EBCDE127 :10083000197323722ADD15CD2517E501050009ED91 :100840005BD6151B732372E1010D0009ED5BD31517 :100850007323722AD8151922D315AF2ADF15EB2A74 :10086000D115ED522BEB219315CD9E16117715CD99 :100870000E16C9446F20796F752077616E742074ED :100880006F20636C65617220746865206578697398 :1008900074696E672068617264206469736B20619B :1008A000737369676E6D656E74732028592F4E29B6 :1008B0003F2024594E002A2A2A2050726576696FFB :1008C00075732068617264206469736B206173734F :1008D068 3AC815 LDA DRV$HEAD 076B 3D DCR A 076C 32A007 STA D$HD 076F 3ACD15 LDA STEP$RATE 0772 5F MOV E,A 0773 1600 MVI D,0 0775 219207 LXI H,D$TRAN$TBL 0778 19 DAD D 0779 7E MOV A,M 077A 329E07 STA D$STPR 077D AF XRA A 077E 32CD15 STA STEP$RATE 0781 219707 LXI H,D$MSC 0784 119D07 LXI D,D$MSD 0787 CDFE06 CALL DO$SCSI 078A 112815 LXI D,CD$MSG ; Init ok -- load A-OK msg 078D C8 RZ ; 078E0069676E6D656E7473206861766520626508 :1008E000656E20636C6561726564202A2A2A0D0A90 :1008F000240D0A0A4F7074696F6E73206176616906 :100900006C61626C653A0D0A092028442920204454 :100910006566696E65207468652043757272656EE0 :10092000742044726976650D0A0920284129202027 :10093000416464206120706172746974696F6E2013 :10094000746F207468652043757272656E742044FC :10095000726976650D0A0A092845534329204578AE :100960006974207468652070726F6772616D0D0A1A :100970000A57686174206E6578742028442F412FCF :10098000455343293F20244 11D414 LXI D,INIT$ERR$MSG ; Init failed -- load error msg 0791 C9 RET D$TRAN$TBL: 0792 3C DB 60 0793 04 DB 4 0794 03 DB 3 0795 02 DB 2 0796 01 DB 1 0797 C20000 D$MSC: DB 0C2H,0,0 079A 000000 DB 0,0,0 079D 0B D$MSD: DB 11 079E 00 D$STPR: DB 0 079F 00 DB 0 07A0 00 D$HD: DB 0 07A1 0000 D$CYL: DB 0,0 07A3 000000 D$RWC: DB 0,0,0  ADD$PARTITION: 07A6 2ACF15 LHLD PARTITION ; Get partition size (in K) 07A9 CD4C17 CALL HL$DIV$2 ; Divide K by 8 to get number 07AC CD4C17 CALL HL$DIV$2 ; . of tracks in this partition 07AF CD4C17 CALL HL$DIV$2 ; . 07B2 22D815 SHLD NTRACKS ; . 07B5 29 DAD H ; Multiply tracks by 2 to get # 07B6 22D615 SHLD NBLOCKS ; . of blocks in this partition 07B9 2AD615 LHLD NBLOCKS ; Compute the number1006B0005914328315114B14CD8B1828DE5FB228E4 :1006C000F4ED53CF15CDA607C39A05C3A219CDE10A :1006D00019E523235E2356E1732372AFF5CDE719A5 :1006E0007EFE0320023600F13CFE1030EFCDE11912 :1006F000CD251722DF1511B608CD0E16C9C9233A2C :10070000C515B6772B3AC315CDDB19B7C93AC41551 :10071000211607C342171E07220732075C0711285C :1007200015C9CDE11911040019CD2517360111287D :1007300015C911540721C615010700EDB0214E0758 :10074000115407CDFE06112815C811D414C90C0088 :1007500000000000000000000000000B2AC6152267 :10076000A1073ACA1 of ALV bytes 07BC 010700 LXI B,7 ; . required for this partition 07BF 09 DAD B ; . 07C0 CD4C17 CALL HL$DIV$2 ; . ( the actual formula is: ) 07C3 CD4C17 CALL HL$DIV$2 ; . ( ALVB = [NBLOCK + 7] / 8 ) 07C6 CD4C17 CALL HL$DIV$2 ; . 07C9 22DA15 SHLD ALVBYTES ; Allocation vector size (in bytes) 07CC ED4BDF15 DW LBCD80,HDC$ALV ; Get ALV base in BC 07D0 09 DAD B ; Add to HL 07D1 ED5BD115 DW LDED80,LAST$BYTE; Compare to last availabl e byte 07D5 CD6016 CALL CMP$HL$DE ; . 07D8 380A DB JRC,ENOUGH-$-1 ; Enough room? 07DA 117514 LXI D,NOT$ENOUGH$RM ; No ... tell 'em. 07DD CD7F17 CALL JUSTIFY ; . 07E0 CD0B19 CALL RET$TO$CONT ; . 07E3 C9 RET ENOUGH: ; ; Update PHYTAB ... ; 07E4 3ACE15 LDA CPM$LTR ; Get data for this logical drive 07E7 CDE719 CALL LB$GETLOGICAL ; . 07EA 3603 MVIH ; . 083B 010500 LXI B,5 ; Bump to disk size 083E 09 DAD B ; . 083F ED5BD615 DW LDED80,NBLOCKS ; Save # of blocks (CP/M wants 0843 1B DCX D ; . [blocks - 1] stored here) 0844 73 MOV M,E ; . 0845 23 INX H ; . 0846 72 MOV M,D ; . 0847 E1 POP H ; . 0848 010D00 LXI B,13 ; Bump to reserved tracks 084B 09 DAD B ; . 084C ED5BD315 DW LDED80,RESERVED ; Save reserved tracks 0850 73 MOV M,E ; . 0851 23  M,03H ; Set Hard Disk driver 07EC 23 INX H ; . 07ED 7E MOV A,M ; Get DPH offset 07EE E6F0 ANI 0F0H ; . 07F0 32DC15 STA DPHOFS ; . (save in order to update DPH) 07F3 47 MOV B,A ; Or in step rate code 07F4 3ACD15 LDA STEP$RATE ; . 07F7 E60F ANI 00FH ; . 07F9 B0 ORA B ; . 07FA 77 MOV M,A ; Save as DPH/step rate 07FB 23 INX H ; . 07FC 3AC515 LDA DRV$LUN ; . 07FF F60A ORI 0AH ; Set to 512 byte sect INX H ; . 0852 72 MOV M,D ; . 0853 2AD815 LHLD NTRACKS ; Update reserved tracks 0856 19 DAD D ; . 0857 22D315 SHLD RESERVED ; . ; ; Display "successful" message ; 085A AF XRA A ; Clear carry 085B 2ADF15 LHLD HDC$ALV ; Compute space remaining 085E EB XCHG ; . 085F 2AD115 LHLD LAST$BYTE ; . 0862 ED52 DB 0EDH,052H ; SBC HL,DE 0864 2B DCX H ; . 0865 EB XCHors, 4K AU 0801 77 MOV M,A ; . 0802 23 INX H ; . 0803 3AC315 LDA SCSI$ADDR ; Update SCSI address 0806 77 MOV M,A ; . ; ; Update DPH ; 0807 2AE115 LHLD DPH$BASE ; Get DPH base 080A 3ADC15 LDA DPHOFS ; Add offset for this unit 080D 4F MOV C,A ; . 080E 0600 MVI B,0 ; . 0810 09 DAD B ; . 0811 010A00 LXI B,0AH ; Add offset to DPB 0814 09 DAD B ; . 0815 22DD15 G ; Convert to decimal 0866 219315 LXI H,SPACE$LEFT$DEC; . 0869 CD9E16 CALL DE$TO$HL$DEC ; . 086C 117715 LXI D,SPACE$LEFT ; . 086F CD0E16 CALL CENTER$OUTPUT ; . 0872 C9 RET * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Misc data and messages . . . * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *  SHLD HDC$UNIT$DPB ; . 0818 23 INX H ; Bump to CKV 0819 23 INX H ; . 081A ED5BDF15 DW LDED80,HDC$ALV ; Get allocation vector to DE 081E 73 MOV M,E ; Save in CKV 081F 23 INX H ; . 0820 72 MOV M,D ; . 0821 23 INX H ; Save in ALV 0822 73 MOV M,E ; . 0823 23 INX H ; . 0824 72 MOV M,D ; . 0825 23 INX H ; . 0826 2ADA15 LHLD ALVBYTES ; Add ALV to ALVBYTES 0829 19 DAD 0873 446F20796FCLEAR$HDC$MSG: DB 'Do you want to clear the existing hard ' 089A 6469736B20 DB 'disk assignments (Y/N)? ','$' 08B3 594E00 CLEAR$HDC$OKC: DB 'YN',0 08B6 2A2A2A2050HDC$CLR$DONE: DB '*** Previous hard disk assignments have ' 08DE 6265656E20 DB 'been cleared ***',CR,LF,'$' 08F1 0D0A0A MAIN$MENU$MSG: DB CR,LF,LF 08F4 4F7074696F DB 'Options available:',CR,LF 0908 0920284429 DB TAB,' (D) Define the Current  D ; . 082A 22DF15 SHLD HDC$ALV ; Save updated ALV base 082D EB XCHG ; . 082E CDE119 CALL LB$HD$INFO ; Get pointer in BIOS to ALV base 0831 73 MOV M,E ; Save updated ALV base in BIOS 0832 23 INX H ; . 0833 72 MOV M,D ; . ; ; Update HDC DPB ... ; 0834 2ADD15 LHLD HDC$UNIT$DPB ; Get ptr to unit DPB ptr back 0837 CD2517 CALL GET$HL$PTR ; Get actual unit DPB ptr in HL 083A E5 PUSH Drive',CR,LF 0929 0920284129 DB TAB,' (A) Add a partition to the ' 0947 4375727265 DB 'Current Drive',CR,LF,LF 0957 0928455343 DB TAB,'(ESC) Exit the program',CR,LF,LF 0971 5768617420 DB 'What next (D/A/ESC)? ','$' 0987 444100 MAIN$MENU$OKC: DB 'DA',0 098A 0D0A0A0A0ASCSI$ADDR$MSG: DB CR,LF,LF,LF,LF,LF 0990 446566696E DB 'Defining the Current Drive ...' 09AE 0D0A DB CR,LF 09B0 3D3D3D3D3D DB '======================================' 09D6 0D0A DB CR, 441000D0A0A0A0A0A1C :10099000446566696E696E67207468652043757288 :1009A00072656E74204472697665202E2E2E0D0AB3 :1009B0003D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D67 :1009C0003D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D57 :1009D0003D3D3D3D3D3D0D0A0A0A54686520437585 :1009E0007272656E74204472697665206973207432 :1009F000686520706879736963616C2068617264EE :100A0000206469736B20647269766520796F752044 :100A10006172652063757272656E746C7920776F90 :100A2000726B696E6720776974682E202054686540 :100A300020646566696E6974696F6E206F66207496F752061 DB 'you are using a Xebec 1410(A) controller.' 0B14 0D0A0A4861 DB CR,LF,LF,'Hard disk controller SCSI ID:' 0B34 0D0A2D2D2D DB CR,LF,'-----------------------------' 0B53 0D0A0A DB CR,LF,LF 0B56 4561636820 DB 'Each hard disk controller must be set ' 0B7C 746F206F6E DB 'to one of the eight SCSI bus ID''s. These ' 0BA6 4944277320 DB 'ID''s range from zero (0) to seven (7). ' 0BCE 496620796F DB 'If you have only one hard disk controller ' 0BF8 696E20796F DB 'in your systeE4 :100A4000686520647269766520636F6E736973747C :100A500073206F66207468652053435349204944CE :100A600020616E642074797065206F6620746865FB :100A70002068617264206469736B20636F6E7472A6 :100A80006F6C6C657220636F6E6E65637465642055 :100A9000746F207468652064726976652C207468B0 :100AA00065206C6F676963616C20756E6974206E78 :100AB000756D62657220284C554E29206F66207432 :100AC00068652064726976652C20616E64207468A4 :100AD000652064726976652063686172616374651C :100AE0007269737469637320696620796F75206118 :100AF0007265m, it''s ID is usually zero ' 0C20 2830292E20 DB '(0). If you have more than one hard disk ' 0C4A 636F6E7472 DB 'controller, make sure they are set to ' 0C70 6469666665 DB 'different ID''s.',CR,LF,LF 0C82 5768617420 DB 'What is the SCSI ID of the current drive''s ' 0CAD 636F6E7472 DB 'controller (0-7, ESC to quit)? ','$' 0CCD 3031323334SCSI$ADDR$OKC: DB '01234567',0 0CD6 0D0A486172HD$CTRL$MSG: DB CR,LF,'Hard disk controller type:' 0CF2 0D0A2D2D2D DB CR,LF,'----------207573696E67206120586562656351 :100B0000203134313028412920636F6E74726F6C4C :100B10006C65722E0D0A0A48617264206469736BF9 :100B200020636F6E74726F6C6C657220534353490F :100B30002049443A0D0A2D2D2D2D2D2D2D2D2D2DF5 :100B40002D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2DD5 :100B50002D2D2D0D0A0A456163682068617264209D :100B60006469736B20636F6E74726F6C6C65722056 :100B70006D7573742062652073657420746F206FC7 :100B80006E65206F662074686520656967687420EB :100B9000534353492062757320494427732E202004 :100BA000546865736520494427732----------------' 0D0E 0D0A0A DB CR,LF,LF 0D11 4F66207468 DB 'Of the following controllers ...',CR,LF,LF 0D34 0931202D20 DB TAB,'1 - Generic burst-mode SCSI controller ' 0D5C 2841646170 DB '(Adaptec ACB4000, Xebec Owl)',CR,LF 0D7A 0932202D20 DB TAB,'2 - Generic byte-mode SCSI controller ' 0DA1 2853687567 DB '(Shugart 1610-4)',CR,LF 0DB3 0933202D20 DB TAB,'3 - Xebec 1410 or 1410A',CR,LF 0DCD 0934202D20 DB TAB,'4 - Data Technology 500 Series',CR,LF 0DEE 0A DB LF 0DEF 5072616E6765D8 :100BB0002066726F6D207A65726F2028302920744C :100BC0006F20736576656E202837292E20204966B0 :100BD00020796F752068617665206F6E6C79206F63 :100BE0006E652068617264206469736B20636F6E48 :100BF00074726F6C6C657220696E20796F757220EB :100C000073797374656D2C206974277320494420AF :100C1000697320757375616C6C79207A65726F20C9 :100C20002830292E2020496620796F75206861764A :100C300065206D6F7265207468616E206F6E65202F :100C400068617264206469736B20636F6E74726F85 :100C50006C6C65722C206D616B65207375726520FC :100C600074686579206172652073657420746F20E3 :100C7000646966666572656E7420494427732E0D3B :100C80000A0A5768617420697320746865205343A9 :100C90005349204944206F6620746865206375724B :100CA00072656E74206472697665277320636F6E57 :100CB00074726F6C6C65722028302D372C20455370 :100CC0004320746F2071756974293F2024303132BC :100CD0003334353637000D0A486172642064697315 :100CE0006B20636F6E74726F6C6C657220747970B8 :100CF000653A0D0A2D2D2D2D2D2D2D2D2D2D2D2D22 :100D00002D2D2D2D2D2D2D2D2D2D2D2D2D2D0D0A56 :100D10000A4F662074LF 09D8 0A0A DB LF,LF 09DA 5468652043 DB 'The Current Drive is the physical hard ' 0A01 6469736B20 DB 'disk drive you are currently working ' 0A26 776974682E DB 'with. The definition of the drive ' 0A49 636F6E7369 DB 'consists of the SCSI ID and type of ' 0A6D 7468652068 DB 'the hard disk controller connected to ' 0A93 7468652064 DB 'the drive, ' 0A9E 746865206C DB 'the logical unit number (LUN) of the ' 0AC3 6472697665 DB 'drive, and the drive characteristics if ' 0AEB 7686520666F6C6C6F77696E29 :100D20006720636F6E74726F6C6C657273202E2E09 :100D30002E0D0A0A0931202D2047656E6572696300 :100D40002062757273742D6D6F646520534353492F :100D500020636F6E74726F6C6C65722028416461E1 :100D60007074656320414342343030302C20586524 :100D7000626563204F776C290D0A0932202D2047C8 :100D8000656E6572696320627974652D6D6F646547 :100D9000205343534920636F6E74726F6C6C65729D :100DA00020285368756761727420313631302D34D4 :100DB000290D0A0933202D205865626563203134DE :100DC0003130206F722031343130410D0A0 9342026 :100DD0002D204461746120546563686E6F6C6F6789 :100DE0007920353030205365726965730D0A0A57D2 :100DF00068696368206F6E65206973207468652078 :100E000043757272656E7420447269766520636FF3 :100E10006E6E656374656420746F2028312C2032F7 :100E20002C20332C206F722034293F202431323380 :100E300034000D0A43757272656E742044726976CF :100E400065206C6F676963616C20756E6974206ED4 :100E5000756D6265723A0D0A2D2D2D2D2D2D2D2DBE :100E60002D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2DB2 :100E70002D2D2D2D2D2D2D2D2D2D0D0A0A45616386 :100E8003 DB 'the Current Drive is required:' 10E1 0D0A0A DB CR,LF,LF 10E4 2020202020 DB ' Number of cylinders? ','$' 1100 2020202020DRV$HEAD$MSG: DB ' Number of heads? ','$' 111C 5374617274DRV$RWC$MSG: DB 'Starting cylinder for RWC? ','$' 1138 5374617274DRV$WPC$MSG: DB 'Starting cylinder for WPC? ','$' 1154 0D0A XEB$STEP$MSG: DB CR,LF 1156 5865626563 DB 'Xebec 1410(A) step mode (choose from the ' 117F 666F6C6C6F DB 'following table):',CR,LF 1192 09302068206469736B20636F6E6E65637465645C :100E900020746F20612068617264206469736B2024 :100EA000636F6E74726F6C6C657220686173206121 :100EB00020756E69717565206E756D6265722C2086 :100EC00063616C6C656420746865204C6F6769634E :100ED000616C20556E6974204E756D6265722C20B0 :100EE0006F72204C554E2E20205468652066697222 :100EF0007374204C554E206F6E20612068617264BF :100F0000206469736B20636F6E74726F6C6C6572B2 :100F1000206973207A65726F202830292C20616E39 :100F20006420746865206E756D6265727320696EE9 :100F300063726561736520617420746861742070E8 :100F40006F696E7420746F2061206D6178696D75B2 :100F50006D206F6620736576656E202837292E20F8 :100F6000204D6F73742068617264206469736B2014 :100F7000636F6E74726F6C6C6572732063616E2048 :100F8000737570706F72742074776F2064726976F5 :100F900065732C207768696368206D65616E7320C6 :100FA000746865204C554E277320666F72207468F4 :100FB0006520636F6E74726F6C6C65722061726510 :100FC00020656974686572207A65726F20283029FF :100FD000206F72206F6E65202831292E20204966EF :100FE000206F6E6C79206F6E65206472697665206768696368 DB 'Which one is the Current Drive connected ' 0E18 746F202831 DB 'to (1, 2, 3, or 4)? ','$' 0E2D 3132 HD$CTRL$OKC: DB '12' 0002 = NON$GENERIC: EQU $-HD$CTRL$OKC 0E2F 333400 DB '34',0 0E32 0D0A437572DRV$LUN$MSG: DB CR,LF,'Current Drive logical unit number:' 0E56 0D0A2D2D2D DB CR,LF,'----------------------------------' 0E7A 0D0A0A DB CR,LF,LF 0E7D 4561636820 DB 'Each disk connected to a hard disk ' 0EA0 636F6E7472 DB 'controller has a 3 :100FF000697320636F6E6E65637465642C2074681A :1010000065206C6F676963616C20756E6974206E12 :10101000756D62657220284C554E29206973206ECB :101020006F726D616C6C79207A65726F202830293F :101030002E20200D0A0A5768617420697320746895 :10104000652043757272656E7420447269766527F7 :1010500073206C6F676963616C20756E6974206EB4 :10106000756D6265722028302D37293F202430317C :10107000323334353637000D0A466F722074686596 :1010800020636F6E74726F6C6C657220796F75205F :10109000696E646963617465642C20746865206698 :1010A0006F6C6unique number, called ' 0EC7 746865204C DB 'the Logical Unit Number, or LUN. ' 0EE9 5468652066 DB 'The first LUN on a hard disk ' 0F06 636F6E7472 DB 'controller is zero (0), and the numbers ' 0F2E 696E637265 DB 'increase at that point to a maximum of ' 0F55 736576656E DB 'seven (7). Most hard disk ' 0F70 636F6E7472 DB 'controllers can support two drives, which ' 0F9A 6D65616E73 DB 'means the LUN''s for the controller are ' 0FC1 6569746865 DB 'either zero (0) or one (1). If only ' C6F77696E67206164646974696FD7 :1010B0006E616C20696E666F726D6174696F6E200F :1010C0006F6E207468652043757272656E7420447B :1010D00072697665206973207265717569726564DD :1010E0003A0D0A0A2020202020204E756D6265727C :1010F000206F662063796C696E646572733F20248B :10110000202020202020202020204E756D62657236 :10111000206F662068656164733F20245374617298 :1011200074696E672063796C696E64657220666F9E :1011300072205257433F20245374617274696E6762 :101140002063796C696E64657220666F72205750F7 :10115000433F20240D0A5865626563 0FE6 6F6E652064 DB 'one drive is connected, the logical ' 100A 756E697420 DB 'unit number (LUN) is normally zero (0). ' 1033 0D0A0A DB CR,LF,LF 1036 5768617420 DB 'What is the Current Drive''s logical ' 105A 756E697420 DB 'unit number (0-7)? ','$' 106E 3031323334DRV$LUN$OKC: DB '01234567',0 1077 0D0A DRV$CYLS$MSG: DB CR,LF 1079 466F722074 DB 'For the controller you indicated, ' 109B 7468652066 DB 'the following additional information on ' 10C3 7468652042031343130E5 :101160002841292073746570206D6F6465202863A1 :10117000686F6F73652066726F6D20746865206696 :101180006F6C6C6F77696E67207461626C65293A69 :101190000D0A0930202D202020336D7320737465D3 :1011A000700D0A0934202D2032303075732062759D :1011B00066666572656420737465700D0A09352072 :1011C0002D20203730757320627566666572656400 :1011D00020737465700D0A0936202D202033307578 :1011E0007320627566666572656420737465700D40 :1011F0000A0937202D202031357573206275666607 :101200006572656420737465700D0A576869636858 :10 02D20 DB TAB,'0 - 3ms step',CR,LF 11A3 0934202D20 DB TAB,'4 - 200us buffered step',CR,LF 11BD 0935202D20 DB TAB,'5 - 70us buffered step',CR,LF 11D7 0936202D20 DB TAB,'6 - 30us buffered step',CR,LF 11F1 0937202D20 DB TAB,'7 - 15us buffered step',CR,LF 120B 5768696368 DB 'Which step mode (0, 4, 5, 6, or 7)? ','$' 1230 30FFFFFF34XEB$STEP$OKC: DB '0',0FFH,0FFH,0FFH,'4567',0 1239 0D0A DTC$STEP$MSG: DB CR,LF 123B 4461746120 DB 'Data Technology 500 Series step mod5700D0A0933202D20313058 :1012D0003075732062756666657265642073746527 :1012E000700D0A0934202D20203530757320627569 :1012F00066666572656420737465700D0A57686967 :1013000063682073746570206D6F64652028302CCD :1013100020312C20322C20332C206F722034293F96 :101320002024303132333400506C656173652064A1 :101330006566696E65207468652043757272656EB6 :1013400074204472697665206265666F72652061FB :101350006464696E67206120706172746974696F7A :101360006E20746F2069742E0D0A5072657373209D :101370007468652052455455524E206B6579e ' 1260 2863686F6F DB '(choose from the ' 1271 666F6C6C6F DB 'following table):',CR,LF 1284 0930202D20 DB TAB,'0 - 3ms step',CR,LF 1295 0931202D20 DB TAB,'1 - 200us buffered step',CR,LF 12AF 0932202D20 DB TAB,'2 - 150us buffered step',CR,LF 12C9 0933202D20 DB TAB,'3 - 100us buffered step',CR,LF 12E3 0934202D20 DB TAB,'4 - 50us buffered step',CR,LF 12FD 5768696368 DB 'Which step mode (0, 1, 2, 3, or 4)? ','$' 1322 3031323334DTC$STEP$OKC: DB '01234',0 1328 50620742F :101380006F20636F6E74696E75652E20240D0A00E0 :101390000D0A0A41646420612043502F4D20706182 :1013A00072746974696F6E206F6E20746865204373 :1013B000757272656E74204472697665202E2E2EC9 :1013C0000D0A3D3D3D3D3D3D3D3D3D3D3D3D3D3DB0 :1013D0003D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D :1013E0003D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D2D :1013F0003D3D0D0A0D0A43502F4D206C65747465F8 :101400007220746F2075736520666F72207468692E :101410007320706172746974696F6E2028462D5054 :101420002C2045534320666F72206E6577204375EC :10143000C656173NO$DRIVE$MSG: DB 'Please define the Current Drive before ' 134F 616464696E DB 'adding a partition to it.',CR,LF 136A 5072657373 DB 'Press the RETURN key to continue. ','$' 138D 0D0A00 NO$DRIVE$OKC: DB CR,LF,0 1390 0D0A0A CPM$LTR$MSG: DB CR,LF,LF 1393 4164642061 DB 'Add a CP/M partition ' 13A8 6F6E207468 DB 'on the Current Drive ...',CR,LF 13C2 3D3D3D3D3D DB '========================' 13DA 3D3D3D3D3D DB '========================' 13F2 0D0A DB CR,L7272656E74204472697665293F20244675 :101440004748494A4B4C4D4E4F50000D0A53697A5C :1014500065206F662074686520783A207061727428 :101460006974696F6E2028696E204B2062797465FB :1014700073293F20240D0A54686572652069732022 :101480006E6F7420656E6F75676820737061636539 :10149000206C65667420746F20696E7374616C6C67 :1014A00020612068617264206469736B20706172CE :1014B000746974696F6E206F662074686520736943 :1014C0007A6520796F7520696E64696361746564FB :1014D0002E0D0A242A2A2A2043616E6E6F74206919 :1014E0006E697469616C697A6F 13F4 0D0A CPM$LTR$MSG2: DB CR,LF 13F6 43502F4D20 DB 'CP/M letter to use for this partition ' 141C 28462D502C DB '(F-P, ESC for new Current Drive)? ','$' 143F 464748494ACPM$LTR$OKC: DB 'FGHIJKLMNOP',0 144B 0D0A PARTITION$MSG: DB CR,LF 144D 53697A6520 DB 'Size of the ' 1459 783A207061CPM$LTR$ECHO: DB 'x: partition (in K bytes)? ','$' 1475 0D0A546865NOT$ENOUGH$RM: DB CR,LF,'There is not enough space left to ' 1499 696E737461 DB 'install a ha52048444320666F4F :1014F00072207468652043757272656E7420447240 :10150000697665202D2D20636865636B20796F7582 :10151000206469736B20706172616D6574657273AC :101520002E202A2A2A0D0A240D0A2A2A2A20437547 :101530007272656E742044726976652073657420DA :10154000746F3A2053435349204944205B785D2C03 :101550002048444320747970653A205B785D2C20E4 :101560006C6F676963616C20756E6974205B785D70 :101570002E202A2A2A0D240D0A3C3C3C2044726964 :10158000766520783A20696E7374616C6C656420AE :101590002D2D207878787878206279746573206FA31210002073746570206D6F64652028302C203435 :101220002C20352C20362C206F722037293F20248B :1012300030FFFFFF34353637000D0A4461746120FA :10124000546563686E6F6C6F67792035303020535A :1012500065726965732073746570206D6F646520B5 :101260002863686F6F73652066726F6D20746865A0 :1012700020666F6C6C6F77696E67207461626C6555 :10128000293A0D0A0930202D202020336D73207358 :101290007465700D0A0931202D20323030757320AD :1012A000627566666572656420737465700D0A09FF :1012B00032202D2031353075732062756666657277 :1012C00065642073746 :1015A000662062696F73206275666665722061727B :1015B00065612072656D61696E696E672E203E3EC1 :1015C0003E0D2400000000000000000000000000AC :1015D000000000000000000000000000000000000B :1015E00000000000F50F0F0F0FE60FCDF9156FF19A :1015F000F5E60FCDF91567F1C9FE0AFA0016C60720 :10160000C630C9E6073C47AF37170520FCC9F5C50A :10161000E5CD2C1778B7CA30163A03013798DA2986 :1016200016E6FE0F0E20C475167E3624CD90167772 :101630007EFE0DCA4416FE0ACA4416FE24CA50167F :10164000EBC31116CD6616FE0ACC951923C33016CE :10165000E1C1F1  C9F53E1ACDEC163DC25716F1C9EC :101660007CBAC07DBBC9F5C5D5E50E025FCD0500CE :10167000E1D1C1F1C9F5C5D5E54779CD661605C2F9 :101680007B16E1D1C1F1C9CDA819FE03CACB06C9A9 :10169000F5C5D5E50E09CD0500E1D1C1F1C93E0181 :1016A0001801AF32EB16C5D5E501F0D8CDCA160149 :1016B00018FCCDCA16019CFFCDCA1601F6FFCDCA93 :1016C000167BC63077AFE1D1C1C93E30E5EB5D5442 :1016D0003C0938FA3DE177FE30200A3AEB16B7288C :1016E0000836201804AF32EB1623C900F53E0DCDA5 :1016F00066163E0ACD66163A0401B7C49519F1C9BB :101700002A010011A219013C00EDB03V 15E1 0000 DPH$BASE: DW 0 15E3 00 CDRIVE$OK DB 0 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Library routines . . . * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * A$TO$HL$HEX: ; ; [DC.27] ; E0ACDD21908 :10171000322417237CB5C82B11DE19010F00EDB060 :101720003EFFB7C900F57E23666FF1C9D506001AE2 :10173000FE0DCA3F17FE24CA3F170413C32F17E13B :10174000EBC9010200CD5617CD2517E9F5AF7C1F77 :10175000677D1F6FF1C9B7C8093DC35717E54F062D :1017600000FE1BCA7A17047EB7C271173D47C37AC1 :1017700017B9CA7A172304C3671778B779E1C93E46 :101780008018023E00320D183E2432AF1AEBAF3201 :1017900012184711B01A7EFE0D200BCDFB173E0D1F :1017A000CD66162318E8FE0A2006CD66162318E635 :1017B000FE0C2006CD54162318DCFE242004CDFB9D :101 ; Converts the number in A to the hex digits in HL ; ; Entry: ; A = number to convert ; ; Exit: ; HL = the hex equivalent of the number (L=high, H=low) ; (use shld to store the converted number) ; ; Modifies: none ; 15E4 F5 PUSH PSW ; Save original number 15E5 0F RRC ; Get high nybble 15E6 0F RRC rd disk partition of the ' 14BE 73697A6520 DB 'size you indicated.' 14D1 0D0A24 DB CR,LF,'$' 14D4 2A2A2A2043INIT$ERR$MSG: DB '*** Cannot initialize HDC for the Current ' 14FE 4472697665 DB 'Drive -- check you disk parameters. ***' 1525 0D0A24 DB CR,LF,'$' 1528 0D0A2A2A2ACD$MSG: DB CR,LF,'*** Current Drive set to: SCSI ID [' 154D 785D2C2048CD$ID: DB 'x], HDC type: [' 155C 785D2C206CCD$TYPE: DB 'x], logical unit [' 156E 785D2E202ACD$LUN: DB  ; . 15E7 0F RRC ; . 15E8 0F RRC ; . 15E9 E60F ANI 0FH ; . 15EB CDF915 CALL A$TO$HEX ; Convert to hex 15EE 6F MOV L,A ; Save in L register 15EF F1 POP PSW ; Get original number back 15F0 F5 PUSH PSW ; Save again for later 15F1 E60F ANI 0FH ; Get low nybble 15F3 CDF915 CALL A$TO$HEX ; Convert to hex 15F6 67 MOV H,A ; Save in H register 15F7 F1 POP PSW ; Get original number back 15F8 C9 RET 'x]. ***',CR,'$' 1577 0D0A3C3C3CSPACE$LEFT: DB CR,LF,'<<< Drive ' 1583 783A20696EDRIVE$INST: DB 'x: installed -- ' 1593 7878787878SPACE$LEFT$DEC: DB 'xxxxx bytes of bios buffer area ' 15B3 72656D6169 DB 'remaining. >>>',CR,'$' 15C3 00 SCSI$ADDR: DB 0 15C4 00 HD$CTRL: DB 0 15C5 00 DRV$LUN: DB 0 15C6 0000 DRV$CYLS: DW 0 15C8 00 DRV$HEAD: DB 0 15C9 0000 DRV$RWC: DW 0 15CB 0000  ; and return A$TO$HEX: ; Convert A to a hex digit 15F9 FE0A CPI 0AH ; If 0-9, we don't need to 15FB FA0016 JM A$TO$HEX$2 ; . add any offset 15FE C607 ADI 07H ; Offset for A-F A$TO$HEX$2: ; . 1600 C630 ADI 30H ; ASCII bias 1602 C9 RET ; and return BIN$TO$SCSI: ; ; [E6.10] ; ; Converts bi DRV$WPC: DW 0 15CD 00 STEP$RATE: DB 0 15CE 00 CPM$LTR: DB 0 15CF 0000 PARTITION: DW 0 15D1 0000 LAST$BYTE: DW 0 15D3 0000 RESERVED: DW 0 15D5 00 HDC$INIT: DB 0 15D6 0000 NBLOCKS: DW 0 15D8 0000 NTRACKS: DW 0 15DA 0000 ALVBYTES: DW 0 15DC 00 DPHOFS: DB 0 15DD 0000 HDC$UNIT$DPB: DW 0 15DF 0000 HDC$ALV: DW 0 ; HDC CSV & HDC ALnary 0-7 to SCSI address ; ; Entry: ; A = number to convert (0-7) ; ; Exit: ; A = converted SCSI address [00H = error] ; ; Modifies: B ; 1603 E607 ANI 07H ; Mask out all but addrs 0-7 1605 3C INR A ; Bump A to shift at least one bit 1606 47 MOV B,A ; . and move to the B register 1607 AF XRA A ; Clear A regist er 1608 37 STC ; Set carry for shift BIN$NEXT$BIT: 1609 17 RAL ; Shift left one bit 160A 05 DCR B ; Decrement count 160B 20FC DB JRNZ,BIN$NEXT$BIT-$-1 and 255 160D C9 RET ; Z = all done CENTER$OUTPUT: ; ; [DC.20] ; ; Automatically centers the output line(s) based on the line width ; stored in SCREEN$W; Go & do the next line OUTPUT$DELIM: 1644 CD6616 CALL CON$CHR ; Output delimiter 1647 FE0A CPI LF ; Wait 10ms if we have a line feed 1649 CC9519 CZ WAIT ; . 164C 23 INX H ; Point to next chr 164D C33016 JMP NEXT$DELIM ; and check that one, also CENTER$DONE: 1650 E1 POP H ; Restore registers 1651 C1 POP B ; . 1652 F1 POP PSW ; . 1653 C9 RET ; and return IDTH. Each line is delimited with CR+LF. This ; routine will return to the caller when it encounters the string ; terminator, '$'. Any additional LF characters after a CR+LF pair ; will be passed through. ; ; Entry: ; DE = Pointer to output string(s), terminated with CR+LF. ; ; Exit: ; The output string(s) are sent to the screen ;  CLEAR$SCREEN: ; ; [E1.28] ; ; This routine clears the screen by calling DO$CRLF 26 times. ; ; Entry: ; None ; ; Exit: ; The screen is cleared ; ; Modifies: ; None ; 1654 F5 PUSH PSW ; Save just in case 1655 3E1A MVI A,26 ; 26 CRLF's  ; Modifies: DE ; 160E F5 PUSH PSW ; Save registers 160F C5 PUSH B ; . 1610 E5 PUSH H ; . CENTER$NEXT$LN: 1611 CD2C17 CALL GET$STRLEN ; Get length to next CR or '$' in B 1614 78 MOV A,B ; Check for zero length 1615 B7 ORA A ; . 1616 CA3016 JZ NEXT$DELIM ; If so, output the CR, LF, etc. 1619 3A0301 LDA SCREEN$WIDTH ; Compute offset needed to center line 161C 37 STC ; . 161D 98  C$NEXT$LINE: 1657 CDEC16 CALL DO$CRLF ; Next line 165A 3D DCR A ; Done? 165B C25716 JNZ C$NEXT$LINE ; Nope. 165E F1 POP PSW ; Restore original AF 165F C9 RET ; and return CMP$HL$DE: ; ; [E6.10] ; ; Compare register pair HL with register pair DE. ; ; Entry: ; DE,HL = data to compar SBB B ; . (if there are too many chrs, just 161E DA2916 JC NO$BLANKS ; . print the line as is . . . ) 1621 E6FE ANI 0FEh ; Clear least significant bit 1623 0F RRC ; . and rotate to divide by two 1624 0E20 MVI C,' ' ; Output enough blanks to center line 1626 C47516 CNZ CON$CHR$AC ; . (only if count is non-zero) NO$BLANKS: 1629 7E MOV A,M ; Save CR for later 162A 3624 MVI M,'$' ; Plug position with '$' for cp/m 162C Ce ; ; Exit: ; Z: DE = HL, NZ: DE # HL ; C: HL < DE, NC: HL >= DE ; ; Modifies: ; PSW ; 1660 7C MOV A,H ; Compare high bytes 1661 BA CMP D ; . 1662 C0 RNZ ; If not zero, flags are set 1663 7D MOV A,L ; Compare low bytes 1664 BB CMP E ; . 1665 C9 RET ; Return with flags set D9016 CALL CON$MSG ; . print string function 162F 77 MOV M,A ; Restore saved CR NEXT$DELIM: 1630 7E MOV A,M ; Get character 1631 FE0D CPI CR ; Print it if CR 1633 CA4416 JZ OUTPUT$DELIM ; . 1636 FE0A CPI LF ; Print it if LF 1638 CA4416 JZ OUTPUT$DELIM ; . 163B FE24 CPI EOS ; Stop processing if EOS ('$') 163D CA5016 JZ CENTER$DONE ; . 1640 EB XCHG ; Put new pointer in DE 1641 C31116 JMP CENTER$NEXT$LN  CON$CHR: ; ; [DC.20] ; ; This routine sends the character in the "A" register to the console ; through the BDOS conout call. ; ; Entry: ; A = character to send ; ; Exit: ; character is sent to the console ; ; Modifies: ; None ; 1666 F5    PUSH PSW 1667 C5 PUSH B 1668 D5 PUSH D 1669 E5 PUSH H 166A 0E02 MVI C,2 166C 5F MOV E,A 166D CD0500 CALL BDOS 1670 E1 POP H 1671 D1 POP D 1672 C1 POP B 1673 F1 POP PSW 1674 C9 RET CON$CHR$AC: ; ; [DC.20] ; ; This routine sends the character in the C register to the console  1691 C5 PUSH B ; . 1692 D5 PUSH D ; . 1693 E5 PUSH H ; . 1694 0E09 MVI C,9 ; BDOS print string command 1696 CD0500 CALL BDOS ; . 1699 E1 POP H ; Restore registers 169A D1 POP D ; . 169B C1 POP B ; . 169C F1 POP PSW ; . 169D C9 RET ; and return DE$TO$HL$DEC: ; ; [E6.25] ; ; Convert the 1 ; the number of times in the A register. ; ; Entry: ; A = Number of times to send character ; C = Character to send ; ; Exit: ; Same ; ; Modifies: ; None ; 1675 F5 PUSH PSW ; Save all registers 1676 C5 PUSH B ; . 1677 D5 PUSH D ; . 1678 E5 PUSH H ; . 1679 47 6-bit number in the DE register pair to a 5-digit ; decimal number. Store this number starting in the memory pointed ; to by the HL register pair. Optionally convert leading zeroes to ; blanks. ; ; Call DE$TO$HL$DEC to convert leading zeroes to blanks ; Call DE$TO$HL$DEC$0 to leave leading zeroes alone ; ; Entry: ; DE = number to convert  MOV B,A ; Move data to accomodate CP/M 167A 79 MOV A,C ; . NEXT$CHR$OUT: 167B CD6616 CALL CON$CHR ; Send 1 chr 167E 05 DCR B ; Decrement counter 167F C27B16 JNZ NEXT$CHR$OUT ; Done? 1682 E1 POP H ; Restore all registers 1683 D1 POP D ; . 1684 C1 POP B ; . 1685 F1 POP PSW ; . 1686 C9 RET ; and return CONIN$NE$XC: ;  ; HL = ptr to target memory location ; ; Exit: ; DE,HL unchanged ; ; Modifies: ; PSW ; 169E 3E01 MVI A,1 ; Set "clear leading 0's" mode 16A0 1801 DB JR,E$DETOHL-$-1 ; Jump to entry point DE$TO$HL$DEC$0: 16A2 AF XRA A ; Set "leave leading 0's alone" mode E$DETOHL: 16A3 32EB16 STA DE$TO$HL$MODE ; Save mode flag 16A6 C5  ; [E1.28] ; ; Console input, no echo, exit on ctrl-c ; ; Entry: ; none ; ; Exit: ; A = character from console, except for ctrl-c, which causes ; an immediate jump to ALL$DONE ; ; Modifies: ; A ; 1687 CDA819 CALL LB$CONIN 168A FE03 CPI CTRLC 168C CACB06 JZ ALL$DON PUSH B ; Save registers 16A7 D5 PUSH D ; . 16A8 E5 PUSH H ; . 16A9 01F0D8 LXI B,-10000 ; Convert ten-thousands digit 16AC CDCA16 CALL TODEC ; . 16AF 0118FC LXI B,-1000 ; Convert thousands digit 16B2 CDCA16 CALL TODEC ; . 16B5 019CFF LXI B,-100 ; Convert hundreds digit 16B8 CDCA16 CALL TODEC ; . 16BB 01F6FF LXI B,-10 ; Convert tens digit 16BE CDCA16 CALL TODEC ; . 16C1 7B MOV A,E ; Convert ones digit 16C2 C630 E 168F C9 RET CON$MSG: ; ; [DC.20] ; ; Console message ; ; Entry: ; DE = pointer to message string, terminated with '$' ; ; Exit: ; message printed on console ; ; Modifies: A, BC ; 1690 F5 PUSH PSW ; Save registers  ADI '0' ; . (Leave zero intact) 16C4 77 MOV M,A ; . 16C5 AF XRA A ; Clear PSW 16C6 E1 POP H ; Restore registers 16C7 D1 POP D ; . 16C8 C1 POP B ; . 16C9 C9 RET ; and return ... TODEC: 16CA 3E30 MVI A,'0' ; Start with an ASCII zero 16CC E5 PUSH H ; Save target string pointer 16CD EB XCHG ; Move number to convert to HL TODEC1: 16CE 5D MOV E,L ;  Save a copy of current HL in DE 16CF 54 MOV D,H ; . (in case we're done) 16D0 3C INR A ; Bump digit 16D1 09 DAD B ; Add "negative" BC to HL 16D2 38FA DB JRC,TODEC1-$-1 and 255 ; Continue while Carry set 16D4 3D DCR A ; Get rid of extra bump 16D5 E1 POP H ; Restore target string pointer 16D6 77 MOV M,A ; Save digit 16D7 FE30 CPI '0' ; Is the digit an ascii zero? 16D9 200A DB JRNZ,NOZERO-$-1 ; No, Turn off leading 0' ; Entry: ; none ; ; Exit: ; Z = bios 1.0 - 1.4 (floppy only bios) ; NZ = bios 2.0 or greater (floppy & fixed disk bios) ; ; Modifies: All registers ; 1700 2A0100 LHLD 1 ; Get start of bios jump table 1703 11A219 LXI D,LB$BIOS$TBL ; Move bios to local storage 1706 013C00 LXI B,LB$LEN ; . (length of bios area) 1709 EDB0 DW LDIR80 ; . s flag 16DB 3AEB16 LDA DE$TO$HL$MODE ; Yes, Check leading 0's flag 16DE B7 ORA A ; Convert leading 0's to blanks? 16DF 2808 DB JRZ,NOBLANK-$-1 ; No, Leave digit alone 16E1 3620 MVI M,' ' ; Yes, Change digit to a blank 16E3 1804 DB JR,NOBLANK-$-1 ; All done for now NOZERO: 16E5 AF XRA A ; Turn off leading 0's flag 16E6 32EB16 STA DE$TO$HL$MODE ; . NOBLANK: 16E9 23 INX H ; Bump digit pointer 16EA C9  (LDIR) 170B 3E0A MVI A,10 ; Test CP/M version 170D CDD219 CALL LB$GETNXT ; Get next jump table 1710 322417 STA BIOS$VERSION ; Save bios version 1713 23 INX H ; See if HL is 0FFFFh 1714 7C MOV A,H ; . 1715 B5 ORA L ; . 1716 C8 RZ ; If so, then old version 1717 2B DCX H ; Fix HL as it has the table addr 1718 11DE19 LXI D,LB$XTBL ; Move extra table to local storage 171B 010F00 LXI B,LB$XLEN ; . (length of extra table)  RET ; and return ... 16EB 00 DE$TO$HL$MODE: DB 0 ; "Convert 0's to blanks" flag DO$CRLF: ; ; [DC.27] ; ; This routine sends a carriage return and a line feed to the terminal, ; and then waits 'SLOW$TERM' ms for a slow terminal to catch up. ; ; Entry: ; none ; 171E EDB0 DW LDIR80 ; . (LDIR) 1720 3EFF MVI A,0FFH ; Set NZ to indicate bios 1722 B7 ORA A ; ... version 2.1+ 1723 C9 RET ; ... and return. BIOS$VERSION: 1724 00 DB 0 ; Current bios version GET$HL$PTR: ; ; [DC.20] ; ; Gets the pointer pointed to by HL and puts it in HL ;  ; Exit: ; CR + LF is sent to the screen. ; ; Modifies: ; none ; 16EC F5 PUSH PSW ; Save AF 16ED 3E0D MVI A,0Dh ; Send carriage return 16EF CD6616 CALL CON$CHR ; . 16F2 3E0A MVI A,0Ah ; and line feed 16F4 CD6616 CALL CON$CHR ; . 16F7 3A0401 LDA SLOW$TERM ; Check slow flag 16FA B7 ORA A ; . 16FB C49519 CNZ WAIT ; wait for the s-l-o-w terminals 16FE F1  ; Entry: ; HL = pointer to put in HL ; ; Exit: ; HL = pointer ; ; Modifies: none ; 1725 F5 PUSH PSW ; Save A register 1726 7E MOV A,M ; Get low byte of pointer 1727 23 INX H ; . 1728 66 MOV H,M ; Get high byte of pointer 1729 6F MOV L,A ; Pointer is now together 172A F1 POP PSW ; Restore A register 172B C9 RET ; POP PSW ; recover original AF 16FF C9 RET ; and return GET$BIOS$VERS: ; ; [E5.24] ; ; Get bios version -- Copies the current BIOS jump tables (starting ; at warm boot) to a local area for ease of utility access. If the ; BIOS is version 2.0 or greater, the secondary jump table is copied ; also. ;  and return GET$STRLEN ; Searches the string pointed to by HL and returns the string length ; to the next carriage return. The length is returned in B. 172C D5 PUSH D ; Save start of string 172D 0600 MVI B,0 ; Clear counter TRY$NEXT$CHR: 172F 1A LDAX D ; Get character 1730 FE0D CPI CR ; Is it CR? 1732 CA3F17 JZ EOS$FOUND ; . 1735 FE24 CPI '$' ; Is it   '$'? 1737 CA3F17 JZ EOS$FOUND ; . 173A 04 INR B ; No -- increment count and 173B 13 INX D ; . point to the next character 173C C32F17 JMP TRY$NEXT$CHR ; . EOS$FOUND: 173F E1 POP H ; CR or '$' found, recall orig ptr 1740 EB XCHG ; DE=orginial, HL=current 1741 C9 RET ; and return GO$TABLE: ; ; [E2.05] ;  character to check ; HL = pointer to list of "OK" characters ; ; Exit: ; A = original character if ok, 0ffh if not in list ; B = position of character in list ; ; Modifies: ; BC ; 175D E5 PUSH H ; Save original "OK" pointer 175E 4F MOV C,A ; Save chr to check against 175F 0600 MVI B,0 ; Clear counter 1761 FE1B CPI E; Jump to a routine based on a table of pointers ; ; Entry: ; A = index into table ; HL = table base address ; ; Exit: ; Routine at (A*2)+HL is executed ; ; Modifies: ; B, HL ; 1742 010200 LXI B,2 ; Compute offset to table of routines 1745 CD5617 CALL INDEX$TABLE ; . 1748 CD2517 CALL GET$HL$PTR ; . 174SC ; If chr is 1763 CA7A17 JZ I$CHR$OK ; . then automatically ok 1766 04 INR B ; . otherwise start counting at 1 I$CHK$NEXT: 1767 7E MOV A,M ; Get chr to check against 1768 B7 ORA A ; End of table? 1769 C27117 JNZ I$NOT$EOT ; No, check chr 176C 3D DCR A ; Decrement to get 0ffh 176D 47 MOV B,A ; Stuff for later move 176E C37A17 JMP I$CHR$OK ; And exit I$NOT$EOT: 1771 B9 CMP C ; Chrs B E9 PCHL ; Jump to proper routine HL$DIV$2: 174C F5 PUSH PSW 174D AF XRA A 174E 7C MOV A,H 174F 1F RAR 1750 67 MOV H,A 1751 7D MOV A,L 1752 1F RAR 1753 6F MOV L,A 1754 F1 POP PSW 1755 C9 RET INDEX$TABLE: ; ; [E1.30] ; ; Computematch? 1772 CA7A17 JZ I$CHR$OK ; . Yes, return 1775 23 INX H ; . No, bump pointer 1776 04 INR B ; . . and bump counter 1777 C36717 JMP I$CHK$NEXT ; . . and check next chr I$CHR$OK: 177A 78 MOV A,B ; Set status based on 177B B7 ORA A ; . position counter 177C 79 MOV A,C ; Get user chr back I$DONE: 177D E1 POP H ; and original "OK" pointer 177E C9 RET ; and return s offset to table given base address, entry length, and entry ; requested. ; ; Entry: ; A = entry # ; BC = table entry length ; HL = base address ; ; Exit: ; HL = address to entry ; ; Modifies: ; A, BC, HL ; 1756 B7 ORA A ; Set up flags for first check I$TBL$ADD JUSTIFY: ; ; [E6.11] ; ; This routine will send a data stream to the console, with each line ; justified based on the SCREEN$WIDTH value. The stream must terminate ; with the CP/M end of string character ($) and may contain imbedded ; CR,LF pairs to separate paragraphs. ; ; NOTE: To insure proper operation, the LF character : 1757 C8 RZ ; If A=0, we're done 1758 09 DAD B ; Otherwise add length to base, 1759 3D DCR A ; . decrement counter, 175A C35717 JMP I$TBL$ADD ; . and check again. IS$IT$OK: ; ; [E1.28] ; ; Check the character in A against the list of "OK" chrs pointed ; to by HL ; ; Entry: ; A =should only follow ; a CR character or another LF character, as the CR character is used to ; flush the current line without justification. ; ; Two entry points are provided: ; JUSTIFY Justify output, flush right ; JUSTIFY$RAGGED Justify output, ragged right ; ; As of E6.11, the flush right routine was not installed, so either ; entry point will provide th e same results. ; ; Entry: ; DE = pointer to line(s) to output ; ; Exit: ; The data is sent to the screen. ; ; Modifies: All registers ; 177F 3E80 MVI A,80H ; Set flush right mode 1781 1802 DB JR,E$JUSTIFY-$-1; Jump to routine entry JUSTIFY$RAGGED: 1783 3E00 MVI A,00H ; Set ragged right mode E$JUST J$NO$B: 17D3 04 INR B ; Increment counter 17D4 23 INX H ; . and input pointer 17D5 13 INX D ; . and output pointer 17D6 3A0301 LDA SCREEN$WIDTH ; Compare counter against screen width 17D9 90 SUB B ; . 17DA F29617 JP J$CHECK$CHR ; And continue checking if not past end ; ; Screen width exceeded, send this line to the screen. ; 17DD 2A1018 LHLD OUTBUF$BLANK ; Get pos of last blank in outpuIFY: 1785 320D18 STA J$MODE ; Save mode byte 1788 3E24 MVI A,'$' ; Mark start of buffer 178A 32AF1A STA OUTBUF-1 ; . 178D EB XCHG ; DE is usually print source J$NEXT$LINE: 178E AF XRA A ; Clear character counter 178F 321218 STA BLANK$LEN ; . 1792 47 MOV B,A ; . 1793 11B01A LXI D,OUTBUF ; Set up buffer pointer J$CHECK$CHR: 1796 7E MOV A,M ; Get character 1797 FE0D CPI CR ; CR? 1799 200Bt buf 17E0 3624 MVI M,'$' ; and plug with eos ('$') 17E2 3A0D18 LDA J$MODE ; Justify right edge only if the 17E5 B7 ORA A ; . right-justify flag is non-zero 17E6 FC0218 CM J$ADD$BLANKS ; . 17E9 CD0318 CALL J$SEND$BUFFER ; Output the line to the screen 17EC CDEC16 CALL DO$CRLF ; and a CR / LF 17EF 2A0E18 LHLD BLANK$POS ; Get pointer to where we left off J$SKIP$BLANKS: 17F2 23 INX H ; Bump pointer past blank(s) 17F3 7E  DB JRNZ,J$NO$R-$-1 ; . 179B CDFB17 CALL J$FLUSH$LINE ; . Flush output line, 179E 3E0D MVI A,CR ; . Output CR, 17A0 CD6616 CALL CON$CHR ; . . 17A3 23 INX H ; . bump ptr & check next 17A4 18E8 DB JR,J$NEXT$LINE-$-1 and 255 J$NO$R: 17A6 FE0A CPI LF ; LF? 17A8 2006 DB JRNZ,J$NO$L-$-1 ; . 17AA CD6616 CALL CON$CHR ; . Output LF, 17AD 23 INX H ; . bump ptr & check next 17AE 18E6 DB JR,J$CHECK$CHR-$-1 aMOV A,M ; . 17F4 FE20 CPI ' ' ; . 17F6 28FA DB JRZ,J$SKIP$BLANKS-$-1 and 255 17F8 C38E17 JMP J$NEXT$LINE ; and check next segment J$FLUSH$LINE: ; Flush line when CR or EOS encountered 17FB 3E24 MVI A,'$' ; Plug current position with EOS ($) 17FD 12 STAX D ; . 17FE CD0318 CALL J$SEND$BUFFER ; Send this line of data 1801 C9 RET ; and return J$ADD$BLANKS: 1802 C9 RET nd 255 J$NO$L: 17B0 FE0C CPI FF ; FF? 17B2 2006 DB JRNZ,J$NO$F-$-1 ; . 17B4 CD5416 CALL CLEAR$SCREEN ; . Clear screen, 17B7 23 INX H ; . bump ptr & check next 17B8 18DC DB JR,J$CHECK$CHR-$-1 and 255 J$NO$F: 17BA FE24 CPI '$' ; End of string? 17BC 2004 DB JRNZ,J$NO$S-$-1 ; . 17BE CDFB17 CALL J$FLUSH$LINE ; . Flush output line, and 17C1 C9 RET ; . return to caller. J$NO$S: 17C2 ; At a later time, this routine will ; justify the right margin by inserting ; extra blanks in the output line. J$SEND$BUFFER: 1803 78 MOV A,B ; If line to output is of zero length, 1804 B7 ORA A ; . then don't output the line. 1805 C8 RZ ; . 1806 11B01A LXI D,OUTBUF ; Get address of output buffer 1809 CD9016 CALL CON$MSG ; and call our print message routine 180C C9 RET ; 12 STAX D ; Not a special chr, save in buffer 17C3 FE20 CPI ' ' ; Blank? 17C5 200C DB JRNZ,J$NO$B-$-1 ; . No, don't save position 17C7 220E18 SHLD BLANK$POS ; Save position for later 17CA EB XCHG ; and save corresponding position 17CB 221018 SHLD OUTBUF$BLANK ; . of the blank we just saved 17CE EB XCHG ; . in the output buffer 17CF 78 MOV A,B ; . 17D0 321218 STA BLANK$LEN ; Save current length also  return 180D 00 J$MODE DB 0 ; Current right justify mode 180E 0000 BLANK$POS DW 0 ; Last blank on this line 1810 0000 OUTBUF$BLANK DW 0 ; Last blank in the output buffer 1812 00 BLANK$LEN DB 0 ; Length of line to the blank ; NOTE: OUTBUF is defined to be after the stack and before the heap. ; end of justify$output data area PROMPT:    ; ; [E6.14] ; ; Prompt the user or the command line for input. ; ; Two entry points are provided: ; PROMPT standard entry, CRLF after chr from user ; PROMPT$NOLF special entry, No CRLF after chr from user ; ; When the command line is used for input, the following characters ; are translated to new values or new functions: back 183C 220601 SHLD CMD$LINE$PTR ; . to the beginning 183F 3E7F MVI A,07FH ; Set count of chrs to 127 1841 320501 STA CMD$LINE$CHRS ; . (the most it could be) 1844 18D9 DB JR,RE$PROMPT-$-1 and 255 P$NO$R: 1846 FE2C CPI ',' ; Change ',' to CR 1848 2002 DB JRNZ,P$NO$C-$-1 ; . 184A 3E0D MVI A,CR ; . P$NO$C: 184C FE2E CPI '.' ; Change '.' to ESC 184E 2002 DB JRNZ,P$NO$D-$-1 ; . 1850 3E1B MVI A,E ; ; Character New character or new function ; -------------- ------------------------------------ ; (space) Ignored ; , (comma) key ; . (period) key ; @ (at-sign) repeat existing command line ; _ (underscore) Prompt and get character from user ; ; Entry: ; DE = pointer to prompt string ; HL = SC ; . P$NO$D: 1852 FE5F CPI '_' ; Underscore = prompt anyway 1854 280E DB JRZ,P$DISP-$-1 ; . 1856 CD8819 CALL TO$UPPER ; Convert the chr to upper case 1859 2A8518 LHLD USER$OKLIST ; Get the user ok chr list 185C CD5D17 CALL IS$IT$OK ; Check the chr against the ok list 185F F0 RP ; If ok, return 1860 AF XRA A ; Otherwise, cancel the cmd line 1861 320501 STA CMD$LINE$CHRS ; . buffer and fall through to p$disppointer to list of valid chars (terminated with 00H) ; ; Exit: ; A = char from the user ; B = position of this character (0, 1, 2, ... n) ; ; Z = char was the escape key ; NZ = char was not the escape key ; ; Modifies: ; PSW, BC ; 1813 3E01 MVI A,01H ; Set CRLF after chr 1815 1802 DB JR,E$PROMPT-$-1 ; Ju P$DISP: 1864 CD7F17 CALL JUSTIFY ; and call justify routine P$TRY$AGAIN: 1867 CD8716 CALL CONIN$NE$XC ; Console input, no echo, except ^C 186A CD8819 CALL TO$UPPER ; Convert the chr to upper case 186D 2A8518 LHLD USER$OKLIST ; Get the user ok chr list 1870 CD5D17 CALL IS$IT$OK ; Check the chr against the ok list 1873 FA6718 JM P$TRY$AGAIN ; Not there, try again 1876 C46616 CNZ CON$CHR ; Display chr we found 1879 F5 PUSHmp to entry point PROMPT$NOLF: 1817 3E00 MVI A,00H ; Set no CRLF after chr E$PROMPT: 1819 328418 STA PROMPT$MODE ; Save prompt mode flag 181C 228518 SHLD USER$OKLIST ; . and user 'ok' chr list RE$PROMPT: 181F 3A0501 LDA CMD$LINE$CHRS ; Are there any characters left from 1822 B7 ORA A ; . the command line? 1823 283F DB JRZ,P$DISP-$-1 ; No, dsp text & get chr from bios 1825 3D DCR A  PSW ; Check mode flag in case we need 187A 3A8418 LDA PROMPT$MODE ; . to send a CR+LF after the 187D CB47 DB BIT,BTST+B0+ZA ; . user's input 187F C4EC16 CNZ DO$CRLF ; . 1882 F1 POP PSW ; . 1883 C9 RET ; and return 1884 00 PROMPT$MODE: DB 0 ; Prompt mode flag 1885 0000 USER$OKLIST: DW 0 ; User 'ok' chr list ; end of PROMPT routine PROMPT$DEC ; Yes, reduce # of chrs by one 1826 320501 STA CMD$LINE$CHRS ; . 1829 2A0601 LHLD CMD$LINE$PTR ; Get command line character 182C 7E MOV A,M ; . 182D 23 INX H ; . 182E 220601 SHLD CMD$LINE$PTR ; . 1831 FE20 CPI ' ' ; Ignore spaces 1833 28EA DB JRZ,RE$PROMPT-$-1 and 255 1835 FE40 CPI '@' ; @ = repeat cmd line 1837 200D DB JRNZ,P$NO$R-$-1 ; . 1839 21311A LXI H,INBUF+2 ; Set command line pointer IMAL: ; ; [E6.11] ; ; Prompt the user for a decimal input of up to 5 digits. The Z flag ; indicates the termination character: Z = ESC key, results may not ; be valid; NZ = RETURN key, results valid. ; ; Entry: ; DE = pointer to prompt string ; ; Exit: ; DE = Value entered by the user, 0-0FFFFH  ÅO AMPRO Hard Disk Format Utility Copyright (C) 1985 AMPRO Computers, Inc. Version 1.5 $ Usage: HFORMAT $ The AMPRO Hard Disk Format utility is used to format hard disk (winchester) drives, on the Adaptec ACB-4000, Data Technology 500 Series (510A, 510B, 520A, 520B), Shugart 1610-4, Xebec 1410 (rom rev "E" or later), Xebec 1410A (rom rev "D" or later) controllers, or the Xebec Owl or Seagate 225N combination drive/controllers. You will be asked for the controller type, controller SCSI address,!: ! , >  { ! : 2 2 : 2 !h n Œ !  Œ  * " : 2 : =2 : _! ~2 : 2 !  Œ !  Œ <  * "m * "s * "o * "q : 2i : _!K ~2k #~2l : 2 !U [ Œ !{ { Œ  Œ F2 >2   ! : 2 : 2 !  Œ !  Œ !  Œ  : 2 !  Œ ! drive unit number, and the drive descriptor information. $CAUTION: ALL DATA WILL BE ERASED ON THE DRIVE YOU SELECT TO FORMAT. $>2!"1uͦA w:%DThis program requires AMPRO bios version . or later. $͠A!Ϳʐx= 2 ""!Ϳx=2 >2 : ʯʯ"!`Ϳx=2 e! r#s2 ! r#s! r#s: ¡! r#s͸ Ϳx=2 m ! Ϳ2x2 !Ϳ !ͿNDWhat is the SCSI address of  Œ  Œ 5!r | :} g:~ o: jjjj+" ))))! #w#r#s!  * |G % =ʮ ~ "j!   "S9> X o g 0ͅ=D_GyMbJ > M> M:7q#œ*D<ͮ>t2#|+ͮ>~#fo $ =O your controller (0-7)? $01234567 Which type of controller are you using: 1 - Adaptec ACB 4000 2 - Shugart 1610-4 3 - Xebec OWL (drive/controller) 4 - Xebec 1410, 1410A 5 - Seagate 225N (drive/controller) 6 - Data Technology 500 Series Choose one (1-6): $123456 Which drive on the controller do you want to format (0-3)? $0123 Please enter the characteristics of the drive you wish to format: $ Number of cylinders: $ Number of heads: $Starting cylinder for RWC: $S~ =G#xy>>2>$2v2Gw~ ͖> M# M# A#$ ͖ ""x2#:1*6$:͞ͅ*#~ ()>$͞xww~#²>>2:*=2~#",> .>_*2n*M:ą>>2ůO!!(L oXGyRwi p#i> Mi>M+ ,6!>{:ą$0123456789  $  !ͿPress the RETURN key to continue ... $ xN#Nwy#tarting cylinder for WPC: $ Landing zone cylinder: $ Adaptec step mode (choose from the following table): 0 - 3ms step 1 - 28us buffered step 2 - 12us buffered step Which step mode (0, 1, or 2)? $012 Data Technology step mode (choose from the following table): 0 - 3ms step 1 - 200us buffered step 2 - 150us buffered step 3 - 100us buffered step 4 - 50us buffered step Which step mode (0, 1, 2, 3, or 4)? $01234 Shugart step mode (choose from the following table): 0 - 3ms~08:00_! )) )#{6a6_>=:=7Rwi p#i> Mi>M+ ,6!>{:ą$0123456You are about to format the following drive with an interleave of (1): $ Press to format, to start over, to quit: $ Formatting . . . $ Setting drive data to 0E5H . . . $ Drive formatted -- no errors. Be sure to use FINDBAD on each of the CP/M letters listed above to find any bad sectors in the drive you just formatted. Example: FINDB step 1 - 1ms step 2 - 200us buffered step 3 - 70us buffered step 4 - 50us buffered step Which step mode (0, 1, 2, 3, or 4)? $012345 Xebec step mode (choose from the following table): 0 - 3ms step 4 - 200us buffered step 5 - 70us buffered step 6 - 30us buffered step 7 - 15us buffered step Which step mode (0, 4, 5, 6, or 7)? $04567 What sector interleave factor (1-9, usually 2)? $123456789: !  7!!!  !g #: w+: }͙AD F:; FINDBAD G: $Drive NOT FORMATTED due to error(s). $ FORMAT ERROR: your controller is not responding. Possible causes: Controller set to wrong SCSI address Controller malfunctioning or not connected SCSI host adapter malfunctioning Cables (SCSI to controller or controller to drive) are bad $ FORMAT ERROR: Error code xx (hex), SCSI command xx (hex). SCSI address bit code xx (hex). (See your hard disk controller manual for details). $ Do another (Y/N)? $NY Cannot format -- you hav  e an unknown or unsupported hard disk controller. $CTCA3 ; get down count value CMP M ; see if count has rolled over JZ CLKEXT ; same count value MOV M,A ; save new count JC CLKEXT ; counter < last count, not rolled LXI H,SECNT ; seconds count INR M ; increment seconds MVI A,60 CMP M DB JRNZ,CLKEXT-$-1 ; exit if no rollover MVI M,0 ; seconds to 0 INX H ; point to min. INR M ; one more min. CMP M 0, 0 HPARM: DB 64,0, 5,31, 1, 16,0, 255,3, 255,0, 0,0, 2,0, 0 IPARM: DB 64,0, 5,31, 1, 16,0, 255,3, 255,0, 0,0, 2,0, 0 JPARM: DB 64,0, 5,31, 1, 16,0, 255,3, 255,0, 0,0, 2,0, 0 KPARM: DB 64,0, 5,31, 1, 16,0, 255,3, 255,0, 0,0, 2,0, 0 LPARM: DB 64,0, 5,31, 1, 16,0, 255,3, 255,0, 0,0, 2,0, 0 MPARM: DB 64,0, 5,31, 1, 16,0, 255,3, 255,0, 0,0, 2,0, 0 NPARM: DB 64,0, 5,31, 1, 16,0, 255,3, 255,0, 0,0, 2,0, 0 OPARM: DB 64,0, 5,31, 1, 16,0, 255,3, 255,0, 0,0, 2,0, 0 PPARM: DB 64,0, 5,31, 1, 16,0, 25 ; 'a' = 60 DB JRNZ,CLKEXT-$-1 ; exit if no rollover MVI M,0 ; min=0 INX H ; point to hours INR M ; one more hour MVI A,24 CMP M DB JRNZ,CLKEXT-$-1 ; exit, same day still MVI M,0 ; hours=0 LHLD DAYCNT INX H ; increment days SHLD DAYCNT DB BIT,BTST+B0+ZH ; test less than >256 DB JRZ,CLKEXT-$-1 ; MVI A,366-256 ; days in calendar(include leap year) CMP L DB JRNZ,CLKEXT-$-1 ; exit no wrap LXI H,0 SHLD DAYCNT ; day 0 LXI H,YRCNT INR M MVI A,100 CMP M ; year wrap ; A = Low byte of value entered by the user, 0-0FFH ; ; Z = ESC key pressed, ignore results ; NZ = RETURN key pressed, results valid ; ; Modifies: ; A, PSW ; 1887 3E01 MVI A,01H ; Set CRLF after entry 1889 1802 DB JR,E$PR$DEC-$-1 ; Jump to entry point PROMPT$DEC$NOLF: 188B 3E00 MVI A,00H ; Set no CRLF after entry E$PR$DEC: 7C00017C912FE20200C220E18EB221018EB78FD :1017D0003212180423133A030190F296172A1018B4 :1017E00036243A0D18B7FC0218CD0318CDEC162A92 :1017F0000E18237EFE2028FAC38E173E2412CD0336 :1018000018C9C978B7C811B01ACD9016C900000020 :101810000000003E0118023E003284182285183A6A :101820000501B7283F3D3205012A06017E23220625 :1018300001FE2028EAFE40200D21311A2206013E39 :101840007F32050118D9FE2C20023E0DFE2E20020B :101850003E1BFE5F280ECD88192A8518CD5D17F036 :10186000AF320501CD7F17CD8716CD88192A85188F :10187000CD5D17FA6718 188D 320A19 STA PROMPT$D$MODE ; Save prompt mode flag 1890 E5 PUSH H ; Save original HL reigster 1891 C5 PUSH B ; . and the BC register, too. 1892 AF XRA A ; Clear the current digit pointer 1893 4F MOV C,A ; Setup count in C register 1894 210419 LXI H,SCRATCH ; Initialize the scratch pointer NEXT$DIGIT: 1897 C5 PUSH B ; Save digit counter 1898 E5 PUSH H ; . and string pointer 1899 21F318 LXI H,DEC$INPUT$OKC46616F53A8418CB47C4CD :10188000EC16F1C90000003E0118023E00320A19B0 :10189000E5C5AF4F210419C5E521F318CD1718E1AF :1018A000C1284CFE0DCADA18FE08CAC3184779FED3 :1018B00005DABD18110019CD9016C3D4180C702389 :1018C000C3D4183E20CD6616AFB9CAD4183E08CD91 :1018D00066162B0D11F218C397183600210419CD86 :1018E00060193EFFB77BF53A0A19B7C4EC16F1C18F :1018F000E1C92430313233343536373839080D00F8 :101900000820082420202020200000111B19CD0EC3 :1019100016113F19214019CD1318C9507265737300 :10192000207468652052455455524E206B657C ; Get current 'ok' chrs 189C CD1718 CALL PROMPT$NOLF ; Prompt for digit 189F E1 POP H ; Get string pointer back 18A0 C1 POP B ; . along with digit counter 18A1 284C DB JRZ,ESCRTN-$-1 ; Return if ESC key hit 18A3 FE0D CPI CR ; Check for return 18A5 CADA18 JZ CONVERT$STRING ; Convert string to decimal, if so 18A8 FE08 CPI BS ; Check for backspace 18AA CAC318 JZ BACKUP$DIGIT ; Back up 1 digit, if we can 18AD 47 MOV920CD :10193000746F20636F6E74696E7565202E2E2E2471 :101940000D00C5AF4F7EFE303812FE3A300ED63055 :1019500047AF81878781878023C3441979B7C1C97D :10196000F5C5110000D5C17EFE303819FE3A30159C :10197000D6305F1600E5210000092929092919EB55 :10198000E123C36519C1F1C9FE7BF29419FE61FA26 :101990009419E65FC9F53EDD3DC29819F13DC29547 :0219A00019C963 :0004EB0011  siz ofs x FPARM: DB 64,0, 5,31, 1, 16,0, 255,3, 255,0, 0,0, 2,0, 0 GPARM: DB 64,0, 5,31, 1, 16,0, 255,3, 255,0, 0,0, 2, B,A ; Save character for a moment 18AE 79 MOV A,C ; Check digit count 18AF FE05 CPI 5 ; . 18B1 DABD18 JC ADD$DIGIT ; 5 digits or less, add to string 18B4 110019 LXI D,BLOT ; More than 5 digits, blot this one 18B7 CD9016 CALL CON$MSG ; . 18BA C3D418 JMP DE$FOR$NEXT ; . ADD$DIGIT: 18BD 0C INR C ; Otherwise bump digit count 18BE 70 MOV M,B ; Save digit 18BF 23 INX H ; Bump digit pointer 18C0 C3D418 JMP DE$FO R$NEXT ; Setup DE for next prompt BACKUP$DIGIT: 18C3 3E20 MVI A,' ' ; Bump forward to clear digit 18C5 CD6616 CALL CON$CHR ; . 18C8 AF XRA A ; Are we at the beginning? 18C9 B9 CMP C ; . 18CA CAD418 JZ DE$FOR$NEXT ; Yes, don't backup 18CD 3E08 MVI A,BS ; Backup to correct position 18CF CD6616 CALL CON$CHR ; . 18D2 2B DCX H ; Backup pointer 1 chr 18D3 0D DCR C ; Push count 1 back, also F 24 NO$MSG: DB '$' 1940 0D00 RTC$OKC: DB CR,0 ; end of RET$TO$CONT routine STR$TO$A: ; ; [E5.26] ; ; Converts the string pointed to by HL to a number in the A reg. ; The conversion will continue until the first non-numeric chr ; found. ; ; NOTE: a test for register overfl DE$FOR$NEXT: 18D4 11F218 LXI D,DEC$INPUT$MSG ; Setup for next prompt 18D7 C39718 JMP NEXT$DIGIT ; . CONVERT$STRING: 18DA 3600 MVI M,0 ; Mark end of string 18DC 210419 LXI H,SCRATCH ; Get beginning of string 18DF CD6019 CALL STR$TO$DE ; Convert string to DE register 18E2 3EFF MVI A,0FFH ; Insure NZ flag 18E4 B7 ORA A ; . 18E5 7B MOV A,E ; Move low byte to A 18E6 F5 PUSH PSW ; Check mode flagow is not made. If HL points ; to a string whose numerical value is greater than 255, inaccurate ; results will occur. ; ; Entry: ; HL = ptr to string ; ; Exit: ; A = value of string in HL ; HL = next character to process ; ; Modifies: ; A, HL ; 1942 C5 PUSH B ; We need the BC  to see if a 18E7 3A0A19 LDA PROMPT$D$MODE ; . CR+LF should be sent after 18EA B7 ORA A ; . the user's input 18EB C4EC16 CNZ DO$CRLF ; . 18EE F1 POP PSW ; . ESCRTN: 18EF C1 POP B ; Get old BC register back 18F0 E1 POP H ; . and original HL, as well. 18F1 C9 RET ; and return with result in HL & A 18F2 24 DEC$INPUT$MSG: DB '$' ; Decimal input message 18F3 3031323334DEC$INPUT$OKC: DB '01234567register 1943 AF XRA A ; Clear totals STA$NEXT$CHR: 1944 4F MOV C,A ; Save results so far . . . 1945 7E MOV A,M ; Get chr 1946 FE30 CPI '0' ; Less than '0'? 1948 3812 DB JRC,NA$DIG-$-1 ; Yes, finished 194A FE3A CPI '9'+1 ; Greater than '9' 194C 300E DB JRNC,NA$DIG-$-1 ; Yes, finished 194E D630 SUI '0' ; No, convert to 0-9 1950 47 MOV B,A ; Save this digit 1951 AF XRA A ; Multiply previous by 189' ; Decimal input 'ok' chrs 18FD 080D00 DB BS,CR,0 ; . 1900 08200824 BLOT: DB BS,' ',BS,'$' ; Blot out digit 1904 2020202020SCRATCH: DB ' ',0 ; Max 5 digits 190A 00 PROMPT$D$MODE: DB 0 ; CRLF flag RET$TO$CONT: ; ; [E2.19] ; ; Prompts and waits for the RETURN key to be pressed. ; ; Entry: ; none 0 1952 81 ADD C ; x1 1953 87 ADD A ; x2 1954 87 ADD A ; x4 1955 81 ADD C ; x5 1956 87 ADD A ; x10 1957 80 ADD B ; Add in new digit 1958 23 INX H ; Bump to next chr 1959 C34419 JMP STA$NEXT$CHR ; Go back for another digit NA$DIG: 195C 79 MOV A,C ; Get totals 195D B7 ORA A ; Set Z/NZ flag 195E C1 POP B ; Get old BC reg back 195F C9 RET ; Return with results in A.  ; ; Exit: ; Display message and wait for a RETURN key. ; ; Modifies: ; all ; 190B 111B19 LXI D,RTC$MSG ; Press RETURN to continue ... 190E CD0E16 CALL CENTER$OUTPUT ; . 1911 113F19 LXI D,NO$MSG ; . 1914 214019 LXI H,RTC$OKC ; . 1917 CD1318 CALL PROMPT ; . [ CR ] 191A C9 RET 191B 5072657373RTC$MSG: DB 'Press the RETURN key to continue ...' 193 STR$TO$DE: ; ; [E5.26] ; ; Converts the string pointed to by HL to a number in the DE reg. ; The conversion will continue until the first non-numeric chr ; found. ; ; NOTE: a test for register overflow is not made. If HL points ; to a string whose numerical value is greater than 65535 (64K),   ; inaccurate results will occur. ; ; Entry: ; HL = ptr to string ; ; Exit: ; DE = value of string in HL ; HL = next character to process ; ; Modifies: ; DE, HL ; ; 1960 F5 PUSH PSW ; We need the A register 1961 C5 PUSH B ; . and the BC register 1962 110000 LXI D,0 ; Clear tot; milliseconds in A ; ; Exit: ; time waited ; ; Modifies: A ; 1995 F5 PUSH PSW 1996 3EDD MVI A,221 1998 3D WAIT$2: DCR A 1999 C29819 JNZ WAIT$2 199C F1 POP PSW 199D 3D DCR A 199E C29519 JNZ WAIT 19A1 C9 RET * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * als STN$NEXT$CHR: 1965 D5 PUSH D ; Save results so far . . . 1966 C1 POP B ; . 1967 7E MOV A,M ; Get chr 1968 FE30 CPI '0' ; Less than '0'? 196A 3819 DB JRC,NO$DIG-$-1 ; Yes, finished 196C FE3A CPI '9'+1 ; Greater than '9' 196E 3015 DB JRNC,NO$DIG-$-1 ; Yes, finished 1970 D630 SUI '0' ; No, convert to 0-9 1972 5F MOV E,A ; Save this digit 1973 1600 MVI D,0 ; . 1975 E5 PUSH H ; Save pt * * Data area (use DS or EQU) * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; Replicated BIOS to make direct calls easier . . . LB$BIOS$TBL: 19A2 LB$WBOOT DS 3 ; Warm boot 19A5 LB$CONST DS 3 ; Console status 19A8 LB$CONIN DS 3 ; Console input 19AB LB$CONOUT DS 3 ; Console output 19AE LB$LISTOUT DS 3 ; r to input string 1976 210000 LXI H,0 ; Multiply previous by 10 1979 09 DAD B ; x1 197A 29 DAD H ; x2 197B 29 DAD H ; x4 197C 09 DAD B ; x5 197D 29 DAD H ; x10 197E 19 DAD D ; Add in new digit 197F EB XCHG ; Save results back to DE 1980 E1 POP H ; Get input string ptr back 1981 23 INX H ; Bump to next chr 1982 C36519 JMP STN$NEXT$CHR ; Go back for another digit NO$DIG: 1985 C1 List output 19B1 LB$PUNCH DS 3 ; Punch output 19B4 LB$READER DS 3 ; Reader input 19B7 LB$HOMDSK DS 3 ; Home disk (move to track 00) 19BA LB$SELDSK DS 3 ; Select disk drive 19BD LB$SETTRK DS 3 ; Select track number 19C0 LB$SETSEC DS 3 ; Select sector number 19C3 LB$SETDMA DS 3 ; Set DMA address 19C6 LB$DSKREAD DS 3 ; Disk read 19C9 LB$DSKWRITE DS 3 ; Disk write 19CC LB$LISTST DS 3 ; List st POP B ; Get old BC reg back 1986 F1 POP PSW ; . and old A reg as well. 1987 C9 RET ; Return with results in DE. TO$UPPER: ; ; [E1.08] ; ; Convert the character in A to upper case. ; ; Entry: ; A = character to convert ; ; Exit: ; A = upper case characteratus 19CF LB$SECTRN DS 3 ; Sector translate routine ; AMPRO-specific BIOS calls 19D2 LB$GETNXT DS 3 ; Get bios ver & next tbl address 19D5 LB$GETEDSK DS 3 ; Get pointer to E-disk storage 19D8 LB$IOINIT DS 3 ; Set new I/O parameters 19DB LB$SCSIDRV DS 3 ; SCSI direct driver 003C = LB$LEN EQU $-LB$BIOS$TBL LB$XTBL: ; 'Extra' table definitions ... 19DE LB$SWAP$DRV DS 3 ; Swap (if alpha) ; ; Modifies: ; A ; 1988 FE7B CPI 'z'+1 ; Convert to upper case 198A F29419 JP UPPER$ALREADY ; . 198D FE61 CPI 'a' ; . 198F FA9419 JM UPPER$ALREADY ; . 1992 E65F ANI 5FH ; . UPPER$ALREADY: 1994 C9 RET ; and return WAIT: ; Wait A ms ; ; Entry:  two logical drives 19E1 LB$HD$INFO DS 3 ; Get HD pointers 19E4 LB$PHYTAB DS 3 ; Set/get phytab access 19E7 LB$GETLOGICAL DS 3 ; Get logical device table entry 19EA LB$RESERVED DS 3 ; Reserved entry 000F = LB$XLEN EQU $-LB$XTBL 19ED DS 64 ; 32-level stack 1A2D STACK: DS 2 ; Old stack pointer 1A2F INBUF: DS 128 ; Command line input buffer 0080 = IBUFL: EQU 128 ; In put buffer length 1AAF OBPLUG: DS 1 ; Start of outbuf ('$') 1AB0 OUTBUF: DS PWIDTH ; Output buffer 0084 = OBUFL: EQU $-OUTBUF; Output buffer length 1B34 HEAPPTR: DS 2 ; Pointer to next area 1B36 HEAPLEN: DS 2 ; Length of next area 1B38 = HEAP: EQU $ ; Start of heap 1B38 END START e: starting RWC cylinder Controller: type/model* * Drive: starting WPC cylinder Drive: logical unit number * Drive: step rate code * Drive: number of cylinders CP/M drive letter * Drive: number of heads Size (Kb) of each partition (*) Only required on non-"SCSI generic" Hard disk controllers NOTE: Your drive's total formatted capacity in Kbytes is: (CYLS-1) * HEADS * SECTORS per TRACK * 0.5 where SECTORS per TRACK depends on your controller and is usually 17 or 18. $!/!/~2#"t DW OTIR80 ; ED B3 = OTIR instruction op code JMP WSCSI1 ; Write more bytes until phase changes ; This code skipped when data is being transferred ... WSCSI2: MOV A,B ; Check 5380 "interrupt" flag ANI 00010000B ; . JZ WSCSI1 ; Wait for DMA request, JMP SCSI$INT ; or process "interrupt" ; Generalized SCSI read routine RSCSI: ; Initiator command reg is already initialized MVI C,NCRDACK ; Source port address OUT NCRSDIR ; Write to this port starts dma recieve 1-* ###: )# %}(`0###Z3ENV!"%"*.":$0 :$881-: T !s!Y: ! x=!B ! 2Mx=2 !-ʻ2\x=22!nʻ2nx=22:8fw͇ʻ!r#s͇ʻ2͇ʻ!r#s8͇ʻ!r#s:_T!0ʻx=2p9!"ʻx=2 !">2Ú: (!Ú!?ʚx2A2Y2K͋(_(SͦÚâ##^#Vs#r~ 6<0%"#: ; Wait for DMA request, keeping an eye on phase. Note: we must do ; a check for DMA request before checking for a phase change, since ; a byte may be queued up waiting to be DACKed prior to the phase ; change. ; RSCSI1: IN NCRBSR MOV B,A ; Keep for phase change checking ANA D ; Mask for DMA request DB JRZ,RSCSI2-$-1 ; This is the heart of the pseudo-DMA transfer. On entry, HL points ; to the data buffer and E should be 0 for 256 byte block transfer, ; or 1 for byte-w+::!B"2\(%6(T!!NT( *":2:=2:_!~22!(< *LLL")"* LLL"K [`8 u :6#~2G:w#: w#:w*:O  "##[s#r#s#r#*"s#r*% [s#r [s#r*"**R+!͞wDo you want to clear the existing hard disk assignments (Y/N)? $YN*** Previous hard disk assignments have been cleared *** $ Options avaiby-byte transfer. NOTE: Use block transfer only if ; you can be sure the controller can buffer 256 bytes of data and ; can transfer at 5.25 us per byte. Extra DACK's after the last REQ ; will do no harm. ; ; INIR register use: H = memory pointer, C = I/O port, B = counter ; MOV B,E ; Set up loop count DW INIR80 ; ED B2 = INIR instruction op code JMP RSCSI1 ; Read more bytes until phase changes ; Be sure and check phase if no DMA ; request, since NCR won't issue any lable: (D) Define the Current Drive (A) Add a partition to the Current Drive (ESC) Exit the program What next (D/A/ESC)? $DA Defining the Current Drive ... ====================================== The Current Drive is the physical hard disk drive you are currently working with. The definition of the drive consists of the SCSI ID and type of the hard disk controller connected to the drive, the logical unit number (LUN) of the drive, and the drive characteristics if you are using a XebecO  Ampro Hard Disk System Initialization Utility Copyright (C) 1985 AMPRO Computers, Inc. Version 1.2 $ Usage: HINIT scsiaddr ctrlr lun [cyl,head,rwc,wpc, steprate] cpmletter partition [,cpmletter partition] ... This program requires AMPRO bios version 3.1 or later. $ The Hard Disk System Initialization utility prepares your Ampro 3.1+ bios to access a hard disk unit. The following information is required to initialize the bios for your hard disk unit: Controller: SCSI address * Driv 1410(A) controller. Hard disk controller SCSI ID: ----------------------------- Each hard disk controller must be set to one of the eight SCSI bus ID's. These ID's range from zero (0) to seven (7). If you have only one hard disk controller in your system, it's ID is usually zero (0). If you have more than one hard disk controller, make sure they are set to different ID's. What is the SCSI ID of the current drive's controller (0-7, ESC to quit)? $01234567 Hard disk controller type: ------------ -------------- Of the following controllers ... 1 - Generic burst-mode SCSI controller (Adaptec ACB4000, Xebec Owl) 2 - Generic byte-mode SCSI controller (Shugart 1610-4) 3 - Xebec 1410 or 1410A 4 - Data Technology 500 Series Which one is the Current Drive connected to (1, 2, 3, or 4)? $1234 Current Drive logical unit number: ---------------------------------- Each disk connected to a hard disk controller has a unique number, called the Logical Unit Number, or LUN. The first LUN on a hard# ~O# ~#1 0x+~1d\ \0f ^_yss{y0{Ì'ͯͯdͯ ͯ}0}o|gھ ñ}o|gy> y0>.> > *. O*. ) OGHNWoHdWor# xo*}ʄ$.Ɉ*. O*. ) OGHNWoHdWor# xo*}ʄ disk controller is zero (0), and the numbers increase at that point to a maximum of seven (7). Most hard disk controllers can support two drives, which means the LUN's for the controller are either zero (0) or one (1). If only one drive is connected, the logical unit number (LUN) is normally zero (0). What is the Current Drive's logical unit number (0-7)? $01234567 For the controller you indicated, the following additional information on the Current Drive is required: Number of cylinders? $ Number of heads? $Starting cylinder for RWC? $Starting cylinder for WPC? $ Xebec 1410(A) step mode (choose from the following table): 0 - 3ms step 4 - 200us buffered step 5 - 70us buffered step 6 - 30us buffered step 7 - 15us buffered step Which step mode (0, 4, 5, 6, or 7)? $04567 Data Technology 500 Series step mode (choose from the following table): 0 - 3ms step 1 - 200us buffered step 2 - 150us buffered step 3 - 100us buffered step 4 - 50us buffered step Whi Z3ENV* R!]~  >?E]/|DIR 1.0 Syntax: DIR dir:afn o Options: A=All, S=System, T=File Type/Name SorX!m~#ʼ ʉTʨSʯA‰>ñy OÉ>@y?OOÉ̈́xyY Ovf!"!q#p22xy:|#+*"͆  ~$rx:<2e:<2+##=e2Pause - e x: > }.xAyDʨ~# * --͆* Files Using͆K ͆K Left ~~#>2ch step mode (0, 1, 2, 3, or 4)? $01234Please define the Current Drive before adding a partition to it. Press the RETURN key to continue. $ Add a CP/M partition on the Current Drive ... ================================================ CP/M letter to use for this partition (F-P, ESC for new Current Drive)? $FGHIJKLMNOP Size of the x: partition (in K bytes)? $ There is not enough space left to install a hard disk partition of the size you indicated. $*** Cannot initialize HDC for the Current Dr=A ~ "#~+"##= *V/F##x_*V^#V#~ѷ"VU>> $og 0=W|}_Gyf{ͨ >2{0w>0]T< 8=w0 :(6 2#> f> f:ĕ*3=*7DMɯ`o&QNfN*B"B*| *7#"7= ~:?c@*7|ʠDM*5# “ڏ xu=x"B`i"/*@s#r#! x¸*/"1*1|g}o."1")*)#")*/}|*)"+*1*+}o|g"+|*1"-*+*-ͭ*/DM*@"%*B"'*%*'Rc yG*%~#~*#*'*%^#V*'"'*%^#V*#*%##"% y?*@DM+) +) Nq#Nq*@DM+) +) N#F^#V`i:?    *<> 2$#|+>~#fo ?$?/V%|g}oɷ =WOz~q=Gzz#gxy>>2 >$22G~ > f# f# T#$  ""x2#:*6$: *#~ (Î>$x͐>>2":(?=2*~#" (@ !1">2, > . >_(͈*]2͇͈*]gf:G>>2 ůO!!(L Gyڽ͐ p#> f>f+ ×6!`>{: $0123456789   $ ?!@Press the RETURN key to continue ...$ ůO~08:00G#Dy~08:00_! )) )#e{a_>=˜=•x͐>>2":(?=2*~#" (@ !1">2, > . >_(͈*]2͇͈*]gf:G>>2 ůO!!(L Gyڽ͐ p#> f>f+ ×6!`>{: $0123456789 c.) ',CR,LF DB 'O - Xebec Owl ' DB '# - all other controllers ',CR,LF,LF DB '$',CR,' ',CR,EOF SIGNON$MSG: DB 'The PARK utility is used to move the heads of a ' DB 'hard disk drive to the landing or shipping zone. ' DB CR,LF,LF DB 'NOTE: This program will NOT return to CP/M when ' DB 'you terminate the parking session with an escape or ' DB 'control-c.' DB CR,LF,LF DB '$' ; ; Initialize the command line input pointer. ; START: IF CMD$LINE$OK ; If we want to allow cmd  EQU 000H ; B Reg ZC EQU 001H ; C Reg ZD EQU 002H ; D Reg ZE EQU 003H ; E Reg ZH EQU 004H ; H Reg ZL EQU 005H ; L Reg ZM EQU 006H ; M Reg ZA EQU 007H ; A Reg ; Jump relative opcode equates (use DB to enter) ; Example: JR AGAIN would be DB JR,AGAIN-$-1 JR EQU 018H ; JR addr JRNZ EQU 020H ; JR NZ,addr JRZ EQU 028H ; JR Z,addr JRNC EQU 030H ; JR NC,addr JRC EQU 038H ; JR C,addr ; IX and IY prefixes (use DB to enter) IX EQU 0DDH ; IX prefix IY EQU 0FDH ; IYline input, LXI H,0080H ; . Save the command line. LXI D,INBUF ; . . LXI B,128 ; . . DW LDIR80 ; . . LXI H,INBUF ; . Set up ptrs and count of chrs MOV A,M ; . . STA CMD$LINE$CHRS ; . Save count of characters, INX H ; . Bump line ptr, SHLD CMD$LINE$PTR ; . . and save ptr to cmd line ENDIF IF NOT CMD$LINE$OK ; If no command line input allowed, MVI A,0 ; . Clear the count of characters, STA CMD$LINE$CHRS ; . . LXI H,0 ; . but set the ptr up anyway. SHLD CMD$L prefix ; Character equates CTRLC EQU 'C'-'@' ; Ctrl-C (ETX) BS EQU 'H'-'@' ; Ctrl-H (Backspace) TAB EQU 'I'-'@' ; Ctrl-I (Tab) LF EQU 'J'-'@' ; Ctrl-J (Line feed) CR EQU 'M'-'@' ; Ctrl-M (Carriage return) NAK EQU 'U'-'@' ; Ctrl-U CAN EQU 'X'-'@' ; Ctrl-X (Cancel) EOF EQU 'Z'-'@' ; Ctrl-Z (CP/M End-of-file) ESC EQU 1BH ; Ctrl-[ (Escape) EOS EQU '$' ; (CP/M End-of-string) DEL EQU 7FH ; (Delete) ; bdos equates BDOS EQU 5 ; bdos entry ; * * * * * * * * ;INE$PTR ; . . ENDIF IF NOT RTN$VIA$WB ; If we're returning without warm boot, LXI H,0000H ; . then get the old stack ptr, DAD SP ; . and SHLD STACK ; . save it for later, ENDIF ; ; This is where you can jump to start the program over. ; TOP$MENU: LXI SP,STACK ; Stuff SP with our stack. CALL GET$BIOS$VERS ; Copy the jmp tbl to a local area ; ; Display the name and signon message ; IF CMD$LINE$OK ; If cmd line input is possible LDA CMD$LINE$CHRS ; Check for any inp ; The code starts here ... ; ; * * * * * * * * ORG 0100H JMP START SCREEN$WIDTH: DB SWIDTH-1 ; 1 less than actual # SLOW$TERM: DB 10 ; Delay (ms) for slow term CMD$LINE$CHRS: DB 0 ; # of cmd line chrs left CMD$LINE$PTR: DW 0 ; Ptr to next cmd line chr NAME$MSG: DB 0DH,'Ampro ' NAME: DB 'PARK' ; <-- Insert name here NAMELN: EQU $-NAME DB ' Utility',CR,LF DB 'Copyright (C) 1985 AMPRO Computers, Inc.',CR,LF DB 'Version ',VERS/10+'0','.',VERS MOD 10+'0' IF INTERNAL ; Display iut and skip ORA A ; . the initial messages if any JNZ CHECK$B$VERS ; . chrs in the cmd line. ENDIF CALL CLEAR$SCREEN ; Clear the screen LXI D,NAME$MSG ; Display the name, version, etc. CALL CENTER$OUTPUT ; . LXI D,SIGNON$MSG ; and the initial message CALL JUSTIFY ; . ; ; Check the version of the bios against the minimum version allowed. ; If the bios is not at least the minimum, display an error message ; and exit to the operating system. ; CHECK$B$VERS: LDA BIOS$VERSION ; nternal revision number? DB 'x',INT$REV/10+'0',INT$REV MOD 10+'0' DB ' [',THIS$YEAR-80+'@' DB THIS$MONTH+'0'+((THIS$MONTH/10)*7) DB '.',THIS$DAY/10+'0',THIS$DAY MOD 10+'0',']' ENDIF DB CR,LF,LF,'$',CR HELP$MSG: DB 'To park a hard disk drive:',CR,LF,LF DB TAB,'PARK scsiaddr logicalunit controller [blocknumber],.' DB CR,LF,LF DB 'Where ''controller'' is one of the following:',CR,LF,LF DB TAB DB 'G - Generic SCSI Controller ',CR,LF DB ' (Adaptec, Seagate 225N, Shugart 1610-4, etGet bios version # CPI MIN$VERSION ; Check against minimum version JNC WHICH$BIOS ; At least minimum version . . . LXI D,BIOS$PLUS ; Not minimum, display error message CALL JUSTIFY ; . JMP LB$WBOOT ; and exit. BIOS$PLUS: DB 'This program requires AMPRO bios version ' VERSION$REQ: DB MIN$VERSION/10,'.',MIN$VERSION MOD 10,' or later.' DB CR,LF,'$' ; ; Perform any initialization particular to each version of the Ampro ; bios, if necessary. ; WHICH$BIOS: LDA BIOS$VERSION ; Get cu rrent bios version CPI 30 ; Is it version 3? DB JRC,CHECK2-$-1 ; No, check for version 2 ; Put version 3 init code here ... CHECK2: CPI 20 ; Is it version 2? DB JRC,AGAIN-$-1 ; No, assume version 1 ; Put version 2 init code here ... AGAIN: ; ; Program main loop . . . ; LXI H,0 ; Set block to zero SHLD SCSI$BLOCK ; . SHLD SCSI$BLOCK+2 ; . LXI D,S$ADDR$MSG ; Get scsi address LXI H,S$ADDR$OKC ; . CALL PROMPT ; . JZ ALL$DONE ; . STA RESULT$ID ; Plug id in messag drive (Old Adaptec letter) DW PARK$GENERIC ; PARK Generic SCSI drive (Old Shugart letter) PARK$AT$BLOCK: LXI H,SCSI$BLOCK+1 ; Move block number into cmd LXI D,HDC$COMMAND+1 ; . LXI B,3 ; . DW LDIR80 ; . MVI A,0BH ; Set seek command JMP PERFORM$CMD ; Do it PARK$GENERIC: MVI A,1BH ; Set park command JMP PERFORM$CMD ; Do it PARK$OWL: MVI A,011H ; Set seek command CALL PERFORM$CMD ; Do it LXI H,BLINK$LED ; Set blink LED command JMP DO$SCSI ; . BLINK$LED: DB 0EDH,0,es STA NO$UNITS$ID ; . MOV A,B ; . DCR A ; . ANI 07H ; Convert binary to SCSI ID INR A ; . MOV B,A ; . XRA A ; . STC ; . NEXT$BIT: RAL ; . DCR B ; . JNZ NEXT$BIT ; . STA SCSI$ADDR ; . LXI D,L$UNIT$MSG ; Get logical unit # LXI H,L$UNIT$OKC ; . CALL PROMPT ; . JZ AGAIN ; . STA RESULT$LUN ; . STA NO$UNITS$UNIT ; . MOV A,B ; . DCR A ; Convert unit # to 0-3 RRC ; Rotate to bits 7,6,5 RRC ; . RRC ; . STA DRV$LUN ; . LXI D,HDC$MSG ; Get c0,0,0,0 ; Blink LED SCSI cmd PERFORM$CMD: LXI H,HDC$COMMAND ; Point to park command MOV M,A ; . (plug cmd) LXI D,HEAP ; Set DE to dummy buffer CALL DO$SCSI ; Execute park command DB JRNZ,NEXT$UNIT-$-1 LXI D,PARK$RESULT ; Display result message CALL CENTER$OUTPUT ; . XRA A ; Indicate that a unit responded STA DRV$RESPONSE ; . NEXT$UNIT: LDA DRV$RESPONSE ; See if any units responded ORA A ; . LXI D,NO$UNITS ; . CNZ CENTER$OUTPUT ; . RET HDC$COMMAND: DB 0,0,0,0,0,ontroller LXI H,HDC$OKC ; . CALL PROMPT ; . JZ AGAIN ; . MOV A,B ; . DCR A ; Check for block number (#) STA CONTROLLER ; . (save controller anyway) JZ GET$BLOCK ; . LXI D,RET$TO$PARK ; Accept on other LXI H,RET$TO$PARK$C ; . controllers CALL PROMPT ; . JMP SKIP$BLOCK ; . GET$BLOCK: LXI D,BLOCK$MSG ; Get block to park on CALL PROMPT$DECIMAL ; . JZ AGAIN ; . LXI H,SCSI$BLOCK ; Save block in buffer area MOV M,B ; . INX H ; . MOV M,C ; . INX H ; . 0,0,0,0,0 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Various messages . . . * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * S$ADDR$MSG: DB CR,LF DB 'What is the SCSI address of your controller ' DB '(0-7)? ','$' S$ADDR$OKC: DB '01234567',0 L$UNIT$MSG: DB CR,LF DB 'What is the logical unit number of the drive ' DB 'you wish to park (0-3)? ','$' L$UNIT$OKC: DB '0123',0 ; Logical unit numbers HDC$MSG: DB CR,LF D MOV M,D ; . INX H ; . MOV M,E ; . SKIP$BLOCK: CALL PARK ; Perform park JMP AGAIN ; Go back for more ... ALL$DONE: ; Don't return to CP/M LXI D,ALL$PARKED ; Give 'all parked message' CALL CENTER$OUTPUT ; . LOONY$TUNES: JMP LOONY$TUNES ; Th-th-th-that's all, folks! * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * General purpose routines . . . * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * DO$SCSI: INX H LDA DRV$B 'Of the following list of controllers:',CR,LF DB TAB,'G - Generic SCSI controller',CR,LF DB TAB,' (Adaptec, Seagate 225N, Shugart 1610-4, etc.)',CR,LF DB TAB,'O - Xebec Owl',CR,LF DB TAB,'# - Any other hard disk controller',CR,LF DB 'Which controller are you using (A,O,S, or #)? ','$' HDC$OKC: DB '#OGAS',0 BLOCK$MSG: DB CR,LF DB 'Park the drive at which block address? ','$' RET$TO$PARK: DB CR,LF DB 'Press the key to park this drive: ','$' RET$TO$PARK$C: DB CR,'0' LUN ORA M MOV M,A DCX H LDA SCSI$ADDR CALL LB$SCSIDRV ORA A RET PARK: MVI A,0FFH ; Set "No response" flag STA DRV$RESPONSE ; . LXI H,HDC$COMMAND ; Clear HDC command bytes LXI D,HDC$COMMAND+1 ; . LXI B,9 ; . MVI M,0 ; . DW LDIR80 ; . LDA CONTROLLER ; Init HDC for this drive LXI H,PARK$EXE ; . JMP GO$TABLE ; . PARK$EXE: DW PARK$AT$BLOCK ; Park at block # DW PARK$OWL ; Xebec Owl DW PARK$GENERIC ; PARK Generic SCSI drive DW PARK$GENERIC ; PARK Generic SCSI SCSI$BLOCK: DW 0,0 UNIT$ID: DB 0 CONTROLLER: DB 0 DRV$RESPONSE: DB 0 PARK$RESULT: DB '>>> SCSI ID ' RESULT$ID: DB 'x, Logical unit ' RESULT$LUN: DB 'x parked. <<<',CR,LF,'$' NO$UNITS: DB '>>> SCSI ID ' NO$UNITS$ID: DB 'x, Logical unit ' NO$UNITS$UNIT: DB 'x did not respond. <<<',CR,LF,'$' ALL$PARKED: DB CR,LF,LF,'>>> You may now turn off ' DB 'your system. <<<',CR,LF,'$' * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Library r outines . . . * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * CENTER$OUTPUT: ; ; [DC.20] ; ; Automatically centers the output line(s) based on the line width ; stored in SCREEN$WIDTH. Each line is delimited with CR+LF. This ; routine will return to the caller when it encounters the string ; terminator, '$'. Any additional LF characters after a CR+LF pair ; will be passed through. ; ; Entry: ; DE = Pointer to output string(s), terminated with CR+LF. ; ; Exit: ; CALL BDOS POP H POP D POP B POP PSW RET CON$CHR$AC: ; ; [DC.20] ; ; This routine sends the character in the C register to the console ; the number of times in the A register. ; ; Entry: ; A = Number of times to send character ; C = Character to send ; ; Exit: ; Same ; ; Modifies: ; None ; PUSH PSW ; Save all registers PUSH B ; . PUSH D ; . PUSH H ; . MOV B,A ; Move data to accomodate CP/M MOV A,C ; . NEXT$CHR$OUT: CALL CON$CHR ; Send 1 chr DCR B ; D The output string(s) are sent to the screen ; ; Modifies: DE ; PUSH PSW ; Save registers PUSH B ; . PUSH H ; . CENTER$NEXT$LN: CALL GET$STRLEN ; Get length to next CR or '$' in B MOV A,B ; Check for zero length ORA A ; . JZ NEXT$DELIM ; If so, output the CR, LF, etc. LDA SCREEN$WIDTH ; Compute offset needed to center line STC ; . SBB B ; . (if there are too many chrs, just JC NO$BLANKS ; . print the line as is . . . ) ANI 0FEh ; Clear least significant bit RRC ; ecrement counter JNZ NEXT$CHR$OUT ; Done? POP H ; Restore all registers POP D ; . POP B ; . POP PSW ; . RET ; and return CONIN$NE$XC: ; ; [E1.28] ; ; Console input, no echo, exit on ctrl-c ; ; Entry: ; none ; ; Exit: ; A = character from console, except for ctrl-c, which causes ; an immediate jump to ALL$DONE ; ; Modifies: ; A ; CALL LB$CONIN CPI CTRLC JZ ALL$DONE RET CON$MSG: ; ; [DC.20] ; ; Console message ; ; Entry: ; DE = pointer to messag. and rotate to divide by two MVI C,' ' ; Output enough blanks to center line CNZ CON$CHR$AC ; . (only if count is non-zero) NO$BLANKS: MOV A,M ; Save CR for later MVI M,'$' ; Plug position with '$' for cp/m CALL CON$MSG ; . print string function MOV M,A ; Restore saved CR NEXT$DELIM: MOV A,M ; Get character CPI CR ; Print it if CR JZ OUTPUT$DELIM ; . CPI LF ; Print it if LF JZ OUTPUT$DELIM ; . CPI EOS ; Stop processing if EOS ('$') JZ CENTER$DONE ; . XCHG ; Put ne string, terminated with '$' ; ; Exit: ; message printed on console ; ; Modifies: A, BC ; PUSH PSW ; Save registers PUSH B ; . PUSH D ; . PUSH H ; . MVI C,9 ; BDOS print string command CALL BDOS ; . POP H ; Restore registers POP D ; . POP B ; . POP PSW ; . RET ; and return DISPLAY$FDEV: ; ; [E2.15] ; ; LXI D,D$FDEV$HDR ; Print header CALL CENTER$OUTPUT ; . LXI H,ACTIVE$FDEV ; Get pointer to active floppies LXI B,0004H ; Set starting and maximum # ew pointer in DE JMP CENTER$NEXT$LN ; Go & do the next line OUTPUT$DELIM: CALL CON$CHR ; Output delimiter CPI LF ; Wait 10ms if we have a line feed CZ WAIT ; . INX H ; Point to next chr JMP NEXT$DELIM ; and check that one, also CENTER$DONE: POP H ; Restore registers POP B ; . POP PSW ; . RET ; and return CLEAR$SCREEN: ; ; [E1.28] ; ; This routine clears the screen by calling DO$CRLF 26 times. ; ; Entry: ; None ; ; Exit: ; The screen is cleared ; ; Modifies: ; D$NEXT$FDEV: MOV A,M ; Get unit # ORA A ; If zero, skip to next JZ D$BUMP$PTR ; . PUSH H ; Copy output line to output buffer PUSH B ; . LXI H,D$FDEV$LIN ; . LXI D,OUTBUF ; . LXI B,D$FDEV$HLEN ; . DW LDIR80 ; . POP B ; . POP H ; . PUSH PSW ; update 'current' drive letter ANI 07FH ; . (mask out 'E-disk' bit) STA OUTBUF+D$CURRENT; . POP PSW ; . ANI 080H ; get 'E-disk' bit back JNZ D$EDISK$OK ; 'E-disk' present, leave E: alone PUSH H ; . PUSH B ; . LX None ; PUSH PSW ; Save just in case MVI A,26 ; 26 CRLF's C$NEXT$LINE: CALL DO$CRLF ; Next line DCR A ; Done? JNZ C$NEXT$LINE ; Nope. POP PSW ; Restore original AF RET ; and return CON$CHR: ; ; [DC.20] ; ; This routine sends the character in the "A" register to the console ; through the BDOS conout call. ; ; Entry: ; A = character to send ; ; Exit: ; character is sent to the console ; ; Modifies: ; None ; PUSH PSW PUSH B PUSH D PUSH H MVI C,2 MOV E,A I H,D$EBLANK ; . LXI D,OUTBUF+D$EDISK; . LXI B,4 ; . DW LDIR80 ; . POP B ; . POP H ; . D$EDISK$OK: PUSH B ; PUSH H ; MOV A,B ; update floppy device number LXI H,FNAMES ; . LXI B,FNAMES$LEN ; . CALL INDEX$TABLE ; . LXI D,OUTBUF+D$FNAME; . LXI B,FNAMES$LEN ; . DW LDIR80 ; . POP H ; . POP B ; . LXI D,OUTBUF ; and output the line CALL CENTER$OUTPUT ; . D$BUMP$PTR: INX H ; Bump pointer to next device, INR B ; increment letter count, MOV A,B ; Compare t o maximum, CMP C ; . JNZ D$NEXT$FDEV ; Do another if we're not done. RET D$FDEV$HDR: DB '- FLOPPY DISK ASSIGNMENTS -',CR,LF DB 'CP/M drive ' DB 'Floppy disk',CR,LF DB '------------------------',CR,LF,'$' D$FDEV$LIN: DB ' ' D$CURRENT: EQU $-D$FDEV$LIN DB 'x ' D$EDISK: EQU $-D$FDEV$LIN DB '(E)' D$EBLANK: DB ' ' D$FNAME: EQU $-D$FDEV$LIN DB ' ' DB CR,LF,'$' D$FDEV$HLEN EQU $-D$FDEV$LIN ; Line length FNAMES: DB 'First ' DB 'Second' DB 'Third  device INX H ; . INX H ; . INX H ; . INX H ; . MOV B,M ; . LHLD CPM$PTR ; Get ptr to CP/M letter area MOV M,B ; Save CP/M drive letter INX H ; Bump pointer INX H ; . SHLD CPM$PTR ; Save CP/M letter area pointer back D$NEXT$UNIT: LDA TOTAL$ACTIVE ; Get count of active units MOV B,A ; Save for a moment LDA LOGICAL$UNIT ; Get unit we're working on INR A ; Bump to next CMP B ; Are we done? JNZ D$GET$UNIT ; No -- go do another CALL D$SEND$LINE ; Send this line' DB 'Fourth' FNAMES$LEN: EQU 6 ; end of DISPLAY$FDEV DISPLAY$SDEV: ; ; [E2.15] ; ; Display the hard disk data in the active device table. ; ; Entry ; Active devices in the ACTIVE$SDEV area ; ; Exit ; Devices are displayed on the console ; ; Modifies ; All ; LDA TOTAL$ACTIVE ; Check how many devices ORA A ; . RZ ; Return if no devices active LXI D,FD$HEADER ; Display table header CALL CENTER$OUTPUT ; . LXI D,LAST$SCSI ; Init local data LXI B,04FFH ; . (fill la out, too. CALL DO$CRLF ; Send out an extra CR+LF. RET ; all done D$SEND$LINE: PUSH PSW ; Save A & flags and PUSH D ; . D just in case LXI D,OUTBUF ; Send line to console CALL CENTER$OUTPUT ; . D$SEND$DONE: POP D ; POP PSW RET LOGICAL$UNIT: DB 0 ; Current logical unit LAST$SCSI: DB 0 ; Last hard disk scsi address LAST$CTRL: DB 0 ; Last hard disk controller LAST$DTYPE: DB 0 ; Last hard disk drive type LAST$DRIVE: DB 0 ; Last hard disk drive CPM$PTR: DW 0 ; Pointer to nest info with 0FFh's) CALL FILL$BLOCK ; . XRA A ; Current logical D$GET$UNIT: STA LOGICAL$UNIT ; save current unit # CALL INDEX$ACTIVE ; HL = address of active table entry LXI D,LAST$SCSI ; See if same device MVI B,4 ; Compare for 4 bytes CALL STR$COMP ; . JZ D$ADD$LETTER ; Same device -- add CP/M letter LDAX D ; Not same device, check to see ORA A ; . if last device was 'FF'. If so, JM D$DONT$DISP ; . don't display the line. CALL D$SEND$LINE ; Send line to console xt CP/M letter pos CT$NAME: DB 'Xebec ' DB 'Adaptec ' ; DB 'Data Technology' ; Supported later ; DB 'Western Digital' ; Supported later DB 'UNKNOWN ' CT$UN: DB 'UNKNOWN ' CT$NLEN: EQU $-CT$UN FD$HEADER: DB '- HARD DISK ASSIGNMENTS -',CR,LF DB 'CP/M drive(s) Controller ' DB 'Addr Unit #',CR,LF DB '-------------------------------------' DB '-------------',CR,LF,'$' DRIVE$INFO: EQU $ DRIVE$LETTERS: EQU $-DRIVE$INFO DB ' D$DONT$DISP: LXI B,4 ; Since DE & HL still point to last & DW LDIR80 ; . current, move current to last. PUSH H ; save ptr LXI H,DRIVE$INFO ; Copy template to output buffer LXI D,OUTBUF ; . LXI B,DRIVE$LEN ; . DW LDIR80 ; . LXI H,OUTBUF+DRIVE$LETTERS ; Setup CP/M letter ptr SHLD CPM$PTR ; . POP H ; Restore ptr to current PUSH H ; . and save it back MOV A,M ; Plug output buffer w/device info CALL SCSI$TO$BIN ; SCSI address ADI '0' ; . (convert to ascii 0-7) STA  ' DRIVE$CTRL: EQU $-DRIVE$INFO DB ' ' DRIVE$ADDRESS: EQU $-DRIVE$INFO DB '0 ' DRIVE$UNIT: EQU $-DRIVE$INFO DB '0' DB CR,LF,'$' DRIVE$LEN EQU $-DRIVE$INFO ; end of DISP$SDEV DO$CRLF: ; ; [DC.27] ; ; This routine sends a carriage return and a line feed to the terminal, ; and then waits 'SLOW$TERM' ms for a slow terminal to catch up. ; ; Entry: ; none ; ; Exit: ; CR + LF is sent to the screen. ; ; Modifies: ; none ; PUSH PSW ; Save AF OUTBUF+DRIVE$ADDRESS ; . INX H ; . MOV A,M ; Controller type PUSH H ; . LXI H,CT$NAME ; . LXI B,CT$NLEN ; . CALL INDEX$TABLE ; . LXI D,OUTBUF+DRIVE$CTRL ; . DW LDIR80 ; . POP H ; . INX H ; . INX H MOV A,M ; Logical unit # RLC ; . (move bits 7-5 to 2-0) RLC ; . RLC ; . ANI 07H ; . (mask out other bits) ADI '0' ; . (convert to ascii 0-7) STA OUTBUF+DRIVE$UNIT ; . POP H ; Restore ptr so we agree D$ADD$LETTER: INX H ; Get CP/M letter for this MVI A,0Dh ; Send carriage return CALL CON$CHR ; . MVI A,0Ah ; and line feed CALL CON$CHR ; . LDA SLOW$TERM ; Check slow flag ORA A ; . CNZ WAIT ; wait for the s-l-o-w terminals POP PSW ; recover original AF RET ; and return FILL$BLOCK: ; ; [E1.29] ; ; Fills the buffer pointed to by DE with the character in C for ; a length of B bytes (max 256). ; ; Entry: ; B = Length to fill ; C = Character to fill with ; DE = Start of buffer ; ; Exit: ; Buffer filled ; ; Mod ifies: ; Only buffer area affected ; PUSH B ; Save registers PUSH D ; . XCHG ; Set up M register use F$NEXT: MOV M,C ; Stuff a char INX H ; Bump pointer DCR B ; Bounce counter JNZ F$NEXT ; Do it again if not done XCHG ; We are done. restore old HL POP D ; Restore other registers POP B ; . RET ; and return GET$ACTIVE$DEV: ; ; [E2.15] ; ; Get the active devices. Store the floppy and E-disk descriptions ; in the ACTIVE$FDEV table, and store the SCSI descriptionA ; Save new disk letter JMP G$NEXT$DEV ; Get next device info G$EDISK: XCHG ; Get pointer to drive entry back CALL G$F$DRIVE ; Convert floppy drive MOV A,M ; Set high bit for E disk ORI 80h ; . MOV M,A ; . JMP G$NEXT$DEV ; Get next device info G$HARD: XCHG ; Get pointer to drive entry back INX H ; (+1) Controller, Drive, Partition MOV A,M ; Get controller (0-3) RRC ; . RRC ; . ANI 03H ; . STA CTRL$TYPE ; . MOV A,M ; Get drive type (0-3) ANI 03H ; . Ss in the ; ACTIVE$SDEV table. ; ; Entry: ; none ; ; Exit: ; The active device descriptions will be in tables. ; ; ACTIVE$FDEV (4 entries, 1 byte each) format: ; ; +0: Current CP/M letter and "E" disk status. ; (Bit 7 set indicates this device is the "E" disk) ; ; ACTIVE$SDEV (11 entries, 8 bytes each) format: ; ; +0: SCSI Address ; +1: Controller type (0-3) ; +2: Drive type (0-3) ; +3: Drive unit (0-7) -- shifted for use with SCSI commands ; +4: Logical partition (0-7) ; +5: CurrentTA DRV$TYPE ; . MOV A,M ; Get partition ANI 0F0H ; . STA PARTITION ; . INX H ; (+2) Unit # MOV A,M ; . ANI 0E0H ; . STA DRV$LUN ; . INX H ; (+3) SCSI address MOV A,M ; . STA SCSI$ADDR ; . POP PSW ; PUSH PSW ; Get CP/M letter ADI 'A' ; . STA CPM$LETTER ; . LHLD NEXT$POS ; Get next buffer position LXI D,SCSI$ADDR ; . and current scratch area XCHG ; Now DE=buffer, HL=scratch LXI B,8 ; Save data DW LDIR80 ; . LXI H,8 ; Update buffer pointer DAD D  CP/M letter ; +6: spare ; +7: spare ; ; Calls: ; LB$GET$LDTE Get logical drive table entry address ; ; Modifies: All ; LXI D,ACTIVE$SDEV ; Clear the table LXI B,ACTIVE$TLEN SHL 8 ; CALL FILL$BLOCK XCHG ; SHLD NEXT$POS ; Save pointer for later XRA A ; Clear count of active SCSI devices STA TOTAL$ACTIVE ; . G$GET$INFO: PUSH PSW ; Save current logical unit # CALL LB$GETLOGICAL ; Get logical drive table entry addr MOV A,M ; If zero, non-active device ORA A ; . JZ G$NEXT$D ; . SHLD NEXT$POS ; . LXI H,TOTAL$ACTIVE ; Bump count of SCSI devices INR M ; . G$NEXT$DEV: POP PSW ; Get logical back INR A ; Bump to next logical CPI 16 ; Do maximum of 16 logicals JNZ G$GET$INFO ; Not done -- go get more RET DS 16-($ MOD 16) ACTIVE$SDEV: DS 12*8 ; SCSI device info ACTIVE$FDEV: DS 4 ; Floppy CP/M letters ACTIVE$TLEN: EQU $-ACTIVE$SDEV ; Active table length TOTAL$ACTIVE: DB 0 ; # of active SCSI devices NEXT$POS: DW 0 ; Next SCSI buffer position SCSI$AEV ; . CPI 8 ; Only driver codes 0-7 supported JP G$NEXT$DEV ; . LXI D,OUTBUF ; Clear scratch area LXI B,0800H ; Fill with 00h for length of 8 bytes CALL FILL$BLOCK ; . XCHG ; Save pointer to drive entry LXI H,G$EXE$TBL ; JMP GO$TABLE ; Jump to proper routine G$EXE$TBL: DW G$NEXT$DEV ; Driver code = 00 DW G$FLOPPY ; Driver code = 01 DW G$EDISK ; Driver code = 02 DW G$HARD ; Driver code = 03 DW G$NEXT$DEV ; Driver code = 04 DW G$NEXT$DEV ; Driver code = 05 DW G$NEXTDDR: DB 0 ; SCSI Address (0-7) CTRL$TYPE: DB 0 ; Controller type (0-3) DRV$TYPE: DB 0 ; Drive type (0-3) DRV$LUN: DB 0 ; Drive logical unit # (0-7) PARTITION: DB 0 ; Drive partition (0-7) CPM$LETTER: DB 0 ; CP/M letter (0-15) UNIT: DB 0 ; Unit number (1-8) SPARE: DB 0 ; Spare ; end of GET$ACTIVE$DEV routine GET$BIOS$VERS: ; ; [E5.24] ; ; Get bios version -- Copies the current BIOS jump tables (starting ; at warm boot) to a local area for ease of utility access. If the ; BIOS is vers$DEV ; Driver code = 06 DW G$NEXT$DEV ; Driver code = 07 G$F$DRIVE: ; Convert floppy drive to ptr INX H ; Get byte MOV A,M ; Floppy drive byte ANI 03h ; Isolate drive bits LXI H,ACTIVE$FDEV ; Compute table addr MOV C,A ; . MVI B,0 ; . DAD B ; . RET ; and return G$FLOPPY: XCHG ; Get pointer to drive entry back CALL G$F$DRIVE ; Convert floppy drive POP PSW ; Get logical unit PUSH PSW ; . ADI 'A' ; Convert 0-15 to A-P ORA M ; Or in E-disk, if present MOV M,ion 2.0 or greater, the secondary jump table is copied ; also. ; ; Entry: ; none ; ; Exit: ; Z = bios 1.0 - 1.4 (floppy only bios) ; NZ = bios 2.0 or greater (floppy & fixed disk bios) ; ; Modifies: All registers ; LHLD 1 ; Get start of bios jump table LXI D,LB$BIOS$TBL ; Move bios to local storage LXI B,LB$LEN ; . (length of bios area) DW LDIR80 ; . (LDIR) MVI A,10 ; Test CP/M version CALL LB$GETNXT ; Get next jump table STA BIOS$VERSION ; Save bios version INX H ; See if  HL is 0FFFFh MOV A,H ; . ORA L ; . RZ ; If so, then old version DCX H ; Fix HL as it has the table addr LXI D,LB$XTBL ; Move extra table to local storage LXI B,LB$XLEN ; . (length of extra table) DW LDIR80 ; . (LDIR) MVI A,0FFH ; Set NZ to indicate bios ORA A ; ... version 2.1+ RET ; ... and return. BIOS$VERSION: DB 0 ; Current bios version GET$HL$PTR: ; ; [DC.20] ; ; Gets the pointer pointed to by HL and puts it in HL ; ; Entry: ; HL = pointer to put in HL  by HL ; ; Entry: ; A = character to check ; HL = pointer to list of "OK" characters ; ; Exit: ; A = original character if ok, 0ffh if not in list ; B = position of character in list ; ; Modifies: ; BC ; PUSH H ; Save original "OK" pointer MOV C,A ; Save chr to check against MVI B,0 ; Clear counter CPI ESC ; If chr is JZ I$CHR$OK ; . then automatically ok INR B ; . otherwise start counting at 1 I$CHK$NEXT: MOV A,M ; Get chr to check against ORA A ; End of table ; ; Exit: ; HL = pointer ; ; Modifies: none ; PUSH PSW ; Save A register MOV A,M ; Get low byte of pointer INX H ; . MOV H,M ; Get high byte of pointer MOV L,A ; Pointer is now together POP PSW ; Restore A register RET ; and return GET$STRLEN ; Searches the string pointed to by HL and returns the string length ; to the next carriage return. The length is returned in B. PUSH D ; Save start of string MVI B,0 ; Clear counter TRY$NEXT$CHR: LDAX D ; Get character C? JNZ I$NOT$EOT ; No, check chr DCR A ; Decrement to get 0ffh MOV B,A ; Stuff for later move JMP I$CHR$OK ; And exit I$NOT$EOT: CMP C ; Chrs match? JZ I$CHR$OK ; . Yes, return INX H ; . No, bump pointer INR B ; . . and bump counter JMP I$CHK$NEXT ; . . and check next chr I$CHR$OK: MOV A,B ; Set status based on ORA A ; . position counter MOV A,C ; Get user chr back I$DONE: POP H ; and original "OK" pointer RET ; and return JUSTIFY: ; ; [E1.30] ; ; This routPI CR ; Is it CR? JZ EOS$FOUND ; . CPI '$' ; Is it '$'? JZ EOS$FOUND ; . INR B ; No -- increment count and INX D ; . point to the next character JMP TRY$NEXT$CHR ; . EOS$FOUND: POP H ; CR or '$' found, recall orig ptr XCHG ; DE=orginial, HL=current RET ; and return GO$TABLE: ; ; [E2.05] ; ; Jump to a routine based on a table of pointers ; ; Entry: ; A = index into table ; HL = table base address ; ; Exit: ; Routine at (A*2)+HL is executed ; ; Modifies: ; B, Hine will send a data stream to the console, with each line ; justified based on the SCREEN$WIDTH value. The stream must terminate ; with the CP/M end of string character ($) and may contain imbedded ; CR,LF pairs to separate paragraphs. ; ; NOTE: To insure proper operation, the LF character should only follow ; a CR character or another LF character, as the CR character is used to ; flush the current line without justification. ; ; Two entry points are provided: ; JUSTIFY Justify output, flush L ; LXI B,2 ; Compute offset to table of routines CALL INDEX$TABLE ; . CALL GET$HL$PTR ; . PCHL ; Jump to proper routine INDEX$ACTIVE: ; ; [E2.10] ; ; Compute index into active table ; ; Entry: ; A = Table entry number (00h-0fh) ; ; Exit: ; HL = Address of table entry ; ; Modifies: ; PSW, DE, HL ; LXI B,8 ; Length of active device entry LXI H,ACTIVE$SDEV ; Table base address JMP INDEX$TABLE ; Return through INDEX$TABLE INDEX$TABLE: ; ; [E1.30] ; ; Computes offright ; JUSTIFY$RAGGED Justify output, ragged right ; ; As of E1.30, the flush right routine was not installed, so either ; entry point will provide the same results. ; ; Entry: ; DE = pointer to line(s) to output ; ; Exit: ; The data is sent to the screen. ; ; Modifies: All registers ; MVI A,80H ; Set flush right mode JMP E$JUSTIFY ; Jump to routine entry JUSTIFY$RAGGED: MVI A,00H ; Set ragged right mode E$JUSTIFY: STA J$MODE ; Save mode byte MVI A,'$' ; Mark start of buffer set to table given base address, entry length, and entry ; requested. ; ; Entry: ; A = entry # ; BC = table entry length ; HL = base address ; ; Exit: ; HL = address to entry ; ; Modifies: ; A, BC, HL ; ORA A ; Set up flags for first check I$TBL$ADD: RZ ; If A=0, we're done DAD B ; Otherwise add length to base, DCR A ; . decrement counter, JMP I$TBL$ADD ; . and check again. IS$IT$OK: ; ; [E1.28] ; ; Check the character in A against the list of "OK" chrs pointed ; toSTA OUTBUF-1 ; . XCHG ; DE is usually print source J$NEXT$LINE: XRA A ; Clear character counter STA BLANK$LEN ; . MOV B,A ; . LXI D,OUTBUF ; Set up buffer pointer J$CHECK$CHR: MOV A,M ; Get character STAX D ; Save in output buffer CPI CR ; CR? CZ J$FLUSH$LINE ; . Yes, flush output line, CZ J$LITERAL ; . . output CR & bump ptr JZ J$NEXT$LINE ; . . and do another. CPI LF ; LF? CZ J$LITERAL ; . Yes, output LF & bump ptr JZ J$CHECK$CHR ; . . and check next chr. CP I '$' ; End of string? CZ J$FLUSH$LINE ; . Yes, flush output line, RZ ; . . and return to caller CPI ' ' ; Blank? JNZ J$NOT$A$BLANK ; . No, don't save position SHLD BLANK$POS ; Save position for later XCHG ; and save corresponding position SHLD OUTBUF$BLANK ; . of the blank we just saved XCHG ; . in the output buffer MOV A,B ; . STA BLANK$LEN ; Save current length also J$NOT$A$BLANK: INR B ; Increment counter INX H ; . and pointer INX D ; . and output pointer s used for input, the following characters ; are translated to new values or new functions: ; ; Character New character or new function ; -------------- ------------------------------------ ; , (comma) key ; . (period) key ; @ (at-sign) repeat existing command line ; _ (underscore) Prompt and get character from user ; ; Entry: ; DE = pointer to prompt string ; HL = pointer to list of valid chars (terminated with 00H) ; ; Exit: ; A = char from the user ; B = position of this LDA SCREEN$WIDTH ; Compare counter against screen width SUB B ; . JP J$CHECK$CHR ; And continue checking if not past end ; ; Screen width exceeded, send this line to the screen. ; LHLD OUTBUF$BLANK ; Get pos of last blank in output buf MVI M,'$' ; and plug with eos ('$') LDA J$MODE ; Justify right edge only if the CM J$ADD$BLANKS ; . right-justify flag is non-zero CALL J$SEND$BUFFER ; Output the line to the screen CALL DO$CRLF ; and a CR / LF LHLD BLANK$POS ; Get pointer to where  character (0, 1, 2, ... n) ; ; Z = char was the escape key ; NZ = char was not the escape key ; ; Modifies: ; A, BC ; MVI A,01H ; Set CRLF after chr JMP E$PROMPT ; Jump to entry point PROMPT$NOLF: MVI A,00H ; Set no CRLF after chr E$PROMPT: STA PROMPT$MODE ; Save prompt mode flag RE$PROMPT: LDA CMD$LINE$CHRS ; Are there any characters left from ORA A ; . the command line? JZ P$DISP ; No -- display & get chr from bios PUSH H ; Yes, save oklist pointer LHLD CMD$LINE$PTR ; awe left off J$SKIP$BLANKS: INX H ; Bump pointer past blank(s) MOV A,M ; . CPI ' ' ; . JZ J$SKIP$BLANKS ; . JMP J$NEXT$LINE ; and check next segment J$FLUSH$LINE: ; Flush line when CR or EOS encountered PUSH PSW ; Save chr & zero flag MVI A,'$' ; Plug current position with EOS ($) STAX D ; . CALL J$SEND$BUFFER ; Send this line of data POP PSW ; Restore chr & zero flag RET ; and return J$LITERAL: ; Send the chr in A PUSH PSW ; Save zero flag CALL CON$CHR ; Consond get chr from command line DCR A ; . Reduce count of chrs by one STA CMD$LINE$CHRS ; . . MOV A,M ; . Get command line character INX H ; . Increment pointer SHLD CMD$LINE$PTR ; . . POP H ; . Restore oklist pointer CPI ' ' ; Ignore blanks JZ RE$PROMPT ; . CPI '@' ; Repeat existing cmd line? JNZ P$NOT$REPEAT ; . (check other chrs if not) PUSH H ; . Save oklist pointer LXI H,INBUF+2 ; . Set command line pointer back SHLD CMD$LINE$PTR ; . . to the beginning POP H le chr out through CP/M INX H ; Bump chr pointer POP PSW ; Restore zero flag RET J$ADD$BLANKS: RET ; At a later time, this routine will justify ; the right margin by inserting extra blanks ; in the output line. J$SEND$BUFFER: MOV A,B ; If line to output is of zero length, ORA A ; . then don't output the line. RZ ; . LXI D,OUTBUF ; Get address of output buffer CALL CON$MSG ; and call our print message routine RET ; return J$MODE DB 0 ; Current right justify; . Restore oklist pointer MVI A,07FH ; . Set the count of chars to 127 STA CMD$LINE$CHRS ; . . (the most it could be) JMP RE$PROMPT ; . and get the next character P$NOT$REPEAT: CPI ',' ; Change ',' to CR JNZ P$NOT$COMMA ; . MVI A,CR ; . P$NOT$COMMA: CPI '.' ; Change '.' to ESC JNZ P$NOT$DOT ; . MVI A,ESC ; . P$NOT$DOT: CPI '_' ; Underline means prompt & get chr JZ P$DISP ; . from bios anyway (user input) CALL TO$UPPER ; Convert the chr to upper case CALL IS$IT$OK ;  mode BLANK$POS DW 0 ; Last blank on this line OUTBUF$BLANK DW 0 ; Last blank in the output buffer BLANK$LEN DB 0 ; Length of line to the blank ; NOTE: OUTBUF is defined to be after the stack and before the heap. ; end of justify$output data area PROMPT: ; ; [E2.19] ; ; Prompt the user or the command line for input. ; ; Two entry points are provided: ; PROMPT standard entry, CRLF after chr from user ; PROMPT$NOLF special entry, No CRLF after chr from user ; ; When the command line iCheck the chr against the ok list RP ; If ok, return XRA A ; Otherwise, cancel the cmd line STA CMD$LINE$CHRS ; . buffer and fall through to p$disp P$DISP: PUSH H ; Save pointer to ok-chrs CALL JUSTIFY ; and call justify routine POP H ; . P$TRY$AGAIN: CALL CONIN$NE$XC ; Console input, no echo, except ^C CALL TO$UPPER ; Convert the chr to upper case CALL IS$IT$OK ; If the character is not "OK" JM P$TRY$AGAIN ; . get another CNZ CON$CHR ; . otherwise display it PUSH PSW ; Ch eck mode flag in case we need LDA PROMPT$MODE ; . to send a CR+LF after the ANI 01H ; . user's input CNZ DO$CRLF ; . POP PSW ; . RET ; and return PROMPT$MODE: DB 0 ; Prompt mode flag PROMPT$DECIMAL: ; ; [E6.11] ; ; Prompt the user for a decimal input of up to 10 digits. The Z flag ; indicates the termination character: Z = ESC key, results may not ; be valid; NZ = RETURN key, results valid. ; ; Entry: ; DE = pointer to prompt string ; ; Exit: ; BC,DE = Value entered by  POP H ; Get original HL back RET ; and return with result in BC & DE DEC$INPUT$MSG: DB '$' ; Decimal input message DEC$INPUT$OKC: DB '0123456789' ; Decimal input 'ok' chrs DB BS,CR,0 ; . BLOT: DB BS,' ',BS,'$' ; Blot out digit SCRATCH: DB ' ',0 ; Max 10 digits PROMPT$D$MODE: DB 0 ; CRLF flag RET$TO$CONT: ; ; [E2.19] ; ; Prompts and waits for the RETURN key to be pressed. ; ; Entry: ; none ; ; Exit: ; Display message and wait for a RETURN key. ; ; Modifies: ; the user, 0-0FFFFFFFFH ; ; Z = ESC key pressed, ignore results ; NZ = RETURN key pressed, results valid ; ; Modifies: ; A, PSW ; MVI A,01H ; Set CRLF after entry DB JR,E$PR$DEC-$-1 ; Jump to entry point PROMPT$DEC$NOLF: MVI A,00H ; Set no CRLF after entry E$PR$DEC: STA PROMPT$D$MODE ; Save prompt mode flag PUSH H ; Save original HL reigster XRA A ; Clear the current digit pointer MOV C,A ; Setup count in C register LXI H,SCRATCH ; Initialize the scratch pointer NEXT$DIGIT: all ; LXI D,RTC$MSG ; Press RETURN to continue ... CALL CENTER$OUTPUT ; . LXI D,NO$MSG ; . LXI H,RTC$OKC ; . CALL PROMPT ; . [ CR ] RET RTC$MSG: DB 'Press the RETURN key to continue ...' NO$MSG: DB '$' RTC$OKC: DB CR,0 ; end of RET$TO$CONT routine SCSI$TO$BIN: ; ; [DC.27] ; ; Converts SCSI address to binary 0-7 ; ; Entry: ; A = SCSI address to convert ; ; Exit: ; A = converted address (0-7) [0FFH = error] ; ; Modifies: B ; MVI B,0FFH ; Set up B register for pPUSH B ; Save digit counter PUSH H ; . and string pointer LXI H,DEC$INPUT$OKC ; Get current 'ok' chrs CALL PROMPT$NOLF ; Prompt for digit POP H ; Get string pointer back POP B ; . along with digit counter DB JRZ,ESCRTN-$-1 ; Return if ESC key hit CPI CR ; Check for return JZ CONVERT$STRING ; Convert string to decimal, if so CPI BS ; Check for backspace JZ BACKUP$DIGIT ; Back up 1 digit, if we can MOV B,A ; Save character for a moment MOV A,C ; Check digit count CPI 10 ossible error ORA A ; If A=0, error JZ SCSI$CONVERTED ; . SCSI$NEXT$BIT: INR B ; Increment count RRC ; Shift address right 1 bit JNC SCSI$NEXT$BIT ; Bit shifted to cary means we're done SCSI$CONVERTED: MOV A,B ; Move converted addr to A RET SORT$ACTIVE: ; ; [E2.21] ; ; Sort active device table entries ; ; Entry: ; none ; ; Exit: ; Active device table is sorted. ; ; Modifies: ; All ; LDA TOTAL$ACTIVE ; Get # of items to sort CPI 02 ; Less than two items? RM ; ; . JC ADD$DIGIT ; 10 digits or less, add to string LXI D,BLOT ; More than 10 digits, blot this one CALL CON$MSG ; . JMP DE$FOR$NEXT ; . ADD$DIGIT: INR C ; Otherwise bump digit count MOV M,B ; Save digit INX H ; Bump digit pointer JMP DE$FOR$NEXT ; Setup DE for next prompt BACKUP$DIGIT: MVI A,' ' ; Bump forward to clear digit CALL CON$CHR ; . XRA A ; Are we at the beginning? CMP C ; . JZ DE$FOR$NEXT ; Yes, don't backup MVI A,BS ; Backup to correct position CALL CO. yes -- no sort necessary S$NEXT$BLOCK: ; . STA SORT$MAX ; Save # to sort LXI B,0001H ; Setup initial compare pointers S$NEXT$ELEM: PUSH B ; Save compare pointers MOV A,C ; Convert pointers to address CALL INDEX$ACTIVE ; . in DE and HL PUSH H ; . MOV A,B ; . CALL INDEX$ACTIVE ; . POP D ; . MVI B,8 ; Compare length = 8 chrs CALL STR$COMP ; Compare string in [DE] to [HL] MVI B,8 ; Swap length = 8 chrs CM STR$SWAP ; Swap if first is less than second POP B ; Get pointN$CHR ; . DCX H ; Backup pointer 1 chr DCR C ; Push count 1 back, also DE$FOR$NEXT: LXI D,DEC$INPUT$MSG ; Setup for next prompt JMP NEXT$DIGIT ; . CONVERT$STRING: MVI M,0 ; Mark end of string LXI H,SCRATCH ; Get beginning of string CALL STR$TO$BCDE ; Convert string to BC & DE regs XRA A ; Insure NZ flag DCR A ; . PUSH PSW ; Check mode flag to see if a LDA PROMPT$D$MODE ; . CR+LF should be sent after ANI 01H ; . the user's input CNZ DO$CRLF ; . POP PSW ; . ESCRTN:ers back INR B ; Point to next item INR C ; LDA SORT$MAX ; Compare with max CMP C ; . JNZ S$NEXT$ELEM ; Not done with this pass ... DCR A ; Make sort limit one smaller CPI 03H ; Done if only 2 elements JP S$NEXT$BLOCK ; Not done if > 2 elements RET SORTMAX: DW 0 ; Sort max range (0-255 elements) STR$COMP: ; ; [E1.18] ; ; Compare two strings ; ; Entry: ; HL = source ; DE = destination ; B = count ; Exit: ; Z = two strings equal ; M = source < dest ; P = sou rce >= dest ; ; Modifies: all ; PUSH D PUSH H NEXT$COMPARE: MOV C,M INX H LDAX D INX D CMP C JNZ NOT$EQUAL DCR B JNZ NEXT$COMPARE NOT$EQUAL: POP H POP D RET STR$SWAP: ; Swap two strings ; ; [E1.18] ; ; Entry: ; HL = source ; DE = destination ; B = count ; Exit: ; data moved ; ; Modifies: all ; MOV C,M LDAX D MOV M,A MOV A,C STAX D INX H INX D DCR B JNZ STR$SWAP RET STR$TO$BCDE: ; ; [E7.09] ; ; Converts the string pointed to by milliseconds in A ; ; Exit: ; time waited ; ; Modifies: A ; PUSH PSW MVI A,221 WAIT$2: DCR A JNZ WAIT$2 POP PSW DCR A JNZ WAIT RET * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Data area . . . * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; Replicated BIOS to make direct calls easier . . . LB$BIOS$TBL: LB$WBOOT DS 3 ; Warm boot LB$CONST DS 3 ; Console status LB$CONIN DS 3 ; Console input LB$CONOUT DS 3 ; Console outpHL to a 32-bit number in the ; DE and A registers. The conversion will continue until the first ; non-numeric chr found. ; ; NOTE: a test for register overflow is not made. If HL points ; to a string whose numerical value is greater than 4,294,967,295 ; (0FFFFFFFFH), inaccurate results will occur. ; ; Entry: ; HL = ptr to string ; ; Exit: ; BC,DE = value of string (BC = high word, DE = low word) ; HL = next character to process ; ; Modifies: ; A, DE, HL ; ; DW LXIX,0 ; Clear totut LB$LISTOUT DS 3 ; List output LB$PUNCH DS 3 ; Punch output LB$READER DS 3 ; Reader input LB$HOMDSK DS 3 ; Home disk (move to track 00) LB$SELDSK DS 3 ; Select disk drive LB$SETTRK DS 3 ; Select track number LB$SETSEC DS 3 ; Select sector number LB$SETDMA DS 3 ; Set DMA address LB$DSKREAD DS 3 ; Disk read LB$DSKWRITE DS 3 ; Disk write LB$LISTST DS 3 ; List status LB$SECTRN DS 3 ; Sector translate routine ; AMPRO-specific BIOS calls LB$GETNXT DS 3 ; Get bios ver & next tbl address LB$GETEDSKals LXI D,0 ; . STN$NEXT$CHR: MOV B,A ; Save current high byte MOV A,M ; Get next chr CPI '0' ; Less than '0'? DB JRC,NO$DIG-$-1 ; Yes, finished CPI '9'+1 ; Greater than '9' DB JRNC,NO$DIG-$-1 ; Yes, finished SUI '0' ; Convert to 0-9 PUSH H ; Save pointer to input string PUSH PSW ; Save converted digit PUSH D ; Setup regs for X10 POP B ; . DW PUSHIX ; . BC = p3, p2 Previous 32-bit POP D ; . DE = p1, p0 number LXI H,0 ; . HL = t3, t2 Current 32-bit DW L DS 3 ; Get pointer to E-disk storage LB$IOINIT DS 3 ; Set new I/O parameters LB$SCSIDRV DS 3 ; SCSI direct driver LB$LEN EQU $-LB$WBOOT ; Length of bios table LB$XTBL: ; 'Extra' table definitions ... LB$SWAP$DRV DS 3 ; Swap two logical drives LB$WINDRV DS 3 ; Set/get win drive parameters LB$PHYTAB DS 3 ; Set/get phytab access LB$GETLOGICAL DS 3 ; Get logical device table entry LB$RESERVED DS 3 ; Reserved entry LB$XLEN EQU $-LB$XTBL ; Length of extra table LB$VERS: DS 1 ; Bios version numbeXIX,0 ; . IX = t1, t0 total MVI A,10 ; Set up count STN$NEXT$X10: ; Add next digit DB 0DDH,019H ; . (ADD IX,DE) DB 0EDH,04AH ; . (ADC HL,BC) DCR A ; . JNZ STN$NEXT$X10 ; . POP PSW ; Get new digit back MOV E,A ; Setup to add new digit MVI D,0 ; . LXI B,0 ; . DB 0DDH,019H ; Add new digit DB 0EDH,04AH ; . XCHG ; Move total in HL back to DE POP H ; Get input string ptr back INX H ; Bump to next chr JMP STN$NEXT$CHR ; Go back for another digit NO$DIG: PUSH D ;r DS 64 ; 32-level stack STACK: DS 2 ; Old stack pointer INBUF: DS 128 ; Command line input buffer IBUFL: EQU 128 ; Input buffer length OBPLUG: DS 1 ; Start of outbuf ('$') OUTBUF: DS PWIDTH ; Output buffer OBUFL: EQU PWIDTH ; Output buffer length HEAPPTR: DS 2 ; Pointer to next area HEAPLEN: DS 2 ; Length of next area HEAP: EQU $ ; Start of heap END START  Move high word to BC POP B ; . DW PUSHIX ; Move low word to DE POP D ; . RET ; Return with results in BC and DE. TO$UPPER: ; ; [E1.08] ; ; Convert the character in A to upper case. ; ; Entry: ; A = character to convert ; ; Exit: ; A = upper case character (if alpha) ; ; Modifies: ; A ; CPI 'z'+1 ; Convert to upper case JP UPPER$ALREADY ; . CPI 'a' ; . JM UPPER$ALREADY ; . ANI 5FH ; . UPPER$ALREADY: RET ; and return WAIT: ; Wait A ms ; ; Entry: ;  : Width DB 88 ; # of lines DB 82 ; # of text lines DB 1 ; FF flag (1=can form feed) DB 'SH ' ; . Shell variable filename DB 'VAR' ; . Shell variable filetype DB ' ' ; . File 1 DB ' ' ; DB ' ' ; . File 2 DB ' ' ; DB ' ' ; . File 3 DB ' ' ; DB ' ' ; . File 4 DB ' ' ; DB 0 ; Public drive area (ZRDOS +) DB 0 ; Public user area (ZRDOS +) ;ENV 128 bytes long ENV2: ; Terminal capabilities data DB 'ADM-3A ' ; . Name; 31 Mar 86.. fsw ; * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * SCSI/Floppy/Hard Disk Boot ROM * ; * * ; * Copyright (C) 1983, 1984, 1985 * ; * AMPRO Computers, Inc. * ; * All rights reserved. * ; * * ; * * * * * * * * * * * * * Include ZCPR3 definitions? ENV: JMP 0 ; Leading JMP ENV1: ; ZCPR3 enviornment descriptor ... DB 'Z3ENV' ; . Environment ID DB 1 ; . Class 1 environment (external) DW EXPATH ; . External path (PATH) DB EXPATHS ; DW RCP ; . Resident command package (RCP) DB RCPS ; DW IOP ; . Input/output package (IOP) DB IOPS ; DW FCP ; . Flow command package (FCP) DB FCPS ; DW Z3NDIR ; . Named directories (NDR) DB Z3NDIRS ; DW Z3CL ; . Command line (CL) DB Z3CLS ; DW * * * * * * * * * * ; ; ; Revision history: ; ; Ver Date Who Description ; --- -------- --- ----------------------------------------- ; 1.2 03/27/86 fsw Changed scsi select routine to current bios ; 3.6 routines. Added SCSI retries. Fixed ; arbitration to provide exit if scsi reset ; occures during arbitration time. ; ; 1.1 10/18/85 fsw Corrected problem booting from 96 tpi disk. ; Added 5 tries for floppy disk reads and ; Z3ENV ; . Environment (ENV) DB Z3ENVS ; DW SHSTK ; . Shell stack (SH) DB SHSTKS ; DB SHSIZE ; DW Z3MSG ; . Message buffer (MSG) DW EXTFCB ; . External FCB (FCB) DW EXTSTK ; . External stack (STK) DB 0 ; . Quiet flag (1=quiet, 0=not quiet) DW Z3WHL ; . Wheel byte (WHL) DB 4 ; . Processor speed (Mhz) DB 'P'-'@' ; . Max disk letter DB 31 ; . Max user number DB 1 ; . 1=ok to accept DU:, 0=not ok DB 0 ; . CRT selection DB 0 ; . Printer selection DB 80 ; . CRT 0 jmp for drive prameters initialization. ; ; 1.0 9/17/85 fsw Initial release. ; ; ; ; DESCRIPTION ; ; This ROM will boot from floppy, hard disk, or SCSI disk server, ; and is based on the orginal AMPRO boot ROM and the SCSI routines ; in Version 3 BIOS. Arbration is used in the SCSI routines. ; ; No alteration to boot sector is required to boot from floppy. ; Booting from hard disk requires the use of the HGEN utility, to ; install a sector on the hard disk: Width DB 24 ; # of lines DB 22 ; # of text lines DB 132 ; . CRT 1: Width DB 24 ; # of lines DB 22 ; # of text lines DB 80 ; . PRT 0: Width DB 66 ; # of lines DB 58 ; # of text lines DB 1 ; FF flag (1=can form feed) DB 96 ; . PRT 1: Width DB 66 ; # of lines DB 58 ; # of text lines DB 1 ; FF flag (1=can form feed) DB 132 ; . PRT 2: Width DB 66 ; # of lines DB 58 ; # of text lines DB 1 ; FF flag (1=can form feed) DB 132 ; . PRT 3 containing hard disk system ; configuration info, and to add code to the boot loader for hard ; disk configuration initialization. ; ; THEORY OF OPERATION ; ; The ROM on reset begins execution at 0000H. It first relocates ; itself to 8000H then continues executation above 8000H. ; The ROM then loads in a "boot loader" sector from floppy, hard disk, ; or other SCSI device. ; ; The first attempt is to load a boot loader from side 0, track 0 ; sector one of floppy drive "A" (drive sel ect "1"), if a floppy ; is present in that drive. If the first byte of that sector is not ; an LXI H or MVI A op code, then an attempt to load a boot loader ; from an SCSI device is made. SCSI ID 0 is used as the SCSI boot ; device if the board's ID is jumpered as 7. Otherwise, SCSI ID 7 ; is used for the attempt to boot from SCSI. ; ; If the appropriate SCSI device is not able to ; provide a legal boot loader (with LXI H or MVI A op code as first ; byte), then the process begins again, loopi ; YES EQU 1 NO EQU 0 MSEC EQU 167 CR EQU 0DH LF EQU 0AH CONT EQU 0 ; system control port SID1 EQU 10H ; select side one of disk SDEN EQU 20H ; select single density ROMOFF EQU 40H ; turn rom off BOOT EQU 8000H ; origin of this program RAM EQU 9000H ; beginning of scratch ram STACK EQU RAM ; stack pointer CTCA EQU 40H ; counter/timer CTCA0 EQU CTCA CTCA1 EQU CTCA+10H CTCA2 EQU CTCA+20H CTCA3 EQU CTCA+30H SIO EQU 80H ; serial io SIOAD EQU SIO SIOBD EQU SIO+8 SIOAC EQU Sng until a legal "boot ; loader" is obtained. ; ; The boot loader is stored at 9000H, followed by a jump to that ; address. The contents of the boot loader determine what happens ; next. Normally the ROM is switched off first thing. ; ; This accommodates: ; ; o Hard disk drive spinup ; o User choice of boot device ; o Networking ; o Odd-ball applications! ; ; ; MISC NOTES ; ; Supports floppy drive step rate of 6 msec only for compatability ; with the 177IO+4 SIOBC EQU SIO+12 CMND EQU 0C0H WTRK EQU CMND+1 WSEC EQU CMND+2 WDAT EQU CMND+3 STAT EQU CMND+4 RTRK EQU CMND+5 RSEC EQU CMND+6 RDAT EQU CMND+7 REST EQU 08H STEPI EQU 58H RDSEC EQU 88H RDID EQU 0C8H FI EQU 0D0H ERMSK EQU 18H ID EQU 29H ; Little board SCSI id ; ; NCR 5380 controller equates ; NCRBASE EQU 20H ; Base address of NCR 5380 NCRCSD EQU NCRBASE+0 ; (R) Current SCSI data register NCRODR EQU NCRBASE+0 ; (W) Output data register NCRICR EQU NCRBASE+1 ; (RW) Init0 or 1772 fdc. ; ; Supports hard disk with 512 byte sectors only. Each call to read ; track reads one AMPRO track of 16 sectors when booting from hard ; disk. ; ; Requires the use of SCSI self-initializing controllers, such as ; Adaptec ACB-4000, Shugart 1610-4, Xebec OWL drive/controller, etc. ; ; FEATURES ; ; Test for presence of 177x floppy disk controller and ; for 5380 SCSI controller. ; ; Test for presence of boot sector on the disk it has read. ; ;iator command register NCRMR EQU NCRBASE+2 ; (RW) Mode register NCRTCR EQU NCRBASE+3 ; (RW) Target command register NCRCSBS EQU NCRBASE+4 ; (R) Current SCSI bus status NCRSER EQU NCRBASE+4 ; (W) Select enable register NCRBSR EQU NCRBASE+5 ; (R) Bus & status register NCRSDS EQU NCRBASE+5 ; (W) Start DMA send NCRIDR EQU NCRBASE+6 ; (R) Input data register NCRSDTR EQU NCRBASE+6 ; (W) Start DMA target receive NCRRPI EQU NCRBASE+7 ; (R) Reset parity/interrupt NCRSDIR EQU NCRBASE+7 ; (W) Start D Test for properly formated floppy disk in drive. ; ; If unable to boot from floppy disk will try SCSI, if ; unable to boot from SCSI, starts over. This sequence ; will repeat untill sucessful. ; ; ; SCSI ID CONVENTIONS ; ; SCSI Master mode: Set board SCSI ID to 7 (refer to board manual). ; When the board's SCSI ID is 7, the boot ROM issues an SCSI ; bus reset, and then uses the device at SCSI ID 0 as the ; SCSI boot device, if floppy boot attempt fails. MA initiator receive NCRDACK EQU NCRBASE+8 ; (RW) DACK pseudo-DMA register ; Current SCSI bus status (NCRCSBS) NCRRST EQU 10000000B ; Reset NCRBSY EQU 01000000B ; Busy NCRREQ EQU 00100000B ; Request NCRMSG EQU 00010000B ; Message NCRCD EQU 00001000B ; Control/Data NCRIO EQU 00000100B ; Input/Output NCRSEL EQU 00000010B ; Select NCRDBP EQU 00000001B ; Data bus parity ;............................................................... ORG BOOT JMP START -BOOT ; power on or re-boot ; ; SCSI Slave mode: Set board SCSI ID to anything other than 7. ; When the board's SCSI ID is not 7, the boot ROM does not ; issue an SCSI bus reset. In this case the device at SCSI ; ID 7 is used as the SCSI boot device if the floppy boot ; attempt fails. This might be a disk server rather than ; a disk controller. ; ; In all cases if will boot from floppy in drive "A" if a legal boot ; sector is present (as defined above) ;******************************************************************** JMP SETUP ; setup disk drive JMP STEPIN ; step in one track JMP SIDEONE ; select side one JMP FDCLR ; clear the fdc JMP SETDMA ; set new dmaadr (hl) JMP READTRK ; read current track at dmaadr JMP READSEC ; read current sector at dmaadr JMP READID ; read next sector address JMP SETPRAM ; pass the hard disk prameters to the ; scsi controller, for dumb controllers. DMAADR: DS 2 IDSV: DS 6 SELBYT: DS 1 TRACK: DS 1 SECTOR: DS 1 STATUS: DS 1 TWOSID: DS 1 SBIAS: DS 1 ST ART: DI XRA A OUT CONT ; clear system control register LXI H,0 LXI D,BOOT RELOC: MOV A,M STAX D INX H INX D MOV A,H CPI 16 ; relocate 16 pages JNZ RELOC -BOOT ; this code runs at address 0 JMP INITSYS ; this code runs relative to boot ; copyright declaration DB 'SCSI Boot Rom Version 1.2 - (C) 1983,1984,1985,1986 ' DB '- AMPRO Computers, Inc. - All rights reserved. ' INITSYS:LXI SP,STACK ; set local stack LXI H,CTCTBL CTCINT: MOV A,M INR A JZ SIOINT DCR A OUT try$hd$dvr ; do hard disk, no fdc present ; ; floppy disk controller present try to boot from floppy ; MVI A,5 STA TRIES ; set up try count CBOOT2: CALL SETUP CALL READID CALL ERROR JNZ CBOOT2 ; try to read id 5 times MVI A,5 STA TRIES ; reset floppy try counter LDA IDSV+2 ; get sector # CPI 17 MVI A,0 JC CB0 INR A CB0: STA TWOSID ORA A RAL RAL RAL RAL STA SBIAS ; 0 if single sided, 16 if 2 sided LXI H,RAM SHLD DMAADR INR A ; sector 1 ( or 17 ) OUT WSE CTCA0 OUT CTCA1 INX H JMP CTCINT CTCTBL: DB 47H,13,255 ;9600 ;CTCTBL: DB 3,0,255 ;19200 SIOINT: LXI H,SIOTBL SIOLP: MOV A,M INR A JZ CBOOT DCR A OUT SIOAC OUT SIOBC INX H JMP SIOLP SIOTBL:DB 4,46H,5,0EAH,3,0C1H,255 ;9600 ;SIOTBL: DB 4,84H,5,06AH,3,0C1H,255 ;19200 ; cboot is the start of the read disk routines. ; ; check little board id, if id = 7 do SCSI reset, if id not=7 ; no reset is issued. ; ; a 1 second time delay is invoked prior to SCSI reset to allow C CALL READSEC CALL ERROR LDA TWOSID JNZ CB0 ; error occured try to read again lda ram ; see if boot record there cpi 21h ; starts with lxi h,xxxx jz ram cpi 3eh ; other choice is mvi a,xx jz ram jmp try$hd$dvr ; see if can do hard disk SETUP: MVI A,'A'-40H OUT CONT ; select a:, side 0 STA SELBYT ; save it CALL FDCLR MVI A,REST ; restore CALL OUTCMD ; to fdc JMP FDWAIT ; Wait for command to complete and ret ; ; Read current track at dmaadr ; READTRK: lda ids; various SCSI devices do their powerup initialization before ; the SCSI reset is issued. ; CBOOT: IN ID ; get little board SCSI id ani 07h ; mask off inr a ; make 1 thru 8 mov b,a ; set 'b' for count xra a stc ; set carry setid: ral dcr b jnz setid sta myid cpi 80h ; scsi id 7 mvi a,10000000b ; target id=7 jnz resetnot MVI A,4 ; 4 x .25 sec CALL TIMER mvi a,80h ; scsi reset out ncricr ; set reset line high holdit: dcr a jnz holdit ; 50 usec min out nv+3 ; sector size cpi 3 lxi h,skwtbl1 ; 96 tpi disk jz rtloop LXI H,SKWTBL ; sector skew table RTLOOP: mvi a,5 ; sta tries ; set floppy try counter MOV C,M INX H INR C RZ ; finished DCR C LDA SBIAS ADD C STA SECTOR OUT WSEC RSAGN: PUSH H ; save skew table pointer CALL READSEC ; read the sector CALL ERROR ; check for errors JNZ RSAGN1 ; try to read the sector again LHLD DMAADR ; get current dmaadr address SHLD DMA ; save current dma addr POP H ; restore scricr ; clear reset line in ncrrpi ; and the interrupt line mvi a,00000001b ; target id=0 ; ; has target id in 'a'. if little board id=7 boot from device 0. ; if little board id not=7, boot from device 7. ; resetnot: sta target ; device to boot from xra a out ncricr ; clear the 5380 registers out ncrmr out ncrtcr out ncrser in ncrmr ; read the mode register ; mode register should equal 0 if ; 5380 is present. sta scsi ; set scsi to zero or non-zero to ; show kew table pointer JMP RTLOOP ; next sector ; ; if error on read sector, restores old dma address and attempts ; to read the same sector again. ; RSAGN1: LHLD DMA ; get old dmaadr dma address SHLD DMAADR ; restore dma address POP H ; restore stack JMP RSAGN ; SKWTBL: DB 1,2,3,4,5,6,7,8,9,10,255 skwtbl1:db 1,2,3,4,5,255 ; ; read id twice, once to see if disk in drive, the second for ; the id value. ; READID: IN STAT IN RDAT MVI A,RDID CALL OUTCMD call fdwait ; See if will timpresence of ncr 5380 ; ; everything on the SCSI buss should have completed initialization and ; SCSI reset may have been issued. ; ; test for presence of 177x floppy disk controller. ; MVI A,0AAH ; test for presence of fdc OUT WSEC ; write pattern to sector reg MOV B,A ; save in 'b' ANI 0FH ; set up loop value CLOOP: DCR A ; give the 177x time for the sec reg JNZ CLOOP ; to set up. IN RSEC ; read the sector reg CMP B ; see if same as written to sec reg JZ CBOOT2 ; JMPe out CPI 255 ; no floppy sta status ; if timeout error, set error status rz ; if timeout just return IN STAT ; clear fdc reg IN RDAT LXI H,IDSV MVI A,RDID CALL OUTCMD CALL RD MOV A,B STA STATUS RET READSEC:IN STAT ; clear status IN RDAT ; clear any trash LHLD DMAADR CALL FDCLR MVI A,RDSEC ; read sector command CALL OUTCMD ; to fdc CALL RD ; read loop MOV A,B STA STATUS SHLD DMAADR RET RD: IN STAT MOV B,A ; save status RAR RNC ; return whe n fdc not busy RAR JNC RD ; wait for drq IN RDAT MOV M,A INX H JMP RD STEPIN: LDA TWOSID ORA A JZ STPI CALL SIDEONE LXI H,TRACK DCR M LXI H,MSEC ; wait one millisecond JMP WT ; wt returns to caller STPI: MVI A,STEPI ; step in command CALL OUTCMD STLP: IN STAT RAR JC STLP RET FDCLR: MVI A,FI OUT CMND MVI A,0 CL: DCR A JNZ CL IN STAT IN RDAT RET OUTCMD: OUT CMND MVI A,19 OC0: DCR A JNZ OC0 ; wait 66.5 usec for fdc to set-up RET SETDMA: SORA H ; 1.0 JNZ TIMER1 ; 2.5 ;total = 6 usec X 41668 LXI H,TIMEOUT DCR M RZ JMP TIMER0 ; ;--------------------------------------------------------------- ; Send bytes to console until zero encountered ; use to insert messages when debuging ; format is ; call puts ; db 'your message',0; must terminate with '0' ; ;PUTS: pop h ; 'hl' has address of msg ; mov c,m ; get char ; inx h ;CONOUT: ; MVI A,01H ; Check "all sent" bit in register 1 ; OUT 84H ; . ; IN 84H ; . ; ANI 0HLD DMAADR SHLD DMA RET SIDEONE:LDA SELBYT ORI SID1 OUT CONT RET ; ; floppy error checking enters here. Returns with zero flag NZ if ; error, or Z if no error. Floppy routines must set STATUS for error ; conditions. ; ERROR: LDA STATUS ANI ERMSK RZ PUSH H LXI H,TRIES ; point to tries DCR M ; tries -1 POP H RNZ ; try again LDA SCSI ; get 5380 present byte ANA A JZ HD$DVR ; Try hard disk, have timed out on floppy ; disk at least 5 times ; ; floppy error fa1H ; "ALL SENT" is bit 0 ; JZ CONOUT ;TRANSMIT BUFFER NOT READY ; MOV A,C ;CHARACTER TO REGISTER A ; OUT 80H ; mov a,m ; ana a ; returns with char in 'a', null = end ; jnz puts+1 ; pchl ; hl has return address ;----------------------------------------------------------------- ; ; if no boot sector is present on the floppy disk, floppy timeout ; has occured, floppy read error, or no floppy disk controller is ; present, entry to the hard disk (scsi) driver is here. ; ; starts with 5 seclls thru to here also hard disk errors enter here to ; start the hole proceedure over and over again. ; ERROR1: XRA A ; make sure prom is turned on OUT CONT JMP 0 ; jmp to prom ; WAIT: LXI H,100 * MSEC WT: DCX H MOV A,H ORA L JNZ WT RET ; ; This routine will wait for a for the FDC to go not busy, showing ; completion of a command. After 1 seconds time out, a FORCE INTERRUPT ; command will be issued to the FDC. Routines will come through here ; at least 5 times before final errond timer to prevent hammering the scsi buss ; with possible scsi resets. ; TRY$HD$DVR: MVI A,20 ; 20 x .25 seconds = 5 sec CALL TIMER ; ; Hard disk driver ; HD$DVR: LXI SP,STACK ; reset stack lxi h,hdtrk shld boot+19 ; patch readtrk xra a ; zero 'a' lxi h,ram ; address to read sector mov m,a ; clear anything at this address sta hdsect ; zero hard disk sector shld dmaadr call scsi$rd ; read boot sector lda ram cpi 21h ; should be lxi h,xxxx jz ram cpi 3eh ; oor occures. Total time out 5 seconds. ; FDWAIT: LXI H,TIMEOUT ; Point to timeout location MVI M,3 ; Set major loops for timeout ; 3 = about 1 sec. DLOOP: IN STAT ; Get FDC status RAR ; test busy bit RNC ; . zero status if busy non-active RAR ; see if byte to be read JC FREAD ; read the byte DCX H ; See if enough minor loops MOV A,H ; . (Approx 34,000 times) ORA L ; . JNZ DLOOP ; Not done with minor loop LXI H,TIMEOUT ; Decrement major loop counter DCR M ; . ther choice is mvi a,xx jz ram jmp error1 ; no boot sector go try floppy again ; ; Read hard disk system to memory. Do 16 sectors at a time. One AMPRO ; hd track. The boot loader will call this routine twice. ; First pass read sectors 0 thru 15, second pass read 16 thru 31 for ; 32 sectors total. ; HDTRK: call scsi$rd cpi 0ffh ; see if return has timeout error jz error1 ; start all over lhld dmaadr lxi d,512 ; update dma address dad d shld dmaadr lda hdsect ; see if two tracks  (timeout loop count) JNZ DLOOP ; . CALL FDCLR ; force fdc clear XRA A ; Set A to 0FFH and status to NZ OUT CONT ; deselect so floppy select light DCR A ; will go out RET ; ; FREAD: IN RDAT ; get the data byte from the fdc JMP DLOOP ; just loop till command over ; ; timer entered with 'a' equal to number of major loops wanted ; each major loop = aprox .25 sec ; TIMER: LXI H,TIMEOUT MOV M,A ; save major loop value TIMER0: LXI H,41668 TIMER1: DCX H ; 1.5 MOV A,L ; 1.0 (32 sectors) inr a ; next sector to read cpi 32 ; have already read 512x32 bytes rz ; cpi 16 ; see if one "track" has been read sta hdsect ; update sector new sector, the boot ; loader reads two tracks. rz ; return to boot jmp hdtrk ; loop till through ; ; ; SCSI return sense data command (Cmd 03) ; SCSI$STAT$CMD: DB 3 ; 00 - REQUEST SENSE COMMAND DB 0 ; 01 - LOGICAL UNIT DB 0 ; 02 - RESERVED DB 0 ; 03 - RESERVED DB 4 ; 04 - NUMBER OF BYTES   DB 0 ; 05 - RESERVED ; ; SCSI read/write command (Cmd 08/0A) ; SCSI$RD$CMD: EQU 08H ; 08 IS READ DATA SCSI$RW$CMD: DB SCSI$RD$CMD ; 00 - 08=Read, 0A=Write HIGH$ADDR: DB 0 ; 01 - High address MED$ADDR: DB 0 ; 02 - Middle address LOW$ADDR: DB 0 ; 03 - Low address DB 1 ; 04 - Number of sectors STEP$RATE: DB 0 ; 05 - Step rate (Xebec) ; ; Init scsi controller prameters ; ; When called HL = address of scsi command ; DE = address of prameter table i reset has occured jz in$progress jmp clear$arbit arbitrate$won: nop ; Arbritration delay nop in ncricr ; Check for lost arbitration ani 20h ; . jnz clear$arbit ; We lost -- start over lda my$id mov b,a in ncrcsd ; See if we're the highest priority sub b ; . remove my addr sub b ; . compare my addr to bus data jm i$win ; We win if result < 0 jmp clear$arbit ; . otherwise we lose -- start over i$win: in ncricr ; Check again for lost arbitration ani 20h ;; SETPRAM: SHLD CMDPTR ; set address of scsi command XCHG ; 'de' to 'hl' SHLD DATPTR ; save address of prameters to pass JMP SCSI$CMD ; ; Read from the hard disk ; SCSI$RD: LXI H,SCSI$RW$CMD ; Get command string SHLD CMDPTR ; Save the command pointer CALL BLD$SCSI$SCTR ; Build SCSI sector address ; ; Exits with status in A. 0FFH = timeout error ; SCSI$CMD: LXI H,TRIES ; set up retry count MVI M,2 SCSI$CMD$RETRY: CALL SELECT ; Perform the SCSI operation LDA STAT . (just in case) jnz clear$arbit ; We lost -- start over mvi a,08h ; set assert BSY bit in icr out ncricr ; . in ncricr ori 04h ; OR in SEL to ICR out ncricr nop ; wait one bus clear delay lda my$id ; Select target: get our ID, mov b,a ; . lda target ; . or in target ID ora b ; . out ncrodr ; . and send to NCR chip mvi a,0dh ; Assert data bus out ncricr ; . (along with SEL & BSY) in ncrmr ; Reset arbitration bit ani 0feh ; . out ncrmr ; . mUS ; Get the return status STA ERFLAG ; save error CPI 0FFH ; Timeout? JZ SCSI$DONE ; Yes, go save timeout status ANI 2 ; Check for SCSI error status JZ SCSI$DONE ; No error -- finish up LHLD CMDPTR SHLD SAVE$CMDPTR ; save old command pointer LXI H,SCSI$STAT$CMD ; get sense SHLD CMDPTR ; set command pointer LHLD DMAADR SHLD SAVE$DMA ; save the current LXI H,MESSAGE ; message area SHLD DMAADR CALL SELECT ; do operation LXI H,TRIES DCR M ; tries -1 LHLD SAvi a,05h ; Release BSY, keep SEL out ncricr ; . and assert data bus nop lxi b,6000h ; 250 ms loop (1M cycles) stim: in ncrcsbs ; Wait for BSY ani busbsy ; . jnz select$ok ; Got him! dcr c jnz stim ; inner loop: 41*256 = 10496 cycles dcr b jnz stim ; outer loop: 10510*96 = 1M cycles xra a ; Select timeout -- clear bus out ncrodr dcr a ; set 'a' to 0ffh sta status ; Save status timeout. jmp all$done ; and clear the registers select$ok: xra a ; Set goodVE$DMA ; get dma address back SHLD DMAADR ; restore dma address LHLD SAVE$CMDPTR SHLD CMDPTR ; restore command pointer JNZ SCSI$CMD$RETRY ; MVI A,0FFH SCSI$DONE: ORA A ; Set Z/NZ for user RET ; and return ; ; ; Build 2-byte SCSI sector number starting with 00 ; ; NOTE: This routine uses only a block number starting with 00 ; and read a maximun of ffh sectors. ; BLD$SCSI$SCTR: lda hdsect sta low$addr ret ; ; Select controller, and fall through to phase if status all$done: mov b,a ; temp save status mvi a,01h ; Release SEL out ncricr ; . xra a ; Remove address from data bus out ncricr ; . mov a,b ; Get status back ora a ; Set status rnz dcr a ; set 'a' to ffh sta status ; clear scsi status to timeout.. ; SCSI.011 ; * * * * * ; * --------\ NOTE: we fall through if we successfully ; * --------/ selected the controller!! ; * * * * * MVI A,00000110B ; Set DMA mode and Monitor Busy OUT NCRMR ; . SCSI$RDY:  selected ok. ; ; busbsy: equ 40h ; SELECT: xra a out ncricr ; Clear initiator command register out ncrtcr ; . and target command register clear$arbit: xra a out ncrmr ; . in ncrrpi ; reset interrupts arbitrate: lda my$id ; Assert my ID (the initiator) out ncrodr ; . mvi a,1 ; start arbitration out ncrmr ; . in$progress: in ncricr ; Wait for "arbitration in ani 40h ; . progress" bit jnz arbitrate$won ; we have argitration in ncrbsr ani 10h ; see if scs; Wait for either a 5380 "Interrupt" or a REQ from Target. ; The REQ is needed since it may have come too soon after ; selection to register an Interrupt. IN NCRBSR ; Check for "Interrupt" ANI 00010000B ; . JNZ SCSI$INT IN NCRCSBS ; Check for REQ ANI NCRREQ ; . JZ SCSI$RDY ; Wait for Interrupt or REQ JMP PHASE ; Process phase vector SCSI$INT: ; Determine cause of 5380 "Interrupt". Either phase ; changed, busy dropped, or bus was reset. If bits 2 and 3 ; of the NCRBSR are not  0's when the Interrupt flag (bit 4) ; is set, then it is either a loss of BUSY or an SCSI RESET. XRA A OUT NCRICR ; Release data bus IN NCRBSR ; Read 5380 Bus and Stat Reg ANI 00001100B ; Keep interesting bits JNZ SCSI$EXIT ; Reset or Busy Loss: Exit ; 00 --> Process phase vector PHASE: ; DMA mode and Monitor Busy must be cleared prior to clearing ; of the 5380 Interrupt Flag. Then mode register is restored. ; Otherwise the interrupt flag may not clear and the DMA Mode ; may notr for multi-sector IN NCRBSR MOV C,A ; Keep for phase change checking ANA D ; Mask for DMA request JZ RSCSI2 ; ; All transfer is one byte at a time ; IN NCRDACK MOV M,A INX H JMP RSCSI1 ; Read until phase changes ; ; This code skipped when data is being transferred ... ; RSCSI2: MOV A,C ; Check phase ANI 00010000B ; . JZ RSCSI1 ; Wait for DMA request JMP SCSI$INT ; Process "interrupt" flag ; ; Generalized SCSI write routine ; WSCSI:  be useable. XRA A ; Clear 5380 Mode Register OUT NCRMR ; . IN NCRRPI ; Reset interrupts MVI A,00000110B ; Set DMA mode and Monitor Busy OUT NCRMR ; . IN NCRCSBS ; Update phase... ANI 00011100B ; Mask all but phase bits, clear carry bit RAR ; Rotate over for target MOV E,A ; . (Save for use with jump table) RAR ; . OUT NCRTCR ; Set phase MVI D,0 ; E is already set (6 ins ago) LXI H,PHASE$TABLE ; Get phase jump table base MVI A,1 ; Assert data bus OUT NCRICR OUT NCRSDS ; Start DMA send ; ; Wait for DMA request, keeping an eye on phase. Note that the NCR ; will not issue an ACK, nor will it generate DMA requests once the ; phase changes, so it is best to treat DMA request checking as a ; higher priority than phase change checking. ; WSCSI1: SHLD DATPTR ; Save (new) data ptr WSCI11: IN NCRBSR MOV C,A ; Save status for use below ANA D ; Check for DMA request JZ WSCSI2 mov a,m  DAD D ; Add offset for this phase MOV A,M ; Get phase pointer into HL INX H ; . MOV H,M ; . MOV L,A ; Pointer is now together MVI D,01000000B ; DMA request mask (used by RSCSI and WRSCSI) PCHL ; Go to it! PHASE$TABLE: DW PHASE0 DW PHASE1 DW PHASE2 DW PHASE3 DW PHASE4 DW PHASE5 DW PHASE6 DW PHASE7 PHASE0: ; Data out phase LHLD DATPTR ; to pass prameters to scsi controller JMP WSCSI ; Execute SCSI write routine PHASE1: ; Data in phase  out ncrdack inx h JMP WSCSI1 ; Write more bytes until phase changes ; ; This code skipped when data is being transferred ... ; WSCSI2: MOV A,C ; Check phase ANI 00010000B ; . JZ WSCSI1 ; Wait for dma request JMP SCSI$INT ; Process "interrupt" ; ; Tempory storage ; TRIES: DB 5 ; number of tries DMA: DS 2 ; save for dma address TIMEOUT: DS 1 MYID: DS 1 TARGET: DS 1 ERFLAG: DS 1 HDSECT: DS 1 DATPTR: DS 2 CMDPTR: DS 2 MESSAGE: DS 4 SCSI: DS 1 ... LHLD DMAADR ; Use data pointer JMP RSCSI ; Execute SCSI read routine PHASE2: ; Command out phase ... LHLD CMDPTR ; Use command pointer JMP WSCSI ; Execute SCSI write routine PHASE3: ; Status in phase ... LXI H,STATUS ; Use status pointer JMP RSCSI ; Execute SCSI read routine PHASE7: ; Message in phase ... LXI H,MESSAGE ; Use message pointer JMP RSCSI ; Execute SCSI read routine ; Currently unused phases PHASE4: PHASE5: PHASE6: SCSISAVE$DMA: DS 2 SAVE$CMDPTR: DS 2 END ferred ... ; WSCSI2: MOV A,C ; Check phase ANI 00010000B ; . JZ WSCSI1 ; Wait for dma request JMP SCSI$INT ; Process "interrupt" ; ; Tempory storage ; TRIES: DB 5 ; number of tries DMA: DS 2 ; save for dma address TIMEOUT: DS 1 MYID: DS 1 TARGET: DS 1 ERFLAG: DS 1 HDSECT: DS 1 DATPTR: DS 2 CMDPTR: DS 2 MESSAGE: DS 4 SCSI: DS 1 $EXIT: XRA A ; clean up 5380 and exit OUT NCRTCR OUT NCRMR IN NCRRPI ; reset unterrupts RET ; Generalized SCSI read routine ; Initiator command reg is already ininialized by phase ; RSCSI: OUT NCRSDIR ; Start DMA initiator receive ; Wait for DMA request, keeping an eye on phase. Note: we must do ; a check for DMA request before checking for a phase change, since ; a byte may be queued up waiting to be DACKed prior to the phase ; change. RSCSI1: SHLD DATPTR ; Save (new) data pttransfer only if ; you can be sure the controller can buffer 256 bytes of data and ; can transfer at 5.25 us per byte. Extra DACK's after the last REQ ; will do no harm. ; ; INIR register use: H = memory pointer, C = I/O port, B = counter ; MOV B,E ; Set up loop count MVI C,NCRDACK ; Set up source port address DB 0EDH ; ED B2 = INIR instruction op code DB 0B2H JMP RSCSI1 ; Read more bytes until phase changes ; Be sure and check phase if no DMA ;  request, since NCR won't issue any ; unneeded DACKs ; This code skipped when data is being transferred ... RSCSI2: MOV A,C ; Check 5380 "interrupt" flag ANI 00010000B ; . JZ RSCSI1 ; Wait for DMA request, JMP SCSI$INT ; or process "interrupt" ENDIF ; ; Temporary storage ; TRIES: DB 5 ; number of tries DMA: DS 2 ; save for dma address TIMEOUT: DS 1 MYID: DS 1 TARGET: DS 1 ERFLAG: DS 1 HDSECT: DS 1 PRAMPTR: DS 2 CMDPTR: DS 2 MESSAGE: DS 4 SCSI: DS 1 SCSI$IOes) ; ; The boot loader is modified to find this offset and install the users ; changes in bios before jumping to cold boot. ; ; NOTES: ; ; Only the system track of the hard disk with SCSI id 0 and LUN 0 will ; be patched. ; ; Only Little Board's jumpered for SCSI initiator id 7 can run this ; utility. ; ; Sector 31 (1F hex) of the hard disk system track is reserved. ; ; Requires special SCSI boot prom . ; ;---------------------------------------------------------------$COUNT DS 1 ; Byte/burst mode control END --------- ; ; The following equates are entry points into the boot prom ; SETDMA EQU 800FH READTRK EQU 8012H ; BOOT EQU 9000h ; location of boot loader TPA EQU 100H OFFSET EQU (BOOT-TPA)-3 ; -3 for jmp start before patch area WBOOT EQU 0 ; location of bios warm boot ; CONTROL EQU 0 ; board control port ; SREAD EQU 08H ; scsi read data SWRITE EQU 0AH ; scsi write data ; CR EQU 0DH LF EQU 0AH ;----------------------------------------------------------------- ; ORG TPA ; cp/m tpa ; * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * Hard Disk Auto-Boot Installer * ; * * ; * Copyright (C) 1985 AMPRO Computers, Inc. * ; * All rights reserved. * ; * * ; * * * * * * * * * * * * * * * * * * * * * * * ; ; ; Revision history: ; ; Ver Date Who JMP START ; ;****************************************************************** ;************************Boot loader******************************* ; values set at 0 are patched to users addresses by the program. ; PATCH$START: MVI A,40H ; must turn off rom out control DMA: lxi H,0 ; set dmaadr address call setdma call readtrk ; read first track call readtrk ; read second track ; ; find the user disk information that was loaded in to memory ; from sector 15 of the hard disk ; lhld Description ; --- -------- --- ----------------------------------------- ; ; 1.2 1/7/85 fsw Installs users HD$ALV$AVAIL: information ; in bios at boot time. ; ; 1.0 9/20/85 fsw Initial release. ; ; VERS EQU 12 ; version 1.2 ; ; This version saves all the setup disk parameters that the user ; has defined by running SYSGEN, HINIT, and SWAP to the hard disk. ; This user defined information is stored on the last sector (sector 31) ; of the system tra (dma+1)+offset ; get load address lxi d,15872 ; offset to where hard disk sector 31 ; landed dad d ; sorce address in 'hl' ; ; move the users dpbase into bios ; DDPBAS: lxi d,0 ; patched to destination address lxi b,256 ; number of bytes to move dw 0b0edh ; z80 ldir ; ; move the users phytab into bios ; DOPHY: lxi d,0 ; patched to address of phytbl lxi b,64 dw 0b0edh ; move the 4 bytes with z80 ldir ; ; move the users dpb's into bios ; DODPB: lxi d,0 ; patched to destick, and is used to "patch" the standard BIOS on boot. ; ; The information on this sector will be read somewhere into memory ; by the hard disk boot prom with an offset of 15872 bytes (3E00 hex) ; from the boot dma address. The user's dpbase (256 bytes), the 64 byte ; PHYTAB with the user's logical/physical configuration, the user's ; hard disk DBP's (176 bytes), the users HD$ALV$AVAIL block (12 bytes), ; and the users hard disk byte/block flag (1 byte) are saved in that order. ; (total 509 bytnation address lxi b,176 ; size hard disk DPB's dw 0b0edh ; z80 ldir ; ; move the users HD$ALV$AVAIL info into bios ; HDAVL: lxi d,0 ; patched to destination address lxi b,12 ; bytes to move dw 0b0edh ; z80 ldir ; ; move the users byte, block mode value to bios ; CTLBYT: lxi d,0 ; patched to destination address mov a,m ; 'hl' has location of byte stax d ; store at 'de' location ; GOBIOS: JMP 0 ; go to cold boot ; SIZE$PATCH: equ $-patch$start ; ;********************End of  Boot loader**************************** ;****************************************************************** ; START: lxi h,0 ; init new stack and save old dad sp shld oldstk lxi sp,stack ; ; clear the buffer area to zeros ; lxi h,btsec lxi b,1024 ; do 1024 bytes CLEAR: xra a mov m,a inx h dcx b mov a,b ora c jnz clear ; ; move the bios jump table to use it's io, easier ; lhld wboot+1 ; get address of bios mvi l,0 ; begining of bios jmp table lxi d,bj$tbl ; bios jmp e boot sector in memory lets see if sysgen has been ; done on the hard disk. two choices are present for the first byte ; of the AMPRO boot sector either mvi a,xx or lxi h,xxxx , check for ; both. ; ldax d ; call to scsi returns data pointer cpi 3eh ; see if mvi a,x jz next cpi 21h ; could be lxi h,xxx jz next call puts ; neither db cr,lf,'Valid Boot sector not present on hard disk, ' db 'do SYSGEN, HINIT, and SWAP, then retry.',0 jmp exit ; ; figure out the dma address to load table lxi b,64 ; move 64 bytes dw 0b0edh ; z80 ldir ; ; check id of board ; in 29h ; get board id ani 07h ; mask board id cpi 7 ; must be 7 jz signon adi '0' sta shid ; show id setting call puts db cr,lf,'Little Board ID = ' SHID: db ' , must = 7 to run this utility.',0 jmp exit ; ; bios jmp table moved, give signon ; SIGNON: call puts db cr,lf,lf,lf db ' AMPRO Hard Disk Auto-Boot Installer ',cr,lf db ' Copyright (C) 1985 AMPtrack 0 at ; the rest if the info we will find in the bios jmp table ; NEXT: ldax d ; find the lxi h,xxx instruction for cpi 21h ; dma address inx d jnz next xchg ; location of dma address in 'hl' mov a,m inx h mov h,m ; dma address in 'hl' mov l,a shld dma+1 ; set dma address in new boot loader ; ; fix the cold boot address ; lhld wboot+1 ; get address of warm boot from cp/m mvi l,0 ; make it a cold boot shld gobios+1 ; patch jmp in boot loader ; ; get users dpbase, RO Computers, Inc. ',cr,lf db ' Version ',VERS/10+'0','.',VERS MOD 10+'0' db cr,lf,lf db 'This utility will install your current hard disk ' db 'configuration on the system ',cr,lf db 'tracks of the SCSI hard disk drive located at ' db 'SCSI ID 0, LUN 0. ',cr,lf,lf db 'Prior to using this program you must use SYSGEN ' db 'to write the proper size ',cr,lf db 'CP/M system to the system tracks of the SCSI hard ' db 'disk drialways at cold boot+80h in AMPRO bios ; mvi l,80h ; offset from cold boot shld ddpbas+1 ; load address in boot loader lxi d,udpbase ; move the dpbase to save area lxi b,256 dw 0b0edh ; move it, ldir push d ; save buffer destination address ; ; get address of phytbl ; call gettbl ; get address of next table lxi d,6 ; offset to phtbac dad d ; 'hl'=address of phtbac routine shld gtbl+1 lxi h,0 ; if 'hl'=00 returns address of phytbl GTBL: call 0 ; call phtbac shld dophy+1 ;ve from which you ',cr,lf db 'will boot. In addition, you must have already ' db 'used the HINIT and SWAP ',cr,lf db 'utilities to customize your system. ',cr,lf,lf db 'NOTE: The CP/M system you install on the hard ' db 'disk must identical to ',cr,lf db 'the system you are running now. ',cr,lf,lf db 'WARNING!!! ',cr,lf db 'As a safety measure, be sure to backup your hard ' db 'disk before you perform ',cr,lf  patch location of phytab in users bios pop d ; get destination address lxi b,64 ; move 64 bytes dw 0b0edh ; z80 ldir push d ; save address ; ; the patch area now contains the phytab as designated by the user. ; ; lets find the users DPB's for the hard disk. Test first to see ; if SWAP has been run ; mvi c,0 ; drive 'A' mvi e,1 ; not first time select call seldsk ; do select to return dpb header address lxi d,10 ; offset to dpb address dad d mov a,m ; get the address of t db 'this function or attempt hard disk auto-booting! ',cr,lf,lf db cr,lf,'Do you wish to continue? (Y/N) ',0 call conin ani 5fh ; make it upper case cpi 'Y' jnz exit ; exits if input not Y ; ; read the current boot sector into memory ; DOIT: mvi a,sread ; scsi read command sta scsicmd lxi h,scsicmd ; point to scsi command lxi d,btsec ; data area mvi a,1 ; target address call scsi jnz scsierr ; not zero results=error ; ; we have thhe dpb in 'hl' inx h mov h,m mov l,a mov a,m ; 'hl' has address of DBP cpi 40+1 ; sectors per track information jnc movdpb ; have hard disk DPB call puts db cr,lf,'Run HINIT and SWAP to set up your system first.' db cr,lf,0 pop d ; restore stack for exit jmp exit ; ; ; find address of first hard disk dpb ; MOVDPB: lhld wboot+1 ; get address of bios mvi l,80h ; offset to dpbase lxi d,16*5 ; offset to first hard disk dpb header dad d ; 'hl'= first hard disk lxi d,10  ; offset to dpb address dad d mov a,m ; get the address of the dpb in 'hl' inx h mov h,m mov l,a pop d ; restore destination address shld dodpb+1 ; address of users hd dpb for boot loader lxi b,176 ; move 176 bytes, 11 dpb's dw 0b0edh ; z80 ldir ; ; find the HD$ALV$AVAIL block to save and the scsi controller burst/byte ; mode value and save. needed for Shugart and other non-burst controllers ; push d ; save 'de' call gettbl ; get address of next table lxi d,3 ; dad dm1 ; numeric adi '7' ; alpha offset (A thru F) jmp num1+2 NUM1: adi '0' ; numeric offset (0 thru 9) sta errtyp+1 ; ERRMSG: call puts db cr,lf,'SCSI read/write error, Sense byte = ' ERRTYP: db ' ',cr,lf,lf,0 ; fall thru and exit ; EXIT: xra a lhld oldstk sphl ret ; ; SEND BYTES TO CONSOLE UNTIL ZERO ENCOUNTERED ; PUTS: pop h ; 'hl' has address of msg mov c,m ; get char call conout ; send to comsole mov a,m cpi lf cz wait ; wait 10 ms after lf for slow terminals  ; shld brst+1 BRST: CALL 0 ; call get hd$info pop d ; get table address back push h ; save address of HD$ALV$AVAIL shld hdavl+1 ; save bios address in boot loader lxi b,12 ; bytes to move into table dw 0b0edh ; z80 ldir pop h ; get location of HD$ALV$AVAIL back push d ; save table address lxi d,4 ; dad d ; 'hl' points to address of byte, burst mov a,m inx h mov h,m mov l,a ; address of byte,burst mode byte mov a,m ; get current value, 0 or 1 pop d stinx h ; next byte mov a,m ; ana a ; see if end=0 jnz puts+1 ; nope pchl ; hl has return address ; WAIT: mvi b,4 lxi d,0 WAIT1: inx d mov a,e cmp d jnz wait1 dcr b rz jmp wait1 ; ; scsi command block ; SCSICMD db sread ; db 0 ; high address db 0 ; middle address LOWADDR db 0 ; low address db 1 ; number of sectors=1 db 0 ; reserved ;***********************Save area************************** ; OLDSTK: ds 2 ; storage for old stack pointer ; BJ$TBL: ; taax d ; save value shld ctlbyt+1 ; save bios address in boot loader ; ; we have all the information from the users bios in the patch area ; read to overlay the first sector and write back to disk. ; lxi h,btsec ; clean the boot sector lxi b,128 CLEAN: xra a mov m,a inx h dcx b mov a,b ora c jnz clean ; ; overlay the new boot loader on the boot sector ; lxi h,patch$start ; begining of new boot loader lxi d,btsec ; location of boot sector in ram lxi b,size$patch ; number of pble of bios jumps CBOOT ds 3 ; cold boot address ds 3 ; warm boot CONST: ds 3 ; console status CONIN: ds 3 ; console character in CONOUT: ds 3 ; console character out ds 3 ; list char out ds 3 ; punch char out ds 3 ; reader char in ds 3 ; home SELDSK: ds 3 ; select disk SETTRK: ds 3 ; set track number SETSEC: ds 3 ; set sector number ds 3 ; set dma address ds 3 ; read disk ds 3 ; write disk ds 3 ; return list status ds 3 ; sector translate GETTBL: ds 3 ; point tatch bytes dw 0b0edh ; z80 ldir, movit ; ; now write it back to hard disk ; mvi a,swrite ; scsi write sta scsicmd mvi a,1 ; target address lxi h,scsicmd ; the scsi command lxi d,btsec ; data area call scsi ; do the write jnz scsierr ; if error ; ; boot sector written, now do users swap and disk information ; mvi a,swrite ; scsi write sta scsicmd mvi a,31 ; sector 31 sta lowaddr ; lxi h,scsicmd lxi d,user$tab ; users bios information mvi a,1 call scsi ; do the wo next jmp table ds 3 ; getedsk, pointer to 'e' disk prameters ds 3 ; ioinit SCSI: ds 3 ; scsi direct driver ; ds 32 ; 32 byte stack area STACK: EQU $ ; BTSEC: DS 512 ; USER$TAB: UDPBASE: DS 256 ; users dpbase UPHYTAB: DS 64 ; users phytab UHDDPB: DS 176 ; users hd dpb's UHDAVAL: DS 12 ; users hd$alv$avail values BYTEBLK: DS 1 ; scsi controller byte, block value TBL$SIZE: EQU $-user$tab END rite jnz scsierr call puts db cr,lf,'Done! You may now boot from hard disk.',cr,lf,lf,0 jmp exit ; ; show any scsi error that may have occured ; SCSIERR: ldax d ; 'de' has address of sense info push psw ; save it ani 0f0h rar ; convert upper nibble to ascii rar rar rar cpi 10 ; alpha or numeric jc num0 adi '7' ; alpha offset (A thru F) jmp num0+1 ; NUM0: adi '0' ; numeric offset (0 thru 9) sta errtyp ; ; do second digit ; pop psw ani 0fh cpi 10 jc nu  Filename.Typ Size Recs CRC 1 -A60103 .E 0K 0 0000 2 BIOS-1-6.ASM 48K 377 5DDE 3 BIOS-3-7.ASM 102K 815 9CAE 4 CRC .CRC 0K 0 0000 5 DIR .COM 2K 16 BE35 6 HF-1-5 .ASM 52K 410 E18F 7 HG-1-2 .ASM 14K 108 F63F 8 HI-1-2 .ASM 54K 419 FDF6 9 HP-1-2 .ASM 48K 372 B83A 10 SBT-1-2 .ASM 28K 209 8ABE requirement to 3.7 for Seagate support. ; ; 1.4 E7.18 RJB Added DTC format, changed minimum bios ; requirement to 3.1 for Shugart support. ; ; 1.3 E6.27 RJB Changed to support bios 3.0 to allow the ; user to manually enter the drive descriptor. ; ; 1.2 E3.14 RJB Modified signon message to include known ; rom revision limitations. ; ; E3.13 RJB Updated XEBEC and ADAPTEC step routines. ; ; 1.1 E2.14 RJB Added message reminding users to run the ; FINDBAD program to find any bad sectors ; on the disk they just formatted. ; ; E2.12 RJB Added message for those don't have any ; hard disk units defined and run the hard ; disk format program anyway. ; ; E1.30 RJB Fixed Xebec directory clear, Adaptec step, ; device select. Added additional user ; interface, error reporting routines. ; ; 1.0 DC.14 RLD Original version. ; ; Program version, and current version date VERS EQU 15 ; Current version THIS$MONTH EQU 4 ; Today's month THIS$DAY EQU 02 ; .  day THIS$YEAR EQU 86 ; . year INT$REV EQU 99 ; Internal revision number ; TRUE and FALSE are defined here NO EQU 0 FALSE EQU 0 YES EQU NOT FALSE TRUE EQU NOT FALSE ; Operating characteristics MIN$VERSION EQU 37 ; Minimum bios version allowed CMD$LINE$OK EQU FALSE ; Allow command line input? RTN$VIA$WB EQU TRUE ; Return to CP/M via warm boot? INTERNAL EQU FALSE ; Internal (unreleased) revision? ; Include diagnostic messages? TEST EQU NO ; TEST diagnostics?  ; Current screen width and output buffer width SWIDTH EQU 80 ; Screen width PWIDTH EQU 132 ; Output buffer width ; Z-80 opcode equates (reversed so we can use a DW to enter them) CPIR80 EQU 0B1EDH ; CPIR INIR80 EQU 0B2EDH ; INIR LDIR80 EQU 0B0EDH ; LDIR OTIR80 EQU 0B3EDH ; OTIR INI80 EQU 0A2EDH ; INI OUTI80 EQU 0A3EDH ; OUTI SBCD80 EQU 043EDH ; LD (dddd),BC LBCD80 EQU 04BEDH ; LD BC,(dddd) SDED80 EQU 053EDH ; LD (dddd),DE LDED80 EQU 05BEDH ; LD DE,(dddd * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Hard Disk Format Utility * * Copyright (C) 1985, 1986 AMPRO COMPUTERS, INC. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; Assemble with asm.com or equivalent. ; All Z80 opcodes are defined with DB or DW statements. ; Revision history: ; ; Ver Date Who Description ; --- ----- --- ------------------------------------------ ; 1.5 F4.02 RJB Added Seagate 225N. Changed minimum bios ; ) SSPD80 EQU 073EDH ; LD (dddd),SP LSPD80 EQU 07BEDH ; LD SP,(dddd) LXIX EQU 021DDH ; LXI IX,dddd SIXD80 EQU 022DDH ; LD (dddd),IX LIXD80 EQU 02ADDH ; LD IX,(dddd) POPIX EQU 0E1DDH ; POP IX PUSHIX EQU 0E5DDH ; PUSH IX LXIY EQU 021DDH ; LXI IY,dddd SIYD80 EQU 022FDH ; LD (dddd),IY LIYD80 EQU 02AFDH ; LD IY,(dddd) POPIY EQU 0E1FDH ; POP IY PUSHIY EQU 0E5FDH ; PUSH IY ; Bit SET/RESET/TEST Z-80 opcode equates (use DB to enter) ; Example: SET 7,D would be DB BIT,BSET +B7+ZD BIT EQU 0CBH ; Bit prefix BTST EQU 040H ; Bit test BRES EQU 080H ; Bit reset BSET EQU 0C0H ; Bit set B0 EQU 000H ; Bit 0 B1 EQU 008H ; Bit 1 B2 EQU 010H ; Bit 2 B3 EQU 018H ; Bit 3 B4 EQU 020H ; Bit 4 B5 EQU 028H ; Bit 5 B6 EQU 030H ; Bit 6 B7 EQU 038H ; Bit 7 ZB EQU 000H ; B Reg ZC EQU 001H ; C Reg ZD EQU 002H ; D Reg ZE EQU 003H ; E Reg ZH EQU 004H ; H Reg ZL EQU 005H ; L Reg ZM EQU 006H ; M Reg ZA EQU 007H ; A Reg ; Jump relatiDB 'You will be asked for the controller ' DB 'type, controller SCSI address, drive unit number, ' DB 'and the drive descriptor information.' DB CR,LF,LF,'$' WARNING$MSG: DB 'CAUTION: ALL DATA WILL BE ERASED ON THE DRIVE YOU ' DB 'SELECT TO FORMAT.',CR,LF,LF,LF DB '$' ; ; Initialize the command line input pointer. ; START: IF CMD$LINE$OK ; If we want to allow cmd line input, LXI H,0080H ; . Save the command line. LXI D,INBUF ; . . LXI B,128 ; . . DW LDIR80 ; . . LXIve opcode equates (use DB to enter) ; Example: JR AGAIN would be DB JR,AGAIN-$-1 JR EQU 018H ; JR addr JRNZ EQU 020H ; JR NZ,addr JRZ EQU 028H ; JR Z,addr JRNC EQU 030H ; JR NC,addr JRC EQU 038H ; JR C,addr ; IX and IY prefixes (use DB to enter) IX EQU 0DDH ; IX prefix IY EQU 0FDH ; IY prefix ; Character equates CTRLC EQU 'C'-'@' ; Ctrl-C (ETX) BS EQU 'H'-'@' ; Ctrl-H (Backspace) TAB EQU 'I'-'@' ; Ctrl-I (Tab) LF EQU 'J'-'@' ; Ctrl-J (Line feed) FF EQU 'L'-' H,INBUF ; . Set up ptrs and count of chrs MOV A,M ; . . STA CMD$LINE$CHRS ; . Save count of characters, INX H ; . Bump line ptr, SHLD CMD$LINE$PTR ; . . and save ptr to cmd line ENDIF IF NOT CMD$LINE$OK ; If no command line input allowed, MVI A,0 ; . Clear the count of characters, STA CMD$LINE$CHRS ; . . LXI H,0 ; . but set the ptr up anyway. SHLD CMD$LINE$PTR ; . . ENDIF IF NOT RTN$VIA$WB ; If we're returning without warm boot, LXI H,0000H ; . then get the old @' ; Ctrl-L (Form feed) CR EQU 'M'-'@' ; Ctrl-M (Carriage return) NAK EQU 'U'-'@' ; Ctrl-U CAN EQU 'X'-'@' ; Ctrl-X (Cancel) EOF EQU 'Z'-'@' ; Ctrl-Z (CP/M End-of-file) ESC EQU 1BH ; Ctrl-[ (Escape) EOS EQU '$' ; (CP/M End-of-string) DEL EQU 7FH ; (Delete) ; bdos equates BDOS EQU 5 ; bdos entry ; * * * * * * * * ; ; The code starts here ... ; ; * * * * * * * * ORG 0100H JMP START SCREEN$WIDTH: DB SWIDTH-1 ; 1 less than actual # SLOW$TERM: DB 10 ; Delastack ptr, DAD SP ; . and SHLD STACK ; . save it for later, ENDIF ; ; This is where you can jump to start the program over. ; TOP$MENU: LXI SP,STACK ; Stuff SP with our stack. CALL GET$BIOS$VERS ; Copy the jmp tbl to a local area ; ; Display the name and signon message ; IF CMD$LINE$OK ; If cmd line input is possible LDA CMD$LINE$CHRS ; Check for any input and skip ORA A ; . the initial messages if any JNZ CHECK$B$VERS ; . chrs in the cmd line. ENDIF CALL CLEARy (ms) for slow term CMD$LINE$CHRS: DB 0 ; # of cmd line chrs left CMD$LINE$PTR: DW 0 ; Ptr to next cmd line chr NAME$MSG: DB 0DH,'AMPRO ' NAME: DB 'Hard Disk Format' DB ' Utility',CR,LF DB 'Copyright (C) 1985 AMPRO Computers, Inc.',CR,LF DB 'Version ',VERS/10+'0','.',VERS MOD 10+'0' IF INTERNAL ; Display internal revision number? DB 'x',INT$REV/10+'0',INT$REV MOD 10+'0' DB ' [',THIS$YEAR-80+'@' DB THIS$MONTH+'0'+((THIS$MONTH/10)*7) DB '.',THIS$DAY/10+'0',THIS$DAY MOD 10+'0',']'$SCREEN ; Clear the screen LXI D,NAME$MSG ; Display the name, version, etc. CALL CENTER$OUTPUT ; . LXI D,SIGNON$MSG ; and the initial message CALL JUSTIFY ; . ; ; Check the version of the bios against the minimum version allowed. ; If the bios is not at least the minimum, display an error message ; and exit to the operating system. ; CHECK$B$VERS: LDA BIOS$VERSION ; Get bios version # CPI MIN$VERSION ; Check against minimum version JNC WHICH$BIOS ; At least minimum version . . . L ENDIF DB CR,LF,LF,'$',CR HELP$MSG: DB 'Usage: HFORMAT' DB CR,LF,'$',CR,' ',EOF SIGNON$MSG: DB 'The AMPRO Hard Disk Format utility is used to ' DB 'format hard disk (winchester) drives, on the ' DB 'Adaptec ACB-4000, ' DB 'Data Technology 500 Series ' DB '(510A, 510B, 520A, 520B), ' DB 'Shugart 1610-4, ' DB 'Xebec 1410 (rom rev "E" or later), ' DB 'Xebec 1410A (rom rev "D" or later) ' DB 'controllers, or the ' DB 'Xebec Owl or Seagate 225N combination drive/controllers. ' XI D,BIOS$PLUS ; Not minimum, display error message CALL JUSTIFY ; . JMP LB$WBOOT ; and exit. BIOS$PLUS: DB 'This program requires AMPRO bios version ' VERSION$REQ: DB MIN$VERSION/10,'.',MIN$VERSION MOD 10,' or later.' DB CR,LF,'$' ; ; Perform any initialization particular to each version of the Ampro ; bios, if necessary. ; WHICH$BIOS: CALL RET$TO$CONT JZ ALL$DONE ; ; Program main loop . . . ; AGAIN: CALL CLEAR$SCREEN ; Clear the screen LXI D,SCSI$ADDR$MSG ; Promp t for SCSI address LXI H,SCSI$ADDR$OKC ; . CALL PROMPT ; . [ 0 1 2 3 4 5 6 7 ] JZ TOP$MENU ; . MOV A,B ; . DCR A ; . CALL BIN$TO$SCSI ; . STA SCSI$ADDR ; . CALL A$TO$HL$HEX ; . SHLD S$ADDR$CODE ; . LXI D,HDC$TYPE$MSG ; Prompt for controller type LXI H,HDC$TYPE$OKC ; . CALL PROMPT ; . [ 1 2 3 4 ] JZ AGAIN ; . MOV A,B ; . DCR A ; . STA HDC$TYPE ; . MVI A,0 ; Set logical unit to 0 for SCSI drives STA DRV$LUN ; . LDA HDC$TYPE ; If Xebec OWL or Seagate 225n  done CPI 'N' ; If yes or CR, play it again, sam, JNZ AGAIN ; . otherwise fall into ALL$DONE ; ; Restore the old stack pointer and exit the program. ; ALL$DONE: JMP LB$WBOOT ; Return via warm boot SCSI$ADDR$MSG: DB 'What is the SCSI address of your ' DB 'controller (0-7)? ','$' SCSI$ADDR$OKC: DB '01234567',0 HDC$TYPE$MSG: DB CR,LF,'Which type of controller are you using:' DB CR,LF,TAB,'1 - Adaptec ACB 4000' DB CR,LF,TAB,'2 - Shugart 1610-4' DB CR,LF,TAB,'3 - XebecCPI XEBEC$OWL ; . skip the drive characteristics JZ SCSI$DRIVE ; . as these SCSI drives already CPI SEAGATE$225N ; . "know" what their characteristics JZ SCSI$DRIVE ; . are. LXI D,DRV$LUN$MSG ; Prompt for drive logical unit # LXI H,DRV$LUN$OKC ; . CALL PROMPT ; . [ 0 1 2 3 ] JZ AGAIN ; . MOV A,B ; . DCR A ; . RRC ; Shift response into high bits RRC ; . RRC ; . ANI 0E0H ; . STA DRV$LUN ; . LXI D,DRV$INFO$MSG ; Ask for drive characteristics CALL JUSTIFY ; . OWL (drive/controller)' DB CR,LF,TAB,'4 - Xebec 1410, 1410A' DB CR,LF,TAB,'5 - Seagate 225N (drive/controller)' DB CR,LF,TAB,'6 - Data Technology 500 Series' DB CR,LF,LF DB 'Choose one (1-6): ','$' HDC$TYPE$OKC: DB '123456',0 ADAPTEC: EQU 0 SHUGART: EQU 1 XEBEC$OWL: EQU 2 XEBEC$1410: EQU 3 SEAGATE$225N: EQU 4 DTC$500: EQU 5 DRV$LUN$MSG: DB CR,LF DB 'Which drive on the controller do you want ' DB 'to format (0-3)? ','$' DRV$LUN$OKC: DB '0123',0 DRV$INFO$MSG: DB CR, LXI D,DRV$CYLS$MSG ; . (Cylinders) CALL PROMPT$DECIMAL ; . JZ AGAIN ; . LXI H,DRV$CYLS ; . MOV M,D ; . INX H ; . MOV M,E ; . LXI D,DRV$HEAD$MSG ; . (Heads) CALL PROMPT$DECIMAL ; . JZ AGAIN ; . STA DRV$HEAD ; . LXI D,DRV$RWC$MSG ; . (RWC) CALL PROMPT$DECIMAL ; . JZ AGAIN ; . LXI H,DRV$RWC ; . MOV M,D ; . INX H ; . MOV M,E ; . LXI D,DRV$WPC$MSG ; . (WPC) CALL PROMPT$DECIMAL ; . JZ AGAIN ; . LXI H,DRV$WPC ; . MOV M,D ; . INX H ; . MOV M,E ; . LF DB 'Please enter the characteristics of the ' DB 'drive you wish to format:',CR,LF,'$' DRV$CYLS$MSG: DB ' Number of cylinders: ','$' DRV$HEAD$MSG: DB ' Number of heads: ','$' DRV$RWC$MSG: DB 'Starting cylinder for RWC: ','$' DRV$WPC$MSG: DB 'Starting cylinder for WPC: ','$' DRV$LZ$MSG: DB ' Landing zone cylinder: ','$' ADP$STEP$MSG: DB CR,LF,LF DB 'Adaptec step mode (choose from the ' DB 'following table):',CR,LF DB TAB,'0 - 3ms step',CR,LF DB TAB,'1 - 28us LDA HDC$TYPE ; . CPI SHUGART ; . JNZ NOT$SHUGART ; . LXI D,DRV$LZ$MSG ; . (Landing zone) CALL PROMPT$DECIMAL ; . JZ AGAIN ; . LXI H,DRV$LZ ; . MOV M,D ; . INX H ; . MOV M,E ; . NOT$SHUGART: CALL GET$STEP ; Get step rate table for this HDC CALL PROMPT ; Get step rate factor JZ AGAIN ; . MOV A,B ; . DCR A ; . STA STEP$RATE ; . SCSI$DRIVE: LXI D,INTL$MSG ; Prompt for interleave factor LXI H,INTL$OKC ; . CALL PROMPT ; . [ 1 2 3 4 5 6 7 8 9 ] STA INTL$EC buffered step',CR,LF DB TAB,'2 - 12us buffered step',CR,LF DB 'Which step mode (0, 1, or 2)? ','$' ADP$STEP$OKC: DB '012',0 DTC$STEP$MSG: DB CR,LF,LF DB 'Data Technology step mode (choose ' DB 'from the following table):',CR,LF DB TAB,'0 - 3ms step',CR,LF DB TAB,'1 - 200us buffered step',CR,LF DB TAB,'2 - 150us buffered step',CR,LF DB TAB,'3 - 100us buffered step',CR,LF DB TAB,'4 - 50us buffered step',CR,LF DB 'Which step mode (0, 1, 2, 3, or 4)? ','$' DTC$STEP$OKC: DHO ; . MOV A,B ; . STA INTERLEAVE ; . (& save the interleave) JZ AGAIN ; . if , back to main loop LXI D,RTF$MSG ; Prompt for return key, to LXI H,RTF$OKC ; . main menu, exits CALL PROMPT ; . [ ESC CR ] JZ AGAIN ; . if , back to main loop CALL HD$FORMAT ; Do the format routine LXI D,AGAIN$MSG ; Display successful msg & prompt LXI H,AGAIN$OKC ; . for another drive to format. CALL PROMPT ; . [ ESC N Y CR ] JZ ALL$DONE ; . if , allB '01234',0 SHU$STEP$MSG: DB CR,LF,LF DB 'Shugart step mode (choose from the ' DB 'following table):',CR,LF DB TAB,'0 - 3ms step',CR,LF DB TAB,'1 - 1ms step',CR,LF DB TAB,'2 - 200us buffered step',CR,LF DB TAB,'3 - 70us buffered step',CR,LF DB TAB,'4 - 50us buffered step',CR,LF DB 'Which step mode (0, 1, 2, 3, or 4)? ','$' SHU$STEP$OKC: DB '012345',0 XEB$STEP$MSG: DB CR,LF,LF DB 'Xebec step mode (choose from the ' DB 'following table):',CR,LF DB TAB,'0 - 3ms s tep',CR,LF DB TAB,'4 - 200us buffered step',CR,LF DB TAB,'5 - 70us buffered step',CR,LF DB TAB,'6 - 30us buffered step',CR,LF DB TAB,'7 - 15us buffered step',CR,LF DB 'Which step mode (0, 4, 5, 6, or 7)? ','$' XEB$STEP$OKC: DB '04567',0 INTL$MSG: DB CR,LF,'What sector interleave factor ' DB '(1-9, usually 2)? ','$' INTL$OKC: DB '123456789',0 SCSI$ADDR: DB 01H HDC$TYPE: DB 0 DRV$LUN: DB 0 DRV$CYLS: DW 0 ; Keep these four items in order DRV$HEAD: DB 0 ; . (cyls, head, rwc, ck" by DB 0EDH,0B0H ; . "track". LDA HDC$TYPE ; Get controller type LXI H,H$FMT$EXE ; & table starting address JMP GO$TABLE ; Jump to controller routine H$FMT$EXE: DW H$DO$ADAPTEC ; Adaptec 4000 DW H$DO$SHUGART ; Shugart 1610-4 DW H$DO$OWL ; Xebec Owl DW H$DO$XEBEC ; Xebec 1410 rev e, 1410A rev d DW H$DO$SEAGATE ; Seagate 225N DW H$DO$DTC ; Data Technology 500 Series H$DO$UNKNOWN: LXI D,NEW$CTRL ; Print error message for an unknown CALL JUSTIFY ; . controller type MVI A,0wpc) DRV$RWC: DW 0 ; . DRV$WPC: DW 0 ; . DRV$LZ: DW 0 STEP$RATE: DB 0 INTERLEAVE: DB 2 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Hard disk display & format routines . . . * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * GET$STEP: LDA HDC$TYPE ; Get controller type LXI H,H$STEP$EXE ; & step table starting addr JMP GO$TABLE ; Jump to controller routine H$STEP$EXE: DW H$STEP$ADP ; Adaptec ACB 4000 DW H$STEP$SHU ; Shugart 1610-4 FFH ; Set error status JMP H$FMT$DONE ; . H$DO$ADAPTEC: LXI D,FMT$START$MSG ; Show the user we're going ... CALL JUSTIFY ; . LXI D,A$MD ; Where to put the fmt data LXI H,DRV$CYLS ; . LXI B,7 ; . DB 0EDH,0B0H ; . (LDIR) LDA STEP$RATE ; Get step rate STA A$STEP ; Save step rate XRA A ; Set stop position to beyond the STA A$LZ ; last track LDA INTERLEAVE ; Set interleave STA A$INTL ; . LXI H,A$MSC ; Mode Select LXI D,A$MSD ; . CALL DO$SCSI ; . JNZ FMT$ERDW H$STEP$XEB ; Xebec Owl DW H$STEP$XEB ; Xebec 1410, 1410A DW H$STEP$ADP ; Seagate 225N DW H$STEP$DTC ; Data Technology 500 Series H$STEP$ADP: LXI D,ADP$STEP$MSG LXI H,ADP$STEP$OKC RET H$STEP$DTC: LXI D,DTC$STEP$MSG LXI H,DTC$STEP$OKC RET H$STEP$SHU: LXI D,SHU$STEP$MSG LXI H,SHU$STEP$OKC RET H$STEP$XEB: LXI D,XEB$STEP$MSG LXI H,XEB$STEP$OKC RET DO$SCSI: ; ; Entry: ; HL = Command string ; DE = Data string ; SCSI address in SCSI$ADDR ; Drive logical unit iROR ; . LXI H,A$FC ; Format unit LXI D,A$FC ; . (no data required) CALL DO$SCSI ; . JNZ FMT$ERROR ; . ; CALL H$DIR$CLEAN ; Clean directory area (not needed) ; JNZ FMT$ERROR ; . JMP H$FMT$DONE ; and jump to the end routine A$MSC: DB 15H,0,0 ; Mode select DB 0,16H,0 ; . A$MSD: DB 0,0,0,8 ; Mode select data DB 0,0,0,0,0 ; . DB 0,2 ; . (block size = 512 bytes) DB 0 ; . DB 1 ; . A$MD: DB 0,0,0,0,0,0,0 ; . (format data from bios) A$LZ: DB 0 ; . (landing zone position) A$n DRV$LUN ; ; Exit: ; HL = unchanged ; DE = unchanged if no error, else ptr to error data ; A = SCSI error code (0 = no error) ; INX H ; Point to drive unit LDA DRV$LUN ; 'OR' it in ORA M ; . MOV M,A ; . DCX H ; Set HL back LDA SCSI$ADDR ; Get SCSI address CALL LB$SCSIDRV ; Call SCSI driver, ORA A ; set status, RET ; and return. HD$FORMAT: ; ; [E6.07] ; ; Format a hard disk unit. ; ; Entry: ; Drive format information in the following locations: ; ; SCSI addressSTEP: DB 0 ; . (adaptec step rate) A$FC: DB 04H ; Format unit DB 06H ; . (use next byte for fill) DB 0E5H ; . (fill byte) DB 00 ; . A$INTL: DB 00 ; . (interleave) DB 00 ; . H$DO$DTC: LXI D,FMT$START$MSG ; Show the user we're going ... CALL JUSTIFY ; . LHLD DRV$CYLS ; Move the data to the proper area SHLD D$CYL ; . LDA DRV$RWC+1 ; . STA D$RWC ; . LDA DRV$HEAD ; . DCR A ; . STA D$HD ; . LDA STEP$RATE ; Get step rate MOV E,A ; Translate from table M of controller SCSI$ADDR ; Hard disk controller type HDC$TYPE ; Disk drive logical unit # DRV$LUN ; Interleave factor INTERLEAVE ; ; Exit: ; designated disk unit is formatted ; ; Modifies: ; all ; LXI D,E5BUF ; Fill first 256 bytes of buffer LXI B,00E5H ; . with 0E5H, used to clear unit CALL FILL$BLOCK ; . if HDC doesn't clear by itself. LXI H,E5BUF ; Fill next 8K with 0E5H. When the LXI D,E5BUF+256 ; . HD$DIR$CLEAN routine is run, the LXI B,8192-256 ; . unit will be cleared "traVI D,0 ; . LXI H,D$TRAN$TBL ; . DAD D ; . MOV A,M ; . STA D$STPR ; . LDA INTERLEAVE ; Set interleave STA D$INTL ; . LXI H,D$MSC ; Mode Select LXI D,D$MSD ; . CALL DO$SCSI ; . JNZ FMT$ERROR ; . LXI H,D$FC ; Format unit LXI D,D$FC ; . (no data required) CALL DO$SCSI ; . JNZ FMT$ERROR ; . ; CALL H$DIR$CLEAN ; Clean directory area ; JNZ FMT$ERROR ; . JMP H$FMT$DONE ; and jump to the end routine D$TRAN$TBL: DB 60 ; 3ms DB 4 ; 200us DB 3 ; 150us DB  2 ; 100us DB 1 ; 50us D$MSC: DB 0C2H,0,0 ; Mode select DB 0,0,0 ; . D$MSD: DB 11 ; Mode select data D$STPR: DB 0 ; . (Step rate) DB 0 ; . (Step mode) D$HD: DB 0 ; . (# of heads) D$CYL: DB 0,0 ; . (# of cylinders) D$RWC: DB 0 ; . (RWC starting cylinder) DB 0,0 D$FC: DB 04H ; Format unit DB 0 ; . DB 0 ; . DB 0 ; . D$INTL: DB 0 ; . (interleave) DB 0 ; . H$DO$SHUGART: LXI D,FMT$START$MSG ; Show the user we're going ... CALL JUSTIFY ; . LHLD DRV$CYLS ; Mo LXI D,E5BUF ; . CALL DO$SCSI ; . JNZ FMT$ERROR ; . LXI H,X$FC ; Format unit LXI D,X$FC ; . (no data required) CALL DO$SCSI ; . JNZ FMT$ERROR ; . ; CALL H$DIR$CLEAN ; Clean directory area (not needed) ; JNZ FMT$ERROR ; . JMP H$FMT$DONE ; and jump to the end routine X$IC: DB 0CH ; Init Drive Characteristics DB 0,0,0,0,0 ; . X$ID: DB 0,0,0,0,0,0,0,0 ; Init Drive data X$WBC: DB 0FH ; Write sector buffer DB 0,0,0,0,0 ; . X$FC: DB 04H ; Format unit DB 0,0,0 ; . X$INve the data to the proper area SHLD S$CYL ; . LHLD DRV$LZ ; . SHLD S$LZ ; . LHLD DRV$RWC ; . SHLD S$RWC ; . LHLD DRV$WPC ; . SHLD S$WPC ; . LDA DRV$HEAD ; . STA S$HD ; . LDA STEP$RATE ; Get step rate MOV E,A ; Translate from table MVI D,0 ; . LXI H,S$TRAN$TBL ; . DAD D ; . DAD D ; . MOV A,M ; . STA S$STPR ; . INX H ; . MOV A,M ; . STA S$STPR+1 ; . LDA INTERLEAVE ; Set interleave STA S$INTL ; . LXI H,S$MSC ; Mode Select LXI D,S$TL: DB 0 ; . X$STEP: DB 0 ; . H$DO$SEAGATE: LXI D,FMT$START$MSG ; Show the user we're going ... CALL JUSTIFY ; . LDA INTERLEAVE ; Set interleave STA SEA$INTL ; . LXI H,SEA$RSD ; Read sense data LXI D,SEA$RSD ; . (to clear reset error) CALL DO$SCSI ; JNZ FMT$ERROR ; LXI H,SEA$FC ; Format unit LXI D,SEA$FC ; . (no data required) CALL DO$SCSI ; . JNZ FMT$ERROR ; . CALL H$DIR$CLEAN ; Clean directory area JNZ FMT$ERROR ; . JMP H$FMT$DONE ; and jump to the end routinMSD ; . CALL DO$SCSI ; . JNZ FMT$ERROR ; . LXI H,S$FC ; Format unit LXI D,S$FC ; . (no data required) CALL DO$SCSI ; . JNZ FMT$ERROR ; . CALL H$DIR$CLEAN ; Clean directory area JNZ FMT$ERROR ; . JMP H$FMT$DONE ; and jump to the end routine S$TRAN$TBL: DB 4,3 ; 3ms DB 4,1 ; 1ms DB 0,200 ; 200us DB 0,70 ; 70us DB 0,50 ; 50us S$MSC: DB 15H,0,0 ; Mode select DB 0,20H,0 ; . S$MSD: DB 0,0,0,8 ; Mode select data DB 0,0,0,0,0 ; . DB 0,2,0 ; . (Block size = e SEA$RSD: DB 03H ; Read sense data DB 0,0,0,0,0 ; SEA$FC: DB 04H ; Format unit DB 00H ; . DB 00H ; . DB 00 ; . SEA$INTL: DB 00 ; . (interleave) DB 00 ; . H$DIR$CLEAN: ; ; This routine clears the drive by reading the capacity of the unit ; and writing sectors filled with 0E5H. This clears all directory ; areas on the unit, no matter what partitioning is provided. This ; clearing is done 'track by track' by sending the data in 8Kb ; blocks. ; LXI D,CLR$DIR$MSG ; Te512 bytes) DB 80H,0 ; . S$HD: DB 0 ; . (# of heads) S$SPW: DB 16 ; . (Step pulse width = 16us) S$STPR: DB 0,0 ; . (Step rate) S$CYL: DB 0,0 ; . (# of cylinders) S$RWC: DB 0,0 ; . (RWC starting cylinder) S$WPC: DB 0,0 ; . (WPC starting cylinder) S$LZ: DB 0,0 ; . (Landing zone cylinder) DB 0,0,0,0,0,0 ; . S$FC: DB 04H ; Format unit DB 0 ; . DB 0 ; . DB 0 ; . S$INTL: DB 0 ; . (interleave) DB 0 ; . H$DO$OWL: MVI A,7 ; Set step rate to '7' for OWL STA STEP$RATE ; (all 'em we're clearing his drive CALL JUSTIFY ; . LXI H,RD$CAP$CMD ; Read the capacity of the drive LXI D,RD$CAP$DATA ; . CALL DO$SCSI ; . RNZ ; Return with status if error ; Convert from blocks to tracks by multiplying HL and ; A by 16 and throwing away the low 8 bits (which is ; the same as dividing by 16, only this is easier). ; HL reg pair C A reg ORA A ; ---------------- - -------- LDA RD$CAP$DATA+1 ; ---------------- - -------- MOV H,A ; xxxxFEDC-------- - -nd fall through to H$DO$XEBEC ... H$DO$XEBEC: LXI D,FMT$START$MSG ; Show the user we're going ... CALL JUSTIFY ; . LXI D,X$ID ; Where to put the fmt data LXI H,DRV$CYLS ; . LXI B,7 ; . DB 0EDH,0B0H ; . (LDIR) LDA STEP$RATE ; Get step rate ORI 20H ; . (set sector buffer bit) STA X$STEP ; . LDA INTERLEAVE ; Set interleave STA X$INTL ; . LXI H,X$IC ; Init Drive Characteristics LXI D,X$ID ; . CALL DO$SCSI ; . JNZ FMT$ERROR ; . LXI H,X$WBC ; Write Sector Buffer ------- LDA RD$CAP$DATA+2 ; xxxxFEDC-------- - -------- MOV L,A ; xxxxFEDCBA987654 - -------- LDA RD$CAP$DATA+3 ; xxxxFEDCBA987654 - 3210xxxx ADD A ; xxxxFEDCBA987654 3 210xxxx- DB 0EDH,06AH ; xxxFEDCBA9876543 - 210xxxx- ADD A ; xxxFEDCBA9876543 2 10xxxx-- DB 0EDH,06AH ; xxFEDCBA98765432 - 10xxxx-- ADD A ; xxFEDCBA98765432 1 0xxxx--- DB 0EDH,06AH ; xFEDCBA987654321 - 0xxxx--- ADD A ; xFEDCBA987654321 0 xxxx---- DB 0EDH,06AH ; FEDCBA9876543210 - xxxx---- ; HL now contains the n umber of 'tracks' CLR$NEXT$TRACK: DCX H ; Decrement the track count SHLD CUR$TRACK ; Save current track XRA A ; Convert back to 20-bit ; A reg C HL reg pair ; -------- - FEDCBA9876543210 DAD H ; -------- F EDCBA9876543210- RAL ; -------F - EDCBA9876543210- DAD H ; -------F E DCBA9876543210-- RAL ; ------FE - DCBA9876543210-- DAD H ; ------FE D CBA9876543210--- RAL ; -----FED - CBA9876543210--- DAD H ; -----FED C BA9876543210---- RAL ; -re the converted number) ; ; Modifies: none ; PUSH PSW ; Save original number RRC ; Get high nybble RRC ; . RRC ; . RRC ; . ANI 0FH ; . CALL A$TO$HEX ; Convert to hex MOV L,A ; Save in L register POP PSW ; Get original number back PUSH PSW ; Save again for later ANI 0FH ; Get low nybble CALL A$TO$HEX ; Convert to hex MOV H,A ; Save in H register POP PSW ; Get original number back RET ; and return A$TO$HEX: ; Convert A to a hex digit CPI 0AH ; If 0-9---FEDC - BA9876543210---- XCHG ; Save block # in write command LXI H,WRITE$BLK$CMD ; . INX H ; . MOV M,A ; Move high byte INX H ; . MOV M,D ; Move middle byte INX H ; . MOV M,E ; Move low byte LXI H,WRITE$BLK$CMD ; Write 8K block to disk at this blk LXI D,E5BUF ; . CALL DO$SCSI ; . RNZ ; Return with status if error LHLD CUR$TRACK ; Get track number back MOV A,H ; See if we're done ORA L ; . JNZ CLR$NEXT$TRACK ; Non-zero means more to do . . . XRA A ;, we don't need to JM A$TO$HEX$2 ; . add any offset ADI 07H ; Offset for A-F A$TO$HEX$2: ; . ADI 30H ; ASCII bias RET ; and return BIN$TO$SCSI: ; Converts binary 0-7 to SCSI address ; ; Entry: ; A = number to convert (0-7) ; ; Exit: ; A = converted SCSI address [00H = error] ; ; Modifies: B ; ANI 07H ; Mask out all but addrs 0-7 INR A ; Bump A to shift at least one MOV B,A ; . bit and move to B register XRA A ; Clear A register STC ; Set carry for shift Set A-OK status RET RD$CAP$CMD: DB 025H,0 ; Read capacity command DB 0,0,0,0,0,0,0,0 ; . RD$CAP$DATA: DB 0,0,0,0,0,0,0,0 ; Read capacity data area WRITE$BLK$CMD: DB 00AH,0 ; Write data cmd DB 0,0,16,0 ; . CUR$TRACK: DW 0 ; Current track data FMT$ERROR: LXI D,NO$RESPONSE ; CPI 0FFH ; Timeout error? JZ FMT$TIMEOUT ; Yes, print timeout msg MOV A,M ; No, Get last command CALL A$TO$HL$HEX ; Convert to hex SHLD ERR$CMD ; Save in output line LXI H,FMT$ERR$CMD ; Ge BIN$NEXT$BIT: RAL ; Shift left one bit DCR B ; Decrement count JNZ BIN$NEXT$BIT ; Zero means all done RET CENTER$OUTPUT: ; ; [DC.20] ; ; Automatically centers the output line(s) based on the line width ; stored in SCREEN$WIDTH. Each line is delimited with CR+LF. This ; routine will return to the caller when it encounters the string ; terminator, '$'. Any additional LF characters after a CR+LF pair ; will be passed through. ; ; Entry: ; DE = Pointer to output string(s), termint status from controller LXI D,FMT$ERR$DATA ; . CALL DO$SCSI ; . LDAX D ; Get error code CALL A$TO$HL$HEX ; Convert to hex SHLD ERR$CODE LXI D,FORMAT$ERROR ; Print error message FMT$TIMEOUT: CALL JUSTIFY ; . MVI A,0FFH ; Set error status JMP H$FMT$DONE ; and return FMT$ERR$CMD DB 3,0,0 ; Request sense DB 0,4,0 FMT$ERR$DATA DB 0,0,0,0 ; Sense data H$FMT$DONE: ORA A ; Set status LXI D,FMT$ERR$MSG ; Print "Errors occurred during PUSH PSW ; . formatting" if NOT ZERO Cated with CR+LF. ; ; Exit: ; The output string(s) are sent to the screen ; ; Modifies: DE ; PUSH PSW ; Save registers PUSH B ; . PUSH H ; . CENTER$NEXT$LN: CALL GET$STRLEN ; Get length to next CR or '$' in B MOV A,B ; Check for zero length ORA A ; . JZ NEXT$DELIM ; If so, output the CR, LF, etc. LDA SCREEN$WIDTH ; Compute offset needed to center line STC ; . SBB B ; . (if there are too many chrs, just JC NO$BLANKS ; . print the line as is . . . ) ANI 0FEh ; Clear lNZ JUSTIFY ; POP PSW ; LXI D,FMT$OK$MSG ; Print "Format complete. No CZ JUSTIFY ; . errors" if ZERO RET ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Library routines . . . * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * A$TO$HL$HEX: ; ; [DC.27] ; ; Converts the number in A to the hex digits in HL ; ; Entry: ; A = number to convert ; ; Exit: ; HL = the hex equivalent of the number (L=high, H=low) ; (use shld to stoeast significant bit RRC ; . and rotate to divide by two MVI C,' ' ; Output enough blanks to center line CNZ CON$CHR$AC ; . (only if count is non-zero) NO$BLANKS: MOV A,M ; Save CR for later MVI M,'$' ; Plug position with '$' for cp/m CALL CON$MSG ; . print string function MOV M,A ; Restore saved CR NEXT$DELIM: MOV A,M ; Get character CPI CR ; Print it if CR JZ OUTPUT$DELIM ; . CPI LF ; Print it if LF JZ OUTPUT$DELIM ; . CPI EOS ; Stop processing if EOS ('$') JZ C ENTER$DONE ; . XCHG ; Put new pointer in DE JMP CENTER$NEXT$LN ; Go & do the next line OUTPUT$DELIM: CALL CON$CHR ; Output delimiter CPI LF ; Wait 10ms if we have a line feed CZ WAIT ; . INX H ; Point to next chr JMP NEXT$DELIM ; and check that one, also CENTER$DONE: POP H ; Restore registers POP B ; . POP PSW ; . RET ; and return CLEAR$SCREEN: ; ; [E1.28] ; ; This routine clears the screen by calling DO$CRLF 26 times. ; ; Entry: ; None ; ; Exit: ; The screeup. ; ; Entry: ; none ; ; Exit: ; CR + LF is sent to the screen. ; ; Modifies: ; none ; PUSH PSW ; Save AF MVI A,0Dh ; Send carriage return CALL CON$CHR ; . MVI A,0Ah ; and line feed CALL CON$CHR ; . LDA SLOW$TERM ; Check slow flag ORA A ; . CNZ WAIT ; wait for the s-l-o-w terminals POP PSW ; recover original AF RET ; and return FILL$BLOCK: ; ; [E1.29] ; ; Fills the buffer pointed to by DE with the character in C for ; a length of B bytes (max 256). ; ; Enn is cleared ; ; Modifies: ; None ; PUSH PSW ; Save just in case MVI A,26 ; 26 CRLF's C$NEXT$LINE: CALL DO$CRLF ; Next line DCR A ; Done? JNZ C$NEXT$LINE ; Nope. POP PSW ; Restore original AF RET ; and return CON$CHR: ; ; [DC.20] ; ; This routine sends the character in the "A" register to the console ; through the BDOS conout call. ; ; Entry: ; A = character to send ; ; Exit: ; character is sent to the console ; ; Modifies: ; None ; PUSH PSW PUSH B PUSH Dtry: ; B = Length to fill ; C = Character to fill with ; DE = Start of buffer ; ; Exit: ; Buffer filled ; ; Modifies: ; Only buffer area affected ; PUSH B ; Save registers PUSH D ; . XCHG ; Set up M register use F$NEXT: MOV M,C ; Stuff a char INX H ; Bump pointer DCR B ; Bounce counter JNZ F$NEXT ; Do it again if not done XCHG ; We are done. restore old HL POP D ; Restore other registers POP B ; . RET ; and return GET$BIOS$VERS: ; ; [DC.20] ; ; Get  PUSH H MVI C,2 MOV E,A CALL BDOS POP H POP D POP B POP PSW RET CON$CHR$AC: ; ; [DC.20] ; ; This routine sends the character in the C register to the console ; the number of times in the A register. ; ; Entry: ; A = Number of times to send character ; C = Character to send ; ; Exit: ; Same ; ; Modifies: ; None ; PUSH PSW ; Save all registers PUSH B ; . PUSH D ; . PUSH H ; . MOV B,A ; Move data to accomodate CP/M MOV A,C ; . NEXT$CHR$OUT: CALL CONbios version -- Copies the current BIOS jump tables (starting ; at warm boot) to a local area for ease of utility access. If the ; BIOS is version 2.0 or greater, the secondary jump table is copied ; also. ; ; Entry: ; none ; ; Exit: ; Z = bios 1.0 - 1.4 (floppy only bios) ; NZ = bios 2.0 or greater (floppy & fixed disk bios) ; ; Modifies: All registers ; LHLD 1 ; Get start of bios jump table LXI D,LB$BIOS$TBL ; Move bios to local storage MVI B,LB$LEN ; . (length of bios area) CALL $CHR ; Send 1 chr DCR B ; Decrement counter JNZ NEXT$CHR$OUT ; Done? POP H ; Restore all registers POP D ; . POP B ; . POP PSW ; . RET ; and return CONIN$NE$XC: ; ; [E1.28] ; ; Console input, no echo, exit on ctrl-c ; ; Entry: ; none ; ; Exit: ; A = character from console, except for ctrl-c, which causes ; an immediate jump to ALL$DONE ; ; Modifies: ; A ; CALL LB$CONIN CPI CTRLC JZ ALL$DONE RET CON$MSG: ; ; [DC.20] ; ; Console message ; ; EMOVE$BLOCK ; . (move routine) MVI A,0 ; Test CP/M version CALL LB$GETNXT ; Get next jump table STA BIOS$VERSION ; Save bios version INX H ; See if HL is 0FFFFh MOV A,H ; . ORA L ; . RZ ; If so, then old version DCX H ; Fix HL as it has the table addr LXI D,LB$XTBL ; Move extra table to local storage MVI B,LB$XLEN ; . (length of extra table) CALL MOVE$BLOCK ; . (move routine) MVI A,0FFH ; Set NZ to indicate bios ORA A ; ... version 2.1+ RET ; ... and return. GETntry: ; DE = pointer to message string, terminated with '$' ; ; Exit: ; message printed on console ; ; Modifies: A, BC ; PUSH PSW ; Save registers PUSH B ; . PUSH D ; . PUSH H ; . MVI C,9 ; BDOS print string command CALL BDOS ; . POP H ; Restore registers POP D ; . POP B ; . POP PSW ; . RET ; and return DO$CRLF: ; ; [DC.27] ; ; This routine sends a carriage return and a line feed to the terminal, ; and then waits 'SLOW$TERM' ms for a slow terminal to catch $HL$PTR: ; ; [DC.20] ; ; Gets the pointer pointed to by HL and puts it in HL ; ; Entry: ; HL = pointer to put in HL ; ; Exit: ; HL = pointer ; ; Modifies: none ; PUSH PSW ; Save A register MOV A,M ; Get low byte of pointer INX H ; . MOV H,M ; Get high byte of pointer MOV L,A ; Pointer is now together POP PSW ; Restore A register RET ; and return GET$STRLEN ; Searches the string pointed to by HL and returns the string length ; to the next carriage return. The length  is returned in B. PUSH D ; Save start of string MVI B,0 ; Clear counter TRY$NEXT$CHR: LDAX D ; Get character CPI CR ; Is it CR? JZ EOS$FOUND ; . CPI '$' ; Is it '$'? JZ EOS$FOUND ; . INR B ; No -- increment count and INX D ; . point to the next character JMP TRY$NEXT$CHR ; . EOS$FOUND: POP H ; CR or '$' found, recall orig ptr XCHG ; DE=orginial, HL=current RET ; and return GO$TABLE: ; ; [E2.05] ; ; Jump to a routine based on a table of pointers ; ; Entry:R,LF pairs to separate paragraphs. ; ; NOTE: To insure proper operation, the LF character should only follow ; a CR character or another LF character, as the CR character is used to ; flush the current line without justification. ; ; Two entry points are provided: ; JUSTIFY Justify output, flush right ; JUSTIFY$RAGGED Justify output, ragged right ; ; As of E6.11, the flush right routine was not installed, so either ; entry point will provide the same results. ; ; Entry: ; DE = pointer to lin ; A = index into table ; HL = table base address ; ; Exit: ; Routine at (A*2)+HL is executed ; ; Modifies: ; B, HL ; LXI B,2 ; Compute offset to table of routines CALL INDEX$TABLE ; . CALL GET$HL$PTR ; . PCHL ; Jump to proper routine INDEX$TABLE: ; ; [E1.30] ; ; Computes offset to table given base address, entry length, and entry ; requested. ; ; Entry: ; A = entry # ; BC = table entry length ; HL = base address ; ; Exit: ; HL = address to entry ; ; Modifies: ; A,e(s) to output ; ; Exit: ; The data is sent to the screen. ; ; Modifies: All registers ; MVI A,80H ; Set flush right mode DB JR,E$JUSTIFY-$-1; Jump to routine entry JUSTIFY$RAGGED: MVI A,00H ; Set ragged right mode E$JUSTIFY: STA J$MODE ; Save mode byte MVI A,'$' ; Mark start of buffer STA OUTBUF-1 ; . XCHG ; DE is usually print source J$NEXT$LINE: XRA A ; Clear character counter STA BLANK$LEN ; . MOV B,A ; . LXI D,OUTBUF ; Set up buffer pointer J$CHECK$CHR: MOV A,M BC, HL ; ORA A ; Set up flags for first check I$TBL$ADD: RZ ; If A=0, we're done DAD B ; Otherwise add length to base, DCR A ; . decrement counter, JMP I$TBL$ADD ; . and check again. IS$IT$OK: ; ; [E1.28] ; ; Check the character in A against the list of "OK" chrs pointed ; to by HL ; ; Entry: ; A = character to check ; HL = pointer to list of "OK" characters ; ; Exit: ; A = original character if ok, 0ffh if not in list ; B = position of character in list ; ; Modifi ; Get character CPI CR ; CR? DB JRNZ,J$NO$R-$-1 ; . CALL J$FLUSH$LINE ; . Flush output line, MVI A,CR ; . Output CR, CALL CON$CHR ; . . INX H ; . bump ptr & check next DB JR,J$NEXT$LINE-$-1 and 255 J$NO$R: CPI LF ; LF? DB JRNZ,J$NO$L-$-1 ; . CALL CON$CHR ; . Output LF, INX H ; . bump ptr & check next DB JR,J$CHECK$CHR-$-1 and 255 J$NO$L: CPI FF ; FF? DB JRNZ,J$NO$F-$-1 ; . CALL CLEAR$SCREEN ; . Clear screen, INX H ; . bump ptr & check next DB JR,J$CHECKes: ; BC ; PUSH H ; Save original "OK" pointer MOV C,A ; Save chr to check against MVI B,0 ; Clear counter CPI ESC ; If chr is JZ I$CHR$OK ; . then automatically ok INR B ; . otherwise start counting at 1 I$CHK$NEXT: MOV A,M ; Get chr to check against ORA A ; End of table? JNZ I$NOT$EOT ; No, check chr DCR A ; Decrement to get 0ffh MOV B,A ; Stuff for later move JMP I$CHR$OK ; And exit I$NOT$EOT: CMP C ; Chrs match? JZ I$CHR$OK ; . Yes, return INX H ; . N$CHR-$-1 and 255 J$NO$F: CPI '$' ; End of string? DB JRNZ,J$NO$S-$-1 ; . CALL J$FLUSH$LINE ; . Flush output line, and RET ; . return to caller. J$NO$S: STAX D ; Not a special chr, save in buffer CPI ' ' ; Blank? DB JRNZ,J$NO$B-$-1 ; . No, don't save position SHLD BLANK$POS ; Save position for later XCHG ; and save corresponding position SHLD OUTBUF$BLANK ; . of the blank we just saved XCHG ; . in the output buffer MOV A,B ; . STA BLANK$LEN ; Save current length ao, bump pointer INR B ; . . and bump counter JMP I$CHK$NEXT ; . . and check next chr I$CHR$OK: MOV A,B ; Set status based on ORA A ; . position counter MOV A,C ; Get user chr back I$DONE: POP H ; and original "OK" pointer RET ; and return JUSTIFY: ; ; [E6.11] ; ; This routine will send a data stream to the console, with each line ; justified based on the SCREEN$WIDTH value. The stream must terminate ; with the CP/M end of string character ($) and may contain imbedded ; Clso J$NO$B: INR B ; Increment counter INX H ; . and input pointer INX D ; . and output pointer LDA SCREEN$WIDTH ; Compare counter against screen width SUB B ; . JP J$CHECK$CHR ; And continue checking if not past end ; ; Screen width exceeded, send this line to the screen. ; LHLD OUTBUF$BLANK ; Get pos of last blank in output buf MVI M,'$' ; and plug with eos ('$') LDA J$MODE ; Justify right edge only if the ORA A ; . right-justify flag is non-zero CM J$ADD$BLANKS ; . CA LL J$SEND$BUFFER ; Output the line to the screen CALL DO$CRLF ; and a CR / LF LHLD BLANK$POS ; Get pointer to where we left off J$SKIP$BLANKS: INX H ; Bump pointer past blank(s) MOV A,M ; . CPI ' ' ; . DB JRZ,J$SKIP$BLANKS-$-1 and 255 JMP J$NEXT$LINE ; and check next segment J$FLUSH$LINE: ; Flush line when CR or EOS encountered MVI A,'$' ; Plug current position with EOS ($) STAX D ; . CALL J$SEND$BUFFER ; Send this line of data RET ; and return J$ADD$BLANKS: RET ; ISP ; No -- display & get chr from bios PUSH H ; Yes, save oklist pointer LHLD CMD$LINE$PTR ; and get chr from command line DCR A ; . Reduce count of chrs by one STA CMD$LINE$CHRS ; . . MOV A,M ; . Get command line character INX H ; . Increment pointer SHLD CMD$LINE$PTR ; . . POP H ; . Restore oklist pointer CPI ',' ; Change ',' to CR JNZ P$NOT$COMMA ; . MVI A,CR ; . P$NOT$COMMA: CPI '.' ; Change '.' to ESC JNZ P$NOT$DOT ; . MVI A,ESC ; . P$NOT$DOT: CPI '_' ;At a later time, this routine will ; justify the right margin by inserting ; extra blanks in the output line. J$SEND$BUFFER: MOV A,B ; If line to output is of zero length, ORA A ; . then don't output the line. RZ ; . LXI D,OUTBUF ; Get address of output buffer CALL CON$MSG ; and call our print message routine RET ; return J$MODE DB 0 ; Current right justify mode BLANK$POS DW 0 ; Last blank on this line OUTBUF$BLANK DW 0 ; Last blank in the output buffer BLANK$LEN DB 0 Underline means prompt & get chr JZ P$DISP ; . from bios anyway (user input) CALL TO$UPPER ; Convert the chr to upper case CALL IS$IT$OK ; Check the chr against the ok list RP ; If ok, return XRA A ; Otherwise, cancel the cmd line STA CMD$LINE$CHRS ; . buffer and fall through to p$disp P$DISP: PUSH H ; Save pointer to ok-chrs CALL JUSTIFY ; and call justify routine POP H ; . P$TRY$AGAIN: CALL CONIN$NE$XC ; Console input, no echo, except ^C CALL TO$UPPER ; Convert the chr to  ; Length of line to the blank ; NOTE: OUTBUF is defined to be after the stack and before the heap. ; end of justify$output data area MOVE$BLOCK: ; ; [DC.20] ; ; Move a block of memory (up to 256 bytes) ; ; Entry: ; HL = source ; DE = destination ; B = count ; Exit: ; data moved ; ; Modifies: ; none ; PUSH PSW ; Save registers PUSH B ; . PUSH D ; . PUSH H ; . M$NEXT$CHR: MOV A,M ; Get next byte, STAX D ; Save in destination. INX H ; Increment pointer to soupper case CALL IS$IT$OK ; If the character is not "OK" JM P$TRY$AGAIN ; . get another CNZ CON$CHR ; . otherwise display it PUSH PSW ; Check mode flag in case we need LDA PROMPT$MODE ; . to send a CR+LF after the ANI 01H ; . user's input CNZ DO$CRLF ; . POP PSW ; . RET ; and return PROMPT$MODE: DB 0 ; Prompt mode flag PROMPT$DECIMAL: ; ; [E6.11] ; ; Prompt the user for a decimal input of up to 5 digits. The Z flag ; indicates the termination character: Z = ESC key, rurce. INX D ; Increment pointer to dest. DCR B ; Decrement counter. JNZ M$NEXT$CHR ; Loop back if we're not done. POP H ; Restore registers POP D ; . POP B ; . POP PSW ; . RET ; No more to do -- return. PROMPT: ; ; [E1.30] ; ; Prompt the user or the command line for input. ; ; Two entry points are provided: ; PROMPT standard entry, CRLF after chr from user ; PROMPT$NOLF special entry, No CRLF after chr from user ; ; Entry: ; DE = pointer to prompt string ; HL = poiesults may not ; be valid; NZ = RETURN key, results valid. ; ; Entry: ; DE = pointer to prompt string ; ; Exit: ; DE = Value entered by the user, 0-0FFFFH ; A = Low byte of value entered by the user, 0-0FFH ; ; Z = ESC key pressed, ignore results ; NZ = RETURN key pressed, results valid ; ; Modifies: ; A, PSW ; MVI A,01H ; Set CRLF after entry DB JR,E$PR$DEC-$-1 ; Jump to entry point PROMPT$DEC$NOLF: MVI A,00H ; Set no CRLF after entry E$PR$DEC: STA PROMPT$D$MODE ; Save prompt mnter to list of valid chars (terminated with 00H) ; ; Exit: ; A = char from the user ; B = position of this character (0, 1, 2, ... n) ; ; Z = char was the escape key ; NZ = char was not the escape key ; ; Modifies: ; A, BC ; MVI A,01H ; Set CRLF after chr JMP E$PROMPT ; Jump to entry point PROMPT$NOLF: MVI A,00H ; Set no CRLF after chr E$PROMPT: STA PROMPT$MODE ; Save prompt mode flag LDA CMD$LINE$CHRS ; Are there any characters left from ORA A ; . the command line? JZ P$Dode flag PUSH H ; Save original HL reigster PUSH B ; . and the BC register, too. XRA A ; Clear the current digit pointer MOV C,A ; Setup count in C register LXI H,SCRATCH ; Initialize the scratch pointer NEXT$DIGIT: PUSH B ; Save digit counter PUSH H ; . and string pointer LXI H,DEC$INPUT$OKC ; Get current 'ok' chrs CALL PROMPT$NOLF ; Prompt for digit POP H ; Get string pointer back POP B ; . along with digit counter DB JRZ,ESCRTN-$-1 ; Return if ESC key hit CPI CR ; C heck for return JZ CONVERT$STRING ; Convert string to decimal, if so CPI BS ; Check for backspace JZ BACKUP$DIGIT ; Back up 1 digit, if we can MOV B,A ; Save character for a moment MOV A,C ; Check digit count CPI 5 ; . JC ADD$DIGIT ; 5 digits or less, add to string LXI D,BLOT ; More than 5 digits, blot this one CALL CON$MSG ; . JMP DE$FOR$NEXT ; . ADD$DIGIT: INR C ; Otherwise bump digit count MOV M,B ; Save digit INX H ; Bump digit pointer JMP DE$FOR$NEXT ; Setup DE fERTED: MOV A,B ; Move converted addr to A RET STR$COMP: ; ; [E1.18] ; ; Compare two strings ; ; Entry: ; HL = source ; DE = destination ; B = count ; Exit: ; Z = two strings equal ; M = source < dest ; P = source >= dest ; ; Modifies: all ; PUSH D PUSH H NEXT$COMPARE: MOV C,M INX H LDAX D INX D CMP C JNZ NOT$EQUAL DCR B JNZ NEXT$COMPARE NOT$EQUAL: POP H POP D RET STR$SWAP: ; Swap two strings ; ; [E1.18] ; ; Entry: ; HL = source ; DE =or next prompt BACKUP$DIGIT: MVI A,' ' ; Bump forward to clear digit CALL CON$CHR ; . XRA A ; Are we at the beginning? CMP C ; . JZ DE$FOR$NEXT ; Yes, don't backup MVI A,BS ; Backup to correct position CALL CON$CHR ; . DCX H ; Backup pointer 1 chr DCR C ; Push count 1 back, also DE$FOR$NEXT: LXI D,DEC$INPUT$MSG ; Setup for next prompt JMP NEXT$DIGIT ; . CONVERT$STRING: MVI M,0 ; Mark end of string LXI H,SCRATCH ; Get beginning of string CALL STR$TO$DE ; Convert st destination ; B = count ; Exit: ; data moved ; ; Modifies: all ; MOV C,M LDAX D MOV M,A MOV A,C STAX D INX H INX D DCR B JNZ STR$SWAP RET STR$TO$DE: ; ; [E5.26] ; ; Converts the string pointed to by HL to a number in the DE reg. ; The conversion will continue until the first non-numeric chr ; found. ; ; NOTE: a test for register overflow is not made. If HL points ; to a string whose numerical value is greater than 65535 (64K), ; inaccurate results will occur. ; ring to DE register MVI A,0FFH ; Insure NZ flag ORA A ; . MOV A,E ; Move low byte to A PUSH PSW ; Check mode flag to see if a LDA PROMPT$D$MODE ; . CR+LF should be sent after ORA A ; . the user's input CNZ DO$CRLF ; . POP PSW ; . ESCRTN: POP B ; Get old BC register back POP H ; . and original HL, as well. RET ; and return with result in HL & A DEC$INPUT$MSG: DB '$' ; Decimal input message DEC$INPUT$OKC: DB '0123456789' ; Decimal input 'ok' chrs DB BS,CR,0 ; . B ; Entry: ; HL = ptr to string ; ; Exit: ; DE = value of string in HL ; HL = next character to process ; ; Modifies: ; DE, HL ; ; PUSH PSW ; We need the A register PUSH B ; . and the BC register LXI D,0 ; Clear totals STN$NEXT$CHR: PUSH D ; Save results so far . . . POP B ; . MOV A,M ; Get chr CPI '0' ; Less than '0'? DB JRC,NO$DIG-$-1 ; Yes, finished CPI '9'+1 ; Greater than '9' DB JRNC,NO$DIG-$-1 ; Yes, finished SUI '0' ; No, convert to 0-9 MOV E,A ; Save thiLOT: DB BS,' ',BS,'$' ; Blot out digit SCRATCH: DB ' ',0 ; Max 5 digits PROMPT$D$MODE: DB 0 ; CRLF flag RET$TO$CONT: ; ; [E2.19] ; ; Prompts and waits for the RETURN key to be pressed. ; ; Entry: ; none ; ; Exit: ; Display message and wait for a RETURN key. ; ; Modifies: ; all ; LXI D,RTC$MSG ; Press RETURN to continue ... CALL CENTER$OUTPUT ; . LXI D,NO$MSG ; . LXI H,RTC$OKC ; . CALL PROMPT ; . [ CR ] RET RTC$MSG: DB 'Press the RETURN key to continue ... ' NO$MSGs digit MVI D,0 ; . PUSH H ; Save ptr to input string LXI H,0 ; Multiply previous by 10 DAD B ; x1 DAD H ; x2 DAD H ; x4 DAD B ; x5 DAD H ; x10 DAD D ; Add in new digit XCHG ; Save results back to DE POP H ; Get input string ptr back INX H ; Bump to next chr JMP STN$NEXT$CHR ; Go back for another digit NO$DIG: POP B ; Get old BC reg back POP PSW ; . and old A reg as well. RET ; Return with results in DE. TO$UPPER: ; ; [E1.08] ; ; Convert the charac: DB '$' RTC$OKC: DB CR,0 ; end of RET$TO$CONT routine SCSI$TO$BIN: ; ; [DC.27] ; ; Converts SCSI address to binary 0-7 ; ; Entry: ; A = SCSI address to convert ; ; Exit: ; A = converted address (0-7) [0FFH = error] ; ; Modifies: B ; MVI B,0FFH ; Set up B register for possible error ORA A ; If A=0, error JZ SCSI$CONVERTED ; . SCSI$NEXT$BIT: INR B ; Increment count RRC ; Shift address right 1 bit JNC SCSI$NEXT$BIT ; Bit shifted to cary means we're done SCSI$CONVter in A to upper case. ; ; Entry: ; A = character to convert ; ; Exit: ; A = upper case character (if alpha) ; ; Modifies: ; A ; CPI 'z'+1 ; Convert to upper case JP UPPER$ALREADY ; . CPI 'a' ; . JM UPPER$ALREADY ; . ANI 5FH ; . UPPER$ALREADY: RET ; and return WAIT: ; Wait A ms ; ; Entry: ; milliseconds in A ; ; Exit: ; time waited ; ; Modifies: A ; PUSH PSW MVI A,221 WAIT$2: DCR A JNZ WAIT$2 POP PSW DCR A JNZ WAIT RET * * * * * * * * * * * *  * * * * * * * * * * * * * * * * * * * * Data area . . . * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; Replicated BIOS to make direct calls easier . . . LB$BIOS$TBL: LB$WBOOT DS 3 ; Warm boot LB$CONST DS 3 ; Console status LB$CONIN DS 3 ; Console input LB$CONOUT DS 3 ; Console output LB$LISTOUT DS 3 ; List output LB$PUNCH DS 3 ; Punch output LB$READER DS 3 ; Reader input LB$HOMDSK DS 3 ; Home disk (move to track 00) LB$SELDSK DS 3 ; Select disk drive L,CR,LF DB 'SCSI address bit code ' S$ADDR$CODE DB 'xx (hex).',CR,LF DB '(See your hard disk controller ' DB 'manual for details).',CR,LF,LF,'$' AGAIN$MSG DB CR,LF,'Do another (Y/N)? ','$' AGAIN$OKC DB 'NY',CR,0 NEW$CTRL DB CR,LF,'Cannot format -- you have an ' DB 'unknown or unsupported hard disk ' DB 'controller.',CR,LF,LF,'$' OLDSP: DS 2 ; old stack pointer STACK: EQU OLDSP+64 ; 31-level stack INBUF: EQU STACK+1 ; Command line input buffer INBUFL: EQU 0 ; Input buffer lB$SETTRK DS 3 ; Select track number LB$SETSEC DS 3 ; Select sector number LB$SETDMA DS 3 ; Set DMA address LB$DSKREAD DS 3 ; Disk read LB$DSKWRITE DS 3 ; Disk write LB$LISTST DS 3 ; List status LB$SECTRN DS 3 ; Sector translate routine ; AMPRO-specific BIOS calls LB$GETNXT DS 3 ; Get bios ver & next tbl address LB$GETEDSK DS 3 ; Get pointer to E-disk storage LB$IOINIT DS 3 ; Set new I/O parameters LB$SCSIDRV DS 3 ; SCSI direct driver LB$LEN EQU $-LB$WBOOT ; Length of bios table LB$XTBL: ; 'ength OBPLUG: EQU INBUF+INBUFL ; Start of outbuf ('$') OUTBUF: EQU OBPLUG+1 ; Output buffer OBUFL: EQU PWIDTH ; Output buffer length HEAP: EQU OUTBUF+OBUFL ; Next available area for data E5BUF: EQU HEAP END rmat -- you have an ' DB 'unknown or unsupported hard disk ' DB 'controller.',CR,LF,LF,'$' OLDSP: DS 2 ; old stack pointer STACK: EQU OLDSP+64 ; 31-level stack INBUF: EQU STACK+1 ; Command line input buffer INBUFL: EQU 0 ; Input buffer lExtra' table definitions ... LB$SWAP$DRV DS 3 ; Swap two logical drives LB$GET$WDP DS 3 ; Set/get win drive parameters LB$PHYTAB DS 3 ; Set/get phytab access LB$GET$LDTE DS 3 ; Get logical device table entry LB$RESERVED DS 3 ; Reserved entry LB$XLEN EQU $-LB$XTBL ; Length of extra table BIOS$VERSION DB 0 ; Bios version number YOU$ARE$ABT DB 'You are about to format the following ' DB 'drive with an interleave of (' INTL$ECHO DB '1):',CR,LF,LF,'$' RTF$MSG DB CR,LF DB 'Press to format, ' DB ' to start over, ' DB ' to quit: ','$' RTF$OKC DB CR,0 FMT$START$MSG DB CR,LF,LF,'Formatting . . . ','$' CLR$DIR$MSG: DB CR,'Setting drive data to 0E5H . . . ','$' FMT$OK$MSG DB CR,'Drive formatted -- no errors. ' DB 'Be sure to use FINDBAD on each of the CP/M ' DB 'letters listed above to find any bad sectors ' DB 'in the drive you just formatted.',CR,LF DB 'Example: FINDBAD F:; FINDBAD G:',CR,LF,LF,'$' FMT$ERR$MSG DB 'Drive NOT FORMATTED due to * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * HInit.asm Version 1 * * * * Copyright (C) 1984,1985 Ampro Computers, Inc. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; Assemble with asm.com or equivalent. ; All Z80 opcodes are defined with DB or DW statements. ; Revision history: ; ; Ver Date Who Description ; --- ----- --- -------------------------------------------- ; 1.2 EA.22 RJB Changed space algori error(s).' DB CR,LF,LF,'$' NO$RESPONSE DB CR,'FORMAT ERROR: your controller ' DB 'is not responding. Possible causes:',CR,LF,LF DB TAB,'Controller set to wrong SCSI address',CR,LF DB TAB,'Controller malfunctioning or not connected',CR,LF DB TAB,'SCSI host adapter malfunctioning',CR,LF DB TAB,'Cables (SCSI to controller or controller ' DB 'to drive) are bad',CR,LF,LF,'$' FORMAT$ERROR DB CR,'FORMAT ERROR: Error code ' ERR$CODE DB 'xx (hex), SCSI command ' ERR$CMD DB 'xx (hex).'thm to be based on the ; # of tracks required to avoid allocating an ; extra block, therby overwriting the next ; partition. ; ; 1.1 E8.22 RJB Corrected calculation of lowest available ; byte when Z3ENV is available. ; ; 1.0 E7.02 RJB Hard disk init for PHYTAB, DPH, DPB, and ; drive initialization, if necessary. ; Program version, and current version date VERS EQU 12 ; Current version THIS$MONTH EQU 10 ; Today's month THIS$DAY EQU 22 ; . day THIS$YEAR EQU 85 ; .   year INT$REV EQU 99 ; Internal revision number ; TRUE and FALSE are defined here NO EQU 0 FALSE EQU 0 YES EQU NOT FALSE TRUE EQU NOT FALSE ; Operating characteristics MIN$VERSION EQU 31 ; Minimum bios version allowed CMD$LINE$OK EQU TRUE ; Allow command line input? RTN$VIA$WB EQU TRUE ; Return to CP/M via warm boot? INTERNAL EQU FALSE ; Internal (unreleased) revision? ; Include diagnostic messages? TEST EQU NO ; TEST diagnostics? ; Current screen width and outp) EOF EQU 'Z'-'@' ; Ctrl-Z (CP/M End-of-file) ESC EQU 1BH ; Ctrl-[ (Escape) EXP EQU 21H ; (Exclamation point) EOS EQU '$' ; (CP/M End-of-string) DEL EQU 7FH ; (Delete) ; bdos equates BDOS EQU 5 ; bdos entry ; * * * * * * * * ; ; The code starts here ... ; ; * * * * * * * * ORG 0100H JMP START SCREEN$WIDTH: DB SWIDTH-1 ; 1 less than actual # SLOW$TERM: DB 10 ; Delay (ms) for slow term CMD$LINE$CHRS: DB 0 ; # of cmd line chrs left CMD$LINE$PTR: DW 0 ; Ptr ut buffer width SWIDTH EQU 80 ; Screen width PWIDTH EQU 132 ; Output buffer width ; Z-80 opcode equates (reversed so we can use a DW to enter them) LDIR80 EQU 0B0EDH ; LDIR (0edh,0b0h) CPIR80 EQU 0B1EDH ; CPIR (0edh,0b1h) INIR80 EQU 0B2EDH ; INIR (0edh,0b2h) OTIR80 EQU 0B3EDH ; OTIR (0edh,0b3h) SBCD80 EQU 043EDH ; SBCD (0edh,043h) LBCD80 EQU 04BEDH ; LBCD (0edh,04bh) SDED80 EQU 053EDH ; SDED (0edh,053h) LDED80 EQU 05BEDH ; LDED (0edh,05bh) SSPD80 EQU 073EDH ; SSPD (to next cmd line chr ZCPR3$TYPE: DB 1 ; External ZCPR3 ENV ZCPR3$PTR: DW 0FE00H ; Pointer to ZCPR3 ENV NAME$MSG: DB 0DH,'Ampro ' NAME: DB 'Hard Disk System Initialization'; <-- Insert name here DB 00H,' Utility',CR,LF ; (Zero marks end-of-name) DB 'Copyright (C) 1985 AMPRO Computers, Inc.',CR,LF DB 'Version ',VERS/10+'0','.',VERS MOD 10+'0' IF INTERNAL ; Display internal revision number? DB 'x',INT$REV/10+'0',INT$REV MOD 10+'0' DB ' [',THIS$YEAR-80+'@' DB THIS$MONTH+'0'+((THIS$MONT0edh,073h) LSPD80 EQU 07BEDH ; LSPD (0edh,07bh) SIXD80 EQU 022DDH ; SIXD (0ddh,022h) LIXD80 EQU 02ADDH ; LIXD (0ddh,02ah) SIYD80 EQU 022FDH ; SIYD (0fdh,022h) LIYD80 EQU 02AFDH ; LIYD (0fdh,02ah) ; Bit SET/RESET/TEST Z-80 opcode equates (use DB to enter) ; Example: SET 7,D would be DB BIT,BSET+B7+ZD BIT EQU 0CBH ; Bit prefix BTST EQU 040H ; Bit test BRES EQU 080H ; Bit reset BSET EQU 0C0H ; Bit set B0 EQU 000H ; Bit 0 B1 EQU 008H ; Bit 1 B2 EQU 010H ; Bit 2 BH/10)*7) DB '.',THIS$DAY/10+'0',THIS$DAY MOD 10+'0',']' ENDIF DB CR,LF,LF,'$',CR HELP$MSG: DB 'Usage: HINIT scsiaddr ctrlr lun ' DB '[cyl,head,rwc,wpc, steprate] ' DB 'cpmletter partition [,cpmletter partition] ...' DB CR,LF,LF BIOS$PLUS: DB 'This program requires AMPRO bios version ' DB MIN$VERSION/10+'0','.',MIN$VERSION MOD 10+'0' DB ' or later.',CR,LF,'$' DB CR,' ',CR,EOF SIGNON$MSG: DB 'The Hard Disk System Initialization utility ' DB 'prepares your Ampro 3.1+ bios ' D3 EQU 018H ; Bit 3 B4 EQU 020H ; Bit 4 B5 EQU 028H ; Bit 5 B6 EQU 030H ; Bit 6 B7 EQU 038H ; Bit 7 ZB EQU 000H ; B Reg ZC EQU 001H ; C Reg ZD EQU 002H ; D Reg ZE EQU 003H ; E Reg ZH EQU 004H ; H Reg ZL EQU 005H ; L Reg ZM EQU 006H ; M Reg ZA EQU 007H ; A Reg ; Jump relative opcode equates (use DB to enter) ; Example: JR AGAIN would be DB JR,AGAIN-$-1 AND 255 DJNZ EQU 010H ; DJNZ addr JR EQU 018H ; JR addr JRNZ EQU 020H ; JR NZ,addr JRZ EQU 028H ; JB 'to access a hard disk unit. The following ' DB 'information is required to initialize the bios ' DB 'for your hard disk unit:',CR,LF,LF DB TAB,'Controller: SCSI address' DB TAB,'* Drive: starting RWC cylinder',CR,LF DB TAB,'Controller: type/model* ' DB TAB,'* Drive: starting WPC cylinder',CR,LF DB TAB,'Drive: logical unit number' DB TAB,'* Drive: step rate code',CR,LF DB TAB,'* Drive: number of cylinders' DB TAB,'CP/M drive letter',CR,LF DB TAB,'* Drive: number of heads' DB TAB,'R Z,addr JRNC EQU 030H ; JR NC,addr JRC EQU 038H ; JR C,addr ; IX and IY prefixes (use DB to enter) IX EQU 0DDH ; IX prefix IY EQU 0FDH ; IY prefix ; Character equates CTRLC EQU 'C'-'@' ; Ctrl-C (ETX) BS EQU 'H'-'@' ; Ctrl-H (Backspace) TAB EQU 'I'-'@' ; Ctrl-I (Tab) LF EQU 'J'-'@' ; Ctrl-J (Line feed) FF EQU 'L'-'@' ; Ctrl-L (Form feed, new pg) CR EQU 'M'-'@' ; Ctrl-M (Carriage return) NAK EQU 'U'-'@' ; Ctrl-U (Negative ack) CAN EQU 'X'-'@' ; Ctrl-X (CancelSize (Kb) of each partition',CR,LF,LF DB '(*) Only required on non-"SCSI generic" ' DB 'Hard disk controllers',CR,LF,LF,LF DB 'NOTE: Your drive''s total formatted ' DB 'capacity in Kbytes is:',CR,LF,TAB DB '(CYLS-1) * HEADS * SECTORS per TRACK * 0.5',CR,LF DB 'where SECTORS per TRACK depends on your controller ' DB 'and is usually 17 or 18.',CR,LF,LF,LF DB '$' ; ; Initialize the command line input pointer. ; START: IF CMD$LINE$OK ; If we want to allow cmd line input, LXI H,0080H  ; . Save the command line. LXI D,INBUF ; . . LXI B,128 ; . . DW LDIR80 ; . . LXI H,INBUF ; . Set up ptrs and count of chrs MOV A,M ; . . STA CMD$LINE$CHRS ; . Save count of characters, INX H ; . Bump line ptr, SHLD CMD$LINE$PTR ; . . and save ptr to cmd line ENDIF IF NOT CMD$LINE$OK ; If no command line input allowed, MVI A,0 ; . Clear the count of characters, STA CMD$LINE$CHRS ; . . LXI H,0 ; . but set the ptr up anyway. SHLD CMD$LINE$PTR ; . . ENDIF L LB$HD$INFO ; Get bottom of ALV storage CALL GET$HL$PTR ; . SHLD HDC$ALV ; . ; ; Compute the DPH base ; LHLD 1 ; Get bios base from wboot vector MVI L,80H ; Assume DPH starts at BIOS+80H SHLD DPH$BASE ; Save it. ; ; Check the version of the bios against the minimum version allowed. ; If the bios is not at least the minimum, display an error message ; and exit to the operating system. ; CHECK$B$VERS: LDA BIOS$VERSION ; Get bios version # CPI MIN$VERSION ; Check against minimum ve IF NOT RTN$VIA$WB ; If we're returning without warm boot, DW SSPD80,STACK ; . then save old stack ptr. ENDIF ; ; Stuff the stack with our pointer and get the bios JMP table. ; LXI SP,STACK ; Set up the stack pointer CALL GET$BIOS$VERS ; Copy the jmp tbl to a local area ; ; Special first-time initialization goes here . . . ; ; Find the lowest Z3 address of the RCP, IOP, FCP, or NDR. The CL, ; ENV, SH, PATH, MSG, FCB, STK, and WHL are all assumed to be either ; in low memory (belorsion DB JRNC,MINBIOS-$-1; At least minimum version . . . LXI D,BIOS$PLUS ; Not minimum, display error message CALL JUSTIFY ; . JMP ALL$DONE ; and exit. ; ; Perform any initialization particular to each version of the Ampro ; bios, if necessary. ; MINBIOS: LDA BIOS$VERSION ; Get current bios version CPI 30 ; Is it version 3? DB JRC,CHECK2-$-1 ; No, check for version 2 ; Bios version 3 init code ... CHECK2: CPI 20 ; Is it version 2? DB JRC,TOPMENU-$-1 ; No, assume versiw 0080H) or above the loadable packages. The ; address found becomes the upper limit to the hard disk allocation ; vectors. If no Z3 environment descriptor is found, the top of ; memory (0FFFFH) is returned as the upper limit to the hard disk ; allocation vectors. LHLD ZCPR3$PTR ; Get pointer to Z3 stuff ... INX H ; Bump to where 'Z3ENV' literal INX H ; . is supposed to be INX H ; . LXI D,Z3$CHECK$V ; Make sure this is a Z3 env MVI B,5 ; . descriptor CHECK$NEXT$Z3: LDAX D ; . on 1 ; Bios version 2 init code ... ; ; This is where you can jump to start the program over. ; TOPMENU: LXI SP,STACK ; Stuff SP with our stack. ; ; Display the name and signon message ; IF CMD$LINE$OK ; If cmd line input is possible LDA CMD$LINE$CHRS ; Check for any input and skip ORA A ; . the initial messages if any DB JRNZ,CLRHD-$-1 ; . chrs in the cmd line. ENDIF CALL CLEAR$SCREEN ; Clear the screen LXI D,NAME$MSG ; Display the name, version, etc. CALL CENTE CMP M ; . DB JRNZ,NO$Z3-$-1 ; Not equal, no Z3 env INX D ; . INX H ; . DB DJNZ,CHECK$NEXT$Z3-$-1 and 255 LXI B,4 ; Bump HL to RCP DAD B ; . LXI D,0FD00H ; Check the next four Z3 elements MVI B,4 ; . (RCP, IOP, FCP, and NDR). keep NEXT$PACKAGE: ; . the smallest non-zero value as PUSH H ; . the upper limit to the hard CALL GET$HL$PTR ; . disk allocation vectors. We MOV A,L ; . assume that we are using at CMP H ; . least 0FD00H and up, as that DB JRZ,SKIP0-$-1R$OUTPUT ; . LXI D,SIGNON$MSG ; and the initial message CALL JUSTIFY ; . CLRHD: LXI D,CLEAR$HDC$MSG ; Clear prior hdc assignments? LXI H,CLEAR$HDC$OKC ; . CALL PROMPT ; . JZ ALL$DONE ; . (end if the ESC key pressed). CPI 'Y' ; . CZ CLEAR$HDC ; . AGAIN: ; ; Program main loop . . . ; IF CMD$LINE$OK ; If cmd line input is possible LDA CMD$LINE$CHRS ; Check for any input and skip ORA A ; . the current status messages DB JRNZ,NOSTAT-$-1 ; . if any chrs in the cmd line. E ; . is the standard Ampro Z3 env. CALL CMP$HL$DE ; . DB JRNC,SKIP0-$-1 ; . XCHG ; . SKIP0: POP H ; . INX H ; . INX H ; . INX H ; . DB DJNZ,NEXT$PACKAGE-$-1 and 255 XCHG ; Save lowest byte found DB JR,SAVE$Z3-$-1 ; . Z3$CHECK$V: DB 'Z3ENV' ; Z3 environment check vector NO$Z3: LXI H,0FFFFH ; Indicate the last available byte SAVE$Z3: ; . is the top of memory, and fall SHLD LAST$BYTE ; . throught to check bios version. ; ; Get the base of ALV storage ; CALNDIF CALL SHOW$STAT ; Show "current drive" + partitions NOSTAT: LXI D,MAIN$MENU$MSG ; Get main choices LXI H,MAIN$MENU$OKC ; . CALL PROMPT ; . JZ ALL$DONE ; . MOV A,B ; . DCR A ; . LXI H,MAIN$MENU$EXE ; . JMP GO$TABLE ; . MAIN$MENU$EXE: DW DEFINE$CDRIVE ; Define "Current Drive" DW DEFINE$PART ; Define parition on "Current Drive" DEFINE$CDRIVE LXI D,SCSI$ADDR$MSG ; Get SCSI address LXI H,SCSI$ADDR$OKC ; . CALL PROMPT ; . JZ ALL$DONE ; . ESC -- finished STA CD$ID  ; . (Save ID in msg) MOV A,B ; . DCR A ; . CALL BIN$TO$SCSI ; . STA SCSI$ADDR ; . LXI D,HD$CTRL$MSG ; Get HD controller name LXI H,HD$CTRL$OKC ; . CALL PROMPT ; . JZ DEFINE$CDRIVE ; . ESC -- top of this section STA CD$TYPE ; . (Save type in msg) MOV A,B ; . DCR A ; . STA HD$CTRL ; . LXI D,DRV$LUN$MSG ; Get drive logical unit # LXI H,DRV$LUN$OKC ; . CALL PROMPT ; . JZ DEFINE$CDRIVE ; . ESC -- back up 1 section STA CD$LUN ; . (Save logical unit # in msg) MOV A,; . DPOK: LXI D,CPM$LTR$MSG ; Get CP/M drive letter DB JR,GET$PART-$-1 ; . GET$PART$2: ; . LXI D,CPM$LTR$MSG2 ; . GET$PART: ; . LXI H,CPM$LTR$OKC ; . CALL PROMPT ; . JZ AGAIN ; . ESC -- next physical drive MOV A,B ; . ADI 4 ; . (bump 1-11 to 5-15) STA CPM$LTR ; . ADI 'A' ; Put current CP/M drive letter STA CPM$LTR$ECHO ; . in prompt STA DRIVE$INST ; . and install message GET$PART$AGAIN: LXI D,PARTITION$MSG ; Get partition size (Kb) CALL PROMPT$DEC$NOLF ; . DB B ; . DCR A ; Convert 0-3 to SCSI lun RRC ; . RRC ; . RRC ; . ANI 1110$0000B ; . mask all but bits 7-6-5 STA DRV$LUN ; . XRA A ; Clear step rate value, in case STA STEP$RATE ; . we've got a non-Xebec HDC LDA HD$CTRL ; Check for Xebec HDC CPI NON$GENERIC ; If generic, then no need to DB JRC,DCDONE-$-1 ; . get drive info ... LXI D,DRV$CYLS$MSG ; Get # of cylinders CALL PROMPT$DECIMAL ; . JZ DEFINE$CDRIVE ; . ESC -- top of this section LXI H,DRV$CYLS ; . MOV JRZ,GET$PART$2-$-1 and 255 ; Go back for more MOV E,A ; . ORA D ; . DB JRZ,GET$PART$AGAIN-$-1 and 255 ; Zero, try again DW SDED80,PARTITION; Save partition value CALL ADD$PARTITION ; Add another drive partition JMP AGAIN ; . ALL$DONE: ; Exit the program ... IF RTN$VIA$WB ; If we're returning via warm boot, JMP LB$WBOOT ; . then JUMP! ENDIF IF NOT RTN$VIA$WB ; Otherwise, DW LSPD80,STACK ; . Get old stack ptr back. RET ; . and return to cp/m ENDIF * * * * * * * * M,D ; . INX H ; . MOV M,E ; . LXI D,DRV$HEAD$MSG ; Get # of heads CALL PROMPT$DECIMAL ; . JZ DEFINE$CDRIVE ; . ESC -- top of this section STA DRV$HEAD ; . LXI D,DRV$RWC$MSG ; Get reduced write current cylinder CALL PROMPT$DECIMAL ; . JZ DEFINE$CDRIVE ; . ESC -- top of this section LXI H,DRV$RWC ; . MOV M,D ; . INX H ; . MOV M,E ; . LXI D,DRV$WPC$MSG ; Get write precomp cylinder CALL PROMPT$DECIMAL ; . JZ DEFINE$CDRIVE ; . ESC -- top of this section LXI H,DRV$WPC* * * * * * * * * * * * * * * * * * * * * * * * Routines specific to this program . . . * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * CLEAR$HDC: CALL LB$HD$INFO ; Get pointer to HD info PUSH H ; Bump to absolute start INX H ; . INX H ; . MOV E,M ; Get absolute start vector INX H ; . MOV D,M ; . POP H ; Plug in current HD info MOV M,E ; . INX H ; . MOV M,D ; . XRA A ; Clear all "driver 3" entries NXTDVR: PUSH PSW ; CALL LB$GET ; . MOV M,D ; . INX H ; . MOV M,E ; . LDA HD$CTRL ; Check for Xebec HDC CPI NON$GENERIC ; . JNZ DTC LXI D,XEB$STEP$MSG ; Get step rate mode value LXI H,XEB$STEP$OKC ; . CALL PROMPT ; . JZ DEFINE$CDRIVE ; . ESC -- top of this section MOV A,B ; . DCR A ; . STA STEP$RATE ; . JMP DCDONE ; . DTC: LXI D,DTC$STEP$MSG LXI H,DTC$STEP$OKC CALL PROMPT JZ DEFINE$CDRIVE MOV A,B DCR A STA STEP$RATE DCDONE: CALL INIT$HDC ; Initialize HDC for this drive ... $LOGICAL ; MOV A,M ; CPI 03H ; Driver 3? DB JRNZ,BUMPD-$-1 ; No, skip it MVI M,0 ; Yes, clear it BUMPD POP PSW ; Bump to next unit INR A ; . CPI 16 ; done? DB JRNC,NXTDVR-$-1 and 255 ; No, do another CALL LB$HD$INFO ; Reset pointer to ALV CALL GET$HL$PTR ; . SHLD HDC$ALV ; . LXI D,HDC$CLR$DONE ; Tell 'em we cleared prior assignments CALL CENTER$OUTPUT ; . RET SHOW$STAT: RET DO$SCSI: INX H LDA DRV$LUN ORA M MOV M,A DCX H LDA SCSI$ADDR CA ; . (ok or error msg returned in DE) LXI H,2 ; Setup initial reserved tracks value SHLD RESERVED ; . MVI A,0FFH ; Mark drive STA CDRIVE$OK ; . CALL CENTER$OUTPUT ; Display either error or ok msg JMP AGAIN ; Go back for more DEFINE$PART: LDA CDRIVE$OK ; Check for drive defined ORA A ; . DB JRNZ,DPOK-$-1 ; Drive defined -- continue LXI D,NO$DRIVE$MSG ; No drive defined -- display message LXI H,NO$DRIVE$OKC ; . and return to main menu. CALL PROMPT ; . JMP AGAIN LL LB$SCSIDRV ORA A RET INIT$HDC: LDA HD$CTRL ; Init HDC for this drive LXI H,HDC$INIT$EXE ; . JMP GO$TABLE ; . HDC$INIT$EXE: DW NO$INIT$NEEDED ; Generic SCSI HDC (burst mode) DW INIT$SHUGART ; Generic SCSI HDC (byte mode) DW INIT$XEBEC ; Xebec 1410(A) DW INIT$DTC ; Data Technology 500 Series NO$INIT$NEEDED: LXI D,CD$MSG ; Just set message RET INIT$SHUGART: CALL LB$HD$INFO ; Get HD info pointer LXI D,4 ; Bump to byte/block ptr DAD D ; . CALL GET$HL$PTR ; Get po inter in HL MVI M,1 ; Set byte mode LXI D,CD$MSG ; Set A-OK message RET INIT$XEBEC: LXI D,X$ID ; Where to put the fmt data LXI H,DRV$CYLS ; . LXI B,7 ; . DB 0EDH,0B0H ; . (LDIR) LXI H,X$IC ; Init Drive Characteristics LXI D,X$ID ; . CALL DO$SCSI ; . LXI D,CD$MSG ; Init ok -- load A-OK msg RZ ; LXI D,INIT$ERR$MSG ; Init failed -- load error msg RET X$IC: DB 0CH DB 0,0,0,0,0 X$ID: DB 0,0,0,0,0,0,0,11 INIT$DTC: LHLD DRV$CYLS SHLD D$CYL LDA DRV$RWC+1 STBump to CKV INX H ; . DW LDED80,HDC$ALV ; Get allocation vector to DE MOV M,E ; Save in CKV INX H ; . MOV M,D ; . INX H ; Save in ALV MOV M,E ; . INX H ; . MOV M,D ; . INX H ; . LHLD ALVBYTES ; Add ALV to ALVBYTES DAD D ; . SHLD HDC$ALV ; Save updated ALV base XCHG ; . CALL LB$HD$INFO ; Get pointer in BIOS to ALV base MOV M,E ; Save updated ALV base in BIOS INX H ; . MOV M,D ; . ; ; Update HDC DPB ... ; LHLD HDC$UNIT$DPB ; Get ptr to unit DPB ptr baA D$RWC LDA DRV$HEAD DCR A STA D$HD LDA STEP$RATE MOV E,A MVI D,0 LXI H,D$TRAN$TBL DAD D MOV A,M STA D$STPR XRA A STA STEP$RATE LXI H,D$MSC LXI D,D$MSD CALL DO$SCSI LXI D,CD$MSG ; Init ok -- load A-OK msg RZ ; LXI D,INIT$ERR$MSG ; Init failed -- load error msg RET D$TRAN$TBL: DB 60 DB 4 DB 3 DB 2 DB 1 D$MSC: DB 0C2H,0,0 DB 0,0,0 D$MSD: DB 11 D$STPR: DB 0 DB 0 D$HD: DB 0 D$CYL: DB 0,0 D$RWC: DB 0,0,0 ADD$PARTITION: LHLD PARTITION ; Get pck CALL GET$HL$PTR ; Get actual unit DPB ptr in HL PUSH H ; . LXI B,5 ; Bump to disk size DAD B ; . DW LDED80,NBLOCKS ; Save # of blocks (CP/M wants DCX D ; . [blocks - 1] stored here) MOV M,E ; . INX H ; . MOV M,D ; . POP H ; . LXI B,13 ; Bump to reserved tracks DAD B ; . DW LDED80,RESERVED ; Save reserved tracks MOV M,E ; . INX H ; . MOV M,D ; . LHLD NTRACKS ; Update reserved tracks DAD D ; . SHLD RESERVED ; . ; ; Display "successful" message ; XRartition size (in K) CALL HL$DIV$2 ; Divide K by 8 to get number CALL HL$DIV$2 ; . of tracks in this partition CALL HL$DIV$2 ; . SHLD NTRACKS ; . DAD H ; Multiply tracks by 2 to get # SHLD NBLOCKS ; . of blocks in this partition LHLD NBLOCKS ; Compute the number of ALV bytes LXI B,7 ; . required for this partition DAD B ; . CALL HL$DIV$2 ; . ( the actual formula is: ) CALL HL$DIV$2 ; . ( ALVB = [NBLOCK + 7] / 8 ) CALL HL$DIV$2 ; . SHLD ALVBYTES ; Allocation vector sizA A ; Clear carry LHLD HDC$ALV ; Compute space remaining XCHG ; . LHLD LAST$BYTE ; . DB 0EDH,052H ; SBC HL,DE DCX H ; . XCHG ; Convert to decimal LXI H,SPACE$LEFT$DEC; . CALL DE$TO$HL$DEC ; . LXI D,SPACE$LEFT ; . CALL CENTER$OUTPUT ; . RET * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Misc data and messages . . . * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * CLEAR$HDC$MSG: DB 'Do you want to clear the existinge (in bytes) DW LBCD80,HDC$ALV ; Get ALV base in BC DAD B ; Add to HL DW LDED80,LAST$BYTE; Compare to last available byte CALL CMP$HL$DE ; . DB JRC,ENOUGH-$-1 ; Enough room? LXI D,NOT$ENOUGH$RM ; No ... tell 'em. CALL JUSTIFY ; . CALL RET$TO$CONT ; . RET ENOUGH: ; ; Update PHYTAB ... ; LDA CPM$LTR ; Get data for this logical drive CALL LB$GETLOGICAL ; . MVI M,03H ; Set Hard Disk driver INX H ; . MOV A,M ; Get DPH offset ANI 0F0H ; . STA DPHOFS ; . (save in  hard ' DB 'disk assignments (Y/N)? ','$' CLEAR$HDC$OKC: DB 'YN',0 HDC$CLR$DONE: DB '*** Previous hard disk assignments have ' DB 'been cleared ***',CR,LF,'$' MAIN$MENU$MSG: DB CR,LF,LF DB 'Options available:',CR,LF DB TAB,' (D) Define the Current Drive',CR,LF DB TAB,' (A) Add a partition to the ' DB 'Current Drive',CR,LF,LF DB TAB,'(ESC) Exit the program',CR,LF,LF DB 'What next (D/A/ESC)? ','$' MAIN$MENU$OKC: DB 'DA',0 SCSI$ADDR$MSG: DB CR,LF,LF,LF,LF,LF DB 'Definingorder to update DPH) MOV B,A ; Or in step rate code LDA STEP$RATE ; . ANI 00FH ; . ORA B ; . MOV M,A ; Save as DPH/step rate INX H ; . LDA DRV$LUN ; . ORI 0AH ; Set to 512 byte sectors, 4K AU MOV M,A ; . INX H ; . LDA SCSI$ADDR ; Update SCSI address MOV M,A ; . ; ; Update DPH ; LHLD DPH$BASE ; Get DPH base LDA DPHOFS ; Add offset for this unit MOV C,A ; . MVI B,0 ; . DAD B ; . LXI B,0AH ; Add offset to DPB DAD B ; . SHLD HDC$UNIT$DPB ; . INX H ;  the Current Drive ...' DB CR,LF DB '======================================' DB CR,LF DB LF,LF DB 'The Current Drive is the physical hard ' DB 'disk drive you are currently working ' DB 'with. The definition of the drive ' DB 'consists of the SCSI ID and type of ' DB 'the hard disk controller connected to ' DB 'the drive, ' DB 'the logical unit number (LUN) of the ' DB 'drive, and the drive characteristics if ' DB 'you are using a Xebec 1410(A) controller.' DB CR,L  F,LF,'Hard disk controller SCSI ID:' DB CR,LF,'-----------------------------' DB CR,LF,LF DB 'Each hard disk controller must be set ' DB 'to one of the eight SCSI bus ID''s. These ' DB 'ID''s range from zero (0) to seven (7). ' DB 'If you have only one hard disk controller ' DB 'in your system, it''s ID is usually zero ' DB '(0). If you have more than one hard disk ' DB 'controller, make sure they are set to ' DB 'different ID''s.',CR,LF,LF DB 'What is the SCSI ID of the buffered step',CR,LF DB TAB,'6 - 30us buffered step',CR,LF DB TAB,'7 - 15us buffered step',CR,LF DB 'Which step mode (0, 4, 5, 6, or 7)? ','$' XEB$STEP$OKC: DB '0',0FFH,0FFH,0FFH,'4567',0 DTC$STEP$MSG: DB CR,LF DB 'Data Technology 500 Series step mode ' DB '(choose from the ' DB 'following table):',CR,LF DB TAB,'0 - 3ms step',CR,LF DB TAB,'1 - 200us buffered step',CR,LF DB TAB,'2 - 150us buffered step',CR,LF DB TAB,'3 - 100us buffered step',CR,LF DB TAB,'4 - 50us bucurrent drive''s ' DB 'controller (0-7, ESC to quit)? ','$' SCSI$ADDR$OKC: DB '01234567',0 HD$CTRL$MSG: DB CR,LF,'Hard disk controller type:' DB CR,LF,'--------------------------' DB CR,LF,LF DB 'Of the following controllers ...',CR,LF,LF DB TAB,'1 - Generic burst-mode SCSI controller ' DB '(Adaptec ACB4000, Xebec Owl)',CR,LF DB TAB,'2 - Generic byte-mode SCSI controller ' DB '(Shugart 1610-4)',CR,LF DB TAB,'3 - Xebec 1410 or 1410A',CR,LF DB TAB,'4 - Data Technology 500 Serffered step',CR,LF DB 'Which step mode (0, 1, 2, 3, or 4)? ','$' DTC$STEP$OKC: DB '01234',0 NO$DRIVE$MSG: DB 'Please define the Current Drive before ' DB 'adding a partition to it.',CR,LF DB 'Press the RETURN key to continue. ','$' NO$DRIVE$OKC: DB CR,LF,0 CPM$LTR$MSG: DB CR,LF,LF DB 'Add a CP/M partition ' DB 'on the Current Drive ...',CR,LF DB '========================' DB '========================' DB CR,LF CPM$LTR$MSG2: DB CR,LF DB 'CP/M letter to use for this partitiies',CR,LF DB LF DB 'Which one is the Current Drive connected ' DB 'to (1, 2, 3, or 4)? ','$' HD$CTRL$OKC: DB '12' NON$GENERIC: EQU $-HD$CTRL$OKC DB '34',0 DRV$LUN$MSG: DB CR,LF,'Current Drive logical unit number:' DB CR,LF,'----------------------------------' DB CR,LF,LF DB 'Each disk connected to a hard disk ' DB 'controller has a unique number, called ' DB 'the Logical Unit Number, or LUN. ' DB 'The first LUN on a hard disk ' DB 'controller is zero (0), and the numbon ' DB '(F-P, ESC for new Current Drive)? ','$' CPM$LTR$OKC: DB 'FGHIJKLMNOP',0 PARTITION$MSG: DB CR,LF DB 'Size of the ' CPM$LTR$ECHO: DB 'x: partition (in K bytes)? ','$' NOT$ENOUGH$RM: DB CR,LF,'There is not enough space left to ' DB 'install a hard disk partition of the ' DB 'size you indicated.' DB CR,LF,'$' INIT$ERR$MSG: DB '*** Cannot initialize HDC for the Current ' DB 'Drive -- check you disk parameters. ***' DB CR,LF,'$' CD$MSG: DB CR,LF,'*** Current Drive set ers ' DB 'increase at that point to a maximum of ' DB 'seven (7). Most hard disk ' DB 'controllers can support two drives, which ' DB 'means the LUN''s for the controller are ' DB 'either zero (0) or one (1). If only ' DB 'one drive is connected, the logical ' DB 'unit number (LUN) is normally zero (0). ' DB CR,LF,LF DB 'What is the Current Drive''s logical ' DB 'unit number (0-7)? ','$' DRV$LUN$OKC: DB '01234567',0 DRV$CYLS$MSG: DB CR,LF DB 'For the controller you into: SCSI ID [' CD$ID: DB 'x], HDC type: [' CD$TYPE: DB 'x], logical unit [' CD$LUN: DB 'x]. ***',CR,'$' SPACE$LEFT: DB CR,LF,'<<< Drive ' DRIVE$INST: DB 'x: installed -- ' SPACE$LEFT$DEC: DB 'xxxxx bytes of bios buffer area ' DB 'remaining. >>>',CR,'$' SCSI$ADDR: DB 0 HD$CTRL: DB 0 DRV$LUN: DB 0 DRV$CYLS: DW 0 DRV$HEAD: DB 0 DRV$RWC: DW 0 DRV$WPC: DW 0 STEP$RATE: DB 0 CPM$LTR: DB 0 PARTITION: DW 0 LAST$BYTE: DW 0 RESERVED: DW 0 HDC$INIT: DB 0 NBLOCKS: DW 0 NTRACKS: Ddicated, ' DB 'the following additional information on ' DB 'the Current Drive is required:' DB CR,LF,LF DB ' Number of cylinders? ','$' DRV$HEAD$MSG: DB ' Number of heads? ','$' DRV$RWC$MSG: DB 'Starting cylinder for RWC? ','$' DRV$WPC$MSG: DB 'Starting cylinder for WPC? ','$' XEB$STEP$MSG: DB CR,LF DB 'Xebec 1410(A) step mode (choose from the ' DB 'following table):',CR,LF DB TAB,'0 - 3ms step',CR,LF DB TAB,'4 - 200us buffered step',CR,LF DB TAB,'5 - 70us W 0 ALVBYTES: DW 0 DPHOFS: DB 0 HDC$UNIT$DPB: DW 0 HDC$ALV: DW 0 ; HDC CSV & HDC ALV DPH$BASE: DW 0 CDRIVE$OK DB 0 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Library routines . . . * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * A$TO$HL$HEX: ; ; [DC.27] ; ; Converts the number in A to the hex digits in HL ; ; Entry: ; A = number to convert ; ; Exit: ; HL = the hex equivalent of the number (L=high, H=low) ; (use shld!  to store the converted number) ; ; Modifies: none ; PUSH PSW ; Save original number RRC ; Get high nybble RRC ; . RRC ; . RRC ; . ANI 0FH ; . CALL A$TO$HEX ; Convert to hex MOV L,A ; Save in L register POP PSW ; Get original number back PUSH PSW ; Save again for later ANI 0FH ; Get low nybble CALL A$TO$HEX ; Convert to hex MOV H,A ; Save in H register POP PSW ; Get original number back RET ; and return A$TO$HEX: ; Convert A to a hex digit CPI 0AH ; ; Stop processing if EOS ('$') JZ CENTER$DONE ; . XCHG ; Put new pointer in DE JMP CENTER$NEXT$LN ; Go & do the next line OUTPUT$DELIM: CALL CON$CHR ; Output delimiter CPI LF ; Wait 10ms if we have a line feed CZ WAIT ; . INX H ; Point to next chr JMP NEXT$DELIM ; and check that one, also CENTER$DONE: POP H ; Restore registers POP B ; . POP PSW ; . RET ; and return CLEAR$SCREEN: ; ; [E1.28] ; ; This routine clears the screen by calling DO$CRLF 26 times. ; ;  If 0-9, we don't need to JM A$TO$HEX$2 ; . add any offset ADI 07H ; Offset for A-F A$TO$HEX$2: ; . ADI 30H ; ASCII bias RET ; and return BIN$TO$SCSI: ; ; [E6.10] ; ; Converts binary 0-7 to SCSI address ; ; Entry: ; A = number to convert (0-7) ; ; Exit: ; A = converted SCSI address [00H = error] ; ; Modifies: B ; ANI 07H ; Mask out all but addrs 0-7 INR A ; Bump A to shift at least one bit MOV B,A ; . and move to the B register XRA A ; Clear A register Entry: ; None ; ; Exit: ; The screen is cleared ; ; Modifies: ; None ; PUSH PSW ; Save just in case MVI A,26 ; 26 CRLF's C$NEXT$LINE: CALL DO$CRLF ; Next line DCR A ; Done? JNZ C$NEXT$LINE ; Nope. POP PSW ; Restore original AF RET ; and return CMP$HL$DE: ; ; [E6.10] ; ; Compare register pair HL with register pair DE. ; ; Entry: ; DE,HL = data to compare ; ; Exit: ; Z: DE = HL, NZ: DE # HL ; C: HL < DE, NC: HL >= DE ; ; Modifies: ; PSW ; MOV A,H ; Compare  STC ; Set carry for shift BIN$NEXT$BIT: RAL ; Shift left one bit DCR B ; Decrement count DB JRNZ,BIN$NEXT$BIT-$-1 and 255 RET ; Z = all done CENTER$OUTPUT: ; ; [DC.20] ; ; Automatically centers the output line(s) based on the line width ; stored in SCREEN$WIDTH. Each line is delimited with CR+LF. This ; routine will return to the caller when it encounters the string ; terminator, '$'. Any additional LF characters after a CR+LF pair ; will be passed through. ; ; Entry: ; Dhigh bytes CMP D ; . RNZ ; If not zero, flags are set MOV A,L ; Compare low bytes CMP E ; . RET ; Return with flags set CON$CHR: ; ; [DC.20] ; ; This routine sends the character in the "A" register to the console ; through the BDOS conout call. ; ; Entry: ; A = character to send ; ; Exit: ; character is sent to the console ; ; Modifies: ; None ; PUSH PSW PUSH B PUSH D PUSH H MVI C,2 MOV E,A CALL BDOS POP H POP D POP B POP PSW RET CON$CHR$AC:E = Pointer to output string(s), terminated with CR+LF. ; ; Exit: ; The output string(s) are sent to the screen ; ; Modifies: DE ; PUSH PSW ; Save registers PUSH B ; . PUSH H ; . CENTER$NEXT$LN: CALL GET$STRLEN ; Get length to next CR or '$' in B MOV A,B ; Check for zero length ORA A ; . JZ NEXT$DELIM ; If so, output the CR, LF, etc. LDA SCREEN$WIDTH ; Compute offset needed to center line STC ; . SBB B ; . (if there are too many chrs, just JC NO$BLANKS ; . print the l ; ; [DC.20] ; ; This routine sends the character in the C register to the console ; the number of times in the A register. ; ; Entry: ; A = Number of times to send character ; C = Character to send ; ; Exit: ; Same ; ; Modifies: ; None ; PUSH PSW ; Save all registers PUSH B ; . PUSH D ; . PUSH H ; . MOV B,A ; Move data to accomodate CP/M MOV A,C ; . NEXT$CHR$OUT: CALL CON$CHR ; Send 1 chr DCR B ; Decrement counter JNZ NEXT$CHR$OUT ; Done? POP H ; Restore all ine as is . . . ) ANI 0FEh ; Clear least significant bit RRC ; . and rotate to divide by two MVI C,' ' ; Output enough blanks to center line CNZ CON$CHR$AC ; . (only if count is non-zero) NO$BLANKS: MOV A,M ; Save CR for later MVI M,'$' ; Plug position with '$' for cp/m CALL CON$MSG ; . print string function MOV M,A ; Restore saved CR NEXT$DELIM: MOV A,M ; Get character CPI CR ; Print it if CR JZ OUTPUT$DELIM ; . CPI LF ; Print it if LF JZ OUTPUT$DELIM ; . CPI EOSregisters POP D ; . POP B ; . POP PSW ; . RET ; and return CONIN$NE$XC: ; ; [E1.28] ; ; Console input, no echo, exit on ctrl-c ; ; Entry: ; none ; ; Exit: ; A = character from console, except for ctrl-c, which causes ; an immediate jump to ALL$DONE ; ; Modifies: ; A ; CALL LB$CONIN CPI CTRLC JZ ALL$DONE RET CON$MSG: ; ; [DC.20] ; ; Console message ; ; Entry: ; DE = pointer to message string, terminated with '$' ; ; Exit: ; message printed on con! sole ; ; Modifies: A, BC ; PUSH PSW ; Save registers PUSH B ; . PUSH D ; . PUSH H ; . MVI C,9 ; BDOS print string command CALL BDOS ; . POP H ; Restore registers POP D ; . POP B ; . POP PSW ; . RET ; and return DE$TO$HL$DEC: ; ; [E6.25] ; ; Convert the 16-bit number in the DE register pair to a 5-digit ; decimal number. Store this number starting in the memory pointed ; to by the HL register pair. Optionally convert leading zeroes to ; blanks. ; ; Call DELF is sent to the screen. ; ; Modifies: ; none ; PUSH PSW ; Save AF MVI A,0Dh ; Send carriage return CALL CON$CHR ; . MVI A,0Ah ; and line feed CALL CON$CHR ; . LDA SLOW$TERM ; Check slow flag ORA A ; . CNZ WAIT ; wait for the s-l-o-w terminals POP PSW ; recover original AF RET ; and return GET$BIOS$VERS: ; ; [E5.24] ; ; Get bios version -- Copies the current BIOS jump tables (starting ; at warm boot) to a local area for ease of utility access. If the ; BIOS is $TO$HL$DEC to convert leading zeroes to blanks ; Call DE$TO$HL$DEC$0 to leave leading zeroes alone ; ; Entry: ; DE = number to convert ; HL = ptr to target memory location ; ; Exit: ; DE,HL unchanged ; ; Modifies: ; PSW ; MVI A,1 ; Set "clear leading 0's" mode DB JR,E$DETOHL-$-1 ; Jump to entry point DE$TO$HL$DEC$0: XRA A ; Set "leave leading 0's alone" mode E$DETOHL: STA DE$TO$HL$MODE ; Save mode flag PUSH B ; Save registers PUSH D ; . PUSH H ; . LXI B,-10000 ; Convert version 2.0 or greater, the secondary jump table is copied ; also. ; ; Entry: ; none ; ; Exit: ; Z = bios 1.0 - 1.4 (floppy only bios) ; NZ = bios 2.0 or greater (floppy & fixed disk bios) ; ; Modifies: All registers ; LHLD 1 ; Get start of bios jump table LXI D,LB$BIOS$TBL ; Move bios to local storage LXI B,LB$LEN ; . (length of bios area) DW LDIR80 ; . (LDIR) MVI A,10 ; Test CP/M version CALL LB$GETNXT ; Get next jump table STA BIOS$VERSION ; Save bios version INX H ; Seeten-thousands digit CALL TODEC ; . LXI B,-1000 ; Convert thousands digit CALL TODEC ; . LXI B,-100 ; Convert hundreds digit CALL TODEC ; . LXI B,-10 ; Convert tens digit CALL TODEC ; . MOV A,E ; Convert ones digit ADI '0' ; . (Leave zero intact) MOV M,A ; . XRA A ; Clear PSW POP H ; Restore registers POP D ; . POP B ; . RET ; and return ... TODEC: MVI A,'0' ; Start with an ASCII zero PUSH H ; Save target string pointer XCHG ; Move number to convert if HL is 0FFFFh MOV A,H ; . ORA L ; . RZ ; If so, then old version DCX H ; Fix HL as it has the table addr LXI D,LB$XTBL ; Move extra table to local storage LXI B,LB$XLEN ; . (length of extra table) DW LDIR80 ; . (LDIR) MVI A,0FFH ; Set NZ to indicate bios ORA A ; ... version 2.1+ RET ; ... and return. BIOS$VERSION: DB 0 ; Current bios version GET$HL$PTR: ; ; [DC.20] ; ; Gets the pointer pointed to by HL and puts it in HL ; ; Entry: ; HL = pointer to put in to HL TODEC1: MOV E,L ; Save a copy of current HL in DE MOV D,H ; . (in case we're done) INR A ; Bump digit DAD B ; Add "negative" BC to HL DB JRC,TODEC1-$-1 and 255 ; Continue while Carry set DCR A ; Get rid of extra bump POP H ; Restore target string pointer MOV M,A ; Save digit CPI '0' ; Is the digit an ascii zero? DB JRNZ,NOZERO-$-1 ; No, Turn off leading 0's flag LDA DE$TO$HL$MODE ; Yes, Check leading 0's flag ORA A ; Convert leading 0's to blanks? DB JRZ,NOBLANK- HL ; ; Exit: ; HL = pointer ; ; Modifies: none ; PUSH PSW ; Save A register MOV A,M ; Get low byte of pointer INX H ; . MOV H,M ; Get high byte of pointer MOV L,A ; Pointer is now together POP PSW ; Restore A register RET ; and return GET$STRLEN ; Searches the string pointed to by HL and returns the string length ; to the next carriage return. The length is returned in B. PUSH D ; Save start of string MVI B,0 ; Clear counter TRY$NEXT$CHR: LDAX D ; Get character$-1 ; No, Leave digit alone MVI M,' ' ; Yes, Change digit to a blank DB JR,NOBLANK-$-1 ; All done for now NOZERO: XRA A ; Turn off leading 0's flag STA DE$TO$HL$MODE ; . NOBLANK: INX H ; Bump digit pointer RET ; and return ... DE$TO$HL$MODE: DB 0 ; "Convert 0's to blanks" flag DO$CRLF: ; ; [DC.27] ; ; This routine sends a carriage return and a line feed to the terminal, ; and then waits 'SLOW$TERM' ms for a slow terminal to catch up. ; ; Entry: ; none ; ; Exit: ; CR +  CPI CR ; Is it CR? JZ EOS$FOUND ; . CPI '$' ; Is it '$'? JZ EOS$FOUND ; . INR B ; No -- increment count and INX D ; . point to the next character JMP TRY$NEXT$CHR ; . EOS$FOUND: POP H ; CR or '$' found, recall orig ptr XCHG ; DE=orginial, HL=current RET ; and return GO$TABLE: ; ; [E2.05] ; ; Jump to a routine based on a table of pointers ; ; Entry: ; A = index into table ; HL = table base address ; ; Exit: ; Routine at (A*2)+HL is executed ; ; Modifies: ; " B, HL ; LXI B,2 ; Compute offset to table of routines CALL INDEX$TABLE ; . CALL GET$HL$PTR ; . PCHL ; Jump to proper routine HL$DIV$2: PUSH PSW XRA A MOV A,H RAR MOV H,A MOV A,L RAR MOV L,A POP PSW RET INDEX$TABLE: ; ; [E1.30] ; ; Computes offset to table given base address, entry length, and entry ; requested. ; ; Entry: ; A = entry # ; BC = table entry length ; HL = base address ; ; Exit: ; HL = address to entry ; ; Modifies: ; A, BC, HL ; ORA  ; Exit: ; The data is sent to the screen. ; ; Modifies: All registers ; MVI A,80H ; Set flush right mode DB JR,E$JUSTIFY-$-1; Jump to routine entry JUSTIFY$RAGGED: MVI A,00H ; Set ragged right mode E$JUSTIFY: STA J$MODE ; Save mode byte MVI A,'$' ; Mark start of buffer STA OUTBUF-1 ; . XCHG ; DE is usually print source J$NEXT$LINE: XRA A ; Clear character counter STA BLANK$LEN ; . MOV B,A ; . LXI D,OUTBUF ; Set up buffer pointer J$CHECK$CHR: MOV A,M ; Get characterA ; Set up flags for first check I$TBL$ADD: RZ ; If A=0, we're done DAD B ; Otherwise add length to base, DCR A ; . decrement counter, JMP I$TBL$ADD ; . and check again. IS$IT$OK: ; ; [E1.28] ; ; Check the character in A against the list of "OK" chrs pointed ; to by HL ; ; Entry: ; A = character to check ; HL = pointer to list of "OK" characters ; ; Exit: ; A = original character if ok, 0ffh if not in list ; B = position of character in list ; ; Modifies: ; BC ; PU CPI CR ; CR? DB JRNZ,J$NO$R-$-1 ; . CALL J$FLUSH$LINE ; . Flush output line, MVI A,CR ; . Output CR, CALL CON$CHR ; . . INX H ; . bump ptr & check next DB JR,J$NEXT$LINE-$-1 and 255 J$NO$R: CPI LF ; LF? DB JRNZ,J$NO$L-$-1 ; . CALL CON$CHR ; . Output LF, INX H ; . bump ptr & check next DB JR,J$CHECK$CHR-$-1 and 255 J$NO$L: CPI FF ; FF? DB JRNZ,J$NO$F-$-1 ; . CALL CLEAR$SCREEN ; . Clear screen, INX H ; . bump ptr & check next DB JR,J$CHECK$CHR-$-1 and 255 SH H ; Save original "OK" pointer MOV C,A ; Save chr to check against MVI B,0 ; Clear counter CPI ESC ; If chr is JZ I$CHR$OK ; . then automatically ok INR B ; . otherwise start counting at 1 I$CHK$NEXT: MOV A,M ; Get chr to check against ORA A ; End of table? JNZ I$NOT$EOT ; No, check chr DCR A ; Decrement to get 0ffh MOV B,A ; Stuff for later move JMP I$CHR$OK ; And exit I$NOT$EOT: CMP C ; Chrs match? JZ I$CHR$OK ; . Yes, return INX H ; . No, bump pointer  J$NO$F: CPI '$' ; End of string? DB JRNZ,J$NO$S-$-1 ; . CALL J$FLUSH$LINE ; . Flush output line, and RET ; . return to caller. J$NO$S: STAX D ; Not a special chr, save in buffer CPI ' ' ; Blank? DB JRNZ,J$NO$B-$-1 ; . No, don't save position SHLD BLANK$POS ; Save position for later XCHG ; and save corresponding position SHLD OUTBUF$BLANK ; . of the blank we just saved XCHG ; . in the output buffer MOV A,B ; . STA BLANK$LEN ; Save current length also J$NO$B: IN INR B ; . . and bump counter JMP I$CHK$NEXT ; . . and check next chr I$CHR$OK: MOV A,B ; Set status based on ORA A ; . position counter MOV A,C ; Get user chr back I$DONE: POP H ; and original "OK" pointer RET ; and return JUSTIFY: ; ; [E6.11] ; ; This routine will send a data stream to the console, with each line ; justified based on the SCREEN$WIDTH value. The stream must terminate ; with the CP/M end of string character ($) and may contain imbedded ; CR,LF pairs to sepR B ; Increment counter INX H ; . and input pointer INX D ; . and output pointer LDA SCREEN$WIDTH ; Compare counter against screen width SUB B ; . JP J$CHECK$CHR ; And continue checking if not past end ; ; Screen width exceeded, send this line to the screen. ; LHLD OUTBUF$BLANK ; Get pos of last blank in output buf MVI M,'$' ; and plug with eos ('$') LDA J$MODE ; Justify right edge only if the ORA A ; . right-justify flag is non-zero CM J$ADD$BLANKS ; . CALL J$SEND$BUFFER arate paragraphs. ; ; NOTE: To insure proper operation, the LF character should only follow ; a CR character or another LF character, as the CR character is used to ; flush the current line without justification. ; ; Two entry points are provided: ; JUSTIFY Justify output, flush right ; JUSTIFY$RAGGED Justify output, ragged right ; ; As of E6.11, the flush right routine was not installed, so either ; entry point will provide the same results. ; ; Entry: ; DE = pointer to line(s) to output ;; Output the line to the screen CALL DO$CRLF ; and a CR / LF LHLD BLANK$POS ; Get pointer to where we left off J$SKIP$BLANKS: INX H ; Bump pointer past blank(s) MOV A,M ; . CPI ' ' ; . DB JRZ,J$SKIP$BLANKS-$-1 and 255 JMP J$NEXT$LINE ; and check next segment J$FLUSH$LINE: ; Flush line when CR or EOS encountered MVI A,'$' ; Plug current position with EOS ($) STAX D ; . CALL J$SEND$BUFFER ; Send this line of data RET ; and return J$ADD$BLANKS: RET ; At a later time, " this routine will ; justify the right margin by inserting ; extra blanks in the output line. J$SEND$BUFFER: MOV A,B ; If line to output is of zero length, ORA A ; . then don't output the line. RZ ; . LXI D,OUTBUF ; Get address of output buffer CALL CON$MSG ; and call our print message routine RET ; return J$MODE DB 0 ; Current right justify mode BLANK$POS DW 0 ; Last blank on this line OUTBUF$BLANK DW 0 ; Last blank in the output buffer BLANK$LEN DB 0 ; Length of lineRNZ,P$NO$D-$-1 ; . MVI A,ESC ; . P$NO$D: CPI '_' ; Underscore = prompt anyway DB JRZ,P$DISP-$-1 ; . CALL TO$UPPER ; Convert the chr to upper case LHLD USER$OKLIST ; Get the user ok chr list CALL IS$IT$OK ; Check the chr against the ok list RP ; If ok, return XRA A ; Otherwise, cancel the cmd line STA CMD$LINE$CHRS ; . buffer and fall through to p$disp P$DISP: CALL JUSTIFY ; and call justify routine P$TRY$AGAIN: CALL CONIN$NE$XC ; Console input, no echo, except ^C CALL TO$ to the blank ; NOTE: OUTBUF is defined to be after the stack and before the heap. ; end of justify$output data area PROMPT: ; ; [E6.14] ; ; Prompt the user or the command line for input. ; ; Two entry points are provided: ; PROMPT standard entry, CRLF after chr from user ; PROMPT$NOLF special entry, No CRLF after chr from user ; ; When the command line is used for input, the following characters ; are translated to new values or new functions: ; ; Character New character or new funUPPER ; Convert the chr to upper case LHLD USER$OKLIST ; Get the user ok chr list CALL IS$IT$OK ; Check the chr against the ok list JM P$TRY$AGAIN ; Not there, try again CNZ CON$CHR ; Display chr we found PUSH PSW ; Check mode flag in case we need LDA PROMPT$MODE ; . to send a CR+LF after the DB BIT,BTST+B0+ZA ; . user's input CNZ DO$CRLF ; . POP PSW ; . RET ; and return PROMPT$MODE: DB 0 ; Prompt mode flag USER$OKLIST: DW 0 ; User 'ok' chr list ; end of PROMPT routine ction ; -------------- ------------------------------------ ; (space) Ignored ; , (comma) key ; . (period) key ; @ (at-sign) repeat existing command line ; _ (underscore) Prompt and get character from user ; ; Entry: ; DE = pointer to prompt string ; HL = pointer to list of valid chars (terminated with 00H) ; ; Exit: ; A = char from the user ; B = position of this character (0, 1, 2, ... n) ; ; Z = char was the escape key ; NZ = char was not the escape key ; ; Modifie PROMPT$DECIMAL: ; ; [E6.11] ; ; Prompt the user for a decimal input of up to 5 digits. The Z flag ; indicates the termination character: Z = ESC key, results may not ; be valid; NZ = RETURN key, results valid. ; ; Entry: ; DE = pointer to prompt string ; ; Exit: ; DE = Value entered by the user, 0-0FFFFH ; A = Low byte of value entered by the user, 0-0FFH ; ; Z = ESC key pressed, ignore results ; NZ = RETURN key pressed, results valid ; ; Modifies: ; A, PSW ; MVI A,01H ; Set CRLFs: ; PSW, BC ; MVI A,01H ; Set CRLF after chr DB JR,E$PROMPT-$-1 ; Jump to entry point PROMPT$NOLF: MVI A,00H ; Set no CRLF after chr E$PROMPT: STA PROMPT$MODE ; Save prompt mode flag SHLD USER$OKLIST ; . and user 'ok' chr list RE$PROMPT: LDA CMD$LINE$CHRS ; Are there any characters left from ORA A ; . the command line? DB JRZ,P$DISP-$-1 ; No, dsp text & get chr from bios DCR A ; Yes, reduce # of chrs by one STA CMD$LINE$CHRS ; . LHLD CMD$LINE$PTR ; Get command line chara after entry DB JR,E$PR$DEC-$-1 ; Jump to entry point PROMPT$DEC$NOLF: MVI A,00H ; Set no CRLF after entry E$PR$DEC: STA PROMPT$D$MODE ; Save prompt mode flag PUSH H ; Save original HL reigster PUSH B ; . and the BC register, too. XRA A ; Clear the current digit pointer MOV C,A ; Setup count in C register LXI H,SCRATCH ; Initialize the scratch pointer NEXT$DIGIT: PUSH B ; Save digit counter PUSH H ; . and string pointer LXI H,DEC$INPUT$OKC ; Get current 'ok' chrs CALL PROcter MOV A,M ; . INX H ; . SHLD CMD$LINE$PTR ; . CPI ' ' ; Ignore spaces DB JRZ,RE$PROMPT-$-1 and 255 CPI '@' ; @ = repeat cmd line DB JRNZ,P$NO$R-$-1 ; . LXI H,INBUF+2 ; Set command line pointer back SHLD CMD$LINE$PTR ; . to the beginning MVI A,07FH ; Set count of chrs to 127 STA CMD$LINE$CHRS ; . (the most it could be) DB JR,RE$PROMPT-$-1 and 255 P$NO$R: CPI ',' ; Change ',' to CR DB JRNZ,P$NO$C-$-1 ; . MVI A,CR ; . P$NO$C: CPI '.' ; Change '.' to ESC DB JMPT$NOLF ; Prompt for digit POP H ; Get string pointer back POP B ; . along with digit counter DB JRZ,ESCRTN-$-1 ; Return if ESC key hit CPI CR ; Check for return JZ CONVERT$STRING ; Convert string to decimal, if so CPI BS ; Check for backspace JZ BACKUP$DIGIT ; Back up 1 digit, if we can MOV B,A ; Save character for a moment MOV A,C ; Check digit count CPI 5 ; . JC ADD$DIGIT ; 5 digits or less, add to string LXI D,BLOT ; More than 5 digits, blot this one CALL CON$MSG ;#  . JMP DE$FOR$NEXT ; . ADD$DIGIT: INR C ; Otherwise bump digit count MOV M,B ; Save digit INX H ; Bump digit pointer JMP DE$FOR$NEXT ; Setup DE for next prompt BACKUP$DIGIT: MVI A,' ' ; Bump forward to clear digit CALL CON$CHR ; . XRA A ; Are we at the beginning? CMP C ; . JZ DE$FOR$NEXT ; Yes, don't backup MVI A,BS ; Backup to correct position CALL CON$CHR ; . DCX H ; Backup pointer 1 chr DCR C ; Push count 1 back, also DE$FOR$NEXT: LXI D,DEC$INPUT$MSG ; Setup  A ; Multiply previous by 10 ADD C ; x1 ADD A ; x2 ADD A ; x4 ADD C ; x5 ADD A ; x10 ADD B ; Add in new digit INX H ; Bump to next chr JMP STA$NEXT$CHR ; Go back for another digit NA$DIG: MOV A,C ; Get totals ORA A ; Set Z/NZ flag POP B ; Get old BC reg back RET ; Return with results in A. STR$TO$DE: ; ; [E5.26] ; ; Converts the string pointed to by HL to a number in the DE reg. ; The conversion will continue until the first non-numeric chr ; found. ; ; NOTfor next prompt JMP NEXT$DIGIT ; . CONVERT$STRING: MVI M,0 ; Mark end of string LXI H,SCRATCH ; Get beginning of string CALL STR$TO$DE ; Convert string to DE register MVI A,0FFH ; Insure NZ flag ORA A ; . MOV A,E ; Move low byte to A PUSH PSW ; Check mode flag to see if a LDA PROMPT$D$MODE ; . CR+LF should be sent after ORA A ; . the user's input CNZ DO$CRLF ; . POP PSW ; . ESCRTN: POP B ; Get old BC register back POP H ; . and original HL, as well. RET ; andE: a test for register overflow is not made. If HL points ; to a string whose numerical value is greater than 65535 (64K), ; inaccurate results will occur. ; ; Entry: ; HL = ptr to string ; ; Exit: ; DE = value of string in HL ; HL = next character to process ; ; Modifies: ; DE, HL ; ; PUSH PSW ; We need the A register PUSH B ; . and the BC register LXI D,0 ; Clear totals STN$NEXT$CHR: PUSH D ; Save results so far . . . POP B ; . MOV A,M ; Get chr CPI '0' ; Less than '0 return with result in HL & A DEC$INPUT$MSG: DB '$' ; Decimal input message DEC$INPUT$OKC: DB '0123456789' ; Decimal input 'ok' chrs DB BS,CR,0 ; . BLOT: DB BS,' ',BS,'$' ; Blot out digit SCRATCH: DB ' ',0 ; Max 5 digits PROMPT$D$MODE: DB 0 ; CRLF flag RET$TO$CONT: ; ; [E2.19] ; ; Prompts and waits for the RETURN key to be pressed. ; ; Entry: ; none ; ; Exit: ; Display message and wait for a RETURN key. ; ; Modifies: ; all ; LXI D,RTC$MSG ; Press RETURN to continue ...'? DB JRC,NO$DIG-$-1 ; Yes, finished CPI '9'+1 ; Greater than '9' DB JRNC,NO$DIG-$-1 ; Yes, finished SUI '0' ; No, convert to 0-9 MOV E,A ; Save this digit MVI D,0 ; . PUSH H ; Save ptr to input string LXI H,0 ; Multiply previous by 10 DAD B ; x1 DAD H ; x2 DAD H ; x4 DAD B ; x5 DAD H ; x10 DAD D ; Add in new digit XCHG ; Save results back to DE POP H ; Get input string ptr back INX H ; Bump to next chr JMP STN$NEXT$CHR ; Go back for another digit NO$DIG CALL CENTER$OUTPUT ; . LXI D,NO$MSG ; . LXI H,RTC$OKC ; . CALL PROMPT ; . [ CR ] RET RTC$MSG: DB 'Press the RETURN key to continue ...' NO$MSG: DB '$' RTC$OKC: DB CR,0 ; end of RET$TO$CONT routine STR$TO$A: ; ; [E5.26] ; ; Converts the string pointed to by HL to a number in the A reg. ; The conversion will continue until the first non-numeric chr ; found. ; ; NOTE: a test for register overflow is not made. If HL points ; to a string whose numerical value is greater than 2: POP B ; Get old BC reg back POP PSW ; . and old A reg as well. RET ; Return with results in DE. TO$UPPER: ; ; [E1.08] ; ; Convert the character in A to upper case. ; ; Entry: ; A = character to convert ; ; Exit: ; A = upper case character (if alpha) ; ; Modifies: ; A ; CPI 'z'+1 ; Convert to upper case JP UPPER$ALREADY ; . CPI 'a' ; . JM UPPER$ALREADY ; . ANI 5FH ; . UPPER$ALREADY: RET ; and return WAIT: ; Wait A ms ; ; Entry: ; milliseconds in A 55, inaccurate ; results will occur. ; ; Entry: ; HL = ptr to string ; ; Exit: ; A = value of string in HL ; HL = next character to process ; ; Modifies: ; A, HL ; PUSH B ; We need the BC register XRA A ; Clear totals STA$NEXT$CHR: MOV C,A ; Save results so far . . . MOV A,M ; Get chr CPI '0' ; Less than '0'? DB JRC,NA$DIG-$-1 ; Yes, finished CPI '9'+1 ; Greater than '9' DB JRNC,NA$DIG-$-1 ; Yes, finished SUI '0' ; No, convert to 0-9 MOV B,A ; Save this digit XRA ; ; Exit: ; time waited ; ; Modifies: A ; PUSH PSW MVI A,221 WAIT$2: DCR A JNZ WAIT$2 POP PSW DCR A JNZ WAIT RET * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Data area (use DS or EQU) * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; Replicated BIOS to make direct calls easier . . . LB$BIOS$TBL: LB$WBOOT DS 3 ; Warm boot LB$CONST DS 3 ; Console status LB$CONIN DS 3 ; Console input LB$CONOUT DS 3 ; Console output LB$LIS# TOUT DS 3 ; List output LB$PUNCH DS 3 ; Punch output LB$READER DS 3 ; Reader input LB$HOMDSK DS 3 ; Home disk (move to track 00) LB$SELDSK DS 3 ; Select disk drive LB$SETTRK DS 3 ; Select track number LB$SETSEC DS 3 ; Select sector number LB$SETDMA DS 3 ; Set DMA address LB$DSKREAD DS 3 ; Disk read LB$DSKWRITE DS 3 ; Disk write LB$LISTST DS 3 ; List status LB$SECTRN DS 3 ; Sector translate routine ; AMPRO-specific BIOS calls LB$GETNXT DS 3 ; Get bios ver & next tbl address LB$GETEDSK DS 3 ; Get pointer to E-disk storage LB$IOINIT DS 3 ; Set new I/O parameters LB$SCSIDRV DS 3 ; SCSI direct driver LB$LEN EQU $-LB$BIOS$TBL LB$XTBL: ; 'Extra' table definitions ... LB$SWAP$DRV DS 3 ; Swap two logical drives LB$HD$INFO DS 3 ; Get HD pointers LB$PHYTAB DS 3 ; Set/get phytab access LB$GETLOGICAL DS 3 ; Get logical device table entry LB$RESERVED DS 3 ; Reserved entry LB$XLEN EQU $-LB$XTBL DS 64 ; 32-level stack STACK: DS 2 ; Old stack pointer INBUF: DS 128 ; Command line input  of terminal (ADM 3A) DB ' ' ; . DB 'K'-'@' ; . Cursor up DB 'J'-'@' ; . Cursor down DB 'L'-'@' ; . Cursor right DB 'H'-'@' ; . Cursor left DB 00 ; . Clear screen delay DB 00 ; . Cursor motion delay DB 00 ; . Clear to EOL delay DB 1BH,'*',0 ; . (CL) Clear screen string DB 1BH,'=%+ %+ ',0 ; . (CM) Cursor motion string DB 1BH,'T',0 ; . (CE) Clear to EOL string DB 1BH,')',0 ; . (SO) Start hilite string DB 1BH,'(',0 ; . (SE) End hilite string DB 0 ; . (TI) Terminal inibuffer IBUFL: EQU 128 ; Input buffer length OBPLUG: DS 1 ; Start of outbuf ('$') OUTBUF: DS PWIDTH ; Output buffer OBUFL: EQU $-OUTBUF; Output buffer length HEAPPTR: DS 2 ; Pointer to next area HEAPLEN: DS 2 ; Length of next area HEAP: EQU $ ; Start of heap END START ry LB$XLEN EQU $-LB$XTBL DS 64 ; 32-level stack STACK: DS 2 ; Old stack pointer INBUF: DS 128 ; Command line input t string DB 0 ; . (TE) Terminal de-init string DB 0 ; ENVEND: ; End of environment and TCAP descriptors CMDSET: DW Z3CL+4 ; Point to first chr in cmd line buf DB Z3CLS ; Command line buffer size PATH: ; Initial path description DB '$',0 ; . Current drive, user 0 DB '$',15 ; . Current drive, user 15 DB 1,'$' ; . Drive A:, current user DB 1,0 ; . Drive A:, user 0 DB 1,15 ; . Drive A:, user 15 DB 0 ; (end of path) ENDIF ; ZCPR3 data DRIVE$TDATA: ; Drive type data DB 01H,02H,04H,08H DB 02H,00H,00H,00H LAST$SG EQU $ ORG BOOT UNINIT EQU $ MUNACT: DS 1 ; UNALLOCATED COUNT VALUE SEKDSK: DS 1 ;SEEK DISK NUMBER SEKTRK: DS 2 ;SEEK TRACK NUMBER SEKSEC: DS 1 ;SEEK SECTOR NUMBER HSTDSK: DS 1 ;HOST DISK NUMBER HSTTRK: DS 2 ;HOST TRACK NUMBER HSTSEC: DS 1 ;HOST SECTOR NUMBER CPMDSK: DS 1 ;SINGLE DENSITY DSK PARM CPMTRK: DS 2 ; AND TRK CPMSEC: DS 1 ; AND SECTOR 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 CPMSPT: DS 1 ; LOGICAL SECTORS PER TRACK SECMSK: DS 1 ; SECTOR MASK SECSHF: DS 1 ; SECTOR SHIFT INT$RETRIES: DS 1 ; Internal retry counter for RD & WR 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 1024 ;HOST BUFFER STATUS: DS 1 MESSAGE: DS 1 CMDPTR DS 2 DATPTR DS 2 LOGDSK DS 1 PHYDRV DS 1 DPHDRV DS 1 PHYTAG DS 2 PHYCMD DS 1 TAGDRV DS 1 TAGPHY DS 1 TAGTYP DS 1 TAGCTL DS 1 SCSI$IO$COUNT DS 1 SCSI$STAT$DAT DS 4 TARGET DS 1 LOGUNIT DS 1 CURDPB DS 2 ; AMPRO BIOS-SPECIFIC STORAGE IDSAVE: DS 6 ;READ ADDRESS BUFFER AREA LTRACK: DS 5 ;LAST FLOPPY TRACK ACCESSED LDISK: DS 1 ;LAST DISK SELECTED TRIES: DS 1 ;NUMBER OF TIMES TO DO IT RWHOST: DS 1 ;LOCAL REDS 0 CSVG: DS 0 CSVH: DS 0 CSVI: DS 0 CSVJ: DS 0 CSVK: DS 0 CSVL: DS 0 CSVM: DS 0 CSVN: DS 0 CSVO: DS 0 CSVP: DS 0 ; * * * * * * * * ; ; Hard disk allocation vector storage ; ; * * * * * * * * HD$ALV EQU (1279/8)+1 ; Maximum 1280 disk blocks ALVF: DS 0 ALVG: DS 0 ALVH: DS 0 ALVI: DS 0 ALVJ: DS 0 ALVK: DS 0 ALVL: DS 0 ALVM: DS 0 ALVN: DS 0 ALVO: DS 0 ALVP: DS 0 HD$CURRENT EQU $ ; Current Bios Buffer Area ptr ENDDATA EQU $ ; Mark the last avail.AD/WRITE FLAG HSTSID: DS 1 ;HOST DISK SIDE SELECT MASK TIMEOUT: DS 1 ;TIMEOUT LOOP COUNTER SECTOR: DS 1 ;TEMPORARY STORAGE CHGDSK: DS 1 ; Flag to tell if we changed drives FRWCMD: DS 1 ; FDC command FRWPTR: DS 2 ; FDC data pointer SAVE$CMDPTR: DS 2 ; SCSI command pointer save area SAVE$DATPTR: DS 2 ; SCSI data pointer save area ; SPECIAL E DISK PARAMETERS - FILLED IN WHEN E DISK IS ; FIRST SELECTED, AND USED IN DEBLOCKING. ESECADJ: DS 1 ;SECTOR NUMBER ADJUST FOR SIDE 1 IF  byte IF ZCPR3 ; RESERVE: EQU 0FD00H ; (0FD00H if ZCPR3) ENDIF ; IF NOT ZCPR3 ; RESERVE: EQU 00000H ; (00000H if no ZCPR3) ENDIF ; FDCSIZE: EQU (MAINEND-BIOS) + (LAST$SG-HDCODE) FDDSIZE: EQU FDATAEND-LAST$SG HDCSIZE: EQU HDCODE-MAINEND HDDSIZE: EQU ENDDATA-FDATAEND ; * * * * * * * * ; ; Show the available free space and the number of sectors needed ; to hold a SYSGEN image of CP/M with this BIOS: ; ; * * * * * * * * FREEMEM: EQU RESERVE-ENDDATA ; Free memory left BUFFKBD KEYBUF: DS BUFFSIZE ; allocate buffer space for 80 character KEYSTOP: EQU $ ; end of buffer address ENDIF DIRBUF: DS 128 ;DIRECTORY ACCESS BUFFER ; * * * * * * * * ; ; Floppy drive directory check vector storage ; ; The length of these vectors allows the use of up to 256 ; directory entries, all of which are checked by BDOS. ; ; Note that these are used for removable floppy media only. ; ; Do not change QPARM to increase the number of directory ; entries without adjustiSGSIZE: EQU (LAST$SG-CCP+127)/128 ; Sysgen size ; Number of sectors -- Must be 50H or less! END BIOS  no ZCPR3) ENDIF ; FDCSIZE: EQU (MAINEND-BIOS) + (LAST$SG-HDCODE) FDDSIZE: EQU FDATAEND-LAST$SG HDCSIZE: EQU HDCODE-MAINEND HDDSIZE: EQU ENDDATA-FDATAEND ; * * * * * * * * ; ; Show the available free space and the number of sectors needed ; to hold a SYSGEN image of CP/M with this BIOS: ; ; * * * * * * * * FREEMEM: EQU RESERVE-ENDDATA ; Free memory left ng the variable FD$CKS. ; ; * * * * * * * * FD$CKS EQU (255/4)+1 ; maximum of 256 directory entries CSVA: DS FD$CKS CSVB: DS FD$CKS CSVC: DS FD$CKS CSVD: DS FD$CKS CSVE: DS FD$CKS ; * * * * * * * * ; ; Floppy drive allocation vector storage ; ; This area is used by BDOS to map all CP/M blocks for the ; target disk drive, and is maintained to indicate which blocks ; on the disk are in use. ; ; The length of the Floppy area is set to 50 Bytes, which is ; enough to handle a 96 TPI DS/DD disk as described in QPARM. ; ; Do not change QPARM to increase storage without adjusting ; the variable FD$ALV. ; ; * * * * * * * * FD$ALV EQU (394/8)+1 ; maximum of 395 disk blocks ALVA: DS FD$ALV ALVB: DS FD$ALV ALVC: DS FD$ALV ALVD: DS FD$ALV ALVE: DS FD$ALV FDATAEND EQU $ HD$VECTORS: EQU $ ; HD check & allocation vectors ; * * * * * * * * ; ; Hard disk directory check vector storage ; ; No Check storage is required - just an address ; ; * * * * * * * * CSVF: $ % % & & ' '