IMD 1.17: 24/12/2010 11:56:16 v rom x3.094 4/4/83 \X COPYRIGHT (C) 1979, DIGITAL RESEARCH _͌> ͒> Ò> Ò͘~#͌ì _2<˯2 ̇!Ҷ2:2a{_:ҷʖ:ҷ>Ľʖ:=2–!B!6#5ʖ:ҷĽ!ͬʧ )!F#xʺ~0wëw!" !~6ͽ:ý(!#͘*~ "ͷ"͌#>?͌͘ =_.:;<> Oͅo$>!Y2*O"ʉ@G:ʐ:wÖx2p0ʹ#*©6?ëw˜0ï#6 ¹.0#*6?w0#6 #6" #~?  xDIR ERA TYPESAVEREN USER!yO#< Ty#O 3ί21y_͸2y2ͽ:˷˜1͘A͌>>͌92^ :ҷ¥.!_~#fow]Эюѥ!v"!çREAD ERRORçNO FILE^:ҷ ! ~ 3#0 Wx x ̀ ͂ G ~ # 3x~#B!Y~ɯ2:ҷ=!Ҿý:ҷ=!Ҿ:ý^T!~  6?#ˆ:`O> K{͘A͒>:͒͢>:͒͢xK > K > ͒x  ͢ØÆ^ BRͧ9!5‚#~Y‚#"T<ÆALL (Y/N)?^ Tʧ͘!6!~ڇ Яw4!Y~ʆ͌†t=ʆf ^ T Я2o&)|+!<ͧÆNO SPACE^ :Ty!B*O=?_s#"^sG!~YѸpsp2mÆÆf ͧÆFILE EXISTS _: É: :ҷʉ=2)ͽÉ T!@k!}|q=qf^!~2>`~2ү2\!!B!~> >#0~O#Cx2͘1)ͽÂf zͧÆBAD LOADCOMf^: !Ҷ Â$$$ SUBәӥӫӱ"C{2!"E9"1A֯22!ty)K!G_^#V*CՐ~߃Eߜߥ߫ ,&-AGMS֛!!ô!ô!Bdos Err On : $Bad Sector$Select$File R/O$:BA2!~6 O͐  :ַE B 2>: ַb# : ַy! 4 5~yy5 6yҐ^H@Oy H H: –ͬ  #H: ! ־ Hù H H $O͐: 2 *CN# x: 2 p&x~+é7ԯ2 H! >w_: ! ־5ͤNkͱ¦ͱxʊ#Nx: ַ! ֖2 ͤ! 5™#wO~x½p Hy<< ʑ :!qMD#2E>! ^#V w#P:BO|^#V#"##"##"##"!O*!O*|!6ʝ6>*w#w*w#w'û*! J*""!N#F*^#V*~#foyx*{_zW+*yx#*DM*s#r*s#ryOxG*0MD!!N: EG>O: \׷S׀*C :qn& ^#V>O^"*}:*)=":O:ࡵo"*C *C!ͮ~2~2ͦ:2ͮ:ׯO:w:w |g}o*ெ# ):BO!yoxg*:BO}!N#F "*#*s#r^ ~!J! J*:o$*C~i6iw**{#zr+s{ozg**͕** ؾ,w͜͸Ͳ!!N#F$**O!~#:A־#~$=2Ek͌::/GyO>2!q*C"͡ʔ*JҔ^:Oyʃ?|x | sږ-|N-# S:2E!~Яw>T D^6k-äPYy 5*{zBK5ڋ>*Cw~#+w#w+ɯ2E22i^ *C :~w~͔͔# #  w ~>2!E5T*C!"C"C!w# F! w͌xد2͢*C ~<wʃG:!ʎì 4~ʶ¬:<ʶ$ʶïZͻׯx>2>2ͻ:!Zܯ2:Eַẅ́͊Ͳ>2>2T*CGͻ:ẅ́n>2;O ^DM;}H>"*C ::ddslO s#r:Eַ͊:==»y==»*Ww#*"͸*:G#š"͸:!w4!iw:Z!E~=26ׯ2*C!!~~#~O~G#n,-.‹! w! yG!x͢.:E<ʄ! q!pQ:E<. ʄ$.:E<ʄi6}2ExN! ~态O>G~G!~G} *C!r#r#r ^ͥ_y#x#{s+p+q-*C ͥ!!q#p#w*:BOYG}*MD "ã:!B־w!>2*C~=2:B2~2wE:A*Cֶw>"!""2B!"!rQQQâ~?ͦ~?rQ*"CQ-Q͜QüQrQ$Q*):B"*)*)Q;*"E:;:A2AQÓQÜQ*C}/_|/*W}_*"}o|g":ʑ*C6:ʑw:2E**E}DQ>2!u ÷ÿ M[`e~ xyz{|}~AUTOST 0123456789 [9 [I!,@Rv         !"#  (?-?R ?$?1:922< 1>͛!6>2`!">22!"!"!p:o(~( O>(͚!:ONENCORE 59k CP/M vers 2.2 Rev X3.094 gG 1983 OSBORNE SOFTWARE TEST ONLY 222yF2!!"͞.* ^#V22*ut| V:A2{2͚!:2% Can't recognize diskette on drive ! Unformatted diskette on drive !y(##NF*BC(|0}0- XxQ('Y(''!! ( ##2"+y(#*~w#~w !~w#~w>K:G:2:Oz2{2y2:ȯ2y2Cɯ2[ȯ2yŸ:>(>2:2:<!~ʾ5:G:<¹!42*<2y(:ȯ2:2:2:2:2!42:G:!( 0)2:(! #ѯ>2:22:22:22:22 :(ѯ!4:(2y2i`{n&!!GO!): !1: :b!!:_^#fk!]~ 5#͟!A!1!)!9I lISoS q [ %q :b!b~( *Y~480#'_!>nf^VSYR}2b:<_!^#~@W>!{(>!z(!>(>!>(1111>@1:;1>'1Ɉ CA}hE4# 11 (0(y0:: >   >!>(/ɯ[(>!y(>!>(>( IS IN ERROR RESET DEFAULT TO DRV A STO A,CDISK ;SET DEFAULT TO A RET DENERR: DB DENL DB CR,LF,'Can''t recognize diskette on drive ' DRV: DS 1 DENL: = *-DENERR-1 FORERR: DB FORL DB CR,LF,'Unformatted diskette on drive ' DRV1: DS 1 FORL: = *-FORERR-1 PAGE CHKSEL: ;Determines if new DPB should be established ;ENTRY ;C = disk selection value (0..15) ;E = BIT0 = 0 IF first call for this disk ;EXIT ;IX = address of drive sequence number ;Z status bit set, good return ;ZACT COMt PIP COM:~VROM ASMVROMEND ASMVROMMAINASM !"#$VROMMAINASM%&'()*+,-./01234VROMMAINASM56789:;<=>?@ABCDVROMMAINASMEFGHIJKLMNOPQRSTVROMMAINASMUVWXYZ[\]^_`abcdVROMG DOCVROMMAINASMefghijklmnopqrstVROMMAINASM.uvwxyzVROM $$$VROM $$$ACT I 808x Copyright SORCIM Corp. 1981 S/N- 007,Version 3.5EEV SorcALL ASMFilenameHEXFilenamePRNτ?1;͟4199!42 ͣ'6 #6 #6͎ 4!:f'*:;'*:;'F<*99>T29>2a$o*9|LH&*9*9*9(%b;'*9*9(%! ͩ"e:U&*:;'!HHF*|ʧ&!"F*e:|:9!B6 29!l$ Last error occurred on Page 123 Total LOST references were !?="9*9"929go"9*9&"9>s2K2:2:͎ 2929292929292929292Q:go"9!e:"^:"9*9":"9:92:5:9=29>2929>T29> 2K*9196:94H*:"9*9"9*9X!.X:9͓*9 "9:9:9*9}eG:9=__ͻ$#D> 24d"`:~G&vG!.#%fh"c:2e:*9"nx(:9¶ x= :9:9x(=:c:G 6)!K="9! B629>22>22J! :9ĭ!$:9ĭFUnterminated IF nest. IUnterminated MACRO definition. !.~O#%~wy<#%J*9*9 ~w# œ~?ʜp ^#V#N#F r+s 9'n!ͭ~24#W$OToo many PROCs in program. *9?9' "9*9 "9yx  !e: f':d:_ :9¶!"f:":>(=*9"n!%4:c:#%^#V>SE>E24\*^:}!e:"^:2d::9 e::d: !9>wd:G::ʁ!4 W † :9 ͓!9~wÁn>-24>O>Y>S>E>A24*n|c~c=ͅ"::s2:ͨ :9ʽ:9>Y:9>F24292929͗!T.:9>P?*9~24 ͒ | >P24 R::9pͬ% ͬ/ƒͺ:9Ҿp %ҭ!f'!9~G?2:>N*nͻ,#!94:9ʤ>Ov ͼ ðv":"9:s2:2:> 2:Dv"9:s2:G::’*:9'> ʔ>#2:!4wðv:rG:e:N:9*:°>L24ð!e:~"^:*92~c!e:~"^:2*92ͬc!e:"^:v | } >W24>2[:\> ͒"\:, ::*^:w\>S24\*9e:':9 b *9?9'>O "9 *n~*!99ʽ f'ͬ-™ ͬ+ ͭ>UN!9{_~wͬ,ʋ N'*n#~T L@ C D F G M R͒:9@S ͒U͍f:9@͍^!9F6:96 I :9@I ͍!9~w*9~>S## C>E>S~29*9#N# f'! f'! W$Unknown CPU: '' ͓!46'#*9ͩ Of' ;' !) ͍'!4>!O$͓' 2929v}29| :9ͤ=D !94:e:- *9?>L͇ "9< ####>*9##"9'!:͡':92:*9:*9 f'"9x #"95%*9~w##s#r*9##h'%0+  3 Ƃ~ G >@w!:͆>w :9ē*9#"9 *c3 ~ ʪ(~w##^#V*9ʠ w#Ò ͤO:9= y*9#%N#Fx w# Ò *9"9|~ : # !"96!"9*9"9!9"9*9;'*9!9f'*9zV  6 s#r#Z ,;  >P ) s#r#"9x29O:9Gʃ ˆ =29} :9¶29>F:9ʴ ¶} :e:b !94:9¶vz°n:9ē:929*9"9*:":Y*9"9*9"9>L >S24!::9w:9 {: :9Ox~ :92*:*:":":͙ x (::2:>*9G:92:":!"9*9|? *n~}:} 1"9F::O@°yw*:#::w#s#rx ʴx@´>w:9x>D :9>:9:[:O::G!d:yO4Q Jx2::[:*\: lMW͛%O::_G͆%!:w{=@~6*^:w#"^:!d:4 ::W{2:[: !46^#þ':9M*9##(%"f:!46=##þ' ͩʝV=ʝ#^=ʝ>V24*^:s#r+y *^:>A+w¬ͩOGx!46V*n+6:d:2d:*^::9y#% Aw# "^:*n+~#:9(=*9"n*94;'::;>~;7ʧ*7ʧ 7ʧ:9¡ ڧ'.!_ʚ;Œ:9¯> #„òaژ{Ҙ #V#Ҟ#:9ʲ*9"9 ʵ>!;?~   7ȷy#:9ʲ*9ͤõ#N f'V>#"'#~'"# x)+pV9 B#0+> !"9"9"9!9!;~ p ~# f}| fO!~ʌ#7y,+-*/()><=^&[] : \(%*9*99'+~ y¹*99'"929*9.:9g"9"9:9 *9*99' "9>a*<<4:9W~#29  F  Rf> z > : "<<> `i"9!429z29 >=9'ҁͪ> !\#!7\\\ END Statement Missing !><\#6y  !W$ACT stopped by user. *99'"9"9\ f'ͻ#$!Ve%!VC f'>2a$!C͂$f$!>="<<6 Pass 1 - Reading D:FILENAME.EXT ;}; ͒:r >Uá*9"n|’7*nͩڤ?>E247go!"t."r!9"jz>Sͼ2l K*h};9'+~ffbMb*h};9' *f;9';A:@2s"tb*h9'+~H"h> 2l!z#%9'F#N   de~# ʼ+"n>2l!;"f!};"h6>2q>E*j24!"tt>2s7ͬ0 :Q:zzB~G#4V#^6Z6T]#%>2rxß*n+ͭ"n#~G:l x+~!9Oʃ!:Pʃ!9Lʃ>2r^#V#F>ßG> x,\]/*$+^^^&()=<> <= >= < > ~-ANDDEFEQGT GE HIGHLE LOWLT MODNE NOTORREVSHLSHRXOR+%>N>2r>#ß:px2p%x2pU+ͭڒ{ڒ#~"n*n+:s*n2s"n,> *n|ͻ#"n#~ ʺ*n+~ȷ+"n*f;9'>O+~2r+~+^+V"f:r2r2s=#%~+fo>>2s&:s*f<;9'>Sr#s#w#:rw#"fG*h;9'>Sp#"h>2q*h};9'+"h~!#%9nu d)0<D {ozg) {oz {oz#!)#!)##?##? 9'l3>2q}l:rG>2rx x> 24 ) ) 5%)5%) ͭ%) E=%) ͩ)z|5%ڻ PY ͩ)):*9 f':9="9$"9 !W$  Memory OVERFLOW Stopped ACT!/q#p# *9(%:9"9:~%"n::::`:97͆`i?ځ'ځ!d3r+s+7!`3Fx!.H!d0R!2Ͱ2b:!?GN#xy_y_ѯ°#7# y÷y?>E2:2:1>w##^#VO:9#y2r>U724*9*98*9*9:9'b! =# cSh= :|:9 ^= :~ w “9'ʺ# µ¥þÐ7!6> oD# 9'7ȷ0 :?[$b#b.b~J%# ~#,4J%~#o$4f'HO$:9@Õ!9~w*9z^:4 |.> 24.5:9 :4!?怰G:9W:9O@:9ʺyzz>@GzGG&z>+24*94~# !4> #6 #6#2*9#"9!4O$H> 245!4:G~=> w# 56 #6:9@!4\!94:9l$*9:9Gʅw#xl͜lx29"9*9:9q<•!z8$Ҹ:9@29!W$G29!"9List file write error. *9}J%: !f'*&*9"2<29*9#"9&!\! \4>2$:9>B>20:0294:OJ%>$!4".%~*.>  ʄ>sw#UҚDښڛnpf'*99'ڼA6m#6a#6c#6 ###".6:9o:9=29bH:9!0*.6 #C*9!?~: ~ ~w 9'*9DM !?~Ex1}1Fd] d#KT]f 6 ^#VogʉNs#FrYP+y>!4".29|^#V#~/#oy&&".:9=29•5>Ë:9H#^*.&O:9:9:9:::?:92@/7N#F:@+w:9+w+p+qr+s*9#"9~#foþ' no ERRORs, 1234 Labels, h bytes not used. Program LWA = h. *Error page 999SYMBOL TABLE *Error page 999 SORCIM 808x Assembler ver 3.5E mm/dd/yy hh:mm Page 999 ~':9*:9'":Oi`) ))6 2:2:͎ *:"9p : f'::p : f'*:^ ͙ ~ *: ^ "::9:9w"*O::Q:#%9'!!*:"O:G_ :9:9<"#"" >!y2Q:&!!y2Q::Q: Q:G!!:"""#"z P!:N:'6 #6  :r!*O::Q:#%"O:2Q:2N:!):*@5w#}B!|6!!!B5u!"@5:9:9·"!!>12':*:"O: (!*@5B5!!B5V$!:929!!W$Hex file write error.  9'!p#9' "O:N:2N:yW :Q:O!):#%:9:9—"*O:x#%"O:!:~#f" #Oog5#o"_j#I"::O*O:9'Š":M:y2M:> "O:">\#!]#> *6"> *6"::O>*:":Y:"X:r!*@5B5!!"\#5#>>?:Z:y2Z:>\#yp ~ ###t#^#r# &#y?H#"N#_Pt#r#\r#@_t#\j#t#zK͛%O:Y:_G͆%!X:w{=#r!2X::Y:W{2Y:bzWu# Y w# ##7! wD$ѷ$ #7D$ѷ$ $D$7:k$`$l$f$>2k$>b$:k$O$2a$2k$O ͻ$~# ¡$Ù$ ͻ$x“$> _xUү$ͻ$Ä$|ͻ$ ͻ$ ~Oʹ#!$`$$ ?? OPEN error - l$!;6#e%!;l$:9%V:9͍zɅo$MDy_xW{z/W{/_xzW{_=%>  L%~ J%J%# S% As%@O:q#p#f'>.f'xy%%ɷ”%!%#%~?BK!xʾ% ô%BJ~0%:%A%[% #%+FyR&:p &x &Bʯ&N&Ql&Hʆ& :pBʯ&Ql&Hʆ&yG&A&;&5&'V&V&dV& V&V&7N&~0Q& Q&# =e&~0R&R&_ #M&)))l&~0R&:&AR&GR&_# M&))))Æ&~0R&R&)o# ²&M&&'&'&'&'}0>02'>0]T< &=kbG:''> x>2'0~0~0#y'z{x7# A'9'h' +~ x['x~# h'x~aڅ'{҅'# u'~#Í'7#Ö'zq#ã'O:'=@I±' ®'V|'}'Ɛ'@'ɯ2(#~:+:\'~@8(##(ͬ#<~>:7:(.$(~.#$(y^(!S:( ^(:(7x7~i(#.^(*V(>?a(~# :(G>  a(x!8(|8(;8(=8(:8(@ʖ(#ʖ(*ʖ(?›(2(a({ w!d:6͹-2e:>I24\..(>.c3]-Cͥ-M..c-3͓-c>d.cle3͓-cm( (me3͓-(-3͓-͒"f:cme3͓-g-à,..͒Xx.c>I*͹-..e3M-M.>!.c3-ڰ)ͥ-*-3>)O- M."-.c3-ڰ)͹-3-- M.>!.cs-e3l- *n+~)͹-M.cs-3@-C*n"9e3\-)ͥ-M..cs-͹-g-3-*ͥ-3-(s-e3\-)ͥ-M..J,3-j*:-ʉ**3 *--"-ڰ*ͥ-.cs-3 -*3-a* \s-s-3-ڃ*:-ƒ*3-a*Ã*s-s-3-ڃ*3-ڃ*:-ƒ*a*s-s-3@-ڃ*͹-..c>H2+3@-++3 *n-+͹-M.cs-~[.+"nÝ,s-s-3-M+3-M+͹-(s-3-^+,s-3)-ڀ+͹-M.>!.͒"g:cs-e3:+O-ڧ+M.e3-Cͥ-.c:+>s-͒"f:́.Ó+H͹->!.c3-+:- ͹-(s-+>d.,Ce3\-Cͥ-M.>!..c3=-*,ͥ-M.͒"f:G,s-e3I-Cͥ-M.͒"f:́..>c3=-l,ͥ-M..cs-e3]-Cͥ-M..c3-ښ,ͥ-.cs-͹-͒"f:c3@-,3-,͹-M.>!.cs-3-,͹-M.>!.3@-Ccs-3 --3-Cͥ-.cs-e3m-;-M.e3l-;-͹-M.cs-3->:->3%->͹-M.>.8,͒"f:́.c!b:55>*9"n*`:##"`:~2d:#~2e:-CM.ͥ-.-ʹ-!d:4-4:9 *nͭ"ny_b#V"-|-͒x.}2-]Cͬ,=-@!.!g:Fw#p*f:"g:*d:o"e::9>C >$24:9>C >#:.*-}o|-^.!e:w͒د†.z†.[.}|†.|<:4 >V24ASMHEX080808085Z80 =+CADD ADICADCJACIANA#ANDANIASEG.ASSERT6BIT@CALLCBITCCCLCCMA/CMC?#CMPCMCNZCNCCPECPOCPDRCPDCPIRCPI#CPICPU3CPCSEG.CZDAA'DAD DA&DBE%DB%DCE%DCRDCX DC%@#DEC DIDJNZDSEG.DS!DW&ECHO5EIEJECT:ELSE=ENDM<endm<ENDIF=END(ENTRY,EQU+ERR;EXT-EXXBEXHLTvIDENT0IF=IM0FIM1VIM2^#INCINDRINDINIRINIINRINXIN,C@IN#JMPJNZJMJCJNCJPEJPOJPJZJRC8JRNC0JRNZ JRZ(JRLDAX LDA:LDDRLDDLDIRLDI#LDKrLD :*KFLHLD*LINK2LIST8"LKLOC#LXIMACRO5MVISMOVWG@(MSG9NEGDNOPORG"ORAORI"OROTDROTIROT,CAOUTDOUTIOUTPAGE:PCHLPOPPROC$PUSHRALRARRCREPT5RETIMRETNERETRIM RLC#RLCRLDo"RLRMRNCRNZRPERPORPRRC#RRCRRDgRRRSTRZSBBCSBCBSBITSBISET+@SHLD"SIM0SLA SPACE7SPHLSRA(SRL8STAXSTA2STC7sSTO2"Cp63SUBSUITITLE1USE/VFD)XCHG#XORXRAXRIXTHL'*M%6[HL]6[IX[IYB C D E H $L -AA?IR AFA6PSWA6SP!6IX$IYdBC B DE D HL$H$AFA6SP!6IX$IYdBC DE HL$[SP]!6[IX]$[IY]d[BC] [DE] [HL]$(((() )%)-))0)3)+G)(((+++*B),U,(,`))*!*8*,6Kl#([ uX" F a T E w  2ͮ8>2k$!"R:ͬ#<@27a5:2$:29͈8*9!\ f'"9"9:94!Vͪ5:95!zͪ5!Af'!~6!l$2!T l$!.7:9f$6!=5$h'*ABS *CODE *DATA !"5!~ 8#O 65͹8!?="9l9 8}6:929l96ͭ8^#VPY##$!\ ?'\!5$ ?? Hex or Prn file name same as Input = 5@R6H=06H=6LO7L=06L=CON:6L=LP:6L=6L6O7PS(7SLA7S=_7S\7R=07R=S7R=F7R7!.7\'8\V!.7z! 77:929Ô5!.V7Ô5>29!RE".>L2.P!:͡'Ô5Í5:9ï6>`2i$:9ï6! 7z7:9ï6PRN;729Ô5;7"9Ô5:;7d!x8872Ô5P;72`i+~=7#%8{7':!d8$YPf'7Sf'!8l$!288!R88!d88Command input errorNO source file specified, ABORTMal-formed numberIll-formed filenamePS > 99SL < 60/!'> :!'!8f' Page *%"9"9OD9T9 .9}|:k99~ 9 9, 9; 9|.9 .9.9a 9{ 9 w#86#8:k9(9~ .9.9#96#86go~<9ѯx~ O9 S9#D9~'d9"d92k96#2k95~#ʇ9<+w#_^#Vѯ7TTTTTTTTTTTTTTTTT=99hhhh?=???99?=?9 :9999990099 ?\:e:`: prompt/command response JMP X30D2 ; end  ',*7:9ï6PRN;729Ô5;7"9Ô5:;7d!x8872Ô5P;72`i+~=7#%8{7':!d8$YPf'7Sf'!8l$!288!R88!d88Command input errorNO source file specified, ABORTMal-formed numberIll-formed filenamePS > 99SL < 60/!'> :!'!8f' Page *%"9"9OD9T9 .9}|:k99~ 9 9, 9; 9|.9 .9.9a (INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE) COPYRIGHT (C) 1979, DIGITAL RESEARCH, PIP VERS 1.5$$$ SUB =.:,<> _[]INPIRDPTRUR1UR2RDROUTLPTUL1PRNLSTPTPUP1UP2PUNTTYCRTUC1CONNULEOFDISK READ ERROR$DISK WRITE ERROR$VERIFY ERROR$NOT A CHARACTER SINK$READER STOPPING $NOT A CHARACTER SOURCE$ABORTED$BAD PARAMETER$INVALID USER NUMBER$RECORD TOO LONG$INVALID DIGIT$END OF FILE, CTL-Z?$CHECKSUM ERROR$CORRECT ERROR, TYPE RETURN OR CTL-Z$INVALID FORMAT$HEX$$$$NO DIRECTORY SPACE$NO FILE$COM$START NOT FOUND$QUIT NOT FOUND$CANNOT CLOSE DESTINATION FILE$DESTINATION IS R/O, DELETE (Y/N)?$**NOT DELETED**$$$$$$$NOT FOUND$COPYING -$REQUIRES CP/M 2.0 OR NEWER FOR OPERATION.$UNRECOGNIZED DESTINATION$CANNOT WRITE$INVALID PIP FORMAT$CANNOT READ$INVALID SEPARATOR$1 :2L> ̈́M9 221@:2!o6+6+6!6#6!6#6:G*o .!N6:^*M^!K6!6!6+6' :$::=2K  :ʤ\:ҷ\x'Ͳ:!\͢  :͈'! Ͳ:$: $͈Ͳ!N6' :!Cwͯ !6:^͢c!6{:/>!/H{ͯ :<2Š ::=HҮͯ !6:Ҿ:2 !6::/H͈;!6:> !/>HHͯ :^!w:<2:0}:@E}:!S!W6: z!]6:cm!c6:_z!_6l ::,: HHҰͯ : 2ó:E:1:2v!q!*8!*6: >ͦ>ͦ!q:_  !p+q.*   !q*&!p+q*2!p+q*2!p+q*22!p+q*!p+q*!p+q*!p+q*2!p+q* LINK VROMMAIN.ASM LINK VROMEND.ASM VROM ASM3456789:;<=>?@ABVROM ASMCDEFGHIJKLMNOPQRVROM ASMSTUVWXYZ[\]^_`abVROM ASMcdefghijklmnopqrVROM ASMRstuvwxyz{|}VROMG DOCVROM $$$VROM $$$VROM $$$VROM $$$ PAGE *[11] ;OPTIONAL COLD BOOT LOADER HCBOOT: ;HARD DISK COLD BOOT ROUTINE ;ENTRY ;NONE ;EXIT ;NONE PROC JMP VSTART ;RESTART VIXEN ECHO 255 DB 0FFH ;FILL ENDM :RLWA: = * ;LWA OF ROM RESIDENT CODE MSG 'LENGTH OF THIS ROM IS = ',:RLWA IF :RLWA > 0FFFCH .9 ERROR CODE TOO LARGE.. ENDIF :ROML: = 0FFFH - * + 1 ;LENGTH OF SPACE LEFT OVER ECHO :ROML DB 0FFH ;FILL ENDM MSG * ; END ;.Date: 4/5/83 ;.Author: DEB ;.Title: ENCORE MONITOR ROM : REV X3.094 ;.Comments: ALPHA ; +---------------+ ; | | ; |ENCORE Monitor | ; | | ; +---------------+ ;X.1 Added the corvus boot : deb ; Added the enable keybd int. before first enable int. : deb ;X.2 Changed the default step delay to 20ml from 12ml : deb ;X.3 Added head settle delay after step : deb ; Changed the delay after motor on to .5 sec : deb ;X.4 Changed to the rev 2 board : deb ; Changed INTERRUPTs and character generater : deb ; Changed reverse in sign-on message : deb ; Changed the number of retrys in SENDEN to NRETRY : deb ; Changed the disk drivers to run with a 1797 : deb ; Deleated some unused jmps in the jump table at f100 : deb ; Shortened DELAY allittle : deb ;X.5 Took EXX out of INTERRUPT routines : deb ;X.6 Added keyboard drivers from Shelly : deb ; Made LKEY a rom only variable : deb ; Changed keyboard matrix : deb ; Changed log-on name to Memory Might : deb ;X.7 Changed keyboard driver : deb ; Changed misspelled words : deb ;X.8 Added screen driver : deb ; Changed log-on name to Express : deb ; Added recalabrate to CBOOT : deb ; Changed windows to ESC,'w',#,ROW,COL,ROW,COL : deb ; Changed jmp table some : deb ; Fixed bug in boot DSKSWP : deb ; Changed second retry value in SENDEN from 3 to NRETRY : deb ; Added section definition : deb ; Took out FORMAT routine (FMTTRK is still in) : deb ;X.9 Fixed bug in error reporting for FMTTRK : deb ; Changed time out constant in RADR to a constant DRQTIMEOUT : deb ; Changed JRNC :3 to JNC :3 in RD_WRT to make it a little faster : deb ; Made CORVUS link conditional by an IF statment : deb ; Added power on diagnostics : deb ; Changed CORVUS referance number ([10]) to [11] : deb ; Made hardware init. a routine : deb ; Changed fault tree in R_WSEC : deb ; Cleaned up code that uses RTRY : deb ; Change ESC sequence character, (VSGH,VEGH,VWDEF) : ymk ; Remove ESC sequence (VRLF,VATR) : ymk ; Add ESC sequence (VSUL, VEUL, VSRV, VERV, VCAS) : ymk ; Removed PUSH IX & IY and POP IX/IY out of INTHNDL (they are not used) : deb ; Added READROM routine & jmp in jump table : deb ; Speeded up console : deb ; Took out ROMCON & referenced CONTBLS directly : deb ; Took out DI at the beginning of the INTHNDL routine : deb ; Made GKEY & DDRV in line code in INTHNDL : DEB ; Fixed bug in EINSRT : deb ; Fixed bug in ENDROW : deb ; Fixed bug in ENDCOL : deb ;X.10 Change boot message and boot error handler : ymk ; Change poweron diagnostic error dislpay message : ymk ; Disable corvus link : ymk ; Shorted IMSG : deb ; Shortened FAILMSG : deb ; Change boot message and boot error handler : deb ; Moved DELAY to disk section : deb ; Changed head settle delay to 40 msec : deb ; Changed disk start up delay to 750 msec : deb ; Changed jump table : deb ; Changed memory address : deb ;X.11 Alternate character set works in console : deb ; Worked on KBDRVR alittle : deb ; Made bell last for 250 msec per TVI 950 spec : deb  ; Power on test rings the bell after a sucsessfull complete : deb ; Changed keyboard decode tables : deb ; 8Eh ; & 8Fh ; & 90h ; & & 91h ; Made KBSCAN faster on 8th rom : deb ; Made SKEY faster : deb ; Took KEYLCK check out of SKEY : deb ; Made INTHNDL alittle faster : deb ; Added two ESC sequences for 256 characters : deb ; ESC U = 256 CHARACTER SET WITH REVERSE VIDEO ; ESC u = 256 CHARACTER SET WITHOUT REVERSE VIDEO ; Made VC_MCRT alittle faster : deb ; Used ROM based display tables (IE. CTBLPTRS ) : deb ; The first thing INITHARD does is clear the screen : deb ;X.12f Changed boot error message : deb ; Changed PODIAG error message : deb ; Fixed bug in INITHARD : deb ; Changed name to ENCORE : deb ; Changde KBSCAN to process ALPHA LOCK only : deb ; Made VC_MCRT a little faster : deb ; Made DO_LF a little faster : deb ; Made final ajustment to memory locations : deb ; Activated checksum test in PODIAG : deb ; Added fill bytes to end of rom : deb ; Fixed bug in CHKSUM : deb ; Final pre-alpha : deb ;X3.094 ALPHA : deb ; Tookout CORVUS : deb ; Fixed bug in INTHNDL : deb ; Switched the upper and lower definition of the character rom : deb ; Took CORVUS code out : deb ; This file must be linked : deb PAGE ;FUNCTIONAL SECTIONS *[1] INITHARD ;HARDWARE INITIONALIZATION *[2] OSTR ;JUNK *[3] ;JUMP TABLE *[4] IMSG ;SIGN ON MESSAGE *[5] CBOOT ;CPM BOOT LOADERS *[6] BTICKS ;SCREEN DRIVER *[7] INTHNDL ;INTERRUPT PROCESSOR *[8] SKEY ;KEYBOARD DRIVER *[9] RDRV ;FLOPPY DISK DRIVER *[10] PODIAG ;POWER ON DIAGNOSTICS *[11] HCBOOT ;OPITIONAL CBOOT LOADER PAGE SCLFRE: = 0B4H ;for DELAY routine DEL: = 7Fh ;DELEATE KEY TAB: = 09h ;TAB NRETRY: = 10 ;NUMBER OF RETRYS ;I/O MAP ;SYSTEM PIO (8155) SYSMS: = 0CH ;ADDRESS PORT TO 8155 MEMORY (0-255) SYSRS: = 0DH ;ADDRESS PORT TO 8155 REGISTERS (0-5) SYSRW: = 08H ;READ/WRITE PORT FOR 8155 ;DISK DSK_CMD = 0 ;Floppy disk DISK COMMAND REG (WRITE) DSK_STS = DSK_CMD ;STATUS REG (READ) DSK_TRK = DSK_CMD+1 ;TRACK REG DSK_SEC = DSK_CMD+2 ;SECTOR REG DSK_DAT = DSK_CMD+3 ;DATA REG (R/W) DRQTIMEOUT: = 4615 ;TIME OUT CONSTANT FOR RADR ROUTINE ;INTERRUPT SERVICE PORT INTPORT = 4 ;KEYBOARD EQUATES KL_LEN: = 3 ;KEY LIST LENGTH KL_USED = 7 ;KEYLIST ENTRY USED KY_SRVD = 6 ;KEY SERVICED ONCE KROW_M: = 38H ;ROW NUMBER MASK KCOL_M: = 7H ;COL NUMBER MASK DB_CT: = 1 ;DEBOUNCE COUNT IRPTCT: = 24 ;INITIAL REPEAT COUNT (400MS) SRPTCT: = 3 ;SECOND REPEAT COUNT (100MS) TOT_ROW = 8 ;TOTAL ROWS BAD = 0FFH ;Used to flag an invalid translated char BADKEY = Bad TBL_LEN = 64 ;Length of keybd xlate tables ROW0_M = 1 ;MASK FOR ADDRESSING ROW 0 ;KEYBOARD Translation table list: NM_TB_NO: = 0 ;NORMAL SH_TB_NO: = NM_TB_NO + 1 ;SHIFT CT_TB_NO: = SH_TB_NO + 1 ;CONTROL AL_TB_NO: = CT_TB_NO + 1 ;ALPHA LOCK CS_TB_NO: = AL_TB_NO + 1 ;CONTROL SHIFT ;DRIVE EQUATES D.SEK: = 010H ;SEEK D.STP: = 020H ;STEP D.STPI: = 040H ;STEP IN D.STPO: = 060H ;STEP OUT D.RDS: = 088H ;READ SECTOR D.WRTS: = 0A8H ;WRITE SECTOR D.RDA: = 0C0H ;READ ADDRESS D.RDT: = 0E0H ;READ TRACK D.WRTT: = 0F0H ;WRITE TRACK D.FINT: = 0D0H ;FORCE INTERRUPT PAGE ;ROM ONLY VARIABLES ROMSTK: = 100H ;ROM STACK USED BY PO & CBOOT ORG 0EBA2H ;BOOT LOADERS TBUFF: DS 1024 ;BUFFER FOR BOOT CLRSTR: = * ;START OF AREA TO CLEAR TEM: DS 1 ;USED IN BOOT ROUTINES CCPADR: DS 2 ;(2) FBA OF CCP ;DISK DRIVERS RTRY: DS 1 ;RETRY COUNTER DACTVE: DS 1 ;<> 0 : DISK ACTIVE DSKSWP: DS 1 ;DISK SWAPPED CELL NUMSEC: DS 2 ;NUMBER OF SECTORS TO R/W R_WCOM: DS 1 ;NUMBER OF SECTORS TO READ OR WRITE DSTSB: DS 6 ;(6) SIX BYTES FOR DISK INFO ;KEYBOARD DRIVER KEYLCK: DS 1 ;KEYBOARD LOCKED CELL LKEY: DS 1 ;(1) LAST KEY PRESSED (FF IF NO KEY PRESSED) TBLBASE DS 2 ;(2) POINTER TO KEYBOARD TABLES KEYLST: DS 6 ;KEY LIST GOES HERE ;ADDRESS IN KEYLST FIRSTKEY = KEYLST SECONDKEY = FIRSTKEY + 2 LASTKEY = KEYLST + 4 ;SCREEN DRIVER OFFSET: DS 1 ;CURSOR OFFSET CURPOS: DS 2 ;CURSOR POSITION BELCNT: DS 1 ;<> 0 : BELL RINGING VRS: DS 8 ;(8) FBA OF VIDEO ROUTINES IN RAM CFLAG: DS 1 ;(1) ESCH FLAG BACKGND DS 1 ;Background attribute flag FWAWIND DS 2 ;First word address of window WINDROWS: DS 1 ;Number of rows in window WINDCOLS: DS 1 ;Number of columns in window TEMPFWA DS 2 ;Holds new FWA while window is being defined TEMPROWS: DS 1 ;Holds new number of rows while window is being defined FSTROW DS 1 ;Holds first row number while window is being defined FSTCOL DS 1 ;Holds first column number while window is being defined CONTBLS DS 2 ;CURRENT SCREEN TABLE ADDRESS ;INTERUPT STACK DS 30 ;STACK SPACE ISTK: DS 0 ;(-40) INTERRUPT STACK AREA ISSTK: DS 2 ;(2) SAVE OLD STACK HERE PAGE ;TRANSFER RAM MEMORY LOCATIONS SEQ: = 0EFF4H ;(2) COUNTER (USED BY BIOS) SEKDEL: = 0EFF6H ;(1) DISK STEP DELAY (USED IN COPY & DIAG) DMADR: = 0EFF7H ;(2) DISK DMA ADDRESS SAVTYP = 0EFF9H ;(1) DISK TYPE SDISK: = 0EFFAH ;(1) DISK IN USE SAVTRK: = 0EFFBH ;(2) TRACK SAVSEC: = 0EFFDH ;(1) SECTOR ;ROM ONLY MEMORY LOCATIONS INTBL: = 0EFFEH ;(2) interrupt vector (EFFE & EFFF) FWAVM: = 0F000H ;FIRST ADDRESS OF MEMORY MAP PAGE ORG 0F000H ;FWA of ROM ;NOTE ;THE FIRST INSTRUCTION MUST BE A JMP TO THE ROM ;THE STACK IS SET TO ROMSTK IN PODIAG PROC JMP PODIAG ;DO POWER ON DIAGNOSTICS AND SET ROM MODE VSTART: ;START OF MONITOR ENTRY POINT (PODIAG JUMPS HERE) LDK DE,IMSG CALL OSTR ;Output initial message EI ;ENABLE INTERRUPTS :1: CALL CI ;Get character CMP ESC JZ HCBOOT ;IF COLD BOOT OFF OF HARD DISK LDK HL,DSKSWP ;disk swap cell STO 0,[HL] ;SET DRIVES A=A, B=B CMP CR JZ CBOOT ;if cold boot off of A INC [hl] ;swap drives: A=B, B=A CMP '"' JZ CBOOT ;if cold boot off of B ;CHEC K FOR LOOPING PO TEST CMP 'T' JRZ VLOOP ;DO PO TEST CMP 't' JRNZ :1 ;LOOP IF NOT PO TEST ;FALL THROUGH TO PO TEST PAGE VLOOP: ; JUMP HERE TO SET UP ENCORE TO RUN POWER-ON SELF-TEST FOREVER. TO DO SO, ; SET LOGIC BOARD 8155 MEMORY LOCATION TO BE = 2. XRA A ;ACCUMU = MEMORY LOCATION ZERO OUT SYSMS LDK A,2 OUT SYSRW ;SET 8155 MEMORY LOCATION ZERO = 2 JMP POSTART ;RUN POWER ON TEST PAGE *[1] INITHARD: ;HARDWARE INITIONALIZATON DI ;DISABLE ITERUPTS *INITIALIZE MEMORY ;CLEAR THE SCREEN LDK HL,FWAVM ;FBA OF VIDEO :LOOP: STO 20H,[HL] INC HL MOV A,L ORA H JRNZ :LOOP ;LOOP TILL END ;CLEAR BUFFERS LDK HL,CLRSTR ;START LDK DE,CLRSTR+1 LDK BC,FWAVM-CLRSTR-1 ;LENGTH STO 0,[HL] ;ZERO FIRST BYTE LDIR ;OVERLAPPING MOVE ;SET VALUES OF ONE LDK A,1 STO A,KEYLCK ;indicate NOT locked ;SET VALUES OF TWO INC A ;A = TWO STO A,SEKDEL ;set seek step rate FOR SEMIENS ;SET "LKEY" LDK A,0FFH STO A,LKEY ;NO KEY READY ;SET POINTER TO KEYBOARD TABLES LDK HL,KYCDTB ;FIRST BYTE OF FIRST TABLE STO HL,TBLBASE ;SET VALUE ;INITIALIZE POINTERS IN THE SYSTEM CONSOLE TABLE LD HL,CTBLPTRS ;SET CURRENT SCREEN TABLE STO HL,CONTBLS ;INITIALIZE OTHER MEMORY LOCATIONS LDK HL,FWAVM STO HL,CURPOS ;Position cursor to top of screen STO HL,FWAWIND ;Initialize window to full screen LDK A,VMCOLS STO A,WINDCOLS ;Full 80 columns LDK A,VMROWS STO A,WINDROWS ;Full 24 rows LDK A,20H STO A,OFFSET ;X-Y positioning offset = 20H ;MOVE VIDEO ROUTINES TO RAM LDK BC,VRL ;LENGTH OF VIDEO ROUTINES LDK DE,VRS ;FBA OF VIDEO ROUTINES IN RAM LDK HL,SOURCE ;FBA OF VIDEO ROUTINES IN ROM LDIR ;SET INTERRUPTS ;SET MODE 2 INTERRUPTS IM2 ;SET INTERRUPT REGISTER LDK A,high INTBL MOV I,A ;SET INTERRUPT VECTOR LDK HL,INTHND STO HL,INTBL ;SET INTERNAL PIO XRA A OUT SYSRS ;SELECT PIO CTL LDK A,0EH OUT SYSRW ;CONFIGURE LDK A,3 OUT SYSRS ;SELECT PORT C LDK A,1111_0111B OUT SYSRW ;CONFIGURE ;CLEAR KEYBOARD INTERRUPT ;DISABLE LDK A,0000_0000B ;DISABLE OUT INTPORT ;ENABLE LDK A,0000_0001B ;ENABLE OUT INTPORT RET PAGE *[2] ;JUNK OSTR: ;OUTPUT STRING TO CONSOLE ;NOTE: OSTR RECOGNIZES 7F AS AN ESCAPE SEQUENCE TO REPEAT CHAR N TIMES. FORMAT IS: 7F, REPEAT COUNT, CHAR ;ENTRY ;DE = FWA OF SOURCE ;EXIT ;NONE PROC LD A,[DE] OR A PUSH AF AND 07FH CMP 07FH MOV C,A JRNZ :4 ;IF NOT REPEAT INC DE LD A,[DE] DEC A MOV B,A ;REPEAT COUNT INC DE LD A,[DE] ;GET REPEAT CHAR MOV C,A :2: PUSH BC PUSH DE CALL COUT ;OUTPUT CHAR POP DE POP BC DJNZ :2 ;IF NOT DONE :4: PUSH DE CALL COUT ;OUTPUT IT POP DE INC DE POP AF JP OSTR ;IF NOT DONE RET PAGE EMBOOT: DB ESC,VDELL ;DELETE CURRENT LINE DB 'BOOT ERROR : CHECK YOUR DISKETT' DC 'E' PAGE READROM: ;READ A BYTE FROM THE ROM ;NOTE ;SINCE THE ROM IS THE ONLY THIS THAT CAN READ THE ROM THIS ROUTINE IS HERE TO DO JUST THAT ;ENTRY ;HL = ADDRESS TO READ ;EXIT ;A = VALUE READ ;HL = HL PROC LD A,[HL] RET PAGE *[3] ;ROM JUMP TABLE MSG 'LENGTH BEFORE 0F100h IS ', * ORG 0F100h ;ROM JUMP TABLE ;CBIOS = Jmps used mainly by CBIOS ;BOOT JMP WBOOT ;CBIOS warm boot ;CONSOLE I/O JMP SKEY ;CBIOS keyboard status JMP CI ;CBIOS keyboard input JMP COUT ;CBIOS console output ;HIGH LEVEL DISK I/O (WITH RETRY) JMP RDRV ;CBIOS HOME JMP RSEC ;CBIOS DISK SECTOR READ JMP WSEC ;CBIOS DISK SECTOR WRITE JMP SENDEN ;CBIOS SENSE THE DENSITY OF DRIVE ;LOW LEVEL DISK I/O (NO RETRY, FOR DIAG) JMP HOME ; HOME DISK DRIVE JMP SEEK ; SEEK TO TRACK JMP STEP ; STEP SAME DIRECTION JMP STEPIN ; STEP IN JMP STEPOUT ; STEP OUT JMP READ ; READ SECTOR JMP WRITE ; WRITE SECTOR JMP RADR ; READ ANY SECTOR HEADER JMP READTRK ; READ TRACK JMP FMTTRK ; Format one track (USED ALSO BY COPY) JMP FORINT ; FORCE INTERRUPT JMP SELDRV ; SELECT DRIVE ;OTHER JMP READROM ; Read a byte from the rom PAGE *[4] ;SIGN ON MESSAGE IMSG: DB VCLRS ;CLEAR SCREEN DB ESC,VSGH ;SET GRAPHIC MODE DB ESC,'=',2+32,21+32 DB 'Q'-40h DB 07Fh, 37, 'W'-40h DB 'E'-40h DB ESC,'=',3+32,21+32 DB 1 DB 07Fh,15,' ' DB 'ENCORE' DB 07Fh,16,' ' DB 4 DB ESC,'=',4+32,21+32 DB 'A'-40h DB 7FH, 15, ' ' DB 'X3.094' DB 7FH, 16, ' ' DB 'D'-40h DB ESC,'=',5+32,21+32 DB 'A'-40h DB 07Fh,37, ' ' DB 'D'-40h DB ESC,'=',6+32,21+32 DB 'A'-40h DB ' ' DB 'S'-40h ;COPYWRITE SYMBEL DB ' 1983 OSBORNE SOFTWARE TEST ONLY ' DB 'D'-40h DB ESC,'=',7+32,21+32 DB 'Z'-40h DB 07Fh, 37, 'X'-40h DB 'C'-40h DB ESC,VEGH ;END GRAPHICS DB ESC,'=',9+32,20+32 DB 'INSERT DISK IN DRIVE A AND PRESS RETURN' DC '.' PAGE *[5] ;CPM BOOT LOADERS CBOOT: ;LOAD ALL THE OPERATING SYSTEM INCLUDING THE CBIOS ;ENTRY ;NONE ;EXIT ;A = DRIVE TO BOOT F ROM PROC ;RECALIBRATE DISK DRIVE CALL RDRV ;HOME DRIVE LDK A,10 STO A,SAVTRK CALL SEEK ;SEEK TO TRK 10 :1: CALL RDRV ;HOME XRA A STO A,SAVTRK ;TRK TO 0 *SET "SAVTYP" CALL SENDEN ;DETERMINE DENSITY JRNZ EBOOT ;PRINT ERROR AND HANG *READ AND SET FBA OF CCP LDK HL,TBUFF STO HL,DMADR ;SET DMA PUSH HL :3: LDK A,1 STO A,SAVSEC ;SET SECTOR MOV B,A CALL RSEC ;READ SECTOR ONE JRNZ EBOOT ;PRINT ERROR AND HANG *CHECK FIRST TWO BYTES OF THE CCP POP HL ;HL = 0D000H LD A,[HL] ;FIRST BYTE CMP 0C3H JRNZ EBOOT ;PRINT ERROR AND HANG INC HL ;HL = 0D001H LD A,[HL] ;SECOND BYTE CMP 05CH JRNZ EBOOT ;PRINT ERROR AND HANG INC HL ;HL = 0D002H ;SET LOAD ADDRESS LD A,[HL] ;get ccp address/100h + 3 SUB 3 LDK L,0 MOV H,A *SET NUMBER OF 128 BYTE BLOCKS TO READ FOR BOOT LDK B,60 ;CCP/BDOS/CBIOS *READ SYSTEM PUSH HL ;SAVE FWA FOR "CCPADR" CALL BCPM ;boot system POP HL *JUMP SYSTEM  STO HL,CCPADR ;SET "CCPADR" LDK DE,1600h ;offset for bios ADD HL,DE ;address of bios in hl JMP [HL] ;CBOOT IN BIOS PAGE EBOOT: ;BOOT ERROR MESSAGE ROUTINE ;ENTRY ;NONE PROC LDK DE,EMBOOT ;BOOT ERROR MESSAGE CALL OSTR :1: JR :1 ;HANG PAGE WBOOT: ;LOAD ONLY THE CCP AND THE BDOS FROM DRIVE A ;ENTRY ;NONE ;EXIT *NOTE* *; THIS ROUTINE DOES NOT EXIT. IT ONLY SETS PARAMETERS FOR BCPM:. *;B = NUMBER OF 128 BYTE BLOCKS TO READ FOR BOOT *;HL = DMA ADDR FOR CCP PROC LDK B,44 ;CCP/BDOS and don't read CBIOS LD HL,CCPADR PAGE BCPM: ;LOAD ALL OR PART OF CPM FROM THE DISK *NOTE* ;This loader will load single or double density and any number of sectors per track or bytes ;per sector. TEM is not zero if there are an uneven number of sectors to read. If this is true the ;last sector is read into a temporary buffer and the part needed is moved into the memory. ;ENTRY ;B = NUMBER OF 128 BYTE BLOCKS TO READ FOR BOOT ;HL = DMA ADDR FOR CCP ;EXIT ;NONE PROC *SET "SDISK", "DMADR" AND "SAVSEC" STO HL,DMADR ;SET DMA XRA A STO A,SDISK ;BOOT ONLY FROM DRIVE A STO A,TEM ;MAKE TEM ZERO INC A STO A,SAVSEC ;set sector *SET "SAVTYP" AND GET NUMBER OF SECTORS PER TRACK PUSH BC ;SAVE NUMBER OF 128 BLOCKS CALL RDRV ;HOME DRIVE CALL SENDEN ;DETERMINE DENSITY JRNZ EBOOT ;PRINT ERROR AND HANG POP DE ;D=NUMBER OF 128 BYTE BLOCKS PUSH BC ;SAVE NUMBER OF SECTORS IN ONE TRACK *SET NUMBER OF SECTORS TO READ LD A,SAVTYP SRL A SRL A ANI 0000_0011B ;A=NUMBER OF BYTES IN ONE SECTOR(0-3) JRZ :2 ;IF 128 BYTES SECTORS ;GET NUMBER TO DEVIDE BY MOV B,A ;B=NUMBER OF BYTES IN ONE SECTOR(1-3) LDK A,1 :1LOOP: SLA A ;TIMES TWO DJNZ :1LOOP MOV B,A ;NUMBER TO DIVIDE BY MOV A,D ;A=NUMBER OF 128 BYTE BLOCKS LDK D,0 :2LOOP: SUB B ;SUBTRACT WITH DIVISOR EX AF ;SAVE FLAGS INC D ;COUNT EX AF ;RESTORE FLAGS JRZ :2 ;IF RESULT IS ZERO (NO PARTIAL SECTORS)  JRNC :2LOOP ;LOOP NEG A ;2 COMP STO A,TEM ;SAVE REMAINDER AND INDICATE A PARTIAL SECTOR :2: POP BC ;B=NUMBER OF SECTORS IN ONE TRACK MOV C,D ;C=NUMBER OF SECTORS TO READ PAGE *READ SYSTEM XRA A ;A=0 :TLOOP: STO A,SAVTRK ;SET TRACK ;CHECK FOR ALL SECTORS READ MOV A,C ;SECTORS TO READ ORA A JRNZ :3 ;IF C IS NOT ZERO CONTINUE ;CHECK FOR NO PARTIAL SECTOR LD A,TEM ORA A JRZ :9 ;STOP IF C=0 AND TEM=0 JR :7 ;READ PARTIAL SECTOR ;UPDATE NUMBER OF SECTORS LEFT TO READ :3: SUB B ;SUBTRACT SECTORS IN ONE TRACK JRNC :4 ;A>B MORE THAN ONE TRACK LEFT TO READ ;IF THIS IS LAST TRACK ZERO NUMBER OF SECTORS LEFT TO READ MOV B,C ;READ ALL THE REMAINING SECTORS XRA A ;THIS WILL ZERO REG C ;CHECK FOR NONZERO VALUE IN TEM AND THE LAST SECTOR TO READ :4: MOV C,A ;SAVE REMAINING SECTORS TO READ LD A,TEM ORA A JRZ :5 ;IF TEM IS ZERO SKIP THIS XRA A ORA C JRNZ :5 ;IF REG C IS NOT ZERO SKIP THIS(NOT LAST TRACK)  ;READ ONE LESS THAN THE LAST SECTOR DEC B ;B=B-1 JRZ :7 ;IF ONLY ONE SECTOR LEFT TO READ ;READ ONE TRACK :5: CALL RSEC ;READ (BC IS SAVED) JRNZ EBOOT ;PRINT ERROR AND HANG ;UPDATE DMA STO HL,DMADR ;SET DMA ;UPDATE TRACK LD A,SAVTRK INC A JR :TLOOP ;TRACK LOOP PAGE *READ A PARTIAL SECTOR :7: PUSH HL ;SAVE ADDRESS TO WRITE TO LDK HL,TBUFF ;ADDRESS OF HOST BUFFER IN BIOS STO HL,DMADR ;SET DMA ;SET TRACK IF NEEDED JRZ :10 ;IF B=0 THEN SAVTRK WAS NOT INCREMENTED LDK HL,SAVTRK DEC [HL] ;SAVTRK = SAVTRK - 1 ;SET THE SECTOR TO B + 1 :10: INC B MOV A,B STO A,SAVSEC ;SET SECTOR ;READ SECTOR INTO HOST BUFF LDK B,1 :RL2: CALL RSEC ;READ ONE SECTOR JNZ EBOOT ;PRINT ERROR AND HANG ;SET NUMBER OF BYTES TO TRANSFER LD A,TEM MOV B,A ;B=NUMBER OF 128 BYTE BLOCK TO TRANSFER LDK HL,0 LDK DE,128 :3LOOP: ADD HL,DE DJNZ :3LOOP PUSH HL POP BC ;BC=NUMBER OF BYTES TO TRANSFER ;TRANSFER BYTES  LDK HL,TBUFF ;SOURCE POP DE ;DESTINATION LDIR ;MOVE ;Clear error indicator and return :9: XRA A RET PAGE *[6] ;VIDEO SCREEN DRIVERS ;VIDEO CONSTANTS BTICKS: = 15 ;DURATION FOR BELL 15 TICKS = 1/4 SEC VMROWS = 24 ;24 Rows VMCOLS = 80 ;80 Columns VLL = 128 ;Length of one video line ;CONTROL CHARACTERS CR = 0Dh ;^M, CR = Carriage Return LF = 0Ah ;^J, LF = Line Feed BKS = 08h ;^H, Backspace CBELL: = 'G'-40h ;Ring the Bell MCUP: = 'K'-40h ;Move cursor up MCRIGH: = 'L'-40h ;Move cursor right VDWN: = 'V'-40H ;Move cursor down VLIN: = '_'-40H ;New line (CR,LF) VCLRS: = 'Z'-40h ;Clear and home cursor VHOME: = '^'-40h ;Home Cursor ;ESCAPE SEQUENCE CHARACTERS ESC = 1Bh ;^[, ESC = Escape VLOCK: = '#' ;Lock Keyboard VUNLK: = '"' ;Unlock Keyboard VCAD: = '=' ;Cursor Addressing VINC: = 'Q' ;Insert Char VDELC: = 'W' ;Delete char VINL: = 'E' ;Insert line VDELL: = 'R' ;Delete line VCEOL: = 'T' ;Clear to end of line VCEOS: = 'Y' ;Clear to end of screen (window) VCAS = 'Z' ;Clear all screen VAL128: = 'a' ;alternate 128 character set VMA128: = 'A' ;MAIN 128 character set V256WO: = 'u' ;256 CHARACTER SET WITHOUT REVERSE VIDEO V256W: = 'U' ;256 CHARACTER SET WITH REVERSE VIDEO VSHI: = ')' ;Start half intensity VEHI: = '(' ;End VSGH: = 'g' ;Start graphics VEGH: = 'G' ;End VRON: = 'b' ;Set reverse video background (black on white) VROFF: = 'd' ;Clear reverse video background (set to white on black) VSUL: = 'l' ;Start underline VEUL: = 'm' ;End underline VSRV: = 'j' ;Start reverse video VERV: = 'k' ;End reverse video VWDEF: = 'z' ;Window define VOFF: = 'o' ;Define X-Y offset PAGE ;Bit definitions for CFLAG flag byte ; +---+---+---+---++---+---+---+---+ ; | 7 | 6 | 5 | 4 || 3 | 2 | 1 | 0 | ; +---+---+---+---++---+---+---+---+ ; | | | | | | | | ;Reverse video <------------------+ |  | | | | | | ;<------------------------------------+ | | | | | | ;<----------------------------------------+ | | | | | ;<--------------------------------------------+ | | | | ; | | | | ;<-------------------------------------------------+ | | | ;<-----------------------------------------------------+ | | ;<---------------------------------------------------------+ | ;Graphics <----------------------------------------------------+ REV_FLG: = 80H ;Reverse video mode GR_FLG: = 01H ;Graphics mode PAGE COUT: ;General output routine to Video Screen ;ENTRY ;C = Character ;CURPOS = Cursor ;CFLAG = Flag+Mode ;EXIT ;CURPOS & CFLAG updated PROC ;TURN OFF OLD CURSOR LD HL,CURPOS ;GET CURSOR POSSISION CALL RLDA ;GET BYTE IN A XRI 1000_0000B ;TOGOL BIT STO A,[HL] ;SAVE ;PROCESS CHARACTER CALL LOOKUPB ;TURN ON NEW CURSOR LD HL,CURPOS ;GET NEW CURSOR POSSISION CALL RLDA ;GET BYTE IN A XRI 1000_0000B ;TOGOL BIT STO A,[HL] ;SAVE RET PAGE LOOKUPB: ;Look up character in the specified table and branch to processing procedure ;If character is not in the table, then branch to default procedure. ;ENTRY ;C = char ;*NOTE* ;After GETTBL is called: ;HL = table address ; 1st byte of table = number of (non-default) table entries ; Entries are 4 bytes long: ; 1st byte = match code ; 2nd byte = next table number ; 4th,5th bytes = branch address ; The last entry is a 3-byte "No Match" default next table number and branch address ;EXIT ;Jumps to branch address in table ;C = character PROC ;GET CURRENT TABLE LD HL,CONTBLS ;HL = Current table's address ;FIND CHARACTER IN TABLE LD A,[HL] ;A = number of entries INC HL ;First entry ORA A JRZ :1 ;If no entries, do default processing MOV B,A ;B = number of entries MOV A,C ;A = character :LOOP: CMP [HL] ;Check for match INC HL ;(2nd byte of this 4 byte entry) JRZ :1 ;If match process INC HL ;(3rd byte of this entry) INC HL ;(4th byte of this entry) INC HL ;1st byte of next entry DJNZ :LOOP ;Continue thru body of table ;SET UP NEXT TABLE ADDRESS :1: PUSH HL ;Save current position in table LD A,[HL] ;A = next table number ADD A,A ;A = A * 2 MOV L,A LDK H,0 ;HL = Table number * 2 LDK DE,CTBLPTRS ;DE = current table pointer IN ROM ADD HL,DE ;[HL] = next table address LD E,[HL] INC HL LD D,[HL] STO DE,CONTBLS ;Set table address to next table address POP HL ;Restore ;BRANCH TO PROCESSING PROCEDURE INC HL ;Go to branch address portion of table entry LD A,[HL] ;1st byte (low order adrs) INC HL LD H,[HL] ;2nd byte (high order adrs) MOV L,A ;HL=adrs from table MOV A,C ;A = char JMP [HL] ;enter routine per table adrs. PAGE ;BASTBL PROCEDURES PROCNORM: ;Normal character entered (ie not a lead-in character) ;Checks for graphics  or normal character and passes character on to appropriate ;routine ;ENTRY ;C = character ;EXIT ;NONE PROC LD A,CFLAG ;Get flags RRC ;Check for graphics mode JRC VGRAPH ;Graphics mode -- process character ;NORMAL mode character processing. MOV A,C CMP ' ' JRC :1 ;If control character ;Display new character and update cursor CALL DISPLAY ;Display new character JMP VC_MCRT ;Move cursor right & RETURN ;If control character Set current table TO CONTROL TABLE :1: LDK L,CTLNUM*2 ;Set current table to control table LDK H,0 ;HL = Table number * 2 LDK DE,CTBLPTRS ;DE = current table pointer IN ROM ADD HL,DE ;[HL] = next table address LD E,[HL] INC HL LD D,[HL] STO DE,CONTBLS ;Set table address to next table address JR LOOKUPB ;Scan table of valid control chrs and branch to appropriate routine. PAGE VGRAPH: ;GRAPHICS mode character processing ;characters 60H-7FH are converted to graphics characters (00H-1FH) ;so that BASIC can access all graphics characters ;ENTRY ;C = char to process MOV A,C BIT 5,A JRZ VOUT BIT 6,A JRZ VOUT ANI 9FH ;Convert to graphics characters ; JR VOUT ;FALL THROUGH PAGE VOUT: ;Display new character and update cursor ;ENTRY ;A = char PROC CALL DISPLAY ;Display new character JMP VC_MCRT ;Move cursor right PAGE ;Control Code character processing VC_CR: ;Carriage return ;ENTRY ;None ;EXIT ;CURPOS = new cursor position PROC LD HL,CURPOS CALL DO_CR STO HL,CURPOS RET PAGE VC_LF: ;Line Feed (if cursor is on last line, scroll screen and add ; new line at bottom) ;ENTRY ;NONE ;EXIT ;CURPOS = new cursor position PROC LD HL,CURPOS CALL DO_LF STO HL,CURPOS RET PAGE VC_BKS: ;Backspace. ;(If in 1st column then wrap around to last column of previous line) ;(No effect if in 1st position of window) ;ENTRY ;NONE ;EXIT ;CURPOS = new cursor position PROC ;CHECK IF AT COLUMN 0 LD HL,CURPOS CALL GETCOL ;Get cursor column JRZ :1 ;if must wrap from col 0 to last col of previous line ;IF NOT, BACKSPACE AND RETURN LD HL,CURPOS DEC HL JR :EXIT ;IF AT COLUMN 0, CHECK FOR ROW 0 :1: CALL GETROW RZ ;Return with no effect if at col 0, row 0 ;IF NOT, WRAP AROUND TO PREVIOUS LINE CALL VC_MCUP ;MOVE UP A LINE (HL = new address) LD HL,CURPOS ;MOVE TO END OF LINE CALL DIST2EOL ;BC = distance from cursor to end of line ADD HL,BC ;HL = new cursor address :EXIT: STO HL,CURPOS ;Save new cursor position RET PAGE VC_MCRT: ;Move Cursor Right (if at end of line, wrap around to next line) ;ENTRY ;NONE ;EXIT ;HL = new cursor position ;CURPOS = new cursor position PROC LD HL,CURPOS CALL DIST2EOL ;A = # of bytes between cursor and end of line JRNZ :1 ;if NOT at last column ;If at last column, wrap around to next line CALL DO_CR ;do CR... CALL DO_LF ;...and LF.  STO HL,CURPOS ;Save new cursor position RET ;MOVE CURSOR TO THE RIGHT AND RETURN :1: INC HL ;move cursor STO HL,CURPOS ;Save new cursor position RET ;RETURN PAGE VC_MCUP: ;Move Cursor Up. (If cursor is on top line then nothing happens) ;ENTRY ;NONE ;EXIT ;CURPOS = new cursor position PROC ;MOVE UP A LINE LD HL,CURPOS ORA A ;Clear carry LDK BC,VLL SBC HL,BC ;Move up a line ;CHECK IF ABOVE SCREEN PUSH HL ;Save cursor LD DE,FWAWIND SBC HL,DE ;Carry flag set if above screen POP HL JRNC :EXIT ;Done if on screen ;IF SO, GO BACK TO OLD POSITION ADD HL,BC :EXIT: STO HL,CURPOS RET PAGE VC_MCDOWN: ;Move cursor down (No effect if cursor is on last line) ;ENTRY ;NONE ;EXIT ;CURPOS updated PROC ;CHECK IF ON LAST LINE LD HL,CURPOS CALL LASTROW ;Check if on last row RZ ;If on last row, do nothing ;IF NOT, MOVE CURSOR DOWN LDK DE,VLL ADD HL,DE STO HL,CURPOS RET PAGE VC_NEWLINE: ;Do CR and LF ;ENTRY ;NONE ;EXIT ;CURPOS updated PROC CALL VC_CR JR VC_LF PAGE VC_BEL: ;Ring the bell ;ENTRY ;NONE ;EXIT ;NONE ;NOTE ;THE INTERRUPTS MUST BE DISABLED BECAUSE THEY MAY READDRESS THE 8155 PROC ;RING BELL DI LDK A,3 OUT SYSRS ;PORT C IN SYSRW ;READ IT ANI 1101_1111B ;RESET BELL BIT TO TURN IT ON OUT SYSRW ;SET BELL COUNT LDK A,BTICKS ;NUMBER OF TICKS STO A,BELCNT ;SET BELL COUNT EI RET PAGE VC_CLRS: ESCZZ: ;Clear window ;ENTRY ;NONE ;EXIT ;HL = new cursor position PROC LD HL,FWAWIND ;Beginning of window STO HL,CURPOS ;Position cursor to beginning of window JR CLR_EOS ;Clear window PAGE ; ESC sequence character processing ESCLCK: ;Lock Keyboard ;ENTRY ;NONE PROC XRA A ;Clear A JR :2 ESCULK: ;Unlock Keyboard ;ENTRY ;NONE LDK A,0FFh :2: STO A,KEYLCK RET PAGE EEOS: ;Erase to end of screen ;ENTRY ;NONE   ;EXIT ;NONE PROC LD HL,CURPOS ; JR CLR_EOS ;Clear to end of screen ;(CURPOS stays the same) PAGE CLR_EOS: ;Clear to end of window ;ENTRY ;HL = Start address ;EXIT ;NONE PROC ;GET NUMBER OF ROWS TO CLEAR CALL GETROW ;Get current row MOV C,A ;Save C = row LD A,WINDROWS SUB C ;A = Number of rows to clear ;CLEAR ROWS :LOOP: PUSH AF PUSH HL CALL CLRLN ;Clear to end of line POP HL CALL DO_CR ;Make sure all lines after the 1st one ;start at the first column LDK DE,VLL ADD HL,DE ;HL = next line's address POP AF DEC A JRNZ :LOOP ;If more rows RET PAGE EDELC: ;Delete Character ;ENTRY ;NONE ;EXIT ;NONE PROC LD HL,CURPOS CALL DIST2EOL ;Z flag set if at end of line JRZ CLR_CHAR ;If at end of line PUSH HL POP DE ;DE = cursor address INC HL ;HL = cursor address + 1 CALL RLDIR ;move characters ; JR CLR_CHAR ;Last character becomes blank ;CURPOS stays the same PAGE CLR_CHAR: ;CLEAR CHARACTER FOR GIVEN POSITION ;ENTRY ;HL = ADDRESS ;EXIT ;HL PRESERVED PROC LD A,BACKGND ORI ' ' ;ADD SPACE STO A,[HL] ;Clear character RET PAGE EINSRT: ;Insert Character ;ENTRY ;NONE PROC LD HL,CURPOS CALL DIST2EOL ;BC = distance to end of line JRZ :1 ;IF IN LAST COLUMN, JUST BLANK CURRENT CHAR ADD HL,BC ;HL = last position in cursor line PUSH HL POP DE ;DE = Last position in line DEC HL ;HL = 2nd to last position CALL RLDDR ;Move line over :1: LDK A,' ' ; JR DISPLAY ;Put a ' ' in cursor position and set selected attributes PAGE DISPLAY: ;Display character at cursor position ;ENTRY ;A = character ;EXIT ;HL = CURPOS PROC LD HL,CURPOS ;HL = current cursor position ;DISPLAY NEW CHARACTER MOV B,A ;SAVE CHAR ;SET BACKGOUND LD A,BACKGND ORA B MOV B,A ;TOGOL REVERSE FLAG LD A,CFLAG ;A = Current ESC sequence attributes ANI 1000_0000B XRA B STO A,[HL] ;Store character RET PAGE ESCSAL: ;MAKE alternate 128 character set PROC LDK B,0001_1000B JR ALTSET ;CHANGE PIO ESCCAL: ;MAKE MAIN 128 character set PROC LDK B,0001_0000B JR ALTSET ;CHANGE PIO ESCWO256: ;256 character set WITHOUT REVERSE VIDEO PROC LDK B,0000_0000B JR ALTSET ;CHANGE PIO ESCW256: ;256 character set WITH REVERSE VIDEO PROC LDK B,0000_1000B ;FALL THROUGH PAGE ALTSET: ;CHANGE THE CHARACTER SET ;ENTRY ;B = NEW VALUE TO BE WRITTEN TO THE PIO ;EXIT ;NONE PROC DI ;SET TO PORT 3 LDK A,3 OUT SYSRS IN SYSRW ;GET OLD VALUE ANI 1110_0111B ;CLEAR BITS ORA B ;SET BITS OUT SYSRW ;SET NEW VALUE EI RET PAGE ;Set and Clear other attribute bits ;Set attributes PROC ESCSHI: LDK B,REV_FLG ;Start half intensity attribute JR :SET ESCSGR: LDK B,GR_FLG ;Start graphics attribute :SET: LD A,CFLAG OR B ;Set bit JR :DONE ;Clear attributes ESCEHI: LDK B,NOT REV_FLG ;Clear half intensity attribute JR :CLR ESCCGR: LDK B,NOT GR_FLG ;Clear graphics attribute :CLR: LD A,CFLAG AND B ;Clear bit :DONE: STO A,CFLAG ;Store new attribute RET PAGE ESCRR: ;Delete Line (scrolls lower lines up and puts cursor at beginning of line) ;ENTRY ;NONE PROC LD HL,CURPOS CALL SCROL_UP ;Delete line and scroll lower lines up JMP VC_CR ;Put cursor at beginning of line PAGE ESCEE: ;Insert Line (puts cursor at beginning of inserted line) ;ENTRY ;NONE ;EXIT ;NONE PROC LD HL,CURPOS CALL SCROL_DOWN ;Scroll lines from cursor down, clear cursor line JMP VC_CR PAGE REVON: ;Set reverse video background ;(Leaves all other background bits alone) ;ENTRY ;NONE ;EXIT ;Screen set to reverse video PROC LD A,BACKGND BIT 7,A ;TEST BIT SBIT 7,A ;Set reverse video bit ;A = New background attributes RNZ ;RETURN IF ALREADY ON JR SET_BACK ;Set new background if not set PAGE REVOFF: ;Clear reverse video background attribute ;(Leaves all other background bits alone) ;ENTRY ;NONE ;EXIT ;Screen set to normal video PROC LD A,BACKGND BIT 7,A ;TEST BIT CBIT 7,A ;Clear reverse video bit ;A = New background attributes RZ ;RETURN IF ALREADY OFF ; JR SET_BACK ;Set new background if not reset PAGE SET_BACK: ;Change background bits for window ;ENTRY ;A = New background definition ; (Bit 7 = Rev video) ;EXIT ;NONE PROC STO A,BACKGND ;TOGGLE APPROPRIATE BACKGROUND BITS FOR WHOLE WINDOW LD A,WINDCOLS MOV B,A ;B = # of columns/row LD HL,FWAWIND ;HL = FWA of window LD A,WINDROWS ;A = # of rows :RLOOP: PUSH AF ;Save row number PUSH BC ;Save # of columns PUSH HL ;Save row address ;SET BIT LOOP :CLOOP: CALL RLDA ;GET BYTE XRI 1000_0000B ;TOGOL STO A,[HL] ;STORE BYTE INC HL DJNZ :CLOOP ;Go to next spot in row POP HL ;Restore row address LDK DE,VLL ADD HL,DE ;Next row's address POP BC POP AF DEC A JRNZ :RLOOP ;If more rows RET PAGE YCOORD: ;Set up Y coordinate for cursor addresssing ;If coordinate is invalid, row is set to last row ;ENTRY ;C = character (Y coordinate + offset) ;EXIT ;CTBLADDR set up for X coordinate PROC CALL ABSOLUTE ;Get absolute coordinate LD HL,CURPOS CALL SETROW ;Set HL to row A STO HL,CURPOS RET PAGE XCOORD: ;Set up X coordinate. If coordinate is out of range, position to column 0 ;ENTRY ;C = character (coordinate + offset) ;EXIT ;CTBLADDR reset to BASTBL, CURPOS set to new cursor position PROC CALL ABSOLUTE ;Get absolute coordinate value LD HL,CURPOS CALL SETCOL ;Set column STO HL,CURPOS RET PAGE SETOFF: ;Set X-Y coordinate offset ;ENTRY ;C = offset ;EXIT ;OFFSET updated PROC MOV A,C STO A,OFFSET RET PAGE STARTROW: ;Define first row of window ;(If row is out or range, set to row 0) ;ENTRY ;C = Row number + offset ;EXIT ;TEMPFWA = Address so far PROC ;CHECK FOR VALID ROW NUMBER MOV A,C CALL ABSOLUTE ;Get absolute number (without offset) LDK B,VMROWS CMP B JRC :1 ;If valid row, A = selected row XRA A ;If invalid, A = row 0 ;GET ROW ADDRESS :1: STO A,FSTROW ;Save row number LDK HL,FWAVM ;Start of video memory CALL ADDROWS ;Get new address STO HL,TEMPFWA ;Save in temporary FWA for window RET PAGE STARTCOL: ;Define first column of window ;(Invalid columns are set to column 0) ;ENTRY ;C = Column number + offset ;TEMPFWA set to selected row, column 0 ;EXIT ;TEMPFWA = FWA for window PROC ;CHECK FOR VALID COLUMN MOV A,C ;A = Selected column + offset CALL ABSOLUTE ;A = Selected column LDK B,VMCOLS ;B = Number of columns in video memory CMP B JRC :1 ;If valid, A = selected column number XRA A ;If invalid, A = 0 ;SET COLUMN IN TEMPFWA :1: STO A,FSTCOL ;Save first column number LD HL,TEMPFWA ;TEMPFWA = selected row, column 0 MOV E,A LDK D,0 ADD HL,DE STO HL,TEMPFWA RET PAGE ENDROW: ;Define last row of window ;(If invalid row selected, row set to last row) ;ENTRY ;C = row number + offset ;EXIT ;TEMPROWS = # of rows in new window PROC ;CHECK FOR VALID ROW MOV A,C ;A = selected row + offset CALL ABSOLUTE ;A = selected row LDK B,VMROWS ;B = number of rows CMP B JRC :1 ;If valid, A = selected row DEC B MOV A,B ;If invalid, A = last row ;CALCULATE NUMBER OF ROWS :1: LDK HL,FSTROW LD B,[HL] ;B = First row number ;A = Last row number SUB B JRNC :2 ;IF VALID XRA A ;SET TO 1 IF INVALID :2: INC A ;A = Number of rows STO A,TEMPROWS ;Save number of rows RET PAGE ENDCOL: ;Define last column for window and save window definition ;(If column out of range, set to last column) ;ENTRY ;C = column number + offset ;EXIT ;New window definitions set up & cursor positioned to home position of new window PROC ;CHECK FOR VALID COLUMN MOV A,C ;A = Selected column + offset CALL ABSOLUTE ;A = Selected column LDK B,VMCOLS ;B = Number of columns in screen CMP B JRC :1 ;If valid, A = selected column DEC B MOV A,B ;A = Last column ;GET NUMBER OF COLUMNS :1: LDK HL,FSTCOL LD B,[HL] ;B = First column ;A = Last column SUB B JRNC :2 ;IF VALID XRA A ;SET TO 1 IF INVALID :2: INC A ;A = Number of columns ;SET NEW WINDOW DEFINITION MOV B,A ;Save number of columns LDK HL,FWAWIND ;Current window definition LD DE,TEMPFWA STO E,[HL] ;Save new FWA INC HL STO D,[HL] IN HL LD A,TEMPROWS STO A,[HL] ;Save new number of rows INC HL STO B,[HL] ;Save new number of columns ; JMP VC_HOME ;Initialize cursor to home position of window PAGE VC_HOME: ;Home Cursor ;ENTRY ;NONE ;EXIT ;CURPOS = new cursor position PROC LD HL,FWAWIND ;Home position STO HL,CURPOS RET PAGE RETPROC: ;Procedure which only returns ;Used for branch addresses for console table entries which don't need to ;do anything ;ENTRY ;NONE ;EXIT ;NONE PROC RET PAGE DO_CR: ;Do Carriage Return processing ;ENTRY ;HL = address to process ;EXIT ;HL = address after carriage return PROC ;CLEAR COLUMN BITS IN SELECTED ADDRESS LDK A,80h AND L MOV L,A ;GET FIRST COLUMN OF WINDOW LD DE,FWAWIND MOV A,E ANI 7FH ;Get first window column ;SET ADDRESS COLUMN TO FIRST COLUMN OF WINDOW OR L ;OR in new column MOV L,A RET PAGE DO_LF: ;Do Line Feed processing (if address is on last line, scroll screen and add new ;line at bottom) ;ENTRY ;HL = Address to process ;EXIT ;HL = Address after line feed PROC ;CHECK IF ON LAST LINE CALL LASTROW JRNZ :1 ;IF NOT on last line ;IF ON LAST LINE, SCROLL WINDOW UP PUSH HL ;Save address LD HL,FWAWIND ;Scroll up the lines from selected position to the end of the window (Clears last line) PUSH HL CALL DIST2LASTROW ;Get A = number of rows between HL and last row POP HL ;HL = start address JRZ :DONE ;IF ON LAST ROW LD BC,WINDCOLS LDK B,0 ;BC = # of columns per row ;MOVE ROWS :LOOP: LDK DE,VLL EX HL,DE ADD HL,DE ;HL = row below DE PUSH BC ;Save row length PUSH HL ;Save row's address CALL RLDIR ;Move row HL to row DE POP HL ;Restore row address POP BC ;Restore row length DEC A JNZ :LOOP ;If more rows ;CLEAR LAST LINE :DONE: CALL CLRLN POP HL ;Restore address RET ;RETURN ;MOVE DOWN ONE LINE :1: LDK DE,VLL ;line length ADD HL,DE ;HL = new address position RET PAGE SCROL_UP: ;Scroll up the lines from selected position to the end of the window (Clears last line) ;ENTRY ;HL = selected position ;EXIT ;NONE PROC ;POSITION AT BEGINNING OF LINE CALL DO_CR ;SCROLL UP PUSH HL CALL DIST2LASTROW ;Get A = number of rows between HL and last row POP HL ;HL = start address JZ CLRLN ;If on last row CLEAR LINE AND RETURN LD BC,WINDCOLS LDK B,0 ;BC = # of columns per row ;MOVE ROWS :LOOP: LDK DE,VLL EX HL,DE ADD HL,DE ;HL = row below DE PUSH BC ;Save row length PUSH HL ;Save row's address CALL RLDIR ;Move row HL to row DE POP HL ;Restore row address POP BC ;Restore row length DEC A JNZ :LOOP ;If more rows ;CLEAR LAST LINE JMP CLRLN PAGE SCROL_DOWN: ;Scroll window down from selected start line to end of window ;(Clears start line) ;ENTRY ;HL = start address ;EXIT ;NONE PROC ;POSITION AT BEGINNING OF LINE CALL DO_CR ;Make sure at beginning of line ;SCROLL DOWN CALL DIST2LASTROW ;Get A = number of rows to scroll JRZ :DONE ;If on last line PUSH AF LD A,WINDROWS DEC A CALL SETROW ;HL = Last row's address LD A,WINDCOLS MOV C,A LDK B,0 ;BC = Number of columns POP AF ;Restore A = Number of rows :LOOP: PUSH HL ;Save row address ORA A ;Clear carry LDK DE,VLL SBC HL,DE POP DE ;HL = row above DE PUSH BC ;Save # chars/row PUSH HL ;Save row address CALL RLDIR POP HL ;Restore POP BC DEC A JRNZ :LOOP ;If more rows ;CLEAR START LINE :DONE: JR CLRLN ;HL = start line's address PAGE LASTROW: ;Check if given address is on last line ;ENTRY ;HL = address ;EXIT ;Z bit set if on last line ;HL preserved PROC CALL GETROW ;Get current row MOV B,A ;B = current row LD A,WINDROWS DEC A ;A = last row SUB B ;Set Z flag if current row = last row RET PAGE GETCOL: ;Get column number of selected address ;(If address is out of range an invalid number is returned) ;ENTRY ;NONE ;EXIT ;A = column number ;Preserves HL PROC ;GET ACTUAL COLUMN NUMBER FOR FIRST COLUMN OF WINDOW LD DE,FWAWIND MOV A,E ANI 7FH MOV C,A ;C = First column number ;GET ACTUAL COLUMN NUMBER FOR SELECTED ADDRESS MOV A,L ;Low 7 bits of L = column ANI 7FH ;Clear high bit ;GET WINDOW COLUMN NUMBER FOR SELECTED ADDRESS SUB C RET PAGE GETROW: ;Get current row of selected address ;(Invalid number returned if address is out of range) ;ENTRY ;HL = address ;EXIT ;A = Row number ;Preserves HL PROC ;GET ACTUAL ROW VALUE OF FIRST ROW IN WINDOW PUSH HL LD HL,FWAWIND ADD HL,HL ;Shift row bits to H MOV A,H ANI 1FH ;Get row bits MOV C,A POP HL ;GET ACTUAL ROW OF SELECTED ADDRESS PUSH HL ADD HL,HL ;Shift row bits to H MOV A,H ANI 1FH ;Get row bits POP HL ;GET WINDOW CURSOR ROW SUB C RET PAGE SETCOL: ;Set HL to given column, current row ;(If column is out of range, set to column 0) ;ENTRY ;HL = selected column ;A = Column number ;EXIT ;HL = set to selected column PROC ;CHECK FOR VALID COLUMN MOV C,A ;Save column LD A,WINDCOL DEC A ;A = Last column in window CMP C ;Set Cflag if position out of range MOV A,C JRNC :1 ;If in range XRA A ;If out of range ;SET COLUMN ;GET ACTUAL COLUMN VALUE FOR WINDOW'S COLUMN 0 :1: LD DE,FWAWIND ;Start of window ADD E ANI 7FH ;A = Actual column value MOV C,A ;Save column value ;SET COLUMN FOR SELECTED ADDRESS MOV A,L ANI 80H ;Clear column bits OR C ;Put in new column bits MOV L,A RET PAGE SETROW: ;Set address to given row, current column ;(If row is out of range, row set to last row) ;ENTRY ;A = row number ;EXIT ;HL = address of given row, column 0 PROC ;GET CURRENT COLUMN MOV C,A PUSH BC ;Save row CALL GETCOL POP BC ;Restore row PUSH AF ;Save column ;CHECK FOR VALID ROW LD A,WINDROWS DEC A ;A = Last valid row number CMP C JRC :1 ;If invalid MOV A,C ;If valid :1: LD HL,FWAWIND ;Start at top of window CALL ADDROWS ;and add A rows :DONE: POP AF ;Restore column JR SETCOL PAGE DIST2EOL: ;Calculate #chrs to between given address and last column in line ;ENTRY ;HL = address ;EXIT ;BC = # characters between address and last column ;A = # characters between address and last column ;Z bit set if 0 characters (ie address is at end of line) ;HL saved PROC PUSH HL CALL GETCOL ;Get column MOV C,A ;C = column LD A,WINDCOLS ;A = line length DEC A ;A = Last column in line SUB C ;A = #chrs between address and last column MOV C,A LDK B,0 ;BC = #chrs between address and last column POP HL RET PAGE DIST2LASTROW: ;Calculate number of rows between given position and last line of video ;ENTRY ;HL = given position ;EXIT ;A = # of rows from given position to beginning of last line ;Flags set: Z if given position on last line ; C if given position past last line PROC CALL GETROW MOV C,A ;C = cursor row LD A,WINDROWS DEC A ;A = last row SUB C RET ;A = # of rows between cursor and last row PAGE EEOL: ;Erase to end of line ;ENTRY ;NONE ;EXIT ;CURPOS unchanged PROC LD HL,CURPOS ; JR CLRLN ;Clear to end of line PAGE CLRLN: ;Clear to end of line ;ENTRY ;HL = start position ;EXIT ;clear to EOL ; Uses All. PROC ;CLEAR START POSITION CALL CLR_CHAR ;Clear character ;FIND NUMBER OF BYTES TO CLEAR CALL DIST2EOL ;BC = distance to end of line, Z flag set RZ ;Done if at end of line PUSH HL POP DE INC DE CALL RLDIR ;Clear rest of line RET PAGE ADDROWS: ;Add rows to given address ;ENTRY ;HL = start address ;A = number of rows ;*NOTE* This routine does not check for address out of range ; The calling procedure must do that ;EXIT ;HL = new address PROC ;CHECK FOR ROW 0 ORA A ;A = row number RZ ;Done if row 0 ;ADD NUMBER OF ROWS TO WINDOW BEGINNING ADDRESS LDK DE,VLL ;Distance to next row :LOOP: ADD HL,DE ;Add a row DEC A JRNZ :LOOP ;If more rows RET PAGE ABSOLUTE: ;Get absolute value for offset number ;ENTRY ;C = Number + offset ;EXIT ;A = Absolute number (without offset) LD A,OFFSET ;Get cursor positioning offset NEG A ADD A,C ;A = Absolute cursor position RET PAGE ;CONSOLE TABLES BASET: ;Base table -- used to look up the first character in a sequence ;The table lists characters and procedures to branch to to process the character ;1st byte of table is number of entries ;Entries are 4 bytes long: ; 1st byte = match code ; 2nd byte = next table number ; 3rd, 4th bytes = branch address ;The last entry is a 3-byte "No Match" default next table and branch address PROC DB BASSIZ ;Number of entries in base table ; +----------------------------------------------+ ; | CHARACTER | NEXT TABLE | BRANCH ADDR | ; +----------------------------------------------+ DB ESC ! DB ESCNUM ! DW RETPROC ;ESC sequence :ENDB: DB BASNUM ! DW PROCNORM ;No Match ;-- Process normal 1 character long "sequence" BASSIZ = (:ENDB-BASET + 1)/4 ;Number of entries in BAST PAGE ESCT: ;Valid ESC-Sequence Table ;1st byte is number of entries ;4 bytes per entry: ascii char, next table number, branch address ;Following body of table is 3 byte No-Match default next table and branch adrs PROC DB ESCSIZ ;Number of bytes ; +----------------------------------------------+ ; | CHARACTER | NEXT TABLE | BRANCH ADDR | ; +----------------------------------------------+ DB VCAD ! DB YNUM ! DW RETPROC ;Cursor Addressing DB VCAS ! DB BASNUM ! DW ESCZZ ;Clear screen to blanks DB VINC ! DB BASNUM ! DW EINSRT ;Insert char DB VDELC ! DB BASNUM ! DW EDELC ;Delete char DB VINL ! DB BASNUM ! DW ESCEE ;Insert line DB VDELL ! DB BASNUM ! DW ESCRR ;Delete line DB VCEOL ! DB BASNUM ! DW EEOL ;Clear to end of line DB VCEOS ! DB BASNUM ! DW EEOS ;Clear to end of screen (window) DB VSRV ! DB BASNUM ! DW ESCSHI ;Start reverse video DB VERV ! DB BASNUM ! DW ESCEHI ;End reverse video DB VSHI ! DB BASNUM ! DW ESCSHI ;Set half intensity mode DB VEHI ! DB BASNUM ! DW ESCEHI ;Clear half intensity mode DB VSUL ! DB BASNUM ! DW ESCSHI ;Start underline DB VEUL ! DB BASNUM ! DW ESCEHI ;End underline DB VSGH ! DB BASNUM ! DW ESCSGR ;Set graphics mode DB VEGH ! DB BASNUM ! DW ESCCGR ;Clr graphics mode DB VWDEF ! DB DWINNUM ! DW RETPROC ;Define a window DB VOFF ! DB OFFNUM ! DW RETPROC ;Define X-Y offset DB VRON ! DB BASNUM ! DW REVON ;Set Reverse video background DB VROFF ! DB BASNUM ! DW REVOFF ;Set normal video background DB VLOCK ! DB BASNUM ! DW ESCLCK ;Lock Keyboard DB VUNLK ! DB BASNUM ! DW ESCULK ;Unlock Keyboard DB VAL128 ! DB BASNUM ! DW ESCSAL ;alternate 128 character set DB VMA128 ! DB BASNUM ! DW ESCCAL ;MAIN 128 character set DB V256W ! DB BASNUM ! DW ESCW256 ;256 CHARACTER SET WITH REVERSE VIDEO DB V256WO ! DB BASNUM ! DW ESCWO256 ;256 CHARACTER SET WITHOUT REVERSE VIDEO :ENDE: DB BASNUM ! DW LOOKUPB ;No Match exit ESCSIZ: = (:ENDE-ESCT+1)/4 ;# of entries in table PAGE CTLT: ;Valid control character table ;1st byte is number of bytes in table ;5 bytes per entry: Ascii char, next table address, branch address ;Following body of table is 4 byte default next table and branch adrs DB CTLSIZ ;# entries in table ; +----------------------------------------------+ ; | CHARACTER | NEXT TABLE | BRANCH ADDR | ; +----------------------------------------------+ DB CR ! DB BASNUM ! DW VC_CR ;carriage return routine DB LF ! DB BASNUM ! DW VC_LF ;line feed DB BKS ! DB BASNUM ! DW VC_BKS ;back space DB MCRIGH ! DB BASNUM ! DW VC_MCRT ;move cursor right DB MCUP ! DB BASNUM ! DW VC_MCUP ;move cursor up DB VDWN ! DB BASNUM ! DW VC_MCDOWN ;Move cursor down DB CBELL ! DB BASNUM ! DW VC_BEL ;Ring bell DB VLIN ! DB BASNUM ! DW VC_NEWLINE ;New line (CR,LF) DB VCLRS ! DB BASNUM ! DW VC_CLRS ;clear screen DB VHOME ! DB BASNUM ! DW VC_HOME ;Cursor Home :ENDC: DB BASNUM ! DW RETPROC ;No match ;--ignore undef control char and go ; back to base table CTLSIZ: = (:ENDC-CTLT+1)/4 ;Number of valid entries PAGE YTAB: ;Y Coordinate table. Only default entry since all values go to the same procedure DB 0 ;Number of entries ; +----------------------------------------------+ ; | CHARACTER | NEXT TABLE | BRANCH ADDR | ; +----------------------------------------------+ DB XNUM ! DW YCOORD ;"No Match" PAGE XTAB: ;X coordinate table. Only default entry since all values go to the same procedure DB 0 ;Number of entries ; +----------------------------------------------+ ; | CHARACTER | NEXT TABLE | BRANCH ADDR | ; +----------------------------------------------+ DB BASNUM ! DW XCOORD ;"No Match" PAGE DWIN: ;Define WINDOW NUM PROC DB DWINSIZ ; +----------------------------------------------+ ; | CHARACTER | NEXT TABLE | BRANCH ADDR | ; +----------------------------------------------+ :ENDF: DB FROWNUM ! DW RETPROC ;THROW AWAY NUMBER DWINSIZ: = (:ENDF-DWIN+1)/4 PAGE FROWT: ;Define first row of window PROC DB FROWSIZ ; +----------------------------------------------+ ; | CHARACTER | NEXT TABLE | BRANCH ADDR | ; +----------------------------------------------+ :ENDF: DB FCOLNUM ! DW STARTROW ;Define first row of window FROWSIZ: = (:ENDF-FROWT+1)/4 PAGE FCOLT: ;Define first column of window PROC DB FCOLSIZ ; +----------------------------------------------+ ; | CHARACTER | NEXT TABLE | BRANCH ADDR | ; +----------------------------------------------+ :ENDF: DB LROWNUM ! DW STARTCOL ;Define first column of window FCOLSIZ: = (:ENDF-FCOLT+1)/4 PAGE LROWT: ;Define last row of window PROC DB LROWSIZ ; +----------------------------------------------+ ; | CHARACTER | NEXT TABLE | BRANCH ADDR | ; +----------------------------------------------+ :ENDL: DB LCOLNUM ! DW ENDROW ;Define last row of window LROWSIZ: = (:ENDL-LROWT+1)/4 PAGE LCOLT: ;Define last column of window PROC DB LCOLSIZ ; +----------------------------------------------+ ; | CHARACTER | NEXT TABLE | BRANCH ADDR | ; +----------------------------------------------+ :ENDL: DB BASNUM ! DW ENDCOL ;Define last column of window LCOLSIZ: = (:ENDL-LCOLT+1)/4 PAGE OFFT: ;Set X offset PROC DB OFFSIZ ; +----------------------------------------------+ ; | CHARACTER | NEXT TABLE | BRANCH ADDR | ; +----------------------------------------------+ :ENDO: DB BASNUM ! DW SETOFF ;Set X-Y offset OFFSIZ: = (:ENDO-OFFT+1)/4 PAGE ;Console table numbers BASNUM: = 1 ;Base table number ESCNUM: = 2 ;Escape table number CTLNUM: = 3 ;Control table number YNUM: = 4 ;Y coordinate table number XNUM: = 5 ;X coordinate table number DWINNUM: = 6 ;DEFINE WINDOW NUMBER FROWNUM: = 7 ; First row table number FCOLNUM: = 8 ; First column table number LROWNUM: = 9 ; Last row table number LCOLNUM: = 10 ; Last column table number OFFNUM: = 11 ;X & Y offset table number CTBLPTRS: ;Console table pointer structure DW BASET ;Current table to be searched Initially search the base table ;Table pointers DW BASET ; Base table DW ESCT ; Escape table DW CTLT ; Control table DW YTAB ; Y-coordinate table DW XTAB ; X-coordinate table DW DWIN ;DEFINE WINDOW NUMBER DW FROWT ; First row of window (for window define) DW FCOLT ; First column of window DW LROWT ; Last row of window DW LCOLT ; Last column of window DW OFFT ; X-Y offset table PAGE ****THIS ROUTINE RUNS IN RAM AT LOCATION "VRS"**** SOURCE = * ;FBA OF CODE TO BE MOVED SHIFT: = SOURCE-VRS ;OFFSET RLDIR: = *-SHIFT ;DO LDIR BUT IN RAM LDIR RET RLDDR: = *-SHIFT ;DO LDDR BUT IN RAM LDDR RET  RLDA: = *-SHIFT ;DO "LD A,[HL]" BUT IN RAM LD A,[HL] RET ****END OF MOVED BLOCK**** VRL: = *-SOURCE ;LENGTH OF BLOCK TO MOVE PAGE *[7] ;INTERRUPT PROCESSOR INTHNDL: ;Interrupt handler PROC ;SAVE STACK AND SET NEW STACK STO SP,ISSTK ;SAVE OLD STACK LDK SP,ISTK ;SET NEW STACK ;Save all registers ;IT IS ASSUMED THAT IX & IY ARE NOT USED PUSH AF PUSH BC PUSH DE PUSH HL PAGE ;KEYBOARD INTERRUPT PROCESSOR ;NOTE ;IT IS ASSUMED THAT IX & IY ARE NOT USED ;CHECK KEYBOARD INTERRUPT IN INTPORT ;GET STATUS BIT 2,A ;TEST BIT 2 JRZ :RET ;RETURN IF NO INTERRUPT PENDING ;CLEAR KEYBOARD INTERRUPT ;DISABLE XRA A ;A=0 : SET DISABLE BIT OUT INTPORT ;ENABLE INC A ;A=1 : SET ENABLE BIT OUT INTPORT ;UPDATE BELL ;CHECK FOR ACTIVE LD A,BELCNT ;GET BELL COUNT ORA A JZ :1 ;IF NOT ACTIVE ;DECREMENT COUNT AND CHECK FOR 0 DEC A STO A,BELCNT ;SAVE BELL COUNT JNZ :1 ;LEAVE BELL RINGING IF NOT ZERO ;TURN BELL OFF LDK A,3 OUT SYSRS ;PORT C IN SYSRW ;READ IT ORI 0010_0000B ;SET BELL BIT TO TURN IT OFF OUT SYSRW ;Routine checks to see if the disk drive motor should be turned off by updating DACTIVE...Routine ALSO :1: LD A,DACTVE OR A JZ :2 ;If inactive ;TURN DRIVE OFF IF DACTVE = 1 DEC A STO A,DACTVE JNZ :2 ;IF DACTVE > 0 LDK A,3 OUT SYSRS ;SELECT PORT 3 IN SYSRW ;READ PORT ORI 0000_0011B ;CLEAR DRIVE BITS OUT SYSRW ;DEACTIVATE DRIVES ;UPDATE COUNTER :2: LD HL,SEQ ;GET LOW TWO BYTES INC HL ;+1 STO HL,SEQ ;STORE ;READ KEYBOARD LD A,KEYLCK OR A CNZ KBDRVR ;READ KEYBOARD IF KEYLOCK NOT ACTIVE PAGE ;END OF INTHNDL ;RESTORE ALL REGISTERS :RET: POP HL POP DE POP BC POP AF ;RESTORE OLD STACK LD SP,ISSTK ;RESTORE OLD STACK EI RET PAGE *[8] ;KEYBOARD DRIVER SKEY: ;Get status of keyboard ;EXIT ;A = FF IF DATA READY ;ZBIT = set if no data ready PROC LD A,LKEY INC A RZ ;INDICATE NO DATA AND RETURN ;INDICATE THERE IS A BYTE WAITING AND RETURN ORI 0FFH ;SET FLAGS RET PAGE CI: ;Read next key from keyboard ;NOTE ;INTERUPTES ARE DISABLED BECAUSE WE DON'T WON'T A KEY TO BE PUT IN WHILE WERE TAKING IT OUT ;EXIT ;A = last key ;C = last key PROC ;CHECK FOR CHARACTER CALL SKEY JZ CI ;if NO data DI LD A,LKEY ;GET CHARACTER MOV C,A ;SAVE IT LDK A,0FFH STO A,LKEY ;clear key from hold MOV A,C ;RESTORE IT EI RET PAGE ; +---------------+ ; | | ; | KEYBOARD | ; | | ; +---------------+ ;NOTE ;IT IS ASSUMED THAT IX & IY ARE NOT USED ;Als include completel tabl drive keystrok translatio wit SEPARATE tabl fo CTRL SHIFT ;ALPH LOCK CTRL-SHIF (bot hel dow simultaneously an norma (n shift-typ key hel down). ;Th keyboar emulate th Televide 9X serie i th followin way I tw key ar hel dow ;simultaneously th las on presse dow i considere a th onl ke presse (i.e. th firs ke ;presse i ignored) I mor tha tw key ar hel down the al ar ignored. ;Keystroke ar interprete thi wa t implemen ke rollover. ;Previousl (o th 01 fo example tw o mor key hel dow simultaneousl woul alternat i ;somewha haphazar fashion. ;Th rapidit wit whic ke wil repea ha bee double t brin performanc mor i lin wit ;th Televideo. ;Th keystrok translatio table ar reference b pointe t th firs one Sinc ther i onl ;on pointer th table mus al b o th sam length Thi i no muc o limitation sinc th ;keyboar sca matri i 8 Th translatio tabl pointe ca b modifie t poin t differen ;se o tables thu changin th keyboar translation. ;An keystrok translatio tabl mus b arrange t correspon t th wa i whic th keyboar i ;scanne (i.e. th wa i whic th keyboar matri i arranged. Fo thi implementation th ;keyboar sca logi diagra i th OSBORN User' Referenc Guid wa use a th reference. ;Du t a anomal i th keyboar switc matrix som contro shif combination ar considere ;invalid An ke i th matri tha i i th sam colum a CTR o SHIF constitute a invali ;sequence Thi i du t th fac tha th switche i th keyboar ar connecte i a ope ;network Tha is curren ca flo i an direction S i CTRL SHIF an (fo example ar al ;hel down whe th keyboar sca routin applie curren t th ro containin th key th ;curren flow u t th CTR ke (whic i o th sam column) ove t th SHIF ke (o th sam ;ro a CTRL an sinc SHIF i down closin th contac t th colum containin it curren flow ;t th junctio a whic th switc fo i positioned Thu i appear tha i dow a wel a ;E I onl on o SHIF o CTR wer hel dow thi woul no occu sinc complet circui amon ;al point i required. PAGE KBDRVR: ;DETECTS AND PROCESSES KEYSTROKES. ;Modified to process key rollover like the TeleVideo 9xx series. ;ENTRY ;NONE ;EXIT ;LKEY = KEYSTROKE ;Any valid keystrokes are translated by KBSERV and sent to the BIOS by LKEY PROC ;Check to see if LKEY is empty or not. LD A,LKEY INC A ;A WILL BE 0 IF no char waiting RNZ ;RETURN IF LKEY HAS A KEY IN IT CALL KBSCAN ;Scan keyboard for latched keys and place keys in keylist ;Check for any keys in the key list. If the first keylist entry is empty, then there are no keys in list LDK HL,FIRSTKEY ;Point at first keylist entry LD A,[HL] ;Get key list entry BIT KL_USED,A ;See if entry used bit is set RZ ;No...Keylist entry: Return ;Now see if keys in list are still down LDK B,KL_LEN ;Set loop counter to number of keys in list. HL points ; to first entry, A contains first key entry :1: BIT KL_USED,A ;Is this keylist entry in use? JRZ :3 ;No...No more entries to check ;Keylist entry not empty: is the key still down? PUSH BC ;Save loop counter over call to CHKEY AND KROW_M+KCOL_M ;Mask off all bits except row & col no. CALL CHKEY ;Call CHKEY to see if key in A is still down POP BC JRNZ :2 ;Z SET IF KEY OFF... PUSH HL ;SAVE POINTER TO CURRENT LIST ENTRY PUSH BC CALL REMOVEKEY ;REMOVE KEY FROM LIST. NEXT KEY (IF ANY) is now in current POP BC ; slot, since REMOVEKEY moves everything down one slot. POP HL LDK A,1 ;Set A to value B should be if this is the last entry CMP B ;Compare A with B. Is this the last entry? JRZ :3 ;Yes... LD A,[HL] ;No. More to check. Load next key, now in current slot JR :1 ;and check this key. ;Key is on: go to next key, if any. :2: INC HL ;Bump HL twice to point to next entry INC HL LD A,[HL] ;Load key pointed to by HL DEC B ;Decrement loop counter. Are we all done? JRNZ :1 ;No... Continue ;Now see if there are still keys in list (i.e., if there are still any down. :3: LDK HL,FIRSTKEY ;Point to first keylist entry BIT KL_USED,[HL] ;Is it in use? RZ ;No. No first key implies no keys at all. Return. ;Now see if the user has more than two keys jammed down at once. ALPHA LOCK, CTRL and SHIFT notwithstanding. ; More than two keys and we don't do anything, just like the TVIs. LDK HL,SECONDKEY+2 ;Point to key after second LD A,[HL] ;Get it. BIT KL_USED,A ;Is it in use? RNZ ;Yes. More than two keys down. Return. ;Only one or two keys down. See if it's two. LDK HL,SECONDKEY ;Point at second keylist entry BIT KL_USED,[HL] ;Is there a second key in the list? JRZ :4 ;No. Check first key ;Two keys down. See it it's time to service the second key. PUSH HL ;Save pointer to keylist entry CALL CKSERV POP HL JRC KBSERV ;Service key pointed to by HL if timed out RET ;Else return... ;As there is no second key down or it is timed out, check first key in list. :4: LDK HL,FIRSTKEY ;Point at first keylist entry PUSH HL  CALL CKSERV ;Is it time to service? POP HL RNC ;No: carry clear, not time to service. Return... ;FALL THROUGH TO KBSERV PAGE KBSERV: ;Routine to service key list entry. ;ENTRY: ;HL = Key list entry to service. ;EXIT: ;None. CT_KEY = 2 SH_KEY = 4 AL_KEY = 3 PROC LD A,[HL] ;Get keylist entry pointed to by HL. AND KROW_M+KCOL_M ;Mask to leave only column and row ;number bits. PUSH AF ;Save key list entry ;Get Status of CTRL, SHIFT and ALPHA LOCK keys. LDK L,1 ;Read row containing SHIFT and CTRL keys ;(Row 1) CALL RDROW ;Call routine to read that row of the ;keyboard. PUSH AF ;Save CTRL and SHIFT row LDK L,80H ;Read row containing ALPHA LOCK key. (Row 8) CALL RDROW ;Read it AND 8 ;AND off all bits except ALPHA LOCK MOV E,A ;Move ALPHA LOCK status to E so SHIFT/CTRL can be restored to A POP AF ;Restore SHIFT and CTRL to A OR E ;OR ALPHA LOCK bit into SHIFT and CTRL status byte ;A now contains SHIFT, CTRL and ALPHA LOCK. ;Thus we can now check for these keys being down: BIT CT_KEY,A ;Is CTRL down? JRZ :2 ;No... BIT SH_KEY,A ;Yes; is SHIFT down too? JRZ :1 ;No...Only CTRL is down LDK A,CS_TB_NO ;CTRL and SHIFT down. Indicate that ;current CTRL/SHIFT table is to be used JR :5 ;Translate key using table indicated by ;C ;Only CTRL down. :1: LDK A,CT_TB_NO ;Use CTRL table... JR :5 ;To translate key. ;CTRL not down... :2: BIT SH_KEY,A ;Is SHIFT down? JRZ :3 ;No... LDK A,SH_TB_NO ;Yes...Use SHIFT table to JR :5 ;translate key ;SHIFT not down. :3: BIT AL_KEY,A ;Is ALPHA LOCK down? JRZ :4 ;No... LDK A,AL_TB_NO ;Yes...Use ALPHA LOCK table to JR :5 ;translate key ;ALPHA LOCK not down. No 'translate' keys down, so use :4: LDK A,NM_TB_NO ;'Normal' table to translate keys ;Translate keystroke on stack according to the table whose number is in C :5: LD HL,TBLBASE ;Load pointer to tables LDK DE,TBL_LEN ;Load length of table OR A ;Set flags to see if tbl no. is zero JRZ :ELP ;Yes...don't bump ptr to next tbl :LP: ADD HL,DE ;Not pointing at right tbl; bump ptr to ;next DEC A ;Decrement tbl no JRNZ :LP ;and bump ptr to next if not zero :ELP: POP AF ;Restore key number to A LDK D,0 ;Zero hi byte of DE to index into ;translate table MOV E,A ;Move key number to E ADD HL,DE ;Add base address of table to index LD A,[HL] ;Get translated keystroke from table. CMP BADKEY ;Is it an invalid keystroke? (most ;likely a bad CTRL/SHIFT combination) RZ ;Yes...return without sending char to BIOS ;PUT CHARACTER IN LKEY TO BE SENT TO OS STO A,LKEY RET PAGE CHKEY: ;CHECKS IF KEY NUMBER IS ON. ;ENTRY ;A = KEYNUMBER ;EXIT ;Z CLR = KEY IS OFF. ;Z SET = KEY IS ON. PROC PUSH HL ;SAVE CALLERS HL PUSH AF ;SAVE KEYNUMBER RAR RAR RAR ;RIGHT JUSTIFY ROW NUMBER CALL GTMASK POP AF ;GET KEY NUMBER PUSH DE ;SAVE ROW MASK CALL GTMASK ;GET COL MASK (COL NUM IS IN BITS 0..2) POP HL ;MOVE ROW MASK TO L CALL RDROW ;GET ROW OF KEYS ADRSED BY L AND E ;Z IND = VALUE OF KEY POP HL RET PAGE REMOVEKEY: ;Remove keylist entry pointed to by HL from keylist ;ENTRY: ;HL = KeyList entry to delete. ;EXIT: ;All following entries in KeyList (if any) are shifted down ;one slot. ;If there are no following entries in the KeyList, the entry ;pointed to is simply zeroed. PROC PUSH HL ;Save pointer to entry to delete LDK DE,LASTKEY ;Load address of last key in list EX HL,DE ;Swap HL and DE so subsequent subtract operation will return ; the number of cells to move or zero if current entry is last STC ;Clear carry so double precision CMC ;subtract with carry can be used SBC HL,DE ;Subtract address of entry to delete from address of last entry ; in list. If zero set the entry to delete is the last in the ; list, else HL contains the number of bytes to move. MOV B,H  ;Move result to BC to set up for LDIR MOV C,L POP DE ;Restore pointer to DE for LDIR JRZ :1 ;If previous subtract resulted in zero, entry to delete is ; last in list and the only action to take is to delete ;the last list entry. MOV H,D ;Copy pointer to entry to delete to HL MOV L,E INC HL ;Bump HL to point to next entry INC HL LDIR ;Do block move: move entries following entry to delete down ; into entry to delete ;Finally, clear last list entry. :1: LDK HL,LASTKEY ;Point to last key list entry STO 0,[HL] ;Clear first byte of entry INC HL ;Point to second byte STO 0,[HL] ;Clear it to. RET PAGE CKSERV: ;Routine to check for time out on key list entry. ;ENTRY: ;HL = entry to check for time out. ;EXIT: ;HL = value on entry. ;Carry flag set if time to service key list entry. ;Additionally, if it is not time to service the key, the time out ;counter of the list entry is decremented. If it is time to ;service the key, the counter is re-initialized. The value ;it is set to depends on whether the key has serviced already. ;If it hasn't, the counter is set to a value which causes a ;slight delay before the key begins to repeat. ;Otherwise, the key has already begun to repeat, so the counter ;is set to a smaller value associated with the rapidity with ;which the key repeats. PROC INC HL ;Increment HL to point to list entry repeat count DEC [HL] ;Decrement repeat count DEC HL ;Decrement HL to point back to key. JRNZ :2 ;Repeat count not zero; not time to service key BIT KY_SRVD,[HL] ;Key ready to service. Has it been serviced before? JRNZ :1 ;Yes... SBIT KY_SRVD,[HL] ;No. Set serviced already bit flag in keylist entry INC HL ;Point to keylist entry repeat count. STO IRPTCT,[HL] ;Initialize repeat count to delay before ;key should start repeating JR :EXIT ;And exit with carry set and HL pointing ;to list entry ;Not first time key has been served :1: INC HL ;Point to entry repeat count STO SRPTCT,[HL] ;Initialize repeat counter to delay before key should repeat again ;Restore HL to initial entry value and set Carry flag denoting it is time to service key. :EXIT: DEC HL ;Decrement HL to point to key list entry STC ;Set carry flag RET ;and return ;Not time to service key. Clear carry :2: STC ;To clear, set carry CMC ;and complement RET PAGE KBSCAN: ;SCAN KEYBOARD FOR ALL KEYS EXCEPT CTRL, ALPHA LOCK, & SHIFT : ENTER DETECTED KEYS IN THE KEYLIST. ;Keystrokes are put in first open entry in list. ;ENTRY ;NONE ;EXIT ;KEYLST = CONTAINS ANY KEYS DETECTED. PROC ;SEE IF ANY KEY PRESSED NOT INCLUDING ALPHA LOCK ;CHECK FIRST 7 ROWS LDK L,0111_1111B CALL RDROW JRNZ :STR ;START SCAN IF A KEY IS PRESSED ;RETURN WHEN NONE ;CHECK LAST ROW EXCLUDING ALPHA LOCK LDK L,1000_0000B CALL RDROW ANI 1000_0011B ;REMOVE ALPHA LOCK & 2ND CR RZ ;RETURN IF NO KEY PRESSED ;START SCAN :STR: LDK L,ROW0_M ;GET ROW 0 CALL RDROW AND 1110_0011B ;REMOVE SHIFT, BLANK, & CTRL LDK B,TOT_ROW ;IN THIS LOOP, REG B CONTAINS TOTROW CURRENT ROW BEING SCANNED :1: JZ :10 ;SKIP COLOM DECODE IF NO KEY PRESSED IN THIS ROW ;CHECK FOR ROW 7 MOV E,A ;E = COLUMNS MOV A,B ;GET COUNT DEC A JNZ :2 ;SKIP IF NOT LAST ROW ;REMOVE ALPHA LOCK MOV A,E ANI 1000_0011B ;REMOVE ALPHA LOCK & 2ND CR RZ ;RETURN IN NO KEY PRESSED IN LAST ROW MOV E,A ;PROSESS ANY KEY IS PRESSED :2: PUSH BC ;SAVE LOOP COUNT LDK A,TOT_ROW SUB B RAL RAL RAL MOV D,A ;D = ROW NUMBER * 8 LDK C,0 ;INITIALIZE COLUMN COUNTER ;SCAN THIS ROW FROM RIGHT TO LEFT TO GET THE COLUMN NUMBER :3: SRL E ;SHIFT COLUMN BIT INTO CARRY JNC :9 ;IF A KEY IS FOUND THEN ;ENTER THE KEY WHOSE COLUMN NUMBER IS IN C AND ROW*8 IS IN D INTO THE KEYLST PROVIDED THE KEY IS NOT ;ALREADY IN LIST AND THERE IS AN EMPTY SLOT IN THE LIST. MOV A,D ADD A,C PUSH BC MOV C,A ;C = KEY NUMBER PUSH DE ;SAVE DE PUSH HL ;SAVE HL LDK B,KL_LEN ;LENGTH OF KEYLIST LDK HL,KEYLST LDK DE,0 :4: LD A,[HL] BIT KL_USED,A JZ :5 ;IF ENTRY IS USED THEN AND KROW_M+KCOL_M CMP C ;CHECK WITH CURRENT KEY JZ :8 ;EXIT IF THIS KEY IS IN LIST JMP :6 :5: MOV E,L ;ELSE (AN EMPTY ENTRY IS FOUND) MOV D,H ;SAVE ADRS OF EMPTY ENTRY IN DE JMP :7 ;And jump to code to save keystroke :6: INC HL INC HL DJNZ :4 ;TILL LIST SCANNED JMP :8 ;No empty entry found... ;CHECK IF AN EMPTY ENTRY WAS FOUND. :7: EX DE,HL ;HL = EMPTY ENTRY STO C,[HL] ;STORE THE KEY IN THE LIST SBIT KL_USED,[HL] ;SET USED FLAG INC HL STO DB_CT,[HL] ;STORE DEBOUNCE DELAY :8: POP HL ;RESTORE ALL REGSTERS POP DE POP BC :9: INC C ;INCREMENT COLUMN NUMBER XOR A CMP E JNZ :3 ;UNTIL ALL COLUMNS SCANNED POP BC ;RSTORE BC :10: SLA L ;MOVE TO NEXT ROW CALL RDROW DJNZ :1 RET PAGE GTMASK: ;GENERATES MASK WITH ONE BIT SET. ;ENTRY ;A = BIT NUMBER (0..7) ;EXIT ;E = MASK PROC LDK E,1 AND 7 :1: RZ SLA E DEC A JR :1 PAGE RDROW: ;READS ROWS OF KEYS ;ENTRY ;L = ROWS TO READ (EACH BIT INDICATES A ROW) ;EXIT ;A = ROW VALUE ;(A BIT IS SET IF THAT BIT (KEY) IS SELECTED IN ANY OF THE CHOSEN ROWS) ;MUST SAVE B REG PROC ;ACTIVATE ROW LDK A,2 OUT SYSRS ;SELECT PORT 2 MOV A,L XRI 0FFH ;INVERT OUT SYSRW ;ACTIVATE ROW ;READ RESULT LDK A,1 ;SELECT PORT A OUT SYSRS IN SYSRW ;GET VALUES XRI 0FFH ;INVERT RET PAGE ; +---------------------------------------+ ; | KEY CODE TRANSLATION TABLES | ; +---------------------------------------+ ;UNSHIFTED KYCDTB: DB esc, tab, Bad, Bad, Bad, cr, '''', '[' DB '1', '2', '3', '4', '5', '6', '7', '8' DB 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i' DB 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k' DB 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',' DB 8ah, 8dh, '0', ' ', '.', 'p', 'o', '9' DB 8bh, 8ch, '-', '/', ';', '\', 'l', '=' DB DEL, '{', Bad, Bad, Bad, Bad, Bad ,8EH ;SHIFTED DB esc, tab, Bad, Bad, Bad, cr , '"', ']' DB '!', '@', '#', '$', '%', '^', '&', '*' DB 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I' DB 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K' DB 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<' DB 8ah, 8dh, ')', ' ', '>', 'P', 'O', '(' DB 8bh, 8ch, '_', '?', ':', '|', 'L', '+' DB DEL, '}', Bad, Bad, Bad, Bad, Bad ,8FH ;CONTROL DB esc, TAB, Bad, Bad, Bad, cr , Bad, '['-40H DB 81H, 82H, 83H, 84H, 85H, 86H, 87H, 88H DB 'Q'-40H, 'W'-40H, 'E'-40H, 'R'-40H, 'T'-40H, 'Y'-40H, 'U'-40H, 'I'-40H DB 'A'-40H, 'S'-40H, 'D'-40H, 'F'-40H, 'G'-40H, 'H'-40H, 'J'-40H, 'K'-40H DB 'Z'-40H, 'X'-40H, 'C'-40H, 'V'-40H, 'B'-40H, 'N'-40H, 'M'-40H, Bad DB 8ah, Bad,80H, ' ', Bad, 'P'-40H, 'O'-40H, 89H DB 8bh, 8ch, '_'-40H, '~', Bad, '\'-40H, 'L'-40H, '`' DB DEL, '{', Bad, Bad, Bad, Bad, Bad ,90H ;ALPHA LOCK DB esc, tab, Bad, Bad, Bad, cr, '''', '[' DB '1', '2', '3', '4', '5', '6', '7', '8' DB 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I' DB 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K' DB 'Z', 'X', 'C', 'V', 'B', 'N', 'M', ',' DB 8ah, 8dh, '0', ' ', '.', 'P', 'O', '9' DB 8bh, 8ch, '-', '/', ';', '\', 'L', '=' DB DEL, '{', Bad, Bad, Bad, Bad, Bad ,8EH ;CONTROL & SHIFT DB esc, tab, Bad, Bad, Bad, cr , Bad, ']'-40H DB 81H, '@'-40H, Bad, 84H, Bad, '^'-40H, 87H, 88H DB 'Q'-40H, 'W'-40H, Bad, 'R'-40H, Bad, 'Y'-40H, 'U'-40H, 'I'-40H DB 'A'-40H, 'S'-40H, Bad, 'F'-40H, Bad, 'H'-40H, 'J'-40H, 'K'-40H DB 'Z'-40H, 'X'-40H, Bad, 'V'-40H, Bad, 'N'-40H, 'M'-40H, Bad DB 8ah, Bad, Bad, ' ', Bad, 'P'-40H, 'O'-40H, Bad DB 8bh, 8ch, '_'-40H, Bad, '_'-40H, '\'-40H, 'L'-40H, '`' DB DEL, '}', Bad, Bad, Bad, Bad, Bad ,91H PAGE *[9] ;FLOPPY DISK DRIVER RDRV: ;RESET DRIVE ;ENTRY ;NONE ;EXIT ;ZBIT = RESET IF ERROR PROC LDK B,NRETRY ;GET NUMBER OF RETRYS :LOOP: PUSH BC ;SAVE RETRY COUNT CALL SELDRV ;SELECT DRIVE CALL HOME ;HOME DRIVE POP BC JRNC :END ;IF GOOD :1: DJNZ :LOOP ;RETRY LOOP LDK A,1 ORA A ;INDICATE ERROR RET :END: XRA A RET PAGE RSEC: ;READ SECTOR ;ENTRY ;B = NUMBER OF SECTORS ;EXIT ;HL = LAST DMA ADDRESS PLUS ONE IF GOOD TRANSFER ;ZBIT = RESET IF ERROR ;A = NONZERO IF ERROR ;B = NUMBER OF SECTORS PROC LDK A,D.RDS STO A,R_WCOM JR R_WSEC PAGE WSEC: ;WRITE A SECTOR ;ENTRY ;B = NUMBER OF SECTORS ;EXIT ;HL = LAST DMA ADDRESS PLUS ONE IF GOOD TRANSFER ;ZBIT = RESET IF ERROR ;A = NONZERO IF ERROR ;B = NUMBER OF SECTORS PROC LDK A,D.WRTS STO A,R_WCOM ;FALLS THROUGH TO "R_WSEC" PAGE R_WSEC: ;READ OR WRITE SEGMENT ;ENTRY ;B = NUMBER OF SECTORS TO READ OR WRITE ;R_WCOM = D.RDS OR D.WRTS ;EXIT ;HL = LAST DMA ADDRESS PLUS ONE IF GOOD TRANSFER ;ZBIT = RESET IF ERROR PROC STO BC,NUMSEC ;SAVE BC LDK A,NRETRY STO A,RTRY ;SET RETRY NUMBER ;SELECT DRIVE CALL SELDRV ;TURN DRIVE ON JRZ :1 ;IF DRIVE ON DON'T READ ADDRESS ;SET "DSK_TRK" TO HEAD POSITION ;ALSO RETRY LOOP START :RLOOP: CALL RADR ;READ ADDRESS AND SET CONTROLLER JRC :2 ;RETRY IF ERROR ;SEEK :1: CALL SEEK ;SEEK TO TRACK JRC :2 ;RETRY IF ERROR ;READ OR WRITE LD BC,NUMSEC ;B = NUMBER OF SECTORS TO R/W CALL RD_WRT ;READ/WRITE PER R_WCOM JRNC :END ;IF GOOD ;RETRY IF ERROR :2: LDK HL,RTRY ;GET RETRYS DEC [HL] JRNZ :RLOOP ;LOOP IF MORE RETRYS :ERR: LDK A,1 ;INDICATE ERROR ORA A JR :3 ;EXIT :END: XRA A ;INDICATE GOOD ;SET "RTRY" AND REGISTER B :3: LD BC,NUMSEC ;BC = RESTORE BC RET PAGE SENDEN: ;DETERMINE THE DENSITY AND NUMBER OF SECTORS PER TRACK OF THIS DISK DRIVE ;ENTRY ;NONE ;EXIT ;B = NUMBER OF SECTORS ON ONE TRACK ;ZBIT = RESET IF ERROR ;SAVTYP IS SET WITH DENSITY AND SECTOR SIZE PROC *CHECK DENSITY ;HOME LOOP LDK A,NRETRY STO A,RTRY ;SET NUMBER OF RETRYS ;DENSITY LOOP(CHECK PRESENT DENSITY FIRST) :RL1: LDK B,2 ;CHECK BOTH DENSITYS :RL2: PUSH BC ;SAVE COUNT ;CHECK THIS DENSITY CALL SELDRV ;SELECT DRIVE CALL RADR ;READ ADDRESS POP BC ;RESTORE DENSITY RETRY JRNC :1 ;IF GOOD *IF DENSITY ERROR CHANGE DENSITY AND LOOP TO :RL2: LD A,SAVTYP ;PRESENT DENSITY XRI 0000_0001B ;CHANGE DENSITY BIT STO A,SAVTYP ;NEW DENSITY DJNZ :RL2 ;DENSITY LOOP *IF BOTH DENSITYS FAIL HOME DRIVE AND TRY AGAIN LDK HL,RTRY DEC [HL] JRZ :ERET ;END IF SECOND TIME THROUGH CALL HOME ;HOME DRIVE JRC :ERET ;END IF ERROR IN HOME JR :RL1 ;TRY AGAIN *SET "SAVTYP" :1: LD A,DSTSB+3 ;SECTOR LENGTH STATUS BYTE ANI 0000_0011B ;0-3 SLA A SLA A ;NOW IS 0000_XX00B WAS 0000_00XXB MOV B,A ;SAVE LD A,SAVTYP ANI 1111_0011B ;CLEAR BITS ORA B ;OR IN SECTOR LENGTH STO A,SAVTYP *READ ADDRESS AND SET NUMBER OF SECTORS AND RETURN LD A,DSTSB+2 ;SECTOR JUST READ MOV D,A ;RETRY LOOP LDK A,NRETRY :RL3: STO A,RTRY ;SET RETRYS ;READ HEADER LOOP :LOOP: PUSH DE ;SAVE LAST SECTOR ADDR CALL RADR ;READ ADDRESS POP DE JRC :ERR ;IF ERROR IN RADR ;CHECK FOR LAST HEADER LD A,DSTSB+2 MOV B,A ;B=PRESENT SECTOR MOV A,D ;A=LAST SECTOR SUB B ;LAST SECTOR - PRESENT SECTOR JRZ :LOOP ;IF THE LAST SECTOR = THE PRESENT SECTOR(THIS SHOULD HAPPEN ONLY ON ERROR RETRY) JRNC :2 ;IF THE VALUE IN A WAS THE LAST SECTOR OF THE TRACK MOV D,B ;D=LAST SECTOR READ JR :LOOP ;LOOP TILL YOU FIND THE LAST TRACK ;SET NUMBER OF SECTORS PER TRACK :2: INC A ;A=NUMBER OF SECTORS PER TRACK MOV B,A XRA A ;RESET FLAGS RET ;GOOD RETURN *IF NUMB. SEC. ERROR MAKE LAST SECTOR READ ZERO AND RETRY TO :LOOP1 :ERR: LDK D,0 LD A,RTRY DEC A JRNZ :RL3 ;RETRY :ERET: LDK A,1 ORA A ;FLAGS TO NONZERO RET ;ERROR RETURN PAGE HOME: ;HOME DISK DRIVE ;DRIVE IS ALREADY SELECTED AND READY ;If "SEKDEL" has the verify bit set this proc will check for seek and crc errors ;ENTRY ;SDISK = DRIVE ;EXIT ;CBIT = SET IF ERROR ;CHANGES ;SEKDEL PROC ;GIVE COMMAND LD A,SEKDEL ;GET SEEK DELAY ANI 0000_0111B ;SPEED & VERIFY BITS ONLY CALL FDSK ;FUNCTION DISK RC ;RETURN IF ERROR CALL WBUSY ;WAIT FOR BUSY TO DROP RC ;RETURN IF ERROR ;CHECK FOR TRACK 0 IN DSK_STS ;GET STATUS BIT 2,A ;TRACK 0 BIT JRZ :1 ;IF NOT ON TRACK ZERO ;CHECK FOR VERIFY LD A,SEKDEL ANI 0000_0100B ;VERIFY? RZ ;NO VERIFY GOOD RETURN IN DSK_STS ANI 0001_1000B ;TEST SEEK AND CRC RZ ;GOOD RETURN :1: STC ;IF ERROR RET PAGE SEEK: ;SEEK TO TRACK DEFINED BY SAVTRK ;TRACK REG UPDATED AND VERIFIED ;ENTRY ;SAVTRK = SET TO DESIRED TRACK ;EXIT ;CBIT = SET IF ERROR ;IF NO ERROR CONTROLLER TRACK = SAVTRK PROC ;CHECK IF ON TRACK LDK HL,SAVTRK IN DSK_TRK ;GET TRACK IT'S ON CMP [HL] RZ ;RETURN IF ON TRACK ;SET TRACK TO GO TO IN DATA REG MOV A,[HL] OUT DSK_DAT ;SET TRACK WANTED ;PERFORM COMMAND LDK B,D.SEK JR PSEKC ;PERFORM SEEK COMMAND PAGE STEP: ;STEP ONE TRACK ;SAVTRK IS NOT USED IN THIS PROC ;CONTROLLER TRK REG IS UPDATED ;ENTRY ;NONE ;EXIT ;CBIT = SET IF ERROR ;IF NO ERROR CONTROLLER TRACK = TRACK +/- 1 PROC LDK B,D.STP JR PSEKC ;PERFORM STEP COMMAND PAGE STEPIN: ;STEP IN ONE TRACK ;SAVTRK IS NOT USED IN THIS PROC ;CONTROLLER TRACK REG IS UPDATED ;ENTRY ;NONE ;EXIT ;CBIT = SET IF ERROR ;IF NO ERROR CONTROLLER TRACK = TRACK + 1 PROC LDK B,D.STPI JR PSEKC ;PERFORM STEP-IN COMMAND PAGE STEPOUT: ;STEP OUT ONE TRACK ;SAVTRK IS NOT USED IN THIS PROC ;CONTROLLER TRACK REG IS UPDATED ;ENTRY ;NONE ;EXIT ;CBIT = SET IF ERROR ;IF NO ERROR CONTROLLER TRACK = TRACK - 1 PROC LDK B,D.STPO JR PSEKC ;PERFORM STEP-OUT COMMAND PAGE PSEKC: ;OR IN SEKDEL AND PERFORM SEEK TYPE COMMAND ;ENTRY ;B = SEEK TYPE COMMAND ;EXIT ;CBIT = SET IF ERROR PROC LD A,SEKDEL ANI 0001_0111B ;ONLY UPDATE,VERIFY, & SPEED ORA B ;OR IN COMMAND CALL FDSK ;FUNCTION DISK RC ;RETURN IF ERROR CALL WBUSY ;WAIT FOR BUSY TO DROP RC ;RETURN IF ERROR ;HEAD SETTLE DELAY LDK A,40 CALL DELAY ;CHECK FOR ERRORS LD A,SEKDEL ANI 0000_0100B ;VERIFY? RZ ;NO VERIFY GOOD RETURN IN DSK_STS ;GET STATUS ANI 0001_1000B ;TEST SEEK AND CRC RZ ;GOOD RETURN STC ;IF ERROR RET PAGE READ: ;READ SECTOR/SECTORS ;ENTRY ;B = NUMB OF SECTORS TO READ ;EXIT ;HL = LAST DMA ADDRESS PLUS ONE IF GOOD TRANSFER ;CBIT = SET IF ERROR PROC LDK A,D.RDS STO A,R_WCOM ;SET READ COMMAND JR RD_WRT ;JMP AND RETURN TO CALLING PROC PAGE WRITE: ;WRITE SECTOR/SECTORS ;ENTRY ;B = NUMB OF SECTORS TO WRITE ;EXIT ;HL = LAST DMA ADDRESS PLUS ONE IF GOOD TRANSFER ;CBIT = SET IF ERROR PROC LDK A,D.WRTS STO A,R_WCOM ;SET WRITE COMMAND ;FALLS THROUGH TO RD_WRT PAGE RD_WRT: ;READ OR WRITE SECTOR/SECTORS ;ENTRY ;B = NUMB OF SECTORS TO READ OR WRITE ;R_WCOM = D.RDS OR D.WRTS ;EXIT ;HL = LAST DMA ADDRESS PLUS ONE IF GOOD TRANSFER ;CBIT = SET IF ERROR ;NOTE ;NO RETRYS ARE PERFORMED HERE PROC ;SET SECTOR REG LD A,SAVSEC OUT DSK_SEC PUSH BC ;SAVE NUMBER OF SECTORS TO R/W ;SET DE TO NUMBER OF BYTES IN ONE SECTOR LDK HL,128 LD A,SAVTYP ;DISK TYPE SRL A ;DUMP TWO BITS SRL A ANI 0000_0011B ;SIZE ONLY ORA A ;SET FLAGS JRZ :1 ;IF 128 MOV B,A :BLOOP: ADD HL,HL ;SHIFT LEFT ONE BIT DJNZ :BLOOP :1: EX DE,HL ;DE=NUMBER OF BYTES IN ONE SECTOR POP BC ;RESTORE PUSH BC ;SAVE NUMBER OF SECTORS TO R/W ;GET COMMAND AND CHECK FOR MULTI-SECTOR MOV A,B ;GET NUMBER OF SECTORS LDK C,0 ;MAKE NONMULTI-SECTOR CMP 2 JRC :2 ;IF LESS THAN TWO SECTORS LDK C,10H ;MAKE MULTI-SECTOR :2: LD A,R_WCOM ;GET D.RDS OR D.WRTS OR C ;MAKE MULTI-SECTOR OR NONMULTI-SECTOR ;SET HL TO NUMBER OF BYTES TO TRANSFER LDK HL,0 :LOOP1: ADD HL,DE DJNZ :LOOP1 PUSH HL ;SAVE LENGTH ;GIVE COMMAND DI ;DISABLE INTERRUPTS CALL FDSK JNC :3 ;IF GOOD ;IF ABORT BEFORE DMA POP DE ;RESTORE STACK POP DE EI RET ;RETURN IF ERROR IN FDSK ;SET RETURN FROM DMA, DMA ADDR AND NUMBER OF BYTES TO TRANSFER :3: POP BC ;RESTORE LENGTH LD HL,DMADR ;HL = DMA ADDRESS LDK DE,:RET PUSH DE ;FOR RETURN ;DO DMA LD A,R_WCOM ;(13) GET COMMAND CMP D.RDS ;(7) JZ DMARD ;(10) READ DMA RETURNS TO :RET JMP DMAWRT ;(10) WRITE DMA RETURNS TO :RET ;RETURN FROM DMA AND CHECK FOR BUSY AND RESET :RET: POP BC ;RESTORE NUMBER OF SECTORS ;CHECK FOR BUSY IN DSK_STS ;GET STATUS BIT 0,A JRZ :4 ;IF NOT BUSY ;IF BUSY CHECK FOR # OF SECTORS READ ;IF 1 SECTOR ONLY THEN CALL WBUSY ;IF > 1 SECTORS THEN CALL FORINT LDK DE,:RET1 PUSH DE ;FOR RETURN DEC B ;SUBTRACT ONE FROM THE NUMBER OF SECTORS AND SET THE ZERO FLAG JZ WBUSY ;IF NON MULTI-SECTOR R/W WAIT FOR BUSY TO DROP JMP FORINT ;CLEAR BUSY :RET1: IN DSK_STS ;RETURN AND GET STATUS ;CHECK FOR ERRORS :4: ANI 0101_1100B ;TEST write protect, rnf, crc, and lost data JRZ :5 ;IF GOOD STC ;IF ERROR RECORD CONTROLLER REGISTERS :5: EI RET PAGE RADR: ;Read Address info. ;READS SIX BYTES INTO "DSTSB" ;ENTRY ;NONE ;EXIT ;A = 0FFH IF TIME OUT ERROR ;CBIT = SET IF ERROR ;DSK_TRK = HEAD POSITION *NOTE* ;SETS TRACK REG IN CONTROLLER IF GOOD PROC LDK A,D.RDA DI CALL FDSK ;function disk JRC :1 ;WAIT FOR FIRST DRQ OR TIME OUT ;SET REGISTERS FOR DMA TRANSFER LDK BC,5 ;SIX BYTES TO READ LDK HL,DSTSB ;FBA FOR DMA ;WAIT FOR 1/4 OF A TRACK(60MS) OR DRQ LDK DE,DRQTIMEOUT :LOOP: IN DSK_STS ; GET STATUS RAR ;(4) RAR ;(4) JC :3 ;(10) GOT DRQ DEC DE ;(6) MOV A,D ;(4) ORA E ;(4) JNZ :LOOP ;(10) ;INDICATE TIME OUT ERROR CALL FORINT ;CLEAR BUSY ORI 0FFH ;A=0FFH JR :2 ;INDICATE A TIME OUT ERROR ;TRANSFER FIRST BYTE AND CALL DMARD FOR LAST FIVE BYTES  :3: IN DSK_DAT ; GET BYTE STO A,[HL] ;(7) STORE BYTE INC HL ;(6) ;BC = 5 CALL DMARD ;(17) CALL DMARD ;RETURN FROM DMARD AND WAIT FOR BUSY TO BE RESET CALL WBUSY JRC :1 ;IF TIME OUT ERROR IN DSK_STS ;GET STATUS ;CHECK FOR ERRORS ANI 0001_1100B ;TEST RNF, CRC AND DATA LOST JRNZ :2 ;IF ERROR ;SET TRACK REGISTER IN DSK_SEC ;GET TRACK OUT DSK_TRK ;SET TRACK XRA A ;RESET CARRY JR :1 :2: STC ;SET CBIT :1: EI RET PAGE READTRK: ;READ ONE TRACK FROM THE DRIVE ;ENTRY ;DMADR = FWA OF BUFFER ;EXIT ;CBIT = SET IF ERROR PROC LDK A,D.RDT DI CALL FDSK JRC :1 ;IF ERROR ;DO DMA LDK BC,0FFFFH ;READ TILL BUSY DROPS LD HL,DMADR CALL DMARD ;DMA READ XRA A ;CLEAR ERROR :1: EI RET PAGE FMTTRK: ;FORMAT ONE TRACK ;ENTRY ;BC = LENGTH ;DMADR = FWA OF BUFFER ;EXIT ;CBIT = SET IF ERROR PROC ;TEST DENSITY AND SET REG D TO 04EH OR 0FFH LD A,SAVTYP LDK D,04EH ;DOUBLE DENSITY FORMAT CHARACTER RRC A JRNC :1 ;IF DOUBLE LDK D,0FFH ;SINGLE DENSITY FORMAT CHARACTER ;GIVE COMMAND :1: LDK A,D.WRTT ;WRITE TRACK COMMAND DI PUSH DE ;SAVE FILL BYTE PUSH BC ;SAVE LENGTH CALL FDSK ;GIVE COMMAND POP BC ;LENGTH POP DE ;FILL BYTE JRC :3 ;IF ERROR ;DO DMA LD HL,DMADR CALL DMAWRT ;DMA WRITE (SAVE D REG) ;PAD REST OF TRACK :LOOP: IN DSK_STS ;GET STATUS RAR ;CHECK FOR BUSY JRNC :2 ;FINISHED IF NO BUSY RAR ;CHECK FOR DRQ JRNC :LOOP ;IF NO DRQ MOV A,D ;CHARACTER TO A OUT DSK_DAT ;STORE BYTE JR :LOOP ;CHECK FOR ERROR :2: ANI 0010_0010B ;TEST write protect, and data lost (SHIFTED LEFT) JRZ :4 ;IF GOOD :3: STC :4: EI RET PAGE FORINT: ;INTERRUPT DISK CONTROLLER ;ENTRY ;NONE ;EXIT ;BUSY CLEARED. PROC PUSH AF PUSH BC LDK A,D.FINT OUT DSK_CMD ;WAIT FOR AT LEAST 28 MICROSECONDS ORA A ;(4) LDK B,7 ;(7) :WLOOP: DJNZ :WLOOP ;(91) = (13*7) WAIT ;CHECK FOR BUSY DROP CALL WBUSY POP BC POP AF RET PAGE FDSK: ;FUNCTION DISK ROUTINE ;THIS IS THE ONLY ROUTINE THAT WRITES TO THE COMMAND REGISTER OF THE CONTROLLER CHIP ;THIS ROUTINE HAS A BUILT IN DELAY OF AT LEAST 28 MICRO SEC. BEFORE READING THE STATUS ON THE CHIP ;ENTRY ;A = FUNCTION CODE ;EXIT ;A = 0FFH IS TIME OUT ERROR ;CBIT = SET IF ERROR PROC MOV B,A ;SAVE FUNCTION CODE IN B ;CHECK FOR BUSY IN DSK_STS ;READ STATUS REGISTER ANI 01 MOV A,B JRZ :1 ;IF NOT BUSY ;RESET BUSY CALL FORINT ;RESET BUSY :1: OUT DSK_CMD ;FUNCTION DRIVE(WRITE COMMAND TO CONTROLLER) ;WAIT FOR 56 SINGLE AND 28 DOUBLE LD A,SAVTYP ;(13) DISK TYPE LDK B,5 ;(7) RRC A ;(4) JNC :WLOOP ;(10) IF DOUBLE DENSITY XRA A ;(4) RESET CARRY FLAG LDK B,13 ;(7) :WLOOP: DJNZ :WLOOP ;(13) WAIT ;WAIT FOR BUSY TO BE SET LDK A,0FFH ;(7) MOV B,A ;(4) 256 LOOPS :LOOP: IN DSK_STS ;TEST BUSY BIT ANI 1 JRNZ :3 ;IF CHIP WENT BUSY DJNZ :LOOP ;IF NOT TIME-OUT ORI 0FFH ;INDICATE TIME STC ;IF ERROR A=FF AND CBIT = SET RET ;SET DRIVE ACTIVE :3: ORI 0FFH STO A,DACTVE ;SET DRIVE ACTIVE COUNTER XRA A ;INDICATE NO ERROR RET PAGE SELDRV: ;SELECT DRIVE ;ENTRY ;SDISK = DRIVE TO SELECT ;EXIT ;ZBIT = SET IF DRIVE WAS SELECTED ;ZBIT = RESET IF DRIVE WASN'T SELECTED *;CBIT = SET IF THERE ARE NO INDEX PULSES PROC DI ;SELECT PORT IN 8155 AND READ BYTE LDK A,3 OUT SYSRS ;SELECT PORT 3 IN SYSRW ;READ PORT ANI 1111_1011B ;CLEAR DENSITY BIT MOV B,A ;SAVE VALUE ;SET DENSITY (SINGLE/DOUBLE) LD A,SAVTYP ;GET TYPE (BIT 0 = DENSITY) RLC ;DENSITY=BIT 1 RLC ;DENSITY=BIT 2 ANI 0000_0100B ;CLEAR ALL BITS BUT DENSITY ORA B ;OR IN VALUE MOV B,A ;SAVE VALUE ;GET DRIVE LD A,SDISK ;GET DRIVE TO SELECT LDK HL,DSKSWP ;DISK DRIVE SWAP CELL XOR [HL] ;SWAP A FOR B IF DSKSWP=1 BIT 0,A ;SET FLAGS MOV A,B ;PORT VALUE IN A JRZ :1 ;IF DRIVE A ;SELECT DRIVE B BIT 1,A ;TEST BIT 1 JRZ :3 ;END IF DRIVE IS SELECTED ORI 0000_0011B ;DISABLE DRIVES ANI 1111_1101B ;SET DRIVE B JR :2 ;ACTIVATE DRIVE ;SELECT DRIVE A :1: BIT 0,A ;TEST BIT 0 JRZ :3 ;END IF DRIVE IS SELECTED ORI 0000_0011B ;DISABLE DRIVES ANI 1111_1110B ;SET DRIVE B ;ACTIVATE DRIVE :2: OUT SYSRW ;ACTIVATE DRIVE ;DELAY LDK A,250 CALL DELAY ;WAIT FOR MOTOR SPIN UP LDK A,250 CALL DELAY ;2ND DELAY LDK A,250 CALL DELAY ;3RD DELAY ORI 0FFH ;INDICATE DRIVE NOT SELECTED ;INDICATE DRIVE IS ACTIVATED :3: JRNZ :4 ;IF 0 SKIP OUT OUT SYSRW ;OUTPUT DENSITY TO PORT :4: LDK A,0FFH STO A,DACTVE EI RET PAGE WBUSY: ;WAIT FOR BUSY TO CLEAR ;This routine must wait for 2 seconds ;2 seconds is the time it takes for the chip to seek 39 tracks and have five index holes go by. ;ENTRY ;NONE ;EXIT ;A = 0FFH IF TIME OUT OCCURRED ;CBIT = SET " " " " PROC LDK BC,0 :LOOP: IN DSK_STS ;(10) BIT 0,A ;(8) DS.BSY JRZ :1 ;(7) GOOD RETURN EX [SP],HL ;(23) DELAY EX [SP],HL ;(23) DELAY EX [SP],HL ;(23) DELAY EX [SP],HL ;(23) DELAY DEC BC ;(6) MOV A,B ;(4) OR C ;(4) JRNZ :LOOP ;(12) IF NOT TIME-OUT LDK A,0FFH ;TIME OUT ERROR STC ;SET ERROR :1: RET PAGE DMARD: ;TRANSFER DATA FROM CONTROLLER TO MEMORY ;ENTRY ;BC = BYTES TO TRANSFER ;HL = FWA OF BUFFER ;EXIT ;HL = NEXT ADDRESS ;DE = DSK_STS PROC :LOOP: IN DSK_STS ;(10) GET STATUS RAR ;(4) RNC ;(5) RETURN IF NO BUSY RAR ;(4) JNC :LOOP ;(10) IF NO DRQ IN DSK_DAT ;(10) GET BYTE STO A,[HL] ;(7) STORE BYTE INC HL ;(6) DEC BC ;(6) MOV A,B ;(4) ORA C ;(4) JNZ :LOOP ;(10) RET PAGE DMAWRT: ;Xfer data from memory to disk ;ENTRY ;BC = BYTES TO TRANSFER ;HL = FWA OF BUFFER ;EXIT ;HL = NEXT ADDRESS PROC :LOOP: IN DSK_STS ;GET STATUS RAR RNC ;RETURN IF NO BUSY RAR JNC :LOOP ;IF NO DRQ LD A,[HL] ;GET BYTE OUT DSK_DAT ;STORE BYTE INC HL DEC BC MOV A,B ORA C JNZ :LOOP RET PAGE DELAY: ;'N' Milliseconds ;ENTRY ;A = Number of Milliseconds to delay ;SCLFRE = (Freq/1000)/25 ;EXIT ;NONE ;USES ;D & A PROC MOV D,A :1: LDK A,SCLFRE :MLOOP: DEC A ;(4 tics) MOV B,B ;(4 tics) MOV C,C ;(4 tics) JRNZ :MLOOP ;(10 tics) If 1 ms not elapsed DEC D JRNZ :1 ;If requested msec not done RET PAGE *[10] PODIAG: ;POWER ON DIAGNOSTICS ; CHECK FOR POWER-ON OR JUST RESET. ASSUME THAT LOGIC BOARD 8155 MEMORY LOCATION IS NOT = 1 AT POWER-ON. ; IF = 1, THEN DON'T RUN POWER-ON DIAGNOSTIC AND OTHERWISE, RUN IT. ;NOTE ;THE MEMORY LOCATION SEMEMS TO BE 0 AFTER POWER UP LDK SP,ROMSTK ;SET STACK CALL INITHARD ;INITIALIZE HARDWARE XRA A ;ACCUMU = MEMORY LOCATION ZERO OUT SYSMS IN SYSRW ;READ 8155 MEMORY LOCATION ZERO DEC A ;TEST CONTENTS FOR VALUE = 1 JZ VSTART ;IF CONTENTS = 1, THEN DON'T RUN SELF TEST ;SET MEMORY TO ZERO AND START TEST LDK A,1 OUT SYSRW ;SET 8155 MEMORY LOCATION ZERO = 1 ;FALL TROUGH TO POSTART PAGE POSTART: ;START OF SELF TEST ; TEST #1: ENCORE RAM MARCH TEST ;NOTE ;THIS TEST MUST NOT USE THE STACK ;NOTE ;INTERUPTS MUST BE DISABLED ; TEST FILLS RAM FROM 0 TO EFFFH WITH PATTERN 55H. RAM IS READ BACK ; BYTE BY BYTE AND REPLACED WITH PATTERN 0AAH, WHICH IS ALSO READ BACK ; BYTE BY BYTE. ; REGISTER USAGE ; A -- TEMPORARY REGISTER ; B -- VALUE READ (POTENTIALLY BAD) FROM BYTE UNDER TEST ; HL -- POINTER TO RAM LOCATION BEING READ OR WRITTEN PROC DI LDK DE,ERAMSG ;PRINT SIGN-ON CALL OSTR LDK A,0F0H ;HIGH BYTE OF FIRST ADDRESS NOT TO BE TESTED LDK HL,0 ;INITIALIZE HL TO ADDRESS OF FIRST BYTE OF RAM TO BE TESTED ; FILL ENCORE RAM WITH VALUE 55H :RLOOP: STO 55H,[HL] ;PUT BACKGROUND PATTERN INTO BYTE UNDER TEST INC HL ;POINT TO NEXT LOCATION TO BE FILLED CMP H ;NO MORE BYTES TO BE FILLED? JRNZ :RLOOP ;IF MORE, THEN LOOP TO CONTINUE RAM FILLING ; CHECK EACH BYTE OF ENCORE RAM FOR 55H. IF OK, THEN WRITE WITH AAH LDK H,0 ;REINITIALIZE HL TO ADDRESS OF FIRST BYTE OF RAM FILLED WITH ; BACKGROUND PATTERN :MLOOP: LDK A,55H ;COMPARE MEMORY LOCATION WITH CMP M ;DID IT CONTAIN COMPLEMENT PATTERN? JNZ FAIL ;IF NOT THE SAME, THEN TEST FAILS CMA ;WRITE COMPLEMENT BACKGROUND PATTERN MOV M,A ; INTO LOCATION UNDER TEST CMP M ;DID IT CONTAIN COMPLEMENT PATTERN? JNZ FAIL ;IF NOT THE SAME, THEN TEST FAILS INC HL ;POINT TO NEXT LOCATION TO BE TESTED MOV A,H ;CHECK FOR TEST COMPLETION CMP 0F0H ;NO MORE MEMORY TO TEST? JRNZ :MLOOP ;IF MORE, THEN JUMP ;FALL THROUGH TO NEXT TEST PAGE ; TEST #2: ENCORE RAM ADDRESS RIPPLE TEST ;NOTE ;THIS TEST MUST NOT USE THE STACK ; A WALKING ONES ADDRESS RIPPLE TEST IS PERFORMED ON ENCORE RAM. THE TEST ; WRITES THE ADDRESS RIPPLE PATTERN TO THE BYTE UNDER TEST. UPON ; FILLING ALL OF THE SIXTEEN RIPPLE ADDRESSES, EACH IS READ BACK ; AND CONTENTS COMPARED VERSUS EXPECTED. ; WALKING ONES RIPPLE EXAMPLE ; BINARY HEXADECIMAL ; 0000000000000001B 0001H ; 0000000000000010B 0002H ; 0000000000000100B 0003H ; . . ; . . ; . . ; 1000000000000000B 0010H ; REGISTER USAGE ; C -- RIPPLE VALUE BEING WRITTEN TO RAM BYTE ; A -- BYTE VALUE READ BACK (POTENTIALLY BAD) FROM BYTE UNDER TEST ; HL -- POINTER TO BYTE BEING WRITTEN OR READ PROC LDK HL, ;POIN T FIRS BYTE UNDE TEST MOV C,L ;INITIALIZE C TO FIRST PATTERN TO USE ; FILL RIPPLE ADDRESS WITH RIPPLE PATTERN :RLOOP: MOV M,C ;WRITE BYTE OF LOCATION UNDER TEST WITH RIPPLE PATTERN SLA H ;COMPUTE HIGH BYTE OF NEXT RIPPLE ADDRESS JRC :2 ;IF NO MORE PATTERNS, THEN JUMP SLA L ;COMPUTE LOWER BYTE OF NEXT RIPPLE ADDRESS JRNC :1 ;IF NO NEED TO ALTER HIGH BYTE, THEN JUMP INC H ;ELSE, SHIFT AFFECTS HIGH BYTE :1: INC C ;SET UP NEXT PATTERN TO WRITE JR :RLOOP  ;CONTINUE RIPPLE WRITE ; READ BACK EACH WORD WRITTEN WITH RIPPLE PATTERN AND COMPARE VERSUS EXPECTED :2: LDK HL,1 ;POINT TO FIRST WORD TESTED MOV A,L ;INITIALIZE WITH FIRST PATTERN TO USE :3: CMP M ;COMPARE WITH EXPECTED PATTERN JNZ FAIL ;IF NOT THE SAME, THE TEST FAILS SLA H ;COMPUTE NEXT HIGH BYTE OF RIPPLE ADDRESS JRC CHKSUM ;IF NO MORE ADDRESSES, THEN JUMP TO NEXT TEST SLA L ;COMPUTE LOWER BYTE OF NEXT RIPPLE ADDRESS JRNC :4 ;IF NO NEED TO ALTER HIGH BYTE, THEN JUMP INC H ;ELSE, SHIFT AFFECTS HIGH BYTE :4: INC A ;SET UP NEXT PATTERN TO READ JR :3 ;CONTINUE RIPPLE COMPARE PAGE CHKSUM: ; TEST #3: ENCORE FIRMWARE 24-BIT CHECKSUM TEST ; REGISTER USAGE ; A -- HIGH BYTE OF CALCULATED 24-BIT CHECKSUM ; BC -- WORD OF ROM READ IN ; DE -- MIDDLE AND LOW BYTE OF CALCULATED 24-BIT CHECKSUM ; HL -- POINTER TO RAM LOCATION BEING READ OR WRITTEN PROC XRA A ;INITIALIZE UPPER BYTE OF CHECKSUM MOV D,A ;INITIALIZE MIDDLE AND LOWER BYTE OF CHECKSUM MOV E,A MOV C,A ;INITIALIZE TEMPORARY STORAGE LDK HL,0F000H ;POINT TO FIRST FIRMWARE WORD TO BE USED AS PART OF CHECKSUM :LOOP: MOV A,C ;RESTORE LOW BYTE OF CHECKSUM ; CALCULATE CHECKSUM ADD M ;RETRIEVE NEXT WORD OF FIRMWARE JRNC :1 ;IF NO OVERFLOW, THEN JUMP INC E ;ELSE, INCREMENT MIDDLE BYTE OF CHECKSUM JRNZ :1 ;IF NO OVERFLOW, THEN JUMP INC D ;ELSE, INCREMENT HIGH BYTE OF CHECKSUM ; DETERMINE IF END OF FIRMWARE REACHED. DON'T PERFORM CHECKSUM ON CHECKSUM! :1: INC HL ;POINT TO NEXT BYTE OF FIRMWARE MOV C,A ;SAVE LOWER BYTE OF CHECKSUM TEMPORARILY MOV A,H ;CHECK FIRMWARE POINTER ; CHECK FOR CHECKSUMMING ADDRESS FFXXH INC A ;TESTING LAST PARAGRAPH (I.E., 16 BYTES) OF FIRMWARE JNZ :LOOP ;IF NOT, THEN CONTINUE CHECKSUMMING MOV A,L ;OTHERWISE, CHECK LOWER BYTE OF FIRMWARE POINTER CMP 0FDH ;POINTING TO FIRST BYTE OF CHECKSUM? JNZ :LOOP ;IF NOT, THEN CONTINUE CHECKSUMMING ; CHECKSUMMING OPERATION COMPLETE. COMPARE WITH VALUE AT FFFDH IN FIRMWARE. MSG 'VALUE TO SET BREAK POINT FOR CHECKSUM IS : ',* MOV B,M ;RETRIEVE UPPER BYTE OF CHECKSUM FROM FIRMWARE INC HL ;POINT TO NEXT BYTE OF FIRMWARE MOV A,M ; " MIDDLE BYTE INC HL ;POINT TO NEXT BYTE OF FIRMWARE MOV L,M ; " LOWER BYTE MOV H,A ;JUGGLE MIDDLE BYTE AROUND ; REGISTER CONFIGURATION ;D,E,C = CALCULATED ;B,H,L = VALUE READ FROM FIRMWARE MOV A,B ;GET HIGH BYTE OF CHECKSUM READ FROM FIRMWARE CMP D ;TEST HIGH AGAINST CALCULATED JRNZ FAIL ;JUMP IF BAD HIGH BYTE CHECKSUM MOV A,H ;TEST MIDDLE BYTE CMP E JRNZ FAIL ;JUMP IF BAD MIDDLE BYTE CHECKSUM MOV A,L ;TEST LOWER BYTE CMP C JRNZ FAIL ;JUMP IF BAD LOWER BYTE CHECKSUM ;FALL THROUGH TO NEXT TEST PAGE ; TEST #4: ENCORE 50/60 HZ INTERRUPT TEST ; ENABLE AND DISABLE INTERRUPT AND POLL FOR ITS STATUS. ; CHECK FOR PROPER ENABLE OF INTERRUPT AND STATUS CHECK PROC ; CLEAR PREVIOUS INTERRUPT STATUS BY DISABLE AND ENABLE OF INTERRUPT XRA A ;DISABLE INTERRUPT OUT INTPORT INC A ;ENABLE INTERRUPT WITH WRITE OF 1 OUT INTPORT ; POLL FOR INTERRUPT OCCURRED (INTERRUPT ENABLED) CALL W17MSEC ;WAIT FOR INTERRUPT TO OCCUR JRZ FAIL ;DID IT OCCUR? IF NOT, THEN TEST FAILED XRA A ;DISABLE INTERRUPT OUT INTPORT INC A ;ENABLE INTERRUPT OUT INTPORT XRA A ;DISABLE INTERRUPT OUT INTPORT ; POLL FOR INTERRUPT NOT PRESENT (INTERRUPT DISABLED) CALL W17MSEC ;WAIT FOR INTERRUPT TO OCCUR JRNZ FAIL ;IF IT OCCURRED, THEN TEST FAILS ;FALL THROUGH TO NEXT TEST PAGE ; TEST #5: 8155 PORT B ; TEST 8155 PORT B BY WRITING VALUES 5AH AND A5H TO IT AND READING IT BACK. ; LOGIC BOARD 8155 I/O PORTS ARE STRUCTURED AS FOLLOWS: ; I/O PORT D REGISTER ADDRESS REGISTER ; " 8 DATA REGISTER ; " C MEMORY ADDRESS REGISTER ; 8155 REGISTER ADDRESSES ARE AS FOLLOWS: ; 0 COMMAND REGISTER ; 1 PORT A ; 2 PORT B ; 3 PORT C ;NOTE ;THERE MUST NOTE BE AN INTERUPTE DURING THIS TEST PROC ;SET PORT LDK A,2 ;8155 PORT B OUT SYSRS ;LATCH IN 8155 PORT ADDRESS ;TEST WITH A5H LDK A,0A5H OUT SYSRW ;WRITE VALUE MOV D,A IN SYSRW ;READ VALUE CMP D ;COMPARE VERSUS ORIGINAL VALUE JRNZ FAIL ;IF BAD, JUMP TO "FAIL" ;TEST WITH 5AH LDK A,5AH OUT SYSRW ;WRITE VALUE MOV D,A IN SYSRW ;READ VALUE CMP D ;COMPARE VERSUS ORIGINAL VALUE JRNZ FAIL ;IF BAD, JUMP TO "FAIL" ;FALL THROUGH TO NEXT TEST PAGE ; TEST #6: FLOPPY DISK CONTROLLER REGISTER WRITE/READ ;NOTE ;THIS TEST SHOULD BE DONE WITH THE CONTROLER IN DD ; PERFORM WRITE AND READBACK OF THESE 1793 FLOPPY DISK CONTROLLER REGISTERS: ; TRACK REGISTER I/O PORT 1 ; SECTOR REGISTER 2 ; DATA REGISTER 3 ; ROUTINE WRITES PATTERN 5AH INTO ONE REGISTER, READS IT BACK, WRITES PATTERN ; A5H INTO IT AND READ IT BACK. TEST TERMINATES IF VALUE READ BACK IS NOT ; THE VALUE WRITTEN. THIS IS PERFORMED FOR EACH OF THE ABOVE REGISTERS. ; NOTE THAT THE DISK CONTROLLER STATUS REGISTER (I/O PORT 0) MUST BE NOT BUSY ; (BIT 0 = 0) BEFORE ANY REGISTER WRITES CAN BE PERFORMED. IF BUSY IS TRUE, ; THEN A FORCE INTERRUPT COMMAND IS ISSUED TO THE FDC TO FORCE BUSY TO BE ; FALSE. PROC CALL FORINT ;ALLWAYS KILL BUSY ; LOAD ALL WRITABLE FDC REGISTERS WITH INITIAL VALUES :1: LDK A,5AH ;INITIALIZE PATTERN OUT DSK_TRK INC A OUT DSK_SEC INC A OUT DSK_DAT LDK C,DSK_TRK ;POINT TO FIRST FDC WRITE/READ REGISTER LDK B,3 ;THREE REGISTERS BEING CHECKED LDK H,5AH ;PUT INITIAL PATTERN ;NOTE : A LITTLE TIME MUST PASS AFTER WRITING A REGESTER BEFORE YOU READ IT BACK (8 MICRO SEC IN DD) ;A = TEMPORARY REGISTER HOLDS VALUE READ BACK ;C = POINTER TO FDC PORT UNDER TEST ;H = VALUE WRITTEN TO PORT ;L = TEMP HOLDER :2: LDK A,1 CALL DELAY IN,C A ;READ FROM PORT CMP H ;COMPARE JRNZ FAIL ;EXIT IF NOT THE SAME CMA ;COMPLEMENT PATTERN MOV L,A OT,C L ;WRITE TO PORT LDK A,1 CALL DELAY IN,C A ;READ FROM PORT CMP L ;COMPARE JRNZ FAIL ;EXIT IF NOT THE SAME ;LOOP TILL ALL REGESTERS INC H ;CALCULATE NEXT TEST PATTERN INC C ;POINT TO NEXT PORT UNDER TEST DJNZ :2 ;CONTINUE TESTING REGISTERS ;SELF TEST PASSED. REINITIALIZE HARDWARE CALL INITHARD ;INITIALIZE HARDWARE XRA A ;ACCUMU = MEMORY LOCATION ZERO OUT SYSMS IN SYSRW ;READ 8155 MEMORY LOCATION ZERO CMP 2 ;WAS VALUE IN THERE = 2? JZ POSTART ;THEN WE ARE LOOPING ON SELF-TEST ;RING BELL, AND START MONITOR LDK C,CBELL CALL COUT ;RING THE BELL JMP VSTART ;START THE MONITOR PAGE FAIL: ;SELF TEST FAILED. DISPLAY FAILURE MESSAGE, NO BELL, AND HANG PROC CALL INITHARD ;REINITIALIZE ENCORE LDK DE,FAILMSG ;PRINT "ENCORE NOT WORKING" MESSAGE CALL OSTR :LOOP: JR :LOOP ;WAIT HERE FOREVER PAGE W17MSEC: ; UTILITY PROCEDURE WAITS FOR A LITTLE OVER 1/60TH OF SECOND OR UNTIL THE ; KEYBOARD INTERRUPT STATUS BIT BECOMES TRUE. ROUTINE RETURNS WITH ZERO ; BIT NOT SET IF INTERRUPT OCCURS AND ZERO BIT SET OTHERWISE. ;EXIT ;ZBIT = RESET = INTERUPT OCCURRED ;ZBIT = SET = INTERUPT DIDN'T OCCURRE PROC ;17 MSEC LDK BC,1360 ;COUNT :LOOP: IN INTPORT ;11 GE INTERRUPT STATUS BIT 2,A ;8 CHECK BIT 2 RNZ ;5 IF IT OCCURRED, THEN EXIT ROUTINE DEC BC ;6 MOV A,B ;4 ORA C ;4 JRNZ :LOOP ;12 IF NOT OVER, THEN LOOP RET PAGE FAILMSG DB VCLRS ;CLEAR SCREEN DB ESC,'=',10+32,28+32 DB 'COMPUTER NEEDS CHECKING' DB ESC,'=',11+32,24+32 DB 'PLEASE CONTACT AN OSBORNE DEALE' DC 'R' ERAMSG: DB VCLRS ;CLEAR SCREEN DB ESC,'=',10+32,29+32 DB 'PERFORMING SELF-TES' DC 'T' NG" MESSAGE CALL OSTR :LOOP: JR :LOOP ;WAIT HERE FOREVER PAGE W17MSEC: ; UTILITY PROCEDURE WAITS FOR A LITTLE OVER 1/60TH OF SECOND OR UNTIL THE ; KEYBOARD INTERRUPT STATUS BIT BECOMES TRUE. ROUTINE RETURNS WITH ZERO ; BIT NOT SET IF INTERRU ; LOOP UNTIL BYTE IS AVAILABLE ;CHECK FOR DRIVE TURN AROUND IN STAT ANI DIFAC ; LOOK AT DRIVE ACTIVE BIT JNZ :1 ; JMP IF LINE TURNED AROUND ;READ BYTE IN INDATA ; READ BYTE FROM CONTROLLER STO A,[DE] ; SAVE IT IN MEMORY ; TOGGLE STROBE LDK A,STROB OUT 28H ;ON STROBE LDK A,0FFH OUT 28H ;OFF STROBE ;INCREMENT POINTER INC DE JMP :LOOP ;LOOP ;END :1: RET PAGE CWRITE: ;CORVUS WRITE ROUTINE ;AFTER WRITE WAITS FOR TURN AROUND ;ENTRY ;INTERRUPTS SHOULD BE DISABLED ;BC = NUMBER OF BYTES ;DE = FBA OF BUFFER ;EXIT ;NONE PROC ;SETUP 8155 ;COMMAND PORT XRA A OUT 21H ;SELECT COMMAND REGISTER LDK A,0000_1111B ;ALL PORTS TO OUTPUT OUT 28H ;C PORT LDK A,3 OUT 21H ;SELECT LDK A,1111_1111B ;ALL FLOTING OUT 28H ;B PORT LDK A,2 OUT 21H ;SELECT LDK A,1111_1111B ;ALL FLOTING OUT 28H ;A PORT LDK A,1 OUT 21H ;SELECT LDK A,1111_1111B ;ALL FLOTING OUT 28H ;TRANSFER LOOP :1: IN STAT ; GET DRIVE STATUS ANI DRDY ; LOOK AT READY BIT JZ :1 ; LOOP UNTIL BYTE IS AVAILABLE LD A,[DE] ; GET BYTE FROM MEMORY OUT 28H ; SEND IT TO CONTROLLER ; TOGGLE STROBE ;SELECT PORT B LDK A,2 OUT 21H ;STROBE LDK A,STROB OUT 28H ;ON STROBE LDK A,0FFH OUT 28H ;OFF STROBE ;RESELECT PORT A FOR DATA TRANSMITION LDK A,1 OUT 21H ;INCREMENT POINTER AND DEC COUNT INC DE DEC BC MOV A,B ORA C JNZ :1 ; COUNT DOWN BYTES LOOP UNTIL DONE ;WAIT FOR DRIVE TURN AROUND :2: IN STAT ; READ STATUS BYTE ANI DIFAC ; LOOK AT DRIVE ACTIVE BIT JNZ :2 ; LOOP ;DELAY AFTER TURN LDK B,4 :4: DJNZ :4 RET ; RETURN GOOD PAGE START: = * RD5CMD: = 100H ;READ 512 BYTES COMMAND ;4 BYTES DB 50 DB 3 ;DRIVE # DW 0 ;SECTOR # PIPEBUF = RD5CMD + 4 ;BUFFER ;IF NOT CORVUS ELSE JMP VSTART ;RESTART VIXEN ECHO 255 DB 0FFH ;FILL ENDM ENDIF ;END OF CORVUS CODE RLWA = * ;LWA OF ROM RESIDENT CODE MSG 'LENGTH OF THIS ROM IS = ',RLWA IF RLWA > 0FFFCH .9 ERROR CODE TOO LARGE.. ENDIF :ROML: = 0FFFH - * + 1 ;LENGTH OF SPACE LEFT OVER ECHO :ROML DB 0FFH ;FILL ENDM MSG * ; END STROBE LDK A,STROB OUT 28H ;ON STROBE LDK A,0FFH OUT 28H ;OFF STROBE ;RESELECT PORT A FOR DATA TRANSMITION LDK A,1 OUT 21H ;INCREMENT POINTER AND DEC COUNT INC DE DEC BC MOV A,B ORA C JNZ :1 ; COUNT DOWN BYTES LOOP UNTIL DONE ;WAIT FOR DRIVE TURN AROUND :2: IN STAT ; READ STATUS BYTE ANI DIFAC ; LOOK AT DRIVE ACTIVE BIT JNZ :2 ; LOOP ;DELAY AFTER TURN LDK B,4 :4: DJNZ :4 RET ; RETURN GOOD PAGE START: = * RD5CMD: = 100H ;READ 512 BYTES COMMAND ;4 BYTES DB 50 DB 3 ;DRIVE # DW 0 ;SECTOR # PIPEBUF = RD5CMD + 4 ;BUFFER ;IF NOT CORVUS ELSE JMP VSTART ;RESTART VIXEN ECHO 255 DB 0FFH ;FILL ENDM ENDIF ;END OF CORVUS CODE RLWA !p+q* !q*& *M *M !p+q*!!p+q*"!p+q*$!6  !kp+q*j> >ڪ Þ !qp+q/ *pDM9: :M2r:N!r !:r *r& N!r4 !6:͔: :ͳ.!ws+p+q+p+q:w=2wN *s*u w*s#"s*u#"u' !"*M^7 !x6:!xھ **DM͆ 2yʭ :yʗ ͯ *"*6:2x÷ *"!x4d !"/ !j}=2| !"*KM^'_ !z6:|!z1 * "}*}DM͆ ' ͯ *"!z4 :e !"͆ !z6:|!z '? 2*H#"H!{6:{ր!Ң *{& :{4 2!{4m *":ڹ ͯ !z4I '2!"!q: !4>!S :S! :2*M! ^#V͎ * :w*#" = = = = = ͯ  *M !6q  !6q  !6q  *& !6à  !6 à  !60à  *& !6  !6  !6  *& . 1 4 7 : = F P [ f q   :2!q: " *M n :c4 *M n :2!c:Q !c:2: !:cw>!n !5 Y : { !6!q:!lwҙ  â :0O !q:O| :O| !6:]2l:o'2o:n'2n:m'2m*mMͣ *nMͣ *oMͣ :]:   *}2D" * * *&"!q:UY: Y:ҩ: ʩ:_2ʘ:€!6<:<2!ژ!6 >!]Ҥ; !6:Q::H: !6*M : !6!q:a/>z!/H:_2:!q:A/>Z!/H8: 2::=O>m:W!Q} Hmd>9>!6:2*M!E ^#V͎ڗO **~2*#"m2m͖ 2m!6m!6m!6 m2mͯ m!62m!62m!62m!62m'2:2:TҒ:2!6*ME:2::Ҳ:<22ý: 2:} >ͯ :i:2:d*M:[ *M:>!(:=2%> >>!F!5+N! ~2!4<2T>>!b}*bMͭz:b2!b6:<2é>!`ҥ*`MͭҞ!`6!6> :é:(!q:!wO! ~2*& :w>!:!4!6>:N<2N!> *N& N2 !p+q!6!6+6 !6: S: M!6g8:N2M*M8p!6!6!6>!ڕ*&P 6!4z!6!6#6#6!6*M8:ھ:*͇g2ê::¿::,͡A<2O>*M8):[ͱ!N5!6ñ:5!6#6>!ڰ!6:<2O>/:!O!T *M͡H~K:¡!6[–ͱ!N5:2:2!4=:[¼ͱ4:!6:.2O8: :* ͇g:[ ͱ!N5!6:%:<2*6 * 6å!q!6> !d*&I :]>!4A>:<2O* :w:?†!6!q!6?!:ҠgÐ!q*&*~!6:22: :]Hں:A2O>: 2ͯ ÷:S:QHI:N<22: H@"2Í202O> c!6Í202O> ڍ*&O*& !sc*&P :w:·>!ұͯ :22:_!6=!6>'!E!4!p+q*0 !r+s+p+q*~$7*>*>H&>*#"*#"> 2:R͎:!6!6=2:ʙ!6:“H9Ž>!6-e!6ͻ2=2ʺ-é:>>"ͻ2:!!5ͻ2ͬ!\-:>>!p+q:,!6*DM9:<!6:z 2W!6D*&L :w:<2Ov*:>=20O> ڒ:0:AO>Ҥ::A }}Hͬ!wͻO`idͻV[2O>2:!X!6:!:=O!L NE!4 E E:/.*&L 6$L9k9.Xͯ *KM^020 :020:121'ͳ':²ͯ !G6!"!"7 *M^n/ :a/:H!6:ͯ !&62*">!b!ͯ >!`0ͯ !q:E:24J!46*}a!44EJ *KM^'́:‚ͯ !36'n::0:f9OY#9.3'ͳ.:020' 'ͳ'7 6'!j>A+!s!"@͓1!"<**"͓n "Dn"":!Q2҂:X!Wғä:ڤ*MEÓ:ұ@@:O2Mc;!6#6>!)*&P ~"::H:H:H:H"!6!4:_jYO jM*"S*" 3@bl*M1͓!""7 *M^͆ \͔!":͎H*#"ͧÝ/ :>͛9ͯ .*#":_!' !'6!36' :1/!aE*#">z?C9IͲÁ.!6> !ڇ*&' ~2 ʀ: y.*M!4Q>!қ:=2á:2:Ҭ\>!ҿ:=2K:2K!:!:K\: \!p+q͈*DM!  ::=H-\:N2O_og_{ozg^#V))) _{ozg^#V) d^#V|g}o n_{ozgO{ozgi`N#Fogo&og H ©=¨!j>A+!s!"@͓1!"<**"͓n "Dn"":!Q2҂:X!Wғä:ڤ*MEÓ:ұ@@:O2Mc;!6#6>!)*&P ~"::H:H:H:H"!6!4:_jYO jM*"S*" 3@bl*M1͓!""7 *M^͆ \͔!":͎H*#"ͧÝ/ :>͛9ͯ .*#":_!' !'6!36' :1/!aE*#">z?C9IͲÁ.!6> !ڇ*&' ~2 ʀ: y.*M!4Q>!қ:=2á:2:Ҭ\>!ҿ:=2K:2K!:!:K\: \!p+q͈* Osborne Encore Firmware Generation Procedure 4/4/83 ---------------------------------------------------------------- 1. Hardware required: a. Prom programmer -- Data I/O 19 -- connected to Osborne-1. b. 2 2732 EPROMs c. In-Circuit Emulator for Z80 plugged into an Osborne Encore 2. Software required: a. Disk with these files 1. act.com 2. vrom.asm 3. pip.com 3. Enter this command to turn source file into hex code: act vrom.asm When assemble completes, this message is displayed on the screen: 'VALUE TO SET BREAK POINT FOR CHECKSUM IS : xxxx' where value is a four-digit hex value. This is the breakpoin address for determing the ROM checksum. The resultant file is vrom.hex. 4 Checksu reside i th las byte o Osborn Encor firmwar a location 0FFFD - 0FFFFH o RO absolut addresse 0FFDȠ - 0FFFH I mus no b burne int th fina ROM Thi mus b don i tw passes first withou th prope checksum an second wit th checksum Th prope checksu i determine b usin a In-Circui Emulato t sto a th locatio displaye abov an readin th value o specifi registers Th secon pas create th releasabl versio o th PROM. 5 First Pass -- Us th Pro Programme t burn-i ever byt: a. Download Osborne Encore firmware into Prom programmer. 1. Boot up Osborne-1. 2 Ente pi ptp: vrom.he WITHOUT pressin RETUR key. 3. Power up prom programmer 4. Enter SEL 83 ENTER SEL D1 START 5. Press RETURN key on Osborne-1 to start download b Inser 273 Pro int Pro programme socke (probabl socket #2) c. Enter PROG 1924 START d. Prom should now be burning. e Onc Pro ha burne successfully d no tur i off-- leave it as is. Remove Prom from programmer. 6 Determin checksum. a Powe u Osborn Encor wit In-Circui Emulato attache plugge int it Z8 socket Pres th Osborn Encor rese button. b. Power up In-Circuit Emulator. 1. Press these buttons on it "RESET" "BKPT A" (address saved from assemble) "BKPT A" key and "1" button simultaneously "BKPT B" and "0" button simultaneously 2. Start emulation by pressing the "RUN BKPT" key. Emulatio shoul stop Thi i no th correc spot Press the "RUN BKPT" key again. 3 Emulatio shoul now sto a prope address. 4. Cop dow registe content b pressin砠 prope sequenc o button an readin th addres (no data LED display a. Register D "REG" "D" b. Register E "REG" "E" c. Register C "REG" "C" 7 Secon Pas -- Bur th fina PROM Pu th checksu int th pro programmer: a. enter this keystroke sequence: KEYBD FFD ENTER (value of register d here) ENTER (value of register e here) ENTER (value of register c here) ENTER b Inser secon (no th previousl burne PROM int th second socket. c Enter PROG START d. Prom should now be burning. e Onc Pro ha burne successfully th release pro i done.  3 Emulatio shoul now sto a prope address. 4. Cop dow registe content b pressin砠 prope sequenc o button an readin th addres (no data LED display a. Register D ;.Date: 4/4/83 ;.Author: DEB ;.Title: ENCORE MONITOR ROM : REV X3.094 ;.Comments: ALPHA ; +---------------+ ; | | ; |ENCORE Monitor | ; | | ; +---------------+ ;X.1 Added the corvus boot : deb ; Added the enable keybd int. before first enable int. : deb ;X.2 Changed the default step delay to 20ml from 12ml : deb ;X.3 Added head settle delay after step : deb ; Changed the delay after motor on to .5 sec : deb ;X.4 Changed to the rev 2 board : deb ; Changed INTERRUPTs and character generater : deb ; Changed reverse in sign-on message : deb ; Changed the number of retrys in SENDEN to NRETRY : deb ; Changed the disk drivers to run with a 1797 : deb ; Deleated some unused jmps in the jump table at f100 : deb ; Shortened DELAY allittle : deb ;X.5 Took EXX out of INTERRUPT routines : deb ;X.6 Added keyboard drivers from Shelly : deb ; Made LKEY a rom only variable : deb ; Changed keyboard matrix : deb ; Changed log-on name to Memory Might : deb ;X.7 Changed keyboard driver : deb ; Changed misspelled words : deb ;X.8 Added screen driver : deb ; Changed log-on name to Express : deb ; Added recalabrate to CBOOT : deb ; Changed windows to ESC,'w',#,ROW,COL,ROW,COL : deb ; Changed jmp table some : deb ; Fixed bug in boot DSKSWP : deb ; Changed second retry value in SENDEN from 3 to NRETRY : deb ; Added section definition : deb ; Took out FORMAT routine (FMTTRK is still in) : deb ;X.9 Fixed bug in error reporting for FMTTRK : deb ; Changed time out constant in RADR to a constant DRQTIMEOUT : deb ; Changed JRNC :3 to JNC :3 in RD_WRT to make it a little faster : deb ; Made CORVUS link conditional by an IF statment : deb ; Added power on diagnostics : deb ; Changed CORVUS referance number ([10]) to [11] : deb ; Made hardware init. a routine : deb ; Changed fault tree in R_WSEC : deb ; Cleaned up code that uses RTRY : deb ; Change ESC sequence character, (VSGH,VEGH,VWDEF) : ymk ; Remove ESC sequence (VRLF,VATR) : ymk ; Add ESC sequence (VSUL, VEUL, VSRV, VERV, VCAS) : ymk ; Removed PUSH IX & IY and POP IX/IY out of INTHNDL (they are not used) : deb ; Added READROM routine & jmp in jump table : deb ; Speeded up console : deb ; Took out ROMCON & referenced CONTBLS directly : deb ; Took out DI at the beginning of the INTHNDL routine : deb ; Made GKEY & DDRV in line code in INTHNDL : DEB ; Fixed bug in EINSRT : deb ; Fixed bug in ENDROW : deb ; Fixed bug in ENDCOL : deb ;X.10 Change boot message and boot error handler : ymk ; Change poweron diagnostic error dislpay message : ymk ; Disable corvus link : ymk ; Shorted IMSG : deb ; Shortened FAILMSG : deb ; Change boot message and boot error handler : deb ; Moved DELAY to disk section : deb ; Changed head settle delay to 40 msec : deb ; Changed disk start up delay to 750 msec : deb ; Changed jump table : deb ; Changed memory address : deb ;X.11 Alternate character set works in console : deb ; Worked on KBDRVR alittle : deb ; Made bell last for 250 msec per TVI 950 spec : deb  ; Power on test rings the bell after a sucsessfull complete : deb ; Changed keyboard decode tables : deb ; 8Eh ; & 8Fh ; & 90h ; & & 91h ; Made KBSCAN faster on 8th rom : deb ; Made SKEY faster : deb ; Took KEYLCK check out of SKEY : deb ; Made INTHNDL alittle faster : deb ; Added two ESC sequences for 256 characters : deb ; ESC U = 256 CHARACTER SET WITH REVERSE VIDEO ; ESC u = 256 CHARACTER SET WITHOUT REVERSE VIDEO ; Made VC_MCRT alittle faster : deb ; Used ROM based display tables (IE. CTBLPTRS ) : deb ; The first thing INITHARD does is clear the screen : deb ;X.12f Changed boot error message : deb ; Changed PODIAG error message : deb ; Fixed bug in INITHARD : deb ; Changed name to ENCORE : deb ; Changde KBSCAN to process ALPHA LOCK only : deb ; Made VC_MCRT a little faster : deb ; Made DO_LF a little faster : deb ; Made final ajustment to memory locations : deb ; Activated checksum test in PODIAG : deb ; Added fill bytes to end of rom : deb ; Fixed bug in CHKSUM : deb ; Final pre-alpha : deb ;X3.094 ALPHA : deb ; Tookout CORVUS : deb ; Fixed bug in INTHNDL : deb ; Switched the upper and lower definition of the character rom : deb PAGE ;FUNCTIONAL SECTIONS *[1] INITHARD ;HARDWARE INITIONALIZATION *[2] OSTR ;JUNK *[3] ;JUMP TABLE *[4] IMSG ;SIGN ON MESSAGE *[5] CBOOT ;CPM BOOT LOADERS *[6] BTICKS ;SCREEN DRIVER *[7] INTHNDL ;INTERRUPT PROCESSOR *[8] SKEY ;KEYBOARD DRIVER *[9] RDRV ;FLOPPY DISK DRIVER *[10] PODIAG ;POWER ON DIAGNOSTICS *[11] HCBOOT ;CORVUS CBOOT LOADER PAGE CORVUS = 0 ;0=FALSE, TRUE<>0 SCLFRE: = 0B4H ;for DELAY routine DEL: = 7Fh ;DELEATE KEY TAB: = 09h ;TAB NRETRY: = 10 ;NUMBER OF RETRYS ;I/O MAP ;SYSTEM PIO (8155) SYSMS: = 0CH ;ADDRESS PORT TO 8155 MEMORY (0-255) SYSRS: = 0DH ;ADDRESS PORT TO 8155 REGISTERS (0-5) SYSRW: = 08H ;READ/WRITE PORT FOR 8155 ;DISK DSK_CMD = 0 ;Floppy disk DISK COMMAND REG (WRITE) DSK_STS = DSK_CMD ;STATUS REG (READ) DSK_TRK = DSK_CMD+1 ;TRACK REG DSK_SEC = DSK_CMD+2 ;SECTOR REG DSK_DAT = DSK_CMD+3 ;DATA REG (R/W) DRQTIMEOUT: = 4615 ;TIME OUT CONSTANT FOR RADR ROUTINE ;INTERRUPT SERVICE PORT INTPORT = 4 ;KEYBOARD EQUATES KL_LEN: = 3 ;KEY LIST LENGTH KL_USED = 7 ;KEYLIST ENTRY USED KY_SRVD = 6 ;KEY SERVICED ONCE KROW_M: = 38H ;ROW NUMBER MASK KCOL_M: = 7H ;COL NUMBER MASK DB_CT: = 1 ;DEBOUNCE COUNT IRPTCT: = 24 ;INITIAL REPEAT COUNT (400MS) SRPTCT: = 3 ;SECOND REPEAT COUNT (100MS) TOT_ROW = 8 ;TOTAL ROWS BAD = 0FFH ;Used to flag an invalid translated char BADKEY = Bad TBL_LEN = 64 ;Length of keybd xlate tables ROW0_M = 1 ;MASK FOR ADDRESSING ROW 0 ;KEYBOARD Translation table list: NM_TB_NO: = 0 ;NORMAL SH_TB_NO: = NM_TB_NO + 1 ;SHIFT CT_TB_NO: = SH_TB_NO + 1 ;CONTROL AL_TB_NO: = CT_TB_NO + 1 ;ALPHA LOCK CS_TB_NO: = AL_TB_NO + 1 ;CONTROL SHIFT ;DRIVE EQUATES D.SEK: = 010H ;SEEK D.STP: = 020H ;STEP D.STPI: = 040H ;STEP IN D.STPO: = 060H ;STEP OUT D.RDS: = 088H ;READ SECTOR D.WRTS: = 0A8H ;WRITE SECTOR D.RDA: = 0C0H ;READ ADDRESS D.RDT: = 0E0H ;READ TRACK D.WRTT: = 0F0H ;WRITE TRACK D.FINT: = 0D0H ;FORCE INTERRUPT PAGE ;ROM ONLY VARIABLES ROMSTK: = 100H ;ROM STACK USED BY PO & CBOOT ORG 0EBA2H ;BOOT LOADERS TBUFF: DS 1024 ;BUFFER FOR BOOT CLRSTR: = * ;START OF AREA TO CLEAR TEM: DS 1 ;USED IN BOOT ROUTINES CCPADR: DS 2 ;(2) FBA OF CCP ;DISK DRIVERS RTRY: DS 1 ;RETRY COUNTER DACTVE: DS 1 ;<> 0 : DISK ACTIVE DSKSWP: DS 1 ;DISK SWAPPED CELL NUMSEC: DS 2 ;NUMBER OF SECTORS TO R/W R_WCOM: DS 1 ;NUMBER OF SECTORS TO READ OR WRITE DSTSB: DS 6 ;(6) SIX BYTES FOR DISK INFO ;KEYBOARD DRIVER KEYLCK: DS 1 ;KEYBOARD LOCKED CELL LKEY: DS 1 ;(1) LAST KEY PRESSED (FF IF NO KEY PRESSED) TBLBASE DS 2 ;(2) POINTER TO KEYBOARD TABLES KEYLST: DS 6 ;KEY LIST GOES HERE ;ADDRESS IN KEYLST  FIRSTKEY = KEYLST SECONDKEY = FIRSTKEY + 2 LASTKEY = KEYLST + 4 ;SCREEN DRIVER OFFSET: DS 1 ;CURSOR OFFSET CURPOS: DS 2 ;CURSOR POSITION BELCNT: DS 1 ;<> 0 : BELL RINGING VRS: DS 8 ;(8) FBA OF VIDEO ROUTINES IN RAM CFLAG: DS 1 ;(1) ESCH FLAG BACKGND DS 1 ;Background attribute flag FWAWIND DS 2 ;First word address of window WINDROWS: DS 1 ;Number of rows in window WINDCOLS: DS 1 ;Number of columns in window TEMPFWA DS 2 ;Holds new FWA while window is being defined TEMPROWS: DS 1 ;Holds new number of rows while window is being defined FSTROW DS 1 ;Holds first row number while window is being defined FSTCOL DS 1 ;Holds first column number while window is being defined CONTBLS DS 2 ;CURRENT SCREEN TABLE ADDRESS ;INTERUPT STACK DS 30 ;STACK SPACE ISTK: DS 0 ;(-40) INTERRUPT STACK AREA ISSTK: DS 2 ;(2) SAVE OLD STACK HERE PAGE ;TRANSFER RAM MEMORY LOCATIONS SEQ: = 0EFF4H ;(2) COUNTER (USED BY BIOS) SEKDEL: = 0EFF6H ;(1) DISK STEP DELAY (USED IN COPY & DIAG) DMADR: = 0EFF7H ;(2) DISK DMA ADDRESS SAVTYP = 0EFF9H ;(1) DISK TYPE SDISK: = 0EFFAH ;(1) DISK IN USE SAVTRK: = 0EFFBH ;(2) TRACK SAVSEC: = 0EFFDH ;(1) SECTOR ;ROM ONLY MEMORY LOCATIONS INTBL: = 0EFFEH ;(2) interrupt vector (EFFE & EFFF) FWAVM: = 0F000H ;FIRST ADDRESS OF MEMORY MAP PAGE ORG 0F000H ;FWA of ROM ;NOTE ;THE FIRST INSTRUCTION MUST BE A JMP TO THE ROM ;THE STACK IS SET TO ROMSTK IN PODIAG PROC JMP PODIAG ;DO POWER ON DIAGNOSTICS AND SET ROM MODE VSTART: ;START OF MONITOR ENTRY POINT (PODIAG JUMPS HERE) LDK DE,IMSG CALL OSTR ;Output initial message EI ;ENABLE INTERRUPTS :1: CALL CI ;Get character CMP ESC JZ HCBOOT ;IF COLD BOOT OFF OF HARD DISK LDK HL,DSKSWP ;disk swap cell STO 0,[HL] ;SET DRIVES A=A, B=B CMP CR JZ CBOOT ;if cold boot off of A INC [hl] ;swap drives: A=B, B=A CMP '"' JZ CBOOT ;if cold boot off of B ;CHECK FOR LOOPING PO TEST CMP 'T'  JRZ VLOOP ;DO PO TEST CMP 't' JRNZ :1 ;LOOP IF NOT PO TEST ;FALL THROUGH TO PO TEST PAGE VLOOP: ; JUMP HERE TO SET UP ENCORE TO RUN POWER-ON SELF-TEST FOREVER. TO DO SO, ; SET LOGIC BOARD 8155 MEMORY LOCATION TO BE = 2. XRA A ;ACCUMU = MEMORY LOCATION ZERO OUT SYSMS LDK A,2 OUT SYSRW ;SET 8155 MEMORY LOCATION ZERO = 2 JMP POSTART ;RUN POWER ON TEST PAGE *[1] INITHARD: ;HARDWARE INITIONALIZATON DI ;DISABLE ITERUPTS *INITIALIZE MEMORY ;CLEAR THE SCREEN LDK HL,FWAVM ;FBA OF VIDEO :LOOP: STO 20H,[HL] INC HL MOV A,L ORA H JRNZ :LOOP ;LOOP TILL END ;CLEAR BUFFERS LDK HL,CLRSTR ;START LDK DE,CLRSTR+1 LDK BC,FWAVM-CLRSTR-1 ;LENGTH STO 0,[HL] ;ZERO FIRST BYTE LDIR ;OVERLAPPING MOVE ;SET VALUES OF ONE LDK A,1 STO A,KEYLCK ;indicate NOT locked ;SET VALUES OF TWO INC A ;A = TWO STO A,SEKDEL ;set seek step rate FOR SEMIENS ;SET "LKEY" LDK A,0FFH STO A,LKEY ;NO KEY READY ;SET POINTER TO KEYBOARD TABLES LDK HL,KYCDTB ;FIRST BYTE OF FIRST TABLE STO HL,TBLBASE ;SET VALUE ;INITIALIZE POINTERS IN THE SYSTEM CONSOLE TABLE LD HL,CTBLPTRS ;SET CURRENT SCREEN TABLE STO HL,CONTBLS ;INITIALIZE OTHER MEMORY LOCATIONS LDK HL,FWAVM STO HL,CURPOS ;Position cursor to top of screen STO HL,FWAWIND ;Initialize window to full screen LDK A,VMCOLS STO A,WINDCOLS ;Full 80 columns LDK A,VMROWS STO A,WINDROWS ;Full 24 rows LDK A,20H STO A,OFFSET ;X-Y positioning offset = 20H ;MOVE VIDEO ROUTINES TO RAM LDK BC,VRL ;LENGTH OF VIDEO ROUTINES LDK DE,VRS ;FBA OF VIDEO ROUTINES IN RAM LDK HL,SOURCE ;FBA OF VIDEO ROUTINES IN ROM LDIR ;SET INTERRUPTS ;SET MODE 2 INTERRUPTS IM2 ;SET INTERRUPT REGISTER LDK A,high INTBL MOV I,A ;SET INTERRUPT VECTOR LDK HL,INTHND STO HL,INTBL ;SET INTERNAL PIO XRA A OUT SYSRS ;SELECT PIO CTL LDK A,0EH OUT SYSRW ;CONFIGURE LDK A,3 OUT SYSRS ;SELECT PORT C LDK A,1111_0111B OUT SYSRW ;CONFIGURE ;CLEAR KEYBOARD INTERRUPT ;DISABLE LDK A,0000_0000B ;DISABLE OUT INTPORT ;ENABLE LDK A,0000_0001B ;ENABLE OUT INTPORT RET PAGE *[2] ;JUNK OSTR: ;OUTPUT STRING TO CONSOLE ;NOTE: OSTR RECOGNIZES 7F AS AN ESCAPE SEQUENCE TO REPEAT CHAR N TIMES. FORMAT IS: 7F, REPEAT COUNT, CHAR ;ENTRY ;DE = FWA OF SOURCE ;EXIT ;NONE PROC LD A,[DE] OR A PUSH AF AND 07FH CMP 07FH MOV C,A JRNZ :4 ;IF NOT REPEAT INC DE LD A,[DE] DEC A MOV B,A ;REPEAT COUNT INC DE LD A,[DE] ;GET REPEAT CHAR MOV C,A :2: PUSH BC PUSH DE CALL COUT ;OUTPUT CHAR POP DE POP BC DJNZ :2 ;IF NOT DONE :4: PUSH DE CALL COUT ;OUTPUT IT POP DE INC DE POP AF JP OSTR ;IF NOT DONE RET PAGE EMBOOT: DB ESC,VDELL ;DELETE CURRENT LINE DB 'BOOT ERROR : CHECK YOUR DISKETT' DC 'E' PAGE READROM: ;READ A BYTE FROM THE ROM ;NOTE ;SINCE THE ROM IS THE ONLY THIS THAT CAN READ THE ROM THIS ROUTINE IS HERE TO DO JUST THAT ;ENTRY ;HL = ADDRESS TO READ ;EXIT ;A = VALUE READ ;HL = HL PROC LD A,[HL] RET PAGE *[3] ;ROM JUMP TABLE MSG 'LENGTH BEFORE 0F100h IS ', * ORG 0F100h ;ROM JUMP TABLE ;CBIOS = Jmps used mainly by CBIOS ;BOOT JMP WBOOT ;CBIOS warm boot ;CONSOLE I/O JMP SKEY ;CBIOS keyboard status JMP CI ;CBIOS keyboard input JMP COUT ;CBIOS console output ;HIGH LEVEL DISK I/O (WITH RETRY) JMP RDRV ;CBIOS HOME JMP RSEC ;CBIOS DISK SECTOR READ JMP WSEC ;CBIOS DISK SECTOR WRITE JMP SENDEN ;CBIOS SENSE THE DENSITY OF DRIVE ;LOW LEVEL DISK I/O (NO RETRY, FOR DIAG) JMP HOME ; HOME DISK DRIVE JMP SEEK ; SEEK TO TRACK JMP STEP ; STEP SAME DIRECTION JMP STEPIN ; STEP IN JMP STEPOUT ; STEP OUT JMP READ ; READ SECTOR JMP WRITE ; WRITE SECTOR JMP RADR ; READ ANY SECTOR HEADER JMP READTRK ; READ TRACK JMP FMTTRK ; Format one track (USED ALSO BY COPY) JMP FORINT ; FORCE INTERRUPT JMP SELDRV ; SELECT DRIVE ;OTHER JMP READROM ; Read a byte from the rom PAGE *[4] ;SIGN ON MESSAGE IMSG: DB VCLRS ;CLEAR SCREEN DB ESC,VSGH ;SET GRAPHIC MODE DB ESC,'=',2+32,21+32 DB 'Q'-40h DB 07Fh, 37, 'W'-40h DB 'E'-40h DB ESC,'=',3+32,21+32 DB 1 DB 07Fh,15,' ' DB 'ENCORE' DB 07Fh,16,' ' DB 4 DB ESC,'=',4+32,21+32 DB 'A'-40h DB 7FH, 15, ' ' DB 'X3.094' DB 7FH, 16, ' ' DB 'D'-40h DB ESC,'=',5+32,21+32 DB 'A'-40h DB 07Fh,37, ' ' DB 'D'-40h DB ESC,'=',6+32,21+32 DB 'A'-40h DB ' ' DB 'S'-40h ;COPYWRITE SYMBEL DB ' 1983 OSBORNE SOFTWARE TEST ONLY ' DB 'D'-40h DB ESC,'=',7+32,21+32 DB 'Z'-40h DB 07Fh, 37, 'X'-40h DB 'C'-40h DB ESC,VEGH ;END GRAPHICS DB ESC,'=',9+32,20+32 DB 'INSERT DISK IN DRIVE A AND PRESS RETURN' DC '.' PAGE *[5] ;CPM BOOT LOADERS CBOOT: ;LOAD ALL THE OPERATING SYSTEM INCLUDING THE CBIOS ;ENTRY ;NONE ;EXIT ;A = DRIVE TO BOOT FROM PROC ;RECALIBRATE DISK! DRIVE CALL RDRV ;HOME DRIVE LDK A,10 STO A,SAVTRK CALL SEEK ;SEEK TO TRK 10 :1: CALL RDRV ;HOME XRA A STO A,SAVTRK ;TRK TO 0 *SET "SAVTYP" CALL SENDEN ;DETERMINE DENSITY JRNZ EBOOT ;PRINT ERROR AND HANG *READ AND SET FBA OF CCP LDK HL,TBUFF STO HL,DMADR ;SET DMA PUSH HL :3: LDK A,1 STO A,SAVSEC ;SET SECTOR MOV B,A CALL RSEC ;READ SECTOR ONE JRNZ EBOOT ;PRINT ERROR AND HANG *CHECK FIRST TWO BYTES OF THE CCP POP HL ;HL = 0D000H LD A,[HL] ;FIRST BYTE CMP 0C3H JRNZ EBOOT ;PRINT ERROR AND HANG INC HL ;HL = 0D001H LD A,[HL] ;SECOND BYTE CMP 05CH JRNZ EBOOT ;PRINT ERROR AND HANG INC HL ;HL = 0D002H ;SET LOAD ADDRESS LD A,[HL] ;get ccp address/100h + 3 SUB 3 LDK L,0 MOV H,A *SET NUMBER OF 128 BYTE BLOCKS TO READ FOR BOOT LDK B,60 ;CCP/BDOS/CBIOS *READ SYSTEM PUSH HL ;SAVE FWA FOR "CCPADR" CALL BCPM ;boot system POP HL *JUMP SYSTEM STO HL,CCPADR ;SET "CCPADR"  LDK DE,1600h ;offset for bios ADD HL,DE ;address of bios in hl JMP [HL] ;CBOOT IN BIOS PAGE EBOOT: ;BOOT ERROR MESSAGE ROUTINE ;ENTRY ;NONE PROC LDK DE,EMBOOT ;BOOT ERROR MESSAGE CALL OSTR :1: JR :1 ;HANG PAGE WBOOT: ;LOAD ONLY THE CCP AND THE BDOS FROM DRIVE A ;ENTRY ;NONE ;EXIT *NOTE* *; THIS ROUTINE DOES NOT EXIT. IT ONLY SETS PARAMETERS FOR BCPM:. *;B = NUMBER OF 128 BYTE BLOCKS TO READ FOR BOOT *;HL = DMA ADDR FOR CCP PROC LDK B,44 ;CCP/BDOS and don't read CBIOS LD HL,CCPADR PAGE BCPM: ;LOAD ALL OR PART OF CPM FROM THE DISK *NOTE* ;This loader will load single or double density and any number of sectors per track or bytes ;per sector. TEM is not zero if there are an uneven number of sectors to read. If this is true the ;last sector is read into a temporary buffer and the part needed is moved into the memory. ;ENTRY ;B = NUMBER OF 128 BYTE BLOCKS TO READ FOR BOOT ;HL = DMA ADDR FOR CCP ;EXIT ;NONE PROC *SET "SDISK", "DMADR" AND "SAVSEC" STO HL,DMADR ;SET DMA XRA A STO A,SDISK ;BOOT ONLY FROM DRIVE A STO A,TEM ;MAKE TEM ZERO INC A STO A,SAVSEC ;set sector *SET "SAVTYP" AND GET NUMBER OF SECTORS PER TRACK PUSH BC ;SAVE NUMBER OF 128 BLOCKS CALL RDRV ;HOME DRIVE CALL SENDEN ;DETERMINE DENSITY JRNZ EBOOT ;PRINT ERROR AND HANG POP DE ;D=NUMBER OF 128 BYTE BLOCKS PUSH BC ;SAVE NUMBER OF SECTORS IN ONE TRACK *SET NUMBER OF SECTORS TO READ LD A,SAVTYP SRL A SRL A ANI 0000_0011B ;A=NUMBER OF BYTES IN ONE SECTOR(0-3) JRZ :2 ;IF 128 BYTES SECTORS ;GET NUMBER TO DEVIDE BY MOV B,A ;B=NUMBER OF BYTES IN ONE SECTOR(1-3) LDK A,1 :1LOOP: SLA A ;TIMES TWO DJNZ :1LOOP MOV B,A ;NUMBER TO DIVIDE BY MOV A,D ;A=NUMBER OF 128 BYTE BLOCKS LDK D,0 :2LOOP: SUB B ;SUBTRACT WITH DIVISOR EX AF ;SAVE FLAGS INC D ;COUNT EX AF ;RESTORE FLAGS JRZ :2 ;IF RESULT IS ZERO (NO PARTIAL SECTORS) JRNC :2LOOP ;LOOP NEG A ;2 COMP STO A,TEM ;SAVE REMAINDER AND INDICATE A PARTIAL SECTOR :2: POP BC ;B=NUMBER OF SECTORS IN ONE TRACK MOV C,D ;C=NUMBER OF SECTORS TO READ PAGE *READ SYSTEM XRA A ;A=0 :TLOOP: STO A,SAVTRK ;SET TRACK ;CHECK FOR ALL SECTORS READ MOV A,C ;SECTORS TO READ ORA A JRNZ :3 ;IF C IS NOT ZERO CONTINUE ;CHECK FOR NO PARTIAL SECTOR LD A,TEM ORA A JRZ :9 ;STOP IF C=0 AND TEM=0 JR :7 ;READ PARTIAL SECTOR ;UPDATE NUMBER OF SECTORS LEFT TO READ :3: SUB B ;SUBTRACT SECTORS IN ONE TRACK JRNC :4 ;A>B MORE THAN ONE TRACK LEFT TO READ ;IF THIS IS LAST TRACK ZERO NUMBER OF SECTORS LEFT TO READ MOV B,C ;READ ALL THE REMAINING SECTORS XRA A ;THIS WILL ZERO REG C ;CHECK FOR NONZERO VALUE IN TEM AND THE LAST SECTOR TO READ :4: MOV C,A ;SAVE REMAINING SECTORS TO READ LD A,TEM ORA A JRZ :5 ;IF TEM IS ZERO SKIP THIS XRA A ORA C JRNZ :5 ;IF REG C IS NOT ZERO SKIP THIS(NOT LAST TRACK) ;READ ONE LESS THAN THE LAST SECTOR DEC B ;B=B-1 JRZ :7 ;IF ONLY ONE SECTOR LEFT TO READ ;READ ONE TRACK :5: CALL RSEC ;READ (BC IS SAVED) JRNZ EBOOT ;PRINT ERROR AND HANG ;UPDATE DMA STO HL,DMADR ;SET DMA ;UPDATE TRACK LD A,SAVTRK INC A JR :TLOOP ;TRACK LOOP PAGE *READ A PARTIAL SECTOR :7: PUSH HL ;SAVE ADDRESS TO WRITE TO LDK HL,TBUFF ;ADDRESS OF HOST BUFFER IN BIOS STO HL,DMADR ;SET DMA ;SET TRACK IF NEEDED JRZ :10 ;IF B=0 THEN SAVTRK WAS NOT INCREMENTED LDK HL,SAVTRK DEC [HL] ;SAVTRK = SAVTRK - 1 ;SET THE SECTOR TO B + 1 :10: INC B MOV A,B STO A,SAVSEC ;SET SECTOR ;READ SECTOR INTO HOST BUFF LDK B,1 :RL2: CALL RSEC ;READ ONE SECTOR JNZ EBOOT ;PRINT ERROR AND HANG ;SET NUMBER OF BYTES TO TRANSFER LD A,TEM MOV B,A ;B=NUMBER OF 128 BYTE BLOCK TO TRANSFER LDK HL,0 LDK DE,128 :3LOOP: ADD HL,DE DJNZ :3LOOP PUSH HL POP BC ;BC=NUMBER OF BYTES TO TRANSFER ;TRANSFER BYTES LDK HL,TBUFF ;SOURCE POP "DE ;DESTINATION LDIR ;MOVE ;Clear error indicator and return :9: XRA A RET PAGE *[6] ;VIDEO SCREEN DRIVERS ;VIDEO CONSTANTS BTICKS: = 15 ;DURATION FOR BELL 15 TICKS = 1/4 SEC VMROWS = 24 ;24 Rows VMCOLS = 80 ;80 Columns VLL = 128 ;Length of one video line ;CONTROL CHARACTERS CR = 0Dh ;^M, CR = Carriage Return LF = 0Ah ;^J, LF = Line Feed BKS = 08h ;^H, Backspace CBELL: = 'G'-40h ;Ring the Bell MCUP: = 'K'-40h ;Move cursor up MCRIGH: = 'L'-40h ;Move cursor right VDWN: = 'V'-40H ;Move cursor down VLIN: = '_'-40H ;New line (CR,LF) VCLRS: = 'Z'-40h ;Clear and home cursor VHOME: = '^'-40h ;Home Cursor ;ESCAPE SEQUENCE CHARACTERS ESC = 1Bh ;^[, ESC = Escape VLOCK: = '#' ;Lock Keyboard VUNLK: = '"' ;Unlock Keyboard VCAD: = '=' ;Cursor Addressing VINC: = 'Q' ;Insert Char VDELC: = 'W' ;Delete char VINL: = 'E' ;Insert line VDELL: = 'R' ;Delete line VCEOL: = 'T' ;Clear to end of line VCEOS: = 'Y' ;Clear to end of screen (window) VCAS = 'Z' ;Clear all screen VAL128: = 'a' ;alternate 128 character set VMA128: = 'A' ;MAIN 128 character set V256WO: = 'u' ;256 CHARACTER SET WITHOUT REVERSE VIDEO V256W: = 'U' ;256 CHARACTER SET WITH REVERSE VIDEO VSHI: = ')' ;Start half intensity VEHI: = '(' ;End VSGH: = 'g' ;Start graphics VEGH: = 'G' ;End VRON: = 'b' ;Set reverse video background (black on white) VROFF: = 'd' ;Clear reverse video background (set to white on black) VSUL: = 'l' ;Start underline VEUL: = 'm' ;End underline VSRV: = 'j' ;Start reverse video VERV: = 'k' ;End reverse video VWDEF: = 'z' ;Window define VOFF: = 'o' ;Define X-Y offset PAGE ;Bit definitions for CFLAG flag byte ; +---+---+---+---++---+---+---+---+ ; | 7 | 6 | 5 | 4 || 3 | 2 | 1 | 0 | ; +---+---+---+---++---+---+---+---+ ; | | | | | | | | ;Reverse video <------------------+ | | | | | | | ;<------------------------------------+ | | | | | | ;<----------------------------------------+ | | | | | ;<--------------------------------------------+ | | | | ; | | | | ;<-------------------------------------------------+ | | | ;<-----------------------------------------------------+ | | ;<---------------------------------------------------------+ | ;Graphics <----------------------------------------------------+ REV_FLG: = 80H ;Reverse video mode GR_FLG: = 01H ;Graphics mode PAGE COUT: ;General output routine to Video Screen ;ENTRY ;C = Character ;CURPOS = Cursor ;CFLAG = Flag+Mode ;EXIT ;CURPOS & CFLAG updated PROC ;TURN OFF OLD CURSOR LD HL,CURPOS ;GET CURSOR POSSISION CALL RLDA ;GET BYTE IN A XRI 1000_0000B ;TOGOL BIT STO A,[HL] ;SAVE ;PROCESS CHARACTER CALL LOOKUPB ;TURN ON NEW CURSOR LD HL,CURPOS ;GET NEW CURSOR POSSISION CALL RLDA ;GET BYTE IN A XRI 1000_0000B ;TOGOL BIT STO A,[HL] ;SAVE RET PAGE LOOKUPB: ;Look up character in the specified table and branch to processing procedure ;If character is not in the table, then branch to default procedure. ;ENTRY ;C = char ;*NOTE* ;After GETTBL is called: ;HL = table address ; 1st byte of table = number of (non-default) table entries ; Entries are 4 bytes long: ; 1st byte = match code ; 2nd byte = next table number ; 4th,5th bytes = branch address ; The last entry is a 3-byte "No Match" default next table number and branch address ;EXIT ;Jumps to branch address in table ;C = character PROC ;GET CURRENT TABLE LD HL,CONTBLS ;HL = Current table's address ;FIND CHARACTER IN TABLE LD A,[HL] ;A = number of entries INC HL ;First entry ORA A JRZ :1 ;If no entries, do default processing MOV B,A ;B = number of entries MOV A,C ;A = character :LOOP: CMP [HL] ;Check for match INC HL ;(2nd byte of this 4 byte entry) JRZ :1 ;If match process INC HL ;(3rd byte of this entry) INC HL ;(4th byte of this entry) INC HL ;1st byte of next entry DJNZ :LOOP ;Continue thru body of table ;SET UP NEXT TABLE ADDRESS :1: PUSH HL ;Save current position in table LD A,[HL] ;A = next table number ADD A,A ;A = A * 2 MOV L,A LDK H,0 ;HL = Table number * 2 LDK DE,CTBLPTRS ;DE = current table pointer IN ROM ADD HL,DE ;[HL] = next table address LD E,[HL] INC HL LD D,[HL] STO DE,CONTBLS ;Set table address to next table address POP HL ;Restore ;BRANCH TO PROCESSING PROCEDURE INC HL ;Go to branch address portion of table entry LD A,[HL] ;1st byte (low order adrs) INC HL LD H,[HL] ;2nd byte (high order adrs) MOV L,A ;HL=adrs from table MOV A,C ;A = char JMP [HL] ;enter routine per table adrs. PAGE ;BASTBL PROCEDURES PROCNORM: ;Normal character entered (ie not a lead-in character) ;Checks for graphics or normal character and passes c#haracter on to appropriate ;routine ;ENTRY ;C = character ;EXIT ;NONE PROC LD A,CFLAG ;Get flags RRC ;Check for graphics mode JRC VGRAPH ;Graphics mode -- process character ;NORMAL mode character processing. MOV A,C CMP ' ' JRC :1 ;If control character ;Display new character and update cursor CALL DISPLAY ;Display new character JMP VC_MCRT ;Move cursor right & RETURN ;If control character Set current table TO CONTROL TABLE :1: LDK L,CTLNUM*2 ;Set current table to control table LDK H,0 ;HL = Table number * 2 LDK DE,CTBLPTRS ;DE = current table pointer IN ROM ADD HL,DE ;[HL] = next table address LD E,[HL] INC HL LD D,[HL] STO DE,CONTBLS ;Set table address to next table address JR LOOKUPB ;Scan table of valid control chrs and branch to appropriate routine. PAGE VGRAPH: ;GRAPHICS mode character processing ;characters 60H-7FH are converted to graphics characters (00H-1FH) ;so that BASIC can access all graphics characters ;ENTRY ;C = char to process MOV A,C BIT 5,A JRZ VOUT BIT 6,A JRZ VOUT ANI 9FH ;Convert to graphics characters ; JR VOUT ;FALL THROUGH PAGE VOUT: ;Display new character and update cursor ;ENTRY ;A = char PROC CALL DISPLAY ;Display new character JMP VC_MCRT ;Move cursor right PAGE ;Control Code character processing VC_CR: ;Carriage return ;ENTRY ;None ;EXIT ;CURPOS = new cursor position PROC LD HL,CURPOS CALL DO_CR STO HL,CURPOS RET PAGE VC_LF: ;Line Feed (if cursor is on last line, scroll screen and add ; new line at bottom) ;ENTRY ;NONE ;EXIT ;CURPOS = new cursor position PROC LD HL,CURPOS CALL DO_LF STO HL,CURPOS RET PAGE VC_BKS: ;Backspace. ;(If in 1st column then wrap around to last column of previous line) ;(No effect if in 1st position of window) ;ENTRY ;NONE ;EXIT ;CURPOS = new cursor position PROC ;CHECK IF AT COLUMN 0 LD HL,CURPOS CALL GETCOL ;Get cursor column JRZ :1 ;if must wrap from col 0 to last col of previous line ;IF NOT, BACKSPACE AND RETURN LD HL,CURPOS DEC HL JR :EXIT ;IF AT COLUMN 0, CHECK FOR ROW 0 :1: CALL GETROW RZ ;Return with no effect if at col 0, row 0 ;IF NOT, WRAP AROUND TO PREVIOUS LINE CALL VC_MCUP ;MOVE UP A LINE (HL = new address) LD HL,CURPOS ;MOVE TO END OF LINE CALL DIST2EOL ;BC = distance from cursor to end of line ADD HL,BC ;HL = new cursor address :EXIT: STO HL,CURPOS ;Save new cursor position RET PAGE VC_MCRT: ;Move Cursor Right (if at end of line, wrap around to next line) ;ENTRY ;NONE ;EXIT ;HL = new cursor position ;CURPOS = new cursor position PROC LD HL,CURPOS CALL DIST2EOL ;A = # of bytes between cursor and end of line JRNZ :1 ;if NOT at last column ;If at last column, wrap around to next line CALL DO_CR ;do CR... CALL DO_LF ;...and LF. STO HL,CURPOS ;Save new cursor position RET ;MOVE CURSOR TO THE RIGHT AND RETURN :1: INC HL ;move cursor STO HL,CURPOS ;Save new cursor position RET ;RETURN PAGE VC_MCUP: ;Move Cursor Up. (If cursor is on top line then nothing happens) ;ENTRY ;NONE ;EXIT ;CURPOS = new cursor position PROC ;MOVE UP A LINE LD HL,CURPOS ORA A ;Clear carry LDK BC,VLL SBC HL,BC ;Move up a line ;CHECK IF ABOVE SCREEN PUSH HL ;Save cursor LD DE,FWAWIND SBC HL,DE ;Carry flag set if above screen POP HL JRNC :EXIT ;Done if on screen ;IF SO, GO BACK TO OLD POSITION ADD HL,BC :EXIT: STO HL,CURPOS RET PAGE VC_MCDOWN: ;Move cursor down (No effect if cursor is on last line) ;ENTRY ;NONE ;EXIT ;CURPOS updated PROC ;CHECK IF ON LAST LINE LD HL,CURPOS CALL LASTROW ;Check if on last row RZ ;If on last row, do nothing ;IF NOT, MOVE CURSOR DOWN LDK DE,VLL ADD HL,DE STO HL,CURPOS RET PAGE VC_NEWLINE: ;Do CR and LF ;ENTRY ;NONE ;EXIT ;CURPOS updated PROC CALL VC_CR JR VC_LF PAGE VC_BEL: ;Ring the bell ;ENTRY ;NONE ;EXIT ;NONE ;NOTE ;THE INTERRUPTS MUST BE DISABLED BECAUSE THEY MAY READDRESS THE 8155 PROC ;RING BELL DI LDK A,3 OUT SYSRS ;PORT C IN SYSRW ;READ IT ANI 1101_1111B ;RESET BELL BIT TO TURN IT ON OUT SYSRW ;SET BELL COUNT LDK A,BTICKS ;NUMBER OF TICKS STO A,BELCNT ;SET BELL COUNT EI RET PAGE VC_CLRS: ESCZZ: ;Clear window ;ENTRY ;NONE ;EXIT ;HL = new cursor position PROC LD HL,FWAWIND ;Beginning of window STO HL,CURPOS ;Position cursor to beginning of window JR CLR_EOS ;Clear window PAGE ; ESC sequence character processing ESCLCK: ;Lock Keyboard ;ENTRY ;NONE PROC XRA A ;Clear A JR :2 ESCULK: ;Unlock Keyboard ;ENTRY ;NONE LDK A,0FFh :2: STO A,KEYLCK RET PAGE EEOS: ;Erase to end of screen ;ENTRY ;NONE ;EXIT ;NONE PROC LD $HL,CURPOS ; JR CLR_EOS ;Clear to end of screen ;(CURPOS stays the same) PAGE CLR_EOS: ;Clear to end of window ;ENTRY ;HL = Start address ;EXIT ;NONE PROC ;GET NUMBER OF ROWS TO CLEAR CALL GETROW ;Get current row MOV C,A ;Save C = row LD A,WINDROWS SUB C ;A = Number of rows to clear ;CLEAR ROWS :LOOP: PUSH AF PUSH HL CALL CLRLN ;Clear to end of line POP HL CALL DO_CR ;Make sure all lines after the 1st one ;start at the first column LDK DE,VLL ADD HL,DE ;HL = next line's address POP AF DEC A JRNZ :LOOP ;If more rows RET PAGE EDELC: ;Delete Character ;ENTRY ;NONE ;EXIT ;NONE PROC LD HL,CURPOS CALL DIST2EOL ;Z flag set if at end of line JRZ CLR_CHAR ;If at end of line PUSH HL POP DE ;DE = cursor address INC HL ;HL = cursor address + 1 CALL RLDIR ;move characters ; JR CLR_CHAR ;Last character becomes blank ;CURPOS stays the same PAGE CLR_CHAR: ;CLEAR CHARACTER FOR GIVEN POSITION ;ENTRY ;HL = ADDRESS ;EXIT ;HL PRESERVED PROC LD A,BACKGND ORI ' ' ;ADD SPACE STO A,[HL] ;Clear character RET PAGE EINSRT: ;Insert Character ;ENTRY ;NONE PROC LD HL,CURPOS CALL DIST2EOL ;BC = distance to end of line JRZ :1 ;IF IN LAST COLUMN, JUST BLANK CURRENT CHAR ADD HL,BC ;HL = last position in cursor line PUSH HL POP DE ;DE = Last position in line DEC HL ;HL = 2nd to last position CALL RLDDR ;Move line over :1: LDK A,' ' ; JR DISPLAY ;Put a ' ' in cursor position and set selected attributes PAGE DISPLAY: ;Display character at cursor position ;ENTRY ;A = character ;EXIT ;HL = CURPOS PROC LD HL,CURPOS ;HL = current cursor position ;DISPLAY NEW CHARACTER MOV B,A ;SAVE CHAR ;SET BACKGOUND LD A,BACKGND ORA B MOV B,A ;TOGOL REVERSE FLAG LD A,CFLAG ;A = Current ESC sequence attributes ANI 1000_0000B XRA B STO A,[HL] ;Store character RET PAGE ESCSAL: ;MAKE alternate 128 character set PROC LDK B,0001_1000B JR ALTSET ;CHANGE PIO ESCCAL: ;MAKE MAIN 128 character set PROC LDK B,0001_0000B JR ALTSET ;CHANGE PIO ESCWO256: ;256 character set WITHOUT REVERSE VIDEO PROC LDK B,0000_0000B JR ALTSET ;CHANGE PIO ESCW256: ;256 character set WITH REVERSE VIDEO PROC LDK B,0000_1000B ;FALL THROUGH PAGE ALTSET: ;CHANGE THE CHARACTER SET ;ENTRY ;B = NEW VALUE TO BE WRITTEN TO THE PIO ;EXIT ;NONE PROC DI ;SET TO PORT 3 LDK A,3 OUT SYSRS IN SYSRW ;GET OLD VALUE ANI 1110_0111B ;CLEAR BITS ORA B ;SET BITS OUT SYSRW ;SET NEW VALUE EI RET PAGE ;Set and Clear other attribute bits ;Set attributes PROC ESCSHI: LDK B,REV_FLG ;Start half intensity attribute JR :SET ESCSGR: LDK B,GR_FLG ;Start graphics attribute :SET: LD A,CFLAG OR B ;Set bit JR :DONE ;Clear attributes ESCEHI: LDK B,NOT REV_FLG ;Clear half intensity attribute JR :CLR ESCCGR: LDK B,NOT GR_FLG ;Clear graphics attribute :CLR: LD A,CFLAG AND B ;Clear bit :DONE: STO A,CFLAG ;Store new attribute RET PAGE ESCRR: ;Delete Line (scrolls lower lines up and puts cursor at beginning of line) ;ENTRY ;NONE PROC LD HL,CURPOS CALL SCROL_UP ;Delete line and scroll lower lines up JMP VC_CR ;Put cursor at beginning of line PAGE ESCEE: ;Insert Line (puts cursor at beginning of inserted line) ;ENTRY ;NONE ;EXIT ;NONE PROC LD HL,CURPOS CALL SCROL_DOWN ;Scroll lines from cursor down, clear cursor line JMP VC_CR PAGE REVON: ;Set reverse video background ;(Leaves all other background bits alone) ;ENTRY ;NONE ;EXIT ;Screen set to reverse video PROC LD A,BACKGND BIT 7,A ;TEST BIT SBIT 7,A ;Set reverse video bit ;A = New background attributes RNZ ;RETURN IF ALREADY ON JR SET_BACK ;Set new background if not set PAGE REVOFF: ;Clear reverse video background attribute ;(Leaves all other background bits alone) ;ENTRY ;NONE ;EXIT ;Screen set to normal video PROC LD A,BACKGND BIT 7,A ;TEST BIT CBIT 7,A ;Clear reverse video bit ;A = New background attributes RZ ;RETURN IF ALREADY OFF ; JR SET_BACK ;Set new background if not reset PAGE SET_BACK: ;Change background bits for window ;ENTRY ;A = New background definition ; (Bit 7 = Rev video) ;EXIT ;NONE PROC STO A,BACKGND ;TOGGLE APPROPRIATE BACKGROUND BITS FOR WHOLE WINDOW LD A,WINDCOLS MOV B,A ;B = # of columns/row LD HL,FWAWIND ;HL = FWA of window LD A,WINDROWS ;A = # of rows :RLOOP: PUSH AF ;Save row number PUSH BC ;Save # of columns PUSH HL ;Save row address ;SET BIT LOOP :CLOOP: CALL RLDA ;GET BYTE XRI 1000_0000B ;TOGOL STO A,[HL] ;STORE BYTE INC HL DJNZ :CLOOP ;Go to next spot in row POP HL ;Restore r%ow address LDK DE,VLL ADD HL,DE ;Next row's address POP BC POP AF DEC A JRNZ :RLOOP ;If more rows RET PAGE YCOORD: ;Set up Y coordinate for cursor addresssing ;If coordinate is invalid, row is set to last row ;ENTRY ;C = character (Y coordinate + offset) ;EXIT ;CTBLADDR set up for X coordinate PROC CALL ABSOLUTE ;Get absolute coordinate LD HL,CURPOS CALL SETROW ;Set HL to row A STO HL,CURPOS RET PAGE XCOORD: ;Set up X coordinate. If coordinate is out of range, position to column 0 ;ENTRY ;C = character (coordinate + offset) ;EXIT ;CTBLADDR reset to BASTBL, CURPOS set to new cursor position PROC CALL ABSOLUTE ;Get absolute coordinate value LD HL,CURPOS CALL SETCOL ;Set column STO HL,CURPOS RET PAGE SETOFF: ;Set X-Y coordinate offset ;ENTRY ;C = offset ;EXIT ;OFFSET updated PROC MOV A,C STO A,OFFSET RET PAGE STARTROW: ;Define first row of window ;(If row is out or range, set to row 0) ;ENTRY ;C = Row number + offset ;EXIT ;TEMPFWA = Address so far PROC ;CHECK FOR VALID ROW NUMBER MOV A,C CALL ABSOLUTE ;Get absolute number (without offset) LDK B,VMROWS CMP B JRC :1 ;If valid row, A = selected row XRA A ;If invalid, A = row 0 ;GET ROW ADDRESS :1: STO A,FSTROW ;Save row number LDK HL,FWAVM ;Start of video memory CALL ADDROWS ;Get new address STO HL,TEMPFWA ;Save in temporary FWA for window RET PAGE STARTCOL: ;Define first column of window ;(Invalid columns are set to column 0) ;ENTRY ;C = Column number + offset ;TEMPFWA set to selected row, column 0 ;EXIT ;TEMPFWA = FWA for window PROC ;CHECK FOR VALID COLUMN MOV A,C ;A = Selected column + offset CALL ABSOLUTE ;A = Selected column LDK B,VMCOLS ;B = Number of columns in video memory CMP B JRC :1 ;If valid, A = selected column number XRA A ;If invalid, A = 0 ;SET COLUMN IN TEMPFWA :1: STO A,FSTCOL ;Save first column number LD HL,TEMPFWA ;TEMPFWA = selected row, column 0 MOV E,A LDK D,0 ADD HL,DE STO HL,TEMPFWA RET PAGE ENDROW: ;Define last row of window ;(If invalid row selected, row set to last row) ;ENTRY ;C = row number + offset ;EXIT ;TEMPROWS = # of rows in new window PROC ;CHECK FOR VALID ROW MOV A,C ;A = selected row + offset CALL ABSOLUTE ;A = selected row LDK B,VMROWS ;B = number of rows CMP B JRC :1 ;If valid, A = selected row DEC B MOV A,B ;If invalid, A = last row ;CALCULATE NUMBER OF ROWS :1: LDK HL,FSTROW LD B,[HL] ;B = First row number ;A = Last row number SUB B JRNC :2 ;IF VALID XRA A ;SET TO 1 IF INVALID :2: INC A ;A = Number of rows STO A,TEMPROWS ;Save number of rows RET PAGE ENDCOL: ;Define last column for window and save window definition ;(If column out of range, set to last column) ;ENTRY ;C = column number + offset ;EXIT ;New window definitions set up & cursor positioned to home position of new window PROC ;CHECK FOR VALID COLUMN MOV A,C ;A = Selected column + offset CALL ABSOLUTE ;A = Selected column LDK B,VMCOLS ;B = Number of columns in screen CMP B JRC :1 ;If valid, A = selected column DEC B MOV A,B ;A = Last column ;GET NUMBER OF COLUMNS :1: LDK HL,FSTCOL LD B,[HL] ;B = First column ;A = Last column SUB B JRNC :2 ;IF VALID XRA A ;SET TO 1 IF INVALID :2: INC A ;A = Number of columns ;SET NEW WINDOW DEFINITION MOV B,A ;Save number of columns LDK HL,FWAWIND ;Current window definition LD DE,TEMPFWA STO E,[HL] ;Save new FWA INC HL STO D,[HL] IN HL LD A,TEMPROWS STO A,[HL] ;Save new number of rows INC HL STO B,[HL] ;Save new number of columns ; JMP VC_HOME ;Initialize cursor to home position of window PAGE VC_HOME: ;Home Cursor ;ENTRY ;NONE ;EXIT ;CURPOS = new cursor position PROC LD HL,FWAWIND ;Home position STO HL,CURPOS RET PAGE RETPROC: ;Procedure which only returns ;Used for branch addresses for console table entries which don't need to ;do anything ;ENTRY ;NONE ;EXIT ;NONE PROC RET PAGE DO_CR: ;Do Carriage Return processing ;ENTRY ;HL = address to process ;EXIT ;HL = address after carriage return PROC ;CLEAR COLUMN BITS IN SELECTED ADDRESS LDK A,80h AND L MOV L,A ;GET FIRST COLUMN OF WINDOW LD DE,FWAWIND MOV A,E ANI 7FH ;Get first window column ;SET ADDRESS COLUMN TO FIRST COLUMN OF WINDOW OR L ;OR in new column MOV L,A RET PAGE DO_LF: ;Do Line Feed processing (if address is on last line, scroll screen and add new ;line at bottom) ;ENTRY ;HL = Address to process ;EXIT ;HL = Address after line feed PROC ;CHECK IF ON LAST LINE CALL LASTROW JRNZ :1 ;IF NOT on last line ;IF ON LAST LINE, SCROLL WINDOW UP PUSH HL ;Save address LD HL,FWAWIND ;Scroll up the lines fr&om selected position to the end of the window (Clears last line) PUSH HL CALL DIST2LASTROW ;Get A = number of rows between HL and last row POP HL ;HL = start address JRZ :DONE ;IF ON LAST ROW LD BC,WINDCOLS LDK B,0 ;BC = # of columns per row ;MOVE ROWS :LOOP: LDK DE,VLL EX HL,DE ADD HL,DE ;HL = row below DE PUSH BC ;Save row length PUSH HL ;Save row's address CALL RLDIR ;Move row HL to row DE POP HL ;Restore row address POP BC ;Restore row length DEC A JNZ :LOOP ;If more rows ;CLEAR LAST LINE :DONE: CALL CLRLN POP HL ;Restore address RET ;RETURN ;MOVE DOWN ONE LINE :1: LDK DE,VLL ;line length ADD HL,DE ;HL = new address position RET PAGE SCROL_UP: ;Scroll up the lines from selected position to the end of the window (Clears last line) ;ENTRY ;HL = selected position ;EXIT ;NONE PROC ;POSITION AT BEGINNING OF LINE CALL DO_CR ;SCROLL UP PUSH HL CALL DIST2LASTROW ;Get A = number of rows between HL and last row POP HL ;HL = start address JZ CLRLN ;If on last row CLEAR LINE AND RETURN LD BC,WINDCOLS LDK B,0 ;BC = # of columns per row ;MOVE ROWS :LOOP: LDK DE,VLL EX HL,DE ADD HL,DE ;HL = row below DE PUSH BC ;Save row length PUSH HL ;Save row's address CALL RLDIR ;Move row HL to row DE POP HL ;Restore row address POP BC ;Restore row length DEC A JNZ :LOOP ;If more rows ;CLEAR LAST LINE JMP CLRLN PAGE SCROL_DOWN: ;Scroll window down from selected start line to end of window ;(Clears start line) ;ENTRY ;HL = start address ;EXIT ;NONE PROC ;POSITION AT BEGINNING OF LINE CALL DO_CR ;Make sure at beginning of line ;SCROLL DOWN CALL DIST2LASTROW ;Get A = number of rows to scroll JRZ :DONE ;If on last line PUSH AF LD A,WINDROWS DEC A CALL SETROW ;HL = Last row's address LD A,WINDCOLS MOV C,A LDK B,0 ;BC = Number of columns POP AF ;Restore A = Number of rows :LOOP: PUSH HL ;Save row address ORA A ;Clear carry LDK DE,VLL SBC HL,DE POP DE ;HL = row above DE PUSH BC ;Save # chars/row PUSH HL ;Save row address CALL RLDIR POP HL ;Restore POP BC DEC A JRNZ :LOOP ;If more rows ;CLEAR START LINE :DONE: JR CLRLN ;HL = start line's address PAGE LASTROW: ;Check if given address is on last line ;ENTRY ;HL = address ;EXIT ;Z bit set if on last line ;HL preserved PROC CALL GETROW ;Get current row MOV B,A ;B = current row LD A,WINDROWS DEC A ;A = last row SUB B ;Set Z flag if current row = last row RET PAGE GETCOL: ;Get column number of selected address ;(If address is out of range an invalid number is returned) ;ENTRY ;NONE ;EXIT ;A = column number ;Preserves HL PROC ;GET ACTUAL COLUMN NUMBER FOR FIRST COLUMN OF WINDOW LD DE,FWAWIND MOV A,E ANI 7FH MOV C,A ;C = First column number ;GET ACTUAL COLUMN NUMBER FOR SELECTED ADDRESS MOV A,L ;Low 7 bits of L = column ANI 7FH ;Clear high bit ;GET WINDOW COLUMN NUMBER FOR SELECTED ADDRESS SUB C RET PAGE GETROW: ;Get current row of selected address ;(Invalid number returned if address is out of range) ;ENTRY ;HL = address ;EXIT ;A = Row number ;Preserves HL PROC ;GET ACTUAL ROW VALUE OF FIRST ROW IN WINDOW PUSH HL LD HL,FWAWIND ADD HL,HL ;Shift row bits to H MOV A,H ANI 1FH ;Get row bits MOV C,A POP HL ;GET ACTUAL ROW OF SELECTED ADDRESS PUSH HL ADD HL,HL ;Shift row bits to H MOV A,H ANI 1FH ;Get row bits POP HL ;GET WINDOW CURSOR ROW SUB C RET PAGE SETCOL: ;Set HL to given column, current row ;(If column is out of range, set to column 0) ;ENTRY ;HL = selected column ;A = Column number ;EXIT ;HL = set to selected column PROC ;CHECK FOR VALID COLUMN MOV C,A ;Save column LD A,WINDCOL DEC A ;A = Last column in window CMP C ;Set Cflag if position out of range MOV A,C JRNC :1 ;If in range XRA A ;If out of range ;SET COLUMN ;GET ACTUAL COLUMN VALUE FOR WINDOW'S COLUMN 0 :1: LD DE,FWAWIND ;Start of window ADD E ANI 7FH ;A = Actual column value MOV C,A ;Save column value ;SET COLUMN FOR SELECTED ADDRESS MOV A,L ANI 80H ;Clear column bits OR C ;Put in new column bits MOV L,A RET PAGE SETROW: ;Set address to given row, current column ;(If row is out of range, row set to last row) ;ENTRY ;A = row number ;EXIT ;HL = address of given row, column 0 PROC ;GET CURRENT COLUMN MOV C,A PUSH BC ;Save row CALL GETCOL POP BC ;Restore row PUSH AF ;Save column ;CHECK FOR VALID ROW LD A,WINDROWS DEC A ;A = Last valid row number CMP C JRC :1 ;If invalid MOV A,C ;If valid :1: LD HL,FWAWIND ;Start at top of window CALL ADDROWS ;and add A rows :DONE: POP AF ;Restore column JR SETCOL PA'GE DIST2EOL: ;Calculate #chrs to between given address and last column in line ;ENTRY ;HL = address ;EXIT ;BC = # characters between address and last column ;A = # characters between address and last column ;Z bit set if 0 characters (ie address is at end of line) ;HL saved PROC PUSH HL CALL GETCOL ;Get column MOV C,A ;C = column LD A,WINDCOLS ;A = line length DEC A ;A = Last column in line SUB C ;A = #chrs between address and last column MOV C,A LDK B,0 ;BC = #chrs between address and last column POP HL RET PAGE DIST2LASTROW: ;Calculate number of rows between given position and last line of video ;ENTRY ;HL = given position ;EXIT ;A = # of rows from given position to beginning of last line ;Flags set: Z if given position on last line ; C if given position past last line PROC CALL GETROW MOV C,A ;C = cursor row LD A,WINDROWS DEC A ;A = last row SUB C RET ;A = # of rows between cursor and last row  PAGE EEOL: ;Erase to end of line ;ENTRY ;NONE ;EXIT ;CURPOS unchanged PROC LD HL,CURPOS ; JR CLRLN ;Clear to end of line PAGE CLRLN: ;Clear to end of line ;ENTRY ;HL = start position ;EXIT ;clear to EOL ; Uses All. PROC ;CLEAR START POSITION CALL CLR_CHAR ;Clear character ;FIND NUMBER OF BYTES TO CLEAR CALL DIST2EOL ;BC = distance to end of line, Z flag set RZ ;Done if at end of line PUSH HL POP DE INC DE CALL RLDIR ;Clear rest of line RET PAGE ADDROWS: ;Add rows to given address ;ENTRY ;HL = start address ;A = number of rows ;*NOTE* This routine does not check for address out of range ; The calling procedure must do that ;EXIT ;HL = new address PROC ;CHECK FOR ROW 0 ORA A ;A = row number RZ ;Done if row 0 ;ADD NUMBER OF ROWS TO WINDOW BEGINNING ADDRESS LDK DE,VLL ;Distance to next row :LOOP: ADD HL,DE ;Add a row DEC A JRNZ :LOOP ;If more rows RET PAGE ABSOLUTE: ;Get absolute value for offset number ;ENTRY ;C = Number + offset ;EXIT ;A = Absolute number (without offset) LD A,OFFSET ;Get cursor positioning offset NEG A ADD A,C ;A = Absolute cursor position RET PAGE ;CONSOLE TABLES BASET: ;Base table -- used to look up the first character in a sequence ;The table lists characters and procedures to branch to to process the character ;1st byte of table is number of entries ;Entries are 4 bytes long: ; 1st byte = match code ; 2nd byte = next table number ; 3rd, 4th bytes = branch address ;The last entry is a 3-byte "No Match" default next table and branch address PROC DB BASSIZ ;Number of entries in base table ; +----------------------------------------------+ ; | CHARACTER | NEXT TABLE | BRANCH ADDR | ; +----------------------------------------------+ DB ESC ! DB ESCNUM ! DW RETPROC ;ESC sequence :ENDB: DB BASNUM ! DW PROCNORM ;No Match ;-- Process normal 1 character long "sequence" BASSIZ = (:ENDB-BASET + 1)/4 ;Number of entries in BAST PAGE ESCT: ;Valid ESC-Sequence Table ;1st byte is number of entries ;4 bytes per entry: ascii char, next table number, branch address ;Following body of table is 3 byte No-Match default next table and branch adrs PROC DB ESCSIZ ;Number of bytes ; +----------------------------------------------+ ; | CHARACTER | NEXT TABLE | BRANCH ADDR | ; +----------------------------------------------+ DB VCAD ! DB YNUM ! DW RETPROC ;Cursor Addressing DB VCAS ! DB BASNUM ! DW ESCZZ ;Clear screen to blanks DB VINC ! DB BASNUM ! DW EINSRT ;Insert char DB VDELC ! DB BASNUM ! DW EDELC ;Delete char DB VINL ! DB BASNUM ! DW ESCEE ;Insert line DB VDELL ! DB BASNUM ! DW ESCRR ;Delete line DB VCEOL ! DB BASNUM ! DW EEOL ;Clear to end of line DB VCEOS ! DB BASNUM ! DW EEOS ;Clear to end of screen (window) DB VSRV ! DB BASNUM ! DW ESCSHI ;Start reverse video DB VERV ! DB BASNUM ! DW ESCEHI ;End reverse video DB VSHI ! DB BASNUM ! DW ESCSHI ;Set half intensity mode DB VEHI ! DB BASNUM ! DW ESCEHI ;Clear half intensity mode DB VSUL ! DB BASNUM ! DW ESCSHI ;Start underline DB VEUL ! DB BASNUM ! DW ESCEHI ;End underline DB VSGH ! DB BASNUM ! DW ESCSGR ;Set graphics mode DB VEGH ! DB BASNUM ! DW ESCCGR ;Clr graphics mode DB VWDEF ! DB DWINNUM ! DW RETPROC ;Define a window DB VOFF ! DB OFFNUM ! DW RETPROC ;Define X-Y offset DB VRON ! DB BASNUM ! DW REVON ;Set Reverse video background DB VROFF ! DB BASNUM ! DW REVOFF ;Set normal video background DB VLOCK ! DB BASNUM ! DW ESCLCK ;Lock Keyboard DB VUNLK ! DB BASNUM ! DW ESCULK ;Unlock Keyboard DB VAL128 ! DB BASNUM ! DW ESCSAL ;alternate 128 character set DB VMA128 ! DB BASNUM ! DW ESCCAL ;MAIN 128 character set DB V256W ! DB BASNUM ! DW ESCW256 ;256 CHARACTER SET WITH REVERSE VIDEO DB V256WO ! DB BASNUM ! DW ESCWO256 ;256 CHARACTER SET WITHOUT REVERSE VIDEO :ENDE: DB BASNUM ! DW LOOKUPB