CPM+ SYS CPM+ SYSD CCP COMFORMAT COMHELP COM8HELP HLPHELP HLP !"#$%&HELP HLP'()*+,-.HELP HLP/0123456HELP HLP789:;<=>HELP HLP?@CONF COMABCONF HLP/CDEKEYFIG COMKFGHIJKEYFIG HLPHKLMNOC1571 COMPCOPYSYS COMQMAC COM\RSTUVWRMAC COMjXYZ[\]^LINK COM{_`abcdefADDBIOS COMTRACE UTL HIST UTL SCREEN40COMPIP COMDSUBMIT COM*READ ME BNKBDOS3SPRjRESBDOS3SPRBNKBIOS3SPRJBDOS3 SPRMCPM3 LIB MODEBAUDLIBX6502 LIB%Z80 LIB/CXEQU LIBCXEQU LIBCX80 ASM5CXDISK ASMCXDISK ASMCXDISK ASMCXEM ASMPCXEXT ASMOCXINTR ASMCXINTR ASMCXIO ASMCXIO ASM@CXKEY ASMuCXKRNL ASMzCXKYCODEASMCXPRINTEASMCXRAMDSKASM&CXSCB ASMCXVT ASM   CXVT ASM  FAST8502ASMFAST8502ASMGENCPM DATCZ SUBMAKESYS DOCCPM3 LIB CXEQU LIB !"#$%CXEQU LIB&X6502 LIB%'()Z80 LIB0*+,CXROM02 ASM9-./0CXROM1 ASM12345678CXROM1 ASM29:;<CXROM80 ASM=>?@ABCDCXROM80 ASM\EFGHIJCXROMINTASMKLCXROMK ASMMNCXROM SUBOMAKEROM DOCPFORMAT ASMQRSTUVWXFORMAT ASMYZ[\]^_`FORMAT ASMhabcdefgCALLVERSASMhDUMP ASM ijECHOVERSASMkRANDOM ASMVlmnopqADDBIOS ASMArstuvF+Copyright (C) 1982, Digital ResearchnLT` BNKBIOS3 SPR F000 0C00 BNKBIOS3 SPR C800 1800 RESBDOS3 SPR EA00 0600 BNKBDOS3 SPR 9A00 2E00 58K TPA $$$$$F1F2dir dir F5F6F728 May 87 F9F10F11F16F17F18F19F20F21F22F23F24F25F26F27F28F29F30F31Help  33#wWWaAA44$zZZsSSeEE55%rRRdDD66&cCCfFFtTTxXX77'yYYgGG88(bBBhHHuUUvVV99)iII jJJ 000mMM kKK oOOnNN+++pPPlLL ---..>::[{@@@,,<###`***;;]}===~^^||//?\11!___ 022" ! qQQ🟟888555 222444777111+++--- 666999333000..."3DUfw ڷmBj?'^d( o@:f( ow"߾h(ݮ`( o2b( o @(y2 ~y# xzxy>2y2 xxy x( Pxyz2* : 2o  x( x2 $xy©( HYʪ Û2%>2y2ܯy >yxUy x: >@2xH :"A*a~<6,>w,}s >c2a!""A:y >yw!S~=2 !"A!6: :( 4((!"A>2:S2:2!"A:[/(>G:Z/G:U/怰Gx(2!6>=2 ">2!"A:2G*$(~wx2!"AxW(  ,>@)x  !>x(' (  > x < 2y2!"!O˶!"07>y( 2!S 2>!2>!S/y20x4nFw27!6"Aɯ2u!"A!"A>!= 6!"Aw:S"0>2!"0>8>2%!L5 !)"0!0"0:N0,!T"00:>M>2%!["0!b"0!y"0>2%:N >#w>=2z!s4,~< >vwo>w!"-> â>8!Ow!N"-:O!"0>2%>22>2%!O!"0:P2!O~w:N2L!"0!:N!l0!,"-: 2!#"-!"-Q!5"-Q!c"-:N80 0?:!O!l"-Q:O! :2Q!"-Rɯ!s5.O ˮ>C2Rɯ2R!>w>28 !O!"-!N"-ɯ2:N2K!"-!"-:s0!>w>2>2!"-!K5 "* 2=2 xxy xaNʹ%!MD5 :Rw͌!60:O >2R!u4~6v!"-:O!un~2Q>02y :y y:D< y2Dx2E"!91*x(%:D !:E ױ(:D !:E >2D:PRT2 6551 RS232   (Bx2'$ > 2G:aOx2a0 *#" x2 x2 x:2a( > 8'y :o"?!91*A*?:2Ͱ2C2:C"?*?KEYS 80COL 40COL PRT1 Aq˳99Ҝvʅq\˅˅˅˅˲ˆq˅˅˅˅˻#˅qʅq˗˗˗˗ ˗>X0_~#f6! :2~2/w x 2% BIOS Err on A: No CCP.COM file !!,!CCP COMͺ!ͨ*2 ͨ2x2"="A_>t,0>O+V!0 2~2w/ x ɯ2!"<(| **)>U | %~( O #>/<033O _ W{ !ͨ:AO !ͨ* ***)>&| h&)))~^U~g > >w^8^%**)>U2!"*"!!***)0&(K|loÈÍjQ>2Ã1Oj$|Ãà à ÃBB+"}{_}o>2~77ø~7"9:OG#Q{ozg# ""!2*%DM**ѵ+)) H~#+}#<:<ʲ<77:<ʢ=2(*f*(}DɯQ"(>QKQKQ>Q"%Q!*$K*"x!*!@$@hK\K:K ~#~ w*NK*NK^#V#N#F!x>QGQx3ڰbڼqҼo5p5"""*!yb! ~G*!NKկ2}!,"**NK6 :+OK2$^#V#N#FxNp:$p:Gjxj Y# A>QFQKK{<<ʽ! ~6 69BK! OSnLT`$Nwy!"(9"f1f! Ҕ2! ~#foCOPYRIGHT (C) 1982, DIGITAL RESEARCH 151282p tx|6TcrWINE VONk k *%DMy> y:yͻ( x*%DMxy( y*%DMx'E܁l"2!"u, ͷ!|  3.~ , e"n!| !"ͥn:<2 !x(!"!6 ERT :*( b  :*(*b!i a y* i a! i azȯ ߯y y!P  None P  None P  None Missing P  None P  None P  None P  None L(? KayPro II c(?Osborne DDK ? Slicer 9@ Epson Euro͡P  Epson QX10I ? IBM-8 SS I ? IBM-8 DS L(  KayPro IV p{O<2گ]!D/( ? "?( 9@ Epson QX10:8s O{22:"Ħ>H2:R=( =(=(=W@:0::-:/ 0:G!:_=2$(:(2:?2>2:N?2:G0ƀ<2_(.:(8G(8>O2?20 B:2:2B".P**s#r#"*,} !":G:(/:G#~2+~2 ##":ڐ2x2:*ڄg"*~2#~2#":G:( :2:G:x2A26.T!*Ͱ>xInsert Disk X in Drive A** ~G*+~( _<W*>2!"*)) 3>_>͘ :ڧ: ( (>>>C>͘N:; = :ڧ*"":++~G2#2<2~'k:G: >͘›կ_:ڧC>͘ hN%xy:|: F= :ڧ(xyk:G:U :=:=2@] w#N#F#=F:bڰw#s#r2bͿ*^#VV :G:< w!q"r6!>2> %:G xG(>G:G:*FG~x *s#r#"!4 :ڧʠ= #*q#~*+0 6$O.6>:ӯ2<2!"է.R<*+6 -*q#p `BF#~#fox2b"c(2b:G*+y 2!`"F>G (x8T*+x2y2> ("(@`8 {0 `[0ƀ>'\>B!PÀ:$O!l pG~!D/(:$O!l ~!(:*J!y*H!:4^w (~P~26#"xx! $ ̓x>@͋ ̀#= y(0!Dx G6 #ͣx! $ GWx̀#= _y(0.pG{@x(!D wͣ͋ ϦϦϵϵϼϼς*3"7/&"* * `" >2$> ͉>@y> ͉>y!" $>2$>yy(0x!D 6#= ͣddg )  @H8@x/O8 ϵϼKϦϾ=TtYy:*EQRW)(GBCDLrd*$## w <2$d _*$##V..ͼ.  T(0$,dddg0ЁO!]dd~  ;8#>!$!$2>O"$*#*$~#foy(!? !J( Wdg!`!s ~#fo!*$s#rd dG.4>@ >]͕؇_ͱx!y7j7?(6:$!!2$*_~G<}s >c2_x=(,:$ Oy :$-6h&))Oo*  ͸r:$<2$*$:$o|g~>2$>>t*$:$8#=2$~#( t:$ > j0:8G:$O<2$:$$ͱWyx + * +RDMbk#+6( * +ȯRDM* +T]+# wV :$ ><2$U:$(=2$:$<2$:2!,"#:"2">2$ͱ~a> 2$͊8ws)ͱ80G̯2$|!"$s)!+| !| ů]  f>2$>2$!~t#( ?Pause:"@2":$=:$(<2$.bf:2:2:2:Q2Q !"$x( * +#"$Ⱦ(#0րG.40֠G.6!*L_^#Vȍ:"2"¦H2$>:q$ ˷2q$>y y 2$y!Su!c"_"a6d*$| 1y xVEUPW:"z0.GF#~y2P!O:O#(:Q!Oˆ:OO>z>y*=>~y8*o*=}!k >͉(:q$2q$:"w : $G:$0&0>,6v,6v!:$(!:8>2_^#V#~2RY Q>yxyɢ  p8   G# (6>G^>:$oxyy!k "* ^#V#"^#V"! ^#V"!@i i a a>2??>~ 2O!s6T`y CP/M 3.0 On the Commodore 128 28 MAY 87 !@+0>42& %80 column display ">2D>2!"!Q Y Q Q Y Y Y Q2::O >>2!u  ~y+  >2"2N!"%!"H"J!O"L!`"&"&"&""%2i`z n&*&)~#fo*&)~#fo~#fo2 2ɯ BIOS Error on : T-, S-2:O :2 1 0!^#V#{(++~2 y2+V+^ cy2i&) ~#fo{ !~2 !~#foi`"i`"i`":ڗ>2#×:#<ï2#*=‡*":*}®:=::<>2*i^#V+ d!K*}@*)): K:) O "!w [O?WGzO:VxGyOGxwq*}}ʴ>2d:#>29ů2~2#!   )xð*}*}"*x"xm*^#V* s#r**s#r*:¾Y4Y̓**~#ng* s#r ^#V램a##)""xx!"""XC*~<*":¾!:·ľ*}*"x"*"g*3:= :Oi :=H:Gi a6:G/O**W :T=ҍ ïaʚ~6*:X)!:¾T>qk!:¾6>X*{Q:_2{2Ē"͂"X~<#cdfg!"()*N!r)!N!)z<*)"!":X*:w:¶w#:¶w*2*}D̓¡>2ͱԺ߹?~¾¾>w͙=2͜:wÚ~̓ʑpá!6NwͧBpͧÚgsr͐-͜ĩͤS)_ͤ̓~?w͐s-?F͜pN͆p# Þ͐*6!¿?~p*6 >2ͱݺԺ߹ͷw*oq͋"@6͚Xͤ͋͗wO~<:· g~w#w#6##)͋@ * g~?G++!o#~>T}! 6**#K"G*~ xr͐-xą@˷7(͚Sʀw :<RHͥ:·>~c!o#~E^#V)G#~#~!~ b k##N#F#^#V#~#fo~o2{2g*wޭʪҢÞ+}*#}o|g:O*s#r#w!~w/~@w//Hͥ*e>=)_g:0"ök*w)*c)-͐ͤÀk*s":;:r2͚Ϊù͚Ϊ·͚}/_|/*e¤W}_*c"e}o|g"c>2{—>2—͇ͱ* «>2͙wBp+ҽ:w͚AP{ 2W>O2ø͐R*e):r͚Ϊc2ZT͐-ڱ3͗@YsY̓Y׺Yͅ:߹Asҽ:@ҽ@ҽ$͚̓Aت=:<~?¯kü?~?ʾZT͐ڼ*>o"͒"!ì:Oݮ"Ý͐6͚ ~2Asv@NN~v$̓W+vw̚v$̓rrͅ:r߹>2+A@2r!Z2!"ög:2T͐-:ʹ>2<2ڱ!¾w: >2*6ݮݱO~<w:*)@ u:G*g`~!x_<_@*oy<:/G?~##~? 6K@?F6##N6⺯2p##q:#*~w>2*p@! ~*"v@*w# ) 6#̺͙N#FxT]## #~ ȷ  *4# ' 4! *~^ ^33G# Pv:dv6 y2@ !)#w*~"ҹ!Fw乨ҹ̓ҹ:w̚":>彯2̓*~wć"̀!~$6:03i"!~6*e>=)Q!QX@˷ >2 ˷!!q#p#w2wW*e_3ҫ-!s:!¾xQ*:<œ. ʩ.ʩAܧrr##sܧ<}rcN! ~态O>G~G!~G~o>_yG~.|°! w:ck[!x?[! ~ʤ͆[͗PPvqO-á=.:<ʰ! Vq##~_@wͶ:WMںʛ>úͶ >TJ:!¦ʷ͞x!¾Ƕw4 ϶PW޶PܧÂէÂ*!!~~#~O~#FsO s#r:(„y==„*!^W*y^#Vx7=2wͼկw#KWK*"J T͞*:¥["+SX:ڜq:ʺ!ʵ>2ܧͤ2ѵO ̩DM͸}޵>r""¯2:2* :·::29:·>:·>*ڈ>F6:_/G:·ʧ:¢ڨ|OͤG:¸_O̩̩zW{´|:·*}|BKN´ zyG:!¾vq:vէvMڂ?Ͷ >T͓Â!">Â:G:O:h=27ryy/W!:l=:<>w##~2 4~?ɳ¹:<ɳɳüޱAX2rK:w++~=wv4͗O5:2X!"*>o+"! *!b"ݮ": r#~?w#>r# L=J Lv wbܧ?~O ͆ڳ†wŒ~è# # x ͗w ٲڲٲڲw@ ~wb͐Úݬ!x>w~6:·6~#+w#w+~;wɯ2KOFq-yl?Npg:·ʓ~( ˆʀHÈ2xą ):@αO~#w͚ʀôb_++V@* )͗Os++r~Gw#* #~$%+@*9>  #>? ;*~ w-xąH"0 *ĊHEʀ@~›:6¦w͚̋ÇPY*{zBKNyʺ Nú2: *~w *" ݮ2>ʄ@~k:(s~*9~Ês~Ժ~ͅ<G:<ޯ2x# W:<­:22G?>Grx~:·2Ô##~*$*">2̀2kºʺ**iҺ@:O~2~WW:2Ôyʛ?ʔx ʔ |̷ǯÔN:r:/GyOOA +¬ ¢y2:·x¹o&:W>OͫE:¸ڟ?N/*"y2ͦ>2 ݮwޭDM*w6# x *ow**ws#r̀*i6#6*}"w@*|<ď>!8>8> t>nͦv8 ~*ownT] KKͦޭ*w"wͦ"w@ :·íNɭ N#Fyح*}|h#ð*ͫ# 6RX*q¾6!"@**#":&2·͒:È0:+Òy<_W`iͫDM*w ~bNpwޭDM*we ^#V#~2>â9͆>!"*y³*X*ÿ͂"*g*K!~<:wb##>w#wĩ> r!~#22Zw*q>ww:c *#*is#r*:!:)e:O!*c:Oͫ}@2æ ~á*g:…o$*~K6?~wKw**i{#zir+s{O:w:Ғ4~:w?r##rp# ä |g}oì*g #G ¾1*q¾:·*w***> r 2":O:¡G2!¶w*~zWw+ !z?#~*!* *G!O~2~m͗O~t>2?:¦2g͝DM*0MD"!*MD$:Oë!N:· «G>O: ©ù*ĩ :·کn` ~#foͤ2O̩"}:O*¯"!s#r#p*kN#F*m^#V#F*:O}|y9*+"*}|yP#9**DM"*ks#r*ms#r#pyox*kw#w*mw#w#w>2'å2*OͶyڲò<*eͲ:0!:¾:·ò2*>*ͫ"ª4#4#4)7 #  w#*J|^#V#"i##"k##"m###"o#"q##"!s )*s!)*|!6~67rrorFile Exists? in Filenameòò>2a.":2:<:55;:2ɯ22{_zW{_zW )7CP/M Error On : Disk I/OInvalid DriveRead/Only FileRead/Only DiskPassword E)"!z<~rs^#V#N#FxN:oʲ̀õ(# Þry< <<%zrͷr6r9rMDÌ:o!6!h: ʚnt2 r62>rz<*9ʌ^: ~x ):*:ţţ>*(+"(w++2+2+ɟp؟!" >2+2*jx.#NzW::!2W!5=^x^z:m:*;#wO:͂^2¢ů͠Ģ:!ڽ*(~ݠנ5Wèբ؟jנM2ͨx΢*(+w"(j͞ !%"(^-:*$P:<\:W:2xM s:<9>2:*9x~+q’x2:**&~2+o#"&!+6Mš:W:2x ͺ*(+"(w  :ܡ>2*2:*(:+w"(ͺ:G::+̜2 5*(~o#"(Mš*(~`Uoj*(~#"(Ñ!*~6s!+6:+‚xoڊ{2Ó#w:2.+:.2-!%"(2*!¥"&!*~4:2-Ԃ:Gͳͨ^2+>2:2*N#G2 2GH)+6:2,:!- ͞:,!͞+*(~L#Bxz:*:*(~ʓOr ͞ ͞! O(Ì*(~2**}ʷ!#¶!""÷:_:*(#wΟxH!¥)6"&:!¥ x5~y 5 6y(^͞@O:=7:͞y ͞:I ͞:=e: zz#͂͞:! ͞ G:Ҏ>xʝʝw>ɯw̩z:»!>wɯ:=zxzz::G:=/ͽx:Āy!4 šn!6@G:x: P:<: P n6 t6! ^6 t6u:)<͠^!Ó*"r*r"ÿ<:g:!͐*f}D! ~6t!rͷ֝O(^ƝƝƝ  :Function = File = !,!"h!9"f! ͉:2t™:!=Hgo:O*;*͂:A2=/::0! dگ61#d ڸïp#:w#6 !6:6 *#!)6.#)͂ O(BDOS > wM  2*7w#6?#7 .,:;[]=<>|!?]45#Ra{i_p# l s s l ls:¬MA L.&]&&&'''N'''4& (#( *ll  iG&l&xIݩ, `) *$ Ơ0 , ܮ0x 0)Ъ 0 0)` 0 !`Iݩ, ` ܭ ݩhhhh@0U0Le USER command sets the current user number. The disk directory can be divided into distinct groups according to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> ThLOADER y; !91""|0!~ʞz=_: _* ""*og*%|}D S#N#F:ʒ#4ʝ^#V{‚:¿*.~w*DM!&_*.& >k s#rr+6.""1*D`.45. F.~. ^#Vx>`. s#rz 6#N#fi%$g1:=<@v_}v=p{_3;{<g"T=X3*j ~P#~R#~L{gbk#N#Fk$&Zcx {~#o}o1!;!"Ï:= w*wWx ~#&*.~s*"ѷ\ Cannot load Program 221282 COPYR '82 DRI <bHA$@DH   A@!" $$@1-! j 1".~2.~2 :Xck*kͮ  b < .~=>$.w.6#w.6#w.61.~  .~~w@.p T~º>+~.~~! yͮ Ë.~~w2g !PROFILE.S !+2 !  +~d {   O! w+w+: =w! 5 c ʋ  :p  m>> ͧ  N Ĩ –.~+w.~2  9 : ! ~##~ !7 : !Կ : x*l " !ZXچ! 6  zz: 6 : %2p  ͆ : =̀ 2r  DIR TYPE ERASE RENAME DIRSYS USER u"Q}:\=p:r Aæ R ÂN ͙ʸ} !M 545 x ]  ̵ 6 : oG! ~怹>2M  xf>:ͦ ͤ ͍ ͤ f ¹2 lf   ͫR  L͞L I *  *  A }_Yl !ͮ ͒6 \&đ %* "l ͍  ûȷ45: w ? A I N   SUBMIT COM ! ͮ ! 6 #"l  !cͿ  O!:r :ͦ ͍ !~B I !pͰ ^#VCOM SUB PRL y!cͰ  î !" * %.2P#ͮ !g 4*l +"l ͷ 2 "Qx2Sl "Tx2V!q ~ :p ͆ .ڶ2* og$2| .w#w#w#w.~ .w#w~?w; ; ! ~#49 w#~$ A  < > _I  ! 6 ! ~#Ͱ 6 m   _  ! 6=  { *.pѯ:r x , \<=!Ͱ =ɯ2 \s 2 ! D ;! : .44 #4"l ~[* 2 a7 {7 w!Y #! *l "l " ~ U #D ]T!̷ 6*%.w#w!} 6 r 6 #w.6#6 #t#6.wo*.s#r.rͧ ̧ m . ^#V45+ w#w.f.5\A "l " l |F# !( | !( : x. +"l ! ͮ   ͮ ~!G8 * ~;#1 կA *l ~:g X #I ѯ*l  *l ~0څ :҅ q X x<Ü AX QX X ~@#~:k #^ *jT~# ® wy#ù ! 4 : !Ͱ ~@*h~ yw y/w*hw*h~I E> ͦ > æ % 0  < : ~ȹͦ #* A !g ~6*  * >? A *l " ~0: :: q "l x~0 xG#Gs : &͘ ͤ &ͦ %˜ >  Ʌo$>?· !  > # ͮ x> # ~ Enter User #: $No File$ required$ERASE $ (Y/N)? $ Press RETURN to Continue $ (User 0)$NON-SYSTEM FILE(S) EXIST$: $$$ SUBL3),3* ( i(L{'I- -) f( I& {' ` ( f( I&) I&)  I&)ݭ $L ( *  1 .( ) L L0) ( ))* )$ )x? 2L.( 7&x> L.&]&&&'''N'''4& (#( *ll  iG&l&xIݩ, `) *$ Ơ0 , ܮ0x 0)Ъ 0 0)` 0 !`Iݩ, ` ܭ ݩhhhh@0U0Le USER command sets the current user number. The disk directory can be divided into distinct groups according to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> Th1*W"@L1|`2] C128 CP/M FORMAT PROGRAM 08 JUNE 19878GO > 22x2ZA22u2jʪ:!!41(.8:( ( (.7"Drive A is a 15x1>1:487ZPlease select disk type to formatCommodore 1581 (Double Sided)Write system track onlySelect Different Drive> 2> 2c Please select disk type to formatC128 Double sidedC128 Single sidedC64 Single sidedIBM Single SidedIBM Double SidedKAYPRO IIKAYPRO IVEPSON QX10OSBORNE DDSelect Different Drive>2> 2c8=.3$)Please select disk type to formatC128 single sidedC64 single sidedSelect Different Drive> 2> 2cPlease select drive you wish to format withDrive ADrive BDrive CDrive D>2> 2cY!0!+!k &!+ !!! ! !  ! !. !? "Insert diskette TO BE FORMATTEDin drive A. Type $ when ready,any other key to abort Sx ‘..formatting diskette in drive A*.^.^K.z<ʒ{2bz2j..writing sector .~#9.3BK.. u .8K.!N :2>.?  format error  Do you want to format another disk?B].....exiting format program   "Are you sure? [ ]B8"-^#V#zz!"rw X+j 0 >0w>.?Gxp`hP"Disk write error ͼ 2>~_#<(ͼ͵) #)).. .: }o>Sx7'ͱ>?(2SxC̝:G:Go&)~##(++~#fox:&8:G:(<2:G:(=2:2:2&@7W!"2. + +x<2W|2!":G*F#~#"g:O.@/xS7T$    @Formatting C128 CP/M on C1581P ' ' ' ' ' Formatting C128 CP/M on C1581' ' ' ' ' C64 single sidedX  I I I I I I I I C128 Single SidedX  I I  I  I I I I I  C128 Double SidedX  I I I I I I  I  I  I  I I I I I I I  5 EPSON QX10 512 byte sectors] OSBORNE Double Densityd KAYPRO IIk KAYPRO IVk r IBM SSy L IBM DS T O &80f' F'F' V' F'f' (D80@D80@(COPYRIGHT CBM 86MHH \   >KMBE$t $t AHCP/M PLUS652A!$~G#} | pCBMx >ÍLxFGmLZɀ (  FGL(DCP/M PLUS803DCBMx ?! 﨑 ! h ' k ' m Í>L!   ,  !)`xIݩ, `0U0L1w<>?2!60!>22!  ~y+  >E >y>2$>2 $ͽ>2$& BOOTING CP/M PLUS>y>@2@"Tf* =  #25< <:5<(<=€* * <|*<|(*<|Í͢͵ ^{)"<+f.!<*<!"<*<+"<}!4"*<^#V#"<)):2##>20 R0yN8< >0> 2y2Ox 0x>LحUТ0  h1  *`, ,L 0 0 111 ! Ơ0 , ܮ0x 0)Ъ 0 0)` 0 !`Iݩ, ` ܭ ݩhhhh@0U0Le USER command sets the current user number. The disk directory can be divided into distinct groups according to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> Th1?:P2ÄCP/M Version 3.0COPYRIGHT 1982, DIGITAL RESEARCH151282654321 ERROR: $ $ Press RETURN to continue $ $Reading HELP.HLP index.$Too many entries in Index Table. Not enough memory.$ $ Creating HELP.HLP....$$ HELP DATHELP.DAT not on current drive.$Too many entries in Index Table. Not enough memory.$$ HELP HLPUnable to Make HELP.HLP.$Writing file HELP.HLP.$Writing file HELP.HLP.$Closing file HELP.DAT.$Closing file HELP.HLP.$HELP.HLP created $ Extracting data....$HELP HLPUnable to find file HELP.HLP.$HELP DATUnable to Make HELP.DAT.$Writing file HELP.DAT.$Unable to Close HELP.HLP.$Unable to Close HELP.DAT.$Extraction complete HELP.DAT created $ Topics available:$ ENTER .subtopic FOR INFORMATION ON THE FOLLOWING SUBTOPICS:$ $ $ $Reading file HELP.HLP.$ HELP> $Requires CP/M Version 3$,HELP HLP HELP UTILITY V1.1 At "HELP>" enter topic {,subtopic}... EXAMPLE: HELP> DIR EXAMPLES $? HELP Topic:$Not found$No HELP.HLP file on the default drive.$1?1?!E6!,6͈"-*-|*-}0HҷN1=2/1<_! p{201!C6!C6ͷ 2j:A+::BJ: \u\͡2 :?/;1X:j\!)6X!,62j:j&!)61x͛zdʛ͚=x͛˜!)6,V 2E H:E/ ,V 2E:E/ IX,V 2E H*jM.,V 2E H,V 2E HPX,V 2E H!)6:E/2j\\2D:ZNEv!Kq*K&!Mp+q*L !Op+q*N !Pq*P& !Rp+q*Q!Tp+q *S 6 *S 6*S!Vp+q*U!Xp+q*W!Zp+q*Y!\p+q *[ 6 *[ 6*[!^p+q*]!!`p+q*_!bp+q*a$!er+s+qX*dDMXX:ctE!jr+s+p+q+q*f*gDM*i -’!nr+s+p+q!o6#6:p *p&*k~ H *p&*k*p&*m  *p&*k*p&*m !o6 !o6!p6 :p<2pí:o!qq:q<2q>!qR \H !q6R !E6!q6:q!sp+q!t6:@/!C *r~<*rwO:/ X*r6*r~ž x*rwÉ X*r~½ \*rwE *r~ !t6*r6  H *r6 H:tͼ"u*u"w!{6!"y:{/>!wH҇ >y)))) DM%\O \o&"yN*y)))) ~$e !{6:{/҄ >w+s#r*y"y %>w:{/HҶ \o&"yN!|6:! !|6:!| *|& ~ *|& 6 *|& ~, *|& 6 :|<2| !|6!:|*|& ~ HA :|<2| *|& ~.d :)2}*|& 6 i !}6:}2|> !|ڛ *|&͏x u:|<2|o :}2|!~6!6#6*~& ~:/H! *~& ~  !6*~& ~ *~& ~[H*~& ~H: :| HHҥ *~& >`*~& ~{Hp *~& ~ *|&͏x *& HqÔ *~& *|&͏x *& w:~<2~:<2 :|<2|> !|! !6 *~& ~[ :|=o&͏x ~ :|=2|*|&͏x 6[:~<2~:|<2|!6 :~<2~î !?6#6#6#6>!|'!6: '*&͏x ~[*&͏ ~C !A6:|==2|*&͏ ~E¤ !B6:|==2|*&͏ ~N !@6:|==2|*&͏ ~L !?6#6:|==2|*&͏ ~ :|==2|:|=2|!6 :<2= :|&X!6>!` *&)))) >u:<26!6>#w#6ͼ"*" \Ju\͡WN!E6:E/\H"!6:ր:E/H*& ~!E6*& ~/!6:E/*& ~/H**M! 2:<2::E/H*& ~0*))))  w*M! 2!6: :E/H*& ~ H*& >`*& ~{H*& ~ *)))) *& w*& *)))) *& w*M! 2:<2i:E/\5*))))  }u*))))  #~u*))))  N#F *))))  q#p*))))  :w*#"*!p>ͭ:<2>+s#r>:E/H\2vN*"*! *)))) u*"*M! 2þâ%:<2 u͑lF2F͑\2NfuF2!"*+!*))))  :d*))))  q#p*"҇!":=!6!ͣ DM%)2͑F2F͑\2N*"|u\2!E6:E/!"*":E/>!HҴ!ͣ DM%\ʝ!E6ñ>+s#r*#"d!"*+!!ͣ DM%2͑\2N*"ҺP\02NC*NBXUX \ku\͡oxN FuF͑F\2N%!6\2:/H:Y$!6è!E6:!E6F2ͼ":E/ҽ!"*":E/>!H]!ͣ DM%\F!E6Z>+s#r*#" !"*+!ں!ͣ DM%FʭF2F͑\2N*"c\NFF͑NX!"}22:)<2: ,:)!"#**"!"1!6*"!":/G*)))) ~$^!6D*))))  :!:/Ұ!6,V 2:›0XáCX,V 2X**0&p>ͭ,V 2 H!6> !*& 6 :<2!6$ *)))) DMuX*#"=*))))  ~!=!6*#"=:],V 2X%!6#6!6#6!":/:/HҼ*)))) ~$ʴ*))))  :)<{*)&͏x *)))) ͛2:q *)))) *)&͏x u:)<2):/:)2!6>!)n&͏x ~ H*)&͏x ~[Hb!6!6n*#"!6x*#"ñ:Ҫ*))))  :Ң*#"ç!6ñ*#"ù!6z:**#"**))))  DM}u*))))  #DM~u!6*))))  ~2D*))))  ~2):!q!6!::E/Hҙ,V 2E:E/Җ!6:!{X:<2a*&͏x DMX:<27 H*)M.:E/ҷ,V 2E:E/\\2DN!6:/:E/H\H:D=2:<2O>/:/H*& ~29!E6!6:/:E/H:*& ~/HHҗ:<2*M! 2*& :=O! w>:§!6ò*& 6$:E/:/H: :@/H,V 2E*MH>!X!6 !D6!E6u,V 2Xh*& 6!,6ͷ 2::?/H_1X:_ogDM!>))덑o|g҉ =wDM!>))Ҟ =–^#V) §_{ozgi`N#Fogo&og_{_z#W $C128_CP/M  COMMAND_LINE`DISK_STATUS KEYBRD_DEFS 6ALPHNUM_KYS $ARROW_KEYS *EXTRA_KEYS 1MFM_FORMATS 8IRT_SHFT_FNCTC\MODE_TOGGLE IBSTRING_EDIT QHEX_EDIT VBSPECIAL_FNCTZVIRTUAL_DISKaaCOMMANDS ekCONVENTIONS iCNTRLCHARS paCOPYSYS 1DATE MEXAMPLES DEVICE #OPTIONS mEXAMPLES uC128_DEVICESCDIR uBUILT-IN wEXAMPLES 4WITHOPTIONS JOPTIONS EXAMPLES DUMP 2ED lCOMMANDS XEXAMPLES ERASE OPTION EXAMPLES FILESPEC *GENCOM OPTIONS 9EXAMPLES GET 2OPTIONS EXAMPLES 8HELP  HEXCOM #{INITDIR '?KEYFIG *JEDITING_KEYS/=EDIT_COLORS 6 EDIT_HEX ;vEDIT_SPECIALA{EDIT_STRINGSDFINISHING_UPJOFOR_EXPERTS PKEY_VALUES YLOG/PHY_CLRS_&SELECT_A_KEYeSETTING_UP kEWHAT_TO_DO pnLIB wOPTIONS <MODIFIERS EXAMPLES ,LINK OPTIONS dEXAMPLES  MAC EXAMPLES QOPTIONS PATCH RPIP (COPY) 8EXAMPLES +OPTIONS PUT OPTIONS BEXAMPLES "RENAME .EXAMPLES  RMAC kOPTIONS GEXAMPLE QSAVE oEXAMPLE SET }LABEL TEXAMPLES _PASSWORDS WMODES ATTRIBUTES EXAMPLES $DEFAULT )NTIME-STAMPS *zOPTIONS -"EXAMPLES 4SDRIVES 5)SETDEF 6BEXAMPLES <bSHOW BLEXAMPLES EeSID JwCOMMANDS NWEXAMPLES rZUTILITIES tjSUBMIT {)SUBFILE }EXECUTE PROFILE.SUB TYPE EXAMPLES <USER >EXAMPLES OXREF  $ $ uU$ $ )C$ < u$ $ < s///1C128_CP/M CP/M On The Commodore 128 Some miscellaneous keyboard and screen features/functions are provided with CP/M on the Commodore 128. These include such things as a selectively displayed disk status line, a virtual disk drive, local/remote handling of keyboard codes, programmable function keys (strings), and a number of additional functions/characters that are assigned to various keys. ///2Command_Line Keys For Processing CP/M Command Line The key labelled CRSR with up and down arrows (bottom right on keyboard) generates the value 17 (same as 'CONTROL w') and causes the latest CP/M command line to be displayed on the screen. The key next to this (CRSR with right and left arrows) allows you to move right and left (unshifted and shifted, respectively) through this command string to edit. This is useful for correcting typing mistakes in lengthy command sequences. ///2Disk_Status Selectively Displayed Disk Status Line There is an optional disk status displayed at the bottom right corner of the screen. The format of this status line is as follows: O Dtt ss where O =Operation, either R or W indicating a Read or Write D =the physical drive address (A,B,C,D) tt=the track number currently being read or written ss=the sector number currently being read or written Normally, the track and sector number are separated by a space. If the disk is formatted MFM, and the track and sector are separated by a '-', the second side of the disk is currently being accessed. You can toggle this status to be displayed or not by typing the RUNSTOP key and the control key simultaneously. ///2Keybrd_Defs Keyboard Definitions The Commodore 128 Keyboard is defined for CP/M as follows: Each key has 4 values associated with it. These are defined as the unshifted, value, the shifted value, the control value and the CAPS LOCK value. The UNSHIFTED value is basically the key as labelled, and is produced by typing the key; the SHIFTED value represents the key, as labelled, when typed with one of the SHIFT keys on either side of the space bar; the CONTROL value is the value produced by typing the key and the CONTROL key simultaneously; the CAPS LOCK value is the value produced when in COMMODORE mode. (COMMODORE mode is entered by typing the COMMODORE key and remains in effect until this key is typed again. This value is therefore typically documented as the COMMODORE value.) ///3AlphNum_Kys AlphaNumeric Keys The alpha keys generate the standard lower case, upper case and control values. The COMMODORE value is merely the upper case value. The numeric keys (the row of keys above the alpha keys) produce the appropriate number as the unshifted value and the COMMODORE value, the symbol above the number on the key as the shifted value and the color on the side of the key (the top one of the two colors shown) as the control value. These colors are defined as 80 column foreground colors. The control value produced by the numbers on the numeric keypad are defined the same as those on the numeric keys, except that they generate 80 column background colors. ///3Arrow_Keys Arrow Keys The up arrow key generates the value 05 (same as 'CONTROLe') as the unshifted, shifted and COMMODORE values; it generates the hexadecimal 12 (same as 'CONTROLr') as the control value. The down arrow key generates the hexadecimal value 18 (same as 'CONTROLx') as the unshiftd, shifted and COMMODORE values; it generates the value 03 (same as 'CONTROLc') as the control value. The left arrow key generates the hexadecimal value 14 (same as 'CONTROLs') as the unshifted, shifted and COMMODORE values; it executes the 40 column screen left function as the control value. The right arrow key generates the value 04 (same as 'CONTROLd') as the unshifted, shifted and COMMODORE values; it executes the 40 column screen right functions as the control value. ///3Extra_Keys Additional Key Characters The key labelled as a British pound sign generates the character '#' as the unshifted, shifted and COMMODORE values; the character '`' is generated as the control value. The up arrow key next to the RESTORE key generates the character '^' as the shifted and control values; the character '|' is generated as the unshifted and COMMODORE values. The '=' key generates the character '=' as the unshifted, shifted and COMMODORE values; the character '~' is generated as the control value. The '/' key generates the character '/' as the unshifted, shifted and COMMODORE values; the character '\' is generated as the control value. The key labelled 'INST DEL' generates the hexadecimal value 7f (ASCII rubout) as the unshifted, shifted and COMMODORE values; the hexadecimal value 16 (same as 'CONTROL v' is generated as the control value. ///2MFM_Formats MFM Disk Formats A variety of double density MFM disk formats is supported (for reading and/or writing) including: Epson QX10 (512 byte sectors, double sided, 10 sectors per track) IBM-8 SS (CP/M 86) (512 byte sectors, single sided, 8 sectors per track) IBM-8 DS (CP/M 86) (512 byte sectors, double sided, 8 sectors per track) KayPro II (512 byte sectors, single sided, 10 sectors per track) KayPro IV (512 byte sectors, double sided, 10 sectors per track) Osborne DD (1024 byte sectors, single sided, 5 sectors per track) When you insert one of these diskettes into the disk drive and try to access it, the system senses the type of disk with respect to the number of bytes per sector and the number of sectors per track. If the disk format is not unique, a box is displayed near the bottom left corner of the screen, showing which disk type you are accessing. The system requires you to select the specific disk type by scrolling through the choices given in this window. Note: The choices are given one at a time; scroll through using the right and left arrow keys. Type return when the disk type that you know is in the disk drive is displayed. Typing CONTROL RETURN will lock this disk format so that you will not be forced to reselect each time you access the disk drive. ///2Rt_SHFT_Fnct Control/Right SHIFT Functions There are 3 functions which are selected by typing the CONTROL key, the RIGHT SHIFT key (the SHIFT key to the right of the space bar) and the appropriate key for the desired function simultaneously. The 3 keys to enable the desired functions are: the key labelled ALT, which is used to select between remote and local handling of certain key values, the right arrow key which is used to initiate editing function keys, and the left arrow key, which is used to initiate replacement of key values with a hexadecimal value. The last 2 functions allow you to edit key definitions directly, without using the KEYFIG program. ///3Mode_Toggle Mode Toggle The key labelled ALT is used to toggle between handling certain functions at the keyboard level or passing the appropriate key code to a remote application for processing. These functions include all hexadecimal key values between 80 and ff. These are defined as follows: 80-9f identify function strings a0-af identify 80 column foreground colors b0-bf identify 80 column background colors c0-cf identify 40 column foreground colors d0-df identify 40 column background colors e0-ef identify 40 column border colors f0-ff identify special functions The default mode is that these keycodes are handled locally. In this mode, the functions as defined above are executed. If remote handling of these codes is selected, the appropriate keycode (80-ff) is passed along to a remote application which processes it however it wishes. ///3String_Edit String Edit To edit a string type the CONTROL KEY, the RIGHT SHIFT key and the RIGHT ARROW key simultaneously, then type the key to which you want to assign the string. Note that the key you pick must already have a string value (80- 9F) assigned to it. A window will pop up at the bottom of the screen, in which you will edit. Type the string and type CONTROL, RIGHT SHIFT, RETURN to exit. For editing, you can use CONTROL, RIGHT SHIFT, RIGHT ARROW or LEFT ARROW to move right or left through the string and CONTROL RIGHT SHIFT + or - to insert or delete a character respectively. ///3Hex_Edit Editing the Hexadecimal Value of a Key To assign a single hex value, type CONTROL,RIGHT SHIFT and LEFT ARROW key simultaneously. Tyoe the key you want to modify. A window will pop up at the bottom of the screen showing the current hex value, per the current mode (unshifted, shifted, COMMODORE or control). Enter the new hex value. NOTE that any illegal key will abort the edit without modifying the key. ///2Special_Fnct Keys Initiating Special Functions The key labelled NO SCROLL executes a PAUSE function. This has the same effect as typing control-s for pausing to read screen dumps. The control value of the NO SCROLL key toggles between two modes (on/off) of automatically tracking the CP/M screen on a 40 column monitor. The right and left arrows at the top of the keyboard initiate the special functions screen right and screen left respectively (40 column screen tracking) as their unshifted, shifted and COMMODORE values. The key labelled ENTER generates a Carriage Return as the unshifted, shifted and COMMODORE values. The control value initiates the special function boot, which reboots the system. The key labelled RUN STOP is undefined as its unshifted, shifted and COMMODORE values, and toggles the display/nondisplay of the disk status line as its control value. ///2Virtual_Disk Virtual Disk Drive The physical disk drive A can be used as drive A or as virtual disk drive E. Whenever you access drive E (for example by doing DIR E:), the system will prompt you to put a diskette in drive E (respond by putting whatever diskette you want into physical drive A, then type RETURN). The next time you access drive A, the system will prompt you to put a diskette in drive A. Again, insert the desired diskette and type return. ///1commands CP/M 3 Command Format: A>COMMAND {command tail} A CP/M 3 command line is composed of a command, an optional command tail, and a carriage return. The command is the name or filename of a program to be executed. The optional command tail can consist of a drive specification, one or more file specifications, and some options or parameters. ///2conventions COMMAND CONVENTIONS The following special symbols define command syntax. {} surrounds an optional item. | separates alternative items in a command line. indicates a carriage return. ^ indicates the Control Key. n substitute a number for n. s substitute a string (group) of characters for s. o substitute an option or option list for o. [] type square brackets to enclose an option list. () type parens to enclose a range of options within an option list. RW Read-Write attribute - opposite of RO RO Read-Only attribute - opposite of RW SYS System attribute - opposite of DIR DIR Directory attribute - opposite of SYS ... preceding element can be repeated as many times as desired. * wildcard: replaces all or part of a filename and/or filetype. ? wildcard: replaces any single character in the same position of a filename and/or filetype. ///1cntrlchars Control Character Function CTRL-A moves cursor one character to the left. Banked system only. CTRL-B moves cursor from beginning to end of command line and back without affecting command. Banked system only. CTRL-C stops executing program when entered at the system prompt or after CTRL-S. CTRL-E forces a physical carriage return without sending command to CP/M 3. CTRL-F moves cursor one character to the right. Banked system only. CTRL-G deletes character at current cursor position if in the middle of a line. Banked system only. CTRL-I same as the TAB key. CTRL-H delete character to the left of cursor. CTRL-J moves cursor to the left of the command line and sends command to CP/M 3. Line feed, has same effect as carriage return. CTRL-K deletes character at cursor and all characters to the right. CTRL-M same as carriage return. CTRL-P echoes console output to the list device. CTRL-Q restarts screen scrolling after a CTRL-S. CTRL-R retypes the characters to the left of the cursor on a new line; updates the command line buffer. CTRL-S stops screen scrolling. CTRL-U updates the command line buffer to contain the characters to the left of the cursor; deletes current line. CTRL-W recalls previous command line if current line is empty; otherwise moves cursor to end of line. CTRL-J,-M,-R,-U and RETURN update the command line buffer for recall with CTRL-W. Banked system only. CTRL-X deletes all characters to the left of the cursor. ///1COPYSYS Explanation: This command is not implemented the same as it is in other CP/M systems. To create a diskette with the CP/M system on it, you must: 1) Format the diskette using the FORMAT program, as either C128 single sided or C128 double sided diskette. 2) Use PIP to copy the files CPM+.SYS and CCP.COM to the newly formatted diskette. NOTE: Only diskettes that you intend to use to boot CP/M need these two files on them. It is not recommended, for the purpose of saving space, that they be put on every diskette. Example: A>FORMAT A>PIP E:=A:CPM+.SYS A>PIP E:=A:CCP.COM ///1DATE Syntax: DATE {CONTINUOUS} DATE {time-specification} DATE SET Explanation: The DATE command lets you display and set the date and time of day. ///2Examples A>DATE Displays the current date and time. A>DATE C Displays the date and time continuously. A>DATE 08/14/82 10:30:0 Sets the date and time. A>DATE SET Prompts for date and time entries. ///1DEVICE Syntax: DEVICE { NAMES | VALUES | physical-dev | logical-dev} DEVICE logical-dev=physical-dev {option} {,physical-dev {option},...} DEVICE logical-dev = NULL DEVICE physical-dev {option} DEVICE CONSOLE [ PAGE | COLUMNS = columns | LINES = lines] Explanation: DEVICE displays current logical device assignments and physical device names. DEVICE assigns logical devices to peripheral devices attached to the computer. DEVICE also sets the communications protocol and speed of a peripheral device, and displays or sets the current console screen size. ///2Options [ XON | NOXON | baud-rate ] XON refers to the XON/XOFF communications protocol. NOXON indicates no protocol and the computer sends data to the device whether or not the device is ready to receive it. baud-rate is the speed of the device. The system accepts the following baud rates: 50 75 110 134 150 300 600 1200 1800 2400 3600 4800 7200 9600 19200 ///2Examples A>DEVICE Displays the physical devices and current assignments of the logical devices in the system. A>DEVICE NAMES Lists the physical devices with a summary of the device characteristics. A>DEVICE VALUES Displays the current logical device assignments. A>DEVICE 80COL Displays the attributes of the physical device 80COL. A>DEVICE CON Displays the assignment of the logical device CON: Assigns the system console output (CONOUT:) to the 40 column monitor (40COL) and the 80 column monitor (80COL). A>DEVICE AUXIN:=CRT2 [XON,9600] Assigns the auxiliary logical input device (AUXIN:) to the physical device CRT using protocol XON/XOFF and sets the transmission rate for the device at 9600. A>DEVICE LST:=NULL Disconnects the list output logical device (LST:). A>DEVICE LPT [XON,9600] Sets the XON/XOFF protocol for the physical device LPT and sets the transmission speed at 9600. A>DEVICE CONSOLE [PAGE] Displays the current console page width in columns and length in lines. A>DEVICE CONSOLE [COLUMNS=40 LINES=16] Sets the screen size to 40 columns and 16 lines. ///2C128_Devices Devices on C128 CP/M Implementation The following are legal devices under the C128 CP/M implementation: 40COL = 40 column monitor 80COL = 80 column monitor PTR1 = Commodore Serial Printer (Serial Bus Device 4) PTR2 = Commodore Serial Printer (Serial Bus Device 5) ///1DIR The DIR command displays the names of files and the characteristics associated with the files. The DIR command has three distinct references: DIR DIRS DIR with Options DIR and DIRS are built-in utilities. DIR with Options is a transient utility and must be loaded into memory from the disk. ///2Built-in Syntax: DIR {d:} DIR {filespec} DIRS {d:} DIRS {filespec} Explanation: The DIR and DIRS Built-in commands display the names of files cataloged in the directory of an on-line disk. DIR lists the names of files in the current user number that have the Directory (DIR) attribute. DIR accepts the * and ? wildcards in the file specification. ///3Examples A>DIR Displays all files in user 0 on drive A that have the Directory attribute. A>DIR B: Displays all DIR files in user 0 on drive B. 2A>DIR C:ZIPPY.DAT Displays the name ZIPPY.DAT if the file is in user 2 on drive C. 4A>DIR *.BAS Displays all DIR files with filetype BAS in user 4 on drive A. B3>DIR X*.C?D Displays all DIR files in user 3 on drive B whose filename begins with the letter X, and whose three character filetype contains the first character C and last character D. A>DIRS Displays all files for user 0 on drive A that have the system (SYS) attribute. A>DIRS *.COM Displays all SYS files with filetype COM on drive A in user 0. A command (.COM) file in user 0 with the system attribute can be accessed from any user number on that drive, and from any drive in the search chain (see SETDEF). ///2withOptions Syntax: DIR {d:} [options] DIR {filespec} {filespec} ... [options] Explanation: The DIR command with options is an enhanced version of the DIR built-in command and displays your files in a variety of ways. DIR can search for files on any or all drives, for any or all user numbers. One or two letters is sufficient to identify an option. You need not type the right hand square bracket. ///3Options Option Function ATT displays the file attributes. DATE displays date and time stamps of files. DIR displays only files that have the DIR attribute. DRIVE=ALL displays files on all on-line drives. DRIVE=(A,B,C,...,P) displays files on the drives specified. DRIVE=d displays files on the drive specified by d. EXCLUDE displays files that DO NOT MATCH the files specified in the command line. FF sends an initial form feed to the printer device if the printer has been activated by CTRL-P. FULL shows the name, size, number of 128-byte records, and attributes of the files. If there is a directory label on the drive, DIR shows the password protection mode and the time stamps. If there is no directory label, DIR displays two file entries on a line, omitting the password and time stamp columns. The display is alphabetically sorted. (See SET for a description of file attributes, directory labels, passwords and protection modes.) LENGTH=n displays n lines of printer output before inserting a table heading. n is a number between 5 and 65536. MESSAGE displays the names of drives and user numbers DIR is searching. NOSORT displays files in the order it finds them on the disk. RO displays only the files that have the Read-Only attribute. RW displays only the files that are set to Read-Write. SIZE displays the filename and size in kilobytes (1024 bytes). SYS displays only the files that have the SYS attribute. USER=ALL displays all files in all user numbers for the default or specified drive. USER=n displays the files in the user number specified by n. USER=(0,1,...,15) displays files under the user numbers specified. ///3Examples A>DIR C: [FULL] Displays full set of characteristics for all files in user 0 on drive C. A>DIR C: [DATE] Lists the files on drive C and their dates. A>DIR D: [RW,SYS] Displays all files in user 0 on drive D with Read-Write and System attributes. 3A>DIR [USER=ALL, DRIVE=ALL] Displays all the files in all user numbers (0-15) in all on- line drives. B6>DIR [exclude] *.DAT Lists all the files on drive B in user 6 that do not have a filetype of .DAT. 3B>DIR [SIZE] *.PLI *.COM *.ASM Displays all the files of type PLI, COM, and ASM in user 3 on drive B in size display format. A>DIR [drive=all user=all] TESTFILE.BOB DIR displays the filename TESTFILE.BOB if it is found on any drive in any user number. A>DIR [size,rw] D: DIR lists each Read-Write file that resides on Drive D, with its size in kilobytes. Note that D: is equivalent to D:*.*. ///1DUMP Syntax: DUMP filespec Explanation: DUMP displays the contents of a file in hexadecimal and ASCII format. Example: A>DUMP ABC.TEX ///1ed Format: ED input-filespec {d:|output-filespec} Explanation: Character file editor. To redirect or rename the new version of the file specify the destination drive or destination filespec. ///2commands ED Command Summary Command Action nA append n lines from original file to memory buffer 0A append file until buffer is one half full #A append file until buffer is full (or end of file) B, -B move CP to the beginning (B) or bottom (-B) of buffer nC, -nC move CP n characters forward (C) or back (-C) through buffer nD, -nD delete n characters before (-D) or from (D) the CP E save new file and return to CP/M-86 Fstring{^Z} find character string H save new file, reedit, use new file as original file I enter insert mode Istring{^Z} insert string at CP Jsearch_str^Zins_str^Zdel_to_str juxtapose strings nK, -nK delete (kill) n lines from the CP nL, -nL, 0L move CP n lines nMcommands execute commands n times n, -n move CP n lines and display that line n: move to line n :ncommand execute command through line n Nstring{^Z} extended find string O return to original file nP, -nP move CP 23 lines forward and display 23 lines at console Q abandon new file, return to CP/M-86 R{^Z} read X$$$$$$$.LIB file into buffer Rfilespec{^Z} read filespec into buffer Sdelete string^Zinsert string substitute string nT, -nT, 0T type n lines U, -U upper-case translation V, -V line numbering on/off 0V display free buffer space nW write n lines to new file 0W write until buffer is half empty nX write or append n lines to X$$$$$$$.LIB nXfilespec{^Z} write n lines to filespec; append if previous xcommand applied to same file 0x{^Z} delete file X$$$$$$$.LIB 0xfilespec{^Z} delete filespec nZ wait n seconds Note: CP points to the current character being referenced in the edit buffer. Use {^Z} to separate multiple commands on the same line. ///2Examples A>ED TEST.DAT A>ED TEST.DAT B: A>ED TEST.DAT TEST2.DAT A>ED TEST.DAT B:TEST2.DAT ///1erase Syntax: ERASE {filespec} {[CONFIRM]} Explanation: The ERASE command removes one or more files from the directory of a disk. Wildcard characters are accepted in the filespec. Directory and data space are automatically reclaimed for later use by another file. The ERASE command can be abbreviated to ERA. ///2Option [CONFIRM] option informs the system to prompt for verification before erasing each file that matches the filespec. CONFIRM can be abbreviated to C. ///2Examples A>ERASE X.PAS Removes the file X.PAS from the disk in drive A. A>ERA *.PRN Confirm (Y/N)?Y All files with the filetype PRN are removed from the disk in drive A. B>ERA A:MY*.* [CONFIRM] Each file on drive A with a filename that begins with MY is displayed with a question mark for confirmation. Type Y to erase the file displayed, N to keep the file. A>ERA B:*.* Confirm (Y/N)?Y All files on drive B are removed from the disk. ///1filespec FILESPEC FORMAT CP/M 3 identifies every file by its unique file specification, which can consist of four parts: the drive specification, the filename, the filetype and the password. The term "filespec" indicates any valid combination of the four parts of a file specification, all separated by their appropriate delimiters. A colon must follow a drive letter. A period must precede a filetype. A semicolon must precede a password. The symbols and rules for the parts of a file specification follow: d: drivespec optional single alpha character (A-P) filename filename 1-8 letters and/or numbers typ filetype optional 0-3 letters and/or numbers password password optional 0-8 letters and/or numbers Valid combinations of the elements of a CP/M 3 file specification are: filename d:filename filename.typ d:filename.typ filename;password d:filename;password filename.typ;password d:filename.typ;password If you do not include a drive specifier, CP/M 3 automatically uses the default drive. Some CP/M 3 commands accept wildcard (* and ?) characters in the filename and/or filetype parts of the command tail. A wildcard in the command line can in one command reference many matching files on the default or specified user number and drive. (See Commands). ///1GENCOM Syntax: GENCOM {COM-filespec} {RSX-filespec} ... {[LOADER | NULL | SCB=(offset,value)]} Explanation: The GENCOM command creates a special COM file with attached RSX files. The GENCOM command can also restore a previously GENCOMed file to the original COM file without the header and RSX's. GENCOM can also attach header records to COM files. ///2Options LOADER sets a flag to keep the program loader active. NULL indicates that only RSX files are specified. GENCOM creates a dummy COM file for the RSX files. The output COM filename is taken from the filename of the first RSX-filespec. SCB=(offset,value) sets the System Control Block from the program by using the hex values specified by (offset,value). ///2Examples A>GENCOM MYPROG PROG1 PROG2 Generates a new COM file MYPROG.COM with attached RSX's PROG1 and PROG2. A>GENCOM PROG1 PROG2 [NULL] Creates a COM file PROG1.COM with RSX's PROG1 and PROG2. A>GENCOM MYPROG GENCOM takes MYPROG.COM, strips off the header and deletes all attached RSX's to restore it to its original COM format. A>GENCOM MYPROG PROG1 PROG2 GENCOM looks at the already-GENCOMed file MYPROG.COM to see if PROG1.RSX and PROG2.RSX are already attached RSX files in the module. If either one is already attached, GENCOM replaces it with the new RSX module. Otherwise, GENCOM appends the specified RSX files to the COM file. ///1GET Syntax: GET {CONSOLE INPUT FROM} FILE filespec{[{ECHO|NO ECHO} | SYSTEM]} GET {CONSOLE INPUT FROM} CONSOLE Explanation: GET directs the system to take console input from a file for the next system command or user program entered at the console. Console input is taken from a file until the program terminates. If the file is exhausted before program input is terminated, the program looks for subsequent input from the console. If the program terminates before exhausting all its input, the system reverts back to the console for console input. With the SYSTEM option, the system immediately goes to the specified file for console input. The system reverts to the console for input when it reaches the end of file. Re-direct the system to the console for console input with the GET CONSOLE INPUT FROM CONSOLE command as a command line in the input file. ///2Options ECHO specifies that input is echoed to the console. This is the default option. NO ECHO specifies that file input is not echoed to the console. The program output and the system prompts are not affected by this option and are still echoed to the console. SYSTEM specifies that all system input is immediately taken from the disk file specified in the command line. GET takes system and program input from the file until the file is exhausted or until GET reads a GET console command from the file. ///2Examples A>GET FILE XINPUT A>MYPROG Tells the system to activate the GET utility. Since SYSTEM is not specified, the system reads the next input line from the console and executes MYPROG. If MYPROG program requires console input, it is taken from the file XINPUT. When MYPROG terminates, the system reverts back to the console for console input. A>GET FILE XIN2 [SYSTEM] Immediately directs the system to get subsequent console input from file XIN2 because it includes the SYSTEM option. The system reverts back to the console for console input when it reaches the end of file in XIN2. Or XIN2 may redirect the system back to the console if it contains a GET CONSOLE command. A>GET CONSOLE Tells the system to get console input from the console. This command may be used in a file (previously specified in a GET FILE command), which is already being read by the system for console input. It is used to re-direct the console input back to the console before the end-of-file is reached. ///1HELP Syntax: HELP {topic} {subtopic1 ... subtopic8} {[NOPAGE|LIST]} Explanation: HELP displays a list of topics and provides summarized information for CP/M 3 commands. HELP topic displays information about that topic. HELP topic subtopic displays information about that subtopic. One or two letters is enough to identify the topics. After HELP displays information for your topic, it displays the special prompt HELP> on your screen, followed by a list of subtopics. - Enter ? to display list of main topics. - Enter a period and subtopic name to access subtopics. - Enter a period to redisplay what you just read. - Press the RETURN key to return to the CP/M 3 system prompt. - [NOPAGE] option disables the 24 lines per page console display. - Press any key to exit a display and return to the HELP> prompt. Examples: A>HELP A>HELP DATE A>HELP DIR OPTIONS A>HELP>.OPTIONS HELP>SET HELP>SET PASSWORD HELP>.PASSWORD HELP>. HELP> ///1HEXCOM Syntax: HEXCOM filename Explanation: The HEXCOM Command generates a command file (filetype .COM) from a .HEX input file. It names the output file with the same filename as the input file but with filetype .COM. HEXCOM always looks for a file with filetype .HEX. Example: A>HEXCOM B:PROGRAM Generates a command file PROGRAM.COM from the input hex file PROGRAM.HEX. ///1INITDIR Syntax: INITDIR {d:} Explanation: The INITDIR Command initializes a disk directory to allow date and time stamping of files on that disk. INITDIR can also recover time/date directory space. Example: A>INITDIR C: INITDIR WILL ACTIVATE TIME-STAMPS FOR SPECIFIED DRIVE. Do you want to re-format the directory on C: (Y/N)?Y ///1KEYFIG The purpose of the KEYFIG program is to allow you to alter the definition of almost ANY key on the keyboard. The only keys that you CANNOT modify are: the SHIFT keys, the SHIFT LOCK key, the CONTROL key, the 40/80 DISPLAY key and the COMMODORE key. At each step, options are presented in menu form. You can scroll through the options in the menus by using the up and down arrow keys at the top of the keyboard; pressing the return key selects the choice that is highlighted. At almost any point, you can exit the program by typing 'CTRL c' (the CONTROL key and C simultaneously.) ///2Editing_Keys Editing Keys Once you have selected a specific key value to edit, you will be given a choice of 5 ways of modifying the key: ASSIGN a new character - which allows you to do a 'one-for-one' replacement of the key. ASSIGN a STRING - which allows you to assign/edit a string (more than 1 character) to the key ASSIGN a COLOR - which allows you to assign an 80 or a 40 column color ASSIGN a special function - which allows you to assign a function from a list of currently available special functions. ASSIGN a HEX value - which allows you to replace the key value with a single hex value. ///3Edit_Colors Assigning/Editing Color Values Once you have chosen to assign a color, you will be given a choice of 5 color types to assign: an 80 column foreground color, an 80 column background color, a 40 column foreground color, a 40 column background color or a 40 column border color. Scroll through and select the one you want to assign. At this point, a color map consisting of 16 boxes labelled 'a' through 'p' will be displayed. Type the letter from the box representing the color that you want to assign. (NOTE that one letter (usually 'a') will appear to be missing, because it blends with the background color - assume ALL boxes are lettered sequentially!) ///3Edit_Hex Assigning/Editing Hexadecimal Values Once you have chosen to assign a hex value to a key, you will be prompted for the value to assign. Only charactersfrom 0-9 and a-f (upper or lower case) will be accepted. As you type characters, the current value is shifted left one nibble and the new value is ORed into the lst nibble. You can type as many characters as you want, but the last 2 you type will be the value assigned to the key. Type return when you are finished. Note: The value you type when the four key values are displayed will not be displayed as hex, but as what the hex value represents. WARNING: This mode should only be used by those familiar with hexadecimal data. ///3Edit_Special Assigning/Editing Special Functions Once you have chosen to assign a special function you will be given a list of 16 currently available special functions. Scroll through the list and assign the function that you want this key to perform. ///3Edit_Strings Assigning/Editing Strings Once you have chosen to assign a string, you will be given a list of 32 available strings (some of which may already be defined.) Scroll through and select the one you want to assign to this key. At this point, the one you choose will be displayed near the top of the screen for editing. You can edit by typing keys and/or by choosing one of the menu options presented - insert a color, insert a hex value, insert a special function or a second string (warning - the remainder of the string will be deleted if you insert a second string.) You can also use the left and right arrow keys and the insert and delete keys. When you are done, select the menu choice "exit string edit and save assigned string". ///2Finishing_Up Finishing Up-Saving Your Work File Once you have loaded your workfile and completed any editing you wanted to do, you will be given three choices as to what to do with your work file: SAVE AS CURRENT - which makes the definitions in your work file effective immediately upon exiting this program SAVE ON CP/M DISK - which will cause the definitions in your work file to be loaded the next time you boot from the disk to which it was saved DON'T SAVE - a means of exiting if you made a mistake or changed your mind. ///2For_Experts For Experts Only The C128 allows you to edit key definitions directly, without using the KEYFIG program. There are 2 alternatives: edit a string or assign a single hex value. To edit a string type the CONTROL KEY, the RIGHT SHIFT key and the RIGHT ARROW key simultaneously, then type the key to which you want to assign the string. Note that the key you pick must already have a string value (80-9F) assigned to it. A window will pop up at the bottom of the screen, in which you will edit. Type the string and type CONTROL, RIGHT SHIFT, RETURN to exit. For editing, you can use CONTROL, RIGHT SHIFT, RIGHT ARROW or LEFT ARROW to move right or left through the string and CONTROL RIGHT SHIFT + or - to insert or delete a character respectively. To assign a single hex value, type CONTROL,RIGHT SHIFT and LEFT ARROW key simultaneously. Again, a window will pop up at the bottom of the screen showing the current hex value. Enter the new hex value. NOTE that any illegal key will abort the edit without modifying the key. ///2Key_Values Key Values Each key has 4 values associated with it: normal value - which represents the unshifted value of the key as labelled. SHIFTED value - which represents the values of the keys, as labelled, obtained by typing the desired key and the shift key simultaneously. CONTROL value - which represents the value of the key obtained by typing the desired key and the CONTROL key simultaneously. CAPS LOCK value - which represents the value obtained while in COMMODORE mode. This mode is obtained by typing the COMMODORE key and stays in effect until you type it again. ///2Log/Phy_Clrs Assigning Logical/Physical Colors Once you have chosen to assign logical/physical colors, you will be given a choice of doing this for either a 40 or an 80 column screen. Then, two color maps will be displayed. The top one is the current logical color map; the bottom one is the physical color map. You will be asked to select the logical color you want to assign (type the letter in the box with the color you want from the top map). Then you will be asked for the physical color you want assigned to it (type the letter in the box with the color you want, from the bottom map.) You can assign as many colors as you want; type the RETURN key when you are finished. ///2Select_a_Key Selecting a Key to Edit To select a key for editing, you must actually select the specific (1 of 4) value of the key that you want to modify. To do this, type the key so that the four values associated with it are displayed. Use the up and down arrow keys to scroll through the four values; type the return key to select the value that is highlighted. This is the specific key value that will be modified. The next time you view this key the new value you assigned will be displayed. You can modify as many keys as you want. When you are done, select the fifth choice - "exit and save work file". (NOTE: To view the up arrow, down arrow or return key, type the desired key and the control key simultaneously). ///2Setting_Up Setting Up Your Work File The first thing you will be asked to do is set up your work file. You will be given a choice of 3 sources from which you can do this: DEFAULT DEFINITIONS - which basically represent a standard set of key definitions. CURRENT DEFINITIONS - which represent the most recently loaded set of definitions. DEFINITIONS ON CP/M BOOT DISK - which represent the set of definitions stored on your boot disk, normally default definitons, unless you replace them via this program. ///3What_To_Do What To Do With Your Work File Once your work file is set up, you will be given a choice of 3 things to do: EDIT KEYS- which allows you to modify key definitions. ASSIGN LOGICAL/PHYSICAL COLORS - which allows you to redefine the meaning associated with a particular color. EXIT AND SAVE YOUR WORK FILE - This is provided here as a quick means of copying one set of definitions to another. For example, loading the default definitions into your work file and saving them as the current definitions, provides a means of restoring your current definitions after running an application which may have used a now undesired set of key definitions. ///1LIB Syntax: LIB filespec{[I|M|P|D]} LIB filespec{[I|M|P]}=filespec{modifier} {,filespec{modifier} ... } Explanation: A library is a file that contains a collection of object modules. Use the LIB utility to create libraries, and to append, replace, select or delete modules from an existing library. Use LIB to obtain information about the contents of library files. LIB creates and maintains library files that contain object modules in Microsoft REL file format. These modules are produced by Digital Research's relocatable macro-assembler program, RMAC, or any other language translator that pruduces modules in Microsoft REL file format. You can use LINK-80 to link the object modules contained in a library to other object files. LINK-80 automatically selects from the library only those modules needed by the program being linked, and then forms an executable file with a filetype of COM. ///2Options I The INDEX option creates an indexed library file of type .IRL. LINK-80 searches faster on indexed libraries than on non-indexed libraries. M The MODULE option displays module names. P The PUBLICS option displays module names and the public variables for the new library file. D The DUMP option displays the contents of object modules in ASCII form. ///2Modifiers Use modifiers in the command line to instruct LIB to delete, replace, or select modules in a library file. Angle brackets enclose the modules to be deleted or replaced. Parentheses enclose the modules to be selected. LIB Modifiers Delete Replace If module name and filename are the same this shorthand can be used: Select (modFIRST-modLAST,mod1,mod2,...,modN) ///2Examples A>LIB TEST4[P] Displays all modules and publics in TEST4.REL. A>LIB TEST5[P]=FILE1,FILE2 Creates TEST5.REL from FILE1.REL and FILE2.REL and displays all modules and publics in TEST5.REL. A>LIB TEST=TEST1(MOD1,MOD4),TEST2(C1-C4,C6) Creates a library file TEST.REL from modules in two source files. TEST1.REL contributes MOD1 and MOD4. LIB extracts modules C1, C4, and all the modules located between them, as well as module C6 from TEST2.REL. A>LIB FILE2=FILE3 Creates FILE2.REL from FILE3.REL, omitting MODA which is a module in FILE3.REL. A>LIB FILE6=FILE5 Creates FILE6.REL from FILE5.REL, FILEB.REL replaces MODA. A>LIB FILE6=FILE5 Module THISNAME is in FILE5.REL. When LIB creates FILE6.REL from FILE5.REL the file THISNAME.REL replaces the similarly named module THISNAME. A>LIB FILE1[I]=B:FILE2(PLOTS,FIND,SEARCH-DISPLAY) Creates FILE1.IRL on drive A from the selected modules PLOTS, FIND, and modules SEARCH through the module DISPLAY, in FILE2.REL on drive B. ///1LINK Syntax: LINK d:{filespec,{[options]}=}filespec{[options]}{,...} Explanation: LINK combines relocatable object modules such as those produced by RMAC and PL/I-80 into a .COM file ready for execution. Relocatable files can contain external references and publics. Relocatable files can reference modules in library files. LINK searches the library files and includes the referenced modules in the output file. See the CP/M 3 Programmer's Utilities Guide for a complete description of LINK- 80. ///2Options Use LINK option switches to control execution parameters. Link options follow the file specifications and are enclosed within square brackets. Multiple switches are separated by commas. LINK-80 Options A Additional memory; reduces buffer space and writes temporary data to disk B BIOS link in banked CP/M 3 system. 1. Aligns data segment on page boundary. 2. Puts length of code segment in header. 3. Defaults to .SPR filetype. Dhhhh Data origin; sets memory origin for common and data area Gn Go; set start address to label n Lhhhh Load; change default load address of module to hhhh. Default 0100H Mhhhh Memory size; Define free memory requirements for MP/M modules. NL No listing of symbol table at console NR No symbol table file OC Output .COM command file. Default OP Output .PRL page relocatable file for execution under MP/M in relocatable segment OR Output .RSP resident system process file for execution under MP/M OS Output .SPR system page relocatable file for execution under MP/M Phhhh Program origin; changes default program origin address to hhhh. Default is 0100H. Q Lists symbols with leading question mark S Search preceding file as a library $Cd Destination of console messages d can be X (console), Y (printer), or Z (zero output). Default is X. $Id Source of intermediate files; d is disk drive A-P. Default is current drive. $Ld Source of library files; d is disk drive A-P. Default is current drive. $Od Destination of of object file; d can be Z or disk drive A-P. Default is to same drive as first file in the LINK-80 command. $Sd Destination of symbol file; d can be Y or Z or disk drive A-P. Default is to same drive as first file in LINK-80 command. ///2Examples A>LINK b:MYFILE[NR] LINK-80 on drive A uses as input MYFILE.REL on drive B and produces the executable machine code file MYFILE.COM on drive B. The [NR] option specifies no symbol table file. A>LINK m1,m2,m3 LINK-80 combines the separately compiled files m1, m2, and m3, resolves their external references, and produces the executable machine code file m1.COM. A>LINK m=m1,m2,m3 LINK-80 combines the separately compiled files m1, m2, and m3 and produces the executable machine code file m.COM. A>LINK MYFILE,FILE5[s] The [s] option tells LINK-80 to search FILE5 as a library. LINK-80 combines MYFILE.REL with the referenced subroutines contained in FILE5.REL on the default drive A and produces MYFILE.COM on drive A. ///1mac Syntax: MAC filename {$options} Explanation: MAC, the CP/M 3 macro assembler, reads assembly language statements from a file of type .ASM, assembles the statements, and produces three output files with the input filename and filetypes of .HEX, .PRN, and .SYM. Filename.HEX contains INTEL hexadecimal format object code. Filename.PRN contains an annotated source listing that you can print or examine at the console. Filename.SYM contains a sorted list of symbols defined in the program. ///2Examples A>MAC SAMPLE A>MAC SAMPLE $PB AA HB SX ///2options Use options to direct the input and output of MAC. Use a letter with the option to indicate the source and destination drives, and console, printer, or zero output. Valid drive names are A thru O. X, P and Z specify console, printer, and zero output, respectively. Assembly Options That Direct Input/Output A source drive for .ASM file (A-O) H destination drive for .HEX file (A-O, Z) L source drive for macrolibrary .LIB files called by the MACLIB statement. P destination drive for .PRN file (A-O, X, P, Z) S destination drive for .SYM file Assembly Options That Modify Contents Of Output File +L lists input lines read from macrollibrary .LIB files -L suppresses listing (default) +M lists all macro lines as they are processed during assembly -M suppresses all macro lines as they are read during assembly *M lists only hex generated by macro expansions +Q lists all LOCAL symbols in the symbol list -Q suppresses all LOCAL symbols in the symbol list (default) +S appends symbol file to print file -S suppresses creation of symbol file +1 produces a pass 1 listing for macro debugging in .PRN file -1 suppress listing on pass 1 (default) ///1PATCH Syntax: PATCH filename{.typ} {n} Explanation: The PATCH command displays or installs patch number n to the CP/M 3 system or command files. The patch number n must be between 1 and 32 inclusive. Example: A>PATCH SHOW 2 Patches the SHOW.COM system file with patch number 2. ///1PIP (copy) Syntax: DESTINATION SOURCE PIP d:{Gn} | filespec{[Gn]} = filespec{[o]},... | d:{[o]} Explanation: The file copy program PIP copies files, combines files, and transfers files between disks, printers, consoles, or other devices attached to your computer. The first filespec is the destination. The second filespec is the source. Use two or more source filespecs separated by commas to combine two or more files into one file. [o] is any combination of the available options. The [Gn] option in the destination filespec tells PIP to copy your file to that user number. PIP with no command tail displays an * prompt and awaits your series of commands, entered and processed one line at a time. The source or destination can be any CP/M 3 logical device. ///2Examples COPY A FILE FROM ONE DISK TO ANOTHER A>PIP b:=a:draft.txt A>PIP b:draft.txt = a: B3>PIP myfile.dat=A:[G9] A9>PIP B:[G3]=myfile.dat COPY A FILE AND RENAME IT A5>PIP newdraft.txt=oldraft.txt C8>PIP b:newdraft.txt=a:oldraft.txt COPY MULTIPLE FILES A>PIP b:=draft.* A>PIP b:=*.* B>PIP b:=c:.*.* C>PIP b:=*.txt[g5] C>PIP a:=*.com[wr] B>PIP a:[g3]=c:*.* COMBINE MULTIPLE FILES A>PIP b:new.dat=file1.dat,file2.dat COPY, RENAME AND PLACE IN USER 1 A>pip newdraft.txt[g1]=oldraft.txt COPY, RENAME AND GET FROM USER 1 A>PIP newdraft.txt=oldraft.txt[g1] COPY TO/FROM LOGICAL DEVICES A>PIP b:funfile.sue=con: A>PIP lst:=con: A>PIP lst:=b:draft.txt[t8] A>PIP prn:=b:draft.txt ///2options PIP OPTIONS A Archive. Copy only files that have been changed since the last copy. C Confirm. PIP prompts for confirmation before each file copy. Dn Delete any characters past column n. E Echo transfer to console. F Filter form-feeds from source data. Gn Get from or go to user n. H Test for valid Hex format. I Ignore :00 Hex data records and test for valid Hex format. K Kill display of filespecs on console. L Translate upper case to lower case. N Number output lines O Object file transfer, ^Z ignored. Pn Set page length to n. (default n=60) Qs^Z Quit copying from source at string s. R Read files that have been set to SYStem. Ss^Z Start copying from the source at the string s. Tn Expand tabs to n spaces. U Translate lower case to upper case. V Verify that data has been written correctly. W Write over Read Only files without console query. Z Zero the parity bit. All options except C,G,K,O,R,V and W force an ASCII file transfer, character by character, terminated by a ^Z. ///1PUT Syntax: PUT CONSOLE {OUTPUT TO} FILE filespec {option} | CONSOLE PUT PRINTER {OUTPUT TO} FILE filespec {option} | PRINTER PUT CONSOLE {OUTPUT TO} CONSOLE PUT PRINTER {OUTPUT TO} PRINTER Explanation: PUT puts console or printer output to a file for the next command entered at the console, until the program terminates. Then console output reverts to the console. Printer output is directed to a file until the program terminates. Then printer output is put back to the printer. PUT with the SYSTEM option directs all subsequent console/printer output to the specified file. This option terminates when you enter the PUT CONSOLE or PUT PRINTER command. ///2Options [ {ECHO | NO ECHO} {FILTER | NO FILTER} | {SYSTEM} ] ECHO specifies that output is echoed to the console. This is the default option when you direct console output to a file. NO ECHO specifies that file output is not echoed to the console. NO ECHO is the default for the PUT PRINTER command. FILTER specifies filtering of control characters, which means that control characters are translated to printable characters. For example, an ESCape character is translated to ^[. NO FILTER means that PUT does not translate control characters. This is the default option. SYSTEM specifies that system output as well as program output is written to the file specified by filespec. Output is written to the file until a subsequent PUT CONSOLE command redirects console output back to the console. ///2Examples A>PUT CONSOLE OUTPUT TO FILE XOUT [ECHO] Directs console output to file XOUT with the output echoed to the console. A>PUT PRINTER OUTPUT TO FILE XOUT A>MYPROG Directs the printer output of program MYPROG to file XOUT. The output is not echoed to the printer. A>PUT PRINTER OUTPUT TO FILE XOUT2 [ECHO,SYSTEM] Directs all printer output to file XOUT2 as well as to the printer (with ECHO option), and the PUT is in effect until you enter a PUT PRINTER OUTPUT TO PRINTER command. A>PUT CONSOLE OUTPUT TO CONSOLE Directs console output back to the console. A>PUT PRINTER OUTPUT TO PRINTER Directs printer output back to the printer. ///1RENAME Syntax: RENAME {new-filespec=old-filespec} Explanation: RENAME lets you change the name of a file in the directory of a disk. To change several filenames in one command use the * or ? wildcards in the file specifications. The RENAME command can be abbreviated REN. REN prompts you for input. ///2Examples A>RENAME NEWFILE.BAS=OLDFILE.BAS The file OLDFILE.BAS changes to NEWFILE.BAS on drive A. A>RENAME The system prompts for the filespecs: Enter New Name:X.PRN Enter Old Name:Y.PRN Y .PRN=X .PRN A> File X.PRN is renamed to Y.PRN on drive A. B>REN A:PRINTS.NEW = PRINCE.NEW The file PRINCE.NEW on drive A changes to PRINTS.NEW on drive A. A>RENAME S*.TEX=A*.TEX The above command renames all the files matching A*.TEX to files with filenames S*.TEX. A>REN B:NEWLIST=B:OLDLIST The file OLDLIST changes to NEWLIST on drive B. Since the second drive specifier, B: is implied by the first one, it is unnecessary in this example. The command line above has the same effect as the following: A>REN B:NEWLIST=OLDLIST or A>REN NEWLIST=B:OLDLIST ///1RMAC Syntax: RMAC filespec {$Rd | $Sd | $Pd} Explanation: RMAC, a relocatable macro assembler, assembles .ASM files of into .REL files that you can link to create .COM files. ///2options RMAC options specify the destination of the output files. Replace d with the destination drive letter for the output files. Option d=output option R- drive for REL file (A-O, Z) S- drive for SYM file (A-O, X, P, Z) P- drive for PRN file (A-O, X, P, Z) A-O specifies drive A-O. X means output to the console. P means output to the printer. Z means zero output. ///2Example A>RMAC TEST $PX SB RB Assembles the file TEST.ASM from drive A, sends the listing file (TEST.PRN) to the console, puts the symbol file (TEST.SYM) on drive B and puts the relocatable object file (TEST.REL) on drive B. ///1SAVE Syntax: SAVE Explanation: SAVE copies the contents of memory to a file. To use SAVE, first issue the SAVE command, then run your program which reads a file into memory. Your program exits to the SAVE utility which prompts you for a filespec to which it copies the contents of memory, and the beginning and ending address of the memory to be SAVEd. ///2Example A>SAVE Activates the SAVE utility. Now enter the name of the program which loads a file into memory. A>SID dump.com Next, execute the program. #g0 When the program exits, SAVE intercepts the return to the system and prompts the user for the filespec and the bounds of memory to be SAVEd. SAVE Ver 3.0 Enter file (type RETURN to exit):dump2.com If file DUMP2.COM exists already, the system asks: Delete dump2.com? Y Then the system asks for the bounds of memory to be saved: Beginning hex address: 100 Ending hex address: 400 The contents of memory from 100H (Hexadecimal) to 400H is copied to file DUMP2.COM. ///1SET Syntax: SET [options] SET d: [options] SET filespec [options] Explanation: SET initiates password protection and time stamping of files. It also sets the file and drive attributes Read-Write, Read-Only, DIR and SYS. It lets you label a disk and password protect the label. To enable time stamping of files, you must first run INITDIR to format the disk directory. ///2Label Syntax: SET {d:} [NAME=labelname.typ] SET [PASSWORD=password] SET [PASSWORD= ///3Examples A>SET [NAME=DISK100] Labels the disk on the default drive as DISK100. A>SET [PASSWORD=SECRET] Assigns SECRET to the disk label. A>SET [PASSWORD= Nullifies the existing password. ///2Passwords SET [PROTECT=ON] SET [PROTECT=OFF] SET filspec [PASSWORD=password] SET filespec [PROTECT=READ] SET filespec [PROTECT=WRITE] SET filespec [PROTECT=DELETE] SET filespec [PROTECT=NONE] SET filespec [attribute-options] ///3Modes Password Protection Modes Mode Protection READ The password is required for reading, copying writing, deleting or renaming the file. WRITE The password is required for writing, deleting or renaming the file. You do not need a password to read the file. DELETE The password is only required for deleting or renaming the file. You do not need a password to read or modify the file. NONE No password exists for the file. If a password password exists, this modifier can be used to delete the password. ///2Attributes RO sets the file attribute to Read-Only. RW sets the file attribute to Read-Write. SYS sets the file attribute to SYS. DIR sets the file attribute to DIR. ARCHIVE=OFF means that the file has not been backed up (archived). ARCHIVE=ON means that the file has been backed up (archived).  The Archive attribute can be turned on by SET or by PIP when copying a group of files with the PIP [A] option. SHOW and DIR display the Archive option. F1=ON|OFF turns on or off the user-definable file attribute F1. F2=ON|OFF turns on or off the user-definable file attribute F2. F3=ON|OFF turns on or off the user-definable file attribute F3. F4=ON|OFF turns on or off the user-definable file attribute F4. ///3Examples SET [PROTECT=ON] Turns on password protection for all the files on the disk. You must turn on password protection before you can assign passwords to files. SET [PROTECT=OFF] Disables password protection for the files on your disk. A>SET MYFILE.TEX [PASSWORD=MYFIL] MYFIL is the password assigned to file MYFILE.TEX. B>SET *.TEX [PASSWORD=SECRET, PROTECT=WRITE] Assigns the password SECRET to all the TEX files on drive B. Each TEX file is given a WRITE protect mode to prevent unauthorized editing. A>SET MYFILE.TEX [RO SYS] Sets MYFILE.TEX to Read-Only and SYStem. ///2Default A>SET [DEFAULT=dd] Instructs the system to use dd as a password if you do not enter a password for a password-protected file. ///2Time-Stamps Syntax: SET [CREATE=ON] SET [ACCESS=ON] SET [UPDATE=ON] Explanation: The above SET commands allow you to keep a record of the time and date of file creation and update, or of the last access and update of your files. ///3Options [CREATE=ON] turns on CREATE time stamps on the disk in the default or specified drive. To record the creation time of a file, the CREATE option must be turned on before the file is created. [ACCESS=ON] turns on ACCESS time stamps on the disk in the default or specified drive. ACCESS and CREATE options are mutually exclusive; only one can be in effect at a time. If you turn on the ACCESS time stamp on a disk that previously had CREATE time stamp, the CREATE time stamp is automatically turned off. [UPDATE=ON] turns on UPDATE time stamps on the disk in the default or specified drive. UPDATE time stamps record the time the file was last modified. ///3Examples A>SET [ACCESS=ON] A>SET [CREATE=ON,UPDATE=ON] ///2Drives Syntax: SET {d:} [RO] SET {d:} [RW] Example: A>SET B: [RO] Sets drive B to Read-Only. ///1SETDEF Syntax: SETDEF { d: {,d: {,d: {,d:}}}} {[ TEMPORARY = d: ] | [ ORDER = (typ {,typ}) ]} SETDEF [DISPLAY | NO DISPLAY] SETDEF [PAGE | NOPAGE] Explanation: SETDEF allows the user to display or define up to four drives for the program search order, the drive for temporary files, and the file type search order. The SETDEF definitions affect only the loading of programs and/or execution of SUBMIT (SUB) files. SETDEF turns on/off the system Display and Console Page modes. When on, the system displays the location and name of programs loaded or SUBmit files executed, and stops after displaying one full console screen of information. ///2Examples A>SETDEF Displays current SETDEF parameters. A>SETDEF [TEMPORARY=C:] Sets disk drive C as the drive to be used for temporary files. A>SETDEF C:,* Tells the system to search for a program on drive C, then, if not found, search for it on the default drive. A>SETDEF [ORDER=(SUB,COM)] Instructs the system to search for a SUB file to execute. If no SUB file is found, search for a COM file. A>SETDEF [DISPLAY] Turns on the system display mode. Henceforth, the system displays the name and location of programs loaded or submit files executed. A>SETDEF [NO DISPLAY] Turns off the system Display mode. ///1SHOW Syntax: SHOW {d:}{[SPACE |LABEL |USERS |DIR |DRIVE]} Explanation: The SHOW command displays the following disk drive information: Access mode and the amount of free disk space Disk label Current user number and Number of files for each user number on the disk Number of free directory entries for the disk Drive characteristics ///2Examples A>SHOW A>SHOW [SPACE] Instructs the system to display access mode and amount of space left on logged-in drives. A>SHOW B: Show access mode for drive B and amount of space left on drive B. A>SHOW B:[LABEL] Displays label information for drive B. A>SHOW [USERS] Displays the current user number and all the users on drive A and the corresponding number of files assigned to them. A>SHOW C:[DIR] Displays the number of free directory entries on drive C. A>SHOW [DRIVE] Displays the drive characteristics of drive A. ///1SID Syntax: SID {pgm-filespec} {,sym-filespec} Explanation: The SID symbolic debugger allows you to monitor and test programs developed for the 8080 microprocessor. SID supports real-time breakpoints, fully monitored execution, symbolic disassembly, assembly, and memory display and fill functions. SID can dynamically load SID utility programs to provide traceback and histogram facilities. ///2Commands Command Meaning As (Assemble) Enter assembly language statements s is the start address Cs{b{,d}} (Call) Call to memory location from SID s is the called address b is the value of the BC register pair d is the value of the DE register pair D{W}{s}{,f} (Display) Display memory in hex and ASCII W is a 16-bit word format s is the start address f is the finish address Epgm-filespec (Load) Load program and symbol table {,sym-filespec} for execution E*sym-filespec (Load) Load a symbol table file Fs,f,d (Fill) Fill memory with constant value s is the start address f is the finish address d is an eight-bit data item G{p}{,a{,b}} (Go) Begin Execution p is a start address a is a temporary breakpoint H (Hex) Displays all symbols with addresses in Hex H.a Displays hex, decimal, and ASCII values of a where a is a symbolic expression Ha,b Computes hex sum and difference of a and b where a and b are symbolic expressions Icommand tail (Input) Input CCP command line L{s}{,f} (List) List 8080 mnemonic instructions s is the start address f is the finish address Ms,h,d (Move) Move Memory Block s is the start address h is the high address of the block d is the destination start address P{p{,c}} (Pass) Pass point set, reset, and display p is a permanent breakpoint address c is initial value of pass counter Rfilespec{,d} (Read) Read Code/Symbols d is an offset to each address S{W}s (Set) Set Memory Values s is address where value is sent W is 16 bit word T{n{,c}} (Trace) Trace Program Execution n is the number of program steps c is the utility entry address. T{W}{n{,c}} (Trace) Trace Without Call W instructs SID not to trace subroutines n is the number of program steps c is the utility entry address U{W}{n{,c}} (Untrace) Monitor Execution without Trace n is the number of program steps c is the utility entry address W instructs SID not to trace subroutines V (Value) Display the value of the next available location in memory (NEXT), the next location after the largest file read in (MSZE), the current value of the Program counter (PC), and the address of the end of available memory (END) Wfilespec,s,f (Write) Write the contents of a contiguous block of memory to filespec. f is finish address X{f}{r} (Examine) Examine/alter CPU state. f is flag bit C,Z,M,E or I. r is register A,B,D,H,S or P. ///2Examples A>SID CP/M 3 loads SID from drive A into memory. SID displays the # prompt when it is ready to accept commands. A>B:SID SAMPLE.HEX CP/M 3 loads SID and the program file SAMPLE.HEX into memory from drive B. ///2Utilities SID utilities, HIST.UTL and TRACE.UTL are special programs that operate with SID to provide additional debugging facilities. The mechanisms for system initialization, data collection, and data display are described in the CP/M SID User's Guide. The HIST utility creates a histogram (bar graph) showing the relative frequency of execution of code within selected program segments of the test program. The HIST utility allows you to monitor those sections of code that execute most frequently. The TRACE utility obtains a backtrace of the instructions that led to a particular breakpoint address in a program under test. You can collect the addresses of up to 256 instructions between pass points in U or T modes. ///1SUBMIT Syntax: SUBMIT {filespec} {argument} ... {argument} Explanation: The SUBMIT command lets you execute a group (batch) of commands from a SUBmit file (a file with filetype of SUB). ///2Subfile The SUB file can contain the following types of lines: Any valid CP/M 3 command Any valid CP/M 3 command with SUBMIT parameters ($0-$9) Any data input line Any program input line with parameters ($0 to $9) The command line cannot exceed 135 characters. The following lines illustrate the variety of lines which may be entered in a SUB file: DIR DIR *.BAK MAC $1 $$$4 PIP LST:=$1.PRN[T$2 $3 $5] DIR *.ASM PIP SUBMIT A>SUBMIT SUBA A>SUBMIT AA ZZ SZ A>SUBMIT B:START DIR E: ///2PROFILE.SUB Everytime you power up or reset your computer, CP/M 3 looks for a special SUBmit file named PROFILE.SUB to execute. If it does not exist, CP/M 3 resumes normal operation. If the PROFILE.SUB file exists, the system executes the commands in the file. This file is convenient to use if you regularly execute a set of commands before you do your regular session on the computer. ///1TYPE Syntax: TYPE {filespec {[ PAGE | NOPAGE ]}} Explanation: The TYPE command displays the contents of an ASCII character file on your screen. [PAGE] Causes the console listing to be displayed in paged mode; i.e., stop automatically after listing n lines of text, where n normally defaults to 24 lines per page. [NOPAGE] Turns off Console Page Mode and continuously displays a typed file on the screen. ///2Examples A>TYPE MYPROG.PLI Displays the contents of the file MYPROG.PLI on your screen. A>TYPE B:THISFILE [PAGE] Displays the contents of the file THISFILE from drive B on your screen twenty four lines at a time. ///1USER Syntax: USER {number} Explanation: The USER command sets the current user number. The disk directory can be divided into distinct groups according to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> The current user number is now 5 on drive A. A>USER 3 3A> This command changes the current User Number to 3. ///1XREF Syntax: XREF {d:} filename {$P} Explanation: XREF provides a cross-reference summary of variable usage in a program. XREF requires the .PRN and .SYM files produced by MAC or RMAC for input to the program. The SYM and PRN files must have the same filename as the filename in the XREF command tail. XREF outputs a file of type .XRF. Examples: A>XREF b:MYPROG A>XREF b:MYPROG $P tax: DIR {d:} DIR {filespec} DIRS {d:} DIRS {filespec} Explanation: lid CP/M 3 command with SUBMIT parameters ($0-$9) Any data input line Any program input line with parameters ($0 to $9) The command line cannot exceed 135 characters. The following lines illustrate the variety of lines which may 1(!~† This program is used to set system parameters. 21 Jan 86 The following Commands are currently supported: 40COL BAUD BACK BORD CHAR CURSOR DATE DRV DUMP FEEL HELP MAP PARITY POKE PRT1 PRT2 REPEAT VOL For more information on the command, type: A>conf help NOTE: the file CONF.HLP must be on the currently logged disk drive. Von Ertwine 6#$(>% >!>">>#$( % >>>2+(<7wÑ Repeat code not found Ñ### ( CONF.HLP file not found ,!(" T]  * @A 8' Enter Topic you want info on or RETURN to exit:  s !t ~ʑ_#6 !u 0.0 Missing or bad topic * 1" .ґ HELP message missing 2 " (*  : _7~\ #a{_: <2    !(> (7A 0 nq PARITY set errorÑ>!>2 ΐϓŖ͙!!!!: 2 !: 2NÑA 0 SOLISLOFAS Cursor errorÑ!`!@1 ͝ 0 W1 ͝ 0_> S< Ñ(Q1y x0>02zP >12zPÑ  x bx x  tx G0x G01 k 0' | } :  #Ñ DUMP HEX error 1 k 0A 0v 0 1 \ # Ñ POKE HEX data error * ~A8b0^#" 2 A 0R 8-8-9-9-10-10-11-11-0.B: O ^#V++s Ñ DRV parameter error @0 ͙ 0 02  Ñ* +* ,bad of missing COLOR parameter Î͙ 0 02Ñ* +* ,bad of missing VOL parameter Î͙ 0<~x(82RÑ* ,bad of missing FEEL parameter ÎA  120603015131175q.?Ñ BAUD RATE parmater missing Ñ.<7:gA 0 5 O; OF 40COL parmater missing ÑxxyÑn i2r A ( ~ O* ~#/(k:(! DATE set error ͝ 0߯2q " y 2p ͝ 0 2q * ~#: " ͝ hn * ~\ ʑ #" " !"n !V  ~ * ~#/f " ~  *n <ͳ 8#"n Nf !(  O ^#V*n "n Current Date is: [  :p :q :r Ñ*n >w* ͑   }< .> 8+X ͑ } '2 N#F#ͳ : (0+++F+N͹ z{}o|g 0 Ox!H!JA 0 " $ CB- ASCI) MPS100 printer parameter missing Ñ̓ )>͝ 82 ̓ #+ͷ +++Ϳ ++: + * s#rÑ CAN NOT install print Filter Ñ!' ## > ++> * ^#VͿ ͷ # ###T] yOT]> *.Z1 * OG(( # ((  7" `i* +#~ (" 1 * ~#\ ( = " 1 7 ,, v gv o͈ G͈ а7; ?#" 7A ; !DM)) )O ; 8}$%7A * ~0? #" 7~\  # ~# >/>:  Ɛ'@' > >  > _mH" j DgAc;Zx0N CONF HLP of variable usage in a program. XREF requires the .PRN and .SYM files produced by MAC or RMAC for input to the program. The SYM and PRN files must have the same filename as the filename in the XREF command tail. XREF outputs a file of type .XRF. Examples: A>XREF b:MYPROG A>XREF b:MYPROG $P tax: DIR {d:} DIR {filespec} DIRS {d:} DIRS {filespec} Explanation: lid CP/M 3 command with SUBMIT parameters ($0-$9) Any data input line Any program input line with parameters ($0 to $9) The command line cannot exceed 135 characters. The following lines illustrate the variety of lines which may Help is available on the following subjects: 21 Jan 85 40COL BAUD BACK BORD CHAR CURSOR DATE DRV DUMP FEEL HELP MAP PARITY POKE PRT REPEAT VOL  40COL =ON, OFF This Command is used to turn the 40 column display ON or OFF. The 40 column display slows the system down about 10%. By turning it off the the system will run a little faster.  BAUD =50,75,110,134,150,300,600,1200 The modem port BAUD rate may be changed with this command. Setting the BAUD rate also changes FEEL and to a lesser extent REPEAT. As the baud rate is increased the amount of time that the processor has to do things is decreased. The system handles the serial port using interrupts. The number of interrupts per second is 3 times the baud rate. See FEEL for more info.  BACK = Set current screen Background color to color supplied.  BORD = Set current screen Border color (40 column screen only) to color supplied.  CHAR = Set current screen Character color to color supplied.  CURSOR = {solid, slow or fast} followed by start (space) end Sets the 80 column display cursor to solid or flash (slow or fast). The user may also include one or two optional parameters that set the start and end scan line for the cursor. This can be used to create an underline cursor or a strike thru cursor. CURSOR=FAST 4 will start the cursor at scan line 4 and end on scan line 7. CURSOR=FAST 0 4 will give a half cursor at top of line. CURSOR=FAST 7 will give an underline cursor.  DATE =[//] [[:]] This command is used to show the current date and time (if no parameters are supplied) or set a new time and/or date. DATE will show the current date and time. DATE 10: will set 10:00:00 with the current date DATE 10:45 1/21/85 will set the time and date as shown.  DRV A,B,C,D =8-0, 8-1, 9-0, 9-1, 10-0, 10-1, 11-0, 11-1 This command is used to allow a DUAL disk drive to be used. The system defaults drive 8-0 to A, 9-0 to B, 10-0 to C and 11-0 to D. If you have a DUAL drive it is numbered 8-0 and 8-1. With this command you can change any drive to use 8-1. DRVC=8-1 will set drive 8-1 to be used as C DRVB=10-0,DRVC=10-1 will set dual drive #10 as drive B and C  DUMP xxxx (address to dump in HEX) This command will dump 16 bytes of memory starting from the HEX address supplied. This is NOT the TPA memory (bank 1) but instead is RAM BANK 0 which is the operation system area.  FEEL =0,1... Feel is a parameter that adjust the way the keyboard feels. The keyboard is scanned with interrupts (the same interrupts that handle the serial port). Thus as the BAUD rate is increased the number of key scans per second increases. To get around this problem not every interrupt is used to scan the keyboard. FEEL sets the number of interrupts that are not used between each one that is used. As the number of key scans is increased the processor slows down. The FEEL parameter is changed when ever the BAUD rate is changed. The default values are set to try to keep about 300 keyboard scans per second. (At 300 BAUD, FEEL is defaulted to 2). NOTE: The FEEL value for 600 and 1200 BAUD are adjusted as follows: @600 ADJ=((FEEL+1)*2)-1 and @1200 ADJ=((FEEL+1)*4)-1  HELP (=topic) This HELP file (CONF.HLP) works with CONF.COM dated 21 Jan 85. There are two ways to use HELP. One way is to type CONF HELP which will place you at a prompt which will allow you to select the topic about which you want information. The other way is to use help on a command line as follows: CONF HELP=topic where topic is the specific topic about which you want information. CONF is designed so that multiple commands and associated parameters can be specified on a single line as shown in the following example: CONF char=2,help=feel,repeat=0 sets character color to red, gives help on feel and turns keyboard repeat off.  MAP (map character sets) This command will display both the primary and the alternate character sets.  PARITY = The serial data can be sent or received with a number of options. The normal and default value is 8 bits, no parity, 1 stop bit (8N1). This command allows you to set the number of bits to 7 or 8. The parity to Odd, Even, Mark, Space or None (only the first letter is used). and the number of stop bits to 1 or 2.  POKE xxxx =byte,[byte,byte,....,byte] This command will allow the user to change bytes within the operating system. Care must be taken because with this command you can BOMB your system. This command works with BANK 0 and NOT the TPA (bank 1). The address range that can be changed in 1000 to FEFF, below 1000h is ROM. POKE 4000=41 42 43 44 45 will write 41 to 4000 and 42 to 4001 etc. POKE 4000=4142434445 will do the same as the above line  PRT PRT1 or PRT2 = CBM, ASCII(secondary adr), MPS1000(in IBM mode) This command allows you to specify whether true ASCII or PET ASCII will be sent to a printer on the serial port. The CBM parameter selects PET ASCII with a secondary address of 7. (A secondary address of 7 selects upper/lower case). The ASCII parameter selects true ASCII and defaults the secondary address to 0. If a number follows the command it is used as the secondary address. The MPS1000 printer can be placed in true ASCII mode by placing DIP switches 1 and 3 on and using the MPS1000 selection (same as =ASCII 128).  REPEAT =0,1,.... This command sets the rate at which keys will repeat. A parameter of 0 turns off repeat; otherwise, the lower the number, the faster the repeat.  VOL =0,1,2,3,4,5,6,7,...,15 This command sets the volume of the keyclicks as specified by the associated parameter. (0 turns the volume off; 15 sets the loudest keyclick; default is 6)  o $9) The command line cannot exceed 135 characters. The following lines illustrate the variety of lines which may 1!!!s# x *W">2%2%.D͚2%h 1|`2U&͆͝C128 SOFT KEYBOARD PROGRAM 3 June 1985ͩWelcome to the Commodore C128 Keyboard Definition program. Do you want help? yͻ9cFrom which of the following sources ofkey definitions would you like to work:Default definitionsDefinitions on the CP/M boot diskCurrent definitions:%< > 2Z&2%2%ͤH5iYour previous work file> 2Z&2%2%]Sorry, no CPM+.SYS file on disk.Type RETURN key to continued͋working from 0 CPM+.SYS$Y CURRENT= DEFAULT definitions2%]Your work file is now set up.You can:Edit a key definitionSet up logical<-->physical colorsExit and save your work file> 2Z&2%2%ͤiBEditing: no key This key has the 4 values shown below. normal --->CMDR SHFT->SHIFTED -->CONTROL -->(done editing-exit and save work file)>2Z&2%2%:%':%G<͊"[&yx(BͲ h&)),$"%*[&"%x2%*%"]&*%"[&> 2 >2 :%'ý:%G:%ʭ:%<ʽ:Z&O*]&O "]&9cNow, please select what you want to do: ASSIGN a STRING (more than 1 character)ASSIGN new (single) character ASSIGN a COLORASSIGN hex valueASSIGN a SPECIAL FUNCTIONdon't modify this key> 2Z&2%2%ͤ8 8O :%ͭ[*]&"[&@IR|xmxrxwxh*[&~aq{ڐx!t*[&~#"[&! !Ҕ_$ SpFn<!>$( O#~ #y#~_$string - GÁ֠!807ְ!80F!40)!408̓40 column border colorÓ"wqforeground"wqbackground colorÓ̓00 column ɧ(G4 _$!ɯ2%=2%ͫÿ >2>2>2`9The following strings exist:>2V&:V&<2V&Gů2%G4x2 0͡ G0 ́--->show other set of strings<--->2Z&2%2%ͤ*]&(wG:2:02:`2`ú2%=2%~#ͩ:%<͡ >>á ( O#~ #y#~͡ +~^# ͖ >á 0 8 xá ͖֠̓ 80 fÓְ͖̓ 80 bÓ͖̓ 40 fÓ͖̓ 40 bkÓ͖̓ 40 bdÓ~#͡ _:%<2%$:%<==2%" 2 9 9cType alphanumeric keys to edit....else select: exit string edit - save assigned stringinsert a colorinsert a hex valueinsert a special functioninsert a second string> 2Z&2%2%:%'͐use rt/lft arrows to move within stringuse inst/del key to edit within string: 02%:%2%ͩ* :%O ́:%) :%(:%<: (:%_ͱ=  ځ _yR xʧ {n W Ͱ r: <2 _: O{ :%{ xU V œ yʭ × Ͳ :Z&O:%o&) ~#fo  - < : ><2 : $=2 O:% n  > V n  U V *]&"%!%"]& *%"]&:%n  ͫ V :%< ͮWARNING: Deletes to end of string-OK?yK ͫ ͐ : 2%V ͗ !+$RDMbk#+6 !+$ȯRDM!*$+$# w* : o|g~]type the character you want to assign:  0 *]&w͊xo&] XxG~= 7k&))>O ~U ]͟Only 0-9 and A-F are legal.Type RETURN key when you are donecEnter HEX value: 2%2%*]&Ny)2%y-2%:%_$:%_$͊x(9~0 8'0^:%2%{2%$$O:%2%>2%:%:%*]&w 8'0>]Do you want to assign:ͻͻborder color?don't assign a color> 2Z&2%2%ͤ> an 80 column a 40 column foreground color?background color?>!>!>!>!>*]&w]Which color do you want to assign?[ ] G4 a>2%>2%z2p{2n!%5 #5 G0 ͱ͊͜~a0*]&wͫ]ͩ>2V&These special functions are available::V&<2V&!>2Z&2%2%ͤ*]&w99Assigning logical <--> physical colorscDo you want to assign colors for:80 column screen?40 column screen?done logical <--> physical colors> 2Z&2%2%ͤ!"!">2%! "!">2%%B͕ LOGICAL COLOR MAPpL ͚ PHYSICAL COLOR MAPpͮHit RETURN key if done assigning colorsͶSelect logical color to be defined 2Y&Select physical color to assign !%_:Y&O {:%ww͊x~_$a  w!w!|!!!!!!!!!!!!!!G4 a!b"c#d$e%f&g'h(i)j*k+l,m-n.o/pG0Ü!!+#Ⱦ(#  $ $~_#<('{222$$$. ͚. Úͩ/é́/Áͮ/îh/hc/ I D ? : 5 0+&!   .Úͤ͟ß.Úͩ!"ů2%29!,>2:2;2<7CPM+ SYS!]!!!"[&* "W&I*W&]T#"W&ͪ*[&q#"[& x I*[&N#"[&*W&]T#"W&>ͪ x :U& }o>9cDo you want to save your work file - on CP/M boot disk?as CURRENT definitions?don't save> 2Z&2%2%ͤd+BcDo you want to do anything else? [ ]yCPM+.SYS disk+]Sorry, no CPM+.SYS file on disk.Type RETURN key to continue.díCURRENT definitionsy+]saving your new definitions to ͝c...exiting keyboard definition programͮAre you sure? [ ]yͮ͊x7' >ͪ(h&)):Z&2%:%'͊x@ʻJͲ:Z&G:%Go&)~##(++~#fox:%ͭ:%G:%<2%':Z&G:%!=2%:Z&2%:%2%/&@eW!%"W&2%.<͚*W&p#q#"W&{( +C> + +x2%W|2V&!%"W&:%G*W&F#~#"W&g:V&O.@͚G0:% _$&exS7T>2%_&,m(=B!_&>2Z&2% 2%:%2%ͪ B~#foG:%2%!_&~# B TYPE RETURN KEY TO RETURN TO MAIN MENUd͊x 9cSORRY - NO KEYFIG.HLP ON DISKtype RETURN key to continuedKEYFIG HLPUNDEFINED^A^B^C^D^E^F^G (BELL)^H (BACKSPACE) ^I (TAB) ^J (LINEFEED) ^K ^L ^M (CARRIAGE RETURN)^N^O^P^Q (X-ON)^R^S (X-OFF)^T^U^V^W^X^Y^Z^[ (ESCAPE)^\^]^^^_RUBOUTSTATUSPAUSE40 COL TRACKING TOGGLESCREEN LEFTSCREEN RIGHTMFM UNLOCKUNDEFINEDUNDEFINEDUNDEFINEDUNDEFINEDUNDEFINEDUNDEFINEDUNDEFINEDUNDEFINEDUNDEFINEDBOOT C-128INST DELRETURNCRSR LF RTF7 F8F1 F2F3 F4F5 F6CRSR UP DOWN3 # 4 $LF SHIFT5 %6 &7 '8 ( 9 )#0(++-,.>-:[.@/,<0BRITISH POUND1*2; ]3CLEAR HOME4SHIFT (RT)5=6UP ARROW (PI)7? /819LEFT ARROW NEXT TO 1;2 "::[{@@@,,<###`***;;]}===~^^||//?\11!___ 022" ! qQQ🟟888555 222444777111+++--- 666999333000...."3DUfw $e placed in true ASCII mode by placing DIP switches 1 and 3 on and using the MPS1000 selection (same as =ASCII 128).  REPEAT =0,1,.... This command sets the rate at which keys will repeat. A parameter of 0 turns off repeat; otherwise, the lower the number, the faster the repeat.  VOL =0,1,2,3,4,5,6,7,...,15 This command sets the volume of the keyclicks as specified by the associated parameter. (0 turns the volume off; 15 sets the loudest keyclick; default is 6)  to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> ThHelp is available on the following topics: --> done help <-- --> General Usage <-- --> Setting up your work file <-- --> What to do with your work file <-- --> Key values <-- --> Selecting a key to edit <-- --> Logical/Physical Colors <-- --> Editing keys <-- --> Assigning/Editing Strings <-- --> Assigning Colors <-- --> Assigning Special Functions <-- --> Assigning HEX values <-- --> Finishing up <-- --> For experts only <-- Use the up and down arrow keys to scroll through the menu; type the return key to select the topic on which you want help.The purpose of this program is to allow you to alter the definition of almost ANY key on the keyboard. The only keys you CANNOT modify are: the SHIFT keys, the SHIFT LOCK key, the CONTROL key, the 40/80 DISPLAY key and the COMMODORE key. At each step, options are presented in menu form. You can scroll through the options in the menus by using the up and down arrow keys at the top of the keyboard; pressing the return key selects the choice that is highlighted. At almost any point, you can exit the program by typing 'CTRL c' (the CONTROL key and C simultaneously.)The first thing you will be asked to do is set up your work file. You will be given a choice of 3 sources from which you can do this: DEFAULT DEFINITIONS - which basically represent a standard set of key definitions. CURRENT DEFINITIONS - which represent the most recently loaded set of definitions. DEFINITIONS ON CP/M BOOT DISK - which represent the set of definitions stored on your boot disk, normally default definitons, unless you replace them via this program.Once your work file is set up, you will be given a choice of 3 things to do: EDIT KEYS- which allows you to modify key definitions. ASSIGN LOGICAL/PHYSICAL COLORS - which allows you to redefine the meaning associated with a particular color. EXIT AND SAVE YOUR WORK FILE - This is provided here as a quick means of copying one set of definitions to another. For example, loading the default definitions into your work file and saving them as the current definitions, provides a means of restoring your current definitions after running an application which may have used a now undesired set of key definitions.Each key has 4 values associated with it: normal value - which represents the unshifted value of the key as labelled. SHIFTED value - which represents the value of the key, as labelled, obtained by typing the desired key and the shift key simultaneously. CONTROL value - which represents the value of the key obtained by typing the desired key and the CONTROL key simultaneously. CAPS LOCK value - which represents the value obtained while in COMMODORE mode. This mode is obtained by typing the COMMODORE key and stays in effect until you type it again.To select a key for editing, you must actually select the specific (1 of 4) value of the key that you want to modify. To do this, type the key so that the four values associated with it are displayed. Use the up and down arrow keys to scroll through the four values; type the return key to select the value that is highlighted. This is the specific key value that will be modified. The next time you view this key the new value you assigned will be displayed. You can modify as many keys as you want. When you are done, select the fifth choice - exit and save work file. (NOTE: To view the up arrow, down arrow or return key, type the desired key and the control key simultaneously). Once you have chosen to assign logical/ physical colors, you will be given a choice of doing this for either a 40 or an 80 column screen. Then, two color maps will be displayed. The top one is the current logical color map; the bottom one is the physical color map. You will be asked to select the logical color you want to assign (type the letter in the box with the color you want from the top map). Then you will be asked for the physical color you want assigned to it (type the letter in the box with the color you want, from the bottom map.) You can assign as many colors as you want; type the RETURN key when you are finished. Once you have selected a specific key value to edit, you will be given a choice of 5 ways of modifying the key: ASSIGN a new character - which allows you to do a 'one-for-one' replacement of the key. ASSIGN a STRING - which allows you to assign/edit a string (more than 1 character) to the key ASSIGN a COLOR - which allows you to assign an 80 or a 40 column color ASSIGN a special function - which allows you to assign a function from a list of currently available special functions. ASSIGN a HEX value - which allows you to replace the key value with a single hex value.Once you have chosen to assign a string, you will be given a list of 32 available strings (some of which may already be defined.) Scroll through and select the one you want to assign to this key. At this point, the one you choose will be displayed near the top of the screen for editing. You can edit by typing keys and/or by choosing one of the menu options presented -insert a color, a hex value, special function or second string (warning - the remainder of the string will be deleted if you insert a second string.) You can also use the left and right arrow keys and the insert and delete keys. When you are done, select the menu choice 'exit string edit and save assigned string.'Once you have chosen to assign a color, you will be given a choice of 5 color types to assign: an 80 column foreground color, an 80 column background color, a 40 column foreground color, a 40 column background color or a 40 column border color. Scroll through and select the one you want to assign. At this point, a color map consisting of 16 boxes labelled a through p will be displayed. Type the letter from the box representing the color that you want to assign. (NOTE that one letter (usually 'a') will appear to be missing, because it blends with the background color - assume ALL boxes are lettered sequentially!)Once you have chosen to assign a special function you will be given a list of 16 currently available special functions. Scroll through the list and assign the function you want this key to perform.Once you have chosen to assign a hex value to a key, you will be prompted for the value to assign. Only characters from 0-9 and a-f (upper or lower case) will be accepted. As you type characters, the current value is shifted left one nibble and the new value is ORed into the lst nibble. You can type as many characters as you want, but the last 2 you type will be the value assigned to the key. Type return when you are finished. Note: The value you type when the four key values are displayed will not be displayed as hex, but as what the hex value represents. WARNING: This mode should only be used by those familiar with hexadecimal data.Once you have loaded your workfile and completed any editing you wanted to do, you will be given three choices as to what to do with your work file: SAVE AS CURRENT - which makes the definitions in your work file effective immediately upon exiting this program SAVE ON CP/M DISK - which will cause the definitions in your work file to be loaded the next time you boot from the disk to which it was saved DON'T SAVE- a means of exiting if you made a mistake or changed your mind Scroll through and select what you want to doTo edit key definitions without using the KEYFIG program, type the CONTROL key, RIGHT SHIFT key and RIGHT or LEFT arrow keys simultaneously (RT arrow selects string edit, LFT arrow selects hex edit); then type the key you want to edit. If assigning a string, the key must already have a string assigned to it. A window will pop up at the bottom of the screen, in which you will edit. Either enter the hex value or type the string. If editing hex, any illegal key will abort the edit without changing the value. Commands for string edit are all entered by typing CTRL,RT SHFT with the command key. RT&LFT arrow keys move within the string, RET exits the edit, '+' or '-' inserts/deletes a character.1'!~] closing brace is not required A>c1571 [a,c will turn off verify on drive A and C Von Ertwine ~# (+A(B( C(D 2:b2bx2s:b>W[>KH!+[:G:bG>>>>*o 2c:(Drive A (G(+0:82(had a channel error 0 h (not on serial bus (is not a FAST device (1571) 2.,0}2!+"2k:•0~9#_ɮ Cu+ V+ ++ V+ p+ V+`  0hhL `M-EM-W xX`M-WHɠE Lߝ  * The Digital Research Inc. COPYSYS program is not implemented on your computer. Your Commodore 128 uses a different method to prepare a new system disk. To obtain information on this method, type: HELP COPYSYS at any system prompt. Note: Be sure to include a space between HELP and COPYSYS. $e placed in true ASCII mode by placing DIP switches 1 and 3 on and using the MPS1000 selection (same as =ASCII 128).  REPEAT =0,1,.... This command sets the rate at which keys will repeat. A parameter of 0 turns off repeat; otherwise, the lower the number, the faster the repeat.  VOL =0,1,2,3,4,5,6,7,...,15 This command sets the volume of the keyclicks as specified by the associated parameter. (0 turns the volume off; 15 sets the loudest keyclick; default is 6)  to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> Th( COPYRIGHT (C) 1977 DIGITAL RESEARCH 112O02Z0̀%!"K2.>2.*M0"$/̓%!"":g0i!"P0"R0"2:0v: 0$  :[0-ʬ+ʬ* :[0!_0M!f0P p  !   :O0Ĝ!":O0*V0}|<r ͪ*|Ĵ:O0_͑H *V0"Ù*V0"E V» ͪ»**»"Ù*K0"X0!0NA#~' ~p"K0*K0N"X0!0q#*w œ:0!x ͜ *V0*R0:_0̍"V02*M0r; !:r :0F: 0e%;m ">2:0b: 020 W,F:0b: 0e,ʹ:re*X0#![0~ʇww2/ͬ:2T/-"."$/2/>2.v:.ʸ!/6+͕%>20:.ʮ:.0209$<!5*}Ģ*V0":0y: 0:yv! X! ^#fkX _~ 0^ Z   2 5 8  :0‰:0=ʉG! 0ʃF#2sÖ*I0| E2V ,[ ͊m *R0"R0"P0 m E2D2V ,ʾ ͊:/ m :/ "> 2/:Į:0 : 0 -Ͳ !/6+:.;?*$/*."$/?"$/:.l*.^#V{r+s5*.^#V ʓ:. r+s!06#wÚ> 209!e/~6![0~6".~,#!0w9 9*.~6 *: 0,Ĵ2f/*.s#r2[02e/*.#"X0$<5ͬ*$/"M00:T/2:/2[0 v>20*.".2[0v*R0m "R0͍"R0!/w >=G*R0*I0"R0"R0 m :/ }>͞ ¥͢ :O0*V0*ʿ͜">2:O0:0:O0!!4:0: 0,>"4:O0: 2\0:0=: 0 F!Fʹ%*X0"`0>2Z0*X0":0k: 0T!T:\0¦:O0¦:0=ʦ ʦ*"X0 !':[0'Tx»!Z04TT!Z05T:\0!":]0!**V0":O0*X0~ Ĵ*X06 '>#G*I0!" :0 :Z0 !0N*K0:O0Ÿ"b0+"X0yʛ 'É' Ͳ >ͮ 222:0: 0 !ͮ-:0:0!4 :0& : 0::0!xI !4̨ e ::̮>͞ } !~5:Į ͵ !4̨!~5 G!~Ҩ4_!p!~ʮ5^!~> >2\0:0N *K0"+"X0:0 >''!:0N : 0,N :0 >  > !0N#~' ) > ''*K0"V0:\0x ʹ:\0" m }*K0"+"X0''*K0"V0>"4ͬ:2T/:[0 “ 2/-*M0"$/*X0!{#zڿ ~+"X0*M0+"M0wß #"K0*M0".:\0 N]T s#r+*V0*{_zW".:\02.R     % *I0:/ ͪ% ͬ:O0ĭ%  :.ʢ :0¢ *K0+"X0!2<20*#"" : 00Ĩ!??" 09"K0+"X0$< :0¢ : 0,? ʹ  *} :]0 :O0 :0 ͤ%:e0ĭ%:0 : 0  ͬͧ%vʹ   ͺ :0: 0 !;* _!5 ^#fkS \ h n 2 ͠ ͻ ͵ ͠ ͖ 8{ Ăy0 2͵ ͖ Gͻ ͋ ͖ 1ͻ ͯ 2ͯ ͖ (Ăy 2͵ ͋ ͖ ͖ Ăy0 ͖ 2ͯ 1 'd ! ^#V#*0}o|g*  ":D x=D y0P 2!0^4! 0q :0Ė: 0,; Ė*I0m |}$† ͌oy Ԍ͋ 8O͖ Ăy01y 1m X:0 : 0, >C͘%:0 : 0 v;:0 : 0 v-!v !v-ʹ {ozg:.7ͮ2Z0!O0~4l!"*|>"V0*""J͊!/6 !/͒%:^0ʏ>2.͡%ͱ*K0*T0&*M0*T0&\ ͍!/w#õH USE FACTOR !/͒%*"P0Þ%z{*P0"R0*"V0 !":O0Ģ*R0̜*R0ĜG:O0xě%:/ *R0̍:xz*P0#"P0E2D20:b!^4!/wjj*R0!6zz{z4A_A?ɯ2.2*T0"V0!.8w# *V0*K0{zҤ*b0+"X0 =$**X0#Þ!.*V0".#"X0$:d0<:0<! 0~?<#ʐ: 0͡!.".^#V"V0}{##~2.*.^#V#"."V0*V0}d##~<2.G*V0##"X0:.> u!.~w>w> u:.P'!5^!/~ !~620͕%2.|z}z> u!.~w:.W=*u!.4C*V0^#V"V0ý!.5¯:20͕%!^4!/w>R͘%>V͘%>Dý>Pý>Lý>Oý>Bý>Sý>N͘%*6".~ 6nLT`-!2~B6~44O!! s#r!1~ _6^4! w!p!2~~!55N!! N#fiooo&)^#fk9BIO[ov ͌z{>ɯo>g͌"!6ů{_zW5>)D*OxG !?DM!xGyO23)#͌)=R|g}o=^͌͌roz{͉͌͌}|͉͌Þ͌Þ͌ë͉͌!!o#Ã͌zg{o͌zg{o͌zg{oolo&3:0: 0 ;!,ɯ2122=2 !"I0&q!1~\5_! ~͔D:2:/ *!"I0:/ :0:0! 0^#=ʙV¨*0!҂ :0:0& !!>O: >2 yU`:10_!~0!1s! ~͔ yU!1~N=w_! ~QZP>2 ypP͘% >U̘%>: 2 3>E͘%óf:.O*.~H:.=!4>͕%0:/#". ͆%2G:0xa{_ ʇ ʇ:0x҇_<20!/w:e/S:e/9ɯ2f/2d/2e/:0:e/ !2f/g/~#»S͉!f/~4!g/_:e/w2e/ɯ<*V0"36*"V0ɯ2!4!f/6".!f/~55!d/^4!g/~f:.:e/JGwf^l͗^{:e/&{!f/4#ww&ʞGʱ2e/xf͗ :e/&ʕ:0  ý͗&{&{ý͗  !e/~&>62/-!.6*M0"$/B".2f/*"V0͗ 2f/2e/2[020> 2͕%>20ɯ202!0~@$6^4#:[0w~$w:[00 6:[0A:[0?e@eAɷP6 o2[0:Z0ʦ:\0 :O0¦:[0':[0 !20:[0 R;/>20:Z0?:\0:O0?́;B*`0*X0++{z~ ++!+"X0:Z02Z0́ͪ'2Z0X:[0*K: ḰͪX? X́ö20Pg>ã6r>ã:[0'ƒ2[0>ã ¡:.ʔ>+2/͕%!/6 >20>20:[02́:0:Z0: 0=!EQ<!LT:[0=!LE>!GT:[0=!GE2[0" 0!04>20![0:0/ʦg¦´/ʦA¦:[0O<QA>HHR>22[0m:B_>fD> j!052!"0!0N#~#A҄0Æ7O!~*0!ʩң)Ú "0 x:[0 '¦́'æ:[0 :[0,;%:[0 !:[0; ,202́/>20:[02́:0G:0::0l:[0'́:[0' 20/:[0'|>20^—́:[0  <¨!~4 >¼!~5 : >20>V>O>I>B͘%!QéÉ $ ? H Y ` e Ò ü ò ~ÏGÇåûfD?<==:e>?; ><>; ;<=R>>>F>;>G==<==>=s;=P=*>=$?P:-?]>*<<==<;=>>y> ;: =;>?>P?<=?>>=<<i;m=>c==>o>v<=<;8?N!Nw#w#W!"V0!.w#w#l2N!.~4^!.~w!.ͼ!.ͼ!.ͼ!/~w!$/ͼ!D/~w!T/~wN#Fp+q!.~^!.!. !. !. !/!$/ !D/!T/5~wN#Fq#p>BØ%!0" * F#%2NG*V0##~w*V0##~<͉:.t!.N!. yq~t +aG=#w#wY*M0!0n& {ozg"V0!K0{#z"M0b*M0!0N#yʢ ~Õb!."O1:N *M0!$/{#z"V0$ _!.*V0~#~1 ~#"M0û1 !͒%Þ%SYMBOL TABLE OVERFLOW G*V0##~w*V0##~=*V0_###1 s#r1 ^#V1 ##"X0P wP ~O!0~z 6~=ͼ !0N#~ͼ „ Ͳ O2Ny *\ ?=)$=)w#Ž&!\60 ڱ&>GO#w ³&>O # &6 &6L#6I#6B#w2|r&\u'>2]0!"%![0~2%wG&!,x&>82%2%!"b0*"M0!1"%"&"@&#"K0"T0' _#~6' D':%A6'>:6'D'>.6'D'>-6'x&!,N'!k-x&!,N':% '> ':%'_!% '6 4ɯ2%2]02e02d02g02%:\ =)!%w#w#w#w#w#w#>2^02_0:m$(!~#$,(~(# 3(%Aʩ(Pʩ(Sʩ(Hʩ(Lʩ(*t(+t(-¶(^0~Sʣ(Mʣ(e0Lʣ(d0Qʣ(g0Rʣ(%1¶(x#3(~AҶ(#3(#6 !)-x&!x&!%͉&!%͉&ͳ'(`&͛'͠':%)!&͉&l&͛'͠'!%60#60#60#>2f0!"&:O0*!"%2%2%2%Z&%u'!-x&z{:]0ʢ)*%F)w)!"%r&\‰)*%#"%+~):.2]0ʢ)r&\!~-N'*%F))Z&!"%*%B&%)¼))*)6# )G&*%*%#"%~!<-x&G:%7*$*x*7*x2*Ϳ'5*9**&*&w#"&!F)`&!"&*&%~ʅ*B&Œ*`*G&`*!S-x&ö,͟**>&*@&w#">&!F)l&!">&*@&&`*_!%~ *2%*b0}!,~ +*#+> *>#**> **b0~>+*#2+> *> *> *}2%!%*O*:/ :O0:%y*:%!O0•+:e0!]0+~,:/ ,!/~ +:f0,:/++:_0,+:/#,:/ ,:_0=+!/~ +!0s!%~!%*4:0!/,G~Y+#x=+> Y+> Y+20!/>x6 #=,G!/~ pͳ'*&}?,>*/,`&%͈':^0*+,!&6S#6Y#6M#w!&w:%2%!"&ͳ'*2%`&%͛'͠'+,:%ʶ,:%.*P0"%.*>&}ʶ,>͕*æ,:%,l&&͈'!-x&CP/M MACRO ASSEM 2.0 NO SOURCE FILE PRESENT NO DIRECTORY SPACE SOURCE FILE NAME ERROR INVALID PARAMETER: SOURCE FILE READ ERROR OUTPUT FILE WRITE ERROR CANNOT CLOSE FILES UNBALANCED MACRO LIB END OF ASSEMBLY G:%x-!%~--.-*P0*%O {-z-.*P0"%!%^4!%w..WƐ'@'Õ*>:͕*!%^Ww*%{-|-}--{?.!%~#-6.-> ͕*> ͕*͞*> ͞*wsT =0,1,.... This command sets the rate at which keys will repeat. A parameter of 0 turns off repeat; otherwise, the lower the number, the faster the repeat.  VOL =0,1,2,3,4,5,6,7,...,15 This command sets the volume of the keyclicks as specified by the associated parameter. (0 turns the volume off; 15 sets the loudest keyclick; default is 6)  to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> Thè COPYRIGHT (C) 1980 DIGITAL RESEARCH @: 5@%nLT`15252'5h+U"!""*"5j"2u3>2v3*5"3-ͩ-:5Z!""$"5"5"5"5"5" " 522>2 5:4 b:4$M:(5-C+C*M:(5!,5M[!35PMp%M(ʡͣ#v#ƒ$:5}% }!"&:5ʦ>%*#5}| V AX*|:5(#$*#5"A*#5"&#v#% RØV AR*&*R"A*5"%5!4NA#~ͫ% p"5*5N"%5!4q#͢%w 3:4(x *#5:,5o"#5V%2*5Ô; !:V :4:4{%͉"">2!:4:424*o,kÊo:4:4{,ʊ:k*%5#!(5~́ w23@:2(4y""3"323>2v3 :u3L!P46+(0>24:u3:v3"U24͋$͇%ͩ$!5*}*#5":4:4: =X!^#fk:Vj&AW y ~   8 ; C :4:4=G!4F#I ,*5͘EIr,o͉n2"5~2 r,Yo :K4 ͉:K4 " : 52> 2K4::4M:4 Mg %U!P46+:v3Ϳ$ý*3*3"3Ϳ$"3½:v3*3^#V{ʽr+s*3^#V ʽ-:v3:r+s!46#w4> 24͋$í!94~6!(5~6"3~,_#!4w͋$ÏV *3o6͋$*3~6 Þ*3:4,"3~ š62:4*3s#r2(5294*3#"%5͇%ͩ$@*3"5":(42:32(5Ģ >24*3"32(5 ͉r!Q4wM>=n2*5~2%! 5%~2͉:K4 v }>v S M:5p*#5*gu>%"u> %2 :5O%:4©:5[%! 4:4©:4,ʀ>:5: O%% 2)5:4:4 !*%5"-5>2'5*%5"&:4:4(:)5N:5N:4=N N*&"%52)ͫ%:(5ī%x;c!'54!'55:)5ž!":*5ʍ!5%Ù*5%*#5":5*%5~ *%56 ͫ%<͉:K4 "5~2o M%(>@%>#*55%!".!/5",:4M:'5M*,~#T :5T !4N*5*,s#r+"%5yP  ͫ%> ͫ%%g >v % 222:4¦ :4 – ì !ʬ ¦ À :4:4€ ( :4 :4:€ :4€ (€ € x !4À  :€ :>S %2 !~5€ :%j B !4À € !~5€ úG!~4_!p!~5^!~>À >2)5:4 *5" +"%5:4ڥ >ͫ%ͫ%[%:4 :4, V :4  + !4N#~ͫ% > ͫ%ͫ%*5"#5:)5- :)5%͉}*5" +"%5ͫ%ͫ%*5"#5>@:2(4:(5 H 23y"*5"3*%5! {#zt ~+"%5*5+"5wT #"5*5"3:)5ʑ N]T s#r+*#5* {_zW"3:)52v3 > > >2 5n2"5 %: 5*#5* 5"#5*55%"#5:5KBn2: 5O0!*", ++ *5:K4 0@:5Ĩ/ú>2) :u3ʭ :4­ *5+"%5[%2!<24*$#"$""*:40!??"4͋$"5+"%5͇%ͩ$+:4­ :4,J "*} :*5 :5%:4 +:25Ĩ/:4 :4  @S+ >2):4„ ͣ#v#: :5$:)%k %G I k :)%:)c %k %+:4„ :4, " :4 :4/ :4 :5 $*#5^#V*S"s#r*5*#5s#r+"5 |#v#*#5" 5:4 :4/ !"5:5> %AB,#*#5 :4:4 !;*M_!Q^#fkox Iͻ8ʗy0IͻGͰͻHIͻ(yIͰͻͻy0ͻIH'd ! ^#V#*"0}o|gF 9"":!`x=`y0l2!!4^4!4q/:4:4,; *5͉: 5ª|}$ªo͕Ͱ8Oͻy0H͕H͉: 5në:4:4,>C0:4M:4  ;C:4#:4 ! #! #{ozgBB**}j!]~ } #ymy>2(>2v3͖*5|EB"#5>%0,# ^#VÕJB*50MB*50!".*5} "#5^#V"5*.s#r+".*."5:u32'5!5~4P!"*|"#5>%*5%"".o!P46 !L4*>2(>2v3͖>2(>2v3͖NB:O* 0:+5ʘ0*5*!5S*5*!5S\gr!P4w#þH USE FACTOR !M4** "5A1z{*5~2*"#5v#!":5(%! 5%n25%%%>%n2G:5x:L4 o:x_*5#"5:5ʽ*5|ʉIB0>%%O%O: 5%*55%ý:5ʽ: 5O*5*5ESS͎2O=>O͎2N=#y{#* 5* 5 "#5" 5͎21͎2=HÎ2Î20:G!^4!K4wOOn2!6z_{_4A_A?*!5"#5*#5*5{z*/5+"%5**+"%5% V%=͇%͢%*%5#þ!v3ʲ:(O! ^#V4@B%GFB>%%O0*#5##~<##ò*#5"|3#"%5͇%:15^:4^!4~?^#ʲ:4͆!~3"z3^#V"#5}ʝ##~2v32w322(!~38w# ͖!~3"z3>2y3*z3^#V#"z3"#5*#5}ʩ##~<2x3G*#5###"%5:w37> ͺ!w3~w7>w> ͺ:w3Pd!5^!K4~ B!~624(02w3%!>%|_}_> ͺ!w3~w:x3ʜ=͢%ͺ!w34È*#5^#V"#5!y35:24(0!^4!K4w>R0>V0>D>P>L>O>B>S>N0!u~ڇK6N4!E s#r!U :mw* 5!] s#r!t~ ڹ6K^4!1w!;p!u~K!5N!E ~#fo!U ~2n!] ^#V"pK2oo&) ^#fkN]ivKzV{K>ɯo>g"!6ů{_zW5>)D*OxGғ !?uDM!xGyOڱò)â͝ddJ)=J|g}o=2o2o*p"rOxKxGyKxGy0KG*p*r}|K\\z{W¢Ü}|ڜâWʜllyWœâ!!#Qzg{ozg{ozg{ol&:oO:n2m*p" 52n2ox:4:4 ;!,ɯ2t2u2 52o=20!"5" 52m{!t~Q5_!1~9:uK:K4 *E"5:U2 5*]" 5*v"#5:K4 $:4§:4KK!4^#=ʣV²*4(—ҌV :4:4V !!*/O:0K>20y_j:t:_!;~:!ts!1~y_!t~X=w_!1~[Kdͪ>20$y$zU0!%2m*#5"v:mP>U0%4>%:m!>2m*202m!" 5/:0Kx*#5DM*5" 5}|^#V<>E0:u3ʛ*3~Œ:v3ʁ!\4>A!(0":3]#"3,ž"3Þ-2\  :4x_<24!K4w:94͜:94ɯ2:4284]294:4:94K)2:4;4~#!͜,!:4~*4!;4_:94w]294ɯ<*#5"W͉#4#*W"#5ɯ2[![4Y5!!:46"3!:4~q5!84^4!;4~â:u3:94†G³]âʻ^¨^·:94&·!:44#wó&G294xâG:94&:4G/G&ʷ/&ʷG/G!94~&>623y"!v36*5"3$"32:4*W"#5GJ2:42942(524> 2S(0>24ɯ242T!4~@`65!^4#:(5O:4yD(w~$w:(50 |:(5D(A:(5?ʱ@ʱD(Aɷ͙| ;!Cͻ2(5:'5:)5:5:(5ͫ%:(5 !J24:(5 ʞ;{>24:'5ʋ:)5.:5‹;Ž*-5*%5++{Iz]~ T++]!]+?"%5:'52'5hͫ%2'5ä:(5*—:S —ʤË ¤24͙ʳ>|ʾ>:(5'2(5> :u3>+2P4(0!K46 >24>24:(52SR:4Z:'5:4=!EQM<8!LE:(5=I!NE>I!LTM>!GT:(5=M!GE2(5"4!44>24!(5:4ruͳ u͇:(5D(OʓQ˜>ßH©>2T2(5:SD(B¹>D> !452T!"4!4N#~#A07O!T/!~*4! ) "4 :(5 5!'':(5 :(5,;%:(5 !:(5; ,J242Z$ l ` / ‰ >24#!:(52S:4; ¡ :4/!:Z/!)!:4 :(5'#!R:(5'z 24É :(5' >24#!^ :(5 #! #!;!)!<!!Z~4z #!>!!Z~#!5z #!:Z#!G )!Rz >24>VG!>OG!>IG!>BG!0!P!w#w#["!"#5!U3w#w#p"!u3~#4^!v3~w!3ͷ"!3ͷ"!3ͷ"!3~w!3ͷ"!4~w!(4~wN#Fp+q!u3~#^!v3"!3#!3#!3#!3"!3#!4"!(4"5~wN#Fq#p>B0!4"%*%F# #2P"*#5##~G=#w#6#w]$*5!4n& {ozg"#5!5{#z$"5f$*5!4N#yʦ$ ~Ù$f$!U3"Q"/$:P"%*5!3{#z"#5%_!U3*#5~#~&%~#$"5ÿ$&%!%*A1SYMBOL TABLE OVERFLOW *#5###w*#5###~,#*#5_####&%s#r&%^#V&%##"%5F%wF%~#!4~l%6~=ͫ%ͫ%!4N#~ͫ% y%͢%͢%2P"*ÿ*:?*ÿ*:@*ÿ*~x/~# *> x/\ ?-$-w#+!\64 #+>GO#w %+>O # <+6 2+6L#6I#6B#w2|*\+>2*5!"B*!(5~2A*w͹*!1*>826*27*!"/5*"5!5"h*"*"*#"5"!5\, _#~ͨ+ ¶+:;*Aͨ+>:ͨ+Ͷ+>.ͨ+Ͷ+>-ͨ+*!1+!32*!1+:=* D,> D,:D*6,_!D* W,6 4ɯ2D*2*522521528*:\ -2;*2@*O:\ʋ,=Ì,y!<*w#w#w#w#>2+52,5:m$>-!~#$ª,~>-# ʱ,<*A-P-S-R-L-*,+,-,-+5~S-M-25L-15Q-8*1,-x#ñ,~A,-#ñ,#6 !1*!*!E**e !N*+-!j**%,r-6* ,,:=*ʂ-:>*…-2:?*ʨ-!***ѯ2:*29* ,,!3*60#60#60#>235!"*:5ͨ/-!"f*2Q*2e**E*+!1*z{:*5G.*B*-.!"B**\..*B*#"B*+~¤.:u32*5G.*\!F2+*f*-•.*!"f**h*ʹ*E*€.a.Ò.Ҫ.ʒ.6# ‹.͹**h**f*#"f*~!2*G:=*..xx/.x.1,..****w#"*!-*!"***j*!*-/~5/ʹ*9//͹*!2*1L/****w#"*!-*!"****/_!5*~ ͳ.27**/5}!1~ /ͳ.#/> ͳ.>#ͳ.ͅ/> ͳ.*/5~/ͳ.#/> ͳ.> ͳ.> ó.}26*!7*è/Oͳ.:K4 :5:=*yx/:8*!5I0:25!*5—0~0:K4 0!K4~ —0:350:P4+—0:,50ʗ0:Q4#0:L4 0:,5=ʗ0!K4~ ʇ0!4s!7*~!6*Ԩ/4:4!K4ʺ0G~ 0#x=ë0> 0> 024!K4>x6 #=0G!K4~ p%,**}0>ͳ.0*j*+:+5ʨ/0!s*6S#6Y#6M#w!*w:>*2=*!"*%,ʨ/26**j*կ ,,0:?*1::*Z1ͬ2L1͎2**}1}w1>B/a1}|Gd/:?*ʓ1**+![2*CP/M RMAC ASSEM 1.1 NO SOURCE FILE PRESENT NO DIRECTORY SPACE SOURCE FILE NAME ERROR INVALID PARAMETER: SOURCE FILE READ ERROR OUTPUT FILE WRITE ERROR CANNOT CLOSE FILES UNBALANCED MACRO LIB END OF ASSEMBLY : 5O!5 ~#fo: 5O!5 s#r:?*yʟ2š2ͬ2Ž2G:9*29*!:*4>6:9*L/29*2%#333/3 3333#332E3 3   MXList WAITING FOR PRINTER $PRINTER READY $.WƐ'@'Õ*>:͕*!%^Ww*%{-|-}--{?.!%~#-6.-> ͕*> ͕*͞*> ͞*wsT =0,1,.... This command sets the rate at which keys will repeat. A parameter of 0 turns off repeat; otherwise, the lower the number, the faster the repeat.  VOL =0,1,2,3,4,5,6,7,...,15 This command sets the volume of the keyclicks as specified by the associated parameter. (0 turns the volume off; 15 sets the loudest keyclick; default is 6)  to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> ThçCOPYRIGHT (C) 1980 DIGITAL RESEARCH nLT`? OVL LINKING $ $ 1L9M9!96w:o9!9D:!""!""!"9*9^#V"9"q::u9 ͥ6**=;"`:"b:q:b:͞8.96`:q:͞8"9|!96wj1:9R,v!!]:ڤ*]:&f;) N#F͋41!]:4:u92:2:2;2E;2u;2;2;2;!D:6+6!E:6!"p9!"m9}2o9!z962v92x92w9!t96X!"y:"{:"}:":":":":":":":":":":":":":"i:"k:"m:"o:}2:!:6#6#6*9"q:2C:2D:2E:2R:!"X:o&"Z:|!"s:!"p;";";";":":";"7;*+":*+":*+" ;*+"9;!":":";"?;!":":";"A;:9*b::9=o&))9  ^#V!!<4*<&^<) <͞8-*<&^<) ^#V"d:M*<&^<) q#p!<4*9&))9  *`:s#r*A:)8"p9*9&))9 q#p:9<29O>D:9=29D:9ڗ*9&))9 ^#V"p9  ^#V"`:*`:DM!96#~ͬ . ":\ -:+: .+: -:9":5*.:~=ͬ :9('*.:~(*.:~)H^*.:~,NDͬ :9['(:9vC()!o96>5!B".:ͬ . ":\ -ˆ*.:~=Ÿͬ ï.+: -§:9ҹ'*.:~*.:~(H*.:~,Dͬ :9'ù:w92y9:9F:9(C(͆7:9):o9:o9H4!"p9>:o929*p9"95*.:~(*.:~ʐn*.:~)p̀^*.:~*.:~(HҍDO:9ʛD*Ͳ!6~̈́6*& 6:[],()?$! : @: <_2 <: !#<ڲ*#<& :<«>!#<4>*.:#".:*.:N2<&õ͵:< ͵!<6 !%<6+6:%< :%<  !<6͸ !\6͊ !!%<6͊> :%<5 !͸ ͵" :<:„ :\:%<Hb !:]A<2\O>v !*%<&\ 6 ô !%<6:<.° ͵͊ڰ :%< ڧ !͸ ͵Ô ! :%<<2% :<02<> : :>!"&<͵͊6 - *&<))))*<& "&<0 D͵ *&<:/͵: W :ZD͵:ڎ :!Q: D*Q:&J: : >!:*!^:6+":^:$t 8'> *0< ~L*0< DMB5*0< 6*0w#6!4w#6*0<##N#F*.< ~O`i~8p8!6Ͷ8ikS*0< DMv5*0< DMd5*0< *0<##N#Fq#pä*0<##q#p*u:#^#V*u: ^#V*u: ^#V*u:~*u:~*u:>*u:~*u: ^#V*w: ^#V!8:=<Hw!>:><Hw!?:?<Hw!@:@<Hw!B͔8>ͥG<ͮ8'*u:"w:*E<#"E<ͺ"u:>͔8$>ͥG<ͮ8!TJ<ͫ8:P<Hr:Q<ҁ!U<6 Æ!U<6:U<q:ͫ8+s#r!`:͹8ң96:T<Һ*JE<ͫ8*P<&i:) N#F,DM,*LE<ͫ8F*P<&i:) *q:s#rN*q:DMͷ!V<6>!V<ڷ!"Y<*V<&i:) ^#V"u:>u:ͫ8ʝͺ"W<*Y![<,*[<&i:) ^#V"u:*[<&<) N#F.>u:ͫ8%OkͥDMͪͮDMͪDMͪͺ"u:![<4!"i:"k:"m:"o:*d:##6*d: 6*d:^#V!`=p+q*d:*_=s#r*d: >!a=q*d: :a=w*d:##>?!b=q*d:##:b=w*d:##~*d:##>w*d:##~*d:##>w*d: ~!c=q*d: >:c=Hẅ́d:8++"\<*\<^#V!e=p+q̈́d:8++"\<*\<*d=s#r*d: ^#V!g=p+q*d: *f=s#r*d: ~!h=q*d: >:h=Hw!k=s+p+q!^=6:k==2k=ʱ*i=:^=2^=*i=#"i=Ñ:^=2^=!n=s+p+qͽ"d:`:d:͞8͹h!n=*l=*d: DM*n=>*>̈́d:8+s#r!r=s+q+p+q*o=DM*q=̈́*^=&^<) ^#V"d:>d:ͫ8ʆh!q=}*o=*d: DM*q=>*}U!r=}>M"d:<>!|=r+s+q+q+q+p+q+q+p+q:u=2}=:z=Һ!}=44*`:"d:*}=& "`:q:ͮ896<*s=DM*u=̈́*^=&^<) N#FU*^=&^<) *d:s#r*}=M͍*v=DM>*y=M*u=Ms*x=Mf*u=*d: *s=DM -B:z=Y*{=DM*d: ~#k!{96 MODULE TOP $UNDEFINED START SYMBOL: $YY???? $$$XX???? $$$RQST$ UNDEFINED SYMBOLS: $ABSOLUTE $CODE SIZE $DATA SIZE $COMMON SIZE $USE FACTOR $!=q*=MͲ!~=4!=q> !=8:=0OͲC:= AOͲ!=q:=O:=O!=p+q!=̈́8MD>=08MD:;!t;!;!;:u;2\. ] -Ÿ\ͩ6!t;6!;6!;6!;6!=6+6>!=*=&f;) ^#V"= *= ~ *= DMv5 *= 6!=6:=<2=:=7::2\. ] -)\ͩ6*p9###H:ͮ8!D:U!\:6*p9###F:ͮ8!C:r!\:6*p9###X:ͮ8҉!\:6:R:>S:ͫ8:U:H:C:/HҼ!\:6!\:6:E:!C:!\:6!\:6:C:*F:"::\:*p9###":*p9"::D:*H:":8*:*:"::r98*:)8":*:*:":Z:X:͞8_X:Z:͞8#"y:e!"y:!:6*X:":!=6>!=ڞ*=&y:) >Ͷ8Ҕͥ:=<2=v!":::2=!=6:=#w:==2= *=&:) *=&: N!: ͠8*=&: ~2=*=& :=w:=2=:=<2=õ*=&: :=w::<2:*b:"d:`:d:͞8q͜/!9H`2UO!: 8DM>ͪ̈́d:8+s#r&!]:6>!]:7*]:&f;) N#F͋4:*]:&<) N#F.B2=:="="=:=O>"=n2=ð-*]:&i:) ^#V"u:>u:ͫ8-2=ͥ"=ͮ"=!"=nͺ"u::]:<2]:w!=r+s+p+q*=}*=_DM͘4*=#*=|_͘4!=p+q*="d:2:=2=:=O>Ґ*=DM^"=ã*=&:) =8"=:=O>:=O>==͞8UO!: ͹8"=*=*="=*=DM*=8*d: ~*d: :!z9/H!"=ͽ"d:`:d:͞8HҴ>=08>͔8S6!~=6U`/wUp/>=08 \8 M`͹ҖÞ2DM_   *=#"=̈́d:8+s#r >!=Ͷ86!=6>#w#62~=ͽ"d:`:d:͞8N/=:=!=6>=08>͔8'6!~=6w*=#"=>&8)))M`̈́d:8+s#r>!=Ͷ8\66!=q!=:~=v d!=6h!=ڤ:==O! *d:N:=<2=|:E:J:*Q:M2"V:!"V:|!=6:Q:!=:==O!J: NͲ:=<2=6D:R:*U:&:) S:8"V:D>!{:Ͷ81*:"V:DX:ͣ8D*X:"V:Z:X:͞8mX:Z:͞8#DM*X:v6*:DM*:6*:DM*:6*:DM*:6`:s:͞89ͮ8*9|=ͫ8 Ͳ(Ͳ*=DM_-Ͳ*=*=+DM_)Ͳl*|9DM_68f ͥOr:t9Z^E.:n~:x9ZyU/?OVLAY?OVLA0RELIRLIRLREL))O`i~8p8>!:!>6::!>:>=O!: NͲ!>4½)2:͕":)2::: !:6!>6::!>. ):>=O!: Hq!>4 *h&\8*|& "9>*7:DM\͏5*9+"9!>q:>2]:*]:&f;) N#F͋4!>q:]:!f:Ҏ *]:&y:) N#F*>͘4:]: Z:y:͞8Ҽ *y:"Z:X:y:͞8 *y:"X:*]:&y:) N#F+q#p!>s+p+q::2>O!: :8">*>DM*>h!ͮ"!>2>:>>!>ͫ8HA!ͱ!">G!*!>">*>DM*>MC:>e!*]:M͋!*>*>*]:*>*>5:=Ҭ!ͱ!"!>>͔8ž!*!>">!>6í!!:]:2%>*>M^ *>DM4*>#DM4O`i~8p8"#>*%>M^ *#>*b:"d:`:d:͞8%"*d: ~#"*d: 6̈́d:8+s#r!!{96:*:MH"H"!^:6:*:Mi"2"g:͜2f:o"=6*:::: -y"::29:*::ͺ/Ҵ":*:͉:*:M"!:͹8"/Ͳͯ/Ͳ Ͳ=6#:*:*:*:*:͉*:*:"::*:M/I#:*:͉*d:DM :*:Mҟ#{#=ͯ6Ü#*:&:) :8DM>*:Mf#:*:*:&:) :8*:͉*]:&y:) N#F*]:*:DM5!=6#!=6*:":*:M^ :]:$$*g:*:":C$*]:&:) :8*]:&y:) q#p:]:P$!=6*]:&y:) N#F *:":>!:Ͷ8::HҲ$:R:Ҕ$=6ò$*:&:) :8"S:::2U:!R:6:0:$)$ò$!&>6>!&>%%*&>&:) *&>&:) 8*&>&:) q#p*&>&y:) q#p*&>&:) >w#6:&><2&>$s:q:͞87%*q:"s::G%͸*9"q:^ :_:/2^::{9]%!!)>s+p+q:)>ˆ%*g:*'>"'>:f:҅%!)>6Ý%*)>&:) '>8+s#r*]:&y:) N#F*]:%*'>DM*)>M͋%*]:&y:) N#F*'>*)>*]:5y y !*>q:*> &>!*>&:*>#&+"ÿ&:*>1&p"ÿ&:*>?&k$ÿ&:^:ҿ&:*>=O!& ^#VI"ÿ&ÿ&͈"ÿ&>ÿ&͵"ÿ&#ÿ&T#ÿ&#ÿ&#ÿ&$ÿ&$ÿ&Q$ÿ&d$ÿ&W&]&`&f&o&u&{&&&&&&&!+>6)&)2->:^:&*->My (')2,>')2+>:+> '*+>M%('͕".>:^:('*.>DM*,>^%:+>&7','!0:6&H'='!0:6!"1:"7::!:'*:͗8"1:"7:. 9\ -u')29!hʦ':92h\͕6¦'\=45)2|29!:6*7:"1:!"9"9^ :_:/2^::!:!_:' ',':e (.e -'e>*2!:\d5I'}/B(}͉ͽ"d:`:d:͞8)͹(:v92\!0>6>!0>گ(h!0>҈(*0>&\ 6 å(:0>=O! *d:*0>&\ w:0><20>g(!!:6.e -¼(\W5/(!!:6.e -(\d5*d:"1>!_:6I'*1>"d:̈́d:8+s#rI(.: -)!:6!:6^ ͽ"d:`:d:͞8)/)*{:DM>fy ^%y !":y y *d:"4>#*4>"d:!3>6>!3>)h!3>ڶ):3>=O! *d:Ny û) y :3><23>Œ)*:"::)͸*9"q:̈́d:8+s#r5)!0:4~ (*6*1:#"1:*7:{z*!"1:/ *1:!>~26>xG:6>26>G )x{_ P*#B*>ɯ`iq#zV*COMPRLRSPSPROVLSYM!;>q*5:> :;>w*5:#"5:!3:͹8ڦ*>*3:DM\͔5!"5:!<>q:8>!<>28>:7><27>*!7>6*8>Mq*!8>6!=>q*=>Mq**A:#"A:!?>p+q*>>}O**>>|O*::+:o9+h,*p9"A::\:,+**V:DM**X:":!@>6::=!@>q+*@>&: N!: p9͞8j+*@>&: N͍+!@>47+:o9:o9HҌ+ -!C>q:C>¢+*X:"D>ó+*C>&:) ^#V"D>D>A:͞8+96D>A:͞8+*+*C>&f;) N#F͋4*C>&y:) >Ͷ8,:C>,*X:DM',,',|9A:͞8&,*A:"|9!G>p+q*F>"H>*C>&y:) F>8+!H>͹8g,*H>DM4O**H>"H>3,::=O!: N!: !y: 8*p9͗8"A>**A>DM**:o9,***p9DM*,*m9DM****:r9,*:DM*,*!J>6>!J> -*!J>4,*p9"A::\:(-ͦ-ͦ-ͦ-!L>6::=!L>|-*L>&: ~2K>u-*K>&:) A:͠8e-ͦ-J-:r-.u--!L>4--*p9*A>A:ͮ8ҕ-ͦ-|-:7>ʥ-ͦ-Õ-!O>q*O>Mͧ**A:#"A:M>A:͞8-ͦ-ù-ͦ-*K>&i:) ^#V"u:>u:ͫ8.ͥ*K>&:) 8"M>͹-ͺ"u:-*K>&<) N#F.*0< ~R.*0< DMd5*0< *0<##N#Fq#p].*0<##q#p2P>:P>ʤ.*K>&:) 8"M>"9:P>O>Ҙ."9͹-2P>c.>5:08>͔8ʾ.q*å.>*5:DM\͔5\v5:w9Z.. \": -.:e /.*o9&\8_* DMe - /:w9#/:w92\\B5:9 A/. ~9\ -9/!"5:}28>27>*ͥ.:x9Z^/. \": -f/.en* -v/:x9ʌ/:x92\\B5!"5:}2R>ͽ"d:`:d:͞8(0͹/H02DMv0 q*!Q>6h!Q>/:Q>=O! *d:Nq*:Q><2Q>/:R><2R>0 q* q*0 q*̈́d:8+s#râ/ q* q*ͥ.!S>q> !S>O0:S>0Oq*Z0:S> AOq*!T>q:T>O60:T>O60!V>p+q*U>|O[0*U>}O[0*9>!=8"W>*W>!=8!Y>s:h0:Y>2h\͕60\>645*W>!=8!|s2*9͗8"9>. \~9 -0:9 1*9>"9>\d5͍0C\͏5!Z>s*9>!=8C "9*9*|9s#r͍0C*Z>&\8DM\͔5:j2j\v5:9ҁ1*|9)8"|9:y9ZŠ1a9ҟ10ñ1g9ұ10!_>q.*[> :_>w*[> ~!`>q*[> :`>w*[> *[> ^#VN#FR* *[> 6*[>^#V!=8"b>?8!a>s1!a>P2*[> DMv5*a>M1*[> DM͕6P2*[> DML5*b>!=8MͲ1*[>  *[> ͞8ҍ2*[>  *[> N#Fq#p *[> ~ڮ2*[> DMB5 *[> 61*[> N#F*[> *[> N#F͔51!e>p+q*[> N#F*d>?8^8*[>q#p*[>*[> 8+*[>##q#p*[>*[> N#F^#V?8*[> s#r *[> N#F`i"h>*[> N#F `i"j>*h>"f>j>f>͞8ڐ3*f>+*[> ^#V\8DM2_2*f>"f>\3*[> ^#V*j>\8DM2*[>  *[> ͞8Ҿ31*[> N#F*[> *[> N#F͏5!n>s+p+q*[>l>͠84 *[> ~4_2*l>DM2ͦ3Ê4*[>##l>͞8Ҋ4 *[> ~34_2*l>DM2:n>j4*[>  *[> N#FPY͹8d463g4ͦ3Ê4*[>  *[> ͞8҇41Ê4ͦ3!p>p+q*o>"[>!s>s+p+q*q>DM3*[> ^#V"]>*[> N#F*q>?8*]>:s>w *[> 6!u>p+q*t>DM3*[> ^#V"]>*[> N#F*t>?8*]>~   +5{>.+55OͲ5w66ͩ6́5;6<566́5͕6<>́5͕6<>645͜6<H66! w #ˆ5>Ö5>2,6""6"$6yo`"&6!"*6͋6-66*&6|6 "&6*"6MD6*$6DM:,65ͷ6g666Ͱ66**6|6U6*$645*"6""6**6#"*6ú56**6ABORTED$NO SPACE$NO FILE: $CANNOT CLOSE$DISK READ ERROR: $DISK WRITE ERROR$YYYP   YP6YPYPYPYPYPYP Ͳ ò!>6#6͐6">*>|$7>9ͫ8"|>##*|> ~!7!>6D7*>|?7!>66"|>D7!>6:>Y7!~>6#6#6Å7*|>~2~>*|> ~2>:>z7:>2>*|> ~2>!>6>!>ڰ7*>&v> ~/*>&: w!>4‹7:72"g:^ *:"|> *g:":*9My *9My *9My *~>My *>My *>My *|>":i`N#Fog_og_{ozg_ogDM!>))덑o|gV8 =D8DM!>))k8 =c8_{ozg^#V) ~8^#V|g}o ˆ8_{ozgi`N#Fogo&og_{_z#W LINK 1.31 $01/04/83?MEMRY$MEMRYX MEMORY OVERFLOW, USE [A] SWITCH$INSUFFICIENT MEMORY$OVERLAPPING SEGMENTS$ XXABS $$$XXPROG $$$XXDATA $$$XXCOMM $$$::;7;YYABS $$$YYPROG $$$YYDATA $$$YYCOMM $$$n;;;;INDEX ERROR$MULTIPLE DEFINITION: $MAIN MODULE ERROR$FIRST COMMON NOT LARGEST$COMMON ERROR$UNRECOGNIZED ITEM $wsT =0,1,.... This command sets the rate at which keys will repeat. A parameter of 0 turns off repeat; otherwise, the lower the number, the faster the repeat.  VOL =0,1,2,3,4,5,6,7,...,15 This command sets the volume of the keyclicks as specified by the associated parameter. (0 turns the volume off; 15 sets the loudest keyclick; default is 6)  to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> Th1ͽ0CPM+ SYS@ñ*,*.}|ڡ!".*,{zғ** v*.".H  DISK FULL: CPM$!".***.#".ɯ22)!@",!".  <  NO DIR SPACE: CPM$!CPM3 SYS^Ñ**}|z!"*{zl*f*"8*"!"**}>*#"ɯ22!""<  NO CPM3 FILE$~# !\ HEXnx**}|a!"*{zS*M*"*"!"**}>*#"ɯ22!""<²  NO BIOS8502 FILE$CXKYCODEHEXrL**}|5!"*{z'*!*"*"!"**}>*#"ɯ22!""<‚ s NO KEYS FILE$!!!Bb!c͹!!!*.}",>3¾ <  CANNOT CLOSE CPM$Loading 8502 BIOS .HEX file Loading Key definition .HEX file Adding new vectors to CPM+.SYS Adding Key def. to CPM+.SYS Adding CPM3.SYS to CPM+.SYS Adding BIOS8502 to CPM+.SYS Closing CPM+.SYS file 2 >}®|2 /g$ " *  }o|g}$|2 Ҵ>2 >}®|2 /g$" D;* ++}o|g}X$|2 Ҵ$3d$$$$$$: G: 3x3: 3: 3*}3|3$3¬!: =2 ¼$3: g. zW ~3# >: 7* " _: =2 3_* w#" _: ɯ2 ͟ʍ:>_<2 _g_owwGG: 2 x͓G0  !L ÷͟ʍa_: ʪ !P ÷! !~#_ This program will create a CPM+.SYS file from The CPM3.SYS file (created by GENCPM) and The 6502 BIOS File supplied in Intel HEX format And CXKYCODE File supplied in Intel HEX format (1st HEX address is FUNCTION table address) (1st two bytes point to ASCII table) The ROM boot code will load the CPM+.SYS file HEX file error - first record must be start adr and last record must contain the last adr All other address must be between the start and end adr also HEX file must be ended with a NULL record and Start address must be on a page boundary and File can NOT be larger than 4K  Ơ0 , ܮ0x 0)Ъ 0 0)` 0 !`Iݩ, ` ܭ ݩhhhh@0U0Le USER command sets the current user number. The disk directory can be divided into distinct groups according to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> Th1TdCP/M Version 3.0COPYRIGHT 1982, DIGITAL RESEARCH151282nLT`0123456789ABCDEF ERROR: $Reading file: $Writing file: $Directory full$Reading file: $Writing file: $Invalid drive.$) ? $) ? $) ? $Bad character, re-enter $ $ Disk read error: $File cannot fit into GENCPM buffer: $Unable to open: $BDOS3 BIOS3 Setting up directory hash tables: $ Enable hashing for drive $: $Unable to allocate space for hash table.$ Setting up Allocation vector for drive $ Setting up Checksum vector for drive $ *** Bank 1 and Common are not included *** *** in the memory segment table. *** $Number of memory segments $ CP/M 3 Base,size,bank ($) $ Enter memory segment table: $ Base,size,bank $Zero length segment not allowed.$Bank one not allowed.$ ERROR: Memory conflict - segment trimmed. $Memory conflict - cannot trim segment.$ ERROR: Memory conflict - segment trimmed. $ ERROR: Memory conflict - segment trimmed. $ CP/M 3 Sys $ Memseg No. $ Bank $ Accept new memory segment table entries $Default entries are shown in (parens). Default base is Hex, precede entry with # for decimal $ Use GENCPM.DAT for defaults $Create a new GENCPM.DAT file $Display Load Map at Cold Boot $Number of console columns $Number of lines in console page $Backspace echoes erased character $Rubout echoes erased character $Initial default drive ($:) ? $Top page of memory $Bank switched memory $Common memory base page $Long error messages $Double allocation vectors $Accept new system definition $ CP/M 3.0 System Generation Copyright (C) 1982, Digital Research $ BNKBIOS3 SPR$BIOS3 SPR$BNKBIOS3 SPR$BDOS3 SPR$RESBDOS3 SPR$BNKBDOS3 SPR$ 64K TPA Copyright (C) 1982, Digital Research *** CP/M 3.0 SYSTEM GENERATION DONE ***$!Tq:UM*T&!Tp+q:Ud*T !Tp+q*T#6:UҀ:Tڀ*T *T#N! *T6 7 7!Tr+s+q+q!U6N*TDMN:TTN͜:T.:T/!U!]6 !m6 !Tp+q *T 6 *T 6*T!Tp+q*T!Tp+q*T!Tp+q*T] ͧ!Tp+q*T} ͧ!Tp+q*T ͧ *T 6!Tp+q*T!Tp+q*T! ͧ!Tp+q*T" ͧ!Up+q*T$!Vr+s+p+q+q:V *V*VDM*V -- !Vs+p+q:VJ *V*VM!VLS!Vq:V e > :Va/>z!V/H҄ :V_2V:V!Vq:V/>!V/HҦ >ͧ>!Vp+q(7*V~ Y7 N7NTe:T *TMV Y*Vw!Vq:VO! N7:VO! N7!Vp+q 7*V|O *V}O H7!Vq*V&+SDM$ !Vp+q!V6!V60!'"V>V͇S† *VM7 !V6>!V VVzSڽ !V6:V<2VVVzS+s#rÔ :V *VM7!V60*V! S"V:V<2V‹ !Vs+q(7:V  #7*V&DMZ  *VM N!Vs+p+q+p+q :T: ͜*V6:V<2VO!T NV 2V  :V,u *V#"V*V6!V6 :V#… !V6  :V02V:V> !VHҽ >!VҸ :V2Vý !V6!V:V *V^*V&+S*V& *Vq !V6*V6ͧ *V6? ͜*VDMN*V~  (7*VN !V6>!Vn *V#"V:V:-Q/HX *V6d ,7*VN :V<2V, *V++"VNÊ *VN*V !V6!V6Te!Vr+s+q:-Q/Ү >!V6#q#p!V6:5Q!Vڳ*V&+SFQ  VzSک:VM*V&+SFQ  ~*V&+SFQ  VzSHJ:V2V*V&+SFQ  ^#V"Vé*V&+SFQ  ~*V&+SFQ  VzSHҩ:V2V*V&+SFQ  ^#V"V:V<2V¿ :V:VH`!V6:5Q!V`*V&+SFQ  VzS/*V&+SFQ  ~H*V&+SFQ  VzSHV:V2V*V&+SFQ  ^#V"V:V<2V:V!$V6!U6ͬ#Q$!H> U͇Sʔ* U|2Uß*U|2U!U:.Q2T*U|!UO:/Q2T*U|O:T2TUTI:-Q/!$V>O:T2T* U|O:T!$V2T:T=2T* U|O:T2TҮ:-Qқ*nV*U*V |!UO:/Q2T*U|O:T2T2Uͬ:U/Ҙ!!V6>!!Vژ*!V&$SQ  6:!V<2!Vsà!U6:V/ҫ*:U2T:T2TTͩ:-Q*T&+SDM*U*T&+SDM*U:-Q/&:U2!V!""V*!VM"V͟:!V2U! U6Û*U|!U2!V* U|!Uo&)##""V*T&+SDM*!V*!VM"V͟:!V2 U:U2!V!""V>T͇S+s#r*!VM"V͟:!V2U* U|!$V2T:T2T U(T(TͩC*$V&+ST͊S+s#r* U|!$V2!V:-Q/ *T&+SDM*!V"*T&+SDM*!V*!VM"V͟:!V!Uw:-QҢ!T6:T2TULTLTͩ*U|2!V*U|!Uo&)*"V""V*T&+SDM*!V*!VM"V͟:!V! Uw:,Q/Ҳ:V2V *V&U  :T2T*T&! S!0*V& U q*T&! S0*V&!U q:V 2V*T&+S"!U$-U RUW !T6#6#6:.Q2U:/Q2UTqT TyT Uͧ pT !T6Uͧ pT pT :;Rһ!;R6:%V2.Q:4Q/24QTT TT L!U6N!Vr+s+p+q*V6 *V#6 *V|O! *V## w*V|O! *V w*V}O! *V w*V}O! *V w!T:TO`iPSW "V*V :0Qw*V :2Qw*V :1Qw.*V :3Qw*V :4QwX*V   :+Q/ҼW*V >*V w:@*V wW*V >*V w^*V :/Qw!)X"V*VN#F!W "V*V"V*V͕S(!$V6-!$V6*VSD*VWR!"&V!V6&VS!V6>!Vڷ*V&)*&V>͒Sʭ*V&)*&VWR"(V*(V ͕Sʭ!V6:V<2Vf:-Q/!V!$V6!$V6V>X W*V"V*V~>>!Vs+p+q+p+q%N*VDMN 7*VDM$  7*VME :,QҨ *V&U *VDM :V 2V*V&U DM*V:V2V*V&U *V&+S:V2V*V&U ) :V2V!Vp+q*V"TͣN,ͧ*VDM !Vr+s+p+q*V^#V"T*V##^#V"T*V ^#V"T*V#DMT  *VDMT *TZSU͊S@?ͧ*T+ZS}<2V!V6!V:V҆*V&+SW "TDMͧ *VDM> :V<2VS*TDMO W*T"T!Vr+s+q:VGTqT TyT *Vn}2T*V#~2TpT WTS}pS}TR+s#r*V&)+!Vs+6:V!V4>T͇S+s#rBKͧ pT^ :V<2VpT *VT :-Q/k)Tw T z!LT"V!U"V͙!T"V!U"V͙!(T"V! U"V͙*V#DMT  *VDMT *VDMeͧWͧ *VDM> *V*Ws#r*V##*Ws#r*V *Ws#r*VDM> !V6&VS(>!V6>!V*V&)*&V>͒S*V&)*&VWR"(V *(V## *(V ͕S*(V ͕SH*(V ͕SH*(V ͕SH*(V ͕SH!V6:V<2V-:V!V6!V6!V6>!V*V&)*&VWR"(V*V&)*&V>͒S*(V S?!V6*(V ͕S:V/c!V6N:VO!=R ~2T *(V WR"*V**V N#F`i))"VN:VAO7N*V&6Q DMʹ ͜*V&6Q ~/*(V q#p:-Q/!V6*V&,V) *Vs#r*V*LV"LV*V͛ 2V'ͧ*V&+SFQ  *(V w*V&+SFQ N`iPS*V&+SFQ  N`iPS*V&+SFQ  ͕S *(V q#p*V&+SFQ  VzS*V&+SFQ  q#p:V<2V:-Q/!V!$V6:T<<2T:T<<2T!V6>!V8*V&NV) >w#6*V&pV) >w#6:V<2V:!Vڡ*V&)*&V>͒Sʗ*V&)*&VWR"(V *(V WR"*V*(V ͕SN:VAO7:7!V6**V ^#V!S*V&+S*V&NV) q#p*V&NV) nVR+s#r*(V ͕S—'N:VAO7:7!V6**V >R!S*V&pV) s#r*V&) VR+s#r **V R*V&pV) CS **V q#p:V<2Vk:Vҫ͜:T2FQ!T:/Q2GQ!"IQ!HQ6!V6ON:GR2T 5Q N*FQM ,7*GQM ,7*HQM N:V/҈!N!V6:5Q!V !V6:V/ :V =O!=R ~2T*V&+SFQ DM *V&+SFQ  N`iPS*V&+SFQ  q#p*V&+SFQ  ~ͧ *V&+SFQ  ~7ͧ *V&+SFQ ~2V*V&*V&+SFQ  N "V*V|*V}O:/QH҆MN!V:/Q*V&+SFQ  Hq!V:/QO`iPS*V&+SFQ  q#p *V}2V!V6!V6!V:V# *V&+SFQ ~2V*V&+SFQ  :V2V*V&+SFQ  *V&+SFQ  !V:V/+~!V/H+ |ͧ!V6 :V!V+~!VHc N*V&+SFQ :Vw!V6 :V!V+~!VH N!V:V*V&+SFQ  Hq!V:VO`iPS*V&+SFQ  q#p!V6:V<2V×1:V<2V"͜!V6:5Q!Vo!:V!N!N:V=O *V&+SFQ NE *V&+SFQ  NE :-Qb!N*V&+SFQ  N ͜:V<2V !T6!V6%NVʹ ͜PNT2V!TT TT N!V6Vʹ ͜:V!FT !!U6+6!W6͌!:W/җ#:R2T͜N;Rʹ :=R2T͜͜N,Qʹ ͜͜:>R2T:2Q<22Q  2Q :2Q=22Q:?R2T:1Q<21Q' 1Q :1Q=21Q:@R2THN3Qʹ ͜:AR2TkN4Qʹ ͜͜:BR2TN:0QAO7NTe:T"*TMV A2W*WM͈ /"Þ":W20Q͜͜:CR2T.Q *.Q&PS"U:DR2TN-Qʹ ͜:-Q/2T:-Q[#:ER2T/Q ͜:FR2TN+Qʹ ͜x#:R2T͜N!W#*W&U 6:W<2W#!W6>!W $*W&U 6$:W<2W#!V6*V&U  !V6TqT TyT Wͧ pT^ pT^ WS#ZS"U!W6>!Wڋ$*W&,V) >w#6:W<2Wh$!"LV:]A$!U6#6!W6>!W$*W&=R 6:W<2W¦$$!U6#6:mD$!U6!T6 Available space in 256 byte pages: $TPA =$, Bank 0 =$, Other banks =$Unable to allocate Dir deblocking buffer space.$Unable to allocate Data deblocking buffer space.$Unable to allocate Data deblocking buffer space.$Drive specified has not been defined. $0FFFFH is an invalid value in the DPH directory BCB address field.$ Setting up Blocking/Deblocking buffers: $ The physical record size is$: $ *** Directory buffer required *** *** and allocated for drive $: *** $ Overlay Directory buffer for drive $: $ Number of directory buffers for drive $: $Minumum number of buffers is 1. $ Number of directory buffers for drive $: $ *** Maximum number of directory buffers *** *** for the current drive is$. *** *** Number of directory buffers reduced *** *** accordingly. *** $ Share buffer(s) with which drive ($:) ? $ *** Data buffer required and *** *** allocated for drive $: *** $ Overlay Data buffer for drive $: $ Number of data buffers for drive $: $Minumum number of buffers is 1. $ Number of data buffers for drive $: $ Share buffer(s) with which drive ($:) ? $ Allocate buffers outside of Common $ Accept new buffer definitions $!W6>!W**W&)*&V>͒S**W&)*&VWR"(V ͕S*(V ͕SHҸ* *(V WR"*V**V ^6 *W&$SQ q#p*W&$SQ  6*(V ͕S*%ͧ!W4*!W6>!W+!"HW}2W>!W=+*W&$SQ HW|S ~H6+*W&$SQ ^#V"HW!W4**W&))lW *HWs#r*W&))  >w#6!W6>!W+*W&$SQ HW|S>͇SH+*W&))lW  *W6 DS+s#r*W&$SQ  6!W4h+!W4*!W6>!W7,*W&+SFQ  *W&W) N#Fq#p*W&+SFQ  *W&7W w!W4+:-QF,!fW6K,!fW6 !W6:W4:fW=2iW!"gW"dW}2 W! W6*T&PS*LViS"bW:-Qڞ,nVbWzS*ViS"bW!W6>!W,*W&W) *W&+SKQ  N#Fq#p*W&$SQ  6!W4£,!W6! W6#6!W6n&))lW  ^#V"JW*W&))lW >͒S:WH3:WE-1&N!W6]&N*W&))lW N#F$ {&N!W6>JWR>fS:WHҚ-!JWVS+s#r!W4g-!JWVS+s#r:W3*W&)*&VWR"(V WR"*V >RZS"^W **V ͕S-!W6-!W6*(V ͕Sc0bB*W&$SQ  >w:-Q.: Wd.! W6*W&$SQ  6&N:WAO7&N.:W{O!=R ~2T&N:WAO7'N*W&$SQ  DMʹ ͜*W&$SQ  ~.*W&$SQ  6.*W&$SQ  6t/:W;O!=R ~2T'N:WAO7>'*W&$SQ  DM  : Wt/! W6*W&$SQ  ~t/A'ͧb'N:WAO7'*W&$SQ  DM  &/*W&$SQ  ~^W͇Sҹ/'N*^WDM$ 'N*W&$SQ  *^Ws*W&$SQ  ~R0:W[O!=R ~2TM(N*W&$SQ  ~AO7(NTe:TL0*TMV A2 W* WM͈ *0/* WMF80/*W&$SQ  : Ww͜c0*WMTCc0 4*(V ͕Sn3!W6*W&$SQ >͒S°0*(V q#p*W&$SQ  6n3bB*W&$SQ  >w:-Qګ1: W1:W1! W6!W6*W&$SQ  6(N:WAO7(N1: W1!W6! W6:Wʨ1:WƋO!=R ~2T(N:WAO7)N*W&$SQ  DMʹ ͜*W&$SQ  ~ґ1*W&$SQ  6è1*W&$SQ  6! W6S2:WKO!=R ~2T)N:WAO76)*W&$SQ  DM  *W&$SQ  >w: WS2! W6*W&$SQ  ~S29)ͧZ)N:WAO7)*W&$SQ  DM  2*W&$SQ  ~$3: WҌ2! W6*W&$SQ  :Ww 3:WkO!=R ~2T)N*W&$SQ  ~AO7)NTe:T 3*TMV A2 W* WM͈ 2Ü2* WMF2Ü2*W&$SQ  : Ww͜*W&$SQ  :Wwn3:U!W]3:W+O!=R ~2T)N*W&$SQ  DMʹ ͜*WMTCn3 4! W6*W6 dWDS+s#r!W4>JWR>fS:WHҿ3!JWVS+s#r!W4Ì3!JWVS+s#rç-!W4n&))lW  ^#V"JW-!T6!W6:W 4bB)NWʹ ͜P,!"PW}2Wo&"TW2W>!Wu5*W&$SQ  ~n5*W&$SQ  ~ >Hһ4:-Q|4!W4á4*W&$SQ !^N#F-S*TW"TW*W&$SQ  ^*PW"PW*W&$SQ  ~ >Hn5:-Q/5!W4*W&$SQ  ~,5*W&$SQ !^N#F-S*TW"TWT5*W&$SQ !^N#F-S*TW"TW*W&$SQ  ^*PW"PW!W4#4*fW&*PW+S*W&) "RW:-Q9W*U"jW*RW*U*TW *LV *V *nV |O:.QO:T2UO:T2T:T2T:T2T|2U!T2.QW"T*T&PS*U "ZW*RW "VW*T"`W*`WW !T͕SC6*`WW 6*`W#"`W6!W6n&))lW  ^#V"JW*W&))lW >͒S:WH9!W6>JWR>fS:WHҶ6!JWVS+s#r!W4Ã6!JWVS+s#r:W8*W&)*&VWR"(V*W&$SQ  >«7*W&$SQ  ~h7*jW6 *jW *VWs#r*W&$SQ VWR+s#r*(V *ZWs#r:fWZWR+s#r:fWjWR+s#rë7*(V"LW*W&$SQ  n&)*&VWR"(V ^#V"NW*LW"(V *NWs#r*W&$SQ  >£8*W&$SQ  ~48*jW6 *jW *VWs#r*W&$SQ VWR+s#r*(V *ZWs#r:fWZWR+s#r:fWjWR+s#rã8*(V"LW*W&$SQ  >o&)*&VWR"(V!Q  >ʂ8*(V ^#V"NWÐ8*(V ^#V"NW*LW"(V *NWs#r!W4>JWR>fS:WH8!JWVS+s#r!W4ç8!JWVS+s#r6!W4n&))lW  ^#V"JW\6!W6>!Wc9*W&,V) >͒S\9*W&)*&VWR"(V *VWs#r*W&,V) VWR+s#r!W4 9!W6>!W9*W&)*&VWR"(V*W&NV) >͒Sʽ9*(V *VWs#r*W&NV) VWR+s#r*W&pV) >͒S9*(V *VWs#r*W&pV) VWR+s#r!W4h9aB!W6>!W::*W&W) *W&+SFQ  N#Fq#p!W4:*V*RW*nV "RW> U͇SUzSH҇:*TW*U|O:.QO:T2Uá:*TW* U|O:.QO:T2U!U:T2T:T2T:T2T:.Q2.Q* U}pS} URU͊S"`W> U͇SUzSHB;*RW|O:/Q2T*U}pS}URW"\W*T&PS"XW*T&PS*U "VWÇ;*RW*`W|O:/Q2TW*U"\WO`iPS*`W "XW*T&PS* U "VW*RW*\W"T*U|O:T2T*W&)*\W"jW*XW"ZWWTS"U*T"`W*`WW !T͕S;*`WW 6*`W#"`W;!W6!W6!W6:5Q!WS<*W&+SFQ  2W!FQ  ~:W!WHL<:W2W:W2W!W4;:T2FQ!T:/Q2GQ:W<*W&+SFQ  O:T<*W&+SFQ  N`iPS!͕S"`W!FQ :T w*W&+SFQ  N`iPS*`WiS!q#p!W6n&))lW  ^#V"JW*W&))lW >͒S:WHғA!W6>JWR>fS:WHh=!JWVS+s#r!W45=!JWVS+s#r:WxA*W&)*&VWR"(V*W&$SQ  >0?*W&$SQ  ~>*(V"LW*W&$SQ  n&)*&VWR"(V ^#V"NW*LW"(V *NWs#r0?*\W*ZWs#r*(V *XWs#r*XW##"XW*\W##"\W!W6*W&$SQ  ~!W ?*W&$SQ ^#V͛ 2W*jW6*W&+SFQ N`iPS!N`iPS!͕S  *jW q#p *jW 6*W&+SFQ  *W&$SQ |S+s#r:fWZWR+s#r *jW s#r:fWjWR+s#r!W46>:fWjW͇S+s#r! >w#6:fWjWR+s#r*W&$SQ  >1A*W&$SQ  ~¤?*(V"LW*W&$SQ  n&)*&VWR"(V ^#V"NW*LW"(V *NWs#r1A*\W*ZWs#r*(V *XWs#r*XW##"XW*\W##"\W!W6*W&$SQ  ~!W A*W&$SQ  ~ҩ@*W&$SQ ^#V͛ 2W*jW6*W&+SFQ N`iPS!N`iPS!͕S  *jW q#p*W&+SFQ   *jW w*W&+SFQ  *W&$SQ |S+s#r@*jW6 *jW *VWs#r*W&$SQ VWR+s#r *jW 6:fWZWR+s#r *jW s#r:fWjWR+s#r!W4?:fWjW͇S+s#r! >w#6:fWjWR+s#r!W4>JWR>fS:WHhA!JWVS+s#r!W45A!JWVS+s#ru=!W4n&))lW  ^#V"JW=!W6>!WA*W&7W *W&+SFQ  w!W4˜A!W6>!WaB*W&)*&VWR"(V*W&NV) >͒S"B*(V *ZWs#r*W&NV) ZWR+s#r*W&pV) >͒SZB*(V *ZWs#r*W&pV) ZWR+s#r!W4A!"W"W!W6:5Q!WB*W&+SFQ  ~¶B*W&+SFQ  VS*W"WB*W&+SFQ  VS*W"W!W4pB$N%N!bWVSDM$ :-QMC%N*WDM$ :U C$%N*WDM$ >W͇S>W͇SHHC!W6MC!W6͜͜!Ws+q*W&$SQ ^#V"W:-QڋC:fWWRbW͊S+s#rF!iW55:W®D*W&$SQ  ~2W!W6:W!WګD!fW:iWYD!iW6*gW#"gW!W6!W6!W6:5Q!W7D*W&+SFQ  2W!FQ  ~:W!WH0D:W2W:W2W!W4C*W&+SFQ  S+s#rcD!fW:iW2iW*W͛ 2W…D4%ͧ>äD*W&+SFQ  WzS+s#r!W4±CF*W&$SQ  ~2W!W6:W!WF!fW:iWoE!iW6*gW#"gW!W6!W6!W6:5Q!WME*W&+SFQ  2W!FQ  ~:W!WHFE:W2W:W2W!W4D*W&+SFQ  S+s#ryE!fW:iW2iW*W&$SQ  ~ڼEWbWzS+s#rYS:/QpSҹEd%ͧ>E*W͛ 2WE%ͧ>E*W&+SFQ  WzS+s#r!W4D>!Wq*W6 dWR>fS'F>%ͧ>ERROR: $ at line $Missing parameter variable$Equals (=) delimiter missing$Invalid drive ignored$Invalid character$Invalid parameter variable$!"WWͧ !W6!W6:W GG:WG͈K2W:WFIGF GF!Wr+s+q:U2W!U65FN*WDMN>FN*WDMZ :WCG.͜:W2U:WoG!W6TlG!W6sG!W4MG*W&W ~2W:W :W H:W HG:W ·G*W#"WMG*W&W ~2WÄG:Wa/>z!W/HG:W_2W:WG!W6:W!W6:W/:W/HI!W6>!W/H*W&W 6 !W4HtG2W!W6:W:W=H:W H:W/H~H*W&W :WwtG2W!W4:H:W=:W H:W/HҧHtG2W~H:W I:W=>!WHH!W6 I:W=HHF GH:WHcF G:W :W/H ItG2WHGtG2W!W6!T:W:W H:W/H[I*W&T :Ww!W4~`i+wtG2WI:W :W/HxItG2W[I!W6#6>!W҇K *W&+S P  ^#V"W! P  ~2WJ:WI:WA2WI:W0/>9!W/HI:W02WI:WA 2W *W&+S P  ^*W&+S*W"W*W&T ~?[J *W&+S P  :WO!=R 6!U6!W4!T5>!T҇K:WʧJ*W&T ~A/>P/HҜJ*W&T ~A*WwäJF GÇK:WJ*W&T ~Y*WwÇK!W6*W6!W6:T=!WڇK:W!WO!T ~2W, K*W#"W6!W6ÀK:W#K!W6 ÀK:W02W:W> !WHQK>!WLK:W2WQK!W6!W:WxK*W^*W&+S*W& sÀKF G!W4J!W6!W6:W:W/HK!W6:W *W&+S P *W& *W&W HK!W4éK:WK!W6K!W4ÒK:WL>:WWͧ T. T~ !W6!W6>!WN!W6#n& +S P  ~2W!W6:W:W/H N!W6>!WڞL'N *W&+S P *W& *W&W w!W4gL:W°L!W6L:WL:WA*W&W wL:W L:W0*W&W wL:WA *W&W w'N*W&W 6 'N*W&W 6='N*W&W 6  *W&+S P  !^*W&+SR"W:WmM'N*W~A*W&W wM:WʞM'N*W~ҐM*W&W 6YÛM*W&W 6NM*WNbN:WM'N*W&W 6,*W#"W*WNbN'N*W&W 6,*W#"W*WNbN'N*W&W 6 'N*W&W 6 !W4PL!W4'L>!W NT^ T :W]NT^ !W6>!WUN*W&W 6!W4:N!W6aN!W4!Wq'N:WO! *W&W w'N:WO! *W&W wO*TDM}oN*T†O]!O> 2 PW:TgxʀO { O: PO*T!O†O~#o}o|O<O:TzO<.O:TƜzO<8O:TzO:TzO:TotOzO:TgN!|!|PRTMSG ,QPAGWID 2QPAGLEN 1QBACKSPC 3QRUBOUT 4QBOOTDRV 0QMEMTOP .QBNKSWT -QCOMBAS /QLERROR  +QNUMSEGS  5QMEMSEG00 KQHASHDRVA6QALTBNKSA +QNDIRRECA ;QNDTARECA KQODIRDRVA [QODTADRVA kQOVLYDIRA {QOVLYDTAA QCRDATAF ;RDBLALV ))덑o|gS =S^#V))) DM!>)):S =2S_og^#V) PS^#V|g}o ZS_{ozgO{ozgi`N#Fogo&og_{_z#WBNKBIOS3SPRRESBDOS3SPRBNKBDOS3SPRCPM3 SYSGENCPM DAT . $ÀCP/M Version 3.0COPYRIGHT 1982, DIGITAL RESEARCH251082654321!9"k1G \!m!w# š!v6H#6E#6X!e6C#6O#6M<<&:g.".g"?S:2n!`w #4o"c*e{ozg"hj:]@*c"\y!5C*^N{zb+"^*^*`*h"!j4&"h"y:b<5*kG!gwxS0  *cN,*cN{zҽ{,*c*e{ozg ~*c#"c> :[ >  X N*c>:> !:q#G*eDM*h ERROR: $DISK READ$LOAD ADDRESS LESS THAN 100$DISK WRITE$LOAD ADDRESS $ERROR ADDRESS $INVALID HEX DIGIT$CHECKSUM ERROR $FIRST ADDRESS $LAST ADDRESS $BYTES READ $RECORDS WRITTEN $CANNOT OPEN SOURCE FILE$DIRECTORY FULL$CANNOT CLOSE FILE$HEXCOM VERS: 3.00 $ Ơ0 , ܮ0x 0)Ъ 0 0)` 0 !`Iݩ, ` ܭ ݩhhhh@0U0Le USER command sets the current user number. The disk directory can be divided into distinct groups according to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> ThÞCOPYRIGHT (C) 1980 DIGITAL RESEARCH nLT`RELIRLFATAL ERROR$l$l1 ͺ!"!6͓*~=:!ͣ !6:/::!ͣ !6:!!/ͣ < ͧv! s+p+q> ͍"̀ځ*>! q** DM* 1q>> ͍+s#r=>!r+s+q+q+p+q> ͍"!6> !*&*6!4¦:! *w* * * DM -* *s#r*"̀*":*. Tu -". u -2:~ l:\.~ -Ql.~ -dup. du -zT!"u*M: *M: !6>}!: :<2¨#u{u>!͘,T>͍)*DMTT"*%DMu{̀+s#r;'*DMu{̀N*"'ͅ>v":2T2u:ҙu͟!6>!ڙ: :<2:ҦT͟:!/Ҵ:͍ >>l͍ >!͘:/H*!*"'*DMT{T:lͪ : >>l?: &#*DMu{:2:2u͉Tp*>@O>*>@*w*~!s+q*&%*& *&%*2& "*DMT*+"*DM3T"!p+q!\#s>!s:+&:2̀&ͣ :22ͧ!s+q+q*M*͍"̀̀Hm*DM̀%*& "!6|*#:w*##:w* :w!6!6\2!:!H÷:!!6l+6**͍!6\* ^#V""!3"$"!o2ͣ :< J.< -B3!6#6!6*#s#r!6\wl!6!6!6\ʒÇ.  -›!&6:!&:&=O! N,:&<2&©**pH*#N*##* ^N0Jͭ1 Gͤͣ  <_1D**M*0G!'q:w**M0*"!6}!6:'҄Çͭ1Ҙ**͇H* >͘ҿ:'/**M*0} <_1K!6#6#6:  . - 12(:( T}L :2:2!:y :2̀y ͣ :22!""*"!6!6: *")*"*K: *: !6#6l: *)"ï !6l+6!6͔ :  G. - !"!\"!"*^#V" $!^q> !^] :^0O,h :^ AO,!_q:_OD :_OD !ap+q>`Mi !`\Mi !cp+q*bDMG!ep+q!d\+J<!hr+s+q*f&4 N,*gDM͵ DM̈́  ,*3&+) >>l!C9 < ,*3&+) ^#V*3M  ,!iq*# :iw*#"!͛o #*DMu{!"*!*"D*!s*D!s*D!s!6*!*"D*!s*D!s*D!s!6*M: *M: *M: O`iN928 "92;!j6:;!jU :j=O!< Hq!j40 *8M*9 !k6:;!kڇ :k=O!< N,!k4g  ,!lq*' :lw*#"!͛ '*DMT{*!*"!"!ns+q: ͪ :n!O> !>O:n2nO!mT!w& 8 !w:o2% & *M͍ !6!6:n!2oK :m!o>O!mC!pq*pM !rp+q*q}OY *q|OY *8M *9DMg *;M !s6:;!sھ :s=O!< NY !s4ž !t6:;!t :t=O!< N: !t4 : 2u: :* *uMi  ,*3&+) N#F+q#p!C6:? *uMY !vq "w:R:ҕ *vM*w *3&+) N#F+q#p*3&+) >>l2C:Ҵ *vM *wDMg !yq:y/:yH >!y# :y::::y8*;< -*:;2:@:<!C6*y&>) N#FG>!ykb :y/:yH҅V :y ¦:823*3&+) *9s#r:y!"+"-"/"1!36<::y<@ Gb :!:y<b :I:y/ *yM :y#~ >!y/͐ :yI:I 7:[:y[Ϳ o >á2zO>Ҏ*zM@:zá2z*zM͵:z,=>)-,),>,=*#"!|p+q*{~**{ >*{#"{>ʹ*~>~,H !6)!\""!o)ͣ !6!6ʹͼi**& w:<2cͣ ʹ7*~-w!6*~)…!6:ғͣ !6*"*~)*:º!6***̈́:*:!6!6lͼͣ Þ!6*~>ʤ*#"}!6*:3ͣ *~=X!6*#"}:X!"}**Ҁ* *}s#r*>wÑ**}̈́ͼҡͣ ʹ*~]*~D!6*~I!6*~M!6*~P!6ͣ ʹè!q!6!6*"ʹ!""!o8ͣ >͍J!"ͼҍ*~(c͆Ç*~_[],()!q: > :a/>z!/H:_2:!p+q*^#V"*##^#V"!6 !6+6:W: Q!6l<*6+: m+_Ax!!6Aڙ:ڐ!l+}::*~:Hھ!*#~A<*wO>!*&*6 '!6:.+A: !l+: !*&*\:<2O* N2!6> !i*& :b>!4F>:<2O* :w:!4~ʶ 6*#"*{zڶ!"ͧ*!~2xG:2G:p ˆx!4~ 6*#"*{z!"*!~2xG:2G x{_ C#5>ɯ$!p+q!6> !ڌ*&*~ x*&*N,:….,!4Q!r+s+p+q*DMG*DMFEͣ !s+p+q+p+q+p+qWͣ !">͍+s#r!oM*DM`:$*DM͐O>!>͍ ͣ !9*DM͠O>9ͣ *"*#"`!r+s+p+q+p+q***DMͮ*!r+s+p+q+p+q***DMͮ!p+q*DMp!6 > !*&*6!4²*DMͰͣ !p+q * 6 * 6*DM̀*͍!p+q*DM+ͣ !q*& , ,!p+q*  !p+q*!p+q*!p+q*! p+q*! p+q* ! p+q* !p+q`*!p+q*_{ozg_ogDM!>))덑o|g = DM!>))4 =,_{ozg~ D^#V) N~ U^#V|g}o `_{ozgO{ozgi`N#Fogo&og_{_z#WLIB 1.1 $REL $$$IRL $$$INDEX ERROR$NO MODULE: $SYNTAX ERROR$APDCentry symbol $select common block $program name $request $error 4 $define common size $chain external $define entry point $error 8 $external + offset $define data size $set program counter $chain address $define program size $end program $end file$FTiw(5ABORTED$DISK READ ERROR$DISK WRITE ERROR$CANNOT CLOSE$DIRECTORY FULL$NO FILE: $i!v"/!Q/+>c!K-6*/K>XG!+>yC!Q/+>c!+Q/>r–!}o|g}ʖ!#"/!/–!/ʖ!/+>c!/ͷ~g"B,U"G-!,,> c!o0ͷX:F-!,,> c!q0ͷ~*G-w#w:F-X!s0͡!F-6*G-*G-^#V#)))"I-*B,*G-^#V))W+"B,*B,>og"@,:F-f!,,> c!y0ͷ~!{0!+Q/>r2K-*I-w#w2P/>2O/2N/!/(,>t!"N-:F-X!D,LG!),>y :#!#6!Q/D,>_:O/!N/:N/2O/2N/!P/4!}0!0*L-#"L-!0A !/*!/>X!/>Xt!D,KLG!.,>y:O/!N/f:N/2O/2N/!/>X!.,!,@!D,KL(,tî!N/4!,/>c!0!0!0n !N-~#!0̓ ã!0ͬ!D,/,>c!0~U!9"0:#Z!#6!#"/r*/>$Gt!##>Gt!#0,>Gt!#6!#6!#"0!0T!F-6!"#!D,6!06:0}͐3>!D,ͧd*0!F-6!#6*##"#*# |.!"0}20!0>!#*0"0!0U!#"0!0+!#*06*0 "0!04í!"#:+.!+6:# :# :#.~!#*#~20:0 20:0Q~:0Þ:K-z"/!0Ur"/*/ 3,>Gt!0#!D,6,> c!0ͷ~Ͳ"0~# ¦*0^#V"0*0^#V"0͕!1"1!216>261251:!12:1::1!51!!1:51og~271:21!216{:71!61281*0:61o:81OLG!1>c:81og>og}281*0:81ogW"0*0:81og####"0*0*0W*00>c*0";1!;1ͷ~>291!1n&}2=1:=1!91*1:91og"1*1~og |*1>ߦw*1~?*16_*1~@*16`!914å*0++*0)"1*11>_*0^#V"31*0^#V#r+s*1*0*0^#V)))s#r*0:61_L*0*0^#V)))>t*0*0^#V)))w#w!31#`*0*31)))^#V1j`*0*0^#V)))"1*1!1>Gt*0*31)))"1*1*1>Gt*31+"31*0*31)))^#V1j!31#T*1"1*0*31)))"1*1*1>Gt*31+"31*11>Gt:71%^}2C1:C1!A1$ *0:A1_LG!>1>t!0>1xy!0>1xy !B14:A1!!1:B1ogw!0>1xy :B12!1!A14ì*00>c*0"D1!D1ͷ~^#V"F1*F1^#V> ͍!H1 *!H1> XÓ1~# s !9"2!1"1!16*1w#w*1ng | *1KLG!1>yº !1**1~ogQ1~og)1^#V*1^#V#r+sH !11>c !1*>22*1~ogQ1~Y !11xyK !24H :2K !1!1> !1* *1*1^#Vͯ1>_ *1~ogQ1~ !1*{ !1*!11xy !1*é !1**1~ogQ1~ !1* *2:1 !16!"1*1n&"1*1"1' *1#"1*1*1W7 *1*1>Ó*1~og |c !1>ߦw !1~?t !16_ !1~@‚ !16`Y2 ~# ˆ *_2^#V"e2*c2^#V"g2!"2*[2^#V"2*2*2W *]2*2ͯ"2!2 :2 *e2*2)))~# *g2^#V#*e2*2)))s#rc *e2*2)))^#V"2*g2*2))~#K *g2*2))^#V"2% *g2^#V#*g2*2))s#r*g2^#V#r+s*a2^#V*g2^#VW !i272>!c!2ͷ~*2+|´ *Y2^#VO"2þ *Y2^#V"2*2*g2++*g2^#V))s#r*g2*g2^#V))w#w*2#"2ô 2~# *26*2LG!X2>yC *2"3*3#~>!3w:3og2~C :2 !26*e2^#V#"3!3"323!3> *3++| !"3Ñ *3>og"3*3:3og)2s#r!34d !" 3*e2^#V" 323*2"3!3"3* 3* 3W_!34:3og)2^#V" 3*e2*3)))^#V"3*2*3j/*3+" 3* 3* 3"3!36\*3*2jY*3#" 3* 3* 3W"3!36\Û :3o* 3"3u* 3"3*e2*3)))^#V"3*2*3jʛ*26*3*2s#r3 ~# ±*3^#V"#3*!3^#V"%3! ÷>2.3*3~ʟ*34*3~og"3!3A !/3*!/3>XG!3>y.!/3>X3t!/3>XG!3>y[!/3>X3t*3!3>}23:3ʐ!/3>S*3:3<_Lt*3"3!3ö*33>_*3"3!3!;3"93!3*3>!t!<3"53!L33>Gt!Q33>Gt!"'32.3*'3*#3^#VW*'3#"'3*#3*'3)))^#V!<3>p!")3*)3 |*53+*)3"73*73~ ]Æ*73~_n*736?|*73~`|*736@*)3#")38*#3*'3)))!M3>Gt*#3*'3)))^#V")32-3!)3~#ʖ:-3 ͟!<33>t!M33>t2-3!-34*%3++*)3))^#V"+3:,31!Q3:-3ogͯ3>Gt*+3O"+3M!Q3:-3ogͯ3>Gt!3A !/3*!/3>S!L3:-3ogͯ>t*%3*)3))^#V")3ø͟!.34*3~!.3!t:-3ogͯ}!;3w!;3~w*93:;3=_L3t*93!3>_!3^#V"<:F4!F46*<KLG!H<>y+!E46ð!E46!4"$Gt!'4I<>Gt!*46!>46z"!4*<@*<"r2<:E4:<>2<>2<*Gt!^<<xy;!<8!<5!<͛#E!<͛!<5:22%^}2<:!4*<@*<"!4*<@*<"2<*t!<͆!<4!<͆^#V^#V  $ "/  Later CP/M or MP/M Version Required$*#=**#={ozgY|g}o!\!l!ÍÝ3>Ý!*3>K* !*   >    !"#$%(^#V^#VF3O3*# 72gl*<"?'w#-!9~sG~#s4! 9~.Y+60e0e6 #M+r>o&9y>o&90w+Š6./G! >0 >-3T]))寕iO>`G>0 <  DM0 > Ew#E~#X~#W #Ý!9Oo>gy~#o>gxGGtwF#"WObk++~+ y~#/~!>)< D=M)6ɯo>g{ozg!dÄlmnpr Conversion2!Ä*%=|^#V"%=###^#V#N#Fxʿ #~ò*%=|^#V#N#F!9yx"%=:L# !9!#{z#  !!9:]#O!^# {#z!]#5#}OD*#=~r##~#fo9!NÄVWXZ\ Free Space Exhausted##^#V#{_zW;{_zW>4z˜{##^#V# ##s#rs#r#s#r+++~sw#r####}*#=}|5*{z5+F+N+V+5^{;{z;}|;{i`~sw#r##q#p i`N#F#^#V~;q4#p+i`##s#rA"]" FREE Request Out-of-Range$ Free Space Overwrite$GKҜMbkÜiFhNhN#Fh^#V"#y2#xүi&ͩ x>!J#{#z*#*# xyxM_!^#VͤG>(Iỳ>)I|*<|6<ͤͶò">,IG> _O! O! O!0:IIWWG|e}e ڐdԒ ͒ڝÔxWN #~Iæ!wͤ*=!9{_z{ G>#I*=>=^#V#q>: >?I!oͤͤ>=I^#V|A}8.))ä#F>A> #\~ >.~ =M^#V# File: Traceback: ERROR FIXED OVERFLOW OVERFLOW UNDERFLOW ZERO DIVIDE END OF FILE UNDEFINED FILE KEYNULCONCONRDRPUNLSTBADG!]#~8  " Condition Stack Overflow$4Ox!< w#s#r#s#r!9!^# s#r!]#N!< +++++q #{Š #zʏ ++~q ++!]#5!~# ž Ú !]#N!< +++++¹ #~# +{ #z ++~ù #^#V=!L#~9!5:L#_!M#^#V"J#~#.~# !*#)))))# )| !*~#|}*#"#:L#*J#~#w# F!*#{ `! d!!#"#Ö!Copyright (c) 1980 Digital Research, v1.3 !"!="="%=2]#2L#*'= !"=q#p##}o"#=*}o|!""+w+w+r+s4w#w#s#r<2)=++*!=s#r"!=*=#"=*=DM!!=x~¨"#~+¨"+F+Nq#p*=+"=ʣ"Ҧ"=Y"!+~O~#~G!>w!/x"yʞ" >O6# x" h"=ɯ ~#fo++"!=~#"*!="²""""  Insufficient Memory$ Invalid I/O List End of Execution$#dd(Copyright (c) 1980 Digital Research V1.3MXList SYMd$PlPRINTER busy XREF 1.3 no SYM file no PRN file CP/M PRNXRFABORTED. V́ + 1@+>  FG1"z*QS cE5T @///,,D,B,G-,Q/D,D,L-,D,D,N-P-L-N-P-G-@,I-P/O/Q/G-I-D,000//D,symbol table overflow ' invalid SYM file format  { *$'symbol table reference overflow 22i2 0# +333lXRF.XRF make error  '.XRF close error .XRF write error <<<_<<bUSER Enter User#:5 5A> ThyÙCP/M Version 3.0COPYRIGHT 1982, DIGITAL RESEARCH151282nLT`CP/M 3 SID - Version 3.0$1 !~=W!x ~#ôbx {~#o}o.ÃO$ y͏ , $  ͌ 9!z6 # L!zw͌j# X:z 0 ͘=N#Fy}80*z{¯#z+++ ¥ z#½# · 9!`͠ y9!rͷ y=!z{w# % w!P͠ y͓}*w#"͌ @.@<!Eͷ~P !ͷ’P͌Q!ͷªP}QxQ!ͷ͓G@Q! ͷ y͓Gþ!ͷ ͓Q!ͷ͓Q͌Q!.ͷ6y#G͙Qà!2ͷQ͓͌Q!>ͷq eg͙Q:zJEËC–EQyQxQRQ** {zҷ*~#" <AOGƐ'@'OxƐ'@'ON# z8O!B N#N ¾SP.* |} !9":q!"28!"9:] ,:e &͟:l &:u &ͮ!I 1lĤ>#J ,!6-X5AڔҔ_!o^#V - G  + Q  1ͳҔ~½:,=”͍" ,~ڔʔ͍=͍=͍!,o͍ "c=͍=”)*c)!"f,*f*c"h ,*cL>::ʗ^#V#L cxZy y~ #*f ڵ™y ¶"c:,*hT*f , ,T:e,>2e,:ʔ%:e  ͟:u ' ͮ!I Y|”,,}5 2l~2m͍͍"n͍"pDMs !l6ʏ } "v=ʏ =ʏ YP !~ #^#V:l *v{ z "r~62t #w6 ” 1l*v*t!~4 #~#F# x ~#s#r#w>~ʽ ͍=; =”͍Lᯕo>gL,>#!u^#V#0}o|ge X x| y0ʃ GÏ yÏ  G| Q z,{ ,<,>'{>',*##V+^+N+y,L ~+ , :”%,ͳҔ~ ͍" = ͍"=”" > 2,Y,!|G }G , w#. ~ڔ ͍!=:r ”͍| !| !|”"!~ʩ #~#V§ z§ :w, ‰ :ʔ!~ :w#s#r, ¾ Ô!~ : 6 ~#^#V ,:ʔ!\6#>  w# ' >w# 1 6~!I =”*"!l6~# T :]?2 7ʔ!">HXE͆*ʾ \ͤ2 w# ™ ͥ͝* ҆ !""Ô\ʔ:¾ W$ _$ $ O { x! i`"v2 $ $ w# $ ͥ͝”þ \̀\̀ GтWx!͓B :>ULT͆!6\~# S 2|:] !7<ʔ\ !t   _*\ ʣ \ w Ø *+\ !ڔw{Ҕè *#^#Vr+s+6͓Ҕ*"s#s#rt ! *v*",!*L*L*vL*+L,o=”͍L:X^#VL\~J ʯ.y:,>."Ž! ;w#́=”͍:ʨs#r#;”}w#:;#;>>2o!"#͍}ʔ==”͍""2mNl :ʔ!\>2|!"*"~:8”*"*"*͠ڔ!"\zn<ʔ*ͯ~# _\V”*#"͠:W\J!*L!,:2:2>2::>2 N, !9# Ô ”J~,=”͍xA|”}ҔgA>;Ag};,;Q|”}!qw,s#r,:[|_!~ʐ![4Ð\ͤŽ2[g>>?,!e>Cw#>Ow#>Mw!u>Sw#>Yw#>Mw., * ͽw#  ͽ  * ?r# {zPY! |}>2!""!Ow #w 0q!\6 ͤ!"~”͍͍͍!6W6!6# ,œ>2ß͓ͣ ͓ͣ ͓ͣ ”ʔ   :@w# G6#. 6# x!a_!~> 55*~#"ů2[\ͤͤͤͤͤͤ!ex#y#*}|͓"*}|":!͓> _ͤ~# 07> >  ͤL:8>.^+~+:8*>:|}^ >.*f}o|/+- , 0 Ô^#V#*NyҔ** n +ñ q#^#V""~/o>g++Û!.ʔ@͔^#V= ͔^'D! ڔ'?!q'”S_&#hqf0 Ҕ)DM)) O I^*r^#V#^q̀))))oqh"s#r#!4-®+»*+ þ-y_xWþ!IXN!p~ !D_^!x^#Vx1>-~~>=G!q~L!9#x sYYͳғ*v" !6û+"f*v~#cڻʷ^#Vû~*v~Gx5@xv5 x805 x6 45>=*t~*t$5x*l$*n:585"CZMEIABDHSP!"2"t+"v!91t*v~:t2l!~ʐ#^#V#~ ƒ!~6ʳ=G#^#V#~xâ#"v!N#FN*>7l :|!~9#~#V*v9z9~==2wͲ:l <!*vNl  |Ͳd=Xl *v5Nl :l|*pMD*n:m7l !"N2>**vͳҟ" *t"c, PASS !~*+"|w=2~ !~##Z:t*rw2t*vF#!s! ^#V&N&N,`r<¦Gæ::^#V#2*r^#V<[>èæxjê8_æ*t2¦,:?*v###æG>è><7*|!N*v!>#> :!>=_~/w/w{G=YP"*##F+N+~a/o>g{\z\<33=>!y$ڇ *y$&>'d !y$4d SYMBOLS NEXT MSZE PC END 6!z$q!h#6?! h record(s) written. h#H!:#A{$O !:h# !2h#!@ !:h#S:h#QHP!:#<2|$2h#:h# HG!)!2h#Ô!2h#02|$O> j!!|$6Ô!2h#02w$O> @!!BH @@ABH B! "BHI$$BI$BI $ HI D$HD$$ H B!$D$"$B$DA!ABI$H B$I $HI$H$! $I $I$I $I $BBHHA"HI$H!$HH$ IDH$$H$"BD $$$HH$B@@D!@H" H " "BI$DI$I $H @HI"$AD@@HA$ $@ $@D IB!  $H $I$$HD H!"A""! I$DDI"I$ @$I"DH BH" !I B  B$H$@"IHBI $$@H@ @@@D !@BA$!" D!$A$B@$@@$"$"@  D@@"DH $I!"DH$BB$"H@ $!D$$I$I$$"A$$I  D UUTH@@!@H@ !$  e USER command sets the current user number. The disk directory can be divided into distinct groups according to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> Th!y~=W!x# ~#bxE {8~#o}oA'.`28!Ip+q*HT!J6J T ` T!p+q*T> >/Ҥ×!p+q*DM͛:̀ ̀:2:!!K:*&L Ǹ!4!K6 ͐uÇYALPSID'TCELLOC$LAITINI!ÓCOPYRIGHT (C) 1977, DIGITAL RESEARCH g gzd{ *9 Wl> W> W*"!"^l!]kl$]xl']::>2l!6!"!~4*s,r,"!~Ol!F2y* "*xT-V-^yA!~4x]> WO" Q>2y*"  INITIAL = COLLECT = DISPLAY = "-A" IN EFFECT, ADDRESS BACKTRACE READY FOR SYMBOLIC BACKTRACE BACKTRACE:%B 2!4þ *%"%:/ ͩ!4¡ :$ !4!"%!q: O !{4>!O :!{O :2*'M!8 ^#V%!t ͫ *%B :w*%#"%` Ø Ø Ø Ø Ø ͩ` *M6` !6 ` !6 ` !6 ` *&T` !6 ` !6 ` !60 ` *& @@ I$B$!!D!$"H@* ͡. ;ͣW!E# ¡ # ¬# ·@ʴʥzʖ=ʐ=|zJz?4)z zD@@HA$ $@ $@D IB!  $H $I$$HD H!"A""! I$DDI"I$ @$I"DH BH" !I B  B$H$@"IHBI $$@H@ @@@D !@BA$!" D!$A$B@$@@$"$"@  D@@"DH $I!"DH$BB$"H@ $!D$$I$I$$"A$$I  D UUTH@@!@H@ !$  e USER command sets the current user number. The disk directory can be divided into distinct groups according to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> Th4!y~=W!x# ~#bxE {8~#o}oA'.`28!Ip+q*HT!J6J T ` T!p+q*T> >/Ҥ×!p+q*DM͛:̀ ̀:2:!!K:*&L Ǹ!4!K6 ͐uëYALPSID'TCELLOC$LAITINI!%cCOPYRIGHT (C) 1977 DIGITAL RESEARCH {{ { {zb{b{*9 {_zW}l&))o> \> \\ß*"!" ͟#͟Prںºx"x#"̀ں͇"1!6# y͟!h͟$h͟'h*̀`*̀`*1̀I ?! ^#Vr+sz`>>!@^#V#̀{ k͇#"/<͟h2**̀`i~#!~6͟*1Þ6͔h*1^#V#Þ͔{> \*/̀>*\ ERROR - FORM IS X,Y TYPE HISTOGRAM BOUNDS HISTOGRAM: ADDR RELATIVE FREQUENCY, LARGEST VALUE = .INITIAL = .COLLECT = .DISPLAY = .... !6 ` !6 ` !6 ` *&T` !6 ` !6 ` !60 ` *&T` !6* ` !6* ` !6* ` *& @AA I$DBD $I$BHA"DH!""@D@@HA$ $@ $@D IB!  $H $I$$HD H!"A""! I$DDI"I$ @$I"DH BH" !I B  B$H$@"IHBI $$@H@ @@@D !@BA$!" D!$A$B@$@@$"$"@  D@@"DH $I!"DH$BB$"H@ $!D$$I$I$$"A$$I  D UUTH@@!@H@ !$  e USER command sets the current user number. The disk directory can be divided into distinct groups according to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> Th1!~# (D(E(O5~F( N5xxyͻ5 Dec 85 This program is used to enable/disable the 40 column display. The 40 column screen slows the system down (stealing BUS cycles). Thus by turning off the 40 column display, programs will run a little faster. The comand format is: SCREEN40 ; A=0 no errors ; A=1 non-recoverable error ; A=2 disk write protected ; A=FF media change detected ; DSEG read$154X: call get$drv$info jm mfm$rd call set$up$GCR ; compute effective track and sector login$rd: lda vic$drv mov b,a lda fast ; get fast flags ana b ; isolate fast bit for this drive jrnz rd$fast ; go handle fast drive rd$slow: mvi a,vicrd ; read a sector of data (A=1) call dsk$fun ; a=0 if no errors jnz test$error ; check for disk error or media change ; ; ; buf$move: xra a ; set direction to read call ?dkmov ; go move buffer to DMA lda sect$cnt ana a rz ; a=0 means not read errors call set$up$next jr rd$slow page ; ; A=drive type info ; mfm$rd: call set$up$MFM rd$fast: mvi a,vic$rd$f call dsk$fun ; go read the disk ani 0eh ; mask off error bits jrnz test$error call get$sector$size inr d inr e ; adjust count for pre-decrement call ?di$int lxi b,0DD00h ; D2PRA inp a ; get current clock polarity xri 10h ; toggle clk$bit outp a ; to have status sent (extra clock ; supplied by rd$1571$data for multi ; sector transfers) lda vic$count rd$multi$sect: push psw push d ; save the sector size call rd$1571$data ; read disk data to DMA address pop d lda vic$data ani 0eh jrnz test$error$pop ; A=0 if no errors pop psw dcr a jrnz rd$multi$sect ei lda sect$cnt ana a ; any sectors left to read jrz done$rd$1571 call set$up$next jr rd$fast done$rd$1571: lxi b,0DD00h ; D2PRA inp a ani not(10h) ; set clk$bit hi outp a xra a ; A=0 for no errors ret page ; ; ; write$154X: call get$drv$info jm mfm$wr call set$up$GCR lda vic$drv mov b,a lda fast ; get fast flags ana b ; isolate fast bit for this drive jrnz wr$fast$drive ; go handle fast drive wr$slow: mvi a,-1 ; set direction to write call ?dkmov ; go move DMA to buffer mvi a,vicwr ; write a sector of data call dsk$fun ; a=0 if no errors ani 0eh jrnz test$error lda sect$cnt ana a rz call set$up$next jr wr$slow test$error$pop: pop psw test$error: ei lda vic$data ani 0fh ; check for disk error or media change cpi 0bh ; disk change ? jrz change$error cpi 08h ; test for write protect error jrz write$prot$error mvi a,1 ; get general error flag ret ; ; write$prot$error: mvi a,2 ret ; ; change$error: mvi a,-1 ret page ; ; ; mfm$wr: call set$up$MFM wr$fast$drive: mvi a,vic$wr$f call dsk$fun ; go send the write command call get$sector$size ; setup DMA adr and transfer count lda vic$count wr$multi$sect: push psw push d ; save sector size call wr$1571$data ; write data to disk from DMA address pop d ani 0eh jrnz test$error$pop pop psw dcr a jrnz wr$multi$sect ei lda sect$cnt ana a rz ; return if no errors (A=0) call set$up$next jr wr$fast$drive page ; ; ; get$drv$info: lhld @dma shld local$dma xchg shld DPH$pointer lda @adrv ; get drive number (0 to F) ana a cz drive$A$E cpi 'E'-'A' ; test if drive E cz drive$A$E dcx h ; point at drive mask dcx h mov a,m ; get drive mask mov b,a ; save in B sta vic$drv ; save vic drive # (values 1,2,4,8) inx h ; point at disk type xra a sta sect$cnt ; clear the count inr a sta vic$count mov a,m ; get disk type ana a ret ; ; drive A and E share the same physical disk drive (unit 8) ; drive$A$E: mov b,a lda curdrv ; get the current drive def cmp b ; curdrv = requested drive ? rz ; yes, return ; no, tell the user to swap disk push h push d push b send$messg: mov a,b ; get requested drive # to A sta curdrv ; make this the current drive adi 'A' ; compute drive letter sta msg$drv RCALL FR$bell ; ring BELL to alert user lxi h,swap$msg$lng*256+buff$pos lxi d,swap$msg call disp$msg$DE$HL ; disp and wait for CR mvi a,vic$test call ?fun65 ; ani 0fh ; cpi 0ch ; not fast ERROR ? ; jrz exit$drv$A$E ; yes, return that's not a problem ; ani 0eh ; other error type ? ; jrnz send$messg exit$drv$A$E: pop b pop d pop h mov a,b ret swap$msg: db 'Insert Disk ' msg$drv: db 'X in Drive A' swap$msg$lng equ $-swap$msg+2 ; +2 for leading and trailing spaces page ; ; ; get$max$num$b: lhld DPH$pointer lxi b,42 ; offset to number of sector(DCP/M PLUS803D(D80@D80@(COPYRIGHT CBM 86MHxFGmLZɀ (  FGLCBMx ?! 﨑 ! h ' k ' m Í>L!   ,  !)`xIݩ, `0U0L1w<>1w<>?2!60!>22!  ~y+  >E >y>2$>2 $ͽ>2$& BOOTING CP/M PLUS>y>@2@"Tf* =  #25< <:5<(<=€* * <|*<|(*<|Í͢͵ ^{)"<+f.!<*<!"<*<+"<}!4"*<^#V#"<)):2##>20 R0yN8< >0> 2y2Ox 0x>LحUТ0  h1  *`, ,L 0 0 111 ! Ơ0 , ܮ0x 0)Ъ 0 0)` 0 !`Iݩ, ` ܭ ݩhhhh@0U0Ls on track dad b mov a,m ; get number sectors/track/side ani 1fh mov b,a ret ; ; ; get$sector$size: lhld DPH$pointer dcx h mov a,m ; disk type in B (bit 5,4 size info) rrc ; ..00 = 080h byte sectors rrc ; ..01 = 100h byte sectors rrc ; ..10 = 200h byte sectors rrc ; ..11 = 400h byte sectors ani 3 jrz set$128 jpo not$3 ; jump if (A=) 01b or 10b inr a ; make A = 4 not$3: mvi e,0 ; set E to zero mov d,a ; set sector size (1,2 or 4) get$DMA: lhld local$DMA ; get the current DMA pointer ret set$128: lxi d,128 jr get$DMA page ; ; ; DSEG set$up$GCR: cpi dsk$c128 jnz tst$next mvi a,4 sta sect$cnt lxi h,sect$buffer shld sect$buf$ptr lhld @trk ; 1 K sector pointer dad h dad h ; make 256 byte pointer ; ; build a list of tracks and sectors ; next$sect: shld @trk RCALL FR$trk$sect lhld vic$trk ; get trk(L) and sector(H) to HL xchg lhld sect$buf$ptr mov m,e inx h mov m,d inx h shld sect$buf$ptr lhld @trk inr l ; update saved above at next$sect mov a,l ani 3 jrnz next$sect ; ; check list of trk-sectors for number of sectors on this trk ; lxi h,sect$buffer shld sect$buf$ptr lda vic$drv mov b,a lda fast ana b ; drive type 1571 jrz handle$1541 ; no, handle as 1541 lda sect$cnt ; number of sectors to rd/wr mov b,a inx h mov a,m ; get 1st sector # sta vic$sect dcx h mov a,m ; get 1st track # sta vic$trk try$next: cmp m ; test for same trk # jrnz exit$no$match inx h inx h ; advance to next trk shld sect$buf$ptr djnz try$next exit$no$match: lda sect$cnt ; number of sectors to rd/wr sub b ; remove number left ; (leaving number matched) sta vic$count ; save number to read mov a,b ; get remaining count sta sect$cnt ; save remaining count ret set$up$next: lda vic$count ; get number of sectors read lhld local$DMA ; get current DMA pointer add h ; advance pointer by number of mov h,a ; sectors read shld local$DMA handle$1541: lhld sect$buf$ptr mov a,m sta vic$trk inx h mov a,m sta vic$sect inx h shld sect$buf$ptr lda vic$drv mov b,a lda fast ana b jrz set$up$next$slow lda sect$cnt sta vic$count xra a ; two reads max with fast drive jr set$up$next$exit set$up$next$slow: lda sect$cnt dcr a set$up$next$exit: sta sect$cnt ret ; ; ; tst$next: if use$1581 cpi dsk$1581 jrz c1581$adj endif tst$c64: mvi b,dir$track ; set the dir track number cpi dsk$c64 ; C64 type disk? lda @sect ; get sector # to set jrz set$up$c64 ; yes, go set up for C64 CP/M disk format ; no, set up as no type(direct addressing) ; ; This format is for direct track and sector addressing ; do$type$7: mvi b,255 ; no dir sector ; ; this routine will adjust the track number if necessary. ; The C64 CP/M disk has the C64 directory in the center ; of the disk. This routine checks and adds one to the track ; number if we have reached or passed the directory track. ; set$up$c64: sta VIC$sect ; lda @trk ; cmp b ; carry=1 if A < dir$track cmc ; add one if dir$track or more (carry not set) aci 0 ; add the carry bit in sta vic$trk ret if use$1581 ; ;****** adjust to read multi-512 byte sectors (system sees 1K sector size) ; c1581$adj: mvi a,2 ; 2 512 byte sectors equ 1 1K sector sta vic$count lda @trk ; cpi C1581$dir$trk*2 ; carry=1 if A < dir$track cmc ; add one if dir$track or more (carry not set) aci 0 ; add the carry bit in rar ; track=@trk/2 ; carry set if odd sta vic$trk ; lda @sect ; sector # are 0 to 9 (10 sector/trk) mov b,a ; jrnc bottom$1581 ; adi 80h ; set top of 1581 bottom$1581: add b ; make 0 to 8 inr a ; adjust to 1 to 9 (odd numbers only) sta VIC$sect ; ret ; endif page ; ; A=dsk$info on entry ; set$up$MFM: mvi d,0 ; D=side # (0) mov e,a ; save dsk$info in E ani TypeX ; look at Type0 to Type7 jrz do$type$0 ; cpi Type2 lda @trk ; used by Type1, Type2 and Type3 jrz do$type$2 jrc do$type$1 ; cpi Type6 ; jrz do$type$6 ; jnc do$type$7 ; MSB of sector(byte) set for 2nd side of disk cpi Type7 jz do$type$7 ; MSB of sector(byte) set for 2nd side of disk ; ; only types 0 to 2 and 7 are currenty defined ; Type3 to Type6 will do Type2 ;do$type$3: ;do$type$6: do$type$2: mov b,a ; save a copy in B sui 40 jrc do$type$0 ; jump if still on side 0 mvi a,79 ; on back side count 39,38,37,...,0 sub b set$trk: mvi d,80h ; D=side # (1) sta @trk jr do$type$0 page ; ; divide the track number by two and if Head=1 ; add #sect/side to @sect ; do$type$1: cmc ; carry was set clear it rar ; divide track by 2 (carry gets LSB) sta @trk jrnc do$type$0 call get$max$num$b ; HL and C changed lda @sect add b sta @sect do$type$0: lda @trk sta vic$trk call get$max$num$b ; B=number of sectors per track per side lda @sect ; ..HL and C changed cmp b jrc is$side$0 mvi d,80h ; D=side # (1) bit C1$bit,e ; dsk$info in E ; sector numbering continues on side 1 ? jrnz is$side$0 ; yes, do not remove side one bias sub b ; no, remove side one bias is$side$0: mov c,a ; hold @sect in C mov a,e ; get dsk$info to A ani S1 ; A=Starting sector number (0 or 1) add c ; add back @sect ora d ; add in the side bit sta vic$sect ret page ; ; input: ; DE = number bytes to read ; HL = DMA address ; CSEG rd$1571$data: lda @dbnk ; get the disk DMA bank call ?bank ; set it lxi b,0DC0Dh ; D1ICR rd$1571$stat$wait: inp a ani 8 ; data ready bit set? jrz rd$1571$stat$wait ; no, loop mvi c,0ch ; D1SDR inp a ; read the status byte sta vic$data ; save it ani 0eh ; any errors ? jrnz rd$1571$exit ; yes, exit lxi b,0DD00h inp a ; get current clock polarity rd$1571$next: lxi b,0DD00h ; D2PRA xri 10h ; toggle clk$bit outp a ; clock the 1571 for a byte dcr e ; DE=count jnz rd$1571$more ; leave as normal jump to keep dcr d ; the transfer speed at it's max jrz rd$1571$exit ; ... ; rd$1571$more: dcr b rd$1571$wait: mvi c,0dh ; D1ICR (DC0Dh) inp c bit 3,c jz rd$1571$wait mvi c,0ch ; D1SDR ini ; (hl) <- (bc) ; hl <- hl+1 ; b <- b-1 jmp rd$1571$next rd$1571$exit: sta bank$0 ; restore current mem config ret page clk$in equ 40h ; ; input: ; DE = number of bytes to write ; HL = DMA address ; wr$1571$data: call ?di$int ; do spout inline lxi b,mode$reg mvi a,fast$wr$en sta io$0 outp a ; set data direction to output sta bank$0 lxi b,0dc05h ; low (D1T1h) xra a outp a dcr c ; low(D1T1l) mvi a,3 ; clk = osc/3 outp a ; mvi c,0eh ; D1CRA inp a ani 80h ori 55h outp a dcr c ; D1ICR inp a lda @dbnk ; get the disk DMA bank call ?bank ; set it mvi a,clk$in sta cur$clk page ; ; clk$wait: lxi b,0dd00h ; D2PRA inp a inp c ; debounce cmp c jrnz clk$wait lda cur$clk ; get old clk value xra c ; check if changed ani clk$in ; (only clock in bit) jrz clk$wait ; loop if not mov a,c ; sta cur$clk ; make this the current clk value lxi b,0dc0ch ; D1SDR mov a,m outp a ; send character to drive inx h ; advance pointer dcx d ; dec the char count inr c ; D1ICR send$wait: inp a ani 8 jz send$wait mov a,d ora e jnz clk$wait ; go send the next byte ; do spin lxi b,0DC0Eh ; D1CRA inp a ani 80h ori 8 outp a lxi b,mode$reg mvi a,fast$rd$en sta io$0 ; enable the MMU outp a ; set data direction to input sta bank$0 ; disable MMU ; spin done page lxi b,0DC0Dh ; D1ICR inp a ; clear data pending flag lxi b,0DD00h ; D2PRA inp a ori 10h ; set clk$bit low (hardware inverted) outp a ; lxi b,0DC0Dh ; D1ICR wait$status: inp a ani 8 jrz wait$status lxi b,0DC0Ch ; D1SDR inp d lxi b,0DD00h ; D2PRA inp a ani not(10h) ; set clk$bit hi (hardware inverted) outp a ; mov a,d ; recover the status byte sta vic$data ei ret page ; ; This routine is used to move a sector of data ; to/from the sector buffer and the DMA pointer. ; A=0 for buffer to DMA (disk read) ; A<>0 for DMA to buffer (disk write) ; CSEG ?dkmov: lhld local$DMA ; current DMA adr lxi d,@buffer ; location of disk read/write buffer lxi b,256 ; sector size ; ; dk$cont: ora a jrnz dsk$read ; swap pointer for read xchg ; ; dsk$read: lda @dbnk ; get the disk bank call ?bank ldir ; do the data move sta bank$0 ; current bank will ALWAYS be 0 ret ; ; ; DSEG dsk$fun: sta vic$cmd lda stat$enable ani 1 ; display of disk info enabled? cnz disp$dsk$info ; yes, go display disk info jmp ?fun65+3 ; go do the function page ; ; ; DSEG ?dskst: disp$dsk$info: mvi a,72 ; r/w in col 72 (col 0-79) sta offset lda vic$cmd mvi b,'R' dcr a ; ?1 normal$rd jrz out$cmd$rd dcr a ; ?2 normal$wr jrz out$cmd$wr dcr a ; ?3 fast$rd jrz out$cmd$rd dcr a ; ?4 fast$wr rnz out$cmd$wr: mvi b,'W' out$cmd$rd: call disp$B call disp$space mvi b,'A'-1 lda vic$drv next$drv: inr b rrc jrnc next$drv call disp$B lda vic$trk call disp$dec lda vic$sect ani 80h cz disp$space mvi b,'-' cnz disp$B lda vic$sect ani 7fh page ; ; ; disp$dec: mvi b,'0'-1 conv$loop: inr b sui 10 jrnc conv$loop adi '0'+10 push psw call disp$B pop psw disp$A: mov b,a disp$B: lxi h,@st40-72+40-8 lda offset mov e,a mvi d,0 dad d ; add the offset mov m,b ; save on 40 col display mov a,e mov c,a ; col # in C inr a sta offset ; advance cursor position xra a ; no attribute to write call ?stat lxi h,@st40 lxi d,vic$screen+40*24 ; update 40 column screen lxi b,40 ldir xra a ret disp$space: mvi b,' ' jr disp$B page ; ; Extended Disk Parameter Headers (XDPHs) ; CSEG ; place tables in common ; ; 1st disk drive on the system ; dw write$154X dw read$154X dw login$154X dw init$154X db 1 ; bit 0 set (drive 0) db dsk$c128 ; format type byte cmdsk0: dph 0,dpb$0 dpb$0: dpb 1024,5,159,2048,128,0 db 0 ; max sector number and lock flag dw 0 ; MFM table pointer page ; ; 2nd disk Drive on the system ; dw write$154X dw read$154X dw login$154X dw init$154X db 2 ; bit 1 set (drive 1) db dsk$c128 ; format type byte cmdsk1: dph 0,dpb$1 dpb$1: dpb 1024,5,159,2048,128,0 db 0 ; max sector number and lock flag dw 0 ; MFM table pointer page ; ; 3rd disk drive on the system ; dw write$154X dw read$154X dw login$154X dw init$154X db 4 ; bit 2 set (drive 2) db dsk$c128 ; format type byte cmdsk2: dph 0,dpb$2 dpb$2: dpb 1024,5,159,2048,128,0 db 0 ; max sector number and lock flag dw 0 ; MFM table pointer page ; ; 4th disk drive on the system ; dw write$154X dw read$154X dw login$154X dw init$154X db 8 ; bit 3 set (drive 3) db dsk$c128 ; format type byte cmdsk3: dph 0,dpb$3 dpb$3: dpb 1024,5,159,2048,128,0 db 0 ; max sector number and lock flag dw 0 ; MFM table pointer page ; ; Drive E: shared with 1st drive (A:) ; dw write$154X dw read$154X dw login$154X dw init$154X db 1 ; bit 0 set (drive 0) db dsk$c128 ; format type byte cmdsk4: dph 0,dpb$4 dpb$4: dpb 1024,5,159,2048,128,0 db 0 ; max sector number and lock flag dw 0 ; MFM table pointer page ; ; NOTE: The blocking factor for all of these formats is ; 1K (2K for double sided), thus the fractional ; parts are unusable by CP/M. They can be accessed ; by absolute sector addressing. ; ; NOTE: 1571 and 1541 disk drives use track numbers ; of 1 to 35 and sector numbers of 0 to nn ; ; The method used to access the full disk ; is to tell the system that there is 1 sector ; per track and then to use the track # as an ; absolute sector address and do conversion in BIOS. ; ; ; DPB FOR C128 CP/M 3.0 disk ( 170K, 34K larger then C64 CP/M) ; 256 byte sectors ( 170.75K ) ; 1 sectors/track ; up to 21 physical sectors (0 to 16,17,18 or 20) ; 680 tracks/disk (usable, 683 real) ; 35 physical tracks (0 to 34) ; 1K allocation blocks ; 64 directory entries ; track offset of 0 ; DSEG ; these tables are moved to common when used dpb$c128$SS: ; (170 allocation units) dpb 1024,1,170,1024,64,0 page ; ; DPB FOR C128 CP/M 3.0 double sided disk ( 340K ) ; 1024 byte sectors (phy=256) ( 341.5K ) ; 1 sectors/track ; up to 21 physical sectors (0 to 16,17,18 or 20) ; 340 tracks/disk (usable, 1366 real) ; 70 physical tracks (0 to 34 side 0, 35 to 69 side 1) ; 2K allocation units ; 128 directory entrys ; track offset of 0 ; dpb$c128$DS: ; (170 allocation units) dpb 1024,1,340,2048,128,0 page ; ; DPB FOR C64 CP/M 2.2 disk -- ( 136K ) ; 256 byte sectors ; 17 sectors / tracks (sector numbering 0-16) ; sector 18 to n on the outer tracks are unused ; 34 tracks / disk ; tracks track 2 to 16 (track numbering 0-34) ; track 17 is the C128 directory track (not counted) ; track 19 to 34 ; 1K allocation blocks ; 64 directory entrys ; track offset of 3 (1st two tracks used for CP/M 2.2 boot) plus ; one sector to adjust for sector numbering of 1 to 35 (not 0 to 34) ; dpb$c64$cpm: ; (144 allocation units) dpb 256,17,34,1024,64,3 page ; ; DPB FOR C128 CP/M 3.0 C1581 DSDD (3.5") ( K ) ; 512 byte sectors ( 720K ) ; 10 sectors/track ; 159 tracks/disk ; 160 physical tracks 80 on top, 79 on bottom, 1 used for ; BAM and disk directory (1581 DOS) (10 sectors per track) ; 2K allocation units ; 128 directory entrys (2 allocation units) ; if use$1581 dpb$1581: ; (xxx allocation units) dpb 1024,5,159,2048,128,0 endif page ; DSEG MFM$table: db S256*2+(16*2-8)+1 ; 256 byte sect, 16 sect/trk db MFM+S256+Type0+C0+S1 ; DSDD dw 0 ; start on track 2 sect 1 (2 alc) dpb 256,32,40,2048,128,2 ; sect# 1 to 16 db 16 ; (top and bottom numbered the same) db 'Epson QX10' ;1 Epson QX10 ; 160 allocation units db 80h+S512*2+(10*2-8)+1 ; 512 byte sect, 10 sect/trk ; db S256*2 ; track 0 is 256 bytes/sector db MFM+S512+Type0+C0+S1 ; DSDD dw 0 ; start on track 2 sect 1 (2 alc) dpb 512,20,40,2048,128,2 ; sect# 1 to 10 db 10 ; (top and bottom numbered the same) db 'Epson QX10' ;2 ; 200 allocation units page db S512*2+(8*2-8)+1 ; 512 byte sect 8 sect/trk db MFM+S512+Type2+C0+S1 ; SSDD dw 0 ; start on track 1 sector 1 (2 alc) dpb 512,8,40,1024,64,1 ; sect# 1 to 8 db 8 ; db ' IBM-8 SS ' ;3 ; 160 allocation units db S512*2+(8*2-8)+1 ; 512 byte sect 8 sect/trk db MFM+S512+Type2+C0+S1 ; DSDD dw 0 ; start on track 1 sector 1 (1 alc) dpb 512,8,80,2048,64,1 ; sect# 1 to 8 db 8 ; (top and bottom numbered the same) db ' IBM-8 DS ' ;4 ; 160 allocation units page db S512*2+(10*2-8)+0 ; 512 byte sector, 10 sect/trk db MFM+S512+Type1+C1+S0 ; DSDD dw 0 ; start on track 0 sector 10 (2 alc) dpb 512,10,80,2048,128,1 ; sect# 0 to 9 on top (even tracks) db 10 ; sect# 10 to 19 on bottom (odd tracks) db 'KayPro IV ' ;5 ; 200 allocation units db S512*2+(10*2-8)+0 ; 512 byte sect, 10 sect/trk db MFM+S512+Type0+C1+S0 ; SSDD dw 0 ; start on track 1 sector 0 (4 alc) dpb 512,10,40,1024,64,1 ; sect# 0 to 9 db 10 ; db 'KayPro II ' ;6 ; 200 allocation units page db S1024*2+(5*2-8)+1 ; 1024 byte sect, 5 sect/trk db MFM+S1024+Type0+C0+S1 ; SSDD dw 0 ; start on track 3 sector 1 (2 alc) dpb 1024,5,40,1024,64,3 ; sect# 1 to 5 db 5 ; db 'Osborne DD' ;7 ; 200 allocation units db S512*2+(9*2-8)+1 ; 512 byte sect 9 sect/track (uses 8) db MFM+S512+Type1+C0+S1 ; DSDD dw 0 ; start on trk 0, sect 1, hd 1 (1 alc) dpb 512,8,80,2048,64,1 ; sect# 1 to 9 db 8 ; (top and bottom numbered the same) db ' Slicer ' ;8 ; 160 allocation units page db S256*2+(16*2-8)+1 ; 256 byte sect, 16 sect/trk db MFM+S256+Type0+C0+S1 ; DSDD dw 0 ; start on track 4 sect 1 (2 alc) dpb 256,32,40,2048,128,4 ; sect# 1 to 16 db 16 ; (top and bottom numbered the same) db 'Epson Euro' ;9 Epson European (MFCP/M ?) ; 160 allocation units db -1 db MFM ; dw 0 ; dpb 512,20,40,2048,128,2 ; db 8 ; db ' None ' ;10 page db -1 db MFM ; dw 0 ; dpb 512,20,40,2048,128,2 ; db 8 ; db ' None ' ;11 db -1 db MFM ; dw 0 ; dpb 512,20,40,2048,128,2 ; db 8 ; db ' None ' ;12 page db -1 db MFM ; dw 0 ; dpb 512,20,40,2048,128,2 ; db 8 ; db ' None ' ;13 db -1 db MFM ; dw 0 ; dpb 512,20,40,2048,128,2 ; db 8 ; db ' None ' ;14 page db -1 db MFM ; dw 0 ; dpb 512,20,40,2048,128,2 ; db 8 ; db ' None ' ;15 db -1 db MFM ; dw 0 ; dpb 512,20,40,2048,128,2 ; db 8 ; db ' None ' ;16 page ; ; not functional yet ; ; db S1024*2+(5*2-8)+1 ; 1024 byte sect 5 sect/track ; db MFM+S1024+Type0+C0+S1 ; SSDD ; dw 0 ; start on trk 2, sect 1 (2 alc) ; dpb 1024,5,40,2048,128,2 ; sect# 1 to 5 ; db 5 ; ; db 'Morrow MD2' ; ; db S1024*2+(5*2-8)+1 ; 1024 byte sect 5 sect/trk ; db MFM+S1024+Type0+C0+S1 ; DSDD ; dw 0 ; start on trk 1, sect 1, hd 0 (3 alc) ; dpb 1024,10,40,2048,192,1 ; sect# 1 to 5 ; db 5 ; ; db 'Morrow MD3' ; MFM$tbl$entries equ ($-MFM$table)/32 db -1 ; mark end of table db -1 page cseg cur$clk: ds 1 dseg lock$flag ds 1 last$match ds 2 window$info: ds 2 dsk$window equ 12 no$dsk$msg: ;1234567890 db ' Missing ' MFM$match$tbl: ds 2*MFM$tbl$entries ; MFM$count MUST follow this parm MFM$count: ds 1 ; MFM$offset MUST follow this parm MFM$offset: ds 1 MFM$cur$ptr: ds 2 DPH$pointer: ds 2 sect$cnt: ds 1 sect$buf$ptr: ds 2 sect$buffer: ds 4*2 local$DMA: ds 2 status$atr equ 0 offset: db 0 end  title 'Terminal Emulation (ADM-31 with K-Pro support) 21 May 86' maclib z80 maclib cxequ lines equ 24 public ?out40,?out80,ADM31 ; ; ADM3A ; ; ; ESC = row col cursor position ; ESC ESC ESC color set color ; added for C128 CP/M ; ^H cursor left ; ^L cursor right ; ^J cursor down ; ^K cursor up ; ^Z home and clear screen ; ^M carrage return ; ^G bell ; ; ADM31 ; ; ; ESC = row col cursor position ; ESC ESC ESC color set color ; added for C128 CP/M ; ESC T clear to end of line ; ESC t clear to end of line ; ESC Y clear to end of screen ; ESC y clear to end of screen ; ESC : home & clear screen ; ESC * home & clear screen ; ESC ) Half intensity on ; ESC ( Half intensity off ; ESC G 4 Reverse video on ; ESC G 2 Blinking on ; ESC G 0 Rev. video and blinking off ; ESC E Insert line ; ESC Q Insert Character ; ESC R Delete Line ; ESC W Delete Character ; ^H cursor left ; ^L cursor right ; ^J cursor down ; ^K cursor up ; ^Z home and clear screen ; ^M carriage return ; ^G bell ; page ; ; KPRO II Terminal control sequences ; ; ; Cursor Control ; ; ^H cursor left (bs) ; ^L cursor right ; ^J cursor down ; ^K cursor up ; ^^ home cursor ; ^Z home cursor & clear screen ; ^M carriage return ; ; Cursor Positioning ; ; ESC = R C (R & C =' '+position) ; ; Line Insert/Delete ; ; ESC E Line Insert ; ESC R Line Delete ; ; Clear to End of Screen/Line ; ; ^X Clear to End of Line ; ^W Clear to End of Screen ; ; Set Greek or ASCII (not supported) ; ; ESC A Set ASCII ; ESC G Set Greek (lower case letters print as Greek Alphabet) ; ; KAYPRO 84 (???) screen commands ; ; ESC B turn attrubute on ; ESC C turn attrubute off ; ; where is defined as: ; 0=reverse video ; 1= ; 2= ; 3= ; ; ; ; The following two sequences are ; use but I do not know what function ; they perform. (added 21 May 86) ; ; ESC D ; ESC L ; page dseg ; ; ; ?out40: mvi a,FR$40 lxi h,parm$area$40 jr out$cont ; ; ; ?out$80: xra a ; 80 column offset is 0 lxi h,parm$area$80 out$cont: sta fun$offset mvi a,7fh ana c mov c,a shld parm$base lhld emulation$adr pchl page ; ; ADM-31 terminal emulation ; ADM31: lhld parm$base ; 1st parm is exec adr (2 bytes) mov a,m inx h mov h,m mov l,a ora h ; L is in A already, test HL=0 mov a,c ; C is char to output jrz start$checking pchl ; ; ; start$checking: lxi h,control$table lxi b,cnt$tbl$lng ccir lxi h,control$exec$adr jrz find$exec$adr cpi 20h rc do$direct: mov d,a TJMP FR$wr$char page ; ; ; char$esc: ; ESC call cont$later ; ; ESC char look for char in the ESC table ; call remove$exec$adr lxi h,esc$table lxi b,esc$tbl$lng ccir rnz ; bad esc sequence lxi h,esc$exec$adr find$exec$adr: dad b dad b mov a,m inx h mov h,m mov l,a pchl page ; ; ; cont$later: pop h ; get address to cont at in H jr save$exec$adr ; save it ; ; ; remove$exec$adr: lxi h,0 save$exec$adr: xchg lhld parm$base mov m,e inx h mov m,d ret ; ; ; esc$esc: call cont$later ; ; check for ESC ESC ESC ; cpi esc ; check if 3rd char is an ESC jrnz remove$exec$adr call cont$later ; ; set current character as the attr ; mov b,a TCALL FR$color jr remove$exec$adr page ; ; ; esc$equ: call cont$later ; ; ESC = R ; lhld parm$base inx h inx h sui ' ' ; remove ascii bias mov m,a cpi '8'-' ' ; test for line 25 (A=24?) jrnz not$status$line ; no, jmp inr a ; yes, A=25 sta paint$size ; set 40 column repaint to 25 lines not$status$line: call cont$later ; ; ESC = R C (go do it) ; sui ' ' mov e,a ; column # to E lhld parm$base inx h inx h mov d,m ; row # to D TCALL FR$cursor$pos jr remove$exec$adr page ; ; ; char$cnt$z: ; ^Z home and clear screen lxi d,lines*256+0 ; B=24(row) C=0(col) TCALL FR$cursor$pos call esc$t ; clear the status line lxi d,0 TCALL FR$cursor$pos esc$y: TJMP FR$CES ; clear to end of screen home$cursor: lxi d,0 TJMP FR$cursor$pos esc$t: TJMP FR$CEL ; clear to end of line ; ; ; do$cr: TJMP FR$do$cr ; ; ; cursor$rt: TJMP FR$cursor$rt ; ; ; cursor$up: TJMP FR$cursor$up ; ; ; cursor$down: TJMP FR$cursor$down ; ; ; cursor$left: TJMP FR$cursor$left page ; ; placed in common so that link and gencpm will not ; cause this code to show up at address 0D000h to 0DFFFh ; char$cnt$g: ; ^G bell RJMP FR$bell ; ; delete character ; esc$W: TJMP FR$char$del ; ; delete line ; esc$R: TJMP FR$line$del ; ; insert character ; esc$Q: TJMP FR$char$ins ; ; insert line ; esc$E: TJMP FR$line$ins page ; ; ESC C atribute off ; esc$C: call cont$later lxi b,4*256+4 ; max+1 num, offset jr esc$num$cont ; ; ESC B atribute on ; esc$B: call cont$later lxi b,4*256+0 ; max+1 num, offset jr esc$num$cont ; ; Set Attribute sequence ; esc$G: call cont$later lxi b,5*256+8 ; max+1 num, table offset esc$num$cont: call remove$exec$adr sui '0' ; remove ascii bias cmp b ; number of functions rnc add c ; get offset mov c,a mvi b,0 lxi h,esc$num$tbl jmp find$exec$adr page ; ; ; esc$D: esc$L: call cont$later ; wait for num1 call cont$later ; wait for num2 call cont$later ; wait for num3 call cont$later ; wait for num4 jmp remove$exec$adr page ; ; Half Intensity Off ; esc$lfp: mvi b,00000001b ; turn intensity up jr set$atr$on ; ; Half Intensity On ; esc$rtp: mvi b,00000001b ; turn intensity down jr set$atr$off ; ; Rev. Video, blink, atl char set, and underline off ; esc$G$0: mvi c,10000000b ; turn attributes off mvi b,11110000b ; attribute bit to change jr set$FR$attr ; ; Select alt character set ; esc$G$1: mvi b,10000000b ; select alt character set jr set$atr$off ; ; Blinking On ; esc$B$2: ; turn flash ON ??? esc$G$2: mvi b,00010000b ; turn on blink attr jr set$atr$on ; ; ; esc$C$2: ; turn flash OFF ??? mvi b,00010000b jr set$atr$off ; ; Under line ; esc$B$3: ; turn underline ON ??? esc$G$3: mvi b,00100000b ; turn on underline bit jr set$atr$on ; ; ; esc$C$3: ; turn under line OFF ??? mvi b,00100000b jr set$atr$off ; ; Reverse Video On ; esc$B$0: esc$G$4: mvi b,01000000b ; turn attributes on set$atr$on: mov c,b ; reverse attr set$FR$attr: TJMP FR$attr ; ; ; esc$C$1: ; turn half bright OFF ??? mvi b,00000001b jr set$atr$on ; ; ; esc$B$1: ; set half bright ON ??? mvi b,00000001b jr set$atr$off ; ; turn reverse video off ; esc$C$0: mvi b,01000000b ; attribute to turn off set$atr$off: mov a,b cma ana b mov c,a TJMP FR$attr page ; ; table scanned top to bottom ; control$table: db 07h ; ^G bell db bs ; ^H cursor left db lf ; ^J cursor down db 0Bh ; ^K cursor up db 0Ch ; ^L cursor right db cr ; ^M carrage return db 1Ah ; ^Z home and clear screen db esc ; ESC db 18h ; ^X Clear to End of Line (K-Pro) db 17h ; ^W Clear to End of Screen (K-Pro) db 1Eh ; ^^ home cursor (K-Pro) cnt$tbl$lng equ $-control$table ; ; table scanned bottom to top ; control$exec$adr: dw home$cursor ; ^^ home cursor (K-Pro) dw esc$y ; ^W CES (K-Pro) dw esc$t ; ^X CEL (K-Pro) dw char$esc ; ESC dw char$cnt$z ; ^Z home and clear screen dw do$cr ; ^M carriage return dw cursor$rt ; ^L cursor right dw cursor$up ; ^K cursor up dw cursor$down ; ^J cursor down dw cursor$left ; ^H cursor left dw char$cnt$g ; ^G bell page ; ; table scanned top to bottom ; esc$table: db '=' ; ESC = R C db 'T' ; ESC T clear to end of line db 't' ; ESC t clear to end of line db 'Y' ; ESC Y clear to end of screen db 'y' ; ESC y clear to end of screen db ':' ; ESC : home & clear screen db '*' ; ESC * home & clear screen db 'E' ; ESC E Insert line db 'Q' ; ESC Q Insert Character db 'R' ; ESC R Delete Line db 'W' ; ESC W Delete Character db ')' ; ESC ) Half intensity on db '(' ; ESC ( Half intensity off db 'G' ; ESC G 4 Reverse video on ; ESC G 2 Blinking on ; ESC G 0 Rev. video and blinking off db 'B' ; ESC B atribute on db 'C' ; ESC C atribute off db esc ; ESC ESC db 'D' ; ESC D ??? db 'L' ; ESC L ??? esc$tbl$lng equ $-esc$table ; ; table scanned bottom to top ; esc$exec$adr: dw esc$L ; ESC L A kaypro function ??? dw esc$D ; ESC D A kaypro function ??? dw esc$esc ; ESC ESC ESC color dw esc$C ; ESC C atribute off dw esc$B ; ESC B atribute on dw esc$G ; ESC G 4 Reverse video on ; ESC G 2 Blinking on ; ESC G 0 Rev. video and blinking off dw esc$lfp ; ESC ( Half intensity off dw esc$rtp ; ESC ) Half intensity on dw esc$W ; ESC W Delete Character dw esc$R ; ESC R Delete Line dw esc$Q ; ESC Q Insert Character dw esc$E ; ESC E Insert line dw char$cnt$z ; ESC * home & clear screen dw char$cnt$z ; ESC : home & clear screen dw esc$y ; ESC y clear to end of screen dw esc$y ; ESC Y clear to end of screen dw esc$t ; ESC t clear to end of line dw esc$t ; ESC T clear to end of line dw esc$equ ; ESC = RC ; ; ; esc$num$tbl: dw esc$b$0 ; ESC B0 reverse video ON dw esc$b$1 ; ESC B1 ??? half bright ON dw esc$b$2 ; ESC B2 ??? blink ON dw esc$b$3 ; ESC B3 ??? under line ON dw esc$c$0 ; ESC C0 reverse video OFF dw esc$c$1 ; ESC C1 ??? half bright OFF dw esc$c$2 ; ESC C2 ??? blink OFF dw esc$c$3 ; ESC C3 ??? under line OFF dw esc$g$0 ; ESC G0 clear attributes (all G functions) dw esc$g$1 ; ESC G1 alt char set dw esc$g$2 ; ESC G2 blink attr on dw esc$g$3 ; ESC G3 underline attr on dw esc$g$4 ; ESC G4 reverse video on ; ; title 'C128 external Disk drive support 28 Apr 86' ; ; This program contains the stubs for bringing up the C128 CP/M ; for the first time. ; ; The method used to stub the system I/O is to send the ; operation request to the serial port as a command and ; recieve responce from the serial channel. ; ; The commands supported are: ; ; CMD: 'I' ; input keyboard char ; RSP: xx ; returns keybord char or 00 if none ; ; CMD 'O'xx ; send char xx to display ; RSP: xx ; echo character ; ; CMD: Rttss ; read sector of data adr by track (tt) sector (ss) ; RSP: xx..yy ; returns 128 bytes of data plus a check sum ; ; CMD: Wttssxx..yy ; write sector of data, sent with a check sum ; ; to (xx..yy) adr by track (tt) sector (ss) ; RSP: xx ; xx=00 if no error ; page maclib cpm3 maclib z80 maclib cxequ public ?int65,?in65,?ins65,?out65,?outs65 extrn ?intbd ; Utility routines in standard BIOS extrn ?pmsg ; print message @ up to 00 ; saves & extrn ?pdec ; print binary number in from 0 to 99. extrn ?pderr ; print BIOS disk error header extrn ?conin,?cono ; con in and out extrn ?const ; get console status ; ; drive table ; public @dtbl extrn cmdsk0,cmdsk1,cmdsk2,cmdsk3,cmdsk4,RMdsk page ; ; DRVTBL.ASM ; CSEG ; place code in common memory @dtbl: dw cmdsk0 ;* drive A 1541/1571 dw cmdsk1 ;* drive B 1541/1571 dw cmdsk2 ;* drive C 1541/1571 dw cmdsk3 ;* drive D 1541/1571 dw cmdsk4 ;* drive E shares drive A dw 0 ;* drive F dw 0 ;* drive G if EXTSYS dw @fdsd0 ;* drive H (external RS232) else dw 0 ;* drive H endif dw 0 ;* drive I dw 0 ;* drive J dw 0 ;* drive K dw 0 ;* drive L dw RMdsk ;* drive M Memory Disk (RAM disk) dw 0 ;* drive N dw 0 ;* drive O dw 0 ;* drive P if EXTSYS CSEG ; ; Extended Disk Parameter Headers (XPDHs) ; dw fd$write dw fd$read dw fd$login dw fd$init db 0 ; relative drive zero db 0 ; format type byte @fdsd0: dph sk128sssd,dpb$8$sssd ; ; DPB FOR 8 IBM 3740 format ( 243K ) ; dpb$8$sssd: dpb 128,26,77,1024,64,2 sk128sssd: skew 26,6,1 page ; ; send an illegial command, should get a period back, meaning ; that the the command was bad. at this point extrnal system ; is ready to receive a valid command. ; CSEG resync: mvi c,0dh call send$c call get cpi '.' jrnz resync mvi c,'O' call send$c mvi c,07 ; beep the bell call send$c call get ; should be a bell code cpi 07 rz call get jr resync ; ; CXDISK.ASM ; ; ; ; dseg fd$read: mvi a,10 sta error$count ; set retrys to 10 retry$read: lxi h,retry$read push h ; save retry address on the stack mvi a,'R' call set$up$dsk ; send command, track and sector read$loop: call get if banked call put$byte$de$bank ; save byte disk bank mov a,c else mov m,a endif inx h call do$sum jrnz read$loop call get lda check$sum cmp c jrnz dsk$error pop h ; remove retry address xra a ; A=0 (no errors) ; ; fd$init: fd$login: ret ; ; ; if banked cseg put$byte$de$bank: lda force$map ; read current MMU configuration stax d ; force to preconfig reg adr in DE mov m,c ; save C in proper bank sta force$map ; force the old bank back ret endif page ; ; ; dseg dsk$error: call resync lda error$count dcr a sta error$count rnz ; return to retry address inr a ; A=1 if hard error pop h ; remove retry address on error ret error$count: db 0 page ; ; ; dseg fd$write: mvi a,10 sta error$count ; set retrys to 10 retry$write: lxi h,retry$write push h mvi a,'W' call set$up$dsk ; send command, track and sector write$loop: if banked call get$byte$de$bank else mov c,m endif call send$c ; leaves sent char in A inx h call do$sum jrnz write$loop lda check$sum call send$a call get ora a ; A=0 if no errors jrnz dsk$error pop h ; remove error address ret ; A=0 (no errors) if banked cseg get$byte$de$bank: lda force$map ; read current MMU configuration stax d ; set current disk bank (in DE) mov c,m sta force$map ; write current MMU conf back ret endif page ; ; compute check sum and adjust byte count ; dseg do$sum: mov b,a lda check$sum ; get the current sum add b ; add in new byte sta check$sum ; save new sum lda count ; get byte count dcr a ; one less to get sta count ; save for later ret ; zero flag set if DONE check$sum: db 0 count: db 0 ; ; send the command, track and sector to the external system ; set count to 128 bytes, clear the checksum and set HL to ; the DMA address ; set$up$dsk: call send$a ; send the comand lda @trk call send$a ; send the track lda @sect call send$a ; send the sector xra a sta check$sum mvi a,80h sta count ; transfer 128 bytes lhld @dma ; HL = current DMA address if banked lxi d,bank$0 ; start by pointing to bank 0 lda @dbnk ; get the current disk I/O bank ora a ; is it set to bank 0 rz ; yes, return inx d ; no, point to bank 1 endif ret page ;========================================================== ; CHARACTOR INITILIZATION ROUTINES ;========================================================== ; ; ; dseg ; ; set external system com rate to 19.2 K baud ; ?int65: init$ext: lhld usart$adr mov b,h mov c,l inx b inx b ; point to command reg mvi a,cmd$init outp a inx b ; point to control reg mvi a,cntr$init$19200 ; baud rate equ 19200 outp a dcx b ; (02) dcx b ; (01) inp a ; read status dcx b ; (00) inp a ; read hung data ret page ;========================================================== ; CHARACTOR INPUT ROUTINES ;========================================================== ; ; ; dseg ?in65: characte input call ?ins65 ; check for character adv. jrz ?in65 ; loop if NOT lda key ; get the key code push psw ; save on stack xra a ; clear key sta key pop psw ; recover current key ret page ;========================================================== ; CHARACTER DEVICE INPUT STATUS ;========================================================== ; ; ; dseg ?ins65: ; character input status lda key ; is there already a key ora a jrnz ret$true ; yes, return true mvi a,'I' ; no, test if any typed call send$a call get ; get key ora a ; =0 if none rz ; return character not advaliable sta key ; was one, save in key ?outs65: ret$true: ori 0ffh ret key: db 0 page ;========================================================== ; CHARACTER DEVICE OUTPUT ;========================================================== ; the charactor to be output is in the C register ; ; ; dseg ?out65: ; character output mov a,c push psw mvi a,'O' call send$a pop psw call send$a ; jmp get ; fall thru to GET ;========================================================== ; EXTERNAL DEVICE LOW LEVEL DRIVERS ;========================================================== ; ; ; dseg get: call in$stat jrz get dcx b ; point to data reg (RxD) inp a mov c,a ret ; ; ; send$c: mov a,c send$a: push psw ; save the character to be output send$loop: call out$stat jrz send$loop pop psw dcx b : point to data register (TxD) outp a ret ; ; ; in$stat: lhld usart$adr mov b,h mov c,l inx b ; point to status register inp a ani rxrdy ret ; ; ; out$stat: lhld usart$adr mov b,h mov c,l inx b ; point to status register inp a ani txrdy ret else ;========================================================== ; CHARACTOR INITILIZATION ROUTINES ;========================================================== ; ; ; dseg ; ; set com rate to value in ?int$bd ; (may need to change rate if not supported) ?int65: init$ext: if use$6551 ; ; must gate 6551 to user port ; this is done by init'ing the out data to an input ; and then setting DTR ; lxi b,CIA2+data$dir$a inp a ori 100b ; make TxD bit (2) an input outp a endif lhld usart$adr mov b,h mov c,l inx b ; point to status reg outp a ; software reset (wr to stat reg) inx b ; point to Command register mvi a,cmd$init ; set DTR active outp a inx b ; point to Control register lda ?int$bd ; get 6551 baud rate ori 10h ; use baud rate generator outp a ; 1 stop (7=0), 8 bits (65=0) ret page ;========================================================== ; CHARACTOR INPUT ROUTINES ;========================================================== ; ; ; dseg ?in65: characte input call ?ins65 jrz ?in65 dcx b ; point to data reg inp a ret ;========================================================== ; CHARACTER DEVICE INPUT STATUS ;========================================================== ; ; ; dseg ?ins65: ; character input status lhld usart$adr mov b,h mov c,l inx b ; point to status register inp a ani rxrdy rz ori -1 ret ;========================================================== ; CHARACTER DEVICE OUTPUT ;========================================================== ; the charactor to be output is in the C register ; ; ; dseg ?out65: ; character output mov a,c push psw call ?outs65 jrz ?out65 pop psw dcx b ; point to data register outp a ret ;========================================================== ; CHARACTER DEVICE OUTPUT STATUS ;========================================================== ; ; ; dseg ?outs65: ; character input status lhld usart$adr mov b,h mov c,l inx b ; point to status register inp a ani txrdy rz ori -1 ret endif end to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> Th title 'Interrupt handler 29 Apr 86' maclib z80 maclib cxequ public ?sysint done$scan: equ 11110111b clear$TxD$bit: equ 10010111b ; 2nd byte of res 2,a set$TxD$bit: equ 11010111b ; 2nd byte of setb 2,a buf$end equ low(RxD$buffer+RxD$buf$size) page ; ; The DE register is not changed by the interrupt handler ; ; maximun of T states advaliable per interrupt ; DMA uses about 10 % (or ) leaving only ; interrupt vectoring use a few more. ; ; if both recv$state and send$state are in idle ; T states 209+82++ (191max,38min) = (482max,329min) ; ; ; if ether recv$state and send$state are active ; T states 209+++ (289max, 82min) = (498max,291min) ; CSEG ?sysint: push psw ;11 push b ;11 push h ;11 ; lxi b,CIA$1+int$ctrl ;10 inp a ;12 clear CIA$1 interrupts ; if not use$6551 lxi b,CIA2+data$a ;10 inp a ;12 out$rs232$cia equ $+1 setb 2,a ;8 this instruction gets modified outp a ;12 inr c ;4 point to data$b (C=1) inp a ;12 mov h,c ;4 set H=1 recv$state: call recv$idle ;17+(153max,54min) send$state: call send$idle ;17+(136max,28min) dcr h ;4 did H=1 ? lxi h,current$key$delay ;10 jnz skip$keyboard ;10 page ; ; T states 32 if not done ; T states 56+ if key scan done ; vector$key$state: dcr m ;11 jrnz exit$int ;7/12 lda int$rate ;13 mov m,a ;7 endif key$state: call key$scan$state ;17+(191max,38min) if not use$6551 db 21h ; lxi h,(mvi m,1) skip$keyboard: mvi m,1 ; endif exit$int: pop h pop b pop psw ei ret if not use$6551 RxD$count: db 0 ; number of bits left to receive TxD$count: db 0 ; number of bits left to transmit current$key$delay: db 1 page ; ; T states 52 start bit ; T states no start bit, que inactive ; T states no start bit, que active, DAV set ; T states no start bit, que active, DAV cleared ; recv$idle: rar ;4 jrnc set$test$start$bit ;7/(12+36) ;11+12+31=54 ; RxD$unque: ;(36)+12+(105) = 153 max jr test$que ;12 ; ; T states 31 no process required ; T states 91 que count adjusted (not empty) ; t states 105 que count adjusted (empty) ; test$que: lda RS232$status ;13 no processing req if QUE ani 00100000b ;7 bit (5) is clear rz ;5/11 mvi a,que$to$data-test$que ;7 sta RxD$unque+1 ;13 set next sub state lxi h,RxD$buf$get ;10 inr m ;11 mov a,m ;7 cpi buf$end ;7 rnz ;5/11 mvi m,low(RxD$buffer) ;10 ret ;10 ; set$test$start$bit: lxi h,test$start$bit ;10 shld recv$state+1 ;16 ret ;10 page ; ; T states 28 if DAV still set ; T states 89 to move char from que to recv$data ; que$to$data: lda RS232$status ;13 rrc ;4 rc ;5/11 lxi h,RxD$buf$get ;10 mov l,m ;7 mov a,m ;7 sta recv$data ;13 mvi a,adjust$cnt-test$que ;7 sta RxD$unque+1 ;13 set next sub state ret ;10 ; ; T states 82 count not zero ; T states 99 count becomes zero ; adjust$cnt: xra a ;4 lxi h,RxD$buf$count ;10 dcr m ;11 mvi l,low(RS232$status) ;7 setb 0,m ;15 set DAV flag jrnz adj$cont ;7/12 res 5,m ;15 que empty turn QUE bit(5) off mvi a,que$empty-test$que ;7 adj$cont: sta RxD$unque+1 ;13 ret ;10 ; ; T states 52/94 ; que$empty: xra a ;4 offset of zero for JR sta RxD$unque+1 ;13 (to get to test$que) lxi h,xon$xoff$flag ;10 mvi a,XON ;7 cmp m ;7 rz ;5/11 mov m,a ;7 mvi a,send$x-send$norm ;7 sta send$idle+1 ;13 ret ;10 page ; ; test for false start ; ; T states 72 if valid start ; T states 52 if false start ; test$start$bit: rar ;4 jrc set$recv$idle ;7/(12+36) RxD in carry bit lxi h,RS232$status ;10 setb 1,m ;15 set receiving data flag lxi h,start$idle$1 ;10 shld recv$state+1 ;16 ret ;10 ; ; T states 36 ; set$recv$idle: lxi h,recv$idle ;10 shld recv$state+1 ;16 ret ;10 ; ; T states 93 ; start$idle$1: xra a ;4 sta recv$bit+2 ;13 lda XxD$config ;13 ani 1 ;7 adi 7 ;7 sta RxD$count ;13 lxi h,que$full$test ;10 shld recv$state+1 ;16 ret ;10 page ; ; T states 57 RxD buffer not full ; T states 117 RxD buffer full (send XOFF) ; T states 86 RxD buffer full (XOFF sent already) ; que$full$test: lxi h,recv$bit ;10 shld recv$state+1 ;16 lda RxD$buf$count ;13 cpi RxD$buf$size-16 ;7 rc ;5/11 lxi h,xon$xoff$flag ;10 mvi a,XOFF ;7 cmp m ;7 rz ;5/11 mov m,a ;7 set mode to send Xoff mvi a,send$x-send$norm ;7 sta send$idle+1 ;13 ret ;10 ; ; T states 64 ; recv$bit: rar ;4 mvi a,00 ;7 RxD in carry bit rar ;4 move data bit into MSB sta recv$bit+2 ;13 lxi h,recv$bit$done$test ;10 shld recv$state+1 ;16 ret ;10 ; ; T states 69 if bits still remaining ; T states ; recv$bit$done$test: lxi h,RxD$count ;10 dcr m ;11 jrnz enter$recv$bit$idle ;7/(12+36) lda XxD$config ;13 rlc ;4 lxi h,enter$RxD$stop ;10 jrnc do$test$stop ;7/12 lxi h,enter$RxD$parity ;10 do$test$stop: shld recv$state+1 ;16 ani 1*2 ;7 A=0 if 7 bits else 8 bits lda recv$bit+2 ;13 jrnz done$adj ;7/12 rrc ;4 done$adj: sta RxD$data ;13 ret ;10 ; ; T states 36 ; enter$recv$bit$idle: lxi h,recv$bit$idle ;10 shld recv$state+1 ;16 ret ;10 ; ; T states 36+(28/105) ; recv$bit$idle: lxi h,recv$bit ;10 shld recv$state+1 ;16 jmp RxD$unque ;10 page ; ; T states 36+(28/105) ; enter$RxD$parity: lxi h,test$RxD$parity ;10 shld recv$state+1 ;16 jmp RxD$unque ;10 ; ; T states bit hi ; T states bit low ; test$RxD$parity: lxi h,RxD$parity$idle ;10 RxD data bit in carry shld recv$state+1 ;16 rar ;4 lda XxD$config ;13 jrc RxD$parity$hi ;7/12 rlc ;4 rlc ;4 mark space mode ? jrnc test$parity$space ;7/(12+15/46) yes, go test it rlc ;4 get odd even mode jr test$odd$even ;12+35/54 ; test$parity$space: ;15/ rlc ;4 rnc ;5/11 jr parity$error ;12+25 ; test$parity$mark: ;15/ rlc ;4 rc ;5/11 jr parity$error ;12+25 page ; RxD$parity$hi: ;4 rlc ;4 rlc ;4 mark/space mode ? jrnc test$parity$mark ;7/12 yes, go test it rlc ;4 get odd/even flag cmc ;4 toggle it test$odd$even: ;35/ lda recv$bit+2 ;13 aci 0 ;7 ana a ;4 rpe ;5/11 parity$error: ;35 lxi h,RS232$status ;10 setb 4,m ;15 set parity error ret ;10 ; ; T states 36 ; RxD$parity$idle: lxi h,enter$RxD$stop ;10 shld recv$state+1 ;16 jmp RxD$unque ;10 page ; ; T states 90 if que not in use and DAV is cleared ; T states 149/151 if data placed in que ; enter$RxD$stop: lda RS232$status ;13 ani 00100001b ;7 DAV set or data in que? jrnz place$in$que ;7/12 yes, place new char in que lda RxD$data ;13 no, place char in data reg. sta recv$data ;13 lxi h,test$RxD$stop$dav ;10 shld recv$state+1 ;16 ret ;10 ; place$in$que: ;116/118 lxi h,RxD$buf$count ;10 inr m ;11 inr l ;4 mov a,m ;7 inr a ;4 cpi buf$end ;7 jrnz put$buf$ok ;7/12 mvi a,low(RxD$buffer) ;7 put$buf$ok: mov m,a ;7 mov l,a ;4 RxD$data equ $+1 mvi a,00 ;7 mov m,a ;7 lxi h,test$RxD$stop$que ;10 shld recv$state+1 ;16 ret page ; ; T states no errors ; T states framing error ; test$RxD$stop$que: rar ;4 mvi a,00100000b ;7 jmp test$RxD$cont ;10 ; ; T states no errors ; T states framing error ; test$RxD$stop$dav: rar ;4 mvi a,00000001b ;7 test$RxD$cont: jrc good$RxD$stop ;7/12 ori 00001000b ;7 set framing error good$RxD$stop: lxi h,RS232$status ;10 ora m ;7 ani 11111101b ;7 clear recv active flag bit mov m,a ;7 lxi h,recv$idle ;10 shld recv$state+1 ;16 ret ;10 page ;* ;* T states stay in idle state ;* T states exit idle state (recv buffer not full) ;* T states exit idle state (recv buffer full) ;* send$idle: jr send$norm ;12 send$norm: lda RS232$status ;13 rlc ;4 rnc ;5/11 lxi h,start$send$1 ;10 shld send$state+1 ;16 mvi a,clear$TxD$bit ;7 sta out$rs232$cia ;13 send the start bit ret ;10 ; ; T states 12+118 ; send$x: xon$xoff$flag equ $+1 mvi a,XON ;7 sta send$bits+1 ;13 xra a ;4 sta send$idle+1 ;13 mvi a,clear$TxD$bit ;7 sta out$rs232$cia ;13 send the start bit lxi h,RS232$status ;10 setb 6,m ;15 flag send bussy lxi h,start$xon$xoff ;10 shld send$state+1 ;16 ret ;10 page ; ; T states 107 ; start$send$1: lda xmit$data ;13 sta send$bits+1 ;13 lxi h,RS232$status ;10 mov a,m ;7 xri 0C0h ;7 clear bit 7 and set bit 6 mov m,a ;7 start$xon$xoff: lda XxD$config ;13 ani 1 ;7 adi 7 ;7 sta TxD$count ;13 enter$send$bits: lxi h,start$bit$idle ;10 shld send$state+1 ;16 ret ;10 ; ; T states 36 ; start$bit$idle: lxi h,send$bits ;10 shld send$state+1 ;16 ret ;10 ; ; T states 94 data bit low ; T states 92 data bit hi ; send$bits: mvi a,00 ;7 rrc ;4 sta send$bits+1 ;13 lxi h,count$TxD ;10 shld send$state+1 ;16 send$TxD: ;42/44 mvi a,set$TxD$bit ;7 jrc send$hi$bit ;7/12 mvi a,clear$TxD$bit ;7 send$hi$bit: sta out$rs232$cia ;13 ret ;10 ; ; T states if more data bits to send ; T states if done sending bits ; count$TxD: lxi h,TxD$count ;10 dcr m ;11 jrnz enter$send$bits ;7/12 lxi h,TxD$parity$wait ;10 shld send$state+1 ;16 ret ;10 page ; ; T states 36 ; TxD$parity$wait: lxi h,TxD$parity ;10 shld send$state+1 ;16 ret ;10 ; ; ; T states 85 if no parity ; T states 124 if mark parity ; T states 126 if space parity ; T states 136 if even parity ; T states 129 if odd parity ; TxD$parity: lda XxD$config ;13 rlc ;4 jrnc TxD$stop ;7/(12+56) lxi h,TxD$parity$idle$1 ;10 shld send$state+1 ;16 rlc ;4 jrnc send$mark$space ;7/(12+16+42/44) rlc ;4 lda send$bits+1 ;13 aci 0 ;7 ana a ;4 mvi a,set$TxD$bit ;7 jpo send$TxD$parity ;10 mvi a,clear$TxD$bit ;7 send$TxD$parity: sta out$rs232$cia ;13 ret ;10 ; send$mark$space: rlc ;4 jr send$TxD ;12+42/44 ; ; T states 36 ; TxD$parity$idle$1: lxi h,TxD$parity$idle$2 ;10 shld send$state+1 ;16 ret ;10 ; ; T states 36 ; TxD$parity$idle$2: lxi h,TxD$stop ;10 shld send$state+1 ;16 ret ;10 page ; ; T states 103/101 ; TxD$stop: lxi h,TxD$stop$idle ;10 shld send$state+1 ;16 mvi a,set$TxD$bit ;7 sta out$rs232$cia ;13 lda XxD$config ;13 ani 2 ;7 jrnz one$stop$bit ;7/12 mvi a,5 ;7 one$stop$bit: inx h ;6 mov m,a ;7 ret ;10 ; ; T states 35/90 ; TxD$stop$idle: mvi a,00 ;7 dcr a ;4 sta TxD$stop$idle+1 ;13 rnz ;5/11 lxi h,RS232$status ;10 res 6,m ;15 lxi h,send$idle ;10 shld send$state+1 ;16 ret ;10 endif page ; ; ; Key$Scan$State: jr scan$CIA ;12 ; ; T states no new key down ; T states state change ; T states new key down ; scan$CIA: stc ;4 mvi a,11111110b ;7 data field updated by code lxi b,key$row ;10 outp a ;12 cpi 11111111b ;7 jrz extra$3 ;7/12 carry=0 if A=11111111 ral ;4 sta scan$CIA+1+1 ;13 lxi h,key$scan$tbl ;10 get current new table pointer inr c ;4 point to KEY$COL (input) jmp cont$read ;10 ; extra$3: ral ;4 sta scan$CIA+1+1 ;13 mvi a,scan$VIC-scan$CIA ;7 sta Key$Scan$State+1 ;13 ret ;10 page ; ; T states no new key and no state change ; scan$VIC: mvi a,11101110b ;7 lxi h,key$scan$tbl ;10 get current new table pointer lxi b,vic$key$row ;10 outp a ;12 rlc ;4 sta scan$VIC+1 ;13 jrnc normal$8 ;7/12 lxi b,key$col ;10 cont$read: inp a ;12 0FFh if no key down inr m ;11 mov l,m ;7 mov b,m ;7 get old value in B mov m,a ;7 save new value xra b ;4 get differances ana b ;4 test for only new keys down rz ;5/11 sta matrix$byte ;13 lxi h,key$found ;10 shld key$state+1 ;16 ret ;10 ; ; normal$8: ; mvi a,scan$CIA-scan$CIA ;7 xra a ;4 sta Key$Scan$State+1 ;13 mov m,l ;7 reset current table pointer lxi h,Key$Repeat$State ;10 shld key$state+1 ;16 ret ;10 page ; ; T states 48 repeat not active ; T states 124 testing repeat (key realeased) ; T states 110 testing repeat (not found) ; T states 109 testing repeat (found) ; Key$Repeat$State: lxi h,flash$wait ;10 shld key$state+1 ;16 repeat$count equ $+1 mvi a,00 ;7 ora a ;4 rz ;5/11 lxi h,repeat$count ;10 dcr a ;4 yes, test for repeat yet jrnz not$repeat$yet ;7/(12+(42/56)) ; ; the following 4 lines of code may NOT be changed. ; CONF.COM looks for them to change the repeat rate. ; also looks for RET ; MVI A,xx ; STA xxxx (see set$key$parm) ; mvi m,3 ;10 lxi h,save$key ;10 shld key$state+1 ;16 ret ;10 ; not$repeat$yet: ;42/56 mov m,a ;7 matrix$pos equ $+1 lda Key$scan$tbl ;13 repeat$mask equ $+1 mvi b,00 ;7 ana b ;4 key still down? (A=0) rz ;5/11 yes, exit for now mvi m,0 ;10 ret ;10 page ; ; T states 101 flash ; T states 72 no flash ; flash$wait: mvi a,01 ;7 dcr a ;4 sta flash$wait+1 ;13 jrnz no$flash ;7/(13+36) mvi a,5 ;7 sta flash$wait+1 ;13 lxi h,flash ;10 shld key$state+1 ;16 ret ;10 ;* ;* ;* T states 135 if cursor off screen ;* T states 119 if cursor on screen ;* flash: lda force$map ;13 sta bank$0 ;13 mov b,a ;4 ; ; toggle 40 column screen cursor on/off ; lhld flash$pos ;16 xra a ;4 clear A ora h ;4 return if H=0 jrz exit$flash ;7/12 mov a,m ;7 xri 80h ;7 mov m,a ;7 exit$flash: mov a,b ;4 sta force$map ;13 no$flash: lxi h,Key$Scan$State ;10 shld key$state+1 ;16 ret ;10 page ; ; ; key$found: ;148/138/157/147/166/156/161/167 matrix$byte equ $+1 mvi b,00 ;7 mov a,b ;4 ani 11110000b ;7 jz check$low$4 ;10+(138/128/133/139) ani 11000000b ;7 jrz check$5$and$4 ;7/(12+(110/100)) ani 10000000b ;7 mvi c,6 ;7 jrnz is$add$1 ;7/(12+70) mvi a,01000000b ;7 jr is$common ;12+66 ; check$5$and$4: ;110/100 mov a,b ;4 ani 00100000b ;7 mvi c,4 ;7 jrnz is$add$1 ;7/(12+70) mvi a,00010000b ;7 jr is$common ;12+66 ; ; check$low$4: ;138/128/133/139 mov a,b ;4 ani 00001111b ;7 jrz exit$found ;7/12 ani 00001100b ;7 jrz check$1$and$0 ;7/12+(96/102) ani 00001000b ;7 mvi c,2 ;7 jrnz is$add$1 ;7/(12+70) mvi a,00000100b ;7 jr is$common ;12+66 ; check$1$and$0: ; mov a,b ;4 ani 00000010b ;7 mvi c,0 ;7 jrnz is$add$1 ;7/(12+70) inr a ;4 set A=1 jr is$common ;12+66 ; ; is$add$1: ;70 inr c ;4 is$common: ;66 sta mask$value ;13 mov a,c ;4 sta bit$value ;13 lxi h,key$found$2 ;10 shld key$state+1 ;16 ret ;10 ; exit$found: lxi h,Key$Scan$state ;10 shld key$state+1 ;16 ret ;10 page ; ; T states ; key$found$2: lxi h,matrix$byte ;10 mask$value equ $+1 mvi a,00 ;7 xra m ;7 clear current bit mov m,a ;7 bit$value equ $+1 mvi b,00 ;7 lxi h,key$scan$tbl ;10 get the pointer mov a,m ;7 sub l ;4 remove the bias dcr a ;4 then one extra (pointer) add a ;4 add a ;4 add a ;4 shift left 3 bits add b ;4 add in bit position sta key$code ;13 save as the key code lxi h,remove$special$keys ;10 shld key$state+1 ;16 ret ;10 page ; ; T states if not a shift of control key ; T states 68/82/96 if cntr / rt_shift / lf_shift ; remove$special$keys: lxi h,key$found ;10 lda key$code ;13 cpi 38h+2 ;7 control key pressed ? jrz bad$key ;7/12 cpi 30h+4 ;7 jrz bad$key ;7/12 cpi 08h+7 ;7 jrz bad$key ;7/12 lxi h,set$key$parm ;10 bad$key: shld key$state+1 ;16 ret ;10 ; ; T states ; ; do not change the next 2 lines. CONF uses them to ; the set repeat rate. (also RET above here) ; set$key$parm: mvi a,8 ;7 sta repeat$count ;13 number of counts for repeat lda key$scan$tbl ;13 sta matrix$pos ;13 lda mask$value ;13 sta repeat$mask ;13 lxi h,build$cntr$byte ;10 shld key$state+1 ;16 ret ;10 ; ; T states ; build$cntr$byte: lda key$scan$tbl+1+7 ;13 get control byte row cma ;4 ani 04h ;7 test control key bit jrz not$control ;7/12 mvi a,7 ;7 not$control: mov b,a ;4 lda key$scan$tbl+1+6 ;13 get rigth shift byte row cma ;4 ani 10h ;7 test right key bit ora b ;4 mov b,a ;4 lda key$scan$tbl+1+1 ;13 get left shift byte row cma ;4 ani 80h ;7 test left key bit ora b ;4 mov b,a ;4 ani 90h ;7 either shift key down? mov a,b ;4 jrz no$shift ;7/12 no, jump ori 2 ;7 yes, set shift control bit no$shift: sta ctrl$byte ;13 lxi h,save$key ;10 shld key$state+1 ;16 ret ;10 page ; ; ; NOTE: character buffer MUST be on one page ; (and have even number of bytes) ; ; buffer is FULL when data at put pointer does not equal 0ffh ; insert new character at (put pointer) ; and character control byte at (put pointer)+1 ; ; T states 38 if buffer is full ; T states 146/148 ; save$key: lhld key$put$ptr ;16 get put pointer mov a,m ;7 get byte from buffer inr a ;4 room in buffer? (-1 if so) rnz ;5/11 no, wait for room in buffer key$code equ $+1 mvi m,00 ;10 get matrix position inr l ;4 ctrl$byte equ $+1 mvi a,00 ;7 mov m,a ;7 inr l ;4 mov a,l ;4 cpi low(key$buffer+key$buf$size) ;7 jrnz put$ptr$ok ;7/12 mvi a,low(key$buffer) ;7 put$ptr$ok: sta key$put$ptr ;13 adjust the low byte of the put ptr lxi h,Key$tick ;10 shld key$state+1 ;16 ret ;10 ; ; T states ; key$tick: lxi b,sid+24 ;10 lda tick$vol ;13 outp a ;12 mvi c,low(sid+11) ;7 mvi a,80h ;7 outp a ;12 inr a ;4 outp a ;12 lxi h,key$scan$state ;10 shld key$state+1 ;16 ret ;10 page ; ;_____ _____ _____ _____ _____ _____ _____ _____ _____ _____ __________ ; | | | | | | | | | | | | | ; | S | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | P | stop | ; |_____|_____|_____|_____|_____|_____|_____|_____|_____|_____| | |_ ; ; ; Reciever State Machine ; ; ;_____ _____ _____ _____ _____ _____ _____ _____ _____ _____ __________ ; | | | | | | | | | | | | | ; | S | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | P | stop | ; |_____|_____|_____|_____|_____|_____|_____|_____|_____|_____| | |_ ; ; ; Transmitter State Machine (TSM) ; ; ; ; Keyboard Scan State Machine (KSSM) ; r inp a ani txrdy rz ori -1 ret endif end to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> Th ; title 'C128 BIOS, main I/O and sys functions 28 Apr 86' ; ; This module contains CXIO,CXINIT,CXMOVE and CXTIME. ; maclib cpm3 maclib z80 maclib cxequ maclib modebaud public ?init,?ldccp,?rlccp public ?user,?di$int extrn ?sysint bdos equ 5 extrn @civec,@covec,@aivec,@aovec,@lovec extrn ?bnksl public ?cinit,?ci,?co,?cist,?cost public @ctbl extrn ?kyscn ; Utility routines in standard BIOS extrn ?wboot ; warm boot vector extrn ?pmsg ; print message @ up to 00 ; saves & extrn ?pdec ; print binary number in from 0 to 99. extrn ?pderr ; print BIOS disk error header extrn ?conin,?cono ; con in and out extrn ?const ; get console status extrn @hour,@min,@sec,@date,?bnksl public ?time page ; ; keyboard scanning routine ; extrn ?get$key,?int$cia extrn Fx$V$tbl ; ; links to 80 column display ; extrn ?out80,?int80 extrn ?out40,?int40 extrn ?pt$i$1101,?pt$o$1,?pt$o$2 extrn ?convt ; extrn ?pt$s$1101 ; ; bios8502 function routines ; public ?fun65 ; ; ; public ?intbd extrn ?int65,?in65,?ins65,?out65,?outs65 ; cseg ;trace: ; xthl ; save hl on stack ; push psw ; call ?pmsg ; DE and BC saved by ?pmsg ; pop psw ; xthl ; ret ; ; CSEG ;disp$A: ; push psw ;;;test ; ani 0fh ;;;test ; adi 90h ;;;test ; daa ;;;test ; aci 40h ;;;test ; daa ;;;test ; sta low$test ;;;test ; pop psw ;;;test ; rar ;;;test ; rar ;;;test ; rar ;;;test ; rar ;;;test ; ani 0fh ;;;test ; adi 90h ;;;test ; daa ;;;test ; aci 40h ;;;test ; daa ;;;test ; sta hi$test ;;;test ; call trace ;;;test ;hi$test: ;;;test ; db 31 ;;;test ;low$test: ;;;test ; db 31 ;;;test ; db ' ' ;;;test ; db 0 ;;;test ; ret ;;;test ; page DSEG ?fun65: sta vic$cmd ; save the command passed in A if not use$6551 fun$di$wait: lda RS232$status ani 11000010b ; char to Xmit, Xmiting or receiving ? jrnz fun$di$wait ; yes, wait for int to clean up endif di lda force$map ; get current MMU configuration push psw ; save it sta io$0 ; make I/O 0 current lxi d,1 ; D=0, E=1 if use$fast lxi b,VIC$speed inp a sta sys$speed outp d ; set slow mode (1 2 MHz Z80) endif lxi b,page$1$h outp d dcr c outp e ; page 1, 0-1 dcr c outp d dcr c outp d ; page 0, 0-0 call enable$6502+6 ; go run the 8502 mvi c,low(page$1$h) outp e dcr c outp e ; page 1, 1-1 dcr c outp e dcr c outp d ; page 0, 1-0 if use$fast lxi b,VIC$speed lda sys$speed ; get desired system speed outp a ; set speed (2 or 4 MHz Z80) endif pop psw ; recover the MMU config. sta force$map ; restore it ei ; turn interrupts back on lda vic$data ; get command results ora a ; set the zero flag if A=0 ret ?di$int: if not use$6551 push psw di$int$1: lda RS232$status ; character to Xmit or currently ani 11000010b ; ..transmitting or receiving ? jrnz di$int$1 ; yes, wait for int to clean up pop psw endif di ret page ; ; set up the MMU for CP/M Plus ; DSEG ; init done from banked memory ?init: mvi a,3eh ; force MMU into I/O space sta force$map ; lxi h,mmu$table+11-1 ; table of 11 values lxi b,mmu$start+11-1 ; to to MMU registers mvi d,11 ; move all 11 bytes to the MMU init$mmu$loop: mov a,m outp a dcx h dcx b dcr d jrnz init$mmu$loop mvi a,1 ; enable track and sector status sta stat$enable ; on the status line ; mvi a,1 ; no parity, 8 bits, 1 stop bit sta XxD$config ; if use$6551 lxi h,int$6551 else lxi h,usart endif shld usart$adr lxi h,?convt shld prt$conv$1 shld prt$conv$2 lxi h,Fx$V$tbl shld key$FX$function ; ; install I/O assignments ; lxi h,4000h+2000h ; 80 and 40 column drivers shld @covec mvi h,80h shld @civec ; assign console input to keys mvi h,10h shld @lovec ; assign printer to LPT: mvi h,00h shld @aivec shld @aovec ; assign rdr/pun port page ; ; print sign on message ; call prt$msg ; print signon message db 'Z'-'@' ; initialize screen pointers db esc,esc,esc db purple+50h ; set character color db esc,esc,esc db black+60h ; set background (BG) color db esc,esc,esc db brown+70h ; set border color db 'Z'-'@' ; home and clear screen (to BG color) db lf,lf,lf if use$fast db 'Fast ' endif if use$6551 db '/w 6551 ' endif db 'CP/M 3.0' if not banked db ' Non-Banked' endif db ' On the Commodore 128 ' date warning db cr,lf db ' ',0 ; ; set CONOUT driver to correct screen ; lxi h,4000h ; 80 column screen vector call read$d505 ral jrnc set$screen mvi a,'4' sta screen$num mvi h,20h ; 40 column screen vector set$screen: call prt$msg ; HL saved screen$num: db '80 column display',cr,lf,lf,lf,lf,0 shld @covec ; assign console output to CRT: (40/80) page ; ; mvi a,-1 ; set block move to NORMAL mode sta source$bnk ; ; install mode 2 page vectors ; mvi a,JMP sta INT$vector ; install a JMP at vector location lxi h,?sysint shld INT$vector+1 ; install int$handler adr ; ; A software fix is required for the lack of hardware to force the ; LSB of the INT vector to 0. If the bus floats INT VECT could be ; read as 0FFh; thus ADRh=I (I=0FCh) ADRl=FF for first read, and ; ADRh=I+1 ADRl=00 for second, to ensure that control is retained ; 0FD00h will also have FDh in it. ; lxi h,int$block ; FC00h lxi d,int$block+1 ; FC01h lxi b,256-1+1 ; interrupt pointer block mvi m,INT$vector/256 ; high and low are equal (FD) ldir mvi a,INT$block/256 stai ; set interrupt page pointer im2 ; enable mode 2 interrupts page ; ; mvi a,vicinit ; null command just to setup BIOS8502 call ?fun65 ; ; ; lda sys$freq ; 0=60Hz 0FFh=50Hz ani 80h ; 0=60Hz 080h=50Hz mov l,a ; save in L lxi b,cia$1+0eh ; point to CRA inp a ; get old config ani 7fh ; clear freq bit ora l ; add in new freq bit outp a ; set new config mvi c,8 ; start RTC outp a lxi h,date$hex shld @date ; set date to system data ; ; setup the sound variables ; lhld key$tbl lxi d,58*4 dad d mov e,m inx h mov d,m inx h xchg shld sound1 ; H=SID reg 24, L=SID reg 5 xchg mov e,m inx h mov d,m xchg shld sound2 ; H=SID reg 6, L=SID reg 1 lxi h,9 dad d mov e,m inx h mov d,m xchg shld sound3 ; H=SID reg 4 then L=SID reg 4 ; ; set-up key click sound registers ; lxi b,sid+7 lxi h,0040h outp l ; (sid+7)=40h inr c outp l ; (sid+8)=40h mvi c,low(sid+12) outp h ; (sid+12)=0 Attack=2ms, Decay=6ms inr c outp h ; (sid+13)=0 Sustain=0, Release=6ms mvi a,6 sta tick$vol ; set keyclick volumn level ; ; set up interrupts for key scan (not software usart) ; if use$6551 lxi d,2273 ; int at 150 BAUD rate lxi b,CIA1+timer$b$low ; outp e ; inr c ; point to timer$b$high outp d ; mvi a,11h ; mvi c,CIA$ctrl$b ; turn on timer B outp a ; lxi b,CIA2+data$b ; setup user port for RS232 inp a ; get old data ori 6 ; set CTS and DTR outp a ; update it endif ret mmu$table: mmu$tbl$M page ; ; ; CSEG prt$msg: xthl call ?pmsg xthl ret ; ; placed in common memory to keep IO from stepping on this code ; always called from bank 0 ; CSEG read$d505: sta io$0 ; enable MMU (not RAM) lxi b,0d505h inp a ; read 40/80 column screen sta bank$0 ; re-enable RAM ret page ; ; ; DSEG if not use$6551 init$RS232: di xra a sta RS232$status lxi h,RxD$buf$count ; clear the count mvi m,0 inr l ; point to RxD$buf$put mvi m,low(RxD$buffer) inr l ; point to RxD$buf$get mvi m,low(RxD$buffer) lxi h,NTSC$baud$table lda sys$freq ora a jrz use$NTSC lxi h,PAL$baud$table use$NTSC: lda RS232$baud cpi baud$1200 ; baud rate less then 1200 baud jrc baud$ok ; yes, go set it mvi a,baud$1200 ; no, 1200 baud is the max sta RS232$baud ; (change to 1200 baud) baud$ok: mov e,a mvi d,0 dad d ; +1X dad d ; +1X dad d ; +1X = +3X mov e,m inx h mov d,m inx h ; mov a,m ; get rate # sta int$rate ; lxi b,CIA1+timer$b$low ; outp e ; inr c ; point to timer$b$high outp d ; mvi a,11h ; mvi c,CIA$ctrl$b ; turn on timer B outp a ; lxi b,CIA2+data$b ; setup user port for RS232 inp a ; get old data ori 6 ; set CTS and DTR outp a ; update it ei ret page ; ; NTSC rates (1.02273 MHz) ; NTSC$baud$table: dw 6818 ; no baud rate (6666.47) db 1 dw 6818 ; 50 6666.7us (6666.47) db 1 dw 4545 ; 75 4444.4us (4443.99) db 1 dw 3099 ; 110 3030.3us (3030.13) db 1 dw 2544 ; 134 2487.6us (2487.46) db 1 dw 2273 ; 150 2222.2us (2222.48) db 2 dw 1136 ; 300 1111.1us (1110.75) db 3 dw 568 ; 600 555.6us ( 555.38) db 6 dw 284 ; 1200 277.8us ( 277.69) db 12 ; ; PAL rates (0.98525 MHz) ; PAL$baud$table: dw 6568 ; no baud rate (6666.32) db 1 dw 6568 ; 50 6666.7us (6666.32) db 1 dw 4379 ; 75 4444.4us (4444.56) db 1 dw 2986 ; 110 3030.3us (3030.70) db 1 dw 2451 ; 134 2487.6us (2487.69) db 1 dw 2189 ; 150 2222.2us (2221.77) db 2 dw 1095 ; 300 1111.1us (1111.39) 300*3 db 3 dw 547 ; 600 555.6us ( 555.19) 600*3 db 6 dw 274 ; 1200 277.8us ( 278.10) 1200*3 db 12 page ; ; ; out$RS232: call out$st$RS232 jrz out$RS232 mov a,c sta xmit$data ; get character to send in A lxi h,RS232$status setb 7,m ; set Xmit request bit ret ; ; ; out$st$RS232: lda RS232$status ani 80h ; bit 8 set if busy xri 80h ; A cleared if busy (=80h if not) rz ori 0ffh ; A=ff if ready (not busy) ret ; ; ; in$RS232: call in$st$RS232 jrz in$RS232 lda recv$data lxi h,RS232$status res 0,m ret ; ; ; in$st$RS232: lda RS232$status ani 1 rz ori 0ffh ; set data ready (-1) ret endif page ; ; this routine is used to provide the user with a method ; of interfacing with low level system functions ; CSEG ; ; input: ; all registers except HL and A are passed to function ; ; output: ; all resisters from function are preserved ; ?user: shld user$hl$temp xchg shld de$temp ; save DE for called function mov e,a ; place function number in E mvi a,num$user$fun-1 ; last legal function number call vector ; function usr$tb: dw read$mem$0 ; 0 dw write$mem$0 ; 1 dw ?kyscn ; 2 dw do$rom$fun ; 3 (L=function #) dw do$6502$fun ; 4 (L=function #) dw read$d505 ; 5 returns MMU reg in A dw code$error ; not 0 to 5 ret version number in HL num$user$fun equ ($-usr$tb)/2 page ; ; address in DE is read and returned in C ; A=0 if no error ; DSEG read$mem$0: ldax d ; read location addressed by DE mov c,a ; value returned in C xra a ; clear error flag ret ; ; address in DE is written to with value in C ; A=0 if no errors ; write$mem$0: mvi a,-1 ; get error flag and 0ffh value cmp d ; do not allow write from FF00 to FFFF ; this is 8502 space, MMU direct reg. rz mov a,d cpi 10h ; do not allow write from 0000 to 0FFF ; this is ROM space mvi a,-1 ; get error flag rc ; return if 00h to 0fh mov a,c stax d xra a ; clear error flag ret page ; ; This is the function code entry point for direct execution ; of driver functions. If the MSB of the function number is ; set, the 40 column driver is used; else the 80 column drive ; is used. ; do$rom$fun: lhld user$hl$temp ; get HL (L=fun #) mvi a,7eh ; only allow even functions ana l cpi 79h jrc no$hl$req lhld @dma ; HL will be passed in @dma by push h ; ..the user no$hl$req: mov l,a rst 5 ; call rom functon (RCALL) L=fun # ret ; mvi a,7eh ; only allow even functions ; ana l ; sta no$hl$req+1 ; cpi 79h ; jrc no$hl$req ; lhld @dma ; HL will be passed in @dma by ; push h ; ..the user ;no$hl$req: ; will be changed to RCALL xx RET for next release (ROM FN 7A, 7C ; and 7E will not function with current code, they expect ; a return address on the stack ; ; RJMP 5Eh ; unused function, real fun# installed ; ..above do$6502$fun: lhld user$hl$temp mov a,l jmp ?fun65 ; ; ; code$error: lxi h,date$hex mvi a,-1 ret page ; ; ; CSEG ?rlccp: lxi h,ccp$buffer lxi b,0c80h load$ccp: sta bank$0 mov a,m sta bank$1 lxi d,-ccp$buffer+100h dad d mov m,a lxi d,ccp$buffer-100h+1 dad d dcx b mov a,b ora c jrnz load$ccp ret page ; ; ; CSEG ?ldccp: xra a sta ccp$fcb+15 ; zero extent lxi h,0 shld fcb$nr ; start at beginning of file lxi d,ccp$fcb call open ; open file containing CCP inr a jrz no$CCP ; error if no file... lxi d,0100h call setdma ; start of TPA lxi d,128 call setmulti ; allow up to 16K bytes lxi d,ccp$fcb call read lxi h,0100h lxi b,0c80h lda force$map push psw ; ; save$ccp: sta bank$1 mov a,m sta bank$0 lxi d,ccp$buffer-100h dad d mov m,a lxi d,-ccp$buffer+100h+1 dad d dcx b mov a,b ora c jrnz save$ccp pop psw sta force$map ret page ; ; The following code does not work with the NEW MMU ; ;?ldccp: ; xra a ; sta ccp$fcb+15 ; zero extent ; lxi h,0 ; shld fcb$nr ; start at beginning of file ; lxi d,ccp$fcb ; call open ; open file containing CCP ; inr a ; ;; trace jz below should be jrz ; jz no$CCP ; error if no file... ; ; lda fcb$rc ; get the record count ; sta ccp$count ; save for later ; lxi d,0100h ; call setdma ; start of TPA ; lxi d,128 ; call setmulti ; allow up to 16K bytes ; lxi d,ccp$fcb ; call read ; ; lxi d,1f0h ; point to buffer ; ; bank 1, page F0 ;; lxi h,101h ; point to CCP (in TPA) ; ; bank 1, page 01 ; mov h,d ; mov l,d ; jr save$ccp ; ; ; ; ;?rlccp: ; lda ccp$count ; ; sui 30 ; we can only save 30 records ; jp ?ldccp ; ; lxi h,1F0h ; point to buffer ; ; bank 1, page F0 ;; lxi d,101h ; point to TPA space ; ; bank 1, page 01 ; mov d,h ; mov e,h ; ;save$ccp: ; mvi b,15 ; number of pages in buffer ;ccp$move$loop: ; push h ; push d ; push b ; call do$move$0$to$1 ; pop b ; pop d ; pop h ; inx h ; inx d ; djnz ccp$move$loop ; ; ret ; ; ;do$move$0$to$1: ; call set$0$and$1 ; call move$0$to$1 ; lxi h,100h ; bank 1 page 0 ;; lxi d,101h ; bank 1 page 1 ; mov d,h ; mov e,h ;; ;; ;; ;set$0$and$1: ; lda force$map ; get current map ; sta io ; force to i/o in bank 0 ; lxi b,page$0$l ; point to 1st page register ; outp l ; set page 0 low ; inr c ; outp h ; set page 0 high ; inr c ; outp e ; set page 1 low ; inr c ; outp d ; set page 1 high ; sta force$map ; ret ; ;; ;; ;; ;move$0$to$1: ; lda force$map ; sta bank$1 ; force bank 1 memory ; lxi h,000h ; source ; lxi d,100h ; dest. ;; lxi b,100h ; mov b,d ; mov c,e ; count ; ldir ; sta force$map ; ret ; page ; ; ; no$CCP: ; here if we couldn't find the file call prtmsg ; report this... db cr,lf,'BIOS Err on A: No CCP.COM file',0 call ?conin ; get a response jr ?ldccp ; and try again ; ; CP/M BDOS Function Interfaces ; CSEG open: mvi c,15 ; open file control block db 21h ; lxi h,(mvi c,26) setdma: mvi c,26 ; set data transfer address db 21h ; lxi h,(mvi c,44) setmulti: mvi c,44 ; set record count db 21h ; lxi h,(mvi c,20) read: mvi c,20 ; read records jmp bdos ; 12345678901 ccp$fcb db 1,'CCP COM',0,0,0 fcb$rc db 0 ds 16 fcb$nr db 0,0,0 page ; ; CXIO.ASM and CXEM.ASM ; ;========================================================== ; ROUITINE TO VECTOR TO HANDLER ;========================================================== ; CP/M IO routines b=device : c=output char : a=input char ; CSEG ; ; ; ?cinit: ; initialize usarts mov b,c call vector$io ; jump with table adr on stack number$drivers: dw ?int$cia ; keys dw ?int80 ; 80col dw ?int40 ; 40col dw ?pt$i$1101 ; prt1 dw ?pt$i$1101 ; prt2 dw ?int65 ; 6551 if not use$6551 dw init$RS232 ; software RS232 endif dw rret ; max$devices equ (($-number$drivers)/2)-1 ; ; ; ?ci characte input call vector$io ; jump with table adr on stack dw key$board$in ; keys dw rret ; 80col dw rret ; 40col dw rret ; ptr1 dw rret ; prt2 dw ?in65 ; 6551 if not use$6551 dw in$RS232 ; software RS232 endif dw null$input ; ; ; ?cist: ; character input status call vector$io ; jump with table adr on stack dw key$board$stat ; keys dw rret ; 80col dw rret ; 40col dw rret ; prt1 dw rret ; prt2 dw ?ins65 ; 6551 if not use$6551 dw in$st$RS232 ; software RS232 endif dw rret ; ; ; ?co: ; character output call vector$io ; jump with table adr on stack dw rret ; keys dw ?out80 ; 80col dw ?out40 ; 40col dw ?pt$o$1 ; prt1 dw ?pt$o$2 ; prt2 dw ?out65 ; 6551 if not use$6551 dw out$RS232 ; software RS232 endif dw rret ; ; ; ?cost: ; character output status call vector$io ; jump with table adr on stack dw ret$true ; keys dw ret$true ; 80col dw ret$true ; 40col dw ret$true ; prt1 ?pt$s$1101 dw ret$true ; prt2 dw ?outs65 ; 6551 if not use$6551 dw out$st$RS232 ; software RS232 endif dw ret$true page ; ; This entry does not care about values of DE ; vector$io: mvi a,max$devices ; check for device # to high mov e,b ; get devive # in E ; ; ; INPUT: ; Vector # in E, Max device in A ; passes value in DE$TEMP in DE ; HL has routine's address in it on entering routine ; ; OUTPUT: ; ALL registers of returning routine are passed ; vector: pop h ; get address vector list mvi d,0 ; zero out the MSB cmp e ; is it too high? jrnc exist ; no, go get the handler address mov e,a ; yes, set to max$dev$handler(last one) exist: dad d ; dad d ; point into table mov a,m inx h mov h,m mov l,a ; get routine adr in HL if banked shld hl$temp ; save exec adr lxi h,0 dad sp lxi sp,bios$stack push h ; save old stack lhld de$temp xchg lhld hl$temp ; recover exec adr lda force$map ; get current bank push psw ; save on stack sta bank$0 ; set bank 0 as current call ipchl sta a$temp ; save value to return pop psw sta force$map ; set old bank back lda a$temp ; recover value to return shld hl$temp pop h ; recover old stack sphl ; set new stack lhld hl$temp ret ipchl: pchl ; jmp to handler ds 30h bios$stack: else lda a$temp xchg lhld de$temp xchg pchl endif page ;========================================================== ; CHARACTER INPUT ROUTINES ;========================================================== DSEG ; ; ; key$board$in: call key$board$stat ; test if key is available jrz key$board$in lda key$buf push psw ; save on stack xra a ; clear key sta key$buf ; ;** the tracking of the display should be able to be turned off ;** this could be done with one of the keyboard's Fx codes ; lda stat$enable bit 6,a jrnz no$update lda char$col$40 mov b,a lda @off40 cmp b jrnc do$update adi 39-1 cmp b jrnc no$update do$update: mvi a,80h sta old$offset ; store 80h to demand update no$update: pop psw ; recover current key rret: ret ; ; ; null$input: ; return a ctl-Z for no device mvi a,1Ah ret page ;========================================================== ; CHARACTER DEVICE INPUT STATUS ;========================================================== DSEG ; ; ; key$board$stat: lda key$buf ora a jrnz ret$true call ?get$key ora a ; =0 if none rz ; return character not advailable sta key$buf ; was one, save in key buffer ret$true: ori 0ffh ; and return true ret page cseg @ctbl db 'KEYS ' ; device 0, internal keyboard db mb$input db baud$none db '80COL ' ; device 1, 80 column display db mb$output db baud$none db '40COL ' ; device 2, 40 column display db mb$output db baud$none db 'PRT1 ' ; device 3, serial bus printer (device 4) db mb$output db baud$none db 'PRT2 ' ; device 4, serial bus printer (device 5) db mb$output db baud$none db '6551 ' ; device 5, EXT CRT db mb$in$out+mb$serial+mb$softbaud+mb$xonxoff ?intbd: db baud$1200 if not use$6551 db 'RS232 ' ; device 6, software RS232 device db mb$in$out+mb$serial+mb$xonxoff+mb$softbaud RS232$baud: db baud$300 endif db 0 ; mark end of table page ; ; TIME.ASM ; cseg ; ; HL and DE must be presevered ; ?time: inr c lxi b,cia$hours jrz set$time ; ; update SCB time (READ THE TIME) ; inp a ; read HR (sets sign flag) jp is$am ; jmp if AM (positive) ani 7fh adi 12h ; noon=24(PM), midnight=12(AM) daa cpi 24h ; check for noon (12+12 PM) jrnz set$hr mvi a,12h jr set$hr is$am: cpi 12h ; check for midnight (AM) jrnz set$hr xra a ; becomes 00:00 set$hr: sta @hour mov b,a lda old$hr mov c,a mov a,b sta old$hr cmp c ; if @hour' ; display start prompt '>' call disp$status lhld msg$ptr lda string$index try$again: cpi buff$large-2 jrc parameters$ok inx h dcr a jr try$again page ; ; ; parameters$ok: adi buff$pos+1 sta cur$pos disp$fun$loop: mov a,m ora a inx h ; advance function pointer jrz disp$fun$end push h call disp$status ; display on status line pop h lda offset ; get current cursor position cpi buff$pos+buff$large-1 ; to end of window? jrnz disp$fun$loop ; no, display next character disp$fun$end: mvi a,'<' ; display end prompt '<' disp$space$fill: call disp$status lda offset ; get current cursor position cpi buff$pos+buff$large ; to end of window? rz mvi a,' ' ; fill to the end with spaces jr disp$space$fill page ; ; ; disp$hex$byte: push psw rar rar rar rar call disp$hex$nibble pop psw disp$hex$nibble: ani 0fh adi '0' cpi '9'+1 jrc disp$status adi 7 disp$status: mov b,a lda offset mov c,a inr a sta offset lda cur$pos cmp c mvi a,01000000b ; set reverse video attributes jrnz not$cur$pos mvi a,00010000b ; set normal video and blink not$cur$pos: jmp ?stat page ; ; ; get$byte: mvi e,0 call read$nibble rc add a add a add a add a mov e,a read$nibble: push d call read$key mov a,b ; get matrix position lxi h,hex$key$tbl lxi b,16 ccir mov a,c pop d stc rnz add e push d push psw call disp$hex$nibble pop psw pop d stc cmc ret ; ; ; read$key: call scan$keys inr b jrz read$key ; no, wait for one dcr b ret page ; ; ; do$alpha$toggle: mvi m,0ffh ; mark buffer position free lda commodore$mode xri 00100001b ani 00100001b sta commodore$mode ; ; output: ; B=FF if no key pressed ; A=00 if no key code assigned ; else A=ASCII key code ; B=matrix position (0-57) ; C=control code (bits 1,0) ; 00=lower case (lowest) ; 01=upper case ; 10=shift ; 11=control (highest) ; (bit 2) control key ; (bit 4) rt. shift key ; (bit 5) commodore key ; (bit 7) lf. shift key ; ; HL= address of ASCII key location ; ?kyscn: scan$keys: lhld key$get$ptr mov a,m ; M=-1 if buffer empty mov b,a ; B=-1 if no character inr a rz ; return if no key is pressed ; ; there is a character in the buffer, ; advance key$get$ptr to next character. ; mov a,l adi 2 cpi low(key$buffer+key$buf$size) jrnz not$buf$end mvi a,low(key$buffer) not$buf$end: sta key$get$ptr ; update low byte of pointer page ; ; test for commodore key, if found toggle commodore mode ; mov a,b ; get buffered matrix position to A cpi alpha$toggle jrz do$alpha$toggle ; ; if normal mode(00), or in commodore mode bit ; inr l ; point to control byte lda commodore$mode ani 00100000b ; save commodore key set bit ora m ; get rest of control byte mov c,a ani 3 mov a,c jrnz is$control$or$shift lda commodore$mode ora c is$control$or$shift: dcr l mvi m,0ffh ; mark buffer position free mov l,b ; save matrix position in HL mvi h,0 dad h dad h ; mult. matrix position by 4 mov c,a ; save the control code in C for caller ani 3 add l ; add the offset mov l,a ; update the pointer xchg lhld key$tbl ; get the start of the ASCII table dad d ; HL now points to the ASCII value mov a,m ; for the input key. ora a ; set zero flag if A=0 ret page ; ; used to convert a keyboard matrix position into it's HEX ; value (keys caps labelled with 0 to 9 and A to F) ; hex$key$tbl: db 15h ; F db 0eh ; E db 12h ; D db 14h ; C db 1ch ; B db 0ah ; A db 20h ; 9 db 1bh ; 8 db 18h ; 7 db 13h ; 6 db 10h ; 5 db 0bh ; 4 db 08h ; 3 db 3bh ; 2 db 38h ; 1 db 23h ; 0  Machine (TSM) ; ; ; ; Keyboard Scan State Machine (KSSM) ; r inp a ani txrdy rz ori -1 ret endif end to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> Th title 'Root module of relocatable BIOS for CP/M 3.0 28 Aug 85' ; version 1.0 5 Sept 84 maclib cxequ ; C128 equates lib maclib modebaud ; define mode bits maclib Z80 ; Copyright (C), 1982 ; Digital Research, Inc ; P.O. Box 579 ; Pacific Grove, CA 93950 ; ; ; This is the invariant portion of the modular BIOS and is ; distributed as source for informational purposes only. ; All desired modifications should be performed by ; adding or changing externally defined modules. ; This allows producing "standard" I/O modules that ; can be combined to support a particular system ; configuration. bell equ 7 ctlQ equ 'Q'-'@' ctlS equ 'S'-'@' ccp equ 0100h ; Console Command Processor ; gets loaded into the TPA page cseg ; GENCPM puts CSEG stuff in ; common memory ; variables in system data page extrn @covec,@civec extrn @aovec extrn @aivec,@lovec ; I/O redirection vectors extrn @mxtpa ; addr of system entry point extrn @bnkbf ; 128 byte scratch buffer ; initialization extrn ?init ; general initialization and signon extrn ?ldccp,?rlccp ; load & reload CCP for BOOT & WBOOT ; user defined character I/O routines extrn ?ci,?co,?cist,?cost ; each take device in extrn ?cinit ; (re)initialize device in extrn @ctbl ; physical character device table ; disk communication data items extrn @dtbl ; table of pointers to XDPHs ; memory control extrn ?xmove,?move ; select move bank, and block move extrn ?bank ; select CPU bank ; clock support extrn ?time ; signal time operation ;; user function extrn ?user ; special functions ; general utility routines public ?pmsg ; print message public ?pdec ; print number from 0 to 65535 public ?pderr ; print BIOS disk error message header page ; External names for BIOS entry points public ?boot,?wboot,?const,?conin,?cono,?list,?auxo,?auxi public ?home,?sldsk,?sttrk,?stsec,?stdma,?read,?write public ?lists,?sctrn public ?conos,?auxis,?auxos,?dvtbl,?devin,?drtbl public ?mltio,?flush,?mov,?tim,?bnksl,?stbnk,?xmov ; BIOS Jump vector. ; ; All BIOS routines are invoked by calling these ; entry points. ?boot: jmp boot ; initial entry on cold start ?wboot: jmp wboot ; reentry on program exit, warm start ?const: jmp const ; return console input status ?conin: jmp conin ; return console input character ?cono: jmp conout ; send console output character ?list: jmp list ; send list output character ?auxo: jmp auxout ; send auxilliary output character ?auxi: jmp auxin ; return auxilliary input character ?home: jmp home ; set disks to logical home ?sldsk: jmp seldsk ; select disk drive, return disk parameter info ?sttrk: jmp settrk ; set disk track ?stsec: jmp setsec ; set disk sector ?stdma: jmp setdma ; set disk I/O memory address ?read: jmp read ; read physical block(s) ?write: jmp write ; write physical block(s) ?lists: jmp listst ; return list device status ?sctrn: jmp sectrn ; translate logical to physical sector ?conos: jmp conost ; return console output status ?auxis: jmp auxist ; return aux input status ?auxos: jmp auxost ; return aux output status ?dvtbl: jmp devtbl ; return address of device def table ?devin: jmp ?cinit ; change baud rate of device ?drtbl: jmp getdrv ; return address of disk drive table ?mltio: jmp multio ; set multiple record count for disk I/O ?flush: jmp flush ; flush BIOS maintained disk caching ?mov: jmp ?move ; block move memory to memory ?tim: jmp ?time ; Signal Time and Date operation ?bnksl: jmp bnksel ; select bank for code execution ; and default DMA ?stbnk: jmp setbnk ; select different bank for disk ; I/O DMA operations. ?xmov: jmp ?xmove ; set source and destination banks ; for one operation jmp ?user ; reserved for future expansion jmp 0 ; reserved for future expansion jmp 0 ; reserved for future expansion page ; ; BOOT ; Initial entry point for system startup. dseg ; this part can be banked boot: lxi sp,boot$stack mvi c,15 ; initialize all 16 character devices c$init$loop: push b call ?cinit pop b dcr c jp c$init$loop call ?init ; perform any additional system initialization ; and print signon message lxi b,16*256+0 lxi h,@dtbl ; init all 16 logical disk drives d$init$loop: push b ; save remaining count and abs drive mov e,m inx h mov d,m inx h ; grab @drv entry mov a,e ora d jrz d$init$next ; if null, no drive push h ; save @drv pointer xchg ; XDPH address in dcx h dcx h mov a,m sta @RDRV ; get relative drive code mov a,c sta @ADRV ; get absolute drive code dcx h ; point to init pointer mov d,m dcx h mov e,m ; get init pointer xchg call ipchl ; call init routine pop h ; recover @drv pointer d$init$next: pop b ; recover counter and drive # inr c djnz d$init$loop ; and loop for each drive jmp boot$1 cseg ; following in resident memory boot$1: call set$jumps call ?ldccp ; fetch CCP for first time jmp ccp page ; WBOOT ; Entry for system restarts. wboot: lxi sp,boot$stack call set$jumps ; initialize page zero call ?rlccp ; reload CCP jmp ccp ; then reset jmp vectors and exit to ccp set$jumps: if banked mvi a,1 call ?bnksl endif mvi a,JMP sta 0 sta 5 ; set up jumps in page zero lxi h,?wboot shld 1 ; BIOS warm start entry lhld @MXTPA shld 6 ; BDOS system call entry ret ds 64 boot$stack equ $ page ; ; DEVTBL ; Return address of character device table devtbl: lxi h,@ctbl ret ; ; GETDRV ; Return address of drive table getdrv: lxi h,@dtbl ret ; ; CONOUT ; Console Output. Send character in ; to all selected devices conout: lhld @covec ; fetch console output bit vector jmp out$scan ; ; AUXOUT ; Auxiliary Output. Send character in ; to all selected devices auxout: lhld @aovec ; fetch aux output bit vector jmp out$scan ; ; LIST ; List Output. Send character in ; to all selected devices. list: lhld @lovec ; fetch list output bit vector out$scan: mvi b,0 ; start with device 0 co$next: dad h ; shift out next bit jrnc not$out$device push h ; save the vector push b ; save the count and character not$out$ready: call coster ora a jrz not$out$ready pop b push b ; restore and resave the character and device call ?co ; if device selected, print it pop b ; recover count and character pop h ; recover the rest of the vector not$out$device: inr b ; next device number mov a,h ora l ; see if any devices left jrnz co$next ; and go find them... ret page ; ; CONOST ; Console Output Status. Return true if ; all selected console output devices ; are ready. conost: lhld @covec ; get console output bit vector jr ost$scan ; ; AUXOST ; Auxiliary Output Status. Return true if ; all selected auxiliary output devices ; are ready. auxost: lhld @aovec ; get aux output bit vector jr ost$scan ; ; LISTST ; List Output Status. Return true if ; all selected list output devices ; are ready. listst: lhld @lovec ; get list output bit vector ost$scan: mvi b,0 ; start with device 0 cos$next: dad h ; check next bit push h ; save the vector push b ; save the count mvi a,0FFh ; assume device ready cc coster ; check status for this device pop b ; recover count pop h ; recover bit vector ora a ; see if device ready rz ; if any not ready, return false inr b ; drop device number mov a,h ora l ; see if any more selected devices jrnz cos$next ori 0FFh ; all selected were ready, return true ret coster: ; check for output device ready, ; including optional xon/xoff support mov l,b mvi h,0 ; make device code 16 bits push h ; save it in stack dad h dad h ; create offset into device dad h ; characteristics tbl lxi d,@ctbl+6 dad d ; make address of mode byte mov a,m ani mb$xonxoff pop h ; recover console number in jz ?cost ; not a xon device, go get output status direct lxi d,xofflist dad d ; make pointer to proper xon/xoff flag call cist1 ; see if this keyboard has character mov a,m cnz ci1 ; get flag or read key if any cpi ctlq jrnz not$q ; if its a ctl-Q, mvi a,0FFh ; set the flag ready not$q: cpi ctls jrnz not$s ; if its a ctl-S, mvi a,00h ; clear the flag not$s: mov m,a ; save the flag call cost1 ; get the actual output status, ana m ; and mask with ctl-Q/ctl-S flag ret ; return this as the status cist1: ; get input status with and saved push b push h call ?cist pop h pop b ora a ret cost1: ; get output status, saving & push b push h call ?cost pop h pop b ora a ret ci1: ; get input, saving & push b push h call ?ci pop h pop b ret page ; ; CONST ; Console Input Status. Return true if ; any selected console input device ; has an available character. const: lhld @civec ; get console input bit vector jr ist$scan ; ; AUXIST ; Auxiliary Input Status. Return true if ; any selected auxiliary input device ; has an available character. auxist: lhld @aivec ; get aux input bit vector ist$scan: mvi b,0 ; start with device 0 cis$next: dad h ; check next bit mvi a,0 ; assume device not ready cc cist1 ; check status for this device ora a rnz ; if any ready, return true inr b ; drop device number mov a,h ora l ; see if any more selected devices jrnz cis$next xra a ; all selected were not ready, return false ret page ; ; CONIN ; Console Input. Return character from first ; ready console input device. conin: lhld @civec jr in$scan ; AUXIN ; Auxiliary Input. Return character from first ; ready auxiliary input device. auxin: lhld @aivec in$scan: push h ; save bit vector mvi b,0 ci$next: dad h ; shift out next bit mvi a,0 ; insure zero a (nonexistant device not ready). cc cist1 ; see if the device has a character ora a jrnz ci$rdy ; this device has a character inr b ; else, next device mov a,h ora l ; see if any more devices jrnz ci$next ; go look at them pop h ; recover bit vector jr in$scan ; loop til we find a character ci$rdy: pop h ; discard extra stack jmp ?ci page ; Utility Subroutines ?pmsg: ; print message @ up to a null ; saves & push b push d pmsg$loop: mov a,m ora a jrz pmsg$exit mov c,a push h call ?cono pop h inx h jr pmsg$loop pmsg$exit: pop d pop b ret ?pdec: ; print binary number 0-65535 from lxi b,table10 lxi d,-10000 next: mvi a,'0'-1 pdecl: push h inr a dad d jrnc stoploop inx sp inx sp jr pdecl stoploop: push d push b mov c,a call ?cono pop b pop d nextdigit: pop h ldax b mov e,a inx b ldax b mov d,a inx b mov a,e ora d jrnz next ret table10: dw -1000,-100,-10,-1,0 ?pderr: lxi h,drive$msg call ?pmsg ; error header lda @adrv adi 'A' mov c,a call ?cono ; drive code lxi h,track$msg call ?pmsg ; track header lhld @trk call ?pdec ; track number lxi h,sector$msg call ?pmsg ; sector header lhld @sect jr ?pdec ; sector number (call/ret) ; ; BNKSEL ; Bank Select. Select CPU bank for further execution. bnksel: sta @cbnk ; remember current bank jmp ?bank ; and go exit through users ; physical bank select routine xofflist: db -1,-1,-1,-1,-1,-1,-1,-1 ; ctl-s clears to zero db -1,-1,-1,-1,-1,-1,-1,-1 dseg ; following resides in banked memory ; Disk I/O interface routines ; ; SELDSK ; Select Disk Drive. Drive code in . ; Invoke login procedure for drive ; if this is first select. Return ; address of disk parameter header ; in seldsk: mov a,c sta @adrv ; save drive select code mov l,c mvi h,0 dad h ; create index from drive code lxi b,@dtbl dad b ; get pointer to dispatch table mov a,m inx h mov h,m mov l,a ; point at disk descriptor ora h rz ; if no entry in table, no disk mov a,e ani 1 jrnz not$first$select ; examine login bit push h xchg ; put pointer in stack & lxi h,-2 dad d mov a,m sta @RDRV ; get relative drive lxi h,-6 dad d ; find LOGIN addr mov a,m inx h mov h,m mov l,a ; get address of LOGIN routine call ipchl ; call LOGIN pop h ; recover DPH pointer not$first$select: ret page ; ; HOME ; Home selected drive. Treated as SETTRK(0). home: lxi b,0 ; same as set track zero ; ; SETTRK ; Set Track. Saves track address from ; in @TRK for further operations. settrk: mov l,c mov h,b shld @trk ret ; ; SETSEC ; Set Sector. Saves sector number from ; in @sect for further operations. setsec: mov l,c mov h,b shld @sect ret ; ; SETDMA ; Set Disk Memory Address. Saves DMA address ; from in @DMA and sets @DBNK to @CBNK ; so that further disk operations take place ; in current bank. setdma: mov l,c mov h,b shld @dma lda @cbnk ; default DMA bank is current bank ; fall through to set DMA bank ; ; SETBNK ; Set Disk Memory Bank. Saves bank number ; in @DBNK for future disk data ; transfers. setbnk: sta @dbnk ret page ; ; ; SECTRN ; Sector Translate. Indexes skew table in ; with sector in . Returns physical sector ; in . If no skew table (=0) then ; returns physical=logical. sectrn: mov l,c mov h,b mov a,d ora e rz xchg dad b mov l,m mvi h,0 ret page ; ; READ ; Read physical record from currently selected drive. ; Finds address of proper read routine from ; extended disk parameter header (XDPH). read: lhld @adrv mvi h,0 dad h ; get drive code and double it lxi d,@dtbl dad d ; make address of table entry mov a,m inx h mov h,m mov l,a ; fetch table entry push h ; save address of table lxi d,-8 dad d ; point to read routine address jr rw$common ; use common code ; ; WRITE ; Write physical sector from currently selected drive. ; Finds address of proper write routine from ; extended disk parameter header (XDPH). write: lhld @adrv mvi h,0 dad h ; get drive code and double it lxi d,@dtbl dad d ; make address of table entry mov a,m inx h mov h,m mov l,a ; fetch table entry push h ; save address of table lxi d,-10 dad d ; point to write routine address rw$common: mov a,m inx h mov h,m mov l,a ; get address of routine pop d ; recover address of table dcx d dcx d ; point to relative drive ldax d sta @rdrv ; get relative drive code and post it inx d inx d ; point to DPH again ipchl: pchl ; leap to driver page ; ; MULTIO ; Set multiple sector count. Saves passed count in ; @CNT multio: sta @cnt ret ; ; FLUSH ; BIOS deblocking buffer flush. Not implemented. flush: xra a ret ; return with no error ; ; error message components ; drive$msg: db cr,lf,bell,'BIOS Error on ',0 track$msg: db ': T-',0 sector$msg: db ', S-',0 end ; value (keys caps labelled with 0 to 9 and A to F) ; hex$key$tbl: db 15h ; F db 0eh ; E db 12h ; D db 14h ; C db 1ch ; B db 0ah ; A db 20h ; 9 db 1bh ; 8 db 18h ; 7 db 13h ; 6 db 10h ; 5 db 0bh ; 4 db 08h ; 3 db 3bh ; 2 db 38h ; 1 db 23h ; 0  Machine (TSM) ; ; ; ; Keyboard Scan State Machine (KSSM) ; r inp a ani txrdy rz ori -1 ret endif end to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> Th title 'CXKYCODE- function and key def file 26 May 85' maclib cxequ number$blks equ 4 ; 256 byte blocks def$per$key equ 4 key$tbl$size equ 11*8*def$per$key color$tbl$size equ 16 ; ; default Function keys and key definition ; org sys$key$area dw ascii$tbl-2 msgtbl: db 'F1',0 db 'F2',0 db 'dir',cr,0 db 'dir ',0 db 'F5',0 db 'F6',0 db 'F7',0 date db 5,18h,cr,0 ; ^E ^X ^D db 'F9',0 db 'F10',0 db 'F11',0 db 0f3h,0f3h,0f3h,0f3h,0f3h,0f3h,0f3h,0f3h,0f3h,0f3h db 0f3h,0f3h,0f3h,0f3h,0f3h,0f3h,0f3h,0f3h,0f3h,0f3h,0 db 0f4h,0f4h,0f4h,0f4h,0f4h,0f4h,0f4h,0f4h,0f4h,0f4h db 0f4h,0f4h,0f4h,0f4h,0f4h,0f4h,0f4h,0f4h,0f4h,0f4h,0 db 0f3h,0f3h,0f3h,0f3h,0 db 0f4h,0f4h,0f4h,0f4h,0 db 'F16',0 db 'F17',0 db 'F18',0 db 'F19',0 db 'F20',0 db 'F21',0 db 'F22',0 db 'F23',0 db 'F24',0 db 'F25',0 db 'F26',0 db 'F27',0 db 'F28',0 db 'F29',0 db 'F30',0 db 'F31',0 db 'Help ',0 msg$size equ $-msgtbl rept (number$blks*256)-msg$size-key$tbl$size-color$tbl$size db 0ffh endm page ascii$tbl: db 7fh,7fh,7fh,16h ; INS DEL db 0dh,0dh,0dh,0dh ; RETURN db 06h,06h,01h,01h ; LF RT db 86h,86h,87h,87h ; F7 F8 db 80h,80h,81h,81h ; F1 F2 db 82h,82h,83h,83h ; F3 F4 db 84h,84h,85h,85h ; F5 F6 db 17h,17h,17h,1ah ; UP DOWN db 33h,33h,23h,0A2h ; 3 # db 77h,57h,57h,17h ; W db 61h,41h,41h,01h ; A db 34h,34h,24h,0A3h ; 4 $ db 7ah,5ah,5ah,1ah ; Z db 73h,53h,53h,13h ; S db 65h,45h,45h,05h ; E db 00h,00h,00h,00h ; (lf shift) db 35h,35h,25h,0A4h ; 5 % db 72h,52h,52h,12h ; R db 64h,44h,44h,04h ; D db 36h,36h,26h,0A5h ; 6 & db 63h,43h,43h,03h ; C db 66h,46h,46h,06h ; F db 74h,54h,54h,14h ; T db 78h,58h,58h,18h ; X db 37h,37h,27h,0A6h ; 7 ' db 79h,59h,59h,19h ; Y db 67h,47h,47h,07h ; G db 38h,38h,28h,0A7h ; 8 ( db 62h,42h,42h,02h ; B db 68h,48h,48h,08h ; H db 75h,55h,55h,15h ; U db 76h,56h,56h,16h ; V db 39h,39h,29h,00h ; 9 ) db 69h,49h,49h,09h ; I db 6ah,4ah,4ah,0ah ; J db 30h,30h,30h,00h ; 0 db 6dh,4dh,4dh,0dh ; M db 6bh,4bh,4bh,0bh ; K db 6fh,4fh,4fh,0fh ; O db 6eh,4eh,4eh,0eh ; N db 2bh,2bh,2bh,00h ; + db 70h,50h,50h,10h ; P db 6ch,4ch,4ch,0ch ; L db 2dh,2dh,2dh,00h ; - db 2eh,2eh,3eh,00h ; . > db 3ah,3ah,5bh,7bh ; : [ { db 40h,40h,40h,00h ; @ db 2ch,2ch,3ch,00h ; , < db 23h,23h,23h,60h ; pound ` db 2ah,2ah,2ah,00h ; * db 3bh,3bh,5dh,7dh ; ; ] } db 00h,00h,00h,0f5h ; clear/home db 00h,00h,00h,00h ; (rt shift) db 3dh,3dh,3dh,7eh ; = ~ db 5eh,5eh,7ch,7ch ; ^ PI | db 2fh,2fh,3fh,5ch ; / ? \ db 31h,31h,21h,0A0h ; 1 db 5fh,5fh,5fh,7fh ; <- db 09h,15h,30h,00h ; (CONTROL) sound1 sound2 db 32h,32h,22h,0A1h ; 2 " db 20h,20h,20h,00h ; Space db 21h,20h,00h,00h ; (Commodore) sound3 db 71h,51h,51h,11h ; Q db 00h,00h,00h,0f0h ; RUN STOP db 9fh,9fh,9fh,9fh ; /HELP/ db 38h,38h,38h,0B7h ; /8/ db 35h,35h,35h,0B4h ; /5/ db 09h,09h,09h,00h ; /TAB/ db 32h,32h,32h,0B1h ; /2/ db 34h,34h,34h,0B3h ; /4/ db 37h,37h,37h,0B6h ; /7/ db 31h,31h,31h,0B0h ; /1/ db 1bh,1bh,1bh,00h ; /ESC/ db 2bh,2bh,2bh,0F7h ; /+/ (select VT100) db 2dh,2dh,2dh,0F6h ; /-/ (select ADM31) db 0Ah,0Ah,0Ah,0Ah ; /Line Feed/ db 0dh,0dh,0dh,0ffh ; /ENTR/ db 36h,36h,36h,0B5h ; /6/ db 39h,39h,39h,00h ; /9/ db 33h,33h,33h,0B2h ; /3/ db 00h,00h,00h,00h ; /Alt/ db 30h,30h,30h,00h ; /0/ db 2eh,2eh,2eh,00h ; /./ db 05h,05h,05h,12h ; /UP/ db 18h,18h,18h,03h ; /DN/ db 13h,13h,13h,08dh ; /LF/ db 04h,04h,04h,08eh ; /RT/ db 0f1h,0f1h,0f1h,0f2h ; /no scroll/ ; ; logical color table (used with ESC ESC ESC char) ; (where char is 50h to 7fh) ; db 000h,011h,022h,033h db 044h,055h,066h,077h db 088h,099h,0aah,0bbh db 0cch,0ddh,0eeh,0ffh to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> Th title 'CXPRINTER Commodore printer drivers 4 Dec 85' maclib z80 maclib cxequ public ?PT$I$1101,?PT$O$1,?pt$o$2 public ?convt ; public ?PT$S$1101 extrn ?fun65 ; ; printer output in register C ; dseg ?pt$o$2: lhld prt$conv$2 call do$convt ; C must be unchanged A=desired code lxi h,prt$buf$2 mvi b,5 jr prt$cont do$convt: mov a,c ; A=desired code mvi c,7 ; C=secondary address pchl ; HL,DE and B may be used ?pt$o$1: lhld prt$conv$1 call do$convt lxi h,prt$buf$1 mvi b,4 ; ; ; prt$cont: inr m mov e,m mvi d,0 xchg dad d ; index into buffer mov m,a xchg ; ani 7Fh ; strip MSB cpi lf ; data a CR ? jrz print$it ; yes, go print this line mov a,m ; no, get current line length cpi prt$buf$lng-1 ; reach end yet ? rnz ; no, exit ; yes, print line of data print$it: mov a,m sta vic$count ; set number of bytes to send mvi m,0 ; set count back to zero inx h shld @buffer ; save location to print from mov a,b sta vic$drv ; pass device # in Vic$drv mov a,c sta vic$trk ; pass secondary adr in Vic$trk mvi a,vic$prt jmp ?fun65 ; ; ; ?convt$none: mvi c,0 ; set secondary adr to 0 ret ; ; ; ?convt: ani 7fh ; only allow real ASCII values for now cpi cr jrz set$msb cpi '"' jrz is$quote cpi '@' rc cpi 60h jrc make$upper$case ; ; if it is a lower case letter subtract 20h ; cpi 'z'+1 jrnc lower$symbols sui 20h ret lower$symbols: adi 60h ret ; ; make$upper$case: cpi 'Z'+1 jrnc upper$symbols set$msb: adi 80h ret ; ; is$quote: mvi a,27h ; convert to tick (shifted 7) ret ; ; upper$symbols: cpi '\' rnz ; mvi a,0ffh ; ; printer initialization code ; ?pt$i$1101: ret ; ; printer status code ; dseg ;?pt$s$1101: ; ret prt$buf$lng equ 81 prt$buf$1: ds prt$buf$lng prt$buf$2: ds prt$buf$lng ; ; title 'C128 Ram Disk support 14 Oct 85' ; maclib cpm3 maclib z80 maclib cxequ ; Utility routines in standard BIOS extrn ?pmsg ; print message @ up to 00 ; saves & extrn ?pdec ; print binary number in from 0 to 99. extrn ?pderr ; print BIOS disk error header extrn ?conin,?cono ; con in and out extrn ?const ; get console status extrn @dtbl ; DMA ram bank public RMdsk extrn ?fun65 extrn ?dkmov page ; CSEG ; place code in common memory ; ; Extended Disk Parameter Headers (XPDHs) ; dw RM$write dw RM$read dw RM$login dw RM$init db 0 ; relative drive zero db 0 ; format type byte RMdsk: ; dph 0,dpb$RM$512 dw 0 ; TRANSLATE TABLE ADDRESS db 0,0,0,0,0,0,0,0,0 ; BDOS SCRATCH AREA db 0 ; MEDIA FLAG DPB$ptr: dw dpb$RM$512 ; DISK PARAMETER BLOCK dw 00000h ; CHECKSUM VECTOR ALLOCATED BY dw 0FFFEh ; ALLOC VECTOR ALLOCATED BY GENCPM dw 0FFFEh ; DIRBCB dw 0FFFEh ; DTABCB dw 0FFFEh ; HASH ALLOC'D db 0 ; HASH BANK ; ; DPB FOR RAM disk ; dpb$RM$128: ; dpb 256,1,512,1024,64,0 DW 0002 ; 128 BYTE RECORDS PER TRACK DB 03,07 ; BLOCK SHIFT AND MASK DB 00 ; EXTENT MASK DW 007Fh ; MAXIMUM BLOCK NUMBER DW 003Fh ; MAXIMUM DIRECTORY ENTRY NUMBER DB 0C0h,00h ; ALLOC VECTOR FOR DIRECTORY DW 8000h ; CHECKSUM SIZE DW 0 ; OFFSET FOR SYSTEM TRACKS DB 1,1 ; PHYSICAL SECTOR SIZE SHIFT dpb$RM$512: ; dpb 256,1,2048,2048,128,0 DW 0002 ; 128 BYTE RECORDS PER TRACK DB 04,0Fh ; BLOCK SHIFT AND MASK DB 01 ; EXTENT MASK DW 00FFh ; MAXIMUM BLOCK NUMBER DW 007Fh ; MAXIMUM DIRECTORY ENTRY NUMBER DB 0C0h,00h ; ALLOC VECTOR FOR DIRECTORY DW 8000h ; CHECKSUM SIZE DW 0 ; OFFSET FOR SYSTEM TRACKS DB 1,1 ; PHYSICAL SECTOR SIZE SHIFT page ; ; ; dseg RM$write: mvi d,VIC$RM$wr lda @dbnk ; get disk bank ana a lhld @dma jrz RM$do$rd$wr call ?dkmov+3 ; A<>0 transfers data from local$DMA to buffer mvi d,VIC$RM$wr jr RM$do$rd$wr$buf ; ; ; RM$read: mvi d,VIC$RM$rd lda @dbnk ; get disk bank ana a ; is it bank zero lhld @dma jrz RM$do$rd$wr ; yes, go read it call RM$do$rd$wr$buf ; no, transfer through buffer lhld @dma call ?dkmov+3 ; A=0 transfers data from buffer to local$DMA xra a ret ; ; ; RM$do$rd$wr$buf: lxi h,@buffer RM$do$rd$wr: lxi b,RM$128$low outp l inr c ; RM$128$mid outp h inr c ; RM$ext$low xra a outp a lhld @trk inr c ; RM$ext$mid outp l inr c ; RM$ext$hi outp h lxi h,256 inr c ; RM$count$low outp l inr c ; RM$count$hi outp h mov a,d ; get rd/wr command call ?fun65 xra a ; set no errors ret page ; ; ; dseg RM$init: lxi b,RM$control xra a outp a ; increment both addresses dcr c ; point to interrupt control register outp a ; disable interrupts lxi h,0 ; point to track 0 shld @trk xra a sta @dbnk ; set DMA bank to zero lxi h,@buffer ; shld @dma test$device$present: mov m,l ; place a pattern in the directory inr l ; ..buffer area jrnz test$device$present ; call RM$read ; read track 0 to DMA buffer lxi h,@buffer ; ..(buffer not changed if lxi d,dir$label ; ..device is not present) lxi b,12 ; test if KEY has been installed test$next$key: ldax d inx d cci jrnz no$match ; KEY missing, test device present jpe test$next$key jr set$size ; KEY is in RAM DISK, go set size page ; ; test if device is present, remove vector if not ; no$match: mvi l,0 ; start back at the buffer beginning test$for$ram$dsk: mov a,m cmp l ; buffer changed? jrnz device$is$present ; yes, then device is present inr l ; no, buffer end? jrnz test$for$ram$dsk ; no, test rest of buffer ; yes, L=0 ; ; device is missing, remove vector ; mov h,l ; remove vector to RAM disk shld @dtbl+('M'-'A')*2 ; .. (drive M:) ret ; ; initialize directory buffer ; device$is$present: call init$buffer ; fill buffer with E5`s lxi h,dir$label lxi d,@buffer lxi b,32 ldir ; install directory label in 1st record lxi h,0 shld @trk ; set track=0 clear$dir: call RM$write ; erase director sectors call init$buffer ; fill buffer with E5`s lda @trk inr a sta @trk cpi 16 ; 16 for 512K Ram disk jrnz clear$dir set$size: lxi h,dpb$RM$128 lxi b,RM$status inp a ani 10h ; mask of size bit (0=128K) jrz set$128K lxi h,dpb$RM$512 set$128K: shld dpb$ptr RM$login: ret page ; ; ; init$buffer: lxi h,@buffer mvi m,0E5h lxi d,@buffer+1 lxi b,256-1 ldir ret ; ; ; dir$label: ;123456789012 3 4 5 6 db ' ERTWINE VON',1,0,0,0 dw 0,0,0,0 dw date$hex,0 dw date$hex,0 ,066h,077h db 088h,099h,0aah,0bbh db 0cch,0ddh,0eeh,0ffh to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> Th public @civec, @covec, @aivec, @aovec, @lovec, @pageM public @bnkbf, @crdma, @crdsk, @vinfo, @resel, @fx, @usrcd public @mltio, @ermde, @erdsk, @media, @bflgs public @date, @hour, @min, @sec, ?erjmp, @mxtpa scb$base equ 0FE00H ; Base of the SCB @CIVEC equ scb$base+22h ; Console Input Redirection ; Vector (word, r/w) @COVEC equ scb$base+24h ; Console Output Redirection ; Vector (word, r/w) @AIVEC equ scb$base+26h ; Auxiliary Input Redirection ; Vector (word, r/w) @AOVEC equ scb$base+28h ; Auxiliary Output Redirection ; Vector (word, r/w) @LOVEC equ scb$base+2Ah ; List Output Redirection ; Vector (word, r/w) @pageM equ scb$base+2Ch ; Page mode. 0=page pause ; none 0 = no page break (byte, r/w) @BNKBF equ scb$base+35h ; Address of 128 Byte Buffer ; for Banked BIOS (word, r/o) @CRDMA equ scb$base+3Ch ; Current DMA Address ; (word, r/o) @CRDSK equ scb$base+3Eh ; Current Disk (byte, r/o) @VINFO equ scb$base+3Fh ; BDOS Variable "INFO" ; (word, r/o) @RESEL equ scb$base+41h ; FCB Flag (byte, r/o) @FX equ scb$base+43h ; BDOS Function for Error ; Messages (byte, r/o) @USRCD equ scb$base+44h ; Current User Code (byte, r/o) @MLTIO equ scb$base+4Ah ; Current Multi-Sector Count ; (byte,r/w) @ERMDE equ scb$base+4Bh ; BDOS Error Mode (byte, r/o) @ERDSK equ scb$base+51h ; BDOS Error Disk (byte,r/o) @MEDIA equ scb$base+54h ; Set by BIOS to indicate ; open door (byte,r/w) @BFLGS equ scb$base+57h ; BDOS Message Size Flag (byte,r/o) @DATE equ scb$base+58h ; Date in Days Since 1 Jan 78 ; (word, r/w) @HOUR equ scb$base+5Ah ; Hour in BCD (byte, r/w) @MIN equ scb$base+5Bh ; Minute in BCD (byte, r/w) @SEC equ scb$base+5Ch ; Second in BCD (byte, r/w) ?ERJMP equ scb$base+5Fh ; BDOS Error Message Jump ; (word, r/w) @MXTPA equ scb$base+62h ; Top of User TPA ; (address at 6,7)(word, r/o) ; end of normal SCB equates fer: lxi h,@buffer mvi m,0E5h lxi d,@buffer+1 lxi b,256-1 ldir ret ; ; ; dir$label: ;123456789012 3 4 5 6 db ' ERTWINE VON',1,0,0,0 dw 0,0,0,0 dw date$hex,0 dw date$hex,0 ,066h,077h db 088h,099h,0aah,0bbh db 0cch,0ddh,0eeh,0ffh to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> Th title 'Terminal Emulation (VT-100) 18 Feb 86' maclib cxequ if use$VT100 maclib z80 lines equ 24 public VT100 ; ; VT-100 ; ; NUL 00h ignored ; ENQ 05h transmit answer back message ; BEL 07h ring bell ; BS 08h back space. stop at left margin ; HT 09h do TAB ; LF 0Ah do line feed scroll at bottom ; VT 0Bh same as LF ; FF 0Ch same as LF ; CR 0Dh do CR ; SO 0Eh invoke G1 set ; SI 0Fh invoke G0 set ; XON 11h ignored ; XOFF 13h ignored ; CAN 18h abort ESC seq (disp error character) ; SUB 1Ah same as CAN ; ESC 1Bh control seq ; DEL 7Fh not used ; ; ; ESC = Keypad mode ; ESC > Keypad mode ; ESC 7 Save current cursor post and char set ; ESC 8 Restore cursor position and char set ; ESC D move cursor down one line ; ESC E move cursor to start of next line ; ESC H set horizontal tab ; ESC M move cursor up one line ; ESC Z same as ESC [ Pn c ; ESC c reset ; ESC # 3 Double height line Top ; ESC # 4 Double height line Bottom ; ESC # 5 set single width line ; ESC # 6 Double width line ; ESC # 8 files screen with E's ; ESC [ Pn A cursor up ; ESC [ Pn B cursor down ; ESC [ Pn C cursor right ; ESC [ Pn D cursor left ; ESC [ Pn ; Pn H cursor positioning ; ESC [ Ps J erase display ; ESC [ Ps K erase line ; ESC [ Pn c device attributes request ; ESC [ Pn ; Pn f cursor positioning ; ESC [ Ps g clear tab stop(s) ; ESC [ Ps;..;Ps h set mode ; ESC [ Ps;..;Ps l reset attributes ; ESC [ Ps;..;Ps m set attributes ; ESC [ Ps n Device status report ; ESC [ Ps q set LED's ; ESC [ Pn ; Pn r Set Top and Bottom Margins ; ESC [ 2 ; Ps y invoke confidence test ; ESC [ x Report / Req parameters ;; ESC ( A select char set ;; ESC ( B select char set ;; ESC ( 0 select char set ;; ESC ( 1 select char set ;; ESC ( 2 select char set ;; ESC ) A select char set ;; ESC ) B select char set ;; ESC ) 0 select char set ;; ESC ) 1 select char set ;; ESC ) 2 select char set ; page dseg ; ; VT-100 terminal emulation ; VT100: lhld parm$base ; 1st parm is exec adr (2 bytes) mov a,m inx h mov h,m mov l,a ora h ; L is in A already, test HL=0 mov a,c ; C is char to output jrz start$checking pchl ; ; ; start$checking: lxi h,control$table lxi b,cnt$tbl$lng ccir lxi h,control$exec$adr jrz find$exec$adr cpi 20h rc do$direct: mov d,a TJMP FR$wr$char page ; ; ; do$ESC: ; ESC control seq call cont$later ; ; ESC char look for char in the ESC table ; call remove$exec$adr lxi h,esc$table lxi b,esc$tbl$lng ccir rnz ; bad esc sequence lxi h,esc$exec$adr find$exec$adr: dad b dad b mov a,m inx h mov h,m mov l,a pchl page ; ; ESC # ; esc$pn: ; ESC # control seq call cont$later ; ; ESC # char look for char in the ESC table ; call remove$exec$adr lxi h,esc$pnd$table lxi b,esc$pnd$tbl$lng ccir rnz ; bad esc sequence lxi h,esc$pnd$exec$adr jr find$exec$adr page ; ; ESC [ ; esc$br: ; ESC [ call clear$parm call cont$later ; ; ESC [ char look for char in the ESC table ; cpi '9'+1 ; input char a parameter jrc put$buffer ; yes, save parameters in buffer call remove$exec$adr lxi h,esc$br$table lxi b,esc$br$tbl$lng ccir rnz ; bad esc sequence lxi h,esc$br$exec$adr jr find$exec$adr ; ; put byte in buffer pointed to by the put pointer+1 (advance pointer) ; put$buffer: mov c,a ; save character in C call get$par ; get address of parameter buffer mov e,m ; get low byte adr of input buffer inx h mov d,m ; get high byte adr of input buffer inx h inr m ; advance input count mov l,m ; get current count (with input) mvi h,0 ; dad d ; compute adr in buf to place input mov m,c ; place input character into buffer ; stc ret ; ; get byte from buffer pointed to by the get pointer+1 (advance pointer) ; get$buffer: call get$par mov e,m inx h mov d,m inx h mov a,m ; recover put counter inx h sub m ; test for end rz inr m ; advance get counter mov l,m ; get the get counter mvi h,0 dad d mov a,m do$DEL: ; DEL not used ret page ; ; ; do$CAN: ; CAN SUB abort ESC seq (disp error character) ; ; Invoke G0 char set ; do$SI: ; SI invoke G0 set ret ; ; Invoke G1 char set ; do$SO: ; SO invoke G1 set ret ; ; move cursor to margin on current line ; do$CR: ; CR do CR TJMP FR$do$cr ; ; ; do$LF: ; FF VT LF do line feed scroll at bottom TJMP FR$cursor$down ; ; move cursor to next tab stop or right margin if none ; do$HT: ; HT do TAB ret ; ; move cursor to left but not past left margin ; do$BS: ; BS back space. stop at left margin TJMP FR$cursor$left ; ; Sound bell tone ; do$BEL: ; BEL ring bell RJMP FR$bell ; ; transmit answerback message ; do$ENQ: ; ENQ transmit answer back message ret ; ; ; esc$pn$8: ; ESC # 8 files screen with E's lxi d,024*256+0 ; set row (D) and col (E) mvi c,24 ; set # of rows (C) out$next$line$E: mvi b,80 ; set # of col (B) dcr d ; start with row 0 push d push b TCALL FR$cursor$pos pop b out$next$E: push b mvi d,'E' TCALL FR$wr$char pop b djnz out$next$E pop d dcr c jrnz out$next$line$E ret ; ; ; esc$pn$6: ; ESC # 6 Double width line ret ; ; ; esc$pn$5: ; ESC # 5 set single width line ret ; ; ; esc$pn$4: ; ESC # 4 Double height line Bottom ret ; ; ; esc$pn$3: ; ESC # 3 Double height line Top ret ; ; Set tab at current cursor column ; esc$HH: ; ESC H set horizontal tab ret ; ; Move cursor down one line, scroll if on bottom margin ; esc$DD: ; ESC D move cursor down one line ret ; ; Move cursor to start of next line, scroll up if cursor ; is on the bottom margin ; esc$EE: ; ESC E move cursor to start of next line ret ; ; Move cursor up one line, if on top margin scroll down ; esc$MM: ; ESC M move cursor up one line ret ; ; reset VT100 to initial state (causes INIT H to be asserted ; briefly ???) ; esc$c: ; ESC c reset ret ; ; ; esc$8: ; ESC 8 Restore cursor position and char set ret ; ; ; esc$7: ; ESC 7 Save current cursor post and char set ret ; ; place Keypad into Numeric mode ; esc$gt: ; ESC > Keypad mode ret ; ; place Keypad into Application mode ; esc$equ: ; ESC = Keypad mode ret ; ; ; esc$br$y: ; ESC [2;Ps y invoke confidence test ret ; ; ; esc$br$x: ; ESC [ x Report / Req parameters ret ; ; ; esc$br$r: ; ESC [Pn;Pn r Set Top and Bottom Margins ret ; ; Ps=0 clear all LED's (default) ; PS=1 set LED 1 ; Ps=2 set LED 2 ; Ps=3 set LED 3 ; Ps=4 set LED 4 ; esc$br$q: ; ESC [Ps q set LED's ret ; ; Ps=5 Status Report ; responce is: ESC [0n (terminal OK) ; ESC [3n (terminal not OK) ; Ps=6 Report cursor position ; responce is: ESC [ Pl ; Pc R ; where Pl is the line number ; and Pc is column number ; esc$br$n: ; ESC [Ps n Device status report ret ; ; Ps=0 attributes off (default) ; Ps=1 bold or increased intensity ; Ps=4 underscore ; Ps=5 blink ; Ps=7 reverse video ; esc$br$m: ; ESC [Ps;;Ps m set character attributes call get$Pn$def0$init check$br$m: dcr c ; check # of parameters used rz ; exit if None ana a ; Ps=0 ? jrz set$atr$off ; set attributes off dcr a ; Ps=1 jrz bold$on ; dcr a ; Ps=2 dcr a ; Ps=3 dcr a ; Ps=4 jrz underline$on ; dcr a ; Ps=5 jrz blink$on ; dcr a ; Ps=6 dcr a ; Ps=7 jrz reverse$on ; call get$Pn$def0 jr check$br$m set$atr$off: bold$on: underline$on: blink$on: reverse$on: ret ; ; Ps=1 cursor key (l=cursor ; h=application) ; Ps=2 ANSI/VT52 (l=VT52 not supported) ; Ps=3 Column (l=80 col ; h=132 col) 80 only ; Ps=4 Scrolling (l=jump ; h=smooth) smooth only ; Ps=5 Screen (l=normal ; h=reverse) ; Ps=6 Origin (l=Absolute ; h=Relative) ; Ps=7 Auto wrap (l=off ; h=on) ; Ps=8 Auto Repeat (l=off ; h=on) ; Ps=9 interlace (l=off ; h=on) ; Ps=20 LF/NL (l=line feed ; h=new line) ; esc$br$l: ; ESC [Ps;;Ps l reset mode ret ; ; see esc$br$l ; esc$br$h: ; ESC [Ps;;Ps h set mode ret ; ; Ps=0 clear tab stop at current column (default) ; Ps=3 clear ALL tab stops ; esc$br$g: ; ESC [Ps g clear tab stop(s) ret ; ; Pn default =1 missing Pn uses default value(s) ; position cursor to line (1st) and column (2nd) ; uses DECOM parm to set origin mode (within margin ; or full screen) ; esc$br$f: ; ESC [Pn;Pn f cursor positioning esc$br$HH: ; ESC [Pn;Pn H cursor positioning call get$Pn$def1$init dcr a mov d,a call get$Pn$def1 ; DE are not changed by this call dcr a mov e,a TJMP FR$cursor$pos ; ; What are you ; response is: ESC [?1; Ps c ; where Ps is: ; 0=base VT100, no options ; 1=processor option (STP) ; 2=advanced video option (AVO) ; 3=AVO and STP ; 4=graphics processor option (GPO) ; 5=GPO and STP ; 6=GPO and AVO ; 7=GPO, STP and AVO ; esc$ZZ: ; ESC Z same as ESC [ Pn c esc$br$c: ; ESC [Pn c device attributes request ret ; ; Ps=0 from cursor to end of line (default) ; Ps=1 from start of line to cursor ; Ps=2 all of cursor line ; esc$br$KK: ; ESC [Ps K erase line ret ; ; Ps=0 from cursor to end of screen ; Ps=1 from start of screen to cursor ; Ps=2 all of screen (cursor is not moved) ; esc$br$JJ: ; ESC [Ps J erase display ret ; ; ; esc$br$DD: ; ESC [Pn D cursor left ret ; ; ; esc$br$CC: ; ESC [Pn C cursor right ret ; ; ; esc$br$BB: ; ESC [Pn B cursor down ret ; ; ; esc$br$AA: ; ESC [Pn A cursor up ret page ; ; convert number to binary ; stop conversion at end or any none number ; (DE may not be changed) ; get$Pn$def0$init: call init$get ; set up to read buffer ; get$Pn$def0: call get$in$parm mov a,b ; get input data to A ret ; ;***** NOTE ESC [ ;4;A is the same as ESC [ 0;4;5A ; ; ; convert number to binary ; stop conversion at end or any none number ; return 1 if input is missing or a zero ; (DE may not changed) ; get$Pn$def1$init: call init$get ; set up to read buffer ; get$Pn$def1: call get$in$parm mov a,b ; get input data to A ora a ; is input =0? rnz ; no, then use it inr a ; yes, then use default of 1 ret ; ; B=converted number in binary (from input string) ; C=number of digits converted+1 ; A=0 if ran out of input else A=last character read from string ; (DE may not be changed) ; get$in$parm: lxi b,1 ; B=0, C=1 get$next$num: lda save$count dcr a rz sta save$count lhld buff$pointer ; get input buffer adr inx h ; PRE incr adr shld buff$pointer mov a,m call test$num rc slar b ; 2x add b ; A=A+2B slar b ; 4x slar b ; 8x add b ; A=A+2B+8B=A+10B mov b,a ; save in B inr c ; advance parmeter count jr get$next$num ; ; return with carry set (Cy=1) if not a number (A=input Char) ; return bianary number in A if it was a number (Cy=0) ; test$num: cpi '0' rc cpi '9'+1 cmc rc sui '0' ret ; ; set up local values to use buffer parameters ; init$get: call get$par ; get pointer to buffer(s) mov e,m inx h mov d,m inx h mov a,m inr a ; adjust for PRE decr sta save$count ; inx h ; mov a,m ; sta get$count xchg shld buff$pointer ret save$count: db 0 buff$pointer: dw 0 page ; ; set buffer back to start ; clear$parm: call get$par inx h inx h mvi m,0 ; zero out the input count ret ; ; ; get$par: lxi h,vt100$par$80 lda fun$offset ana a rz lxi h,vt100$par$40 ret ; ; ; vt100$par$80: dw buffer$80 db 0 ; current put pointer into buffer ; ; ; vt100$par$40: dw buffer$40 db 0 ; current put pointer into buffer buffer$80 equ $-1 ds 20 buffer$40 equ $-1 ds 20 page ; ; ; cont$later: pop h ; get address to cont at in H jr save$exec$adr ; save it ; ; ; remove$exec$adr: lxi h,0 save$exec$adr: xchg lhld parm$base mov m,e inx h mov m,d ret page ; ; table scanned top to bottom ; control$table: db 05h ; ENQ transmit answer back message db 07h ; BEL ring bell db 08h ; BS back space. stop at left margin db 09h ; HT do TAB db 0Ah ; LF do line feed scroll at bottom db 0Bh ; VT same as LF db 0Ch ; FF same as LF db 0Dh ; CR do CR db 0Eh ; SO invoke G1 set db 0Fh ; SI invoke G0 set db 18h ; CAN abort ESC seq (disp error character) db 1Ah ; SUB same as CAN db 1Bh ; ESC control seq db 7Fh ; DEL not used cnt$tbl$lng equ $-control$table ; ; table scanned bottom to top ; control$exec$adr: dw do$DEL ; DEL not used dw do$ESC ; ESC control seq dw do$CAN ; SUB same as CAN dw do$CAN ; CAN abort ESC seq (disp error character) dw do$SI ; SI invoke G0 set dw do$SO ; SO invoke G1 set dw do$CR ; CR do CR dw do$LF ; FF same as LF dw do$LF ; VT same as LF dw do$LF ; LF do line feed scroll at bottom dw do$HT ; HT do TAB dw do$BS ; BS back space. stop at left margin dw do$BEL ; BEL ring bell dw do$ENQ ; ENQ transmit answer back message page ; ; table scanned top to bottom ; esc$table: db '=' ; ESC = Keypad mode db '>' ; ESC > Keypad mode db '7' ; ESC 7 Save current cursor post and char set db '8' ; ESC 8 Restore cursor position and char set db 'D' ; ESC D move cursor down one line db 'E' ; ESC E move cursor to start of next line db 'H' ; ESC H set horizontal tab db 'M' ; ESC M move cursor up one line db 'Z' ; ESC Z same as ESC [ Pn c db 'c' ; ESC c reset db '#' ; ESC # control seq db '[' ; ESC [ cursor up esc$tbl$lng equ $-esc$table ; ; table scanned bottom to top ; esc$exec$adr: dw esc$br ; ESC [ cursor up dw esc$pn ; ESC # control seq dw esc$c ; ESC c reset dw esc$ZZ ; ESC Z same as ESC [ Pn c dw esc$MM ; ESC M move cursor up one line dw esc$HH ; ESC H set horizontal tab dw esc$EE ; ESC E move cursor to start of next line dw esc$DD ; ESC D move cursor down one line dw esc$8 ; ESC 8 Restore cursor position and char set dw esc$7 ; ESC 7 Save current cursor post and char set dw esc$gt ; ESC > Keypad mode dw esc$equ ; ESC = Keypad mode ; ; ; esc$pnd$table: db '3' ; ESC # 3 Double height line Top db '4' ; ESC # 4 Double height line Bottom db '5' ; ESC # 5 set single width line db '6' ; ESC # 6 Double width line db '8' ; ESC # 8 files screen with E's esc$pnd$tbl$lng equ $-esc$pnd$table esc$pnd$exec$adr: dw esc$pn$8 ; ESC # 8 files screen with E's dw esc$pn$6 ; ESC # 6 Double width line dw esc$pn$5 ; ESC # 5 set single width line dw esc$pn$4 ; ESC # 4 Double height line Bottom dw esc$pn$3 ; ESC # 3 Double height line Top ; ; ; esc$br$table: db 'A' ; ESC [ Pn A cursor up db 'B' ; ESC [ Pn B cursor down db 'C' ; ESC [ Pn C cursor right db 'D' ; ESC [ Pn D cursor left db 'H' ; ESC [ Pn ; Pn H cursor positioning db 'J' ; ESC [ Ps J erase display db 'K' ; ESC [ Ps K erase line db 'c' ; ESC [ Pn c device attributes request db 'f' ; ESC [ Pn ; Pn f cursor positioning db 'g' ; ESC [ Ps g clear tab stop(s) db 'h' ; ESC [ Ps;..;Ps h set mode db 'l' ; ESC [ Ps;..;Ps l reset attributes db 'm' ; ESC [ Ps;..;Ps m set attributes db 'n' ; ESC [ Ps n Device status report db 'q' ; ESC [ Ps q set LED's db 'r' ; ESC [ Pn ; Pn r Set Top and Bottom Margins db 'x' ; ESC [ x Report / Req parameters db 'y' ; ESC [ 2 ; Ps y invoke confidence test esc$br$tbl$lng equ $-esc$br$table esc$br$exec$adr: dw esc$br$y ; ESC [2;Ps y invoke confidence test dw esc$br$x ; ESC [ x Report / Req parameters dw esc$br$r ; ESC [Pn;Pn r Set Top and Bottom Margins dw esc$br$q ; ESC [Ps q set LED's dw esc$br$n ; ESC [Ps n Device status report dw esc$br$m ; ESC [Ps;;Ps m set attributes dw esc$br$l ; ESC [Ps;;Ps l reset attributes dw esc$br$h ; ESC [Ps;;Ps h set mode dw esc$br$g ; ESC [Ps g clear tab stop(s) dw esc$br$f ; ESC [Pn;Pn f cursor positioning dw esc$br$c ; ESC [Pn c device attributes request dw esc$br$KK ; ESC [Ps K erase line dw esc$br$JJ ; ESC [Ps J erase display dw esc$br$HH ; ESC [Pn;Pn H cursor positioning dw esc$br$DD ; ESC [Pn D cursor left dw esc$br$CC ; ESC [Pn C cursor right dw esc$br$BB ; ESC [Pn B cursor down dw esc$br$AA ; ESC [Pn A cursor up endif end ; ; ; esc$esc: call cont$later ; ; check for ESC ESC ESC ; cpi esc ; check if 3rd char is an ESC jrnz remove$exec$adr call cont$later ; ; set current character as the attr ; mov b,a TCALL FR$color jr remove$exec$adr ; ; ; esc$equ: call cont$later ; ; ESC = R ; lhld parm$base inx h inx h sui ' ' ; remove ascii bias mov m,a cpi '8'-' ' ; test for line 25 (A=24?) jrnz not$status$line ; no, jmp inr a ; yes, A=25 sta paint$size ; set 40 column repaint to 25 lines not$status$line: call cont$later ; ; ESC = R C (go do it) ; sui ' ' mov e,a ; column # to E lhld parm$base inx h inx h mov d,m ; row # to D TCALL FR$cursor$pos jr remove$exec$adr page ; ; ; char$cnt$z: ; ^Z home and clear screen lxi d,lines*256+0 ; B=24(row) C=0(col) TCALL FR$cursor$pos call esc$t ; clear the status line lxi d,0 TCALL FR$cursor$pos esc$y: TJMP FR$CES ; clear to end of screen home$cursor: lxi d,0 TJMP FR$cursor$pos esc$t: TJMP FR$CEL ; clear to end of line ; ; ; cursor$rt: TJMP FR$cursor$rt ; ; ; cursor$up: TJMP FR$cursor$up page ; ; delete character ; esc$W: TJMP FR$char$del ; ; delete line ; esc$R: TJMP FR$line$del ; ; insert character ; esc$Q: TJMP FR$char$ins ; ; insert line ; esc$E: TJMP FR$line$ins page ; ; Half Intensity Off ; esc$lfp: mvi c,00000001b ; turn intensity up jr set$FR$atr$c ; ; Half Intensity On ; esc$rtp: mvi c,00000000b ; turn intensity down parn$cont: mvi b,00000001b ; attribute bit to change jr set$FR$attr ; ; Set Attribute sequence ; esc$G: call cont$later ; ; ESC G char ; call remove$exec$adr sui '4' ; '4' reverse video on jrz esc$G$4 inr a ; '3' underline attr on jrz esc$G$3 inr a ; '2' blink attr on jrz esc$G$2 inr a ; '1' alt char set jrz esc$G$1 inr a ; '0' clear attributes rnz ; ; Rev. Video, blink, atl char set, and underline off ; esc$G$0: mvi c,10000000b ; turn attributes off mvi b,11110000b ; attribute bit to change jr set$FR$attr ; ; Select alt character set ; esc$G$1: mvi c,00000000b ; select alt character set mvi b,10000000b jr set$FR$attr ; ; Blinking On ; esc$G$2: mvi c,00010000b ; turn on blink attr jr set$FR$atr$c ; ; Under line ; esc$G$3: mvi c,00100000b ; turn on underline bit jr set$FR$atr$c ; ; Reverse Video On ; esc$G$4: mvi c,01000000b ; turn attributes on set$FR$atr$c: mov b,c ; reverse attr set$FR$attr: TJMP FR$attr ,066h,077h db 088h,099h,0aah,0bbh db 0cch,0ddh,0eeh,0ffh to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> Th title '8502 drivers 4 Mar 86' maclib x6502 maclib z80 maclib cxequ $-MACRO ; ; COMMON EQUATES ; ; page 0 variables, from 0a to 8f are usable ; prtno equ 0000Ah ; 0Ah second$adr equ prtno+1 ; 0Bh DATCHN equ second$adr+1 ; 0Ch CMDCHN equ datchn+1 ; 0Dh DEVNO equ cmdchn+1 ; 0Eh adr$1 equ devno+1 ; 0Fh temp$byte equ adr$1+2 ; 11h ; equ temp$byte+1 ; 12h pal$nts equ 00a03h ; FF=PAL=50Hz 0=NTSC=60Hz serial equ 00a1ch d2pra equ 0dd00h ; serial control port (clk and data) d1sdr equ 0dc0ch ; Fast serial data reg. d1icr equ 0dc0dh ; serial channel interrupt control reg clkbit equ 10h ; d2pra clock bit mask ; ; KERNAL EQUATES ; K$spin$spout equ 0FF64h ; C=0 spin C=1 spout K$setbnk equ 0FF68h ; set the logical bank # for open ; disk commands ;I A=load and store bank # (C128 type bank) ; X=file name bank # K$readst equ 0FFB7h ; read status byte ;O A = status K$setlfs equ 0FFBAh ; setup a logical file ;I A=logical file # ; X=device # (0-31) ; Y=seconday command (FF if nane) K$setnam equ 0FFBDh ; set up file name for OPEN ;I A=name length ; X=low byte pointer to name ; Y=high byte pointer to name K$open equ 0FFC0h ; open a logical file (after setlfs ; and setnam) ;O A = error # (1,2,4,5,6,240) K$chkin equ 0FFC6h ; open a channel for input ;I X = logical file # ;O A = errors #(0,3,5,6) K$chkout equ 0FFC9h ; open a channel for output ;I X = logical file # ;O A = error #(0,3,5,7) K$clrchn equ 0FFCCh ; clears ALL I/O channel K$chrin equ 0FFCFh ; get a character from input channel ;O A=input character K$chrout equ 0FFD2h ; output a character to output channel ;I A =output char ;GETIN equ 0FFE4h K$clall equ 0FFE7h ; close ALL open logical files K$close equ 0FFC3h ; close a logical file ;I A = logical channel # to be closed ;O A = error #(0,240) RESET equ 0FFFCh PAGE ; org bios8502 ; ; **** THIS IS THE COMMAND LOOP **** ; start: if use$fast @ldx sys$speed ;-K get desired system speed @stx vic$speed ;-K set system speed endif @ldx -1,# ;-K @txs ;-K set the stack to the top @JSR VICIO ;-K go find and do requested operation bios$exit: @sei ;?K DISABLE INTERRUPTS @ldx 3eh,# ;?K set up Z80 memory map as required @stx force$map ;?K @ldx 82h,# ;-K @stx CIA1+int$ctrl ;-K turn on CIA timer B interrupts if use$fast @ldx 0,# ;-K get value for 1 MHz mode (slow) @stx vic$speed ;-K set system speed endif @jmp enable$z80+6 ;-K PAGE ; ; ; iotbl: dw sys$reset ;-1 reset system (C128) dw initilize ;0 initialize the 8502 dw READ ;1 Read a sector of data to sector buffer dw WRITE ;2 Write a " " " " " " dw readf ;3 Set-up for fast read (154X only) dw writef ;4 Set-up for fast write (154X only) dw dsktst ;5 test for 154x and diskette type dw query$dsk ;6 get disk characteristics dw PRINT ;7 print data character dw FORMAT ;8 format disk as 1541 disk dw user$fun ;9 vector to user code (L=viccount,H=vicdata) dw ram$dsk$rd ;10 RAM disk read dw ram$dsk$wr ;11 RAM disk write NUMCMD equ ($-IOTBL)/2 ; NUMBER OF COMMANDS iotbl$low equ low(iotbl) ; ; ; sys$reset: ;**CMD ENTRY** @jsr en$kernal ;-K @JMP (RESET) ;+K ; ; ; user$fun: ;**CMD ENTRY** @jmp (vic$count) ;-K page ; ; **** IO COMMAND DISPATCH ROUTINE **** ; VICIO: @lda vic$cmd ;-K get the command @cmp NUMCMD,# ;-K is this a valid command @bcs bad$command ;-K no, exit without doing anything ;-K yes, get vector to it @cld ;-K clear to binary mode @asl a ;-K A=2*CMD (carry cleared) @clc ;-K @adc iotbl$low+2,# ;-K add to vector table start address @sta VICIO2+1 ;-K modify the JMP instructions ind adr VICIO2: @jmp (IOTBL) ;-K this is the ind adr that ; is modified above ; ; ; input$byte: @sei @lda d2pra @eor clk$bit,# @sta d2pra ; @lda 8,# in$1: @bit d1icr @beq in$1 @lda d1sdr bad$command: @RTS ;-K page ; ; initialize the 8502 ; initilize: ;**CMD ENTRY** @ldx low(irqs),# ;-K @ldy high(irqs),# ;-K @stx 314h ;-K IRQ vector @sty 315h ;-K @stx 316h ;-K BRK vector @sty 317h ;-K @stx 318h ;-K NMI vector @sty 319h ;-K @jsr en$kernal ;-K @lda 0fffeh ;+K @sta 0fffeh ;+K write to RAM under ROM @lda 0ffffh ;+K @sta 0ffffh ;+K @lda 6,# ;+K @sta CIA2+data$dir$b ;+K setup user port for RS232 @lda pal$nts ;+K -1=50Hz(PAL) 0=60Hz(NTSC) @sta sys$freq ;+K @jmp K$clall ;+K close all open files PAGE ; ; **** DISK SECTOR READ **** ; READ: ;**CMD ENTRY** @JSR set$drv ;-K @jsr en$kernal ;+K @ldx datchn ;+K @jsr K$chkin ;+K @bcs disk$changed ;+K @jsr K$clrchn ;+K clear the input channel for now @LDA '1',# ;+K read command @JSR setup ;+K send it @JSR CKINDT ;+K @LDX 0,# ;+K ; READ1: @JSR K$chrin ;+K get a byte from the KERNAL @STA @BUFFER,X ;+K save it in the buffer @INX ;+K advance the buffer pointer @BNE READ1 ;+K loop back if not past buf end @jmp K$clrchn ;+K CLEAR CHANNEL ; ; disk$changed: @lda 0bh,# ;?K disk changed error code @sta vic$data ;?K @jmp en$K$open ;?K page ; ; **** DISK SECTOR WRITE **** ; WRITE: ;**CMD ENTRY** @jsr set$drv ;-K @jsr ckotcm ;-K @LDY setpnt$lng,# ;+K ; WRITE0: @LDA SETPNT,X ;+K @JSR K$chrout ;+K @INX ;+K @DEY ;+K @BNE WRITE0 ;+K @JSR K$clrchn ;+K @JSR CKINCM ;+K @BNE WRITE2 ;+K @JSR K$clrchn ;+K @JSR CKOTDT ;+K @LDX 0,# ;+K ; WRITE1: @sei ;+K disable interrupts @ldy 3fh,# ;+K enable all RAM in bank 0 @sty force$map ;+K @LDA @BUFFER,X ;-K @ldy 0,# ;-K re-enable kernal @sty force$map ;-K @JSR K$chrout ;+K write buffer character @INX ;+K @BNE WRITE1 ;+K write all 256 bytes of buffer @JSR K$clrchn ;+K clear the channel @LDA '2',# ;+K write command @JMP setup ;+K ; WRITE2: @lda 0ffh,# ;+K @sta vic$data ;+K writes thru ROM to RAM @jmp opencm ;+K page ; ; Set-up for fast disk write ; writef: ;**CMD ENTRY** @lda 2,# ;-K 2=read command @skip2 ;-K ; ; Set-up for fast disk read ; readf: ;**CMD ENTRY** @lda 0,# ;-K 0=read command @sta f$cmd ;-K @lda 0,# ;-K @sta vic$data ;-K @jsr set$drv$f ;-K @ldy f$cmd$lng,# ;-K command set above rd/wr @jsr send$fast ;-K @jmp clk$hi ;+K page ; ; test the format of the disk return code to CP/M ; telling the disk type. Also test for FAST disk drive. ; dsktst: ;**CMD ENTRY** @lda vic$drv ;-K @eor 0ffh,# ;-K @and fast ;-K @sta fast ;-K clear fast indicator bit for current drive @jsr set$and$open ;-K set drv close and reopen the channel @ldx 0,# ;+K delay to allow drive to reset status tst$delay: @nop ;+K @nop ;+K @dex ;+K @bne tst$delay ;+K @ldy inq$cmd$lng,# ;+K @ldx inq$cmd,# ;+K @jsr send$fast$cmd ;+K @jsr input$byte ;+K @sta vic$data ;+K @jsr clk$hi ;+K @sty io$0 ;+K 2/24 @lda vic$drv ;-K @ora fast ;-K set current drive as fast @sta fast ;-K @rts ;-K page ; ; ; query$dsk: ;**CMD ENTRY** @jsr set$drv$f ;-K will query track set by user @ldy query$cmd$lng,# ;-K command length is 4 @ldx query$cmd,# ;-K @jsr send$fast$cmd ;-K @jsr input$byte ;+K @sta vic$data ;+K @bpl clk$hi ;+K exit if not MFM @and 0eh,# ;+K test for error @bne clk$hi ;+K exit if error @jsr input$byte ;+K read offset sectors status byte @sta @buffer ;+K @and 0eh,# ;+K test for error @bne clk$hi ;+K exit if error @tax ;+K get a zero in X @ldy 5,# ;+K five info bytes are sent back query$loop: @inx @jsr input$byte @sta @buffer,X @dey @bne query$loop clk$hi: @lda d2pra ;+K set clock bit HIGH @and 0ffh-clkbit,# @sta d2pra @rts PAGE ; ; **** PRINTER OUTPUT **** ; ; this routine will support two printers ; the device number is passed in vic$drv (4,5) ; secondary address in vic$trk ; the logical file number is equal to the device # ; if VIC$count=0 then output character in VIC$data ; if VIC$count<>0 then output characters pointered to by @buffer ; PRINT: ;**CMD ENTRY** @lda vic$drv ;-K @sta prtno ;-K @lda vic$trk ;-K ;; @sta second$adr ;-K this line should be deleted and one @cmp second$adr ;-K ..below used. @sta second$adr ;-K save secondary adr @bne reopen$prt ;-K @jsr en$kernal ;-K print$cont: @ldx prtno ;+K @JSR K$chkout ;+K @BCS PERR0 ;+K PRINT ERROR IF CARRY SET @sty io$0 ;+K 2/24 @ldx vic$count ;-K @bne print$buffer ;-K @LDA vic$data ;-K GET CHARACTER @sta io$0 ;-K @JSR K$chrout ;+K AND PRINT IT @JMP K$clrchn ;+K CLEAR CHANNEL print$buffer: @stx temp$byte ;-K @lda @buffer ;-K @sta adr$1 ;-K @lda @buffer+1 ;-K @sta adr$1+1 ;-K @ldy 0,# ;-K @ldx 0,# ;-K print$buf$loop: @sta bank$0 ;?K enable RAM bank 0 (no I/O) @lda (adr$1),y ;rK @stx force$map ;rK @jsr K$chrout ;+K @iny ;+K @dec temp$byte ;+K @bne print$buf$loop ;+K @jmp K$clrchn ;+K ; ; PERR0: @CMP 3,# ;+K FILE NOT OPEN? @BNE PERR1 ;+K BRANCH IF NO reopen$prt: @JSR OPNPRT ;?K OPEN PRINTER CHANNEL @BCC print$cont ;+K IF CARRY CLEAR, OK TO PRINT PERR1: @LDA 255,# ;+K NO DEVICE PRESENT @STA vic$data ;+K FLAG BAD ATTEMPT writes to ram under ROM PRTST: @RTS ;+K PAGE ; ; **** FORMAT DISK ROUTINE **** ; FORMAT: ;**CMD ENTRY** @jsr set$drv$num ;-K @lda fast ;-K @and vicdrv ;-K @bne format$fast ;-K @JSR CKOTCM ;-K returns X=0 @LDY fmtcmd$lng,# ;+K FMT1: @LDA FMTCMD,X ;+K @JSR K$chrout ;+K @INX ;+K @DEY ;+K @BNE FMT1 ;+K @JSR K$clrchn ;+K fmt2: @JSR CKINCM ;+K check for errors @BEQ setup3 ;+K no errors, return good status @BNE setup5 ;+K error return error status format$fast: @ldx @buffer ;-K get command length fast$F: ;-K @lda @buffer+1-1,x ;-K @sta F$cmd-1,x ;-K @dex ;-K transfer command tail from buffer+1 @bne fast$F @ldy @buffer ;-K @iny ;-K @iny ;-K count is tail length plus 2 @ldx F$cmd ;-K @jsr send$fast$cmd ;-K @jmp fmt2 ;+K PAGE ; ; ; ram$dsk$rd: ; RAM disk read @ldx 81h,# ;-K @skip$2 ;-K ; ; ; ram$dsk$wr: ; RAM disk write @ldx 80h,# ;-K if use$fast @lda 0,# ;-K 0=slow (1 MHz) @sta vic$speed ;-K set to slow mode endif @lda 3Fh,# @stx RM$command ;-K give command to RAM DISK @sta force$map ; remove I/O area @rts ;-K PAGE ; ; ; setup: @STA DSKCMD+1 ;?K @LDA 2,# ;?K RETRY COUNT @STA vic$data ;?K writes to RAM under ROM @JSR CKOTCM ;?K returns X=0 @LDY dskcmd$lng,# ;+K setup2: @LDA DSKCMD,X ;+K @JSR K$chrout ;+K @INX ;+K @DEY ;+K @BNE setup2 ;+K @JSR K$clrchn ;+K @JSR CKINCM ;+K @BEQ setup3 ;+K @sty io$0 ;+K 2/24 @DEC vic$data ;-K @BEQ setup5 ;-K @jmp disk$changed ;-k ; ; setup5: @LDA 0dh,# ;?K normal read/write error flag @skip2 ;?K ALWAYS ; ; ; setup3: @lda 0,# ;?K get data good flag setup4: @STA vic$data ;?K writes to RAM under ROM @jsr en$kernal ;?K @JMP K$clrchn ;+K page ; ; ; send$fast$cmd: @jsr set$cmd ;?K unit # must have been set already send$fast: @ldx 0,# ;?K @stx force$map ;?K enable the kernal @ldx cmdchn ;+K @jsr K$chkout ;+K @bcs chan$error ;+K @ldx 0,# ;+K sendf: @lda f$cmd$buf,x ;+K @jsr K$chrout ;+K @inx ;+K @dey ;+K @bne sendf ;+K @jsr K$clrchn ;+K @bit serial ;+K @bvc not$fast ;+K @bit d1icr ;+K clear interrupts from chip @rts ;+K chan$error: @lda 0dh,# ;+K get error code @skip2 ;+K not$fast: @lda 0ch,# ;+K get error code @sta vic$data ;+K @jsr clk$hi ;+K @jmp bios$exit ;+K ; ; ; set$cmd: @lda dskcmd+5 ;?K check lsb of unit # @ror a ;?K get lsb to carry bit @bcc unit$0 ;?K @inx ;?K make command for unit 1 unit$0: @stx F$cmd ;?K @rts page ; ; ........not tested........ ; ;rd$buff: ; @sei ; disable interrupts ; @lda vic$data ; @sta adr$1+1 ; save hi part of address ; @lda 0,# ; @sta adr$1 ; save low part of address ; @tax ; get a zero for both indexes ; @tay ; ;rd$buf$1: ; @lda (adr$1),y ; @sta @buffer,x ; @inx ; @iny ; @bne rd$buf$1 ; @rts PAGE ; ; ; set$drv: @lda vic$trk ;-K @jsr binasc ;-K @stx dskcmd+7 ;-K @sta dskcmd+8 ;-K @lda vic$sect ;-K @bmi no$side$1 ;-K @jsr binasc ;-K @stx dskcmd+10 ;-K @sta dskcmd+11 ;-K @jmp set$drv$num ;-K no$side$1: @lda 04h,# ;-K @sta vic$data ;-K @jmp bios$exit ;-K ; ; ; set$drv$f: @lda vic$count ;-K @sta f$rd$count ;-K @lda vic$trk ;-K @sta f$rd$trk @lda vic$sect ;-K @bpl side$0 ;-K @tax ;-K @lda f$cmd ;-K @ora 10h,# ;-K @sta f$cmd ;-K @txa ;-K @and 7fh,# ;-K side$0: @sta f$rd$sect ;-K page ; ; VIC$DRV dev,dat,cmd ; 00000001 device #8-0 8,11,15 ; 00000010 device #9-0 9,12,16 ; 00000100 device #10-0 10,13,17 ; 00001000 device #11-0 11,14,18 ; 10000001 device #8-1 8,11,15 ; 10000010 device #9-1 9,12,16 ; 10000100 device #10-1 10,13,17 ; 10001000 device #11-1 11,14,18 ; set$drv$num: @ldy 8-1,# ;-K start as drive 8 @ldx '0',# ;-K ..unit 0 @lda vic$drv ;-K get requested drv# @bpl unit$nu$0 @inx ;-K make unit 1 unit$nu$0: @iny ;-K add one to the drive # @lsr a ;-K is drive number correct? @bcc unit$nu$0 ;-K no, loop back @stx dskcmd+5 ;-K save unit# to disk cmd string @stx fmtcmd+1 ;-K save unit# to format cmd string @txa @ror a ;-K get lsb to carry bit @lda F$cmd @and 0feh,# @adc 0,# ; set the lsb if carry set (carry cleared) @sta F$cmd @tya ;-K get device # to A @sta devno ;-K save device # @adc 3,# ;-K make the data chan# (carry cleared above) @sta datchn ;-K save data chan# @adc 4,# ;-K make the cmd chan# @sta cmdchn ;-K save cmd chan# @lda serial ;-K @and 0bfh,# ;-K @sta serial ;-K clear the fast serial indicator @rts ;-K page ; ; **** CONVERT BINARY TO ASCII **** ; BINASC: @CLD ;?K @LDX '0',# ;?K @SEC ;?K BA0: @SBC 10,# ;?K @BCC BA1 ;?K @INX ;?K @BCS BA0 ;?K BA1: @ADC 3Ah,# ;?K @RTS ;?K PAGE ; ; **** OPEN DISK COMMAND CHANNEL **** ; set$and$open: @jsr set$drv$num ;-K en$K$open: @jsr en$kernal ;-K opencm: @LDA CMDCHN ;+K @clc ;+K clear the carry to force true closing @JSR K$close ;+K @LDA CMDCHN ;+K @LDX DEVNO ;+K @LDY 15,# ;+K @JSR K$setlfs ;+K @lda 0,# ;+K bank (C128 type) for load and store @sta F$stat ;+K write status byte value = 0 @tax ;+K file name bank (C128 type bank#) @jsr K$setbnk ;+K @ldx write$stat,# ;+K @jsr set$cmd ;+K @lda 4,# ;+K write status command lenght @ldx low(f$cmd$buf),# ;+K @ldy high(f$cmd$buf),# ;+K @JSR K$setnam ;+K @JSR K$open ;+K @bcs misdsk @JSR K$readst @ROL A ;+K GET MSB TO CARRY @BCS MISDSK ;+K DEVICE MISSING IF CARRY SET @bit serial ;+K test for fast device @bvs no$dt$open ;+K do not open data channel if fast ; ; **** OPEN DISK DATA CHANNEL **** ; OPENDT: @LDA DATCHN ;+K @clc ;+K forces true closing of channel @JSR K$close ;+K @LDA DATCHN ;+K @LDX DEVNO ;+K @LDY 8,# ;+K @JSR K$setlfs ;+K @lda 0,# ;+K bank (C128 type) for load and store @tax ;+K file name bank (C128 type bank#) @jsr K$setbnk ;+K @LDA 1,# ;+K @LDX low(POUND),# ;+K @LDY high(POUND),# ;+K @JSR K$setnam ;+K @jsr K$open ;+K @bcs misdsk no$dt$open: @rts page ; ; ; * DEVICE MISSING, CLEAN UP ERROR * ; MISDSK: @LDA 0fh,# ;+K SET ERROR CODE for missing drive @STA vic$data ;+K writes to RAM under ROM @LDA CMDCHN ;+K K$close CHANNEL @clc ;+K force true closing of channel @JSR K$close ;+K @JMP bios$exit ;+K PAGE ; ; **** SELF CORRECTING CHECK IO ROUTINES **** ; CKICM: @JSR OPENCM ;+K CKINCM: @LDX CMDCHN ;+K @JSR K$chkin ;+K @BCS CKICM ;+K @JSR K$chrin ;+K @CMP '0',# ;+K @RTS ;+K ; ; ; CKIDT: @JSR OPENDT ;+K CKINDT: @LDX DATCHN ;+K @JSR K$chkin ;+K @BCS CKIDT ;+K @RTS ;+K ; ; ; CKODT: @JSR OPENDT ;+K CKOTDT: @LDX DATCHN ;+K @JSR K$chkout ;+K @BCS CKODT ;+K @RTS ;+K ; ; ; CKOCM: @jsr OPENCM ;+K CKOTCM: @jsr en$kernal ;?K @LDX CMDCHN ;+K @JSR K$chkout ;+K @BCS CKOCM ;+K @LDX 0,# ;+K @RTS ;+K PAGE ; ; **** OPEN PRINTER CHANNEL **** ; opnprt: @jsr en$kernal ;-K @lda prtno ;+K @clc ;+K @JSR K$close ;+K @lda prtno ;+K @TAX ;+K LDX #4 (or #5) @ldy second$adr ;+K secondary adr passed in vic$trk (normaly=7) @JSR K$setlfs ;+K @LDA 0,# ;+K @JSR K$setnam ;+K @lda 0,# ;+K bank (C128 type) for load and store @tax ;+K file name bank (C128 type bank#) @jsr K$setbnk ;+K @JMP K$open ;+K page ; ; handle all interrupts in BIOS 8502 (throw them away) ; irqs: @lda CIA$1+int$ctrl @lda CIA$2+int$ctrl @lda 0fh,# @sta VIC+25 @pla @sta force$map @pla @tay @pla @tax @pla @rti ; ; ; en$kernal: @ldy 0,# ;?K @sty force$map ;?K @rts ;+K page ; ; ; DSKCMD: db 'U1:8 0 tt ss',CR dskcmd$lng equ $-dskcmd POUND: db '#' FMTCMD: db 'N0:CP/M DISK,65',CR fmtcmd$lng equ $-FMTCMD SETPNT: db 'B-P 8 0',CR setpnt$lng equ $-setpnt ; ; fast command buffer ; f$cmd$buf: db 'U0' ; not set f$cmd: db 0 ; byte 3 F$stat: f$rd$trk: db 1 ; byte 4 f$rd$sect: db 0 ; byte 5 f$rd$count: db 1 ; byte 6 db 0 ; byte 7 db 0 ; byte 8 db 0 ; byte 9 db 0 ; byte 10 db 0 ; byte 11 f$cmd$lng equ 6 ; U0+cmd+track+sector+#sectors write$stat equ 01001100b write$stat$lng equ 4 ; U0+cmd+(status to write) inq$cmd: equ 00000100b inq$cmd$lng equ 3 ; U0+cmd query$cmd: equ 10001010b query$cmd$lng equ 4 ; U0+cmd+(track offset) to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> ThPRTMSG = Y PAGWID = 4F PAGLEN = 17 BACKSPC = N RUBOUT = N BOOTDRV = A MEMTOP = FB BNKSWT = Y COMBAS = E0 LERROR = Y NUMSEGS = 01 MEMSEG00 = 60,3B,00 MEMSEG01 = 00,C0,02 MEMSEG02 = 00,C0,03 MEMSEG03 = 00,C0,04 MEMSEG04 = 00,C0,05 MEMSEG05 = 00,C0,06 MEMSEG06 = 00,C0,07 MEMSEG07 = 00,C0,08 MEMSEG08 = 00,C0,09 MEMSEG09 = 00,C0,0A MEMSEG0A = 00,C0,0B MEMSEG0B = 00,C0,0C MEMSEG0C = 00,C0,0D MEMSEG0D = 00,C0,0E MEMSEG0E = 00,C0,0F MEMSEG0F = 00,C0,10 HASHDRVA = Y HASHDRVB = Y HASHDRVC = Y HASHDRVD = Y HASHDRVE = Y HASHDRVF = Y HASHDRVG = Y HASHDRVH = N HASHDRVI = Y HASHDRVJ = Y HASHDRVK = Y HASHDRVL = Y HASHDRVM = Y HASHDRVN = Y HASHDRVO = Y HASHDRVP = Y ALTBNKSA = Y ALTBNKSB = Y ALTBNKSC = N ALTBNKSD = N ALTBNKSE = N ALTBNKSF = N ALTBNKSG = N ALTBNKSH = N ALTBNKSI = N ALTBNKSJ = N ALTBNKSK = N ALTBNKSL = N ALTBNKSM = N ALTBNKSN = N ALTBNKSO = N ALTBNKSP = N NDIRRECA = 04 NDIRRECB = 04 NDIRRECC = 00 NDIRRECD = 00 NDIRRECE = 00 NDIRRECF = 01 NDIRRECG = 01 NDIRRECH = 00 NDIRRECI = 01 NDIRRECJ = 01 NDIRRECK = 01 NDIRRECL = 01 NDIRRECM = 04 NDIRRECN = 01 NDIRRECO = 01 NDIRRECP = 01 NDTARECA = 01 NDTARECB = 00 NDTARECC = 00 NDTARECD = 00 NDTARECE = 00 NDTARECF = 01 NDTARECG = 01 NDTARECH = 00 NDTARECI = 01 NDTARECJ = 01 NDTARECK = 01 NDTARECL = 01 NDTARECM = 00 NDTARECN = 01 NDTARECO = 01 NDTARECP = 01 ODIRDRVA = A ODIRDRVB = A ODIRDRVC = B ODIRDRVD = B ODIRDRVE = B ODIRDRVF = A ODIRDRVG = A ODIRDRVH = B ODIRDRVI = A ODIRDRVJ = A ODIRDRVK = A ODIRDRVL = A ODIRDRVM = A ODIRDRVN = A ODIRDRVO = A ODIRDRVP = A ODTADRVA = A ODTADRVB = A ODTADRVC = A ODTADRVD = A ODTADRVE = A ODTADRVF = A ODTADRVG = A ODTADRVH = A ODTADRVI = A ODTADRVJ = A ODTADRVK = A ODTADRVL = A ODTADRVM = A ODTADRVN = A ODTADRVO = A ODTADRVP = A OVLYDIRA = Y OVLYDIRB = Y OVLYDIRC = Y OVLYDIRD = Y OVLYDIRE = Y OVLYDIRF = Y OVLYDIRG = Y OVLYDIRH = Y OVLYDIRI = Y OVLYDIRJ = Y OVLYDIRK = Y OVLYDIRL = Y OVLYDIRM = Y OVLYDIRN = Y OVLYDIRO = Y OVLYDIRP = Y OVLYDTAA = Y OVLYDTAB = Y OVLYDTAC = Y OVLYDTAD = Y OVLYDTAE = Y OVLYDTAF = Y OVLYDTAG = Y OVLYDTAH = Y OVLYDTAI = Y OVLYDTAJ = Y OVLYDTAK = Y OVLYDTAL = Y OVLYDTAM = Y OVLYDTAN = Y OVLYDTAO = Y OVLYDTAP = Y CRDATAF = N DBLALV = Y d$trk: db 1 ; byte 4 f$rd$sect: db 0 ; byte 5 f$rd$count: db 1 ; byte 6 db 0 ; byte 7 db 0 ; byte 8 db 0 ; byte 9 db 0 ; byte 10 db 0 ; byte 11 f$cmd$lng equ 6 ; U0+cmd+track+sector+#sectors write$stat equ 01001100b write$stat$lng equ 4 ; U0+cmd+(status to write) inq$cmd: equ 00000100b inq$cmd$lng equ 3 ; U0+cmd query$cmd: equ 10001010b query$cmd$lng equ 4 ; U0+cmd+(track offset) to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> Thera *.prn era *.rel era *.bak rmac cxkrnl $$pz-s rmac cxio $$pz-s rmac cxintr $$pz-s rmac cxramdsk $$pz-s rmac cxkey $$pz-s rmac cxem $$pz-s rmac cxvt $$pz-s rmac cx80 $$pz-s rmac cxprinte $$pz-s rmac cxdisk $$pz-s rmac cxext $$pz-s rmac cxscb $$pz-s mac cxkycode $$pz-s mac fast8502 $$pz-s link bnkbios3[b]=cxkrnl,cxio,cxintr,cxkey,cxem,cxvt,cx80,cxprinte,cxdisk,cxramdsk,cxext,cxscb gencpm auto addbios fast8502 era *.sym era cpm3.sys db 0 ; byte 10 db 0 ; byte 11 f$cmd$lng equ 6 ; U0+cmd+track+sector+#sectors write$stat equ 01001100b write$stat$lng equ 4 ; U0+cmd+(status to write) inq$cmd: equ 00000100b inq$cmd$lng equ 3 ; U0+cmd query$cmd: equ 10001010b query$cmd$lng equ 4 ; U0+cmd+(track offset) to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> Th MAKESYS.DOC 08May87 CP/M 3.0 on the Commodore 128 28May87 To generate a new CPM+.SYS file used by CP/M on the Commodore 128 follow the procedure listed below. You will need a 1581 disk drive for this task. Without a 1581, you will have to make modifications to the procedure to suit your system (refer to the MAKESYS instructions on the 5.25" diskette that accompanies the DRI manual offer). If you're lucky enough to possess a 1750 RAM expander, you could use it (drive M:) in place of the 1581 work disk. This procedure requires a 400K work space. 1. Create a 1581 work diskette, using the FORMAT utility, or start with an empty RAMdisk (drive M:). 2. Copy the following files to the work disk, using the PIP utility: From USER 0: (these are the utilities you will need) RMAC.COM MAC.COM LINK.COM GENCPM.COM ADDBIOS.COM SUBMIT.COM From USER 1: (these are the data files) CX80.ASM CXDISK.ASM CXEM.ASM CXEXT.ASM CXINTR.ASM CXIO.ASM CXKEY.ASM CXKRNL.ASM CXKYCODE.ASM CXPRINTE.ASM CXRAMDSK.ASM CXSCB.ASM CXVT.ASM FAST8502.ASM CPM3.LIB CXEQU.LIB MODEBAUD.LIB X6502.LIB Z80.LIB BNKBDOS3.SPR RESBDOS3.SPR CZ.SUB GENCPM.DAT 3. Enter 'SUBMIT CZ' and the rest is almost automatic. Just answer 'Y' to all the ERASE? prompts. 4. When the process is complete, you will have a CPM+.SYS file that you can copy to any disk from which you want to be able to boot. You also need to copy the Console Command Processor (CCP.COM) from USER 0 to the disk from which you want to boot. 5. Details regarding System Generation can be found in the DRI System Guide. There are several differences to be noted, however, such as somewhat different module names and the implementation of system utilities such as COPYSYS and CPMLDR. USER areas 1 and 2. Read them for details about system generation. Use PIP to backup this disk. DO NOT use this disk for a work disk! e USER command sets the current user number. The disk directory can be divided into distinct groups according to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> Th; Macro Definitions for CP/M3 BIOS Data Structures. ; dtbl - drive table ; dph translate$table, - disk parameter header ; disk$parameter$block, ; checksum$size, (optional) ; alloc$size (optional) ; skew sectors, - skew table ; skew$factor, ; first$sector$number ; dpb physical$sector$size, - disk parameter block ; physical$sectors$per$track, ; number$tracks, ; block$size, ; number$dir$entries, ; track$offset, ; checksum$vec$size (optional) ; Drive Table. Contains 16 one word entries. dtbl macro ?list local ?n ?n set 0 irp ?drv, ?n set ?n+1 dw ?drv endm if ?n > 16 .' Too many drives. Max 16 allowed' exitm endif if ?n < 16 rept (16-?n) dw 0 endm endif endm dph macro ?trans,?dpb,?csize,?asize local ?csv,?alv dw ?trans ; translate table address db 0,0,0,0,0,0,0,0,0 ; BDOS Scratch area db 0 ; media flag dw ?dpb ; disk parameter block if not nul ?csize dw ?csv ; checksum vector else dw 0FFFEh ; checksum vector allocated by endif ; GENCPM if not nul ?asize dw ?alv ; allocation vector else dw 0FFFEh ; alloc vector allocated by GENCPM endif dw 0fffeh,0fffeh,0fffeh ; dirbcb, dtabcb, hash alloc'd ; by GENCPM db 0 ; hash bank if not nul ?csize ?csv ds ?csize ; checksum vector endif if not nul ?asize ?alv ds ?asize ; allocation vector endif endm dpb macro ?psize,?pspt,?trks,?bls,?ndirs,?off,?ncks local ?spt,?bsh,?blm,?exm,?dsm,?drm,?al0,?al1,?cks,?psh,?psm local ?n ;; physical sector mask and physical sector shift ?psh set 0 ?n set ?psize/128 ?psm set ?n-1 rept 8 ?n set ?n/2 if ?n = 0 exitm endif ?psh set ?psh + 1 endm ?spt set ?pspt*(?psize/128) ?bsh set 3 ?n set ?bls/1024 rept 8 ?n set ?n/2 if ?n = 0 exitm endif ?bsh set ?bsh + 1 endm ?blm set ?bls/128-1 ?size set (?trks-?off)*?spt ?dsm set ?size/(?bls/128)-1 ?exm set ?bls/1024 if ?dsm > 255 if ?bls = 1024 .'Error, can''t have this size disk with 1k block size' exitm endif ?exm set ?exm/2 endif ?exm set ?exm-1 ?all set 0 ?n set (?ndirs*32+?bls-1)/?bls rept ?n ?all set (?all shr 1) or 8000h endm ?al0 set high ?all ?al1 set low ?all ?drm set ?ndirs-1 if not nul ?ncks ?cks set ?ncks else ?cks set ?ndirs/4 endif dw ?spt ; 128 byte records per track db ?bsh,?blm ; block shift and mask db ?exm ; extent mask dw ?dsm ; maximum block number dw ?drm ; maximum directory entry number db ?al0,?al1 ; alloc vector for directory dw ?cks ; checksum size dw ?off ; offset for system tracks db ?psh,?psm ; physical sector size shift ; and mask endm ; gcd macro ?m,?n ;; greatest common divisor of m,n ;; produces value gcdn as result ;; (used in sector translate table generation) ?gcdm set ?m ;;variable for m ?gcdn set ?n ;;variable for n ?gcdr set 0 ;;variable for r rept 65535 ?gcdx set ?gcdm/?gcdn ?gcdr set ?gcdm - ?gcdx*?gcdn if ?gcdr = 0 exitm endif ?gcdm set ?gcdn ?gcdn set ?gcdr endm endm skew macro ?secs,?skf,?fsc ;; generate the translate table ?nxtsec set 0 ;;next sector to fill ?nxtbas set 0 ;;moves by one on overflow gcd %?secs,?skf ;; ?gcdn = gcd(?secs,skew) ?neltst set ?secs/?gcdn ;; neltst is number of elements to generate ;; before we overlap previous elements ?nelts set ?neltst ;;counter rept ?secs ;;once for each sector db ?nxtsec+?fsc ?nxtsec set ?nxtsec+?skf if ?nxtsec >= ?secs ?nxtsec set ?nxtsec-?secs endif ?nelts set ?nelts-1 if ?nelts = 0 ?nxtbas set ?nxtbas+1 ?nxtsec set ?nxtbas ?nelts set ?neltst endif endm endm  $*MACRO false equ 0 true equ not false use$fast equ false use$6551 equ false ;true use$vt100 equ false use$1581 equ true banked equ true EXTSYS equ false ; use external system as disk and char I/O pre$release equ false ; start at Jan 1,1978 78 79 80 81 82 83 84 85 86 dt$hx$yr equ 365+365+366+365+365+365+366+365+365 ; 1985 1 2 3 4 5 6 7 8 9 10 11 12 date$hex equ dt$hx$yr+31+28+31+30+28 date macro db '28 May 87' endm ; ; this is only for Pre-Released versions (done in RED) ; warning macro if pre$release db cr,lf,lf db esc,esc,esc,red+20h db 'User Beware:',cr,lf ;1234567890123456789012345678901234567890 db ' This version of the software is a',cr,lf db ' PRE-RELEASE for testing only. It has',cr,lf db ' been tested but has not yet passed QA.',cr,lf db esc,esc,esc,purple+50h endif endm space macro ?x,for ?x equ start start set start+for endm ; ; boot memory map (bank 0 only) ; bios02 equ 3000h ; block$buffer equ 3400h ; uses 2K boot$parm equ 3C00h ; uses about 256 bytes ; ; bank 0 low memory map ; ROM equ 0000h VIC$color equ 1000h ; I/O page only (IO$0 selected) SYS$key$area equ 1000h ; 3 256 byte blocks (allow 4) screen$40 equ 1400h ; 2 X 80 X 25 = 4000 BANK$parm$blk equ 2400h ; allow 0.5K of parameters BIOS8502 equ 2600h ; 1.5K VIC$screen equ 2C00h ; 1K ccp$buffer equ 3000h ; 0c80h (allow 4K) bank0$free equ 4000h ; start of free area in bank 0 ; ; mapped I/O locations ; VIC equ 0D000h ; 8564 SID equ 0D400h ; 6581 MMU equ 0D500h ; 8722 DS8563 equ 0D600h ; 8563 INT$6551 equ 0D700h ; 6551 (added to enginnerring units) VIC$C$H equ 0D800h ; (memory mapped only in IO$0) VIC$C$L equ 01000h ; (memory and i/o mapped in IO$0) CIA1 equ 0DC00h ; 6526 CIA2 equ 0DD00h ; 6526 USART equ 0DE00h ; 6551 (extrn card) RAM$dsk$base equ 0DF00h ; 8726 ; ; Common memory allocation ; int$block equ 0FC00h ; mode 2 interrupt pointers (to FDFDh) parm$block equ 0FD00h ; system parameters @buffer equ 0FE00h ; disk buffer (256 bytes) ; 0FF00h ; to 0FFFFh used by 8502 ; ; the following are C128 system equates ; enable$z80 equ 0FFD0h ; 8502 code return$z80 equ 0FFDCh enable$6502 equ 0FFE0h ; Z80 code return$6502 equ 0FFEEh page start set parm$block+1 ; 1st byte used as Intterrupt pointer space vic$cmd,1 ;; bios8502 command byte space vic$drv,1 ; bios8502 drive (bit 0 set, drv 0) space vic$trk,1 ;; bios8502 track # space vic$sect,1 ;; bios8502 sector # space vic$count,1 ; bios8502 sector count space vic$data,1 ;; bios8502 data byte to/from space cur$drv,1 ; current disk installed to Vir. drive space fast,1 ; bit 0 set, drv 0 is fast. ect. space key$tbl,2 ;; pointer to keyboard table space fun$tbl,2 ;; pointer to function table space color$tbl$ptr,2 ;; pointer to logical color table space fun$offset,1 ;; function # to be preformed space sound$1,2 ;; space sound$2,2 ;; space sound$3,2 ;; space @trk,2 ;; current track number space @dma,2 ;; current DMA address ; ; below here not used by ROM ; space @sect,2 ; current sector number space @cnt,1 ; record count for multisector transfer space @cbnk,1 ; bank for processor operations space @dbnk,1 ; bank for DMA operations space @adrv,1 ; currently selected disk drive space @rdrv,1 ; controller relative disk drive space sys$speed,0 ; byte value 0=1MHz, 1=2 MHz (no 40 column disp) space ccp$count,1 ; number of records in the CCP (not used) space stat$enable,1 ; status line enable ; 7 kybrd, key codes(1), functions(0) ; 6 40 column tracking on(0), off(1) ; 0 disk stat, enable(1), disable(0) space emulation$adr,2 ; address of current emulation space usart$adr,2 ; PTR to 6551 reg (not used before 6 Dec 85) ; CXIO equates space int$hl,2+20 ; interrupt HL hold location space int$stack,0 ; currently only 10*2 used space user$hl$temp,2 ; user function HL hold location space hl$temp,2 ; misc temp storage (used by VECTOR) space de$temp,2 ; misc temp storage (used by VECTOR) space a$temp,1 ; misc temp storage (used by VECTOR) space source$bnk,1 ; inter bank move source bank # space dest$bnk,1 ; inter bank move dest bank # space MFM$tbl$ptr,2 ; pointer to MFM table ; 1st release end (3 June and 1 Aug 85) space prt$conv$1,2 ; pointer to printer 1 ASCII Conversion space prt$conv$2,2 ; pointer to printer 2 ASCII Conversion space key$FX$function,2 space XxD$config,1 ; bit 7 0 = no parity 1 = parity ; bit 6 0 = mark/space 1 = odd/even ; bit 5 0 = space/even 1 = mark/odd ; bit 1 0 = 1 stop bit 1 = 2 stop bits ; bit 0 0 = 7 data bits 1 = 8 data bits space RS232$status,1 ; bit 7, 1=send data, 0=no data ; bit 6, 1=sending data ; bit 5, 1=recv que active ; bit 4, 1=parity error ; bit 3, 1=framing error ; bit 2, 1=recv over run (no used) ; bit 1, 1=receiving data ; bit 0, 1=Data byte ready space xmit$data,1 ; data byte to send space recv$data,1 ; received data byte ; ; The following equates are used by the interrupt driven keyboard handler ; space int$rate,1 ; ; 1st byte is a pointer into table, 2nd to 12th byte represent ; the keyboards current state (active low), NOTE: only ; current if key$buffer is not full ; space key$scan$tbl,12 ; ; keyboard roll over buffer ; key$buf$size equ 8*2 ; must be an even number of bytes space key$get$ptr,2 space key$put$ptr,2 space key$buffer,key$buf$size ; ; software UART recv buffer ; RxD$buf$size equ 64 space RxD$buf$count,1 space RxD$buf$put,1 space RxD$buf$get,1 space RxD$buffer,RxD$buf$size space tick$vol,1 INT$vector equ 0FDFDh ;; contains a JMP int$handler ; (in common) page ;===> 40 column misc parm start set BANK$parm$blk space temp$1,2 ;; space @off40,0 ;; space cur$offset,2 ;; space old$offset,1 ;; space prt$flg,1 ;; space flash$pos,2 ;; ; ;===> 40 column position and color storage space paint$size,1 ;; space char$adr$40,2 ;; space char$col$40,1 ;; space char$row$40,1 ;; space attr$40,1 ;; space bg$color$40,1 ;; space bd$color$40,1 ;; space rev$40,1 ;; ; ;===> 80 column position and color storage space char$adr,2 ;; space char$col,1 ;; space char$row,1 ;; space current$atr,1 ;; space bg$color$80,1 ;; space char$color$80,1 ;; ; ROM uses localtions above this point ; ;===> Emulation parameters space parm$base,2 space parm$area$80,3 ; ds 2 ; 80 column exec$adr ; ds 1 ; 80 column row # space parm$area$40,3 ; ds 2 ; 40 column exec$adr ; ds 1 ; 40 column row # space buffer$80$col,40*2 ; ;===> CXIO parameters ; int$count not used by releases past 10 Oct 85 space int$count,1 ; one added every 1/60th sec space key$buf,1 ; ;===> CXKEYS parameters space key$down$tbl,11*2 ; not used any more (int code) ;;;;; free space above, new interrupt driven code does not require this space ; control$keys equ key$down$tbl+11*2 ; byte, not used any more (int code) space commodore$mode,1 space msgptr,2 space offset,1 space cur$pos,1 space string$index,1 ; 1st release end (3 June 85) space sys$freq,1 ; -1=50Hz, 0=60Hz ; 2nd release end (1 Aug 85) page ;===> temp ROM boot data storage blk$ptr$cnt equ 32 start set boot$parm space load$count,2 ; number of 128 byte blocks to load space ld$blk$ptr,2 ; current sector dma pointer space blk$unld$ptr,2 ; read memory block (1k,2K) pointer space block$size,1 ; block size (1K=32 or 2K=64) space block$end,2 ; allow 48K cpm.sys to load space block$ptrs,blk$ptr$cnt ; end of block load buffer (+1K or +2K) space info$buffer,12 ; CPM3.sys load adr's and counts space ext$num,1 ; CPM3.SYS current ext # space retry,1+64 space boot$stack,0 ; allow 64 bytes of stack ;===> special equates used by CXKEY special equ 00010111b SF$exit equ 001h ; RETURN KEY SF$insert equ 028h ; PLUS KEY SF$delete equ 02Bh ; MINUS KEY alpha$toggle equ 03Dh ; commodore key alt$key equ 050h ; alterant key SF$left equ 055h ; left arrow key lf$arrow equ 055h ; left arrow key SF$right equ 056h ; right arrow key rt$arrow equ 056h ; right arrow key buff$large equ 25 buff$small equ 7 buff$pos equ 7 page ;===> External RS232 interface controls ; rxd$6551 equ 0 ; read ; txd$6551 equ 0 ; write ; status$6551 equ 1 ; read ; reset$6551 equ 1 ; write ; command$6551 equ 2 ; read/write ; control$6551 equ 3 ; read/write txrdy equ 10h rxrdy equ 08h cmd$init equ 0bh ; no parity, enable txd + rxd, interrupts off cntr$init$19200 equ 1Fh ; 1 stop, 8 bits, 19200 baud cntr$init$9600 equ 1Eh ; 1 stop, 8 bits, 9600 baud (internal) cntr$init$600 equ 17h ; 600 baud ;===> memory management loactions mmu$start equ MMU conf$reg equ MMU ; 3eh conf$reg$1 equ MMU+1 ; 3fh conf$reg$2 equ MMU+2 ; 7fh conf$reg$3 equ MMU+3 ; 3eh conf$reg$4 equ MMU+4 ; 7eh mode$reg equ MMU+5 ; b1h ram$reg equ MMU+6 ; 0bh 16K top Common page$0$l equ MMU+7 ; 00h page$0$h equ MMU+8 ; 01h page$1$l equ MMU+9 ; 01h page$1$h equ MMU+10 ; 01h mmu$version equ MMU+11 ; ??h enable$C64 equ 11110001b ; FS=0 z80$off equ 10110001b ; value to be write to enable 8502 z80$on equ 10110000b fast$rd$en equ Z80$on+0 ; fast serial read fast$wr$en equ Z80$on+8 ; fast serial write common$4K equ 09h ; top 4K common common$8K equ 0ah ; top 8K common common$16K equ 0bh ; top 16K common ;===> preconfiguration maps force$map equ 0ff00h bank$0 equ 0ff01h ; 3fh bank$1 equ 0ff02h ; 7fh io equ 0ff03h ; 3eh io$0 equ 0ff03h ; 3eh io$1 equ 0ff04h ; 7eh page ;===> 80 column display equates DS$index$reg equ DS8563 DS$status$reg equ DS8563 DS$data$reg equ DS8563+1 ;===> register pointers DS$cursor$high equ 14 DS$cursor$low equ 15 DS$rw$ptr$high equ 18 DS$rw$ptr$low equ 19 DS$rw$data equ 31 DS$color equ 26 ;===> status bits DS$ready equ 80h DS$lt$pen equ 40h ;===> display memory layout (16K) 0-3fffh DS$screen equ 0000h DS$attribute equ 0800h DS$char$def equ 2000h ; ;===> VIC equates (8564) ; VIC$blk equ VIC+17 ; bit 4 = 1 for screen on VIC$blk$msk equ 00010000b ; VIC$key$row equ VIC+47 ; output VIC$speed equ VIC+48 ; bit 0 = 1 for fast VIC$speed$msk equ 00000001b ; ; vic colors black equ 0 white equ 1 red equ 2 cyan equ 3 purple equ 4 green equ 5 blue equ 6 yellow equ 7 orange equ 8 brown equ 9 lt$red equ 10 dark$grey equ 11 med$gray equ 12 lt$green equ 13 lt$blue equ 14 lt$grey equ 15 page RM$status equ RAM$dsk$base ;read only register ; bit 7 Interrupt pending if 1 ; 6 Transfer complete if 1 ; 5 Block verify error if 1 ; note: bits 5-7 are cleared when read ; 4 128K if 0, 512K if 1 ; 3-0 Version # ; RM$command equ RAM$dsk$base+1 ;r/w ; bit 7 execute per current config. if set ; 6 reserved ; 5 enable auto reload if set (restores all register to ; value before command was done, else point to ; next byte to read/write.) ; 4 disable FF00 decode if set (do operation after command writen) ; 3,2 reserved ; 1,0 00 = transfer C128 --> Ram Disk ; 01 = Transfer C128 <-- Ram Disk ; 10 = swap C128 <-> Ram Disk ; 11 = Verify C128 = Ram Disk ; RM$128$low equ RAM$dsk$base+2 ;r/w ; bits 0 to 7 of C128 address ; RM$128$mid equ RAM$dsk$base+3 ;r/w ; bits 8 to 15 of the C128 address ; RM$ext$low equ RAM$dsk$base+4 ;r/w ; bits 0 to 7 of Ram Disk address ; RM$ext$mid equ RAM$dsk$base+5 ;r/w ; bits 8 to 15 of Ram Disk address ; RM$ext$hi equ RAM$dsk$base+6 ;r/w ; bit 16 of Ram Disk address if 128K version ; bits 16 to 18 of Ram Disk address if 512K version ; RM$count$low equ RAM$dsk$base+7 ;r/w ; low byte transfer count (bits 0-7) ; RM$count$hi equ RAM$dsk$base+8 ;r/w ; hi byte transfer count (bits 8-15) ; RM$intr$mask equ RAM$dsk$base+9 ;r/w ; bit 7 1=enable chip interrupts ; 6 1=enable end of block interrupts ; 5 1=enable verify error interrupts ; RM$control equ RAM$dsk$base+10 ;r/w ; bit 7,6 00 Increment both addresses (default) ; 01 Fix expansion address ; 10 Fix C128 address ; 11 Fix both addresses ; page ;===> CIA equates Data$a equ 00h Data$b equ 01h Data$dir$a equ 02h Data$dir$b equ 03h timer$a$low equ 04h timer$a$high equ 05h timer$b$low equ 06h timer$b$high equ 07h tod$sec$60 equ 08h tod$sec equ 09h tod$min equ 0ah tod$hrs equ 0bh sync$data equ 0ch int$ctrl equ 0dh cia$ctrl$a equ 0eh cia$ctrl$b equ 0fh CIA$hours equ CIA1+tod$hrs key$row equ CIA1+Data$a ; output key$col equ CIA1+Data$b ; input data$hi equ 4 ; RS232 data line HI data$low equ 0 ; RS232 data line LOW lf$shift$key equ 80h rt$shift$key equ 10h commodore$key equ 20h control$key equ 04h type$lower equ 0 type$upper equ 1 type$shift equ 2 type$cntrl equ 3 type$field equ 00000011b page bnk1 equ 1 page0 equ 0 page1 equ 1 MMU$tbl$M macro db 3fh,3fh,7fh,3eh,7eh ; config reg's db z80$on,common$8K ; mode & mem db page0,bnk1,page1,bnk1 ; page reg's endm page ; ; ROM functions ; TJMP macro x rst 2 ! db x endm TCALL macro x mvi l,x ! rst 4 endm RJMP macro x rst 3 ! db x endm RCALL macro x mvi l,x ! rst 5 endm FR$40 equ 2 ; offset to 40 column ROM functions FR$wr$char equ 00h ; D=char auto advance FR$cursor$pos equ 04h ; B=row, C=column FR$cursor$up equ 08h FR$cursor$down equ 0Ch FR$cursor$left equ 10h FR$cursor$rt equ 14h FR$do$cr equ 18h FR$CEL equ 1Ch FR$CES equ 20h FR$char$ins equ 24h FR$char$del equ 28h FR$line$ins equ 2Ch FR$line$del equ 30h FR$color equ 34h ; B=color FR$attr equ 38h ; B=bit to set/clear, C=bit value FR$rd$chr$atr equ 3Ch ; in D=row, E=col ; out H=row, L=col, B=char, C=attr(real) FR$wr$chr$atr equ 40h ; in D=row, E=col, B=char, C=attr(real) ; out H=row, L=col FR$rd$color equ 44h ;FR$wr$color equ 48h ; equ 4Ch page ; FR$trk$sect equ 50h FR$check$CBM equ 52h FR$bell equ 54h ; equ 56h ; equ 58h ; equ 5Ah ; equ 5Ch ; equ 5Eh FR$trk$40 equ 60h FR$set$cur$40 equ 62h FR$line$paint equ 64h FR$screen$paint equ 66h FR$prt$msg$both equ 68h FR$prt$de$both equ 6Ah FR$update$it equ 6Ch ; equ 6Eh FR$ASCII$to$pet equ 70h FR$cur$adr$40 equ 72h FR$cur$adr$80 equ 74h FR$look$color equ 76h ; equ 78h FR$blk$fill equ 7Ah ; HL passed on the stack FR$blk$move equ 7Ch ; " FR$char$inst equ 7Eh ; " ; ; fixed ROM locations ; R$cmp$hl$de equ 100h-6 R$write$memory equ 180h+0 R$read$memory equ 180h+3 R$set$update$adr equ 180h+6 R$wait equ 180h+9 R$status$color$tbl equ 1000h-246-16 R$color$convert$tbl equ 1000h-230-16 page ; ; Disk type byte definition ; ; bit 7 0=GCR, 1=MFM ; ; if bit 7 is 1 (MFM) ; 6 C0=0, C1=1 (side 2 #, 0 to (n/2)-1 or n/2 to n-1) ; 5,4 00=128, 01=256, 10=512, 11=1024 byte/sector ; 3,2,1 disk type (MFM) ; 0 starting sector # ( 0 or 1) ; ; if bit 7 is 0 (GCR) ; 6 unused (set to 0) ; 5,4 01 (256 byte sectors) (for 1541or 1571) ; 10 (512 byte sectors) (for 1581) ; 3,2,1 disk type (GCR) ; Type0 = none, set track and sector as passed ; Type1 = C64 CP/M type disk (1541-71) ; Type2 = C128 CP/M type disk (1541-71) ; 0 unused (set to 0) MFM equ 1*128 C0 equ 0*64 ; 2nd side start at begining C1 equ 1*64 ; 2nd side continues from first C1$bit equ 6 Type0 equ 0*2 ; (MFM) top, bottom then next track ; (TRK# 0 to (34 or 39)) Type1 equ 1*2 ; (MFM) top (trk 0 even), bottom (trk 1 odd) ; (TRK# 0 to (69 or 79)) Type2 equ 2*2 ; (MFM) top TRK# 0 to 39, bottom TRK# 40 to 79 ; (TRK# on back start at 39 and go to 0) Type7 equ 7*2 ; (MFM) pass the byte values supplied in @trk ; and @sect TypeX equ 7*2 S0 equ 0*1 ; start at sector 0 S1 equ 1*1 ; start at sector 1 S128 equ 0*16 S256 equ 1*16 S512 equ 2*16 S1024 equ 3*16 ; dsk$none equ Type0+S256 ; access to any sector on the disk dsk$c64 equ Type1+S256 dsk$c128 equ Type2+S256 dsk$1581 equ Type2+S512 dir$track equ 18 ; C64 disk dir track c1581$dir$trk equ 39 ; C1581 disk dir track page ; ; 6510 commands ; vic$reset equ -1 ; reboot C128 vic$init equ 0 ; initilize the bios8502 vic$rd equ 1 ; read one sector of data (256 bytes) vic$wr equ 2 ; write one sector of data vic$rdF equ 3 ; set-up for fast read (many sectors) vic$wrF equ 4 ; set-up for fast write vic$test equ 5 ; test current disk in drive vic$query equ 6 ; get start sectors and #sector/trk vic$prt equ 7 ; print data character vic$frmt equ 8 ; format a disk (1541) vic$user$fun equ 9 vic$RM$rd equ 10 ; RAM disk read vic$RM$wr equ 11 ; RAM disk write ; ; control charactors ; eom equ 00h bell equ 07h bs equ 08h lf equ 0ah cr equ 0dh xon equ 11h xoff equ 13h esc equ 1bh  ;1234567890123456789012345678901234567890 db ' This version of the software is a',cr,lf db ' PRE-RELEASE for testing only. It has',cr,lf db ' been tested but has not yet passed QA.',cr,lf db esc,esc,esc,purple+50h endif endm space macro ?x,for ?x equ start start set start+for endm ; ; boot memory map (bank 0 only) ; bios02 equ 3000h ; ; This macro library is to be used with DRI's MAC or RMAC ; (MAC and RMAC are registered trademarks of Digital Research) ; ; The code structure is the same as normal 6502 asmabler ; with the following differences: ; ; Hex numbers '$00' are replaced with a number followed by an h ; i.e. normal 8080 type numbers (also have binary, and octal) ; ; The immediate instruction's format is different. Below is an ; example: ; normal 6502 ASM LIB 6502 ASM ; lda #$A5 lda 0A5h,# ; ; Written by Von Ertwine ; 26 July 84 ; xaaa macro @W,@Y,@Z if nul @Z if @Y<256 db @W+4,@Y else db @W+12 dw @Y endif else if '&@Z'='X)' db @W,@Y&) else if '&@Z'='X' if @Y<256 db @W+20,@Y else db @W+28 dw @Y endif else if '&@Z'='Y' @A set 0 irpc @x,@y if '&@X'='(' @A set 1 endif endm if @A=1 db @W+16,@Y else db @W+24 dw @Y endif else if '&@Z'='#' if @Y<256 db @W+8,@Y else db @W,0,0 'Error' endif endif endif endif endif endif endm xbb macro @W,@Y,@Z @A set 0 if not nul @Z @A set 16 if (@W=86h) or (@W=84h) if @Y>256 'Error' endif endif endif if @Y<256 db @W+@A,@Y else db @W+@A+8 dw @Y endif endm xbbb macro @W,@Y,@Z if NUL @Z @A set 0 irpc @X,@Y @A set @A+1 endm if @A=1 if '&@Y'='A' db @W+8 else if @Y<256 db @W+4,@Y else db @W+12 dw @Y endif endif else if @Y<256 db @W+4,@Y else db @W+12 dw @Y endif endif else if @Y<256 db @W+20,@Y else db @W+28 dw @Y endif endif endm xcc macro @W,@Y,@Z if NUL @Z if @Y<256 db @W+4,@Y else db @W+12 dw @Y endif else if '&@Z'='#' db @W,@Y else 'Error' endif endif endm xddd macro @W,@Y,@Z if NUL @Z if @Y<256 db @W+4,@Y else db @W+12 dw @Y endif else if '&@Z'='#' db @W,@Y else if @Y<256 db @W+20,@Y else db @W+28 dw @Y endif endif endif endm @adc macro @u,@v xaaa 61h,@u,@v endm @and macro @u,@v xaaa 21h,@u,@v endm @asl macro @u,@v xbbb 2,@u,@v endm @bcc macro @u db 90h,@u-$-1 endm @bcs macro @u db 0b0h,@u-$-1 endm @beq macro @u db 0f0h,@u-$-1 endm @bit macro @u if @u<256 db 24h,@u else db 2ch dw @u endif endm @bmi macro @u db 30h,@u-$-1 endm @bne macro @u db 0d0h,@u-$-1 endm @bpl macro @u db 10h,@u-$-1 endm @brk macro db 00h endm @bvc macro @u db 50h,@u-$-1 endm @bvs macro @u db 70h,@u-$-1 endm @clc macro db 018h endm @cld macro db 0d8h endm @cli macro db 058h endm @clv macro db 0b8h endm @cmp macro @u,@v xaaa 0c1h,@u,@v endm @cpx macro @u,@v xcc 0e0h,@u,@v endm @cpy macro @u,@v xcc 0c0h,@u,@v endm @dec macro @u,@v xbb 0c6h,@u,@v endm @dex macro db 0cah endm @dey macro db 088h endm @eor macro @u,@v xaaa 41h,@u,@v endm @inc macro @u,@v xbb 0e6h,@u,@v endm @inx macro db 0e8h endm @iny macro db 0c8h endm @jmp macro @u @A set 0 irpc @X,@u if '&@X'='(' @A set 20h endif endm db 4ch+@A dw @U endm @jsr macro @u db 20h dw @u endm @lda macro @u,@v xaaa 0a1h,@u,@v endm @ldx macro @u,@v xddd 0a2h,@u,@v endm @ldy macro @u,@v xddd 0a0h,@u,@v endm @lsr macro @u,@v xbbb 42h,@u,@v endm @nop macro db 0eah endm @ora macro @u,@v xaaa 1,@u,@v endm @pha macro db 048h endm @php macro db 008h endm @pla macro db 068h endm @plp macro db 028h endm @rol macro @u,@v xbbb 22h,@u,@v endm @ror macro @u,@v xbbb 62h,@u,@v endm @rti macro db 040h endm @rts macro db 060h endm @sbc macro @u,@v xaaa 0e1h,@u,@v endm @sec macro db 038h endm @sed macro db 0f8h endm @sei macro db 078h endm @sta macro @u,@v xaaa 81h,@u,@v endm @stx macro @u,@v xbb 86h,@u,@v endm @sty macro @u,@v xbb 84h,@u,@v endm @tax macro db 0aah endm @tay macro db 0a8h endm @tsx macro db 0bah endm @txa macro db 08ah endm @txs macro db 09ah endm @tya macro db 098h endm @skip1 macro db 024h endm @skip2 macro db 02ch endm  Ơ0 , ܮ0x 0)Ъ 0 0)` 0 !`Iݩ, ` ܭ ݩhhhh@0U0Le USER command sets the current user number. The disk directory can be divided into distinct groups according to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> Th; ; Z80 JR instructiuons fixed 5/11/85 VCE ; ; ; @CHK MACRO USED FOR CHECKING 8 BIT DISPLACMENTS ; @CHK MACRO ?DD ;; USED FOR CHECKING RANGE OF 8-BIT DISP.S IF (?DD GT 7FH) AND (?DD LT 0FF80H) 'DISPLACEMENT RANGE ERROR - Z80 LIB' ENDIF ENDM LDX MACRO ?R,?D @CHK ?D DB 0DDH,?R*8+46H,?D ENDM LDY MACRO ?R,?D @CHK ?D DB 0FDH,?R*8+46H,?D ENDM STX MACRO ?R,?D @CHK ?D DB 0DDH,70H+?R,?D ENDM STY MACRO ?R,?D @CHK ?D DB 0FDH,70H+?R,?D ENDM MVIX MACRO ?N,?D @CHK ?D DB 0DDH,36H,?D,?N ENDM MVIY MACRO ?N,?D @CHK ?D DB 0FDH,36H,?D,?N ENDM LDAI MACRO DB 0EDH,57H ENDM LDAR MACRO DB 0EDH,5FH ENDM STAI MACRO DB 0EDH,47H ENDM STAR MACRO DB 0EDH,4FH ENDM LXIX MACRO ?NNNN DB 0DDH,21H DW ?NNNN ENDM LXIY MACRO ?NNNN DB 0FDH,21H DW ?NNNN ENDM LDED MACRO ?NNNN DB 0EDH,5BH DW ?NNNN ENDM LBCD MACRO ?NNNN DB 0EDH,4BH DW ?NNNN ENDM LSPD MACRO ?NNNN DB 0EDH,07BH DW ?NNNN ENDM LIXD MACRO ?NNNN DB 0DDH,2AH DW ?NNNN ENDM LIYD MACRO ?NNNN DB 0FDH,2AH DW ?NNNN ENDM SBCD MACRO ?NNNN DB 0EDH,43H DW ?NNNN ENDM SDED MACRO ?NNNN DB 0EDH,53H DW ?NNNN ENDM SSPD MACRO ?NNNN DB 0EDH,73H DW ?NNNN ENDM SIXD MACRO ?NNNN DB 0DDH,22H DW ?NNNN ENDM SIYD MACRO ?NNNN DB 0FDH,22H DW ?NNNN ENDM SPIX MACRO DB 0DDH,0F9H ENDM SPIY MACRO DB 0FDH,0F9H ENDM PUSHIX MACRO DB 0DDH,0E5H ENDM PUSHIY MACRO DB 0FDH,0E5H ENDM POPIX MACRO DB 0DDH,0E1H ENDM POPIY MACRO DB 0FDH,0E1H ENDM EXAF MACRO DB 08H ENDM EXX MACRO DB 0D9H ENDM XTIX MACRO DB 0DDH,0E3H ENDM XTIY MACRO DB 0FDH,0E3H ENDM LDI MACRO DB 0EDH,0A0H ENDM LDIR MACRO DB 0EDH,0B0H ENDM LDD MACRO DB 0EDH,0A8H ENDM LDDR MACRO DB 0EDH,0B8H ENDM CCI MACRO DB 0EDH,0A1H ENDM CCIR MACRO DB 0EDH,0B1H ENDM CCD MACRO DB 0EDH,0A9H ENDM CCDR MACRO DB 0EDH,0B9H ENDM ADDX MACRO ?D @CHK ?D DB 0DDH,86H,?D ENDM ADDY MACRO ?D @CHK ?D DB 0FDH,86H,?D ENDM ADCX MACRO ?D @CHK ?D DB 0DDH,8EH,?D ENDM ADCY MACRO ?D @CHK ?D DB 0FDH,8EH,?D ENDM SUBX MACRO ?D @CHK ?D DB 0DDH,96H,?D ENDM SUBY MACRO ?D @CHK ?D DB 0FDH,96H,?D ENDM SBCX MACRO ?D @CHK ?D DB 0DDH,9EH,?D ENDM SBCY MACRO ?D @CHK ?D DB 0FDH,9EH,?D ENDM ANDX MACRO ?D @CHK ?D DB 0DDH,0A6H,?D ENDM ANDY MACRO ?D @CHK ?D DB 0FDH,0A6H,?D ENDM XORX MACRO ?D @CHK ?D DB 0DDH,0AEH,?D ENDM XORY MACRO ?D @CHK ?D DB 0FDH,0AEH,?D ENDM ORX MACRO ?D @CHK ?D DB 0DDH,0B6H,?D ENDM ORY MACRO ?D @CHK ?D DB 0FDH,0B6H,?D ENDM CMPX MACRO ?D @CHK ?D DB 0DDH,0BEH,?D ENDM CMPY MACRO ?D @CHK ?D DB 0FDH,0BEH,?D ENDM INRX MACRO ?D @CHK ?D DB 0DDH,34H,?D ENDM INRY MACRO ?D @CHK ?D DB 0FDH,34H,?D ENDM DCRX MACRO ?D @CHK ?D DB 0DDH,035H,?D ENDM DCRY MACRO ?D @CHK ?D DB 0FDH,35H,?D ENDM NEG MACRO DB 0EDH,44H ENDM IM0 MACRO DB 0EDH,46H ENDM IM1 MACRO DB 0EDH,56H ENDM IM2 MACRO DB 0EDH,5EH ENDM BC EQU 0 DE EQU 2 HL EQU 4 IX EQU 4 IY EQU 4 DADC MACRO ?R DB 0EDH,?R*8+4AH ENDM DSBC MACRO ?R DB 0EDH,?R*8+42H ENDM DADX MACRO ?R DB 0DDH,?R*8+09H ENDM DADY MACRO ?R DB 0FDH,?R*8+09H ENDM INXIX MACRO DB 0DDH,23H ENDM INXIY MACRO DB 0FDH,23H ENDM DCXIX MACRO DB 0DDH,2BH ENDM DCXIY MACRO DB 0FDH,2BH ENDM BIT MACRO ?N,?R DB 0CBH,?N*8+?R+40H ENDM SETB MACRO ?N,?R DB 0CBH,?N*8+?R+0C0H ENDM RES MACRO ?N,?R DB 0CBH,?N*8+?R+80H ENDM BITX MACRO ?N,?D @CHK ?D DB 0DDH,0CBH,?D,?N*8+46H ENDM BITY MACRO ?N,?D @CHK ?D DB 0FDH,0CBH,?D,?N*8+46H ENDM SETX MACRO ?N,?D @CHK ?D DB 0DDH,0CBH,?D,?N*8+0C6H ENDM SETY MACRO ?N,?D @CHK ?D DB 0FDH,0CBH,?D,?N*8+0C6H ENDM RESX MACRO ?N,?D @CHK ?D DB 0DDH,0CBH,?D,?N*8+86H ENDM RESY MACRO ?N,?D @CHK ?D DB 0FDH,0CBH,?D,?N*8+86H ENDM JR MACRO ?N DB 18H,?N-$-1 @CHK ?N-$ ENDM JRC MACRO ?N DB 38H,?N-$-1 @CHK ?N-$ ENDM JRNC MACRO ?N DB 30H,?N-$-1 @CHK ?N-$ ENDM JRZ MACRO ?N DB 28H,?N-$-1 @CHK ?N-$ ENDM JRNZ MACRO ?N DB 20H,?N-$-1 @CHK ?N-$ ENDM DJNZ MACRO ?N DB 10H,?N-$-1 @CHK ?N-$ ENDM PCIX MACRO DB 0DDH,0E9H ENDM PCIY MACRO DB 0FDH,0E9H ENDM RETI MACRO DB 0EDH,4DH ENDM RETN MACRO DB 0EDH,45H ENDM INP MACRO ?R DB 0EDH,?R*8+40H ENDM OUTP MACRO ?R DB 0EDH,?R*8+41H ENDM INI MACRO DB 0EDH,0A2H ENDM INIR MACRO DB 0EDH,0B2H ENDM IND MACRO DB 0EDH,0AAH ENDM INDR MACRO DB 0EDH,0BAH ENDM OUTI MACRO DB 0EDH,0A3H ENDM OUTIR MACRO DB 0EDH,0B3H ENDM OUTD MACRO DB 0EDH,0ABH ENDM OUTDR MACRO DB 0EDH,0BBH ENDM RLCR MACRO ?R DB 0CBH, 00H + ?R ENDM RLCX MACRO ?D @CHK ?D DB 0DDH, 0CBH, ?D, 06H ENDM RLCY MACRO ?D @CHK ?D DB 0FDH, 0CBH, ?D, 06H ENDM RALR MACRO ?R DB 0CBH, 10H+?R ENDM RALX MACRO ?D @CHK ?D DB 0DDH, 0CBH, ?D, 16H ENDM RALY MACRO ?D @CHK ?D DB 0FDH, 0CBH, ?D, 16H ENDM RRCR MACRO ?R DB 0CBH, 08H + ?R ENDM RRCX MACRO ?D @CHK ?D DB 0DDH, 0CBH, ?D, 0EH ENDM RRCY MACRO ?D @CHK ?D DB 0FDH, 0CBH, ?D, 0EH ENDM RARR MACRO ?R DB 0CBH, 18H + ?R ENDM RARX MACRO ?D @CHK ?D DB 0DDH, 0CBH, ?D, 1EH ENDM RARY MACRO ?D @CHK ?D DB 0FDH, 0CBH, ?D, 1EH ENDM SLAR MACRO ?R DB 0CBH, 20H + ?R ENDM SLAX MACRO ?D @CHK ?D DB 0DDH, 0CBH, ?D, 26H ENDM SLAY MACRO ?D @CHK ?D DB 0FDH, 0CBH, ?D, 26H ENDM SRAR MACRO ?R DB 0CBH, 28H+?R ENDM SRAX MACRO ?D @CHK ?D DB 0DDH, 0CBH, ?D, 2EH ENDM SRAY MACRO ?D @CHK ?D DB 0FDH, 0CBH, ?D, 2EH ENDM SRLR MACRO ?R DB 0CBH, 38H + ?R ENDM SRLX MACRO ?D @CHK ?D DB 0DDH, 0CBH, ?D, 3EH ENDM SRLY MACRO ?D @CHK ?D DB 0FDH, 0CBH, ?D, 3EH ENDM RLD MACRO DB 0EDH, 6FH ENDM RRD MACRO DB 0EDH, 67H ENDM  page ; ************************************************* ; - - ; - BIOS8502 code (for read only) - ; - - ; ************************************************* ; ; 10 May 85 ; ; COMMON EQUATES ; pointer equ 20h datchn equ 11 ; use data channel #11 cmdchn equ 15 ; use comand channel #15 ; ; KERNAL EQUATES ; serial equ 00A1Ch D2PRA equ 0DD00h D1SDR equ 0DC0Ch D1ICR equ 0DC0Dh clk$bit equ 10h K$set$bnk equ 0FF68h K$setlfs equ 0FFBAh ; setup a logical file ;I A=logical file # ; X=device # (0-31) ; Y=seconday command (FF if nane) K$setnam equ 0FFBDh ; set up file name for OPEN ;I A=name length ; X=low byte pointer to name ; Y=high byte pointer to name K$open equ 0FFC0h ; open a logical file (after SETLFS & SETNAM) ;O A = error # (1,2,4,5,6,240) K$chkout equ 0FFC9h ; open a channel for output ;I X = logical file # ;O A = error #(0,3,5,7) K$clrchn equ 0FFCCh ; clears ALL I/O channel K$chkin equ 0FFC6h ; open a channel for input ;I X = logical file # ;O A = errors #(0,3,5,6) K$chrin equ 0FFCFh ; get a character from input channel ;O A=input character K$chrout equ 0FFD2h ; output a character to output channel ;I A =output char K$clall equ 0FFE7h ; close all open files K$close equ 0FFC3h ; close a logical file ;I A = logical channel # to be closed ;O A = error #(0,240) K$readst equ 0FFB7h ; read status byte ;O A = status PAGE ; ; ; **** THIS IS THE COMMAND LOOP **** ; boot$02$code: @lda 0,# ; turn on the kernal @sta force$map ; @jmp (0fffch) ; jmp to its start boot$size equ $-boot$02$code BB equ bios$02-$ ; BIOS BIAS ; bios$65$code: @lda 0,# ;-K @sta vic$data ;-K @JSR VICIO+BB ;-K go find and do requested operation CMDLP: @sei @lda 3eh,# ;?K set up Z80 memory map as required @sta force$map ;-K @jmp enable$z80 ;-K PAGE ; ; ; ; ; **** IO COMMAND DISPATCH ROUTINE **** ; VICIO: @CLD ;-K clear to binary mode @LDA vic$cmd ;-K get the command @bne read ;-K 0=initialize ; 1=read page ; ; ; initilize: ; initialize the 8502 @ldx 0,# ;-K @stx force$map ;-K enable the kernal @stx VIC+26 ;+K turn off VIC interrupts @ldx low(irqs+BB),# @ldy high(irqs+BB),# @stx 314h ;+K IRQ vector @sty 315h @stx 316h ;+K BRK vector @sty 317h @stx 318h ;+K NMI vector @sty 319h @jmp opencm+BB ;+K go open channel to disk drive PAGE ; ; **** DISK SECTOR READ **** ; READ: @lda @dma ;-K @sta pointer ;-K @lda @dma+1 ;-K @sta pointer+1 ;-K setdrv: @lda vic$trk ;-K @sta F$rd$trk+BB ;-K @JSR BINASC+BB ;-K @STX dskcmd$T$h+BB ;-K @STA dskcmd$T$l+BB ;-K @lda vic$sect ;-K @sta F$rd$sect+BB ;-K @JSR BINASC+BB ;-K @STX dskcmd$S$h+BB ;-K @STA dskcmd$S$l+BB ;-K @lda fast ;-K @bne read$F ;-K @sta force$map ;-K A=0 if we did not branch @ldx datchn,# ;+K @jsr K$chkin ;+K @bcs disk$changed ;+K @jsr K$clrchn ;+K clear the input channel for now @JSR SETUP+BB ;+K @JSR CKINDT+BB ;+K @ldy 0,# ;+K READ1: @JSR K$chrin ;+K get a byte from the KERNAL @STA (pointer),y ;-K save it to the DMA pointer @iny ;+K advance the buffer pointer @BNE READ1 ;+K loop back if not past buf end @jmp K$clrchn ;+K CLEAR CHANNEL DISK$CHANGED: @lda 0FFh,# ;?K @skip2 fst$error: @lda 0dh,# @sta vic$data ;?K @jmp CMDLP+BB ; ; ; read$F: @lda 0,# ;-K @sta force$map ;-K @ldx cmdchn,# ;+K @jsr K$chkout ;+K @bcs fst$error ;+K ; @ldx 0,# ;+K @ldy Fcmd$lng,# ;+K sendf: @lda Fcmd$buf+BB-1,y ;+K @jsr K$chrout ;+K ; @inx @dey @bne sendf @jsr K$clrchn ;+K @bit D1ICR ;+K @ldx F$rd$count+BB ;+K rd$sector: @jsr read$byte+BB ;+K @and 0eh,# ;+K mask off error bits @bne fst$error @ldy 0,# rd$buffer: @jsr read$byte+BB ;+K @sta (pointer),y ;+K @iny ;+K @bne rd$buffer ;+K @inc pointer+1 ;+K @dex ;+K @bne rd$sector ;+K clk$hi: @lda d2pra ;+K @and 0ffh-clk$bit,# ;+K @sta d2pra ;+K @rts ;+K ; ; * DEVICE MISSING, CLEAN UP ERROR * ; MISDSK: @LDA 00fh,# ;+K SET ERROR CODE @STA vic$data ;+K writes to RAM under ROM @JMP CMDLP+BB ;+K PAGE ; ; **** OPEN DISK COMMAND CHANNEL **** ; opencm: @LDA cmdchn,# ;+K @CLC ;+K @JSR K$close ;+K @LDA cmdchn,# ;+K @sta fast ;+K set fast flag @LDX 8,# ;+K @TAY ;+K @JSR K$setlfs ;+K @LDA 0,# ;+K @sta serial ;+K clear fast serial indicator @TAX ;+K @JSR K$set$bnk ;+K @LDA 4,# ;+K @LDX low(U0POINT+BB),# ;+K @LDY high(U0POINT+BB),# ;+K @JSR K$setnam ;+K @JSR K$open ;+K @bcs misdsk @jsr K$readst @ROL A ;+K GET MSB TO CARRY @BCS MISDSK ;+K DEVICE MISSING IF CARRY SET @bit serial ;+K test for fast device @bvs no$dt$open ;+K do not open data channel if fast page ; ; **** OPEN DISK DATA CHANNEL **** ; OPENDT: @LDA datchn,# ;+K @CLC ;+K @JSR K$close ;+K @LDA datchn,# ;+K @LDX 8,# ;+K @LDY 8,# ;+K @JSR K$setlfs ;+K @LDA 0,# ;+K @sta fast ;+K clear fast flag @TAX ;+K @JSR K$set$bnk ;+K @LDA 1,# ;+K @LDX low(POUND+BB),# ;+K @LDY high(POUND+BB),# ;+K @JSR K$setnam ;+K @JSR K$open ;+K @bcs misdsk no$dt$open: @rts PAGE ; ; SETUP: @JSR CKOTCM+BB ;+K @LDY dskcmd$lng,# ;+K SETUP2: @LDA DSKCMD+BB-1,y ;+K @JSR K$chrout ;+K @DEY ;+K @BNE SETUP2 ;+K @JSR K$clrchn ;+K @JSR CKINCM+BB ;+K @BEQ SETUP3 ;+K SETUP5: @LDA 0dh,# ;+K get error flag @STA vic$data ;+K writes to RAM under ROM setup3: @JMP K$clrchn ;+K page ; ; ; read$byte: @sei @lda d2pra @eor clk$bit,# @sta d2pra @lda 8,# in$1: @bit d1icr @beq in$1 @lda d1sdr @rts page ; ; handle all interrupts in BIOS 8502 (throw them away) ; irqs: @lda CIA$1+int$ctrl @lda CIA$2+int$ctrl @lda 0fh,# @sta VIC+25 ; ; system saved memory config, Y, X and A before getting here ; @pla @sta force$map @pla @tay @pla @tax @pla @rti ; ; PAGE ; ; **** CONVERT BINARY TO ASCII **** ; BINASC: @CLD ;-K @LDX '0',# ;-K @SEC ;-K BA0: @SBC 10,# ;-K @BCC BA1 ;-K @INX ;-K @BCS BA0 ;-K BA1: @ADC 3Ah,# ;-K @RTS ;-K PAGE ; ; **** SELF CORRECTING CHECK IO ROUTINES **** ; CKICM: @JSR OPENCM+BB ;+K CKINCM: @LDX cmdchn,# ;+K @JSR K$chkin ;+K @BCS CKICM ;+K @JSR K$chrin ;+K @CMP '0',# ;+K @RTS ;+K ; ; ; CKIDT: @JSR OPENDT+BB ;+K CKINDT: @LDX datchn,# ;+K @JSR K$chkin ;+K @BCS CKIDT ;+K @RTS ;+K ; ; ; CKOCM: @jsr OPENCM+BB ;+K CKOTCM: @LDX cmdchn,# ;+K @JSR K$chkout ;+K @BCS CKOCM ;+K @RTS ;+K PAGE dskcmd: db CR ; dskcmd$S$l: db 's' ; dskcmd$S$h: db 's ' ; dskcmd$T$l: db 't' ; dskcmd$T$h: db 't 0 8:1' U0POINT: db 'U' ; dskcmd$lng equ $-DSKCMD db '0',4Ch,0 ; reset disk change status (open) POUND: db '#' F$cmd$buf: F$rd$count: db 1 ; 5 1st read always one sector F$rd$sect: db 0 ; 4 filled in F$rd$trk: db 0 ; 3 filled in F$cmd: db 0 ; 2 read=0 db '0U' ; 1 Fcmd$lng equ $-F$cmd$buf bios$size equ $-bios$65$code  endm @sed macro db 0f8h endm @sei macro db 078h endm @sta macro @u,@v xaaa 81h,@u,@v endm @stx macro @u,@v xbb 86h,@u,@v endm @sty macro @u,@v xbb 84h,@u,@v endm @tax macro db 0aah endm @tay macro db 0a8h endm @tsx macro db 0bah endm @txa macro db 08ah endm @txs macro db 09ah endm @tya macro db 098h endm @skip1 macro db 024h endm @skip2 macro db 02ch endm  Ơ0 , ܮ0x 0)Ъ 0 0)` 0 !`Iݩ, ` ܭ ݩhhhh@0U0Le USER command sets the current user number. The disk directory can be divided into distinct groups according to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> Th title 'CP/M 3 ROM loader 13 May 85' maclib z80 maclib cpm3 maclib cxequ maclib x6502 boot$8502 equ 1100h lines equ 24 ; number of user lines on screen(s) rownum macro row,col db row+80h,col endm ; ; power on location ; org 00h ; RST 0 mvi a,3eh sta force$map jmp power$up ; continue init somewhere else ; ; boot CP/M entry point ; ; org 08h ; RST 1 lxi sp,boot$stack mvi a,3Fh ; MMU enable RAM bank 0 no I/O jmp loader$start page ; ; * TJMP * user to jmp to a Terminal ROM routine ; user code: ; RST 2 ; db fun# (0,4,8,C,....,44) ; ; org 10h ; RST 2 pop h mov l,m jmp 020h nop nop nop ; ; * RJMP * user to jmp to a ROM routine ; user code: ; RST 3 ; db fun# ; ; org 18h ; RST 3 pop h ; get the return address mov l,m ; get user function # (0,2,...,fe) jmp 028h ; nop nop nop page ; ; * TCALL * used to call a Terminal ROM routine ; user code: ; mvi l,fun# (0,4,8,C,....,44) ; RST 4 ; ; org 20h ; RST 4 lda fun$offset ; =0 if 80 column, <>0 if 40 column ana a ; is this an 80 column function? jrz 28h ; yes, no offset required inr l ; no, advance to next vector inr l ; ; * RCALL * used to call a ROM routine ; user code: ; mvi l,fun# (0,2,4,6,.....,7E) ; RST 5 ; ; org 28h ; RST 5 mvi h,01h ; vectors on page 1 mov a,m inx h mov h,m mov l,a pchl nop page ; ; RST 6 is NOT defined.. this area is used for the ROM date ; ONLY.... ; ; org 30h ; RST 6 db '05/12/85' ; org 38h ; RST 7 (interrupt mode 1 start adr) jmp 0fdfdh page ; ; ; power$up: lxi b,VIC$key$row lxi d,0fffch ; D=ff, E=fc outp d ; set extra 3 scan lines off inx b ; point to clock speed reg outp e ; bits 7-2 unused ; bit 1 enable test mode (1) ; bit 0 2 Mhz (1) / 1 MHz (0) ; ; continue the check to see if a C64 type chartrage is installed ; (EXROM or GAME active) if so we enter C64 mode ; lxi b,mode$reg ; get EXROM and GAME bits mvi a,z80$on outp a ; set bit high inp a ; see if they went high cma ; make highs low ani 30h ; EXROM or GAME enabled? jrz test$key ; no, now test the commodore key ; ; This is a one way trip, no return flights. ; Thus we do not have to do the transfer from RAM ; (as in C128 mode). We just enable C64 and run. ; go$c64: mvi a,enable$c64 outp a ; should never get here RST 0 ; unless there are hardware problems page test$key: lxi b,0dc0fh ; D1CRB mvi a,8h ; turn off timers outp a dcr c ; D1CRA outp a mvi c,03h ; D1DDRB = inputs xra a ; A=00 outp a dcr c ; D1DDRA = outputs dcr a ; A=FF outp a dcr c ; dc01 dcr c ; dc00 mvi a,01111111b ; bit 7 for commodore key outp a inx b ; dc01 point to key$col inp a ani commodore$key lxi b,mode$reg jrz go$c64 go$c128: ; ; set MMU registers to a known state ; lxi h,mmu$init$data+11-1 ; start at the End lxi b,mmu$start+11-1 ; and work forward mvi d,11 ; for all 11 bytes init$mmu$next: mov a,m ; get table value outp a ; send to MMU dcx h dcr c dcr d jrnz init$mmu$next ; ; install 8502 code that will enable C128 mode and ; execute at the location pointed to by FFFC (reset vector) ; lxi h,boot$02$code lxi d,boot$8502 lxi b,boot$size ldir lxi h,swap$code lxi d,enable$z80 lxi b,swap$size ldir ; ; Get ready to enter C128 mode. Install vectors in ram that will ; force the processor to execute RAM code in low memory. ; The RAM code in low memory ENABLES the kernal and does ; an indirect JMP to FFFC (reset vector). ; lxi h,boot$8502 ; C128 start adr shld 0fffah ; install NMI vector shld 0fffch ; install RESET vector shld 0fffeh shld return$z80+1 jmp enable$6502 page ; ; scan buffer for CPM+.SYS file ; scan$dir: call update$buffer ; returns HL=block$buffer lda block$size ; 32 for 1K block, 64 for 2K block ; ..number director entries/sector check$next: shld @dma lxi d,sys$name ; point to system name push psw call name$match cz found pop psw lhld @dma ; get current buffer pointer lxi d,32 dad d dcr a jrnz check$next ret page ; ; compare the strings (11 bytes each) pointed to by ; DE and HL. Return with Zero flag set if equal. ; name$match: mvi b,12 ; number of bytes to match xchg ; [HL]=search name [DE]=dir entry match$next: ldax d ; get string 1 character ani 7fh ; remove any attr. cmp m ; compare to string 2 rnz ; exit if they don't match inx h inx d djnz match$next lda block$size ; cpi 64 ; 2K block? ldax d ; get the dir ext# jrnz ext$1k ; no, ext # ok ; yes, (carry=0) rar ; divide by 2, ext could be 0 or 1 ; ..for the 1st and 2 or 3 for the ext$1k: ; ..second entry sta ext$num null$code: xra a ; return with zero flag set ret page ; ; ; sys$name: ; 12345678901 db 0,'CPM+ SYS' ; must be in user 0's space db 0 ; ; ; ; org 0100h-6 cmp$hl$de: mov a,h cmp d rnz mov a,l cmp e ret page ; org 0100h dw wr$char$80 ; function # 00 dw wr$char$40 ; function # 02 dw crs$pos$80 ; function # 04 dw crs$pos$40 ; function # 06 dw crs$up$80 ; function # 08 dw crs$up$40 ; function # 0A dw crs$down$80 ; function # 0C dw crs$down$40 ; function # 0E dw crs$left$80 ; function # 10 dw crs$left$40 ; function # 12 dw crs$rt$80 ; function # 14 dw crs$rt$40 ; function # 16 dw crs$cr$80 ; function # 18 dw crs$cr$40 ; function # 1A dw CEL$80 ; function # 1C dw CEL$40 ; function # 1E dw CES$80 ; function # 20 dw CES$40 ; function # 22 dw char$ins$80 ; function # 24 dw char$ins$40 ; function # 26 dw char$del$80 ; function # 28 dw char$del$40 ; function # 2A dw line$ins$80 ; function # 2C dw line$ins$40 ; function # 2E dw line$del$80 ; function # 30 dw line$del$40 ; function # 32 dw set$color$80 ; function # 34 dw set$color$40 ; function # 36 dw set$attr$80 ; function # 38 dw set$attr$40 ; function # 3A dw rd$chr$80 ; function # 3C dw rd$chr$40 ; function # 3E page dw wr$chr$80 ; function # 40 dw wr$chr$40 ; function # 42 dw rd$color$80 ; function # 44 dw rd$color$40 ; function # 46 dw null$code ; function # 48 dw null$code ; function # 4A dw null$code ; function # 4C dw null$code ; function # 4E dw convert$record ; function # 50 dw check$cbm ; function # 52 dw bell ; function # 54 dw null$code ; function # 56 dw null$code ; function # 58 dw null$code ; function # 5A dw null$code ; function # 5C dw null$code ; function # 5E dw trk$40 ; function # 60 dw set$cursor$40 ; function # 62 dw line$paint ; function # 64 dw screen$paint ; function # 66 dw prt$msg$both ; function # 68 dw prt$de$both ; function # 6A dw update$it ; function # 6C dw null$code ; function # 6E dw ASCII$to$petASCII ; function # 70 dw cur$adr$40$hl$sz$a ; function # 72 dw cur$adr$80$hl$sz$a ; function # 74 dw lookup$color ; function # 76 dw null$code ; function # 78 dw blk$fill ; function # 7A ret adr, HL on stack dw blk$move ; function # 7C ret adr, HL on stack dw char$install$gp ; function # 7E ret adr, HL on stack ; the last 3 function are called by 1st pushing HL on the stack ; and then doing the call ; user code as follows: ; lxi h,xyz ; value to be passed in HL ; push h ; extra value on stack ; RCALL .... ; ; stack clean page ; ; org 180h ; jmp write$memory jmp read$memory jmp set$update$adr jmp wait ; ; ; loader$start: ; ; setup the MMU for booting CP/M ; sta force$map ; ; clear bank 0 RAM 3000h to feffh. This is the system area. ; lxi h,3000h lxi d,3001h lxi b,0ff00h-3000h-1 mov m,l ldir ; ; move bios and swap code into ram ; lxi h,bios$65$code lxi d,bios$02 lxi b,bios$size ldir lxi h,swap$code lxi d,enable$z80 lxi b,swap$size ldir mvi a,RET ; get z80 return adr sta return$6502 ; store the RET ; ; initilize the 8502 bios ; ; xra a ; cleared by memory fill ; sta vic$cmd call enable$6502 page ; ; set MMU registers to a known state (for CP/M to use) ; lxi h,mmu$init$data+11-1 ; start at the End lxi b,mmu$start+11-1 ; and work forward mvi d,11 ; for all 11 bytes init$mmu$cpm: mov a,m ; get table value outp a ; send to MMU dcx h dcr c dcr d jrnz init$mmu$cpm ; re-enabled RAM bank 0 (no I/O) ; ; Clear the work area ; lxi h,1000h lxi d,1000h+1 lxi b,3000h-1000h-1 ; number of bytes to clear mov m,l ; clear the 1st one ldir ; copy 1st to all page ; ; set 80 column colors and set up Video memory with ASCII char set ; mvi a,26 call wait mvi a,90h ; foreground red background black outp a mvi a,83h ; set attr and color (lt. blue) sta current$atr ; ..for 80 column display mvi a,0eh ; set color (lt. blue) sta attr$40 ; ..for 40 column display call install$ASCII ; convert char set to true ASCII mvi a,25 ; number of lines on the 40 col display sta paint$size ; ; Let the user know we are booting CP/M ; call prt$msg$both db -1 ; clear both screens rownum 1,10 db 'BOOTING CP/M PLUS',0 ; ; point 40 column screen to CP/M screen area ; lxi b,VIC+24 mvi a,vic$screen*4/256+6 ; upper and lower case set (+6) outp a page call check$dsk ; is this a C128 disk ? jnz tell$user ; no, tell the user ; ; ; lxi h,dir$ptrs shld ld$blk$ptr call scan$dir ; check 1st block call scan$dir ; check 2nd block (1K or 2K) lhld block$ptrs ; 1st pointer <>0 if file mov a,h ; name exist ora l ; pointer = 0 jz tell$user ; yes, inform user there is a error ; no, file found, process it page ; ************************************************* ; * * ; * load 1st group to 1K buffer * ; * * ; ************************************************* ; ; ; file$found: lxi h,block$ptrs shld ld$blk$ptr call update$buffer ; ************************************************* ; * * ; * extract boot info * ; * * ; ************************************************* ; ; ; get$boot$info: lxi h,block$buffer lxi d,info$buffer lxi b,12 ldir call prt$msg$both rownum 10,0 db 0 ; end of string marker lxi h,block$buffer+80h call prt$hl$both lxi h,block$buffer+256 ; set scan pointer shld blk$unld$ptr page ; ************************************************* ; * * ; * load keyboard data to system RAM * ; * * ; ************************************************* call prt$msg$both rownum 3,12 ; db 'LOADING DATA TABLES',0 db 'DATA TABLES',0 lhld info$buffer+10 shld key$tbl ; install keyboard translation pointer lxi h,info$buffer+9 call get$size$adr ; HL=adr DE=# (128 btye) records shld fun$tbl load$next$forward: call load$record ; HL =load address (in and out) lxi d,128 ; move pointer back to buf start dad d jrnz load$next$forward page ; ************************************************* ; * * ; * transfer CP/M code to load address * ; * * ; ************************************************* ; ; ; load$common: call prt$msg$both rownum 4,12 ; db 'LOADING COMMON CODE',0 db 'COMMON CODE',0 lxi h,info$buffer+1 ; load common code call load$reverse call prt$msg$both rownum 5,12 ; db 'LOADING BANKED CODE',0 db 'BANKED CODE',0 lxi h,info$buffer+3 ; load banked code call load$reverse page ; ************************************************* ; * * ; * now load the bios8502 code * ; * * ; ************************************************* call prt$msg$both rownum 6,12 ; db 'LOADING BIOS8502 CODE',0 db 'BIOS8502 CODE',0 lxi h,info$buffer+7 ; load banked code call load$reverse lda info$buffer+7 ; get code size (in 256 byte blocks) mov b,a lda info$buffer+6 ; get page pointer (pointer to end) sub b ; find the start ; install jmp adr to BIOS02 sta return$z80+2 ; (jmp) (low) (high) xra a sta return$z80+1 ; (jmp) (low) (high) ; ************************************************* ; * * ; * now let's start executing CP/M Plus * ; * * ; ************************************************* lhld info$buffer+4 ; get start address pchl ; transfer control to CP/M page ; ********************************* ; - - ; - SUBROUTINES - ; - - ; ********************************* ; ; returns with zero flag set if bootable disk in drive ; check$dsk: lxi h,@buffer shld @dma xra a sta vic$sect ; set track 1 sector 0 (1st sector inr a ; on the disk) sta vic$trk call read$sector ; a=0 if no errors call check$cbm ; disk have CBM in first sector ? rnz ; no, exit inr a ; yes, is it double sided? lxi h,block$buffer+1024 ; buffer end address (1K blocks) mvi a,32 ; number of dir entries per block jrnz set$block$size ; yes, set it ; no, set 2K block parameters mvi h,high(block$buffer+2048) add a ; 64 dir entries set$block$size shld block$end sta block$size ; 32=1K, 64=2K (# dir entries/block) xra a ; set zero flag (is CP/M disk) ret page ; ************************************************* ; - - ; - save CPM+.SYS group numbers - ; - - ; ************************************************* ; ; found a dir entry that has the right name ; add block pointers to list ; found: lxi d,block$ptrs ; point to start of block pointers lda ext$num ora a jrz ext$num$0 lxi d,block$ptrs+16 dcr a jnz ext$error ext$num$0: lhld @dma ; get current pointer lxi b,16 ; number of bytes to move dad b ; also advance to block pointers ldir lda block$ptrs ora a ; 1st block present ? rz ; no, read more dir. lhld block$ptrs+15 ; extent full? xra a ; get a zero cmp l ; cmp to block$prt+15 jrz go$boot$it ; no, this is it then cmp h ; cmp to block$prt+16 ; 2nd block present ? rz ; no, read more dir. go$boot$it: jmp file$found ; two parms are still on the stack ; but at this point who cares page ; ; ; load$reverse: call get$size$adr ; HL=adr DE=# records (128 byte) load$next: lxi d,-128 ; move pointer back to buf start dad d call load$record jrnz load$next ret ; ; ; get$size$adr: mov e,m mvi d,0 ; get buffer size (#256 byte) mov a,e ; get size to A ora a jz table$error ; exit if count=0 xchg dad h ; HL=#128 byte blocks shld load$count xchg dcx h mov h,m mvi l,0 ret page ; ; ; load$record: push h ; save to address lhld block$end ; get buffer end adr xchg lhld blk$unld$ptr call cmp$hl$de cz update$buffer xchg lxi h,128 dad d shld blk$unld$ptr pop h ; recover save address push h xchg ; HL=source DE=dest. lxi b,128 ; size of move ldir lhld load$count dcx h shld load$count mov a,l ora h pop h ret page ; ; ; update$buffer: lxi h,block$buffer shld @dma push h ; save block buffer adr for ret lhld ld$blk$ptr ; get the current block pointer mvi d,0 ; zero MSB of block pointer mov e,m ; get LSB of block pointer inx h ; advance pointer shld ld$blk$ptr xchg ; get block number to HL ; ; read the block pointed to by the HL ; into the data buffer ; dad h ; 2x dad h ; 4x 256=1K lda block$size ; =32 for 1K, =64 for 2K rrc rrc rrc ; 32/8=4, 64/8=8 cpi 32/8 ; 1K block size? jrz is$1K$block dad h ; 8x 256=2K is$1K$block: shld @trk next$block: dcr a ; 3 or 7 sectors left to read sta vic$count ; ..1st sector is read anyway push psw mvi a,1 sta F$rd$count+BB ; call convert$record ; set track, sector (adjust for offset) lhld @trk inx h shld @trk ; save for later pop psw jrz rd$1541 lda fast ana a ; 0=1541, 0<>1571 jrz rd$1541 lhld vic$trk ; get track and sector # push h ; save on stack check$next$trk: call convert$record ; convert next track and sector pop h ; recover 1st trk and sector # lda vic$trk ; get trk$number cmp l ; same trk as 1st sector jrnz not$same$trk push h ; resave 1st trk and sect lhld @trk inx h shld @trk lxi h,F$rd$count+BB inr m lxi h,vic$count dcr m jrnz check$next$trk pop h not$same$trk: shld vic$trk ; save the 1st track sector # rd$1541: call read$sector ; read the sector to the buffer lxi h,@dma+1 ; point to dma high byte lda F$rd$count+BB add m mov m,a ; adjust for next read lda vic$count ana a ; test if all sectors read? jrnz next$block ; no loop back pop h ; recover block buffer adr ret page ; ; convert block number to sector and track ; convert$record: mvi a,35 sta temp$1 ; store a track offset of 35 lhld @trk ; get start block # lxi d,680 ; 0 to 680 sectors per side ora a ; clear the carry dsbc d ; negative if <680 jrnc side$1 ; jump if still positive >=680 xra a ; sta temp$1 ; store a track offset of 0 dad d ; add it back side$1: inx h ; skip 1st sector (both sides) inx h ; skip 2nd sector (both sides) lxi d,357 ; get first value to subtract lxi b,21*256+1-1 ; b=sectors/track c=track offset-1 ora a ; clear the carry bit dsbc d ; jrc too$much ; inx h ; add 1 to skip track 18 sector 0 lxi d,490-357 ; get first value to subtract lxi b,19*256+18-1 ; b=sectors/track c=track offset-1 dsbc d ; jrc too$much ; lxi d,598-490 ; get first value to subtract lxi b,18*256+25-1 ; b=sectors/track c=track offset-1 dsbc d ; jrc too$much ; lxi d,0 lxi b,17*256+31-1 ; b=sectors/track c=track offset-1 page ; ; at this point B= number of sectors/track and C=track offset ; after DE is added back to HL (1st inst), HL is the number of ; sector past the current track (in C). ; too$much: dad d ; add back what made sum go negitive mvi d,0 ; number of sectors/track in DE mov e,b ora a ; clear the carry bit sect$pos: inr c ; add one to the current track (1-35) dsbc d ; remove a track's worth of sectors jrnc sect$pos ; less then one?, no jmp dad d ; make HL positive again ; ; at this point HL has the remainder (sector # 0-20) and ; C has the track number (1-35), DE and B still has the ; # sectors/track for the current track. ; lda temp$1 ; get track offset add c ; add to current track sta vic$trk ; save it push h lxi h,special$skew lxi b,21 ; number of sectors in 1st region mov a,e cmp c jrz correct$region dad b ; move past current region dcx b dcx b ; 19 adjust$loop: cmp c jrz correct$region dad b dcx b jr adjust$loop ; ; ; correct$region: pop b ; get logical sector # in BC dad b mov a,m ; get translated sector number to A sta vic$sect ; value from 0 to 20 will be returned inr a ; A is required to be non-zero on ret ret page ; ; ; read$sector: mvi a,3 sta retry read$again: mvi a,vicrd ; read a sector of data sta vic$cmd call disp$dsk$info call enable$6502 mvi a,3fh ; mmu ram bank 0 (no I/O) sta force$map lda vic$data ora a ; problems? jrnz read$error ; yes, check for disk error or media change ; no, go move buffer to DMA address ret page ; ; ; check$cbm: lxi h,@buffer mov a,m cpi 'C' ; C ? rnz ; no, return inr l ; @buffer+1 mov a,m cpi 'B' ; B ? rnz ; no, return inr l ; @buffer+0 mov a,m cpi 'M' ; M ? rnz mvi l,0ffh ; @buffer+0ffh ; point to the double sided flag mov a,m ; read it, 0FFh if double sided ret page ; ; ; ext$error: call prt$msg$both rownum 19,5 db '32K MAX CPM+.SYS SIZE',0 try$again: rst 1 ; ; ; read$error: inr a ; test for -1 jrz try$again lda retry dcr a sta retry jrnz read$again call prt$msg$both rownum 19,5 db 'READ ERROR',0 error$2: call prt$msg$both db ' - HIT RETURN TO RETRY' rownum 20,15 db 'DEL TO ENTER C128 MODE',0 ; ; ; wait$key: lxi b,key$row mvi a,11111110b ; bit 0 for RETURN key outp a inr c ; point to key$col inp a ani 2 ; on bit 1 (0-7) jrz try$again inp a ani 1 ; delete key down jrnz wait$key ; no, wait for RETURN key rst 0 ; yes, reboot C128-mode page ; ; CPM+.SYS file not on this disk test user to install ; a system disk and wait for a CR to continue ; tell$user: call prt$msg$both rownum 19,5 db 'NO',0 error$1: call prt$msg$both db ' CPM+.SYS FILE',0 jr error$2 ; ; ; table$error: call prt$msg$both rownum 19,5 db 'BAD',0 jr error$1 page ; ; ; prt$msg$both: xthl call prt$hl$both xthl ret update$it: lxi h,-1 shld old$offset ; force an update ; ; ; prt$de$both: push d ; ; ; prt$hl$both$loop: pop h ; ; ; prt$hl$both: mov d,m inx h ; advance the pointer lda prt$flg ana a jrz no$flag xra d sta prt$flg mov d,a no$flag: mov a,d ora a rz cpi '$' rz ; yes, return push h lxi h,prt$hl$both$loop push h cpi LF rz page ; ; ; check$both$CR: cpi CR jrnz check$erase$both ; ; do$crlf$both: call crs$cr$40 call crs$cr$80 call crs$down$40 RJMP FR$cursor$down ; cursor down 80 ; ; ; check$erase$both: cpi -1 jrnz check$both$CUR$$POS ; ; Erase both screens ; lxi d,24*256 ; erase the status line 1st call curpos$BC$both call CEL$40 call CEL$80 lxi d,0 ; erase main screen call curpos$BC$both call CES$40 RJMP FR$CES check$both$CUR$POS: ani 80h jrz out$d$both ; curpos$D$both: pop b ; get return adr in BC pop h ; get pointer in HL mov e,m ; E=column # inx h push h ; save new pointer push b ; save return adr res 7,d ; D=row # curpos$BC$both: push d ; save cursor address call crs$pos$40 pop d RJMP FR$cursor$pos ; 80 column page ; ; ; disp$dsk$info: lxi d,24*256+80-6 call crs$pos$80 lxi d,24*256+40-6 call crs$pos$40 lda vic$trk call disp$dec mvi d,' ' call out$d$both lda vic$sect disp$dec: mvi b,'0'-1 conv$loop: inr b sui 10 jrnc conv$loop adi '0'+10 push psw mov a,b call disp$A pop psw disp$A: mov d,a ; ; ; out$d$both: push d call wr$char$40 pop d RJMP FR$wr$char u,@v xbb 86h,@u,@v endm @sty macro @u,@v xbb 84h,@u,@v endm @tax macro db 0aah endm @tay macro db 0a8h endm @tsx macro db 0bah endm @txa macro db 08ah endm @txs macro db 09ah endm @tya macro db 098h endm @skip1 macro db 024h endm @skip2 macro db 02ch endm  Ơ0 , ܮ0x 0)Ъ 0 0)` 0 !`Iݩ, ` ܭ ݩhhhh@0U0Le USER command sets the current user number. The disk directory can be divided into distinct groups according to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> Th ; 13 May 85 ;** ;** 80 COLUMN FUNCTION CODE ;** fixed$8563 equ false ;* ;* Write character in D to current cursor address ;* Advance cursor next position ;* wr$char$80: lhld char$adr call write$char$80 lda char$col ; get cursor column number cpi 80-1 jrz do$crlf inr a sta char$col ; update column number lhld char$adr ; get cursor address inx h shld char$adr ; update cursor address ; ; input: ; HL=current cursor address ; set$cursor: mvi a,14 ; call wait ; outp h mvi a,15 ; call wait ; outp l ret page ;* ;* Set current ROW and COL (supplied in DE) ;* ;* crs$pos$80: mov a,d cpi 25 rnc mov a,e cpi 80 rnc xchg ; cursor row # in D,column # in C shld char$col ; ; returns with cursor set and current ROW, COLUMN in BC ; and character screen address in HL ; compute$adr: lhld char$col call cur$adr$hl ; HL=cursor address on return shld char$adr jr set$cursor ; call/ret page ;* ;* Move cursor up one line; do nothing if on the ;* top line ;* crs$up$80: lda char$row ora a rz dcr a set$row$80: sta char$row jr compute$adr do$crlf: xra a sta char$col ;* ;* ;* ;* crs$down$80: lda char$row cpi lines-1 ; on bottom line ? jrz scroll$up ; yes, scroll the screen jrnc set$24$80 ; past it, set it to line 24 inr a jr set$row$80 ;* ;* ;* ;* crs$left$80: lda char$col ora a rz dcr a set$col$80: sta char$col jr compute$adr page ;* ;* ;* ;* crs$rt$80: lda char$col inr a cpi 80 jrnz set$col$80 ret ;* ;* ;* ;* crs$cr$80: xra a jr set$col$80 page ; ; ; set$24$80: mvi a,lines-1 sta char$row ; ; ; scroll$up: lxi h,80 lxi d,0 lxi b,80*(lines-1) call block$move$80 ; ; ; clear$bottom$line: lxi h,80*(lines-1) lxi b,80 call block$fill$space$80 jr compute$adr page ;* ;* B= bit position to set or clear ;* C= new bit value ;* ;* attr byte def. (in B and C) ;* bit 7-alternate char set (uper case set) ;* bit 6-reverse video ;* bit 5-underline ;* bit 4-blink ;* bit 0-full intensity ;* ;* set$attr$80: lda current$atr cma ; invert A ora b ; force new bit to 1 cma ; restore A ora c sta current$atr ret page ;* ;* ASCII codes(B) 20h to 2Fh set character color ;* 30h to 3Fh set background color ;* 50h to 5Fh set logical character color ;* 60h to 6Fh set logical background color ;* all others code do nothing ;* ;* set$color$80: mov a,b ; get color to A sui 20h ; remove the BIAS cpi 20h ; physical color ? (00h-1Fh) jrc ?col$80 ; yes, go set it mvi c,20h ; max color value+1 (00h-1Fh) call lookup$color$1 ; convert char in A to color (ret in A) ; C=max color character rc ; return if error mov a,m ; get color bytes ani 0fh ; LSB is 80 column color add b ; Add color offset back ; 0-f set forground color ; 10-1f set background color page ; ; set color in A (00-0F sets the character color) ; (10-1F sets the background color) ; ; This routine first calls lookup color to convert the 40 column ; color (normal color) to the 80 column RGBI color ; ?col$80: sta temp1 mvi c,20h ; max color value+1 (00h-1Fh) adi 30h ; restore a bias lxi h,color$convert$tbl ; table to use call lookup$color$2 ; convert to same color as 40 Column mov a,m ; get character color add b ; add color offset back cpi 10h ; character color? (0-f) jrc chr$col$80 ; yes, go do it ; no, fall thru and set background ; ; set background color (10-1F) ; ani 0Fh ; get value of 0 to F sta bg$color$80 push psw mvi a,26 ; color register call wait pop psw outp a ret ;* ;* ;* rd$color$80: lda bg$color$80 mov b,a lda current$atr mov d,a lda char$color$80 ret page ; ; set character color ; chr$col$80: mov b,a lda current$atr ani 0f0h ; remove old color ora b ; merge new color sta current$atr ; save new attr lda temp1 sta char$color$80 ; ; set current char position color to new color ; lhld char$adr ; get current cursor adr lxi d,800h ; offset to attr dad d ; pointing to current char attr call set$update$adr ; point to attr byte lda current$atr outp a ret page ;* ;* ;* ;* CEL$80: call cur$adr$80$hl$sz$a ; HL=cur adr, DE=line start adr ; BC=count to move, A=BC+1 inx b ; 1 to 80 to fill jr cont$space$fill ;* ;* ;* ;* CES$80: call cur$adr$80$hl$sz$a ; HL=cur adr, DE=line start adr ; BC=count to move, A=BC+1 xchg ; cursor address in DE lxi h,lines*80 xra a ; clear the carry dsbc DE ; count will be minus if on status line rm ; return if on status line mov b,h mov c,l ; count to BC xchg ; cursor address back to HL cont$space$fill: jmp block$fill$space$80 page ;* ;* ;* char$ins$80: call cur$adr$80$hl$sz$a ; HL=cur adr, DE=line start adr ; BC=count to move, A=BC+1 (1-80) lxi h,80-1 dad d ; point to end of line dcr a ; A=1 if at end of line jrz char$ins$80$end mov d,h mov e,l ; HL=DE= end of line address dcx h ; [HL--] -> [DE--] count BC push b push h push d call insert$low lxi b,800h ; attribute offset pop h dad b xchg pop h dad b pop b insert$low: push b call set$update$adr inp a xchg push psw call set$update$adr pop psw outp a xchg pop b dcx h dcx d dcx b mov a,b ora c jrnz insert$low lhld char$adr char$ins$80$end: jmp write$space$80 page ;* ;* ;* ;* char$del$80: call cur$adr$80$hl$sz$a ; HL=cur adr, DE=line start adr ; BC=count to move, A=BC+1 push d ; save line start address mov d,h mov e,l ; DE=HL=cursor address inx h ; [HL++]->[DE++] count BC call block$move$80 ; DE points to last position pop h ; recover line start address lxi d,80-1 dad d ; point to end of line jmp write$space$80 page ;* ;* ;* Moves one line at a time, down one line, starting with the next ;* to the bottom line. Once the cursor line is moved down, the ;* cursor line is cleared. ;* line$ins$80: lxi d,new$offset mvi a,lines-1 ; cursor on or past the last line ? lhld char$col cmp h jz clear$bottom$line ; no bottom, clear bottom line jrc line$ins$cont ; past, lxi h,(lines-2)*80 lxi d,(lines-1)*80 mvi b,lines move$next$down: call move$line$down lda char$row cmp b jrnz move$next$down call cur$adr$80$hl$sz$a ; HL=cur adr, DE=line start adr ; BC=count to move, A=BC+1 xchg ; get line start adr lxi b,80 jr block$fill$space$80 ; ; ; line$ins$cont: inr a cmp l rnz jmp update$it page ; ; INPUT: ; HL=source ; DE=dest ; B=line number ; OUTPUT: ; HL=source-80 ; DE=dest-80 ; B=line number - 1 ; move$line$down: push b push h push d lxi b,80 call block$move$80 lxi b,-80 pop h dad b xchg pop h dad b pop b dcr b ret page ;* ;* ;* line$del$80: lda char$row cpi lines ; is the cursor past the bottom line ? rnc ; yes, exit call cur$adr$80$hl$sz$a ; HL=cur adr, DE=line start adr ; BC=count to move, A=BC+1 lxi h,80 ; line length dad d ; HL=start of next line xchg ; move from address in DE push h ; save TO address lxi h,lines*80 xra a ; clear the carry dsbc DE mov b,h mov c,l ; count to BC pop h ; recover TO address xchg ; move from address back to HL call block$move$80 ; DE points to last position jmp clear$bottom$line page ; ; user interface point ; blk$fill: pop h ; get the return addres xthl ; get HL, ret adr to stack. jr block$fill$80 ; ; INPUT: ; HL=start address ; BC=count ; block$fill$space$80: lda current$atr mov e,a mvi d,' ' ; ; 80 block fill ; ; INPUT: ; HL=start address ; BC=count ; D=fill character, E=attribute ; block$fill$80: mov a,b ; get MSB of count to A ana a ; is it zero jrz fill$less$256 ; yes, move less than 256 bytes block$fill$cont$80: push h push d push b xra a call fill$data$80 pop b pop d pop h inr h djnz block$fill$cont$80 page ; ; ; fill$less$256: mov a,c ; get LSB of count to A ana a ; is it zero ? rz ; yes, none left to fill, return ; ; count in A (1 to 256) (0=256) ; HL=fill adr ; DE=fill character, and attribute ; fill$data$80: push psw ; save count push h ; save adr push d ; save fill character call fill$half$80 pop d ; recover fill character lxi b,800h ; offset to attributes pop h ; recover adr dad b ; HL=attr adr call do$twice? pop psw ; recover count mov d,e ; get the attr to D page ; ; fill$half$80: push psw ; save the count call set$update$adr ; write address to chip R18,R19 outp d ; write update data (R31) pop psw dcr a ; already wrote one above rz ; return if only one required push psw mvi a,24 call wait inp a ; get old value in reg 24 ani 7fh outp a ; clear R24(7), enabling block writes mvi a,30 call wait pop psw ; recover the count outp a ; write count to R30 if fixed$8563 ret else mvi b,0 mov c,a inx b ; add back the one removed above dad b push d ; save fill char (in D) push h ; HL=end address mvi a,18 call wait inp h mvi a,19 call wait inp l ; HL=current pointer pop d ; DE=end adr pop b ; get fill char (to B) finish$fill: call cmp$HL$DE ; compare dest with chip dest ; HL [DE--] count BC push b push d lddr ; DE=cursor position xchg call write$space$40 ; write a space at the cursor adr pop h lxi b,800h ; now move the attributes dad b pop b mov d,h mov e,l ; HL=DE= end of line address dcx h ; [HL--] -> [DE--] count BC lddr ; DE=cursor position ret ; ; ; write$space$40: lda rev$40 adi ' ' ; clear character, enable cursor mov m,a ret page ;* ;* ;* ;* char$del$40: lxi h,line$paint push h call cur$adr$40$hl$sz$a ; HL=cur adr, DE=line start adr ; BC=count to move, A=BC+1 lxi d,screen$40 dad d ; point to screen memory location dcr a ; at end of line ? jrz write$space$40 ; yes, then just erase cursor pos mov d,h mov e,l ; DE=HL=cursor address push b push h inx h ; [HL++]->[DE++] count BC ldir ; DE points to last position xchg call write$space$40 ; place a space at the end of line pop h lxi b,800h+1 ; now move the attributes dad b pop b mov d,h mov e,l ; HL=DE= cursor attr address inx h ; [HL++] -> [DE++] count BC ldir ; ret page ;* ;* ;* ;* line$ins$40: lxi h,screen$paint push h lda char$row$40 cpi lines-1 jrz clear$bottom$line$40 rnc ; return if on status line call cur$adr$40$hl$sz$a ; HL=cur adr, DE=line start adr ; BC=count to move, A=BC+1 lxi h,screen$40 dad d ; point to line start memory location push h ; save start address lxi d,80 dad d ; point to start of next line xchg ; cursor line(+1) start address in DE lxi h,screen$40+80*lines ; end of screen address xra a ; clear the carry bit (and A) dsbc DE ; HL=HL-DE mov b,h mov c,l ; count in lxi h,screen$40+80*(lines-1)-1 ; HL=end of screen-80 lxi d,screen$40+80*lines-1 ; DE=end of screen push b lddr page pop b lxi h,screen$40+80*(lines-1)-1+800h lxi d,screen$40+80*lines-1+800h lddr ; scroll the attributes pop h ; get cursor line start address mov d,h mov e,l inx d lxi b,80-1 jr space$fill$40 ; ; ; clear$bottom$line$40: lxi h,screen$40+(lines-1)*80 lxi d,screen$40+(lines-1)*80+1 lxi b,80-1 space$fill$40: lda rev$40 adi ' ' mov m,a ldir ret page ;* ;* ;* ;* line$del$40: lxi h,screen$paint push h lda char$row$40 cpi lines-1 ; on or past last line ? jrz clear$bottom$line$40 ; on, just clear it rnc ; past it, return call cur$adr$40$hl$sz$a ; HL=cur adr, DE=line start adr ; BC=count to move, A=BC+1 lxi h,screen$40 dad d ; point to line start memory location push h ; save cursor line start adr lxi d,80 dad d ; point to start of next line xchg ; cursor line(+1) start address in DE lxi h,screen$40+80*lines ; end of screen address xra a ; clear the carry bit (and A) dsbc DE ; HL=HL-DE mov b,h mov c,l ; count in xchg ; HL=start of line after cursor line pop d ; start of cursor line push b ; save count push h ; save source push d ; save dest ldir lxi b,800h ; get attribute offset pop h ; recover dest dad b ; attr dest xchg ; dest belongs in DE pop h ; recover source dad b ; attr source pop b ; recover count ldir jr clear$bottom$line$40 page ;* ;* B=bits to set or clear ;* C=bits new value ;* ;* attr byte def. (in B) ;* bit 7- ;* bit 6-reverse video * ;* bit 5-underline ;* bit 4-blink ;* bit 0-full intensity (masked off) ;* ;* set$attr$40: mov a,b ani 070h mov b,a mov a,c ani 070h mov c,a lda attr$40 cma ora b cma ; bits in B cleared A ora c ; add new value sta attr$40 ral ; get reverse attr in bit 7 ani 80h sta rev$40 ret page ;* ;* ASCII codes 20h to 2Fh set character color ;* 30h to 3Fh set background color ;* 40h to 4Fh set border color ;* 50h to 5Fh set locical character color ;* 60h to 6Fh set logical background color ;* 70h to 7Fh set logical border color ;* all others code do nothing ;* ;* All colors are assigned from color lookup table ;* set$color$40: mov a,b sui 20h cpi 30h jrc ?col$40 mvi c,30h ; max color value+1 (00h-2Fh) call lookup$color$1 ; HL points to table entry on ret rc ; exit if error mov a,m ; get table value again rrc rrc rrc rrc ; get upper 4 bits to lower ani 0fh add b ; get old MSB ?col$40: cpi 10h ; character color? (0-f) jrc char$color$40 ; yes, go do it ; no, fall thru test background, border cpi 20h ; background color? (10-1f) jrc back$color$40 ; yes, go do it ; no, fall thru and set border color ; ; set border color ; ani 0fh ; color from 0-f sta bd$color$40 lxi b,VIC+32 outp a ret page ; ; set background color (10-1F) ; back$color$40: ani 0Fh ; get value of 0 to F sta bg$color$40 lxi b,VIC+33 outp a ret ;* ;* ;* rd$color$40: lda bg$color$40 mov b,a lda bd$color$40 mov c,a lda attr$40 mov d,a ani 0fh ret ; ; set character color ; char$color$40: mov b,a lda attr$40 ani 0f0h ora b sta attr$40 lhld char$adr$40 lxi d,800h dad d mov m,a ; jmp line$paint page ; ; ; line$paint: lda old$offset mov b,a ora a cm trk$40 lda @off40 ; cmp b sta old$offset jrnz screen$paint call cur$adr$40$hl$sz$a ; DE=start of row adr (REL) lxi h,screen$40 ; get start of screen dad d ; HL=row start address (ABS) xchg ; save in DE lhld @off40 ; get current screen offset (0-39) dad d ; screen source adr in HL push h ; save for later lda char$row$40 ; get current row # mov l,a ; HL=row # (H=0) call Lx40$plus$VIC xchg ; place screen adr (25X40) in DE pop h ; recover logical screen adr (25X80) push h ; save for attr move push d mvi a,1 ; one line only call update$window$fun pop h ; recover screen pointer (25X40) lxi b,vic$color-vic$screen dad b ; point to Vic color memory xchg ; DE=color memory pointer pop h ; recover screen pointer (25X80) lxi b,800h ; offset to attributes dad b mvi a,1 ; one line only jr update$window$fun ; page ; ; hl=offset (0 to 39) ; screen$paint: lhld @off40 lda paint$size ; number of lines to move push h push psw ; save the count lxi d,screen$40 dad d ; point to start of visible screen lxi d,vic$screen ; place to move it to call update$window$fun pop psw pop h lxi d,screen$40+800h dad d ; add the screen offset lxi d,vic$color ; ; Always called from bank 0, Placed in common so that IO ; will not overlay this code. Can go in ROM ; update$window$fun: sta io$0 update$window$loop: lxi b,40 ; number of bytes to move ldir push d lxi d,80-40 ; advance pointer to next line dad d pop d dcr a jrnz update$window$loop sta bank$0 ret page ; ; ; trk$40: lda char$col$40 ; get the current column number sui 40-8 ; remove 1st 32 columns jrnc use$offset ; if pass column 32, set an offset xra a use$offset: ani 0f8h ; move sta @off40 ret page ; ; ; set$cursor$40: call no$cursor call line$paint ; will do a screen paint if required lda @off40 ; get screen offset mov b,a ; save offset (0 to 39) lhld char$col$40 ; H=row, L=col mov a,l ; get col # in A sub b ; remove offset jrc no$cursor cpi 40 jrnc no$cursor mov c,a mvi b,0 ; BC=cursor column # mov l,h ; get row # in L call Lx40$plus$VIC dad b jr set$flash ; no$cursor: lxi h,0 ; if H=0 (L=xx) then cursor off ; set$flash: shld flash$pos ret page ; ; ; Lx40$plus$VIC: mvi h,0 dad h ; 2X dad h ; 4X dad h ; 8X mov d,h mov e,l ; DE=8X dad h ; 16X dad h ; 32X dad d ; 8X+32X=40X lxi d,vic$screen dad d ; point to screen area ret page ; ; input: ; range 20h to 7fh in B ; output: ; in A ; ascii$to$petascii: mov a,b cpi 40h jrz is40 ; get at sign rc ; ret if code was 20h - 3fh cpi 'Z'+1 ; is it an upper case letter ? rc ; yes, code was 41h - 5Ah sui 40h cpi 60h-40h jrz was$60 ; 60h converted to 27h jrc was$5b$to$5f sui 20h cpi 'z'+1-60h rc ; code was 61h - 7Ah cpi '{'-60h jrz is$left$brace cpi '|'-60h jrz is$vert$bar cpi '}'-60h jrz isright$brace cpi '~'-60h rnz mvi a,64 ; commodore horz bar ret was$60: mvi a,126 ; solid upper left corner ret is$left$brace: mvi a,115 ; ret is$vert$bar: mvi a,93 ; commodore vertical bar ret is$right$brace: mvi a,107 ; ret was$5b$to$5f: cpi '\'-40h jrz is$back$slash cpi '_'-40h rnz mvi a,100 ; commodore under line ret is$back$slash: mvi a,127 ; upper left and lower right corners ret is40: xra a ret page ; ; ; cur$adr$40$hl$sz$a: lhld char$col$40 jr cur$adr$hl$sz$a ; ; ; cur$adr$80$hl$sz$a: lhld char$col ; ; INPUT: ; H=row L=col ; ; OUTPUT: ; HL=cursor address ; DE=cursor line start address ; BC=# character to end of line ( <80 ) ; (not counting the cursor position) ; A=BC+1 ; cur$adr$hl$sz$a: mvi a,80-1 ; get line length sub l ; A= mov c,a cur$adr$hl: mov b,l ; save column # mov l,h mvi h,0 ; HL=row # dad h ; 2x dad h ; 4x dad h ; 8x dad h ; 16x mov d,h mov e,l ; save 16x dad h ; 32x dad h ; 64x dad d ; 64x+16x=80x xchg ; DE=row start address mov l,b ; get saved column # mvi h,0 ; HL=column # dad d ; HL=cursor address mvi b,0 ; BC= count (if call to cur$adr$hl$sz$a:) inr a ; number of bytes to end of line (1-80) ret page ; ; destroys DE,HL,B,A ; lookup$color: mov a,b ; color supplied in B lookup$color$1: lhld color$tbl$ptr ; ; HL=table adr ; A= color input ; C= max allowable color value ; lookup$color$2: sui 30h ; remove bias rc cmp c ; above limit cmc rc ; yes, return input out-of-range mov b,a ; save adjusted color # ani 0fh ; get only the color # mov e,a mvi d,0 dad d ; get converted color address mov a,b ; get the ASCII char back ani 30h ; keep only char/background/borber bits mov b,a ; save char/background bit ret page ; ; ; bell: lxi b,sid+24 lhld sound$1 outp h mvi c,5 outp l lhld sound$2 inr c outp h mvi c,1 outp l lhld sound$3 mvi c,4 outp h outp l ret  @skip1 macro db 024h endm @skip2 macro db 02ch endm  Ơ0 , ܮ0x 0)Ъ 0 0)` 0 !`Iݩ, ` ܭ ݩhhhh@0U0Le USER command sets the current user number. The disk directory can be divided into distinct groups according to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> Th page chr$move macro xx,yy,zz lxi h,xx*16+DS$char$def lxi d,yy*16+DS$char$def lxi b,zz*16-8 call block$move$80 endm chr$fill macro xx,yy,zz lxi h,xx*16+DS$char$def ; start adr lxi b,yy*16 ; count mvi d,zz ; character to fill with call block$fill$80 endm newoffset equ 179*11*2 ; ; 1st move pet-asc characters to ASCII positions ; install$ASCII: lxi h,100h*16+DS$char$def+4 ; point to center of @ char call rd$mem ; ..read it to B inr b ; ..if it is a zero then dcr b ; ..install$ascii has been done rz ; ..so just exit Chr$fill 180h,64,0 ; fill 180-1bf with 0 Chr$move 17ah,18ah,1 Chr$move 169h,189h,1 Chr$move 15eh,18eh,2 ; move 2 character definitions Chr$move 101h,161h,26 ; move 16 character definitions Chr$fill 100h,32,0 Chr$move 000h,140h,1 Chr$move 01bh,15bh,3 ; move 3 character definitions Chr$move 01ch,180h,1 Chr$move 01eh,181h,2 Chr$move 040h,1c0h,64 ; move 16 character definitions ; now install characters that are NOT already defined lxi d,extra$char$table lxi h,15ch*16+DS$char$def call char$install lxi h,15eh*16+DS$char$def mvi b,3 ; install 5e, 5f and 60 call char$install$group lxi h,17bh*16+DS$char$def mvi b,5 jr char$install$group ; call/ret page ; ; user function, HL supplied on the stack under the stack ; char$install$gp: pop h ; get return address xthl ; get HL from stack (ret adr to stack) ; ; this routine will install a group of characters form ; system memory into the video (character def) memory. ; ; INPUT: ; DE=system memory character definition ; HL=character code adr to install ; B=number of characters to install (should be > 2) ; OUTPUT: ; DE=eight more then on entry ; HL=character code adr to install + B*16 ; B=0 ; char$install$group: push b push h call char$install pop h lxi b,16 dad b ; advance to the next character pop b djnz char$install$group ret page ; ; this routine will install the character pointed to by DE ; into the 8563 ASCII char set, character number pointed ; to by HL. ; INPUT: ; DE=system memory character definition ; HL=character code adr to install ; OUTPUT: ; DE=eight more then on entry ; H=0 ; char$install: call set$update$adr ; mvi h,8 ; set the loop count install$char$loop: ldax d ; get the input data outp a ; save to video memory dcr c ; point to status register inx d ; advance the input pointer write$wait: inp a ; wait for the chip to write ral ; the data to memory (with auto jrnc write$wait ; incrment) inr c ; point to the data register dcr h ; dec the loop count jrnz install$char$loop ret page e USER command sets the current user number. The disk directory can be divided into distinct groups according to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> Th PAGE swap$code: @sei ; ffd5 @lda 3eh,# ; ffd0 @sta force$map ; ffd2 @lda z80$on,# ; ffd6 @sta mode$reg ; ffd8 @nop ; ffdb @jmp bios$02 ; ffdc @nop ; ffdf di ; ffe5 mvi a,3eh ; ffe0 sta force$map ; ffe2 lxi b,mode$reg ; ffe6 mvi a,z80$off ; ffe9 outp a ; ffeb nop ; ffed rst 1 ; ffee jump to load CP/M swap$size equ $-swap$code free$space equ 1000h-230-16-$ page ; ********************************* ; * * ; * Fixed data tables * ; * * ; ********************************* ; ; org 1000h-230-16 ; -246 ; ; 40 column color to RGBI ; color$convert$tbl: db 00h ; 0 black db 0fh ; 1 white db 08h ; 2 red db 07h ; 3 cyan db 0bh ; 4 purple db 04h ; 5 green db 02h ; 6 blue db 0dh ; 7 yellow db 0ah ; 8 orange db 0ch ; 9 brown db 09h ; A light red db 06h ; B gray 1 db 01h ; C gray 2 db 05h ; D light green db 03h ; E light blue db 0eh ; F gray 3 ; ; org 1000h-86-144 ; 8*18 ; -230 ; extra$char$table: db 000h,060h,030h,018h,00ch,006h,003h,000h ; 1 db 018h,03ch,066h,000h,000h,000h,000h,000h ; 2 db 000h,000h,000h,000h,000h,000h,07fh,000h ; 3 db 060h,030h,018h,000h,000h,000h,000h,000h ; 4 db 01ch,030h,030h,060h,030h,030h,01ch,000h ; 5 db 018h,018h,018h,018h,018h,018h,018h,000h ; 6 db 038h,00ch,00ch,006h,00ch,00ch,038h,000h ; 7 db 000h,01bh,02ah,066h,000h,000h,000h,000h ; 8 db 000h,000h,000h,000h,000h,041h,07fh,000h ; 9 db 000h,0f2h,05bh,039h,001h,04eh,065h,037h ; 10 db 006h,003h,01eh,007h,00bh,068h,04bh,034h ; 11 db 017h,001h,044h,062h,02dh,018h,012h,00bh ; 12 db 063h,059h,031h,017h,000h,00bh,059h,072h ; 13 db 02bh,018h,00fh,063h,000h,04fh,02bh,005h ; 14 db 04ch,068h,02dh,017h,016h,069h,049h,025h ; 15 db 017h,013h,045h,068h,029h,018h,017h,007h ; 16 db 00ch,068h,04bh,034h,013h,00fh,005h,04bh ; 17 db 070h,031h,00dh,00dh,008h,008h,06ch,00dh ; 18 org 1000h-75-11 ; -86 mmu$init$data: db 3fh,3fh,7fh,3eh,7eh ; config regs db z80$on,common$16K db 00 dir$ptrs: ; part of both MMU data and db 00,01 ; dir$ptrs db 00 org 1000h-75 ; -75 special$skew: skew 21,5,0 skew 19,5,0 skew 18,5,0 skew 17,5,0 org free$space end $adr ; mvi h,8 ; set the loop count install$char$loop: ldax d ; get the input data outp a ; save to video memory dcr c ; point to status register inx d ; advance the input pointer write$wait: inp a ; wait for the chip to write ral ; the data to memory (with auto jrnc write$wait ; incrment) inr c ; point to the data register dcr h ; dec the loop count jrnz install$char$loop ret page e USER command sets the current user number. The disk directory can be divided into distinct groups according to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> Thpip cxrom.asm=cxrom1.asm,cxromint.asm,cxrom80.asm,cxrom02.asm,cxromk.asm[v mac cxrom $$pz-s  special$skew: skew 21,5,0 skew 19,5,0 skew 18,5,0 skew 17,5,0 org free$space end $adr ; mvi h,8 ; set the loop count install$char$loop: ldax d ; get the input data outp a ; save to video memory dcr c ; point to status register inx d ; advance the input pointer write$wait: inp a ; wait for the chip to write ral ; the data to memory (with auto jrnc write$wait ; incrment) inr c ; point to the data register dcr h ; dec the loop count jrnz install$char$loop ret page e USER command sets the current user number. The disk directory can be divided into distinct groups according to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> Th MAKEROM.DOC CP/M 3.0 on the Commodore 128 28May87 To create the ROM BIOS used by CP/M on the Commodore 128 follow the procedure listed below. You will need a 1571 or 1581 disk drive, or a 1750 RAM disk, for this task. If you do not have one of these devices, you will have to make modifications to suit your system. Slightly more than a 200K space is needed for the procedure described. 1. Create a work diskette by using the FORMAT utility. If you are using a 1571 drive select the C128 double sided option. If you are using a 1750 RAMdisk (drive M:), make sure it is empty. 2. Copy the following files to your work disk, using the PIP utility: From USER 0: PIP.COM MAC.COM SUBMIT.COM From USER 2: CXROM.SUB CXROM1.ASM CXROM02.ASM CXROM80.ASM CXROMINT.ASM CXROMK.ASM CPM3.LIB CXEQU.LIB X6502.LIB Z80.LIB 3. To assemble new ROM code, select the drive which contains your work disk (eg, A:) and enter: 'SUBMIT CXROM' and the automatic process will begin. The output is in the file CXROM.HEX. 4. This code should be regarded as an invariant portion of CP/M for the Commodore 128, and is available as source for informational purposes only. For alternatives to the 'ROM Loader', see the source for the FORMAT utility (to support the 1581 disk drive, it was necessary to place a new Loader on the 1581 system track). e USER command sets the current user number. The disk directory can be divided into distinct groups according to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> Th title 'C128 Format Program 08 June 1987' ; modified 08June87 by V.Ertwine & F.Bowen: add 1581 support ; modified 07May86 by V.Ertwine: add more MFM formats ; original 15May85 by V.Ertwine: original release maclib z80 maclib cxequ maclib x6502 format$1581 equ true $*MACRO boot$code$02 equ 00B00h boot$code$80 equ 0E000h ; ; RAM loader equates ; rownum macro row,col db row+80h,col endm sys$name equ 000EDh ; cmp$hl$de equ 000FAh ; read$sector equ 0044Fh ; ext$error equ 00480h ; tell$user equ 004FFh ; table$error equ 0051Bh ; prt$msg$both equ 00526h ; prt$HL$both equ 00534h ; install$ASCII equ 005BDh ; wait equ 00945h ; ;BIOS$65$code equ 00D22h ; ;BIOS$size equ 001C3h ; ;F$rd$count equ 031BDh ; swap$code equ 00EE5h ; swap$size equ 0001Fh ; MMU$init$data equ 00FAAh ; page ;""""""""""""" ;E Q U A T E S ;""""""""""""" cret: equ 01 ; matrix position of return key disk$ready$key: equ 11 ; matrix position of $ ctrlc: equ 20 ; matrix position of c key yes$key: equ 25 ; yes - matrix position of 'y' key no$key: equ 39 ; 'no' - matrix position of n key cursor$up$key: equ 53h ; matrix position of up arrow cursor$dn$key: equ 54h ; matrix position of down arrow top$line: equ 0 ; screen top row for signon message use$line: equ 2 ; screen row for "using source" message keynam$line: equ 4 ; screen row for showing keyname lots$line: equ 6 ; screen row for showing big messages prompt$line: equ 10 ; screen row for showing menus spec$line: equ 23 ; status line row for special messages crlf: equ 0ffh ; code to do cr,lf do$6502$fun: equ 4 scrsz40: equ 20h ; flag value that this is a 40 column screen scrsz80: equ 40h ; flag value that this is an 80 column screen both: equ scrsz40+scrsz80 ; both of the above user$offset: equ 3*(30-1) page ;""""""""""""""""""" ;CP/M function calls ;""""""""""""""""""" bdos: equ 05 ;bdos call entry point conin: equ 01 ;char returned in a conout: equ 02 ;char sent in e constat: equ 11 ;console status cur$dsk: equ 25 ;get current disk to A getscb: equ 49 ;get system control block ;""""""""""""""""""""""""" ; 1581 Drive equates ;""""""""""""""""""""""""" ; constants buf$alc equ 081h ; allocate buffer 0 (no buf 7) ; memory location jobs equ 002h ; list of jobs to be done hdrs equ 00Bh ; header info (track and sector) buf$use equ 06Dh ; bit X set allocates buffer X next$job equ 083h ; pointer to next job to be done hdrjob equ 099h vtrans$ts equ 1B8h ; sector x-lat vector drv$buf equ 300h ; buffer 0 start adr ;boot$ret equ 0d35Ah ; will change with next ROM boot$ret equ 0FF5Ah ; return from drive boot code page ; pointer equ 20h ; DMA pointer used by 8502 cmdchn equ 15 ; use comand channel #15 ; ; KERNAL EQUATES ; serial equ 00A1Ch D2PRA equ 0DD00h D1SDR equ 0DC0Ch D1ICR equ 0DC0Dh clk$bit equ 10h K$set$bnk equ 0FF68h ; K$setlfs equ 0FFBAh ; setup a logical file K$setnam equ 0FFBDh ; set up file name for OPEN K$open equ 0FFC0h ; open a logical file (after SETLFS & SETNAM) K$chkout equ 0FFC9h ; open a channel for output K$clrchn equ 0FFCCh ; clears ALL I/O channel K$chkin equ 0FFC6h ; open a channel for input K$chrin equ 0FFCFh ; get a character from input channel K$chrout equ 0FFD2h ; output a character to output channel K$clall equ 0FFE7h ; close all open files K$close equ 0FFC3h ; close a logical file K$readst equ 0FFB7h ; read status byte page ;"""""""""""""""""""""""""""""""""" ;m a c r o d e f i n i t i o n s ;"""""""""""""""""""""""""""""""""" define macro label,for org ramalc label equ $ ramalc set ramalc+for endm save$top$bottom macro toprow,number mvi a,toprow+number-1 sta bottom$choice mvi a,toprow sta top$choice endm skip$and$destroy$hl macro db 21h endm zero? macro r1,r2 mov a,r1 ora r2 endm fmt macro fmtdef1,fmtdef2 DW fmtdef1 IF NOT NUL fmtdef2 DW fmtdef2 ELSE DW 0 ENDIF ENDM wrdef macro ?trk,?sect,?pointer db ?trk,?sect dw ?pointer endm defstart macro fillbyte IF NOT NUL fillbyte db fillbyte ELSE db 0 ENDIF ENDM defbuf macro ?count,?offset,?pointer dw ?count dw ?offset dw ?pointer endm definline macro ?count,?offset db ?count,-1 dw ?offset endm defexec macro ?adr db 0,-1 dw ?adr endm defend macro dw -1 endm page ;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" ;S T A R T H E R E ;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" org 100h ;"""""""""""""" ;initialization ;"""""""""""""" lxi sp,stack ;set up stack lhld 0001 ;read jump vector for i/o lxi d,user$offset ;..add this dad d shld go$user$fun+1 ;install vector to user BIOS functions lxi d,scbpbrd ;point to my parameter block mvi c,getscb ;..CP/M function to determine screen size call bdos mov a,h ani both ;..save whether 40,80 or both sta scrsiz ;NOW we are ready to start ;""""""""" ;SAY$HELLO: ;""""""""" call clear$screen ;set up to call posit$top ;..print signon message call print$msg db 'C128 CP/M FORMAT PROGRAM' db crlf db ' 08 JUNE 1987' db eom page mvi c,cur$dsk ; RETURN CURRENT DISK call bdos ; ..in A cpi 4 jrc select$new xra a ; if not A,B,C or D set A page ;---------- select$new: ;---------- mov b,a ; save in B for later mov c,a ; A=B=C= selection # (0-3) inr c ; (1-4) mvi a,80h ; rlc will give 01 select$next: rlc ; drive byte 0000dcba binary dcr c jrnz select$next sta fmt$drv sta vic$drv mov a,b ; get current drive select (0-3) sta sel$drv adi 'A' sta dsp$drv$1 sta dsp$drv$2 sta dsp$drv$3 ; ;***** login requested drive ; call get$disk$info ani 0Eh cpi 0Eh jz select$drv page ;-------------- ;show$disk$type: ;-------------- lda fast ;first tell user what type disk lxi h,fmt$drv ;point to format drive ana m ;..drive a= lst bit lxi h,3134h ; 0=1541 jrz show$slow$fast ; ; ;***** test for 1581 or 1571 ; ; if format$1581 mvi l,'8' ;assume 1581 lda vic$data cpi 0A3h ;horrible hack for *blank* disks! jrz show$slow$fast ; it is an empty 3.5" drive cpi 0A9h jrz show$slow$fast ; it is a virgin 3.5" diskette ani 0B0h ; cpi 020h ;Resident fmt with 512 byte sectors? jrz show$slow$fast ; yes, gotta be a 1581 endif mvi l,'7' ;none of the above, set as a 1571 show$slow$fast: shld a$15xx ;..store the type in message call clear$lots ; call posit$using call print$msg db 'Drive ' dsp$drv$1: db 'A is a 15' a$15xx: db 'x1',eom mvi a,use$line call highlight$line re$start: lxi sp,stack ; set up stack lda a$15xx cpi '4' jz get$1541$choices if format$1581 cpi '7' jz get$1571$choices ; cpi '8' ; jz get$1581$choices ; page ;--------------- ;get$1581$choices: ;--------------- call show$prompt ; db 'Please select disk type to format' db crlf,'Commodore 1581 (Double Sided)' db crlf,'Write system track only' db crlf,'Select Different Drive' db eom save$top$bottom promptline+1,3 call menu$response dw c128$ds$81 dw c128$sys$81 dw select$drv endif page ;--------------- get$1571choices: ;--------------- call show$prompt db 'Please select disk type to format' db crlf,'C128 Double sided' db crlf,'C128 Single sided' db crlf,'C64 Single sided' db crlf,'IBM Single Sided' db crlf,'IBM Double Sided' db crlf,'KAYPRO II' db crlf,'KAYPRO IV' db crlf,'EPSON QX10' db crlf,'OSBORNE DD' db crlf,'Select Different Drive' db eom save$top$bottom promptline+1,10 call menu$response dw c128$ds dw c128$ss dw c64$ss ; dw c1571$ibm$ss ; dw c1571$ibm$ds ; dw c1571$kp$2 ; dw c1571$kp$4 ; dw c1571$epson ; dw c1571$osborne ; dw select$drv ; page ;---------------- get$1541$choices: ;---------------- call show$prompt ; db 'Please select disk type to format' db crlf,'C128 single sided' db crlf,'C64 single sided' db crlf,'Select Different Drive' db eom save$top$bottom promptline+1,3 call menu$response dw c128$ss dw c64$ss dw select$drv ;---------- select$drv: ;---------- call show$prompt ; db 'Please select drive you wish to format with' db crlf,'Drive A' db crlf,'Drive B' db crlf,'Drive C' db crlf,'Drive D' db eom save$top$bottom promptline+1,4 call menu$response dw 0 ; continue execute inline jmp select$new page ; ; if format$1581 c128$ds$81: lxi h,c1581$dsk$def jr format$str c128$sys$81: lxi h,c1581$sys$def jr format$str endif ; ; c128$ds: lxi h,c128$ds$dsk$def jr format$str ; ; c128$ss: lxi h,c128$ss$dsk$def jr format$str ; ; c64$ss: lxi h,c64$ss$dsk$def jr format$str ; ; c1571$epson: lxi h,epson$dsk$def jr format$str ; ; c1571$osborne: lxi h,osborne$dsk$def jr format$str ; ; c1571$kp$2: lxi h,kp$2$dsk$def jr format$str ; ; c1571$kp$4: lxi h,kp$4$dsk$def jr format$str ; ; c1571$ibm$ss: lxi h,ibm$dsk$def$ss jr format$str ; ; C1571$ibm$ds: lxi h,ibm$dsk$def$ds ; jr format$str page ; ; ; format$str: ; call print$msg ; db 'Formatting',crlf,eom call print$what shld fmt$tbl$ptr call clear$prompt call print$msg db 'Insert diskette TO BE FORMATTED' db crlf,'in drive ' dsp$drv$2: db 'A. Type $ when ready,' db crlf,'any other key to abort ',eom call scan$for$key mov a,b cpi disk$ready$key jnz user$panics call clear$prompt call print$msg db '..formatting diskette in drive ' dsp$drv$3: db 'A',crlf,eom lhld fmt$tbl$ptr ; do the format call get$DE$from$HL ; get format table pointer (side 1) cnz format$DE$tbl call get$DE$from$HL ; get format table pointer (side 2) cnz format$DE$tbl call set$dsk$type page ; ; ; format$1: call get$DE$from$HL ; get track & sect mov a,d ; DE=-1 ? ana e inr a jz format$another? mov a,e sta trk mov a,d sta sect call print$msg db '..writing sector',cr,eom call get$DE$from$HL ; get DEF pointer xchg ; HL=DEF pointer, DE=MAIN pointer push d ; save MAIN pointer ; ; ; mov a,m ; get fill byte inx h call init$buf$with$A ; (HL saved) next$fill: call get$DE$from$HL ; get word count to DE jm count$minus mov b,d ; save count in BC mov c,e call get$DE$from$HL ; get offset in buffer push d call get$DE$from$HL ; get pointer to data xthl ; save DEF pointer get offset push d ; save DATA pointer lxi d,sect$buf dad d ; HL= buffer+offset pop d ; DE= DATA pointer xchg ; HL= DATA ptr, DE= buffer+offset ldir ; move data to buffer pop h ; recover DEF pointer jr next$fill page ; ; ; count$minus: inr e ; test for -1 jrnz cnt$not$minus$1 call write$data pop h ; recover MAIN pointer jmp format$1 cnt$not$minus$1: dcr e ; test for 0 jrnz data$inline call get$DE$from$HL xchg ; HL=code adr, DE=DEF pointer push d ; save DEF pointer call ipchl pop h ; recover DEF pointer jmp next$fill data$inline: mvi b,0 mov c,e ; BC=number of bytes to move call get$DE$from$HL ; get offset push h ; save DEF pointer lxi h,sect$buf dad d ; HL=buffer+offset xchg ; DE=buffer+offset pop h ; recover DEF pointer ldir jmp next$fill page ; ; ; format$DE$tbl: push h ; save MAIN pointer xchg ; HL=format table pointer mov c,m ; get count mvi b,0 ; count will be 1 to 255 inr c ; move count also lxi d,@buffer ; point to command buffer area ldir ; move format data to buffer lda fmt$drv ;..bit 0==drive a, MSB=unit 0 sta vic$drv mvi a,do$6502$fun mvi l,vic$frmt call go$user$fun ;call,ret ora a jrnz format$error pop h ret page ;------------ format$error: ;------------ call print$msg db ' format error',cr,lf,eom user$panics: pop h ;--------------- format$another?: ;--------------- call print$msg db crlf,lf,lf db 'Do you want to format another disk?' db eom call get$yes$or$no jc re$start ;----------- exit$format: ;----------- call clear$screen call posit$prompt call print$msg db '.....exiting format program',cr,lf,lf,eom exit$clean: mvi c,13 call bdos ; reset disk system mvi c,constat call bdos ana a jz 0 mvi c,conin call bdos jmp 0 ;--------- quit$prog: ;--------- push psw push b push d push h call posit$spec ;for special messages call print$msg db 'Are you sure? [ ]',bs,bs,eom call get$yes$or$no jrc exit$clean call posit$spec call clear$eol pop h pop d pop b pop psw ret page ;-------------- get$DE$from$HL: ;-------------- mov e,m inx h mov d,m inx h mov a,d ora e rz mov a,d ana a ret ipchl: pchl ;--------------- init$buf$with$A: ;--------------- push h lxi h,sect$buf shld dma mov m,a lxi d,sect$buf+1 lxi b,1024 ldir pop h ret ; ; set disk type to TYPE 0 (GCR direct sector I/O) ;------------ set$dsk$type: ;------------ push h mvi c,13 call bdos ; reset disk system lxi d,sel$pb call BIOS$ind dcx h call get$disk$info bit a,7 ; MFM disk? jrnz size$ok ; yes, then size is ok ani 30h ; no, 1571 GCR reports jrnz size$ok ; ...128 byte sectors mvi a,10h ; set 256 byte sectors size$ok: ani 00110000b ; set disk type to DSK$none mov m,a ; this will allow direct sector access pop h ret ;------------- get$disk$info: ;------------- push h mvi a,do$6502$fun mvi l,vic$test call go$user$fun ;call,ret mov b,a ;save status from drive in B also pop h ret page ;---------- write$data: ;---------- lxi d,dma$bnk$pb call BIOS$ind lxi d,dma$pb call BIOS$ind lxi d,trk$pb call BIOS$ind lxi d,sect$pb call BIOS$ind lxi d,wr$pb call BIOS$ind ana a rz pop h call posit$spec call print$msg db 'Disk write error',crlf,eom jmp exit$format page ;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" ; ;""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" beep: mvi e,7 jr do$con$out do$cr$lf: mvi e,cr call do$con$out mvi e,lf do$con$out: mvi c,conout jmp bdos BIOS$ind: mvi c,50 jmp bdos print$what: push h call clear$lots pop h call print$hl push h mvi a,lots$line call highlight$line pop h ret show$prompt: call clear$lots ; call posit$prompt ;----------------------------------------------------- print$msg: ;print a message on the screen ;----------------------------------------------------- xthl call print$hl xthl ret print$hl: push h print$lp: pop h mov a,m ;..get the message mov e,a ;in a for call to bdos inx h ;..update pointer ana a ;if char was 0, pointer = return address rz ;..end message push h ;..restore pointer inr a ;..FF==cr,lf jrz char$eq$cr$lf call do$con$out jr print$lp ;..loop char$eq$cr$lf: call do$cr$lf jr print$lp clear$prompt: call posit$prompt call clear$eos posit$prompt: lxi d,prompt$line*256+0 ; B=row C=col jr set$fx$cp$cmd clear$edit: call posit$editing call clear$eos posit$editing: lxi d,keynam$line*256+0 jr set$fx$cp$cmd posit$top: lxi d,top$line*256 jr set$fx$cp$cmd posit$using: lxi d,use$line*256 ; B=row C=col jr set$fx$cp$cmd clear$lots: call posit$lots call clear$eos posit$lots: lxi d,lots$line*256 jr set$fx$cp$cmd posit$spec: lxi d,spec$line*256 set$fx$cp$cmd: ;set up to position cursor mvi l,FR$cursor$pos jr go$screen$fun clear$eos: mvi l,FR$CES jr go$screen$fun clear$eol: mvi l,FR$CEL go$screen$fun: push b lda scr$siz mvi c,FR$40 cpi scrsz40 jrnz set$fx$eighty set$fx$forty: mov a,l add c mov l,a set$fx$eighty: mvi a,3 ; direct to screen fun # pop b go$user$fun: jmp 0000 ; address filled in page ;""""""""""""""""""""""""""""""""""""""""""""""""" ;s c a n f o r y e s o r n o a n s w e r ;""""""""""""""""""""""""""""""""""""""""""""""""" get$yes$or$no: call scan$for$key mov a,b cpi yes$key stc rz sui no$key ana a ;clear carry for no rz call beep jr get$yes$or$no ;""""""""""""""""""""""""""""""""""""""""""""" ;s c a n f o r k e y b o a r d i n p u t ;""""""""""""""""""""""""""""""""""""""""""""" scan$for$key: mvi a,2 call go$user$fun inr b jrz scan$for$key dcr b ret page ;""""""""""""""""""""""""""""""" ;c l e a r t h e s c r e e n ;""""""""""""""""""""""""""""""" clear$screen: call print$msg db 1ah,eom ret ;""""""""""""""""""""""""""""""""""""""""" ;g e t r e s p o n s e t o m e n u ;""""""""""""""""""""""""""""""""""""""""" menu$response: sta current$choice call highlight$line wait$ans: call scan$for$key mov a,b cpi cret jz made$selection cpi ctrlc cz quit$prog call up$or$down? cz scroll$values jr wait$ans made$selection: lda top$choice mov b,a lda current$choice sub b ;a=0-x for choices mov b,a ;..save it pop d mov l,a mvi h,0 ;first test if de is pointing to a 00 dad h ;*2 xchg ;(00--> just return) mov a,m inx h ora m inx h jrz back$to$?? dcx h dcx h dad d ;+ beginning of jump table mov a,m inx h mov h,m mov l,a back$to$??: mov a,b ;a=0-x pchl page ;""""""""""""""""""""""""""""""""""""""""""""""""""""" ;s c r o l l u p & d o w n t h r o u g h m e n u ;""""""""""""""""""""""""""""""""""""""""""""""""""""" scroll$values: push psw lda current$choice ;unhighlight the current menu line mvi h,0 ;..dont set any additional attributes call write$hi$line ;..common routine for writing current line pop psw ;get flags back jrc scroll$up lda bottom$choice mov b,a lda current$choice cmp b ;current==bottom && scrolldown?? jrz force$top inr a sta current$choice jr highlight$line ;call,ret scroll$up: lda top$choice mov b,a lda current$choice cmp b ;current==top && scroll up?? jrz force$bottom dcr a sta current$choice jr highlight$line ;call,ret force$top: lda top$choice ;to scroll down from bottom==top sta current$choice jr highlight$line ;call,ret force$bottom: lda bottom$choice ;to scroll up from top==bottom sta current$choice highlight$line: ;a=row # to be highlighted call read$this$row ;to highlight, read current row and mvi h,40h ;..write it out with rev vid attribute jr write$hi$line page read$this$row: push psw ;save the row number for others mov d,a ;d=row mvi e,0 ;column (e) = 0 lxi h,save$buffer ;a place to read into shld temp$ptr ;save a pointer xra a ;..initialize count to 0 sta read$count read$row$lp: push d ;..save it to loop mvi l,FR$rd$chr$atr ;read char and attribute from (de) call go$screen$fun ;go read a character lhld temp$ptr ;get buffer pointer mov m,b ;buffer the character inx h mov m,c ;..and the attribute inx h ;to next character shld temp$ptr ;save the pointer pop d ;current row,column inx d ;next row,column mov a,e ;when count(column)=, we have read maximum cpi 40 jrnz read$row$lp dcx h ;point to last character written mov b,e ;# of characters to scan for trailing spaces mvi a,' ' ;..space character to scan for scan$space$lp: dcx h ;char, not attribute cmp m ;..is char a space?? jrnz end$scan ;if not, we are done dcx h ;..else decrement to previous attribute djnz scan$space$lp ;keep looking end$scan: mov a,b inr a sta read$count ;store # of non-white chars to restore pop psw ;restore a=row # ret page write$hi$line: mov d,a ;current row passed in a mvi e,0 ;..start at column 0 mov a,h ;..additional attribute bits passed in h sta temp ;save attribute value to be ored lxi h,save$buffer ;where the current line was read into shld temp$ptr ;..save pointer to it lda read$count ;number of bytes actually in line (no trailing spaces) mov b,a ;..count in b wr$hi$li$loop: push b ;save the counter push d ;save the cursor position lhld temp$ptr ;get pointer mov b,m ;get char in b inx h ;point to attribute mov a,m ;..get attribute inx h ;update to next character shld temp$ptr ;..save the pointer mov h,a ;..put attribute here for a moment lda temp ;get the attribute passed (either rev vid or none) ora h ;..set it mov c,a ;..attribute must be passed in c mvi l,FR$wr$chr$atr ;write character and attribute functions call go$screen$fun ;go do it pop d ;cursor position back inx d ;..next pop b ;get counter back djnz wr$hi$li$loop ;..loop ret ;...line is rewritten up$or$down?: mov a,b ;get matrix row in a cpi cursor$up$key ;is it cursor up? stc rz ;..return if cursor up sui cursor$dn$key ana a ;clear carry flag ret ;return something to caller page ;------------------------------- ;p a r a m e t e r b l o c k s ;------------------------------- scbpbrd: db 24h ;set offset for conout db 0 ;..get (read)scb (hl =returnedword,a=byte) dw 0 ;just for the hell of it wr$pb: ;write parameter block db 14 ;write sector db 0 dw 0 dw 0 dw 0 sel$pb: ;select parameter block db 9 ; select drive function db 0 ; a sel$drv: dw 0 ; bc drive # dw 1 ; de lsb=0 means 1st time select dw 0 ; hl trk$pb: ;track parameter block db 10 ; set track db 0 trk: dw 0001h ; track # dw 0 dw 0 sect$pb: ;sector parameter block db 11 ; set sector # db 0 sect: dw 0001h ; sector # dw 0 dw 0 dma$pb: ;dma parameter block db 12 db 0 dma: dw 4000h ; dma pointer dw 0 dw 0 dma$bnk$pb: ;dma bank parameter block db 28 db 1 ; dma bank 1 dw 0 dw 0 dw 0 page ; ; 39-1 | 39-2 | 39-3 | ;"""""""""""""""|"""""""""""""""|"""""""""""""""| ; disk | BAM | BAM | disk | DRV | SYS | ; lable | 1 | 2 | DIR | boot | boot | ;"""""""|"""""""|"""""""|"""""""|"""""""|"""""""| ; 40-0 | 40-1 | 40-2 | 40-3 | 40-4 | 40-5 | ; ; ; 39-4 | 39-5 | ;"""""""""""""""|"""""""""""""""| ; LDR | LDR | LDR | | ; #1 | #2 | #3 | | ;"""""""|"""""""|"""""""|"""""""| ; 40-6 | 40-7 | 40-8 | 40-9 | ; if format$1581 c1581$dsk$def: db 'Formatting C128 CP/M on C1581',eom fmt fmt$tbl$c1581 wrdef 39,1,ST$sect$39$1 wrdef 39,2,ST$sect$39$2 wrdef 39,3,ST$sect$39$3 wrdef 39,4,ST$loader$start$1 wrdef 39,5,ST$loader$start$2 defend c1581$sys$def: db 'Formatting C128 CP/M on C1581',eom fmt 0 wrdef 39,1,ST$sect$39$1 wrdef 39,2,ST$sect$39$2 wrdef 39,3,ST$sect$39$3 wrdef 39,4,ST$loader$start$1 wrdef 39,5,ST$loader$start$2 defend endif page ; ; ; c64$ss$dsk$def: db 'C64 single sided',eom fmt fmt$tbl$c64$ss wrdef 1,0,ST$c64$1$0 ; track, sector, DEF wrdef 3,0,ST$E5s ; track, sector, DEF wrdef 3,1,ST$E5s ; track, sector, DEF wrdef 3,2,ST$E5s ; track, sector, DEF wrdef 3,3,ST$E5s ; track, sector, DEF wrdef 3,4,ST$E5s ; track, sector, DEF wrdef 3,5,ST$E5s ; track, sector, DEF wrdef 3,6,ST$E5s ; track, sector, DEF wrdef 3,7,ST$E5s ; track, sector, DEF defend page ; ; ; c128$ss$dsk$def: db 'C128 Single Sided',eom fmt fmt$tbl$c64$ss wrdef 1,0,ST$c128$1$0$ss ; track, sector, DEF wrdef 1,3,ST$E5s wrdef 1,4,ST$E5s wrdef 1,9,ST$E5s wrdef 1,10,ST$E5s wrdef 1,14,ST$E5s wrdef 1,15,ST$E5s wrdef 1,19,ST$E5s wrdef 1,20,ST$E5s wrdef 18,0,ST$sect$18$0 defend page ; ; ; c128$ds$dsk$def: db 'C128 Double Sided',eom fmt fmt$tbl$c64$ss wrdef 1,0,ST$c128$1$0$ds ; track, sector, DEF wrdef 1,1,ST$E5s wrdef 1,2,ST$E5s wrdef 1,3,ST$E5s wrdef 1,4,ST$E5s wrdef 1,7,ST$E5s wrdef 1,8,ST$E5s wrdef 1,9,ST$E5s wrdef 1,10,ST$E5s wrdef 1,12,ST$E5s wrdef 1,13,ST$E5s wrdef 1,14,ST$E5s wrdef 1,15,ST$E5s wrdef 1,17,ST$E5s wrdef 1,18,ST$E5s wrdef 1,19,ST$E5s wrdef 1,20,ST$E5s wrdef 18,0,ST$sect$18$0 wrdef 53,0,ST$sect$18$0 defend page ; ; ; epson$dsk$def: db 'EPSON QX10 512 byte sectors',eom fmt fmt$tbl$epson defend ; ; no sector to be set-up ; osborne$dsk$def: db 'OSBORNE Double Density',eom fmt fmt$tbl$osborne defend ; ; ; kp$2$dsk$def: db 'KAYPRO II',eom fmt fmt$tbl$kp$2 defend kp$4$dsk$def: db 'KAYPRO IV',eom fmt fmt$tbl$kp$2,fmt$tbl$kp$4 defend page ; ; IBM -- single sided disk definition ; ibm$dsk$def$ss: db 'IBM SS',eom fmt fmt$tbl$ibm$ss wrdef 0,1,ST$ibm$ss ; track, sector, DEF defend ; ; ; ibm$dsk$def$ds: db 'IBM DS',eom fmt fmt$tbl$ibm$ds wrdef 0,1,ST$ibm$ds ; track, sector, DEF defend page ; ; ; if format$1581 fmt$tbl$c1581: db 1 db 10000110b ;parameter N (cmd 4) db 2 ; sector size =512 db 79 ; last track # 79 db 10 ; number sectors/track db 0 ; starting track # db 0E5h ; fill byte db 38 ; gap 3 endif ; ; GCR Format parameters ; fmt$tbl$c64$ss: table$ds: db 4 db 00000110b ;parameter N (cmd 4) db 00000000b ;parameter MD (Mode GCR) db '8' ;parameter ID low db '0' ;parameter ID high ; ; ; fmt$tbl$epson: db 6 db 01100110b ; N cmd 4 db 10000001b ; MD Mode MFM (start sector 1) db 0 ; CP interleave of 0 db 2 ; SZ 512 byte sectors db 39 ; LT last track 39 db 10 ; NS 10 sectors/track ; ST Starting track logical (def 0) ; S Starting Offset Physical (def 0) ; FL Fill byte (def E5) ; ; ; fmt$tbl$osborne: db 6 db 01000110b ; N cmd 4 db 10000001b ; MD Mode MFM (start sector 1) db 0 ; CP interleave of 0 db 3 ; SZ 1024 byte sectors db 39 ; LT last track 39 db 5 ; NS 5 sectors/track ; ST Starting track logical (def 0) ; S Starting Offset Physical (def 0) ; FL Fill byte (def E5) page ; ; KAYPRO II (single sided) ; -- uses this format data to format the top and ; -- bottom of KAYPRO II and KAYPRO IV disk ; fmt$tbl$kp$2: db 6 db 01000110b ; N cmd 4 db 10000000b ; MD Mode MFM (start sector 0) db 0 ; CP interleave of 0 db 2 ; SZ 512 byte sectors db 39 ; LT last track 39 db 10 ; NS 10 sectors/track ; ST Starting track logical (def 0) ; S Starting Offset Physical (def 0) ; FL Fill byte (def E5) ; ; KAYPRO IV (double sided) ; -- uses this format data to format the top of the disk (side 1) ; fmt$tbl$kp$4: db 6 db 01010110b ; N cmd 4 db 10001010b ; MD Mode MFM (start sector 10) db 0 ; CP interleave of 0 db 2 ; SZ 512 byte sectors db 39 ; LT last track 39 db 10 ; NS 10 sectors/track ; ST Starting track logical (def 0) ; S Starting Offset Physical (def 0) ; FL Fill byte (def E5) page ; ; ; fmt$tbl$ibm$ss: db 6 db 01000110b ; N cmd 4 db 10000001b ; MD Mode MFM (start sector 1) db 0 ; CP interleave of 0 db 2 ; SZ 512 byte sectors db 39 ; LT last track 39 db 8 ; NS 8 sectors/track ; ST Starting track logical (def 0) ; S Starting Offset Physical (def 0) ; FL Fill byte (def E5) ; ; ; fmt$tbl$ibm$ds: db 6 db 01100110b ; N cmd 4 format DS db 10000001b ; MD Mode MFM (start sector 1) db 0 ; CP interleave of 0 db 2 ; SZ 512 byte sectors db 39 ; LT last track 39 db 8 ; NS 8 sectors/track ; ST Starting track logical (def 0) ; S Starting Offset Physical (def 0) ; FL Fill byte (def E5) page ; ; ; if format$1581 ST$sect$39$1: defstart 0 defbuf 29,0,sect$39$1 definline 8,100h db 40,2 ; next BAM track and sector db 44h,not(44h) ; DISK version # db '80' ; Disk ID db 40h ; verify off, check header ID on db 80h ; enable auto load defend ; ; ; ST$sect$39$2: defstart 0 definline 7,1 db -1 ; mark end of BAM db 44h,not(44h) ; Disk Version # db '80' ; ID db 40h ; verify off, check header ID on db 80h ; enable auto load definline 20,101h db -1 ; next track sector (end) db 83h ; type USR db 40,4 ; logical trk 40 sector 4 db 'COPYRIGHT CBM 86' definline 1,11Eh db 1 defend page ; ; ; ST$sect$39$3: defstart 0 definline 5,0 db 0,lng$drv$cd+5 dw drv$buf ; exec adr in drv db lng$drv$cd defbuf lng$drv$cd,5,drv$code$1581 defexec boot$check$sum ; compute Check SUM defbuf 0c9h,100h,boot$1581$sector defend ; ; ; ST$loader$start$1: defstart 0 defbuf 512,0,loader$start defend ; ; ; ST$loader$start$2: defstart 0 defbuf loader$size-512,0,loader$start+512 defend endif page ; ; ; ST$c64$1$0: defstart 0E5h definline 4,0 db 'KMBE' defend ; ; ; ST$c128$1$0$ss: defstart 0 defbuf 24h,0,sect$1$0 defend ; ; ; ST$c128$1$0$ds: defstart 0 defbuf 24h,0,sect$1$0 definline 1,255 db -1 defend page ; ; ; ST$sect$18$0: defstart 0 definline 4,0 db 1,5,41h,80h definline 4,48h db 11h,0fch,-1,7 definline 27,90h db 'CP/M PLUS' db 0a0h,0a0h,0a0h db 0a0h,0a0h,0a0h db 0a0h,0a0h,0a0h db '65',0a0h,'2A' db 0a0h,0a0h db 0a0h,0a0h defend ; ; ; ST$E5s: defstart 0E5h defend ; ; IBM single sided ; -- Track 0, Sector 1 last byte =0 ; ST$ibm$ss: defstart 0E5h definline 1,512-1 ; last byte=0 for IBM single sided db 0 defend ; ; IBM double sided ; -- Track 0, Sector 1 last byte =1 ; ST$ibm$ds: defstart 0E5h definline 1,512-1 ; last byte=0 for IBM single sided db 1 defend page ; ; Computes and sets the check SUM for the 1581 Drive Boot sector ; if format$1581 boot$check$sum: lxi h,sect$buf+2 lxi d,sect$buf+2+lng$drv$cd+3 mvi b,0 ; start SUM =0 sum$next: mov a,m add b aci 0 ; add carry to LSB mov b,a ; return sum to B inx h mov a,l cmp e jrnz sum$next mov a,h cmp d jrnz sum$next mov m,b ; save sum to end of buffer ret endif page ; ; 1541 and 1571 BOOT sector ; track 1 sector 0 sector definition (256 bytes) ; sect$1$0: db 'CBM',0,0,0,0,0,0 ; bytes 0 to 8 @sei ; byte 9 @jsr 0ff84h @lda 3eh,# ; set MMU to bank 0 @sta 0ff00h ; .. RAM and IO only @lda 0c3h,# @sta 0FFEEh @lda 08,# @sta 0FFEFh @lda 0,# @sta 0FFF0h @jmp 0ffd0h ; swap to Z80 (RST1 location) page if format$1581 CV equ drv$buf-$ my$trans$hi set high(my$trans+CV) my$trans$low set low(my$trans+CV) ; ; drv$code$1581: @sei @lda VTRANS$TS ; get old vector and save it @sta CV+code$exit$2+1 @lda VTRANS$TS+1 @sta CV+code$exit$2+2 @lda my$trans$low,# ; install new vector @sta VTRANS$TS @lda my$trans$hi,# @sta VTRANS$TS+1 @lda buf$alc,# @sta buf$use ; protect this code @jmp boot$ret my$trans: @ldx next$job @lda jobs,x ; get current job @cmp 80h,# ; is it a READ @bne code$exit$1 @ldy hdrjob ; get index @ldx hdrs+1,y ; get logical sector @bne code$exit$1 @ldx hdrs,y ; get logical track @dex ; was it one @bne code$exit$1 @ldx 40,# @stx hdrs,y ; change to logical TRK=40 @ldx 5,# @stx hdrs+1,y ; change to logical SECT=5 code$exit$1: @lda CV+code$exit$2+1 @sta VTRANS$TS ; get old vector and save it @lda CV+code$exit$2+2 @sta VTRANS$TS+1 code$exit$2: @jmp 0000 lng$drv$cd equ $-drv$code$1581 page ; ; 1581 Directory Sector ; sect$39$1: db 40,3 ; directory track & sector (logical) db 44h,0 ; Disk versions and null flag db 'CP/M PLUS',0a0h,0a0h,0a0h db 0a0h,0a0h,0a0h,0a0h,0a0h,0a0h db '80',0a0h,'3D',0a0h,0a0h page ; 1581 Boot sector ; track 1 sector 0 sector definition (256 bytes) ; BB equ boot$code$02-$ ; boot$1581$sector: db 'CBM',0,0,0,0,0,0 ; bytes 0 to 8 @sei ; (9) @jsr 0ff84h ; (A-C) reset I/O ; ; Clear Bank 0 memory ; @lda 3Fh,# ; (D,E) Enable RAM 0 @sta 0FF00h ; (F-11) @lda 10h,# ; (12,13) high byte of page pointer @sta 21h ; (14,15) save hiagh byte of pointer @lda 0,# ; (16,17) low byte of page pointer @sta 20h ; (18,19) save low byte of pointer @ldx 0EFh,# ; (1A,1B) from 1000h to FEFFh @tay ; (1Ch) start at 0 era$loop: @sta (20h),y ; (1D,1E) @iny ; (1Fh) @bne era$loop ; (20,21) @inc 21h ; (22,23) point to next page @dex ; (24) @bne era$loop ; (25,26) @sta 0FF00h ; (27-29) re-enable kernal and I/O ; ; load sectors that contain CP/M boot code (RAM version) ; ; open command chanel to drive 8 ; @lda 15,# ; (2A,2B) @ldx 8,# ; (2C,2D) @tay ; (2Eh) @jsr 0FFBAh ; (2F-31) SETLFS @lda 0,# ; (32,33) @tax ; (34) @jsr 0FF68h ; (35-37) SETBNK @lda 4,# ; (38,39) @ldx low(u0point+BB),# ; (3A,3B) @ldy high(u0point+BB),# ; (3C,3D) ;;;*** @jsr 0FFBDh ; (3E-40) SETNAM @jsr 0FFC0h ; (41-43) OPEN ; ; read sector 39-4 ; dma0 equ high(boot$code$80) @lda 39,# @ldx 4,# @ldy dma0,# @jsr rd$sector+BB ; ; read sector 39-5 ; @lda 39,# @ldx 5,# @jsr rd$sect$buf+BB ; ; install JMP BOOT$CP/M ; low$start equ low(boot$code$80) hi$start equ high(boot$code$80) @lda 0c3h,# @sta 0FFEEh @lda low$start,# @sta 0FFEFh @lda hi$start,# @sta 0FFF0h @lda 3eh,# ; set MMU to bank 0 @sta 0ff00h ; .. RAM and IO only @jmp 0FFD0h ; swap to Z80 (RST1 location) rd$sector: @sty 21h ; hi byte of DMA adr rd$sect$buf: @sta trk02+BB @stx sect02+BB @ldx 15,# ; CMD chan # @jsr 0FFC9h ; CHKOUT @ldy 6,# sendf: @lda R$cmd+BB,y @jsr 0FFD2h ; CHROUT @dey @bne sendf @jsr 0FFCCh ; CLRCHN @bit 0DC0Dh ; D1ICR @jsr read$byte+BB ; read status @ldx 2,# ; 2 256 byte blocks/sector @ldy 0,# @sty 20h ; low byte of DMA adr rd$buff: @jsr read$byte+BB @sta (20h),y ; at dma adr @iny @bne rd$buff @inc 21h ; advance DMA pointer @dex @bne rd$buff @lda 0DD00h ; D2PRA @and 0EFh,# ; @sta 0DD00h ; set clk hi @rts ; read$byte: @sei ; disable interrupts @lda 0DD00h ; D2PRA @eor 10h,# ; clock bit @sta 0DD00h @lda 8,# in$1: @bit 0DC0Dh ; D1ICR @beq in$1 @lda 0DC0Ch ; D1SDR @rts R$cmd equ $-1 db 1 ; count sect02: db 0 ; sector # trk02: db 0 ; track # db 0,'0' ; read comand =00h u0point: db 'U0',4Ch,0 ; Inquire Status page ; ZZ equ boot$code$80-$ LOADER$START: ; ; setup the MMU for booting CP/M ; lxi sp,boot$stack mvi a,3Fh sta force$map ; ; move bios and swap code into ram ; lxi h,bios$65$code+ZZ lxi d,bios$02 lxi b,bios$size ldir lxi h,swap$code lxi d,enable$z80 lxi b,swap$size ldir mvi a,RET ; get z80 return adr sta return$6502 ; store the RET ; ; initilize the 8502 bios ; xra a ; cleared by memory fill sta vic$cmd call enable$6502 page ; ; set MMU registers to a known state (for CP/M to use) ; lxi h,mmu$init$data+11-1 ; start at the End lxi b,mmu$start+11-1 ; and work forward mvi d,11 ; for all 11 bytes INIT$MMU$CPM: mov a,m ; get table value outp a ; send to MMU dcx h dcr c dcr d jrnz INIT$MMU$CPM ; re-enabled RAM bank 0 (no I/O) ; ; set 80 column colors and set up Video memory with ASCII char set ; mvi a,26 call wait mvi a,90h ; foreground red background black outp a mvi a,85h ; set attr and color sta current$atr ; ..for 80 column display mvi a,green ; set color sta attr$40 ; ..for 40 column display call install$ASCII ; convert char set to true ASCII mvi a,25 ; number of lines on the 40 col display sta paint$size page ; ; Let the user know we are booting CP/M ; call prt$msg$both db -1 ; clear both screens rownum 1,10 db 'BOOTING CP/M PLUS',0 ; ; point 40 column screen to CP/M screen area ; lxi b,VIC+24 mvi a,vic$screen*4/256+6 ; upper and lower case set (+6) outp a ; ; ; mvi a,64 sta block$size ; 64 dir entries/2K allocation lxi h,DIR$PTRS+ZZ shld ld$blk$ptr call SCAN$DIR+ZZ ; check 1st block call SCAN$DIR+ZZ ; check 2nd block (1K or 2K) lhld block$ptrs ; 1st pointer <>0 if file mov a,h ; name exist ora l ; pointer = 0 jz tell$user ; yes, inform user there is a error ; no, file FOUND, process it page ;---------------------------- ; load 1st group to 1K buffer ;---------------------------- FILE$FOUND: lxi h,block$ptrs shld ld$blk$ptr call UPDATE$BUFFER+ZZ ;-------------- ;GET$BOOT$INFO: ;-------------- lxi h,block$buffer lxi d,info$buffer lxi b,12 ldir call prt$msg$both rownum 10,0 db 0 ; end of string marker lxi h,block$buffer+80h call prt$hl$both lxi h,block$buffer+256 ; set scan pointer shld blk$unld$ptr page ;--------------------------------- ; load keyboard data to system RAM ;--------------------------------- call prt$msg$both rownum 3,12 db 'DATA TABLES',0 lhld info$buffer+10 shld key$tbl ; install keyboard translation pointer lxi h,info$buffer+9 call GET$SIZE$ADR+ZZ ; HL=adr DE=# (128 btye) records shld fun$tbl LOAD$NEXT$FORWARD: call LOAD$RECORD+ZZ ; HL =load address (in and out) lxi d,128 ; move pointer back to buf start dad d jrnz LOAD$NEXT$FORWARD page ;----------------------------------- ; transfer CP/M code to load address ;----------------------------------- call prt$msg$both rownum 4,12 db 'COMMON CODE',0 lxi h,info$buffer+1 ; load common code call LOAD$REVERSE+ZZ call prt$msg$both rownum 5,12 db 'BANKED CODE',0 lxi h,info$buffer+3 ; load banked code call LOAD$REVERSE+ZZ page ;--------------------------- ; now load the bios8502 code ;--------------------------- call prt$msg$both rownum 6,12 db 'BIOS8502 CODE',0 lxi h,info$buffer+7 ; load banked code call LOAD$REVERSE+ZZ lda info$buffer+7 ; get code size (in 256 byte blocks) mov b,a lda info$buffer+6 ; get page pointer (pointer to end) sub b ; find the start ; install jmp adr to BIOS02 sta return$z80+2 ; (jmp) (low) (high) xra a sta return$z80+1 ; (jmp) (low) (high) ;------------------------------------ ; now let's start executing CP/M Plus ;------------------------------------ lhld info$buffer+4 ; get start address pchl ; transfer control to CP/M page ;-------------; ; SUBROUTINES ; ;-------------; ; scan buffer for CPM+.SYS file ; SCAN$DIR: call UPDATE$BUFFER+ZZ ; returns HL=block$buffer mvi a,64 ; 64 for 2K block ; ..number director entries/sector CHECK$NEXT: shld @dma lxi d,sys$name ; point to system name push psw call name$match+ZZ cz FOUND+ZZ pop psw lhld @dma ; get current buffer pointer lxi d,32 dad d dcr a jrnz CHECK$NEXT ret page ; ; ; name$match: mvi b,12 xchg match$next: ldax d ani 7fh cmp m rnz inx h inx d djnz match$next ldax d sta ext$num xra a ret page ;---------------------------- ; save CPM+.SYS group numbers ;---------------------------- ; found a dir entry that has the right name ; add block pointers to list ; FOUND: lxi d,block$ptrs ; point to start of block pointers lda ext$num ora a jrz EXT$NUM$0 lxi d,block$ptrs+16 dcr a jnz ext$error EXT$NUM$0: lhld @dma ; get current pointer lxi b,16 ; number of bytes to move dad b ; also advance to block pointers ldir lhld block$ptrs mov a,h ora l ; 1st block present ? rz ; no, read more dir. lhld block$ptrs+14 ; extent full? mov a,h ora l jrz GO$BOOT$IT ; no, this is it then lhld block$ptrs+16 ; 2nd block present ? mov a,h ora l rz ; no, read more dir. GO$BOOT$IT: jmp FILE$FOUND+ZZ ; two parms are still on the stack ; but at this point who cares page ; ; ; LOAD$REVERSE: call GET$SIZE$ADR+ZZ ; HL=adr DE=# records (128 byte) LOAD$NEXT: lxi d,-128 ; move pointer back to buf start dad d call LOAD$RECORD+ZZ jrnz LOAD$NEXT ret ; ; ; GET$SIZE$ADR: mov e,m mvi d,0 ; get buffer size (#256 byte) mov a,e ; get size to A ora a jz table$error ; exit if count=0 xchg dad h ; HL=#128 byte blocks shld load$count xchg dcx h mov h,m mvi l,0 ret page ; ; ; LOAD$RECORD: push h ; save to address lxi h,block$buffer+2048 xchg lhld blk$unld$ptr call cmp$hl$de cz UPDATE$BUFFER+ZZ xchg lxi h,128 dad d shld blk$unld$ptr pop h ; recover save address push h xchg ; HL=source DE=dest. lxi b,128 ; size of move ldir lhld load$count dcx h shld load$count mov a,l ora h pop h ret page ; ; ; UPDATE$BUFFER: lxi h,block$buffer shld @dma push h ; save block buffer adr for ret lhld ld$blk$ptr ; get the current block pointer mov e,m ; get LSB of block pointer inx h ; advance pointer mov d,m ; zero MSB of block pointer inx h shld ld$blk$ptr xchg ; get block number to HL ; ; read the block pointed to by the HL ; into the data buffer ; dad h ; 2X (1k blocks) dad h ; 4x (512 byte blocks) push h call read$1K+ZZ ; read 1st 1K block lda @dma+1 adi 4 sta @dma+1 pop h inx h inx h call read$1K+ZZ ; read 2nd 1K block pop h ; recover block buffer adr ret ; ; convert block number (in HL) to sector and track ; read$1K: mvi a,2 sta F$rd$count+BZ ; lxi d,10 ; 10 sectors per side lxi b,-1 compute$trk: inx b ora a ; clear the carry dsbc d ; negative if <10 jrnc compute$trk ; jump if still positive >=10 dad d ; add it back mov a,c ; get trk # (0 to 159) cpi 39*2 jrc bump$trk inr a inr c bump$trk: rrc ; move bit 0 to carry mvi a,1 ; sector numbers are 1 to 10 jrnc side$0 mvi a,11 ; or 11 to 20 side$0: add l ; get sector # (0-9) sta VIC$sect mov a,c ; get trk # (0 to 159) rar ; divide by 2 (carry was cleared) sta VIC$trk jmp read$sector ; read the sector to the buffer DIR$PTRS: dw 0,1 page ; ; ; **** THIS IS THE COMMAND LOOP **** ; BZ equ bios$02-$ ; BIOS BIAS ; bios$65$code: @sei @lda 0,# ;-K @sta vic$data ;-K @JSR VICIO+BZ ;-K go find and do requested operation CMDLP: @sei @lda 3eh,# ;?K set up Z80 memory map as required @sta force$map ;-K @jmp enable$z80 ;-K ; ; **** IO COMMAND DISPATCH ROUTINE **** ; VICIO: @CLD ;-K clear to binary mode @LDA vic$cmd ;-K get the command @bne read ;-K 0=initialize ; 1=read page ; ; ; initilize: ; initialize the 8502 @ldx 0,# ;-K @stx force$map ;-K enable the kernal @stx VIC+26 ;+K turn off VIC interrupts @ldx low(irqs+BZ),# @ldy high(irqs+BZ),# @stx 314h ;+K IRQ vector @sty 315h @stx 316h ;+K BRK vector @sty 317h @stx 318h ;+K NMI vector @sty 319h ; ; **** OPEN DISK COMMAND CHANNEL **** ; @LDA cmdchn,# ;+K @CLC ;+K @JSR K$close ;+K @LDA cmdchn,# ;+K @LDX 8,# ;+K @TAY ;+K @JSR K$setlfs ;+K @LDA 0,# ;+K @TAX ;+K @JSR K$set$bnk ;+K @LDA 4,# ;+K @LDX low(U0PT+BZ),# ;+K @LDY high(U0PT+BZ),# ;+K @JSR K$setnam ;+K @JSR K$open ;+K @bcs misdsk @jsr K$readst @ROL A ;+K GET MSB TO CARRY @BCS MISDSK ;+K DEVICE MISSING IF CARRY SET @rts ; ; * DEVICE MISSING, CLEAN UP ERROR * ; MISDSK: @LDA 00fh,# ;+K SET ERROR CODE @skip2 fst$error: @lda 0dh,# ;?K @skip2 DISK$CHANGED: @lda 0FFh,# ;?K @STA vic$data ;?K writes to RAM under ROM @JMP CMDLP+BZ ;?K PAGE ; ; **** DISK SECTOR READ **** ; READ: @ldx 0,# ;-K get read command (side 0) @lda VIC$sect @cmp 11,# @bmi on$side$0 @ldx 10h,# ; get read command (side 1) @sbc 10,# ; remove bias of 10 on$side$0: @stx F$cmd+BZ @sta F$rd$sect+BZ @lda VIC$trk @sta F$rd$trk+BZ @lda @dma ;-K @sta pointer ;-K @lda @dma+1 ;-K @sta pointer+1 ;-K @lda 0,# ;-K @sta force$map ;-K @ldx cmdchn,# ;+K @jsr K$chkout ;+K @bcs fst$error ;+K @ldy Fcmd$lng,# ;+K sendf$rd: @lda Fcmd$buf+BZ-1,y ;+K @jsr K$chrout ;+K @dey ;+K @bne sendf$rd ;+K @jsr K$clrchn ;+K @bit D1ICR ;+K @ldx F$rd$count+BZ ;+K rd$sect: @sei ;+K @jsr rd$byte+BZ ;+K @and 0eh,# ;+K mask off error bits @bne fst$error ;+K @ldy 0,# ;+K start index at buffer start @jsr read$256+BZ ;+K read 1st 256 byte block @jsr read$256+BZ ;+K read 2nd 256 byte block @dex ;+K @bne rd$sect ;+K clk$hi: @lda d2pra ;+K @and 0ffh-clk$bit,# ;+K @sta d2pra ;+K @rts ;+K PAGE ; ; read$256: @jsr rd$byte+BZ ;+K @sta (pointer),y ;+K @iny ;+K @bne read$256 ;+K @inc pointer+1 ;+K @rts ; rd$byte: @lda d2pra @eor clk$bit,# @sta d2pra @lda 8,# rd$1: @bit d1icr @beq rd$1 @lda d1sdr @rts page ; ; handle all interrupts in BIOS 8502 (throw them away) ; irqs: @lda CIA$1+int$ctrl @lda CIA$2+int$ctrl @lda 0fh,# @sta VIC+25 ; ; system saved memory config, Y, X and A before getting here ; @pla @sta force$map @pla @tay @pla @tax @pla @rti PAGE F$cmd$buf: F$rd$count: db 2 ; 5 F$rd$sect: db 0 ; 4 filled in F$rd$trk: db 0 ; 3 filled in F$cmd: db 0 ; 2 read=0 db '0' U0PT: db 'U' ; 1 Fcmd$lng equ $-F$cmd$buf db '0',4Ch,0 ; reset disk change status (open) bios$size equ $-bios$65$code loader$size equ $-loader$start if loader$size > 2048 ' loader size error' endif endif page endofcode: ramalc set endofcode define top$choice,1 ; top row of these choices define bottom$choice,1 ; bottom row of these choices define current$choice,1 ; current row of these choices define fmt$drv,1 ; drive to do format on define fmt$tbl$ptr,2 ; pointer to current format table define save$buffer,80*2 ; save a row here define scrsiz,1 ; current screen size flag define temp,1 ; miscellaneous define temp$ptr,2 ; temporary ptr for moving tables define read$count,1 ; # of characters in saved line define top$of$stack,300 define stack,0 define sect$buf,1024 ; largest sector is 1024 end  ; CALLVERS program bdos equ 5 ; entry point for BDOS prtstr equ 9 ; print string function vers equ 12 ; get version function cr equ 0dh ; carriage return lf equ 0ah ; line feed org 100h mvi d,5 ; Perform 5 times loop: push d ; save counter mvi c,prtstr lxi d,call$msg ; print call message call bdos mvi c,vers call bdos ; try to get version # ; CALLVERS will intercept mov a,l sta curvers pop d dcr d ; decrement counter jnz loop mvi c,0 jmp bdos call$msg: db cr,lf,'**** CALLVERS **** $' curvers db 0 end  to place a new Loader on the 1581 system track). e USER command sets the current user number. The disk directory can be divided into distinct groups according to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> Th; Dump program, reads input file and displays hex data ; org 100h bdos equ 0005h ;dos entry point cons equ 1 ;read console typef equ 2 ;type function printf equ 9 ;buffer print entry brkf equ 11 ;break key function (true if char ready) openf equ 15 ;file open readf equ 20 ;read function ; fcb equ 5ch ;file control block address buff equ 80h ;input disk buffer address ; ; non graphic characters cr equ 0dh ;carriage return lf equ 0ah ;line feed ; ; file control block definitions fcbdn equ fcb+0 ;disk name fcbfn equ fcb+1 ;file name fcbft equ fcb+9 ;disk file type (3 characters) fcbrl equ fcb+12 ;file's current reel number fcbrc equ fcb+15 ;file's record count (0 to 128) fcbcr equ fcb+32 ;current (next) record number (0 to 127) fcbln equ fcb+33 ;fcb length ; ; set up stack lxi h,0 dad sp ; entry stack pointer in hl from the ccp shld oldsp ; set sp to local stack area (restored at finis) lxi sp,stktop ; read and print successive buffers call setup ;set up input file cpi 255 ;255 if file not present jnz openok ;skip if open is ok ; ; file not there, give error message and return lxi d,opnmsg call err jmp finis ;to return ; openok: ;open operation ok, set buffer index to end mvi a,80h sta ibp ;set buffer pointer to 80h ; hl contains next address to print lxi h,0 ;start with 0000 ; gloop: push h ;save line position call gnb pop h ;recall line position jc finis ;carry set by gnb if end file mov b,a ; print hex values ; check for line fold mov a,l ani 0fh ;check low 4 bits jnz nonum ; print line number call crlf ; ; check for break key call break ; accum lsb = 1 if character ready rrc ;into carry jc finis ;don't print any more ; mov a,h call phex mov a,l call phex nonum: inx h ;to next line number mvi a,' ' call pchar mov a,b call phex jmp gloop ; finis: ; end of dump call crlf lhld oldsp sphl ; stack pointer contains ccp's stack location ret ;to the ccp ; ; ; subroutines ; break: ;check break key (actually any key will do) push h! push d! push b; environment saved mvi c,brkf call bdos pop b! pop d! pop h; environment restored ret ; pchar: ;print a character push h! push d! push b; saved mvi c,typef mov e,a call bdos pop b! pop d! pop h; restored ret ; crlf: mvi a,cr call pchar mvi a,lf call pchar ret ; ; pnib: ;print nibble in reg a ani 0fh ;low 4 bits cpi 10 jnc p10 ; less than or equal to 9 adi '0' jmp prn ; ; greater or equal to 10 p10: adi 'a' - 10 prn: call pchar ret ; phex: ;print hex char in reg a push psw rrc rrc rrc rrc call pnib ;print nibble pop psw call pnib ret ; err: ;print error message ; d,e addresses message ending with "$" mvi c,printf ;print buffer function call bdos ret ; ; gnb: ;get next byte lda ibp cpi 80h jnz g0 ; read another buffer ; ; call diskr ora a ;zero value if read ok jz g0 ;for another byte ; end of data, return with carry set for eof stc ret ; g0: ;read the byte at buff+reg a mov e,a ;ls byte of buffer index mvi d,0 ;double precision index to de inr a ;index=index+1 sta ibp ;back to memory ; pointer is incremented ; save the current file address lxi h,buff dad d ; absolute character address is in hl mov a,m ; byte is in the accumulator ora a ;reset carry bit ret ; setup: ;set up file ; open the file for input xra a ;zero to accum sta fcbcr ;clear current record ; lxi d,fcb mvi c,openf call bdos ; 255 in accum if open error ret ; diskr: ;read disk file record push h! push d! push b lxi d,fcb mvi c,readf call bdos pop b! pop d! pop h ret ; ; fixed message area signon: db 'file dump version 2.0$' opnmsg: db cr,lf,'no input file present on disk$' ; variable area ibp: ds 2 ;input buffer pointer oldsp: ds 2 ;entry sp value from ccp ; ; stack area ds 64 ;reserve 32 level stack stktop: ; end  ; ECHOVERS RSX pstring equ 9 ; string print function cr equ 0dh lf equ 0ah ; ; RSX PREFIX STRUCTURE ; db 0,0,0,0,0,0 ; room for serial number jmp ftest ; begin of program next db 0c3H ; jump dw 0 ; next module in line prev: dw 0 ; previous module remov: db 0ffh ; remove flag set nonbnk: db 0 db 'ECHOVERS' space: ds 3 ftest: ; is this function 12? mov a,c cpi 12 jz begin ; yes - intercept jmp next ; some other function begin: lxi h,0 dad sp ;save stack shld ret$stack lxi sp,loc$stack mvi c,pstring lxi d,test$msg ; print message call next ; call BDOS lhld ret$stack ; restore user stack sphl lxi h,0031h ; return version number = 0031h ret test$msg: db cr,lf,'**** ECHOVERS **** $' ret$stack: dw 0 ds 32 ; 16 level stack loc$stack: end to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> Th;*************************************************** ;* * ;* sample random access program for cp/m 3 * ;* * ;*************************************************** org 100h ;base of tpa ; reboot equ 0000h ;system reboot bdos equ 0005h ;bdos entry point ; coninp equ 1 ;console input function conout equ 2 ;console output function pstring equ 9 ;print string until '$' rstring equ 10 ;read console buffer version equ 12 ;return version number openf equ 15 ;file open function closef equ 16 ;close function makef equ 22 ;make file function readr equ 33 ;read random writer equ 34 ;write random wrtrzf equ 40 ;write random zero fill parsef equ 152 ;parse function ; fcb equ 005ch ;default file control block ranrec equ fcb+33 ;random record position ranovf equ fcb+35 ;high order (overflow) byte buff equ 0080h ;buffer address ; cr equ 0dh ;carriage return lf equ 0ah ;line feed ; ;*************************************************** ;* * ;* load SP, set-up file for random access * ;* * ;*************************************************** lxi sp,stack ; ; version 3.1? mvi c,version call bdos cpi 31h ;version 3.1 or better? jnc versok ; bad version, message and go back lxi d,badver call print jmp reboot ; versok: ; correct version for random access mvi c,openf ;open default fcb rdname: lda fcb+1 cpi ' ' jnz opfile lxi d,entmsg call print call parse jmp versok opfile: lxi d,fcb call bdos inr a ;err 255 becomes zero jnz ready ; ; cannot open file, so create it mvi c,makef lxi d,fcb call bdos inr a ;err 255 becomes zero jnz ready ; ; cannot create file, directory full lxi d,nospace call print jmp reboot ;back to ccp ; ;*************************************************** ;* * ;* loop back to "ready" after each command * ;* * ;*************************************************** ; ready: ; file is ready for processing ; call readcom ;read next command shld ranrec ;store input record# lxi h,ranovf mov m,c ;set ranrec high byte cpi 'Q' ;quit? jnz notq ; ; quit processing, close file mvi c,closef lxi d,fcb call bdos inr a ;err 255 becomes 0 jz error ;error message, retry jmp reboot ;back to ccp ; ;*************************************************** ;* * ;* end of quit command, process write * ;* * ;*************************************************** notq: ; not the quit command, random write? cpi 'W' jnz notw ; ; this is a random write, fill buffer until cr lxi d,datmsg call print ;data prompt mvi c,127 ;up to 127 characters lxi h,buff ;destination rloop: ;read next character to buff push b ;save counter push h ;next destination call getchr ;character to a pop h ;restore counter pop b ;restore next to fill cpi cr ;end of line? jz erloop ; not end, store character mov m,a inx h ;next to fill dcr c ;counter goes down jnz rloop ;end of buffer? erloop: ; end of read loop, store 00 mvi m,0 ; ; write the record to selected record number mvi c,writer lxi d,fcb call bdos ora a ;error code zero? jnz error ;message if not jmp ready ;for another record ; ; ;******************************************************** ;* * ;* end of write command, process write random zero fill * ;* * ;******************************************************** notw: ; not the quit command, random write zero fill? cpi 'F' jnz notf ; ; this is a random write, fill buffer until cr lxi d,datmsg call print ;data prompt mvi c,127 ;up to 127 characters lxi h,buff ;destination rloop1: ;read next character to buff push b ;save counter push h ;next destination call getchr ;character to a pop h ;restore counter pop b ;restore next to fill cpi cr ;end of line? jz erloop1 ; not end, store character mov m,a inx h ;next to fill dcr c ;counter goes down jnz rloop1 ;end of buffer? erloop1: ; end of read loop, store 00 mvi m,0 ; ; write the record to selected record number mvi c,wrtrzf lxi d,fcb call bdos ora a ;error code zero? jnz error ;message if not jmp ready ;for another record ; ;*************************************************** ;* * ;* end of write commands, process read * ;* * ;*************************************************** notf: ; not a write command, read record? cpi 'R' jnz error ;skip if not ; ; read random record mvi c,readr lxi d,fcb call bdos ora a ;return code 00? jnz error ; ; read was successful, write to console call crlf ;new line mvi c,128 ;max 128 characters lxi h,buff ;next to get wloop: mov a,m ;next character inx h ;next to get ani 7fh ;mask parity jz ready ;for another command if 00 push b ;save counter push h ;save next to get cpi ' ' ;graphic? cnc putchr ;skip output if not pop h pop b dcr c ;count=count-1 jnz wloop jmp ready ; ;*************************************************** ;* * ;* end of read command, all errors end-up here * ;* * ;*************************************************** ; error: lxi d,errmsg call print jmp ready ; ;*************************************************** ;* * ;* utility subroutines for console i/o * ;* * ;*************************************************** getchr: ;read next console character to a mvi c,coninp call bdos ret ; putchr: ;write character from a to console mvi c,conout mov e,a ;character to send call bdos ;send character ret ; crlf: ;send carriage return line feed mvi a,cr ;carriage return call putchr mvi a,lf ;line feed call putchr ret ; parse: ;read and parse filespec lxi d,conbuf mvi c,rstring call bdos lxi d,pfncb mvi c,parsef call bdos ret ; print: ;print the buffer addressed by de until $ push d call crlf pop d ;new line mvi c,pstring call bdos ;print the string ret ; readcom: ;read the next command line to the conbuf lxi d,prompt call print ;command? mvi c,rstring lxi d,conbuf call bdos ;read command line ; command line is present, scan it mvi c,0 ;start with 00 lxi h,0 ; 0000 lxi d,conlin;command line readc: ldax d ;next command character inx d ;to next command position ora a ;cannot be end of command rz ; not zero, numeric? sui '0' cpi 10 ;carry if numeric jnc endrd ; add-in next digit push psw mov a,c ;value = ahl dad h adc a ;*2 push a ;save value * 2 push h dad h ;*4 adc a dad h ;*8 adc a pop b ;*2 + *8 = *10 dad b pop b adc b pop b ;+digit mov c,b mvi b,0 dad b aci 0 mov c,a jnc readc jmp readcom endrd: ; end of read, restore value in a adi '0' ;command cpi 'a' ;translate case? rc ; lower case, mask lower case bits ani 101$1111b ret ;return with value in chl ; ;*************************************************** ;* * ;* string data area for console messages * ;* * ;*************************************************** badver: db 'sorry, you need cp/m version 3$' nospace: db 'no directory space$' datmsg: db 'type data: $' errmsg: db 'error, try again.$' prompt: db 'next command? $' entmsg: db 'enter filename: $' ; ;*************************************************** ;* * ;* fixed and variable data area * ;* * ;*************************************************** conbuf: db conlen ;length of console buffer consiz: ds 1 ;resulting size after read conlin: ds 32 ;length 32 buffer conlen equ $-consiz ; pfncb: dw conlin dw fcb ; ds 32 ;16 level stack stack: end t test$msg: db cr,lf,'**** ECHOVERS **** $' ret$stack: dw 0 ds 32 ; 16 level stack loc$stack: end to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> Th title 'Add bios8502 to CPM3.SYS file 2 June 85' maclib seqio lxi sp,stack call disp$sign$on FILE outfile,CPM,,CPM+,SYS,16*1024 FILE infile,CPM3,,CPM3,SYS,4*1024 FILE infile,BIOS8502,,1,HEX,1024 FILE infile,KEYS,,CXKYCODE,HEX,1024 lxi h,load$bios$msg call disp$loop call load$bios$8502 ; load hex file to buffer lxi h,load$key$msg call disp$loop call load$keys ; load hex file to buffer lxi h,add$vect$msg call disp$loop call add$vectors ; add the new vector pointers lxi h,inst$key$msg call disp$loop call insert$key$defs ; add FUNCTION KEYS and KEY definition lxi h,inst$cpm$msg call disp$loop call finish$rest ; transfer rest of system over lxi h,inst$bios$msg call disp$loop call add$bios$8502 ; save bios8502 to CP/M file lxi h,closing$msg call disp$loop finis CPM jmp 0 ; exit back to CP/M page load$bios$msg: db 'Loading 8502 BIOS .HEX file',cr,lf,0 load$key$msg: db 'Loading Key definition .HEX file',cr,lf,0 add$vect$msg: db 'Adding new vectors to CPM+.SYS',cr,lf,0 inst$key$msg: db 'Adding Key def. to CPM+.SYS',cr,lf,0 inst$cpm$msg: db 'Adding CPM3.SYS to CPM+.SYS',cr,lf,0 inst$bios$msg: db 'Adding BIOS8502 to CPM+.SYS',cr,lf,0 closing$msg: db 'Closing CPM+.SYS file',cr,lf,lf,lf,0 page ;; ;; ;; load$bios$8502: xra a sta file$num ; use bios8502 file for HEX input call read$header ; get BIOS8502 start adr mov a,l ; LSB should be zero ora a jnz adr$error push h mov a,h sta bios$addr cma mov h,a inr h ; two's comp of start adr lxi d,buffer$bios$8502 dad d shld bias pop h call finish$load hex$load: jc done$bios8502 ; done when carry set call load$record jmp hex$load done$bios$8502: lhld hex$addr ; get last address lxi d,buffer$bios$8502 mov a,l sub e mov l,a mov a,h sbb d mov h,a mov a,l ora a jz size$ok inr h size$ok: mov a,h sta bios$size cpi 4096/256 jnc size$error ret page load$keys: mvi a,-1 sta file$num ; use KEYS file for HEX input call read$header ; get KEYS start adr mov a,l ; LSB should be zero ora a jnz adr$error push h mov a,h sta keys$addr cma mov h,a inr h ; two's comp of start adr lxi d,buffer$keys dad d shld bias pop h call finish$load hex$load$keys: jc done$keys ; done when carry set call load$record jmp hex$load$keys done$keys: lhld hex$addr ; get last address dcx h dcx h ; two byte header for key def adr lxi d,buffer$keys mov a,l sub e mov l,a mov a,h sbb d mov h,a mov a,l ora a jz keys$size$ok inr h keys$size$ok: mov a,h sta keys$size cpi (1024/256)+1 jnc size$error ret page ;; ;; ;; add$vectors: mvi b,6 ; use first 6 bytes of old header get$1st: push b ; read in the header info GET CPM3 PUT CPM pop b dcr b jnz get$1st ; remove next six bytes from old header get CPM3 ; bios8502 top page # get CPM3 ; bios8502 # of blocks (256 bytes) get CPM3 ; KEYS bottom page # (function key adr) get CPM3 ; KEYS # of blocks (256 bytes) get CPM3 ; key definition adr (low) get CPM3 ; key definition adr (high) lda bios$size ; install load info into header mov b,a lda bios$addr add b put CPM ; bios8502 top page # mov a,b put CPM ; bios8502 # of (256 byte) blocks ; ; install MSG tbl and FUN tbl pointers ; lda keys$addr put CPM ; function key start adr (high only) lda keys$size put CPM ; KEYS # of (256 byte) blocks lhld buffer$keys mov a,l push h put CPM ; key definition adr (low) pop h mov a,h put CPM ; Key definition adr (high) ; ; only move 256 bytes total (128 bytes info, 128 message) ; mvi b,256-6-6 ; number of bytes left to move get$2nd: push b ; read in the header info GET CPM3 PUT CPM pop b dcr b jnz get$2nd ret page ;; ;; add FUNCTION KEYS and KEY definition ;; insert$key$defs: lxi h,buffer$keys+2 ; 1st two bytes point to the ; ..key definition insert$keys$loop: mvi c,0 ; save 256 bytes call save$loop lda keys$size dcr a sta keys$size jnz insert$keys$loop ret ;; ;; transfer rest of system over ;; finish$rest: get CPM3 ; save CPM3.SYS to CPM.SYS rz put CPM jmp finish$rest page ;; ;; ;; add$bios$8502: lda bios$size mov h,a mvi l,0 lxi d,buffer$bios$8502 xchg dad d ; HL=next free address DE=size mov a,d ; number of 256 byte blocks add a ; number of 128 byte blocks mov d,a ; save count in D save$next: lxi b,-128 dad b ; back up the pointer push h push d call save$128$bytes pop d pop h dcr d jnz save$next ret ; ; ; save$128$bytes: mvi c,128 save$loop mov a,m push h put CPM pop h inx h dcr c jnz save$loop ret page ; ; ; load$record: call read$header ; record adr in HL finish$load: xchg lda hex$count cpi 0+1 ; see if length=0 stc ; set END OF FILE rz ; null record marks the end lhld bias dad d shld hex$addr call read$byte ; this byte should be a zero ana a jnz hex$error hex$record$read: lda hex$count dcr a sta hex$count jz hex$record$done call read$byte lhld hex$addr mov m,a inx h shld hex$addr jmp hex$record$read hex$record$done: call read$byte lda hex$sum ana a ; clears carry (marks end of record) jnz hex$error ret read$header: xra a sta hex$sum call read$hex$byte ; get input character jz hex$error ; missing char is a problem cpi ':' jnz read$header call read$byte ; get record length inr a sta hex$count call read$byte ; get high address mov h,a push h call read$byte ; get low address pop h mov l,a ret read$byte: call read$hex$val ; get a hexadecimal value rlc rlc rlc rlc ; move to upper 4 bits push psw call read$hex$val ; get a hexadecimal value mov b,a pop psw ora b ; make a data byte from two hex digits mov b,a lda hex$sum ; add to sum add b sta hex$sum mov a,b ; return byte value ret read$hex$val: call get$upper ; force to upper case mov b,a sui '0' ; remove number bias jm hex$error cpi 9+1 ; return if a number rc sui 'A'-'0' ; remover extra if A to F jm hex$error adi 10 cpi 0fh+1 rc ; return if valid hex number (0-F) hex$error: lxi h,hex$mess jmp dsp$and$exit get$upper: call read$hex$byte jz hex$error cpi 'a' rc ani 5fh ret read$hex$byte: lda file$num ora a jz read$hex$fst get KEYS ret read$hex$fst: get BIOS8502 ret adr$error: lxi h,adr$mess jmp dsp$and$exit size$error: lxi h,size$mess dsp$and$exit: call disp$loop jmp 0 page disp$sign$on: lxi h,message disp$loop: mov a,m ora a rz inx h push h PUT CON pop h jmp disp$loop message: db cr,lf,lf,lf,lf,lf,lf,lf,lf,lf,lf,lf,lf,lf db ' This program will create a CPM+.SYS file from',cr,lf db ' The CPM3.SYS file (created by GENCPM) and',cr,lf db ' The 6502 BIOS File supplied in Intel HEX format',cr,lf db ' And CXKYCODE File supplied in Intel HEX format',cr,lf db ' (1st HEX address is FUNCTION table address)',cr,lf db ' (1st two bytes point to ASCII table)',cr,lf db lf,lf db ' The ROM boot code will load the CPM+.SYS file',cr,lf,lf db 0 hex$mess: db 'HEX file error - first record must be start adr and',cr,lf db ' last record must contain the last adr' db cr,lf db ' All other address must be between',cr,lf db ' the start and end adr',cr,lf db ' also HEX file must be ended with a NULL record',cr,lf,lf db ' and ' adr$mess: db 'Start address must be on a page boundary',cr,lf,lf db ' and ' size$mess: db 'File can NOT be larger than 4K',cr,lf,0 keys$size: ds 1 keys$addr: ds 1 bios$size: ds 1 bios$addr: ds 1 bias: ds 2 hex$count: ds 1 hex$addr: ds 2 hex$sum: ds 1 file$num: ds 1 buffer$bios$8502: ds 4096 buffer$keys: ds 1024+2 ds 60 stack: buffers equ stack end L3),3* ( i(L{'I- -) f( I& {' ` ( f( I&) I&)  I&)ݭ $L ( *  1 .( ) L L0) ( ))* )$ )x? 2L.( 7&x> L.&]&&&'''N'''4& (#( *ll  iG&l&xIݩ, `) *$ Ơ0 , ܮ0x 0)Ъ 0 0)` 0 !`Iݩ, ` ܭ ݩhhhh@0U0Le USER command sets the current user number. The disk directory can be divided into distinct groups according to a "User Number." User numbers range from 0 through 15. ///2Examples A>USER Enter User#:5 5A> Th